1 /*
2 $Id: cddb_cmd.c,v 1.66 2007/08/07 03:12:53 jcaratzas Exp $
3
4 Copyright (C) 2003, 2004, 2005 Kris Verbeeck <airborne@advalvas.be>
5
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Library General Public
8 License as published by the Free Software Foundation; either
9 version 2 of the License, or (at your option) any later version.
10
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Library General Public License for more details.
15
16 You should have received a copy of the GNU Library General Public
17 License along with this library; if not, write to the
18 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA.
20 */
21
22 #include <errno.h>
23 #include <stdarg.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <sys/types.h>
27 #include <sys/stat.h>
28 #include <unistd.h>
29
30 #include "cddb/cddb_ni.h"
31 #include "cddb/ll.h"
32
33
34 static const char *CDDB_COMMANDS[CMD_LAST] = {
35 "cddb hello %s %s %s %s",
36 "quit",
37 "cddb read %s %08x",
38 "cddb query %08x %d %s %d",
39 "cddb write %s %08x",
40 "proto %d",
41 "sites",
42 "words=%s%s", /* special full text search command (only HTTP) */
43 "cddb album %s / %s",
44 };
45
46 #define WRITE_BUF_SIZE 4096
47
48
49 /*
50 * Small memory cache for querying local database.
51 */
52 #define QUERY_CACHE_SIZE 256
53 static struct query_cache_entry {
54 unsigned int discid;
55 cddb_cat_t category;
56 } query_cache[QUERY_CACHE_SIZE];
57
58
59 /* --- prototypes --- */
60
61
62 /**
63 * @return the line read or NULL if something goes wrong
64 */
65 char *cddb_read_line(cddb_conn_t *c);
66
67 /**
68 * @returns The amount of data written into the buffer.
69 */
70 int cddb_write_data(cddb_conn_t *c, char *buf, int size, cddb_disc_t *disc);
71
72 int cddb_http_parse_response(cddb_conn_t *c);
73
74 void cddb_http_parse_headers(cddb_conn_t *c);
75
76 int cddb_http_send_cmd(cddb_conn_t *c, cddb_cmd_t cmd, va_list args);
77
78 int cddb_parse_record(cddb_conn_t *c, cddb_disc_t *disc);
79
80 static int cddb_parse_query_data(cddb_conn_t *c, cddb_disc_t *disc,
81 const char *line);
82
83 static int cddb_handle_response_list(cddb_conn_t *c, cddb_disc_t *disc);
84
85 static int cddb_parse_search_data(cddb_conn_t *c, cddb_disc_t **disc,
86 char *line, regmatch_t *matches);
87
88 static void cddb_search_param_str(cddb_search_params_t *params,
89 char *buf, int len);
90
91 char *cddb_cache_file_name(cddb_conn_t *c, cddb_disc_t *disc);
92
93 int cddb_cache_exists(cddb_conn_t *c, cddb_disc_t *disc);
94
95 int cddb_cache_open(cddb_conn_t *c, cddb_disc_t *disc, const char* mode);
96
97 void cddb_cache_close(cddb_conn_t *c);
98
99 int cddb_cache_read(cddb_conn_t *c, cddb_disc_t *disc);
100
101 int cddb_cache_query(cddb_conn_t *c, cddb_disc_t *disc);
102
103 int cddb_cache_query_disc(cddb_conn_t *c, cddb_disc_t *disc);
104
105 /**
106 * Initialize the local query cache.
107 */
108 void cddb_cache_query_init(void);
109
110 int cddb_cache_mkdir(cddb_conn_t *c, cddb_disc_t *disc);
111
112
113 /* --- CDDB slave routines --- */
114
115
cddb_cache_file_name(cddb_conn_t * c,cddb_disc_t * disc)116 char *cddb_cache_file_name(cddb_conn_t *c, cddb_disc_t *disc)
117 {
118 char *fn = NULL;
119 int len;
120
121 /* calculate needed buffer size (+11 for two slashes, disc id and
122 terminating zero */
123 len = strlen(c->cache_dir) + strlen(CDDB_CATEGORY[disc->category]) + 11;
124 /* reserve enough memory */
125 fn = (char*)malloc(len + 1);
126 /* create file name */
127 if (fn) {
128 snprintf(fn, len + 1, "%s/%s/%08x", c->cache_dir,
129 CDDB_CATEGORY[disc->category], disc->discid);
130 } else {
131 cddb_errno_log_crit(c, CDDB_ERR_OUT_OF_MEMORY);
132 }
133 return fn;
134 }
135
cddb_cache_exists(cddb_conn_t * c,cddb_disc_t * disc)136 int cddb_cache_exists(cddb_conn_t *c, cddb_disc_t *disc)
137 {
138 int rv = FALSE;
139 char *fn = NULL;
140 struct stat buf;
141
142 cddb_log_debug("cddb_cache_exists()");
143 /* try to stat cache file */
144 fn = cddb_cache_file_name(c, disc);
145 if (fn) {
146 if ((stat(fn, &buf) == -1) || !S_ISREG(buf.st_mode)) {
147 cddb_log_debug("...not in cache");
148 } else {
149 cddb_log_debug("...in cache");
150 rv = TRUE;
151 }
152 }
153 FREE_NOT_NULL(fn);
154 return rv;
155 }
156
cddb_cache_open(cddb_conn_t * c,cddb_disc_t * disc,const char * mode)157 int cddb_cache_open(cddb_conn_t *c, cddb_disc_t *disc, const char* mode)
158 {
159 int rv = FALSE;
160 char *fn = NULL;
161
162 cddb_log_debug("cddb_cache_open()");
163 /* close previous entry */
164 cddb_cache_close(c);
165 /* open new entry */
166 fn = cddb_cache_file_name(c, disc);
167 if (fn) {
168 c->cache_fp = fopen(fn, mode);
169 rv = (c->cache_fp != NULL);
170 }
171 FREE_NOT_NULL(fn);
172 return rv;
173 }
174
cddb_cache_close(cddb_conn_t * c)175 void cddb_cache_close(cddb_conn_t *c)
176 {
177 if (c->cache_fp != NULL) {
178 cddb_log_debug("cddb_cache_close()");
179 fclose(c->cache_fp);
180 c->cache_fp = NULL;
181 }
182 }
183
cddb_cache_read(cddb_conn_t * c,cddb_disc_t * disc)184 int cddb_cache_read(cddb_conn_t *c, cddb_disc_t *disc)
185 {
186 int rv;
187
188 cddb_log_debug("cddb_cache_read()");
189 if (c->use_cache == CACHE_OFF) {
190 /* don't use cache */
191 cddb_log_debug("...cache disabled");
192 return FALSE;
193 }
194
195 /* check whether cached version exists */
196 if (!cddb_cache_exists(c, disc)) {
197 /* no cached version available */
198 cddb_log_debug("...no cached version found");
199 return FALSE;
200 }
201
202 /* try to open cache file */
203 if (!cddb_cache_open(c, disc, "r")) {
204 /* cached version not readable */
205 char *fn = cddb_cache_file_name(c, disc);
206 cddb_log_warn("cache file not readable: %s", fn);
207 FREE_NOT_NULL(fn);
208 return FALSE;
209 }
210
211 /* parse CDDB record */
212 cddb_log_debug("...cached version found");
213 c->cache_read = TRUE;
214 rv = cddb_parse_record(c, disc);
215 c->cache_read = FALSE;
216
217 /* close cache entry */
218 cddb_cache_close(c);
219
220 return rv;
221 }
222
cddb_cache_query_init(void)223 void cddb_cache_query_init(void)
224 {
225 static int query_cache_init = FALSE;
226 int i;
227
228 if (!query_cache_init) {
229 for (i = 0; i < sizeof(QUERY_CACHE_SIZE); i++) {
230 query_cache[i].category = CDDB_CAT_INVALID;
231 }
232 query_cache_init = TRUE;
233 }
234 }
235
236 /* use upper 8 bits of disc ID as hash */
237 #define cddb_cache_query_hash(disc) ((disc)->discid >> 24)
238
cddb_cache_query(cddb_conn_t * c,cddb_disc_t * disc)239 int cddb_cache_query(cddb_conn_t *c, cddb_disc_t *disc)
240 {
241 int hash;
242
243 cddb_log_debug("cddb_cache_query()");
244 if (c->use_cache == CACHE_OFF) {
245 /* don't use cache */
246 cddb_log_debug("...cache disabled");
247 return FALSE;
248 }
249
250 /* initialize memory cache */
251 cddb_cache_query_init();
252
253 /* calculate disc hash */
254 hash = cddb_cache_query_hash(disc);
255
256 /* data already in memory? */
257 if (query_cache[hash].discid == disc->discid) {
258 cddb_log_debug("...entry found in memory");
259 disc->category = query_cache[hash].category;
260 cddb_errno_set(c, CDDB_ERR_OK);
261 return TRUE;
262 }
263
264 /* search local database on disc */
265 return cddb_cache_query_disc(c, disc);
266 }
267
cddb_cache_query_disc(cddb_conn_t * c,cddb_disc_t * disc)268 int cddb_cache_query_disc(cddb_conn_t *c, cddb_disc_t *disc)
269 {
270 int cat, hash;
271
272 cddb_log_debug("cddb_cache_query_disc()");
273 for (cat = CDDB_CAT_DATA; cat < CDDB_CAT_INVALID; cat++) {
274 disc->category = cat;
275 if (cddb_cache_exists(c, disc)) {
276 /* update memory cache */
277 hash = cddb_cache_query_hash(disc);
278 query_cache[hash].discid = disc->discid;
279 query_cache[hash].category = disc->category;
280 cddb_log_debug("...entry found in local db");
281 cddb_errno_set(c, CDDB_ERR_OK);
282 return TRUE;
283 }
284 }
285 disc->category = CDDB_CAT_INVALID;
286 cddb_log_debug("...entry not found in local db");
287 return FALSE;
288 }
289
290 #if defined( WIN32 )
291 #define MKDIR(dir, mode) mkdir(dir)
292 #else
293 #define MKDIR(dir, mode) mkdir(dir, mode)
294 #endif
295
cddb_cache_mkdir(cddb_conn_t * c,cddb_disc_t * disc)296 int cddb_cache_mkdir(cddb_conn_t *c, cddb_disc_t *disc)
297 {
298 char *fn = NULL;
299
300 cddb_log_debug("cddb_cache_mkdir()");
301 /* create CDDB slave dir */
302 if ((MKDIR(c->cache_dir, 0755) == -1) && (errno != EEXIST)) {
303 cddb_log_error("could not create cache directory: %s", c->cache_dir);
304 return FALSE;
305 }
306
307 /* create category dir */
308 fn = (char*)malloc(c->buf_size);
309 snprintf(fn, c->buf_size, "%s/%s", c->cache_dir, CDDB_CATEGORY[disc->category]);
310 if ((MKDIR(fn, 0755) == -1) && (errno != EEXIST)) {
311 cddb_log_error("could not create category directory: %s", fn);
312 free(fn);
313 return FALSE;
314 }
315 free(fn);
316
317 return TRUE;
318 }
319
320
321 /* --- server request / response handling --- */
322
323
cddb_get_response_code(cddb_conn_t * c,char ** msg)324 int cddb_get_response_code(cddb_conn_t *c, char **msg)
325 {
326 char *line, *space;
327 int code, rv;
328
329 cddb_log_debug("cddb_get_response_code()");
330 line = cddb_read_line(c);
331 if (!line) {
332 if (cddb_errno(c) != CDDB_ERR_OK) {
333 cddb_errno_log_error(c, CDDB_ERR_UNEXPECTED_EOF);
334 }
335 return -1;
336 }
337
338 rv = sscanf(line, "%d", &code);
339 if (rv != 1) {
340 cddb_errno_log_error(c, CDDB_ERR_INVALID_RESPONSE);
341 return -1;
342 }
343
344 space = strchr(line, CHR_SPACE);
345 if (space == NULL) {
346 cddb_errno_log_error(c, CDDB_ERR_INVALID_RESPONSE);
347 return -1;
348 }
349 *msg = space + 1; /* message starts after space */
350
351 cddb_errno_set(c, CDDB_ERR_OK);
352 cddb_log_debug("...code = %d (%s)", code, *msg);
353 return code;
354 }
355
cddb_read_line(cddb_conn_t * c)356 char *cddb_read_line(cddb_conn_t *c)
357 {
358 char *s;
359
360 cddb_log_debug("cddb_read_line()");
361 /* read line, possibly returning NULL */
362 if (c->cache_read) {
363 s = fgets(c->line, c->buf_size, cddb_cache_file(c));
364 } else {
365 s = sock_fgets(c->line, c->buf_size, c);
366 }
367
368 /* strip off any line-terminating characters */
369 if (s) {
370 s = s + strlen(s) - 1;
371 while ((s >= c->line) &&
372 ((*s == CHR_CR) || (*s == CHR_LF))) {
373 *s = CHR_EOS;
374 s--;
375 }
376 } else {
377 return NULL;
378 }
379
380 cddb_errno_set(c, CDDB_ERR_OK);
381 cddb_log_debug("...[%c] line = '%s'", (c->cache_read ? 'C' : 'N'), c->line);
382 return c->line;
383 }
384
url_encode(char * s)385 static void url_encode(char *s)
386 {
387 while (*s) {
388 switch (*s) {
389 case ' ': *s = '+'; break;
390 }
391 s++;
392 }
393 }
394
cddb_http_parse_response(cddb_conn_t * c)395 int cddb_http_parse_response(cddb_conn_t *c)
396 {
397 char *line;
398 int code;
399
400 if ((line = cddb_read_line(c)) == NULL) {
401 /* no HTTP response line */
402 cddb_errno_log_error(c, CDDB_ERR_UNEXPECTED_EOF);
403 return FALSE;
404 }
405
406 if (sscanf(line, "%*s %d %*s", &code) != 1) {
407 /* invalid */
408 cddb_errno_log_error(c, CDDB_ERR_INVALID_RESPONSE);
409 return FALSE;
410 }
411
412 cddb_log_debug("...HTTP response code = %d", code);
413 switch (code) {
414 case 200:
415 /* HTTP OK */
416 break;
417 case 407:
418 cddb_errno_log_error(c, CDDB_ERR_PROXY_AUTH);
419 return FALSE;
420 break;
421 default:
422 /* anythign else = error */
423 cddb_errno_log_error(c, CDDB_ERR_SERVER_ERROR);
424 return FALSE;
425 }
426
427 cddb_errno_set(c, CDDB_ERR_OK);
428 return TRUE;
429 }
430
cddb_http_parse_headers(cddb_conn_t * c)431 void cddb_http_parse_headers(cddb_conn_t *c)
432 {
433 char *line;
434
435 cddb_log_debug("cddb_http_parse_headers()");
436 while (((line = cddb_read_line(c)) != NULL) &&
437 (*line != CHR_EOS)) {
438 /* no-op */
439 }
440 }
441
cddb_add_proxy_auth(cddb_conn_t * c)442 static int cddb_add_proxy_auth(cddb_conn_t *c)
443 {
444 /* send proxy authorization if credentials are set */
445 if (c->http_proxy_auth) {
446 sock_fprintf(c, "Proxy-Authorization: Basic %s\r\n", c->http_proxy_auth);
447 }
448 return TRUE;
449 }
450
cddb_http_send_cmd(cddb_conn_t * c,cddb_cmd_t cmd,va_list args)451 int cddb_http_send_cmd(cddb_conn_t *c, cddb_cmd_t cmd, va_list args)
452 {
453 cddb_log_debug("cddb_http_send_cmd()");
454 switch (cmd) {
455 case CMD_WRITE:
456 /* entry submission (POST method) */
457 {
458 char *category;
459 int discid, size;
460
461 category = va_arg(args, char *);
462 discid = va_arg(args, int);
463 size = va_arg(args, int);
464
465 if (c->is_http_proxy_enabled) {
466 /* use an HTTP proxy */
467 sock_fprintf(c, "POST http://%s:%d%s HTTP/1.0\r\n",
468 c->server_name, c->server_port, c->http_path_submit);
469 sock_fprintf(c, "Host: %s:%d\r\n",
470 c->server_name, c->server_port);
471 cddb_add_proxy_auth(c);
472 } else {
473 /* direct connection */
474 sock_fprintf(c, "POST %s HTTP/1.0\r\n", c->http_path_submit);
475 }
476
477 sock_fprintf(c, "Category: %s\r\n", category);
478 sock_fprintf(c, "Discid: %08x\r\n", discid);
479 sock_fprintf(c, "User-Email: %s@%s\r\n", c->user, c->hostname);
480 sock_fprintf(c, "Submit-Mode: submit\r\n");
481 sock_fprintf(c, "Content-Length: %d\r\n", size);
482 sock_fprintf(c, "Charset: UTF-8\r\n");
483 sock_fprintf(c, "\r\n");
484 }
485 break;
486 default:
487 /* anything else */
488 {
489 char *buf;
490 int rv;
491
492 if (c->is_http_proxy_enabled) {
493 /* use an HTTP proxy */
494 sock_fprintf(c, "GET http://%s:%d%s?",
495 c->server_name, c->server_port, c->http_path_query);
496 } else {
497 /* direct connection */
498 sock_fprintf(c, "GET %s?", c->http_path_query);
499 }
500
501 buf = (char*)malloc(c->buf_size);
502 rv = vsnprintf(buf, c->buf_size, CDDB_COMMANDS[cmd], args);
503 if (rv < 0 || rv >= c->buf_size) {
504 /* buffer is too small */
505 cddb_errno_log_crit(c, CDDB_ERR_LINE_SIZE);
506 return FALSE;
507 }
508 url_encode(buf);
509 if (cmd == CMD_SEARCH) {
510 sock_fprintf(c, "%s", buf);
511 } else {
512 sock_fprintf(c, "cmd=%s&", buf);
513 sock_fprintf(c, "hello=%s+%s+%s+%s&",
514 c->user, c->hostname, c->cname, c->cversion);
515 sock_fprintf(c, "proto=%d", DEFAULT_PROTOCOL_VERSION);
516 }
517 free(buf);
518 sock_fprintf(c, " HTTP/1.0\r\n");
519
520 if (c->is_http_proxy_enabled) {
521 /* insert host header */
522 sock_fprintf(c, "Host: %s:%d\r\n",
523 c->server_name, c->server_port);
524 cddb_add_proxy_auth(c);
525 }
526 sock_fprintf(c, "\r\n");
527
528 /* parse HTTP response line */
529 if (!cddb_http_parse_response(c)) {
530 return FALSE;
531 }
532
533 /* skip HTTP response headers */
534 cddb_http_parse_headers(c);
535 }
536 }
537
538 cddb_errno_set(c, CDDB_ERR_OK);
539 return TRUE;
540 }
541
cddb_send_cmd(cddb_conn_t * c,int cmd,...)542 int cddb_send_cmd(cddb_conn_t *c, int cmd, ...)
543 {
544 va_list args;
545
546 cddb_log_debug("cddb_send_cmd()");
547 if (!CONNECTION_OK(c)) {
548 cddb_errno_log_error(c, CDDB_ERR_NOT_CONNECTED);
549 return FALSE;
550 }
551
552 va_start(args, cmd);
553 if (c->is_http_enabled) {
554 /* HTTP */
555 if (!cddb_http_send_cmd(c, cmd, args)) {
556 int errnum;
557
558 errnum = cddb_errno(c); /* save error number */
559 cddb_disconnect(c);
560 cddb_errno_set(c, errnum); /* restore error number */
561 return FALSE;
562 }
563 } else {
564 /* CDDBP */
565 sock_vfprintf(c, CDDB_COMMANDS[cmd], args);
566 sock_fprintf(c, "\n");
567 }
568 va_end(args);
569
570 cddb_errno_set(c, CDDB_ERR_OK);
571 return TRUE;
572 }
573
574 #define STATE_START 0
575 #define STATE_TRACK_OFFSETS 1
576 #define STATE_DISC_LENGTH 2
577 #define STATE_DISC_REVISION 3
578 #define STATE_DISC_TITLE 4
579 #define STATE_DISC_YEAR 5
580 #define STATE_DISC_GENRE 6
581 #define STATE_DISC_EXT 7
582 #define STATE_TRACK_TITLE 8
583 #define STATE_TRACK_EXT 9
584 #define STATE_PLAY_ORDER 10
585 #define STATE_END_DOT 11
586 #define STATE_STOP 12
587
588 #define MULTI_NONE 0
589 #define MULTI_ARTIST 1
590 #define MULTI_TITLE 2
591 #define MULTI_EXT 3
592
cddb_parse_record(cddb_conn_t * c,cddb_disc_t * disc)593 int cddb_parse_record(cddb_conn_t *c, cddb_disc_t *disc)
594 {
595 char *line, *buf;
596 int state, multi_line = MULTI_NONE;
597 #ifdef HAVE_REGEX_H
598 regmatch_t matches[6];
599 #endif
600 cddb_track_t *track;
601 int cache_content;
602 int track_no = 0, old_no = -1;
603
604 cddb_log_debug("cddb_parse_record()");
605 /*
606 * Do we need to cache the processed content ? We cache if:
607 * 1. caching is allowed (CACHE_ON or CACHE_ONLY)
608 * and
609 * 2. a cached version does not yet exist
610 */
611 cache_content = !c->cache_read && (c->use_cache != CACHE_OFF) &&
612 !cddb_cache_exists(c, disc);
613 if (cache_content) {
614 /* create cache directory structure */
615 /* XXX: what to do if mkdir fails? */
616 cache_content = cddb_cache_mkdir(c, disc);
617 cache_content &= cddb_cache_open(c, disc, "w");
618 }
619 cddb_log_debug("...cache_content: %s", (cache_content ? "yes" : "no"));
620
621 state = STATE_START;
622 while ((line = cddb_read_line(c)) != NULL) {
623
624 if (cache_content) {
625 fprintf(cddb_cache_file(c), "%s\n", line);
626 }
627
628 switch (state) {
629 case STATE_START:
630 cddb_log_debug("...state: START");
631 if (regexec(REGEX_TRACK_FRAME_OFFSETS, line, 0, NULL, 0) == 0) {
632 /* expect a list of track frame offsets now */
633 state = STATE_TRACK_OFFSETS;
634 }
635 break;
636 case STATE_TRACK_OFFSETS:
637 cddb_log_debug("...state: TRACK OFFSETS");
638 if (regexec(REGEX_TRACK_FRAME_OFFSET, line, 2, matches, 0) == 0) {
639 track = cddb_disc_get_track(disc, track_no);
640 if (!track) {
641 /* no such track present in disc structure yet */
642 track = cddb_track_new();
643 /* XXX: insert at track_no pos?? */
644 cddb_disc_add_track(disc, track);
645 }
646 track->frame_offset = cddb_regex_get_int(line, matches, 1);
647 track_no++;
648 break;
649 } else {
650 /* expect disc length now */
651 state = STATE_DISC_LENGTH;
652 }
653 case STATE_DISC_LENGTH:
654 cddb_log_debug("...state: DISC LENGTH");
655 if (regexec(REGEX_DISC_LENGTH, line, 2, matches, 0) == 0) {
656 disc->length = cddb_regex_get_int(line, matches, 1);
657 /* expect disc revision now */
658 state = STATE_DISC_REVISION;
659 }
660 break;
661 case STATE_DISC_REVISION:
662 cddb_log_debug("...state: DISC REVISION");
663 if (regexec(REGEX_DISC_REVISION, line, 2, matches, 0) == 0) {
664 disc->revision = cddb_regex_get_int(line, matches, 1);
665 /* expect disc title now */
666 state = STATE_DISC_TITLE;
667 }
668 break;
669 case STATE_DISC_TITLE:
670 cddb_log_debug("...state: DISC TITLE");
671 if (regexec(REGEX_DISC_TITLE, line, 5, matches, 0) == 0) {
672 /* XXX: more error detection possible! */
673 if (multi_line == MULTI_NONE) {
674 /* start parsing title or artist, delete current
675 track and artist in case this disc structure is
676 being reused from a previous read */
677 cddb_disc_set_artist(disc, NULL);
678 cddb_disc_set_title(disc, NULL);
679 }
680 if (matches[2].rm_so != -1) {
681 /* both artist and title of disc are specified */
682 buf = cddb_regex_get_string(line, matches, 2);
683 cddb_disc_append_artist(disc, buf);
684 free(buf);
685 buf = cddb_regex_get_string(line, matches, 3);
686 cddb_disc_append_title(disc, buf);
687 free(buf);
688 /* we should only get title continuations now */
689 multi_line = MULTI_TITLE;
690 } else {
691 /* only title or artist of disc on this line */
692 if (multi_line != MULTI_TITLE) {
693 /* this line is part of the artist name */
694 buf = cddb_regex_get_string(line, matches, 4);
695 cddb_disc_append_artist(disc, buf);
696 free(buf);
697 /* next line might be continuation of artist name */
698 multi_line = MULTI_ARTIST;
699 } else {
700 /* this line is part of the title */
701 buf = cddb_regex_get_string(line, matches, 4);
702 cddb_disc_append_title(disc, buf);
703 free(buf);
704 }
705 }
706 break;
707 }
708 if (multi_line == MULTI_NONE) {
709 /* not yet parsing multi-line DTITLE */
710 /* might be comment line, just skip it */
711 break;
712 }
713 /* if format was not 'artist / title' we assume that
714 the title and artist name are equal (see specs) */
715 if (disc->artist != NULL && disc->title == NULL) {
716 cddb_disc_set_title(disc, disc->artist);
717 }
718 multi_line = MULTI_NONE;
719 /* fall through to end multi-line disc title */
720 case STATE_DISC_YEAR:
721 cddb_log_debug("...state: DISC YEAR");
722 if (regexec(REGEX_DISC_YEAR, line, 2, matches, 0) == 0) {
723 disc->year = cddb_regex_get_int(line, matches, 1);
724 /* expect disc genre now */
725 state = STATE_DISC_GENRE;
726 break;
727 }
728 /* fall through because disc year is optional */
729 case STATE_DISC_GENRE:
730 cddb_log_debug("...state: DISC GENRE");
731 if (regexec(REGEX_DISC_GENRE, line, 2, matches, 0) == 0) {
732 buf = cddb_regex_get_string(line, matches, 1);
733 cddb_disc_set_genre(disc, buf);
734 free(buf);
735 /* expect track title now */
736 state = STATE_TRACK_TITLE;
737 break;
738 }
739 /* fall through because disc genre is optional */
740 case STATE_TRACK_TITLE:
741 cddb_log_debug("...state: TRACK TITLE");
742 if (regexec(REGEX_TRACK_TITLE, line, 6, matches, 0) == 0) {
743 state = STATE_TRACK_TITLE;
744 track_no = cddb_regex_get_int(line, matches, 1);
745 track = cddb_disc_get_track(disc, track_no);
746 if (track == NULL) {
747 cddb_errno_log_error(c, CDDB_ERR_TRACK_NOT_FOUND);
748 return FALSE;
749 }
750 if (track_no != old_no) {
751 old_no = track_no;
752 /* reset multi-line flag, expect artist first */
753 multi_line = MULTI_ARTIST;
754 /* delete current title and artist in case this
755 track structure is being reused from a previous
756 read */
757 cddb_track_set_artist(track, NULL);
758 cddb_track_set_title(track, NULL);
759 }
760 if (matches[3].rm_so == -1) {
761 /* only title or artist of track on this line */
762 if (multi_line != MULTI_TITLE) {
763 /* this line might be part of the artist,
764 but if we don't encounter a ' / ' it's the title,
765 so we use the title space for now and fix it later
766 if needed (see below) */
767 buf = cddb_regex_get_string(line, matches, 5);
768 cddb_track_append_title(track, buf);
769 free(buf);
770 } else {
771 /* this line is part of the title */
772 buf = cddb_regex_get_string(line, matches, 5);
773 cddb_track_append_title(track, buf);
774 free(buf);
775 }
776 } else {
777 /* we might have put the artist in the title space,
778 fix this now (see artist) */
779 track->artist = track->title;
780 track->title = NULL;
781 /* both artist and title of track are specified */
782 buf = cddb_regex_get_string(line, matches, 3);
783 cddb_track_append_artist(track, buf);
784 free(buf);
785 buf = cddb_regex_get_string(line, matches, 4);
786 cddb_track_append_title(track, buf);
787 free(buf);
788 /* we should only get title continuations now */
789 multi_line = MULTI_TITLE;
790 }
791 /* valid track title, process next line */
792 break;
793 }
794 multi_line = MULTI_NONE;
795 old_no = -1;
796 /* fall through, we might have reached end of track titles */
797 case STATE_DISC_EXT:
798 cddb_log_debug("...state: DISC EXT");
799 if (regexec(REGEX_DISC_EXT, line, 2, matches, 0) == 0) {
800 state = STATE_DISC_EXT;
801 if (multi_line == MULTI_NONE) {
802 /* start parsing extended disc data, delete
803 current data in case this disc structure is
804 being reused from a previous read */
805 cddb_disc_set_ext_data(disc, NULL);
806 multi_line = MULTI_EXT;
807 }
808 buf = cddb_regex_get_string(line, matches, 1);
809 if (*buf) {
810 cddb_disc_append_ext_data(disc, buf);
811 }
812 free(buf);
813 break;
814 }
815 multi_line = MULTI_NONE;
816 /* fall through, reached end of multi-line extended disc data */
817 case STATE_TRACK_EXT:
818 cddb_log_debug("...state: TRACK EXT");
819 if (regexec(REGEX_TRACK_EXT, line, 3, matches, 0) == 0) {
820 state = STATE_TRACK_EXT;
821 track_no = cddb_regex_get_int(line, matches, 1);
822 track = cddb_disc_get_track(disc, track_no);
823 if (track == NULL) {
824 cddb_errno_log_error(c, CDDB_ERR_TRACK_NOT_FOUND);
825 return FALSE;
826 }
827 if (track_no != old_no) {
828 old_no = track_no;
829 /* start parsing extended track data for a new
830 track, delete current data in case this
831 track structure is being reused from a
832 previous read */
833 cddb_track_set_ext_data(track, NULL);
834 }
835 buf = cddb_regex_get_string(line, matches, 2);
836 if (*buf) {
837 cddb_track_append_ext_data(track, buf);
838 }
839 free(buf);
840 break;
841 }
842 /* fall through, reached end of extended track data? */
843 case STATE_PLAY_ORDER:
844 cddb_log_debug("...state: PLAY ORDER");
845 if (regexec(REGEX_PLAY_ORDER, line, 2, matches, 0) == 0) {
846 /* expect nothing more */
847 state = STATE_END_DOT;
848 break;
849 }
850 /* fall through, reached end? */
851 case STATE_END_DOT:
852 cddb_log_debug("...state: STOP");
853 if (*line == CHR_DOT) {
854 /* server response ends with a dot, so end of parsing */
855 state = STATE_STOP;
856 break;
857 }
858 default:
859 /* unexpected line */
860 cddb_log_error("unexpected line = '%s'", line);
861 }
862 /* break if we have to stop parsing */
863 if (state == STATE_STOP) {
864 break;
865 }
866 }
867
868 /* change state to STOP if end of stream reached */
869 if (line == NULL) {
870 state = STATE_STOP;
871 }
872
873 if (cache_content) {
874 cddb_cache_close(c);
875 }
876
877 if (state != STATE_STOP) {
878 /* something wrong with the CDDB entry (either the network
879 response or the cached version) */
880 if (c->cache_read) {
881 /* we're reading from the cache, remove the invalid entry */
882 char *fn = cddb_cache_file_name(c, disc);
883 if (fn) {
884 cddb_log_warn("removing invalid cache entry '%s'", fn);
885 unlink(fn);
886 }
887 FREE_NOT_NULL(fn);
888 }
889 cddb_errno_log_error(c, CDDB_ERR_INVALID_RESPONSE);
890 return FALSE;
891 }
892
893 if (!cddb_disc_iconv(c->charset->cd_from_freedb, disc)) {
894 cddb_errno_log_error(c, CDDB_ERR_ICONV_FAIL);
895 return FALSE;
896 }
897
898 cddb_errno_set(c, CDDB_ERR_OK);
899 return TRUE;
900 }
901
902
903 /* --- server commands --- */
904
905
cddb_read(cddb_conn_t * c,cddb_disc_t * disc)906 int cddb_read(cddb_conn_t *c, cddb_disc_t *disc)
907 {
908 char *msg;
909 int code, rc;
910
911 cddb_log_debug("cddb_read()");
912 /* check whether we have enough info to execute the command */
913 if ((disc->category == CDDB_CAT_INVALID) || (disc->discid == 0)) {
914 cddb_errno_log_error(c, CDDB_ERR_DATA_MISSING);
915 return FALSE;
916 }
917
918 if (cddb_cache_read(c, disc)) {
919 /* cached version found */
920 return TRUE;
921 } else if (c->use_cache == CACHE_ONLY) {
922 /* no network access allowed */
923 cddb_errno_set(c, CDDB_ERR_DISC_NOT_FOUND);
924 return FALSE;
925 }
926
927 if (!cddb_connect(c)) {
928 /* connection not OK */
929 return FALSE;
930 }
931
932 /* send read command and check response */
933 if (!cddb_send_cmd(c, CMD_READ, CDDB_CATEGORY[disc->category], disc->discid)) {
934 return FALSE;
935 }
936 switch (code = cddb_get_response_code(c, &msg)) {
937 case -1:
938 return FALSE;
939 case 210: /* OK, CDDB database entry follows */
940 break;
941 case 401: /* specified CDDB entry not found */
942 cddb_errno_set(c, CDDB_ERR_DISC_NOT_FOUND);
943 return FALSE;
944 case 402: /* server error */
945 case 403: /* database entry is corrupt */
946 cddb_errno_log_error(c, CDDB_ERR_SERVER_ERROR);
947 return FALSE;
948 case 409: /* no handshake */
949 case 530: /* server error, server timeout */
950 cddb_disconnect(c);
951 cddb_errno_log_error(c, CDDB_ERR_NOT_CONNECTED);
952 return FALSE;
953 default:
954 cddb_errno_log_error(c, CDDB_ERR_UNKNOWN);
955 return FALSE;
956 }
957
958 /* parse CDDB record */
959 rc = cddb_parse_record(c, disc);
960
961 /* close connection if using HTTP */
962 if (c->is_http_enabled) {
963 cddb_disconnect(c);
964 }
965
966 return rc;
967 }
968
cddb_parse_query_data(cddb_conn_t * c,cddb_disc_t * disc,const char * line)969 static int cddb_parse_query_data(cddb_conn_t *c, cddb_disc_t *disc,
970 const char *line)
971 {
972 char *aux;
973 regmatch_t matches[7];
974
975 if (regexec(REGEX_QUERY_MATCH, line, 7, matches, 0) == REG_NOMATCH) {
976 /* invalid repsponse */
977 cddb_errno_log_error(c, CDDB_ERR_INVALID_RESPONSE);
978 return FALSE;
979 }
980 /* extract category */
981 aux = cddb_regex_get_string(line, matches, 1);
982 cddb_disc_set_category_str(disc, aux);
983 free(aux); /* free temporary buffer */
984 /* extract disc ID */
985 aux = cddb_regex_get_string(line, matches, 2);
986 disc->discid = strtoll(aux, NULL, 16);
987 free(aux); /* free temporary buffer */
988 /* extract artist and title */
989 if (matches[4].rm_so != -1) {
990 /* both artist and title of disc are specified */
991 disc->artist = cddb_regex_get_string(line, matches, 4);
992 disc->title = cddb_regex_get_string(line, matches, 5);
993 } else {
994 /* only title of disc is specified */
995 disc->title = cddb_regex_get_string(line, matches, 6);
996 }
997
998 if (!cddb_disc_iconv(c->charset->cd_from_freedb, disc)) {
999 cddb_errno_log_error(c, CDDB_ERR_ICONV_FAIL);
1000 return FALSE;
1001 }
1002
1003 cddb_errno_set(c, CDDB_ERR_OK);
1004 return TRUE;
1005 }
1006
cddb_handle_response_list(cddb_conn_t * c,cddb_disc_t * disc)1007 static int cddb_handle_response_list(cddb_conn_t *c, cddb_disc_t *disc)
1008 {
1009 char *msg, *line;
1010 int code, count;
1011
1012 switch (code = cddb_get_response_code(c, &msg)) {
1013 case -1:
1014 return -1;
1015 case 200: /* found exact match */
1016 cddb_log_debug("...exact match");
1017 if (!cddb_parse_query_data(c, disc, msg)) {
1018 return -1;
1019 }
1020 count = 1;
1021 break;
1022 case 210: /* found exact matches, list follows */
1023 case 211: /* found inexact matches, list follows */
1024 cddb_log_debug("...(in)exact matches");
1025 {
1026 cddb_disc_t *aux;
1027
1028 while ((line = cddb_read_line(c)) != NULL) {
1029 /* end of list? */
1030 if (*line == CHR_DOT) {
1031 break;
1032 }
1033 /* clone disc and fill in the blanks */
1034 aux = cddb_disc_clone(disc);
1035 if (!cddb_parse_query_data(c, aux, line)) {
1036 cddb_disc_destroy(aux);
1037 return -1;
1038 }
1039 list_append(c->query_data, aux);
1040 }
1041 if (list_size(c->query_data) == 0) {
1042 /* empty result set */
1043 cddb_errno_log_error(c, CDDB_ERR_INVALID_RESPONSE);
1044 return -1;
1045 }
1046 /* return first disc in result set */
1047 cddb_disc_copy(disc, (cddb_disc_t *)element_data(list_first(c->query_data)));
1048 }
1049 count = list_size(c->query_data);
1050 break;
1051 case 202: /* no match found */
1052 cddb_log_debug("...no match");
1053 count = 0;
1054 break;
1055 case 403: /* database entry is corrupt */
1056 cddb_errno_log_error(c, CDDB_ERR_SERVER_ERROR);
1057 return -1;
1058 case 409: /* no handshake */
1059 case 530: /* server error, server timeout */
1060 cddb_disconnect(c);
1061 cddb_errno_log_error(c, CDDB_ERR_NOT_CONNECTED);
1062 return -1;
1063 default:
1064 cddb_errno_log_error(c, CDDB_ERR_UNKNOWN);
1065 return -1;
1066 }
1067
1068 /* close connection if using HTTP */
1069 if (c->is_http_enabled) {
1070 cddb_disconnect(c);
1071 }
1072
1073 cddb_log_debug("...number of matches: %d", count);
1074 cddb_errno_set(c, CDDB_ERR_OK);
1075 return count;
1076 }
1077
cddb_query(cddb_conn_t * c,cddb_disc_t * disc)1078 int cddb_query(cddb_conn_t *c, cddb_disc_t *disc)
1079 {
1080 char *buf, offset[32];
1081 cddb_track_t *track;
1082
1083 cddb_log_debug("cddb_query()");
1084 /* clear previous query result set */
1085 list_flush(c->query_data);
1086
1087 /* recalculate disc ID to make sure it matches the disc data */
1088 cddb_disc_calc_discid(disc);
1089
1090 /* check whether we have enough info to execute the command */
1091 cddb_log_debug("...disc->discid = %08x", disc->discid);
1092 cddb_log_debug("...disc->length = %d", disc->length);
1093 cddb_log_debug("...disc->track_cnt = %d", disc->track_cnt);
1094 if ((disc->discid == 0) || (disc->length == 0) || (disc->track_cnt == 0)) {
1095 cddb_errno_log_error(c, CDDB_ERR_DATA_MISSING);
1096 return -1;
1097 }
1098
1099 if (cddb_cache_query(c, disc)) {
1100 /* cached version found */
1101 return TRUE;
1102 } else if (c->use_cache == CACHE_ONLY) {
1103 /* no network access allowed */
1104 cddb_errno_set(c, CDDB_ERR_DISC_NOT_FOUND);
1105 return FALSE;
1106 }
1107
1108 buf = (char*)malloc(c->buf_size);
1109 /* check track offsets and generate offset list */
1110 buf[0] = CHR_EOS;
1111 for (track = cddb_disc_get_track_first(disc);
1112 track != NULL;
1113 track = cddb_disc_get_track_next(disc)) {
1114 if (track->frame_offset == -1) {
1115 cddb_errno_log_error(c, CDDB_ERR_DATA_MISSING);
1116 free(buf);
1117 return -1;
1118 }
1119 snprintf(offset, sizeof(offset), "%d ", track->frame_offset);
1120 if (strlen(buf) + strlen(offset) >= c->buf_size) {
1121 /* buffer is too small */
1122 cddb_errno_log_crit(c, CDDB_ERR_LINE_SIZE);
1123 free(buf);
1124 return -1;
1125 }
1126 strcat(buf, offset);
1127 }
1128
1129 if (!cddb_connect(c)) {
1130 /* connection not OK */
1131 free(buf);
1132 return -1;
1133 }
1134
1135 /* send query command and check response */
1136 if (!cddb_send_cmd(c, CMD_QUERY, disc->discid, disc->track_cnt, buf, disc->length)) {
1137 free(buf);
1138 return -1;
1139 }
1140 free(buf);
1141 return cddb_handle_response_list(c, disc);
1142 }
1143
cddb_query_next(cddb_conn_t * c,cddb_disc_t * disc)1144 int cddb_query_next(cddb_conn_t *c, cddb_disc_t *disc)
1145 {
1146 elem_t *aux;
1147
1148 cddb_log_debug("cddb_query_next()");
1149 aux = list_next(c->query_data);
1150 if (!aux) {
1151 /* no more discs */
1152 cddb_errno_set(c, CDDB_ERR_DISC_NOT_FOUND);
1153 return FALSE;
1154 }
1155 /* return next disc in result set */
1156 cddb_disc_copy(disc, (cddb_disc_t *)element_data(aux));
1157
1158 cddb_errno_set(c, CDDB_ERR_OK);
1159 return TRUE;
1160 }
1161
cddb_album(cddb_conn_t * c,cddb_disc_t * disc)1162 int cddb_album(cddb_conn_t *c, cddb_disc_t *disc)
1163 {
1164 cddb_log_debug("cddb_album()");
1165 /* clear previous query result set */
1166 list_flush(c->query_data);
1167
1168 /* check whether we have enough info to execute the command */
1169 cddb_log_debug("...disc->artist = %s", STR_OR_NULL(disc->artist));
1170 cddb_log_debug("...disc->title = %s", STR_OR_NULL(disc->title));
1171 if (!disc->title && !disc->artist) {
1172 cddb_errno_log_error(c, CDDB_ERR_DATA_MISSING);
1173 return -1;
1174 }
1175
1176 if (c->use_cache == CACHE_ONLY) {
1177 /* no network access allowed */
1178 cddb_errno_set(c, CDDB_ERR_DISC_NOT_FOUND);
1179 return FALSE;
1180 }
1181
1182 if (!cddb_connect(c)) {
1183 /* connection not OK */
1184 return -1;
1185 }
1186
1187 /* send query command and check response */
1188 if (!cddb_send_cmd(c, CMD_ALBUM, STR_OR_EMPTY(disc->artist), STR_OR_EMPTY(disc->title))) {
1189 return -1;
1190 }
1191 return cddb_handle_response_list(c, disc);
1192 }
1193
cddb_album_next(cddb_conn_t * c,cddb_disc_t * disc)1194 int cddb_album_next(cddb_conn_t *c, cddb_disc_t *disc)
1195 {
1196 cddb_log_debug("cddb_album_next() ->");
1197 return cddb_query_next(c, disc);
1198 }
1199
cddb_parse_search_data(cddb_conn_t * c,cddb_disc_t ** disc,char * line,regmatch_t * matches)1200 static int cddb_parse_search_data(cddb_conn_t *c, cddb_disc_t **disc,
1201 char *line, regmatch_t *matches)
1202 {
1203 regmatch_t pre_matches[11];
1204 char *buf;
1205
1206 /* HACK: because of greedy matching of POSIX regular expressions
1207 we first need to check whether the prefix remainder also
1208 contains a valid match. */
1209 buf = cddb_regex_get_string(line, matches, 1);
1210 if (regexec(REGEX_TEXT_SEARCH, buf, 11, pre_matches, 0) == 0) {
1211 cddb_parse_search_data(c, disc, buf, pre_matches);
1212 }
1213 free(buf);
1214 /* clone so that duplicate matches get correct artist and title */
1215 if (*disc) {
1216 *disc = cddb_disc_clone(*disc);
1217 } else {
1218 *disc = cddb_disc_new();
1219 }
1220 if (*disc == NULL) {
1221 cddb_errno_log_error(c, CDDB_ERR_OUT_OF_MEMORY);
1222 return FALSE;
1223 }
1224 /* fill in the results in the new disc */
1225 buf = cddb_regex_get_string(line, matches, 2);
1226 cddb_disc_set_category_str(*disc, buf);
1227 free(buf);
1228 cddb_disc_set_discid(*disc, cddb_regex_get_hex(line, matches, 3));
1229 if (matches[6].rm_so != -1) {
1230 buf = cddb_regex_get_string(line, matches, 6);
1231 cddb_disc_set_artist(*disc, buf);
1232 free(buf);
1233 buf = cddb_regex_get_string(line, matches, 7);
1234 cddb_disc_set_title(*disc, buf);
1235 free(buf);
1236 } else if (matches[8].rm_so != -1) {
1237 buf = cddb_regex_get_string(line, matches, 8);
1238 cddb_disc_set_artist(*disc, buf);
1239 cddb_disc_set_title(*disc, buf);
1240 free(buf);
1241 } else if (matches[10].rm_so != -1) {
1242 /* nothing to do, values should be correct because of cloning */
1243 }
1244 list_append(c->query_data, *disc);
1245 return TRUE;
1246 }
1247
1248 /**
1249 * Build the search parameter string.
1250 */
cddb_search_param_str(cddb_search_params_t * params,char * buf,int len)1251 static void cddb_search_param_str(cddb_search_params_t *params,
1252 char *buf, int len)
1253 {
1254 char *p = buf;
1255 int i;
1256
1257 /* XXX: to buffer overflow checking */
1258 strcpy(p, "&allfields="); p += 11;
1259 if (params->fields == SEARCH_ALL) {
1260 strcpy(p, "YES"); p += 3;
1261 } else {
1262 strcpy(p, "NO"); p += 2;
1263 if (params->fields & SEARCH_ARTIST) {
1264 strcpy(p, "&fields=artist"); p += 14;
1265 }
1266 if (params->fields & SEARCH_TITLE) {
1267 strcpy(p, "&fields=title"); p += 13;
1268 }
1269 if (params->fields & SEARCH_TRACK) {
1270 strcpy(p, "&fields=track"); p += 13;
1271 }
1272 if (params->fields & SEARCH_OTHER) {
1273 strcpy(p, "&fields=rest"); p += 12;
1274 }
1275 }
1276 strcpy(p, "&allcats="); p += 9;
1277 if (params->cats == SEARCH_ALL) {
1278 strcpy(p, "YES"); p += 3;
1279 } else {
1280 strcpy(p, "NO"); p += 2;
1281 for (i = 0; i < CDDB_CAT_INVALID; i++) {
1282 if (params->cats & SEARCHCAT(i)) {
1283 strcpy(p, "&cats="); p += 6;
1284 strcpy(p, CDDB_CATEGORY[i]); p += strlen(CDDB_CATEGORY[i]);
1285 }
1286 }
1287 }
1288 strcpy(p, "&grouping=cats"); p += 14;
1289 }
1290
cddb_search(cddb_conn_t * c,cddb_disc_t * disc,const char * str)1291 int cddb_search(cddb_conn_t *c, cddb_disc_t *disc, const char *str)
1292 {
1293 regmatch_t matches[11];
1294 char *line;
1295 int count;
1296 cddb_disc_t *aux = NULL;
1297 char paramstr[1024]; /* big enough! */
1298
1299 /* NOTE: For server access this function uses the special
1300 'cddb_search_conn' connection structure. */
1301 cddb_log_debug("cddb_search()");
1302 /* copy proxy parameters */
1303 cddb_clone_proxy(cddb_search_conn, c);
1304 /* clear previous query result set */
1305 list_flush(c->query_data);
1306
1307 if (!cddb_connect(cddb_search_conn)) {
1308 /* connection not OK, copy error code */
1309 cddb_errno_set(c, cddb_errno(cddb_search_conn));
1310 return -1;
1311 }
1312
1313 /* prepare search parameters string */
1314 cddb_search_param_str(&c->srch, paramstr, sizeof(paramstr));
1315
1316 /* send query command and check response */
1317 if (!cddb_send_cmd(cddb_search_conn, CMD_SEARCH, str, paramstr)) {
1318 /* sending command failed, copy error code */
1319 cddb_errno_set(c, cddb_errno(cddb_search_conn));
1320 return -1;
1321 }
1322
1323 /* parse HTML response page */
1324 while ((line = cddb_read_line(cddb_search_conn)) != NULL) {
1325 if (regexec(REGEX_TEXT_SEARCH, line, 11, matches, 0) == 0) {
1326 /* process matching result line */
1327 if (!cddb_parse_search_data(c, &aux, line, matches)) {
1328 return -1;
1329 }
1330 }
1331 }
1332 /* return first disc in result set */
1333 count = list_size(c->query_data);
1334 if (count != 0) {
1335 cddb_disc_copy(disc,
1336 (cddb_disc_t *)element_data(list_first(c->query_data)));
1337 }
1338 /* close connection */
1339 cddb_disconnect(cddb_search_conn);
1340
1341 cddb_log_debug("...number of matches: %d", count);
1342 cddb_errno_set(c, CDDB_ERR_OK);
1343 return count;
1344 }
1345
cddb_search_next(cddb_conn_t * c,cddb_disc_t * disc)1346 int cddb_search_next(cddb_conn_t *c, cddb_disc_t *disc)
1347 {
1348 cddb_log_debug("cddb_search_next() ->");
1349 return cddb_query_next(c, disc);
1350 }
1351
cddb_write_data(cddb_conn_t * c,char * buf,int size,cddb_disc_t * disc)1352 int cddb_write_data(cddb_conn_t *c, char *buf, int size, cddb_disc_t *disc)
1353 {
1354 int i, remaining;
1355 cddb_track_t *track;
1356 const char *s;
1357
1358 /* Appends some data to the buffer. The first parameter is the
1359 number of bytes that will be added. The other parameters are a
1360 format string and its arguments as in printf. */
1361 /* XXX: error checking on buffer size */
1362 #define CDDB_WRITE_APPEND(l, ...) \
1363 snprintf(buf, remaining, __VA_ARGS__); remaining -= l; buf += l;
1364
1365 remaining = size;
1366 CDDB_WRITE_APPEND(9, "# xmcd\n#\n");
1367 /* track offsets */
1368 CDDB_WRITE_APPEND(23, "# Track frame offsets:\n");
1369 for (track = cddb_disc_get_track_first(disc);
1370 track != NULL;
1371 track = cddb_disc_get_track_next(disc)) {
1372 CDDB_WRITE_APPEND(6+8, "# %8d\n", track->frame_offset);
1373 }
1374 /* disc length */
1375 CDDB_WRITE_APPEND(26+6, "#\n# Disc length: %6d seconds\n", disc->length);
1376 /* submission info */
1377 CDDB_WRITE_APPEND(15+8, "#\n# Revision: %8d\n", disc->revision);
1378 CDDB_WRITE_APPEND(21+strlen(c->cname)+strlen(c->cversion),
1379 "# Submitted via: %s %s\n#\n", c->cname, c->cversion);
1380 /* disc data */
1381 CDDB_WRITE_APPEND(8+8, "DISCID=%08x\n", disc->discid);
1382 CDDB_WRITE_APPEND(11+strlen(disc->artist)+strlen(disc->title),
1383 "DTITLE=%s / %s\n", disc->artist, disc->title);
1384 if (disc->year != 0) {
1385 CDDB_WRITE_APPEND(7+4, "DYEAR=%d\n", disc->year);
1386 } else {
1387 CDDB_WRITE_APPEND(7, "DYEAR=\n");
1388 }
1389 if (disc->genre && (*disc->genre != '\0')) {
1390 s = disc->genre;
1391 } else {
1392 s = CDDB_CATEGORY[disc->category];
1393 }
1394 CDDB_WRITE_APPEND(8+strlen(s), "DGENRE=%s\n", s);
1395 /* track data */
1396 for (track = cddb_disc_get_track_first(disc), i=0;
1397 track != NULL;
1398 track = cddb_disc_get_track_next(disc), i++) {
1399 if (track->artist != NULL) {
1400 CDDB_WRITE_APPEND(11+(i/10+1)+strlen(track->artist)+strlen(track->title),
1401 "TTITLE%d=%s / %s\n", i, track->artist, track->title);
1402 } else {
1403 CDDB_WRITE_APPEND(8+(i/10+1)+strlen(track->title),
1404 "TTITLE%d=%s\n", i, track->title);
1405 }
1406 }
1407 /* extended data */
1408 if (disc->ext_data != NULL) {
1409 CDDB_WRITE_APPEND(6+strlen(disc->ext_data), "EXTD=%s\n", disc->ext_data);
1410 } else {
1411 CDDB_WRITE_APPEND(6, "EXTD=\n");
1412 }
1413 for (track = cddb_disc_get_track_first(disc), i=0;
1414 track != NULL;
1415 track = cddb_disc_get_track_next(disc), i++) {
1416 if (track->ext_data != NULL) {
1417 CDDB_WRITE_APPEND(6+(i/10+1)+strlen(track->ext_data),
1418 "EXTT%d=%s\n", i, track->ext_data);
1419 } else {
1420 CDDB_WRITE_APPEND(6+(i/10+1), "EXTT%d=\n", i);
1421 }
1422 }
1423 /* play order */
1424 CDDB_WRITE_APPEND(11, "PLAYORDER=\n");
1425
1426 return (size - remaining);
1427 }
1428
cddb_write(cddb_conn_t * c,cddb_disc_t * disc)1429 int cddb_write(cddb_conn_t *c, cddb_disc_t *disc)
1430 {
1431 char *msg;
1432 int code, size;
1433 cddb_track_t *track;
1434 char buf[WRITE_BUF_SIZE];
1435
1436 cddb_log_debug("cddb_write()");
1437 /* check whether the default e-mail address has been changed, the
1438 freedb spec requires this */
1439 if (strcmp(c->user, DEFAULT_USER) == 0 ||
1440 strcmp(c->hostname, DEFAULT_HOST) == 0) {
1441 cddb_errno_log_error(c, CDDB_ERR_EMAIL_INVALID);
1442 return FALSE;
1443 }
1444 /* check whether we have enough disc data to execute the command */
1445 if ((disc->discid == 0) || (disc->category == CDDB_CAT_INVALID) ||
1446 (disc->length == 0) || (disc->track_cnt == 0) ||
1447 (disc->artist == NULL) || (disc->title == NULL)) {
1448 cddb_errno_log_error(c, CDDB_ERR_DATA_MISSING);
1449 return FALSE;
1450 }
1451
1452 /* check whether we have enough track data to execute the command */
1453 for (track = cddb_disc_get_track_first(disc);
1454 track != NULL;
1455 track = cddb_disc_get_track_next(disc)) {
1456 if ((track->frame_offset == -1) || (track->title == NULL)) {
1457 cddb_errno_log_error(c, CDDB_ERR_DATA_MISSING);
1458 return FALSE;
1459 }
1460 }
1461
1462 /* convert to FreeDB character set */
1463 if (!cddb_disc_iconv(c->charset->cd_to_freedb, disc)) {
1464 cddb_errno_log_error(c, CDDB_ERR_ICONV_FAIL);
1465 return FALSE;
1466 }
1467
1468 /* create CDDB entry */
1469 size = cddb_write_data(c, buf, sizeof(buf), disc);
1470
1471 /* cache data if needed */
1472 if (c->use_cache != CACHE_OFF) {
1473 /* create cache directory structure */
1474 /* XXX: what to do if mkdir fails? */
1475 if (cddb_cache_mkdir(c, disc)) {
1476 /* open file, possibly overwriting it */
1477 cddb_log_debug("...caching data");
1478 cddb_cache_open(c, disc, "w");
1479 fwrite(buf, sizeof(char), size, cddb_cache_file(c));
1480 cddb_cache_close(c);
1481 }
1482 }
1483
1484 /* stop if no network access is allowed */
1485 if (c->use_cache == CACHE_ONLY) {
1486 cddb_errno_set(c, CDDB_ERR_OK);
1487 return TRUE;
1488 }
1489
1490 if (!cddb_connect(c)) {
1491 /* connection not OK */
1492 return FALSE;
1493 }
1494
1495 /* send query command and check response */
1496 if (!cddb_send_cmd(c, CMD_WRITE, CDDB_CATEGORY[disc->category], disc->discid, size)) {
1497 return FALSE;
1498 }
1499 if (!c->is_http_enabled) {
1500 switch (code = cddb_get_response_code(c, &msg)) {
1501 case -1:
1502 return FALSE;
1503 case 320: /* OK, input CDDB data */
1504 break;
1505 case 401: /* permission denied */
1506 case 402: /* server file system full/file access failed */
1507 case 501: /* entry rejected */
1508 cddb_errno_log_error(c, CDDB_ERR_PERMISSION_DENIED);
1509 return FALSE;
1510 case 409: /* no handshake */
1511 case 530: /* server error, server timeout */
1512 cddb_disconnect(c);
1513 cddb_errno_log_error(c, CDDB_ERR_NOT_CONNECTED);
1514 return FALSE;
1515 default:
1516 cddb_errno_log_error(c, CDDB_ERR_UNKNOWN);
1517 return FALSE;
1518 }
1519 }
1520
1521 /* ready to send data */
1522 cddb_log_debug("...sending data");
1523 sock_fwrite(buf, sizeof(char), size, c);
1524 if (c->is_http_enabled) {
1525 /* skip HTTP response headers */
1526 cddb_http_parse_headers(c);
1527 } else {
1528 /* send terminating marker */
1529 sock_fprintf(c, ".\n");
1530 }
1531
1532 /* check response */
1533 switch (code = cddb_get_response_code(c, &msg)) {
1534 case -1:
1535 return FALSE;
1536 case 200: /* CDDB entry accepted */
1537 cddb_log_debug("...entry accepted");
1538 break;
1539 case 401: /* CDDB entry rejected */
1540 case 500: /* (HTTP) Missing required header information */
1541 case 501: /* (HTTP) Invalid header information */
1542 cddb_log_debug("...entry not accepted");
1543 cddb_errno_log_error(c, CDDB_ERR_REJECTED);
1544 return FALSE;
1545 case 530: /* server error, server timeout */
1546 cddb_disconnect(c);
1547 cddb_errno_log_error(c, CDDB_ERR_NOT_CONNECTED);
1548 return FALSE;
1549 default:
1550 cddb_errno_log_error(c, CDDB_ERR_UNKNOWN);
1551 return FALSE;
1552 }
1553
1554 /* close connection if using HTTP */
1555 if (c->is_http_enabled) {
1556 cddb_disconnect(c);
1557 }
1558
1559 cddb_errno_set(c, CDDB_ERR_OK);
1560 return TRUE;
1561 }
1562
cddb_sites(cddb_conn_t * c)1563 int cddb_sites(cddb_conn_t *c)
1564 {
1565 char *msg, *line;
1566 int code;
1567 cddb_site_t *site;
1568
1569 cddb_log_debug("cddb_sites()");
1570 /* clear previous sites result set */
1571 list_flush(c->sites_data);
1572
1573 if (!cddb_connect(c)) {
1574 /* connection not OK */
1575 return FALSE;
1576 }
1577
1578 /* send sites command and check response */
1579 if (!cddb_send_cmd(c, CMD_SITES)) {
1580 return FALSE;
1581 }
1582 switch (code = cddb_get_response_code(c, &msg)) {
1583 case -1:
1584 return FALSE;
1585 case 210: /* OK, site information follows */
1586 break;
1587 case 401: /* no site information */
1588 return FALSE;
1589 default:
1590 cddb_errno_log_error(c, CDDB_ERR_UNKNOWN);
1591 return FALSE;
1592 }
1593
1594 while ((line = cddb_read_line(c)) != NULL) {
1595 /* end of list? */
1596 if (*line == CHR_DOT) {
1597 break;
1598 }
1599 site = cddb_site_new();
1600 if (!site) {
1601 cddb_errno_log_error(c, CDDB_ERR_OUT_OF_MEMORY);
1602 return FALSE;
1603 }
1604 if (!cddb_site_parse(site, line)) {
1605 /* skip parsing errors */
1606 cddb_log_warn("unable to parse site: %s", line);
1607 cddb_site_destroy(site);
1608 continue;
1609 }
1610 if (!cddb_site_iconv(c->charset->cd_from_freedb, site)) {
1611 cddb_errno_log_error(c, CDDB_ERR_ICONV_FAIL);
1612 cddb_site_destroy(site);
1613 return FALSE;
1614 }
1615 if (!list_append(c->sites_data, site)) {
1616 cddb_errno_log_error(c, CDDB_ERR_OUT_OF_MEMORY);
1617 cddb_site_destroy(site);
1618 return FALSE;
1619 }
1620 }
1621
1622 /* close connection if using HTTP */
1623 if (c->is_http_enabled) {
1624 cddb_disconnect(c);
1625 }
1626
1627 return TRUE;
1628 }
1629