source: trunk/mediafolder/c/cddb/cddb.cpp@ 104

Last change on this file since 104 was 104, checked in by gyoung, 23 months ago

Remaining changes from merge with Lars 2.9 branch

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