summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAleksander Machniak <alec@alec.pl>2014-08-01 12:49:37 +0200
committerAleksander Machniak <alec@alec.pl>2014-08-01 12:49:37 +0200
commitfcb7d4fc034335d960917abd37254bd3997cf2f3 (patch)
treedbd65826f37ad7dc17b3a4ff0dcec66cb4f1feaa
parent9453257baf8934cd7667c30d92450689c9a0ded8 (diff)
Fix various iCloud vCard issues, added fallback for external photos (#1489993)
-rw-r--r--CHANGELOG1
-rw-r--r--program/lib/Roundcube/html.php2
-rw-r--r--program/lib/Roundcube/rcube_vcard.php10
-rw-r--r--program/steps/addressbook/func.inc10
-rw-r--r--program/steps/addressbook/photo.inc8
-rw-r--r--program/steps/mail/show.inc4
-rw-r--r--tests/Framework/VCard.php19
7 files changed, 42 insertions, 12 deletions
diff --git a/CHANGELOG b/CHANGELOG
index a6ade5bfc..a2de91fa6 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -41,6 +41,7 @@ CHANGELOG Roundcube Webmail
- Fix some mime-type to extension mapping checks in Installer (#1489983)
- Fix errors when using localStorage in Safari's private browsing mode (#1489996)
- Fix bug where $Forwarded flag was being set even if server didn't support it (#1490000)
+- Fix various iCloud vCard issues, added fallback for external photos (#1489993)
RELEASE 1.0.2
-------------
diff --git a/program/lib/Roundcube/html.php b/program/lib/Roundcube/html.php
index bcf89d7df..f18cad0bf 100644
--- a/program/lib/Roundcube/html.php
+++ b/program/lib/Roundcube/html.php
@@ -153,7 +153,7 @@ class html
$attr = array('src' => $attr);
}
return self::tag('img', $attr + array('alt' => ''), null, array_merge(self::$common_attrib,
- array('src','alt','width','height','border','usemap','onclick')));
+ array('src','alt','width','height','border','usemap','onclick','onerror')));
}
/**
diff --git a/program/lib/Roundcube/rcube_vcard.php b/program/lib/Roundcube/rcube_vcard.php
index 4a2684f10..96add110f 100644
--- a/program/lib/Roundcube/rcube_vcard.php
+++ b/program/lib/Roundcube/rcube_vcard.php
@@ -110,7 +110,7 @@ class rcube_vcard
public function load($vcard, $charset = RCUBE_CHARSET, $detect = false)
{
self::$values_decoded = false;
- $this->raw = self::vcard_decode($vcard);
+ $this->raw = self::vcard_decode(self::cleanup($vcard));
// resolve charset parameters
if ($charset == null) {
@@ -496,7 +496,7 @@ class rcube_vcard
if (preg_match('/^END:VCARD$/i', $line)) {
// parse vcard
- $obj = new rcube_vcard(self::cleanup($vcard_block), $charset, true, self::$fieldmap);
+ $obj = new rcube_vcard($vcard_block, $charset, true, self::$fieldmap);
// FN and N is required by vCard format (RFC 2426)
// on import we can be less restrictive, let's addressbook decide
if (!empty($obj->displayname) || !empty($obj->surname) || !empty($obj->firstname) || !empty($obj->email)) {
@@ -532,9 +532,9 @@ class rcube_vcard
// Cleanup
$vcard = preg_replace(array(
// convert special types (like Skype) to normal type='skype' classes with this simple regex ;)
- '/item(\d+)\.(TEL|EMAIL|URL)([^:]*?):(.*?)item\1.X-ABLabel:(?:_\$!<)?([\w-() ]*)(?:>!\$_)?./s',
- '/^item\d*\.X-AB.*$/m', // remove cruft like item1.X-AB*
- '/^item\d*\./m', // remove item1.ADR instead of ADR
+ '/item(\d+)\.(TEL|EMAIL|URL)([^:]*?):(.*?)item\1.X-ABLabel:(?:_\$!<)?([\w-() ]*)(?:>!\$_)?./si',
+ '/^item\d*\.X-AB.*$/mi', // remove cruft like item1.X-AB*
+ '/^item\d*\./mi', // remove item1.ADR instead of ADR
'/\n+/', // remove empty lines
'/^(N:[^;\R]*)$/m', // if N doesn't have any semicolons, add some
),
diff --git a/program/steps/addressbook/func.inc b/program/steps/addressbook/func.inc
index d4c57cc9d..38de93d05 100644
--- a/program/steps/addressbook/func.inc
+++ b/program/steps/addressbook/func.inc
@@ -816,11 +816,15 @@ function rcmail_contact_photo($attrib)
}
$photo_img = $RCMAIL->url($url);
}
- else
+ else {
$ff_value = '-del-'; // will disable delete-photo action
+ }
- $img = html::img(array('src' => $photo_img, 'border' => 1, 'alt' => $RCMAIL->gettext('contactphoto')));
- $content = html::div($attrib, $img);
+ $content = html::div($attrib, html::img(array(
+ 'src' => $photo_img,
+ 'alt' => $RCMAIL->gettext('contactphoto'),
+ 'onerror' => 'this.src = rcmail.env.photo_placeholder',
+ )));
if ($CONTACT_COLTYPES['photo'] && ($RCMAIL->action == 'edit' || $RCMAIL->action == 'add')) {
$RCMAIL->output->add_gui_object('contactphoto', $attrib['id']);
diff --git a/program/steps/addressbook/photo.inc b/program/steps/addressbook/photo.inc
index 482185735..30d09ffcc 100644
--- a/program/steps/addressbook/photo.inc
+++ b/program/steps/addressbook/photo.inc
@@ -72,8 +72,12 @@ $plugin = $RCMAIL->plugins->exec_hook('contact_photo',
if ($plugin['url']) {
$RCMAIL->output->redirect($plugin['url']);
}
-else {
- $data = $plugin['data'];
+
+$data = $plugin['data'];
+
+// detect if photo data is an URL
+if (strlen($data) < 1024 && filter_var($data, FILTER_VALIDATE_URL)) {
+ $RCMAIL->output->redirect($data);
}
// deliver alt image
diff --git a/program/steps/mail/show.inc b/program/steps/mail/show.inc
index 4b2d78d31..d4121fdd8 100644
--- a/program/steps/mail/show.inc
+++ b/program/steps/mail/show.inc
@@ -349,8 +349,10 @@ function rcmail_message_contactphoto($attrib)
'_task' => 'addressbook',
'_action' => 'photo',
'_email' => $MESSAGE->sender['mailto'],
- '_alt' => $placeholder
+ '_alt' => $placeholder,
));
+
+ $attrib['onerror'] = "this.src = '" . ($placeholder ? $placeholder : 'program/resources/blank.gif') . "'";
}
else {
$photo_img = $placeholder ? $placeholder : 'program/resources/blank.gif';
diff --git a/tests/Framework/VCard.php b/tests/Framework/VCard.php
index 0a34fc51f..c23dba844 100644
--- a/tests/Framework/VCard.php
+++ b/tests/Framework/VCard.php
@@ -79,6 +79,25 @@ class Framework_VCard extends PHPUnit_Framework_TestCase
$this->assertEquals("http://domain.tld", $vcard['website:other'][0], "Decode dummy backslash character");
}
+ /**
+ * Some Apple vCard quirks (#1489993)
+ */
+ function test_parse_six()
+ {
+ $vcard = new rcube_vcard("BEGIN:VCARD\n"
+ . "VERSION:3.0\n"
+ . "N:;;;;\n"
+ . "FN:Apple Computer AG\n"
+ . "ITEM1.ADR;type=WORK;type=pref:;;Birgistrasse 4a;Wallisellen-Zürich;;8304;Switzerland\n"
+ . "PHOTO;ENCODING=B:aHR0cDovL3Rlc3QuY29t\n"
+ . "END:VCARD"
+ );
+
+ $result = $vcard->get_assoc();
+
+ $this->assertCount(1, $result['address:work'], "ITEM1.-prefixed entry");
+ }
+
function test_import()
{
$input = file_get_contents($this->_srcpath('apple.vcf'));