Merge branch 'dev-text2html'
Conflicts:
program/js/app.js
Fix handling magic_quotes in rcube_text2html and rcube_html2text - move
stripslashes from these classes to action files
3 files added
15 files modified
| | |
| | | if (limit <= 0) |
| | | return; |
| | | |
| | | $('pre > blockquote', $('#messagebody')).each(function() { |
| | | $('div.message-part div.pre > blockquote', $('#messagebody')).each(function() { |
| | | var div, link, q = $(this), |
| | | text = $.trim(q.text()), |
| | | res = text.split(/\n/); |
| | |
| | | { |
| | | this.stop_spellchecking(); |
| | | |
| | | if (props.mode == 'html') { |
| | | this.plain2html($('#'+props.id).val(), props.id); |
| | | var input = $('#' + props.id); |
| | | |
| | | if (props.mode == 'html') |
| | | this.plain2html(input.val(), function(data) { |
| | | input.val(data); |
| | | tinyMCE.execCommand('mceAddControl', false, props.id); |
| | | |
| | | if (this.env.default_font) |
| | | if (ref.env.default_font) |
| | | setTimeout(function() { |
| | | $(tinyMCE.get(props.id).getBody()).css('font-family', ref.env.default_font); |
| | | }, 500); |
| | | } |
| | | else if (this.html2plain(tinyMCE.get(props.id).getContent(), props.id)) |
| | | }); |
| | | else |
| | | this.html2plain(tinyMCE.get(props.id).getContent(), function(data) { |
| | | tinyMCE.execCommand('mceRemoveControl', false, props.id); |
| | | input.val(data); |
| | | }); |
| | | |
| | | return true; |
| | | }; |
| | |
| | | /********* html to text conversion functions *********/ |
| | | /********************************************************/ |
| | | |
| | | this.html2plain = function(htmlText, id) |
| | | this.html2plain = function(html, func) |
| | | { |
| | | return this.format_converter(html, 'html', func); |
| | | }; |
| | | |
| | | this.plain2html = function(plain, func) |
| | | { |
| | | return this.format_converter(plain, 'plain', func); |
| | | }; |
| | | |
| | | this.format_converter = function(text, format, func) |
| | | { |
| | | // warn the user (if converted content is not empty) |
| | | if (!htmlText || !(htmlText.replace(/<[^>]+>| |\s/g, '')).length) { |
| | | if (!text |
| | | || (format == 'html' && !(text.replace(/<[^>]+>| |\xC2\xA0|\s/g, '')).length) |
| | | || (format != 'html' && !(text.replace(/\xC2\xA0|\s/g, '')).length) |
| | | ) { |
| | | // without setTimeout() here, textarea is filled with initial (onload) content |
| | | setTimeout(function() { $('#'+id).val(''); }, 50); |
| | | setTimeout(function() { if (func) func(''); }, 50); |
| | | return true; |
| | | } |
| | | |
| | | if (!confirm(this.get_label('editorwarning'))) |
| | | var confirmed = this.env.editor_warned || confirm(this.get_label('editorwarning')); |
| | | |
| | | this.env.editor_warned = true; |
| | | |
| | | if (!confirmed) |
| | | return false; |
| | | |
| | | var url = '?_task=utils&_action=html2text', |
| | | var url = '?_task=utils&_action=' + (format == 'html' ? 'html2text' : 'text2html'), |
| | | lock = this.set_busy(true, 'converting'); |
| | | |
| | | this.log('HTTP POST: ' + url); |
| | | |
| | | $.ajax({ type: 'POST', url: url, data: htmlText, contentType: 'application/octet-stream', |
| | | $.ajax({ type: 'POST', url: url, data: text, contentType: 'application/octet-stream', |
| | | error: function(o, status, err) { ref.http_error(o, status, err, lock); }, |
| | | success: function(data) { ref.set_busy(false, null, lock); $('#'+id).val(data); ref.log(data); } |
| | | success: function(data) { |
| | | ref.set_busy(false, null, lock); |
| | | if (func) func(data); |
| | | } |
| | | }); |
| | | |
| | | return true; |
| | | }; |
| | | |
| | | this.plain2html = function(plain, id) |
| | | { |
| | | var lock = this.set_busy(true, 'converting'); |
| | | |
| | | plain = plain.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>'); |
| | | $('#'+id).val(plain ? '<pre>'+plain+'</pre>' : ''); |
| | | |
| | | this.set_busy(false, null, lock); |
| | | }; |
| | | |
| | | |
| | |
| | | apply_source_formatting: true, |
| | | theme: 'advanced', |
| | | language: config.lang, |
| | | content_css: config.skin_path + '/editor_content.css', |
| | | content_css: config.skin_path + '/editor_content.css?v2', |
| | | theme_advanced_toolbar_location: 'top', |
| | | theme_advanced_toolbar_align: 'left', |
| | | theme_advanced_buttons3: '', |
| | |
| | | // Variables used for building the link list |
| | | $this->_link_list = array(); |
| | | |
| | | $text = trim(stripslashes($this->html)); |
| | | $text = $this->html; |
| | | |
| | | // Convert HTML to TXT |
| | | $this->_converter($text); |
| | |
| | | * Interpret a format=flowed message body according to RFC 2646 |
| | | * |
| | | * @param string $text Raw body formatted as flowed text |
| | | * @param string $mark Mark each flowed line with specified character |
| | | * |
| | | * @return string Interpreted text with unwrapped lines and stuffed space removed |
| | | */ |
| | | public static function unfold_flowed($text) |
| | | public static function unfold_flowed($text, $mark = null) |
| | | { |
| | | $text = preg_split('/\r?\n/', $text); |
| | | $last = -1; |
| | | $q_level = 0; |
| | | $marks = array(); |
| | | |
| | | foreach ($text as $idx => $line) { |
| | | if (preg_match('/^(>+)/', $line, $m)) { |
| | |
| | | ) { |
| | | $text[$last] .= $line; |
| | | unset($text[$idx]); |
| | | |
| | | if ($mark) { |
| | | $marks[$last] = true; |
| | | } |
| | | } |
| | | else { |
| | | $last = $idx; |
| | |
| | | } |
| | | else { |
| | | // remove space-stuffing |
| | | $line = preg_replace('/^\s/', '', $line); |
| | | $line = preg_replace('/^ /', '', $line); |
| | | |
| | | if (isset($text[$last]) && $line |
| | | && $text[$last] != '-- ' |
| | |
| | | ) { |
| | | $text[$last] .= $line; |
| | | unset($text[$idx]); |
| | | |
| | | if ($mark) { |
| | | $marks[$last] = true; |
| | | } |
| | | } |
| | | else { |
| | | $text[$idx] = $line; |
| | |
| | | $q_level = $q; |
| | | } |
| | | |
| | | if (!empty($marks)) { |
| | | foreach (array_keys($marks) as $mk) { |
| | | $text[$mk] = $mark . $text[$mk]; |
| | | } |
| | | } |
| | | |
| | | return implode("\r\n", $text); |
| | | } |
| | | |
New file |
| | |
| | | <?php |
| | | |
| | | /** |
| | | +-----------------------------------------------------------------------+ |
| | | | This file is part of the Roundcube Webmail client | |
| | | | Copyright (C) 2008-2014, The Roundcube Dev Team | |
| | | | | |
| | | | Licensed under the GNU General Public License version 3 or | |
| | | | any later version with exceptions for skins & plugins. | |
| | | | See the README file for a full license statement. | |
| | | | | |
| | | | PURPOSE: | |
| | | | Converts plain text to HTML | |
| | | +-----------------------------------------------------------------------+ |
| | | | Author: Aleksander Machniak <alec@alec.pl> | |
| | | +-----------------------------------------------------------------------+ |
| | | */ |
| | | |
| | | /** |
| | | * Converts plain text to HTML |
| | | * |
| | | * @package Framework |
| | | * @subpackage Utils |
| | | */ |
| | | class rcube_text2html |
| | | { |
| | | /** |
| | | * Contains the HTML content after conversion. |
| | | * |
| | | * @var string $html |
| | | */ |
| | | protected $html; |
| | | |
| | | /** |
| | | * Contains the plain text. |
| | | * |
| | | * @var string $text |
| | | */ |
| | | protected $text; |
| | | |
| | | /** |
| | | * Configuration |
| | | * |
| | | * @var array $config |
| | | */ |
| | | protected $config = array( |
| | | // non-breaking space |
| | | 'space' => "\xC2\xA0", |
| | | // enables format=flowed parser |
| | | 'flowed' => false, |
| | | // enables wrapping for non-flowed text |
| | | 'wrap' => true, |
| | | // line-break tag |
| | | 'break' => "<br>\n", |
| | | // prefix and suffix (wrapper element) |
| | | 'begin' => '<div class="pre">', |
| | | 'end' => '</div>', |
| | | // enables links replacement |
| | | 'links' => true, |
| | | ); |
| | | |
| | | |
| | | /** |
| | | * Constructor. |
| | | * |
| | | * If the plain text source string (or file) is supplied, the class |
| | | * will instantiate with that source propagated, all that has |
| | | * to be done it to call get_html(). |
| | | * |
| | | * @param string $source Plain text |
| | | * @param boolean $from_file Indicates $source is a file to pull content from |
| | | * @param array $config Class configuration |
| | | */ |
| | | function __construct($source = '', $from_file = false, $config = array()) |
| | | { |
| | | if (!empty($source)) { |
| | | $this->set_text($source, $from_file); |
| | | } |
| | | |
| | | if (!empty($config) && is_array($config)) { |
| | | $this->config = array_merge($this->config, $config); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Loads source text into memory, either from $source string or a file. |
| | | * |
| | | * @param string $source Plain text |
| | | * @param boolean $from_file Indicates $source is a file to pull content from |
| | | */ |
| | | function set_text($source, $from_file = false) |
| | | { |
| | | if ($from_file && file_exists($source)) { |
| | | $this->text = file_get_contents($source); |
| | | } |
| | | else { |
| | | $this->text = $source; |
| | | } |
| | | |
| | | $this->_converted = false; |
| | | } |
| | | |
| | | /** |
| | | * Returns the HTML content. |
| | | * |
| | | * @return string HTML content |
| | | */ |
| | | function get_html() |
| | | { |
| | | if (!$this->_converted) { |
| | | $this->_convert(); |
| | | } |
| | | |
| | | return $this->html; |
| | | } |
| | | |
| | | /** |
| | | * Prints the HTML. |
| | | */ |
| | | function print_html() |
| | | { |
| | | print $this->get_html(); |
| | | } |
| | | |
| | | /** |
| | | * Workhorse function that does actual conversion (calls _converter() method). |
| | | */ |
| | | protected function _convert() |
| | | { |
| | | // Convert TXT to HTML |
| | | $this->html = $this->_converter($this->text); |
| | | $this->_converted = true; |
| | | } |
| | | |
| | | /** |
| | | * Workhorse function that does actual conversion. |
| | | * |
| | | * @param string Plain text |
| | | */ |
| | | protected function _converter($text) |
| | | { |
| | | // make links and email-addresses clickable |
| | | $attribs = array('link_attribs' => array('rel' => 'noreferrer', 'target' => '_blank')); |
| | | $replacer = new rcmail_string_replacer($attribs); |
| | | |
| | | if ($this->config['flowed']) { |
| | | $flowed_char = 0x01; |
| | | $text = rcube_mime::unfold_flowed($text, chr($flowed_char)); |
| | | } |
| | | |
| | | // search for patterns like links and e-mail addresses and replace with tokens |
| | | if ($this->config['links']) { |
| | | $text = $replacer->replace($text); |
| | | } |
| | | |
| | | // split body into single lines |
| | | $text = preg_split('/\r?\n/', $text); |
| | | $quote_level = 0; |
| | | $last = null; |
| | | |
| | | // wrap quoted lines with <blockquote> |
| | | for ($n = 0, $cnt = count($text); $n < $cnt; $n++) { |
| | | $flowed = false; |
| | | if ($this->config['flowed'] && ord($text[$n][0]) == $flowed_char) { |
| | | $flowed = true; |
| | | $text[$n] = substr($text[$n], 1); |
| | | } |
| | | |
| | | if ($text[$n][0] == '>' && preg_match('/^(>+ {0,1})+/', $text[$n], $regs)) { |
| | | $q = substr_count($regs[0], '>'); |
| | | $text[$n] = substr($text[$n], strlen($regs[0])); |
| | | $text[$n] = $this->_convert_line($text[$n], $flowed || $this->config['wrap']); |
| | | $_length = strlen(str_replace(' ', '', $text[$n])); |
| | | |
| | | if ($q > $quote_level) { |
| | | if ($last !== null) { |
| | | $text[$last] .= (!$length ? "\n" : '') |
| | | . $replacer->get_replacement($replacer->add( |
| | | str_repeat('<blockquote>', $q - $quote_level))) |
| | | . $text[$n]; |
| | | |
| | | unset($text[$n]); |
| | | } |
| | | else { |
| | | $text[$n] = $replacer->get_replacement($replacer->add( |
| | | str_repeat('<blockquote>', $q - $quote_level))) . $text[$n]; |
| | | |
| | | $last = $n; |
| | | } |
| | | } |
| | | else if ($q < $quote_level) { |
| | | $text[$last] .= (!$length ? "\n" : '') |
| | | . $replacer->get_replacement($replacer->add( |
| | | str_repeat('</blockquote>', $quote_level - $q))) |
| | | . $text[$n]; |
| | | |
| | | unset($text[$n]); |
| | | } |
| | | else { |
| | | $last = $n; |
| | | } |
| | | } |
| | | else { |
| | | $text[$n] = $this->_convert_line($text[$n], $flowed || $this->config['wrap']); |
| | | $q = 0; |
| | | $_length = strlen(str_replace(' ', '', $text[$n])); |
| | | |
| | | if ($quote_level > 0) { |
| | | $text[$last] .= (!$length ? "\n" : '') |
| | | . $replacer->get_replacement($replacer->add( |
| | | str_repeat('</blockquote>', $quote_level))) |
| | | . $text[$n]; |
| | | |
| | | unset($text[$n]); |
| | | } |
| | | else { |
| | | $last = $n; |
| | | } |
| | | } |
| | | |
| | | $quote_level = $q; |
| | | $length = $_length; |
| | | } |
| | | |
| | | if ($quote_level > 0) { |
| | | $text[$last] .= $replacer->get_replacement($replacer->add( |
| | | str_repeat('</blockquote>', $quote_level))); |
| | | } |
| | | |
| | | $text = join("\n", $text); |
| | | |
| | | // colorize signature (up to <sig_max_lines> lines) |
| | | $len = strlen($text); |
| | | $sig_sep = "--" . $this->config['space'] . "\n"; |
| | | $sig_max_lines = rcube::get_instance()->config->get('sig_max_lines', 15); |
| | | |
| | | while (($sp = strrpos($text, $sig_sep, $sp ? -$len+$sp-1 : 0)) !== false) { |
| | | if ($sp == 0 || $text[$sp-1] == "\n") { |
| | | // do not touch blocks with more that X lines |
| | | if (substr_count($text, "\n", $sp) < $sig_max_lines) { |
| | | $text = substr($text, 0, max(0, $sp)) |
| | | .'<span class="sig">'.substr($text, $sp).'</span>'; |
| | | } |
| | | |
| | | break; |
| | | } |
| | | } |
| | | |
| | | // insert url/mailto links and citation tags |
| | | $text = $replacer->resolve($text); |
| | | |
| | | // replace line breaks |
| | | $text = str_replace("\n", $this->config['break'], $text); |
| | | |
| | | return $this->config['begin'] . $text . $this->config['end']; |
| | | } |
| | | |
| | | /** |
| | | * Converts spaces in line of text |
| | | */ |
| | | protected function _convert_line($text, $is_flowed) |
| | | { |
| | | static $table; |
| | | |
| | | if (empty($table)) { |
| | | $table = get_html_translation_table(HTML_SPECIALCHARS); |
| | | unset($table['?']); |
| | | } |
| | | |
| | | // skip signature separator |
| | | if ($text == '-- ') { |
| | | return '--' . $this->config['space']; |
| | | } |
| | | |
| | | // replace HTML special characters |
| | | $text = strtr($text, $table); |
| | | |
| | | $nbsp = $this->config['space']; |
| | | |
| | | // replace some whitespace characters |
| | | $text = str_replace(array("\r", "\t"), array('', ' '), $text); |
| | | |
| | | // replace spaces with non-breaking spaces |
| | | if ($is_flowed) { |
| | | $pos = 0; |
| | | $diff = 0; |
| | | $len = strlen($nbsp); |
| | | $copy = $text; |
| | | |
| | | while (($pos = strpos($text, ' ', $pos)) !== false) { |
| | | if ($pos == 0 || $text[$pos-1] == ' ') { |
| | | $copy = substr_replace($copy, $nbsp, $pos + $diff, 1); |
| | | $diff += $len - 1; |
| | | } |
| | | $pos++; |
| | | } |
| | | |
| | | $text = $copy; |
| | | } |
| | | else { |
| | | // make the whole line non-breakable |
| | | $text = str_replace(array(' ', '-', '/'), array($nbsp, '-⁠', '/⁠'), $text); |
| | | } |
| | | |
| | | return $text; |
| | | } |
| | | } |
| | |
| | | $messages['importmessageerror'] = 'Import failed! The uploaded file is not a valid message or mailbox file'; |
| | | $messages['opnotpermitted'] = 'Operation not permitted!'; |
| | | $messages['nofromaddress'] = 'Missing e-mail address in selected identity.'; |
| | | $messages['editorwarning'] = 'Switching to the plain text editor will cause all text formatting to be lost. Do you wish to continue?'; |
| | | $messages['editorwarning'] = 'Switching editor type may cause text formatting to be lost. Do you wish to continue?'; |
| | | $messages['httpreceivedencrypterror'] = 'A fatal configuration error occurred. Contact your administrator immediately. <b>Your message can not be sent.</b>'; |
| | | $messages['smtpconnerror'] = 'SMTP Error ($code): Connection to server failed.'; |
| | | $messages['smtpautherror'] = 'SMTP Error ($code): Authentication failed.'; |
| | |
| | | } |
| | | |
| | | if (!$sql_arr['html_signature']) { |
| | | $html = "<pre>" . $html . "</pre>"; |
| | | $t2h = new rcube_text2html($sql_arr['signature'], false); |
| | | $html = $t2h->get_html(); |
| | | } |
| | | |
| | | $a_signatures[$identity_id]['text'] = $text; |
| | |
| | | } |
| | | } |
| | | |
| | | if ($part->ctype_parameters['format'] == 'flowed') { |
| | | $body = rcube_mime::unfold_flowed($body); |
| | | } |
| | | |
| | | // add HTML formatting |
| | | $body = rcmail_plain_body($body); |
| | | if ($body) { |
| | | $body = '<pre>' . $body . '</pre>'; |
| | | } |
| | | $body = rcmail_plain_body($body, $part->ctype_parameters['format'] == 'flowed'); |
| | | } |
| | | } |
| | | else { |
| | |
| | | |
| | | // plaintext postprocessing |
| | | if ($part->ctype_secondary == 'plain') { |
| | | if ($part->ctype_secondary == 'plain' && $part->ctype_parameters['format'] == 'flowed') { |
| | | $body = rcube_mime::unfold_flowed($body); |
| | | } |
| | | |
| | | $body = rcmail_plain_body($body); |
| | | $body = rcmail_plain_body($body, $part->ctype_parameters['format'] == 'flowed'); |
| | | } |
| | | |
| | | // allow post-processing of the message body |
| | | $data = $RCMAIL->plugins->exec_hook('message_part_after', |
| | | array('type' => $part->ctype_secondary, 'body' => $body, 'id' => $part->mime_id) + $data); |
| | | |
| | | return $data['type'] == 'html' ? $data['body'] : html::tag('pre', array(), $data['body']); |
| | | return $data['body']; |
| | | } |
| | | |
| | | /** |
| | | * Handle links and citation marks in plain text message |
| | | * |
| | | * @param string Plain text string |
| | | * @param boolean Set to True if the source text is in format=flowed |
| | | * |
| | | * @return string Formatted HTML string |
| | | */ |
| | | function rcmail_plain_body($body) |
| | | function rcmail_plain_body($body, $flowed = false) |
| | | { |
| | | global $RCMAIL; |
| | | |
| | | // make links and email-addresses clickable |
| | | $attribs = array('link_attribs' => array('rel' => 'noreferrer', 'target' => '_blank')); |
| | | $replacer = new rcmail_string_replacer($attribs); |
| | | |
| | | // search for patterns like links and e-mail addresses and replace with tokens |
| | | $body = $replacer->replace($body); |
| | | |
| | | // split body into single lines |
| | | $body = preg_split('/\r?\n/', $body); |
| | | $quote_level = 0; |
| | | $last = -1; |
| | | |
| | | // find/mark quoted lines... |
| | | for ($n=0, $cnt=count($body); $n < $cnt; $n++) { |
| | | if ($body[$n][0] == '>' && preg_match('/^(>+ {0,1})+/', $body[$n], $regs)) { |
| | | $q = substr_count($regs[0], '>'); |
| | | $body[$n] = substr($body[$n], strlen($regs[0])); |
| | | |
| | | if ($q > $quote_level) { |
| | | $body[$n] = $replacer->get_replacement($replacer->add( |
| | | str_repeat('<blockquote>', $q - $quote_level))) . $body[$n]; |
| | | $last = $n; |
| | | } |
| | | else if ($q < $quote_level) { |
| | | $body[$n] = $replacer->get_replacement($replacer->add( |
| | | str_repeat('</blockquote>', $quote_level - $q))) . $body[$n]; |
| | | $last = $n; |
| | | } |
| | | } |
| | | else { |
| | | $q = 0; |
| | | if ($quote_level > 0) |
| | | $body[$n] = $replacer->get_replacement($replacer->add( |
| | | str_repeat('</blockquote>', $quote_level))) . $body[$n]; |
| | | } |
| | | |
| | | $quote_level = $q; |
| | | } |
| | | |
| | | $body = join("\n", $body); |
| | | |
| | | // quote plain text (don't use rcube::Q() here, to display entities "as is") |
| | | $table = get_html_translation_table(HTML_SPECIALCHARS); |
| | | unset($table['?']); |
| | | $body = strtr($body, $table); |
| | | |
| | | // colorize signature (up to <sig_max_lines> lines) |
| | | $len = strlen($body); |
| | | $sig_max_lines = $RCMAIL->config->get('sig_max_lines', 15); |
| | | |
| | | while (($sp = strrpos($body, "-- \n", $sp ? -$len+$sp-1 : 0)) !== false) { |
| | | if ($sp == 0 || $body[$sp-1] == "\n") { |
| | | // do not touch blocks with more that X lines |
| | | if (substr_count($body, "\n", $sp) < $sig_max_lines) { |
| | | $body = substr($body, 0, max(0, $sp)) |
| | | . '<span class="sig">'.substr($body, $sp).'</span>'; |
| | | } |
| | | |
| | | break; |
| | | } |
| | | } |
| | | |
| | | // insert url/mailto links and citation tags |
| | | $body = $replacer->resolve($body); |
| | | $options = array('flowed' => $flowed, 'wrap' => !$flowed); |
| | | $text2html = new rcube_text2html($body, false, $options); |
| | | $body = $text2html->get_html(); |
| | | |
| | | return $body; |
| | | } |
| | |
| | | $plugin = $RCMAIL->plugins->exec_hook('message_body_prefix', |
| | | array('part' => $MESSAGE, 'prefix' => '')); |
| | | |
| | | $out .= html::div('message-part', $plugin['prefix'] . html::tag('pre', array(), |
| | | rcmail_plain_body(rcube::Q($MESSAGE->body, 'strict', false)))); |
| | | $out .= html::div('message-part', |
| | | $plugin['prefix'] . rcmail_plain_body($MESSAGE->body)); |
| | | } |
| | | } |
| | | |
| | |
| | | |
| | | if (!$savedraft) { |
| | | if ($isHtml) { |
| | | // remove signature's div ID |
| | | $message_body = preg_replace('/\s*id="_rc_sig"/', '', $message_body); |
| | | $b_style = 'padding: 0 0.4em; border-left: #1010ff 2px solid; margin: 0'; |
| | | $pre_style = 'margin: 0; padding: 0; font-family: monospace'; |
| | | |
| | | // add inline css for blockquotes |
| | | $bstyle = 'padding-left:5px; border-left:#1010ff 2px solid; margin-left:5px'; |
| | | $message_body = preg_replace('/<blockquote>/', |
| | | '<blockquote type="cite" style="'.$bstyle.'">', $message_body); |
| | | $message_body = preg_replace( |
| | | array( |
| | | // remove signature's div ID |
| | | '/\s*id="_rc_sig"/', |
| | | // add inline css for blockquotes and container |
| | | '/<blockquote>/', |
| | | '/<div class="pre">/' |
| | | ), |
| | | array( |
| | | '', |
| | | '<blockquote type="cite" style="'.$b_style.'">', |
| | | '<div class="pre" style="'.$pre_style.'">' |
| | | ), |
| | | $message_body); |
| | | } |
| | | |
| | | // Check spelling before send |
| | |
| | | if (!preg_match('/\.(php|ini|conf)$/', $file) && strpos($file, '/etc/') === false) { |
| | | $footer = file_get_contents($file); |
| | | if ($isHtml && !$html_footer) { |
| | | $footer = '<pre>' . $footer . '</pre>'; |
| | | $t2h = new rcube_text2html($footer, false); |
| | | $footer = $t2h->get_html(); |
| | | } |
| | | return $footer; |
| | | } |
| | |
| | | |
| | | $html = stream_get_contents(fopen('php://input', 'r')); |
| | | |
| | | // strip slashes if magic_quotes enabled |
| | | if (get_magic_quotes_gpc() || get_magic_quotes_runtime()) { |
| | | $html = stripslashes($html); |
| | | } |
| | | |
| | | // Replace emoticon images with its text representation |
| | | $html = $RCMAIL->replace_emoticons($html); |
| | | |
New file |
| | |
| | | <?php |
| | | |
| | | /* |
| | | +-----------------------------------------------------------------------+ |
| | | | program/steps/utils/text2html.inc | |
| | | | | |
| | | | This file is part of the Roundcube Webmail client | |
| | | | Copyright (C) 2005-2014, The Roundcube Dev Team | |
| | | | | |
| | | | Licensed under the GNU General Public License version 3 or | |
| | | | any later version with exceptions for skins & plugins. | |
| | | | See the README file for a full license statement. | |
| | | | | |
| | | | PURPOSE: | |
| | | | Convert plain text to HTML | |
| | | | | |
| | | +-----------------------------------------------------------------------+ |
| | | | Author: Thomas Bruederli <roundcube@gmail.com> | |
| | | +-----------------------------------------------------------------------+ |
| | | */ |
| | | |
| | | $text = stream_get_contents(fopen('php://input', 'r')); |
| | | |
| | | // strip slashes if magic_quotes enabled |
| | | if (get_magic_quotes_gpc() || get_magic_quotes_runtime()) { |
| | | $html = stripslashes($html); |
| | | } |
| | | |
| | | $converter = new rcube_text2html($text, false, array('wrap' => true)); |
| | | |
| | | header('Content-Type: text/html; charset=' . RCUBE_CHARSET); |
| | | print $converter->get_html(); |
| | | exit; |
| | |
| | | margin-top: 2px; |
| | | } |
| | | |
| | | pre |
| | | { |
| | | div.pre { |
| | | margin: 0; |
| | | padding: 0; |
| | | white-space: -moz-pre-wrap !important; |
| | | white-space: pre-wrap !important; |
| | | white-space: pre; |
| | | word-wrap: break-word; /* IE (and Safari) */ |
| | | font-family: monospace; |
| | | } |
| | | |
| | | blockquote |
| | | { |
| | | padding-left: 5px; |
| | | border-left: #1010ff 2px solid; |
| | | margin-left: 5px; |
| | | width: 100%; |
| | | margin: 0; |
| | | padding: 0 0.4em; |
| | | } |
| | |
| | | color: #0000CC; |
| | | } |
| | | |
| | | div.message-part pre, |
| | | div.message-htmlpart pre, |
| | | div.message-part div.pre |
| | | { |
| | | margin: 0px; |
| | | padding: 0px; |
| | | font-family: monospace; |
| | | font-size: 12px; |
| | | white-space: -moz-pre-wrap !important; |
| | | white-space: pre-wrap !important; |
| | | white-space: pre; |
| | | } |
| | | |
| | | div.message-part span.sig |
| | |
| | | border-left: 2px solid blue; |
| | | border-right: 2px solid blue; |
| | | background-color: #F6F6F6; |
| | | margin: 2px 0px; |
| | | padding: 1px 8px 1px 10px; |
| | | margin: 2px 0; |
| | | padding: 0 0.4em; |
| | | overflow: hidden; |
| | | text-overflow: ellipsis; |
| | | } |
| | | |
| | | div.message-part blockquote blockquote |
| | |
| | | margin-top: 2px; |
| | | } |
| | | |
| | | pre |
| | | { |
| | | div.pre { |
| | | margin: 0; |
| | | padding: 0; |
| | | white-space: -moz-pre-wrap !important; |
| | | white-space: pre-wrap !important; |
| | | white-space: pre; |
| | | word-wrap: break-word; /* IE (and Safari) */ |
| | | font-family: monospace; |
| | | } |
| | | |
| | | blockquote |
| | | { |
| | | padding-left: 5px; |
| | | border-left: #1010ff 2px solid; |
| | | margin-left: 5px; |
| | | width: 100%; |
| | | margin: 0; |
| | | padding: 0 0.4em; |
| | | } |
| | |
| | | border-top: 0; |
| | | } |
| | | |
| | | div.message-part pre, |
| | | div.message-htmlpart pre, |
| | | div.message-part div.pre { |
| | | margin: 0; |
| | | padding: 0; |
| | | font-family: monospace; |
| | | font-size: 12px; |
| | | white-space: -moz-pre-wrap !important; |
| | | white-space: pre-wrap !important; |
| | | white-space: pre; |
| | | } |
| | | |
| | | div.message-part span.sig { |
| | |
| | | border-left: 2px solid blue; |
| | | border-right: 2px solid blue; |
| | | background-color: #F6F6F6; |
| | | margin: 2px 0 2px 0; |
| | | padding: 1px 8px 1px 10px; |
| | | margin: 2px 0; |
| | | padding: 0 0.4em; |
| | | overflow: hidden; |
| | | text-overflow: ellipsis; |
| | | } |
| | | |
| | | div.message-part blockquote blockquote { |
New file |
| | |
| | | <?php |
| | | |
| | | /** |
| | | * Test class to test rcube_text2html class |
| | | * |
| | | * @package Tests |
| | | */ |
| | | class Framework_Text2Html extends PHPUnit_Framework_TestCase |
| | | { |
| | | |
| | | /** |
| | | * Data for test_text2html() |
| | | */ |
| | | function data_text2html() |
| | | { |
| | | $options = array( |
| | | 'begin' => '', |
| | | 'end' => '', |
| | | 'break' => '<br>', |
| | | 'links' => false, |
| | | 'flowed' => false, |
| | | 'wrap' => false, |
| | | 'space' => '_', // replace UTF-8 non-breaking space for simpler testing |
| | | ); |
| | | |
| | | $data[] = array(" aaaa", "_aaaa", $options); |
| | | $data[] = array("aaaa aaaa", "aaaa_aaaa", $options); |
| | | $data[] = array("aaaa aaaa", "aaaa__aaaa", $options); |
| | | $data[] = array("aaaa aaaa", "aaaa___aaaa", $options); |
| | | $data[] = array("aaaa\taaaa", "aaaa____aaaa", $options); |
| | | $data[] = array("aaaa\naaaa", "aaaa<br>aaaa", $options); |
| | | $data[] = array("aaaa\n aaaa", "aaaa<br>_aaaa", $options); |
| | | $data[] = array("aaaa\n aaaa", "aaaa<br>__aaaa", $options); |
| | | $data[] = array("aaaa\n aaaa", "aaaa<br>___aaaa", $options); |
| | | $data[] = array("\taaaa", "____aaaa", $options); |
| | | $data[] = array("\naaaa", "<br>aaaa", $options); |
| | | $data[] = array("\n aaaa", "<br>_aaaa", $options); |
| | | $data[] = array("\n aaaa", "<br>__aaaa", $options); |
| | | $data[] = array("\n aaaa", "<br>___aaaa", $options); |
| | | $data[] = array("aaaa\n\nbbbb", "aaaa<br><br>bbbb", $options); |
| | | $data[] = array(">aaaa \n>aaaa", "<blockquote>aaaa_<br>aaaa</blockquote>", $options); |
| | | $data[] = array(">aaaa\n>aaaa", "<blockquote>aaaa<br>aaaa</blockquote>", $options); |
| | | $data[] = array(">aaaa \n>bbbb\ncccc dddd", "<blockquote>aaaa_<br>bbbb</blockquote>cccc_dddd", $options); |
| | | $data[] = array("aaaa-bbbb/cccc", "aaaa-⁠bbbb/⁠cccc", $options); |
| | | |
| | | $options['flowed'] = true; |
| | | |
| | | $data[] = array(" aaaa", "aaaa", $options); |
| | | $data[] = array("aaaa aaaa", "aaaa_aaaa", $options); |
| | | $data[] = array("aaaa aaaa", "aaaa__aaaa", $options); |
| | | $data[] = array("aaaa aaaa", "aaaa___aaaa", $options); |
| | | $data[] = array("aaaa\taaaa", "aaaa____aaaa", $options); |
| | | $data[] = array("aaaa\naaaa", "aaaa<br>aaaa", $options); |
| | | $data[] = array("aaaa\n aaaa", "aaaa<br>aaaa", $options); |
| | | $data[] = array("aaaa\n aaaa", "aaaa<br>_aaaa", $options); |
| | | $data[] = array("aaaa\n aaaa", "aaaa<br>__aaaa", $options); |
| | | $data[] = array("\taaaa", "____aaaa", $options); |
| | | $data[] = array("\naaaa", "<br>aaaa", $options); |
| | | $data[] = array("\n aaaa", "<br>aaaa", $options); |
| | | $data[] = array("\n aaaa", "<br>_aaaa", $options); |
| | | $data[] = array("\n aaaa", "<br>__aaaa", $options); |
| | | $data[] = array("aaaa\n\nbbbb", "aaaa<br><br>bbbb", $options); |
| | | $data[] = array(">aaaa \n>aaaa", "<blockquote>aaaa aaaa</blockquote>", $options); |
| | | $data[] = array(">aaaa\n>aaaa", "<blockquote>aaaa<br>aaaa</blockquote>", $options); |
| | | $data[] = array(">aaaa \n>bbbb\ncccc dddd", "<blockquote>aaaa bbbb</blockquote>cccc_dddd", $options); |
| | | |
| | | $options['flowed'] = false; |
| | | $options['wrap'] = true; |
| | | |
| | | $data[] = array(">>aaaa bbbb\n>>\n>>>\n>cccc\n\ndddd eeee", |
| | | "<blockquote><blockquote>aaaa bbbb<br><br><blockquote><br></blockquote></blockquote>cccc</blockquote><br>dddd eeee", $options); |
| | | $data[] = array("\n>>aaaa\n\ndddd", |
| | | "<br><blockquote><blockquote>aaaa</blockquote></blockquote><br>dddd", $options); |
| | | $data[] = array("aaaa\n>bbbb\n>cccc\n\ndddd\n>>test", |
| | | "aaaa<blockquote>bbbb<br>cccc</blockquote><br>dddd<blockquote><blockquote>test</blockquote></blockquote>", $options); |
| | | |
| | | return $data; |
| | | } |
| | | |
| | | /** |
| | | * Test text to html conversion |
| | | * |
| | | * @dataProvider data_text2html |
| | | */ |
| | | function test_text2html($input, $output, $options) |
| | | { |
| | | $t2h = new rcube_text2html($input, false, $options); |
| | | |
| | | $html = $t2h->get_html(); |
| | | |
| | | $this->assertEquals($output, $html); |
| | | } |
| | | } |
| | |
| | | <file>Framework/SpellcheckPspell.php</file> |
| | | <file>Framework/Spellchecker.php</file> |
| | | <file>Framework/StringReplacer.php</file> |
| | | <file>Framework/Text2Html.php</file> |
| | | <file>Framework/User.php</file> |
| | | <file>Framework/Utils.php</file> |
| | | <file>Framework/VCard.php</file> |