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