4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 * http://www.gnu.org/copyleft/gpl.html
22 * @ingroup SpecialPage
25 class SpecialEmailUser
extends UnlistedSpecialPage
{
28 public function __construct(){
29 parent
::__construct( 'Emailuser' );
32 protected function getFormFields(){
38 'default' => $wgUser->getSkin()->link(
39 $wgUser->getUserPage(),
40 htmlspecialchars( $wgUser->getName() )
42 'label-message' => 'emailfrom',
43 'id' => 'mw-emailuser-sender',
48 'default' => $wgUser->getSkin()->link(
49 $this->mTargetObj
->getUserPage(),
50 htmlspecialchars( $this->mTargetObj
->getName() )
52 'label-message' => 'emailto',
53 'id' => 'mw-emailuser-recipient',
58 'default' => $this->mTargetObj
->getName(),
62 'default' => wfMsgExt( 'defemailsubject', array( 'content', 'parsemag' ) ),
63 'label-message' => 'emailsubject',
72 'label-message' => 'emailmessage',
77 'label-message' => 'emailccme',
78 'default' => $wgUser->getBoolOption( 'ccmeonemails' ),
83 public function execute( $par ) {
84 global $wgRequest, $wgOut, $wgUser;
85 $this->mTarget
= is_null( $par )
86 ?
$wgRequest->getVal( 'wpTarget', '' )
89 $ret = self
::getTarget( $this->mTarget
);
90 if( $ret instanceof User
){
91 $this->mTargetObj
= $ret;
93 $wgOut->showErrorPage( "{$ret}title", "{$ret}text" );
97 $error = self
::getPermissionsError( $wgUser, $wgRequest->getVal( 'wpEditToken' ) );
103 $wgOut->permissionRequired( 'sendemail' );
105 case 'blockedemailuser':
106 $wgOut->blockedPage();
108 case 'actionthrottledtext':
109 $wgOut->rateLimited();
112 case 'usermaildisabled':
113 $wgOut->showErrorPage( $error, "{$error}text" );
117 list( $title, $msg, $params ) = $error;
118 $wgOut->showErrorPage( $title, $msg, $params );
122 $form = new HTMLForm( $this->getFormFields() );
123 $form->addPreText( wfMsgExt( 'emailpagetext', 'parseinline' ) );
124 $form->setSubmitText( wfMsg( 'emailsend' ) );
125 $form->setTitle( $this->getTitle() );
126 $form->setSubmitCallback( array( __CLASS__
, 'submit' ) );
127 $form->setWrapperLegend( wfMsgExt( 'email-legend', 'parsemag' ) );
130 if( !wfRunHooks( 'EmailUserForm', array( &$form ) ) ){
134 $wgOut->setPagetitle( wfMsg( 'emailpage' ) );
135 $result = $form->show();
137 if( $result === true ){
138 $wgOut->setPagetitle( wfMsg( 'emailsent' ) );
139 $wgOut->addWikiMsg( 'emailsenttext' );
140 $wgOut->returnToMain( false, $this->mTargetObj
->getUserPage() );
145 * Validate target User
147 * @param $target String: target user name
148 * @return User object on success or a string on error
150 public static function getTarget( $target ) {
151 if ( $target == '' ) {
152 wfDebug( "Target is empty.\n" );
156 $nu = User
::newFromName( $target );
157 if( !$nu instanceof User ||
!$nu->getId() ) {
158 wfDebug( "Target is invalid user.\n" );
160 } else if ( !$nu->isEmailConfirmed() ) {
161 wfDebug( "User has no valid email.\n" );
163 } else if ( !$nu->canReceiveEmail() ) {
164 wfDebug( "User does not allow user emails.\n" );
165 return 'nowikiemail';
172 * Check whether a user is allowed to send email
174 * @param $user User object
175 * @param $editToken String: edit token
176 * @return null on success or string on error
178 public static function getPermissionsError( $user, $editToken ) {
179 global $wgEnableEmail, $wgEnableUserEmail;
180 if( !$wgEnableEmail ||
!$wgEnableUserEmail ){
181 return 'usermaildisabled';
184 if( !$user->isAllowed( 'sendemail' ) ) {
188 if( !$user->isEmailConfirmed() ){
189 return 'mailnologin';
192 if( $user->isBlockedFromEmailuser() ) {
193 wfDebug( "User is blocked from sending e-mail.\n" );
194 return "blockedemailuser";
197 if( $user->pingLimiter( 'emailuser' ) ) {
198 wfDebug( "Ping limiter triggered.\n" );
199 return 'actionthrottledtext';
203 wfRunHooks( 'UserCanSendEmail', array( &$user, &$hookErr ) );
204 wfRunHooks( 'EmailUserPermissionsErrors', array( $user, $editToken, &$hookErr ) );
213 * Really send a mail. Permissions should have been checked using
214 * getPermissionsError(). It is probably also a good
215 * idea to check the edit token and ping limiter in advance.
217 * @return Mixed: True on success, String on error
219 public static function submit( $data ) {
220 global $wgUser, $wgUserEmailUseReplyTo, $wgSiteName;
222 $target = self
::getTarget( $data['Target'] );
223 if( !$target instanceof User
){
224 return wfMsgExt( $target . 'text', 'parse' );
226 $to = new MailAddress( $target );
227 $from = new MailAddress( $wgUser );
228 $subject = $data['Subject'];
229 $text = $data['Text'];
231 // Add a standard footer and trim up trailing newlines
232 $text = rtrim( $text ) . "\n\n-- \n";
235 array( 'content', 'parsemag' ),
236 array( $from->name
, $to->name
)
240 if( !wfRunHooks( 'EmailUser', array( &$to, &$from, &$subject, &$text, &$error ) ) ) {
244 if( $wgUserEmailUseReplyTo ) {
245 // Put the generic wiki autogenerated address in the From:
246 // header and reserve the user for Reply-To.
248 // This is a bit ugly, but will serve to differentiate
249 // wiki-borne mails from direct mails and protects against
250 // SPF and bounce problems with some mailers (see below).
251 global $wgPasswordSender;
252 $mailFrom = new MailAddress( $wgPasswordSender );
255 // Put the sending user's e-mail address in the From: header.
257 // This is clean-looking and convenient, but has issues.
258 // One is that it doesn't as clearly differentiate the wiki mail
259 // from "directly" sent mails.
261 // Another is that some mailers (like sSMTP) will use the From
262 // address as the envelope sender as well. For open sites this
263 // can cause mails to be flunked for SPF violations (since the
264 // wiki server isn't an authorized sender for various users'
265 // domains) as well as creating a privacy issue as bounces
266 // containing the recipient's e-mail address may get sent to
272 $mailResult = UserMailer
::send( $to, $mailFrom, $subject, $text, $replyTo );
274 if( WikiError
::isError( $mailResult ) && false ) {
275 return $mailResult->getMessage();
277 // if the user requested a copy of this mail, do this now,
278 // unless they are emailing themselves, in which case one
279 // copy of the message is sufficient.
280 if ( $data['CCMe'] && $to != $from ) {
286 wfRunHooks( 'EmailUserCC', array( &$from, &$from, &$cc_subject, &$text ) );
287 $ccResult = UserMailer
::send( $from, $from, $cc_subject, $text );
288 if( WikiError
::isError( $ccResult ) ) {
289 // At this stage, the user's CC mail has failed, but their
290 // original mail has succeeded. It's unlikely, but still,
291 // what to do? We can either show them an error, or we can
292 // say everything was fine, or we can say we sort of failed
293 // AND sort of succeeded. Of these options, simply saying
294 // there was an error is probably best.
295 return $ccResult->getMessage();
299 wfRunHooks( 'EmailUserComplete', array( $to, $from, $subject, $text ) );