public function testInsensitiveMatch() { $address = new Horde_Mail_Rfc822_Address('Test <*****@*****.**>'); $this->assertTrue($address->matchInsensitive('Foo <*****@*****.**>')); $this->assertTrue($address->matchInsensitive('Foo <*****@*****.**>')); $this->assertTrue($address->matchInsensitive('Foo <*****@*****.**>')); }
/** * @dataProvider commentOutputProvider */ public function testCommentOutput($expected, $params) { $ob = new Horde_Mail_Rfc822_Address(); foreach ($params as $key => $val) { $ob->{$key} = $val; } $this->assertEquals($expected, $ob->writeAddress(array('comment' => true))); }
/** * Constructor. * * @param string|Horde_Mail_Rfc822_Object $from The email address of the * original sender. * @param Horde_Mime_Headers $h The headers object for * the message. * @param string $attrib Use this for the * attribution config * instead of the default * prefs version. */ public function __construct($from, Horde_Mime_Headers $h, $attrib = null) { global $prefs; $this->_text = preg_replace_callback('/\\%./', function ($matches) use($from, $h) { switch ($matches[0]) { case '%n': /* New line. */ return "\n"; case '%%': /* Percent character. */ return '%'; case '%f': /* Name and email address of original sender. */ if ($from) { $from = new Horde_Mail_Rfc822_Address($from); return $from->writeAddress(array('noquote' => true)); } return _("Unknown Sender"); case '%a': /* Senders email address(es). */ /* Senders email address(es). */ case '%p': /* Senders name(s). */ $out = array(); foreach (IMP::parseAddressList($from) as $addr) { if ($matches[0] == '%a') { if (!is_null($addr->mailbox)) { $out[] = $addr->bare_address; } } else { $out[] = $addr->label; } } return count($out) ? implode(', ', $out) : _("Unknown Sender"); case '%r': /* RFC 822 date and time. */ return $h['Date']; case '%d': /* Date as ddd, dd mmm yyyy. */ return strftime("%a, %d %b %Y", strtotime($h['Date'])); case '%c': /* Date and time in locale's default. */ /* Date and time in locale's default. */ case '%x': /* Date in locale's default. */ return strftime($matches[0], strtotime($h['Date'])); case '%m': /* Message-ID. */ return strval($h['Message-Id']); case '%s': /* Message subject. */ return strlen($subject = $h['Subject']) ? $subject : _("[No Subject]"); default: return ''; } }, is_null($attrib) ? $prefs->getValue('attrib_text') : $attrib); }
/** * @dataProvider domainMatchProvider */ public function testDomainMatch($addr, $tests) { $address = new Horde_Mail_Rfc822_Address($addr); foreach ($tests as $val) { $match = $address->matchDomain($val[0]); if ($val[1]) { $this->assertTrue($match); } else { $this->assertFalse($match); } } }
public function testDomainMatch() { $address = new Horde_Mail_Rfc822_Address('Test <*****@*****.**>'); $this->assertTrue($address->matchDomain('example.com')); $this->assertFalse($address->matchDomain('foo.example.com')); $address2 = new Horde_Mail_Rfc822_Address('Test <*****@*****.**>'); $this->assertTrue($address2->matchDomain('example.com')); $this->assertTrue($address2->matchDomain('foo.example.com')); $address3 = new Horde_Mail_Rfc822_Address('Test <*****@*****.**>'); $this->assertTrue($address3->matchDomain('example.co.uk')); $this->assertFalse($address3->matchDomain('foo.example.co.uk')); $this->assertTrue($address3->matchDomain('co.uk')); $address4 = new Horde_Mail_Rfc822_Address('Test <*****@*****.**>'); $this->assertTrue($address4->matchDomain('example.co.uk')); $this->assertTrue($address4->matchDomain('foo.example.co.uk')); $this->assertTrue($address4->matchDomain('co.uk')); }
/** * Import an event response into a user's calendar. Used for updating * attendee information from a meeting response. * * @param Horde_Icalendar_vEvent $vEvent The event data. * @param string $attendee The attendee. */ public function calendar_import_attendee(Horde_Icalendar_vEvent $vEvent, $attendee) { if ($this->_registry->hasMethod('calendar/updateAttendee')) { // If the mail interface (i.e., IMP) provides a mime driver for // iTips, check if we are allowed to autoupdate. If we have no // configuration, err on the side of caution and DO NOT auto import. $config = $GLOBALS['injector']->getInstance('Horde_Core_Factory_MimeViewer')->getViewerConfig('text/calendar', $this->_registry->hasInterface('mail')); if ($config[1]['driver'] == 'Itip' && !empty($config[1]['auto_update_eventreply'])) { if (is_array($config[1]['auto_update_eventreply'])) { $adr = new Horde_Mail_Rfc822_Address($attendee); $have_match = false; foreach ($config[1]['auto_update_eventreply'] as $val) { if ($adr->matchDomain($val)) { $have_match = true; break; } } if (!$have_match) { return; } } try { $this->_registry->calendar->updateAttendee($vEvent, $attendee); } catch (Horde_Exception $e) { $this->_logger->err($e->getMessage()); } } } }
/** * Determine if we are going to auto-update the reply. * * @param string $type The type of reply. Must match one of the * 'auto_update_*' configuration keys in the iTip * mime viewer configuration. * @param string $sender The sender. * * @return boolean */ protected function _autoUpdateReply($type, $sender) { if (!empty($this->_conf[$type])) { if (is_array($this->_conf[$type])) { $ob = new Horde_Mail_Rfc822_Address($sender); foreach ($this->_conf[$type] as $val) { if ($ob->matchDomain($val)) { return true; } } } else { return true; } } return false; }
/** * Return the message's From: address. * * @return string The From address of this message. * @throws Horde_ActiveSync_Exception @since 2.27.0 */ public function getFromAddress() { $from = $this->envelope->from->addresses; try { $a = new Horde_Mail_Rfc822_Address(current($from)); } catch (Horde_ActiveSync_Exception $e) { throw new Horde_ActiveSync_Exception($e); } return $a->writeAddress(false); }
/** * Returns whether an email address matches this attendee. * * @param string $email An email address. * @param boolean $caseSensitive Whether to match case-sensitive. * * @return boolean True if the email address matches this attendee. */ public function matchesEmail($email, $caseSensitive) { $email = new Horde_Mail_Rfc822_Address($email); return $caseSensitive && $email->match($this->email) || !$caseSensitive && $email->matchInsensitive($this->email); }
/** * Checks to see whether the specified attendee is associated with the * current event. * * @param string $email The email address of the attendee. * @param boolean $case_sensitive Match in a case sensitive manner. * @since 4.3.0 * @return boolean True if the specified attendee is present for this * event. */ public function hasAttendee($email, $case_sensitive = false) { $email = new Horde_Mail_Rfc822_Address($email); foreach (array_keys($this->attendees) as $attendee) { if ($case_sensitive && $email->match($attendee) || !$case_sensitive && $email->matchInsensitive($email)) { return true; } } return false; }
} catch (Horde_Exception $e) { $notification->push($e); break; } if ($attachment && $registry->hasMethod('tickets/addAttachment')) { try { $registry->call('tickets/addAttachment', array('ticket_id' => $ticketId, 'name' => $attachment['name'], 'data' => file_get_contents($attachment['tmp_name']))); } catch (Horde_Exception $e) { $notification->push($e); } } $redirect_url->redirect(); } /* Add user's name to the email address if provided. */ if ($name) { $addr_ob = new Horde_Mail_Rfc822_Address($email); if (is_null($addr_ob->host)) { $addr_ob->host = $conf['problems']['maildomain']; } $addr_ob->personal = $name; $email = $addr_ob->writeAddress(true); } $mail = new Horde_Mime_Mail(array('body' => $body, 'Subject' => _("[Problem Report]") . ' ' . $subject, 'To' => $conf['problems']['email'], 'From' => $email)); $mail->addHeader('Sender', 'horde-problem@' . $conf['problems']['maildomain']); /* Add attachment. */ if ($attachment) { $mail->addAttachment($attachment['tmp_name'], $attachment['name'], $attachment['type']); } try { $mail->send($injector->getInstance('Horde_Mail')); /* Success. */
/** * Determines the reply text and headers for a message. * * @param integer $type The reply type (self::REPLY* constant). * @param IMP_Contents $contents An IMP_Contents object. * @param array $opts Additional options: * - format: (string) Force to this format. * DEFAULT: Auto-determine. * - to: (string) The recipient of the reply. Overrides the * automatically determined value. * * @return array An array with the following keys: * - addr: (array) Address lists (to, cc, bcc; Horde_Mail_Rfc822_List * objects). * - body: (string) The text of the body part. * - format: (string) The format of the body message (html, text). * - identity: (integer) The identity to use for the reply based on the * original message's addresses. * - lang: (array) Language code (keys)/language name (values) of the * original sender's preferred language(s). * - reply_list_id: (string) List ID label. * - reply_recip: (integer) Number of recipients in reply list. * - subject: (string) Formatted subject. * - type: (integer) The reply type used (either self::REPLY_ALL, * self::REPLY_LIST, or self::REPLY_SENDER). * @throws IMP_Exception */ public function replyMessage($type, $contents, array $opts = array()) { global $injector, $language, $prefs; if (!$contents instanceof IMP_Contents) { throw new IMP_Exception(_("Could not retrieve message data from the mail server.")); } $alist = new Horde_Mail_Rfc822_List(); $addr = array('to' => clone $alist, 'cc' => clone $alist, 'bcc' => clone $alist); $h = $contents->getHeader(); $match_identity = $this->_getMatchingIdentity($h); $reply_type = self::REPLY_SENDER; if (!$this->_replytype) { $this->_setMetadata('indices', $contents->getIndicesOb()); /* Set the Message-ID related headers (RFC 5322 [3.6.4]). */ if ($tmp = $h['Message-ID']) { $msg_id = $tmp->getIdentificationOb(); $msg_id = reset($msg_id->ids); if (strlen($msg_id)) { $this->_setMetadata('in_reply_to', $msg_id); } } else { $msg_id = null; } if ($tmp = $h['References']) { $ref_ob = $tmp->getIdentificationOb(); if (!count($ref_ob->ids) && ($tmp = $h['In-Reply-To'])) { $ref_ob = $tmp->getIdentificationOb(); if (count($ref_ob->ids) > 1) { $ref_ob->ids = array(); } } if (count($ref_ob->ids)) { $this->_setMetadata('references', array_merge($ref_ob->ids, array_filter(array($msg_id)))); } } } $subject = strlen($s = $h['Subject']) ? 'Re: ' . strval(new Horde_Imap_Client_Data_BaseSubject($s, array('keepblob' => true))) : 'Re: '; $force = false; if (in_array($type, array(self::REPLY_AUTO, self::REPLY_SENDER))) { if (isset($opts['to'])) { $addr['to']->add($opts['to']); $force = true; } elseif ($tmp = $h['reply-to']) { $addr['to']->add($tmp->getAddressList()); $force = true; } elseif ($tmp = $h['from']) { $addr['to']->add($tmp->getAddressList()); } } elseif ($type === self::REPLY_ALL) { $force = isset($h['reply-to']); } /* We might need $list_info in the reply_all section. */ $list_info = in_array($type, array(self::REPLY_AUTO, self::REPLY_LIST)) ? $contents->getListInformation() : null; if (!is_null($list_info) && !empty($list_info['reply_list'])) { /* If To/Reply-To and List-Reply address are the same, no need * to handle these address separately. */ $rlist = new Horde_Mail_Rfc822_Address($list_info['reply_list']); if (!$rlist->match($addr['to'])) { $addr['to'] = clone $alist; $addr['to']->add($rlist); $reply_type = self::REPLY_LIST; } } elseif (in_array($type, array(self::REPLY_ALL, self::REPLY_AUTO))) { /* Clear the To field if we are auto-determining addresses. */ if ($type == self::REPLY_AUTO) { $addr['to'] = clone $alist; } /* Filter out our own address from the addresses we reply to. */ $identity = $injector->getInstance('IMP_Identity'); $all_addrs = $identity->getAllFromAddresses(); /* Build the To: header. It is either: * 1) the Reply-To address (if not a personal address) * 2) the From address(es) (if it doesn't contain a personal * address) * 3) all remaining Cc addresses. */ $to_fields = array('from', 'reply-to'); foreach (array('reply-to', 'from', 'to', 'cc') as $val) { /* If either a reply-to or $to is present, we use this address * INSTEAD of the from address. */ if ($force && $val == 'from' || !($tmp = $h[$val])) { continue; } $ob = $tmp->getAddressList(true); /* For From: need to check if at least one of the addresses is * personal. */ if ($val == 'from') { foreach ($ob->raw_addresses as $addr_ob) { if ($all_addrs->contains($addr_ob)) { /* The from field contained a personal address. * Use the 'To' header as the primary reply-to * address instead. */ $to_fields[] = 'to'; /* Add other non-personal from addresses to the * list of CC addresses. */ $ob->setIteratorFilter($ob::BASE_ELEMENTS, $all_addrs); $addr['cc']->add($ob); $all_addrs->add($ob); continue 2; } } } $ob->setIteratorFilter($ob::BASE_ELEMENTS, $all_addrs); foreach ($ob as $hdr_ob) { if ($hdr_ob instanceof Horde_Mail_Rfc822_Group) { $addr['cc']->add($hdr_ob); $all_addrs->add($hdr_ob->addresses); } elseif ($val != 'to' || is_null($list_info) || !$force || empty($list_info['exists'])) { /* Don't add as To address if this is a list that * doesn't have a post address but does have a * reply-to address. */ if (in_array($val, $to_fields)) { /* If from/reply-to doesn't have personal * information, check from address. */ if (is_null($hdr_ob->personal) && ($tmp = $h['from']) && ($to_ob = $tmp->getAddressList(true)->first()) && !is_null($to_ob->personal) && $hdr_ob->match($to_ob)) { $addr['to']->add($to_ob); } else { $addr['to']->add($hdr_ob); } } else { $addr['cc']->add($hdr_ob); } $all_addrs->add($hdr_ob); } } } /* Build the Cc: (or possibly the To:) header. If this is a * reply to a message that was already replied to by the user, * this reply will go to the original recipients (Request * #8485). */ if (count($addr['cc'])) { $reply_type = self::REPLY_ALL; } if (!count($addr['to'])) { $addr['to'] = $addr['cc']; $addr['cc'] = clone $alist; } /* Build the Bcc: header. */ if ($tmp = $h['bcc']) { $bcc = $tmp->getAddressList(true); $bcc->add($identity->getBccAddresses()); $bcc->setIteratorFilter(0, $all_addrs); foreach ($bcc as $val) { $addr['bcc']->add($val); } } } if (!$this->_replytype || $reply_type != $this->_replytype) { $this->_replytype = $reply_type; $this->changed = 'changed'; } $ret = $this->replyMessageText($contents, array('format' => isset($opts['format']) ? $opts['format'] : null)); if ($prefs->getValue('reply_charset') && $ret['charset'] != $this->charset) { $this->charset = $ret['charset']; $this->changed = 'changed'; } unset($ret['charset']); if ($type == self::REPLY_AUTO) { switch ($reply_type) { case self::REPLY_ALL: try { $recip_list = $this->recipientList($addr); $ret['reply_recip'] = count($recip_list['list']); } catch (IMP_Compose_Exception $e) { $ret['reply_recip'] = 0; } break; case self::REPLY_LIST: if (($list_parse = $injector->getInstance('Horde_ListHeaders')->parse('list-id', strval($h['List-Id']))) && !is_null($list_parse->label)) { $ret['reply_list_id'] = $list_parse->label; } break; } } if (($lang = $h['Accept-Language']) || ($lang = $h['X-Accept-Language'])) { $langs = array(); foreach (explode(',', $lang->value_single) as $val) { if (($name = Horde_Nls::getLanguageISO($val)) !== null) { $langs[trim($val)] = $name; } } $ret['lang'] = array_unique($langs); /* Don't show display if original recipient is asking for reply in * the user's native language. */ if (count($ret['lang']) == 1 && reset($ret['lang']) && substr(key($ret['lang']), 0, 2) == substr($language, 0, 2)) { unset($ret['lang']); } } return array_merge(array('addr' => $addr, 'identity' => $match_identity, 'subject' => $subject, 'type' => $reply_type), $ret); }
/** * @dataProvider insensitiveMatchProvider */ public function testInsensitiveMatch($in, $match, $expected) { $address = new Horde_Mail_Rfc822_Address($in); $this->assertEquals($expected, $address->matchInsensitive($match)); }
public function testParsingPersonalPartWithQuotes() { $email = '"Test \\"F-oo\\" Bar" <*****@*****.**>'; $ob = new Horde_Mail_Rfc822_Address($email); $this->assertEquals('"Test \\"F-oo\\" Bar" <*****@*****.**>', $ob->writeAddress()); $this->assertEquals($email, $ob->writeAddress(true)); }
/** * Return the message's From: address. * * @return string The From address of this message. */ public function getFromAddress() { $from = $this->_envelope->from->addresses; $a = new Horde_Mail_Rfc822_Address(current($from)); return $a->writeAddress(false); }
/** */ public function generateKey($opts) { $skey = $this->_generateSecretKeyPacket($opts['keylength'], 'OpenPGP_SecretKeyPacket'); $id = new Horde_Mail_Rfc822_Address($opts['email']); if (strlen($opts['comment'])) { $id->comment[] = $opts['comment']; } if (strlen($opts['name'])) { $id->personal = $opts['name']; } /* This is the private key we are creating. */ $key = new OpenPGP_Message(array($skey, new OpenPGP_UserIDPacket($id->writeAddress(array('comment' => true))))); $rsa = OpenPGP_Crypt_RSA::convert_private_key($skey); $rsa->setHash(Horde_String::lower($opts['hash'])); $rsa_sign_func = array('RSA' => array($opts['hash'] => function ($data) use($rsa) { return array($rsa->sign($data)); })); /* Create signature packet. */ $sig = new OpenPGP_SignaturePacket($key, 'RSA', $opts['hash']); /* "Generic certification of a User ID and Public-Key packet." */ $sig->signature_type = 0x10; /* Add subpacket information. */ $sig->hashed_subpackets[] = new OpenPGP_SignaturePacket_KeyFlagsPacket(array(0x3)); $sig->hashed_subpackets[] = new OpenPGP_SignaturePacket_PreferredSymmetricAlgorithmsPacket(array(0x9, 0x8, 0x7, 0x2)); $sig->hashed_subpackets[] = new OpenPGP_SignaturePacket_PreferredHashAlgorithmsPacket(array(0x8, 0x9, 0xa, 0xb, 0x2)); $sig->hashed_subpackets[] = new OpenPGP_SignaturePacket_PreferredCompressionAlgorithmsPacket(array(0x2, 0x1)); $ks_prefs = new OpenPGP_SignaturePacket_KeyServerPreferencesPacket(); $ks_prefs->no_modify = true; $sig->hashed_subpackets[] = $ks_prefs; $sig->hashed_subpackets[] = new OpenPGP_SignaturePacket_FeaturesPacket(array(0x1)); if (isset($opts['expire'])) { $sig->hashed_subpackets[] = new OpenPGP_SignaturePacket_KeyExpirationTimePacket($opts['expire'] - time()); } $sig->unhashed_subpackets[] = new OpenPGP_SignaturePacket_IssuerPacket(substr($skey->fingerprint, -16)); $key[] = $sig; /* Create self-signature. */ $sig->sign_data($rsa_sign_func); /* OpenPGP currently (as of April 2015) encrypts passphrases w/ * AES-128 & SHA-1, so use this strategy. */ if (strlen($opts['passphrase'])) { $cipher = new Crypt_AES(CRYPT_AES_MODE_CFB); $cipher->setKeyLength(128); $s2k = new OpenPGP_S2K(crypt_random_string(8), 2); $cipher->setKey($s2k->make_key($opts['passphrase'], 16)); $iv = crypt_random_string(16); $this->_encryptPrivateKey($skey, $cipher, $s2k, $iv); } /* Encryption subkey. See RFC 4880 [5.5.1.2] (by convention, top-level * key is used for signing and subkeys are used for encryption) */ $ekey = $this->_generateSecretKeyPacket($opts['keylength'], 'OpenPGP_SecretSubkeyPacket'); /* Computing signature: RFC 4880 [5.2.4] */ $sig = new OpenPGP_SignaturePacket(implode('', $skey->fingerprint_material()) . implode('', $ekey->fingerprint_material()), 'RSA', $opts['hash']); /* This is a "Subkey Binding Signature". */ $sig->signature_type = 0x18; $sig->hashed_subpackets[] = new OpenPGP_SignaturePacket_KeyFlagsPacket(array(0xc)); $sig->unhashed_subpackets[] = new OpenPGP_SignaturePacket_IssuerPacket(substr($skey->fingerprint, -16)); $sig->sign_data($rsa_sign_func); if (strlen($opts['passphrase'])) { $this->_encryptPrivateKey($ekey, $cipher, $s2k, $iv); } $key[] = $ekey; $key[] = $sig; return new Horde_Pgp_Element_PrivateKey($key); }