2 * Routines for popping a window to display current packet
4 * Copyright 2000, Jeffrey C. Foster <jfoste@woodward.com>
8 * Wireshark - Network traffic analyzer
9 * By Gerald Combs <gerald@wireshark.org>
10 * Copyright 1998 Gerald Combs
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.
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.
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 USA.
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 ?
37 #include <gdk/gdkkeysyms.h>
38 #if GTK_CHECK_VERSION(3,0,0)
39 # include <gdk/gdkkeysyms-compat.h>
44 #include <epan/epan.h>
45 #include <epan/timestamp.h>
46 #include <epan/packet.h>
47 #include <epan/prefs.h>
48 #include <epan/column.h>
49 #include <epan/addr_resolv.h>
50 #include <epan/plugins.h>
51 #include <epan/epan_dissect.h>
52 #include <epan/strutil.h>
53 #include <epan/tvbuff-int.h>
57 #include "../summary.h"
59 #include "ui/recent.h"
60 #include "ui/simple_dialog.h"
61 #include "ui/ui_util.h"
63 #include "ui/gtk/font_utils.h"
64 #include "ui/gtk/main.h"
65 #include "ui/gtk/packet_win.h"
66 #include "ui/gtk/packet_panes.h"
67 #include "ui/gtk/keys.h"
68 #include "ui/gtk/gtkglobals.h"
69 #include "ui/gtk/gui_utils.h"
74 /* Data structure holding information about a packet-detail window. */
75 struct PacketWinData {
76 frame_data *frame; /* The frame being displayed */
77 struct wtap_pkthdr phdr; /* Packet header */
78 guint8 *pd; /* Packet data */
80 GtkWidget *tv_scrollw;
83 field_info *finfo_selected;
90 #ifdef WANT_PACKET_EDITOR
91 struct FieldinfoWinData {
92 frame_data *frame; /* The frame being displayed */
93 struct wtap_pkthdr phdr; /* Packet header */
94 guint8 *pd; /* Packet data */
109 struct CommonWinData {
110 frame_data *frame; /* The frame being displayed */
111 guint8 *pd; /* Data for packet */
118 static gboolean edit_pkt_common_key_pressed_cb(GdkEventKey *event, struct CommonWinData *DataPtr);
121 /* List of all the packet-detail windows popped up. */
122 static GList *detail_windows;
124 static void new_tree_view_selection_changed_cb(GtkTreeSelection *sel,
128 static void destroy_new_window(GObject *object, gpointer user_data);
131 button_press_handler(GtkWidget *widget, GdkEvent *event, gpointer data _U_)
133 if (widget == NULL || event == NULL) {
137 tree_view_select(widget, (GdkEventButton *) event);
139 /* GDK_2BUTTON_PRESS is a doubleclick -> expand/collapse tree row */
140 if (event->type == GDK_2BUTTON_PRESS) {
143 if (gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(widget),
144 (gint) (((GdkEventButton *)event)->x),
145 (gint) (((GdkEventButton *)event)->y),
146 &path, NULL, NULL, NULL))
148 if (gtk_tree_view_row_expanded(GTK_TREE_VIEW(widget), path)) {
149 gtk_tree_view_collapse_row(GTK_TREE_VIEW(widget), path);
151 gtk_tree_view_expand_row(GTK_TREE_VIEW(widget), path, FALSE);
153 gtk_tree_path_free(path);
160 #ifdef WANT_PACKET_EDITOR
162 proto_finfo_find(proto_tree *tree, field_info *old_finfo)
166 for (node = tree->first_child; node != NULL; node = node->next) {
167 field_info *cur = PNODE_FINFO(node);
172 /* check everything, if it doesn't work report to me */
173 if (cur->hfinfo == old_finfo->hfinfo &&
174 cur->start == old_finfo->start && cur->length == old_finfo->length &&
175 cur->appendix_start == old_finfo->appendix_start && cur->appendix_length == old_finfo->appendix_length &&
176 cur->tree_type == old_finfo->tree_type && cur->flags == old_finfo->flags)
181 if ((cur = proto_finfo_find((proto_tree *)node, old_finfo)))
188 finfo_window_refresh(struct FieldinfoWinData *DataPtr)
190 field_info *old_finfo = DataPtr->finfo;
195 GtkWidget *byte_view;
196 gchar label_str[ITEM_LABEL_LENGTH];
198 /* always update byteviews */
199 if (DataPtr->bv && (byte_view = get_notebook_bv_ptr(DataPtr->bv))) {
200 int pos_inside = DataPtr->pd_offset - DataPtr->start_offset - old_finfo->start;
202 if (pos_inside < 0 || pos_inside >= old_finfo->length)
205 data = DataPtr->pd + DataPtr->start_offset + old_finfo->start;
206 packet_hex_editor_print(byte_view, data, DataPtr->frame, pos_inside, DataPtr->pd_bitoffset, old_finfo->length);
209 if (DataPtr->app_bv && (byte_view = get_notebook_bv_ptr(DataPtr->app_bv))) {
210 int pos_inside = DataPtr->pd_offset - DataPtr->start_offset - old_finfo->appendix_start;
212 if (pos_inside < 0 || pos_inside >= old_finfo->appendix_length)
215 data = DataPtr->pd + DataPtr->start_offset + old_finfo->appendix_start;
216 packet_hex_editor_print(byte_view, data, DataPtr->frame, pos_inside, DataPtr->pd_bitoffset, old_finfo->appendix_length);
220 epan_dissect_init(&edt, TRUE, TRUE);
222 if (old_finfo->hfinfo)
223 proto_tree_prime_hfid(edt.tree, old_finfo->hfinfo->id);
225 epan_dissect_run(&edt, &DataPtr->phdr, DataPtr->pd, DataPtr->frame, NULL);
227 /* Try to find finfo which looks like old_finfo.
228 * We might not found one, if protocol requires specific magic values, etc... */
229 if (!(finfo = proto_finfo_find(edt.tree, old_finfo))) {
230 epan_dissect_cleanup(&edt);
231 gtk_entry_set_text(GTK_ENTRY(DataPtr->repr), "[finfo not found, try with another value, or restore old. If you think it is bug, fill bugreport]");
235 /* XXX, update fvalue_edit, e.g. when hexedit was changed */
237 if (finfo->rep == NULL) {
238 proto_item_fill_label(finfo, label_str);
239 gtk_entry_set_text(GTK_ENTRY(DataPtr->repr), label_str);
241 gtk_entry_set_text(GTK_ENTRY(DataPtr->repr), finfo->rep->representation);
243 epan_dissect_cleanup(&edt);
248 finfo_integer_common(struct FieldinfoWinData *DataPtr, guint64 u_val)
250 const field_info *finfo = DataPtr->finfo;
251 const header_field_info *hfinfo = finfo->hfinfo;
253 unsigned int finfo_offset = DataPtr->start_offset + finfo->start;
254 int finfo_length = finfo->length;
256 if (finfo_offset <= DataPtr->frame->cap_len && finfo_offset + finfo_length <= DataPtr->frame->cap_len) {
257 guint32 u_mask = hfinfo->bitmask;
259 while (finfo_length--) {
260 guint8 *ptr = (FI_GET_FLAG(finfo, FI_LITTLE_ENDIAN)) ?
261 &(DataPtr->pd[finfo_offset++]) :
262 &(DataPtr->pd[finfo_offset + finfo_length]);
268 for (i = 0; i < 8; i++) {
288 finfo_window_refresh(DataPtr);
292 finfo_string_changed(GtkEditable *editable, gpointer user_data)
294 struct FieldinfoWinData *DataPtr = (struct FieldinfoWinData *) user_data;
297 const field_info *finfo = DataPtr->finfo;
298 unsigned int finfo_offset = DataPtr->start_offset + finfo->start;
299 int finfo_length = finfo->length;
300 int finfo_type = (finfo->hfinfo) ? finfo->hfinfo->type : FT_NONE;
302 const gchar *val = gtk_entry_get_text(GTK_ENTRY(editable));
304 if (finfo_offset <= DataPtr->frame->cap_len && finfo_offset + finfo_length <= DataPtr->frame->cap_len) {
306 while (finfo_length && *val) {
307 DataPtr->pd[finfo_offset++] = *val;
312 /* When FT_STRINGZ is there free space for NUL? */
313 if (finfo_type == FT_STRINGZ && finfo_length) {
314 DataPtr->pd[finfo_offset++] = '\0';
318 /* XXX, string shorter than previous one. Warn user (red background?), for now fill with NULs */
319 while (finfo_length > 0) {
320 DataPtr->pd[finfo_offset++] = '\0';
324 finfo_window_refresh(DataPtr);
328 finfo_boolean_changed(GtkToggleButton *togglebutton, gpointer user_data)
330 struct FieldinfoWinData *DataPtr = (struct FieldinfoWinData *) user_data;
332 gboolean val = gtk_toggle_button_get_active(togglebutton);
334 finfo_integer_common(DataPtr, val ? G_MAXUINT64 : 0);
338 finfo_integer_changed(GtkSpinButton *spinbutton, gpointer user_data)
340 struct FieldinfoWinData *DataPtr = (struct FieldinfoWinData *) user_data;
342 const field_info *finfo = DataPtr->finfo;
343 const header_field_info *hfinfo = finfo->hfinfo;
344 int finfo_type = (hfinfo) ? hfinfo->type : FT_NONE;
346 gdouble val = gtk_spin_button_get_value(spinbutton);
349 if (finfo_type == FT_INT8 || finfo_type == FT_INT16 || finfo_type == FT_INT24 || finfo_type == FT_INT32 || finfo_type == FT_INT64)
350 u_val = (guint64) ((gint64) val);
352 else if (finfo_type == FT_UINT8 || finfo_type == FT_UINT16 || finfo_type == FT_UINT24 || finfo_type == FT_UINT32 || finfo_type == FT_UINT64)
353 u_val = (guint64) val;
355 g_assert_not_reached();
359 if (hfinfo->bitmask && hfinfo->bitshift > 0)
360 u_val <<= hfinfo->bitshift;
362 finfo_integer_common(DataPtr, u_val);
366 finfo_ipv4_changed(GtkSpinButton *spinbutton, gpointer user_data)
368 struct FieldinfoWinData *DataPtr = (struct FieldinfoWinData *) user_data;
370 gdouble val = gtk_spin_button_get_value(spinbutton);
372 finfo_integer_common(DataPtr, (guint32) val);
376 finfo_bv_key_pressed_cb(GtkWidget *bv _U_, GdkEventKey *event, gpointer user_data)
378 struct FieldinfoWinData *DataPtr = (struct FieldinfoWinData *)user_data;
379 const field_info *finfo = DataPtr->finfo;
380 struct CommonWinData data;
381 gboolean have_appendix;
385 data.frame = DataPtr->frame;
386 data.pd = DataPtr->pd;
387 data.pd_offset = DataPtr->pd_offset;
388 data.pd_bitoffset = DataPtr->pd_bitoffset;
390 ret = edit_pkt_common_key_pressed_cb(event, &data);
393 DataPtr->pd_offset = data.pd_offset;
394 DataPtr->pd_bitoffset = data.pd_bitoffset;
396 /* XXX, assuming finfo->appendix_start >= finfo->start, and if appendix exists, main exists also.
397 * easy to fix if needed */
398 have_appendix = (finfo->appendix_start >= 0 && finfo->appendix_length > 0);
400 if ((DataPtr->pd_offset >= DataPtr->start_offset + finfo->start && DataPtr->pd_offset < DataPtr->start_offset + finfo->start + finfo->length) ||
401 (have_appendix && DataPtr->pd_offset >= DataPtr->start_offset + finfo->appendix_start && DataPtr->pd_offset < DataPtr->start_offset + finfo->appendix_start + finfo->appendix_length))
402 { /* pd_offset ok */ }
404 if (have_appendix && DataPtr->pd_offset >= DataPtr->start_offset + finfo->appendix_start + finfo->appendix_length) {
405 DataPtr->pd_offset = DataPtr->start_offset + finfo->start;
406 DataPtr->pd_bitoffset = 0; /* first bit */
408 } else if (DataPtr->pd_offset >= DataPtr->start_offset + finfo->start + finfo->length) {
410 DataPtr->pd_offset = DataPtr->start_offset + finfo->appendix_start;
412 DataPtr->pd_offset = DataPtr->start_offset + finfo->start;
413 DataPtr->pd_bitoffset = 0; /* first bit */
416 if (DataPtr->pd_offset < DataPtr->start_offset + finfo->start) {
418 DataPtr->pd_offset = DataPtr->start_offset + finfo->appendix_start + finfo->appendix_length-1;
420 DataPtr->pd_offset = DataPtr->start_offset + finfo->start + finfo->length-1;
421 /* XXX, last bit/octect? */
423 } else if (have_appendix && DataPtr->pd_offset < DataPtr->start_offset + finfo->appendix_start) {
424 DataPtr->pd_offset = DataPtr->start_offset + finfo->start + finfo->length-1;
425 /* XXX, last bit/octect? */
429 finfo_window_refresh(DataPtr);
434 finfo_ipv4_input(GtkSpinButton *spinbutton, gpointer arg1, gpointer user_data _U_)
436 const gchar *addr_str = gtk_entry_get_text(GTK_ENTRY(spinbutton));
437 gdouble *out_val = (gdouble *) arg1;
440 /* XXX, get_host_ipaddr() support hostname resolution */
441 if (!get_host_ipaddr(addr_str, &addr))
442 return GTK_INPUT_ERROR;
443 addr = GUINT32_FROM_BE(addr);
445 unsigned int a0, a1, a2, a3;
447 if (sscanf(addr_str, "%u.%u.%u.%u", &a0, &a1, &a2, &a3) != 4)
448 return GTK_INPUT_ERROR;
450 if (a0 > 255 || a1 > 255 || a2 > 255 || a3 > 255)
451 return GTK_INPUT_ERROR;
453 addr = a0 << 24 | a1 << 16 | a2 << 8 | a3;
455 *out_val = (gdouble) addr;
460 finfo_ipv4_output(GtkSpinButton *spinbutton, gpointer user_data _U_)
465 adj = gtk_spin_button_get_adjustment(spinbutton);
466 value = (guint32) gtk_adjustment_get_value(adj);
467 value = GUINT32_TO_BE(value);
468 /* ip_to_str_buf((guint8*)&value, buf, MAX_IP_STR_LEN); */ /* not exported */
469 gtk_entry_set_text(GTK_ENTRY(spinbutton), ip_to_str((guint8*)&value)); /* XXX, can we ep_alloc() inside gui? */
474 new_finfo_window(GtkWidget *w, struct FieldinfoWinData *DataPtr)
476 field_info *finfo = DataPtr->finfo;
477 const header_field_info *hfinfo = finfo->hfinfo;
478 int finfo_type = (hfinfo) ? hfinfo->type : FT_NONE;
480 GtkWidget *dialog = gtk_dialog_new_with_buttons("Editing finfo: ....",
482 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
483 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
484 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
487 GtkWidget *dialog_vbox = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
488 GtkWidget *fvalue_edit;
489 GtkWidget *native_repr;
490 GtkWidget *bv_nb_ptr;
491 GtkWidget *frame, *frame_vbox;
495 if (!FI_GET_FLAG(finfo, FI_LITTLE_ENDIAN) && !FI_GET_FLAG(finfo, FI_BIG_ENDIAN)) {
496 fvalue_edit = gtk_entry_new();
497 gtk_entry_set_text(GTK_ENTRY(fvalue_edit), "<not added by proto_tree_add_item()>");
498 gtk_editable_set_editable(GTK_EDITABLE(fvalue_edit), FALSE);
499 gtk_widget_set_sensitive(fvalue_edit, FALSE);
502 fvalue_edit = gtk_entry_new();
503 gtk_entry_set_text(GTK_ENTRY(fvalue_edit), "<ERROR: Value stored in finfo doesn't match value from tvb>");
504 gtk_editable_set_editable(GTK_EDITABLE(fvalue_edit), FALSE);
505 gtk_widget_set_sensitive(fvalue_edit, FALSE);
507 } */ else if (finfo_type == FT_INT8 || finfo_type == FT_INT16 || finfo_type == FT_INT24 || finfo_type == FT_INT32 ||
508 finfo_type == FT_UINT8 || finfo_type == FT_UINT16 || finfo_type == FT_UINT24 || finfo_type == FT_UINT32)
510 #if GTK_CHECK_VERSION(3,0,0)
517 if (finfo_type == FT_INT8 || finfo_type == FT_UINT8)
519 if (finfo_type == FT_INT16 || finfo_type == FT_UINT16)
521 if (finfo_type == FT_INT24 || finfo_type == FT_UINT24)
523 if (finfo_type == FT_INT32 || finfo_type == FT_UINT32)
525 /* if (finfo_type == FT_INT64 || finfo_type == FT_UINT64)
528 if (finfo->length * 8 < bitcount)
529 bitcount = finfo->length / 8;
531 if (hfinfo->bitmask && hfinfo->bitshift > 0)
532 bitcount -= hfinfo->bitshift;
534 /* XXX, hfinfo->bitmask: Can we configure GTK_ADJUSTMENT to do custom step? (value-changed signal?) */
536 /* XXX, I'm little worried about these casts from (unsigned) integer to double... */
538 if (finfo_type == FT_INT8 || finfo_type == FT_INT16 || finfo_type == FT_INT24 || finfo_type == FT_INT32 /* || finfo_type == FT_INT64 */)
539 adj = gtk_adjustment_new((double) fvalue_get_sinteger(&finfo->value), (double) -(G_GINT64_CONSTANT(1) << (bitcount-1)), (double) ((G_GINT64_CONSTANT(1) << (bitcount-1))-1), 1.0, 10.0, 0);
540 else if (finfo_type == FT_UINT8 || finfo_type == FT_UINT16 || finfo_type == FT_UINT24 || finfo_type == FT_UINT32 /* || finfo_type == FT_UINT64 */ )
541 adj = gtk_adjustment_new((double) fvalue_get_uinteger(&finfo->value), 0.0, (double) ((G_GINT64_CONSTANT(1U) << bitcount)-1), 1.0, 10.0, 0);
543 g_assert_not_reached();
547 fvalue_edit = gtk_spin_button_new(GTK_ADJUSTMENT(adj), 1.0, 0);
548 gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(fvalue_edit), TRUE);
549 g_signal_connect(fvalue_edit, "value-changed", G_CALLBACK(finfo_integer_changed), DataPtr);
551 } else if (finfo_type == FT_STRING || finfo_type == FT_STRINGZ) {
552 fvalue_edit = gtk_entry_new();
553 gtk_entry_set_max_length(GTK_ENTRY(fvalue_edit), finfo->length);
554 gtk_entry_set_text(GTK_ENTRY(fvalue_edit), fvalue_get(&finfo->value));
555 g_signal_connect(fvalue_edit, "changed", G_CALLBACK(finfo_string_changed), DataPtr);
557 } else if (finfo_type == FT_BOOLEAN) {
558 fvalue_edit = gtk_check_button_new();
559 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(fvalue_edit), (fvalue_get_uinteger(&finfo->value) != 0));
560 g_signal_connect(fvalue_edit, "toggled", G_CALLBACK(finfo_boolean_changed), DataPtr);
562 } else if (finfo_type == FT_IPv4) {
563 guint32 net_addr = ipv4_get_net_order_addr(fvalue_get(&finfo->value));
564 #if GTK_CHECK_VERSION(3,0,0)
569 adj = gtk_adjustment_new((double) (GUINT32_FROM_BE(net_addr)), 0.0, 4294967295.0 /* (2^32)-1 */, 1.0, 256.0, 0);
571 /* XXX, create four gtk_spin_button_new which takes 0..255 */
572 fvalue_edit = gtk_spin_button_new(GTK_ADJUSTMENT(adj), 1.0, 0);
573 gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(fvalue_edit), GTK_UPDATE_IF_VALID);
574 g_signal_connect(fvalue_edit, "value-changed", G_CALLBACK(finfo_ipv4_changed), DataPtr);
575 g_signal_connect(fvalue_edit, "input", G_CALLBACK(finfo_ipv4_input), NULL);
576 g_signal_connect(fvalue_edit, "output", G_CALLBACK(finfo_ipv4_output), NULL);
580 /* List of unsupported FT_*:
581 FT_NONE, FT_PROTOCOL,
582 FT_BYTES, FT_UINT_BYTES,
583 FT_INT64, FT_UINT64, ; should work with FT_INT[8,16,24,32] code
585 FT_IPXNET, FT_IPv6, FT_ETHER,
588 FT_ABSOLUTE_TIME, FT_RELATIVE_TIME
590 fvalue_edit = gtk_entry_new();
591 gtk_entry_set_text(GTK_ENTRY(fvalue_edit), "<not supported>");
592 gtk_editable_set_editable(GTK_EDITABLE(fvalue_edit), FALSE);
593 gtk_widget_set_sensitive(fvalue_edit, FALSE);
595 gtk_box_pack_start(GTK_BOX(dialog_vbox), fvalue_edit, FALSE, FALSE, 0);
596 gtk_widget_show(fvalue_edit);
598 DataPtr->edit = fvalue_edit;
600 native_repr = gtk_entry_new();
601 gtk_editable_set_editable(GTK_EDITABLE(native_repr), FALSE);
602 gtk_widget_set_sensitive(native_repr, FALSE);
603 gtk_box_pack_start(GTK_BOX(dialog_vbox), native_repr, FALSE, FALSE, 0);
604 gtk_widget_show(native_repr);
606 DataPtr->repr = native_repr;
608 frame = gtk_frame_new("Hex edit");
609 frame_vbox = ws_gtk_box_new(GTK_ORIENTATION_VERTICAL, 1, TRUE);
612 if (finfo->start >= 0 && finfo->length > 0) {
613 GtkWidget *byte_view;
615 bv_nb_ptr = byte_view_new();
616 gtk_box_pack_start(GTK_BOX(frame_vbox), bv_nb_ptr, TRUE, TRUE, 0);
617 gtk_widget_set_size_request(bv_nb_ptr, -1, BV_SIZE);
618 gtk_widget_show(bv_nb_ptr);
620 if ((byte_view = get_notebook_bv_ptr(bv_nb_ptr)))
621 g_signal_connect(byte_view, "key-press-event", G_CALLBACK(finfo_bv_key_pressed_cb), DataPtr);
622 DataPtr->bv = bv_nb_ptr;
625 if (finfo->appendix_start >= 0 && finfo->appendix_length > 0) {
626 GtkWidget *byte_view;
627 /* Appendix byte view */
628 bv_nb_ptr = byte_view_new();
629 gtk_box_pack_start(GTK_BOX(frame_vbox), bv_nb_ptr, TRUE, TRUE, 0);
630 gtk_widget_set_size_request(bv_nb_ptr, -1, BV_SIZE);
631 gtk_widget_show(bv_nb_ptr);
633 if ((byte_view = get_notebook_bv_ptr(bv_nb_ptr)))
634 g_signal_connect(byte_view, "key-press-event", G_CALLBACK(finfo_bv_key_pressed_cb), DataPtr);
635 DataPtr->app_bv = bv_nb_ptr;
637 gtk_container_add(GTK_CONTAINER(frame), frame_vbox);
638 gtk_widget_show(frame_vbox); gtk_widget_show(frame);
639 gtk_container_add(GTK_CONTAINER(dialog_vbox), frame);
641 gtk_window_set_default_size(GTK_WINDOW(dialog), DEF_WIDTH, -1);
642 finfo_window_refresh(DataPtr);
643 result = gtk_dialog_run(GTK_DIALOG(dialog));
644 gtk_widget_destroy(dialog);
649 edit_pkt_tree_row_activated_cb(GtkTreeView *tree_view, GtkTreePath *path, GtkTreeViewColumn *column _U_, gpointer user_data)
651 struct PacketWinData *DataPtr = (struct PacketWinData*)user_data;
656 model = gtk_tree_view_get_model(tree_view);
657 if (!gtk_tree_model_get_iter(model, &iter, path))
660 gtk_tree_model_get(model, &iter, 1, &finfo, -1);
664 if (!FI_GET_FLAG(finfo, FI_GENERATED) &&
665 finfo->ds_tvb && finfo->ds_tvb->real_data >= DataPtr->pd && finfo->ds_tvb->real_data <= DataPtr->pd + DataPtr->frame->cap_len)
667 struct FieldinfoWinData data;
669 data.frame = DataPtr->frame;
670 data.phdr = DataPtr->phdr;
671 data.pd = g_memdup(DataPtr->pd, DataPtr->frame->cap_len);
672 data.start_offset = (int) (finfo->ds_tvb->real_data - DataPtr->pd);
675 data.app_bv = data.bv = NULL;
676 data.repr = data.edit = NULL;
678 data.pd_offset = data.start_offset + finfo->start;
679 data.pd_bitoffset = 0;
681 if (new_finfo_window(DataPtr->main, &data) == GTK_RESPONSE_ACCEPT) {
682 /* DataPtr->phdr = data.phdr; */
683 memcpy(DataPtr->pd, data.pd, DataPtr->frame->cap_len);
685 proto_tree_draw(NULL, DataPtr->tree_view);
686 epan_dissect_cleanup(&(DataPtr->edt));
687 epan_dissect_init(&(DataPtr->edt), TRUE, TRUE);
688 epan_dissect_run(&(DataPtr->edt), &DataPtr->phdr, DataPtr->pd, DataPtr->frame, NULL);
689 add_byte_views(&(DataPtr->edt), DataPtr->tree_view, DataPtr->bv_nb_ptr);
690 proto_tree_draw(DataPtr->edt.tree, DataPtr->tree_view);
695 /* XXX, simple_dialog() is shown on top of main_window, instead of edit_window. */
696 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK, "Item can't be edited. FI_GENERATED or tvb not subset of packet data (uncompressed?)");
701 edit_pkt_common_key_pressed_cb(GdkEventKey *event, struct CommonWinData *DataPtr)
705 switch (recent.gui_bytes_view) {
707 if (event->keyval >= 'a' && event->keyval <= 'f')
708 val = (event->keyval - 'a') + 10;
709 else if (event->keyval >= 'A' && event->keyval <= 'F')
710 val = (event->keyval - 'A') + 10;
711 else if (event->keyval >= '0' && event->keyval <= '9')
712 val = (event->keyval - '0');
713 else if (event->keyval == GDK_Left)
714 DataPtr->pd_bitoffset -= 4;
715 else if (event->keyval == GDK_Right)
716 DataPtr->pd_bitoffset += 4;
722 * XXX Allow (DataPtr->pd_bitoffset % 4) != 0 ? */
723 if (DataPtr->pd_bitoffset < 4) {
724 DataPtr->pd[DataPtr->pd_offset] = (DataPtr->pd[DataPtr->pd_offset] & 0x0f) | (val << 4);
725 DataPtr->pd_bitoffset = 4;
727 DataPtr->pd[DataPtr->pd_offset] = (DataPtr->pd[DataPtr->pd_offset] & 0xf0) | val;
728 DataPtr->pd_bitoffset = 8;
730 /* DataPtr->pd_bitoffset += 4; */
735 if (event->keyval == '0' || event->keyval == '1')
736 val = (event->keyval != '0');
737 else if (event->keyval == GDK_Left)
738 DataPtr->pd_bitoffset -= 1;
739 else if (event->keyval == GDK_Right)
740 DataPtr->pd_bitoffset += 1;
746 DataPtr->pd[DataPtr->pd_offset] |= (1 << (7-DataPtr->pd_bitoffset));
748 DataPtr->pd[DataPtr->pd_offset] &= ~(1 << (7-DataPtr->pd_bitoffset));
749 DataPtr->pd_bitoffset += 1;
754 g_assert_not_reached();
758 while (DataPtr->pd_bitoffset >= 8) {
759 DataPtr->pd_offset += 1;
760 DataPtr->pd_bitoffset -= 8;
762 while (DataPtr->pd_bitoffset < 0) {
763 DataPtr->pd_offset -= 1;
764 DataPtr->pd_bitoffset += 8;
772 edit_pkt_win_key_pressed_cb(GtkWidget *win _U_, GdkEventKey *event, gpointer user_data)
774 struct PacketWinData *DataPtr = (struct PacketWinData *)user_data;
775 struct CommonWinData data;
778 tvbuff_t *ds_tvb = NULL;
781 data.frame = DataPtr->frame;
782 data.pd = DataPtr->pd;
783 data.pd_offset = DataPtr->pd_offset;
784 data.pd_bitoffset = DataPtr->pd_bitoffset;
786 ret = edit_pkt_common_key_pressed_cb(event, &data);
789 DataPtr->pd_offset = data.pd_offset;
790 DataPtr->pd_bitoffset = data.pd_bitoffset;
792 if (DataPtr->pd_offset < 0) {
793 DataPtr->pd_offset = DataPtr->frame->cap_len-1;
794 /* XXX, last bit/octect? */
797 if ((guint)DataPtr->pd_offset >= DataPtr->frame->cap_len) {
798 DataPtr->pd_offset = 0;
799 DataPtr->pd_bitoffset = 0; /* first bit */
805 /* redissect if changed */
806 if (data.val != -1) {
807 /* XXX, can be optimized? */
808 proto_tree_draw(NULL, DataPtr->tree_view);
809 epan_dissect_cleanup(&(DataPtr->edt));
810 epan_dissect_init(&(DataPtr->edt), TRUE, TRUE);
811 epan_dissect_run(&(DataPtr->edt), &DataPtr->phdr, DataPtr->pd, DataPtr->frame, NULL);
812 add_byte_views(&(DataPtr->edt), DataPtr->tree_view, DataPtr->bv_nb_ptr);
813 proto_tree_draw(DataPtr->edt.tree, DataPtr->tree_view);
816 for (src_le = DataPtr->edt.pi.data_src; src_le != NULL; src_le = src_le->next) {
817 const struct data_source *src = src_le->data;
818 tvbuff_t *tvb = get_data_source_tvb(src);
820 if (tvb && tvb->real_data == DataPtr->pd) {
826 if (ds_tvb != NULL) {
827 GtkWidget *byte_view;
829 set_notebook_page(DataPtr->bv_nb_ptr, ds_tvb);
830 byte_view = get_notebook_bv_ptr(DataPtr->bv_nb_ptr);
832 packet_hex_editor_print(byte_view, DataPtr->pd, DataPtr->frame, DataPtr->pd_offset, DataPtr->pd_bitoffset, DataPtr->frame->cap_len);
838 edit_pkt_destroy_new_window(GObject *object _U_, gpointer user_data)
840 /* like destroy_new_window, but without freeding DataPtr->pd */
841 struct PacketWinData *DataPtr = user_data;
843 detail_windows = g_list_remove(detail_windows, DataPtr);
844 proto_tree_draw(NULL, DataPtr->tree_view);
845 epan_dissect_cleanup(&(DataPtr->edt));
848 /* XXX, notify main packet list that packet should be redisplayed */
851 static gint g_direct_compare_func(gconstpointer a, gconstpointer b, gpointer user_data _U_) {
860 static void modifed_frame_data_free(gpointer data) {
861 modified_frame_data *mfd = (modified_frame_data *) data;
867 #endif /* WANT_PACKET_EDITOR */
869 void new_packet_window(GtkWidget *w _U_, gboolean editable _U_)
871 #define NewWinTitleLen 1000
872 char Title[NewWinTitleLen] = "";
874 GtkWidget *main_w, *main_vbox, *pane,
875 *tree_view, *tv_scrollw,
877 struct PacketWinData *DataPtr;
880 if (!cfile.current_frame) {
881 /* nothing has been captured so far */
885 /* With the new packetlists "lazy columns" it's neccesary to reread the frame */
886 if (!cf_read_frame(&cfile, cfile.current_frame)) {
887 /* error reading the frame */
891 /* Allocate data structure to represent this window. */
892 DataPtr = (struct PacketWinData *) g_malloc(sizeof(struct PacketWinData));
894 DataPtr->frame = cfile.current_frame;
895 DataPtr->phdr = cfile.phdr;
896 DataPtr->pd = (guint8 *)g_malloc(DataPtr->frame->cap_len);
897 memcpy(DataPtr->pd, cfile.pd, DataPtr->frame->cap_len);
899 epan_dissect_init(&(DataPtr->edt), TRUE, TRUE);
900 epan_dissect_run(&(DataPtr->edt), &DataPtr->phdr, DataPtr->pd,
901 DataPtr->frame, &cfile.cinfo);
902 epan_dissect_fill_in_columns(&(DataPtr->edt), FALSE, TRUE);
905 * Build title of window by getting column data constructed when the
906 * frame was dissected.
908 for (i = 0; i < cfile.cinfo.num_cols; ++i) {
909 TextPtr = cfile.cinfo.col_data[i];
910 if ((strlen(Title) + strlen(TextPtr)) < NewWinTitleLen - 1) {
911 g_strlcat(Title, TextPtr, NewWinTitleLen);
912 g_strlcat(Title, " ", NewWinTitleLen);
916 main_w = window_new(GTK_WINDOW_TOPLEVEL, Title);
917 gtk_window_set_default_size(GTK_WINDOW(main_w), DEF_WIDTH, -1);
919 /* Container for paned windows */
920 main_vbox = ws_gtk_box_new(GTK_ORIENTATION_VERTICAL, 1, FALSE);
921 gtk_container_set_border_width(GTK_CONTAINER(main_vbox), 1);
922 gtk_container_add(GTK_CONTAINER(main_w), main_vbox);
923 gtk_widget_show(main_vbox);
925 /* Panes for the tree and byte view */
926 pane = gtk_paned_new(GTK_ORIENTATION_VERTICAL);
927 gtk_box_pack_start(GTK_BOX(main_vbox), pane, TRUE, TRUE, 0);
928 gtk_widget_show(pane);
931 tv_scrollw = proto_tree_view_new(&tree_view);
932 gtk_paned_pack1(GTK_PANED(pane), tv_scrollw, TRUE, TRUE);
933 gtk_widget_set_size_request(tv_scrollw, -1, TV_SIZE);
934 gtk_widget_show(tv_scrollw);
935 gtk_widget_show(tree_view);
938 bv_nb_ptr = byte_view_new();
939 gtk_paned_pack2(GTK_PANED(pane), bv_nb_ptr, FALSE, FALSE);
940 gtk_widget_set_size_request(bv_nb_ptr, -1, BV_SIZE);
941 gtk_widget_show(bv_nb_ptr);
943 DataPtr->main = main_w;
944 DataPtr->tv_scrollw = tv_scrollw;
945 DataPtr->tree_view = tree_view;
946 DataPtr->bv_nb_ptr = bv_nb_ptr;
947 detail_windows = g_list_append(detail_windows, DataPtr);
949 /* load callback handlers */
950 g_signal_connect(gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view)),
951 "changed", G_CALLBACK(new_tree_view_selection_changed_cb), DataPtr);
952 g_signal_connect(tree_view, "button_press_event", G_CALLBACK(button_press_handler), NULL);
953 #ifdef WANT_PACKET_EDITOR
954 if (editable && DataPtr->frame->cap_len != 0) {
955 g_signal_connect(main_w, "key-press-event", G_CALLBACK(edit_pkt_win_key_pressed_cb), DataPtr);
956 /* XXX, popup-menu instead of row-activated? */
957 g_signal_connect(tree_view, "row-activated", G_CALLBACK(edit_pkt_tree_row_activated_cb), DataPtr);
958 g_signal_connect(main_w, "destroy", G_CALLBACK(edit_pkt_destroy_new_window), DataPtr);
961 g_signal_connect(main_w, "destroy", G_CALLBACK(destroy_new_window), DataPtr);
963 /* draw the protocol tree & print hex data */
964 add_byte_views(&(DataPtr->edt), tree_view, DataPtr->bv_nb_ptr);
965 proto_tree_draw(DataPtr->edt.tree, tree_view);
967 DataPtr->finfo_selected = NULL;
968 DataPtr->pd_offset = 0;
969 DataPtr->pd_bitoffset = 0;
970 gtk_widget_show(main_w);
972 #ifdef WANT_PACKET_EDITOR
973 if (editable && DataPtr->frame->cap_len != 0) {
974 /* XXX, there's no Save button here, so lets assume packet is always edited */
975 modified_frame_data *mfd = g_malloc(sizeof(modified_frame_data));
977 mfd->pd = DataPtr->pd;
978 mfd->phdr = DataPtr->phdr;
980 if (cfile.edited_frames == NULL)
981 cfile.edited_frames = g_tree_new_full(g_direct_compare_func, NULL, NULL, modifed_frame_data_free);
982 g_tree_insert(cfile.edited_frames, GINT_TO_POINTER(DataPtr->frame->num), mfd);
983 DataPtr->frame->file_off = -1;
989 destroy_new_window(GObject *object _U_, gpointer user_data)
991 struct PacketWinData *DataPtr = (struct PacketWinData *)user_data;
993 detail_windows = g_list_remove(detail_windows, DataPtr);
994 proto_tree_draw(NULL, DataPtr->tree_view);
995 epan_dissect_cleanup(&(DataPtr->edt));
1000 /* called when a tree row is (un)selected in the popup packet window */
1002 new_tree_view_selection_changed_cb(GtkTreeSelection *sel, gpointer user_data)
1005 GtkWidget *byte_view;
1008 GtkTreeModel *model;
1011 struct PacketWinData *DataPtr = (struct PacketWinData*)user_data;
1013 /* if something is selected */
1014 if (gtk_tree_selection_get_selected(sel, &model, &iter))
1016 gtk_tree_model_get(model, &iter, 1, &finfo, -1);
1019 set_notebook_page(DataPtr->bv_nb_ptr, finfo->ds_tvb);
1020 byte_view = get_notebook_bv_ptr(DataPtr->bv_nb_ptr);
1021 if (!byte_view) /* exit if no hex window to write in */
1024 data = get_byte_view_data_and_length(byte_view, &len);
1027 len = DataPtr->frame->cap_len;
1030 DataPtr->finfo_selected = finfo;
1032 #ifdef WANT_PACKET_EDITOR
1033 DataPtr->pd_offset = 0;
1034 DataPtr->pd_bitoffset = 0;
1036 if (!FI_GET_FLAG(finfo, FI_GENERATED) &&
1037 finfo->ds_tvb && finfo->ds_tvb->real_data >= DataPtr->pd && finfo->ds_tvb->real_data <= DataPtr->pd + DataPtr->frame->cap_len)
1039 /* I haven't really test if TVB subsets works, but why not? :> */
1040 int pd_offset = (int) (finfo->ds_tvb->real_data - DataPtr->pd);
1042 /* some code from packet_hex_print */
1043 int finfo_offset = finfo->start;
1044 int finfo_len = finfo->length;
1046 if (!(finfo_offset >= 0 && finfo_len > 0)) {
1047 finfo_offset = finfo->appendix_start;
1048 finfo_len = finfo->appendix_length;
1051 /* Don't care about things like bitmask or LE/BE, just point DataPtr->tvb_[bit]offset to proper offsets. */
1052 if (finfo_offset >= 0 && finfo_len > 0) {
1053 DataPtr->pd_offset = pd_offset + finfo_offset;
1054 DataPtr->pd_bitoffset = 0; /* XXX */
1057 if (DataPtr->pd_offset < 0)
1058 DataPtr->pd_offset = 0;
1059 if ((guint)DataPtr->pd_offset >= DataPtr->frame->cap_len)
1060 DataPtr->pd_offset = 0;
1064 packet_hex_print(byte_view, data, DataPtr->frame, finfo, len);
1068 DataPtr->finfo_selected = NULL;
1070 byte_view = get_notebook_bv_ptr(DataPtr->bv_nb_ptr);
1071 if (!byte_view) /* exit if no hex window to write in */
1074 data = get_byte_view_data_and_length(byte_view, &len);
1075 g_assert(data != NULL);
1076 packet_hex_reprint(byte_view);
1080 /* Functions called from elsewhere to act on all popup packet windows. */
1082 /* Destroy all popup packet windows. */
1084 destroy_packet_wins(void)
1086 struct PacketWinData *DataPtr;
1088 /* Destroying a packet window causes it to be removed from
1089 the list of packet windows, so we can't do a "g_list_foreach()"
1090 to go through the list of all packet windows and destroy them
1091 as we find them; instead, as long as the list is non-empty,
1092 we destroy the first window on the list. */
1093 while (detail_windows != NULL) {
1094 DataPtr = (struct PacketWinData *)(detail_windows->data);
1095 window_destroy(DataPtr->main);
1100 redraw_packet_bytes_cb(gpointer data, gpointer user_data _U_)
1102 struct PacketWinData *DataPtr = (struct PacketWinData *)data;
1104 redraw_packet_bytes(DataPtr->bv_nb_ptr, DataPtr->frame, DataPtr->finfo_selected);
1107 /* Redraw the packet bytes part of all the popup packet windows. */
1109 redraw_packet_bytes_packet_wins(void)
1111 g_list_foreach(detail_windows, redraw_packet_bytes_cb, NULL);