public function testEmptyData() { $ical = new Horde_Icalendar(); $ical->parsevCalendar(file_get_contents(__DIR__ . '/fixtures/empty.ics')); $this->assertEquals(array(), $ical->getComponents()); $ical->parsevCalendar(''); $this->assertEquals(array(), $ical->getComponents()); }
/** * Variables required in form input: * - imple_submit: vcard action. Contains import and source properties * - mime_id * - muid * * @return boolean True on success. */ protected function _handle(Horde_Variables $vars) { global $registry, $injector, $notification; $iCal = new Horde_Icalendar(); try { $contents = $injector->getInstance('IMP_Factory_Contents')->create(new IMP_Indices_Mailbox($vars)); if (!($mime_part = $contents->getMimePart($vars->mime_id))) { throw new IMP_Exception(_("Cannot retrieve vCard data from message.")); } elseif (!$iCal->parsevCalendar($mime_part->getContents(), 'VCALENDAR', $mime_part->getCharset())) { throw new IMP_Exception(_("Error reading the contact data.")); } $components = $iCal->getComponents(); } catch (Exception $e) { $notification->push($e, 'horde.error'); } $import = !empty($vars->imple_submit->import) ? $vars->imple_submit->import : false; $source = !empty($vars->imple_submit->source) ? $vars->imple_submit->source : false; if ($import && $source && $registry->hasMethod('contacts/import')) { $count = 0; foreach ($components as $c) { if ($c->getType() == 'vcard') { try { $registry->call('contacts/import', array($c, null, $source)); ++$count; } catch (Horde_Exception $e) { $notification->push(Horde_Core_Translation::t("There was an error importing the contact data:") . ' ' . $e->getMessage(), 'horde.error'); } } } $notification->push(sprintf(Horde_Core_Translation::ngettext("%d contact was successfully added to your address book.", "%d contacts were successfully added to your address book.", $count), $count), 'horde.success'); } }
private function _getFixture($element) { $iCal = new Horde_Icalendar(); $iCal->parsevCalendar(file_get_contents(__DIR__ . '/../fixtures/allday.ics')); $components = $iCal->getComponents(); return $components[$element]; }
/** * Process the iCalendar data. * * @return array A hash of UID => id. * @throws Kronolith_Exception */ protected function _process() { $ids = array(); $components = $this->_iCal->getComponents(); if (count($components) == 0) { throw new Kronolith_Exception(_("No iCalendar data was found.")); } foreach ($components as $component) { if (!$this->_preSave($component)) { continue; } try { // RECURRENCE-ID - must import after base event is // imported/saved so defer these until all other data is // processed. $component->getAttribute('RECURRENCE-ID'); $this->_exceptions[] = $component; } catch (Horde_Icalendar_Exception $e) { $event = $this->_driver->getEvent(); $event->fromiCalendar($component, true); // Delete existing exception events. There is no efficient way // to determine if any existing events have been changed/deleted // so we just remove them all since they will be re-added during // the import process. foreach ($event->boundExceptions() as $exception) { $this->_driver->deleteEvent($exception->id); } // Save and post-process. $event->save(); $this->_postSave($event); $ids[$event->uid] = $event->id; } } // Save exception events. foreach ($this->_exceptions as $exception) { $event = $this->_driver->getEvent(); $event->fromiCalendar($exception); $event->save(); } return $ids; }
/** * @dataProvider timezones */ public function testFile($file) { $result = ''; $ical = new Horde_Icalendar(); $ical->parsevCalendar(file_get_contents($file)); foreach ($ical->getComponents() as $component) { if ($component->getType() != 'vEvent') { continue; } $date = $component->getAttribute('DTSTART'); if (is_array($date)) { continue; } $result .= str_replace("\r", '', $component->getAttribute('SUMMARY')) . "\n"; $d = new Horde_Date($date); $result .= $d->format('H:i') . "\n"; } $this->assertStringEqualsFile(__DIR__ . '/fixtures/vTimezone/' . basename($file, 'ics') . 'txt', $result, 'Failed parsing file ' . basename($file)); }
/** * Return the full rendered version of the Horde_Mime_Part object. * * URL parameters used by this function: * - c: (integer) The VCARD component that contains an image. * - p: (integer) The index of image inside the component to display. * * @return array See parent::render(). * @throws Horde_Exception */ protected function _renderInline() { $vars = $GLOBALS['injector']->getInstance('Horde_Variables'); if (!isset($vars->p)) { $imp_contents = $this->getConfigParam('imp_contents'); $GLOBALS['injector']->getInstance('Horde_Core_Factory_Imple')->create('IMP_Ajax_Imple_VcardImport', array('mime_id' => $this->_mimepart->getMimeId(), 'muid' => strval($imp_contents->getIndicesOb()))); $this->_imageUrl = $this->getConfigParam('imp_contents')->urlView($this->_mimepart, 'download_render', array('params' => array('mode' => IMP_Contents::RENDER_INLINE))); return parent::_renderInline(); } /* Send the requested photo. */ $data = $this->_mimepart->getContents(); $ical = new Horde_Icalendar(); if (!$ical->parsevCalendar($data, 'VCALENDAR', $this->_mimepart->getCharset())) { // TODO: Error reporting return array(); } $components = $ical->getComponents(); if (!isset($components[$vars->c])) { // TODO: Error reporting return array(); } $name = $components[$vars->c]->getAttributeDefault('FN', false); if ($name === false) { $name = $components[$vars->c]->printableName(); } if (empty($name)) { $name = preg_replace('/\\..*?$/', '', $this->_mimepart->getName()); } $photos = $components[$vars->c]->getAllAttributes('PHOTO'); if (!isset($photos[$vars->p])) { // TODO: Error reporting return array(); } $type = 'image/' . Horde_String::lower($photos[$vars->p]['params']['TYPE']); return array($this->_mimepart->getMimeId() => array('data' => base64_decode($photos[$vars->p]['value']), 'name' => $name . '.' . Horde_Mime_Magic::mimeToExt($type), 'type' => $type)); }
/** * Return the rendered inline version of the Horde_Mime_Part object. * * @return array See parent::render(). */ protected function _renderInline() { $GLOBALS['page_output']->growler = true; $data = $this->_mimepart->getContents(); $mime_id = $this->_mimepart->getMimeId(); // Parse the iCal file. $vCal = new Horde_Icalendar(); if (!$vCal->parsevCalendar($data, 'VCALENDAR', $this->_mimepart->getCharset())) { $status = new IMP_Mime_Status($this->_mimepart, _("The calendar data is invalid")); $status->action(IMP_Mime_Status::ERROR); return array($mime_id => array('data' => '', 'status' => $status, 'type' => 'text/html; charset=UTF-8')); } // Check if we got vcard data with the wrong vcalendar mime type. $imp_contents = $this->getConfigParam('imp_contents'); $c = $vCal->getComponentClasses(); if (count($c) == 1 && !empty($c['horde_icalendar_vcard'])) { return $imp_contents->renderMIMEPart($mime_id, IMP_Contents::RENDER_INLINE, array('type' => 'text/x-vcard')); } $imple = $GLOBALS['injector']->getInstance('Horde_Core_Factory_Imple')->create('IMP_Ajax_Imple_ItipRequest', array('mime_id' => $mime_id, 'muid' => strval($imp_contents->getIndicesOb()))); // Get the method type. try { $method = $vCal->getAttribute('METHOD'); } catch (Horde_Icalendar_Exception $e) { $method = ''; } $out = array(); $exceptions = array(); $components = $vCal->getComponents(); foreach ($components as $key => $component) { switch ($component->getType()) { case 'vEvent': try { if ($component->getAttribute('RECURRENCE-ID')) { $exceptions[] = $this->_vEvent($component, $key, $method, $components); } } catch (Horde_ICalendar_Exception $e) { $out[] = $this->_vEvent($component, $key, $method, $components); } break; case 'vTodo': $out[] = $this->_vTodo($component, $key, $method); break; case 'vTimeZone': // Ignore them. break; case 'vFreebusy': $out[] = $this->_vFreebusy($component, $key, $method); break; // @todo: handle stray vcards here as well. // @todo: handle stray vcards here as well. default: $out[] = sprintf(_("Unhandled component of type: %s"), $component->getType()); break; } } // If we don't have any other parts, any exceptions should be shown // since this is likely an update to a series instance such as a // cancellation etc... if (empty($out)) { $out = $exceptions; } $view = $this->_getViewOb(); $view->formid = $imple->getDomId(); $view->out = implode('', $out); return array($mime_id => array('data' => $view->render('base'), 'type' => 'text/html; charset=UTF-8')); }
private function _getFixture($name, $item = 0) { $iCal = new Horde_Icalendar(); $iCal->parsevCalendar(file_get_contents(__DIR__ . '/../fixtures/' . $name)); $components = $iCal->getComponents(); $event = new Kronolith_Event_Sql(new Kronolith_Stub_Driver()); $event->fromiCalendar($components[$item], true); return $event; }
/** * Return the attendee participation status. * * @param Horde_Icalendar $vCal The vCalendar component. * * @param Horde_Icalendar * @throws Horde_ActiveSync_Exception */ protected function _getiTipStatus($vCal) { foreach ($vCal->getComponents() as $component) { switch ($component->getType()) { case 'vEvent': try { $atparams = $component->getAttribute('ATTENDEE', true); } catch (Horde_Icalendar_Exception $e) { throw new Horde_ActiveSync_Exception($e); } if (!is_array($atparams)) { throw new Horde_Icalendar_Exception('Unexpected value'); } return $atparams[0]['PARTSTAT']; } } }
*/ require_once 'Horde/Cli.php'; require_once 'Horde/Icalendar.php'; // This only works on the command line. if (!Horde_Cli::runningFromCLI()) { exit("Must be run from the command line\n"); } // Load the CLI environment - make sure there's no time limit, init // some variables, etc. $cli = Horde_Cli::init(); if (empty($argv[1])) { $cli->fatal('No file specified on the command line.'); } $input_file = $argv[1]; if (!file_exists($input_file)) { $cli->fatal($input_file . ' does not exist.'); } if (!is_readable($input_file)) { $cli->fatal($input_file . ' is not readable.'); } $cli->writeln($cli->blue('Parsing ' . $input_file . ' ...')); $data = file_get_contents($input_file); $ical = new Horde_Icalendar(); if (!$ical->parseVCalendar($data)) { $cli->fatal('iCalendar parsing failed.'); } $cli->writeln($cli->green('Parsing successful, found ' . $ical->getComponentCount() . ' component(s).')); $components = $ical->getComponents(); foreach ($components as $component) { var_dump($component->toHash(true)); }
/** * Converts all components of a Horde_Icalendar container into a * Kronolith_Event list. * * @param Horde_Icalendar $ical A Horde_Icalendar container. * * @return array List of Kronolith_Event_Ical objects. * @throws Kronolith_Exception */ protected function _convertEvents($ical) { $events = array(); foreach ($ical->getComponents() as $component) { if ($component->getType() == 'vEvent') { try { $events[] = new Kronolith_Event_Ical($this, $component); } catch (Kronolith_Exception $e) { Horde::log(sprintf('Failed to parse event from remote calendar: url = "%s"', $this->calendar), 'INFO'); } } } return $events; }
/** */ public function davPutObject($collection, $object, $data) { $dav = $GLOBALS['injector']->getInstance('Horde_Dav_Storage'); $internal = $dav->getInternalCollectionId($collection, 'tasks') ?: $collection; if (!Nag::hasPermission($internal, Horde_Perms::EDIT)) { throw new Nag_Exception("Task List does not exist or no permission to edit"); } $ical = new Horde_Icalendar(); if (!$ical->parsevCalendar($data)) { throw new Nag_Exception(_("There was an error importing the iCalendar data.")); } $storage = $GLOBALS['injector']->getInstance('Nag_Factory_Driver')->create($internal); foreach ($ical->getComponents() as $content) { if (!$content instanceof Horde_Icalendar_Vtodo) { continue; } $task = new Nag_Task(); $task->fromiCalendar($content); try { try { $existing_id = $dav->getInternalObjectId($object, $internal) ?: preg_replace('/\\.ics$/', '', $object); } catch (Horde_Dav_Exception $e) { $existing_id = $object; } $existing_task = Nag::getTask($internal, $existing_id); /* Check if our task is newer then the existing - get the * task's history. */ $modified = $this->_modified($internal, $existing_task->uid); try { if (!empty($modified) && $content->getAttribute('LAST-MODIFIED') < $modified) { /* LAST-MODIFIED timestamp of existing entry is newer: * don't replace it. */ continue; } } catch (Horde_Icalendar_Exception $e) { } $task->owner = $existing_task->owner; $storage->modify($existing_task->id, $task->toHash()); } catch (Horde_Exception_NotFound $e) { $hash = $task->toHash(); $newTask = $storage->add($hash); $dav->addObjectMap($newTask[0], $object, $internal); } } }
/** * Replaces the task identified by UID with the content represented in the * specified content type. * * If you want to replace multiple tasks with the UID specified in the * VCALENDAR data, you may use $this->import instead. This automatically does a * replace if existings UIDs are found. * * * @param string $uid Identify the task to replace. * @param string $content The content of the task. * @param string $contentType What format is the data in? Currently supports: * - text/x-vcalendar * - text/calendar * * @return boolean Success or failure. */ public function replace($uid, $content, $contentType) { $factory = $GLOBALS['injector']->getInstance('Nag_Factory_Driver'); $existing = $factory->create('')->getByUID($uid); $taskId = $existing->id; $owner = $existing->owner; if (!Nag::hasPermission($existing->tasklist, Horde_Perms::EDIT)) { throw new Horde_Exception_PermissionDenied(); } switch ($contentType) { case 'text/calendar': case 'text/x-vcalendar': if (!$content instanceof Horde_Icalendar_Vtodo) { $iCal = new Horde_Icalendar(); if (!$iCal->parsevCalendar($content)) { throw new Nag_Exception(_("There was an error importing the iCalendar data.")); } $components = $iCal->getComponents(); $component = null; foreach ($components as $content) { if ($content instanceof Horde_Icalendar_Vtodo) { if ($component !== null) { throw new Nag_Exception(_("Multiple iCalendar components found; only one vTodo is supported.")); } $component = $content; } } if ($component === null) { throw new Nag_Exception(_("No iCalendar data was found.")); } } $task = new Nag_Task(); $task->fromiCalendar($content); $task->owner = $owner; $factory->create($existing->tasklist)->modify($taskId, $task->toHash()); break; case 'activesync': $task = new Nag_Task(); $task->fromASTask($content); $task->owner = $owner; $factory->create($existing->tasklist)->modify($taskId, $task->toHash()); break; default: throw new Nag_Exception(sprintf(_("Unsupported Content-Type: %s"), $contentType)); } return $result; }
/** * Import a contact represented in the specified contentType. * * @param string $content The content of the contact. * @param string $contentType What format is the data in? Currently * supports array, text/directory, text/vcard, * text/x-vcard, and activesync. * @param string $source The source into which the contact will be * imported. * * @return string The new UID. * * @throws Turba_Exception * @throws Turba_Exception_ObjectExists */ public function import($content, $contentType = 'array', $source = null) { global $cfgSources, $injector, $prefs; /* Get default address book from user preferences. */ if (empty($source) && !($source = $prefs->getValue('default_dir'))) { // On new installations default_dir is not set. Try default // addressbook if it's editable. Otherwise use first editable // addressbook. $edit_sources = Turba::getAddressBooks(Horde_Perms::EDIT); $default_source = Turba::getDefaultAddressbook(); if (isset($edit_sources[$default_source])) { // use default addressbook $source = $default_source; } else { // Use first writable source $source = reset($edit_sources); } } // Check existence of and permissions on the specified source. if (!isset($cfgSources[$source])) { throw new Turba_Exception(sprintf(_("Invalid address book: %s"), $source)); } $driver = $injector->getInstance('Turba_Factory_Driver')->create($source); if (!$driver->hasPermission(Horde_Perms::EDIT)) { throw new Turba_Exception(_("Permission denied")); } if (!$content instanceof Horde_Icalendar_Vcard) { switch ($contentType) { case 'activesync': $content = $driver->fromASContact($content); break; case 'array': if (!isset($content['emails']) && isset($content['email'])) { $content['emails'] = $content['email']; } break; case 'text/x-vcard': case 'text/vcard': case 'text/directory': $iCal = new Horde_Icalendar(); if (!$iCal->parsevCalendar($content)) { throw new Turba_Exception(_("There was an error importing the iCalendar data.")); } switch ($iCal->getComponentCount()) { case 0: throw new Turba_Exception(_("No vCard data was found.")); case 1: $content = $iCal->getComponent(0); break; default: $ids = array(); foreach ($iCal->getComponents() as $c) { if ($c instanceof Horde_Icalendar_Vcard) { $content = $driver->toHash($c); $result = $driver->search($content); if (count($result)) { continue; } $ids[] = $driver->add($content); } } return $ids; } break; default: throw new Turba_Exception(sprintf(_("Unsupported Content-Type: %s"), $contentType)); } } if ($content instanceof Horde_Icalendar_Vcard) { $content = $driver->toHash($content); } // Check if the entry already exists in the data source. $result = $driver->search($content); if (count($result)) { throw new Turba_Exception_ObjectExists(_("Already Exists")); } // We can't use $object->setValue() here since that cannot be used // with composite fields. $hooks = $injector->getInstance('Horde_Core_Hooks'); if ($hooks->hookExists('encode_attribute', 'turba')) { foreach ($content as $attribute => &$value) { try { $value = $hooks->callHook('encode_attribute', 'turba', array($attribute, $value, null, null)); } catch (Turba_Exception $e) { } } } $result = $driver->add($content); return $driver->getObject($result)->getValue('__uid'); }
/** * Processes the components of a Horde_Icalendar container into an event * list. * * @param array $results Gets filled with the events in the * given time range. * @param Horde_Icalendar $ical An Horde_Icalendar container. * @param Horde_Date $startInterval Start of range date. * @param Horde_Date $endInterval End of range date. * @param boolean $showRecurrence Return every instance of a recurring * event? If false, will only return * recurring events once inside the * $startDate - $endDate range. * @param boolean $json Store the results of the events' * toJson() method? * @param boolean $coverDates Whether to add the events to all days * that they cover. * $param boolean $hideExceptions Hide events that represent exceptions * to a recurring event. * @param string $id Enforce a certain event id (not UID). * * @throws Kronolith_Exception */ protected function _processComponents(&$results, $ical, $startDate, $endDate, $showRecurrence, $json, $coverDates, $hideExceptions, $id = null) { $components = $ical->getComponents(); $events = array(); $count = count($components); $exceptions = array(); for ($i = 0; $i < $count; $i++) { $component = $components[$i]; if ($component->getType() == 'vEvent') { $event = new Kronolith_Event_Ical($this, $component); $event->permission = $this->getPermission(); // Force string so JSON encoding is consistent across drivers. $event->id = $id ? $id : 'ical' . $i; /* Catch RECURRENCE-ID attributes which mark single recurrence * instances. */ try { $recurrence_id = $component->getAttribute('RECURRENCE-ID'); if (is_int($recurrence_id) && is_string($uid = $component->getAttribute('UID')) && is_int($seq = $component->getAttribute('SEQUENCE'))) { $exceptions[$uid][$seq] = $recurrence_id; if ($hideExceptions) { continue; } $event->id .= '/' . $recurrence_id; } } catch (Horde_Icalendar_Exception $e) { } /* Ignore events out of the period. */ $recurs = $event->recurs(); if ($endDate && $event->start->compareDateTime($endDate) > 0 || $startDate && !$recurs && $event->end->compareDateTime($startDate) < 0) { continue; } if ($recurs && $startDate) { // Fixed end date? Check if end is before start period. if ($event->recurrence->hasRecurEnd() && $event->recurrence->recurEnd->compareDateTime($startDate) < 0) { continue; } elseif ($endDate) { $next = $event->recurrence->nextRecurrence($startDate); if ($next == false || $next->compareDateTime($endDate) > 0) { continue; } } } $events[] = $event; } } /* Loop through all explicitly defined recurrence intances and create * exceptions for those in the event with the matching recurrence. */ foreach ($events as $key => $event) { if ($event->recurs() && isset($exceptions[$event->uid][$event->sequence])) { $timestamp = $exceptions[$event->uid][$event->sequence]; $events[$key]->recurrence->addException(date('Y', $timestamp), date('m', $timestamp), date('d', $timestamp)); } Kronolith::addEvents($results, $event, $startDate, $endDate, $showRecurrence, $json, $coverDates); } }
/** */ public function davPutObject($collection, $object, $data) { $dav = $GLOBALS['injector']->getInstance('Horde_Dav_Storage'); $internal = $dav->getInternalCollectionId($collection, 'contacts') ?: $collection; $driver = $GLOBALS['injector']->getInstance('Turba_Factory_Driver')->create($internal); if (!$driver->hasPermission(Horde_Perms::EDIT)) { throw new Turba_Exception("Address Book does not exist or no permission to edit"); } $ical = new Horde_Icalendar(); if (!$ical->parsevCalendar($data)) { throw new Turba_Exception(_("There was an error importing the vCard data.")); } foreach ($ical->getComponents() as $content) { if (!$content instanceof Horde_Icalendar_Vcard) { continue; } $contact = $driver->toHash($content); try { try { $existing_id = $dav->getInternalObjectId($object, $internal) ?: preg_replace('/\\.vcf$/', '', $object); } catch (Horde_Dav_Exception $e) { $existing_id = $object; } $existing_contact = $driver->getObject($existing_id); /* Check if our contact is newer then the existing - get the * contact's history. */ $modified = $existing_contact->lastModification(); try { if (!empty($modified) && $content->getAttribute('LAST-MODIFIED')->before($modified)) { /* LAST-MODIFIED timestamp of existing entry is newer: * don't replace it. */ continue; } } catch (Horde_Icalendar_Exception $e) { } foreach ($contact as $attribute => $value) { if ($attribute != '__key') { $existing_contact->setValue($attribute, $value); } } $existing_contact->store(); } catch (Horde_Exception_NotFound $e) { $id = $driver->add($contact); $dav->addObjectMap($id, $object, $internal); } } }
/** * Import a contact represented in the specified contentType. * * @param string $content The content of the contact. * @param string $contentType What format is the data in? Currently * supports array, text/directory, text/vcard, * text/x-vcard, and activesync. * @param string $source The source into which the contact will be * imported. * * @return string The new UID. * * @throws Turba_Exception * @throws Turba_Exception_ObjectExists */ public function import($content, $contentType = 'array', $source = null) { global $injector; $source = $this->_getSource($source); $driver = $injector->getInstance('Turba_Factory_Driver')->create($source); if (!$driver->hasPermission(Horde_Perms::EDIT)) { throw new Turba_Exception(_("Permission denied")); } if ($content instanceof Horde_Icalendar_Vcard) { $content = $driver->toHash($content); } else { switch ($contentType) { case 'activesync': $content = $driver->fromASContact($content); break; case 'array': if (!isset($content['emails']) && isset($content['email'])) { $content['emails'] = $content['email']; } break; case 'text/x-vcard': case 'text/vcard': case 'text/directory': $iCal = new Horde_Icalendar(); if (!$iCal->parsevCalendar($content)) { throw new Turba_Exception(_("There was an error importing the iCalendar data.")); } switch ($iCal->getComponentCount()) { case 0: throw new Turba_Exception(_("No vCard data was found.")); case 1: $content = $iCal->getComponent(0); break; default: $ids = array(); foreach ($iCal->getComponents() as $c) { if ($c instanceof Horde_Icalendar_Vcard) { $content = $driver->toHash($c); $result = $driver->search($content); if (count($result)) { continue; } $ids[] = $driver->add($content); } } return $ids; } break; default: throw new Turba_Exception(sprintf(_("Unsupported Content-Type: %s"), $contentType)); } } // Check if the entry already exists in the data source. $result = $driver->search($content); if (count($result)) { throw new Turba_Exception_ObjectExists(_("Already Exists")); } // We can't use $object->setValue() here since that cannot be used // with composite fields. return $driver->getObject($driver->add($this->_encodeContent($content)))->getValue('__uid'); }
/** */ public function davPutObject($collection, $object, $data) { $dav = $GLOBALS['injector']->getInstance('Horde_Dav_Storage'); $internal = $dav->getInternalCollectionId($collection, 'calendar') ?: $collection; if (!Kronolith::hasPermission($internal, Horde_Perms::EDIT)) { throw new Kronolith_Exception(_("Calendar does not exist or no permission to edit")); } $ical = new Horde_Icalendar(); if (!$ical->parsevCalendar($data)) { throw new Kronolith_Exception(_("There was an error importing the iCalendar data.")); } $kronolith_driver = Kronolith::getDriver(null, $internal); foreach ($ical->getComponents() as $content) { if (!$content instanceof Horde_Icalendar_Vevent) { continue; } $event = $kronolith_driver->getEvent(); $event->fromiCalendar($content, true); try { try { $existing_id = $dav->getInternalObjectId($object, $internal) ?: preg_replace('/\\.ics$/', '', $object); } catch (Horde_Dav_Exception $e) { $existing_id = $object; } $existing_event = $kronolith_driver->getEvent($existing_id); /* Check if our event is newer then the existing - get the * event's history. */ $existing_event->loadHistory(); $modified = $existing_event->modified ?: $existing_event->created; try { if (!empty($modified) && $content->getAttribute('LAST-MODIFIED') < $modified->timestamp()) { /* LAST-MODIFIED timestamp of existing entry is newer: * don't replace it. */ continue; } } catch (Horde_Icalendar_Exception $e) { } // Don't change creator/owner. $event->creator = $existing_event->creator; } catch (Horde_Exception_NotFound $e) { $existing_event = null; } // Save entry. $id = $event->save(); if (!$existing_event) { $dav->addObjectMap($id, $object, $internal); } // Send iTip messages. // Notifications will get lost, there is no way to return messages // to clients. Kronolith::sendITipNotifications($event, new Horde_Notification_Handler(new Horde_Notification_Storage_Object()), Kronolith::ITIP_REQUEST); } }
/** * Return the rendered inline version of the Horde_Mime_Part object. * * @return array See parent::render(). */ protected function _renderInline() { $browser = $this->getConfigParam('browser'); $notification = $this->getConfigParam('notification'); $prefs = $this->getConfigParam('prefs'); $registry = $this->getConfigParam('registry'); $data = $this->_mimepart->getContents(); $html = ''; $title = Horde_Core_Translation::t("vCard"); $iCal = new Horde_Icalendar(); if (!$iCal->parsevCalendar($data, 'VCALENDAR', $this->_mimepart->getCharset())) { $notification->push(Horde_Core_Translation::t("There was an error reading the contact data."), 'horde.error'); } if (Horde_Util::getFormData('import') && Horde_Util::getFormData('source') && $registry->hasMethod('contacts/import')) { $source = Horde_Util::getFormData('source'); $count = 0; foreach ($iCal->getComponents() as $c) { if ($c->getType() == 'vcard') { try { $registry->call('contacts/import', array($c, null, $source)); ++$count; } catch (Horde_Exception $e) { $notification->push(Horde_Core_Translation::t("There was an error importing the contact data:") . ' ' . $e->getMessage(), 'horde.error'); } } } $notification->push(sprintf(Horde_Core_Translation::ngettext("%d contact was successfully added to your address book.", "%d contacts were successfully added to your address book.", $count), $count), 'horde.success'); } $html .= '<table class="horde-table" style="width:100%">'; foreach ($iCal->getComponents() as $i => $vc) { if ($i > 0) { $html .= '<tr><td colspan="2"> </td></tr>'; } $addresses = $vc->getAllAttributes('EMAIL'); $html .= '<tr><td colspan="2" class="header">'; if (($fullname = $vc->getAttributeDefault('FN', false)) === false) { $fullname = count($addresses) ? $addresses[0]['value'] : Horde_Core_Translation::t("[No Label]"); } $html .= htmlspecialchars($fullname) . '</td></tr>'; $n = $vc->printableName(); if (!empty($n)) { $html .= $this->_row(Horde_Core_Translation::t("Name"), $n); } try { $html .= $this->_row(Horde_Core_Translation::t("Alias"), implode("\n", $vc->getAttributeValues('ALIAS'))); } catch (Horde_Icalendar_Exception $e) { } try { $birthdays = $vc->getAttributeValues('BDAY'); $birthday = new Horde_Date($birthdays[0]); $html .= $this->_row(Horde_Core_Translation::t("Birthday"), $birthday->strftime($prefs->getValue('date_format'))); } catch (Horde_Icalendar_Exception $e) { } $photos = $vc->getAllAttributes('PHOTO'); foreach ($photos as $p => $photo) { if (isset($photo['params']['VALUE']) && Horde_String::upper($photo['params']['VALUE']) == 'URI') { $html .= $this->_row(Horde_Core_Translation::t("Photo"), '<img src="' . htmlspecialchars($photo['value']) . '" />', false); } elseif (isset($photo['params']['ENCODING']) && Horde_String::upper($photo['params']['ENCODING']) == 'B' && isset($photo['params']['TYPE'])) { if ($browser->hasFeature('datauri') === true || $browser->hasFeature('datauri') >= strlen($photo['value'])) { $html .= $this->_row(Horde_Core_Translation::t("Photo"), '<img src="' . Horde_Url_Data::create($photo['params']['TYPE'], base64_decode($photo['value'])) . '" />', false); } elseif ($this->_imageUrl) { $html .= $this->_row(Horde_Core_Translation::t("Photo"), '<img src="' . $this->_imageUrl->add(array('c' => $i, 'p' => $p)) . '" />', false); } } } $labels = $vc->getAllAttributes('LABEL'); foreach ($labels as $label) { if (isset($label['params']['TYPE'])) { if (!is_array($label['params']['TYPE'])) { $label['params']['TYPE'] = array($label['params']['TYPE']); } } else { $label['params']['TYPE'] = array_keys($label['params']); } $types = array(); foreach ($label['params']['TYPE'] as $type) { switch (Horde_String::upper($type)) { case 'HOME': $types[] = Horde_Core_Translation::t("Home Address"); break; case 'WORK': $types[] = Horde_Core_Translation::t("Work Address"); break; case 'DOM': $types[] = Horde_Core_Translation::t("Domestic Address"); break; case 'INTL': $types[] = Horde_Core_Translation::t("International Address"); break; case 'POSTAL': $types[] = Horde_Core_Translation::t("Postal Address"); break; case 'PARCEL': $types[] = Horde_Core_Translation::t("Parcel Address"); break; case 'PREF': $types[] = Horde_Core_Translation::t("Preferred Address"); break; } } if (!count($types)) { $types = array(Horde_Core_Translation::t("Address")); } $html .= $this->_row(implode('/', $types), $label['value']); } $adrs = $vc->getAllAttributes('ADR'); foreach ($adrs as $item) { if (isset($item['params']['TYPE'])) { if (!is_array($item['params']['TYPE'])) { $item['params']['TYPE'] = array($item['params']['TYPE']); } } else { $item['params']['TYPE'] = array_keys($item['params']); } $address = $item['values']; $a = array(); $a_list = array(Horde_Icalendar_Vcard::ADR_STREET, Horde_Icalendar_Vcard::ADR_LOCALITY, Horde_Icalendar_Vcard::ADR_REGION, Horde_Icalendar_Vcard::ADR_POSTCODE, Horde_Icalendar_Vcard::ADR_COUNTRY); foreach ($a_list as $val) { if (isset($address[$val])) { $a[] = $address[$val]; } } $types = array(); foreach ($item['params']['TYPE'] as $type) { switch (Horde_String::upper($type)) { case 'HOME': $types[] = Horde_Core_Translation::t("Home Address"); break; case 'WORK': $types[] = Horde_Core_Translation::t("Work Address"); break; case 'DOM': $types[] = Horde_Core_Translation::t("Domestic Address"); break; case 'INTL': $types[] = Horde_Core_Translation::t("International Address"); break; case 'POSTAL': $types[] = Horde_Core_Translation::t("Postal Address"); break; case 'PARCEL': $types[] = Horde_Core_Translation::t("Parcel Address"); break; case 'PREF': $types[] = Horde_Core_Translation::t("Preferred Address"); break; } } if (!count($types)) { $types = array(Horde_Core_Translation::t("Address")); } $html .= $this->_row(implode('/', $types), implode("\n", $a)); } $numbers = $vc->getAllAttributes('TEL'); foreach ($numbers as $number) { if (isset($number['params']['TYPE'])) { if (!is_array($number['params']['TYPE'])) { $number['params']['TYPE'] = array($number['params']['TYPE']); } foreach ($number['params']['TYPE'] as $type) { $number['params'][Horde_String::upper($type)] = true; } } if (isset($number['params']['FAX'])) { $html .= $this->_row(Horde_Core_Translation::t("Fax"), $number['value']); } else { if (isset($number['params']['HOME'])) { $html .= $this->_row(Horde_Core_Translation::t("Home Phone"), $number['value']); } elseif (isset($number['params']['WORK'])) { $html .= $this->_row(Horde_Core_Translation::t("Work Phone"), $number['value']); } elseif (isset($number['params']['CELL'])) { $html .= $this->_row(Horde_Core_Translation::t("Cell Phone"), $number['value']); } else { $html .= $this->_row(Horde_Core_Translation::t("Phone"), $number['value']); } } } $emails = array(); foreach ($addresses as $address) { if (isset($address['params']['TYPE'])) { if (!is_array($address['params']['TYPE'])) { $address['params']['TYPE'] = array($address['params']['TYPE']); } foreach ($address['params']['TYPE'] as $type) { $address['params'][Horde_String::upper($type)] = true; } } $email = '<a href="'; if ($registry->hasMethod('mail/compose')) { $email .= $registry->call('mail/compose', array(array('to' => $address['value']))); } else { $email .= 'mailto:' . htmlspecialchars($address['value']); } $email .= '">' . htmlspecialchars($address['value']) . '</a>'; if (isset($address['params']['PREF'])) { array_unshift($emails, $email); } else { $emails[] = $email; } } if (count($emails)) { $html .= $this->_row(Horde_Core_Translation::t("Email"), implode("\n", $emails), false); } try { $title = $vc->getAttributeValues('TITLE'); $html .= $this->_row(Horde_Core_Translation::t("Title"), $title[0]); } catch (Horde_Icalendar_Exception $e) { } try { $role = $vc->getAttributeValues('ROLE'); $html .= $this->_row(Horde_Core_Translation::t("Role"), $role[0]); } catch (Horde_Icalendar_Exception $e) { } try { $org = $vc->getAttributeValues('ORG'); $html .= $this->_row(Horde_Core_Translation::t("Company"), $org[0]); if (isset($org[1])) { $html .= $this->_row(Horde_Core_Translation::t("Department"), $org[1]); } } catch (Horde_Icalendar_Exception $e) { } try { $notes = $vc->getAttributeValues('NOTE'); $html .= $this->_row(Horde_Core_Translation::t("Notes"), $notes[0]); } catch (Horde_Icalendar_Exception $e) { } try { $url = $vc->getAttributeValues('URL'); $html .= $this->_row(Horde_Core_Translation::t("URL"), '<a href="' . htmlspecialchars($url[0]) . '" target="_blank">' . htmlspecialchars($url[0]) . '</a>', false); } catch (Horde_Icalendar_Exception $e) { } } $html .= '</table>'; if ($registry->hasMethod('contacts/import') && $registry->hasMethod('contacts/sources')) { $html .= '<div class="horde-form-buttons"><form action="' . Horde::selfUrl() . '" method="get" name="vcard_import" id="vcard_import">' . Horde_Util::formInput(); foreach ($_GET as $key => $val) { $html .= '<input type="hidden" name="' . htmlspecialchars($key) . '" value="' . htmlspecialchars($val) . '" />'; } $sources = $registry->call('contacts/sources', array(true)); if (count($sources) > 1) { $html .= '<input type="submit" class="horde-default" name="import" value="' . Horde_Core_Translation::t("Add to address book:") . '" />' . ' <label for="add_source" class="hidden">' . Horde_Core_Translation::t("Address Book") . '</label>' . '<select id="add_source" name="source">'; foreach ($sources as $key => $label) { $selected = $key == $prefs->getValue('add_source') ? ' selected="selected"' : ''; $html .= '<option value="' . htmlspecialchars($key) . '"' . $selected . '>' . htmlspecialchars($label) . '</option>'; } $html .= '</select>'; } else { reset($sources); $html .= '<input type="submit" class="horde-default" name="import" value="' . Horde_Core_Translation::t("Add to my address book") . '" />' . '<input type="hidden" name="source" value="' . htmlspecialchars(key($sources)) . '" />'; } $html .= '</form></div>'; } Horde::startBuffer(); $notification->notify(array('listeners' => 'status')); return $this->_renderReturn(Horde::endBuffer() . $html, 'text/html; charset=' . $this->getConfigParam('charset')); }
/** * Retrieves the free/busy information for a given email address, if any * information is available. * * @param string $email The email address to look for. * @param boolean $json Whether to return the free/busy data as a simple * object suitable to be transferred as json. * * @return Horde_Icalendar_Vfreebusy|object Free/busy component. * @throws Kronolith_Exception */ public static function get($email, $json = false) { $default_domain = empty($GLOBALS['conf']['storage']['default_domain']) ? null : $GLOBALS['conf']['storage']['default_domain']; $rfc822 = new Horde_Mail_Rfc822(); try { $res = $rfc822->parseAddressList($email, array('default_domain' => $default_domain)); } catch (Horde_Mail_Exception $e) { throw new Kronolith_Exception($e); } if (!($tmp = $res[0])) { throw new Kronolith_Exception(_("No valid email address found")); } $email = $tmp->bare_address; /* Check if we can retrieve a VFB from the Free/Busy URL, if one is * set. */ $url = self::getUrl($email); if ($url) { $url = trim($url); $http = $GLOBALS['injector']->getInstance('Horde_Core_Factory_HttpClient')->create(array('request.verifyPeer' => false)); try { $response = $http->get($url); } catch (Horde_Http_Exception $e) { throw new Kronolith_Exception(sprintf(_("The free/busy url for %s cannot be retrieved."), $email)); } if ($response->code == 200 && ($data = $response->getBody())) { // Detect the charset of the iCalendar data. $contentType = $response->getHeader('Content-Type'); if ($contentType && strpos($contentType, ';') !== false) { list(, $charset, ) = explode(';', $contentType); $data = Horde_String::convertCharset($data, trim(str_replace('charset=', '', $charset)), 'UTF-8'); } $vCal = new Horde_Icalendar(); $vCal->parsevCalendar($data, 'VCALENDAR'); $components = $vCal->getComponents(); $vCal = new Horde_Icalendar(); $vFb = Horde_Icalendar::newComponent('vfreebusy', $vCal); $vFb->setAttribute('ORGANIZER', $email); $found = false; foreach ($components as $component) { if ($component instanceof Horde_Icalendar_Vfreebusy) { $found = true; $vFb->merge($component); } } if ($found) { // @todo: actually store the results in the storage, so // that they can be retrieved later. We should store the // plain iCalendar data though, to avoid versioning // problems with serialize iCalendar objects. return $json ? self::toJson($vFb) : $vFb; } } } /* Check storage driver. */ $storage = $GLOBALS['injector']->getInstance('Kronolith_Factory_Storage')->create(); try { $fb = $storage->search($email); return $json ? self::toJson($fb) : $fb; } catch (Horde_Exception_NotFound $e) { if ($url) { throw new Kronolith_Exception(sprintf(_("No free/busy information found at the free/busy url of %s."), $email)); } throw new Kronolith_Exception(sprintf(_("No free/busy url found for %s."), $email)); } }
/** * Replaces the event identified by UID with the content represented in the * specified contentType. * * @param string $uid Idenfity the event to replace. * @param mixed $content The content of the event. String or * Horde_Icalendar_Vevent * @param string $contentType What format is the data in? Currently supports: * text/calendar * text/x-vcalendar * (Ignored if content is Horde_Icalendar_Vevent) * activesync (Horde_ActiveSync_Message_Appointment) * @param string $calendar Ensure the event is replaced in the specified * calendar. @since 4.2.0 * * @return mixed For EAS operations, an array of 'uid' and 'atchash' * are returned. @since 4.3.0 * @throws Kronolith_Exception */ public function replace($uid, $content, $contentType, $calendar = null) { $event = Kronolith::getDriver(null, $calendar)->getByUID($uid); if (!$event->hasPermission(Horde_Perms::EDIT) || $event->private && $event->creator != $GLOBALS['registry']->getAuth()) { throw new Horde_Exception_PermissionDenied(); } if ($content instanceof Horde_Icalendar_Vevent) { $component = $content; } elseif ($content instanceof Horde_ActiveSync_Message_Appointment) { $event->fromASAppointment($content); $atc_hash = $event->addEASFiles($content); $event->save(); $event->uid = $uid; return array('uid' => $event->uid, 'atchash' => $atc_hash); return; } else { switch ($contentType) { case 'text/calendar': case 'text/x-vcalendar': if (!$content instanceof Horde_Icalendar_Vevent) { $iCal = new Horde_Icalendar(); if (!$iCal->parsevCalendar($content)) { throw new Kronolith_Exception(_("There was an error importing the iCalendar data.")); } $components = $iCal->getComponents(); $component = null; foreach ($components as $content) { if ($content instanceof Horde_Icalendar_Vevent) { if ($component !== null) { throw new Kronolith_Exception(_("Multiple iCalendar components found; only one vEvent is supported.")); } $component = $content; } } if ($component === null) { throw new Kronolith_Exception(_("No iCalendar data was found.")); } } break; default: throw new Kronolith_Exception(sprintf(_("Unsupported Content-Type: %s"), $contentType)); } } try { $component->getAttribute('RECURRENCE-ID'); $this->_addiCalEvent($component, Kronolith::getDriver(null, $calendar), true); } catch (Horde_Icalendar_Exception $e) { $event->fromiCalendar($component, true); // Ensure we keep the original UID, even when content does not // contain one and fromiCalendar creates a new one. $event->uid = $uid; $event->save(); } }
/** * @requires extension bcmath */ public function testMeetingTnef() { $winmail = file_get_contents(__DIR__ . '/fixtures/winmail2.dat'); $tnef = Horde_Compress::factory('Tnef'); $tnef_data = $tnef->decompress($winmail); // Test the meta data $this->assertEquals($tnef_data[0]['type'], 'text'); $this->assertEquals($tnef_data[0]['subtype'], 'calendar'); $this->assertEquals($tnef_data[0]['name'], 'Test Meeting'); // Test the generated iCalendar. $iCal = new Horde_Icalendar(); if (!$iCal->parsevCalendar($tnef_data[0]['stream'])) { throw new Horde_Compress_Exception(_("There was an error importing the iCalendar data.")); } $components = $iCal->getComponents(); if (count($components) == 0) { throw new Horde_Compress_Exception(_("No iCalendar data was found.")); } $iTip = current($components); $this->assertEquals($iTip->getAttribute('SUMMARY'), 'Test Meeting'); $this->assertEquals($iTip->getAttribute('DESCRIPTION'), 'This is a test meeting.'); $this->assertEquals($iTip->getAttribute('ORGANIZER'), 'mailto:mike@theupstairsroom.com'); $this->assertEquals($iTip->getAttribute('UID'), 'D38D34D34D34F36D347B4D34EF87396F00000000367B4D3CD34D34D34D34EF4774D3877BF3ADDA774D35D34D34D34D34D34D34D34D34D74D34D34D34D3471CF747DB6F469FE5EE34F386FCE75F79DFC6B675FE9D'); $this->assertEquals($iTip->getAttribute('ATTENDEE'), '*****@*****.**'); $params = $iTip->getAttribute('ATTENDEE', true); if (!$params) { throw new Horde_Compress_Exception('Could not find expected parameters.'); } $this->assertEquals($params[0]['ROLE'], 'REQ-PARTICIPANT'); $this->assertEquals($params[0]['PARTSTAT'], 'NEEDS-ACTION'); $this->assertEquals($params[0]['RSVP'], 'TRUE'); }
public function vtodo2sif($vcard) { $iCal = new Horde_Icalendar(); if (!$iCal->parsevCalendar($vcard)) { return PEAR::raiseError('There was an error importing the data.'); } $components = $iCal->getComponents(); switch (count($components)) { case 0: return PEAR::raiseError('No data was found'); case 1: $content = $components[0]; break; default: return PEAR::raiseError('Multiple components found; only one is supported.'); } $hash['Complete'] = 0; $due = false; $attr = $content->getAllAttributes(); foreach ($attr as $item) { switch ($item['name']) { case 'SUMMARY': $hash['Subject'] = $item['value']; break; case 'DESCRIPTION': $hash['Body'] = $item['value']; break; case 'PRIORITY': if ($item['value'] == 1) { $hash['Importance'] = 2; } elseif ($item['value'] == 5) { $hash['Importance'] = 0; } else { $hash['Importance'] = 1; } break; case 'DTSTART': $hash['StartDate'] = Horde_Icalendar::_exportDateTime($item['value']); break; case 'DUE': $hash['DueDate'] = Horde_Icalendar::_exportDateTime($item['value']); $due = $item['value']; break; case 'AALARM': $hash['ReminderTime'] = $item['value']; $hash['ReminderSet'] = 1; break; case 'STATUS': $hash['Complete'] = $item['value'] == 'COMPLETED' ? 1 : 0; break; case 'CATEGORIES': $hash['Categories'] = $item['value']; break; case 'CLASS': switch (Horde_String::upper($item['value'])) { case 'PUBLIC': $hash['Sensitivity'] = 0; break; case 'PRIVATE': $hash['Sensitivity'] = 2; break; case 'CONFIDENTIAL': $hash['Sensitivity'] = 3; break; } break; } } if ($due && !isset($hash['ReminderSet'])) { // Parse VALARM components. foreach ($content->getComponents() as $component) { if ($component->getType() != 'vAlarm') { continue; } try { $trigger = $component->getAttribute('TRIGGER'); } catch (Horde_Icalendar_Exception $e) { continue; } if (is_array($trigger) || empty($trigger)) { continue; } $hash['ReminderSet'] = 1; $hash['ReminderTime'] = Horde_Icalendar::_exportDateTime($due - $trigger); } } return Horde_SyncMl_Device_sync4j::array2sif($hash, '<?xml version="1.0"?><task>', '</task>'); }
/** * Replace the memo identified by UID with the content represented in * the specified contentType. * * @param string $uid Idenfity the memo to replace. * @param string $content The content of the memo. * @param string $contentType What format is the data in? Currently supports: * text/plain * text/x-vnote * activesync * @throws Mnemo_Exception * @throws Horde_Exception_PermissionDenied */ public function replace($uid, $content, $contentType) { $storage = $GLOBALS['injector']->getInstance('Mnemo_Factory_Driver')->create(); $memo = $storage->getByUID($uid); if (!array_key_exists($memo['memolist_id'], Mnemo::listNotepads(false, Horde_Perms::EDIT))) { throw new Horde_Exception_PermissionDenied(); } switch ($contentType) { case 'text/plain': $storage->modify($memo['memo_id'], $storage->getMemoDescription($content), $content, null); break; case 'text/x-vnote': if (!$content instanceof Horde_Icalendar_Vnote) { $iCal = new Horde_Icalendar(); if (!$iCal->parsevCalendar($content)) { throw new Mnemo_Exception(_("There was an error importing the iCalendar data.")); } $components = $iCal->getComponents(); switch (count($components)) { case 0: throw new Mnemo_Exception(_("No iCalendar data was found.")); case 1: $content = $components[0]; break; default: throw new Mnemo_Exception(_("Multiple iCalendar components found; only one vNote is supported.")); } } $note = $storage->fromiCalendar($content); $storage->modify($memo['memo_id'], $note['desc'], $note['body'], !empty($note['tags']) ? $note['tags'] : ''); break; case 'activesync': $storage->modify($memo['memo_id'], $content->subject, $content->body->data, $content->categories); break; default: throw new Mnemo_Exception(sprintf(_("Unsupported Content-Type: %s"), $contentType)); } }
/** * Variables required in form input: * - identity (TODO: ? Code uses it, but it is never set anywhere) * - imple_submit: itip_action(s) * - mime_id * - muid * * @return boolean True on success. */ protected function _handle(Horde_Variables $vars) { global $injector, $notification, $registry; $actions = (array) $vars->imple_submit; $result = false; $vCal = new Horde_Icalendar(); /* Retrieve the calendar data from the message. */ try { $contents = $injector->getInstance('IMP_Factory_Contents')->create(new IMP_Indices_Mailbox($vars)); $mime_part = $contents->getMIMEPart($vars->mime_id); if (empty($mime_part)) { throw new IMP_Exception(_("Cannot retrieve calendar data from message.")); } elseif (!$vCal->parsevCalendar($mime_part->getContents(), 'VCALENDAR', $mime_part->getCharset())) { throw new IMP_Exception(_("The calendar data is invalid")); } $components = $vCal->getComponents(); } catch (Exception $e) { $notification->push($e, 'horde.error'); $actions = array(); } foreach ($actions as $key => $action) { $pos = strpos($key, '['); $key = substr($key, $pos + 1, strlen($key) - $pos - 2); switch ($action) { case 'delete': // vEvent cancellation. if ($registry->hasMethod('calendar/delete')) { $guid = $components[$key]->getAttribute('UID'); $recurrenceId = null; try { // This is a cancellation of a recurring event instance. $recurrenceId = $components[$key]->getAttribute('RECURRENCE-ID'); $atts = $components[$key]->getAttribute('RECURRENCE-ID', true); $range = null; foreach ($atts as $att) { if (array_key_exists('RANGE', $att)) { $range = $att['RANGE']; } } } catch (Horde_Icalendar_Exception $e) { } try { $registry->call('calendar/delete', array($guid, $recurrenceId, $range)); $notification->push(_("Event successfully deleted."), 'horde.success'); $result = true; } catch (Horde_Exception $e) { $notification->push(sprintf(_("There was an error deleting the event: %s"), $e->getMessage()), 'horde.error'); } } else { $notification->push(_("This action is not supported."), 'horde.warning'); } break; case 'update': // vEvent reply. if ($registry->hasMethod('calendar/updateAttendee')) { try { $from = $contents->getHeader()->getOb('from'); $registry->call('calendar/updateAttendee', array($components[$key], $from[0]->bare_address)); $notification->push(_("Respondent Status Updated."), 'horde.success'); $result = true; } catch (Horde_Exception $e) { $notification->push(sprintf(_("There was an error updating the event: %s"), $e->getMessage()), 'horde.error'); } } else { $notification->push(_("This action is not supported."), 'horde.warning'); } break; case 'import': case 'accept-import': // vFreebusy reply. // vFreebusy publish. // vEvent request. // vEvent publish. // vTodo publish. // vJournal publish. switch ($components[$key]->getType()) { case 'vEvent': $result = $this->_handlevEvent($key, $components, $mime_part); // Must check for exceptions. foreach ($components as $k => $component) { try { if ($component->getType() == 'vEvent' && $component->getAttribute('RECURRENCE-ID')) { $uid = $component->getAttribute('UID'); if ($uid == $components[$key]->getAttribute('UID')) { $this->_handlevEvent($k, $components, $mime_part); } } } catch (Horde_Icalendar_Exception $e) { } } break; case 'vFreebusy': // Import into Kronolith. if ($registry->hasMethod('calendar/import_vfreebusy')) { try { $registry->call('calendar/import_vfreebusy', array($components[$key])); $notification->push(_("The user's free/busy information was sucessfully stored."), 'horde.success'); $result = true; } catch (Horde_Exception $e) { $notification->push(sprintf(_("There was an error importing user's free/busy information: %s"), $e->getMessage()), 'horde.error'); } } else { $notification->push(_("This action is not supported."), 'horde.warning'); } break; case 'vTodo': // Import into Nag. if ($registry->hasMethod('tasks/import')) { try { $guid = $registry->call('tasks/import', array($components[$key], $mime_part->getType())); $url = Horde::url($registry->link('tasks/show', array('uid' => $guid))); $notification->push(_("The task has been added to your tasklist.") . ' ' . Horde::link($url, _("View task"), null, '_blank') . Horde_Themes_Image::tag('mime/icalendar.png', array('alt' => _("View task"))) . '</a>', 'horde.success', array('content.raw')); $result = true; } catch (Horde_Exception $e) { $notification->push(sprintf(_("There was an error importing the task: %s"), $e->getMessage()), 'horde.error'); } } else { $notification->push(_("This action is not supported."), 'horde.warning'); } break; case 'vJournal': default: $notification->push(_("This action is not supported."), 'horde.warning'); } if ($action == 'import') { break; } // Fall-through for 'accept-import' // Fall-through for 'accept-import' case 'accept': case 'deny': case 'tentative': // vEvent request. if (isset($components[$key]) && $components[$key]->getType() == 'vEvent') { $vEvent = $components[$key]; $resource = new Horde_Itip_Resource_Identity($injector->getInstance('IMP_Identity'), $vEvent->getAttribute('ATTENDEE'), $vars->identity); switch ($action) { case 'accept': case 'accept-import': $type = new Horde_Itip_Response_Type_Accept($resource); break; case 'deny': $type = new Horde_Itip_Response_Type_Decline($resource); break; case 'tentative': $type = new Horde_Itip_Response_Type_Tentative($resource); break; } try { // Send the reply. Horde_Itip::factory($vEvent, $resource)->sendMultiPartResponse($type, new Horde_Core_Itip_Response_Options_Horde('UTF-8', array()), $injector->getInstance('IMP_Mail')); $notification->push(_("Reply Sent."), 'horde.success'); $result = true; } catch (Horde_Itip_Exception $e) { $notification->push(sprintf(_("Error sending reply: %s."), $e->getMessage()), 'horde.error'); } } else { $notification->push(_("This action is not supported."), 'horde.warning'); } break; case 'send': case 'reply': case 'reply2m': // vfreebusy request. if (isset($components[$key]) && $components[$key]->getType() == 'vFreebusy') { $vFb = $components[$key]; // Get the organizer details. try { $organizer = parse_url($vFb->getAttribute('ORGANIZER')); } catch (Horde_Icalendar_Exception $e) { break; } $organizerEmail = $organizer['path']; $organizer = $vFb->getAttribute('ORGANIZER', true); $organizerFullEmail = new Horde_Mail_Rfc822_Address($organizerEmail); if (isset($organizer['cn'])) { $organizerFullEmail->personal = $organizer['cn']; } if ($action == 'reply2m') { $startStamp = time(); $endStamp = $startStamp + 60 * 24 * 3600; } else { try { $startStamp = $vFb->getAttribute('DTSTART'); } catch (Horde_Icalendar_Exception $e) { $startStamp = time(); } try { $endStamp = $vFb->getAttribute('DTEND'); } catch (Horde_Icalendar_Exception $e) { } if (!$endStamp) { try { $duration = $vFb->getAttribute('DURATION'); $endStamp = $startStamp + $duration; } catch (Horde_Icalendar_Exception $e) { $endStamp = $startStamp + 60 * 24 * 3600; } } } $vfb_reply = $registry->call('calendar/getFreeBusy', array($startStamp, $endStamp)); // Find out who we are and update status. $identity = $injector->getInstance('IMP_Identity'); $email = $identity->getFromAddress(); // Build the reply. $msg_headers = new Horde_Mime_Headers(); $vCal = new Horde_Icalendar(); $vCal->setAttribute('PRODID', '-//The Horde Project//' . $msg_headers->getUserAgent() . '//EN'); $vCal->setAttribute('METHOD', 'REPLY'); $vCal->addComponent($vfb_reply); $message = _("Attached is a reply to a calendar request you sent."); $body = new Horde_Mime_Part(); $body->setType('text/plain'); $body->setCharset('UTF-8'); $body->setContents(Horde_String::wrap($message, 76)); $ics = new Horde_Mime_Part(); $ics->setType('text/calendar'); $ics->setCharset('UTF-8'); $ics->setContents($vCal->exportvCalendar()); $ics->setName('icalendar.ics'); $ics->setContentTypeParameter('METHOD', 'REPLY'); $mime = new Horde_Mime_Part(); $mime->addPart($body); $mime->addPart($ics); // Build the reply headers. $msg_headers->addReceivedHeader(array('dns' => $injector->getInstance('Net_DNS2_Resolver'), 'server' => $conf['server']['name'])); $msg_headers->addMessageIdHeader(); $msg_headers->addHeader('Date', date('r')); $msg_headers->addHeader('From', $email); $msg_headers->addHeader('To', $organizerFullEmail); $identity->setDefault($vars->identity); $replyto = $identity->getValue('replyto_addr'); if (!empty($replyto) && !$email->match($replyto)) { $msg_headers->addHeader('Reply-To', $replyto); } $msg_headers->addHeader('Subject', _("Free/Busy Request Response")); // Send the reply. try { $mime->send($organizerEmail, $msg_headers, $injector->getInstance('IMP_Mail')); $notification->push(_("Reply Sent."), 'horde.success'); $result = true; } catch (Exception $e) { $notification->push(sprintf(_("Error sending reply: %s."), $e->getMessage()), 'horde.error'); } } else { $notification->push(_("Invalid Action selected for this component."), 'horde.warning'); } break; case 'nosup': // vFreebusy request. // vFreebusy request. default: $notification->push(_("This action is not supported."), 'horde.warning'); break; } } return $result; }
public function testBug12869RecurrenceEndFromIcalendar() { date_default_timezone_set('Europe/Amsterdam'); $iCal = new Horde_Icalendar(); $iCal->parsevCalendar(file_get_contents(__DIR__ . '/fixtures/bug12869.ics')); $components = $iCal->getComponents(); foreach ($components as $content) { if ($content instanceof Horde_Icalendar_Vevent) { $start = new Horde_Date($content->getAttribute('DTSTART')); $end = new Horde_Date($content->getAttribute('DTEND')); $rrule = $content->getAttribute('RRULE'); $recurrence = new Horde_Date_Recurrence($start, $end); $recurrence->fromRRule20($rrule); break; } } $after = array('year' => 2013, 'month' => 12); $after['mday'] = 11; $this->assertEquals('2013-12-12 13:45:00', (string) $recurrence->nextRecurrence($after)); $after['mday'] = 18; $this->assertEquals('2013-12-19 13:45:00', (string) $recurrence->nextRecurrence($after)); $after['mday'] = 20; $this->assertEquals('', (string) $recurrence->nextRecurrence($after)); date_default_timezone_set('Europe/Berlin'); }