xref: /plan9-contrib/acme/bin/source/acd/cddb.c (revision afb30c3eb94b92629560c385d0152410d412fdfb)
19a747e4fSDavid du Colombier #include "acd.h"
29a747e4fSDavid du Colombier #include <ctype.h>
39a747e4fSDavid du Colombier 
49a747e4fSDavid du Colombier /* see CDDBPROTO */
59a747e4fSDavid du Colombier static ulong
cddb_sum(int n)69a747e4fSDavid du Colombier cddb_sum(int n)
79a747e4fSDavid du Colombier {
89a747e4fSDavid du Colombier 	int ret;
99a747e4fSDavid du Colombier 	ret = 0;
109a747e4fSDavid du Colombier 	while(n > 0) {
119a747e4fSDavid du Colombier 		ret += n%10;
129a747e4fSDavid du Colombier 		n /= 10;
139a747e4fSDavid du Colombier 	}
149a747e4fSDavid du Colombier 	return ret;
159a747e4fSDavid du Colombier }
169a747e4fSDavid du Colombier 
179a747e4fSDavid du Colombier static ulong
diskid(Toc * t)189a747e4fSDavid du Colombier diskid(Toc *t)
199a747e4fSDavid du Colombier {
209a747e4fSDavid du Colombier 	int i, n, tmp;
219a747e4fSDavid du Colombier 	Msf *ms, *me;
229a747e4fSDavid du Colombier 
239a747e4fSDavid du Colombier 	n = 0;
249a747e4fSDavid du Colombier 	for(i=0; i < t->ntrack; i++)
259a747e4fSDavid du Colombier 		n += cddb_sum(t->track[i].start.m*60+t->track[i].start.s);
269a747e4fSDavid du Colombier 
279a747e4fSDavid du Colombier 	ms = &t->track[0].start;
289a747e4fSDavid du Colombier 	me = &t->track[t->ntrack].start;
299a747e4fSDavid du Colombier 	tmp = (me->m*60+me->s) - (ms->m*60+ms->s);
309a747e4fSDavid du Colombier 
319a747e4fSDavid du Colombier 	/*
329a747e4fSDavid du Colombier 	 * the spec says n%0xFF rather than n&0xFF.  it's unclear which is correct.
339a747e4fSDavid du Colombier 	 * most CDs are in the database under both entries.
349a747e4fSDavid du Colombier 	 */
359a747e4fSDavid du Colombier 	return ((n & 0xFF) << 24 | (tmp << 8) | t->ntrack);
369a747e4fSDavid du Colombier }
379a747e4fSDavid du Colombier 
38*afb30c3eSDavid du Colombier static void
append(char ** d,char * s)39*afb30c3eSDavid du Colombier append(char **d, char *s)
40*afb30c3eSDavid du Colombier {
41*afb30c3eSDavid du Colombier 	char *r;
42*afb30c3eSDavid du Colombier 	if (*d == nil)
43*afb30c3eSDavid du Colombier 		*d = estrdup(s);
44*afb30c3eSDavid du Colombier 	else {
45*afb30c3eSDavid du Colombier 		r = emalloc(strlen(*d) + strlen(s) + 1);
46*afb30c3eSDavid du Colombier 		strcpy(r, *d);
47*afb30c3eSDavid du Colombier 		strcat(r, s);
48*afb30c3eSDavid du Colombier 		free(*d);
49*afb30c3eSDavid du Colombier 		*d = r;
50*afb30c3eSDavid du Colombier 	}
51*afb30c3eSDavid du Colombier }
52*afb30c3eSDavid du Colombier 
539a747e4fSDavid du Colombier static int
cddbfilltoc(Toc * t)549a747e4fSDavid du Colombier cddbfilltoc(Toc *t)
559a747e4fSDavid du Colombier {
569a747e4fSDavid du Colombier 	int fd;
579a747e4fSDavid du Colombier 	int i;
589a747e4fSDavid du Colombier 	char *p, *q;
599a747e4fSDavid du Colombier 	Biobuf bin;
609a747e4fSDavid du Colombier 	Msf *m;
619a747e4fSDavid du Colombier 	char *f[10];
629a747e4fSDavid du Colombier 	int nf;
639a747e4fSDavid du Colombier 	char *id, *categ;
64*afb30c3eSDavid du Colombier 	char gottrack[MTRACK];
65*afb30c3eSDavid du Colombier 	int gottitle;
669a747e4fSDavid du Colombier 
679a747e4fSDavid du Colombier 	fd = dial("tcp!freedb.freedb.org!888", 0, 0, 0);
689a747e4fSDavid du Colombier 	if(fd < 0) {
699a747e4fSDavid du Colombier 		fprint(2, "cannot dial: %r\n");
709a747e4fSDavid du Colombier 		return -1;
719a747e4fSDavid du Colombier 	}
729a747e4fSDavid du Colombier 	Binit(&bin, fd, OREAD);
739a747e4fSDavid du Colombier 
749a747e4fSDavid du Colombier 	if((p=Brdline(&bin, '\n')) == nil || atoi(p)/100 != 2) {
759a747e4fSDavid du Colombier 	died:
769a747e4fSDavid du Colombier 		close(fd);
779a747e4fSDavid du Colombier 		Bterm(&bin);
789a747e4fSDavid du Colombier 		fprint(2, "error talking to server\n");
799a747e4fSDavid du Colombier 		if(p) {
809a747e4fSDavid du Colombier 			p[Blinelen(&bin)-1] = 0;
819a747e4fSDavid du Colombier 			fprint(2, "server says: %s\n", p);
829a747e4fSDavid du Colombier 		}
839a747e4fSDavid du Colombier 		return -1;
849a747e4fSDavid du Colombier 	}
859a747e4fSDavid du Colombier 
869a747e4fSDavid du Colombier 	fprint(fd, "cddb hello gre plan9 9cd 1.0\r\n");
879a747e4fSDavid du Colombier 	if((p = Brdline(&bin, '\n')) == nil || atoi(p)/100 != 2)
889a747e4fSDavid du Colombier 		goto died;
899a747e4fSDavid du Colombier 
909a747e4fSDavid du Colombier 	fprint(fd, "cddb query %8.8lux %d", diskid(t), t->ntrack);
919a747e4fSDavid du Colombier 	DPRINT(2, "cddb query %8.8lux %d", diskid(t), t->ntrack);
929a747e4fSDavid du Colombier 	for(i=0; i<t->ntrack; i++) {
939a747e4fSDavid du Colombier 		m = &t->track[i].start;
949a747e4fSDavid du Colombier 		fprint(fd, " %d", (m->m*60+m->s)*75+m->f);
959a747e4fSDavid du Colombier 		DPRINT(2, " %d", (m->m*60+m->s)*75+m->f);
969a747e4fSDavid du Colombier 	}
979a747e4fSDavid du Colombier 	m = &t->track[t->ntrack-1].end;
989a747e4fSDavid du Colombier 	fprint(fd, " %d\r\n", m->m*60+m->s);
999a747e4fSDavid du Colombier 	DPRINT(2, " %d\r\n", m->m*60+m->s);
1009a747e4fSDavid du Colombier 
1019a747e4fSDavid du Colombier 	if((p = Brdline(&bin, '\n')) == nil || atoi(p)/100 != 2)
1029a747e4fSDavid du Colombier 		goto died;
1039a747e4fSDavid du Colombier 	p[Blinelen(&bin)-1] = 0;
1049a747e4fSDavid du Colombier 	DPRINT(2, "cddb: %s\n", p);
1059a747e4fSDavid du Colombier 	nf = tokenize(p, f, nelem(f));
1069a747e4fSDavid du Colombier 	if(nf < 1)
1079a747e4fSDavid du Colombier 		goto died;
1089a747e4fSDavid du Colombier 
1099a747e4fSDavid du Colombier 	switch(atoi(f[0])) {
1109a747e4fSDavid du Colombier 	case 200:	/* exact match */
1119a747e4fSDavid du Colombier 		if(nf < 3)
1129a747e4fSDavid du Colombier 			goto died;
1139a747e4fSDavid du Colombier 		categ = f[1];
1149a747e4fSDavid du Colombier 		id = f[2];
1159a747e4fSDavid du Colombier 		break;
1169a747e4fSDavid du Colombier 	case 211:	/* close matches */
1179a747e4fSDavid du Colombier 		if((p = Brdline(&bin, '\n')) == nil)
1189a747e4fSDavid du Colombier 			goto died;
1199a747e4fSDavid du Colombier 		if(p[0] == '.')	/* no close matches? */
1209a747e4fSDavid du Colombier 			goto died;
1219a747e4fSDavid du Colombier 		p[Blinelen(&bin)-1] = '\0';
1229a747e4fSDavid du Colombier 
1239a747e4fSDavid du Colombier 		/* accept first match */
1249a747e4fSDavid du Colombier 		nf = tokenize(p, f, nelem(f));
1259a747e4fSDavid du Colombier 		if(nf < 2)
1269a747e4fSDavid du Colombier 			goto died;
1279a747e4fSDavid du Colombier 		categ = f[0];
1289a747e4fSDavid du Colombier 		id = f[1];
1299a747e4fSDavid du Colombier 
1309a747e4fSDavid du Colombier 		/* snarf rest of buffer */
1319a747e4fSDavid du Colombier 		while(p[0] != '.') {
1329a747e4fSDavid du Colombier 			if((p = Brdline(&bin, '\n')) == nil)
1339a747e4fSDavid du Colombier 				goto died;
1349a747e4fSDavid du Colombier 			p[Blinelen(&bin)-1] = '\0';
1359a747e4fSDavid du Colombier 			DPRINT(2, "cddb: %s\n", p);
1369a747e4fSDavid du Colombier 		}
1379a747e4fSDavid du Colombier 		break;
1389a747e4fSDavid du Colombier 	case 202: /* no match */
1399a747e4fSDavid du Colombier 	default:
1409a747e4fSDavid du Colombier 		goto died;
1419a747e4fSDavid du Colombier 	}
1429a747e4fSDavid du Colombier 
1439a747e4fSDavid du Colombier 	/* fetch results for this cd */
1449a747e4fSDavid du Colombier 	fprint(fd, "cddb read %s %s\r\n", categ, id);
145*afb30c3eSDavid du Colombier 
146*afb30c3eSDavid du Colombier 	memset(gottrack, 0, sizeof(gottrack));
147*afb30c3eSDavid du Colombier 	gottitle = 0;
1489a747e4fSDavid du Colombier 	do {
1499a747e4fSDavid du Colombier 		if((p = Brdline(&bin, '\n')) == nil)
1509a747e4fSDavid du Colombier 			goto died;
1519a747e4fSDavid du Colombier 		q = p+Blinelen(&bin)-1;
1529a747e4fSDavid du Colombier 		while(isspace(*q))
1539a747e4fSDavid du Colombier 			*q-- = 0;
1549a747e4fSDavid du Colombier DPRINT(2, "cddb %s\n", p);
155*afb30c3eSDavid du Colombier 		if(strncmp(p, "DTITLE=", 7) == 0) {
156*afb30c3eSDavid du Colombier 			if (gottitle)
157*afb30c3eSDavid du Colombier 				append(&t->title, p + 7);
158*afb30c3eSDavid du Colombier 			else
1599a747e4fSDavid du Colombier 				t->title = estrdup(p+7);
160*afb30c3eSDavid du Colombier 			gottitle = 1;
161*afb30c3eSDavid du Colombier 		} else if(strncmp(p, "TTITLE", 6) == 0 && isdigit(p[6])) {
1629a747e4fSDavid du Colombier 			i = atoi(p+6);
1639a747e4fSDavid du Colombier 			if(i < t->ntrack) {
1649a747e4fSDavid du Colombier 				p += 6;
1659a747e4fSDavid du Colombier 				while(isdigit(*p))
1669a747e4fSDavid du Colombier 					p++;
1679a747e4fSDavid du Colombier 				if(*p == '=')
1689a747e4fSDavid du Colombier 					p++;
1699a747e4fSDavid du Colombier 
170*afb30c3eSDavid du Colombier 				if (gottrack[i])
171*afb30c3eSDavid du Colombier 					append(&t->track[i].title, p);
172*afb30c3eSDavid du Colombier 				else
1739a747e4fSDavid du Colombier 					t->track[i].title = estrdup(p);
174*afb30c3eSDavid du Colombier 				gottrack[i] = 1;
1759a747e4fSDavid du Colombier 			}
1769a747e4fSDavid du Colombier 		}
1779a747e4fSDavid du Colombier 	} while(*p != '.');
1789a747e4fSDavid du Colombier 
1799a747e4fSDavid du Colombier 	fprint(fd, "quit\r\n");
1809a747e4fSDavid du Colombier 	close(fd);
1819a747e4fSDavid du Colombier 	Bterm(&bin);
1829a747e4fSDavid du Colombier 
1839a747e4fSDavid du Colombier 	return 0;
1849a747e4fSDavid du Colombier }
1859a747e4fSDavid du Colombier 
1869a747e4fSDavid du Colombier void
cddbproc(void * v)1879a747e4fSDavid du Colombier cddbproc(void *v)
1889a747e4fSDavid du Colombier {
1899a747e4fSDavid du Colombier 	Drive *d;
1909a747e4fSDavid du Colombier 	Toc t;
1919a747e4fSDavid du Colombier 
1929a747e4fSDavid du Colombier 	threadsetname("cddbproc");
1939a747e4fSDavid du Colombier 	d = v;
1949a747e4fSDavid du Colombier 	while(recv(d->cdbreq, &t))
1959a747e4fSDavid du Colombier 		if(cddbfilltoc(&t) == 0)
1969a747e4fSDavid du Colombier 			send(d->cdbreply, &t);
1979a747e4fSDavid du Colombier }
198