1 | <?php |
---|
2 | /*********************************************** |
---|
3 | * File : vcarddir.php |
---|
4 | * Project : Z-Push |
---|
5 | * Descr : This backend is for vcard directories. |
---|
6 | * |
---|
7 | * Created : 01.10.2007 |
---|
8 | * |
---|
9 | * Copyright 2007 - 2012 Zarafa Deutschland GmbH |
---|
10 | * |
---|
11 | * This program is free software: you can redistribute it and/or modify |
---|
12 | * it under the terms of the GNU Affero General Public License, version 3, |
---|
13 | * as published by the Free Software Foundation with the following additional |
---|
14 | * term according to sec. 7: |
---|
15 | * |
---|
16 | * According to sec. 7 of the GNU Affero General Public License, version 3, |
---|
17 | * the terms of the AGPL are supplemented with the following terms: |
---|
18 | * |
---|
19 | * "Zarafa" is a registered trademark of Zarafa B.V. |
---|
20 | * "Z-Push" is a registered trademark of Zarafa Deutschland GmbH |
---|
21 | * The licensing of the Program under the AGPL does not imply a trademark license. |
---|
22 | * Therefore any rights, title and interest in our trademarks remain entirely with us. |
---|
23 | * |
---|
24 | * However, if you propagate an unmodified version of the Program you are |
---|
25 | * allowed to use the term "Z-Push" to indicate that you distribute the Program. |
---|
26 | * Furthermore you may use our trademarks where it is necessary to indicate |
---|
27 | * the intended purpose of a product or service provided you use it in accordance |
---|
28 | * with honest practices in industrial or commercial matters. |
---|
29 | * If you want to propagate modified versions of the Program under the name "Z-Push", |
---|
30 | * you may only do so if you have a written permission by Zarafa Deutschland GmbH |
---|
31 | * (to acquire a permission please contact Zarafa at trademark@zarafa.com). |
---|
32 | * |
---|
33 | * This program is distributed in the hope that it will be useful, |
---|
34 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
35 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
36 | * GNU Affero General Public License for more details. |
---|
37 | * |
---|
38 | * You should have received a copy of the GNU Affero General Public License |
---|
39 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
---|
40 | * |
---|
41 | * Consult LICENSE file for details |
---|
42 | ************************************************/ |
---|
43 | include_once('lib/default/diffbackend/diffbackend.php'); |
---|
44 | |
---|
45 | class BackendVCardDir extends BackendDiff { |
---|
46 | /**---------------------------------------------------------------------------------------------------------- |
---|
47 | * default backend methods |
---|
48 | */ |
---|
49 | |
---|
50 | /** |
---|
51 | * Authenticates the user - NOT EFFECTIVELY IMPLEMENTED |
---|
52 | * Normally some kind of password check would be done here. |
---|
53 | * Alternatively, the password could be ignored and an Apache |
---|
54 | * authentication via mod_auth_* could be done |
---|
55 | * |
---|
56 | * @param string $username |
---|
57 | * @param string $domain |
---|
58 | * @param string $password |
---|
59 | * |
---|
60 | * @access public |
---|
61 | * @return boolean |
---|
62 | */ |
---|
63 | public function Logon($username, $domain, $password) { |
---|
64 | return true; |
---|
65 | } |
---|
66 | |
---|
67 | /** |
---|
68 | * Logs off |
---|
69 | * |
---|
70 | * @access public |
---|
71 | * @return boolean |
---|
72 | */ |
---|
73 | public function Logoff() { |
---|
74 | return true; |
---|
75 | } |
---|
76 | |
---|
77 | /** |
---|
78 | * Sends an e-mail |
---|
79 | * Not implemented here |
---|
80 | * |
---|
81 | * @param SyncSendMail $sm SyncSendMail object |
---|
82 | * |
---|
83 | * @access public |
---|
84 | * @return boolean |
---|
85 | * @throws StatusException |
---|
86 | */ |
---|
87 | public function SendMail($sm) { |
---|
88 | return false; |
---|
89 | } |
---|
90 | |
---|
91 | /** |
---|
92 | * Returns the waste basket |
---|
93 | * |
---|
94 | * @access public |
---|
95 | * @return string |
---|
96 | */ |
---|
97 | public function GetWasteBasket() { |
---|
98 | return false; |
---|
99 | } |
---|
100 | |
---|
101 | /** |
---|
102 | * Returns the content of the named attachment as stream |
---|
103 | * not implemented |
---|
104 | * |
---|
105 | * @param string $attname |
---|
106 | * |
---|
107 | * @access public |
---|
108 | * @return SyncItemOperationsAttachment |
---|
109 | * @throws StatusException |
---|
110 | */ |
---|
111 | public function GetAttachmentData($attname) { |
---|
112 | return false; |
---|
113 | } |
---|
114 | |
---|
115 | /**---------------------------------------------------------------------------------------------------------- |
---|
116 | * implemented DiffBackend methods |
---|
117 | */ |
---|
118 | |
---|
119 | /** |
---|
120 | * Returns a list (array) of folders. |
---|
121 | * In simple implementations like this one, probably just one folder is returned. |
---|
122 | * |
---|
123 | * @access public |
---|
124 | * @return array |
---|
125 | */ |
---|
126 | public function GetFolderList() { |
---|
127 | ZLog::Write(LOGLEVEL_DEBUG, 'VCDir::GetFolderList()'); |
---|
128 | $contacts = array(); |
---|
129 | $folder = $this->StatFolder("root"); |
---|
130 | $contacts[] = $folder; |
---|
131 | |
---|
132 | return $contacts; |
---|
133 | } |
---|
134 | |
---|
135 | /** |
---|
136 | * Returns an actual SyncFolder object |
---|
137 | * |
---|
138 | * @param string $id id of the folder |
---|
139 | * |
---|
140 | * @access public |
---|
141 | * @return object SyncFolder with information |
---|
142 | */ |
---|
143 | public function GetFolder($id) { |
---|
144 | ZLog::Write(LOGLEVEL_DEBUG, 'VCDir::GetFolder('.$id.')'); |
---|
145 | if($id == "root") { |
---|
146 | $folder = new SyncFolder(); |
---|
147 | $folder->serverid = $id; |
---|
148 | $folder->parentid = "0"; |
---|
149 | $folder->displayname = "Contacts"; |
---|
150 | $folder->type = SYNC_FOLDER_TYPE_CONTACT; |
---|
151 | |
---|
152 | return $folder; |
---|
153 | } else return false; |
---|
154 | } |
---|
155 | |
---|
156 | /** |
---|
157 | * Returns folder stats. An associative array with properties is expected. |
---|
158 | * |
---|
159 | * @param string $id id of the folder |
---|
160 | * |
---|
161 | * @access public |
---|
162 | * @return array |
---|
163 | */ |
---|
164 | public function StatFolder($id) { |
---|
165 | ZLog::Write(LOGLEVEL_DEBUG, 'VCDir::StatFolder('.$id.')'); |
---|
166 | $folder = $this->GetFolder($id); |
---|
167 | |
---|
168 | $stat = array(); |
---|
169 | $stat["id"] = $id; |
---|
170 | $stat["parent"] = $folder->parentid; |
---|
171 | $stat["mod"] = $folder->displayname; |
---|
172 | |
---|
173 | return $stat; |
---|
174 | } |
---|
175 | |
---|
176 | /** |
---|
177 | * Creates or modifies a folder |
---|
178 | * not implemented |
---|
179 | * |
---|
180 | * @param string $folderid id of the parent folder |
---|
181 | * @param string $oldid if empty -> new folder created, else folder is to be renamed |
---|
182 | * @param string $displayname new folder name (to be created, or to be renamed to) |
---|
183 | * @param int $type folder type |
---|
184 | * |
---|
185 | * @access public |
---|
186 | * @return boolean status |
---|
187 | * @throws StatusException could throw specific SYNC_FSSTATUS_* exceptions |
---|
188 | * |
---|
189 | */ |
---|
190 | public function ChangeFolder($folderid, $oldid, $displayname, $type){ |
---|
191 | return false; |
---|
192 | } |
---|
193 | |
---|
194 | /** |
---|
195 | * Deletes a folder |
---|
196 | * |
---|
197 | * @param string $id |
---|
198 | * @param string $parent is normally false |
---|
199 | * |
---|
200 | * @access public |
---|
201 | * @return boolean status - false if e.g. does not exist |
---|
202 | * @throws StatusException could throw specific SYNC_FSSTATUS_* exceptions |
---|
203 | * |
---|
204 | */ |
---|
205 | public function DeleteFolder($id, $parentid){ |
---|
206 | return false; |
---|
207 | } |
---|
208 | |
---|
209 | /** |
---|
210 | * Returns a list (array) of messages |
---|
211 | * |
---|
212 | * @param string $folderid id of the parent folder |
---|
213 | * @param long $cutoffdate timestamp in the past from which on messages should be returned |
---|
214 | * |
---|
215 | * @access public |
---|
216 | * @return array/false array with messages or false if folder is not available |
---|
217 | */ |
---|
218 | public function GetMessageList($folderid, $cutoffdate) { |
---|
219 | ZLog::Write(LOGLEVEL_DEBUG, 'VCDir::GetMessageList('.$folderid.')'); |
---|
220 | $messages = array(); |
---|
221 | |
---|
222 | $dir = opendir($this->getPath()); |
---|
223 | if(!$dir) |
---|
224 | return false; |
---|
225 | |
---|
226 | while($entry = readdir($dir)) { |
---|
227 | if(is_dir($this->getPath() .'/'.$entry)) |
---|
228 | continue; |
---|
229 | |
---|
230 | $message = array(); |
---|
231 | $message["id"] = $entry; |
---|
232 | $stat = stat($this->getPath() .'/'.$entry); |
---|
233 | $message["mod"] = $stat["mtime"]; |
---|
234 | $message["flags"] = 1; // always 'read' |
---|
235 | |
---|
236 | $messages[] = $message; |
---|
237 | } |
---|
238 | |
---|
239 | return $messages; |
---|
240 | } |
---|
241 | |
---|
242 | /** |
---|
243 | * Returns the actual SyncXXX object type. |
---|
244 | * |
---|
245 | * @param string $folderid id of the parent folder |
---|
246 | * @param string $id id of the message |
---|
247 | * @param ContentParameters $contentparameters parameters of the requested message (truncation, mimesupport etc) |
---|
248 | * |
---|
249 | * @access public |
---|
250 | * @return object/false false if the message could not be retrieved |
---|
251 | */ |
---|
252 | public function GetMessage($folderid, $id, $contentparameters) { |
---|
253 | ZLog::Write(LOGLEVEL_DEBUG, 'VCDir::GetMessage('.$folderid.', '.$id.', ..)'); |
---|
254 | if($folderid != "root") |
---|
255 | return; |
---|
256 | |
---|
257 | $types = array ('dom' => 'type', 'intl' => 'type', 'postal' => 'type', 'parcel' => 'type', 'home' => 'type', 'work' => 'type', |
---|
258 | 'pref' => 'type', 'voice' => 'type', 'fax' => 'type', 'msg' => 'type', 'cell' => 'type', 'pager' => 'type', |
---|
259 | 'bbs' => 'type', 'modem' => 'type', 'car' => 'type', 'isdn' => 'type', 'video' => 'type', |
---|
260 | 'aol' => 'type', 'applelink' => 'type', 'attmail' => 'type', 'cis' => 'type', 'eworld' => 'type', |
---|
261 | 'internet' => 'type', 'ibmmail' => 'type', 'mcimail' => 'type', |
---|
262 | 'powershare' => 'type', 'prodigy' => 'type', 'tlx' => 'type', 'x400' => 'type', |
---|
263 | 'gif' => 'type', 'cgm' => 'type', 'wmf' => 'type', 'bmp' => 'type', 'met' => 'type', 'pmb' => 'type', 'dib' => 'type', |
---|
264 | 'pict' => 'type', 'tiff' => 'type', 'pdf' => 'type', 'ps' => 'type', 'jpeg' => 'type', 'qtime' => 'type', |
---|
265 | 'mpeg' => 'type', 'mpeg2' => 'type', 'avi' => 'type', |
---|
266 | 'wave' => 'type', 'aiff' => 'type', 'pcm' => 'type', |
---|
267 | 'x509' => 'type', 'pgp' => 'type', 'text' => 'value', 'inline' => 'value', 'url' => 'value', 'cid' => 'value', 'content-id' => 'value', |
---|
268 | '7bit' => 'encoding', '8bit' => 'encoding', 'quoted-printable' => 'encoding', 'base64' => 'encoding', |
---|
269 | ); |
---|
270 | |
---|
271 | |
---|
272 | // Parse the vcard |
---|
273 | $message = new SyncContact(); |
---|
274 | |
---|
275 | $data = file_get_contents($this->getPath() . "/" . $id); |
---|
276 | $data = str_replace("\x00", '', $data); |
---|
277 | $data = str_replace("\r\n", "\n", $data); |
---|
278 | $data = str_replace("\r", "\n", $data); |
---|
279 | $data = preg_replace('/(\n)([ \t])/i', '', $data); |
---|
280 | |
---|
281 | $lines = explode("\n", $data); |
---|
282 | |
---|
283 | $vcard = array(); |
---|
284 | foreach($lines as $line) { |
---|
285 | if (trim($line) == '') |
---|
286 | continue; |
---|
287 | $pos = strpos($line, ':'); |
---|
288 | if ($pos === false) |
---|
289 | continue; |
---|
290 | |
---|
291 | $field = trim(substr($line, 0, $pos)); |
---|
292 | $value = trim(substr($line, $pos+1)); |
---|
293 | |
---|
294 | $fieldparts = preg_split('/(?<!\\\\)(\;)/i', $field, -1, PREG_SPLIT_NO_EMPTY); |
---|
295 | |
---|
296 | $type = strtolower(array_shift($fieldparts)); |
---|
297 | |
---|
298 | $fieldvalue = array(); |
---|
299 | |
---|
300 | foreach ($fieldparts as $fieldpart) { |
---|
301 | if(preg_match('/([^=]+)=(.+)/', $fieldpart, $matches)){ |
---|
302 | if(!in_array(strtolower($matches[1]),array('value','type','encoding','language'))) |
---|
303 | continue; |
---|
304 | if(isset($fieldvalue[strtolower($matches[1])]) && is_array($fieldvalue[strtolower($matches[1])])){ |
---|
305 | $fieldvalue[strtolower($matches[1])] = array_merge($fieldvalue[strtolower($matches[1])], preg_split('/(?<!\\\\)(\,)/i', $matches[2], -1, PREG_SPLIT_NO_EMPTY)); |
---|
306 | }else{ |
---|
307 | $fieldvalue[strtolower($matches[1])] = preg_split('/(?<!\\\\)(\,)/i', $matches[2], -1, PREG_SPLIT_NO_EMPTY); |
---|
308 | } |
---|
309 | }else{ |
---|
310 | if(!isset($types[strtolower($fieldpart)])) |
---|
311 | continue; |
---|
312 | $fieldvalue[$types[strtolower($fieldpart)]][] = $fieldpart; |
---|
313 | } |
---|
314 | } |
---|
315 | // |
---|
316 | switch ($type) { |
---|
317 | case 'categories': |
---|
318 | //case 'nickname': |
---|
319 | $val = preg_split('/(?<!\\\\)(\,)/i', $value); |
---|
320 | $val = array_map("w2ui", $val); |
---|
321 | break; |
---|
322 | default: |
---|
323 | $val = preg_split('/(?<!\\\\)(\;)/i', $value); |
---|
324 | break; |
---|
325 | } |
---|
326 | if(isset($fieldvalue['encoding'][0])){ |
---|
327 | switch(strtolower($fieldvalue['encoding'][0])){ |
---|
328 | case 'q': |
---|
329 | case 'quoted-printable': |
---|
330 | foreach($val as $i => $v){ |
---|
331 | $val[$i] = quoted_printable_decode($v); |
---|
332 | } |
---|
333 | break; |
---|
334 | case 'b': |
---|
335 | case 'base64': |
---|
336 | foreach($val as $i => $v){ |
---|
337 | $val[$i] = base64_decode($v); |
---|
338 | } |
---|
339 | break; |
---|
340 | } |
---|
341 | }else{ |
---|
342 | foreach($val as $i => $v){ |
---|
343 | $val[$i] = $this->unescape($v); |
---|
344 | } |
---|
345 | } |
---|
346 | $fieldvalue['val'] = $val; |
---|
347 | $vcard[$type][] = $fieldvalue; |
---|
348 | } |
---|
349 | |
---|
350 | if(isset($vcard['email'][0]['val'][0])) |
---|
351 | $message->email1address = $vcard['email'][0]['val'][0]; |
---|
352 | if(isset($vcard['email'][1]['val'][0])) |
---|
353 | $message->email2address = $vcard['email'][1]['val'][0]; |
---|
354 | if(isset($vcard['email'][2]['val'][0])) |
---|
355 | $message->email3address = $vcard['email'][2]['val'][0]; |
---|
356 | |
---|
357 | if(isset($vcard['tel'])){ |
---|
358 | foreach($vcard['tel'] as $tel) { |
---|
359 | if(!isset($tel['type'])){ |
---|
360 | $tel['type'] = array(); |
---|
361 | } |
---|
362 | if(in_array('car', $tel['type'])){ |
---|
363 | $message->carphonenumber = $tel['val'][0]; |
---|
364 | }elseif(in_array('pager', $tel['type'])){ |
---|
365 | $message->pagernumber = $tel['val'][0]; |
---|
366 | }elseif(in_array('cell', $tel['type'])){ |
---|
367 | $message->mobilephonenumber = $tel['val'][0]; |
---|
368 | }elseif(in_array('home', $tel['type'])){ |
---|
369 | if(in_array('fax', $tel['type'])){ |
---|
370 | $message->homefaxnumber = $tel['val'][0]; |
---|
371 | }elseif(empty($message->homephonenumber)){ |
---|
372 | $message->homephonenumber = $tel['val'][0]; |
---|
373 | }else{ |
---|
374 | $message->home2phonenumber = $tel['val'][0]; |
---|
375 | } |
---|
376 | }elseif(in_array('work', $tel['type'])){ |
---|
377 | if(in_array('fax', $tel['type'])){ |
---|
378 | $message->businessfaxnumber = $tel['val'][0]; |
---|
379 | }elseif(empty($message->businessphonenumber)){ |
---|
380 | $message->businessphonenumber = $tel['val'][0]; |
---|
381 | }else{ |
---|
382 | $message->business2phonenumber = $tel['val'][0]; |
---|
383 | } |
---|
384 | }elseif(empty($message->homephonenumber)){ |
---|
385 | $message->homephonenumber = $tel['val'][0]; |
---|
386 | }elseif(empty($message->home2phonenumber)){ |
---|
387 | $message->home2phonenumber = $tel['val'][0]; |
---|
388 | }else{ |
---|
389 | $message->radiophonenumber = $tel['val'][0]; |
---|
390 | } |
---|
391 | } |
---|
392 | } |
---|
393 | //;;street;city;state;postalcode;country |
---|
394 | if(isset($vcard['adr'])){ |
---|
395 | foreach($vcard['adr'] as $adr) { |
---|
396 | if(empty($adr['type'])){ |
---|
397 | $a = 'other'; |
---|
398 | }elseif(in_array('home', $adr['type'])){ |
---|
399 | $a = 'home'; |
---|
400 | }elseif(in_array('work', $adr['type'])){ |
---|
401 | $a = 'business'; |
---|
402 | }else{ |
---|
403 | $a = 'other'; |
---|
404 | } |
---|
405 | if(!empty($adr['val'][2])){ |
---|
406 | $b=$a.'street'; |
---|
407 | $message->$b = w2ui($adr['val'][2]); |
---|
408 | } |
---|
409 | if(!empty($adr['val'][3])){ |
---|
410 | $b=$a.'city'; |
---|
411 | $message->$b = w2ui($adr['val'][3]); |
---|
412 | } |
---|
413 | if(!empty($adr['val'][4])){ |
---|
414 | $b=$a.'state'; |
---|
415 | $message->$b = w2ui($adr['val'][4]); |
---|
416 | } |
---|
417 | if(!empty($adr['val'][5])){ |
---|
418 | $b=$a.'postalcode'; |
---|
419 | $message->$b = w2ui($adr['val'][5]); |
---|
420 | } |
---|
421 | if(!empty($adr['val'][6])){ |
---|
422 | $b=$a.'country'; |
---|
423 | $message->$b = w2ui($adr['val'][6]); |
---|
424 | } |
---|
425 | } |
---|
426 | } |
---|
427 | |
---|
428 | if(!empty($vcard['fn'][0]['val'][0])) |
---|
429 | $message->fileas = w2ui($vcard['fn'][0]['val'][0]); |
---|
430 | if(!empty($vcard['n'][0]['val'][0])) |
---|
431 | $message->lastname = w2ui($vcard['n'][0]['val'][0]); |
---|
432 | if(!empty($vcard['n'][0]['val'][1])) |
---|
433 | $message->firstname = w2ui($vcard['n'][0]['val'][1]); |
---|
434 | if(!empty($vcard['n'][0]['val'][2])) |
---|
435 | $message->middlename = w2ui($vcard['n'][0]['val'][2]); |
---|
436 | if(!empty($vcard['n'][0]['val'][3])) |
---|
437 | $message->title = w2ui($vcard['n'][0]['val'][3]); |
---|
438 | if(!empty($vcard['n'][0]['val'][4])) |
---|
439 | $message->suffix = w2ui($vcard['n'][0]['val'][4]); |
---|
440 | if(!empty($vcard['bday'][0]['val'][0])){ |
---|
441 | $tz = date_default_timezone_get(); |
---|
442 | date_default_timezone_set('UTC'); |
---|
443 | $message->birthday = strtotime($vcard['bday'][0]['val'][0]); |
---|
444 | date_default_timezone_set($tz); |
---|
445 | } |
---|
446 | if(!empty($vcard['org'][0]['val'][0])) |
---|
447 | $message->companyname = w2ui($vcard['org'][0]['val'][0]); |
---|
448 | if(!empty($vcard['note'][0]['val'][0])){ |
---|
449 | $message->body = w2ui($vcard['note'][0]['val'][0]); |
---|
450 | $message->bodysize = strlen($vcard['note'][0]['val'][0]); |
---|
451 | $message->bodytruncated = 0; |
---|
452 | } |
---|
453 | if(!empty($vcard['role'][0]['val'][0])) |
---|
454 | $message->jobtitle = w2ui($vcard['role'][0]['val'][0]);//$vcard['title'][0]['val'][0] |
---|
455 | if(!empty($vcard['url'][0]['val'][0])) |
---|
456 | $message->webpage = w2ui($vcard['url'][0]['val'][0]); |
---|
457 | if(!empty($vcard['categories'][0]['val'])) |
---|
458 | $message->categories = $vcard['categories'][0]['val']; |
---|
459 | |
---|
460 | if(!empty($vcard['photo'][0]['val'][0])) |
---|
461 | $message->picture = base64_encode($vcard['photo'][0]['val'][0]); |
---|
462 | |
---|
463 | return $message; |
---|
464 | } |
---|
465 | |
---|
466 | /** |
---|
467 | * Returns message stats, analogous to the folder stats from StatFolder(). |
---|
468 | * |
---|
469 | * @param string $folderid id of the folder |
---|
470 | * @param string $id id of the message |
---|
471 | * |
---|
472 | * @access public |
---|
473 | * @return array |
---|
474 | */ |
---|
475 | public function StatMessage($folderid, $id) { |
---|
476 | ZLog::Write(LOGLEVEL_DEBUG, 'VCDir::StatMessage('.$folderid.', '.$id.')'); |
---|
477 | if($folderid != "root") |
---|
478 | return false; |
---|
479 | |
---|
480 | $stat = stat($this->getPath() . "/" . $id); |
---|
481 | |
---|
482 | $message = array(); |
---|
483 | $message["mod"] = $stat["mtime"]; |
---|
484 | $message["id"] = $id; |
---|
485 | $message["flags"] = 1; |
---|
486 | |
---|
487 | return $message; |
---|
488 | } |
---|
489 | |
---|
490 | /** |
---|
491 | * Called when a message has been changed on the mobile. |
---|
492 | * This functionality is not available for emails. |
---|
493 | * |
---|
494 | * @param string $folderid id of the folder |
---|
495 | * @param string $id id of the message |
---|
496 | * @param SyncXXX $message the SyncObject containing a message |
---|
497 | * |
---|
498 | * @access public |
---|
499 | * @return array same return value as StatMessage() |
---|
500 | * @throws StatusException could throw specific SYNC_STATUS_* exceptions |
---|
501 | */ |
---|
502 | public function ChangeMessage($folderid, $id, $message) { |
---|
503 | ZLog::Write(LOGLEVEL_DEBUG, 'VCDir::ChangeMessage('.$folderid.', '.$id.', ..)'); |
---|
504 | $mapping = array( |
---|
505 | 'fileas' => 'FN', |
---|
506 | 'lastname;firstname;middlename;title;suffix' => 'N', |
---|
507 | 'email1address' => 'EMAIL;INTERNET', |
---|
508 | 'email2address' => 'EMAIL;INTERNET', |
---|
509 | 'email3address' => 'EMAIL;INTERNET', |
---|
510 | 'businessphonenumber' => 'TEL;WORK', |
---|
511 | 'business2phonenumber' => 'TEL;WORK', |
---|
512 | 'businessfaxnumber' => 'TEL;WORK;FAX', |
---|
513 | 'homephonenumber' => 'TEL;HOME', |
---|
514 | 'home2phonenumber' => 'TEL;HOME', |
---|
515 | 'homefaxnumber' => 'TEL;HOME;FAX', |
---|
516 | 'mobilephonenumber' => 'TEL;CELL', |
---|
517 | 'carphonenumber' => 'TEL;CAR', |
---|
518 | 'pagernumber' => 'TEL;PAGER', |
---|
519 | ';;businessstreet;businesscity;businessstate;businesspostalcode;businesscountry' => 'ADR;WORK', |
---|
520 | ';;homestreet;homecity;homestate;homepostalcode;homecountry' => 'ADR;HOME', |
---|
521 | ';;otherstreet;othercity;otherstate;otherpostalcode;othercountry' => 'ADR', |
---|
522 | 'companyname' => 'ORG', |
---|
523 | 'body' => 'NOTE', |
---|
524 | 'jobtitle' => 'ROLE', |
---|
525 | 'webpage' => 'URL', |
---|
526 | ); |
---|
527 | $data = "BEGIN:VCARD\nVERSION:2.1\nPRODID:Z-Push\n"; |
---|
528 | foreach($mapping as $k => $v){ |
---|
529 | $val = ''; |
---|
530 | $ks = explode(';', $k); |
---|
531 | foreach($ks as $i){ |
---|
532 | if(!empty($message->$i)) |
---|
533 | $val .= $this->escape($message->$i); |
---|
534 | $val.=';'; |
---|
535 | } |
---|
536 | if(empty($val)) |
---|
537 | continue; |
---|
538 | $val = substr($val,0,-1); |
---|
539 | if(strlen($val)>50){ |
---|
540 | $data .= $v.":\n\t".substr(chunk_split($val, 50, "\n\t"), 0, -1); |
---|
541 | }else{ |
---|
542 | $data .= $v.':'.$val."\n"; |
---|
543 | } |
---|
544 | } |
---|
545 | if(!empty($message->categories)) |
---|
546 | $data .= 'CATEGORIES:'.implode(',', $this->escape($message->categories))."\n"; |
---|
547 | if(!empty($message->picture)) |
---|
548 | $data .= 'PHOTO;ENCODING=BASE64;TYPE=JPEG:'."\n\t".substr(chunk_split($message->picture, 50, "\n\t"), 0, -1); |
---|
549 | if(isset($message->birthday)) |
---|
550 | $data .= 'BDAY:'.date('Y-m-d', $message->birthday)."\n"; |
---|
551 | $data .= "END:VCARD"; |
---|
552 | |
---|
553 | // not supported: anniversary, assistantname, assistnamephonenumber, children, department, officelocation, radiophonenumber, spouse, rtf |
---|
554 | |
---|
555 | if(!$id){ |
---|
556 | if(!empty($message->fileas)){ |
---|
557 | $name = u2wi($message->fileas); |
---|
558 | }elseif(!empty($message->lastname)){ |
---|
559 | $name = $name = u2wi($message->lastname); |
---|
560 | }elseif(!empty($message->firstname)){ |
---|
561 | $name = $name = u2wi($message->firstname); |
---|
562 | }elseif(!empty($message->companyname)){ |
---|
563 | $name = $name = u2wi($message->companyname); |
---|
564 | }else{ |
---|
565 | $name = 'unknown'; |
---|
566 | } |
---|
567 | $name = preg_replace('/[^a-z0-9 _-]/i', '', $name); |
---|
568 | $id = $name.'.vcf'; |
---|
569 | $i = 0; |
---|
570 | while(file_exists($this->getPath().'/'.$id)){ |
---|
571 | $i++; |
---|
572 | $id = $name.$i.'.vcf'; |
---|
573 | } |
---|
574 | } |
---|
575 | file_put_contents($this->getPath().'/'.$id, $data); |
---|
576 | return $this->StatMessage($folderid, $id); |
---|
577 | } |
---|
578 | |
---|
579 | /** |
---|
580 | * Changes the 'read' flag of a message on disk |
---|
581 | * |
---|
582 | * @param string $folderid id of the folder |
---|
583 | * @param string $id id of the message |
---|
584 | * @param int $flags read flag of the message |
---|
585 | * |
---|
586 | * @access public |
---|
587 | * @return boolean status of the operation |
---|
588 | * @throws StatusException could throw specific SYNC_STATUS_* exceptions |
---|
589 | */ |
---|
590 | public function SetReadFlag($folderid, $id, $flags) { |
---|
591 | return false; |
---|
592 | } |
---|
593 | |
---|
594 | /** |
---|
595 | * Called when the user has requested to delete (really delete) a message |
---|
596 | * |
---|
597 | * @param string $folderid id of the folder |
---|
598 | * @param string $id id of the message |
---|
599 | * |
---|
600 | * @access public |
---|
601 | * @return boolean status of the operation |
---|
602 | * @throws StatusException could throw specific SYNC_STATUS_* exceptions |
---|
603 | */ |
---|
604 | public function DeleteMessage($folderid, $id) { |
---|
605 | return unlink($this->getPath() . '/' . $id); |
---|
606 | } |
---|
607 | |
---|
608 | /** |
---|
609 | * Called when the user moves an item on the PDA from one folder to another |
---|
610 | * not implemented |
---|
611 | * |
---|
612 | * @param string $folderid id of the source folder |
---|
613 | * @param string $id id of the message |
---|
614 | * @param string $newfolderid id of the destination folder |
---|
615 | * |
---|
616 | * @access public |
---|
617 | * @return boolean status of the operation |
---|
618 | * @throws StatusException could throw specific SYNC_MOVEITEMSSTATUS_* exceptions |
---|
619 | */ |
---|
620 | public function MoveMessage($folderid, $id, $newfolderid) { |
---|
621 | return false; |
---|
622 | } |
---|
623 | |
---|
624 | |
---|
625 | /**---------------------------------------------------------------------------------------------------------- |
---|
626 | * private vcard-specific internals |
---|
627 | */ |
---|
628 | |
---|
629 | /** |
---|
630 | * The path we're working on |
---|
631 | * |
---|
632 | * @access private |
---|
633 | * @return string |
---|
634 | */ |
---|
635 | private function getPath() { |
---|
636 | return str_replace('%u', $this->store, VCARDDIR_DIR); |
---|
637 | } |
---|
638 | |
---|
639 | /** |
---|
640 | * Escapes a string |
---|
641 | * |
---|
642 | * @param string $data string to be escaped |
---|
643 | * |
---|
644 | * @access private |
---|
645 | * @return string |
---|
646 | */ |
---|
647 | function escape($data){ |
---|
648 | if (is_array($data)) { |
---|
649 | foreach ($data as $key => $val) { |
---|
650 | $data[$key] = $this->escape($val); |
---|
651 | } |
---|
652 | return $data; |
---|
653 | } |
---|
654 | $data = str_replace("\r\n", "\n", $data); |
---|
655 | $data = str_replace("\r", "\n", $data); |
---|
656 | $data = str_replace(array('\\', ';', ',', "\n"), array('\\\\', '\\;', '\\,', '\\n'), $data); |
---|
657 | return u2wi($data); |
---|
658 | } |
---|
659 | |
---|
660 | /** |
---|
661 | * Un-escapes a string |
---|
662 | * |
---|
663 | * @param string $data string to be un-escaped |
---|
664 | * |
---|
665 | * @access private |
---|
666 | * @return string |
---|
667 | */ |
---|
668 | function unescape($data){ |
---|
669 | $data = str_replace(array('\\\\', '\\;', '\\,', '\\n','\\N'),array('\\', ';', ',', "\n", "\n"),$data); |
---|
670 | return $data; |
---|
671 | } |
---|
672 | }; |
---|
673 | ?> |
---|