From 42a09eda30d1609077a8e1e3a45b0b347c88da7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Lehrke?= Date: Mon, 22 Mar 2010 18:03:23 +0000 Subject: [PATCH] Add configurable client character set for SyncML & various fixes --- .../inc/class.addressbook_vcal.inc.php | 33 ++++--- calendar/inc/class.calendar_ical.inc.php | 90 ++++++++++++------- infolog/inc/class.infolog_ical.inc.php | 65 +++++++++----- .../inc/horde/Horde/SyncML/Command/Alert.php | 2 +- phpgwapi/inc/horde/Horde/SyncML/State_egw.php | 3 + phpgwapi/inc/horde/Horde/iCalendar.php | 45 +++++++--- 6 files changed, 160 insertions(+), 78 deletions(-) diff --git a/addressbook/inc/class.addressbook_vcal.inc.php b/addressbook/inc/class.addressbook_vcal.inc.php index 05a0d31b6f..a832741025 100644 --- a/addressbook/inc/class.addressbook_vcal.inc.php +++ b/addressbook/inc/class.addressbook_vcal.inc.php @@ -119,11 +119,13 @@ class addressbook_vcal extends addressbook_bo * @param string $_vcard the vcard * @param int/string $_abID=null the internal addressbook id or !$_abID for a new enty * @param boolean $merge=false merge data with existing entry + * @param string $charset The encoding charset for $text. Defaults to + * utf-8 for new format, iso-8859-1 for old format. * @return int contact id */ - function addVCard($_vcard, $_abID=null, $merge=false) + function addVCard($_vcard, $_abID=null, $merge=false, $charset=null) { - if (!($contact = $this->vcardtoegw($_vcard))) return false; + if (!($contact = $this->vcardtoegw($_vcard, $charset))) return false; if ($_abID) { @@ -159,9 +161,10 @@ class addressbook_vcal extends addressbook_bo // update entry $contact['id'] = $_abID; } - elseif (array_key_exists('filter_addressbook', $GLOBALS['egw_info']['user']['preferences']['syncml'])) + elseif (isset($GLOBALS['egw_info']['user']['preferences']['syncml']['filter_addressbook']) && + (int)$GLOBALS['egw_info']['user']['preferences']['syncml']['filter_addressbook']) { - $contact['owner'] = (int) $GLOBALS['egw_info']['user']['preferences']['syncml']['filter_addressbook']; + $contact['owner'] = (int)$GLOBALS['egw_info']['user']['preferences']['syncml']['filter_addressbook']; if ($contact['owner'] == -1) { $contact['owner'] = $GLOBALS['egw_info']['user']['account_primary_group']; @@ -450,7 +453,7 @@ class addressbook_vcal extends addressbook_bo //$vCard->setParameter($vcardField, $options); } - $result = $vCard->exportvCalendar(); + $result = $vCard->exportvCalendar($_charset); if ($this->log) { error_log(__FILE__.'['.__LINE__.'] '.__METHOD__ . @@ -461,11 +464,11 @@ class addressbook_vcal extends addressbook_bo return $result; } - function search($_vcard, $contentID=null, $relax=false) + function search($_vcard, $contentID=null, $relax=false, $charset=null) { $result = array(); - if (($contact = $this->vcardtoegw($_vcard))) + if (($contact = $this->vcardtoegw($_vcard, $charset))) { if (is_array($contact['category'])) { @@ -490,12 +493,20 @@ class addressbook_vcal extends addressbook_bo if (is_array($_supportedFields)) $this->supportedFields = $_supportedFields; } - function vcardtoegw($_vcard) + /** + * Parses a string containing vCard data. + * + * @param string $_vcard The data to parse. + * @param string $charset The encoding charset for $text. Defaults to + * utf-8 for new format, iso-8859-1 for old format. + * + * @return array|boolean The contact data or false on errors. + */ + function vcardtoegw($_vcard, $charset=null) { // the horde class does the charset conversion. DO NOT CONVERT HERE. // be as flexible as possible - $databaseFields = array( 'ADR;WORK' => array('','adr_one_street2','adr_one_street','adr_one_locality','adr_one_region', 'adr_one_postalcode','adr_one_countryname'), @@ -539,14 +550,12 @@ class addressbook_vcal extends addressbook_bo array2string($_vcard)."\n",3,$this->logfile); } - //Horde::logMessage("vCalAddressbook vcardtoegw:\n$_vcard", __FILE__, __LINE__, PEAR_LOG_DEBUG); - require_once(EGW_SERVER_ROOT.'/phpgwapi/inc/horde/Horde/iCalendar.php'); $container = false; $vCard = Horde_iCalendar::newComponent('vcard', $container); - if (!$vCard->parsevCalendar($_vcard, 'VCARD')) + if (!$vCard->parsevCalendar($_vcard, 'VCARD', $charset)) { return False; } diff --git a/calendar/inc/class.calendar_ical.inc.php b/calendar/inc/class.calendar_ical.inc.php index 3fa47a1d33..41b6e722df 100644 --- a/calendar/inc/class.calendar_ical.inc.php +++ b/calendar/inc/class.calendar_ical.inc.php @@ -189,14 +189,15 @@ class calendar_ical extends calendar_boupdate * @param int $recur_date=0 if set export the next recurrence at or after the timestamp, * default 0 => export whole series (or events, if not recurring) * @param string $principalURL='' Used for CalDAV exports - * @return string|boolean string with iCal or false on error (eg. no permission to read the event) + * @param string $charset='UTF-8' encoding of the vcalendar, default UTF-8 + * @return string|boolean string with iCal or false on error (e.g. no permission to read the event) */ - function &exportVCal($events, $version='1.0', $method='PUBLISH', $recur_date=0, $principalURL='') + function &exportVCal($events, $version='1.0', $method='PUBLISH', $recur_date=0, $principalURL='', $charset='UTF-8') { if ($this->log) { error_log(__FILE__.'['.__LINE__.'] '.__METHOD__. - "($version, $method, $recur_date, $principalURL)\n", + "($version, $method, $recur_date, $principalURL, $charset)\n", 3, $this->logfile); } $egwSupportedFields = array( @@ -465,20 +466,30 @@ class calendar_ical extends calendar_boupdate switch ($icalFieldName) { case 'ATTENDEE': - //if (count($event['participants']) == 1 && isset($event['participants'][$this->user])) break; foreach ((array)$event['participants'] as $uid => $status) { if (!($info = $this->resource_info($uid))) continue; - $participantURL = $info['email'] ? 'MAILTO:'.$info['email'] : ''; - $participantCN = '"' . ($info['cn'] ? $info['cn'] : $info['name']) . '"'; + if ($this->log) + { + error_log(__FILE__.'['.__LINE__.'] '.__METHOD__ . + '()attendee:' . array2string($info) ."\n",3,$this->logfile); + } + $participantCN = '"' . (empty($info['cn']) ? $info['name'] : $info['cn']) . '"'; + if ($version == '1.0') + { + $participantURL = trim($participantCN . (empty($info['email']) ? '' : ' <' . $info['email'] .'>')); + } + else + { + $participantURL = empty($info['email']) ? '' : 'MAILTO:' . $info['email']; + } calendar_so::split_status($status, $quantity, $role); - if ($role == 'CHAIR' && $uid != $this->user) + if ($role == 'CHAIR') { $organizerURL = $participantURL; $organizerCN = $participantCN; $organizerUID = $uid; } - // RB: MAILTO href contains only the email-address, NO cn! $attributes['ATTENDEE'][] = $participantURL; // RSVP={TRUE|FALSE} // resonse expected, not set in eGW => status=U $rsvp = $status == 'U' ? 'TRUE' : 'FALSE'; @@ -522,10 +533,17 @@ class calendar_ical extends calendar_boupdate // according to iCalendar standard, ORGANIZER not used for events in the own calendar if (!$organizerCN) { - $organizerURL = $GLOBALS['egw']->accounts->id2name($event['owner'],'account_email'); - $organizerURL = $organizerURL ? 'MAILTO:'.$organizerURL : ''; - $organizerCN = '"' . trim($GLOBALS['egw']->accounts->id2name($event['owner'],'account_firstname') + $organizerCN = '"' . trim($GLOBALS['egw']->accounts->id2name($event['owner'],'account_firstname') . ' ' . $GLOBALS['egw']->accounts->id2name($event['owner'],'account_lastname')) . '"'; + $organizerURL = $GLOBALS['egw']->accounts->id2name($event['owner'],'account_email'); + if ($version == '1.0') + { + $organizerURL = trim($organizerCN . (empty($organizerURL) ? '' : ' <' . $organizerURL .'>')); + } + else + { + $organizerURL = empty($organizerURL) ? '' : 'MAILTO:' . $organizerURL; + } $organizerUID = $event['owner']; if (!isset($event['participants'][$event['owner']])) { @@ -870,18 +888,18 @@ class calendar_ical extends calendar_boupdate { foreach (is_array($value) && $parameters[$key]['VALUE']!='DATE' ? $value : array($value) as $valueID => $valueData) { - $valueData = $GLOBALS['egw']->translation->convert($valueData,$GLOBALS['egw']->translation->charset(),'UTF-8'); + $valueData = $GLOBALS['egw']->translation->convert($valueData,$GLOBALS['egw']->translation->charset(),$charset); $paramData = (array) $GLOBALS['egw']->translation->convert(is_array($value) ? $parameters[$key][$valueID] : $parameters[$key], - $GLOBALS['egw']->translation->charset(),'UTF-8'); + $GLOBALS['egw']->translation->charset(),$charset); $valuesData = (array) $GLOBALS['egw']->translation->convert($values[$key], - $GLOBALS['egw']->translation->charset(),'UTF-8'); + $GLOBALS['egw']->translation->charset(),$charset); $content = $valueData . implode(';', $valuesData); if (preg_match('/[^\x20-\x7F]/', $content) || ($paramData['CN'] && preg_match('/[^\x20-\x7F]/', $paramData['CN']))) { - $paramData['CHARSET'] = 'UTF-8'; + $paramData['CHARSET'] = $charset; switch ($this->productManufacturer) { case 'groupdav': @@ -973,13 +991,15 @@ class calendar_ical extends calendar_boupdate * default 0 => import whole series (or events, if not recurring) * @param string $principalURL='' Used for CalDAV imports * @param int $user=null account_id of owner, default null + * @param string $charset The encoding charset for $text. Defaults to + * utf-8 for new format, iso-8859-1 for old format. * @return int|boolean cal_id > 0 on success, false on failure or 0 for a failed etag */ - function importVCal($_vcalData, $cal_id=-1, $etag=null, $merge=false, $recur_date=0, $principalURL='', $user=null) + function importVCal($_vcalData, $cal_id=-1, $etag=null, $merge=false, $recur_date=0, $principalURL='', $user=null, $charset=null) { if (!is_array($this->supportedFields)) $this->setSupportedFields(); - if (!($events = $this->icaltoegw($_vcalData, $principalURL))) + if (!($events = $this->icaltoegw($_vcalData, $principalURL, $charset))) { return false; } @@ -1025,7 +1045,7 @@ class calendar_ical extends calendar_boupdate if ($this->log) { error_log(__FILE__.'['.__LINE__.'] '.__METHOD__ - ."($cal_id, $etag, $recur_date, $principalURL, $user)\n" + ."($cal_id, $etag, $recur_date, $principalURL, $user, $charset)\n" . array2string($event)."\n",3,$this->logfile); } @@ -1739,10 +1759,10 @@ class calendar_ical extends calendar_boupdate { switch ($deviceInfo['tzid']) { - case 1: + case -1: $this->tzid = false; // use event's TZ break; - case 2: + case -2: $this->tzid = null; // use UTC for export break; default: @@ -1943,9 +1963,16 @@ class calendar_ical extends calendar_boupdate break; case 'file': // used outside of SyncML, eg. by the calendar itself ==> all possible fields - if ($this->cal_prefs['export_timezone']) + if (isset($this->cal_prefs['export_timezone'])) { - $this->tzid = $this->cal_prefs['export_timezone']; + switch ($this->cal_prefs['export_timezone']) + { + case 1: + $this->tzid = false; // use event's TZ + break; + default: + $this->tzid = $this->cal_prefs['export_timezone']; + } } else { @@ -1993,13 +2020,15 @@ class calendar_ical extends calendar_boupdate * * @param string $_vcalData * @param string $principalURL='' Used for CalDAV imports + * @param string $charset The encoding charset for $text. Defaults to + * utf-8 for new format, iso-8859-1 for old format. * @return array|boolean events on success, false on failure */ - function icaltoegw($_vcalData, $principalURL='') + function icaltoegw($_vcalData, $principalURL='', $charset=null) { if ($this->log) { - error_log(__FILE__.'['.__LINE__.'] '.__METHOD__."($principalURL)\n" . + error_log(__FILE__.'['.__LINE__.'] '.__METHOD__."($principalURL, $charset)\n" . array2string($_vcalData)."\n",3,$this->logfile); } @@ -2017,7 +2046,7 @@ class calendar_ical extends calendar_boupdate date_default_timezone_set($tzid); $vcal = new Horde_iCalendar; - if (!$vcal->parsevCalendar($_vcalData)) + if (!$vcal->parsevCalendar($_vcalData, 'VCALENDAR', $charset)) { if ($this->log) { @@ -2825,9 +2854,9 @@ class calendar_ical extends calendar_boupdate return $event; } - function search($_vcalData, $contentID=null, $relax=false) + function search($_vcalData, $contentID=null, $relax=false, $charset=null) { - if (($events = $this->icaltoegw($_vcalData))) + if (($events = $this->icaltoegw($_vcalData, $charset))) { // this function only supports searching a single event if (count($events) == 1) @@ -2859,9 +2888,10 @@ class calendar_ical extends calendar_boupdate * @param int $user account_id * @param mixed $end=null end-date, default now+1 month * @param boolean $utc=true if false, use severtime for dates + * @param string $charset='UTF-8' encoding of the vcalendar, default UTF-8 * @return string */ - function freebusy($user,$end=null,$utc=true) + function freebusy($user,$end=null,$utc=true, $charset='UTF-8') { if (!$end) $end = $this->now_su + 100*DAY_s; // default next 100 days @@ -2875,7 +2905,7 @@ class calendar_ical extends calendar_boupdate 'ORGANIZER' => $GLOBALS['egw']->translation->convert( $GLOBALS['egw']->accounts->id2name($user,'account_firstname').' '. $GLOBALS['egw']->accounts->id2name($user,'account_lastname'), - $GLOBALS['egw']->translation->charset(),'utf-8'), + $GLOBALS['egw']->translation->charset(),$charset), ); if ($utc) { @@ -2934,6 +2964,6 @@ class calendar_ical extends calendar_boupdate } $vcal->addComponent($vfreebusy); - return $vcal->exportvCalendar(); + return $vcal->exportvCalendar($charset); } } \ No newline at end of file diff --git a/infolog/inc/class.infolog_ical.inc.php b/infolog/inc/class.infolog_ical.inc.php index 8ead65250a..b083dc369a 100644 --- a/infolog/inc/class.infolog_ical.inc.php +++ b/infolog/inc/class.infolog_ical.inc.php @@ -114,9 +114,11 @@ class infolog_ical extends infolog_bo * @param int|array $task infolog_id or infolog-tasks data * @param string $_version='2.0' could be '1.0' too * @param string $_method='PUBLISH' - * @return string/boolean string with vCal or false on error (eg. no permission to read the event) + * @param string $charset='UTF-8' encoding of the vcalendar, default UTF-8 + * + * @return string|boolean string with vCal or false on error (eg. no permission to read the event) */ - function exportVTODO($task, $_version='2.0',$_method='PUBLISH') + function exportVTODO($task, $_version='2.0',$_method='PUBLISH', $charset='UTF-8') { if (is_array($task)) { @@ -156,7 +158,7 @@ class infolog_ical extends infolog_bo } $taskData = $GLOBALS['egw']->translation->convert($taskData, - $GLOBALS['egw']->translation->charset(), 'UTF-8'); + $GLOBALS['egw']->translation->charset(), $charset); if ($this->log) { @@ -275,7 +277,7 @@ class infolog_ical extends infolog_bo if (preg_match('/[^\x20-\x7F]/', $value)) { - $options['CHARSET'] = 'UTF-8'; + $options['CHARSET'] = $charset; switch ($this->productManufacturer) { case 'groupdav': @@ -421,16 +423,19 @@ class infolog_ical extends infolog_bo * @param int $_taskID=-1 info_id, default -1 = new entry * @param boolean $merge=false merge data with existing entry * @param int $user=null delegate new task to this account_id, default null + * @param string $charset The encoding charset for $text. Defaults to + * utf-8 for new format, iso-8859-1 for old format. + * * @return int|boolean integer info_id or false on error */ - function importVTODO(&$_vcalData, $_taskID=-1, $merge=false, $user=null) + function importVTODO(&$_vcalData, $_taskID=-1, $merge=false, $user=null, $charset=null) { if ($this->tzid) { date_default_timezone_set($this->tzid); } - $taskData = $this->vtodotoegw($_vcalData,$_taskID); + $taskData = $this->vtodotoegw($_vcalData,$_taskID, $charset); if ($this->tzid) { date_default_timezone_set($GLOBALS['egw_info']['server']['server_timezone']); @@ -472,10 +477,12 @@ class infolog_ical extends infolog_bo * @param string $_vcalData VTODO * @param int $contentID=null infolog_id (or null, if unkown) * @param boolean $relax=false if true, a weaker match algorithm is used + * @param string $charset The encoding charset for $text. Defaults to + * utf-8 for new format, iso-8859-1 for old format. * * @return array of infolog_ids of matching entries */ - function searchVTODO($_vcalData, $contentID=null, $relax=false) + function searchVTODO($_vcalData, $contentID=null, $relax=false, $charset=null) { $result = array(); @@ -483,7 +490,7 @@ class infolog_ical extends infolog_bo { date_default_timezone_set($this->tzid); } - $taskData = $this->vtodotoegw($_vcalData,$contentID); + $taskData = $this->vtodotoegw($_vcalData, $contentID, $charset); if ($this->tzid) { date_default_timezone_set($GLOBALS['egw_info']['server']['server_timezone']); @@ -504,9 +511,12 @@ class infolog_ical extends infolog_bo * * @param string $_vcalData VTODO data * @param int $_taskID=-1 infolog_id of the entry + * @param string $charset The encoding charset for $text. Defaults to + * utf-8 for new format, iso-8859-1 for old format. + * * @return array infolog entry or false on error */ - function vtodotoegw($_vcalData, $_taskID=-1) + function vtodotoegw($_vcalData, $_taskID=-1, $charset=null) { if ($this->log) { @@ -515,7 +525,7 @@ class infolog_ical extends infolog_bo } $vcal = new Horde_iCalendar; - if (!($vcal->parsevCalendar($_vcalData))) + if (!($vcal->parsevCalendar($_vcalData, 'VCALENDAR', $charset))) { if ($this->log) { @@ -683,14 +693,16 @@ class infolog_ical extends infolog_bo * * @param int $_noteID the infolog_id of the entry * @param string $_type content type (e.g. text/plain) - * @return string VNOTE representation of the infolog entry + * @param string $charset='UTF-8' encoding of the vcalendar, default UTF-8 + * + * @return string|boolean VNOTE representation of the infolog entry or false on error */ - function exportVNOTE($_noteID, $_type) + function exportVNOTE($_noteID, $_type, $charset='UTF-8') { if(!($note = $this->read($_noteID, true, 'server'))) return false; $note = $GLOBALS['egw']->translation->convert($note, - $GLOBALS['egw']->translation->charset(), 'UTF-8'); + $GLOBALS['egw']->translation->charset(), $charset); switch ($_type) { @@ -703,7 +715,7 @@ class infolog_ical extends infolog_bo { $cats = $this->get_categories(array($note['info_cat'])); $note['info_cat'] = $GLOBALS['egw']->translation->convert($cats[0], - $GLOBALS['egw']->translation->charset(), 'UTF-8'); + $GLOBALS['egw']->translation->charset(), $charset); } $vnote = new Horde_iCalendar_vnote(); $vNote->setAttribute('VERSION', '1.1'); @@ -715,7 +727,7 @@ class infolog_ical extends infolog_bo $options = array(); if (preg_match('/[^\x20-\x7F]/', $value)) { - $options['CHARSET'] = 'UTF-8'; + $options['CHARSET'] = $charset; switch ($this->productManufacturer) { case 'groupdav': @@ -773,9 +785,12 @@ class infolog_ical extends infolog_bo * @param string $_type content type (eg.g text/plain) * @param int $_noteID=-1 info_id, default -1 = new entry * @param boolean $merge=false merge data with existing entry + * @param string $charset The encoding charset for $text. Defaults to + * utf-8 for new format, iso-8859-1 for old format. + * * @return int|boolean integer info_id or false on error */ - function importVNOTE(&$_vcalData, $_type, $_noteID=-1, $merge=false) + function importVNOTE(&$_vcalData, $_type, $_noteID=-1, $merge=false, $charset=null) { if ($this->log) { @@ -783,7 +798,7 @@ class infolog_ical extends infolog_bo array2string($_vcalData)."\n",3,$this->logfile); } - if (!($note = $this->vnotetoegw($_vcalData, $_type, $_noteID))) return false; + if (!($note = $this->vnotetoegw($_vcalData, $_type, $_noteID, $charset))) return false; if($_noteID > 0) $note['info_id'] = $_noteID; @@ -804,12 +819,14 @@ class infolog_ical extends infolog_bo * @param string $_vcalData VNOTE * @param int $contentID=null infolog_id (or null, if unkown) * @param boolean $relax=false if true, a weaker match algorithm is used + * @param string $charset The encoding charset for $text. Defaults to + * utf-8 for new format, iso-8859-1 for old format. * * @return infolog_id of a matching entry or false, if nothing was found */ - function searchVNOTE($_vcalData, $_type, $contentID=null, $relax=false) + function searchVNOTE($_vcalData, $_type, $contentID=null, $relax=false, $charset=null) { - if (!($note = $this->vnotetoegw($_vcalData,$_type,$contentID))) return array(); + if (!($note = $this->vnotetoegw($_vcalData, $_type, $contentID, $charset))) return array(); if ($contentID) $note['info_id'] = $contentID; @@ -824,9 +841,12 @@ class infolog_ical extends infolog_bo * @param string $_data VNOTE data * @param string $_type content type (eg.g text/plain) * @param int $_noteID=-1 infolog_id of the entry + * @param string $charset The encoding charset for $text. Defaults to + * utf-8 for new format, iso-8859-1 for old format. + * * @return array infolog entry or false on error */ - function vnotetoegw($_data, $_type, $_noteID=-1) + function vnotetoegw($_data, $_type, $_noteID=-1, $charset=null) { if ($this->log) { @@ -840,8 +860,7 @@ class infolog_ical extends infolog_bo case 'text/plain': $note = array(); $note['info_type'] = 'note'; - $botranslation =& CreateObject('phpgwapi.translation'); - $txt = $botranslation->convert($_data, 'utf-8'); + $txt = $GLOBALS['egw']->translation->convert($_data, $charset); $txt = str_replace("\r\n", "\n", $txt); if (preg_match('/([^\n]+)\n\n(.*)/m', $txt, $match)) @@ -857,7 +876,7 @@ class infolog_ical extends infolog_bo case 'text/x-vnote': $vnote = new Horde_iCalendar; - if (!$vcal->parsevCalendar($_data)) return false; + if (!$vcal->parsevCalendar($_data, 'VCALENDAR', $charset)) return false; $version = $vcal->getAttribute('VERSION'); $components = $vnote->getComponent(); diff --git a/phpgwapi/inc/horde/Horde/SyncML/Command/Alert.php b/phpgwapi/inc/horde/Horde/SyncML/Command/Alert.php index 61e057ea3c..1d4a8bfcc6 100644 --- a/phpgwapi/inc/horde/Horde/SyncML/Command/Alert.php +++ b/phpgwapi/inc/horde/Horde/SyncML/Command/Alert.php @@ -141,7 +141,7 @@ class Horde_SyncML_Command_Alert extends Horde_SyncML_Command { // Check if anchor sent from client matches our own stored // data. if ($clientlast == $this->_metaAnchorLast) { - // Last sync anchors matche, TwoWaySync will do. + // Last sync anchors match, TwoWaySync will do. $anchormatch = true; Horde::logMessage('SyncML: Anchor timestamps match, TwoWaySync possible. Syncing data since ' . date('Y-m-d H:i:s', $serverAnchorLast), diff --git a/phpgwapi/inc/horde/Horde/SyncML/State_egw.php b/phpgwapi/inc/horde/Horde/SyncML/State_egw.php index a3daf0aa12..e2e72c4cd9 100644 --- a/phpgwapi/inc/horde/Horde/SyncML/State_egw.php +++ b/phpgwapi/inc/horde/Horde/SyncML/State_egw.php @@ -157,6 +157,7 @@ class EGW_SyncML_State extends Horde_SyncML_State $deviceUIDExtension = 'uidExtension-' . $this->_sourceURI; $deviceNonBlockingAllday = 'nonBlockingAllday-' . $this->_sourceURI; $deviceTimezone = 'tzid-' . $this->_sourceURI; + $deviceCharSet = 'charset-' . $this->_sourceURI; if (isset($this->_clientDeviceInfo) && is_array($this->_clientDeviceInfo)) { // update user preferences @@ -164,6 +165,7 @@ class EGW_SyncML_State extends Horde_SyncML_State $this->_clientDeviceInfo['uidExtension'] = $syncml_prefs[$deviceUIDExtension]; $this->_clientDeviceInfo['nonBlockingAllday'] = $syncml_prefs[$deviceNonBlockingAllday]; $this->_clientDeviceInfo['tzid'] = $syncml_prefs[$deviceTimezone]; + $this->_clientDeviceInfo['charset'] = $syncml_prefs[$deviceCharSet]; // use cached information return $this->_clientDeviceInfo; } @@ -214,6 +216,7 @@ class EGW_SyncML_State extends Horde_SyncML_State 'uidExtension' => $syncml_prefs[$deviceUIDExtension], 'nonBlockingAllday' => $syncml_prefs[$deviceNonBlockingAllday], 'tzid' => $syncml_prefs[$deviceTimezone], + 'charset' => $syncml_prefs[$deviceCharSet], 'dataStore' => unserialize($row['dev_datastore']), ); return $this->_clientDeviceInfo; diff --git a/phpgwapi/inc/horde/Horde/iCalendar.php b/phpgwapi/inc/horde/Horde/iCalendar.php index f6e99fd9df..ede61557e5 100644 --- a/phpgwapi/inc/horde/Horde/iCalendar.php +++ b/phpgwapi/inc/horde/Horde/iCalendar.php @@ -462,8 +462,11 @@ class Horde_iCalendar { /** * Export as vCalendar format. + * + * @param string $charset The encoding charset for $text. Defaults to + * utf-8 for new format, standard character set for old format. */ - function exportvCalendar() + function exportvCalendar($charset = null) { // Default values. $requiredAttributes['PRODID'] = '-//The Horde Project//Horde_iCalendar Library' . (defined('HORDE_VERSION') ? ', Horde ' . constant('HORDE_VERSION') : '') . '//EN'; @@ -475,7 +478,7 @@ class Horde_iCalendar { } } - return $this->_exportvData('VCALENDAR'); + return $this->_exportvData('VCALENDAR', $charset); } /** @@ -881,10 +884,12 @@ class Horde_iCalendar { * Export this component in vCal format. * * @param string $base The type of the base object. + * @param string $charset The encoding charset for $text. Defaults to + * utf-8 for new format, standard character set for old format. * * @return string vCal format data. */ - function _exportvData($base = 'VCALENDAR') + function _exportvData($base = 'VCALENDAR', $charset = null) { $base = String::upper($base); @@ -898,6 +903,15 @@ class Horde_iCalendar { // Ensure that version is the first attribute. $result .= 'VERSION:' . $this->_version . $this->_newline; } + + if (empty($charset)) { + if ($this->isOldFormat()) { + $charset = NLS::getCharset(); + } else { + $charset = 'utf-8'; + } + } + foreach ($this->_attributes as $attribute) { $name = $attribute['name']; if ($name == 'VERSION') { @@ -910,9 +924,12 @@ class Horde_iCalendar { if ($params) { foreach ($params as $param_name => $param_value) { /* Skip CHARSET for iCalendar 2.0 data, not allowed. */ - if ($param_name == 'CHARSET' - && (!$this->isOldFormat() || empty($param_value))) { - continue; + if ($param_name == 'CHARSET') { + if (!$this->isOldFormat() || empty($param_value)) { + continue; + } else { + $param_value = String::Upper($param_value); + } } if ($param_name == 'ENCODING') { continue; @@ -926,6 +943,11 @@ class Horde_iCalendar { if ($this->isOldFormat() && $param_name == 'TZID') { continue; } + // Skip CN in ATTENDEE adn ORGANIZER for vCalendar 1.0 + if ($this->isOldFormat() && $param_name == 'CN' && + ($name == 'ATTENDEE' || $name == 'ORGANIZER')) { + continue; + } if ($param_value === null) { $params_str .= ";$param_name"; } else { @@ -945,8 +967,7 @@ class Horde_iCalendar { $value = $this->_exportDateTime($value); break; - - // Support additional fields after date. + // Support additional fields after date. case 'AALARM': case 'DALARM': if (isset($params['VALUE'])) { @@ -1143,7 +1164,7 @@ class Horde_iCalendar { !isset($params['CHARSET'])) { // Add CHARSET as well. At least the synthesis client // gets confused otherwise - $params['CHARSET'] = NLS::getCharset(); + $params['CHARSET'] = String::upper($charset); $params_str .= ';CHARSET=' . $params['CHARSET']; } } else { @@ -1209,7 +1230,7 @@ class Horde_iCalendar { $params_str .= ';ENCODING=' . $params['ENCODING']; $attr_string = $name . $params_str . ':' . $this->_newline . ' ' . $this->_base64Encode($value); $attr_string = String::wordwrap($attr_string, 75, $this->_newline . ' ', - true, 'utf-8', true); + true, 'utf-8', true); // charset does not matter $result .= $attr_string . $this->_newline; if ($this->isOldFormat()) { $result .= $this->_newline; // Append an empty line @@ -1227,7 +1248,7 @@ class Horde_iCalendar { } if (!$this->isOldFormat()) { $attr_string = String::wordwrap($attr_string, 75, $this->_newline . ' ', - true, 'utf-8', true); + true, $charset, true); } $result .= $attr_string . $this->_newline; } @@ -1238,7 +1259,7 @@ class Horde_iCalendar { // Not supported continue; } - $result .= $component->exportvCalendar(); + $result .= $component->exportvCalendar($charset); } return $result . 'END:' . $base . $this->_newline;