From b58f11841539035f8fa06c2a0e64dd9199d6a089 Mon Sep 17 00:00:00 2001 From: thomascube Date: Tue, 21 Oct 2008 09:41:32 +0000 Subject: [PATCH] Improve vcard import (#1485502); try utf-8 first in charset detection --- program/include/rcube_shared.inc | 12 ++--- program/include/rcube_vcard.php | 63 +++++++++++++++---------- program/localization/ar_SA/messages.inc | 2 +- program/localization/az_AZ/messages.inc | 2 +- program/localization/cs_CZ/messages.inc | 2 +- program/localization/cy_GB/messages.inc | 2 +- program/localization/de_DE/messages.inc | 2 +- program/localization/en_GB/messages.inc | 2 +- program/localization/fi_FI/messages.inc | 2 +- program/localization/fr_FR/messages.inc | 2 +- program/localization/he_IL/messages.inc | 2 +- program/localization/it_IT/messages.inc | 2 +- program/localization/lt_LT/messages.inc | 2 +- program/localization/nn_NO/messages.inc | 2 +- program/localization/ru_RU/messages.inc | 2 +- program/localization/zh_CN/messages.inc | 2 +- program/steps/addressbook/import.inc | 2 +- 17 files changed, 59 insertions(+), 46 deletions(-) diff --git a/program/include/rcube_shared.inc b/program/include/rcube_shared.inc index 3b63d9c0e..26de5b45c 100644 --- a/program/include/rcube_shared.inc +++ b/program/include/rcube_shared.inc @@ -575,12 +575,12 @@ function rc_detect_encoding($string, $failover='') // FIXME: the order is important, because sometimes // iso string is detected as euc-jp and etc. $enc = array( - 'SJIS', 'BIG5', 'GB2312', 'UTF-8', - 'ISO-8859-1', 'ISO-8859-2', 'ISO-8859-3', 'ISO-8859-4', - 'ISO-8859-5', 'ISO-8859-6', 'ISO-8859-7', 'ISO-8859-8', 'ISO-8859-9', - 'ISO-8859-10', 'ISO-8859-13', 'ISO-8859-14', 'ISO-8859-15', 'ISO-8859-16', - 'WINDOWS-1252', 'WINDOWS-1251', 'EUC-JP', 'EUC-TW', 'KOI8-R', - 'ISO-2022-KR', 'ISO-2022-JP' + 'UTF-8', 'SJIS', 'BIG5', 'GB2312', + 'ISO-8859-1', 'ISO-8859-2', 'ISO-8859-3', 'ISO-8859-4', + 'ISO-8859-5', 'ISO-8859-6', 'ISO-8859-7', 'ISO-8859-8', 'ISO-8859-9', + 'ISO-8859-10', 'ISO-8859-13', 'ISO-8859-14', 'ISO-8859-15', 'ISO-8859-16', + 'WINDOWS-1252', 'WINDOWS-1251', 'EUC-JP', 'EUC-TW', 'KOI8-R', + 'ISO-2022-KR', 'ISO-2022-JP' ); $result = mb_detect_encoding($string, join(',', $enc)); diff --git a/program/include/rcube_vcard.php b/program/include/rcube_vcard.php index ca7ca0822..ea345415d 100644 --- a/program/include/rcube_vcard.php +++ b/program/include/rcube_vcard.php @@ -218,6 +218,9 @@ class rcube_vcard // remove vcard 2.1 charset definitions $vcard = preg_replace('/;CHARSET=[^:;]+/', '', $vcard); + + // if N doesn't have any semicolons, add some + $vcard = preg_replace('/^(N:[^;\R]*)$/m', '\1;;;;', $vcard); return $vcard; } @@ -241,38 +244,48 @@ class rcube_vcard // Perform RFC2425 line unfolding $vcard = preg_replace(array("/\r/", "/\n\s+/"), '', $vcard); + $lines = preg_split('/\r?\n/', $vcard); $data = array(); - if (preg_match_all('/^([^\\:]*):(.+)$/m', $vcard, $regs, PREG_SET_ORDER)) { - foreach($regs as $line) { - // convert 2.1-style "EMAIL;internet;home:" to 3.0-style "EMAIL;TYPE=internet;TYPE=home:" - if (($data['VERSION'][0] == "2.1") && preg_match('/^([^;]+);([^:]+)/', $line[1], $regs2) && !preg_match('/^TYPE=/i', $regs2[2])) { - $line[1] = $regs2[1]; - foreach (explode(';', $regs2[2]) as $prop) - $line[1] .= ';' . (strpos($prop, '=') ? $prop : 'TYPE='.$prop); - } - - if (!preg_match('/^(BEGIN|END)$/', $line[1]) && preg_match_all('/([^\\;]+);?/', $line[1], $regs2)) { - $entry = array(self::vcard_unquote($line[2])); + + for ($i=0; $i < count($lines); $i++) { + if (!preg_match('/^([^\\:]*):(.+)$/', $lines[$i], $line)) + continue; + + // convert 2.1-style "EMAIL;internet;home:" to 3.0-style "EMAIL;TYPE=internet;TYPE=home:" + if (($data['VERSION'][0] == "2.1") && preg_match('/^([^;]+);([^:]+)/', $line[1], $regs2) && !preg_match('/^TYPE=/i', $regs2[2])) { + $line[1] = $regs2[1]; + foreach (explode(';', $regs2[2]) as $prop) + $line[1] .= ';' . (strpos($prop, '=') ? $prop : 'TYPE='.$prop); + } - foreach($regs2[1] as $attrid => $attr) { - if ((list($key, $value) = explode('=', $attr)) && $value) { - if ($key == 'ENCODING') - $entry[0] = self::decode_value($entry[0], $value); - else - $entry[strtolower($key)] = array_merge((array)$entry[strtolower($key)], (array)self::vcard_unquote($value, ',')); - } - else if ($attrid > 0) { - $entry[$key] = true; # true means attr without =value + if (!preg_match('/^(BEGIN|END)$/', $line[1]) && preg_match_all('/([^\\;]+);?/', $line[1], $regs2)) { + $entry = array(''); + $field = $regs2[1][0]; + + foreach($regs2[1] as $attrid => $attr) { + if ((list($key, $value) = explode('=', $attr)) && $value) { + if ($key == 'ENCODING') { + # add next line(s) to value string if QP line end detected + while ($value == 'QUOTED-PRINTABLE' && ereg('=$', $lines[$i])) + $line[2] .= "\n" . $lines[++$i]; + + $line[2] = self::decode_value($line[2], $value); } + else + $entry[strtolower($key)] = array_merge((array)$entry[strtolower($key)], (array)self::vcard_unquote($value, ',')); + } + else if ($attrid > 0) { + $entry[$key] = true; # true means attr without =value } - - $data[$regs2[1][0]][] = count($entry) > 1 ? $entry : $entry[0]; } - } - unset($data['VERSION']); + $entry[0] = self::vcard_unquote($line[2]); + $data[$field][] = count($entry) > 1 ? $entry : $entry[0]; + } } + unset($data['VERSION']); + return $data; } @@ -331,7 +344,7 @@ class rcube_vcard { foreach((array)$data as $type => $entries) { /* valid N has 5 properties */ - while ($type == "N" && count($entries[0]) < 5) + while ($type == "N" && is_array($entries[0]) && count($entries[0]) < 5) $entries[0][] = ""; foreach((array)$entries as $entry) { diff --git a/program/localization/ar_SA/messages.inc b/program/localization/ar_SA/messages.inc index 850736f16..b8387b99f 100644 --- a/program/localization/ar_SA/messages.inc +++ b/program/localization/ar_SA/messages.inc @@ -89,7 +89,7 @@ $messages['selectimportfile'] = 'رجاء اختر ملفاً لرفعه'; $messages['addresswriterror'] = 'دفتر العناوين المحدد غير قابل للكتابة'; $messages['importwait'] = 'جاري الاستيراد، رجاء انتظر...'; $messages['importerror'] = 'فشل الاستيراد! الملف المرفوع ليس ملف vCard صالح.'; -$messages['importconfirm'] = 'تم استيراد $inserted مراسلين بنجاح، وتجاهل $skipped موجودين مسبقاً:$names'; +$messages['importconfirm'] = 'تم استيراد $inserted مراسلين بنجاح، وتجاهل $skipped موجودين مسبقاً:

$names

'; $messages['opnotpermitted'] = 'العملية ممنوعة!'; $messages['nofromaddress'] = 'عنوان البريد الالكتروني غير محدد في الهويّة المنتقاة'; diff --git a/program/localization/az_AZ/messages.inc b/program/localization/az_AZ/messages.inc index e692471b7..6835bc0b6 100644 --- a/program/localization/az_AZ/messages.inc +++ b/program/localization/az_AZ/messages.inc @@ -87,7 +87,7 @@ $messages['selectimportfile'] = 'Zəhmət olmasa, yüklənilən faylı seç'; $messages['addresswriterror'] = 'Seçilmiş ünvan kitabçası yazılmayandır'; $messages['importwait'] = 'İdxal, gözləyin...'; $messages['importerror'] = 'İdxal alınmadı! Yüklənilən fayl vCard fayla uyğun deyil.'; -$messages['importconfirm'] = '$inserted ünvanlar müvəffəqiyyətlə idxal edildi, mövcud daxil edilən $skipped atla: $names'; +$messages['importconfirm'] = '$inserted ünvanlar müvəffəqiyyətlə idxal edildi, mövcud daxil edilən $skipped atla:

$names

'; $messages['opnotpermitted'] = 'Əməliyyata icazə verilmir!'; $messages['nofromaddress'] = 'Seçilmiş eynilikdə e-poçt ünvanı axtarılır'; diff --git a/program/localization/cs_CZ/messages.inc b/program/localization/cs_CZ/messages.inc index f4daa6e40..631b0a2c1 100644 --- a/program/localization/cs_CZ/messages.inc +++ b/program/localization/cs_CZ/messages.inc @@ -90,7 +90,7 @@ $messages['selectimportfile'] = 'Prosím vyberte soubor k nahrání'; $messages['addresswriterror'] = 'Vybraný seznam kontaktů není zapisovatelný'; $messages['importwait'] = 'Importuji, prosím čekejte...'; $messages['importerror'] = 'Během importu nastala chyba! Nahraný soubor není ve formátu vCard.'; -$messages['importconfirm'] = 'Úspěšně naimportováno $inserted kontaktů, $skipped existujících záznamů přeskočeno:$names'; +$messages['importconfirm'] = 'Úspěšně naimportováno $inserted kontaktů, $skipped existujících záznamů přeskočeno:

$names

'; $messages['opnotpermitted'] = 'Operace není povolena!'; ?> \ No newline at end of file diff --git a/program/localization/cy_GB/messages.inc b/program/localization/cy_GB/messages.inc index 7f152a6b3..b12c332d5 100644 --- a/program/localization/cy_GB/messages.inc +++ b/program/localization/cy_GB/messages.inc @@ -87,7 +87,7 @@ $messages['selectimportfile'] = 'Dewiswch ffeil i\'w lwytho fyny'; $messages['addresswriterror'] = 'Nid yw\'n bosib ysgrifennu i\'r llyfr cyfeiriadau '; $messages['importwait'] = 'Yn mewnforio, arhoswch os gwelwch yn dda...'; $messages['importerror'] = 'Methwyd a mewnforio! Nid yw\'r ffeil a lwythwyd fyny yn ffeil vCard dilys.'; -$messages['importconfirm'] = 'Fe mewnforiwyd $inserted cyswllt yn llwyddiannus, anwybyddwyd $skipped cofnod presennol: $names'; +$messages['importconfirm'] = 'Fe mewnforiwyd $inserted cyswllt yn llwyddiannus, anwybyddwyd $skipped cofnod presennol:

$names

'; $messages['opnotpermitted'] = 'Ni chaniateir y weithred!'; $messages['nofromaddress'] = 'Cyfeiriad e-bost ar goll yn y personoliaeth a ddewiswyd'; diff --git a/program/localization/de_DE/messages.inc b/program/localization/de_DE/messages.inc index 81b00e3b9..0e01c93f0 100644 --- a/program/localization/de_DE/messages.inc +++ b/program/localization/de_DE/messages.inc @@ -88,7 +88,7 @@ $messages['selectimportfile'] = 'Bitte wählen Sie eine Datei zum Importieren au $messages['addresswriterror'] = 'Das ausgewählte Adressbuch kann nicht verändert werden'; $messages['importwait'] = 'Daten werden importiert, bitte warten...'; $messages['importerror'] = 'Import fehlgeschlagen! Die hochgeladene Datei ist nicht im vCard-Format.'; -$messages['importconfirm'] = 'Es wurden $inserted Adressen erfolgreich importiert und $skipped bestehende Einträge übersprungen:$names'; +$messages['importconfirm'] = 'Es wurden $inserted Adressen erfolgreich importiert und $skipped bestehende Einträge übersprungen:

$names

'; $messages['opnotpermitted'] = 'Operation nicht erlaubt!'; ?> diff --git a/program/localization/en_GB/messages.inc b/program/localization/en_GB/messages.inc index 70b8f4693..e9ce8feb0 100644 --- a/program/localization/en_GB/messages.inc +++ b/program/localization/en_GB/messages.inc @@ -90,7 +90,7 @@ $messages['selectimportfile'] = 'Please select a file to upload'; $messages['addresswriterror'] = 'The selected address book is not writeable'; $messages['importwait'] = 'Importing, please wait...'; $messages['importerror'] = 'Import failed! The uploaded file is not a valid vCard file.'; -$messages['importconfirm'] = 'Successfully imported $inserted contacts, $skipped existing entries skipped:$names'; +$messages['importconfirm'] = 'Successfully imported $inserted contacts, $skipped existing entries skipped:

$names

'; $messages['opnotpermitted'] = 'Operation not permitted!'; $messages['nofromaddress'] = 'Missing e-mail address in selected identity'; diff --git a/program/localization/fi_FI/messages.inc b/program/localization/fi_FI/messages.inc index e83b9a386..7dd82ec4a 100644 --- a/program/localization/fi_FI/messages.inc +++ b/program/localization/fi_FI/messages.inc @@ -91,7 +91,7 @@ $messages['selectimportfile'] = 'Valitse lähetettävä tiedosto'; $messages['addresswriterror'] = 'Valittuun osoitekirjaan ei voi kirjoittaa'; $messages['importwait'] = 'Tuodaan, odota...'; $messages['importerror'] = 'Tuonti epäonnistui! Lähetetty tiedosto ei ole vCard -muodossa.'; -$messages['importconfirm'] = '$inserted kontaktia tuotu onnistuneesti $inserted kontaktioa, $skipped olemassaolevaa kontaktia hypättiin yli: $names'; +$messages['importconfirm'] = '$inserted kontaktia tuotu onnistuneesti $inserted kontaktioa, $skipped olemassaolevaa kontaktia hypättiin yli:

$names

'; $messages['opnotpermitted'] = 'Toiminto ei ole sallittu!'; $messages['nofromaddress'] = 'Valittu identiteetti ei sisällä sähköpostiosoitetta'; diff --git a/program/localization/fr_FR/messages.inc b/program/localization/fr_FR/messages.inc index 332c4d5de..417f8ce43 100644 --- a/program/localization/fr_FR/messages.inc +++ b/program/localization/fr_FR/messages.inc @@ -90,7 +90,7 @@ $messages['selectimportfile'] = 'Veuillez sélectionner un fichier à envoyer'; $messages['addresswriterror'] = 'Impossible d\'écrire dans le carnet d\'adresse sélectionné'; $messages['importwait'] = 'Importation, veuillez patienter...'; $messages['importerror'] = 'Importation échouée ! Le fichier envoyé n\'est pas un fichier vCard valide.'; -$messages['importconfirm'] = '$inserted contacts importés avec succès, $skipped entrées existantes ignorées:$names'; +$messages['importconfirm'] = '$inserted contacts importés avec succès, $skipped entrées existantes ignorées:

$names

'; $messages['opnotpermitted'] = 'Cette opération n\'est pas permise !'; ?> diff --git a/program/localization/he_IL/messages.inc b/program/localization/he_IL/messages.inc index c8b46c125..046e19e81 100644 --- a/program/localization/he_IL/messages.inc +++ b/program/localization/he_IL/messages.inc @@ -87,7 +87,7 @@ $messages['selectimportfile'] = 'נא לבחור קובץ לייבוא'; $messages['addresswriterror'] = 'פנקס הכתובות שנבחר אינו ניתן לכתיבה'; $messages['importwait'] = 'ייבוא, נא להמתין..'; $messages['importerror'] = 'חוקי vCard הייבוא נכשל כי הקובץ אינו בפורמט'; -$messages['importconfirm'] = 'יובאו $inserted אנשי קשר, $skipped היו קיימים $names'; +$messages['importconfirm'] = 'יובאו $inserted אנשי קשר, $skipped היו קיימים

$names

'; $messages['opnotpermitted'] = 'פעולה אסורה!'; ?> diff --git a/program/localization/it_IT/messages.inc b/program/localization/it_IT/messages.inc index 8a44d17f0..46f9d3997 100644 --- a/program/localization/it_IT/messages.inc +++ b/program/localization/it_IT/messages.inc @@ -90,7 +90,7 @@ $messages['selectimportfile'] = 'Per favore, seleziona il file da caricare'; $messages['addresswriterror'] = 'La rubrica selezionata non è scrivibile'; $messages['importwait'] = 'Importazione in corso, attendere...'; $messages['importerror'] = 'Importazione fallita! Il file caricato non è un file vCard valido.'; -$messages['importconfirm'] = 'Importati con successo $inserted contatti, saltate $skipped voci esistenti:$names'; +$messages['importconfirm'] = 'Importati con successo $inserted contatti, saltate $skipped voci esistenti:

$names

'; $messages['opnotpermitted'] = 'Operazione non consentita!'; $messages['nofromaddress'] = 'Indirizzo e-mail mancante nell\'identità selezionata'; diff --git a/program/localization/lt_LT/messages.inc b/program/localization/lt_LT/messages.inc index 2912d19f4..a44954cee 100644 --- a/program/localization/lt_LT/messages.inc +++ b/program/localization/lt_LT/messages.inc @@ -88,7 +88,7 @@ $messages['selectimportfile'] = 'Prašome pasirinkti bylą įkėlimui'; $messages['addresswriterror'] = 'Pasirinkta adresų knyga nėra įrašoma'; $messages['importwait'] = 'Importuojama, prašome palaukti...'; $messages['importerror'] = 'Importavimas nepavyko! Įkelta byla nėra vCard formato.'; -$messages['importconfirm'] = 'Sėkmingai importuoti $inserted kontaktai, $skipped egzistuojančių įrašų praleista:$names'; +$messages['importconfirm'] = 'Sėkmingai importuoti $inserted kontaktai, $skipped egzistuojančių įrašų praleista:

$names

'; $messages['opnotpermitted'] = 'Operacija neleistina!'; ?> diff --git a/program/localization/nn_NO/messages.inc b/program/localization/nn_NO/messages.inc index b20d0c8bf..c348728b3 100644 --- a/program/localization/nn_NO/messages.inc +++ b/program/localization/nn_NO/messages.inc @@ -86,7 +86,7 @@ $messages['selectimportfile'] = 'Vel ei fil til å lasta opp'; $messages['addresswriterror'] = 'Denne adresseboka er ikkje skrivbar'; $messages['importwait'] = 'Importerer, vent...'; $messages['importerror'] = 'Importering feila! Fila er ikkje ei korrekt vCard-file.'; -$messages['importconfirm'] = 'Importerte $inserted kontakar, hoppa over $skipped oppføringar: $names'; +$messages['importconfirm'] = 'Importerte $inserted kontakar, hoppa over $skipped oppføringar:

$names

'; $messages['opnotpermitted'] = 'Ulovleg operasjon.'; ?> diff --git a/program/localization/ru_RU/messages.inc b/program/localization/ru_RU/messages.inc index 6ad3b7081..35c15ee0a 100644 --- a/program/localization/ru_RU/messages.inc +++ b/program/localization/ru_RU/messages.inc @@ -91,7 +91,7 @@ $messages['selectimportfile'] = 'Выберите файл для загрузк $messages['addresswriterror'] = 'Выбранная адресная книга недоступна для записи'; $messages['importwait'] = 'Импортирование, пожалуйста, подождите...'; $messages['importerror'] = 'Импорт завершился неудачно! Загруженный файл не является правильным файлом vCard.'; -$messages['importconfirm'] = 'Успешно импортировано $inserted контакт(ов), пропущено $skipped существующих:$names'; +$messages['importconfirm'] = 'Успешно импортировано $inserted контакт(ов), пропущено $skipped существующих:

$names

'; $messages['opnotpermitted'] = 'Действие запрещено!'; $messages['nofromaddress'] = 'В выбранном профиле не хватает адреса электронной почты'; diff --git a/program/localization/zh_CN/messages.inc b/program/localization/zh_CN/messages.inc index 06be91530..b8003e0f2 100644 --- a/program/localization/zh_CN/messages.inc +++ b/program/localization/zh_CN/messages.inc @@ -91,7 +91,7 @@ $messages['selectimportfile'] = '请选择要上传的文件'; $messages['addresswriterror'] = '已选择的地址簿不可写'; $messages['importwait'] = '正在导入,请稍后...'; $messages['importerror'] = '导入失败!所上传的文件不是有效的 vCard 文件。'; -$messages['importconfirm'] = '成功导入 $inserted 联系人,$skipped 乎略已存在的联系人:$names'; +$messages['importconfirm'] = '成功导入 $inserted 联系人,$skipped 乎略已存在的联系人:

$names

'; $messages['opnotpermitted'] = '不允许的操作'; $messages['nofromaddress'] = '选种的身份中没有邮件地址'; diff --git a/program/steps/addressbook/import.inc b/program/steps/addressbook/import.inc index 93452eccd..59490973c 100644 --- a/program/steps/addressbook/import.inc +++ b/program/steps/addressbook/import.inc @@ -58,7 +58,7 @@ function rcmail_import_confirm($attrib) global $IMPORT_STATS; $vars = get_object_vars($IMPORT_STATS); - $vars['names'] = join(', ', $IMPORT_STATS->names); + $vars['names'] = join(', ', array_map('Q', $IMPORT_STATS->names)); return html::p($attrib, Q(rcube_label(array( 'name' => 'importconfirm',