MediaWiki
REL1_21
|
00001 <?php 00032 class MailAddress { 00038 function __construct( $address, $name = null, $realName = null ) { 00039 if ( is_object( $address ) && $address instanceof User ) { 00040 $this->address = $address->getEmail(); 00041 $this->name = $address->getName(); 00042 $this->realName = $address->getRealName(); 00043 } else { 00044 $this->address = strval( $address ); 00045 $this->name = strval( $name ); 00046 $this->realName = strval( $realName ); 00047 } 00048 } 00049 00054 function toString() { 00055 # PHP's mail() implementation under Windows is somewhat shite, and 00056 # can't handle "Joe Bloggs <[email protected]>" format email addresses, 00057 # so don't bother generating them 00058 if ( $this->address ) { 00059 if ( $this->name != '' && !wfIsWindows() ) { 00060 global $wgEnotifUseRealName; 00061 $name = ( $wgEnotifUseRealName && $this->realName ) ? $this->realName : $this->name; 00062 $quoted = UserMailer::quotedPrintable( $name ); 00063 if ( strpos( $quoted, '.' ) !== false || strpos( $quoted, ',' ) !== false ) { 00064 $quoted = '"' . $quoted . '"'; 00065 } 00066 return "$quoted <{$this->address}>"; 00067 } else { 00068 return $this->address; 00069 } 00070 } else { 00071 return ""; 00072 } 00073 } 00074 00075 function __toString() { 00076 return $this->toString(); 00077 } 00078 } 00079 00083 class UserMailer { 00084 static $mErrorString; 00085 00096 protected static function sendWithPear( $mailer, $dest, $headers, $body ) { 00097 $mailResult = $mailer->send( $dest, $headers, $body ); 00098 00099 # Based on the result return an error string, 00100 if ( PEAR::isError( $mailResult ) ) { 00101 wfDebug( "PEAR::Mail failed: " . $mailResult->getMessage() . "\n" ); 00102 return Status::newFatal( 'pear-mail-error', $mailResult->getMessage() ); 00103 } else { 00104 return Status::newGood(); 00105 } 00106 } 00107 00120 static function arrayToHeaderString( $headers, $endl = "\n" ) { 00121 $strings = array(); 00122 foreach( $headers as $name => $value ) { 00123 $strings[] = "$name: $value"; 00124 } 00125 return implode( $endl, $strings ); 00126 } 00127 00133 static function makeMsgId() { 00134 global $wgSMTP, $wgServer; 00135 00136 $msgid = uniqid( wfWikiID() . ".", true ); /* true required for cygwin */ 00137 if ( is_array( $wgSMTP ) && isset( $wgSMTP['IDHost'] ) && $wgSMTP['IDHost'] ) { 00138 $domain = $wgSMTP['IDHost']; 00139 } else { 00140 $url = wfParseUrl( $wgServer ); 00141 $domain = $url['host']; 00142 } 00143 return "<$msgid@$domain>"; 00144 } 00145 00161 public static function send( $to, $from, $subject, $body, $replyto = null, $contentType = 'text/plain; charset=UTF-8' ) { 00162 global $wgSMTP, $wgEnotifMaxRecips, $wgAdditionalMailParams, $wgAllowHTMLEmail; 00163 $mime = null; 00164 if ( !is_array( $to ) ) { 00165 $to = array( $to ); 00166 } 00167 00168 // mail body must have some content 00169 $minBodyLen = 10; 00170 // arbitrary but longer than Array or Object to detect casting error 00171 00172 // body must either be a string or an array with text and body 00173 if ( 00174 !( 00175 !is_array( $body ) && 00176 strlen( $body ) >= $minBodyLen 00177 ) 00178 && 00179 !( 00180 is_array( $body ) && 00181 isset( $body['text'] ) && 00182 isset( $body['html'] ) && 00183 strlen( $body['text'] ) >= $minBodyLen && 00184 strlen( $body['html'] ) >= $minBodyLen 00185 ) 00186 ) { 00187 // if it is neither we have a problem 00188 return Status::newFatal( 'user-mail-no-body' ); 00189 } 00190 00191 if ( !$wgAllowHTMLEmail && is_array( $body ) ) { 00192 // HTML not wanted. Dump it. 00193 $body = $body['text']; 00194 } 00195 00196 wfDebug( __METHOD__ . ': sending mail to ' . implode( ', ', $to ) . "\n" ); 00197 00198 # Make sure we have at least one address 00199 $has_address = false; 00200 foreach ( $to as $u ) { 00201 if ( $u->address ) { 00202 $has_address = true; 00203 break; 00204 } 00205 } 00206 if ( !$has_address ) { 00207 return Status::newFatal( 'user-mail-no-addy' ); 00208 } 00209 00210 # Forge email headers 00211 # ------------------- 00212 # 00213 # WARNING 00214 # 00215 # DO NOT add To: or Subject: headers at this step. They need to be 00216 # handled differently depending upon the mailer we are going to use. 00217 # 00218 # To: 00219 # PHP mail() first argument is the mail receiver. The argument is 00220 # used as a recipient destination and as a To header. 00221 # 00222 # PEAR mailer has a recipient argument which is only used to 00223 # send the mail. If no To header is given, PEAR will set it to 00224 # to 'undisclosed-recipients:'. 00225 # 00226 # NOTE: To: is for presentation, the actual recipient is specified 00227 # by the mailer using the Rcpt-To: header. 00228 # 00229 # Subject: 00230 # PHP mail() second argument to pass the subject, passing a Subject 00231 # as an additional header will result in a duplicate header. 00232 # 00233 # PEAR mailer should be passed a Subject header. 00234 # 00235 # -- hashar 20120218 00236 00237 $headers['From'] = $from->toString(); 00238 $headers['Return-Path'] = $from->address; 00239 00240 if ( $replyto ) { 00241 $headers['Reply-To'] = $replyto->toString(); 00242 } 00243 00244 $headers['Date'] = date( 'r' ); 00245 $headers['Message-ID'] = self::makeMsgId(); 00246 $headers['X-Mailer'] = 'MediaWiki mailer'; 00247 00248 # Line endings need to be different on Unix and Windows due to 00249 # the bug described at http://trac.wordpress.org/ticket/2603 00250 if ( wfIsWindows() ) { 00251 $endl = "\r\n"; 00252 } else { 00253 $endl = "\n"; 00254 } 00255 00256 if ( is_array( $body ) ) { 00257 // we are sending a multipart message 00258 wfDebug( "Assembling multipart mime email\n" ); 00259 if ( !stream_resolve_include_path( 'Mail/mime.php' ) ) { 00260 wfDebug( "PEAR Mail_Mime package is not installed. Falling back to text email.\n" ); 00261 } 00262 else { 00263 require_once( 'Mail/mime.php' ); 00264 if ( wfIsWindows() ) { 00265 $body['text'] = str_replace( "\n", "\r\n", $body['text'] ); 00266 $body['html'] = str_replace( "\n", "\r\n", $body['html'] ); 00267 } 00268 $mime = new Mail_mime( array( 'eol' => $endl ) ); 00269 $mime->setTXTBody( $body['text'] ); 00270 $mime->setHTMLBody( $body['html'] ); 00271 $body = $mime->get(); // must call get() before headers() 00272 $headers = $mime->headers( $headers ); 00273 } 00274 } 00275 if ( !isset( $mime ) ) { 00276 // sending text only, either deliberately or as a fallback 00277 if ( wfIsWindows() ) { 00278 $body = str_replace( "\n", "\r\n", $body ); 00279 } 00280 $headers['MIME-Version'] = '1.0'; 00281 $headers['Content-type'] = ( is_null( $contentType ) ? 00282 'text/plain; charset=UTF-8' : $contentType ); 00283 $headers['Content-transfer-encoding'] = '8bit'; 00284 } 00285 00286 $ret = wfRunHooks( 'AlternateUserMailer', array( $headers, $to, $from, $subject, $body ) ); 00287 if ( $ret === false ) { 00288 // the hook implementation will return false to skip regular mail sending 00289 return Status::newGood(); 00290 } elseif ( $ret !== true ) { 00291 // the hook implementation will return a string to pass an error message 00292 return Status::newFatal( 'php-mail-error', $ret ); 00293 } 00294 00295 if ( is_array( $wgSMTP ) ) { 00296 # 00297 # PEAR MAILER 00298 # 00299 00300 if ( !stream_resolve_include_path( 'Mail.php' ) ) { 00301 throw new MWException( 'PEAR mail package is not installed' ); 00302 } 00303 require_once( 'Mail.php' ); 00304 00305 wfSuppressWarnings(); 00306 00307 // Create the mail object using the Mail::factory method 00308 $mail_object =& Mail::factory( 'smtp', $wgSMTP ); 00309 if ( PEAR::isError( $mail_object ) ) { 00310 wfDebug( "PEAR::Mail factory failed: " . $mail_object->getMessage() . "\n" ); 00311 wfRestoreWarnings(); 00312 return Status::newFatal( 'pear-mail-error', $mail_object->getMessage() ); 00313 } 00314 00315 wfDebug( "Sending mail via PEAR::Mail\n" ); 00316 00317 $headers['Subject'] = self::quotedPrintable( $subject ); 00318 00319 # When sending only to one recipient, shows it its email using To: 00320 if ( count( $to ) == 1 ) { 00321 $headers['To'] = $to[0]->toString(); 00322 } 00323 00324 # Split jobs since SMTP servers tends to limit the maximum 00325 # number of possible recipients. 00326 $chunks = array_chunk( $to, $wgEnotifMaxRecips ); 00327 foreach ( $chunks as $chunk ) { 00328 $status = self::sendWithPear( $mail_object, $chunk, $headers, $body ); 00329 # FIXME : some chunks might be sent while others are not! 00330 if ( !$status->isOK() ) { 00331 wfRestoreWarnings(); 00332 return $status; 00333 } 00334 } 00335 wfRestoreWarnings(); 00336 return Status::newGood(); 00337 } else { 00338 # 00339 # PHP mail() 00340 # 00341 if( count( $to ) > 1 ) { 00342 $headers['To'] = 'undisclosed-recipients:;'; 00343 } 00344 $headers = self::arrayToHeaderString( $headers, $endl ); 00345 00346 wfDebug( "Sending mail via internal mail() function\n" ); 00347 00348 self::$mErrorString = ''; 00349 $html_errors = ini_get( 'html_errors' ); 00350 ini_set( 'html_errors', '0' ); 00351 set_error_handler( 'UserMailer::errorHandler' ); 00352 00353 $safeMode = wfIniGetBool( 'safe_mode' ); 00354 00355 foreach ( $to as $recip ) { 00356 if ( $safeMode ) { 00357 $sent = mail( $recip, self::quotedPrintable( $subject ), $body, $headers ); 00358 } else { 00359 $sent = mail( $recip, self::quotedPrintable( $subject ), $body, $headers, $wgAdditionalMailParams ); 00360 } 00361 } 00362 00363 restore_error_handler(); 00364 ini_set( 'html_errors', $html_errors ); 00365 00366 if ( self::$mErrorString ) { 00367 wfDebug( "Error sending mail: " . self::$mErrorString . "\n" ); 00368 return Status::newFatal( 'php-mail-error', self::$mErrorString ); 00369 } elseif ( ! $sent ) { 00370 // mail function only tells if there's an error 00371 wfDebug( "Unknown error sending mail\n" ); 00372 return Status::newFatal( 'php-mail-error-unknown' ); 00373 } else { 00374 return Status::newGood(); 00375 } 00376 } 00377 } 00378 00385 static function errorHandler( $code, $string ) { 00386 self::$mErrorString = preg_replace( '/^mail\(\)(\s*\[.*?\])?: /', '', $string ); 00387 } 00388 00394 public static function rfc822Phrase( $phrase ) { 00395 $phrase = strtr( $phrase, array( "\r" => '', "\n" => '', '"' => '' ) ); 00396 return '"' . $phrase . '"'; 00397 } 00398 00410 public static function quotedPrintable( $string, $charset = '' ) { 00411 # Probably incomplete; see RFC 2045 00412 if( empty( $charset ) ) { 00413 $charset = 'UTF-8'; 00414 } 00415 $charset = strtoupper( $charset ); 00416 $charset = str_replace( 'ISO-8859', 'ISO8859', $charset ); // ? 00417 00418 $illegal = '\x00-\x08\x0b\x0c\x0e-\x1f\x7f-\xff='; 00419 $replace = $illegal . '\t ?_'; 00420 if( !preg_match( "/[$illegal]/", $string ) ) { 00421 return $string; 00422 } 00423 $out = "=?$charset?Q?"; 00424 $out .= preg_replace_callback( "/([$replace])/", 00425 array( __CLASS__, 'quotedPrintableCallback' ), $string ); 00426 $out .= '?='; 00427 return $out; 00428 } 00429 00430 protected static function quotedPrintableCallback( $matches ) { 00431 return sprintf( "=%02X", ord( $matches[1] ) ); 00432 } 00433 } 00434 00455 class EmailNotification { 00456 protected $subject, $body, $replyto, $from; 00457 protected $timestamp, $summary, $minorEdit, $oldid, $composed_common, $pageStatus; 00458 protected $mailTargets = array(); 00459 00463 protected $title; 00464 00468 protected $editor; 00469 00484 public function notifyOnPageChange( $editor, $title, $timestamp, $summary, $minorEdit, $oldid = false, $pageStatus = 'changed' ) { 00485 global $wgEnotifUseJobQ, $wgEnotifWatchlist, $wgShowUpdatedMarker, $wgEnotifMinorEdits, 00486 $wgUsersNotifiedOnAllChanges, $wgEnotifUserTalk; 00487 00488 if ( $title->getNamespace() < 0 ) { 00489 return; 00490 } 00491 00492 // Build a list of users to notify 00493 $watchers = array(); 00494 if ( $wgEnotifWatchlist || $wgShowUpdatedMarker ) { 00495 $dbw = wfGetDB( DB_MASTER ); 00496 $res = $dbw->select( array( 'watchlist' ), 00497 array( 'wl_user' ), 00498 array( 00499 'wl_user != ' . intval( $editor->getID() ), 00500 'wl_namespace' => $title->getNamespace(), 00501 'wl_title' => $title->getDBkey(), 00502 'wl_notificationtimestamp IS NULL', 00503 ), __METHOD__ 00504 ); 00505 foreach ( $res as $row ) { 00506 $watchers[] = intval( $row->wl_user ); 00507 } 00508 if ( $watchers ) { 00509 // Update wl_notificationtimestamp for all watching users except the editor 00510 $fname = __METHOD__; 00511 $dbw->onTransactionIdle( 00512 function() use ( $dbw, $timestamp, $watchers, $title, $fname ) { 00513 $dbw->begin( $fname ); 00514 $dbw->update( 'watchlist', 00515 array( /* SET */ 00516 'wl_notificationtimestamp' => $dbw->timestamp( $timestamp ) 00517 ), array( /* WHERE */ 00518 'wl_user' => $watchers, 00519 'wl_namespace' => $title->getNamespace(), 00520 'wl_title' => $title->getDBkey(), 00521 ), $fname 00522 ); 00523 $dbw->commit( $fname ); 00524 } 00525 ); 00526 } 00527 } 00528 00529 $sendEmail = true; 00530 // If nobody is watching the page, and there are no users notified on all changes 00531 // don't bother creating a job/trying to send emails 00532 // $watchers deals with $wgEnotifWatchlist 00533 if ( !count( $watchers ) && !count( $wgUsersNotifiedOnAllChanges ) ) { 00534 $sendEmail = false; 00535 // Only send notification for non minor edits, unless $wgEnotifMinorEdits 00536 if ( !$minorEdit || ( $wgEnotifMinorEdits && !$editor->isAllowed( 'nominornewtalk' ) ) ) { 00537 $isUserTalkPage = ( $title->getNamespace() == NS_USER_TALK ); 00538 if ( $wgEnotifUserTalk && $isUserTalkPage && $this->canSendUserTalkEmail( $editor, $title, $minorEdit ) ) { 00539 $sendEmail = true; 00540 } 00541 } 00542 } 00543 00544 if ( !$sendEmail ) { 00545 return; 00546 } 00547 if ( $wgEnotifUseJobQ ) { 00548 $params = array( 00549 'editor' => $editor->getName(), 00550 'editorID' => $editor->getID(), 00551 'timestamp' => $timestamp, 00552 'summary' => $summary, 00553 'minorEdit' => $minorEdit, 00554 'oldid' => $oldid, 00555 'watchers' => $watchers, 00556 'pageStatus' => $pageStatus 00557 ); 00558 $job = new EnotifNotifyJob( $title, $params ); 00559 JobQueueGroup::singleton()->push( $job ); 00560 } else { 00561 $this->actuallyNotifyOnPageChange( $editor, $title, $timestamp, $summary, $minorEdit, $oldid, $watchers, $pageStatus ); 00562 } 00563 } 00564 00581 public function actuallyNotifyOnPageChange( $editor, $title, $timestamp, $summary, $minorEdit, 00582 $oldid, $watchers, $pageStatus = 'changed' ) { 00583 # we use $wgPasswordSender as sender's address 00584 global $wgEnotifWatchlist; 00585 global $wgEnotifMinorEdits, $wgEnotifUserTalk; 00586 00587 wfProfileIn( __METHOD__ ); 00588 00589 # The following code is only run, if several conditions are met: 00590 # 1. EmailNotification for pages (other than user_talk pages) must be enabled 00591 # 2. minor edits (changes) are only regarded if the global flag indicates so 00592 00593 $isUserTalkPage = ( $title->getNamespace() == NS_USER_TALK ); 00594 00595 $this->title = $title; 00596 $this->timestamp = $timestamp; 00597 $this->summary = $summary; 00598 $this->minorEdit = $minorEdit; 00599 $this->oldid = $oldid; 00600 $this->editor = $editor; 00601 $this->composed_common = false; 00602 $this->pageStatus = $pageStatus; 00603 00604 $formattedPageStatus = array( 'deleted', 'created', 'moved', 'restored', 'changed' ); 00605 00606 wfRunHooks( 'UpdateUserMailerFormattedPageStatus', array( &$formattedPageStatus ) ); 00607 if ( !in_array( $this->pageStatus, $formattedPageStatus ) ) { 00608 throw new MWException( 'Not a valid page status!' ); 00609 } 00610 00611 $userTalkId = false; 00612 00613 if ( !$minorEdit || ( $wgEnotifMinorEdits && !$editor->isAllowed( 'nominornewtalk' ) ) ) { 00614 00615 if ( $wgEnotifUserTalk && $isUserTalkPage && $this->canSendUserTalkEmail( $editor, $title, $minorEdit ) ) { 00616 $targetUser = User::newFromName( $title->getText() ); 00617 $this->compose( $targetUser ); 00618 $userTalkId = $targetUser->getId(); 00619 } 00620 00621 if ( $wgEnotifWatchlist ) { 00622 // Send updates to watchers other than the current editor 00623 $userArray = UserArray::newFromIDs( $watchers ); 00624 foreach ( $userArray as $watchingUser ) { 00625 if ( $watchingUser->getOption( 'enotifwatchlistpages' ) && 00626 ( !$minorEdit || $watchingUser->getOption( 'enotifminoredits' ) ) && 00627 $watchingUser->isEmailConfirmed() && 00628 $watchingUser->getID() != $userTalkId ) 00629 { 00630 $this->compose( $watchingUser ); 00631 } 00632 } 00633 } 00634 } 00635 00636 global $wgUsersNotifiedOnAllChanges; 00637 foreach ( $wgUsersNotifiedOnAllChanges as $name ) { 00638 if ( $editor->getName() == $name ) { 00639 // No point notifying the user that actually made the change! 00640 continue; 00641 } 00642 $user = User::newFromName( $name ); 00643 $this->compose( $user ); 00644 } 00645 00646 $this->sendMails(); 00647 wfProfileOut( __METHOD__ ); 00648 } 00649 00656 private function canSendUserTalkEmail( $editor, $title, $minorEdit ) { 00657 global $wgEnotifUserTalk; 00658 $isUserTalkPage = ( $title->getNamespace() == NS_USER_TALK ); 00659 00660 if ( $wgEnotifUserTalk && $isUserTalkPage ) { 00661 $targetUser = User::newFromName( $title->getText() ); 00662 00663 if ( !$targetUser || $targetUser->isAnon() ) { 00664 wfDebug( __METHOD__ . ": user talk page edited, but user does not exist\n" ); 00665 } elseif ( $targetUser->getId() == $editor->getId() ) { 00666 wfDebug( __METHOD__ . ": user edited their own talk page, no notification sent\n" ); 00667 } elseif ( $targetUser->getOption( 'enotifusertalkpages' ) && 00668 ( !$minorEdit || $targetUser->getOption( 'enotifminoredits' ) ) ) 00669 { 00670 if ( $targetUser->isEmailConfirmed() ) { 00671 wfDebug( __METHOD__ . ": sending talk page update notification\n" ); 00672 return true; 00673 } else { 00674 wfDebug( __METHOD__ . ": talk page owner doesn't have validated email\n" ); 00675 } 00676 } else { 00677 wfDebug( __METHOD__ . ": talk page owner doesn't want notifications\n" ); 00678 } 00679 } 00680 return false; 00681 } 00682 00686 private function composeCommonMailtext() { 00687 global $wgPasswordSender, $wgPasswordSenderName, $wgNoReplyAddress; 00688 global $wgEnotifFromEditor, $wgEnotifRevealEditorAddress; 00689 global $wgEnotifImpersonal, $wgEnotifUseRealName; 00690 00691 $this->composed_common = true; 00692 00693 # You as the WikiAdmin and Sysops can make use of plenty of 00694 # named variables when composing your notification emails while 00695 # simply editing the Meta pages 00696 00697 $keys = array(); 00698 $postTransformKeys = array(); 00699 $pageTitleUrl = $this->title->getCanonicalUrl(); 00700 $pageTitle = $this->title->getPrefixedText(); 00701 00702 if ( $this->oldid ) { 00703 // Always show a link to the diff which triggered the mail. See bug 32210. 00704 $keys['$NEWPAGE'] = "\n\n" . wfMessage( 'enotif_lastdiff', 00705 $this->title->getCanonicalUrl( 'diff=next&oldid=' . $this->oldid ) ) 00706 ->inContentLanguage()->text(); 00707 00708 if ( !$wgEnotifImpersonal ) { 00709 // For personal mail, also show a link to the diff of all changes 00710 // since last visited. 00711 $keys['$NEWPAGE'] .= "\n\n" . wfMessage( 'enotif_lastvisited', 00712 $this->title->getCanonicalUrl( 'diff=0&oldid=' . $this->oldid ) ) 00713 ->inContentLanguage()->text(); 00714 } 00715 $keys['$OLDID'] = $this->oldid; 00716 // @deprecated Remove in MediaWiki 1.23. 00717 $keys['$CHANGEDORCREATED'] = wfMessage( 'changed' )->inContentLanguage()->text(); 00718 } else { 00719 # clear $OLDID placeholder in the message template 00720 $keys['$OLDID'] = ''; 00721 $keys['$NEWPAGE'] = ''; 00722 // @deprecated Remove in MediaWiki 1.23. 00723 $keys['$CHANGEDORCREATED'] = wfMessage( 'created' )->inContentLanguage()->text(); 00724 } 00725 00726 $keys['$PAGETITLE'] = $this->title->getPrefixedText(); 00727 $keys['$PAGETITLE_URL'] = $this->title->getCanonicalUrl(); 00728 $keys['$PAGEMINOREDIT'] = $this->minorEdit ? 00729 wfMessage( 'minoredit' )->inContentLanguage()->text() : ''; 00730 $keys['$UNWATCHURL'] = $this->title->getCanonicalUrl( 'action=unwatch' ); 00731 00732 if ( $this->editor->isAnon() ) { 00733 # real anon (user:xxx.xxx.xxx.xxx) 00734 $keys['$PAGEEDITOR'] = wfMessage( 'enotif_anon_editor', $this->editor->getName() ) 00735 ->inContentLanguage()->text(); 00736 $keys['$PAGEEDITOR_EMAIL'] = wfMessage( 'noemailtitle' )->inContentLanguage()->text(); 00737 00738 } else { 00739 $keys['$PAGEEDITOR'] = $wgEnotifUseRealName ? $this->editor->getRealName() : $this->editor->getName(); 00740 $emailPage = SpecialPage::getSafeTitleFor( 'Emailuser', $this->editor->getName() ); 00741 $keys['$PAGEEDITOR_EMAIL'] = $emailPage->getCanonicalUrl(); 00742 } 00743 00744 $keys['$PAGEEDITOR_WIKI'] = $this->editor->getUserPage()->getCanonicalUrl(); 00745 00746 # Replace this after transforming the message, bug 35019 00747 $postTransformKeys['$PAGESUMMARY'] = $this->summary == '' ? ' - ' : $this->summary; 00748 00749 # Now build message's subject and body 00750 $this->subject = wfMessage( 'enotif_subject_' . $this->pageStatus )->inContentLanguage() 00751 ->params( $pageTitle, $keys['$PAGEEDITOR'] )->text(); 00752 00753 $keys['$PAGEINTRO'] = wfMessage( 'enotif_body_intro_' . $this->pageStatus ) 00754 ->inContentLanguage()->params( $pageTitle, $keys['$PAGEEDITOR'], $pageTitleUrl ) 00755 ->text(); 00756 00757 $body = wfMessage( 'enotif_body' )->inContentLanguage()->plain(); 00758 $body = strtr( $body, $keys ); 00759 $body = MessageCache::singleton()->transform( $body, false, null, $this->title ); 00760 $this->body = wordwrap( strtr( $body, $postTransformKeys ), 72 ); 00761 00762 # Reveal the page editor's address as REPLY-TO address only if 00763 # the user has not opted-out and the option is enabled at the 00764 # global configuration level. 00765 $adminAddress = new MailAddress( $wgPasswordSender, $wgPasswordSenderName ); 00766 if ( $wgEnotifRevealEditorAddress 00767 && ( $this->editor->getEmail() != '' ) 00768 && $this->editor->getOption( 'enotifrevealaddr' ) ) 00769 { 00770 $editorAddress = new MailAddress( $this->editor ); 00771 if ( $wgEnotifFromEditor ) { 00772 $this->from = $editorAddress; 00773 } else { 00774 $this->from = $adminAddress; 00775 $this->replyto = $editorAddress; 00776 } 00777 } else { 00778 $this->from = $adminAddress; 00779 $this->replyto = new MailAddress( $wgNoReplyAddress ); 00780 } 00781 } 00782 00790 function compose( $user ) { 00791 global $wgEnotifImpersonal; 00792 00793 if ( !$this->composed_common ) 00794 $this->composeCommonMailtext(); 00795 00796 if ( $wgEnotifImpersonal ) { 00797 $this->mailTargets[] = new MailAddress( $user ); 00798 } else { 00799 $this->sendPersonalised( $user ); 00800 } 00801 } 00802 00806 function sendMails() { 00807 global $wgEnotifImpersonal; 00808 if ( $wgEnotifImpersonal ) { 00809 $this->sendImpersonal( $this->mailTargets ); 00810 } 00811 } 00812 00822 function sendPersonalised( $watchingUser ) { 00823 global $wgContLang, $wgEnotifUseRealName; 00824 // From the PHP manual: 00825 // Note: The to parameter cannot be an address in the form of "Something <[email protected]>". 00826 // The mail command will not parse this properly while talking with the MTA. 00827 $to = new MailAddress( $watchingUser ); 00828 00829 # $PAGEEDITDATE is the time and date of the page change 00830 # expressed in terms of individual local time of the notification 00831 # recipient, i.e. watching user 00832 $body = str_replace( 00833 array( '$WATCHINGUSERNAME', 00834 '$PAGEEDITDATE', 00835 '$PAGEEDITTIME' ), 00836 array( $wgEnotifUseRealName ? $watchingUser->getRealName() : $watchingUser->getName(), 00837 $wgContLang->userDate( $this->timestamp, $watchingUser ), 00838 $wgContLang->userTime( $this->timestamp, $watchingUser ) ), 00839 $this->body ); 00840 00841 return UserMailer::send( $to, $this->from, $this->subject, $body, $this->replyto ); 00842 } 00843 00850 function sendImpersonal( $addresses ) { 00851 global $wgContLang; 00852 00853 if ( empty( $addresses ) ) { 00854 return null; 00855 } 00856 00857 $body = str_replace( 00858 array( '$WATCHINGUSERNAME', 00859 '$PAGEEDITDATE', 00860 '$PAGEEDITTIME' ), 00861 array( wfMessage( 'enotif_impersonal_salutation' )->inContentLanguage()->text(), 00862 $wgContLang->date( $this->timestamp, false, false ), 00863 $wgContLang->time( $this->timestamp, false, false ) ), 00864 $this->body ); 00865 00866 return UserMailer::send( $addresses, $this->from, $this->subject, $body, $this->replyto ); 00867 } 00868 00869 } # end of class EmailNotification