/** * 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'); }
public function testGenerate() { $h = new Horde_Mime_Headers(); $ob = new Horde_Mime_Mdn($h); try { $ob->generate(true, true, 'deleted', 'foo', null); $this->fail('Expected Exception'); } catch (RuntimeException $e) { } $date = 'Tue, 18 Nov 2014 20:14:17 -0700'; $mdn_addr = 'Aäb <*****@*****.**>'; $h->addHeader('Date', $date); $h->addHeader('Subject', 'Test'); $h->addHeader('To', '"BAR" <*****@*****.**>'); $ob->addMdnRequestHeaders($mdn_addr); $mailer = new Horde_Mail_Transport_Mock(); $ob->generate(true, true, 'displayed', 'test.example.com', $mailer, array('from_addr' => '*****@*****.**'), array('error'), array('error' => 'Foo')); $sent = str_replace("\r\n", "\n", $mailer->sentMessages[0]); $this->assertEquals('auto-replied', $sent['headers']['Auto-Submitted']); $this->assertEquals('*****@*****.**', $sent['headers']['From']); $this->assertEquals($mdn_addr, Horde_Mime::decode($sent['headers']['To'])); $this->assertEquals('Disposition Notification', $sent['headers']['Subject']); $this->assertStringMatchesFormat('This message is in MIME format. --=%s Content-Type: text/plain; format=flowed; DelSp=Yes The message sent on Tue, 18 Nov 2014 20:14:17 -0700 to BAR <*****@*****.**> with subject "Test" has been displayed. This is no guarantee that the message has been read or understood. --=%s Content-Type: message/disposition-notification Reporting-UA: test.example.com; Horde Application Framework 5 Final-Recipient: rfc822;bar@example.com Disposition: manual-action/MDN-sent-manually; displayed/error Error: Foo --=%s Content-Type: message/rfc822 Date: Tue, 18 Nov 2014 20:14:17 -0700 Subject: Test To: BAR <*****@*****.**> Disposition-Notification-To: =?utf-8?b?QcOkYg==?= <*****@*****.**> --=%s ', $sent['body']); }
/** */ 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; }
public function userConfirmationNeededProvider() { $out = array(); $h = new Horde_Mime_Headers(); $out[] = array(clone $h, true); $h->addHeader('Return-Path', '*****@*****.**'); $out[] = array(clone $h, false); $h->addHeader('Return-Path', '*****@*****.**'); $out[] = array(clone $h, true); $h->replaceHeader('Return-Path', '*****@*****.**'); $h->addHeader(Horde_Mime_Mdn::MDN_HEADER, '*****@*****.**'); $out[] = array(clone $h, true); $h->replaceHeader(Horde_Mime_Mdn::MDN_HEADER, '*****@*****.**'); $out[] = array(clone $h, false); return $out; }
/** * Adds a message header. * * @param string $header The header name. * @param string $value The header value. * @param boolean $overwrite If true, an existing header of the same name * is being overwritten; if false, multiple * headers are added; if null, the correct * behaviour is automatically chosen depending * on the header name. * * @throws Horde_Mime_Exception */ public function addHeader($header, $value, $overwrite = null) { $lc_header = Horde_String::lower($header); if (is_null($overwrite) && in_array($lc_header, $this->_headers->singleFields(true))) { $overwrite = true; } if ($overwrite) { $this->_headers->removeHeader($header); } if ($lc_header === 'bcc') { $this->_bcc = $value; } else { $this->_headers->addHeader($header, $value); } }
/** */ public function __set($name, $value) { if (!strlen($value)) { return; } switch ($name) { case 'bcc': case 'cc': case 'date': case 'from': case 'in_reply_to': case 'message_id': case 'reply_to': case 'sender': case 'subject': case 'to': switch ($name) { case 'from': foreach (array('reply_to', 'sender') as $val) { if ($this->{$val}->match($value)) { $this->_data->removeHeader($val); } } break; case 'reply_to': case 'sender': if ($this->from->match($value)) { $this->_data->removeHeader($name); return; } /* Convert reply-to name. */ if ($name == 'reply_to') { $name = 'reply-to'; } break; } $this->_data->addHeader($name, $value, array('sanity_check' => true)); break; } }
/** */ public function __set($name, $value) { if (!strlen($value)) { return; } $name = $this->_normalizeProperty($name); switch ($name) { case 'bcc': case 'cc': case 'date': case 'from': case 'in-reply-to': case 'message-id': case 'reply-to': case 'sender': case 'subject': case 'to': switch ($name) { case 'from': if ($this->reply_to->match($value)) { unset($this->_data['reply-to']); } if ($this->sender->match($value)) { unset($this->_data['sender']); } break; case 'reply-to': case 'sender': if ($this->from->match($value)) { unset($this->_data[$name]); return; } break; } $this->_data->addHeader($name, $value); break; } }
public function testUndisclosedHeaderParsing() { $hdrs = new Horde_Mime_Headers(); $hdrs->addHeader('To', 'undisclosed-recipients'); $this->assertEquals('', $hdrs->getValue('To')); $hdrs = new Horde_Mime_Headers(); $hdrs->addHeader('To', 'undisclosed-recipients:'); $this->assertEquals('', $hdrs->getValue('To')); $hdrs = new Horde_Mime_Headers(); $hdrs->addHeader('To', 'undisclosed-recipients:;'); $this->assertEquals('', $hdrs->getValue('To')); }
/** * Builds a Horde_Mime_Headers object from header text. * * @param mixed $text A text string (or, as of 2.3.0, a Horde_Stream * object or stream resource) containing the headers. * * @return Horde_Mime_Headers A new Horde_Mime_Headers object. */ public static function parseHeaders($text) { $curr = null; $headers = new Horde_Mime_Headers(); $hdr_list = array(); if ($text instanceof Horde_Stream) { $stream = $text; $stream->rewind(); } else { $stream = new Horde_Stream_Temp(); $stream->add($text, true); } while (!$stream->eof()) { if (!($val = rtrim($stream->getToChar("\n", false), "\r"))) { break; } if ($curr && ($val[0] == ' ' || $val[0] == "\t")) { $curr->text .= ' ' . ltrim($val); } else { $pos = strpos($val, ':'); $curr = new stdClass(); $curr->header = substr($val, 0, $pos); $curr->text = ltrim(substr($val, $pos + 1)); $hdr_list[] = $curr; } } foreach ($hdr_list as $val) { /* When parsing, only keep the FIRST header seen for single value * text-only headers, since newer headers generally are appended * to the top of the message. */ if (!($ob = $headers[$val->header]) || !$ob instanceof Horde_Mime_Headers_Element_Single || $ob instanceof Horde_Mime_Headers_Addresses) { $headers->addHeader($val->header, rtrim($val->text)); } } if (!$text instanceof Horde_Stream) { $stream->close(); } return $headers; }
/** * Generate the headers for the MIME envelope of a Kolab groupware object. * * @param string $user The current user. * * @return Horde_Mime_Headers The headers for the MIME envelope. */ protected function createEnvelopeHeaders() { $headers = new Horde_Mime_Headers(); $headers->setEOL("\r\n"); $headers->addHeader('From', $this->_getDriver()->getAuth()); $headers->addHeader('To', $this->_getDriver()->getAuth()); $headers->addHeader('Date', date('r')); $headers->addHeader('Subject', $this->getUid()); $headers->addHeader('User-Agent', 'Horde_Kolab_Storage ' . Horde_Kolab_Storage::VERSION); $headers->addHeader('MIME-Version', '1.0'); $headers->addHeader('X-Kolab-Type', Horde_Kolab_Storage_Object_MimeType::getMimeTypeFromObjectType($this->getType())); return $headers; }
/** * Send notification to attachment owner. */ public function sendNotification() { global $conf, $injector, $registry; if (empty($conf['compose']['link_attachments_notify'])) { return; } try { $identity = $injector->getInstance('Horde_Core_Factory_Identity')->create($this->_user); $address = $identity->getDefaultFromAddress(); /* Ignore missing addresses, which are returned as <>. */ if (strlen($address) < 3 || $this->_getDeleteToken()) { return; } $address_full = $identity->getDefaultFromAddress(true); /* Load user prefs to correctly translate gettext strings. */ if (!$registry->getAuth()) { $prefs = $injector->getInstance('Horde_Core_Factory_Prefs')->create('imp', array('user' => $this->_user)); $registry->setLanguageEnvironment($prefs->getValue('language')); } $h = new Horde_Mime_Headers(); $h->addReceivedHeader(array('dns' => $injector->getInstance('Net_DNS2_Resolver'), 'server' => $conf['server']['name'])); $h->addMessageIdHeader(); $h->addUserAgentHeader(); $h->addHeader('Date', date('r')); $h->addHeader('From', $address_full); $h->addHeader('To', $address_full); $h->addHeader('Subject', _("Notification: Linked attachment downloaded")); $h->addHeader('Auto-Submitted', 'auto-generated'); $msg = new Horde_Mime_Part(); $msg->setType('text/plain'); $msg->setCharset('UTF-8'); $md = $this->_atc->getMetadata(); $msg->setContents(Horde_String::wrap(_("Your linked attachment has been downloaded by at least one user.") . "\n\n" . sprintf(_("Name: %s"), $md->filename) . "\n" . sprintf(_("Type: %s"), $md->type) . "\n" . sprintf(_("Sent Date: %s"), date('r', $md->time)) . "\n\n" . _("Click on the following link to permanently delete the attachment:") . "\n" . strval($this->_atc->link_url->add('d', $this->_getDeleteToken(true))))); $msg->send($address, $h, $injector->getInstance('Horde_Mail')); } catch (Exception $e) { Horde::log($e, 'ERR'); } }
/** * @dataProvider headerGenerationProvider */ public function testHeaderGeneration($label, $data, $class) { $hdrs = new Horde_Mime_Headers(); $this->assertNull($hdrs[$label]); $hdrs->addHeader($label, $data); $ob = $hdrs[$label]; $this->assertNotNull($ob); $this->assertInstanceOf($class, $ob); }
/** * Get a Horde_Mime object representint the data contained in this object. * * [MS_ASEMAIL 3.1.53] * * @return array An array containing: * - part: Horde_Mime_Part containing the body data NO ATTACHMENTS. * - headers: Horde_Mime_Headers containing the envelope headers. */ public function draftToMime() { // Main text body. $text = new Horde_Mime_Part(); $body = $this->airsyncbasebody; $text->setContents($body->data); if ($body->type == Horde_ActiveSync::BODYPREF_TYPE_HTML) { $text->setType('text/html'); } else { $text->setType('text/plain'); } // Add headers that are sent with ADD; $headers = new Horde_Mime_Headers(); if ($this->to) { $headers->addHeader('To', $this->to); } if ($this->cc) { $headers->addHeader('Cc', $this->cc); } if ($this->subject) { $headers->addHeader('Subject', $this->subject); } if ($this->bcc) { $headers->addHeader('Bcc', $this->bcc); } if ($this->reply_to) { $headers->addHeader('reply-to', $this->reply_to); } if ($this->importance) { $headers->addHeader('importance', $this->importance); } return array('part' => $text, 'headers' => $headers); }
/** * Send a redirect (a/k/a resent) message. See RFC 5322 [3.6.6]. * * @param mixed $to The addresses to redirect to. * @param boolean $log Whether to log the resending in the history and * sentmail log. * * @return array An object with the following properties for each * redirected message: * - contents: (IMP_Contents) The contents object. * - headers: (Horde_Mime_Headers) The header object. * - mbox: (IMP_Mailbox) Mailbox of the message. * - uid: (string) UID of the message. * * @throws IMP_Compose_Exception */ public function sendRedirectMessage($to, $log = true) { global $injector, $registry; $recip = $this->recipientList(array('to' => $to)); $identity = $injector->getInstance('IMP_Identity'); $from_addr = $identity->getFromAddress(); $out = array(); foreach ($this->getMetadata('redirect_indices') as $val) { foreach ($val->uids as $val2) { try { $contents = $injector->getInstance('IMP_Factory_Contents')->create($val->mbox->getIndicesOb($val2)); } catch (IMP_Exception $e) { throw new IMP_Compose_Exception(_("Error when redirecting message.")); } $headers = $contents->getHeader(); /* We need to set the Return-Path header to the current user - * see RFC 2821 [4.4]. */ $headers->removeHeader('return-path'); $headers->addHeader('Return-Path', $from_addr); /* Generate the 'Resent' headers (RFC 5322 [3.6.6]). These * headers are prepended to the message. */ $resent_headers = new Horde_Mime_Headers(); $resent_headers->addHeader('Resent-Date', date('r')); $resent_headers->addHeader('Resent-From', $from_addr); $resent_headers->addHeader('Resent-To', $recip['header']['to']); $resent_headers->addHeader('Resent-Message-ID', Horde_Mime_Headers_MessageId::create()); $header_text = trim($resent_headers->toString(array('encode' => 'UTF-8'))) . "\n" . trim($contents->getHeader(IMP_Contents::HEADER_TEXT)); $this->_prepSendMessageAssert($recip['list']); $to = $this->_prepSendMessage($recip['list']); $hdr_array = $headers->toArray(array('charset' => 'UTF-8')); $hdr_array['_raw'] = $header_text; try { $injector->getInstance('IMP_Mail')->send($to, $hdr_array, $contents->getBody()); } catch (Horde_Mail_Exception $e) { $e2 = new IMP_Compose_Exception($e); if (($prev = $e->getPrevious()) && $prev instanceof Horde_Smtp_Exception) { if ($prev instanceof Horde_Smtp_Exception_Recipients) { $e2 = new IMP_Compose_Exception_Addresses($e); foreach ($prev->recipients as $val) { $e2->addAddress(new Horde_Mail_Rfc822_Address($val), _("Address rejected by the sending mail server."), $e2::BAD); } } Horde::log(sprintf("SMTP Error: %s (%u; %s)", $prev->raw_msg, $prev->getCode(), $prev->getEnhancedSmtpCode() ?: 'N/A'), 'ERR'); $e2->logged = true; } throw $e2; } $recipients = strval($recip['list']); Horde::log(sprintf("%s Redirected message sent to %s from %s", $_SERVER['REMOTE_ADDR'], $recipients, $registry->getAuth()), 'INFO'); if ($log && ($tmp = $headers['Message-ID'])) { $msg_id = reset($tmp->getIdentificationOb()->ids); /* Store history information. */ $injector->getInstance('IMP_Maillog')->log(new IMP_Maillog_Message($msg_id), new IMP_Maillog_Log_Redirect(array('msgid' => reset($resent_headers->getIdentificationOb()->ids), 'recipients' => $recipients))); $injector->getInstance('IMP_Sentmail')->log(IMP_Sentmail::REDIRECT, $msg_id, $recipients); } $tmp = new stdClass(); $tmp->contents = $contents; $tmp->headers = $headers; $tmp->mbox = $val->mbox; $tmp->uid = $val2; $out[] = $tmp; } } return $out; }
/** * @dataProvider getObjectAndMimeTypes */ public function testMatchMimePartToHeaderType($type, $mime_type) { $headers = new Horde_Mime_Headers(); $headers->addHeader('X-Kolab-Type', $mime_type); $this->assertEquals(array(2, $type), Horde_Kolab_Storage_Object_MimeType::matchMimePartToHeaderType($this->getMultipartMimeMessage($mime_type), $headers)); }
/** * Builds a Horde_Mime_Headers object from header text. * * @param mixed $text A text string (or, as of 2.3.0, a Horde_Stream * object or stream resource) containing the headers. * * @return Horde_Mime_Headers A new Horde_Mime_Headers object. */ public static function parseHeaders($text) { $currheader = $currtext = null; $mime = self::mimeParamFields(); $to_process = array(); if ($text instanceof Horde_Stream) { $stream = $text; $stream->rewind(); } else { $stream = new Horde_Stream_Temp(); $stream->add($text, true); } while (!$stream->eof()) { if (!($val = rtrim($stream->getToChar("\n", false), "\r"))) { break; } if ($val[0] == ' ' || $val[0] == "\t") { $currtext .= ' ' . ltrim($val); } else { if (!is_null($currheader)) { $to_process[] = array($currheader, rtrim($currtext)); } $pos = strpos($val, ':'); $currheader = substr($val, 0, $pos); $currtext = ltrim(substr($val, $pos + 1)); } } if (!is_null($currheader)) { $to_process[] = array($currheader, $currtext); } $headers = new Horde_Mime_Headers(); reset($to_process); while (list(, $val) = each($to_process)) { /* Ignore empty headers. */ if (!strlen($val[1])) { continue; } if (in_array(Horde_String::lower($val[0]), $mime)) { $res = Horde_Mime::decodeParam($val[0], $val[1]); $headers->addHeader($val[0], $res['val'], array('params' => $res['params'], 'sanity_check' => true)); } else { $headers->addHeader($val[0], $val[1], array('sanity_check' => true)); } } return $headers; }
/** */ public function replaceHeader($header, $value, array $opts = array()) { $this->_headers->removeHeader($header); $this->_headers->addHeader($header, $value, $opts); }
public function testBug14381() { $hdrs = new Horde_Mime_Headers(); $hdrs->addHeader('Date', 'Sat, 22 May 2016 01:41:04 0000'); $this->assertEquals($hdrs->getValue('Date'), 'Sat, 22 May 2016 01:41:04 +0000'); $hdrs = new Horde_Mime_Headers(); $hdrs->addHeader('Date', 'Sat, 22 May 2016 01:41:04 +0000'); $this->assertEquals($hdrs->getValue('Date'), 'Sat, 22 May 2016 01:41:04 +0000'); }
/** * 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 getMessage(Horde_Itip_Response_Type $type, Horde_Itip_Response_Options $options) { $message = new Horde_Mime_Part(); $message->setType('text/calendar'); $options->prepareIcsMimePart($message); $message->setContents($this->getIcalendar($type, $options)->exportvCalendar()); $message->setEOL("\r\n"); $this->_setIcsFilename($message); $message->setContentTypeParameter('METHOD', 'REPLY'); // Build the reply headers. $from = $this->_resource->getFrom(); $reply_to = $this->_resource->getReplyTo(); $headers = new Horde_Mime_Headers(); $headers->addHeaderOb(Horde_Mime_Headers_Date::create()); $headers->addHeader('From', $from); $headers->addHeader('To', $this->_request->getOrganizer()); if (!empty($reply_to) && $reply_to != $from) { $headers->addHeader('Reply-to', $reply_to); } $headers->addHeader('Subject', $type->getSubject()); $options->prepareResponseMimeHeaders($headers); return array($headers, $message); }
/** * Sends this message. * * @param Mail $mailer A Mail object. * @param boolean $resend If true, the message id and date are re-used; * If false, they will be updated. * @param boolean $flowed Send message in flowed text format. * * @throws Horde_Mime_Exception */ public function send($mailer, $resend = false, $flowed = true) { /* Add mandatory headers if missing. */ $has_header = $this->_headers->getValue('Message-ID'); if (!$resend || !$has_header) { if ($has_header) { $this->_headers->removeHeader('Message-ID'); } $this->_headers->addMessageIdHeader(); } if (!$this->_headers->getValue('User-Agent')) { $this->_headers->addUserAgentHeader(); } $has_header = $this->_headers->getValue('Date'); if (!$resend || !$has_header) { if ($has_header) { $this->_headers->removeHeader('Date'); } $this->_headers->addHeader('Date', date('r')); } if (isset($this->_base)) { $basepart = $this->_base; } else { /* Send in flowed format. */ if ($flowed && !empty($this->_body)) { $flowed = new Horde_Text_Flowed($this->_body->getContents(), $this->_body->getCharset()); $flowed->setDelSp(true); $this->_body->setContentTypeParameter('format', 'flowed'); $this->_body->setContentTypeParameter('DelSp', 'Yes'); $this->_body->setContents($flowed->toFlowed()); } /* Build mime message. */ $body = new Horde_Mime_Part(); if (!empty($this->_body) && !empty($this->_htmlBody)) { $body->setType('multipart/alternative'); $this->_body->setDescription(Horde_Mime_Translation::t("Plaintext Version of Message")); $body->addPart($this->_body); $this->_htmlBody->setDescription(Horde_Mime_Translation::t("HTML Version of Message")); $body->addPart($this->_htmlBody); } elseif (!empty($this->_htmlBody)) { $body = $this->_htmlBody; } elseif (!empty($this->_body)) { $body = $this->_body; } if (count($this->_parts)) { $basepart = new Horde_Mime_Part(); $basepart->setType('multipart/mixed'); $basepart->isBasePart(true); if ($body) { $basepart->addPart($body); } foreach ($this->_parts as $mime_part) { $basepart->addPart($mime_part); } } else { $basepart = $body; $basepart->isBasePart(true); } } $basepart->setHeaderCharset($this->_charset); /* Build recipients. */ $recipients = clone $this->_recipients; foreach (array('to', 'cc') as $header) { $recipients->add($this->_headers->getOb($header)); } if ($this->_bcc) { $recipients->add($this->_bcc); } /* Trick Horde_Mime_Part into re-generating the message headers. */ $this->_headers->removeHeader('MIME-Version'); /* Send message. */ $recipients->unique(); $basepart->send($recipients->writeAddress(), $this->_headers, $mailer); /* Remember the basepart */ $this->_base = $basepart; }
/** * Builds and sends a digest message. * * @param array $messages List of message contents (string|resource). * @param integer $action Either Horde_Spam::SPAM or Horde_Spam::INNOCENT. * * @return integer The number of reported messages. */ protected function _reportDigest(array $messages, $action) { if (empty($messages)) { return 0; } /* Build the MIME structure. */ $mime = new Horde_Mime_Part(); $mime->setType('multipart/digest'); foreach ($messages as $val) { $rfc822 = new Horde_Mime_Part(); $rfc822->setType('message/rfc822'); $rfc822->setContents($val); $mime[] = $rfc822; } $spam_headers = new Horde_Mime_Headers(); $spam_headers->addHeaderOb(Horde_Mime_Headers_MessageId::create()); $spam_headers->addHeaderOb(Horde_Mime_Headers_Date::create()); $spam_headers->addHeader('To', $this->_email); $spam_headers->addHeader('From', $this->_from_addr); $spam_headers->addHeader('Subject', sprintf(Horde_Spam_Translation::t("%s report from %s"), $action === Horde_Spam::SPAM ? 'spam' : 'innocent', $this->_user)); /* Send the message. */ try { $mime->send($this->_email, $spam_headers, $this->_mail); return count($messages); } catch (Horde_Mail_Exception $e) { $this->_logger->warn($e); return 0; } }
/** * Add a MDN (read receipt) request header. * * @param mixed $to The address(es) the receipt should be mailed to. */ public function addMdnRequestHeaders($to) { /* This is the RFC 3798 way of requesting a receipt. */ $this->_headers->addHeader(self::MDN_HEADER, $to); }
public function headersProvider() { $hdrs = new Horde_Mime_Headers(); $hdrs->addHeader('From', '*****@*****.**'); return array(array(null, ''), array("From: test@example.com\n\n", "From: test@example.com\n\n"), array($hdrs, "From: test@example.com\n\n")); }
/** * Builds a Horde_Mime_Headers object from header text. * This function can be called statically: * $headers = Horde_Mime_Headers::parseHeaders(). * * @param string $text A text string containing the headers. * * @return Horde_Mime_Headers A new Horde_Mime_Headers object. */ public static function parseHeaders($text) { $currheader = $currtext = null; $mime = self::mimeParamFields(); $to_process = array(); foreach (explode("\n", $text) as $val) { $val = rtrim($val); if (empty($val)) { break; } if ($val[0] == ' ' || $val[0] == "\t") { $currtext .= ' ' . ltrim($val); } else { if (!is_null($currheader)) { $to_process[] = array($currheader, $currtext); } $pos = strpos($val, ':'); $currheader = substr($val, 0, $pos); $currtext = ltrim(substr($val, $pos + 1)); } } if (!is_null($currheader)) { $to_process[] = array($currheader, $currtext); } $headers = new Horde_Mime_Headers(); reset($to_process); while (list(, $val) = each($to_process)) { /* Ignore empty headers. */ if (!strlen($val[1])) { continue; } if (in_array(Horde_String::lower($val[0]), $mime)) { $res = Horde_Mime::decodeParam($val[0], $val[1]); $headers->addHeader($val[0], $res['val'], array('params' => $res['params'], 'sanity_check' => true)); } else { $headers->addHeader($val[0], $val[1], array('sanity_check' => true)); } } return $headers; }
/** */ public function report(array $msgs, $action) { global $injector; $ret = 0; switch ($this->_format) { case 'redirect': /* Send the message. */ foreach ($msgs as $val) { try { $imp_compose = $injector->getInstance('IMP_Factory_Compose')->create(); $imp_compose->redirectMessage($val->getIndicesOb()); $imp_compose->sendRedirectMessage($this->_email, false); ++$ret; } 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; } $self = $this; $reportDigest = function ($m) use($action, $from_line, $self) { global $injector, $registry; if (empty($m)) { return 0; } /* Build the MIME structure. */ $mime = new Horde_Mime_Part(); $mime->setType('multipart/digest'); foreach ($m as $val) { $rfc822 = new Horde_Mime_Part(); $rfc822->setType('message/rfc822'); $rfc822->setContents($val->fullMessageText(array('stream' => true))); $mime[] = $rfc822; } $spam_headers = new Horde_Mime_Headers(); $spam_headers->addHeaderOb(Horde_Mime_Headers_MessageId::create()); $spam_headers->addHeaderOb(Horde_Mime_Headers_Date::create()); $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 { $imp_compose = $injector->getInstance('IMP_Factory_Compose')->create(); $recip_list = $imp_compose->recipientList(array('to' => $this->_email)); $imp_compose->sendMessage($recip_list['list'], $spam_headers, $mime, 'UTF-8'); return count($m); } catch (IMP_Compose_Exception $e) { $e->log(); return 0; } }; $mlimit = $orig_mlimit = empty($this->_opts['digest_limit_msgs']) ? null : $this->_opts['digest_limit_msgs']; $slimit = $orig_slimit = empty($this->_opts['digest_limit_size']) ? null : $this->_opts['digest_limit_size']; $todo = array(); foreach ($msgs as $val) { $process = false; $todo[] = $val; if (!is_null($mlimit) && !--$mlimit) { $process = true; } if (!is_null($slimit) && ($slimit -= $val->getMIMEMessage()->getBytes()) < 0) { $process = true; /* If we have exceeded size limits with this single * message, it exceeds the maximum limit and we can't * send it at all. Don't confuse the user and instead * report is as a "success" for UI purposes. */ if (count($todo) === 1) { ++$ret; $todo = array(); Horde::log('Could not send spam/innocent reporting message because original message was too large.', 'NOTICE'); } } if ($process) { $ret += $reportDigest($todo); $todo = array(); $mlimit = $orig_mlimit; $slimit = $orig_slimit; } } $ret += $reportDigest($todo); break; } return $ret; }
/** * 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.") . ' ' . 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; }
/** * Send a redirect (a/k/a resent) message. See RFC 5322 [3.6.6]. * * @param mixed $to The addresses to redirect to. * @param boolean $log Whether to log the resending in the history and * sentmail log. * * @return array An object with the following properties for each * redirected message: * - contents: (IMP_Contents) The contents object. * - headers: (Horde_Mime_Headers) The header object. * - mbox: (IMP_Mailbox) Mailbox of the message. * - uid: (string) UID of the message. * * @throws IMP_Compose_Exception */ public function sendRedirectMessage($to, $log = true) { global $injector, $registry; $recip = $this->recipientList(array('to' => $to)); $identity = $injector->getInstance('IMP_Identity'); $from_addr = $identity->getFromAddress(); $out = array(); foreach ($this->getMetadata('redirect_indices') as $val) { foreach ($val->uids as $val2) { try { $contents = $injector->getInstance('IMP_Factory_Contents')->create($val->mbox->getIndicesOb($val2)); } catch (IMP_Exception $e) { throw new IMP_Compose_Exception(_("Error when redirecting message.")); } $headers = $contents->getHeader(); /* We need to set the Return-Path header to the current user - * see RFC 2821 [4.4]. */ $headers->removeHeader('return-path'); $headers->addHeader('Return-Path', $from_addr); /* Generate the 'Resent' headers (RFC 5322 [3.6.6]). These * headers are prepended to the message. */ $resent_headers = new Horde_Mime_Headers(); $resent_headers->addHeader('Resent-Date', date('r')); $resent_headers->addHeader('Resent-From', $from_addr); $resent_headers->addHeader('Resent-To', $recip['header']['to']); $resent_headers->addHeader('Resent-Message-ID', Horde_Mime::generateMessageId()); $header_text = trim($resent_headers->toString(array('encode' => 'UTF-8'))) . "\n" . trim($contents->getHeader(IMP_Contents::HEADER_TEXT)); $this->_prepSendMessageAssert($recip['list']); $to = $this->_prepSendMessage($recip['list']); $hdr_array = $headers->toArray(array('charset' => 'UTF-8')); $hdr_array['_raw'] = $header_text; try { $injector->getInstance('IMP_Mail')->send($to, $hdr_array, $contents->getBody()); } catch (Horde_Mail_Exception $e) { throw new IMP_Compose_Exception($e); } $recipients = strval($recip['list']); Horde::log(sprintf("%s Redirected message sent to %s from %s", $_SERVER['REMOTE_ADDR'], $recipients, $registry->getAuth()), 'INFO'); if ($log) { /* Store history information. */ $msg_id = new Horde_Mail_Rfc822_Identification($headers->getValue('message-id')); $injector->getInstance('IMP_Maillog')->log(new IMP_Maillog_Message(reset($msg_id->ids)), new IMP_Maillog_Log_Redirect($recipients)); $injector->getInstance('IMP_Sentmail')->log(IMP_Sentmail::REDIRECT, reset($msg_id->ids), $recipients); } $tmp = new stdClass(); $tmp->contents = $contents; $tmp->headers = $headers; $tmp->mbox = $val->mbox; $tmp->uid = $val2; $out[] = $tmp; } } return $out; }