From: Gunnar Wrobel Date: Wed, 4 Aug 2010 13:58:44 +0000 (+0200) Subject: Start new Itip library. X-Git-Url: https://git.internetallee.de/?a=commitdiff_plain;h=6c5cb5c48a6834f6381c02f37ef2da57ebf72dea;p=horde.git Start new Itip library. --- diff --git a/framework/Itip/TODO b/framework/Itip/TODO new file mode 100644 index 000000000..e60de1ac6 --- /dev/null +++ b/framework/Itip/TODO @@ -0,0 +1,3 @@ + + - Merge with Horde Imp + - Complete unit testing diff --git a/framework/Itip/lib/Horde/Itip.php b/framework/Itip/lib/Horde/Itip.php new file mode 100644 index 000000000..2e13a4d58 --- /dev/null +++ b/framework/Itip/lib/Horde/Itip.php @@ -0,0 +1,141 @@ + + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Itip + */ + +/** + * Handles iTip invitation requests/responses. + * + * Copyright 2010 Klarälvdalens Datakonsult AB + * + * See the enclosed file COPYING for license information (LGPL). If you did not + * receive this file, see + * http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. + * + * @category Horde + * @package Itip + * @author Gunnar Wrobel + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Itip + */ +class Horde_Itip +{ + /** + * The iTip response. + * + * @var Horde_Itip_Response + */ + private $_response; + + /** + * Constructor. + * + * @param Horde_Itip_Response $response The iTip response. + */ + public function __construct( + Horde_Itip_Response $response + ) { + $this->_response = $response; + } + + /** + * Return the response as an iCalendar vEvent object. + * + * @param Horde_Itip_Response_Type $type The response type. + * + * @return Horde_iCalendar_vevent The response object. + */ + public function getVeventResponse( + Horde_Itip_Response_Type $type + ) { + return $this->_response->getVevent( + $type, false + ); + } + + /** + * Return the response as an iCalendar object. + * + * @param Horde_Itip_Response_Type $type The response type. + * @param string $product_id The ID that should be set as + * the iCalendar product id. + * + * @return Horde_iCalendar The response object. + */ + public function getIcalendarResponse( + Horde_Itip_Response_Type $type, + $product_id + ) { + return $this->_response->getIcalendar( + $type, $product_id + ); + } + + /** + * Return the response as a MIME message. + * + * @param Horde_Itip_Response_Type $type The response type. + * @param string $product_id The ID that should be set + * as the iCalendar product + * id. + * @param string $subject_comment An optional comment on + * the subject line. + * + * @return array A list of two object: The mime headers and the mime + * message. + */ + public function getMessageResponse( + Horde_Itip_Response_Type $type, + $product_id, + $subject_comment = null + ) { + return $this->_response->getMessage( + $type, $product_id, $subject_comment + ); + } + + /** + * Factory for generating a response object for an iCalendar invitation. + * + * @param Horde_iCalendar_vevent $vevent The iCalendar request. + * @param Horde_Itip_Resource $resource The invited resource. + * + * @return Horde_Itip_Response The prepared response. + */ + static public function prepareResponse( + Horde_iCalendar_vevent $vevent, + Horde_Itip_Resource $resource + ) { + return new Horde_Itip_Response( + new Horde_Itip_Event_Vevent( + $vevent + ), + $resource + ); + } + + /** + * Factory for generating an iTip handler for an iCalendar invitation. + * + * @param Horde_iCalendar_vevent $vevent The iCalendar request. + * @param Horde_Itip_Resource $resource The invited resource. + * + * @return Horde_Itip The iTip handler. + */ + static public function factory( + Horde_iCalendar_vevent $vevent, + Horde_Itip_Resource $resource + ) { + return new Horde_Itip( + self::prepareResponse($vevent, $resource) + ); + } +} \ No newline at end of file diff --git a/framework/Itip/lib/Horde/Itip/Event.php b/framework/Itip/lib/Horde/Itip/Event.php new file mode 100644 index 000000000..c11b61d80 --- /dev/null +++ b/framework/Itip/lib/Horde/Itip/Event.php @@ -0,0 +1,103 @@ + + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Itip + */ + +/** + * Defines the event interface required for iTip-Handling / resource booking. + * + * Copyright 2010 Klarälvdalens Datakonsult AB + * + * See the enclosed file COPYING for license information (LGPL). If you did not + * receive this file, see + * http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. + * + * @category Horde + * @package Itip + * @author Gunnar Wrobel + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Itip + */ +interface Horde_Itip_Event +{ + /** + * Returns the event as vEvent. + * + * @return Horde_iCalendar_vevent The wrapped event. + */ + public function getVevent(); + + /** + * Return the method of the iTip request. + * + * @return string The method of the request. + */ + public function getMethod(); + + /** + * Return the uid of the iTip event. + * + * @return string The uid of the event. + */ + public function getUid(); + + /** + * Return the summary for the event. + * + * @return string The summary. + */ + public function getSummary(); + + /** + * Return the start of the iTip event. + * + * @return string The start of the event. + */ + public function getStart(); + + /** + * Return the end of the iTip event. + * + * @return string The end of the event. + */ + public function getEnd(); + + /** + * Return the organizer of the iTip event. + * + * @return string The organizer of the event. + */ + public function getOrganizer(); + + /** + * Copy the details from an event into this one. + * + * @param Horde_Itip_Event $event The event to copy from. + * + * @return NULL + */ + public function copyEventInto(Horde_Itip_Event $event); + + /** + * Set the attendee parameters. + * + * @param string $attendee The mail address of the attendee. + * @param string $common_name Common name of the attendee. + * @param string $status Attendee status (ACCPETED, DECLINED, TENTATIVE) + * + * @return NULL + */ + public function setAttendee($attendee, $common_name, $status); + + public function getKolabObject(); + + public function setAccepted($resource); +} \ No newline at end of file diff --git a/framework/Itip/lib/Horde/Itip/Event/Vevent.php b/framework/Itip/lib/Horde/Itip/Event/Vevent.php new file mode 100644 index 000000000..f5741b081 --- /dev/null +++ b/framework/Itip/lib/Horde/Itip/Event/Vevent.php @@ -0,0 +1,615 @@ + + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Server + */ + +/** + * A wrapper for vEvent iCalender data. + * + * Copyright 2010 Klarälvdalens Datakonsult AB + * + * See the enclosed file COPYING for license information (LGPL). If you did not + * receive this file, see + * http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. + * + * @category Kolab + * @package Kolab_Filter + * @author Gunnar Wrobel + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Server + */ +class Horde_Itip_Event_Vevent +implements Horde_Itip_Event +{ + /** + * The wrapped vEvent. + * + * @var Horde_iCalendar_vevent + */ + private $_vevent; + + /** + * Constructor. + * + * @param Horde_iCalendar_vevent $vevent The iCalendar object that will be + * wrapped by this instance. + */ + public function __construct(Horde_iCalendar_vevent $vevent) + { + $this->_vevent = $vevent; + } + + /** + * Returns the wrapped vEvent. + * + * @return Horde_iCalendar_vevent The wrapped event. + */ + public function getVevent() + { + return $this->_vevent; + } + + /** + * Return the method of the iTip request. + * + * @return string The method of the request. + */ + public function getMethod() + { + return $this->_vevent->getAttributeDefault('METHOD', 'REQUEST'); + } + + /** + * Return the uid of the iTip event. + * + * @return string The uid of the event. + */ + public function getUid() + { + return $this->_vevent->getAttributeDefault('UID', ''); + } + + /** + * Return the summary for the event. + * + * @return string|PEAR_Error The summary. + */ + public function getSummary() + { + return $this->_vevent->getAttributeDefault('SUMMARY', _("No summary available")); + } + + /** + * Return the start of the iTip event. + * + * @return string The start of the event. + */ + public function getStart() + { + return $this->_vevent->getAttributeDefault('DTSTART', 0); + } + + /** + * Return the end of the iTip event. + * + * @return string The end of the event. + */ + public function getEnd() + { + return $this->_vevent->getAttributeDefault('DTEND', 0); + } + + /** + * Return the organizer of the iTip event. + * + * @return string The organizer of the event. + */ + public function getOrganizer() + { + return preg_replace('/^mailto:\s*/i', '', $this->_vevent->getAttributeDefault('ORGANIZER', '')); + } + + /** + * Copy the details from an event into this one. + * + * @param Horde_Itip_Event $event The event to copy from. + * + * @return NULL + */ + public function copyEventInto(Horde_Itip_Event $event) + { + $this->copyUid($event); + $this->copySummary($event); + $this->copyDescription($event); + $this->copyStart($event); + $this->copyEndOrDuration($event); + $this->copySequence($event); + $this->copyLocation($event); + $this->copyOrganizer($event); + } + + /** + * Set the attendee parameters. + * + * @param string $attendee The mail address of the attendee. + * @param string $common_name Common name of the attendee. + * @param string $status Attendee status (ACCPETED, DECLINED, TENTATIVE) + * + * @return NULL + */ + public function setAttendee($attendee, $common_name, $status) + { + $this->_vevent->setAttribute( + 'ATTENDEE', + 'MAILTO:' . $attendee, + array( + 'CN' => $common_name, + 'PARTSTAT' => $status + ) + ); + } + + public function getKolabObject() + { + $object = array(); + $object['uid'] = $this->getUid(); + + $org_params = $this->_vevent->getAttribute('ORGANIZER', true); + if (!is_a( $org_params, 'PEAR_Error')) { + if (!empty($org_params[0]['CN'])) { + $object['organizer']['display-name'] = $org_params[0]['CN']; + } + $orgemail = $this->_vevent->getAttributeDefault('ORGANIZER', ''); + if (preg_match('/mailto:(.*)/i', $orgemail, $regs )) { + $orgemail = $regs[1]; + } + $object['organizer']['smtp-address'] = $orgemail; + } + $object['summary'] = $this->_vevent->getAttributeDefault('SUMMARY', ''); + $object['location'] = $this->_vevent->getAttributeDefault('LOCATION', ''); + $object['body'] = $this->_vevent->getAttributeDefault('DESCRIPTION', ''); + $dtend = $this->_vevent->getAttributeDefault('DTEND', ''); + if (is_array($dtend)) { + $object['_is_all_day'] = true; + } + $start = new Horde_Kolab_Resource_Epoch($this->getStart()); + $object['start-date'] = $start->getEpoch(); + $end = new Horde_Kolab_Resource_Epoch($dtend); + $object['end-date'] = $end->getEpoch(); + + $attendees = $this->_vevent->getAttribute('ATTENDEE'); + if (!is_a( $attendees, 'PEAR_Error')) { + $attendees_params = $this->_vevent->getAttribute('ATTENDEE', true); + if (!is_array($attendees)) { + $attendees = array($attendees); + } + if (!is_array($attendees_params)) { + $attendees_params = array($attendees_params); + } + + $object['attendee'] = array(); + for ($i = 0; $i < count($attendees); $i++) { + $attendee = array(); + if (isset($attendees_params[$i]['CN'])) { + $attendee['display-name'] = $attendees_params[$i]['CN']; + } + + $attendeeemail = $attendees[$i]; + if (preg_match('/mailto:(.*)/i', $attendeeemail, $regs)) { + $attendeeemail = $regs[1]; + } + $attendee['smtp-address'] = $attendeeemail; + + if (!isset($attendees_params[$i]['RSVP']) + || $attendees_params[$i]['RSVP'] == 'FALSE') { + $attendee['request-response'] = false; + } else { + $attendee['request-response'] = true; + } + + if (isset($attendees_params[$i]['ROLE'])) { + $attendee['role'] = $attendees_params[$i]['ROLE']; + } + + if (isset($attendees_params[$i]['PARTSTAT'])) { + $status = strtolower($attendees_params[$i]['PARTSTAT']); + switch ($status) { + case 'needs-action': + case 'delegated': + $attendee['status'] = 'none'; + break; + default: + $attendee['status'] = $status; + break; + } + } + + $object['attendee'][] = $attendee; + } + } + + // Alarm + $valarm = $this->_vevent->findComponent('VALARM'); + if ($valarm) { + $trigger = $valarm->getAttribute('TRIGGER'); + if (!is_a($trigger, 'PEAR_Error')) { + $p = $valarm->getAttribute('TRIGGER', true); + if ($trigger < 0) { + // All OK, enter the alarm into the XML + // NOTE: The Kolab XML format seems underspecified + // wrt. alarms currently... + $object['alarm'] = -$trigger / 60; + } + } + } + + // Recurrence + $rrule_str = $this->_vevent->getAttribute('RRULE'); + if (!is_a($rrule_str, 'PEAR_Error')) { + require_once 'Horde/Date/Recurrence.php'; + $recurrence = new Horde_Date_Recurrence(time()); + $recurrence->fromRRule20($rrule_str); + $object['recurrence'] = $recurrence->toHash(); + } + + return $object; + } + + public function setAccepted($resource) + { + // Update our status within the iTip request and send the reply + $this->_vevent->setAttribute('STATUS', 'CONFIRMED', array(), false); + $attendees = $this->_vevent->getAttribute('ATTENDEE'); + if (!is_array($attendees)) { + $attendees = array($attendees); + } + $attparams = $this->_vevent->getAttribute('ATTENDEE', true); + foreach ($attendees as $i => $attendee) { + $attendee = preg_replace('/^mailto:\s*/i', '', $attendee); + if ($attendee != $resource) { + continue; + } + + $attparams[$i]['PARTSTAT'] = 'ACCEPTED'; + if (array_key_exists('RSVP', $attparams[$i])) { + unset($attparams[$i]['RSVP']); + } + } + + // Re-add all the attendees to the event, using our updates status info + $firstatt = array_pop($attendees); + $firstattparams = array_pop($attparams); + $this->_vevent->setAttribute('ATTENDEE', $firstatt, $firstattparams, false); + foreach ($attendees as $i => $attendee) { + $this->_vevent->setAttribute('ATTENDEE', $attendee, $attparams[$i]); + } + } + + /** + * Set the uid of the iTip event. + * + * @param string $uid The uid of the event. + * + * @return NULL + */ + private function setUid($uid) + { + $this->_vevent->setAttribute('UID', $uid); + } + + /** + * Copy the uid from the request into the provided iTip instance. + * + * @return NULL + */ + private function copyUid(Horde_Itip_Event $itip) + { + $itip->setUid($this->getUid()); + } + + /** + * Set the summary for the event. + * + * @param string $summary The summary. + * + * @return NULL + */ + private function setSummary($summary) + { + $this->_vevent->setAttribute('SUMMARY', $summary); + } + + /** + * Copy the summary from the request into the provided iTip instance. + * + * @return NULL + */ + private function copySummary(Horde_Itip_Event $itip) + { + $itip->setSummary($this->getSummary()); + } + + /** + * Does the event have a description? + * + * @return boolean True if it has a description, false otherwise. + */ + private function hasDescription() + { + return !($this->_vevent->getAttribute('DESCRIPTION') instanceOf PEAR_Error); + } + + /** + * Return the description for the event. + * + * @return string|PEAR_Error The description. + */ + private function getDescription() + { + return $this->_vevent->getAttribute('DESCRIPTION'); + } + + /** + * Set the description for the event. + * + * @param string $description The description. + * + * @return NULL + */ + private function setDescription($description) + { + $this->_vevent->setAttribute('DESCRIPTION', $description); + } + + /** + * Copy the description from the request into the provided iTip instance. + * + * @return NULL + */ + private function copyDescription(Horde_Itip_Event $itip) + { + if ($this->hasDescription()) { + $itip->setDescription($this->getDescription()); + } + } + + /** + * Return the start parameters of the iTip event. + * + * @return array The start parameters of the event. + */ + public function getStartParameters() + { + return array_pop($this->_vevent->getAttribute('DTSTART', true)); + } + + /** + * Set the start of the iTip event. + * + * @param string $start The start of the event. + * @param array $parameters Additional parameters. + * + * @return NULL + */ + private function setStart($start, $parameters) + { + $this->_vevent->setAttribute('DTSTART', $start, $parameters); + } + + /** + * Copy the start time from the request into the provided iTip instance. + * + * @return NULL + */ + private function copyStart(Horde_Itip_Event $itip) + { + $itip->setStart($this->getStart(), $this->getStartParameters()); + } + + /** + * Does the event have an end? + * + * @return boolean True if it has an end, false otherwise. + */ + private function hasEnd() + { + return !($this->_vevent->getAttribute('DTEND') instanceOf PEAR_Error); + } + + /** + * Return the end parameters of the iTip event. + * + * @return array The end parameters of the event. + */ + private function getEndParameters() + { + return array_pop($this->_vevent->getAttribute('DTEND', true)); + } + + /** + * Set the end of the iTip event. + * + * @param string $end The end of the event. + * @param array $parameters Additional parameters. + * + * @return NULL + */ + private function setEnd($end, $parameters) + { + $this->_vevent->setAttribute('DTEND', $end, $parameters); + } + + /** + * Return the duration for the event. + * + * @return string|PEAR_Error The duration of the event. + */ + private function getDuration() + { + return $this->_vevent->getAttribute('DURATION'); + } + + /** + * Return the duration parameters of the iTip event. + * + * @return array The duration parameters of the event. + */ + private function getDurationParameters() + { + return array_pop($this->_vevent->getAttribute('DURATION', true)); + } + + /** + * Set the duration of the iTip event. + * + * @param string $duration The duration of the event. + * @param array $parameters Additional parameters. + * + * @return NULL + */ + private function setDuration($duration, $parameters) + { + $this->_vevent->setAttribute('DURATION', $duration, $parameters); + } + + /** + * Copy the end time or event duration from the request into the provided + * iTip instance. + * + * @return NULL + */ + private function copyEndOrDuration(Horde_Itip_Event $itip) + { + if ($this->hasEnd()) { + $itip->setEnd($this->getEnd(), $this->getEndParameters()); + } else { + $itip->setDuration($this->getDuration(), $this->getDurationParameters()); + } + } + + /** + * Return the sequence for the event. + * + * @return string|PEAR_Error The sequence. + */ + private function getSequence() + { + return $this->_vevent->getAttributeDefault('SEQUENCE', 0); + } + + /** + * Set the sequence for the event. + * + * @param string $sequence The sequence. + * + * @return NULL + */ + private function setSequence($sequence) + { + $this->_vevent->setAttribute('SEQUENCE', $sequence); + } + /** + * Copy the sequence from the request into the provided iTip instance. + * + * @return NULL + */ + private function copySequence(Horde_Itip_Event $itip) + { + $itip->setSequence($this->getSequence()); + } + + /** + * Does the event have a location? + * + * @return boolean True if it has a location, false otherwise. + */ + private function hasLocation() + { + return !($this->_vevent->getAttribute('LOCATION') instanceOf PEAR_Error); + } + + /** + * Return the location for the event. + * + * @return string|PEAR_Error The location. + */ + private function getLocation() + { + return $this->_vevent->getAttribute('LOCATION'); + } + + /** + * Set the location for the event. + * + * @param string $location The location. + * + * @return NULL + */ + private function setLocation($location) + { + $this->_vevent->setAttribute('LOCATION', $location); + } + + /** + * Copy the location from the request into the provided iTip instance. + * + * @return NULL + */ + private function copyLocation(Horde_Itip_Event $itip) + { + if ($this->hasLocation()) { + $itip->setLocation($this->getLocation()); + } + } + + /** + * Return the organizer for the event. + * + * @return string|PEAR_Error The organizer of the event. + */ + private function getRawOrganizer() + { + return $this->_vevent->getAttribute('ORGANIZER'); + } + + /** + * Return the organizer parameters of the iTip event. + * + * @return array The organizer parameters of the event. + */ + private function getOrganizerParameters() + { + return array_pop($this->_vevent->getAttribute('ORGANIZER', true)); + } + + /** + * Set the organizer of the iTip event. + * + * @param string $organizer The organizer of the event. + * @param array $parameters Additional parameters. + * + * @return NULL + */ + private function setOrganizer($organizer, $parameters) + { + $this->_vevent->setAttribute('ORGANIZER', $organizer, $parameters); + } + + /** + * Copy the organizer from the request into the provided iTip instance. + * + * @return NULL + */ + private function copyOrganizer(Horde_Itip_Event $itip) + { + $itip->setOrganizer($this->getRawOrganizer(), $this->getOrganizerParameters()); + } +} \ No newline at end of file diff --git a/framework/Itip/lib/Horde/Itip/Exception.php b/framework/Itip/lib/Horde/Itip/Exception.php new file mode 100644 index 000000000..9c82e417b --- /dev/null +++ b/framework/Itip/lib/Horde/Itip/Exception.php @@ -0,0 +1,30 @@ + + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Itip + */ + +/** + * This class provides the standard error class for Horde_Itip exceptions. + * + * Copyright 2010 The Horde Project (http://www.horde.org/) + * + * See the enclosed file COPYING for license information (LGPL). If you + * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html. + * + * @category Horde + * @package Itip + * @author Gunnar Wrobel + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Itip + */ +class Horde_Itip_Exception extends Exception +{ +} diff --git a/framework/Itip/lib/Horde/Itip/Resource.php b/framework/Itip/lib/Horde/Itip/Resource.php new file mode 100644 index 000000000..e10e642af --- /dev/null +++ b/framework/Itip/lib/Horde/Itip/Resource.php @@ -0,0 +1,51 @@ + + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Itip + */ + +/** + * Provides information about an invited resource. + * + * Copyright 2010 Kolab Systems AG + * + * See the enclosed file COPYING for license information (LGPL). If you did not + * receive this file, see + * http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. + * + * @category Horde + * @package Itip + * @author Gunnar Wrobel + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Itip + */ +interface Horde_Itip_Resource +{ + /** + * Retrieve the mail address of the resource. + * + * @return string The mail address. + */ + public function getMailAddress(); + + /** + * Retrieve the common name of the resource. + * + * @return string The common name. + */ + public function getCommonName(); + + /** + * Retrieve the "From" address for this resource. + * + * @return string The "From" address. + */ + public function getFrom(); +} \ No newline at end of file diff --git a/framework/Itip/lib/Horde/Itip/Resource/Base.php b/framework/Itip/lib/Horde/Itip/Resource/Base.php new file mode 100644 index 000000000..8a378faf5 --- /dev/null +++ b/framework/Itip/lib/Horde/Itip/Resource/Base.php @@ -0,0 +1,87 @@ + + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Itip + */ + +/** + * Simple information provider for an invited resource. + * + * Copyright 2010 Kolab Systems AG + * + * See the enclosed file COPYING for license information (LGPL). If you did not + * receive this file, see + * http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. + * + * @category Horde + * @package Itip + * @author Gunnar Wrobel + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Itip + */ +class Horde_Itip_Resource_Base +implements Horde_Itip_Resource +{ + /** + * The mail address. + * + * @var string + */ + private $_mail; + + /** + * The common name. + * + * @var string + */ + private $_common_name; + + /** + * Constructor. + * + * @param string $mail The mail address. + * @param string $common_name The common name. + */ + public function __construct($mail, $common_name) + { + $this->_mail = $mail; + $this->_common_name = $common_name; + } + + /** + * Retrieve the mail address of the resource. + * + * @return string The mail address. + */ + public function getMailAddress() + { + return $this->_mail; + } + + /** + * Retrieve the common name of the resource. + * + * @return string The common name. + */ + public function getCommonName() + { + return $this->_common_name; + } + + /** + * Retrieve the "From" address for this resource. + * + * @return string The "From" address. + */ + public function getFrom() + { + return sprintf("%s <%s>", $this->_common_name, $this->_mail); + } +} \ No newline at end of file diff --git a/framework/Itip/lib/Horde/Itip/Response.php b/framework/Itip/lib/Horde/Itip/Response.php new file mode 100644 index 000000000..3fea90c41 --- /dev/null +++ b/framework/Itip/lib/Horde/Itip/Response.php @@ -0,0 +1,172 @@ + + * @author Gunnar Wrobel + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Itip + */ + +/** + * Handles Itip response data. + * + * Copyright 2004-2010 Klarälvdalens Datakonsult AB + * + * See the enclosed file COPYING for license information (LGPL). If you did not + * receive this file, see + * http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. + * + * @category Horde + * @package Itip + * @author Steffen Hansen + * @author Gunnar Wrobel + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Itip + */ +class Horde_Itip_Response +{ + /** + * The request we are going to answer. + * + * @var Horde_Itip_Event + */ + private $_request; + + /** + * The requested resource. + * + * @var Horde_Itip_Resource + */ + private $_resource; + + /** + * The status type of this response. + * + * @var Horde_Itip_Response_Type + */ + private $_type; + + /** + * Constructor. + * + * @param Horde_Itip_Event $request The request this + * instance will respond + * to. + * @param Horde_Itip_Resource $resource The requested + * resource. + */ + public function __construct( + Horde_Itip_Event $request, + Horde_Itip_Resource $resource + ) { + $this->_request = $request; + $this->_resource = $resource; + } + + /** + * Return the response as an iCalendar vveEnt 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(); + } + + /** + * Return the response as an iCalendar object. + * + * @param Horde_Itip_Response_Type $type The response + * type. + * @param string $product_id The ID that + * should be set + * as the iCalendar + * product id. + * + * @return Horde_iCalendar The response object. + */ + public function getIcalendar( + Horde_Itip_Response_Type $type, + $product_id + ) { + $vCal = new Horde_iCalendar(); + $vCal->setAttribute('PRODID', $product_id); + $vCal->setAttribute('METHOD', 'REPLY'); + $vCal->addComponent($this->getVevent($type, $vCal)); + return $vCal; + } + + /** + * Return the response as a MIME message. + * + * @param Horde_Itip_Response_Type $type The response + * type. + * @param string $product_id The ID that + * should be set + * as the iCalendar + * product id. + * @param string $subject_comment An optional comment on the subject line. + * + * @return array A list of two object: The mime headers and the mime + * message. + */ + public function getMessage( + Horde_Itip_Response_Type $type, + $product_id, + $subject_comment = null + ) { + $ics = new MIME_Part( + 'text/calendar', + $this->getIcalendar($type, $product_id)->exportvCalendar(), + 'UTF-8' + ); + $ics->setContentTypeParameter('method', 'REPLY'); + + //$mime->addPart($body); + //$mime->addPart($ics); + // The following was ::convertMimePart($mime). This was removed so that we + // send out single-part MIME replies that have the iTip file as the body, + // with the correct mime-type header set, etc. The reason we want to do this + // is so that Outlook interprets the messages as it does Outlook-generated + // responses, i.e. double-clicking a reply will automatically update your + // meetings, showing different status icons in the UI, etc. + $message = MIME_Message::convertMimePart($ics); + $message->setCharset('UTF-8'); + $message->setTransferEncoding('quoted-printable'); + $message->transferEncodeContents(); + + // Build the reply headers. + $headers = new MIME_Headers(); + $headers->addHeader('Date', date('r')); + $headers->addHeader('From', $this->_resource->getFrom()); + $headers->addHeader('To', $this->_request->getOrganizer()); + $headers->addHeader( + 'Subject', $type->getSubject($subject_comment) + ); + $headers->addMIMEHeaders($message); + return array($headers, $message); + } +} \ No newline at end of file diff --git a/framework/Itip/lib/Horde/Itip/Response/Type.php b/framework/Itip/lib/Horde/Itip/Response/Type.php new file mode 100644 index 000000000..9a3ffd507 --- /dev/null +++ b/framework/Itip/lib/Horde/Itip/Response/Type.php @@ -0,0 +1,65 @@ + + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Server + */ + +/** + * Marks the response type. + * + * Copyright 2010 Klarälvdalens Datakonsult AB + * + * See the enclosed file COPYING for license information (LGPL). If you did not + * receive this file, see + * http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. + * + * @category Kolab + * @package Kolab_Filter + * @author Gunnar Wrobel + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Server + */ +interface Horde_Itip_Response_Type +{ + /** + * Return the status of the response. + * + * @return string The status. + */ + public function getStatus(); + + /** + * Return the abbreviated subject of the response. + * + * @return string The short subject. + */ + public function getShortSubject(); + + /** + * Return the subject of the response. + * + * @param string $comment An optional comment that should appear in the + * response subject. + * + * @return string The subject. + */ + public function getSubject($comment = null); + + /** + * Return an additional message for the response. + * + * @param boolean $is_update Indicates if the request was an update. + * @param string $comment An optional comment that should appear in the + * response message. + * + * @return string The message. + */ + public function getMessage($is_update = false, $comment = null); +} \ No newline at end of file diff --git a/framework/Itip/lib/Horde/Itip/Response/Type/Accept.php b/framework/Itip/lib/Horde/Itip/Response/Type/Accept.php new file mode 100644 index 000000000..96a4c9283 --- /dev/null +++ b/framework/Itip/lib/Horde/Itip/Response/Type/Accept.php @@ -0,0 +1,65 @@ + + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Server + */ + +/** + * Indicates an accepted invitation. + * + * Copyright 2010 Klarälvdalens Datakonsult AB + * + * See the enclosed file COPYING for license information (LGPL). If you did not + * receive this file, see + * http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. + * + * @category Kolab + * @package Kolab_Filter + * @author Gunnar Wrobel + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Server + */ +class Horde_Itip_Response_Type_Accept +extends Horde_Itip_Response_Type_Base +{ + /** + * Return the status of the response. + * + * @return string The status. + */ + public function getStatus() + { + return 'ACCEPTED'; + } + + /** + * Return the abbreviated subject of the response. + * + * @return string The short subject. + */ + public function getShortSubject() + { + return _("Accepted"); + } + + /** + * Return the short message for the response. + * + * @param boolean $is_update Indicates if the request was an update. + * + * @return string The short message. + */ + public function getShortMessage($is_update = false) + { + return $is_update + ? _("has accepted the update to the following event") + : _("has accepted the invitation to the following event"); + } +} \ No newline at end of file diff --git a/framework/Itip/lib/Horde/Itip/Response/Type/Base.php b/framework/Itip/lib/Horde/Itip/Response/Type/Base.php new file mode 100644 index 000000000..cd65a2943 --- /dev/null +++ b/framework/Itip/lib/Horde/Itip/Response/Type/Base.php @@ -0,0 +1,125 @@ + + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Server + */ + +/** + * Basic iTip response type definition. + * + * Copyright 2010 Klarälvdalens Datakonsult AB + * + * See the enclosed file COPYING for license information (LGPL). If you did not + * receive this file, see + * http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. + * + * @category Kolab + * @package Kolab_Filter + * @author Gunnar Wrobel + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Server + */ +abstract class Horde_Itip_Response_Type_Base +implements Horde_Itip_Response_Type +{ + /** + * The request we are going to answer. + * + * @var Horde_Itip_Event + */ + private $_request; + + /** + * Set the request. + * + * @param Horde_Itip_Event $request The request this + * instance will respond + * to. + * + * @return NULL + */ + public function setRequest( + Horde_Itip_Event $request + ) { + $this->_request = $request; + } + + /** + * Get the request for this response. + * + * @return Horde_Itip_Event The request this instance will + * respond to. + * + * @throws Horde_Itip_Exception If the request has not been + * set yet. + */ + public function getRequest() + { + if (empty($this->_request)) { + throw new Horde_Itip_Exception( + 'The iTip request is still undefined!' + ); + } + return $this->_request; + } + + /** + * Return the subject of the response. + * + * @param string $comment An optional comment that should appear in the + * response subject. + * + * @return string The subject. + */ + public function getSubject($comment = null) + { + if ($comment === null) { + return sprintf( + '%s: %s', + $this->getShortSubject(), + $this->getRequest()->getSummary() + ); + } else { + return sprintf( + '%s [%s]: %s', + $this->getShortSubject(), + $comment, + $this->getRequest()->getSummary() + ); + } + } + + /** + * Return an additional message for the response. + * + * @param boolean $is_update Indicates if the request was an update. + * @param string $comment An optional comment that should appear in the + * response message. + * + * @return string The message. + */ + public function getMessage($is_update = false, $comment = null) + { + if ($comment === null) { + return sprintf( + "%s %s:\n\n%s", + $this->getShortMessage($update), + $this->getRequest()->getSummary() + ); + } else { + return sprintf( + "%s %s:\n\n%s\n\n%s", + $this->getShortMessage($update), + $this->getRequest()->getSummary(), + $comment + ); + } + } +} \ No newline at end of file diff --git a/framework/Itip/lib/Horde/Itip/Response/Type/Decline.php b/framework/Itip/lib/Horde/Itip/Response/Type/Decline.php new file mode 100644 index 000000000..3e6b4298d --- /dev/null +++ b/framework/Itip/lib/Horde/Itip/Response/Type/Decline.php @@ -0,0 +1,65 @@ + + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Server + */ + +/** + * Indicates a declined invitation. + * + * Copyright 2010 Klarälvdalens Datakonsult AB + * + * See the enclosed file COPYING for license information (LGPL). If you did not + * receive this file, see + * http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. + * + * @category Kolab + * @package Kolab_Filter + * @author Gunnar Wrobel + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Server + */ +class Horde_Itip_Response_Type_Decline +extends Horde_Itip_Response_Type_Base +{ + /** + * Return the status of the response. + * + * @return string The status. + */ + public function getStatus() + { + return 'DECLINED'; + } + + /** + * Return the abbreviated subject of the response. + * + * @return string The short subject. + */ + public function getShortSubject() + { + return _("Declined"); + } + + /** + * Return the short message for the response. + * + * @param boolean $is_update Indicates if the request was an update. + * + * @return string The short message. + */ + public function getShortMessage($is_update = false) + { + return $is_update + ? _("has declined the update to the following event") + : _("has declined the invitation to the following event"); + } +} \ No newline at end of file diff --git a/framework/Itip/lib/Horde/Itip/Response/Type/Tentative.php b/framework/Itip/lib/Horde/Itip/Response/Type/Tentative.php new file mode 100644 index 000000000..8da0b3f71 --- /dev/null +++ b/framework/Itip/lib/Horde/Itip/Response/Type/Tentative.php @@ -0,0 +1,65 @@ + + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Server + */ + +/** + * Indicates a tentatively accepted invitation. + * + * Copyright 2010 Klarälvdalens Datakonsult AB + * + * See the enclosed file COPYING for license information (LGPL). If you did not + * receive this file, see + * http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. + * + * @category Kolab + * @package Kolab_Filter + * @author Gunnar Wrobel + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Server + */ +class Horde_Itip_Response_Type_Tentative +extends Horde_Itip_Response_Type_Base +{ + /** + * Return the status of the response. + * + * @return string The status. + */ + public function getStatus() + { + return 'TENTATIVE'; + } + + /** + * Return the abbreviated subject of the response. + * + * @return string The short subject. + */ + public function getShortSubject() + { + return _("Tentative"); + } + + /** + * Return the short message for the response. + * + * @param boolean $is_update Indicates if the request was an update. + * + * @return string The short message. + */ + public function getShortMessage($is_update = false) + { + return $is_update + ? _("has tentatively accepted the update to the following event") + : _("has tentatively accepted the invitation to the following event"); + } +} \ No newline at end of file