diff --git a/addressbook/inc/class.addressbook_groupdav.inc.php b/addressbook/inc/class.addressbook_groupdav.inc.php index 00689b24dd..f4df479a60 100644 --- a/addressbook/inc/class.addressbook_groupdav.inc.php +++ b/addressbook/inc/class.addressbook_groupdav.inc.php @@ -291,10 +291,8 @@ class addressbook_groupdav extends groupdav_handler private function _get_handler() { $handler =& new addressbook_vcal(); - if (strpos($_SERVER['HTTP_USER_AGENT'],'KHTML') !== false) - { - $handler->setSupportedFields('KDE'); - } + $handler->setSupportedFields('GroupDAV',$this->agent); + return $handler; } diff --git a/addressbook/inc/class.addressbook_vcal.inc.php b/addressbook/inc/class.addressbook_vcal.inc.php index 83e2259dd6..2770e16c60 100644 --- a/addressbook/inc/class.addressbook_vcal.inc.php +++ b/addressbook/inc/class.addressbook_vcal.inc.php @@ -128,11 +128,11 @@ class addressbook_vcal extends addressbook_bo { $value = $GLOBALS['egw']->translation->convert(trim($value), $sysCharSet,$_charset); - if(($extra_charset_attribute || $this->productManufacturer == 'kde') && preg_match('/([\177-\377])/',$value)) + if(($extra_charset_attribute || $this->productName == 'kde') && preg_match('/([\177-\377])/',$value)) { $options['CHARSET'] = $_charset; // KAddressbook requires non-ascii chars to be qprint encoded, other clients eg. nokia phones have trouble with that - if ($this->productManufacturer == 'kde') + if ($this->productName == 'kde') { $options['ENCODING'] = 'QUOTED-PRINTABLE'; } @@ -251,7 +251,7 @@ class addressbook_vcal extends addressbook_bo 'TITLE' => array('title'), ); - $defaultFields[1] = array( // all entries, nexthaus corporation, ... + $defaultFields[1] = array( // all entries, nexthaus corporation, groupdav, ... 'ADR;WORK' => array('','','adr_one_street','adr_one_locality','adr_one_region', 'adr_one_postalcode','adr_one_countryname'), 'ADR;HOME' => array('','','adr_two_street','adr_two_locality','adr_two_region', @@ -618,8 +618,15 @@ class addressbook_vcal extends addressbook_bo $this->supportedFields = $defaultFields[1]; break; - case 'kde': // KDE Addressbook via GroupDAV - $this->supportedFields = $defaultFields[8]; + case 'groupdav': // all GroupDAV access goes through here + switch($this->productName) + { + case 'kde': // KDE Addressbook + $this->supportedFields = $defaultFields[8]; + break; + default: + $this->supportedFields = $defaultFields[1]; + } break; // the fallback for SyncML diff --git a/calendar/inc/class.calendar_groupdav.inc.php b/calendar/inc/class.calendar_groupdav.inc.php index a14333a201..9f1c050126 100644 --- a/calendar/inc/class.calendar_groupdav.inc.php +++ b/calendar/inc/class.calendar_groupdav.inc.php @@ -99,14 +99,15 @@ class calendar_groupdav extends groupdav_handler //header('X-EGROUPWARE-EVENT-'.$event['id'].': '.$event['title'].': '.date('Y-m-d H:i:s',$event['start']).' - '.date('Y-m-d H:i:s',$event['end'])); $props = array( HTTP_WebDAV_Server::mkprop('getetag',$this->get_etag($event)), - HTTP_WebDAV_Server::mkprop('getcontenttype', strpos($_SERVER['HTTP_USER_AGENT'],'KHTML') === false ? + HTTP_WebDAV_Server::mkprop('getcontenttype', $this->agent != 'kde' ? 'text/calendar; charset=utf-8; component=VEVENT' : 'text/calendar'), // getlastmodified and getcontentlength are required by WebDAV and Cadaver eg. reports 404 Not found if not set HTTP_WebDAV_Server::mkprop('getlastmodified', $event['modified']), ); if ($calendar_data) { - $content = ExecMethod2('calendar.calendar_ical.exportVCal',array($event),'2.0','PUBLISH',false,false); + if (is_null($handler)) $handler = $this->_get_handler(); + $content = $handler->exportVCal(array($event),'2.0','PUBLISH'); $props[] = HTTP_WebDAV_Server::mkprop('getcontentlength',bytes($content)); $props[] = HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'calendar-data',$content); } @@ -247,7 +248,8 @@ class calendar_groupdav extends groupdav_handler { return $event; } - $options['data'] = ExecMethod2('calendar.calendar_ical.exportVCal',array($event),'2.0','PUBLISH',false,false); + $handler = $this->_get_handler(); + $options['data'] = $handler->exportVCal(array($event),'2.0','PUBLISH'); $options['mimetype'] = 'text/calendar; charset=utf-8'; header('Content-Encoding: identity'); header('ETag: '.$this->get_etag($event)); @@ -270,7 +272,8 @@ class calendar_groupdav extends groupdav_handler { return $event; } - if (!($cal_id = ExecMethod2('calendar.calendar_ical.importVCal',$options['content'],is_numeric($id) ? $id : -1, + $handler = $this->_get_handler(); + if (!($cal_id = $handler->importVCal($options['content'],is_numeric($id) ? $id : -1, self::etag2value($this->http_if_match)))) { if ($this->debug) error_log(__METHOD__."(,$id) importVCal($options[content]) returned false"); @@ -373,4 +376,17 @@ class calendar_groupdav extends groupdav_handler return $props; } + + /** + * Get the handler and set the supported fields + * + * @return calendar_ical + */ + private function _get_handler() + { + $handler =& new calendar_ical(); + $handler->setSupportedFields('GroupDAV',$this->agent); + + return $handler; + } } \ No newline at end of file diff --git a/calendar/inc/class.calendar_ical.inc.php b/calendar/inc/class.calendar_ical.inc.php index d7f6200a4c..1d343e7b79 100644 --- a/calendar/inc/class.calendar_ical.inc.php +++ b/calendar/inc/class.calendar_ical.inc.php @@ -107,12 +107,9 @@ class calendar_ical extends calendar_boupdate * @param int/array $events (array of) cal_id or array of the events * @param string $version='1.0' could be '2.0' too * @param string $method='PUBLISH' - * @param boolean $force_own_uid=true ignore the stored and maybe from the client transfered uid and generate a new one - * RalfBecker: GroupDAV/CalDAV requires to switch that non RFC conform behavior off, dont know if SyncML still needs it - * @param boolean $extra_charset_attribute=true GroupDAV/CalDAV dont need the charset attribute and some clients have problems with it - * @return string/boolean string with vCal or false on error (eg. no permission to read the event) + * @return string/boolean string with iCal or false on error (eg. no permission to read the event) */ - function &exportVCal($events,$version='1.0', $method='PUBLISH',$force_own_uid=true,$extra_charset_attribute=true) + function &exportVCal($events,$version='1.0', $method='PUBLISH') { $egwSupportedFields = array( 'CLASS' => array('dbName' => 'public'), @@ -443,7 +440,6 @@ class calendar_ical extends calendar_boupdate } } - //$attributes['UID'] = $force_own_uid ? $eventGUID : $event['uid']; $attributes['UID'] = $event['uid']; foreach($attributes as $key => $value) { @@ -459,7 +455,7 @@ class calendar_ical extends calendar_boupdate { $options['ENCODING'] = 'QUOTED-PRINTABLE'; } - if($extra_charset_attribute && preg_match('/([\177-\377])/',$valueData)) + if($this->productManufacturer != 'GroupDAV' && preg_match('/([\177-\377])/',$valueData)) { $options['CHARSET'] = 'UTF-8'; } @@ -1221,6 +1217,14 @@ class calendar_ical extends calendar_boupdate $this->supportedFields = $defaultFields['full']; break; + case 'groupdav': // all GroupDAV access goes through here + switch($this->productName) + { + default: + $this->supportedFields = $defaultFields['full']; + } + break; + // the fallback for SyncML default: error_log("Unknown calendar SyncML client: manufacturer='$_productManufacturer' product='$_productName'"); diff --git a/infolog/inc/class.infolog_groupdav.inc.php b/infolog/inc/class.infolog_groupdav.inc.php index a5dcd09557..9857db6c2d 100644 --- a/infolog/inc/class.infolog_groupdav.inc.php +++ b/infolog/inc/class.infolog_groupdav.inc.php @@ -69,7 +69,7 @@ class infolog_groupdav extends groupdav_handler 'path' => '/infolog/'.$task['info_id'].'.ics', 'props' => array( HTTP_WebDAV_Server::mkprop('getetag',$this->get_etag($task)), - HTTP_WebDAV_Server::mkprop('getcontenttype', strpos($_SERVER['HTTP_USER_AGENT'],'KHTML') === false ? + HTTP_WebDAV_Server::mkprop('getcontenttype',$this->agent != 'kde' ? 'text/calendar; charset=utf-8; component=VTODO' : 'text/calendar'), // Konqueror (3.5) dont understand it otherwise // getlastmodified and getcontentlength are required by WebDAV and Cadaver eg. reports 404 Not found if not set HTTP_WebDAV_Server::mkprop('getlastmodified', $task['info_datemodified']), @@ -94,7 +94,7 @@ class infolog_groupdav extends groupdav_handler { return $task; } - $handler = new infolog_ical(); + $handler = $this->_get_handler(); $options['data'] = $handler->exportVTODO($id,'2.0',false,false); // keep UID the client set and no extra charset attributes $options['mimetype'] = 'text/calendar; charset=utf-8'; header('Content-Encoding: identity'); @@ -117,7 +117,7 @@ class infolog_groupdav extends groupdav_handler { return $ok; } - $handler = new infolog_ical(); + $handler = $this->_get_handler(); if (!($info_id = $handler->importVTODO($options['content'],is_numeric($id) ? $id : -1))) { if ($this->debug) error_log(__METHOD__."(,$id) import_vtodo($options[content]) returned false"); @@ -189,4 +189,17 @@ class infolog_groupdav extends groupdav_handler } return '"'.$info['info_id'].':'.$info['info_datemodified'].'"'; } + + /** + * Get the handler and set the supported fields + * + * @return infolog_ical + */ + private function _get_handler() + { + $handler =& new infolog_ical(); + $handler->setSupportedFields('GroupDAV',$this->agent); + + return $handler; + } } \ 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 7a14d1b502..fe6f535db1 100644 --- a/infolog/inc/class.infolog_ical.inc.php +++ b/infolog/inc/class.infolog_ical.inc.php @@ -31,17 +31,23 @@ class infolog_ical extends infolog_bo 3 => 0, ); + /** + * manufacturer and name of the sync-client + * + * @var string + */ + var $productManufacturer = 'file'; + var $productName = ''; + /** * Exports one InfoLog tast to an iCalendar VTODO * * @param int $_taskID info_id - * @param string $version='2.0' could be '1.0' too - * @param boolean $force_own_uid=true ignore the stored and maybe from the client transfered uid and generate a new one - * RalfBecker: GroupDAV/CalDAV requires to switch that non RFC conform behavior off, dont know if SyncML still needs it - * @param boolean $extra_charset_attribute=true GroupDAV/CalDAV dont need the charset attribute and some clients have problems with it + * @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) */ - function exportVTODO($_taskID, $_version='2.0',$force_own_uid=true,$extra_charset_attribute=true) + function exportVTODO($_taskID, $_version='2.0',$_method='PUBLISH') { $taskData = $this->read($_taskID); @@ -51,7 +57,7 @@ class infolog_ical extends infolog_bo $vcal = &new Horde_iCalendar; $vcal->setAttribute('VERSION',$_version); - $vcal->setAttribute('METHOD','PUBLISH'); + $vcal->setAttribute('METHOD',$_method); $vevent = Horde_iCalendar::newComponent('VTODO',$vcal); @@ -68,7 +74,7 @@ class infolog_ical extends infolog_bo { $options['ENCODING'] = 'QUOTED-PRINTABLE'; } - if($extra_charset_attribute && preg_match('/([\177-\377])/',$value)) + if($this->productManufacturer != 'GroupDAV' && preg_match('/([\177-\377])/',$value)) { $options['CHARSET'] = 'UTF-8'; } @@ -83,7 +89,6 @@ class infolog_ical extends infolog_bo $vevent->setAttribute('DTSTAMP',time()); $vevent->setAttribute('CREATED',$GLOBALS['egw']->contenthistory->getTSforAction('infolog_task',$_taskID,'add')); $vevent->setAttribute('LAST-MODIFIED',$GLOBALS['egw']->contenthistory->getTSforAction('infolog_task',$_taskID,'modify')); - //$vevent->setAttribute('UID',$force_own_uid ? $taskGUID : $taskData['info_uid']); $vevent->setAttribute('UID',$taskData['info_uid']); $vevent->setAttribute('CLASS',$taskData['info_access'] == 'public' ? 'PUBLIC' : 'PRIVATE'); $vevent->setAttribute('STATUS',$this->status2vtodo($taskData['info_status'])); @@ -375,5 +380,20 @@ class infolog_ical extends infolog_bo } return FALSE; } + + /** + * Set the supported fields + * + * Currently we only store manufacturer and name + * + * @param string $_productManufacturer + * @param string $_productName + */ + function setSupportedFields($_productManufacturer='file', $_productName='') + { + // save them vor later use + $this->productManufacturer = $_productManufacturer; + $this->productName = $_productName; + } } diff --git a/phpgwapi/inc/class.groupdav_handler.inc.php b/phpgwapi/inc/class.groupdav_handler.inc.php index ae07141988..bfe0efe3e8 100644 --- a/phpgwapi/inc/class.groupdav_handler.inc.php +++ b/phpgwapi/inc/class.groupdav_handler.inc.php @@ -65,6 +65,12 @@ abstract class groupdav_handler * @var string */ var $http_if_match; + /** + * Identified user agent + * + * @var string + */ + var $agent; /** * Constructor @@ -78,6 +84,7 @@ abstract class groupdav_handler $this->app = $app; if (!is_null($debug)) $this->debug = $debug; $this->base_uri = is_null($base_uri) ? $base_uri : $_SERVER['SCRIPT_NAME']; + $this->agent = self::get_agent(); $this->translation =& $GLOBALS['egw']->translation; $this->egw_charset = $this->translation->charset(); @@ -259,4 +266,41 @@ abstract class groupdav_handler } return $handler_cache[$app]; } + + /** + * Identify know GroupDAV agents by HTTP_USER_AGENT header + * + * @return string|boolean agent name or false + */ + static function get_agent() + { + static $agent; + + if (is_null($agent)) + { + $agent = false; + // identify the agent (GroupDAV client) from the HTTP_USER_AGENT header + $user_agent = strtolower($_SERVER['HTTP_USER_AGENT']); + foreach(array( + 'davkit' => 'davkit', // Apple iCal + 'bionicmessage.net' => 'funambol', // funambol GroupDAV connector from bionicmessage.net + 'zideone' => 'zideone', // zideone outlook plugin + 'lightning' => 'lightning', // Lighting (SOGo connector for addressbook) + 'khtml' => 'kde', // KDE clients + 'cadaver' => 'cadaver', + ) as $pattern => $name) + { + if (strpos($user_agent,$pattern) !== false) + { + $agent = $name; + break; + } + } + if (!$agent) + { + error_log("Unrecogniced GroupDAV client: HTTP_USER_AGENT='$_SERVER[HTTP_USER_AGENT]'!"); + } + } + return $agent; + } } \ No newline at end of file