/* * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ #include <u.h>#include <libc.h>#include <bio.h>#include <ctype.h> char *server = "freedb.freedb.org"; int debug;#define DPRINT if(debug)fprintint tflag;int Tflag; typedef struct Track Track;struct Track { int n; char *title;}; enum { MTRACK = 64,}; typedef struct Toc Toc;struct Toc { ulong diskid; int ntrack; char *title; Track track[MTRACK];}; void*emalloc(uint n){ void *p; p = malloc(n); if(p == nil) sysfatal("can't malloc: %r"); memset(p, 0, n); return p;} char*estrdup(char *s){ char *t; t = emalloc(strlen(s)+1); strcpy(t, s); return t;} static voiddumpcddb(Toc *t){ int i, n, s; print("title %s\n", t->title); for(i=0; i<t->ntrack; i++){ if(tflag){ n = t->track[i+1].n; if(i == t->ntrack-1) n *= 75; s = (n - t->track[i].n)/75; print("%d\t%s\t%d:%2.2d\n", i+1, t->track[i].title, s/60, s%60); } else print("%d\t%s\n", i+1, t->track[i].title); } if(Tflag){ s = t->track[i].n; print("Total time: %d:%2.2d\n", s/60, s%60); }} char*append(char *a, char *b){ char *c; c = emalloc(strlen(a)+strlen(b)+1); strcpy(c, a); strcat(c, b); return c;} static intcddbfilltoc(Toc *t){ int fd; int i; char *p, *q; Biobuf bin; char *f[10]; int nf; char *id, *categ; fd = dial(netmkaddr(server, "tcp", "888"), 0, 0, 0); if(fd < 0) { fprint(2, "%s: %s: cannot dial: %r\n", argv0, server); return -1; } Binit(&bin, fd, OREAD); if((p=Brdline(&bin, '\n')) == nil || atoi(p)/100 != 2) { died: close(fd); Bterm(&bin); fprint(2, "%s: error talking to cddb server %s\n", argv0, server); if(p) { p[Blinelen(&bin)-1] = 0; fprint(2, "%s: server says: %s\n", argv0, 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; /* * Protocol level 6 is the same as level 5 except that * the character set is now UTF-8 instead of ISO-8859-1. */ fprint(fd, "proto 6\r\n"); DPRINT(2, "proto 6\r\n"); if((p = Brdline(&bin, '\n')) == nil || atoi(p)/100 != 2) goto died; p[Blinelen(&bin)-1] = 0; DPRINT(2, "cddb: %s\n", p); fprint(fd, "cddb query %8.8lux %d", t->diskid, t->ntrack); DPRINT(2, "cddb query %8.8lux %d", t->diskid, t->ntrack); for(i=0; i<t->ntrack; i++) { fprint(fd, " %d", t->track[i].n); DPRINT(2, " %d", t->track[i].n); } fprint(fd, " %d\r\n", t->track[t->ntrack].n); DPRINT(2, " %d\r\n", t->track[t->ntrack].n); 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 210: /* exact matches */ 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; } t->title = ""; for(i=0; i<t->ntrack; i++) t->track[i].title = ""; /* fetch results for this cd */ fprint(fd, "cddb read %s %s\r\n", categ, id); 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) t->title = append(t->title, p+7); 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++; t->track[i].title = append(t->track[i].title, estrdup(p)); } } } while(*p != '.'); fprint(fd, "quit\r\n"); close(fd); Bterm(&bin); return 0;} voidusage(void){ fprint(2, "usage: aux/cddb [-DTt] [-s server] query diskid n ...\n"); exits("usage");} voidmain(int argc, char **argv){ int i; Toc toc; ARGBEGIN{ case 'D': debug = 1; break; case 's': server = EARGF(usage()); break; case 'T': Tflag = 1; /*FALLTHROUGH*/ case 't': tflag = 1; break; }ARGEND if(argc < 3 || strcmp(argv[0], "query") != 0) usage(); toc.diskid = strtoul(argv[1], 0, 16); toc.ntrack = atoi(argv[2]); if(argc != 3+toc.ntrack+1) sysfatal("argument count does not match given ntrack"); for(i=0; i<=toc.ntrack; i++) toc.track[i].n = atoi(argv[3+i]); if(cddbfilltoc(&toc) < 0) exits("whoops"); dumpcddb(&toc); exits(nil);}
/*
* This file is part of the UCB release of Plan 9. It is subject to the license
* terms in the LICENSE file found in the top-level directory of this
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
* part of the UCB release of Plan 9, including this file, may be copied,
* modified, propagated, or distributed except according to the terms contained
* in the LICENSE file.
*/
#include <u.h>
#include <libc.h>
#include <bio.h>
#include <ctype.h>
char *server = "freedb.freedb.org";
int debug;
#define DPRINT if(debug)fprint
int tflag;
int Tflag;
typedef struct Track Track;
struct Track {
int n;
char *title;
};
enum {
MTRACK = 64,
};
typedef struct Toc Toc;
struct Toc {
ulong diskid;
int ntrack;
char *title;
Track track[MTRACK];
};
void*
emalloc(uint n)
{
void *p;
p = malloc(n);
if(p == nil)
sysfatal("can't malloc: %r");
memset(p, 0, n);
return p;
}
char*
estrdup(char *s)
{
char *t;
t = emalloc(strlen(s)+1);
strcpy(t, s);
return t;
}
static void
dumpcddb(Toc *t)
{
int i, n, s;
print("title %s\n", t->title);
for(i=0; i<t->ntrack; i++){
if(tflag){
n = t->track[i+1].n;
if(i == t->ntrack-1)
n *= 75;
s = (n - t->track[i].n)/75;
print("%d\t%s\t%d:%2.2d\n", i+1, t->track[i].title, s/60, s%60);
}
else
print("%d\t%s\n", i+1, t->track[i].title);
}
if(Tflag){
s = t->track[i].n;
print("Total time: %d:%2.2d\n", s/60, s%60);
}
}
char*
append(char *a, char *b)
{
char *c;
c = emalloc(strlen(a)+strlen(b)+1);
strcpy(c, a);
strcat(c, b);
return c;
}
static int
cddbfilltoc(Toc *t)
{
int fd;
int i;
char *p, *q;
Biobuf bin;
char *f[10];
int nf;
char *id, *categ;
fd = dial(netmkaddr(server, "tcp", "888"), 0, 0, 0);
if(fd < 0) {
fprint(2, "%s: %s: cannot dial: %r\n", argv0, server);
return -1;
}
Binit(&bin, fd, OREAD);
if((p=Brdline(&bin, '\n')) == nil || atoi(p)/100 != 2) {
died:
close(fd);
Bterm(&bin);
fprint(2, "%s: error talking to cddb server %s\n",
argv0, server);
if(p) {
p[Blinelen(&bin)-1] = 0;
fprint(2, "%s: server says: %s\n", argv0, 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;
/*
* Protocol level 6 is the same as level 5 except that
* the character set is now UTF-8 instead of ISO-8859-1.
*/
fprint(fd, "proto 6\r\n");
DPRINT(2, "proto 6\r\n");
if((p = Brdline(&bin, '\n')) == nil || atoi(p)/100 != 2)
goto died;
p[Blinelen(&bin)-1] = 0;
DPRINT(2, "cddb: %s\n", p);
fprint(fd, "cddb query %8.8lux %d", t->diskid, t->ntrack);
DPRINT(2, "cddb query %8.8lux %d", t->diskid, t->ntrack);
for(i=0; i<t->ntrack; i++) {
fprint(fd, " %d", t->track[i].n);
DPRINT(2, " %d", t->track[i].n);
}
fprint(fd, " %d\r\n", t->track[t->ntrack].n);
DPRINT(2, " %d\r\n", t->track[t->ntrack].n);
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 210: /* exact matches */
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;
}
t->title = "";
for(i=0; i<t->ntrack; i++)
t->track[i].title = "";
/* fetch results for this cd */
fprint(fd, "cddb read %s %s\r\n", categ, id);
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)
t->title = append(t->title, p+7);
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++;
t->track[i].title = append(t->track[i].title, estrdup(p));
}
}
} while(*p != '.');
fprint(fd, "quit\r\n");
close(fd);
Bterm(&bin);
return 0;
}
void
usage(void)
{
fprint(2, "usage: aux/cddb [-DTt] [-s server] query diskid n ...\n");
exits("usage");
}
void
main(int argc, char **argv)
{
int i;
Toc toc;
ARGBEGIN{
case 'D':
debug = 1;
break;
case 's':
server = EARGF(usage());
break;
case 'T':
Tflag = 1;
/*FALLTHROUGH*/
case 't':
tflag = 1;
break;
}ARGEND
if(argc < 3 || strcmp(argv[0], "query") != 0)
usage();
toc.diskid = strtoul(argv[1], 0, 16);
toc.ntrack = atoi(argv[2]);
if(argc != 3+toc.ntrack+1)
sysfatal("argument count does not match given ntrack");
for(i=0; i<=toc.ntrack; i++)
toc.track[i].n = atoi(argv[3+i]);
if(cddbfilltoc(&toc) < 0)
exits("whoops");
dumpcddb(&toc);
exits(nil);
}