ref: a3626a6efacc99bdfbe733758d508ed38ed8148c
dir: /acme/bin/source/acd/cddb.c/
#include "acd.h" #include <ctype.h> /* see CDDBPROTO */ static ulong cddb_sum(int n) { int ret; ret = 0; while(n > 0) { ret += n%10; n /= 10; } return ret; } static ulong diskid(Toc *t) { int i, n, tmp; Msf *ms, *me; n = 0; for(i=0; i < t->ntrack; i++) n += cddb_sum(t->track[i].start.m*60+t->track[i].start.s); ms = &t->track[0].start; me = &t->track[t->ntrack].start; tmp = (me->m*60+me->s) - (ms->m*60+ms->s); /* * the spec says n%0xFF rather than n&0xFF. it's unclear which is correct. * most CDs are in the database under both entries. */ return ((n & 0xFF) << 24 | (tmp << 8) | t->ntrack); } static void append(char **d, char *s) { char *r; if (*d == nil) *d = estrdup(s); else { r = emalloc(strlen(*d) + strlen(s) + 1); strcpy(r, *d); strcat(r, s); free(*d); *d = r; } } static int cddbfilltoc(Toc *t) { int fd; int i; char *p, *q; Biobuf bin; Msf *m; char *f[10]; int nf; char *id, *categ; char gottrack[MTRACK]; int gottitle; fd = dial("tcp!freedb.freedb.org!888", 0, 0, 0); if(fd < 0) { fprint(2, "cannot dial: %r\n"); return -1; } Binit(&bin, fd, OREAD); if((p=Brdline(&bin, '\n')) == nil || atoi(p)/100 != 2) { died: close(fd); Bterm(&bin); fprint(2, "error talking to server\n"); if(p) { p[Blinelen(&bin)-1] = 0; fprint(2, "server says: %s\n", p); } return -1; } fprint(fd, "cddb hello gre plan9 9cd 1.0\r\n"); if((p = Brdline(&bin, '\n')) == nil || atoi(p)/100 != 2) goto died; fprint(fd, "cddb query %8.8lux %d", diskid(t), t->ntrack); DPRINT(2, "cddb query %8.8lux %d", diskid(t), t->ntrack); for(i=0; i<t->ntrack; i++) { m = &t->track[i].start; fprint(fd, " %d", (m->m*60+m->s)*75+m->f); DPRINT(2, " %d", (m->m*60+m->s)*75+m->f); } m = &t->track[t->ntrack-1].end; fprint(fd, " %d\r\n", m->m*60+m->s); DPRINT(2, " %d\r\n", m->m*60+m->s); if((p = Brdline(&bin, '\n')) == nil || atoi(p)/100 != 2) goto died; p[Blinelen(&bin)-1] = 0; DPRINT(2, "cddb: %s\n", p); nf = tokenize(p, f, nelem(f)); if(nf < 1) goto died; switch(atoi(f[0])) { case 200: /* exact match */ if(nf < 3) goto died; categ = f[1]; id = f[2]; break; case 211: /* close matches */ if((p = Brdline(&bin, '\n')) == nil) goto died; if(p[0] == '.') /* no close matches? */ goto died; p[Blinelen(&bin)-1] = '\0'; /* accept first match */ nf = tokenize(p, f, nelem(f)); if(nf < 2) goto died; categ = f[0]; id = f[1]; /* snarf rest of buffer */ while(p[0] != '.') { if((p = Brdline(&bin, '\n')) == nil) goto died; p[Blinelen(&bin)-1] = '\0'; DPRINT(2, "cddb: %s\n", p); } break; case 202: /* no match */ default: goto died; } /* fetch results for this cd */ fprint(fd, "cddb read %s %s\r\n", categ, id); memset(gottrack, 0, sizeof(gottrack)); gottitle = 0; do { if((p = Brdline(&bin, '\n')) == nil) goto died; q = p+Blinelen(&bin)-1; while(isspace(*q)) *q-- = 0; DPRINT(2, "cddb %s\n", p); if(strncmp(p, "DTITLE=", 7) == 0) { if (gottitle) append(&t->title, p + 7); else t->title = estrdup(p+7); gottitle = 1; } else if(strncmp(p, "TTITLE", 6) == 0 && isdigit(p[6])) { i = atoi(p+6); if(i < t->ntrack) { p += 6; while(isdigit(*p)) p++; if(*p == '=') p++; if (gottrack[i]) append(&t->track[i].title, p); else t->track[i].title = estrdup(p); gottrack[i] = 1; } } } while(*p != '.'); fprint(fd, "quit\r\n"); close(fd); Bterm(&bin); return 0; } void cddbproc(void *v) { Drive *d; Toc t; threadsetname("cddbproc"); d = v; while(recv(d->cdbreq, &t)) if(cddbfilltoc(&t) == 0) send(d->cdbreply, &t); }