Sync up my changes so far to the content list (now called object
[obnox/wireshark/wip.git] / gtk / export_object_http.c
1 /* export_object_http.c
2  * Routines for tracking & saving objects found in HTTP streams
3  * See also: export_object.c / export_object.h for common code
4  * Copyright 2007, Stephen Fisher <stephentfisher@yahoo.com>
5  *
6  * $Id$
7  * 
8  * Wireshark - Network traffic analyzer
9  * By Gerald Combs <gerald@wireshark.org>
10  * Copyright 1998 Gerald Combs
11  *
12  * This program is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU General Public License
14  * as published by the Free Software Foundation; either version 2
15  * of the License, or (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
25  * USA.
26  */
27
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
31
32 #include <glib.h>
33 #include <gtk/gtk.h>
34
35 /* This feature has not been ported to GTK1 */
36 #if GTK_MAJOR_VERSION >= 2
37
38 #include "export_object.h"
39
40 #include <epan/dissectors/packet-http.h>
41 #include <epan/emem.h>
42 #include <epan/epan.h>
43 #include <epan/prefs.h>
44 #include <epan/tap.h>
45 #include <file.h>
46 #include <globals.h>
47 #include <simple_dialog.h>
48 #include <stat_menu.h>
49 #include <gtk/compat_macros.h>
50 #include <gtk/dlg_utils.h>
51 #include <gtk/file_dlg.h>
52 #include <gtk/gui_utils.h>
53 #include <gtk/gui_stat_menu.h>
54
55 static void
56 eo_http_reset(void *tapdata)
57 {
58         export_object_list_t *object_list = tapdata;
59
60         if(object_list->entries) {
61                 g_slist_free(object_list->entries);
62                 object_list->entries = NULL;
63         }
64
65         object_list->iter = NULL;
66         object_list->row_selected = -1;
67 }
68
69 static int
70 eo_http_packet(void *tapdata, packet_info *pinfo, epan_dissect_t *edt _U_,
71                const void *data)
72 {
73         export_object_list_t *object_list = tapdata;
74         const http_info_value_t *stat_info = data;
75         export_object_entry_t *entry;
76
77         if(stat_info->content_type &&
78            g_ascii_strncasecmp(stat_info->content_type, "<NULL>", 6) != 0) {
79                 entry = g_malloc(sizeof(export_object_entry_t));
80
81                 entry->pkt_num = pinfo->fd->num;
82                 entry->hostname = g_strdup(stat_info->http_host);
83                 entry->content_type = g_strdup(stat_info->content_type);
84
85                 if(stat_info->request_uri)
86                         entry->filename =
87                                 g_path_get_basename(stat_info->request_uri);
88                 else
89                         entry->filename = NULL;
90
91                 entry->payload_len = stat_info->payload_len;
92                 entry->payload_data = g_memdup(stat_info->payload_data,
93                                                stat_info->payload_len);
94
95                 object_list->entries =
96                         g_slist_append(object_list->entries, entry);
97                 return 1;
98         } else {
99                 return 0;
100         }
101 }
102
103 static void
104 eo_http_draw(void *tapdata)
105 {
106         export_object_list_t *object_list = tapdata;
107         export_object_entry_t *eo_entry;
108
109         GSList *slist_entry = NULL;
110         GSList *last_slist_entry = NULL;
111         gint last_slist_entry_num;
112         GtkTreeIter new_iter;
113         gchar *column_text[EO_NUM_COLUMNS];
114
115         last_slist_entry = g_slist_last(object_list->entries);
116         last_slist_entry_num = g_slist_position(object_list->entries,
117                                                 last_slist_entry);
118
119         while(object_list->slist_pos <= last_slist_entry_num &&
120               last_slist_entry_num != -1) {
121                 slist_entry = g_slist_nth(object_list->entries,
122                                           object_list->slist_pos);
123                 eo_entry = slist_entry->data;
124                 
125                 column_text[0] = g_strdup_printf("%u", eo_entry->pkt_num);
126                 column_text[1] = g_strdup_printf("%s", eo_entry->hostname);
127                 column_text[2] = g_strdup_printf("%s", eo_entry->content_type);
128                 column_text[3] = g_strdup_printf("%u", eo_entry->payload_len);
129                 column_text[4] = g_strdup_printf("%s", eo_entry->filename);
130
131                 gtk_tree_store_append(object_list->store, &new_iter,
132                                       object_list->iter);
133
134                 gtk_tree_store_set(object_list->store, &new_iter,
135                                    EO_PKT_NUM_COLUMN, column_text[0],
136                                    EO_HOSTNAME_COLUMN, column_text[1],
137                                    EO_CONTENT_TYPE_COLUMN, column_text[2],
138                                    EO_BYTES_COLUMN, column_text[3],
139                                    EO_FILENAME_COLUMN, column_text[4],
140                                    -1);
141
142                 g_free(column_text[0]);
143                 g_free(column_text[1]);
144                 g_free(column_text[2]);
145                 g_free(column_text[3]);
146                 g_free(column_text[4]);
147
148                 object_list->slist_pos++;
149         }
150 }
151
152 void
153 eo_http_cb(GtkWidget *widget _U_, gpointer data _U_)
154 {
155         GString *error_msg;
156         GtkWidget *sw;
157         GtkCellRenderer *renderer;
158         GtkTreeViewColumn *column;
159         GtkTreeSelection *selection;
160         GtkWidget *vbox, *bbox, *close_bt, *save_bt, *save_all_bt;
161         GtkTooltips *button_bar_tips;
162
163         export_object_list_t *object_list = g_malloc0(sizeof(export_object_list_t));
164
165         button_bar_tips = gtk_tooltips_new();
166
167         /* Data will be gathered via a tap callback */
168         error_msg = register_tap_listener("http", object_list, NULL,
169                                           eo_http_reset,
170                                           eo_http_packet,
171                                           eo_http_draw);
172
173         if (error_msg) {
174                 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
175                               "Can't register http tap: %s\n", error_msg->str);
176                 g_string_free(error_msg, TRUE);
177                 return;
178         }
179
180         object_list->dlg = dlg_window_new("Wireshark: HTTP Content List");
181
182         gtk_window_set_default_size(GTK_WINDOW(object_list->dlg),
183                                     DEF_WIDTH, DEF_HEIGHT);
184
185         vbox = gtk_vbox_new(FALSE, 5);
186
187         gtk_container_border_width(GTK_CONTAINER(vbox), 5);
188         gtk_container_add(GTK_CONTAINER(object_list->dlg), vbox);
189
190         sw = scrolled_window_new(NULL, NULL);
191         gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw),
192                                             GTK_SHADOW_IN);
193
194         gtk_container_add(GTK_CONTAINER(vbox), sw);
195
196         object_list->store = gtk_tree_store_new(EO_NUM_COLUMNS,
197                                                  G_TYPE_STRING, G_TYPE_STRING,
198                                                  G_TYPE_STRING, G_TYPE_STRING,
199                                                  G_TYPE_STRING);
200
201         object_list->tree = tree_view_new(GTK_TREE_MODEL(object_list->store));
202
203         object_list->tree_view = GTK_TREE_VIEW(object_list->tree);
204
205         renderer = gtk_cell_renderer_text_new();
206         column = gtk_tree_view_column_new_with_attributes("Packet num",
207                                                           renderer,
208                                                           "text",
209                                                           EO_PKT_NUM_COLUMN,
210                                                           NULL);
211         gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
212         gtk_tree_view_append_column(object_list->tree_view, column);
213
214         renderer = gtk_cell_renderer_text_new();
215         column = gtk_tree_view_column_new_with_attributes("Hostname",
216                                                           renderer,
217                                                           "text",
218                                                           EO_HOSTNAME_COLUMN,
219                                                           NULL);
220         gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
221         gtk_tree_view_append_column(object_list->tree_view, column);
222
223         renderer = gtk_cell_renderer_text_new();
224         column = gtk_tree_view_column_new_with_attributes("Content Type",
225                                                           renderer,
226                                                           "text",
227                                                           EO_CONTENT_TYPE_COLUMN,
228                                                           NULL);
229         gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
230         gtk_tree_view_append_column(object_list->tree_view, column);
231
232         renderer = gtk_cell_renderer_text_new();
233         column = gtk_tree_view_column_new_with_attributes("Bytes",
234                                                           renderer,
235                                                           "text",
236                                                           EO_BYTES_COLUMN,
237                                                           NULL);
238         gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
239         gtk_tree_view_append_column(object_list->tree_view, column);
240
241         renderer = gtk_cell_renderer_text_new();
242         column = gtk_tree_view_column_new_with_attributes("Filename",
243                                                           renderer,
244                                                           "text",
245                                                           EO_FILENAME_COLUMN,
246                                                           NULL);
247         gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
248         gtk_tree_view_append_column(object_list->tree_view, column);
249
250         gtk_container_add(GTK_CONTAINER(sw), object_list->tree);
251
252         selection = gtk_tree_view_get_selection(object_list->tree_view);
253         SIGNAL_CONNECT(selection, "changed", eo_remember_row_num, object_list);
254
255         bbox = gtk_hbox_new(FALSE, 5);
256
257         /* Save All button */
258         save_all_bt = gtk_button_new_with_mnemonic("Save _All");
259         SIGNAL_CONNECT(save_all_bt, "clicked", eo_save_all_clicked_cb,
260                        object_list);
261         gtk_tooltips_set_tip(GTK_TOOLTIPS(button_bar_tips), save_all_bt,
262                              "Save all displayed objects with their displayed "
263                              "filenames.", NULL);
264         gtk_box_pack_end(GTK_BOX(bbox), save_all_bt, FALSE, FALSE, 0);
265
266         /* Save button */
267         save_bt = BUTTON_NEW_FROM_STOCK(GTK_STOCK_SAVE);
268         SIGNAL_CONNECT(save_bt, "clicked", eo_save_clicked_cb, object_list);
269         gtk_tooltips_set_tip(GTK_TOOLTIPS(button_bar_tips), save_bt,
270                              "Saves the currently selected content to a file.",
271                              NULL);
272         gtk_box_pack_end(GTK_BOX(bbox), save_bt, FALSE, FALSE, 0);
273
274         /* Close button */
275         close_bt = BUTTON_NEW_FROM_STOCK(GTK_STOCK_CLOSE);
276         window_set_cancel_button(object_list->dlg, close_bt,
277                                  window_cancel_button_cb);
278         gtk_tooltips_set_tip(GTK_TOOLTIPS(button_bar_tips), close_bt,
279                              "Close this dialog.", NULL);
280         gtk_box_pack_end(GTK_BOX(bbox), close_bt, FALSE, FALSE, 0);
281
282         /* Pack the buttons into the "button box" */
283         gtk_box_pack_end(GTK_BOX(vbox), bbox, FALSE, FALSE, 0);
284         gtk_widget_show(bbox);
285
286         /* Setup delete/destroy signal handlers */
287         SIGNAL_CONNECT(object_list->dlg, "delete_event",
288                        window_delete_event_cb, NULL);
289         SIGNAL_CONNECT(object_list->dlg, "destroy",
290                        eo_win_destroy_cb, NULL);
291
292         /* Show the window */
293         gtk_widget_show_all(object_list->dlg);
294         window_present(object_list->dlg);
295
296         cf_retap_packets(&cfile, FALSE);
297 }
298 #endif /* GTK_MAJOR_VERSION >= 2 */