wireshark/gtk/export_object.c
Stephen Fisher eeea95ccbe HTTP Export Object updates:
- Split the HTTP tap into two taps: one for the HTTP statistics
   and the other for the export object function.  This allows the
   HTTP statistics to work again (they seem to have been
   partially broken since SVN rev 18901).
 - Pass the conversation data (conv_data) between functions now
   instead of using the global variable stat_info (now only used
   for the HTTP stats)
 - Pass only pointers from the HTTP dissector to the Export Object
   tap, where we'll then copy the values and insert into the slist.
 - Make sure we free all memory allocated by this feature when
   we're done with it.
 - Various other minor improvements


svn path=/trunk/; revision=21021
2007-03-13 20:42:04 +00:00

418 lines
12 KiB
C

/* export_object.c
* Common routines for tracking & saving objects found in streams of data
* Copyright 2007, Stephen Fisher <stephentfisher@yahoo.com>
*
* $Id$
*
* Wireshark - Network traffic analyzer
* By Gerald Combs <gerald@wireshark.org>
* Copyright 1998 Gerald Combs
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <glib.h>
#include <gtk/gtk.h>
/* This feature has not been ported to GTK1 */
#if GTK_MAJOR_VERSION >= 2
#include <alert_box.h>
#include <simple_dialog.h>
#include <epan/packet_info.h>
#include <epan/prefs.h>
#include <epan/tap.h>
#include <gtk/compat_macros.h>
#include <gtk/dlg_utils.h>
#include <gtk/file_dlg.h>
#include <gtk/gui_utils.h>
#include <gtk/help_dlg.h>
#include <gtk/main.h>
#include <wiretap/file_util.h>
#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include "export_object.h"
enum {
EO_PKT_NUM_COLUMN,
EO_HOSTNAME_COLUMN,
EO_CONTENT_TYPE_COLUMN,
EO_BYTES_COLUMN,
EO_FILENAME_COLUMN,
EO_NUM_COLUMNS /* must be last */
};
static void
eo_remember_this_row(GtkTreeModel *model _U_, GtkTreePath *path,
GtkTreeIter *iter _U_, gpointer arg)
{
export_object_list_t *object_list = arg;
export_object_entry_t *entry;
gint *path_index;
if((path_index = gtk_tree_path_get_indices(path)) == NULL)
/* Row not found in tree - shouldn't happen */
return;
object_list->row_selected = path_index[0];
/* Select the corresponding packet in the packet list */
entry = g_slist_nth_data(object_list->entries,
object_list->row_selected);
cf_goto_frame(&cfile, entry->pkt_num);
}
static void
eo_remember_row_num(GtkTreeSelection *sel, gpointer data)
{
gtk_tree_selection_selected_foreach(sel, eo_remember_this_row, data);
}
/* Called when the Export Object window is closed in any way */
static void
eo_win_destroy_cb(GtkWindow *win _U_, gpointer data)
{
export_object_list_t *object_list = data;
export_object_entry_t *entry;
GSList *slist = object_list->entries;
protect_thread_critical_region();
remove_tap_listener(object_list);
unprotect_thread_critical_region();
while(slist) {
entry = slist->data;
g_free(entry->hostname);
g_free(entry->content_type);
g_free(entry->filename);
g_free(entry->payload_data);
slist = slist->next;
g_free(entry);
}
g_slist_free(object_list->entries);
g_free(object_list);
}
static void
eo_save_entry(gchar *save_as_filename, export_object_entry_t *entry)
{
int to_fd;
to_fd = eth_open(save_as_filename, O_WRONLY | O_CREAT | O_EXCL |
O_BINARY, 0644);
if(to_fd == -1) { /* An error occurred */
open_failure_alert_box(save_as_filename, errno, TRUE);
g_free(save_as_filename);
return;
}
if(eth_write(to_fd, entry->payload_data, entry->payload_len) < 0) {
write_failure_alert_box(save_as_filename, errno);
eth_close(to_fd);
g_free(save_as_filename);
return;
}
if (eth_close(to_fd) < 0) {
write_failure_alert_box(save_as_filename, errno);
g_free(save_as_filename);
return;
}
g_free(save_as_filename);
}
static void
eo_save_clicked_cb(GtkWidget *widget _U_, gpointer arg)
{
GtkWidget *save_as_w;
export_object_list_t *object_list = arg;
export_object_entry_t *entry = NULL;
entry = g_slist_nth_data(object_list->entries,
object_list->row_selected);
if(!entry) {
simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK, "No object was selected for saving. Please click on an object and click save again.");
return;
}
save_as_w = file_selection_new("Wireshark: Save Object As ...",
FILE_SELECTION_SAVE);
gtk_window_set_transient_for(GTK_WINDOW(save_as_w),
GTK_WINDOW(object_list->dlg));
gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(save_as_w),
entry->filename);
if(gtk_dialog_run(GTK_DIALOG(save_as_w)) == GTK_RESPONSE_ACCEPT)
eo_save_entry(gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(save_as_w)), entry);
window_destroy(save_as_w);
}
static void
eo_save_all_clicked_cb(GtkWidget *widget _U_, gpointer arg)
{
gchar *save_as_fullpath;
export_object_list_t *object_list = arg;
export_object_entry_t *entry;
GtkWidget *save_in_w;
GSList *slist = object_list->entries;
save_in_w = file_selection_new("Wireshark: Save All Objects In ...",
FILE_SELECTION_CREATE_FOLDER);
gtk_window_set_transient_for(GTK_WINDOW(save_in_w),
GTK_WINDOW(object_list->dlg));
if(gtk_dialog_run(GTK_DIALOG(save_in_w)) == GTK_RESPONSE_ACCEPT) {
while(slist) {
entry = slist->data;
save_as_fullpath = g_build_filename(gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(save_in_w)), entry->filename, NULL);
eo_save_entry(save_as_fullpath, entry);
slist = slist->next;
}
}
window_destroy(save_in_w);
}
/* Runs at the beginning of tapping only */
static void
eo_reset(void *tapdata)
{
export_object_list_t *object_list = tapdata;
object_list->entries = NULL;
object_list->iter = NULL;
object_list->row_selected = -1;
}
static void
eo_draw(void *tapdata)
{
export_object_list_t *object_list = tapdata;
export_object_entry_t *eo_entry;
GSList *slist = object_list->entries;
GtkTreeIter new_iter;
while(slist) {
eo_entry = slist->data;
gtk_tree_store_append(object_list->store, &new_iter,
object_list->iter);
gtk_tree_store_set(object_list->store, &new_iter,
EO_PKT_NUM_COLUMN, eo_entry->pkt_num,
EO_HOSTNAME_COLUMN, eo_entry->hostname,
EO_CONTENT_TYPE_COLUMN, eo_entry->content_type,
EO_BYTES_COLUMN, eo_entry->payload_len,
EO_FILENAME_COLUMN, eo_entry->filename,
-1);
slist = slist->next;
}
}
void
export_object_window(gchar *tapname, gchar *name, tap_packet_cb tap_packet)
{
GtkWidget *sw;
GtkCellRenderer *renderer;
GtkTreeViewColumn *column;
GtkTreeSelection *selection;
GtkWidget *vbox, *bbox, *help_bt, *close_bt, *save_bt, *save_all_bt;
GtkTooltips *button_bar_tips;
GString *error_msg;
export_object_list_t *object_list;
gchar *window_title;
/* Initialize our object list structure */
object_list = g_malloc0(sizeof(export_object_list_t));
/* Data will be gathered via a tap callback */
error_msg = register_tap_listener(tapname, object_list, NULL,
eo_reset,
tap_packet,
eo_draw);
if (error_msg) {
simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
"Can't register http tap: %s\n", error_msg->str);
g_string_free(error_msg, TRUE);
return;
}
/* Setup our GUI window */
button_bar_tips = gtk_tooltips_new();
window_title = g_strdup_printf("Wireshark: %s object list", name);
object_list->dlg = dlg_window_new(window_title);
g_free(window_title);
gtk_window_set_default_size(GTK_WINDOW(object_list->dlg),
DEF_WIDTH, DEF_HEIGHT);
vbox = gtk_vbox_new(FALSE, 5);
gtk_container_border_width(GTK_CONTAINER(vbox), 5);
gtk_container_add(GTK_CONTAINER(object_list->dlg), vbox);
sw = scrolled_window_new(NULL, NULL);
gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw),
GTK_SHADOW_IN);
gtk_container_add(GTK_CONTAINER(vbox), sw);
object_list->store = gtk_tree_store_new(EO_NUM_COLUMNS,
G_TYPE_INT, G_TYPE_STRING,
G_TYPE_STRING, G_TYPE_INT,
G_TYPE_STRING);
object_list->tree = tree_view_new(GTK_TREE_MODEL(object_list->store));
object_list->tree_view = GTK_TREE_VIEW(object_list->tree);
renderer = gtk_cell_renderer_text_new();
column = gtk_tree_view_column_new_with_attributes("Packet num",
renderer,
"text",
EO_PKT_NUM_COLUMN,
NULL);
gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
gtk_tree_view_append_column(object_list->tree_view, column);
renderer = gtk_cell_renderer_text_new();
column = gtk_tree_view_column_new_with_attributes("Hostname",
renderer,
"text",
EO_HOSTNAME_COLUMN,
NULL);
gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
gtk_tree_view_append_column(object_list->tree_view, column);
renderer = gtk_cell_renderer_text_new();
column = gtk_tree_view_column_new_with_attributes("Content Type",
renderer,
"text",
EO_CONTENT_TYPE_COLUMN,
NULL);
gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
gtk_tree_view_append_column(object_list->tree_view, column);
renderer = gtk_cell_renderer_text_new();
column = gtk_tree_view_column_new_with_attributes("Bytes",
renderer,
"text",
EO_BYTES_COLUMN,
NULL);
gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
gtk_tree_view_append_column(object_list->tree_view, column);
renderer = gtk_cell_renderer_text_new();
column = gtk_tree_view_column_new_with_attributes("Filename",
renderer,
"text",
EO_FILENAME_COLUMN,
NULL);
gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
gtk_tree_view_append_column(object_list->tree_view, column);
gtk_container_add(GTK_CONTAINER(sw), object_list->tree);
selection = gtk_tree_view_get_selection(object_list->tree_view);
SIGNAL_CONNECT(selection, "changed", eo_remember_row_num, object_list);
bbox = gtk_hbox_new(FALSE, 5);
/* Help button */
help_bt = BUTTON_NEW_FROM_STOCK(GTK_STOCK_HELP);
SIGNAL_CONNECT(help_bt, "clicked", topic_cb, HELP_EXPORT_OBJECT_LIST);
gtk_tooltips_set_tip(GTK_TOOLTIPS(button_bar_tips), help_bt,
"Show help for this dialog.", NULL);
gtk_box_pack_start(GTK_BOX(bbox), help_bt, FALSE, FALSE, 0);
/* Save All button */
save_all_bt = gtk_button_new_with_mnemonic("Save _All");
SIGNAL_CONNECT(save_all_bt, "clicked", eo_save_all_clicked_cb,
object_list);
gtk_tooltips_set_tip(GTK_TOOLTIPS(button_bar_tips), save_all_bt,
"Save all listed objects with their displayed "
"filenames.", NULL);
gtk_box_pack_end(GTK_BOX(bbox), save_all_bt, FALSE, FALSE, 0);
/* Save button */
save_bt = BUTTON_NEW_FROM_STOCK(GTK_STOCK_SAVE_AS);
SIGNAL_CONNECT(save_bt, "clicked", eo_save_clicked_cb, object_list);
gtk_tooltips_set_tip(GTK_TOOLTIPS(button_bar_tips), save_bt,
"Saves the currently selected content to a file.",
NULL);
gtk_box_pack_end(GTK_BOX(bbox), save_bt, FALSE, FALSE, 0);
/* Close button */
close_bt = BUTTON_NEW_FROM_STOCK(GTK_STOCK_CLOSE);
GTK_WIDGET_SET_FLAGS(close_bt, GTK_CAN_DEFAULT);
gtk_tooltips_set_tip(GTK_TOOLTIPS(button_bar_tips), close_bt,
"Close this dialog.", NULL);
gtk_box_pack_end(GTK_BOX(bbox), close_bt, FALSE, FALSE, 0);
/* Pack the buttons into the "button box" */
gtk_box_pack_end(GTK_BOX(vbox), bbox, FALSE, FALSE, 0);
gtk_widget_show(bbox);
/* Setup cancel/delete/destroy signal handlers */
SIGNAL_CONNECT(object_list->dlg, "delete_event",
window_delete_event_cb, NULL);
SIGNAL_CONNECT(object_list->dlg, "destroy",
eo_win_destroy_cb, object_list);
window_set_cancel_button(object_list->dlg, close_bt,
window_cancel_button_cb);
/* Show the window */
gtk_widget_show_all(object_list->dlg);
window_present(object_list->dlg);
cf_retap_packets(&cfile, FALSE);
}
#endif /* GTK_MAJOR_VERSION >= 2 */