Get the value of an attribute.
public getAttribute ( string $name, boolean $params = false ) : mixed | ||
$name | string | The name of the attribute. |
$params | boolean | Return the parameters for this attribute instead of its value. |
Результат | mixed | (string) The value of the attribute. (array) The parameters for the attribute or multiple values for an attribute. |
/** * @requires extension bcmath */ public function testvTodo() { $tnef = Horde_Compress::factory('Tnef'); $mime = Horde_Mime_Part::parseMessage(file_get_contents(__DIR__ . '/fixtures/tnef_task.eml')); try { $tnef_data = $tnef->decompress($mime->getPart(2)->getContents()); } catch (Horde_Mapi_Exception $e) { $this->markTestSkipped('Horde_Mapi is not available'); } catch (Horde_Compress_Exception $e) { var_dump($e); } // 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.")); } $this->assertEquals($iCal->getAttribute('METHOD'), 'REQUEST'); $components = $iCal->getComponents(); if (count($components) == 0) { throw new Horde_Compress_Exception(_("No iCalendar data was found.")); } $vTodo = current($components); $this->assertEquals($vTodo->getAttribute('SUMMARY'), 'Test Task'); $this->assertEquals($vTodo->getAttribute('UID'), 'EDF71E6FA6FB69A79D79FE1D6DCDBBD300000000DFD9B6FB'); $this->assertEquals($vTodo->getAttribute('ATTENDEE'), 'Michael Rubinsky <*****@*****.**>'); $params = $vTodo->getAttribute('ATTENDEE', true); if (!$params) { throw new Horde_Compress_Exception('Could not find expected parameters.'); } $this->assertEquals($params[0]['ROLE'], 'REQ-PARTICIPANT'); $this->assertEquals($vTodo->getAttribute('ORGANIZER'), 'mailto: mike@theupstairsroom.com'); }
/** * Builds a proper AS mail message object. * * @param Horde_Imap_Client_Mailbox $mbox The IMAP mailbox. * @param Horde_Imap_Client_Data_Fetch $data The fetch results. * @param array $options Additional Options: * - truncation: (integer) Truncate the message body to this length. * DEFAULT: No truncation. * - bodyprefs: (array) Bodyprefs, if sent from device. * DEFAULT: none (No body prefs sent or enforced). * - bodypartprefs: (array) Bodypartprefs, if sent from device. * DEFAULT: none (No body part prefs sent or enforced). * - mimesupport: (integer) Indicates if MIME is supported or not. * Possible values: 0 - Not supported 1 - Only S/MIME or * 2 - All MIME. * DEFAULT: 0 (No MIME support) * - protocolversion: (float) The EAS protocol version to support. * DEFAULT: 2.5 * * @return Horde_ActiveSync_Message_Mail The message object suitable for * streaming to the device. */ protected function _buildMailMessage(Horde_Imap_Client_Mailbox $mbox, Horde_Imap_Client_Data_Fetch $data, $options = array()) { $version = empty($options['protocolversion']) ? Horde_ActiveSync::VERSION_TWOFIVE : $options['protocolversion']; $imap_message = new Horde_ActiveSync_Imap_Message($this->_getImapOb(), $mbox, $data); $eas_message = Horde_ActiveSync::messageFactory('Mail'); // Build To: data (POOMMAIL_TO has a max length of 32768). $to = $imap_message->getToAddresses(); $eas_message->to = array_pop($to['to']); foreach ($to['to'] as $to_atom) { if (strlen($eas_message->to) + strlen($to_atom) > 32768) { break; } $eas_message->to .= ',' . $to_atom; } $eas_message->displayto = implode(';', $to['displayto']); if (empty($eas_message->displayto)) { $eas_message->displayto = $eas_message->to; } // Ensure we don't send broken UTF8 data to the client. It makes clients // angry. And we don't like angry clients. $hdr_charset = $imap_message->getStructure()->getHeaderCharset(); // Fill in other header data try { $eas_message->from = $imap_message->getFromAddress(); } catch (Horde_ActiveSync_Exception $e) { $this->_logger->err($e->getMessage()); } try { $eas_message->cc = $imap_message->getCc(); } catch (Horde_ActiveSync_Exception $e) { $this->_logger->err($e->getMessage()); } try { $eas_message->reply_to = $imap_message->getReplyTo(); } catch (Horde_ActiveSync_Exception $e) { $this->_logger->err($e->getMessage()); } $eas_message->subject = Horde_ActiveSync_Utils::ensureUtf8($imap_message->getSubject(), $hdr_charset); $eas_message->threadtopic = $eas_message->subject; $eas_message->datereceived = $imap_message->getDate(); $eas_message->read = $imap_message->getFlag(Horde_Imap_Client::FLAG_SEEN); // Default to IPM.Note - may change below depending on message content. $eas_message->messageclass = 'IPM.Note'; // Codepage id. MS recommends to always set to UTF-8 when possible. // See http://msdn.microsoft.com/en-us/library/windows/desktop/dd317756%28v=vs.85%29.aspx $eas_message->cpid = Horde_ActiveSync_Message_Mail::INTERNET_CPID_UTF8; // Message importance. First try X-Priority, then Importance since // Outlook sends the later. if ($priority = $imap_message->getHeaders()->getValue('X-priority')) { $priority = preg_replace('/\\D+/', '', $priority); } else { $priority = $imap_message->getHeaders()->getValue('Importance'); } $eas_message->importance = $this->_getEASImportance($priority); // Get the body data. $mbd = $imap_message->getMessageBodyDataObject($options); if ($version == Horde_ActiveSync::VERSION_TWOFIVE) { $eas_message->body = $mbd->plain['body']->stream; $eas_message->bodysize = $mbd->plain['body']->length(true); $eas_message->bodytruncated = $mbd->plain['truncated']; $eas_message->attachments = $imap_message->getAttachments($version); } else { // Get the message body and determine original type. if ($mbd->html) { $eas_message->airsyncbasenativebodytype = Horde_ActiveSync::BODYPREF_TYPE_HTML; } else { $eas_message->airsyncbasenativebodytype = Horde_ActiveSync::BODYPREF_TYPE_PLAIN; } $airsync_body = Horde_ActiveSync::messageFactory('AirSyncBaseBody'); $body_type_pref = $mbd->getBodyTypePreference(); if ($body_type_pref == Horde_ActiveSync::BODYPREF_TYPE_MIME) { $this->_logger->info(sprintf('[%s] Sending MIME Message.', $this->_procid)); // ActiveSync *REQUIRES* all data sent to be in UTF-8, so we // must convert the body parts to UTF-8. Unfortunately if the // email is signed (or encrypted for that matter) we can't // alter the data in anyway or the signature will not be // verified, so we fetch the entire message and hope for the best. if (!$imap_message->isSigned() && !$imap_message->isEncrypted()) { $mime = new Horde_Mime_Part(); if ($mbd->plain) { $plain_mime = new Horde_Mime_Part(); $plain_mime->setType('text/plain'); $plain_mime->setContents($mbd->plain['body']->stream, array('usestream' => true)); $plain_mime->setCharset('UTF-8'); } if ($mbd->html) { $html_mime = new Horde_Mime_Part(); $html_mime->setType('text/html'); $html_mime->setContents($mbd->html['body']->stream, array('usestream' => true)); $html_mime->setCharset('UTF-8'); } // Sanity check the mime type if (!$mbd->html && !empty($plain_mime)) { $mime = $plain_mime; } elseif (!$mbd->plain && !empty($html_mime)) { $mime = $html_mime; } elseif (!empty($plain_mime) && !empty($html_mime)) { $mime->setType('multipart/alternative'); $mime->addPart($plain_mime); $mime->addPart($html_mime); } $html_mime = null; $plain_mime = null; // If we have attachments, create a multipart/mixed wrapper. if ($imap_message->hasAttachments()) { $base = new Horde_Mime_Part(); $base->setType('multipart/mixed'); $base->addPart($mime); $atc = $imap_message->getAttachmentsMimeParts(); foreach ($atc as $atc_part) { $base->addPart($atc_part); } $eas_message->airsyncbaseattachments = $imap_message->getAttachments($version); } else { $base = $mime; } $mime = null; // Populate the EAS body structure with the MIME data, but // remove the Content-Type and Content-Transfer-Encoding // headers since we are building this ourselves. $headers = $imap_message->getHeaders(); $headers->removeHeader('Content-Type'); $headers->removeHeader('Content-Transfer-Encoding'); $airsync_body->data = $base->toString(array('headers' => $headers, 'stream' => true)); $airsync_body->estimateddatasize = $base->getBytes(); } else { // Signed/Encrypted message - can't mess with it at all. $raw = new Horde_ActiveSync_Rfc822($imap_message->getFullMsg(true), false); $airsync_body->estimateddatasize = $raw->getBytes(); $airsync_body->data = $raw->getString(); $eas_message->airsyncbaseattachments = $imap_message->getAttachments($version); } $airsync_body->type = Horde_ActiveSync::BODYPREF_TYPE_MIME; // MIME Truncation // @todo Remove this sanity-check hack in 3.0. This is needed // since truncationsize incorrectly defaulted to a // MIME_TRUNCATION constant and could be cached in the sync-cache. $ts = !empty($options['bodyprefs'][Horde_ActiveSync::BODYPREF_TYPE_MIME]['truncationsize']) ? $options['bodyprefs'][Horde_ActiveSync::BODYPREF_TYPE_MIME]['truncationsize'] : false; $mime_truncation = !empty($ts) && $ts > 9 ? $ts : (!empty($options['truncation']) && $options['truncation'] > 9 ? $options['truncation'] : false); $this->_logger->info(sprintf('[%s] Checking MIMETRUNCATION: %s, ServerData: %s', $this->_procid, $mime_truncation, $airsync_body->estimateddatasize)); if (!empty($mime_truncation) && $airsync_body->estimateddatasize > $mime_truncation) { ftruncate($airsync_body->data, $mime_truncation); $airsync_body->truncated = '1'; } else { $airsync_body->truncated = '0'; } $eas_message->airsyncbasebody = $airsync_body; } elseif ($body_type_pref == Horde_ActiveSync::BODYPREF_TYPE_HTML) { // Sending non MIME encoded HTML message text. $eas_message->airsyncbasebody = $this->_buildHtmlPart($mbd, $airsync_body); $eas_message->airsyncbaseattachments = $imap_message->getAttachments($version); } elseif ($body_type_pref == Horde_ActiveSync::BODYPREF_TYPE_PLAIN) { // Non MIME encoded plaintext $this->_logger->info(sprintf('[%s] Sending PLAINTEXT Message.', $this->_procid)); if (!empty($mbd->plain['size'])) { $airsync_body->estimateddatasize = $mbd->plain['size']; $airsync_body->truncated = $mbd->plain['truncated']; $airsync_body->data = $mbd->plain['body']->stream; $airsync_body->type = Horde_ActiveSync::BODYPREF_TYPE_PLAIN; $eas_message->airsyncbasebody = $airsync_body; } $eas_message->airsyncbaseattachments = $imap_message->getAttachments($version); } // It's legal to have both a BODY and a BODYPART, so we must also // check for that. if ($version > Horde_ActiveSync::VERSION_FOURTEEN && !empty($options['bodypartprefs'])) { $body_part = Horde_ActiveSync::messageFactory('AirSyncBaseBodypart'); $eas_message->airsyncbasebodypart = $this->_buildBodyPart($mbd, $options, $body_part); } if ($version > Horde_ActiveSync::VERSION_TWELVEONE) { $flags = array(); $msgFlags = $this->_getMsgFlags(); foreach ($imap_message->getFlags() as $flag) { if (!empty($msgFlags[Horde_String::lower($flag)])) { $flags[] = $msgFlags[Horde_String::lower($flag)]; } } $eas_message->categories = $flags; } } // Body Preview? Note that this is different from BodyPart's preview if ($version >= Horde_ActiveSync::VERSION_FOURTEEN && !empty($options['bodyprefs']['preview'])) { $mbd->plain['body']->rewind(); $eas_message->airsyncbasebody->preview = $mbd->plain['body']->substring(0, $options['bodyprefs']['preview']); } $mbd = null; // Check for special message types. if ($imap_message->isEncrypted()) { $eas_message->messageclass = 'IPM.Note.SMIME'; } elseif ($imap_message->isSigned()) { $eas_message->messageclass = 'IPM.Note.SMIME.MultipartSigned'; } $part = $imap_message->getStructure(); if ($part->getType() == 'multipart/report') { $ids = array_keys($imap_message->contentTypeMap()); reset($ids); $part1_id = next($ids); $part2_id = Horde_Mime::mimeIdArithmetic($part1_id, 'next'); $lines = explode(chr(13), $imap_message->getBodyPart($part2_id, array('decode' => true))); switch ($part->getContentTypeParameter('report-type')) { case 'delivery-status': foreach ($lines as $line) { if (strpos(trim($line), 'Action:') === 0) { switch (trim(substr(trim($line), 7))) { case 'failed': $eas_message->messageclass = 'REPORT.IPM.NOTE.NDR'; break 2; case 'delayed': $eas_message->messageclass = 'REPORT.IPM.NOTE.DELAYED'; break 2; case 'delivered': $eas_message->messageclass = 'REPORT.IPM.NOTE.DR'; break 2; } } } break; case 'disposition-notification': foreach ($lines as $line) { if (strpos(trim($line), 'Disposition:') === 0) { if (strpos($line, 'displayed') !== false) { $eas_message->messageclass = 'REPORT.IPM.NOTE.IPNRN'; } elseif (strpos($line, 'deleted') !== false) { $eas_message->messageclass = 'REPORT.IPM.NOTE.IPNNRN'; } break; } } } } $part = null; // Check for meeting requests and POOMMAIL_FLAG data if ($version >= Horde_ActiveSync::VERSION_TWELVE) { $eas_message->contentclass = 'urn:content-classes:message'; if ($mime_part = $imap_message->hasiCalendar()) { $data = Horde_ActiveSync_Utils::ensureUtf8($mime_part->getContents(), $mime_part->getCharset()); $vCal = new Horde_Icalendar(); if ($vCal->parsevCalendar($data, 'VCALENDAR', $mime_part->getCharset())) { $classes = $vCal->getComponentClasses(); } else { $classes = array(); } if (!empty($classes['horde_icalendar_vevent'])) { try { $method = $vCal->getAttribute('METHOD'); $eas_message->contentclass = 'urn:content-classes:calendarmessage'; } catch (Horde_Icalendar_Exception $e) { } switch ($method) { case 'REQUEST': case 'PUBLISH': $eas_message->messageclass = 'IPM.Schedule.Meeting.Request'; $mtg = Horde_ActiveSync::messageFactory('MeetingRequest'); $mtg->fromvEvent($vCal); $eas_message->meetingrequest = $mtg; break; case 'REPLY': try { $reply_status = $this->_getiTipStatus($vCal); switch ($reply_status) { case 'ACCEPTED': $eas_message->messageclass = 'IPM.Schedule.Meeting.Resp.Pos'; break; case 'DECLINED': $eas_message->messageclass = 'IPM.Schedule.Meeting.Resp.Neg'; break; case 'TENTATIVE': $eas_message->messageclass = 'IPM.Schedule.Meeting.Resp.Tent'; } $mtg = Horde_ActiveSync::messageFactory('MeetingRequest'); $mtg->fromvEvent($vCal); $eas_message->meetingrequest = $mtg; } catch (Horde_ActiveSync_Exception $e) { $this->_logger->err($e->getMessage()); } } } } if ($imap_message->getFlag(Horde_Imap_Client::FLAG_FLAGGED)) { $poommail_flag = Horde_ActiveSync::messageFactory('Flag'); $poommail_flag->subject = $imap_message->getSubject(); $poommail_flag->flagstatus = Horde_ActiveSync_Message_Flag::FLAG_STATUS_ACTIVE; $poommail_flag->flagtype = Horde_Imap_Client::FLAG_FLAGGED; $eas_message->flag = $poommail_flag; } } if ($version >= Horde_ActiveSync::VERSION_FOURTEEN) { $eas_message->messageid = $imap_message->getHeaders()->getValue('Message-ID'); $eas_message->forwarded = $imap_message->getFlag(Horde_Imap_Client::FLAG_FORWARDED); $eas_message->answered = $imap_message->getFlag(Horde_Imap_Client::FLAG_ANSWERED); } $imap_message = null; return $eas_message; }
/** * 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) { } }
/** * Return a reference to a new component. * * @param string $type The type of component to return * @param Horde_Icalendar $container A container that this component * will be associated with. * * @return object Reference to a Horde_Icalendar_* object as specified. */ public static function newComponent($type, $container) { $type = Horde_String::lower($type); $class = __CLASS__ . '_' . Horde_String::ucfirst($type); if (class_exists($class)) { $component = new $class(); if ($container !== false) { $component->_container = $container; // Use version of container, not default set by component // constructor. $component->setVersion($container->getAttribute('VERSION')); } } else { // Should return an dummy x-unknown type class here. $component = false; } return $component; }
/** * 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')); }
/** * 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)); if (!($mime_part = $contents->getMimePart($vars->mime_id))) { throw new IMP_Exception(_("Cannot retrieve calendar data from message.")); } if ($vars->ctype) { $mime_part = clone $mime_part; $mime_part->setType($vars->ctype); } if (!$vCal->parsevCalendar($mime_part->getContents(), 'VCALENDAR', $mime_part->getCharset())) { throw new IMP_Exception(_("The calendar data is invalid")); } $components = $vCal->getComponents(); $v1 = $vCal->getAttribute('VERSION') == '1.0'; } 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]->getAttributeSingle('UID'); $recurrenceId = null; $range = null; try { // This is a cancellation of a recurring event instance. $recurrenceId = $components[$key]->getAttributeSingle('RECURRENCE-ID'); $atts = $components[$key]->getAttribute('RECURRENCE-ID', true); 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. // vTodo reply. switch ($components[$key]->getType()) { case 'vEvent': if ($registry->hasMethod('calendar/updateAttendee')) { try { if ($tmp = $contents->getHeader()->getHeader('from')) { $registry->call('calendar/updateAttendee', array($components[$key], $tmp->getAddressList(true)->first()->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 'vTodo': if ($registry->hasMethod('tasks/updateAttendee')) { try { if ($tmp = $contents->getHeader()->getHeader('from')) { $registry->call('tasks/updateAttendee', array($components[$key], $tmp->getAddressList(true)->first()->bare_address)); $notification->push(_("Respondent Status Updated."), 'horde.success'); $result = true; } } catch (Horde_Exception $e) { $notification->push(sprintf(_("There was an error updating the task: %s"), $e->getMessage()), 'horde.error'); } } else { $notification->push(_("This action is not supported."), 'horde.warning'); } break; } break; case 'import': case 'accept-import': // vFreebusy reply. // vFreebusy publish. // vEvent request. // vEvent publish. // vTodo publish. // vJournal publish. switch ($components[$key]->getType()) { case 'vEvent': // If we have accepted and are importing, update the // user's attendance status in the vCal so it will be // reflected when it is imported. if ($action == 'accept-import') { try { $a = $components[$key]->getAttribute('ATTENDEE'); if (!is_array($a)) { $a = array($a); } $a_params = $components[$key]->getAttribute('ATTENDEE', true); foreach ($a as $a_key => $attendee) { $attendee_email = preg_replace('/mailto:/i', '', $attendee); $identity = $injector->getInstance('IMP_Identity'); if (!is_null($id = $identity->getMatchingIdentity($attendee_email))) { $components[$key]->removeAttribute('ATTENDEE'); if ($v1) { $a_params[$a_key]['STATUS'] = 'ACCEPTED'; } else { $a_params[$a_key]['PARTSTAT'] = 'ACCEPTED'; } foreach ($a as $ai_key => $i_attendee) { $components[$key]->setAttribute('ATTENDEE', $i_attendee, $a_params[$ai_key]); } break; } } } catch (Horde_Icalendar_Exception $e) { $notification->push(sprintf(_("There was an error updating attendee status: %s"), $e->getMessage()), 'horde.error'); } } // Handle the import, and check for exceptions. $result = $this->_handlevEvent($key, $components, $mime_part); foreach ($components as $k => $component) { try { if ($component->getType() == 'vEvent' && $component->getAttribute('RECURRENCE-ID')) { $uid = $component->getAttributeSingle('UID'); if ($uid == $components[$key]->getAttributeSingle('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' || $components[$key]->getType() == 'vTodo')) { $vEvent = $components[$key]; try { $resource = new Horde_Itip_Resource_Identity($injector->getInstance('IMP_Identity'), $vEvent->getAttribute('ATTENDEE'), $vars->identity); } catch (Horde_Icalendar_Exception $e) { throw new Horde_Itip_Exception('No ATTENDEE data, unable to reply.'); } 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 { if ($vEvent->getType() == 'vEvent') { // Send the reply. Horde_Itip::factory($vEvent, $resource)->sendMultiPartResponse($type, new Horde_Core_Itip_Response_Options_Horde('UTF-8', array()), $injector->getInstance('IMP_Mail')); } elseif ($vEvent->getType() == 'vTodo') { Horde_Itip::vTodoFactory($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->getAttributeSingle('ORGANIZER')); } catch (Horde_Icalendar_Exception $e) { break; } $organizerEmail = $organizer['path']; $organizer = $vFb->getAttributeSingle('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->getAttributeSingle('DTSTART'); } catch (Horde_Icalendar_Exception $e) { $startStamp = time(); } try { $endStamp = $vFb->getAttributeSingle('DTEND'); } catch (Horde_Icalendar_Exception $e) { } if (!$endStamp) { try { $duration = $vFb->getAttributeSingle('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(); $vCal = new Horde_Icalendar(); $vCal->setAttribute('PRODID', '-//The Horde Project//' . strval(Horde_Mime_Headers_UserAgent::create()) . '//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[] = $body; $mime[] = $ics; // Build the reply headers. $msg_headers = new Horde_Mime_Headers(); $msg_headers->addHeaderOb(Horde_Core_Mime_Headers_Received::createHordeHop()); $msg_headers->addHeaderOb(Horde_Mime_Headers_MessageId::create()); $msg_headers->addHeaderOb(Horde_Mime_Headers_Date::create()); $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; }
/** * Parses the various exception related fields. Only deal with the EXDATE * field here. * * @param Horde_Icalendar $vEvent The vEvent part. */ 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); } // 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) { } }
/** * 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); } // 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 { $this->recurrenceid = $vEvent->getAttribute('RECURRENCE-ID'); $originaldt = new Horde_Date($this->recurrenceid); $this->exceptionoriginaldate = $originaldt; $this->baseid = $this->uid; $this->uid = null; try { $originalEvent = $this->getDriver()->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) { } }