Correct Aphlict websocket URI construction after PHP8 compatibility changes
[phabricator.git] / src / applications / metamta / util / PhabricatorMailUtil.php
blob270e9786f3e1e8ba9afbce5d9ee96bfe6fffc5c0
1 <?php
3 final class PhabricatorMailUtil
4 extends Phobject {
6 /**
7 * Normalize an email address for comparison or lookup.
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.
13 * @param PhutilEmailAddress Email address.
14 * @return PhutilEmailAddress Normalized address.
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);
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);
25 if (phutil_nonempty_string($prefix)) {
26 $prefix = $prefix.'+';
27 $len = strlen($prefix);
29 if (!strncasecmp($raw_address, $prefix, $len)) {
30 $raw_address = substr($raw_address, $len);
34 return id(clone $address)
35 ->setAddress($raw_address);
38 /**
39 * Determine if two inbound email addresses are effectively identical.
41 * This method strips and normalizes addresses so that equivalent variations
42 * are correctly detected as identical. For example, these addresses are all
43 * considered to match one another:
45 * "Abraham Lincoln" <alincoln@example.com>
46 * alincoln@example.com
47 * <ALincoln@example.com>
48 * "Abraham" <phabricator+ALINCOLN@EXAMPLE.COM> # With configured prefix.
50 * @param PhutilEmailAddress Email address.
51 * @param PhutilEmailAddress Another email address.
52 * @return bool True if addresses are effectively the same address.
54 public static function matchAddresses(
55 PhutilEmailAddress $u,
56 PhutilEmailAddress $v) {
58 $u = self::normalizeAddress($u);
59 $v = self::normalizeAddress($v);
61 return ($u->getAddress() === $v->getAddress());
64 public static function isReservedAddress(PhutilEmailAddress $address) {
65 $address = self::normalizeAddress($address);
66 $local = $address->getLocalPart();
68 $reserved = array(
69 'admin',
70 'administrator',
71 'hostmaster',
72 'list',
73 'list-request',
74 'majordomo',
75 'postmaster',
76 'root',
77 'ssl-admin',
78 'ssladmin',
79 'ssladministrator',
80 'sslwebmaster',
81 'sysadmin',
82 'uucp',
83 'webmaster',
85 'noreply',
86 'no-reply',
89 $reserved = array_fuse($reserved);
91 if (isset($reserved[$local])) {
92 return true;
95 $default_address = id(new PhabricatorMailEmailEngine())
96 ->newDefaultEmailAddress();
97 if (self::matchAddresses($address, $default_address)) {
98 return true;
101 $void_address = id(new PhabricatorMailEmailEngine())
102 ->newVoidEmailAddress();
103 if (self::matchAddresses($address, $void_address)) {
104 return true;
107 return false;
110 public static function isUserAddress(PhutilEmailAddress $address) {
111 $user_email = id(new PhabricatorUserEmail())->loadOneWhere(
112 'address = %s',
113 $address->getAddress());
115 return (bool)$user_email;