]>
Commit | Line | Data |
---|---|---|
1 | <?php | |
2 | ||
3 | /* $Id$ */ | |
4 | final class VTYPE { | |
5 | const VEVENT = 1; | |
6 | const VTODO = 2; | |
7 | const VJOURNAL = 3; | |
8 | const VFREEBUSY = 4; | |
9 | const VTIMEZONE = 5; | |
10 | const VALARM = 6; | |
11 | private $value; | |
12 | ||
13 | public function __construct($value) { | |
14 | switch ($value) { | |
15 | case 'VEVENT': $this->value = self::VEVENT; break; | |
16 | case 'VTODO': $this->value = self::VTODO; break; | |
17 | case 'VJOURNAL': $this->value = self::VJOURNAL; break; | |
18 | case 'VFREEBUSY': $this->value = self::VFREEBUSY; break; | |
19 | case 'VTIMEZONE': $this->value = self::VTIMEZONE; break; | |
20 | case 'VALARM': $this->value = self::VALARM; break; | |
21 | case self::VEVENT: | |
22 | case self::VTODO: | |
23 | case self::VJOURNAL: | |
24 | case self::VFREEBUSY: | |
25 | case self::VTIMEZONE: | |
26 | case self::VALARM: $this->value = $value; break; | |
27 | default: throw new Exception ("$value: Invalid VTYPE"); | |
28 | } | |
29 | } | |
30 | ||
31 | private function __clone() {} | |
32 | ||
33 | public function ordinal() { | |
34 | return $this->value; | |
35 | } | |
36 | ||
37 | public function __toString() { | |
38 | switch ($this->value) { | |
39 | case self::VEVENT: return 'VEVENT'; break; | |
40 | case self::VTODO: return 'VTODO'; break; | |
41 | case self::VJOURNAL: return 'VJOURNAL'; break; | |
42 | case self::VFREEBUSY: return 'VFREEBUSY'; break; | |
43 | case self::VTIMEZONE: return 'VTIMEZONE'; break; | |
44 | case self::VALARM: return 'VALARM'; break; | |
45 | } | |
46 | } | |
47 | ||
48 | } | |
49 | ||
50 | abstract class CaldavRessource | |
51 | implements ArrayAccess, IteratorAggregate { | |
52 | ||
53 | private $client; | |
54 | ||
55 | function __construct($url, $uid = '', $pwd = '', $cal = '') { | |
56 | if (empty($url)) | |
57 | throw new Exception("Missing URL"); | |
58 | $this->client = new CalDAVClient($url, $uid, $pwd, $cal); | |
59 | } | |
60 | ||
61 | /** | |
62 | * abstract functions to be implemented by sub classes | |
63 | */ | |
64 | abstract function update($url, $etag = NULL); | |
65 | abstract function newComponent($c_type); | |
66 | abstract function getComponents($start, $end); | |
67 | abstract function delete($url, $etag = NULL); | |
68 | ||
69 | protected function callServer($method, $param = array()) { | |
70 | $error = TRUE; | |
71 | $msg = "Unknown error"; | |
72 | ||
73 | if (! is_array($param)) | |
74 | throw new Exception("Parameters must be inclosed in an array"); | |
75 | switch (strtolower($method)) { | |
76 | case 'getevents': | |
77 | if (count($param) != 2) { | |
78 | $error = TRUE; | |
79 | $msg = "Expected 2 parameters"; | |
80 | break; | |
81 | } | |
82 | if ($this->isDateTime($param[0]) && | |
83 | $this->isDateTime($param[1])) { | |
84 | $res = $this->client->GetEvents($param[0], $param[1]); | |
85 | $error = FALSE; | |
86 | } | |
87 | else { | |
88 | $msg = "[${param[0]},${param[1]}]: Invalid DateTime"; | |
89 | $error = TRUE; | |
90 | } | |
91 | break; | |
92 | case 'getbyuid': | |
93 | if (count($param) != 1) { | |
94 | $error = TRUE; | |
95 | $msg = "Expected 1 parameter"; | |
96 | break; | |
97 | } | |
98 | $res = $this->client->GetEntryByUid($param[0]); | |
99 | $error = FALSE; | |
100 | break; | |
101 | case 'put': | |
102 | if (count($param) < 2 || count($param) > 3) { | |
103 | $error = TRUE; | |
104 | $msg = "Syntax: URL, CalDAV_resource[, ETag]"; | |
105 | break; | |
106 | } | |
107 | if (count($param) == 2) | |
108 | $res = $this->client->DoPUTRequest($param[0], $param[1]); | |
109 | else | |
110 | $res = $this->client->DoPUTRequest($param[0], $param[1], $param[2]); | |
111 | $error = FALSE; | |
112 | break; | |
113 | case 'delete': | |
114 | if (count($param) < 1 || count($param) > 2) { | |
115 | $error = TRUE; | |
116 | $msg = "Syntax: URL[, ETag]"; | |
117 | break; | |
118 | } | |
119 | if (count($param) == 1) | |
120 | $res = $this->client->DoDELETERequest($param[0]); | |
121 | else | |
122 | $res = $this->client->DoDELETERequest($param[0], $param[1]); | |
123 | $error = FALSE; | |
124 | break; | |
125 | default: | |
126 | throw new Exception("$method: Unknown method"); | |
127 | } | |
128 | if ($error) | |
129 | throw new Exception($msg); | |
130 | else | |
131 | return $res; | |
132 | } | |
133 | ||
134 | static function isDateTime($var) { | |
135 | return (preg_match("/^([0-9]{8})T([0-9]{6})Z?$/", $var) > 0); | |
136 | } | |
137 | ||
138 | /** | |
139 | * Returned date-time will always be in UTC | |
140 | */ | |
141 | static function timestamp2ICal($ts, $localtime = TRUE) { | |
142 | $ts = (int) $ts; | |
143 | if ($ts < 0) | |
144 | throw new Exception("$ts: invalid timestamp"); | |
145 | if ($localtime) { | |
146 | $date = date('Ymd', $ts); | |
147 | $time = date('His', $ts); | |
148 | $res = sprintf("%sT%s", $date, $time); | |
149 | } | |
150 | else { | |
151 | $date = gmdate('Ymd', $ts); | |
152 | $time = gmdate('His', $ts); | |
153 | $res = sprintf("%sT%sZ", $date, $time); | |
154 | } | |
155 | return $res; | |
156 | } | |
157 | ||
158 | static function iCal2Timestamp($ical) { | |
159 | if (! self::isDateTime($ical)) { | |
160 | // test for badly formed all-day event | |
161 | //print "$ical"; | |
162 | $res = preg_match("/^([0-9]{4})([0-9]{2})([0-9]{2})$/", | |
163 | $ical, $parts); | |
164 | if ($res == 0) | |
165 | throw new Exception("$ical: invalid CalDAV Date-Time"); | |
166 | else { | |
167 | $timepart = array('00', '00', '00'); | |
168 | $parts = array_merge($parts, $timepart); | |
169 | } | |
170 | } | |
171 | else { | |
172 | $date = "([0-9]{4})([0-9]{2})([0-9]{2})"; | |
173 | $time = "([0-9]{2})([0-9]{2})([0-9]{2})"; | |
174 | preg_match("/^${date}T${time}(Z?)$/", $ical, $parts); | |
175 | } | |
176 | if (count($parts) == 8 && ! empty($parts[7])) | |
177 | return gmmktime($parts[4], $parts[5], $parts[6], | |
178 | $parts[2], $parts[3], $parts[1]); | |
179 | else | |
180 | return mktime($parts[4], $parts[5], $parts[6], | |
181 | $parts[2], $parts[3], $parts[1]); | |
182 | } | |
183 | ||
184 | private static function down_hour($date) { | |
185 | //print "$date<br/>"; | |
186 | if (! self::isDateTime($date)) { | |
187 | // test for badly formed all-day event | |
188 | $res = preg_match("/^([0-9]{4})([0-9]{2})([0-9]{2})$/", | |
189 | $date, $parts); | |
190 | if ($res == 0) | |
191 | throw new Exception("$date: invalid CalDAV Date-Time"); | |
192 | else { | |
193 | array_shift($parts); | |
194 | $timepart = array('T', '00', '00', '00'); | |
195 | $parts = array_merge($parts, $timepart); | |
196 | return implode('', $parts); | |
197 | } | |
198 | } | |
199 | else { | |
200 | $a = explode('T', $date); | |
201 | $a[1] = substr_replace($a[1], '0000', 2); | |
202 | return $a[0].'T'.$a[1]; | |
203 | } | |
204 | } | |
205 | ||
206 | static function fix_allday_event(&$date_a, &$date_b) { | |
207 | //print "$date_a : $date_b<br/>"; | |
208 | if ($date_a == $date_b) { | |
209 | if (! self::isDateTime($date_a) && ! self::isDateTime($date_b)) { | |
210 | $res1 = preg_match("/^([0-9]{4})([0-9]{2})([0-9]{2})$/", | |
211 | $date_a); | |
212 | $res2 = preg_match("/^([0-9]{4})([0-9]{2})([0-9]{2})$/", | |
213 | $date_b); | |
214 | if ($res1 == 0 || $res2 == 0) | |
215 | throw new Exception("$date_a, $date_b: invalid CalDAV Date-Time"); | |
216 | else { | |
217 | $date_a .= "T000000"; | |
218 | $date_b .= "T235959"; | |
219 | } | |
220 | } | |
221 | else { | |
222 | preg_match("/^([0-9]{4}[0-9]{2}[0-9]{2})T([0-9]{6})$/", | |
223 | $date_a, $part_a); | |
224 | preg_match("/^([0-9]{4}[0-9]{2}[0-9]{2})T([0-9]{6})$/", | |
225 | $date_b, $part_b); | |
226 | $date_a = $part_a[1]."T000000"; | |
227 | $date_b = $part_b[1]."T235959"; | |
228 | //print "$date_a : $date_b<br/>"; | |
229 | } | |
230 | //print "$date_a : $date_b<br/>"; | |
231 | } | |
232 | } | |
233 | ||
234 | static function datecmp($date_a, $date_b) { | |
235 | $date_a = self::iCal2Timestamp($date_a); | |
236 | $date_b = self::iCal2Timestamp(self::down_hour($date_b)); | |
237 | if ($date_a < $date_b) | |
238 | $res = -1; | |
239 | else if ($date_a > $date_b) | |
240 | $res = 1; | |
241 | else | |
242 | $res = 0; | |
243 | return $res; | |
244 | } | |
245 | ||
246 | private static function intcmpstr($a_str, $b_str) { | |
247 | $a = (int) $a_str; | |
248 | $b = (int) $b_str; | |
249 | //print "$a:$b<br/>"; | |
250 | if ($a > $b) | |
251 | return 1; | |
252 | else if ($a < $b) | |
253 | return -1; | |
254 | else | |
255 | return 0; | |
256 | } | |
257 | ||
258 | static function cmpdate($date_a, $date_b) { | |
259 | $datepart = explode('T', $date_a); | |
260 | $d_a = $datepart[0]; | |
261 | $datepart = explode('T', $date_b); | |
262 | $d_b = $datepart[0]; | |
263 | $y_cmp = self::intcmpstr(substr($d_a, 0, 4), substr($d_b, 0, 4)); | |
264 | if ($y_cmp == 0) { | |
265 | $m_cmp = self::intcmpstr(substr($d_a, 4, 2), substr($d_b, 4, 2)); | |
266 | if ($m_cmp == 0) { | |
267 | return self::intcmpstr(substr($d_a, 6, 2), substr($d_b, 6, 2)); | |
268 | } | |
269 | return $m_cmp; | |
270 | } | |
271 | return $y_cmp; | |
272 | } | |
273 | ||
274 | static function cmptime($time_a, $time_b) { | |
275 | $timepart = explode('T', $time_a); | |
276 | $t_a = $timepart[1]; | |
277 | $timepart = explode('T', $time_b); | |
278 | $t_b = $timepart[1]; | |
279 | //print "$t_a:$t_b<br/>"; | |
280 | $h_cmp = self::intcmpstr(substr($t_a, 0, 2), substr($t_b, 0, 2)); | |
281 | if ($h_cmp == 0) { | |
282 | $m_cmp = self::intcmpstr(substr($t_a, 2, 2), substr($t_b, 2, 2)); | |
283 | if ($m_cmp == 0) { | |
284 | return self::intcmpstr(substr($t_a, 4, 2), substr($t_b, 4, 2)); | |
285 | } | |
286 | return $m_cmp; | |
287 | } | |
288 | return $h_cmp; | |
289 | } | |
290 | ||
291 | static function allDayEvent($time_a, $time_b) { | |
292 | //echo $time_a.':'.$time_b.'<br/>'; | |
293 | $a = explode('T', $time_a); | |
294 | if (count($a) < 2) | |
295 | array_push($a, '0000'); | |
296 | $b = explode('T', $time_b); | |
297 | if (count($b) < 2) | |
298 | array_push($b, '0000'); | |
299 | $t = strtotime($time_b) - 3600; | |
300 | $t = date("Ymd\THm", $t); | |
301 | return (self::cmpdate($time_a, $t) == 0 && | |
302 | $a[1] == '0000' && $b[1] == '0000'); | |
303 | } | |
304 | } |