diff --git a/addressbook/inc/class.addressbook_hooks.inc.php b/addressbook/inc/class.addressbook_hooks.inc.php index b1d791c394..3bed6efecc 100644 --- a/addressbook/inc/class.addressbook_hooks.inc.php +++ b/addressbook/inc/class.addressbook_hooks.inc.php @@ -305,7 +305,7 @@ class addressbook_hooks 'help' => 'Which charset should be used for the vCard import and export.', 'xmlrpc' => True, 'admin' => false, - 'default'=> 'iso-8859-1', + 'default'=> 'utf-8', ); } return $settings; diff --git a/addressbook/inc/class.addressbook_vcal.inc.php b/addressbook/inc/class.addressbook_vcal.inc.php index f006514afc..6d0adaa0a8 100644 --- a/addressbook/inc/class.addressbook_vcal.inc.php +++ b/addressbook/inc/class.addressbook_vcal.inc.php @@ -12,9 +12,10 @@ * @version $Id$ */ +use EGroupware\Api; + /** * Addressbook - vCard parser - * */ class addressbook_vcal extends addressbook_bo { @@ -555,11 +556,17 @@ class addressbook_vcal extends addressbook_bo $container = false; $vCard = Horde_Icalendar::newComponent('vcard', $container); - if (!$vCard->parsevCalendar($_vcard, 'VCARD', $charset)) + if ($charset && $charset != 'utf-8') + { + $_vcard = Api\Translation::convert($_vcard, $charset, 'utf-8'); + } + if (!$vCard->parsevCalendar($_vcard, 'VCARD')) { return False; } - } else { + } + else + { $vCard = $_vcard; } $vcardValues = $vCard->getAllAttributes(); diff --git a/addressbook/js/app.js b/addressbook/js/app.js index d64fc3defa..88b8a9ff4a 100644 --- a/addressbook/js/app.js +++ b/addressbook/js/app.js @@ -230,7 +230,7 @@ app.classes.addressbook = AppJS.extend( extras.owner.push('c'+ids); } } - + if(orgs.length > 0) { // Get organisation contacts, then show infolog list @@ -704,13 +704,13 @@ app.classes.addressbook = AppJS.extend( adb_mail_vcard: function(_action, _elems) { var app_registry = egw.link_get_registry('mail'); - if (typeof app_registry['view'] == 'undefined') app_registry = egw.link_get_registry('felamimail'); var link = egw().link("/index.php","menuaction="+app_registry['add']['menuaction']); for (var i = 0; i < _elems.length; i++) { var idToUse = _elems[i].id; var idToUseArray = idToUse.split('::'); idToUse = idToUseArray[1]; + link += "&preset[type][]="+encodeURIComponent("text/vcard; charset="+(egw.preference('vcard_charset', 'addressbook') || 'utf-8')); link += "&preset[file][]="+encodeURIComponent("vfs://default/apps/addressbook/"+idToUse+"/.entry"); } if (typeof app_registry['view'] != 'undefined' && typeof app_registry['view_popup'] != 'undefined' ) @@ -903,7 +903,7 @@ app.classes.addressbook = AppJS.extend( break; } }, - + /** * Get title in order to set it as document title * @returns {string} diff --git a/api/src/CalDAV/IcalIterator.php b/api/src/CalDAV/IcalIterator.php index 889861e3d6..9eeffce8ec 100644 --- a/api/src/CalDAV/IcalIterator.php +++ b/api/src/CalDAV/IcalIterator.php @@ -253,8 +253,12 @@ class IcalIterator extends Horde_Icalendar implements \Iterator return; //return PEAR::raiseError("Unable to create object for type $type"); } - //error_log(__METHOD__."() about to call parsevCalendar('".substr($data,0,100)."...','$type','$this->charset')"); - $this->component->parsevCalendar($data, $type, $this->charset); + if ($this->charset && $this->charset != 'utf-8') + { + $data = Api\Translation::convert($data, $this->charset, 'utf-8'); + } + //error_log(__METHOD__."() about to call parsevCalendar('".substr($data,0,100)."...','$type')"); + $this->component->parsevCalendar($data, $type); // VTIMEZONE components are NOT returned, they are only processed internally if ($type == 'VTIMEZONE') diff --git a/api/src/Mail.php b/api/src/Mail.php index 00e9bb6eaa..f710ebe7c4 100644 --- a/api/src/Mail.php +++ b/api/src/Mail.php @@ -5708,11 +5708,10 @@ class Mail if ($part && ($partDisposition=='attachment' || $partDisposition=='inline' || ($part->getPrimaryType() == 'text' && $part->getSubType() == 'calendar'))) { //$headerObject=$part->getAllDispositionParameters();//not used anywhere around here - $structure_bytes = $part->getBytes(); - $structure_mime=$part->getType(); - $structure_partID=$part->getMimeId(); - $filename=$part->getName(); - //error_log(__METHOD__.__LINE__." fetchPartContents(".array2string($_uid).", $structure_partID, $_stream, $_preserveSeen,$structure_mime)" ); + $structure_mime = $part->getType(); + $filename = $part->getName(); + $charset = $part->getContentTypeParameter('charset'); + //$structure_bytes = $part->getBytes(); $structure_partID=$part->getMimeId(); error_log(__METHOD__.__LINE__." fetchPartContents(".array2string($_uid).", $structure_partID, $_stream, $_preserveSeen,$structure_mime)" ); $this->fetchPartContents($_uid, $part, $_stream, $_preserveSeen=true,$structure_mime); if ($_returnPart) return $part; } @@ -5727,8 +5726,8 @@ class Mail } $attachmentData = array( 'type' => $structure_mime, + 'charset' => $charset, 'filename' => $filename, - //'attachment' => $part->getContents(array('stream'=>$_stream)) 'attachment' => $part->getContents(array( // tnef_decode needs strings not a stream 'stream' => $_stream && !($filename == 'winmail.dat' && $_winmail_nr) diff --git a/api/src/Mailer.php b/api/src/Mailer.php index 66a9e352f4..355feb5db4 100644 --- a/api/src/Mailer.php +++ b/api/src/Mailer.php @@ -321,19 +321,18 @@ class Mailer extends Horde_Mime_Mail * "text/calendar; method=..." get automatic detected and added as highest priority alternative * * @param string|resource $data Path to the attachment or open file-descriptor - * @param string $name The file name to use for the attachment. - * @param string $type The content type of the file. - * @param string $charset The character set of the part, only relevant for text parts. + * @param string $name =null file name to use for the attachment + * @param string $type =null content type of the file, incl. parameters eg. "text/plain; charset=utf-8" + * @param string $old_type =null used to support phpMailer signature (deprecated) * @return integer part-number * @throws Exception\NotFound if $file could not be opened for reading */ - public function addAttachment($data, $name = null, $type = null, $charset = 'us-ascii') + public function addAttachment($data, $name = null, $type = null, $old_type=null) { // deprecated PHPMailer::AddAttachment($path, $name = '', $encoding = 'base64', $type = 'application/octet-stream') call if ($type === 'base64') { - $type = $charset; - $charset = 'us-ascii'; + $type = $old_type; } // pass file as resource to Horde_Mime_Part::setContent() @@ -358,6 +357,14 @@ class Mailer extends Horde_Mime_Mail $part = new Horde_Mime_Part(); $part->setType($type); + // set content-type parameters, which get ignored by setType + if (preg_match_all('/;\s*([^=]+)=([^;]*)/', $type, $matches)) + { + foreach($matches[1] as $n => $label) + { + $part->setContentTypeParameter($label, $matches[2][$n]); + } + } $part->setContents($resource); // setting name, also sets content-disposition attachment (!), therefore we have to do it after "text/calendar; method=" handling @@ -365,7 +372,7 @@ class Mailer extends Horde_Mime_Mail // this should not be necessary, because binary data get detected by mime-type, // but at least Cyrus complains about NUL characters - $part->setTransferEncoding('base64', array('send' => true)); + if (substr($type, 0, 5) != 'text/') $part->setTransferEncoding('base64', array('send' => true)); $part->setDisposition('attachment'); return $this->addMimePart($part); diff --git a/calendar/inc/class.calendar_ical.inc.php b/calendar/inc/class.calendar_ical.inc.php index cce7cb38d0..baa09a9b81 100644 --- a/calendar/inc/class.calendar_ical.inc.php +++ b/calendar/inc/class.calendar_ical.inc.php @@ -2264,7 +2264,11 @@ class calendar_ical extends calendar_boupdate $events = array(); $vcal = new Horde_Icalendar; - if (!$vcal->parsevCalendar($_vcalData, 'VCALENDAR', $charset)) + if ($charset && $charset != 'utf-8') + { + $_vcalData = Api\Translation::convert($_vcalData, $charset, 'utf-8'); + } + if (!$vcal->parsevCalendar($_vcalData, 'VCALENDAR')) { if ($this->log) { diff --git a/infolog/inc/class.infolog_ical.inc.php b/infolog/inc/class.infolog_ical.inc.php index d0a5cce8c0..489c4f81c6 100644 --- a/infolog/inc/class.infolog_ical.inc.php +++ b/infolog/inc/class.infolog_ical.inc.php @@ -405,7 +405,7 @@ class infolog_ical extends infolog_bo foreach((array)$value as $compvData) { $comp = Horde_Icalendar::newComponent(substr($name,3), $vevent); - $comp->parsevCalendar($compvData,substr($name,3),'utf-8'); + $comp->parsevCalendar($compvData,substr($name,3)); $vevent->addComponent($comp); } } @@ -654,7 +654,11 @@ class infolog_ical extends infolog_bo } $vcal = new Horde_Icalendar; - if (!($vcal->parsevCalendar($_vcalData, 'VCALENDAR', $charset))) + if ($charset && $charset != 'utf-8') + { + $_vcalData = Api\Translation::convert($_vcalData, $charset, 'utf-8'); + } + if (!($vcal->parsevCalendar($_vcalData, 'VCALENDAR'))) { if ($this->log) { @@ -1096,7 +1100,11 @@ class infolog_ical extends infolog_bo case 'text/x-vnote': $vnote = new Horde_Icalendar; - if (!$vnote->parsevCalendar($_data, 'VCALENDAR', $charset)) return false; + if ($charset && $charset != 'utf-8') + { + $_data = Api\Translation::convert($_data, $charset, 'utf-8'); + } + if (!$vnote->parsevCalendar($_data, 'VCALENDAR')) return false; $components = $vnote->getComponent(); foreach ($components as $component) diff --git a/mail/inc/class.mail_compose.inc.php b/mail/inc/class.mail_compose.inc.php index 6081817d4e..cb522689ce 100644 --- a/mail/inc/class.mail_compose.inc.php +++ b/mail/inc/class.mail_compose.inc.php @@ -913,6 +913,11 @@ class mail_compose { $name .= '.'.mime_magic::mime2ext($type); } + // use type specified by caller, if Vfs reports only default, or contains specified type (eg. "text/vcard; charset=utf-8") + if (!empty($types[$k]) && ($type == 'application/octet-stream' || stripos($types[$k], $type) === 0)) + { + $type = $types[$k]; + } $path = str_replace('+','%2B',$path); $formData = array( 'name' => $name, diff --git a/mail/inc/class.mail_ui.inc.php b/mail/inc/class.mail_ui.inc.php index 509f3b6ff9..3de000797f 100644 --- a/mail/inc/class.mail_ui.inc.php +++ b/mail/inc/class.mail_ui.inc.php @@ -2383,7 +2383,7 @@ $filter['before']= date("d-M-Y", $cutoffdate2); $eventid = $calendar_ical->search($attachment['attachment'],-1); //error_log(__METHOD__.array2string($eventid)); if (!$eventid) $eventid = -1; - $event = $calendar_ical->importVCal($attachment['attachment'],(is_array($eventid)?$eventid[0]:$eventid),null,true); + $event = $calendar_ical->importVCal($attachment['attachment'],(is_array($eventid)?$eventid[0]:$eventid),null,true,0,'',null,$attachment['charset']); //error_log(__METHOD__.$event); if ((int)$event > 0) { @@ -2401,7 +2401,7 @@ $filter['before']= date("d-M-Y", $cutoffdate2); // double \r\r\n seems to end a vcard prematurely, so we set them to \r\n //error_log(__METHOD__.__LINE__.$attachment['attachment']); $attachment['attachment'] = str_replace("\r\r\n", "\r\n", $attachment['attachment']); - $vcard = $addressbook_vcal->vcardtoegw($attachment['attachment']); + $vcard = $addressbook_vcal->vcardtoegw($attachment['attachment'], $attachment['charset']); if ($vcard['uid']) { $vcard['uid'] = trim($vcard['uid']); @@ -2412,7 +2412,7 @@ $filter['before']= date("d-M-Y", $cutoffdate2); // if there are not enough fields in the vcard (or the parser was unable to correctly parse the vcard (as of VERSION:3.0 created by MSO)) if ($contact || count($vcard)>2) { - $contact = $addressbook_vcal->addVCard($attachment['attachment'],(is_array($contact)?array_shift($contact):$contact),true); + $contact = $addressbook_vcal->addVCard($attachment['attachment'],(is_array($contact)?array_shift($contact):$contact),true,$attachment['charset']); } if ((int)$contact > 0) {