1/*
2 * Copyright (C) 2007 Thomas Georgiou <TAGeorgiou@gmail.com> and Jeff Cooper <weirdsox11@gmail.com>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Library General Public License version 2 as
6 * published by the Free Software Foundation
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details
12 *
13 * You should have received a copy of the GNU Library General Public
14 * License along with this program; if not, write to the
15 * Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 */
18
19#include "dictengine.h"
20#include <iostream>
21
22#include <KDebug>
23#include <KLocale>
24#include <ktcpsocket.h>
25
26#include <Plasma/DataContainer>
27
28DictEngine::DictEngine(QObject* parent, const QVariantList& args)
29 : Plasma::DataEngine(parent, args)
30 , m_tcpSocket(0)
31{
32 Q_UNUSED(args)
33 m_serverName = "dict.org"; //In case we need to switch it later
34 m_dictName = "wn"; //Default, good dictionary
35}
36
37DictEngine::~DictEngine()
38{
39}
40
41void DictEngine::setDict(const QString &dict)
42{
43 m_dictName = dict;
44}
45
46void DictEngine::setServer(const QString &server)
47{
48 m_serverName = server;
49}
50
51static QString wnToHtml(const QString &word, QByteArray &text)
52{
53 Q_UNUSED(word)
54 QList<QByteArray> splitText = text.split('\n');
55 QString def;
56 def += "<dl>\n";
57 QRegExp linkRx("\\{(.*)\\}");
58 linkRx.setMinimal(true);
59
60 bool isFirst=true;
61 while (!splitText.empty()) {
62 //150 n definitions retrieved - definitions follow
63 //151 word database name - text follows
64 //250 ok (optional timing information here)
65 //552 No match
66 QString currentLine = splitText.takeFirst();
67 if (currentLine.startsWith(QLatin1String("151"))) {
68 isFirst = true;
69 continue;
70 }
71
72 if (currentLine.startsWith('.')) {
73 def += "</dd>";
74 continue;
75 }
76
77 if (!(currentLine.startsWith(QLatin1String("150"))
78 || currentLine.startsWith(QLatin1String("151"))
79 || currentLine.startsWith(QLatin1String("250"))
80 || currentLine.startsWith(QLatin1String("552")))) {
81 currentLine.replace(linkRx,"<a href=\"\\1\">\\1</a>");
82
83 if (isFirst) {
84 def += "<dt><b>" + currentLine + "</b></dt>\n<dd>";
85 isFirst = false;
86 continue;
87 } else {
88 if (currentLine.contains(QRegExp("([1-9]{1,2}:)"))) {
89 def += "\n<br>\n";
90 }
91 currentLine.replace(QRegExp("^([\\s\\S]*[1-9]{1,2}:)"), "<b>\\1</b>");
92 def += currentLine;
93 continue;
94 }
95 }
96
97 }
98
99 def += "</dl>";
100 return def;
101}
102
103void DictEngine::getDefinition()
104{
105 m_tcpSocket->readAll();
106 QByteArray ret;
107
108 m_tcpSocket->write(QByteArray("DEFINE "));
109 m_tcpSocket->write(m_dictName.toAscii());
110 m_tcpSocket->write(QByteArray(" \""));
111 m_tcpSocket->write(m_currentWord.toUtf8());
112 m_tcpSocket->write(QByteArray("\"\n"));
113 m_tcpSocket->flush();
114
115 while (!ret.contains("250") && !ret.contains("552") && !ret.contains("550")) {
116 m_tcpSocket->waitForReadyRead();
117 ret += m_tcpSocket->readAll();
118 }
119
120 connect(m_tcpSocket, SIGNAL(disconnected()), this, SLOT(socketClosed()));
121 m_tcpSocket->disconnectFromHost();
122 // setData(m_currentWord, m_dictName, ret);
123 // qWarning()<<ret;
124 setData(m_currentWord, "text", wnToHtml(m_currentWord,ret));
125}
126
127void DictEngine::getDicts()
128{
129 QMap<QString, QString> theHash;
130 m_tcpSocket->readAll();
131 QByteArray ret;
132
133 m_tcpSocket->write(QByteArray("SHOW DB\n"));;
134 m_tcpSocket->flush();
135
136 m_tcpSocket->waitForReadyRead();
137 while (!ret.contains("250")) {
138 m_tcpSocket->waitForReadyRead();
139 ret += m_tcpSocket->readAll();
140 }
141
142 QList<QByteArray> retLines = ret.split('\n');
143 QString tmp1, tmp2;
144
145 while (!retLines.empty()) {
146 QString curr(retLines.takeFirst());
147
148 if (curr.startsWith(QLatin1String("554"))) {
149 //TODO: What happens if no DB available?
150 //TODO: Eventually there will be functionality to change the server...
151 break;
152 }
153
154 // ignore status code and empty lines
155 if (curr.startsWith(QLatin1String("250")) || curr.startsWith(QLatin1String("110"))
156 || curr.isEmpty()) {
157 continue;
158 }
159
160 if (!curr.startsWith('-') && !curr.startsWith('.')) {
161 curr = curr.trimmed();
162 tmp1 = curr.section(' ', 0, 0);
163 tmp2 = curr.section(' ', 1);
164 // theHash.insert(tmp1, tmp2);
165 //kDebug() << tmp1 + " " + tmp2;
166 setData("list-dictionaries", tmp1, tmp2);
167 }
168 }
169
170 m_tcpSocket->disconnectFromHost();
171// setData("list-dictionaries", "dictionaries", QByteArray(theHash);
172}
173
174
175
176void DictEngine::socketClosed()
177{
178 m_tcpSocket->deleteLater();
179 m_tcpSocket = 0;
180}
181
182bool DictEngine::sourceRequestEvent(const QString &query)
183{
184 // FIXME: this is COMPLETELY broken .. it can only look up one query at a time!
185 // a DataContainer subclass that does the look up should probably be made
186 if (m_currentQuery == query) {
187 return false;
188 }
189
190 if (m_tcpSocket) {
191 m_tcpSocket->abort(); //stop if lookup is in progress and new query is requested
192 m_tcpSocket->deleteLater();
193 m_tcpSocket = 0;
194 }
195
196 QStringList queryParts = query.split(':', QString::SkipEmptyParts);
197 if (queryParts.isEmpty()) {
198 return false;
199 }
200
201 m_currentWord = queryParts.last();
202 m_currentQuery = query;
203
204 //asked for a dictionary?
205 if (queryParts.count() > 1) {
206 setDict(queryParts[queryParts.count()-2]);
207 //default to wordnet
208 } else {
209 setDict("wn");
210 }
211
212 //asked for a server?
213 if (queryParts.count() > 2) {
214 setServer(queryParts[queryParts.count()-3]);
215 //default to wordnet
216 } else {
217 setServer("dict.org");
218 }
219
220 if (m_currentWord.simplified().isEmpty()) {
221 setData(m_currentWord, m_dictName, QString());
222 } else {
223 setData(m_currentWord, m_dictName, QString());
224 m_tcpSocket = new KTcpSocket(this);
225 m_tcpSocket->abort();
226 connect(m_tcpSocket, SIGNAL(disconnected()), this, SLOT(socketClosed()));
227
228 if (m_currentWord == "list-dictionaries") {
229 connect(m_tcpSocket, SIGNAL(readyRead()), this, SLOT(getDicts()));
230 } else {
231 connect(m_tcpSocket, SIGNAL(readyRead()), this, SLOT(getDefinition()));
232 }
233
234 m_tcpSocket->connectToHost(m_serverName, 2628);
235 }
236
237 return true;
238}
239
240#include "dictengine.moc"
241