Author: Chuck Hagenbuch (chuck@horde.org)
Author: Michael Slusarz (slusarz@horde.org)
Inheritance: implements ArrayAccess, implements Countable, implements RecursiveIterator, implements Serializable
Example #1
0
 /**
  * Constructor.
  *
  * @param Horde_Mime_Part $mime_part  A MIME part object. Must be of
  *                                    type multipart/related.
  */
 public function __construct(Horde_Mime_Part $mime_part)
 {
     if ($mime_part->getType() != 'multipart/related') {
         throw new InvalidArgumentException('MIME part must be of type multipart/related');
     }
     $id = null;
     $ids = array();
     $related_id = $mime_part->getMimeId();
     /* Build a list of parts -> CIDs. */
     foreach ($mime_part->partIterator() as $val) {
         $part_id = $val->getMimeId();
         $ids[] = $part_id;
         if (strcmp($related_id, $part_id) !== 0 && ($cid = $val->getContentId())) {
             $this->_cids[$part_id] = $cid;
         }
     }
     /* Look at the 'start' parameter to determine which part to start
      * with. If no 'start' parameter, use the first part (RFC 2387
      * [3.1]). */
     if ($start = $mime_part->getContentTypeParameter('start')) {
         $id = $this->cidSearch(trim($start, '<> '));
     }
     if (empty($id)) {
         reset($ids);
         $id = next($ids);
     }
     $this->_start = $id;
 }
Example #2
0
 /**
  * Sends a message to an email address supposed to be added to the
  * identity.
  *
  * A message is send to this address containing a time-sensitive link to
  * confirm that the address really belongs to that user.
  *
  * @param integer $id       The identity's ID.
  * @param string $old_addr  The old From: address.
  *
  * @throws Horde_Mime_Exception
  */
 public function verifyIdentity($id, $old_addr)
 {
     global $injector, $notification, $registry;
     $hash = strval(new Horde_Support_Randomid());
     $pref = $this->_confirmEmail();
     $pref[$hash] = $this->get($id);
     $pref[$hash][self::EXPIRE] = time() + self::EXPIRE_SECS;
     $this->_confirmEmail($pref);
     $new_addr = $this->getValue($this->_prefnames['from_addr'], $id);
     $confirm = Horde::url($registry->getServiceLink('emailconfirm')->add('h', $hash)->setRaw(true), true);
     $message = sprintf(Horde_Core_Translation::t("You have requested to add the email address \"%s\" to the list of your personal email addresses.\n\nGo to the following link to confirm that this is really your address:\n%s\n\nIf you don't know what this message means, you can delete it."), $new_addr, $confirm);
     $msg_headers = new Horde_Mime_Headers();
     $msg_headers->addHeaderOb(Horde_Mime_Headers_MessageId::create());
     $msg_headers->addHeaderOb(Horde_Mime_Headers_UserAgent::create());
     $msg_headers->addHeaderOb(Horde_Mime_Headers_Date::create());
     $msg_headers->addHeader('To', $new_addr);
     $msg_headers->addHeader('From', $old_addr);
     $msg_headers->addHeader('Subject', Horde_Core_Translation::t("Confirm new email address"));
     $body = new Horde_Mime_Part();
     $body->setType('text/plain');
     $body->setContents(Horde_String::wrap($message, 76));
     $body->setCharset('UTF-8');
     $body->send($new_addr, $msg_headers, $injector->getInstance('Horde_Mail'));
     $notification->push(sprintf(Horde_Core_Translation::t("A message has been sent to \"%s\" to verify that this is really your address. The new email address is activated as soon as you confirm this message."), $new_addr), 'horde.message');
 }
Example #3
0
 /**
  * If this MIME part can contain embedded MIME part(s), and those part(s)
  * exist, return a representation of that data.
  *
  * @return mixed  A Horde_Mime_Part object representing the embedded data.
  *                Returns null if no embedded MIME part(s) exist.
  */
 protected function _getEmbeddedMimeParts()
 {
     /* Get the data from the attachment. */
     try {
         if (!($tnef = $this->getConfigParam('tnef'))) {
             $tnef = Horde_Compress::factory('Tnef');
             $this->setConfigParam('tnef', $tnef);
         }
         $tnefData = $tnef->decompress($this->_mimepart->getContents());
     } catch (Horde_Compress_Exception $e) {
         $tnefData = array();
     }
     if (!count($tnefData)) {
         return null;
     }
     $mixed = new Horde_Mime_Part();
     $mixed->setType('multipart/mixed');
     reset($tnefData);
     while (list(, $data) = each($tnefData)) {
         $temp_part = new Horde_Mime_Part();
         $temp_part->setName($data['name']);
         $temp_part->setDescription($data['name']);
         $temp_part->setContents($data['stream']);
         /* Short-circuit MIME-type guessing for winmail.dat parts;
          * we're showing enough entries for them already. */
         $type = $data['type'] . '/' . $data['subtype'];
         if (in_array($type, array('application/octet-stream', 'application/base64'))) {
             $type = Horde_Mime_Magic::filenameToMIME($data['name']);
         }
         $temp_part->setType($type);
         $mixed->addPart($temp_part);
     }
     return $mixed;
 }
Example #4
0
 /**
  */
 public function matchStructure(Horde_Mime_Part $data)
 {
     foreach ($data->partIterator() as $val) {
         if (IMP_Mime_Attachment::isAttachment($val)) {
             return true;
         }
     }
     return false;
 }
Example #5
0
 /**
  * Renders a token into text matching the requested format.
  *
  * @param array $options The "options" portion of the token (second
  * element).
  *
  * @return string The text rendered from the token options.
  */
 public function token($options)
 {
     $part = new Horde_Mime_Part();
     $part->setContents($options['text']);
     $part->setType('application/x-extension-' . $options['attr']['type']);
     $viewer = Horde_Mime_Viewer::factory('Horde_Core_Mime_Viewer_Syntaxhighlighter', $part, array('registry' => $GLOBALS['registry']));
     $data = $viewer->render('inline');
     $data = reset($data);
     return $data['data'];
 }
Example #6
0
 public function testStructure()
 {
     $this->assertInstanceOf('Horde_Mime_Part', $this->ob->getStructure());
     $test = new Horde_Mime_Part();
     $test->setType('image/foo');
     $this->ob->setStructure($test);
     $serialize_ob = unserialize(serialize($this->ob));
     foreach (array($this->ob, $serialize_ob) as $val) {
         $ret = $val->getStructure();
         $this->assertInstanceOf('Horde_Mime_Part', $ret);
         $this->assertEquals('image/foo', $ret->getType('image/foo'));
     }
 }
Example #7
0
 private function getMultipartMimeMessage($mime_type)
 {
     $envelope = new Horde_Mime_Part();
     $envelope->setType('multipart/mixed');
     $foo = new Horde_Mime_Part();
     $foo->setType('foo/bar');
     $envelope->addPart($foo);
     $kolab = new Horde_Mime_Part();
     $kolab->setType($mime_type);
     $envelope->addPart($kolab);
     $envelope->buildMimeIds();
     return $envelope;
 }
Example #8
0
 /**
  */
 public function report(IMP_Contents $contents, $action)
 {
     global $injector, $registry;
     $imp_compose = $injector->getInstance('IMP_Factory_Compose')->create();
     switch ($this->_format) {
         case 'redirect':
             /* Send the message. */
             try {
                 $imp_compose->redirectMessage($contents->getIndicesOb());
                 $imp_compose->sendRedirectMessage($this->_email, false);
                 return true;
             } catch (IMP_Compose_Exception $e) {
                 $e->log();
             }
             break;
         case 'digest':
         default:
             try {
                 $from_line = $injector->getInstance('IMP_Identity')->getFromLine();
             } catch (Horde_Exception $e) {
                 $from_line = null;
             }
             /* Build the MIME structure. */
             $mime = new Horde_Mime_Part();
             $mime->setType('multipart/digest');
             $rfc822 = new Horde_Mime_Part();
             $rfc822->setType('message/rfc822');
             $rfc822->setContents($contents->fullMessageText(array('stream' => true)));
             $mime->addPart($rfc822);
             $spam_headers = new Horde_Mime_Headers();
             $spam_headers->addMessageIdHeader();
             $spam_headers->addHeader('Date', date('r'));
             $spam_headers->addHeader('To', $this->_email);
             if (!is_null($from_line)) {
                 $spam_headers->addHeader('From', $from_line);
             }
             $spam_headers->addHeader('Subject', sprintf(_("%s report from %s"), $action == IMP_Spam::SPAM ? 'spam' : 'innocent', $registry->getAuth()));
             /* Send the message. */
             try {
                 $recip_list = $imp_compose->recipientList(array('to' => $this->_email));
                 $imp_compose->sendMessage($recip_list['list'], $spam_headers, $mime, 'UTF-8');
                 $rfc822->clearContents();
                 return true;
             } catch (IMP_Compose_Exception $e) {
                 $e->log();
                 $rfc822->clearContents();
             }
             break;
     }
     return false;
 }
Example #9
0
 /**
  * @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');
 }
Example #10
0
 public function testIconvHtmlMessage()
 {
     $conn = $this->getMockBuilder('Horde_Imap_Client_Socket')->disableOriginalConstructor()->setMethods(['fetch'])->getMock();
     $urlGenerator = $this->getMockBuilder('\\OCP\\IURLGenerator')->disableOriginalConstructor()->getMock();
     //linkToRoute 'mail.proxy.proxy'
     $urlGenerator->expects($this->any())->method('linkToRoute')->will($this->returnCallback(function ($url) {
         return "https://docs.example.com/server/go.php?to={$url}";
     }));
     $htmlService = new \OCA\Mail\Service\Html($urlGenerator);
     // mock first fetch
     $firstFetch = new Horde_Imap_Client_Data_Fetch();
     $firstPart = Horde_Mime_Part::parseMessage(file_get_contents(__DIR__ . '/data/mail-message-123.txt'), ['level' => 1]);
     $firstFetch->setStructure($firstPart);
     $firstFetch->setBodyPart(1, $firstPart->getPart(1)->getContents());
     $firstFetch->setBodyPart(2, $firstPart->getPart(2)->getContents());
     $firstResult = new Horde_Imap_Client_Fetch_Results();
     $firstResult[123] = $firstFetch;
     $conn->expects($this->any())->method('fetch')->willReturn($firstResult);
     $message = new \OCA\Mail\Message($conn, 'INBOX', 123, null, true, $htmlService);
     $htmlBody = $message->getHtmlBody(0, 0, 123, function () {
         return null;
     });
     $this->assertTrue(strlen($htmlBody) > 1000);
     $plainTextBody = $message->getPlainBody();
     $this->assertTrue(strlen($plainTextBody) > 1000);
 }
Example #11
0
 /**
  * @dataProvider message_inbound_handler_trim_testprovider
  */
 public function test_messageinbound_handler_trim($file, $source, $expectedplain, $expectedhtml)
 {
     $this->resetAfterTest();
     $mime = Horde_Mime_Part::parseMessage($source);
     if ($plainpartid = $mime->findBody('plain')) {
         $messagedata = new stdClass();
         $messagedata->plain = $mime->getPart($plainpartid)->getContents();
         $messagedata->html = '';
         list($message, $format) = test_handler::remove_quoted_text($messagedata);
         list($message, $expectedplain) = preg_replace("#\r\n#", "\n", array($message, $expectedplain));
         // Normalise line endings on both strings.
         $this->assertEquals($expectedplain, $message);
         $this->assertEquals(FORMAT_PLAIN, $format);
     }
     if ($htmlpartid = $mime->findBody('html')) {
         $messagedata = new stdClass();
         $messagedata->plain = '';
         $messagedata->html = $mime->getPart($htmlpartid)->getContents();
         list($message, $format) = test_handler::remove_quoted_text($messagedata);
         // Normalise line endings on both strings.
         list($message, $expectedhtml) = preg_replace("#\r\n#", "\n", array($message, $expectedhtml));
         $this->assertEquals($expectedhtml, $message);
         $this->assertEquals(FORMAT_PLAIN, $format);
     }
 }
Example #12
0
 /**
  * Test creating a Horde_ActiveSync_Message_MeetingRequest from a MIME Email
  */
 public function testInvite()
 {
     $this->markTestIncomplete('Has issues on 32bit systems');
     $fixture = file_get_contents(__DIR__ . '/fixtures/invitation_one.eml');
     $mime = Horde_Mime_Part::parseMessage($fixture);
     $msg = new Horde_ActiveSync_Message_MeetingRequest();
     foreach ($mime->contentTypeMap() as $id => $type) {
         if ($type == 'text/calendar') {
             $vcal = new Horde_Icalendar();
             $vcal->parseVcalendar($mime->getPart($id)->getContents());
             $msg->fromvEvent($vcal);
             break;
         }
     }
     $stream = fopen('php://memory', 'wb+');
     $encoder = new Horde_ActiveSync_Wbxml_Encoder($stream);
     $msg->encodeStream($encoder);
     rewind($stream);
     $results = stream_get_contents($stream);
     fclose($stream);
     $stream = fopen(__DIR__ . '/fixtures/meeting_request_one.wbxml', 'r+');
     $expected = '';
     // Using file_get_contents or even fread mangles the binary data for some
     // reason.
     while ($line = fgets($stream)) {
         $expected .= $line;
     }
     fclose($stream);
     $this->assertEquals($expected, $results);
 }
Example #13
0
 public function testHasiCalendar()
 {
     $fixture = file_get_contents(__DIR__ . '/fixtures/invitation_one.eml');
     $mime = new Horde_ActiveSync_Mime(Horde_Mime_Part::parseMessage($fixture));
     $this->assertEquals(true, $mime->hasAttachments());
     $this->assertEquals(false, $mime->isSigned());
     $this->assertEquals(true, (bool) $mime->hasiCalendar());
 }
Example #14
0
 /**
  * Determines if a MIME type is an attachment.
  *
  * @param Horde_Mime_Part $part  The MIME part.
  */
 public static function isAttachment(Horde_Mime_Part $part)
 {
     $type = $part->getType();
     switch ($type) {
         case 'application/ms-tnef':
         case 'application/pgp-keys':
         case 'application/vnd.ms-tnef':
             return false;
     }
     if ($part->parent) {
         switch ($part->parent->getType()) {
             case 'multipart/encrypted':
                 switch ($type) {
                     case 'application/octet-stream':
                         return false;
                 }
                 break;
             case 'multipart/signed':
                 switch ($type) {
                     case 'application/pgp-signature':
                     case 'application/pkcs7-signature':
                     case 'application/x-pkcs7-signature':
                         return false;
                 }
                 break;
         }
     }
     switch ($part->getDisposition()) {
         case 'attachment':
             return true;
     }
     switch ($part->getPrimaryType()) {
         case 'application':
             if (strlen($part->getName())) {
                 return true;
             }
             break;
         case 'audio':
         case 'video':
             return true;
         case 'multipart':
             return false;
     }
     return false;
 }
Example #15
0
 /**
  * Adds a MIME Viewer action to the status text.
  *
  * @param string $action  Action ID.
  * @param string $text    Action description.
  * @param array $attr     Additional attributes.
  */
 public function addMimeAction($action, $text, array $attr = array())
 {
     $attr['mimevieweraction'] = $action;
     if (!is_null($this->_part)) {
         $attr['mimeviewerid'] = $this->_part->getMimeId();
     }
     $url = new Horde_Url('#');
     $this->addText($url->link($attr) . $text . '</a>');
 }
Example #16
0
 /**
  */
 protected function _write($filename, Horde_Mime_Part $part)
 {
     global $browser;
     try {
         $this->_vfs->write($this->_vfspath, $this->_id, $filename, true);
     } catch (Horde_Vfs_Exception $e) {
         throw new IMP_Compose_Exception($e);
     }
     // Prevent 'jar:' attacks on Firefox.  See Ticket #5892.
     $type = $part->getType();
     if ($browser->isBrowser('mozilla') && in_array(Horde_String::lower($type), array('application/java-archive', 'application/x-jar'))) {
         $type = 'application/octet-stream';
     }
     $md = $this->getMetadata();
     $md->filename = $part->getName(true);
     $md->time = time();
     $md->type = $type;
     $this->saveMetadata($md);
 }
Example #17
0
 /**
  */
 public function serialize()
 {
     /* Don't store Mime_Part data. Can't use clone here ATM, since there
      * appears to be a PHP bug. Since this is an object specific to IMP
      * (and we are only using in a certain predictable way), it should
      * be ok to directly alter the MIME part object without any ill
      * effects. */
     $this->_part->clearContents();
     $this->_isBuilt = false;
     return $GLOBALS['injector']->getInstance('Horde_Pack')->pack(array($this->_composeCache, $this->id, $this->_linked, $this->_part, $this->related, $this->_uuid), array('compression' => false, 'phpob' => true));
 }
Example #18
0
    public function testBug10431()
    {
        $text = 'Das könnte zum Beispiel so aussehen, dass wir bei entsprechenden Anfragen diese an eine Kontaktperson bei Euch weiterleiten. Oder Ihr schnürt ein entsprechendes Paket, dass wir in unseren Angeboten mit anführen. Bei erfolgreicher Vermittlung bekämen wir eine Vermittlungsgebühr.
Wir ständen dann weiterhin für 3rd-Level-Support zur Verfügung, d.h. für alle Anfragen des Kunden bzgl. Horde, die nicht zum Tagesgeschäft gehören.';
        $text = Horde_String::convertCharset($text, 'UTF-8', 'ISO-8859-1');
        $textBody = new Horde_Mime_Part();
        $textBody->setType('text/plain');
        $textBody->setCharset('ISO-8859-1');
        $flowed = new Horde_Text_Flowed($text, 'ISO-8859-1');
        $flowed->setDelSp(true);
        $textBody->setContents($flowed->toFlowed());
        $flowed_txt = $textBody->toString(array('headers' => false));
        $textBody2 = new Horde_Mime_Part();
        $textBody2->setType('text/plain');
        $textBody2->setCharset('ISO-8859-1');
        $textBody2->setContents($flowed_txt, array('encoding' => 'quoted-printable'));
        $flowed2 = new Horde_Text_Flowed($textBody2->getContents(), 'ISO-8859-1');
        $flowed2->setMaxLength(0);
        $flowed2->setDelSp(true);
        $this->assertEquals($text, trim($flowed2->toFixed()));
    }
Example #19
0
 public function testReplace()
 {
     $part = Horde_Mime_Part::parseMessage(file_get_contents(__DIR__ . '/fixtures/related_msg.txt'));
     $related = new Horde_Mime_Related($part);
     $ob = $related->cidReplace($part['1']->getContents(), array($this, 'callbackTestReplace'));
     $body = $ob->dom->getElementsByTagName('body');
     $this->assertEquals(1, $body->length);
     $this->assertEquals('2', $body->item(0)->getAttribute('background'));
     $body = $ob->dom->getElementsByTagName('img');
     $this->assertEquals(1, $body->length);
     $this->assertEquals('3', $body->item(0)->getAttribute('src'));
 }
Example #20
0
File: Mime.php Project: horde/horde
 /**
  * Return the MIME part of the iCalendar attachment, if available.
  *
  * @return mixed  The mime id of an iCalendar part, if present. Otherwise
  *                false.
  */
 public function hasiCalendar()
 {
     if (!$this->hasAttachments()) {
         return false;
     }
     foreach ($this->_base->contentTypeMap() as $id => $type) {
         if ($type == 'text/calendar' || $type == 'application/ics') {
             return $id;
         }
     }
     return false;
 }
Example #21
0
 /**
  * Return the MIME part of the iCalendar attachment, if available.
  *
  * @return mixed  The mime part, if present, false otherwise.
  */
 public function hasiCalendar()
 {
     if (!$this->hasAttachments()) {
         return false;
     }
     foreach ($this->_base->contentTypeMap() as $id => $type) {
         if ($type == 'text/calendar') {
             return $this->_base->getPart($id);
         }
     }
     return false;
 }
Example #22
0
 /**
  * Generates a Horde_Mime_Part object, in accordance with RFC 3156, that
  * contains a public key.
  *
  * @return Horde_Mime_Part  Object that contains the armored public key.
  */
 public function createMimePart()
 {
     $part = new Horde_Mime_Part();
     $part->setType('application/pgp-keys');
     $part->setHeaderCharset('UTF-8');
     $part->setDescription(Horde_Pgp_Translation::t("PGP Public Key"));
     $part->setContents(strval($this), array('encoding' => '7bit'));
     return $part;
 }
Example #23
0
 /**
  * Variables required in form input:
  *   - identity (TODO: ? Code uses it, but it is never set anywhere)
  *   - imple_submit: itip_action(s)
  *   - mime_id
  *   - muid
  *
  * @return boolean  True on success.
  */
 protected function _handle(Horde_Variables $vars)
 {
     global $injector, $notification, $registry;
     $actions = (array) $vars->imple_submit;
     $result = false;
     $vCal = new Horde_Icalendar();
     /* Retrieve the calendar data from the message. */
     try {
         $contents = $injector->getInstance('IMP_Factory_Contents')->create(new IMP_Indices_Mailbox($vars));
         $mime_part = $contents->getMIMEPart($vars->mime_id);
         if (empty($mime_part)) {
             throw new IMP_Exception(_("Cannot retrieve calendar data from message."));
         } elseif (!$vCal->parsevCalendar($mime_part->getContents(), 'VCALENDAR', $mime_part->getCharset())) {
             throw new IMP_Exception(_("The calendar data is invalid"));
         }
         $components = $vCal->getComponents();
     } catch (Exception $e) {
         $notification->push($e, 'horde.error');
         $actions = array();
     }
     foreach ($actions as $key => $action) {
         $pos = strpos($key, '[');
         $key = substr($key, $pos + 1, strlen($key) - $pos - 2);
         switch ($action) {
             case 'delete':
                 // vEvent cancellation.
                 if ($registry->hasMethod('calendar/delete')) {
                     $guid = $components[$key]->getAttribute('UID');
                     $recurrenceId = null;
                     try {
                         // This is a cancellation of a recurring event instance.
                         $recurrenceId = $components[$key]->getAttribute('RECURRENCE-ID');
                         $atts = $components[$key]->getAttribute('RECURRENCE-ID', true);
                         $range = null;
                         foreach ($atts as $att) {
                             if (array_key_exists('RANGE', $att)) {
                                 $range = $att['RANGE'];
                             }
                         }
                     } catch (Horde_Icalendar_Exception $e) {
                     }
                     try {
                         $registry->call('calendar/delete', array($guid, $recurrenceId, $range));
                         $notification->push(_("Event successfully deleted."), 'horde.success');
                         $result = true;
                     } catch (Horde_Exception $e) {
                         $notification->push(sprintf(_("There was an error deleting the event: %s"), $e->getMessage()), 'horde.error');
                     }
                 } else {
                     $notification->push(_("This action is not supported."), 'horde.warning');
                 }
                 break;
             case 'update':
                 // vEvent reply.
                 if ($registry->hasMethod('calendar/updateAttendee')) {
                     try {
                         $from = $contents->getHeader()->getOb('from');
                         $registry->call('calendar/updateAttendee', array($components[$key], $from[0]->bare_address));
                         $notification->push(_("Respondent Status Updated."), 'horde.success');
                         $result = true;
                     } catch (Horde_Exception $e) {
                         $notification->push(sprintf(_("There was an error updating the event: %s"), $e->getMessage()), 'horde.error');
                     }
                 } else {
                     $notification->push(_("This action is not supported."), 'horde.warning');
                 }
                 break;
             case 'import':
             case 'accept-import':
                 // vFreebusy reply.
                 // vFreebusy publish.
                 // vEvent request.
                 // vEvent publish.
                 // vTodo publish.
                 // vJournal publish.
                 switch ($components[$key]->getType()) {
                     case 'vEvent':
                         $result = $this->_handlevEvent($key, $components, $mime_part);
                         // Must check for exceptions.
                         foreach ($components as $k => $component) {
                             try {
                                 if ($component->getType() == 'vEvent' && $component->getAttribute('RECURRENCE-ID')) {
                                     $uid = $component->getAttribute('UID');
                                     if ($uid == $components[$key]->getAttribute('UID')) {
                                         $this->_handlevEvent($k, $components, $mime_part);
                                     }
                                 }
                             } catch (Horde_Icalendar_Exception $e) {
                             }
                         }
                         break;
                     case 'vFreebusy':
                         // Import into Kronolith.
                         if ($registry->hasMethod('calendar/import_vfreebusy')) {
                             try {
                                 $registry->call('calendar/import_vfreebusy', array($components[$key]));
                                 $notification->push(_("The user's free/busy information was sucessfully stored."), 'horde.success');
                                 $result = true;
                             } catch (Horde_Exception $e) {
                                 $notification->push(sprintf(_("There was an error importing user's free/busy information: %s"), $e->getMessage()), 'horde.error');
                             }
                         } else {
                             $notification->push(_("This action is not supported."), 'horde.warning');
                         }
                         break;
                     case 'vTodo':
                         // Import into Nag.
                         if ($registry->hasMethod('tasks/import')) {
                             try {
                                 $guid = $registry->call('tasks/import', array($components[$key], $mime_part->getType()));
                                 $url = Horde::url($registry->link('tasks/show', array('uid' => $guid)));
                                 $notification->push(_("The task has been added to your tasklist.") . '&nbsp;' . Horde::link($url, _("View task"), null, '_blank') . Horde_Themes_Image::tag('mime/icalendar.png', array('alt' => _("View task"))) . '</a>', 'horde.success', array('content.raw'));
                                 $result = true;
                             } catch (Horde_Exception $e) {
                                 $notification->push(sprintf(_("There was an error importing the task: %s"), $e->getMessage()), 'horde.error');
                             }
                         } else {
                             $notification->push(_("This action is not supported."), 'horde.warning');
                         }
                         break;
                     case 'vJournal':
                     default:
                         $notification->push(_("This action is not supported."), 'horde.warning');
                 }
                 if ($action == 'import') {
                     break;
                 }
                 // Fall-through for 'accept-import'
             // Fall-through for 'accept-import'
             case 'accept':
             case 'deny':
             case 'tentative':
                 // vEvent request.
                 if (isset($components[$key]) && $components[$key]->getType() == 'vEvent') {
                     $vEvent = $components[$key];
                     $resource = new Horde_Itip_Resource_Identity($injector->getInstance('IMP_Identity'), $vEvent->getAttribute('ATTENDEE'), $vars->identity);
                     switch ($action) {
                         case 'accept':
                         case 'accept-import':
                             $type = new Horde_Itip_Response_Type_Accept($resource);
                             break;
                         case 'deny':
                             $type = new Horde_Itip_Response_Type_Decline($resource);
                             break;
                         case 'tentative':
                             $type = new Horde_Itip_Response_Type_Tentative($resource);
                             break;
                     }
                     try {
                         // Send the reply.
                         Horde_Itip::factory($vEvent, $resource)->sendMultiPartResponse($type, new Horde_Core_Itip_Response_Options_Horde('UTF-8', array()), $injector->getInstance('IMP_Mail'));
                         $notification->push(_("Reply Sent."), 'horde.success');
                         $result = true;
                     } catch (Horde_Itip_Exception $e) {
                         $notification->push(sprintf(_("Error sending reply: %s."), $e->getMessage()), 'horde.error');
                     }
                 } else {
                     $notification->push(_("This action is not supported."), 'horde.warning');
                 }
                 break;
             case 'send':
             case 'reply':
             case 'reply2m':
                 // vfreebusy request.
                 if (isset($components[$key]) && $components[$key]->getType() == 'vFreebusy') {
                     $vFb = $components[$key];
                     // Get the organizer details.
                     try {
                         $organizer = parse_url($vFb->getAttribute('ORGANIZER'));
                     } catch (Horde_Icalendar_Exception $e) {
                         break;
                     }
                     $organizerEmail = $organizer['path'];
                     $organizer = $vFb->getAttribute('ORGANIZER', true);
                     $organizerFullEmail = new Horde_Mail_Rfc822_Address($organizerEmail);
                     if (isset($organizer['cn'])) {
                         $organizerFullEmail->personal = $organizer['cn'];
                     }
                     if ($action == 'reply2m') {
                         $startStamp = time();
                         $endStamp = $startStamp + 60 * 24 * 3600;
                     } else {
                         try {
                             $startStamp = $vFb->getAttribute('DTSTART');
                         } catch (Horde_Icalendar_Exception $e) {
                             $startStamp = time();
                         }
                         try {
                             $endStamp = $vFb->getAttribute('DTEND');
                         } catch (Horde_Icalendar_Exception $e) {
                         }
                         if (!$endStamp) {
                             try {
                                 $duration = $vFb->getAttribute('DURATION');
                                 $endStamp = $startStamp + $duration;
                             } catch (Horde_Icalendar_Exception $e) {
                                 $endStamp = $startStamp + 60 * 24 * 3600;
                             }
                         }
                     }
                     $vfb_reply = $registry->call('calendar/getFreeBusy', array($startStamp, $endStamp));
                     // Find out who we are and update status.
                     $identity = $injector->getInstance('IMP_Identity');
                     $email = $identity->getFromAddress();
                     // Build the reply.
                     $msg_headers = new Horde_Mime_Headers();
                     $vCal = new Horde_Icalendar();
                     $vCal->setAttribute('PRODID', '-//The Horde Project//' . $msg_headers->getUserAgent() . '//EN');
                     $vCal->setAttribute('METHOD', 'REPLY');
                     $vCal->addComponent($vfb_reply);
                     $message = _("Attached is a reply to a calendar request you sent.");
                     $body = new Horde_Mime_Part();
                     $body->setType('text/plain');
                     $body->setCharset('UTF-8');
                     $body->setContents(Horde_String::wrap($message, 76));
                     $ics = new Horde_Mime_Part();
                     $ics->setType('text/calendar');
                     $ics->setCharset('UTF-8');
                     $ics->setContents($vCal->exportvCalendar());
                     $ics->setName('icalendar.ics');
                     $ics->setContentTypeParameter('METHOD', 'REPLY');
                     $mime = new Horde_Mime_Part();
                     $mime->addPart($body);
                     $mime->addPart($ics);
                     // Build the reply headers.
                     $msg_headers->addReceivedHeader(array('dns' => $injector->getInstance('Net_DNS2_Resolver'), 'server' => $conf['server']['name']));
                     $msg_headers->addMessageIdHeader();
                     $msg_headers->addHeader('Date', date('r'));
                     $msg_headers->addHeader('From', $email);
                     $msg_headers->addHeader('To', $organizerFullEmail);
                     $identity->setDefault($vars->identity);
                     $replyto = $identity->getValue('replyto_addr');
                     if (!empty($replyto) && !$email->match($replyto)) {
                         $msg_headers->addHeader('Reply-To', $replyto);
                     }
                     $msg_headers->addHeader('Subject', _("Free/Busy Request Response"));
                     // Send the reply.
                     try {
                         $mime->send($organizerEmail, $msg_headers, $injector->getInstance('IMP_Mail'));
                         $notification->push(_("Reply Sent."), 'horde.success');
                         $result = true;
                     } catch (Exception $e) {
                         $notification->push(sprintf(_("Error sending reply: %s."), $e->getMessage()), 'horde.error');
                     }
                 } else {
                     $notification->push(_("Invalid Action selected for this component."), 'horde.warning');
                 }
                 break;
             case 'nosup':
                 // vFreebusy request.
             // vFreebusy request.
             default:
                 $notification->push(_("This action is not supported."), 'horde.warning');
                 break;
         }
     }
     return $result;
 }
Example #24
0
 /**
  * Return the response as a MIME message.
  *
  * @param Horde_Itip_Response_Type $type       The response type.
  * @param Horde_Itip_Response_Options $options The options for the response.
  *
  * @return array A list of two object: The mime headers and the mime
  *               message.
  */
 public function getMultiPartMessage(Horde_Itip_Response_Type $type, Horde_Itip_Response_Options $options)
 {
     $message = new Horde_Mime_Part();
     $message->setType('multipart/alternative');
     list($headers, $ics) = $this->getMessage($type, $options);
     $body = new Horde_Mime_Part();
     $body->setType('text/plain');
     $options->prepareMessageMimePart($body);
     $body->setContents(Horde_String::wrap($type->getMessage(), 76));
     $message->addPart($body);
     $message->addPart($ics);
     return array($headers, $message);
 }
Example #25
0
 /**
  * Return a Mime object representing the entire message.
  *
  * @return Horde_Mime_Part  The Mime object.
  */
 public function getMimeObject()
 {
     $this->_stream->rewind();
     $part = Horde_Mime_Part::parseMessage($this->_stream->getString());
     $part->isBasePart(true);
     return $part;
 }
Example #26
0
 /**
  * Retrieve locally cached message data.
  *
  * @param string $type    Either 'hdr', 'hdrob', 'msg', 'size', 'stat',
  *                        'top', or 'uidl'.
  * @param integer $index  The message index.
  * @param mixed $data     Additional information needed.
  *
  * @return mixed  The cached data. 'msg' returns a stream resource. All
  *                other types return strings.
  *
  * @throws Horde_Imap_Client_Exception
  */
 protected function _pop3Cache($type, $index = self::MBOX_CACHE, $data = null)
 {
     if (isset($this->_temp['pop3cache'][$index][$type])) {
         if ($type == 'msg') {
             rewind($this->_temp['pop3cache'][$index][$type]);
         }
         return $this->_temp['pop3cache'][$index][$type];
     }
     switch ($type) {
         case 'hdr':
         case 'top':
             $data = null;
             if ($type == 'top' || $this->_capability('TOP')) {
                 try {
                     $res = $this->_sendLine('TOP ' . $index . ' 0', array('multiline' => 'stream'));
                     rewind($res['data']);
                     $data = stream_get_contents($res['data']);
                     fclose($res['data']);
                 } catch (Horde_Imap_Client_Exception $e) {
                     $this->_temp['no_top'] = true;
                     if ($type == 'top') {
                         return null;
                     }
                 }
             }
             if (is_null($data)) {
                 $data = Horde_Mime_Part::getRawPartText(stream_get_contents($this->_pop3Cache('msg', $index)), 'header', 0);
             }
             break;
         case 'hdrob':
             $data = Horde_Mime_Headers::parseHeaders($this->_pop3Cache('hdr', $index));
             break;
         case 'msg':
             $res = $this->_sendLine('RETR ' . $index, array('multiline' => 'stream'));
             $data = $res['data'];
             rewind($data);
             break;
         case 'size':
         case 'uidl':
             $data = array();
             try {
                 $res = $this->_sendLine($type == 'size' ? 'LIST' : 'UIDL', array('multiline' => 'array'));
                 foreach ($res['data'] as $val) {
                     $resp_data = explode(' ', $val, 2);
                     $data[$resp_data[0]] = $resp_data[1];
                 }
             } catch (Horde_Imap_Client_Exception $e) {
                 if ($type == 'uidl') {
                     $this->_temp['no_uidl'] = true;
                 }
             }
             break;
         case 'stat':
             $resp = $this->_sendLine('STAT');
             $resp_data = explode(' ', $resp['resp'], 2);
             $data = array('msgs' => $resp_data[0], 'size' => $resp_data[1]);
             break;
     }
     $this->_temp['pop3cache'][$index][$type] = $data;
     return $data;
 }
Example #27
0
 /**
  * Recursively parse BODYSTRUCTURE data from a FETCH return (see
  * RFC 3501 [7.4.2]).
  *
  * @param Horde_Imap_Client_Tokenize $data  Data returned from the server.
  *
  * @return Horde_Mime_Part  Mime part object.
  */
 protected function _parseBodystructure(Horde_Imap_Client_Tokenize $data)
 {
     $ob = new Horde_Mime_Part();
     // If index 0 is an array, this is a multipart part.
     if (($entry = $data->next()) === true) {
         do {
             $ob->addPart($this->_parseBodystructure($data));
         } while (($entry = $data->next()) === true);
         // The subpart type.
         $ob->setType('multipart/' . $entry);
         // After the subtype is further extension information. This
         // information MAY appear for BODYSTRUCTURE requests.
         // This is parameter information.
         if (($tmp = $data->next()) === false) {
             return $ob;
         } elseif ($tmp === true) {
             foreach ($this->_parseStructureParams($data, 'content-type') as $key => $val) {
                 $ob->setContentTypeParameter($key, $val);
             }
         }
     } else {
         $ob->setType($entry . '/' . $data->next());
         if ($data->next() === true) {
             foreach ($this->_parseStructureParams($data, 'content-type') as $key => $val) {
                 $ob->setContentTypeParameter($key, $val);
             }
         }
         if (!is_null($tmp = $data->next())) {
             $ob->setContentId($tmp);
         }
         if (!is_null($tmp = $data->next())) {
             $ob->setDescription(Horde_Mime::decode($tmp));
         }
         if (!is_null($tmp = $data->next())) {
             $ob->setTransferEncoding($tmp);
         }
         $ob->setBytes($data->next());
         // If the type is 'message/rfc822' or 'text/*', several extra
         // fields are included
         switch ($ob->getPrimaryType()) {
             case 'message':
                 if ($ob->getSubType() == 'rfc822') {
                     if ($data->next() === true) {
                         // Ignore: envelope
                         $data->flushIterator(false);
                     }
                     if ($data->next() === true) {
                         $ob->addPart($this->_parseBodystructure($data));
                     }
                     $data->next();
                     // Ignore: lines
                 }
                 break;
             case 'text':
                 $data->next();
                 // Ignore: lines
                 break;
         }
         // After the subtype is further extension information. This
         // information MAY appear for BODYSTRUCTURE requests.
         // Ignore: MD5
         if ($data->next() === false) {
             return $ob;
         }
     }
     // This is disposition information
     if (($tmp = $data->next()) === false) {
         return $ob;
     } elseif ($tmp === true) {
         $ob->setDisposition($data->next());
         if ($data->next() === true) {
             foreach ($this->_parseStructureParams($data, 'content-disposition') as $key => $val) {
                 $ob->setDispositionParameter($key, $val);
             }
         }
         $data->next();
     }
     // This is language information. It is either a single value or a list
     // of values.
     if (($tmp = $data->next()) === false) {
         return $ob;
     } elseif (!is_null($tmp)) {
         $ob->setLanguage($tmp === true ? $data->flushIterator() : $tmp);
     }
     // Ignore location (RFC 2557) and consume closing paren.
     $data->flushIterator(false);
     return $ob;
 }
Example #28
0
 /**
  * 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;
 }
Example #29
0
 /**
  * Strips one or all MIME parts out of a message.
  *
  * @param string $partid  The MIME ID of the part to strip. All parts are
  *                        stripped if null.
  *
  * @return IMP_Indices  Returns the new indices object.
  * @throws IMP_Exception
  */
 public function stripPart($partid = null)
 {
     global $injector;
     list($mbox, $uid) = $this->getSingle();
     if (!$uid) {
         return;
     }
     if ($mbox->readonly) {
         throw new IMP_Exception(_("Cannot strip the part as the mailbox is read-only."));
     }
     $uidvalidity = $mbox->uidvalid;
     $contents = $injector->getInstance('IMP_Factory_Contents')->create($this);
     $message = $contents->getMIMEMessage();
     $boundary = trim($message->getContentTypeParameter('boundary'), '"');
     $url = new Horde_Imap_Client_Url();
     $url->mailbox = $mbox;
     $url->uid = $uid;
     $url->uidvalidity = $uidvalidity;
     $imp_imap = $mbox->imp_imap;
     /* Always add the header to output. */
     $url->section = 'HEADER';
     $parts = array(array('t' => 'url', 'v' => strval($url)));
     for ($id = 1;; ++$id) {
         if (!($part = $message[$id])) {
             break;
         }
         $parts[] = array('t' => 'text', 'v' => "\r\n--" . $boundary . "\r\n");
         if ($id != 1 && is_null($partid) || $id == $partid) {
             $newPart = new Horde_Mime_Part();
             $newPart->setType('text/plain');
             /* Need to make sure all text is in the correct charset. */
             $newPart->setCharset('UTF-8');
             $newPart->setContents(sprintf(_("[Part stripped: Original part type: %s, name: %s]"), $part->getType(), $contents->getPartName($part)));
             $newPart->setDisposition('attachment');
             $parts[] = array('t' => 'text', 'v' => $newPart->toString(array('canonical' => true, 'headers' => true, 'stream' => true)));
         } else {
             $url->section = $id . '.MIME';
             $parts[] = array('t' => 'url', 'v' => strval($url));
             $url->section = $id;
             $parts[] = array('t' => 'url', 'v' => strval($url));
         }
     }
     $parts[] = array('t' => 'text', 'v' => "\r\n--" . $boundary . "--\r\n");
     /* Get the headers for the message. */
     $query = new Horde_Imap_Client_Fetch_Query();
     $query->imapDate();
     $query->flags();
     try {
         $res = $imp_imap->fetch($mbox, $query, array('ids' => $imp_imap->getIdsOb($uid)))->first();
         if (is_null($res)) {
             throw new IMP_Imap_Exception();
         }
         $flags = $res->getFlags();
         /* If in Virtual Inbox, we need to reset flag to unseen so that it
          * appears again in the mailbox list. */
         if ($mbox->vinbox) {
             $flags = array_values(array_diff($flags, array(Horde_Imap_Client::FLAG_SEEN)));
         }
         $new_uid = $imp_imap->append($mbox, array(array('data' => $parts, 'flags' => $flags, 'internaldate' => $res->getImapDate())))->ids;
         $new_uid = reset($new_uid);
     } catch (IMP_Imap_Exception $e) {
         throw new IMP_Exception(_("An error occured while attempting to strip the part."));
     }
     $this->delete(array('keeplog' => true, 'nuke' => true));
     $indices_ob = $mbox->getIndicesOb($new_uid);
     /* We need to replace the old UID(s) in the URL params. */
     $vars = $injector->getInstance('Horde_Variables');
     if (isset($vars->buid)) {
         list(, $vars->buid) = $mbox->toBuids($indices_ob)->getSingle();
     }
     if (isset($vars->uid)) {
         $vars->uid = $new_uid;
     }
     return $indices_ob;
 }
Example #30
0
File: Mime.php Project: horde/horde
 /**
  * Converts armored input into a Horde_Mime_Part object.
  *
  * @param mixed $input  Armored input.
  * @param array $opts   Additional options:
  *   - charset: (string) Charset of the armored input.
  *
  * @return mixed  Either null if no PGP data was found, or a
  *                Horde_Mime_Part object.
  */
 public function armorToPart($input, array $opts = array())
 {
     $opts = array_merge(array('charset' => 'UTF-8'), $opts);
     $armor = Horde_Pgp_Armor::create($input);
     $new_part = new Horde_Mime_Part();
     $new_part->setType('multipart/mixed');
     foreach ($armor as $val) {
         switch (get_class($val)) {
             case 'Horde_Pgp_Element_Text':
                 $part = new Horde_Mime_Part();
                 $part->setType('text/plain');
                 $part->setCharset($opts['charset']);
                 $part->setContents($val->message[0]->data);
                 $new_part[] = $part;
                 break;
             case 'Horde_Pgp_Element_PrivateKey':
             case 'Horde_Pgp_Element_PublicKey':
                 $part = new Horde_Mime_Part();
                 $part->setType('application/pgp-keys');
                 $part->setContents(strval($val));
                 $new_part[] = $part;
                 break;
             case 'Horde_Pgp_Element_Message':
                 // TODO: Message can also be text or signature
                 $part = $this->_encryptBase($val);
                 $part->setMetadata(self::PGP_ARMOR, true);
                 $part['2']->setMetadata(self::PGP_CHARSET, isset($val->headers['Charset']) ? $val->headers['Charset'] : 'UTF-8');
                 $new_part[] = $part;
                 break;
             case 'Horde_Pgp_Element_SignedMessage':
                 $part = $this->_signPart($val->text, $val->signature);
                 $new_part[] = $part;
                 break;
         }
     }
     return count($new_part->getParts()) ? $new_part : null;
 }