From c344b64f13e7aa3c87c423cc14e57536d28c40b6 Mon Sep 17 00:00:00 2001 From: Thomas Bruederli Date: Fri, 18 Oct 2013 12:50:25 +0200 Subject: Get supported spell-check languages from the configured backend; replace suspended google spell service with our new service at spell.roundcube.net --- program/lib/Roundcube/rcube_spellcheck_atd.php | 12 ++++++ program/lib/Roundcube/rcube_spellcheck_enchant.php | 18 +++++++++ program/lib/Roundcube/rcube_spellcheck_engine.php | 7 ++++ program/lib/Roundcube/rcube_spellcheck_googie.php | 36 ++++++++++++----- program/lib/Roundcube/rcube_spellcheck_pspell.php | 29 +++++++++++++ program/lib/Roundcube/rcube_spellchecker.php | 47 +++++++++++++++++++++- program/steps/mail/compose.inc | 27 +++---------- program/steps/utils/spell.inc | 3 ++ 8 files changed, 147 insertions(+), 32 deletions(-) diff --git a/program/lib/Roundcube/rcube_spellcheck_atd.php b/program/lib/Roundcube/rcube_spellcheck_atd.php index 68e8b7cb8..9f073f56f 100644 --- a/program/lib/Roundcube/rcube_spellcheck_atd.php +++ b/program/lib/Roundcube/rcube_spellcheck_atd.php @@ -38,6 +38,18 @@ class rcube_spellcheck_atd extends rcube_spellcheck_engine 'es' => 'es.', ); + /** + * Return a list of languages supported by this backend + * + * @see rcube_spellcheck_engine::languages() + */ + function languages() + { + $langs = array_values($this->langhosts); + $langs[] = 'en'; + return $langs; + } + /** * Set content and check spelling * diff --git a/program/lib/Roundcube/rcube_spellcheck_enchant.php b/program/lib/Roundcube/rcube_spellcheck_enchant.php index a22251e00..14d6fff46 100644 --- a/program/lib/Roundcube/rcube_spellcheck_enchant.php +++ b/program/lib/Roundcube/rcube_spellcheck_enchant.php @@ -30,6 +30,24 @@ class rcube_spellcheck_enchant extends rcube_spellcheck_engine private $enchant_dictionary; private $matches = array(); + /** + * Return a list of languages supported by this backend + * + * @see rcube_spellcheck_engine::languages() + */ + function languages() + { + $this->init(); + + $langs = array(); + $dicts = enchant_broker_list_dicts($this->enchant_broker); + foreach ($dicts as $dict) { + $langs[] = preg_replace('/-.*$/', '', $dict['lang_tag']); + } + + return array_unique($langs); + } + /** * Initializes Enchant dictionary */ diff --git a/program/lib/Roundcube/rcube_spellcheck_engine.php b/program/lib/Roundcube/rcube_spellcheck_engine.php index 88e10ac05..3cb4ca3de 100644 --- a/program/lib/Roundcube/rcube_spellcheck_engine.php +++ b/program/lib/Roundcube/rcube_spellcheck_engine.php @@ -42,6 +42,13 @@ abstract class rcube_spellcheck_engine $this->lang = $lang; } + /** + * Return a list of languages supported by this backend + * + * @return array Indexed list of language codes + */ + abstract function languages(); + /** * Set content and check spelling * diff --git a/program/lib/Roundcube/rcube_spellcheck_googie.php b/program/lib/Roundcube/rcube_spellcheck_googie.php index 70507dc23..3777942a6 100644 --- a/program/lib/Roundcube/rcube_spellcheck_googie.php +++ b/program/lib/Roundcube/rcube_spellcheck_googie.php @@ -26,12 +26,27 @@ */ class rcube_spellcheck_googie extends rcube_spellcheck_engine { - const GOOGLE_HOST = 'ssl://www.google.com'; - const GOOGLE_PORT = 443; + const GOOGIE_HOST = 'ssl://spell.roundcube.net'; + const GOOGIE_PORT = 443; private $matches = array(); private $content; + /** + * Return a list of languages supported by this backend + * + * @see rcube_spellcheck_engine::languages() + */ + function languages() + { + return array('am','ar','ar','bg','br','ca','cs','cy','da', + 'de_CH','de_DE','el','en_GB','en_US', + 'eo','es','et','eu','fa','fi','fr_FR','ga','gl','gl', + 'he','hr','hu','hy','is','it','ku','lt','lv','nl', + 'pl','pt_BR','pt_PT','ro','ru', + 'sk','sl','sv','uk'); + } + /** * Set content and check spelling * @@ -52,25 +67,25 @@ class rcube_spellcheck_googie extends rcube_spellcheck_engine $path = $a_uri['path'] . ($a_uri['query'] ? '?'.$a_uri['query'] : '') . $this->lang; } else { - $host = self::GOOGLE_HOST; - $port = self::GOOGLE_PORT; + $host = self::GOOGIE_HOST; + $port = self::GOOGIE_PORT; $path = '/tbproxy/spell?lang=' . $this->lang; } - // Google has some problem with spaces, use \n instead - $gtext = str_replace(' ', "\n", $text); + $path .= sprintf('&key=%06d', $_SESSION['user_id']); $gtext = '' .'' - .'' . $gtext . '' + .'' . htmlspecialchars($text, ENT_QUOTES, RCUBE_CHARSET) . '' .''; $store = ''; 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 .= "User-Agent: Roundcube Webmail/" . RCMAIL_VERSION . " (Googiespell Wrapper)\r\n"; $out .= "Content-Length: " . strlen($gtext) . "\r\n"; - $out .= "Content-Type: application/x-www-form-urlencoded\r\n"; + $out .= "Content-Type: text/xml\r\n"; $out .= "Connection: Close\r\n\r\n"; $out .= $gtext; fwrite($fp, $out); @@ -83,8 +98,10 @@ class rcube_spellcheck_googie extends rcube_spellcheck_engine // parse HTTP response if (preg_match('!^HTTP/1.\d (\d+)(.+)!', $store, $m)) { $http_status = $m[1]; - if ($http_status != '200') + if ($http_status != '200') { $this->error = 'HTTP ' . $m[1] . $m[2]; + $this->error .= "\n" . $store; + } } if (!$store) { @@ -92,6 +109,7 @@ class rcube_spellcheck_googie extends rcube_spellcheck_engine } else if (preg_match('/error = "Error code $m[1] returned"; + $this->error .= preg_match('/([^<]+)/', $store, $m) ? ": " . html_entity_decode($m[1]) : ''; } preg_match_all('/([^<]*)<\/c>/', $store, $matches, PREG_SET_ORDER); diff --git a/program/lib/Roundcube/rcube_spellcheck_pspell.php b/program/lib/Roundcube/rcube_spellcheck_pspell.php index ce089ed8f..b12684e43 100644 --- a/program/lib/Roundcube/rcube_spellcheck_pspell.php +++ b/program/lib/Roundcube/rcube_spellcheck_pspell.php @@ -29,6 +29,35 @@ class rcube_spellcheck_pspell extends rcube_spellcheck_engine private $plink; private $matches = array(); + /** + * Return a list of languages supported by this backend + * + * @see rcube_spellcheck_engine::languages() + */ + function languages() + { + $defaults = array('en'); + $langs = array(); + + // get aspell dictionaries + exec('aspell dump dicts', $dicts); + if (!empty($dicts)) { + $seen = array(); + foreach ($dicts as $lang) { + $lang = preg_replace('/-.*$/', '', $lang); + $langc = strlen($lang) == 2 ? $lang.'_'.strtoupper($lang) : $lang; + if (!$seen[$langc]++) + $langs[] = $lang; + } + $langs = array_unique($langs); + } + else { + $langs = $defaults; + } + + return $langs; + } + /** * Initializes PSpell dictionary */ diff --git a/program/lib/Roundcube/rcube_spellchecker.php b/program/lib/Roundcube/rcube_spellchecker.php index 31835dbb5..d087d2584 100644 --- a/program/lib/Roundcube/rcube_spellchecker.php +++ b/program/lib/Roundcube/rcube_spellchecker.php @@ -65,6 +65,49 @@ class rcube_spellchecker } } + /** + * Return a list of supported languages + */ + function languages() + { + // trust configuration + $configured = $this->rc->config->get('spellcheck_languages'); + if (!empty($configured) && is_array($configured) && !$configured[0]) { + return $configured; + } + else if (!empty($configured)) { + $langs = (array)$configured; + } + else if ($this->backend) { + $langs = $this->backend->languages(); + } + + // load index + @include(RCUBE_LOCALIZATION_DIR . 'index.inc'); + + // add correct labels + $languages = array(); + foreach ($langs as $lang) { + $langc = strtolower(substr($lang, 0, 2)); + $alias = $rcube_language_aliases[$langc]; + if (!$alias) { + $alias = $langc.'_'.strtoupper($langc); + } + if ($rcube_languages[$lang]) { + $languages[$lang] = $rcube_languages[$lang]; + } + else if ($rcube_languages[$alias]) { + $languages[$lang] = $rcube_languages[$alias]; + } + else { + $languages[$lang] = ucfirst($lang); + } + } + + asort($languages); + + return $languages; + } /** * Set content and check spelling @@ -152,7 +195,7 @@ class rcube_spellchecker // send output $out = ''; - foreach ($this->matches as $item) { + foreach ((array)$this->matches as $item) { $out .= ''; $out .= is_array($item[4]) ? implode("\t", $item[4]) : $item[4]; $out .= ''; @@ -173,7 +216,7 @@ class rcube_spellchecker { $result = array(); - foreach ($this->matches as $item) { + foreach ((array)$this->matches as $item) { if ($this->engine == 'pspell') { $word = $item[0]; } diff --git a/program/steps/mail/compose.inc b/program/steps/mail/compose.inc index dc2452506..166a58341 100644 --- a/program/steps/mail/compose.inc +++ b/program/steps/mail/compose.inc @@ -852,29 +852,14 @@ function rcmail_compose_body($attrib) // Set language list if (!empty($CONFIG['enable_spellcheck'])) { - $engine = $RCMAIL->config->get('spellcheck_engine','googie'); + $engine = new rcube_spellchecker(); $dictionary = (bool) $RCMAIL->config->get('spellcheck_dictionary'); - $spellcheck_langs = (array) $RCMAIL->config->get('spellcheck_languages', - array('da'=>'Dansk', 'de'=>'Deutsch', 'en' => 'English', 'es'=>'Español', - 'fr'=>'Français', 'it'=>'Italiano', 'nl'=>'Nederlands', 'pl'=>'Polski', - 'pt'=>'Português', 'ru'=>'Русский', 'fi'=>'Suomi', 'sv'=>'Svenska')); - - // googie works only with two-letter codes - if ($engine == 'googie') { - $lang = strtolower(substr($_SESSION['language'], 0, 2)); - - $spellcheck_langs_googie = array(); - foreach ($spellcheck_langs as $key => $name) - $spellcheck_langs_googie[strtolower(substr($key,0,2))] = $name; - $spellcheck_langs = $spellcheck_langs_googie; - } - else { - $lang = $_SESSION['language']; + $spellcheck_langs = $engine->languages(); + $lang = $_SESSION['language']; - // if not found in the list, try with two-letter code - if (!$spellcheck_langs[$lang]) - $lang = strtolower(substr($lang, 0, 2)); - } + // if not found in the list, try with two-letter code + if (!$spellcheck_langs[$lang]) + $lang = strtolower(substr($lang, 0, 2)); if (!$spellcheck_langs[$lang]) $lang = 'en'; diff --git a/program/steps/utils/spell.inc b/program/steps/utils/spell.inc index 1c68e8328..595cfd6f2 100644 --- a/program/steps/utils/spell.inc +++ b/program/steps/utils/spell.inc @@ -47,6 +47,9 @@ if ($err = $spellchecker->error()) { 'file' => __FILE__, 'line' => __LINE__, 'message' => "Spell check engine error: " . trim($err)), true, false); + + header("HTTP/1.0 500 Internal Server Error"); + exit; } // set response length -- cgit v1.2.3