]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/aux/cddb.c
aux/cddb: freedb.org is dead, use gnudb.org
[plan9front.git] / sys / src / cmd / aux / cddb.c
1 #include <u.h>
2 #include <libc.h>
3 #include <bio.h>
4 #include <ctype.h>
5
6 char *server = "gnudb.org";
7
8 int debug;
9 #define DPRINT if(debug)fprint
10 int tflag;
11 int Tflag;
12
13 typedef struct Track Track;
14 struct Track {
15         int n;
16         char *title;
17 };
18
19 enum {
20         MTRACK = 64,
21 };
22
23 typedef struct Toc Toc;
24 struct Toc {
25         ulong diskid;
26         int ntrack;
27         char *title;
28         Track track[MTRACK];
29 };
30
31 void*
32 emalloc(uint n)
33 {
34         void *p;
35
36         p = malloc(n);
37         if(p == nil)
38                 sysfatal("can't malloc: %r");
39         memset(p, 0, n);
40         return p;
41 }
42
43 char*
44 estrdup(char *s)
45 {
46         char *t;
47
48         t = emalloc(strlen(s)+1);
49         strcpy(t, s);
50         return t;
51 }
52
53 static void
54 dumpcddb(Toc *t)
55 {
56         int i, n, s;
57
58         print("title    %s\n", t->title);
59         for(i=0; i<t->ntrack; i++){
60                 if(tflag){
61                         n = t->track[i+1].n;
62                         if(i == t->ntrack-1)
63                                 n *= 75;
64                         s = (n - t->track[i].n)/75;
65                         print("%d\t%s\t%d:%2.2d\n", i+1, t->track[i].title, s/60, s%60);
66                 }
67                 else
68                         print("%d\t%s\n", i+1, t->track[i].title);
69         }
70         if(Tflag){
71                 s = t->track[i].n;
72                 print("Total time: %d:%2.2d\n", s/60, s%60);
73         }
74 }
75
76 char*
77 append(char *a, char *b)
78 {
79         char *c;
80
81         c = emalloc(strlen(a)+strlen(b)+1);
82         strcpy(c, a);
83         strcat(c, b);
84         return c;
85 }
86
87 static int
88 cddbfilltoc(Toc *t)
89 {
90         int fd;
91         int i;
92         char *p, *q;
93         Biobuf bin;
94         char *f[10];
95         int nf;
96         char *id, *categ;
97
98         fd = dial(netmkaddr(server, "tcp", "8880"), 0, 0, 0);
99         if(fd < 0) {
100                 fprint(2, "%s: %s: cannot dial: %r\n", argv0, server);
101                 return -1;
102         }
103         Binit(&bin, fd, OREAD);
104
105         if((p=Brdline(&bin, '\n')) == nil || atoi(p)/100 != 2) {
106         died:
107                 close(fd);
108                 Bterm(&bin);
109                 fprint(2, "%s: error talking to cddb server %s\n",
110                         argv0, server);
111                 if(p) {
112                         p[Blinelen(&bin)-1] = 0;
113                         fprint(2, "%s: server says: %s\n", argv0, p);
114                 }
115                 return -1;
116         }
117
118         fprint(fd, "cddb hello gre plan9 9cd 1.0\r\n");
119         if((p = Brdline(&bin, '\n')) == nil || atoi(p)/100 != 2)
120                 goto died;
121
122         /*
123          *      Protocol level 6 is the same as level 5 except that
124          *      the character set is now UTF-8 instead of ISO-8859-1. 
125          */
126         fprint(fd, "proto 6\r\n");
127         DPRINT(2, "proto 6\r\n");
128         if((p = Brdline(&bin, '\n')) == nil || atoi(p)/100 != 2)
129                 goto died;
130         p[Blinelen(&bin)-1] = 0;
131         DPRINT(2, "cddb: %s\n", p);
132
133         fprint(fd, "cddb query %8.8lux %d", t->diskid, t->ntrack);
134         DPRINT(2, "cddb query %8.8lux %d", t->diskid, t->ntrack);
135         for(i=0; i<t->ntrack; i++) {
136                 fprint(fd, " %d", t->track[i].n);
137                 DPRINT(2, " %d", t->track[i].n);
138         }
139         fprint(fd, " %d\r\n", t->track[t->ntrack].n);
140         DPRINT(2, " %d\r\n", t->track[t->ntrack].n);
141
142         if((p = Brdline(&bin, '\n')) == nil || atoi(p)/100 != 2)
143                 goto died;
144         p[Blinelen(&bin)-1] = 0;
145         DPRINT(2, "cddb: %s\n", p);
146         nf = tokenize(p, f, nelem(f));
147         if(nf < 1)
148                 goto died;
149
150         switch(atoi(f[0])) {
151         case 200:       /* exact match */
152                 if(nf < 3)
153                         goto died;
154                 categ = f[1];
155                 id = f[2];
156                 break;
157         case 210:       /* exact matches */
158         case 211:       /* close matches */
159                 if((p = Brdline(&bin, '\n')) == nil)
160                         goto died;
161                 if(p[0] == '.') /* no close matches? */
162                         goto died;
163                 p[Blinelen(&bin)-1] = '\0';
164
165                 /* accept first match */
166                 nf = tokenize(p, f, nelem(f));
167                 if(nf < 2)
168                         goto died;
169                 categ = f[0];
170                 id = f[1];
171
172                 /* snarf rest of buffer */
173                 while(p[0] != '.') {
174                         if((p = Brdline(&bin, '\n')) == nil)
175                                 goto died;
176                         p[Blinelen(&bin)-1] = '\0';
177                         DPRINT(2, "cddb: %s\n", p);
178                 }
179                 break;
180         case 202: /* no match */
181         default:
182                 goto died;
183         }
184
185         t->title = "";
186         for(i=0; i<t->ntrack; i++)
187                 t->track[i].title = "";
188
189         /* fetch results for this cd */
190         fprint(fd, "cddb read %s %s\r\n", categ, id);
191         do {
192                 if((p = Brdline(&bin, '\n')) == nil)
193                         goto died;
194                 q = p+Blinelen(&bin)-1;
195                 while(isspace(*q))
196                         *q-- = 0;
197 DPRINT(2, "cddb %s\n", p);
198                 if(strncmp(p, "DTITLE=", 7) == 0)
199                         t->title = append(t->title, p+7);
200                 else if(strncmp(p, "TTITLE", 6) == 0 && isdigit(p[6])) {
201                         i = atoi(p+6);
202                         if(i < t->ntrack) {
203                                 p += 6;
204                                 while(isdigit(*p))
205                                         p++;
206                                 if(*p == '=')
207                                         p++;
208
209                                 t->track[i].title = append(t->track[i].title, estrdup(p));
210                         }
211                 } 
212         } while(*p != '.');
213
214         fprint(fd, "quit\r\n");
215         close(fd);
216         Bterm(&bin);
217
218         return 0;
219 }
220
221 void
222 usage(void)
223 {
224         fprint(2, "usage: aux/cddb [-DTt] [-s server] query diskid n ...\n");
225         exits("usage");
226 }
227
228 void
229 main(int argc, char **argv)
230 {
231         int i;
232         Toc toc;
233
234         ARGBEGIN{
235         case 'D':
236                 debug = 1;
237                 break;
238         case 's':
239                 server = EARGF(usage());
240                 break;
241         case 'T':
242                 Tflag = 1;
243                 /*FALLTHROUGH*/
244         case 't':
245                 tflag = 1;
246                 break;
247         }ARGEND
248
249         if(argc < 3 || strcmp(argv[0], "query") != 0)
250                 usage();
251
252         toc.diskid = strtoul(argv[1], 0, 16);
253         toc.ntrack = atoi(argv[2]);
254         if(argc != 3+toc.ntrack+1)
255                 sysfatal("argument count does not match given ntrack");
256
257         for(i=0; i<=toc.ntrack; i++)
258                 toc.track[i].n = atoi(argv[3+i]);
259
260         if(cddbfilltoc(&toc) < 0)
261                 exits("whoops");
262
263         dumpcddb(&toc);
264         exits(nil);
265 }