You are here

pm_email_notify.module in Privatemsg 7.2

Notifies users about new Private Messages via Email.

File

pm_email_notify/pm_email_notify.module
View source
<?php

/**
 * @file
 * Notifies users about new Private Messages via Email.
 */

/**
 * Disable e-mail notifications.
 */
define('PM_EMAIL_NOTIFY_LEVEL_DISABLED', 0);

/**
 * Enable e-mail notifications only for new threads.
 */
define('PM_EMAIL_NOTIFY_LEVEL_THREAD', 4);

/**
 * Enable e-mail notifications only once until a user visits a threads.
 */
define('PM_EMAIL_NOTIFY_LEVEL_UNREAD_ONCE', 8);

/**
 * Enable e-mail notifications for all messages.
 */
define('PM_EMAIL_NOTIFY_LEVEL_ALL', 12);

/**
 * Enable e-mail notifications and use the global default.
 *
 * A negative value will be ignored by the settings API.
 */
define('PM_EMAIL_NOTIFY_LEVEL_DEFAULT', -1);

/**
 * Implements hook_perm().
 */
function pm_email_notify_permission() {
  return array(
    'set privatemsg e-mail notification level' => array(
      'title' => t('Set Privatemsg E-Mail notification level'),
      'description' => t('Users with this permission may override the default e-mail notification level. Even without this permission, they can still opt-out (but not opt-in if disabled by default) of email notifications.'),
    ),
    'change privatemsg e-mail notification for indirect messages' => array(
      'title' => t('Change privatemsg e-mail notification for indirect messages'),
      'description' => t('Users with this permission may override the default setting.'),
    ),
    'reveal e-mail address when sending messages' => array(
      'title' => t('Allow opt-in to reveal e-mail address when sending messages'),
      'description' => t('Users with this permission may opt-in to reveal their e-mail addresses when sending messages.'),
    ),
  );
}

/**
 * Retrieve notification level of a user.
 *
 * This function retrieves user's pm notification level from database,
 * if user preference doesn't exist - it uses default value instead.
 *
 * @param $uid
 *   User ID.
 *
 * @return
 *   Returns a PM_EMAIL_NOTIFY_LEVEL_* constant indicating the notification
 *   level of the requested user.
 */
function _pm_email_notify_user_level($uid = NULL) {

  // Either check the setting for this user or the global default.
  if ($uid) {
    $keys = array(
      'user' => array(
        $uid,
      ),
      'global' => array(
        0,
      ),
    );
  }
  else {
    $keys = array(
      'global' => array(
        0,
      ),
    );
  }
  return privatemsg_get_setting('email_notify_level', $keys, PM_EMAIL_NOTIFY_LEVEL_ALL);
}

/**
 * Checks if a user should only be notified when addressed directly.
 *
 * @param $uid
 *   User ID.
 *
 * @param
 *   TRUE if notifications should only be sent for directly addressed
 *   recipients.
 *
 * @return bool
 *   The effective setting for this user.
 */
function _pm_email_notify_only_user($uid) {

  // Either check the setting for this user or the global default.
  $keys = array(
    'user' => array(
      $uid,
    ),
    'global' => array(
      0,
    ),
  );
  return privatemsg_get_setting('email_notify_only_user', $keys);
}

/**
 * Checks if a message author wants his email address as a sender.
 *
 * @param $uid
 *   The author's user ID.
 *
 * @return bool
 *   Whether or not to use the author's email address.
 */
function _pm_email_notify_show_sender($uid) {

  // Either check the setting for this user or the global default.
  $keys = array(
    'user' => array(
      $uid,
    ),
    'global' => array(
      0,
    ),
  );
  return privatemsg_get_setting('show_sender_mail', $keys);
}

/**
 * Retrieve notification setting of a user and check if they should receive
 * an e-mail notification for a message.
 *
 * Note: This function tries to return as quickly as possible, to avoid extra
 * processing in batch executions.
 *
 * @param $uid
 *   User uid
 * @param $message
 *   Message.
 *
 * @return bool
 *   Whether or not to notify the user in question.
 */
function _pm_email_notify_send_check($uid, $message) {
  static $notifications = array();
  $mid = $message->mid;
  $thread_id = $message->thread_id;
  $level = _pm_email_notify_user_level($uid);

  // If the user has notifications disabled, we can skip the rest.
  if ($level == PM_EMAIL_NOTIFY_LEVEL_DISABLED) {
    return FALSE;
  }

  // If the user has all notifications enabled, we can skip the rest.
  if ($level == PM_EMAIL_NOTIFY_LEVEL_ALL) {
    return TRUE;
  }

  // Cache the result set in case this method is executed in batched operation
  // which will perform many unnecessary repeated processing.
  if (!isset($notifications[$uid][$mid])) {

    // Prime the setting to false.
    $notifications[$uid][$mid] = FALSE;
    if ($level == PM_EMAIL_NOTIFY_LEVEL_THREAD) {

      // Is this the origin of a thread?
      $notifications[$uid][$mid] = $mid == $thread_id;
    }
    elseif ($level == PM_EMAIL_NOTIFY_LEVEL_UNREAD_ONCE) {

      // If this is the first message of a thread, always send a notification.
      if ($mid == $thread_id) {
        $notifications[$uid][$mid] = TRUE;
      }
      else {

        // Check if this user has more than a single unread message
        // in that thread. If yes, they already got a notification.
        // They always have at least one unread message because they just
        // received one.
        $unread_count = db_query("SELECT COUNT(*) FROM {pm_index} WHERE thread_id = :thread_id AND is_new = 1 AND recipient = :recipient AND type IN ('user', 'hidden')", array(
          ':thread_id' => $thread_id,
          ':recipient' => $uid,
        ))
          ->fetchField();
        $notifications[$uid][$mid] = $unread_count == 1;
      }
    }
  }
  return $notifications[$uid][$mid];
}

/**
 * Implements hook_privatemsg_message_insert().
 */
function pm_email_notify_privatemsg_message_insert($message) {
  foreach ($message->recipients as $recipient) {
    pm_email_notify_send_mail($recipient, $message);
  }
}

/**
 * Implements hook_privatemsg_message_recipient_changed().
 *
 * Notifies users who were added to a message about new Private Messages
 * via Email.
 */
function pm_email_notify_privatemsg_message_recipient_changed($mid, $thread_id, $recipient_id, $type, $added) {
  $types = array(
    'user',
  );

  // Only send mail if the recipient was added.
  if ($added) {
    if ($message = privatemsg_message_load($mid)) {

      // Check if we should send an email to 'hidden' recipients.
      if (!_pm_email_notify_only_user($recipient_id)) {
        $types[] = 'hidden';
      }
      if (in_array($type, $types) && _pm_email_notify_send_check($recipient_id, $message) && ($recipient = user_load($recipient_id))) {
        pm_email_notify_send_mail($recipient, $message);
      }
    }
  }
}

/**
 * Send a pm notification email to a recipient.
 */
function pm_email_notify_send_mail($recipient, $message) {

  // Check if the recipient enabled email notifications.
  if (isset($recipient->uid) && !empty($recipient->mail) && _pm_email_notify_send_check($recipient->uid, $message)) {

    // Send them a new pm notification email if they did.
    $params['recipient'] = $recipient;
    $params['message'] = $message;
    if (_pm_email_notify_show_sender($message->author->uid)) {

      // User author's email as a sender.
      $from = $message->author->mail;
    }
    else {

      // Token replacements for email from address.
      $data = array(
        'privatemsg_message' => $params['message'],
        'privatemsg_recipient' => $params['recipient'],
      );
      $options = array(
        'language' => user_preferred_language($params['recipient']),
        // Don't sanitize output since this is used in an email, not a browser.
        'sanitize' => FALSE,
        // Custom token to avoid custom token handling.
        'privatemsg-display-invalid' => FALSE,
      );
      $from = trim(token_replace(variable_get('pm_email_notify_from', ''), $data, $options));
    }
    drupal_mail('pm_email_notify', 'notice', $recipient->mail, user_preferred_language($recipient), $params, !empty($from) ? $from : NULL);
  }
}

/**
 * Retrieves the default text for body and subject texts.
 *
 * @param $key
 *   Defines with string to return, either subject or body.
 *
 * @return
 *   The default text for the given key.
 */
function _pm_email_notify_source_text($key) {
  $text = variable_get('pm_email_notify_' . $key, FALSE);
  if (empty($text)) {
    switch ($key) {
      case 'subject':
        $text = 'New private message at [site:name].';
        break;
      case 'body':
        $text = "Hi [privatemsg_message:recipient],\n\nThis is an automatic reminder from the site [site:name]. You have received a new private message from [privatemsg_message:author].\n\nTo read your message, follow this link:\n[privatemsg_message:url]\n\nIf you don't want to receive these emails again, change your preferences here:\n[privatemsg_message:recipient:edit-url]";
        break;
    }
  }
  return $text;
}

/**
 * Returns body or subject strings.
 *
 * @param $key
 *   Defines which string to return, either subject or body.
 * @param $language
 *   Optionally define the language to translate into. Defaults to the
 *   active language.
 * @return
 *   The translated text.
 */
function pm_email_notify_text($key, $language = NULL) {
  $text = _pm_email_notify_source_text($key);
  $function = 'i18n_string_translate';
  if (function_exists($function)) {
    $translated = $function('pm_email_notify:mail:mail:' . $key, $text, array(
      'langcode' => isset($language) ? $language->language : NULL,
    ));
    return $translated;
  }
  return $text;
}

/**
 * Implements hook_mail().
 */
function pm_email_notify_mail($key, &$message, $params) {
  switch ($key) {
    case 'notice':
      $data = array(
        'privatemsg_message' => $params['message'],
        'privatemsg_recipient' => $params['recipient'],
      );
      $options = array(
        'language' => user_preferred_language($params['recipient']),
        // Don't sanitize output since this is used in an email, not a browser.
        'sanitize' => FALSE,
        // Custom token to avoid custom token handling.
        'privatemsg-display-invalid' => FALSE,
      );
      $message['subject'] = trim(token_replace(pm_email_notify_text('subject', $options['language']), $data, $options));
      $message['body'][] = trim(token_replace(pm_email_notify_text('body', $options['language']), $data, $options));
      break;
  }
}

/**
 * Implements hook_form_FORM_ID_alter().
 */
function pm_email_notify_form_user_profile_form_alter(&$form, &$form_state) {
  if ($form['#user_category'] == 'account') {
    if (privatemsg_user_access('reveal e-mail address when sending messages')) {
      $form['privatemsg']['pm_show_sender_mail'] = array(
        '#type' => 'checkbox',
        '#title' => t('Show my email address'),
        '#description' => t('Use my private email address as a sender for notification mails to users I have sent private messages to. If unchecked, the notification will be sent by a generic account.'),
        '#default_value' => _pm_email_notify_show_sender($form['#user']->uid),
        '#access' => privatemsg_user_access('reveal e-mail address when sending messages'),
      );
    }
    if (privatemsg_user_access('read privatemsg')) {
      if (privatemsg_user_access('set privatemsg e-mail notification level')) {
        $form['privatemsg']['pm_email_notify_level'] = array(
          '#type' => 'radios',
          '#title' => t('Send me an e-mail notification...'),
          '#options' => array(
            PM_EMAIL_NOTIFY_LEVEL_DISABLED => t('Never.'),
            PM_EMAIL_NOTIFY_LEVEL_THREAD => t('Only for a new conversation'),
            PM_EMAIL_NOTIFY_LEVEL_UNREAD_ONCE => t("Only once for a conversation until I've read the messages"),
            PM_EMAIL_NOTIFY_LEVEL_ALL => t('Every time I receive a message'),
          ),
          '#default_value' => _pm_email_notify_user_level($form['#user']->uid),
        );
      }
      else {

        // If the user does not have permissions to customize the notification
        // level, allow him to opt out of email notifications if they are not
        // disabled by default.
        $is_enabled = _pm_email_notify_user_level();
        $form['privatemsg']['pm_email_notify_level'] = array(
          '#type' => 'checkbox',
          '#title' => t('Receive email notification for incoming private messages'),
          '#return_value' => variable_get('privatemsg_setting_email_notify_level', PM_EMAIL_NOTIFY_LEVEL_ALL),
          '#default_value' => $is_enabled ? _pm_email_notify_user_level($form['#user']->uid) : PM_EMAIL_NOTIFY_LEVEL_DISABLED,
          '#access' => (bool) $is_enabled,
        );
      }
      $form['privatemsg']['pm_email_only_user'] = array(
        '#type' => 'checkbox',
        '#title' => t("Don't send me e-mail notifications for mass messages."),
        '#default_value' => _pm_email_notify_only_user($form['#user']->uid),
        '#access' => privatemsg_user_access('change privatemsg e-mail notification for indirect messages'),
      );
    }
  }
}

/**
 * Implements hook_user_insert().
 */
function pm_email_notify_user_insert(&$edit, $account, $category) {
  pm_email_notify_user_update($edit, $account, $category);
}

/**
 * Implements hook_user_update().
 */
function pm_email_notify_user_update(&$edit, $account, $category) {
  if (isset($edit['pm_email_notify_level'])) {
    privatemsg_set_setting('user', $account->uid, 'email_notify_level', $edit['pm_email_notify_level']);
    unset($edit['pm_email_notify_level']);
  }
  if (isset($edit['pm_email_only_user'])) {
    privatemsg_set_setting('user', $account->uid, 'email_notify_only_user', $edit['pm_email_only_user']);
    unset($edit['pm_email_only_user']);
  }
  if (isset($edit['pm_show_sender_mail'])) {
    privatemsg_set_setting('user', $account->uid, 'show_sender_mail', $edit['pm_show_sender_mail']);
    unset($edit['pm_show_sender_mail']);
  }
}

/**
 * Implements hook_user_delete().
 */
function pm_email_notify_user_delete($account) {
  privatemsg_del_setting('user', $account->uid, 'email_notify_level');
  privatemsg_del_setting('user', $account->uid, 'email_notify_only_user');
  privatemsg_del_setting('user', $account->uid, 'show_sender_mail');
}

/**
 * Implements hook_form_FORM_ID_alter().
 */
function pm_email_notify_form_privatemsg_admin_settings_alter(&$form, &$form_state) {
  $form['pm_email_notify'] = array(
    '#type' => 'fieldset',
    '#title' => t('E-mail notify'),
    '#group' => 'settings',
    '#weight' => 22,
  );
  $form['pm_email_notify']['privatemsg_setting_email_notify_level'] = array(
    '#type' => 'radios',
    '#title' => t('Default e-mail notification level'),
    '#options' => array(
      PM_EMAIL_NOTIFY_LEVEL_DISABLED => t('Never send a notification'),
      PM_EMAIL_NOTIFY_LEVEL_THREAD => t('Only send a notification when a new discussion thread is created'),
      PM_EMAIL_NOTIFY_LEVEL_UNREAD_ONCE => t("Only send a notification when the user has not already received a notification since he last viewed a discussion thread."),
      PM_EMAIL_NOTIFY_LEVEL_ALL => t('Always send a notification'),
    ),
    '#default_value' => variable_get('privatemsg_setting_email_notify_level', PM_EMAIL_NOTIFY_LEVEL_ALL),
    '#description' => t('Choose when e-mail notifications will be sent by the system. Users with the appropriate permission may override this setting on the account edit page.'),
    '#weight' => 0,
  );
  $form['pm_email_notify']['privatemsg_setting_email_notify_only_user'] = array(
    '#type' => 'checkbox',
    '#title' => t('Only send e-mail notifications to individual users who are addressed directly'),
    '#default_value' => variable_get('privatemsg_setting_email_only_user', FALSE),
    '#weight' => 1,
  );
  $form['pm_email_notify']['pm_email_notify_desc'] = array(
    '#type' => 'item',
    '#title' => t('Customize the email messages sent to users upon receipt of a new private message.'),
    '#weight' => 2,
  );
  $form['pm_email_notify']['pm_email_notify_from'] = array(
    '#type' => 'textfield',
    '#title' => t('From e-mail address for notifications'),
    '#default_value' => variable_get('pm_email_notify_from', ''),
    '#weight' => 3,
    '#description' => t('This is the e-mail address that notifications will come from. Leave blank to use the site default.'),
  );
  $form['pm_email_notify']['privatemsg_setting_show_sender_mail'] = array(
    '#type' => 'checkbox',
    '#title' => t("Use sender's email address"),
    '#description' => t("Use the sender's private email address instead of a generic sender for notification mails. This is the site default setting; users may override it individually."),
    '#default_value' => variable_get('privatemsg_setting_show_sender_mail', FALSE),
    '#weight' => 3,
  );
  $form['pm_email_notify']['pm_email_notify_subject'] = array(
    '#type' => 'textfield',
    '#title' => t('Subject of notification messages'),
    '#default_value' => variable_get('pm_email_notify_subject', _pm_email_notify_source_text('subject')),
    '#weight' => 4,
  );
  $form['pm_email_notify']['pm_email_notify_body'] = array(
    '#type' => 'textarea',
    '#title' => t('Body of notification messages'),
    '#default_value' => variable_get('pm_email_notify_body', _pm_email_notify_source_text('body')),
    '#weight' => 5,
  );
  if (module_exists('token')) {
    $form['pm_email_notify']['token'] = array(
      '#type' => 'fieldset',
      '#title' => t('Token browser'),
      '#weight' => -1,
      '#weight' => 6,
    );
    $form['pm_email_notify']['token']['browser'] = array(
      '#theme' => 'token_tree',
      '#token_types' => array(
        'privatemsg_message',
      ),
    );
  }
  else {
    $form['pm_email_notify']['token'] = array(
      '#type' => 'fieldset',
      '#title' => t('Token Suggestions'),
      '#weight' => -1,
      '#collapsible' => TRUE,
      '#collapsed' => TRUE,
      '#weight' => 6,
    );
    $form['pm_email_notify']['token']['suggestions'] = array(
      '#type' => 'item',
      '#markup' => t('Many tokens may be used, including: [privatemsg_message:url], [privatemsg_message:thread-id], [privatemsg_message:author:name], [privatemsg_message:author:uid], [privatemsg_message:recipient:name], [privatemsg_message:subject], [privatemsg_message:body]. Enable the <a href="https://drupal.org/project/token">Token module</a> to see all available.'),
    );
  }
  if (module_exists('i18n_string')) {
    $form['#submit'][] = 'pm_email_notify_admin_settings_update_strings';
  }
}

/**
 * Form submit callback to update the translation string sources.
 */
function pm_email_notify_admin_settings_update_strings($form, &$form_state) {
  i18n_string_update('pm_email_notify:mail:mail:subject', $form_state['values']['pm_email_notify_subject']);
  i18n_string_update('pm_email_notify:mail:mail:body', $form_state['values']['pm_email_notify_body']);
}

/**
 * Implements hook_i18n_string_info().
 */
function pm_email_notify_i18n_string_info() {
  return array(
    'pm_email_notify' => array(
      'title' => t('Privatemsg Email Notification'),
      'format' => FALSE,
      'list' => TRUE,
    ),
  );
}

/**
 * Refresh callback to update the string translation sources.
 */
function pm_email_notify_i18n_string_list($group) {
  if ($group == 'pm_email_notify' || $group == 'all') {
    $strings['pm_email_notify']['mail']['mail']['subject'] = _pm_email_notify_source_text('subject');
    $strings['pm_email_notify']['mail']['mail']['body'] = _pm_email_notify_source_text('body');
    return $strings;
  }
}

Functions

Namesort descending Description
pm_email_notify_admin_settings_update_strings Form submit callback to update the translation string sources.
pm_email_notify_form_privatemsg_admin_settings_alter Implements hook_form_FORM_ID_alter().
pm_email_notify_form_user_profile_form_alter Implements hook_form_FORM_ID_alter().
pm_email_notify_i18n_string_info Implements hook_i18n_string_info().
pm_email_notify_i18n_string_list Refresh callback to update the string translation sources.
pm_email_notify_mail Implements hook_mail().
pm_email_notify_permission Implements hook_perm().
pm_email_notify_privatemsg_message_insert Implements hook_privatemsg_message_insert().
pm_email_notify_privatemsg_message_recipient_changed Implements hook_privatemsg_message_recipient_changed().
pm_email_notify_send_mail Send a pm notification email to a recipient.
pm_email_notify_text Returns body or subject strings.
pm_email_notify_user_delete Implements hook_user_delete().
pm_email_notify_user_insert Implements hook_user_insert().
pm_email_notify_user_update Implements hook_user_update().
_pm_email_notify_only_user Checks if a user should only be notified when addressed directly.
_pm_email_notify_send_check Retrieve notification setting of a user and check if they should receive an e-mail notification for a message.
_pm_email_notify_show_sender Checks if a message author wants his email address as a sender.
_pm_email_notify_source_text Retrieves the default text for body and subject texts.
_pm_email_notify_user_level Retrieve notification level of a user.

Constants

Namesort descending Description
PM_EMAIL_NOTIFY_LEVEL_ALL Enable e-mail notifications for all messages.
PM_EMAIL_NOTIFY_LEVEL_DEFAULT Enable e-mail notifications and use the global default.
PM_EMAIL_NOTIFY_LEVEL_DISABLED Disable e-mail notifications.
PM_EMAIL_NOTIFY_LEVEL_THREAD Enable e-mail notifications only for new threads.
PM_EMAIL_NOTIFY_LEVEL_UNREAD_ONCE Enable e-mail notifications only once until a user visits a threads.