diff options
-rw-r--r-- | it_mail.class | 51 | ||||
-rwxr-xr-x | tests/it_mail.t | 49 |
2 files changed, 69 insertions, 31 deletions
diff --git a/it_mail.class b/it_mail.class index 46095bf..5746056 100644 --- a/it_mail.class +++ b/it_mail.class @@ -82,7 +82,7 @@ function add_header($header, $value) { case 'To': foreach ((array)$value as $val) - $this->to[] = $this->header_escape($val, true); + $this->to[] = $this->addrlist_escape($val); break; case 'Subject': @@ -91,12 +91,12 @@ function add_header($header, $value) case 'Cc': foreach ((array)$value as $val) - $this->cc[] = $this->header_escape($val, true); + $this->cc[] = $this->addrlist_escape($val); break; case 'Bcc': foreach ((array)$value as $val) - $this->bcc[] = $this->header_escape($val, true); + $this->bcc[] = $this->addrlist_escape($val); break; case 'charset': @@ -108,7 +108,7 @@ function add_header($header, $value) /* FALLTHROUGH */ default: $this->header_names[] = $header; - $this->header_values[] = $this->header_escape($value, $header == 'From' || $header == 'Reply-To'); + $this->header_values[] = $header == 'From' || $header =='Reply-To' ? $this->addrlist_escape($value) : $this->header_escape($value); break; } } @@ -302,32 +302,31 @@ function send($p = array()) * @param $string String to be escaped * @return String escape suitable for sending in header line */ -function header_escape($string, $emailmode = false) +function header_escape($string) { - $escape = function ($part) - { - return preg_match('/[\x00-\x1f\x7f-\xff]/', $part) - ? ("=?{$this->charset}?Q?" . str_replace(" ", "_", preg_replace_callback('/[\x00-\x1f=\x7f-\xff]/', function($m) { return sprintf('=%02X', ord($m[0])); }, trim($part, '"'))) . "?=") - : $part; - }; + return preg_match('/[\x00-\x1f\x7f-\xff]/', $string) + ? ("=?{$this->charset}?Q?" . str_replace(" ", "_", preg_replace_callback('/[\x00-\x1f=\x7f-\xff]/', function($m) { return sprintf('=%02X', ord($m[0])); }, trim($string, '"'))) . "?=") + : $string; +} - if ($emailmode) +/** + * INTERNAL: Escape address lists in headers like From, To, Cc, Bcc + * @param $string String containing address list + * @return String suitable for sending in address list headers + */ +function addrlist_escape($string) +{ + # Exclude e-mail addresses from being encoded as + # e.g. GMail or Exchange have problems with that + foreach (explode(',', $string) as $mailbox) { - # If in emailmode (From, To, Cc, Bcc) then exclude e-mail addresses - # from being encoded as e.g. GMail or Exchange have problems with that - $emailpattern = '/^(.*)(\s+?<[^>]+@[^>]+>\s*)$/'; - foreach (explode(',', $string) as $mailbox) - { - if (preg_match($emailpattern, $mailbox, $matches)) - $result[] = $escape($matches[1]) . $matches[2]; - else - $result[] = $mailbox; - } - - return implode(',', $result); + if (preg_match('/^(.*)(\s+?<[^>]+@[^>]+>\s*)$/', $mailbox, $matches)) + $result[] = $this->header_escape($matches[1]) . $matches[2]; + else + $result[] = $mailbox; } - else - return $escape($string); + + return implode(',', $result); } diff --git a/tests/it_mail.t b/tests/it_mail.t index 181c3df..1762788 100755 --- a/tests/it_mail.t +++ b/tests/it_mail.t @@ -7,7 +7,7 @@ $mail = new it_mail(); # header_escape tests # is( - $mail->header_escape('éxample@example.com', true), + $mail->addrlist_escape('éxample@example.com', true), 'éxample@example.com', "Don't escape plain email addresses in email headers", ); @@ -19,25 +19,64 @@ is( ); is( - $mail->header_escape('Èxample User <èxample@example.com>', true), + $mail->addrlist_escape('Èxample User <èxample@example.com>', true), '=?utf-8?Q?=C3=88xample_User?= <èxample@example.com>', "Escape name but not email in email headers", ); is( - $mail->header_escape('Example User <example@example.com>', true), + $mail->addrlist_escape('Example User <example@example.com>', true), 'Example User <example@example.com>', "Don't escape characters that don't need escaping" ); is( - $mail->header_escape('example@example.com, éxample@example.com, Sömeone Ëlse <sömeone@example.com>', true), + $mail->addrlist_escape('example@example.com, éxample@example.com, Sömeone Ëlse <sömeone@example.com>', true), 'example@example.com, éxample@example.com,=?utf-8?Q?_S=C3=B6meone_=C3=8Blse?= <sömeone@example.com>', "Don't escape email addresses but escape realnames", ); is( - $mail->header_escape('"Alfred E. Neuman" <neuman@example.com>', true), + $mail->addrlist_escape('"Alfred E. Neuman" <neuman@example.com>', true), '"Alfred E. Neuman" <neuman@example.com>', "Don't remove quoting characters from realname", ); + + +$mail = new it_mail( + 'From' => 'Someone Ïmportant <ïmportant@search.ch>', + 'To' => 'éxample@example.com, example@example.com, Sömeone Ëlse <sömeone@example.com>, "Alfred E. Neuman" <neuman@example.com>', + 'Cc' => 'éxample@example.com, example@example.com, Sömeone Ëlse <sömeone@example.com>, "Alfred E. Neuman" <neuman@example.com>', + 'Bcc' => 'éxample@example.com, example@example.com, Sömeone Ëlse <sömeone@example.com>, "Alfred E. Neuman" <neuman@example.com>', + 'Subject' => "§önÐë®z€ı¢ħèṇ", +); + +is( + $mail->to[0], + 'éxample@example.com, example@example.com,=?utf-8?Q?_S=C3=B6meone_=C3=8Blse?= <sömeone@example.com>, "Alfred E. Neuman" <neuman@example.com>', + 'Escape To: field as addrlist', +); + +is( + $mail->cc[0], + 'éxample@example.com, example@example.com,=?utf-8?Q?_S=C3=B6meone_=C3=8Blse?= <sömeone@example.com>, "Alfred E. Neuman" <neuman@example.com>', + 'Escape Cc: field as addrlist', +); + +is( + $mail->bcc[0], + 'éxample@example.com, example@example.com,=?utf-8?Q?_S=C3=B6meone_=C3=8Blse?= <sömeone@example.com>, "Alfred E. Neuman" <neuman@example.com>', + 'Escape Bcc: field as addrlist', +); + +is( + $mail->header_values[0], + '=?utf-8?Q?Someone_=C3=8Fmportant?= <ïmportant@search.ch>', + 'Escape From: field as addrlist', +); + +is( + $mail->subject, + "§önÐë®z€ı¢ħèṇ", + "Don't escape Subject: field on instanziation", +); |