19f068ce64a9d6d05858fabff9d801e7680315f4
[metze/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 #ifdef HAVE_SYS_TYPES_H
39 #include <sys/types.h>
40 #endif
41
42 #include <gtk/gtk.h>
43
44 #include <string.h>
45
46 #include <epan/epan.h>
47 #include <epan/timestamp.h>
48 #include <epan/packet.h>
49 #include <epan/prefs.h>
50 #include <epan/column.h>
51 #include <epan/addr_resolv.h>
52 #include <epan/plugins.h>
53 #include <epan/epan_dissect.h>
54 #include <epan/strutil.h>
55
56 #include "../file.h"
57 #include "../print.h"
58 #include "../ui_util.h"
59 #include "../summary.h"
60
61 #include "gtk/main.h"
62 #include "gtk/packet_win.h"
63 #include "gtk/main_proto_draw.h"
64 #include "gtk/keys.h"
65 #include "gtk/gtkglobals.h"
66 #include "gtk/gui_utils.h"
67
68
69 /* Data structure holding information about a packet-detail window. */
70 struct PacketWinData {
71         frame_data *frame;         /* The frame being displayed */
72         union wtap_pseudo_header pseudo_header; /* Pseudo-header for packet */
73         guint8     *pd;            /* Data for packet */
74         GtkWidget  *main;
75         GtkWidget  *tv_scrollw;
76         GtkWidget  *tree_view;
77         GtkWidget  *bv_nb_ptr;
78         field_info *finfo_selected;
79         epan_dissect_t  *edt;
80 };
81
82 /* List of all the packet-detail windows popped up. */
83 static GList *detail_windows;
84
85 static void new_tree_view_selection_changed_cb(GtkTreeSelection *sel,
86                                                gpointer user_data);
87
88
89 static void destroy_new_window(GtkObject *object, gpointer user_data);
90
91 static gboolean
92 button_press_handler(GtkWidget *widget, GdkEvent *event, gpointer data _U_)
93 {
94   if (widget == NULL || event == NULL) {
95     return FALSE;
96   }
97
98   tree_view_select(widget, (GdkEventButton *) event);
99
100   /* GDK_2BUTTON_PRESS is a doubleclick -> expand/collapse tree row */
101   if (event->type == GDK_2BUTTON_PRESS) {
102     GtkTreePath      *path;
103
104     if (gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(widget),
105                                       (gint) (((GdkEventButton *)event)->x),
106                                       (gint) (((GdkEventButton *)event)->y),
107                                       &path, NULL, NULL, NULL))
108     {
109       if (gtk_tree_view_row_expanded(GTK_TREE_VIEW(widget), path)) {
110         gtk_tree_view_collapse_row(GTK_TREE_VIEW(widget), path);
111       } else {
112         gtk_tree_view_expand_row(GTK_TREE_VIEW(widget), path, FALSE);
113       }
114       gtk_tree_path_free(path);
115     }
116   }
117
118   return FALSE;
119 }
120
121 void new_window_cb(GtkWidget *w _U_)
122 {
123 #define NewWinTitleLen 1000
124   char Title[NewWinTitleLen] = "";
125   const char *TextPtr;
126   gint tv_size = 95, bv_size = 75;
127   GtkWidget *main_w, *main_vbox, *pane,
128                       *tree_view, *tv_scrollw,
129                       *bv_nb_ptr;
130   struct PacketWinData *DataPtr;
131   int i;
132
133   if (!cfile.current_frame) {
134     /* nothing has been captured so far */
135     return;
136   }
137
138 #ifdef NEW_PACKET_LIST
139
140   /* With the new packetlists "lazy columns" it's neccesary to reread the frame */
141   if (!cf_read_frame(&cfile, cfile.current_frame)) {
142     /* error reading the frame */
143     return;
144   }
145 #endif
146
147   /* Allocate data structure to represent this window. */
148   DataPtr = (struct PacketWinData *) g_malloc(sizeof(struct PacketWinData));
149
150   DataPtr->frame = cfile.current_frame;
151   memcpy(&DataPtr->pseudo_header, &cfile.pseudo_header, sizeof DataPtr->pseudo_header);
152   DataPtr->pd = g_malloc(DataPtr->frame->cap_len);
153   memcpy(DataPtr->pd, cfile.pd, DataPtr->frame->cap_len);
154   DataPtr->edt = epan_dissect_new(TRUE, TRUE);
155   epan_dissect_run(DataPtr->edt, &DataPtr->pseudo_header, DataPtr->pd,
156           DataPtr->frame, &cfile.cinfo);
157   epan_dissect_fill_in_columns(DataPtr->edt, FALSE, TRUE);
158
159   /*
160    * Build title of window by getting column data constructed when the
161    * frame was dissected.
162    */
163   for (i = 0; i < cfile.cinfo.num_cols; ++i) {
164     TextPtr = cfile.cinfo.col_data[i];
165     if ((strlen(Title) + strlen(TextPtr)) < NewWinTitleLen - 1) {
166       g_strlcat(Title, TextPtr, NewWinTitleLen);
167       g_strlcat(Title, " ", NewWinTitleLen);
168     }
169   }
170
171   main_w = window_new(GTK_WINDOW_TOPLEVEL, Title);
172   gtk_window_set_default_size(GTK_WINDOW(main_w), DEF_WIDTH, -1);
173
174   /* Container for paned windows  */
175   main_vbox = gtk_vbox_new(FALSE, 1);
176   gtk_container_set_border_width(GTK_CONTAINER(main_vbox), 1);
177   gtk_container_add(GTK_CONTAINER(main_w), main_vbox);
178   gtk_widget_show(main_vbox);
179
180   /* Panes for the tree and byte view */
181   pane = gtk_vpaned_new();
182   gtk_container_add(GTK_CONTAINER(main_vbox), pane);
183   gtk_widget_show(pane);
184
185   /* Tree view */
186   tv_scrollw = main_tree_view_new(&prefs, &tree_view);
187   gtk_paned_pack1(GTK_PANED(pane), tv_scrollw, TRUE, TRUE);
188   gtk_widget_set_size_request(tv_scrollw, -1, tv_size);
189   gtk_widget_show(tv_scrollw);
190   gtk_widget_show(tree_view);
191
192   /* Byte view */
193   bv_nb_ptr = byte_view_new();
194   gtk_paned_pack2(GTK_PANED(pane), bv_nb_ptr, FALSE, FALSE);
195   gtk_widget_set_size_request(bv_nb_ptr, -1, bv_size);
196   gtk_widget_show(bv_nb_ptr);
197
198   DataPtr->main = main_w;
199   DataPtr->tv_scrollw = tv_scrollw;
200   DataPtr->tree_view = tree_view;
201   DataPtr->bv_nb_ptr = bv_nb_ptr;
202   detail_windows = g_list_append(detail_windows, DataPtr);
203
204   /* load callback handlers */
205   g_signal_connect(gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view)),
206                  "changed", G_CALLBACK(new_tree_view_selection_changed_cb), DataPtr);
207   g_signal_connect(tree_view, "button_press_event", G_CALLBACK(button_press_handler), NULL);
208   g_signal_connect(main_w, "destroy", G_CALLBACK(destroy_new_window), DataPtr);
209
210   /* draw the protocol tree & print hex data */
211   add_byte_views(DataPtr->edt, tree_view, DataPtr->bv_nb_ptr);
212   proto_tree_draw(DataPtr->edt->tree, tree_view);
213
214   DataPtr->finfo_selected = NULL;
215   gtk_widget_show(main_w);
216 }
217
218 static void
219 destroy_new_window(GtkObject *object _U_, gpointer user_data)
220 {
221   struct PacketWinData *DataPtr = user_data;
222
223   detail_windows = g_list_remove(detail_windows, DataPtr);
224   epan_dissect_free(DataPtr->edt);
225   g_free(DataPtr->pd);
226   g_free(DataPtr);
227 }
228
229 /* called when a tree row is (un)selected in the popup packet window */
230 static void
231 new_tree_view_selection_changed_cb(GtkTreeSelection *sel, gpointer user_data)
232 {
233     field_info   *finfo;
234     GtkWidget    *byte_view;
235     const guint8 *data;
236     guint         len;
237     GtkTreeModel *model;
238     GtkTreeIter   iter;
239
240     struct PacketWinData *DataPtr = (struct PacketWinData*)user_data;
241
242     /* if something is selected */
243     if (gtk_tree_selection_get_selected(sel, &model, &iter))
244     {
245         gtk_tree_model_get(model, &iter, 1, &finfo, -1);
246         if (!finfo) return;
247
248         set_notebook_page(DataPtr->bv_nb_ptr, finfo->ds_tvb);
249         byte_view = get_notebook_bv_ptr(DataPtr->bv_nb_ptr);
250         if (!byte_view) /* exit if no hex window to write in */
251             return;
252
253         data = get_byte_view_data_and_length(byte_view, &len);
254         if (data == NULL) {
255             data = DataPtr->pd;
256             len =  DataPtr->frame->cap_len;
257         }
258
259         DataPtr->finfo_selected = finfo;
260         packet_hex_print(byte_view, data, DataPtr->frame, finfo, len);
261     }
262     else
263     {
264         DataPtr->finfo_selected = NULL;
265
266         byte_view = get_notebook_bv_ptr(DataPtr->bv_nb_ptr);
267         if (!byte_view) /* exit if no hex window to write in */
268             return;
269
270         data = get_byte_view_data_and_length(byte_view, &len);
271         g_assert(data != NULL);
272         packet_hex_reprint(byte_view);
273     }
274 }
275
276 /* Functions called from elsewhere to act on all popup packet windows. */
277
278 /* Destroy all popup packet windows. */
279 void
280 destroy_packet_wins(void)
281 {
282         struct PacketWinData *DataPtr;
283
284         /* Destroying a packet window causes it to be removed from
285            the list of packet windows, so we can't do a "g_list_foreach()"
286            to go through the list of all packet windows and destroy them
287            as we find them; instead, as long as the list is non-empty,
288            we destroy the first window on the list. */
289         while (detail_windows != NULL) {
290                 DataPtr = (struct PacketWinData *)(detail_windows->data);
291                 window_destroy(DataPtr->main);
292         }
293 }
294
295 static void
296 redraw_packet_bytes_cb(gpointer data, gpointer user_data _U_)
297 {
298         struct PacketWinData *DataPtr = (struct PacketWinData *)data;
299
300         redraw_packet_bytes(DataPtr->bv_nb_ptr, DataPtr->frame, DataPtr->finfo_selected);
301 }
302
303 /* Redraw the packet bytes part of all the popup packet windows. */
304 void
305 redraw_packet_bytes_packet_wins(void)
306 {
307         g_list_foreach(detail_windows, redraw_packet_bytes_cb, NULL);
308 }