summaryrefslogtreecommitdiff
path: root/acme/bin/source/acd/cddb.c
diff options
context:
space:
mode:
Diffstat (limited to 'acme/bin/source/acd/cddb.c')
-rw-r--r--acme/bin/source/acd/cddb.c197
1 files changed, 197 insertions, 0 deletions
diff --git a/acme/bin/source/acd/cddb.c b/acme/bin/source/acd/cddb.c
new file mode 100644
index 000000000..ba1fa7604
--- /dev/null
+++ b/acme/bin/source/acd/cddb.c
@@ -0,0 +1,197 @@
+#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);
+}