summaryrefslogtreecommitdiffstats
path: root/kscd/libwm/cddb.c
diff options
context:
space:
mode:
Diffstat (limited to 'kscd/libwm/cddb.c')
-rw-r--r--kscd/libwm/cddb.c588
1 files changed, 588 insertions, 0 deletions
diff --git a/kscd/libwm/cddb.c b/kscd/libwm/cddb.c
new file mode 100644
index 00000000..657ab6a4
--- /dev/null
+++ b/kscd/libwm/cddb.c
@@ -0,0 +1,588 @@
+/*
+ * $Id$
+ *
+ * This file is part of WorkMan, the civilized CD player library
+ * (c) 1991-1997 by Steven Grimm (original author)
+ * (c) by Dirk Försterling (current 'author' = maintainer)
+ * The maintainer can be contacted by his e-mail address:
+ * milliByte@DeathsDoor.com
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ *
+ * establish connection to cddb server and get data
+ * socket stuff gotten from gnu port of the finger command
+ *
+ * provided by Sven Oliver Moll
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/signal.h>
+#include <ctype.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+
+#include "include/wm_config.h"
+#include "include/wm_struct.h"
+#include "include/wm_cdinfo.h"
+#include "include/wm_helpers.h"
+#include "include/wm_cddb.h"
+
+struct wm_cddb cddb;
+
+extern struct wm_cdinfo thiscd;
+static int cur_cddb_protocol;
+static char *cur_cddb_server;
+static char *cur_cddb_mail_adress;
+static char *cur_cddb_path_to_cgi;
+static char *cur_cddb_proxy_server;
+
+/* local prototypes */
+int cddb_sum(int);
+char *string_split(char *line, char delim);
+void string_makehello(char *line, char delim);
+int connect_open(void);
+void connect_close(void);
+void connect_getline(char *line);
+void connect_read_entry(void);
+void cddbp_send(const char *line);
+void cddbp_read(char *category, unsigned int id);
+void http_send(char* line);
+void http_read(char *category, unsigned int id);
+void cddb_request(void);
+/* local prototypes END */
+
+static int Socket;
+static FILE *Connection;
+
+/*
+ *
+ */
+void
+cddb_cur2struct(void)
+{
+ cddb.protocol = cur_cddb_protocol;
+ strcpy(cddb.cddb_server, cur_cddb_server);
+ strcpy(cddb.mail_adress, cur_cddb_mail_adress);
+ strcpy(cddb.path_to_cgi, cur_cddb_path_to_cgi);
+ strcpy(cddb.proxy_server, cur_cddb_proxy_server);
+} /* cddb_cur2struct() */
+
+/*
+ *
+ */
+void
+cddb_struct2cur(void)
+{
+ cur_cddb_protocol = cddb.protocol;
+ cur_cddb_server = (cddb.cddb_server);
+ cur_cddb_mail_adress = (cddb.mail_adress);
+ cur_cddb_path_to_cgi = (cddb.path_to_cgi);
+ cur_cddb_proxy_server = (cddb.proxy_server);
+} /* cddb_struct2cur() */
+
+
+/*
+ * Subroutine from cddb_discid
+ */
+int
+cddb_sum(int n)
+{
+ char buf[12],
+ *p;
+ int ret = 0;
+
+ /* For backward compatibility this algorithm must not change */
+ sprintf(buf, "%lu", (unsigned long)n);
+ for (p = buf; *p != '\0'; p++)
+ ret += (*p - '0');
+
+ return (ret);
+} /* cddb_sum() */
+
+
+/*
+ * Calculate the discid of a CD according to cddb
+ */
+unsigned long
+cddb_discid(void)
+{
+ int i,
+ t,
+ n = 0;
+
+ /* For backward compatibility this algorithm must not change */
+ for (i = 0; i < thiscd.ntracks; i++) {
+
+ n += cddb_sum(thiscd.trk[i].start / 75);
+ /*
+ * Just for demonstration (See below)
+ *
+ * t += (thiscd.trk[i+1].start / 75) -
+ * (thiscd.trk[i ].start / 75);
+ */
+ }
+
+ /*
+ * Mathematics can be fun. Example: How to reduce a full loop to
+ * a simple statement. The discid algorhythm is so half-hearted
+ * developed that it doesn't even use the full 32bit range.
+ * But it seems to be always this way: The bad standards will be
+ * accepted, the good ones turned down.
+ * Boy, you pulled out the /75. This is not correct here, because
+ * this calculation needs the integer division for both .start
+ * fields.
+ */
+
+ t = (thiscd.trk[thiscd.ntracks].start / 75)
+ - (thiscd.trk[0].start / 75);
+ return ((n % 0xff) << 24 | t << 8 | thiscd.ntracks);
+} /* cddb_discid() */
+
+/*
+ * Split a string into two components according to the first occurrence of
+ * the delimiter.
+ */
+char *
+string_split(char *line, char delim)
+{
+ char *p1;
+
+ for (p1=line;*p1;p1++)
+ {
+ if(*p1 == delim)
+ {
+ *p1 = 0;
+ return ++p1;
+ }
+ }
+ return (NULL);
+} /* string_split() */
+
+/*
+ * Generate the hello string according to the cddb protocol
+ * delimiter is either ' ' (cddbp) or '+' (http)
+ */
+void
+string_makehello(char *line,char delim)
+{
+ char mail[84],*host;
+
+ strcpy(mail,cddb.mail_adress);
+ host=string_split(mail,'@');
+
+ sprintf(line,"%shello%c%s%c%s%c%s%c%s",
+ delim == ' ' ? "cddb " : "&",
+ delim == ' ' ? ' ' : '=',
+ mail,delim,
+ host,delim,
+ WORKMAN_NAME,delim,
+ WORKMAN_VERSION);
+} /* string_makehello() */
+
+/*
+ * Open the TCP connection to the cddb/proxy server
+ */
+int
+connect_open(void)
+{
+ char *host;
+ struct hostent *hp;
+ struct sockaddr_in soc_in;
+ int port;
+
+ if(cddb.protocol == 3) /* http proxy */
+ host = wm_strdup(cddb.proxy_server);
+ else
+ host = wm_strdup(cddb.cddb_server);
+ /*
+ * t=string_split(host,':');
+ */
+ port=atoi(string_split(host,':'));
+ if(!port)
+ port=8880;
+
+#ifndef NDEBUG
+ printf("%s:%d\n",host,port);
+#endif
+ hp =gethostbyname(host);
+
+ if (hp == NULL)
+ {
+ static struct hostent def;
+ static struct in_addr defaddr;
+ static char *alist[1];
+ static char namebuf[128];
+ int inet_addr();
+
+ defaddr.s_addr = inet_addr(host);
+ if ((int) defaddr.s_addr == -1)
+ {
+#ifndef NDEBUG
+ printf("unknown host: %s\n", host);
+#endif
+ return (-1);
+ }
+ strcpy(namebuf, host);
+ def.h_name = namebuf;
+ def.h_addr_list = alist, def.h_addr = (char *)&defaddr;
+ def.h_length = sizeof (struct in_addr);
+ def.h_addrtype = AF_INET;
+ def.h_aliases = 0;
+ hp = &def;
+ }
+ soc_in.sin_family = hp->h_addrtype;
+ bcopy(hp->h_addr, (char *)&soc_in.sin_addr, hp->h_length);
+ soc_in.sin_port = htons(port);
+ Socket = socket(hp->h_addrtype, SOCK_STREAM, 0);
+ if (Socket < 0)
+ {
+ perror("socket");
+ return (-1);
+ }
+ fflush(stdout);
+ if (connect(Socket, (struct sockaddr *)&soc_in, sizeof (soc_in)) < 0)
+ {
+ perror("connect");
+ close(Socket);
+ return (-1);
+ }
+
+ Connection = fdopen(Socket, "r");
+ return (0);
+} /* connect_open() */
+
+
+/*
+ * Close the connection
+ */
+void
+connect_close(void)
+{
+ (void)fclose(Connection);
+ close(Socket);
+} /* connect_close() */
+
+/*
+ * Get a line from the connection with CR and LF stripped
+ */
+void
+connect_getline(char *line)
+{
+ char c;
+
+ while ((c = getc(Connection)) != '\n')
+ {
+ *line = c;
+ if ((c != '\r') && (c != (char)0xff))
+ line++;
+ }
+ *line=0;
+} /* connect_getline() */
+
+/*
+ * Read the CD data from the server and place them into the cd struct
+ */
+void
+connect_read_entry(void)
+{
+ char type;
+ int trknr;
+
+ char *t,*t2,tempbuf[2000];
+
+ while(strcmp(tempbuf,"."))
+ {
+ connect_getline(tempbuf);
+
+ t=string_split(tempbuf,'=');
+ if(t != NULL)
+ {
+ type=tempbuf[0];
+
+ if(strncmp("TITLE",tempbuf+1,5))
+ continue;
+
+ if('D' == type)
+ {
+ /*
+ * Annahme: "Interpret / Titel" ist falsch.
+ * Daher: NULL-String erwarten.
+ */
+ t2=string_split(t,'/');
+ if(t2 == NULL)
+ t2 = t;
+ if(*t2 == ' ')
+ t2++;
+ strncpy(cd->cdname,t2,sizeof(cd->cdname)-1);
+ cd->cdname[sizeof(cd->cdname)-1]='\0';
+
+ for(t2=t;*t2;t2++)
+ {
+ if((*t2 == ' ') && (*(t2+1) == 0))
+ *t2=0;
+ }
+ strncpy(cd->artist,t,sizeof(cd->artist)-1);
+ cd->artist[sizeof(cd->artist)-1]='\0';
+ }
+
+ if('T' == type)
+ {
+ trknr=atoi(tempbuf+6);
+ /*
+ * printf("Track %d:%s\n",trknr,t);
+ */
+ wm_strmcpy(&cd->trk[trknr].songname,t);
+ }
+ /*
+ * fprintf(stderr, "%s %s\n",tempbuf,t);
+ */
+ }
+ }
+} /* connect_read_entry() */
+
+/*
+ * Send a command to the server using cddbp
+ */
+void
+cddbp_send(const char *line)
+{
+ write(Socket, line, strlen(line));
+ write(Socket, "\n", 1);
+} /* cddbp_send() */
+
+/*
+ * Send the "read from cddb" command to the server using cddbp
+ */
+void
+cddbp_read(char *category, unsigned int id)
+{
+ char tempbuf[84];
+ sprintf(tempbuf, "cddb read %s %08x", category, id);
+ cddbp_send(tempbuf);
+} /* cddbp_read() */
+
+/*
+ * Send a command to the server using http
+ */
+void
+http_send(char* line)
+{
+ char tempbuf[2000];
+
+ write(Socket, "GET ", 4);
+#ifndef NDEBUG
+ printf("GET ");
+#endif
+ if(cddb.protocol == 3)
+ {
+ write(Socket, "http://", 7);
+ write(Socket, cddb.cddb_server, strlen(cddb.cddb_server));
+#ifndef NDEBUG
+ printf("http://%s",cddb.cddb_server);
+#endif
+ }
+ write(Socket, cddb.path_to_cgi, strlen(cddb.path_to_cgi));
+ write(Socket, "?cmd=" ,5);
+ write(Socket, line, strlen(line));
+#ifndef NDEBUG
+ printf("%s?cmd=%s",cddb.path_to_cgi,line);
+#endif
+ string_makehello(tempbuf,'+');
+ write(Socket, tempbuf, strlen(tempbuf));
+#ifndef NDEBUG
+ printf("%s",tempbuf);
+#endif
+ write(Socket, "&proto=1 HTTP/1.0\n\n", 19);
+#ifndef NDEBUG
+ printf("&proto=1 HTTP/1.0\n");
+#endif
+ do
+ connect_getline(tempbuf);
+ while(strcmp(tempbuf,""));
+} /* http_send() */
+
+/*
+ * Send the "read from cddb" command to the server using http
+ */
+void
+http_read(char *category, unsigned int id)
+{
+ char tempbuf[84];
+ sprintf(tempbuf, "cddb+read+%s+%08x", category, id);
+ http_send(tempbuf);
+} /* http_read() */
+
+/*
+ * The main routine called from the ui
+ */
+void
+cddb_request(void)
+{
+ int i;
+ char tempbuf[2000];
+ extern int cur_ntracks;
+
+ int status;
+ char category[21];
+ unsigned int id;
+
+ strcpy(cddb.cddb_server,"localhost:888");
+ strcpy(cddb.mail_adress,"svolli@bigfoot.com");
+ /*
+ * cddb.protocol = 1;
+ */
+ wipe_cdinfo();
+
+ switch(cddb.protocol)
+ {
+ case 1: /* cddbp */
+#ifndef NDEBUG
+ printf("USING CDDBP\n");
+ printf("open\n");
+#endif
+ connect_open();
+ connect_getline(tempbuf);
+#ifndef NDEBUG
+ printf("[%s]\n",tempbuf);
+#endif
+ /*
+ * if(atoi(tempbuf) == 201) return;
+ */
+
+ /*
+ * strcpy(tempbuf,"cddb hello svolli bigfoot.com Eierkratzer eins");
+ */
+ string_makehello(tempbuf,' ');
+#ifndef NDEBUG
+ fprintf(stderr, "%s\n", tempbuf);
+#endif
+ cddbp_send(tempbuf);
+ connect_getline(tempbuf);
+#ifndef NDEBUG
+ printf("[%s]\n",tempbuf);
+ printf("query\n");
+#endif
+ sprintf(tempbuf, "cddb query %08x %d",thiscd.cddbid,thiscd.ntracks);
+ for (i = 0; i < cur_ntracks; i++)
+ if (thiscd.trk[i].section < 2)
+ sprintf(tempbuf + strlen(tempbuf), " %d",
+ thiscd.trk[i].start);
+ sprintf(tempbuf + strlen(tempbuf), " %d\n", thiscd.length);
+#ifndef NDEBUG
+ printf(">%s<\n",tempbuf);
+#endif
+ cddbp_send(tempbuf);
+ connect_getline(tempbuf);
+#ifndef NDEBUG
+ printf("[%s]\n",tempbuf);
+#endif
+ status=atoi(tempbuf);
+ /*
+ * fprintf(stderr, "status:%d\n",status);
+ * fprintf(stderr,"category:%s\n",category);
+ * fprintf(stderr,"id:%s\n",id);
+ */
+ if(status == 200) /* Exact match */
+ {
+ sscanf(tempbuf,"%d %20s %08x",&status,category,&id);
+ cddbp_read(category,id);
+ connect_read_entry();
+ }
+
+ if(status == 211) /* Unexact match, multiple possible
+ * Hack: always use first. */
+ {
+ connect_getline(tempbuf);
+ sscanf(tempbuf,"%20s %08x",category,&id);
+ while(strcmp(tempbuf,"."))
+ connect_getline(tempbuf);
+ cddbp_read(category,id);
+ connect_read_entry();
+ }
+
+ cddbp_send("quit");
+ connect_close();
+#ifndef NDEBUG
+ printf("close\n");
+#endif
+ break;
+ case 2: /* http */
+ case 3: /* http proxy */
+#ifndef NDEBUG
+ printf("USING HTTP%s\n",
+ (cddb.protocol == 3) ? " WITH PROXY" : "");
+ printf("query\n");
+#endif
+ sprintf(tempbuf, "cddb+query+%08x+%d",thiscd.cddbid,thiscd.ntracks);
+ for (i = 0; i < cur_ntracks; i++)
+ if (thiscd.trk[i].section < 2)
+ sprintf(tempbuf + strlen(tempbuf), "+%d",
+ thiscd.trk[i].start);
+ sprintf(tempbuf + strlen(tempbuf), "+%d", thiscd.length);
+#ifndef NDEBUG
+ printf(">%s<\n",tempbuf);
+#endif
+ connect_open();
+ http_send(tempbuf);
+ connect_getline(tempbuf);
+#ifndef NDEBUG
+ printf("[%s]\n",tempbuf);
+#endif
+ status=atoi(tempbuf);
+ /*
+ * fprintf(stderr, "status:%d\n",status);
+ * fprintf(stderr, "category:%s\n",category);
+ * fprintf(stderr, "id:%s\n",id);
+ */
+
+ if(status == 200) /* Exact match */
+ {
+ connect_close();
+ connect_open();
+ sscanf(tempbuf,"%d %20s %08x",&status,category,&id);
+ http_read(category,id);
+ connect_read_entry();
+ }
+
+ if(status == 211) /* Unexact match, multiple possible
+ * Hack: always use first. */
+ {
+ connect_getline(tempbuf);
+ sscanf(tempbuf,"%20s %08x",category,&id);
+ while(strcmp(tempbuf,"."))
+ connect_getline(tempbuf);
+ connect_close();
+ connect_open();
+ http_read(category,id);
+ connect_read_entry();
+ }
+ /* moved close above break */
+ connect_close();
+ break;
+ default: /* off */
+ break;
+ }
+} /* cddb_request() */
+