iOS iCal sends now pricipal-property-search reports to autocomplete participants, but not (yet) displays the result, for whatever reason ...

This commit is contained in:
Ralf Becker 2011-09-25 12:00:20 +00:00
parent b4b04844fe
commit 14dde4c1ff
3 changed files with 184 additions and 28 deletions

View File

@ -44,4 +44,4 @@ $headertime = microtime(true);
$groupdav = new groupdav(); $groupdav = new groupdav();
$groupdav->ServeRequest(); $groupdav->ServeRequest();
//error_log(sprintf("GroupDAV %s request took %5.3f s (header include took %5.3f s)",$_SERVER['REQUEST_METHOD'],microtime(true)-$starttime,$headertime-$starttime)); error_log(sprintf('GroupDAV %s request: status "%s", took %5.3f s'.($headertime?' (header include took %5.3f s)':''),$_SERVER['REQUEST_METHOD'].($_SERVER['REQUEST_METHOD']=='REPORT'?' '.$groupdav->propfind_options['root']['name']:'').' '.$_SERVER['PATH_INFO'],$groupdav->_http_status,microtime(true)-$starttime,$headertime-$starttime));

View File

@ -277,32 +277,40 @@ class groupdav extends HTTP_WebDAV_Server
*/ */
function OPTIONS($path, &$dav, &$allow) function OPTIONS($path, &$dav, &$allow)
{ {
list(,$app) = explode('/',$path); if (preg_match('#/(calendar|inbox|outbox)/#', $path))
switch($app)
{ {
case 'calendar': $app = 'calendar';
if (!in_array(2,$dav)) $dav[] = 2;
$dav[] = 'access-control';
$dav[] = 'calendar-access';
$dav[] = 'calendar-auto-schedule';
$dav[] = 'calendar-proxy';
//$dav[] = 'calendar-availibility';
//$dav[] = 'calendarserver-private-events';
break;
case 'addressbook':
if (!in_array(2,$dav)) $dav[] = 2;
//$dav[] = 3; // revision aka versioning support not implemented
$dav[] = 'access-control';
$dav[] = 'addressbook'; // CardDAV uses "addressbook" NOT "addressbook-access"
break;
default: // used eg. for root, and needs all above settings, as some clients only use these!
if (!in_array(2,$dav)) $dav[] = 2;
$dav[] = 'access-control';
$dav[] = 'calendar-access';
$dav[] = 'calendar-auto-schedule';
$dav[] = 'calendar-proxy';
$dav[] = 'addressbook';
} }
elseif (strpos($path, '/addressbook/') !== false)
{
$app = 'addressbook';
}
// CalDAV and CardDAV
if (!in_array(2,$dav)) $dav[] = 2;
$dav[] = 'access-control';
if ($app !== 'addressbook') // CalDAV
{
$dav[] = 'calendar-access';
$dav[] = 'calendar-auto-schedule';
$dav[] = 'calendar-proxy';
// required by iOS iCal to use principal-property-search to autocomplete participants (and locations)
$dav[] = 'calendarserver-principal-property-search';
// other capabilities calendarserver announces
//$dav[] = 'calendar-schedule';
//$dav[] = 'calendar-availability';
//$dav[] = 'inbox-availability';
//$dav[] = 'calendarserver-private-events';
//$dav[] = 'calendarserver-private-comments';
//$dav[] = 'calendarserver-sharing';
//$dav[] = 'calendarserver-sharing-no-scheduling';
}
elseif ($app !== 'calendar') // CardDAV
{
$dav[] = 'addressbook'; // CardDAV uses "addressbook" NOT "addressbook-access"
}
//error_log(__METHOD__."('$path') --> app='$app' --> DAV: ".implode(', ', $dav));
} }
/** /**
@ -502,7 +510,7 @@ class groupdav extends HTTP_WebDAV_Server
$ret = false; $ret = false;
foreach($this->propfind_options['props'] as $prop) foreach($this->propfind_options['props'] as $prop)
{ {
if ($prop['name'] == $name && (is_null($ns) || $prop['ns'] == $ns)) if ($prop['name'] == $name && (is_null($ns) || $prop['xmlns'] == $ns))
{ {
$ret = true; $ret = true;
break; break;
@ -858,6 +866,11 @@ class groupdav extends HTTP_WebDAV_Server
} }
echo "</table>\n"; echo "</table>\n";
$dav = array(1);
$allow = false;
$this->OPTIONS($options['path'], $dav, $allow);
echo "<p>DAV: ".implode(', ', $dav)."</p>\n";
echo "</body>\n</html>\n"; echo "</body>\n</html>\n";
common::egw_exit(); common::egw_exit();

View File

@ -49,6 +49,9 @@ class groupdav_principals extends groupdav_handler
'principal-property-search' => array( 'principal-property-search' => array(
'method' => 'principal_property_search_report', 'method' => 'principal_property_search_report',
), ),
'principal-search-property-set' => array(
'method' => 'principal_search_property_set_report',
),
/*'expand-property' => array( /*'expand-property' => array(
// an other report calendarserver announces // an other report calendarserver announces
),*/ ),*/
@ -189,6 +192,43 @@ class groupdav_principals extends groupdav_handler
* but interprets returning all principals (all have a matching calendar-home-set) as NOT supporting CalDAV scheduling * but interprets returning all principals (all have a matching calendar-home-set) as NOT supporting CalDAV scheduling
* --> search only current user's principal, when Lightning searches for calendar-home-set * --> search only current user's principal, when Lightning searches for calendar-home-set
* *
* Example from iOS iCal autocompleting invitees using calendarserver-principal-property-search WebDAV extension
* <x0:principal-property-search xmlns:x2="urn:ietf:params:xml:ns:caldav" xmlns:x1="http://calendarserver.org/ns/" xmlns:x0="DAV:" test="anyof">
* <x0:property-search>
* <x0:prop>
* <x0:displayname/>
* </x0:prop>
* <x0:match match-type="contains">beck</x0:match>
* </x0:property-search>
* <x0:property-search>
* <x0:prop>
* <x1:email-address-set/>
* </x0:prop>
* <x0:match match-type="starts-with">beck</x0:match>
* </x0:property-search>
* <x0:property-search>
* <x0:prop>
* <x1:first-name/>
* </x0:prop>
* <x0:match match-type="starts-with">beck</x0:match>
* </x0:property-search>
* <x0:property-search>
* <x0:prop>
* <x1:last-name/>
* </x0:prop>
* <x0:match match-type="starts-with">beck</x0:match>
* </x0:property-search>
* <x0:prop>
* <x1:first-name/>
* <x1:last-name/>
* <x0:displayname/>
* <x1:email-address-set/>
* <x2:calendar-user-address-set/>
* <x1:record-type/>
* <x0:principal-URL/>
* </x0:prop>
* </x0:principal-property-search>
*
* @param string $path * @param string $path
* @param array $options * @param array $options
* @param array &$files * @param array &$files
@ -223,7 +263,7 @@ class groupdav_principals extends groupdav_handler
if (isset($property_search) && is_array($search_props[$property_search])) if (isset($property_search) && is_array($search_props[$property_search]))
{ {
$search_props[$property_search]['match'] = $prop['data']; $search_props[$property_search]['match'] = $prop['data'];
// optional match-type: "contains" (default), "starts-with" // optional match-type: "contains" (default), "starts-with", "ends-with", "equals"
$search_props[$property_search]['match-type'] = $prop['attrs']['match-type']; $search_props[$property_search]['match-type'] = $prop['attrs']['match-type'];
} }
break; break;
@ -314,7 +354,7 @@ class groupdav_principals extends groupdav_handler
* *
* @param string $value value to test * @param string $value value to test
* @param string $match criteria/sub-string * @param string $match criteria/sub-string
* @param string $match_type='contains' or 'starts-with' * @param string $match_type='contains' 'starts-with', 'ends-with' or 'equals'
*/ */
private static function match($value, $match, $match_type='contains') private static function match($value, $match, $match_type='contains')
{ {
@ -335,6 +375,109 @@ class groupdav_principals extends groupdav_handler
} }
} }
/**
* Handle principal-search-property-set report
*
* REPORT /principals/ HTTP/1.1
* <?xml version="1.0" encoding="utf-8" ?>
* <x0:principal-search-property-set xmlns:x0="DAV:"/>
*
* <?xml version='1.0' encoding='UTF-8'?>
* <principal-search-property-set xmlns='DAV:'>
* <principal-search-property>
* <prop>
* <displayname/>
* </prop>
* <description xml:lang='en'>Display Name</description>
* </principal-search-property>
* <principal-search-property>
* <prop>
* <email-address-set xmlns='http://calendarserver.org/ns/'/>
* </prop>
* <description xml:lang='en'>Email Addresses</description>
* </principal-search-property>
* <principal-search-property>
* <prop>
* <last-name xmlns='http://calendarserver.org/ns/'/>
* </prop>
* <description xml:lang='en'>Last Name</description>
* </principal-search-property>
* <principal-search-property>
* <prop>
* <calendar-user-type xmlns='urn:ietf:params:xml:ns:caldav'/>
* </prop>
* <description xml:lang='en'>Calendar User Type</description>
* </principal-search-property>
* <principal-search-property>
* <prop>
* <first-name xmlns='http://calendarserver.org/ns/'/>
* </prop>
* <description xml:lang='en'>First Name</description>
* </principal-search-property>
* <principal-search-property>
* <prop>
* <calendar-user-address-set xmlns='urn:ietf:params:xml:ns:caldav'/>
* </prop>
* <description xml:lang='en'>Calendar User Address Set</description>
* </principal-search-property>
* </principal-search-property-set>
*
* @param string $path
* @param array $options
* @param array &$files
* @param int $user account_id
* @return mixed boolean true on success, false on failure or string with http status (eg. '404 Not Found')
*/
function principal_search_property_set_report($path,&$options,&$files,$user)
{
static $search_props = array(
// from iOS iCal
'displayname' => 'Display Name',
'email-address-set' => array('description' => 'Email Addresses', 'ns' => groupdav::CALENDARSERVER),
'last-name' => array('description' => 'Last Name', 'ns' => groupdav::CALENDARSERVER),
'calendar-user-type' => array('description' => 'Calendar User Type', 'ns' => groupdav::CALENDARSERVER),
'first-name' => array('description' => 'First Name', 'ns' => groupdav::CALENDARSERVER),
'calendar-user-address-set' => array('description' => 'Calendar User Address Set', 'ns' => groupdav::CALENDARSERVER),
// Lightning
'calendar-home-set' => array('description' => 'Calendar Home Set', 'ns' => groupdav::CALENDARSERVER),
// others, we generally support all properties of the principal
);
header('Content-type: text/xml; charset=UTF-8');
$xml = new XMLWriter;
$xml->openMemory();
$xml->setIndent(true);
$xml->startDocument('1.0', 'UTF-8');
$xml->startElementNs(null, 'principal-search-property-set', 'DAV:');
foreach($search_props as $name => $data)
{
$xml->startElement('principal-search-property');
$xml->startElement('prop');
if (is_array($data) && !empty($data['ns']))
{
$xml->writeElementNs(null, $name, $data['ns']);
}
else
{
$xml->writeElement($name);
}
$xml->endElement(); // prop
$xml->startElement('description');
$xml->writeAttribute('xml:lang', 'en');
$xml->text(is_array($data) ? $data['description'] : $data);
$xml->endElement(); // description
$xml->endElement(); // principal-search-property
}
$xml->endElement(); // principal-search-property-set
$xml->endDocument();
echo $xml->outputMemory();
common::egw_exit();
}
/** /**
* Do propfind in /pricipals/users * Do propfind in /pricipals/users
* *