[ Index ] |
PHP Cross Reference of MediaWiki-1.24.0 |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * Implements Special:Emailuser 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 2 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License along 16 * with this program; if not, write to the Free Software Foundation, Inc., 17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 * http://www.gnu.org/copyleft/gpl.html 19 * 20 * @file 21 * @ingroup SpecialPage 22 */ 23 24 /** 25 * A special page that allows users to send e-mails to other users 26 * 27 * @ingroup SpecialPage 28 */ 29 class SpecialEmailUser extends UnlistedSpecialPage { 30 protected $mTarget; 31 32 /** 33 * @var User|string $mTargetObj 34 */ 35 protected $mTargetObj; 36 37 public function __construct() { 38 parent::__construct( 'Emailuser' ); 39 } 40 41 public function getDescription() { 42 $target = self::getTarget( $this->mTarget ); 43 if ( !$target instanceof User ) { 44 return $this->msg( 'emailuser-title-notarget' )->text(); 45 } 46 47 return $this->msg( 'emailuser-title-target', $target->getName() )->text(); 48 } 49 50 protected function getFormFields() { 51 return array( 52 'From' => array( 53 'type' => 'info', 54 'raw' => 1, 55 'default' => Linker::link( 56 $this->getUser()->getUserPage(), 57 htmlspecialchars( $this->getUser()->getName() ) 58 ), 59 'label-message' => 'emailfrom', 60 'id' => 'mw-emailuser-sender', 61 ), 62 'To' => array( 63 'type' => 'info', 64 'raw' => 1, 65 'default' => Linker::link( 66 $this->mTargetObj->getUserPage(), 67 htmlspecialchars( $this->mTargetObj->getName() ) 68 ), 69 'label-message' => 'emailto', 70 'id' => 'mw-emailuser-recipient', 71 ), 72 'Target' => array( 73 'type' => 'hidden', 74 'default' => $this->mTargetObj->getName(), 75 ), 76 'Subject' => array( 77 'type' => 'text', 78 'default' => $this->msg( 'defemailsubject', 79 $this->getUser()->getName() )->inContentLanguage()->text(), 80 'label-message' => 'emailsubject', 81 'maxlength' => 200, 82 'size' => 60, 83 'required' => true, 84 ), 85 'Text' => array( 86 'type' => 'textarea', 87 'rows' => 20, 88 'cols' => 80, 89 'label-message' => 'emailmessage', 90 'required' => true, 91 ), 92 'CCMe' => array( 93 'type' => 'check', 94 'label-message' => 'emailccme', 95 'default' => $this->getUser()->getBoolOption( 'ccmeonemails' ), 96 ), 97 ); 98 } 99 100 public function execute( $par ) { 101 $out = $this->getOutput(); 102 $out->addModuleStyles( 'mediawiki.special' ); 103 104 $this->mTarget = is_null( $par ) 105 ? $this->getRequest()->getVal( 'wpTarget', $this->getRequest()->getVal( 'target', '' ) ) 106 : $par; 107 108 // This needs to be below assignment of $this->mTarget because 109 // getDescription() needs it to determine the correct page title. 110 $this->setHeaders(); 111 $this->outputHeader(); 112 113 // error out if sending user cannot do this 114 $error = self::getPermissionsError( 115 $this->getUser(), 116 $this->getRequest()->getVal( 'wpEditToken' ), 117 $this->getConfig() 118 ); 119 120 switch ( $error ) { 121 case null: 122 # Wahey! 123 break; 124 case 'badaccess': 125 throw new PermissionsError( 'sendemail' ); 126 case 'blockedemailuser': 127 throw new UserBlockedError( $this->getUser()->mBlock ); 128 case 'actionthrottledtext': 129 throw new ThrottledError; 130 case 'mailnologin': 131 case 'usermaildisabled': 132 throw new ErrorPageError( $error, "{$error}text" ); 133 default: 134 # It's a hook error 135 list( $title, $msg, $params ) = $error; 136 throw new ErrorPageError( $title, $msg, $params ); 137 } 138 // Got a valid target user name? Else ask for one. 139 $ret = self::getTarget( $this->mTarget ); 140 if ( !$ret instanceof User ) { 141 if ( $this->mTarget != '' ) { 142 // Messages used here: notargettext, noemailtext, nowikiemailtext 143 $ret = ( $ret == 'notarget' ) ? 'emailnotarget' : ( $ret . 'text' ); 144 $out->wrapWikiMsg( "<p class='error'>$1</p>", $ret ); 145 } 146 $out->addHTML( $this->userForm( $this->mTarget ) ); 147 148 return; 149 } 150 151 $this->mTargetObj = $ret; 152 153 $context = new DerivativeContext( $this->getContext() ); 154 $context->setTitle( $this->getPageTitle() ); // Remove subpage 155 $form = new HTMLForm( $this->getFormFields(), $context ); 156 // By now we are supposed to be sure that $this->mTarget is a user name 157 $form->addPreText( $this->msg( 'emailpagetext', $this->mTarget )->parse() ); 158 $form->setSubmitTextMsg( 'emailsend' ); 159 $form->setSubmitCallback( array( __CLASS__, 'uiSubmit' ) ); 160 $form->setWrapperLegendMsg( 'email-legend' ); 161 $form->loadData(); 162 163 if ( !wfRunHooks( 'EmailUserForm', array( &$form ) ) ) { 164 return; 165 } 166 167 $result = $form->show(); 168 169 if ( $result === true || ( $result instanceof Status && $result->isGood() ) ) { 170 $out->setPageTitle( $this->msg( 'emailsent' ) ); 171 $out->addWikiMsg( 'emailsenttext', $this->mTarget ); 172 $out->returnToMain( false, $this->mTargetObj->getUserPage() ); 173 } 174 } 175 176 /** 177 * Validate target User 178 * 179 * @param string $target Target user name 180 * @return User User object on success or a string on error 181 */ 182 public static function getTarget( $target ) { 183 if ( $target == '' ) { 184 wfDebug( "Target is empty.\n" ); 185 186 return 'notarget'; 187 } 188 189 $nu = User::newFromName( $target ); 190 if ( !$nu instanceof User || !$nu->getId() ) { 191 wfDebug( "Target is invalid user.\n" ); 192 193 return 'notarget'; 194 } elseif ( !$nu->isEmailConfirmed() ) { 195 wfDebug( "User has no valid email.\n" ); 196 197 return 'noemail'; 198 } elseif ( !$nu->canReceiveEmail() ) { 199 wfDebug( "User does not allow user emails.\n" ); 200 201 return 'nowikiemail'; 202 } 203 204 return $nu; 205 } 206 207 /** 208 * Check whether a user is allowed to send email 209 * 210 * @param User $user 211 * @param string $editToken Edit token 212 * @param Config $config optional for backwards compatibility 213 * @return string|null Null on success or string on error 214 */ 215 public static function getPermissionsError( $user, $editToken, Config $config = null ) { 216 if ( $config === null ) { 217 wfDebug( __METHOD__ . ' called without a Config instance passed to it' ); 218 $config = ConfigFactory::getDefaultInstance()->makeConfig( 'main' ); 219 } 220 if ( !$config->get( 'EnableEmail' ) || !$config->get( 'EnableUserEmail' ) ) { 221 return 'usermaildisabled'; 222 } 223 224 if ( !$user->isAllowed( 'sendemail' ) ) { 225 return 'badaccess'; 226 } 227 228 if ( !$user->isEmailConfirmed() ) { 229 return 'mailnologin'; 230 } 231 232 if ( $user->isBlockedFromEmailuser() ) { 233 wfDebug( "User is blocked from sending e-mail.\n" ); 234 235 return "blockedemailuser"; 236 } 237 238 if ( $user->pingLimiter( 'emailuser' ) ) { 239 wfDebug( "Ping limiter triggered.\n" ); 240 241 return 'actionthrottledtext'; 242 } 243 244 $hookErr = false; 245 246 wfRunHooks( 'UserCanSendEmail', array( &$user, &$hookErr ) ); 247 wfRunHooks( 'EmailUserPermissionsErrors', array( $user, $editToken, &$hookErr ) ); 248 249 if ( $hookErr ) { 250 return $hookErr; 251 } 252 253 return null; 254 } 255 256 /** 257 * Form to ask for target user name. 258 * 259 * @param string $name User name submitted. 260 * @return string Form asking for user name. 261 */ 262 protected function userForm( $name ) { 263 $string = Xml::openElement( 264 'form', 265 array( 'method' => 'get', 'action' => wfScript(), 'id' => 'askusername' ) 266 ) . 267 Html::hidden( 'title', $this->getPageTitle()->getPrefixedText() ) . 268 Xml::openElement( 'fieldset' ) . 269 Html::rawElement( 'legend', null, $this->msg( 'emailtarget' )->parse() ) . 270 Xml::inputLabel( 271 $this->msg( 'emailusername' )->text(), 272 'target', 273 'emailusertarget', 274 30, 275 $name 276 ) . 277 ' ' . 278 Xml::submitButton( $this->msg( 'emailusernamesubmit' )->text() ) . 279 Xml::closeElement( 'fieldset' ) . 280 Xml::closeElement( 'form' ) . "\n"; 281 282 return $string; 283 } 284 285 /** 286 * Submit callback for an HTMLForm object, will simply call submit(). 287 * 288 * @since 1.20 289 * @param array $data 290 * @param HTMLForm $form 291 * @return Status|string|bool 292 */ 293 public static function uiSubmit( array $data, HTMLForm $form ) { 294 return self::submit( $data, $form->getContext() ); 295 } 296 297 /** 298 * Really send a mail. Permissions should have been checked using 299 * getPermissionsError(). It is probably also a good 300 * idea to check the edit token and ping limiter in advance. 301 * 302 * @param array $data 303 * @param IContextSource $context 304 * @return Status|string|bool Status object, or potentially a String on error 305 * or maybe even true on success if anything uses the EmailUser hook. 306 */ 307 public static function submit( array $data, IContextSource $context ) { 308 $config = $context->getConfig(); 309 310 $target = self::getTarget( $data['Target'] ); 311 if ( !$target instanceof User ) { 312 // Messages used here: notargettext, noemailtext, nowikiemailtext 313 return $context->msg( $target . 'text' )->parseAsBlock(); 314 } 315 316 $to = MailAddress::newFromUser( $target ); 317 $from = MailAddress::newFromUser( $context->getUser() ); 318 $subject = $data['Subject']; 319 $text = $data['Text']; 320 321 // Add a standard footer and trim up trailing newlines 322 $text = rtrim( $text ) . "\n\n-- \n"; 323 $text .= $context->msg( 'emailuserfooter', 324 $from->name, $to->name )->inContentLanguage()->text(); 325 326 $error = ''; 327 if ( !wfRunHooks( 'EmailUser', array( &$to, &$from, &$subject, &$text, &$error ) ) ) { 328 return $error; 329 } 330 331 if ( $config->get( 'UserEmailUseReplyTo' ) ) { 332 // Put the generic wiki autogenerated address in the From: 333 // header and reserve the user for Reply-To. 334 // 335 // This is a bit ugly, but will serve to differentiate 336 // wiki-borne mails from direct mails and protects against 337 // SPF and bounce problems with some mailers (see below). 338 $mailFrom = new MailAddress( $config->get( 'PasswordSender' ), 339 wfMessage( 'emailsender' )->inContentLanguage()->text() ); 340 $replyTo = $from; 341 } else { 342 // Put the sending user's e-mail address in the From: header. 343 // 344 // This is clean-looking and convenient, but has issues. 345 // One is that it doesn't as clearly differentiate the wiki mail 346 // from "directly" sent mails. 347 // 348 // Another is that some mailers (like sSMTP) will use the From 349 // address as the envelope sender as well. For open sites this 350 // can cause mails to be flunked for SPF violations (since the 351 // wiki server isn't an authorized sender for various users' 352 // domains) as well as creating a privacy issue as bounces 353 // containing the recipient's e-mail address may get sent to 354 // the sending user. 355 $mailFrom = $from; 356 $replyTo = null; 357 } 358 359 $status = UserMailer::send( $to, $mailFrom, $subject, $text, $replyTo ); 360 361 if ( !$status->isGood() ) { 362 return $status; 363 } else { 364 // if the user requested a copy of this mail, do this now, 365 // unless they are emailing themselves, in which case one 366 // copy of the message is sufficient. 367 if ( $data['CCMe'] && $to != $from ) { 368 $cc_subject = $context->msg( 'emailccsubject' )->rawParams( 369 $target->getName(), $subject )->text(); 370 wfRunHooks( 'EmailUserCC', array( &$from, &$from, &$cc_subject, &$text ) ); 371 $ccStatus = UserMailer::send( $from, $from, $cc_subject, $text ); 372 $status->merge( $ccStatus ); 373 } 374 375 wfRunHooks( 'EmailUserComplete', array( $to, $from, $subject, $text ) ); 376 377 return $status; 378 } 379 } 380 381 protected function getGroupName() { 382 return 'users'; 383 } 384 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Fri Nov 28 14:03:12 2014 | Cross-referenced by PHPXref 0.7.1 |