GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/cdio/cddb.c Lines: 0 205 0.0 %
Date: 2016-12-06 Branches: 0 132 0.0 %

Line Branch Exec Source
1
/* $OpenBSD: cddb.c,v 1.20 2015/01/16 06:40:06 deraadt Exp $ */
2
/*
3
 * Copyright (c) 2002 Marc Espie.
4
 *
5
 * Redistribution and use in source and binary forms, with or without
6
 * modification, are permitted provided that the following conditions
7
 * are met:
8
 * 1. Redistributions of source code must retain the above copyright
9
 *    notice, this list of conditions and the following disclaimer.
10
 * 2. Redistributions in binary form must reproduce the above copyright
11
 *    notice, this list of conditions and the following disclaimer in the
12
 *    documentation and/or other materials provided with the distribution.
13
 *
14
 * THIS SOFTWARE IS PROVIDED BY THE OPENBSD PROJECT AND CONTRIBUTORS
15
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
16
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
17
 * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OPENBSD
18
 * PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
19
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
20
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25
 */
26
27
#include <sys/socket.h>
28
#include <netinet/in.h>
29
#include <sys/cdio.h>
30
#include <err.h>
31
#include <netdb.h>
32
#include <stdio.h>
33
#include <stdlib.h>
34
#include <string.h>
35
#include <unistd.h>
36
#include <limits.h>
37
#include <vis.h>
38
#include "extern.h"
39
40
unsigned long	cddb_sum(unsigned long);
41
void		send_hello(FILE *);
42
void		send_query(FILE *, int, struct cd_toc_entry *);
43
int		further_query(FILE *, char *);
44
int		connect_to(const char *, const char *);
45
int		parse_connect_to(const char *, const char *);
46
char *		get_line(FILE *);
47
char *		get_answer(FILE *);
48
void		verify_track_names(char **, int, struct cd_toc_entry *);
49
void		safe_copy(char **, const char *);
50
51
unsigned long
52
cddb_sum(unsigned long v)
53
{
54
	unsigned long sum = 0;
55
56
	while (v > 0) {
57
		sum += v % 10;
58
		v /= 10;
59
	}
60
	return (sum);
61
}
62
63
unsigned long
64
cddb_discid(int n, struct cd_toc_entry *e)
65
{
66
	unsigned long sum;
67
	int i;
68
69
	sum = 0;
70
	for (i =0; i < n; i++)
71
		sum += cddb_sum(entry2time(e+i));
72
	return (((sum % 0xff) << 24) |
73
	    ((entry2time(e+n) - entry2time(e)) << 8) | n);
74
}
75
76
void
77
send_hello(FILE *cout)
78
{
79
	char hostname[HOST_NAME_MAX+1];
80
81
	if (gethostname(hostname, sizeof(hostname)) == -1)
82
		strlcpy(hostname, "unknown", sizeof hostname);
83
	fprintf(cout, "CDDB HELLO %s %s cdio " VERSION "\r\n",
84
	    getlogin(), hostname);
85
	fflush(cout);
86
}
87
88
void
89
send_query(FILE *f, int n, struct cd_toc_entry *e)
90
{
91
	int i;
92
93
	fprintf(f, "cddb query %8lx %d", cddb_discid(n, e), n);
94
	for (i = 0; i < n; i++)
95
		fprintf(f, " %lu", entry2frames(e+i));
96
	fprintf(f, " %lu\r\n", (entry2frames(e+n)-entry2frames(e)) /75);
97
}
98
99
#define MAXSIZE 256
100
char copy_buffer[MAXSIZE];
101
102
void
103
safe_copy(char **p, const char *title)
104
{
105
	strnvis(copy_buffer, title, MAXSIZE-1, VIS_TAB|VIS_NL);
106
	if (*p == NULL)
107
		*p = strdup(copy_buffer);
108
	else {
109
		char *n;
110
111
		if (asprintf(&n, "%s%s", *p, copy_buffer) == -1)
112
			return;
113
		free(*p);
114
		*p = n;
115
	}
116
}
117
118
int
119
further_query(FILE *cout, char *line)
120
{
121
	char *key;
122
	char *title;
123
124
	key = strchr(line, ' ');
125
	if (!key)
126
		return 0;
127
	*key++ = 0;
128
	title = strchr(key, ' ');
129
	if (!title)
130
		return 0;
131
	*title++ = 0;
132
	strnvis(copy_buffer, title, MAXSIZE-1, VIS_TAB|VIS_NL);
133
	printf("%s", copy_buffer);
134
	strnvis(copy_buffer, line, MAXSIZE-1, VIS_TAB|VIS_NL);
135
	printf("(%s)\n", copy_buffer);
136
	fprintf(cout, "CDDB READ %s %s\r\n", line, key);
137
	fflush(cout);
138
	return 1;
139
}
140
141
142
int
143
connect_to(const char *host, const char *serv)
144
{
145
	int s = -1;
146
	struct addrinfo hints, *res0 = NULL, *res;
147
	int error;
148
149
	memset(&hints, 0, sizeof hints);
150
	hints.ai_family = PF_UNSPEC;
151
	hints.ai_socktype = SOCK_STREAM;
152
153
	error = getaddrinfo(host, serv, &hints, &res0);
154
	if (error) {
155
		warnx("%s", gai_strerror(error));
156
		return -1;
157
	}
158
159
	for (res = res0; res; res = res->ai_next) {
160
		s = socket(res->ai_family, res->ai_socktype,
161
		    res->ai_protocol);
162
		if (s == -1)
163
			continue;
164
		if (connect(s, res->ai_addr, res->ai_addrlen) == -1) {
165
			close(s);
166
			s = -1;
167
			continue;
168
		}
169
		break;
170
	}
171
	if (s == -1)
172
		warn("cddb");
173
	freeaddrinfo(res0);
174
	return s;
175
}
176
177
int
178
parse_connect_to(const char *host_port, const char *port)
179
{
180
	int s;
181
	char *last, *host;
182
183
	host = (char *)host_port;
184
185
	last = strrchr(host_port, ':');
186
	if (last != 0 && !(last != host && last[-1] == ':')) {
187
		port = last + 1;
188
		host = malloc(last - host_port + 1);
189
		if (!host)
190
			return -1;
191
		memcpy(host, host_port, last-host_port);
192
		host[last-host_port] = 0;
193
	}
194
	s = connect_to(host, port);
195
	if (host != host_port)
196
		free(host);
197
	return s;
198
}
199
200
char *
201
get_line(FILE *cin)
202
{
203
	char *line;
204
	size_t len;
205
206
	line = fgetln(cin, &len);
207
	if (!line)
208
		return NULL;
209
	if (len == 0)
210
		return NULL;
211
	if (line[len-1] == '\n')
212
		line[--len] = 0;
213
	if (len != 0 && line[len-1] == '\r')
214
		line[--len] = 0;
215
	if (line[len] != 0)
216
		return NULL;
217
	return line;
218
}
219
220
char *
221
get_answer(FILE *cin)
222
{
223
	char *line;
224
225
	line = get_line(cin);
226
	if (!line || *line != '2')
227
		return NULL;
228
	else
229
		return line;
230
}
231
232
void
233
verify_track_names(char **names, int n, struct cd_toc_entry *e)
234
{
235
	int i;
236
237
	for (i = 0; i < n; i++) {
238
		if (names[i] == 0)
239
			names[i] = strdup(e->control & 4 ? "data" : "audio");
240
	}
241
}
242
243
char **
244
cddb(const char *host_port, int n, struct cd_toc_entry *e, char *arg)
245
{
246
	int s = -1;
247
	int s2 = -1;
248
	FILE *cin = NULL;
249
	FILE *cout = NULL;
250
	char *type;
251
	char *line;
252
	char **result = NULL;
253
	int i;
254
	const char *errstr;
255
256
	s = parse_connect_to(host_port, "cddb");
257
	if (s == -1)
258
		goto end;
259
	s2 = dup(s);
260
	if (s2 == -1)
261
		goto end;
262
	cin = fdopen(s, "r");
263
	if (!cin) {
264
		warn("cddb: fdopen");
265
		goto end;
266
	}
267
	s = -1;
268
	cout = fdopen(s2, "w");
269
	if (!cout) {
270
		warn("cddb: fdopen");
271
		goto end;
272
	}
273
	s2 = -1;
274
	line = get_answer(cin);
275
	if (!line) {
276
		warnx("cddb: won't talk to us");
277
		goto end;
278
	}
279
280
	send_hello(cout);
281
	line = get_answer(cin);
282
	if (!line) {
283
		warnx("cddb: problem in hello");
284
		goto end;
285
	}
286
287
	send_query(cout, n, e);
288
	fflush(cout);
289
	line = get_answer(cin);
290
	if (!line) {
291
		warnx("cddb: problem in query");
292
		goto end;
293
	}
294
	type = strchr(line, ' ');
295
	if (!type)
296
		goto end;
297
	*type++ = 0;
298
	/* no match or other issue */
299
	if (strcmp(line, "202") == 0) {
300
		printf("cddb: No match in database\n");
301
		goto end;
302
	}
303
	if (strcmp(line, "211") == 0 || strcmp(line, "212") == 0) {
304
		int number = strtonum(arg, 0, INT_MAX, &errstr);
305
		if (errstr != NULL && *arg != '\0') {
306
			warnx("cddb: invalid index");
307
			goto end;
308
		}
309
		if (number == 0) {
310
			if (strcmp(line, "211") == 0)
311
				printf("cddb: multiple matches\n");
312
			else {
313
				printf("cddb: inexact match\n");
314
				number = 1;
315
			}
316
		}
317
		if (number == 0) {
318
			for (i = 1;; i++) {
319
				line = get_line(cin);
320
				if (!line || strcmp(line, ".") == 0)
321
					goto end;
322
				printf("%d: %s\n", i, line);
323
			}
324
		} else {
325
			int ok = 0;
326
327
			for (i = 1;; i++) {
328
				line = get_line(cin);
329
				if (!line)
330
					break;
331
				if (strcmp(line, ".") == 0)
332
					break;
333
				if (i == number)
334
					ok = further_query(cout, line);
335
			}
336
			if (!ok)
337
				goto end;
338
		}
339
	} else if (strcmp(line, "200") != 0 || !further_query(cout, type))
340
		goto end;
341
	result = calloc(sizeof(char *), n + 1);
342
	if (!result)
343
		goto end;
344
	for (i = 0; i <= n; i++)
345
		result[i] = NULL;
346
	line = get_answer(cin);
347
	if (!line)
348
		goto end2;
349
	for (;;) {
350
		int k;
351
		char *end;
352
353
		line = get_line(cin);
354
		if (!line)
355
			goto end2;
356
		if (strcmp(line, ".") == 0)
357
			break;
358
		if (strncmp(line, "TTITLE", 6) != 0)
359
			continue;
360
		line += 6;
361
		end = strchr(line, '=');
362
		if (end == NULL)
363
			continue;
364
		*end++ = '\0';
365
		k = strtonum(line, 0, n - 1, &errstr);
366
		if (errstr != NULL)
367
			continue;
368
		safe_copy(&result[k], end);
369
	}
370
	fprintf(cout, "QUIT\r\n");
371
	verify_track_names(result, n, e);
372
	goto end;
373
end2:
374
	free(result);
375
	result = NULL;
376
end:
377
	if (cout)
378
		fclose(cout);
379
	if (cin)
380
		fclose(cin);
381
	if (s != -1)
382
		close(s);
383
	if (s2 != -1)
384
		close(s2);
385
	return result;
386
}
387
388
void
389
free_names(char **names)
390
{
391
	int i;
392
393
	for (i = 0; names[i]; i++)
394
		free(names[i]);
395
	free(names);
396
}