cui/source/options/optlanguagetool.cxx | 3 cui/source/options/optlanguagetool.hxx | 3 cui/uiconfig/ui/langtoolconfigpage.ui | 38 ++++ lingucomponent/source/spellcheck/languagetool/languagetoolimp.cxx | 78 +++++++++- lingucomponent/source/spellcheck/languagetool/languagetoolimp.hxx | 3 5 files changed, 119 insertions(+), 6 deletions(-)
New commits: commit 5cd71035842776fec05f1423b9cc1acf33f12a13 Author: Henry Castro <hcas...@collabora.com> AuthorDate: Mon Nov 21 21:34:24 2022 -0400 Commit: Andras Timar <andras.ti...@collabora.com> CommitDate: Sat Jan 28 09:23:18 2023 +0000 lingucomponent: implement custom request http rest protocol Request: POST /api/check HTTP/1.1 Host: localhost:8099 Content-Type: application/json Cache-Control: no-cache { "dictionaries": [ "daily", "jungblutt" ], "text-language": "en-DE", "property-sets": [ "base", "daily", "culture" ], "hyphenation": true, "spellchecking-level": 1, "correction-proposals": true, "single-word-mode": false, "message-language": "fr-LU", "message-level": 1, "text": "This is a final throw for the interface to the Duden server." } Signed-off-by: Henry Castro <hcas...@collabora.com> Change-Id: I2a288a7c573014d42df03f7cc12c57a7f788750e Reviewed-on: https://gerrit.libreoffice.org/c/core/+/143107 Reviewed-by: Ashod Nakashian <a...@collabora.com> Reviewed-on: https://gerrit.libreoffice.org/c/core/+/145607 Reviewed-by: Andras Timar <andras.ti...@collabora.com> Tested-by: Andras Timar <andras.ti...@collabora.com> diff --git a/lingucomponent/source/spellcheck/languagetool/languagetoolimp.cxx b/lingucomponent/source/spellcheck/languagetool/languagetoolimp.cxx index 1dce1845fc43..12d39ef8af93 100644 --- a/lingucomponent/source/spellcheck/languagetool/languagetoolimp.cxx +++ b/lingucomponent/source/spellcheck/languagetool/languagetoolimp.cxx @@ -55,6 +55,8 @@ using namespace linguistic; #define COL_ORANGE Color(0xD1, 0x68, 0x20) +constexpr OUStringLiteral sDuden = u"duden"; + namespace { Sequence<PropertyValue> lcl_GetLineColorPropertyFromErrorId(const std::string& rErrorId) @@ -226,11 +228,28 @@ ProofreadingResult SAL_CALL LanguageToolGrammarChecker::doProofreading( } tools::Long http_code = 0; + std::string response_body; OUString langTag(aLocale.Language + "-" + aLocale.Country); - OString postData(OUStringToOString(Concat2View("text=" + aText + "&language=" + langTag), - RTL_TEXTENCODING_UTF8)); - const std::string response_body - = makeHttpRequest(checkerURL, HTTP_METHOD::HTTP_POST, postData, http_code); + + if (rLanguageOpts.getRestProtocol() == sDuden) + { + std::stringstream aStream; + boost::property_tree::ptree aTree; + aTree.put("text-language", langTag.toUtf8().getStr()); + aTree.put("text", aText.toUtf8().getStr()); + aTree.put("hyphenation", false); + aTree.put("spellchecking-level", 3); + aTree.put("correction-proposals", true); + boost::property_tree::write_json(aStream, aTree); + response_body = makeDudenHttpRequest(checkerURL, HTTP_METHOD::HTTP_POST, + aStream.str().c_str(), http_code); + } + else + { + OString postData(OUStringToOString(Concat2View("text=" + aText + "&language=" + langTag), + RTL_TEXTENCODING_UTF8)); + response_body = makeHttpRequest(checkerURL, HTTP_METHOD::HTTP_POST, postData, http_code); + } if (http_code != 200) { @@ -317,6 +336,57 @@ void LanguageToolGrammarChecker::parseProofreadingJSONResponse(ProofreadingResul rResult.aErrors = aErrors; } +std::string LanguageToolGrammarChecker::makeDudenHttpRequest(std::string_view aURL, HTTP_METHOD method, + const OString& aData, + tools::Long& nCode) +{ + std::unique_ptr<CURL, std::function<void(CURL*)>> curl(curl_easy_init(), + [](CURL* p) { curl_easy_cleanup(p); }); + if (!curl) + return {}; // empty string + + std::string sResponseBody; + struct curl_slist* pList = nullptr; + SvxLanguageToolOptions& rLanguageOpts = SvxLanguageToolOptions::Get(); + OString sAccessToken = OString("access_token: ") + + OUStringToOString(rLanguageOpts.getApiKey(), RTL_TEXTENCODING_UTF8); + + pList = curl_slist_append(pList, "Cache-Control: no-cache"); + pList = curl_slist_append(pList, "Content-Type: application/json"); + if (!sAccessToken.isEmpty()) + pList = curl_slist_append(pList, sAccessToken.getStr()); + + curl_easy_setopt(curl.get(), CURLOPT_HTTPHEADER, pList); + curl_easy_setopt(curl.get(), CURLOPT_FAILONERROR, 1L); + curl_easy_setopt(curl.get(), CURLOPT_URL, aURL.data()); + curl_easy_setopt(curl.get(), CURLOPT_TIMEOUT, CURL_TIMEOUT); + curl_easy_setopt(curl.get(), CURLOPT_WRITEFUNCTION, WriteCallback); + curl_easy_setopt(curl.get(), CURLOPT_WRITEDATA, static_cast<void*>(&sResponseBody)); + + // allow unknown or self-signed certificates + if (rLanguageOpts.getSSLVerification() == false) + { + curl_easy_setopt(curl.get(), CURLOPT_SSL_VERIFYPEER, false); + curl_easy_setopt(curl.get(), CURLOPT_SSL_VERIFYHOST, false); + } + + if (method == HTTP_METHOD::HTTP_POST) + { + curl_easy_setopt(curl.get(), CURLOPT_POST, 1L); + curl_easy_setopt(curl.get(), CURLOPT_POSTFIELDS, aData.getStr()); + } + + CURLcode cc = curl_easy_perform(curl.get()); + if (cc != CURLE_OK) + { + SAL_WARN("languagetool", "CURL request returned with error: " << static_cast<sal_Int32>(cc)); + } + + curl_easy_getinfo(curl.get(), CURLINFO_RESPONSE_CODE, &nCode); + return sResponseBody; + +} + std::string LanguageToolGrammarChecker::makeHttpRequest(std::string_view aURL, HTTP_METHOD method, const OString& aPostData, tools::Long& nStatusCode) diff --git a/lingucomponent/source/spellcheck/languagetool/languagetoolimp.hxx b/lingucomponent/source/spellcheck/languagetool/languagetoolimp.hxx index 0262be896cd6..c3b79c95a43c 100644 --- a/lingucomponent/source/spellcheck/languagetool/languagetoolimp.hxx +++ b/lingucomponent/source/spellcheck/languagetool/languagetoolimp.hxx @@ -53,6 +53,9 @@ class LanguageToolGrammarChecker LanguageToolGrammarChecker& operator=(const LanguageToolGrammarChecker&) = delete; static void parseProofreadingJSONResponse(css::linguistic2::ProofreadingResult& rResult, std::string_view aJSONBody); + static std::string makeDudenHttpRequest(std::string_view aURL, HTTP_METHOD method, + const OString& aPostData, + tools::Long& nStatusCode); static std::string makeHttpRequest(std::string_view aURL, HTTP_METHOD method, const OString& aPostData, tools::Long& nStatusCode); commit 7e2ef33d31eba98ded508b749799ce42b5e4f42c Author: Henry Castro <hcas...@collabora.com> AuthorDate: Mon Nov 21 21:30:02 2022 -0400 Commit: Andras Timar <andras.ti...@collabora.com> CommitDate: Sat Jan 28 09:23:04 2023 +0000 cui: add entry "RestProtocol" to language tool dialog Signed-off-by: Henry Castro <hcas...@collabora.com> Change-Id: I6511fc2b353c47b1ff537c42d3484b3a42c1b121 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/143106 Reviewed-by: Ashod Nakashian <a...@collabora.com> Reviewed-on: https://gerrit.libreoffice.org/c/core/+/145606 Reviewed-by: Andras Timar <andras.ti...@collabora.com> Tested-by: Andras Timar <andras.ti...@collabora.com> diff --git a/cui/source/options/optlanguagetool.cxx b/cui/source/options/optlanguagetool.cxx index f0006d1dd0e0..7a087b09e8c0 100644 --- a/cui/source/options/optlanguagetool.cxx +++ b/cui/source/options/optlanguagetool.cxx @@ -30,6 +30,7 @@ OptLanguageToolTabPage::OptLanguageToolTabPage(weld::Container* pPage, , m_xBaseURLED(m_xBuilder->weld_entry("baseurl")) , m_xUsernameED(m_xBuilder->weld_entry("username")) , m_xApiKeyED(m_xBuilder->weld_entry("apikey")) + , m_xRestProtocol(m_xBuilder->weld_entry("restprotocol")) , m_xActivateBox(m_xBuilder->weld_check_button("activate")) , m_xSSLDisableVerificationBox(m_xBuilder->weld_check_button("verifyssl")) , m_xApiSettingsFrame(m_xBuilder->weld_frame("apisettings")) @@ -73,6 +74,7 @@ void OptLanguageToolTabPage::Reset(const SfxItemSet*) m_xUsernameED->set_text(rLanguageOpts.getUsername()); m_xApiKeyED->set_text(rLanguageOpts.getApiKey()); + m_xRestProtocol->set_text(rLanguageOpts.getRestProtocol()); m_xSSLDisableVerificationBox->set_active(rLanguageOpts.getSSLVerification() != true); } @@ -89,6 +91,7 @@ bool OptLanguageToolTabPage::FillItemSet(SfxItemSet*) rLanguageOpts.setUsername(m_xUsernameED->get_text()); rLanguageOpts.setApiKey(m_xApiKeyED->get_text()); + rLanguageOpts.setRestProtocol(m_xRestProtocol->get_text()); rLanguageOpts.setSSLVerification(m_xSSLDisableVerificationBox->get_active() != true); return false; } diff --git a/cui/source/options/optlanguagetool.hxx b/cui/source/options/optlanguagetool.hxx index 666512804c62..141d88f63bb4 100644 --- a/cui/source/options/optlanguagetool.hxx +++ b/cui/source/options/optlanguagetool.hxx @@ -38,6 +38,7 @@ private: std::unique_ptr<weld::Entry> m_xBaseURLED; std::unique_ptr<weld::Entry> m_xUsernameED; std::unique_ptr<weld::Entry> m_xApiKeyED; + std::unique_ptr<weld::Entry> m_xRestProtocol; std::unique_ptr<weld::CheckButton> m_xActivateBox; std::unique_ptr<weld::CheckButton> m_xSSLDisableVerificationBox; std::unique_ptr<weld::Frame> m_xApiSettingsFrame; @@ -45,4 +46,4 @@ private: void EnableControls(bool bEnable); DECL_LINK(CheckHdl, weld::Toggleable&, void); -}; \ No newline at end of file +}; diff --git a/cui/uiconfig/ui/langtoolconfigpage.ui b/cui/uiconfig/ui/langtoolconfigpage.ui index 237040fa76b7..1d7452161998 100644 --- a/cui/uiconfig/ui/langtoolconfigpage.ui +++ b/cui/uiconfig/ui/langtoolconfigpage.ui @@ -80,7 +80,7 @@ <object class="GtkGrid" id="grid2"> <property name="visible">True</property> <property name="can_focus">False</property> - <property name="row_spacing">5</property> + <property name="row_spacing">6</property> <property name="column_spacing">12</property> <child> <object class="GtkLabel" id="base"> @@ -191,6 +191,42 @@ <property name="top_attach">5</property> </packing> </child> + <child> + <object class="GtkLabel" id="restlbl"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="halign">start</property> + <property name="label" translatable="yes" context="langtoolconfigpage|restlbl">REST protocol:</property> + <property name="use_underline">True</property> + <property name="mnemonic_widget">restprotocol</property> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">6</property> + </packing> + </child> + <child> + <object class="GtkEntry" id="restprotocol"> + <property name="visible">True</property> + <property name="can_focus">True</property> + </object> + <packing> + <property name="left_attach">1</property> + <property name="top_attach">6</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="restdesc"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="halign">start</property> + <property name="label" translatable="yes" context="langtoolconfigpage|restdesc">Your LanguageTool REST API protocol for usage.</property> + </object> + <packing> + <property name="left_attach">1</property> + <property name="top_attach">7</property> + </packing> + </child> <child> <placeholder/> </child>