$title) { // Skip empty titles. if ($title = trim($title)) { // Output plaintext instead of a link if there is a title // without a path. $path = trim($paths[$i]); if (!empty($paths[$i]) && $paths[$i] != '') { $trail[] = l($title, trim($paths[$i])); } else { $trail[] = check_plain($title); } } } drupal_set_breadcrumb($trail); } /** * Action Implementation: Send mail. */ function rules_action_mail($to, $subject, $message, $from = NULL, $langcode, $settings, RulesState $state, RulesPlugin $element) { $to = str_replace(array("\r", "\n"), '', $to); $from = !empty($from) ? str_replace(array("\r", "\n"), '', $from) : NULL; $params = array( 'subject' => $subject, 'message' => $message, 'langcode' => $langcode, ); // Set a unique key for this mail. $name = isset($element->root()->name) ? $element->root()->name : 'unnamed'; $key = 'rules_action_mail_' . $name . '_' . $element->elementId(); $languages = language_list(); $language = isset($languages[$langcode]) ? $languages[$langcode] : language_default(); $message = drupal_mail('rules', $key, $to, $language, $params, $from); if ($message['result']) { watchdog('rules', 'Successfully sent email to %recipient', array('%recipient' => $to)); } } /** * Action: Send mail to all users of a specific role group(s). */ function rules_action_mail_to_users_of_role($roles, $subject, $message, $from = NULL, $settings, RulesState $state, RulesPlugin $element) { $from = !empty($from) ? str_replace(array("\r", "\n"), '', $from) : NULL; // All authenticated users, which is everybody. if (in_array(DRUPAL_AUTHENTICATED_RID, $roles)) { $result = db_query('SELECT mail FROM {users} WHERE uid > 0'); } else { // Avoid sending emails to members of two or more target role groups. $result = db_query('SELECT DISTINCT u.mail FROM {users} u INNER JOIN {users_roles} r ON u.uid = r.uid WHERE r.rid IN (:rids)', array(':rids' => $roles)); } // Now, actually send the mails. $params = array( 'subject' => $subject, 'message' => $message, ); // Set a unique key for this mail. $name = isset($element->root()->name) ? $element->root()->name : 'unnamed'; $key = 'rules_action_mail_to_users_of_role_' . $name . '_' . $element->elementId(); $languages = language_list(); $message = array('result' => TRUE); foreach ($result as $row) { $message = drupal_mail('rules', $key, $row->mail, language_default(), $params, $from); // If $message['result'] is FALSE, then it's likely that email sending is // failing at the moment, and we should just abort sending any more. If // however, $message['result'] is NULL, then it's likely that a module has // aborted sending this particular email to this particular user, and we // should just keep on sending emails to the other users. // For more information on the result value, see drupal_mail(). if ($message['result'] === FALSE) { break; } } if ($message['result'] !== FALSE) { $role_names = array_intersect_key(user_roles(TRUE), array_flip($roles)); watchdog('rules', 'Successfully sent email to the role(s) %roles.', array('%roles' => implode(', ', $role_names))); } } /** * Implements hook_mail(). * * Sets the message subject and body as configured. */ function rules_mail($key, &$message, $params) { $message['subject'] .= str_replace(array("\r", "\n"), '', $params['subject']); $message['body'][] = $params['message']; } /** * Action: Block an IP address. */ function rules_action_block_ip($ip_address = NULL) { if (empty($ip_address)) { $ip_address = ip_address(); } db_insert('blocked_ips')->fields(array('ip' => $ip_address))->execute(); watchdog('rules', 'Banned IP address %ip', array('%ip' => $ip_address)); } /** * A class implementing a rules input evaluator processing tokens. */ class RulesTokenEvaluator extends RulesDataInputEvaluator { /** * Overrides RulesDataInputEvaluator::prepare(). */ public function prepare($text, $var_info) { $text = is_array($text) ? implode('', $text) : $text; // Skip this evaluator if there are no tokens. $this->setting = token_scan($text) ? TRUE : NULL; } /** * Evaluate tokens. * * We replace the tokens on our own as we cannot use token_replace(), because * token usually assumes that $data['node'] is a of type node, which doesn't * hold in general in our case. * So we properly map variable names to variable data types and then run the * replacement ourself. */ public function evaluate($text, $options, RulesState $state) { $var_info = $state->varInfo(); $options += array('sanitize' => FALSE); $replacements = array(); $data = array(); // We also support replacing tokens in a list of textual values. $whole_text = is_array($text) ? implode('', $text) : $text; foreach (token_scan($whole_text) as $var_name => $tokens) { $var_name = str_replace('-', '_', $var_name); if (isset($var_info[$var_name]) && ($token_type = _rules_system_token_map_type($var_info[$var_name]['type']))) { // We have to key $data with the type token uses for the variable. $data = rules_unwrap_data(array($token_type => $state->get($var_name)), array($token_type => $var_info[$var_name])); $replacements += token_generate($token_type, $tokens, $data, $options); } else { $replacements += token_generate($var_name, $tokens, array(), $options); } // Remove tokens if no replacement value is found. As token_replace() does // if 'clear' is set. $replacements += array_fill_keys($tokens, ''); } // Optionally clean the list of replacement values. if (!empty($options['callback']) && function_exists($options['callback'])) { $function = $options['callback']; $function($replacements, $data, $options); } // Actually apply the replacements. $tokens = array_keys($replacements); $values = array_values($replacements); if (is_array($text)) { foreach ($text as $i => $text_item) { $text[$i] = str_replace($tokens, $values, $text_item); } return $text; } return str_replace($tokens, $values, $text); } /** * Create documentation about the available replacement patterns. * * @param array $var_info * Array with the available variables. * * @return array * Renderable array with the replacement pattern documentation. */ public static function help($var_info) { $render = array( '#type' => 'fieldset', '#title' => t('Replacement patterns'), '#collapsible' => TRUE, '#collapsed' => TRUE, '#description' => t('Note that token replacements containing chained objects – such as [node:author:uid] – are not listed here, but are still available. The data selection input mode may help you find more complex replacement patterns. See the online documentation for more information about complex replacement patterns.', array('@url' => rules_external_help('chained-tokens'))), ); $token_info = token_info(); foreach ($var_info as $name => $info) { $token_types[$name] = _rules_system_token_map_type($info['type']); } foreach ($token_types as $name => $token_type) { if (isset($token_info['types'][$token_type])) { $render[$name] = array( '#theme' => 'table', '#header' => array(t('Token'), t('Label'), t('Description')), '#prefix' => '

' . t('Replacement patterns for %label', array('%label' => $var_info[$name]['label'])) . '

', ); foreach ($token_info['tokens'][$token_type] as $token => $info) { $token = '[' . str_replace('_', '-', $name) . ':' . $token . ']'; $render[$name]['#rows'][$token] = array( check_plain($token), check_plain($info['name']), check_plain($info['description']), ); } } } return $render; } } /** * Looks for a token type mapping. Defaults to passing through the type. */ function _rules_system_token_map_type($type) { $entity_info = entity_get_info(); if (isset($entity_info[$type]['token type'])) { return $entity_info[$type]['token type']; } $cache = rules_get_cache(); if (isset($cache['data_info'][$type]['token type'])) { return $cache['data_info'][$type]['token type']; } return $type; } /** * @} */