PageRenderTime 48ms CodeModel.GetById 17ms RepoModel.GetById 1ms app.codeStats 0ms

/lib/mail.php

https://github.com/Br3nda/laconica
PHP | 699 lines | 426 code | 82 blank | 191 comment | 15 complexity | e9a18b7139a7e23583a61095ab9e8bae MD5 | raw file
Possible License(s): AGPL-3.0
  1. <?php
  2. /**
  3. * Laconica, the distributed open-source microblogging tool
  4. *
  5. * utilities for sending email
  6. *
  7. * PHP version 5
  8. *
  9. * LICENCE: This program is free software: you can redistribute it and/or modify
  10. * it under the terms of the GNU Affero General Public License as published by
  11. * the Free Software Foundation, either version 3 of the License, or
  12. * (at your option) any later version.
  13. *
  14. * This program is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. * GNU Affero General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU Affero General Public License
  20. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  21. *
  22. * @category Mail
  23. * @package Laconica
  24. * @author Evan Prodromou <evan@controlyourself.ca>
  25. * @author Zach Copley <zach@controlyourself.ca>
  26. * @author Robin Millette <millette@controlyourself.ca>
  27. * @author Sarven Capadisli <csarven@controlyourself.ca>
  28. * @copyright 2008 Control Yourself, Inc.
  29. * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
  30. * @link http://laconi.ca/
  31. */
  32. if (!defined('LACONICA')) {
  33. exit(1);
  34. }
  35. require_once 'Mail.php';
  36. /**
  37. * return the configured mail backend
  38. *
  39. * Uses the $config array to make a mail backend. Cached so it is safe to call
  40. * more than once.
  41. *
  42. * @return Mail backend
  43. */
  44. function mail_backend()
  45. {
  46. static $backend = null;
  47. if (!$backend) {
  48. $backend = Mail::factory(common_config('mail', 'backend'),
  49. (common_config('mail', 'params')) ?
  50. common_config('mail', 'params') :
  51. array());
  52. if (PEAR::isError($backend)) {
  53. common_server_error($backend->getMessage(), 500);
  54. }
  55. }
  56. return $backend;
  57. }
  58. /**
  59. * send an email to one or more recipients
  60. *
  61. * @param array $recipients array of strings with email addresses of recipients
  62. * @param array $headers array mapping strings to strings for email headers
  63. * @param string $body body of the email
  64. *
  65. * @return boolean success flag
  66. */
  67. function mail_send($recipients, $headers, $body)
  68. {
  69. // XXX: use Mail_Queue... maybe
  70. $backend = mail_backend();
  71. if (!isset($headers['Content-Type'])) {
  72. $headers['Content-Type'] = 'text/plain; charset=UTF-8';
  73. }
  74. assert($backend); // throws an error if it's bad
  75. $sent = $backend->send($recipients, $headers, $body);
  76. if (PEAR::isError($sent)) {
  77. common_log(LOG_ERR, 'Email error: ' . $sent->getMessage());
  78. return false;
  79. }
  80. return true;
  81. }
  82. /**
  83. * returns the configured mail domain
  84. *
  85. * Defaults to the server name.
  86. *
  87. * @return string mail domain, suitable for making email addresses.
  88. */
  89. function mail_domain()
  90. {
  91. $maildomain = common_config('mail', 'domain');
  92. if (!$maildomain) {
  93. $maildomain = common_config('site', 'server');
  94. }
  95. return $maildomain;
  96. }
  97. /**
  98. * returns a good address for sending email from this server
  99. *
  100. * Uses either the configured value or a faked-up value made
  101. * from the mail domain.
  102. *
  103. * @return string notify from address
  104. */
  105. function mail_notify_from()
  106. {
  107. $notifyfrom = common_config('mail', 'notifyfrom');
  108. if (!$notifyfrom) {
  109. $domain = mail_domain();
  110. $notifyfrom = common_config('site', 'name') .' <noreply@'.$domain.'>';
  111. }
  112. return $notifyfrom;
  113. }
  114. /**
  115. * sends email to a user
  116. *
  117. * @param User &$user user to send email to
  118. * @param string $subject subject of the email
  119. * @param string $body body of the email
  120. * @param string $address optional specification of email address
  121. *
  122. * @return boolean success flag
  123. */
  124. function mail_to_user(&$user, $subject, $body, $address=null)
  125. {
  126. if (!$address) {
  127. $address = $user->email;
  128. }
  129. $recipients = $address;
  130. $profile = $user->getProfile();
  131. $headers['From'] = mail_notify_from();
  132. $headers['To'] = $profile->getBestName() . ' <' . $address . '>';
  133. $headers['Subject'] = $subject;
  134. return mail_send($recipients, $headers, $body);
  135. }
  136. /**
  137. * Send an email to confirm a user's control of an email address
  138. *
  139. * @param User $user User claiming the email address
  140. * @param string $code Confirmation code
  141. * @param string $nickname Nickname of user
  142. * @param string $address email address to confirm
  143. *
  144. * @see common_confirmation_code()
  145. *
  146. * @return success flag
  147. */
  148. function mail_confirm_address($user, $code, $nickname, $address)
  149. {
  150. $subject = _('Email address confirmation');
  151. $body = sprintf(_("Hey, %s.\n\n".
  152. "Someone just entered this email address on %s.\n\n" .
  153. "If it was you, and you want to confirm your entry, ".
  154. "use the URL below:\n\n\t%s\n\n" .
  155. "If not, just ignore this message.\n\n".
  156. "Thanks for your time, \n%s\n"),
  157. $nickname, common_config('site', 'name'),
  158. common_local_url('confirmaddress', array('code' => $code)),
  159. common_config('site', 'name'));
  160. return mail_to_user($user, $subject, $body, $address);
  161. }
  162. /**
  163. * notify a user of subscription by another user
  164. *
  165. * This is just a wrapper around the profile-based version.
  166. *
  167. * @param User $listenee user who is being subscribed to
  168. * @param User $listener user who is subscribing
  169. *
  170. * @see mail_subscribe_notify_profile()
  171. *
  172. * @return void
  173. */
  174. function mail_subscribe_notify($listenee, $listener)
  175. {
  176. $other = $listener->getProfile();
  177. mail_subscribe_notify_profile($listenee, $other);
  178. }
  179. /**
  180. * notify a user of subscription by a profile (remote or local)
  181. *
  182. * This function checks to see if the listenee has an email
  183. * address and wants subscription notices.
  184. *
  185. * @param User $listenee user who's being subscribed to
  186. * @param Profile $other profile of person who's listening
  187. *
  188. * @return void
  189. */
  190. function mail_subscribe_notify_profile($listenee, $other)
  191. {
  192. if ($listenee->email && $listenee->emailnotifysub) {
  193. // use the recipient's localization
  194. common_init_locale($listenee->language);
  195. $profile = $listenee->getProfile();
  196. $name = $profile->getBestName();
  197. $long_name = ($other->fullname) ?
  198. ($other->fullname . ' (' . $other->nickname . ')') : $other->nickname;
  199. $recipients = $listenee->email;
  200. $headers['From'] = mail_notify_from();
  201. $headers['To'] = $name . ' <' . $listenee->email . '>';
  202. $headers['Subject'] = sprintf(_('%1$s is now listening to '.
  203. 'your notices on %2$s.'),
  204. $other->getBestName(),
  205. common_config('site', 'name'));
  206. $body = sprintf(_('%1$s is now listening to your notices on %2$s.'."\n\n".
  207. "\t".'%3$s'."\n\n".
  208. '%4$s'.
  209. '%5$s'.
  210. '%6$s'.
  211. "\n".'Faithfully yours,'."\n".'%7$s.'."\n\n".
  212. "----\n".
  213. "Change your email address or ".
  214. "notification options at ".'%8$s' ."\n"),
  215. $long_name,
  216. common_config('site', 'name'),
  217. $other->profileurl,
  218. ($other->location) ?
  219. sprintf(_("Location: %s\n"), $other->location) : '',
  220. ($other->homepage) ?
  221. sprintf(_("Homepage: %s\n"), $other->homepage) : '',
  222. ($other->bio) ?
  223. sprintf(_("Bio: %s\n\n"), $other->bio) : '',
  224. common_config('site', 'name'),
  225. common_local_url('emailsettings'));
  226. // reset localization
  227. common_init_locale();
  228. mail_send($recipients, $headers, $body);
  229. }
  230. }
  231. /**
  232. * notify a user of their new incoming email address
  233. *
  234. * User's email and incoming fields should already be updated.
  235. *
  236. * @param User $user user with the new address
  237. *
  238. * @return void
  239. */
  240. function mail_new_incoming_notify($user)
  241. {
  242. $profile = $user->getProfile();
  243. $name = $profile->getBestName();
  244. $headers['From'] = $user->incomingemail;
  245. $headers['To'] = $name . ' <' . $user->email . '>';
  246. $headers['Subject'] = sprintf(_('New email address for posting to %s'),
  247. common_config('site', 'name'));
  248. $body = sprintf(_("You have a new posting address on %1\$s.\n\n".
  249. "Send email to %2\$s to post new messages.\n\n".
  250. "More email instructions at %3\$s.\n\n".
  251. "Faithfully yours,\n%4\$s"),
  252. common_config('site', 'name'),
  253. $user->incomingemail,
  254. common_local_url('doc', array('title' => 'email')),
  255. common_config('site', 'name'));
  256. mail_send($user->email, $headers, $body);
  257. }
  258. /**
  259. * generate a new address for incoming messages
  260. *
  261. * @todo check the database for uniqueness
  262. *
  263. * @return string new email address for incoming messages
  264. */
  265. function mail_new_incoming_address()
  266. {
  267. $prefix = common_confirmation_code(64);
  268. $suffix = mail_domain();
  269. return $prefix . '@' . $suffix;
  270. }
  271. /**
  272. * broadcast a notice to all subscribers with SMS notification on
  273. *
  274. * This function sends SMS messages to all users who have sms addresses;
  275. * have sms notification on; and have sms enabled for this particular
  276. * subscription.
  277. *
  278. * @param Notice $notice The notice to broadcast
  279. *
  280. * @return success flag
  281. */
  282. function mail_broadcast_notice_sms($notice)
  283. {
  284. // Now, get users subscribed to this profile
  285. $user = new User();
  286. $UT = common_config('db','type')=='pgsql'?'"user"':'user';
  287. $user->query('SELECT nickname, smsemail, incomingemail ' .
  288. "FROM $UT JOIN subscription " .
  289. "ON $UT.id = subscription.subscriber " .
  290. 'WHERE subscription.subscribed = ' . $notice->profile_id . ' ' .
  291. 'AND subscription.subscribed != subscription.subscriber ' .
  292. "AND $UT.smsemail IS NOT null " .
  293. "AND $UT.smsnotify = 1 " .
  294. 'AND subscription.sms = 1 ');
  295. while ($user->fetch()) {
  296. common_log(LOG_INFO,
  297. 'Sending notice ' . $notice->id . ' to ' . $user->smsemail,
  298. __FILE__);
  299. $success = mail_send_sms_notice_address($notice,
  300. $user->smsemail,
  301. $user->incomingemail);
  302. if (!$success) {
  303. // XXX: Not sure, but I think that's the right thing to do
  304. common_log(LOG_WARNING,
  305. 'Sending notice ' . $notice->id . ' to ' .
  306. $user->smsemail . ' FAILED, cancelling.',
  307. __FILE__);
  308. return false;
  309. }
  310. }
  311. $user->free();
  312. unset($user);
  313. return true;
  314. }
  315. /**
  316. * send a notice to a user via SMS
  317. *
  318. * A convenience wrapper around mail_send_sms_notice_address()
  319. *
  320. * @param Notice $notice notice to send
  321. * @param User $user user to receive notice
  322. *
  323. * @see mail_send_sms_notice_address()
  324. *
  325. * @return boolean success flag
  326. */
  327. function mail_send_sms_notice($notice, $user)
  328. {
  329. return mail_send_sms_notice_address($notice,
  330. $user->smsemail,
  331. $user->incomingemail);
  332. }
  333. /**
  334. * send a notice to an SMS email address from a given address
  335. *
  336. * We use the user's incoming email address as the "From" address to make
  337. * replying to notices easier.
  338. *
  339. * @param Notice $notice notice to send
  340. * @param string $smsemail email address to send to
  341. * @param string $incomingemail email address to set as 'from'
  342. *
  343. * @return boolean success flag
  344. */
  345. function mail_send_sms_notice_address($notice, $smsemail, $incomingemail)
  346. {
  347. $to = $nickname . ' <' . $smsemail . '>';
  348. $other = $notice->getProfile();
  349. common_log(LOG_INFO, 'Sending notice ' . $notice->id .
  350. ' to ' . $smsemail, __FILE__);
  351. $headers = array();
  352. $headers['From'] = ($incomingemail) ? $incomingemail : mail_notify_from();
  353. $headers['To'] = $to;
  354. $headers['Subject'] = sprintf(_('%s status'),
  355. $other->getBestName());
  356. $body = $notice->content;
  357. return mail_send($smsemail, $headers, $body);
  358. }
  359. /**
  360. * send a message to confirm a claim for an SMS number
  361. *
  362. * @param string $code confirmation code
  363. * @param string $nickname nickname of user claiming number
  364. * @param string $address email address to send the confirmation to
  365. *
  366. * @see common_confirmation_code()
  367. *
  368. * @return void
  369. */
  370. function mail_confirm_sms($code, $nickname, $address)
  371. {
  372. $recipients = $address;
  373. $headers['From'] = mail_notify_from();
  374. $headers['To'] = $nickname . ' <' . $address . '>';
  375. $headers['Subject'] = _('SMS confirmation');
  376. // FIXME: I18N
  377. $body = "$nickname: confirm you own this phone number with this code:";
  378. $body .= "\n\n";
  379. $body .= $code;
  380. $body .= "\n\n";
  381. mail_send($recipients, $headers, $body);
  382. }
  383. /**
  384. * send a mail message to notify a user of a 'nudge'
  385. *
  386. * @param User $from user nudging
  387. * @param User $to user being nudged
  388. *
  389. * @return boolean success flag
  390. */
  391. function mail_notify_nudge($from, $to)
  392. {
  393. common_init_locale($to->language);
  394. $subject = sprintf(_('You\'ve been nudged by %s'), $from->nickname);
  395. $from_profile = $from->getProfile();
  396. $body = sprintf(_("%1\$s (%2\$s) is wondering what you are up to ".
  397. "these days and is inviting you to post some news.\n\n".
  398. "So let's hear from you :)\n\n".
  399. "%3\$s\n\n".
  400. "Don't reply to this email; it won't get to them.\n\n".
  401. "With kind regards,\n".
  402. "%4\$s\n"),
  403. $from_profile->getBestName(),
  404. $from->nickname,
  405. common_local_url('all', array('nickname' => $to->nickname)),
  406. common_config('site', 'name'));
  407. common_init_locale();
  408. return mail_to_user($to, $subject, $body);
  409. }
  410. /**
  411. * send a message to notify a user of a direct message (DM)
  412. *
  413. * This function checks to see if the recipient wants notification
  414. * of DMs and has a configured email address.
  415. *
  416. * @param Message $message message to notify about
  417. * @param User $from user sending message; default to sender
  418. * @param User $to user receiving message; default to recipient
  419. *
  420. * @return boolean success code
  421. */
  422. function mail_notify_message($message, $from=null, $to=null)
  423. {
  424. if (is_null($from)) {
  425. $from = User::staticGet('id', $message->from_profile);
  426. }
  427. if (is_null($to)) {
  428. $to = User::staticGet('id', $message->to_profile);
  429. }
  430. if (is_null($to->email) || !$to->emailnotifymsg) {
  431. return true;
  432. }
  433. common_init_locale($to->language);
  434. $subject = sprintf(_('New private message from %s'), $from->nickname);
  435. $from_profile = $from->getProfile();
  436. $body = sprintf(_("%1\$s (%2\$s) sent you a private message:\n\n".
  437. "------------------------------------------------------\n".
  438. "%3\$s\n".
  439. "------------------------------------------------------\n\n".
  440. "You can reply to their message here:\n\n".
  441. "%4\$s\n\n".
  442. "Don't reply to this email; it won't get to them.\n\n".
  443. "With kind regards,\n".
  444. "%5\$s\n"),
  445. $from_profile->getBestName(),
  446. $from->nickname,
  447. $message->content,
  448. common_local_url('newmessage', array('to' => $from->id)),
  449. common_config('site', 'name'));
  450. common_init_locale();
  451. return mail_to_user($to, $subject, $body);
  452. }
  453. /**
  454. * notify a user that one of their notices has been chosen as a 'fave'
  455. *
  456. * Doesn't check that the user has an email address nor if they
  457. * want to receive notification of faves. Maybe this happens higher
  458. * up the stack...?
  459. *
  460. * @param User $other The user whose notice was faved
  461. * @param User $user The user who faved the notice
  462. * @param Notice $notice The notice that was faved
  463. *
  464. * @return void
  465. */
  466. function mail_notify_fave($other, $user, $notice)
  467. {
  468. $profile = $user->getProfile();
  469. $bestname = $profile->getBestName();
  470. common_init_locale($other->language);
  471. $subject = sprintf(_('%s added your notice as a favorite'), $bestname);
  472. $body = sprintf(_("%1\$s just added your notice from %2\$s".
  473. " as one of their favorites.\n\n" .
  474. "The URL of your notice is:\n\n" .
  475. "%3\$s\n\n" .
  476. "The text of your notice is:\n\n" .
  477. "%4\$s\n\n" .
  478. "You can see the list of %1\$s's favorites here:\n\n" .
  479. "%5\$s\n\n" .
  480. "Faithfully yours,\n" .
  481. "%6\$s\n"),
  482. $bestname,
  483. common_exact_date($notice->created),
  484. common_local_url('shownotice',
  485. array('notice' => $notice->id)),
  486. $notice->content,
  487. common_local_url('showfavorites',
  488. array('nickname' => $user->nickname)),
  489. common_config('site', 'name'));
  490. common_init_locale();
  491. mail_to_user($other, $subject, $body);
  492. }
  493. /**
  494. * notify a user that they have received an "attn:" message AKA "@-reply"
  495. *
  496. * @param User $user The user who recevied the notice
  497. * @param Notice $notice The notice that was sent
  498. *
  499. * @return void
  500. */
  501. function mail_notify_attn($user, $notice)
  502. {
  503. if (!$user->email || !$user->emailnotifyattn) {
  504. return;
  505. }
  506. $sender = $notice->getProfile();
  507. $bestname = $sender->getBestName();
  508. common_init_locale($user->language);
  509. $subject = sprintf(_('%s sent a notice to your attention'), $bestname);
  510. $body = sprintf(_("%1\$s just sent a notice to your attention (an '@-reply') on %2\$s.\n\n".
  511. "The notice is here:\n\n".
  512. "\t%3\$s\n\n" .
  513. "It reads:\n\n".
  514. "\t%4\$s\n\n" .
  515. "You can reply back here:\n\n".
  516. "\t%5\$s\n\n" .
  517. "The list of all @-replies for you here:\n\n" .
  518. "%6\$s\n\n" .
  519. "Faithfully yours,\n" .
  520. "%2\$s\n\n" .
  521. "P.S. You can turn off these email notifications here: %7\$s\n"),
  522. $bestname,
  523. common_config('site', 'name'),
  524. common_local_url('shownotice',
  525. array('notice' => $notice->id)),
  526. $notice->content,
  527. common_local_url('newnotice',
  528. array('replyto' => $sender->nickname)),
  529. common_local_url('replies',
  530. array('nickname' => $user->nickname)),
  531. common_local_url('emailsettings'));
  532. common_init_locale();
  533. mail_to_user($user, $subject, $body);
  534. }
  535. /**
  536. * Send a mail message to notify a user that her Twitter bridge link
  537. * has stopped working, and therefore has been removed. This can
  538. * happen when the user changes her Twitter password, or otherwise
  539. * revokes access.
  540. *
  541. * @param User $user user whose Twitter bridge link has been removed
  542. *
  543. * @return boolean success flag
  544. */
  545. function mail_twitter_bridge_removed($user)
  546. {
  547. common_init_locale($user->language);
  548. $profile = $user->getProfile();
  549. $subject = sprintf(_('Your Twitter bridge has been disabled.'));
  550. $body = sprintf(_("Hi, %1\$s. We're sorry to inform you that your " .
  551. 'link to Twitter has been disabled. Your Twitter credentials ' .
  552. 'have either changed (did you recently change your Twitter ' .
  553. 'password?) or you have otherwise revoked our access to your ' .
  554. "Twitter account.\n\n" .
  555. 'You can re-enable your Twitter bridge by visiting your ' .
  556. "Twitter settings page:\n\n\t%2\$s\n\n" .
  557. "Regards,\n%3\$s\n"),
  558. $profile->getBestName(),
  559. common_local_url('twittersettings'),
  560. common_config('site', 'name'));
  561. common_init_locale();
  562. return mail_to_user($user, $subject, $body);
  563. }
  564. /**
  565. * Send a mail message to notify a user that her Facebook Application
  566. * access has been removed.
  567. *
  568. * @param User $user user whose Facebook app link has been removed
  569. *
  570. * @return boolean success flag
  571. */
  572. function mail_facebook_app_removed($user)
  573. {
  574. common_init_locale($user->language);
  575. $profile = $user->getProfile();
  576. $site_name = common_config('site', 'name');
  577. $subject = sprintf(
  578. _('Your %s Facebook application access has been disabled.',
  579. $site_name));
  580. $body = sprintf(_("Hi, %1\$s. We're sorry to inform you that we are " .
  581. 'unable to update your Facebook status from %s, and have disabled ' .
  582. 'the Facebook application for your account. This may be because ' .
  583. 'you have removed the Facebook application\'s authorization, or ' .
  584. 'have deleted your Facebook account. You can re-enable the ' .
  585. 'Facebook application and automatic status updating by ' .
  586. "re-installing the %1\$s Facebook application.\n\nRegards,\n\n%1\$s"),
  587. $site_name);
  588. common_init_locale();
  589. return mail_to_user($user, $subject, $body);
  590. }