xref: /plan9/acme/bin/source/acd/cddb.c (revision afb30c3eb94b92629560c385d0152410d412fdfb)
1 #include "acd.h"
2 #include <ctype.h>
3 
4 /* see CDDBPROTO */
5 static ulong
cddb_sum(int n)6 cddb_sum(int n)
7 {
8 	int ret;
9 	ret = 0;
10 	while(n > 0) {
11 		ret += n%10;
12 		n /= 10;
13 	}
14 	return ret;
15 }
16 
17 static ulong
diskid(Toc * t)18 diskid(Toc *t)
19 {
20 	int i, n, tmp;
21 	Msf *ms, *me;
22 
23 	n = 0;
24 	for(i=0; i < t->ntrack; i++)
25 		n += cddb_sum(t->track[i].start.m*60+t->track[i].start.s);
26 
27 	ms = &t->track[0].start;
28 	me = &t->track[t->ntrack].start;
29 	tmp = (me->m*60+me->s) - (ms->m*60+ms->s);
30 
31 	/*
32 	 * the spec says n%0xFF rather than n&0xFF.  it's unclear which is correct.
33 	 * most CDs are in the database under both entries.
34 	 */
35 	return ((n & 0xFF) << 24 | (tmp << 8) | t->ntrack);
36 }
37 
38 static void
append(char ** d,char * s)39 append(char **d, char *s)
40 {
41 	char *r;
42 	if (*d == nil)
43 		*d = estrdup(s);
44 	else {
45 		r = emalloc(strlen(*d) + strlen(s) + 1);
46 		strcpy(r, *d);
47 		strcat(r, s);
48 		free(*d);
49 		*d = r;
50 	}
51 }
52 
53 static int
cddbfilltoc(Toc * t)54 cddbfilltoc(Toc *t)
55 {
56 	int fd;
57 	int i;
58 	char *p, *q;
59 	Biobuf bin;
60 	Msf *m;
61 	char *f[10];
62 	int nf;
63 	char *id, *categ;
64 	char gottrack[MTRACK];
65 	int gottitle;
66 
67 	fd = dial("tcp!freedb.freedb.org!888", 0, 0, 0);
68 	if(fd < 0) {
69 		fprint(2, "cannot dial: %r\n");
70 		return -1;
71 	}
72 	Binit(&bin, fd, OREAD);
73 
74 	if((p=Brdline(&bin, '\n')) == nil || atoi(p)/100 != 2) {
75 	died:
76 		close(fd);
77 		Bterm(&bin);
78 		fprint(2, "error talking to server\n");
79 		if(p) {
80 			p[Blinelen(&bin)-1] = 0;
81 			fprint(2, "server says: %s\n", p);
82 		}
83 		return -1;
84 	}
85 
86 	fprint(fd, "cddb hello gre plan9 9cd 1.0\r\n");
87 	if((p = Brdline(&bin, '\n')) == nil || atoi(p)/100 != 2)
88 		goto died;
89 
90 	fprint(fd, "cddb query %8.8lux %d", diskid(t), t->ntrack);
91 	DPRINT(2, "cddb query %8.8lux %d", diskid(t), t->ntrack);
92 	for(i=0; i<t->ntrack; i++) {
93 		m = &t->track[i].start;
94 		fprint(fd, " %d", (m->m*60+m->s)*75+m->f);
95 		DPRINT(2, " %d", (m->m*60+m->s)*75+m->f);
96 	}
97 	m = &t->track[t->ntrack-1].end;
98 	fprint(fd, " %d\r\n", m->m*60+m->s);
99 	DPRINT(2, " %d\r\n", m->m*60+m->s);
100 
101 	if((p = Brdline(&bin, '\n')) == nil || atoi(p)/100 != 2)
102 		goto died;
103 	p[Blinelen(&bin)-1] = 0;
104 	DPRINT(2, "cddb: %s\n", p);
105 	nf = tokenize(p, f, nelem(f));
106 	if(nf < 1)
107 		goto died;
108 
109 	switch(atoi(f[0])) {
110 	case 200:	/* exact match */
111 		if(nf < 3)
112 			goto died;
113 		categ = f[1];
114 		id = f[2];
115 		break;
116 	case 211:	/* close matches */
117 		if((p = Brdline(&bin, '\n')) == nil)
118 			goto died;
119 		if(p[0] == '.')	/* no close matches? */
120 			goto died;
121 		p[Blinelen(&bin)-1] = '\0';
122 
123 		/* accept first match */
124 		nf = tokenize(p, f, nelem(f));
125 		if(nf < 2)
126 			goto died;
127 		categ = f[0];
128 		id = f[1];
129 
130 		/* snarf rest of buffer */
131 		while(p[0] != '.') {
132 			if((p = Brdline(&bin, '\n')) == nil)
133 				goto died;
134 			p[Blinelen(&bin)-1] = '\0';
135 			DPRINT(2, "cddb: %s\n", p);
136 		}
137 		break;
138 	case 202: /* no match */
139 	default:
140 		goto died;
141 	}
142 
143 	/* fetch results for this cd */
144 	fprint(fd, "cddb read %s %s\r\n", categ, id);
145 
146 	memset(gottrack, 0, sizeof(gottrack));
147 	gottitle = 0;
148 	do {
149 		if((p = Brdline(&bin, '\n')) == nil)
150 			goto died;
151 		q = p+Blinelen(&bin)-1;
152 		while(isspace(*q))
153 			*q-- = 0;
154 DPRINT(2, "cddb %s\n", p);
155 		if(strncmp(p, "DTITLE=", 7) == 0) {
156 			if (gottitle)
157 				append(&t->title, p + 7);
158 			else
159 				t->title = estrdup(p+7);
160 			gottitle = 1;
161 		} else if(strncmp(p, "TTITLE", 6) == 0 && isdigit(p[6])) {
162 			i = atoi(p+6);
163 			if(i < t->ntrack) {
164 				p += 6;
165 				while(isdigit(*p))
166 					p++;
167 				if(*p == '=')
168 					p++;
169 
170 				if (gottrack[i])
171 					append(&t->track[i].title, p);
172 				else
173 					t->track[i].title = estrdup(p);
174 				gottrack[i] = 1;
175 			}
176 		}
177 	} while(*p != '.');
178 
179 	fprint(fd, "quit\r\n");
180 	close(fd);
181 	Bterm(&bin);
182 
183 	return 0;
184 }
185 
186 void
cddbproc(void * v)187 cddbproc(void *v)
188 {
189 	Drive *d;
190 	Toc t;
191 
192 	threadsetname("cddbproc");
193 	d = v;
194 	while(recv(d->cdbreq, &t))
195 		if(cddbfilltoc(&t) == 0)
196 			send(d->cdbreply, &t);
197 }
198