00001 #include <freedb/freedb.hxx>
00002
00005 FreedbRemote::FreedbRemote(string servername = "freedb.freedb.org")
00006 : _sockfd(-1)
00007 {
00008 connect(servername);
00009 }
00010
00015 FreedbRemote::~FreedbRemote()
00016 {
00017 disconnect();
00018 }
00019
00028 void FreedbRemote::sendCommand(string command) const
00029 {
00030 command += "\n";
00031 int retval = send(_sockfd, command.data(), command.length(), 0);
00032 }
00033
00048 string FreedbRemote::getResponseLine(bool stripcr = true) const
00049 {
00050 string response;
00051 char buf;
00052 int retval;
00053
00054 while (buf != '\n')
00055 {
00056 retval = recv(_sockfd, (void *)&buf, 1, 0);
00057
00058 if (buf != '\r' || stripcr == false)
00059 {
00060 response += buf;
00061 }
00062 }
00063
00064 return(response);
00065 }
00066
00086 void FreedbRemote::connect(string servername = "freedb.freedb.org")
00087 {
00088 struct sockaddr_in saddr;
00089 struct hostent* dns;
00090 int addrlen = sizeof(struct sockaddr);
00091
00092 _sockfd = socket(PF_INET, SOCK_STREAM, 0);
00093
00094 if (_sockfd == (-1))
00095 {
00096 Error err;
00097
00098 err.errcode = errno;
00099 err.errmsg = strerror(errno);
00100
00101 throw err;
00102 }
00103
00104 dns = gethostbyname(servername.c_str());
00105
00106 if (dns == NULL)
00107 {
00108 Error err;
00109
00110 switch (h_errno)
00111 {
00112 case HOST_NOT_FOUND:
00113 err.errmsg = "Host not found";
00114 break;
00115
00116 case NO_ADDRESS:
00117 err.errmsg = "Host has no IP-Adress";
00118 break;
00119
00120 case NO_RECOVERY:
00121 err.errmsg = "Permanent DNS server error";
00122 break;
00123
00124 case TRY_AGAIN:
00125 err.errmsg = "Temporary DNS server error";
00126 break;
00127
00128 default:
00129 err.errmsg = "Unknown error";
00130 }
00131
00132 throw err;
00133 }
00134
00135 saddr.sin_family = AF_INET;
00136 saddr.sin_port = htons(CDDBP_PORT);
00137 saddr.sin_addr = *((struct in_addr *)dns->h_addr_list[0]);
00138
00139
00140 int retval = ::connect(_sockfd, (struct sockaddr *)&saddr, addrlen);
00141 if (retval == (-1))
00142 {
00143
00144 Error err;
00145
00146 err.errcode = errno;
00147 err.errmsg = strerror(errno);
00148
00149 throw err;
00150 }
00151
00152
00153
00154 string response = getResponseLine();
00155
00156 if (response.substr(0, 2) != "20")
00157 {
00158 Error err;
00159 err.errcode = stoi(response.substr(0, 3));
00160
00161 switch (err.errcode)
00162 {
00163 case 432:
00164 err.errmsg = "Permission denied";
00165 break;
00166
00167 case 433:
00168 err.errmsg = "Too many users";
00169 break;
00170
00171 case 434:
00172 err.errmsg = "System load too high";
00173 break;
00174
00175 default:
00176 err.errmsg = "Unknown error";
00177 }
00178
00179 err.extinfo = response;
00180
00181 throw err;
00182 }
00183
00184 cout << response;
00185
00186 _greeting = response;
00187 }
00188
00191 void FreedbRemote::disconnect()
00192 {
00193 if (_sockfd != -1)
00194 {
00195 sendCommand("quit");
00196
00197 int retval = close(_sockfd);
00198 if (retval == (-1))
00199 {
00200 Error err;
00201 err.errcode = errno;
00202 err.errmsg = strerror(errno);
00203 throw err;
00204 }
00205 }
00206 }
00207
00220 void FreedbRemote::doHandshake(string username, string clientname, string version) const
00221 {
00222 char* hn = new char[256];
00223 int retval = gethostname(hn, 256);
00224 if (retval == (-1))
00225 {
00226 Error err;
00227 err.errcode = errno;
00228 err.errmsg = strerror(errno);
00229 throw err;
00230 }
00231
00232
00233 string hostname = hn;
00234 string handshake = "cddb hello " + username + " " + hostname + " " + clientname + " " + version;
00235
00236 sendCommand(handshake);
00237
00238
00239 string response = getResponseLine();
00240
00241 if (response.substr(0, 2) != "20")
00242 {
00243 Error err;
00244 err.errcode = stoi(response.substr(0, 3));
00245
00246 switch (err.errcode)
00247 {
00248 case 431:
00249 err.errmsg = "Handshake not successful";
00250 break;
00251
00252 case 402:
00253 err.errmsg = "Already shook hands";
00254 break;
00255
00256 default:
00257 err.errmsg = "Unknown error";
00258 }
00259
00260 err.extinfo = response;
00261
00262 throw err;
00263 }
00264 }
00265
00266 ServerInfo FreedbRemote::parseServerInfoLine(string line)
00267 {
00268 ServerInfo info;
00269 int lastpos = 0, currentpos;
00270
00271 if (line[0] == '\n')
00272 {
00273 line = line.substr(1, line.length() - 1);
00274 }
00275
00276
00277 currentpos = line.find(" ", lastpos);
00278 info.site = line.substr(lastpos, currentpos);
00279 lastpos = currentpos + 1;
00280
00281
00282 currentpos = line.find(" ", lastpos);
00283 info.port = stoi(line.substr(lastpos, currentpos));
00284 lastpos = currentpos + 1 ;
00285
00286
00287 currentpos = line.find(" ", lastpos);
00288 string latitude = line.substr(lastpos, currentpos);
00289 lastpos = currentpos + 1 ;
00290 info.latitude.compassdirection = latitude.substr(0, 1);
00291 info.latitude.degrees = stoi(latitude.substr(1, 3));
00292 info.latitude.minutes = stoi(latitude.substr(5, 2));
00293
00294
00295 currentpos = line.find(" ", lastpos);
00296 string longitude = line.substr(lastpos, currentpos);
00297 lastpos = currentpos + 1 ;
00298 info.longitude.compassdirection = longitude.substr(0, 1);
00299 info.longitude.degrees = stoi(longitude.substr(1, 3));
00300 info.longitude.minutes = stoi(longitude.substr(5, 2));
00301
00302
00303 info.description = line.substr(lastpos, line.length() - lastpos);
00304
00305 return(info);
00306 }
00307
00308
00309 vector<ServerInfo> FreedbRemote::getServerList() const
00310 {
00311 vector<ServerInfo> servers;
00312
00313 sendCommand("sites");
00314
00315 string response = getResponseLine();
00316
00317 if (response.substr(0, 1) != "2")
00318 {
00319 Error err;
00320 err.errcode = stoi(response.substr(0, 3));
00321
00322 switch (err.errcode)
00323 {
00324 case 401:
00325 err.errmsg = "No site information available";
00326 break;
00327
00328 default:
00329 err.errmsg = "Unknown error";
00330 }
00331
00332 err.extinfo = response;
00333
00334 throw err;
00335 }
00336
00337 char buf;
00338 bool newline = false;
00339 int lines = 0, retval;
00340
00341 response = "";
00342
00343 while (1)
00344 {
00345 retval = recv(_sockfd, (void *)&buf, 1, 0);
00346
00347 if (buf == '.' && newline == true)
00348 {
00349 break;
00350 }
00351
00352 if (buf == '\n')
00353 {
00354 newline = true;
00355 lines++;
00356
00357 servers.push_back(parseServerInfoLine(response));
00358
00359 response = "";
00360 }
00361 else
00362 {
00363 newline = false;
00364 }
00365
00366 if (buf != '\r')
00367 {
00368 response += buf;
00369 }
00370 }
00371
00372 return(servers);
00373 }
00374
00375
00376 vector<string> FreedbRemote::getCategories() const
00377 {
00378 vector<string> categories;
00379
00380 sendCommand("lscat");
00381
00382 string response = getResponseLine();
00383
00384 if (response.substr(0, 3) != "210")
00385 {
00386 Error err;
00387 err.errcode = stoi(response.substr(0, 3));
00388
00389 switch (err.errcode)
00390 {
00391 default:
00392 err.errmsg = "Unknown error";
00393 }
00394
00395 err.extinfo = response;
00396
00397 throw err;
00398 }
00399
00400 char buf;
00401 bool newline = false;
00402 int lines = 0, retval;
00403
00404 response = "";
00405
00406 while (1)
00407 {
00408 retval = recv(_sockfd, (void *)&buf, 1, 0);
00409
00410 if (buf == '.' && newline == true)
00411 {
00412 break;
00413 }
00414
00415 if (buf == '\n')
00416 {
00417 newline = true;
00418 lines++;
00419
00420 categories.push_back(response);
00421
00422 response = "";
00423 }
00424 else
00425 {
00426 newline = false;
00427 }
00428
00429 if (buf != '\r')
00430 {
00431 response += buf;
00432 }
00433 }
00434
00435 return(categories);
00436 }
00437
00438
00439 vector<SearchResult> FreedbRemote::search() const
00440 {
00441 }