@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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

+106 -71
+2
src/__phutil_library_map__.php
··· 3408 3408 'PhabricatorMailRoutingRule' => 'applications/metamta/constants/PhabricatorMailRoutingRule.php', 3409 3409 'PhabricatorMailStamp' => 'applications/metamta/stamp/PhabricatorMailStamp.php', 3410 3410 'PhabricatorMailTarget' => 'applications/metamta/replyhandler/PhabricatorMailTarget.php', 3411 + 'PhabricatorMailUtil' => 'applications/metamta/util/PhabricatorMailUtil.php', 3411 3412 'PhabricatorMainMenuBarExtension' => 'view/page/menu/PhabricatorMainMenuBarExtension.php', 3412 3413 'PhabricatorMainMenuSearchView' => 'view/page/menu/PhabricatorMainMenuSearchView.php', 3413 3414 'PhabricatorMainMenuView' => 'view/page/menu/PhabricatorMainMenuView.php', ··· 9215 9216 'PhabricatorMailRoutingRule' => 'Phobject', 9216 9217 'PhabricatorMailStamp' => 'Phobject', 9217 9218 'PhabricatorMailTarget' => 'Phobject', 9219 + 'PhabricatorMailUtil' => 'Phobject', 9218 9220 'PhabricatorMainMenuBarExtension' => 'Phobject', 9219 9221 'PhabricatorMainMenuSearchView' => 'AphrontView', 9220 9222 'PhabricatorMainMenuView' => 'AphrontView',
+3 -63
src/applications/metamta/receiver/PhabricatorMailReceiver.php
··· 25 25 ->withApplicationPHIDs(array($app->getPHID())) 26 26 ->execute(); 27 27 28 - foreach ($mail->getToAddresses() as $to_address) { 28 + foreach ($mail->newTargetAddresses() as $address) { 29 29 foreach ($application_emails as $application_email) { 30 - $create_address = $application_email->getAddress(); 31 - if ($this->matchAddresses($create_address, $to_address)) { 30 + $create_address = $application_email->newAddress(); 31 + if (PhabricatorMailUtil::matchAddresses($create_address, $address)) { 32 32 $this->setApplicationEmail($application_email); 33 33 return true; 34 34 } ··· 193 193 MetaMTAReceivedMailStatus::STATUS_UNKNOWN_SENDER, 194 194 $reasons); 195 195 } 196 - 197 - /** 198 - * Determine if two inbound email addresses are effectively identical. This 199 - * method strips and normalizes addresses so that equivalent variations are 200 - * correctly detected as identical. For example, these addresses are all 201 - * considered to match one another: 202 - * 203 - * "Abraham Lincoln" <alincoln@example.com> 204 - * alincoln@example.com 205 - * <ALincoln@example.com> 206 - * "Abraham" <phabricator+ALINCOLN@EXAMPLE.COM> # With configured prefix. 207 - * 208 - * @param string Email address. 209 - * @param string Another email address. 210 - * @return bool True if addresses match. 211 - */ 212 - public static function matchAddresses($u, $v) { 213 - $u = self::getRawAddress($u); 214 - $v = self::getRawAddress($v); 215 - 216 - $u = self::stripMailboxPrefix($u); 217 - $v = self::stripMailboxPrefix($v); 218 - 219 - return ($u === $v); 220 - } 221 - 222 - 223 - /** 224 - * Strip a global mailbox prefix from an address if it is present. Phabricator 225 - * can be configured to prepend a prefix to all reply addresses, which can 226 - * make forwarding rules easier to write. A prefix looks like: 227 - * 228 - * example@phabricator.example.com # No Prefix 229 - * phabricator+example@phabricator.example.com # Prefix "phabricator" 230 - * 231 - * @param string Email address, possibly with a mailbox prefix. 232 - * @return string Email address with any prefix stripped. 233 - */ 234 - public static function stripMailboxPrefix($address) { 235 - $address = id(new PhutilEmailAddress($address))->getAddress(); 236 - 237 - $prefix_key = 'metamta.single-reply-handler-prefix'; 238 - $prefix = PhabricatorEnv::getEnvConfig($prefix_key); 239 - 240 - $len = strlen($prefix); 241 - 242 - if ($len) { 243 - $prefix = $prefix.'+'; 244 - $len = $len + 1; 245 - } 246 - 247 - if ($len) { 248 - if (!strncasecmp($address, $prefix, $len)) { 249 - $address = substr($address, strlen($prefix)); 250 - } 251 - } 252 - 253 - return $address; 254 - } 255 - 256 196 257 197 /** 258 198 * Reduce an email address to its canonical form. For example, an address
+5 -6
src/applications/metamta/receiver/PhabricatorObjectMailReceiver.php
··· 150 150 private function matchObjectAddressInMail( 151 151 PhabricatorMetaMTAReceivedMail $mail) { 152 152 153 - foreach ($mail->getToAddresses() as $address) { 153 + foreach ($mail->newTargetAddresses() as $address) { 154 154 $parts = $this->matchObjectAddress($address); 155 155 if ($parts) { 156 156 return $parts; ··· 160 160 return null; 161 161 } 162 162 163 - private function matchObjectAddress($address) { 163 + private function matchObjectAddress(PhutilEmailAddress $address) { 164 + $address = PhabricatorMailUtil::normalizeAddress($address); 165 + $local = $address->getLocalPart(); 166 + 164 167 $regexp = $this->getAddressRegexp(); 165 - 166 - $address = self::stripMailboxPrefix($address); 167 - $local = id(new PhutilEmailAddress($address))->getLocalPart(); 168 - 169 168 $matches = null; 170 169 if (!preg_match($regexp, $local, $matches)) { 171 170 return false;
+6 -2
src/applications/metamta/receiver/__tests__/PhabricatorMailReceiverTestCase.php
··· 17 17 18 18 foreach ($same as $address) { 19 19 $this->assertTrue( 20 - PhabricatorMailReceiver::matchAddresses($base, $address), 20 + PhabricatorMailUtil::matchAddresses( 21 + new PhutilEmailAddress($base), 22 + new PhutilEmailAddress($address)), 21 23 pht('Address %s', $address)); 22 24 } 23 25 ··· 32 34 33 35 foreach ($diff as $address) { 34 36 $this->assertFalse( 35 - PhabricatorMailReceiver::matchAddresses($base, $address), 37 + PhabricatorMailUtil::matchAddresses( 38 + new PhutilEmailAddress($base), 39 + new PhutilEmailAddress($address)), 36 40 pht('Address: %s', $address)); 37 41 } 38 42 }
+4
src/applications/metamta/storage/PhabricatorMetaMTAApplicationEmail.php
··· 88 88 return $message; 89 89 } 90 90 91 + public function newAddress() { 92 + return new PhutilEmailAddress($this->getAddress()); 93 + } 94 + 91 95 /* -( PhabricatorPolicyInterface )----------------------------------------- */ 92 96 93 97
+21
src/applications/metamta/storage/PhabricatorMetaMTAReceivedMail.php
··· 82 82 return $this->getRawEmailAddresses(idx($this->headers, 'to')); 83 83 } 84 84 85 + public function newTargetAddresses() { 86 + $raw_addresses = array(); 87 + 88 + foreach ($this->getToAddresses() as $raw_address) { 89 + $raw_addresses[] = $raw_address; 90 + } 91 + 92 + foreach ($this->getCCAddresses() as $raw_address) { 93 + $raw_addresses[] = $raw_address; 94 + } 95 + 96 + $raw_addresses = array_unique($raw_addresses); 97 + 98 + $addresses = array(); 99 + foreach ($raw_addresses as $raw_address) { 100 + $addresses[] = new PhutilEmailAddress($raw_address); 101 + } 102 + 103 + return $addresses; 104 + } 105 + 85 106 public function loadAllRecipientPHIDs() { 86 107 $addresses = array_merge( 87 108 $this->getToAddresses(),
+65
src/applications/metamta/util/PhabricatorMailUtil.php
··· 1 + <?php 2 + 3 + final class PhabricatorMailUtil 4 + extends Phobject { 5 + 6 + /** 7 + * Normalize an email address for comparison or lookup. 8 + * 9 + * Phabricator can be configured to prepend a prefix to all reply addresses, 10 + * which can make forwarding rules easier to write. This method strips the 11 + * prefix if it is present, and normalizes casing and whitespace. 12 + * 13 + * @param PhutilEmailAddress Email address. 14 + * @return PhutilEmailAddress Normalized address. 15 + */ 16 + public static function normalizeAddress(PhutilEmailAddress $address) { 17 + $raw_address = $address->getAddress(); 18 + $raw_address = phutil_utf8_strtolower($raw_address); 19 + $raw_address = trim($raw_address); 20 + 21 + // If a mailbox prefix is configured and present, strip it off. 22 + $prefix_key = 'metamta.single-reply-handler-prefix'; 23 + $prefix = PhabricatorEnv::getEnvConfig($prefix_key); 24 + $len = strlen($prefix); 25 + 26 + if ($len) { 27 + $prefix = $prefix.'+'; 28 + $len = $len + 1; 29 + 30 + if (!strncasecmp($raw_address, $prefix, $len)) { 31 + $raw_address = substr($raw_address, $len); 32 + } 33 + } 34 + 35 + return id(clone $address) 36 + ->setAddress($raw_address); 37 + } 38 + 39 + /** 40 + * Determine if two inbound email addresses are effectively identical. 41 + * 42 + * This method strips and normalizes addresses so that equivalent variations 43 + * are correctly detected as identical. For example, these addresses are all 44 + * considered to match one another: 45 + * 46 + * "Abraham Lincoln" <alincoln@example.com> 47 + * alincoln@example.com 48 + * <ALincoln@example.com> 49 + * "Abraham" <phabricator+ALINCOLN@EXAMPLE.COM> # With configured prefix. 50 + * 51 + * @param PhutilEmailAddress Email address. 52 + * @param PhutilEmailAddress Another email address. 53 + * @return bool True if addresses are effectively the same address. 54 + */ 55 + public static function matchAddresses( 56 + PhutilEmailAddress $u, 57 + PhutilEmailAddress $v) { 58 + 59 + $u = self::normalizeAddress($u); 60 + $v = self::normalizeAddress($v); 61 + 62 + return ($u->getAddress() === $v->getAddress()); 63 + } 64 + 65 + }