示例#1
0
 /**
  * Constructor
  *
  * The splitter should receive an readable file stream as it's input.
  *
  * @param resource $input
  * @param int $options Parser options, see the OPTIONS constants.
  */
 public function __construct($input, $options = 0)
 {
     $data = VObject\Reader::read($input, $options);
     $vtimezones = array();
     $components = array();
     foreach ($data->children() as $component) {
         if (!$component instanceof VObject\Component) {
             continue;
         }
         // Get all timezones
         if ($component->name === 'VTIMEZONE') {
             $this->vtimezones[(string) $component->TZID] = $component;
             continue;
         }
         // Get component UID for recurring Events search
         if ($component->UID) {
             $uid = (string) $component->UID;
         } else {
             // Generating a random UID
             $uid = sha1(microtime()) . '-vobjectimport';
         }
         // Take care of recurring events
         if (!array_key_exists($uid, $this->objects)) {
             $this->objects[$uid] = new VCalendar();
         }
         $this->objects[$uid]->add(clone $component);
     }
 }
 /**
  * Merges all vcard objects, and builds one big vcf export
  *
  * @param array $nodes
  * @return string
  */
 public function generateVCF(array $nodes)
 {
     $output = "";
     foreach ($nodes as $node) {
         if (!isset($node[200]['{' . Plugin::NS_CARDDAV . '}address-data'])) {
             continue;
         }
         $nodeData = $node[200]['{' . Plugin::NS_CARDDAV . '}address-data'];
         // Parsing this node so VObject can clean up the output.
         $output .= VObject\Reader::read($nodeData)->serialize();
     }
     return $output;
 }
示例#3
0
 /**
  * Parses some information from calendar objects, used for optimized
  * calendar-queries.
  *
  * Returns an array with the following keys:
  *   * etag
  *   * size
  *   * componentType
  *   * firstOccurence
  *   * lastOccurence
  *
  * @param string $calendarData
  * @return array
  */
 protected function getDenormalizedData($calendarData)
 {
     $vObject = VObject\Reader::read($calendarData);
     $componentType = null;
     $component = null;
     $firstOccurence = null;
     $lastOccurence = null;
     foreach ($vObject->getComponents() as $component) {
         if ($component->name !== 'VTIMEZONE') {
             $componentType = $component->name;
             break;
         }
     }
     if (!$componentType) {
         throw new \SabreForRainLoop\DAV\Exception\BadRequest('Calendar objects must have a VJOURNAL, VEVENT or VTODO component');
     }
     if ($componentType === 'VEVENT') {
         $firstOccurence = $component->DTSTART->getDateTime()->getTimeStamp();
         // Finding the last occurence is a bit harder
         if (!isset($component->RRULE)) {
             if (isset($component->DTEND)) {
                 $lastOccurence = $component->DTEND->getDateTime()->getTimeStamp();
             } elseif (isset($component->DURATION)) {
                 $endDate = clone $component->DTSTART->getDateTime();
                 $endDate->add(VObject\DateTimeParser::parse($component->DURATION->getValue()));
                 $lastOccurence = $endDate->getTimeStamp();
             } elseif (!$component->DTSTART->hasTime()) {
                 $endDate = clone $component->DTSTART->getDateTime();
                 $endDate->modify('+1 day');
                 $lastOccurence = $endDate->getTimeStamp();
             } else {
                 $lastOccurence = $firstOccurence;
             }
         } else {
             $it = new VObject\RecurrenceIterator($vObject, (string) $component->UID);
             $maxDate = new \DateTime(self::MAX_DATE);
             if ($it->isInfinite()) {
                 $lastOccurence = $maxDate->getTimeStamp();
             } else {
                 $end = $it->getDtEnd();
                 while ($it->valid() && $end < $maxDate) {
                     $end = $it->getDtEnd();
                     $it->next();
                 }
                 $lastOccurence = $end->getTimeStamp();
             }
         }
     }
     return array('etag' => md5($calendarData), 'size' => strlen($calendarData), 'componentType' => $componentType, 'firstOccurence' => $firstOccurence, 'lastOccurence' => $lastOccurence);
 }
示例#4
0
 /**
  * This method handles POST requests to the schedule-outbox.
  *
  * Currently, two types of requests are support:
  *   * FREEBUSY requests from RFC 6638
  *   * Simple iTIP messages from draft-desruisseaux-caldav-sched-04
  *
  * The latter is from an expired early draft of the CalDAV scheduling
  * extensions, but iCal depends on a feature from that spec, so we
  * implement it.
  *
  * @param Schedule\IOutbox $outboxNode
  * @param string $outboxUri
  * @return void
  */
 public function outboxRequest(Schedule\IOutbox $outboxNode, $outboxUri)
 {
     // Parsing the request body
     try {
         $vObject = VObject\Reader::read($this->server->httpRequest->getBody(true));
     } catch (VObject\ParseException $e) {
         throw new DAV\Exception\BadRequest('The request body must be a valid iCalendar object. Parse error: ' . $e->getMessage());
     }
     // The incoming iCalendar object must have a METHOD property, and a
     // component. The combination of both determines what type of request
     // this is.
     $componentType = null;
     foreach ($vObject->getComponents() as $component) {
         if ($component->name !== 'VTIMEZONE') {
             $componentType = $component->name;
             break;
         }
     }
     if (is_null($componentType)) {
         throw new DAV\Exception\BadRequest('We expected at least one VTODO, VJOURNAL, VFREEBUSY or VEVENT component');
     }
     // Validating the METHOD
     $method = strtoupper((string) $vObject->METHOD);
     if (!$method) {
         throw new DAV\Exception\BadRequest('A METHOD property must be specified in iTIP messages');
     }
     // So we support two types of requests:
     //
     // REQUEST with a VFREEBUSY component
     // REQUEST, REPLY, ADD, CANCEL on VEVENT components
     $acl = $this->server->getPlugin('acl');
     if ($componentType === 'VFREEBUSY' && $method === 'REQUEST') {
         $acl && $acl->checkPrivileges($outboxUri, '{' . Plugin::NS_CALDAV . '}schedule-query-freebusy');
         $this->handleFreeBusyRequest($outboxNode, $vObject);
     } elseif ($componentType === 'VEVENT' && in_array($method, array('REQUEST', 'REPLY', 'ADD', 'CANCEL'))) {
         $acl && $acl->checkPrivileges($outboxUri, '{' . Plugin::NS_CALDAV . '}schedule-post-vevent');
         $this->handleEventNotification($outboxNode, $vObject);
     } else {
         throw new DAV\Exception\NotImplemented('SabreDAV supports only VFREEBUSY (REQUEST) and VEVENT (REQUEST, REPLY, ADD, CANCEL)');
     }
 }
 /**
  * Sets the input objects
  *
  * You must either specify a valendar object as a strong, or as the parse
  * Component.
  * It's also possible to specify multiple objects as an array.
  *
  * @param mixed $objects
  * @return void
  */
 public function setObjects($objects)
 {
     if (!is_array($objects)) {
         $objects = array($objects);
     }
     $this->objects = array();
     foreach ($objects as $object) {
         if (is_string($object)) {
             $this->objects[] = Reader::read($object);
         } elseif ($object instanceof Component) {
             $this->objects[] = $object;
         } else {
             throw new \InvalidArgumentException('You can only pass strings or \\SabreForRainLoop\\VObject\\Component arguments to setObjects');
         }
     }
 }
 /**
  * This method validates if a filters (as passed to calendarQuery) matches
  * the given object.
  *
  * @param array $object
  * @param array $filters
  * @return bool
  */
 protected function validateFilterForObject(array $object, array $filters)
 {
     // Unfortunately, setting the 'calendardata' here is optional. If
     // it was excluded, we actually need another call to get this as
     // well.
     if (!isset($object['calendardata'])) {
         $object = $this->getCalendarObject($object['calendarid'], $object['uri']);
     }
     $data = is_resource($object['calendardata']) ? stream_get_contents($object['calendardata']) : $object['calendardata'];
     $vObject = VObject\Reader::read($data);
     $validator = new CalDAV\CalendarQueryValidator();
     return $validator->validate($vObject, $filters);
 }
示例#7
0
 /**
  * Validates if a vcard makes it throught a list of filters.
  *
  * @param string $vcardData
  * @param array $filters
  * @param string $test anyof or allof (which means OR or AND)
  * @return bool
  */
 public function validateFilters($vcardData, array $filters, $test)
 {
     $vcard = VObject\Reader::read($vcardData);
     if (!$filters) {
         return true;
     }
     foreach ($filters as $filter) {
         $isDefined = isset($vcard->{$filter['name']});
         if ($filter['is-not-defined']) {
             if ($isDefined) {
                 $success = false;
             } else {
                 $success = true;
             }
         } elseif (!$filter['param-filters'] && !$filter['text-matches'] || !$isDefined) {
             // We only need to check for existence
             $success = $isDefined;
         } else {
             $vProperties = $vcard->select($filter['name']);
             $results = array();
             if ($filter['param-filters']) {
                 $results[] = $this->validateParamFilters($vProperties, $filter['param-filters'], $filter['test']);
             }
             if ($filter['text-matches']) {
                 $texts = array();
                 foreach ($vProperties as $vProperty) {
                     $texts[] = $vProperty->getValue();
                 }
                 $results[] = $this->validateTextMatches($texts, $filter['text-matches'], $filter['test']);
             }
             if (count($results) === 1) {
                 $success = $results[0];
             } else {
                 if ($filter['test'] === 'anyof') {
                     $success = $results[0] || $results[1];
                 } else {
                     $success = $results[0] && $results[1];
                 }
             }
         }
         // else
         // There are two conditions where we can already determine whether
         // or not this filter succeeds.
         if ($test === 'anyof' && $success) {
             return true;
         }
         if ($test === 'allof' && !$success) {
             return false;
         }
     }
     // foreach
     // If we got all the way here, it means we haven't been able to
     // determine early if the test failed or not.
     //
     // This implies for 'anyof' that the test failed, and for 'allof' that
     // we succeeded. Sounds weird, but makes sense.
     return $test === 'allof';
 }
示例#8
0
 public function PopulateByVCard($sUid, $sVCard, $sEtag = '', $oLogger = null)
 {
     if ("" === \substr($sVCard, 0, 3)) {
         $sVCard = \substr($sVCard, 3);
     }
     $this->Properties = array();
     if (!\class_exists('SabreForRainLoop\\DAV\\Client')) {
         return false;
     }
     if (!empty($sEtag)) {
         $this->Etag = $sEtag;
     }
     $this->IdContactStr = $sUid;
     try {
         $oVCard = \SabreForRainLoop\VObject\Reader::read($sVCard);
     } catch (\Exception $oExc) {
         if ($oLogger) {
             $oLogger->WriteException($oExc);
             $oLogger->WriteDump($sVCard);
         }
     }
     //		if ($oLogger)
     //		{
     //			$oLogger->WriteDump($sVCard);
     //		}
     $bOwnCloud = false;
     $aProperties = array();
     if ($oVCard) {
         $bOwnCloud = empty($oVCard->PRODID) ? false : false !== \strpos(\strtolower($oVCard->PRODID), 'owncloud');
         $bOldVersion = empty($oVCard->VERSION) ? false : \in_array((string) $oVCard->VERSION, array('2.1', '2.0', '1.0'));
         if (isset($oVCard->FN) && '' !== \trim($oVCard->FN)) {
             $sValue = $this->getPropertyValueHelper($oVCard->FN, $bOldVersion);
             $aProperties[] = new Property(PropertyType::FULLNAME, $sValue);
         }
         if (isset($oVCard->NICKNAME) && '' !== \trim($oVCard->NICKNAME)) {
             $sValue = $sValue = $this->getPropertyValueHelper($oVCard->NICKNAME, $bOldVersion);
             $aProperties[] = new Property(PropertyType::NICK_NAME, $sValue);
         }
         if (isset($oVCard->NOTE) && '' !== \trim($oVCard->NOTE)) {
             $sValue = $this->getPropertyValueHelper($oVCard->NOTE, $bOldVersion);
             $aProperties[] = new Property(PropertyType::NOTE, $sValue);
         }
         if (isset($oVCard->N)) {
             $aNames = $oVCard->N->getParts();
             foreach ($aNames as $iIndex => $sValue) {
                 $sValue = \trim($sValue);
                 if ($bOldVersion && !isset($oVCard->N->parameters['CHARSET'])) {
                     if (0 < \strlen($sValue)) {
                         $sEncValue = @\utf8_encode($sValue);
                         if (0 === \strlen($sEncValue)) {
                             $sEncValue = $sValue;
                         }
                         $sValue = $sEncValue;
                     }
                 }
                 $sValue = \MailSo\Base\Utils::Utf8Clear($sValue);
                 switch ($iIndex) {
                     case 0:
                         $aProperties[] = new Property(PropertyType::LAST_NAME, $sValue);
                         break;
                     case 1:
                         $aProperties[] = new Property(PropertyType::FIRST_NAME, $sValue);
                         break;
                     case 2:
                         $aProperties[] = new Property(PropertyType::MIDDLE_NAME, $sValue);
                         break;
                     case 3:
                         $aProperties[] = new Property(PropertyType::NAME_PREFIX, $sValue);
                         break;
                     case 4:
                         $aProperties[] = new Property(PropertyType::NAME_SUFFIX, $sValue);
                         break;
                 }
             }
         }
         if (isset($oVCard->EMAIL)) {
             $this->addArrayPropertyHelper($aProperties, $oVCard->EMAIL, PropertyType::EMAIl);
         }
         if (isset($oVCard->URL)) {
             $this->addArrayPropertyHelper($aProperties, $oVCard->URL, PropertyType::WEB_PAGE);
         }
         if (isset($oVCard->TEL)) {
             $this->addArrayPropertyHelper($aProperties, $oVCard->TEL, PropertyType::PHONE);
         }
         $sUidValue = $oVCard->UID ? (string) $oVCard->UID : \SabreForRainLoop\DAV\UUIDUtil::getUUID();
         $aProperties[] = new Property(PropertyType::UID, $sUidValue);
         if (empty($this->IdContactStr)) {
             $this->IdContactStr = $sUidValue;
         }
         $this->Properties = $aProperties;
     }
     $this->UpdateDependentValues();
     return true;
 }
 /**
  * Merges all calendar objects, and builds one big ics export
  *
  * @param array $nodes
  * @return string
  */
 public function generateICS(array $nodes)
 {
     $calendar = new VObject\Component\VCalendar();
     $calendar->version = '2.0';
     if (DAV\Server::$exposeVersion) {
         $calendar->prodid = '-//SabreDAV//SabreDAV ' . DAV\Version::VERSION . '//EN';
     } else {
         $calendar->prodid = '-//SabreDAV//SabreDAV//EN';
     }
     $calendar->calscale = 'GREGORIAN';
     $collectedTimezones = array();
     $timezones = array();
     $objects = array();
     foreach ($nodes as $node) {
         if (!isset($node[200]['{' . Plugin::NS_CALDAV . '}calendar-data'])) {
             continue;
         }
         $nodeData = $node[200]['{' . Plugin::NS_CALDAV . '}calendar-data'];
         $nodeComp = VObject\Reader::read($nodeData);
         foreach ($nodeComp->children() as $child) {
             switch ($child->name) {
                 case 'VEVENT':
                 case 'VTODO':
                 case 'VJOURNAL':
                     $objects[] = $child;
                     break;
                     // VTIMEZONE is special, because we need to filter out the duplicates
                 // VTIMEZONE is special, because we need to filter out the duplicates
                 case 'VTIMEZONE':
                     // Naively just checking tzid.
                     if (in_array((string) $child->TZID, $collectedTimezones)) {
                         continue;
                     }
                     $timezones[] = $child;
                     $collectedTimezones[] = $child->TZID;
                     break;
             }
         }
     }
     foreach ($timezones as $tz) {
         $calendar->add($tz);
     }
     foreach ($objects as $obj) {
         $calendar->add($obj);
     }
     return $calendar->serialize();
 }