Автор: Mike Cochrane (mike@graftonhall.co.nz)
Пример #1
0
 /**
  */
 protected function _create($mbox, $subject, $body)
 {
     global $notification, $registry;
     $list = str_replace(self::TASKLIST_EDIT, '', $mbox);
     /* Create a new iCalendar. */
     $vCal = new Horde_Icalendar();
     $vCal->setAttribute('PRODID', '-//The Horde Project//IMP ' . $registry->getVersion() . '//EN');
     $vCal->setAttribute('METHOD', 'PUBLISH');
     /* Create a new vTodo object using this message's contents. */
     $vTodo = Horde_Icalendar::newComponent('vtodo', $vCal);
     $vTodo->setAttribute('SUMMARY', $subject);
     $vTodo->setAttribute('DESCRIPTION', $body);
     $vTodo->setAttribute('PRIORITY', '3');
     /* Get the list of editable tasklists. */
     $lists = $this->getTasklists(true);
     /* Attempt to add the new vTodo item to the requested tasklist. */
     try {
         $res = $registry->call('tasks/import', array($vTodo, 'text/calendar', $list));
     } catch (Horde_Exception $e) {
         $notification->push($e);
         return;
     }
     if (!$res) {
         $notification->push(_("An unknown error occured while creating the new task."), 'horde.error');
     } elseif (!empty($lists)) {
         $name = '"' . htmlspecialchars($subject) . '"';
         /* Attempt to convert the object name into a hyperlink. */
         if ($registry->hasLink('tasks/show')) {
             $name = sprintf('<a href="%s">%s</a>', Horde::url($registry->link('tasks/show', array('uid' => $res))), $name);
         }
         $notification->push(sprintf(_("%s was successfully added to \"%s\"."), $name, htmlspecialchars($lists[$list]->get('name'))), 'horde.success', array('content.raw'));
     }
 }
Пример #2
0
 /**
  * Yet another problem: Outlook seems to remove the organizer from
  * the iCal when forwarding -- we put the original sender back in
  * as organizer.
  *
  * @param string        $icaltext  The ical message.
  * @param MIME_Headers  $from      The message sender.
  */
 function _addOrganizer(&$icaltxt, $from)
 {
     global $conf;
     if (isset($conf['kolab']['filter']['email_domain'])) {
         $email_domain = $conf['kolab']['filter']['email_domain'];
     } else {
         $email_domain = 'localhost';
     }
     $iCal = new Horde_Icalendar();
     $iCal->parsevCalendar($icaltxt);
     $vevent =& $iCal->findComponent('VEVENT');
     if ($vevent) {
         $organizer = $vevent->getAttribute('ORGANIZER', true);
         if (is_a($organizer, 'PEAR_Error')) {
             $adrs = imap_rfc822_parse_adrlist($from, $email_domain);
             if (count($adrs) > 0) {
                 $org_email = 'mailto:' . $adrs[0]->mailbox . '@' . $adrs[0]->host;
                 $org_name = $adrs[0]->personal;
                 if ($org_name) {
                     $vevent->setAttribute('ORGANIZER', $org_email, array('CN' => $org_name), false);
                 } else {
                     $vevent->setAttribute('ORGANIZER', $org_email, array(), false);
                 }
                 Horde::log(sprintf("Adding missing organizer '%s <%s>' to iCal.", $org_name, $org_email), 'DEBUG');
                 $icaltxt = $iCal->exportvCalendar();
             }
         }
     }
 }
Пример #3
0
 /**
  * Test creating a Horde_ActiveSync_Message_MeetingRequest from a MIME Email
  */
 public function testInvite()
 {
     $this->markTestIncomplete('Has issues on 32bit systems');
     $fixture = file_get_contents(__DIR__ . '/fixtures/invitation_one.eml');
     $mime = Horde_Mime_Part::parseMessage($fixture);
     $msg = new Horde_ActiveSync_Message_MeetingRequest();
     foreach ($mime->contentTypeMap() as $id => $type) {
         if ($type == 'text/calendar') {
             $vcal = new Horde_Icalendar();
             $vcal->parseVcalendar($mime->getPart($id)->getContents());
             $msg->fromvEvent($vcal);
             break;
         }
     }
     $stream = fopen('php://memory', 'wb+');
     $encoder = new Horde_ActiveSync_Wbxml_Encoder($stream);
     $msg->encodeStream($encoder);
     rewind($stream);
     $results = stream_get_contents($stream);
     fclose($stream);
     $stream = fopen(__DIR__ . '/fixtures/meeting_request_one.wbxml', 'r+');
     $expected = '';
     // Using file_get_contents or even fread mangles the binary data for some
     // reason.
     while ($line = fgets($stream)) {
         $expected .= $line;
     }
     fclose($stream);
     $this->assertEquals($expected, $results);
 }
Пример #4
0
 private function _getFixture($element)
 {
     $iCal = new Horde_Icalendar();
     $iCal->parsevCalendar(file_get_contents(__DIR__ . '/../fixtures/allday.ics'));
     $components = $iCal->getComponents();
     return $components[$element];
 }
Пример #5
0
 /**
  * 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');
     }
 }
Пример #6
0
 /**
  * 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(_("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();
     $components = $vCal->getComponents();
     foreach ($components as $key => $component) {
         switch ($component->getType()) {
             case 'vEvent':
                 try {
                     if ($component->getAttribute('RECURRENCE-ID')) {
                         break;
                     }
                 } 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;
         }
     }
     $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'));
 }
Пример #7
0
 public function testGeo()
 {
     $ical = new Horde_Icalendar();
     $ical->parsevCalendar(file_get_contents(__DIR__ . '/fixtures/geo1.vcf'));
     $this->assertEquals(array('latitude' => -17.87, 'longitude' => 37.24), $ical->getComponent(0)->getAttribute('GEO'));
     $ical->parsevCalendar(file_get_contents(__DIR__ . '/fixtures/geo2.vcf'));
     $this->assertEquals(array('latitude' => 37.386013, 'longitude' => -122.082932), $ical->getComponent(0)->getAttribute('GEO'));
 }
Пример #8
0
 public function testIgnoringMultipleAttributeValues()
 {
     $ical = new Horde_Icalendar();
     $ical->parsevCalendar(file_get_contents(__DIR__ . '/fixtures/multiple-summary.ics'));
     $result = $ical->getComponent(0)->getAttributeSingle('SUMMARY');
     $this->assertInternalType('string', $result);
     $this->assertEquals('Summary 1', $result);
 }
Пример #9
0
 public function testFiles()
 {
     $test_files = glob(__DIR__ . '/fixtures/charset*.ics');
     foreach ($test_files as $file) {
         $ical = new Horde_Icalendar();
         $ical->parsevCalendar(file_get_contents($file));
         $this->assertEquals('möchen', $ical->getComponent(0)->getAttribute('SUMMARY'));
     }
 }
Пример #10
0
 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]);
     return $event;
 }
Пример #11
0
 public function testBug14132()
 {
     $ical = new Horde_Icalendar();
     $ical->parsevCalendar(file_get_contents(__DIR__ . '/fixtures/bug14132.ics'));
     $params = $ical->getComponent(1)->getAttribute('DTSTART', true);
     $tz = $params[0]['TZID'];
     $start = $ical->getComponent(1)->getAttribute('DTSTART');
     $dtstart = new Horde_Date($start, $tz);
     $this->assertEquals((string) $dtstart, '2015-10-09 03:00:00');
 }
Пример #12
0
 /**
  * Return the response as an iCalendar vEvent object.
  *
  * @param Horde_Itip_Response_Type $type The response type.
  * @param Horde_Icalendar|boolean  $vCal The parent container or false if not
  *                                       provided.
  *
  * @return Horde_Icalendar_Vevent The response object.
  */
 public function getVevent(Horde_Itip_Response_Type $type, $vCal = false)
 {
     $itip_reply = new Horde_Itip_Event_Vevent(Horde_Icalendar::newComponent('VEVENT', $vCal));
     $this->_request->copyEventInto($itip_reply);
     $type->setRequest($this->_request);
     $itip_reply->setAttendee($this->_resource->getMailAddress(), $this->_resource->getCommonName(), $type->getStatus());
     return $itip_reply->getVevent();
 }
Пример #13
0
 /**
  * @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));
 }
Пример #14
0
 /**
  * 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;
 }
Пример #15
0
 public function testRead()
 {
     $ical = new Horde_Icalendar();
     $ical->parsevCalendar(file_get_contents(__DIR__ . '/fixtures/vfreebusy1.ics'));
     // Get the vFreeBusy component
     $vfb = $ical->getComponent(0);
     // Dump the type
     $this->assertEquals('vFreebusy', $vfb->getType());
     // Dump the vfreebusy component again (the duration should be
     // converted to start/end
     $this->assertStringEqualsFile(__DIR__ . '/fixtures/vfreebusy2.ics', $vfb->exportvCalendar());
     // Dump organizer name
     $this->assertEquals('GunnarWrobel', $vfb->getName());
     // Dump organizer mail
     $this->assertEquals('*****@*****.**', $vfb->getEmail());
     // Dump busy periods
     $this->assertEquals(array(1164258000 => 1164261600, 1164268800 => 1164276000), $vfb->getBusyPeriods());
     // Decode the summary information
     $extra = $vfb->getExtraParams();
     $this->assertEquals('testtermin', base64_decode($extra[1164258000]['X-SUMMARY']));
     // Dump the free periods in between the two given time stamps
     $this->assertEquals(array(1164261600 => 1164268800), $vfb->getFreePeriods(1164261500, 1164268900));
     // Dump start of the free/busy information
     $this->assertEquals(1164236400, $vfb->getStart());
     // Dump end of the free/busy information
     $this->assertEquals(1169420400, $vfb->getEnd());
     // Free periods don't get added
     $vfb->addBusyPeriod('FREE', 1164261600, 1164268800);
     $this->assertEquals(array(1164258000 => 1164261600, 1164268800 => 1164276000), $vfb->getBusyPeriods());
     // Add a busy period with start/end (11:00 / 12:00)
     $vfb->addBusyPeriod('BUSY', 1164279600, 1164283200);
     // Add a busy period with start/duration (14:00 / 2h)
     $vfb->addBusyPeriod('BUSY', 1164290400, null, 7200, array('X-SUMMARY' => 'dGVzdA=='));
     // Dump busy periods
     $this->assertEquals(array(1164258000 => 1164261600, 1164268800 => 1164276000, 1164279600 => 1164283200, 1164290400 => 1164297600), $vfb->getBusyPeriods());
     // Dump the extra parameters
     $this->assertEquals(array(1164258000 => array('X-UID' => 'MmZlNWU3NDRmMGFjNjZkNjRjZjFkZmFmYTE4NGFiZTQ=', 'X-SUMMARY' => 'dGVzdHRlcm1pbg=='), 1164268800 => array(), 1164279600 => array(), 1164290400 => array('X-SUMMARY' => 'dGVzdA==')), $vfb->getExtraParams());
     return $vfb;
 }
Пример #16
0
 /**
  * Retrieve Free/Busy data for the specified resource.
  *
  * @param string $resource Fetch the Free/Busy data for this resource.
  *
  * @return Horde_Icalendar_Vfreebusy The Free/Busy data.
  */
 public function get($resource)
 {
     global $conf;
     $url = self::getUrl($resource);
     Horde::log(sprintf('Freebusy URL for resource %s is %s', $resource, $url), 'DEBUG');
     list($user, $domain) = explode('@', $resource);
     if (empty($domain)) {
         $domain = $conf['kolab']['filter']['email_domain'];
     }
     /**
      * This section matches Kronolith_Freebusy and should be merged with it
      * again in a single Horde_Freebusy module.
      */
     $options = array('method' => 'GET', 'timeout' => 5, 'allowRedirects' => true);
     if (!empty($conf['http']['proxy']['proxy_host'])) {
         $options = array_merge($options, $conf['http']['proxy']);
     }
     $http = new HTTP_Request($url, $options);
     $http->setBasicAuth($conf['kolab']['filter']['calendar_id'] . '@' . $domain, $conf['kolab']['filter']['calendar_pass']);
     @$http->sendRequest();
     if ($http->getResponseCode() != 200) {
         throw new Horde_Kolab_Resource_Exception(sprintf('Unable to retrieve free/busy information for %s', $resource), Horde_Kolab_Resource_Exception::NO_FREEBUSY);
     }
     $vfb_text = $http->getResponseBody();
     // Detect the charset of the iCalendar data.
     $contentType = $http->getResponseHeader('Content-Type');
     if ($contentType && strpos($contentType, ';') !== false) {
         list(, $charset, ) = explode(';', $contentType);
         $vfb_text = Horde_String::convertCharset($vfb_text, trim(str_replace('charset=', '', $charset)), 'UTF-8');
     }
     $iCal = new Horde_Icalendar();
     $iCal->parsevCalendar($vfb_text, 'VCALENDAR');
     $vfb =& $iCal->findComponent('VFREEBUSY');
     if ($vfb === false) {
         throw new Horde_Kolab_Resource_Exception(sprintf('Invalid or no free/busy information available for %s', $resource), Horde_Kolab_Resource_Exception::NO_FREEBUSY);
     }
     $vfb->simplify();
     return $vfb;
 }
Пример #17
0
 /**
  * @param mixed Kronolith_Event|string $event  The event object or error
  *                                             string to display.
  */
 public function __construct($event)
 {
     if (!$event) {
         echo '<h3>' . _("Event not found") . '</h3>';
         exit;
     }
     if (is_string($event)) {
         echo '<h3>' . $event . '</h3>';
         exit;
     }
     $iCal = new Horde_Icalendar('2.0');
     if ($event->calendarType == 'internal') {
         try {
             $share = $GLOBALS['injector']->getInstance('Kronolith_Shares')->getShare($event->calendar);
             $iCal->setAttribute('X-WR-CALNAME', $share->get('name'));
         } catch (Exception $e) {
         }
     }
     $iCal->addComponent($event->toiCalendar($iCal));
     $content = $iCal->exportvCalendar();
     $GLOBALS['browser']->downloadHeaders($event->getTitle() . '.ics', 'text/calendar; charset=UTF-8', true, strlen($content));
     echo $content;
     exit;
 }
Пример #18
0
 /**
  * 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));
 }
Пример #19
0
 /**
  * @throws Kronolith_Exception
  */
 public function search($email, $private_only = false)
 {
     $server = $GLOBALS['injector']->getInstance('Horde_Kolab_Session')->getFreebusyServer();
     if (empty($server)) {
         throw new Horde_Exception_NotFound();
     }
     $http = $GLOBALS['injector']->getInstance('Horde_Core_Factory_HttpClient')->create(array('request.username' => $GLOBALS['registry']->getAuth(), 'request.password' => $GLOBALS['registry']->getAuthCredential('password')));
     try {
         $response = $http->get(sprintf('%s/%s.xfb', $server, $email));
     } catch (Horde_Http_Exception $e) {
         throw new Horde_Exception_NotFound();
     }
     if ($response->code != 200) {
         throw new Horde_Exception_NotFound();
     }
     $vfb_text = $response->getBody();
     $iCal = new Horde_Icalendar();
     $iCal->parsevCalendar($vfb_text);
     $vfb = $iCal->findComponent('VFREEBUSY');
     if ($vfb === false) {
         throw new Horde_Exception_NotFound();
     }
     return $vfb;
 }
Пример #20
0
 /**
  * Groks the TZID and returns an offset in seconds from UTC for this
  * date and time.
  *
  * @param array $date   A date hash.
  * @param array $time   A time hash.
  * @param string $tzid  A timezone ID.
  *
  * @return integer  The offset from UTC in seconds for the provided
  *                  timezone and date/time.
  */
 protected function _parseTZID($date, $time, $tzid)
 {
     $vtimezone = $this->_container->findComponentByAttribute('vtimezone', 'TZID', $tzid);
     if (!$vtimezone) {
         return false;
     }
     $change_times = array();
     foreach ($vtimezone->getComponents() as $o) {
         $change_times = array_merge($change_times, $vtimezone->parseChild($o, $date['year']));
     }
     if (!$change_times) {
         return false;
     }
     usort($change_times, function ($a, $b) {
         if (!$a['end']) {
             if (!$b['end']) {
                 return $a['time'] - $b['time'];
             }
             return 1;
         }
         if (!$b['end']) {
             return -1;
         }
         return $a['end'] - $b['end'];
     });
     // Time is arbitrarily based on UTC for comparison.
     $t = @gmmktime($time['hour'], $time['minute'], $time['second'], $date['month'], $date['mday'], $date['year']);
     if ($t < $change_times[0]['time']) {
         return $change_times[0]['from'];
     }
     for ($i = 0, $n = count($change_times); $i < $n - 1; $i++) {
         // See Bug: 14153. Some timezone definitions may be such that a
         // transition will incorrectly match due to the way we parse the
         // 'end' times. There *may* be a more correct way to do this by
         // sorting the transitions/handling 'end' values differently.
         if ($t >= $change_times[$i]['time'] && $t < $change_times[$i + 1]['time'] && $this->_checkEndDate($t, $change_times[$i + 1])) {
             return $change_times[$i]['to'];
         }
     }
     if ($t >= $change_times[$n - 1]['time']) {
         return $change_times[$n - 1]['to'];
     }
     return false;
 }
Пример #21
0
 /**
  * Parses a string containing vFreebusy data.
  *
  * @param string $data     The data to parse.
  * @param $type TODO
  * @param $charset TODO
  */
 public function parsevCalendar($data, $type = null, $charset = null)
 {
     parent::parsevCalendar($data, 'VFREEBUSY', $charset);
     // Do something with all the busy periods.
     foreach ($this->_attributes as $key => $attribute) {
         if ($attribute['name'] != 'FREEBUSY') {
             continue;
         }
         foreach ($attribute['values'] as $value) {
             $params = isset($attribute['params']) ? $attribute['params'] : array();
             if (isset($value['duration'])) {
                 $this->addBusyPeriod('BUSY', $value['start'], null, $value['duration'], $params);
             } else {
                 $this->addBusyPeriod('BUSY', $value['start'], $value['end'], null, $params);
             }
         }
         unset($this->_attributes[$key]);
     }
 }
Пример #22
0
 /**
  * Groks the TZID and returns an offset in seconds from UTC for this
  * date and time.
  *
  * @param array $date   A date hash.
  * @param array $time   A time hash.
  * @param string $tzid  A timezone ID.
  *
  * @return integer  The offset from UTC in seconds for the provided
  *                  timezone and date/time.
  */
 protected function _parseTZID($date, $time, $tzid)
 {
     $vtimezone = $this->_container->findComponentByAttribute('vtimezone', 'TZID', $tzid);
     if (!$vtimezone) {
         return false;
     }
     $change_times = array();
     foreach ($vtimezone->getComponents() as $o) {
         $change_times = array_merge($change_times, $vtimezone->parseChild($o, $date['year']));
     }
     if (!$change_times) {
         return false;
     }
     usort($change_times, function ($a, $b) {
         if (!$a['end']) {
             if (!$b['end']) {
                 return $a['time'] - $b['time'];
             }
             return 1;
         }
         if (!$b['end']) {
             return -1;
         }
         return $a['end'] - $b['end'];
     });
     // Time is arbitrarily based on UTC for comparison.
     $t = @gmmktime($time['hour'], $time['minute'], $time['second'], $date['month'], $date['mday'], $date['year']);
     if ($t < $change_times[0]['time']) {
         return $change_times[0]['from'];
     }
     for ($i = 0, $n = count($change_times); $i < $n - 1; $i++) {
         if ($t >= $change_times[$i]['time'] && $t < $change_times[$i + 1]['time']) {
             return $change_times[$i]['to'];
         }
     }
     if ($t >= $change_times[$n - 1]['time']) {
         return $change_times[$n - 1]['to'];
     }
     return false;
 }
Пример #23
0
 /**
  * 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.") . '&nbsp;' . 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;
 }
Пример #24
0
 /**
  * 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'];
         }
     }
 }
Пример #25
0
 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>');
 }
Пример #26
0
             $notification->push(_("Calendar successfully purged."), 'horde.success');
         } catch (Exception $e) {
             $notification->push(sprintf(_("The calendar could not be purged: %s"), $e->getMessage()), 'horde.error');
         }
     }
 }
 $recurrences = array();
 $ical = null;
 foreach ($next_step as $row) {
     if ($max_events !== true && $num_events >= $max_events) {
         Horde::permissionDeniedError('kronolith', 'max_events', sprintf(_("You are not allowed to create more than %d events."), $perms->hasAppPermission('max_events')));
         break;
     }
     if ($row instanceof Horde_Icalendar_Vevent) {
         if (!$ical) {
             $ical = new Horde_Icalendar();
         }
         $ical->addComponent($row);
         if ($max_events !== true) {
             $num_events++;
         }
         continue;
     }
     try {
         $event = $kronolith_driver->getEvent();
     } catch (Exception $e) {
         $msg = _("Can't create a new event.") . ' ' . sprintf(_("This is what the server said: %s"), $e->getMessage());
         $notification->push($msg, 'horde.error');
         $error = true;
         break;
     }
Пример #27
0
 /**
  * Handle parsing recurrence related fields.
  *
  * @param Horde_Icalendar $vEvent
  * @throws Kronolith_Exception
  */
 protected function _handlevEventRecurrence($vEvent)
 {
     // Recurrence.
     try {
         $rrule = $vEvent->getAttribute('RRULE');
         if (!is_array($rrule)) {
             $this->recurrence = new Horde_Date_Recurrence($this->start);
             if (strpos($rrule, '=') !== false) {
                 $this->recurrence->fromRRule20($rrule);
             } else {
                 $this->recurrence->fromRRule10($rrule);
             }
             /* Delete all existing exceptions to this event if it
              * already exists */
             if (!empty($this->uid)) {
                 $kronolith_driver = Kronolith::getDriver(null, $this->calendar);
                 $search = new StdClass();
                 $search->start = $this->recurrence->getRecurStart();
                 $search->end = $this->recurrence->getRecurEnd();
                 $search->baseid = $this->uid;
                 $results = $kronolith_driver->search($search);
                 foreach ($results as $days) {
                     foreach ($days as $exception) {
                         $kronolith_driver->deleteEvent($exception->id);
                     }
                 }
             }
             // Exceptions. EXDATE represents deleted events, just add the
             // exception, no new event is needed.
             $exdates = $vEvent->getAttributeValues('EXDATE');
             if (is_array($exdates)) {
                 foreach ($exdates as $exdate) {
                     if (is_array($exdate)) {
                         $this->recurrence->addException((int) $exdate['year'], (int) $exdate['month'], (int) $exdate['mday']);
                     }
                 }
             }
         }
     } catch (Horde_Icalendar_Exception $e) {
     }
     // RECURRENCE-ID indicates that this event represents an exception
     try {
         $recurrenceid = $vEvent->getAttribute('RECURRENCE-ID');
         $kronolith_driver = Kronolith::getDriver(null, $this->calendar);
         $originaldt = new Horde_Date($recurrenceid);
         $this->exceptionoriginaldate = $originaldt;
         $this->baseid = $this->uid;
         $this->uid = null;
         try {
             $originalEvent = $kronolith_driver->getByUID($this->baseid);
             $originalEvent->recurrence->addException($originaldt->format('Y'), $originaldt->format('m'), $originaldt->format('d'));
             $originalEvent->save();
         } catch (Horde_Exception_NotFound $e) {
             throw new Kronolith_Exception(_("Unable to locate original event series."));
         }
     } catch (Horde_Icalendar_Exception $e) {
     }
 }
Пример #28
0
 /**
  * Export this memo in iCalendar format.
  *
  * @param array  memo      The memo (hash array) to export
  * @param Horde_Icalendar  A Horde_Icalendar object that acts as container.
  *
  * @return Horde_Icalendar_Vnote  object for this event.
  */
 public function toiCalendar($memo, $calendar)
 {
     global $prefs;
     $vnote = Horde_Icalendar::newComponent('vnote', $calendar);
     $vnote->setAttribute('UID', $memo['uid']);
     $vnote->setAttribute('BODY', $memo['body']);
     $vnote->setAttribute('SUMMARY', $memo['desc']);
     if (!empty($memo['tags'])) {
         $vnote->setAttribute('CATEGORIES', implode(', ', $memo['tags']));
     }
     /* Get the note's history. */
     $history = $GLOBALS['injector']->getInstance('Horde_History');
     $log = $history->getHistory('mnemo:' . $memo['memolist_id'] . ':' . $memo['uid']);
     if ($log) {
         foreach ($log as $entry) {
             switch ($entry['action']) {
                 case 'add':
                     $created = $entry['ts'];
                     break;
                 case 'modify':
                     $modified = $entry['ts'];
                     break;
             }
         }
     }
     if (!empty($created)) {
         $vnote->setAttribute('DCREATED', $created);
     }
     if (!empty($modified)) {
         $vnote->setAttribute('LAST-MODIFIED', $modified);
     }
     return $vnote;
 }
Пример #29
0
 protected function toHash($vcard, $map = array())
 {
     $driver = new Turba_Driver();
     foreach ($map as $field => $config) {
         $driver->map[$field] = $config;
     }
     $ical = new Horde_Icalendar();
     $ical->parsevCalendar($vcard);
     return $driver->toHash($ical->getComponent(0));
 }
Пример #30
0
 /**
  * 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();
     }
 }