xref: /plan9/sys/src/cmd/aux/cddb.c (revision fd87a217ca5963330c6d5a07235e643d3509b52f)
19a747e4fSDavid du Colombier #include <u.h>
29a747e4fSDavid du Colombier #include <libc.h>
39a747e4fSDavid du Colombier #include <bio.h>
49a747e4fSDavid du Colombier #include <ctype.h>
59a747e4fSDavid du Colombier 
69a747e4fSDavid du Colombier char *server = "freedb.freedb.org";
73ec9be0fSDavid du Colombier 
89a747e4fSDavid du Colombier int debug;
99a747e4fSDavid du Colombier #define DPRINT if(debug)fprint
103ff48bf5SDavid du Colombier int tflag;
113ff48bf5SDavid du Colombier int Tflag;
129a747e4fSDavid du Colombier 
139a747e4fSDavid du Colombier typedef struct Track Track;
149a747e4fSDavid du Colombier struct Track {
159a747e4fSDavid du Colombier 	int n;
169a747e4fSDavid du Colombier 	char *title;
179a747e4fSDavid du Colombier };
189a747e4fSDavid du Colombier 
199a747e4fSDavid du Colombier enum {
209a747e4fSDavid du Colombier 	MTRACK = 64,
219a747e4fSDavid du Colombier };
223ec9be0fSDavid du Colombier 
239a747e4fSDavid du Colombier typedef struct Toc Toc;
249a747e4fSDavid du Colombier struct Toc {
259a747e4fSDavid du Colombier 	ulong diskid;
269a747e4fSDavid du Colombier 	int ntrack;
279a747e4fSDavid du Colombier 	char *title;
289a747e4fSDavid du Colombier 	Track track[MTRACK];
299a747e4fSDavid du Colombier };
309a747e4fSDavid du Colombier 
319a747e4fSDavid du Colombier void*
emalloc(uint n)329a747e4fSDavid du Colombier emalloc(uint n)
339a747e4fSDavid du Colombier {
349a747e4fSDavid du Colombier 	void *p;
359a747e4fSDavid du Colombier 
369a747e4fSDavid du Colombier 	p = malloc(n);
379a747e4fSDavid du Colombier 	if(p == nil)
389a747e4fSDavid du Colombier 		sysfatal("can't malloc: %r");
399a747e4fSDavid du Colombier 	memset(p, 0, n);
409a747e4fSDavid du Colombier 	return p;
419a747e4fSDavid du Colombier }
429a747e4fSDavid du Colombier 
439a747e4fSDavid du Colombier char*
estrdup(char * s)449a747e4fSDavid du Colombier estrdup(char *s)
459a747e4fSDavid du Colombier {
469a747e4fSDavid du Colombier 	char *t;
479a747e4fSDavid du Colombier 
489a747e4fSDavid du Colombier 	t = emalloc(strlen(s)+1);
499a747e4fSDavid du Colombier 	strcpy(t, s);
509a747e4fSDavid du Colombier 	return t;
519a747e4fSDavid du Colombier }
529a747e4fSDavid du Colombier 
539a747e4fSDavid du Colombier static void
dumpcddb(Toc * t)549a747e4fSDavid du Colombier dumpcddb(Toc *t)
559a747e4fSDavid du Colombier {
563ff48bf5SDavid du Colombier 	int i, n, s;
579a747e4fSDavid du Colombier 
589a747e4fSDavid du Colombier 	print("title	%s\n", t->title);
593ff48bf5SDavid du Colombier 	for(i=0; i<t->ntrack; i++){
603ff48bf5SDavid du Colombier 		if(tflag){
613ff48bf5SDavid du Colombier 			n = t->track[i+1].n;
623ff48bf5SDavid du Colombier 			if(i == t->ntrack-1)
633ff48bf5SDavid du Colombier 				n *= 75;
643ff48bf5SDavid du Colombier 			s = (n - t->track[i].n)/75;
653ff48bf5SDavid du Colombier 			print("%d\t%s\t%d:%2.2d\n", i+1, t->track[i].title, s/60, s%60);
663ff48bf5SDavid du Colombier 		}
673ff48bf5SDavid du Colombier 		else
683ff48bf5SDavid du Colombier 			print("%d\t%s\n", i+1, t->track[i].title);
693ff48bf5SDavid du Colombier 	}
703ff48bf5SDavid du Colombier 	if(Tflag){
713ff48bf5SDavid du Colombier 		s = t->track[i].n;
723ff48bf5SDavid du Colombier 		print("Total time: %d:%2.2d\n", s/60, s%60);
733ff48bf5SDavid du Colombier 	}
749a747e4fSDavid du Colombier }
759a747e4fSDavid du Colombier 
769a747e4fSDavid du Colombier char*
append(char * a,char * b)779a747e4fSDavid du Colombier append(char *a, char *b)
789a747e4fSDavid du Colombier {
799a747e4fSDavid du Colombier 	char *c;
809a747e4fSDavid du Colombier 
819a747e4fSDavid du Colombier 	c = emalloc(strlen(a)+strlen(b)+1);
829a747e4fSDavid du Colombier 	strcpy(c, a);
839a747e4fSDavid du Colombier 	strcat(c, b);
849a747e4fSDavid du Colombier 	return c;
859a747e4fSDavid du Colombier }
869a747e4fSDavid du Colombier 
879a747e4fSDavid du Colombier static int
cddbfilltoc(Toc * t)889a747e4fSDavid du Colombier cddbfilltoc(Toc *t)
899a747e4fSDavid du Colombier {
909a747e4fSDavid du Colombier 	int fd;
919a747e4fSDavid du Colombier 	int i;
929a747e4fSDavid du Colombier 	char *p, *q;
939a747e4fSDavid du Colombier 	Biobuf bin;
949a747e4fSDavid du Colombier 	char *f[10];
959a747e4fSDavid du Colombier 	int nf;
969a747e4fSDavid du Colombier 	char *id, *categ;
979a747e4fSDavid du Colombier 
989a747e4fSDavid du Colombier 	fd = dial(netmkaddr(server, "tcp", "888"), 0, 0, 0);
999a747e4fSDavid du Colombier 	if(fd < 0) {
1003ec9be0fSDavid du Colombier 		fprint(2, "%s: %s: cannot dial: %r\n", argv0, server);
1019a747e4fSDavid du Colombier 		return -1;
1029a747e4fSDavid du Colombier 	}
1039a747e4fSDavid du Colombier 	Binit(&bin, fd, OREAD);
1049a747e4fSDavid du Colombier 
1059a747e4fSDavid du Colombier 	if((p=Brdline(&bin, '\n')) == nil || atoi(p)/100 != 2) {
1069a747e4fSDavid du Colombier 	died:
1079a747e4fSDavid du Colombier 		close(fd);
1089a747e4fSDavid du Colombier 		Bterm(&bin);
1093ec9be0fSDavid du Colombier 		fprint(2, "%s: error talking to cddb server %s\n",
1103ec9be0fSDavid du Colombier 			argv0, server);
1119a747e4fSDavid du Colombier 		if(p) {
1129a747e4fSDavid du Colombier 			p[Blinelen(&bin)-1] = 0;
1133ec9be0fSDavid du Colombier 			fprint(2, "%s: server says: %s\n", argv0, p);
1149a747e4fSDavid du Colombier 		}
1159a747e4fSDavid du Colombier 		return -1;
1169a747e4fSDavid du Colombier 	}
1179a747e4fSDavid du Colombier 
1189a747e4fSDavid du Colombier 	fprint(fd, "cddb hello gre plan9 9cd 1.0\r\n");
1199a747e4fSDavid du Colombier 	if((p = Brdline(&bin, '\n')) == nil || atoi(p)/100 != 2)
1209a747e4fSDavid du Colombier 		goto died;
1219a747e4fSDavid du Colombier 
12255e9c1d6SDavid du Colombier 	/*
12355e9c1d6SDavid du Colombier 	 *	Protocol level 6 is the same as level 5 except that
12455e9c1d6SDavid du Colombier 	 *	the character set is now UTF-8 instead of ISO-8859-1.
12555e9c1d6SDavid du Colombier  	 */
12655e9c1d6SDavid du Colombier 	fprint(fd, "proto 6\r\n");
12755e9c1d6SDavid du Colombier 	DPRINT(2, "proto 6\r\n");
12855e9c1d6SDavid du Colombier 	if((p = Brdline(&bin, '\n')) == nil || atoi(p)/100 != 2)
12955e9c1d6SDavid du Colombier 		goto died;
13055e9c1d6SDavid du Colombier 	p[Blinelen(&bin)-1] = 0;
13155e9c1d6SDavid du Colombier 	DPRINT(2, "cddb: %s\n", p);
13255e9c1d6SDavid du Colombier 
1339a747e4fSDavid du Colombier 	fprint(fd, "cddb query %8.8lux %d", t->diskid, t->ntrack);
1349a747e4fSDavid du Colombier 	DPRINT(2, "cddb query %8.8lux %d", t->diskid, t->ntrack);
1359a747e4fSDavid du Colombier 	for(i=0; i<t->ntrack; i++) {
1369a747e4fSDavid du Colombier 		fprint(fd, " %d", t->track[i].n);
1379a747e4fSDavid du Colombier 		DPRINT(2, " %d", t->track[i].n);
1389a747e4fSDavid du Colombier 	}
1399a747e4fSDavid du Colombier 	fprint(fd, " %d\r\n", t->track[t->ntrack].n);
1409a747e4fSDavid du Colombier 	DPRINT(2, " %d\r\n", t->track[t->ntrack].n);
1419a747e4fSDavid du Colombier 
1429a747e4fSDavid du Colombier 	if((p = Brdline(&bin, '\n')) == nil || atoi(p)/100 != 2)
1439a747e4fSDavid du Colombier 		goto died;
1449a747e4fSDavid du Colombier 	p[Blinelen(&bin)-1] = 0;
1459a747e4fSDavid du Colombier 	DPRINT(2, "cddb: %s\n", p);
1469a747e4fSDavid du Colombier 	nf = tokenize(p, f, nelem(f));
1479a747e4fSDavid du Colombier 	if(nf < 1)
1489a747e4fSDavid du Colombier 		goto died;
1499a747e4fSDavid du Colombier 
1509a747e4fSDavid du Colombier 	switch(atoi(f[0])) {
1519a747e4fSDavid du Colombier 	case 200:	/* exact match */
1529a747e4fSDavid du Colombier 		if(nf < 3)
1539a747e4fSDavid du Colombier 			goto died;
1549a747e4fSDavid du Colombier 		categ = f[1];
1559a747e4fSDavid du Colombier 		id = f[2];
1569a747e4fSDavid du Colombier 		break;
157*fd87a217SDavid du Colombier 	case 210:	/* exact matches */
1589a747e4fSDavid du Colombier 	case 211:	/* close matches */
1599a747e4fSDavid du Colombier 		if((p = Brdline(&bin, '\n')) == nil)
1609a747e4fSDavid du Colombier 			goto died;
1619a747e4fSDavid du Colombier 		if(p[0] == '.')	/* no close matches? */
1629a747e4fSDavid du Colombier 			goto died;
1639a747e4fSDavid du Colombier 		p[Blinelen(&bin)-1] = '\0';
1649a747e4fSDavid du Colombier 
1659a747e4fSDavid du Colombier 		/* accept first match */
1669a747e4fSDavid du Colombier 		nf = tokenize(p, f, nelem(f));
1679a747e4fSDavid du Colombier 		if(nf < 2)
1689a747e4fSDavid du Colombier 			goto died;
1699a747e4fSDavid du Colombier 		categ = f[0];
1709a747e4fSDavid du Colombier 		id = f[1];
1719a747e4fSDavid du Colombier 
1729a747e4fSDavid du Colombier 		/* snarf rest of buffer */
1739a747e4fSDavid du Colombier 		while(p[0] != '.') {
1749a747e4fSDavid du Colombier 			if((p = Brdline(&bin, '\n')) == nil)
1759a747e4fSDavid du Colombier 				goto died;
1769a747e4fSDavid du Colombier 			p[Blinelen(&bin)-1] = '\0';
1779a747e4fSDavid du Colombier 			DPRINT(2, "cddb: %s\n", p);
1789a747e4fSDavid du Colombier 		}
1799a747e4fSDavid du Colombier 		break;
1809a747e4fSDavid du Colombier 	case 202: /* no match */
1819a747e4fSDavid du Colombier 	default:
1829a747e4fSDavid du Colombier 		goto died;
1839a747e4fSDavid du Colombier 	}
1849a747e4fSDavid du Colombier 
1859a747e4fSDavid du Colombier 	t->title = "";
1869a747e4fSDavid du Colombier 	for(i=0; i<t->ntrack; i++)
1879a747e4fSDavid du Colombier 		t->track[i].title = "";
1889a747e4fSDavid du Colombier 
1899a747e4fSDavid du Colombier 	/* fetch results for this cd */
1909a747e4fSDavid du Colombier 	fprint(fd, "cddb read %s %s\r\n", categ, id);
1919a747e4fSDavid du Colombier 	do {
1929a747e4fSDavid du Colombier 		if((p = Brdline(&bin, '\n')) == nil)
1939a747e4fSDavid du Colombier 			goto died;
1949a747e4fSDavid du Colombier 		q = p+Blinelen(&bin)-1;
1959a747e4fSDavid du Colombier 		while(isspace(*q))
1969a747e4fSDavid du Colombier 			*q-- = 0;
1979a747e4fSDavid du Colombier DPRINT(2, "cddb %s\n", p);
1989a747e4fSDavid du Colombier 		if(strncmp(p, "DTITLE=", 7) == 0)
1999a747e4fSDavid du Colombier 			t->title = append(t->title, p+7);
2009a747e4fSDavid du Colombier 		else if(strncmp(p, "TTITLE", 6) == 0 && isdigit(p[6])) {
2019a747e4fSDavid du Colombier 			i = atoi(p+6);
2029a747e4fSDavid du Colombier 			if(i < t->ntrack) {
2039a747e4fSDavid du Colombier 				p += 6;
2049a747e4fSDavid du Colombier 				while(isdigit(*p))
2059a747e4fSDavid du Colombier 					p++;
2069a747e4fSDavid du Colombier 				if(*p == '=')
2079a747e4fSDavid du Colombier 					p++;
2089a747e4fSDavid du Colombier 
2099a747e4fSDavid du Colombier 				t->track[i].title = append(t->track[i].title, estrdup(p));
2109a747e4fSDavid du Colombier 			}
2119a747e4fSDavid du Colombier 		}
2129a747e4fSDavid du Colombier 	} while(*p != '.');
2139a747e4fSDavid du Colombier 
2149a747e4fSDavid du Colombier 	fprint(fd, "quit\r\n");
2159a747e4fSDavid du Colombier 	close(fd);
2169a747e4fSDavid du Colombier 	Bterm(&bin);
2179a747e4fSDavid du Colombier 
2189a747e4fSDavid du Colombier 	return 0;
2199a747e4fSDavid du Colombier }
2209a747e4fSDavid du Colombier 
2219a747e4fSDavid du Colombier void
usage(void)2229a747e4fSDavid du Colombier usage(void)
2239a747e4fSDavid du Colombier {
2243ff48bf5SDavid du Colombier 	fprint(2, "usage: aux/cddb [-DTt] [-s server] query diskid n ...\n");
2259a747e4fSDavid du Colombier 	exits("usage");
2269a747e4fSDavid du Colombier }
2279a747e4fSDavid du Colombier 
2289a747e4fSDavid du Colombier void
main(int argc,char ** argv)2299a747e4fSDavid du Colombier main(int argc, char **argv)
2309a747e4fSDavid du Colombier {
2319a747e4fSDavid du Colombier 	int i;
2329a747e4fSDavid du Colombier 	Toc toc;
2339a747e4fSDavid du Colombier 
2349a747e4fSDavid du Colombier 	ARGBEGIN{
2359a747e4fSDavid du Colombier 	case 'D':
2369a747e4fSDavid du Colombier 		debug = 1;
2379a747e4fSDavid du Colombier 		break;
2389a747e4fSDavid du Colombier 	case 's':
2399a747e4fSDavid du Colombier 		server = EARGF(usage());
2409a747e4fSDavid du Colombier 		break;
2413ff48bf5SDavid du Colombier 	case 'T':
2423ff48bf5SDavid du Colombier 		Tflag = 1;
2433ff48bf5SDavid du Colombier 		/*FALLTHROUGH*/
2443ff48bf5SDavid du Colombier 	case 't':
2453ff48bf5SDavid du Colombier 		tflag = 1;
2463ff48bf5SDavid du Colombier 		break;
2479a747e4fSDavid du Colombier 	}ARGEND
2489a747e4fSDavid du Colombier 
2499a747e4fSDavid du Colombier 	if(argc < 3 || strcmp(argv[0], "query") != 0)
2509a747e4fSDavid du Colombier 		usage();
2519a747e4fSDavid du Colombier 
2529a747e4fSDavid du Colombier 	toc.diskid = strtoul(argv[1], 0, 16);
2539a747e4fSDavid du Colombier 	toc.ntrack = atoi(argv[2]);
2549a747e4fSDavid du Colombier 	if(argc != 3+toc.ntrack+1)
2559a747e4fSDavid du Colombier 		sysfatal("argument count does not match given ntrack");
2569a747e4fSDavid du Colombier 
2579a747e4fSDavid du Colombier 	for(i=0; i<=toc.ntrack; i++)
2589a747e4fSDavid du Colombier 		toc.track[i].n = atoi(argv[3+i]);
2599a747e4fSDavid du Colombier 
2609a747e4fSDavid du Colombier 	if(cddbfilltoc(&toc) < 0)
2619a747e4fSDavid du Colombier 		exits("whoops");
2629a747e4fSDavid du Colombier 
2639a747e4fSDavid du Colombier 	dumpcddb(&toc);
2649a747e4fSDavid du Colombier 	exits(nil);
2659a747e4fSDavid du Colombier }
266