| [ Index ] |
PHP Cross Reference of Drupal 6 (gatewave) |
[Summary view] [Print] [Text view]
1 <?php 2 // $Id: mail.inc,v 1.123 2010/01/17 00:16:15 dww Exp $ 3 4 function project_issue_mailhandler($node, $result, $i, $header, $mailbox) { 5 if ($node->type == 'project') { 6 if (node_access('create', 'project_issue')) { 7 $node->nid = preg_replace('/@.+/', '', $node->nid); 8 9 if ($node->nid) { 10 /* 11 ** Base the new entry on the node it belongs to, this ensures all 12 ** values are initially correct. 13 */ 14 $entry = node_load(array('nid' => $node->nid, 'type' => 'project_issue')); 15 } 16 17 // Possible attributes 18 $fields = array( 19 'pid' => t('Project'), 20 'category' => t('Category'), 21 'component' => t('Component'), 22 'priority' => t('Priority'), 23 'rid' => t('Version'), 24 'assigned' => t('Assigned to'), 25 'sid' => t('Status') 26 ); 27 28 /* 29 ** Only change the title if it doesn't have the old title in it. 30 ** This should prevent the title from changing due to added 31 ** prefixes. It may on occasion make false positives, but if 32 ** a title change is that minor who cares? 33 */ 34 $entry->title = (strpos($node->title, $entry->title)) ? $entry->title : $node->title; 35 36 $entry->teaser = $node->teaser; 37 $entry->body = $node->body; 38 $entry->uid = $node->uid; 39 40 foreach ($fields as $var => $text) { 41 $text = strtolower(str_replace(' ', '_', $text)); 42 if (isset($node->project_issue[$text])) { 43 $node->project_issue[$text] = trim($node->project_issue[$text]); 44 switch ($var) { 45 case 'pid': 46 $project = node_load($node->project_issue[$text]); 47 if ($project->nid) { 48 $entry->project_issue['pid'] = $project->nid; 49 } 50 break; 51 case 'category': 52 if (($category = array_search($node->project_issue[$text], project_issue_category(0, 0)))) { 53 $entry->project_issue['category'] = $category; 54 } 55 break; 56 case 'priority': 57 if (($priority = array_search($node->project_issue[$text], project_issue_priority()))) { 58 $entry->project_issue['priority'] = $priority; 59 } 60 break; 61 case 'rid': 62 if ($entry->project_issue['pid'] && ($nid = db_result(db_query("SELECT nid FROM {project_release_nodes} WHERE pid = %d AND version = '%s'", $entry->project_issue['pid'], $node->project_issue[$text]), 0))) { 63 $entry->project_issue['rid'] = $nid; 64 } 65 break; 66 case 'assigned': 67 if ($user = user_load(array('name' => $node->project_issue[$text]))) { 68 $entry->project_issue['assigned'] = $user->uid; 69 } 70 break; 71 case 'sid': 72 if (($state = array_search($node->project_issue[$text], project_issue_state()))) { 73 $entry->project_issue['sid'] = $state; 74 } 75 break; 76 case 'component': 77 if ($entry->project_issue['pid'] && ($project = node_load(array('nid' => $entry->project_issue['pid'], 'type' => 'project_project')))) { 78 if ($project && in_array($node->project_issue[$text], $project->project_issue['components'])) { 79 $entry->project_issue['component'] = $node->project_issue[$text]; 80 } 81 } 82 break; 83 } 84 } 85 } 86 87 if (empty($entry->nid)) { 88 $entry->sid = variable_get('project_issue_default_state', 1); 89 $entry->type = 'project_issue'; 90 $entry = node_validate($entry, $error); 91 $error or ($entry->nid = node_save($entry)); 92 } 93 else { 94 $error = project_comment_validate($entry); 95 $error or project_comment_save($entry); 96 } 97 } 98 else { 99 $error['user'] = t('You are not authorized to access this page.'); 100 } 101 102 if ($error && $mailbox['replies']) { 103 // Send the user his errors 104 $mailto = mailhandler_get_fromaddress($header, $mailbox); 105 $mailfrom = variable_get('site_mail', ini_get('sendmail_from')); 106 $headers = array( 107 'X-Mailer' => 'Drupal Project module (http://drupal.org/project/project)', 108 ); 109 110 $body = t('You had some errors in your submission:'); 111 foreach ($error as $field => $text) { 112 $body .= "\n * $field: $text"; 113 } 114 115 drupal_mail('project_issue_mailhandler_error', $mailto, t('E-mail submission to !sn failed - !subj', array('!sn' => variable_get('site_name', 'Drupal'), '!subj' => $header->subject)), $body, $mailfrom, $headers); 116 } 117 118 // Return a NULL result so mailhandler doesn't save the node using the default methods. 119 return NULL; 120 } 121 else { 122 return $node; 123 } 124 } 125 126 function project_mail_urls($url = 0) { 127 static $urls = array(); 128 if ($url) { 129 // If $url is an internal link (eg. '/project/project'), such 130 // as might be returned from the url() function with the 131 // $absolute parameter set to FALSE, we must remove 132 // the leading slash before passing this path through the url() 133 // function again, or otherwise we'll get two slashes in a row 134 // and thus a bad URL. 135 if (substr($url, 0, 1) == '/') { 136 $url = substr($url, 1); 137 } 138 $urls[] = strpos($url, '://') ? $url : url($url, array('absolute' => TRUE)); 139 return count($urls); 140 } 141 return $urls; 142 } 143 144 function project_mail_output(&$body, $html = 1, $format = FILTER_FORMAT_DEFAULT) { 145 static $i = 0; 146 147 if ($html) { 148 $body = check_markup($body, $format, FALSE); 149 $pattern = '@<a +([^ >]+ )*?href *= *"([^>"]+?)"[^>]*>([^<]+?)</a>@ei'; 150 $body = preg_replace($pattern, "'\\3 ['. project_mail_urls('\\2') .']'", $body); 151 $urls = project_mail_urls(); 152 if (count($urls)) { 153 $body .= "\n"; 154 for ($max = count($urls); $i < $max; $i++) { 155 $body .= '['. ($i + 1) .'] '. $urls[$i] ."\n"; 156 } 157 } 158 159 $body = preg_replace('!</?blockquote>!i', '"', $body); 160 $body = preg_replace('!</?(em|i)>!i', '/', $body); 161 $body = preg_replace('!</?(b|strong)>!i', '*', $body); 162 $body = preg_replace("@<br />(?!\n)@i", "\n", $body); 163 $body = preg_replace("@</p>(?!\n\n)@i", "\n\n", $body); 164 $body = preg_replace("@<li>@i", "* ", $body); 165 $body = preg_replace("@</li>\n?@i", "\n", $body); 166 $body = strip_tags($body); 167 $body = decode_entities($body); 168 $body = wordwrap($body, 72); 169 } 170 else { 171 $body = decode_entities($body); 172 } 173 } 174 175 function project_mail_notify($nid) { 176 global $user; 177 178 if (defined('PROJECT_NOMAIL')) { 179 return; 180 } 181 182 $node = node_load($nid, NULL, TRUE); 183 $project = node_load(array('nid' => $node->project_issue['pid'], 'type' => 'project_project')); 184 185 // Store a copy of the issue, so we can load the original issue values 186 // below. 187 $issue = drupal_clone($node); 188 189 // Load in the original issue data here, since we want a running 190 // reverse history. 191 $original_issue_data = unserialize($node->project_issue['original_issue_data']); 192 $fields = project_issue_field_labels('email'); 193 foreach ($fields as $field => $label) { 194 if ($field != 'name' && $field != 'updator') { 195 $issue->original_issue_metadata->$field = $original_issue_data->$field; 196 } 197 } 198 199 // Record users that are connected to this issue. 200 $uids = array(); 201 if (!empty($node->uid)) { 202 $uids[$node->uid] = $node->uid; 203 } 204 if (!empty($node->project_issue['assigned'])) { 205 $uids[$node->project_issue['assigned']] = $node->project_issue['assigned']; 206 } 207 208 // Create complete history of the bug report. 209 $history = array($issue); 210 $result = db_query('SELECT u.name, c.cid, c.nid, c.subject, c.comment, c.uid, c.format, pic.* FROM {project_issue_comments} pic INNER JOIN {comments} c ON c.cid = pic.cid INNER JOIN {users} u ON u.uid = c.uid WHERE c.nid = %d AND c.status = %d ORDER BY pic.timestamp', $node->nid, COMMENT_PUBLISHED); 211 212 while ($comment = db_fetch_object($result)) { 213 $comment->comment = db_decode_blob($comment->comment); 214 $comment->files = comment_upload_load_files($comment->cid); 215 $history[] = $comment; 216 // Record users that are connected to this issue. 217 if ($comment->uid) { 218 $uids[$comment->uid] = $comment->uid; 219 } 220 } 221 222 if (count($uids)) { 223 $placeholders = implode(',', array_fill(0, count($uids), '%d')); 224 array_unshift($uids, $node->project_issue['pid']); 225 $result = db_query("SELECT p.*, u.uid, u.name, u.mail FROM {project_subscriptions} p INNER JOIN {users} u ON p.uid = u.uid WHERE u.status = 1 AND p.nid = %d AND (p.level = 2 OR (p.level = 1 AND u.uid IN ($placeholders)))", $uids); 226 } 227 else { 228 $result = db_query('SELECT p.*, u.uid, u.name, u.mail FROM {project_subscriptions} p INNER JOIN {users} u ON p.uid = u.uid WHERE u.status = 1 AND p.nid = %d AND p.level = 2', $node->project_issue['pid']); 229 } 230 231 // To save workload, check here if either the anonymous role or the 232 // authenticated role has the 'view uploaded files' permission, since 233 // we only need to process each user's file access permission if this 234 // is NOT the case. 235 $check_file_perms = !db_result(db_query("SELECT COUNT(*) FROM {permission} WHERE perm LIKE '%view uploaded files%' AND rid IN (%d, %d)", DRUPAL_ANONYMOUS_RID, DRUPAL_AUTHENTICATED_RID)); 236 237 // We need to determine if node_access() checks are necessary. The 238 // check will be needed if any of the following is true: 239 // 1. The node is not published. 240 // 2. There is at least on node access control module enabled. 241 // 3. Both the anonymous and authenticated user do not have 242 // the 'access project issues' permission. 243 $allowed_roles = user_roles(FALSE, 'access project issues'); 244 if (isset($allowed_roles[DRUPAL_ANONYMOUS_RID]) || isset($allowed_roles[DRUPAL_AUTHENTICATED_RID])) { 245 $anon_auth_access = TRUE; 246 } 247 $grants = module_implements('node_grants'); 248 $check_node_access = $node->status != 1 || empty($anon_auth_access) || !empty($grants); 249 250 $params['node'] = $node; 251 $params['project'] = $project; 252 $params['history'] = $history; 253 254 $sender->name = t('!name (!site)', array('!name' => $user->name, '!site' => variable_get('site_name', 'Drupal'))); 255 $sender->mail = strtr(variable_get('project_issue_reply_to', variable_get('site_mail', ini_get('sendmail_from'))), array('%project' => $project->project['uri'])); 256 // The sender name is enclosed by double quotes below 257 // to satisfy RFC2822 <http://www.faqs.org/rfcs/rfc2822.html>, 258 // which requires double quotes when special characters (including 259 // some punctuation) are used. See example in Appendix A.1.2. 260 $from = '"' . mime_header_encode($sender->name) . "\" <$sender->mail>"; 261 262 while ($recipient = db_fetch_object($result)) { 263 // To save work, only go through a user_load if we need it. 264 if ($check_file_perms || $check_node_access) { 265 $account = user_load(array('uid' => $recipient->uid)); 266 $language = user_preferred_language($account); 267 } 268 else { 269 $language = language_default(); 270 } 271 272 $can_access = $check_node_access ? node_access('view', $node, $account) : TRUE; 273 274 if ($can_access) { 275 $display_files = $check_file_perms ? user_access('view uploaded files', $account) : TRUE; 276 277 $params['display_files'] = $display_files; 278 drupal_mail('project_issue', 'project_issue_update_notification', $recipient->mail, $language, $params, $from); 279 } 280 } 281 282 if (is_array($project->project_issue['mail_copy_filter']) && count(array_filter($project->project_issue['mail_copy_filter'])) && !$project->project_issue['mail_copy_filter'][$node->project_issue['category']]) { 283 return; 284 } 285 286 if (is_array($project->project_issue['mail_copy_filter_state']) && count(array_filter($project->project_issue['mail_copy_filter_state'])) && !$project->project_issue['mail_copy_filter_state'][$node->project_issue['sid']]) { 287 return; 288 } 289 290 if (!empty($project->project_issue['mail_copy'])) { 291 $params['display_files'] = TRUE; 292 $message['body'][] = $links; 293 $message['body'][] = project_mail_generate_followup_mail_body($node, $history, TRUE); 294 drupal_mail('project_issue', 'project_issue_update_notification', $project->project_issue['mail_copy'], language_default(), $params, $from); 295 } 296 } 297 298 /* 299 * Implementation of hook_mail() 300 */ 301 function project_issue_mail($key, &$message, $params) { 302 global $base_url; 303 304 switch ($key) { 305 case "project_issue_update_notification": 306 // There could be stale data in the cached node, so reset the cache. 307 $node = $params['node']; 308 $project = $params['project']; 309 $history = $params['history']; 310 $fields = project_issue_field_labels('email'); 311 312 $domain = preg_replace('|.+://([a-zA-Z0-9\._-]+).*|', '\1', $base_url); 313 314 $message['headers'] += array( 315 'Date' => date('r'), 316 'X-Mailer' => 'Drupal Project module (http://drupal.org/project/project)', 317 'List-Id' => "$project->title <". $project->project['uri'] ."-issues-$domain>", 318 'List-Archive' => '<'. url('project/issues/'. $project->project['uri'], array('absolute' => TRUE)) .'>', 319 'List-Subscribe' => '<'. url('project/issues/subscribe-mail/'. $project->project['uri'], array('absolute' => TRUE)) .'>', 320 'List-Unsubscribe' => '<'. url('project/issues/subscribe-mail/'. $project->project['uri'], array('absolute' => TRUE)) .'>' 321 ); 322 323 // Comments exist, set headers accordingly. 324 if (count($history) > 1) { 325 foreach ($history as $comment) { 326 // We need the most recent cid and the next most recent cid for the 327 // message headers. Instead of issuing another query, just keep track 328 // of them here. 329 $previous_cid = isset($cid) ? $cid : ''; 330 $cid = isset($comment->cid) ? $comment->cid : 0; 331 } 332 $message['headers']['Message-Id'] = "<type=project&nid=$node->nid&cid=$cid&host=@$domain>"; 333 $message['headers']['In-Reply-To'] = "<type=project&nid=$node->nid&host=@$domain>"; 334 $message['headers']['References'] = "<type=project&nid=$node->nid&host=@$domain> <type=project&nid=$node->nid&cid=$previous_cid&host=@$domain> <type=project&nid=$node->nid&revcount=1&host=@$domain>"; 335 } else { 336 // Only original issue in this email. 337 $message['headers']['Message-Id'] = "<type=project&nid=$node->nid&host=@$domain>"; 338 } 339 340 project_mail_output($node->title, 0); 341 $message['subject'] = t('[!short_name] [!category] !title', array('!short_name' => $project->project['uri'], '!category' => $node->project_issue['category'], '!title' => $node->title)); 342 343 // Create link to related node 344 $links = t('Issue status update for !link', array('!link' => "\n". url("node/$node->nid", array('absolute' => TRUE)))) ."\n"; 345 $links .= t('Post a follow up: !link', array('!link' => "\n". url("comment/reply/$node->nid", array('fragment' => 'comment-form', 'absolute' => TRUE)))) ."\n"; 346 $message['body'][] = $links; 347 $message['body'][] = project_mail_generate_followup_mail_body($node, $history, $params['display_files']); 348 349 break; 350 351 case 'project_issue_critical_summary': 352 $project = $params['project']; 353 $message['headers'] += array( 354 'Date' => date('r'), 355 'X-Mailer' => 'Drupal Project Issues module (http://drupal.org/project/project_issue)', 356 'List-Id' => "$project->title <". preg_replace('|.+://([a-zA-Z0-9\._-]+).*|', '\1', $base_url) .'-project-issues-digest>', 357 'List-Archive' => '<'. url('project/issues', array('query' => array('priorities' => '1'), 'absolute' => TRUE)) .'>', 358 ); 359 $message['subject'] = t('Release critical bugs for !date', array('!date' => date('F d, Y', time()))); 360 $message['body'][] = $params['body']; 361 break; 362 363 case 'project_issue_reminder': 364 $sender->name = variable_get('site_name', ''); 365 $sender->mail = variable_get('site_mail', ''); 366 $message['headers'] += array( 367 'Return-Path' => "<$sender->mail;>", 368 'Date' => date('r'), 369 'From' => "$sender->name <$sender->mail>", 370 'X-Mailer' => 'Drupal Project Issues module (http://drupal.org/project/project_issue)', 371 'List-Id' => "$sender->name <project-reminder-". preg_replace('|.+://([a-zA-Z0-9\._-]+).*|', '\1', $base_url) .'>', 372 'List-Archive' => '<'. url('project', array('absolute' => TRUE)) .'>', 373 ); 374 $message['subject'] = t('Your submitted bugs for !date', array('!date' => date('F d, Y', time()))); 375 $message['body'][] = $params['body']; 376 break; 377 } 378 } 379 380 /** 381 * Format the body of an issue followup email. 382 * 383 * @param $node 384 * The issue node. 385 * @param $history 386 * An array containing the history of issue followups. 387 * @param $display_files 388 * Boolean indicating if file attachments should be displayed. 389 * @return 390 * A string of the email body. 391 */ 392 function project_mail_generate_followup_mail_body($node, $history, $display_files) { 393 global $user; 394 static $output_with_files = NULL, $output_without_files = NULL; 395 396 // Return cached output if available. 397 if ($display_files) { 398 if (isset($output_with_files)) { 399 return $output_with_files; 400 } 401 } 402 else { 403 if (isset($output_without_files)) { 404 return $output_without_files; 405 } 406 } 407 408 // Get most recent update. 409 $entry = array_pop($history); 410 411 $node->project_issue['updator'] = $entry->name ? $entry->name : $user->name; 412 413 // Check if the latest entry is actually the initial issue. 414 if (empty($history)) { 415 $metadata_previous = new stdClass(); 416 // Have to get the metadata into the entry object. 417 $metadata_entry = $entry->original_issue_metadata; 418 $content = $entry->body; 419 } 420 else { 421 $metadata_previous = end($history); 422 // If the previous was the original issue, then we need to pull 423 // out the metadata from project_issue. 424 if (isset($metadata_previous->original_issue_metadata)) { 425 $metadata_previous = $metadata_previous->original_issue_metadata; 426 } 427 $metadata_entry = $entry; 428 $content = $entry->comment; 429 } 430 431 $fields = project_issue_field_labels('email'); 432 $comment_changes = project_issue_metadata_changes($node, $metadata_previous, $metadata_entry, $fields); 433 434 // Since $node->name will always be the original issue author, and since 435 // $node->project_issue['updator'] isn't a property of either $previous or 436 // $entry, these two properties will never show up as being different when 437 // project_issue_metadata_changes() is called, and therefore neither of 438 // these will ever be elements of the $comment_changes array. Since we do 439 // want them to be printed in issue emails, we just need to add their labels 440 // back into the $comment_changes array here, so that 441 // theme_project_issue_mail_summary_field() will know to print the data for 442 // these two fields. 443 $comment_changes['name'] = array( 444 'label' => $fields['name'], 445 ); 446 $comment_changes['updator'] = array( 447 'label' => $fields['updator'], 448 ); 449 450 $summary = theme('project_issue_mail_summary', $entry, $node, $comment_changes, $display_files); 451 452 // Create main body content 453 project_mail_output($content, 1, $entry->format); 454 $body = "$content\n$entry->name\n"; 455 456 $hr = str_repeat('-', 72); 457 458 if (count($history)) { 459 460 $body .= "\n\n"; 461 $body .= t('Original issue:') ."\n"; 462 $body .= project_mail_format_entry(array_shift($history), $display_files, TRUE); 463 if (count($history)) { 464 $body .= "\n". t('Previous comments (!count):', array('!count' => count($history))) ."\n"; 465 foreach ($history as $entry) { 466 $body .= project_mail_format_entry($entry, $display_files); 467 } 468 } 469 } 470 471 $output = "$summary\n$body"; 472 473 // Set cached output. 474 if ($display_files) { 475 $output_with_files = $output; 476 } 477 else { 478 $output_without_files = $output; 479 } 480 481 return $output; 482 } 483 484 /** 485 * Themes the display of the issue metadata summary 486 * that is shown at the top of an issue emai. 487 * 488 * @param $entry 489 * The object representing the current entry. This will be a node object 490 * if the current entry is the original issue node; otherwise this will be 491 * a comment object. 492 * @param $node 493 * The original issue node object. 494 * @param $changes 495 * A nested array containing the metadata changes between the original 496 * issue and the first comment, or two consecutive comments. This array 497 * is the output of the project_issue_metadata_changes() function. 498 * @param $display_files 499 * Boolean indicating if file attachments should be displayed. 500 * @return 501 * A string containing the themed text of the issue metadata table. 502 */ 503 function theme_project_issue_mail_summary($entry, $node, $changes, $display_files) { 504 // Mail summary (status values). 505 $summary = ''; 506 foreach ($changes as $field => $change) { 507 $summary .= theme('project_issue_mail_summary_field', $node, $field, $change); 508 } 509 510 $summary .= project_mail_format_attachments($entry, $display_files); 511 return $summary; 512 } 513 514 /** 515 * Theme the email output of one project issue metadata field. 516 * 517 * @param $node 518 * The project issue node object. 519 * @param $field_name 520 * The name of the field to theme. 521 * @param $change 522 * A nested array containing changes to project issue metadata 523 * for the given issue or comment. 524 * @return 525 * A themed line or lines of text ready for inclusion into the email body. 526 */ 527 function theme_project_issue_mail_summary_field($node, $field_name, $change) { 528 // We need to run the label name through strip_tags here so that 529 // the spacing isn't messed up if there are HTML tags in $change['label']. 530 $text = str_pad(strip_tags($change['label']). ':', 14); 531 $summary_row = ''; 532 if (!empty($change['label']) && isset($change['old']) && isset($change['new']) && $field_name != 'updator' && $field_name != 'name') { 533 if (is_array($change['old']) || is_array($change['new'])) { 534 $removed = array(); 535 if (is_array($change['old'])) { 536 foreach ($change['old'] as $item) { 537 $removed[] = '-'. $item; 538 } 539 } 540 elseif (!empty($change['old'])) { 541 $removed[] = '-'. $change['old']; 542 } 543 544 $added = array(); 545 if (is_array($change['new'])) { 546 foreach ($change['new'] as $item) { 547 $added[] = '+'. $item; 548 } 549 } 550 elseif (!empty($change['new'])) { 551 $added[] = '+'. $change['new']; 552 } 553 554 $summary_row = " $text". trim(implode(', ', $removed). ' ' .implode(', ', $added)) ."\n"; 555 } 556 else { 557 $summary_row .= "-$text". project_issue_change_summary($field_name, $change['old']) ."\n"; 558 $summary_row .= "+$text". project_issue_change_summary($field_name, $change['new']) ."\n"; 559 } 560 } 561 elseif (!empty($change['label'])) { 562 if (!empty($change['new'])) { 563 // This condition is necessary when building the first email message of an 564 // issue, since in this case $change['old'] should not exist. 565 if (is_array($change['new'])) { 566 $summary_row .= " $text". implode(', ', $change['new']) ."\n"; 567 } 568 else { 569 $summary_row .= " $text". project_issue_change_summary($field_name, $change['new']) ."\n"; 570 } 571 } 572 else { 573 // This condition is where fields that are stored in the $node object and 574 // which haven't changed but should be printed anyway get processed. 575 // For example, the project, category, etc. are printed in each email 576 // whether or not they have changed. 577 // @TODO: Should we really assume the field in is $node->project_issue[]? 578 if (isset($node->project_issue[$field_name])) { 579 $summary_row .= " $text". project_issue_change_summary($field_name, $node->project_issue[$field_name]) ."\n"; 580 } 581 } 582 } 583 // HTML tags in the email will make it hard to read, so pass 584 // this output through strip_tags(). 585 return strip_tags($summary_row); 586 } 587 588 /** 589 * Formats attachments for issue notification e-mails. 590 * 591 * @param $entry 592 * An issue or followup object containing the file data. 593 * @param $display_files 594 * Boolean indicating if file attachments should be displayed. 595 * @return 596 * A formatted string of file attachments. 597 */ 598 function project_mail_format_attachments($entry, $display_files) { 599 $output = ''; 600 if ($display_files && is_array($entry->files)) { 601 foreach ($entry->files as $file) { 602 // Comment upload has it's files in an array, so cast to an object 603 // for consistency. 604 $file = (object) $file; 605 $output .= ' '. str_pad(t('Attachment') .':', 14) . file_create_url($file->filepath) .' ('. format_size($file->filesize) .")\n"; 606 } 607 } 608 return $output; 609 } 610 611 /** 612 * Format an issue entry for display in an email. 613 * 614 * @param entry 615 * The entry to the formatted. 616 * @param $display_files 617 * Boolean indicating if file attachments should be displayed. 618 * @param is_original 619 * Whether this entry is the original issue or a followup. Followup issues 620 * will be automatically numbered. 621 * @return 622 * Formatted text for the entry. 623 */ 624 function project_mail_format_entry($entry, $display_files, $is_original = FALSE) { 625 static $history_count = 1; 626 $hr = str_repeat('-', 72); 627 $output = "$hr\n"; 628 629 // Nodes and comments have different stamp fields. 630 $timestamp = isset($entry->created) ? $entry->created : $entry->timestamp; 631 632 if (!$is_original) { 633 $output .= "$entry->subject -- "; 634 } 635 636 $output .= format_date($timestamp, 'large') ." : $entry->name\n"; 637 638 if (!$is_original) { 639 $output .= url("node/$entry->nid", array('fragment' => "comment-$entry->cid", 'absolute' => TRUE)) ."\n"; 640 } 641 642 $output .= project_mail_format_attachments($entry, $display_files); 643 644 // Must distinguish between nodes and comments -- here we do it 645 // by looking for a revision ID. 646 if (empty($entry->vid)) { 647 $content = $entry->comment; 648 } 649 else { 650 $content = $entry->body; 651 } 652 653 project_mail_output($content, 1, $entry->format); 654 655 if ($content) { 656 $output .= "\n$content"; 657 } 658 return $output; 659 } 660
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated: Thu Mar 24 11:18:33 2011 | Cross-referenced by PHPXref 0.7 |