mail.php 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890
  1. <?php
  2. // This file is part of GNU social - https://www.gnu.org/software/social
  3. //
  4. // GNU social is free software: you can redistribute it and/or modify
  5. // it under the terms of the GNU Affero General Public License as published by
  6. // the Free Software Foundation, either version 3 of the License, or
  7. // (at your option) any later version.
  8. //
  9. // GNU social 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 Affero General Public License for more details.
  13. //
  14. // You should have received a copy of the GNU Affero General Public License
  15. // along with GNU social. If not, see <http://www.gnu.org/licenses/>.
  16. /**
  17. * Utilities for sending email
  18. *
  19. * @category Mail
  20. * @package GNUsocial
  21. * @author Evan Prodromou <evan@status.net>
  22. * @author Zach Copley <zach@status.net>
  23. * @author Robin Millette <millette@status.net>
  24. * @author Sarven Capadisli <csarven@status.net>
  25. * @copyright 2008 StatusNet, Inc.
  26. * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
  27. */
  28. defined('GNUSOCIAL') || die();
  29. require_once 'Mail.php';
  30. /**
  31. * return the configured mail backend
  32. *
  33. * Uses the $config array to make a mail backend. Cached so it is safe to call
  34. * more than once.
  35. *
  36. * @return Mail backend
  37. */
  38. function mail_backend()
  39. {
  40. static $backend = null;
  41. global $_PEAR;
  42. if (!$backend) {
  43. $mail = new Mail();
  44. $backend = $mail->factory(
  45. common_config('mail', 'backend'),
  46. common_config('mail', 'params') ?: []
  47. );
  48. if ($_PEAR->isError($backend)) {
  49. throw new EmailException($backend->getMessage(), $backend->getCode());
  50. }
  51. }
  52. return $backend;
  53. }
  54. /**
  55. * send an email to one or more recipients
  56. *
  57. * @param array $recipients array of strings with email addresses of recipients
  58. * @param array $headers array mapping strings to strings for email headers
  59. * @param string $body body of the email
  60. *
  61. * @return boolean success flag
  62. */
  63. function mail_send($recipients, $headers, $body)
  64. {
  65. global $_PEAR;
  66. try {
  67. // XXX: use Mail_Queue... maybe
  68. $backend = mail_backend();
  69. if (!isset($headers['Content-Type'])) {
  70. $headers['Content-Type'] = 'text/plain; charset=UTF-8';
  71. }
  72. if ($backend === null) { // throws an error if it's bad
  73. doom("メールバックエンドにエラー。", __FILE__, __LINE__);
  74. }
  75. $sent = $backend->send($recipients, $headers, $body);
  76. if ($_PEAR->isError($sent)) {
  77. throw new EmailException($sent->getMessage(), !is_null($send->getCode()) ? $sent->getCode() : 0);
  78. }
  79. return true;
  80. } catch (PEAR_Exception $e) {
  81. common_log(
  82. LOG_ERR,
  83. "Unable to send email - '{$e->getMessage()}'. "
  84. . 'Is your mail subsystem set up correctly?'
  85. );
  86. return false;
  87. }
  88. }
  89. /**
  90. * returns the configured mail domain
  91. *
  92. * Defaults to the server name.
  93. *
  94. * @return string mail domain, suitable for making email addresses.
  95. */
  96. function mail_domain()
  97. {
  98. $maildomain = common_config('mail', 'domain');
  99. if (!$maildomain) {
  100. $maildomain = common_config('site', 'server');
  101. }
  102. return $maildomain;
  103. }
  104. /**
  105. * returns a good address for sending email from this server
  106. *
  107. * Uses either the configured value or a faked-up value made
  108. * from the mail domain.
  109. *
  110. * @return string notify from address
  111. */
  112. function mail_notify_from()
  113. {
  114. $notifyfrom = common_config('mail', 'notifyfrom');
  115. if (!$notifyfrom) {
  116. $domain = mail_domain();
  117. $notifyfrom = '"'. str_replace('"', '\\"', common_config('site', 'name')) .'" <noreply@'.$domain.'>';
  118. }
  119. return $notifyfrom;
  120. }
  121. /**
  122. * sends email to a user
  123. *
  124. * @param User &$user user to send email to
  125. * @param string $subject subject of the email
  126. * @param string $body body of the email
  127. * @param array $headers optional list of email headers
  128. * @param string $address optional specification of email address
  129. *
  130. * @return boolean success flag
  131. */
  132. function mail_to_user($user, $subject, $body, $headers=array(), $address=null)
  133. {
  134. if (!$address) {
  135. $address = $user->email;
  136. }
  137. $recipients = $address;
  138. $profile = $user->getProfile();
  139. $headers['Date'] = date("r", time());
  140. $headers['From'] = mail_notify_from();
  141. $headers['To'] = $profile->getBestName() . ' <' . $address . '>';
  142. $headers['Subject'] = $subject;
  143. return mail_send($recipients, $headers, $body);
  144. }
  145. /**
  146. * notify a user of subscription by another user
  147. *
  148. * This is just a wrapper around the profile-based version.
  149. *
  150. * @param User $listenee user who is being subscribed to
  151. * @param User $listener user who is subscribing
  152. *
  153. * @see mail_subscribe_notify_profile()
  154. *
  155. * @return void
  156. */
  157. function mail_subscribe_notify($listenee, $listener)
  158. {
  159. $other = $listener->getProfile();
  160. mail_subscribe_notify_profile($listenee, $other);
  161. }
  162. /**
  163. * notify a user of subscription by a profile (remote or local)
  164. *
  165. * This function checks to see if the listenee has an email
  166. * address and wants subscription notices.
  167. *
  168. * @param User $listenee user who's being subscribed to
  169. * @param Profile $other profile of person who's listening
  170. *
  171. * @return void
  172. */
  173. function mail_subscribe_notify_profile($listenee, $other)
  174. {
  175. if ($other->hasRight(Right::EMAILONSUBSCRIBE) &&
  176. $listenee->email && $listenee->emailnotifysub) {
  177. $profile = $listenee->getProfile();
  178. $name = $profile->getBestName();
  179. $long_name = $other->getFancyName();
  180. $recipients = $listenee->email;
  181. // use the recipient's localization
  182. common_switch_locale($listenee->language);
  183. $headers = _mail_prepare_headers('subscribe', $listenee->nickname, $other->nickname);
  184. $headers['From'] = mail_notify_from();
  185. $headers['To'] = $name . ' <' . $listenee->email . '>';
  186. // TRANS: Subject of new-subscriber notification e-mail.
  187. // TRANS: %1$s is the subscribing user's nickname, %2$s is the StatusNet sitename.
  188. $headers['Subject'] = sprintf(
  189. _('%1$s is now following you on %2$s.'),
  190. $other->getBestName(),
  191. common_config('site', 'name')
  192. );
  193. // TRANS: Main body of new-subscriber notification e-mail.
  194. // TRANS: %1$s is the subscriber's long name, %2$s is the StatusNet sitename.
  195. $body = sprintf(
  196. _('%1$s is now following you on %2$s.'),
  197. $long_name,
  198. common_config('site', 'name')
  199. ) .
  200. mail_profile_block($other) .
  201. mail_footer_block();
  202. // reset localization
  203. common_switch_locale();
  204. mail_send($recipients, $headers, $body);
  205. }
  206. }
  207. function mail_subscribe_pending_notify_profile($listenee, $other)
  208. {
  209. if ($other->hasRight(Right::EMAILONSUBSCRIBE) &&
  210. $listenee->email && $listenee->emailnotifysub) {
  211. $profile = $listenee->getProfile();
  212. $name = $profile->getBestName();
  213. $long_name = ($other->fullname) ?
  214. ($other->fullname . ' (' . $other->nickname . ')') : $other->nickname;
  215. $recipients = $listenee->email;
  216. // use the recipient's localization
  217. common_switch_locale($listenee->language);
  218. $headers = _mail_prepare_headers('subscribe', $listenee->nickname, $other->nickname);
  219. $headers['From'] = mail_notify_from();
  220. $headers['To'] = $name . ' <' . $listenee->email . '>';
  221. // TRANS: Subject of pending new-subscriber notification e-mail.
  222. // TRANS: %1$s is the subscribing user's nickname, %2$s is the StatusNet sitename.
  223. $headers['Subject'] = sprintf(
  224. _('%1$s would like to listen to '.
  225. 'your notices on %2$s.'),
  226. $other->getBestName(),
  227. common_config('site', 'name')
  228. );
  229. // TRANS: Main body of pending new-subscriber notification e-mail.
  230. // TRANS: %1$s is the subscriber's long name, %2$s is the StatusNet sitename.
  231. $body = sprintf(
  232. _('%1$s would like to listen to your notices on %2$s. ' .
  233. 'You may approve or reject their subscription at %3$s'),
  234. $long_name,
  235. common_config('site', 'name'),
  236. common_local_url('subqueue', ['nickname' => $listenee->nickname])
  237. ) .
  238. mail_profile_block($other) .
  239. mail_footer_block();
  240. // reset localization
  241. common_switch_locale();
  242. mail_send($recipients, $headers, $body);
  243. }
  244. }
  245. function mail_footer_block()
  246. {
  247. // TRANS: Common footer block for StatusNet notification emails.
  248. // TRANS: %1$s is the StatusNet sitename,
  249. // TRANS: %2$s is a link to the addressed user's e-mail settings.
  250. return "\n\n" . sprintf(
  251. _('Faithfully yours,'.
  252. "\n".'%1$s.'."\n\n".
  253. "----\n".
  254. "Change your email address or ".
  255. "notification options at ".'%2$s'),
  256. common_config('site', 'name'),
  257. common_local_url('emailsettings')
  258. ) . "\n";
  259. }
  260. /**
  261. * Format a block of profile info for a plaintext notification email.
  262. *
  263. * @param Profile $profile
  264. * @return string
  265. */
  266. function mail_profile_block($profile)
  267. {
  268. // TRANS: Layout for
  269. // TRANS: %1$s is the subscriber's profile URL, %2$s is the subscriber's location (or empty)
  270. // TRANS: %3$s is the subscriber's homepage URL (or empty), %4%s is the subscriber's bio (or empty)
  271. $out = array();
  272. $out[] = "";
  273. $out[] = "";
  274. // TRANS: Profile info line in notification e-mail.
  275. // TRANS: %s is a URL.
  276. $out[] = sprintf(_("Profile: %s"), $profile->profileurl);
  277. if ($profile->location) {
  278. // TRANS: Profile info line in notification e-mail.
  279. // TRANS: %s is a location.
  280. $out[] = sprintf(_("Location: %s"), $profile->location);
  281. }
  282. if ($profile->homepage) {
  283. // TRANS: Profile info line in notification e-mail.
  284. // TRANS: %s is a homepage.
  285. $out[] = sprintf(_("Homepage: %s"), $profile->homepage);
  286. }
  287. if ($profile->bio) {
  288. // TRANS: Profile info line in notification e-mail.
  289. // TRANS: %s is biographical information.
  290. $out[] = sprintf(_("Bio: %s"), $profile->bio);
  291. }
  292. $blocklink = common_local_url('block', array('profileid' => $profile->id));
  293. // This'll let ModPlus add the remote profile info so it's possible
  294. // to block remote users directly...
  295. Event::handle('MailProfileInfoBlockLink', array($profile, &$blocklink));
  296. // TRANS: This is a paragraph in a new-subscriber e-mail.
  297. // TRANS: %s is a URL where the subscriber can be reported as abusive.
  298. $out[] = sprintf(
  299. _('If you believe this account is being used abusively, ' .
  300. 'you can block them from your subscribers list and ' .
  301. 'report as spam to site administrators at %s.'),
  302. $blocklink
  303. );
  304. $out[] = "";
  305. return implode("\n", $out);
  306. }
  307. /**
  308. * notify a user of their new incoming email address
  309. *
  310. * User's email and incoming fields should already be updated.
  311. *
  312. * @param User $user user with the new address
  313. *
  314. * @return void
  315. */
  316. function mail_new_incoming_notify($user)
  317. {
  318. $profile = $user->getProfile();
  319. $name = $profile->getBestName();
  320. $headers['From'] = $user->incomingemail;
  321. $headers['To'] = $name . ' <' . $user->email . '>';
  322. // TRANS: Subject of notification mail for new posting email address.
  323. // TRANS: %s is the StatusNet sitename.
  324. $headers['Subject'] = sprintf(
  325. _('New email address for posting to %s'),
  326. common_config('site', 'name')
  327. );
  328. // TRANS: Body of notification mail for new posting email address.
  329. // TRANS: %1$s is the StatusNet sitename, %2$s is the e-mail address to send
  330. // TRANS: to to post by e-mail, %3$s is a URL to more instructions.
  331. $body = sprintf(
  332. _("You have a new posting address on %1\$s.\n\n".
  333. "Send email to %2\$s to post new messages.\n\n".
  334. "More email instructions at %3\$s."),
  335. common_config('site', 'name'),
  336. $user->incomingemail,
  337. common_local_url('doc', ['title' => 'email'])
  338. ) .
  339. mail_footer_block();
  340. mail_send($user->email, $headers, $body);
  341. }
  342. /**
  343. * generate a new address for incoming messages
  344. *
  345. * @todo check the database for uniqueness
  346. *
  347. * @return string new email address for incoming messages
  348. */
  349. function mail_new_incoming_address()
  350. {
  351. $prefix = common_confirmation_code(64);
  352. $suffix = mail_domain();
  353. return $prefix . '@' . $suffix;
  354. }
  355. /**
  356. * broadcast a notice to all subscribers with SMS notification on
  357. *
  358. * This function sends SMS messages to all users who have sms addresses;
  359. * have sms notification on; and have sms enabled for this particular
  360. * subscription.
  361. *
  362. * @param Notice $notice The notice to broadcast
  363. *
  364. * @return success flag
  365. */
  366. function mail_broadcast_notice_sms($notice)
  367. {
  368. // Now, get users subscribed to this profile
  369. $user = new User();
  370. $replies = $notice->getReplies();
  371. $repliesQry = '';
  372. if (!empty($replies)) {
  373. $repliesQry = sprintf(
  374. 'OR %s.id IN (%s)',
  375. $user->escapedTableName(),
  376. implode(',', $replies)
  377. );
  378. }
  379. $user->query(sprintf(
  380. 'SELECT nickname, smsemail, incomingemail ' .
  381. 'FROM %1$s LEFT JOIN subscription ' .
  382. 'ON %1$s.id = subscription.subscriber ' .
  383. 'AND subscription.subscribed = %2$d ' .
  384. 'AND subscription.subscribed <> subscription.subscriber ' .
  385. // Users (other than the sender) who `want SMS notices':
  386. 'WHERE %1$s.id <> %2$d ' .
  387. 'AND %1$s.smsemail IS NOT NULL ' .
  388. 'AND %1$s.smsnotify IS TRUE ' .
  389. // ... where either the user _is_ subscribed to the sender
  390. // (any of the "subscription" fields IS NOT NULL)
  391. // and wants to get SMS for all of this scribe's notices...
  392. 'AND (subscription.sms IS TRUE ' .
  393. // ... or where the user was mentioned in
  394. // or replied-to with the notice:
  395. $repliesQry .
  396. ')',
  397. $user->escapedTableName(),
  398. $notice->profile_id
  399. ));
  400. while ($user->fetch()) {
  401. common_log(
  402. LOG_INFO,
  403. 'Sending notice ' . $notice->id . ' to ' . $user->smsemail,
  404. __FILE__
  405. );
  406. $success = mail_send_sms_notice_address(
  407. $notice,
  408. $user->smsemail,
  409. $user->incomingemail,
  410. $user->nickname
  411. );
  412. if (!$success) {
  413. // XXX: Not sure, but I think that's the right thing to do
  414. common_log(
  415. LOG_WARNING,
  416. 'Sending notice ' . $notice->id . ' to ' . $user->smsemail . ' FAILED, canceling.',
  417. __FILE__
  418. );
  419. return false;
  420. }
  421. }
  422. $user->free();
  423. unset($user);
  424. return true;
  425. }
  426. /**
  427. * send a notice to a user via SMS
  428. *
  429. * A convenience wrapper around mail_send_sms_notice_address()
  430. *
  431. * @param Notice $notice notice to send
  432. * @param User $user user to receive notice
  433. *
  434. * @see mail_send_sms_notice_address()
  435. *
  436. * @return boolean success flag
  437. */
  438. function mail_send_sms_notice($notice, $user)
  439. {
  440. return mail_send_sms_notice_address(
  441. $notice,
  442. $user->smsemail,
  443. $user->incomingemail,
  444. $user->nickname
  445. );
  446. }
  447. /**
  448. * send a notice to an SMS email address from a given address
  449. *
  450. * We use the user's incoming email address as the "From" address to make
  451. * replying to notices easier.
  452. *
  453. * @param Notice $notice notice to send
  454. * @param string $smsemail email address to send to
  455. * @param string $incomingemail email address to set as 'from'
  456. * @param string $nickname nickname to add to beginning
  457. *
  458. * @return boolean success flag
  459. */
  460. function mail_send_sms_notice_address($notice, $smsemail, $incomingemail, $nickname)
  461. {
  462. $to = $nickname . ' <' . $smsemail . '>';
  463. $other = $notice->getProfile();
  464. common_log(LOG_INFO, 'Sending notice ' . $notice->id .
  465. ' to ' . $smsemail, __FILE__);
  466. $headers = array();
  467. $headers['From'] = ($incomingemail) ? $incomingemail : mail_notify_from();
  468. $headers['To'] = $to;
  469. // TRANS: Subject line for SMS-by-email notification messages.
  470. // TRANS: %s is the posting user's nickname.
  471. $headers['Subject'] = sprintf(_('%s status'), $other->getBestName());
  472. $body = $notice->content;
  473. return mail_send($smsemail, $headers, $body);
  474. }
  475. /**
  476. * send a message to confirm a claim for an SMS number
  477. *
  478. * @param string $code confirmation code
  479. * @param string $nickname nickname of user claiming number
  480. * @param string $address email address to send the confirmation to
  481. *
  482. * @see common_confirmation_code()
  483. *
  484. * @return void
  485. */
  486. function mail_confirm_sms($code, $nickname, $address)
  487. {
  488. $recipients = $address;
  489. $headers['From'] = mail_notify_from();
  490. $headers['To'] = $nickname . ' <' . $address . '>';
  491. // TRANS: Subject line for SMS-by-email address confirmation message.
  492. $headers['Subject'] = _('SMS confirmation');
  493. // TRANS: Main body heading for SMS-by-email address confirmation message.
  494. // TRANS: %s is the addressed user's nickname.
  495. $body = sprintf(_('%s: confirm you own this phone number with this code:'), $nickname);
  496. $body .= "\n\n";
  497. $body .= $code;
  498. $body .= "\n\n";
  499. mail_send($recipients, $headers, $body);
  500. }
  501. /**
  502. * send a mail message to notify a user of a 'nudge'
  503. *
  504. * @param User $from user nudging
  505. * @param User $to user being nudged
  506. *
  507. * @return boolean success flag
  508. */
  509. function mail_notify_nudge($from, $to)
  510. {
  511. common_switch_locale($to->language);
  512. // TRANS: Subject for 'nudge' notification email.
  513. // TRANS: %s is the nudging user.
  514. $subject = sprintf(_('You have been nudged by %s'), $from->nickname);
  515. $from_profile = $from->getProfile();
  516. // TRANS: Body for 'nudge' notification email.
  517. // TRANS: %1$s is the nuding user's long name, $2$s is the nudging user's nickname,
  518. // TRANS: %3$s is a URL to post notices at.
  519. $body = sprintf(
  520. _('%1$s (%2$s) is wondering what you are up to ' .
  521. "these days and is inviting you to post some news.\n\n" .
  522. "So let's hear from you :)\n\n" .
  523. "%3\$s\n\n" .
  524. "Don't reply to this email; it won't get to them."),
  525. $from_profile->getBestName(),
  526. $from->nickname,
  527. common_local_url('all', ['nickname' => $to->nickname])
  528. ) .
  529. mail_footer_block();
  530. common_switch_locale();
  531. $headers = _mail_prepare_headers('nudge', $to->nickname, $from->nickname);
  532. return mail_to_user($to, $subject, $body, $headers);
  533. }
  534. /**
  535. * send a message to notify a user of a direct message (DM)
  536. *
  537. * This function checks to see if the recipient wants notification
  538. * of DMs and has a configured email address.
  539. *
  540. * @param Notice $message message to notify about
  541. * @param User $from user sending message
  542. * @param array $to users receiving the message
  543. *
  544. * @return boolean success code
  545. */
  546. function mail_notify_message(Notice $message, Profile $from = null, ?array $to = null)
  547. {
  548. if (is_null($from)) {
  549. $from = $message->getProfile();
  550. }
  551. if (is_null($to)) {
  552. $to = [];
  553. foreach ($message->getAttentionProfiles() as $attention) {
  554. if ($attention->isLocal()) {
  555. $to[] = $attention;
  556. }
  557. }
  558. }
  559. $success = true;
  560. foreach ($to as $t) {
  561. if (is_null($t->email) || !$t->emailnotifymsg) {
  562. continue;
  563. }
  564. common_switch_locale($t->language);
  565. // TRANS: Subject for direct-message notification email.
  566. // TRANS: %s is the sending user's nickname.
  567. $subject = sprintf(_('New private message from %s'), $from->getNickname());
  568. // TRANS: Body for direct-message notification email.
  569. // TRANS: %1$s is the sending user's long name, %2$s is the sending user's nickname,
  570. // TRANS: %3$s is the message content, %4$s a URL to the message,
  571. $body = sprintf(
  572. _("%1\$s (%2\$s) sent you a private message:\n\n".
  573. "------------------------------------------------------\n".
  574. "%3\$s\n".
  575. "------------------------------------------------------\n\n".
  576. "You can reply to their message here:\n\n".
  577. "%4\$s\n\n".
  578. "Don't reply to this email; it won't get to them."),
  579. $from->getBestName(),
  580. $from->getNickname(),
  581. $message->getContent(),
  582. common_local_url('newmessage', ['to' => $from->getID()])
  583. ) .
  584. mail_footer_block();
  585. $headers = _mail_prepare_headers('message', $t->getNickname(), $from->getNickname());
  586. common_switch_locale();
  587. if (!mail_to_user($t, $subject, $body, $headers)) {
  588. common_log(LOG_ERR, "Failed to notify user:{$t->getID()} about the new message:{$message->getID()} sent by user:{$from->getID()}");
  589. $success = false;
  590. }
  591. }
  592. return $success;
  593. }
  594. /**
  595. * Notify a user that they have received an "attn:" message AKA "@-reply"
  596. *
  597. * @param Profile $rcpt The Profile who recevied the notice, should be a local user
  598. * @param Notice $notice The notice that was sent
  599. *
  600. * @return void
  601. */
  602. function mail_notify_attn(Profile $rcpt, Notice $notice)
  603. {
  604. if (!$rcpt->isLocal()) {
  605. return;
  606. }
  607. $sender = $notice->getProfile();
  608. if ($rcpt->sameAs($sender)) {
  609. return;
  610. }
  611. // See if the notice's author who mentions this user is sandboxed
  612. if (!$sender->hasRight(Right::EMAILONREPLY)) {
  613. return;
  614. }
  615. // If the author has blocked the author, don't spam them with a notification.
  616. if ($rcpt->hasBlocked($sender)) {
  617. return;
  618. }
  619. $user = $rcpt->getUser();
  620. if (!$user->receivesEmailNotifications()) {
  621. return;
  622. }
  623. common_switch_locale($user->language);
  624. if ($notice->hasConversation()) {
  625. $conversationUrl = common_local_url(
  626. 'conversation',
  627. ['id' => $notice->conversation]
  628. ) . '#notice-'.$notice->getID();
  629. // TRANS: Line in @-reply notification e-mail. %s is conversation URL.
  630. $conversationEmailText = sprintf(_("The full conversation can be read here:\n\n".
  631. "\t%s"), $conversationUrl) . "\n\n";
  632. } else {
  633. $conversationEmailText = '';
  634. }
  635. // TRANS: E-mail subject for notice notification.
  636. // TRANS: %1$s is the "fancy name" for a profile.
  637. $subject = sprintf(_('%1$s sent a notice to your attention'), $sender->getFancyName());
  638. // TRANS: Body of @-reply notification e-mail.
  639. // TRANS: %1$s is the sending user's name, $2$s is the GNU social sitename,
  640. // TRANS: %3$s is a URL to the notice, %4$s is the notice text,
  641. // TRANS: %5$s is the text "The full conversation can be read here:" and a URL to the full conversion if it exists (otherwise empty),
  642. // TRANS: %6$s is a URL to reply to the notice, %7$s is a URL to all @-replies for the addressed user,
  643. $body = sprintf(
  644. _("%1\$s just sent a notice to your attention (an '@-reply') on %2\$s.\n\n".
  645. "The notice is here:\n\n".
  646. "\t%3\$s\n\n" .
  647. "It reads:\n\n".
  648. "\t%4\$s\n\n" .
  649. "%5\$s" .
  650. "You can reply back here:\n\n".
  651. "\t%6\$s\n\n" .
  652. "The list of all @-replies for you here:\n\n" .
  653. "%7\$s"),
  654. $sender->getFancyName(), //%1
  655. common_config('site', 'name'), //%2
  656. common_local_url(
  657. 'shownotice',
  658. ['notice' => $notice->getID()]
  659. ), //%3
  660. $notice->getContent(), //%4
  661. $conversationEmailText, //%5
  662. common_local_url(
  663. 'newnotice',
  664. ['replyto' => $sender->getNickname(), 'inreplyto' => $notice->getID()]
  665. ), //%6
  666. common_local_url(
  667. 'replies',
  668. ['nickname' => $rcpt->getNickname()]
  669. )
  670. ) . //%7
  671. mail_footer_block();
  672. $headers = _mail_prepare_headers('mention', $rcpt->getNickname(), $sender->getNickname());
  673. common_switch_locale();
  674. mail_to_user($user, $subject, $body, $headers);
  675. }
  676. /**
  677. * Prepare the common mail headers used in notification emails
  678. *
  679. * @param string $msg_type type of message being sent to the user
  680. * @param string $to nickname of the receipient
  681. * @param string $from nickname of the user triggering the notification
  682. *
  683. * @return array list of mail headers to include in the message
  684. */
  685. function _mail_prepare_headers($msg_type, $to, $from)
  686. {
  687. $headers = array(
  688. 'X-StatusNet-MessageType' => $msg_type,
  689. 'X-StatusNet-TargetUser' => $to,
  690. 'X-StatusNet-SourceUser' => $from,
  691. 'X-StatusNet-Domain' => common_config('site', 'server')
  692. );
  693. return $headers;
  694. }
  695. /**
  696. * Send notification emails to group administrator.
  697. *
  698. * @param User_group $group
  699. * @param Profile $joiner
  700. */
  701. function mail_notify_group_join($group, $joiner)
  702. {
  703. // This returns a Profile query...
  704. $admin = $group->getAdmins();
  705. while ($admin->fetch()) {
  706. // We need a local user for email notifications...
  707. $adminUser = User::getKV('id', $admin->id);
  708. // @fixme check for email preference?
  709. if ($adminUser && $adminUser->email) {
  710. // use the recipient's localization
  711. common_switch_locale($adminUser->language);
  712. $headers = _mail_prepare_headers('join', $admin->nickname, $joiner->nickname);
  713. $headers['From'] = mail_notify_from();
  714. $headers['To'] = $admin->getBestName() . ' <' . $adminUser->email . '>';
  715. // TRANS: Subject of group join notification e-mail.
  716. // TRANS: %1$s is the joining user's nickname, %2$s is the group name, and %3$s is the StatusNet sitename.
  717. $headers['Subject'] = sprintf(
  718. _('%1$s has joined your group %2$s on %3$s'),
  719. $joiner->getBestName(),
  720. $group->getBestName(),
  721. common_config('site', 'name')
  722. );
  723. // TRANS: Main body of group join notification e-mail.
  724. // TRANS: %1$s is the subscriber's long name, %2$s is the group name, and %3$s is the StatusNet sitename,
  725. // TRANS: %4$s is a block of profile info about the subscriber.
  726. // TRANS: %5$s is a link to the addressed user's e-mail settings.
  727. $body = sprintf(
  728. _('%1$s has joined your group %2$s on %3$s.'),
  729. $joiner->getFancyName(),
  730. $group->getFancyName(),
  731. common_config('site', 'name')
  732. ) .
  733. mail_profile_block($joiner) .
  734. mail_footer_block();
  735. // reset localization
  736. common_switch_locale();
  737. mail_send($adminUser->email, $headers, $body);
  738. }
  739. }
  740. }
  741. /**
  742. * Send notification emails to group administrator.
  743. *
  744. * @param User_group $group
  745. * @param Profile $joiner
  746. */
  747. function mail_notify_group_join_pending($group, $joiner)
  748. {
  749. $admin = $group->getAdmins();
  750. while ($admin->fetch()) {
  751. // We need a local user for email notifications...
  752. $adminUser = User::getKV('id', $admin->id);
  753. // @fixme check for email preference?
  754. if ($adminUser && $adminUser->email) {
  755. // use the recipient's localization
  756. common_switch_locale($adminUser->language);
  757. $headers = _mail_prepare_headers('join', $admin->nickname, $joiner->nickname);
  758. $headers['From'] = mail_notify_from();
  759. $headers['To'] = $admin->getBestName() . ' <' . $adminUser->email . '>';
  760. // TRANS: Subject of pending group join request notification e-mail.
  761. // TRANS: %1$s is the joining user's nickname, %2$s is the group name, and %3$s is the StatusNet sitename.
  762. $headers['Subject'] = sprintf(
  763. _('%1$s wants to join your group %2$s on %3$s.'),
  764. $joiner->getBestName(),
  765. $group->getBestName(),
  766. common_config('site', 'name')
  767. );
  768. // TRANS: Main body of pending group join request notification e-mail.
  769. // TRANS: %1$s is the subscriber's long name, %2$s is the group name, and %3$s is the StatusNet sitename,
  770. // TRANS: %4$s is the URL to the moderation queue page.
  771. $body = sprintf(
  772. _('%1$s would like to join your group %2$s on %3$s. ' .
  773. 'You may approve or reject their group membership at %4$s'),
  774. $joiner->getFancyName(),
  775. $group->getFancyName(),
  776. common_config('site', 'name'),
  777. common_local_url('groupqueue', ['nickname' => $group->nickname])
  778. ) .
  779. mail_profile_block($joiner) .
  780. mail_footer_block();
  781. // reset localization
  782. common_switch_locale();
  783. mail_send($adminUser->email, $headers, $body);
  784. }
  785. }
  786. }