1 /******************************* LICENCE **************************************
2 * Any code in this file may be redistributed or modified under the terms of
3 * the GNU General Public Licence as published by the Free Software
4 * Foundation; version 2 of the licence.
5 ****************************** END LICENCE ***********************************/
6 
7 /******************************************************************************
8 * Author:
9 * Andrew Smith, http://littlesvr.ca/misc/contactandrew.php
10 *
11 * Contributors:
12 * Sebastian Pipping <sebastian@pipping.org>
13 *
14 ******************************************************************************/
15 
16 #include <gtk/gtk.h>
17 #include <gdk/gdkkeysyms.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <stdbool.h>
21 #include <fcntl.h>
22 #include <unistd.h>
23 #include <sys/stat.h>
24 #include <time.h>
25 #include <libintl.h>
26 #include <errno.h>
27 #include <regex.h>
28 
29 #include "isomaster.h"
30 
31 extern GtkWidget* GBLmainWindow;
32 extern GtkWidget* GBLisoTreeView;
33 extern GtkListStore* GBLisoListStore;
34 extern char* GBLisoCurrentDir;
35 extern GtkWidget* GBLfsTreeView;
36 extern GtkListStore* GBLfsListStore;
37 extern char* GBLfsCurrentDir;
38 extern GtkWidget* GBLisoSizeLbl;
39 extern GtkWidget* GBLisoCurrentDirField;
40 extern GdkPixbuf* GBLdirPixbuf;
41 extern GdkPixbuf* GBLfilePixbuf;
42 extern AppSettings GBLappSettings;
43 extern GtkWidget* GBLrecentlyOpenWidgets[5];
44 
45 /* info about the image being worked on */
46 VolInfo GBLvolInfo;
47 /* to know whether am working on an image */
48 bool GBLisoPaneActive = false;
49 /* to know whether any changes to the image have been requested */
50 bool GBLisoChangesProbable = false;
51 /* the size of the iso if it were written right now */
52 static bk_off_t GBLisoSize = 0;
53 /* the progress bar from the writing dialog box */
54 static GtkWidget* GBLWritingProgressBar;
55 /* the progress bar from the extracting dialog box */
56 static GtkWidget* GBLactivityProgressBar;
57 /* the column for the filename in the iso pane */
58 static GtkTreeViewColumn* GBLfilenameIsoColumn;
59 /* the window with the progress bar for writing */
60 GtkWidget* GBLwritingProgressWindow;
61 #ifdef ENABLE_SAVE_OVERWRITE
62 static char* openIsoPathAndName = NULL;
63 #endif
64 /* to really stop an operation, not just for one row */
65 static bool GBLoperationCanceled;
66 
activityProgressUpdaterCbk(VolInfo * volInfo)67 void activityProgressUpdaterCbk(VolInfo* volInfo)
68 {
69     if(GBLactivityProgressBar != NULL)
70     {
71         gtk_progress_bar_pulse(GTK_PROGRESS_BAR(GBLactivityProgressBar));
72 
73         /* redraw progress bar */
74         while(gtk_events_pending())
75             gtk_main_iteration();
76     }
77 }
78 
activityProgressWindowDeleteCbk(GtkWidget * widget,GdkEvent * event,gpointer user_data)79 gboolean activityProgressWindowDeleteCbk(GtkWidget* widget, GdkEvent* event,
80                                           gpointer user_data)
81 {
82     /* don't allow closing */
83     return TRUE;
84 }
85 
acceptIsoPathCbk(GtkEntry * entry,gpointer user_data)86 void acceptIsoPathCbk(GtkEntry *entry, gpointer user_data)
87 {
88     const char* newPath;
89     char* newPathTerminated;
90 
91     newPath = gtk_entry_get_text(entry);
92 
93     if(newPath[strlen(newPath) - 1] == '/')
94     {
95         changeIsoDirectory((char*)newPath);
96     }
97     else
98     {
99         newPathTerminated = malloc(strlen(newPath) + 2);
100         if(newPathTerminated == NULL)
101             fatalError("newPathTerminated = malloc(strlen(newPath) + 2) failed");
102 
103         strcpy(newPathTerminated, newPath);
104         strcat(newPathTerminated, "/");
105 
106         changeIsoDirectory(newPathTerminated);
107 
108         free(newPathTerminated);
109     }
110 }
111 
addToIsoCbk(GtkButton * button,gpointer data)112 void addToIsoCbk(GtkButton *button, gpointer data)
113 {
114     GtkTreeSelection* selection;
115 
116     if(!GBLisoPaneActive)
117     /* no iso open */
118         return;
119 
120     selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(GBLfsTreeView));
121 
122     /* CREATE and show progress bar */
123     GtkWidget* progressWindow;
124     GtkWidget* label;
125 
126     /* dialog window for the progress bar */
127     progressWindow = gtk_dialog_new();
128     gtk_dialog_set_has_separator(GTK_DIALOG(progressWindow), FALSE);
129     gtk_window_set_modal(GTK_WINDOW(progressWindow), TRUE);
130     gtk_window_set_title(GTK_WINDOW(progressWindow), _("Progress"));
131     gtk_window_set_transient_for(GTK_WINDOW(progressWindow), GTK_WINDOW(GBLmainWindow));
132     g_signal_connect_swapped(progressWindow, "delete-event",
133                              G_CALLBACK(activityProgressWindowDeleteCbk), NULL);
134     g_signal_connect_swapped(progressWindow, "response",
135                              G_CALLBACK(cancelOperation), NULL);
136 
137     label = gtk_label_new(_("Please wait while I'm adding the selected items..."));
138     gtk_box_pack_start(GTK_BOX(GTK_DIALOG(progressWindow)->vbox), label, TRUE, TRUE, 0);
139     gtk_widget_show(label);
140 
141     if(GBLappSettings.scanForDuplicateFiles)
142     {
143         label = gtk_label_new(_("(scanning for duplicate files)"));
144         gtk_box_pack_start(GTK_BOX(GTK_DIALOG(progressWindow)->vbox), label, TRUE, TRUE, 0);
145         gtk_widget_show(label);
146     }
147 
148     /* the progress bar */
149     GBLactivityProgressBar = gtk_progress_bar_new();
150     gtk_box_pack_start(GTK_BOX(GTK_DIALOG(progressWindow)->vbox), GBLactivityProgressBar, TRUE, TRUE, 0);
151     gtk_widget_show(GBLactivityProgressBar);
152 
153     /* button to cancel adding */
154     gtk_dialog_add_button(GTK_DIALOG(progressWindow), GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
155 
156     /* if i show it before i add the children, the window ends up being not centered */
157     gtk_widget_show(progressWindow);
158     /* END CREATE and show progress bar */
159 
160     GBLoperationCanceled = false;
161 
162     gtk_tree_selection_selected_foreach(selection, addToIsoEachRowCbk, NULL);
163 
164     gtk_widget_destroy(progressWindow);
165     GBLactivityProgressBar = NULL;
166 
167     if(gtk_tree_selection_count_selected_rows(selection) > 0)
168     /* reload iso view */
169     {
170         refreshIsoView();
171     }
172 
173     /* iso size label */
174     char sizeStr[20];
175     GBLisoSize = 35845;
176     //if(GBLvolInfo.filenameTypes & FNTYPE_JOLIET)
177         GBLisoSize += 2048;
178     GBLisoSize += bk_estimate_iso_size(&GBLvolInfo, FNTYPE_9660 | FNTYPE_JOLIET | FNTYPE_ROCKRIDGE);
179     formatSize(GBLisoSize, sizeStr, sizeof(sizeStr));
180     gtk_label_set_text(GTK_LABEL(GBLisoSizeLbl), sizeStr);
181 }
182 
addToIsoEachRowCbk(GtkTreeModel * model,GtkTreePath * path,GtkTreeIter * iterator,gpointer data)183 void addToIsoEachRowCbk(GtkTreeModel* model, GtkTreePath* path,
184                         GtkTreeIter* iterator, gpointer data)
185 {
186     int fileType;
187     char* itemName;
188     char* fullItemName; /* with full path */
189     int rc;
190     GtkWidget* warningDialog;
191 
192     if(GBLoperationCanceled)
193         return;
194 
195     gtk_tree_model_get(model, iterator, COLUMN_HIDDEN_TYPE, &fileType,
196                                         COLUMN_FILENAME, &itemName, -1);
197 
198     if(fileType == FILE_TYPE_DIRECTORY || fileType == FILE_TYPE_REGULAR ||
199        fileType == FILE_TYPE_SYMLINK)
200     {
201         fullItemName = (char*)malloc(strlen(GBLfsCurrentDir) + strlen(itemName) + 1);
202         if(fullItemName == NULL)
203             fatalError("addToIsoEachRowCbk(): malloc("
204                        "strlen(GBLfsCurrentDir) + strlen(itemName) + 1) failed");
205 
206         strcpy(fullItemName, GBLfsCurrentDir);
207         strcat(fullItemName, itemName);
208 
209         rc = bk_add(&GBLvolInfo, fullItemName, GBLisoCurrentDir, activityProgressUpdaterCbk);
210         if(rc <= 0 && rc != BKWARNING_OPER_PARTLY_FAILED)
211         {
212             warningDialog = gtk_message_dialog_new(GTK_WINDOW(GBLmainWindow),
213                                                    GTK_DIALOG_DESTROY_WITH_PARENT,
214                                                    GTK_MESSAGE_ERROR,
215                                                    GTK_BUTTONS_CLOSE,
216                                                    _("Failed to add '%s': '%s'"),
217                                                    fullItemName,
218                                                    bk_get_error_string(rc));
219             gtk_window_set_modal(GTK_WINDOW(warningDialog), TRUE);
220             gtk_dialog_run(GTK_DIALOG(warningDialog));
221             gtk_widget_destroy(warningDialog);
222         }
223         else
224             GBLisoChangesProbable = true;
225 
226         free(fullItemName);
227     }
228     else
229     {
230         warningDialog = gtk_message_dialog_new(GTK_WINDOW(GBLmainWindow),
231                                                GTK_DIALOG_DESTROY_WITH_PARENT,
232                                                GTK_MESSAGE_ERROR,
233                                                GTK_BUTTONS_CLOSE,
234                                                "GUI error, adding anything other than "
235                                                "files and directories doesn't work");
236         gtk_window_set_modal(GTK_WINDOW(warningDialog), TRUE);
237         gtk_dialog_run(GTK_DIALOG(warningDialog));
238         gtk_widget_destroy(warningDialog);
239     }
240 
241     g_free(itemName);
242 }
243 
askForPermissions(const char * fullItemName,mode_t * permissions)244 bool askForPermissions(const char* fullItemName, mode_t* permissions)
245 {
246     GtkWidget* dialog;
247     GtkWidget* table;
248     GtkWidget* label;
249     int rc;
250     int count;
251     bool didChange = false;
252 
253     rc = bk_get_permissions(&GBLvolInfo, fullItemName, permissions);
254     if(rc <= 0)
255     {
256         dialog = gtk_message_dialog_new(GTK_WINDOW(GBLmainWindow),
257                                         GTK_DIALOG_DESTROY_WITH_PARENT,
258                                         GTK_MESSAGE_ERROR,
259                                         GTK_BUTTONS_CLOSE,
260                                         "bk_get_permissions() failed (%s), please report bug",
261                                         bk_get_error_string(rc));
262         gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
263         gtk_dialog_run(GTK_DIALOG(dialog));
264         gtk_widget_destroy(dialog);
265         return false;
266     }
267 
268     dialog = gtk_dialog_new_with_buttons(_("Change permissions"),
269                                          GTK_WINDOW(GBLmainWindow),
270                                          GTK_DIALOG_DESTROY_WITH_PARENT,
271                                          GTK_STOCK_OK,
272                                          GTK_RESPONSE_ACCEPT,
273                                          GTK_STOCK_CANCEL,
274                                          GTK_RESPONSE_REJECT,
275                                          NULL);
276     g_signal_connect(dialog, "close", G_CALLBACK(rejectDialogCbk), NULL);
277     gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT);
278 
279     table = gtk_table_new(3, 11, FALSE);
280     //~ gtk_table_set_row_spacings(GTK_TABLE(table), 5);
281     //~ gtk_table_set_col_spacings(GTK_TABLE(table), 5);
282     gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), table, TRUE, TRUE, 0);
283     gtk_widget_show(table);
284 
285     label = gtk_label_new("User");
286     gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 3, 0, 1);
287     gtk_widget_show(label);
288 
289     label = gtk_label_new("Group");
290     gtk_table_attach_defaults(GTK_TABLE(table), label, 4, 7, 0, 1);
291     gtk_widget_show(label);
292 
293     label = gtk_label_new("Others");
294     gtk_table_attach_defaults(GTK_TABLE(table), label, 8, 11, 0, 1);
295     gtk_widget_show(label);
296 
297     for(count = 0; count < 11; count++)
298     {
299         if(count == 0 || count == 4 || count == 8)
300         {
301             label = gtk_label_new("r");
302             gtk_table_attach_defaults(GTK_TABLE(table), label, count, count + 1, 1, 2);
303             gtk_widget_show(label);
304         }
305         else if(count == 1 || count == 5 || count == 9)
306         {
307             label = gtk_label_new("w");
308             gtk_table_attach_defaults(GTK_TABLE(table), label, count, count + 1, 1, 2);
309             gtk_widget_show(label);
310         }
311         else if(count == 2 || count == 6 || count == 10)
312         {
313             label = gtk_label_new("x");
314             gtk_table_attach_defaults(GTK_TABLE(table), label, count, count + 1, 1, 2);
315             gtk_widget_show(label);
316         }
317         else
318         {
319             label = gtk_label_new("-");
320             gtk_table_attach_defaults(GTK_TABLE(table), label, count, count + 1, 1, 2);
321             gtk_widget_show(label);
322         }
323     }
324 
325     /* CREATE checkboxes for permissions */
326     GtkWidget* urCbx; /* user read */
327     GtkWidget* uwCbx;
328     GtkWidget* uxCbx;
329     GtkWidget* grCbx; /* group read */
330     GtkWidget* gwCbx;
331     GtkWidget* gxCbx;
332     GtkWidget* orCbx; /* others readd */
333     GtkWidget* owCbx;
334     GtkWidget* oxCbx;
335 
336     urCbx = gtk_check_button_new();
337     gtk_table_attach_defaults(GTK_TABLE(table), urCbx, 0, 1, 2, 3);
338     if(*permissions & 0400)
339         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(urCbx), TRUE);
340     gtk_widget_show(urCbx);
341 
342     uwCbx = gtk_check_button_new();
343     gtk_table_attach_defaults(GTK_TABLE(table), uwCbx, 1, 2, 2, 3);
344     if(*permissions & 0200)
345         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(uwCbx), TRUE);
346     gtk_widget_show(uwCbx);
347 
348     uxCbx = gtk_check_button_new();
349     gtk_table_attach_defaults(GTK_TABLE(table), uxCbx, 2, 3, 2, 3);
350     if(*permissions & 0100)
351         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(uxCbx), TRUE);
352     gtk_widget_show(uxCbx);
353 
354     label = gtk_label_new("-");
355     gtk_table_attach_defaults(GTK_TABLE(table), label, 3, 4, 2, 3);
356     gtk_widget_show(label);
357 
358     grCbx = gtk_check_button_new();
359     gtk_table_attach_defaults(GTK_TABLE(table), grCbx, 4, 5, 2, 3);
360     if(*permissions & 0040)
361         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(grCbx), TRUE);
362     gtk_widget_show(grCbx);
363 
364     gwCbx = gtk_check_button_new();
365     gtk_table_attach_defaults(GTK_TABLE(table), gwCbx, 5, 6, 2, 3);
366     if(*permissions & 0020)
367         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gwCbx), TRUE);
368     gtk_widget_show(gwCbx);
369 
370     gxCbx = gtk_check_button_new();
371     gtk_table_attach_defaults(GTK_TABLE(table), gxCbx, 6, 7, 2, 3);
372     if(*permissions & 0010)
373         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gxCbx), TRUE);
374     gtk_widget_show(gxCbx);
375 
376     label = gtk_label_new("-");
377     gtk_table_attach_defaults(GTK_TABLE(table), label, 7, 8, 2, 3);
378     gtk_widget_show(label);
379 
380     orCbx = gtk_check_button_new();
381     gtk_table_attach_defaults(GTK_TABLE(table), orCbx, 8, 9, 2, 3);
382     if(*permissions & 0004)
383         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(orCbx), TRUE);
384     gtk_widget_show(orCbx);
385 
386     owCbx = gtk_check_button_new();
387     gtk_table_attach_defaults(GTK_TABLE(table), owCbx, 9, 10, 2, 3);
388     if(*permissions & 0002)
389         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(owCbx), TRUE);
390     gtk_widget_show(owCbx);
391 
392     oxCbx = gtk_check_button_new();
393     gtk_table_attach_defaults(GTK_TABLE(table), oxCbx, 10, 11, 2, 3);
394     if(*permissions & 0001)
395         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(oxCbx), TRUE);
396     gtk_widget_show(oxCbx);
397     /* END CREATE checkboxes for permissions */
398 
399     gtk_widget_show(dialog);
400 
401     rc = gtk_dialog_run(GTK_DIALOG(dialog));
402     if(rc == GTK_RESPONSE_ACCEPT)
403     {
404         *permissions = 0;
405 
406         if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(urCbx)))
407             *permissions |= 0400;
408         if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(uwCbx)))
409             *permissions |= 0200;
410         if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(uxCbx)))
411             *permissions |= 0100;
412         if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(grCbx)))
413             *permissions |= 0040;
414         if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gwCbx)))
415             *permissions |= 0020;
416         if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gxCbx)))
417             *permissions |= 0010;
418         if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(orCbx)))
419             *permissions |= 0004;
420         if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(owCbx)))
421             *permissions |= 0002;
422         if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(oxCbx)))
423             *permissions |= 0001;
424 
425         didChange = true;
426     }
427 
428     gtk_widget_destroy(dialog);
429 
430     return didChange;
431 }
432 
buildIsoBrowser(GtkWidget * boxToPackInto)433 void buildIsoBrowser(GtkWidget* boxToPackInto)
434 {
435     GtkWidget* scrolledWindow;
436     GtkTreeSelection *selection;
437     GtkCellRenderer* renderer;
438     GtkTreeViewColumn* column;
439 
440     GBLisoListStore = gtk_list_store_new(NUM_COLUMNS,
441                                          GDK_TYPE_PIXBUF, /* icon */
442                                          G_TYPE_STRING, /* name */
443                                          G_TYPE_UINT, /* size (64-bit sizes not allowed on an iso) */
444                                          G_TYPE_UINT /* file type */
445                                          );
446 
447     scrolledWindow = gtk_scrolled_window_new(NULL, NULL);
448     gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolledWindow),
449 				   GTK_POLICY_AUTOMATIC,
450 				   GTK_POLICY_AUTOMATIC);
451     //~ gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolledWindow),
452                                         //~ GTK_SHADOW_ETCHED_IN);
453     gtk_box_pack_start(GTK_BOX(boxToPackInto), scrolledWindow, TRUE, TRUE, 0);
454     gtk_widget_show(scrolledWindow);
455 
456     /* view widget */
457     GBLisoTreeView = gtk_tree_view_new_with_model(GTK_TREE_MODEL(GBLisoListStore));
458     gtk_tree_view_set_search_column(GTK_TREE_VIEW(GBLisoTreeView), COLUMN_FILENAME);
459     g_object_unref(GBLisoListStore); /* destroy model automatically with view */
460     gtk_container_add(GTK_CONTAINER(scrolledWindow), GBLisoTreeView);
461     g_signal_connect(GBLisoTreeView, "row-activated", (GCallback)isoRowDblClickCbk, NULL);
462     g_signal_connect(GBLisoTreeView, "select-cursor-parent", (GCallback)isoGoUpDirTreeCbk, NULL);
463     g_signal_connect(GBLisoTreeView, "key-press-event", (GCallback)isoKeyPressedCbk, NULL);
464     /* The problem with this is that i get a popup menu before the row is selected.
465     * if i do a connect_after the handler never gets called. So no right-click menu. */
466     g_signal_connect(GBLisoTreeView, "button-press-event", (GCallback)isoButtonPressedCbk, NULL);
467     g_signal_connect(GBLisoTreeView, "button-release-event", (GCallback)isoButtonReleasedCbk, NULL);
468     gtk_widget_show(GBLisoTreeView);
469 
470     /* this won't be enabled until gtk allows me to drag a multiple selection */
471     //~ GtkTargetEntry targetEntry;
472     //~ targetEntry.target = "text/plain";
473     //~ targetEntry.flags = 0;
474     //~ targetEntry.info = 0;
475     //~ gtk_tree_view_enable_model_drag_dest(GTK_TREE_VIEW(GBLisoTreeView), &targetEntry, 1, GDK_ACTION_COPY);
476 
477     /* enable multi-line selection */
478     selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(GBLisoTreeView));
479     gtk_tree_selection_set_mode(selection, GTK_SELECTION_MULTIPLE);
480 
481     /* filename column */
482     GBLfilenameIsoColumn = gtk_tree_view_column_new();
483     gtk_tree_view_column_set_title(GBLfilenameIsoColumn, _("Name"));
484     gtk_tree_view_column_set_resizable(GBLfilenameIsoColumn, TRUE);
485 
486     renderer = gtk_cell_renderer_pixbuf_new();
487     gtk_tree_view_column_pack_start(GBLfilenameIsoColumn, renderer, FALSE);
488     gtk_tree_view_column_add_attribute(GBLfilenameIsoColumn, renderer, "pixbuf", COLUMN_ICON);
489 
490     renderer = gtk_cell_renderer_text_new();
491     /* this would fuck up usability beyond what my patience can handle */
492     //~ g_object_set(renderer, "editable", TRUE, NULL);
493     gtk_tree_view_column_pack_start(GBLfilenameIsoColumn, renderer, TRUE);
494     gtk_tree_view_column_add_attribute(GBLfilenameIsoColumn, renderer, "text", COLUMN_FILENAME);
495 
496     gtk_tree_view_column_set_sort_column_id(GBLfilenameIsoColumn, COLUMN_FILENAME);
497     gtk_tree_view_column_set_expand(GBLfilenameIsoColumn, TRUE);
498     gtk_tree_view_append_column(GTK_TREE_VIEW(GBLisoTreeView), GBLfilenameIsoColumn);
499 
500     gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(GBLisoListStore), COLUMN_FILENAME,
501                                     sortByName, NULL, NULL);
502 
503     /* size column */
504     column = gtk_tree_view_column_new();
505     renderer = gtk_cell_renderer_text_new();
506     gtk_tree_view_column_set_title(column, _("Size"));
507     gtk_tree_view_column_pack_start(column, renderer, FALSE);
508     gtk_tree_view_column_add_attribute(column, renderer, "text", COLUMN_SIZE);
509     gtk_tree_view_column_set_cell_data_func(column, renderer, sizeCellDataFunc32, NULL, NULL);
510     gtk_tree_view_column_set_sort_column_id(column, COLUMN_SIZE);
511     gtk_tree_view_append_column(GTK_TREE_VIEW(GBLisoTreeView), column);
512 
513     gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(GBLisoListStore), COLUMN_SIZE,
514                                     sortBySize, NULL, NULL);
515 
516     /* set default sort */
517     gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(GBLisoListStore),
518                                          GBLappSettings.isoSortColumnId,
519                                          GBLappSettings.isoSortDirection);
520 
521     gtk_widget_set_sensitive(GBLisoCurrentDirField, FALSE);
522     gtk_widget_set_sensitive(GBLisoTreeView, FALSE);
523 }
524 
buildIsoLocator(GtkWidget * boxToPackInto)525 void buildIsoLocator(GtkWidget* boxToPackInto)
526 {
527     GBLisoCurrentDirField = gtk_entry_new();
528     //gtk_entry_set_editable(GTK_ENTRY(GBLisoCurrentDirField), FALSE);
529     g_signal_connect(GBLisoCurrentDirField, "activate", (GCallback)acceptIsoPathCbk, NULL);
530     gtk_box_pack_start(GTK_BOX(boxToPackInto), GBLisoCurrentDirField, FALSE, FALSE, 0);
531     gtk_widget_show(GBLisoCurrentDirField);
532 }
533 
cancelOperation(GtkDialog * dialog,gint arg1,gpointer user_data)534 void cancelOperation(GtkDialog* dialog, gint arg1, gpointer user_data)
535 {
536     bk_cancel_operation(&GBLvolInfo);
537     GBLoperationCanceled = true;
538 }
539 
changeIsoDirectory(const char * newDirStr)540 void changeIsoDirectory(const char* newDirStr)
541 {
542     int rc;
543     BkDir* newDir;
544     BkFileBase* child;
545     GtkTreeIter listIterator;
546     GtkTreeModel* model;
547     GtkWidget* warningDialog;
548 
549     rc = bk_get_dir_from_string(&GBLvolInfo, newDirStr, &newDir);
550     if(rc <= 0)
551     {
552         warningDialog = gtk_message_dialog_new(GTK_WINDOW(GBLmainWindow),
553                                                GTK_DIALOG_DESTROY_WITH_PARENT,
554                                                GTK_MESSAGE_ERROR,
555                                                GTK_BUTTONS_CLOSE,
556                                                _("Failed to change directory: '%s'"),
557                                                bk_get_error_string(rc));
558         gtk_window_set_modal(GTK_WINDOW(warningDialog), TRUE);
559         gtk_dialog_run(GTK_DIALOG(warningDialog));
560         gtk_widget_destroy(warningDialog);
561         return;
562     }
563 
564     /* for improved performance disconnect the model from tree view before udating it */
565     model = gtk_tree_view_get_model(GTK_TREE_VIEW(GBLisoTreeView));
566     g_object_ref(model);
567     gtk_tree_view_set_model(GTK_TREE_VIEW(GBLisoTreeView), NULL);
568 
569     /* this is the only way to disable sorting (for a huge performance boost) */
570     gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(GBLfsListStore), COLUMN_FILENAME,
571                                     sortVoid, NULL, NULL);
572     gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(GBLfsListStore), COLUMN_SIZE,
573                                     sortVoid, NULL, NULL);
574 
575     gtk_list_store_clear(GBLisoListStore);
576 
577 #if GTK_MINOR_VERSION >= 8
578     /* to make sure width of filename column isn't bigger than needed (need gtk 2.8) */
579     gtk_tree_view_column_queue_resize(GBLfilenameIsoColumn);
580 #endif
581 
582     /* add all directories to the tree */
583     child = newDir->children;
584     while(child != NULL)
585     {
586         if(IS_DIR(child->posixFileMode))
587         /* directory */
588         {
589             gtk_list_store_append(GBLisoListStore, &listIterator);
590             gtk_list_store_set(GBLisoListStore, &listIterator,
591                                COLUMN_ICON, GBLdirPixbuf,
592                                COLUMN_FILENAME, child->name,
593                                COLUMN_SIZE, 0,
594                                COLUMN_HIDDEN_TYPE, FILE_TYPE_DIRECTORY,
595                                -1);
596         }
597         else if(IS_REG_FILE(child->posixFileMode))
598         {
599             gtk_list_store_append(GBLisoListStore, &listIterator);
600             gtk_list_store_set(GBLisoListStore, &listIterator,
601                                COLUMN_ICON, GBLfilePixbuf,
602                                COLUMN_FILENAME, child->name,
603                                COLUMN_SIZE, (BK_FILE_PTR(child))->size,
604                                COLUMN_HIDDEN_TYPE, FILE_TYPE_REGULAR,
605                                -1);
606         }
607         else if(IS_SYMLINK(child->posixFileMode))
608         {
609             gtk_list_store_append(GBLisoListStore, &listIterator);
610             gtk_list_store_set(GBLisoListStore, &listIterator,
611                                COLUMN_ICON, GBLfilePixbuf,
612                                COLUMN_FILENAME, child->name,
613                                COLUMN_SIZE, 0,
614                                COLUMN_HIDDEN_TYPE, FILE_TYPE_SYMLINK,
615                                -1);
616         }
617 
618         child = child->next;
619     }
620 
621     /* reconnect the model and view now */
622     gtk_tree_view_set_model(GTK_TREE_VIEW(GBLisoTreeView), model);
623     g_object_unref(model);
624 
625     /* reenable sorting */
626     gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(GBLfsListStore), COLUMN_FILENAME,
627                                     sortByName, NULL, NULL);
628     gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(GBLfsListStore), COLUMN_SIZE,
629                                     sortBySize, NULL, NULL);
630 
631     /* set current directory string */
632     if(GBLisoCurrentDir != NULL)
633         free(GBLisoCurrentDir);
634     GBLisoCurrentDir = (char*)malloc(strlen(newDirStr) + 1);
635     if(GBLisoCurrentDir == NULL)
636         fatalError("changeIsoDirectory(): malloc(strlen(newDirStr) + 1) failed");
637     strcpy(GBLisoCurrentDir, newDirStr);
638 
639     /* update the field with the path and name */
640     gtk_entry_set_text(GTK_ENTRY(GBLisoCurrentDirField), GBLisoCurrentDir);
641 }
642 
changePermissionsBtnCbk(GtkMenuItem * menuitem,gpointer data)643 void changePermissionsBtnCbk(GtkMenuItem *menuitem, gpointer data)
644 {
645     GtkTreeSelection* selection;
646 
647     /* do nothing if no image open */
648     if(!GBLisoPaneActive)
649         return;
650 
651     selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(GBLisoTreeView));
652 
653     int numSelectedRows = gtk_tree_selection_count_selected_rows(selection);
654 
655     if(numSelectedRows == 1)
656         gtk_tree_selection_selected_foreach(selection, changePermissionsRowCbk, NULL);
657     else
658     {
659         GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(GBLisoTreeView));
660         GList* rowsList = gtk_tree_selection_get_selected_rows(selection, NULL);
661         mode_t permissions;
662         bool firstRow = true;
663         bool cancelled = false;
664 
665         GList* row = rowsList;
666         while(row != NULL && !cancelled)
667         {
668             GtkTreeIter iter;
669             char* itemName;
670             char* fullItemName;
671 
672             gtk_tree_model_get_iter(model, &iter, row->data);
673             gtk_tree_model_get(model, &iter, COLUMN_FILENAME, &itemName, -1);
674 
675             fullItemName = malloc(strlen(GBLisoCurrentDir) + strlen(itemName) + 1);
676             if(fullItemName == NULL)
677                 fatalError("changePermissionsRowCbk(): malloc("
678                            "strlen(GBLisoCurrentDir) + strlen(itemName) + 1) failed (out of memory?)");
679 
680             strcpy(fullItemName, GBLisoCurrentDir);
681             strcat(fullItemName, itemName);
682 
683             if(firstRow)
684             {
685                 cancelled = !askForPermissions(fullItemName, &permissions);
686                 firstRow = false;
687             }
688 
689             if(!cancelled)
690             {
691                 bk_set_permissions(&GBLvolInfo, fullItemName, permissions);
692                 GBLisoChangesProbable = true;
693             }
694 
695             g_free(itemName);
696             free(fullItemName);
697             row = row->next;
698         }
699 
700         g_list_foreach(rowsList, (GFunc)gtk_tree_path_free, NULL);
701         g_list_free(rowsList);
702     } // multiple rows
703 }
704 
changePermissionsRowCbk(GtkTreeModel * model,GtkTreePath * path,GtkTreeIter * iterator,gpointer data)705 void changePermissionsRowCbk(GtkTreeModel* model, GtkTreePath* path,
706                              GtkTreeIter* iterator, gpointer data)
707 {
708     char* itemName;
709     char* fullItemName;
710     mode_t permissions;
711 
712     gtk_tree_model_get(model, iterator, COLUMN_FILENAME, &itemName, -1);
713 
714     fullItemName = malloc(strlen(GBLisoCurrentDir) + strlen(itemName) + 1);
715     if(fullItemName == NULL)
716         fatalError("changePermissionsRowCbk(): malloc("
717                    "strlen(GBLisoCurrentDir) + strlen(itemName) + 1) failed (out of memory?)");
718 
719     strcpy(fullItemName, GBLisoCurrentDir);
720     strcat(fullItemName, itemName);
721 
722     if(askForPermissions(fullItemName, &permissions))
723     {
724         bk_set_permissions(&GBLvolInfo, fullItemName, permissions);
725         GBLisoChangesProbable = true;
726     }
727 
728     g_free(itemName);
729     free(fullItemName);
730 }
731 
732 
closeIso(void)733 void closeIso(void)
734 {
735     if(!GBLisoPaneActive)
736     /* no image open or created, nothing to do */
737         return;
738 
739     gtk_list_store_clear(GBLisoListStore);
740 
741     bk_destroy_vol_info(&GBLvolInfo);
742 
743     GBLisoSize = 0;
744     gtk_label_set_text(GTK_LABEL(GBLisoSizeLbl), "");
745 
746     gtk_window_set_title(GTK_WINDOW(GBLmainWindow), "ISO Master");
747 
748     gtk_widget_set_sensitive(GBLisoCurrentDirField, FALSE);
749     gtk_widget_set_sensitive(GBLisoTreeView, FALSE);
750 
751     GBLisoPaneActive = false;
752 
753 #ifdef ENABLE_SAVE_OVERWRITE
754     if(openIsoPathAndName != NULL)
755     {
756         free(openIsoPathAndName);
757         openIsoPathAndName = NULL;
758     }
759 #endif
760 }
761 
confirmCloseIso(void)762 bool confirmCloseIso(void)
763 {
764     GtkWidget* warningDialog;
765     gint response;
766 
767     warningDialog = gtk_message_dialog_new(GTK_WINDOW(GBLmainWindow),
768                                            GTK_DIALOG_DESTROY_WITH_PARENT,
769                                            GTK_MESSAGE_QUESTION,
770                                            GTK_BUTTONS_NONE,
771                                            _("It seems that you have made changes to the ISO but "
772                                            "haven't saved them. Are you sure you want to close it?"));
773     gtk_dialog_add_buttons(GTK_DIALOG(warningDialog),
774                            GTK_STOCK_GO_BACK, GTK_RESPONSE_CANCEL,
775                            GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE,
776                            NULL);
777     gtk_window_set_modal(GTK_WINDOW(warningDialog), TRUE);
778     gtk_dialog_set_default_response(GTK_DIALOG(warningDialog), GTK_RESPONSE_CLOSE);
779     response = gtk_dialog_run(GTK_DIALOG(warningDialog));
780     gtk_widget_destroy(warningDialog);
781 
782     if(response == GTK_RESPONSE_CLOSE)
783         return true;
784     else
785         return false;
786 }
787 
deleteSelectedFromIso(void)788 void deleteSelectedFromIso(void)
789 {
790     GtkTreeSelection* selection;
791 
792     if(!GBLisoPaneActive)
793     /* no iso open */
794         return;
795 
796     selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(GBLisoTreeView));
797 
798     gtk_tree_selection_selected_foreach(selection, deleteFromIsoEachRowCbk, NULL);
799 
800     if(gtk_tree_selection_count_selected_rows(selection) > 0)
801     /* reload iso view */
802     {
803         refreshIsoView();
804     }
805 
806     /* iso size label */
807     char sizeStr[20];
808     GBLisoSize = 35845;
809     //if(GBLvolInfo.filenameTypes & FNTYPE_JOLIET)
810         GBLisoSize += 2048;
811     GBLisoSize += bk_estimate_iso_size(&GBLvolInfo, FNTYPE_9660 | FNTYPE_JOLIET | FNTYPE_ROCKRIDGE);
812     formatSize(GBLisoSize, sizeStr, sizeof(sizeStr));
813     gtk_label_set_text(GTK_LABEL(GBLisoSizeLbl), sizeStr);
814 }
815 
deleteFromIsoCbk(GtkButton * button,gpointer data)816 void deleteFromIsoCbk(GtkButton *button, gpointer data)
817 {
818     deleteSelectedFromIso();
819 }
820 
deleteFromIsoEachRowCbk(GtkTreeModel * model,GtkTreePath * path,GtkTreeIter * iterator,gpointer data)821 void deleteFromIsoEachRowCbk(GtkTreeModel* model, GtkTreePath* path,
822                              GtkTreeIter* iterator, gpointer data)
823 {
824     int fileType;
825     char* itemName;
826     char* fullItemName; /* with full path */
827     int rc;
828     GtkWidget* warningDialog;
829 
830     gtk_tree_model_get(model, iterator, COLUMN_HIDDEN_TYPE, &fileType,
831                                         COLUMN_FILENAME, &itemName, -1);
832 
833     if(fileType == FILE_TYPE_DIRECTORY || fileType == FILE_TYPE_REGULAR ||
834        fileType == FILE_TYPE_SYMLINK)
835     {
836         fullItemName = (char*)malloc(strlen(GBLisoCurrentDir) + strlen(itemName) + 1);
837         if(fullItemName == NULL)
838             fatalError("deleteFromIsoEachRowCbk(): malloc("
839                        "strlen(GBLisoCurrentDir) + strlen(itemName) + 1) failed");
840 
841         strcpy(fullItemName, GBLisoCurrentDir);
842         strcat(fullItemName, itemName);
843 
844         rc = bk_delete(&GBLvolInfo, fullItemName);
845         if(rc <= 0)
846         {
847             warningDialog = gtk_message_dialog_new(GTK_WINDOW(GBLmainWindow),
848                                                    GTK_DIALOG_DESTROY_WITH_PARENT,
849                                                    GTK_MESSAGE_ERROR,
850                                                    GTK_BUTTONS_CLOSE,
851                                                    _("Failed to delete '%s': '%s'"),
852                                                    itemName,
853                                                    bk_get_error_string(rc));
854             gtk_window_set_modal(GTK_WINDOW(warningDialog), TRUE);
855             gtk_dialog_run(GTK_DIALOG(warningDialog));
856             gtk_widget_destroy(warningDialog);
857         }
858         else
859             GBLisoChangesProbable = true;
860 
861         free(fullItemName);
862     }
863     else
864     {
865         warningDialog = gtk_message_dialog_new(GTK_WINDOW(GBLmainWindow),
866                                                GTK_DIALOG_DESTROY_WITH_PARENT,
867                                                GTK_MESSAGE_ERROR,
868                                                GTK_BUTTONS_CLOSE,
869                                                _("GUI error, deleting anything other than "
870                                                "files and directories doesn't work"));
871         gtk_window_set_modal(GTK_WINDOW(warningDialog), TRUE);
872         gtk_dialog_run(GTK_DIALOG(warningDialog));
873         gtk_widget_destroy(warningDialog);
874     }
875 
876     g_free(itemName);
877 }
878 
extractFromIsoCbk(GtkButton * button,gpointer data)879 void extractFromIsoCbk(GtkButton *button, gpointer data)
880 {
881     GtkTreeSelection* selection;
882     GtkWidget* progressWindow = NULL;
883     GtkWidget* descriptionLabel;
884 
885     if(!GBLisoPaneActive)
886     /* no iso open */
887         return;
888 
889     selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(GBLisoTreeView));
890 
891     if(gtk_tree_selection_count_selected_rows(selection) > 0)
892     {
893         /* dialog window for the progress bar */
894         progressWindow = gtk_dialog_new();
895         gtk_dialog_set_has_separator(GTK_DIALOG(progressWindow), FALSE);
896         gtk_window_set_modal(GTK_WINDOW(progressWindow), TRUE);
897         gtk_window_set_title(GTK_WINDOW(progressWindow), _("Progress"));
898         gtk_window_set_transient_for(GTK_WINDOW(progressWindow), GTK_WINDOW(GBLmainWindow));
899         g_signal_connect_swapped(progressWindow, "delete-event",
900                                  G_CALLBACK(activityProgressWindowDeleteCbk), NULL);
901         g_signal_connect_swapped(progressWindow, "response",
902                                  G_CALLBACK(cancelOperation), NULL);
903 
904         /* just some text */
905         descriptionLabel = gtk_label_new(_("Please wait while I'm extracting the selected files..."));
906         gtk_box_pack_start(GTK_BOX(GTK_DIALOG(progressWindow)->vbox), descriptionLabel, TRUE, TRUE, 0);
907         gtk_widget_show(descriptionLabel);
908 
909         /* the progress bar */
910         GBLactivityProgressBar = gtk_progress_bar_new();
911         gtk_box_pack_start(GTK_BOX(GTK_DIALOG(progressWindow)->vbox), GBLactivityProgressBar, TRUE, TRUE, 0);
912         gtk_widget_show(GBLactivityProgressBar);
913 
914         /* button to cancel extracting */
915         gtk_dialog_add_button(GTK_DIALOG(progressWindow), GTK_STOCK_CANCEL, GTK_RESPONSE_NONE);
916 
917         /* if i show it before i add the children, the window ends up being not centered */
918         gtk_widget_show(progressWindow);
919 
920         GBLoperationCanceled = false;
921 
922         gtk_tree_selection_selected_foreach(selection, extractFromIsoEachRowCbk, NULL);
923 
924         refreshFsView();
925 
926         gtk_widget_destroy(progressWindow);
927     }
928 
929     GBLactivityProgressBar = NULL;
930 }
931 
extractFromIsoEachRowCbk(GtkTreeModel * model,GtkTreePath * path,GtkTreeIter * iterator,gpointer data)932 void extractFromIsoEachRowCbk(GtkTreeModel* model, GtkTreePath* path,
933                               GtkTreeIter* iterator, gpointer data)
934 {
935     int fileType;
936     char* itemName;
937     char* fullItemName; /* with full path */
938     int rc;
939     GtkWidget* warningDialog;
940 
941     if(GBLoperationCanceled)
942         return;
943 
944     gtk_tree_model_get(model, iterator, COLUMN_HIDDEN_TYPE, &fileType,
945                                         COLUMN_FILENAME, &itemName, -1);
946 
947     fullItemName = (char*)malloc(strlen(GBLisoCurrentDir) + strlen(itemName) + 1);
948     if(fullItemName == NULL)
949         fatalError("extractFromIsoEachRowCbk(): malloc("
950                    "strlen(GBLisoCurrentDir) + strlen(itemName) + 1) failed (out of memory?)");
951 
952     strcpy(fullItemName, GBLisoCurrentDir);
953     strcat(fullItemName, itemName);
954 
955     rc = bk_extract(&GBLvolInfo, fullItemName, GBLfsCurrentDir,
956                     true, activityProgressUpdaterCbk);
957     if(rc <= 0)
958     {
959         warningDialog = gtk_message_dialog_new(GTK_WINDOW(GBLmainWindow),
960                                                GTK_DIALOG_DESTROY_WITH_PARENT,
961                                                GTK_MESSAGE_ERROR,
962                                                GTK_BUTTONS_CLOSE,
963                                                _("Failed to extract '%s': '%s'"),
964                                                itemName,
965                                                bk_get_error_string(rc));
966         gtk_window_set_modal(GTK_WINDOW(warningDialog), TRUE);
967         gtk_dialog_run(GTK_DIALOG(warningDialog));
968         gtk_widget_destroy(warningDialog);
969     }
970 
971     free(fullItemName);
972 
973     g_free(itemName);
974 }
975 
976 /******************************************************************************
977 * isoButtonPressedCbk()
978 * Make sure that a right-click on the view doesn't send the signal to the
979 * widget. If it did, a selection of multiple rows would be lost.
980 * I have a feeling someone did this shit in GTK just to piss on users */
isoButtonPressedCbk(GtkWidget * isoView,GdkEventButton * event,gpointer user_data)981 gboolean isoButtonPressedCbk(GtkWidget* isoView, GdkEventButton* event, gpointer user_data)
982 {
983     if(!GBLisoPaneActive)
984     /* no iso open */
985         return FALSE;
986 
987     if(event->type == GDK_BUTTON_PRESS  &&  event->button == 3)
988     {
989         /* Stop event propagation */
990         /*!! Would be nice if I could only stop event propagation if click was on
991         * the selection, I have to look into how that may be done, if at all */
992         return TRUE;
993     }
994 
995     return FALSE;
996 }
997 
998 /******************************************************************************
999 * isoButtonReleasedCbk()
1000 * Show context menu if releasing the right mouse button */
isoButtonReleasedCbk(GtkWidget * isoView,GdkEventButton * event,gpointer user_data)1001 gboolean isoButtonReleasedCbk(GtkWidget* isoView, GdkEventButton* event, gpointer user_data)
1002 {
1003     if(!GBLisoPaneActive)
1004     /* no iso open */
1005         return FALSE;
1006 
1007     if(event->type == GDK_BUTTON_RELEASE &&  event->button == 3)
1008     {
1009         showIsoContextMenu(isoView, event);
1010     }
1011 
1012     return FALSE;
1013 }
1014 
1015 /* this is called from a button and via a treeview event so don't use the parameters */
isoGoUpDirTreeCbk(GtkButton * button,gpointer data)1016 void isoGoUpDirTreeCbk(GtkButton *button, gpointer data)
1017 {
1018     int count;
1019     bool done;
1020     char* newCurrentDir;
1021     GtkWidget* warningDialog;
1022 
1023     /* do nothing if no image open */
1024     if(!GBLisoPaneActive)
1025         return;
1026 
1027     /* do nothing if already at root */
1028     if(GBLisoCurrentDir[0] == '/' && GBLisoCurrentDir[1] == '\0')
1029         return;
1030 
1031     /* need to allocate a new string because changeIsoDirectory() uses it
1032     * to copy from after freeing GBLisoCurrentDir */
1033     newCurrentDir = (char*)malloc(strlen(GBLisoCurrentDir) + 1);
1034     if(GBLisoCurrentDir == NULL)
1035         fatalError("isoGoUpDirTree(): malloc(strlen(GBLisoCurrentDir) + 1) failed");
1036     strcpy(newCurrentDir, GBLisoCurrentDir);
1037 
1038     /* look for the second last slash */
1039     done = false;
1040     for(count = strlen(newCurrentDir) - 1; !done && count >= 0; count--)
1041     {
1042         if(newCurrentDir[count - 1] == '/')
1043         /* truncate the string */
1044         {
1045             newCurrentDir[count] = '\0';
1046             changeIsoDirectory(newCurrentDir);
1047             done = true;
1048         }
1049     }
1050 
1051     if(!done)
1052     {
1053         warningDialog = gtk_message_dialog_new(GTK_WINDOW(GBLmainWindow),
1054                                                GTK_DIALOG_DESTROY_WITH_PARENT,
1055                                                GTK_MESSAGE_ERROR,
1056                                                GTK_BUTTONS_CLOSE,
1057                                                "GUI error, GBLisoCurrentDir is not '/' and has "
1058                                                "only one slash, please report bug.");
1059         gtk_window_set_modal(GTK_WINDOW(warningDialog), TRUE);
1060         gtk_dialog_run(GTK_DIALOG(warningDialog));
1061         gtk_widget_destroy(warningDialog);
1062     }
1063 
1064     free(newCurrentDir);
1065 }
1066 
isoKeyPressedCbk(GtkWidget * widget,GdkEventKey * event,gpointer user_data)1067 gboolean isoKeyPressedCbk(GtkWidget* widget, GdkEventKey* event, gpointer user_data)
1068 {
1069     if(event->keyval == GDK_Delete)
1070     {
1071         deleteFromIsoCbk(NULL, NULL);
1072 
1073         return TRUE;
1074     }
1075 
1076     return FALSE;
1077 }
1078 
isoRowDblClickCbk(GtkTreeView * treeview,GtkTreePath * path,GtkTreeViewColumn * col,gpointer data)1079 void isoRowDblClickCbk(GtkTreeView* treeview, GtkTreePath* path,
1080                        GtkTreeViewColumn* col, gpointer data)
1081 {
1082     GtkTreeModel* model;
1083     GtkTreeIter iterator;
1084     char* name;
1085     char* newCurrentDir;
1086     int fileType;
1087     GtkWidget* warningDialog;
1088 
1089     model = gtk_tree_view_get_model(treeview);
1090 
1091     if(gtk_tree_model_get_iter(model, &iterator, path) == FALSE)
1092     {
1093         warningDialog = gtk_message_dialog_new(GTK_WINDOW(GBLmainWindow),
1094                                                GTK_DIALOG_DESTROY_WITH_PARENT,
1095                                                GTK_MESSAGE_ERROR,
1096                                                GTK_BUTTONS_CLOSE,
1097                                                "GUI error: 'isoRowDblClicked(): "
1098                                                "gtk_tree_model_get_iter() failed'");
1099         gtk_window_set_modal(GTK_WINDOW(warningDialog), TRUE);
1100         gtk_dialog_run(GTK_DIALOG(warningDialog));
1101         gtk_widget_destroy(warningDialog);
1102         return;
1103     }
1104 
1105     gtk_tree_model_get(model, &iterator, COLUMN_HIDDEN_TYPE, &fileType, -1);
1106     if(fileType == FILE_TYPE_DIRECTORY)
1107     {
1108         gtk_tree_model_get(model, &iterator, COLUMN_FILENAME, &name, -1);
1109 
1110         newCurrentDir = (char*)malloc(strlen(GBLisoCurrentDir) + strlen(name) + 2);
1111         if(newCurrentDir == NULL)
1112             fatalError("isoRowDblClicked(): malloc("
1113                        "strlen(GBLisoCurrentDir) + strlen(name) + 2) failed");
1114 
1115         strcpy(newCurrentDir, GBLisoCurrentDir);
1116         strcat(newCurrentDir, name);
1117         strcat(newCurrentDir, "/");
1118 
1119         changeIsoDirectory(newCurrentDir);
1120 
1121         free(newCurrentDir);
1122         g_free(name);
1123     }
1124     /* else do nothing (not a directory) */
1125 }
1126 
1127 /* This callback is also used by an accelerator so make sure you don't use
1128 * the parameters, since they may not be the menuitem parameters */
newIsoCbk(GtkMenuItem * menuItem,gpointer data)1129 gboolean newIsoCbk(GtkMenuItem* menuItem, gpointer data)
1130 {
1131     int rc;
1132     GtkWidget* warningDialog;
1133 
1134     if(GBLisoChangesProbable && !confirmCloseIso())
1135         return TRUE;
1136 
1137     closeIso();
1138 
1139     rc = bk_init_vol_info(&GBLvolInfo, GBLappSettings.scanForDuplicateFiles);
1140     if(rc <= 0)
1141     {
1142         warningDialog = gtk_message_dialog_new(GTK_WINDOW(GBLmainWindow),
1143                                                GTK_DIALOG_DESTROY_WITH_PARENT,
1144                                                GTK_MESSAGE_ERROR,
1145                                                GTK_BUTTONS_CLOSE,
1146                                                _("Failed to initialise bkisofs: '%s'"),
1147                                                bk_get_error_string(rc));
1148         gtk_window_set_modal(GTK_WINDOW(warningDialog), TRUE);
1149         gtk_dialog_run(GTK_DIALOG(warningDialog));
1150         gtk_widget_destroy(warningDialog);
1151         return TRUE;
1152     }
1153 
1154     GBLvolInfo.warningCbk = operationFailed;
1155 
1156     GBLappSettings.filenameTypesToWrite = FNTYPE_9660 | FNTYPE_ROCKRIDGE | FNTYPE_JOLIET;
1157 
1158     /* iso size label */
1159     char sizeStr[20];
1160     GBLisoSize = 35845;
1161     //if(GBLvolInfo.filenameTypes & FNTYPE_JOLIET)
1162         GBLisoSize += 2048;
1163     GBLisoSize += bk_estimate_iso_size(&GBLvolInfo, FNTYPE_9660 | FNTYPE_JOLIET | FNTYPE_ROCKRIDGE);
1164     formatSize(GBLisoSize, sizeStr, sizeof(sizeStr));
1165     gtk_label_set_text(GTK_LABEL(GBLisoSizeLbl), sizeStr);
1166 
1167     gtk_widget_set_sensitive(GBLisoCurrentDirField, TRUE);
1168     gtk_widget_set_sensitive(GBLisoTreeView, TRUE);
1169 
1170     GBLisoPaneActive = true;
1171 
1172     GBLisoChangesProbable = false;
1173 
1174     changeIsoDirectory("/");
1175 
1176     /* the accelerator callback must return true */
1177     return TRUE;
1178 }
1179 
openIso(char * filename)1180 void openIso(char* filename)
1181 {
1182     int rc;
1183     GtkWidget* warningDialog;
1184 
1185     /* MAYBE move around in recently open list */
1186     int alreadyInListIndex = -1;
1187     for(int i = 0; i < 5; i++)
1188     {
1189         const char* oldText = gtk_label_get_text(GTK_LABEL(
1190                 gtk_bin_get_child(GTK_BIN(GBLrecentlyOpenWidgets[i]))));
1191         if(strcmp(oldText, filename) == 0)
1192             alreadyInListIndex = i;
1193     }
1194     //!! flipping them is weird, what's really needed is to put the found
1195     // one up and push everything else down once, but that's too much work
1196     // so for now just add to the list if it's not already there, and do
1197     // nothing otherwise
1198     //~ if(alreadyInListIndex != -1)
1199     //~ {
1200         //~ const char* oldFirst = gtk_label_get_text(GTK_LABEL(
1201                 //~ gtk_bin_get_child(GTK_BIN(GBLrecentlyOpenWidgets[0]))));
1202 
1203         //~ // flip the two
1204         //~ printf("flip '%s' '%s'\n", oldFirst, gtk_label_get_text(GTK_LABEL(
1205                     //~ gtk_bin_get_child(GTK_BIN(GBLrecentlyOpenWidgets[alreadyInListIndex])))));
1206         //~ gtk_label_set_text(GTK_LABEL(
1207                     //~ gtk_bin_get_child(GTK_BIN(GBLrecentlyOpenWidgets[alreadyInListIndex]))),
1208                     //~ oldFirst);
1209         //~ gtk_label_set_text(GTK_LABEL(
1210                     //~ gtk_bin_get_child(GTK_BIN(GBLrecentlyOpenWidgets[0]))),
1211                     //~ filename);
1212     //~ }
1213     /* END MAYBE move around in recently open list */
1214 
1215     /* MAYBE record recently open */
1216     if(alreadyInListIndex == -1)
1217     {
1218         // move all existing ones down once
1219         for(int i = 4; i > 0; i--)
1220         {
1221             const char* oldText = gtk_label_get_text(GTK_LABEL(
1222                     gtk_bin_get_child(GTK_BIN(GBLrecentlyOpenWidgets[i - 1]))));
1223             gtk_label_set_text(GTK_LABEL(
1224                     gtk_bin_get_child(GTK_BIN(GBLrecentlyOpenWidgets[i]))),
1225                     oldText);
1226             if(oldText[0] != '\0')
1227                 gtk_widget_show(GBLrecentlyOpenWidgets[i]);
1228         }
1229         gtk_label_set_text(GTK_LABEL(
1230                     gtk_bin_get_child(GTK_BIN(GBLrecentlyOpenWidgets[0]))),
1231                     filename);
1232         gtk_widget_show(GBLrecentlyOpenWidgets[0]);
1233     }
1234     /* END MAYBE record recently open */
1235 
1236     if(GBLisoChangesProbable && !confirmCloseIso())
1237         return;
1238 
1239     closeIso();
1240 
1241     rc = bk_init_vol_info(&GBLvolInfo, GBLappSettings.scanForDuplicateFiles);
1242     if(rc <= 0)
1243     {
1244         warningDialog = gtk_message_dialog_new(GTK_WINDOW(GBLmainWindow),
1245                                                GTK_DIALOG_DESTROY_WITH_PARENT,
1246                                                GTK_MESSAGE_ERROR,
1247                                                GTK_BUTTONS_CLOSE,
1248                                                _("Failed to initialise bkisofs: '%s'"),
1249                                                bk_get_error_string(rc));
1250         gtk_window_set_modal(GTK_WINDOW(warningDialog), TRUE);
1251         gtk_dialog_run(GTK_DIALOG(warningDialog));
1252         gtk_widget_destroy(warningDialog);
1253         return;
1254     }
1255 
1256     GBLvolInfo.warningCbk = operationFailed;
1257 
1258     GBLappSettings.filenameTypesToWrite = FNTYPE_9660 | FNTYPE_ROCKRIDGE | FNTYPE_JOLIET;
1259 
1260     rc = bk_open_image(&GBLvolInfo, filename);
1261     if(rc <= 0)
1262     {
1263         warningDialog = gtk_message_dialog_new(GTK_WINDOW(GBLmainWindow),
1264                                                GTK_DIALOG_DESTROY_WITH_PARENT,
1265                                                GTK_MESSAGE_ERROR,
1266                                                GTK_BUTTONS_CLOSE,
1267                                                _("Failed to open iso file for reading: '%s'"),
1268                                                bk_get_error_string(rc));
1269         gtk_window_set_modal(GTK_WINDOW(warningDialog), TRUE);
1270         gtk_dialog_run(GTK_DIALOG(warningDialog));
1271         gtk_widget_destroy(warningDialog);
1272         return;
1273     }
1274 
1275     rc = bk_read_vol_info(&GBLvolInfo);
1276     if(rc <= 0)
1277     {
1278         warningDialog = gtk_message_dialog_new(GTK_WINDOW(GBLmainWindow),
1279                                                GTK_DIALOG_DESTROY_WITH_PARENT,
1280                                                GTK_MESSAGE_ERROR,
1281                                                GTK_BUTTONS_CLOSE,
1282                                                _("Failed to read volume info: '%s'"),
1283                                                bk_get_error_string(rc));
1284         gtk_window_set_modal(GTK_WINDOW(warningDialog), TRUE);
1285         gtk_dialog_run(GTK_DIALOG(warningDialog));
1286         gtk_widget_destroy(warningDialog);
1287         closeIso();
1288         return;
1289     }
1290 
1291     /* CREATE and show progress bar */
1292     GtkWidget* progressWindow;
1293     GtkWidget* label;
1294 
1295     /* dialog window for the progress bar */
1296     progressWindow = gtk_dialog_new();
1297     gtk_dialog_set_has_separator(GTK_DIALOG(progressWindow), FALSE);
1298     gtk_window_set_modal(GTK_WINDOW(progressWindow), TRUE);
1299     gtk_window_set_title(GTK_WINDOW(progressWindow), _("Progress"));
1300     gtk_window_set_transient_for(GTK_WINDOW(progressWindow), GTK_WINDOW(GBLmainWindow));
1301     g_signal_connect_swapped(progressWindow, "delete-event",
1302                              G_CALLBACK(activityProgressWindowDeleteCbk), NULL);
1303     g_signal_connect_swapped(progressWindow, "response",
1304                              G_CALLBACK(cancelOperation), NULL);
1305 
1306     label = gtk_label_new(_("Please wait while I'm reading the image..."));
1307     gtk_box_pack_start(GTK_BOX(GTK_DIALOG(progressWindow)->vbox), label, TRUE, TRUE, 0);
1308     gtk_widget_show(label);
1309 
1310     if(GBLappSettings.scanForDuplicateFiles)
1311     {
1312         label = gtk_label_new(_("(scanning for duplicate files)"));
1313         gtk_box_pack_start(GTK_BOX(GTK_DIALOG(progressWindow)->vbox), label, TRUE, TRUE, 0);
1314         gtk_widget_show(label);
1315     }
1316 
1317     /* the progress bar */
1318     GBLactivityProgressBar = gtk_progress_bar_new();
1319     gtk_box_pack_start(GTK_BOX(GTK_DIALOG(progressWindow)->vbox), GBLactivityProgressBar, TRUE, TRUE, 0);
1320     gtk_widget_show(GBLactivityProgressBar);
1321 
1322     /* button to cancel adding */
1323     gtk_dialog_add_button(GTK_DIALOG(progressWindow), GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
1324 
1325     /* if i show it before i add the children, the window ends up being not centered */
1326     gtk_widget_show(progressWindow);
1327     /* END CREATE and show progress bar */
1328 
1329     /* READ entire directory tree */
1330     if(GBLvolInfo.filenameTypes & FNTYPE_ROCKRIDGE)
1331         rc = bk_read_dir_tree(&GBLvolInfo, FNTYPE_ROCKRIDGE, true, activityProgressUpdaterCbk);
1332     else if(GBLvolInfo.filenameTypes & FNTYPE_JOLIET)
1333         rc = bk_read_dir_tree(&GBLvolInfo, FNTYPE_JOLIET, false, activityProgressUpdaterCbk);
1334     else
1335         rc = bk_read_dir_tree(&GBLvolInfo, FNTYPE_9660, false, activityProgressUpdaterCbk);
1336     if(rc <= 0)
1337     {
1338         warningDialog = gtk_message_dialog_new(GTK_WINDOW(GBLmainWindow),
1339                                                GTK_DIALOG_DESTROY_WITH_PARENT,
1340                                                GTK_MESSAGE_ERROR,
1341                                                GTK_BUTTONS_CLOSE,
1342                                                _("Failed to read directory tree: '%s'"),
1343                                                bk_get_error_string(rc));
1344         gtk_window_set_modal(GTK_WINDOW(warningDialog), TRUE);
1345         gtk_dialog_run(GTK_DIALOG(warningDialog));
1346         gtk_widget_destroy(warningDialog);
1347     }
1348     /* END READ entire directory tree */
1349 
1350     gtk_widget_destroy(progressWindow);
1351     GBLactivityProgressBar = NULL;
1352 
1353     if(rc <= 0)
1354     {
1355         closeIso();
1356         return;
1357     }
1358 
1359 #ifdef ENABLE_SAVE_OVERWRITE
1360     openIsoPathAndName = malloc(strlen(filename) + 1);
1361     strcpy(openIsoPathAndName, filename);
1362 #endif
1363 
1364     /* iso size label */
1365     char sizeStr[20];
1366     GBLisoSize = 35845;
1367     //if(GBLvolInfo.filenameTypes & FNTYPE_JOLIET)
1368         GBLisoSize += 2048;
1369 
1370     /* SET WINDOW title */
1371     int filenameLen = strlen(filename);
1372 
1373     char* windowTitle = malloc(filenameLen + strlen(" - ISO Master") + 1);
1374     if(windowTitle == NULL)
1375             fatalError("windowTitle = malloc(strlen(filename) + \" - ISO Master\" + 1) failed");
1376 
1377     int lastSlashIndex = -1;
1378     int count;
1379     for(count = 0; count < filenameLen; count++)
1380     {
1381         if(filename[count] == '/')
1382             lastSlashIndex = count;
1383     }
1384 
1385     if(lastSlashIndex == -1)
1386         strcpy(windowTitle, filename);
1387     else
1388         strcpy(windowTitle, filename + lastSlashIndex + 1);
1389     strcat(windowTitle, " - ISO Master");
1390 
1391     gtk_window_set_title(GTK_WINDOW(GBLmainWindow), windowTitle);
1392 
1393     free(windowTitle);
1394     /* END SET WINDOW title */
1395 
1396     GBLisoSize += bk_estimate_iso_size(&GBLvolInfo, FNTYPE_9660 | FNTYPE_JOLIET | FNTYPE_ROCKRIDGE);
1397     formatSize(GBLisoSize, sizeStr, sizeof(sizeStr));
1398     gtk_label_set_text(GTK_LABEL(GBLisoSizeLbl), sizeStr);
1399 
1400     gtk_widget_set_sensitive(GBLisoCurrentDirField, TRUE);
1401     gtk_widget_set_sensitive(GBLisoTreeView, TRUE);
1402 
1403     changeIsoDirectory("/");
1404 
1405     GBLisoPaneActive = true;
1406 
1407     GBLisoChangesProbable = false;
1408 }
1409 
1410 /* This callback is also used by an accelerator so make sure you don't use
1411 * the parameters, since they may not be the menuitem parameters */
openIsoCbk(GtkMenuItem * menuItem,gpointer data)1412 gboolean openIsoCbk(GtkMenuItem* menuItem, gpointer data)
1413 {
1414     GtkWidget *dialog;
1415     char* filename = NULL;
1416     GtkFileFilter* nameFilter;
1417     int dialogRespose;
1418 
1419     dialog = gtk_file_chooser_dialog_new("Open File",
1420                                          NULL,
1421                                          GTK_FILE_CHOOSER_ACTION_OPEN,
1422                                          GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
1423                                          GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
1424                                          NULL);
1425 
1426     nameFilter = gtk_file_filter_new();
1427     gtk_file_filter_add_pattern(GTK_FILE_FILTER(nameFilter), "*.[iI][sS][oO]");
1428     gtk_file_filter_set_name(GTK_FILE_FILTER(nameFilter), _("ISO Images"));
1429     gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), GTK_FILE_FILTER(nameFilter));
1430 
1431     nameFilter = gtk_file_filter_new();
1432     gtk_file_filter_add_pattern(GTK_FILE_FILTER(nameFilter), "*.[nN][rR][gG]");
1433     gtk_file_filter_set_name(GTK_FILE_FILTER(nameFilter), _("NRG Images"));
1434     gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), GTK_FILE_FILTER(nameFilter));
1435 
1436     nameFilter = gtk_file_filter_new();
1437     gtk_file_filter_add_pattern(GTK_FILE_FILTER(nameFilter), "*.[mM][dD][fF]");
1438     gtk_file_filter_set_name(GTK_FILE_FILTER(nameFilter), _("MDF Images"));
1439     gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), GTK_FILE_FILTER(nameFilter));
1440 
1441     nameFilter = gtk_file_filter_new();
1442     gtk_file_filter_add_pattern(GTK_FILE_FILTER(nameFilter), "*");
1443     gtk_file_filter_set_name(GTK_FILE_FILTER(nameFilter), _("All files"));
1444     gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), GTK_FILE_FILTER(nameFilter));
1445 
1446     if(GBLappSettings.lastIsoDir != NULL)
1447         gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), GBLappSettings.lastIsoDir);
1448 
1449     dialogRespose = gtk_dialog_run(GTK_DIALOG(dialog));
1450 
1451     if(dialogRespose == GTK_RESPONSE_ACCEPT)
1452     {
1453         filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
1454 
1455         /* RECORD last iso dir */
1456         char* lastIsoDir = gtk_file_chooser_get_current_folder(GTK_FILE_CHOOSER(dialog));
1457         if(lastIsoDir)
1458         {
1459             if(GBLappSettings.lastIsoDir != NULL && strlen(lastIsoDir) > strlen(GBLappSettings.lastIsoDir))
1460             {
1461                 free(GBLappSettings.lastIsoDir);
1462                 GBLappSettings.lastIsoDir = NULL;
1463             }
1464 
1465             if(GBLappSettings.lastIsoDir == NULL)
1466                 GBLappSettings.lastIsoDir = malloc(strlen(lastIsoDir) + 1);
1467 
1468             strcpy(GBLappSettings.lastIsoDir, lastIsoDir);
1469 
1470             g_free(lastIsoDir);
1471         }
1472         else /* e.g. when opening a file from the <Recently used> view */
1473         {
1474             free(GBLappSettings.lastIsoDir);
1475             GBLappSettings.lastIsoDir = NULL;
1476         }
1477         /* END RECORD last iso dir */
1478     }
1479 
1480     gtk_widget_destroy(dialog);
1481 
1482     if(dialogRespose == GTK_RESPONSE_ACCEPT)
1483     {
1484         openIso(filename);
1485 
1486         g_free(filename);
1487     }
1488 
1489     //~ openIso("image.iso");
1490 
1491     /* the accelerator callback must return true */
1492     return TRUE;
1493 }
1494 
openRecentIso(GtkMenuItem * menuitem,gpointer data)1495 void openRecentIso(GtkMenuItem *menuitem, gpointer data)
1496 {
1497     const char* filename = gtk_label_get_text(GTK_LABEL(
1498                     gtk_bin_get_child(GTK_BIN(menuitem))));
1499     openIso((char*)filename);
1500 }
1501 
operationFailed(const char * msg)1502 bool operationFailed(const char* msg)
1503 {
1504     GtkWidget* warningDialog;
1505     gint response;
1506 
1507     warningDialog = gtk_message_dialog_new(GTK_WINDOW(GBLmainWindow),
1508                                            GTK_DIALOG_DESTROY_WITH_PARENT,
1509                                            GTK_MESSAGE_WARNING,
1510                                            GTK_BUTTONS_YES_NO,
1511                                            _("%s\n\nDo you wish to continue?"),
1512                                            msg);
1513     gtk_window_set_modal(GTK_WINDOW(warningDialog), TRUE);
1514     gtk_dialog_set_default_response(GTK_DIALOG(warningDialog), GTK_RESPONSE_YES);
1515     response = gtk_dialog_run(GTK_DIALOG(warningDialog));
1516     gtk_widget_destroy(warningDialog);
1517 
1518     if(response == GTK_RESPONSE_YES)
1519         return true;
1520     else
1521     {
1522         GBLoperationCanceled = true;
1523         return false;
1524     }
1525 }
1526 
refreshIsoView(void)1527 void refreshIsoView(void)
1528 {
1529     char* isoCurrentDir; /* for changeIsoDirectory() */
1530 
1531     isoCurrentDir = malloc(strlen(GBLisoCurrentDir) + 1);
1532     if(isoCurrentDir == NULL)
1533         fatalError("refreshIsoView(): malloc("
1534                    "strlen(GBLisoCurrentDir) + 1) failed");
1535     strcpy(isoCurrentDir, GBLisoCurrentDir);
1536 
1537     /* remember scroll position */
1538     GdkRectangle visibleRect;
1539     gtk_tree_view_get_visible_rect(GTK_TREE_VIEW(GBLisoTreeView), &visibleRect);
1540 
1541     changeIsoDirectory(isoCurrentDir);
1542 
1543     /* need the -1 because if i call this function with the same coordinates that
1544     * the view already has, the position is set to 0. think it's a gtk bug. */
1545     gtk_tree_view_scroll_to_point(GTK_TREE_VIEW(GBLisoTreeView), visibleRect.x - 1, visibleRect.y - 1);
1546 
1547     free(isoCurrentDir);
1548 }
1549 
renameSelected(void)1550 void renameSelected(void)
1551 {
1552     GtkTreeSelection* selection;
1553 
1554     /* do nothing if no image open */
1555     if(!GBLisoPaneActive)
1556         return;
1557 
1558     selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(GBLisoTreeView));
1559 
1560     if(gtk_tree_selection_count_selected_rows(selection) != 1)
1561         return;
1562 
1563     /* there's just one row selected but this is the easiest way to do it */
1564     gtk_tree_selection_selected_foreach(selection, renameSelectedRowCbk, NULL);
1565 
1566     /* can't put this in the callback because gtk complains */
1567     refreshIsoView();
1568 }
1569 
renameSelectedRowCbk(GtkTreeModel * model,GtkTreePath * path,GtkTreeIter * iterator,gpointer data)1570 void renameSelectedRowCbk(GtkTreeModel* model, GtkTreePath* path,
1571                           GtkTreeIter* iterator, gpointer data)
1572 {
1573     GtkWidget* dialog;
1574     GtkWidget* nameField;
1575     int rc;
1576     char* itemName;
1577     char* fullItemName;
1578     GtkWidget* warningDialog;
1579 
1580     gtk_tree_model_get(model, iterator, COLUMN_FILENAME, &itemName, -1);
1581 
1582     fullItemName = (char*)malloc(strlen(GBLisoCurrentDir) + strlen(itemName) + 1);
1583     if(fullItemName == NULL)
1584         fatalError("extractFromIsoEachRowCbk(): malloc("
1585                    "strlen(GBLisoCurrentDir) + strlen(itemName) + 1) failed (out of memory?)");
1586 
1587     strcpy(fullItemName, GBLisoCurrentDir);
1588     strcat(fullItemName, itemName);
1589 
1590     dialog = gtk_dialog_new_with_buttons(_("Enter a new name:"),
1591                                          GTK_WINDOW(GBLmainWindow),
1592                                          GTK_DIALOG_DESTROY_WITH_PARENT,
1593                                          GTK_STOCK_OK,
1594                                          GTK_RESPONSE_ACCEPT,
1595                                          GTK_STOCK_CANCEL,
1596                                          GTK_RESPONSE_REJECT,
1597                                          NULL);
1598     g_signal_connect(dialog, "close", G_CALLBACK(rejectDialogCbk), NULL);
1599 
1600     nameField = gtk_entry_new_with_max_length(NCHARS_FILE_ID_MAX_STORE);
1601     gtk_entry_set_text(GTK_ENTRY(nameField), itemName);
1602     gtk_entry_set_width_chars(GTK_ENTRY(nameField), 32);
1603     g_signal_connect(nameField, "activate", (GCallback)acceptDialogCbk, dialog);
1604     gtk_widget_show(nameField);
1605     gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), nameField, TRUE, TRUE, 0);
1606 
1607     gtk_widget_show(dialog);
1608 
1609     rc = gtk_dialog_run(GTK_DIALOG(dialog));
1610     if(rc == GTK_RESPONSE_ACCEPT)
1611     {
1612         rc = bk_rename(&GBLvolInfo, fullItemName, gtk_entry_get_text(GTK_ENTRY(nameField)));
1613         if(rc < 0)
1614         {
1615             warningDialog = gtk_message_dialog_new(GTK_WINDOW(GBLmainWindow),
1616                                                    GTK_DIALOG_DESTROY_WITH_PARENT,
1617                                                    GTK_MESSAGE_ERROR,
1618                                                    GTK_BUTTONS_CLOSE,
1619                                                    _("Failed to rename '%s': %s"),
1620                                                    itemName,
1621                                                    bk_get_error_string(rc));
1622             gtk_window_set_modal(GTK_WINDOW(warningDialog), TRUE);
1623             gtk_dialog_run(GTK_DIALOG(warningDialog));
1624             gtk_widget_destroy(warningDialog);
1625         }
1626         else
1627             GBLisoChangesProbable = true;
1628     }
1629 
1630     gtk_widget_destroy(dialog);
1631 
1632     g_free(itemName);
1633     free(fullItemName);
1634 }
1635 
renameSelectedBtnCbk(GtkMenuItem * menuitem,gpointer data)1636 void renameSelectedBtnCbk(GtkMenuItem *menuitem, gpointer data)
1637 {
1638     /* because I'm lazy just call this one, it will work */
1639     renameSelected();
1640 }
1641 
saveIso(char * filename)1642 void saveIso(char* filename)
1643 {
1644     int rc;
1645     GtkWidget* descriptionLabel;
1646     GtkWidget* okButton;
1647     GtkWidget* cancelButton;
1648     GtkWidget* warningDialog;
1649 
1650     /* dialog window for the progress bar */
1651     GBLwritingProgressWindow = gtk_dialog_new();
1652     gtk_dialog_set_has_separator(GTK_DIALOG(GBLwritingProgressWindow), FALSE);
1653     gtk_window_set_modal(GTK_WINDOW(GBLwritingProgressWindow), TRUE);
1654     gtk_window_set_title(GTK_WINDOW(GBLwritingProgressWindow), _("Progress"));
1655     gtk_window_set_transient_for(GTK_WINDOW(GBLwritingProgressWindow), GTK_WINDOW(GBLmainWindow));
1656     g_signal_connect_swapped(GBLwritingProgressWindow, "delete-event",
1657                              G_CALLBACK(writingProgressWindowDeleteCbk), NULL);
1658     g_signal_connect_swapped(GBLwritingProgressWindow, "response",
1659                              G_CALLBACK(writingProgressResponse), GBLwritingProgressWindow);
1660     g_signal_connect_swapped(GBLwritingProgressWindow, "destroy",
1661                              G_CALLBACK(writingProgressWindowDestroyedCbk), NULL);
1662 
1663     /* just some text */
1664     descriptionLabel = gtk_label_new(_("Please wait while I'm saving the new image to disk..."));
1665     gtk_box_pack_start(GTK_BOX(GTK_DIALOG(GBLwritingProgressWindow)->vbox), descriptionLabel, TRUE, TRUE, 0);
1666     gtk_widget_show(descriptionLabel);
1667 
1668     /* the progress bar */
1669     GBLWritingProgressBar = gtk_progress_bar_new();
1670     gtk_box_pack_start(GTK_BOX(GTK_DIALOG(GBLwritingProgressWindow)->vbox), GBLWritingProgressBar, TRUE, TRUE, 0);
1671     gtk_widget_show(GBLWritingProgressBar);
1672 
1673     /* button to close the dialog (disabled until writing finished) */
1674     okButton = gtk_dialog_add_button(GTK_DIALOG(GBLwritingProgressWindow), GTK_STOCK_OK, GTK_RESPONSE_OK);
1675     gtk_widget_set_sensitive(okButton, FALSE);
1676 
1677     /* button to cancel writing */
1678     cancelButton = gtk_dialog_add_button(GTK_DIALOG(GBLwritingProgressWindow), GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
1679 
1680     /* if i show it before i add the children, the window ends up being not centered */
1681     gtk_widget_show(GBLwritingProgressWindow);
1682 
1683     /* write new image */
1684     rc = bk_write_image(filename, &GBLvolInfo, time(NULL), GBLappSettings.filenameTypesToWrite,
1685                         writingProgressUpdaterCbk);
1686     if(rc < 0)
1687     {
1688         warningDialog = gtk_message_dialog_new(GTK_WINDOW(GBLmainWindow),
1689                                                GTK_DIALOG_DESTROY_WITH_PARENT,
1690                                                GTK_MESSAGE_ERROR,
1691                                                GTK_BUTTONS_CLOSE,
1692                                                _("Failed to write image to '%s': '%s'"),
1693                                                filename,
1694                                                bk_get_error_string(rc));
1695         gtk_window_set_modal(GTK_WINDOW(warningDialog), TRUE);
1696         gtk_dialog_run(GTK_DIALOG(warningDialog));
1697         gtk_widget_destroy(warningDialog);
1698         if(GBLWritingProgressBar != NULL)
1699             gtk_widget_destroy(GBLwritingProgressWindow);
1700     }
1701     else
1702         GBLisoChangesProbable = false;
1703 
1704     if(GBLWritingProgressBar != NULL)
1705     /* progress window hasn't been destroyed */
1706     {
1707         /* enable the ok button so the user can close the progress window */
1708         gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(GBLWritingProgressBar), 1.0);
1709         gtk_widget_set_sensitive(okButton, TRUE);
1710         gtk_widget_grab_focus(okButton);
1711         gtk_widget_set_sensitive(cancelButton, FALSE);
1712     }
1713 }
1714 
1715 /* This callback is also used by an accelerator so make sure you don't use
1716 * the parameters, since they may not be the menuitem parameters */
saveIsoCbk(GtkWidget * widget,GdkEvent * event)1717 gboolean saveIsoCbk(GtkWidget *widget, GdkEvent *event)
1718 {
1719     GtkWidget *dialog;
1720     char* filename = NULL;
1721     int dialogResponse;
1722     GtkFileFilter* nameFilter;
1723     GtkWidget* addExtensionCheckbox;
1724     bool askedToAddExtension;
1725 
1726     /* do nothing if no image open */
1727     if(!GBLisoPaneActive)
1728         return TRUE;
1729 
1730     dialog = gtk_file_chooser_dialog_new(_("Save File"),
1731                                          NULL,
1732                                          GTK_FILE_CHOOSER_ACTION_SAVE,
1733                                          GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
1734                                          GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
1735                                          NULL);
1736     // gtk problem? enter doesn't work
1737     //g_signal_connect(dialog, "key-press-event", (GCallback), NULL);
1738 
1739     nameFilter = gtk_file_filter_new();
1740     gtk_file_filter_add_pattern(GTK_FILE_FILTER(nameFilter), "*.[iI][sS][oO]");
1741     gtk_file_filter_set_name(GTK_FILE_FILTER(nameFilter), _("ISO Images"));
1742     gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), GTK_FILE_FILTER(nameFilter));
1743 
1744     nameFilter = gtk_file_filter_new();
1745     gtk_file_filter_add_pattern(GTK_FILE_FILTER(nameFilter), "*");
1746     gtk_file_filter_set_name(GTK_FILE_FILTER(nameFilter), _("All files"));
1747     gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), GTK_FILE_FILTER(nameFilter));
1748 
1749     addExtensionCheckbox = gtk_check_button_new_with_label(_("Add extension automatically"));
1750     gtk_file_chooser_set_extra_widget(GTK_FILE_CHOOSER(dialog), addExtensionCheckbox);
1751     if(GBLappSettings.appendExtension)
1752         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(addExtensionCheckbox), TRUE);
1753     else
1754         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(addExtensionCheckbox), FALSE);
1755     gtk_widget_show(addExtensionCheckbox);
1756 
1757     if(GBLappSettings.lastIsoDir != NULL)
1758         gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), GBLappSettings.lastIsoDir);
1759 
1760     dialogResponse = gtk_dialog_run(GTK_DIALOG(dialog));
1761 
1762     if(dialogResponse == GTK_RESPONSE_ACCEPT)
1763     {
1764         filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
1765 
1766         /* RECORD last iso dir */
1767         char* lastIsoDir = gtk_file_chooser_get_current_folder(GTK_FILE_CHOOSER(dialog));
1768         if(lastIsoDir)
1769         {
1770             if(GBLappSettings.lastIsoDir != NULL && strlen(lastIsoDir) > strlen(GBLappSettings.lastIsoDir))
1771             {
1772                 free(GBLappSettings.lastIsoDir);
1773                 GBLappSettings.lastIsoDir = NULL;
1774             }
1775 
1776             if(GBLappSettings.lastIsoDir == NULL)
1777                 GBLappSettings.lastIsoDir = malloc(strlen(lastIsoDir) + 1);
1778 
1779             strcpy(GBLappSettings.lastIsoDir, lastIsoDir);
1780 
1781             g_free(lastIsoDir);
1782         }
1783         else /* e.g. when opening a file from the <Recently used> view */
1784         {
1785             free(GBLappSettings.lastIsoDir);
1786             GBLappSettings.lastIsoDir = NULL;
1787         }
1788         /* END RECORD last iso dir */
1789 
1790         askedToAddExtension = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(addExtensionCheckbox));
1791     }
1792 
1793     gtk_widget_destroy(dialog);
1794 
1795     if(dialogResponse == GTK_RESPONSE_ACCEPT)
1796     {
1797         char* nameWithExtension;
1798 
1799         nameWithExtension = malloc(strlen(filename) + 5);
1800         if(nameWithExtension == NULL)
1801             fatalError("saveIsoCbk(): malloc(strlen(filename) + 5) failed");
1802 
1803         strcpy(nameWithExtension, filename);
1804         g_free(filename);
1805 
1806         if(askedToAddExtension)
1807         {
1808             regex_t extensionRegex;
1809 
1810             regcomp(&extensionRegex, ".*\\.[iI][sS][oO]$", 0);
1811 
1812             if(regexec(&extensionRegex, nameWithExtension, 0, NULL, 0) != 0)
1813             /* doesn't already end with .iso */
1814                 strcat(nameWithExtension, ".iso");
1815 
1816             GBLappSettings.appendExtension = true;
1817         }
1818         else
1819             GBLappSettings.appendExtension = false;
1820 
1821         saveIso(nameWithExtension);
1822 
1823         free(nameWithExtension);
1824     }
1825 
1826     //~ saveIso("/home/andrei/out.iso");
1827 
1828     /* the accelerator callback must return true */
1829     return TRUE;
1830 }
1831 
1832 #ifdef ENABLE_SAVE_OVERWRITE
1833 #define TEMPFILENAME "/tmp/isomaster-temp.iso"
saveOverwriteIsoCbk(GtkWidget * widget,GdkEvent * event)1834 gboolean saveOverwriteIsoCbk(GtkWidget *widget, GdkEvent *event)
1835 {
1836     int sourceFile;
1837     int destFile;
1838     int numBytesRead;
1839     char line[1024];
1840     GtkWidget* warningDialog;
1841 
1842     saveIso(TEMPFILENAME);
1843 
1844     printf("moving %s to %s\n", TEMPFILENAME, openIsoPathAndName);
1845 
1846     sourceFile = open(TEMPFILENAME, O_RDONLY);
1847     if(sourceFile == -1)
1848     {
1849         warningDialog = gtk_message_dialog_new(GTK_WINDOW(GBLmainWindow),
1850                                                GTK_DIALOG_DESTROY_WITH_PARENT,
1851                                                GTK_MESSAGE_ERROR,
1852                                                GTK_BUTTONS_CLOSE,
1853                                                "Failed to open %s for reading",
1854                                                TEMPFILENAME);
1855         gtk_window_set_modal(GTK_WINDOW(warningDialog), TRUE);
1856         gtk_dialog_run(GTK_DIALOG(warningDialog));
1857         gtk_widget_destroy(warningDialog);
1858         if(GBLWritingProgressBar != NULL)
1859             gtk_widget_destroy(GBLwritingProgressWindow);
1860     }
1861 
1862     destFile = open(openIsoPathAndName, O_WRONLY | O_CREAT);
1863     if(destFile == -1)
1864     {
1865         warningDialog = gtk_message_dialog_new(GTK_WINDOW(GBLmainWindow),
1866                                                GTK_DIALOG_DESTROY_WITH_PARENT,
1867                                                GTK_MESSAGE_ERROR,
1868                                                GTK_BUTTONS_CLOSE,
1869                                                "Failed to open %s for writing",
1870                                                openIsoPathAndName);
1871         gtk_window_set_modal(GTK_WINDOW(warningDialog), TRUE);
1872         gtk_dialog_run(GTK_DIALOG(warningDialog));
1873         gtk_widget_destroy(warningDialog);
1874         if(GBLWritingProgressBar != NULL)
1875             gtk_widget_destroy(GBLwritingProgressWindow);
1876     }
1877 
1878     while((numBytesRead = read(sourceFile, line, sizeof(line))) > 0)
1879       write(destFile, line, numBytesRead);
1880 
1881     close(sourceFile);
1882     close(destFile);
1883 
1884     return FALSE;
1885 }
1886 #endif
1887 
showIsoContextMenu(GtkWidget * isoView,GdkEventButton * event)1888 void showIsoContextMenu(GtkWidget* isoView, GdkEventButton* event)
1889 {
1890     GtkWidget* menu;
1891     GtkWidget* menuItem;
1892     GtkTreeSelection* selection;
1893     gint numSelectedRows;
1894     GtkAccelGroup* accelGroup;
1895 
1896     selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(GBLisoTreeView));
1897 
1898     numSelectedRows = gtk_tree_selection_count_selected_rows(selection);
1899     if(numSelectedRows == 0)
1900         return;
1901 
1902     /* have this here just so that the shortcut keys show in the context menu */
1903     accelGroup = gtk_accel_group_new();
1904     gtk_window_add_accel_group(GTK_WINDOW(GBLmainWindow), accelGroup);
1905 
1906     menu = gtk_menu_new();
1907     gtk_menu_set_accel_group(GTK_MENU(menu), accelGroup);
1908 
1909     menuItem = gtk_image_menu_item_new_with_label(_("Rename"));
1910     g_signal_connect(menuItem, "activate",
1911                      (GCallback)renameSelectedBtnCbk, NULL);
1912     gtk_menu_item_set_accel_path(GTK_MENU_ITEM(menuItem), "<ISOMaster>/Contextmenu/Rename");
1913     gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuItem);
1914     gtk_widget_show_all(menu);
1915     if(numSelectedRows > 1)
1916         gtk_widget_set_sensitive(menuItem, FALSE);
1917 
1918     menuItem = gtk_image_menu_item_new_with_label(_("View"));
1919     g_signal_connect(menuItem, "activate",
1920                      (GCallback)viewSelectedBtnCbk, NULL);
1921     gtk_menu_item_set_accel_path(GTK_MENU_ITEM(menuItem), "<ISOMaster>/Contextmenu/View");
1922     gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuItem);
1923     gtk_widget_show_all(menu);
1924 
1925     menuItem = gtk_image_menu_item_new_with_label(_("Edit"));
1926     g_signal_connect(menuItem, "activate",
1927                      (GCallback)editSelectedBtnCbk, NULL);
1928     gtk_menu_item_set_accel_path(GTK_MENU_ITEM(menuItem), "<ISOMaster>/Contextmenu/Edit");
1929     gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuItem);
1930     gtk_widget_show_all(menu);
1931 
1932     menuItem = gtk_image_menu_item_new_with_label(_("Change permissions"));
1933     g_signal_connect(menuItem, "activate",
1934                      (GCallback)changePermissionsBtnCbk, NULL);
1935     gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuItem);
1936     gtk_widget_show_all(menu);
1937     //~ if(numSelectedRows > 1)
1938         //~ gtk_widget_set_sensitive(menuItem, FALSE);
1939 
1940     gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL,
1941                    event->button, gdk_event_get_time((GdkEvent*)event));
1942 }
1943 
1944 /* this handles the ok and cancel buttons in the progress window */
writingProgressResponse(GtkDialog * dialog,gint arg1,gpointer user_data)1945 void writingProgressResponse(GtkDialog* dialog, gint arg1, gpointer user_data)
1946 {
1947     if(arg1 == GTK_RESPONSE_CANCEL)
1948         bk_cancel_operation(&GBLvolInfo);
1949     else if(arg1 == GTK_RESPONSE_OK)
1950         gtk_widget_destroy(GBLwritingProgressWindow);
1951 }
1952 
writingProgressUpdaterCbk(VolInfo * volInfo,double percentComplete)1953 void writingProgressUpdaterCbk(VolInfo* volInfo, double percentComplete)
1954 {
1955     if(GBLWritingProgressBar != NULL)
1956     {
1957         gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(GBLWritingProgressBar), percentComplete / 100);
1958 
1959         /* redraw progress bar */
1960         while(gtk_events_pending())
1961             gtk_main_iteration();
1962     }
1963 }
1964 
writingProgressWindowDeleteCbk(GtkWidget * widget,GdkEvent * event,gpointer user_data)1965 gboolean writingProgressWindowDeleteCbk(GtkWidget* widget, GdkEvent* event,
1966                                         gpointer user_data)
1967 {
1968     /* don't allow closing */
1969     return TRUE;
1970 }
1971 
writingProgressWindowDestroyedCbk(void)1972 void writingProgressWindowDestroyedCbk(void)
1973 {
1974     GBLwritingProgressWindow = NULL;
1975     GBLWritingProgressBar = NULL;
1976 }
1977