0
|
1 <?php
|
|
2
|
|
3 /**
|
|
4 +-----------------------------------------------------------------------+
|
|
5 | This file is part of the Roundcube Webmail client |
|
|
6 | Copyright (C) 2008-2012, The Roundcube Dev Team |
|
|
7 | |
|
|
8 | Licensed under the GNU General Public License version 3 or |
|
|
9 | any later version with exceptions for skins & plugins. |
|
|
10 | See the README file for a full license statement. |
|
|
11 | |
|
|
12 | PURPOSE: |
|
|
13 | CSV to vCard data conversion |
|
|
14 +-----------------------------------------------------------------------+
|
|
15 | Author: Aleksander Machniak <alec@alec.pl> |
|
|
16 +-----------------------------------------------------------------------+
|
|
17 */
|
|
18
|
|
19 /**
|
|
20 * CSV to vCard data converter
|
|
21 *
|
|
22 * @package Framework
|
|
23 * @subpackage Addressbook
|
|
24 * @author Aleksander Machniak <alec@alec.pl>
|
|
25 */
|
|
26 class rcube_csv2vcard
|
|
27 {
|
|
28 /**
|
|
29 * CSV to vCard fields mapping
|
|
30 *
|
|
31 * @var array
|
|
32 */
|
|
33 protected $csv2vcard_map = array(
|
|
34 // MS Outlook 2010
|
|
35 'anniversary' => 'anniversary',
|
|
36 'assistants_name' => 'assistant',
|
|
37 'assistants_phone' => 'phone:assistant',
|
|
38 'birthday' => 'birthday',
|
|
39 'business_city' => 'locality:work',
|
|
40 'business_countryregion' => 'country:work',
|
|
41 'business_fax' => 'phone:work,fax',
|
|
42 'business_phone' => 'phone:work',
|
|
43 'business_phone_2' => 'phone:work2',
|
|
44 'business_postal_code' => 'zipcode:work',
|
|
45 'business_state' => 'region:work',
|
|
46 'business_street' => 'street:work',
|
|
47 //'business_street_2' => '',
|
|
48 //'business_street_3' => '',
|
|
49 'car_phone' => 'phone:car',
|
|
50 'categories' => 'groups',
|
|
51 //'children' => '',
|
|
52 'company' => 'organization',
|
|
53 //'company_main_phone' => '',
|
|
54 'department' => 'department',
|
|
55 'email_2_address' => 'email:other',
|
|
56 //'email_2_type' => '',
|
|
57 'email_3_address' => 'email:other',
|
|
58 //'email_3_type' => '',
|
|
59 'email_address' => 'email:pref',
|
|
60 //'email_type' => '',
|
|
61 'first_name' => 'firstname',
|
|
62 'gender' => 'gender',
|
|
63 'home_city' => 'locality:home',
|
|
64 'home_countryregion' => 'country:home',
|
|
65 'home_fax' => 'phone:home,fax',
|
|
66 'home_phone' => 'phone:home',
|
|
67 'home_phone_2' => 'phone:home2',
|
|
68 'home_postal_code' => 'zipcode:home',
|
|
69 'home_state' => 'region:home',
|
|
70 'home_street' => 'street:home',
|
|
71 //'home_street_2' => '',
|
|
72 //'home_street_3' => '',
|
|
73 //'initials' => '',
|
|
74 //'isdn' => '',
|
|
75 'job_title' => 'jobtitle',
|
|
76 //'keywords' => '',
|
|
77 //'language' => '',
|
|
78 'last_name' => 'surname',
|
|
79 //'location' => '',
|
|
80 'managers_name' => 'manager',
|
|
81 'middle_name' => 'middlename',
|
|
82 //'mileage' => '',
|
|
83 'mobile_phone' => 'phone:cell',
|
|
84 'notes' => 'notes',
|
|
85 //'office_location' => '',
|
|
86 'other_city' => 'locality:other',
|
|
87 'other_countryregion' => 'country:other',
|
|
88 'other_fax' => 'phone:other,fax',
|
|
89 'other_phone' => 'phone:other',
|
|
90 'other_postal_code' => 'zipcode:other',
|
|
91 'other_state' => 'region:other',
|
|
92 'other_street' => 'street:other',
|
|
93 //'other_street_2' => '',
|
|
94 //'other_street_3' => '',
|
|
95 'pager' => 'phone:pager',
|
|
96 'primary_phone' => 'phone:pref',
|
|
97 //'profession' => '',
|
|
98 //'radio_phone' => '',
|
|
99 'spouse' => 'spouse',
|
|
100 'suffix' => 'suffix',
|
|
101 'title' => 'title',
|
|
102 'web_page' => 'website:homepage',
|
|
103
|
|
104 // Thunderbird
|
|
105 'birth_day' => 'birthday-d',
|
|
106 'birth_month' => 'birthday-m',
|
|
107 'birth_year' => 'birthday-y',
|
|
108 'display_name' => 'displayname',
|
|
109 'fax_number' => 'phone:fax',
|
|
110 'home_address' => 'street:home',
|
|
111 //'home_address_2' => '',
|
|
112 'home_country' => 'country:home',
|
|
113 'home_zipcode' => 'zipcode:home',
|
|
114 'mobile_number' => 'phone:cell',
|
|
115 'nickname' => 'nickname',
|
|
116 'organization' => 'organization',
|
|
117 'pager_number' => 'phone:pager',
|
|
118 'primary_email' => 'email:pref',
|
|
119 'secondary_email' => 'email:other',
|
|
120 'web_page_1' => 'website:homepage',
|
|
121 'web_page_2' => 'website:other',
|
|
122 'work_phone' => 'phone:work',
|
|
123 'work_address' => 'street:work',
|
|
124 //'work_address_2' => '',
|
|
125 'work_country' => 'country:work',
|
|
126 'work_zipcode' => 'zipcode:work',
|
|
127 'last' => 'surname',
|
|
128 'first' => 'firstname',
|
|
129 'work_city' => 'locality:work',
|
|
130 'work_state' => 'region:work',
|
|
131 'home_city_short' => 'locality:home',
|
|
132 'home_state_short' => 'region:home',
|
|
133
|
|
134 // Atmail
|
|
135 'date_of_birth' => 'birthday',
|
|
136 'email' => 'email:pref',
|
|
137 'home_mobile' => 'phone:cell',
|
|
138 'home_zip' => 'zipcode:home',
|
|
139 'info' => 'notes',
|
|
140 'user_photo' => 'photo',
|
|
141 'url' => 'website:homepage',
|
|
142 'work_company' => 'organization',
|
|
143 'work_dept' => 'departament',
|
|
144 'work_fax' => 'phone:work,fax',
|
|
145 'work_mobile' => 'phone:work,cell',
|
|
146 'work_title' => 'jobtitle',
|
|
147 'work_zip' => 'zipcode:work',
|
|
148 'group' => 'groups',
|
|
149
|
|
150 // GMail
|
|
151 'groups' => 'groups',
|
|
152 'group_membership' => 'groups',
|
|
153 'given_name' => 'firstname',
|
|
154 'additional_name' => 'middlename',
|
|
155 'family_name' => 'surname',
|
|
156 'name' => 'displayname',
|
|
157 'name_prefix' => 'prefix',
|
|
158 'name_suffix' => 'suffix',
|
|
159 );
|
|
160
|
|
161 /**
|
|
162 * CSV label to text mapping for English
|
|
163 *
|
|
164 * @var array
|
|
165 */
|
|
166 protected $label_map = array(
|
|
167 // MS Outlook 2010
|
|
168 'anniversary' => "Anniversary",
|
|
169 'assistants_name' => "Assistant's Name",
|
|
170 'assistants_phone' => "Assistant's Phone",
|
|
171 'birthday' => "Birthday",
|
|
172 'business_city' => "Business City",
|
|
173 'business_countryregion' => "Business Country/Region",
|
|
174 'business_fax' => "Business Fax",
|
|
175 'business_phone' => "Business Phone",
|
|
176 'business_phone_2' => "Business Phone 2",
|
|
177 'business_postal_code' => "Business Postal Code",
|
|
178 'business_state' => "Business State",
|
|
179 'business_street' => "Business Street",
|
|
180 //'business_street_2' => "Business Street 2",
|
|
181 //'business_street_3' => "Business Street 3",
|
|
182 'car_phone' => "Car Phone",
|
|
183 'categories' => "Categories",
|
|
184 //'children' => "Children",
|
|
185 'company' => "Company",
|
|
186 //'company_main_phone' => "Company Main Phone",
|
|
187 'department' => "Department",
|
|
188 //'directory_server' => "Directory Server",
|
|
189 'email_2_address' => "E-mail 2 Address",
|
|
190 //'email_2_type' => "E-mail 2 Type",
|
|
191 'email_3_address' => "E-mail 3 Address",
|
|
192 //'email_3_type' => "E-mail 3 Type",
|
|
193 'email_address' => "E-mail Address",
|
|
194 //'email_type' => "E-mail Type",
|
|
195 'first_name' => "First Name",
|
|
196 'gender' => "Gender",
|
|
197 'home_city' => "Home City",
|
|
198 'home_countryregion' => "Home Country/Region",
|
|
199 'home_fax' => "Home Fax",
|
|
200 'home_phone' => "Home Phone",
|
|
201 'home_phone_2' => "Home Phone 2",
|
|
202 'home_postal_code' => "Home Postal Code",
|
|
203 'home_state' => "Home State",
|
|
204 'home_street' => "Home Street",
|
|
205 //'home_street_2' => "Home Street 2",
|
|
206 //'home_street_3' => "Home Street 3",
|
|
207 //'initials' => "Initials",
|
|
208 //'isdn' => "ISDN",
|
|
209 'job_title' => "Job Title",
|
|
210 //'keywords' => "Keywords",
|
|
211 //'language' => "Language",
|
|
212 'last_name' => "Last Name",
|
|
213 //'location' => "Location",
|
|
214 'managers_name' => "Manager's Name",
|
|
215 'middle_name' => "Middle Name",
|
|
216 //'mileage' => "Mileage",
|
|
217 'mobile_phone' => "Mobile Phone",
|
|
218 'notes' => "Notes",
|
|
219 //'office_location' => "Office Location",
|
|
220 'other_city' => "Other City",
|
|
221 'other_countryregion' => "Other Country/Region",
|
|
222 'other_fax' => "Other Fax",
|
|
223 'other_phone' => "Other Phone",
|
|
224 'other_postal_code' => "Other Postal Code",
|
|
225 'other_state' => "Other State",
|
|
226 'other_street' => "Other Street",
|
|
227 //'other_street_2' => "Other Street 2",
|
|
228 //'other_street_3' => "Other Street 3",
|
|
229 'pager' => "Pager",
|
|
230 'primary_phone' => "Primary Phone",
|
|
231 //'profession' => "Profession",
|
|
232 //'radio_phone' => "Radio Phone",
|
|
233 'spouse' => "Spouse",
|
|
234 'suffix' => "Suffix",
|
|
235 'title' => "Title",
|
|
236 'web_page' => "Web Page",
|
|
237
|
|
238 // Thunderbird
|
|
239 'birth_day' => "Birth Day",
|
|
240 'birth_month' => "Birth Month",
|
|
241 'birth_year' => "Birth Year",
|
|
242 'display_name' => "Display Name",
|
|
243 'fax_number' => "Fax Number",
|
|
244 'home_address' => "Home Address",
|
|
245 //'home_address_2' => "Home Address 2",
|
|
246 'home_country' => "Home Country",
|
|
247 'home_zipcode' => "Home ZipCode",
|
|
248 'mobile_number' => "Mobile Number",
|
|
249 'nickname' => "Nickname",
|
|
250 'organization' => "Organization",
|
|
251 'pager_number' => "Pager Namber",
|
|
252 'primary_email' => "Primary Email",
|
|
253 'secondary_email' => "Secondary Email",
|
|
254 'web_page_1' => "Web Page 1",
|
|
255 'web_page_2' => "Web Page 2",
|
|
256 'work_phone' => "Work Phone",
|
|
257 'work_address' => "Work Address",
|
|
258 //'work_address_2' => "Work Address 2",
|
|
259 'work_city' => "Work City",
|
|
260 'work_country' => "Work Country",
|
|
261 'work_state' => "Work State",
|
|
262 'work_zipcode' => "Work ZipCode",
|
|
263
|
|
264 // Atmail
|
|
265 'date_of_birth' => "Date of Birth",
|
|
266 'email' => "Email",
|
|
267 //'email_2' => "Email2",
|
|
268 //'email_3' => "Email3",
|
|
269 //'email_4' => "Email4",
|
|
270 //'email_5' => "Email5",
|
|
271 'home_mobile' => "Home Mobile",
|
|
272 'home_zip' => "Home Zip",
|
|
273 'info' => "Info",
|
|
274 'user_photo' => "User Photo",
|
|
275 'url' => "URL",
|
|
276 'work_company' => "Work Company",
|
|
277 'work_dept' => "Work Dept",
|
|
278 'work_fax' => "Work Fax",
|
|
279 'work_mobile' => "Work Mobile",
|
|
280 'work_title' => "Work Title",
|
|
281 'work_zip' => "Work Zip",
|
|
282 'group' => "Group",
|
|
283
|
|
284 // GMail
|
|
285 'groups' => "Groups",
|
|
286 'group_membership' => "Group Membership",
|
|
287 'given_name' => "Given Name",
|
|
288 'additional_name' => "Additional Name",
|
|
289 'family_name' => "Family Name",
|
|
290 'name' => "Name",
|
|
291 'name_prefix' => "Name Prefix",
|
|
292 'name_suffix' => "Name Suffix",
|
|
293 );
|
|
294
|
|
295 /**
|
|
296 * Special fields map for GMail format
|
|
297 *
|
|
298 * @var array
|
|
299 */
|
|
300 protected $gmail_label_map = array(
|
|
301 'E-mail' => array(
|
|
302 'Value' => array(
|
|
303 'home' => 'email:home',
|
|
304 'work' => 'email:work',
|
|
305 '*' => 'email:other',
|
|
306 ),
|
|
307 ),
|
|
308 'Phone' => array(
|
|
309 'Value' => array(
|
|
310 'home' => 'phone:home',
|
|
311 'homefax' => 'phone:homefax',
|
|
312 'main' => 'phone:pref',
|
|
313 'pager' => 'phone:pager',
|
|
314 'mobile' => 'phone:cell',
|
|
315 'work' => 'phone:work',
|
|
316 'workfax' => 'phone:workfax',
|
|
317 ),
|
|
318 ),
|
|
319 'Relation' => array(
|
|
320 'Value' => array(
|
|
321 'spouse' => 'spouse',
|
|
322 ),
|
|
323 ),
|
|
324 'Website' => array(
|
|
325 'Value' => array(
|
|
326 'profile' => 'website:profile',
|
|
327 'blog' => 'website:blog',
|
|
328 'homepage' => 'website:homepage',
|
|
329 'work' => 'website:work',
|
|
330 ),
|
|
331 ),
|
|
332 'Address' => array(
|
|
333 'Street' => array(
|
|
334 'home' => 'street:home',
|
|
335 'work' => 'street:work',
|
|
336 ),
|
|
337 'City' => array(
|
|
338 'home' => 'locality:home',
|
|
339 'work' => 'locality:work',
|
|
340 ),
|
|
341 'Region' => array(
|
|
342 'home' => 'region:home',
|
|
343 'work' => 'region:work',
|
|
344 ),
|
|
345 'Postal Code' => array(
|
|
346 'home' => 'zipcode:home',
|
|
347 'work' => 'zipcode:work',
|
|
348 ),
|
|
349 'Country' => array(
|
|
350 'home' => 'country:home',
|
|
351 'work' => 'country:work',
|
|
352 ),
|
|
353 ),
|
|
354 'Organization' => array(
|
|
355 'Name' => array(
|
|
356 '' => 'organization',
|
|
357 ),
|
|
358 'Title' => array(
|
|
359 '' => 'jobtitle',
|
|
360 ),
|
|
361 'Department' => array(
|
|
362 '' => 'department',
|
|
363 ),
|
|
364 ),
|
|
365 );
|
|
366
|
|
367
|
|
368 protected $local_label_map = array();
|
|
369 protected $vcards = array();
|
|
370 protected $map = array();
|
|
371 protected $gmail_map = array();
|
|
372
|
|
373
|
|
374 /**
|
|
375 * Class constructor
|
|
376 *
|
|
377 * @param string $lang File language
|
|
378 */
|
|
379 public function __construct($lang = 'en_US')
|
|
380 {
|
|
381 // Localize fields map
|
|
382 if ($lang && $lang != 'en_US') {
|
|
383 if (file_exists(RCUBE_LOCALIZATION_DIR . "$lang/csv2vcard.inc")) {
|
|
384 include RCUBE_LOCALIZATION_DIR . "$lang/csv2vcard.inc";
|
|
385 }
|
|
386
|
|
387 if (!empty($map)) {
|
|
388 $this->local_label_map = array_merge($this->label_map, $map);
|
|
389 }
|
|
390 }
|
|
391
|
|
392 $this->label_map = array_flip($this->label_map);
|
|
393 $this->local_label_map = array_flip($this->local_label_map);
|
|
394 }
|
|
395
|
|
396 /**
|
|
397 * Import contacts from CSV file
|
|
398 *
|
|
399 * @param string $csv Content of the CSV file
|
|
400 */
|
|
401 public function import($csv)
|
|
402 {
|
|
403 // convert to UTF-8
|
|
404 $head = substr($csv, 0, 4096);
|
|
405 $charset = rcube_charset::detect($head, RCUBE_CHARSET);
|
|
406 $csv = rcube_charset::convert($csv, $charset);
|
|
407 $csv = preg_replace(array('/^[\xFE\xFF]{2}/', '/^\xEF\xBB\xBF/', '/^\x00+/'), '', $csv); // also remove BOM
|
|
408 $head = '';
|
|
409 $prev_line = false;
|
|
410
|
|
411 $this->map = array();
|
|
412 $this->gmail_map = array();
|
|
413
|
|
414 // Parse file
|
|
415 foreach (preg_split("/[\r\n]+/", $csv) as $line) {
|
|
416 if (!empty($prev_line)) {
|
|
417 $line = '"' . $line;
|
|
418 }
|
|
419
|
|
420 $elements = $this->parse_line($line);
|
|
421
|
|
422 if (empty($elements)) {
|
|
423 continue;
|
|
424 }
|
|
425
|
|
426 // Parse header
|
|
427 if (empty($this->map)) {
|
|
428 $this->parse_header($elements);
|
|
429 if (empty($this->map)) {
|
|
430 break;
|
|
431 }
|
|
432 }
|
|
433 // Parse data row
|
|
434 else {
|
|
435 // handle multiline elements (e.g. Gmail)
|
|
436 if (!empty($prev_line)) {
|
|
437 $first = array_shift($elements);
|
|
438
|
|
439 if ($first[0] == '"') {
|
|
440 $prev_line[count($prev_line)-1] = '"' . $prev_line[count($prev_line)-1] . "\n" . substr($first, 1);
|
|
441 }
|
|
442 else {
|
|
443 $prev_line[count($prev_line)-1] .= "\n" . $first;
|
|
444 }
|
|
445
|
|
446 $elements = array_merge($prev_line, $elements);
|
|
447 }
|
|
448
|
|
449 $last_element = $elements[count($elements)-1];
|
|
450 if ($last_element[0] == '"') {
|
|
451 $elements[count($elements)-1] = substr($last_element, 1);
|
|
452 $prev_line = $elements;
|
|
453 continue;
|
|
454 }
|
|
455 $this->csv_to_vcard($elements);
|
|
456 $prev_line = false;
|
|
457 }
|
|
458 }
|
|
459 }
|
|
460
|
|
461 /**
|
|
462 * Export vCards
|
|
463 *
|
|
464 * @return array rcube_vcard List of vcards
|
|
465 */
|
|
466 public function export()
|
|
467 {
|
|
468 return $this->vcards;
|
|
469 }
|
|
470
|
|
471 /**
|
|
472 * Parse CSV file line
|
|
473 */
|
|
474 protected function parse_line($line)
|
|
475 {
|
|
476 $line = trim($line);
|
|
477 if (empty($line)) {
|
|
478 return null;
|
|
479 }
|
|
480
|
|
481 $fields = rcube_utils::explode_quoted_string(',', $line);
|
|
482
|
|
483 // remove quotes if needed
|
|
484 if (!empty($fields)) {
|
|
485 foreach ($fields as $idx => $value) {
|
|
486 if (($len = strlen($value)) > 1 && $value[0] == '"' && $value[$len-1] == '"') {
|
|
487 // remove surrounding quotes
|
|
488 $value = substr($value, 1, -1);
|
|
489 // replace doubled quotes inside the string with single quote
|
|
490 $value = str_replace('""', '"', $value);
|
|
491
|
|
492 $fields[$idx] = $value;
|
|
493 }
|
|
494 }
|
|
495 }
|
|
496
|
|
497 return $fields;
|
|
498 }
|
|
499
|
|
500 /**
|
|
501 * Parse CSV header line, detect fields mapping
|
|
502 */
|
|
503 protected function parse_header($elements)
|
|
504 {
|
|
505 $map1 = array();
|
|
506 $map2 = array();
|
|
507 $size = count($elements);
|
|
508
|
|
509 // check English labels
|
|
510 for ($i = 0; $i < $size; $i++) {
|
|
511 $label = $this->label_map[$elements[$i]];
|
|
512 if ($label && !empty($this->csv2vcard_map[$label])) {
|
|
513 $map1[$i] = $this->csv2vcard_map[$label];
|
|
514 }
|
|
515 }
|
|
516
|
|
517 // check localized labels
|
|
518 if (!empty($this->local_label_map)) {
|
|
519 for ($i = 0; $i < $size; $i++) {
|
|
520 $label = $this->local_label_map[$elements[$i]];
|
|
521
|
|
522 // special localization label
|
|
523 if ($label && $label[0] == '_') {
|
|
524 $label = substr($label, 1);
|
|
525 }
|
|
526
|
|
527 if ($label && !empty($this->csv2vcard_map[$label])) {
|
|
528 $map2[$i] = $this->csv2vcard_map[$label];
|
|
529 }
|
|
530 }
|
|
531 }
|
|
532
|
|
533 $this->map = count($map1) >= count($map2) ? $map1 : $map2;
|
|
534
|
|
535 // support special Gmail format
|
|
536 foreach ($this->gmail_label_map as $key => $items) {
|
|
537 $num = 1;
|
|
538 while (($_key = "$key $num - Type") && ($found = array_search($_key, $elements)) !== false) {
|
|
539 $this->gmail_map["$key:$num"] = array('_key' => $key, '_idx' => $found);
|
|
540 foreach (array_keys($items) as $item_key) {
|
|
541 $_key = "$key $num - $item_key";
|
|
542 if (($found = array_search($_key, $elements)) !== false) {
|
|
543 $this->gmail_map["$key:$num"][$item_key] = $found;
|
|
544 }
|
|
545 }
|
|
546
|
|
547 $num++;
|
|
548 }
|
|
549 }
|
|
550 }
|
|
551
|
|
552 /**
|
|
553 * Convert CSV data row to vCard
|
|
554 */
|
|
555 protected function csv_to_vcard($data)
|
|
556 {
|
|
557 $contact = array();
|
|
558 foreach ($this->map as $idx => $name) {
|
|
559 $value = $data[$idx];
|
|
560 if ($value !== null && $value !== '') {
|
|
561 if (!empty($contact[$name])) {
|
|
562 $contact[$name] = (array) $contact[$name];
|
|
563 $contact[$name][] = $value;
|
|
564 }
|
|
565 else {
|
|
566 $contact[$name] = $value;
|
|
567 }
|
|
568 }
|
|
569 }
|
|
570
|
|
571 // Gmail format support
|
|
572 foreach ($this->gmail_map as $idx => $item) {
|
|
573 $type = preg_replace('/[^a-z]/', '', strtolower($data[$item['_idx']]));
|
|
574 $key = $item['_key'];
|
|
575
|
|
576 unset($item['_idx']);
|
|
577 unset($item['_key']);
|
|
578
|
|
579 foreach ($item as $item_key => $item_idx) {
|
|
580 $value = $data[$item_idx];
|
|
581 if ($value !== null && $value !== '') {
|
|
582 foreach (array($type, '*') as $_type) {
|
|
583 if ($data_idx = $this->gmail_label_map[$key][$item_key][$_type]) {
|
|
584 $value = explode(' ::: ', $value);
|
|
585
|
|
586 if (!empty($contact[$data_idx])) {
|
|
587 $contact[$data_idx] = array_merge((array) $contact[$data_idx], $value);
|
|
588 }
|
|
589 else {
|
|
590 $contact[$data_idx] = $value;
|
|
591 }
|
|
592 break;
|
|
593 }
|
|
594 }
|
|
595 }
|
|
596 }
|
|
597 }
|
|
598
|
|
599 if (empty($contact)) {
|
|
600 return;
|
|
601 }
|
|
602
|
|
603 // Handle special values
|
|
604 if (!empty($contact['birthday-d']) && !empty($contact['birthday-m']) && !empty($contact['birthday-y'])) {
|
|
605 $contact['birthday'] = $contact['birthday-y'] .'-' .$contact['birthday-m'] . '-' . $contact['birthday-d'];
|
|
606 }
|
|
607
|
|
608 if (!empty($contact['groups'])) {
|
|
609 // categories/groups separator in vCard is ',' not ';'
|
|
610 $contact['groups'] = str_replace(',', '', $contact['groups']);
|
|
611 $contact['groups'] = str_replace(';', ',', $contact['groups']);
|
|
612
|
|
613 if (!empty($this->gmail_map)) {
|
|
614 // remove "* " added by GMail
|
|
615 $contact['groups'] = str_replace('* ', '', $contact['groups']);
|
|
616 // replace strange delimiter
|
|
617 $contact['groups'] = str_replace(' ::: ', ',', $contact['groups']);
|
|
618 }
|
|
619 }
|
|
620
|
|
621 // Empty dates, e.g. "0/0/00", "0000-00-00 00:00:00"
|
|
622 foreach (array('birthday', 'anniversary') as $key) {
|
|
623 if (!empty($contact[$key])) {
|
|
624 $date = preg_replace('/[0[:^word:]]/', '', $contact[$key]);
|
|
625 if (empty($date)) {
|
|
626 unset($contact[$key]);
|
|
627 }
|
|
628 }
|
|
629 }
|
|
630
|
|
631 if (!empty($contact['gender']) && ($gender = strtolower($contact['gender']))) {
|
|
632 if (!in_array($gender, array('male', 'female'))) {
|
|
633 unset($contact['gender']);
|
|
634 }
|
|
635 }
|
|
636
|
|
637 // Convert address(es) to rcube_vcard data
|
|
638 foreach ($contact as $idx => $value) {
|
|
639 $name = explode(':', $idx);
|
|
640 if (in_array($name[0], array('street', 'locality', 'region', 'zipcode', 'country'))) {
|
|
641 $contact['address:'.$name[1]][$name[0]] = $value;
|
|
642 unset($contact[$idx]);
|
|
643 }
|
|
644 }
|
|
645
|
|
646 // Create vcard object
|
|
647 $vcard = new rcube_vcard();
|
|
648 foreach ($contact as $name => $value) {
|
|
649 $name = explode(':', $name);
|
|
650 if (is_array($value) && $name[0] != 'address') {
|
|
651 foreach ((array) $value as $val) {
|
|
652 $vcard->set($name[0], $val, $name[1]);
|
|
653 }
|
|
654 }
|
|
655 else {
|
|
656 $vcard->set($name[0], $value, $name[1]);
|
|
657 }
|
|
658 }
|
|
659
|
|
660 // add to the list
|
|
661 $this->vcards[] = $vcard;
|
|
662 }
|
|
663 }
|