You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
589 lines
13 KiB
589 lines
13 KiB
/*
|
|
* $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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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() */
|
|
|