1 #include "acd.h" 2 #include <ctype.h> 3 4 /* see CDDBPROTO */ 5 static ulong 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 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 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 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 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