Use G_GINT64_CONSTANT to handle 64-bit constants in the code.
[obnox/wireshark/wip.git] / 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  * $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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
25  *
26  * To do:
27  * - Add close button to bottom.
28  * - improve the window Title and allow user to config it
29  * - Add print support ? ( could be a mess)
30  * - Add button to have main window jump to this packet ?
31  */
32
33
34 #ifdef HAVE_CONFIG_H
35 # include "config.h"
36 #endif
37
38 #include <gtk/gtk.h>
39
40 #include <string.h>
41
42 #include <epan/epan.h>
43 #include "main.h"
44 #include <epan/timestamp.h>
45 #include <epan/packet.h>
46 #include "summary.h"
47 #include "file.h"
48 #include <epan/prefs.h>
49 #include "menu.h"
50 #include "../menu.h"
51 #include <epan/column.h>
52 #include "print.h"
53 #include <epan/addr_resolv.h>
54 #include "packet_win.h"
55 #include "simple_dialog.h"
56 #include "proto_draw.h"
57 #include "keys.h"
58 #include "gtkglobals.h"
59 #include "gui_utils.h"
60 #include <epan/plugins.h>
61 #include <epan/epan_dissect.h>
62 #include "compat_macros.h"
63
64 #include "../ui_util.h"
65
66 /* Data structure holding information about a packet-detail window. */
67 struct PacketWinData {
68         frame_data *frame;         /* The frame being displayed */
69         union wtap_pseudo_header pseudo_header; /* Pseudo-header for packet */
70         guint8     *pd;            /* Data for packet */
71         GtkWidget  *main;
72         GtkWidget  *tv_scrollw;
73         GtkWidget  *tree_view;
74         GtkWidget  *bv_nb_ptr;
75         field_info *finfo_selected;
76         epan_dissect_t  *edt;
77 };
78
79 /* List of all the packet-detail windows popped up. */
80 static GList *detail_windows;
81
82 #if GTK_MAJOR_VERSION < 2
83 static void new_tree_view_select_row_cb(GtkCTree *ctree, GList *node,
84                                         gint column, gpointer user_data);
85
86 static void new_tree_view_unselect_row_cb( GtkCTree *ctree, GList *node,
87                                            gint column, gpointer user_data);
88 #else
89 static void new_tree_view_selection_changed_cb(GtkTreeSelection *sel,
90                                                gpointer user_data);
91
92 #endif
93
94 static void destroy_new_window(GtkObject *object, gpointer user_data);
95
96 void new_window_cb(GtkWidget *w _U_)
97 {
98 #define NewWinTitleLen 1000
99   char Title[NewWinTitleLen] = "";
100   const char *TextPtr;
101   gint tv_size = 95, bv_size = 75;
102   GtkWidget *main_w, *main_vbox, *pane,
103                       *tree_view, *tv_scrollw,
104                       *bv_nb_ptr;
105   struct PacketWinData *DataPtr;
106   int i;
107
108   /* Allocate data structure to represent this window. */
109   DataPtr = (struct PacketWinData *) g_malloc(sizeof(struct PacketWinData));
110
111   DataPtr->frame = cfile.current_frame;
112   memcpy(&DataPtr->pseudo_header, &cfile.pseudo_header, sizeof DataPtr->pseudo_header);
113   DataPtr->pd = g_malloc(DataPtr->frame->cap_len);
114   memcpy(DataPtr->pd, cfile.pd, DataPtr->frame->cap_len);
115   DataPtr->edt = epan_dissect_new(TRUE, TRUE);
116   epan_dissect_run(DataPtr->edt, &DataPtr->pseudo_header, DataPtr->pd,
117           DataPtr->frame, &cfile.cinfo);
118   epan_dissect_fill_in_columns(DataPtr->edt);
119
120   /*
121    * Build title of window by getting column data constructed when the
122    * frame was dissected.
123    */
124   for (i = 0; i < cfile.cinfo.num_cols; ++i) {
125     TextPtr = cfile.cinfo.col_data[i];
126     if ((strlen(Title) + strlen(TextPtr)) < NewWinTitleLen - 1) {
127       strcat(Title, TextPtr);
128       strcat(Title, " ");
129     }
130   }
131
132   main_w = window_new(GTK_WINDOW_TOPLEVEL, Title);
133   gtk_window_set_default_size(GTK_WINDOW(main_w), DEF_WIDTH, -1);
134
135   /* Container for paned windows  */
136   main_vbox = gtk_vbox_new(FALSE, 1);
137   gtk_container_border_width(GTK_CONTAINER(main_vbox), 1);
138   gtk_container_add(GTK_CONTAINER(main_w), main_vbox);
139   gtk_widget_show(main_vbox);
140
141   /* Panes for the tree and byte view */
142   pane = gtk_vpaned_new();
143   gtk_paned_gutter_size(GTK_PANED(pane), (GTK_PANED(pane))->handle_size);
144   gtk_container_add(GTK_CONTAINER(main_vbox), pane);
145   gtk_widget_show(pane);
146
147   /* Tree view */
148   tv_scrollw = main_tree_view_new(&prefs, &tree_view);
149   gtk_paned_pack1(GTK_PANED(pane), tv_scrollw, TRUE, TRUE);
150   WIDGET_SET_SIZE(tv_scrollw, -1, tv_size);
151   gtk_widget_show(tv_scrollw);
152   gtk_widget_show(tree_view);
153
154   /* Byte view */
155   bv_nb_ptr = byte_view_new();
156   gtk_paned_pack2(GTK_PANED(pane), bv_nb_ptr, FALSE, FALSE);
157   WIDGET_SET_SIZE(bv_nb_ptr, -1, bv_size);
158   gtk_widget_show(bv_nb_ptr);
159
160   DataPtr->main = main_w;
161   DataPtr->tv_scrollw = tv_scrollw;
162   DataPtr->tree_view = tree_view;
163   DataPtr->bv_nb_ptr = bv_nb_ptr;
164   detail_windows = g_list_append(detail_windows, DataPtr);
165
166   /* load callback handlers */
167 #if GTK_MAJOR_VERSION < 2
168   SIGNAL_CONNECT(tree_view, "tree-select-row", new_tree_view_select_row_cb,
169                  DataPtr);
170
171   SIGNAL_CONNECT(tree_view, "tree-unselect-row", new_tree_view_unselect_row_cb,
172                  DataPtr);
173 #else
174   SIGNAL_CONNECT(gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view)),
175                  "changed", new_tree_view_selection_changed_cb, DataPtr);
176 #endif
177
178   SIGNAL_CONNECT(main_w, "destroy", destroy_new_window, DataPtr);
179
180   /* draw the protocol tree & print hex data */
181   add_byte_views(DataPtr->edt, tree_view, DataPtr->bv_nb_ptr);
182   proto_tree_draw(DataPtr->edt->tree, tree_view);
183
184   DataPtr->finfo_selected = NULL;
185   gtk_widget_show(main_w);
186 }
187
188 static void
189 destroy_new_window(GtkObject *object _U_, gpointer user_data)
190 {
191   struct PacketWinData *DataPtr = user_data;
192
193   detail_windows = g_list_remove(detail_windows, DataPtr);
194   epan_dissect_free(DataPtr->edt);
195   g_free(DataPtr->pd);
196   g_free(DataPtr);
197 }
198
199 #if GTK_MAJOR_VERSION < 2
200 /* called when a tree row is selected in the popup packet window */
201 static void
202 new_tree_view_select_row_cb(GtkCTree *ctree, GList *node, gint column _U_,
203                             gpointer user_data)
204 {
205         field_info *finfo;
206         GtkWidget *byte_view;
207         const guint8 *data;
208         guint len;
209
210         struct PacketWinData *DataPtr = (struct PacketWinData*)user_data;
211
212         g_assert(node);
213         finfo = gtk_ctree_node_get_row_data( ctree, GTK_CTREE_NODE(node) );
214         if (!finfo) return;
215
216         set_notebook_page(DataPtr->bv_nb_ptr, finfo->ds_tvb);
217         byte_view = get_notebook_bv_ptr(DataPtr->bv_nb_ptr);
218         if ( !byte_view)        /* exit if no hex window to write in */
219                 return;
220
221         data = get_byte_view_data_and_length(byte_view, &len);
222         if (data == NULL) {
223                 data = DataPtr->pd;
224                 len =  DataPtr->frame->cap_len;
225         }
226
227         DataPtr->finfo_selected = finfo;
228         packet_hex_print(GTK_TEXT(byte_view), data,
229                 DataPtr->frame, finfo, len);
230 }
231
232 /* called when a tree row is unselected in the popup packet window */
233 static void
234 new_tree_view_unselect_row_cb(GtkCTree *ctree _U_, GList *node _U_,
235                               gint column _U_, gpointer user_data)
236 {
237         GtkWidget* byte_view;
238         const guint8* data;
239         guint len;
240
241         struct PacketWinData *DataPtr = (struct PacketWinData*)user_data;
242
243         DataPtr->finfo_selected = NULL;
244
245         byte_view = get_notebook_bv_ptr(DataPtr->bv_nb_ptr);
246         if ( !byte_view)        /* exit if no hex window to write in */
247                 return;
248
249         data = get_byte_view_data_and_length(byte_view, &len);
250         g_assert(data != NULL);
251         packet_hex_reprint(GTK_TEXT(byte_view));
252 }
253 #else
254 /* called when a tree row is (un)selected in the popup packet window */
255 static void
256 new_tree_view_selection_changed_cb(GtkTreeSelection *sel, gpointer user_data)
257 {
258     field_info   *finfo;
259     GtkWidget    *byte_view;
260     const guint8 *data;
261     guint         len;
262     GtkTreeModel *model;
263     GtkTreeIter   iter;
264
265     struct PacketWinData *DataPtr = (struct PacketWinData*)user_data;
266
267     /* if something is selected */
268     if (gtk_tree_selection_get_selected(sel, &model, &iter))
269     {
270         gtk_tree_model_get(model, &iter, 1, &finfo, -1);
271         if (!finfo) return;
272
273         set_notebook_page(DataPtr->bv_nb_ptr, finfo->ds_tvb);
274         byte_view = get_notebook_bv_ptr(DataPtr->bv_nb_ptr);
275         if (!byte_view) /* exit if no hex window to write in */
276             return;
277
278         data = get_byte_view_data_and_length(byte_view, &len);
279         if (data == NULL) {
280             data = DataPtr->pd;
281             len =  DataPtr->frame->cap_len;
282         }
283
284         DataPtr->finfo_selected = finfo;
285         packet_hex_print(GTK_TEXT_VIEW(byte_view), data,
286                          DataPtr->frame, finfo, len);
287     }
288     else
289     {
290         DataPtr->finfo_selected = NULL;
291
292         byte_view = get_notebook_bv_ptr(DataPtr->bv_nb_ptr);
293         if (!byte_view) /* exit if no hex window to write in */
294             return;
295
296         data = get_byte_view_data_and_length(byte_view, &len);
297         g_assert(data != NULL);
298         packet_hex_reprint(GTK_TEXT_VIEW(byte_view));
299     }
300 }
301 #endif
302
303 /* Functions called from elsewhere to act on all popup packet windows. */
304
305 /* Destroy all popup packet windows. */
306 void
307 destroy_packet_wins(void)
308 {
309         struct PacketWinData *DataPtr;
310
311         /* Destroying a packet window causes it to be removed from
312            the list of packet windows, so we can't do a "g_list_foreach()"
313            to go through the list of all packet windows and destroy them
314            as we find them; instead, as long as the list is non-empty,
315            we destroy the first window on the list. */
316         while (detail_windows != NULL) {
317                 DataPtr = (struct PacketWinData *)(detail_windows->data);
318                 window_destroy(DataPtr->main);
319         }
320 }
321
322 static void
323 redraw_hex_dump_cb(gpointer data, gpointer user_data _U_)
324 {
325         struct PacketWinData *DataPtr = (struct PacketWinData *)data;
326
327         redraw_hex_dump(DataPtr->bv_nb_ptr, DataPtr->frame, DataPtr->finfo_selected);
328 }
329
330 /* Redraw the hex dump part of all the popup packet windows. */
331 void
332 redraw_hex_dump_packet_wins(void)
333 {
334         g_list_foreach(detail_windows, redraw_hex_dump_cb, NULL);
335 }