1 /*
2     SPDX-FileCopyrightText: 2009 Jakub Wieczorek <faw217@gmail.com>
3     SPDX-FileCopyrightText: 2009 Christian Franke <cfchris6@ts2server.com>
4     SPDX-FileCopyrightText: 2009 Fredy Yanardi <fyanardi@gmail.com>
5 
6     SPDX-License-Identifier: GPL-2.0-or-later
7 */
8 
9 #include "OpenSearchEngine.h"
10 
11 #include <QRegExp>
12 #include <QStringList>
13 #include <QScriptEngine>
14 #include <QScriptValue>
15 #include <QLocale>
16 #include <QUrlQuery>
17 
OpenSearchEngine(QObject *)18 OpenSearchEngine::OpenSearchEngine(QObject *)
19     : m_scriptEngine(nullptr)
20 {
21 }
22 
~OpenSearchEngine()23 OpenSearchEngine::~OpenSearchEngine()
24 {
25     delete m_scriptEngine;
26 }
27 
parseTemplate(const QString & searchTerm,const QString & searchTemplate)28 QString OpenSearchEngine::parseTemplate(const QString &searchTerm, const QString &searchTemplate)
29 {
30     QString result = searchTemplate;
31     result.replace(QLatin1String("{count}"), QLatin1String("20"));
32     result.replace(QLatin1String("{startIndex}"), QLatin1String("0"));
33     result.replace(QLatin1String("{startPage}"), QLatin1String("0"));
34     result.replace(QLatin1String("{language}"), QLocale::languageToString(QLocale().language()));
35     result.replace(QLatin1String("{inputEncoding}"), QLatin1String("UTF-8"));
36     result.replace(QLatin1String("{outputEncoding}"), QLatin1String("UTF-8"));
37     result.replace(QLatin1String("{searchTerms}"), searchTerm);
38     return result;
39 }
40 
name() const41 QString OpenSearchEngine::name() const
42 {
43     return m_name;
44 }
45 
setName(const QString & name)46 void OpenSearchEngine::setName(const QString &name)
47 {
48     m_name = name;
49 }
50 
description() const51 QString OpenSearchEngine::description() const
52 {
53     return m_description;
54 }
55 
setDescription(const QString & description)56 void OpenSearchEngine::setDescription(const QString &description)
57 {
58     m_description = description;
59 }
60 
searchUrlTemplate() const61 QString OpenSearchEngine::searchUrlTemplate() const
62 {
63     return m_searchUrlTemplate;
64 }
65 
setSearchUrlTemplate(const QString & searchUrlTemplate)66 void OpenSearchEngine::setSearchUrlTemplate(const QString &searchUrlTemplate)
67 {
68     m_searchUrlTemplate = searchUrlTemplate;
69 }
70 
searchUrl(const QString & searchTerm) const71 QUrl OpenSearchEngine::searchUrl(const QString &searchTerm) const
72 {
73     if (m_searchUrlTemplate.isEmpty()) {
74         return QUrl();
75     }
76 
77     QUrl retVal = QUrl::fromEncoded(parseTemplate(searchTerm, m_searchUrlTemplate).toUtf8());
78     QUrlQuery query(retVal);
79 
80     QList<Parameter>::const_iterator end = m_searchParameters.constEnd();
81     QList<Parameter>::const_iterator i = m_searchParameters.constBegin();
82     for (; i != end; ++i) {
83         query.addQueryItem(i->first, parseTemplate(searchTerm, i->second));
84     }
85 
86     retVal.setQuery(query);
87     return retVal;
88 }
89 
providesSuggestions() const90 bool OpenSearchEngine::providesSuggestions() const
91 {
92     return !m_suggestionsUrlTemplate.isEmpty();
93 }
94 
suggestionsUrlTemplate() const95 QString OpenSearchEngine::suggestionsUrlTemplate() const
96 {
97     return m_suggestionsUrlTemplate;
98 }
99 
setSuggestionsUrlTemplate(const QString & suggestionsUrlTemplate)100 void OpenSearchEngine::setSuggestionsUrlTemplate(const QString &suggestionsUrlTemplate)
101 {
102     m_suggestionsUrlTemplate = suggestionsUrlTemplate;
103 }
104 
suggestionsUrl(const QString & searchTerm) const105 QUrl OpenSearchEngine::suggestionsUrl(const QString &searchTerm) const
106 {
107     if (m_suggestionsUrlTemplate.isEmpty()) {
108         return QUrl();
109     }
110 
111     QUrl retVal = QUrl::fromEncoded(parseTemplate(searchTerm, m_suggestionsUrlTemplate).toUtf8());
112     QUrlQuery query(retVal);
113 
114     QList<Parameter>::const_iterator end = m_suggestionsParameters.constEnd();
115     QList<Parameter>::const_iterator i = m_suggestionsParameters.constBegin();
116     for (; i != end; ++i) {
117         query.addQueryItem(i->first, parseTemplate(searchTerm, i->second));
118     }
119 
120     retVal.setQuery(query);
121     return retVal;
122 }
123 
searchParameters() const124 QList<OpenSearchEngine::Parameter> OpenSearchEngine::searchParameters() const
125 {
126     return m_searchParameters;
127 }
128 
setSearchParameters(const QList<Parameter> & searchParameters)129 void OpenSearchEngine::setSearchParameters(const QList<Parameter> &searchParameters)
130 {
131     m_searchParameters = searchParameters;
132 }
133 
suggestionsParameters() const134 QList<OpenSearchEngine::Parameter> OpenSearchEngine::suggestionsParameters() const
135 {
136     return m_suggestionsParameters;
137 }
138 
setSuggestionsParameters(const QList<Parameter> & suggestionsParameters)139 void OpenSearchEngine::setSuggestionsParameters(const QList<Parameter> &suggestionsParameters)
140 {
141     m_suggestionsParameters = suggestionsParameters;
142 }
143 
imageUrl() const144 QString OpenSearchEngine::imageUrl() const
145 {
146     return m_imageUrl;
147 }
148 
setImageUrl(const QString & imageUrl)149 void OpenSearchEngine::setImageUrl(const QString &imageUrl)
150 {
151     m_imageUrl = imageUrl;
152 }
153 
image() const154 QImage OpenSearchEngine::image() const
155 {
156     return m_image;
157 }
158 
setImage(const QImage & image)159 void OpenSearchEngine::setImage(const QImage &image)
160 {
161     m_image = image;
162 }
163 
isValid() const164 bool OpenSearchEngine::isValid() const
165 {
166     return (!m_name.isEmpty() && !m_searchUrlTemplate.isEmpty());
167 }
168 
operator ==(const OpenSearchEngine & other) const169 bool OpenSearchEngine::operator==(const OpenSearchEngine &other) const
170 {
171     return (m_name == other.m_name
172             && m_description == other.m_description
173             && m_imageUrl == other.m_imageUrl
174             && m_searchUrlTemplate == other.m_searchUrlTemplate
175             && m_suggestionsUrlTemplate == other.m_suggestionsUrlTemplate
176             && m_searchParameters == other.m_searchParameters
177             && m_suggestionsParameters == other.m_suggestionsParameters);
178 }
179 
operator <(const OpenSearchEngine & other) const180 bool OpenSearchEngine::operator<(const OpenSearchEngine &other) const
181 {
182     return (m_name < other.m_name);
183 }
184 
parseSuggestion(const QByteArray & resp)185 QStringList OpenSearchEngine::parseSuggestion(const QByteArray &resp)
186 {
187     const QString response = QString::fromUtf8(resp.constData(), resp.size()).trimmed();
188 
189     if (response.isEmpty()) {
190         return QStringList();
191     }
192 
193     if (!response.startsWith(QLatin1Char('[')) || !response.endsWith(QLatin1Char(']'))) {
194         return QStringList();
195     }
196 
197 #ifdef __GNUC__
198 #warning "QScriptEngine is deprecated, port to QJsonDocument"
199 #endif
200 
201     if (!m_scriptEngine) {
202         m_scriptEngine = new QScriptEngine();
203     }
204 
205     // Evaluate the JSON response using QtScript.
206     if (!m_scriptEngine->canEvaluate(response)) {
207         return QStringList();
208     }
209 
210     QScriptValue responseParts = m_scriptEngine->evaluate(response);
211 
212     if (!responseParts.property(1).isArray()) {
213         return QStringList();
214     }
215 
216     QStringList suggestionsList;
217     qScriptValueToSequence(responseParts.property(1), suggestionsList);
218 
219     return suggestionsList;
220 }
221 
222