You are here

casetracker_mail.module in Case Tracker 5

Enables mail sending and Mailhandler integration for Case Tracker.

File

casetracker_mail.module
View source
<?php

/**
 * @file
 * Enables mail sending and Mailhandler integration for Case Tracker.
 */

/**
 * Implementation of hook_help().
 */
function casetracker_mail_help($section) {
  switch ($section) {
    case 'admin/settings/casetracker_mail':
      return '<p>' . t('Configure the various Case Tracker mail options with these settings.') . '</p>';
  }
}

/**
 * Implementation of hook_menu().
 */
function casetracker_mail_menu($may_cache) {
  $items = array();
  if ($may_cache) {
    $items[] = array(
      'access' => user_access('administer case tracker'),
      'callback' => 'drupal_get_form',
      'callback arguments' => 'casetracker_mail_settings',
      'description' => t('Configure the various Case Tracker mail options with these settings.'),
      'path' => 'admin/settings/casetracker/mail',
      'title' => t('CT Mail'),
      'type' => MENU_LOCAL_TASK,
    );
  }
  return $items;
}

/**
 * Sends out emails. Woot! Do people still say woot? Man, I'm old.
 *
 * @param $node
 *   The case $node object that is being inserted or modified.
 * @param $comment
 *   The $comment array, passed only if this a comment has been left.
 */
function casetracker_mail_send($case, $comment = NULL) {
  global $user;

  // is it a comment post
  $isComment = !is_null($comment);

  // get the project data
  $pid = $isComment ? $comment['prid'] : $case->pid;
  $project = db_fetch_object(db_query("SELECT cp.project_number, n.title FROM {casetracker_project} cp LEFT JOIN {node} n ON (n.vid = cp.vid) WHERE cp.nid = %d", $pid));

  // get the assigned to name
  $assignToId = $isComment ? $comment['assign_to'] : $case->assign_to;
  $assignToName = is_numeric($assignToId) ? casetracker_get_name($assignToId) : $assignToId;
  $variables = array(
    '%project_id' => $pid,
    '%project_number' => $project->project_number,
    '%project_title' => $project->title,
    '%case_id' => $case->nid,
    '%case_number' => $project->project_number . '-' . $case->case_number,
    '%case_title' => $isComment ? $comment['case_title'] : $case->title,
    '%case_type' => casetracker_case_state_load('type', $isComment ? $comment['case_type_id'] : $case->case_type_id),
    '%case_priority' => casetracker_case_state_load('priority', $isComment ? $comment['case_priority_id'] : $case->case_priority_id),
    '%case_status' => casetracker_case_state_load('status', $isComment ? $comment['case_status_id'] : $case->case_status_id),
    '%case_assigned' => $assignToName,
    '%case_author' => casetracker_get_name($case->uid),
    '%case_created' => format_date($case->created, 'large'),
    '%case_changed' => format_date($case->changed, 'large'),
    '%case_url' => url('node/' . $case->nid, NULL, NULL, TRUE),
    // @todo fails for CCK or non-body cases.
    '%case_description' => _casetracker_mail_plain_description($case->body),
    '%comment' => NULL,
  );
  if (isset($comment)) {

    // make a master %comment variable that contains the values of this specific comment.
    // @todo it'd be nice if we could display all the previous comments, as the project.module currently does.
    $variables['%comment'] = strtr(variable_get('casetracker_mail_comment_message', _casetracker_mail_comment_message()), array(
      '%comment_author' => casetracker_get_name($comment['uid']),
      '%comment_created' => format_date($comment['date'], 'large'),
      '%comment_title' => $comment['subject'],
      '%comment_description' => _casetracker_mail_plain_description($comment['comment']),
    ));
  }

  // make our own message ID so we can log it and allow responses via mailhandler.
  $msg_id = '<' . time() . '.' . mt_rand() . '@' . drupal_strtolower($_SERVER['SERVER_NAME']) . '>';
  $from = variable_get('casetracker_mail_address', variable_get('site_mail', ini_get('sendmail_from')));
  $subject = strtr(variable_get('casetracker_mail_subject', _casetracker_mail_subject()), $variables);
  $body = strtr(variable_get('casetracker_mail_case_message', _casetracker_mail_case_message()), $variables);
  db_query("INSERT INTO {casetracker_mail} (msg_id, nid, cid) VALUES ('%s', %d, %d)", $msg_id, $case->nid, isset($comment['cid']) ? $comment['cid'] : 0);

  // @todo this currently sends to only author and assigned. there needs to be
  // finer-grain control here, like an OG subscribers or all commenters, etc.
  $results = db_query("SELECT uid, name, mail FROM {users} WHERE uid IN (%d, %d, %d)", $comment['uid'], $case->uid, is_numeric($assignToId) ? $assignToId : casetracker_get_uid($assignToId));
  while ($result = db_fetch_object($results)) {
    if ($result->uid == $user->uid) {
      continue;
    }

    // don't fire to currently commenting user.
    if (!$result->mail) {
      continue;
    }

    // don't fire blanks.
    // if we get here a mail is send
    $mail_status = drupal_mail('casetracker_mail', $result->mail, $subject, $body, $from, array(
      'Message-ID' => $msg_id,
    ));
    if (!$mail_status) {

      // mail failure doesn't actually tell us much, since PHP returns no error string, but hey, feel good, right?
      watchdog('casetracker_mail', t('E-mail notification failed for %address.', array(
        '%address' => $result->mail,
      )));
    }
  }
}

/**
 * Implementation of hook_comment().
 */
function casetracker_mail_comment(&$comment, $op) {
  switch ($op) {
    case 'insert':
    case 'update':
      $node = node_load($comment['nid']);

      // checks type and compares existing case meta to submitted.
      if (!in_array($node->type, variable_get('casetracker_case_node_types', array(
        'casetracker_basic_case',
      )), TRUE)) {
        return;

        // if this isn't a casetracker case node type, return without sullying our miserable code. MISERY!
      }

      // NP: 'Caught' from Stu Phillips's album 'Knight Rider: The Stu Phillips Scores: Original Television Soundtrack'.
      casetracker_mail_send($node, $comment);
      break;
    case 'delete':
      db_query('DELETE FROM {casetracker_mail} WHERE cid = %d', $comment->cid);
      break;
  }
}

/**
 * Implementation of hook_nodeapi().
 */
function casetracker_mail_nodeapi(&$node, $op, $teaser = NULL, $page = NULL) {
  switch ($op) {
    case 'insert':
    case 'update':
      if (in_array($node->type, variable_get('casetracker_case_node_types', array(
        'casetracker_basic_case',
      )), TRUE)) {
        casetracker_mail_send($node);
      }
      break;
    case 'delete':
      if (in_array($node->type, variable_get('casetracker_case_node_types', array(
        'casetracker_basic_case',
      )), TRUE)) {
        db_query('DELETE FROM {casetracker_mail} WHERE nid = %d', $node->nid);
      }
      break;
  }
}

/**
 * Implementation of hook_mailhandler().
 *
 *   project_number: 500
 *   type: casetracker_case
 *   case_title: This is a case title! Yes!
 *   assign_to: Morbus Iff
 *   case_status: open
 *   case_priority: 1-high
 *   case_type: bug
 */
function casetracker_mailhandler($node, $result, $msg_number, $header, $mailbox) {
  $source_msg_id = $header->references;

  // used for comment replies. actually
  // dependent on a few assumptions: the angle brackets are stored in the
  // casetracker_mail table and that a reply can never be replied too. both
  // are accurate, but it's not the most flexible of designs.
  // determine the right values based on those in the email.
  $node->title = $node->case_title ? $node->case_title : $node->title;
  $node->assign_to = $node->assign_to ? $node->assign_to : $node->uid;
  foreach (array(
    'priority',
    'status',
    'type',
  ) as $state) {
    $options = casetracker_case_state_load($state);
    $node->{'case_' . $state . '_id'} = $node->{'case_' . $state} ? db_result(db_query("SELECT csid FROM {casetracker_case_states} WHERE case_state_name = LOWER('%s') AND case_state_realm = '%s'", drupal_strtolower($node->{'case_' . $state}), $state)) : variable_get('casetracker_default_case_' . $state, array_shift(array_keys($options)));
  }

  // @todo potential hack for CCK fields: explode on [ and make
  // a new array level for every one you see. maybe, maybe.
  $node->pid = db_result(db_query("SELECT nid FROM {casetracker_project} WHERE project_number = %d", $node->project_number));
  if ($node->pid && !$source_msg_id) {

    // if we've got a project number, and this isn't a reply, make a new case.
    $node->status = 1;
    return $node;

    // we'll publish the node by default, but @todo this should be configurable.
  }
  elseif ($source_msg_id) {
    $comment = array();

    // a source message ID exists, so this is a comment via email.
    $result = db_fetch_object(db_query("SELECT msg_id, nid, cid FROM {casetracker_mail} WHERE msg_id = '%s'", $source_msg_id));
    $case = node_load($result->nid);
    $comment['nid'] = $result->nid;
    $comment['pid'] = $result->cid;
    $comment['comment'] = $node->body;
    $comment['uid'] = $node->uid;
    $comment['subject'] = $node->title;
    $comment['case_priority_id'] = $case->case_priority_id;
    $comment['case_type_id'] = $case->case_type_id;
    $comment['case_status_id'] = $case->case_status_id;
    $comment['case_title'] = $case->title;
    $comment['pid'] = $case->pid;
    $comment['assign_to'] = casetracker_get_name($case->assign_to);

    // @todo allow emailed comments to change these states.
    comment_save($comment);
  }
  else {
    return $node;
  }
}

/**
 * Configures the various Case Tracker mail options; system_settings_form().
 */
function casetracker_mail_settings() {
  $form = array();
  $form['casetracker_mail'] = array(
    '#type' => 'fieldset',
    '#title' => t('E-mail settings'),
    '#collapsible' => TRUE,
    '#collapsed' => FALSE,
    '#description' => t('Enter the From address, subject, case message, and comment message for Case Tracker generated mails. Available variables are %project_id (the node ID), %project_number, %project_title, %case_id (the node ID), %case_number, %case_title.'),
  );
  $form['casetracker_mail']['casetracker_mail_address'] = array(
    '#type' => 'textfield',
    '#title' => t('E-mail address'),
    '#default_value' => variable_get('casetracker_mail_address', variable_get('site_mail', ini_get('sendmail_from'))),
    '#description' => t('A valid e-mail address used in the From: of all Case Tracker generated mails.'),
  );
  $form['casetracker_mail']['casetracker_mail_subject'] = array(
    '#type' => 'textfield',
    '#title' => t('Subject'),
    '#default_value' => variable_get('casetracker_mail_subject', _casetracker_mail_subject()),
    '#description' => t('Enter the subject of all Case Tracker generated mails.'),
  );
  $form['casetracker_mail']['casetracker_mail_case_message'] = array(
    '#rows' => 15,
    '#type' => 'textarea',
    '#title' => t('Case message'),
    '#default_value' => variable_get('casetracker_mail_case_message', _casetracker_mail_case_message()),
    '#description' => t('Enter the case message body of Case Tracker generated mails. Apart from the variables mentioned above, additional variables include %case_type, %case_priority, %case_status, %case_assigned, %case_author, %case_created, %case_changed, %case_url, %case_description, %comment (see below for the value of the %comment variable).'),
  );

  // @todo it is not exactly clear how CCK node types (or other custom node fields) will be available as %variables.
  // @todo it also doesn't appear like we can give a list of all other comments made on this particular case.
  $form['casetracker_mail']['casetracker_mail_comment_message'] = array(
    '#rows' => 10,
    '#type' => 'textarea',
    '#title' => t('Comment message'),
    '#default_value' => variable_get('casetracker_mail_comment_message', _casetracker_mail_comment_message()),
    '#description' => t('Enter the comment message body of Case Tracker generated mails. The %comment variable in the \'Case message\' text above will be replaced by this value (if applicable). Available additional variables are %comment_author, %comment_title, %comment_description.'),
  );
  return system_settings_form($form);
}

/**
 * Returns the default message for Case Tracker case mails.
 */
function _casetracker_mail_case_message() {
  return "Case status update for %case_url\n\n" . "Project:          %project_title\n" . "Type:             %case_type\n" . "Priority:         %case_priority\n" . "Status:           %case_status\n" . "Assigned:         %case_assigned\n" . "Opened by:        %case_author\n" . "Opened on:        %case_created\n" . "Last modified:    %case_changed\n\n" . "%case_description\n\n" . "%comment\n";
}
function _casetracker_mail_comment_message() {
  return "------------------------------------------------------------------------\n\n" . "Comment by:       %comment_author\n" . "Comment title:    %comment_title\n\n" . "%comment_description\n\n";
}

/**
 * Returns the default subject line for Case Tracker mails.
 */
function _casetracker_mail_subject() {
  return '[%project_title %case_type %case_number] %case_title';
}

/**
 * Function to clear the possible html from a mail and generate readable txt version
 * 
 * @param 	string
 * @return 	string
 */
function _casetracker_mail_plain_description($_description) {

  // tags that should be have a newline behind their ass
  $tags = array(
    '</h1>',
    '</h2>',
    '</h3>',
    '</h4>',
    '</h5>',
    '</h6>',
    '</p>',
    '<br>',
    '<br/>',
    '<br />',
    '</div>',
    '</pre>',
    '</code>',
    '</ul>',
    '</ol>',
    '</li>',
    '</dl>',
    '</dd>',
    '</dt>',
  );
  foreach ($tags as $tag) {
    $_description = str_replace($tag, $tag . "\n", $_description);
  }
  $result = filter_xss($_description, array(
    'dd',
  ));
  return $result;
}

Functions

Namesort descending Description
casetracker_mailhandler Implementation of hook_mailhandler().
casetracker_mail_comment Implementation of hook_comment().
casetracker_mail_help Implementation of hook_help().
casetracker_mail_menu Implementation of hook_menu().
casetracker_mail_nodeapi Implementation of hook_nodeapi().
casetracker_mail_send Sends out emails. Woot! Do people still say woot? Man, I'm old.
casetracker_mail_settings Configures the various Case Tracker mail options; system_settings_form().
_casetracker_mail_case_message Returns the default message for Case Tracker case mails.
_casetracker_mail_comment_message
_casetracker_mail_plain_description Function to clear the possible html from a mail and generate readable txt version
_casetracker_mail_subject Returns the default subject line for Case Tracker mails.