Mercurial > audlegacy
annotate Plugins/Input/cdaudio/cddb.c @ 827:6812adf5ff2e trunk
[svn] Okay, we need to pinch more playback code to avoid false positives.
author | chainsaw |
---|---|
date | Sun, 12 Mar 2006 15:05:18 -0800 |
parents | 1c2c92c7f222 |
children | 2b2f719d8cbb |
rev | line source |
---|---|
61 | 1 /* |
2 * cddb.c Copyright 1999-2001 Håvard Kvålen <havardk@xmms.org> | |
3 * | |
4 * | |
5 * This program is free software; you can redistribute it and/or modify | |
6 * it under the terms of the GNU General Public License as published by | |
7 * the Free Software Foundation; either version 2 of the License, or | |
8 * (at your option) any later version. | |
9 * | |
10 * This program is distributed in the hope that it will be useful, | |
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 * GNU General Public License for more details. | |
14 * | |
15 * You should have received a copy of the GNU General Public License | |
16 * along with this program; if not, write to the Free Software | |
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |
18 */ | |
19 | |
20 | |
21 #include "cddb.h" | |
22 | |
23 #include <glib.h> | |
24 #include <glib/gprintf.h> | |
25 #include <gtk/gtk.h> | |
26 #include <stdarg.h> | |
27 | |
28 #include <libaudacious/util.h> | |
29 | |
30 #include "http.h" | |
31 #include "cdaudio.h" | |
32 #include "cdinfo.h" | |
33 | |
34 | |
35 static guint32 cached_id = 0; | |
36 static GtkWidget *server_dialog, *server_clist; | |
37 static GtkWidget *debug_window, *debug_clist; | |
38 static GList *debug_messages = NULL; | |
39 static GList *temp_messages = NULL; | |
40 static guint cddb_timeout_id; | |
41 | |
42 G_LOCK_DEFINE_STATIC(list); | |
43 | |
44 void configure_set_cddb_server(gchar * server); | |
45 | |
46 static void | |
47 cddb_log(gchar * str, ...) | |
48 { | |
49 static GList *end_ptr = NULL; | |
50 static gint message_num = 0; | |
51 va_list args; | |
52 gchar *text; | |
53 | |
54 va_start(args, str); | |
55 text = g_strdup_vprintf(str, args); | |
56 va_end(args); | |
57 | |
58 message_num++; | |
59 debug_messages = g_list_prepend(debug_messages, text); | |
60 if (!end_ptr) | |
61 end_ptr = debug_messages; | |
62 if (message_num > CDDB_LOG_MAX) { | |
63 GList *temp; | |
64 | |
65 temp = g_list_previous(end_ptr); | |
66 temp->next = NULL; | |
67 g_free(end_ptr->data); | |
68 g_list_free_1(end_ptr); | |
69 end_ptr = temp; | |
70 message_num--; | |
71 } | |
72 if (debug_window) { | |
73 G_LOCK(list); | |
74 temp_messages = g_list_append(temp_messages, g_strdup(text)); | |
75 G_UNLOCK(list); | |
76 } | |
77 } | |
78 | |
79 static gint | |
80 cddb_sum(gint in) | |
81 { | |
82 gint retval = 0; | |
83 | |
84 while (in > 0) { | |
85 retval += in % 10; | |
86 in /= 10; | |
87 } | |
88 return retval; | |
89 } | |
90 | |
91 guint32 | |
92 cdda_cddb_compute_discid(cdda_disc_toc_t * info) | |
93 { | |
94 gint i; | |
95 guint high = 0, low; | |
96 | |
97 for (i = info->first_track; i <= info->last_track; i++) | |
98 high += cddb_sum(info->track[i].minute * 60 + info->track[i].second); | |
99 | |
100 low = (info->leadout.minute * 60 + info->leadout.second) - | |
101 (info->track[info->first_track].minute * 60 + | |
102 info->track[info->first_track].second); | |
103 | |
104 return ((high % 0xff) << 24 | low << 8 | (info->last_track - | |
105 info->first_track + 1)); | |
106 } | |
107 | |
108 static gchar * | |
109 cddb_generate_offset_string(cdda_disc_toc_t * info) | |
110 { | |
111 gchar *buffer; | |
112 int i; | |
113 | |
114 buffer = g_malloc(info->last_track * 7 + 1); | |
115 | |
116 sprintf(buffer, "%d", LBA(info->track[info->first_track])); | |
117 | |
118 for (i = info->first_track + 1; i <= info->last_track; i++) | |
119 sprintf(buffer, "%s+%d", buffer, LBA(info->track[i])); | |
120 | |
121 return buffer; | |
122 } | |
123 | |
124 static gchar * | |
125 cddb_generate_hello_string(void) | |
126 { | |
127 static gchar *buffer; | |
128 | |
129 if (buffer == NULL) { | |
130 gchar *env, *client = NULL, *version = NULL, **strs = NULL; | |
131 | |
132 env = getenv("XMMS_CDDB_CLIENT_NAME"); | |
133 if (env) { | |
134 strs = g_strsplit(env, " ", 2); | |
135 if (strs && strs[0] && strs[1]) { | |
136 client = strs[0]; | |
137 version = strs[1]; | |
138 } | |
139 } | |
140 | |
141 if (!client || !version) { | |
747 | 142 client = PACKAGE_NAME; |
143 version = PACKAGE_VERSION; | |
61 | 144 } |
145 | |
146 buffer = g_strdup_printf("&hello=nobody+localhost+%s+%s", | |
147 client, version); | |
148 if (strs) | |
149 g_strfreev(strs); | |
150 } | |
151 return buffer; | |
152 } | |
153 | |
154 static gint | |
155 cddb_http_open_connection(const gchar * server, gint port) | |
156 { | |
157 gint sock; | |
158 gchar *status; | |
159 | |
160 if ((sock = http_open_connection(server, 80)) == 0) | |
161 status = "Failed"; | |
162 else | |
163 status = "Ok"; | |
164 | |
165 cddb_log("Connecting to CDDB-server %s: %s", server, status); | |
166 return sock; | |
167 } | |
168 | |
169 | |
170 static gboolean | |
171 cddb_query(gchar * server, cdda_disc_toc_t * info, | |
172 cddb_disc_header_t * cddb_info) | |
173 { | |
174 /* | |
175 * Query the cddb-server for the cd. | |
176 * Returns the *real* diskid and category. | |
177 */ | |
178 | |
179 gint sock; | |
180 gchar *offsets, *getstr; | |
181 gchar buffer[256]; | |
182 gchar **response; | |
183 gint i; | |
184 | |
185 if ((sock = cddb_http_open_connection(server, 80)) == 0) | |
186 return FALSE; | |
187 | |
188 offsets = cddb_generate_offset_string(info); | |
189 | |
190 cddb_log("Sending query-command. Disc ID: %08x", | |
191 cdda_cddb_compute_discid(info)); | |
192 | |
193 getstr = | |
194 g_strdup_printf | |
195 ("GET /~cddb/cddb.cgi?cmd=cddb+query+%08x+%d+%s+%d%s&proto=%d HTTP/1.0\r\n\r\n", | |
196 cdda_cddb_compute_discid(info), | |
197 info->last_track - info->first_track + 1, offsets, | |
198 (info->leadout.minute * 60 + info->leadout.second), | |
199 cddb_generate_hello_string(), cdda_cfg.cddb_protocol_level); | |
200 | |
201 g_free(offsets); | |
202 write(sock, getstr, strlen(getstr)); | |
203 g_free(getstr); | |
204 | |
205 if (http_read_first_line(sock, buffer, 256) < 0) { | |
206 http_close_connection(sock); | |
207 return FALSE; | |
208 } | |
209 | |
210 response = g_strsplit(buffer, " ", 4); | |
211 | |
212 cddb_log("Query response: %s", buffer); | |
213 | |
214 switch (strtol(response[0], NULL, 10)) { | |
215 case 200: | |
216 /* One exact match */ | |
217 for (i = 0; i < 4; i++) { | |
218 if (response[i] == NULL) { | |
219 g_strfreev(response); | |
220 return FALSE; | |
221 } | |
222 } | |
223 cddb_info->category = g_strdup(response[1]); | |
224 cddb_info->discid = strtoul(response[2], NULL, 16); | |
225 break; | |
802
1c2c92c7f222
[svn] Bug #423 - Add retrieval of first entry in case of multiple matches. Good enough to remove the FIXME?
nemo
parents:
747
diff
changeset
|
226 case 211: |
1c2c92c7f222
[svn] Bug #423 - Add retrieval of first entry in case of multiple matches. Good enough to remove the FIXME?
nemo
parents:
747
diff
changeset
|
227 /* multiple matches - use first match */ |
1c2c92c7f222
[svn] Bug #423 - Add retrieval of first entry in case of multiple matches. Good enough to remove the FIXME?
nemo
parents:
747
diff
changeset
|
228 g_strfreev(response); |
1c2c92c7f222
[svn] Bug #423 - Add retrieval of first entry in case of multiple matches. Good enough to remove the FIXME?
nemo
parents:
747
diff
changeset
|
229 if (http_read_first_line(sock, buffer, 256) < 0) { |
1c2c92c7f222
[svn] Bug #423 - Add retrieval of first entry in case of multiple matches. Good enough to remove the FIXME?
nemo
parents:
747
diff
changeset
|
230 http_close_connection(sock); |
1c2c92c7f222
[svn] Bug #423 - Add retrieval of first entry in case of multiple matches. Good enough to remove the FIXME?
nemo
parents:
747
diff
changeset
|
231 return FALSE; |
1c2c92c7f222
[svn] Bug #423 - Add retrieval of first entry in case of multiple matches. Good enough to remove the FIXME?
nemo
parents:
747
diff
changeset
|
232 } |
1c2c92c7f222
[svn] Bug #423 - Add retrieval of first entry in case of multiple matches. Good enough to remove the FIXME?
nemo
parents:
747
diff
changeset
|
233 response = g_strsplit(buffer, " ", 4); |
1c2c92c7f222
[svn] Bug #423 - Add retrieval of first entry in case of multiple matches. Good enough to remove the FIXME?
nemo
parents:
747
diff
changeset
|
234 for (i = 0; i < 4; i++) { |
1c2c92c7f222
[svn] Bug #423 - Add retrieval of first entry in case of multiple matches. Good enough to remove the FIXME?
nemo
parents:
747
diff
changeset
|
235 if (response[i] == NULL) { |
1c2c92c7f222
[svn] Bug #423 - Add retrieval of first entry in case of multiple matches. Good enough to remove the FIXME?
nemo
parents:
747
diff
changeset
|
236 g_strfreev(response); |
1c2c92c7f222
[svn] Bug #423 - Add retrieval of first entry in case of multiple matches. Good enough to remove the FIXME?
nemo
parents:
747
diff
changeset
|
237 return FALSE; |
1c2c92c7f222
[svn] Bug #423 - Add retrieval of first entry in case of multiple matches. Good enough to remove the FIXME?
nemo
parents:
747
diff
changeset
|
238 } |
1c2c92c7f222
[svn] Bug #423 - Add retrieval of first entry in case of multiple matches. Good enough to remove the FIXME?
nemo
parents:
747
diff
changeset
|
239 } |
1c2c92c7f222
[svn] Bug #423 - Add retrieval of first entry in case of multiple matches. Good enough to remove the FIXME?
nemo
parents:
747
diff
changeset
|
240 cddb_info->category = g_strdup(response[1]); |
1c2c92c7f222
[svn] Bug #423 - Add retrieval of first entry in case of multiple matches. Good enough to remove the FIXME?
nemo
parents:
747
diff
changeset
|
241 cddb_info->discid = strtoul(response[2], NULL, 16); |
1c2c92c7f222
[svn] Bug #423 - Add retrieval of first entry in case of multiple matches. Good enough to remove the FIXME?
nemo
parents:
747
diff
changeset
|
242 break; |
61 | 243 default: /* FIXME: Handle other 2xx */ |
244 g_strfreev(response); | |
245 return FALSE; | |
246 } | |
802
1c2c92c7f222
[svn] Bug #423 - Add retrieval of first entry in case of multiple matches. Good enough to remove the FIXME?
nemo
parents:
747
diff
changeset
|
247 http_close_connection(sock); |
61 | 248 |
249 g_strfreev(response); | |
250 return TRUE; | |
251 } | |
252 | |
253 static gint | |
254 cddb_check_protocol_level(const gchar * server) | |
255 { | |
256 gint level = 0, sock, n; | |
257 gchar *str, buffer[256]; | |
258 | |
259 if ((sock = cddb_http_open_connection(server, 80)) == 0) | |
260 return 0; | |
261 | |
262 str = | |
263 g_strdup_printf | |
264 ("GET /~cddb/cddb.cgi?cmd=stat%s&proto=1 HTTP/1.0\r\n\r\n", | |
265 cddb_generate_hello_string()); | |
266 | |
267 write(sock, str, strlen(str)); | |
268 g_free(str); | |
269 | |
270 if ((n = http_read_first_line(sock, buffer, 256)) < 0 || | |
271 atoi(buffer) != 210) { | |
272 if (n > 0) | |
273 cddb_log("Getting cddb protocol level failed: %s", buffer); | |
274 else | |
275 cddb_log("Getting cddb protocol level failed."); | |
276 | |
277 http_close_connection(sock); | |
278 return 0; | |
279 } | |
280 | |
281 while (http_read_line(sock, buffer, 256) >= 0) { | |
282 g_strstrip(buffer); | |
283 if (!strncmp(buffer, "max proto:", 10)) | |
284 level = atoi(buffer + 10); | |
285 if (!strcmp(buffer, ".")) | |
286 break; | |
287 } | |
288 http_close_connection(sock); | |
289 cddb_log("Getting cddb protocol level. Got level %d", level); | |
290 return (MIN(level, CDDB_MAX_PROTOCOL_LEVEL)); | |
291 } | |
292 | |
293 #define BUF2SIZE (80*3) | |
294 | |
295 static gboolean | |
296 cddb_read(gchar * server, cddb_disc_header_t * cddb_info, cdinfo_t * cdinfo) | |
297 { | |
298 gint sock; | |
299 gchar *readstr; | |
300 gchar buffer[256], buffer2[BUF2SIZE]; | |
301 gchar *realstr, *temp; | |
302 gint len, command, bufs; | |
303 gint num, oldnum; | |
304 | |
305 if ((sock = cddb_http_open_connection(server, 80)) == 0) | |
306 return FALSE; | |
307 | |
308 cddb_log("Sending read-command. Disc ID: %08x. Category: %s", | |
309 cddb_info->discid, cddb_info->category); | |
310 | |
311 readstr = | |
312 g_strdup_printf | |
313 ("GET /~cddb/cddb.cgi?cmd=cddb+read+%s+%08x%s&proto=%d HTTP/1.0\r\n\r\n", | |
314 cddb_info->category, cddb_info->discid, | |
315 cddb_generate_hello_string(), cdda_cfg.cddb_protocol_level); | |
316 | |
317 write(sock, readstr, strlen(readstr)); | |
318 g_free(readstr); | |
319 | |
320 if (http_read_first_line(sock, buffer, 256) < 0) { | |
321 http_close_connection(sock); | |
322 return FALSE; | |
323 } | |
324 | |
325 cddb_log("Read response: %s", buffer); | |
326 | |
327 command = 1; | |
328 bufs = 0; | |
329 oldnum = -1; | |
330 do { | |
331 /* fprintf(stderr,"%s\n",buffer); */ | |
332 realstr = strchr(buffer, '='); | |
333 if (buffer[0] == '#' || !realstr) | |
334 continue; | |
335 | |
336 realstr++; | |
337 len = strlen(realstr); | |
338 | |
339 switch (command) { | |
340 case 1: | |
341 if (!strncmp(buffer, "DISCID", 6)) | |
342 break; | |
343 command++; | |
344 case 2: | |
345 if (!strncmp(buffer, "DTITLE", 6)) { | |
346 strncpy(buffer2 + bufs, realstr, BUF2SIZE - bufs); | |
347 bufs += len; | |
348 break; | |
349 } | |
350 if (bufs > 0) { | |
351 buffer2[BUF2SIZE - 1] = '\0'; | |
352 if ((temp = strstr(buffer2, " / ")) != NULL) { | |
353 cdda_cdinfo_cd_set(cdinfo, g_strdup(temp + 3), | |
354 g_strndup(buffer2, temp - buffer2)); | |
355 } | |
356 else | |
357 cdda_cdinfo_cd_set(cdinfo, g_strdup(buffer2), | |
358 g_strdup(buffer2)); | |
359 bufs = 0; | |
360 } | |
361 command++; | |
362 case 3: | |
363 if (!strncmp(buffer, "TTITLE", 6)) { | |
364 num = atoi(buffer + 6); | |
365 if (oldnum < 0 || num == oldnum) { | |
366 strncpy(buffer2 + bufs, realstr, BUF2SIZE - bufs); | |
367 bufs += len; | |
368 } | |
369 else { | |
370 buffer2[BUF2SIZE - 1] = '\0'; | |
371 cdda_cdinfo_track_set(cdinfo, oldnum + 1, NULL, | |
372 g_strdup(buffer2)); | |
373 strncpy(buffer2, realstr, BUF2SIZE); | |
374 bufs = len; | |
375 } | |
376 oldnum = num; | |
377 break; | |
378 } | |
379 if (oldnum >= 0) | |
380 cdda_cdinfo_track_set(cdinfo, oldnum + 1, NULL, | |
381 g_strdup(buffer2)); | |
382 bufs = 0; | |
383 oldnum = -1; | |
384 command++; | |
385 case 4: | |
386 if (!strncmp(buffer, "EXTD", 4)) { | |
387 break; | |
388 } | |
389 command++; | |
390 case 5: | |
391 if (!strncmp(buffer, "EXTT", 4)) { | |
392 break; | |
393 } | |
394 command++; | |
395 case 6: | |
396 if (!strncmp(buffer, "PLAYORDER", 9)) { | |
397 break; | |
398 } | |
399 command++; | |
400 default: | |
401 g_log(NULL, G_LOG_LEVEL_WARNING, "%s: illegal cddb-data: %s", | |
747 | 402 PACKAGE_NAME, buffer); |
61 | 403 break; |
404 } | |
405 | |
406 } while (http_read_line(sock, buffer, 256) >= 0); | |
407 | |
408 if (oldnum >= 0) | |
409 cdda_cdinfo_track_set(cdinfo, oldnum + 1, NULL, g_strdup(buffer2)); | |
410 | |
411 http_close_connection(sock); | |
412 return TRUE; | |
413 } | |
414 | |
415 static gint | |
416 cddb_get_protocol_level(void) | |
417 { | |
418 if (cdda_cfg.cddb_protocol_level < 1) | |
419 cdda_cfg.cddb_protocol_level = | |
420 cddb_check_protocol_level(cdda_cfg.cddb_server); | |
421 | |
422 return cdda_cfg.cddb_protocol_level; | |
423 } | |
424 | |
425 static GList * | |
426 cddb_get_server_list(const gchar * server, gint protocol_level) | |
427 { | |
428 gint sock; | |
429 gchar *getstr; | |
430 gchar buffer[256]; | |
431 gchar **message; | |
432 GList *list = NULL; | |
433 | |
434 if ((sock = cddb_http_open_connection(server, 80)) == 0) | |
435 return NULL; | |
436 | |
437 cddb_log("Sending sites-command"); | |
438 | |
439 getstr = | |
440 g_strdup_printf | |
441 ("GET /~cddb/cddb.cgi?cmd=sites%s&proto=%d HTTP/1.0\r\n\r\n", | |
442 cddb_generate_hello_string(), protocol_level); | |
443 | |
444 write(sock, getstr, strlen(getstr)); | |
445 g_free(getstr); | |
446 | |
447 if (http_read_first_line(sock, buffer, 256) < 0) { | |
448 http_close_connection(sock); | |
449 return NULL; | |
450 } | |
451 | |
452 cddb_log("Sites response: %s", buffer); | |
453 | |
454 switch (atoi(buffer)) { | |
455 case 210: | |
456 while ((http_read_line(sock, buffer, 256)) > 1) { | |
457 message = g_strsplit(buffer, " ", 6); | |
458 if (message && message[0] && message[1] && | |
459 !strcasecmp(message[1], "http")) { | |
460 list = g_list_prepend(list, message); | |
461 } | |
462 else { | |
463 /* Ignore non-http servers */ | |
464 g_strfreev(message); | |
465 } | |
466 } | |
467 list = g_list_reverse(list); | |
468 break; | |
469 case 401: | |
470 /* No site information available */ | |
471 break; | |
472 default: | |
473 break; | |
474 } | |
475 http_close_connection(sock); | |
476 return list; | |
477 } | |
478 | |
479 gint | |
480 search_for_discid(gchar * abs_filename, gchar ** cddb_file, guint32 disc_id) | |
481 { | |
482 GDir *dir; | |
483 const gchar *dir_entry; | |
484 gchar tmp_id[10]; | |
485 | |
486 if (!(dir = g_dir_open(abs_filename, 0, NULL))) | |
487 return (0); | |
488 | |
489 memset(tmp_id, 0, 10); | |
490 | |
491 snprintf(tmp_id, sizeof(tmp_id), "%08x", disc_id); | |
492 while ((dir_entry = g_dir_read_name(dir))) { | |
493 if (!strncmp(tmp_id, dir_entry, 8)) { | |
494 cddb_file[0] = g_build_filename(abs_filename, dir_entry, NULL); | |
495 g_dir_close(dir); | |
496 return (1); | |
497 } | |
498 } | |
499 g_dir_close(dir); | |
500 | |
501 return (0); | |
502 } | |
503 | |
504 gint | |
505 scan_cddb_dir(gchar * server, gchar ** cddb_file, guint32 disc_id) | |
506 { | |
507 | |
508 GDir *dir; | |
509 const gchar *dir_entry; | |
510 gchar abs_filename[FILENAME_MAX]; | |
511 | |
512 if (!(dir = g_dir_open(&server[7], 0, NULL))) { | |
513 return 0; | |
514 } | |
515 | |
516 while ((dir_entry = g_dir_read_name(dir))) { | |
517 strcpy(abs_filename, &server[7]); | |
518 if (abs_filename[strlen(abs_filename) - 1] != '/') { | |
519 strcat(abs_filename, "/"); | |
520 } | |
521 strcat(abs_filename, dir_entry); | |
522 | |
523 if (dir_entry[0] != '.' && | |
524 g_file_test(abs_filename, G_FILE_TEST_IS_DIR) && | |
525 search_for_discid(abs_filename, cddb_file, disc_id)) { | |
526 break; | |
527 } | |
528 } | |
529 | |
530 g_dir_close(dir); | |
531 return (cddb_file[0] != NULL); | |
532 } | |
533 | |
534 gint | |
535 cddb_read_file(gchar * file, cddb_disc_header_t * cddb_info, | |
536 cdinfo_t * cdinfo) | |
537 { | |
538 FILE *fd; | |
539 gchar buffer[256], buffer2[BUF2SIZE]; | |
540 gchar *realstr, *temp; | |
541 gint len, command, bufs; | |
542 gint num, oldnum; | |
543 | |
544 if ((fd = fopen(file, "r")) == NULL) | |
545 return 0; | |
546 | |
547 command = 1; | |
548 bufs = 0; | |
549 oldnum = -1; | |
550 while (fgets(buffer, 256, fd) != NULL) { | |
551 realstr = strchr(buffer, '='); | |
552 if (buffer[0] == '#' || !realstr) | |
553 continue; | |
554 | |
555 realstr++; | |
556 len = strlen(realstr); | |
557 if (realstr[len - 1] == '\n') | |
558 realstr[--len] = '\0'; /* remove newline */ | |
559 | |
560 switch (command) { | |
561 case 1: | |
562 if (!strncmp(buffer, "DISCID", 6)) | |
563 break; | |
564 command++; | |
565 case 2: | |
566 if (!strncmp(buffer, "DTITLE", 6)) { | |
567 strncpy(buffer2 + bufs, realstr, BUF2SIZE - bufs); | |
568 bufs += len; | |
569 break; | |
570 } | |
571 if (bufs > 0) { | |
572 buffer2[BUF2SIZE - 1] = '\0'; | |
573 if ((temp = strstr(buffer2, " / ")) != NULL) { | |
574 cdda_cdinfo_cd_set(cdinfo, g_strdup(temp + 3), | |
575 g_strndup(buffer2, temp - buffer2)); | |
576 } | |
577 else | |
578 cdda_cdinfo_cd_set(cdinfo, g_strdup(buffer2), | |
579 g_strdup(buffer2)); | |
580 bufs = 0; | |
581 } | |
582 command++; | |
583 case 3: | |
584 if (!strncmp(buffer, "TTITLE", 6)) { | |
585 num = atoi(buffer + 6); | |
586 if (oldnum < 0 || num == oldnum) { | |
587 strncpy(buffer2 + bufs, realstr, BUF2SIZE - bufs); | |
588 bufs += len; | |
589 } | |
590 else { | |
591 buffer2[BUF2SIZE - 1] = '\0'; | |
592 cdda_cdinfo_track_set(cdinfo, oldnum + 1, NULL, | |
593 g_strdup(buffer2)); | |
594 strncpy(buffer2, realstr, BUF2SIZE); | |
595 bufs = len; | |
596 } | |
597 oldnum = num; | |
598 break; | |
599 } | |
600 if (oldnum >= 0) | |
601 cdda_cdinfo_track_set(cdinfo, oldnum + 1, NULL, | |
602 g_strdup(buffer2)); | |
603 bufs = 0; | |
604 oldnum = -1; | |
605 command++; | |
606 case 4: | |
607 if (!strncmp(buffer, "EXTD", 4)) { | |
608 break; | |
609 } | |
610 command++; | |
611 case 5: | |
612 if (!strncmp(buffer, "EXTT", 4)) { | |
613 break; | |
614 } | |
615 command++; | |
616 case 6: | |
617 if (!strncmp(buffer, "PLAYORDER", 9)) { | |
618 break; | |
619 } | |
620 command++; | |
621 default: | |
622 g_log(NULL, G_LOG_LEVEL_WARNING, "%s: illegal cddb-data: %s", | |
747 | 623 PACKAGE_NAME, buffer); |
61 | 624 break; |
625 } | |
626 | |
627 } | |
628 | |
629 if (oldnum >= 0) | |
630 cdda_cdinfo_track_set(cdinfo, oldnum + 1, NULL, g_strdup(buffer2)); | |
631 | |
632 fclose(fd); | |
633 return (1); | |
634 } | |
635 | |
636 | |
637 void | |
638 cdda_cddb_get_info(cdda_disc_toc_t * toc, cdinfo_t * cdinfo) | |
639 { | |
640 guint32 disc_id; | |
641 cddb_disc_header_t cddb_disc_info; | |
642 gchar *cddb_file[1]; | |
643 disc_id = cdda_cddb_compute_discid(toc); | |
644 cddb_file[0] = NULL; | |
645 | |
646 if ((cached_id != disc_id) | |
647 && (strncmp(cdda_cfg.cddb_server, "file://", 7) != 0)) { | |
648 if (cddb_get_protocol_level() == 0) | |
649 return; | |
650 | |
651 cached_id = disc_id; | |
652 if (!cddb_query(cdda_cfg.cddb_server, toc, &cddb_disc_info)) | |
653 return; | |
654 if (!cddb_read(cdda_cfg.cddb_server, &cddb_disc_info, cdinfo)) | |
655 return; | |
656 cdinfo->is_valid = TRUE; | |
657 | |
658 } | |
659 else if ((cached_id != disc_id) | |
660 && (strncmp(cdda_cfg.cddb_server, "file://", 7) == 0)) { | |
661 cached_id = disc_id; | |
662 if (!scan_cddb_dir(cdda_cfg.cddb_server, cddb_file, disc_id)) | |
663 return; | |
664 if (!cddb_read_file(cddb_file[0], &cddb_disc_info, cdinfo)) { | |
665 g_free(cddb_file[0]); | |
666 return; | |
667 } | |
668 cdinfo->is_valid = TRUE; | |
669 g_free(cddb_file[0]); | |
670 } | |
671 } | |
672 | |
673 void | |
674 cdda_cddb_set_server(const gchar * new_server) | |
675 { | |
676 if (strcmp(cdda_cfg.cddb_server, new_server)) { | |
677 g_free(cdda_cfg.cddb_server); | |
678 cdda_cfg.cddb_server = g_strdup(new_server); | |
679 cdda_cfg.cddb_protocol_level = 0; | |
680 cached_id = 0; | |
681 } | |
682 } | |
683 | |
684 | |
685 static gchar * | |
686 cddb_position_string(gchar * input) | |
687 { | |
688 gchar deg[4], min[3]; | |
689 if (input == NULL || strlen(input) < 7) | |
690 return g_strdup(""); | |
691 strncpy(deg, input + 1, 3); | |
692 deg[3] = '\0'; | |
693 strncpy(min, input + 5, 2); | |
694 min[2] = '\0'; | |
695 return g_strdup_printf("%2d°%s'%c", atoi(deg), min, input[0]); | |
696 } | |
697 | |
698 static void | |
699 cddb_server_dialog_ok_cb(GtkWidget * w, gpointer data) | |
700 { | |
701 gchar *text; | |
702 gint pos; | |
703 GtkEntry *entry = GTK_ENTRY(data); | |
704 | |
705 if (!GTK_CLIST(server_clist)->selection) | |
706 return; | |
707 pos = GPOINTER_TO_INT(GTK_CLIST(server_clist)->selection->data); | |
708 gtk_clist_get_text(GTK_CLIST(server_clist), pos, 0, &text); | |
709 cdda_cddb_set_server(text); | |
710 gtk_entry_set_text(entry, text); | |
711 gtk_widget_destroy(server_dialog); | |
712 } | |
713 | |
714 static void | |
715 cddb_server_dialog_select(GtkWidget * w, gint row, gint column, | |
716 GdkEvent * event, gpointer data) | |
717 { | |
718 if (event->type == GDK_2BUTTON_PRESS) | |
719 cddb_server_dialog_ok_cb(NULL, NULL); | |
720 } | |
721 | |
722 void | |
723 cdda_cddb_show_server_dialog(GtkWidget * w, gpointer data) | |
724 { | |
725 GtkWidget *vbox, *bbox, *okbutton, *cancelbutton; | |
726 GtkEntry *server_entry = GTK_ENTRY(data); | |
727 gchar *titles[] = { "Server", "Latitude", "Longitude", "Description" }; | |
728 GList *servers; | |
729 const gchar *server; | |
730 gint level; | |
731 | |
732 if (server_dialog) | |
733 return; | |
734 | |
735 server = gtk_entry_get_text(server_entry); | |
736 | |
737 if ((level = cddb_check_protocol_level(server)) < 3) { | |
738 if (!level) | |
739 xmms_show_message("CDDB", | |
740 "Unable to connect to CDDB-server", | |
741 "Ok", FALSE, NULL, NULL); | |
742 else | |
743 /* CDDB level < 3 has the "sites" command, | |
744 but the format is different. Not supported yet */ | |
745 xmms_show_message("CDDB", | |
746 "Can't get server list from the current CDDB-server\n" | |
747 "Unsupported CDDB protocol level", | |
748 "Ok", FALSE, NULL, NULL); | |
749 return; | |
750 } | |
751 | |
752 if ((servers = cddb_get_server_list(server, level)) == NULL) { | |
753 xmms_show_message("CDDB", | |
754 "No site information available", | |
755 "Ok", FALSE, NULL, NULL); | |
756 return; | |
757 } | |
758 | |
759 server_dialog = gtk_dialog_new(); | |
760 g_signal_connect(G_OBJECT(server_dialog), "destroy", | |
761 G_CALLBACK(gtk_widget_destroyed), &server_dialog); | |
762 gtk_window_set_title(GTK_WINDOW(server_dialog), "CDDB servers"); | |
763 gtk_window_set_modal(GTK_WINDOW(server_dialog), TRUE); | |
764 | |
765 vbox = gtk_vbox_new(FALSE, 0); | |
766 gtk_container_set_border_width(GTK_CONTAINER(vbox), 15); | |
767 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(server_dialog)->vbox), vbox, | |
768 TRUE, TRUE, 0); | |
769 | |
770 server_clist = gtk_clist_new_with_titles(4, titles); | |
771 g_signal_connect(G_OBJECT(server_clist), "select-row", | |
772 G_CALLBACK(cddb_server_dialog_select), NULL); | |
773 gtk_box_pack_start(GTK_BOX(vbox), server_clist, TRUE, TRUE, 0); | |
774 | |
775 bbox = gtk_hbutton_box_new(); | |
776 gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END); | |
777 gtk_button_box_set_spacing(GTK_BUTTON_BOX(bbox), 5); | |
778 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(server_dialog)->action_area), | |
779 bbox, TRUE, TRUE, 0); | |
780 | |
781 okbutton = gtk_button_new_with_label("Ok"); | |
782 g_signal_connect(G_OBJECT(okbutton), "clicked", | |
783 G_CALLBACK(cddb_server_dialog_ok_cb), data); | |
784 gtk_box_pack_start(GTK_BOX(bbox), okbutton, TRUE, TRUE, 0); | |
785 cancelbutton = gtk_button_new_with_label("Cancel"); | |
786 g_signal_connect_swapped(G_OBJECT(cancelbutton), "clicked", | |
787 G_CALLBACK(gtk_widget_destroy), | |
788 GTK_OBJECT(server_dialog)); | |
789 gtk_box_pack_start(GTK_BOX(bbox), cancelbutton, TRUE, TRUE, 0); | |
790 GTK_WIDGET_SET_FLAGS(okbutton, GTK_CAN_DEFAULT); | |
791 GTK_WIDGET_SET_FLAGS(cancelbutton, GTK_CAN_DEFAULT); | |
792 gtk_widget_grab_default(okbutton); | |
793 | |
794 while (servers) { | |
795 gchar *row[4]; | |
796 gint i; | |
797 | |
798 row[0] = g_strdup(((gchar **) servers->data)[0]); | |
799 row[1] = cddb_position_string(((gchar **) servers->data)[4]); | |
800 row[2] = cddb_position_string(((gchar **) servers->data)[5]); | |
801 row[3] = g_strdup(((gchar **) servers->data)[6]); | |
802 gtk_clist_append(GTK_CLIST(server_clist), row); | |
803 for (i = 0; i < 4; i++) | |
804 g_free(row[i]); | |
805 g_strfreev(servers->data); | |
806 servers = g_list_next(servers); | |
807 } | |
808 g_list_free(servers); | |
809 gtk_clist_columns_autosize(GTK_CLIST(server_clist)); | |
810 gtk_widget_show_all(server_dialog); | |
811 } | |
812 | |
813 static gboolean | |
814 cddb_update_log_window(gpointer data) | |
815 { | |
816 if (!debug_window) { | |
817 cddb_timeout_id = 0; | |
818 return FALSE; | |
819 } | |
820 | |
821 G_LOCK(list); | |
822 if (temp_messages != NULL) { | |
823 GList *temp; | |
824 GDK_THREADS_ENTER(); | |
825 gtk_clist_freeze(GTK_CLIST(debug_clist)); | |
826 for (temp = temp_messages; temp; temp = temp->next) { | |
827 gchar *text = temp->data; | |
828 gtk_clist_append(GTK_CLIST(debug_clist), &text); | |
829 g_free(text); | |
830 } | |
831 gtk_clist_columns_autosize(GTK_CLIST(debug_clist)); | |
832 gtk_clist_thaw(GTK_CLIST(debug_clist)); | |
833 gtk_clist_moveto(GTK_CLIST(debug_clist), | |
834 GTK_CLIST(debug_clist)->rows - 1, -1, 0.5, 0); | |
835 GDK_THREADS_LEAVE(); | |
836 g_list_free(temp_messages); | |
837 temp_messages = NULL; | |
838 } | |
839 G_UNLOCK(list); | |
840 return TRUE; | |
841 } | |
842 | |
843 | |
844 void | |
845 cdda_cddb_show_network_window(GtkWidget * w, gpointer data) | |
846 { | |
847 GtkWidget *vbox, *bbox, *close, *scroll_win; | |
848 GList *temp; | |
849 | |
850 if (debug_window) | |
851 return; | |
852 | |
853 debug_window = gtk_window_new(GTK_WINDOW_TOPLEVEL); | |
854 g_signal_connect(G_OBJECT(debug_window), "destroy", | |
855 G_CALLBACK(gtk_widget_destroyed), &debug_window); | |
856 gtk_window_set_title(GTK_WINDOW(debug_window), "CDDB networkdebug"); | |
857 gtk_window_set_resizable(GTK_WINDOW(debug_window), TRUE); | |
858 gtk_window_set_default_size(GTK_WINDOW(debug_window), 400, 150); | |
859 gtk_container_border_width(GTK_CONTAINER(debug_window), 10); | |
860 | |
861 vbox = gtk_vbox_new(FALSE, 10); | |
862 gtk_container_add(GTK_CONTAINER(debug_window), vbox); | |
863 | |
864 scroll_win = gtk_scrolled_window_new(NULL, NULL); | |
865 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll_win), | |
866 GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS); | |
867 debug_clist = gtk_clist_new(1); | |
868 gtk_container_add(GTK_CONTAINER(scroll_win), debug_clist); | |
869 gtk_box_pack_start(GTK_BOX(vbox), scroll_win, TRUE, TRUE, 0); | |
870 | |
871 temp = debug_messages; | |
872 while (temp) { | |
873 gtk_clist_prepend(GTK_CLIST(debug_clist), (gchar **) & temp->data); | |
874 temp = g_list_next(temp); | |
875 } | |
876 | |
877 bbox = gtk_hbutton_box_new(); | |
878 gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_SPREAD); | |
879 gtk_button_box_set_spacing(GTK_BUTTON_BOX(bbox), 5); | |
880 gtk_box_pack_start(GTK_BOX(vbox), bbox, FALSE, FALSE, 0); | |
881 | |
882 close = gtk_button_new_with_label("Close"); | |
883 g_signal_connect_swapped(G_OBJECT(close), "clicked", | |
884 G_CALLBACK(gtk_widget_destroy), | |
885 GTK_OBJECT(debug_window)); | |
886 GTK_WIDGET_SET_FLAGS(close, GTK_CAN_DEFAULT); | |
887 gtk_box_pack_start(GTK_BOX(bbox), close, TRUE, TRUE, 0); | |
888 gtk_widget_grab_default(close); | |
889 | |
890 gtk_clist_columns_autosize(GTK_CLIST(debug_clist)); | |
891 gtk_clist_set_button_actions(GTK_CLIST(debug_clist), 0, | |
892 GTK_BUTTON_IGNORED); | |
893 gtk_clist_moveto(GTK_CLIST(debug_clist), | |
894 GTK_CLIST(debug_clist)->rows - 1, -1, 0, 0); | |
895 | |
896 cddb_timeout_id = gtk_timeout_add(500, cddb_update_log_window, NULL); | |
897 gtk_widget_show_all(debug_window); | |
898 } | |
899 | |
900 void | |
901 cddb_quit(void) | |
902 { | |
903 if (cddb_timeout_id) | |
904 gtk_timeout_remove(cddb_timeout_id); | |
905 cddb_timeout_id = 0; | |
906 } |