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