2 * $Id: cddb.c,v 1.2 1999/02/14 09:50:42 dirk Exp $
4 * This file is part of WorkMan, the civilized CD player library
5 * (c) 1991-1997 by Steven Grimm (original author)
6 * (c) by Dirk Försterling (current 'author' = maintainer)
7 * The maintainer can be contacted by his e-mail address:
8 * milliByte@DeathsDoor.com
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Library General Public
12 * License as published by the Free Software Foundation; either
13 * version 2 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Library General Public License for more details.
20 * You should have received a copy of the GNU Library General Public
21 * License along with this library; if not, write to the Free
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 * establish connection to cddb server and get data
26 * socket stuff gotten from gnu port of the finger command
28 * provided by Sven Oliver Moll
32 static char cddb_id
[] = "$Id: cddb.c,v 1.2 1999/02/14 09:50:42 dirk Exp $";
38 #include <sys/types.h>
40 #include <sys/signal.h>
43 #include <sys/socket.h>
44 #include <netinet/in.h>
47 #include "include/wm_config.h"
48 #include "include/wm_struct.h"
49 #include "include/wm_cdinfo.h"
50 #include "include/wm_helpers.h"
53 * This is for identifying WorkMan at CDDB servers
55 #define PROGRAM WORKMAN_NAME
56 #define VERSION WORKMAN_VERSION
60 int cur_cddb_protocol
;
61 char *cur_cddb_server
;
62 char *cur_cddb_mail_adress
;
63 char *cur_cddb_path_to_cgi
;
64 char *cur_cddb_proxy_server
;
75 cddb
.protocol
= cur_cddb_protocol
;
76 strcpy(cddb
.cddb_server
, cur_cddb_server
);
77 strcpy(cddb
.mail_adress
, cur_cddb_mail_adress
);
78 strcpy(cddb
.path_to_cgi
, cur_cddb_path_to_cgi
);
79 strcpy(cddb
.proxy_server
, cur_cddb_proxy_server
);
80 } /* cddb_cur2struct() */
88 cur_cddb_protocol
= cddb
.protocol
;
89 cur_cddb_server
= (cddb
.cddb_server
);
90 cur_cddb_mail_adress
= (cddb
.mail_adress
);
91 cur_cddb_path_to_cgi
= (cddb
.path_to_cgi
);
92 cur_cddb_proxy_server
= (cddb
.proxy_server
);
93 } /* cddb_struct2cur() */
97 * Subroutine from cddb_discid
106 /* For backward compatibility this algorithm must not change */
107 sprintf(buf
, "%lu", (unsigned long)n
);
108 for (p
= buf
; *p
!= '\0'; p
++)
116 * Calculate the discid of a CD according to cddb
125 /* For backward compatibility this algorithm must not change */
126 for (i
= 0; i
< thiscd
.ntracks
; i
++) {
128 n
+= cddb_sum(thiscd
.trk
[i
].start
/ 75);
130 * Just for demonstration (See below)
132 * t += (thiscd.trk[i+1].start / 75) -
133 * (thiscd.trk[i ].start / 75);
138 * Mathematics can be fun. Example: How to reduce a full loop to
139 * a simple statement. The discid algorhythm is so half-hearted
140 * developed that it doesn't even use the full 32bit range.
141 * But it seems to be always this way: The bad standards will be
142 * accepted, the good ones turned down.
145 t
= (thiscd
.trk
[thiscd
.ntracks
].start
-thiscd
.trk
[0].start
)/75;
146 return ((n
% 0xff) << 24 | t
<< 8 | thiscd
.ntracks
);
147 } /* cddb_discid() */
150 * Split a string into two components according to the first occurance of
154 string_split(char *line
, char delim
)
158 for (p1
=line
;*p1
;p1
++)
167 } /* string_split() */
170 * Generate the hello string according to the cddb protocol
171 * delimiter is either ' ' (cddbp) or '+' (http)
174 string_makehello(char *line
,char delim
)
178 strcpy(mail
,cddb
.mail_adress
);
179 host
=string_split(mail
,'@');
181 sprintf(line
,"%shello%c%s%c%s%c%s%c%s",
182 delim
== ' ' ? "cddb " : "&",
183 delim
== ' ' ? ' ' : '=',
188 } /* string_makehello() */
191 * Open the TCP connection to the cddb/proxy server
198 struct sockaddr_in soc_in
;
201 if(cddb
.protocol
== 3) /* http proxy */
202 host
= strdup(cddb
.proxy_server
);
204 host
= strdup(cddb
.cddb_server
);
206 * t=string_split(host,':');
208 port
=atoi(string_split(host
,':'));
212 printf("%s:%d\n",host
,port
);
213 hp
=gethostbyname(host
);
217 static struct hostent def
;
218 static struct in_addr defaddr
;
219 static char *alist
[1];
220 static char namebuf
[128];
223 defaddr
.s_addr
= inet_addr(host
);
224 if (defaddr
.s_addr
== -1)
226 printf("unknown host: %s\n", host
);
229 strcpy(namebuf
, host
);
230 def
.h_name
= namebuf
;
231 def
.h_addr_list
= alist
, def
.h_addr
= (char *)&defaddr
;
232 def
.h_length
= sizeof (struct in_addr
);
233 def
.h_addrtype
= AF_INET
;
237 soc_in
.sin_family
= hp
->h_addrtype
;
238 bcopy(hp
->h_addr
, (char *)&soc_in
.sin_addr
, hp
->h_length
);
239 soc_in
.sin_port
= htons(port
);
240 Socket
= socket(hp
->h_addrtype
, SOCK_STREAM
, 0);
247 if (connect(Socket
, (struct sockaddr
*)&soc_in
, sizeof (soc_in
)) < 0)
254 Connection
= fdopen(Socket
, "r");
256 } /* connect_open() */
260 * Close the connection
265 (void)fclose(Connection
);
267 } /* connect_close() */
270 * Get a line from the connection with CR and LF stripped
273 connect_getline(char *line
)
277 while ((c
= getc(Connection
)) != '\n')
280 if ((c
!= '\r') && (c
!= (char)0xff))
284 } /* connect_getline() */
287 * Read the CD data from the server and place them into the cd struct
290 connect_read_entry(void)
295 char *t
,*t2
,tempbuf
[2000];
297 while(strcmp(tempbuf
,"."))
299 connect_getline(tempbuf
);
301 t
=string_split(tempbuf
,'=');
306 if(strncmp("TITLE",tempbuf
+1,5))
312 * Annahme: "Interpret / Titel" ist falsch.
313 * Daher: NULL-String erwarten.
315 t2
=string_split(t
,'/');
320 strcpy(cd
->cdname
,t2
);
324 if((*t2
== ' ') && (*(t2
+1) == 0))
327 strcpy(cd
->artist
,t
);
332 trknr
=atoi(tempbuf
+6);
334 * printf("Track %d:%s\n",trknr,t);
336 wm_strmcpy(&cd
->trk
[trknr
].songname
,t
);
339 * fprintf(stderr, "%s %s\n",tempbuf,t);
343 } /* connect_read_entry() */
346 * Send a command to the server using cddbp
349 cddbp_send(char *line
)
351 write(Socket
, line
, strlen(line
));
352 write(Socket
, "\n", 1);
356 * Send the "read from cddb" command to the server using cddbp
359 cddbp_read(char *category
, unsigned int id
)
362 sprintf(tempbuf
, "cddb read %s %08x", category
, id
);
367 * Send a command to the server using http
370 http_send(char* line
)
374 write(Socket
, "GET ", 4);
376 if(cddb
.protocol
== 3)
378 write(Socket
, "http://", 7);
379 write(Socket
, cddb
.cddb_server
, strlen(cddb
.cddb_server
));
380 printf("http://%s",cddb
.cddb_server
);
382 write(Socket
, cddb
.path_to_cgi
, strlen(cddb
.path_to_cgi
));
383 write(Socket
, "?cmd=" ,5);
384 write(Socket
, line
, strlen(line
));
385 printf("%s?cmd=%s",cddb
.path_to_cgi
,line
);
386 string_makehello(tempbuf
,'+');
387 write(Socket
, tempbuf
, strlen(tempbuf
));
388 printf("%s",tempbuf
);
389 write(Socket
, "&proto=1 HTTP/1.0\n\n", 19);
390 printf("&proto=1 HTTP/1.0\n");
392 connect_getline(tempbuf
);
393 while(strcmp(tempbuf
,""));
397 * Send the "read from cddb" command to the server using http
400 http_read(char *category
, unsigned int id
)
403 sprintf(tempbuf
, "cddb+read+%s+%08x", category
, id
);
408 * The main routine called from the ui
415 extern int cur_ntracks
;
421 strcpy(cddb
.cddb_server
,"localhost:888");
422 strcpy(cddb
.mail_adress
,"svolli@bigfoot.com");
428 switch(cddb
.protocol
)
431 printf("USING CDDBP\n");
434 connect_getline(tempbuf
);
435 printf("[%s]\n",tempbuf
);
437 * if(atoi(tempbuf) == 201) return;
441 * strcpy(tempbuf,"cddb hello svolli bigfoot.com Eierkratzer eins");
443 string_makehello(tempbuf
,' ');
444 fprintf(stderr
, "%s\n", tempbuf
);
446 connect_getline(tempbuf
);
447 printf("[%s]\n",tempbuf
);
450 sprintf(tempbuf
, "cddb query %08x %d",thiscd
.cddbid
,thiscd
.ntracks
);
451 for (i
= 0; i
< cur_ntracks
; i
++)
452 if (thiscd
.trk
[i
].section
< 2)
453 sprintf(tempbuf
+ strlen(tempbuf
), " %d",
454 thiscd
.trk
[i
].start
);
455 sprintf(tempbuf
+ strlen(tempbuf
), " %d\n", thiscd
.length
);
456 printf(">%s<\n",tempbuf
);
458 connect_getline(tempbuf
);
459 printf("[%s]\n",tempbuf
);
461 status
=atoi(tempbuf
);
463 * fprintf(stderr, "status:%d\n",status);
464 * fprintf(stderr,"category:%s\n",category);
465 * fprintf(stderr,"id:%s\n",id);
467 if(status
== 200) /* Exact match */
469 sscanf(tempbuf
,"%d %s %08x",&status
,category
,&id
);
470 cddbp_read(category
,id
);
471 connect_read_entry();
474 if(status
== 211) /* Unexact match, multiple possible
475 * Hack: always use first. */
477 connect_getline(tempbuf
);
478 sscanf(tempbuf
,"%s %08x",category
,&id
);
479 while(strcmp(tempbuf
,"."))
480 connect_getline(tempbuf
);
481 cddbp_read(category
,id
);
482 connect_read_entry();
490 case 3: /* http proxy */
491 printf("USING HTTP%s\n",
492 (cddb
.protocol
== 3) ? " WITH PROXY" : "");
494 sprintf(tempbuf
, "cddb+query+%08x+%d",thiscd
.cddbid
,thiscd
.ntracks
);
495 for (i
= 0; i
< cur_ntracks
; i
++)
496 if (thiscd
.trk
[i
].section
< 2)
497 sprintf(tempbuf
+ strlen(tempbuf
), "+%d",
498 thiscd
.trk
[i
].start
);
499 sprintf(tempbuf
+ strlen(tempbuf
), "+%d", thiscd
.length
);
500 printf(">%s<\n",tempbuf
);
503 connect_getline(tempbuf
);
504 printf("[%s]\n",tempbuf
);
506 status
=atoi(tempbuf
);
508 * fprintf(stderr, "status:%d\n",status);
509 * fprintf(stderr, "category:%s\n",category);
510 * fprintf(stderr, "id:%s\n",id);
513 if(status
== 200) /* Exact match */
517 sscanf(tempbuf
,"%d %s %08x",&status
,category
,&id
);
518 http_read(category
,id
);
519 connect_read_entry();
522 if(status
== 211) /* Unexact match, multiple possible
523 * Hack: always use first. */
525 connect_getline(tempbuf
);
526 sscanf(tempbuf
,"%s %08x",category
,&id
);
527 while(strcmp(tempbuf
,"."))
528 connect_getline(tempbuf
);
531 http_read(category
,id
);
532 connect_read_entry();
534 /* moved close above break */
540 } /* cddb_request() */