]> scripts.mit.edu Git - autoinstalls/mediawiki.git/blob - includes/specials/SpecialEmailuser.php
MediaWiki 1.16.0
[autoinstalls/mediawiki.git] / includes / specials / SpecialEmailuser.php
1 <?php
2 /**
3  * @file
4  * @ingroup SpecialPage
5  */
6
7 /**
8  *      Constructor for Special:Emailuser.
9  */
10 function wfSpecialEmailuser( $par ) {
11         global $wgRequest, $wgUser, $wgOut;
12
13         if ( !EmailUserForm::userEmailEnabled() ) {
14                 $wgOut->showErrorPage( 'nosuchspecialpage', 'nospecialpagetext' );
15                 return;
16         }
17
18         $action = $wgRequest->getVal( 'action' );
19         $target = isset($par) ? $par : $wgRequest->getVal( 'target' );
20         $targetUser = EmailUserForm::validateEmailTarget( $target );
21         
22         if ( !( $targetUser instanceof User ) ) {
23                 $wgOut->showErrorPage( $targetUser.'title', $targetUser.'text' );
24                 return;
25         }
26         
27         $form = new EmailUserForm( $targetUser,
28                         $wgRequest->getText( 'wpText' ),
29                         $wgRequest->getText( 'wpSubject' ),
30                         $wgRequest->getBool( 'wpCCMe' ) );
31         if ( $action == 'success' ) {
32                 $form->showSuccess();
33                 return;
34         }
35                                         
36         $error = EmailUserForm::getPermissionsError( $wgUser, $wgRequest->getVal( 'wpEditToken' ) );
37         if ( $error ) {
38                 switch ( $error ) {
39                         case 'blockedemailuser':
40                                 $wgOut->blockedPage();
41                                 return;
42                         case 'actionthrottledtext':
43                                 $wgOut->rateLimited();
44                                 return;
45                         case 'sessionfailure':
46                                 $form->showForm();
47                                 return;
48                         case 'mailnologin':
49                                 $wgOut->showErrorPage( 'mailnologin', 'mailnologintext' );
50                                 return;
51                         default:
52                                 // It's a hook error
53                                 list( $title, $msg, $params ) = $error;
54                                 $wgOut->showErrorPage( $title, $msg, $params );
55                                 return;
56                                 
57                 }
58         }       
59         
60         if ( "submit" == $action && $wgRequest->wasPosted() ) {
61                 $result = $form->doSubmit();
62                 
63                 if ( !is_null( $result ) ) {
64                         $wgOut->addHTML( wfMsg( "usermailererror" ) .
65                                         ' ' . htmlspecialchars( $result->getMessage() ) );
66                 } else {
67                         $titleObj = SpecialPage::getTitleFor( "Emailuser" );
68                         $encTarget = wfUrlencode( $form->getTarget()->getName() );
69                         $wgOut->redirect( $titleObj->getFullURL( "target={$encTarget}&action=success" ) );
70                 }
71         } else {
72                 $form->showForm();
73         }
74 }
75
76 /**
77  * Implements the Special:Emailuser web interface, and invokes userMailer for sending the email message.
78  * @ingroup SpecialPage
79  */
80 class EmailUserForm {
81
82         var $target;
83         var $text, $subject;
84         var $cc_me;     // Whether user requested to be sent a separate copy of their email.
85
86         /**
87          * @param User $target
88          */
89         function EmailUserForm( $target, $text, $subject, $cc_me ) {
90                 $this->target = $target;
91                 $this->text = $text;
92                 $this->subject = $subject;
93                 $this->cc_me = $cc_me;
94         }
95
96         function showForm() {
97                 global $wgOut, $wgUser;
98                 $skin = $wgUser->getSkin();
99
100                 $wgOut->setPagetitle( wfMsg( "emailpage" ) );
101                 $wgOut->addWikiMsg( "emailpagetext" );
102
103                 if ( $this->subject === "" ) {
104                         $this->subject = wfMsgExt( 'defemailsubject', array( 'content', 'parsemag' ) );
105                 }
106
107                 $titleObj = SpecialPage::getTitleFor( "Emailuser" );
108                 $action = $titleObj->getLocalURL( "target=" .
109                         urlencode( $this->target->getName() ) . "&action=submit" );
110
111                 $wgOut->addHTML(  
112                         Xml::openElement( 'form', array( 'method' => 'post', 'action' => $action, 'id' => 'emailuser' ) ) .
113                         Xml::openElement( 'fieldset' ) .
114                         Xml::element( 'legend', null, wfMsgExt( 'email-legend', 'parsemag' ) ) .
115                         Xml::openElement( 'table', array( 'class' => 'mw-emailuser-table' ) ) .
116                         "<tr>
117                                 <td class='mw-label'>" .
118                                         Xml::label( wfMsg( 'emailfrom' ), 'emailfrom' ) .
119                                 "</td>
120                                 <td class='mw-input' id='mw-emailuser-sender'>" .
121                                         $skin->link( $wgUser->getUserPage(), htmlspecialchars( $wgUser->getName() ) ) .
122                                 "</td>
123                         </tr>
124                         <tr>
125                                 <td class='mw-label'>" .
126                                         Xml::label( wfMsg( 'emailto' ), 'emailto' ) .
127                                 "</td>
128                                 <td class='mw-input' id='mw-emailuser-recipient'>" .
129                                         $skin->link( $this->target->getUserPage(), htmlspecialchars( $this->target->getName() ) ) .
130                                 "</td>
131                         </tr>
132                         <tr>
133                                 <td class='mw-label'>" .
134                                         Xml::label( wfMsg( 'emailsubject' ), 'wpSubject' ) .
135                                 "</td>
136                                 <td class='mw-input'>" .
137                                         Xml::input( 'wpSubject', 60, $this->subject, array( 'type' => 'text', 'maxlength' => 200 ) ) .
138                                 "</td>
139                         </tr>
140                         <tr>
141                                 <td class='mw-label'>" .
142                                         Xml::label( wfMsg( 'emailmessage' ), 'wpText' ) .
143                                 "</td>
144                                 <td class='mw-input'>" .
145                                         Xml::textarea( 'wpText', $this->text, 80, 20, array( 'id' => 'wpText' ) ) .
146                                 "</td>
147                         </tr>
148                         <tr>
149                                 <td></td>
150                                 <td class='mw-input'>" .
151                                         Xml::checkLabel( wfMsg( 'emailccme' ), 'wpCCMe', 'wpCCMe', $wgUser->getBoolOption( 'ccmeonemails' ) ) .
152                                 "</td>
153                         </tr>
154                         <tr>
155                                 <td></td>
156                                 <td class='mw-submit'>" .
157                                         Xml::submitButton( wfMsg( 'emailsend' ), array( 'name' => 'wpSend', 'accesskey' => 's' ) ) .
158                                 "</td>
159                         </tr>" .
160                         Xml::hidden( 'wpEditToken', $wgUser->editToken() ) .
161                         Xml::closeElement( 'table' ) .
162                         Xml::closeElement( 'fieldset' ) .
163                         Xml::closeElement( 'form' )
164                 );
165         }
166
167         /*
168          * Really send a mail. Permissions should have been checked using 
169          * EmailUserForm::getPermissionsError. It is probably also a good idea to
170          * check the edit token and ping limiter in advance.
171          */
172         function doSubmit() {
173                 global $wgUser, $wgUserEmailUseReplyTo, $wgSiteName;
174
175                 $to = new MailAddress( $this->target );
176                 $from = new MailAddress( $wgUser );
177                 $subject = $this->subject;
178
179                 // Add a standard footer and trim up trailing newlines
180                 $this->text = rtrim($this->text) . "\n\n-- \n" . wfMsgExt( 'emailuserfooter',
181                         array( 'content', 'parsemag' ), array( $from->name, $to->name ) );
182                 
183                 if( wfRunHooks( 'EmailUser', array( &$to, &$from, &$subject, &$this->text ) ) ) {
184
185                         if( $wgUserEmailUseReplyTo ) {
186                                 // Put the generic wiki autogenerated address in the From:
187                                 // header and reserve the user for Reply-To.
188                                 //
189                                 // This is a bit ugly, but will serve to differentiate
190                                 // wiki-borne mails from direct mails and protects against
191                                 // SPF and bounce problems with some mailers (see below).
192                                 global $wgPasswordSender;
193                                 $mailFrom = new MailAddress( $wgPasswordSender );
194                                 $replyTo = $from;
195                         } else {
196                                 // Put the sending user's e-mail address in the From: header.
197                                 //
198                                 // This is clean-looking and convenient, but has issues.
199                                 // One is that it doesn't as clearly differentiate the wiki mail
200                                 // from "directly" sent mails.
201                                 //
202                                 // Another is that some mailers (like sSMTP) will use the From
203                                 // address as the envelope sender as well. For open sites this
204                                 // can cause mails to be flunked for SPF violations (since the
205                                 // wiki server isn't an authorized sender for various users'
206                                 // domains) as well as creating a privacy issue as bounces
207                                 // containing the recipient's e-mail address may get sent to
208                                 // the sending user.
209                                 $mailFrom = $from;
210                                 $replyTo = null;
211                         }
212                         
213                         $mailResult = UserMailer::send( $to, $mailFrom, $subject, $this->text, $replyTo );
214
215                         if( WikiError::isError( $mailResult ) ) {
216                                 return $mailResult;
217                                 
218                         } else {
219
220                                 // if the user requested a copy of this mail, do this now,
221                                 // unless they are emailing themselves, in which case one copy of the message is sufficient.
222                                 if ($this->cc_me && $to != $from) {
223                                         $cc_subject = wfMsg('emailccsubject', $this->target->getName(), $subject);
224                                         if( wfRunHooks( 'EmailUser', array( &$from, &$from, &$cc_subject, &$this->text ) ) ) {
225                                                 $ccResult = UserMailer::send( $from, $from, $cc_subject, $this->text );
226                                                 if( WikiError::isError( $ccResult ) ) {
227                                                         // At this stage, the user's CC mail has failed, but their
228                                                         // original mail has succeeded. It's unlikely, but still, what to do?
229                                                         // We can either show them an error, or we can say everything was fine,
230                                                         // or we can say we sort of failed AND sort of succeeded. Of these options,
231                                                         // simply saying there was an error is probably best.
232                                                         return $ccResult;
233                                                 }
234                                         }
235                                 }
236
237                                 wfRunHooks( 'EmailUserComplete', array( $to, $from, $subject, $this->text ) );
238                                 return;
239                         }
240                 }
241         }
242
243         function showSuccess( &$user = null ) {
244                 global $wgOut;
245                 
246                 if ( is_null($user) )
247                         $user = $this->target;
248
249                 $wgOut->setPagetitle( wfMsg( "emailsent" ) );
250                 $wgOut->addWikiMsg( 'emailsenttext' );
251
252                 $wgOut->returnToMain( false, $user->getUserPage() );
253         }
254         
255         function getTarget() {
256                 return $this->target;
257         }
258         
259         static function userEmailEnabled() {
260                 global $wgEnableEmail, $wgEnableUserEmail;
261                 return $wgEnableEmail && $wgEnableUserEmail;
262                 
263         }
264         static function validateEmailTarget ( $target ) {
265                 if ( $target == "" ) {
266                         wfDebug( "Target is empty.\n" );
267                         return "notarget";
268                 }
269         
270                 $nt = Title::newFromURL( $target );
271                 if ( is_null( $nt ) ) {
272                         wfDebug( "Target is invalid title.\n" );
273                         return "notarget";
274                 }
275         
276                 $nu = User::newFromName( $nt->getText() );
277                 if( !$nu instanceof User || !$nu->getId() ) {
278                         wfDebug( "Target is invalid user.\n" );
279                         return "notarget";
280                 } else if ( !$nu->isEmailConfirmed() ) {
281                         wfDebug( "User has no valid email.\n" );
282                         return "noemail";
283                 } else if ( !$nu->canReceiveEmail() ) {
284                         wfDebug( "User does not allow user emails.\n" );
285                         return "nowikiemail";
286                 }
287                 
288                 return $nu;
289         }
290         static function getPermissionsError ( $user, $editToken ) {
291                 if( !$user->canSendEmail() ) {
292                         wfDebug( "User can't send.\n" );
293                         // FIXME: this is also the error if user is in a group
294                         //        that is not allowed to send e-mail (no right
295                         //        'sendemail'). Error messages should probably
296                         //        be more fine grained.
297                         return "mailnologin";
298                 }
299                 
300                 if( $user->isBlockedFromEmailuser() ) {
301                         wfDebug( "User is blocked from sending e-mail.\n" );
302                         return "blockedemailuser";
303                 }
304                 
305                 if( $user->pingLimiter( 'emailuser' ) ) {
306                         wfDebug( "Ping limiter triggered.\n" ); 
307                         return 'actionthrottledtext';
308                 }
309                 
310                 $hookErr = null;
311                 wfRunHooks( 'EmailUserPermissionsErrors', array( $user, $editToken, &$hookErr ) );
312                 
313                 if ($hookErr) {
314                         return $hookErr;
315                 }
316                 
317                 if( !$user->matchEditToken( $editToken ) ) {
318                         wfDebug( "Matching edit token failed.\n" );
319                         return 'sessionfailure';
320                 }
321         }
322         
323         static function newFromURL( $target, $text, $subject, $cc_me )
324         {
325                 $nt = Title::newFromURL( $target );
326                 $nu = User::newFromName( $nt->getText() );
327                 return new EmailUserForm( $nu, $text, $subject, $cc_me );
328         }
329 }