Improve vcard import: map more fields, support photo urls, better UTF-16 charset detection

release-0.6
thomascube 13 years ago
parent ec6c397769
commit 0fbadebe13

@ -40,6 +40,7 @@ class rcube_vcard
'notes' => 'NOTE',
'email' => 'EMAIL',
'address' => 'ADR',
'jobtitle' => 'TITLE',
'gender' => 'X-GENDER',
'maidenname' => 'X-MAIDENNAME',
'anniversary' => 'X-ANNIVERSARY',
@ -165,6 +166,10 @@ class rcube_vcard
}
}
}
// force subtype if none set
if (preg_match('/^(email|phone|address|website)/', $key) && !$subtype)
$subtype = 'other';
if ($subtype)
$key .= ':' . $subtype;
@ -277,8 +282,14 @@ class rcube_vcard
break;
case 'photo':
$encoded = !preg_match('![^a-z0-9/=+-]!i', $value);
$this->raw['PHOTO'][0] = array(0 => $encoded ? $value : base64_encode($value), 'BASE64' => true);
if (strpos($value, 'http:') === 0) {
// TODO: fetch file from URL and save it locally?
$this->raw['PHOTO'][0] = array(0 => $value, 'URL' => true);
}
else {
$encoded = !preg_match('![^a-z0-9/=+-]!i', $value);
$this->raw['PHOTO'][0] = array(0 => $encoded ? $value : base64_encode($value), 'BASE64' => true);
}
break;
case 'email':
@ -422,10 +433,16 @@ class rcube_vcard
{
// Convert special types (like Skype) to normal type='skype' classes with this simple regex ;)
$vcard = preg_replace(
'/item(\d+)\.(TEL|URL)([^:]*?):(.*?)item\1.X-ABLabel:(?:_\$!<)?([\w-() ]*)(?:>!\$_)?./s',
'/item(\d+)\.(TEL|EMAIL|URL)([^:]*?):(.*?)item\1.X-ABLabel:(?:_\$!<)?([\w-() ]*)(?:>!\$_)?./s',
'\2;type=\5\3:\4',
$vcard);
// convert Apple X-ABRELATEDNAMES into X-* fields for better compatibility
$vcard = preg_replace_callback(
'/item(\d+)\.(X-ABRELATEDNAMES)([^:]*?):(.*?)item\1.X-ABLabel:(?:_\$!<)?([\w-() ]*)(?:>!\$_)?./s',
array('self', 'x_abrelatednames_callback'),
$vcard);
// Remove cruft like item1.X-AB*, item1.ADR instead of ADR, and empty lines
$vcard = preg_replace(array('/^item\d*\.X-AB.*$/m', '/^item\d*\./m', "/\n+/"), array('', '', "\n"), $vcard);
@ -440,6 +457,11 @@ class rcube_vcard
return $vcard;
}
private static function x_abrelatednames_callback($matches)
{
return 'X-' . strtoupper($matches[5]) . $matches[3] . ':'. $matches[4];
}
private static function rfc2425_fold_callback($matches)
{
@ -631,6 +653,12 @@ class rcube_vcard
if (substr($string, 0, 2) == "\xFF\xFE") return 'UTF-16LE'; // Little Endian
if (substr($string, 0, 3) == "\xEF\xBB\xBF") return 'UTF-8';
// heuristics
if ($string[0] == "\0" && $string[1] == "\0" && $string[2] == "\0" && $string[3] != "\0") return 'UTF-32BE';
if ($string[0] != "\0" && $string[1] == "\0" && $string[2] == "\0" && $string[3] == "\0") return 'UTF-32LE';
if ($string[0] == "\0" && $string[1] != "\0" && $string[2] == "\0" && $string[3] != "\0") return 'UTF-16BE';
if ($string[0] != "\0" && $string[1] == "\0" && $string[2] != "\0" && $string[3] == "\0") return 'UTF-16LE';
// use mb_detect_encoding()
$encodings = array('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',

@ -365,6 +365,10 @@ function rcmail_contact_form($form, $record, $attrib = null)
// skip cols unknown to the backend
if (!$coltypes[$col])
continue;
// only string values are expected here
if (is_array($record[$col]))
$record[$col] = join(' ', $record[$col]);
if ($RCMAIL->action == 'show') {
if (!empty($record[$col]))
@ -563,7 +567,9 @@ function rcmail_contact_photo($attrib)
if ($CONTACT_COLTYPES['photo']) {
$RCMAIL->output->set_env('photo_placeholder', $photo_img);
if ($record['photo'])
if (strpos($record['photo'], 'http:') === 0)
$photo_img = $record['photo'];
else if ($record['photo'])
$photo_img = $RCMAIL->url(array('_action' => 'photo', '_cid' => $record['ID'], '_source' => $_REQUEST['_source']));
$img = html::img(array('src' => $photo_img, 'border' => 1, 'alt' => ''));
$content = html::div($attrib, $img);

@ -138,7 +138,7 @@ if ($_FILES['_file']['tmp_name'] && is_uploaded_file($_FILES['_file']['tmp_name'
// We're using UTF8 internally
$email = rcube_idn_to_utf8($email);
if (!$replace) {
if (!$replace && $email) {
// compare e-mail address
$existing = $CONTACTS->search('email', $email, false, false);
if (!$existing->count) { // compare display name

Binary file not shown.

@ -54,4 +54,12 @@ class rcube_test_vcards extends UnitTestCase
$this->assertEqual("Iksiñski", $vcards2[0]->surname, "Detect charset in encoded values");
}
function test_encodings()
{
$input = file_get_contents($this->_srcpath('utf-16_sample.vcf'));
$vcards = rcube_vcard::import($input);
$this->assertEqual("Ǽgean ĽdaMonté", $vcards[0]->displayname, "Decoded from UTF-16");
}
}

Loading…
Cancel
Save