MediaWiki
REL1_22
|
00001 <?php 00029 class SpecialEmailUser extends UnlistedSpecialPage { 00030 protected $mTarget; 00031 00035 protected $mTargetObj; 00036 00037 public function __construct() { 00038 parent::__construct( 'Emailuser' ); 00039 } 00040 00041 public function getDescription() { 00042 $target = self::getTarget( $this->mTarget ); 00043 if ( !$target instanceof User ) { 00044 return $this->msg( 'emailuser-title-notarget' )->text(); 00045 } 00046 00047 return $this->msg( 'emailuser-title-target', $target->getName() )->text(); 00048 } 00049 00050 protected function getFormFields() { 00051 return array( 00052 'From' => array( 00053 'type' => 'info', 00054 'raw' => 1, 00055 'default' => Linker::link( 00056 $this->getUser()->getUserPage(), 00057 htmlspecialchars( $this->getUser()->getName() ) 00058 ), 00059 'label-message' => 'emailfrom', 00060 'id' => 'mw-emailuser-sender', 00061 ), 00062 'To' => array( 00063 'type' => 'info', 00064 'raw' => 1, 00065 'default' => Linker::link( 00066 $this->mTargetObj->getUserPage(), 00067 htmlspecialchars( $this->mTargetObj->getName() ) 00068 ), 00069 'label-message' => 'emailto', 00070 'id' => 'mw-emailuser-recipient', 00071 ), 00072 'Target' => array( 00073 'type' => 'hidden', 00074 'default' => $this->mTargetObj->getName(), 00075 ), 00076 'Subject' => array( 00077 'type' => 'text', 00078 'default' => $this->msg( 'defemailsubject', 00079 $this->getUser()->getName() )->inContentLanguage()->text(), 00080 'label-message' => 'emailsubject', 00081 'maxlength' => 200, 00082 'size' => 60, 00083 'required' => true, 00084 ), 00085 'Text' => array( 00086 'type' => 'textarea', 00087 'rows' => 20, 00088 'cols' => 80, 00089 'label-message' => 'emailmessage', 00090 'required' => true, 00091 ), 00092 'CCMe' => array( 00093 'type' => 'check', 00094 'label-message' => 'emailccme', 00095 'default' => $this->getUser()->getBoolOption( 'ccmeonemails' ), 00096 ), 00097 ); 00098 } 00099 00100 public function execute( $par ) { 00101 $out = $this->getOutput(); 00102 $out->addModuleStyles( 'mediawiki.special' ); 00103 00104 $this->mTarget = is_null( $par ) 00105 ? $this->getRequest()->getVal( 'wpTarget', $this->getRequest()->getVal( 'target', '' ) ) 00106 : $par; 00107 00108 // This needs to be below assignment of $this->mTarget because 00109 // getDescription() needs it to determine the correct page title. 00110 $this->setHeaders(); 00111 $this->outputHeader(); 00112 00113 // error out if sending user cannot do this 00114 $error = self::getPermissionsError( 00115 $this->getUser(), 00116 $this->getRequest()->getVal( 'wpEditToken' ) 00117 ); 00118 00119 switch ( $error ) { 00120 case null: 00121 # Wahey! 00122 break; 00123 case 'badaccess': 00124 throw new PermissionsError( 'sendemail' ); 00125 case 'blockedemailuser': 00126 throw new UserBlockedError( $this->getUser()->mBlock ); 00127 case 'actionthrottledtext': 00128 throw new ThrottledError; 00129 case 'mailnologin': 00130 case 'usermaildisabled': 00131 throw new ErrorPageError( $error, "{$error}text" ); 00132 default: 00133 # It's a hook error 00134 list( $title, $msg, $params ) = $error; 00135 throw new ErrorPageError( $title, $msg, $params ); 00136 } 00137 // Got a valid target user name? Else ask for one. 00138 $ret = self::getTarget( $this->mTarget ); 00139 if ( !$ret instanceof User ) { 00140 if ( $this->mTarget != '' ) { 00141 $ret = ( $ret == 'notarget' ) ? 'emailnotarget' : ( $ret . 'text' ); 00142 $out->wrapWikiMsg( "<p class='error'>$1</p>", $ret ); 00143 } 00144 $out->addHTML( $this->userForm( $this->mTarget ) ); 00145 00146 return false; 00147 } 00148 00149 $this->mTargetObj = $ret; 00150 00151 $context = new DerivativeContext( $this->getContext() ); 00152 $context->setTitle( $this->getTitle() ); // Remove subpage 00153 $form = new HTMLForm( $this->getFormFields(), $context ); 00154 // By now we are supposed to be sure that $this->mTarget is a user name 00155 $form->addPreText( $this->msg( 'emailpagetext', $this->mTarget )->parse() ); 00156 $form->setSubmitTextMsg( 'emailsend' ); 00157 $form->setSubmitCallback( array( __CLASS__, 'uiSubmit' ) ); 00158 $form->setWrapperLegendMsg( 'email-legend' ); 00159 $form->loadData(); 00160 00161 if ( !wfRunHooks( 'EmailUserForm', array( &$form ) ) ) { 00162 return false; 00163 } 00164 00165 $result = $form->show(); 00166 00167 if ( $result === true || ( $result instanceof Status && $result->isGood() ) ) { 00168 $out->setPageTitle( $this->msg( 'emailsent' ) ); 00169 $out->addWikiMsg( 'emailsenttext', $this->mTarget ); 00170 $out->returnToMain( false, $this->mTargetObj->getUserPage() ); 00171 } 00172 } 00173 00180 public static function getTarget( $target ) { 00181 if ( $target == '' ) { 00182 wfDebug( "Target is empty.\n" ); 00183 00184 return 'notarget'; 00185 } 00186 00187 $nu = User::newFromName( $target ); 00188 if ( !$nu instanceof User || !$nu->getId() ) { 00189 wfDebug( "Target is invalid user.\n" ); 00190 00191 return 'notarget'; 00192 } elseif ( !$nu->isEmailConfirmed() ) { 00193 wfDebug( "User has no valid email.\n" ); 00194 00195 return 'noemail'; 00196 } elseif ( !$nu->canReceiveEmail() ) { 00197 wfDebug( "User does not allow user emails.\n" ); 00198 00199 return 'nowikiemail'; 00200 } 00201 00202 return $nu; 00203 } 00204 00212 public static function getPermissionsError( $user, $editToken ) { 00213 global $wgEnableEmail, $wgEnableUserEmail; 00214 00215 if ( !$wgEnableEmail || !$wgEnableUserEmail ) { 00216 return 'usermaildisabled'; 00217 } 00218 00219 if ( !$user->isAllowed( 'sendemail' ) ) { 00220 return 'badaccess'; 00221 } 00222 00223 if ( !$user->isEmailConfirmed() ) { 00224 return 'mailnologin'; 00225 } 00226 00227 if ( $user->isBlockedFromEmailuser() ) { 00228 wfDebug( "User is blocked from sending e-mail.\n" ); 00229 00230 return "blockedemailuser"; 00231 } 00232 00233 if ( $user->pingLimiter( 'emailuser' ) ) { 00234 wfDebug( "Ping limiter triggered.\n" ); 00235 00236 return 'actionthrottledtext'; 00237 } 00238 00239 $hookErr = false; 00240 00241 wfRunHooks( 'UserCanSendEmail', array( &$user, &$hookErr ) ); 00242 wfRunHooks( 'EmailUserPermissionsErrors', array( $user, $editToken, &$hookErr ) ); 00243 00244 if ( $hookErr ) { 00245 return $hookErr; 00246 } 00247 00248 return null; 00249 } 00250 00257 protected function userForm( $name ) { 00258 global $wgScript; 00259 $string = Xml::openElement( 00260 'form', 00261 array( 'method' => 'get', 'action' => $wgScript, 'id' => 'askusername' ) 00262 ) . 00263 Html::hidden( 'title', $this->getTitle()->getPrefixedText() ) . 00264 Xml::openElement( 'fieldset' ) . 00265 Html::rawElement( 'legend', null, $this->msg( 'emailtarget' )->parse() ) . 00266 Xml::inputLabel( 00267 $this->msg( 'emailusername' )->text(), 00268 'target', 00269 'emailusertarget', 00270 30, 00271 $name 00272 ) . 00273 ' ' . 00274 Xml::submitButton( $this->msg( 'emailusernamesubmit' )->text() ) . 00275 Xml::closeElement( 'fieldset' ) . 00276 Xml::closeElement( 'form' ) . "\n"; 00277 00278 return $string; 00279 } 00280 00289 public static function uiSubmit( array $data, HTMLForm $form ) { 00290 return self::submit( $data, $form->getContext() ); 00291 } 00292 00303 public static function submit( array $data, IContextSource $context ) { 00304 global $wgUserEmailUseReplyTo; 00305 00306 $target = self::getTarget( $data['Target'] ); 00307 if ( !$target instanceof User ) { 00308 return $context->msg( $target . 'text' )->parseAsBlock(); 00309 } 00310 00311 $to = new MailAddress( $target ); 00312 $from = new MailAddress( $context->getUser() ); 00313 $subject = $data['Subject']; 00314 $text = $data['Text']; 00315 00316 // Add a standard footer and trim up trailing newlines 00317 $text = rtrim( $text ) . "\n\n-- \n"; 00318 $text .= $context->msg( 'emailuserfooter', 00319 $from->name, $to->name )->inContentLanguage()->text(); 00320 00321 $error = ''; 00322 if ( !wfRunHooks( 'EmailUser', array( &$to, &$from, &$subject, &$text, &$error ) ) ) { 00323 return $error; 00324 } 00325 00326 if ( $wgUserEmailUseReplyTo ) { 00327 // Put the generic wiki autogenerated address in the From: 00328 // header and reserve the user for Reply-To. 00329 // 00330 // This is a bit ugly, but will serve to differentiate 00331 // wiki-borne mails from direct mails and protects against 00332 // SPF and bounce problems with some mailers (see below). 00333 global $wgPasswordSender, $wgPasswordSenderName; 00334 00335 $mailFrom = new MailAddress( $wgPasswordSender, $wgPasswordSenderName ); 00336 $replyTo = $from; 00337 } else { 00338 // Put the sending user's e-mail address in the From: header. 00339 // 00340 // This is clean-looking and convenient, but has issues. 00341 // One is that it doesn't as clearly differentiate the wiki mail 00342 // from "directly" sent mails. 00343 // 00344 // Another is that some mailers (like sSMTP) will use the From 00345 // address as the envelope sender as well. For open sites this 00346 // can cause mails to be flunked for SPF violations (since the 00347 // wiki server isn't an authorized sender for various users' 00348 // domains) as well as creating a privacy issue as bounces 00349 // containing the recipient's e-mail address may get sent to 00350 // the sending user. 00351 $mailFrom = $from; 00352 $replyTo = null; 00353 } 00354 00355 $status = UserMailer::send( $to, $mailFrom, $subject, $text, $replyTo ); 00356 00357 if ( !$status->isGood() ) { 00358 return $status; 00359 } else { 00360 // if the user requested a copy of this mail, do this now, 00361 // unless they are emailing themselves, in which case one 00362 // copy of the message is sufficient. 00363 if ( $data['CCMe'] && $to != $from ) { 00364 $cc_subject = $context->msg( 'emailccsubject' )->rawParams( 00365 $target->getName(), $subject )->text(); 00366 wfRunHooks( 'EmailUserCC', array( &$from, &$from, &$cc_subject, &$text ) ); 00367 $ccStatus = UserMailer::send( $from, $from, $cc_subject, $text ); 00368 $status->merge( $ccStatus ); 00369 } 00370 00371 wfRunHooks( 'EmailUserComplete', array( $to, $from, $subject, $text ) ); 00372 00373 return $status; 00374 } 00375 } 00376 00377 protected function getGroupName() { 00378 return 'users'; 00379 } 00380 }