| 1 |
<?php
|
| 2 |
// $Id: casetracker_mail.module,v 1.19 2008/03/09 14:50:55 zero2one Exp $
|
| 3 |
|
| 4 |
/**
|
| 5 |
* @file
|
| 6 |
* Enables mail sending and Mailhandler integration for Case Tracker.
|
| 7 |
*/
|
| 8 |
|
| 9 |
/**
|
| 10 |
* Implementation of hook_help().
|
| 11 |
*/
|
| 12 |
function casetracker_mail_help($section) {
|
| 13 |
switch ($section) {
|
| 14 |
case 'admin/settings/casetracker_mail':
|
| 15 |
return '<p>'.t('Configure the various Case Tracker mail options with these settings.').'</p>';
|
| 16 |
}
|
| 17 |
}
|
| 18 |
|
| 19 |
/**
|
| 20 |
* Implementation of hook_menu().
|
| 21 |
*/
|
| 22 |
function casetracker_mail_menu($may_cache) {
|
| 23 |
$items = array();
|
| 24 |
|
| 25 |
if ($may_cache) {
|
| 26 |
$items[] = array(
|
| 27 |
'access' => user_access('administer case tracker'),
|
| 28 |
'callback' => 'drupal_get_form',
|
| 29 |
'callback arguments' => 'casetracker_mail_settings',
|
| 30 |
'description' => t('Configure the various Case Tracker mail options with these settings.'),
|
| 31 |
'path' => 'admin/settings/casetracker/mail',
|
| 32 |
'title' => t('CT Mail'),
|
| 33 |
'type' => MENU_LOCAL_TASK,
|
| 34 |
);
|
| 35 |
}
|
| 36 |
|
| 37 |
return $items;
|
| 38 |
}
|
| 39 |
|
| 40 |
/**
|
| 41 |
* Sends out emails. Woot! Do people still say woot? Man, I'm old.
|
| 42 |
*
|
| 43 |
* @param $node
|
| 44 |
* The case $node object that is being inserted or modified.
|
| 45 |
* @param $comment
|
| 46 |
* The $comment array, passed only if this a comment has been left.
|
| 47 |
*/
|
| 48 |
function casetracker_mail_send($case, $comment = NULL) {
|
| 49 |
global $user;
|
| 50 |
|
| 51 |
// is it a comment post
|
| 52 |
$isComment = !is_null($comment);
|
| 53 |
|
| 54 |
// get the project data
|
| 55 |
$pid = ($isComment)
|
| 56 |
? $comment['prid']
|
| 57 |
: $case->pid;
|
| 58 |
$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));
|
| 59 |
|
| 60 |
// get the assigned to name
|
| 61 |
$assignToId = ($isComment)
|
| 62 |
? $comment['assign_to']
|
| 63 |
: $case->assign_to;
|
| 64 |
$assignToName = (is_numeric($assignToId))
|
| 65 |
? casetracker_get_name($assignToId)
|
| 66 |
: $assignToId;
|
| 67 |
|
| 68 |
$variables = array(
|
| 69 |
'%project_id' => $pid,
|
| 70 |
'%project_number' => $project->project_number,
|
| 71 |
'%project_title' => $project->title,
|
| 72 |
'%case_id' => $case->nid,
|
| 73 |
'%case_number' => $project->project_number .'-'. $case->case_number,
|
| 74 |
'%case_title' => $isComment
|
| 75 |
? $comment['case_title']
|
| 76 |
: $case->title,
|
| 77 |
'%case_type' => casetracker_case_state_load(
|
| 78 |
'type',
|
| 79 |
$isComment
|
| 80 |
? $comment['case_type_id']
|
| 81 |
: $case->case_type_id),
|
| 82 |
'%case_priority' => casetracker_case_state_load(
|
| 83 |
'priority',
|
| 84 |
$isComment
|
| 85 |
? $comment['case_priority_id']
|
| 86 |
: $case->case_priority_id),
|
| 87 |
'%case_status' => casetracker_case_state_load(
|
| 88 |
'status',
|
| 89 |
$isComment
|
| 90 |
? $comment['case_status_id']
|
| 91 |
: $case->case_status_id),
|
| 92 |
'%case_assigned' => $assignToName,
|
| 93 |
'%case_author' => casetracker_get_name($case->uid),
|
| 94 |
'%case_created' => format_date($case->created, 'large'),
|
| 95 |
'%case_changed' => format_date($case->changed, 'large'),
|
| 96 |
'%case_url' => url('node/'.$case->nid, NULL, NULL, TRUE),
|
| 97 |
// @todo fails for CCK or non-body cases.
|
| 98 |
'%case_description' => _casetracker_mail_plain_description($case->body),
|
| 99 |
'%comment' => NULL,
|
| 100 |
);
|
| 101 |
|
| 102 |
|
| 103 |
|
| 104 |
if (isset($comment)) { // make a master %comment variable that contains the values of this specific comment.
|
| 105 |
// @todo it'd be nice if we could display all the previous comments, as the project.module currently does.
|
| 106 |
$variables['%comment'] = strtr(variable_get('casetracker_mail_comment_message', _casetracker_mail_comment_message()), array(
|
| 107 |
'%comment_author' => casetracker_get_name($comment['uid']),
|
| 108 |
'%comment_created' => format_date($comment['date'], 'large'),
|
| 109 |
'%comment_title' => $comment['subject'],
|
| 110 |
'%comment_description' => _casetracker_mail_plain_description($comment['comment']),
|
| 111 |
));
|
| 112 |
}
|
| 113 |
|
| 114 |
// make our own message ID so we can log it and allow responses via mailhandler.
|
| 115 |
$msg_id = '<'. time() .'.'. mt_rand() .'@'. drupal_strtolower($_SERVER['SERVER_NAME']) .'>';
|
| 116 |
$from = variable_get('casetracker_mail_address', variable_get('site_mail', ini_get('sendmail_from')));
|
| 117 |
$subject = strtr(variable_get('casetracker_mail_subject', _casetracker_mail_subject()), $variables);
|
| 118 |
$body = strtr(variable_get('casetracker_mail_case_message', _casetracker_mail_case_message()), $variables);
|
| 119 |
db_query("INSERT INTO {casetracker_mail} (msg_id, nid, cid) VALUES ('%s', %d, %d)", $msg_id, $case->nid, isset($comment['cid']) ? $comment['cid'] : 0);
|
| 120 |
|
| 121 |
// @todo this currently sends to only author and assigned. there needs to be
|
| 122 |
// finer-grain control here, like an OG subscribers or all commenters, etc.
|
| 123 |
$results = db_query(
|
| 124 |
"SELECT uid, name, mail FROM {users} WHERE uid IN (%d, %d, %d)",
|
| 125 |
$comment['uid'],
|
| 126 |
$case->uid,
|
| 127 |
is_numeric($assignToId)
|
| 128 |
? $assignToId
|
| 129 |
: casetracker_get_uid($assignToId)
|
| 130 |
);
|
| 131 |
|
| 132 |
while ($result = db_fetch_object($results)) {
|
| 133 |
if ($result->uid == $user->uid) { continue; } // don't fire to currently commenting user.
|
| 134 |
if (!$result->mail) { continue; } // don't fire blanks.
|
| 135 |
|
| 136 |
// if we get here a mail is send
|
| 137 |
$mail_status = drupal_mail('casetracker_mail', $result->mail, $subject, $body, $from, array('Message-ID' => $msg_id));
|
| 138 |
if (!$mail_status) { // mail failure doesn't actually tell us much, since PHP returns no error string, but hey, feel good, right?
|
| 139 |
watchdog('casetracker_mail', t('E-mail notification failed for %address.', array('%address' => $result->mail)));
|
| 140 |
}
|
| 141 |
}
|
| 142 |
}
|
| 143 |
|
| 144 |
/**
|
| 145 |
* Implementation of hook_comment().
|
| 146 |
*/
|
| 147 |
function casetracker_mail_comment(&$comment, $op) {
|
| 148 |
switch ($op) {
|
| 149 |
case 'insert':
|
| 150 |
case 'update':
|
| 151 |
$node = node_load($comment['nid']); // checks type and compares existing case meta to submitted.
|
| 152 |
if (!in_array($node->type, variable_get('casetracker_case_node_types', array('casetracker_basic_case')), TRUE)) {
|
| 153 |
return; // if this isn't a casetracker case node type, return without sullying our miserable code. MISERY!
|
| 154 |
} // NP: 'Caught' from Stu Phillips's album 'Knight Rider: The Stu Phillips Scores: Original Television Soundtrack'.
|
| 155 |
|
| 156 |
casetracker_mail_send($node, $comment);
|
| 157 |
break;
|
| 158 |
|
| 159 |
case 'delete':
|
| 160 |
db_query('DELETE FROM {casetracker_mail} WHERE cid = %d', $comment->cid);
|
| 161 |
break;
|
| 162 |
}
|
| 163 |
}
|
| 164 |
|
| 165 |
/**
|
| 166 |
* Implementation of hook_nodeapi().
|
| 167 |
*/
|
| 168 |
function casetracker_mail_nodeapi(&$node, $op, $teaser = NULL, $page = NULL) {
|
| 169 |
switch ($op) {
|
| 170 |
case 'insert':
|
| 171 |
case 'update':
|
| 172 |
if (in_array($node->type, variable_get('casetracker_case_node_types', array('casetracker_basic_case')), TRUE)) {
|
| 173 |
dvm('send');
|
| 174 |
casetracker_mail_send($node);
|
| 175 |
} break;
|
| 176 |
|
| 177 |
case 'delete':
|
| 178 |
if (in_array($node->type, variable_get('casetracker_case_node_types', array('casetracker_basic_case')), TRUE)) {
|
| 179 |
db_query('DELETE FROM {casetracker_mail} WHERE nid = %d', $node->nid);
|
| 180 |
} break;
|
| 181 |
}
|
| 182 |
}
|
| 183 |
|
| 184 |
/**
|
| 185 |
* Implementation of hook_mailhandler().
|
| 186 |
*
|
| 187 |
* project_number: 500
|
| 188 |
* type: casetracker_case
|
| 189 |
* case_title: This is a case title! Yes!
|
| 190 |
* assign_to: Morbus Iff
|
| 191 |
* case_status: open
|
| 192 |
* case_priority: 1-high
|
| 193 |
* case_type: bug
|
| 194 |
*/
|
| 195 |
function casetracker_mailhandler($node, $result, $msg_number, $header, $mailbox) {
|
| 196 |
$source_msg_id = $header->references; // used for comment replies. actually
|
| 197 |
// dependent on a few assumptions: the angle brackets are stored in the
|
| 198 |
// casetracker_mail table and that a reply can never be replied too. both
|
| 199 |
// are accurate, but it's not the most flexible of designs.
|
| 200 |
|
| 201 |
// determine the right values based on those in the email.
|
| 202 |
$node->title = $node->case_title ? $node->case_title : $node->title;
|
| 203 |
$node->assign_to = $node->assign_to ? $node->assign_to : $node->uid;
|
| 204 |
foreach (array('priority', 'status', 'type') as $state) {
|
| 205 |
$options = casetracker_case_state_load($state);
|
| 206 |
$node->{'case_'.$state.'_id'} = $node->{'case_'.$state}
|
| 207 |
? 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))
|
| 208 |
: variable_get('casetracker_default_case_'.$state, array_shift(array_keys($options)));
|
| 209 |
}
|
| 210 |
|
| 211 |
// @todo potential hack for CCK fields: explode on [ and make
|
| 212 |
// a new array level for every one you see. maybe, maybe.
|
| 213 |
|
| 214 |
$node->pid = db_result(db_query("SELECT nid FROM {casetracker_project} WHERE project_number = %d", $node->project_number));
|
| 215 |
if ($node->pid && !$source_msg_id) { // if we've got a project number, and this isn't a reply, make a new case.
|
| 216 |
$node->status = 1; return $node; // we'll publish the node by default, but @todo this should be configurable.
|
| 217 |
}
|
| 218 |
elseif ($source_msg_id) {
|
| 219 |
$comment = array(); // a source message ID exists, so this is a comment via email.
|
| 220 |
$result = db_fetch_object(db_query("SELECT msg_id, nid, cid FROM {casetracker_mail} WHERE msg_id = '%s'", $source_msg_id));
|
| 221 |
$case = node_load($result->nid);
|
| 222 |
$comment['nid'] = $result->nid;
|
| 223 |
$comment['pid'] = $result->cid;
|
| 224 |
$comment['comment'] = $node->body;
|
| 225 |
$comment['uid'] = $node->uid;
|
| 226 |
$comment['subject'] = $node->title;
|
| 227 |
$comment['case_priority_id'] = $case->case_priority_id;
|
| 228 |
$comment['case_type_id'] = $case->case_type_id;
|
| 229 |
$comment['case_status_id'] = $case->case_status_id;
|
| 230 |
$comment['case_title'] = $case->title;
|
| 231 |
$comment['pid'] = $case->pid;
|
| 232 |
$comment['assign_to'] = casetracker_get_name($case->assign_to);
|
| 233 |
// @todo allow emailed comments to change these states.
|
| 234 |
comment_save($comment);
|
| 235 |
}
|
| 236 |
// else (if no pid) then pass the node back for default processing)
|
| 237 |
else {
|
| 238 |
return $node;
|
| 239 |
}
|
| 240 |
}
|
| 241 |
|
| 242 |
/**
|
| 243 |
* Configures the various Case Tracker mail options; system_settings_form().
|
| 244 |
*/
|
| 245 |
function casetracker_mail_settings() {
|
| 246 |
$form = array();
|
| 247 |
|
| 248 |
$form['casetracker_mail'] = array(
|
| 249 |
'#type' => 'fieldset',
|
| 250 |
'#title' => t('E-mail settings'),
|
| 251 |
'#collapsible' => TRUE,
|
| 252 |
'#collapsed' => FALSE,
|
| 253 |
'#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.'),
|
| 254 |
);
|
| 255 |
$form['casetracker_mail']['casetracker_mail_address'] = array(
|
| 256 |
'#type' => 'textfield',
|
| 257 |
'#title' => t('E-mail address'),
|
| 258 |
'#default_value' => variable_get('casetracker_mail_address', variable_get('site_mail', ini_get('sendmail_from'))),
|
| 259 |
'#description' => t('A valid e-mail address used in the From: of all Case Tracker generated mails.'),
|
| 260 |
);
|
| 261 |
$form['casetracker_mail']['casetracker_mail_subject'] = array(
|
| 262 |
'#type' => 'textfield',
|
| 263 |
'#title' => t('Subject'),
|
| 264 |
'#default_value' => variable_get('casetracker_mail_subject', _casetracker_mail_subject()),
|
| 265 |
'#description' => t('Enter the subject of all Case Tracker generated mails.'),
|
| 266 |
);
|
| 267 |
$form['casetracker_mail']['casetracker_mail_case_message'] = array(
|
| 268 |
'#rows' => 15,
|
| 269 |
'#type' => 'textarea',
|
| 270 |
'#title' => t('Case message'),
|
| 271 |
'#default_value' => variable_get('casetracker_mail_case_message', _casetracker_mail_case_message()),
|
| 272 |
'#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).'),
|
| 273 |
); // @todo it is not exactly clear how CCK node types (or other custom node fields) will be available as %variables.
|
| 274 |
// @todo it also doesn't appear like we can give a list of all other comments made on this particular case.
|
| 275 |
$form['casetracker_mail']['casetracker_mail_comment_message'] = array(
|
| 276 |
'#rows' => 10,
|
| 277 |
'#type' => 'textarea',
|
| 278 |
'#title' => t('Comment message'),
|
| 279 |
'#default_value' => variable_get('casetracker_mail_comment_message', _casetracker_mail_comment_message()),
|
| 280 |
'#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.'),
|
| 281 |
);
|
| 282 |
|
| 283 |
return system_settings_form($form);
|
| 284 |
}
|
| 285 |
|
| 286 |
/**
|
| 287 |
* Returns the default message for Case Tracker case mails.
|
| 288 |
*/
|
| 289 |
function _casetracker_mail_case_message() {
|
| 290 |
return
|
| 291 |
"Case status update for %case_url\n\n".
|
| 292 |
"Project: %project_title\n".
|
| 293 |
"Type: %case_type\n".
|
| 294 |
"Priority: %case_priority\n".
|
| 295 |
"Status: %case_status\n".
|
| 296 |
"Assigned: %case_assigned\n".
|
| 297 |
"Opened by: %case_author\n".
|
| 298 |
"Opened on: %case_created\n".
|
| 299 |
"Last modified: %case_changed\n\n".
|
| 300 |
"%case_description\n\n".
|
| 301 |
"%comment\n"
|
| 302 |
;
|
| 303 |
}
|
| 304 |
|
| 305 |
function _casetracker_mail_comment_message() {
|
| 306 |
return // @todo it'd be nice if this looked like the project.module with a date.
|
| 307 |
"------------------------------------------------------------------------\n\n".
|
| 308 |
"Comment by: %comment_author\n" .
|
| 309 |
"Comment title: %comment_title\n\n".
|
| 310 |
"%comment_description\n\n"
|
| 311 |
;
|
| 312 |
}
|
| 313 |
|
| 314 |
/**
|
| 315 |
* Returns the default subject line for Case Tracker mails.
|
| 316 |
*/
|
| 317 |
function _casetracker_mail_subject() {
|
| 318 |
return '[%project_title %case_type %case_number] %case_title';
|
| 319 |
}
|
| 320 |
|
| 321 |
/**
|
| 322 |
* Function to clear the possible html from a mail and generate readable txt version
|
| 323 |
*
|
| 324 |
* @param string
|
| 325 |
* @return string
|
| 326 |
*/
|
| 327 |
function _casetracker_mail_plain_description($_description) {
|
| 328 |
// tags that should be have a newline behind their ass
|
| 329 |
$tags = array(
|
| 330 |
'</h1>', '</h2>', '</h3>', '</h4>', '</h5>', '</h6>',
|
| 331 |
'</p>', '<br>', '<br/>', '<br />', '</div>', '</pre>',
|
| 332 |
'</code>', '</ul>', '</ol>', '</li>', '</dl>', '</dd>',
|
| 333 |
'</dt>',
|
| 334 |
);
|
| 335 |
foreach($tags AS $tag)
|
| 336 |
{
|
| 337 |
$_description = str_replace($tag, $tag . "\n", $_description);
|
| 338 |
}
|
| 339 |
$result = filter_xss($_description, array('dd'));
|
| 340 |
|
| 341 |
return $result;
|
| 342 |
}
|