File indexing completed on 2024-04-14 04:49:13
0001 /* 0002 SPDX-FileCopyrightText: 2002 Rik Hemsley (rikkus) <rik@kde.org> 0003 SPDX-FileCopyrightText: 2002 Benjamin Meyer <ben-devel@meyerhome.net> 0004 SPDX-FileCopyrightText: 2005 Richard Lärkäng <nouseforaname@home.se> 0005 0006 SPDX-License-Identifier: LGPL-2.0-or-later 0007 */ 0008 0009 #include "asynccddbplookup.h" 0010 #include "logging.h" 0011 0012 namespace KCDDB 0013 { 0014 AsyncCDDBPLookup::AsyncCDDBPLookup() 0015 : CDDBPLookup(), 0016 state_(Idle) 0017 { 0018 0019 } 0020 0021 AsyncCDDBPLookup::~AsyncCDDBPLookup() 0022 { 0023 } 0024 0025 Result 0026 AsyncCDDBPLookup::lookup 0027 ( 0028 const QString & hostname, 0029 uint port, 0030 const TrackOffsetList & trackOffsetList 0031 ) 0032 { 0033 socket_ = new QTcpSocket; 0034 socket_->connectToHost(hostname, port); 0035 0036 connect (socket_, SIGNAL(error(QAbstractSocket::SocketError)), SLOT(slotGotError(QAbstractSocket::SocketError))); 0037 0038 connect (socket_, &QAbstractSocket::connected, 0039 this, &AsyncCDDBPLookup::slotConnectionSuccess ); 0040 0041 connect (socket_, &QIODevice::readyRead, this, &AsyncCDDBPLookup::slotReadyRead ); 0042 0043 trackOffsetList_ = trackOffsetList; 0044 0045 state_ = WaitingForConnection; 0046 0047 return Success; 0048 } 0049 0050 void 0051 AsyncCDDBPLookup::slotGotError(QAbstractSocket::SocketError error) 0052 { 0053 state_ = Idle; 0054 0055 if ( error == QAbstractSocket::HostNotFoundError ) 0056 Q_EMIT finished( HostNotFound ); 0057 else if ( error == QAbstractSocket::SocketTimeoutError ) 0058 Q_EMIT finished( NoResponse ); 0059 else 0060 Q_EMIT finished( UnknownError ); 0061 } 0062 0063 void 0064 AsyncCDDBPLookup::slotConnectionSuccess() 0065 { 0066 qCDebug(LIBKCDDB) << "Connection successful"; 0067 state_ = WaitingForGreeting; 0068 } 0069 0070 void 0071 AsyncCDDBPLookup::slotReadyRead() 0072 { 0073 qCDebug(LIBKCDDB) << "Ready to read. State: " << stateToString(); 0074 0075 while ( Idle != state_ && isConnected() && socket_->canReadLine() ) 0076 read(); 0077 } 0078 0079 void 0080 AsyncCDDBPLookup::read() 0081 { 0082 switch ( state_ ) 0083 { 0084 case WaitingForGreeting: 0085 0086 if ( !parseGreeting( readLine() ) ) 0087 { 0088 result_ = ServerError; 0089 doQuit(); 0090 return; 0091 } 0092 0093 doHandshake(); 0094 0095 break; 0096 0097 case WaitingForHandshake: 0098 0099 if ( !parseHandshake( readLine() ) ) 0100 { 0101 result_ = ServerError; 0102 doQuit(); 0103 return; 0104 } 0105 0106 doProto(); 0107 0108 break; 0109 0110 case WaitingForProtoResponse: 0111 0112 // Ignore the response for now 0113 readLine(); 0114 0115 doQuery(); 0116 0117 break; 0118 0119 case WaitingForQueryResponse: 0120 result_ = parseQuery( readLine() ); 0121 0122 switch ( result_ ) 0123 { 0124 case Success: 0125 requestCDInfoForMatch(); 0126 break; 0127 0128 case MultipleRecordFound: 0129 state_ = WaitingForMoreMatches; 0130 break; 0131 0132 default: // Error :( 0133 doQuit(); 0134 return; 0135 } 0136 0137 break; 0138 0139 case WaitingForMoreMatches: 0140 { 0141 QString line = readLine(); 0142 0143 if (line.startsWith(QLatin1String( "." ))) 0144 requestCDInfoForMatch(); 0145 else 0146 parseExtraMatch( line ); 0147 } 0148 0149 break; 0150 0151 case WaitingForCDInfoResponse: 0152 { 0153 Result result = parseRead( readLine() ); 0154 0155 if ( Success != result ) 0156 { 0157 result_ = result; 0158 doQuit(); 0159 return; 0160 } 0161 0162 state_ = WaitingForCDInfoData; 0163 } 0164 0165 break; 0166 0167 case WaitingForCDInfoData: 0168 { 0169 QString line = readLine(); 0170 0171 if (line.startsWith(QLatin1String( "." ))) 0172 { 0173 parseCDInfoData(); 0174 requestCDInfoForMatch(); 0175 } 0176 else 0177 cdInfoBuffer_ << line; 0178 } 0179 0180 break; 0181 0182 case WaitingForQuitResponse: 0183 0184 state_ = Idle; 0185 0186 char c; 0187 while ( socket_->bytesAvailable() ) 0188 socket_->getChar(&c); 0189 0190 close(); 0191 0192 Q_EMIT finished( result_ ); 0193 0194 break; 0195 0196 default: 0197 0198 break; 0199 } 0200 } 0201 0202 QString 0203 AsyncCDDBPLookup::readLine() 0204 { 0205 return QString::fromUtf8(socket_->readLine()); 0206 } 0207 0208 void 0209 AsyncCDDBPLookup::doHandshake() 0210 { 0211 sendHandshake(); 0212 0213 state_ = WaitingForHandshake; 0214 } 0215 0216 void 0217 AsyncCDDBPLookup::doProto() 0218 { 0219 sendProto(); 0220 0221 state_ = WaitingForProtoResponse; 0222 } 0223 0224 void 0225 AsyncCDDBPLookup::doQuery() 0226 { 0227 sendQuery(); 0228 0229 state_ = WaitingForQueryResponse; 0230 } 0231 0232 void 0233 AsyncCDDBPLookup::requestCDInfoForMatch() 0234 { 0235 if (matchList_.isEmpty()) 0236 { 0237 result_ = cdInfoList_.isEmpty()? NoRecordFound : Success; 0238 doQuit(); 0239 return; 0240 } 0241 0242 CDDBMatch match = matchList_.takeFirst(); 0243 0244 sendRead( match ); 0245 0246 state_ = WaitingForCDInfoResponse; 0247 } 0248 0249 void 0250 AsyncCDDBPLookup::parseCDInfoData() 0251 { 0252 CDInfo info; 0253 0254 if (info.load( cdInfoBuffer_ )) 0255 { 0256 info.set( QLatin1String( "category" ), category_ ); 0257 info.set( QLatin1String( "discid" ), discid_ ); 0258 info.set( QLatin1String( "source" ), QLatin1String( "freedb" ) ); 0259 cdInfoList_.append( info ); 0260 } 0261 0262 cdInfoBuffer_.clear(); 0263 } 0264 0265 void 0266 AsyncCDDBPLookup::doQuit() 0267 { 0268 state_ = WaitingForQuitResponse; 0269 0270 sendQuit(); 0271 } 0272 0273 QString 0274 AsyncCDDBPLookup::stateToString() const 0275 { 0276 switch (state_) 0277 { 0278 case Idle: 0279 return QLatin1String( "Idle" ); 0280 break; 0281 0282 case WaitingForConnection: 0283 return QLatin1String( "WaitingForConnection" ); 0284 break; 0285 0286 case WaitingForGreeting: 0287 return QLatin1String( "WaitingForGreeting" ); 0288 break; 0289 0290 case WaitingForProtoResponse: 0291 return QLatin1String( "WaitingForProtoResponse" ); 0292 break; 0293 0294 case WaitingForHandshake: 0295 return QLatin1String( "WaitingForHandshake" ); 0296 break; 0297 0298 case WaitingForQueryResponse: 0299 return QLatin1String( "WaitingForQueryResponse" ); 0300 break; 0301 0302 case WaitingForMoreMatches: 0303 return QLatin1String( "WaitingForMoreMatches" ); 0304 break; 0305 0306 case WaitingForCDInfoResponse: 0307 return QLatin1String( "WaitingForCDInfoResponse" ); 0308 break; 0309 0310 case WaitingForCDInfoData: 0311 return QLatin1String( "WaitingForCDInfoData" ); 0312 break; 0313 0314 case WaitingForQuitResponse: 0315 return QLatin1String( "WaitingForQuitResponse" ); 0316 break; 0317 0318 default: 0319 return QLatin1String( "Unknown" ); 0320 break; 0321 } 0322 } 0323 } 0324 0325 #include "moc_asynccddbplookup.cpp" 0326 0327 // vim:tabstop=2:shiftwidth=2:expandtab:cinoptions=(s,U1,m1