annotate includes/mail.inc @ 20:e3d20ebd63d1 tip

Added tag 6.9 for changeset 3edae6ecd6c6
author Franck Deroche <franck@defr.org>
date Thu, 15 Jan 2009 10:16:10 +0100
parents 589fb7c02327
children
rev   line source
webmaster@1 1 <?php
webmaster@11 2 // $Id: mail.inc,v 1.8.2.4 2008/10/06 11:04:08 dries Exp $
webmaster@1 3
webmaster@1 4 /**
webmaster@1 5 * Compose and optionally send an e-mail message.
webmaster@1 6 *
webmaster@1 7 * Sending an e-mail works with defining an e-mail template (subject, text
webmaster@1 8 * and possibly e-mail headers) and the replacement values to use in the
webmaster@1 9 * appropriate places in the template. Processed e-mail templates are
webmaster@1 10 * requested from hook_mail() from the module sending the e-mail. Any module
webmaster@1 11 * can modify the composed e-mail message array using hook_mail_alter().
webmaster@1 12 * Finally drupal_mail_send() sends the e-mail, which can be reused
webmaster@1 13 * if the exact same composed e-mail is to be sent to multiple recipients.
webmaster@1 14 *
webmaster@1 15 * Finding out what language to send the e-mail with needs some consideration.
webmaster@1 16 * If you send e-mail to a user, her preferred language should be fine, so
webmaster@1 17 * use user_preferred_language(). If you send email based on form values
webmaster@1 18 * filled on the page, there are two additional choices if you are not
webmaster@1 19 * sending the e-mail to a user on the site. You can either use the language
webmaster@1 20 * used to generate the page ($language global variable) or the site default
webmaster@1 21 * language. See language_default(). The former is good if sending e-mail to
webmaster@1 22 * the person filling the form, the later is good if you send e-mail to an
webmaster@1 23 * address previously set up (like contact addresses in a contact form).
webmaster@1 24 *
webmaster@1 25 * Taking care of always using the proper language is even more important
webmaster@1 26 * when sending e-mails in a row to multiple users. Hook_mail() abstracts
webmaster@1 27 * whether the mail text comes from an administrator setting or is
webmaster@1 28 * static in the source code. It should also deal with common mail tokens,
webmaster@1 29 * only receiving $params which are unique to the actual e-mail at hand.
webmaster@1 30 *
webmaster@1 31 * An example:
webmaster@1 32 *
webmaster@1 33 * @code
webmaster@1 34 * function example_notify($accounts) {
webmaster@1 35 * foreach ($accounts as $account) {
webmaster@1 36 * $params['account'] = $account;
webmaster@1 37 * // example_mail() will be called based on the first drupal_mail() parameter.
webmaster@11 38 * drupal_mail('example', 'notice', $account->mail, user_preferred_language($account), $params);
webmaster@1 39 * }
webmaster@1 40 * }
webmaster@1 41 *
webmaster@1 42 * function example_mail($key, &$message, $params) {
webmaster@1 43 * $language = $message['language'];
webmaster@1 44 * $variables = user_mail_tokens($params['account'], $language);
webmaster@1 45 * switch($key) {
webmaster@1 46 * case 'notice':
webmaster@1 47 * $message['subject'] = t('Notification from !site', $variables, $language->language);
webmaster@1 48 * $message['body'] = t("Dear !username\n\nThere is new content available on the site.", $variables, $language->language);
webmaster@1 49 * break;
webmaster@1 50 * }
webmaster@1 51 * }
webmaster@1 52 * @endcode
webmaster@1 53 *
webmaster@1 54 * @param $module
webmaster@1 55 * A module name to invoke hook_mail() on. The {$module}_mail() hook will be
webmaster@1 56 * called to complete the $message structure which will already contain common
webmaster@1 57 * defaults.
webmaster@1 58 * @param $key
webmaster@1 59 * A key to identify the e-mail sent. The final e-mail id for e-mail altering
webmaster@1 60 * will be {$module}_{$key}.
webmaster@1 61 * @param $to
webmaster@1 62 * The e-mail address or addresses where the message will be sent to. The
webmaster@1 63 * formatting of this string must comply with RFC 2822. Some examples are:
webmaster@1 64 * user@example.com
webmaster@1 65 * user@example.com, anotheruser@example.com
webmaster@1 66 * User <user@example.com>
webmaster@1 67 * User <user@example.com>, Another User <anotheruser@example.com>
webmaster@1 68 * @param $language
webmaster@1 69 * Language object to use to compose the e-mail.
webmaster@1 70 * @param $params
webmaster@1 71 * Optional parameters to build the e-mail.
webmaster@1 72 * @param $from
webmaster@1 73 * Sets From, Reply-To, Return-Path and Error-To to this value, if given.
webmaster@1 74 * @param $send
webmaster@1 75 * Send the message directly, without calling drupal_mail_send() manually.
webmaster@1 76 * @return
webmaster@1 77 * The $message array structure containing all details of the
webmaster@1 78 * message. If already sent ($send = TRUE), then the 'result' element
webmaster@1 79 * will contain the success indicator of the e-mail, failure being already
webmaster@1 80 * written to the watchdog. (Success means nothing more than the message being
webmaster@1 81 * accepted at php-level, which still doesn't guarantee it to be delivered.)
webmaster@1 82 */
webmaster@1 83 function drupal_mail($module, $key, $to, $language, $params = array(), $from = NULL, $send = TRUE) {
webmaster@1 84 $default_from = variable_get('site_mail', ini_get('sendmail_from'));
webmaster@1 85
webmaster@1 86 // Bundle up the variables into a structured array for altering.
webmaster@1 87 $message = array(
webmaster@1 88 'id' => $module .'_'. $key,
webmaster@1 89 'to' => $to,
webmaster@1 90 'from' => isset($from) ? $from : $default_from,
webmaster@1 91 'language' => $language,
webmaster@1 92 'params' => $params,
webmaster@1 93 'subject' => '',
webmaster@1 94 'body' => array()
webmaster@1 95 );
webmaster@1 96
webmaster@1 97 // Build the default headers
webmaster@1 98 $headers = array(
webmaster@1 99 'MIME-Version' => '1.0',
webmaster@1 100 'Content-Type' => 'text/plain; charset=UTF-8; format=flowed; delsp=yes',
webmaster@1 101 'Content-Transfer-Encoding' => '8Bit',
webmaster@1 102 'X-Mailer' => 'Drupal'
webmaster@1 103 );
webmaster@1 104 if ($default_from) {
webmaster@1 105 // To prevent e-mail from looking like spam, the addresses in the Sender and
webmaster@1 106 // Return-Path headers should have a domain authorized to use the originating
webmaster@1 107 // SMTP server. Errors-To is redundant, but shouldn't hurt.
webmaster@1 108 $headers['From'] = $headers['Reply-To'] = $headers['Sender'] = $headers['Return-Path'] = $headers['Errors-To'] = $default_from;
webmaster@1 109 }
webmaster@1 110 if ($from) {
webmaster@1 111 $headers['From'] = $headers['Reply-To'] = $from;
webmaster@1 112 }
webmaster@1 113 $message['headers'] = $headers;
webmaster@1 114
webmaster@1 115 // Build the e-mail (get subject and body, allow additional headers) by
webmaster@1 116 // invoking hook_mail() on this module. We cannot use module_invoke() as
webmaster@1 117 // we need to have $message by reference in hook_mail().
webmaster@1 118 if (function_exists($function = $module .'_mail')) {
webmaster@1 119 $function($key, $message, $params);
webmaster@1 120 }
webmaster@1 121
webmaster@1 122 // Invoke hook_mail_alter() to allow all modules to alter the resulting e-mail.
webmaster@1 123 drupal_alter('mail', $message);
webmaster@1 124
webmaster@1 125 // Concatenate and wrap the e-mail body.
webmaster@1 126 $message['body'] = is_array($message['body']) ? drupal_wrap_mail(implode("\n\n", $message['body'])) : drupal_wrap_mail($message['body']);
webmaster@1 127
webmaster@1 128 // Optionally send e-mail.
webmaster@1 129 if ($send) {
webmaster@1 130 $message['result'] = drupal_mail_send($message);
webmaster@1 131
webmaster@1 132 // Log errors
webmaster@1 133 if (!$message['result']) {
webmaster@1 134 watchdog('mail', 'Error sending e-mail (from %from to %to).', array('%from' => $message['from'], '%to' => $message['to']), WATCHDOG_ERROR);
webmaster@1 135 drupal_set_message(t('Unable to send e-mail. Please contact the site admin, if the problem persists.'), 'error');
webmaster@1 136 }
webmaster@1 137 }
webmaster@1 138
webmaster@1 139 return $message;
webmaster@1 140 }
webmaster@1 141
webmaster@1 142 /**
webmaster@1 143 * Send an e-mail message, using Drupal variables and default settings.
webmaster@1 144 * More information in the <a href="http://php.net/manual/en/function.mail.php">
webmaster@1 145 * PHP function reference for mail()</a>. See drupal_mail() for information on
webmaster@1 146 * how $message is composed.
webmaster@1 147 *
webmaster@1 148 * @param $message
webmaster@1 149 * Message array with at least the following elements:
webmaster@1 150 * - id
webmaster@1 151 * A unique identifier of the e-mail type. Examples: 'contact_user_copy',
webmaster@1 152 * 'user_password_reset'.
webmaster@1 153 * - to
webmaster@1 154 * The mail address or addresses where the message will be sent to. The
webmaster@1 155 * formatting of this string must comply with RFC 2822. Some examples are:
webmaster@1 156 * user@example.com
webmaster@1 157 * user@example.com, anotheruser@example.com
webmaster@1 158 * User <user@example.com>
webmaster@1 159 * User <user@example.com>, Another User <anotheruser@example.com>
webmaster@1 160 * - subject
webmaster@1 161 * Subject of the e-mail to be sent. This must not contain any newline
webmaster@1 162 * characters, or the mail may not be sent properly.
webmaster@1 163 * - body
webmaster@1 164 * Message to be sent. Accepts both CRLF and LF line-endings.
webmaster@1 165 * E-mail bodies must be wrapped. You can use drupal_wrap_mail() for
webmaster@1 166 * smart plain text wrapping.
webmaster@1 167 * - headers
webmaster@1 168 * Associative array containing all mail headers.
webmaster@1 169 * @return
webmaster@1 170 * Returns TRUE if the mail was successfully accepted for delivery,
webmaster@1 171 * FALSE otherwise.
webmaster@1 172 */
webmaster@1 173 function drupal_mail_send($message) {
webmaster@1 174 // Allow for a custom mail backend.
webmaster@1 175 if (variable_get('smtp_library', '') && file_exists(variable_get('smtp_library', ''))) {
webmaster@1 176 include_once './'. variable_get('smtp_library', '');
webmaster@1 177 return drupal_mail_wrapper($message);
webmaster@1 178 }
webmaster@1 179 else {
webmaster@1 180 $mimeheaders = array();
webmaster@1 181 foreach ($message['headers'] as $name => $value) {
webmaster@1 182 $mimeheaders[] = $name .': '. mime_header_encode($value);
webmaster@1 183 }
webmaster@1 184 return mail(
webmaster@1 185 $message['to'],
webmaster@1 186 mime_header_encode($message['subject']),
webmaster@1 187 // Note: e-mail uses CRLF for line-endings, but PHP's API requires LF.
webmaster@1 188 // They will appear correctly in the actual e-mail that is sent.
webmaster@1 189 str_replace("\r", '', $message['body']),
webmaster@5 190 // For headers, PHP's API suggests that we use CRLF normally,
webmaster@5 191 // but some MTAs incorrecly replace LF with CRLF. See #234403.
webmaster@1 192 join("\n", $mimeheaders)
webmaster@1 193 );
webmaster@1 194 }
webmaster@1 195 }
webmaster@1 196
webmaster@1 197 /**
webmaster@1 198 * Perform format=flowed soft wrapping for mail (RFC 3676).
webmaster@1 199 *
webmaster@1 200 * We use delsp=yes wrapping, but only break non-spaced languages when
webmaster@1 201 * absolutely necessary to avoid compatibility issues.
webmaster@1 202 *
webmaster@1 203 * We deliberately use LF rather than CRLF, see drupal_mail().
webmaster@1 204 *
webmaster@1 205 * @param $text
webmaster@1 206 * The plain text to process.
webmaster@1 207 * @param $indent (optional)
webmaster@1 208 * A string to indent the text with. Only '>' characters are repeated on
webmaster@1 209 * subsequent wrapped lines. Others are replaced by spaces.
webmaster@1 210 */
webmaster@1 211 function drupal_wrap_mail($text, $indent = '') {
webmaster@1 212 // Convert CRLF into LF.
webmaster@1 213 $text = str_replace("\r", '', $text);
webmaster@1 214 // See if soft-wrapping is allowed.
webmaster@1 215 $clean_indent = _drupal_html_to_text_clean($indent);
webmaster@1 216 $soft = strpos($clean_indent, ' ') === FALSE;
webmaster@1 217 // Check if the string has line breaks.
webmaster@1 218 if (strpos($text, "\n") !== FALSE) {
webmaster@1 219 // Remove trailing spaces to make existing breaks hard.
webmaster@1 220 $text = preg_replace('/ +\n/m', "\n", $text);
webmaster@1 221 // Wrap each line at the needed width.
webmaster@1 222 $lines = explode("\n", $text);
webmaster@1 223 array_walk($lines, '_drupal_wrap_mail_line', array('soft' => $soft, 'length' => strlen($indent)));
webmaster@1 224 $text = implode("\n", $lines);
webmaster@1 225 }
webmaster@1 226 else {
webmaster@1 227 // Wrap this line.
webmaster@1 228 _drupal_wrap_mail_line($text, 0, array('soft' => $soft, 'length' => strlen($indent)));
webmaster@1 229 }
webmaster@1 230 // Empty lines with nothing but spaces.
webmaster@1 231 $text = preg_replace('/^ +\n/m', "\n", $text);
webmaster@1 232 // Space-stuff special lines.
webmaster@1 233 $text = preg_replace('/^(>| |From)/m', ' $1', $text);
webmaster@1 234 // Apply indentation. We only include non-'>' indentation on the first line.
webmaster@1 235 $text = $indent . substr(preg_replace('/^/m', $clean_indent, $text), strlen($indent));
webmaster@1 236
webmaster@1 237 return $text;
webmaster@1 238 }
webmaster@1 239
webmaster@1 240 /**
webmaster@1 241 * Transform an HTML string into plain text, preserving the structure of the
webmaster@1 242 * markup. Useful for preparing the body of a node to be sent by e-mail.
webmaster@1 243 *
webmaster@1 244 * The output will be suitable for use as 'format=flowed; delsp=yes' text
webmaster@1 245 * (RFC 3676) and can be passed directly to drupal_mail() for sending.
webmaster@1 246 *
webmaster@1 247 * We deliberately use LF rather than CRLF, see drupal_mail().
webmaster@1 248 *
webmaster@1 249 * This function provides suitable alternatives for the following tags:
webmaster@1 250 * <a> <em> <i> <strong> <b> <br> <p> <blockquote> <ul> <ol> <li> <dl> <dt>
webmaster@1 251 * <dd> <h1> <h2> <h3> <h4> <h5> <h6> <hr>
webmaster@1 252 *
webmaster@1 253 * @param $string
webmaster@1 254 * The string to be transformed.
webmaster@1 255 * @param $allowed_tags (optional)
webmaster@1 256 * If supplied, a list of tags that will be transformed. If omitted, all
webmaster@1 257 * all supported tags are transformed.
webmaster@1 258 * @return
webmaster@1 259 * The transformed string.
webmaster@1 260 */
webmaster@1 261 function drupal_html_to_text($string, $allowed_tags = NULL) {
webmaster@1 262 // Cache list of supported tags.
webmaster@1 263 static $supported_tags;
webmaster@1 264 if (empty($supported_tags)) {
webmaster@1 265 $supported_tags = array('a', 'em', 'i', 'strong', 'b', 'br', 'p', 'blockquote', 'ul', 'ol', 'li', 'dl', 'dt', 'dd', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'hr');
webmaster@1 266 }
webmaster@1 267
webmaster@1 268 // Make sure only supported tags are kept.
webmaster@1 269 $allowed_tags = isset($allowed_tags) ? array_intersect($supported_tags, $allowed_tags) : $supported_tags;
webmaster@1 270
webmaster@1 271 // Make sure tags, entities and attributes are well-formed and properly nested.
webmaster@1 272 $string = _filter_htmlcorrector(filter_xss($string, $allowed_tags));
webmaster@1 273
webmaster@1 274 // Apply inline styles.
webmaster@7 275 $string = preg_replace('!</?(em|i)((?> +)[^>]*)?>!i', '/', $string);
webmaster@7 276 $string = preg_replace('!</?(strong|b)((?> +)[^>]*)?>!i', '*', $string);
webmaster@1 277
webmaster@1 278 // Replace inline <a> tags with the text of link and a footnote.
webmaster@1 279 // 'See <a href="http://drupal.org">the Drupal site</a>' becomes
webmaster@1 280 // 'See the Drupal site [1]' with the URL included as a footnote.
webmaster@1 281 _drupal_html_to_mail_urls(NULL, TRUE);
webmaster@1 282 $pattern = '@(<a[^>]+?href="([^"]*)"[^>]*?>(.+?)</a>)@i';
webmaster@1 283 $string = preg_replace_callback($pattern, '_drupal_html_to_mail_urls', $string);
webmaster@1 284 $urls = _drupal_html_to_mail_urls();
webmaster@1 285 $footnotes = '';
webmaster@1 286 if (count($urls)) {
webmaster@1 287 $footnotes .= "\n";
webmaster@1 288 for ($i = 0, $max = count($urls); $i < $max; $i++) {
webmaster@1 289 $footnotes .= '['. ($i + 1) .'] '. $urls[$i] ."\n";
webmaster@1 290 }
webmaster@1 291 }
webmaster@1 292
webmaster@1 293 // Split tags from text.
webmaster@1 294 $split = preg_split('/<([^>]+?)>/', $string, -1, PREG_SPLIT_DELIM_CAPTURE);
webmaster@1 295 // Note: PHP ensures the array consists of alternating delimiters and literals
webmaster@1 296 // and begins and ends with a literal (inserting $null as required).
webmaster@1 297
webmaster@1 298 $tag = FALSE; // Odd/even counter (tag or no tag)
webmaster@1 299 $casing = NULL; // Case conversion function
webmaster@1 300 $output = '';
webmaster@1 301 $indent = array(); // All current indentation string chunks
webmaster@1 302 $lists = array(); // Array of counters for opened lists
webmaster@1 303 foreach ($split as $value) {
webmaster@1 304 $chunk = NULL; // Holds a string ready to be formatted and output.
webmaster@1 305
webmaster@1 306 // Process HTML tags (but don't output any literally).
webmaster@1 307 if ($tag) {
webmaster@1 308 list($tagname) = explode(' ', strtolower($value), 2);
webmaster@1 309 switch ($tagname) {
webmaster@1 310 // List counters
webmaster@1 311 case 'ul':
webmaster@1 312 array_unshift($lists, '*');
webmaster@1 313 break;
webmaster@1 314 case 'ol':
webmaster@1 315 array_unshift($lists, 1);
webmaster@1 316 break;
webmaster@1 317 case '/ul':
webmaster@1 318 case '/ol':
webmaster@1 319 array_shift($lists);
webmaster@1 320 $chunk = ''; // Ensure blank new-line.
webmaster@1 321 break;
webmaster@1 322
webmaster@1 323 // Quotation/list markers, non-fancy headers
webmaster@1 324 case 'blockquote':
webmaster@1 325 // Format=flowed indentation cannot be mixed with lists.
webmaster@1 326 $indent[] = count($lists) ? ' "' : '>';
webmaster@1 327 break;
webmaster@1 328 case 'li':
webmaster@1 329 $indent[] = is_numeric($lists[0]) ? ' '. $lists[0]++ .') ' : ' * ';
webmaster@1 330 break;
webmaster@1 331 case 'dd':
webmaster@1 332 $indent[] = ' ';
webmaster@1 333 break;
webmaster@1 334 case 'h3':
webmaster@1 335 $indent[] = '.... ';
webmaster@1 336 break;
webmaster@1 337 case 'h4':
webmaster@1 338 $indent[] = '.. ';
webmaster@1 339 break;
webmaster@1 340 case '/blockquote':
webmaster@1 341 if (count($lists)) {
webmaster@1 342 // Append closing quote for inline quotes (immediately).
webmaster@1 343 $output = rtrim($output, "> \n") ."\"\n";
webmaster@1 344 $chunk = ''; // Ensure blank new-line.
webmaster@1 345 }
webmaster@1 346 // Fall-through
webmaster@1 347 case '/li':
webmaster@1 348 case '/dd':
webmaster@1 349 array_pop($indent);
webmaster@1 350 break;
webmaster@1 351 case '/h3':
webmaster@1 352 case '/h4':
webmaster@1 353 array_pop($indent);
webmaster@1 354 case '/h5':
webmaster@1 355 case '/h6':
webmaster@1 356 $chunk = ''; // Ensure blank new-line.
webmaster@1 357 break;
webmaster@1 358
webmaster@1 359 // Fancy headers
webmaster@1 360 case 'h1':
webmaster@1 361 $indent[] = '======== ';
webmaster@1 362 $casing = 'drupal_strtoupper';
webmaster@1 363 break;
webmaster@1 364 case 'h2':
webmaster@1 365 $indent[] = '-------- ';
webmaster@1 366 $casing = 'drupal_strtoupper';
webmaster@1 367 break;
webmaster@1 368 case '/h1':
webmaster@1 369 case '/h2':
webmaster@1 370 $casing = NULL;
webmaster@1 371 // Pad the line with dashes.
webmaster@1 372 $output = _drupal_html_to_text_pad($output, ($tagname == '/h1') ? '=' : '-', ' ');
webmaster@1 373 array_pop($indent);
webmaster@1 374 $chunk = ''; // Ensure blank new-line.
webmaster@1 375 break;
webmaster@1 376
webmaster@1 377 // Horizontal rulers
webmaster@1 378 case 'hr':
webmaster@1 379 // Insert immediately.
webmaster@1 380 $output .= drupal_wrap_mail('', implode('', $indent)) ."\n";
webmaster@1 381 $output = _drupal_html_to_text_pad($output, '-');
webmaster@1 382 break;
webmaster@1 383
webmaster@1 384 // Paragraphs and definition lists
webmaster@1 385 case '/p':
webmaster@1 386 case '/dl':
webmaster@1 387 $chunk = ''; // Ensure blank new-line.
webmaster@1 388 break;
webmaster@1 389 }
webmaster@1 390 }
webmaster@1 391 // Process blocks of text.
webmaster@1 392 else {
webmaster@1 393 // Convert inline HTML text to plain text.
webmaster@1 394 $value = trim(preg_replace('/\s+/', ' ', decode_entities($value)));
webmaster@1 395 if (strlen($value)) {
webmaster@1 396 $chunk = $value;
webmaster@1 397 }
webmaster@1 398 }
webmaster@1 399
webmaster@1 400 // See if there is something waiting to be output.
webmaster@1 401 if (isset($chunk)) {
webmaster@1 402 // Apply any necessary case conversion.
webmaster@1 403 if (isset($casing)) {
webmaster@1 404 $chunk = $casing($chunk);
webmaster@1 405 }
webmaster@1 406 // Format it and apply the current indentation.
webmaster@1 407 $output .= drupal_wrap_mail($chunk, implode('', $indent)) ."\n";
webmaster@1 408 // Remove non-quotation markers from indentation.
webmaster@1 409 $indent = array_map('_drupal_html_to_text_clean', $indent);
webmaster@1 410 }
webmaster@1 411
webmaster@1 412 $tag = !$tag;
webmaster@1 413 }
webmaster@1 414
webmaster@1 415 return $output . $footnotes;
webmaster@1 416 }
webmaster@1 417
webmaster@1 418 /**
webmaster@1 419 * Helper function for array_walk in drupal_wrap_mail().
webmaster@1 420 *
webmaster@1 421 * Wraps words on a single line.
webmaster@1 422 */
webmaster@1 423 function _drupal_wrap_mail_line(&$line, $key, $values) {
webmaster@1 424 // Use soft-breaks only for purely quoted or unindented text.
webmaster@1 425 $line = wordwrap($line, 77 - $values['length'], $values['soft'] ? " \n" : "\n");
webmaster@1 426 // Break really long words at the maximum width allowed.
webmaster@1 427 $line = wordwrap($line, 996 - $values['length'], $values['soft'] ? " \n" : "\n");
webmaster@1 428 }
webmaster@1 429
webmaster@1 430 /**
webmaster@1 431 * Helper function for drupal_html_to_text().
webmaster@1 432 *
webmaster@1 433 * Keeps track of URLs and replaces them with placeholder tokens.
webmaster@1 434 */
webmaster@1 435 function _drupal_html_to_mail_urls($match = NULL, $reset = FALSE) {
webmaster@1 436 global $base_url, $base_path;
webmaster@1 437 static $urls = array(), $regexp;
webmaster@11 438
webmaster@1 439 if ($reset) {
webmaster@1 440 // Reset internal URL list.
webmaster@1 441 $urls = array();
webmaster@1 442 }
webmaster@1 443 else {
webmaster@1 444 if (empty($regexp)) {
webmaster@1 445 $regexp = '@^'. preg_quote($base_path, '@') .'@';
webmaster@1 446 }
webmaster@1 447 if ($match) {
webmaster@1 448 list(, , $url, $label) = $match;
webmaster@1 449 // Ensure all URLs are absolute.
webmaster@1 450 $urls[] = strpos($url, '://') ? $url : preg_replace($regexp, $base_url .'/', $url);
webmaster@1 451 return $label .' ['. count($urls) .']';
webmaster@1 452 }
webmaster@1 453 }
webmaster@1 454 return $urls;
webmaster@1 455 }
webmaster@1 456
webmaster@1 457 /**
webmaster@1 458 * Helper function for drupal_wrap_mail() and drupal_html_to_text().
webmaster@1 459 *
webmaster@1 460 * Replace all non-quotation markers from a given piece of indentation with spaces.
webmaster@1 461 */
webmaster@1 462 function _drupal_html_to_text_clean($indent) {
webmaster@1 463 return preg_replace('/[^>]/', ' ', $indent);
webmaster@1 464 }
webmaster@1 465
webmaster@1 466 /**
webmaster@1 467 * Helper function for drupal_html_to_text().
webmaster@1 468 *
webmaster@1 469 * Pad the last line with the given character.
webmaster@1 470 */
webmaster@1 471 function _drupal_html_to_text_pad($text, $pad, $prefix = '') {
webmaster@1 472 // Remove last line break.
webmaster@1 473 $text = substr($text, 0, -1);
webmaster@1 474 // Calculate needed padding space and add it.
webmaster@1 475 if (($p = strrpos($text, "\n")) === FALSE) {
webmaster@1 476 $p = -1;
webmaster@1 477 }
webmaster@1 478 $n = max(0, 79 - (strlen($text) - $p));
webmaster@1 479 // Add prefix and padding, and restore linebreak.
webmaster@1 480 return $text . $prefix . str_repeat($pad, $n - strlen($prefix)) ."\n";
webmaster@1 481 }