Index: MediaWiki/branches/1.11/includes/UserMailer.php
===================================================================
--- MediaWiki/branches/1.11/includes/UserMailer.php	(revision 1280)
+++ MediaWiki/branches/1.11/includes/UserMailer.php	(revision 1281)
@@ -73,4 +73,20 @@
 }
 
+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
@@ -86,14 +102,28 @@
  */
 function userMailer( $to, $from, $subject, $body, $replyto=null ) {
-	global $wgUser, $wgSMTP, $wgOutputEncoding, $wgErrorString;
+	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->toString();
@@ -104,5 +134,5 @@
 		$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';
 
@@ -115,16 +145,14 @@
 
 		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
@@ -149,18 +177,34 @@
 		}
 
-		$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 (function_exists('mail'))
+			if (is_array($to))
+				foreach ($to as $recip)
+					$sent = mail( $recip->toString(), wfQuotedPrintable( $subject ), $body, $headers );
+			else
+				$sent = mail( $to->toString(), wfQuotedPrintable( $subject ), $body, $headers );
+		else
+			$wgErrorString = 'PHP is not configured to send mail';
+
+
 		restore_error_handler();
 
 		if ( $wgErrorString ) {
 			wfDebug( "Error sending mail: $wgErrorString\n" );
-		}
-		return $wgErrorString;
+			return $wgErrorString;
+		} elseif (! $sent) {
+			//mail function only tells if there's an error
+			wfDebug( "Error sending mail\n" );
+			return 'mailer error';
+		} else {
+			return '';
+		}
 	}
 }
+
+
 
 /**
@@ -205,4 +249,25 @@
 	/**@}}*/
 
+	function notifyOnPageChange($editor, &$title, $timestamp, $summary, $minorEdit, $oldid = false) {
+		global $wgEnotifUseJobQ;
+	
+		if( $title->getNamespace() < 0 )
+			return;
+
+		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
@@ -213,9 +278,10 @@
 	 * @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';
@@ -235,10 +301,12 @@
 		$this->minorEdit = $minorEdit;
 		$this->oldid = $oldid;
-		$this->composeCommonMailtext();
+		$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() );
@@ -246,5 +314,5 @@
 					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;
@@ -288,5 +356,8 @@
 							# ... 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
@@ -299,6 +370,11 @@
 		foreach ( $wgUsersNotifedOnAllChanges as $name ) {
 			$user = User::newFromName( $name );
-			$this->composeAndSendPersonalisedMail( $user );
-		}
+			if ($wgEnotifImpersonal)
+				$impersonals[] = $user;
+			else
+				$this->composeAndSendPersonalisedMail( $user );
+		}
+
+		$this->composeAndSendImpersonalMail($impersonals);
 
 		if ( $wgShowUpdatedMarker || $wgEnotifWatchlist ) {
@@ -312,8 +388,10 @@
 					'wl_title' => $title->getDBkey(),
 					'wl_namespace' => $title->getNamespace(),
+					'wl_notificationtimestamp IS NULL'
 				), 'UserMailer::NotifyOnChange'
 			);
 			# FIXME what do we do on failure ?
 		}
+
 		wfProfileOut( $fname );
 	} # function NotifyOnChange
@@ -322,7 +400,8 @@
 	 * @private
 	 */
-	function composeCommonMailtext() {
-		global $wgUser, $wgEmergencyContact, $wgNoReplyAddress;
+	function composeCommonMailtext($editor) {
+		global $wgEmergencyContact, $wgNoReplyAddress;
 		global $wgEnotifFromEditor, $wgEnotifRevealEditorAddress;
+		global $wgEnotifImpersonal;
 
 		$summary = ($this->summary == '') ? ' - ' : $this->summary;
@@ -354,4 +433,12 @@
 		}
 
+		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();
@@ -367,10 +454,10 @@
 		# 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;
@@ -384,8 +471,9 @@
 		}
 
-		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 {
@@ -395,5 +483,5 @@
 			$keys['$PAGEEDITOR_EMAIL'] = $emailPage->getFullUrl();
 		}
-		$userPage = $wgUser->getUserPage();
+		$userPage = $editor->getUserPage();
 		$keys['$PAGEEDITOR_WIKI'] = $userPage->getFullUrl();
 		$body = strtr( $body, $keys );
@@ -406,6 +494,4 @@
 		$this->body    = $body;
 	}
-
-
 
 	/**
@@ -436,8 +522,31 @@
 			$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
-?>
+
