Squelch some qualifier (const vs. non-const) warnings.
[obnox/wireshark/wip.git] / gtk / export_object.c
1 /* export_object.c
2  * Common routines for tracking & saving objects found in streams of data
3  * Copyright 2007, Stephen Fisher <stephentfisher@yahoo.com>
4  *
5  * $Id$
6  * 
7  * Wireshark - Network traffic analyzer
8  * By Gerald Combs <gerald@wireshark.org>
9  * Copyright 1998 Gerald Combs
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
24  * USA.
25  */
26
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
30
31 #include <glib.h>
32 #include <gtk/gtk.h>
33
34 /* This feature has not been ported to GTK1 */
35 #if GTK_MAJOR_VERSION >= 2
36
37 #include <alert_box.h>
38 #include <simple_dialog.h>
39
40 #include <epan/packet_info.h>
41 #include <epan/prefs.h>
42 #include <epan/tap.h>
43 #include <gtk/compat_macros.h>
44 #include <gtk/dlg_utils.h>
45 #include <gtk/file_dlg.h>
46 #include <gtk/gui_utils.h>
47 #include <gtk/help_dlg.h>
48 #include <gtk/main.h>
49 #include <wiretap/file_util.h>
50
51 #ifdef HAVE_FCNTL_H
52 #include <fcntl.h>
53 #endif
54
55 #ifdef HAVE_UNISTD_H
56 #include <unistd.h>
57 #endif
58
59 #include "export_object.h"
60
61 enum {
62         EO_PKT_NUM_COLUMN,
63         EO_HOSTNAME_COLUMN,
64         EO_CONTENT_TYPE_COLUMN,
65         EO_BYTES_COLUMN,
66         EO_FILENAME_COLUMN,
67         EO_NUM_COLUMNS /* must be last */
68 };
69
70
71 static void
72 eo_remember_this_row(GtkTreeModel *model _U_, GtkTreePath *path,
73                      GtkTreeIter *iter _U_, gpointer arg)
74 {
75         export_object_list_t *object_list = arg;
76         export_object_entry_t *entry;
77
78         gint *path_index;
79
80         if((path_index = gtk_tree_path_get_indices(path)) == NULL)
81                 /* Row not found in tree - shouldn't happen */
82                 return;
83
84         object_list->row_selected = path_index[0];
85
86         /* Select the corresponding packet in the packet list */
87         entry = g_slist_nth_data(object_list->entries,
88                                  object_list->row_selected);
89         cf_goto_frame(&cfile, entry->pkt_num);
90 }
91
92 static void
93 eo_remember_row_num(GtkTreeSelection *sel, gpointer data)
94 {
95         gtk_tree_selection_selected_foreach(sel, eo_remember_this_row, data);
96 }
97
98
99 /* Called when the Export Object window is closed in any way */
100 static void
101 eo_win_destroy_cb(GtkWindow *win _U_, gpointer data)
102 {
103         export_object_list_t *object_list = data;
104         export_object_entry_t *entry;
105         GSList *slist = object_list->entries;
106
107         protect_thread_critical_region();
108         remove_tap_listener(object_list);
109         unprotect_thread_critical_region();
110
111         while(slist) {
112                 entry = slist->data;
113                 
114                 g_free(entry->hostname);
115                 g_free(entry->content_type);
116                 g_free(entry->filename);
117                 g_free(entry->payload_data);
118                 
119                 slist = slist->next; 
120                 g_free(entry);
121         }
122
123         g_slist_free(object_list->entries);
124         g_free(object_list);
125 }
126
127 static void
128 eo_save_entry(gchar *save_as_filename, export_object_entry_t *entry)
129 {
130         int to_fd;
131
132         to_fd = eth_open(save_as_filename, O_WRONLY | O_CREAT | O_EXCL |
133                          O_BINARY, 0644);
134         if(to_fd == -1) { /* An error occurred */
135                 open_failure_alert_box(save_as_filename, errno, TRUE);
136                 g_free(save_as_filename);
137                 return;
138         }
139
140         if(eth_write(to_fd, entry->payload_data, entry->payload_len) < 0) {
141                 write_failure_alert_box(save_as_filename, errno);
142                 eth_close(to_fd);
143                 g_free(save_as_filename);
144                 return;
145         }
146
147         if (eth_close(to_fd) < 0) {
148                 write_failure_alert_box(save_as_filename, errno);
149                 g_free(save_as_filename);
150                 return;
151         }
152
153         g_free(save_as_filename);
154 }
155
156
157 static void
158 eo_save_clicked_cb(GtkWidget *widget _U_, gpointer arg)
159 {
160         GtkWidget *save_as_w;
161         export_object_list_t *object_list = arg;
162         export_object_entry_t *entry = NULL;
163
164         entry = g_slist_nth_data(object_list->entries,
165                                  object_list->row_selected);
166
167         if(!entry) {
168                 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK, "No object was selected for saving.  Please click on an object and click save again.");
169                 return;
170         }
171
172         save_as_w = file_selection_new("Wireshark: Save Object As ...",
173                                        FILE_SELECTION_SAVE);
174
175         gtk_window_set_transient_for(GTK_WINDOW(save_as_w),
176                                      GTK_WINDOW(object_list->dlg));
177
178         gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(save_as_w),
179                                           entry->filename);
180
181         if(gtk_dialog_run(GTK_DIALOG(save_as_w)) == GTK_RESPONSE_ACCEPT)
182                 eo_save_entry(gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(save_as_w)), entry);
183
184         window_destroy(save_as_w);
185 }
186
187 static void
188 eo_save_all_clicked_cb(GtkWidget *widget _U_, gpointer arg)
189 {
190         gchar *save_as_fullpath;
191         export_object_list_t *object_list = arg;
192         export_object_entry_t *entry;
193         GtkWidget *save_in_w;
194         GSList *slist = object_list->entries;
195
196         save_in_w = file_selection_new("Wireshark: Save All Objects In ...",
197                                        FILE_SELECTION_CREATE_FOLDER);
198
199         gtk_window_set_transient_for(GTK_WINDOW(save_in_w),
200                                      GTK_WINDOW(object_list->dlg));
201
202         if(gtk_dialog_run(GTK_DIALOG(save_in_w)) == GTK_RESPONSE_ACCEPT) {
203                 while(slist) {
204                         entry = slist->data;
205
206                         save_as_fullpath = g_build_filename(gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(save_in_w)), entry->filename, NULL);
207                         
208                         eo_save_entry(save_as_fullpath, entry);
209
210                         slist = slist->next;
211                 }
212         }
213
214         window_destroy(save_in_w);
215 }
216
217 /* Runs at the beginning of tapping only */
218 static void
219 eo_reset(void *tapdata)
220 {
221         export_object_list_t *object_list = tapdata;
222
223         object_list->entries = NULL;
224         object_list->iter = NULL;
225         object_list->row_selected = -1;
226 }
227
228 static void
229 eo_draw(void *tapdata)
230 {
231         export_object_list_t *object_list = tapdata;
232         export_object_entry_t *eo_entry;
233
234         GSList *slist = object_list->entries;
235         GtkTreeIter new_iter;
236
237         while(slist) {
238                 eo_entry = slist->data;
239                 
240                 gtk_tree_store_append(object_list->store, &new_iter,
241                                       object_list->iter);
242
243                 gtk_tree_store_set(object_list->store, &new_iter,
244                                    EO_PKT_NUM_COLUMN, eo_entry->pkt_num,
245                                    EO_HOSTNAME_COLUMN, eo_entry->hostname,
246                                    EO_CONTENT_TYPE_COLUMN, eo_entry->content_type,
247                                    EO_BYTES_COLUMN, eo_entry->payload_len,
248                                    EO_FILENAME_COLUMN, eo_entry->filename,
249                                    -1);
250
251                 slist = slist->next;
252         }
253 }
254
255 void
256 export_object_window(const gchar *tapname, const gchar *name, tap_packet_cb tap_packet)
257 {
258         GtkWidget *sw;
259         GtkCellRenderer *renderer;
260         GtkTreeViewColumn *column;
261         GtkTreeSelection *selection;
262         GtkWidget *vbox, *bbox, *help_bt, *close_bt, *save_bt, *save_all_bt;
263         GtkTooltips *button_bar_tips;
264         GString *error_msg;
265         export_object_list_t *object_list;
266         gchar *window_title;
267
268         /* Initialize our object list structure */
269         object_list = g_malloc0(sizeof(export_object_list_t));
270
271         /* Data will be gathered via a tap callback */
272         error_msg = register_tap_listener(tapname, object_list, NULL,
273                                           eo_reset,
274                                           tap_packet,
275                                           eo_draw);
276
277         if (error_msg) {
278                 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
279                               "Can't register http tap: %s\n", error_msg->str);
280                 g_string_free(error_msg, TRUE);
281                 return;
282         }
283
284         /* Setup our GUI window */
285         button_bar_tips = gtk_tooltips_new();
286
287         window_title = g_strdup_printf("Wireshark: %s object list", name);
288         object_list->dlg = dlg_window_new(window_title);
289         g_free(window_title);
290
291         gtk_window_set_default_size(GTK_WINDOW(object_list->dlg),
292                                     DEF_WIDTH, DEF_HEIGHT);
293
294         vbox = gtk_vbox_new(FALSE, 5);
295
296         gtk_container_border_width(GTK_CONTAINER(vbox), 5);
297         gtk_container_add(GTK_CONTAINER(object_list->dlg), vbox);
298
299         sw = scrolled_window_new(NULL, NULL);
300         gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw),
301                                             GTK_SHADOW_IN);
302
303         gtk_container_add(GTK_CONTAINER(vbox), sw);
304
305         object_list->store = gtk_tree_store_new(EO_NUM_COLUMNS,
306                                                  G_TYPE_INT, G_TYPE_STRING,
307                                                  G_TYPE_STRING, G_TYPE_INT,
308                                                  G_TYPE_STRING);
309
310         object_list->tree = tree_view_new(GTK_TREE_MODEL(object_list->store));
311
312         object_list->tree_view = GTK_TREE_VIEW(object_list->tree);
313
314         renderer = gtk_cell_renderer_text_new();
315         column = gtk_tree_view_column_new_with_attributes("Packet num",
316                                                           renderer,
317                                                           "text",
318                                                           EO_PKT_NUM_COLUMN,
319                                                           NULL);
320         gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
321         gtk_tree_view_append_column(object_list->tree_view, column);
322
323         renderer = gtk_cell_renderer_text_new();
324         column = gtk_tree_view_column_new_with_attributes("Hostname",
325                                                           renderer,
326                                                           "text",
327                                                           EO_HOSTNAME_COLUMN,
328                                                           NULL);
329         gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
330         gtk_tree_view_append_column(object_list->tree_view, column);
331
332         renderer = gtk_cell_renderer_text_new();
333         column = gtk_tree_view_column_new_with_attributes("Content Type",
334                                                           renderer,
335                                                           "text",
336                                                           EO_CONTENT_TYPE_COLUMN,
337                                                           NULL);
338         gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
339         gtk_tree_view_append_column(object_list->tree_view, column);
340
341         renderer = gtk_cell_renderer_text_new();
342         column = gtk_tree_view_column_new_with_attributes("Bytes",
343                                                           renderer,
344                                                           "text",
345                                                           EO_BYTES_COLUMN,
346                                                           NULL);
347         gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
348         gtk_tree_view_append_column(object_list->tree_view, column);
349
350         renderer = gtk_cell_renderer_text_new();
351         column = gtk_tree_view_column_new_with_attributes("Filename",
352                                                           renderer,
353                                                           "text",
354                                                           EO_FILENAME_COLUMN,
355                                                           NULL);
356         gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
357         gtk_tree_view_append_column(object_list->tree_view, column);
358
359         gtk_container_add(GTK_CONTAINER(sw), object_list->tree);
360
361         selection = gtk_tree_view_get_selection(object_list->tree_view);
362         SIGNAL_CONNECT(selection, "changed", eo_remember_row_num, object_list);
363
364
365         bbox = gtk_hbox_new(FALSE, 5);
366
367         /* Help button */
368         help_bt = BUTTON_NEW_FROM_STOCK(GTK_STOCK_HELP);
369         SIGNAL_CONNECT(help_bt, "clicked", topic_cb, HELP_EXPORT_OBJECT_LIST);
370         gtk_tooltips_set_tip(GTK_TOOLTIPS(button_bar_tips), help_bt,
371                              "Show help for this dialog.", NULL);
372         gtk_box_pack_start(GTK_BOX(bbox), help_bt, FALSE, FALSE, 0);
373
374         /* Save All button */
375         save_all_bt = gtk_button_new_with_mnemonic("Save A_ll");
376         SIGNAL_CONNECT(save_all_bt, "clicked", eo_save_all_clicked_cb,
377                        object_list);
378         gtk_tooltips_set_tip(GTK_TOOLTIPS(button_bar_tips), save_all_bt,
379                              "Save all listed objects with their displayed "
380                              "filenames.", NULL);
381         gtk_box_pack_end(GTK_BOX(bbox), save_all_bt, FALSE, FALSE, 0);
382
383         /* Save button */
384         save_bt = BUTTON_NEW_FROM_STOCK(GTK_STOCK_SAVE_AS);
385         SIGNAL_CONNECT(save_bt, "clicked", eo_save_clicked_cb, object_list);
386         gtk_tooltips_set_tip(GTK_TOOLTIPS(button_bar_tips), save_bt,
387                              "Saves the currently selected content to a file.",
388                              NULL);
389         gtk_box_pack_end(GTK_BOX(bbox), save_bt, FALSE, FALSE, 0);
390
391         /* Close button */
392         close_bt = BUTTON_NEW_FROM_STOCK(GTK_STOCK_CLOSE);
393         GTK_WIDGET_SET_FLAGS(close_bt, GTK_CAN_DEFAULT);
394         gtk_tooltips_set_tip(GTK_TOOLTIPS(button_bar_tips), close_bt,
395                              "Close this dialog.", NULL);
396         gtk_box_pack_end(GTK_BOX(bbox), close_bt, FALSE, FALSE, 0);
397
398         /* Pack the buttons into the "button box" */
399         gtk_box_pack_end(GTK_BOX(vbox), bbox, FALSE, FALSE, 0);
400         gtk_widget_show(bbox);
401
402         /* Setup cancel/delete/destroy signal handlers */
403         SIGNAL_CONNECT(object_list->dlg, "delete_event",
404                        window_delete_event_cb, NULL);
405         SIGNAL_CONNECT(object_list->dlg, "destroy",
406                        eo_win_destroy_cb, object_list);
407         window_set_cancel_button(object_list->dlg, close_bt,
408                                  window_cancel_button_cb);
409
410         /* Show the window */
411         gtk_widget_show_all(object_list->dlg);
412         window_present(object_list->dlg);
413
414         cf_retap_packets(&cfile, FALSE);
415 }
416
417 #endif /* GTK_MAJOR_VERSION >= 2 */