Typo
[lhc/web/wiklou.git] / includes / UserMailer.php
index 19a4728..561ad1d 100644 (file)
@@ -29,8 +29,8 @@
  */
 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
+        * @param $address Mixed: string with an email address, or a User object
+        * @param $name String: human-readable name if a string address is given
         */
        function __construct( $address, $name=null ) {
                if( is_object( $address ) && $address instanceof User ) {
@@ -52,7 +52,7 @@ class MailAddress {
                # so don't bother generating them
                if( $this->name != '' && !wfIsWindows() ) {
                        $quoted = wfQuotedPrintable( $this->name );
-                       if( strpos( $quoted, '.' ) !== false ) {
+                       if( strpos( $quoted, '.' ) !== false || strpos( $quoted, ',' ) !== false ) {
                                $quoted = '"' . $quoted . '"';
                        }
                        return "$quoted <{$this->address}>";
@@ -76,17 +76,14 @@ class UserMailer {
         */
        protected static function sendWithPear($mailer, $dest, $headers, $body)
        {
-               $mailResult =& $mailer->send($dest, $headers, $body);
+               $mailResult = $mailer->send($dest, $headers, $body);
 
                # Based on the result return an error string,
-               if ($mailResult === true) {
-                       return '';
-               } elseif (is_object($mailResult)) {
+               if( PEAR::isError( $mailResult ) ) {
                        wfDebug( "PEAR::Mail failed: " . $mailResult->getMessage() . "\n" );
-                       return $mailResult->getMessage();
+                       return new WikiError( $mailResult->getMessage() );
                } else {
-                       wfDebug( "PEAR::Mail failed, unknown error result\n" );
-                       return 'Mail object return unknown error.';
+                       return true;
                }
        }
 
@@ -101,8 +98,10 @@ class UserMailer {
         * @param $subject String: email's subject.
         * @param $body String: email's text.
         * @param $replyto String: optional reply-to email (default: null).
+        * @param $contentType String: optional custom Content-Type
+        * @return mixed True on success, a WikiError object on failure.
         */
-       static function send( $to, $from, $subject, $body, $replyto=null ) {
+       static function send( $to, $from, $subject, $body, $replyto=null, $contentType=null ) {
                global $wgSMTP, $wgOutputEncoding, $wgErrorString, $wgEnotifImpersonal;
                global $wgEnotifMaxRecips;
 
@@ -128,10 +127,12 @@ class UserMailer {
 
                        $headers['From'] = $from->toString();
 
-                       if ($wgEnotifImpersonal)
+                       if ($wgEnotifImpersonal) {
                                $headers['To'] = 'undisclosed-recipients:;';
-                       else
-                               $headers['To'] = $to->toString();
+                       }
+                       else {
+                               $headers['To'] = implode( ", ", (array )$dest );
+                       }
 
                        if ( $replyto ) {
                                $headers['Reply-To'] = $replyto->toString();
@@ -139,7 +140,8 @@ class UserMailer {
                        $headers['Subject'] = wfQuotedPrintable( $subject );
                        $headers['Date'] = date( 'r' );
                        $headers['MIME-Version'] = '1.0';
-                       $headers['Content-type'] = 'text/plain; charset='.$wgOutputEncoding;
+                       $headers['Content-type'] = (is_null($contentType) ?
+                                       'text/plain; charset='.$wgOutputEncoding : $contentType);
                        $headers['Content-transfer-encoding'] = '8bit';
                        $headers['Message-ID'] = "<$msgid@" . $wgSMTP['IDHost'] . '>'; // FIXME
                        $headers['X-Mailer'] = 'MediaWiki mailer';
@@ -148,25 +150,21 @@ class UserMailer {
                        $mail_object =& Mail::factory('smtp', $wgSMTP);
                        if( PEAR::isError( $mail_object ) ) {
                                wfDebug( "PEAR::Mail factory failed: " . $mail_object->getMessage() . "\n" );
-                               return $mail_object->getMessage();
+                               return new WikiError( $mail_object->getMessage() );
                        }
 
                        wfDebug( "Sending mail via PEAR::Mail to $dest\n" );
-                       if (is_array($dest)) {
-                               $chunks = array_chunk($dest, $wgEnotifMaxRecips);
-                               foreach ($chunks as $chunk) {
-                                       $e = self::sendWithPear($mail_object, $chunk, $headers, $body);
-                                       if ($e != '')
-                                               return $e;
-                               }
-                       } else
-                               return $mail_object->send($dest, $headers, $body);
-
+                       $chunks = array_chunk( (array)$dest, $wgEnotifMaxRecips );
+                       foreach ($chunks as $chunk) {
+                               $e = self::sendWithPear($mail_object, $chunk, $headers, $body);
+                               if( WikiError::isError( $e ) )
+                                       return $e;
+                       }
                } else  {
                        # In the following $headers = expression we removed "Reply-To: {$from}\r\n" , because it is treated differently
                        # (fifth parameter of the PHP mail function, see some lines below)
 
-                       # Line endings need to be different on Unix and Windows due to 
+                       # Line endings need to be different on Unix and Windows due to
                        # the bug described at http://trac.wordpress.org/ticket/2603
                        if ( wfIsWindows() ) {
                                $body = str_replace( "\n", "\r\n", $body );
@@ -174,9 +172,11 @@ class UserMailer {
                        } else {
                                $endl = "\n";
                        }
+                       $ctype = (is_null($contentType) ? 
+                                       'text/plain; charset='.$wgOutputEncoding : $contentType);
                        $headers =
                                "MIME-Version: 1.0$endl" .
-                               "Content-type: text/plain; charset={$wgOutputEncoding}$endl" .
+                               "Content-type: $ctype$endl" .
                                "Content-Transfer-Encoding: 8bit$endl" .
                                "X-Mailer: MediaWiki mailer$endl".
                                'From: ' . $from->toString();
@@ -207,13 +207,13 @@ class UserMailer {
 
                        if ( $wgErrorString ) {
                                wfDebug( "Error sending mail: $wgErrorString\n" );
-                               return $wgErrorString;
+                               return new WikiError( $wgErrorString );
                        } elseif (! $sent) {
                                //mail function only tells if there's an error
                                wfDebug( "Error sending mail\n" );
-                               return 'mailer error';
+                               return new WikiError( 'mailer error' );
                        } else {
-                               return '';
+                               return true;
                        }
                }
        }
@@ -259,17 +259,12 @@ class UserMailer {
  *
  */
 class EmailNotification {
-       /**@{{
-        * @private
-        */
-       var $to, $subject, $body, $replyto, $from;
-       var $user, $title, $timestamp, $summary, $minorEdit, $oldid;
-       var $mailTargets = array();
-
-       /**@}}*/
+       private $to, $subject, $body, $replyto, $from;
+       private $user, $title, $timestamp, $summary, $minorEdit, $oldid, $composed_common, $editor;
+       private $mailTargets = array();
 
        /**
-        * Send emails corresponding to the user $editor editing the page $title. 
+        * Send emails corresponding to the user $editor editing the page $title.
         * Also updates wl_notificationtimestamp.
         *
         * May be deferred via the job queue.
@@ -283,13 +278,14 @@ class EmailNotification {
         */
        function notifyOnPageChange($editor, $title, $timestamp, $summary, $minorEdit, $oldid = false) {
                global $wgEnotifUseJobQ;
-       
+
                if( $title->getNamespace() < 0 )
                        return;
 
                if ($wgEnotifUseJobQ) {
                        $params = array(
                                "editor" => $editor->getName(),
+                               "editorID" => $editor->getID(),
                                "timestamp" => $timestamp,
                                "summary" => $summary,
                                "minorEdit" => $minorEdit,
@@ -303,9 +299,9 @@ class EmailNotification {
        }
 
        /*
-        * Immediate version of notifyOnPageChange(). 
+        * Immediate version of notifyOnPageChange().
         *
-        * Send emails corresponding to the user $editor editing the page $title. 
+        * Send emails corresponding to the user $editor editing the page $title.
         * Also updates wl_notificationtimestamp.
         *
         * @param $editor User object
@@ -317,7 +313,7 @@ class EmailNotification {
         */
        function actuallyNotifyOnPageChange($editor, $title, $timestamp, $summary, $minorEdit, $oldid=false) {
 
-               # we use $wgEmergencyContact as sender's address
+               # we use $wgPasswordSender as sender's address
                global $wgEnotifWatchlist;
                global $wgEnotifMinorEdits, $wgEnotifUserTalk, $wgShowUpdatedMarker;
                global $wgEnotifImpersonal;
@@ -337,7 +333,8 @@ class EmailNotification {
                $this->summary = $summary;
                $this->minorEdit = $minorEdit;
                $this->oldid = $oldid;
-               $this->composeCommonMailtext($editor);
+               $this->editor = $editor;
+               $this->composed_common = false;
 
                $userTalkId = false;
 
@@ -349,37 +346,44 @@ class EmailNotification {
                                } elseif ( $targetUser->getId() == $editor->getId() ) {
                                        wfDebug( __METHOD__.": user edited their own talk page, no notification sent\n" );
                                } elseif( $targetUser->getOption( 'enotifusertalkpages' ) ) {
-                                       wfDebug( __METHOD__.": sending talk page update notification\n" );
-                                       $this->compose( $targetUser );
-                                       $userTalkId = $targetUser->getId();
+                                       if( $targetUser->isEmailConfirmed() ) {
+                                               wfDebug( __METHOD__.": sending talk page update notification\n" );
+                                               $this->compose( $targetUser );
+                                               $userTalkId = $targetUser->getId();
+                                       } else {
+                                               wfDebug( __METHOD__.": talk page owner doesn't have validated email\n" );
+                                       }
                                } else {
                                        wfDebug( __METHOD__.": talk page owner doesn't want notifications\n" );
                                }
                        }
 
-
                        if ( $wgEnotifWatchlist ) {
                                // Send updates to watchers other than the current editor
-                               $userCondition = 'wl_user <> ' . intval( $editor->getId() );
+                               $userCondition = 'wl_user != ' . $editor->getID();
                                if ( $userTalkId !== false ) {
-                                       // Already sent an email to this person 
-                                       $userCondition .= ' AND wl_user <> ' . intval( $userTalkId );
+                                       // Already sent an email to this person
+                                       $userCondition .= ' AND wl_user != ' . intval( $userTalkId );
                                }
                                $dbr = wfGetDB( DB_SLAVE );
 
-                               $res = $dbr->select( 'watchlist', array( 'wl_user' ),
+                               list( $user ) = $dbr->tableNamesN( 'user' );
+
+                               $res = $dbr->select( array( 'watchlist', 'user' ),
+                                       array( "$user.*" ),
                                        array(
+                                               'wl_user=user_id',
                                                'wl_title' => $title->getDBkey(),
                                                'wl_namespace' => $title->getNamespace(),
                                                $userCondition,
                                                'wl_notificationtimestamp IS NULL',
                                        ), __METHOD__ );
+                               $userArray = UserArray::newFromResult( $res );
 
-                               foreach ( $res as $row ) {
-                                       $watchingUser = User::newFromId( $row->wl_user );
-                                       if ( $watchingUser->getOption( 'enotifwatchlistpages' ) && 
-                                               ( !$minorEdit || $watchingUser->getOption('enotifminoredits') ) && 
-                                               $watchingUser->isEmailConfirmed() ) 
+                               foreach ( $userArray as $watchingUser ) {
+                                       if ( $watchingUser->getOption( 'enotifwatchlistpages' ) &&
+                                               ( !$minorEdit || $watchingUser->getOption('enotifminoredits') ) &&
+                                               $watchingUser->isEmailConfirmed() )
                                        {
                                                $this->compose( $watchingUser );
                                        }
@@ -387,8 +391,8 @@ class EmailNotification {
                        }
                }
 
-               global $wgUsersNotifedOnAllChanges;
-               foreach ( $wgUsersNotifedOnAllChanges as $name ) {
+               global $wgUsersNotifiedOnAllChanges;
+               foreach ( $wgUsersNotifiedOnAllChanges as $name ) {
                        $user = User::newFromName( $name );
                        $this->compose( $user );
                }
@@ -396,8 +400,9 @@ class EmailNotification {
                $this->sendMails();
 
                if ( $wgShowUpdatedMarker || $wgEnotifWatchlist ) {
-                       # mark the changed watch-listed page with a timestamp, so that the page is
-                       # listed with an "updated since your last visit" icon in the watch list, ...
+                       # Mark the changed watch-listed page with a timestamp, so that the page is
+                       # listed with an "updated since your last visit" icon in the watch list. Do
+                       # not do this to users for their own edits.
                        $dbw = wfGetDB( DB_MASTER );
                        $dbw->update( 'watchlist',
                                array( /* SET */
@@ -405,7 +410,8 @@ class EmailNotification {
                                ), array( /* WHERE */
                                        'wl_title' => $title->getDBkey(),
                                        'wl_namespace' => $title->getNamespace(),
-                                       'wl_notificationtimestamp IS NULL'
+                                       'wl_notificationtimestamp IS NULL',
+                                       'wl_user != ' . $editor->getID()
                                ), __METHOD__
                        );
                }
@@ -416,11 +422,13 @@ class EmailNotification {
        /**
         * @private
         */
-       function composeCommonMailtext($editor) {
-               global $wgEmergencyContact, $wgNoReplyAddress;
+       function composeCommonMailtext() {
+               global $wgPasswordSender, $wgNoReplyAddress;
                global $wgEnotifFromEditor, $wgEnotifRevealEditorAddress;
                global $wgEnotifImpersonal;
 
+               $this->composed_common = true;
+
                $summary = ($this->summary == '') ? ' - ' : $this->summary;
                $medit   = ($this->minorEdit) ? wfMsg( 'minoredit' ) : '';
 
@@ -451,7 +459,7 @@ class EmailNotification {
 
                if ($wgEnotifImpersonal && $this->oldid)
                        /*
-                        * For impersonal mail, show a diff link to the last 
+                        * For impersonal mail, show a diff link to the last
                         * revision.
                         */
                        $keys['$NEWPAGE'] = wfMsgForContent('enotif_lastdiff',
@@ -470,8 +478,9 @@ class EmailNotification {
                # Reveal the page editor's address as REPLY-TO address only if
                # the user has not opted-out and the option is enabled at the
                # global configuration level.
+               $editor = $this->editor;
                $name    = $editor->getName();
-               $adminAddress = new MailAddress( $wgEmergencyContact, 'WikiAdmin' );
+               $adminAddress = new MailAddress( $wgPasswordSender, 'WikiAdmin' );
                $editorAddress = new MailAddress( $editor );
                if( $wgEnotifRevealEditorAddress
                    && ( $editor->getEmail() != '' )
@@ -519,6 +528,10 @@ class EmailNotification {
         */
        function compose( $user ) {
                global $wgEnotifImpersonal;
+
+               if ( !$this->composed_common )
+                       $this->composeCommonMailtext();
+
                if ( $wgEnotifImpersonal ) {
                        $this->mailTargets[] = new MailAddress( $user );
                } else {
@@ -567,7 +580,7 @@ class EmailNotification {
        }
 
        /**
-        * Same as sendPersonalised but does impersonal mail suitable for bulk 
+        * Same as sendPersonalised but does impersonal mail suitable for bulk
         * mailing.  Takes an array of MailAddress objects.
         */
        function sendImpersonal( $addresses ) {
@@ -582,7 +595,7 @@ class EmailNotification {
                                array(  wfMsgForContent('enotif_impersonal_salutation'),
                                        $wgLang->timeanddate($this->timestamp, true, false, false)),
                                $this->body);
-               
+
                return UserMailer::send($addresses, $this->from, $this->subject, $body, $this->replyto);
        }
 
@@ -594,9 +607,7 @@ class EmailNotification {
 function wfRFC822Phrase( $s ) {
        return UserMailer::rfc822Phrase( $s );
 }
+
 function userMailer( $to, $from, $subject, $body, $replyto=null ) {
        return UserMailer::send( $to, $from, $subject, $body, $replyto );
 }
-
-
-