public function testBadMailAddresses() { $address1 = MailAddress::create()->setAddress("vasya@example.com"); $address2 = MailAddress::create()->setAddress("va sya@example.com"); try { $address1->toString(); $address2->toString(); $this->fail(); } catch (WrongArgumentException $e) { //pass } }
/** * Send an e-mail to this user's account. Does not check for * confirmed status or validity. * * @param string $subject Message subject * @param string $body Message body * @param User|null $from Optional sending user; if unspecified, default * $wgPasswordSender will be used. * @param string $replyto Reply-To address * @return Status */ public function sendMail($subject, $body, $from = null, $replyto = null) { global $wgPasswordSender; if ($from instanceof User) { $sender = MailAddress::newFromUser($from); } else { $sender = new MailAddress($wgPasswordSender, wfMessage('emailsender')->inContentLanguage()->text()); } $to = MailAddress::newFromUser($this); return UserMailer::send($to, $sender, $subject, $body, array('replyTo' => $replyto)); }
/** * Really send a mail. Permissions should have been checked using * getPermissionsError(). It is probably also a good * idea to check the edit token and ping limiter in advance. * * @param array $data * @param IContextSource $context * @return Status|string|bool Status object, or potentially a String on error * or maybe even true on success if anything uses the EmailUser hook. */ public static function submit(array $data, IContextSource $context) { $config = $context->getConfig(); $target = self::getTarget($data['Target']); if (!$target instanceof User) { // Messages used here: notargettext, noemailtext, nowikiemailtext return $context->msg($target . 'text')->parseAsBlock(); } $to = MailAddress::newFromUser($target); $from = MailAddress::newFromUser($context->getUser()); $subject = $data['Subject']; $text = $data['Text']; // Add a standard footer and trim up trailing newlines $text = rtrim($text) . "\n\n-- \n"; $text .= $context->msg('emailuserfooter', $from->name, $to->name)->inContentLanguage()->text(); $error = ''; if (!Hooks::run('EmailUser', array(&$to, &$from, &$subject, &$text, &$error))) { return $error; } if ($config->get('UserEmailUseReplyTo')) { /** * Put the generic wiki autogenerated address in the From: * header and reserve the user for Reply-To. * * This is a bit ugly, but will serve to differentiate * wiki-borne mails from direct mails and protects against * SPF and bounce problems with some mailers (see below). */ $mailFrom = new MailAddress($config->get('PasswordSender'), wfMessage('emailsender')->inContentLanguage()->text()); $replyTo = $from; } else { /** * Put the sending user's e-mail address in the From: header. * * This is clean-looking and convenient, but has issues. * One is that it doesn't as clearly differentiate the wiki mail * from "directly" sent mails. * * Another is that some mailers (like sSMTP) will use the From * address as the envelope sender as well. For open sites this * can cause mails to be flunked for SPF violations (since the * wiki server isn't an authorized sender for various users' * domains) as well as creating a privacy issue as bounces * containing the recipient's e-mail address may get sent to * the sending user. */ $mailFrom = $from; $replyTo = null; } $status = UserMailer::send($to, $mailFrom, $subject, $text, array('replyTo' => $replyTo)); if (!$status->isGood()) { return $status; } else { // if the user requested a copy of this mail, do this now, // unless they are emailing themselves, in which case one // copy of the message is sufficient. if ($data['CCMe'] && $to != $from) { $cc_subject = $context->msg('emailccsubject')->rawParams($target->getName(), $subject)->text(); // target and sender are equal, because this is the CC for the sender Hooks::run('EmailUserCC', array(&$from, &$from, &$cc_subject, &$text)); $ccStatus = UserMailer::send($from, $from, $cc_subject, $text); $status->merge($ccStatus); } Hooks::run('EmailUserComplete', array($to, $from, $subject, $text)); return $status; } }
/** * Does the per-user customizations to a notification e-mail (name, * timestamp in proper timezone, etc) and sends it out. * Returns true if the mail was sent successfully. * * @param User $watchingUser * @return bool * @private */ function sendPersonalised($watchingUser) { global $wgContLang, $wgEnotifUseRealName; // 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 = MailAddress::newFromUser($watchingUser); # $PAGEEDITDATE is the time and date of the page change # expressed in terms of individual local time of the notification # recipient, i.e. watching user $body = str_replace(array('$WATCHINGUSERNAME', '$PAGEEDITDATE', '$PAGEEDITTIME'), array($wgEnotifUseRealName && $watchingUser->getRealName() !== '' ? $watchingUser->getRealName() : $watchingUser->getName(), $wgContLang->userDate($this->timestamp, $watchingUser), $wgContLang->userTime($this->timestamp, $watchingUser)), $this->body); return UserMailer::send($to, $this->from, $this->subject, $body, $this->replyto); }
function execute($para) { global $wgRequest, $wgOut, $wgUser, $wgWhiteListOverride, $wgWhiteListManagerGroup, $wgWhiteListRestrictedGroup, $wgSitename; $dbr = wfGetDB(DB_SLAVE); if (!isset($para) || $para == '') { $user = $wgUser; } else { $user = WhiteListUserFromId($user); } $this->setHeaders(); $wgOut->setPagetitle(wfMsg('whitelist')); if (!in_array($wgWhiteListRestrictedGroup, $user->getGroups())) { if (!($userName = $user->getRealName())) { $userName = $user->getName(); } $wgOut->addWikiText(wfMsg('whitelistnonrestricted', $userName)); return true; } if ($wgRequest->getVal('submit', '') == wfMsg('whitelistnewtableprocess')) { $sender = new MailAddress($wgUser->getEmail(), $wgUser->getRealName()); $to = ''; if (constant("MW_USER_VERSION") < 4) { $to = new User(); $to->mId = $wgRequest->getint('manager', 0); } else { $to = WhiteListUserFromId($wgRequest->getint('manager', 0)); } // FIXME: I think this mail will be sent in the wrong language. $requestedPages = $wgRequest->getVal('newPages'); $requestedPagesCount = count($requestedPages); $to->sendMail("[{$wgSitename}] " . wfMsg('whitelistrequest'), wfMsgExt('whitelistrequestmsg', array('parsemag'), $wgUser->getRealName(), $requestedPages, $requestedPagesCount), $sender->toString(), null, 'WhiteList'); $wgOut->addWikiText(wfMsg('whitelistrequestconf', $to->getRealName())); $wgOut->addWikiText(""); } $wgOut->addHTML("<table cellspacing=0 cellpadding=2 border=1 width=100%><tr>"); $wgOut->addHTML("<th>" . wfMsg('whitelistpagelist', $user->getRealName()) . "</th><th>" . wfMsg('whitelistrequest') . "</th>"); $wgOut->addHTML("</tr><tr><td width=30%>"); $res = WhiteListEdit::contractorWhiteListTable($dbr, $user->getId()); for ($row = $dbr->fetchObject($res); $row; $row = $dbr->fetchObject($res)) { WhiteListEdit::DisplayWildCardMatches($row->wl_page_title, $row->wl_page_title, 0); } $dbr->freeResult($res); $pages = array(); foreach ($wgWhiteListOverride['always']['read'] as $page) { array_push($pages, $page); } foreach ($wgWhiteListOverride['always']['edit'] as $page) { array_push($pages, $page); } sort($pages); foreach ($pages as $page) { WhiteListEdit::DisplayWildCardMatches($page, $page, 0); } $wgOut->addHTML("</td><td valign=top>"); $wgOut->addHTML("<table cellspacing=0 cellpadding=2 border=0 width=100%><tr><td align='right'>{$wgWhiteListManagerGroup}:</td><td>"); $wgOut->addHTML("<form method=\"post\">"); $wgOut->addHTML('<select name="manager">'); $users = array(); $dbr->begin(); $res = $dbr->select('user_groups', 'ug_user', array('ug_group' => $wgWhiteListManagerGroup), __METHOD__); $dbr->commit(); for ($row = $dbr->fetchObject($res); $row; $row = $dbr->fetchObject($res)) { $u = WhiteListUserFromID($row->ug_user); $users[$u->getRealName()] = $row->ug_user; } $dbr->freeResult($res); ksort($users); foreach ($users as $name => $id) { $wgOut->addHTML("<option value=\"{$id}\">" . $name . "</option>"); } $wgOut->addHTML('</select> '); $wgOut->addHTML("</td></tr><tr><td align='right'>" . wfMsg('mywhitelistpages') . ":</td><td>"); $wgOut->addHTML("<textarea name='newPages' cols=40 rows=5></textarea>"); $wgOut->addHTML("</td></tr><tr><td colspan=2><center>"); $wgOut->addHTML("<input type='submit' name='submit' value='" . wfMsg('whitelistnewtableprocess') . "' />"); $wgOut->addHTML("</form>"); $wgOut->addHTML("</center></td></tr></table>"); $wgOut->addHTML("</td></tr></table>"); $wgOut->addHTML("</td></tr></table>"); }
/** * Helper function fo UserMailer::send() which does the actual sending. It expects a $to * list which the UserMailerSplitTo hook would not split further. * @param MailAddress[] $to Array of recipients' email addresses * @param MailAddress $from Sender's email * @param string $subject Email's subject. * @param string $body Email's text or Array of two strings to be the text and html bodies * @param array $options: * 'replyTo' MailAddress * 'contentType' string default 'text/plain; charset=UTF-8' * 'headers' array Extra headers to set * * @throws MWException * @throws Exception * @return Status */ protected static function sendInternal(array $to, MailAddress $from, $subject, $body, $options = array()) { global $wgSMTP, $wgEnotifMaxRecips, $wgAdditionalMailParams; $mime = null; $replyto = isset($options['replyTo']) ? $options['replyTo'] : null; $contentType = isset($options['contentType']) ? $options['contentType'] : 'text/plain; charset=UTF-8'; $headers = isset($options['headers']) ? $options['headers'] : array(); // Allow transformation of content, such as encrypting/signing $error = false; if (!Hooks::run('UserMailerTransformContent', array($to, $from, &$body, &$error))) { if ($error) { return Status::newFatal('php-mail-error', $error); } else { return Status::newFatal('php-mail-error-unknown'); } } /** * Forge email headers * ------------------- * * WARNING * * DO NOT add To: or Subject: headers at this step. They need to be * handled differently depending upon the mailer we are going to use. * * To: * PHP mail() first argument is the mail receiver. The argument is * used as a recipient destination and as a To header. * * PEAR mailer has a recipient argument which is only used to * send the mail. If no To header is given, PEAR will set it to * to 'undisclosed-recipients:'. * * NOTE: To: is for presentation, the actual recipient is specified * by the mailer using the Rcpt-To: header. * * Subject: * PHP mail() second argument to pass the subject, passing a Subject * as an additional header will result in a duplicate header. * * PEAR mailer should be passed a Subject header. * * -- hashar 20120218 */ $headers['From'] = $from->toString(); $returnPath = $from->address; $extraParams = $wgAdditionalMailParams; // Hook to generate custom VERP address for 'Return-Path' Hooks::run('UserMailerChangeReturnPath', array($to, &$returnPath)); // Add the envelope sender address using the -f command line option when PHP mail() is used. // Will default to the $from->address when the UserMailerChangeReturnPath hook fails and the // generated VERP address when the hook runs effectively. $extraParams .= ' -f ' . $returnPath; $headers['Return-Path'] = $returnPath; if ($replyto) { $headers['Reply-To'] = $replyto->toString(); } $headers['Date'] = MWTimestamp::getLocalInstance()->format('r'); $headers['Message-ID'] = self::makeMsgId(); $headers['X-Mailer'] = 'MediaWiki mailer'; $headers['List-Unsubscribe'] = '<' . SpecialPage::getTitleFor('Preferences')->getFullURL('', false, PROTO_CANONICAL) . '>'; // Line endings need to be different on Unix and Windows due to // the bug described at http://trac.wordpress.org/ticket/2603 if (wfIsWindows()) { $endl = "\r\n"; } else { $endl = "\n"; } if (is_array($body)) { // we are sending a multipart message wfDebug("Assembling multipart mime email\n"); if (!stream_resolve_include_path('Mail/mime.php')) { wfDebug("PEAR Mail_Mime package is not installed. Falling back to text email.\n"); // remove the html body for text email fall back $body = $body['text']; } else { // Check if pear/mail_mime is already loaded (via composer) if (!class_exists('Mail_mime')) { require_once 'Mail/mime.php'; } if (wfIsWindows()) { $body['text'] = str_replace("\n", "\r\n", $body['text']); $body['html'] = str_replace("\n", "\r\n", $body['html']); } $mime = new Mail_mime(array('eol' => $endl, 'text_charset' => 'UTF-8', 'html_charset' => 'UTF-8')); $mime->setTXTBody($body['text']); $mime->setHTMLBody($body['html']); $body = $mime->get(); // must call get() before headers() $headers = $mime->headers($headers); } } if ($mime === null) { // sending text only, either deliberately or as a fallback if (wfIsWindows()) { $body = str_replace("\n", "\r\n", $body); } $headers['MIME-Version'] = '1.0'; $headers['Content-type'] = is_null($contentType) ? 'text/plain; charset=UTF-8' : $contentType; $headers['Content-transfer-encoding'] = '8bit'; } // allow transformation of MIME-encoded message if (!Hooks::run('UserMailerTransformMessage', array($to, $from, &$subject, &$headers, &$body, &$error))) { if ($error) { return Status::newFatal('php-mail-error', $error); } else { return Status::newFatal('php-mail-error-unknown'); } } $ret = Hooks::run('AlternateUserMailer', array($headers, $to, $from, $subject, $body)); if ($ret === false) { // the hook implementation will return false to skip regular mail sending return Status::newGood(); } elseif ($ret !== true) { // the hook implementation will return a string to pass an error message return Status::newFatal('php-mail-error', $ret); } if (is_array($wgSMTP)) { // Check if pear/mail is already loaded (via composer) if (!class_exists('Mail')) { // PEAR MAILER if (!stream_resolve_include_path('Mail.php')) { throw new MWException('PEAR mail package is not installed'); } require_once 'Mail.php'; } MediaWiki\suppressWarnings(); // Create the mail object using the Mail::factory method $mail_object =& Mail::factory('smtp', $wgSMTP); if (PEAR::isError($mail_object)) { wfDebug("PEAR::Mail factory failed: " . $mail_object->getMessage() . "\n"); MediaWiki\restoreWarnings(); return Status::newFatal('pear-mail-error', $mail_object->getMessage()); } wfDebug("Sending mail via PEAR::Mail\n"); $headers['Subject'] = self::quotedPrintable($subject); // When sending only to one recipient, shows it its email using To: if (count($to) == 1) { $headers['To'] = $to[0]->toString(); } // Split jobs since SMTP servers tends to limit the maximum // number of possible recipients. $chunks = array_chunk($to, $wgEnotifMaxRecips); foreach ($chunks as $chunk) { $status = self::sendWithPear($mail_object, $chunk, $headers, $body); // FIXME : some chunks might be sent while others are not! if (!$status->isOK()) { MediaWiki\restoreWarnings(); return $status; } } MediaWiki\restoreWarnings(); return Status::newGood(); } else { // PHP mail() if (count($to) > 1) { $headers['To'] = 'undisclosed-recipients:;'; } $headers = self::arrayToHeaderString($headers, $endl); wfDebug("Sending mail via internal mail() function\n"); self::$mErrorString = ''; $html_errors = ini_get('html_errors'); ini_set('html_errors', '0'); set_error_handler('UserMailer::errorHandler'); try { $safeMode = wfIniGetBool('safe_mode'); foreach ($to as $recip) { if ($safeMode) { $sent = mail($recip, self::quotedPrintable($subject), $body, $headers); } else { $sent = mail($recip, self::quotedPrintable($subject), $body, $headers, $extraParams); } } } catch (Exception $e) { restore_error_handler(); throw $e; } restore_error_handler(); ini_set('html_errors', $html_errors); if (self::$mErrorString) { wfDebug("Error sending mail: " . self::$mErrorString . "\n"); return Status::newFatal('php-mail-error', self::$mErrorString); } elseif (!$sent) { // mail function only tells if there's an error wfDebug("Unknown error sending mail\n"); return Status::newFatal('php-mail-error-unknown'); } else { return Status::newGood(); } } }
/** * Does the per-user customizations to a notification e-mail (name, * timestamp in proper timezone, etc) and sends it out. * Returns true if the mail was sent successfully. * * @param User $watchingUser * @param string $source * @return bool * @private */ function sendPersonalised($watchingUser, $source) { global $wgContLang, $wgEnotifUseRealName; // 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 = MailAddress::newFromUser($watchingUser); # $PAGEEDITDATE is the time and date of the page change # expressed in terms of individual local time of the notification # recipient, i.e. watching user $body = str_replace(array('$WATCHINGUSERNAME', '$PAGEEDITDATE', '$PAGEEDITTIME'), array($wgEnotifUseRealName && $watchingUser->getRealName() !== '' ? $watchingUser->getRealName() : $watchingUser->getName(), $wgContLang->userDate($this->timestamp, $watchingUser), $wgContLang->userTime($this->timestamp, $watchingUser)), $this->body); $headers = array(); if ($source === self::WATCHLIST) { $headers['List-Help'] = 'https://www.mediawiki.org/wiki/Special:MyLanguage/Help:Watchlist'; } return UserMailer::send($to, $this->from, $this->subject, $body, array('replyTo' => $this->replyto, 'headers' => $headers)); }
function doSubmit() { global $wgOut, $wgContactSender, $wgContactSenderName; #TODO: check captcha $fname = 'EmailContactForm::doSubmit'; wfDebug("{$fname}: start\n"); $to = new MailAddress($this->target); $from = new MailAddress($wgContactSender, $wgContactSenderName); $replyto = $this->fromaddress ? new MailAddress($this->fromaddress, $this->fromname) : NULL; $subject = trim($this->subject); if ($subject === "") { $subject = wfMsgForContent("contactpage-defsubject"); } if ($this->fromname !== "") { $subject = wfMsgForContent("contactpage-subject-and-sender", $subject, $this->fromname); } if (wfRunHooks('ContactForm', array(&$to, &$replyto, &$subject, &$this->text))) { wfDebug("{$fname}: sending mail from " . $from->toString() . " to " . $to->toString() . " replyto " . ($replyto == null ? '-/-' : $replyto->toString()) . "\n"); #HACK: in MW 1.9, replyto must be a string, in MW 1.0, it must be an object! $ver = preg_replace('![^\\d._+]!', '', $GLOBALS['wgVersion']); $replyaddr = $replyto == null ? NULL : version_compare($ver, '1.10', '<') ? $replyto->toString() : $replyto; $mailResult = userMailer($to, $from, $subject, $this->text, $replyaddr); if (WikiError::isError($mailResult)) { $wgOut->addHTML(wfMsg("usermailererror") . $mailResult); } else { // if the user requested a copy of this mail, do this now, // unless they are emailing themselves, in which case one copy of the message is sufficient. if ($this->cc_me && $replyto) { $cc_subject = wfMsg('emailccsubject', $this->target->getName(), $subject); if (wfRunHooks('ContactForm', array(&$from, &$replyto, &$cc_subject, &$this->text))) { wfDebug("{$fname}: sending cc mail from " . $from->toString() . " to " . $replyto->toString() . "\n"); $ccResult = userMailer($replyto, $from, $cc_subject, $this->text); if (WikiError::isError($ccResult)) { // At this stage, the user's CC mail has failed, but their // original mail has succeeded. It's unlikely, but still, what to do? // We can either show them an error, or we can say everything was fine, // or we can say we sort of failed AND sort of succeeded. Of these options, // simply saying there was an error is probably best. $wgOut->addHTML(wfMsg("usermailererror") . $ccResult); return; } } } wfDebug("{$fname}: success\n"); $titleObj = SpecialPage::getTitleFor("Contact"); $wgOut->redirect($titleObj->getFullURL("action=success")); wfRunHooks('ContactFromComplete', array($to, $replyto, $subject, $this->text)); } } wfDebug("{$fname}: end\n"); }
/** * 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 MailAddress $to : recipient's email (or an array of them) * @param MailAddress $from : sender's email * @param String $subject : email's subject. * @param String $body : email's text. * $body can be array with text and html version of email message, and also can contain attachements * $body = array('text' => 'Email text', 'html' => '<b>Email text</b>') * @param MailAddress $replyTo : optional reply-to email (default: null). * @param String $contentType : optional custom Content-Type * @param String $category : optional category for statistic * @param int $priority : optional priority for email * @param Array $attachments : optional list of files to send as attachments * * @return Status object * @throws MWException */ public static function send(MailAddress $to, MailAddress $from, $subject, $body, MailAddress $replyTo = null, $contentType = null, $category = 'UserMailer', $priority = 0, $attachments = []) { if (!is_array($to)) { $to = [$to]; } # Make sure we have at least one address $has_address = false; foreach ($to as $u) { if ($u->address) { $has_address = true; break; } } if (!$has_address) { return Status::newFatal('user-mail-no-addy'); } wfRunHooks('UserMailerSend', [&$to]); # Forge email headers # ------------------- # # WARNING # # DO NOT add To: or Subject: headers at this step. They need to be # handled differently depending upon the mailer we are going to use. # # To: # PHP mail() first argument is the mail receiver. The argument is # used as a recipient destination and as a To header. # # PEAR mailer has a recipient argument which is only used to # send the mail. If no To header is given, PEAR will set it to # to 'undisclosed-recipients:'. # # NOTE: To: is for presentation, the actual recipient is specified # by the mailer using the Rcpt-To: header. # # Subject: # PHP mail() second argument to pass the subject, passing a Subject # as an additional header will result in a duplicate header. # # PEAR mailer should be passed a Subject header. # # -- hashar 20120218 $headers['From'] = $from->toString(); $headers['Return-Path'] = $from->address; if ($replyTo && $replyTo instanceof MailAddress) { $headers['Reply-To'] = $replyTo->toString(); } $headers['Date'] = date('r'); $headers['MIME-Version'] = '1.0'; if (empty($attachments)) { $headers['Content-Type'] = is_null($contentType) ? 'text/plain; charset=UTF-8' : $contentType; $headers['Content-Transfer-Encoding'] = '8bit'; } $headers['Message-ID'] = self::makeMsgId(); $headers['X-Mailer'] = 'MediaWiki mailer'; $headers['X-Msg-Category'] = $category; if ($priority) { $headers['X-Priority'] = $priority; } $ret = wfRunHooks('AlternateUserMailer', [$headers, $to, $from, $subject, $body, $priority, $attachments]); if ($ret === false) { return Status::newGood(); } elseif ($ret !== true) { return Status::newFatal('php-mail-error', $ret); } # MoLi: body can be an array with text and html message # MW core uses only text version of email message, so $body as array should be used only with AlternateUserMailer hook if (is_array($body) && isset($body['text'])) { $body = $body['text']; } if (is_array(F::app()->wg->SMTP)) { # # PEAR MAILER # if (function_exists('stream_resolve_include_path')) { $found = stream_resolve_include_path('Mail.php'); } else { $found = Fallback::stream_resolve_include_path('Mail.php'); } if (!$found) { throw new MWException('PEAR mail package is not installed'); } require_once 'Mail.php'; wfSuppressWarnings(); // Create the mail object using the Mail::factory method $mail_object =& Mail::factory('smtp', F::app()->wg->SMTP); if (PEAR::isError($mail_object)) { wfDebug("PEAR::Mail factory failed: " . $mail_object->getMessage() . "\n"); wfRestoreWarnings(); return Status::newFatal('pear-mail-error', $mail_object->getMessage()); } wfDebug("Sending mail via PEAR::Mail\n"); $headers['Subject'] = self::quotedPrintable($subject); # When sending only to one recipient, shows it its email using To: if (count($to) == 1) { $headers['To'] = $to[0]->toString(); } # Split jobs since SMTP servers tends to limit the maximum # number of possible recipients. $chunks = array_chunk($to, F::app()->wg->EnotifMaxRecips); foreach ($chunks as $chunk) { if (!wfRunHooks('ComposeMail', [$chunk, &$body, &$headers])) { continue; } $status = self::sendWithPear($mail_object, $chunk, $headers, $body); # FIXME : some chunks might be sent while others are not! if (!$status->isOK()) { wfRestoreWarnings(); return $status; } } wfRestoreWarnings(); return Status::newGood(); } else { # # PHP mail() # # 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); $endl = "\r\n"; } else { $endl = "\n"; } if (count($to) > 1) { $headers['To'] = 'undisclosed-recipients:;'; } $headers = self::arrayToHeaderString($headers, $endl); wfDebug("Sending mail via internal mail() function\n"); self::$mErrorString = ''; $html_errors = ini_get('html_errors'); ini_set('html_errors', '0'); $safeMode = wfIniGetBool('safe_mode'); foreach ($to as $recip) { if (!wfRunHooks('ComposeMail', array($recip, &$body, &$headers))) { continue; } if ($safeMode) { $sent = mail($recip, self::quotedPrintable($subject), $body, $headers); } else { $sent = mail($recip, self::quotedPrintable($subject), $body, $headers, F::app()->wg->AdditionalMailParams); } } ini_set('html_errors', $html_errors); if (self::$mErrorString) { wfDebug("Error sending mail: " . self::$mErrorString . "\n"); return Status::newFatal('php-mail-error', self::$mErrorString); } elseif (!$sent) { // mail function only tells if there's an error wfDebug("Unknown error sending mail\n"); return Status::newFatal('php-mail-error-unknown'); } else { return Status::newGood(); } } }
function doSubmit() { global $wgOut, $wgUser; global $wgUserEmailUseReplyTo, $wgPasswordSender; global $wgContactSender, $wgContactSenderName, $wgContactIncludeIP; $csender = $wgContactSender ? $wgContactSender : $wgPasswordSender; $cname = $wgContactSenderName; $senderIP = wfGetIP(); wfDebug(__METHOD__ . ": start\n"); $targetAddress = new MailAddress($this->target); $replyto = null; $contactSender = new MailAddress($csender, $cname); if (!$this->fromaddress) { $submitterAddress = $contactSender; } else { $submitterAddress = new MailAddress($this->fromaddress, $this->fromname); if ($wgUserEmailUseReplyTo) { $replyto = $submitterAddress; } } $subject = trim($this->subject); if ($subject === '') { $subject = wfMsgForContent('contactpage-defsubject'); } $includeIP = $wgContactIncludeIP && ($this->includeIP || $wgUser->isAnon()); if ($this->fromname !== '') { if ($includeIP) { $subject = wfMsgForContent('contactpage-subject-and-sender-withip', $subject, $this->fromname, $senderIP); } else { $subject = wfMsgForContent('contactpage-subject-and-sender', $subject, $this->fromname); } } elseif ($this->fromaddress !== '') { if ($includeIP) { $subject = wfMsgForContent('contactpage-subject-and-sender-withip', $subject, $this->fromaddress, $senderIP); } else { $subject = wfMsgForContent('contactpage-subject-and-sender', $subject, $this->fromaddress); } } elseif ($includeIP) { $subject = wfMsgForContent('contactpage-subject-and-sender', $subject, $senderIP); } if (!wfRunHooks('ContactForm', array(&$targetAddress, &$replyto, &$subject, &$this->text, $this->formType))) { wfDebug(__METHOD__ . ": aborted by hook\n"); return; } wfDebug(__METHOD__ . ": sending mail from " . $submitterAddress->toString() . " to " . $targetAddress->toString() . " replyto " . ($replyto == null ? '-/-' : $replyto->toString()) . "\n"); $mailResult = UserMailer::send($targetAddress, $submitterAddress, $subject, $this->text, $replyto); if (WikiError::isError($mailResult)) { $wgOut->addWikiMsg('usermailererror') . $mailResult->getMessage(); wfDebug(__METHOD__ . ": got error from UserMailer: " . $mailResult->getMessage() . "\n"); return; } // if the user requested a copy of this mail, do this now, // unless they are emailing themselves, in which case one copy of the message is sufficient. if ($this->cc_me && $this->fromaddress) { $cc_subject = wfMsg('emailccsubject', $this->target->getName(), $subject); if (wfRunHooks('ContactForm', array(&$submitterAddress, &$contactSender, &$cc_subject, &$this->text, $this->formType))) { wfDebug(__METHOD__ . ": sending cc mail from " . $contactSender->toString() . " to " . $submitterAddress->toString() . "\n"); $ccResult = UserMailer::send($submitterAddress, $contactSender, $cc_subject, $this->text); if (WikiError::isError($ccResult)) { // At this stage, the user's CC mail has failed, but their // original mail has succeeded. It's unlikely, but still, what to do? // We can either show them an error, or we can say everything was fine, // or we can say we sort of failed AND sort of succeeded. Of these options, // simply saying there was an error is probably best. $wgOut->addWikiText(wfMsg('usermailererror') . $ccResult); return; } } } wfDebug(__METHOD__ . ": success\n"); $titleObj = SpecialPage::getTitleFor('Contact'); $wgOut->redirect($titleObj->getFullURL('action=success')); wfRunHooks('ContactFromComplete', array($targetAddress, $replyto, $subject, $this->text)); wfDebug(__METHOD__ . ": end\n"); }
/** * 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 $to MailAddress: recipient's email * @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). */ function userMailer($to, $from, $subject, $body, $replyto = false) { global $wgUser, $wgSMTP, $wgOutputEncoding, $wgErrorString; // WERELATE - if mail from WeRelate system, set to WeRelate donotreply@werelate.org; otherwise set to {name} werelate-user@werelate.org // this is done because Amazon SES requires validating all sender emails, and we don't want to do that for each user // TODO: this needs to be parameterized so other websites can enter their own from addresses if (substr($from->address, -13) === '@werelate.org' && ($from->name === 'WeRelateAdmin' || !$from->name)) { $replyto = ''; $from = new MailAddress('*****@*****.**', 'WeRelate'); } else { $replyto = $from->toString(); $from = new MailAddress('*****@*****.**', $from->name); } if (is_array($wgSMTP)) { require_once 'Mail.php'; $timestamp = time(); $dest = $to->address; $headers['From'] = $from->toString(); $headers['To'] = $to->toString(); if ($replyto) { $headers['Reply-To'] = $replyto; } else { $headers['Reply-To'] = $from->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['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 {$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.'; } } 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) $headers = "MIME-Version: 1.0\n" . "Content-type: text/plain; charset={$wgOutputEncoding}\n" . "Content-Transfer-Encoding: 8bit\n" . "X-Mailer: MediaWiki mailer\n" . "From: {$from->toString()}\n"; if ($replyto) { $headers .= "Reply-To: {$replyto}\n"; } else { $headers .= 'Reply-To: ' . $from->toString() . "\n"; } $dest = $to->toString(); $wgErrorString = ''; set_error_handler('mailErrorHandler'); wfDebug("Sending mail via internal mail() function to {$dest}\n"); mail($dest, wfQuotedPrintable($subject), $body, $headers); restore_error_handler(); if ($wgErrorString) { wfDebug("Error sending mail: {$wgErrorString}\n"); } return $wgErrorString; } }
function doSubmit() { global $wgOut, $wgRequest; global $wgUserEmailUseReplyTo, $wgEmergencyContact; global $wgContactSender, $wgContactSenderName; $csender = $wgContactSender ? $wgContactSender : $wgEmergencyContact; $cname = $wgContactSenderName; $fname = 'EmailContactForm::doSubmit'; wfDebug("{$fname}: start\n"); $to = new MailAddress($this->target); $replyto = null; if (!$this->fromaddress) { $from = new MailAddress($csender, $cname); } elseif ($wgUserEmailUseReplyTo) { $from = new MailAddress($csender, $cname); $replyto = new MailAddress($this->fromaddress, $this->fromname); } else { $from = new MailAddress($this->fromaddress, $this->fromname); } $subject = trim($this->subject); if ($subject === "") { $subject = wfMsgForContent("contactpage-defsubject"); } if ($this->fromname !== "") { $subject = wfMsgForContent("contactpage-subject-and-sender", $subject, $this->fromname); } elseif ($this->fromaddress !== "") { $subject = wfMsgForContent("contactpage-subject-and-sender", $subject, $this->fromaddress); } if (wfRunHooks('ContactForm', array(&$to, &$replyto, &$subject, &$this->text))) { wfDebug("{$fname}: sending mail from " . $from->toString() . " to " . $to->toString() . " replyto " . ($replyto == null ? '-/-' : $replyto->toString()) . "\n"); $replyaddr = $replyto == null ? null : $replyto; $mailResult = UserMailer::send($to, $from, $subject, $this->text, $replyaddr); if (WikiError::isError($mailResult)) { $wgOut->addWikiText(wfMsg("usermailererror") . $mailResult->getMessage()); } else { // if the user requested a copy of this mail, do this now, // unless they are emailing themselves, in which case one copy of the message is sufficient. if ($this->cc_me && $replyto) { $cc_subject = wfMsg('emailccsubject', $this->target->getName(), $subject); if (wfRunHooks('ContactForm', array(&$from, &$replyto, &$cc_subject, &$this->text))) { wfDebug("{$fname}: sending cc mail from " . $from->toString() . " to " . $replyto->toString() . "\n"); $ccResult = UserMailer::send($replyto, $from, $cc_subject, $this->text); if (WikiError::isError($ccResult)) { // At this stage, the user's CC mail has failed, but their // original mail has succeeded. It's unlikely, but still, what to do? // We can either show them an error, or we can say everything was fine, // or we can say we sort of failed AND sort of succeeded. Of these options, // simply saying there was an error is probably best. $wgOut->addWikiText(wfMsg("usermailererror") . $ccResult); return; } } } wfDebug("{$fname}: success\n"); $returnto = Title::newFromText($wgRequest->getVal('returnto')); if (is_null($returnto) || !$returnto->isLocal()) { $returnto = SpecialPage::getTitleFor("Contact"); } $wgOut->redirect($returnto->getFullUrl()); wfRunHooks('ContactFromComplete', array($to, $replyto, $subject, $this->text)); } } wfDebug("{$fname}: end\n"); }
public function addBcc($bcc, $bccName = '') { if (!$this->isValidMail($bcc)) { throw new \Core3\Exception\InvalidArgument(); } $adr = new MailAddress(); $adr->setAddress($bcc); $adr->setName($bccName); $this->mailBcc[] = $adr; }
/** * 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 MailAddress|MailAddress[] $to Recipient's email (or an array of them) * @param MailAddress $from Sender's email * @param string $subject Email's subject. * @param string $body Email's text or Array of two strings to be the text and html bodies * @param MailAddress $replyto Optional reply-to email (default: null). * @param string $contentType Optional custom Content-Type (default: text/plain; charset=UTF-8) * @throws MWException * @throws Exception * @return Status */ public static function send($to, $from, $subject, $body, $replyto = null, $contentType = 'text/plain; charset=UTF-8') { global $wgSMTP, $wgEnotifMaxRecips, $wgAdditionalMailParams, $wgAllowHTMLEmail; $mime = null; if (!is_array($to)) { $to = array($to); } // mail body must have some content $minBodyLen = 10; // arbitrary but longer than Array or Object to detect casting error // body must either be a string or an array with text and body if (!(!is_array($body) && strlen($body) >= $minBodyLen) && !(is_array($body) && isset($body['text']) && isset($body['html']) && strlen($body['text']) >= $minBodyLen && strlen($body['html']) >= $minBodyLen)) { // if it is neither we have a problem return Status::newFatal('user-mail-no-body'); } if (!$wgAllowHTMLEmail && is_array($body)) { // HTML not wanted. Dump it. $body = $body['text']; } wfDebug(__METHOD__ . ': sending mail to ' . implode(', ', $to) . "\n"); # Make sure we have at least one address $has_address = false; foreach ($to as $u) { if ($u->address) { $has_address = true; break; } } if (!$has_address) { return Status::newFatal('user-mail-no-addy'); } # Forge email headers # ------------------- # # WARNING # # DO NOT add To: or Subject: headers at this step. They need to be # handled differently depending upon the mailer we are going to use. # # To: # PHP mail() first argument is the mail receiver. The argument is # used as a recipient destination and as a To header. # # PEAR mailer has a recipient argument which is only used to # send the mail. If no To header is given, PEAR will set it to # to 'undisclosed-recipients:'. # # NOTE: To: is for presentation, the actual recipient is specified # by the mailer using the Rcpt-To: header. # # Subject: # PHP mail() second argument to pass the subject, passing a Subject # as an additional header will result in a duplicate header. # # PEAR mailer should be passed a Subject header. # # -- hashar 20120218 $headers['From'] = $from->toString(); $returnPath = $from->address; $extraParams = $wgAdditionalMailParams; // Hook to generate custom VERP address for 'Return-Path' Hooks::run('UserMailerChangeReturnPath', array($to, &$returnPath)); # Add the envelope sender address using the -f command line option when PHP mail() is used. # Will default to the $from->address when the UserMailerChangeReturnPath hook fails and the # generated VERP address when the hook runs effectively. $extraParams .= ' -f ' . $returnPath; $headers['Return-Path'] = $returnPath; if ($replyto) { $headers['Reply-To'] = $replyto->toString(); } $headers['Date'] = MWTimestamp::getLocalInstance()->format('r'); $headers['Message-ID'] = self::makeMsgId(); $headers['X-Mailer'] = 'MediaWiki mailer'; # Line endings need to be different on Unix and Windows due to # the bug described at http://trac.wordpress.org/ticket/2603 if (wfIsWindows()) { $endl = "\r\n"; } else { $endl = "\n"; } if (is_array($body)) { // we are sending a multipart message wfDebug("Assembling multipart mime email\n"); if (!stream_resolve_include_path('Mail/mime.php')) { wfDebug("PEAR Mail_Mime package is not installed. Falling back to text email.\n"); // remove the html body for text email fall back $body = $body['text']; } else { require_once 'Mail/mime.php'; if (wfIsWindows()) { $body['text'] = str_replace("\n", "\r\n", $body['text']); $body['html'] = str_replace("\n", "\r\n", $body['html']); } $mime = new Mail_mime(array('eol' => $endl, 'text_charset' => 'UTF-8', 'html_charset' => 'UTF-8')); $mime->setTXTBody($body['text']); $mime->setHTMLBody($body['html']); $body = $mime->get(); // must call get() before headers() $headers = $mime->headers($headers); } } if ($mime === null) { // sending text only, either deliberately or as a fallback if (wfIsWindows()) { $body = str_replace("\n", "\r\n", $body); } $headers['MIME-Version'] = '1.0'; $headers['Content-type'] = is_null($contentType) ? 'text/plain; charset=UTF-8' : $contentType; $headers['Content-transfer-encoding'] = '8bit'; } $ret = Hooks::run('AlternateUserMailer', array($headers, $to, $from, $subject, $body)); if ($ret === false) { // the hook implementation will return false to skip regular mail sending return Status::newGood(); } elseif ($ret !== true) { // the hook implementation will return a string to pass an error message return Status::newFatal('php-mail-error', $ret); } if (is_array($wgSMTP)) { # # PEAR MAILER # //start Eli Agbayani Nov 26, 2015 $path = '/usr/local/Cellar/php53/5.3.29_2/lib/php'; set_include_path(get_include_path() . PATH_SEPARATOR . $path); //end Eli Agbayani if (!stream_resolve_include_path('Mail.php')) { throw new MWException('PEAR mail package is not installed'); } require_once 'Mail.php'; wfSuppressWarnings(); // Create the mail object using the Mail::factory method $mail_object =& Mail::factory('smtp', $wgSMTP); if (PEAR::isError($mail_object)) { wfDebug("PEAR::Mail factory failed: " . $mail_object->getMessage() . "\n"); wfRestoreWarnings(); return Status::newFatal('pear-mail-error', $mail_object->getMessage()); } wfDebug("Sending mail via PEAR::Mail\n"); $headers['Subject'] = self::quotedPrintable($subject); # When sending only to one recipient, shows it its email using To: if (count($to) == 1) { $headers['To'] = $to[0]->toString(); } # Split jobs since SMTP servers tends to limit the maximum # number of possible recipients. $chunks = array_chunk($to, $wgEnotifMaxRecips); foreach ($chunks as $chunk) { $status = self::sendWithPear($mail_object, $chunk, $headers, $body); # FIXME : some chunks might be sent while others are not! if (!$status->isOK()) { wfRestoreWarnings(); return $status; } } wfRestoreWarnings(); return Status::newGood(); } else { # # PHP mail() # if (count($to) > 1) { $headers['To'] = 'undisclosed-recipients:;'; } $headers = self::arrayToHeaderString($headers, $endl); wfDebug("Sending mail via internal mail() function\n"); self::$mErrorString = ''; $html_errors = ini_get('html_errors'); ini_set('html_errors', '0'); set_error_handler('UserMailer::errorHandler'); try { $safeMode = wfIniGetBool('safe_mode'); foreach ($to as $recip) { if ($safeMode) { $sent = mail($recip, self::quotedPrintable($subject), $body, $headers); } else { $sent = mail($recip, self::quotedPrintable($subject), $body, $headers, $extraParams); } } } catch (Exception $e) { restore_error_handler(); throw $e; } restore_error_handler(); ini_set('html_errors', $html_errors); if (self::$mErrorString) { wfDebug("Error sending mail: " . self::$mErrorString . "\n"); return Status::newFatal('php-mail-error', self::$mErrorString); } elseif (!$sent) { // mail function only tells if there's an error wfDebug("Unknown error sending mail\n"); return Status::newFatal('php-mail-error-unknown'); } else { return Status::newGood(); } } }
/** * @covers MailAddress::__toString */ public function test__ToString() { $ma = new MailAddress('*****@*****.**', 'UserName', 'A real name'); $this->assertEquals($ma->toString(), (string) $ma); }
protected function doResolveRequest($approved, $data) { $request = GlobalRenameRequest::newFromId($data['rid']); $oldUser = User::newFromName($request->getName()); if ($request->userIsGlobal() || $request->getWiki() === wfWikiId()) { $notifyEmail = MailAddress::newFromUser($oldUser); } else { $notifyEmail = $this->getRemoteUserMailAddress($request->getWiki(), $request->getName()); } $newUser = User::newFromName($request->getNewName(), 'creatable'); $status = new Status(); $session = $this->getContext()->exportSession(); if ($approved) { if ($request->userIsGlobal()) { // Trigger a global rename job $globalRenameUser = new GlobalRenameUser($this->getUser(), $oldUser, CentralAuthUser::getInstance($oldUser), $newUser, CentralAuthUser::getInstance($newUser), new GlobalRenameUserStatus($newUser->getName()), 'JobQueueGroup::singleton', new GlobalRenameUserDatabaseUpdates(), new GlobalRenameUserLogger($this->getUser()), $session); $status = $globalRenameUser->rename($data); } else { // If the user is local-only: // * rename the local user using LocalRenameUserJob // * create a global user attached only to the local wiki $job = new LocalRenameUserJob(Title::newFromText('Global rename job'), array('from' => $oldUser->getName(), 'to' => $newUser->getName(), 'renamer' => $this->getUser()->getName(), 'movepages' => true, 'suppressredirects' => true, 'promotetoglobal' => true, 'reason' => $data['reason'], 'session' => $session)); JobQueueGroup::singleton($request->getWiki())->push($job); // Now log it $this->logPromotionRename($oldUser->getName(), $request->getWiki(), $newUser->getName(), $data['reason']); $status = Status::newGood(); } } if ($status->isGood()) { $request->setStatus($approved ? GlobalRenameRequest::APPROVED : GlobalRenameRequest::REJECTED); $request->setCompleted(wfTimestampNow()); $request->setPerformer(CentralAuthUser::getInstance($this->getUser())->getId()); $request->setComments($data['comments']); if ($request->save()) { // Send email to the user about the change in status. if ($approved) { $subject = $this->msg('globalrenamequeue-email-subject-approved')->inContentLanguage()->text(); $body = $this->msg('globalrenamequeue-email-body-approved', array($oldUser->getName(), $newUser->getName()))->inContentLanguage()->text(); } else { $subject = $this->msg('globalrenamequeue-email-subject-rejected')->inContentLanguage()->text(); $body = $this->msg('globalrenamequeue-email-body-rejected', array($oldUser->getName(), $newUser->getName(), $request->getComments()))->inContentLanguage()->text(); } if ($notifyEmail !== null && $notifyEmail->address) { $type = $approved ? 'approval' : 'rejection'; wfDebugLog('CentralAuthRename', "Sending {$type} email to User:{$oldUser->getName()}/{$notifyEmail->address}"); $this->sendNotificationEmail($notifyEmail, $subject, $body); } } else { $status->fatal('globalrenamequeue-request-savefailed'); } } return $status; }
function wfTodoParserFunction_Render( &$parser, $input, $users, $project='') { global $wgOut, $wgSitename, $wgEmergencyContact, $todoPreview; global $wgUseProjects; $username = ''; $fullname = ''; $u = 0; $userIdList = array(); $userIdList2 = array(); $dbr = wfGetDB( DB_SLAVE ); $task_text = ''; $task_project = ''; if ($wgUseProjects) { if (isset($project) && ($project != '')) { $task_project .= "''"; $first = true; $validProjects = getValidProjects(); $projlist = preg_split('/\s*,\s*/', $project, -1, PREG_SPLIT_NO_EMPTY); foreach ( $projlist as $proj ) { if (!$first) { $task_project .= ', '; } else { $first = false; } $task_project .= validateProject($validProjects, $proj); } $task_project .= "'' - "; } } $task_text .= "$input (''' "; if ($users == '') { // if no user specified $task_text .= wfMsgTL('tasklistunspecuser'); } else { $first = true; $userlist = preg_split('/\s*,\s*/', $users, -1, PREG_SPLIT_NO_EMPTY); foreach ( $userlist as $user ) { if (!$first) { $task_text .= ', '; } else { $first = false; } $userid = getUserIDFromUserText($user); if ($userid != 0) { // successfully found the user $u = User::newFromId($userid); $username = $u->getName(); $fullname = $u->getRealName(); if ($fullname == '') $task_text .= $username; else $task_text .= $fullname; array_push($userIdList, $userid); array_push($userIdList2, $userid); } else { // fall through to worst case scenario $task_text .= wfMsgTL('tasklistincorrectuser'); } } } $task_text .= "''' )"; $text = $task_project . $task_text; /* The following assumes the existance of an extra wiki table called $prefix_todo. To create this table issue CREATE TABLE wiki_todo ( id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, hash TINYBLOB ); */ $hash = md5($task_text); if (is_object($todoPreview) && !$todoPreview->preview) { /* Only when the action is a Submit instead of a Preview, send out an email reminder and store in database (if needed). */ $adminAddress = new MailAddress( $wgEmergencyContact, 'WikiAdmin' ); $tasklist = Title::newFromText("Special:TaskList"); $body = sprintf(wfMsgTL('tasklistemailbody'), $parser->getTitle()->getFullURL(), $tasklist->getFullURL(), $wgSitename); $row = $dbr->selectRow( 'todo', 'id', array( 'hash' => $hash ), __METHOD__ ); if (!$row) { // this is a new todo item while ($userid = array_pop($userIdList)) { $u = User::newFromId($userid); $fullname = $u->getRealName(); $email = sprintf(wfMsgTL('tasklistemail'), $fullname . $body); $u->sendMail(sprintf(wfMsgTL('tasklistemailsubject'), $wgSitename), $email, $adminAddress->toString()); $dbr->insert('todo', array( 'hash' => $hash ), __METHOD__ ); } } } return $text; }