274 lines · 5.0 KB · C
RawDownload
/*  * 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);}