* (bug 10242) Update Chinese translations
[lhc/web/wiklou.git] / includes / UserMailer.php
index f0d1995..d74416f 100644 (file)
@@ -22,7 +22,6 @@
  * @author <brion@pobox.com>
  * @author <mail@tgries.de>
  *
- * @package MediaWiki
  */
 
 /**
@@ -33,6 +32,11 @@ function wfRFC822Phrase( $phrase ) {
        return '"' . $phrase . '"';
 }
 
+/**
+ * Stores a single person's name and email address.
+ * These are passed in via the constructor, and will be returned in SMTP
+ * header format when requested.
+ */
 class MailAddress {
        /**
         * @param mixed $address String with an email address, or a User object
@@ -68,6 +72,22 @@ class MailAddress {
        }
 }
 
+function send_mail($mailer, $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)) {
+               wfDebug( "PEAR::Mail failed: " . $mailResult->getMessage() . "\n" );
+               return $mailResult->getMessage();
+       } else {
+               wfDebug( "PEAR::Mail failed, unknown error result\n" );
+               return 'Mail object return unknown error.';
+       }
+}
+
 /**
  * This function will perform a direct (authenticated) login to
  * a SMTP Server to use for mail relaying if 'wgSMTP' specifies an
@@ -78,28 +98,42 @@ class MailAddress {
  * @param $from MailAddress: sender's email
  * @param $subject String: email's subject.
  * @param $body String: email's text.
- * @param $replyto String: optional reply-to email (default: false).
+ * @param $replyto String: optional reply-to email (default: null).
  */
-function userMailer( $to, $from, $subject, $body, $replyto=false ) {
-       global $wgUser, $wgSMTP, $wgOutputEncoding, $wgErrorString;
+function userMailer( $to, $from, $subject, $body, $replyto=null ) {
+       global $wgSMTP, $wgOutputEncoding, $wgErrorString, $wgEnotifImpersonal;
+       global $wgEnotifMaxRecips;
 
        if (is_array( $wgSMTP )) {
                require_once( 'Mail.php' );
 
-               $timestamp = time();
-               $dest = $to->address;
+               $msgid = str_replace(" ", "_", microtime());
+               if (function_exists('posix_getpid'))
+                       $msgid .= '.' . posix_getpid();
+
+               if (is_array($to)) {
+                       $dest = array();
+                       foreach ($to as $u)
+                               $dest[] = $u->address;
+               } else
+                       $dest = $to->address;
 
                $headers['From'] = $from->toString();
-               $headers['To'] = $to->toString();
+
+               if ($wgEnotifImpersonal)
+                       $headers['To'] = 'undisclosed-recipients:;';
+               else
+                       $headers['To'] = $to->toString();
+
                if ( $replyto ) {
-                       $headers['Reply-To'] = $replyto;
+                       $headers['Reply-To'] = $replyto->toString();
                }
                $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'] . '>'; // FIXME
+               $headers['Message-ID'] = "<$msgid@" . $wgSMTP['IDHost'] . '>'; // FIXME
                $headers['X-Mailer'] = 'MediaWiki mailer';
 
                // Create the mail object using the Mail::factory method
@@ -110,18 +144,16 @@ function userMailer( $to, $from, $subject, $body, $replyto=false ) {
                }
 
                wfDebug( "Sending mail via PEAR::Mail to $dest\n" );
-               $mailResult =& $mail_object->send($dest, $headers, $body);
-
-               # Based on the result return an error string,
-               if ($mailResult === true) {
-                       return '';
-               } elseif (is_object($mailResult)) {
-                       wfDebug( "PEAR::Mail failed: " . $mailResult->getMessage() . "\n" );
-                       return $mailResult->getMessage();
-               } else {
-                       wfDebug( "PEAR::Mail failed, unknown error result\n" );
-                       return 'Mail object return unknown error.';
-               }
+               if (is_array($dest)) {
+                       $chunks = array_chunk($dest, $wgEnotifMaxRecips);
+                       foreach ($chunks as $chunk) {
+                               $e = send_mail($mail_object, $chunk, $headers, $body);
+                               if ($e != '')
+                                       return $e;
+                       }
+               } else
+                       return $mail_object->send($dest, $headers, $body);
+
        } 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)
@@ -141,15 +173,19 @@ function userMailer( $to, $from, $subject, $body, $replyto=false ) {
                        "X-Mailer: MediaWiki mailer$endl".
                        'From: ' . $from->toString();
                if ($replyto) {
-                       $headers .= "{$endl}Reply-To: $replyto";
+                       $headers .= "{$endl}Reply-To: " . $replyto->toString();
                }
 
-               $dest = $to->toString();
-
                $wgErrorString = '';
                set_error_handler( 'mailErrorHandler' );
-               wfDebug( "Sending mail via internal mail() function to $dest\n" );
-               mail( $dest, wfQuotedPrintable( $subject ), $body, $headers );
+               wfDebug( "Sending mail via internal mail() function\n" );
+
+               if (is_array($to))
+                       foreach ($to as $recip)
+                               mail( $recip->toString(), wfQuotedPrintable( $subject ), $body, $headers );
+               else
+                       mail( $to->toString(), wfQuotedPrintable( $subject ), $body, $headers );
+
                restore_error_handler();
 
                if ( $wgErrorString ) {
@@ -189,7 +225,6 @@ function mailErrorHandler( $code, $string ) {
  *
  * Visit the documentation pages under http://meta.wikipedia.com/Enotif
  *
- * @package MediaWiki
  *
  */
 class EmailNotification {
@@ -201,6 +236,25 @@ class EmailNotification {
 
        /**@}}*/
 
+       function notifyOnPageChange($editor, &$title, $timestamp, $summary, $minorEdit, $oldid = false) {
+               global $wgEnotifUseJobQ;
+               global $wgEnotifWatchlist, $wgShowUpdatedMarker;
+
+               if ($wgEnotifUseJobQ) {
+                       $params = array(
+                               "editor" => $editor->getName(),
+                               "timestamp" => $timestamp,
+                               "summary" => $summary,
+                               "minorEdit" => $minorEdit,
+                               "oldid" => $oldid);
+                       $job = new EnotifNotifyJob($title, $params);
+                       $job->insert();
+               } else {
+                       $this->actuallyNotifyOnPageChange($editor, $title, $timestamp, $summary, $minorEdit, $oldid);
+               }
+
+       }
+
        /**
         * @todo document
         * @param $title Title object
@@ -209,11 +263,12 @@ class EmailNotification {
         * @param $minorEdit
         * @param $oldid (default: false)
         */
-       function notifyOnPageChange(&$title, $timestamp, $summary, $minorEdit, $oldid=false) {
+       function actuallyNotifyOnPageChange($editor, &$title, $timestamp, $summary, $minorEdit, $oldid=false) {
 
                # we use $wgEmergencyContact as sender's address
-               global $wgUser, $wgEnotifWatchlist;
+               global $wgEnotifWatchlist;
                global $wgEnotifMinorEdits, $wgEnotifUserTalk, $wgShowUpdatedMarker;
+               global $wgEnotifImpersonal;
 
                $fname = 'UserMailer::notifyOnPageChange';
                wfProfileIn( $fname );
@@ -226,16 +281,25 @@ class EmailNotification {
                $enotifusertalkpage = ($isUserTalkPage && $wgEnotifUserTalk);
                $enotifwatchlistpage = $wgEnotifWatchlist;
 
+               $this->title =& $title;
+               $this->timestamp = $timestamp;
+               $this->summary = $summary;
+               $this->minorEdit = $minorEdit;
+               $this->oldid = $oldid;
+               $this->composeCommonMailtext($editor);
+
+               $impersonals = array();
+
                if ( (!$minorEdit || $wgEnotifMinorEdits) ) {
                        if( $wgEnotifWatchlist ) {
                                // Send updates to watchers other than the current editor
-                               $userCondition = 'wl_user <> ' . intval( $wgUser->getId() );
+                               $userCondition = 'wl_user <> ' . intval( $editor->getId() );
                        } elseif( $wgEnotifUserTalk && $title->getNamespace() == NS_USER_TALK ) {
                                $targetUser = User::newFromName( $title->getText() );
                                if( is_null( $targetUser ) ) {
                                        wfDebug( "$fname: user-talk-only mode; no such user\n" );
                                        $userCondition = false;
-                               } elseif( $targetUser->getId() == $wgUser->getId() ) {
+                               } elseif( $targetUser->getId() == $editor->getId() ) {
                                        wfDebug( "$fname: user-talk-only mode; editor is target user\n" );
                                        $userCondition = false;
                                } else {
@@ -247,7 +311,7 @@ class EmailNotification {
                                $userCondition = false;
                        }
                        if( $userCondition ) {
-                               $dbr =& wfGetDB( DB_MASTER );
+                               $dbr = wfGetDB( DB_MASTER );
 
                                $res = $dbr->select( 'watchlist', array( 'wl_user' ),
                                        array(
@@ -260,13 +324,7 @@ class EmailNotification {
                                # if anyone is watching ... set up the email message text which is
                                # common for all receipients ...
                                if ( $dbr->numRows( $res ) > 0 ) {
-                                       $this->title =& $title;
-                                       $this->timestamp = $timestamp;
-                                       $this->summary = $summary;
-                                       $this->minorEdit = $minorEdit;
-                                       $this->oldid = $oldid;
 
-                                       $this->composeCommonMailtext();
                                        $watchingUser = new User();
 
                                        # ... now do for all watching users ... if the options fit
@@ -283,7 +341,10 @@ class EmailNotification {
                                                && ($watchingUser->isEmailConfirmed() ) ) {
                                                        # ... adjust remaining text and page edit time placeholders
                                                        # which needs to be personalized for each user
-                                                       $this->composeAndSendPersonalisedMail( $watchingUser );
+                                                       if ($wgEnotifImpersonal)
+                                                               $impersonals[] = $watchingUser;
+                                                       else
+                                                               $this->composeAndSendPersonalisedMail( $watchingUser );
 
                                                } # if the watching user has an email address in the preferences
                                        }
@@ -291,10 +352,21 @@ class EmailNotification {
                        } # if anyone is watching
                } # if $wgEnotifWatchlist = true
 
+               global $wgUsersNotifedOnAllChanges;
+               foreach ( $wgUsersNotifedOnAllChanges as $name ) {
+                       $user = User::newFromName( $name );
+                       if ($wgEnotifImpersonal)
+                               $impersonals[] = $user;
+                       else
+                               $this->composeAndSendPersonalisedMail( $user );
+               }
+
+               $this->composeAndSendImpersonalMail($impersonals);
+
                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, ...
-                       $dbw =& wfGetDB( DB_MASTER );
+                       $dbw = wfGetDB( DB_MASTER );
                        $success = $dbw->update( 'watchlist',
                                array( /* SET */
                                        'wl_notificationtimestamp' => $dbw->timestamp($timestamp)
@@ -305,15 +377,17 @@ class EmailNotification {
                        );
                        # FIXME what do we do on failure ?
                }
+
                wfProfileOut( $fname );
        } # function NotifyOnChange
 
        /**
         * @private
         */
-       function composeCommonMailtext() {
-               global $wgUser, $wgEmergencyContact, $wgNoReplyAddress;
+       function composeCommonMailtext($editor) {
+               global $wgEmergencyContact, $wgNoReplyAddress;
                global $wgEnotifFromEditor, $wgEnotifRevealEditorAddress;
+               global $wgEnotifImpersonal;
 
                $summary = ($this->summary == '') ? ' - ' : $this->summary;
                $medit   = ($this->minorEdit) ? wfMsg( 'minoredit' ) : '';
@@ -343,6 +417,14 @@ class EmailNotification {
                        $keys['$CHANGEDORCREATED'] = wfMsgForContent( 'created' );
                }
 
+               if ($wgEnotifImpersonal && $this->oldid)
+                       /*
+                        * For impersonal mail, show a diff link to the last 
+                        * revision.
+                        */
+                       $keys['$NEWPAGE'] = wfMsgForContent('enotif_lastdiff',
+                                       $this->title->getFullURL("oldid={$this->oldid}&diff=prev"));
+
                $body = strtr( $body, $keys );
                $pagetitle = $this->title->getPrefixedText();
                $keys['$PAGETITLE']          = $pagetitle;
@@ -356,12 +438,12 @@ 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.
-               $name    = $wgUser->getName();
+               $name    = $editor->getName();
                $adminAddress = new MailAddress( $wgEmergencyContact, 'WikiAdmin' );
-               $editorAddress = new MailAddress( $wgUser );
+               $editorAddress = new MailAddress( $editor );
                if( $wgEnotifRevealEditorAddress
-                   && ( $wgUser->getEmail() != '' )
-                   && $wgUser->getOption( 'enotifrevealaddr' ) ) {
+                   && ( $editor->getEmail() != '' )
+                   && $editor->getOption( 'enotifrevealaddr' ) ) {
                        if( $wgEnotifFromEditor ) {
                                $from    = $editorAddress;
                        } else {
@@ -370,13 +452,14 @@ class EmailNotification {
                        }
                } else {
                        $from    = $adminAddress;
-                       $replyto = $wgNoReplyAddress;
+                       $replyto = new MailAddress( $wgNoReplyAddress );
                }
 
-               if( $wgUser->isIP( $name ) ) {
+               if( $editor->isIP( $name ) ) {
                        #real anon (user:xxx.xxx.xxx.xxx)
-                       $subject = str_replace('$PAGEEDITOR', 'anonymous user '. $name, $subject);
-                       $keys['$PAGEEDITOR']       = 'anonymous user ' . $name;
+                       $utext = wfMsgForContent('enotif_anon_editor', $name);
+                       $subject = str_replace('$PAGEEDITOR', $utext, $subject);
+                       $keys['$PAGEEDITOR']       = $utext;
                        $keys['$PAGEEDITOR_EMAIL'] = wfMsgForContent( 'noemailtitle' );
                } else {
                        $subject = str_replace('$PAGEEDITOR', $name, $subject);
@@ -384,7 +467,7 @@ class EmailNotification {
                        $emailPage = SpecialPage::getSafeTitleFor( 'Emailuser', $name );
                        $keys['$PAGEEDITOR_EMAIL'] = $emailPage->getFullUrl();
                }
-               $userPage = $wgUser->getUserPage();
+               $userPage = $editor->getUserPage();
                $keys['$PAGEEDITOR_WIKI'] = $userPage->getFullUrl();
                $body = strtr( $body, $keys );
                $body = wordwrap( $body, 72 );
@@ -396,8 +479,6 @@ class EmailNotification {
                $this->body    = $body;
        }
 
-
-
        /**
         * Does the per-user customizations to a notification e-mail (name,
         * timestamp in proper timezone, etc) and sends it out.
@@ -425,8 +506,31 @@ class EmailNotification {
                        $wgLang->timeanddate( $this->timestamp, true, false, $timecorrection ),
                        $body);
 
-               $error = userMailer( $to, $this->from, $this->subject, $body, $this->replyto );
-               return ($error == '');
+               return userMailer($to, $this->from, $this->subject, $body, $this->replyto);
+       }
+
+       /**
+        * Same as composeAndSendPersonalisedMail but does impersonal mail 
+        * suitable for bulk mailing.  Takes an array of users.
+        */
+       function composeAndSendImpersonalMail($users) {
+               global $wgLang;
+
+               if (empty($users))
+                       return;
+
+               $to = array();
+               foreach ($users as $user)
+                       $to[] = new MailAddress($user);
+
+               $body = str_replace(
+                               array(  '$WATCHINGUSERNAME',
+                                       '$PAGEEDITDATE'),
+                               array(  wfMsgForContent('enotif_impersonal_salutation'),
+                                       $wgLang->timeanddate($this->timestamp, true, false, false)),
+                               $this->body);
+               
+               return userMailer($to, $this->from, $this->subject, $body, $this->replyto);
        }
 
 } # end of class EmailNotification