PageRenderTime 24ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/extensions/ContactPage/SpecialContact.php

https://github.com/ChuguluGames/mediawiki-svn
PHP | 441 lines | 334 code | 65 blank | 42 comment | 66 complexity | be9c11ab7ad3aeb86ae9246aa023d3d9 MD5 | raw file
  1. <?php
  2. /**
  3. * Speclial:Contact, a contact form for visitors.
  4. * Based on SpecialEmailUser.php
  5. *
  6. * @file
  7. * @ingroup SpecialPage
  8. * @author Daniel Kinzler, brightbyte.de
  9. * @copyright © 2007 Daniel Kinzler
  10. * @license GNU General Public Licence 2.0 or later
  11. */
  12. if( !defined( 'MEDIAWIKI' ) ) {
  13. echo( "not a valid entry point.\n" );
  14. die( 1 );
  15. }
  16. /**
  17. * Provides the contact form
  18. * @ingroup SpecialPage
  19. */
  20. class SpecialContact extends SpecialPage {
  21. /**
  22. * Constructor
  23. */
  24. public function __construct() {
  25. parent::__construct( 'Contact' );
  26. }
  27. /**
  28. * Main execution function
  29. *
  30. * @param $par Mixed: Parameters passed to the page
  31. */
  32. public function execute( $par ) {
  33. global $wgUser, $wgOut, $wgRequest, $wgEnableEmail, $wgContactUser;
  34. if( !$wgEnableEmail || !$wgContactUser ) {
  35. $wgOut->showErrorPage( 'nosuchspecialpage', 'nospecialpagetext' );
  36. return;
  37. }
  38. $action = $wgRequest->getVal( 'action' );
  39. $nu = User::newFromName( $wgContactUser );
  40. if( is_null( $nu ) || !$nu->canReceiveEmail() ) {
  41. wfDebug( "Target is invalid user or can't receive.\n" );
  42. $wgOut->showErrorPage( 'noemailtitle', 'noemailtext' );
  43. return;
  44. }
  45. // Blocked users cannot use the contact form if they're disabled from sending email.
  46. if ( $wgUser->isBlockedFromEmailuser() ) {
  47. $wgOut->blockedPage();
  48. return;
  49. }
  50. $f = new EmailContactForm( $nu, $par );
  51. if ( 'success' == $action ) {
  52. wfDebug( __METHOD__ . ": success.\n" );
  53. $f->showSuccess();
  54. } elseif ( 'submit' == $action && $wgRequest->wasPosted() && $f->hasAllInfo() ) {
  55. $token = $wgRequest->getVal( 'wpEditToken' );
  56. if( $wgUser->isAnon() ) {
  57. # Anonymous users may not have a session
  58. # open. Check for suffix anyway.
  59. $tokenOk = ( EDIT_TOKEN_SUFFIX == $token );
  60. } else {
  61. $tokenOk = $wgUser->matchEditToken( $token );
  62. }
  63. if ( !$tokenOk ) {
  64. wfDebug( __METHOD__ . ": bad token (" . ( $wgUser->isAnon() ? 'anon' : 'user' ) . "): $token\n" );
  65. $wgOut->addWikiMsg( 'sessionfailure' );
  66. $f->showForm();
  67. } elseif ( !$f->passCaptcha() ) {
  68. wfDebug( __METHOD__ . ": captcha failed" );
  69. $wgOut->addWikiMsg( 'contactpage-captcha-failed' );
  70. $f->showForm();
  71. } else {
  72. wfDebug( __METHOD__ . ": submit\n" );
  73. $f->doSubmit();
  74. }
  75. } else {
  76. wfDebug( __METHOD__ . ": form\n" );
  77. $f->showForm();
  78. }
  79. }
  80. }
  81. /**
  82. * @todo document
  83. * @ingroup SpecialPage
  84. */
  85. class EmailContactForm {
  86. var $target;
  87. var $text, $subject;
  88. var $cc_me; // Whether user requested to be sent a separate copy of their email.
  89. /**
  90. * @param User $target
  91. */
  92. function __construct( $target, $par ) {
  93. global $wgRequest, $wgUser;
  94. $this->wasPosted = $wgRequest->wasPosted();
  95. $this->formType = $wgRequest->getText( 'formtype', $par );
  96. # Check for type in [[Special:Contact/type]]: change pagetext and prefill form fields
  97. if ( $this->formType != '' ) {
  98. $message = 'contactpage-pagetext-' . $this->formType;
  99. $text = wfMsgExt( $message, 'parse' );
  100. if ( !wfEmptyMsg( $message, $text ) ) {
  101. $this->formularText = $text;
  102. } else {
  103. $this->formularText = wfMsgExt( 'contactpage-pagetext', 'parse' );
  104. }
  105. $message = 'contactpage-subject-' . $this->formType;
  106. $text = wfMsgForContentNoTrans( $message );
  107. if ( !wfEmptyMsg( $message, $text ) ) {
  108. $this->subject = $wgRequest->getText( 'wpSubject', $text );
  109. } else {
  110. $this->subject = $wgRequest->getText( 'wpSubject' );
  111. }
  112. $message = 'contactpage-text-' . $this->formType;
  113. $text = wfMsgForContentNoTrans( $message );
  114. if ( !wfEmptyMsg( $message, $text ) ) {
  115. $this->text = $wgRequest->getText( 'wpText', $text );
  116. } else {
  117. $this->text = $wgRequest->getText( 'wpText' );
  118. }
  119. } else {
  120. $this->formularText = wfMsgExt( 'contactpage-pagetext', 'parse' );
  121. $this->text = $wgRequest->getText( 'wpText' );
  122. $this->subject = $wgRequest->getText( 'wpSubject' );
  123. }
  124. $this->target = $target;
  125. $this->cc_me = $wgRequest->getBool( 'wpCCMe' );
  126. $this->includeIP = $wgRequest->getBool( 'wpIncludeIP' );
  127. $this->fromname = $wgRequest->getText( 'wpFromName' );
  128. $this->fromaddress = $wgRequest->getText( 'wpFromAddress' );
  129. if( $wgUser->isLoggedIn() ) {
  130. if( !$this->fromname ) {
  131. $this->fromname = $wgUser->getName();
  132. }
  133. if( !$this->fromaddress ) {
  134. $this->fromaddress = $wgUser->getEmail();
  135. }
  136. }
  137. // prepare captcha if applicable
  138. if ( $this->useCaptcha() ) {
  139. $captcha = ConfirmEditHooks::getInstance();
  140. $captcha->trigger = 'contactpage';
  141. $captcha->action = 'contact';
  142. }
  143. }
  144. function hasAllInfo() {
  145. global $wgContactRequireAll;
  146. if ( $this->text === null ) {
  147. return false;
  148. } else {
  149. $this->text = trim( $this->text );
  150. }
  151. if ( $this->text === '' ) {
  152. return false;
  153. }
  154. if ( $wgContactRequireAll ) {
  155. if ( $this->fromname === null ) {
  156. return false;
  157. } else {
  158. $this->fromname = trim( $this->fromname );
  159. }
  160. if ( $this->fromname === '' ) {
  161. return false;
  162. }
  163. if ( $this->fromaddress === null ) {
  164. return false;
  165. } else {
  166. $this->fromaddress = trim( $this->fromaddress );
  167. }
  168. if ( $this->fromaddress === '' ) {
  169. return false;
  170. }
  171. }
  172. return true;
  173. }
  174. function showForm() {
  175. global $wgOut, $wgUser, $wgContactRequireAll, $wgContactIncludeIP, $wgRequest;
  176. #TODO: show captcha
  177. $wgOut->setPageTitle( wfMsg( 'contactpage-title' ) );
  178. $wgOut->addHTML( $this->formularText );
  179. if ( $this->subject === '' ) {
  180. $this->subject = wfMsgForContent( 'contactpage-defsubject' );
  181. }
  182. $msgSuffix = $wgContactRequireAll ? '-required' : '';
  183. $titleObj = SpecialPage::getTitleFor( 'Contact' );
  184. $action = $titleObj->getLocalURL( 'action=submit' );
  185. $token = $wgUser->isAnon() ? EDIT_TOKEN_SUFFIX : $wgUser->editToken(); //this kind of sucks, really...
  186. $form =
  187. Xml::openElement( 'form', array( 'method' => 'post', 'action' => $action, 'id' => 'emailuser' ) ) .
  188. Xml::openElement( 'fieldset' ) .
  189. Xml::element( 'legend', null, wfMsg( 'contactpage-legend' ) ) .
  190. Xml::openElement( 'table', array( 'id' => 'mailheader' ) ) .
  191. '<tr>
  192. <td class="mw-label">' .
  193. Xml::label( wfMsg( 'emailsubject' ), 'wpSubject' ) .
  194. '</td>
  195. <td class="mw-input" id="mw-contactpage-subject">' .
  196. Xml::input( 'wpSubject', 60, $this->subject, array( 'type' => 'text', 'maxlength' => 200 ) ) .
  197. '</td>
  198. </tr>
  199. <tr>
  200. <td class="mw-label">' .
  201. Xml::label( wfMsg( "contactpage-fromname$msgSuffix" ), 'wpFromName' ) .
  202. '</td>
  203. <td class="mw-input" id="mw-contactpage-from">' .
  204. Xml::input( 'wpFromName', 60, $this->fromname, array( 'type' => 'text', 'maxlength' => 200 ) ) .
  205. '</td>
  206. </tr>
  207. <tr>
  208. <td class="mw-label">' .
  209. Xml::label( wfMsg( "contactpage-fromaddress$msgSuffix" ), 'wpFromAddress' ) .
  210. '</td>
  211. <td class="mw-input" id="mw-contactpage-address">' .
  212. Xml::input( 'wpFromAddress', 60, $this->fromaddress, array( 'type' => 'text', 'maxlength' => 200 ) ) .
  213. '</td>
  214. </tr>';
  215. // Allow other extensions to add more fields into Special:Contact
  216. wfRunHooks( 'ContactFormBeforeMessage', array( $this, &$form ) );
  217. $form .= '<tr>
  218. <td></td>
  219. <td class="mw-input" id="mw-contactpage-formfootnote">
  220. <small>' . wfMsg( "contactpage-formfootnotes$msgSuffix" ) . '</small>
  221. </td>
  222. </tr>
  223. <tr>
  224. <td class="mw-label">' .
  225. Xml::label( wfMsg( 'emailmessage' ), 'wpText' ) .
  226. '</td>
  227. <td class="mw-input">' .
  228. Xml::textarea( 'wpText', $this->text, 80, 20, array( 'id' => 'wpText' ) ) .
  229. '</td>
  230. </tr>';
  231. if ( $wgContactIncludeIP && $wgUser->isLoggedIn() ) {
  232. $form .= '<tr>
  233. <td></td>
  234. <td class="mw-input">' .
  235. Xml::checkLabel( wfMsg( 'contactpage-includeip' ), 'wpIncludeIP', 'wpIncludeIP', false ) .
  236. '</td>
  237. </tr>';
  238. }
  239. $ccme = $this->wasPosted ? $this->cc_me : $wgUser->getBoolOption( 'ccmeonemails' );
  240. $form .= '<tr>
  241. <td></td>
  242. <td class="mw-input">' .
  243. Xml::checkLabel( wfMsg( 'emailccme' ), 'wpCCMe', 'wpCCMe', $ccme ) .
  244. '<br />' . $this->getCaptcha() .
  245. '</td>
  246. </tr>
  247. <tr>
  248. <td></td>
  249. <td class="mw-submit">' .
  250. Xml::submitButton( wfMsg( 'emailsend' ), array( 'name' => 'wpSend', 'accesskey' => 's' ) ) .
  251. '</td>
  252. </tr>' .
  253. Html::hidden( 'wpEditToken', $token ) .
  254. Html::hidden( 'formtype', $this->formType ) .
  255. Xml::closeElement( 'table' ) .
  256. Xml::closeElement( 'fieldset' ) .
  257. Xml::closeElement( 'form' );
  258. $wgOut->addHTML( $form );
  259. }
  260. function useCaptcha() {
  261. global $wgCaptchaClass, $wgCaptchaTriggers, $wgUser;
  262. if ( !$wgCaptchaClass ) {
  263. return false; // no captcha installed
  264. }
  265. if ( !@$wgCaptchaTriggers['contactpage'] ) {
  266. return false; // don't trigger on contact form
  267. }
  268. if( $wgUser->isAllowed( 'skipcaptcha' ) ) {
  269. wfDebug( "EmailContactForm::useCaptcha: user group allows skipping captcha\n" );
  270. return false;
  271. }
  272. return true;
  273. }
  274. function getCaptcha() {
  275. global $wgCaptcha;
  276. if ( !$this->useCaptcha() ) {
  277. return '';
  278. }
  279. wfSetupSession(); #NOTE: make sure we have a session. May be required for captchas to work.
  280. return '<div class="captcha">' .
  281. $wgCaptcha->getForm() .
  282. wfMsgWikiHtml( 'contactpage-captcha' ) .
  283. "</div>\n";
  284. }
  285. function passCaptcha() {
  286. global $wgCaptcha;
  287. if ( !$this->useCaptcha() ) {
  288. return true;
  289. }
  290. return $wgCaptcha->passCaptcha();
  291. }
  292. function doSubmit() {
  293. global $wgOut, $wgUser;
  294. global $wgUserEmailUseReplyTo, $wgPasswordSender;
  295. global $wgContactSender, $wgContactSenderName, $wgContactIncludeIP;
  296. $csender = $wgContactSender ? $wgContactSender : $wgPasswordSender;
  297. $cname = $wgContactSenderName;
  298. $senderIP = wfGetIP();
  299. wfDebug( __METHOD__ . ": start\n" );
  300. $targetAddress = new MailAddress( $this->target );
  301. $replyto = null;
  302. $contactSender = new MailAddress( $csender, $cname );
  303. if ( !$this->fromaddress ) {
  304. $submitterAddress = $contactSender;
  305. } else {
  306. $submitterAddress = new MailAddress( $this->fromaddress, $this->fromname );
  307. if ( $wgUserEmailUseReplyTo ) {
  308. $replyto = $submitterAddress;
  309. }
  310. }
  311. $subject = trim( $this->subject );
  312. if ( $subject === '' ) {
  313. $subject = wfMsgForContent( 'contactpage-defsubject' );
  314. }
  315. $includeIP = $wgContactIncludeIP && ( $this->includeIP || $wgUser->isAnon() );
  316. if ( $this->fromname !== '' ) {
  317. if ( $includeIP ) {
  318. $subject = wfMsgForContent( 'contactpage-subject-and-sender-withip', $subject, $this->fromname, $senderIP );
  319. } else {
  320. $subject = wfMsgForContent( 'contactpage-subject-and-sender', $subject, $this->fromname );
  321. }
  322. } elseif ( $this->fromaddress !== '' ) {
  323. if ( $includeIP ) {
  324. $subject = wfMsgForContent( 'contactpage-subject-and-sender-withip', $subject, $this->fromaddress, $senderIP );
  325. } else {
  326. $subject = wfMsgForContent( 'contactpage-subject-and-sender', $subject, $this->fromaddress );
  327. }
  328. } elseif ( $includeIP ) {
  329. $subject = wfMsgForContent( 'contactpage-subject-and-sender', $subject, $senderIP );
  330. }
  331. if( !wfRunHooks( 'ContactForm', array( &$targetAddress, &$replyto, &$subject, &$this->text, $this->formType ) ) ) {
  332. wfDebug( __METHOD__ . ": aborted by hook\n" );
  333. return;
  334. }
  335. wfDebug( __METHOD__ . ": sending mail from " . $submitterAddress->toString() .
  336. " to " . $targetAddress->toString().
  337. " replyto " . ( $replyto == null ? '-/-' : $replyto->toString() ) . "\n" );
  338. $mailResult = UserMailer::send( $targetAddress, $submitterAddress, $subject, $this->text, $replyto );
  339. if( WikiError::isError( $mailResult ) ) {
  340. $wgOut->addWikiMsg( 'usermailererror' ) . $mailResult->getMessage();
  341. wfDebug( __METHOD__ . ": got error from UserMailer: " . $mailResult->getMessage() . "\n" );
  342. return;
  343. }
  344. // if the user requested a copy of this mail, do this now,
  345. // unless they are emailing themselves, in which case one copy of the message is sufficient.
  346. if( $this->cc_me && $this->fromaddress ) {
  347. $cc_subject = wfMsg( 'emailccsubject', $this->target->getName(), $subject );
  348. if( wfRunHooks( 'ContactForm', array( &$submitterAddress, &$contactSender, &$cc_subject, &$this->text, $this->formType ) ) ) {
  349. wfDebug( __METHOD__ . ": sending cc mail from " . $contactSender->toString() .
  350. " to " . $submitterAddress->toString() . "\n" );
  351. $ccResult = UserMailer::send( $submitterAddress, $contactSender, $cc_subject, $this->text );
  352. if( WikiError::isError( $ccResult ) ) {
  353. // At this stage, the user's CC mail has failed, but their
  354. // original mail has succeeded. It's unlikely, but still, what to do?
  355. // We can either show them an error, or we can say everything was fine,
  356. // or we can say we sort of failed AND sort of succeeded. Of these options,
  357. // simply saying there was an error is probably best.
  358. $wgOut->addWikiText( wfMsg( 'usermailererror' ) . $ccResult );
  359. return;
  360. }
  361. }
  362. }
  363. wfDebug( __METHOD__ . ": success\n" );
  364. $titleObj = SpecialPage::getTitleFor( 'Contact' );
  365. $wgOut->redirect( $titleObj->getFullURL( 'action=success' ) );
  366. wfRunHooks( 'ContactFromComplete', array( $targetAddress, $replyto, $subject, $this->text ) );
  367. wfDebug( __METHOD__ . ": end\n" );
  368. }
  369. function showSuccess() {
  370. global $wgOut;
  371. $wgOut->setPageTitle( wfMsg( 'emailsent' ) );
  372. $wgOut->addWikiMsg( 'emailsenttext' );
  373. $wgOut->returnToMain( false );
  374. }
  375. }