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

Last change on this file was 127, checked in by gyoung, 22 months ago

Changes to build pmcddb.exe with VAC 3.08. This builds but doesn't run no error returned

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