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