source: branches/v2.9/mediafolder/c/cddb/cddbcls.cpp

Last change on this file was 2, checked in by stevenhl, 8 years ago

Import sources from cwmm-full.zip dated 2005-03-21

File size: 14.5 KB
Line 
1/*
2 * This file is (C) Chris Wohlgemuth 1999
3 */
4/*
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; see the file COPYING. If not, write to
17 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19
20#include <os2.h>
21#include <stdio.h> /* For stderr */
22#include <string.h>
23#include <io.h>
24#include <fcntl.h>
25#include <sys/types.h>
26#include <sys/socket.h>
27#include <netdb.h>
28#include <errno.h>
29#include <netinet/in.h>
30
31#include "cddb.h"
32#include "cddb.hh"
33
34#define CDDB_OK 0
35#define CDDB_MORE 1
36#define CDDB_ERROR -1
37
38#define verbose 1
39
40extern int h_errno;
41extern int errno;
42LONG extern CDDBDiscID(char * drive,CDDBINFO *cddbInfo);
43
44extern int port;
45extern char host[100];
46extern char username[100];
47extern char hostname[100];
48extern char clientname[100];
49extern char version[100];
50
51/* You may set this in another module to a valid handle
52 and the error text is written to this window (WinSetWindowText())
53 This isn't threadsafe so be sure about what you're doing!! */
54
55HWND hwndError=NULL;
56
57/*****************************************************/
58
59clsTrack::clsTrack(char * title,int trackNo)
60{
61 strncpy(trackname,title,sizeof(trackname));
62 iTrackNo=trackNo;
63 nextTrack=0;
64}
65/*****************************************************/
66
67
68
69
70/* If iFuz==0 then we have one exact match. If iFuz==1
71 we have one of n exact matches or a fuzzy match. */
72cddb::cddb(char * chrTitle,char *chrArtist, char *category, int iFuz=0)
73{
74 firstTrack=0;
75 nextCddb=0;
76 iFuzzy=iFuz;
77 strncpy(title,chrTitle,sizeof(title));
78 strncpy(artist,chrArtist,sizeof(artist));
79
80 return;
81}
82
83cddb::~cddb()
84{
85 clsTrack * tempTrack;
86
87 while(!firstTrack) {
88 tempTrack=firstTrack;
89 firstTrack=firstTrack->nextTrack;
90 delete(tempTrack);
91 }
92
93 if(nextCddb)delete nextCddb;
94
95 return;
96}
97
98/* Method to link different matches together */
99void cddb::linkCddb(cddb * Cddb)
100{
101 /* The new cddb goes to the end of the list */
102 if(nextCddb){
103 nextCddb->linkCddb(Cddb);
104 return;
105 }
106 nextCddb=Cddb;
107 return;
108}
109
110int cddb::newTrack(char * trackTitle, int trackNo)
111{
112 clsTrack * tempTrack;
113
114 tempTrack=new clsTrack(trackTitle, trackNo);
115 if(!tempTrack)return 1;
116 addTrack(tempTrack);
117 return 0;
118}
119
120void cddb::addTrack(clsTrack * track)
121{
122 clsTrack * tempTrack;
123
124 if(!firstTrack) {
125 firstTrack=track;
126 return;
127 }
128
129 tempTrack=firstTrack;
130 while(tempTrack->nextTrack) {
131 tempTrack=tempTrack->nextTrack;
132 }
133 tempTrack->nextTrack=track;
134 return;
135}
136
137clsTrack * cddb::cddbNextTrack(clsTrack * track)
138{
139 if(!track)return 0;
140 return track->nextTrack;
141}
142
143/**********************************************************/
144/* Some helper functions
145 */
146void printError(char* errorString)
147{
148 char buffer[CCHMAXPATH];
149 char *ptr;
150
151 strncpy(buffer, errorString, sizeof(buffer));
152 fprintf(stderr,"%s",errorString);
153 /* hwndError is global, so this isn't threadsafe */
154 if(hwndError) {
155 ptr=strchr(buffer,'\n');
156 if(ptr) {
157 *ptr=0;
158 }
159 WinSetWindowText(hwndError, buffer);
160 }
161}
162
163void printErrorCR(char* errorString)
164{
165 fprintf(stderr,"%s\n",errorString);
166}
167
168
169void printData(char* outString)
170{
171 int fileHandle;
172 int rc;
173
174 fileHandle=open("cddb.out",O_APPEND|O_TEXT|O_WRONLY);
175 if(fileHandle==-1) {
176 printError("Cannot open cddb.out");
177 return;
178 }
179 rc= write(fileHandle,outString,strlen(outString));
180 // write(fileHandle,"\n",sizeof("\n"));
181 close(fileHandle);
182 return;
183}
184
185
186/**********************************************************/
187/* CDDB Stuff */
188
189int readResponse(int s, char * buffer,int size)
190{
191 int a;
192 int rc;
193
194 rc=1;
195 for(a=0;a<size&&rc>0;a++) {
196 rc=read(s,&buffer[a],1);
197 if(buffer[a]=='\n') {
198 buffer[a]=0;
199 return CDDB_MORE;
200 }
201 if(rc==-1)
202 return CDDB_ERROR;
203 }
204
205 return CDDB_ERROR;
206}
207
208/* Returns the cddb code. */
209int get_cddb_code( char * chrResponse)
210{
211 return atoi(chrResponse);
212}
213
214/* Check error codes coming from the server*/
215int check_cddb_code(char * chrResponse)
216{
217 switch (chrResponse[0])
218 {
219 case '2': return CDDB_OK;
220 case '3': return CDDB_MORE;
221 case '4':
222 printError("CDDB server error");
223 return CDDB_ERROR;
224 case '5':
225 printError("CDDB client error");
226 return CDDB_ERROR;
227 default:
228 printError("Unknown error");
229 break;
230 }
231 return CDDB_ERROR;
232}
233
234/* Performing the handshake procedure with the CDDB server */
235/* s: socket handle */
236int cddb_handshaking(int s)
237{
238 char buffer[512];
239 int rc;
240
241 /* Handshaking */
242 if(verbose)
243 printError("Handshaking... ");
244 sprintf(buffer,"cddb hello %s %s %s %s\n",username,hostname,clientname,version);
245 rc=write(s,buffer,strlen(buffer));
246 if(rc==-1) {
247 printError("Handshaking: cannot write to CDDB server");
248 return -1;
249 }
250 if(verbose)
251 printError("done\n");
252 if(verbose==2)
253 printError("Response: ");
254
255 rc=readResponse(s,buffer,sizeof(buffer));
256 if(rc==CDDB_ERROR) {
257 printError("Handshaking: cannot get response");
258 return -1;
259 }
260 if(verbose==2)
261 printErrorCR(buffer);
262
263 if(check_cddb_code(buffer)==CDDB_ERROR)
264 return -1;
265
266 return 0;
267}
268
269/* s: socket handle */
270int cddb_setting_proto(int s)
271{
272 char buffer[512];
273 int rc;
274 int iProtLevel;
275
276 iProtLevel=4;/* Startlevel */
277 /* Setting protocol level */
278 do {
279 if(verbose)
280 printError("\nSetting protocol level... ");
281 sprintf(buffer,"proto %d\n",iProtLevel);
282 printError(buffer);
283 rc=write(s,buffer,strlen(buffer));
284 if(rc==-1) {
285 printError("Protocol: cannot write to CDDB server");
286 return -1;
287 }
288 if(verbose)
289 printError("done\n");
290 if(verbose==2)
291 printError("Response: ");
292
293 rc=readResponse(s,buffer,sizeof(buffer));
294 if(rc==CDDB_ERROR) {
295 printError("Set protocol: cannot get response");
296 return -1;
297 }
298 if(verbose==2)
299 printErrorCR(buffer);
300
301 /* Check cddb code */
302 if(check_cddb_code(buffer)==CDDB_ERROR) {
303 if(get_cddb_code(buffer)!=501)
304 return -1;/* Unknown error */
305 }
306 else
307 break;
308 iProtLevel--;
309 }while(iProtLevel>0);
310
311 return 0;
312}
313
314/* This is called if the CDDB database has got several matches for our
315 discid. We take all matches and decide later, which to use. */
316cddb * query_get_all_matches(int s)
317{
318 cddb * root=0;
319 cddb * Cddb=0;
320 int rc;
321 char buffer[512];
322
323 do {
324 rc=readResponse(s,buffer,sizeof(buffer)); /* Get next line */
325
326 if(rc==CDDB_ERROR)
327 return root; /* return what we have so far */
328
329 if(buffer[0]=='.') /* End of data */
330 return root; /* return what we have */
331
332 /* A new cddb instance for every match */
333 Cddb=new cddb("","","",1); /* One fuzzy match or one of several matches */
334 /* Get the data for this match */
335 sscanf(buffer, " %20s %x %100[^/\r\n] / %100[^\r\n]", Cddb->category,&Cddb->discid,Cddb->artist,Cddb->title);
336 /* Link the cddb instance into the list */
337 if(!root)
338 root=Cddb;
339 else
340 root->linkCddb(Cddb);
341
342 }while(true);
343
344}
345
346/* Query some data */
347/* With the data given we later query the
348 tracknames */
349cddb * cddb_query(int s, CDDBINFO *cddbInfo)
350{
351 char buffer[512]={0};
352 char track[20];
353 char title[100];
354 char artist[100];
355 char categ[20];
356 int rc;
357 int code;
358 int a;
359 cddb * Cddb;
360 cddb * Cddb2;
361 char * chrPtr;
362
363 /* Sending query */
364 if(verbose)
365 printError("Sending query cmd... ");
366 /* Build cmd-line */
367 sprintf(buffer,"cddb query %08x %d",cddbInfo->discid,cddbInfo->numTracks);
368 for(a=0;a<cddbInfo->numTracks;a++) {
369 sprintf(track," %d",cddbInfo->startSector[a]);
370 strcat(buffer,track);
371 }
372 sprintf(track," %d\n",cddbInfo->discLength);
373 strcat(buffer,track);
374 if(verbose==2)
375 printErrorCR(buffer);
376 rc=write(s,buffer,strlen(buffer));
377 if(rc==-1) {
378 printError("Query: cannot write to CDDB server");
379 return 0;
380 }
381 if(verbose)
382 printError(" done\n");
383 if(verbose==2)
384 printError("Response: ");
385
386 rc=readResponse(s,buffer,sizeof(buffer));
387 //rc=read(s,buffer,sizeof(buffer)-1);
388 if(rc==CDDB_ERROR) {
389 printError("Query: cannot get response");
390 return 0;
391 }
392 if(verbose==2) {
393 printErrorCR(buffer);
394 }
395 if(check_cddb_code(buffer)==CDDB_ERROR)
396 return 0;
397 code=get_cddb_code(buffer);
398
399 /* Check output */
400 switch(code)
401 {
402 case 200: /* exact match */
403 Cddb=new cddb("","","");
404 /*sscanf(buffer+4, "%20s %x %100[^ ] / %100[^\r\n]", Cddb->category,&Cddb->discid,Cddb->artist,Cddb->title);
405 */
406 sscanf(buffer+4, "%20s %x %100[^/\r\n] / %100[^\r\n]", Cddb->category,&Cddb->discid,Cddb->artist,Cddb->title);
407 /* printData(buffer);
408 printData(buffer+4); */
409 return Cddb;
410 break;
411 case 210: /* several exact matches */
412 case 211: /* several inexact matches */
413 return query_get_all_matches(s); /* if there's an error this call returns 0 */
414 break;
415 case 202:
416 default:
417 /* We shouldn't reach this */
418 return 0;
419 }
420 /* We shouldn't reach this */
421 return 0;
422}
423
424/* Reads the CDDB banner from the server after connecting */
425/* We don't really need it so it is only shown on stderr */
426int cddb_banner(int s)
427{
428 char buffer[512];
429 int rc;
430
431 /* Get CDDB-Banner */
432 if(verbose)
433 printErrorCR("Querying CDDB-Banner...");
434 rc=readResponse(s,buffer,sizeof(buffer));
435 if(rc==CDDB_ERROR) {
436 printError("Cannot read CDDB-Banner");
437 return -1;
438 }
439 if(verbose==2)
440 printErrorCR(buffer);
441
442 if(check_cddb_code(buffer)==CDDB_ERROR)
443 return -1;
444 return 0;
445}
446
447/* Ask for the information about our CD. Parse it and
448 save it in the data file. */
449int read_and_parse(int s,cddb * Cddb)
450{
451 int rc;
452 char buffer[512];
453 char key[20];
454 char trackName[100];
455 int iTrack;
456
457 do{
458 rc=readResponse(s,buffer,sizeof(buffer));
459 if(rc==CDDB_ERROR) {
460 printError("Read request: cannot get response");
461 return CDDB_ERROR;
462 }
463 /* Print the data to the outfile */
464 printData(buffer);
465 if(buffer[0]=='#') /* This is a comment */
466 { }
467 // printf("Found Comment: %s\n",buffer);
468 else{
469 if(buffer[0]=='.') /* End of data */
470 return CDDB_OK; /* Done */
471 //printf("Found data: %s\n",buffer);
472 sscanf(buffer,"%20[^0-9=]",key);
473 /* We put track names into a linked list in the cddb instance */
474 if(!strcmp(strupr(key),"TTITLE")) {
475 iTrack=0;
476 /* We have a disc title */
477 sscanf(buffer,"%20[^0-9]%d=%100[^\n\r]",key,iTrack,trackName);
478 Cddb->newTrack(trackName,iTrack); /* New track entry in cddb instance */
479 }
480 }
481 }while(rc==CDDB_MORE);
482
483}
484
485cddb_read(int s,cddb * Cddb)
486{
487 char buffer[512];
488 int rc;
489
490 /* Sending read */
491
492 /* Build cmd-line */
493 sprintf(buffer,"cddb read %s %08x\n",Cddb->category,Cddb->discid);
494 if(verbose)
495 printError("\nSending read cmd... ");
496 if(verbose==2)
497 printError(buffer);
498
499 rc=write(s,buffer,strlen(buffer));
500 if(rc==-1) {
501 printError("Read request: cannot write to CDDB server");
502 return -1;
503 }
504 if(verbose)
505 printError("done\n");
506 if(verbose==2)
507 printError("Response: ");
508
509 rc=readResponse(s,buffer,sizeof(buffer));
510 if(rc==CDDB_ERROR) {
511 printError("Read request: cannot get response");
512 return -1;
513 }
514 if(verbose==2)
515 printError(buffer);
516 if(check_cddb_code(buffer)==CDDB_ERROR)
517 return CDDB_ERROR;
518
519 /* Get the data */
520 read_and_parse(s,Cddb);
521 return CDDB_OK;
522}
523
524/****************************************************/
525
526
527int cddbConnectToHost(int * skt) {
528
529 struct hostent *he;
530 struct sockaddr_in sa_in;
531 char buffer[512];
532 int s;
533
534 /* Creating socket */
535 if(verbose)
536 printError("Creating socket... ");
537 s=socket(AF_INET,SOCK_STREAM,0);
538 if(s==-1) {
539 printError("Cannot create socket!");
540 return -1;
541 }
542 *skt=s;
543 if(verbose)
544 printError("Socket created\n");
545
546 /* Querying host */
547 if(verbose)
548 printError("Querying host... ");
549 he = gethostbyname(host);
550 if(he==NULL) {
551 printError("Cannot get host address.\ngethostbyname() returned error: ");
552 switch (h_errno)
553 {
554 case HOST_NOT_FOUND:
555 printError("Host not found\n");
556 break;
557 case TRY_AGAIN:
558 printError("Temporary error. Try again later.\n");
559 break;
560 case NO_DATA:
561 printError("Name valid but name server has no associated address.\n");
562 break;
563 case NO_RECOVERY:
564 printError("Unrecoverable error.\n");
565 break;
566 default:
567 printError("Unknown error\n");
568 }
569 /* Close the socket */
570 close(s);
571 return -1;
572 }
573
574 if(verbose)
575 printError("Host found.\n");
576
577
578 /* Connecting to host */
579 if(verbose)
580 printError("Connecting to host... ");
581 memset(&sa_in,0, sizeof(struct sockaddr_in));
582
583 sa_in.sin_family=AF_INET;
584 sa_in.sin_port=htons((unsigned short)port);
585 memcpy(&sa_in.sin_addr, he->h_addr, he->h_length);
586
587 if(connect(s,(struct sockaddr*)&sa_in,sizeof(struct sockaddr_in))==-1) {
588 sprintf(buffer,"errno: %d\n",errno);
589 printError(buffer);
590 switch (errno)
591 {
592 case EBADF:
593 printError("No valid socket descriptor");
594 break;
595 case EISCONN:
596 printError("The socket is already connected\n");
597 break;
598 case ETIMEDOUT:
599 printError("No connection. Timed out.\n");
600 break;
601 case ECONNREFUSED:
602 printError("Connection refused by host.\n");
603 break;
604 case EADDRNOTAVAIL:
605 printError("Address not avaiable.\n");
606 break;
607
608 default:
609 printError("General failure: Cannot connect to host\n");
610 }
611 close(s);
612 return -1;
613 }
614 if(verbose)
615 printError("connected.\n");
616 return 0;
617}
618
619
620
Note: See TracBrowser for help on using the repository browser.