1 /* EasyTAG - Tag editor for audio files
2 * Copyright (C) 2014,2015 David King <amigadave@amigadave.com>
3 * Copyright (C) 2000-2003 Jerome Couderc <easytag@gmail.com>
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 */
19
20 #include "config.h"
21
22 #include "cddb_dialog.h"
23
24 #include <glib/gi18n.h>
25 #include <glib/gstdio.h>
26 #include <stdio.h>
27 #include <unistd.h>
28 #include <string.h>
29 #include <stdlib.h>
30 #include <sys/types.h>
31 #include "win32/win32dep.h"
32 #ifndef G_OS_WIN32
33 #include <sys/socket.h>
34 /* Patch OpenBSD from Jim Geovedi. */
35 #include <netinet/in.h>
36 #include <arpa/inet.h>
37 /* End patch */
38 #include <netdb.h>
39 #endif /* !G_OS_WIN32 */
40 #include <errno.h>
41
42 #include "application_window.h"
43 #include "easytag.h"
44 #include "enums.h"
45 #include "et_core.h"
46 #include "browser.h"
47 #include "scan_dialog.h"
48 #include "log.h"
49 #include "misc.h"
50 #include "setting.h"
51 #include "id3_tag.h"
52 #include "setting.h"
53 #include "charset.h"
54
55 typedef struct
56 {
57 GtkWidget *album_list_view;
58 GtkWidget *track_list_view;
59
60 GList *album_list;
61
62 GtkListStore *album_list_model;
63 GtkListStore *track_list_model;
64
65 GtkWidget *search_entry;
66
67 GtkWidget *apply_button;
68 GtkWidget *automatic_search_button;
69 GtkWidget *manual_search_button;
70 GtkWidget *stop_search_button;
71
72 GtkWidget *status_bar;
73 guint status_bar_context;
74
75 gboolean stop_searching;
76
77 GtkWidget *artist_check;
78 GtkWidget *album_check;
79 GtkWidget *track_check;
80 GtkWidget *other_check;
81
82 GtkWidget *blues_check;
83 GtkWidget *classical_check;
84 GtkWidget *country_check;
85 GtkWidget *folk_check;
86 GtkWidget *jazz_check;
87 GtkWidget *misc_check;
88 GtkWidget *newage_check;
89 GtkWidget *reggae_check;
90 GtkWidget *rock_check;
91 GtkWidget *soundtrack_check;
92
93 GtkWidget *filename_check;
94 GtkWidget *title_check;
95 GtkWidget *fill_artist_check;
96 GtkWidget *fill_album_check;
97 GtkWidget *year_check;
98 GtkWidget *fill_track_check;
99 GtkWidget *track_total_check;
100 GtkWidget *genre_check;
101
102 GtkWidget *scanner_check;
103 GtkWidget *dlm_check;
104 } EtCDDBDialogPrivate;
105
106 G_DEFINE_TYPE_WITH_PRIVATE (EtCDDBDialog, et_cddb_dialog, GTK_TYPE_DIALOG)
107
108 /*
109 * Structure used for each item of the album list. Aslo attached to each row of
110 * the album list
111 */
112 typedef struct
113 {
114 gchar *server_name; /* Remote access: server name. Local access : NULL */
115 guint server_port; /* Remote access: server port. Local access: 0 */
116 gchar *server_cgi_path; /* Remote access: server CGI path.
117 * Local access: discid file path */
118
119 GdkPixbuf *bitmap; /* Pixmap logo for the server. */
120
121 gchar *artist_album; /* CDDB artist+album (allocated) */
122 gchar *category; /* CDDB genre (allocated) */
123 gchar *id; /* example : 8d0de30c (allocated) */
124 GList *track_list; /* List of CddbTrackAlbum items. */
125 gboolean other_version; /* TRUE if this album is another version of the
126 * previous one. */
127
128 /* Filled when loading the track list. */
129 gchar *artist; /* (allocated) */
130 gchar *album; /* (allocated) */
131 gchar *genre; /* (allocated) */
132 gchar *year; /* (allocated) */
133 guint duration;
134 } CddbAlbum;
135
136
137 /*
138 * Structure used for each item of the track_list of the CddbAlbum structure.
139 */
140 typedef struct
141 {
142 guint track_number;
143 gchar *track_name; /* (allocated) */
144 guint duration;
145 CddbAlbum *cddbalbum; /* Pointer to the parent CddbAlbum structure (to
146 * quickly access album properties). */
147 } CddbTrackAlbum;
148
149
150 typedef struct
151 {
152 gulong offset;
153 } CddbTrackFrameOffset;
154
155 enum
156 {
157 CDDB_ALBUM_LIST_PIXBUF,
158 CDDB_ALBUM_LIST_ALBUM,
159 CDDB_ALBUM_LIST_CATEGORY,
160 CDDB_ALBUM_LIST_DATA,
161 CDDB_ALBUM_LIST_FONT_STYLE,
162 CDDB_ALBUM_LIST_FONT_WEIGHT,
163 CDDB_ALBUM_LIST_FOREGROUND_COLOR,
164 CDDB_ALBUM_LIST_COUNT
165 };
166
167 enum
168 {
169 CDDB_TRACK_LIST_NUMBER,
170 CDDB_TRACK_LIST_NAME,
171 CDDB_TRACK_LIST_TIME,
172 CDDB_TRACK_LIST_DATA,
173 CDDB_TRACK_LIST_ETFILE,
174 CDDB_TRACK_LIST_COUNT
175 };
176
177 enum
178 {
179 SORT_LIST_NUMBER,
180 SORT_LIST_NAME
181 };
182
183
184 #define CDDB_GENRE_MAX ( sizeof(cddb_genre_vs_id3_genre)/sizeof(cddb_genre_vs_id3_genre[0]) - 1 )
185 static const gchar *cddb_genre_vs_id3_genre [][2] =
186 {
187 /* Cddb Genre - ID3 Genre */
188 {"Blues", "Blues"},
189 {"Classical", "Classical"},
190 {"Country", "Country"},
191 {"Data", "Other"},
192 {"Folk", "Folk"},
193 {"Jazz", "Jazz"},
194 {"NewAge", "New Age"},
195 {"Reggae", "Reggae"},
196 {"Rock", "Rock"},
197 {"Soundtrack", "Soundtrack"},
198 {"Misc", "Other"}
199 };
200
201
202 // File for result of the Cddb/Freedb request (on remote access)
203 static const gchar CDDB_RESULT_FILE[] = "cddb_result_file.tmp";
204
205 static const guint MAX_STRING_LEN = 1024;
206
207
208 /**************
209 * Prototypes *
210 **************/
211 static gboolean Cddb_Free_Track_Album_List (GList *track_list);
212
213 static gint Cddb_Read_Line (FILE **file, gchar **cddb_out);
214 static gint Cddb_Read_Http_Header (FILE **file, gchar **cddb_out);
215 static gint Cddb_Read_Cddb_Header (FILE **file, gchar **cddb_out);
216
217 static GdkPixbuf *Cddb_Get_Pixbuf_From_Server_Name (const gchar *server_name);
218
219 static const gchar *Cddb_Get_Id3_Genre_From_Cddb_Genre (const gchar *cddb_genre);
220
221 static gint Cddb_Track_List_Sort_Func (GtkTreeModel *model, GtkTreeIter *a,
222 GtkTreeIter *b, gpointer data);
223
224 static gchar *Cddb_Format_Proxy_Authentification (void);
225
226 static void Cddb_Get_Album_Tracks_List_CB (EtCDDBDialog *self, GtkTreeSelection *selection);
227
228
229 /*
230 * The window to connect to the cd data base.
231 */
232
233 static void
update_apply_button_sensitivity(EtCDDBDialog * self)234 update_apply_button_sensitivity (EtCDDBDialog *self)
235 {
236 EtCDDBDialogPrivate *priv;
237
238 priv = et_cddb_dialog_get_instance_private (self);
239
240 /* If any field is set, enable the apply button. */
241 if (priv->apply_button
242 && gtk_tree_model_iter_n_children (GTK_TREE_MODEL (priv->track_list_model),
243 NULL) > 0
244 && (g_settings_get_flags (MainSettings, "cddb-set-fields") != 0))
245 {
246 gtk_widget_set_sensitive (GTK_WIDGET (priv->apply_button), TRUE);
247 }
248 else
249 {
250 gtk_widget_set_sensitive (GTK_WIDGET (priv->apply_button), FALSE);
251 }
252 }
253
254 static void
update_search_button_sensitivity(EtCDDBDialog * self)255 update_search_button_sensitivity (EtCDDBDialog *self)
256 {
257 EtCDDBDialogPrivate *priv;
258
259 priv = et_cddb_dialog_get_instance_private (self);
260
261 if (priv->manual_search_button
262 && *(gtk_entry_get_text (GTK_ENTRY (priv->search_entry)))
263 && (g_settings_get_flags (MainSettings, "cddb-search-fields") != 0)
264 && (g_settings_get_flags (MainSettings, "cddb-search-categories") != 0))
265 {
266 gtk_widget_set_sensitive (GTK_WIDGET (priv->manual_search_button), TRUE);
267 }
268 else
269 {
270 gtk_widget_set_sensitive (GTK_WIDGET (priv->manual_search_button), FALSE);
271 }
272 }
273
274 /*
275 * Show collected infos of the album in the status bar
276 */
277 static void
show_album_info(EtCDDBDialog * self,GtkTreeSelection * selection)278 show_album_info (EtCDDBDialog *self, GtkTreeSelection *selection)
279 {
280 EtCDDBDialogPrivate *priv;
281 CddbAlbum *cddbalbum = NULL;
282 gchar *msg, *duration_str;
283 GtkTreeIter row;
284 priv = et_cddb_dialog_get_instance_private (self);
285
286 if (gtk_tree_selection_get_selected(selection, NULL, &row))
287 {
288 gtk_tree_model_get(GTK_TREE_MODEL(priv->album_list_model), &row, CDDB_ALBUM_LIST_DATA, &cddbalbum, -1);
289 }
290 if (!cddbalbum)
291 return;
292
293 duration_str = Convert_Duration((gulong)cddbalbum->duration);
294 msg = g_strdup_printf(_("Album: ‘%s’, "
295 "artist: ‘%s’, "
296 "length: ‘%s’, "
297 "year: ‘%s’, "
298 "genre: ‘%s’, "
299 "disc ID: ‘%s’"),
300 cddbalbum->album ? cddbalbum->album : "",
301 cddbalbum->artist ? cddbalbum->artist : "",
302 duration_str,
303 cddbalbum->year ? cddbalbum->year : "",
304 cddbalbum->genre ? cddbalbum->genre : "",
305 cddbalbum->id ? cddbalbum->id : "");
306 gtk_statusbar_push(GTK_STATUSBAR(priv->status_bar), priv->status_bar_context, msg);
307 g_free(msg);
308 g_free(duration_str);
309 }
310
311 /*
312 * Select the corresponding file into the main file list
313 */
314 static void
Cddb_Track_List_Row_Selected(EtCDDBDialog * self,GtkTreeSelection * selection)315 Cddb_Track_List_Row_Selected (EtCDDBDialog *self, GtkTreeSelection *selection)
316 {
317 EtCDDBDialogPrivate *priv;
318 GList *selectedRows;
319 GList *l;
320
321 priv = et_cddb_dialog_get_instance_private (self);
322
323 // Exit if we don't have to select files in the main list
324 if (!g_settings_get_boolean (MainSettings, "cddb-follow-file"))
325 return;
326
327 selectedRows = gtk_tree_selection_get_selected_rows(selection, NULL);
328
329 // We might be called with no rows selected
330 if (!selectedRows)
331 {
332 return;
333 }
334
335 /* Unselect files in the main list before re-selecting them... */
336 et_application_window_browser_unselect_all (ET_APPLICATION_WINDOW (MainWindow));
337
338 for (l = selectedRows; l != NULL; l = g_list_next (l))
339 {
340 GtkTreeIter currentFile;
341 gchar *text_path;
342
343 if (gtk_tree_model_get_iter (GTK_TREE_MODEL (priv->track_list_model),
344 ¤tFile, (GtkTreePath*)l->data))
345 {
346 if (g_settings_get_boolean (MainSettings, "cddb-dlm-enabled"))
347 {
348 ET_File *etfile;
349
350 gtk_tree_model_get (GTK_TREE_MODEL (priv->track_list_model),
351 ¤tFile, CDDB_TRACK_LIST_NAME,
352 &text_path, -1);
353 etfile = et_application_window_browser_select_file_by_dlm (ET_APPLICATION_WINDOW (MainWindow),
354 text_path,
355 TRUE);
356 gtk_list_store_set (priv->track_list_model, ¤tFile,
357 CDDB_TRACK_LIST_ETFILE, etfile, -1);
358 }
359 else
360 {
361 text_path = gtk_tree_model_get_string_from_iter (GTK_TREE_MODEL (priv->track_list_model),
362 ¤tFile);
363 et_application_window_browser_select_file_by_iter_string (ET_APPLICATION_WINDOW (MainWindow),
364 text_path,
365 TRUE);
366 }
367
368 g_free (text_path);
369 }
370 }
371
372 g_list_free_full (selectedRows, (GDestroyNotify)gtk_tree_path_free);
373 }
374
375 /*
376 * Invert the selection of every row in the track list
377 */
378 static void
Cddb_Track_List_Invert_Selection(EtCDDBDialog * self)379 Cddb_Track_List_Invert_Selection (EtCDDBDialog *self)
380 {
381 EtCDDBDialogPrivate *priv;
382 GtkTreeSelection *selection;
383 GtkTreeIter iter;
384 gboolean valid;
385
386 priv = et_cddb_dialog_get_instance_private (self);
387
388 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(priv->track_list_view));
389
390 if (selection)
391 {
392 /* Must block the select signal to avoid selecting all files (one by one) in the main list */
393 g_signal_handlers_block_by_func (selection,
394 G_CALLBACK (Cddb_Track_List_Row_Selected),
395 NULL);
396
397 valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(priv->track_list_model), &iter);
398 while (valid)
399 {
400 if (gtk_tree_selection_iter_is_selected(selection, &iter))
401 {
402 gtk_tree_selection_unselect_iter(selection, &iter);
403 } else
404 {
405 gtk_tree_selection_select_iter(selection, &iter);
406 }
407 valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(priv->track_list_model), &iter);
408 }
409 g_signal_handlers_unblock_by_func (selection,
410 G_CALLBACK (Cddb_Track_List_Row_Selected),
411 NULL);
412 g_signal_emit_by_name(G_OBJECT(gtk_tree_view_get_selection(GTK_TREE_VIEW(priv->track_list_view))), "changed");
413 }
414 }
415
416 /*
417 * Set the row apperance depending if we have cached info or not
418 * Bold/Red = Info are already loaded, but not displayed
419 * Italic/Light Red = Duplicate CDDB entry
420 */
421 static void
Cddb_Album_List_Set_Row_Appearance(EtCDDBDialog * self,GtkTreeIter * row)422 Cddb_Album_List_Set_Row_Appearance (EtCDDBDialog *self, GtkTreeIter *row)
423 {
424 EtCDDBDialogPrivate *priv;
425 CddbAlbum *cddbalbum = NULL;
426
427 priv = et_cddb_dialog_get_instance_private (self);
428
429 gtk_tree_model_get(GTK_TREE_MODEL(priv->album_list_model), row,
430 CDDB_ALBUM_LIST_DATA, &cddbalbum, -1);
431
432 if (cddbalbum->track_list != NULL)
433 {
434 if (g_settings_get_boolean (MainSettings, "file-changed-bold"))
435 {
436 gtk_list_store_set(priv->album_list_model, row,
437 CDDB_ALBUM_LIST_FONT_STYLE, PANGO_STYLE_NORMAL,
438 CDDB_ALBUM_LIST_FONT_WEIGHT, PANGO_WEIGHT_BOLD,
439 CDDB_ALBUM_LIST_FOREGROUND_COLOR, NULL,-1);
440 } else
441 {
442 if (cddbalbum->other_version == TRUE)
443 {
444 const GdkRGBA LIGHT_RED = { 1.0, 0.5, 0.5, 1.0 };
445 gtk_list_store_set(priv->album_list_model, row,
446 CDDB_ALBUM_LIST_FONT_STYLE, PANGO_STYLE_NORMAL,
447 CDDB_ALBUM_LIST_FONT_WEIGHT, PANGO_WEIGHT_NORMAL,
448 CDDB_ALBUM_LIST_FOREGROUND_COLOR, &LIGHT_RED, -1);
449 } else
450 {
451 gtk_list_store_set(priv->album_list_model, row,
452 CDDB_ALBUM_LIST_FONT_STYLE, PANGO_STYLE_NORMAL,
453 CDDB_ALBUM_LIST_FONT_WEIGHT, PANGO_WEIGHT_NORMAL,
454 CDDB_ALBUM_LIST_FOREGROUND_COLOR, &RED, -1);
455 }
456 }
457 }
458 else
459 {
460 if (cddbalbum->other_version == TRUE)
461 {
462 if (g_settings_get_boolean (MainSettings, "file-changed-bold"))
463 {
464 gtk_list_store_set(priv->album_list_model, row,
465 CDDB_ALBUM_LIST_FONT_STYLE, PANGO_STYLE_ITALIC,
466 CDDB_ALBUM_LIST_FONT_WEIGHT, PANGO_WEIGHT_NORMAL,
467 CDDB_ALBUM_LIST_FOREGROUND_COLOR, NULL,-1);
468 } else
469 {
470 const GdkRGBA GREY = { 0.664, 0.664, 0.664, 1.0 };
471 gtk_list_store_set(priv->album_list_model, row,
472 CDDB_ALBUM_LIST_FONT_STYLE, PANGO_STYLE_NORMAL,
473 CDDB_ALBUM_LIST_FONT_WEIGHT, PANGO_WEIGHT_NORMAL,
474 CDDB_ALBUM_LIST_FOREGROUND_COLOR, &GREY, -1);
475 }
476 } else
477 {
478 gtk_list_store_set(priv->album_list_model, row,
479 CDDB_ALBUM_LIST_FONT_STYLE, PANGO_STYLE_NORMAL,
480 CDDB_ALBUM_LIST_FONT_WEIGHT, PANGO_WEIGHT_NORMAL,
481 CDDB_ALBUM_LIST_FOREGROUND_COLOR, NULL, -1);
482 }
483 }
484 }
485
486 /*
487 * Clear the album model, blocking the tree view selection changed handlers
488 * during the process, to prevent the handlers being called on removed rows.
489 */
490 static void
cddb_album_model_clear(EtCDDBDialog * self)491 cddb_album_model_clear (EtCDDBDialog *self)
492 {
493 EtCDDBDialogPrivate *priv;
494 GtkTreeSelection *selection;
495
496 priv = et_cddb_dialog_get_instance_private (self);
497
498 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->album_list_view));
499
500 g_signal_handlers_block_by_func (selection,
501 G_CALLBACK (Cddb_Get_Album_Tracks_List_CB),
502 self);
503 g_signal_handlers_block_by_func (selection, G_CALLBACK (show_album_info),
504 self);
505
506 gtk_list_store_clear (priv->album_list_model);
507
508 g_signal_handlers_unblock_by_func (selection, G_CALLBACK (show_album_info),
509 self);
510 g_signal_handlers_unblock_by_func (selection,
511 G_CALLBACK (Cddb_Get_Album_Tracks_List_CB),
512 self);
513 }
514
515 /*
516 * Clear the album model, blocking the tree view selection changed handlers
517 * during the process, to prevent the handlers being called on removed rows.
518 */
519 static void
cddb_track_model_clear(EtCDDBDialog * self)520 cddb_track_model_clear (EtCDDBDialog *self)
521 {
522 EtCDDBDialogPrivate *priv;
523 GtkTreeSelection *selection;
524
525 priv = et_cddb_dialog_get_instance_private (self);
526
527 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->track_list_view));
528
529 g_signal_handlers_block_by_func (selection,
530 G_CALLBACK (Cddb_Track_List_Row_Selected),
531 self);
532
533 gtk_list_store_clear (priv->track_list_model);
534
535 g_signal_handlers_unblock_by_func (selection,
536 G_CALLBACK (Cddb_Track_List_Row_Selected),
537 self);
538 }
539
540 /*
541 * Load the CddbTrackList into the corresponding List
542 */
543 static void
Cddb_Load_Track_Album_List(EtCDDBDialog * self,GList * track_list)544 Cddb_Load_Track_Album_List (EtCDDBDialog *self, GList *track_list)
545 {
546 EtCDDBDialogPrivate *priv;
547
548 priv = et_cddb_dialog_get_instance_private (self);
549
550 if (track_list && priv->track_list_view)
551 {
552 GList *l;
553
554 /* Must block the select signal of the target to avoid looping. */
555 cddb_track_model_clear (self);
556
557 for (l = g_list_first (track_list); l != NULL; l = g_list_next (l))
558 {
559 gchar *row_text;
560 CddbTrackAlbum *cddbtrackalbum = l->data;
561
562 row_text = Convert_Duration ((gulong)cddbtrackalbum->duration);
563
564 /* Load the row in the list. */
565 gtk_list_store_insert_with_values (priv->track_list_model, NULL,
566 G_MAXINT,
567 CDDB_TRACK_LIST_NUMBER,
568 cddbtrackalbum->track_number,
569 CDDB_TRACK_LIST_NAME,
570 cddbtrackalbum->track_name,
571 CDDB_TRACK_LIST_TIME,
572 row_text,
573 CDDB_TRACK_LIST_DATA,
574 cddbtrackalbum,
575 -1);
576
577 g_free (row_text);
578 }
579
580 update_apply_button_sensitivity (self);
581 }
582 }
583
584 /*
585 * Cddb_Open_Connection:
586 * @host: a hostname
587 * @port: a port number
588 *
589 * Open a connection to @hostname, performing a DNS lookup as necessary.
590 *
591 * Returns: the socket fd, or 0 upon failure
592 */
593 /* TODO: Propagate the GError to the caller. */
594 static gint
Cddb_Open_Connection(EtCDDBDialog * self,const gchar * host,gint port)595 Cddb_Open_Connection (EtCDDBDialog *self, const gchar *host, gint port)
596 {
597 EtCDDBDialogPrivate *priv;
598 GSocketConnectable *address;
599 GSocketAddressEnumerator *enumerator;
600 GCancellable *cancellable;
601 GSocketAddress *sockaddress;
602 GError *error = NULL;
603 GError *sock_error = NULL;
604 gint socket_id = 0;
605 gchar *msg;
606
607 g_return_val_if_fail (self != NULL, 0);
608 g_return_val_if_fail (host != NULL && port > 0, 0);
609
610 priv = et_cddb_dialog_get_instance_private (self);
611
612 msg = g_strdup_printf(_("Resolving host '%s'…"),host);
613 gtk_statusbar_push (GTK_STATUSBAR (priv->status_bar),
614 priv->status_bar_context, msg);
615 g_free(msg);
616
617 while (gtk_events_pending ())
618 {
619 gtk_main_iteration ();
620 }
621
622 address = g_network_address_new (host, port);
623 enumerator = g_socket_connectable_enumerate (address);
624 g_object_unref (address);
625
626 cancellable = g_cancellable_new ();
627
628 while (socket_id == 0
629 && (sockaddress = g_socket_address_enumerator_next (enumerator,
630 cancellable,
631 &error)))
632 {
633 struct sockaddr sockaddr_in;
634 gint optval = 1;
635
636 if (!g_socket_address_to_native (sockaddress, &sockaddr_in,
637 sizeof (sockaddr_in),
638 sock_error ? NULL : &sock_error))
639 {
640 g_object_unref (sockaddress);
641 continue;
642 }
643
644 g_object_unref (sockaddress);
645
646 while (gtk_events_pending ())
647 {
648 gtk_main_iteration ();
649 }
650
651 /* Create socket. */
652 if ((socket_id = socket (AF_INET, SOCK_STREAM, 0)) < 0)
653 {
654 msg = g_strdup_printf (_("Cannot create a new socket ‘%s’"),
655 g_strerror (errno));
656 gtk_statusbar_push (GTK_STATUSBAR (priv->status_bar),
657 priv->status_bar_context, msg);
658 Log_Print (LOG_ERROR, "%s", msg);
659 g_free (msg);
660 goto err;
661 }
662
663 /* FIXME : must catch SIGPIPE? */
664 if (setsockopt (socket_id, SOL_SOCKET, SO_KEEPALIVE, (void *)&optval,
665 sizeof (optval)) < 0)
666 {
667 Log_Print (LOG_WARNING,
668 _("Cannot set options on the newly-created socket"));
669 }
670
671 /* Open connection to the server. */
672 msg = g_strdup_printf (_("Connecting to host ‘%s’, port ‘%d’…"), host,
673 port);
674 gtk_statusbar_push (GTK_STATUSBAR (priv->status_bar),
675 priv->status_bar_context, msg);
676 g_free (msg);
677
678 while (gtk_events_pending ())
679 {
680 gtk_main_iteration ();
681 }
682
683 if (connect (socket_id, &sockaddr_in, sizeof (struct sockaddr)) < 0)
684 {
685 msg = g_strdup_printf (_("Cannot connect to host ‘%s’: %s"), host,
686 g_strerror (errno));
687 gtk_statusbar_push (GTK_STATUSBAR (priv->status_bar),
688 priv->status_bar_context, msg);
689 Log_Print (LOG_ERROR, "%s", msg);
690 g_free (msg);
691
692 goto err;
693 }
694 }
695
696 if (socket_id != 0)
697 {
698 /* First address failed, but a later address succeeded. */
699 if (sock_error)
700 {
701 g_debug ("Failure while looking up address: %s",
702 sock_error->message);
703 g_error_free (sock_error);
704 }
705 }
706
707 if (error)
708 {
709 msg = g_strdup_printf (_("Cannot resolve host ‘%s’: %s"), host,
710 error->message);
711 gtk_statusbar_push (GTK_STATUSBAR (priv->status_bar),
712 priv->status_bar_context, msg);
713 Log_Print (LOG_ERROR, "%s", msg);
714 g_free (msg);
715 g_error_free (error);
716 goto err;
717 }
718
719 g_object_unref (enumerator);
720 g_object_unref (cancellable);
721
722 msg = g_strdup_printf (_("Connected to host ‘%s’"), host);
723 gtk_statusbar_push (GTK_STATUSBAR (priv->status_bar), priv->status_bar_context,
724 msg);
725 g_free (msg);
726
727 while (gtk_events_pending ())
728 {
729 gtk_main_iteration ();
730 }
731
732 return socket_id;
733
734 err:
735 g_object_unref (enumerator);
736 g_object_unref (cancellable);
737
738 return 0;
739 }
740
741 /*
742 * Close the connection correcponding to the socket_id
743 */
744 static void
Cddb_Close_Connection(EtCDDBDialog * self,gint socket_id)745 Cddb_Close_Connection (EtCDDBDialog *self, gint socket_id)
746 {
747 EtCDDBDialogPrivate *priv;
748
749 #ifndef G_OS_WIN32
750 shutdown(socket_id,SHUT_RDWR);
751 #endif /* !G_OS_WIN32 */
752 close(socket_id);
753
754 g_return_if_fail (ET_CDDB_DIALOG (self));
755
756 priv = et_cddb_dialog_get_instance_private (self);
757
758 priv->stop_searching = FALSE;
759 }
760
761 /*
762 * Read the result of the request and write it into a file.
763 * And return the number of bytes read.
764 * - bytes_read=0 => no more data.
765 * - bytes_read_total : use to add bytes of severals pages... must be initialized before
766 *
767 * Server answser is formated like this :
768 *
769 * HTTP/1.1 200 OK\r\n }
770 * Server: Apache/1.3.19 (Unix) PHP/4.0.4pl1\r\n } "Header"
771 * Connection: close\r\n }
772 * \r\n
773 * <html>\n }
774 * [...] } "Body"
775 */
776 static gint
Cddb_Write_Result_To_File(EtCDDBDialog * self,gint socket_id,gulong * bytes_read_total)777 Cddb_Write_Result_To_File (EtCDDBDialog *self,
778 gint socket_id,
779 gulong *bytes_read_total)
780 {
781 EtCDDBDialogPrivate *priv;
782 gchar *file_path = NULL;
783 FILE *file;
784
785 priv = et_cddb_dialog_get_instance_private (self);
786
787 /* Cache directory was already created by Log_Print(). */
788 file_path = g_build_filename (g_get_user_cache_dir (), PACKAGE_TARNAME,
789 CDDB_RESULT_FILE, NULL);
790
791 if ((file = g_fopen (file_path, "w+")) != NULL)
792 {
793 gchar cddb_out[MAX_STRING_LEN+1];
794 gint bytes_read = 0;
795
796 while (!priv->stop_searching
797 // Read data
798 && (bytes_read = recv(socket_id,(void *)&cddb_out,MAX_STRING_LEN,0)) > 0 )
799 {
800 gchar *size_str;
801 gchar *msg;
802
803
804 // Write to file
805 cddb_out[bytes_read] = 0;
806 if (fwrite (&cddb_out, bytes_read, 1, file) != 1)
807 {
808 Log_Print (LOG_ERROR,
809 _("Error while writing CDDB results to file ‘%s’"),
810 file_path);
811 break;
812 }
813
814 *bytes_read_total += bytes_read;
815
816 //g_print("\nLine : %lu : %s\n",bytes_read,cddb_out);
817
818 // Display message
819 size_str = g_format_size (*bytes_read_total);
820 msg = g_strdup_printf(_("Receiving data (%s)…"),size_str);
821 gtk_statusbar_push (GTK_STATUSBAR (priv->status_bar),
822 priv->status_bar_context, msg);
823 g_free(msg);
824 g_free(size_str);
825 while (gtk_events_pending())
826 gtk_main_iteration();
827 }
828
829 fclose(file);
830
831 if (bytes_read < 0)
832 {
833 Log_Print (LOG_ERROR, _("Error when reading CDDB response ‘%s’"),
834 g_strerror(errno));
835 return -1; // Error!
836 }
837
838 } else
839 {
840 Log_Print (LOG_ERROR, _("Cannot create file ‘%s’: %s"), file_path,
841 g_strerror(errno));
842 }
843 g_free(file_path);
844
845 return 0;
846 }
847
848 static void
cddb_track_frame_offset_free(CddbTrackFrameOffset * offset)849 cddb_track_frame_offset_free (CddbTrackFrameOffset *offset)
850 {
851 g_slice_free (CddbTrackFrameOffset, offset);
852 }
853
854 /*
855 * Look up a specific album in freedb, and save to a CddbAlbum structure
856 */
857 static gboolean
Cddb_Get_Album_Tracks_List(EtCDDBDialog * self,GtkTreeSelection * selection)858 Cddb_Get_Album_Tracks_List (EtCDDBDialog *self, GtkTreeSelection* selection)
859 {
860 EtCDDBDialogPrivate *priv;
861 gint socket_id = 0;
862 CddbAlbum *cddbalbum = NULL;
863 GList *TrackOffsetList = NULL;
864 gchar *cddb_in, *cddb_out = NULL;
865 gchar *msg, *copy, *valid;
866 const gchar CDDB_END_STR[] = ".";
867 gchar *proxy_auth;
868 gchar *cddb_server_name;
869 guint cddb_server_port;
870 gchar *cddb_server_cgi_path;
871 gboolean proxy_enabled;
872 gchar *proxy_hostname;
873 guint proxy_port;
874 gint bytes_written;
875 gulong bytes_read_total = 0;
876 FILE *file = NULL;
877 gboolean read_track_offset = FALSE;
878 GtkTreeIter row;
879
880 priv = et_cddb_dialog_get_instance_private (self);
881
882 cddb_track_model_clear (self);
883 update_apply_button_sensitivity (self);
884
885 if (gtk_tree_selection_get_selected(selection, NULL, &row))
886 {
887 gtk_tree_model_get(GTK_TREE_MODEL(priv->album_list_model), &row, CDDB_ALBUM_LIST_DATA, &cddbalbum, -1);
888 }
889 if (!cddbalbum)
890 return FALSE;
891
892 // We have already the track list
893 if (cddbalbum->track_list != NULL)
894 {
895 Cddb_Load_Track_Album_List (self, cddbalbum->track_list);
896 return TRUE;
897 }
898
899 // Parameters of the server used
900 cddb_server_name = cddbalbum->server_name;
901 cddb_server_port = cddbalbum->server_port;
902 cddb_server_cgi_path = cddbalbum->server_cgi_path;
903
904 {
905 /* Connection to the server. */
906 proxy_enabled = g_settings_get_boolean (MainSettings,
907 "cddb-proxy-enabled");
908 proxy_hostname = g_settings_get_string (MainSettings,
909 "cddb-proxy-hostname");
910 proxy_port = g_settings_get_uint (MainSettings, "cddb-proxy-port");
911 if ((socket_id = Cddb_Open_Connection (self,
912 proxy_enabled
913 ? proxy_hostname
914 : cddb_server_name,
915 proxy_enabled
916 ? proxy_port
917 : cddb_server_port)) <= 0)
918 {
919 g_free (proxy_hostname);
920 return FALSE;
921 }
922
923 if ( strstr(cddb_server_name,"gnudb") != NULL )
924 {
925 // For gnudb
926 // New version of gnudb doesn't use a cddb request, but a http request
927 /* HTTP/1.0 to avoid the server returning chunked results.
928 * https://bugzilla.gnome.org/show_bug.cgi?id=743812 */
929 cddb_in = g_strdup_printf("GET %s%s/gnudb/"
930 "%s/%s"
931 " HTTP/1.0\r\n"
932 "Host: %s:%u\r\n"
933 "User-Agent: %s %s\r\n"
934 "%s"
935 "Connection: close\r\n"
936 "\r\n",
937 proxy_enabled ? "http://" : "",
938 proxy_enabled ? cddb_server_name : "",
939 cddbalbum->category,cddbalbum->id,
940 cddb_server_name,cddb_server_port,
941 PACKAGE_NAME, PACKAGE_VERSION,
942 (proxy_auth=Cddb_Format_Proxy_Authentification())
943 );
944 }else
945 {
946 // CDDB Request (ex: GET /~cddb/cddb.cgi?cmd=cddb+read+jazz+0200a401&hello=noname+localhost+EasyTAG+0.31&proto=1 HTTP/1.1\r\nHost: freedb.freedb.org:80\r\nConnection: close)
947 // Without proxy : "GET /~cddb/cddb.cgi?…" but doesn't work with a proxy.
948 // With proxy : "GET http://freedb.freedb.org/~cddb/cddb.cgi?…"
949 /* HTTP/1.0 to avoid the server returning chunked results.
950 * https://bugzilla.gnome.org/show_bug.cgi?id=743812 */
951 cddb_in = g_strdup_printf("GET %s%s%s?cmd=cddb+read+"
952 "%s+%s"
953 "&hello=noname+localhost+%s+%s"
954 "&proto=6 HTTP/1.0\r\n"
955 "Host: %s:%u\r\n"
956 "%s"
957 "Connection: close\r\n\r\n",
958 proxy_enabled ? "http://" : "",
959 proxy_enabled ? cddb_server_name : "",
960 cddb_server_cgi_path,
961 cddbalbum->category,cddbalbum->id,
962 PACKAGE_NAME, PACKAGE_VERSION,
963 cddb_server_name,cddb_server_port,
964 (proxy_auth=Cddb_Format_Proxy_Authentification())
965 );
966 }
967
968
969 g_free(proxy_auth);
970 //g_print("Request Cddb_Get_Album_Tracks_List : '%s'\n", cddb_in);
971
972 // Send the request
973 gtk_statusbar_push(GTK_STATUSBAR(priv->status_bar),priv->status_bar_context,_("Sending request…"));
974 while (gtk_events_pending()) gtk_main_iteration();
975 if ( (bytes_written=send(socket_id,cddb_in,strlen(cddb_in)+1,0)) < 0)
976 {
977 Log_Print (LOG_ERROR, _("Cannot send the request ‘%s’"),
978 g_strerror (errno));
979 Cddb_Close_Connection (self, socket_id);
980 g_free(cddb_in);
981 g_free (proxy_hostname);
982 return FALSE;
983 }
984 g_free(cddb_in);
985 g_free (proxy_hostname);
986
987
988 // Read the answer
989 gtk_statusbar_push(GTK_STATUSBAR(priv->status_bar),priv->status_bar_context,_("Receiving data…"));
990 while (gtk_events_pending())
991 gtk_main_iteration();
992
993 /* Write result in a file. */
994 if (Cddb_Write_Result_To_File (self, socket_id, &bytes_read_total) < 0)
995 {
996 msg = g_strdup(_("The server returned a bad response"));
997 gtk_statusbar_push(GTK_STATUSBAR(priv->status_bar),priv->status_bar_context,msg);
998 Log_Print(LOG_ERROR,"%s",msg);
999 g_free(msg);
1000 gtk_widget_set_sensitive(GTK_WIDGET(priv->stop_search_button),FALSE);
1001 return FALSE;
1002 }
1003
1004
1005 // Parse server answer : Check HTTP Header (freedb or gnudb) and CDDB Header (freedb only)
1006 file = NULL;
1007 if ( strstr(cddb_server_name,"gnudb") != NULL )
1008 {
1009 // For gnudb (don't check CDDB header)
1010 if ( Cddb_Read_Http_Header(&file,&cddb_out) <= 0 )
1011 {
1012 msg = g_strdup_printf (_("The server returned a bad response ‘%s’"),
1013 cddb_out);
1014 gtk_statusbar_push(GTK_STATUSBAR(priv->status_bar),priv->status_bar_context,msg);
1015 Log_Print(LOG_ERROR,"%s",msg);
1016 g_free(msg);
1017 g_free(cddb_out);
1018 if (file)
1019 fclose(file);
1020 return FALSE;
1021 }
1022 }else
1023 {
1024 /* For freedb. */
1025 if (Cddb_Read_Http_Header (&file, &cddb_out) <= 0)
1026 {
1027 msg = g_strdup_printf (_("The server returned a bad response ‘%s’"),
1028 cddb_out);
1029 gtk_statusbar_push (GTK_STATUSBAR (priv->status_bar),
1030 priv->status_bar_context, msg);
1031 Log_Print (LOG_ERROR, "%s", msg);
1032
1033 g_free (msg);
1034 g_free (cddb_out);
1035
1036 if (file)
1037 {
1038 fclose (file);
1039 }
1040
1041 return FALSE;
1042 }
1043
1044 g_free (cddb_out);
1045
1046 if (Cddb_Read_Cddb_Header (&file, &cddb_out) <= 0)
1047 {
1048 msg = g_strdup_printf (_("The server returned a bad response ‘%s’"),
1049 cddb_out);
1050 gtk_statusbar_push (GTK_STATUSBAR (priv->status_bar),
1051 priv->status_bar_context, msg);
1052 Log_Print (LOG_ERROR, "%s", msg);
1053
1054 g_free (msg);
1055 g_free (cddb_out);
1056
1057 if (file)
1058 {
1059 fclose (file);
1060 }
1061
1062 return FALSE;
1063 }
1064 }
1065 g_free(cddb_out);
1066
1067 }
1068
1069 while (!priv->stop_searching && Cddb_Read_Line (&file, &cddb_out) > 0)
1070 {
1071 if (!cddb_out) // Empty line?
1072 continue;
1073 //g_print("%s\n",cddb_out);
1074
1075 // To avoid the cddb lookups to hang (Patch from Paul Giordano)
1076 /* It appears that on some systems that cddb lookups continue to attempt
1077 * to get data from the socket even though the other system has completed
1078 * sending. The fix adds one check to the loops to see if the actual
1079 * end of data is in the last block read. In this case, the last line
1080 * will be a single '.'
1081 */
1082 if (strlen (cddb_out) <= 3 && strstr (cddb_out, CDDB_END_STR) != NULL)
1083 {
1084 g_free (cddb_out);
1085 break;
1086 }
1087
1088 if ( strstr(cddb_out,"Track frame offsets")!=NULL ) // We read the Track frame offset
1089 {
1090 read_track_offset = TRUE; // The next reads are for the tracks offset
1091 g_free (cddb_out);
1092 continue;
1093
1094 }else if (read_track_offset) // We are reading a track offset? (generates TrackOffsetList)
1095 {
1096 if ( strtoul(cddb_out+1,NULL,10)>0 )
1097 {
1098 CddbTrackFrameOffset *cddbtrackframeoffset = g_slice_new (CddbTrackFrameOffset);
1099 cddbtrackframeoffset->offset = strtoul(cddb_out+1,NULL,10);
1100 TrackOffsetList = g_list_append(TrackOffsetList,cddbtrackframeoffset);
1101 }else
1102 {
1103 read_track_offset = FALSE; // No more track offset
1104 }
1105
1106 g_free (cddb_out);
1107 continue;
1108
1109 }else if ( strstr(cddb_out,"Disc length: ")!=NULL ) // Length of album (in second)
1110 {
1111 cddbalbum->duration = atoi(strchr(cddb_out,':')+1);
1112 if (TrackOffsetList) // As it must be the last item, do nothing if no previous data
1113 {
1114 CddbTrackFrameOffset *cddbtrackframeoffset = g_slice_new (CddbTrackFrameOffset);
1115 cddbtrackframeoffset->offset = cddbalbum->duration * 75; // It's the last offset
1116 TrackOffsetList = g_list_append(TrackOffsetList,cddbtrackframeoffset);
1117 }
1118
1119 g_free (cddb_out);
1120 continue;
1121
1122 }else if ( strncmp(cddb_out,"DTITLE=",7)==0 ) // "Artist / Album" names
1123 {
1124 // Note : disc title too long take severals lines. For example :
1125 // DTITLE=Marilyn Manson / The Nobodies (2005 Against All Gods Mix - Korea Tour L
1126 // DTITLE=imited Edition)
1127 if (!cddbalbum->album)
1128 {
1129 // It is the first time we find DTITLE...
1130
1131 gchar *alb_ptr = strstr(cddb_out," / ");
1132 // Album
1133 if (alb_ptr && alb_ptr[3])
1134 {
1135 cddbalbum->album = Try_To_Validate_Utf8_String(alb_ptr+3);
1136 *alb_ptr = 0;
1137 }
1138
1139 // Artist
1140 cddbalbum->artist = Try_To_Validate_Utf8_String(cddb_out+7); // '7' to skip 'DTITLE='
1141 }else
1142 {
1143 // It is at least the second time we find DTITLE
1144 // So we suppose that only the album was truncated
1145
1146 // Album
1147 valid = Try_To_Validate_Utf8_String(cddb_out+7); // '7' to skip 'DTITLE='
1148 copy = cddbalbum->album; // To free...
1149 cddbalbum->album = g_strconcat(cddbalbum->album,valid,NULL);
1150 g_free(copy);
1151 }
1152
1153 g_free (cddb_out);
1154 continue;
1155
1156 }else if ( strncmp(cddb_out,"DYEAR=",6)==0 ) // Year
1157 {
1158 valid = Try_To_Validate_Utf8_String(cddb_out+6); // '6' to skip 'DYEAR='
1159 if (!et_str_empty (valid))
1160 cddbalbum->year = valid;
1161
1162 g_free (cddb_out);
1163 continue;
1164
1165 }else if ( strncmp(cddb_out,"DGENRE=",7)==0 ) // Genre
1166 {
1167 valid = Try_To_Validate_Utf8_String(cddb_out+7); // '7' to skip 'DGENRE='
1168 if (!et_str_empty (valid))
1169 cddbalbum->genre = valid;
1170
1171 g_free (cddb_out);
1172 continue;
1173
1174 }else if ( strncmp(cddb_out,"TTITLE",6)==0 ) // Track title (for exemple : TTITLE10=xxxx)
1175 {
1176 CddbTrackAlbum *cddbtrackalbum_last = NULL;
1177
1178 CddbTrackAlbum *cddbtrackalbum = g_slice_new0 (CddbTrackAlbum);
1179 cddbtrackalbum->cddbalbum = cddbalbum; // To find the CddbAlbum father quickly
1180
1181 // Here is a fix when TTITLExx doesn't contain an "=", we skip the line
1182 if ((copy = strchr (cddb_out, '=')) != NULL)
1183 {
1184 cddbtrackalbum->track_name = Try_To_Validate_Utf8_String(copy+1);
1185 }else
1186 {
1187 g_free (cddb_out);
1188 continue;
1189 }
1190
1191 *strchr (cddb_out, '=') = 0;
1192 cddbtrackalbum->track_number = atoi(cddb_out+6)+1;
1193
1194 // Note : titles too long take severals lines. For example :
1195 // TTITLE15=Bob Marley vs. Funkstar De Luxe Remix - Sun Is Shining (Radio De Lu
1196 // TTITLE15=xe Edit)
1197 // So to check it, we compare current track number with the previous one...
1198 if (cddbalbum->track_list)
1199 cddbtrackalbum_last = g_list_last(cddbalbum->track_list)->data;
1200 if (cddbtrackalbum_last && cddbtrackalbum_last->track_number == cddbtrackalbum->track_number)
1201 {
1202 gchar *track_name = g_strconcat(cddbtrackalbum_last->track_name,cddbtrackalbum->track_name,NULL);
1203 g_free(cddbtrackalbum_last->track_name);
1204
1205 cddbtrackalbum_last->track_name = Try_To_Validate_Utf8_String(track_name);
1206
1207 /* Frees useless allocated data previously. */
1208 g_free(cddbtrackalbum->track_name);
1209 g_slice_free (CddbTrackAlbum, cddbtrackalbum);
1210 }else
1211 {
1212 if (TrackOffsetList && TrackOffsetList->next)
1213 {
1214 cddbtrackalbum->duration = (((CddbTrackFrameOffset *)TrackOffsetList->next->data)->offset
1215 - ((CddbTrackFrameOffset *)TrackOffsetList->data)->offset)
1216 / 75; /* Calculate time in seconds. */
1217 TrackOffsetList = g_list_next (TrackOffsetList);
1218 }
1219 cddbalbum->track_list = g_list_append(cddbalbum->track_list,cddbtrackalbum);
1220 }
1221
1222 g_free (cddb_out);
1223 continue;
1224
1225 }else if ( strncmp(cddb_out,"EXTD=",5)==0 ) // Extended album data
1226 {
1227 gchar *genre_ptr = strstr(cddb_out,"ID3G:");
1228 gchar *year_ptr = strstr(cddb_out,"YEAR:");
1229 // May contains severals EXTD field it too long
1230 // EXTD=Techno
1231 // EXTD= YEAR: 1997 ID3G: 18
1232 // EXTD= ID3G: 17
1233 if (year_ptr && cddbalbum->year)
1234 cddbalbum->year = g_strdup_printf("%d",atoi(year_ptr+5));
1235 if (genre_ptr && cddbalbum->genre)
1236 cddbalbum->genre = g_strdup(Id3tag_Genre_To_String(atoi(genre_ptr+5)));
1237
1238 g_free (cddb_out);
1239 continue;
1240 }
1241
1242 g_free(cddb_out);
1243 }
1244
1245 // Close file opened for reading lines
1246 if (file)
1247 {
1248 fclose(file);
1249 file = NULL;
1250 }
1251
1252 /* Remote access. */
1253 /* Close connection */
1254 Cddb_Close_Connection (self, socket_id);
1255
1256 /* Set color of the selected row (without reloading the whole list) */
1257 Cddb_Album_List_Set_Row_Appearance (self, &row);
1258
1259 /* Load the track list of the album */
1260 gtk_statusbar_push(GTK_STATUSBAR(priv->status_bar),priv->status_bar_context,_("Loading album track list…"));
1261 while (gtk_events_pending()) gtk_main_iteration();
1262 Cddb_Load_Track_Album_List (self, cddbalbum->track_list);
1263
1264 show_album_info (self, gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->album_list_view)));
1265
1266 g_list_free_full (g_list_first (TrackOffsetList),
1267 (GDestroyNotify)cddb_track_frame_offset_free);
1268 return TRUE;
1269 }
1270
1271 /*
1272 * Callback when selecting a row in the Album List.
1273 * We get the list of tracks of the selected album
1274 */
1275 static void
Cddb_Get_Album_Tracks_List_CB(EtCDDBDialog * self,GtkTreeSelection * selection)1276 Cddb_Get_Album_Tracks_List_CB (EtCDDBDialog *self, GtkTreeSelection *selection)
1277 {
1278 gint i;
1279 gint i_max = 5;
1280
1281 /* As may be not opened the first time (The server returned a wrong answer!)
1282 * me try to reconnect severals times */
1283 for (i = 1; i <= i_max; i++)
1284 {
1285 if (Cddb_Get_Album_Tracks_List (self, selection) == TRUE)
1286 {
1287 break;
1288 }
1289 }
1290 }
1291
1292 /*
1293 * Load the priv->album_list into the corresponding List
1294 */
1295 static void
Cddb_Load_Album_List(EtCDDBDialog * self,gboolean only_red_lines)1296 Cddb_Load_Album_List (EtCDDBDialog *self, gboolean only_red_lines)
1297 {
1298 EtCDDBDialogPrivate *priv;
1299 GtkTreeIter iter;
1300 GList *l;
1301
1302 GtkTreeSelection *selection;
1303 GList *selectedRows = NULL;
1304 GtkTreeIter currentIter;
1305 CddbAlbum *cddbalbumSelected = NULL;
1306
1307 priv = et_cddb_dialog_get_instance_private (self);
1308
1309 // Memorize the current selected item
1310 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(priv->album_list_view));
1311 selectedRows = gtk_tree_selection_get_selected_rows(selection, NULL);
1312 if (selectedRows)
1313 {
1314 if (gtk_tree_model_get_iter(GTK_TREE_MODEL(priv->album_list_model), ¤tIter, (GtkTreePath*)selectedRows->data))
1315 gtk_tree_model_get(GTK_TREE_MODEL(priv->album_list_model), ¤tIter,
1316 CDDB_ALBUM_LIST_DATA, &cddbalbumSelected, -1);
1317 }
1318
1319 /* Remove lines. */
1320 cddb_album_model_clear (self);
1321
1322 // Reload list following parameter 'only_red_lines'
1323 for (l = g_list_first (priv->album_list); l != NULL; l = g_list_next (l))
1324 {
1325 CddbAlbum *cddbalbum = l->data;
1326
1327 if ( (only_red_lines && cddbalbum->track_list) || !only_red_lines)
1328 {
1329 /* Load the row in the list. */
1330 gtk_list_store_insert_with_values (priv->album_list_model, &iter,
1331 G_MAXINT,
1332 CDDB_ALBUM_LIST_PIXBUF,
1333 cddbalbum->bitmap,
1334 CDDB_ALBUM_LIST_ALBUM,
1335 cddbalbum->artist_album,
1336 CDDB_ALBUM_LIST_CATEGORY,
1337 cddbalbum->category,
1338 CDDB_ALBUM_LIST_DATA,
1339 cddbalbum, -1);
1340
1341 Cddb_Album_List_Set_Row_Appearance (self, &iter);
1342
1343 // Select this item if it is the saved one...
1344 if (cddbalbum == cddbalbumSelected)
1345 gtk_tree_selection_select_iter(gtk_tree_view_get_selection(GTK_TREE_VIEW(priv->album_list_view)), &iter);
1346 }
1347 }
1348 }
1349
1350 /*
1351 * Free priv->album_list
1352 */
1353 static gboolean
Cddb_Free_Album_List(EtCDDBDialog * self)1354 Cddb_Free_Album_List (EtCDDBDialog *self)
1355 {
1356 EtCDDBDialogPrivate *priv;
1357 GList *l;
1358
1359 priv = et_cddb_dialog_get_instance_private (self);
1360
1361 g_return_val_if_fail (priv->album_list != NULL, FALSE);
1362
1363 priv->album_list = g_list_first (priv->album_list);
1364
1365 for (l = priv->album_list; l != NULL; l = g_list_next (l))
1366 {
1367 CddbAlbum *cddbalbum = l->data;
1368
1369 if (cddbalbum)
1370 {
1371 g_free(cddbalbum->server_name);
1372 g_free (cddbalbum->server_cgi_path);
1373 g_object_unref(cddbalbum->bitmap);
1374
1375 g_free(cddbalbum->artist_album);
1376 g_free(cddbalbum->category);
1377 g_free(cddbalbum->id);
1378 if (cddbalbum->track_list)
1379 {
1380 Cddb_Free_Track_Album_List(cddbalbum->track_list);
1381 cddbalbum->track_list = NULL;
1382 }
1383 g_free(cddbalbum->artist);
1384 g_free(cddbalbum->album);
1385 g_free(cddbalbum->genre);
1386 g_free(cddbalbum->year);
1387
1388 g_slice_free (CddbAlbum, cddbalbum);
1389 }
1390 }
1391
1392 g_list_free (priv->album_list);
1393 priv->album_list = NULL;
1394
1395 return TRUE;
1396 }
1397
1398 /*
1399 * Fields : artist, title, track, rest
1400 * CDDB Categories : blues, classical, country, data, folk, jazz, misc, newage, reggae, rock, soundtrack
1401 */
1402 static gchar *
Cddb_Generate_Request_String_With_Fields_And_Categories_Options(EtCDDBDialog * self)1403 Cddb_Generate_Request_String_With_Fields_And_Categories_Options (EtCDDBDialog *self)
1404 {
1405 GString *string;
1406 guint search_fields;
1407 guint search_categories;
1408
1409 /* Init. */
1410 string = g_string_sized_new (256);
1411
1412 /* Fields. */
1413 /* FIXME: Fetch cddb-search-fields "all-set" mask. */
1414 #if 0
1415 if (search_all_fields)
1416 {
1417 g_string_append (string, "&allfields=YES");
1418 }
1419 else
1420 {
1421 g_string_append (string, "&allfields=NO");
1422 }
1423 #endif
1424
1425 search_fields = g_settings_get_flags (MainSettings, "cddb-search-fields");
1426
1427 if (search_fields & ET_CDDB_SEARCH_FIELD_ARTIST)
1428 {
1429 g_string_append (string, "&fields=artist");
1430 }
1431 if (search_fields & ET_CDDB_SEARCH_FIELD_TITLE)
1432 {
1433 g_string_append (string, "&fields=title");
1434 }
1435 if (search_fields & ET_CDDB_SEARCH_FIELD_TRACK)
1436 {
1437 g_string_append (string, "&fields=track");
1438 }
1439 if (search_fields & ET_CDDB_SEARCH_FIELD_OTHER)
1440 {
1441 g_string_append (string, "&fields=rest");
1442 }
1443
1444 /* Categories (warning: there is one other CDDB category that is not used
1445 * here ("data")) */
1446 search_categories = g_settings_get_flags (MainSettings,
1447 "cddb-search-categories");
1448 g_string_append (string, "&allcats=NO");
1449
1450 if (search_categories & ET_CDDB_SEARCH_CATEGORY_BLUES)
1451 {
1452 g_string_append (string, "&cats=blues");
1453 }
1454 if (search_categories & ET_CDDB_SEARCH_CATEGORY_CLASSICAL)
1455 {
1456 g_string_append (string, "&cats=classical");
1457 }
1458 if (search_categories & ET_CDDB_SEARCH_CATEGORY_COUNTRY)
1459 {
1460 g_string_append (string, "&cats=country");
1461 }
1462 if (search_categories & ET_CDDB_SEARCH_CATEGORY_FOLK)
1463 {
1464 g_string_append (string, "&cats=folk");
1465 }
1466 if (search_categories & ET_CDDB_SEARCH_CATEGORY_JAZZ)
1467 {
1468 g_string_append (string, "&cats=jazz");
1469 }
1470 if (search_categories & ET_CDDB_SEARCH_CATEGORY_MISC)
1471 {
1472 g_string_append (string, "&cats=misc");
1473 }
1474 if (search_categories & ET_CDDB_SEARCH_CATEGORY_NEWAGE)
1475 {
1476 g_string_append (string, "&cats=newage");
1477 }
1478 if (search_categories & ET_CDDB_SEARCH_CATEGORY_REGGAE)
1479 {
1480 g_string_append (string, "&cats=reggae");
1481 }
1482 if (search_categories & ET_CDDB_SEARCH_CATEGORY_ROCK)
1483 {
1484 g_string_append (string, "&cats=rock");
1485 }
1486 if (search_categories & ET_CDDB_SEARCH_CATEGORY_SOUNDTRACK)
1487 {
1488 g_string_append (string, "&cats=soundtrack");
1489 }
1490
1491 return g_string_free (string, FALSE);
1492 }
1493
1494
1495 /*
1496 * Site FREEDB.ORG - Manual Search
1497 * Send request (using the HTML search page in freedb.org site) to the CD database
1498 * to get the list of albums matching to a string.
1499 */
1500 static gboolean
Cddb_Search_Album_List_From_String_Freedb(EtCDDBDialog * self)1501 Cddb_Search_Album_List_From_String_Freedb (EtCDDBDialog *self)
1502 {
1503 EtCDDBDialogPrivate *priv;
1504 gint socket_id;
1505 gchar *string = NULL;
1506 gchar *tmp, *tmp1;
1507 gchar *cddb_in; // For the request to send
1508 gchar *cddb_out = NULL; // Answer received
1509 gchar *cddb_out_tmp;
1510 gchar *msg;
1511 gchar *proxy_auth = NULL;
1512 gchar *cddb_server_name;
1513 guint cddb_server_port;
1514 gchar *cddb_server_cgi_path;
1515 gboolean proxy_enabled;
1516 gchar *proxy_hostname;
1517 guint proxy_port;
1518
1519 gchar *ptr_cat, *cat_str, *id_str, *art_alb_str;
1520 gchar *art_alb_tmp = NULL;
1521 gboolean use_art_alb = FALSE;
1522 gchar *end_str;
1523 gchar *html_end_str;
1524 gchar buffer[MAX_STRING_LEN+1];
1525 gint bytes_written;
1526 gulong bytes_read_total = 0;
1527 FILE *file = NULL;
1528 gboolean web_search_disabled = FALSE;
1529
1530 priv = et_cddb_dialog_get_instance_private (self);
1531
1532 gtk_statusbar_push(GTK_STATUSBAR(priv->status_bar),priv->status_bar_context,"");
1533
1534 /* Get words to search... */
1535 string = g_strdup (gtk_entry_get_text (GTK_ENTRY (priv->search_entry)));
1536 if (et_str_empty (string))
1537 {
1538 return FALSE;
1539 }
1540
1541 /* Format the string of words */
1542 g_strstrip (string);
1543 /* Remove the duplicated spaces */
1544 while ((tmp=strstr(string," "))!=NULL) // Search 2 spaces
1545 {
1546 tmp1 = tmp + 1;
1547 while (*tmp1)
1548 *(tmp++) = *(tmp1++);
1549 *tmp = '\0';
1550 }
1551
1552 /* Convert spaces to '+' */
1553 while ( (tmp=strchr(string,' '))!=NULL )
1554 *tmp = '+';
1555
1556 cddb_server_name = g_settings_get_string (MainSettings,
1557 "cddb-manual-search-hostname");
1558 cddb_server_port = g_settings_get_uint (MainSettings,
1559 "cddb-manual-search-port");
1560 cddb_server_cgi_path = g_settings_get_string (MainSettings,
1561 "cddb-manual-search-path");
1562
1563 /* Connection to the server */
1564 proxy_enabled = g_settings_get_boolean (MainSettings,
1565 "cddb-proxy-enabled");
1566 proxy_hostname = g_settings_get_string (MainSettings,
1567 "cddb-proxy-hostname");
1568 proxy_port = g_settings_get_uint (MainSettings, "cddb-proxy-port");
1569 if ((socket_id = Cddb_Open_Connection (self,
1570 proxy_enabled
1571 ? proxy_hostname
1572 : cddb_server_name,
1573 proxy_enabled
1574 ? proxy_port
1575 : cddb_server_port)) <= 0)
1576 {
1577 g_free (string);
1578 g_free (cddb_server_name);
1579 g_free (cddb_server_cgi_path);
1580 g_free (proxy_hostname);
1581 return FALSE;
1582 }
1583
1584 /* Build request */
1585 //cddb_in = g_strdup_printf("GET http://www.freedb.org/freedb_search.php?" // In this case, problem with squid cache...
1586 cddb_in = g_strdup_printf("GET %s%s/freedb_search.php?"
1587 "words=%s"
1588 "%s"
1589 "&grouping=none"
1590 " HTTP/1.1\r\n"
1591 "Host: %s:%u\r\n"
1592 "User-Agent: %s %s\r\n"
1593 "%s"
1594 "Connection: close\r\n"
1595 "\r\n",
1596 proxy_enabled ? "http://" : "",
1597 proxy_enabled ? cddb_server_name : "",
1598 string,
1599 (tmp = Cddb_Generate_Request_String_With_Fields_And_Categories_Options (self)),
1600 cddb_server_name,cddb_server_port,
1601 PACKAGE_NAME, PACKAGE_VERSION,
1602 (proxy_auth=Cddb_Format_Proxy_Authentification())
1603 );
1604
1605 g_free(string);
1606 g_free(tmp);
1607 g_free(proxy_auth);
1608 //g_print("Request Cddb_Search_Album_List_From_String_Freedb : '%s'\n", cddb_in);
1609
1610 // Send the request
1611 gtk_statusbar_push(GTK_STATUSBAR(priv->status_bar),priv->status_bar_context,_("Sending request…"));
1612 while (gtk_events_pending()) gtk_main_iteration();
1613 if ( (bytes_written=send(socket_id,cddb_in,strlen(cddb_in)+1,0)) < 0)
1614 {
1615 Log_Print (LOG_ERROR, _("Cannot send the request ‘%s’"),
1616 g_strerror (errno));
1617 Cddb_Close_Connection (self, socket_id);
1618 g_free(cddb_in);
1619 g_free(string);
1620 g_free(cddb_server_name);
1621 g_free(cddb_server_cgi_path);
1622 g_free (proxy_hostname);
1623 return FALSE;
1624 }
1625 g_free(cddb_in);
1626
1627
1628 /* Delete previous album list. */
1629 cddb_album_model_clear (self);
1630 cddb_track_model_clear (self);
1631
1632 if (priv->album_list)
1633 {
1634 Cddb_Free_Album_List (self);
1635 }
1636 gtk_widget_set_sensitive (GTK_WIDGET (priv->stop_search_button), TRUE);
1637
1638
1639 /*
1640 * Read the answer
1641 */
1642 gtk_statusbar_push(GTK_STATUSBAR(priv->status_bar),priv->status_bar_context,_("Receiving data…"));
1643 while (gtk_events_pending())
1644 gtk_main_iteration();
1645
1646 /* Write result in a file. */
1647 if (Cddb_Write_Result_To_File (self, socket_id, &bytes_read_total) < 0)
1648 {
1649 msg = g_strdup(_("The server returned a bad response"));
1650 gtk_statusbar_push(GTK_STATUSBAR(priv->status_bar),priv->status_bar_context,msg);
1651 Log_Print(LOG_ERROR,"%s",msg);
1652 g_free(msg);
1653 g_free(cddb_server_name);
1654 g_free(cddb_server_cgi_path);
1655 gtk_widget_set_sensitive(GTK_WIDGET(priv->stop_search_button),FALSE);
1656 return FALSE;
1657 }
1658
1659 // Parse server answer : Check returned code in the first line
1660 if (Cddb_Read_Http_Header(&file,&cddb_out) <= 0 || !cddb_out) // Order is important!
1661 {
1662 msg = g_strdup_printf (_("The server returned a bad response ‘%s’"),
1663 cddb_out);
1664 gtk_statusbar_push(GTK_STATUSBAR(priv->status_bar),priv->status_bar_context,msg);
1665 Log_Print(LOG_ERROR,"%s",msg);
1666 g_free(msg);
1667 g_free(cddb_out);
1668 g_free(cddb_server_name);
1669 g_free(cddb_server_cgi_path);
1670 g_free (proxy_hostname);
1671 gtk_widget_set_sensitive(GTK_WIDGET(priv->stop_search_button),FALSE);
1672 if (file)
1673 fclose(file);
1674 return FALSE;
1675 }
1676 g_free(cddb_out);
1677
1678 // Read other lines, and get list of matching albums
1679 // Composition of a line :
1680 // - freedb.org
1681 // <a href="http://www.freedb.org/freedb_search_fmt.php?cat=rock&id=8c0f0a0b">Bob Dylan / MTV Unplugged</a><br>
1682 cat_str = g_strdup("http://www.freedb.org/freedb_search_fmt.php?cat=");
1683 id_str = g_strdup("&id=");
1684 art_alb_str = g_strdup("\">");
1685 end_str = g_strdup("</a>"); //"</a><br>");
1686 html_end_str = g_strdup("</body>"); // To avoid the cddb lookups to hang
1687 while (!priv->stop_searching && Cddb_Read_Line (&file, &cddb_out) > 0)
1688 {
1689 cddb_out_tmp = cddb_out;
1690 //g_print("%s\n",cddb_out); // To print received data
1691
1692 // If the web search is disabled! (ex : http://www.freedb.org/modules.php?name=News&file=article&sid=246)
1693 // The following string is displayed in the search page
1694 if (cddb_out != NULL && strstr(cddb_out_tmp,"Sorry, The web-based search is currently down.") != NULL)
1695 {
1696 web_search_disabled = TRUE;
1697 break;
1698 }
1699
1700 // We may have severals album in the same line (other version of the same album?)
1701 // Note : we test that the 'end' delimiter exists to avoid crashes
1702 while ( cddb_out != NULL && (ptr_cat=strstr(cddb_out_tmp,cat_str)) != NULL && strstr(cddb_out_tmp,end_str) != NULL )
1703 {
1704 gchar *ptr_font, *ptr_font1;
1705 gchar *ptr_id, *ptr_art_alb, *ptr_end;
1706 gchar *copy;
1707 CddbAlbum *cddbalbum;
1708
1709 cddbalbum = g_slice_new0 (CddbAlbum);
1710
1711
1712 // Parameters of the server used
1713 cddbalbum->server_name = g_strdup(cddb_server_name);
1714 cddbalbum->server_port = cddb_server_port;
1715 cddbalbum->server_cgi_path = g_strdup(cddb_server_cgi_path);
1716 cddbalbum->bitmap = Cddb_Get_Pixbuf_From_Server_Name(cddbalbum->server_name);
1717
1718 // Get album category
1719 cddb_out_tmp = ptr_cat + strlen(cat_str);
1720 strncpy(buffer,cddb_out_tmp,MAX_STRING_LEN);
1721 if ( (ptr_id=strstr(buffer,id_str)) != NULL )
1722 *ptr_id = 0;
1723 cddbalbum->category = Try_To_Validate_Utf8_String(buffer);
1724
1725
1726 // Get album ID
1727 //cddb_out_tmp = strstr(cddb_out_tmp,id_str) + strlen(id_str);
1728 cddb_out_tmp = ptr_cat + strlen(cat_str) + 2;
1729 strncpy(buffer,cddb_out_tmp,MAX_STRING_LEN);
1730 if ( (ptr_art_alb=strstr(buffer,art_alb_str)) != NULL )
1731 *ptr_art_alb = 0;
1732 cddbalbum->id = Try_To_Validate_Utf8_String(buffer);
1733
1734
1735 // Get album and artist names.
1736 // Note : some names can be like this "<font size=-1>2</font>" (for other version of the same album)
1737 cddb_out_tmp = strstr(cddb_out_tmp,art_alb_str) + strlen(art_alb_str);
1738 strncpy(buffer,cddb_out_tmp,MAX_STRING_LEN);
1739 if ( (ptr_end=strstr(buffer,end_str)) != NULL )
1740 *ptr_end = 0;
1741 if ( (ptr_font=strstr(buffer,"</font>")) != NULL )
1742 {
1743 copy = NULL;
1744 *ptr_font = 0;
1745 if ( (ptr_font1=strstr(buffer,">")) != NULL )
1746 {
1747 copy = g_strdup_printf("%s -> %s",ptr_font1+1,art_alb_tmp);
1748 cddbalbum->other_version = TRUE;
1749 }else
1750 {
1751 copy = g_strdup(buffer);
1752 }
1753
1754 }else
1755 {
1756 copy = g_strdup(buffer);
1757 art_alb_tmp = cddbalbum->artist_album;
1758 use_art_alb = TRUE;
1759 }
1760
1761 cddbalbum->artist_album = Try_To_Validate_Utf8_String(copy);
1762 g_free(copy);
1763
1764 if (use_art_alb)
1765 {
1766 art_alb_tmp = cddbalbum->artist_album;
1767 use_art_alb = FALSE;
1768 }
1769
1770
1771 // New position the search the next string
1772 cddb_out_tmp = strstr(cddb_out_tmp,end_str) + strlen(end_str);
1773
1774 priv->album_list = g_list_append(priv->album_list,cddbalbum);
1775 }
1776
1777 // To avoid the cddb lookups to hang (Patch from Paul Giordano)
1778 /* It appears that on some systems that cddb lookups continue to attempt
1779 * to get data from the socket even though the other system has completed
1780 * sending. Here we see if the actual end of data is in the last block read.
1781 * In the case of the html scan, the </body> tag is used because there's
1782 * no crlf followint the </html> tag.
1783 */
1784 if (strstr(cddb_out_tmp,html_end_str)!=NULL)
1785 {
1786 g_free(cddb_out);
1787 break;
1788 }
1789 g_free(cddb_out);
1790 }
1791 g_free(cat_str); g_free(id_str); g_free(art_alb_str); g_free(end_str); g_free(html_end_str);
1792 g_free(cddb_server_name);
1793 g_free(cddb_server_cgi_path);
1794 g_free (proxy_hostname);
1795
1796 // Close file opened for reading lines
1797 if (file)
1798 {
1799 fclose(file);
1800 file = NULL;
1801 }
1802
1803 gtk_widget_set_sensitive(GTK_WIDGET(priv->stop_search_button),FALSE);
1804
1805 /* Close connection. */
1806 Cddb_Close_Connection (self, socket_id);
1807
1808 if (web_search_disabled)
1809 msg = g_strdup_printf(_("Sorry, the web-based search is currently not available"));
1810 else
1811 {
1812 msg = g_strdup_printf (ngettext ("Found one matching album",
1813 "Found %u matching albums",
1814 g_list_length (priv->album_list)),
1815 g_list_length (priv->album_list));
1816 }
1817
1818 gtk_statusbar_push(GTK_STATUSBAR(priv->status_bar),priv->status_bar_context,msg);
1819 g_free(msg);
1820
1821 /* Load the albums found in the list. */
1822 Cddb_Load_Album_List (self, FALSE);
1823
1824 return TRUE;
1825 }
1826
1827 /*
1828 * Site GNUDB.ORG - Manual Search
1829 * Send request (using the HTML search page in freedb.org site) to the CD database
1830 * to get the list of albums matching to a string.
1831 */
1832 static gboolean
Cddb_Search_Album_List_From_String_Gnudb(EtCDDBDialog * self)1833 Cddb_Search_Album_List_From_String_Gnudb (EtCDDBDialog *self)
1834 {
1835 EtCDDBDialogPrivate *priv;
1836 gint socket_id;
1837 gchar *string = NULL;
1838 gchar *tmp, *tmp1;
1839 gchar *cddb_in; // For the request to send
1840 gchar *cddb_out = NULL; // Answer received
1841 gchar *cddb_out_tmp;
1842 gchar *msg;
1843 gchar *proxy_auth = NULL;
1844 gchar *cddb_server_name;
1845 guint cddb_server_port;
1846 gchar *cddb_server_cgi_path;
1847 gboolean proxy_enabled;
1848 gchar *proxy_hostname;
1849 guint proxy_port;
1850
1851 gchar *ptr_cat, *cat_str, *art_alb_str;
1852 gchar *end_str;
1853 gchar *ptr_sraf, *sraf_str, *sraf_end_str;
1854 gchar *html_end_str;
1855 gchar buffer[MAX_STRING_LEN+1];
1856 gint bytes_written;
1857 gulong bytes_read_total = 0;
1858 FILE *file;
1859 gint num_albums = 0;
1860 gint total_num_albums = 0;
1861
1862 gchar *next_page = NULL;
1863 gint next_page_cpt = 0;
1864 gboolean next_page_found;
1865
1866 priv = et_cddb_dialog_get_instance_private (self);
1867
1868 gtk_statusbar_push(GTK_STATUSBAR(priv->status_bar),priv->status_bar_context,"");
1869
1870 /* Get words to search... */
1871 string = g_strdup (gtk_entry_get_text (GTK_ENTRY (priv->search_entry)));
1872 if (et_str_empty (string))
1873 {
1874 return FALSE;
1875 }
1876
1877 /* Format the string of words */
1878 g_strstrip (string);
1879 /* Remove the duplicated spaces */
1880 while ((tmp=strstr(string," "))!=NULL) // Search 2 spaces
1881 {
1882 tmp1 = tmp + 1;
1883 while (*tmp1)
1884 *(tmp++) = *(tmp1++);
1885 *tmp = '\0';
1886 }
1887
1888 /* Convert spaces to '+' */
1889 while ( (tmp=strchr(string,' '))!=NULL )
1890 *tmp = '+';
1891
1892 /* Delete previous album list. */
1893 cddb_album_model_clear (self);
1894 cddb_track_model_clear (self);
1895
1896 if (priv->album_list)
1897 {
1898 Cddb_Free_Album_List (self);
1899 }
1900 gtk_widget_set_sensitive(GTK_WIDGET(priv->stop_search_button),TRUE);
1901
1902
1903 // Do a loop to load all the pages of results
1904 do
1905 {
1906 cddb_server_name = g_settings_get_string (MainSettings,
1907 "cddb-manual-search-hostname");
1908 cddb_server_port = g_settings_get_uint (MainSettings,
1909 "cddb-manual-search-port");
1910 cddb_server_cgi_path = g_settings_get_string (MainSettings,
1911 "cddb-manual-search-path");
1912
1913 /* Connection to the server */
1914 proxy_enabled = g_settings_get_boolean (MainSettings,
1915 "cddb-proxy-enabled");
1916 proxy_hostname = g_settings_get_string (MainSettings,
1917 "cddb-proxy-hostname");
1918 proxy_port = g_settings_get_uint (MainSettings, "cddb-proxy-port");
1919 if ((socket_id = Cddb_Open_Connection (self,
1920 proxy_enabled ? proxy_hostname
1921 : cddb_server_name,
1922 proxy_enabled ? proxy_port
1923 : cddb_server_port)) <= 0)
1924 {
1925 g_free(string);
1926 g_free(cddb_server_name);
1927 g_free(cddb_server_cgi_path);
1928 g_free (proxy_hostname);
1929 gtk_widget_set_sensitive(GTK_WIDGET(priv->stop_search_button),FALSE);
1930 return FALSE;
1931 }
1932
1933
1934 /* Build request */
1935 cddb_in = g_strdup_printf("GET %s%s/search/"
1936 "%s"
1937 "?page=%d"
1938 " HTTP/1.1\r\n"
1939 "Host: %s:%u\r\n"
1940 "User-Agent: %s %s\r\n"
1941 "%s"
1942 "Connection: close\r\n"
1943 "\r\n",
1944 proxy_enabled ? "http://" : "",
1945 proxy_enabled ? cddb_server_name : "",
1946 string,
1947 next_page_cpt,
1948 cddb_server_name,cddb_server_port,
1949 PACKAGE_NAME, PACKAGE_VERSION,
1950 (proxy_auth=Cddb_Format_Proxy_Authentification())
1951 );
1952 next_page_found = FALSE;
1953 g_free(proxy_auth);
1954 //g_print("Request Cddb_Search_Album_List_From_String_Gnudb : '%s'\n", cddb_in);
1955
1956 // Send the request
1957 gtk_statusbar_push(GTK_STATUSBAR(priv->status_bar),priv->status_bar_context,_("Sending request…"));
1958 while (gtk_events_pending()) gtk_main_iteration();
1959 if ( (bytes_written=send(socket_id,cddb_in,strlen(cddb_in)+1,0)) < 0)
1960 {
1961 Log_Print (LOG_ERROR, _("Cannot send the request ‘%s’"),
1962 g_strerror (errno));
1963 Cddb_Close_Connection (self, socket_id);
1964 g_free (cddb_in);
1965 g_free (string);
1966 g_free (cddb_server_name);
1967 g_free (cddb_server_cgi_path);
1968 g_free (proxy_hostname);
1969 gtk_widget_set_sensitive (GTK_WIDGET (priv->stop_search_button),
1970 FALSE);
1971 return FALSE;
1972 }
1973 g_free(cddb_in);
1974
1975
1976 /*
1977 * Read the answer
1978 */
1979 if (total_num_albums != 0)
1980 msg = g_strdup_printf(_("Receiving data of page %d (album %d/%d)…"),next_page_cpt,num_albums,total_num_albums);
1981 else
1982 msg = g_strdup_printf(_("Receiving data of page %d…"),next_page_cpt);
1983
1984 gtk_statusbar_push(GTK_STATUSBAR(priv->status_bar),priv->status_bar_context,msg);
1985 g_free(msg);
1986 while (gtk_events_pending())
1987 gtk_main_iteration();
1988
1989 /* Write result in a file. */
1990 if (Cddb_Write_Result_To_File (self, socket_id, &bytes_read_total) < 0)
1991 {
1992 msg = g_strdup(_("The server returned a bad response"));
1993 gtk_statusbar_push(GTK_STATUSBAR(priv->status_bar),priv->status_bar_context,msg);
1994 Log_Print(LOG_ERROR,"%s",msg);
1995 g_free(msg);
1996 g_free(string);
1997 g_free(cddb_server_name);
1998 g_free(cddb_server_cgi_path);
1999 g_free (proxy_hostname);
2000 gtk_widget_set_sensitive(GTK_WIDGET(priv->stop_search_button),FALSE);
2001 return FALSE;
2002 }
2003
2004 // Parse server answer : Check returned code in the first line
2005 file = NULL;
2006 if (Cddb_Read_Http_Header(&file,&cddb_out) <= 0 || !cddb_out) // Order is important!
2007 {
2008 msg = g_strdup_printf (_("The server returned a bad response ‘%s’"),
2009 cddb_out);
2010 gtk_statusbar_push(GTK_STATUSBAR(priv->status_bar),priv->status_bar_context,msg);
2011 Log_Print(LOG_ERROR,"%s",msg);
2012 g_free(msg);
2013 g_free(cddb_out);
2014 g_free(string);
2015 g_free(cddb_server_name);
2016 g_free(cddb_server_cgi_path);
2017 g_free (proxy_hostname);
2018 gtk_widget_set_sensitive(GTK_WIDGET(priv->stop_search_button),FALSE);
2019 if (file)
2020 fclose(file);
2021 return FALSE;
2022 }
2023 g_free(cddb_out);
2024
2025 // The next page if exists will contains this url :
2026 g_free(next_page);
2027 next_page = g_strdup_printf("?page=%d",++next_page_cpt);
2028
2029 // Read other lines, and get list of matching albums
2030 // Composition of a line :
2031 // - gnudb.org
2032 // <a href="http://www.gnudb.org/cd/ro21123813"><b>Indochine / Le Birthday Album</b></a><br>
2033 cat_str = g_strdup("http://www.gnudb.org/cd/");
2034 art_alb_str = g_strdup("\"><b>");
2035 end_str = g_strdup("</b></a>"); //"</a><br>");
2036 html_end_str = g_strdup("</body>"); // To avoid the cddb lookups to hang
2037 // Composition of a line displaying the number of albums
2038 // <h2>Search Results, 3486 albums found:</h2>
2039 sraf_str = g_strdup("<h2>Search Results, ");
2040 sraf_end_str = g_strdup(" albums found:</h2>");
2041
2042 while (!priv->stop_searching && Cddb_Read_Line (&file, &cddb_out) > 0)
2043 {
2044 cddb_out_tmp = cddb_out;
2045 //g_print("%s\n",cddb_out); // To print received data
2046
2047 // Line that displays the number of total albums return by the search
2048 if ( cddb_out != NULL
2049 && total_num_albums == 0 // Do it only the first time
2050 && (ptr_sraf=strstr(cddb_out_tmp,sraf_end_str)) != NULL
2051 && strstr(cddb_out_tmp,sraf_str) != NULL )
2052 {
2053 // Get total number of albums
2054 ptr_sraf = 0;
2055 total_num_albums = atoi(cddb_out_tmp + strlen(sraf_str));
2056 }
2057
2058 // For GNUDB.ORG : one album per line
2059 if ( cddb_out != NULL
2060 && (ptr_cat=strstr(cddb_out_tmp,cat_str)) != NULL
2061 && strstr(cddb_out_tmp,end_str) != NULL )
2062 {
2063 gchar *ptr_art_alb, *ptr_end;
2064 gchar *valid;
2065 CddbAlbum *cddbalbum;
2066
2067 cddbalbum = g_slice_new0 (CddbAlbum);
2068
2069 // Parameters of the server used
2070 cddbalbum->server_name = g_strdup(cddb_server_name);
2071 cddbalbum->server_port = cddb_server_port;
2072 cddbalbum->server_cgi_path = g_strdup(cddb_server_cgi_path);
2073 cddbalbum->bitmap = Cddb_Get_Pixbuf_From_Server_Name(cddbalbum->server_name);
2074
2075 num_albums++;
2076
2077 // Get album category
2078 cddb_out_tmp = ptr_cat + strlen(cat_str);
2079 strncpy(buffer,cddb_out_tmp,MAX_STRING_LEN);
2080 *(buffer+2) = 0;
2081
2082 // Check only the 2 first characters to set the right category
2083 if ( strncmp(buffer,"blues",2)==0 )
2084 valid = g_strdup("blues");
2085 else if ( strncmp(buffer,"classical",2)==0 )
2086 valid = g_strdup("classical");
2087 else if ( strncmp(buffer,"country",2)==0 )
2088 valid = g_strdup("country");
2089 else if ( strncmp(buffer,"data",2)==0 )
2090 valid = g_strdup("data");
2091 else if ( strncmp(buffer,"folk",2)==0 )
2092 valid = g_strdup("folk");
2093 else if ( strncmp(buffer,"jazz",2)==0 )
2094 valid = g_strdup("jazz");
2095 else if ( strncmp(buffer,"misc",2)==0 )
2096 valid = g_strdup("misc");
2097 else if ( strncmp(buffer,"newage",2)==0 )
2098 valid = g_strdup("newage");
2099 else if ( strncmp(buffer,"reggae",2)==0 )
2100 valid = g_strdup("reggae");
2101 else if ( strncmp(buffer,"rock",2)==0 )
2102 valid = g_strdup("rock");
2103 else //if ( strncmp(buffer,"soundtrack",2)==0 )
2104 valid = g_strdup("soundtrack");
2105
2106 cddbalbum->category = valid; //Not useful -> Try_To_Validate_Utf8_String(valid);
2107
2108
2109 // Get album ID
2110 cddb_out_tmp = ptr_cat + strlen(cat_str) + 2;
2111 strncpy(buffer,cddb_out_tmp,MAX_STRING_LEN);
2112 if ( (ptr_art_alb=strstr(buffer,art_alb_str)) != NULL )
2113 *ptr_art_alb = 0;
2114 cddbalbum->id = Try_To_Validate_Utf8_String(buffer);
2115
2116
2117 // Get album and artist names.
2118 cddb_out_tmp = strstr(cddb_out_tmp,art_alb_str) + strlen(art_alb_str);
2119 strncpy(buffer,cddb_out_tmp,MAX_STRING_LEN);
2120 if ( (ptr_end=strstr(buffer,end_str)) != NULL )
2121 *ptr_end = 0;
2122 cddbalbum->artist_album = Try_To_Validate_Utf8_String(buffer);
2123
2124 priv->album_list = g_list_append(priv->album_list,cddbalbum);
2125 }
2126
2127 // To avoid the cddb lookups to hang (Patch from Paul Giordano)
2128 /* It appears that on some systems that cddb lookups continue to attempt
2129 * to get data from the socket even though the other system has completed
2130 * sending. Here we see if the actual end of data is in the last block read.
2131 * In the case of the html scan, the </body> tag is used because there's
2132 * no crlf followint the </html> tag.
2133 */
2134 /***if (strstr(cddb_out_tmp,html_end_str)!=NULL)
2135 break;***/
2136
2137
2138 // Check if the link to the next results exists to loop again with the next link
2139 if (cddb_out != NULL && next_page != NULL
2140 && (strstr(cddb_out_tmp,next_page) != NULL || next_page_cpt < 2) ) // BUG : "next_page_cpt < 2" to fix a bug in gnudb : the page 0 doesn't contain link to the page=1, so we force it...
2141 {
2142 next_page_found = TRUE;
2143
2144 if ( !(next_page_cpt < 2) ) // Don't display message in this case as it will be displayed each line of page 0 and 1
2145 {
2146 msg = g_strdup_printf(_("More results to load…"));
2147 gtk_statusbar_push(GTK_STATUSBAR(priv->status_bar),priv->status_bar_context,msg);
2148 g_free(msg);
2149
2150 while (gtk_events_pending())
2151 gtk_main_iteration();
2152 }
2153 }
2154
2155 g_free(cddb_out);
2156 }
2157 g_free(cat_str); g_free(art_alb_str); g_free(end_str); g_free(html_end_str);
2158 g_free(sraf_str);g_free(sraf_end_str);
2159 g_free(cddb_server_name);
2160 g_free(cddb_server_cgi_path);
2161 g_free (proxy_hostname);
2162
2163 // Close file opened for reading lines
2164 if (file)
2165 {
2166 fclose(file);
2167 file = NULL;
2168 }
2169
2170 /* Close connection. */
2171 Cddb_Close_Connection (self, socket_id);
2172
2173 } while (next_page_found);
2174 g_free(string);
2175
2176
2177 gtk_widget_set_sensitive(GTK_WIDGET(priv->stop_search_button),FALSE);
2178
2179 msg = g_strdup_printf(ngettext("Found one matching album","Found %d matching albums",num_albums),num_albums);
2180 gtk_statusbar_push(GTK_STATUSBAR(priv->status_bar),priv->status_bar_context,msg);
2181 g_free(msg);
2182
2183 /* Load the albums found in the list. */
2184 Cddb_Load_Album_List (self, FALSE);
2185
2186 return TRUE;
2187 }
2188
2189 /*
2190 * Select the function to use according the server adress for the manual search
2191 * - freedb.freedb.org
2192 * - gnudb.gnudb.org
2193 */
2194 static gboolean
Cddb_Search_Album_List_From_String(EtCDDBDialog * self)2195 Cddb_Search_Album_List_From_String (EtCDDBDialog *self)
2196 {
2197 gchar *hostname = g_settings_get_string (MainSettings,
2198 "cddb-manual-search-hostname");
2199
2200 if (strstr (hostname, "gnudb") != NULL)
2201 {
2202 /* Use gnudb. */
2203 g_free (hostname);
2204 return Cddb_Search_Album_List_From_String_Gnudb (self);
2205 }
2206 else
2207 {
2208 /* Use freedb. */
2209 g_free (hostname);
2210 return Cddb_Search_Album_List_From_String_Freedb (self);
2211 }
2212 }
2213
2214 /*
2215 * set_et_file_from_cddb_album:
2216 * @etfile: an ET_File on which to set values
2217 * @cddbtrackalbum: a CddbTrackAlbum from which to take values
2218 * @set_fields: flags value for the fields to set
2219 * @list_length: length of the CDDB album data (in tracks)
2220 *
2221 * Set the values obtained from CDDB and stored in @cddbtrackalbum to the
2222 * given @etfile.
2223 */
2224 static void
set_et_file_from_cddb_album(ET_File * etfile,CddbTrackAlbum * cddbtrackalbum,guint set_fields,guint list_length)2225 set_et_file_from_cddb_album (ET_File * etfile,
2226 CddbTrackAlbum *cddbtrackalbum,
2227 guint set_fields,
2228 guint list_length)
2229 {
2230 File_Tag *FileTag = NULL;
2231 File_Name *FileName = NULL;
2232
2233 g_return_if_fail (etfile != NULL);
2234 g_return_if_fail (cddbtrackalbum != NULL);
2235
2236 if (set_fields != 0)
2237 {
2238 /* Allocation of a new FileTag. */
2239 FileTag = et_file_tag_new ();
2240 et_file_tag_copy_into (FileTag, etfile->FileTag->data);
2241
2242 if (set_fields & ET_CDDB_SET_FIELD_TITLE)
2243 {
2244 et_file_tag_set_title (FileTag,
2245 cddbtrackalbum->track_name);
2246 }
2247
2248 if ((set_fields & ET_CDDB_SET_FIELD_ARTIST)
2249 && cddbtrackalbum->cddbalbum->artist)
2250 {
2251 et_file_tag_set_artist (FileTag,
2252 cddbtrackalbum->cddbalbum->artist);
2253 }
2254
2255 if ((set_fields & ET_CDDB_SET_FIELD_ALBUM)
2256 && cddbtrackalbum->cddbalbum->album)
2257 {
2258 et_file_tag_set_album (FileTag,
2259 cddbtrackalbum->cddbalbum->album);
2260 }
2261
2262 if ((set_fields & ET_CDDB_SET_FIELD_YEAR)
2263 && cddbtrackalbum->cddbalbum->year)
2264 {
2265 et_file_tag_set_year (FileTag,
2266 cddbtrackalbum->cddbalbum->year);
2267 }
2268
2269 if (set_fields & ET_CDDB_SET_FIELD_TRACK)
2270 {
2271 gchar *track_number;
2272
2273 track_number = et_track_number_to_string (cddbtrackalbum->track_number);
2274
2275 et_file_tag_set_track_number (FileTag, track_number);
2276
2277 g_free (track_number);
2278 }
2279
2280 if (set_fields & ET_CDDB_SET_FIELD_TRACK_TOTAL)
2281 {
2282 gchar *track_total;
2283
2284 track_total = et_track_number_to_string (list_length);
2285
2286 et_file_tag_set_track_total (FileTag, track_total);
2287
2288 g_free (track_total);
2289 }
2290
2291 if ((set_fields & ET_CDDB_SET_FIELD_GENRE)
2292 && (cddbtrackalbum->cddbalbum->genre
2293 || cddbtrackalbum->cddbalbum->category))
2294 {
2295 if (!et_str_empty (cddbtrackalbum->cddbalbum->genre))
2296 {
2297 et_file_tag_set_genre (FileTag,
2298 Cddb_Get_Id3_Genre_From_Cddb_Genre (cddbtrackalbum->cddbalbum->genre));
2299 }
2300 else
2301 {
2302 et_file_tag_set_genre (FileTag,
2303 Cddb_Get_Id3_Genre_From_Cddb_Genre (cddbtrackalbum->cddbalbum->category));
2304 }
2305 }
2306 }
2307
2308 /* Filename field. */
2309 if (set_fields & ET_CDDB_SET_FIELD_FILENAME)
2310 {
2311 gchar *track_number;
2312 gchar *filename_generated_utf8;
2313 gchar *filename_new_utf8;
2314
2315 /* Allocation of a new FileName. */
2316 FileName = et_file_name_new ();
2317
2318 /* Build the filename with the path. */
2319 track_number = et_track_number_to_string (cddbtrackalbum->track_number);
2320
2321 filename_generated_utf8 = g_strconcat (track_number, " - ",
2322 cddbtrackalbum->track_name,
2323 NULL);
2324 et_filename_prepare (filename_generated_utf8,
2325 g_settings_get_boolean (MainSettings,
2326 "rename-replace-illegal-chars"));
2327 filename_new_utf8 = et_file_generate_name (etfile,
2328 filename_generated_utf8);
2329
2330 ET_Set_Filename_File_Name_Item(FileName,filename_new_utf8,NULL);
2331
2332 g_free (track_number);
2333 g_free(filename_generated_utf8);
2334 g_free(filename_new_utf8);
2335 }
2336
2337 ET_Manage_Changes_Of_File_Data (etfile, FileName, FileTag);
2338
2339 /* Then run current scanner if requested. */
2340 if (g_settings_get_boolean (MainSettings, "cddb-run-scanner"))
2341 {
2342 EtScanDialog *dialog;
2343
2344 dialog = ET_SCAN_DIALOG (et_application_window_get_scan_dialog (ET_APPLICATION_WINDOW (MainWindow)));
2345
2346 if (dialog)
2347 {
2348 Scan_Select_Mode_And_Run_Scanner (dialog, etfile);
2349 }
2350 }
2351 }
2352 /*
2353 * Set CDDB data (from tracks list) into tags of the main file list
2354 */
2355 static gboolean
Cddb_Set_Track_Infos_To_File_List(EtCDDBDialog * self)2356 Cddb_Set_Track_Infos_To_File_List (EtCDDBDialog *self)
2357 {
2358 EtCDDBDialogPrivate *priv;
2359 guint row;
2360 guint list_length;
2361 guint rows_to_loop = 0;
2362 guint selectedcount;
2363 guint file_selectedcount;
2364 guint counter = 0;
2365 GList *file_iterlist = NULL;
2366 GList *file_selectedrows;
2367 GList *selectedrows = NULL;
2368 gboolean CddbTrackList_Line_Selected;
2369 CddbTrackAlbum *cddbtrackalbum = NULL;
2370 GtkTreeSelection *selection = NULL;
2371 GtkTreeSelection *file_selection = NULL;
2372 GtkListStore *fileListModel;
2373 GtkTreePath *currentPath = NULL;
2374 GtkTreeIter currentIter;
2375 GtkTreeIter *fileIter;
2376 gpointer iterptr;
2377
2378 g_return_val_if_fail (ETCore->ETFileDisplayedList != NULL, FALSE);
2379
2380 priv = et_cddb_dialog_get_instance_private (self);
2381
2382 et_application_window_update_et_file_from_ui (ET_APPLICATION_WINDOW (MainWindow));
2383
2384 /* FIXME: Hack! */
2385 file_selection = et_application_window_browser_get_selection (ET_APPLICATION_WINDOW (MainWindow));
2386 fileListModel = GTK_LIST_STORE (gtk_tree_view_get_model (gtk_tree_selection_get_tree_view (file_selection)));
2387 list_length = gtk_tree_model_iter_n_children(GTK_TREE_MODEL(priv->track_list_model), NULL);
2388
2389 // Take the selected files in the cddb track list, else the full list
2390 // Note : Just used to calculate "cddb_track_list_length" because
2391 // "GPOINTER_TO_INT(cddb_track_list->data)" doesn't return the number of the
2392 // line when "cddb_track_list = g_list_first(GTK_CLIST(CddbTrackCList)->row_list)"
2393 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(priv->track_list_view));
2394 selectedcount = gtk_tree_selection_count_selected_rows(selection);
2395
2396 /* Check if at least one line was selected. No line selected is equal to all lines selected. */
2397 if (selectedcount > 0)
2398 {
2399 /* Loop through selected rows only */
2400 CddbTrackList_Line_Selected = TRUE;
2401 rows_to_loop = selectedcount;
2402 selectedrows = gtk_tree_selection_get_selected_rows(selection, NULL);
2403 } else
2404 {
2405 /* Loop through all rows */
2406 CddbTrackList_Line_Selected = FALSE;
2407 rows_to_loop = list_length;
2408 }
2409
2410 file_selectedcount = gtk_tree_selection_count_selected_rows (file_selection);
2411
2412 if (file_selectedcount > 0)
2413 {
2414 GList *l;
2415
2416 /* Rows are selected in the file list, apply tags to them only */
2417 file_selectedrows = gtk_tree_selection_get_selected_rows(file_selection, NULL);
2418
2419 for (l = file_selectedrows; l != NULL; l = g_list_next (l))
2420 {
2421 counter++;
2422 iterptr = g_malloc0(sizeof(GtkTreeIter));
2423 if (gtk_tree_model_get_iter (GTK_TREE_MODEL (fileListModel),
2424 (GtkTreeIter *)iterptr,
2425 (GtkTreePath *)l->data))
2426 {
2427 file_iterlist = g_list_prepend (file_iterlist, iterptr);
2428 }
2429
2430 if (counter == rows_to_loop) break;
2431 }
2432
2433 /* Free the useless bit */
2434 g_list_free_full (file_selectedrows,
2435 (GDestroyNotify)gtk_tree_path_free);
2436
2437 } else /* No rows selected, use the first x items in the list */
2438 {
2439 gtk_tree_model_get_iter_first(GTK_TREE_MODEL(fileListModel), ¤tIter);
2440
2441 do
2442 {
2443 counter++;
2444 iterptr = g_memdup(¤tIter, sizeof(GtkTreeIter));
2445 file_iterlist = g_list_prepend (file_iterlist, iterptr);
2446 } while (gtk_tree_model_iter_next(GTK_TREE_MODEL(fileListModel), ¤tIter));
2447
2448 file_selectedcount = gtk_tree_model_iter_n_children(GTK_TREE_MODEL(fileListModel), NULL);
2449 }
2450
2451 if (file_selectedcount != rows_to_loop)
2452 {
2453 GtkWidget *msgdialog;
2454 gint response;
2455
2456 msgdialog = gtk_message_dialog_new(GTK_WINDOW(self),
2457 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
2458 GTK_MESSAGE_QUESTION,
2459 GTK_BUTTONS_NONE,
2460 "%s",
2461 _("The number of CDDB results does not match the number of selected files"));
2462 gtk_dialog_add_buttons (GTK_DIALOG (msgdialog), _("_Cancel"),
2463 GTK_RESPONSE_CANCEL, _("_Apply"),
2464 GTK_RESPONSE_APPLY, NULL);
2465 gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(msgdialog),"%s","Do you want to continue?");
2466 gtk_window_set_title (GTK_WINDOW (msgdialog),
2467 _("Write Tag from CDDB"));
2468 response = gtk_dialog_run(GTK_DIALOG(msgdialog));
2469 gtk_widget_destroy(msgdialog);
2470
2471 if (response != GTK_RESPONSE_APPLY)
2472 {
2473 g_list_free_full (file_iterlist, (GDestroyNotify)g_free);
2474 //gdk_window_raise(CddbWindow->window);
2475 return FALSE;
2476 }
2477 }
2478
2479 file_iterlist = g_list_reverse (file_iterlist);
2480 //ET_Debug_Print_File_List (NULL, __FILE__, __LINE__, __FUNCTION__);
2481
2482 for (row=0; row < rows_to_loop; row++)
2483 {
2484 if (CddbTrackList_Line_Selected == FALSE)
2485 {
2486 if(row == 0)
2487 currentPath = gtk_tree_path_new_first();
2488 else
2489 gtk_tree_path_next(currentPath);
2490 } else /* (e.g.: if CddbTrackList_Line_Selected == TRUE) */
2491 {
2492 if(row == 0)
2493 {
2494 currentPath = (GtkTreePath *)selectedrows->data;
2495 } else
2496 {
2497 selectedrows = g_list_next(selectedrows);
2498 currentPath = (GtkTreePath *)selectedrows->data;
2499 }
2500 }
2501
2502 if (gtk_tree_model_get_iter (GTK_TREE_MODEL (priv->track_list_model),
2503 ¤tIter, currentPath))
2504 {
2505 gtk_tree_model_get (GTK_TREE_MODEL (priv->track_list_model),
2506 ¤tIter, CDDB_TRACK_LIST_DATA,
2507 &cddbtrackalbum, -1);
2508 }
2509 else
2510 {
2511 g_warning ("Iter not found matching path in CDDB track list model");
2512 }
2513
2514 /* Set values in the ETFile. */
2515 if (g_settings_get_boolean (MainSettings, "cddb-dlm-enabled"))
2516 {
2517 ET_File *etfile = NULL;
2518 guint set_fields;
2519
2520 gtk_tree_model_get (GTK_TREE_MODEL (priv->track_list_model),
2521 ¤tIter, CDDB_TRACK_LIST_ETFILE, &etfile,
2522 -1);
2523
2524 /* If the row in the model does not already have an ET_File
2525 * associated with it, take one from the browser selection. */
2526 if (!etfile)
2527 {
2528 fileIter = (GtkTreeIter*) file_iterlist->data;
2529 etfile = et_application_window_browser_get_et_file_from_iter (ET_APPLICATION_WINDOW (MainWindow),
2530 fileIter);
2531 }
2532
2533 /* Tag fields. */
2534 set_fields = g_settings_get_flags (MainSettings, "cddb-set-fields");
2535
2536 set_et_file_from_cddb_album (etfile, cddbtrackalbum, set_fields,
2537 list_length);
2538 }
2539 else if (cddbtrackalbum)
2540 {
2541 ET_File *etfile;
2542 guint set_fields;
2543
2544 fileIter = (GtkTreeIter*) file_iterlist->data;
2545 etfile = et_application_window_browser_get_et_file_from_iter (ET_APPLICATION_WINDOW (MainWindow),
2546 fileIter);
2547
2548 /* Tag fields. */
2549 set_fields = g_settings_get_flags (MainSettings, "cddb-set-fields");
2550
2551 set_et_file_from_cddb_album (etfile, cddbtrackalbum, set_fields,
2552 list_length);
2553 }
2554
2555 if(!file_iterlist->next) break;
2556 file_iterlist = file_iterlist->next;
2557 }
2558
2559 g_list_free_full (g_list_first (file_iterlist), (GDestroyNotify)g_free);
2560 g_list_free_full (g_list_first (selectedrows),
2561 (GDestroyNotify)gtk_tree_path_free);
2562
2563 et_application_window_browser_refresh_list (ET_APPLICATION_WINDOW (MainWindow));
2564 et_application_window_display_et_file (ET_APPLICATION_WINDOW (MainWindow),
2565 ETCore->ETFileDisplayed);
2566
2567 return TRUE;
2568 }
2569
2570 static void
stop_search(EtCDDBDialog * self)2571 stop_search (EtCDDBDialog *self)
2572 {
2573 EtCDDBDialogPrivate *priv;
2574
2575 priv = et_cddb_dialog_get_instance_private (self);
2576
2577 priv->stop_searching = TRUE;
2578 }
2579
2580 /*
2581 * Unselect all rows in the track list
2582 */
2583 static void
track_list_unselect_all(EtCDDBDialog * self)2584 track_list_unselect_all (EtCDDBDialog *self)
2585 {
2586 EtCDDBDialogPrivate *priv;
2587 GtkTreeSelection *selection;
2588
2589 priv = et_cddb_dialog_get_instance_private (self);
2590
2591 g_return_if_fail (priv->track_list_view != NULL);
2592
2593 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->track_list_view));
2594 if (selection)
2595 {
2596 gtk_tree_selection_unselect_all (selection);
2597 }
2598 }
2599
2600 /*
2601 * Select all rows in the track list
2602 */
2603 static void
track_list_select_all(EtCDDBDialog * self)2604 track_list_select_all (EtCDDBDialog *self)
2605 {
2606 EtCDDBDialogPrivate *priv;
2607 GtkTreeSelection *selection;
2608
2609 priv = et_cddb_dialog_get_instance_private (self);
2610
2611 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->track_list_view));
2612
2613 if (selection)
2614 {
2615 gtk_tree_selection_select_all (selection);
2616 }
2617 }
2618
2619 static gboolean
on_track_list_button_press_event(EtCDDBDialog * self,GdkEventButton * event,GtkTreeView * track_list_view)2620 on_track_list_button_press_event (EtCDDBDialog *self,
2621 GdkEventButton *event,
2622 GtkTreeView *track_list_view)
2623 {
2624 if (event->type == GDK_2BUTTON_PRESS
2625 && event->button == GDK_BUTTON_PRIMARY)
2626 {
2627 GdkWindow *bin_window;
2628
2629 bin_window = gtk_tree_view_get_bin_window (track_list_view);
2630
2631 if (bin_window != event->window)
2632 {
2633 /* Ignore the event if it is on the header (which is not the bin
2634 * window. */
2635 return GDK_EVENT_PROPAGATE;
2636 }
2637
2638 /* Double left mouse click */
2639 track_list_select_all (self);
2640
2641 return GDK_EVENT_STOP;
2642 }
2643
2644 return GDK_EVENT_PROPAGATE;
2645 }
2646
2647 static void
et_cddb_dialog_on_response(EtCDDBDialog * self,gint response_id,gpointer user_data)2648 et_cddb_dialog_on_response (EtCDDBDialog *self,
2649 gint response_id,
2650 gpointer user_data)
2651 {
2652 switch (response_id)
2653 {
2654 case GTK_RESPONSE_CLOSE:
2655 gtk_widget_hide (GTK_WIDGET (self));
2656 break;
2657 case GTK_RESPONSE_DELETE_EVENT:
2658 break;
2659 default:
2660 g_assert_not_reached ();
2661 break;
2662 }
2663 }
2664
2665 static void
Cddb_Destroy_Window(EtCDDBDialog * self)2666 Cddb_Destroy_Window (EtCDDBDialog *self)
2667 {
2668 et_cddb_dialog_on_response (self, GTK_RESPONSE_CLOSE, NULL);
2669 }
2670
2671 static void
init_search_field_check(GtkWidget * widget)2672 init_search_field_check (GtkWidget *widget)
2673 {
2674 g_object_set_data (G_OBJECT (widget), "flags-type",
2675 GSIZE_TO_POINTER (ET_TYPE_CDDB_SEARCH_FIELD));
2676 g_object_set_data (G_OBJECT (widget), "flags-key",
2677 (gpointer) "cddb-search-fields");
2678 g_settings_bind_with_mapping (MainSettings, "cddb-search-fields", widget,
2679 "active", G_SETTINGS_BIND_DEFAULT,
2680 et_settings_flags_toggle_get,
2681 et_settings_flags_toggle_set, widget, NULL);
2682 }
2683 static void
init_search_category_check(GtkWidget * widget)2684 init_search_category_check (GtkWidget *widget)
2685 {
2686 g_object_set_data (G_OBJECT (widget), "flags-type",
2687 GSIZE_TO_POINTER (ET_TYPE_CDDB_SEARCH_CATEGORY));
2688 g_object_set_data (G_OBJECT (widget), "flags-key",
2689 (gpointer) "cddb-search-categories");
2690 g_settings_bind_with_mapping (MainSettings, "cddb-search-categories",
2691 widget, "active", G_SETTINGS_BIND_DEFAULT,
2692 et_settings_flags_toggle_get,
2693 et_settings_flags_toggle_set, widget, NULL);
2694 }
2695
2696 static void
init_set_field_check(GtkWidget * widget)2697 init_set_field_check (GtkWidget *widget)
2698 {
2699 g_object_set_data (G_OBJECT (widget), "flags-type",
2700 GSIZE_TO_POINTER (ET_TYPE_CDDB_SET_FIELD));
2701 g_object_set_data (G_OBJECT (widget), "flags-key",
2702 (gpointer) "cddb-set-fields");
2703 g_settings_bind_with_mapping (MainSettings, "cddb-set-fields", widget,
2704 "active", G_SETTINGS_BIND_DEFAULT,
2705 et_settings_flags_toggle_get,
2706 et_settings_flags_toggle_set, widget, NULL);
2707 }
2708
2709 static void
create_cddb_dialog(EtCDDBDialog * self)2710 create_cddb_dialog (EtCDDBDialog *self)
2711 {
2712 EtCDDBDialogPrivate *priv;
2713 GtkTreePath *path;
2714
2715 priv = et_cddb_dialog_get_instance_private (self);
2716
2717 /* Button to generate CddbId and request string from the selected files. */
2718 gtk_widget_grab_default (priv->automatic_search_button);
2719
2720 /* Set content of the clipboard if available. */
2721 gtk_editable_paste_clipboard (GTK_EDITABLE (priv->search_entry));
2722
2723 /* Button to run the search. */
2724 gtk_widget_grab_default (priv->manual_search_button);
2725
2726 /* Search options. */
2727 init_search_field_check (priv->artist_check);
2728 init_search_field_check (priv->album_check);
2729 init_search_field_check (priv->track_check);
2730 init_search_field_check (priv->other_check);
2731
2732 init_search_category_check (priv->blues_check);
2733 init_search_category_check (priv->classical_check);
2734 init_search_category_check (priv->country_check);
2735 init_search_category_check (priv->folk_check);
2736 init_search_category_check (priv->jazz_check);
2737 init_search_category_check (priv->misc_check);
2738 init_search_category_check (priv->newage_check);
2739 init_search_category_check (priv->reggae_check);
2740 init_search_category_check (priv->rock_check);
2741 init_search_category_check (priv->soundtrack_check);
2742
2743 /* Result of search. */
2744 /* List of albums. */
2745 path = gtk_tree_path_new_first ();
2746 gtk_tree_view_set_cursor (GTK_TREE_VIEW (priv->album_list_view), path, NULL,
2747 FALSE);
2748 gtk_tree_path_free (path);
2749
2750 /* List of tracks. */
2751 gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (priv->track_list_model),
2752 SORT_LIST_NUMBER,
2753 Cddb_Track_List_Sort_Func,
2754 GINT_TO_POINTER (SORT_LIST_NUMBER), NULL);
2755 gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (priv->track_list_model),
2756 SORT_LIST_NAME, Cddb_Track_List_Sort_Func,
2757 GINT_TO_POINTER (SORT_LIST_NAME), NULL);
2758
2759 /* Apply results to fields. */
2760 init_set_field_check (priv->filename_check);
2761 init_set_field_check (priv->title_check);
2762 init_set_field_check (priv->fill_artist_check);
2763 init_set_field_check (priv->fill_album_check);
2764 init_set_field_check (priv->year_check);
2765 init_set_field_check (priv->fill_track_check);
2766 init_set_field_check (priv->track_total_check);
2767 init_set_field_check (priv->genre_check);
2768
2769 /* Check box to run the scanner. */
2770 g_settings_bind (MainSettings, "cddb-run-scanner",
2771 priv->scanner_check, "active",
2772 G_SETTINGS_BIND_DEFAULT);
2773
2774 /* Check box to use DLM (also used in the preferences window). */
2775 g_settings_bind (MainSettings, "cddb-dlm-enabled", priv->dlm_check,
2776 "active", G_SETTINGS_BIND_DEFAULT);
2777
2778 /* Status bar. */
2779 priv->status_bar_context = gtk_statusbar_get_context_id (GTK_STATUSBAR (priv->status_bar),
2780 "Messages");
2781 gtk_statusbar_push (GTK_STATUSBAR (priv->status_bar),
2782 priv->status_bar_context, _("Ready to search"));
2783
2784 g_signal_emit_by_name (priv->search_entry, "changed");
2785 priv->stop_searching = FALSE;
2786 }
2787
2788 /*
2789 * Sort the track list
2790 */
2791 static gint
Cddb_Track_List_Sort_Func(GtkTreeModel * model,GtkTreeIter * a,GtkTreeIter * b,gpointer data)2792 Cddb_Track_List_Sort_Func (GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b,
2793 gpointer data)
2794 {
2795 gint sortcol = GPOINTER_TO_INT(data);
2796 gchar *text1, *text1cp;
2797 gchar *text2, *text2cp;
2798 gint num1;
2799 gint num2;
2800 gint ret = 0;
2801
2802 switch (sortcol)
2803 {
2804 case SORT_LIST_NUMBER:
2805 gtk_tree_model_get(model, a, CDDB_TRACK_LIST_NUMBER, &num1, -1);
2806 gtk_tree_model_get(model, b, CDDB_TRACK_LIST_NUMBER, &num2, -1);
2807 if (num1 < num2)
2808 return -1;
2809 else if(num1 > num2)
2810 return 1;
2811 else
2812 return 0;
2813 break;
2814
2815 case SORT_LIST_NAME:
2816 gtk_tree_model_get(model, a, CDDB_TRACK_LIST_NAME, &text1, -1);
2817 gtk_tree_model_get(model, b, CDDB_TRACK_LIST_NAME, &text2, -1);
2818 text1cp = g_utf8_collate_key_for_filename(text1, -1);
2819 text2cp = g_utf8_collate_key_for_filename(text2, -1);
2820 // Must be the same rules as "ET_Comp_Func_Sort_File_By_Ascending_Filename" to be
2821 // able to sort in the same order files in cddb and in the file list.
2822 ret = g_settings_get_boolean (MainSettings,
2823 "sort-case-sensitive") ? strcmp (text1cp, text2cp)
2824 : strcasecmp (text1cp, text2cp);
2825
2826 g_free(text1);
2827 g_free(text2);
2828 g_free(text1cp);
2829 g_free(text2cp);
2830 break;
2831 default:
2832 g_assert_not_reached ();
2833 break;
2834 }
2835
2836 return ret;
2837 }
2838
2839 /*
2840 * Read one line (of the connection) into cddb_out.
2841 * return : -1 on error
2842 * 0 if no more line to read (EOF)
2843 * 1 if more lines to read
2844 *
2845 * Server answser is formated like this :
2846 *
2847 * HTTP/1.1 200 OK\r\n }
2848 * Server: Apache/1.3.19 (Unix) PHP/4.0.4pl1\r\n } "Header"
2849 * Connection: close\r\n }
2850 * \r\n
2851 * <html>\n }
2852 * [...] } "Body"
2853 */
2854 static gint
Cddb_Read_Line(FILE ** file,gchar ** cddb_out)2855 Cddb_Read_Line (FILE **file, gchar **cddb_out)
2856 {
2857 gchar buffer[MAX_STRING_LEN];
2858 gchar *result;
2859 size_t l;
2860
2861 if (*file == NULL)
2862 {
2863 // Open the file for reading the first time
2864 gchar *file_path;
2865
2866 file_path = g_build_filename (g_get_user_cache_dir (), PACKAGE_TARNAME,
2867 CDDB_RESULT_FILE, NULL);
2868
2869 if ((*file = g_fopen (file_path, "r")) == 0)
2870 {
2871 Log_Print (LOG_ERROR, _("Cannot open file ‘%s’: %s"), file_path,
2872 g_strerror (errno));
2873 g_free (file_path);
2874 return -1; // Error!
2875 }
2876 g_free (file_path);
2877 }
2878
2879 result = fgets(buffer,sizeof(buffer),*file);
2880 if (result != NULL)
2881 {
2882 l = strlen(buffer);
2883 if (l > 0 && buffer[l-1] == '\n')
2884 buffer[l-1] = '\0';
2885
2886 // Many '\r' chars may be present
2887 while ((l = strlen(buffer)) > 0 && buffer[l-1] == '\r')
2888 buffer[l-1] = '\0';
2889
2890 *cddb_out = g_strdup(buffer);
2891 }else
2892 {
2893 // On error, or EOF
2894 fclose(*file);
2895 *file = NULL;
2896
2897 //*cddb_out = NULL;
2898 *cddb_out = g_strdup(""); // To avoid a crash
2899
2900 return 0;
2901 }
2902
2903 //g_print("Line read: %s\n",*cddb_out);
2904 return 1;
2905 }
2906
2907
2908 /*
2909 * Read HTTP header data : from "HTTP/1.1 200 OK" to the blank line
2910 */
2911 static gint
Cddb_Read_Http_Header(FILE ** file,gchar ** cddb_out)2912 Cddb_Read_Http_Header (FILE **file, gchar **cddb_out)
2913 {
2914
2915 // The 'file' is opened (if no error) in this function
2916 if ( Cddb_Read_Line(file,cddb_out) < 0 )
2917 return -1; // Error!
2918
2919 // First line must be : "HTTP/1.1 200 OK"
2920 if ( !*cddb_out || strncmp("HTTP",*cddb_out,4)!=0 || strstr(*cddb_out,"200 OK")==NULL )
2921 return -1;
2922
2923 /* Read until end of the HTTP header up to the next blank line. */
2924 do
2925 {
2926 g_free (*cddb_out);
2927 }
2928 while (Cddb_Read_Line (file, cddb_out) > 0 && !et_str_empty (*cddb_out));
2929
2930 //g_print("Http Header : %s\n",*cddb_out);
2931 return 1;
2932 }
2933
2934 /*
2935 * Read CDDB header data when requesting a file (cmd=cddb+read+<album genre>+<discid>)
2936 * Must be read after the HTTP header :
2937 *
2938 * HTTP/1.1 200 OK
2939 * Date: Sun, 26 Nov 2006 22:37:13 GMT
2940 * Server: Apache/2.0.54 (Debian GNU/Linux) mod_python/3.1.3 Python/2.3.5 PHP/4.3.10-16 proxy_html/2.4 mod_perl/1.999.21 Perl/v5.8.4
2941 * Expires: Sun Nov 26 23:37:14 2006
2942 * Content-Length: 1013
2943 * Connection: close
2944 * Content-Type: text/plain; charset=UTF-8
2945 *
2946 * 210 newage 710ed208 CD database entry follows (until terminating `.')
2947 *
2948 * Cddb Header is the line like this :
2949 * 210 newage 710ed208 CD database entry follows (until terminating `.')
2950 */
2951 static gint
Cddb_Read_Cddb_Header(FILE ** file,gchar ** cddb_out)2952 Cddb_Read_Cddb_Header (FILE **file, gchar **cddb_out)
2953 {
2954 if ( Cddb_Read_Line(file,cddb_out) < 0 )
2955 return -1; // Error!
2956
2957 /* Some requests receive some strange data (arbitrary: less than 10 chars.)
2958 * at the beginning (2 or 3 characters)... So we read one line more... */
2959 if (!*cddb_out || strlen (*cddb_out) < 10)
2960 {
2961 g_free (*cddb_out);
2962
2963 if (Cddb_Read_Line (file, cddb_out) < 0)
2964 {
2965 return -1; /* Error! */
2966 }
2967 }
2968
2969 //g_print("Cddb Header : %s\n",*cddb_out);
2970
2971 // Read the line
2972 // 200 - exact match
2973 // 210 - multiple exact matches
2974 // 211 - inexact match
2975 if ( *cddb_out == NULL
2976 || (strncmp(*cddb_out,"200",3)!=0
2977 && strncmp(*cddb_out,"210",3)!=0
2978 && strncmp(*cddb_out,"211",3)!=0) )
2979 return -1;
2980
2981 return 1;
2982 }
2983
2984
2985
2986 static gboolean
Cddb_Free_Track_Album_List(GList * track_list)2987 Cddb_Free_Track_Album_List (GList *track_list)
2988 {
2989 GList *l;
2990
2991 g_return_val_if_fail (track_list != NULL, FALSE);
2992
2993 track_list = g_list_first (track_list);
2994
2995 for (l = track_list; l != NULL; l = g_list_next (l))
2996 {
2997 CddbTrackAlbum *cddbtrackalbum = l->data;
2998
2999 if (cddbtrackalbum)
3000 {
3001 g_free(cddbtrackalbum->track_name);
3002 g_slice_free (CddbTrackAlbum, cddbtrackalbum);
3003 }
3004 }
3005
3006 g_list_free (track_list);
3007
3008 return TRUE;
3009 }
3010
3011 /*
3012 * Send cddb query using the CddbId generated from the selected files to get the
3013 * list of albums matching with this cddbid.
3014 */
3015 gboolean
et_cddb_dialog_search_from_selection(EtCDDBDialog * self)3016 et_cddb_dialog_search_from_selection (EtCDDBDialog *self)
3017 {
3018 EtCDDBDialogPrivate *priv;
3019 gint socket_id;
3020 gint bytes_written;
3021 gulong bytes_read_total = 0;
3022 FILE *file = NULL;
3023
3024 gchar *cddb_in = NULL; /* For the request to send. */
3025 gchar *cddb_out = NULL; /* Answer received */
3026 gchar *cddb_out_tmp;
3027 gchar *msg;
3028 gchar *proxy_auth;
3029 gchar *cddb_server_name;
3030 guint cddb_server_port;
3031 gchar *cddb_server_cgi_path;
3032 gboolean proxy_enabled;
3033 gchar *proxy_hostname;
3034 guint proxy_port;
3035 gint server_try = 0;
3036 GString *query_string;
3037 gchar *cddb_discid;
3038 const gchar CDDB_END_STR[] = ".";
3039
3040 guint total_frames = 150; /* First offset is (almost) always 150 */
3041 guint disc_length = 2; /* and 2s elapsed before first track */
3042
3043 GtkTreeSelection *file_selection = NULL;
3044 guint file_selectedcount = 0;
3045 GtkTreeIter currentIter;
3046 guint total_id;
3047 guint num_tracks;
3048
3049 gpointer iterptr;
3050
3051 GtkListStore *fileListModel;
3052 GtkTreeIter *fileIter;
3053 GList *file_iterlist = NULL;
3054 GList *l;
3055
3056 priv = et_cddb_dialog_get_instance_private (self);
3057
3058 /* Number of selected files. */
3059 /* FIXME: Hack! */
3060 file_selection = et_application_window_browser_get_selection (ET_APPLICATION_WINDOW (MainWindow));
3061 fileListModel = GTK_LIST_STORE (gtk_tree_view_get_model (gtk_tree_selection_get_tree_view (file_selection)));
3062 file_selectedcount = gtk_tree_selection_count_selected_rows(file_selection);
3063
3064 // Create the list 'file_iterlist' of selected files (no selected files => all files selected)
3065 if (file_selectedcount > 0)
3066 {
3067 GList* file_selectedrows = gtk_tree_selection_get_selected_rows(file_selection, NULL);
3068
3069 for (l = file_selectedrows; l != NULL; l = g_list_next (l))
3070 {
3071 iterptr = g_malloc0(sizeof(GtkTreeIter));
3072 if (gtk_tree_model_get_iter(GTK_TREE_MODEL(fileListModel),
3073 (GtkTreeIter*) iterptr,
3074 (GtkTreePath*) l->data))
3075 {
3076 file_iterlist = g_list_prepend (file_iterlist, iterptr);
3077 }
3078 }
3079 g_list_free_full (file_selectedrows,
3080 (GDestroyNotify)gtk_tree_path_free);
3081
3082 } else /* No rows selected, use the whole list */
3083 {
3084 gtk_tree_model_get_iter_first(GTK_TREE_MODEL(fileListModel), ¤tIter);
3085
3086 do
3087 {
3088 iterptr = g_memdup(¤tIter, sizeof(GtkTreeIter));
3089 file_iterlist = g_list_prepend (file_iterlist, iterptr);
3090 } while (gtk_tree_model_iter_next(GTK_TREE_MODEL(fileListModel), ¤tIter));
3091
3092 file_selectedcount = gtk_tree_model_iter_n_children(GTK_TREE_MODEL(fileListModel), NULL);
3093 }
3094
3095 if (file_selectedcount == 0)
3096 {
3097 msg = g_strdup_printf(_("No file selected"));
3098 gtk_statusbar_push(GTK_STATUSBAR(priv->status_bar),priv->status_bar_context,msg);
3099 g_free(msg);
3100 return TRUE;
3101 }else if (file_selectedcount > 99)
3102 {
3103 // The CD redbook standard defines the maximum number of tracks as 99, any
3104 // queries with more than 99 tracks will never return a result.
3105 msg = g_strdup_printf(_("More than 99 files selected. Cannot send request"));
3106 gtk_statusbar_push(GTK_STATUSBAR(priv->status_bar),priv->status_bar_context,msg);
3107 g_free(msg);
3108 return FALSE;
3109 }else
3110 {
3111 msg = g_strdup_printf (ngettext ("One file selected",
3112 "%u files selected",
3113 file_selectedcount),
3114 file_selectedcount);
3115 gtk_statusbar_push(GTK_STATUSBAR(priv->status_bar),priv->status_bar_context,msg);
3116 g_free(msg);
3117 }
3118
3119 // Generate query string and compute discid from the list 'file_iterlist'
3120 total_id = 0;
3121 num_tracks = file_selectedcount;
3122 query_string = g_string_new ("");
3123
3124 file_iterlist = g_list_reverse (file_iterlist);
3125
3126 for (l = file_iterlist; l != NULL; l = g_list_next (l))
3127 {
3128 ET_File *etfile;
3129 gulong secs = 0;
3130
3131 fileIter = (GtkTreeIter *)l->data;
3132 etfile = et_application_window_browser_get_et_file_from_iter (ET_APPLICATION_WINDOW (MainWindow),
3133 fileIter);
3134
3135 if (query_string->len > 0)
3136 {
3137 g_string_append_printf (query_string, "+%u", total_frames);
3138 }
3139 else
3140 {
3141 g_string_append_printf (query_string, "%u", total_frames);
3142 }
3143
3144 secs = etfile->ETFileInfo->duration;
3145 total_frames += secs * 75;
3146 disc_length += secs;
3147 while (secs > 0)
3148 {
3149 total_id = total_id + (secs % 10);
3150 secs = secs / 10;
3151 }
3152 }
3153
3154 g_list_free_full (file_iterlist, (GDestroyNotify)g_free);
3155
3156 /* Compute CddbId. */
3157 cddb_discid = g_strdup_printf ("%08x", (guint)(((total_id % 0xFF) << 24) |
3158 (disc_length << 8) | num_tracks));
3159
3160
3161 /* Delete previous album list. */
3162 cddb_album_model_clear (self);
3163 cddb_track_model_clear (self);
3164
3165 if (priv->album_list)
3166 {
3167 Cddb_Free_Album_List (self);
3168 }
3169 gtk_widget_set_sensitive(GTK_WIDGET(priv->stop_search_button),TRUE);
3170
3171
3172 {
3173 /*
3174 * Remote cddb acces
3175 *
3176 * Request the two servers
3177 * - 1) www.freedb.org
3178 * - 2) MusicBrainz Gateway : freedb.musicbrainz.org (in Easytag < 2.1.1, it was: www.mb.inhouse.co.uk)
3179 */
3180 while (server_try < 2)
3181 {
3182 server_try++;
3183 if (server_try == 1)
3184 {
3185 /* 1st try. */
3186 cddb_server_name = g_settings_get_string (MainSettings,
3187 "cddb-automatic-search-hostname");
3188 cddb_server_port = g_settings_get_uint (MainSettings,
3189 "cddb-automatic-search-port");
3190 cddb_server_cgi_path = g_settings_get_string (MainSettings,
3191 "cddb-automatic-search-path");
3192
3193 }
3194 else
3195 {
3196 /* 2nd try. */
3197 cddb_server_name = g_settings_get_string (MainSettings,
3198 "cddb-automatic-search-hostname2");
3199 cddb_server_port = g_settings_get_uint (MainSettings,
3200 "cddb-automatic-search-port");
3201 cddb_server_cgi_path = g_settings_get_string (MainSettings,
3202 "cddb-automatic-search-path2");
3203 }
3204
3205 // Check values
3206 if (!cddb_server_name || strcmp(cddb_server_name,"")==0)
3207 continue;
3208
3209 /* Connection to the server. */
3210 proxy_enabled = g_settings_get_boolean (MainSettings,
3211 "cddb-proxy-enabled");
3212 proxy_hostname = g_settings_get_string (MainSettings,
3213 "cddb-proxy-hostname");
3214 proxy_port = g_settings_get_uint (MainSettings, "cddb-proxy-port");
3215
3216 if ((socket_id = Cddb_Open_Connection (self,
3217 proxy_enabled
3218 ? proxy_hostname
3219 : cddb_server_name,
3220 proxy_enabled
3221 ? proxy_port
3222 : cddb_server_port)) <= 0)
3223 {
3224 g_free(cddb_in);
3225 g_free(cddb_server_name);
3226 g_free(cddb_server_cgi_path);
3227 g_free (proxy_hostname);
3228 g_string_free (query_string, TRUE);
3229 g_free (cddb_discid);
3230 return FALSE;
3231 }
3232
3233 // CDDB Request (ex: GET /~cddb/cddb.cgi?cmd=cddb+query+0800ac01+1++150+172&hello=noname+localhost+EasyTAG+0.31&proto=1 HTTP/1.1\r\nHost: freedb.freedb.org:80\r\nConnection: close)
3234 // Without proxy : "GET /~cddb/cddb.cgi?…" but doesn't work with a proxy.
3235 // With proxy : "GET http://freedb.freedb.org/~cddb/cddb.cgi?…"
3236 // proto=1 => ISO-8859-1 - proto=6 => UTF-8
3237 cddb_in = g_strdup_printf("GET %s%s%s?cmd=cddb+query+"
3238 "%s+"
3239 "%u+%s+"
3240 "%u"
3241 "&hello=noname+localhost+%s+%s"
3242 "&proto=6 HTTP/1.1\r\n"
3243 "Host: %s:%u\r\n"
3244 "%s"
3245 "Connection: close\r\n\r\n",
3246 proxy_enabled ? "http://" : "",
3247 proxy_enabled ? cddb_server_name : "",
3248 cddb_server_cgi_path,
3249 cddb_discid,
3250 num_tracks, query_string->str,
3251 disc_length,
3252 PACKAGE_NAME, PACKAGE_VERSION,
3253 cddb_server_name,cddb_server_port,
3254 (proxy_auth=Cddb_Format_Proxy_Authentification())
3255 );
3256 g_free (proxy_auth);
3257 //g_print("Request Cddb_Search_Album_From_Selected_Files : '%s'\n", cddb_in);
3258
3259 msg = g_strdup_printf (_("Sending request (disc ID: %s, #tracks: %u, Disc length: %u)…"),
3260 cddb_discid, num_tracks, disc_length);
3261 gtk_statusbar_push(GTK_STATUSBAR(priv->status_bar),priv->status_bar_context,msg);
3262 g_free(msg);
3263
3264 while (gtk_events_pending())
3265 gtk_main_iteration();
3266
3267 if ( (bytes_written=send(socket_id,cddb_in,strlen(cddb_in)+1,0)) < 0)
3268 {
3269 Log_Print (LOG_ERROR, _("Cannot send the request ‘%s’"),
3270 g_strerror (errno));
3271 Cddb_Close_Connection (self, socket_id);
3272 g_free (cddb_in);
3273 g_free (cddb_server_name);
3274 g_free (cddb_server_cgi_path);
3275 g_free (proxy_hostname);
3276 g_string_free (query_string, TRUE);
3277 g_free (cddb_discid);
3278 return FALSE;
3279 }
3280 g_free(cddb_in);
3281 cddb_in = NULL;
3282
3283
3284 /*
3285 * Read the answer
3286 */
3287 gtk_statusbar_push(GTK_STATUSBAR(priv->status_bar),priv->status_bar_context,_("Receiving data…"));
3288 while (gtk_events_pending())
3289 gtk_main_iteration();
3290
3291 /* Write result in a file. */
3292 if (Cddb_Write_Result_To_File (self, socket_id, &bytes_read_total) < 0)
3293 {
3294 msg = g_strdup(_("The server returned a bad response"));
3295 gtk_statusbar_push(GTK_STATUSBAR(priv->status_bar),priv->status_bar_context,msg);
3296 Log_Print(LOG_ERROR,"%s",msg);
3297 g_free(msg);
3298 g_free(cddb_server_name);
3299 g_free(cddb_server_cgi_path);
3300 g_free (proxy_hostname);
3301 g_string_free (query_string, TRUE);
3302 g_free (cddb_discid);
3303 gtk_widget_set_sensitive(GTK_WIDGET(priv->stop_search_button),FALSE);
3304 return FALSE;
3305 }
3306
3307 // Parse server answer : Check returned code in the first line
3308 file = NULL;
3309 if (Cddb_Read_Http_Header(&file,&cddb_out) <= 0 || !cddb_out) // Order is important!
3310 {
3311 msg = g_strdup_printf (_("The server returned a bad response ‘%s’"),
3312 cddb_out);
3313 gtk_statusbar_push(GTK_STATUSBAR(priv->status_bar),priv->status_bar_context,msg);
3314 Log_Print(LOG_ERROR,"%s",msg);
3315 g_free(msg);
3316 g_free(cddb_out);
3317 g_free(cddb_server_name);
3318 g_free(cddb_server_cgi_path);
3319 g_free (proxy_hostname);
3320 g_string_free (query_string, TRUE);
3321 g_free (cddb_discid);
3322 gtk_widget_set_sensitive(GTK_WIDGET(priv->stop_search_button),FALSE);
3323 if (file)
3324 fclose(file);
3325 return FALSE;
3326 }
3327 g_free(cddb_out);
3328
3329 /*
3330 * Format :
3331 * For Freedb, Gnudb, the lines to read are like :
3332 * 211 Found inexact matches, list follows (until terminating `.')
3333 * rock 8f0dc00b Archive / Noise
3334 * rock 7b0dd80b Archive / Noise
3335 * .
3336 * For MusicBrainz Cddb Gateway (see http://wiki.musicbrainz.org/CddbGateway), the lines to read are like :
3337 * 200 jazz 7e0a100a Pink Floyd / Dark Side of the Moon
3338 */
3339 while (!priv->stop_searching
3340 && Cddb_Read_Line (&file, &cddb_out) > 0)
3341 {
3342 cddb_out_tmp = cddb_out;
3343 //g_print("%s\n",cddb_out);
3344
3345 // To avoid the cddb lookups to hang (Patch from Paul Giordano)
3346 /* It appears that on some systems that cddb lookups continue to attempt
3347 * to get data from the socket even though the other system has completed
3348 * sending. The fix adds one check to the loops to see if the actual
3349 * end of data is in the last block read. In this case, the last line
3350 * will be a single '.'
3351 */
3352 if (cddb_out_tmp && strlen (cddb_out_tmp) <= 3
3353 && strstr (cddb_out_tmp, CDDB_END_STR) != NULL)
3354 {
3355 g_free (cddb_out);
3356 cddb_out = NULL;
3357 break;
3358 }
3359
3360 // Compatibility for the MusicBrainz CddbGateway
3361 if ( cddb_out_tmp && strlen(cddb_out_tmp)>3
3362 && (strncmp(cddb_out_tmp,"200",3)==0
3363 || strncmp(cddb_out_tmp,"210",3)==0
3364 || strncmp(cddb_out_tmp,"211",3)==0) )
3365 cddb_out_tmp = cddb_out_tmp + 4;
3366
3367 // Reading of lines with albums (skiping return code lines :
3368 // "211 Found inexact matches, list follows (until terminating `.')" )
3369 if (cddb_out != NULL && strstr(cddb_out_tmp,"/") != NULL)
3370 {
3371 gchar* ptr;
3372 CddbAlbum *cddbalbum;
3373
3374 cddbalbum = g_slice_new0 (CddbAlbum);
3375
3376 // Parameters of the server used
3377 cddbalbum->server_name = g_strdup(cddb_server_name);
3378 cddbalbum->server_port = cddb_server_port;
3379 cddbalbum->server_cgi_path = g_strdup(cddb_server_cgi_path);
3380 cddbalbum->bitmap = Cddb_Get_Pixbuf_From_Server_Name(cddbalbum->server_name);
3381
3382 // Get album category
3383 if ( (ptr = strstr(cddb_out_tmp, " ")) != NULL )
3384 {
3385 *ptr = 0;
3386 cddbalbum->category = Try_To_Validate_Utf8_String(cddb_out_tmp);
3387 *ptr = ' ';
3388 cddb_out_tmp = ptr + 1;
3389 }
3390
3391 // Get album ID
3392 if ( (ptr = strstr(cddb_out_tmp, " ")) != NULL )
3393 {
3394 *ptr = 0;
3395 cddbalbum->id = Try_To_Validate_Utf8_String(cddb_out_tmp);
3396 *ptr = ' ';
3397 cddb_out_tmp = ptr + 1;
3398 }
3399
3400 // Get album and artist names.
3401 cddbalbum->artist_album = Try_To_Validate_Utf8_String(cddb_out_tmp);
3402
3403 priv->album_list = g_list_append(priv->album_list,cddbalbum);
3404 }
3405
3406 g_free(cddb_out);
3407 }
3408 g_free (cddb_out);
3409 g_free(cddb_server_name);
3410 g_free(cddb_server_cgi_path);
3411 g_free (proxy_hostname);
3412
3413 /* Close file opened for reading lines. */
3414 if (file)
3415 {
3416 fclose(file);
3417 file = NULL;
3418 }
3419
3420 /* Close connection. */
3421 Cddb_Close_Connection (self, socket_id);
3422 }
3423 }
3424
3425 g_string_free (query_string, TRUE);
3426
3427 msg = g_strdup_printf (ngettext ("DiscID ‘%s’ gave one matching album",
3428 "DiscID ‘%s’ gave %u matching albums",
3429 g_list_length (priv->album_list)),
3430 cddb_discid, g_list_length (priv->album_list));
3431 gtk_statusbar_push(GTK_STATUSBAR(priv->status_bar),priv->status_bar_context,msg);
3432 g_free(msg);
3433
3434 g_free(cddb_discid);
3435
3436 gtk_widget_set_sensitive (GTK_WIDGET (priv->stop_search_button), FALSE);
3437
3438 /* Load the albums found in the list. */
3439 Cddb_Load_Album_List (self, FALSE);
3440
3441 return TRUE;
3442 }
3443
3444 /*
3445 * Returns the corresponding ID3 genre (the name, not the value)
3446 */
3447 static const gchar *
Cddb_Get_Id3_Genre_From_Cddb_Genre(const gchar * cddb_genre)3448 Cddb_Get_Id3_Genre_From_Cddb_Genre (const gchar *cddb_genre)
3449 {
3450 gsize i;
3451
3452 g_return_val_if_fail (cddb_genre != NULL, "");
3453
3454 for (i = 0; i <= CDDB_GENRE_MAX; i++)
3455 {
3456 if (g_ascii_strcasecmp (cddb_genre, cddb_genre_vs_id3_genre[i][0]) == 0)
3457 {
3458 return cddb_genre_vs_id3_genre[i][1];
3459 }
3460 }
3461
3462 return cddb_genre;
3463 }
3464
3465 /*
3466 * Returns the pixmap to display following the server name
3467 */
3468 static GdkPixbuf *
Cddb_Get_Pixbuf_From_Server_Name(const gchar * server_name)3469 Cddb_Get_Pixbuf_From_Server_Name (const gchar *server_name)
3470 {
3471 g_return_val_if_fail (server_name != NULL, NULL);
3472
3473 if (strstr (server_name, "freedb.org"))
3474 return gdk_pixbuf_new_from_resource ("/org/gnome/EasyTAG/images/freedb.png",
3475 NULL);
3476 else if (strstr(server_name,"gnudb.org"))
3477 return gdk_pixbuf_new_from_resource ("/org/gnome/EasyTAG/images/gnudb.png",
3478 NULL);
3479 else if (strstr(server_name,"musicbrainz.org"))
3480 return gdk_pixbuf_new_from_resource ("/org/gnome/EasyTAG/images/musicbrainz.png",
3481 NULL);
3482 else
3483 return NULL;
3484 }
3485
3486
3487 static gchar *
Cddb_Format_Proxy_Authentification(void)3488 Cddb_Format_Proxy_Authentification (void)
3489 {
3490 gchar *username;
3491 gchar *password;
3492 gchar *ret;
3493
3494 username = g_settings_get_string (MainSettings, "cddb-proxy-username");
3495 password = g_settings_get_string (MainSettings, "cddb-proxy-password");
3496
3497 if (g_settings_get_boolean (MainSettings, "cddb-proxy-enabled")
3498 && username && *username )
3499 {
3500 const gchar *tempstr;
3501 gchar *str_encoded;
3502
3503 tempstr = g_strconcat (username, ":", password, NULL);
3504 str_encoded = g_base64_encode((const guchar *)tempstr, strlen(tempstr));
3505
3506 ret = g_strdup_printf("Proxy-authorization: Basic %s\r\n", str_encoded);
3507 g_free (str_encoded);
3508 }
3509 else
3510 {
3511 ret = g_strdup ("");
3512 }
3513
3514 g_free (username);
3515 g_free (password);
3516
3517 return ret;
3518 }
3519
3520 static void
et_cddb_dialog_finalize(GObject * object)3521 et_cddb_dialog_finalize (GObject *object)
3522 {
3523 EtCDDBDialog *self;
3524 EtCDDBDialogPrivate *priv;
3525
3526 self = ET_CDDB_DIALOG (object);
3527 priv = et_cddb_dialog_get_instance_private (self);
3528
3529 if (priv->album_list)
3530 {
3531 Cddb_Free_Album_List (self);
3532 }
3533
3534 G_OBJECT_CLASS (et_cddb_dialog_parent_class)->finalize (object);
3535 }
3536
3537 static void
et_cddb_dialog_init(EtCDDBDialog * self)3538 et_cddb_dialog_init (EtCDDBDialog *self)
3539 {
3540 gtk_widget_init_template (GTK_WIDGET (self));
3541 create_cddb_dialog (self);
3542 }
3543
3544 static void
et_cddb_dialog_class_init(EtCDDBDialogClass * klass)3545 et_cddb_dialog_class_init (EtCDDBDialogClass *klass)
3546 {
3547 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
3548
3549 G_OBJECT_CLASS (klass)->finalize = et_cddb_dialog_finalize;
3550
3551 gtk_widget_class_set_template_from_resource (widget_class,
3552 "/org/gnome/EasyTAG/cddb_dialog.ui");
3553 gtk_widget_class_bind_template_child_private (widget_class, EtCDDBDialog,
3554 album_list_model);
3555 gtk_widget_class_bind_template_child_private (widget_class, EtCDDBDialog,
3556 album_list_view);
3557 gtk_widget_class_bind_template_child_private (widget_class, EtCDDBDialog,
3558 track_list_model);
3559 gtk_widget_class_bind_template_child_private (widget_class, EtCDDBDialog,
3560 track_list_view);
3561 gtk_widget_class_bind_template_child_private (widget_class, EtCDDBDialog,
3562 search_entry);
3563 gtk_widget_class_bind_template_child_private (widget_class, EtCDDBDialog,
3564 apply_button);
3565 gtk_widget_class_bind_template_child_private (widget_class, EtCDDBDialog,
3566 automatic_search_button);
3567 gtk_widget_class_bind_template_child_private (widget_class, EtCDDBDialog,
3568 manual_search_button);
3569 gtk_widget_class_bind_template_child_private (widget_class, EtCDDBDialog,
3570 stop_search_button);
3571 gtk_widget_class_bind_template_child_private (widget_class, EtCDDBDialog,
3572 status_bar);
3573 gtk_widget_class_bind_template_child_private (widget_class, EtCDDBDialog,
3574 artist_check);
3575 gtk_widget_class_bind_template_child_private (widget_class, EtCDDBDialog,
3576 album_check);
3577 gtk_widget_class_bind_template_child_private (widget_class, EtCDDBDialog,
3578 track_check);
3579 gtk_widget_class_bind_template_child_private (widget_class, EtCDDBDialog,
3580 other_check);
3581 gtk_widget_class_bind_template_child_private (widget_class, EtCDDBDialog,
3582 blues_check);
3583 gtk_widget_class_bind_template_child_private (widget_class, EtCDDBDialog,
3584 classical_check);
3585 gtk_widget_class_bind_template_child_private (widget_class, EtCDDBDialog,
3586 country_check);
3587 gtk_widget_class_bind_template_child_private (widget_class, EtCDDBDialog,
3588 folk_check);
3589 gtk_widget_class_bind_template_child_private (widget_class, EtCDDBDialog,
3590 jazz_check);
3591 gtk_widget_class_bind_template_child_private (widget_class, EtCDDBDialog,
3592 misc_check);
3593 gtk_widget_class_bind_template_child_private (widget_class, EtCDDBDialog,
3594 newage_check);
3595 gtk_widget_class_bind_template_child_private (widget_class, EtCDDBDialog,
3596 reggae_check);
3597 gtk_widget_class_bind_template_child_private (widget_class, EtCDDBDialog,
3598 rock_check);
3599 gtk_widget_class_bind_template_child_private (widget_class, EtCDDBDialog,
3600 soundtrack_check);
3601 gtk_widget_class_bind_template_child_private (widget_class, EtCDDBDialog,
3602 filename_check);
3603 gtk_widget_class_bind_template_child_private (widget_class, EtCDDBDialog,
3604 title_check);
3605 gtk_widget_class_bind_template_child_private (widget_class, EtCDDBDialog,
3606 fill_artist_check);
3607 gtk_widget_class_bind_template_child_private (widget_class, EtCDDBDialog,
3608 fill_album_check);
3609 gtk_widget_class_bind_template_child_private (widget_class, EtCDDBDialog,
3610 year_check);
3611 gtk_widget_class_bind_template_child_private (widget_class, EtCDDBDialog,
3612 fill_track_check);
3613 gtk_widget_class_bind_template_child_private (widget_class, EtCDDBDialog,
3614 track_total_check);
3615 gtk_widget_class_bind_template_child_private (widget_class, EtCDDBDialog,
3616 genre_check);
3617 gtk_widget_class_bind_template_child_private (widget_class, EtCDDBDialog,
3618 dlm_check);
3619 gtk_widget_class_bind_template_child_private (widget_class, EtCDDBDialog,
3620 scanner_check);
3621 gtk_widget_class_bind_template_callback (widget_class,
3622 et_cddb_dialog_on_response);
3623 gtk_widget_class_bind_template_callback (widget_class,
3624 et_cddb_dialog_search_from_selection);
3625 gtk_widget_class_bind_template_callback (widget_class,
3626 on_track_list_button_press_event);
3627 gtk_widget_class_bind_template_callback (widget_class, show_album_info);
3628 gtk_widget_class_bind_template_callback (widget_class, stop_search);
3629 gtk_widget_class_bind_template_callback (widget_class,
3630 track_list_select_all);
3631 gtk_widget_class_bind_template_callback (widget_class,
3632 track_list_unselect_all);
3633 gtk_widget_class_bind_template_callback (widget_class,
3634 update_apply_button_sensitivity);
3635 gtk_widget_class_bind_template_callback (widget_class,
3636 update_search_button_sensitivity);
3637 gtk_widget_class_bind_template_callback (widget_class,
3638 Cddb_Destroy_Window);
3639 gtk_widget_class_bind_template_callback (widget_class,
3640 Cddb_Get_Album_Tracks_List_CB);
3641 gtk_widget_class_bind_template_callback (widget_class,
3642 Cddb_Set_Track_Infos_To_File_List);
3643 gtk_widget_class_bind_template_callback (widget_class,
3644 Cddb_Search_Album_List_From_String);
3645 gtk_widget_class_bind_template_callback (widget_class,
3646 Cddb_Track_List_Invert_Selection);
3647 gtk_widget_class_bind_template_callback (widget_class,
3648 Cddb_Track_List_Row_Selected);
3649 }
3650
3651 /*
3652 * et_cddb_dialog_new:
3653 *
3654 * Create a new EtCDDBDialog instance.
3655 *
3656 * Returns: a new #EtCDDBDialog
3657 */
3658 EtCDDBDialog *
et_cddb_dialog_new(void)3659 et_cddb_dialog_new (void)
3660 {
3661 return g_object_new (ET_TYPE_CDDB_DIALOG, NULL);
3662 }
3663