From c9d61baf815700ed32427bf46fed3a5cc093216a Mon Sep 17 00:00:00 2001 From: braverock Date: Sun, 6 Jun 2004 14:28:48 +0000 Subject: [PATCH] - add sqBodyWrap utility functions to rewrap entire body rather than one line at a time - improves old sqWordWrap for reply - patch contributed by Justus Pendleton git-svn-id: https://svn.code.sf.net/p/squirrelmail/code/trunk/squirrelmail@7606 7612ce4b-ef26-0410-bec9-ea0150e637f0 --- functions/strings.php | 279 ++++++++++++++++++++++++++++++++++++++---- src/compose.php | 10 +- 2 files changed, 262 insertions(+), 27 deletions(-) diff --git a/functions/strings.php b/functions/strings.php index 6db1afa8..27dfa8a1 100644 --- a/functions/strings.php +++ b/functions/strings.php @@ -33,6 +33,237 @@ $SQM_INTERNAL_VERSION = array(1,5,1); */ require_once(SM_PATH . 'functions/global.php'); +/** + * Appends citation markers to the string. + * Also appends a trailing space. + * + * @author Justus Pendleton + * + * @param string str The string to append to + * @param int citeLevel the number of markers to append + * @return null + */ +function sqMakeCite (&$str, $citeLevel) { + for ($i = 0; $i < $citeLevel; $i++) { + $str .= '>'; + } + if ($citeLevel != 0) { + $str .= ' '; + } +} + +/** + * Create a newline in the string, adding citation + * markers to the newline as necessary. + * + * @author Justus Pendleton + * + * @param string str the string to make a newline in + * @param int citeLevel the citation level the newline is at + * @param int column starting column of the newline + * @return null + */ +function sqMakeNewLine (&$str, $citeLevel, &$column) { + $str .= "\n"; + $column = 0; + if ($citeLevel > 0) { + sqMakeCite ($str, $citeLevel); + $column = $citeLevel + 1; + } else { + $column = 0; + } +} + +/** + * Wraps text at $wrap characters. While sqWordWrap takes + * a single line of text and wraps it, this function works + * on the entire corpus at once, this allows it to be a little + * bit smarter and when and how to wrap. + * + * @author Justus Pendleton + * + * @param string body the entire body of text + * @param int wrap the maximum line length + * @return string the wrapped text + */ +function &sqBodyWrap (&$body, $wrap) { + // the newly wrapped text + $outString = ''; + // current column since the last newline in the outstring + $outStringCol = 0; + $length = strlen($body); + // where we are in the original string + $pos = 0; + // the number of >>> citation markers we are currently at + $citeLevel = 0; + + // the main loop, whenever we start a newline of input text + // we start from here + while ($pos < $length) { + // we're at the beginning of a line, get the new cite level + $newCiteLevel = 0; + + while (($pos < $length) && ($body{$pos} == '>')) { + $newCiteLevel++; + $pos++; + + // skip over any spaces interleaved among the cite markers + while (($pos < $length) && ($body{$pos} == ' ')) { + $pos++; + } + if ($pos >= $length) { + break; + } + } + + // special case: if this is a blank line then maintain it + // (i.e. try to preserve original paragraph breaks) + // unless they occur at the very beginning of the text + if (($body{$pos} == "\n") && (strlen($outString) != 0)) { + $outStringLast = $outString{strlen($outString) - 1}; + if ($outStringLast != "\n") { + $outString .= "\n"; + } + sqMakeCite ($outString, $newCiteLevel); + $outString .= "\n"; + $pos++; + $outStringCol = 0; + continue; + } + + // if the cite level has changed, then start a new line + // with the new cite level. + if (($citeLevel != $newCiteLevel) && ($pos > ($newCiteLevel + 1)) && ($outStringCol != 0)) { + sqMakeNewLine ($outString, 0, $outStringCol); + } + + $citeLevel = $newCiteLevel; + + // prepend the quote level if necessary + if ($outStringCol == 0) { + sqMakeCite ($outString, $citeLevel); + // if we added a citation then move the column + // out by citelevel + 1 (the cite markers + the space) + $outStringCol = $citeLevel + ($citeLevel ? 1 : 0); + } else if ($outStringCol > $citeLevel) { + // not a cite and we're not at the beginning of a line + // in the output. add a space to separate the new text + // from previous text. + $outString .= ' '; + $outStringCol++; + } + + // find the next newline -- we don't want to go further than that + $nextNewline = strpos ($body, "\n", $pos); + if ($nextNewline === FALSE) { + $nextNewline = $length; + } + + // Don't wrap unquoted lines at all. For now the textarea + // will work fine for this. Maybe revisit this later though + // (for completeness more than anything else, I think) + if ($citeLevel == 0) { + $outString .= substr ($body, $pos, ($nextNewline - $pos)); + $outStringCol = $nextNewline - $pos; + if ($nextNewline != $length) { + sqMakeNewLine ($outString, 0, $outStringCol); + } + $pos = $nextNewline + 1; + continue; + } + + // inner loop, (obviously) handles wrapping up to + // the next newline + while ($pos < $nextNewline) { + // skip over initial spaces + while (($pos < $nextNewline) && (ctype_space ($body{$pos}))) { + $pos++; + } + + // if this is a short line then just append it and continue outer loop + if (($outStringCol + $nextNewline - $pos) <= ($wrap - $citeLevel - 1)) { + // if this is the final line in the input string then include + // any trailing newlines + if (($nextNewline + 1 == $length) && ($body{$nextNewline} == "\n")) { + $nextNewline++; + } + + // trim trailing spaces + $lastRealChar = $nextNewline; + while (($lastRealChar > $pos) && (ctype_space ($body{$lastRealChar}))) { + $lastRealChar--; + } + + $outString .= substr ($body, $pos, ($lastRealChar - $pos + 1)); + $outStringCol += ($lastRealChar - $pos); + $pos = $nextNewline + 1; + continue; + } + + $eol = $pos + $wrap - $citeLevel - $outStringCol; + // eol is the tentative end of line. + // look backwards for there for a whitespace to break at. + // if it's already less than our current position then + // our current line is already too long, break immediately + // and restart outer loop + if ($eol <= $pos) { + sqMakeNewLine ($outString, $citeLeve, $outStringCol); + continue; + } + + // start looking backwards for whitespace to break at. + $breakPoint = $eol; + while (($breakPoint > $pos) && (! ctype_space ($body{$breakPoint}))) { + $breakPoint--; + } + + // if we didn't find a breakpoint by looking backward then we + // need to figure out what to do about that + if ($breakPoint == $pos) { + // if we are not at the beginning then end this line + // and start a new loop + if ($outStringCol > ($citeLevel + 1)) { + sqMakeNewLine ($outString, $citeLevel, $outStringCol); + continue; + } else { + // just hard break here. most likely we are breaking + // a really long URL. could also try searching + // forward for a break point, which is what Mozilla + // does. don't bother for now. + $breakPoint = $eol; + } + } + + // special case: maybe we should have wrapped last + // time. if the first breakpoint here makes the + // current line too long and there is already text on + // the current line, break and loop again if at + // beginning of current line, don't force break + $SLOP = 6; + if ((($outStringCol + ($breakPoint - $pos)) > ($wrap + $SLOP)) && ($outStringCol > ($citeLevel + 1))) { + sqMakeNewLine ($outString, $citeLevel, $outStringCol); + continue; + } + + // skip newlines or whitespace at the beginning of the string + $substring = substr ($body, $pos, ($breakPoint - $pos)); + $substring = rtrim ($substring); // do rtrim and ctype_space have the same ideas about whitespace? + $outString .= $substring; + $outStringCol += strlen ($substring); + // advance past the whitespace which caused the wrap + $pos = $breakPoint; + while (($pos < $length) && (ctype_space ($body{$pos}))) { + $pos++; + } + if ($pos < $length) { + sqMakeNewLine ($outString, $citeLevel, $outStringCol); + } + } + } + + return $outString; +} + /** * Wraps text at $wrap characters * @@ -310,8 +541,8 @@ function OneTimePadDecrypt ($string, $epad) { /** * Randomizes the mt_rand() function. * - * Toss this in strings or integers and it will seed the generator - * appropriately. With strings, it is better to get them long. + * Toss this in strings or integers and it will seed the generator + * appropriately. With strings, it is better to get them long. * Use md5() to lengthen smaller strings. * * @param mixed val a value to seed the random number generator @@ -515,14 +746,14 @@ function makeComposeLink($url, $text = null, $target='') } - // if not using "compose in new window", make + // if not using "compose in new window", make // regular link and be done with it if($compose_new_win != '1') { return makeInternalLink($url, $text, $target); } - // build the compose in new window link... + // build the compose in new window link... // if javascript is on, use onClick event to handle it @@ -566,14 +797,14 @@ function sm_print_r() { * version of fwrite which checks for failure */ function sq_fwrite($fp, $string) { - // write to file - $count = @fwrite($fp,$string); - // the number of bytes written should be the length of the string - if($count != strlen($string)) { - return FALSE; - } - - return $count; + // write to file + $count = @fwrite($fp,$string); + // the number of bytes written should be the length of the string + if($count != strlen($string)) { + return FALSE; + } + + return $count; } /** @@ -587,11 +818,11 @@ function sq_fwrite($fp, $string) { *
  • HTML_SPECIALCHARS - html special characters table
  • * * @param integer $quote_style quote encoding style. Possible values (without quotes): - * * @param string $charset charset used for encoding. default to us-ascii, 'auto' uses $default_charset global value. * @return array html translation array */ @@ -605,21 +836,21 @@ function sq_get_html_translation_table($table,$quote_style=ENT_COMPAT,$charset=' // < and > $sq_html_ent_table = array_merge($sq_html_ent_table, - array("<" => '<', - ">" => '>') - ); + array("<" => '<', + ">" => '>') + ); // double quotes if ($quote_style == ENT_COMPAT) $sq_html_ent_table = array_merge($sq_html_ent_table, - array("\"" => '"') - ); + array("\"" => '"') + ); // double and single quotes if ($quote_style == ENT_QUOTES) $sq_html_ent_table = array_merge($sq_html_ent_table, - array("\"" => '"', - "'" => ''') - ); + array("\"" => '"', + "'" => ''') + ); if ($charset=='auto') $charset=$default_charset; @@ -647,11 +878,11 @@ function sq_get_html_translation_table($table,$quote_style=ENT_COMPAT,$charset=' * * @param string $string string that has to be sanitized * @param integer $quote_style quote encoding style. Possible values (without quotes): - * * @param string $charset charset used for encoding. defaults to 'us-ascii', 'auto' uses $default_charset global value. * @return string sanitized string */ diff --git a/src/compose.php b/src/compose.php index 5852039a..9b83c016 100644 --- a/src/compose.php +++ b/src/compose.php @@ -372,6 +372,9 @@ if ($send) { * Rewrap $body so that no line is bigger than $editor_size * This should only really kick in the sqWordWrap function * if the browser doesn't support "VIRTUAL" as the wrap type. + * + * (braverock:) It is unclear if this code should be replaced + * with sqBodyWrap or removed entirely. */ $body = explode("\n", $body); $newBody = ''; @@ -386,7 +389,6 @@ if ($send) { $newBody .= $line . "\n"; } - } $body = $newBody; @@ -790,14 +792,12 @@ function newMail ($mailbox='', $passed_id='', $passed_ent_id='', $action='', $se /* this corrects some wrapping/quoting problems on replies */ $rewrap_body = explode("\n", $body); $from = (is_array($orig_header->from)) ? $orig_header->from[0] : $orig_header->from; - sqUnWordWrap($body); // unwrap and then reset it?! $body = ''; $strip_sigs = getPref($data_dir, $username, 'strip_sigs'); foreach ($rewrap_body as $line) { if ($strip_sigs && substr($line,0,3) == '-- ') { break; } - sqWordWrap($line, ($editor_size)); if (preg_match("/^(>+)/", $line, $matches)) { $gt = $matches[1]; $body .= $body_quote . str_replace("\n", "\n$body_quote$gt ", rtrim($line)) ."\n"; @@ -805,6 +805,10 @@ function newMail ($mailbox='', $passed_id='', $passed_ent_id='', $action='', $se $body .= $body_quote . (!empty($body_quote) ? ' ' : '') . str_replace("\n", "\n$body_quote" . (!empty($body_quote) ? ' ' : ''), rtrim($line)) . "\n"; } } + + //rewrap the body to clean up quotations and line lengths + $body = sqBodyWrap ($body, $editor_size); + $body = getReplyCitation($from , $orig_header->date) . $body; $composeMessage->reply_rfc822_header = $orig_header; -- 2.25.1