| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742 | 
							- <?php
 
- /**
 
-  * @file
 
-  * Copy of drupal_html_to_text improvements from issue #299138.
 
-  */
 
- /**
 
-  * Perform format=flowed soft wrapping for mail (RFC 3676).
 
-  *
 
-  * We use delsp=yes wrapping, but only break non-spaced languages when
 
-  * absolutely necessary to avoid compatibility issues.
 
-  *
 
-  * We deliberately use variable_get('mail_line_endings', MAIL_LINE_ENDINGS)
 
-  * rather than "\r\n".
 
-  *
 
-  * @param $text
 
-  *   The plain text to process.
 
-  * @param array $options
 
-  *   (optional) An array containing one or more of the following keys:
 
-  *   - indent: A string to indent the text with. Only '>' characters are
 
-  *     repeated on subsequent wrapped lines. Others are replaced by spaces.
 
-  *   - max: The maximum length at which to wrap each line. Defaults to 80.
 
-  *   - stuff: Whether to space-stuff special lines.  Defaults to TRUE.
 
-  *   - hard: Whether to enforce the maximum line length even if no convenient
 
-  *     space character is available.  Defaults to FALSE.
 
-  *   - pad: A string to use for padding short lines to 'max' characters.  If
 
-  *     more than one character, only the last will be repeated.
 
-  *   - break: The line break sequence to insert.  The default is one of the
 
-  *     following:
 
-  *     - "\r\n": Windows, when $text does not contain a space character.
 
-  *     - "\n": Non-Windows, when $text does not contain a space character.
 
-  *     - " \r\n": On Windows, when $text contains at least one space.
 
-  *     - " \n": Non-Windows, when $text contains at least one space.
 
-  *
 
-  * @see drupal_mail()
 
-  */
 
- function mailsystem_wrap_mail($text, array $options = array()) {
 
-   static $defaults;
 
-   if (!isset($defaults)) {
 
-     $defaults = array(
 
-       'indent' => '',
 
-       'pad' => '',
 
-       'pad_repeat' => '',
 
-       'max' => 80,
 
-       'stuff' => TRUE,
 
-       'hard' => FALSE,
 
-       'eol' => variable_get('mail_line_endings', MAIL_LINE_ENDINGS),
 
-     );
 
-   }
 
-   $options += $defaults;
 
-   if (!isset($options['break'])) {
 
-     // Allow soft-wrap spaces only when $text contains at least one space.
 
-     $options['break'] = (strpos($text, ' ') === FALSE ? '' : ' ') . $defaults['eol'];
 
-   }
 
-   $options['wrap'] = $options['max'] - drupal_strlen($options['indent']);
 
-   if ($options['pad']) {
 
-     $options['pad_repeat'] = drupal_substr($options['pad'], -1, 1);
 
-   }
 
-   // The 'clean' indent is applied to all lines after the first one.
 
-   $options['clean'] = _mailsystem_html_to_text_clean($options['indent']);
 
-   // Wrap lines according to RFC 3676.
 
-   $lines = explode($defaults['eol'], $text);
 
-   array_walk($lines, '_mailsystem_wrap_mail_line', $options);
 
-   // Expand the lines array on newly-inserted line breaks.
 
-   $lines = explode($defaults['eol'], implode($defaults['eol'], $lines));
 
-   // Apply indentation, space-stuffing, and padding.
 
-   array_walk($lines, '_mailsystem_indent_mail_line', $options);
 
-   return implode($defaults['eol'], $lines);
 
- }
 
- /**
 
-  * Transform an HTML string into plain text, preserving the structure of the
 
-  * markup. Useful for preparing the body of a node to be sent by e-mail.
 
-  *
 
-  * The output will be suitable for use as 'format=flowed; delsp=yes' text
 
-  * (RFC 3676) and can be passed directly to drupal_mail() for sending.
 
-  *
 
-  * We deliberately use variable_get('mail_line_endings', MAIL_LINE_ENDINGS)
 
-  * rather than "\r\n".
 
-  *
 
-  * This function provides suitable alternatives for the following tags:
 
-  *
 
-  * <a> <address> <b> <blockquote> <br /> <caption> <cite> <dd> <div> <dl> <dt>
 
-  * <em> <h1> <h2> <h3> <h4> <h5> <h6> <hr /> <i> <li> <ol> <p> <pre> <strong>
 
-  * <table> <tbody> <td> <tfoot> <thead> <tr> <u> <ul>
 
-  *
 
-  * The following tag attributes are supported:
 
-  * - <a href=...>: Hyperlink destination urls.
 
-  * - <li value=...>: Ordered list item numbers.
 
-  * - <ol start=...>: Ordered list start number.
 
-  *
 
-  * @param $string
 
-  *   The string to be transformed.
 
-  * @param $allowed_tags
 
-  *   (optional) If supplied, a list of tags that will be transformed. If
 
-  *   omitted, all supported tags are transformed.
 
-  *
 
-  * @return
 
-  *   The transformed string.
 
-  *
 
-  * @see drupal_mail()
 
-  */
 
- function mailsystem_html_to_text($string, $allowed_tags = NULL) {
 
-   $eol = variable_get('mail_line_endings', MAIL_LINE_ENDINGS);
 
-   // Cache list of supported tags.
 
-   static $supported_tags;
 
-   if (!isset($supported_tags)) {
 
-     $supported_tags = array(
 
-       'a', 'address', 'b', 'blockquote', 'br', 'cite', 'dd', 'div', 'dl',
 
-       'dt', 'em', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'hr', 'i', 'li',
 
-       'ol', 'p', 'pre', 'strong', 'table', 'td', 'tr', 'u', 'ul',
 
-     );
 
-   }
 
-   // Make sure only supported tags are kept.
 
-   $allowed_tags = isset($allowed_tags) ? array_intersect($supported_tags, $allowed_tags) : $supported_tags;
 
-   // Parse $string into a DOM tree.
 
-   $dom = filter_dom_load($string);
 
-   $notes = array();
 
-   // Recursively convert the DOM tree into plain text.
 
-   $text = _mailsystem_html_to_text($dom->documentElement, $allowed_tags, $notes);
 
-   // Hard-wrap at 1000 characters (including the line break sequence)
 
-   // and space-stuff special lines.
 
-   $text = mailsystem_wrap_mail($text, array('max' => 1000 - strlen($eol), 'hard' => TRUE));
 
-   // Change non-breaking spaces back to regular spaces, and trim line breaks.
 
-   // chr(160) is the non-breaking space character.
 
-   $text = str_replace(chr(160), ' ', trim($text, $eol));
 
-   // Add footnotes;
 
-   if ($notes) {
 
-     // Add a blank line before the footnote list.
 
-     $text .= $eol;
 
-     foreach ($notes as $url => $note) {
 
-       $text .= $eol . '[' . $note . '] ' . $url;
 
-     }
 
-   }
 
-   return $text;
 
- }
 
- /**
 
-  * Helper function for drupal_html_to_text().
 
-  *
 
-  * Recursively converts $node to text, wrapping and indenting as necessary.
 
-  *
 
-  * @param $node
 
-  *   The source DOMNode.
 
-  * @param $allowed_tags
 
-  *   A list of tags that will be transformed.
 
-  * @param array &$notes
 
-  *   A writeable array of footnote reference numbers, keyed by their
 
-  *   respective hyperlink destination urls.
 
-  * @param $line_length
 
-  *   The maximum length of a line, for wrapping.  Defaults to 80 characters.
 
-  * @param array $parents
 
-  *   The list of ancestor tags, from nearest to most distant.  Defaults to an
 
-  *   empty array().
 
-  * @param $count
 
-  *   The number to use for the next list item within an ordered list.  Defaults
 
-  *   to 1.
 
-  */
 
- function _mailsystem_html_to_text(DOMNode $node, array $allowed_tags, array &$notes, $line_length = 80, array $parents = array(), &$count = NULL) {
 
-   if (!isset($count)) {
 
-     $count = 1;
 
-   }
 
-   $eol = variable_get('mail_line_endings', MAIL_LINE_ENDINGS);
 
-   if ($node->nodeType === XML_TEXT_NODE) {
 
-     // For text nodes, we just copy the text content.
 
-     $text = $node->textContent;
 
-     // Convert line breaks and trim trailing spaces.
 
-     $text = preg_replace('/ *\r?\n/', $eol, $text);
 
-     if (in_array('pre', $parents)) {
 
-       // Within <pre> tags, all spaces become non-breaking.
 
-       // chr(160) is the non-breaking space character.
 
-       $text = str_replace(' ', chr(160), $text);
 
-     }
 
-     else {
 
-       // Outside <pre> tags, collapse whitespace.
 
-       $text = preg_replace('/[[:space:]]+/', ' ', $text);
 
-     }
 
-     return $text;
 
-   }
 
-   // Non-text node.
 
-   $tag = '';
 
-   $text = '';
 
-   $child_text = '';
 
-   $child_count = 1;
 
-   $indent = '';
 
-   $prefix = '';
 
-   $suffix = '';
 
-   $pad = '';
 
-   if (isset($node->tagName) && in_array($node->tagName, $allowed_tags)) {
 
-     $tag = $node->tagName;
 
-     switch ($tag) {
 
-       // Turn links with valid hrefs into footnotes.
 
-       case 'a':
 
-         $test = !empty($node->attributes);
 
-         $test = $test && ($href = $node->attributes->getNamedItem('href'));
 
-         $test = $test && ($url = url(preg_replace('|^' . base_path() . '|', '', $href->nodeValue), array('absolute' => TRUE)));
 
-         $test = $test && valid_url($url);
 
-         if ($test) {
 
-           // Only add links that have not already been added.
 
-           if (isset($notes[$url])) {
 
-             $note = $notes[$url];
 
-           }
 
-           else {
 
-             $note = count($notes) + 1;
 
-             $notes[$url] = $note;
 
-           }
 
-           $suffix = ' [' . $note . ']';
 
-         }
 
-         break;
 
-       // Generic block-level tags.
 
-       case 'address':
 
-       case 'caption':
 
-       case 'div':
 
-       case 'p':
 
-       case 'pre':
 
-         // Start on a new line except as the first child of a list item.
 
-         if (!isset($parents[0]) || $parents[0] !== 'li' || !$node->isSameNode($node->parentNode->firstChild)) {
 
-           $text = $eol;
 
-         }
 
-         $suffix = $eol;
 
-         break;
 
-       // Forced line break.
 
-       case 'br':
 
-         $text = $eol;
 
-         break;
 
-       // Boldface by wrapping with "*" characters.
 
-       case 'b':
 
-       case 'strong':
 
-         $prefix = '*';
 
-         $suffix = '*';
 
-         break;
 
-       // Italicize by wrapping with "/" characters.
 
-       case 'cite':
 
-       case 'em':
 
-       case 'i':
 
-         $prefix = '/';
 
-         $suffix = '/';
 
-         break;
 
-       // Underline by wrapping with "_" characters.
 
-       case 'u':
 
-         $prefix = '_';
 
-         $suffix = '_';
 
-         break;
 
-       // Blockquotes are indented by "> " at each level.
 
-       case 'blockquote':
 
-         $text = $eol;
 
-         // chr(160) is the non-breaking space character.
 
-         $indent = '>' . chr(160);
 
-         $suffix = $eol;
 
-         break;
 
-       // Dictionary definitions are indented by four spaces.
 
-       case 'dd':
 
-         // chr(160) is the non-breaking space character.
 
-         $indent = chr(160) . chr(160) . chr(160) . chr(160);
 
-         $suffix = $eol;
 
-         break;
 
-       // Dictionary list.
 
-       case 'dl':
 
-         // Start on a new line as the first child of a list item.
 
-         if (!isset($parents[0]) || $parents[0] !== 'li' || !$node->isSameNode($node->parentNode->firstChild)) {
 
-           $text = $eol;
 
-         }
 
-         $suffix = $eol;
 
-         break;
 
-       // Dictionary term.
 
-       case 'dt':
 
-         $suffix = $eol;
 
-         break;
 
-       // Header level 1 is prefixed by eight "=" characters.
 
-       case 'h1':
 
-         $text = "$eol$eol";
 
-         // chr(160) is the non-breaking space character.
 
-         $indent = '========' . chr(160);
 
-         $pad = chr(160) . '=';
 
-         $suffix = $eol;
 
-         break;
 
-       // Header level 2 is prefixed by six "-" characters.
 
-       case 'h2':
 
-         $text = "$eol$eol";
 
-         // chr(160) is the non-breaking space character.
 
-         $indent = '------' . chr(160);
 
-         $pad = chr(160) . '-';
 
-         $suffix = $eol;
 
-         break;
 
-       // Header level 3 is prefixed by four "." characters and a space.
 
-       case 'h3':
 
-         $text = "$eol$eol";
 
-         // chr(160) is the non-breaking space character.
 
-         $indent = '....' . chr(160);
 
-         $suffix = $eol;
 
-         break;
 
-       // Header level 4 is prefixed by three "." characters and a space.
 
-       case 'h4':
 
-         $text = "$eol$eol";
 
-         // chr(160) is the non-breaking space character.
 
-         $indent = '...' . chr(160);
 
-         $suffix = $eol;
 
-         break;
 
-       // Header level 5 is prefixed by two "." character and a space.
 
-       case 'h5':
 
-         $text = "$eol$eol";
 
-         // chr(160) is the non-breaking space character.
 
-         $indent = '..' . chr(160);
 
-         $suffix = $eol;
 
-         break;
 
-       // Header level 6 is prefixed by one "." character and a space.
 
-       case 'h6':
 
-         $text = "$eol$eol";
 
-         // chr(160) is the non-breaking space character.
 
-         $indent = '.' . chr(160);
 
-         $suffix = $eol;
 
-         break;
 
-       // Horizontal rulers become a line of "-" characters.
 
-       case 'hr':
 
-         $text = $eol;
 
-         $child_text = '-';
 
-         $pad = '-';
 
-         $suffix = $eol;
 
-         break;
 
-       // List items are treated differently depending on the parent tag.
 
-       case 'li':
 
-         // Ordered list item.
 
-         if (reset($parents) === 'ol') {
 
-           // Check the value attribute.
 
-           $test = !empty($node->attributes);
 
-           $test = $test && ($value = $node->attributes->getNamedItem('value'));
 
-           if ($test) {
 
-             $count = $value->nodeValue;
 
-           }
 
-           // chr(160) is the non-breaking space character.
 
-           $indent = ($count < 10 ? chr(160) : '') . chr(160) . "$count)" . chr(160);
 
-           $count++;
 
-         }
 
-         // Unordered list item.
 
-         else {
 
-           // chr(160) is the non-breaking space character.
 
-           $indent = chr(160) . '*' . chr(160);
 
-         }
 
-         $suffix = $eol;
 
-         break;
 
-       // Ordered lists.
 
-       case 'ol':
 
-         // Start on a new line as the first child of a list item.
 
-         if (!isset($parents[0]) || $parents[0] !== 'li' || !$node->isSameNode($node->parentNode->firstChild)) {
 
-           $text = $eol;
 
-         }
 
-         // Check the start attribute.
 
-         $test = !empty($node->attributes);
 
-         $test = $test && ($value = $node->attributes->getNamedItem('start'));
 
-         if ($test) {
 
-           $child_count = $value->nodeValue;
 
-         }
 
-         break;
 
-       // Tables require special handling.
 
-       case 'table':
 
-         return _mailsystem_html_to_text_table($node, $allowed_tags, $notes, $line_length);
 
-       // Separate adjacent table cells by two non-breaking spaces.
 
-       case 'td':
 
-         if (!empty($node->nextSibling)) {
 
-           // chr(160) is the non-breaking space character.
 
-           $suffix = chr(160) . chr(160);
 
-         }
 
-         break;
 
-       // End each table row with a newline.
 
-       case 'tr':
 
-         $suffix = $eol;
 
-         break;
 
-       // Unordered lists.
 
-       case 'ul':
 
-         // Start on a new line as the first child of a list item.
 
-         if (!isset($parents[0]) || $parents[0] !== 'li' || !$node->isSameNode($node->parentNode->firstChild)) {
 
-           $text = $eol;
 
-         }
 
-         break;
 
-       default:
 
-         // Coder review complains if there is no default case.
 
-         break;
 
-     }
 
-     // Only add allowed tags to the $parents array.
 
-     array_unshift($parents, $tag);
 
-   }
 
-   // Copy each child node to output.
 
-   if ($node->hasChildNodes()) {
 
-     foreach ($node->childNodes as $child) {
 
-       $child_text .= _mailsystem_html_to_text($child, $allowed_tags, $notes, $line_length - drupal_strlen($indent), $parents, $child_count);    }
 
-   }
 
-   // We only add prefix and suffix if the child nodes were non-empty.
 
-   if ($child_text > '') {
 
-     // We capitalize the contents of h1 and h2 tags.
 
-     if ($tag === 'h1' || $tag === 'h2') {
 
-       $child_text = drupal_strtoupper($child_text);
 
-     }
 
-     // Don't add a newline to an existing newline.
 
-     if ($suffix === $eol && drupal_substr($child_text, - drupal_strlen($eol)) === $eol) {
 
-       $suffix = '';
 
-     }
 
-     // Trim spaces around newlines except with <pre> or inline tags.
 
-     if (!in_array($tag, array('a', 'b', 'cite', 'em', 'i', 'pre', 'strong', 'u'))) {
 
-       $child_text = preg_replace('/ *' . $eol . ' */', $eol, $child_text);
 
-     }
 
-     // Soft-wrap at effective line length, but don't space-stuff.
 
-     $child_text = mailsystem_wrap_mail(
 
-       $prefix . $child_text,
 
-       array(
 
-         // chr(160) is the non-breaking space character.
 
-         'break' => chr(160) . $eol,
 
-         'indent' => $indent,
 
-         'max' => $line_length,
 
-         'pad' => $pad,
 
-         'stuff' => FALSE,
 
-       )
 
-     ) . $suffix;
 
-     if ($tag === 'pre') {
 
-       // Perform RFC-3676 soft-wrapping.
 
-       // chr(160) is the non-breaking space character.
 
-       $child_text = str_replace(chr(160), ' ', $child_text);
 
-       $child_text = mailsystem_wrap_mail(
 
-         $child_text,
 
-         array('max' => $line_length, 'stuff' => FALSE)
 
-       );
 
-       // chr(160) is the non-breaking space character.
 
-       $child_text = str_replace(' ', chr(160), $child_text);
 
-     }
 
-     $text .= $child_text;
 
-   }
 
-   return $text;
 
- }
 
- /**
 
-  * Helper function for _mailsystem_html_to_text().
 
-  *
 
-  * Renders a <table> DOM Node into plain text.  Attributes such as rowspan,
 
-  * colspan, padding, border, etc. are ignored.
 
-  *
 
-  * @param DOMNode $node
 
-  *   The DOMNode corresponding to the <table> tag and its contents.
 
-  * @param $allowed_tags
 
-  *   The list of allowed tags passed to _mailsystem_html_to_text().
 
-  * @param array &$notes
 
-  *   A writeable array of footnote reference numbers, keyed by their
 
-  *   respective hyperlink destination urls.
 
-  * @param $table_width
 
-  *   The desired maximum table width, after word-wrapping each table cell.
 
-  *
 
-  * @return
 
-  *   A plain text representation of the table.
 
-  *
 
-  * @see _mailsystem_html_to_text()
 
-  */
 
- function _mailsystem_html_to_text_table(DOMNode $node, $allowed_tags = NULL, array &$notes = array(), $table_width = 80) {
 
-   $eol = variable_get('mail_line_endings', MAIL_LINE_ENDINGS);
 
-   $header = array();
 
-   $footer = array();
 
-   $body = array();
 
-   $text = $eol;
 
-   $current = $node;
 
-   while (TRUE) {
 
-     if (isset($current->tagName)) {
 
-       switch ($current->tagName) {
 
-         case 'caption':  // The table caption is added first.
 
-           $text = _mailsystem_html_to_text($current, $allowed_tags, $notes, $table_width);
 
-           break;
 
-         case 'tr':
 
-           switch ($current->parentNode->tagName) {
 
-             case 'thead':
 
-               $header[] = $current;
 
-               break;
 
-             case 'tfoot':
 
-               $footer[] = $current;
 
-               break;
 
-             default: // Either 'tbody' or 'table'
 
-               $body[] = $current;
 
-               break;
 
-           }
 
-           break;
 
-         default:
 
-           if ($current->hasChildNodes()) {
 
-             $current = $current->firstChild;
 
-             continue 2;
 
-           }
 
-       }
 
-     }
 
-     do {
 
-       if ($current->nextSibling) {
 
-         $current = $current->nextSibling;
 
-         continue 2;
 
-       }
 
-       $current = $current->parentNode;
 
-     } while ($current && !$current->isSameNode($node));
 
-     break;
 
-   }
 
-   // Merge the thead, tbody, and tfoot sections together.
 
-   if ($rows = array_merge($header, $body, $footer)) {
 
-     $num_rows = count($rows);
 
-     // First just count the number of columns.
 
-     $num_cols = 0;
 
-     foreach ($rows as $row) {
 
-       $row_cols = 0;
 
-       foreach ($row->childNodes as $cell) {
 
-         if (isset($cell->tagName) && in_array($cell->tagName, array('td', 'th'))) {
 
-           $row_cols++;
 
-         }
 
-       }
 
-       $num_cols = max($num_cols, $row_cols);
 
-     }
 
-     // If any columns were found, calculate each column height and width.
 
-     if ($num_cols) {
 
-       // Set up a binary search for best wrap width for each column.
 
-       $max = max($table_width - $num_cols - 1, 1);
 
-       $max_wraps = array_fill(0, $num_cols, $max);
 
-       $try = max(intval(($table_width - 1) / $num_cols - 1), 1);
 
-       $try_wraps = array_fill(0, $num_cols, $try);
 
-       $min_wraps = array_fill(0, $num_cols, 1);
 
-       // Start searching...
 
-       $change = FALSE;
 
-       do {
 
-         $change = FALSE;
 
-         $widths = array_fill(0, $num_cols, 0);
 
-         $heights = array_fill(0, $num_rows, 0);
 
-         $table = array_fill(0, $num_rows, array_fill(0, $num_cols, ''));
 
-         $breaks = array_fill(0, $num_cols, FALSE);
 
-         foreach ($rows as $i => $row) {
 
-           $j = 0;
 
-           foreach ($row->childNodes as $cell) {
 
-             if (!isset($cell->tagName) || !in_array($cell->tagName, array('td', 'th'))) {
 
-               // Skip text nodes.
 
-               continue;
 
-             }
 
-             // Render the cell contents.
 
-             $cell = _mailsystem_html_to_text($cell, $allowed_tags, $notes, $try_wraps[$j]);
 
-             // Trim leading line-breaks and trailing whitespace.
 
-             // chr(160) is the non-breaking space character.
 
-             $cell = rtrim(ltrim($cell, $eol), ' ' . $eol . chr(160));
 
-             $table[$i][$j] = $cell;
 
-             if ($cell > '') {
 
-               // Split the cell into lines.
 
-               $lines = explode($eol, $cell);
 
-               // The row height is the maximum number of lines among all the
 
-               // cells in that row.
 
-               $heights[$i] = max($heights[$i], count($lines));
 
-               foreach ($lines as $line) {
 
-                 $this_width = drupal_strlen($line);
 
-                 // The column width is the maximum line width among all the
 
-                 // lines in that column.
 
-                 if ($this_width > $widths[$j]) {
 
-                   $widths[$j] = $this_width;
 
-                   // If the longest line in a column contains at least one
 
-                   // space character, then the table can be made narrower.
 
-                   $breaks[$j] = strpos(' ', $line) !== FALSE;
 
-                 }
 
-               }
 
-             }
 
-             $j++;
 
-           }
 
-         }
 
-         // Calculate the total table width;
 
-         $this_width = array_sum($widths) + $num_cols + 1;
 
-         if ($this_width > $table_width) {
 
-           // Wider than desired.
 
-           if (!in_array(TRUE, $breaks)) {
 
-             // If there are no more break points, then the table is already as
 
-             // narrow as it can get, so we're done.
 
-             break;
 
-           }
 
-           foreach ($try_wraps as $i => $wrap) {
 
-             $max_wraps[$i] = min($max_wraps[$i], $wrap);
 
-             if ($breaks[$i]) {
 
-               $new_wrap = intval(($min_wraps[$i] + $max_wraps[$i]) / 2);
 
-               $new_wrap = min($new_wrap, $widths[$i] - 1);
 
-               $new_wrap = max($new_wrap, $min_wraps[$i]);
 
-             }
 
-             else {
 
-               // There's no point in trying to make the column narrower than
 
-               // the widest un-wrappable line in the column.
 
-               $min_wraps[$i] = $widths[$i];
 
-               $new_wrap = $widths[$i];
 
-             }
 
-             if ($try_wraps[$i] > $new_wrap) {
 
-               $try_wraps[$i] = $new_wrap;
 
-               $change = TRUE;
 
-             }
 
-           }
 
-         }
 
-         elseif ($this_width < $table_width) {
 
-           // Narrower than desired.
 
-           foreach ($try_wraps as $i => $wrap) {
 
-             if ($min_wraps[$i] < $wrap) {
 
-               $min_wraps[$i] = $wrap;
 
-             }
 
-             $new_wrap = intval(($min_wraps[$i] + $max_wraps[$i]) / 2);
 
-             $new_wrap = max($new_wrap, $widths[$i] + 1);
 
-             $new_wrap = min($new_wrap, $max_wraps[$i]);
 
-             if ($try_wraps[$i] < $new_wrap) {
 
-               $try_wraps[$i] = $new_wrap;
 
-               $change = TRUE;
 
-             }
 
-           }
 
-         }
 
-       } while ($change);
 
-       // Pad each cell to column width and line height.
 
-       for ($i = 0; $i < $num_rows; $i++) {
 
-         if ($heights[$i]) {
 
-           for ($j = 0; $j < $num_cols; $j++) {
 
-             $cell = $table[$i][$j];
 
-             // Pad each cell to the maximum number of lines in that row.
 
-             $lines = array_pad(explode($eol, $cell), $heights[$i], '');
 
-             foreach ($lines as $k => $line) {
 
-               // Pad each line to the maximum width in that column.
 
-               $repeat = $widths[$j] - drupal_strlen($line);
 
-               if ($repeat > 0) {
 
-                 // chr(160) is the non-breaking space character.
 
-                 $lines[$k] .= str_repeat(chr(160), $repeat);
 
-               }
 
-             }
 
-             $table[$i][$j] = $lines;
 
-           }
 
-         }
 
-       }
 
-       // Generate the row separator line.
 
-       $separator = '+';
 
-       for($i = 0; $i < $num_cols; $i++) {
 
-         $separator .= str_repeat('-', $widths[$i]) . '+';
 
-       }
 
-       $separator .= $eol;
 
-       for ($i = 0; $i < $num_rows; $i++) {
 
-         $text .= $separator;
 
-         if (!$heights[$i]) {
 
-           continue;
 
-         }
 
-         $row = $table[$i];
 
-         // For each row, iterate first by lines within the row.
 
-         for ($k = 0; $k < $heights[$i]; $k++) {
 
-           // Add a vertical-bar at the beginning of each row line.
 
-           $row_line = '|';
 
-           $trimmed = '';
 
-           // Within each row line, iterate by cells within that line.
 
-           for ($j = 0; $j < $num_cols; $j++) {
 
-             // Add a vertical bar at the end of each cell line.
 
-             $row_line .= $row[$j][$k] . '|';
 
-             // chr(160) is the non-breaking space character.
 
-             $trimmed .= trim($row[$j][$k], ' ' . $eol . chr(160));
 
-           }
 
-           if ($trimmed > '') {
 
-             // Only print rows that are non-empty.
 
-             $text .= $row_line . $eol;
 
-           }
 
-         }
 
-       }
 
-       // Final output ends with a row separator.
 
-       $text .= $separator;
 
-     }
 
-   }
 
-   // Make sure formatted table content doesn't line-wrap.
 
-   // chr(160) is the non-breaking space character.
 
-   return str_replace(' ', chr(160), $text);
 
- }
 
- /**
 
-  * Helper function for array_walk in drupal_wrap_mail().
 
-  *
 
-  * Inserts $values['break'] sequences to break up $line into parts of no more
 
-  * than $values['wrap'] characters. Only breaks at space characters, unless
 
-  * $values['hard'] is TRUE.
 
-  */
 
- function _mailsystem_wrap_mail_line(&$line, $key, $values) {
 
-   $line = wordwrap($line, $values['wrap'], $values['break'], $values['hard']);
 
- }
 
- /**
 
-  * Helper function for array_walk in drupal_wrap_mail().
 
-  *
 
-  * If $values['pad'] is non-empty, $values['indent'] will be added at the start
 
-  * of each line, and $values['pad'] at the end, repeating the last character of
 
-  * $values['pad'] until the line length equals $values['max'].
 
-  *
 
-  * If $values['pad'] is empty, $values['indent'] will be added at the start of
 
-  * the first line, and $values['clean'] at the start of subsequent lines.
 
-  *
 
-  * If $values['stuff'] is true, then an extra space character will be added at
 
-  * the start of any line beginning with a space, a '>', or the word 'From'.
 
-  *
 
-  * @see http://www.ietf.org/rfc/rfc3676.txt
 
-  */
 
- function _mailsystem_indent_mail_line(&$line, $key, $values) {
 
-   if ($line == '') {
 
-     return;
 
-   }
 
-   if ($values['pad']) {
 
-     $line = $values['indent'] . $line;
 
-     $count = $values['max'] - drupal_strlen($line) - drupal_strlen($values['pad']);
 
-     if ($count >= 0) {
 
-       $line .= $values['pad'] . str_repeat($values['pad_repeat'], $count);
 
-     }
 
-   }
 
-   else {
 
-     $line = $values[$key === 0 ? 'indent' : 'clean'] . $line;
 
-   }
 
-   if ($values['stuff']) {
 
-     // chr(160) is the non-breaking space character.
 
-     $line = preg_replace('/^(' . chr(160) . '| |>|From)/', ' $1', $line);
 
-   }
 
- }
 
- /**
 
-  * Helper function for drupal_wrap_mail() and drupal_html_to_text().
 
-  *
 
-  * Replace all non-quotation markers from a given piece of indentation with
 
-  * non-breaking space characters.
 
-  */
 
- function _mailsystem_html_to_text_clean($indent) {
 
-   // chr(160) is the non-breaking space character.
 
-   return preg_replace('/[^>]/', chr(160), $indent);
 
- }
 
 
  |