diff options
-rw-r--r-- | CHANGELOG | 1 | ||||
-rw-r--r-- | config/defaults.inc.php | 19 | ||||
-rw-r--r-- | program/lib/Roundcube/rcube_spellcheck_atd.php | 192 |
3 files changed, 205 insertions, 7 deletions
@@ -1,6 +1,7 @@ CHANGELOG Roundcube Webmail =========================== +- Add spellchecker backend for the After the Deadline service - Replace markdown-style [1] link indexes in plain text email bodies - Fixed issues where HTML comments inside style tag would hang Internet Explorer - Improved mailto: link arguments handling (#1489363) diff --git a/config/defaults.inc.php b/config/defaults.inc.php index 9afa4ac81..65c9eaaba 100644 --- a/config/defaults.inc.php +++ b/config/defaults.inc.php @@ -566,15 +566,20 @@ $config['enable_spellcheck'] = true; // Setting it to 'shared' will make the dictionary shared by all users. $config['spellcheck_dictionary'] = false; -// Set the spell checking engine. 'googie' is the default. -// 'pspell' and 'enchant' are also available, but they require -// PHP Pspell or Enchant extensions. When using Nox Spell Server, also set 'googie' here. +// Set the spell checking engine. Possible values: +// - 'googie' - the default +// - 'pspell' - requires the PHP Pspell module and aspell installed +// - 'enchant' - requires the PHP Enchant module +// - 'atd' - install your own After the Deadline server or check with the people at http://www.afterthedeadline.com before using their API +// Since Google shut down their public spell checking service, you need to +// connect to a Nox Spell Server when using 'googie' here. Therefore specify the 'spellcheck_uri' $config['spellcheck_engine'] = 'googie'; -// For a locally installed Nox Spell Server, please specify the URI to call it. -// Get Nox Spell Server from http://orangoo.com/labs/?page_id=72 -// Leave empty to use the Google spell checking service, what means -// that the message content will be sent to Google in order to check spelling +// For locally installed Nox Spell Server or After the Deadline services, +// please specify the URI to call it. +// Get Nox Spell Server from http://orangoo.com/labs/?page_id=72 or +// the After the Deadline package from http://www.afterthedeadline.com. +// Leave empty to use the public API of service.afterthedeadline.com $config['spellcheck_uri'] = ''; // These languages can be selected for spell checking. diff --git a/program/lib/Roundcube/rcube_spellcheck_atd.php b/program/lib/Roundcube/rcube_spellcheck_atd.php new file mode 100644 index 000000000..68e8b7cb8 --- /dev/null +++ b/program/lib/Roundcube/rcube_spellcheck_atd.php @@ -0,0 +1,192 @@ +<?php + +/* + +-----------------------------------------------------------------------+ + | This file is part of the Roundcube Webmail client | + | | + | Copyright (C) 2013, 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: | + | Spellchecking backend implementation for afterthedeadline services | + +-----------------------------------------------------------------------+ + | Author: Thomas Bruederli <roundcube@gmail.com> | + +-----------------------------------------------------------------------+ +*/ + +/** + * Spellchecking backend implementation to work with an After the Deadline service + * See http://www.afterthedeadline.com/ for more information + * + * @package Framework + * @subpackage Utils + */ +class rcube_spellcheck_atd extends rcube_spellcheck_engine +{ + const SERVICE_HOST = 'service.afterthedeadline.com'; + const SERVICE_PORT = 80; + + private $matches = array(); + private $content; + private $langhosts = array( + 'fr' => 'fr.', + 'de' => 'de.', + 'pt' => 'pt.', + 'es' => 'es.', + ); + + /** + * Set content and check spelling + * + * @see rcube_spellcheck_engine::check() + */ + function check($text) + { + $this->content = $text; + + // spell check uri is configured + $rcube = rcube::get_instance(); + $url = $rcube->config->get('spellcheck_uri'); + $key = $rcube->config->get('spellcheck_atd_key'); + + if ($url) { + $a_uri = parse_url($url); + $ssl = ($a_uri['scheme'] == 'https' || $a_uri['scheme'] == 'ssl'); + $port = $a_uri['port'] ? $a_uri['port'] : ($ssl ? 443 : 80); + $host = ($ssl ? 'ssl://' : '') . $a_uri['host']; + $path = $a_uri['path'] . ($a_uri['query'] ? '?'.$a_uri['query'] : '') . $this->lang; + } + else { + $host = self::SERVICE_HOST; + $port = self::SERVICE_PORT; + $path = '/checkDocument'; + + // prefix host for other languages than 'en' + $lang = substr($this->lang, 0, 2); + if ($this->langhosts[$lang]) + $host = $this->langhosts[$lang] . $host; + } + + $postdata = 'data=' . urlencode($text); + + if (!empty($key)) + $postdata .= '&key=' . urlencode($key); + + $response = $headers = ''; + $in_header = true; + if ($fp = fsockopen($host, $port, $errno, $errstr, 30)) { + $out = "POST $path HTTP/1.0\r\n"; + $out .= "Host: " . str_replace('ssl://', '', $host) . "\r\n"; + $out .= "Content-Length: " . strlen($postdata) . "\r\n"; + $out .= "Content-Type: application/x-www-form-urlencoded\r\n"; + $out .= "Connection: Close\r\n\r\n"; + $out .= $postdata; + fwrite($fp, $out); + + while (!feof($fp)) { + if ($in_header) { + $line = fgets($fp, 512); + $headers .= $line; + if (trim($line) == '') + $in_header = false; + } + else { + $response .= fgets($fp, 1024); + } + } + fclose($fp); + } + + // parse HTTP response headers + if (preg_match('!^HTTP/1.\d (\d+)(.+)!', $headers, $m)) { + $http_status = $m[1]; + if ($http_status != '200') + $this->error = 'HTTP ' . $m[1] . $m[2]; + } + + if (!$response) { + $this->error = "Empty result from spelling engine"; + } + + try { + $result = new SimpleXMLElement($response); + } + catch (Exception $e) { + $thid->error = "Unexpected response from server: " . $store; + return array(); + } + + foreach ($result->error as $error) { + if (strval($error->type) == 'spelling') { + $word = strval($error->string); + + // skip exceptions + if ($this->dictionary->is_exception($word)) { + continue; + } + + $prefix = strval($error->precontext); + $start = $prefix ? mb_strpos($text, $prefix) : 0; + $pos = mb_strpos($text, $word, $start); + $len = mb_strlen($word); + $num = 0; + + $match = array($word, $pos, $len, null, array()); + foreach ($error->suggestions->option as $option) { + $match[4][] = strval($option); + if (++$num == self::MAX_SUGGESTIONS) + break; + } + $matches[] = $match; + } + } + + $this->matches = $matches; + return $matches; + } + + /** + * Returns suggestions for the specified word + * + * @see rcube_spellcheck_engine::get_words() + */ + function get_suggestions($word) + { + $matches = $word ? $this->check($word) : $this->matches; + + if ($matches[0][4]) { + return $matches[0][4]; + } + + return array(); + } + + /** + * Returns misspelled words + * + * @see rcube_spellcheck_engine::get_suggestions() + */ + function get_words($text = null) + { + if ($text) { + $matches = $this->check($text); + } + else { + $matches = $this->matches; + $text = $this->content; + } + + $result = array(); + + foreach ($matches as $m) { + $result[] = mb_substr($text, $m[1], $m[2], RCUBE_CHARSET); + } + + return $result; + } + +} + |