You are here

mass_contact.module in Mass Contact 5.2

This is the main code file for the Mass Contact module. This module enables users to contact multiple users through selected roles.

File

mass_contact.module
View source
<?php

/**
 * @file
 * This is the main code file for the Mass Contact module. This module
 * enables users to contact multiple users through selected roles.
 */

/* ************************************************
 *
 * Functions for implementing various Drupal hooks.
 *
 * ***********************************************/

/**
 * Implementation of hook_help().
 */
function mass_contact_help($section) {
  $output = '';
  switch ($section) {
    case 'admin/help#mass_contact':
      $output .= '<p><b>' . t('Related tasks:') . '</b><br /><ol>' . '<li>' . l('Set Permissions', 'admin/user/access', array(), NULL, 'module-mass_contact') . '</li>' . '<li>' . l('List current categories', 'admin/build/mass_contact') . '</li>' . '<li>' . l('Add new category', 'admin/build/mass_contact/add') . '</li>' . '<li>' . l('Configure the module', 'admin/build/mass_contact/settings') . '</li>' . '<li>' . l('Send mass e-mail', 'mass_contact') . '</li></ol>';
      $output .= '<p>' . t('The Mass Contact module is simply a modified version of the core contact module. It works opposite the latter, in that it allows site moderators (or anyone with permission), to <a href="mass_contact">send mass e-mail</a> to a set role or group of roles or even to all registered users.') . '</p>';
      $output .= '<p>' . t("The sender's own address may be placed in the 'To:' field and all recipients placed in the 'BCC:' field, or the recipients simply placed in the 'To:' field. Note that the latter option leaves all recipients open to abuse due to their e-mail addresses being visible to all other recipients.") . '</p>';
      $output .= '<p>' . t("The e-mail may be sent as HTML or plain text, and may include one or more binary file attachments (if permitted by the sytem administrator).") . '</p>';
      $output .= '<p>' . t("At the option of the sender (if permitted by admin), a node may be created in order to keep a record of the e-mail sent. Do not try to send e-mails by creating nodes; it will not work.") . '</p>';
      $output .= '<p>' . t('Users may opt-out of mass mailings on their profile page, but this may be overridden by the admin (or respected). The entire opt-out system may be disabled on the <a href="@settings-page">settings page</a>.', array(
        '@settings-page' => url('admin/build/mass_contact/settings'),
      )) . '</p>';
      $output .= '<p>' . t('Make sure to add at least one category and configure the module before trying to send mass e-mails.') . '</p>';
      if (!module_exists('menu')) {
        $menu_note = t('The menu item can be customized and configured only once the menu module has been <a href="@modules-page">enabled</a>.', array(
          '@modules-page' => url('admin/build/modules'),
        ));
      }
      else {
        $menu_note = '';
      }
      $output .= '<p>' . t('The Mass Contact module also adds a <a href="@menu-settings">menu item</a> (disabled by default) to the navigation block.', array(
        '@menu-settings' => url('admin/build/menu'),
      )) . ' ' . $menu_note . '</p>';
      return $output;
  }
}

//  End of mass_contact_help().

/**
 * Implementation of hook_perm().
 */
function mass_contact_perm() {
  $permissions = array(
    'administer mass contact',
    'choose whether to archive mass contact messages',
    'create mass_contact content',
    'send mass contact attachments',
    'send mass contact e-mails',
  );
  $result = db_query('SELECT category FROM {mass_contact}');
  while ($category = db_fetch_object($result)) {
    $permissions[] = 'send to users in the ' . $category->category . ' category';
  }
  return $permissions;
}

//  End of mass_contact_perm().

/**
 * Implementation of hook_menu().
 */
function mass_contact_menu($may_cache) {
  $items = array();
  if ($may_cache) {
    $items[] = array(
      'path' => 'admin/build/mass_contact',
      'title' => t('Mass Contact form'),
      'description' => t('Create a mass contact form and set up categories for the form to use.'),
      'callback' => 'mass_contact_admin_categories',
      'access' => user_access('administer mass contact'),
    );
    $items[] = array(
      'path' => 'admin/build/mass_contact/list',
      'title' => t('Category list'),
      'callback' => 'mass_contact_admin_categories',
      'access' => user_access('administer mass contact'),
      'type' => MENU_DEFAULT_LOCAL_TASK,
    );
    $items[] = array(
      'path' => 'admin/build/mass_contact/add',
      'title' => t('Add category'),
      'callback' => 'drupal_get_form',
      'callback arguments' => array(
        'mass_contact_admin_edit',
      ),
      'access' => user_access('administer mass contact'),
      'type' => MENU_LOCAL_TASK,
      'weight' => 1,
    );
    $items[] = array(
      'path' => 'admin/build/mass_contact/edit',
      'title' => t('Edit Mass Contact category'),
      'callback' => 'drupal_get_form',
      'callback arguments' => array(
        'mass_contact_admin_edit',
      ),
      'access' => user_access('administer mass contact'),
      'type' => MENU_CALLBACK,
    );
    $items[] = array(
      'path' => 'admin/build/mass_contact/delete',
      'title' => t('Delete Mass Contact category'),
      'callback' => 'drupal_get_form',
      'callback arguments' => array(
        'mass_contact_admin_delete',
      ),
      'access' => user_access('administer mass contact'),
      'type' => MENU_CALLBACK,
    );
    $items[] = array(
      'path' => 'admin/build/mass_contact/settings',
      'title' => t('Settings'),
      'callback' => 'drupal_get_form',
      'callback arguments' => array(
        'mass_contact_admin_settings',
      ),
      'access' => user_access('administer mass contact'),
      'type' => MENU_LOCAL_TASK,
      'weight' => 2,
    );
    $items[] = array(
      'path' => 'mass_contact',
      'title' => t('Mass Contact'),
      'callback' => 'mass_contact_site_page',
      'access' => user_access('send mass contact e-mails'),
    );
    $items[] = array(
      'path' => 'node/add/mass_contact',
      'title' => t('Mass Contact Message'),
      'access' => user_access('create mass_contact content'),
      'type' => MENU_SUGGESTED_ITEM,
    );
  }
  return $items;
}

//  End of mass_contact_menu().

/**
 * Implementation of hook_nodeapi().
 */
function mass_contact_nodeapi(&$node, $op, $a3 = NULL, $a4 = NULL) {

  // If this is a delete operation and the node type is mass_contact, then
  // check for an attachment and delete the file if one exists.
  if ($op == 'delete' && $node->type == 'mass_contact') {

    // Look for the key phrase in the node body. If it exists, then there is
    // an attachment that needs to be deleted.
    $offset1 = strpos($node->body, '<hr>Attachment:<br />');
    if ($offset1) {

      // Using the saved attachment path, find the file name.
      $file_location = variable_get('mass_contact_attachment_location', file_directory_path() . '/mass_contact_attachments');
      $file_location_start = strpos($node->body, $file_location, $offset1);
      if ($file_location_start) {

        // Get the attachment file name.
        $file_location_end = strpos($node->body, '">', $file_location_start);
        $file_path_name = substr($node->body, $file_location_start, $file_location_end - $file_location_start);
        if (file_exists($file_path_name)) {
          if (!file_delete($file_path_name)) {

            // Log an error.
            watchdog('mass_contact', t('There was an error deleting the attachment.'), WATCHDOG_ERROR);
          }
        }
        else {

          // Log an error.
          watchdog('mass_contact', t('There was an indication of an attachment within the node body, but the attachment was not found. If the attachment is still there, it was NOT deleted.'), WATCHDOG_WARNING);
        }
      }
      else {

        // Log an error.
        watchdog('mass_contact', t('There was an indication of an attachment within the node body, but the attachment path was not found. If the attachment is still there, it was NOT deleted.'), WATCHDOG_WARNING);
      }
    }
  }
}

//  End of mass_contact_nodeapi().

/**
 * Implementation of hook_user().
 */
function mass_contact_user($type, $edit, &$user, $category = NULL) {
  if ($type == 'form' && $category == 'account') {
    if (variable_get('mass_contact_optout_d', 0) == 1) {
      $form['mail'] = array(
        '#type' => 'fieldset',
        '#title' => t('Mass contact settings'),
        '#weight' => 5,
        '#collapsible' => TRUE,
      );
      $form['mail']['mass_contact_optout'] = array(
        '#type' => 'checkbox',
        '#title' => t('Opt-out of mass e-mails'),
        '#default_value' => $edit['mass_contact_optout'],
        '#description' => variable_get('mass_contact_optout_message', t('Allows you to opt-out of receiving mass e-mails from privileged users. Note that site administrators are able to include you in mass e-mails even if you choose not to enable this feature, and the ability to opt-out may be removed by the administrator at any time.')),
      );
      return $form;
    }
    elseif (variable_get('mass_contact_optout_d', 0) == 2) {

      // Initialize the variables we're going to use.
      $users_roles = array();
      $user_role = 0;
      $included_categories = array();

      // Get all the roles this user is a memeber of.
      $user_roles = db_query('SELECT rid FROM {users_roles} WHERE uid = %d', $user->uid);

      // Start with the 'authenticated user' role, as it's not in the database.
      $users_roles[] = 2;

      // Put them into an array for later reference.
      while ($user_role = db_fetch_array($user_roles)) {
        $users_roles[] = $user_role;
      }

      // Get all Mass Contact categories.
      $categories = db_query('SELECT cid, category, recipients FROM {mass_contact}');

      // Iterate through each category.
      while ($category = db_fetch_object($categories)) {

        // Pull out the roles that are a part of this category.
        foreach (explode(',', $category->recipients) as $role_id) {

          // If the category's role is one the user is part of, show the category.
          if (in_array($role_id, $users_roles)) {
            $included_categories[$category->cid] = $category->category;
          }
        }
      }
      if ($included_categories) {
        $form['mail'] = array(
          '#type' => 'fieldset',
          '#title' => t('Mass contact settings'),
          '#weight' => 5,
          '#collapsible' => TRUE,
          '#description' => variable_get('mass_contact_optout_message', t('Allows you to opt-out of receiving mass e-mails from privileged users. Note that site administrators are able to include you in mass e-mails even if you choose not to enable this feature, and the ability to opt-out may be removed by the administrator at any time.')),
        );
        foreach ($included_categories as $category_cid => $category_category) {

          // If the category's role is one the user is part of, show the category.
          $form['mail']['mass_contact_optout_' . $category_cid] = array(
            '#type' => 'checkbox',
            '#title' => t('Opt-out of mass e-mails to the %category category.', array(
              '%category' => $category_category,
            )),
            '#default_value' => $edit['mass_contact_optout_' . $category_cid],
          );
        }
      }
      return $form;
    }
  }
  elseif ($type == 'validate') {
    return array(
      'mass_contact_optout' => $edit['mass_contact_optout'],
    );
  }
}

//  End of mass_contact_user().

/* **************************************************************
 *
 * Functions for listing, adding/editing and deleting categories.
 *
 * *************************************************************/

/**
 * Displays a list of all existing categories.
 *
 * @return
 *   The themed page listing all current categories.
 */
function mass_contact_admin_categories() {
  $result = db_query('SELECT cid, category, recipients, selected FROM {mass_contact}');
  $rows = array();
  while ($category = db_fetch_object($result)) {
    $rolenamesa = array();
    foreach (explode(',', $category->recipients) as $rid) {
      $namerole = db_fetch_object(db_query('SELECT name FROM {role} WHERE rid = %d', $rid));
      $rolenamesa[] = $namerole->name;
    }
    $rolenames = implode(', ', $rolenamesa);
    $rows[] = array(
      $category->category,
      $rolenames,
      $category->selected ? t('Yes') : t('No'),
      l(t('edit'), 'admin/build/mass_contact/edit/' . $category->cid),
      l(t('delete'), 'admin/build/mass_contact/delete/' . $category->cid),
    );
  }
  $header = array(
    t('Category'),
    t('Recipients'),
    t('Selected'),
    array(
      'data' => t('Operations'),
      'colspan' => 2,
    ),
  );
  return theme('table', $header, $rows);
}

//  End of mass_contact_admin_categories().

/**
 * Displays a form to add or edit a category.
 *
 * @param cid
 *   The id of the category to edit. If NULL, then add rather than edit.
 *
 * @return
 *   An associative array that defines the form to be built.
 */
function mass_contact_admin_edit($cid = NULL) {
  $edit = array(
    'category' => '',
    'recipients' => '',
    'selected' => '',
    'cid' => '',
  );
  if (arg(3) == "edit" && $cid > 0) {
    $edit = db_fetch_array(db_query("SELECT * FROM {mass_contact} WHERE cid = %d", $cid));
  }
  $form['category'] = array(
    '#type' => 'textfield',
    '#title' => t('Category'),
    '#maxlength' => 255,
    '#default_value' => $edit['category'],
    '#description' => t("Will appear in the subject of your e-mail as [category]."),
    '#required' => TRUE,
  );

  // get all roles except anonymous
  $allroles = db_query('SELECT rid, name FROM {role} WHERE rid > 1');
  while ($roleobj = db_fetch_object($allroles)) {
    $onerid = $roleobj->rid;
    $onename = $roleobj->name;
    $rolesarray[$onerid] = $onename;
  }
  $form['recipients'] = array(
    '#type' => 'checkboxes',
    '#title' => t('Roles to receive e-mail'),
    '#options' => $rolesarray,
    '#default_value' => explode(',', $edit['recipients']),
    '#description' => t('These roles will be added to the mailing list. Note: if you check "authenticated users", other roles will not be added, as they will receive the e-mail anyway.'),
  );
  $form['selected_categories'] = array(
    '#type' => 'fieldset',
    '#title' => t('Selected categories'),
  );
  $form['selected_categories']['selected'] = array(
    '#type' => 'select',
    '#title' => t('Selected'),
    '#options' => array(
      '0' => t('No'),
      '1' => t('Yes'),
    ),
    '#default_value' => $edit['selected'],
    '#description' => t('Set this to <em>Yes</em> if you would like this category to be selected by default.'),
  );
  $form['selected_categories']['reset_selected'] = array(
    '#type' => 'checkbox',
    '#title' => t('Reset all previously selected categories to <em>No</em>.'),
  );
  $form['cid'] = array(
    '#type' => 'value',
    '#value' => $edit['cid'],
  );
  $form['submit'] = array(
    '#type' => 'submit',
    '#value' => t('Submit'),
  );
  return $form;
}

//  End of mass_contact_admin_edit().

/**
 * Validates the submission of the category add/edit page.
 *
 * @param form_id
 *   The unique string identifying the form.
 * @param form_values
 *   The array of values returned by the form.
 */
function mass_contact_admin_edit_validate($form_id, $form_values) {
  $recipients = $form_values['recipients'];
  foreach ($recipients as $checkr) {
    if ($checkr > 1) {
      return;
    }
  }
  form_set_error('recipients', t('You must check one or more recipients.'));
}

//  End of mass_contact_admin_edit_validate().

/**
 * Processes the adding or editing of a category.
 *
 * @param form_id
 *   The unique string identifying the form.
 * @param form_values
 *   The array of values returned by the form.
 */
function mass_contact_admin_edit_submit($form_id, $form_values) {
  if ($form_values['reset_selected']) {

    // Unselect all other contact categories.
    db_query('UPDATE {mass_contact} SET selected = 0');
  }

  // Remove 0s for unselected roles, convert to csv.
  $recipients = $form_values['recipients'];

  // If all authenticated users are already added, remove all roles.
  if ($recipients[2] == 2) {
    foreach ($recipients as $checkr) {
      if ($checkr > 2) {
        $recipients[$checkr] = 0;
      }
    }
  }

  // Remove roles that were not selected.
  foreach ($recipients as $recip) {
    if ($recip != 0) {
      $newformrec[] = $recip;
    }
  }
  $form_values['recipients'] = implode(',', $newformrec);
  if (arg(3) == 'add') {
    db_query("INSERT INTO {mass_contact} (category, recipients, reply, weight, selected) VALUES ('%s', '%s', '%s', %d, %d)", $form_values['category'], $form_values['recipients'], $form_values['reply'], $form_values['weight'], $form_values['selected']);
    drupal_set_message(t('Category %category has been added.', array(
      '%category' => $form_values['category'],
    )));
    watchdog('mass_contact', t('Mass Contact form: category %category added.', array(
      '%category' => $form_values['category'],
    )), WATCHDOG_NOTICE, l(t('view'), 'admin/build/mass_contact'));
  }
  else {
    db_query("UPDATE {mass_contact} SET category = '%s', recipients = '%s', reply = '%s', weight = %d, selected = %d WHERE cid = %d", $form_values['category'], $form_values['recipients'], $form_values['reply'], $form_values['weight'], $form_values['selected'], $form_values['cid']);
    drupal_set_message(t('Category %category has been updated.', array(
      '%category' => $form_values['category'],
    )));
    watchdog('mass_contact', t('Mass Contact form: category %category updated.', array(
      '%category' => $form_values['category'],
    )), WATCHDOG_NOTICE, l(t('view'), 'admin/build/mass_contact'));
  }
  return 'admin/build/mass_contact';
}

//  End of mass_contact_admin_edit_submit().

/**
 * Displays a form to select a category to delete.
 *
 * @param cid
 *   The id of the category to delete.
 *
 * @return
 *   A confirmation form for the user to acknowledge.
 */
function mass_contact_admin_delete($cid = NULL) {
  $info = db_fetch_object(db_query("SELECT category FROM {mass_contact} WHERE cid = %d", $cid));
  if ($info) {
    $form['category'] = array(
      '#type' => 'value',
      '#value' => $info->category,
    );
    return confirm_form($form, t('Are you sure you want to delete %category?', array(
      '%category' => $info->category,
    )), 'admin/build/mass_contact', t('This action cannot be undone.'), t('Delete'), t('Cancel'));
  }
  else {
    drupal_set_message(t('Category not found.'), 'error');
    drupal_goto('admin/build/mass_contact');
  }
}

//  End of mass_contact_admin_delete().

/**
 * Does the actual deleting of the category.
 *
 * @param form_id
 *   The unique string identifying the form.
 * @param form_values
 *   The array of values returned by the form.
 */
function mass_contact_admin_delete_submit($form_id, $form_values) {
  db_query("DELETE FROM {mass_contact} WHERE cid = %d", arg(4));
  drupal_set_message(t('Category %category has been deleted.', array(
    '%category' => $form_values['category'],
  )));
  watchdog('mass_contact', t('Mass Contact form: category %category deleted.', array(
    '%category' => $form_values['category'],
  )), WATCHDOG_NOTICE);
  return 'admin/build/mass_contact';
}

//  End of mass_contact_admin_delete_submit().

/* ***********************************************
 *
 * Functions for handling administrative settings.
 *
 * **********************************************/

/**
 * Administration settings form.
 *
 * @return
 *   An associative array that defines the form to be built.
 */
function mass_contact_admin_settings() {
  $form['mass_contact_form_information'] = array(
    '#type' => 'textarea',
    '#title' => t('Additional information for Mass Contact form'),
    '#default_value' => variable_get('mass_contact_form_information', t('Send e-mails using the following form.')),
    '#description' => t('Information to show on the <a href="@form">Mass Contact page</a>.', array(
      '@form' => url('mass_contact'),
    )),
  );
  $form['mass_contact_character_set'] = array(
    '#type' => 'textfield',
    '#title' => t('Character set'),
    '#default_value' => variable_get('mass_contact_character_set', ''),
    '#description' => t('You may specify an alternate character set to use when sending e-mails. If left blank, the default of UTF-8 will be used. If you are unsure of what to put here, then leave it blank. Caution: setting this may not get you the results you desire. Other modules may come along and change that value after it has been set by this module.'),
  );
  $form['mass_contact_default_sender'] = array(
    '#type' => 'fieldset',
    '#title' => t('Default sender information'),
    '#description' => t('If anything is specified in here, it is used in place of the "Your name" and "Your e-mail address" fileds when sending the mass e-mail. Otherwise, the sender\'s name and e-mail address will be the default values. You must fill in both values, if you want to specify a default.'),
  );
  $form['mass_contact_default_sender']['mass_contact_default_sender_name'] = array(
    '#type' => 'textfield',
    '#title' => t('Default sender name'),
    '#default_value' => variable_get('mass_contact_default_sender_name', ''),
    '#size' => 60,
    '#maxlength' => 128,
    '#description' => t('The optional user name to send e-mail as. Replaces the "Your name" value when sending mass e-mails.'),
  );
  $form['mass_contact_default_sender']['mass_contact_default_sender_email'] = array(
    '#type' => 'textfield',
    '#title' => t('Default sender e-mail address'),
    '#default_value' => variable_get('mass_contact_default_sender_email', ''),
    '#size' => 60,
    '#maxlength' => 128,
    '#description' => t('The optional user e-mail address to send e-mail as. Replaces the "Your e-mail address" value when sending mass e-mails.'),
  );
  $form['mass_contact_default_sender']['mass_contact_default_sender_changable'] = array(
    '#type' => 'checkbox',
    '#title' => t('Allow the sender to change these values.'),
    '#default_value' => variable_get('mass_contact_default_sender_changable', 0),
    '#description' => t('If checked, gives the sender the ability of changing the default sender and e-mail address when creating the message. If unchecked, the fields will be disabled.'),
  );
  $form['mass_contact_recipient_limit'] = array(
    '#type' => 'textfield',
    '#title' => t('Maximum number of recipients before splitting up the e-mail'),
    '#size' => 10,
    '#default_value' => variable_get('mass_contact_recipient_limit', 0),
    '#description' => t('This is a workaround for server-side limits on the number of recipients in a single mail message. Once this limit is reached, the recipient list will be broken up and multiple copies of the message will be sent out until all recipients receive the mail. Setting this to "0" will turn off this feature.'),
    '#required' => TRUE,
  );
  $form['mass_contact_optout_d'] = array(
    '#type' => 'radios',
    '#title' => t('Allow users to opt-out of mass e-mails.'),
    '#default_value' => variable_get('mass_contact_optout_d', 0),
    '#options' => array(
      0 => 'No',
      1 => 'Yes',
      2 => 'Selected categories',
    ),
    '#description' => t("Allow users to opt-out of receiving mass e-mails. If 'No' is chosen, then the site's users will not be able to opt-out of receiving mass e-mails. If 'Yes' is chosen, then the site's users will be able to opt-out of receiving mass e-mails, and they will not receive any from any category. If 'Selected categories' is chosen, then the site's users will be able to opt-out of receiving mass e-mails from which ever categories they choose."),
  );
  $form['mass_contact_optout_message'] = array(
    '#type' => 'textarea',
    '#title' => t('The message to display to users when giving them the option to opt out'),
    '#default_value' => variable_get('mass_contact_optout_message', t('Allows you to opt-out of receiving mass e-mails from privileged users. Note that site administrators are able to include you in mass e-mails even if you choose not to enable this feature, and the ability to opt-out may be removed by the administrator at any time.')),
    '#description' => t('This is the message users will see in thier account settings page when they are presented with a list of categories to opt out of.'),
  );
  $form['mass_contact_bcc_d'] = array(
    '#type' => 'checkbox',
    '#title' => t('Send as BCC (hide recipients) by default.'),
    '#default_value' => variable_get('mass_contact_bcc_d', 1),
  );
  $form['mass_contact_bcc_d_override'] = array(
    '#type' => 'checkbox',
    '#title' => t('Allow sender to override BCC setting.'),
    '#default_value' => variable_get('mass_contact_bcc_d_override', 1),
  );
  $form['mass_contact_category_override'] = array(
    '#type' => 'checkbox',
    '#title' => t('Include category in subject line.'),
    '#default_value' => variable_get('mass_contact_category_override', 1),
  );
  $form['mass_contact_supplemental_texts'] = array(
    '#type' => 'fieldset',
    '#title' => t('Supplemental message body texts'),
    '#description' => t('You may specify additional text to insert before and/or after the message text of every mass e-mail that is sent.'),
  );
  if (module_exists('token')) {
    $form['mass_contact_supplemental_texts']['mass_contact_message_prefix'] = array(
      '#type' => 'textarea',
      '#title' => t('Text to be prepended to all messages'),
      '#default_value' => variable_get('mass_contact_message_prefix', t('[user-name] has sent you a mass e-mail from [site-name].')),
      '#description' => t('The text you specify above will be added to all e-mails sent out. The text will be placed before the message text entered in by the sender.'),
    );
    $form['mass_contact_supplemental_texts']['mass_contact_message_suffix'] = array(
      '#type' => 'textarea',
      '#title' => t('Text to be appended to all messages'),
      '#default_value' => variable_get('mass_contact_message_suffix', t('')),
      '#description' => t('The text you specify above will be added to all e-mails sent out. The text will be placed after the message text entered in by the sender.'),
    );
    $form['mass_contact_supplemental_texts']['mass_contact_replacement_tokens'] = array(
      '#type' => 'fieldset',
      '#title' => t('Replacement tokens'),
      '#collapsible' => TRUE,
      '#collapsed' => TRUE,
      '#description' => t('You may use any of the following replacements tokens for use in the prefix and/or suffix texts above.'),
    );
    $form['mass_contact_supplemental_texts']['mass_contact_replacement_tokens']['token_help'] = array(
      '#value' => theme('token_help', 'global'),
    );
  }
  else {
    $form['mass_contact_supplemental_texts']['mass_contact_message_prefix'] = array(
      '#type' => 'textarea',
      '#title' => t('Text to be prepended to all messages'),
      '#default_value' => variable_get('mass_contact_message_prefix', t('You were sent a mass e-mail from !site.', array(
        '!site' => url(NULL, NULL, NULL, TRUE),
      ))),
      '#description' => t('The text you specify above will be added to all e-mails sent out. The text will be placed before the message text entered in by the sender.'),
    );
    $form['mass_contact_supplemental_texts']['mass_contact_message_suffix'] = array(
      '#type' => 'textarea',
      '#title' => t('Text to be appended to all messages'),
      '#default_value' => variable_get('mass_contact_message_suffix', t('')),
      '#description' => t('The text you specify above will be added to all e-mails sent out. The text will be placed after the message text entered in by the sender.'),
    );
  }
  $form['mass_contact_html_d'] = array(
    '#type' => 'checkbox',
    '#title' => t('Send as HTML by default.'),
    '#default_value' => variable_get('mass_contact_html_d', 1),
    '#description' => t('This will use the default input filter as specified on the <a href="@formats_settings">Input formats settings</a> page.', array(
      '@formats_settings' => url('admin/settings/filters'),
    )),
  );
  $form['mass_contact_html_d_override'] = array(
    '#type' => 'checkbox',
    '#title' => t('Allow sender to override HTML setting.'),
    '#default_value' => variable_get('mass_contact_html_d_override', 1),
  );
  $form['mass_contact_number_of_attachments'] = array(
    '#type' => 'textfield',
    '#title' => t('Number of attachments'),
    '#default_value' => variable_get('mass_contact_number_of_attachments', '3'),
    '#size' => 10,
    '#description' => t("The number of attachments to allow on the contact form. The maximum number of allowed uploads may be limited by PHP. If necessary, check your system's PHP php.ini file for a max_file_uploads directive to change."),
  );
  $form['mass_contact_attachment_location'] = array(
    '#type' => 'textfield',
    '#title' => t('Attachment location'),
    '#default_value' => variable_get('mass_contact_attachment_location', file_directory_path() . '/mass_contact_attachments'),
    '#description' => t('If a copy of the message is saved as a node, this is the file path where to save the attachment so it can be viewed later.'),
  );
  $form['mass_contact_nodecc_d'] = array(
    '#type' => 'checkbox',
    '#title' => t('Save a copy as a node by default.'),
    '#default_value' => variable_get('mass_contact_nodecc_d', 1),
  );
  $form['mass_contact_nodecc_d_override'] = array(
    '#type' => 'checkbox',
    '#title' => t('Allow sender to override node copy setting.'),
    '#default_value' => variable_get('mass_contact_nodecc_d_override', 1),
  );
  $form['mass_contact_hourly_threshold'] = array(
    '#type' => 'select',
    '#title' => t('Hourly threshold'),
    '#options' => drupal_map_assoc(array(
      1,
      2,
      3,
      4,
      5,
      6,
      7,
      8,
      9,
      10,
      15,
      20,
      25,
      30,
      40,
      50,
      75,
      100,
    )),
    '#default_value' => variable_get('mass_contact_hourly_threshold', 3),
    '#description' => t('The maximum number of Mass Contact form submissions a user can perform per hour.'),
  );
  return system_settings_form($form);
}

//  End of mass_contact_admin_settings().

/**
 * Validates the administration settings form.
 *
 * @param form_id
 *   The unique string identifying the form.
 * @param form_values
 *   The array of values returned by the form.
 */
function mass_contact_admin_settings_validate($form_id, $form_values) {
  if (!empty($form_values['mass_contact_default_sender_name'])) {
    if (empty($form_values['mass_contact_default_sender_email'])) {
      form_set_error('mass_contact_default_sender_email', t('If you are going to specify default user settings, you must specify both a user name and a user e-mail address.'));
    }
  }
  if (!empty($form_values['mass_contact_default_sender_email'])) {
    if (empty($form_values['mass_contact_default_sender_name'])) {
      form_set_error('mass_contact_default_sender_name', t('If you are going to specify default user settings, you must specify both a user name and a user e-mail address.'));
    }
  }
}

//  End of mass_contact_admin_settings_validate().

/* ********************************
 *
 * Functions for sending a message.
 *
 * *******************************/

/**
 * The mail page
 *
 * @return
 *   Either an error, if flood control is active and triggered, or a
 *   rendered form.
 */
function mass_contact_site_page() {
  global $user;
  if (!user_access('administer mass contact') && !flood_is_allowed('mass_contact', variable_get('mass_contact_hourly_threshold', 3))) {
    $output = t("You cannot send more than %number messages per hour. Please try again later.", array(
      '%number' => variable_get('mass_contact_hourly_threshold', 3),
    ));
  }
  else {
    $output = drupal_get_form('mass_contact_mail_page');
  }
  return $output;
}

//  End of mass_contact_site_page().

/**
 * Generates the main Mass Contact mail form.
 *
 * @return
 *   An associative array that defines the form to be built.
 */
function mass_contact_mail_page() {
  global $user;
  $categories = array();
  $default_category = array();
  $default_category_name = '';
  $result = db_query('SELECT cid, category, selected FROM {mass_contact} ORDER BY weight, category');
  while ($category = db_fetch_object($result)) {
    if (user_access('send to users in the ' . $category->category . ' category')) {
      $categories[$category->cid] = $category->category;
      if ($category->selected) {
        $default_category[] = $category->cid;
        $default_category_name = $category->category;
      }
    }
  }
  if (count($categories) == 1) {
    $default_category = array_keys($categories);
    $default_category_name = $categories[$default_category[0]];
  }
  if (count($categories) > 0) {
    $form['#attributes'] = array(
      'enctype' => "multipart/form-data",
    );
    $form['#token'] = $user->name . $user->mail;
    $form['contact_information'] = array(
      '#value' => filter_xss_admin(variable_get('mass_contact_form_information', t('Send an e-mail message using the contact form below.'))),
    );
    $mass_contact_default_sender_name = variable_get('mass_contact_default_sender_name', '');
    if ($mass_contact_default_sender_name) {
      $form['name'] = array(
        '#type' => 'textfield',
        '#title' => t('Your name'),
        '#maxlength' => 255,
        '#default_value' => $mass_contact_default_sender_name,
        '#disabled' => !variable_get('mass_contact_default_sender_changable', 0),
      );
    }
    else {
      $form['name'] = array(
        '#type' => 'textfield',
        '#title' => t('Your name'),
        '#maxlength' => 255,
        '#default_value' => $user->uid ? $user->name : '',
        '#required' => TRUE,
      );
    }
    $mass_contact_default_sender_email = variable_get('mass_contact_default_sender_email', '');
    if ($mass_contact_default_sender_email) {
      $form['mail'] = array(
        '#type' => 'textfield',
        '#title' => t('Your e-mail address'),
        '#maxlength' => 255,
        '#default_value' => $mass_contact_default_sender_email,
        '#disabled' => !variable_get('mass_contact_default_sender_changable', 0),
      );
    }
    else {
      $form['mail'] = array(
        '#type' => 'textfield',
        '#title' => t('Your e-mail address'),
        '#maxlength' => 255,
        '#default_value' => $user->uid ? $user->mail : '',
        '#required' => TRUE,
      );
    }
    if (count($categories) > 1 || !isset($default_category)) {

      // Display a choice when one is needed.
      $form['cid'] = array(
        '#type' => 'select',
        '#title' => t('Category'),
        '#default_value' => $default_category,
        '#options' => $categories,
        '#required' => TRUE,
        '#multiple' => TRUE,
      );
    }
    else {

      // Otherwise, just use the default category.
      $form['cid'] = array(
        '#type' => 'value',
        '#value' => $default_category,
      );
      $form['cid-info'] = array(
        '#type' => 'markup',
        '#value' => '<p>Sending to all users subscribed to the ' . $default_category_name . ' category.</p>',
      );
    }
    $optout_setting = variable_get('mass_contact_optout_d', 0);
    if ($optout_setting == 1 || $optout_setting == 2) {

      // Allow to override or respect opt-outs if admin, otherwise use default.
      if (user_access('administer mass contact')) {
        $form['optout'] = array(
          '#type' => 'checkbox',
          '#title' => t('Respect user opt-outs.'),
          '#default_value' => 1,
        );
      }
      else {
        $form['optout'] = array(
          '#type' => 'hidden',
          '#default_value' => 1,
        );
      }
    }

    // Check if the user can override the BCC setting.
    if (variable_get('mass_contact_bcc_d_override', 1)) {
      $form['bcc'] = array(
        '#type' => 'checkbox',
        '#title' => t('Send as BCC (hide recipients).'),
        '#default_value' => variable_get('mass_contact_bcc_d', 1),
      );
    }
    else {
      $form['bcc'] = array(
        '#type' => 'value',
        '#value' => variable_get('mass_contact_bcc_d', 1),
      );
      $form['bcc-info'] = array(
        '#type' => 'markup',
        '#value' => '<p>' . (variable_get('mass_contact_bcc_d', 1) ? t('Recipients will be hidden.') : t('Recipients will NOT be hidden.')) . '</p>',
      );
    }
    $form['subject'] = array(
      '#type' => 'textfield',
      '#title' => t('Subject'),
      '#maxlength' => 255,
      '#required' => TRUE,
    );
    $form['body_filter']['message'] = array(
      '#type' => 'textarea',
      '#title' => t('Message'),
      '#rows' => 12,
      '#required' => TRUE,
    );
    $form['body_filter']['format'] = filter_form(FILTER_FORMAT_DEFAULT);

    // Check if the user can override the HTML setting.
    if (variable_get('mass_contact_html_d_override', 1)) {
      $form['html'] = array(
        '#type' => 'checkbox',
        '#title' => t('Send as HTML.'),
        '#default_value' => variable_get('mass_contact_html_d', 1),
        '#description' => t('This will use the settings for the default input filter. More information about what is available is on the <a href="@formats_settings">Input formats</a> page.', array(
          '@formats_settings' => url('filter/tips'),
        )),
      );
    }
    else {
      $form['html'] = array(
        '#type' => 'value',
        '#value' => variable_get('mass_contact_html_d', 1),
      );
      $form['html-info'] = array(
        '#type' => 'markup',
        '#value' => '<p>' . (variable_get('mass_contact_html_d', 1) ? t('The message will be sent as HTML.') : t('The message will be sent as plain text.')) . '</p>',
      );
    }

    // Show the attachment fields, if allowed.
    if (user_access('send mass contact attachments')) {
      for ($i = 1; $i <= variable_get('mass_contact_number_of_attachments', '3'); $i++) {
        $form['attachment_' . $i] = array(
          '#type' => 'file',
          '#title' => t('Attachment #!number', array(
            '!number' => $i,
          )),
        );
      }
    }

    // We do not allow anonymous users to send themselves a copy because it
    // can be abused to spam people.
    if ($user->uid) {
      $form['copy'] = array(
        '#type' => 'checkbox',
        '#title' => t('Send yourself a copy.'),
      );
    }
    if (user_access('choose whether to archive mass contact messages')) {

      // Check if the user can override the node copy setting.
      if (variable_get('mass_contact_nodecc_d_override', 1)) {
        $form['nodecc'] = array(
          '#type' => 'checkbox',
          '#title' => t('Save a copy as a node.'),
          '#default_value' => variable_get('mass_contact_nodecc_d', 1),
        );
      }
      else {
        $form['nodecc'] = array(
          '#type' => 'hidden',
          '#default_value' => variable_get('mass_contact_nodecc_d', 1),
        );
      }
    }
    else {
      $form['nodecc'] = array(
        '#type' => 'hidden',
        '#default_value' => variable_get('mass_contact_nodecc_d', 1),
      );
    }

    /*
       // Place holder for future use.
       $form['preview'] = array(
         '#type' => 'button',
         '#value' => t('Preview')
       );
    */
    $form['submit'] = array(
      '#type' => 'submit',
      '#value' => t('Send e-mail'),
    );
  }
  else {
    $form['error'] = array(
      '#value' => '<p><b>' . t('Either you have not created any categories, or you are not allowed to send to any of the existing categories.') . '<br /><br />' . t('Either create at least one category of users to send to, or contact your system administer for access to the existing categories.') . '</b>',
    );
  }
  if (user_access('administer mass contact')) {
    $form['tasklist'] = array(
      '#type' => 'fieldset',
      '#title' => t('Related tasks'),
      '#collapsible' => TRUE,
      '#collapsed' => FALSE,
      '#prefix' => '<p>',
    );
    $form['tasklist']['list'] = array(
      '#value' => '<p><ol>' . '<li>' . l('Set Permissions', 'admin/user/access', array(), NULL, 'module-mass_contact') . '</li>' . '<li>' . l('List current categories', 'admin/build/mass_contact') . '</li>' . '<li>' . l('Add new category', 'admin/build/mass_contact/add') . '</li>' . '<li>' . l('Configure the module', 'admin/build/mass_contact/settings') . '</li>' . '<li>' . l('Help', 'admin/help/mass_contact') . '</li></ol>',
    );
  }
  return $form;
}

//  End of mass_contact_mail_page().

/**
 * Validates the main Mass Contact mail form.
 *
 * @param form_id
 *   The unique string identifying the form.
 * @param form_values
 *   The array of values returned by the form.
 */
function mass_contact_mail_page_validate($form_id, $form_values) {
  if (!$form_values['cid']) {
    form_set_error('category', t('You must select a valid category.'));
  }
  if (!valid_email_address($form_values['mail'])) {
    form_set_error('mass_contact', t('You must enter a valid e-mail address.'));
  }
  _mass_contact_upload_validate($form_id, $form_values);
}

//  End of mass_contact_mail_page_validate().

/**
 * Processes the main Mass Contact mail form.
 *
 * @param form_id
 *   The unique string identifying the form.
 * @param form_values
 *   The array of values returned by the form.
 */
function mass_contact_mail_page_submit($form_id, $form_values) {
  $headers = array();
  $character_set = variable_get('mass_contact_character_set', '') ? variable_get('mass_contact_character_set', '') : 'UTF-8';
  $bcc = $form_values['bcc'];
  $nodecc = $form_values['nodecc'];
  $from = $form_values['mail'];
  $body_plain = '';
  $boundary_html = md5(uniqid(mt_rand()));
  $body_html = '';
  $message = '';
  $has_attachments = FALSE;
  $boundary_attachment = md5(uniqid(mt_rand()));
  $message_attachments = array();
  $send_error = 0;

  // Check for the exsistance of attachments.
  for ($i = 1; $i <= variable_get('mass_contact_number_of_attachments', '3'); $i++) {
    if ($_FILES['files']['size']['attachment_' . $i] > 0) {
      $has_attachments = TRUE;
      break;
    }
  }

  // Set the "Content-Type" header based on the presence or absence of an
  // attachment and the HTML setting.
  if ($has_attachments) {
    $headers['Content-Type'] = 'multipart/mixed; boundary="' . $boundary_attachment . '"';
  }
  elseif ($form_values['html']) {
    $headers['Content-Type'] = 'multipart/alternative; boundary="' . $boundary_html . '"';
  }
  else {
    $headers['Content-Type'] = 'text/plain; charset=' . $character_set . '; format=flowed';
  }

  // Create the body part(s) of the message.
  // Create the plain text body. We now always create a plain text body.
  if ($form_values['html']) {

    // If this is supposed to be an HTML e-mail, we need to process the plain
    // text part differently.
    // Make this process better, by utilizing existing modules. This will
    // become the norm, eliminating the need for the module check.
    if (module_exists('html_to_text')) {

      // Start with the message prefix.
      if (variable_get('mass_contact_message_prefix', '')) {
        if (module_exists('token')) {
          $body_plain .= drupal_html_to_text(check_markup(token_replace(variable_get('mass_contact_message_prefix', '')), $form_values['format'])) . "\n";
        }
        else {
          $body_plain .= drupal_html_to_text(check_markup(variable_get('mass_contact_message_prefix', ''), $form_values['format'])) . "\n";
        }
      }

      // Add in the actual message.
      $body_plain .= drupal_html_to_text(check_markup($form_values['message'], $form_values['format'])) . "\n";

      // End with the message suffix.
      if (variable_get('mass_contact_message_suffix', '')) {
        if (module_exists('token')) {
          $body_plain .= drupal_html_to_text(check_markup(token_replace(variable_get('mass_contact_message_suffix', '')), $form_values['format']));
        }
        else {
          $body_plain .= drupal_html_to_text(check_markup(variable_get('mass_contact_message_suffix', ''), $form_values['format']));
        }
      }
    }
    else {

      // Start with the message prefix.
      if (variable_get('mass_contact_message_prefix', '')) {
        if (module_exists('token')) {
          $body_plain .= wordwrap(strip_tags(check_markup(token_replace(variable_get('mass_contact_message_prefix', '')), $form_values['format']))) . "\n";
        }
        else {
          $body_plain .= wordwrap(strip_tags(check_markup(variable_get('mass_contact_message_prefix', ''), $form_values['format']))) . "\n";
        }
      }

      // Add in the actual message.
      $body_plain .= wordwrap(strip_tags(check_markup($form_values['message'], $form_values['format']))) . "\n";

      // End with the message suffix.
      if (variable_get('mass_contact_message_suffix', '')) {
        if (module_exists('token')) {
          $body_plain .= wordwrap(strip_tags(check_markup(token_replace(variable_get('mass_contact_message_suffix', '')), $form_values['format'])));
        }
        else {
          $body_plain .= wordwrap(strip_tags(check_markup(variable_get('mass_contact_message_suffix', ''), $form_values['format'])));
        }
      }
    }
  }
  else {

    // Start with the message prefix.
    if (variable_get('mass_contact_message_prefix', '')) {
      if (module_exists('token')) {
        $body_plain .= wordwrap(token_replace(variable_get('mass_contact_message_prefix', ''))) . "\n";
      }
      else {
        $body_plain .= wordwrap(variable_get('mass_contact_message_prefix', '')) . "\n";
      }
    }

    // Add in the actual message.
    $body_plain .= wordwrap($form_values['message']) . "\n";

    // End with the message suffix.
    if (variable_get('mass_contact_message_suffix', '')) {
      if (module_exists('token')) {
        $body_plain .= wordwrap(token_replace(variable_get('mass_contact_message_suffix', '')));
      }
      else {
        $body_plain .= wordwrap(variable_get('mass_contact_message_suffix', ''));
      }
    }
  }

  // If this is an HTML message, create the HTML body part.
  if ($form_values['html']) {

    // Start with the message prefix.
    if (variable_get('mass_contact_message_prefix', '')) {
      if (module_exists('token')) {
        $body_html .= check_markup(token_replace(variable_get('mass_contact_message_prefix', '')), $form_values['format']);
      }
      else {
        $body_html .= check_markup(variable_get('mass_contact_message_prefix', ''), $form_values['format']);
      }
    }

    // Add in the actual message.
    $body_html .= check_markup($form_values['message'], $form_values['format']);

    // End with the message suffix.
    if (variable_get('mass_contact_message_suffix', '')) {
      if (module_exists('token')) {
        $body_html .= check_markup(token_replace(variable_get('mass_contact_message_suffix', '')), $form_values['format']);
      }
      else {
        $body_html .= check_markup(variable_get('mass_contact_message_suffix', ''), $form_values['format']);
      }
    }
  }

  // Put it all together.
  // Check to see if we have either an attachment or an HTML message.
  if ($has_attachments || $form_values['html']) {

    // If we have either, we add the following.
    $message .= "\nThis is a MIME-formatted multipart message.\n\nIf you see this text it means that your e-mail software does not support MIME-formatted multipart messages.\n\nYou might want to consider changing your e-mail software to one that understands how to properly display MIME-formatted multipart messages.\n";

    // Add our boundary, based on the content.
    if ($has_attachments) {
      $message .= "\n--{$boundary_attachment}\n";
    }
    else {
      $message .= "\n--{$boundary_html}\n";
    }

    // If we have both an attachment and an HTML message, we need the following.
    if ($has_attachments && $form_values['html']) {
      $message .= 'Content-Type: multipart/alternative; boundary="' . $boundary_html . '"' . "\n";
      $message .= "\n--{$boundary_html}\n";
    }

    // Add the plain text part to the message.
    $message .= "Content-Type: text/plain; charset={$character_set}; format=flowed\n";

    // The 8bit Data mechanism is similar to 7bit, except that it allows for
    // character sets other than US-ASCII to be used (RFC 2045, sections 2.7
    // and 2.8).
    // When the Content-Transfer-Encoding is not specified, "7bit" is the
    // default mechanism (RFC 2045, sections 6 and 6.1).
    $message .= "Content-Transfer-Encoding: 8bit\n\n";
    $message .= $body_plain;

    // If there is an HTML part, add it to the message.
    if ($form_values['html']) {
      $message .= "\n--{$boundary_html}\n";
      $message .= "Content-Type: text/html; charset={$character_set}; format=flowed\n";

      // The 8bit Data mechanism is similar to 7bit, except that it allows for
      // character sets other than US-ASCII to be used (RFC 2045, sections 2.7
      // and 2.8).
      // When the Content-Transfer-Encoding is not specified, "7bit" is the
      // default mechanism (RFC 2045, sections 6 and 6.1).
      $message .= "Content-Transfer-Encoding: 8bit\n\n";
      $message .= $body_html;

      // Add the closing boundary line (RFC 2046, section 5.1 and 5.1.1).
      $message .= "\n--{$boundary_html}--\n";
    }
  }
  else {

    // There is neither an attachment nor an HTML message, so this is not a
    // multipart message, and we just add the plain text part.
    $message = $body_plain;
  }

  // For the node copy, we want to handle attachments differently, so we'll
  // save the message as it currently stands.
  if (variable_get('mass_contact_nodecc_d', 1) || $form_values['nodecc'] == 1) {
    $node_message = $message;
  }

  // If there are attachments, add them.
  if ($has_attachments) {
    if (module_exists('mimemail') && variable_get('mimemail_alter', 0) == 1) {
      $message_attachments = _mass_contact_process_mime_mail_attachments();
    }
    else {
      $message = _mass_contact_process_attachments($message, $boundary_attachment);

      // Add the closing boundary line (RFC 2046, section 5.1 and 5.1.1).
      $message .= "--{$boundary_attachment}--\n";
    }
  }

  ///////////////////////////////////////////////////////////////////////////

  //
  //  @TODO:  The whole rest of this function needs to be re-thought out and
  //          refactored, possibly separating some of it out into other
  //          functions.
  //

  ///////////////////////////////////////////////////////////////////////////

  /*
   Task order:
     Create the e-mail message, starting w/the header
     Get the list of categories
     Create the list of recipients
     Add the list of recipients to the e-mail message
  */

  // Load the category information.
  foreach ($form_values['cid'] as $cid) {
    $cids .= $cid;
    if (next($form_values['cid'])) {
      $cids .= ", ";
    }
  }
  $result = db_query("SELECT * FROM {mass_contact} WHERE cid IN (%s)", $cids);
  while ($contact = db_fetch_object($result)) {

    // Format the subject line.
    if (variable_get('mass_contact_category_override', 1)) {
      $subject = t('[!category] !subject', array(
        '!category' => $contact->category,
        '!subject' => $form_values['subject'],
      ));
    }
    else {
      $subject = $form_values['subject'];
    }

    // Prepare the body.
    $body = $message;
    $node_body = $node_message;
    $uidooa = array();

    // Check for opt-out unless overridden by admin.
    $optout_setting = variable_get('mass_contact_optout_d', 0);
    if ($optout_setting == 1 || $optout_setting == 2) {
      if ($form_values['optout'] == 1) {
        $ooresult = db_query("SELECT uid FROM {users} WHERE status <> %d", 0);
        while ($oouid = db_fetch_object($ooresult)) {
          $account = user_load(array(
            'uid' => $oouid->uid,
            'status' => 1,
          ));
          if ($optout_setting == 1 && $account->mass_contact_optout == 1) {
            $uidoo = $oouid->uid;
            $uidooa[$uidoo] = 1;
          }
          elseif ($optout_setting == 2) {
            $optout_cid = 'mass_contact_optout_' . $contact->cid;
            if ($account->{$optout_cid} == 1) {
              $uidoo = $oouid->uid;
              $uidooa[$uidoo] = 1;
            }
          }
        }
      }
    }
    global $user;

    // Create the recipient list.
    $recipientouta = array();
    $roles = explode(',', $contact->recipients);
    foreach ($roles as $r) {
      if ($r == 2) {

        // all users
        $recipients = db_query("SELECT name, mail, uid FROM {users} WHERE status <> 0 AND uid > 0");
        while ($obj = db_fetch_object($recipients)) {
          $rname = $obj->name;
          $rmail = $obj->mail;
          $ruid = $obj->uid;
          if ($rname != $user->name && !$uidooa[$ruid]) {
            $recipientouta[$rname] = $rmail;
          }
        }
        break;
      }
      else {

        // Get from users_roles, then role -> user.
        $uids = db_query("SELECT ur.uid FROM {users_roles} ur LEFT JOIN {users} u ON ur.uid = u.uid WHERE ur.rid = %d AND u.status <> 0", $r);
        while ($obj = db_fetch_object($uids)) {
          $ruid = $obj->uid;
          $userobj = db_fetch_object(db_query("SELECT name, mail FROM {users} WHERE uid = %d", $ruid));
          $rname = $userobj->name;
          $rmail = $userobj->mail;
          if (isset($uidooa[$ruid])) {
            if ($rname != $user->name && !$uidooa[$ruid]) {
              $recipientouta[$rname] = $rmail;
            }
          }
          else {
            if ($rname != $user->name) {
              $recipientouta[$rname] = $rmail;
            }
          }
        }
      }
    }

    // Check for empty recipient list.
    if (count($recipientouta) == 0) {
      drupal_set_message(t('There are no users in this category. Mail not sent.'));
      return '';
    }
    $recipientout = array();

    // Check for recipient limit and break up recipient list, if necessary.
    $recip_limit = variable_get('mass_contact_recipient_limit', 0);
    if (count($recipientouta) > $recip_limit && $recip_limit != 0) {
      $countrecip = 0;
      $ccc = 0;
      foreach ($recipientouta as $rnamea => $rmaila) {

        //        $recipientout[] = $rnamea ." <". $rmaila .">";
        $recipientout[] = $rmaila;

        //        $recipient_temp[] = $rnamea ." <". $rmaila .">";
        $recipient_temp[] = $rmaila;
        $countrecip = count($recipient_temp);
        if ($countrecip == $recip_limit) {
          $recipient_send = implode(', ', $recipient_temp);

          // set bcc
          if ($bcc == 1) {

            // hidden recipients
            $headers['Bcc'] = $recipient_send;
            $to = $from;
          }
          else {
            $to = $recipient_send;
          }
          ++$ccc;

          // Send the e-mail to the recipients:
          if (module_exists('mimemail') && variable_get('mimemail_alter', 0) == 1) {
            if ($form_values['html']) {
              $success = mimemail($from, $to, $subject, $body_html, NULL, $headers, $body_plain, $message_attachments, 'mass-contact-page-mail');
            }
            else {
              $success = mimemail($from, $to, $subject, $body_html, TRUE, $headers, $body_plain, $message_attachments, 'mass-contact-page-mail');
            }
          }
          else {
            $success = drupal_mail('mass-contact-page-mail', $to, $subject, $body, $from, $headers);
          }
          if ($success) {
            watchdog('mass_contact', t('[Success] Send #@ccc: -e-mails', array(
              '@ccc' => $ccc,
              '-e-mails' => $recipient_send,
            )), WATCHDOG_NOTICE);
          }
          else {
            watchdog('mass_contact', t('There was a problem sending batch #@ccc to: -e-mails: -e-mails', array(
              '@ccc' => $ccc,
              '-e-mails' => $recipient_send,
            )), WATCHDOG_ERROR);
            ++$send_error;
          }

          // reset array
          $recipient_temp = array();
          $countrecip = 0;
        }
      }

      // Send the remainder.
      if ($countrecip != 0) {
        $recipient_send = implode(', ', $recipient_temp);
        if ($bcc == 1) {

          // hidden recipients
          $headers['Bcc'] = $recipient_send;
          $to = $from;
        }
        else {
          $to = $recipient_send;
        }
        ++$ccc;

        // Send the e-mail to the recipients:
        if (module_exists('mimemail') && variable_get('mimemail_alter', 0) == 1) {
          if ($form_values['html']) {
            $success = mimemail($from, $to, $subject, $body_html, NULL, $headers, $body_plain, $message_attachments, 'mass-contact-page-mail');
          }
          else {
            $success = mimemail($from, $to, $subject, $body_html, TRUE, $headers, $body_plain, $message_attachments, 'mass-contact-page-mail');
          }
        }
        else {
          $success = drupal_mail('mass-contact-page-mail', $to, $subject, $body, $from, $headers);
        }

        // Send a copy to self, if requested.
        if ($form_values['copy'] && !$bcc) {
          drupal_mail('mass-contact-user-copy', $from, $subject, $body, $from, $headers);
        }
        if ($success) {
          watchdog('mass_contact', t('[Success] Send Remainder: -e-mails', array(
            '-e-mails' => $recipient_send,
          )), WATCHDOG_NOTICE);
        }
        else {
          watchdog('mass_contact', t('There was a problem sending remaining batch to: -e-mails', array(
            '@ccc' => $ccc,
            '-e-mails' => $recipient_send,
          )), WATCHDOG_ERROR);
          ++$send_error;
        }
      }
      $total_recip = count($recipientout);
      $recipientout = implode(', ', $recipientout);
    }
    else {
      foreach ($recipientouta as $rnamea => $rmaila) {

        //        $recipientout[] = $rnamea ." <". $rmaila .">";
        $recipientout[] = $rmaila;
      }
      $total_recip = count($recipientout);
      $recipientout = implode(', ', $recipientout);

      // set bcc
      if ($bcc == 1) {

        // hidden recipients
        $headers['Bcc'] = $recipientout;
        $to = $from;
      }
      else {
        $to = $recipientout;
      }

      // Send the e-mail to the recipients.
      if (module_exists('mimemail') && variable_get('mimemail_alter', 0) == 1) {
        if ($form_values['html']) {
          $success = mimemail($from, $to, $subject, $body_html, NULL, $headers, $body_plain, $message_attachments, 'mass-contact-page-mail');
        }
        else {
          $success = mimemail($from, $to, $subject, $body_html, TRUE, $headers, $body_plain, $message_attachments, 'mass-contact-page-mail');
        }
      }
      else {
        $success = drupal_mail('mass-contact-page-mail', $to, $subject, $body, $from, $headers);
      }

      // Send a copy to self, if requested.
      if ($form_values['copy'] && !$bcc) {
        drupal_mail('mass-contact-user-copy', $from, $subject, $body, $from, $headers);
      }
      if ($success) {
        watchdog('mass_contact', t('[Success] Send Once: -e-mails', array(
          '-e-mails' => $recipientout,
        )), WATCHDOG_NOTICE);
      }
      else {
        watchdog('mass_contact', t('There was a problem sending e-mail to: -e-mails', array(
          '-e-mails' => $recipientout,
        )), WATCHDOG_ERROR);
        ++$send_error;
      }
    }

    // Error checking & reporting and node saving.
    // Check for errors.
    if ($send_error == 0) {

      // If there are no errors, check to see if we need to save the message as a node.
      if ($nodecc == 1) {

        // Check to see if the node type exists.
        $check = db_fetch_array(db_query("SELECT * FROM {node_type} WHERE type = 'mass_contact'"));
        if (!$check) {

          // If the node type does not exist, create it.
          _mass_contact_create_node_type();
        }

        // Save the message as a node.
        _mass_contact_save_node($subject, $node_body, $recipientout, $contact->category, $roles, $user->uid, $has_attachments);
      }

      // Log the operation.
      flood_register_event('mass_contact');
      watchdog('mass_contact', t('%name-from sent an e-mail to the %category group.', array(
        '%name-from' => $form_values['name'] . " <{$from}>",
        '%category' => $contact->category,
      )));

      // Inform the user.
      drupal_set_message(t('The message was successfully sent to @total user(s). (See <a href="@log_link">Drupal\'s logs</a> for the list of recepients.)', array(
        '@total' => $total_recip,
        '@log_link' => url('admin/logs/watchdog'),
      )));
    }
    else {
      drupal_set_message(t('One or more errors were encountered sending the message. Check <a href="@log_link">Drupal\'s logs</a> and the mail server\'s logs and try again.', array(
        '@log_link' => url('admin/logs/watchdog'),
      )));
    }
  }

  // Jump to home page rather than back to mail page to avoid
  // contradictory messages if flood control has been activated.
  return '';
}

//  End of mass_contact_mail_page_submit().

/* *************************
 *
 * Private helper functions.
 *
 * ************************/

/**
 * Validate the attachment(s).
 *
 * @param form_id
 *   A unique string identifying the form.
 * @param form_values
 *   The contents of the form fields.
 */
function _mass_contact_upload_validate($form_id, $form_values) {

  // Accumulator for disk space quotas.
  $filesize = 0;

  // Loop through each possible attachment.
  for ($i = 1; $i <= variable_get('mass_contact_number_of_attachments', '3'); $i++) {

    // Check to see if an attachment exists.
    if ($_FILES['files']['size']['attachment_' . $i] > 0) {
      global $user;

      // Bypass validation for uid = 1.
      if ($user->uid != 1) {

        // Update filesize accumulator.
        $filesize += $_FILES['files']['size']['attachment_' . $i];
        $error = array();

        // Validate file against all users roles.
        // Only denies an upload when all roles prevent it.
        foreach ($user->roles as $rid => $name) {
          $extensions = variable_get("upload_extensions_{$rid}", variable_get('upload_extensions_default', 'jpg jpeg gif png txt doc xls pdf ppt pps odt ods odp'));
          $uploadsize = variable_get("upload_uploadsize_{$rid}", variable_get('upload_uploadsize_default', 1)) * 1024 * 1024;
          $usersize = variable_get("upload_usersize_{$rid}", variable_get('upload_usersize_default', 1)) * 1024 * 1024;
          $regex = '/\\.(' . ereg_replace(' +', '|', preg_quote($extensions)) . ')$/i';
          if (!preg_match($regex, $_FILES['files']['name']['attachment_' . $i])) {
            $error['extension']++;
          }
          if ($uploadsize && $_FILES['files']['size']['attachment_' . $i] > $uploadsize) {
            $error['uploadsize']++;
          }
          if ($usersize && $filesize > $usersize) {
            $error['usersize']++;
          }
        }
        $user_roles = count($user->roles);
        if ($error['extension'] == $user_roles) {
          form_set_error('attachment_' . $i, t('The selected file %name can not be attached to this post, because it is only possible to attach files with the following extensions: %files-allowed.', array(
            '%name' => $_FILES['files']['name']['attachment_' . $i],
            '%files-allowed' => $extensions,
          )));
        }
        if ($error['uploadsize'] == $user_roles) {
          form_set_error('attachment_' . $i, t('The selected file %name can not be attached to this post, because it exceeded the maximum filesize of %maxsize.', array(
            '%name' => $_FILES['files']['name']['attachment_' . $i],
            '%maxsize' => format_size($uploadsize),
          )));
        }
        if ($error['usersize'] == $user_roles) {
          form_set_error('attachment_' . $i, t('The selected file %name can not be attached to this post, because the maximum file size of %quota per upload has been reached.', array(
            '%name' => $_FILES['files']['name']['attachment_' . $i],
            '%quota' => format_size($usersize),
          )));
        }
        if (drupal_strlen($_FILES['files']['name']['attachment_' . $i]) > 255) {
          form_set_error('attachment_' . $i, t('The selected file %name can not be attached to this post, because the filename is too long.', array(
            '%name' => $_FILES['files']['name']['attachment_' . $i],
          )));
        }
      }
    }
  }
}

//  End of _mass_contact_upload_validate().

/**
 * Check for attachments and process them, if one or more exists.
 *
 * @param message
 *   The message, as it exists, so far.
 * @param boundary_id
 *   The id to use as a boundary between attachments and the rest of the
 *   message.
 *
 * @return
 *   The attachments, ready to be appended to the existing message.
 */
function _mass_contact_process_attachments($message, $boundary_id) {
  $message .= "\n";

  // Loop through each possible attachment.
  for ($i = 1; $i <= variable_get('mass_contact_number_of_attachments', '3'); $i++) {

    // Check to see if the attachment exists.
    if ($_FILES['files']['size']['attachment_' . $i] > 0) {

      // Process the attachment.
      $message .= "--{$boundary_id}\n";
      $message .= "Content-Type: " . $_FILES['files']['type']['attachment_' . $i] . "; name=\"" . $_FILES['files']['name']['attachment_' . $i] . "\"\n";
      $message .= "Content-Transfer-Encoding: base64\n";
      $message .= "Content-Disposition: attachment; filename=\"" . $_FILES['files']['name']['attachment_' . $i] . "\"\n\n";
      if (file_exists($_FILES['files']['tmp_name']['attachment_' . $i])) {
        $message .= chunk_split(base64_encode(file_get_contents($_FILES['files']['tmp_name']['attachment_' . $i])));
      }
      else {
        $message .= chunk_split(base64_encode(file_get_contents(file_directory_temp() . '/' . $_FILES['files']['name']['attachment_' . $i])));
      }
      $message .= "\n";
    }
  }
  return $message;
}

//  End of _mass_contact_process_attachments().

/**
 * Process attachments for use with Mime Mail.
 *
 * @return
 *   The attachment information, as Mime Mail expects it.
 */
function _mass_contact_process_mime_mail_attachments() {

  // Set an initial value.
  $files = array();

  // Loop through each possible attachment.
  for ($i = 1; $i <= variable_get('mass_contact_number_of_attachments', '3'); $i++) {

    // Check to see if the attachment exists.
    if ($_FILES['files']['size']['attachment_' . $i] > 0) {
      $files[] = array(
        'filepath' => $_FILES['files']['tmp_name']['attachment'],
        'filename' => $_FILES['files']['name']['attachment'],
        'filemime' => $_FILES['files']['type']['attachment'],
      );
    }
  }
  return $files;
}

//  End of _mass_contact_process_mime_mail_attachments().

/**
 * Create the mass contact node type.
 */
function _mass_contact_create_node_type() {
  $info->type = "mass_contact";
  $info->name = "Mass Contact Message";
  $info->module = "node";
  $info->description = "Archived copy of mass e-mails sent from this site";
  $info->help = "";
  $info->has_title = 1;
  $info->title_label = "Subject";
  $info->has_body = 1;
  $info->body_label = "Message Body";
  $info->min_word_count = 0;
  $info->custom = 1;
  $info->modified = 0;
  $info->locked = 0;
  $info->orig_type = 'mass_contact';
  db_query("INSERT INTO {node_type} (type, name, module, description, help, has_title, title_label, has_body, body_label, min_word_count, custom, modified, locked, orig_type) VALUES ('%s', '%s', '%s', '%s', '%s', %d, '%s', %d, '%s', %d, %d, %d, %d, '%s')", $info->type, $info->name, $info->module, $info->description, $info->help, $info->has_title, $info->title_label, $info->has_body, $info->body_label, $info->min_word_count, $info->custom, $info->modified, $info->locked, $info->orig_type);
  module_invoke_all('node_type', 'insert', $info);
  drupal_set_message(t('Node type created.'));
}

//  End of _mass_contact_create_node_type().

/**
 * Save the sent mail as a node.
 *
 * @param subject
 *   The subject of the message and the title of the node.
 * @param body
 *   The body of the message and node.
 * @param recipients
 *   The users who received a copy of the message.
 * @param category
 *   The category of users sent to.
 * @param roles
 *   The various roles the category represents.
 * @param uid
 *   The user who sent the message is also the user who owns the node.
 * @param $has_attachments
 *   An boolean indictaing whether there were attachments in the message.
 */
function _mass_contact_save_node($subject, $body, $recipients, $category, $roles, $uid, $has_attachments) {

  // get role names
  foreach ($roles as $r) {
    $roletemp = db_fetch_object(db_query("SELECT name FROM {role} WHERE rid = %d", $r));
    $rolesenta[] = $roletemp->name;
  }
  $rolesent = implode(', ', $rolesenta);

  // Create and populate the node object.
  $node = new stdClass();
  $node->title = $subject;
  $node->body = '<p><i>' . t('Category: ') . $category . '</i><p><i>' . t('Roles: ') . $rolesent . '</i><p><i>' . t('Recipients: ') . $recipients . '</i><p>' . $body;
  $node->teaser = node_teaser($node->body);
  $node->type = 'mass_contact';
  $node->uid = $uid;

  // Save the node;
  node_save($node);

  // Get new node id.
  $nidobj = db_fetch_object(db_query("SELECT nid FROM {node} WHERE type = 'mass_contact' ORDER BY changed DESC"));
  $node->nid = $nidobj->nid;

  // Add any attachments, if they exist.
  if ($has_attachments) {
    for ($i = 1; $i <= variable_get('mass_contact_number_of_attachments', '3'); $i++) {
      if ($_FILES['files']['error']['attachment_' . $i] == UPLOAD_ERR_OK) {

        // Create and populate a file object.
        $file = new stdClass();
        $file->filename = $_FILES['files']['name']['attachment_' . $i];
        $file->filepath = $_FILES['files']['tmp_name']['attachment_' . $i];
        $file->filemime = $_FILES['files']['type']['attachment_' . $i];
        $file->filesize = $_FILES['files']['size']['attachment_' . $i];
        $file->list = 1;
        $file->new = true;

        // Copy the file to Drupal's 'files' directory.
        $new_file = file_save_upload($file, $file->filename);
        if ($new_file) {
          $new_file->fid = db_next_id('{files}_fid');
          $node->files[$new_file->fid] = $new_file;
          node_save($node);
          db_query("INSERT INTO {files} (fid, nid, filename, filepath, filemime, filesize) VALUES (%d, %d, '%s', '%s', '%s', %d)", $file->fid, $node->nid, $file->filename, $file->filepath, $file->filemime, $file->filesize);
          db_query("INSERT INTO {file_revisions} (fid, vid, list, description) VALUES (%d, %d, %d, '%s')", $file->fid, $node->vid, $file->list, $file->description);
        }
        else {
          drupal_set_message('Failed to save attachment: ' . $_FILES['files']['name']['attachment_' . $i]);
          continue;
        }
      }
    }
  }

  // Log node creation.
  watchdog('content', t('Mass Contact content added "%title".', array(
    '%title' => $subject,
  )), WATCHDOG_NOTICE, l(t('View'), 'node/' . $node->nid));

  // Inform the user.
  drupal_set_message(t('A copy has been created as a node.'));
}

//  End of _mass_contact_save_node().

Functions

Namesort descending Description
mass_contact_admin_categories Displays a list of all existing categories.
mass_contact_admin_delete Displays a form to select a category to delete.
mass_contact_admin_delete_submit Does the actual deleting of the category.
mass_contact_admin_edit Displays a form to add or edit a category.
mass_contact_admin_edit_submit Processes the adding or editing of a category.
mass_contact_admin_edit_validate Validates the submission of the category add/edit page.
mass_contact_admin_settings Administration settings form.
mass_contact_admin_settings_validate Validates the administration settings form.
mass_contact_help Implementation of hook_help().
mass_contact_mail_page Generates the main Mass Contact mail form.
mass_contact_mail_page_submit Processes the main Mass Contact mail form.
mass_contact_mail_page_validate Validates the main Mass Contact mail form.
mass_contact_menu Implementation of hook_menu().
mass_contact_nodeapi Implementation of hook_nodeapi().
mass_contact_perm Implementation of hook_perm().
mass_contact_site_page The mail page
mass_contact_user Implementation of hook_user().
_mass_contact_create_node_type Create the mass contact node type.
_mass_contact_process_attachments Check for attachments and process them, if one or more exists.
_mass_contact_process_mime_mail_attachments Process attachments for use with Mime Mail.
_mass_contact_save_node Save the sent mail as a node.
_mass_contact_upload_validate Validate the attachment(s).