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