'); /** * Implementation of hook_autoload_info(). */ function messaging_autoload_info() { return array( 'Messaging_Object' => array('file' => 'includes/messaging_object.class.inc'), 'Messaging_Cached_Object' => array('file' => 'includes/messaging_object.class.inc'), 'Messaging_Destination' => array('file' => 'includes/messaging_destination.class.inc'), 'Messaging_Message' => array('file' => 'includes/messaging_message.class.inc'), 'Messaging_Send_Method' => array('file' => 'includes/messaging_method.class.inc'), 'Messaging_Method_Mail' => array('file' => 'includes/messaging_method_mail.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; case 'admin/messaging/settings/method': $output = '' . t('Depending on your content format and the tokens you are using for messages it is important that you use the right filtering for the message body. Set up the filters you need using the Input formats page', array('@input_formats' => url('admin/settings/filters'))) . '
'; return $output; } } /** * 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, ); 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 'delete': // Delete user data from tables Messaging_Destination::delete_multiple(array('uid' => $user->uid)); db_query("DELETE FROM {messaging_store} WHERE uid = %d", $user->uid); break; case 'update': // Claim user mail address if in destinations table if (function_exists('messaging_mail_update_user')) { messaging_mail_update_user($user); } break; 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 **/ /** * Get send method object * * @param $method * Method name or Messaging_Method object * @param $method_info * Array of properties to build a custom send method */ function messaging_send_method($method, $method_info = array()) { $send_methods = &messaging_static(__FUNCTION__); if (is_object($method)) { return $method; } if (!isset($send_methods[$method])) { if ($info = messaging_method_info($method)) { $class = !empty($info['class']) ? $info['class'] : 'Messaging_Send_Method'; $send_methods[$method] = new $class($method, $info); } else { // No info available from modules. This is a custom method or a disabled one $send_methods[$method] = new Messaging_Send_Method($method, $method_info); } } return $send_methods[$method]; } /** * Build message object from object or array */ function messaging_message_build($message) { if(is_object($message) && is_a($message, 'Messaging_Message')) { return $message; } else { return new Messaging_Message($message); } } /** * Send message to destination object * * @param $destination * Messaging Destination 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 $queue * Optional send method. Defaults to the user account predefined method */ function messaging_message_send_destination($destination, $message, $queue = FALSE) { messaging_debug('Sending message to destination', array('destination' => $destination, 'message' => $message)); // Build array of parameters so they can be overridden by callbacks $message = messaging_message_build($message); $message->uid = $destination->uid; $message->method = $destination->method; $message->destination = $destination->address; $message->acccount = $destination->get_account(); if ($queue) { return $message->queue(); } else { return $message->send(); } } /** * 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 = FALSE) { messaging_debug('Sending message to user', array('account' => $account, 'message' => $message, 'method' => $method)); // Build array of parameters so they can be overridden by callbacks $message = messaging_message_build($message); $message->method = $method ? $method : messaging_method_default($account); $message->queue = $queue ? 1 : 0; // Log in case it cannot be delivered. This can be overridden by user callback //$message->log = TRUE; $message->set_user($account); // Check user and availability if there's a callback for that. Depending on the sending method, // when user is not available it may just be discarded / queued / redirected through other method $message->process = TRUE; $message->discard = FALSE; // This can go through multiple redirections, when done $process should be FALSE while (!$message->queue && $message->method && !$message->discard && $message->process && ($callback = messaging_method_info($message->method, 'user callback'))) { $params = _messaging_callback_invoke($callback, $message); } // The sending method may have decided the message is to be discarded. if ($message->discard) { return FALSE; } if ($message->method && empty($message->destination)) { $message->destination = messaging_user_destination($account, $message->method, $message); } // Now check that we have a destination for this user account. If set to FALSE we just don't try anymore // Send the message or, if no destination, abort the message sending if ($message->method && $message->destination) { messaging_debug('Found destination for user, sending message', array('method' => $message->method, 'destination' => $message->destination)); $message->send(); } elseif (!empty($message->log)) { // Save the message, let it there for further reference messaging_log('Destination not available for user account', array('method' => $method, 'account' => $account)); $message->destination = 'ERROR'; $message->cron = $message->queue = 0; $message->log = 1; $message->success = FALSE; $message->store(); } return $message->success; } /** * Build destination object from user account (and create destination if not exists) */ function messaging_account_build_destination($account, $method = NULL, $address = NULL) { if ($account->uid) { if ($method && !$address) { $address = messaging_user_destination($account, $method); } if ($method && $address) { return Messaging_Destination::create($method, $address, $account->uid); } elseif (($fallback = messaging_method_default($account)) && $fallback != $method) { // Retry with new method return messaging_account_build_destination($account, $fallback); } } elseif ($method && $address) { // Anonymous users // @todo check the address doesn't belong to any user ??? return Messaging_Destination::create($method, $address, 0); } } /** * Get destination from user account. * * This will handle also anonymous user accounts that should have a 'destination' property */ function messaging_user_destination($account, $method, $message = NULL) { return messaging_send_method($method)->get_user_address($account); } /** * Send message to array of destinations. 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)); // Convert into an object and add all the information into the message object $message = messaging_message_build($message); $message->method = $method ? $method : messaging_method_default(NULL); $message->source['type'] = 'outgoing'; $message->destinations = $destinations; $message->queue = $queue ? 1 : 0; $message->sent = $message->queued = 0; if ($queue) { $message->queue(); } else { $message->send_multiple(); } // This will return true if the message was sent or queued for delivery if (!isset($message->success)) { $message->success = $message->sent || $message->queued; } return $message->success; } /** * Test sending, just log message */ function messaging_message_test($message, $destinations = array()) { $message->prepare(); $message->render(); messaging_log('Emulating message sending (test run)', array('summary' => (string)$message, 'message' => $message, 'destinations' => $destinations)); return $message->success = TRUE; } /** * Message default callback: preprocessing */ function messaging_message_prepare($message, $info) { Messaging_Send_Method::default_prepare($message, $info); } /** * 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 $address * 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($address, $message, $method) { $message = messaging_message_build($message); $message->method = $method; if ($send_method = messaging_send_method($method)) { return $send_method->send_address($address, $message); } else { watchdog('messaging', 'Message could not be delivered for method %method', array('%method' => $method), WATCHDOG_ERROR); return FALSE; } } /** * Implementation of hook_cron() * * Process queued messages for delivery */ function messaging_cron() { messaging_store('queue_process'); messaging_store('queue_cleanup'); } /** * 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]); } else { $info[$method] = messaging_translate("method:$method:name", $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) { $send_method = messaging_send_method($method); return $send_method && $send_method->user_access($account); } /** * 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 from variable for each enabled method foreach (array_keys($info) as $name) { $info[$name] = array_merge($info[$name], variable_get('messaging_method_' . $name, array())); } // Allow altering by other modules drupal_alter('messaging_methods', $info); } return messaging_array_info($info, $method, $property, $default); } /** * 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('', '