1 /*                                                     -*- linux-c -*-
2     Copyright (C) 2004 Tom Szilagyi
3 
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8 
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13 
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17 
18     $Id: cddb_lookup.c 1287 2014-04-27 20:51:08Z tszilagyi $
19 */
20 
21 #include <config.h>
22 
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <glib.h>
27 #include <glib-object.h>
28 #include <gdk/gdk.h>
29 #include <gtk/gtk.h>
30 #include <cddb/cddb.h>
31 
32 #ifdef HAVE_CDDA
33 #include "cdda.h"
34 #include "store_cdda.h"
35 #endif /* HAVE_CDDA */
36 
37 #include "athread.h"
38 #include "common.h"
39 #include "utils.h"
40 #include "utils_gui.h"
41 #include "i18n.h"
42 #include "options.h"
43 #include "music_browser.h"
44 #include "store_file.h"
45 #include "cddb_lookup.h"
46 
47 
48 extern options_t options;
49 
50 extern GtkWidget * browser_window;
51 extern GtkTreeStore * music_store;
52 
53 
54 enum {
55 	CASE_UP,
56 	CASE_DOWN
57 };
58 
59 enum {
60 	CDDB_INIT,
61 	CDDB_BUSY,
62 	CDDB_SUCCESS,
63 	CDDB_ERROR,
64 	CDDB_NO_MATCH,
65 	CDDB_ABORTED
66 };
67 
68 enum {
69 	CDDB_TYPE_QUERY,
70 	CDDB_TYPE_SUBMIT,
71 	CDDB_TYPE_SUBMIT_NEW
72 };
73 
74 typedef struct {
75 
76 	AQUALUNG_THREAD_DECLARE(thread_id);
77 	AQUALUNG_MUTEX_DECLARE(mutex);
78 
79 	int state;
80 	int type;
81 
82 	int ntracks;
83 	int * frames;
84 	int record_length;
85 
86 	cddb_disc_t ** records;
87 	int nrecords;
88 
89 	int counter;
90 	int aborted;
91 
92 	GtkTreeIter iter_record;
93 
94 	GtkWidget * progress_win;
95 	GtkWidget * progress_label;
96 	GtkWidget * progbar;
97 
98 	GtkWidget * combo;
99 
100 	GtkWidget * artist_entry;
101 	GtkWidget * title_entry;
102 	GtkWidget * year_spinner;
103 	GtkWidget * category_entry;
104 	GtkWidget * category_combo;
105 	GtkWidget * genre_entry;
106 	GtkWidget * ext_entry;
107 	GtkWidget * track_list;
108 	GtkListStore * track_store;
109 
110 	GtkWidget * year_import_button;
111 	GtkWidget * title_import_button;
112 
113 	int year_imported;
114 	int title_imported;
115 
116 } cddb_lookup_t;
117 
118 
119 void cddb_dialog(cddb_lookup_t * data);
120 void cddb_dialog_load_disc(cddb_lookup_t * data, cddb_disc_t * disc);
121 
122 
123 const char *
notnull(const char * str)124 notnull(const char * str) {
125 
126 	return str ? str : "";
127 }
128 
129 cddb_lookup_t *
cddb_lookup_new()130 cddb_lookup_new () {
131 
132 	cddb_lookup_t * data;
133 
134 	if ((data = calloc(1, sizeof(cddb_lookup_t))) == NULL) {
135 		fprintf(stderr, "cddb_lookup_new: calloc error\n");
136 		return NULL;
137 	}
138 
139 #ifndef HAVE_LIBPTHREAD
140 	data->mutex = g_mutex_new();
141 #endif /* !HAVE_LIBPTHREAD */
142 
143 	data->state = CDDB_INIT;
144 
145 	return data;
146 }
147 
148 void
cddb_lookup_set_state(cddb_lookup_t * data,int state)149 cddb_lookup_set_state(cddb_lookup_t * data, int state) {
150 
151 	AQUALUNG_MUTEX_LOCK(data->mutex);
152 	data->state = state;
153 	AQUALUNG_MUTEX_UNLOCK(data->mutex);
154 }
155 
156 int
cddb_lookup_get_state(cddb_lookup_t * data)157 cddb_lookup_get_state(cddb_lookup_t * data) {
158 
159 	int state;
160 
161 	AQUALUNG_MUTEX_LOCK(data->mutex);
162 	state = data->state;
163 	AQUALUNG_MUTEX_UNLOCK(data->mutex);
164 
165 	return state;
166 }
167 
168 void
cddb_lookup_free(cddb_lookup_t * data)169 cddb_lookup_free(cddb_lookup_t * data) {
170 
171 	if (data->records != NULL) {
172 		int i;
173 		for (i = 0; i < data->nrecords; i++) {
174 			if (data->records[i] != NULL) {
175 				cddb_disc_destroy(data->records[i]);
176 			}
177 		}
178 		free(data->records);
179 	}
180 
181 	if (data->frames != NULL) {
182 		free(data->frames);
183 	}
184 
185 #ifndef HAVE_LIBPTHREAD
186 	g_mutex_free(data->mutex);
187 #endif /* !HAVE_LIBPTHREAD */
188 
189 	free(data);
190 }
191 
192 
193 int
cddb_connection_setup(cddb_conn_t ** conn)194 cddb_connection_setup(cddb_conn_t ** conn) {
195 
196 	if ((*conn = cddb_new()) == NULL) {
197 		fprintf(stderr, "cddb_lookup.c: cddb_connection_setup(): cddb_new error\n");
198 		return 1;
199 	}
200 
201 	cddb_set_server_name(*conn, options.cddb_server);
202 	cddb_set_timeout(*conn, options.cddb_timeout);
203 	cddb_set_charset(*conn, "UTF-8");
204 
205 	if (options.cddb_local[0] != '\0') {
206 		cddb_cache_set_dir(*conn, options.cddb_local);
207 	}
208 
209 	if (options.cddb_cache_only) {
210 		cddb_cache_only(*conn);
211 	}
212 
213 	if (options.inet_use_proxy) {
214 		cddb_http_enable(*conn);
215 		cddb_set_server_port(*conn, 80);
216 		cddb_http_proxy_enable(*conn);
217 		cddb_set_http_proxy_server_name(*conn, options.inet_proxy);
218 		cddb_set_http_proxy_server_port(*conn, options.inet_proxy_port);
219 	} else {
220 		cddb_http_proxy_disable(*conn);
221 		if (options.cddb_use_http) {
222 			cddb_http_enable(*conn);
223 			cddb_set_server_port(*conn, 80);
224 		} else {
225 			cddb_http_disable(*conn);
226 			cddb_set_server_port(*conn, 888);
227 		}
228 	}
229 
230 	return 0;
231 }
232 
233 void
cddb_lookup(cddb_lookup_t * data)234 cddb_lookup(cddb_lookup_t * data) {
235 
236 	cddb_conn_t * conn = NULL;
237 	cddb_disc_t * disc = NULL;
238 	cddb_track_t * track = NULL;
239 
240 	int i;
241 
242 	if (cddb_connection_setup(&conn) == 1) {
243 		cddb_lookup_set_state(data, CDDB_ERROR);
244 		return;
245 	}
246 
247 	if ((disc = cddb_disc_new()) == NULL) {
248 		fprintf(stderr, "cddb_lookup(): cddb_disc_new error\n");
249 		cddb_lookup_set_state(data, CDDB_ERROR);
250 		return;
251 	}
252 
253 	cddb_disc_set_length(disc, data->record_length);
254 
255 	for (i = 0; i < data->ntracks; i++) {
256 		track = cddb_track_new();
257 		cddb_track_set_frame_offset(track, data->frames[i]);
258 		cddb_disc_add_track(disc, track);
259 	}
260 
261 	data->nrecords = cddb_query(conn, disc);
262 
263 	if (data->nrecords <= 0) {
264 		cddb_destroy(conn);
265 		cddb_disc_destroy(disc);
266 		cddb_lookup_set_state(data, (data->nrecords == 0) ? CDDB_NO_MATCH : CDDB_ERROR);
267 		return;
268 	}
269 
270 	cddb_lookup_set_state(data, CDDB_BUSY);
271 
272 	if ((data->records = (cddb_disc_t **)calloc(data->nrecords, sizeof(cddb_disc_t *))) == NULL) {
273 		fprintf(stderr, "cddb_lookup(): malloc error\n");
274 		cddb_lookup_set_state(data, CDDB_ERROR);
275 		return;
276 	}
277 
278 	for (i = 0; i < data->nrecords; i++) {
279 
280 		if (cddb_lookup_get_state(data) == CDDB_ABORTED) {
281 			break;
282 		}
283 
284 		if (i > 0 && !cddb_query_next(conn, disc)) {
285 			break;
286 		}
287 		cddb_read(conn, disc);
288 		data->records[i] = cddb_disc_clone(disc);
289 
290 		AQUALUNG_MUTEX_LOCK(data->mutex);
291 		data->counter++;
292 		AQUALUNG_MUTEX_UNLOCK(data->mutex);
293 	}
294 
295 	cddb_destroy(conn);
296 	cddb_disc_destroy(disc);
297 
298 	if (cddb_lookup_get_state(data) == CDDB_ABORTED) {
299 		cddb_lookup_free(data);
300 		return;
301 	}
302 
303 	cddb_lookup_set_state(data, CDDB_SUCCESS);
304 }
305 
306 
307 static void
abort_cb(GtkWidget * widget,gpointer user_data)308 abort_cb(GtkWidget * widget, gpointer user_data) {
309 
310 	cddb_lookup_set_state((cddb_lookup_t *)user_data, CDDB_ABORTED);
311 }
312 
313 
314 void
create_query_progress_window(cddb_lookup_t * data)315 create_query_progress_window(cddb_lookup_t * data) {
316 
317 	GtkWidget * vbox;
318 	GtkWidget * hbuttonbox;
319 	GtkWidget * hseparator;
320 	GtkWidget * abort_button;
321 
322 
323 	data->progress_win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
324         gtk_window_set_title(GTK_WINDOW(data->progress_win), _("CDDB query"));
325         gtk_window_set_position(GTK_WINDOW(data->progress_win), GTK_WIN_POS_CENTER);
326         gtk_window_resize(GTK_WINDOW(data->progress_win), 330, 120);
327         g_signal_connect(G_OBJECT(data->progress_win), "delete_event",
328 			 G_CALLBACK(abort_cb), data);
329         gtk_container_set_border_width(GTK_CONTAINER(data->progress_win), 10);
330 
331 	vbox = gtk_vbox_new(FALSE, 0);
332 	gtk_container_add(GTK_CONTAINER(data->progress_win), vbox);
333 
334 	data->progress_label = gtk_label_new(_("Retrieving matches from server..."));
335 	gtk_box_pack_start(GTK_BOX(vbox), data->progress_label, FALSE, FALSE, 0);
336 
337 	data->progbar = gtk_progress_bar_new();
338 	gtk_progress_bar_set_text(GTK_PROGRESS_BAR(data->progbar), _("Connecting to CDDB server..."));
339 	gtk_box_pack_start(GTK_BOX(vbox), data->progbar, FALSE, FALSE, 6);
340 
341         hseparator = gtk_hseparator_new ();
342         gtk_widget_show (hseparator);
343         gtk_box_pack_start (GTK_BOX (vbox), hseparator, FALSE, TRUE, 5);
344 
345 	hbuttonbox = gtk_hbutton_box_new();
346 	gtk_box_pack_end(GTK_BOX(vbox), hbuttonbox, FALSE, TRUE, 0);
347 	gtk_button_box_set_layout(GTK_BUTTON_BOX(hbuttonbox), GTK_BUTTONBOX_END);
348 
349         abort_button = gui_stock_label_button(_("Abort"), GTK_STOCK_CANCEL);
350         g_signal_connect(G_OBJECT(abort_button), "clicked",
351 			 G_CALLBACK(abort_cb), data);
352   	gtk_container_add(GTK_CONTAINER(hbuttonbox), abort_button);
353 
354         gtk_widget_grab_focus(abort_button);
355 
356 	gtk_widget_show_all(data->progress_win);
357 }
358 
359 
360 #ifdef HAVE_CDDA
361 void
store_cdda_export_merged(cddb_lookup_t * data,char * artist,char * record,char * genre,int year,char ** tracks)362 store_cdda_export_merged(cddb_lookup_t * data, char * artist, char * record, char * genre, int year, char ** tracks) {
363 
364 	int i;
365 	GtkTreeIter iter;
366 
367 	char name[MAXLEN];
368 	cdda_drive_t * drive;
369 
370 	for (i = 0; gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(music_store),
371 						  &iter, &data->iter_record, i); i++) {
372 
373 		gtk_tree_store_set(music_store, &iter, MS_COL_NAME, tracks[i], -1);
374 	}
375 
376 	gtk_tree_model_get(GTK_TREE_MODEL(music_store), &data->iter_record, MS_COL_DATA, &drive, -1);
377 
378 	strncpy(drive->disc.artist_name, artist, MAXLEN-1);
379 	strncpy(drive->disc.record_name, record, MAXLEN-1);
380 	strncpy(drive->disc.genre, genre, MAXLEN-1);
381 	drive->disc.year = year;
382 
383 	snprintf(name, MAXLEN-1, "%s: %s",
384 		 drive->disc.artist_name,
385 		 drive->disc.record_name);
386 
387 	gtk_tree_store_set(music_store, &data->iter_record, MS_COL_NAME, name, -1);
388 
389 	music_store_selection_changed(STORE_TYPE_CDDA);
390 }
391 #endif /* HAVE_CDDA */
392 
393 
394 void
cddb_lookup_merge(cddb_lookup_t * data,char * artist,char * record,char * genre,int * year,char ** tracks)395 cddb_lookup_merge(cddb_lookup_t * data, char * artist, char * record, char * genre, int * year, char ** tracks) {
396 
397 	int i, j, y;
398 
399 	map_t * map_artist = NULL;
400 	map_t * map_record = NULL;
401 	map_t * map_genre = NULL;
402 	map_t * map_year = NULL;
403 	map_t ** map_tracks = NULL;
404 
405 	char tmp[MAXLEN];
406 
407 
408 	if ((map_tracks = (map_t **)calloc(data->ntracks, sizeof(map_t *))) == NULL) {
409 		fprintf(stderr, "cddb_lookup_merge: calloc error\n");
410 		return;
411 	}
412 
413 	for (i = 0; i < data->nrecords; i++) {
414 
415 		strncpy(tmp, notnull(cddb_disc_get_artist(data->records[i])), MAXLEN-1);
416 		if (!is_all_wspace(tmp)) {
417 			map_put(&map_artist, tmp);
418 		}
419 
420 		strncpy(tmp, notnull(cddb_disc_get_title(data->records[i])), MAXLEN-1);
421 		if (!is_all_wspace(tmp)) {
422 			map_put(&map_record, tmp);
423 		}
424 
425 		if (genre != NULL) {
426 			strncpy(tmp, notnull(cddb_disc_get_genre(data->records[i])), MAXLEN-1);
427 			if (!is_all_wspace(tmp)) {
428 				map_put(&map_genre, tmp);
429 			}
430 		}
431 
432 		y = cddb_disc_get_year(data->records[i]);
433 		if (is_valid_year(y)) {
434 			snprintf(tmp, MAXLEN-1, "%d", y);
435 			map_put(&map_year, tmp);
436 		}
437 
438 		for (j = 0; j < data->ntracks; j++) {
439 			strncpy(tmp,
440 				notnull(cddb_track_get_title(cddb_disc_get_track(data->records[i], j))),
441 				MAXLEN-1);
442 			if (!is_all_wspace(tmp)) {
443 				map_put(map_tracks + j, tmp);
444 			}
445 		}
446 	}
447 
448 	if (map_artist) {
449 		strncpy(artist, map_get_max(map_artist), MAXLEN-1);
450 	}
451 
452 	if (map_record) {
453 		strncpy(record, map_get_max(map_record), MAXLEN-1);
454 	}
455 
456 	if (map_genre) {
457 		strncpy(genre, map_get_max(map_genre), MAXLEN-1);
458 	}
459 
460 	if (map_year) {
461 		*year = atoi(map_get_max(map_year));
462 	}
463 
464 	for (j = 0; j < data->ntracks; j++) {
465 
466 		if (map_tracks[j]) {
467 			strncpy(tracks[j], map_get_max(map_tracks[j]), MAXLEN-1);
468 			map_free(map_tracks[j]);
469 		}
470 	}
471 
472 	map_free(map_artist);
473 	map_free(map_record);
474 	map_free(map_genre);
475 	map_free(map_year);
476 	free(map_tracks);
477 }
478 
479 gboolean
query_timeout_cb(gpointer user_data)480 query_timeout_cb(gpointer user_data) {
481 
482 	cddb_lookup_t * data = (cddb_lookup_t *)user_data;
483 	int state = cddb_lookup_get_state(data);
484 	char text[MAXLEN];
485 
486 	switch (state) {
487 	case CDDB_INIT:
488 		return TRUE;
489 	case CDDB_BUSY:
490 		snprintf(text, MAXLEN, "%d / %d", data->counter, data->nrecords);
491 		gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(data->progbar),
492 					      (double)data->counter / data->nrecords);
493 		gtk_progress_bar_set_text(GTK_PROGRESS_BAR(data->progbar), text);
494 		return TRUE;
495 	case CDDB_SUCCESS:
496 		gtk_widget_destroy(data->progress_win);
497 		cddb_dialog(data);
498 		break;
499 	case CDDB_ERROR:
500 		gtk_widget_destroy(data->progress_win);
501 		message_dialog(_("Error"),
502 			       browser_window,
503 			       GTK_MESSAGE_ERROR,
504 			       GTK_BUTTONS_OK,
505 			       NULL,
506 			       _("An error occurred while attempting "
507 				 "to connect to the CDDB server."));
508 		break;
509 	case CDDB_NO_MATCH:
510 		gtk_widget_destroy(data->progress_win);
511 		if (data->type == CDDB_TYPE_QUERY) {
512 			message_dialog(_("Warning"),
513 				       browser_window,
514 				       GTK_MESSAGE_WARNING,
515 				       GTK_BUTTONS_OK,
516 				       NULL,
517 				       _("No matching record found."));
518 		} else {
519 			data->type = CDDB_TYPE_SUBMIT_NEW;
520 			cddb_dialog(data);
521 		}
522 		break;
523 	case CDDB_ABORTED:
524 		gtk_widget_destroy(data->progress_win);
525 		return FALSE;
526 	}
527 
528 	cddb_lookup_free(data);
529 
530 	return FALSE;
531 }
532 
533 
534 #ifdef HAVE_CDDA
535 gboolean
cdda_auto_query_timeout_cb(gpointer user_data)536 cdda_auto_query_timeout_cb(gpointer user_data) {
537 
538 	cddb_lookup_t * data = (cddb_lookup_t *)user_data;
539 	int state = cddb_lookup_get_state(data);
540 
541 	if (state == CDDB_INIT || state == CDDB_BUSY) {
542 		return TRUE;
543 	}
544 
545 	if (state == CDDB_SUCCESS) {
546 		char artist[MAXLEN];
547 		char record[MAXLEN];
548 		char genre[MAXLEN];
549 		int year = 0;
550 		char ** tracks;
551 		int i;
552 
553 		artist[0] = '\0';
554 		record[0] = '\0';
555 		genre[0] = '\0';
556 
557 		if ((tracks = calloc(data->ntracks, sizeof(char *))) == NULL) {
558 			fprintf(stderr, "cdda_auto_query_timeout_cb(): calloc error\n");
559 			return FALSE;
560 		}
561 
562 		for (i = 0; i < data->ntracks; i++) {
563 			if ((tracks[i] = calloc(1, MAXLEN * sizeof(char))) == NULL) {
564 				fprintf(stderr, "cdda_auto_query_timeout_cb(): calloc error\n");
565 				return FALSE;
566 			}
567 		}
568 
569 		cddb_lookup_merge(data, artist, record, genre, &year, tracks);
570 		store_cdda_export_merged(data, artist, record, genre, year, tracks);
571 
572 		for (i = 0; i < data->ntracks; i++) {
573 			free(tracks[i]);
574 		}
575 		free(tracks);
576 	}
577 
578 	if (options.cdda_add_to_playlist) {
579 		cdda_drive_t * drive;
580 		gtk_tree_model_get(GTK_TREE_MODEL(music_store), &data->iter_record,
581 				   MS_COL_DATA, &drive, -1);
582 		cdda_add_to_playlist(&data->iter_record, drive->disc.hash);
583 	}
584 
585 	cddb_lookup_free(data);
586 
587 	return FALSE;
588 }
589 #endif /* HAVE_CDDA */
590 
591 
592 static void
add_to_comments(cddb_lookup_t * data,GtkWidget * entry)593 add_to_comments(cddb_lookup_t * data, GtkWidget * entry) {
594 
595 	record_data_t * record_data;
596 
597 	gtk_tree_model_get(GTK_TREE_MODEL(music_store), &data->iter_record, MS_COL_DATA, &record_data, -1);
598 
599 	if (record_data->comment != NULL && record_data->comment[0] != '\0') {
600 		char comment[MAXLEN];
601 		snprintf(comment, MAXLEN-1, "%s\n%s",
602 			 record_data->comment,
603 			 gtk_entry_get_text(GTK_ENTRY(entry)));
604 		free_strdup(&record_data->comment, comment);
605 	} else {
606 		free_strdup(&record_data->comment, gtk_entry_get_text(GTK_ENTRY(entry)));
607 	}
608 
609 	music_store_mark_changed(&data->iter_record);
610 }
611 
612 static void
add_category_to_comments(GtkWidget * widget,gpointer user_data)613 add_category_to_comments(GtkWidget * widget, gpointer user_data) {
614 
615 	cddb_lookup_t * data = (cddb_lookup_t *)user_data;
616 	add_to_comments(data, data->category_entry);
617 }
618 
619 static void
add_genre_to_comments(GtkWidget * widget,gpointer user_data)620 add_genre_to_comments(GtkWidget * widget, gpointer user_data) {
621 
622 	cddb_lookup_t * data = (cddb_lookup_t *)user_data;
623 	add_to_comments(data, data->genre_entry);
624 }
625 
626 static void
add_ext_to_comments(GtkWidget * widget,gpointer user_data)627 add_ext_to_comments(GtkWidget * widget, gpointer user_data) {
628 
629 	cddb_lookup_t * data = (cddb_lookup_t *)user_data;
630 	add_to_comments(data, data->ext_entry);
631 }
632 
633 static void
import_as_artist(GtkWidget * widget,gpointer user_data)634 import_as_artist(GtkWidget * widget, gpointer user_data) {
635 
636 	GtkTreeIter parent;
637 	GtkTreePath * path;
638 	cddb_lookup_t * data = (cddb_lookup_t *)user_data;
639 
640 	path = gtk_tree_model_get_path(GTK_TREE_MODEL(music_store), &data->iter_record);
641 	gtk_tree_path_up(path);
642 	gtk_tree_model_get_iter(GTK_TREE_MODEL(music_store), &parent, path);
643 	gtk_tree_path_free(path);
644 	gtk_tree_store_set(music_store, &parent,
645 			   MS_COL_NAME, gtk_entry_get_text(GTK_ENTRY(data->artist_entry)), -1);
646 
647 	music_store_mark_changed(&parent);
648 }
649 
650 
651 static void
import_as_title(GtkWidget * widget,gpointer user_data)652 import_as_title(GtkWidget * widget, gpointer user_data) {
653 
654 	cddb_lookup_t * data = (cddb_lookup_t *)user_data;
655 
656 	if (data->title_imported) {
657 		gtk_tree_store_set(music_store, &data->iter_record,
658 				   MS_COL_SORT, gtk_entry_get_text(GTK_ENTRY(data->title_entry)), -1);
659 	} else {
660 		gtk_tree_store_set(music_store, &data->iter_record,
661 				   MS_COL_NAME, gtk_entry_get_text(GTK_ENTRY(data->title_entry)), -1);
662 
663 		data->title_imported = 1;
664 		gtk_button_set_label(GTK_BUTTON(data->title_import_button), _("Import as Sort Key"));
665 	}
666 
667 	music_store_mark_changed(&data->iter_record);
668 }
669 
670 static void
import_as_year(GtkWidget * widget,gpointer user_data)671 import_as_year(GtkWidget * widget, gpointer user_data) {
672 
673 	cddb_lookup_t * data = (cddb_lookup_t *)user_data;
674 	int year = gtk_spin_button_get_value(GTK_SPIN_BUTTON(data->year_spinner));
675 
676 	if (data->year_imported) {
677 		char buf[16];
678 		snprintf(buf, 15, "%d", year);
679 		gtk_tree_store_set(music_store, &data->iter_record, MS_COL_SORT, buf, -1);
680 	} else {
681 		record_data_t * record_data;
682 		gtk_tree_model_get(GTK_TREE_MODEL(music_store), &data->iter_record,
683 				   MS_COL_DATA, &record_data, -1);
684 		record_data->year = year;
685 
686 		data->year_imported = 1;
687 		gtk_button_set_label(GTK_BUTTON(data->year_import_button), _("Import as Sort Key"));
688 	}
689 
690 
691 	music_store_mark_changed(&data->iter_record);
692 }
693 
694 gboolean
title_entry_focused(GtkWidget * widget,GdkEventFocus * event,gpointer user_data)695 title_entry_focused(GtkWidget * widget, GdkEventFocus * event, gpointer user_data) {
696 
697 	cddb_lookup_t * data = (cddb_lookup_t *)user_data;
698 
699 	data->title_imported = 0;
700 	gtk_button_set_label(GTK_BUTTON(data->title_import_button), _("Import as Title"));
701 
702 	return FALSE;
703 }
704 
705 gboolean
year_spinner_focused(GtkWidget * widget,GdkEventFocus * event,gpointer user_data)706 year_spinner_focused(GtkWidget * widget, GdkEventFocus * event, gpointer user_data) {
707 
708 	cddb_lookup_t * data = (cddb_lookup_t *)user_data;
709 
710 	data->year_imported = 0;
711 	gtk_button_set_label(GTK_BUTTON(data->year_import_button), _("Import as Year"));
712 
713 	return FALSE;
714 }
715 
716 
717 static void
changed_combo(GtkWidget * widget,gpointer * user_data)718 changed_combo(GtkWidget * widget, gpointer * user_data) {
719 
720 	cddb_lookup_t * data = (cddb_lookup_t *)user_data;
721 	int i = gtk_combo_box_get_active(GTK_COMBO_BOX(data->combo));
722 
723 	if (i >= 0 && i < data->nrecords) {
724 		cddb_dialog_load_disc(data, data->records[i]);
725 	}
726 
727 	if (data->type == CDDB_TYPE_QUERY && iter_get_store_type(&data->iter_record) == STORE_TYPE_FILE) {
728 		title_entry_focused(data->title_entry, NULL, user_data);
729 		year_spinner_focused(data->year_spinner, NULL, user_data);
730 	}
731 }
732 
733 
734 static void
cell_edited_callback(GtkCellRendererText * cell,gchar * path,gchar * text,gpointer user_data)735 cell_edited_callback(GtkCellRendererText * cell, gchar * path, gchar * text, gpointer user_data) {
736 
737 	cddb_lookup_t * data = (cddb_lookup_t *)user_data;
738 	GtkTreeIter iter;
739 
740 	if (gtk_tree_model_get_iter_from_string(GTK_TREE_MODEL(data->track_store), &iter, path)) {
741 		gtk_list_store_set(data->track_store, &iter, 0, text, -1);
742 	}
743 }
744 
745 
746 gboolean
create_cddb_write_error_dialog(gpointer data)747 create_cddb_write_error_dialog(gpointer data) {
748 
749 	message_dialog(_("Error"),
750 		       browser_window,
751 		       GTK_MESSAGE_ERROR,
752 		       GTK_BUTTONS_OK,
753 		       NULL,
754 		       (char *)data);
755 
756 	return FALSE;
757 }
758 
759 int
create_cddb_write_warn_dialog(char * text)760 create_cddb_write_warn_dialog(char * text) {
761 
762 	int ret = message_dialog(_("Warning"),
763 				 browser_window,
764 				 GTK_MESSAGE_WARNING,
765 				 GTK_BUTTONS_YES_NO,
766 				 NULL,
767 				 text);
768 
769 	return (ret != GTK_RESPONSE_YES);
770 }
771 
772 static int
check_case(char * text,int _case)773 check_case(char * text, int _case) {
774 
775 	char * str;
776 	char * p;
777 	int has = 0;
778 	int ret = 0;
779 
780 	for (p = text; *p; p = g_utf8_next_char(p)) {
781 
782 		gunichar ch = g_utf8_get_char(p);
783 
784 		if (g_unichar_islower(ch) || g_unichar_isupper(ch)) {
785 			has = 1;
786 			break;
787 		}
788 	}
789 
790 	if (!has) {
791 		return 1;
792 	}
793 
794 	switch (_case) {
795 	case CASE_UP:
796 		str = g_utf8_strup(text, -1);
797 		ret = strcmp(str, text);
798 		g_free(str);
799 		break;
800 	case CASE_DOWN:
801 		str = g_utf8_strdown(text, -1);
802 		ret = strcmp(str, text);
803 		g_free(str);
804 		break;
805 	}
806 
807 	return ret;
808 }
809 
810 
811 int
cddb_submit_check(cddb_lookup_t * data)812 cddb_submit_check(cddb_lookup_t * data) {
813 
814 	GtkTreeIter iter_trlist;
815 	char * artist;
816 	char * title;
817 	char * genre;
818 	char * ext;
819 	int category;
820 	int year;
821 	int i;
822 
823 
824 	artist = (char *)gtk_entry_get_text(GTK_ENTRY(data->artist_entry));
825 	if (is_all_wspace(artist)) {
826 		gtk_widget_grab_focus(data->artist_entry);
827 		return 1;
828 	}
829 
830 	if (!check_case(artist, CASE_DOWN)) {
831 		if (create_cddb_write_warn_dialog(_("Artist appears to be in all lowercase.\n"
832 						    "Do you want to proceed?"))) {
833 			gtk_widget_grab_focus(data->artist_entry);
834 			return 1;
835 		}
836 	}
837 
838 	if (!check_case(artist, CASE_UP)) {
839 		if (create_cddb_write_warn_dialog(_("Artist appears to be in all uppercase.\n"
840 						    "Do you want to proceed?"))) {
841 			gtk_widget_grab_focus(data->artist_entry);
842 			return 1;
843 		}
844 	}
845 
846 	title = (char *)gtk_entry_get_text(GTK_ENTRY(data->title_entry));
847 	if (is_all_wspace(title)) {
848 		gtk_widget_grab_focus(data->title_entry);
849 		return 1;
850 	}
851 
852 	if (!check_case(title, CASE_DOWN)) {
853 		if (create_cddb_write_warn_dialog(_("Title appears to be in all lowercase.\n"
854 						    "Do you want to proceed?"))) {
855 			gtk_widget_grab_focus(data->title_entry);
856 			return 1;
857 		}
858 	}
859 
860 	if (!check_case(title, CASE_UP)) {
861 		if (create_cddb_write_warn_dialog(_("Title appears to be in all uppercase.\n"
862 						    "Do you want to proceed?"))) {
863 			gtk_widget_grab_focus(data->title_entry);
864 			return 1;
865 		}
866 	}
867 
868 	year = gtk_spin_button_get_value(GTK_SPIN_BUTTON(data->year_spinner));
869 
870 	if (year == YEAR_MIN) {
871 		if (create_cddb_write_warn_dialog(_("It is very likely that the year is wrong.\n"
872 						    "Do you want to proceed?"))) {
873 			gtk_widget_grab_focus(data->year_spinner);
874 			return 1;
875 		}
876 	}
877 
878 	if (data->type == CDDB_TYPE_SUBMIT_NEW) {
879 		category = gtk_combo_box_get_active(GTK_COMBO_BOX(data->category_combo));
880 		if (category == 0) {
881 			gtk_widget_grab_focus(data->category_combo);
882 			return 1;
883 		}
884 	}
885 
886 	genre = (char *)gtk_entry_get_text(GTK_ENTRY(data->genre_entry));
887 	if (genre[0] != '\0' && is_all_wspace(genre)) {
888 		gtk_widget_grab_focus(data->genre_entry);
889 		return 1;
890 	}
891 
892 	ext = (char *)gtk_entry_get_text(GTK_ENTRY(data->ext_entry));
893 	if (ext[0] != '\0' && is_all_wspace(ext)) {
894 		gtk_widget_grab_focus(data->ext_entry);
895 		return 1;
896 	}
897 
898 	for (i = 0; gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(data->track_store),
899 						  &iter_trlist, NULL, i); i++) {
900 		char * name;
901 		gtk_tree_model_get(GTK_TREE_MODEL(data->track_store),
902 				   &iter_trlist, 0, &name, -1);
903 
904 		if (is_all_wspace(name)) {
905 			gtk_tree_selection_select_iter(gtk_tree_view_get_selection(GTK_TREE_VIEW(data->track_list)),
906 						       &iter_trlist);
907 			return 1;
908 		}
909 
910 		g_free(name);
911 	}
912 
913 	return 0;
914 }
915 
916 void
cddb_submit(cddb_lookup_t * data,int n)917 cddb_submit(cddb_lookup_t * data, int n) {
918 
919 	GtkTreeIter iter_trlist;
920 	cddb_conn_t * conn = NULL;
921 	cddb_disc_t * disc = NULL;
922 	int i;
923 
924 
925 	if (cddb_connection_setup(&conn) == 1) {
926 		return;
927 	}
928 
929 	if (!cddb_set_email_address(conn, options.cddb_email)) {
930 		create_cddb_write_error_dialog(_("The email address provided for submission is invalid."));
931 		cddb_destroy(conn);
932 		return;
933 	}
934 
935 	cddb_http_enable(conn);
936 	cddb_set_server_port(conn, 80);
937 
938 	if (n < 0) {
939 		cddb_track_t * track = NULL;
940 
941 		if ((disc = cddb_disc_new()) == NULL) {
942 			fprintf(stderr, "cddb_submit: cddb_disc_new error\n");
943 			cddb_destroy(conn);
944 			return;
945 		}
946 
947 		for (i = 0; i < data->ntracks; i++) {
948 			track = cddb_track_new();
949 			cddb_track_set_frame_offset(track, data->frames[i]);
950 			cddb_disc_add_track(disc, track);
951 		}
952 
953 		cddb_disc_set_length(disc, data->record_length);
954 		cddb_disc_set_category(disc, gtk_combo_box_get_active(GTK_COMBO_BOX(data->category_combo)) - 1);
955 
956 		if (cddb_disc_calc_discid(disc) == 0) {
957 			fprintf(stderr, "cddb_submit: cddb_disc_calc_discid error\n");
958 			cddb_disc_destroy(disc);
959 			cddb_destroy(conn);
960 			return;
961 		}
962 	} else {
963 		disc = data->records[n];
964 #ifdef LIBCDDB_REVISION
965 		cddb_disc_set_revision(disc, cddb_disc_get_revision(disc) + 1);
966 #endif /* LIBCDDB_REVISION */
967 	}
968 
969 	for (i = 0; gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(data->track_store),
970 						  &iter_trlist, NULL, i); i++) {
971 		char * name;
972 		gtk_tree_model_get(GTK_TREE_MODEL(data->track_store),
973 				   &iter_trlist, 0, &name, -1);
974 
975 		cddb_track_set_title(cddb_disc_get_track(disc, i), name);
976 		g_free(name);
977 	}
978 
979 	cddb_disc_set_artist(disc, gtk_entry_get_text(GTK_ENTRY(data->artist_entry)));
980 	cddb_disc_set_title(disc, gtk_entry_get_text(GTK_ENTRY(data->title_entry)));
981 	cddb_disc_set_year(disc, gtk_spin_button_get_value(GTK_SPIN_BUTTON(data->year_spinner)));
982 	cddb_disc_set_genre(disc, gtk_entry_get_text(GTK_ENTRY(data->genre_entry)));
983 	cddb_disc_set_ext_data(disc, gtk_entry_get_text(GTK_ENTRY(data->ext_entry)));
984 
985 	if (!cddb_write(conn, disc)) {
986 		create_cddb_write_error_dialog(_("An error occurred while submitting the record to the CDDB server."));
987 	}
988 
989 	cddb_destroy(conn);
990 
991 	if (n < 0) {
992 		cddb_disc_destroy(disc);
993 	}
994 }
995 
996 
997 void
cddb_dialog_load_disc(cddb_lookup_t * data,cddb_disc_t * disc)998 cddb_dialog_load_disc(cddb_lookup_t * data, cddb_disc_t * disc) {
999 
1000 	GtkTreeIter iter;
1001 	int i;
1002 
1003 	gtk_entry_set_text(GTK_ENTRY(data->artist_entry), notnull(cddb_disc_get_artist(disc)));
1004 	gtk_entry_set_text(GTK_ENTRY(data->title_entry), notnull(cddb_disc_get_title(disc)));
1005 	gtk_entry_set_text(GTK_ENTRY(data->category_entry), notnull(cddb_disc_get_category_str(disc)));
1006 	gtk_entry_set_text(GTK_ENTRY(data->genre_entry), notnull(cddb_disc_get_genre(disc)));
1007 	gtk_entry_set_text(GTK_ENTRY(data->ext_entry), notnull(cddb_disc_get_ext_data(disc)));
1008 
1009 	gtk_spin_button_set_value(GTK_SPIN_BUTTON(data->year_spinner), cddb_disc_get_year(disc));
1010 
1011 	gtk_list_store_clear(GTK_LIST_STORE(data->track_store));
1012 
1013 	for (i = 0; i < data->ntracks; i++) {
1014 		gtk_list_store_append(data->track_store, &iter);
1015 		gtk_list_store_set(data->track_store, &iter, 0,
1016 				   notnull(cddb_track_get_title(cddb_disc_get_track(disc, i))), -1);
1017 	}
1018 }
1019 
1020 
1021 void
store_load_tracklist(cddb_lookup_t * data)1022 store_load_tracklist(cddb_lookup_t * data) {
1023 
1024 	GtkTreeIter iter;
1025 	GtkTreeIter iter_trlist;
1026 	int i = 0;
1027 
1028 	while (gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(music_store),
1029 					     &iter, &data->iter_record, i++)) {
1030 		char * name;
1031 
1032 		gtk_tree_model_get(GTK_TREE_MODEL(music_store), &iter, MS_COL_NAME, &name, -1);
1033 		gtk_list_store_append(data->track_store, &iter_trlist);
1034 		gtk_list_store_set(data->track_store, &iter_trlist, 0, name, -1);
1035 		g_free(name);
1036 	}
1037 }
1038 
1039 void
cddb_dialog_load_store_file(cddb_lookup_t * data)1040 cddb_dialog_load_store_file(cddb_lookup_t * data) {
1041 
1042 	GtkTreeIter iter_artist;
1043 	record_data_t * record_data;
1044 	char * str;
1045 
1046 	store_load_tracklist(data);
1047 
1048 	gtk_tree_model_iter_parent(GTK_TREE_MODEL(music_store), &iter_artist, &data->iter_record);
1049 	gtk_tree_model_get(GTK_TREE_MODEL(music_store), &iter_artist, MS_COL_NAME, &str, -1);
1050 	gtk_entry_set_text(GTK_ENTRY(data->artist_entry), str);
1051 	g_free(str);
1052 
1053 	gtk_tree_model_get(GTK_TREE_MODEL(music_store), &data->iter_record, MS_COL_NAME, &str, -1);
1054 	gtk_entry_set_text(GTK_ENTRY(data->title_entry), str);
1055 	g_free(str);
1056 
1057 	gtk_tree_model_get(GTK_TREE_MODEL(music_store), &data->iter_record, MS_COL_DATA, &record_data, -1);
1058 	gtk_spin_button_set_value(GTK_SPIN_BUTTON(data->year_spinner), record_data->year);
1059 }
1060 
1061 
1062 #ifdef HAVE_CDDA
1063 void
cddb_dialog_load_store_cdda(cddb_lookup_t * data)1064 cddb_dialog_load_store_cdda(cddb_lookup_t * data) {
1065 
1066 	store_load_tracklist(data);
1067 
1068 	cdda_drive_t * drive;
1069 
1070 	gtk_tree_model_get(GTK_TREE_MODEL(music_store), &data->iter_record,
1071 			   MS_COL_DATA, &drive, -1);
1072 
1073 	gtk_entry_set_text(GTK_ENTRY(data->artist_entry), drive->disc.artist_name);
1074 	gtk_entry_set_text(GTK_ENTRY(data->title_entry), drive->disc.record_name);
1075 	gtk_entry_set_text(GTK_ENTRY(data->genre_entry), drive->disc.genre);
1076 	gtk_spin_button_set_value(GTK_SPIN_BUTTON(data->year_spinner), drive->disc.year);
1077 }
1078 #endif /* HAVE_CDDA */
1079 
1080 
1081 void
export_tracklist(cddb_lookup_t * data)1082 export_tracklist(cddb_lookup_t * data) {
1083 
1084 	int i;
1085 	GtkTreeIter iter;
1086 	GtkTreeIter iter_trlist;
1087 
1088 	for (i = 0; gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(music_store),
1089 						  &iter, &data->iter_record, i); i++) {
1090 
1091 		if (gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(data->track_store),
1092 						  &iter_trlist, NULL, i)) {
1093 			char * name;
1094 			gtk_tree_model_get(GTK_TREE_MODEL(data->track_store), &iter_trlist, 0, &name, -1);
1095 			gtk_tree_store_set(music_store, &iter, MS_COL_NAME, name, -1);
1096 			g_free(name);
1097 		}
1098 	}
1099 }
1100 
1101 void
store_file_export(cddb_lookup_t * data)1102 store_file_export(cddb_lookup_t * data) {
1103 
1104 	export_tracklist(data);
1105 	music_store_mark_changed(&data->iter_record);
1106 }
1107 
1108 
1109 #ifdef HAVE_CDDA
1110 void
store_cdda_export(cddb_lookup_t * data)1111 store_cdda_export(cddb_lookup_t * data) {
1112 
1113 	char name[MAXLEN];
1114 	cdda_drive_t * drive;
1115 
1116 	export_tracklist(data);
1117 
1118 	gtk_tree_model_get(GTK_TREE_MODEL(music_store), &data->iter_record, MS_COL_DATA, &drive, -1);
1119 
1120 	strncpy(drive->disc.artist_name, gtk_entry_get_text(GTK_ENTRY(data->artist_entry)), MAXLEN-1);
1121 	strncpy(drive->disc.record_name, gtk_entry_get_text(GTK_ENTRY(data->title_entry)), MAXLEN-1);
1122 	strncpy(drive->disc.genre, gtk_entry_get_text(GTK_ENTRY(data->genre_entry)), MAXLEN-1);
1123 	drive->disc.year = gtk_spin_button_get_value(GTK_SPIN_BUTTON(data->year_spinner));
1124 
1125 	snprintf(name, MAXLEN-1, "%s: %s",
1126 		 drive->disc.artist_name,
1127 		 drive->disc.record_name);
1128 
1129 	gtk_tree_store_set(music_store, &data->iter_record, MS_COL_NAME, name, -1);
1130 }
1131 #endif /* HAVE_CDDA */
1132 
1133 
1134 void
cddb_dialog(cddb_lookup_t * data)1135 cddb_dialog(cddb_lookup_t * data) {
1136 
1137 	GtkWidget * dialog;
1138 	GtkWidget * table;
1139 
1140 	GtkWidget * hbox;
1141 	GtkWidget * label;
1142 	GtkWidget * button;
1143 
1144 	GtkWidget * viewport;
1145 	GtkWidget * scrollwin;
1146 	GtkCellRenderer * renderer;
1147 	GtkTreeViewColumn * column;
1148 
1149 	int i;
1150 	char text[MAXLEN];
1151 
1152 
1153         dialog = gtk_dialog_new_with_buttons(NULL,
1154 					     GTK_WINDOW(browser_window),
1155 					     GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_NO_SEPARATOR,
1156 					     GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
1157 					     GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
1158 					     NULL);
1159 
1160 	gtk_window_set_position(GTK_WINDOW(dialog), GTK_WIN_POS_CENTER);
1161         gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT);
1162 
1163 	switch (data->type) {
1164 	case CDDB_TYPE_QUERY:
1165 		gtk_window_set_title(GTK_WINDOW(dialog), _("CDDB query"));
1166 		break;
1167 	case CDDB_TYPE_SUBMIT:
1168 		gtk_window_set_title(GTK_WINDOW(dialog), _("Correct existing record"));
1169 		break;
1170 	case CDDB_TYPE_SUBMIT_NEW:
1171 		gtk_window_set_title(GTK_WINDOW(dialog), _("Submit new record"));
1172 		break;
1173 	}
1174 
1175 	table = gtk_table_new(8, 3, FALSE);
1176 	gtk_box_pack_start(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))),
1177 			   table, FALSE, FALSE, 2);
1178 
1179 	if (data->type != CDDB_TYPE_SUBMIT_NEW) {
1180 		hbox = gtk_hbox_new(FALSE, 0);
1181 		gtk_table_attach(GTK_TABLE(table), hbox, 0, 1, 0, 1, GTK_FILL, GTK_FILL, 5, 3);
1182 		label = gtk_label_new(_("Matches:"));
1183 		gtk_box_pack_end(GTK_BOX(hbox), label, FALSE, FALSE, 2);
1184 
1185 		data->combo = gtk_combo_box_new_text();
1186 		for (i = 0; i < data->nrecords; i++) {
1187 			snprintf(text, MAXLEN, "%d. %s: %s [%x] ",
1188 				 i + 1,
1189 				 notnull(cddb_disc_get_artist(data->records[i])),
1190 				 notnull(cddb_disc_get_title(data->records[i])),
1191 				 cddb_disc_get_discid(data->records[i]));
1192 			gtk_combo_box_append_text(GTK_COMBO_BOX(data->combo), text);
1193 		}
1194 
1195 		gtk_combo_box_set_active(GTK_COMBO_BOX(data->combo), 0);
1196 		g_signal_connect(data->combo, "changed", G_CALLBACK(changed_combo), data);
1197 
1198 		gtk_table_attach(GTK_TABLE(table), data->combo, 1, 3, 0, 1, GTK_FILL, GTK_FILL, 5, 3);
1199 	}
1200 
1201 	hbox = gtk_hbox_new(FALSE, 0);
1202 	gtk_table_attach(GTK_TABLE(table), hbox, 0, 1, 1, 2, GTK_FILL, GTK_FILL, 5, 3);
1203 	label = gtk_label_new(_("Artist:"));
1204         gtk_box_pack_end(GTK_BOX(hbox), label, FALSE, FALSE, 2);
1205 
1206 	data->artist_entry = gtk_entry_new();
1207 	gtk_table_attach(GTK_TABLE(table), data->artist_entry, 1, 2, 1, 2,
1208 			 GTK_FILL | GTK_EXPAND, GTK_FILL | GTK_EXPAND, 5, 3);
1209 
1210 	hbox = gtk_hbox_new(FALSE, 0);
1211 	gtk_table_attach(GTK_TABLE(table), hbox, 0, 1, 2, 3, GTK_FILL, GTK_FILL, 5, 3);
1212 	label = gtk_label_new(_("Title:"));
1213         gtk_box_pack_end(GTK_BOX(hbox), label, FALSE, FALSE, 2);
1214 
1215 	data->title_entry = gtk_entry_new();
1216 	gtk_table_attach(GTK_TABLE(table), data->title_entry, 1, 2, 2, 3,
1217 			 GTK_FILL | GTK_EXPAND, GTK_FILL | GTK_EXPAND, 5, 3);
1218 
1219 	hbox = gtk_hbox_new(FALSE, 0);
1220 	gtk_table_attach(GTK_TABLE(table), hbox, 0, 1, 3, 4, GTK_FILL, GTK_FILL, 5, 3);
1221 	label = gtk_label_new(_("Year:"));
1222         gtk_box_pack_end(GTK_BOX(hbox), label, FALSE, FALSE, 2);
1223 
1224 	data->year_spinner = gtk_spin_button_new_with_range(YEAR_MIN, YEAR_MAX, 1);
1225 	gtk_table_attach(GTK_TABLE(table), data->year_spinner, 1, 2, 3, 4,
1226 			 GTK_FILL | GTK_EXPAND, GTK_FILL | GTK_EXPAND, 5, 3);
1227 
1228 	hbox = gtk_hbox_new(FALSE, 0);
1229 	gtk_table_attach(GTK_TABLE(table), hbox, 0, 1, 4, 5, GTK_FILL, GTK_FILL, 5, 3);
1230 	label = gtk_label_new(_("Category:"));
1231         gtk_box_pack_end(GTK_BOX(hbox), label, FALSE, FALSE, 2);
1232 
1233 	if (data->type != CDDB_TYPE_SUBMIT_NEW) {
1234 		data->category_entry = gtk_entry_new();
1235 		gtk_editable_set_editable(GTK_EDITABLE(data->category_entry), FALSE);
1236 		gtk_table_attach(GTK_TABLE(table), data->category_entry, 1, 2, 4, 5,
1237 				 GTK_FILL | GTK_EXPAND, GTK_FILL | GTK_EXPAND, 5, 3);
1238 	} else {
1239 		data->category_combo = gtk_combo_box_new_text();
1240 		gtk_combo_box_append_text(GTK_COMBO_BOX(data->category_combo), _("(choose a category)"));
1241 		gtk_combo_box_append_text(GTK_COMBO_BOX(data->category_combo), "data");
1242 		gtk_combo_box_append_text(GTK_COMBO_BOX(data->category_combo), "folk");
1243 		gtk_combo_box_append_text(GTK_COMBO_BOX(data->category_combo), "jazz");
1244 		gtk_combo_box_append_text(GTK_COMBO_BOX(data->category_combo), "misc");
1245 		gtk_combo_box_append_text(GTK_COMBO_BOX(data->category_combo), "rock");
1246 		gtk_combo_box_append_text(GTK_COMBO_BOX(data->category_combo), "country");
1247 		gtk_combo_box_append_text(GTK_COMBO_BOX(data->category_combo), "blues");
1248 		gtk_combo_box_append_text(GTK_COMBO_BOX(data->category_combo), "newage");
1249 		gtk_combo_box_append_text(GTK_COMBO_BOX(data->category_combo), "reagge");
1250 		gtk_combo_box_append_text(GTK_COMBO_BOX(data->category_combo), "classical");
1251 		gtk_combo_box_append_text(GTK_COMBO_BOX(data->category_combo), "soundtrack");
1252 		gtk_combo_box_set_active(GTK_COMBO_BOX(data->category_combo), 0);
1253 		gtk_table_attach(GTK_TABLE(table), data->category_combo, 1, 2, 4, 5,
1254 				 GTK_FILL | GTK_EXPAND, GTK_FILL | GTK_EXPAND, 5, 3);
1255 	}
1256 
1257 	hbox = gtk_hbox_new(FALSE, 0);
1258 	gtk_table_attach(GTK_TABLE(table), hbox, 0, 1, 5, 6, GTK_FILL, GTK_FILL, 5, 3);
1259 	label = gtk_label_new(_("Genre:"));
1260         gtk_box_pack_end(GTK_BOX(hbox), label, FALSE, FALSE, 2);
1261 
1262 	data->genre_entry = gtk_entry_new();
1263 	gtk_table_attach(GTK_TABLE(table), data->genre_entry, 1, 2, 5, 6,
1264 			 GTK_FILL | GTK_EXPAND, GTK_FILL | GTK_EXPAND, 5, 3);
1265 
1266 	hbox = gtk_hbox_new(FALSE, 0);
1267 	gtk_table_attach(GTK_TABLE(table), hbox, 0, 1, 6, 7, GTK_FILL, GTK_FILL, 5, 3);
1268 	label = gtk_label_new(_("Extended data:"));
1269         gtk_box_pack_end(GTK_BOX(hbox), label, FALSE, FALSE, 2);
1270 
1271 	data->ext_entry = gtk_entry_new();
1272 	gtk_table_attach(GTK_TABLE(table), data->ext_entry, 1, 2, 6, 7,
1273 			 GTK_FILL | GTK_EXPAND, GTK_FILL | GTK_EXPAND, 5, 3);
1274 
1275 	if (data->type == CDDB_TYPE_QUERY && iter_get_store_type(&data->iter_record) == STORE_TYPE_FILE) {
1276 
1277 		g_signal_connect(G_OBJECT(data->title_entry), "focus-in-event",
1278 				 G_CALLBACK(title_entry_focused), data);
1279 		g_signal_connect(G_OBJECT(data->year_spinner), "focus-in-event",
1280 				 G_CALLBACK(year_spinner_focused), data);
1281 
1282 		button = gtk_button_new_with_label(_("Import as Artist"));
1283 		g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(import_as_artist), data);
1284 		gtk_table_attach(GTK_TABLE(table), button, 2, 3, 1, 2, GTK_FILL, GTK_FILL, 5, 3);
1285 
1286 		data->title_import_button = gtk_button_new_with_label(_("Import as Title"));
1287 		g_signal_connect(G_OBJECT(data->title_import_button), "clicked",
1288 				 G_CALLBACK(import_as_title), data);
1289 		gtk_table_attach(GTK_TABLE(table), data->title_import_button,
1290 				 2, 3, 2, 3, GTK_FILL, GTK_FILL, 5, 3);
1291 
1292 		data->year_import_button = gtk_button_new_with_label(_("Import as Year"));
1293 		g_signal_connect(G_OBJECT(data->year_import_button), "clicked",
1294 				 G_CALLBACK(import_as_year), data);
1295 		gtk_table_attach(GTK_TABLE(table), data->year_import_button,
1296 				 2, 3, 3, 4, GTK_FILL, GTK_FILL, 5, 3);
1297 
1298 		button = gtk_button_new_with_label(_("Add to Comments"));
1299 		g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(add_category_to_comments), data);
1300 		gtk_table_attach(GTK_TABLE(table), button, 2, 3, 4, 5, GTK_FILL, GTK_FILL, 5, 3);
1301 
1302 		button = gtk_button_new_with_label(_("Add to Comments"));
1303 		g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(add_genre_to_comments), data);
1304 		gtk_table_attach(GTK_TABLE(table), button, 2, 3, 5, 6, GTK_FILL, GTK_FILL, 5, 3);
1305 
1306 		button = gtk_button_new_with_label(_("Add to Comments"));
1307 		g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(add_ext_to_comments), data);
1308 		gtk_table_attach(GTK_TABLE(table), button, 2, 3, 6, 7, GTK_FILL, GTK_FILL, 5, 3);
1309 	}
1310 
1311 	data->track_store = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_BOOLEAN);
1312         data->track_list = gtk_tree_view_new_with_model(GTK_TREE_MODEL(data->track_store));
1313 
1314 	renderer = gtk_cell_renderer_text_new();
1315 	g_object_set(renderer, "editable", TRUE, NULL);
1316 	g_signal_connect(renderer, "edited", (GCallback)cell_edited_callback, data);
1317 	column = gtk_tree_view_column_new_with_attributes(_("Tracks"),
1318 							  renderer,
1319 							  "text", 0,
1320 							  NULL);
1321         gtk_tree_view_append_column(GTK_TREE_VIEW(data->track_list), column);
1322         gtk_tree_view_set_reorderable(GTK_TREE_VIEW(data->track_list), FALSE);
1323 
1324         viewport = gtk_viewport_new(NULL, NULL);
1325 	scrollwin = gtk_scrolled_window_new(NULL, NULL);
1326 	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrollwin),
1327 				       GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1328 	gtk_widget_set_size_request(scrollwin, -1, 200);
1329         gtk_table_attach(GTK_TABLE(table), viewport, 0, 3, 7, 8,
1330 			 GTK_FILL | GTK_EXPAND, GTK_FILL | GTK_EXPAND, 5, 3);
1331         gtk_container_add(GTK_CONTAINER(viewport), scrollwin);
1332         gtk_container_add(GTK_CONTAINER(scrollwin), data->track_list);
1333 
1334 	gtk_widget_show_all(dialog);
1335 
1336 	if (data->type != CDDB_TYPE_SUBMIT_NEW) {
1337 		cddb_dialog_load_disc(data, data->records[0]);
1338 	} else {
1339 		if (iter_get_store_type(&data->iter_record) == STORE_TYPE_FILE) {
1340 			cddb_dialog_load_store_file(data);
1341 		} else {
1342 #ifdef HAVE_CDDA
1343 			cddb_dialog_load_store_cdda(data);
1344 #endif /* HAVE_CDDA */
1345 		}
1346 	}
1347 
1348  display:
1349 
1350 	if (aqualung_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
1351 
1352 		if (data->type == CDDB_TYPE_SUBMIT || data->type == CDDB_TYPE_SUBMIT_NEW) {
1353 			if (cddb_submit_check(data)) {
1354 				goto display;
1355 			}
1356 		}
1357 
1358 		if (data->type == CDDB_TYPE_SUBMIT) {
1359 			cddb_submit(data, gtk_combo_box_get_active(GTK_COMBO_BOX(data->combo)));
1360 		}
1361 
1362 		if (data->type == CDDB_TYPE_SUBMIT_NEW) {
1363 			cddb_submit(data, -1);
1364 		}
1365 
1366 		if (data->type == CDDB_TYPE_QUERY) {
1367 			if (iter_get_store_type(&data->iter_record) == STORE_TYPE_FILE) {
1368 				store_file_export(data);
1369 			} else {
1370 #ifdef HAVE_CDDA
1371 				store_cdda_export(data);
1372 #endif /* HAVE_CDDA */
1373 			}
1374 		}
1375 	}
1376 
1377 	gtk_widget_destroy(dialog);
1378 }
1379 
1380 
1381 void *
cddb_lookup_thread(void * arg)1382 cddb_lookup_thread(void * arg) {
1383 
1384 	AQUALUNG_THREAD_DETACH();
1385 
1386 	cddb_lookup((cddb_lookup_t *)arg);
1387 
1388 	return NULL;
1389 }
1390 
1391 void
cddb_start_lookup_thread(GtkTreeIter * iter_record,int type,int progress,int ntracks,int * frames,int length,gboolean (* timeout_cb)(gpointer))1392 cddb_start_lookup_thread(GtkTreeIter * iter_record,
1393 			 int type,
1394 			 int progress,
1395 			 int ntracks, int * frames, int length,
1396 			 gboolean (*timeout_cb)(gpointer)) {
1397 
1398 	cddb_lookup_t * data;
1399 
1400 	if ((data = cddb_lookup_new()) == NULL) {
1401 		return;
1402 	}
1403 
1404 	data->iter_record = *iter_record;
1405 	data->type = type;
1406 	data->ntracks = ntracks;
1407 	data->frames = frames;
1408 	data->record_length = length;
1409 
1410 	AQUALUNG_THREAD_CREATE(data->thread_id, NULL, cddb_lookup_thread, data);
1411 	if (progress) {
1412 		create_query_progress_window(data);
1413 	}
1414 	aqualung_timeout_add(100, timeout_cb, data);
1415 }
1416 
1417 void
cddb_start_query(GtkTreeIter * iter_record,int ntracks,int * frames,int length)1418 cddb_start_query(GtkTreeIter * iter_record, int ntracks, int * frames, int length) {
1419 
1420 	cddb_start_lookup_thread(iter_record,
1421 				 CDDB_TYPE_QUERY,
1422 				 1,
1423 				 ntracks, frames, length,
1424 				 query_timeout_cb);
1425 }
1426 
1427 void
cddb_start_submit(GtkTreeIter * iter_record,int ntracks,int * frames,int length)1428 cddb_start_submit(GtkTreeIter * iter_record, int ntracks, int * frames, int length) {
1429 
1430 	if (options.cddb_email[0] == '\0') {
1431 		create_cddb_write_error_dialog(_("You have to provide an email address for CDDB submission."));
1432 		return;
1433 	}
1434 
1435 	cddb_start_lookup_thread(iter_record,
1436 				 CDDB_TYPE_SUBMIT,
1437 				 1,
1438 				 ntracks, frames, length,
1439 				 query_timeout_cb);
1440 }
1441 
1442 #ifdef HAVE_CDDA
1443 void
cddb_auto_query_cdda(GtkTreeIter * drive_iter,int ntracks,int * frames,int length)1444 cddb_auto_query_cdda(GtkTreeIter * drive_iter, int ntracks, int * frames, int length) {
1445 
1446 	cddb_start_lookup_thread(drive_iter,
1447 				 CDDB_TYPE_QUERY,
1448 				 0,
1449 				 ntracks, frames, length,
1450 				 cdda_auto_query_timeout_cb);
1451 }
1452 #endif /* HAVE_CDDA */
1453 
1454 void
cddb_query_batch(int ntracks,int * frames,int length,char * artist,char * record,int * year,char ** tracks)1455 cddb_query_batch(int ntracks, int * frames, int length,
1456 		 char * artist, char * record, int * year, char ** tracks) {
1457 
1458 	cddb_lookup_t * data;
1459 
1460 	if ((data = cddb_lookup_new()) == NULL) {
1461 		return;
1462 	}
1463 
1464 	data->type = CDDB_TYPE_QUERY;
1465 	data->ntracks = ntracks;
1466 	data->frames = frames;
1467 	data->record_length = length;
1468 
1469 	cddb_lookup(data);
1470 	cddb_lookup_merge(data, artist, record, NULL/*genre*/, year, tracks);
1471 	cddb_lookup_free(data);
1472 }
1473 
1474 
1475 // vim: shiftwidth=8:tabstop=8:softtabstop=8 :
1476 
1477