mirror of
https://we.phorge.it/source/phorge.git
synced 2024-12-26 15:30:58 +01:00
Extract some email address utility code from the receiver stack
Summary: Ref T7477. We have some address normalization code in the reciever stack that is really shared code. I want to introduce some new callsites elsewhere but don't want to put a lot of static calls to other random objects all over the place. This technically "solves" T7477 (it changes "to" to "to + cc" for finding receivers) but doesn't yet implement proper behavior (with multiple receivers, for example). Test Plan: Ran unit tests, which cover this pretty well. Additional changes will vet this more thoroughly. Reviewers: amckinley Reviewed By: amckinley Maniphest Tasks: T7477 Differential Revision: https://secure.phabricator.com/D19948
This commit is contained in:
parent
e2f0571104
commit
57b3619181
7 changed files with 106 additions and 71 deletions
|
@ -3408,6 +3408,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorMailRoutingRule' => 'applications/metamta/constants/PhabricatorMailRoutingRule.php',
|
||||
'PhabricatorMailStamp' => 'applications/metamta/stamp/PhabricatorMailStamp.php',
|
||||
'PhabricatorMailTarget' => 'applications/metamta/replyhandler/PhabricatorMailTarget.php',
|
||||
'PhabricatorMailUtil' => 'applications/metamta/util/PhabricatorMailUtil.php',
|
||||
'PhabricatorMainMenuBarExtension' => 'view/page/menu/PhabricatorMainMenuBarExtension.php',
|
||||
'PhabricatorMainMenuSearchView' => 'view/page/menu/PhabricatorMainMenuSearchView.php',
|
||||
'PhabricatorMainMenuView' => 'view/page/menu/PhabricatorMainMenuView.php',
|
||||
|
@ -9215,6 +9216,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorMailRoutingRule' => 'Phobject',
|
||||
'PhabricatorMailStamp' => 'Phobject',
|
||||
'PhabricatorMailTarget' => 'Phobject',
|
||||
'PhabricatorMailUtil' => 'Phobject',
|
||||
'PhabricatorMainMenuBarExtension' => 'Phobject',
|
||||
'PhabricatorMainMenuSearchView' => 'AphrontView',
|
||||
'PhabricatorMainMenuView' => 'AphrontView',
|
||||
|
|
|
@ -25,10 +25,10 @@ abstract class PhabricatorMailReceiver extends Phobject {
|
|||
->withApplicationPHIDs(array($app->getPHID()))
|
||||
->execute();
|
||||
|
||||
foreach ($mail->getToAddresses() as $to_address) {
|
||||
foreach ($mail->newTargetAddresses() as $address) {
|
||||
foreach ($application_emails as $application_email) {
|
||||
$create_address = $application_email->getAddress();
|
||||
if ($this->matchAddresses($create_address, $to_address)) {
|
||||
$create_address = $application_email->newAddress();
|
||||
if (PhabricatorMailUtil::matchAddresses($create_address, $address)) {
|
||||
$this->setApplicationEmail($application_email);
|
||||
return true;
|
||||
}
|
||||
|
@ -194,66 +194,6 @@ abstract class PhabricatorMailReceiver extends Phobject {
|
|||
$reasons);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if two inbound email addresses are effectively identical. This
|
||||
* method strips and normalizes addresses so that equivalent variations are
|
||||
* correctly detected as identical. For example, these addresses are all
|
||||
* considered to match one another:
|
||||
*
|
||||
* "Abraham Lincoln" <alincoln@example.com>
|
||||
* alincoln@example.com
|
||||
* <ALincoln@example.com>
|
||||
* "Abraham" <phabricator+ALINCOLN@EXAMPLE.COM> # With configured prefix.
|
||||
*
|
||||
* @param string Email address.
|
||||
* @param string Another email address.
|
||||
* @return bool True if addresses match.
|
||||
*/
|
||||
public static function matchAddresses($u, $v) {
|
||||
$u = self::getRawAddress($u);
|
||||
$v = self::getRawAddress($v);
|
||||
|
||||
$u = self::stripMailboxPrefix($u);
|
||||
$v = self::stripMailboxPrefix($v);
|
||||
|
||||
return ($u === $v);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Strip a global mailbox prefix from an address if it is present. Phabricator
|
||||
* can be configured to prepend a prefix to all reply addresses, which can
|
||||
* make forwarding rules easier to write. A prefix looks like:
|
||||
*
|
||||
* example@phabricator.example.com # No Prefix
|
||||
* phabricator+example@phabricator.example.com # Prefix "phabricator"
|
||||
*
|
||||
* @param string Email address, possibly with a mailbox prefix.
|
||||
* @return string Email address with any prefix stripped.
|
||||
*/
|
||||
public static function stripMailboxPrefix($address) {
|
||||
$address = id(new PhutilEmailAddress($address))->getAddress();
|
||||
|
||||
$prefix_key = 'metamta.single-reply-handler-prefix';
|
||||
$prefix = PhabricatorEnv::getEnvConfig($prefix_key);
|
||||
|
||||
$len = strlen($prefix);
|
||||
|
||||
if ($len) {
|
||||
$prefix = $prefix.'+';
|
||||
$len = $len + 1;
|
||||
}
|
||||
|
||||
if ($len) {
|
||||
if (!strncasecmp($address, $prefix, $len)) {
|
||||
$address = substr($address, strlen($prefix));
|
||||
}
|
||||
}
|
||||
|
||||
return $address;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Reduce an email address to its canonical form. For example, an address
|
||||
* like:
|
||||
|
|
|
@ -150,7 +150,7 @@ abstract class PhabricatorObjectMailReceiver extends PhabricatorMailReceiver {
|
|||
private function matchObjectAddressInMail(
|
||||
PhabricatorMetaMTAReceivedMail $mail) {
|
||||
|
||||
foreach ($mail->getToAddresses() as $address) {
|
||||
foreach ($mail->newTargetAddresses() as $address) {
|
||||
$parts = $this->matchObjectAddress($address);
|
||||
if ($parts) {
|
||||
return $parts;
|
||||
|
@ -160,12 +160,11 @@ abstract class PhabricatorObjectMailReceiver extends PhabricatorMailReceiver {
|
|||
return null;
|
||||
}
|
||||
|
||||
private function matchObjectAddress($address) {
|
||||
private function matchObjectAddress(PhutilEmailAddress $address) {
|
||||
$address = PhabricatorMailUtil::normalizeAddress($address);
|
||||
$local = $address->getLocalPart();
|
||||
|
||||
$regexp = $this->getAddressRegexp();
|
||||
|
||||
$address = self::stripMailboxPrefix($address);
|
||||
$local = id(new PhutilEmailAddress($address))->getLocalPart();
|
||||
|
||||
$matches = null;
|
||||
if (!preg_match($regexp, $local, $matches)) {
|
||||
return false;
|
||||
|
|
|
@ -17,7 +17,9 @@ final class PhabricatorMailReceiverTestCase extends PhabricatorTestCase {
|
|||
|
||||
foreach ($same as $address) {
|
||||
$this->assertTrue(
|
||||
PhabricatorMailReceiver::matchAddresses($base, $address),
|
||||
PhabricatorMailUtil::matchAddresses(
|
||||
new PhutilEmailAddress($base),
|
||||
new PhutilEmailAddress($address)),
|
||||
pht('Address %s', $address));
|
||||
}
|
||||
|
||||
|
@ -32,7 +34,9 @@ final class PhabricatorMailReceiverTestCase extends PhabricatorTestCase {
|
|||
|
||||
foreach ($diff as $address) {
|
||||
$this->assertFalse(
|
||||
PhabricatorMailReceiver::matchAddresses($base, $address),
|
||||
PhabricatorMailUtil::matchAddresses(
|
||||
new PhutilEmailAddress($base),
|
||||
new PhutilEmailAddress($address)),
|
||||
pht('Address: %s', $address));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -88,6 +88,10 @@ final class PhabricatorMetaMTAApplicationEmail
|
|||
return $message;
|
||||
}
|
||||
|
||||
public function newAddress() {
|
||||
return new PhutilEmailAddress($this->getAddress());
|
||||
}
|
||||
|
||||
/* -( PhabricatorPolicyInterface )----------------------------------------- */
|
||||
|
||||
|
||||
|
|
|
@ -82,6 +82,27 @@ final class PhabricatorMetaMTAReceivedMail extends PhabricatorMetaMTADAO {
|
|||
return $this->getRawEmailAddresses(idx($this->headers, 'to'));
|
||||
}
|
||||
|
||||
public function newTargetAddresses() {
|
||||
$raw_addresses = array();
|
||||
|
||||
foreach ($this->getToAddresses() as $raw_address) {
|
||||
$raw_addresses[] = $raw_address;
|
||||
}
|
||||
|
||||
foreach ($this->getCCAddresses() as $raw_address) {
|
||||
$raw_addresses[] = $raw_address;
|
||||
}
|
||||
|
||||
$raw_addresses = array_unique($raw_addresses);
|
||||
|
||||
$addresses = array();
|
||||
foreach ($raw_addresses as $raw_address) {
|
||||
$addresses[] = new PhutilEmailAddress($raw_address);
|
||||
}
|
||||
|
||||
return $addresses;
|
||||
}
|
||||
|
||||
public function loadAllRecipientPHIDs() {
|
||||
$addresses = array_merge(
|
||||
$this->getToAddresses(),
|
||||
|
|
65
src/applications/metamta/util/PhabricatorMailUtil.php
Normal file
65
src/applications/metamta/util/PhabricatorMailUtil.php
Normal file
|
@ -0,0 +1,65 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorMailUtil
|
||||
extends Phobject {
|
||||
|
||||
/**
|
||||
* Normalize an email address for comparison or lookup.
|
||||
*
|
||||
* Phabricator can be configured to prepend a prefix to all reply addresses,
|
||||
* which can make forwarding rules easier to write. This method strips the
|
||||
* prefix if it is present, and normalizes casing and whitespace.
|
||||
*
|
||||
* @param PhutilEmailAddress Email address.
|
||||
* @return PhutilEmailAddress Normalized address.
|
||||
*/
|
||||
public static function normalizeAddress(PhutilEmailAddress $address) {
|
||||
$raw_address = $address->getAddress();
|
||||
$raw_address = phutil_utf8_strtolower($raw_address);
|
||||
$raw_address = trim($raw_address);
|
||||
|
||||
// If a mailbox prefix is configured and present, strip it off.
|
||||
$prefix_key = 'metamta.single-reply-handler-prefix';
|
||||
$prefix = PhabricatorEnv::getEnvConfig($prefix_key);
|
||||
$len = strlen($prefix);
|
||||
|
||||
if ($len) {
|
||||
$prefix = $prefix.'+';
|
||||
$len = $len + 1;
|
||||
|
||||
if (!strncasecmp($raw_address, $prefix, $len)) {
|
||||
$raw_address = substr($raw_address, $len);
|
||||
}
|
||||
}
|
||||
|
||||
return id(clone $address)
|
||||
->setAddress($raw_address);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if two inbound email addresses are effectively identical.
|
||||
*
|
||||
* This method strips and normalizes addresses so that equivalent variations
|
||||
* are correctly detected as identical. For example, these addresses are all
|
||||
* considered to match one another:
|
||||
*
|
||||
* "Abraham Lincoln" <alincoln@example.com>
|
||||
* alincoln@example.com
|
||||
* <ALincoln@example.com>
|
||||
* "Abraham" <phabricator+ALINCOLN@EXAMPLE.COM> # With configured prefix.
|
||||
*
|
||||
* @param PhutilEmailAddress Email address.
|
||||
* @param PhutilEmailAddress Another email address.
|
||||
* @return bool True if addresses are effectively the same address.
|
||||
*/
|
||||
public static function matchAddresses(
|
||||
PhutilEmailAddress $u,
|
||||
PhutilEmailAddress $v) {
|
||||
|
||||
$u = self::normalizeAddress($u);
|
||||
$v = self::normalizeAddress($v);
|
||||
|
||||
return ($u->getAddress() === $v->getAddress());
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in a new issue