*
* $Id$
*
- * Ethereal - Network traffic analyzer
- * By Gerald Combs <gerald@ethereal.com>
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
* Copyright 2000 Gerald Combs
*
* This program is free software; you can redistribute it and/or
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifdef HAVE_CONFIG_H
#include <stdio.h>
#include <string.h>
-#ifdef HAVE_IO_H
-#include <io.h> /* open/close on win32 */
-#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#include "isprint.h"
+#include "file_util.h"
#include "color.h"
#include "colors.h"
#include "file.h"
#include "follow_dlg.h"
#include <epan/follow.h>
#include "dlg_utils.h"
+#include "file_dlg.h"
#include "keys.h"
#include "globals.h"
#include "main.h"
#include <epan/prefs.h>
#include <epan/addr_resolv.h>
#include <epan/charsets.h>
-#include "util.h"
-#include "ui_util.h"
+#include "tempfile.h"
+#include "gui_utils.h"
#include <epan/epan_dissect.h>
#include <epan/filesystem.h>
#include "compat_macros.h"
#include <epan/ipproto.h>
-#include "stat_menu.h"
#include "print_mswin.h"
#include "font_utils.h"
+#include "help_dlg.h"
+
+/* This is backwards-compatibility code for old versions of GTK+ (2.2.1 and
+ * earlier). It defines the new wrap behavior (unknown in earlier versions)
+ * as the old (slightly buggy) wrap behavior.
+ */
+#ifndef GTK_WRAP_WORD_CHAR
+#define GTK_WRAP_WORD_CHAR GTK_WRAP_WORD
+#endif
/* Show Stream */
typedef enum {
GtkWidget *carray_bt;
GtkWidget *raw_bt;
GtkWidget *follow_save_as_w;
+#if GTK_MAJOR_VERSION >= 2
+ GtkWidget *find_dlg_w;
+#endif
gboolean is_ipv6;
char *filter_out_filter;
GtkWidget *filter_te;
static void follow_charset_toggle_cb(GtkWidget * w, gpointer parent_w);
static void follow_load_text(follow_info_t *follow_info);
static void follow_filter_out_stream(GtkWidget * w, gpointer parent_w);
+#if GTK_MAJOR_VERSION >= 2
+static void follow_find_cb(GtkWidget * w, gpointer data);
+static void follow_find_button_cb(GtkWidget * w _U_, gpointer parent_w);
+static void follow_find_destroy_cb(GtkWidget * win _U_, gpointer data);
+#endif
static void follow_print_stream(GtkWidget * w, gpointer parent_w);
static void follow_save_as_cmd_cb(GtkWidget * w, gpointer data);
static void follow_save_as_ok_cb(GtkWidget * w, gpointer fs);
static void follow_stream_om_server(GtkWidget * w, gpointer data);
-/* With MSVC and a libethereal.dll, we need a special declaration. */
-ETH_VAR_IMPORT FILE *data_out_file;
+/* With MSVC and a libwireshark.dll, we need a special declaration. */
+WS_VAR_IMPORT FILE *data_out_file;
#define E_FOLLOW_INFO_KEY "follow_info_key"
follow_stream_cb(GtkWidget * w, gpointer data _U_)
{
GtkWidget *streamwindow, *vbox, *txt_scrollw, *text, *filter_te;
- GtkWidget *hbox, *button_hbox, *button, *radio_bt;
- GtkWidget *stream_fr, *stream_vb;
+ GtkWidget *hbox, *bbox, *button, *radio_bt;
+ GtkWidget *stream_fr, *stream_vb;
GtkWidget *stream_om, *stream_menu, *stream_mi;
- GtkTooltips *tooltips;
- int tmp_fd;
+ GtkTooltips *tooltips;
+ int tmp_fd;
gchar *follow_filter;
const gchar *previous_filter;
- int filter_out_filter_len;
+ int filter_out_filter_len;
const char *hostname0, *hostname1;
char *port0, *port1;
char string[128];
follow_tcp_stats_t stats;
follow_info_t *follow_info;
+ tcp_stream_chunk sc;
/* we got tcp so we can follow */
- if (cfile.edt->pi.ipproto != 6) {
+ if (cfile.edt->pi.ipproto != IP_PROTO_TCP) {
simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
"Error following stream. Please make\n"
"sure you have a TCP packet selected.");
return;
}
- data_out_file = fdopen(tmp_fd, "wb");
+ data_out_file = fdopen(tmp_fd, "w+b");
if (data_out_file == NULL) {
simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
"Could not create temporary file %s: %s",
follow_info->data_out_filename, strerror(errno));
- close(tmp_fd);
+ eth_close(tmp_fd);
unlink(follow_info->data_out_filename);
g_free(follow_info);
return;
/* Free the filter string, as we're done with it. */
g_free(follow_filter);
- /* The data_out_file should now be full of the streams information */
- fclose(data_out_file);
-
/* The data_out_filename file now has all the text that was in the session */
- streamwindow = dlg_window_new("Follow TCP stream");
+ streamwindow = dlg_window_new("Follow TCP Stream");
/* needed in follow_filter_out_stream(), is there a better way? */
follow_info->streamwindow = streamwindow;
vbox = gtk_vbox_new(FALSE, 6);
gtk_container_add(GTK_CONTAINER(streamwindow), vbox);
- /* content frame */
+ /* content frame */
if (incomplete_tcp_stream) {
stream_fr = gtk_frame_new("Stream Content (incomplete)");
} else {
#else
text = gtk_text_view_new();
gtk_text_view_set_editable(GTK_TEXT_VIEW(text), FALSE);
+ gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(text), GTK_WRAP_WORD_CHAR);
#endif
gtk_container_add(GTK_CONTAINER(txt_scrollw), text);
follow_info->text = text;
hbox = gtk_hbox_new(FALSE, 1);
gtk_box_pack_start(GTK_BOX(stream_vb), hbox, FALSE, FALSE, 0);
+#if GTK_MAJOR_VERSION >= 2
+ /* Create Find Button */
+ button = BUTTON_NEW_FROM_STOCK(GTK_STOCK_FIND);
+ SIGNAL_CONNECT(button, "clicked", follow_find_cb, follow_info);
+ gtk_tooltips_set_tip (tooltips, button, "Find text in the displayed content", NULL);
+ gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
+#endif
+
/* Create Save As Button */
button = BUTTON_NEW_FROM_STOCK(GTK_STOCK_SAVE_AS);
SIGNAL_CONNECT(button, "clicked", follow_save_as_cmd_cb, follow_info);
struct e_in6_addr ipaddr;
memcpy(&ipaddr, stats.ip_address[0], 16);
hostname0 = get_hostname6(&ipaddr);
- memcpy(&ipaddr, stats.ip_address[0], 16);
+ memcpy(&ipaddr, stats.ip_address[1], 16);
hostname1 = get_hostname6(&ipaddr);
} else {
guint32 ipaddr;
gtk_widget_show(stream_mi);
follow_info->show_stream = BOTH_HOSTS;
+ /* Go back to the top of the file and read the first tcp_stream_chunk
+ * to ensure that the IP addresses and port numbers in the drop-down
+ * list are tied to the correct lines displayed by follow_read_stream()
+ * later on (which also reads from this file). Close the file when
+ * we're done.
+ */
+
+ rewind(data_out_file);
+ fread(&sc, 1, sizeof(sc), data_out_file);
+ fclose(data_out_file);
+
/* Host 0 --> Host 1 */
- g_snprintf(string, sizeof(string), "%s:%s --> %s:%s (%u bytes)",
- hostname0, port0, hostname1, port1,
- stats.bytes_written[0]);
+ if(sc.src_port == strtol(port0, NULL, 10)) {
+ g_snprintf(string, sizeof(string), "%s:%s --> %s:%s (%u bytes)",
+ hostname0, port0, hostname1, port1,
+ stats.bytes_written[0]);
+ } else {
+ g_snprintf(string, sizeof(string), "%s:%s --> %s:%s (%u bytes)",
+ hostname1, port1, hostname0, port0,
+ stats.bytes_written[0]);
+ }
+
stream_mi = gtk_menu_item_new_with_label(string);
SIGNAL_CONNECT(stream_mi, "activate", follow_stream_om_client,
follow_info);
gtk_widget_show(stream_mi);
/* Host 1 --> Host 0 */
- g_snprintf(string, sizeof(string), "%s:%s --> %s:%s (%u bytes)",
- hostname1, port1, hostname0, port0,
- stats.bytes_written[1]);
+ if(sc.src_port == strtol(port0, NULL, 10)) {
+ g_snprintf(string, sizeof(string), "%s:%s --> %s:%s (%u bytes)",
+ hostname1, port1, hostname0, port0,
+ stats.bytes_written[1]);
+ } else {
+ g_snprintf(string, sizeof(string), "%s:%s --> %s:%s (%u bytes)",
+ hostname0, port0, hostname1, port1,
+ stats.bytes_written[1]);
+ }
+
stream_mi = gtk_menu_item_new_with_label(string);
SIGNAL_CONNECT(stream_mi, "activate", follow_stream_om_server,
follow_info);
follow_info);
follow_info->raw_bt = radio_bt;
- /* button hbox */
- button_hbox = gtk_hbutton_box_new();
- gtk_box_pack_start(GTK_BOX(vbox), button_hbox, FALSE, FALSE, 0);
- gtk_button_box_set_layout (GTK_BUTTON_BOX(button_hbox), GTK_BUTTONBOX_END);
- gtk_button_box_set_spacing(GTK_BUTTON_BOX(button_hbox), 5);
+ /* Button row: (help), filter out, close button */
+ if(topic_available(HELP_FILESET_DIALOG)) {
+ bbox = dlg_button_row_new(WIRESHARK_STOCK_FILTER_OUT_STREAM, GTK_STOCK_CLOSE, GTK_STOCK_HELP, NULL);
+ } else {
+ bbox = dlg_button_row_new(WIRESHARK_STOCK_FILTER_OUT_STREAM, GTK_STOCK_CLOSE, NULL);
+ }
+ gtk_box_pack_start(GTK_BOX(vbox), bbox, FALSE, FALSE, 5);
- /* Create exclude stream button */
- button = gtk_button_new_with_label("Filter out this stream");
- SIGNAL_CONNECT(button, "clicked", follow_filter_out_stream, follow_info);
+
+ button = OBJECT_GET_DATA(bbox, WIRESHARK_STOCK_FILTER_OUT_STREAM);
gtk_tooltips_set_tip (tooltips, button,
"Build a display filter which cuts this stream from the capture", NULL);
- gtk_box_pack_start(GTK_BOX(button_hbox), button, FALSE, FALSE, 0);
+ SIGNAL_CONNECT(button, "clicked", follow_filter_out_stream, follow_info);
- /* Create Close Button */
- button = BUTTON_NEW_FROM_STOCK(GTK_STOCK_CLOSE);
+ button = OBJECT_GET_DATA(bbox, GTK_STOCK_CLOSE);
+ window_set_cancel_button(streamwindow, button, window_cancel_button_cb);
gtk_tooltips_set_tip (tooltips, button,
"Close the dialog and keep the current display filter", NULL);
- gtk_box_pack_start(GTK_BOX(button_hbox), button, FALSE, FALSE, 0);
- GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
+ gtk_widget_grab_default(button);
- window_set_cancel_button(streamwindow, button, window_cancel_button_cb);
+ if(topic_available(HELP_FILESET_DIALOG)) {
+ button = OBJECT_GET_DATA(bbox, GTK_STOCK_HELP);
+ SIGNAL_CONNECT(button, "clicked", topic_cb, HELP_FOLLOW_TCP_STREAM_DIALOG);
+ }
/* Tuck away the follow_info object into the window */
OBJECT_SET_DATA(streamwindow, E_FOLLOW_INFO_KEY, follow_info);
gchar initbuf[256];
guint32 server_packet_count = 0;
guint32 client_packet_count = 0;
- char buffer[FLT_BUF_SIZE];
+ char buffer[FLT_BUF_SIZE+1]; /* +1 to fix ws bug 1043 */
size_t nchars;
static const gchar hexchars[16] = "0123456789abcdef";
iplen = (follow_info->is_ipv6) ? 16 : 4;
- data_out_file = fopen(follow_info->data_out_filename, "rb");
+ data_out_file = eth_fopen(follow_info->data_out_filename, "rb");
if (data_out_file == NULL) {
simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
"Could not open temporary file %s: %s", follow_info->data_out_filename,
return;
}
+#if GTK_MAJOR_VERSION >= 2
+static void
+follow_find_cb(GtkWidget * w _U_, gpointer data)
+{
+ follow_info_t *follow_info = data;
+ GtkTooltips *tooltips;
+ GtkWidget *find_dlg_w, *main_vb, *buttons_row, *find_lb;
+ GtkWidget *find_hb, *find_text_box, *find_bt, *cancel_bt;
+
+ tooltips = gtk_tooltips_new();
+
+ if (follow_info->find_dlg_w != NULL) {
+ /* There's already a dialog box; reactivate it. */
+ reactivate_window(follow_info->find_dlg_w);
+ return;
+ }
+
+ /* Create the find box */
+ find_dlg_w = dlg_window_new("Wireshark: Find text");
+ gtk_window_set_transient_for(GTK_WINDOW(find_dlg_w),
+ GTK_WINDOW(follow_info->streamwindow));
+ gtk_window_set_destroy_with_parent(GTK_WINDOW(find_dlg_w), TRUE);
+ follow_info->find_dlg_w = find_dlg_w;
+
+ SIGNAL_CONNECT(find_dlg_w, "destroy", follow_find_destroy_cb, follow_info);
+ SIGNAL_CONNECT(find_dlg_w, "delete_event", window_delete_event_cb, NULL);
+
+ /* Main vertical box */
+ main_vb = gtk_vbox_new(FALSE, 3);
+ gtk_container_border_width(GTK_CONTAINER(main_vb), 5);
+ gtk_container_add(GTK_CONTAINER(find_dlg_w), main_vb);
+
+ /* Horizontal box for find label, entry field and up/down radio buttons*/
+ find_hb = gtk_hbox_new(FALSE, 3);
+ gtk_container_add(GTK_CONTAINER(main_vb), find_hb);
+ gtk_widget_show(find_hb);
+
+ /* Find label */
+ find_lb = gtk_label_new("Find text:");
+ gtk_box_pack_start(GTK_BOX(find_hb), find_lb, FALSE, FALSE, 0);
+ gtk_widget_show(find_lb);
+
+ /* Find field */
+ find_text_box = gtk_entry_new();
+ gtk_box_pack_start(GTK_BOX(find_hb), find_text_box, FALSE, FALSE, 0);
+ gtk_tooltips_set_tip(tooltips, find_text_box, "Text to search for (case sensitive)", NULL);
+ gtk_widget_show(find_text_box);
+
+ /* Buttons row */
+ buttons_row = dlg_button_row_new(GTK_STOCK_FIND, GTK_STOCK_CANCEL, NULL);
+ gtk_container_add(GTK_CONTAINER(main_vb), buttons_row);
+ find_bt = OBJECT_GET_DATA(buttons_row, GTK_STOCK_FIND);
+ cancel_bt = OBJECT_GET_DATA(buttons_row, GTK_STOCK_CANCEL);
+
+ SIGNAL_CONNECT(find_bt, "clicked", follow_find_button_cb, follow_info);
+ OBJECT_SET_DATA(find_bt, "find_string", find_text_box);
+ window_set_cancel_button(find_dlg_w, cancel_bt, window_cancel_button_cb);
+
+ /* Hitting return in the find field "clicks" the find button */
+ dlg_set_activate(find_text_box, find_bt);
+
+ /* Show the dialog */
+ gtk_widget_show_all(find_dlg_w);
+ window_present(find_dlg_w);
+}
+
+static void
+follow_find_button_cb(GtkWidget * w, gpointer data)
+{
+ gboolean found;
+ const gchar *find_string;
+ follow_info_t *follow_info = data;
+ GtkTextBuffer *buffer;
+ GtkTextIter iter, match_start, match_end;
+ GtkTextMark *last_pos_mark;
+ GtkWidget *find_string_w;
+
+ /* Get the text the user typed into the find field */
+ find_string_w = (GtkWidget *)OBJECT_GET_DATA(w, "find_string");
+ find_string = gtk_entry_get_text(GTK_ENTRY(find_string_w));
+
+ /* Get the buffer associated with the follow stream */
+ buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(follow_info->text));
+ gtk_text_buffer_get_start_iter(buffer, &iter);
+
+ /* Look for the search string in the buffer */
+ last_pos_mark = gtk_text_buffer_get_mark(buffer, "last_position");
+ if(last_pos_mark)
+ gtk_text_buffer_get_iter_at_mark(buffer, &iter, last_pos_mark);
+
+ found = gtk_text_iter_forward_search(&iter, find_string, 0, &match_start,
+ &match_end,
+ NULL);
+
+ if(found) {
+ gtk_text_buffer_select_range(buffer, &match_start, &match_end);
+ last_pos_mark = gtk_text_buffer_create_mark (buffer, "last_position",
+ &match_end, FALSE);
+ gtk_text_view_scroll_mark_onscreen(GTK_TEXT_VIEW(follow_info->text), last_pos_mark);
+ } else {
+ /* We didn't find a match */
+ simple_dialog(ESD_TYPE_INFO, ESD_BTN_OK,
+ "%sFind text has reached the end of the followed "
+ "stream%s\n\nThe next search will start from the "
+ "beginning", simple_dialog_primary_start(),
+ simple_dialog_primary_end());
+ if(last_pos_mark)
+ gtk_text_buffer_delete_mark(buffer, last_pos_mark);
+ }
+
+}
+
+static void
+follow_find_destroy_cb(GtkWidget * win _U_, gpointer data)
+{
+ follow_info_t *follow_info = data;
+
+ /* Note that we no longer have a dialog box. */
+ follow_info->find_dlg_w = NULL;
+}
+#endif /* GTK_MAJOR_VERSION >= 2 */
+
static void
follow_print_stream(GtkWidget * w _U_, gpointer data)
{
print_mswin(print_dest);
/* trash temp file */
- remove(print_dest);
+ eth_remove(print_dest);
}
#endif
return;
#ifdef _WIN32
if (win_printer) {
/* trash temp file */
- remove(print_dest);
+ eth_remove(print_dest);
}
#endif
}
#endif
#if GTK_MAJOR_VERSION >= 2 || GTK_MINOR_VERSION >= 3
+ gboolean line_break = FALSE;
/* While our isprint() hack is in place, we
* have to use convert some chars to '.' in order
* to be able to see the data we *should* see
for (i = 0; i < nchars; i++) {
if (buffer[i] == '\n' || buffer[i] == '\r')
+ {
+ line_break = TRUE;
continue;
+ }
if (! isprint(buffer[i])) {
buffer[i] = '.';
}
}
+
+ /* XXX - workaround for bug 852
+ * Force a line break so that the text view
+ * doesn't blow up on excessive long lines.
+ */
+ if (line_break == FALSE)
+ buffer[i] = '\n';
#endif
#if GTK_MAJOR_VERSION < 2
return;
}
- new_win = file_selection_new("Ethereal: Save TCP Follow Stream As",
+ new_win = file_selection_new("Wireshark: Save TCP Follow Stream As",
FILE_SELECTION_SAVE);
follow_info->follow_save_as_w = new_win;
follow_info = OBJECT_GET_DATA(fs, E_FOLLOW_INFO_KEY);
if (follow_info->show_type == SHOW_RAW) {
/* Write the data out as raw binary data */
- fh = fopen(to_name, "wb");
+ fh = eth_fopen(to_name, "wb");
} else {
/* Write it out as text */
- fh = fopen(to_name, "w");
+ fh = eth_fopen(to_name, "w");
}
if (fh == NULL) {
open_failure_alert_box(to_name, errno, TRUE);