From 5cfddf9a82dedce72e74f5d0f0acacf5bb2ba40c Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Mon, 12 Dec 2005 06:04:45 +0000 Subject: [PATCH] * (bug 3407) Fix encoding of subject and from/to headers on notification mails; userMailer() now takes a MailAddress wrapper object instead of a raw string to abstract things a level. --- RELEASE-NOTES | 3 ++ includes/SpecialEmailuser.php | 27 ++++++++-------- includes/User.php | 4 ++- includes/UserMailer.php | 61 ++++++++++++++++++++++++++--------- 4 files changed, 66 insertions(+), 29 deletions(-) diff --git a/RELEASE-NOTES b/RELEASE-NOTES index 9b6e16a3ea..37253c320e 100644 --- a/RELEASE-NOTES +++ b/RELEASE-NOTES @@ -314,6 +314,9 @@ fully support the editing toolbar, but was found to be too confusing. * Fix regression: old version missing from edit links on CSS/JS pages * (bug 3073) Keep search parameter on paging in Special:Newimages * (bug 3211) Include Date, To mail headers when using PEAR::Mail +* (bug 3407) Fix encoding of subject and from/to headers on notification + mails; userMailer() now takes a MailAddress wrapper object instead of + a raw string to abstract things a level. === Caveats === diff --git a/includes/SpecialEmailuser.php b/includes/SpecialEmailuser.php index 2c6e1397e6..83d02b8d07 100644 --- a/includes/SpecialEmailuser.php +++ b/includes/SpecialEmailuser.php @@ -46,8 +46,7 @@ function wfSpecialEmailuser( $par ) { return; } - $address = $nu->getEmail(); - $f = new EmailUserForm( $nu->getName() . " <{$address}>", $target ); + $f = new EmailUserForm( $nu ); if ( "success" == $action ) { $f->showSuccess(); @@ -66,13 +65,14 @@ function wfSpecialEmailuser( $par ) { */ class EmailUserForm { - var $mAddress; var $target; var $text, $subject; - function EmailUserForm( $addr, $target ) { + /** + * @param User $target + */ + function EmailUserForm( $target ) { global $wgRequest; - $this->mAddress = $addr; $this->target = $target; $this->text = $wgRequest->getText( 'wpText' ); $this->subject = $wgRequest->getText( 'wpSubject' ); @@ -91,7 +91,7 @@ class EmailUserForm { $emf = wfMsg( "emailfrom" ); $sender = $wgUser->getName(); $emt = wfMsg( "emailto" ); - $rcpt = str_replace( "_", " ", $this->target ); + $rcpt = $this->target->getName(); $emr = wfMsg( "emailsubject" ); $emm = wfMsg( "emailmessage" ); $ems = wfMsg( "emailsend" ); @@ -99,7 +99,7 @@ class EmailUserForm { $titleObj = Title::makeTitle( NS_SPECIAL, "Emailuser" ); $action = $titleObj->escapeLocalURL( "target=" . - urlencode( $this->target ) . "&action=submit" ); + urlencode( $this->target->getName() ) . "&action=submit" ); $token = $wgUser->editToken(); $wgOut->addHTML( " @@ -129,20 +129,21 @@ class EmailUserForm { function doSubmit() { global $wgOut, $wgUser; - $from = wfQuotedPrintable( $wgUser->getName() ) . " <" . $wgUser->getEmail() . ">"; - $subject = wfQuotedPrintable( $this->subject ); + $to = new MailAddress( $this->target ); + $from = new MailAddress( $wgUser ); + $subject = $this->subject; - if (wfRunHooks('EmailUser', array(&$this->mAddress, &$from, &$subject, &$this->text))) { + if( wfRunHooks( 'EmailUser', array( &$to, &$from, &$subject, &$this->text ) ) ) { - $mailResult = userMailer( $this->mAddress, $from, $subject, $this->text ); + $mailResult = userMailer( $to, $from, $subject, $this->text ); if( WikiError::isError( $mailResult ) ) { $wgOut->addHTML( wfMsg( "usermailererror" ) . $mailResult); } else { $titleObj = Title::makeTitle( NS_SPECIAL, "Emailuser" ); - $encTarget = wfUrlencode( $this->target ); + $encTarget = wfUrlencode( $this->target->getName() ); $wgOut->redirect( $titleObj->getFullURL( "target={$encTarget}&action=success" ) ); - wfRunHooks('EmailUserComplete', array($this->mAddress, $from, $subject, $this->text)); + wfRunHooks( 'EmailUserComplete', array( $to, $from, $subject, $this->text ) ); } } } diff --git a/includes/User.php b/includes/User.php index f3c32450b8..1c59a64ce1 100644 --- a/includes/User.php +++ b/includes/User.php @@ -1701,7 +1701,9 @@ class User { } require_once( 'UserMailer.php' ); - $error = userMailer( $this->getEmail(), $from, $subject, $body ); + $to = new MailAddress( $this ); + $sender = new MailAddress( $from ); + $error = userMailer( $to, $sender, $subject, $body ); if( $error == '' ) { return true; diff --git a/includes/UserMailer.php b/includes/UserMailer.php index 67c7176dce..b887b1e72e 100644 --- a/includes/UserMailer.php +++ b/includes/UserMailer.php @@ -35,14 +35,42 @@ function wfRFC822Phrase( $phrase ) { return '"' . $phrase . '"'; } +class MailAddress { + /** + * @param mixed $address String with an email address, or a User object + * @param string $name Human-readable name if a string address is given + */ + function MailAddress( $address, $name=null ) { + if( is_object( $address ) && is_a( $address, 'User' ) ) { + $this->address = $address->getEmail(); + $this->name = $address->getName(); + } else { + $this->address = strval( $address ); + $this->name = strval( $name ); + } + } + + /** + * Return formatted and quoted address to insert into SMTP headers + * @return string + */ + function toString() { + if( $this->name != '' ) { + return wfQuotedPrintable( $this->name ) . " <" . $this->address . ">"; + } else { + return $this->address; + } + } +} + /** * This function will perform a direct (authenticated) login to * a SMTP Server to use for mail relaying if 'wgSMTP' specifies an * array of parameters. It requires PEAR:Mail to do that. * Otherwise it just uses the standard PHP 'mail' function. * - * @param string $to recipient's email - * @param string $from sender's email + * @param MailAddress $to recipient's email + * @param MailAddress $from sender's email * @param string $subject email's subject * @param string $body email's text * @param string $replyto optional reply-to email (default : false) @@ -54,24 +82,25 @@ function userMailer( $to, $from, $subject, $body, $replyto=false ) { require_once( 'Mail.php' ); $timestamp = time(); - - $headers['From'] = $from; - $headers['To'] = $to; + $dest = $to->toString(); + + $headers['From'] = $from->toString(); + $headers['To'] = $dest; if ( $replyto ) { $headers['Reply-To'] = $replyto; } - $headers['Subject'] = $subject; + $headers['Subject'] = wfQuotedPrintable( $subject ); $headers['Date'] = date( 'r' ); $headers['MIME-Version'] = '1.0'; $headers['Content-type'] = 'text/plain; charset='.$wgOutputEncoding; $headers['Content-transfer-encoding'] = '8bit'; - $headers['Message-ID'] = "<{$timestamp}" . $wgUser->getName() . '@' . $wgSMTP['IDHost'] . '>'; + $headers['Message-ID'] = "<{$timestamp}" . $wgUser->getName() . '@' . $wgSMTP['IDHost'] . '>'; // FIXME $headers['X-Mailer'] = 'MediaWiki mailer'; // Create the mail object using the Mail::factory method $mail_object =& Mail::factory('smtp', $wgSMTP); - wfDebug( "Sending mail via PEAR::Mail to $to\n" ); - $mailResult =& $mail_object->send($to, $headers, $body); + wfDebug( "Sending mail via PEAR::Mail to $dest" ); + $mailResult =& $mail_object->send($dest, $headers, $body); # Based on the result return an error string, if ($mailResult === true) { @@ -91,15 +120,17 @@ function userMailer( $to, $from, $subject, $body, $replyto=false ) { "Content-type: text/plain; charset={$wgOutputEncoding}\n" . "Content-Transfer-Encoding: 8bit\n" . "X-Mailer: MediaWiki mailer\n". - 'From: ' . $from . "\n"; + 'From: ' . $from->toString() . "\n"; if ($replyto) { $headers .= "Reply-To: $replyto\n"; } + $dest = $to->toString(); + $wgErrorString = ''; set_error_handler( 'mailErrorHandler' ); - wfDebug( "Sending mail via internal mail() function to $to\n" ); - mail( $to, $subject, $body, $headers ); + wfDebug( "Sending mail via internal mail() function to $dest\n" ); + mail( $dest, wfQuotedPrintable( $subject ), $body, $headers ); restore_error_handler(); if ( $wgErrorString ) { @@ -306,8 +337,8 @@ class EmailNotification { # the user has not opted-out and the option is enabled at the # global configuration level. $name = $wgUser->getName(); - $adminAddress = 'WikiAdmin <' . $wgEmergencyContact . '>'; - $editorAddress = wfRFC822Phrase( $name ) . ' <' . $wgUser->getEmail() . '>'; + $adminAddress = new MailAddress( $wgEmergencyContact, 'WikiAdmin' ); + $editorAddress = new MailAddress( $wgUser ); if( $wgEnotifRevealEditorAddress && ( $wgUser->getEmail() != '' ) && $wgUser->getOption( 'enotifrevealaddr' ) ) { @@ -362,7 +393,7 @@ class EmailNotification { // From the PHP manual: // Note: The to parameter cannot be an address in the form of "Something ". // The mail command will not parse this properly while talking with the MTA. - $to = $watchingUser->getEmail(); + $to = new MailAddress( $watchingUser ); $body = str_replace( '$WATCHINGUSERNAME', $watchingUser->getName() , $this->body ); $timecorrection = $watchingUser->getOption( 'timecorrection' ); -- 2.20.1