Subversion Repositories planix.SVN

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
#include <u.h>
2
#include <libc.h>
3
#include <bio.h>
4
#include <ctype.h>
5
 
6
char *server = "freedb.freedb.org";
7
 
8
int debug;
9
#define DPRINT if(debug)fprint
10
int tflag;
11
int Tflag;
12
 
13
typedef struct Track Track;
14
struct Track {
15
	int n;
16
	char *title;
17
};
18
 
19
enum {
20
	MTRACK = 64,
21
};
22
 
23
typedef struct Toc Toc;
24
struct Toc {
25
	ulong diskid;
26
	int ntrack;
27
	char *title;
28
	Track track[MTRACK];
29
};
30
 
31
void*
32
emalloc(uint n)
33
{
34
	void *p;
35
 
36
	p = malloc(n);
37
	if(p == nil)
38
		sysfatal("can't malloc: %r");
39
	memset(p, 0, n);
40
	return p;
41
}
42
 
43
char*
44
estrdup(char *s)
45
{
46
	char *t;
47
 
48
	t = emalloc(strlen(s)+1);
49
	strcpy(t, s);
50
	return t;
51
}
52
 
53
static void
54
dumpcddb(Toc *t)
55
{
56
	int i, n, s;
57
 
58
	print("title	%s\n", t->title);
59
	for(i=0; i<t->ntrack; i++){
60
		if(tflag){
61
			n = t->track[i+1].n;
62
			if(i == t->ntrack-1)
63
				n *= 75;
64
			s = (n - t->track[i].n)/75;
65
			print("%d\t%s\t%d:%2.2d\n", i+1, t->track[i].title, s/60, s%60);
66
		}
67
		else
68
			print("%d\t%s\n", i+1, t->track[i].title);
69
	}
70
	if(Tflag){
71
		s = t->track[i].n;
72
		print("Total time: %d:%2.2d\n", s/60, s%60);
73
	}
74
}
75
 
76
char*
77
append(char *a, char *b)
78
{
79
	char *c;
80
 
81
	c = emalloc(strlen(a)+strlen(b)+1);
82
	strcpy(c, a);
83
	strcat(c, b);
84
	return c;
85
}
86
 
87
static int
88
cddbfilltoc(Toc *t)
89
{
90
	int fd;
91
	int i;
92
	char *p, *q;
93
	Biobuf bin;
94
	char *f[10];
95
	int nf;
96
	char *id, *categ;
97
 
98
	fd = dial(netmkaddr(server, "tcp", "888"), 0, 0, 0);
99
	if(fd < 0) {
100
		fprint(2, "%s: %s: cannot dial: %r\n", argv0, server);
101
		return -1;
102
	}
103
	Binit(&bin, fd, OREAD);
104
 
105
	if((p=Brdline(&bin, '\n')) == nil || atoi(p)/100 != 2) {
106
	died:
107
		close(fd);
108
		Bterm(&bin);
109
		fprint(2, "%s: error talking to cddb server %s\n",
110
			argv0, server);
111
		if(p) {
112
			p[Blinelen(&bin)-1] = 0;
113
			fprint(2, "%s: server says: %s\n", argv0, p);
114
		}
115
		return -1;
116
	}
117
 
118
	fprint(fd, "cddb hello gre plan9 9cd 1.0\r\n");
119
	if((p = Brdline(&bin, '\n')) == nil || atoi(p)/100 != 2)
120
		goto died;
121
 
122
	/*
123
	 *	Protocol level 6 is the same as level 5 except that
124
	 *	the character set is now UTF-8 instead of ISO-8859-1. 
125
 	 */
126
	fprint(fd, "proto 6\r\n");
127
	DPRINT(2, "proto 6\r\n");
128
	if((p = Brdline(&bin, '\n')) == nil || atoi(p)/100 != 2)
129
		goto died;
130
	p[Blinelen(&bin)-1] = 0;
131
	DPRINT(2, "cddb: %s\n", p);
132
 
133
	fprint(fd, "cddb query %8.8lux %d", t->diskid, t->ntrack);
134
	DPRINT(2, "cddb query %8.8lux %d", t->diskid, t->ntrack);
135
	for(i=0; i<t->ntrack; i++) {
136
		fprint(fd, " %d", t->track[i].n);
137
		DPRINT(2, " %d", t->track[i].n);
138
	}
139
	fprint(fd, " %d\r\n", t->track[t->ntrack].n);
140
	DPRINT(2, " %d\r\n", t->track[t->ntrack].n);
141
 
142
	if((p = Brdline(&bin, '\n')) == nil || atoi(p)/100 != 2)
143
		goto died;
144
	p[Blinelen(&bin)-1] = 0;
145
	DPRINT(2, "cddb: %s\n", p);
146
	nf = tokenize(p, f, nelem(f));
147
	if(nf < 1)
148
		goto died;
149
 
150
	switch(atoi(f[0])) {
151
	case 200:	/* exact match */
152
		if(nf < 3)
153
			goto died;
154
		categ = f[1];
155
		id = f[2];
156
		break;
157
	case 210:	/* exact matches */
158
	case 211:	/* close matches */
159
		if((p = Brdline(&bin, '\n')) == nil)
160
			goto died;
161
		if(p[0] == '.')	/* no close matches? */
162
			goto died;
163
		p[Blinelen(&bin)-1] = '\0';
164
 
165
		/* accept first match */
166
		nf = tokenize(p, f, nelem(f));
167
		if(nf < 2)
168
			goto died;
169
		categ = f[0];
170
		id = f[1];
171
 
172
		/* snarf rest of buffer */
173
		while(p[0] != '.') {
174
			if((p = Brdline(&bin, '\n')) == nil)
175
				goto died;
176
			p[Blinelen(&bin)-1] = '\0';
177
			DPRINT(2, "cddb: %s\n", p);
178
		}
179
		break;
180
	case 202: /* no match */
181
	default:
182
		goto died;
183
	}
184
 
185
	t->title = "";
186
	for(i=0; i<t->ntrack; i++)
187
		t->track[i].title = "";
188
 
189
	/* fetch results for this cd */
190
	fprint(fd, "cddb read %s %s\r\n", categ, id);
191
	do {
192
		if((p = Brdline(&bin, '\n')) == nil)
193
			goto died;
194
		q = p+Blinelen(&bin)-1;
195
		while(isspace(*q))
196
			*q-- = 0;
197
DPRINT(2, "cddb %s\n", p);
198
		if(strncmp(p, "DTITLE=", 7) == 0)
199
			t->title = append(t->title, p+7);
200
		else if(strncmp(p, "TTITLE", 6) == 0 && isdigit(p[6])) {
201
			i = atoi(p+6);
202
			if(i < t->ntrack) {
203
				p += 6;
204
				while(isdigit(*p))
205
					p++;
206
				if(*p == '=')
207
					p++;
208
 
209
				t->track[i].title = append(t->track[i].title, estrdup(p));
210
			}
211
		} 
212
	} while(*p != '.');
213
 
214
	fprint(fd, "quit\r\n");
215
	close(fd);
216
	Bterm(&bin);
217
 
218
	return 0;
219
}
220
 
221
void
222
usage(void)
223
{
224
	fprint(2, "usage: aux/cddb [-DTt] [-s server] query diskid n ...\n");
225
	exits("usage");
226
}
227
 
228
void
229
main(int argc, char **argv)
230
{
231
	int i;
232
	Toc toc;
233
 
234
	ARGBEGIN{
235
	case 'D':
236
		debug = 1;
237
		break;
238
	case 's':
239
		server = EARGF(usage());
240
		break;
241
	case 'T':
242
		Tflag = 1;
243
		/*FALLTHROUGH*/
244
	case 't':
245
		tflag = 1;
246
		break;
247
	}ARGEND
248
 
249
	if(argc < 3 || strcmp(argv[0], "query") != 0)
250
		usage();
251
 
252
	toc.diskid = strtoul(argv[1], 0, 16);
253
	toc.ntrack = atoi(argv[2]);
254
	if(argc != 3+toc.ntrack+1)
255
		sysfatal("argument count does not match given ntrack");
256
 
257
	for(i=0; i<=toc.ntrack; i++)
258
		toc.track[i].n = atoi(argv[3+i]);
259
 
260
	if(cddbfilltoc(&toc) < 0)
261
		exits("whoops");
262
 
263
	dumpcddb(&toc);
264
	exits(nil);
265
}