'); /** * Implementation of hook_autoload_info(). */ function messaging_autoload_info() { return array( 'Messaging_Message' => array('file' => 'classes/messaging_message.class.inc'), 'Messaging_Send_Method' => array('file' => 'classes/messaging_method.class.inc'), 'Messaging_Mail_Method' => array('file' => 'classes/messaging_method.class.inc'), 'Messaging_Message_Template' => array('file' => 'classes/messaging_message_template.class.inc'), ); } /** * Implementation of hook_help(). */ function messaging_help($path, $arg) { switch ($path) { case 'admin/help#messaging': $output = '

' . t('The messaging module is the engine that handles outgoing messages and message queueing for different sending methods.') . '

'; $output .= '

' . t('You need to enable one or more of the included plug-ins to be able to actually take advantage of it.') . '

'; return $output; default: if ($arg[0] == 'admin') { if ($arg[1] == 'settings' && $arg[2] == 'filters') { return '

'. t('Filters are used also for messaging. If the input format is to be used only for messaging you don\'t need to allow any role for it.') .'

'; } if ($arg[1] == 'messaging') { require_once drupal_get_path('module', 'messaging') .'/messaging.admin.inc'; return messaging_admin_help($path, $arg); } } } } /** * Implementation of hook_menu() */ function messaging_menu() { $items['admin/messaging'] = array( 'title' => 'Messaging', 'access arguments' => array('administer messaging'), 'description' => 'Administer and configure messaging', 'page callback' => 'system_admin_menu_block_page', 'file' => 'system.admin.inc', 'file path' => drupal_get_path('module', 'system'), ); $items['admin/messaging/settings'] = array( 'title' => 'Messaging settings', 'description' => 'Configuration of messaging framework', 'page callback' => 'drupal_get_form', 'page arguments' => array('messaging_admin_settings'), 'access arguments' => array('administer messaging'), 'file' => 'messaging.admin.inc', ); $items['admin/messaging/settings/overview'] = array( 'title' => 'Messaging', 'description' => 'Configuration of sending methods', 'type' => MENU_DEFAULT_LOCAL_TASK, 'weight' => -10, ); $items['admin/messaging/settings/method'] = array( 'title' => 'Send methods', 'description' => 'Configuration of sending methods', 'page callback' => 'drupal_get_form', 'page arguments' => array('messaging_admin_method_settings'), 'access arguments' => array('administer messaging'), 'weight' => -10, 'file' => 'messaging.admin.inc', 'type' => MENU_LOCAL_TASK, ); $items['admin/messaging/settings/method/overview'] = array( 'title' => 'General', 'description' => 'General settings', 'type' => MENU_DEFAULT_LOCAL_TASK, 'weight' => -10, ); $items['admin/messaging/template'] = array( 'title' => 'Message templates', 'description' => 'Configuration of message templates', 'page callback' => 'messaging_admin_template', 'access arguments' => array('administer messaging'), 'file' => 'messaging.admin.inc', ); $items['admin/messaging/template/edit'] = array( 'title' => 'Message templates', 'page callback' => 'messaging_admin_template_edit', 'type' => MENU_CALLBACK, 'access arguments' => array('administer messaging'), 'file' => 'messaging.admin.inc', ); return $items; } /** * Implementation of hook_perm() */ function messaging_perm() { return array('administer messaging'); } /** * Implementation of hook_user(). * * Adds fieldset and default sending method setting. */ function messaging_user($type, $edit, &$user, $category = NULL) { switch ($type) { case 'form': if ($category == 'account' && ($list = messaging_method_list($user))) { $form['messaging'] = array( '#type' => 'fieldset', '#title' => t('Messaging settings'), '#weight' => 5, '#collapsible' => TRUE, ); $form['messaging']['messaging_default'] = array( '#type' => 'select', '#title' => t('Default send method'), '#default_value' => messaging_method_default($user), '#options' => $list, '#description' => t('Default sending method for getting messages from this system.'), '#disabled' => count($list) == 1, ); return $form; } break; } } /** Messaging API **/ /** * Send message to user represented by account * * We are applying same output filter for everybody, depending on send method * * The final rendering of the message depends on send method too. I.e. a mail messaging * method may want to insert '--' before the body footer. * * @ TODO Consider whether it makes sense to allow users decide on formatting * * @param $account * User object to recieve message. * @param $message * Array of message parts that will be compiled depending on send method. * Mandatory message parts, which may have nexted parts are: * - 'type' * - 'subject' * - 'body'. The message body may have 'header', 'content', 'footer', 'etc' * @param $method * Optional send method. Defaults to the user account predefined method */ function messaging_message_send_user($account, $message, $method = NULL, $queue = 0) { messaging_debug('Sending message to user', array('account' => $account, 'message' => $message, 'method' => $method)); // Build array of parameters so they can be overridden by callbacks $method = $method ? $method : messaging_method_default($account); $message = messaging_message_build($message); $message->method = $method; $message->queue = $queue; // Now check that we have a destination for this user account. If set to FALSE we just don't try anymore $message->destination = messaging_user_destination($account, $method); $message->set_user($account); // Send the message or, if no destination, abort the message sending if (!empty($message->destination)) { messaging_debug('Found destination for user, sending message', array('method' => $method, 'destination' => $message->destination)); return $message->send(); } else { // Save the message, let it there for further reference messaging_log('Destination not available for user account', array('method' => $method, 'account' => $account)); $message->set_error('Destination not available for user account'); } return FALSE; } /** * Get destination from user account. * * This will handle also anonymous user accounts that should have a 'destination' property */ function messaging_user_destination($account, $method) { if ($send_method = messaging_send_method($method)) { return $send_method->user_destination($account); } } /** * Send message to array of destinations using the same method. The message is rendered just once. * * The $message array may have the following elements * 'subject' => Message subject, may be already rendered or not * 'body' => Message content, may be already rendered or not * 'params' => Optional message params, indexed by sending method group * I.e. params for mail methods will be in $message['params']['mail'] * 'render' => Optional flag to mark the message subject and body as rendered * 'sender' => Optional int to identify message sender, may be $user->uid * 'sender_account' => Optional user account to use as message sender * @param $destinations * Array of destinations for sending. * The element type depends on sending method so it can be a list of e-mail addresses, user accounts, etc * @param $message * Message object or array, not rendered * @param $method * Sending method. Unlike for messaging_message_send_user() for which the sending method may be user's default * it is not an optional parameter for this function. * @param $queue * Optional flag, 0 for normal queueing, 1 to force queueing. * We may want to force queueing for bulk messaging. Otherwise it will depend on the sending method * wether to queue the messages (for pull methods) or not (push methods) */ function messaging_message_send($destinations, $message, $method, $queue = 0) { messaging_debug('Sending message', array('destinations' => $destinations, 'message' => $message, 'method' => $method, 'queue' => $queue)); // Get default sending method, or default for this user account $method = $method ? $method : messaging_method_default(NULL); // Convert into an object and add all the information into the message object $message = messaging_message_build($message); $message->method = $method; $message->type = 'outgoing'; $message->queue = $queue; if ($send_method = messaging_send_method($method)) { if ($queue) { $results = $send_method->queue_multiple($message, $destinations); } else { $results = $send_method->send_multiple($message, $destinations); } } if (empty($results)) { watchdog('messaging', 'Message could not be delivered for method %method', array('%method' => $method), WATCHDOG_ERROR); } return isset($results) ? $results : array(); } /** * Send for real, finally invoking method's callback function * * This sends messages one by one, so the callback function only need to support a single destination * Specific parameters for this message group are processed here too * * @param $destination * Single destination, may be email, user account, etc... * @param $message * Message object * @param $method * Sending method * * @return boolean * Message successfully sent */ function messaging_message_send_out($destination, $message, $method) { $message = messaging_message_build($message); $message->type = 'outgoing'; $message->destination = $destination; $message->method = $method; $result = $message->send(); if ($result === FALSE) { watchdog('messaging', 'Message could not be delivered for method %method, destination %destination', array('%method' => $method, '%destination' => $destination), WATCHDOG_ERROR); } return $result; } /** * Implementation of hook_cron() * * Process queued messages for delivery */ function messaging_cron() { messaging_store('queue_process'); messaging_store('queue_cleanup'); } /** * Pull pending messages for given methods and user accounts * * Each returned message will be an array with the following elements * - 'uid', destination uid * - 'sender', originating uid * - 'subject', message subject to be rendered * - 'body', message body to be rendered * @param $method * Send method * @param $users * User id or array of user id's * @param $limit * Optional limit for number of messages * @param $delete * Optional whether to delete messages when fetching * @return array() * Array of pending messages. */ function messaging_pull_pending($method, $users = NULL, $limit = 0, $delete = TRUE) { $params['method'] = $method; $params['queue'] = 1; if (isset($users)) { $params['uid'] = $users; } $messages = messaging_store('get', $params); // Not exactly delete but mark as sent if ($messages && $delete) { messaging_store('sent', array_keys($messages)); } return $messages; } /** * Returns list of messaging methods for a type * * I.e. all messaging methods of pull type */ function messaging_method_type($type) { $result = array(); foreach (messaging_method_info() as $method => $info) { if ($info['type'] & $type) { $result[$method] = $info; } } return $result; } /** * List sending methods * * @param $account * Optional user account, for checking permissions against this account */ function messaging_method_list($account = NULL) { $info = messaging_method_info(NULL, 'name'); if ($account) { foreach (array_keys($info) as $method) { // Check access for each method and check destination if (!messaging_method_permission($method, $account) || !messaging_user_destination($account, $method)) { unset($info[$method]); } } } return $info; } /** * Check permission for method and account * * @param $method * Sending method id * @param $account * User account to check permission */ function messaging_method_permission($method, $account = NULL) { $info = messaging_method_info($method); // This sending method may be disabled if (!$info) { return FALSE; } elseif (!empty($info['access'])) { return user_access($info['access'], $account); } else { return TRUE; } } /** * Returns default messaging method */ function messaging_method_default($account = NULL) { if ($account && !empty($account->messaging_default) && messaging_method_permission($account->messaging_default, $account)) { return $account->messaging_default; } elseif ($method = variable_get('messaging_default_method', '')) { return $method; } else { return key(messaging_method_info()); } } /** * Get setting from user account or get default setting if not available * * If first checks for a 'messaging_$name' property in the user account * and returns the value of the variable 'messaging_default_$name' if not set * * There's an optional variable 'messaging_peruser_$name' that if true will block * per user settings and use only global settings. * * @param $name * Option name * @param $account * Optional account to check setting for * @param $default * Default value if no option set */ function messaging_user_setting($name, $account = NULL, $default = NULL) { $variable = 'messaging_' . $name; if ($account && isset($account->$variable) && variable_get('messaging_peruser_' . $name, 1)) { return $account->$variable; } else { return variable_get('messaging_default_' . $name, $default); } } /** * Returns messaging methods properties * * @param $method * Optional, Method to get properties for, none or NULL for all methods * @param $property * Optional, Property to get, none or NULL for all properties * @param $default * Optional default value to return when there's not that property for the method */ function messaging_method_info($method = NULL, $property = NULL, $default = NULL, $refresh = FALSE) { $info = &messaging_static(__FUNCTION__); if (!$info || $refresh) { $info = module_invoke_all('messaging', 'send methods'); // Merge settings for each enabled method, just default filter if variable not set $default_settings = array('filter' => variable_get('messaging_default_filter', '')); foreach (array_keys($info) as $name) { $info[$name] = array_merge($info[$name], variable_get('messaging_method_' . $name, $default_settings)); } // Allow altering by other modules drupal_alter('messaging_methods', $info); } return _messaging_info($info, $method, $property, $default); } /** * Returns information about message groups * * @param $group * Optional message group. Returns all groups if null. * @param $key * Optional message key inside the group. Returns all keys if null. * @return array() * Depending on parameters, may be all message groups and keys or only a specific one. */ function messaging_message_group($group = NULL, $key = NULL) { $info = &messaging_static(__FUNCTION__); if (!isset($info)) { $info = module_invoke_all('messaging', 'message groups'); } return _messaging_info($info, $group, $key); } /** * Composes message from different parts, recursively and applies filter * * Filter is applied now only once * * @param $text * Simple string or array of message parts * It may have named elements like #prefix and #text * or it may be single strings to render straight forward * @param $glue * Text to glue all lines together * @param $filter * Input format to apply to the results */ function messaging_text_render($text, $glue = '', $filter = NULL) { $output = ''; if (is_array($text)) { if (isset($text['#prefix'])) { $output .= $text['#prefix'].$glue; unset($text['#prefix']); } if (isset($text['#text'])) { $output .= $text['#text']; return $output; } foreach (element_children($text) as $key) { // The filter is not passed along $text[$key] = messaging_text_render($text[$key], $glue); } $output .= implode($glue, $text); } else { $output .= $text; } // The filter is applied now only once if ($filter) { $output = check_markup($output, $filter, FALSE); } return $output; } /** * Implementation of hook_filter(). Contains a basic set of essential filters. * - Plain text: * Strips out all html * Replaces html entities * - HTML to text * Same with some text formatting * Relies on html_to_text module */ function messaging_filter($op, $delta = 0, $format = -1, $text = '') { switch ($op) { case 'list': $info[0] = t('Plain text'); $info[1] = t('HTML to text'); return $info; case 'description': switch ($delta) { case 0: return t('Filters out all HTML tags and replaces HTML entities by characters, respects HTML line breaks.'); case 1: return t('Replaces HTML tags and entities with plain text formatting, moving links at the end. This filter is just for text messages and it isn\'t safe for rendering content on a web page.'); } case 'process': switch ($delta) { case 0: return messaging_check_plain($text, "\n"); case 1: return drupal_html_to_text($text); default: return $text; } case 'settings': return; default: return $text; } } /** * HTML to text simple filtering. * - Replace some tags with line endings: p, br, hr, li, h1, h2, h3, h4 * Strip out all HTML tags and decode entities * * @param $text * Text to clean up * @param $break * Optional character to replace tags for line breaks */ function messaging_check_plain($text, $break = NULL) { // This have to be done before the filtering because tag markers may have been previously parsed with check_plain $text = str_replace(array('<', '>'), array('<', '>'), $text); // Clean up the HTML and replace some tags with line endings if (isset($break)) { $text = _filter_htmlcorrector($text); $text = str_replace(array('

', '
', '
', '', '', '', '', ''), $break, $text); } // Final text clean up return messaging_text_clean($text); } /** * Converts strings to plain utf-8 single line */ function messaging_check_subject($text) { $text = messaging_check_plain($text); // taken from _sanitizeHeaders() in PEAR mail() : http://pear.php.net/package/Mail $text = preg_replace('=((0x0A/%0A|0x0D/%0D|\\n|\\r)\S).*=i', NULL, $text); return $text; } /** * Entry point for the storage API */ function messaging_store() { static $include; if (!isset($include)) { require_once drupal_get_path('module', 'messaging') .'/messaging.store.inc'; $include = TRUE; } $args = func_get_args(); $function = 'messaging_store_'. array_shift($args); return call_user_func_array($function, $args); } /** * Helper user loading function with static caching */ function messaging_load_user($uid) { $cache = &messaging_static(__FUNCTION__); if (!$cache || !array_key_exists($uid, $cache)) { $cache[$uid] = user_load(array('uid' => $uid)); } return $cache[$uid]; } /** * Helper function for message loading from the store * * @param $mqid * Message id */ function messaging_message_load($mqid) { $cache = &messaging_static(__FUNCTION__); if (!isset($cache[$mqid])) { if ($message = messaging_store('load', $mqid)) { $cache[$mqid] = $message; } else { $cache[$mqid] = FALSE; } } return $cache[$mqid]; } /** * Do token replacement. * * Uses token_logic if enabled, standard token replacement otherwise */ function messaging_text_replace($text, $objects) { // Add some token types $objects['global'] = NULL; // Use token_logic if available, http://code.developmentseed.org/token_logic // Otherwise use standard contrib token module, http://drupal.org/project/token if (module_exists('token_logic')) { return token_logic_replace_multiple($text, $objects); } else { return token_replace_multiple($text, $objects); } } /** * Build a simple text with message subject and body * * This is useful for methods requiring a simple text instead of header and subject * * @param $message * Message object * @param $glue * Separator to glue subject and body together */ function messaging_text_build($message, $glue = ' ') { $parts = array(trim($message->subject), trim($message->body)); $parts = array_filter($parts); if ($parts) { $text = implode($glue, $parts); return $text; } else { return ''; } } /** * Clean text of HTML stuff and optionally of line endings * * @param $text * Dirty HTML text to be filtered * @param $newline * Optional string to be used as line ending */ function messaging_text_clean($text, $newline= NULL) { // HTML entities to plain text conversion. $text = decode_entities($text); // Filters out all remaining HTML tags $text = filter_xss($text, array()); // Optionally, replace new lines if (!is_null($newline)) { $text = str_replace("\n", $newline, $text); } // Trim out remaining beginning/ending spaces $text = trim($text); return $text; } /** * Truncate messages to given length. Adapted from node_teaser() in node.module */ function messaging_text_truncate($text, $length) { // If we have a short message, return the message if (drupal_strlen($text) < $length) { return $text; } // Initial slice. $teaser = truncate_utf8($text, $length); $position = 0; // Cache the reverse of the message. $reversed = strrev($teaser); // split at paragraph boundaries. $breakpoints = array('

' => 0, '
' => 6, '
' => 4, "\n" => 1); // We use strpos on the reversed needle and haystack for speed. foreach ($breakpoints as $point => $offset) { $length = strpos($reversed, strrev($point)); if ($length !== FALSE) { $position = - $length - $offset; return ($position == 0) ? $teaser : substr($teaser, 0, $position); } } // When even the first paragraph is too long, we try to split at the end of // the last full sentence. $breakpoints = array('. ' => 1, '! ' => 1, '? ' => 1, ' ' => 0); $min_length = strlen($reversed); foreach ($breakpoints as $point => $offset) { $length = strpos($reversed, strrev($point)); if ($length !== FALSE) { $min_length = min($length, $min_length); $position = 0 - $length - $offset; } } return ($position == 0) ? $teaser : substr($teaser, 0, $position); } /** * Process incoming message. This is the entry point for plug-in modules * * This is just a wrapper for handling incoming in messaging_incoming module */ function messaging_message_in($method, $channel, $message, $params = array()) { if (function_exists('messaging_incoming_post')) { return messaging_incoming_post($method, $channel, $message, $params); } else { return FALSE; } } /** * Update messaging method. * * When a messaging method is disabled, we need to update current settings for this and other modues */ function messaging_method_disable($method) { module_load_include('install', 'messaging'); if ($replace = messaging_update_method_replace($method)) { messaging_update_method_disable($method, $replace); drupal_set_message(t('Disabled messaging sending method %method and replaced by %replace', array('%method' => messaging_method_info($method, 'title'), '%replace' => messaging_method_info($replace, 'title')))); } else { // It seems all methods are disabled, print warning drupal_set_message(t('Disabled messaging sending method but cannot find a replacement. Please, enable some other sending method.'), 'error'); } } /** * Build callback structure to be invoked later * * A callback structure will be an array containing the function name to invoke * and a list of arguments for that function * * @param $function * Function name * @param $arg1, $arg1, $arg3 */ function _messaging_callback() { $args = func_get_args(); if (count($args) > 1) { // Array with function name, param1, param2.. return $args; } else { // Simple string with function name return array_shift($args); } } /** * Invoke callback with variable arguments * * We don't check whether the function exists so it will crash if it's missing * * @param $callback * Function name or array(function, arg1, arg2..) * @param $arg1, $arg2... * Variable number of arguments */ function _messaging_callback_invoke() { $args = func_get_args(); $callback = array_shift($args); if (is_array($callback)) { // It is an array: function, arg1, arg2... $function = array_shift($callback); $params = $callback; } else { // It is just a function name $function = $callback; $params = array(); } // Merge parameters and go for it $params = array_merge($params, $args); return call_user_func_array($function, $params); } /** * Invoke ordered list of callbacks on message * * For each callback name this function will search existing callbacks in $info ('[name] callback') * and if not existing will try the default callback 'messaging_message_[name]' * * @see _messaging_callback() for callback structure * * @param $callback_keys * Array of callbacks to invoke, ordered list * @param $message * Message object * @param $info * Messaging method info which may contain callbacks */ function messaging_message_callbacks($callback_keys, $message, $info) { while (!empty($message->process) && ($key = array_shift($callback_keys))) { if ($callback = _messaging_callback_get($info, $key)) { $message = messaging_message_invoke($callback, $message, $info); } elseif (function_exists('messaging_message_' . $key)) { $message = call_user_func('messaging_message_' . $key, $message, $info); } } return $message; } /** * Implementation of hook_token_list(). Documents the individual * tokens handled by the module. */ function messaging_token_list($type = 'all') { $tokens = array(); if ($type == 'message' || $type == 'all') { $tokens['message']['message-subject'] = t('The message subject.'); $tokens['message']['message-body'] = t('The message body.'); $tokens['message']['message-author-name'] = t('The message\'s author name.'); $tokens['message']['message-method'] = t('The message\'s method name.'); $tokens['message']['message-date'] = t('The message\'s sending date.'); } return $tokens; } /** * Implementation of hook_token_values() */ function messaging_token_values($type, $object = NULL, $options = array()) { switch ($type) { case 'message': if ($message = $object) { $values['message-subject'] = check_plain($message->subject); $values['message-body'] = filter_xss($message->body); $sender = messaging_load_user($message->sender); $values['message-author-name'] = check_plain($sender->name); $tokens['message-method'] = messaging_method_info($message->method, 'name'); $tokens['message-date'] = format_date($message->sent); return $values; } break; } } /** * Implementation of hook_theme() */ function messaging_theme() { return array( 'messaging_admin_method_settings' => array( 'arguments' => array('element' => NULL), 'file' => 'messaging.admin.inc', ), ); } /** * Add a callback to a callback collection * * @param $callback_list * Existing callback list or method info array * @param $type * Callback type * @param $callback * Callback function name or array('function_name', arg1, arg2...) * */ function _messaging_callback_add(&$callback_list, $type, $callback) { $name = $type . ' callback'; // If the existing callback is a single function name, make it an array if (!empty($callback_list[$name]) && !is_array($callback_list[$name])) { $callback_list[$name] = array($callback_list[$name]); } $callback_list[$name][] = $callback; } /** * Get a callback from the information array if present * * @param $info * Information array, typically a messaging method info array * @param $type * Callback type, the search key will be '[type] callback' * @param $default * Default callback to return if not in the $info array */ function _messaging_callback_get($info, $type, $default = NULL) { if (!empty($info[$type . ' callback'])) { return $info[$type . ' callback']; } else { return $default; } } /** * Helper function to get property from an info array * * Depending on method and property, returns the full array or a specific property */ function _messaging_info($info, $method = NULL, $property = NULL, $default = NULL) { if ($method && $property) { return isset($info[$method][$property]) ? $info[$method][$property] : $default; } elseif ($method) { return isset($info[$method]) ? $info[$method] : $default; } elseif ($property) { // Get this property as a list indexed by method $props = array(); foreach($info as $method => $values) { if (isset($values[$property])) { $props[$method] = $values[$property]; } } return $props; } else { return $info; } } /** * Get information from an array of data * * If $type and $field, return $data[$type][$field] * If $type and not $field, return $data[$type] * If not $type and $field, return that field indexed by type * * @param $data * Array of arrays with the form * array( * type1 => array( * field1 => value11, * field2 => value12, * ), * type2 => ... * ) * @param $type * Main index to check * @param $field * Field in $data[$info] to check * @param $default * Value to return if no data found */ function messaging_array_info($data, $type = NULL, $field = NULL, $default = NULL) { if ($field && $type) { return isset($data[$type][$field]) ? $data[$type][$field] : $default; } elseif ($field) { $return = array(); foreach ($data as $key => $info) { $return[$key] = isset($info[$field]) ? $info[$field] : $default; } return $return; } elseif ($type) { // The default for this case will be an array if not specified return isset($data[$type]) ? $data[$type] : (isset($default) ? $default : array()); } else { return $data; } } /** * Helper function for query builders. * * Using schema data get 'field = [placeholder]' and args arrays */ function _messaging_query_conditions($table, $params) { $schema = drupal_get_schema($table); $conditions = $args = array(); foreach ($params as $field => $value) { $type = $schema['fields'][$field]['type']; // For array values, build IN conditions if (is_array($value)) { $conditions[] = $field . ' IN (' . db_placeholders($value, $type) . ')'; $args = array_merge($args, $value); } elseif (is_null($value)) { $condtions[] = $field . ' IS NULL'; } else { $conditions[] = $field . ' = ' . db_type_placeholder($type); $args[] = $value; } } return array('conditions' => $conditions, 'args' => $args); } /** * Short hand for info logs * * Call messaging_log(TRUE) to enable logging */ function messaging_log($txt = NULL, $variables = NULL) { if (function_exists('messaging_debug_log')) { return messaging_debug_log($txt, $variables, 'info'); } else { return _messaging_log('info', $txt, $variables); } } /** * Short hand for debug logs * * Call messaging_debug(TRUE) to enable logging */ function messaging_debug($txt = NULL, $variables = NULL) { if (function_exists('messaging_debug_log')) { return messaging_debug_log($txt, $variables); } } /** * Get logs without formatting */ function messaging_log_get() { if ($logs = _messaging_log('return')) { _messaging_log('reset'); return $logs; } } /** * Init logging system so logs are saved from now on */ function messaging_log_start() { return _messaging_log('start'); } /** * Format logs */ function messaging_log_format($logs) { $rows = array(); foreach ($logs as $log) { list($type, $string, $append, $objects) = _messaging_log_prepare($log); // Full objects/arrays are only rendered when debug module is enabled if ($objects && function_exists('_messaging_debug_format_log')) { $text = _messaging_debug_format_log($type, $string, $append, $objects); } else { $text = $string; if ($append) { $text .= '
' . implode(' ', $append); } } $rows[] = array( $type, $text, ); } return theme('table', array(t('Type'), t('Message')), $rows); } /** * Quick logging for debugging and manual queue processing */ function _messaging_log($type, $txt = NULL, $variables = NULL, $severity = WATCHDOG_NOTICE) { static $enabled = FALSE; switch ($type) { case 'info': case 'debug': if ($enabled) { $_SESSION['messaging_log'][] = array($type, $txt, $variables, $severity); } break; case 'return': return isset($_SESSION['messaging_log']) ? $_SESSION['messaging_log'] : NULL; break; case 'reset': unset($_SESSION['messaging_log']); break; case 'start': $enabled = TRUE; break; case 'stop': $enabled = FALSE; break; } } /** * Prepare log item for formatting * * Each log item has type, string, args, severity */ function _messaging_log_prepare($log) { list($type, $string, $args, $severity) = $log; $append = $replace = $objects = array(); if ($args) { // Transform arguments before inserting them. foreach ($args as $key => $value) { if (is_string($value) || is_numeric($value)) { switch ($key[0]) { case '@': // Escaped only. $replace[$key] = check_plain($value); break; case '%': $replace[$key] = theme('placeholder', $value); break; case '!': // Pass-through. $replace[$key] = $value; break; default: // Append to string a key value pair, different from watchdog format $append[$key] = '' . $key . '= ' . check_plain($value); break; } } else { $objects[$key] = $value; } } $string = strtr($string, $replace); } return array($type, $string, $append, $objects); } /** * Get send method object * * @param $method * Method name or Messaging_Method object */ function messaging_send_method($method) { $send_methods = &messaging_static(__FUNCTION__); if (is_object($method)) { return $method; } if (!isset($send_methods[$method])) { $info = messaging_method_info($method); $class = !empty($info['class']) ? $info['class'] : 'Messaging_Send_Method'; $send_methods[$method] = new $class($info, $method); } return $send_methods[$method]; } /** * Build Message object from message array * * The $message array may have the following elements * 'subject' => Message subject, may be already rendered or not * 'body' => Message content, may be already rendered or not * 'params' => Optional message params, indexed by sending method group * I.e. params for mail methods will be in $message['params']['mail'] * 'sender' => Optional int to identify message sender, may be $user->uid * 'sender_account' => Optional user account to use as message sender */ function messaging_message_build($message) { if (is_object($message) && $message instanceof Messaging_Message) { return $message; } else { return new Messaging_Message($message); } } /** * Central static variable storage, Drupal 7 core backport * * See http://api.drupal.org/api/function/drupal_static/7 */ function &messaging_static($name, $default_value = NULL, $reset = FALSE) { static $data = array(), $default = array(); if (!isset($name)) { // All variables are reset. This needs to be done one at a time so that // references returned by earlier invocations of drupal_static() also get // reset. foreach ($default as $name => $value) { $data[$name] = $value; } // As the function returns a reference, the return should always be a // variable. return $data; } if ($reset) { // The reset means the default is loaded. if (array_key_exists($name, $default)) { $data[$name] = $default[$name]; } else { // Reset was called before a default is set and yet a variable must be // returned. return $data; } } elseif (!array_key_exists($name, $data)) { // Store the default value internally and also copy it to the reference to // be returned. $default[$name] = $data[$name] = $default_value; } return $data[$name]; }