ILIAS  release_5-4 Revision v5.4.26-12-gabc799a52e6
Plugin.php
Go to the documentation of this file.
1 <?php
2 
3 namespace Sabre\CardDAV;
4 
5 use Sabre\DAV;
8 use Sabre\DAVACL;
9 use Sabre\HTTP;
12 use Sabre\VObject;
13 
23 class Plugin extends DAV\ServerPlugin {
24 
28  const ADDRESSBOOK_ROOT = 'addressbooks';
29 
33  const NS_CARDDAV = 'urn:ietf:params:xml:ns:carddav';
34 
41  public $directories = [];
42 
48  protected $server;
49 
55  protected $maxResourceSize = 10000000;
56 
63  function initialize(DAV\Server $server) {
64 
65  /* Events */
66  $server->on('propFind', [$this, 'propFindEarly']);
67  $server->on('propFind', [$this, 'propFindLate'], 150);
68  $server->on('report', [$this, 'report']);
69  $server->on('onHTMLActionsPanel', [$this, 'htmlActionsPanel']);
70  $server->on('beforeWriteContent', [$this, 'beforeWriteContent']);
71  $server->on('beforeCreateFile', [$this, 'beforeCreateFile']);
72  $server->on('afterMethod:GET', [$this, 'httpAfterGet']);
73 
74  $server->xml->namespaceMap[self::NS_CARDDAV] = 'card';
75 
76  $server->xml->elementMap['{' . self::NS_CARDDAV . '}addressbook-query'] = 'Sabre\\CardDAV\\Xml\\Request\\AddressBookQueryReport';
77  $server->xml->elementMap['{' . self::NS_CARDDAV . '}addressbook-multiget'] = 'Sabre\\CardDAV\\Xml\\Request\\AddressBookMultiGetReport';
78 
79  /* Mapping Interfaces to {DAV:}resourcetype values */
80  $server->resourceTypeMapping['Sabre\\CardDAV\\IAddressBook'] = '{' . self::NS_CARDDAV . '}addressbook';
81  $server->resourceTypeMapping['Sabre\\CardDAV\\IDirectory'] = '{' . self::NS_CARDDAV . '}directory';
82 
83  /* Adding properties that may never be changed */
84  $server->protectedProperties[] = '{' . self::NS_CARDDAV . '}supported-address-data';
85  $server->protectedProperties[] = '{' . self::NS_CARDDAV . '}max-resource-size';
86  $server->protectedProperties[] = '{' . self::NS_CARDDAV . '}addressbook-home-set';
87  $server->protectedProperties[] = '{' . self::NS_CARDDAV . '}supported-collation-set';
88 
89  $server->xml->elementMap['{http://calendarserver.org/ns/}me-card'] = 'Sabre\\DAV\\Xml\\Property\\Href';
90 
91  $this->server = $server;
92 
93  }
94 
102  function getFeatures() {
103 
104  return ['addressbook'];
105 
106  }
107 
118  function getSupportedReportSet($uri) {
119 
120  $node = $this->server->tree->getNodeForPath($uri);
121  if ($node instanceof IAddressBook || $node instanceof ICard) {
122  return [
123  '{' . self::NS_CARDDAV . '}addressbook-multiget',
124  '{' . self::NS_CARDDAV . '}addressbook-query',
125  ];
126  }
127  return [];
128 
129  }
130 
131 
139  function propFindEarly(DAV\PropFind $propFind, DAV\INode $node) {
140 
141  $ns = '{' . self::NS_CARDDAV . '}';
142 
143  if ($node instanceof IAddressBook) {
144 
145  $propFind->handle($ns . 'max-resource-size', $this->maxResourceSize);
146  $propFind->handle($ns . 'supported-address-data', function() {
148  });
149  $propFind->handle($ns . 'supported-collation-set', function() {
151  });
152 
153  }
154  if ($node instanceof DAVACL\IPrincipal) {
155 
156  $path = $propFind->getPath();
157 
158  $propFind->handle('{' . self::NS_CARDDAV . '}addressbook-home-set', function() use ($path) {
159  return new LocalHref($this->getAddressBookHomeForPrincipal($path) . '/');
160  });
161 
162  if ($this->directories) $propFind->handle('{' . self::NS_CARDDAV . '}directory-gateway', function() {
163  return new LocalHref($this->directories);
164  });
165 
166  }
167 
168  if ($node instanceof ICard) {
169 
170  // The address-data property is not supposed to be a 'real'
171  // property, but in large chunks of the spec it does act as such.
172  // Therefore we simply expose it as a property.
173  $propFind->handle('{' . self::NS_CARDDAV . '}address-data', function() use ($node) {
174  $val = $node->get();
175  if (is_resource($val))
176  $val = stream_get_contents($val);
177 
178  return $val;
179 
180  });
181 
182  }
183 
184  }
185 
194  function report($reportName, $dom, $path) {
195 
196  switch ($reportName) {
197  case '{' . self::NS_CARDDAV . '}addressbook-multiget' :
198  $this->server->transactionType = 'report-addressbook-multiget';
199  $this->addressbookMultiGetReport($dom);
200  return false;
201  case '{' . self::NS_CARDDAV . '}addressbook-query' :
202  $this->server->transactionType = 'report-addressbook-query';
203  $this->addressBookQueryReport($dom);
204  return false;
205  default :
206  return;
207 
208  }
209 
210 
211  }
212 
219  protected function getAddressbookHomeForPrincipal($principal) {
220 
221  list(, $principalId) = \Sabre\HTTP\URLUtil::splitPath($principal);
222  return self::ADDRESSBOOK_ROOT . '/' . $principalId;
223 
224  }
225 
226 
236  function addressbookMultiGetReport($report) {
237 
238  $contentType = $report->contentType;
239  $version = $report->version;
240  if ($version) {
241  $contentType .= '; version=' . $version;
242  }
243 
244  $vcardType = $this->negotiateVCard(
246  );
247 
248  $propertyList = [];
249  $paths = array_map(
250  [$this->server, 'calculateUri'],
251  $report->hrefs
252  );
253  foreach ($this->server->getPropertiesForMultiplePaths($paths, $report->properties) as $props) {
254 
255  if (isset($props['200']['{' . self::NS_CARDDAV . '}address-data'])) {
256 
257  $props['200']['{' . self::NS_CARDDAV . '}address-data'] = $this->convertVCard(
258  $props[200]['{' . self::NS_CARDDAV . '}address-data'],
259  $vcardType
260  );
261 
262  }
263  $propertyList[] = $props;
264 
265  }
266 
267  $prefer = $this->server->getHTTPPrefer();
268 
269  $this->server->httpResponse->setStatus(207);
270  $this->server->httpResponse->setHeader('Content-Type', 'application/xml; charset=utf-8');
271  $this->server->httpResponse->setHeader('Vary', 'Brief,Prefer');
272  $this->server->httpResponse->setBody($this->server->generateMultiStatus($propertyList, $prefer['return'] === 'minimal'));
273 
274  }
275 
289  function beforeWriteContent($path, DAV\IFile $node, &$data, &$modified) {
290 
291  if (!$node instanceof ICard)
292  return;
293 
294  $this->validateVCard($data, $modified);
295 
296  }
297 
311  function beforeCreateFile($path, &$data, DAV\ICollection $parentNode, &$modified) {
312 
313  if (!$parentNode instanceof IAddressBook)
314  return;
315 
316  $this->validateVCard($data, $modified);
317 
318  }
319 
330  protected function validateVCard(&$data, &$modified) {
331 
332  // If it's a stream, we convert it to a string first.
333  if (is_resource($data)) {
334  $data = stream_get_contents($data);
335  }
336 
337  $before = $data;
338 
339  try {
340 
341  // If the data starts with a [, we can reasonably assume we're dealing
342  // with a jCal object.
343  if (substr($data, 0, 1) === '[') {
345 
346  // Converting $data back to iCalendar, as that's what we
347  // technically support everywhere.
348  $data = $vobj->serialize();
349  $modified = true;
350  } else {
352  }
353 
354  } catch (VObject\ParseException $e) {
355 
356  throw new DAV\Exception\UnsupportedMediaType('This resource only supports valid vCard or jCard data. Parse error: ' . $e->getMessage());
357 
358  }
359 
360  if ($vobj->name !== 'VCARD') {
361  throw new DAV\Exception\UnsupportedMediaType('This collection can only support vcard objects.');
362  }
363 
365  $prefer = $this->server->getHTTPPrefer();
366 
367  if ($prefer['handling'] !== 'strict') {
369  }
370 
371  $messages = $vobj->validate($options);
372 
373  $highestLevel = 0;
374  $warningMessage = null;
375 
376  // $messages contains a list of problems with the vcard, along with
377  // their severity.
378  foreach ($messages as $message) {
379 
380  if ($message['level'] > $highestLevel) {
381  // Recording the highest reported error level.
382  $highestLevel = $message['level'];
383  $warningMessage = $message['message'];
384  }
385 
386  switch ($message['level']) {
387 
388  case 1 :
389  // Level 1 means that there was a problem, but it was repaired.
390  $modified = true;
391  break;
392  case 2 :
393  // Level 2 means a warning, but not critical
394  break;
395  case 3 :
396  // Level 3 means a critical error
397  throw new DAV\Exception\UnsupportedMediaType('Validation error in vCard: ' . $message['message']);
398 
399  }
400 
401  }
402  if ($warningMessage) {
403  $this->server->httpResponse->setHeader(
404  'X-Sabre-Ew-Gross',
405  'vCard validation warning: ' . $warningMessage
406  );
407 
408  // Re-serializing object.
409  $data = $vobj->serialize();
410  if (!$modified && strcmp($data, $before) !== 0) {
411  // This ensures that the system does not send an ETag back.
412  $modified = true;
413  }
414  }
415 
416  // Destroy circular references to PHP will GC the object.
417  $vobj->destroy();
418  }
419 
420 
430  protected function addressbookQueryReport($report) {
431 
432  $depth = $this->server->getHTTPDepth(0);
433 
434  if ($depth == 0) {
435  $candidateNodes = [
436  $this->server->tree->getNodeForPath($this->server->getRequestUri())
437  ];
438  if (!$candidateNodes[0] instanceof ICard) {
439  throw new ReportNotSupported('The addressbook-query report is not supported on this url with Depth: 0');
440  }
441  } else {
442  $candidateNodes = $this->server->tree->getChildren($this->server->getRequestUri());
443  }
444 
445  $contentType = $report->contentType;
446  if ($report->version) {
447  $contentType .= '; version=' . $report->version;
448  }
449 
450  $vcardType = $this->negotiateVCard(
452  );
453 
454  $validNodes = [];
455  foreach ($candidateNodes as $node) {
456 
457  if (!$node instanceof ICard)
458  continue;
459 
460  $blob = $node->get();
461  if (is_resource($blob)) {
462  $blob = stream_get_contents($blob);
463  }
464 
465  if (!$this->validateFilters($blob, $report->filters, $report->test)) {
466  continue;
467  }
468 
469  $validNodes[] = $node;
470 
471  if ($report->limit && $report->limit <= count($validNodes)) {
472  // We hit the maximum number of items, we can stop now.
473  break;
474  }
475 
476  }
477 
478  $result = [];
479  foreach ($validNodes as $validNode) {
480 
481  if ($depth == 0) {
482  $href = $this->server->getRequestUri();
483  } else {
484  $href = $this->server->getRequestUri() . '/' . $validNode->getName();
485  }
486 
487  list($props) = $this->server->getPropertiesForPath($href, $report->properties, 0);
488 
489  if (isset($props[200]['{' . self::NS_CARDDAV . '}address-data'])) {
490 
491  $props[200]['{' . self::NS_CARDDAV . '}address-data'] = $this->convertVCard(
492  $props[200]['{' . self::NS_CARDDAV . '}address-data'],
493  $vcardType,
494  $report->addressDataProperties
495  );
496 
497  }
498  $result[] = $props;
499 
500  }
501 
502  $prefer = $this->server->getHTTPPrefer();
503 
504  $this->server->httpResponse->setStatus(207);
505  $this->server->httpResponse->setHeader('Content-Type', 'application/xml; charset=utf-8');
506  $this->server->httpResponse->setHeader('Vary', 'Brief,Prefer');
507  $this->server->httpResponse->setBody($this->server->generateMultiStatus($result, $prefer['return'] === 'minimal'));
508 
509  }
510 
519  function validateFilters($vcardData, array $filters, $test) {
520 
521 
522  if (!$filters) return true;
523  $vcard = VObject\Reader::read($vcardData);
524 
525  foreach ($filters as $filter) {
526 
527  $isDefined = isset($vcard->{$filter['name']});
528  if ($filter['is-not-defined']) {
529  if ($isDefined) {
530  $success = false;
531  } else {
532  $success = true;
533  }
534  } elseif ((!$filter['param-filters'] && !$filter['text-matches']) || !$isDefined) {
535 
536  // We only need to check for existence
537  $success = $isDefined;
538 
539  } else {
540 
541  $vProperties = $vcard->select($filter['name']);
542 
543  $results = [];
544  if ($filter['param-filters']) {
545  $results[] = $this->validateParamFilters($vProperties, $filter['param-filters'], $filter['test']);
546  }
547  if ($filter['text-matches']) {
548  $texts = [];
549  foreach ($vProperties as $vProperty)
550  $texts[] = $vProperty->getValue();
551 
552  $results[] = $this->validateTextMatches($texts, $filter['text-matches'], $filter['test']);
553  }
554 
555  if (count($results) === 1) {
556  $success = $results[0];
557  } else {
558  if ($filter['test'] === 'anyof') {
559  $success = $results[0] || $results[1];
560  } else {
561  $success = $results[0] && $results[1];
562  }
563  }
564 
565  } // else
566 
567  // There are two conditions where we can already determine whether
568  // or not this filter succeeds.
569  if ($test === 'anyof' && $success) {
570 
571  // Destroy circular references to PHP will GC the object.
572  $vcard->destroy();
573 
574  return true;
575  }
576  if ($test === 'allof' && !$success) {
577 
578  // Destroy circular references to PHP will GC the object.
579  $vcard->destroy();
580 
581  return false;
582  }
583 
584  } // foreach
585 
586 
587  // Destroy circular references to PHP will GC the object.
588  $vcard->destroy();
589 
590  // If we got all the way here, it means we haven't been able to
591  // determine early if the test failed or not.
592  //
593  // This implies for 'anyof' that the test failed, and for 'allof' that
594  // we succeeded. Sounds weird, but makes sense.
595  return $test === 'allof';
596 
597  }
598 
610  protected function validateParamFilters(array $vProperties, array $filters, $test) {
611 
612  foreach ($filters as $filter) {
613 
614  $isDefined = false;
615  foreach ($vProperties as $vProperty) {
616  $isDefined = isset($vProperty[$filter['name']]);
617  if ($isDefined) break;
618  }
619 
620  if ($filter['is-not-defined']) {
621  if ($isDefined) {
622  $success = false;
623  } else {
624  $success = true;
625  }
626 
627  // If there's no text-match, we can just check for existence
628  } elseif (!$filter['text-match'] || !$isDefined) {
629 
630  $success = $isDefined;
631 
632  } else {
633 
634  $success = false;
635  foreach ($vProperties as $vProperty) {
636  // If we got all the way here, we'll need to validate the
637  // text-match filter.
638  $success = DAV\StringUtil::textMatch($vProperty[$filter['name']]->getValue(), $filter['text-match']['value'], $filter['text-match']['collation'], $filter['text-match']['match-type']);
639  if ($success) break;
640  }
641  if ($filter['text-match']['negate-condition']) {
642  $success = !$success;
643  }
644 
645  } // else
646 
647  // There are two conditions where we can already determine whether
648  // or not this filter succeeds.
649  if ($test === 'anyof' && $success) {
650  return true;
651  }
652  if ($test === 'allof' && !$success) {
653  return false;
654  }
655 
656  }
657 
658  // If we got all the way here, it means we haven't been able to
659  // determine early if the test failed or not.
660  //
661  // This implies for 'anyof' that the test failed, and for 'allof' that
662  // we succeeded. Sounds weird, but makes sense.
663  return $test === 'allof';
664 
665  }
666 
675  protected function validateTextMatches(array $texts, array $filters, $test) {
676 
677  foreach ($filters as $filter) {
678 
679  $success = false;
680  foreach ($texts as $haystack) {
681  $success = DAV\StringUtil::textMatch($haystack, $filter['value'], $filter['collation'], $filter['match-type']);
682 
683  // Breaking on the first match
684  if ($success) break;
685  }
686  if ($filter['negate-condition']) {
687  $success = !$success;
688  }
689 
690  if ($success && $test === 'anyof')
691  return true;
692 
693  if (!$success && $test == 'allof')
694  return false;
695 
696 
697  }
698 
699  // If we got all the way here, it means we haven't been able to
700  // determine early if the test failed or not.
701  //
702  // This implies for 'anyof' that the test failed, and for 'allof' that
703  // we succeeded. Sounds weird, but makes sense.
704  return $test === 'allof';
705 
706  }
707 
718  function propFindLate(DAV\PropFind $propFind, DAV\INode $node) {
719 
720  // If the request was made using the SOGO connector, we must rewrite
721  // the content-type property. By default SabreDAV will send back
722  // text/x-vcard; charset=utf-8, but for SOGO we must strip that last
723  // part.
724  if (strpos($this->server->httpRequest->getHeader('User-Agent'), 'Thunderbird') === false) {
725  return;
726  }
727  $contentType = $propFind->get('{DAV:}getcontenttype');
728  list($part) = explode(';', $contentType);
729  if ($part === 'text/x-vcard' || $part === 'text/vcard') {
730  $propFind->set('{DAV:}getcontenttype', 'text/x-vcard');
731  }
732 
733  }
734 
744  function htmlActionsPanel(DAV\INode $node, &$output) {
745 
746  if (!$node instanceof AddressBookHome)
747  return;
748 
749  $output .= '<tr><td colspan="2"><form method="post" action="">
750  <h3>Create new address book</h3>
751  <input type="hidden" name="sabreAction" value="mkcol" />
752  <input type="hidden" name="resourceType" value="{DAV:}collection,{' . self::NS_CARDDAV . '}addressbook" />
753  <label>Name (uri):</label> <input type="text" name="name" /><br />
754  <label>Display name:</label> <input type="text" name="{DAV:}displayname" /><br />
755  <input type="submit" value="create" />
756  </form>
757  </td></tr>';
758 
759  return false;
760 
761  }
762 
773 
774  if (strpos($response->getHeader('Content-Type'), 'text/vcard') === false) {
775  return;
776  }
777 
778  $target = $this->negotiateVCard($request->getHeader('Accept'), $mimeType);
779 
780  $newBody = $this->convertVCard(
781  $response->getBody(),
782  $target
783  );
784 
785  $response->setBody($newBody);
786  $response->setHeader('Content-Type', $mimeType . '; charset=utf-8');
787  $response->setHeader('Content-Length', strlen($newBody));
788 
789  }
790 
805  protected function negotiateVCard($input, &$mimeType = null) {
806 
808  $input,
809  [
810  // Most often used mime-type. Version 3
811  'text/x-vcard',
812  // The correct standard mime-type. Defaults to version 3 as
813  // well.
814  'text/vcard',
815  // vCard 4
816  'text/vcard; version=4.0',
817  // vCard 3
818  'text/vcard; version=3.0',
819  // jCard
820  'application/vcard+json',
821  ]
822  );
823 
824  $mimeType = $result;
825  switch ($result) {
826 
827  default :
828  case 'text/x-vcard' :
829  case 'text/vcard' :
830  case 'text/vcard; version=3.0' :
831  $mimeType = 'text/vcard';
832  return 'vcard3';
833  case 'text/vcard; version=4.0' :
834  return 'vcard4';
835  case 'application/vcard+json' :
836  return 'jcard';
837 
838  // @codeCoverageIgnoreStart
839  }
840  // @codeCoverageIgnoreEnd
841 
842  }
843 
852  protected function convertVCard($data, $target, array $propertiesFilter = null) {
853 
854  if (is_resource($data)) {
855  $data = stream_get_contents($data);
856  }
858  if (!empty($propertiesFilter)) {
859  $propertiesFilter = array_merge(['UID', 'VERSION', 'FN'], $propertiesFilter);
860  $keys = array_unique(array_map(function($child) {
861  return $child->name;
862  }, $input->children()));
863  $keys = array_diff($keys, $propertiesFilter);
864  foreach ($keys as $key) {
865  unset($input->$key);
866  }
867  $data = $input->serialize();
868  }
869  $output = null;
870  try {
871 
872  switch ($target) {
873  default :
874  case 'vcard3' :
875  if ($input->getDocumentType() === VObject\Document::VCARD30) {
876  // Do nothing
877  return $data;
878  }
879  $output = $input->convert(VObject\Document::VCARD30);
880  return $output->serialize();
881  case 'vcard4' :
882  if ($input->getDocumentType() === VObject\Document::VCARD40) {
883  // Do nothing
884  return $data;
885  }
886  $output = $input->convert(VObject\Document::VCARD40);
887  return $output->serialize();
888  case 'jcard' :
889  $output = $input->convert(VObject\Document::VCARD40);
890  return json_encode($output);
891 
892  }
893 
894  } finally {
895 
896  // Destroy circular references to PHP will GC the object.
897  $input->destroy();
898  if (!is_null($output)) {
899  $output->destroy();
900  }
901  }
902 
903  }
904 
913  function getPluginName() {
914 
915  return 'carddav';
916 
917  }
918 
930  function getPluginInfo() {
931 
932  return [
933  'name' => $this->getPluginName(),
934  'description' => 'Adds support for CardDAV (rfc6352)',
935  'link' => 'http://sabre.io/dav/carddav/',
936  ];
937 
938  }
939 
940 }
validateParamFilters(array $vProperties, array $filters, $test)
Validates if a param-filter can be applied to a specific property.
Definition: Plugin.php:610
This interface represents a HTTP response.
The RequestInterface represents a HTTP request.
$path
Definition: aliased.php:25
validateTextMatches(array $texts, array $filters, $test)
Validates if a text-filter can be applied to a specific property.
Definition: Plugin.php:675
The baseclass for all server plugins.
setBody($body)
Updates the body resource with a new stream.
$result
beforeCreateFile($path, &$data, DAV\ICollection $parentNode, &$modified)
This method is triggered before a new file is created.
Definition: Plugin.php:311
if($argc< 2) $paths
Definition: migrateto20.php:44
foreach($paths as $path) $request
Definition: asyncclient.php:32
static negotiate($acceptHeaderValue, array $availableOptions)
Deprecated! Use negotiateContentType.
Definition: Util.php:38
LocalHref property.
Definition: LocalHref.php:25
AddressBook Home class.
const NS_CARDDAV
xml namespace for CardDAV elements
Definition: Plugin.php:33
negotiateVCard($input, &$mimeType=null)
This helper function performs the content-type negotiation for vcards.
Definition: Plugin.php:805
getPluginName()
Returns a plugin name.
Definition: Plugin.php:913
httpAfterGet(RequestInterface $request, ResponseInterface $response)
This event is triggered after GET requests.
Definition: Plugin.php:772
This class holds all the information about a PROPFIND request.
Definition: PropFind.php:11
CardDAV plugin.
Definition: Plugin.php:23
getPluginInfo()
Returns a bunch of meta-data about the plugin.
Definition: Plugin.php:930
propFindLate(DAV\PropFind $propFind, DAV\INode $node)
This event is triggered when fetching properties.
Definition: Plugin.php:718
propFindEarly(DAV\PropFind $propFind, DAV\INode $node)
Adds all CardDAV-specific properties.
Definition: Plugin.php:139
AddressBook interface.
$keys
Card interface.
Definition: ICard.php:17
The ICollection Interface.
Definition: ICollection.php:14
getSupportedReportSet($uri)
Returns a list of reports this plugin supports.
Definition: Plugin.php:118
$version
Definition: build.php:27
getAddressbookHomeForPrincipal($principal)
Returns the addressbook home for a given principal.
Definition: Plugin.php:219
$messages
Definition: en.php:5
initialize(DAV\Server $server)
Initializes the plugin.
Definition: Plugin.php:63
catch(Exception $e) $message
addressbookMultiGetReport($report)
This function handles the addressbook-multiget REPORT.
Definition: Plugin.php:236
$success
Definition: Utf8Test.php:86
static textMatch($haystack, $needle, $collation, $matchType='contains')
Checks if a needle occurs in a haystack ;)
Definition: StringUtil.php:27
beforeWriteContent($path, DAV\IFile $node, &$data, &$modified)
This method is triggered before a file gets updated with new content.
Definition: Plugin.php:289
$maxResourceSize
The default PDO storage uses a MySQL MEDIUMBLOB for iCalendar data, which can hold up to 2^24 = 16777...
Definition: Plugin.php:55
validateFilters($vcardData, array $filters, $test)
Validates if a vcard makes it throught a list of filters.
Definition: Plugin.php:519
const VCARD30
vCard 3.0.
Definition: Document.php:44
Main DAV server class.
Definition: Server.php:23
getHeader($name)
Returns a specific HTTP header, based on it&#39;s name.
This interface represents a file in the directory tree.
Definition: IFile.php:16
The INode interface is the base interface, and the parent class of both ICollection and IFile...
Definition: INode.php:12
$vobj
Definition: rrulebench.php:21
const ADDRESSBOOK_ROOT
Url to the addressbooks.
Definition: Plugin.php:28
static readJson($data, $options=0)
Parses a jCard or jCal object, and returns the top component.
Definition: Reader.php:67
const REPAIR
The following constants are used by the validate() method.
Definition: Node.php:27
IPrincipal interface.
Definition: IPrincipal.php:16
static read($data, $options=0, $charset='UTF-8')
Parses a vCard or iCalendar object, and returns the top component.
Definition: Reader.php:42
$results
Definition: svg-scanner.php:47
validateVCard(&$data, &$modified)
Checks if the submitted iCalendar data is in fact, valid.
Definition: Plugin.php:330
Exception thrown by Reader if an invalid object was attempted to be parsed.
const VCARD40
vCard 4.0.
Definition: Document.php:49
if($path[strlen($path) - 1]==='/') if(is_dir($path)) if(!file_exists($path)) if(preg_match('#\.php$#D', mb_strtolower($path, 'UTF-8'))) $contentType
Definition: module.php:144
convertVCard($data, $target, array $propertiesFilter=null)
Converts a vcard blob to a different version, or jcard.
Definition: Plugin.php:852
getFeatures()
Returns a list of supported features.
Definition: Plugin.php:102
report($reportName, $dom, $path)
This functions handles REPORT requests specific to CardDAV.
Definition: Plugin.php:194
$response
$target
Definition: test.php:19
$key
Definition: croninfo.php:18
static splitPath($path)
Returns the &#39;dirname&#39; and &#39;basename&#39; for a path.
Definition: URLUtil.php:83
setHeader($name, $value)
Updates a HTTP header.
const PROFILE_CARDDAV
If this option is set, the validator will operate on the vcards on the assumption that the vcards nee...
Definition: Node.php:36
getBody()
Returns the message body, as it&#39;s internal representation.
htmlActionsPanel(DAV\INode $node, &$output)
This method is used to generate HTML output for the Sabre.
Definition: Plugin.php:744
$test
Definition: Utf8Test.php:84
addressbookQueryReport($report)
This function handles the addressbook-query REPORT.
Definition: Plugin.php:430
$data
Definition: bench.php:6