source: branches/v2.9/mediafolder/c/cddb/cddb.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: 16.0 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("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("CDDB server error");
240 return CDDB_ERROR;
241 case '5':
242 printError("CDDB client error");
243 return CDDB_ERROR;
244 default:
245 printError("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("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("Handshaking: cannot write to CDDB server");
267 return -1;
268 }
269 if(verbose)
270 printError("done\n");
271 if(verbose==2)
272 printError("Response: ");
273
274 rc=readResponse(s,buffer,sizeof(buffer));
275 if(rc==CDDB_ERROR) {
276 printError("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("\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("Protocol: cannot write to CDDB server");
305 return -1;
306 }
307 if(verbose)
308 printError("done\n");
309 if(verbose==2)
310 printError("Response: ");
311
312 rc=readResponse(s,buffer,sizeof(buffer));
313 if(rc==CDDB_ERROR) {
314 printError("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("","","",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("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("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("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("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("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("Query: cannot write to CDDB server");
418 return 0;
419 }
420 if(verbose)
421 printError(" done\n");
422 if(verbose==2)
423 printError("Response: ");
424
425 rc=readResponse(s,buffer,sizeof(buffer));
426 //rc=read(s,buffer,sizeof(buffer)-1);
427 if(rc==CDDB_ERROR) {
428 printError("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("","","");
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("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("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}
527
528cddb_read(int s,cddb * Cddb)
529{
530 char buffer[512];
531 int rc;
532
533 /* Sending read */
534
535 /* Build cmd-line */
536 sprintf(buffer,"cddb read %s %08x\n",Cddb->category,Cddb->discid);
537 if(verbose)
538 printError("\nSending read cmd... ");
539 if(verbose==2)
540 printError(buffer);
541
542 rc=write(s,buffer,strlen(buffer));
543 if(rc==-1) {
544 printError("Read request: cannot write to CDDB server");
545 return -1;
546 }
547 if(verbose)
548 printError("done\n");
549 if(verbose==2)
550 printError("Response: ");
551
552 rc=readResponse(s,buffer,sizeof(buffer));
553 if(rc==CDDB_ERROR) {
554 printError("Read request: cannot get response");
555 return -1;
556 }
557 if(verbose==2)
558 printError(buffer);
559 if(check_cddb_code(buffer)==CDDB_ERROR)
560 return CDDB_ERROR;
561
562 /* Get the data */
563 read_and_parse(s,Cddb);
564 return CDDB_OK;
565}
566
567/****************************************************/
568
569
570int cddbConnectToHost(int * skt) {
571
572 struct hostent *he;
573 struct sockaddr_in sa_in;
574 char buffer[512];
575 int s;
576
577 /* Creating socket */
578 if(verbose)
579 printError("Creating socket... ");
580 s=socket(AF_INET,SOCK_STREAM,0);
581 if(s==-1) {
582 printError("Cannot create socket!");
583 return -1;
584 }
585 *skt=s;
586 if(verbose)
587 printError("Socket created\n");
588
589 /* Querying host */
590 if(verbose)
591 printError("Querying host... ");
592 he = gethostbyname(host);
593 if(he==NULL) {
594 printError("Cannot get host address.\ngethostbyname() returned error: ");
595 switch (h_errno)
596 {
597 case HOST_NOT_FOUND:
598 printError("Host not found\n");
599 break;
600 case TRY_AGAIN:
601 printError("Temporary error. Try again later.\n");
602 break;
603 case NO_DATA:
604 printError("Name valid but name server has no associated address.\n");
605 break;
606 case NO_RECOVERY:
607 printError("Unrecoverable error.\n");
608 break;
609 default:
610 printError("Unknown error\n");
611 }
612 /* Close the socket */
613 close(s);
614 return -1;
615 }
616
617 if(verbose)
618 printError("Host found.\n");
619
620
621 /* Connecting to host */
622 if(verbose)
623 printError("Connecting to host... ");
624 memset(&sa_in,0, sizeof(struct sockaddr_in));
625
626 sa_in.sin_family=AF_INET;
627 sa_in.sin_port=htons((unsigned short)port);
628 memcpy(&sa_in.sin_addr, he->h_addr, he->h_length);
629
630 if(connect(s,(struct sockaddr*)&sa_in,sizeof(struct sockaddr_in))==-1) {
631 sprintf(buffer,"errno: %d\n",errno);
632 printError(buffer);
633 switch (errno)
634 {
635 case EBADF:
636 printError("No valid socket descriptor");
637 break;
638 case EISCONN:
639 printError("The socket is already connected\n");
640 break;
641 case ETIMEDOUT:
642 printError("No connection. Timed out.\n");
643 break;
644 case ECONNREFUSED:
645 printError("Connection refused by host.\n");
646 break;
647 case EADDRNOTAVAIL:
648 printError("Address not avaiable.\n");
649 break;
650
651 default:
652 printError("General failure: Cannot connect to host\n");
653 }
654 close(s);
655 return -1;
656 }
657 if(verbose)
658 printError("connected.\n");
659 return 0;
660}
661
662
663
664
665
666
667
668
669
670
671
Note: See TracBrowser for help on using the repository browser.