Add configurable client character set for SyncML & various fixes

This commit is contained in:
Jörg Lehrke 2010-03-22 18:03:23 +00:00
parent 1d4190276c
commit 42a09eda30
6 changed files with 160 additions and 78 deletions

View File

@ -119,11 +119,13 @@ class addressbook_vcal extends addressbook_bo
* @param string $_vcard the vcard * @param string $_vcard the vcard
* @param int/string $_abID=null the internal addressbook id or !$_abID for a new enty * @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 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 * @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) if ($_abID)
{ {
@ -159,9 +161,10 @@ class addressbook_vcal extends addressbook_bo
// update entry // update entry
$contact['id'] = $_abID; $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) if ($contact['owner'] == -1)
{ {
$contact['owner'] = $GLOBALS['egw_info']['user']['account_primary_group']; $contact['owner'] = $GLOBALS['egw_info']['user']['account_primary_group'];
@ -450,7 +453,7 @@ class addressbook_vcal extends addressbook_bo
//$vCard->setParameter($vcardField, $options); //$vCard->setParameter($vcardField, $options);
} }
$result = $vCard->exportvCalendar(); $result = $vCard->exportvCalendar($_charset);
if ($this->log) if ($this->log)
{ {
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__ . error_log(__FILE__.'['.__LINE__.'] '.__METHOD__ .
@ -461,11 +464,11 @@ class addressbook_vcal extends addressbook_bo
return $result; return $result;
} }
function search($_vcard, $contentID=null, $relax=false) function search($_vcard, $contentID=null, $relax=false, $charset=null)
{ {
$result = array(); $result = array();
if (($contact = $this->vcardtoegw($_vcard))) if (($contact = $this->vcardtoegw($_vcard, $charset)))
{ {
if (is_array($contact['category'])) if (is_array($contact['category']))
{ {
@ -490,12 +493,20 @@ class addressbook_vcal extends addressbook_bo
if (is_array($_supportedFields)) $this->supportedFields = $_supportedFields; 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. // the horde class does the charset conversion. DO NOT CONVERT HERE.
// be as flexible as possible // be as flexible as possible
$databaseFields = array( $databaseFields = array(
'ADR;WORK' => array('','adr_one_street2','adr_one_street','adr_one_locality','adr_one_region', 'ADR;WORK' => array('','adr_one_street2','adr_one_street','adr_one_locality','adr_one_region',
'adr_one_postalcode','adr_one_countryname'), 'adr_one_postalcode','adr_one_countryname'),
@ -539,14 +550,12 @@ class addressbook_vcal extends addressbook_bo
array2string($_vcard)."\n",3,$this->logfile); 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'); require_once(EGW_SERVER_ROOT.'/phpgwapi/inc/horde/Horde/iCalendar.php');
$container = false; $container = false;
$vCard = Horde_iCalendar::newComponent('vcard', $container); $vCard = Horde_iCalendar::newComponent('vcard', $container);
if (!$vCard->parsevCalendar($_vcard, 'VCARD')) if (!$vCard->parsevCalendar($_vcard, 'VCARD', $charset))
{ {
return False; return False;
} }

View File

@ -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, * @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) * default 0 => export whole series (or events, if not recurring)
* @param string $principalURL='' Used for CalDAV exports * @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) if ($this->log)
{ {
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__. error_log(__FILE__.'['.__LINE__.'] '.__METHOD__.
"($version, $method, $recur_date, $principalURL)\n", "($version, $method, $recur_date, $principalURL, $charset)\n",
3, $this->logfile); 3, $this->logfile);
} }
$egwSupportedFields = array( $egwSupportedFields = array(
@ -465,20 +466,30 @@ class calendar_ical extends calendar_boupdate
switch ($icalFieldName) switch ($icalFieldName)
{ {
case 'ATTENDEE': case 'ATTENDEE':
//if (count($event['participants']) == 1 && isset($event['participants'][$this->user])) break;
foreach ((array)$event['participants'] as $uid => $status) foreach ((array)$event['participants'] as $uid => $status)
{ {
if (!($info = $this->resource_info($uid))) continue; if (!($info = $this->resource_info($uid))) continue;
$participantURL = $info['email'] ? 'MAILTO:'.$info['email'] : ''; if ($this->log)
$participantCN = '"' . ($info['cn'] ? $info['cn'] : $info['name']) . '"'; {
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); calendar_so::split_status($status, $quantity, $role);
if ($role == 'CHAIR' && $uid != $this->user) if ($role == 'CHAIR')
{ {
$organizerURL = $participantURL; $organizerURL = $participantURL;
$organizerCN = $participantCN; $organizerCN = $participantCN;
$organizerUID = $uid; $organizerUID = $uid;
} }
// RB: MAILTO href contains only the email-address, NO cn!
$attributes['ATTENDEE'][] = $participantURL; $attributes['ATTENDEE'][] = $participantURL;
// RSVP={TRUE|FALSE} // resonse expected, not set in eGW => status=U // RSVP={TRUE|FALSE} // resonse expected, not set in eGW => status=U
$rsvp = $status == 'U' ? 'TRUE' : 'FALSE'; $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 // according to iCalendar standard, ORGANIZER not used for events in the own calendar
if (!$organizerCN) if (!$organizerCN)
{ {
$organizerURL = $GLOBALS['egw']->accounts->id2name($event['owner'],'account_email'); $organizerCN = '"' . trim($GLOBALS['egw']->accounts->id2name($event['owner'],'account_firstname')
$organizerURL = $organizerURL ? 'MAILTO:'.$organizerURL : '';
$organizerCN = '"' . trim($GLOBALS['egw']->accounts->id2name($event['owner'],'account_firstname')
. ' ' . $GLOBALS['egw']->accounts->id2name($event['owner'],'account_lastname')) . '"'; . ' ' . $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']; $organizerUID = $event['owner'];
if (!isset($event['participants'][$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) 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) ? $paramData = (array) $GLOBALS['egw']->translation->convert(is_array($value) ?
$parameters[$key][$valueID] : $parameters[$key], $parameters[$key][$valueID] : $parameters[$key],
$GLOBALS['egw']->translation->charset(),'UTF-8'); $GLOBALS['egw']->translation->charset(),$charset);
$valuesData = (array) $GLOBALS['egw']->translation->convert($values[$key], $valuesData = (array) $GLOBALS['egw']->translation->convert($values[$key],
$GLOBALS['egw']->translation->charset(),'UTF-8'); $GLOBALS['egw']->translation->charset(),$charset);
$content = $valueData . implode(';', $valuesData); $content = $valueData . implode(';', $valuesData);
if (preg_match('/[^\x20-\x7F]/', $content) || if (preg_match('/[^\x20-\x7F]/', $content) ||
($paramData['CN'] && preg_match('/[^\x20-\x7F]/', $paramData['CN']))) ($paramData['CN'] && preg_match('/[^\x20-\x7F]/', $paramData['CN'])))
{ {
$paramData['CHARSET'] = 'UTF-8'; $paramData['CHARSET'] = $charset;
switch ($this->productManufacturer) switch ($this->productManufacturer)
{ {
case 'groupdav': case 'groupdav':
@ -973,13 +991,15 @@ class calendar_ical extends calendar_boupdate
* default 0 => import whole series (or events, if not recurring) * default 0 => import whole series (or events, if not recurring)
* @param string $principalURL='' Used for CalDAV imports * @param string $principalURL='' Used for CalDAV imports
* @param int $user=null account_id of owner, default null * @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 * @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 (!is_array($this->supportedFields)) $this->setSupportedFields();
if (!($events = $this->icaltoegw($_vcalData, $principalURL))) if (!($events = $this->icaltoegw($_vcalData, $principalURL, $charset)))
{ {
return false; return false;
} }
@ -1025,7 +1045,7 @@ class calendar_ical extends calendar_boupdate
if ($this->log) if ($this->log)
{ {
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__ 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); . array2string($event)."\n",3,$this->logfile);
} }
@ -1739,10 +1759,10 @@ class calendar_ical extends calendar_boupdate
{ {
switch ($deviceInfo['tzid']) switch ($deviceInfo['tzid'])
{ {
case 1: case -1:
$this->tzid = false; // use event's TZ $this->tzid = false; // use event's TZ
break; break;
case 2: case -2:
$this->tzid = null; // use UTC for export $this->tzid = null; // use UTC for export
break; break;
default: default:
@ -1943,9 +1963,16 @@ class calendar_ical extends calendar_boupdate
break; break;
case 'file': // used outside of SyncML, eg. by the calendar itself ==> all possible fields 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 else
{ {
@ -1993,13 +2020,15 @@ class calendar_ical extends calendar_boupdate
* *
* @param string $_vcalData * @param string $_vcalData
* @param string $principalURL='' Used for CalDAV imports * @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 * @return array|boolean events on success, false on failure
*/ */
function icaltoegw($_vcalData, $principalURL='') function icaltoegw($_vcalData, $principalURL='', $charset=null)
{ {
if ($this->log) if ($this->log)
{ {
error_log(__FILE__.'['.__LINE__.'] '.__METHOD__."($principalURL)\n" . error_log(__FILE__.'['.__LINE__.'] '.__METHOD__."($principalURL, $charset)\n" .
array2string($_vcalData)."\n",3,$this->logfile); array2string($_vcalData)."\n",3,$this->logfile);
} }
@ -2017,7 +2046,7 @@ class calendar_ical extends calendar_boupdate
date_default_timezone_set($tzid); date_default_timezone_set($tzid);
$vcal = new Horde_iCalendar; $vcal = new Horde_iCalendar;
if (!$vcal->parsevCalendar($_vcalData)) if (!$vcal->parsevCalendar($_vcalData, 'VCALENDAR', $charset))
{ {
if ($this->log) if ($this->log)
{ {
@ -2825,9 +2854,9 @@ class calendar_ical extends calendar_boupdate
return $event; 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 // this function only supports searching a single event
if (count($events) == 1) if (count($events) == 1)
@ -2859,9 +2888,10 @@ class calendar_ical extends calendar_boupdate
* @param int $user account_id * @param int $user account_id
* @param mixed $end=null end-date, default now+1 month * @param mixed $end=null end-date, default now+1 month
* @param boolean $utc=true if false, use severtime for dates * @param boolean $utc=true if false, use severtime for dates
* @param string $charset='UTF-8' encoding of the vcalendar, default UTF-8
* @return string * @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 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( 'ORGANIZER' => $GLOBALS['egw']->translation->convert(
$GLOBALS['egw']->accounts->id2name($user,'account_firstname').' '. $GLOBALS['egw']->accounts->id2name($user,'account_firstname').' '.
$GLOBALS['egw']->accounts->id2name($user,'account_lastname'), $GLOBALS['egw']->accounts->id2name($user,'account_lastname'),
$GLOBALS['egw']->translation->charset(),'utf-8'), $GLOBALS['egw']->translation->charset(),$charset),
); );
if ($utc) if ($utc)
{ {
@ -2934,6 +2964,6 @@ class calendar_ical extends calendar_boupdate
} }
$vcal->addComponent($vfreebusy); $vcal->addComponent($vfreebusy);
return $vcal->exportvCalendar(); return $vcal->exportvCalendar($charset);
} }
} }

View File

@ -114,9 +114,11 @@ class infolog_ical extends infolog_bo
* @param int|array $task infolog_id or infolog-tasks data * @param int|array $task infolog_id or infolog-tasks data
* @param string $_version='2.0' could be '1.0' too * @param string $_version='2.0' could be '1.0' too
* @param string $_method='PUBLISH' * @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)) if (is_array($task))
{ {
@ -156,7 +158,7 @@ class infolog_ical extends infolog_bo
} }
$taskData = $GLOBALS['egw']->translation->convert($taskData, $taskData = $GLOBALS['egw']->translation->convert($taskData,
$GLOBALS['egw']->translation->charset(), 'UTF-8'); $GLOBALS['egw']->translation->charset(), $charset);
if ($this->log) if ($this->log)
{ {
@ -275,7 +277,7 @@ class infolog_ical extends infolog_bo
if (preg_match('/[^\x20-\x7F]/', $value)) if (preg_match('/[^\x20-\x7F]/', $value))
{ {
$options['CHARSET'] = 'UTF-8'; $options['CHARSET'] = $charset;
switch ($this->productManufacturer) switch ($this->productManufacturer)
{ {
case 'groupdav': case 'groupdav':
@ -421,16 +423,19 @@ class infolog_ical extends infolog_bo
* @param int $_taskID=-1 info_id, default -1 = new entry * @param int $_taskID=-1 info_id, default -1 = new entry
* @param boolean $merge=false merge data with existing entry * @param boolean $merge=false merge data with existing entry
* @param int $user=null delegate new task to this account_id, default null * @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 * @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) if ($this->tzid)
{ {
date_default_timezone_set($this->tzid); date_default_timezone_set($this->tzid);
} }
$taskData = $this->vtodotoegw($_vcalData,$_taskID); $taskData = $this->vtodotoegw($_vcalData,$_taskID, $charset);
if ($this->tzid) if ($this->tzid)
{ {
date_default_timezone_set($GLOBALS['egw_info']['server']['server_timezone']); 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 string $_vcalData VTODO
* @param int $contentID=null infolog_id (or null, if unkown) * @param int $contentID=null infolog_id (or null, if unkown)
* @param boolean $relax=false if true, a weaker match algorithm is used * @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 * @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(); $result = array();
@ -483,7 +490,7 @@ class infolog_ical extends infolog_bo
{ {
date_default_timezone_set($this->tzid); date_default_timezone_set($this->tzid);
} }
$taskData = $this->vtodotoegw($_vcalData,$contentID); $taskData = $this->vtodotoegw($_vcalData, $contentID, $charset);
if ($this->tzid) if ($this->tzid)
{ {
date_default_timezone_set($GLOBALS['egw_info']['server']['server_timezone']); 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 string $_vcalData VTODO data
* @param int $_taskID=-1 infolog_id of the entry * @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 * @return array infolog entry or false on error
*/ */
function vtodotoegw($_vcalData, $_taskID=-1) function vtodotoegw($_vcalData, $_taskID=-1, $charset=null)
{ {
if ($this->log) if ($this->log)
{ {
@ -515,7 +525,7 @@ class infolog_ical extends infolog_bo
} }
$vcal = new Horde_iCalendar; $vcal = new Horde_iCalendar;
if (!($vcal->parsevCalendar($_vcalData))) if (!($vcal->parsevCalendar($_vcalData, 'VCALENDAR', $charset)))
{ {
if ($this->log) if ($this->log)
{ {
@ -683,14 +693,16 @@ class infolog_ical extends infolog_bo
* *
* @param int $_noteID the infolog_id of the entry * @param int $_noteID the infolog_id of the entry
* @param string $_type content type (e.g. text/plain) * @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; if(!($note = $this->read($_noteID, true, 'server'))) return false;
$note = $GLOBALS['egw']->translation->convert($note, $note = $GLOBALS['egw']->translation->convert($note,
$GLOBALS['egw']->translation->charset(), 'UTF-8'); $GLOBALS['egw']->translation->charset(), $charset);
switch ($_type) switch ($_type)
{ {
@ -703,7 +715,7 @@ class infolog_ical extends infolog_bo
{ {
$cats = $this->get_categories(array($note['info_cat'])); $cats = $this->get_categories(array($note['info_cat']));
$note['info_cat'] = $GLOBALS['egw']->translation->convert($cats[0], $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 = new Horde_iCalendar_vnote();
$vNote->setAttribute('VERSION', '1.1'); $vNote->setAttribute('VERSION', '1.1');
@ -715,7 +727,7 @@ class infolog_ical extends infolog_bo
$options = array(); $options = array();
if (preg_match('/[^\x20-\x7F]/', $value)) if (preg_match('/[^\x20-\x7F]/', $value))
{ {
$options['CHARSET'] = 'UTF-8'; $options['CHARSET'] = $charset;
switch ($this->productManufacturer) switch ($this->productManufacturer)
{ {
case 'groupdav': case 'groupdav':
@ -773,9 +785,12 @@ class infolog_ical extends infolog_bo
* @param string $_type content type (eg.g text/plain) * @param string $_type content type (eg.g text/plain)
* @param int $_noteID=-1 info_id, default -1 = new entry * @param int $_noteID=-1 info_id, default -1 = new entry
* @param boolean $merge=false merge data with existing 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 * @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) if ($this->log)
{ {
@ -783,7 +798,7 @@ class infolog_ical extends infolog_bo
array2string($_vcalData)."\n",3,$this->logfile); 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; if($_noteID > 0) $note['info_id'] = $_noteID;
@ -804,12 +819,14 @@ class infolog_ical extends infolog_bo
* @param string $_vcalData VNOTE * @param string $_vcalData VNOTE
* @param int $contentID=null infolog_id (or null, if unkown) * @param int $contentID=null infolog_id (or null, if unkown)
* @param boolean $relax=false if true, a weaker match algorithm is used * @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 * @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; if ($contentID) $note['info_id'] = $contentID;
@ -824,9 +841,12 @@ class infolog_ical extends infolog_bo
* @param string $_data VNOTE data * @param string $_data VNOTE data
* @param string $_type content type (eg.g text/plain) * @param string $_type content type (eg.g text/plain)
* @param int $_noteID=-1 infolog_id of the entry * @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 * @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) if ($this->log)
{ {
@ -840,8 +860,7 @@ class infolog_ical extends infolog_bo
case 'text/plain': case 'text/plain':
$note = array(); $note = array();
$note['info_type'] = 'note'; $note['info_type'] = 'note';
$botranslation =& CreateObject('phpgwapi.translation'); $txt = $GLOBALS['egw']->translation->convert($_data, $charset);
$txt = $botranslation->convert($_data, 'utf-8');
$txt = str_replace("\r\n", "\n", $txt); $txt = str_replace("\r\n", "\n", $txt);
if (preg_match('/([^\n]+)\n\n(.*)/m', $txt, $match)) if (preg_match('/([^\n]+)\n\n(.*)/m', $txt, $match))
@ -857,7 +876,7 @@ class infolog_ical extends infolog_bo
case 'text/x-vnote': case 'text/x-vnote':
$vnote = new Horde_iCalendar; $vnote = new Horde_iCalendar;
if (!$vcal->parsevCalendar($_data)) return false; if (!$vcal->parsevCalendar($_data, 'VCALENDAR', $charset)) return false;
$version = $vcal->getAttribute('VERSION'); $version = $vcal->getAttribute('VERSION');
$components = $vnote->getComponent(); $components = $vnote->getComponent();

View File

@ -141,7 +141,7 @@ class Horde_SyncML_Command_Alert extends Horde_SyncML_Command {
// Check if anchor sent from client matches our own stored // Check if anchor sent from client matches our own stored
// data. // data.
if ($clientlast == $this->_metaAnchorLast) { if ($clientlast == $this->_metaAnchorLast) {
// Last sync anchors matche, TwoWaySync will do. // Last sync anchors match, TwoWaySync will do.
$anchormatch = true; $anchormatch = true;
Horde::logMessage('SyncML: Anchor timestamps match, TwoWaySync possible. Syncing data since ' Horde::logMessage('SyncML: Anchor timestamps match, TwoWaySync possible. Syncing data since '
. date('Y-m-d H:i:s', $serverAnchorLast), . date('Y-m-d H:i:s', $serverAnchorLast),

View File

@ -157,6 +157,7 @@ class EGW_SyncML_State extends Horde_SyncML_State
$deviceUIDExtension = 'uidExtension-' . $this->_sourceURI; $deviceUIDExtension = 'uidExtension-' . $this->_sourceURI;
$deviceNonBlockingAllday = 'nonBlockingAllday-' . $this->_sourceURI; $deviceNonBlockingAllday = 'nonBlockingAllday-' . $this->_sourceURI;
$deviceTimezone = 'tzid-' . $this->_sourceURI; $deviceTimezone = 'tzid-' . $this->_sourceURI;
$deviceCharSet = 'charset-' . $this->_sourceURI;
if (isset($this->_clientDeviceInfo) if (isset($this->_clientDeviceInfo)
&& is_array($this->_clientDeviceInfo)) { && is_array($this->_clientDeviceInfo)) {
// update user preferences // update user preferences
@ -164,6 +165,7 @@ class EGW_SyncML_State extends Horde_SyncML_State
$this->_clientDeviceInfo['uidExtension'] = $syncml_prefs[$deviceUIDExtension]; $this->_clientDeviceInfo['uidExtension'] = $syncml_prefs[$deviceUIDExtension];
$this->_clientDeviceInfo['nonBlockingAllday'] = $syncml_prefs[$deviceNonBlockingAllday]; $this->_clientDeviceInfo['nonBlockingAllday'] = $syncml_prefs[$deviceNonBlockingAllday];
$this->_clientDeviceInfo['tzid'] = $syncml_prefs[$deviceTimezone]; $this->_clientDeviceInfo['tzid'] = $syncml_prefs[$deviceTimezone];
$this->_clientDeviceInfo['charset'] = $syncml_prefs[$deviceCharSet];
// use cached information // use cached information
return $this->_clientDeviceInfo; return $this->_clientDeviceInfo;
} }
@ -214,6 +216,7 @@ class EGW_SyncML_State extends Horde_SyncML_State
'uidExtension' => $syncml_prefs[$deviceUIDExtension], 'uidExtension' => $syncml_prefs[$deviceUIDExtension],
'nonBlockingAllday' => $syncml_prefs[$deviceNonBlockingAllday], 'nonBlockingAllday' => $syncml_prefs[$deviceNonBlockingAllday],
'tzid' => $syncml_prefs[$deviceTimezone], 'tzid' => $syncml_prefs[$deviceTimezone],
'charset' => $syncml_prefs[$deviceCharSet],
'dataStore' => unserialize($row['dev_datastore']), 'dataStore' => unserialize($row['dev_datastore']),
); );
return $this->_clientDeviceInfo; return $this->_clientDeviceInfo;

View File

@ -462,8 +462,11 @@ class Horde_iCalendar {
/** /**
* Export as vCalendar format. * 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. // Default values.
$requiredAttributes['PRODID'] = '-//The Horde Project//Horde_iCalendar Library' . (defined('HORDE_VERSION') ? ', Horde ' . constant('HORDE_VERSION') : '') . '//EN'; $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. * Export this component in vCal format.
* *
* @param string $base The type of the base object. * @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. * @return string vCal format data.
*/ */
function _exportvData($base = 'VCALENDAR') function _exportvData($base = 'VCALENDAR', $charset = null)
{ {
$base = String::upper($base); $base = String::upper($base);
@ -898,6 +903,15 @@ class Horde_iCalendar {
// Ensure that version is the first attribute. // Ensure that version is the first attribute.
$result .= 'VERSION:' . $this->_version . $this->_newline; $result .= 'VERSION:' . $this->_version . $this->_newline;
} }
if (empty($charset)) {
if ($this->isOldFormat()) {
$charset = NLS::getCharset();
} else {
$charset = 'utf-8';
}
}
foreach ($this->_attributes as $attribute) { foreach ($this->_attributes as $attribute) {
$name = $attribute['name']; $name = $attribute['name'];
if ($name == 'VERSION') { if ($name == 'VERSION') {
@ -910,9 +924,12 @@ class Horde_iCalendar {
if ($params) { if ($params) {
foreach ($params as $param_name => $param_value) { foreach ($params as $param_name => $param_value) {
/* Skip CHARSET for iCalendar 2.0 data, not allowed. */ /* Skip CHARSET for iCalendar 2.0 data, not allowed. */
if ($param_name == 'CHARSET' if ($param_name == 'CHARSET') {
&& (!$this->isOldFormat() || empty($param_value))) { if (!$this->isOldFormat() || empty($param_value)) {
continue; continue;
} else {
$param_value = String::Upper($param_value);
}
} }
if ($param_name == 'ENCODING') { if ($param_name == 'ENCODING') {
continue; continue;
@ -926,6 +943,11 @@ class Horde_iCalendar {
if ($this->isOldFormat() && $param_name == 'TZID') { if ($this->isOldFormat() && $param_name == 'TZID') {
continue; 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) { if ($param_value === null) {
$params_str .= ";$param_name"; $params_str .= ";$param_name";
} else { } else {
@ -945,8 +967,7 @@ class Horde_iCalendar {
$value = $this->_exportDateTime($value); $value = $this->_exportDateTime($value);
break; break;
// Support additional fields after date.
// Support additional fields after date.
case 'AALARM': case 'AALARM':
case 'DALARM': case 'DALARM':
if (isset($params['VALUE'])) { if (isset($params['VALUE'])) {
@ -1143,7 +1164,7 @@ class Horde_iCalendar {
!isset($params['CHARSET'])) { !isset($params['CHARSET'])) {
// Add CHARSET as well. At least the synthesis client // Add CHARSET as well. At least the synthesis client
// gets confused otherwise // gets confused otherwise
$params['CHARSET'] = NLS::getCharset(); $params['CHARSET'] = String::upper($charset);
$params_str .= ';CHARSET=' . $params['CHARSET']; $params_str .= ';CHARSET=' . $params['CHARSET'];
} }
} else { } else {
@ -1209,7 +1230,7 @@ class Horde_iCalendar {
$params_str .= ';ENCODING=' . $params['ENCODING']; $params_str .= ';ENCODING=' . $params['ENCODING'];
$attr_string = $name . $params_str . ':' . $this->_newline . ' ' . $this->_base64Encode($value); $attr_string = $name . $params_str . ':' . $this->_newline . ' ' . $this->_base64Encode($value);
$attr_string = String::wordwrap($attr_string, 75, $this->_newline . ' ', $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; $result .= $attr_string . $this->_newline;
if ($this->isOldFormat()) { if ($this->isOldFormat()) {
$result .= $this->_newline; // Append an empty line $result .= $this->_newline; // Append an empty line
@ -1227,7 +1248,7 @@ class Horde_iCalendar {
} }
if (!$this->isOldFormat()) { if (!$this->isOldFormat()) {
$attr_string = String::wordwrap($attr_string, 75, $this->_newline . ' ', $attr_string = String::wordwrap($attr_string, 75, $this->_newline . ' ',
true, 'utf-8', true); true, $charset, true);
} }
$result .= $attr_string . $this->_newline; $result .= $attr_string . $this->_newline;
} }
@ -1238,7 +1259,7 @@ class Horde_iCalendar {
// Not supported // Not supported
continue; continue;
} }
$result .= $component->exportvCalendar(); $result .= $component->exportvCalendar($charset);
} }
return $result . 'END:' . $base . $this->_newline; return $result . 'END:' . $base . $this->_newline;