Files
roundcubemail/program/lib/Roundcube/spellchecker/googie.php
2024-06-02 15:57:56 +02:00

168 lines
5.6 KiB
PHP

<?php
/*
+-----------------------------------------------------------------------+
| This file is part of the Roundcube Webmail client |
| |
| Copyright (C) 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 to work with Googiespell |
+-----------------------------------------------------------------------+
| Author: Aleksander Machniak <machniak@kolabsys.com> |
| Author: Thomas Bruederli <roundcube@gmail.com> |
+-----------------------------------------------------------------------+
*/
/**
* Spellchecking backend implementation to work with a Googiespell service
*/
class rcube_spellchecker_googie extends rcube_spellchecker_engine
{
public const GOOGIE_HOST = 'https://spell.roundcube.net';
private $content;
/**
* Return a list of languages supported by this backend
*
* @see rcube_spellchecker_engine::languages()
*/
#[Override]
public function languages()
{
return [
'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
*
* @see rcube_spellchecker_engine::check()
*/
#[Override]
public function check($text)
{
$this->content = $text;
if (empty($text)) {
return true;
}
$this->matches = $matches = [];
$rcube = rcube::get_instance();
$client = $rcube->get_http_client();
// spell check uri is configured
$url = $rcube->config->get('spellcheck_uri');
if (!$url) {
$url = self::GOOGIE_HOST . '/tbproxy/spell?lang=';
}
$url .= $this->lang;
$url .= sprintf('&key=%06d', !empty($_SESSION['user_id']) ? $_SESSION['user_id'] : 0);
$gtext = '<?xml version="1.0" encoding="utf-8" ?>'
. '<spellrequest textalreadyclipped="0" ignoredups="0" ignoredigits="1" ignoreallcaps="1">'
. '<text>' . htmlspecialchars($text, \ENT_QUOTES, RCUBE_CHARSET) . '</text>'
. '</spellrequest>';
try {
$response = $client->post($url, [
'connect_timeout' => 5, // seconds
'headers' => [
'User-Agent' => 'Roundcube Webmail/' . RCUBE_VERSION . ' (Googiespell Wrapper)',
'Content-type' => 'text/xml',
],
'body' => $gtext,
]
);
} catch (Exception $e) {
// Do nothing, the error set below should be logged by the caller
}
if (empty($response)) {
$this->error = isset($e) ? $e->getMessage() : 'Spelling engine failure';
} elseif ($response->getStatusCode() != 200) {
$this->error = 'HTTP ' . $response->getReasonPhrase();
} else {
$response_body = $response->getBody();
if (preg_match('/<spellresult error="([^"]+)"/', $response_body, $m) && $m[1]) {
$this->error = "Error code {$m[1]} returned";
$this->error .= preg_match('/<errortext>([^<]+)/', $response_body, $m) ? ': ' . html_entity_decode($m[1]) : '';
}
preg_match_all('/<c o="([^"]*)" l="([^"]*)" s="([^"]*)">([^<]*)<\/c>/', $response_body, $matches, \PREG_SET_ORDER);
// skip exceptions (if appropriate options are enabled)
foreach ($matches as $idx => $match) {
$word = mb_substr($text, $match[1], $match[2], RCUBE_CHARSET);
// skip exceptions
if ($this->dictionary->is_exception($word)) {
unset($matches[$idx]);
}
}
}
$this->matches = $matches;
return count($this->matches) == 0;
}
/**
* Returns suggestions for the specified word
*
* @see rcube_spellchecker_engine::get_words()
*/
#[Override]
public function get_suggestions($word)
{
$this->check($word);
if (!empty($this->matches[0][4])) {
$suggestions = explode("\t", $this->matches[0][4]);
if (count($suggestions) > self::MAX_SUGGESTIONS) {
$suggestions = array_slice($suggestions, 0, self::MAX_SUGGESTIONS);
}
return $suggestions;
}
return [];
}
/**
* Returns misspelled words
*
* @see rcube_spellchecker_engine::get_suggestions()
*/
#[Override]
public function get_words($text = null)
{
if ($text) {
$this->check($text);
} else {
$text = $this->content;
}
$result = [];
foreach ($this->matches as $m) {
$result[] = mb_substr($text, $m[1], $m[2], RCUBE_CHARSET);
}
return $result;
}
}