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