rfc822_header->to as $recip) $toList[] = $recip->mailbox . $delimiter . $recip->host; foreach ($message->rfc822_header->cc as $recip) $ccList[] = $recip->mailbox . $delimiter . $recip->host; foreach ($message->rfc822_header->bcc as $recip) $bccList[] = $recip->mailbox . $delimiter . $recip->host; foreach ($message->rfc822_header->reply_to as $sender) $replyToList[] = $sender->mailbox . $delimiter . $sender->host; foreach ($message->rfc822_header->from as $sender) $fromList[] = $sender->mailbox . $delimiter . $sender->host; // too many recipients? log it and possibly send alert // $total_recips = sizeof($toList) + sizeof($ccList) + sizeof($bccList); if ($total_recips >= $sl_mass_mail_limit) { global $username, $sl_log_mass_mailing_show_recipients, $sl_log_mass_mailing_show_message_body, $body, $sl_log_mass_mailing_show_subject, $sl_log_mass_mailing_show_from, $sl_log_mass_mailing_show_reply_to, $sl_dateformat, $sl_namelookups, $subject; $msg = 'Total ' . $total_recips . ' recipients'; $address_delim = ', '; if ($sl_log_mass_mailing_show_recipients) { $msg .= ' (TO: ' . implode($address_delim, $toList) . ')'; $msg .= ' (CC: ' . implode($address_delim, $ccList) . ')'; $msg .= ' (BCC: ' . implode($address_delim, $bccList) . ')'; } if ($sl_log_mass_mailing_show_from) $msg .= ' (FROM: ' . implode($address_delim, $fromList) . ')'; if ($sl_log_mass_mailing_show_reply_to) $msg .= ' (REPLY-TO: ' . implode($address_delim, $replyToList) . ')'; if ($sl_log_mass_mailing_show_subject) $msg .= ' (SUBJECT: ' . $subject . ')'; if ($sl_log_mass_mailing_show_message_body) $msg .= ' (BODY: ' . $body . ')'; sl_logit('MASS_MAILING', $msg); } } /** * Monitor mails when they are sent * */ function sl_monitor_sent_msgs_do($args) { $delimiter = '@'; // if the message was not sent, don't log it // if (!$args[0]) return; global $domain, $only_log_domains, $skip_domains, $sl_log_events, $sl_log_outgoing_messages_show_from, $sl_log_outgoing_messages_show_reply_to, $sl_log_outgoing_messages_show_subject, $sl_log_outgoing_messages_show_recipients, $sl_log_outgoing_messages_show_message_body; sl_get_config(); if (!in_array('OUTGOING_MAIL', $sl_log_events) || (isset($only_log_domains['OUTGOING_MAIL']) && is_array($only_log_domains['OUTGOING_MAIL']) && !empty($only_log_domains['OUTGOING_MAIL']) && !in_array($domain, $only_log_domains['OUTGOING_MAIL'])) || (isset($skip_domains['OUTGOING_MAIL']) && is_array($skip_domains['OUTGOING_MAIL']) && !empty($skip_domains['OUTGOING_MAIL']) && in_array($domain, $skip_domains['OUTGOING_MAIL']))) return; // grab TO, CC, and BCC fields from message // if (check_sm_version(1, 5, 2)) $message = $args[1]; else $message = $args[2]; $toList = array(); $ccList = array(); $bccList = array(); $replyToList = array(); $fromList = array(); foreach ($message->rfc822_header->to as $recip) $toList[] = $recip->mailbox . $delimiter . $recip->host; foreach ($message->rfc822_header->cc as $recip) $ccList[] = $recip->mailbox . $delimiter . $recip->host; foreach ($message->rfc822_header->bcc as $recip) $bccList[] = $recip->mailbox . $delimiter . $recip->host; foreach ($message->rfc822_header->reply_to as $sender) $replyToList[] = $sender->mailbox . $delimiter . $sender->host; foreach ($message->rfc822_header->from as $sender) $fromList[] = $sender->mailbox . $delimiter . $sender->host; // have to remove < and > because otherwise the message ID // will get removed entirely by the strip_tags() call in // sl_logit() // if (!empty($message->rfc822_header->message_id)) { $msg = 'Message-ID: ' . str_replace(array('<', '>'), '', $message->rfc822_header->message_id); //$msg = 'Message-ID: ' . strtr($message->rfc822_header->message_id, '<>', '()'); } else { $msg = 'Message-ID: unavailable'; } $address_delim = ', '; if ($sl_log_outgoing_messages_show_recipients) { $msg .= ' (TO: ' . implode($address_delim, $toList) . ')'; $msg .= ' (CC: ' . implode($address_delim, $ccList) . ')'; $msg .= ' (BCC: ' . implode($address_delim, $bccList) . ')'; } if ($sl_log_outgoing_messages_show_from) $msg .= ' (FROM: ' . implode($address_delim, $fromList) . ')'; if ($sl_log_outgoing_messages_show_reply_to) $msg .= ' (REPLY-TO: ' . implode($address_delim, $replyToList) . ')'; global $body, $subject; if ($sl_log_outgoing_messages_show_subject) $msg .= ' (SUBJECT: ' . $subject . ')'; ///$msg .= ' (SUBJECT: ' . $message->subject . ')'; if ($sl_log_outgoing_messages_show_message_body) $msg .= ' (BODY: ' . $body . ')'; ///$msg .= ' (BODY: ' . $message->body_part . ')'; sl_logit('OUTGOING_MAIL', $msg); } /** * Build log fields and send off to be logged * * Custom event types are acceptable as long as they are enabled * in the configuration file. * * @param string $event The event type * @param string $message The log message - note that any HTML * tags will be removed (optional; default = empty) * @param string $user Override for username (if not given, * will use the SquirrelMail user found * in SESSION. (optional; default = empty) * */ function sl_logit($event, $message='', $user='') { global $sl_namelookups, $sl_dateformat, $username, $domain; sl_get_config(); // construct log fields // if (empty($user)) $user = $username; $timestamp = time(); $date_str = sldate($sl_dateformat, $timestamp); if (!sqgetGlobalVar('REMOTE_ADDR', $user_address, SQ_SERVER)) $user_address = ''; if ($sl_namelookups) $user_address .= ' (' . gethostbyaddr($user_address) . ')'; // remove HTML from message and bring multiline into one line // $message = strip_tags(preg_replace("/(\r\n|\n|\r)+/", ' ', $message)); // send off to be logged // sl_send_to_log($event, $timestamp, $date_str, $user, $domain, $user_address, $message); } /** * Dispatch fields to be logged to the registered log types * * Also sends alerts if needed. * * Custom event types are acceptable as long as they are enabled * in the configuration file. * * @param string $event The event type * @param int $timestamp The date and time of the event * @param string $date_str A formatted, humyn-readable version of * the $timestamp * @param string $user The user that triggered the event (optional; * default = empty) * @param string $dom The user's domain (optional; default = empty) * @param string $remote_addr The user's IP and/or hostname * information (optional; default = empty) * @param string $message The log message (optional; deafult = empty) * */ function sl_send_to_log($event, $timestamp, $date_str, $user='', $dom='', $remote_addr='', $message='') { global $sl_logs, $sl_send_alerts, $sl_alert_to, $sl_alert_cc, $sl_alert_bcc, $sl_alert_subject_template; sl_get_config(); // find empty parameters // if (empty($user)) $user = 'N/A'; if (empty($dom)) $dom = 'N/A'; if (empty($remote_addr)) $remote_addr = 'N/A'; // send message to each log type that is enabled // foreach ($sl_logs as $log => $allowed_events) { // skip if the current event not logged for any log type // if (!in_array($event, array_keys($allowed_events))) continue; // construct full log message // $full_message = str_replace(array('%1', '%2', '%3', '%4', '%5', '%6', '%7'), array($event, $user, $dom, $remote_addr, $timestamp, $date_str, $message), $allowed_events[$event]); if ($log == 'FILE') { sl_log_to_file($full_message); } else if ($log == 'SQL') { include_once(SM_PATH . 'plugins/squirrel_logger/database_functions.php'); // note that in this case, $full_message will just be the revised event name sl_log_to_db($full_message, $user, $dom, $remote_addr, $timestamp, $message); } else if (strpos($log, 'SYSTEM') === 0) { sl_log_to_system_log($log, $full_message); } } // send alerts if needed // if (in_array($event, array_keys($sl_send_alerts))) { // construct full log message // $body = str_replace(array('%1', '%2', '%3', '%4', '%5', '%6', '%7'), array($event, $user, $dom, $remote_addr, $timestamp, $date_str, $message), $sl_send_alerts[$event]); include_once(SM_PATH . 'plugins/squirrel_logger/alert_functions.php'); // collect recipients // if (!empty($sl_alert_to[$event])) $to = $sl_alert_to[$event]; else $to = ''; if (!empty($sl_alert_cc[$event])) $cc = $sl_alert_cc[$event]; else $cc = ''; if (!empty($sl_alert_bcc[$event])) $bcc = $sl_alert_bcc[$event]; else $bcc = ''; // build subject // $subject = str_replace(array('%1', '%2'), array($event, $user), $sl_alert_subject_template); // send it // sl_send_alert($body, $subject, $to, $cc, $bcc); } } /** * Log a message to a file * * @param string $message The log message * */ function sl_log_to_file($message) { global $sl_logfile; sl_get_config(); // write final message to file // if ($FILE = @fopen($sl_logfile, 'ab')) { @fwrite($FILE, $message); // @fwrite($FILE, $message, 8192); fclose($FILE); } } /** * Log a message to the system log * * @param string $log The details that specify the * log facility, priority, ident, * options, etc. * @param string $message The message to be logged * */ function sl_log_to_system_log($log, $message) { global $sl_fail_silently, $sl_use_GMT; sl_get_config(); // $log_details will potentially have these elements: // "SYSTEM" (fixed), priority, facility, ident, options // $log_details = explode(':', $log, 5); if (empty($log_details[1])) $log_details[1] = LOG_INFO; else eval('$log_details[1] = ' . $log_details[1] . ';'); // change from string to (integer) constant // if we have no openlog() details, then don't use it // if (sizeof($log_details) == 2) { syslog($log_details[1], $message); return; } // make sure we have default facility // if (empty($log_details[2])) $facility = LOG_SYSLOG; else eval('$facility = ' . $log_details[2] . ';'); // change from string to (integer) constant // make sure we have default ident // if (empty($log_details[3])) $log_details[3] = 0; // make sure we have default options // if (empty($log_details[4])) $options = 0; else eval('$options = ' . $log_details[4] . ';'); // change from string to (integer) constant // note that the use of sq_call_function_suppress_errors() // requires SM 1.4.12, SM 1.5.2 or Compatibility 2.0.10 // $result = sq_call_function_suppress_errors('openlog', array($log_details[3], $options, $facility)); if (!$result) if ($sl_fail_silently) return; else { if (empty($log_details[2])) $log_details[2] = ''; if (empty($log_details[3])) $log_details[3] = ''; if (empty($log_details[4])) $log_details[4] = ''; sl_error('ERROR: cannot open system log facility ' . $log_details[2] . ' with ident ' . $log_details[3] . ' and options ' . $log_details[4]); exit; } // now we can log, but make sure to obey timezone setting // if ($sl_use_GMT) { $saved_timezone = getenv('TZ'); putenv('TZ=UTC'); sq_call_function_suppress_errors('syslog', array($log_details[1], $message)); sq_call_function_suppress_errors('closelog'); putenv('TZ=' . $saved_timezone); } else { sq_call_function_suppress_errors('syslog', array($log_details[1], $message)); sq_call_function_suppress_errors('closelog'); } } /** * Print out unexpected error * * Program execution usually should halt after calling this function * * @param string $msg The error message * */ function sl_error($msg) { // don't get caught in a loop of trying to re-report errors of errors! // global $color, $reporting_error_for_squirrel_logger, $oTemplate; $reporting_error_for_squirrel_logger = 1; if (check_sm_version (1, 5, 2) && !is_object($oTemplate)) sl_finish_sm_init(); $ret = plain_error_message($msg, $color); if (check_sm_version (1, 5, 2)) { echo $ret; global $oTemplate; $oTemplate->display('footer.tpl'); } } /** * Finish SquirrelMail initialization tasks just enough to be * able to display an error when one occurs before output is * otherwise expected. * */ function sl_finish_sm_init() { if (check_sm_version(1, 5, 2)) { include_once(SM_PATH . 'functions/display_messages.php' ); include_once(SM_PATH . 'functions/page_header.php'); include_once(SM_PATH . 'functions/html.php'); global $sTemplateID, $oTemplate, $squirrelmail_language; $sTemplateID = Template::get_default_template_set(); $oTemplate = Template::construct_template($sTemplateID); set_up_language($squirrelmail_language, true); return; } return; //NOTE: The following are copied from another function in the same_ip plugin that does the same thing, except that it appears to need the following because the error message is i18n-ized, whereas in Squirrel Logger, it is not. However, I am keeping the following just in case I change that fact. if (check_sm_version(1, 5, 0)) { include_once(SM_PATH . 'include/load_prefs.php'); return; } if (check_sm_version(1, 4, 0)) { // the following line is only needed because webmail.php // doesn't include validate.php; argh! // include_once(SM_PATH . 'functions/i18n.php'); include_once(SM_PATH . 'functions/display_messages.php'); return; } }