1 /* grip.c
2  *
3  * Copyright (c) 1998-2004  Mike Oliphant <grip@nostatic.org>
4  *
5  *   http://www.nostatic.org/grip
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License as
9  * published by the Free Software Foundation; either version 2 of the
10  * License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
20  * USA
21  */
22 
23 #include <pthread.h>
24 #include <config.h>
25 #include <fcntl.h>
26 #include <stdio.h>
27 #include <unistd.h>
28 #include <sys/param.h>
29 #include <sys/types.h>
30 #include <sys/wait.h>
31 #include <time.h>
32 #include <gdk/gdkx.h> /* GDK_DISPLAY() */
33 #include "grip.h"
34 #include "discdb.h"
35 #include "cdplay.h"
36 #include "discedit.h"
37 #include "rip.h"
38 #include "common.h"
39 #include "dialog.h"
40 #include "gripcfg.h"
41 #include "xpm.h"
42 #include "parsecfg.h"
43 #include "tray.h"
44 
45 static void ReallyDie(gint reply,gpointer data);
46 static void DoHelp(GtkWidget *widget,gpointer data);
47 static void MakeHelpPage(GripInfo *ginfo);
48 static void MakeAboutPage(GripGUI *uinfo);
49 static void MakeStyles(GripGUI *uinfo);
50 static void Homepage(GtkWidget *widget,gpointer data);
51 static void LoadImages(GripGUI *uinfo);
52 static void DoLoadConfig(GripInfo *ginfo);
53 void LoadProxyConfig(GripInfo *ginfo, char* proxy_env);
54 void DoSaveConfig(GripInfo *ginfo);
55 
56 #define BASE_CFG_ENTRIES \
57 {"grip_version",CFG_ENTRY_STRING,256,ginfo->version},\
58 {"cd_device",CFG_ENTRY_STRING,256,ginfo->cd_device},\
59 {"force_scsi",CFG_ENTRY_STRING,256,ginfo->force_scsi},\
60 {"ripexename",CFG_ENTRY_STRING,256,ginfo->ripexename},\
61 {"ripcmdline",CFG_ENTRY_STRING,256,ginfo->ripcmdline},\
62 {"wav_filter_cmd",CFG_ENTRY_STRING,256,ginfo->wav_filter_cmd},\
63 {"disc_filter_cmd",CFG_ENTRY_STRING,256,ginfo->disc_filter_cmd},\
64 {"mp3exename",CFG_ENTRY_STRING,256,ginfo->mp3exename},\
65 {"mp3cmdline",CFG_ENTRY_STRING,256,ginfo->mp3cmdline},\
66 {"dbserver",CFG_ENTRY_STRING,256,ginfo->dbserver.name},\
67 {"ripfileformat",CFG_ENTRY_STRING,256,ginfo->ripfileformat},\
68 {"ripfileformat_multi",CFG_ENTRY_STRING,256,ginfo->ripfileformat_multi},\
69 {"mp3fileformat",CFG_ENTRY_STRING,256,ginfo->mp3fileformat},\
70 {"mp3fileformat_multi",CFG_ENTRY_STRING,256,ginfo->mp3fileformat_multi},\
71 {"mp3extension",CFG_ENTRY_STRING,10,ginfo->mp3extension},\
72 {"m3ufileformat",CFG_ENTRY_STRING,256,ginfo->m3ufileformat},\
73 {"delete_wavs",CFG_ENTRY_BOOL,0,&ginfo->delete_wavs},\
74 {"add_m3u",CFG_ENTRY_BOOL,0,&ginfo->add_m3u},\
75 {"rel_m3u",CFG_ENTRY_BOOL,0,&ginfo->rel_m3u},\
76 {"add_to_db",CFG_ENTRY_BOOL,0,&ginfo->add_to_db},\
77 {"use_proxy",CFG_ENTRY_BOOL,0,&ginfo->use_proxy},\
78 {"proxy_name",CFG_ENTRY_STRING,256,ginfo->proxy_server.name},\
79 {"proxy_port",CFG_ENTRY_INT,0,&(ginfo->proxy_server.port)},\
80 {"proxy_user",CFG_ENTRY_STRING,80,ginfo->proxy_server.username},\
81 {"proxy_pswd",CFG_ENTRY_STRING,80,ginfo->proxy_server.pswd},\
82 {"cdupdate",CFG_ENTRY_STRING,256,ginfo->cdupdate},\
83 {"user_email",CFG_ENTRY_STRING,256,ginfo->user_email},\
84 {"ripnice",CFG_ENTRY_INT,0,&ginfo->ripnice},\
85 {"mp3nice",CFG_ENTRY_INT,0,&ginfo->mp3nice},\
86 {"mp3_filter_cmd",CFG_ENTRY_STRING,256,ginfo->mp3_filter_cmd},\
87 {"doid3",CFG_ENTRY_BOOL,0,&ginfo->doid3},\
88 {"doid3v2",CFG_ENTRY_BOOL,0,&ginfo->doid3v2},\
89 {"tag_mp3_only",CFG_ENTRY_BOOL,0,&ginfo->tag_mp3_only},\
90 {"id3_comment",CFG_ENTRY_STRING,30,ginfo->id3_comment},\
91 {"max_wavs",CFG_ENTRY_INT,0,&ginfo->max_wavs},\
92 {"auto_rip",CFG_ENTRY_BOOL,0,&ginfo->auto_rip},\
93 {"eject_after_rip",CFG_ENTRY_BOOL,0,&ginfo->eject_after_rip},\
94 {"eject_delay",CFG_ENTRY_INT,0,&ginfo->eject_delay},\
95 {"delayed_encoding",CFG_ENTRY_BOOL,0,&ginfo->delayed_encoding},\
96 {"delay_before_rip",CFG_ENTRY_BOOL,0,&ginfo->delay_before_rip},\
97 {"stop_between_tracks",CFG_ENTRY_BOOL,0,&ginfo->stop_between_tracks},\
98 {"beep_after_rip",CFG_ENTRY_BOOL,0,&ginfo->beep_after_rip},\
99 {"faulty_eject",CFG_ENTRY_BOOL,0,&ginfo->faulty_eject},\
100 {"poll_drive",CFG_ENTRY_BOOL,0,&ginfo->poll_drive},\
101 {"poll_interval",CFG_ENTRY_INT,0,&ginfo->poll_interval},\
102 {"use_proxy_env",CFG_ENTRY_BOOL,0,&ginfo->use_proxy_env},\
103 {"db_cgi",CFG_ENTRY_STRING,256,ginfo->dbserver.cgi_prog},\
104 {"cddb_submit_email",CFG_ENTRY_STRING,256,ginfo->discdb_submit_email},\
105 {"discdb_encoding",CFG_ENTRY_STRING,16,ginfo->discdb_encoding},\
106 {"id3_encoding",CFG_ENTRY_STRING,16,ginfo->id3_encoding},\
107 {"id3v2_encoding",CFG_ENTRY_STRING,16,ginfo->id3v2_encoding},\
108 {"db_use_freedb",CFG_ENTRY_BOOL,0,&ginfo->db_use_freedb},\
109 {"dbserver2",CFG_ENTRY_STRING,256,ginfo->dbserver2.name},\
110 {"db2_cgi",CFG_ENTRY_STRING,256,ginfo->dbserver2.cgi_prog},\
111 {"no_interrupt",CFG_ENTRY_BOOL,0,&ginfo->no_interrupt},\
112 {"stop_first",CFG_ENTRY_BOOL,0,&ginfo->stop_first},\
113 {"play_first",CFG_ENTRY_BOOL,0,&ginfo->play_first},\
114 {"play_on_insert",CFG_ENTRY_BOOL,0,&ginfo->play_on_insert},\
115 {"automatic_cddb",CFG_ENTRY_BOOL,0,&ginfo->automatic_discdb},\
116 {"automatic_reshuffle",CFG_ENTRY_BOOL,0,&ginfo->automatic_reshuffle},\
117 {"no_lower_case",CFG_ENTRY_BOOL,0,&ginfo->sprefs.no_lower_case},\
118 {"no_underscore",CFG_ENTRY_BOOL,0,&ginfo->sprefs.no_underscore},\
119 {"non_posix_m3u_directory_paths",CFG_ENTRY_BOOL,0,&ginfo->sprefs.non_posix_m3u_directory_paths},\
120 {"allow_high_bits",CFG_ENTRY_BOOL,0,&ginfo->sprefs.allow_high_bits},\
121 {"escape",CFG_ENTRY_BOOL,0,&ginfo->sprefs.escape},\
122 {"allow_these_chars",CFG_ENTRY_STRING,256,ginfo->sprefs.allow_these_chars},\
123 {"show_tray_icon",CFG_ENTRY_BOOL,0,&ginfo->show_tray_icon},\
124 {"num_cpu",CFG_ENTRY_INT,0,&ginfo->edit_num_cpu},\
125 {"kbits_per_sec",CFG_ENTRY_INT,0,&ginfo->kbits_per_sec},\
126 {"selected_encoder",CFG_ENTRY_INT,0,&ginfo->selected_encoder},\
127 {"selected_ripper",CFG_ENTRY_INT,0,&ginfo->selected_ripper},\
128 {"play_mode",CFG_ENTRY_INT,0,&ginfo->play_mode},\
129 {"playloop",CFG_ENTRY_BOOL,0,&ginfo->playloop},\
130 {"win_width",CFG_ENTRY_INT,0,&uinfo->win_width},\
131 {"win_height",CFG_ENTRY_INT,0,&uinfo->win_height},\
132 {"win_height_edit",CFG_ENTRY_INT,0,&uinfo->win_height_edit},\
133 {"win_width_min",CFG_ENTRY_INT,0,&uinfo->win_width_min},\
134 {"win_height_min",CFG_ENTRY_INT,0,&uinfo->win_height_min},\
135 {"vol_vis",CFG_ENTRY_BOOL,0,&uinfo->volvis},\
136 {"track_edit_vis",CFG_ENTRY_BOOL,0,&uinfo->track_edit_visible},\
137 {"track_prog_vis",CFG_ENTRY_BOOL,0,&uinfo->track_prog_visible},\
138 {"volume",CFG_ENTRY_INT,0,&ginfo->volume},\
139 {"execute_after_encode_cmd",CFG_ENTRY_STRING,256,ginfo->execute_after_encode_cmd},
140 
141 #define CDPAR_CFG_ENTRIES \
142 {"disable_paranoia",CFG_ENTRY_BOOL,0,&ginfo->disable_paranoia},\
143 {"disable_extra_paranoia",CFG_ENTRY_BOOL,0,&ginfo->disable_extra_paranoia},\
144 {"disable_scratch_detect",CFG_ENTRY_BOOL,0,&ginfo->disable_scratch_detect},\
145 {"disable_scratch_repair",CFG_ENTRY_BOOL,0,&ginfo->disable_scratch_repair},\
146 {"calc_gain",CFG_ENTRY_BOOL,0,&ginfo->calc_gain},
147 
148 #ifdef CDPAR
149 #define CFG_ENTRIES BASE_CFG_ENTRIES CDPAR_CFG_ENTRIES
150 #else
151 #define CFG_ENTRIES BASE_CFG_ENTRIES
152 #endif
153 
AppWindowStateCB(GtkWidget * widget,GdkEventWindowState * event,gpointer data)154 gboolean AppWindowStateCB(GtkWidget *widget, GdkEventWindowState *event, gpointer data)
155 {
156   GripInfo *ginfo = (GripInfo*)data;
157   GripGUI *uinfo = &(ginfo->gui_info);
158   GdkWindowState state = event->new_window_state;
159 
160   if ((state & GDK_WINDOW_STATE_WITHDRAWN) || (state & GDK_WINDOW_STATE_ICONIFIED)) {
161     ginfo->app_visible = FALSE;
162     return TRUE;
163   } else {
164     ginfo->app_visible = TRUE;
165     gtk_window_get_position(GTK_WINDOW(uinfo->app), &uinfo->x, &uinfo->y);
166     return TRUE;
167   }
168 
169   return FALSE;
170 }
171 
GripNew(char * device,char * scsi_device,char * config_filename,gboolean force_small,gboolean local_mode,gboolean no_redirect)172 GtkWidget *GripNew(char *device,char *scsi_device,
173 		   char *config_filename,
174 		   gboolean force_small,
175 		   gboolean local_mode,gboolean no_redirect)
176 {
177   GtkWidget *app;
178   GripInfo *ginfo;
179   GripGUI *uinfo;
180   int major,minor,point;
181   char buf[256];
182   GList icon_list = {NULL, NULL, NULL};
183 
184   icon_list.data=gdk_pixbuf_new_from_file(GNOME_ICONDIR"/grip.png", NULL);
185   gtk_window_set_default_icon_list(&icon_list);
186 
187   app = gtk_window_new(GTK_WINDOW_TOPLEVEL);
188   gtk_window_set_title(GTK_WINDOW(app), _("Grip"));
189   gtk_window_set_screen(GTK_WINDOW(app), gdk_screen_get_default());
190 
191   ginfo=g_new0(GripInfo,1);
192 
193   gtk_object_set_user_data(GTK_OBJECT(app),(gpointer)ginfo);
194 
195   uinfo=&(ginfo->gui_info);
196   uinfo->app=app;
197   uinfo->track_list=NULL;
198 
199   uinfo->win_width=WINWIDTH;
200   uinfo->win_height=WINHEIGHT;
201   uinfo->win_height_edit=WINHEIGHTEDIT;
202   uinfo->win_width_min=MIN_WINWIDTH;
203   uinfo->win_height_min=MIN_WINHEIGHT;
204 
205   if(config_filename && *config_filename)
206     g_snprintf(ginfo->config_filename,256,"%s",config_filename);
207   else {
208     strcpy(ginfo->config_filename,".grip");
209   }
210 
211   Debug("Using config file [%s]\n",ginfo->config_filename);
212 
213   DoLoadConfig(ginfo);
214 
215   if(device) g_snprintf(ginfo->cd_device,256,"%s",device);
216   if(scsi_device) g_snprintf(ginfo->force_scsi,256,"%s",scsi_device);
217 
218   uinfo->minimized=force_small;
219   ginfo->local_mode=local_mode;
220   ginfo->do_redirect=!no_redirect;
221 
222   if(!CDInitDevice(ginfo->cd_device,&(ginfo->disc))) {
223     sprintf(buf,_("Error: Unable to initialize [%s]\n"),ginfo->cd_device);
224 
225     DisplayMsg(GTK_MESSAGE_INFO, NULL, buf);
226   }
227 
228   CDStat(&(ginfo->disc),TRUE);
229 
230   gtk_window_set_policy(GTK_WINDOW(app),FALSE,TRUE,FALSE);
231   gtk_window_set_wmclass(GTK_WINDOW(app),"grip","Grip");
232   g_signal_connect(G_OBJECT(app),"delete_event",
233 		   G_CALLBACK(GripDie),NULL);
234 
235   if(uinfo->minimized) {
236     gtk_widget_set_size_request(GTK_WIDGET(app),MIN_WINWIDTH,
237                                 MIN_WINHEIGHT);
238 
239     gtk_window_resize(GTK_WINDOW(app),uinfo->win_width_min,
240                                 uinfo->win_height_min);
241   }
242   else {
243     gtk_widget_set_size_request(GTK_WIDGET(app),WINWIDTH,
244                                 WINHEIGHT);
245 
246     if(uinfo->track_edit_visible) {
247       gtk_window_resize(GTK_WINDOW(app),uinfo->win_width,
248                         uinfo->win_height_edit);
249     }
250     else {
251       gtk_window_resize(GTK_WINDOW(app),uinfo->win_width,
252                         uinfo->win_height);
253     }
254   }
255 
256   gtk_widget_realize(app);
257 
258   uinfo->winbox=gtk_vbox_new(FALSE,3);
259   if(!uinfo->minimized)
260     gtk_container_border_width(GTK_CONTAINER(uinfo->winbox),3);
261 
262   uinfo->notebook=gtk_notebook_new();
263 
264   LoadImages(uinfo);
265   MakeStyles(uinfo);
266   MakeTrackPage(ginfo);
267   MakeRipPage(ginfo);
268   MakeConfigPage(ginfo);
269   MakeHelpPage(ginfo);
270   MakeAboutPage(uinfo);
271   ginfo->tray_icon_made = FALSE;
272   ginfo->tray_menu_sensitive = TRUE;
273 
274   gtk_box_pack_start(GTK_BOX(uinfo->winbox),uinfo->notebook,TRUE,TRUE,0);
275   if(!uinfo->minimized) gtk_widget_show(uinfo->notebook);
276 
277   uinfo->track_edit_box=MakeEditBox(ginfo);
278   gtk_box_pack_start(GTK_BOX(uinfo->winbox),uinfo->track_edit_box,
279 		     FALSE,FALSE,0);
280   if(uinfo->track_edit_visible) gtk_widget_show(uinfo->track_edit_box);
281 
282 
283   uinfo->playopts=MakePlayOpts(ginfo);
284   gtk_box_pack_start(GTK_BOX(uinfo->winbox),uinfo->playopts,FALSE,FALSE,0);
285   if(uinfo->track_prog_visible) gtk_widget_show(uinfo->playopts);
286 
287   uinfo->controls=MakeControls(ginfo);
288   if(uinfo->minimized)
289     gtk_box_pack_start(GTK_BOX(uinfo->winbox),uinfo->controls,TRUE,TRUE,0);
290   else
291     gtk_box_pack_start(GTK_BOX(uinfo->winbox),uinfo->controls,FALSE,FALSE,0);
292   gtk_widget_show(uinfo->controls);
293 
294   gtk_container_add(GTK_CONTAINER(app), uinfo->winbox);
295   gtk_widget_show(uinfo->winbox);
296   gtk_widget_show(app);
297 
298   CheckNewDisc(ginfo,FALSE);
299 
300   /* Check if we're running this version for the first time */
301   if(strcmp(VERSION,ginfo->version)!=0) {
302     strcpy(ginfo->version,VERSION);
303 
304     sscanf(VERSION,"%d.%d.%d",&major,&minor,&point);
305 
306     /* Check if we have a dev release */
307     /*if(minor%2) {
308       DisplayMsg(GTK_MESSAGE_WARNING, (GtkWindow *)ginfo->gui_info.app,
309                  _("This is a development version of Grip. If you encounter problems, you are encouraged to revert to the latest stable version."));
310     }*/
311   }
312 
313   g_signal_connect(app, "window-state-event", G_CALLBACK(AppWindowStateCB), ginfo);
314 
315   return app;
316 }
317 
GripDie(GtkWidget * widget,gpointer data)318 void GripDie(GtkWidget *widget,gpointer data)
319 {
320   GripInfo *ginfo;
321 
322   ginfo=(GripInfo *)gtk_object_get_user_data(GTK_OBJECT(widget));
323 
324   if(ginfo->ripping_a_disc || ginfo->encoding)
325     ReallyDie(ConfirmDialog ((GtkWindow *)ginfo->gui_info.app,
326                              _("Work is in progress.\nReally shut down?")),
327               ginfo);
328   else
329     ReallyDie(0,ginfo);
330 }
331 
ReallyDie(gint reply,gpointer data)332 static void ReallyDie(gint reply,gpointer data)
333 {
334   GripInfo *ginfo;
335 
336   if(reply) return;
337 
338   ginfo=(GripInfo *)data;
339 
340   if(ginfo->ripping_a_disc) KillRip(NULL,ginfo);
341   if(ginfo->encoding) KillEncode(NULL,ginfo);
342 
343   if(!ginfo->no_interrupt)
344     CDStop(&(ginfo->disc));
345 
346   DoSaveConfig(ginfo);
347 
348   gtk_main_quit();
349 }
350 
MakeNewPage(GtkWidget * notebook,char * name)351 GtkWidget *MakeNewPage(GtkWidget *notebook,char *name)
352 {
353   GtkWidget *page;
354   GtkWidget *label;
355 
356   page=gtk_frame_new(NULL);
357   gtk_widget_show(page);
358 
359   label=gtk_label_new(name);
360   gtk_notebook_append_page(GTK_NOTEBOOK(notebook),page,label);
361 
362   return page;
363 }
364 
DoHelp(GtkWidget * widget,gpointer data)365 static void DoHelp(GtkWidget *widget, gpointer data)
366 {
367   GdkScreen *screen;
368   GError *error = NULL;
369 
370   screen = gtk_widget_get_screen (widget);
371 
372   gtk_show_uri(screen, "ghelp:grip", gtk_get_current_event_time(), &error);
373 
374   if (error != NULL) {
375     GtkWidget *d;
376     GtkWidget *toplevel = gtk_widget_get_toplevel (widget);
377 
378     d = gtk_message_dialog_new(GTK_IS_WINDOW(toplevel) ? GTK_WINDOW(toplevel) : NULL,
379                                GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
380                                GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE,
381                                "%s", _("Unable to open help file"));
382     gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (d),
383                                               "%s", error->message);
384     g_signal_connect (d, "response", G_CALLBACK (gtk_widget_destroy), NULL);
385     gtk_window_present (GTK_WINDOW (d));
386 
387     g_error_free (error);
388   }
389 }
390 
MakeHelpPage(GripInfo * ginfo)391 static void MakeHelpPage(GripInfo *ginfo)
392 {
393   GtkWidget *help_page;
394   GtkWidget *button;
395   GtkWidget *vbox;
396 
397   help_page=MakeNewPage(ginfo->gui_info.notebook,_("Help"));
398 
399   vbox=gtk_vbox_new(FALSE,0);
400   gtk_container_border_width(GTK_CONTAINER(vbox),3);
401 
402   button=gtk_button_new_with_label(_("Table Of Contents"));
403   gtk_signal_connect(GTK_OBJECT(button), "clicked",
404                      GTK_SIGNAL_FUNC(DoHelp), NULL);
405   gtk_box_pack_start(GTK_BOX(vbox), button, FALSE, FALSE, 0);
406   gtk_widget_show(button);
407 
408   gtk_container_add(GTK_CONTAINER(help_page),vbox);
409   gtk_widget_show(vbox);
410 }
411 
MakeAboutPage(GripGUI * uinfo)412 void MakeAboutPage(GripGUI *uinfo)
413 {
414   GtkWidget *aboutpage;
415   GtkWidget *vbox,*vbox2,*hbox;
416   GtkWidget *label;
417   GtkWidget *logo;
418   GtkWidget *ebox;
419   GtkWidget *button;
420   gchar *versionbuf;
421 
422   aboutpage=MakeNewPage(uinfo->notebook,_("About"));
423 
424   ebox=gtk_event_box_new();
425   gtk_widget_set_style(ebox,uinfo->style_wb);
426 
427   vbox=gtk_vbox_new(TRUE,5);
428   gtk_container_border_width(GTK_CONTAINER(vbox),3);
429 
430   logo=Loadxpm(GTK_WIDGET(uinfo->app),grip_xpm);
431 
432   gtk_box_pack_start(GTK_BOX(vbox),logo,FALSE,FALSE,0);
433   gtk_widget_show(logo);
434 
435   vbox2=gtk_vbox_new(TRUE,0);
436 
437   versionbuf = g_strdup_printf(_("Version %s"),VERSION);
438   label=gtk_label_new(versionbuf);
439   g_free(versionbuf);
440 
441   gtk_widget_set_style(label,uinfo->style_wb);
442   gtk_box_pack_start(GTK_BOX(vbox2),label,FALSE,FALSE,0);
443   gtk_widget_show(label);
444 
445   label=gtk_label_new("Copyright\n1998-2005, Mike Oliphant\n2016-2021, Johnny A. Solbu");
446   gtk_widget_set_style(label,uinfo->style_wb);
447   gtk_box_pack_start(GTK_BOX(vbox2),label,FALSE,FALSE,0);
448   gtk_widget_show(label);
449 
450 #if defined(__sun__)
451   label=gtk_label_new("Solaris Port, David Meleedy");
452   gtk_widget_set_style(label,uinfo->style_wb);
453   gtk_box_pack_start(GTK_BOX(vbox2),label,FALSE,FALSE,0);
454   gtk_widget_show(label);
455 #endif
456 
457   hbox=gtk_hbox_new(TRUE,0);
458 
459   button=gtk_button_new_with_label(PACKAGE_BUGREPORT);
460   gtk_widget_set_style(button,uinfo->style_dark_grey);
461   gtk_widget_set_style(GTK_BIN(button)->child,
462 		       uinfo->style_dark_grey);
463   gtk_signal_connect(GTK_OBJECT(button),"clicked",
464 		     GTK_SIGNAL_FUNC(Homepage),uinfo);
465   gtk_box_pack_start(GTK_BOX(hbox),button,FALSE,FALSE,0);
466   gtk_widget_show(button);
467 
468   gtk_box_pack_start(GTK_BOX(vbox2),hbox,FALSE,FALSE,0);
469   gtk_widget_show(hbox);
470 
471 
472   gtk_container_add(GTK_CONTAINER(vbox),vbox2);
473   gtk_widget_show(vbox2);
474 
475   gtk_container_add(GTK_CONTAINER(ebox),vbox);
476   gtk_widget_show(vbox);
477 
478   gtk_container_add(GTK_CONTAINER(aboutpage),ebox);
479   gtk_widget_show(ebox);
480 }
481 
MakeStyles(GripGUI * uinfo)482 static void MakeStyles(GripGUI *uinfo)
483 {
484   GdkColor gdkblack;
485   GdkColor gdkwhite;
486   GdkColor *color_LCD;
487   GdkColor *color_dark_grey;
488 
489   gdk_color_white(gdk_colormap_get_system(),&gdkwhite);
490   gdk_color_black(gdk_colormap_get_system(),&gdkblack);
491 
492   color_LCD=MakeColor(33686,38273,29557);
493   color_dark_grey=MakeColor(0x4444,0x4444,0x4444);
494 
495   uinfo->style_wb=MakeStyle(&gdkwhite,&gdkblack,FALSE);
496   uinfo->style_LCD=MakeStyle(color_LCD,color_LCD,FALSE);
497   uinfo->style_dark_grey=MakeStyle(&gdkwhite,color_dark_grey,TRUE);
498 }
499 
Homepage(GtkWidget * widget,gpointer data)500 static void Homepage(GtkWidget *widget,gpointer data)
501 {
502   GripGUI *uinfo=(GripGUI *)data;
503   if (!gtk_show_uri(gtk_widget_get_screen (widget), PACKAGE_BUGREPORT,
504                     gtk_get_current_event_time(), NULL))
505     DisplayMsg(GTK_MESSAGE_WARNING, (GtkWindow *)uinfo->app,
506                _("Error: Trying to show homepage failed."));
507 }
508 
LoadImages(GripGUI * uinfo)509 static void LoadImages(GripGUI *uinfo)
510 {
511   uinfo->check_image=Loadxpm(uinfo->app,check_xpm);
512   uinfo->eject_image=Loadxpm(uinfo->app,eject_xpm);
513   uinfo->cdscan_image=Loadxpm(uinfo->app,cdscan_xpm);
514   uinfo->ff_image=Loadxpm(uinfo->app,ff_xpm);
515   uinfo->lowleft_image=Loadxpm(uinfo->app,lowleft_xpm);
516   uinfo->lowright_image=Loadxpm(uinfo->app,lowright_xpm);
517   uinfo->minmax_image=Loadxpm(uinfo->app,minmax_xpm);
518   uinfo->nexttrk_image=Loadxpm(uinfo->app,nexttrk_xpm);
519   uinfo->playpaus_image=Loadxpm(uinfo->app,playpaus_xpm);
520   uinfo->prevtrk_image=Loadxpm(uinfo->app,prevtrk_xpm);
521   uinfo->loop_image=Loadxpm(uinfo->app,loop_xpm);
522   uinfo->noloop_image=Loadxpm(uinfo->app,noloop_xpm);
523   uinfo->random_image=Loadxpm(uinfo->app,random_xpm);
524   uinfo->playlist_image=Loadxpm(uinfo->app,playlist_xpm);
525   uinfo->playnorm_image=Loadxpm(uinfo->app,playnorm_xpm);
526   uinfo->quit_image=Loadxpm(uinfo->app,quit_xpm);
527   uinfo->rew_image=Loadxpm(uinfo->app,rew_xpm);
528   uinfo->stop_image=Loadxpm(uinfo->app,stop_xpm);
529   uinfo->upleft_image=Loadxpm(uinfo->app,upleft_xpm);
530   uinfo->upright_image=Loadxpm(uinfo->app,upright_xpm);
531   uinfo->vol_image=Loadxpm(uinfo->app,vol_xpm);
532   uinfo->discdbwht_image=Loadxpm(uinfo->app,discdbwht_xpm);
533   uinfo->rotate_image=Loadxpm(uinfo->app,rotate_xpm);
534   uinfo->edit_image=Loadxpm(uinfo->app,edit_xpm);
535   uinfo->progtrack_image=Loadxpm(uinfo->app,progtrack_xpm);
536   uinfo->mail_image=Loadxpm(uinfo->app,mail_xpm);
537   uinfo->save_image=Loadxpm(uinfo->app,save_xpm);
538 
539   uinfo->empty_image=NewBlankPixmap(uinfo->app);
540 
541   uinfo->discdb_pix[0]=Loadxpm(uinfo->app,discdb0_xpm);
542   uinfo->discdb_pix[1]=Loadxpm(uinfo->app,discdb1_xpm);
543 
544   uinfo->play_pix[0]=Loadxpm(uinfo->app,playnorm_xpm);
545   uinfo->play_pix[1]=Loadxpm(uinfo->app,random_xpm);
546   uinfo->play_pix[2]=Loadxpm(uinfo->app,playlist_xpm);
547 
548   uinfo->rip_pix[0]=Loadxpm(uinfo->app,rip0_xpm);
549   uinfo->rip_pix[1]=Loadxpm(uinfo->app,rip1_xpm);
550   uinfo->rip_pix[2]=Loadxpm(uinfo->app,rip2_xpm);
551   uinfo->rip_pix[3]=Loadxpm(uinfo->app,rip3_xpm);
552 
553   uinfo->mp3_pix[0]=Loadxpm(uinfo->app,enc0_xpm);
554   uinfo->mp3_pix[1]=Loadxpm(uinfo->app,enc1_xpm);
555   uinfo->mp3_pix[2]=Loadxpm(uinfo->app,enc2_xpm);
556   uinfo->mp3_pix[3]=Loadxpm(uinfo->app,enc3_xpm);
557 
558   uinfo->smile_pix[0]=Loadxpm(uinfo->app,smile1_xpm);
559   uinfo->smile_pix[1]=Loadxpm(uinfo->app,smile2_xpm);
560   uinfo->smile_pix[2]=Loadxpm(uinfo->app,smile3_xpm);
561   uinfo->smile_pix[3]=Loadxpm(uinfo->app,smile4_xpm);
562   uinfo->smile_pix[4]=Loadxpm(uinfo->app,smile5_xpm);
563   uinfo->smile_pix[5]=Loadxpm(uinfo->app,smile6_xpm);
564   uinfo->smile_pix[6]=Loadxpm(uinfo->app,smile7_xpm);
565   uinfo->smile_pix[7]=Loadxpm(uinfo->app,smile8_xpm);
566 }
567 
GripUpdate(GtkWidget * app)568 void GripUpdate(GtkWidget *app)
569 {
570   GripInfo *ginfo;
571   time_t secs;
572 
573   ginfo=(GripInfo *)gtk_object_get_user_data(GTK_OBJECT(app));
574 
575   if(ginfo->ffwding) FastFwd(ginfo);
576   if(ginfo->rewinding) Rewind(ginfo);
577 
578   secs=time(NULL);
579 
580   /* Make sure we don't mod by zero */
581   if(!ginfo->poll_interval)
582     ginfo->poll_interval=1;
583 
584   if(ginfo->ripping|ginfo->encoding) UpdateRipProgress(ginfo);
585 
586   if(!ginfo->ripping_a_disc) {
587     if(ginfo->poll_drive && !(secs%ginfo->poll_interval)) {
588       if(!ginfo->have_disc)
589 	CheckNewDisc(ginfo,FALSE);
590     }
591 
592     UpdateDisplay(ginfo);
593   }
594 
595   UpdateTray(ginfo);
596 }
597 
Busy(GripGUI * uinfo)598 void Busy(GripGUI *uinfo)
599 {
600   gdk_window_set_cursor(uinfo->app->window,uinfo->wait_cursor);
601 
602   UpdateGTK();
603 }
604 
UnBusy(GripGUI * uinfo)605 void UnBusy(GripGUI *uinfo)
606 {
607   gdk_window_set_cursor(uinfo->app->window,NULL);
608 
609   UpdateGTK();
610 }
611 
DoLoadConfig(GripInfo * ginfo)612 static void DoLoadConfig(GripInfo *ginfo)
613 {
614   GripGUI *uinfo=&(ginfo->gui_info);
615   char filename[512];
616   char renamefile[520];
617   char outputdir[256];
618   int confret;
619   CFGEntry cfg_entries[]={
620     CFG_ENTRIES
621     {"outputdir",CFG_ENTRY_STRING,256,outputdir},
622     {"",CFG_ENTRY_LAST,0,NULL}
623   };
624 
625   outputdir[0]='\0';
626 
627   uinfo->minimized=FALSE;
628   uinfo->volvis=FALSE;
629   uinfo->track_prog_visible=FALSE;
630   uinfo->track_edit_visible=FALSE;
631 
632   uinfo->wait_cursor=gdk_cursor_new(GDK_WATCH);
633 
634   uinfo->tray_icon=NULL;
635 
636   uinfo->id3_genre_item_list=NULL;
637 
638   *ginfo->version='\0';
639 
640   strcpy(ginfo->cd_device,"/dev/cd0");
641   *ginfo->force_scsi='\0';
642 
643   ginfo->local_mode=FALSE;
644   ginfo->have_disc=FALSE;
645   ginfo->tray_open=FALSE;
646   ginfo->faulty_eject=FALSE;
647   ginfo->looking_up=FALSE;
648   ginfo->play_mode=PM_NORMAL;
649   ginfo->playloop=TRUE;
650   ginfo->automatic_reshuffle=TRUE;
651   ginfo->ask_submit=FALSE;
652   ginfo->is_new_disc=FALSE;
653   ginfo->first_time=TRUE;
654   ginfo->automatic_discdb=TRUE;
655   ginfo->auto_eject_countdown=0;
656   ginfo->current_discid=0;
657   ginfo->volume=255;
658 #if defined(__FreeBSD__) || defined(__NetBSD__)
659   ginfo->poll_drive=FALSE;
660   ginfo->poll_interval=15;
661 #else
662   ginfo->poll_drive=TRUE;
663   ginfo->poll_interval=1;
664 #endif
665 
666   ginfo->changer_slots=0;
667   ginfo->current_disc=0;
668 
669   ginfo->proxy_server.name[0]='\0';
670   ginfo->proxy_server.port=8000;
671   ginfo->use_proxy=FALSE;
672   ginfo->use_proxy_env=FALSE;
673 
674   strcpy(ginfo->dbserver.name,"gnudb.gnudb.org");
675   strcpy(ginfo->dbserver.cgi_prog,"~cddb/cddb.cgi");
676   ginfo->dbserver.port=80;
677   ginfo->dbserver.use_proxy=0;
678   ginfo->dbserver.proxy=&(ginfo->proxy_server);
679 
680   strcpy(ginfo->dbserver2.name,"");
681   strcpy(ginfo->dbserver2.cgi_prog,"~cddb/cddb.cgi");
682   ginfo->dbserver2.port=80;
683   ginfo->dbserver2.use_proxy=0;
684   ginfo->dbserver2.proxy=&(ginfo->proxy_server);
685 
686   strcpy(ginfo->discdb_submit_email,"submit@gnudb.org");
687   ginfo->db_use_freedb=TRUE;
688   *ginfo->user_email='\0';
689 
690   strcpy(ginfo->discdb_encoding,"UTF-8");
691   strcpy(ginfo->id3_encoding,"UTF-8");
692   strcpy(ginfo->id3v2_encoding,"UTF-8");
693 
694   ginfo->local_mode=FALSE;
695   ginfo->update_required=FALSE;
696   ginfo->looking_up=FALSE;
697   ginfo->ask_submit=FALSE;
698   ginfo->is_new_disc=FALSE;
699   ginfo->automatic_discdb=TRUE;
700   ginfo->play_first=TRUE;
701   ginfo->play_on_insert=FALSE;
702   ginfo->stop_first=FALSE;
703   ginfo->no_interrupt=FALSE;
704   ginfo->playing=FALSE;
705   ginfo->stopped=FALSE;
706   ginfo->ffwding=FALSE;
707   ginfo->rewinding=FALSE;
708 
709   strcpy(ginfo->title_split_chars,"/");
710 
711   ginfo->curr_pipe_fd=-1;
712 
713   ginfo->num_cpu=1;
714   ginfo->ripping=FALSE;
715   ginfo->ripping_a_disc=FALSE;
716   ginfo->encoding=FALSE;
717   ginfo->rip_partial=FALSE;
718   ginfo->stop_rip=FALSE;
719   ginfo->stop_encode=FALSE;
720   ginfo->rip_finished=0;
721   ginfo->num_wavs=0;
722   ginfo->doencode=FALSE;
723   ginfo->encode_list=NULL;
724   ginfo->pending_list=NULL;
725   ginfo->delayed_encoding = 0;
726   ginfo->do_redirect=TRUE;
727   ginfo->selected_ripper=0;
728 #ifdef CDPAR
729   ginfo->stop_thread_rip_now=FALSE;
730   ginfo->using_builtin_cdp=TRUE;
731   ginfo->disable_paranoia=FALSE;
732   ginfo->disable_extra_paranoia=FALSE;
733   ginfo->disable_scratch_detect=FALSE;
734   ginfo->disable_scratch_repair=FALSE;
735   ginfo->calc_gain=FALSE;
736 #else
737   ginfo->using_builtin_cdp=FALSE;
738 #endif
739   ginfo->in_rip_thread=FALSE;
740   strcpy(ginfo->ripfileformat,"~/ogg/%A/%d/%n.wav");
741   strcpy(ginfo->ripfileformat_multi,"~/ogg/%A/%d/%a_%n.wav");
742 #ifdef __linux__
743   FindExeInPath("cdparanoia", ginfo->ripexename, sizeof(ginfo->ripexename));
744   strcpy(ginfo->ripcmdline,"-d %c %t:[.%s]-%t:[.%e] %w");
745 #else
746   FindExeInPath("cdda2wav", ginfo->ripexename, sizeof(ginfo->ripexename));
747 #ifdef __sun__
748   strcpy(ginfo->ripcmdline,"-x -H -t %t -O wav %w");
749 #else
750   strcpy(ginfo->ripcmdline,"-D %C -x -H -t %t -O wav %w");
751 #endif /* not sun */
752 #endif /* not linux */
753 
754   ginfo->ripnice=0;
755   ginfo->max_wavs=99;
756   ginfo->auto_rip=FALSE;
757   ginfo->beep_after_rip=TRUE;
758   ginfo->eject_after_rip=TRUE;
759   ginfo->eject_delay=0;
760   ginfo->delay_before_rip=FALSE;
761   ginfo->stop_between_tracks=FALSE;
762   *ginfo->wav_filter_cmd='\0';
763   *ginfo->disc_filter_cmd='\0';
764   ginfo->selected_encoder=0;
765   strcpy(ginfo->mp3cmdline,"-o %m -a %a -l %d -t %n -b %b %w -N %t -G %G -d %y");
766   FindExeInPath("oggenc", ginfo->mp3exename, sizeof(ginfo->mp3exename));
767   strcpy(ginfo->mp3fileformat,"~/ogg/%A/%d/%t_%n.%x");
768   strcpy(ginfo->mp3fileformat_multi,"~/ogg/%A/%d/%t_%a_%n.%x");
769   strcpy(ginfo->mp3extension,"ogg");
770   ginfo->mp3nice=0;
771   *ginfo->mp3_filter_cmd='\0';
772   ginfo->delete_wavs=TRUE;
773   ginfo->add_to_db=FALSE;
774   ginfo->add_m3u=TRUE;
775   ginfo->rel_m3u=TRUE;
776   strcpy(ginfo->m3ufileformat,"~/ogg/%A-%d.m3u");
777   ginfo->kbits_per_sec=192;
778   ginfo->edit_num_cpu=1;
779   ginfo->doid3=TRUE;
780   ginfo->doid3=FALSE;
781   ginfo->tag_mp3_only=TRUE;
782   strcpy(ginfo->id3_comment,_("Created by Grip"));
783   *ginfo->cdupdate='\0';
784   ginfo->sprefs.no_lower_case=FALSE;
785   ginfo->sprefs.allow_high_bits=FALSE;
786   ginfo->sprefs.escape=FALSE;
787   ginfo->sprefs.no_underscore=FALSE;
788   ginfo->sprefs.non_posix_m3u_directory_paths=FALSE;
789   *ginfo->sprefs.allow_these_chars='\0';
790   ginfo->show_tray_icon=TRUE;
791 
792   sprintf(filename,"%s/%s", g_get_home_dir(), ginfo->config_filename);
793 
794   confret=LoadConfig(filename,"GRIP",2,2,cfg_entries);
795 
796   if(confret<0) {
797     /* Check if the config is out of date */
798     if(confret==-2) {
799       DisplayMsg(GTK_MESSAGE_WARNING, (GtkWindow *)ginfo->gui_info.app,
800                  _("Your config file is out of date -- "
801                    "resetting to defaults.\n"
802                    "You will need to re-configure Grip.\n"
803                    "Your old config file has been saved with -old appended."));
804 
805       sprintf(renamefile,"%s-old",filename);
806 
807       rename(filename,renamefile);
808     }
809 
810     DoSaveConfig(ginfo);
811   }
812 
813   LoadRipperConfig(ginfo,ginfo->selected_ripper);
814   LoadEncoderConfig(ginfo,ginfo->selected_encoder);
815 
816   /* Phase out 'outputdir' variable */
817 
818   if(*outputdir) {
819     strcpy(filename,outputdir);
820     MakePath(filename);
821     strcat(filename,ginfo->mp3fileformat);
822     strcpy(ginfo->mp3fileformat,filename);
823 
824     strcpy(filename,outputdir);
825     MakePath(filename);
826     strcat(filename,ginfo->mp3fileformat_multi);
827     strcpy(ginfo->mp3fileformat_multi,filename);
828 
829     strcpy(filename,outputdir);
830     MakePath(filename);
831     strcat(filename,ginfo->ripfileformat);
832     strcpy(ginfo->ripfileformat,filename);
833 
834     strcpy(filename,outputdir);
835     MakePath(filename);
836     strcat(filename,ginfo->ripfileformat_multi);
837     strcpy(ginfo->ripfileformat_multi,filename);
838 
839     *outputdir='\0';
840   }
841 
842   ginfo->dbserver2.use_proxy=ginfo->dbserver.use_proxy=ginfo->use_proxy;
843   ginfo->dbserver2.proxy=ginfo->dbserver.proxy;
844 
845   ginfo->num_cpu=ginfo->edit_num_cpu;
846 
847   if(!*ginfo->user_email) {
848     g_snprintf(ginfo->user_email, 256, "%s@%s", g_get_user_name(), g_get_host_name());
849   }
850 
851   if(ginfo->use_proxy_env) {   /* Get proxy info from "http_proxy" */
852     char * const proxy_env = g_strdup (g_getenv ("http_proxy"));
853     if(proxy_env) {
854       LoadProxyConfig(ginfo, proxy_env);
855     }
856     g_free (proxy_env);
857   }
858 }
859 
860 /** Extract proxy server name and port from proxy_env and update ginfo */
LoadProxyConfig(GripInfo * const ginfo,char * proxy_env)861 void LoadProxyConfig(GripInfo * const ginfo, char* proxy_env)
862 {
863   g_assert(ginfo);
864   g_assert(proxy_env);
865 
866   /* Skip the "http://" if it's present */
867   const char* SCHEME_PFX = "http://";
868   if(!strncasecmp(proxy_env, SCHEME_PFX, strlen(SCHEME_PFX))) proxy_env += strlen(SCHEME_PFX);
869 
870   char *tok=strtok(proxy_env,":");
871   if(tok) strncpy(ginfo->proxy_server.name,tok,255);
872 
873   /* Make sure ginfo->proxy_server.name is terminated correctly. */
874   ginfo->proxy_server.name[255] = 0;
875 
876   tok=strtok(NULL,"/");
877   if(tok) ginfo->proxy_server.port=atoi(tok);
878 
879   Debug(_("server is %s, port %d\n"), ginfo->proxy_server.name,
880         ginfo->proxy_server.port);
881 }
882 
DoSaveConfig(GripInfo * ginfo)883 void DoSaveConfig(GripInfo *ginfo)
884 {
885   char filename[256];
886   GripGUI *uinfo=&(ginfo->gui_info);
887   CFGEntry cfg_entries[]={
888     CFG_ENTRIES
889     {"",CFG_ENTRY_LAST,0,NULL}
890   };
891 
892   if(ginfo->edit_num_cpu>MAX_NUM_CPU) ginfo->edit_num_cpu=MAX_NUM_CPU;
893 
894   g_snprintf(filename,256,"%s/%s", g_get_home_dir(), ginfo->config_filename);
895 
896   if(!SaveConfig(filename,"GRIP",2,cfg_entries))
897     DisplayMsg(GTK_MESSAGE_WARNING, (GtkWindow *)ginfo->gui_info.app,
898                _("Error: Unable to save config file."));
899 
900   SaveRipperConfig(ginfo,ginfo->selected_ripper);
901   SaveEncoderConfig(ginfo,ginfo->selected_encoder);
902 }
903 
904 /* Shut down stuff (generally before an exec) */
CloseStuff(void * user_data)905 void CloseStuff(void *user_data)
906 {
907   GripInfo *ginfo;
908   int fd;
909 
910   ginfo=(GripInfo *)user_data;
911 
912   close(ConnectionNumber(GDK_DISPLAY()));
913   close(ginfo->disc.cd_desc);
914 
915   fd=open("/dev/null",O_RDWR);
916   dup2(fd,0);
917 
918   if(ginfo->do_redirect) {
919     if(ginfo->curr_pipe_fd>0) {
920       dup2(ginfo->curr_pipe_fd,1);
921       dup2(ginfo->curr_pipe_fd,2);
922 
923       ginfo->curr_pipe_fd=-1;
924     }
925     else {
926       dup2(fd,1);
927       dup2(fd,2);
928     }
929   }
930 
931   /* Close any other filehandles that might be around */
932   for(fd=3;fd<NOFILE;fd++) {
933     close(fd);
934   }
935 }
936