wmmisc: Bump to version 1.2.
[dockapps.git] / ascd / libworkman / cddb.c
blob6351607133734796dbc6deada6440f30ca3d24b9
1 /*
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 $";
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <strings.h>
37 #include <unistd.h>
38 #include <sys/types.h>
39 #include <sys/stat.h>
40 #include <sys/signal.h>
41 #include <ctype.h>
42 #include <sys/time.h>
43 #include <sys/socket.h>
44 #include <netinet/in.h>
45 #include <netdb.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
58 struct wm_cddb cddb;
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;
66 int Socket;
67 FILE *Connection;
72 void
73 cddb_cur2struct(void)
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() */
85 void
86 cddb_struct2cur(void)
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
99 int
100 cddb_sum(int n)
102 char buf[12],
104 int ret = 0;
106 /* For backward compatibility this algorithm must not change */
107 sprintf(buf, "%lu", (unsigned long)n);
108 for (p = buf; *p != '\0'; p++)
109 ret += (*p - '0');
111 return (ret);
112 } /* cddb_sum() */
116 * Calculate the discid of a CD according to cddb
118 unsigned long
119 cddb_discid(void)
121 int i,
123 n = 0;
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
151 * the delimiter.
153 char *
154 string_split(char *line, char delim)
156 char *p1;
158 for (p1=line;*p1;p1++)
160 if(*p1 == delim)
162 *p1 = 0;
163 return ++p1;
166 return (NULL);
167 } /* string_split() */
170 * Generate the hello string according to the cddb protocol
171 * delimiter is either ' ' (cddbp) or '+' (http)
173 void
174 string_makehello(char *line,char delim)
176 char mail[84],*host;
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 == ' ' ? ' ' : '=',
184 mail,delim,
185 host,delim,
186 PROGRAM,delim,
187 VERSION);
188 } /* string_makehello() */
191 * Open the TCP connection to the cddb/proxy server
194 connect_open(void)
196 char *host;
197 struct hostent *hp;
198 struct sockaddr_in soc_in;
199 int port;
201 if(cddb.protocol == 3) /* http proxy */
202 host = strdup(cddb.proxy_server);
203 else
204 host = strdup(cddb.cddb_server);
206 * t=string_split(host,':');
208 port=atoi(string_split(host,':'));
209 if(!port)
210 port=8880;
212 printf("%s:%d\n",host,port);
213 hp =gethostbyname(host);
215 if (hp == NULL)
217 static struct hostent def;
218 static struct in_addr defaddr;
219 static char *alist[1];
220 static char namebuf[128];
221 int inet_addr();
223 defaddr.s_addr = inet_addr(host);
224 if (defaddr.s_addr == -1)
226 printf("unknown host: %s\n", host);
227 return (-1);
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;
234 def.h_aliases = 0;
235 hp = &def;
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);
241 if (Socket < 0)
243 perror("socket");
244 return (-1);
246 fflush(stdout);
247 if (connect(Socket, (struct sockaddr *)&soc_in, sizeof (soc_in)) < 0)
249 perror("connect");
250 close(Socket);
251 return (-1);
254 Connection = fdopen(Socket, "r");
255 return (0);
256 } /* connect_open() */
260 * Close the connection
262 void
263 connect_close(void)
265 (void)fclose(Connection);
266 close(Socket);
267 } /* connect_close() */
270 * Get a line from the connection with CR and LF stripped
272 void
273 connect_getline(char *line)
275 char c;
277 while ((c = getc(Connection)) != '\n')
279 *line = c;
280 if ((c != '\r') && (c != (char)0xff))
281 line++;
283 *line=0;
284 } /* connect_getline() */
287 * Read the CD data from the server and place them into the cd struct
289 void
290 connect_read_entry(void)
292 char type;
293 int trknr;
295 char *t,*t2,tempbuf[2000];
297 while(strcmp(tempbuf,"."))
299 connect_getline(tempbuf);
301 t=string_split(tempbuf,'=');
302 if(t != NULL)
304 type=tempbuf[0];
306 if(strncmp("TITLE",tempbuf+1,5))
307 continue;
309 if('D' == type)
312 * Annahme: "Interpret / Titel" ist falsch.
313 * Daher: NULL-String erwarten.
315 t2=string_split(t,'/');
316 if(t2 == NULL)
317 t2 = t;
318 if(*t2 == ' ')
319 t2++;
320 strcpy(cd->cdname,t2);
322 for(t2=t;*t2;t2++)
324 if((*t2 == ' ') && (*(t2+1) == 0))
325 *t2=0;
327 strcpy(cd->artist,t);
330 if('T' == type)
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
348 void
349 cddbp_send(char *line)
351 write(Socket, line, strlen(line));
352 write(Socket, "\n", 1);
353 } /* cddbp_send() */
356 * Send the "read from cddb" command to the server using cddbp
358 void
359 cddbp_read(char *category, unsigned int id)
361 char tempbuf[84];
362 sprintf(tempbuf, "cddb read %s %08x", category, id);
363 cddbp_send(tempbuf);
364 } /* cddbp_read() */
367 * Send a command to the server using http
369 void
370 http_send(char* line)
372 char tempbuf[2000];
374 write(Socket, "GET ", 4);
375 printf("GET ");
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,""));
394 } /* http_send() */
397 * Send the "read from cddb" command to the server using http
399 void
400 http_read(char *category, unsigned int id)
402 char tempbuf[84];
403 sprintf(tempbuf, "cddb+read+%s+%08x", category, id);
404 http_send(tempbuf);
405 } /* http_read() */
408 * The main routine called from the ui
410 void
411 cddb_request(void)
413 int i;
414 char tempbuf[2000];
415 extern int cur_ntracks;
417 int status;
418 char category[20];
419 unsigned int id;
421 strcpy(cddb.cddb_server,"localhost:888");
422 strcpy(cddb.mail_adress,"svolli@bigfoot.com");
424 * cddb.protocol = 1;
426 wipe_cdinfo();
428 switch(cddb.protocol)
430 case 1: /* cddbp */
431 printf("USING CDDBP\n");
432 printf("open\n");
433 connect_open();
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);
445 cddbp_send(tempbuf);
446 connect_getline(tempbuf);
447 printf("[%s]\n",tempbuf);
449 printf("query\n");
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);
457 cddbp_send(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();
485 cddbp_send("quit");
486 connect_close();
487 printf("close\n");
488 break;
489 case 2: /* http */
490 case 3: /* http proxy */
491 printf("USING HTTP%s\n",
492 (cddb.protocol == 3) ? " WITH PROXY" : "");
493 printf("query\n");
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);
501 connect_open();
502 http_send(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 */
515 connect_close();
516 connect_open();
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);
529 connect_close();
530 connect_open();
531 http_read(category,id);
532 connect_read_entry();
534 /* moved close above break */
535 connect_close();
536 break;
537 default: /* off */
538 break;
540 } /* cddb_request() */