Emoticons-related code refactoring
- Emoticons: All emoticons-related functionality is handled by the plugin now
- Emoticons: Added option to switch on/off emoticons in compose editor (#1485732)
- Emoticons: Added option to switch on/off emoticons in plain text messages
- Plugin API: Added disabled_plugins an disabled_buttons options in html_editor hook
- Plugin API: Added html2text hook
4 files added
12 files modified
| | |
| | | CHANGELOG Roundcube Webmail |
| | | =========================== |
| | | |
| | | - Emoticons: Added option to switch on/off emoticons in compose editor (#1485732) |
| | | - Emoticons: Added option to switch on/off emoticons in plain text messages |
| | | - Emoticons: All emoticons-related functionality is handled by the plugin now |
| | | - Installer: Add button to save generated config file in system temp directory (#1488149) |
| | | - Remove common subject prefixes Re:, Re[x]:, Re-x: on reply (#1490497) |
| | | - Added GSSAPI/Kerberos authentication plugin - krb_authentication |
| | |
| | | - Installer: Remove system() function use (#1490139) |
| | | - Password plugin: Added 'kpasswd' driver by Peter Allgeyer |
| | | - Add initdb.sh to create database from initial.sql script with prefix support (#1490188) |
| | | - Plugin API: Added disabled_plugins an disabled_buttons options in html_editor hook |
| | | - Plugin API: Added html2text hook |
| | | - Plugin API: Added message_part_body hook |
| | | - Plugin API: Added message_ready hook |
| | | - Plugin API: Add special onload() method to execute plugin actions before startup (session and GUI initialization) |
| | |
| | | { |
| | | "name": "roundcube/emoticons", |
| | | "type": "roundcube-plugin", |
| | | "description": "Sample plugin to replace emoticons in plain text message body with real icons.", |
| | | "description": "Plugin that adds emoticons support.", |
| | | "license": "GPLv3+", |
| | | "version": "1.4", |
| | | "version": "2.0", |
| | | "authors": [ |
| | | { |
| | | "name": "Thomas Bruederli", |
New file |
| | |
| | | <?php |
| | | |
| | | // Enable emoticons in plain text messages preview |
| | | $config['emoticons_display'] = false; |
| | | |
| | | // Enable emoticons in compose editor (HTML) |
| | | $config['emoticons_compose'] = true; |
| | |
| | | <?php |
| | | |
| | | /** |
| | | * Display Emoticons |
| | | * Emoticons |
| | | * |
| | | * Sample plugin to replace emoticons in plain text message body with real icons |
| | | * Plugin to replace emoticons in plain text message body with real icons. |
| | | * Also it enables emoticons in HTML compose editor. Both features are optional. |
| | | * |
| | | * @version @package_version@ |
| | | * @license GNU GPLv3+ |
| | |
| | | */ |
| | | class emoticons extends rcube_plugin |
| | | { |
| | | public $task = 'mail'; |
| | | public $task = 'mail|settings|utils'; |
| | | |
| | | |
| | | /** |
| | | * Plugin initilization. |
| | | */ |
| | | function init() |
| | | { |
| | | $this->add_hook('message_part_after', array($this, 'replace')); |
| | | $rcube = rcube::get_instance(); |
| | | |
| | | $this->add_hook('message_part_after', array($this, 'message_part_after')); |
| | | $this->add_hook('message_outgoing_body', array($this, 'message_outgoing_body')); |
| | | $this->add_hook('html2text', array($this, 'html2text')); |
| | | $this->add_hook('html_editor', array($this, 'html_editor')); |
| | | |
| | | if ($rcube->task == 'settings') { |
| | | $this->add_hook('preferences_list', array($this, 'preferences_list')); |
| | | $this->add_hook('preferences_save', array($this, 'preferences_save')); |
| | | } |
| | | } |
| | | |
| | | function replace($args) |
| | | /** |
| | | * 'message_part_after' hook handler to replace common plain text emoticons |
| | | * with emoticon images (<img>) |
| | | */ |
| | | function message_part_after($args) |
| | | { |
| | | // This is a lookbehind assertion which will exclude html entities |
| | | // E.g. situation when ";)" in "")" shouldn't be replaced by the icon |
| | | // It's so long because of assertion format restrictions |
| | | $entity = '(?<!&' |
| | | . '[a-zA-Z0-9]{2}' . '|' . '#[0-9]{2}' . '|' |
| | | . '[a-zA-Z0-9]{3}' . '|' . '#[0-9]{3}' . '|' |
| | | . '[a-zA-Z0-9]{4}' . '|' . '#[0-9]{4}' . '|' |
| | | . '[a-zA-Z0-9]{5}' . '|' |
| | | . '[a-zA-Z0-9]{6}' . '|' |
| | | . '[a-zA-Z0-9]{7}' |
| | | . ')'; |
| | | |
| | | // map of emoticon replacements |
| | | $map = array( |
| | | '/(?<!mailto):D/' => $this->img_tag('smiley-laughing.gif', ':D' ), |
| | | '/:-D/' => $this->img_tag('smiley-laughing.gif', ':-D' ), |
| | | '/:\(/' => $this->img_tag('smiley-frown.gif', ':(' ), |
| | | '/:-\(/' => $this->img_tag('smiley-frown.gif', ':-(' ), |
| | | '/'.$entity.';\)/' => $this->img_tag('smiley-wink.gif', ';)' ), |
| | | '/'.$entity.';-\)/' => $this->img_tag('smiley-wink.gif', ';-)' ), |
| | | '/8\)/' => $this->img_tag('smiley-cool.gif', '8)' ), |
| | | '/8-\)/' => $this->img_tag('smiley-cool.gif', '8-)' ), |
| | | '/(?<!mailto):O/i' => $this->img_tag('smiley-surprised.gif', ':O' ), |
| | | '/(?<!mailto):-O/i' => $this->img_tag('smiley-surprised.gif', ':-O' ), |
| | | '/(?<!mailto):P/i' => $this->img_tag('smiley-tongue-out.gif', ':P' ), |
| | | '/(?<!mailto):-P/i' => $this->img_tag('smiley-tongue-out.gif', ':-P' ), |
| | | '/(?<!mailto):@/i' => $this->img_tag('smiley-yell.gif', ':@' ), |
| | | '/(?<!mailto):-@/i' => $this->img_tag('smiley-yell.gif', ':-@' ), |
| | | '/O:\)/i' => $this->img_tag('smiley-innocent.gif', 'O:)' ), |
| | | '/O:-\)/i' => $this->img_tag('smiley-innocent.gif', 'O:-)' ), |
| | | '/(?<!O):\)/' => $this->img_tag('smiley-smile.gif', ':)' ), |
| | | '/(?<!O):-\)/' => $this->img_tag('smiley-smile.gif', ':-)' ), |
| | | '/(?<!mailto):\$/' => $this->img_tag('smiley-embarassed.gif', ':$' ), |
| | | '/(?<!mailto):-\$/' => $this->img_tag('smiley-embarassed.gif', ':-$' ), |
| | | '/(?<!mailto):\*/i' => $this->img_tag('smiley-kiss.gif', ':*' ), |
| | | '/(?<!mailto):-\*/i' => $this->img_tag('smiley-kiss.gif', ':-*' ), |
| | | '/(?<!mailto):S/i' => $this->img_tag('smiley-undecided.gif', ':S' ), |
| | | '/(?<!mailto):-S/i' => $this->img_tag('smiley-undecided.gif', ':-S' ), |
| | | ); |
| | | |
| | | if ($args['type'] == 'plain') { |
| | | $args['body'] = preg_replace( |
| | | array_keys($map), array_values($map), $args['body']); |
| | | $this->load_config(); |
| | | |
| | | $rcube = rcube::get_instance(); |
| | | if (!$rcube->config->get('emoticons_display', false)) { |
| | | return $args; |
| | | } |
| | | |
| | | require_once __DIR__ . '/emoticons_engine.php'; |
| | | |
| | | $args['body'] = emoticons_engine::text2icons($args['body']); |
| | | } |
| | | |
| | | return $args; |
| | | } |
| | | |
| | | private function img_tag($ico, $title) |
| | | /** |
| | | * 'message_outgoing_body' hook handler to replace image emoticons from TinyMCE |
| | | * editor with image attachments. |
| | | */ |
| | | function message_outgoing_body($args) |
| | | { |
| | | $path = './program/js/tinymce/plugins/emoticons/img/'; |
| | | return html::img(array('src' => $path.$ico, 'title' => $title)); |
| | | if ($args['type'] == 'html') { |
| | | $this->load_config(); |
| | | |
| | | $rcube = rcube::get_instance(); |
| | | if (!$rcube->config->get('emoticons_compose', true)) { |
| | | return $args; |
| | | } |
| | | |
| | | require_once __DIR__ . '/emoticons_engine.php'; |
| | | |
| | | // look for "emoticon" images from TinyMCE and change their src paths to |
| | | // be file paths on the server instead of URL paths. |
| | | $images = emoticons_engine::replace($args['body']); |
| | | |
| | | // add these images as attachments to the MIME message |
| | | foreach ($images as $img_name => $img_file) { |
| | | $args['message']->addHTMLImage($img_file, 'image/gif', '', true, $img_name); |
| | | } |
| | | } |
| | | |
| | | return $args; |
| | | } |
| | | |
| | | /** |
| | | * 'html2text' hook handler to replace image emoticons from TinyMCE |
| | | * editor with plain text emoticons. |
| | | * |
| | | * This is executed on html2text action, i.e. when switching from HTML to text |
| | | * in compose window (or similiar place). Also when generating alternative |
| | | * text/plain part. |
| | | */ |
| | | function html2text($args) |
| | | { |
| | | $rcube = rcube::get_instance(); |
| | | |
| | | if ($rcube->action == 'html2text' || $rcube->action == 'send') { |
| | | $this->load_config(); |
| | | |
| | | if (!$rcube->config->get('emoticons_compose', true)) { |
| | | return $args; |
| | | } |
| | | |
| | | require_once __DIR__ . '/emoticons_engine.php'; |
| | | |
| | | $args['body'] = emoticons_engine::icons2text($args['body']); |
| | | } |
| | | |
| | | return $args; |
| | | } |
| | | |
| | | /** |
| | | * 'html_editor' hook handler, where we enable emoticons in TinyMCE |
| | | */ |
| | | function html_editor($args) |
| | | { |
| | | $rcube = rcube::get_instance(); |
| | | |
| | | $this->load_config(); |
| | | |
| | | if (!$rcube->config->get('emoticons_compose', true)) { |
| | | $args['disabled_plugins'][] = 'emoticons'; |
| | | $args['disabled_buttons'][] = 'emoticons'; |
| | | } |
| | | |
| | | return $args; |
| | | } |
| | | |
| | | /** |
| | | * 'preferences_list' hook handler |
| | | */ |
| | | function preferences_list($args) |
| | | { |
| | | $rcube = rcube::get_instance(); |
| | | $dont_override = $rcube->config->get('dont_override', array()); |
| | | |
| | | if ($args['section'] == 'mailview' && !in_array('emoticons_display', $dont_override)) { |
| | | $this->load_config(); |
| | | $this->add_texts('localization'); |
| | | |
| | | $field_id = 'emoticons_display'; |
| | | $checkbox = new html_checkbox(array('name' => '_' . $field_id, 'id' => $field_id, 'value' => 1)); |
| | | |
| | | $args['blocks']['main']['options']['emoticons_display'] = array( |
| | | 'title' => $this->gettext('emoticonsdisplay'), |
| | | 'content' => $checkbox->show(intval($rcube->config->get('emoticons_display', false))) |
| | | ); |
| | | } |
| | | else if ($args['section'] == 'compose' && !in_array('emoticons_compose', $dont_override)) { |
| | | $this->load_config(); |
| | | $this->add_texts('localization'); |
| | | |
| | | $field_id = 'emoticons_compose'; |
| | | $checkbox = new html_checkbox(array('name' => '_' . $field_id, 'id' => $field_id, 'value' => 1)); |
| | | |
| | | $args['blocks']['main']['options']['emoticons_compose'] = array( |
| | | 'title' => $this->gettext('emoticonscompose'), |
| | | 'content' => $checkbox->show(intval($rcube->config->get('emoticons_compose', true))) |
| | | ); |
| | | } |
| | | |
| | | return $args; |
| | | } |
| | | |
| | | /** |
| | | * 'preferences_save' hook handler |
| | | */ |
| | | function preferences_save($args) |
| | | { |
| | | $rcube = rcube::get_instance(); |
| | | $dont_override = $rcube->config->get('dont_override', array()); |
| | | |
| | | if ($args['section'] == 'mailview' && !in_array('emoticons_display', $dont_override)) { |
| | | $args['prefs']['emoticons_display'] = rcube_utils::get_input_value('_emoticons_display', rcube_utils::INPUT_POST) ? true : false; |
| | | } |
| | | else if ($args['section'] == 'compose' && !in_array('emoticons_compose', $dont_override)) { |
| | | $args['prefs']['emoticons_compose'] = rcube_utils::get_input_value('_emoticons_compose', rcube_utils::INPUT_POST) ? true : false; |
| | | } |
| | | |
| | | return $args; |
| | | } |
| | | } |
New file |
| | |
| | | <?php |
| | | |
| | | /** |
| | | * @license GNU GPLv3+ |
| | | * @author Thomas Bruederli |
| | | * @author Aleksander Machniak |
| | | */ |
| | | class emoticons_engine |
| | | { |
| | | const IMG_PATH = 'program/js/tinymce/plugins/emoticons/img/'; |
| | | |
| | | /** |
| | | * Replaces TinyMCE's emoticon images with plain-text representation |
| | | * |
| | | * @param string $html HTML content |
| | | * |
| | | * @return string HTML content |
| | | */ |
| | | public static function icons2text($html) |
| | | { |
| | | $emoticons = array( |
| | | '8-)' => 'smiley-cool', |
| | | ':-#' => 'smiley-foot-in-mouth', |
| | | ':-*' => 'smiley-kiss', |
| | | ':-X' => 'smiley-sealed', |
| | | ':-P' => 'smiley-tongue-out', |
| | | ':-@' => 'smiley-yell', |
| | | ":'(" => 'smiley-cry', |
| | | ':-(' => 'smiley-frown', |
| | | ':-D' => 'smiley-laughing', |
| | | ':-)' => 'smiley-smile', |
| | | ':-S' => 'smiley-undecided', |
| | | ':-$' => 'smiley-embarassed', |
| | | 'O:-)' => 'smiley-innocent', |
| | | ':-|' => 'smiley-money-mouth', |
| | | ':-O' => 'smiley-surprised', |
| | | ';-)' => 'smiley-wink', |
| | | ); |
| | | |
| | | foreach ($emoticons as $idx => $file) { |
| | | // <img title="Cry" src="http://.../program/js/tinymce/plugins/emoticons/img/smiley-cry.gif" border="0" alt="Cry" /> |
| | | $file = preg_quote(self::IMG_PATH . $file . '.gif', '/'); |
| | | $search[] = '/<img (title="[a-z ]+" )?src="[^"]+' . $file . '"[^>]+\/>/i'; |
| | | $replace[] = $idx; |
| | | } |
| | | |
| | | return preg_replace($search, $replace, $html); |
| | | } |
| | | |
| | | /** |
| | | * Replace common plain text emoticons with empticon <img> tags |
| | | * |
| | | * @param string $text Text |
| | | * |
| | | * @return string Converted text |
| | | */ |
| | | public static function text2icons($text) |
| | | { |
| | | // This is a lookbehind assertion which will exclude html entities |
| | | // E.g. situation when ";)" in "")" shouldn't be replaced by the icon |
| | | // It's so long because of assertion format restrictions |
| | | $entity = '(?<!&' |
| | | . '[a-zA-Z0-9]{2}' . '|' . '#[0-9]{2}' . '|' |
| | | . '[a-zA-Z0-9]{3}' . '|' . '#[0-9]{3}' . '|' |
| | | . '[a-zA-Z0-9]{4}' . '|' . '#[0-9]{4}' . '|' |
| | | . '[a-zA-Z0-9]{5}' . '|' |
| | | . '[a-zA-Z0-9]{6}' . '|' |
| | | . '[a-zA-Z0-9]{7}' |
| | | . ')'; |
| | | |
| | | // map of emoticon replacements |
| | | $map = array( |
| | | '/(?<!mailto):D/' => self::img_tag('smiley-laughing.gif', ':D' ), |
| | | '/:-D/' => self::img_tag('smiley-laughing.gif', ':-D' ), |
| | | '/:\(/' => self::img_tag('smiley-frown.gif', ':(' ), |
| | | '/:-\(/' => self::img_tag('smiley-frown.gif', ':-(' ), |
| | | '/'.$entity.';\)/' => self::img_tag('smiley-wink.gif', ';)' ), |
| | | '/'.$entity.';-\)/' => self::img_tag('smiley-wink.gif', ';-)' ), |
| | | '/8\)/' => self::img_tag('smiley-cool.gif', '8)' ), |
| | | '/8-\)/' => self::img_tag('smiley-cool.gif', '8-)' ), |
| | | '/(?<!mailto):O/i' => self::img_tag('smiley-surprised.gif', ':O' ), |
| | | '/(?<!mailto):-O/i' => self::img_tag('smiley-surprised.gif', ':-O' ), |
| | | '/(?<!mailto):P/i' => self::img_tag('smiley-tongue-out.gif', ':P' ), |
| | | '/(?<!mailto):-P/i' => self::img_tag('smiley-tongue-out.gif', ':-P' ), |
| | | '/(?<!mailto):@/i' => self::img_tag('smiley-yell.gif', ':@' ), |
| | | '/(?<!mailto):-@/i' => self::img_tag('smiley-yell.gif', ':-@' ), |
| | | '/O:\)/i' => self::img_tag('smiley-innocent.gif', 'O:)' ), |
| | | '/O:-\)/i' => self::img_tag('smiley-innocent.gif', 'O:-)' ), |
| | | '/(?<!O):\)/' => self::img_tag('smiley-smile.gif', ':)' ), |
| | | '/(?<!O):-\)/' => self::img_tag('smiley-smile.gif', ':-)' ), |
| | | '/(?<!mailto):\$/' => self::img_tag('smiley-embarassed.gif', ':$' ), |
| | | '/(?<!mailto):-\$/' => self::img_tag('smiley-embarassed.gif', ':-$' ), |
| | | '/(?<!mailto):\*/i' => self::img_tag('smiley-kiss.gif', ':*' ), |
| | | '/(?<!mailto):-\*/i' => self::img_tag('smiley-kiss.gif', ':-*' ), |
| | | '/(?<!mailto):S/i' => self::img_tag('smiley-undecided.gif', ':S' ), |
| | | '/(?<!mailto):-S/i' => self::img_tag('smiley-undecided.gif', ':-S' ), |
| | | ); |
| | | |
| | | return preg_replace(array_keys($map), array_values($map), $text); |
| | | } |
| | | |
| | | protected static function img_tag($ico, $title) |
| | | { |
| | | return html::img(array('src' => './' . self::IMG_PATH . $ico, 'title' => $title)); |
| | | } |
| | | |
| | | /** |
| | | * Replace emoticon icons <img> 'src' attribute, so it can |
| | | * be replaced with real file by Mail_Mime. |
| | | * |
| | | * @param string &$html HTML content |
| | | * |
| | | * @return array List of image files |
| | | */ |
| | | public static function replace(&$html) |
| | | { |
| | | // Replace this: |
| | | // <img src="http[s]://.../tinymce/plugins/emoticons/img/smiley-cool.gif" ... /> |
| | | // with this: |
| | | // <img src="/path/on/server/.../tinymce/plugins/emoticons/img/smiley-cool.gif" ... /> |
| | | |
| | | $rcube = rcube::get_instance(); |
| | | $assets_dir = $rcube->config->get('assets_dir'); |
| | | $path = unslashify($assets_dir ?: INSTALL_PATH) . '/' . self::IMG_PATH; |
| | | $offset = 0; |
| | | $images = array(); |
| | | |
| | | // remove any null-byte characters before parsing |
| | | $html = preg_replace('/\x00/', '', $html); |
| | | |
| | | if (preg_match_all('# src=[\'"]([^\'"]+)#', $html, $matches, PREG_OFFSET_CAPTURE)) { |
| | | foreach ($matches[1] as $m) { |
| | | // find emoticon image tags |
| | | if (preg_match('#'. self::IMG_PATH . '(.*)$#', $m[0], $imatches)) { |
| | | $image_name = $imatches[1]; |
| | | |
| | | // sanitize image name so resulting attachment doesn't leave images dir |
| | | $image_name = preg_replace('/[^a-zA-Z0-9_\.\-]/i', '', $image_name); |
| | | $image_file = $path . $image_name; |
| | | |
| | | // Add the same image only once |
| | | $images[$image_name] = $image_file; |
| | | |
| | | $html = substr_replace($html, $image_file, $m[1] + $offset, strlen($m[0])); |
| | | $offset += strlen($image_file) - strlen($m[0]); |
| | | } |
| | | } |
| | | } |
| | | |
| | | return $images; |
| | | } |
| | | } |
New file |
| | |
| | | <?php |
| | | |
| | | /* |
| | | +-----------------------------------------------------------------------+ |
| | | | plugins/emoticons/localization/<lang>.inc | |
| | | | | |
| | | | Localization file of the Roundcube Webmail Emoticons plugin | |
| | | | Copyright (C) 2012-2015, 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. | |
| | | | | |
| | | +-----------------------------------------------------------------------+ |
| | | |
| | | For translation see https://www.transifex.com/projects/p/roundcube-webmail/resource/plugin-emoticons/ |
| | | */ |
| | | |
| | | $labels = array(); |
| | | $labels['emoticonsdisplay'] = 'Display emoticons in plain text messages'; |
| | | $labels['emoticonscompose'] = 'Enable emoticons'; |
| | | |
| | | ?> |
| | |
| | | $this->assertInstanceOf('emoticons', $plugin); |
| | | $this->assertInstanceOf('rcube_plugin', $plugin); |
| | | } |
| | | |
| | | /** |
| | | * replace() method tests |
| | | */ |
| | | function test_replace() |
| | | { |
| | | $rcube = rcube::get_instance(); |
| | | $plugin = new emoticons($rcube->api); |
| | | |
| | | $map = array( |
| | | ':D' => array('smiley-laughing.gif', ':D' ), |
| | | ':-D' => array('smiley-laughing.gif', ':-D' ), |
| | | ':(' => array('smiley-frown.gif', ':(' ), |
| | | ':-(' => array('smiley-frown.gif', ':-(' ), |
| | | '8)' => array('smiley-cool.gif', '8)' ), |
| | | '8-)' => array('smiley-cool.gif', '8-)' ), |
| | | ':O' => array('smiley-surprised.gif', ':O' ), |
| | | ':-O' => array('smiley-surprised.gif', ':-O' ), |
| | | ':P' => array('smiley-tongue-out.gif', ':P' ), |
| | | ':-P' => array('smiley-tongue-out.gif', ':-P' ), |
| | | ':@' => array('smiley-yell.gif', ':@' ), |
| | | ':-@' => array('smiley-yell.gif', ':-@' ), |
| | | 'O:)' => array('smiley-innocent.gif', 'O:)' ), |
| | | 'O:-)' => array('smiley-innocent.gif', 'O:-)' ), |
| | | ':)' => array('smiley-smile.gif', ':)' ), |
| | | ':-)' => array('smiley-smile.gif', ':-)' ), |
| | | ':$' => array('smiley-embarassed.gif', ':$' ), |
| | | ':-$' => array('smiley-embarassed.gif', ':-$' ), |
| | | ':*' => array('smiley-kiss.gif', ':*' ), |
| | | ':-*' => array('smiley-kiss.gif', ':-*' ), |
| | | ':S' => array('smiley-undecided.gif', ':S' ), |
| | | ':-S' => array('smiley-undecided.gif', ':-S' ), |
| | | ); |
| | | |
| | | foreach ($map as $body => $expected) { |
| | | $args = array('type' => 'plain', 'body' => $body); |
| | | $args = $plugin->replace($args); |
| | | $this->assertRegExp('/' . preg_quote($expected[0], '/') . '/', $args['body']); |
| | | $this->assertRegExp('/title="' . preg_quote($expected[1], '/') . '"/', $args['body']); |
| | | } |
| | | } |
| | | } |
New file |
| | |
| | | <?php |
| | | |
| | | class EmoticonsEngine extends PHPUnit_Framework_TestCase |
| | | { |
| | | |
| | | function setUp() |
| | | { |
| | | include_once __DIR__ . '/../emoticons_engine.php'; |
| | | } |
| | | |
| | | /** |
| | | * text2icons() method tests |
| | | */ |
| | | function test_text2icons() |
| | | { |
| | | $map = array( |
| | | ':D' => array('smiley-laughing.gif', ':D' ), |
| | | ':-D' => array('smiley-laughing.gif', ':-D' ), |
| | | ':(' => array('smiley-frown.gif', ':(' ), |
| | | ':-(' => array('smiley-frown.gif', ':-(' ), |
| | | '8)' => array('smiley-cool.gif', '8)' ), |
| | | '8-)' => array('smiley-cool.gif', '8-)' ), |
| | | ':O' => array('smiley-surprised.gif', ':O' ), |
| | | ':-O' => array('smiley-surprised.gif', ':-O' ), |
| | | ':P' => array('smiley-tongue-out.gif', ':P' ), |
| | | ':-P' => array('smiley-tongue-out.gif', ':-P' ), |
| | | ':@' => array('smiley-yell.gif', ':@' ), |
| | | ':-@' => array('smiley-yell.gif', ':-@' ), |
| | | 'O:)' => array('smiley-innocent.gif', 'O:)' ), |
| | | 'O:-)' => array('smiley-innocent.gif', 'O:-)' ), |
| | | ':)' => array('smiley-smile.gif', ':)' ), |
| | | ':-)' => array('smiley-smile.gif', ':-)' ), |
| | | ':$' => array('smiley-embarassed.gif', ':$' ), |
| | | ':-$' => array('smiley-embarassed.gif', ':-$' ), |
| | | ':*' => array('smiley-kiss.gif', ':*' ), |
| | | ':-*' => array('smiley-kiss.gif', ':-*' ), |
| | | ':S' => array('smiley-undecided.gif', ':S' ), |
| | | ':-S' => array('smiley-undecided.gif', ':-S' ), |
| | | ); |
| | | |
| | | foreach ($map as $body => $expected) { |
| | | $result = emoticons_engine::text2icons($body); |
| | | |
| | | $this->assertRegExp('/' . preg_quote($expected[0], '/') . '/', $result); |
| | | $this->assertRegExp('/title="' . preg_quote($expected[1], '/') . '"/', $result); |
| | | } |
| | | } |
| | | } |
| | |
| | | rcmail::get_instance()->html_editor($mode); |
| | | } |
| | | |
| | | function rcmail_replace_emoticons($html) |
| | | { |
| | | return rcmail::get_instance()->replace_emoticons($html); |
| | | } |
| | | |
| | | function rcmail_deliver_message(&$message, $from, $mailto, &$smtp_error, &$body_file=null, $smtp_opts=null) |
| | | { |
| | | return rcmail::get_instance()->deliver_message($message, $from, $mailto, $smtp_error, $body_file, $smtp_opts); |
| | |
| | | */ |
| | | public function html_editor($mode = '') |
| | | { |
| | | $hook = $this->plugins->exec_hook('html_editor', array('mode' => $mode)); |
| | | $spellcheck = intval($this->config->get('enable_spellcheck')); |
| | | $spelldict = intval($this->config->get('spellcheck_dictionary')); |
| | | $disabled_plugins = array(); |
| | | $disabled_buttons = array(); |
| | | |
| | | if (!$spellcheck) { |
| | | $disabled_plugins[] = 'spellchecker'; |
| | | } |
| | | |
| | | $hook = $this->plugins->exec_hook('html_editor', array( |
| | | 'mode' => $mode, |
| | | 'disabled_plugins' => $disabled_plugins, |
| | | 'disabled_buttons' => $disabled_buttons, |
| | | )); |
| | | |
| | | if ($hook['abort']) { |
| | | return; |
| | |
| | | 'mode' => $mode, |
| | | 'lang' => $lang, |
| | | 'skin_path' => $this->output->get_skin_path(), |
| | | 'spellcheck' => intval($this->config->get('enable_spellcheck')), |
| | | 'spelldict' => intval($this->config->get('spellcheck_dictionary')) |
| | | 'spellcheck' => $spellcheck, // deprecated |
| | | 'spelldict' => $spelldict, |
| | | 'disabled_plugins' => $hook['disabled_plugins'], |
| | | 'disabled_buttons' => $hook['disabled_buttons'], |
| | | ); |
| | | |
| | | $this->output->add_label('selectimage', 'addimage', 'selectmedia', 'addmedia'); |
| | |
| | | $this->output->include_css('program/js/tinymce/roundcube/browser.css'); |
| | | $this->output->include_script('tinymce/tinymce.min.js'); |
| | | $this->output->include_script('editor.js'); |
| | | } |
| | | |
| | | /** |
| | | * Replaces TinyMCE's emoticon images with plain-text representation |
| | | * |
| | | * @param string $html HTML content |
| | | * |
| | | * @return string HTML content |
| | | */ |
| | | public static function replace_emoticons($html) |
| | | { |
| | | $emoticons = array( |
| | | '8-)' => 'smiley-cool', |
| | | ':-#' => 'smiley-foot-in-mouth', |
| | | ':-*' => 'smiley-kiss', |
| | | ':-X' => 'smiley-sealed', |
| | | ':-P' => 'smiley-tongue-out', |
| | | ':-@' => 'smiley-yell', |
| | | ":'(" => 'smiley-cry', |
| | | ':-(' => 'smiley-frown', |
| | | ':-D' => 'smiley-laughing', |
| | | ':-)' => 'smiley-smile', |
| | | ':-S' => 'smiley-undecided', |
| | | ':-$' => 'smiley-embarassed', |
| | | 'O:-)' => 'smiley-innocent', |
| | | ':-|' => 'smiley-money-mouth', |
| | | ':-O' => 'smiley-surprised', |
| | | ';-)' => 'smiley-wink', |
| | | ); |
| | | |
| | | foreach ($emoticons as $idx => $file) { |
| | | // <img title="Cry" src="http://.../program/js/tinymce/plugins/emoticons/img/smiley-cry.gif" border="0" alt="Cry" /> |
| | | $search[] = '/<img title="[a-z ]+" src="https?:\/\/[a-z0-9_.\/-]+\/tinymce\/plugins\/emoticons\/img\/'.$file.'.gif"[^>]+\/>/i'; |
| | | $replace[] = $idx; |
| | | } |
| | | |
| | | return preg_replace($search, $replace, $html); |
| | | } |
| | | |
| | | /** |
| | |
| | | return file_get_contents($name, false); |
| | | } |
| | | |
| | | /** |
| | | * Converts HTML content into plain text |
| | | * |
| | | * @param string $html HTML content |
| | | * @param array $options Conversion parameters (width, links, charset) |
| | | * |
| | | * @return string Plain text |
| | | */ |
| | | public function html2text($html, $options) |
| | | { |
| | | $default_options = array( |
| | | 'links' => true, |
| | | 'width' => 75, |
| | | 'body' => $html, |
| | | 'charset' => RCUBE_CHARSET, |
| | | ); |
| | | |
| | | $options = array_merge($default_options, $options); |
| | | |
| | | // Plugins may want to modify HTML in another/additional way |
| | | $options = $this->plugins->exec_hook('html2text', $options); |
| | | |
| | | // Convert to text |
| | | if (!$options['abort']) { |
| | | $converter = new rcube_html2text($options['body'], |
| | | false, $options['links'], $options['width'], $options['charset']); |
| | | |
| | | $options['body'] = rtrim($converter->get_text()); |
| | | } |
| | | |
| | | return $options['body']; |
| | | } |
| | | |
| | | |
| | | /************************************************************************ |
| | | ********* Deprecated methods (to be removed) ********* |
| | |
| | | else { |
| | | $.extend(conf, { |
| | | plugins: 'autolink charmap code colorpicker directionality emoticons link image media nonbreaking' |
| | | + ' paste table tabfocus textcolor searchreplace' + (config.spellcheck ? ' spellchecker' : ''), |
| | | + ' paste table tabfocus textcolor searchreplace spellchecker', |
| | | toolbar: 'bold italic underline | alignleft aligncenter alignright alignjustify' |
| | | + ' | bullist numlist outdent indent ltr rtl blockquote | forecolor backcolor | fontselect fontsizeselect' |
| | | + ' | link unlink table | emoticons charmap image media | code searchreplace undo redo', |
| | |
| | | }); |
| | | } |
| | | |
| | | // disable TinyMCE plugins/buttons from Roundcube plugin |
| | | $.each(config.disabled_plugins || [], function() { |
| | | conf.plugins = conf.plugins.replace(this, ''); |
| | | }); |
| | | $.each(config.disabled_plugins || [], function() { |
| | | conf.toolbar = conf.toolbar.replace(this, ''); |
| | | }); |
| | | conf.toolbar = conf.toolbar.replace(/\|\s+\|/g, '|'); |
| | | |
| | | // support external configuration settings e.g. from skin |
| | | if (window.rcmail_editor_settings) |
| | | $.extend(conf, window.rcmail_editor_settings); |
| | |
| | | $text = $html = $sql_arr['signature']; |
| | | |
| | | if ($sql_arr['html_signature']) { |
| | | $h2t = new rcube_html2text($html, false, true); |
| | | $text = trim($h2t->get_text()); |
| | | $text = $RCMAIL->html2text($html); |
| | | } |
| | | else { |
| | | $t2h = new rcube_text2html($text, false); |
| | |
| | | // use html part if it has been used for message (pre)viewing |
| | | // decrease line length for quoting |
| | | $len = $COMPOSE['mode'] == RCUBE_COMPOSE_REPLY ? $LINE_LENGTH-2 : $LINE_LENGTH; |
| | | $txt = new rcube_html2text($body, false, true, $len); |
| | | $body = $txt->get_text(); |
| | | $body = $RCMAIL->html2text($body, array('width' => $len)); |
| | | } |
| | | else { |
| | | if ($part->ctype_secondary == 'plain' && $part->ctype_parameters['format'] == 'flowed') { |
| | |
| | | $data['body'] = rcube_enriched::to_html($data['body']); |
| | | } |
| | | |
| | | $txt = new rcube_html2text($data['body'], false, true); |
| | | $body = $txt->get_text(); |
| | | $body = $RCMAIL->html2text($data['body']); |
| | | $part->ctype_secondary = 'plain'; |
| | | } |
| | | // text/html |
| | |
| | | |
| | | $MAIL_MIME->setHTMLBody($plugin['body']); |
| | | |
| | | // replace emoticons |
| | | $plugin['body'] = $RCMAIL->replace_emoticons($plugin['body']); |
| | | |
| | | // add a plain text version of the e-mail as an alternative part. |
| | | $h2t = new rcube_html2text($plugin['body'], false, true, 0, $message_charset); |
| | | $plainTextPart = rcube_mime::wordwrap($h2t->get_text(), $LINE_LENGTH, "\r\n", false, $message_charset); |
| | | $plainTextPart = $RCMAIL->html2text($plugin['body'], array('width' => 0, 'charset' => $message_charset)); |
| | | $plainTextPart = rcube_mime::wordwrap($plainTextPart, $LINE_LENGTH, "\r\n", false, $message_charset); |
| | | $plainTextPart = wordwrap($plainTextPart, 998, "\r\n", true); |
| | | |
| | | // make sure all line endings are CRLF (#1486712) |
| | |
| | | $plugin = $RCMAIL->plugins->exec_hook('message_outgoing_body', |
| | | array('body' => $plainTextPart, 'type' => 'alternative', 'message' => $MAIL_MIME)); |
| | | |
| | | // add a plain text version of the e-mail as an alternative part. |
| | | $MAIL_MIME->setTXTBody($plugin['body']); |
| | | |
| | | // look for "emoticon" images from TinyMCE and change their src paths to |
| | | // be file paths on the server instead of URL paths. |
| | | rcmail_fix_emoticon_paths($MAIL_MIME); |
| | | |
| | | // Extract image Data URIs into message attachments (#1488502) |
| | | rcmail_extract_inline_images($MAIL_MIME, $from); |
| | |
| | | } |
| | | |
| | | return false; |
| | | } |
| | | |
| | | /** |
| | | * go from this: |
| | | * <img src="http[s]://.../tinymce/plugins/emoticons/img/smiley-cool.gif" border="0" alt="Cool" title="Cool" /> |
| | | * |
| | | * to this: |
| | | * |
| | | * <img src="/path/on/server/.../tinymce/plugins/emoticons/img/smiley-cool.gif" border="0" alt="Cool" title="Cool" /> |
| | | */ |
| | | function rcmail_fix_emoticon_paths($mime_message) |
| | | { |
| | | global $RCMAIL; |
| | | |
| | | $body = $mime_message->getHTMLBody(); |
| | | |
| | | // remove any null-byte characters before parsing |
| | | $body = preg_replace('/\x00/', '', $body); |
| | | |
| | | $searchstr = 'program/js/tinymce/plugins/emoticons/img/'; |
| | | $assets_dir = $RCMAIL->config->get('assets_dir'); |
| | | $path = ($assets_dir ?: INSTALL_PATH) . '/' . $searchstr; |
| | | $offset = 0; |
| | | |
| | | // keep track of added images, so they're only added once |
| | | $included_images = array(); |
| | | |
| | | if (preg_match_all('# src=[\'"]([^\'"]+)#', $body, $matches, PREG_OFFSET_CAPTURE)) { |
| | | foreach ($matches[1] as $m) { |
| | | // find emoticon image tags |
| | | if (preg_match('#'.$searchstr.'(.*)$#', $m[0], $imatches)) { |
| | | $image_name = $imatches[1]; |
| | | |
| | | // sanitize image name so resulting attachment doesn't leave images dir |
| | | $image_name = preg_replace('/[^a-zA-Z0-9_\.\-]/i', '', $image_name); |
| | | $img_file = $path . $image_name; |
| | | |
| | | if (!in_array($image_name, $included_images)) { |
| | | // add the image to the MIME message |
| | | $res = $mime_message->addHTMLImage($img_file, 'image/gif', '', true, $image_name); |
| | | if (is_a($res, 'PEAR_Error')) { |
| | | $RCMAIL->output->show_message("emoticonerror", 'error'); |
| | | continue; |
| | | } |
| | | |
| | | array_push($included_images, $image_name); |
| | | } |
| | | |
| | | $body = substr_replace($body, $img_file, $m[1] + $offset, strlen($m[0])); |
| | | $offset += strlen($img_file) - strlen($m[0]); |
| | | } |
| | | } |
| | | } |
| | | |
| | | $mime_message->setHTMLBody($body); |
| | | } |
| | | |
| | | /** |
| | |
| | | $html = stripslashes($html); |
| | | } |
| | | |
| | | // Replace emoticon images with its text representation |
| | | $html = $RCMAIL->replace_emoticons($html); |
| | | $params['links'] = (bool) rcube_utils::get_input_value('_do_links', rcube_utils::INPUT_GET); |
| | | $params['width'] = (int) rcube_utils::get_input_value('_width', rcube_utils::INPUT_GET); |
| | | |
| | | $do_links = (bool) rcube_utils::get_input_value('_do_links', rcube_utils::INPUT_GET); |
| | | $width = (int) rcube_utils::get_input_value('_width', rcube_utils::INPUT_GET); |
| | | $text = $RCMAIL->html2text($html, $params); |
| | | |
| | | // Convert to text |
| | | $converter = new rcube_html2text($html, false, $do_links, $width); |
| | | |
| | | header('Content-Type: text/plain; charset=UTF-8'); |
| | | print rtrim($converter->get_text()); |
| | | header('Content-Type: text/plain; charset=' . RCUBE_CHARSET); |
| | | print $text; |
| | | exit; |
| | |
| | | <file>./../plugins/database_attachments/tests/DatabaseAttachments.php</file> |
| | | <file>./../plugins/debug_logger/tests/DebugLogger.php</file> |
| | | <file>./../plugins/emoticons/tests/Emoticons.php</file> |
| | | <file>./../plugins/emoticons/tests/EmoticonsEngine.php</file> |
| | | <file>./../plugins/enigma/tests/Enigma.php</file> |
| | | <file>./../plugins/example_addressbook/tests/ExampleAddressbook.php</file> |
| | | <file>./../plugins/filesystem_attachments/tests/FilesystemAttachments.php</file> |