1 | <?php |
||||||
2 | /** |
||||||
3 | * Addressbook - vCard / iCal parser |
||||||
4 | * |
||||||
5 | * @link http://www.egroupware.org |
||||||
6 | * @author Lars Kneschke <[email protected]> |
||||||
7 | * @author Ralf Becker <RalfBecker-AT-outdoor-training.de> |
||||||
8 | * @author Joerg Lehrke <[email protected]> |
||||||
9 | * @package addressbook |
||||||
10 | * @subpackage export |
||||||
11 | * @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License |
||||||
12 | * @version $Id$ |
||||||
13 | */ |
||||||
14 | |||||||
15 | use EGroupware\Api; |
||||||
16 | use EGroupware\Api\Link; |
||||||
17 | |||||||
18 | /** |
||||||
19 | * Addressbook - vCard parser |
||||||
20 | */ |
||||||
21 | class addressbook_vcal extends addressbook_bo |
||||||
22 | { |
||||||
23 | /** |
||||||
24 | * product manufacturer from setSupportedFields (lowercase!) |
||||||
25 | * |
||||||
26 | * @var string |
||||||
27 | */ |
||||||
28 | var $productManufacturer = 'file'; |
||||||
29 | /** |
||||||
30 | * product name from setSupportedFields (lowercase!) |
||||||
31 | * |
||||||
32 | * @var string |
||||||
33 | */ |
||||||
34 | var $productName; |
||||||
35 | /** |
||||||
36 | * supported fields for vCard file and CardDAV import/export |
||||||
37 | * |
||||||
38 | * @var array |
||||||
39 | */ |
||||||
40 | var $databaseFields = array( // all entries e.g. for CardDAV |
||||||
41 | 'ADR;WORK' => array('','adr_one_street2','adr_one_street','adr_one_locality','adr_one_region', |
||||||
42 | 'adr_one_postalcode','adr_one_countryname'), |
||||||
43 | 'ADR;HOME' => array('','adr_two_street2','adr_two_street','adr_two_locality','adr_two_region', |
||||||
44 | 'adr_two_postalcode','adr_two_countryname'), |
||||||
45 | 'BDAY' => array('bday'), |
||||||
46 | 'CLASS' => array('private'), |
||||||
47 | 'CATEGORIES' => array('cat_id'), |
||||||
48 | 'EMAIL;WORK' => array('email'), |
||||||
49 | 'EMAIL;HOME' => array('email_home'), |
||||||
50 | 'N' => array('n_family','n_given','n_middle', |
||||||
51 | 'n_prefix','n_suffix'), |
||||||
52 | 'FN' => array('n_fn'), |
||||||
53 | 'NOTE' => array('note'), |
||||||
54 | 'ORG' => array('org_name','org_unit','room'), |
||||||
55 | 'TEL;CELL;WORK' => array('tel_cell'), |
||||||
56 | 'TEL;CELL;HOME' => array('tel_cell_private'), |
||||||
57 | 'TEL;CAR' => array('tel_car'), |
||||||
58 | 'TEL;OTHER' => array('tel_other'), |
||||||
59 | 'TEL;VOICE;WORK' => array('tel_work'), |
||||||
60 | 'TEL;FAX;WORK' => array('tel_fax'), |
||||||
61 | 'TEL;HOME;VOICE' => array('tel_home'), |
||||||
62 | 'TEL;FAX;HOME' => array('tel_fax_home'), |
||||||
63 | 'TEL;PAGER' => array('tel_pager'), |
||||||
64 | 'TITLE' => array('title'), |
||||||
65 | 'URL;WORK' => array('url'), |
||||||
66 | 'URL;HOME' => array('url_home'), |
||||||
67 | 'ROLE' => array('role'), |
||||||
68 | 'NICKNAME' => array('label'), |
||||||
69 | 'FBURL' => array('freebusy_uri'), |
||||||
70 | 'PHOTO' => array('jpegphoto'), |
||||||
71 | 'X-ASSISTANT' => array('assistent'), |
||||||
72 | 'X-ASSISTANT-TEL' => array('tel_assistent'), |
||||||
73 | 'UID' => array('uid'), |
||||||
74 | 'REV' => array('modified'), |
||||||
75 | //'KEY' multivalued with mime-type to export PGP and S/Mime public keys |
||||||
76 | 'KEY' => array('pubkey'), |
||||||
77 | //set for Apple: 'X-ABSHOWAS' => array('fileas_type'), // Horde vCard class uses uppercase prop-names! |
||||||
78 | ); |
||||||
79 | |||||||
80 | var $supportedFields; |
||||||
81 | |||||||
82 | /** |
||||||
83 | * VCard version |
||||||
84 | * |
||||||
85 | * @var string |
||||||
86 | */ |
||||||
87 | var $version; |
||||||
88 | /** |
||||||
89 | * Client CTCap Properties |
||||||
90 | * |
||||||
91 | * @var array |
||||||
92 | */ |
||||||
93 | var $clientProperties; |
||||||
94 | /** |
||||||
95 | * Set Logging |
||||||
96 | * |
||||||
97 | * @var string |
||||||
98 | * off = false; |
||||||
99 | */ |
||||||
100 | var $log = false; |
||||||
101 | var $logfile="/tmp/log-vcard"; |
||||||
102 | /** |
||||||
103 | * Constructor |
||||||
104 | * |
||||||
105 | * @param string $contact_app the current application |
||||||
106 | * @param string $_contentType the content type (version) |
||||||
107 | * @param array $_clientProperties client properties |
||||||
108 | */ |
||||||
109 | function __construct($contact_app='addressbook', $_contentType='text/x-vcard', &$_clientProperties = array()) |
||||||
110 | { |
||||||
111 | parent::__construct($contact_app); |
||||||
112 | if ($this->log) |
||||||
113 | { |
||||||
114 | $this->logfile = $GLOBALS['egw_info']['server']['temp_dir']."/log-vcard"; |
||||||
115 | error_log(__FILE__.'['.__LINE__.'] '.__METHOD__."()\n" . |
||||||
116 | array2string($_contentType)."\n",3,$this->logfile); |
||||||
117 | } |
||||||
118 | switch($_contentType) |
||||||
119 | { |
||||||
120 | case 'text/vcard': |
||||||
121 | $this->version = '3.0'; |
||||||
122 | break; |
||||||
123 | default: |
||||||
124 | $this->version = '2.1'; |
||||||
125 | break; |
||||||
126 | } |
||||||
127 | $this->clientProperties = $_clientProperties; |
||||||
128 | $this->supportedFields = $this->databaseFields; |
||||||
129 | } |
||||||
130 | /** |
||||||
131 | * import a vard into addressbook |
||||||
132 | * |
||||||
133 | * @param string $_vcard the vcard |
||||||
134 | * @param int/string $_abID =null the internal addressbook id or !$_abID for a new enty |
||||||
0 ignored issues
–
show
Documentation
Bug
introduced
by
![]() |
|||||||
135 | * @param boolean $merge =false merge data with existing entry |
||||||
136 | * @param string $charset The encoding charset for $text. Defaults to |
||||||
137 | * utf-8 for new format, iso-8859-1 for old format. |
||||||
138 | * @return int contact id |
||||||
139 | */ |
||||||
140 | function addVCard($_vcard, $_abID=null, $merge=false, $charset=null) |
||||||
141 | { |
||||||
142 | if (!($contact = $this->vcardtoegw($_vcard, $charset))) return false; |
||||||
143 | |||||||
144 | if ($_abID) |
||||||
145 | { |
||||||
146 | if (($old_contact = $this->read($_abID))) |
||||||
147 | { |
||||||
148 | $contact['photo_unchanged'] = $old_contact['jpegphoto'] === $contact['jpegphoto']; |
||||||
149 | if ($merge) |
||||||
150 | { |
||||||
151 | foreach (array_keys($contact) as $key) |
||||||
152 | { |
||||||
153 | if (!empty($old_contact[$key])) |
||||||
154 | { |
||||||
155 | $contact[$key] = $old_contact[$key]; |
||||||
156 | } |
||||||
157 | } |
||||||
158 | } |
||||||
159 | else |
||||||
160 | { |
||||||
161 | if (isset($old_contact['account_id'])) |
||||||
162 | { |
||||||
163 | $contact['account_id'] = $old_contact['account_id']; |
||||||
164 | } |
||||||
165 | if (is_array($contact['cat_id'])) |
||||||
166 | { |
||||||
167 | $contact['cat_id'] = implode(',',$this->find_or_add_categories($contact['cat_id'], $_abID)); |
||||||
168 | } |
||||||
169 | else |
||||||
170 | { |
||||||
171 | // restore from orignal |
||||||
172 | $contact['cat_id'] = $old_contact['cat_id']; |
||||||
173 | } |
||||||
174 | } |
||||||
175 | } |
||||||
176 | // update entry |
||||||
177 | $contact['id'] = $_abID; |
||||||
178 | } |
||||||
179 | else |
||||||
180 | { |
||||||
181 | // If photo is set, we want to update it |
||||||
182 | $contact['photo_unchanged'] = false; |
||||||
183 | if (is_array($contact['cat_id'])) |
||||||
184 | { |
||||||
185 | $contact['cat_id'] = implode(',',$this->find_or_add_categories($contact['cat_id'], -1)); |
||||||
186 | } |
||||||
187 | } |
||||||
188 | if (isset($contact['owner']) && $contact['owner'] != $this->user) |
||||||
189 | { |
||||||
190 | $contact['private'] = 0; // foreign contacts are never private! |
||||||
191 | } |
||||||
192 | if ($this->log) |
||||||
193 | { |
||||||
194 | error_log(__FILE__.'['.__LINE__.'] '.__METHOD__."()\n" . |
||||||
195 | array2string($contact)."\n",3,$this->logfile); |
||||||
196 | } |
||||||
197 | return $this->save($contact); |
||||||
198 | } |
||||||
199 | |||||||
200 | /** |
||||||
201 | * return a vcard |
||||||
202 | * |
||||||
203 | * @param int/string $_id the id of the contact |
||||||
0 ignored issues
–
show
|
|||||||
204 | * @param string $_charset ='UTF-8' encoding of the vcard, default UTF-8 |
||||||
205 | * @param boolean $extra_charset_attribute =true GroupDAV/CalDAV dont need the charset attribute and some clients have problems with it |
||||||
206 | * @return string containing the vcard |
||||||
207 | */ |
||||||
208 | function getVCard($_id,$_charset='UTF-8',$extra_charset_attribute=true) |
||||||
209 | { |
||||||
210 | $vCard = new Horde_Icalendar_Vcard($this->version); |
||||||
211 | $vCard->setAttribute('PRODID','-//EGroupware//NONSGML EGroupware Addressbook '.$GLOBALS['egw_info']['apps']['api']['version'].'//'. |
||||||
212 | strtoupper($GLOBALS['egw_info']['user']['preferences']['common']['lang'])); |
||||||
213 | |||||||
214 | $sysCharSet = Api\Translation::charset(); |
||||||
215 | |||||||
216 | // KAddressbook and Funambol4BlackBerry always requires non-ascii chars to be qprint encoded. |
||||||
217 | if ($this->productName == 'kde' || |
||||||
218 | ($this->productManufacturer == 'funambol' && $this->productName == 'blackberry plug-in')) |
||||||
219 | { |
||||||
220 | $extra_charset_attribute = true; |
||||||
221 | } |
||||||
222 | |||||||
223 | if (!($entry = $this->read($_id))) |
||||||
224 | { |
||||||
225 | return false; |
||||||
226 | } |
||||||
227 | |||||||
228 | $this->fixup_contact($entry); |
||||||
229 | |||||||
230 | foreach ($this->supportedFields as $vcardField => $databaseFields) |
||||||
231 | { |
||||||
232 | $values = array(); |
||||||
233 | $options = array(); |
||||||
234 | $hasdata = 0; |
||||||
235 | // seperate fields from their options/attributes |
||||||
236 | $vcardFields = explode(';', $vcardField); |
||||||
237 | $vcardField = $vcardFields[0]; |
||||||
238 | $i = 1; |
||||||
239 | while (isset($vcardFields[$i])) |
||||||
240 | { |
||||||
241 | list($oname, $oval) = explode('=', $vcardFields[$i]); |
||||||
242 | if (!$oval && ($this->version == '3.0')) |
||||||
243 | { |
||||||
244 | // declare OPTION as TYPE=OPTION |
||||||
245 | $options['TYPE'][] = $oname ; |
||||||
246 | } |
||||||
247 | else |
||||||
248 | { |
||||||
249 | $options[$oname] = $oval; |
||||||
250 | } |
||||||
251 | $i++; |
||||||
252 | } |
||||||
253 | if (is_array($options['TYPE'])) |
||||||
254 | { |
||||||
255 | $oval = implode(",", $options['TYPE']); |
||||||
256 | unset($options['TYPE']); |
||||||
257 | $options['TYPE'] = $oval; |
||||||
258 | } |
||||||
259 | if (isset($this->clientProperties[$vcardField]['Size'])) |
||||||
260 | { |
||||||
261 | $size = $this->clientProperties[$vcardField]['Size']; |
||||||
262 | $noTruncate = $this->clientProperties[$vcardField]['NoTruncate']; |
||||||
263 | if ($this->log && $size > 0) |
||||||
264 | { |
||||||
265 | error_log(__FILE__.'['.__LINE__.'] '.__METHOD__ . |
||||||
266 | "() $vcardField Size: $size, NoTruncate: " . |
||||||
267 | ($noTruncate ? 'TRUE' : 'FALSE') . "\n",3,$this->logfile); |
||||||
268 | } |
||||||
269 | //Horde::logMessage("vCalAddressbook $vcardField Size: $size, NoTruncate: " . |
||||||
270 | // ($noTruncate ? 'TRUE' : 'FALSE'), __FILE__, __LINE__, PEAR_LOG_DEBUG); |
||||||
271 | } |
||||||
272 | else |
||||||
273 | { |
||||||
274 | $size = -1; |
||||||
275 | $noTruncate = false; |
||||||
276 | } |
||||||
277 | foreach ($databaseFields as $databaseField) |
||||||
278 | { |
||||||
279 | $value = ''; |
||||||
280 | |||||||
281 | if (!empty($databaseField)) |
||||||
282 | { |
||||||
283 | $value = trim($entry[$databaseField]); |
||||||
284 | } |
||||||
285 | |||||||
286 | switch ($databaseField) |
||||||
287 | { |
||||||
288 | case 'modified': |
||||||
289 | $value = gmdate("Y-m-d\TH:i:s\Z",Api\DateTime::user2server($value)); |
||||||
290 | $hasdata++; |
||||||
291 | break; |
||||||
292 | |||||||
293 | case 'private': |
||||||
294 | $value = $value ? 'PRIVATE' : 'PUBLIC'; |
||||||
295 | $hasdata++; |
||||||
296 | break; |
||||||
297 | |||||||
298 | case 'bday': |
||||||
299 | if (!empty($value)) |
||||||
300 | { |
||||||
301 | if ($size == 8) |
||||||
302 | { |
||||||
303 | $value = str_replace('-','',$value); |
||||||
304 | } |
||||||
305 | elseif (isset($options['TYPE']) && ( |
||||||
306 | $options['TYPE'] == 'BASIC')) |
||||||
307 | { |
||||||
308 | unset($options['TYPE']); |
||||||
309 | // used by old SyncML implementations |
||||||
310 | $value = str_replace('-','',$value).'T000000Z'; |
||||||
311 | } |
||||||
312 | $hasdata++; |
||||||
313 | } |
||||||
314 | break; |
||||||
315 | |||||||
316 | case 'jpegphoto': |
||||||
317 | if (empty($value) && ($entry['files'] & Api\Contacts::FILES_BIT_PHOTO)) |
||||||
318 | { |
||||||
319 | $value = file_get_contents(Api\Link::vfs_path('addressbook', $entry['id'], Api\Contacts::FILES_PHOTO)); |
||||||
320 | } |
||||||
321 | if (!empty($value) && |
||||||
322 | (($size < 0) || (strlen($value) < $size))) |
||||||
323 | { |
||||||
324 | if (!isset($options['TYPE'])) |
||||||
325 | { |
||||||
326 | $options['TYPE'] = 'JPEG'; |
||||||
327 | } |
||||||
328 | if (!isset($options['ENCODING'])) |
||||||
329 | { |
||||||
330 | $options['ENCODING'] = 'BASE64'; |
||||||
331 | } |
||||||
332 | $hasdata++; |
||||||
333 | // need to encode binary image, not done in Horde Icalendar |
||||||
334 | $value = base64_encode($value); |
||||||
335 | } |
||||||
336 | else |
||||||
337 | { |
||||||
338 | $value = ''; |
||||||
339 | } |
||||||
340 | break; |
||||||
341 | |||||||
342 | case 'pubkey': // for now we only export S/Mime publik key, as no device supports PGP |
||||||
343 | // https://en.wikipedia.org/wiki/VCard (search for "KEY") |
||||||
344 | if (($value = $this->get_key($entry, false))) |
||||||
345 | { |
||||||
346 | $options['TYPE'] = 'SMIME'; |
||||||
347 | $options['MEDIATYPE'] = 'application/x-x509-user-cert'; |
||||||
348 | $options['ENCODING'] = $this->version == '3.0' ? 'b' : 'BASE64'; |
||||||
349 | $value = base64_encode($value); |
||||||
350 | $hasdata++; |
||||||
351 | } |
||||||
352 | break; |
||||||
353 | |||||||
354 | case 'cat_id': |
||||||
355 | if (!empty($value) && ($values = /*str_replace(',','\\,',*/$this->get_categories($value)))//) |
||||||
356 | { |
||||||
357 | $values = (array) Api\Translation::convert($values, $sysCharSet, $_charset); |
||||||
358 | $value = implode(',', $values); // just for the CHARSET recognition |
||||||
359 | if (($size > 0) && strlen($value) > $size) |
||||||
360 | { |
||||||
361 | // let us try with only the first category |
||||||
362 | $value = $values[0]; |
||||||
363 | if (strlen($value) > $size) |
||||||
364 | { |
||||||
365 | if ($this->log) |
||||||
366 | { |
||||||
367 | error_log(__FILE__.'['.__LINE__.'] '.__METHOD__ . |
||||||
368 | "() $vcardField omitted due to maximum size $size\n",3,$this->logfile); |
||||||
369 | } |
||||||
370 | // Horde::logMessage("vCalAddressbook $vcardField omitted due to maximum size $size", |
||||||
371 | // __FILE__, __LINE__, PEAR_LOG_WARNING); |
||||||
372 | continue; |
||||||
373 | } |
||||||
374 | $values = array(); |
||||||
375 | } |
||||||
376 | if (preg_match('/[^\x20-\x7F]/', $value)) |
||||||
377 | { |
||||||
378 | if ($extra_charset_attribute || $this->productName == 'kde') |
||||||
379 | { |
||||||
380 | $options['CHARSET'] = $_charset; |
||||||
381 | } |
||||||
382 | // KAddressbook requires non-ascii chars to be qprint encoded, other clients eg. nokia phones have trouble with that |
||||||
383 | if ($this->productName == 'kde') |
||||||
384 | { |
||||||
385 | $options['ENCODING'] = 'QUOTED-PRINTABLE'; |
||||||
386 | } |
||||||
387 | elseif ($this->productManufacturer == 'funambol') |
||||||
388 | { |
||||||
389 | $options['ENCODING'] = 'FUNAMBOL-QP'; |
||||||
390 | } |
||||||
391 | elseif (preg_match(Api\CalDAV\Handler::REQUIRE_QUOTED_PRINTABLE_ENCODING, $value)) |
||||||
392 | { |
||||||
393 | $options['ENCODING'] = 'QUOTED-PRINTABLE'; |
||||||
394 | } |
||||||
395 | elseif (!$extra_charset_attribute) |
||||||
396 | { |
||||||
397 | unset($options['ENCODING']); |
||||||
398 | } |
||||||
399 | } |
||||||
400 | $hasdata++; |
||||||
401 | } |
||||||
402 | break; |
||||||
403 | |||||||
404 | case 'n_fn': |
||||||
405 | case 'fileas_type': |
||||||
406 | // mark entries with fileas_type == 'org_name' as X-ABSHOWAS:COMPANY (Apple AB specific) |
||||||
407 | if (isset($this->supportedFields['X-ABSHOWAS']) && |
||||||
408 | $entry['org_name'] == $entry['n_fileas'] && $entry['fileas_type'] == 'org_name') |
||||||
409 | { |
||||||
410 | if ($vcardField == 'X-ABSHOWAS') $value = 'COMPANY'; |
||||||
411 | if ($databaseField == 'n_fn') $value = $entry['org_name']; |
||||||
412 | } |
||||||
413 | //error_log("vcardField='$vcardField', databaseField='$databaseField', this->supportedFields['X-ABSHOWAS']=".array2string($this->supportedFields['X-ABSHOWAS'])." --> value='$value'"); |
||||||
414 | // fall-through |
||||||
415 | |||||||
416 | default: |
||||||
417 | if (($size > 0) && strlen(implode(',', $values) . $value) > $size) |
||||||
418 | { |
||||||
419 | if ($noTruncate) |
||||||
420 | { |
||||||
421 | if ($this->log) |
||||||
422 | { |
||||||
423 | error_log(__FILE__.'['.__LINE__.'] '.__METHOD__ . |
||||||
424 | "() $vcardField omitted due to maximum size $size\n",3,$this->logfile); |
||||||
425 | } |
||||||
426 | // Horde::logMessage("vCalAddressbook $vcardField omitted due to maximum size $size", |
||||||
427 | // __FILE__, __LINE__, PEAR_LOG_WARNING); |
||||||
428 | continue; |
||||||
429 | } |
||||||
430 | // truncate the value to size |
||||||
431 | $cursize = strlen(implode('', $values)); |
||||||
432 | $left = $size - $cursize - count($databaseFields) + 1; |
||||||
433 | if ($left > 0) |
||||||
434 | { |
||||||
435 | $value = substr($value, 0, $left); |
||||||
436 | } |
||||||
437 | else |
||||||
438 | { |
||||||
439 | $value = ''; |
||||||
440 | } |
||||||
441 | if ($this->log) |
||||||
442 | { |
||||||
443 | error_log(__FILE__.'['.__LINE__.'] '.__METHOD__ . |
||||||
444 | "() $vcardField truncated to maximum size $size\n",3,$this->logfile); |
||||||
445 | } |
||||||
446 | //Horde::logMessage("vCalAddressbook $vcardField truncated to maximum size $size", |
||||||
447 | // __FILE__, __LINE__, PEAR_LOG_INFO); |
||||||
448 | } |
||||||
449 | if (!empty($value) // required field |
||||||
450 | || in_array($vcardField,array('FN','ORG','N')) |
||||||
451 | || ($size >= 0 && !$noTruncate)) |
||||||
452 | { |
||||||
453 | $value = Api\Translation::convert(trim($value), $sysCharSet, $_charset); |
||||||
454 | $values[] = $value; |
||||||
455 | if ($this->version == '2.1' && preg_match('/[^\x20-\x7F]/', $value)) |
||||||
456 | { |
||||||
457 | if ($extra_charset_attribute || $this->productName == 'kde') |
||||||
458 | { |
||||||
459 | $options['CHARSET'] = $_charset; |
||||||
460 | } |
||||||
461 | // KAddressbook requires non-ascii chars to be qprint encoded, other clients eg. nokia phones have trouble with that |
||||||
462 | if ($this->productName == 'kde') |
||||||
463 | { |
||||||
464 | $options['ENCODING'] = 'QUOTED-PRINTABLE'; |
||||||
465 | } |
||||||
466 | elseif ($this->productManufacturer == 'funambol') |
||||||
467 | { |
||||||
468 | $options['ENCODING'] = 'FUNAMBOL-QP'; |
||||||
469 | } |
||||||
470 | elseif (preg_match(Api\CalDAV\Handler::REQUIRE_QUOTED_PRINTABLE_ENCODING, $value)) |
||||||
471 | { |
||||||
472 | $options['ENCODING'] = 'QUOTED-PRINTABLE'; |
||||||
473 | } |
||||||
474 | elseif (!$extra_charset_attribute) |
||||||
475 | { |
||||||
476 | unset($options['ENCODING']); |
||||||
477 | } |
||||||
478 | } |
||||||
479 | if ($vcardField == 'TEL' && $entry['tel_prefer'] && |
||||||
480 | ($databaseField == $entry['tel_prefer'])) |
||||||
481 | { |
||||||
482 | if ($options['TYPE']) |
||||||
483 | { |
||||||
484 | $options['TYPE'] .= ','; |
||||||
485 | } |
||||||
486 | $options['TYPE'] .= 'PREF'; |
||||||
487 | } |
||||||
488 | $hasdata++; |
||||||
489 | } |
||||||
490 | else |
||||||
491 | { |
||||||
492 | $values[] = ''; |
||||||
493 | } |
||||||
494 | break; |
||||||
495 | } |
||||||
496 | } |
||||||
497 | |||||||
498 | if ($hasdata <= 0) |
||||||
499 | { |
||||||
500 | // don't add the entry if there is no data for this field, |
||||||
501 | // except it's a mendatory field |
||||||
502 | continue; |
||||||
503 | } |
||||||
504 | |||||||
505 | $vCard->setAttribute($vcardField, $value, $options, true, $values); |
||||||
506 | } |
||||||
507 | |||||||
508 | // current iOS 8.4 shows TEL;TYPE="WORK,VOICE":+49 123 4567890 as '"WORK' |
||||||
509 | // old (patched) Horde iCalendar, did not enclosed parameter in quotes |
||||||
510 | $result = preg_replace('/^TEL;TYPE="([^"]+)":/m', 'TEL;TYPE=$1:', |
||||||
511 | $vCard->exportvCalendar($_charset)); |
||||||
0 ignored issues
–
show
The call to
Horde_Icalendar_Vcard::exportvCalendar() has too many arguments starting with $_charset .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue. If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above. ![]() |
|||||||
512 | |||||||
513 | if ($this->log) |
||||||
514 | { |
||||||
515 | error_log(__FILE__.'['.__LINE__.'] '.__METHOD__ . |
||||||
516 | "() '$this->productManufacturer','$this->productName'\n",3,$this->logfile); |
||||||
517 | error_log(__FILE__.'['.__LINE__.'] '.__METHOD__."()\n" . |
||||||
518 | array2string($result)."\n",3,$this->logfile); |
||||||
519 | } |
||||||
520 | return $result; |
||||||
521 | } |
||||||
522 | |||||||
523 | function search($_vcard, $contentID=null, $relax=false, $charset=null) |
||||||
524 | { |
||||||
525 | $result = array(); |
||||||
526 | |||||||
527 | if (($contact = $this->vcardtoegw($_vcard, $charset))) |
||||||
528 | { |
||||||
529 | if (is_array($contact['category'])) |
||||||
530 | { |
||||||
531 | $contact['category'] = implode(',',$this->find_or_add_categories($contact['category'], |
||||||
532 | $contentID ? $contentID : -1)); |
||||||
533 | } |
||||||
534 | if ($contentID) |
||||||
535 | { |
||||||
536 | $contact['id'] = $contentID; |
||||||
537 | } |
||||||
538 | $result = $this->find_contact($contact, $relax); |
||||||
539 | } |
||||||
540 | return $result; |
||||||
541 | } |
||||||
542 | |||||||
543 | function setSupportedFields($_productManufacturer='file', $_productName='', $_supportedFields = null) |
||||||
544 | { |
||||||
545 | $this->productManufacturer = strtolower($_productManufacturer); |
||||||
546 | $this->productName = strtolower($_productName); |
||||||
547 | |||||||
548 | if (is_array($_supportedFields)) $this->supportedFields = $_supportedFields; |
||||||
549 | } |
||||||
550 | |||||||
551 | function setDatabaseFields($_databaseFields) |
||||||
552 | { |
||||||
553 | if (is_array($_databaseFields)) $this->databaseFields = $_databaseFields; |
||||||
554 | } |
||||||
555 | |||||||
556 | /** |
||||||
557 | * Parses a string containing vCard data. |
||||||
558 | * |
||||||
559 | * @param string $_vcard The data to parse. |
||||||
560 | * @param string $charset The encoding charset for $text. Defaults to |
||||||
561 | * utf-8 for new format, iso-8859-1 for old format. |
||||||
562 | * |
||||||
563 | * @return array|boolean The contact data or false on errors. |
||||||
564 | */ |
||||||
565 | function vcardtoegw($_vcard, $charset=null) |
||||||
566 | { |
||||||
567 | // the horde class does the charset conversion. DO NOT CONVERT HERE. |
||||||
568 | // be as flexible as possible |
||||||
569 | |||||||
570 | if ($this->log) |
||||||
571 | { |
||||||
572 | error_log(__FILE__.'['.__LINE__.'] '.__METHOD__."()\n" . |
||||||
573 | array2string($_vcard)."\n",3,$this->logfile); |
||||||
574 | } |
||||||
575 | |||||||
576 | if(!($_vcard instanceof Horde_Icalendar)) |
||||||
0 ignored issues
–
show
|
|||||||
577 | { |
||||||
578 | $container = false; |
||||||
579 | $vCard = Horde_Icalendar::newComponent('vcard', $container); |
||||||
580 | |||||||
581 | if ($charset && $charset != 'utf-8') |
||||||
582 | { |
||||||
583 | $_vcard = Api\Translation::convert($_vcard, $charset, 'utf-8'); |
||||||
584 | } |
||||||
585 | if (!$vCard->parsevCalendar($_vcard, 'VCARD')) |
||||||
586 | { |
||||||
587 | return False; |
||||||
588 | } |
||||||
589 | } |
||||||
590 | else |
||||||
591 | { |
||||||
592 | $vCard = $_vcard; |
||||||
593 | } |
||||||
594 | $vcardValues = $vCard->getAllAttributes(); |
||||||
595 | |||||||
596 | if (!empty($GLOBALS['egw_info']['user']['preferences']['syncml']['minimum_uid_length'])) |
||||||
597 | { |
||||||
598 | $minimum_uid_length = $GLOBALS['egw_info']['user']['preferences']['syncml']['minimum_uid_length']; |
||||||
599 | } |
||||||
600 | else |
||||||
601 | { |
||||||
602 | $minimum_uid_length = 8; |
||||||
603 | } |
||||||
604 | |||||||
605 | #print "<pre>$_vcard</pre>"; |
||||||
606 | |||||||
607 | #error_log(print_r($vcardValues, true)); |
||||||
608 | //Horde::logMessage("vCalAddressbook vcardtoegw: " . print_r($vcardValues, true), __FILE__, __LINE__, PEAR_LOG_DEBUG); |
||||||
609 | |||||||
610 | $email = 1; |
||||||
611 | $tel = 1; |
||||||
612 | $cell = 1; |
||||||
613 | $url = 1; |
||||||
614 | $pref_tel = false; |
||||||
615 | |||||||
616 | $rowNames = array(); |
||||||
617 | foreach($vcardValues as $key => $vcardRow) |
||||||
618 | { |
||||||
619 | $rowName = strtoupper($vcardRow['name']); |
||||||
620 | if ($vcardRow['value'] == '' && implode('', $vcardRow['values']) == '') |
||||||
621 | { |
||||||
622 | unset($vcardRow); |
||||||
623 | continue; |
||||||
624 | } |
||||||
625 | $rowTypes = array(); |
||||||
626 | |||||||
627 | $vcardRow['uparams'] = array(); |
||||||
628 | foreach ($vcardRow['params'] as $pname => $params) |
||||||
629 | { |
||||||
630 | $pname = strtoupper($pname); |
||||||
631 | $vcardRow['uparams'][$pname] = $params; |
||||||
632 | } |
||||||
633 | |||||||
634 | |||||||
635 | // expand 3.0 TYPE paramters to 2.1 qualifiers |
||||||
636 | $vcardRow['tparams'] = array(); |
||||||
637 | foreach ($vcardRow['uparams'] as $pname => $params) |
||||||
638 | { |
||||||
639 | switch ($pname) |
||||||
640 | { |
||||||
641 | case 'TYPE': |
||||||
642 | if (is_array($params)) |
||||||
643 | { |
||||||
644 | $rowTypes = array(); |
||||||
645 | foreach ($params as $param) |
||||||
646 | { |
||||||
647 | $rowTypes[] = strtoupper($param); |
||||||
648 | } |
||||||
649 | } |
||||||
650 | else |
||||||
651 | { |
||||||
652 | $rowTypes[] = strtoupper($params); |
||||||
653 | } |
||||||
654 | foreach ($rowTypes as $type) |
||||||
655 | { |
||||||
656 | switch ($type) |
||||||
657 | { |
||||||
658 | |||||||
659 | case 'OTHER': |
||||||
660 | case 'WORK': |
||||||
661 | case 'HOME': |
||||||
662 | $vcardRow['tparams'][$type] = ''; |
||||||
663 | break; |
||||||
664 | case 'CELL': |
||||||
665 | case 'PAGER': |
||||||
666 | case 'FAX': |
||||||
667 | case 'VOICE': |
||||||
668 | case 'CAR': |
||||||
669 | case 'PREF': |
||||||
670 | case 'X-CUSTOMLABEL-CAR': |
||||||
671 | case 'X-CUSTOMLABEL-IPHONE': |
||||||
672 | case 'IPHONE': |
||||||
673 | if ($vcardRow['name'] == 'TEL') |
||||||
0 ignored issues
–
show
Coding Style
Comprehensibility
introduced
by
|
|||||||
674 | { |
||||||
675 | $vcardRow['tparams'][$type] = ''; |
||||||
676 | } |
||||||
677 | default: |
||||||
678 | break; |
||||||
679 | } |
||||||
680 | } |
||||||
681 | break; |
||||||
682 | default: |
||||||
683 | break; |
||||||
684 | } |
||||||
685 | } |
||||||
686 | |||||||
687 | $vcardRow['uparams'] += $vcardRow['tparams']; |
||||||
688 | ksort($vcardRow['uparams']); |
||||||
689 | |||||||
690 | foreach ($vcardRow['uparams'] as $pname => $params) |
||||||
691 | { |
||||||
692 | switch ($pname) |
||||||
693 | { |
||||||
694 | case 'PREF': |
||||||
695 | if (substr($rowName,0,3) == 'TEL' && !$pref_tel) |
||||||
696 | { |
||||||
697 | $pref_tel = $key; |
||||||
698 | } |
||||||
699 | break; |
||||||
700 | case 'FAX': |
||||||
701 | case 'PAGER': |
||||||
702 | case 'VOICE': |
||||||
703 | case 'OTHER': |
||||||
704 | case 'CELL': |
||||||
705 | if ($rowName != 'TEL') break; |
||||||
706 | case 'WORK': |
||||||
707 | case 'HOME': |
||||||
708 | $rowName .= ';' . $pname; |
||||||
709 | break; |
||||||
710 | case 'CAR': |
||||||
711 | case 'X-CUSTOMLABEL-CAR': |
||||||
712 | if ($rowName == 'TEL') |
||||||
713 | { |
||||||
714 | $rowName = 'TEL;CAR'; |
||||||
715 | } |
||||||
716 | break; |
||||||
717 | case 'X-CUSTOMLABEL-IPHONE': |
||||||
718 | case 'IPHONE': |
||||||
719 | if ($rowName == 'TEL' || $rowName == 'TEL;CELL') |
||||||
720 | { |
||||||
721 | $rowName = 'TEL;CELL;HOME'; |
||||||
722 | } |
||||||
723 | break; |
||||||
724 | default: |
||||||
725 | if (strpos($pname, 'X-FUNAMBOL-') === 0) |
||||||
726 | { |
||||||
727 | // Propriatary Funambol extension will be ignored |
||||||
728 | $rowName .= ';' . $pname; |
||||||
729 | } |
||||||
730 | break; |
||||||
731 | } |
||||||
732 | } |
||||||
733 | |||||||
734 | if ($rowName == 'EMAIL') |
||||||
735 | { |
||||||
736 | $rowName .= ';X-egw-Ref' . $email++; |
||||||
737 | } |
||||||
738 | |||||||
739 | if (($rowName == 'TEL;CELL') || |
||||||
740 | ($rowName == 'TEL;CELL;VOICE')) |
||||||
741 | { |
||||||
742 | $rowName = 'TEL;CELL;X-egw-Ref' . $cell++; |
||||||
743 | } |
||||||
744 | |||||||
745 | if (($rowName == 'TEL') || |
||||||
746 | ($rowName == 'TEL;VOICE')) |
||||||
747 | { |
||||||
748 | $rowName = 'TEL;X-egw-Ref' . $tel++; |
||||||
749 | } |
||||||
750 | |||||||
751 | if ($rowName == 'URL') |
||||||
752 | { |
||||||
753 | $rowName = 'URL;X-egw-Ref' . $url++; |
||||||
754 | } |
||||||
755 | |||||||
756 | // current algorithm cant cope with multiple attributes of same name |
||||||
757 | // --> cumulate them in values, so they can be used later (works only for values, not for parameters!) |
||||||
758 | if (($k = array_search($rowName, $rowNames)) != false) |
||||||
0 ignored issues
–
show
|
|||||||
759 | { |
||||||
760 | $vcardValues[$k]['values'] = array_merge($vcardValues[$k]['values'],$vcardValues[$key]['values']); |
||||||
761 | } |
||||||
762 | $rowNames[$key] = $rowName; |
||||||
763 | } |
||||||
764 | |||||||
765 | if ($this->log) |
||||||
766 | { |
||||||
767 | error_log(__FILE__.'['.__LINE__.'] '.__METHOD__."()\n" . |
||||||
768 | array2string($rowNames)."\n",3,$this->logfile); |
||||||
769 | } |
||||||
770 | |||||||
771 | // All rowNames of the vCard are now concatenated with their qualifiers. |
||||||
772 | // If qualifiers are missing we apply a default strategy. |
||||||
773 | // E.g. ADR will be either ADR;WORK, if no ADR;WORK is given, |
||||||
774 | // or else ADR;HOME, if not available elsewhere. |
||||||
775 | |||||||
776 | $finalRowNames = array(); |
||||||
777 | |||||||
778 | foreach ($rowNames as $vcardKey => $rowName) |
||||||
779 | { |
||||||
780 | switch ($rowName) |
||||||
781 | { |
||||||
782 | case 'VERSION': |
||||||
783 | break; |
||||||
784 | case 'ADR': |
||||||
785 | if (!in_array('ADR;WORK', $rowNames) |
||||||
786 | && !isset($finalRowNames['ADR;WORK'])) |
||||||
787 | { |
||||||
788 | $finalRowNames['ADR;WORK'] = $vcardKey; |
||||||
789 | } |
||||||
790 | elseif (!in_array('ADR;HOME', $rowNames) |
||||||
791 | && !isset($finalRowNames['ADR;HOME'])) |
||||||
792 | { |
||||||
793 | $finalRowNames['ADR;HOME'] = $vcardKey; |
||||||
794 | } |
||||||
795 | break; |
||||||
796 | case 'TEL;FAX': |
||||||
797 | if (!in_array('TEL;FAX;WORK', $rowNames) |
||||||
798 | && !isset($finalRowNames['TEL;FAX;WORK'])) |
||||||
799 | { |
||||||
800 | $finalRowNames['TEL;FAX;WORK'] = $vcardKey; |
||||||
801 | } |
||||||
802 | elseif (!in_array('TEL;FAX;HOME', $rowNames) |
||||||
803 | && !isset($finalRowNames['TEL;FAX;HOME'])) |
||||||
804 | { |
||||||
805 | $finalRowNames['TEL;FAX;HOME'] = $vcardKey; |
||||||
806 | } |
||||||
807 | break; |
||||||
808 | case 'TEL;WORK': |
||||||
809 | if (!in_array('TEL;VOICE;WORK', $rowNames) |
||||||
810 | && !isset($finalRowNames['TEL;VOICE;WORK'])) |
||||||
811 | { |
||||||
812 | $finalRowNames['TEL;VOICE;WORK'] = $vcardKey; |
||||||
813 | } |
||||||
814 | break; |
||||||
815 | case 'TEL;HOME': |
||||||
816 | if (!in_array('TEL;HOME;VOICE', $rowNames) |
||||||
817 | && !isset($finalRowNames['TEL;HOME;VOICE'])) |
||||||
818 | { |
||||||
819 | $finalRowNames['TEL;HOME;VOICE'] = $vcardKey; |
||||||
820 | } |
||||||
821 | break; |
||||||
822 | case 'TEL;OTHER;VOICE': |
||||||
823 | if (!in_array('TEL;OTHER', $rowNames) |
||||||
824 | && !isset($finalRowNames['TEL;OTHER'])) |
||||||
825 | { |
||||||
826 | $finalRowNames['TEL;OTHER'] = $vcardKey; |
||||||
827 | } |
||||||
828 | break; |
||||||
829 | case 'TEL;PAGER;WORK': |
||||||
830 | case 'TEL;PAGER;HOME': |
||||||
831 | if (!in_array('TEL;PAGER', $rowNames) |
||||||
832 | && !isset($finalRowNames['TEL;PAGER'])) |
||||||
833 | { |
||||||
834 | $finalRowNames['TEL;PAGER'] = $vcardKey; |
||||||
835 | } |
||||||
836 | break; |
||||||
837 | case 'TEL;CAR;VOICE': |
||||||
838 | case 'TEL;CAR;CELL': |
||||||
839 | case 'TEL;CAR;CELL;VOICE': |
||||||
840 | if (!isset($finalRowNames['TEL;CAR'])) |
||||||
841 | { |
||||||
842 | $finalRowNames['TEL;CAR'] = $vcardKey; |
||||||
843 | } |
||||||
844 | break; |
||||||
845 | case 'TEL;X-egw-Ref1': |
||||||
846 | if (!in_array('TEL;VOICE;WORK', $rowNames) |
||||||
0 ignored issues
–
show
Coding Style
Comprehensibility
introduced
by
|
|||||||
847 | && !in_array('TEL;WORK', $rowNames) |
||||||
848 | && !isset($finalRowNames['TEL;VOICE;WORK'])) |
||||||
849 | { |
||||||
850 | $finalRowNames['TEL;VOICE;WORK'] = $vcardKey; |
||||||
851 | break; |
||||||
852 | } |
||||||
853 | case 'TEL;X-egw-Ref2': |
||||||
854 | if (!in_array('TEL;HOME;VOICE', $rowNames) |
||||||
0 ignored issues
–
show
Coding Style
Comprehensibility
introduced
by
|
|||||||
855 | && !in_array('TEL;HOME', $rowNames) |
||||||
856 | && !isset($finalRowNames['TEL;HOME;VOICE'])) |
||||||
857 | { |
||||||
858 | $finalRowNames['TEL;HOME;VOICE'] = $vcardKey; |
||||||
859 | break; |
||||||
860 | } |
||||||
861 | case 'TEL;X-egw-Ref3': |
||||||
862 | if (!in_array('TEL;OTHER', $rowNames) |
||||||
863 | && !in_array('TEL;OTHER;VOICE', $rowNames) |
||||||
864 | && !isset($finalRowNames['TEL;OTHER'])) |
||||||
865 | { |
||||||
866 | $finalRowNames['TEL;OTHER'] = $vcardKey; |
||||||
867 | } |
||||||
868 | break; |
||||||
869 | case 'TEL;CELL;X-egw-Ref1': |
||||||
870 | if (!in_array('TEL;CELL;WORK', $rowNames) |
||||||
0 ignored issues
–
show
Coding Style
Comprehensibility
introduced
by
|
|||||||
871 | && !isset($finalRowNames['TEL;CELL;WORK'])) |
||||||
872 | { |
||||||
873 | $finalRowNames['TEL;CELL;WORK'] = $vcardKey; |
||||||
874 | break; |
||||||
875 | } |
||||||
876 | case 'TEL;CELL;X-egw-Ref2': |
||||||
877 | if (!in_array('TEL;CELL;HOME', $rowNames) |
||||||
0 ignored issues
–
show
Coding Style
Comprehensibility
introduced
by
|
|||||||
878 | && !isset($finalRowNames['TEL;CELL;HOME'])) |
||||||
879 | { |
||||||
880 | $finalRowNames['TEL;CELL;HOME'] = $vcardKey; |
||||||
881 | break; |
||||||
882 | } |
||||||
883 | case 'TEL;CELL;X-egw-Ref3': |
||||||
884 | if (!in_array('TEL;CAR', $rowNames) |
||||||
885 | && !in_array('TEL;CAR;VOICE', $rowNames) |
||||||
886 | && !in_array('TEL;CAR;CELL', $rowNames) |
||||||
887 | && !in_array('TEL;CAR;CELL;VOICE', $rowNames) |
||||||
888 | && !isset($finalRowNames['TEL;CAR'])) |
||||||
889 | { |
||||||
890 | $finalRowNames['TEL;CAR'] = $vcardKey; |
||||||
891 | } |
||||||
892 | break; |
||||||
893 | case 'EMAIL;X-egw-Ref1': |
||||||
894 | if (!in_array('EMAIL;WORK', $rowNames) && |
||||||
0 ignored issues
–
show
Coding Style
Comprehensibility
introduced
by
|
|||||||
895 | !isset($finalRowNames['EMAIL;WORK'])) |
||||||
896 | { |
||||||
897 | $finalRowNames['EMAIL;WORK'] = $vcardKey; |
||||||
898 | break; |
||||||
899 | } |
||||||
900 | case 'EMAIL;X-egw-Ref2': |
||||||
901 | if (!in_array('EMAIL;HOME', $rowNames) && |
||||||
902 | !isset($finalRowNames['EMAIL;HOME'])) |
||||||
903 | { |
||||||
904 | $finalRowNames['EMAIL;HOME'] = $vcardKey; |
||||||
905 | } |
||||||
906 | break; |
||||||
907 | case 'URL;X-egw-Ref1': |
||||||
908 | if (!in_array('URL;WORK', $rowNames) && |
||||||
0 ignored issues
–
show
Coding Style
Comprehensibility
introduced
by
|
|||||||
909 | !isset($finalRowNames['URL;WORK'])) |
||||||
910 | { |
||||||
911 | $finalRowNames['URL;WORK'] = $vcardKey; |
||||||
912 | break; |
||||||
913 | } |
||||||
914 | case 'URL;X-egw-Ref2': |
||||||
915 | if (!in_array('URL;HOME', $rowNames) && |
||||||
916 | !isset($finalRowNames['URL;HOME'])) |
||||||
917 | { |
||||||
918 | $finalRowNames['URL;HOME'] = $vcardKey; |
||||||
919 | } |
||||||
920 | break; |
||||||
921 | case 'X-EVOLUTION-ASSISTANT': |
||||||
922 | if (!isset($finalRowNames['X-ASSISTANT'])) |
||||||
923 | { |
||||||
924 | $finalRowNames['X-ASSISTANT'] = $vcardKey; |
||||||
925 | } |
||||||
926 | break; |
||||||
927 | default: |
||||||
928 | if (!isset($finalRowNames[$rowName])) |
||||||
929 | { |
||||||
930 | $finalRowNames[$rowName] = $vcardKey; |
||||||
931 | } |
||||||
932 | break; |
||||||
933 | } |
||||||
934 | } |
||||||
935 | |||||||
936 | if ($this->log) |
||||||
937 | { |
||||||
938 | error_log(__FILE__.'['.__LINE__.'] '.__METHOD__."()\n" . |
||||||
939 | array2string($finalRowNames)."\n",3,$this->logfile); |
||||||
940 | } |
||||||
941 | |||||||
942 | $contact = array(); |
||||||
943 | // to be able to delete fields, we have to set all supported fields to at least null |
||||||
944 | foreach($this->supportedFields as $fields) |
||||||
945 | { |
||||||
946 | foreach($fields as $field) |
||||||
947 | { |
||||||
948 | if ($field != 'fileas_type') $contact[$field] = null; |
||||||
949 | } |
||||||
950 | } |
||||||
951 | |||||||
952 | foreach ($finalRowNames as $key => $vcardKey) |
||||||
953 | { |
||||||
954 | if (isset($this->databaseFields[$key])) |
||||||
955 | { |
||||||
956 | $fieldNames = $this->databaseFields[$key]; |
||||||
957 | foreach ($fieldNames as $fieldKey => $fieldName) |
||||||
958 | { |
||||||
959 | if (!empty($fieldName)) |
||||||
960 | { |
||||||
961 | $value = trim($vcardValues[$vcardKey]['values'][$fieldKey]); |
||||||
962 | |||||||
963 | if ($pref_tel && (($vcardKey == $pref_tel) || |
||||||
964 | ($vcardValues[$vcardKey]['name'] == 'TEL') && |
||||||
965 | ($vcardValues[$vcardKey]['value'] == $vcardValues[$pref_tel]['value']))) |
||||||
966 | { |
||||||
967 | $contact['tel_prefer'] = $fieldName; |
||||||
968 | } |
||||||
969 | switch($fieldName) |
||||||
970 | { |
||||||
971 | case 'bday': |
||||||
972 | $contact[$fieldName] = $vcardValues[$vcardKey]['value']['year'] . |
||||||
973 | '-' . $vcardValues[$vcardKey]['value']['month'] . |
||||||
974 | '-' . $vcardValues[$vcardKey]['value']['mday']; |
||||||
975 | break; |
||||||
976 | |||||||
977 | case 'private': |
||||||
978 | $contact[$fieldName] = (int) ( strtoupper($value) == 'PRIVATE'); |
||||||
979 | break; |
||||||
980 | |||||||
981 | case 'cat_id': |
||||||
982 | $contact[$fieldName] = $vcardValues[$vcardKey]['values']; |
||||||
983 | break; |
||||||
984 | |||||||
985 | case 'jpegphoto': |
||||||
986 | $contact[$fieldName] = $vcardValues[$vcardKey]['value']; |
||||||
987 | if(in_array($vcardValues[$vcardKey]['params']['ENCODING'],array('b','B','BASE64'))) |
||||||
988 | { |
||||||
989 | $contact[$fieldName] = base64_decode($contact[$fieldName]); |
||||||
990 | } |
||||||
991 | break; |
||||||
992 | |||||||
993 | case 'pubkey': |
||||||
994 | $content = $vcardValues[$vcardKey]['value']; |
||||||
995 | if(in_array($vcardValues[$vcardKey]['params']['ENCODING'],array('b','B','BASE64'))) |
||||||
996 | { |
||||||
997 | $content = base64_decode($content); |
||||||
0 ignored issues
–
show
|
|||||||
998 | } |
||||||
999 | if ($vcardValues[$vcardKey]['params']['ENCODING'] === 'SMIME') |
||||||
1000 | { |
||||||
1001 | // ignore re-importing of S/Mime pubkey for now, as we might be called for a new contact |
||||||
1002 | continue; |
||||||
1003 | } |
||||||
1004 | break; |
||||||
1005 | |||||||
1006 | case 'note': |
||||||
1007 | $contact[$fieldName] = str_replace("\r\n", "\n", $vcardValues[$vcardKey]['value']); |
||||||
1008 | break; |
||||||
1009 | |||||||
1010 | case 'fileas_type': |
||||||
1011 | // store Apple's X-ABSHOWAS:COMPANY as fileas_type == 'org_name' |
||||||
1012 | if ($vcardValues[$vcardKey]['value'] == 'COMPANY') |
||||||
1013 | { |
||||||
1014 | $contact[$fieldName] = 'org_name'; |
||||||
1015 | } |
||||||
1016 | break; |
||||||
1017 | |||||||
1018 | case 'uid': |
||||||
1019 | if (strlen($value) < $minimum_uid_length) { |
||||||
1020 | // we don't use it |
||||||
1021 | break; |
||||||
1022 | } |
||||||
1023 | default: |
||||||
1024 | $contact[$fieldName] = $value; |
||||||
1025 | break; |
||||||
1026 | } |
||||||
1027 | } |
||||||
1028 | } |
||||||
1029 | } |
||||||
1030 | // add unsupported attributes as with '##' prefix |
||||||
1031 | elseif(($attribute = $vcardValues[$vcardKey]) && !in_array($attribute['name'],array('PRODID','REV'))) |
||||||
1032 | { |
||||||
1033 | // for attributes with multiple values in multiple lines, merge the values |
||||||
1034 | if (isset($contact['##'.$attribute['name']])) |
||||||
1035 | { |
||||||
1036 | error_log(__METHOD__."() contact['##$attribute[name]'] = ".array2string($contact['##'.$attribute['name']])); |
||||||
1037 | $attribute['values'] = array_merge( |
||||||
1038 | is_array($contact['##'.$attribute['name']]) ? $contact['##'.$attribute['name']]['values'] : (array)$contact['##'.$attribute['name']], |
||||||
1039 | $attribute['values']); |
||||||
1040 | } |
||||||
1041 | $contact['##'.$attribute['name']] = $attribute['params'] || count($attribute['values']) > 1 ? |
||||||
1042 | serialize($attribute) : $attribute['value']; |
||||||
1043 | } |
||||||
1044 | } |
||||||
1045 | |||||||
1046 | $this->fixup_contact($contact); |
||||||
1047 | |||||||
1048 | if ($this->log) |
||||||
1049 | { |
||||||
1050 | error_log(__FILE__.'['.__LINE__.'] '.__METHOD__ . |
||||||
1051 | "() '$this->productManufacturer','$this->productName'\n",3,$this->logfile); |
||||||
1052 | error_log(__FILE__.'['.__LINE__.'] '.__METHOD__."()\n" . |
||||||
1053 | array2string($contact)."\n",3,$this->logfile); |
||||||
1054 | } |
||||||
1055 | return $contact; |
||||||
1056 | } |
||||||
1057 | |||||||
1058 | /** |
||||||
1059 | * Exports some contacts: download or write to a file |
||||||
1060 | * |
||||||
1061 | * @param array $ids contact-ids |
||||||
1062 | * @param string $file filename or null for download |
||||||
1063 | */ |
||||||
1064 | function export($ids, $file=null) |
||||||
1065 | { |
||||||
1066 | if (!$file) |
||||||
1067 | { |
||||||
1068 | $filename = count($ids) == 1 ? Link::title('addressbook',$ids[0]): 'egw_addressbook_'.date('Y-m-d'); |
||||||
1069 | Api\Header\Content::type(($filename ? $filename : 'addressbook').'.vcf','text/x-vcard'); |
||||||
1070 | } |
||||||
1071 | if (!($fp = fopen($file ? $file : 'php://output','w'))) |
||||||
1072 | { |
||||||
1073 | return false; |
||||||
1074 | } |
||||||
1075 | if (isset($GLOBALS['egw_info']['user']['preferences']['addressbook']['vcard_charset'])) |
||||||
1076 | { |
||||||
1077 | $charset = $GLOBALS['egw_info']['user']['preferences']['addressbook']['vcard_charset']; |
||||||
1078 | } |
||||||
1079 | else |
||||||
1080 | { |
||||||
1081 | $charset = 'utf-8'; |
||||||
1082 | } |
||||||
1083 | foreach ($ids as $id) |
||||||
1084 | { |
||||||
1085 | fwrite($fp,$this->getVCard($id, $charset)); |
||||||
1086 | } |
||||||
1087 | fclose($fp); |
||||||
1088 | |||||||
1089 | if (!$file) |
||||||
1090 | { |
||||||
1091 | exit(); |
||||||
0 ignored issues
–
show
|
|||||||
1092 | } |
||||||
1093 | return true; |
||||||
1094 | } |
||||||
1095 | |||||||
1096 | /** |
||||||
1097 | * return a groupVCard |
||||||
1098 | * |
||||||
1099 | * @param array $list values for 'list_uid', 'list_name', 'list_modified', 'members' |
||||||
1100 | * @param string $version ='3.0' vcard version |
||||||
1101 | * @return string containing the vcard |
||||||
1102 | */ |
||||||
1103 | function getGroupVCard(array $list,$version='3.0') |
||||||
1104 | { |
||||||
1105 | $vCard = new Horde_Icalendar_Vcard($version); |
||||||
1106 | $vCard->setAttribute('PRODID','-//EGroupware//NONSGML EGroupware Addressbook '.$GLOBALS['egw_info']['apps']['api']['version'].'//'. |
||||||
1107 | strtoupper($GLOBALS['egw_info']['user']['preferences']['common']['lang'])); |
||||||
1108 | |||||||
1109 | $vCard->setAttribute('N',$list['list_name'],array(),true,array($list['list_name'],'','','','')); |
||||||
1110 | $vCard->setAttribute('FN',$list['list_name']); |
||||||
1111 | |||||||
1112 | $vCard->setAttribute('X-ADDRESSBOOKSERVER-KIND','group'); |
||||||
1113 | foreach($list['members'] as $uid) |
||||||
1114 | { |
||||||
1115 | $vCard->setAttribute('X-ADDRESSBOOKSERVER-MEMBER','urn:uuid:'.$uid); |
||||||
1116 | } |
||||||
1117 | $vCard->setAttribute('REV',Api\DateTime::to($list['list_modified'],'Y-m-d\TH:i:s\Z')); |
||||||
1118 | $vCard->setAttribute('UID',$list['list_uid']); |
||||||
1119 | |||||||
1120 | return $vCard->exportvCalendar(); |
||||||
1121 | } |
||||||
1122 | } |
||||||
1123 |