MediaWiki
REL1_20
|
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 $form->addPreText( $this->msg( 'emailpagetext' )->parse() ); 00143 $form->setSubmitTextMsg( 'emailsend' ); 00144 $form->setTitle( $this->getTitle() ); 00145 $form->setSubmitCallback( array( __CLASS__, 'uiSubmit' ) ); 00146 $form->setWrapperLegendMsg( 'email-legend' ); 00147 $form->loadData(); 00148 00149 if( !wfRunHooks( 'EmailUserForm', array( &$form ) ) ) { 00150 return false; 00151 } 00152 00153 $result = $form->show(); 00154 00155 if( $result === true || ( $result instanceof Status && $result->isGood() ) ) { 00156 $out->setPageTitle( $this->msg( 'emailsent' ) ); 00157 $out->addWikiMsg( 'emailsenttext' ); 00158 $out->returnToMain( false, $this->mTargetObj->getUserPage() ); 00159 } 00160 } 00161 00168 public static function getTarget( $target ) { 00169 if ( $target == '' ) { 00170 wfDebug( "Target is empty.\n" ); 00171 return 'notarget'; 00172 } 00173 00174 $nu = User::newFromName( $target ); 00175 if( !$nu instanceof User || !$nu->getId() ) { 00176 wfDebug( "Target is invalid user.\n" ); 00177 return 'notarget'; 00178 } elseif ( !$nu->isEmailConfirmed() ) { 00179 wfDebug( "User has no valid email.\n" ); 00180 return 'noemail'; 00181 } elseif ( !$nu->canReceiveEmail() ) { 00182 wfDebug( "User does not allow user emails.\n" ); 00183 return 'nowikiemail'; 00184 } 00185 00186 return $nu; 00187 } 00188 00196 public static function getPermissionsError( $user, $editToken ) { 00197 global $wgEnableEmail, $wgEnableUserEmail; 00198 if( !$wgEnableEmail || !$wgEnableUserEmail ) { 00199 return 'usermaildisabled'; 00200 } 00201 00202 if( !$user->isAllowed( 'sendemail' ) ) { 00203 return 'badaccess'; 00204 } 00205 00206 if( !$user->isEmailConfirmed() ) { 00207 return 'mailnologin'; 00208 } 00209 00210 if( $user->isBlockedFromEmailuser() ) { 00211 wfDebug( "User is blocked from sending e-mail.\n" ); 00212 return "blockedemailuser"; 00213 } 00214 00215 if( $user->pingLimiter( 'emailuser' ) ) { 00216 wfDebug( "Ping limiter triggered.\n" ); 00217 return 'actionthrottledtext'; 00218 } 00219 00220 $hookErr = false; 00221 wfRunHooks( 'UserCanSendEmail', array( &$user, &$hookErr ) ); 00222 wfRunHooks( 'EmailUserPermissionsErrors', array( $user, $editToken, &$hookErr ) ); 00223 if ( $hookErr ) { 00224 return $hookErr; 00225 } 00226 00227 return null; 00228 } 00229 00236 protected function userForm( $name ) { 00237 global $wgScript; 00238 $string = Xml::openElement( 'form', array( 'method' => 'get', 'action' => $wgScript, 'id' => 'askusername' ) ) . 00239 Html::hidden( 'title', $this->getTitle()->getPrefixedText() ) . 00240 Xml::openElement( 'fieldset' ) . 00241 Html::rawElement( 'legend', null, $this->msg( 'emailtarget' )->parse() ) . 00242 Xml::inputLabel( $this->msg( 'emailusername' )->text(), 'target', 'emailusertarget', 30, $name ) . ' ' . 00243 Xml::submitButton( $this->msg( 'emailusernamesubmit' )->text() ) . 00244 Xml::closeElement( 'fieldset' ) . 00245 Xml::closeElement( 'form' ) . "\n"; 00246 return $string; 00247 } 00248 00257 public static function uiSubmit( array $data, HTMLForm $form ) { 00258 return self::submit( $data, $form->getContext() ); 00259 } 00260 00269 public static function submit( array $data, IContextSource $context ) { 00270 global $wgUserEmailUseReplyTo; 00271 00272 $target = self::getTarget( $data['Target'] ); 00273 if( !$target instanceof User ) { 00274 return $context->msg( $target . 'text' )->parseAsBlock(); 00275 } 00276 $to = new MailAddress( $target ); 00277 $from = new MailAddress( $context->getUser() ); 00278 $subject = $data['Subject']; 00279 $text = $data['Text']; 00280 00281 // Add a standard footer and trim up trailing newlines 00282 $text = rtrim( $text ) . "\n\n-- \n"; 00283 $text .= $context->msg( 'emailuserfooter', 00284 $from->name, $to->name )->inContentLanguage()->text(); 00285 00286 $error = ''; 00287 if( !wfRunHooks( 'EmailUser', array( &$to, &$from, &$subject, &$text, &$error ) ) ) { 00288 return $error; 00289 } 00290 00291 if( $wgUserEmailUseReplyTo ) { 00292 // Put the generic wiki autogenerated address in the From: 00293 // header and reserve the user for Reply-To. 00294 // 00295 // This is a bit ugly, but will serve to differentiate 00296 // wiki-borne mails from direct mails and protects against 00297 // SPF and bounce problems with some mailers (see below). 00298 global $wgPasswordSender, $wgPasswordSenderName; 00299 $mailFrom = new MailAddress( $wgPasswordSender, $wgPasswordSenderName ); 00300 $replyTo = $from; 00301 } else { 00302 // Put the sending user's e-mail address in the From: header. 00303 // 00304 // This is clean-looking and convenient, but has issues. 00305 // One is that it doesn't as clearly differentiate the wiki mail 00306 // from "directly" sent mails. 00307 // 00308 // Another is that some mailers (like sSMTP) will use the From 00309 // address as the envelope sender as well. For open sites this 00310 // can cause mails to be flunked for SPF violations (since the 00311 // wiki server isn't an authorized sender for various users' 00312 // domains) as well as creating a privacy issue as bounces 00313 // containing the recipient's e-mail address may get sent to 00314 // the sending user. 00315 $mailFrom = $from; 00316 $replyTo = null; 00317 } 00318 00319 $status = UserMailer::send( $to, $mailFrom, $subject, $text, $replyTo ); 00320 00321 if( !$status->isGood() ) { 00322 return $status; 00323 } else { 00324 // if the user requested a copy of this mail, do this now, 00325 // unless they are emailing themselves, in which case one 00326 // copy of the message is sufficient. 00327 if ( $data['CCMe'] && $to != $from ) { 00328 $cc_subject = $context->msg( 'emailccsubject' )->rawParams( 00329 $target->getName(), $subject )->text(); 00330 wfRunHooks( 'EmailUserCC', array( &$from, &$from, &$cc_subject, &$text ) ); 00331 $ccStatus = UserMailer::send( $from, $from, $cc_subject, $text ); 00332 $status->merge( $ccStatus ); 00333 } 00334 00335 wfRunHooks( 'EmailUserComplete', array( $to, $from, $subject, $text ) ); 00336 return $status; 00337 } 00338 } 00339 }