Reworked GroupDAV and iCal/vCard handler to set 'GroupDAV' as product

manufacturer and the recogniced GroupDAV client as product name.
This way we are able to handle different GroupDAV clients, as we
allready do with different SyncML clients.
Also removed the no longer needed code enabling the use of the real UID, 
as SyncML does no longer misuse the UID for it's GUID.
This commit is contained in:
Ralf Becker 2008-11-03 09:36:20 +00:00
parent 71edd1c938
commit 43f860ba8f
7 changed files with 133 additions and 31 deletions

View File

@ -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;
}

View File

@ -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,9 +618,16 @@ class addressbook_vcal extends addressbook_bo
$this->supportedFields = $defaultFields[1];
break;
case 'kde': // KDE Addressbook via GroupDAV
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
default:

View File

@ -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;
}
}

View File

@ -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'");

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}