KCDDB

asynccddbplookup.cpp
1/*
2 SPDX-FileCopyrightText: 2002 Rik Hemsley (rikkus) <rik@kde.org>
3 SPDX-FileCopyrightText: 2002 Benjamin Meyer <ben-devel@meyerhome.net>
4 SPDX-FileCopyrightText: 2005 Richard Lärkäng <nouseforaname@home.se>
5
6 SPDX-License-Identifier: LGPL-2.0-or-later
7*/
8
9#include "asynccddbplookup.h"
10#include "logging.h"
11
12namespace KCDDB
13{
14 AsyncCDDBPLookup::AsyncCDDBPLookup()
15 : CDDBPLookup(),
16 state_(Idle)
17 {
18
19 }
20
21 AsyncCDDBPLookup::~AsyncCDDBPLookup()
22 {
23 }
24
25 Result
26 AsyncCDDBPLookup::lookup
27 (
28 const QString & hostname,
29 uint port,
30 const TrackOffsetList & trackOffsetList
31 )
32 {
33 socket_ = new QTcpSocket;
34 socket_->connectToHost(hostname, port);
35
36 connect (socket_, SIGNAL(error(QAbstractSocket::SocketError)), SLOT(slotGotError(QAbstractSocket::SocketError)));
37
39 this, &AsyncCDDBPLookup::slotConnectionSuccess );
40
41 connect (socket_, &QIODevice::readyRead, this, &AsyncCDDBPLookup::slotReadyRead );
42
43 trackOffsetList_ = trackOffsetList;
44
45 state_ = WaitingForConnection;
46
47 return Success;
48 }
49
50 void
51 AsyncCDDBPLookup::slotGotError(QAbstractSocket::SocketError error)
52 {
53 state_ = Idle;
54
56 Q_EMIT finished( HostNotFound );
57 else if ( error == QAbstractSocket::SocketTimeoutError )
58 Q_EMIT finished( NoResponse );
59 else
60 Q_EMIT finished( UnknownError );
61 }
62
63 void
64 AsyncCDDBPLookup::slotConnectionSuccess()
65 {
66 qCDebug(LIBKCDDB) << "Connection successful";
67 state_ = WaitingForGreeting;
68 }
69
70 void
71 AsyncCDDBPLookup::slotReadyRead()
72 {
73 qCDebug(LIBKCDDB) << "Ready to read. State: " << stateToString();
74
75 while ( Idle != state_ && isConnected() && socket_->canReadLine() )
76 read();
77 }
78
79 void
80 AsyncCDDBPLookup::read()
81 {
82 switch ( state_ )
83 {
84 case WaitingForGreeting:
85
86 if ( !parseGreeting( readLine() ) )
87 {
88 result_ = ServerError;
89 doQuit();
90 return;
91 }
92
93 doHandshake();
94
95 break;
96
97 case WaitingForHandshake:
98
99 if ( !parseHandshake( readLine() ) )
100 {
101 result_ = ServerError;
102 doQuit();
103 return;
104 }
105
106 doProto();
107
108 break;
109
110 case WaitingForProtoResponse:
111
112 // Ignore the response for now
113 readLine();
114
115 doQuery();
116
117 break;
118
119 case WaitingForQueryResponse:
120 result_ = parseQuery( readLine() );
121
122 switch ( result_ )
123 {
124 case Success:
125 requestCDInfoForMatch();
126 break;
127
128 case MultipleRecordFound:
129 state_ = WaitingForMoreMatches;
130 break;
131
132 default: // Error :(
133 doQuit();
134 return;
135 }
136
137 break;
138
139 case WaitingForMoreMatches:
140 {
141 QString line = readLine();
142
143 if (line.startsWith(QLatin1String( "." )))
144 requestCDInfoForMatch();
145 else
146 parseExtraMatch( line );
147 }
148
149 break;
150
151 case WaitingForCDInfoResponse:
152 {
153 Result result = parseRead( readLine() );
154
155 if ( Success != result )
156 {
157 result_ = result;
158 doQuit();
159 return;
160 }
161
162 state_ = WaitingForCDInfoData;
163 }
164
165 break;
166
167 case WaitingForCDInfoData:
168 {
169 QString line = readLine();
170
171 if (line.startsWith(QLatin1String( "." )))
172 {
173 parseCDInfoData();
174 requestCDInfoForMatch();
175 }
176 else
177 cdInfoBuffer_ << line;
178 }
179
180 break;
181
182 case WaitingForQuitResponse:
183
184 state_ = Idle;
185
186 char c;
187 while ( socket_->bytesAvailable() )
188 socket_->getChar(&c);
189
190 close();
191
192 Q_EMIT finished( result_ );
193
194 break;
195
196 default:
197
198 break;
199 }
200 }
201
202 QString
203 AsyncCDDBPLookup::readLine()
204 {
205 return QString::fromUtf8(socket_->readLine());
206 }
207
208 void
209 AsyncCDDBPLookup::doHandshake()
210 {
211 sendHandshake();
212
213 state_ = WaitingForHandshake;
214 }
215
216 void
217 AsyncCDDBPLookup::doProto()
218 {
219 sendProto();
220
221 state_ = WaitingForProtoResponse;
222 }
223
224 void
225 AsyncCDDBPLookup::doQuery()
226 {
227 sendQuery();
228
229 state_ = WaitingForQueryResponse;
230 }
231
232 void
233 AsyncCDDBPLookup::requestCDInfoForMatch()
234 {
235 if (matchList_.isEmpty())
236 {
237 result_ = cdInfoList_.isEmpty()? NoRecordFound : Success;
238 doQuit();
239 return;
240 }
241
242 CDDBMatch match = matchList_.takeFirst();
243
244 sendRead( match );
245
246 state_ = WaitingForCDInfoResponse;
247 }
248
249 void
250 AsyncCDDBPLookup::parseCDInfoData()
251 {
252 CDInfo info;
253
254 if (info.load( cdInfoBuffer_ ))
255 {
256 info.set( QLatin1String( "category" ), category_ );
257 info.set( QLatin1String( "discid" ), discid_ );
258 info.set( QLatin1String( "source" ), QLatin1String( "freedb" ) );
259 cdInfoList_.append( info );
260 }
261
262 cdInfoBuffer_.clear();
263 }
264
265 void
266 AsyncCDDBPLookup::doQuit()
267 {
268 state_ = WaitingForQuitResponse;
269
270 sendQuit();
271 }
272
273 QString
274 AsyncCDDBPLookup::stateToString() const
275 {
276 switch (state_)
277 {
278 case Idle:
279 return QLatin1String( "Idle" );
280 break;
281
282 case WaitingForConnection:
283 return QLatin1String( "WaitingForConnection" );
284 break;
285
286 case WaitingForGreeting:
287 return QLatin1String( "WaitingForGreeting" );
288 break;
289
290 case WaitingForProtoResponse:
291 return QLatin1String( "WaitingForProtoResponse" );
292 break;
293
294 case WaitingForHandshake:
295 return QLatin1String( "WaitingForHandshake" );
296 break;
297
298 case WaitingForQueryResponse:
299 return QLatin1String( "WaitingForQueryResponse" );
300 break;
301
302 case WaitingForMoreMatches:
303 return QLatin1String( "WaitingForMoreMatches" );
304 break;
305
306 case WaitingForCDInfoResponse:
307 return QLatin1String( "WaitingForCDInfoResponse" );
308 break;
309
310 case WaitingForCDInfoData:
311 return QLatin1String( "WaitingForCDInfoData" );
312 break;
313
314 case WaitingForQuitResponse:
315 return QLatin1String( "WaitingForQuitResponse" );
316 break;
317
318 default:
319 return QLatin1String( "Unknown" );
320 break;
321 }
322 }
323}
324
325#include "moc_asynccddbplookup.cpp"
326
327// vim:tabstop=2:shiftwidth=2:expandtab:cinoptions=(s,U1,m1
KCOREADDONS_EXPORT Result match(QStringView pattern, QStringView str)
QVariant read(const QByteArray &data, int versionOverride=0)
void error(QWidget *parent, const QString &text, const QString &title, const KGuiItem &buttonOk, Options options=Notify)
const QList< QKeySequence > & close()
void connectToHost(const QHostAddress &address, quint16 port, OpenMode openMode)
void readyRead()
QString fromUtf8(QByteArrayView str)
bool startsWith(QChar c, Qt::CaseSensitivity cs) const const
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Mon Nov 18 2024 12:17:48 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.