From bb8781c6d756c76c65e3cdce4f53bf9cca2f9193 Mon Sep 17 00:00:00 2001 From: thomascube Date: Thu, 25 Sep 2008 13:51:24 +0000 Subject: Improve vcard decoding and import step --- program/include/rcube_vcard.php | 47 +++++++++++++++++++++++++++++------- program/steps/addressbook/import.inc | 11 +++++---- 2 files changed, 44 insertions(+), 14 deletions(-) diff --git a/program/include/rcube_vcard.php b/program/include/rcube_vcard.php index 3ad47a5cb..8cc390c7a 100644 --- a/program/include/rcube_vcard.php +++ b/program/include/rcube_vcard.php @@ -73,7 +73,7 @@ class rcube_vcard $this->business = ($this->raw['X-ABShowAs'][0] == 'COMPANY') || (join('', (array)$this->raw['N'][0]) == '' && !empty($this->organization)); foreach ((array)$this->raw['EMAIL'] as $i => $raw_email) - $this->email[$i] = $raw_email[0]; + $this->email[$i] = is_array($raw_email) ? $raw_email[0] : $raw_email; // make the pref e-mail address the first entry in $this->email $pref_index = $this->get_type_index('EMAIL', 'pref'); @@ -217,7 +217,7 @@ class rcube_vcard $vcard = preg_replace(array('/^item\d*\.X-AB.*$/m', '/^item\d*\./m', "/\n+/"), array('', '', "\n"), $vcard); // remove vcard 2.1 charset definitions - $vcard = preg_replace('/;CHARSET=[^:]+/', '', $vcard); + $vcard = preg_replace('/;CHARSET=[^:;]+/', '', $vcard); return $vcard; } @@ -244,19 +244,26 @@ class rcube_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,home:" - if(($data['VERSION'][0] == "2.1") && preg_match('/^([^;]+);([^:]+)/', $line[1], $regs2) && !preg_match('/^TYPE=/i', $regs2[2])) { - $line[1] = $regs2[1] . ";TYPE=" . strtr($regs2[2], array(";" => ",")); + // 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])); foreach($regs2[1] as $attrid => $attr) { - if ((list($key, $value) = explode('=', $attr)) && $value) - $entry[strtolower($key)] = array_merge((array)$entry[strtolower($key)], (array)self::vcard_unquote($value, ',')); - elseif ($attrid > 0) + 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 + } } $data[$regs2[1][0]][] = count($entry) > 1 ? $entry : $entry[0]; @@ -292,6 +299,28 @@ class rcube_vcard } + /** + * Decode a given string with the encoding rule from ENCODING attributes + * + * @param string String to decode + * @param string Encoding type (quoted-printable and base64 supported) + * @return string Decoded 8bit value + */ + private static function decode_value($value, $encoding) + { + switch (strtolower($encoding)) { + case 'quoted-printable': + return quoted_printable_decode($value); + + case 'base64': + return base64_decode($value); + + default: + return $value; + } + } + + /** * Encodes an entry for storage in our database (vcard 3.0 format, unfolded) * @@ -381,7 +410,7 @@ class rcube_vcard )*\z/xs', substr($string, 0, 2048))) return 'UTF-8'; - return null; + return 'ISO-8859-1'; # fallback to Latin-1 } } diff --git a/program/steps/addressbook/import.inc b/program/steps/addressbook/import.inc index a0786e214..93452eccd 100644 --- a/program/steps/addressbook/import.inc +++ b/program/steps/addressbook/import.inc @@ -124,6 +124,12 @@ if ($_FILES['_file']['tmp_name'] && is_uploaded_file($_FILES['_file']['tmp_name' foreach ($vcards as $vcard) { $email = $vcard->email[0]; + // skip entries without an e-mail address + if (empty($email)) { + $IMPORT_STATS->nomail++; + continue; + } + if (!$replace) { // compare e-mail address $existing = $CONTACTS->search('email', $email, false, false); @@ -135,11 +141,6 @@ if ($_FILES['_file']['tmp_name'] && is_uploaded_file($_FILES['_file']['tmp_name' continue; } } - // skip entries without an e-mail address - if (empty($email)) { - $IMPORT_STATS->nomail++; - continue; - } $success = $CONTACTS->insert(array( 'name' => $vcard->displayname, -- cgit v1.2.3