From edfe90f9ffebf48ea8f9bbd5b98aadc4e0cb6275 Mon Sep 17 00:00:00 2001 From: Gunnar Wrobel
Date: Tue, 10 Aug 2010 18:01:18 +0200 Subject: [PATCH] Completed testing of sending the iTip response. --- imp/lib/tests/Imp/Autoload.php | 9 + imp/lib/tests/Imp/Stub/Browser.php | 14 + imp/lib/tests/Imp/Stub/Identity.php | 41 ++ imp/lib/tests/Imp/Stub/Injector.php | 19 + imp/lib/tests/Imp/Stub/Prefs.php | 14 + imp/lib/tests/Imp/Stub/Registry.php | 16 + imp/lib/tests/Imp/Unit/Mime/Viewer/ItipTest.php | 490 +++++++++++++++++++++++- 7 files changed, 600 insertions(+), 3 deletions(-) create mode 100644 imp/lib/tests/Imp/Stub/Browser.php create mode 100644 imp/lib/tests/Imp/Stub/Identity.php create mode 100644 imp/lib/tests/Imp/Stub/Injector.php create mode 100644 imp/lib/tests/Imp/Stub/Prefs.php create mode 100644 imp/lib/tests/Imp/Stub/Registry.php diff --git a/imp/lib/tests/Imp/Autoload.php b/imp/lib/tests/Imp/Autoload.php index 3fccc6475..b44c5f1a9 100644 --- a/imp/lib/tests/Imp/Autoload.php +++ b/imp/lib/tests/Imp/Autoload.php @@ -23,6 +23,8 @@ if (!spl_autoload_functions()) { . '} else if (substr($filename, 0, 4) == "IMP/") {' . ' $filename = substr($filename, 4);' . ' $filename = dirname(__FILE__) . "/../../$filename";' + . '} else if ($filename == "IMP") {' + . ' $filename = dirname(__FILE__) . "/../../$filename";' . '}' . '$err_mask = E_ALL ^ E_WARNING;' . '$oldErrorReporting = error_reporting($err_mask);' @@ -34,3 +36,10 @@ if (!spl_autoload_functions()) { /** Catch strict standards */ error_reporting(E_ALL | E_STRICT); + +/** Load stubs */ +require_once 'Stub/Browser.php'; +require_once 'Stub/Identity.php'; +require_once 'Stub/Injector.php'; +require_once 'Stub/Prefs.php'; +require_once 'Stub/Registry.php'; \ No newline at end of file diff --git a/imp/lib/tests/Imp/Stub/Browser.php b/imp/lib/tests/Imp/Stub/Browser.php new file mode 100644 index 000000000..4d2387a5f --- /dev/null +++ b/imp/lib/tests/Imp/Stub/Browser.php @@ -0,0 +1,14 @@ +_id = $id; + } + + public function getFromAddress() + { + return 'test@example.org'; + } + + public function getValue($value) + { + switch ($value) { + case 'fullname': + return 'Mr. Test'; + case 'replyto_addr': + switch ($this->_id) { + case 'test': + return 'test@example.org'; + case 'other': + return 'reply@example.org'; + } + } + } +} \ No newline at end of file diff --git a/imp/lib/tests/Imp/Stub/Injector.php b/imp/lib/tests/Imp/Stub/Injector.php new file mode 100644 index 000000000..09071a241 --- /dev/null +++ b/imp/lib/tests/Imp/Stub/Injector.php @@ -0,0 +1,19 @@ +_mail)) { + $this->_mail = new Horde_Mail_Transport_Mock(); + } + return $this->_mail; + } + } +} \ No newline at end of file diff --git a/imp/lib/tests/Imp/Stub/Prefs.php b/imp/lib/tests/Imp/Stub/Prefs.php new file mode 100644 index 000000000..ec504723f --- /dev/null +++ b/imp/lib/tests/Imp/Stub/Prefs.php @@ -0,0 +1,14 @@ +_charset; + } + + public function setCharset($charset) + { + $this->_charset = $charset; + } +} \ No newline at end of file diff --git a/imp/lib/tests/Imp/Unit/Mime/Viewer/ItipTest.php b/imp/lib/tests/Imp/Unit/Mime/Viewer/ItipTest.php index ccf137b60..b137e0751 100644 --- a/imp/lib/tests/Imp/Unit/Mime/Viewer/ItipTest.php +++ b/imp/lib/tests/Imp/Unit/Mime/Viewer/ItipTest.php @@ -35,14 +35,498 @@ require_once dirname(__FILE__) . '/../../../Autoload.php'; class Imp_Unit_Mime_Viewer_ItipTest extends PHPUnit_Framework_TestCase { - public function testMinimalItipHandlingSteps() + public function setUp() { - $viewer = $this->getViewer(); + $GLOBALS['registry'] = new IMP_Stub_Registry(); + $GLOBALS['browser'] = new IMP_Stub_Browser(); + $GLOBALS['prefs'] = new IMP_Stub_Prefs(); + $GLOBALS['injector'] = new IMP_Stub_Injector(); + $GLOBALS['conf']['server']['name'] = 'localhost'; + $_GET['identity'] = 'test'; + $_SERVER['REMOTE_ADDR'] = 'localhost'; + $_SESSION = array('imp' => array('view' => 'imp')); } - private function getViewer() + public function testAcceptingAnInvitationResultsInReplySent() + { + $_GET['itip_action'] = array(0 => 'accept'); + $viewer = $this->_getViewer($this->_getInvitation()->exportvCalendar()); + $result = $viewer->render('inline'); + $result = array_pop($result); + $this->assertContains('Reply Sent.', $result['data']); + } + + /** + * @todo This seems strange. How should the user know that an incomplete + * event results in no action but just redisplays the invitation? + */ + public function testAcceptingAnInvitationWithoutOrganizerResultsInNoAction() + { + $_GET['itip_action'] = array(0 => 'accept'); + $vCal = new Horde_Icalendar(); + $vCal->setAttribute('METHOD', 'REQUEST'); + $inv = Horde_Icalendar::newComponent('VEVENT', $vCal); + $inv->setAttribute('UID', '1'); + $viewer = $this->_getViewer($inv->exportvCalendar()); + $viewer->render('inline'); + $mail = $this->_getMail(); + $this->assertEquals('', $mail); + } + + public function testAcceptingAnInvitationResultsInMimeMessageSent() + { + $_GET['itip_action'] = array(0 => 'accept'); + $viewer = $this->_getViewer($this->_getInvitation()->exportvCalendar()); + $viewer->render('inline'); + $this->assertType('Horde_Icalendar', $this->_getIcalendar()); + } + + public function testResultMessageContainsProductId() + { + $_GET['itip_action'] = array(0 => 'accept'); + $viewer = $this->_getViewer($this->_getInvitation()->exportvCalendar()); + $viewer->render('inline'); + $this->assertEquals('-//The Horde Project//Horde Application Framework 4//EN', $this->_getIcalendar()->getAttribute('PRODID')); + } + + public function testResultMessageIndicatesMethodReply() + { + $_GET['itip_action'] = array(0 => 'accept'); + $viewer = $this->_getViewer($this->_getInvitation()->exportvCalendar()); + $viewer->render('inline'); + $this->assertEquals('REPLY', $this->_getIcalendar()->getAttribute('METHOD')); + } + + public function testResultMessageContainsVevent() + { + $_GET['itip_action'] = array(0 => 'accept'); + $viewer = $this->_getViewer($this->_getInvitation()->exportvCalendar()); + $viewer->render('inline'); + $this->assertType('Horde_Icalendar_Vevent', $this->_getVevent()); + } + + public function testResultMessageContainsCopiedUid() + { + $_GET['itip_action'] = array(0 => 'accept'); + $viewer = $this->_getViewer($this->_getInvitation()->exportvCalendar()); + $viewer->render('inline'); + $this->assertEquals('1001', $this->_getVevent()->getAttribute('UID')); + } + + /** + * @todo Should this really throw an exception? Adapt once the Mime Viewer + * does error handling (empty array return value) + */ + public function testResultMessageThrowsExceptionIfUidIsMissing() + { + $_GET['itip_action'] = array(0 => 'accept'); + $vCal = new Horde_Icalendar(); + $vCal->setAttribute('METHOD', 'REQUEST'); + $inv = Horde_Icalendar::newComponent('VEVENT', $vCal); + $inv->setAttribute('ORGANIZER', 'somebody@example.com'); + $viewer = $this->_getViewer($inv->exportvCalendar()); + $this->assertEquals(array(), $viewer->render('inline')); + } + + public function testResultMessageContainsCopiedSummary() + { + $_GET['itip_action'] = array(0 => 'accept'); + $viewer = $this->_getViewer($this->_getInvitation()->exportvCalendar()); + $viewer->render('inline'); + $this->assertEquals('Test Invitation', $this->_getVevent()->getAttribute('SUMMARY')); + } + + public function testResultMessageContainsEmptySummaryIfNotAvailable() + { + $_GET['itip_action'] = array(0 => 'accept'); + $viewer = $this->_getViewer($this->_getMinimalInvitation()->exportvCalendar()); + $viewer->render('inline'); + $this->assertEquals('', $this->_getVevent()->getAttribute('SUMMARY')); + } + + public function testResultMessageContainsCopiedDescription() + { + $_GET['itip_action'] = array(0 => 'accept'); + $viewer = $this->_getViewer($this->_getInvitation()->exportvCalendar()); + $viewer->render('inline'); + $this->assertEquals('You are invited', $this->_getVevent()->getAttribute('DESCRIPTION')); + } + + public function testResultMessageContainsEmptyDescriptionIfNotAvailable() + { + $_GET['itip_action'] = array(0 => 'accept'); + $viewer = $this->_getViewer($this->_getMinimalInvitation()->exportvCalendar()); + $viewer->render('inline'); + $this->assertEquals('Default', $this->_getVevent()->getAttributeDefault('DESCRIPTION', 'Default')); + } + + public function testResultMessageContainsCopiedStartDate() + { + $_GET['itip_action'] = array(0 => 'accept'); + $viewer = $this->_getViewer($this->_getInvitation()->exportvCalendar()); + $viewer->render('inline'); + $this->assertEquals('1222419600', $this->_getVevent()->getAttribute('DTSTART')); + } + + public function testResultMessageContainsCopiedStartDateParameters() + { + $_GET['itip_action'] = array(0 => 'accept'); + $viewer = $this->_getViewer($this->_getInvitation()->exportvCalendar()); + $viewer->render('inline'); + $dtstart = $this->_getVevent()->getAttribute('DTSTART', true); + $this->assertEquals(array('TEST' => 'start'), array_pop($dtstart)); + } + + public function testResultMessageContainsCopiedEndDate() + { + $_GET['itip_action'] = array(0 => 'accept'); + $viewer = $this->_getViewer($this->_getInvitation()->exportvCalendar()); + $viewer->render('inline'); + $this->assertEquals('1222423200', $this->_getVevent()->getAttribute('DTEND')); + } + + public function testResultMessageContainsCopiedEndDateParameters() + { + $_GET['itip_action'] = array(0 => 'accept'); + $viewer = $this->_getViewer($this->_getInvitation()->exportvCalendar()); + $viewer->render('inline'); + $dtend = $this->_getVevent()->getAttribute('DTEND', true); + $this->assertEquals(array('TEST' => 'end'), array_pop($dtend)); + } + + public function testResultMessageContainsCopiedDurationIfEndDateIsMissing() + { + $_GET['itip_action'] = array(0 => 'accept'); + $start = new Horde_Date('20080926T110000'); + $vCal = new Horde_Icalendar(); + $vCal->setAttribute('METHOD', 'REQUEST'); + $inv = Horde_Icalendar::newComponent('VEVENT', $vCal); + $inv->setAttribute('UID', '1001'); + $inv->setAttribute('ORGANIZER', 'orga@example.org'); + $inv->setAttribute('DTSTART', $start->timestamp()); + $inv->setAttribute('DURATION', '3600', array('TEST' => 'duration')); + $viewer = $this->_getViewer($inv->exportvCalendar()); + $viewer->render('inline'); + $this->assertEquals('3600', $this->_getVevent()->getAttribute('DURATION')); + } + + public function testResultMessageContainsCopiedDurationParametersIfEndDateIsMissing() + { + $_GET['itip_action'] = array(0 => 'accept'); + $start = new Horde_Date('20080926T110000'); + $vCal = new Horde_Icalendar(); + $vCal->setAttribute('METHOD', 'REQUEST'); + $inv = Horde_Icalendar::newComponent('VEVENT', $vCal); + $inv->setAttribute('UID', '1001'); + $inv->setAttribute('ORGANIZER', 'orga@example.org'); + $inv->setAttribute('DTSTART', $start->timestamp()); + $inv->setAttribute('DURATION', '3600', array('TEST' => 'duration')); + $viewer = $this->_getViewer($inv->exportvCalendar()); + $viewer->render('inline'); + $duration = $this->_getVevent()->getAttribute('DURATION', true); + $this->assertEquals(array('TEST' => 'duration'), array_pop($duration)); + } + + public function testResultMessageContainsCopiedInvitation() + { + $_GET['itip_action'] = array(0 => 'accept'); + $inv = $this->_getInvitation(); + $inv->setAttribute('SEQUENCE', '10'); + $viewer = $this->_getViewer($inv->exportvCalendar()); + $viewer->render('inline'); + $this->assertEquals('10', $this->_getVevent()->getAttribute('SEQUENCE')); + } + + public function testResultMessageContainsNoSequenceIfNotAvailable() + { + $_GET['itip_action'] = array(0 => 'accept'); + $viewer = $this->_getViewer($this->_getMinimalInvitation()->exportvCalendar()); + $viewer->render('inline'); + $this->assertEquals('99', $this->_getVevent()->getAttributeDefault('SEQUENCE', '99')); + } + + public function testResultMessageContainsCopiedOrganizer() + { + $_GET['itip_action'] = array(0 => 'accept'); + $viewer = $this->_getViewer($this->_getInvitation()->exportvCalendar()); + $viewer->render('inline'); + $this->assertEquals('mailto:orga@example.org', $this->_getVevent()->getAttribute('ORGANIZER')); + } + + public function testResultMessageContainsCopiedOrganizerParameters() + { + $_GET['itip_action'] = array(0 => 'accept'); + $viewer = $this->_getViewer($this->_getInvitation()->exportvCalendar()); + $viewer->render('inline'); + $organizer = $this->_getVevent()->getAttribute('ORGANIZER', true); + $this->assertEquals(array('CN' => 'Mr. Orga'), array_pop($organizer)); + } + + public function testResultMessageContainsAttendeeEmail() + { + $_GET['itip_action'] = array(0 => 'accept'); + $viewer = $this->_getViewer($this->_getInvitation()->exportvCalendar()); + $viewer->render('inline'); + $this->assertEquals('mailto:test@example.org', $this->_getVevent()->getAttribute('ATTENDEE')); + } + + public function testResultMessageContainsAttendeeName() + { + $_GET['itip_action'] = array(0 => 'accept'); + $viewer = $this->_getViewer($this->_getInvitation()->exportvCalendar()); + $viewer->render('inline'); + $attendee = $this->_getVevent()->getAttribute('ATTENDEE', true); + $params = array_pop($attendee); + $this->assertEquals('Mr. Test', $params['CN']); + } + + public function testAcceptActionResultsInMessageWithAttendeeStatusAccept() + { + $_GET['itip_action'] = array(0 => 'accept'); + $viewer = $this->_getViewer($this->_getInvitation()->exportvCalendar()); + $viewer->render('inline'); + $attendee = $this->_getVevent()->getAttribute('ATTENDEE', true); + $params = array_pop($attendee); + $this->assertEquals('ACCEPTED', $params['PARTSTAT']); + } + + public function testDenyActionResultsInMessageWithAttendeeStatusDecline() + { + $_GET['itip_action'] = array(0 => 'deny'); + $viewer = $this->_getViewer($this->_getInvitation()->exportvCalendar()); + $viewer->render('inline'); + $attendee = $this->_getVevent()->getAttribute('ATTENDEE', true); + $params = array_pop($attendee); + $this->assertEquals('DECLINED', $params['PARTSTAT']); + } + + public function testTentativeActionResultsInMessageWithAttendeeStatusTentative() + { + $_GET['itip_action'] = array(0 => 'tentative'); + $viewer = $this->_getViewer($this->_getInvitation()->exportvCalendar()); + $viewer->render('inline'); + $attendee = $this->_getVevent()->getAttribute('ATTENDEE', true); + $params = array_pop($attendee); + $this->assertEquals('TENTATIVE', $params['PARTSTAT']); + } + + public function testResultIsAMultipartMimeMessage() + { + $_GET['itip_action'] = array(0 => 'accept'); + $viewer = $this->_getViewer($this->_getInvitation()->exportvCalendar()); + $viewer->render('inline'); + $this->assertEquals('multipart/alternative', $this->_getMimeMessage()->getType()); + } + + public function testAcceptResultContainsAcceptMimeMessage() + { + $_GET['itip_action'] = array(0 => 'accept'); + $viewer = $this->_getViewer($this->_getInvitation()->exportvCalendar()); + $viewer->render('inline'); + $this->assertEquals('Mr. Test has accepted.', $this->_getMimeMessage()->getPart(1)->getContents()); + } + + public function testDenyResultContainsDeclineMimeMessage() + { + $_GET['itip_action'] = array(0 => 'deny'); + $viewer = $this->_getViewer($this->_getInvitation()->exportvCalendar()); + $viewer->render('inline'); + $this->assertEquals('Mr. Test has declined.', $this->_getMimeMessage()->getPart(1)->getContents()); + } + + public function testTentativeResultContainsTentativeMimeMessage() + { + $_GET['itip_action'] = array(0 => 'tentative'); + $viewer = $this->_getViewer($this->_getInvitation()->exportvCalendar()); + $viewer->render('inline'); + $this->assertEquals('Mr. Test has tentatively accepted.', $this->_getMimeMessage()->getPart(1)->getContents()); + } + + public function testResultMimeMessagePartOneHasRegistryCharset() + { + $GLOBALS['registry']->setCharset('BIG5'); + $_GET['itip_action'] = array(0 => 'accept'); + $viewer = $this->_getViewer($this->_getInvitation()->exportvCalendar()); + $viewer->render('inline'); + $this->assertEquals('BIG5', $this->_getMimeMessage()->getPart(1)->getCharset()); + } + + public function testResultMimeMessagePartTwoHasRegistryCharset() + { + $GLOBALS['registry']->setCharset('BIG5'); + $_GET['itip_action'] = array(0 => 'accept'); + $viewer = $this->_getViewer($this->_getInvitation()->exportvCalendar()); + $viewer->render('inline'); + $this->assertEquals('BIG5', $this->_getMimeMessage()->getPart(2)->getCharset()); + } + + public function testResultMimeMessagePartTwoHasFileName() + { + $_GET['itip_action'] = array(0 => 'accept'); + $viewer = $this->_getViewer($this->_getInvitation()->exportvCalendar()); + $viewer->render('inline'); + $this->assertEquals('event-reply.ics', $this->_getMimeMessage()->getPart(2)->getName()); + } + + public function testResultMimeMessagePartTwoHasContentTypeParameter() + { + $_GET['itip_action'] = array(0 => 'accept'); + $viewer = $this->_getViewer($this->_getInvitation()->exportvCalendar()); + $viewer->render('inline'); + $this->assertEquals('REPLY', $this->_getMimeMessage()->getPart(2)->getContentTypeParameter('METHOD')); + } + + public function testResultMimeMessageHeadersContainsReceivedHeader() + { + $_GET['itip_action'] = array(0 => 'accept'); + $viewer = $this->_getViewer($this->_getInvitation()->exportvCalendar()); + $viewer->render('inline'); + $this->assertContains('(Horde Framework) with HTTP', $this->_getMailHeaders()->getValue('Received')); + } + + public function testResultMimeMessageHeadersContainsMessageId() + { + $_GET['itip_action'] = array(0 => 'accept'); + $viewer = $this->_getViewer($this->_getInvitation()->exportvCalendar()); + $viewer->render('inline'); + $this->assertContains('.Horde.', $this->_getMailHeaders()->getValue('Message-ID')); + } + + public function testResultMimeMessageHeadersContainsDate() + { + $_GET['itip_action'] = array(0 => 'accept'); + $viewer = $this->_getViewer($this->_getInvitation()->exportvCalendar()); + $viewer->render('inline'); + $date = $this->_getMailHeaders()->getValue('Date'); + $this->assertTrue(!empty($date)); + } + + public function testResultMimeMessageHeadersContainsFrom() + { + $_GET['itip_action'] = array(0 => 'accept'); + $viewer = $this->_getViewer($this->_getInvitation()->exportvCalendar()); + $viewer->render('inline'); + $this->assertEquals('test@example.org', $this->_getMailHeaders()->getValue('From')); + } + + public function testResultMimeMessageHeadersContainsTo() + { + $_GET['itip_action'] = array(0 => 'accept'); + $viewer = $this->_getViewer($this->_getInvitation()->exportvCalendar()); + $viewer->render('inline'); + $this->assertEquals('orga@example.org', $this->_getMailHeaders()->getValue('To')); + } + + public function testAcceptActionResultMimeMessageHeadersContainsAcceptSubject() + { + $_GET['itip_action'] = array(0 => 'accept'); + $viewer = $this->_getViewer($this->_getInvitation()->exportvCalendar()); + $viewer->render('inline'); + $this->assertEquals('Accepted: Test Invitation', $this->_getMailHeaders()->getValue('Subject')); + } + + public function testDenyActionResultMimeMessageHeadersContainsDeclineSubject() + { + $_GET['itip_action'] = array(0 => 'deny'); + $viewer = $this->_getViewer($this->_getInvitation()->exportvCalendar()); + $viewer->render('inline'); + $this->assertEquals('Declined: Test Invitation', $this->_getMailHeaders()->getValue('Subject')); + } + + public function testTentativeActionResultMimeMessageHeadersContainsTentativeSubject() + { + $_GET['itip_action'] = array(0 => 'tentative'); + $viewer = $this->_getViewer($this->_getInvitation()->exportvCalendar()); + $viewer->render('inline'); + $this->assertEquals('Tentative: Test Invitation', $this->_getMailHeaders()->getValue('Subject')); + } + public function testResultMimeMessageHeadersContainsReplyToForAlternateIdentity() + { + $_GET['identity'] = 'other'; + $_GET['itip_action'] = array(0 => 'accept'); + $viewer = $this->_getViewer($this->_getInvitation()->exportvCalendar()); + $viewer->render('inline'); + $this->assertEquals('reply@example.org', $this->_getMailHeaders()->getValue('Reply-To')); + } + + private function _getViewer($invitation) { $part = new Horde_Mime_Part(); + $part->setContents($invitation); return new IMP_Horde_Mime_Viewer_Itip($part); } + + private function _getInvitation() + { + $start = new Horde_Date('20080926T110000'); + $end = new Horde_Date('20080926T120000'); + $vCal = new Horde_Icalendar(); + $vCal->setAttribute('METHOD', 'REQUEST'); + $inv = Horde_Icalendar::newComponent('VEVENT', $vCal); + $inv->setAttribute('UID', '1001'); + $inv->setAttribute('SUMMARY', 'Test Invitation'); + $inv->setAttribute('DESCRIPTION', 'You are invited'); + $inv->setAttribute('LOCATION', 'Somewhere'); + $inv->setAttribute('ORGANIZER', 'mailto:orga@example.org', array('cn' => 'Mr. Orga')); + $inv->setAttribute('DTSTART', $start->timestamp(), array('TEST' => 'start')); + $inv->setAttribute('DTEND', $end->timestamp(), array('TEST' => 'end')); + $inv->setAttribute('ATTENDEE', 'mailto:orga@example.org', array('CN' => 'Mr. Orga')); + $inv->setAttribute('ATTENDEE', 'mailto:test@example.org', array('CN' => 'Mr. Test')); + return $inv; + } + + private function _getMinimalInvitation() + { + $start = new Horde_Date('20080926T110000'); + $end = new Horde_Date('20080926T120000'); + $vCal = new Horde_Icalendar(); + $vCal->setAttribute('METHOD', 'REQUEST'); + $inv = Horde_Icalendar::newComponent('VEVENT', $vCal); + $inv->setAttribute('UID', '1001'); + $inv->setAttribute('ORGANIZER', 'mailto:orga@example.org', array('cn' => 'Mr. Orga')); + $inv->setAttribute('DTSTART', $start->timestamp()); + $inv->setAttribute('DTEND', $end->timestamp()); + return $inv; + } + + private function _getMailHeaders() + { + if (isset($GLOBALS['injector']->getInstance('IMP_Mail')->sentMessages[0])) { + return Horde_Mime_Headers::parseHeaders( + $GLOBALS['injector']->getInstance('IMP_Mail')->sentMessages[0]['header_text'] + ); + } + } + + private function _getMail() + { + $mail = ''; + if (isset($GLOBALS['injector']->getInstance('IMP_Mail')->sentMessages[0])) { + $mail .= $GLOBALS['injector']->getInstance('IMP_Mail')->sentMessages[0]['header_text'] . "\n\n"; + $body = $GLOBALS['injector']->getInstance('IMP_Mail')->sentMessages[0]['body']; + while (!feof($body)) { + $mail .= fread($body, 8192); + } + } + return $mail; + } + + private function _getMimeMessage() + { + $mail = $this->_getMail(); + return Horde_Mime_Part::parseMessage($mail); + } + + private function _getIcalendar() + { + $part = $this->_getMimeMessage(); + $iCal = new Horde_Icalendar(); + $iCal->parsevCalendar($part->getPart(2)->getContents()); + return $iCal; + } + + private function _getVevent() + { + return $this->_getIcalendar()->getComponent(0); + } } -- 2.11.0