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                                      &currentFile, (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                                     &currentFile, 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, &currentFile,
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                                                                  &currentFile);
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), &currentIter, (GtkTreePath*)selectedRows->data))
1315             gtk_tree_model_get(GTK_TREE_MODEL(priv->album_list_model), &currentIter,
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), &currentIter);
2440 
2441         do
2442         {
2443             counter++;
2444             iterptr = g_memdup(&currentIter, sizeof(GtkTreeIter));
2445             file_iterlist = g_list_prepend (file_iterlist, iterptr);
2446         } while (gtk_tree_model_iter_next(GTK_TREE_MODEL(fileListModel), &currentIter));
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                                      &currentIter, currentPath))
2504         {
2505             gtk_tree_model_get (GTK_TREE_MODEL (priv->track_list_model),
2506                                 &currentIter, 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                                 &currentIter, 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), &currentIter);
3085 
3086         do
3087         {
3088             iterptr = g_memdup(&currentIter, sizeof(GtkTreeIter));
3089             file_iterlist = g_list_prepend (file_iterlist, iterptr);
3090         } while (gtk_tree_model_iter_next(GTK_TREE_MODEL(fileListModel), &currentIter));
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