mirror of
https://github.com/EGroupware/egroupware.git
synced 2024-12-28 01:28:53 +01:00
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:
parent
71edd1c938
commit
43f860ba8f
@ -291,10 +291,8 @@ class addressbook_groupdav extends groupdav_handler
|
|||||||
private function _get_handler()
|
private function _get_handler()
|
||||||
{
|
{
|
||||||
$handler =& new addressbook_vcal();
|
$handler =& new addressbook_vcal();
|
||||||
if (strpos($_SERVER['HTTP_USER_AGENT'],'KHTML') !== false)
|
$handler->setSupportedFields('GroupDAV',$this->agent);
|
||||||
{
|
|
||||||
$handler->setSupportedFields('KDE');
|
|
||||||
}
|
|
||||||
return $handler;
|
return $handler;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -128,11 +128,11 @@ class addressbook_vcal extends addressbook_bo
|
|||||||
{
|
{
|
||||||
$value = $GLOBALS['egw']->translation->convert(trim($value), $sysCharSet,$_charset);
|
$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;
|
$options['CHARSET'] = $_charset;
|
||||||
// KAddressbook requires non-ascii chars to be qprint encoded, other clients eg. nokia phones have trouble with that
|
// 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';
|
$options['ENCODING'] = 'QUOTED-PRINTABLE';
|
||||||
}
|
}
|
||||||
@ -251,7 +251,7 @@ class addressbook_vcal extends addressbook_bo
|
|||||||
'TITLE' => array('title'),
|
'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;WORK' => array('','','adr_one_street','adr_one_locality','adr_one_region',
|
||||||
'adr_one_postalcode','adr_one_countryname'),
|
'adr_one_postalcode','adr_one_countryname'),
|
||||||
'ADR;HOME' => array('','','adr_two_street','adr_two_locality','adr_two_region',
|
'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];
|
$this->supportedFields = $defaultFields[1];
|
||||||
break;
|
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];
|
$this->supportedFields = $defaultFields[8];
|
||||||
break;
|
break;
|
||||||
|
default:
|
||||||
|
$this->supportedFields = $defaultFields[1];
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
// the fallback for SyncML
|
// the fallback for SyncML
|
||||||
default:
|
default:
|
||||||
|
@ -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']));
|
//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(
|
$props = array(
|
||||||
HTTP_WebDAV_Server::mkprop('getetag',$this->get_etag($event)),
|
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'),
|
'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
|
// getlastmodified and getcontentlength are required by WebDAV and Cadaver eg. reports 404 Not found if not set
|
||||||
HTTP_WebDAV_Server::mkprop('getlastmodified', $event['modified']),
|
HTTP_WebDAV_Server::mkprop('getlastmodified', $event['modified']),
|
||||||
);
|
);
|
||||||
if ($calendar_data)
|
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('getcontentlength',bytes($content));
|
||||||
$props[] = HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'calendar-data',$content);
|
$props[] = HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'calendar-data',$content);
|
||||||
}
|
}
|
||||||
@ -247,7 +248,8 @@ class calendar_groupdav extends groupdav_handler
|
|||||||
{
|
{
|
||||||
return $event;
|
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';
|
$options['mimetype'] = 'text/calendar; charset=utf-8';
|
||||||
header('Content-Encoding: identity');
|
header('Content-Encoding: identity');
|
||||||
header('ETag: '.$this->get_etag($event));
|
header('ETag: '.$this->get_etag($event));
|
||||||
@ -270,7 +272,8 @@ class calendar_groupdav extends groupdav_handler
|
|||||||
{
|
{
|
||||||
return $event;
|
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))))
|
self::etag2value($this->http_if_match))))
|
||||||
{
|
{
|
||||||
if ($this->debug) error_log(__METHOD__."(,$id) importVCal($options[content]) returned false");
|
if ($this->debug) error_log(__METHOD__."(,$id) importVCal($options[content]) returned false");
|
||||||
@ -373,4 +376,17 @@ class calendar_groupdav extends groupdav_handler
|
|||||||
|
|
||||||
return $props;
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
@ -107,12 +107,9 @@ class calendar_ical extends calendar_boupdate
|
|||||||
* @param int/array $events (array of) cal_id or array of the events
|
* @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 $version='1.0' could be '2.0' too
|
||||||
* @param string $method='PUBLISH'
|
* @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
|
* @return string/boolean string with iCal or false on error (eg. no permission to read the event)
|
||||||
* 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)
|
|
||||||
*/
|
*/
|
||||||
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(
|
$egwSupportedFields = array(
|
||||||
'CLASS' => array('dbName' => 'public'),
|
'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'];
|
$attributes['UID'] = $event['uid'];
|
||||||
foreach($attributes as $key => $value)
|
foreach($attributes as $key => $value)
|
||||||
{
|
{
|
||||||
@ -459,7 +455,7 @@ class calendar_ical extends calendar_boupdate
|
|||||||
{
|
{
|
||||||
$options['ENCODING'] = 'QUOTED-PRINTABLE';
|
$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';
|
$options['CHARSET'] = 'UTF-8';
|
||||||
}
|
}
|
||||||
@ -1221,6 +1217,14 @@ class calendar_ical extends calendar_boupdate
|
|||||||
$this->supportedFields = $defaultFields['full'];
|
$this->supportedFields = $defaultFields['full'];
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'groupdav': // all GroupDAV access goes through here
|
||||||
|
switch($this->productName)
|
||||||
|
{
|
||||||
|
default:
|
||||||
|
$this->supportedFields = $defaultFields['full'];
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
// the fallback for SyncML
|
// the fallback for SyncML
|
||||||
default:
|
default:
|
||||||
error_log("Unknown calendar SyncML client: manufacturer='$_productManufacturer' product='$_productName'");
|
error_log("Unknown calendar SyncML client: manufacturer='$_productManufacturer' product='$_productName'");
|
||||||
|
@ -69,7 +69,7 @@ class infolog_groupdav extends groupdav_handler
|
|||||||
'path' => '/infolog/'.$task['info_id'].'.ics',
|
'path' => '/infolog/'.$task['info_id'].'.ics',
|
||||||
'props' => array(
|
'props' => array(
|
||||||
HTTP_WebDAV_Server::mkprop('getetag',$this->get_etag($task)),
|
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
|
'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
|
// 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']),
|
HTTP_WebDAV_Server::mkprop('getlastmodified', $task['info_datemodified']),
|
||||||
@ -94,7 +94,7 @@ class infolog_groupdav extends groupdav_handler
|
|||||||
{
|
{
|
||||||
return $task;
|
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['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';
|
$options['mimetype'] = 'text/calendar; charset=utf-8';
|
||||||
header('Content-Encoding: identity');
|
header('Content-Encoding: identity');
|
||||||
@ -117,7 +117,7 @@ class infolog_groupdav extends groupdav_handler
|
|||||||
{
|
{
|
||||||
return $ok;
|
return $ok;
|
||||||
}
|
}
|
||||||
$handler = new infolog_ical();
|
$handler = $this->_get_handler();
|
||||||
if (!($info_id = $handler->importVTODO($options['content'],is_numeric($id) ? $id : -1)))
|
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");
|
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'].'"';
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
@ -31,17 +31,23 @@ class infolog_ical extends infolog_bo
|
|||||||
3 => 0,
|
3 => 0,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* manufacturer and name of the sync-client
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
var $productManufacturer = 'file';
|
||||||
|
var $productName = '';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Exports one InfoLog tast to an iCalendar VTODO
|
* Exports one InfoLog tast to an iCalendar VTODO
|
||||||
*
|
*
|
||||||
* @param int $_taskID info_id
|
* @param int $_taskID info_id
|
||||||
* @param string $version='2.0' could be '1.0' too
|
* @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
|
* @param string $_method='PUBLISH'
|
||||||
* 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 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);
|
$taskData = $this->read($_taskID);
|
||||||
|
|
||||||
@ -51,7 +57,7 @@ class infolog_ical extends infolog_bo
|
|||||||
|
|
||||||
$vcal = &new Horde_iCalendar;
|
$vcal = &new Horde_iCalendar;
|
||||||
$vcal->setAttribute('VERSION',$_version);
|
$vcal->setAttribute('VERSION',$_version);
|
||||||
$vcal->setAttribute('METHOD','PUBLISH');
|
$vcal->setAttribute('METHOD',$_method);
|
||||||
|
|
||||||
$vevent = Horde_iCalendar::newComponent('VTODO',$vcal);
|
$vevent = Horde_iCalendar::newComponent('VTODO',$vcal);
|
||||||
|
|
||||||
@ -68,7 +74,7 @@ class infolog_ical extends infolog_bo
|
|||||||
{
|
{
|
||||||
$options['ENCODING'] = 'QUOTED-PRINTABLE';
|
$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';
|
$options['CHARSET'] = 'UTF-8';
|
||||||
}
|
}
|
||||||
@ -83,7 +89,6 @@ class infolog_ical extends infolog_bo
|
|||||||
$vevent->setAttribute('DTSTAMP',time());
|
$vevent->setAttribute('DTSTAMP',time());
|
||||||
$vevent->setAttribute('CREATED',$GLOBALS['egw']->contenthistory->getTSforAction('infolog_task',$_taskID,'add'));
|
$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('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('UID',$taskData['info_uid']);
|
||||||
$vevent->setAttribute('CLASS',$taskData['info_access'] == 'public' ? 'PUBLIC' : 'PRIVATE');
|
$vevent->setAttribute('CLASS',$taskData['info_access'] == 'public' ? 'PUBLIC' : 'PRIVATE');
|
||||||
$vevent->setAttribute('STATUS',$this->status2vtodo($taskData['info_status']));
|
$vevent->setAttribute('STATUS',$this->status2vtodo($taskData['info_status']));
|
||||||
@ -375,5 +380,20 @@ class infolog_ical extends infolog_bo
|
|||||||
}
|
}
|
||||||
return FALSE;
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,6 +65,12 @@ abstract class groupdav_handler
|
|||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
var $http_if_match;
|
var $http_if_match;
|
||||||
|
/**
|
||||||
|
* Identified user agent
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
var $agent;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
@ -78,6 +84,7 @@ abstract class groupdav_handler
|
|||||||
$this->app = $app;
|
$this->app = $app;
|
||||||
if (!is_null($debug)) $this->debug = $debug;
|
if (!is_null($debug)) $this->debug = $debug;
|
||||||
$this->base_uri = is_null($base_uri) ? $base_uri : $_SERVER['SCRIPT_NAME'];
|
$this->base_uri = is_null($base_uri) ? $base_uri : $_SERVER['SCRIPT_NAME'];
|
||||||
|
$this->agent = self::get_agent();
|
||||||
|
|
||||||
$this->translation =& $GLOBALS['egw']->translation;
|
$this->translation =& $GLOBALS['egw']->translation;
|
||||||
$this->egw_charset = $this->translation->charset();
|
$this->egw_charset = $this->translation->charset();
|
||||||
@ -259,4 +266,41 @@ abstract class groupdav_handler
|
|||||||
}
|
}
|
||||||
return $handler_cache[$app];
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user