Have the frame_tvbuff.c routines not use the global cfile.
[metze/wireshark/wip.git] / ui / gtk / packet_win.c
1 /* packet_win.c
2  * Routines for popping a window to display current packet
3  *
4  * Copyright 2000, Jeffrey C. Foster <jfoste@woodward.com>
5  *
6  * Wireshark - Network traffic analyzer
7  * By Gerald Combs <gerald@wireshark.org>
8  * Copyright 1998 Gerald Combs
9  *
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public License
12  * as published by the Free Software Foundation; either version 2
13  * of the License, or (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23  *
24  * To do:
25  * - Add close button to bottom.
26  * - improve the window Title and allow user to config it
27  * - Add print support ? ( could be a mess)
28  * - Add button to have main window jump to this packet ?
29  */
30
31
32 #include "config.h"
33
34 #include <gtk/gtk.h>
35 #include <gdk/gdkkeysyms.h>
36 #if GTK_CHECK_VERSION(3,0,0)
37 # include <gdk/gdkkeysyms-compat.h>
38 #endif
39
40 #include <string.h>
41
42 #include <epan/epan.h>
43 #include <epan/timestamp.h>
44 #include <epan/packet.h>
45 #include <epan/prefs.h>
46 #include <epan/column.h>
47 #include <epan/addr_resolv.h>
48 #include <epan/epan_dissect.h>
49 #include <epan/strutil.h>
50 #include <epan/tvbuff-int.h>
51 #include <epan/print.h>
52
53 #include "../../file.h"
54 #include "../../summary.h"
55
56 #include "ui/recent.h"
57 #include "ui/simple_dialog.h"
58 #include "ui/ws_ui_util.h"
59
60 #include "ui/gtk/font_utils.h"
61 #include "ui/gtk/main.h"
62 #include "ui/gtk/packet_win.h"
63 #include "ui/gtk/packet_panes.h"
64 #include "ui/gtk/keys.h"
65 #include "ui/gtk/gtkglobals.h"
66 #include "ui/gtk/gui_utils.h"
67 #include "ui/gtk/old-gtk-compat.h"
68
69 #include "frame_tvbuff.h"
70
71 #include "globals.h"
72
73 #define BV_SIZE 75
74 #define TV_SIZE 95
75
76 /* Data structure holding information about a packet-detail window. */
77 struct PacketWinData {
78         frame_data *frame;         /* The frame being displayed */
79         struct wtap_pkthdr phdr;   /* Packet header */
80         guint8     *pd;            /* Packet data */
81         GtkWidget  *main;
82         GtkWidget  *tv_scrollw;
83         GtkWidget  *tree_view;
84         GtkWidget  *bv_nb_ptr;
85         field_info *finfo_selected;
86         epan_dissect_t  edt;
87
88         int pd_offset;
89         int pd_bitoffset;
90 };
91
92 /* List of all the packet-detail windows popped up. */
93 static GList *detail_windows;
94
95 static void new_tree_view_selection_changed_cb(GtkTreeSelection *sel,
96                                                gpointer user_data);
97
98
99 static void destroy_new_window(GObject *object, gpointer user_data);
100
101 static gboolean
102 button_press_handler(GtkWidget *widget, GdkEvent *event, gpointer data _U_)
103 {
104         if (widget == NULL || event == NULL) {
105                 return FALSE;
106         }
107
108         tree_view_select(widget, (GdkEventButton *) event);
109
110         /* GDK_2BUTTON_PRESS is a doubleclick -> expand/collapse tree row */
111         if (event->type == GDK_2BUTTON_PRESS) {
112                 GtkTreePath      *path;
113
114                 if (gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(widget),
115                                                   (gint) (((GdkEventButton *)event)->x),
116                                                   (gint) (((GdkEventButton *)event)->y),
117                                                   &path, NULL, NULL, NULL))
118                 {
119                         if (gtk_tree_view_row_expanded(GTK_TREE_VIEW(widget), path)) {
120                                 gtk_tree_view_collapse_row(GTK_TREE_VIEW(widget), path);
121                         }       else {
122                                 gtk_tree_view_expand_row(GTK_TREE_VIEW(widget), path, FALSE);
123                         }
124                         gtk_tree_path_free(path);
125                 }
126         }
127
128         return FALSE;
129 }
130
131 /* Returns dynamically allocated memory, must be freed by caller after use */
132 static char*
133 create_packet_window_title(void)
134 {
135         GString *title;
136         int i;
137
138         title = g_string_new("");
139
140         /*
141          * Build title of window by getting column data constructed when the
142          * frame was dissected.
143          */
144         for (i = 0; i < cfile.cinfo.num_cols; ++i) {
145                 g_string_append(title, cfile.cinfo.columns[i].col_data);
146                 g_string_append_c(title, ' ');
147         }
148
149         return g_string_free(title, FALSE);
150 }
151
152 static void
153 redissect_packet_window(gpointer object, gpointer user_data _U_)
154 {
155         struct PacketWinData *DataPtr = (struct PacketWinData *)object;
156         char *title;
157
158         /* XXX, can be optimized? */
159         proto_tree_draw(NULL, DataPtr->tree_view);
160         epan_dissect_cleanup(&(DataPtr->edt));
161         epan_dissect_init(&(DataPtr->edt), cfile.epan, TRUE, TRUE);
162         epan_dissect_run(&(DataPtr->edt), cfile.cd_t, &DataPtr->phdr,
163             frame_tvbuff_new(&cfile.provider, DataPtr->frame, DataPtr->pd),
164             DataPtr->frame, NULL);
165         add_byte_views(&(DataPtr->edt), DataPtr->tree_view, DataPtr->bv_nb_ptr);
166         proto_tree_draw(DataPtr->edt.tree, DataPtr->tree_view);
167
168         /* update the window title */
169         title = create_packet_window_title();
170         gtk_window_set_title(GTK_WINDOW(DataPtr->main), title);
171         g_free(title);
172 }
173
174 void new_packet_window(GtkWidget *w _U_, gboolean reference, gboolean editable _U_)
175 {
176         char  *title;
177         GtkWidget *main_w, *main_vbox, *pane,
178                   *tree_view, *tv_scrollw,
179                   *bv_nb_ptr;
180         struct PacketWinData *DataPtr;
181         frame_data *fd;
182
183         if(reference) {
184                 guint32            framenum;
185                 header_field_info *hfinfo;
186
187                 if (! cfile.finfo_selected) {
188                         return;
189                 }
190
191                 hfinfo = cfile.finfo_selected->hfinfo;
192
193                 g_assert(hfinfo);
194
195                 if (hfinfo->type != FT_FRAMENUM) {
196                         return;
197                 }
198
199                 framenum = fvalue_get_uinteger(&cfile.finfo_selected->value);
200
201                 if (framenum == 0) {
202                         return;
203                 }
204
205                 fd = frame_data_sequence_find(cfile.provider.frames, framenum);
206         }
207         else {
208                 fd = cfile.current_frame;
209         }
210
211         if (!fd) {
212                 /* nothing has been captured so far */
213                 return;
214         }
215
216         /* With the new packetlists "lazy columns" it's necessary to reread the record */
217         if (!cf_read_record(&cfile, fd)) {
218                 /* error reading the record */
219                 return;
220         }
221
222         /* Allocate data structure to represent this window. */
223         DataPtr = (struct PacketWinData *) g_malloc(sizeof(struct PacketWinData));
224
225         /* XXX, protect cfile.epan from closing (ref counting?) */
226         DataPtr->frame = fd;
227         DataPtr->phdr  = cfile.phdr;
228         DataPtr->pd = (guint8 *)g_malloc(DataPtr->frame->cap_len);
229         memcpy(DataPtr->pd, ws_buffer_start_ptr(&cfile.buf), DataPtr->frame->cap_len);
230
231         epan_dissect_init(&(DataPtr->edt), cfile.epan, TRUE, TRUE);
232         epan_dissect_run(&(DataPtr->edt), cfile.cd_t, &DataPtr->phdr,
233                          frame_tvbuff_new(&cfile.provider, DataPtr->frame, DataPtr->pd),
234                          DataPtr->frame, &cfile.cinfo);
235         epan_dissect_fill_in_columns(&(DataPtr->edt), FALSE, TRUE);
236
237         /* update the window title */
238         title = create_packet_window_title();
239         main_w = window_new(GTK_WINDOW_TOPLEVEL, title);
240         g_free(title);
241         gtk_window_set_default_size(GTK_WINDOW(main_w), DEF_WIDTH, -1);
242
243         /* Container for paned windows  */
244         main_vbox = ws_gtk_box_new(GTK_ORIENTATION_VERTICAL, 1, FALSE);
245         gtk_container_set_border_width(GTK_CONTAINER(main_vbox), 1);
246         gtk_container_add(GTK_CONTAINER(main_w), main_vbox);
247         gtk_widget_show(main_vbox);
248
249         /* Panes for the tree and byte view */
250         pane = gtk_paned_new(GTK_ORIENTATION_VERTICAL);
251         gtk_box_pack_start(GTK_BOX(main_vbox), pane, TRUE, TRUE, 0);
252         gtk_widget_show(pane);
253
254         /* Tree view */
255         tv_scrollw = proto_tree_view_new(&tree_view);
256         gtk_paned_pack1(GTK_PANED(pane), tv_scrollw, TRUE, TRUE);
257         gtk_widget_set_size_request(tv_scrollw, -1, TV_SIZE);
258         gtk_widget_show(tv_scrollw);
259         gtk_widget_show(tree_view);
260
261         /* Byte view */
262         bv_nb_ptr = byte_view_new();
263         gtk_paned_pack2(GTK_PANED(pane), bv_nb_ptr, FALSE, FALSE);
264         gtk_widget_set_size_request(bv_nb_ptr, -1, BV_SIZE);
265         gtk_widget_show(bv_nb_ptr);
266
267         DataPtr->main = main_w;
268         DataPtr->tv_scrollw = tv_scrollw;
269         DataPtr->tree_view = tree_view;
270         DataPtr->bv_nb_ptr = bv_nb_ptr;
271         detail_windows = g_list_append(detail_windows, DataPtr);
272
273         /* load callback handlers */
274         g_signal_connect(gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view)),
275                          "changed", G_CALLBACK(new_tree_view_selection_changed_cb), DataPtr);
276         g_signal_connect(tree_view, "button_press_event", G_CALLBACK(button_press_handler), NULL);
277                 g_signal_connect(main_w, "destroy", G_CALLBACK(destroy_new_window), DataPtr);
278
279         /* draw the protocol tree & print hex data */
280         add_byte_views(&(DataPtr->edt), tree_view, DataPtr->bv_nb_ptr);
281         proto_tree_draw(DataPtr->edt.tree, tree_view);
282
283         DataPtr->finfo_selected = NULL;
284         DataPtr->pd_offset = 0;
285         DataPtr->pd_bitoffset = 0;
286         gtk_widget_show(main_w);
287 }
288
289 void
290 redissect_all_packet_windows(void)
291 {
292         g_list_foreach(detail_windows, redissect_packet_window, NULL);
293 }
294
295 static void
296 destroy_new_window(GObject *object _U_, gpointer user_data)
297 {
298         struct PacketWinData *DataPtr = (struct PacketWinData *)user_data;
299
300         detail_windows = g_list_remove(detail_windows, DataPtr);
301         proto_tree_draw(NULL, DataPtr->tree_view);
302         epan_dissect_cleanup(&(DataPtr->edt));
303         g_free(DataPtr->pd);
304         g_free(DataPtr);
305 }
306
307 /* called when a tree row is (un)selected in the popup packet window */
308 static void
309 new_tree_view_selection_changed_cb(GtkTreeSelection *sel, gpointer user_data)
310 {
311         field_info   *finfo;
312         GtkWidget    *byte_view;
313         const guint8 *data;
314         guint         len;
315         GtkTreeModel *model;
316         GtkTreeIter   iter;
317
318         struct PacketWinData *DataPtr = (struct PacketWinData*)user_data;
319
320         /* if something is selected */
321         if (gtk_tree_selection_get_selected(sel, &model, &iter))
322         {
323                 gtk_tree_model_get(model, &iter, 1, &finfo, -1);
324                 if (!finfo) return;
325
326                 set_notebook_page(DataPtr->bv_nb_ptr, finfo->ds_tvb);
327                 byte_view = get_notebook_bv_ptr(DataPtr->bv_nb_ptr);
328                 if (!byte_view) /* exit if no hex window to write in */
329                         return;
330
331                 data = get_byte_view_data_and_length(byte_view, &len);
332                 if (data == NULL) {
333                         data = DataPtr->pd;
334                         len =  DataPtr->frame->cap_len;
335                 }
336
337                 DataPtr->finfo_selected = finfo;
338
339                 packet_hex_print(byte_view, data, DataPtr->frame, finfo, len);
340         }
341         else
342         {
343                 DataPtr->finfo_selected = NULL;
344
345                 byte_view = get_notebook_bv_ptr(DataPtr->bv_nb_ptr);
346                 if (!byte_view) /* exit if no hex window to write in */
347                         return;
348
349                 data = get_byte_view_data_and_length(byte_view, &len);
350                 g_assert(data != NULL);
351                 packet_hex_reprint(byte_view);
352         }
353 }
354
355 /* Functions called from elsewhere to act on all popup packet windows. */
356
357 /* Destroy all popup packet windows. */
358 void
359 destroy_packet_wins(void)
360 {
361         struct PacketWinData *DataPtr;
362
363         /* Destroying a packet window causes it to be removed from
364            the list of packet windows, so we can't do a "g_list_foreach()"
365            to go through the list of all packet windows and destroy them
366            as we find them; instead, as long as the list is non-empty,
367            we destroy the first window on the list. */
368         while (detail_windows != NULL) {
369                 DataPtr = (struct PacketWinData *)(detail_windows->data);
370                 window_destroy(DataPtr->main);
371         }
372 }
373
374 static void
375 redraw_packet_bytes_cb(gpointer data, gpointer user_data _U_)
376 {
377         struct PacketWinData *DataPtr = (struct PacketWinData *)data;
378
379         redraw_packet_bytes(DataPtr->bv_nb_ptr, DataPtr->frame, DataPtr->finfo_selected);
380 }
381
382 /* Redraw the packet bytes part of all the popup packet windows. */
383 void
384 redraw_packet_bytes_packet_wins(void)
385 {
386         g_list_foreach(detail_windows, redraw_packet_bytes_cb, NULL);
387 }
388
389 /*
390  * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
391  *
392  * Local variables:
393  * c-basic-offset: 8
394  * tab-width: 8
395  * indent-tabs-mode: t
396  * End:
397  *
398  * vi: set shiftwidth=8 tabstop=8 noexpandtab:
399  * :indentSize=8:tabSize=8:noTabs=false:
400  */