Ethereal-dev: Re: [ethereal-dev] plugins support

Note: This archive is from the project's previous web site, ethereal.com. This list is no longer active.

From: Olivier Abad <abad@xxxxxxxxxxxxx>
Date: Wed, 10 Nov 1999 23:07:20 +0100
Hi,

Here is a new version of the plugins patch.
The "details" button in the plugins selection dialog is now enabled, and
allows to change the filter used to activate the plugin (the plugin must
be enabled to allow the change).

I also removed the "name" symbol in the plugins.

On lun, nov 08, 1999 at 04:02:36 -0600, Gilbert Ramirez wrote:
> 
> We'll embed guile or perl so that plugins can be written in scripting
> languages.

I'm going on vacation for 10 days. I may have time to read some
documentation about this.

Olivier


diff -Nru ethereal/Makefile.am ethereal.plug/Makefile.am
--- ethereal/Makefile.am	Wed Nov 10 22:28:38 1999
+++ ethereal.plug/Makefile.am	Wed Nov 10 22:29:10 1999
@@ -156,6 +156,8 @@
 	ipproto.c      \
 	packet.c       \
 	packet.h       \
+	plugins.c      \
+	plugins.h      \
 	prefs.c        \
 	prefs.h        \
 	print.c        \
diff -Nru ethereal/configure.in ethereal.plug/configure.in
--- ethereal/configure.in	Thu Oct 28 05:33:19 1999
+++ ethereal.plug/configure.in	Wed Nov 10 22:29:10 1999
@@ -131,6 +131,7 @@
 AC_CHECK_HEADERS(sys/stat.h sys/sockio.h sys/types.h netinet/in.h sys/socket.h net/if.h)
 AC_CHECK_HEADERS(sys/wait.h)
 AC_CHECK_HEADERS(stddef.h)
+AC_CHECK_HEADERS(dlfcn.h)
 
 dnl SNMP Check
 AC_ARG_ENABLE(snmp,
diff -Nru ethereal/file.c ethereal.plug/file.c
--- ethereal/file.c	Mon Nov  8 07:53:18 1999
+++ ethereal.plug/file.c	Wed Nov 10 22:29:10 1999
@@ -85,6 +85,10 @@
 #include "timestamp.h"
 #include "conversation.h"
 
+#ifdef HAVE_DLFCN_H
+#include "plugins.h"
+#endif
+
 #ifndef __RESOLV_H__
 #include "resolv.h"
 #endif
@@ -834,7 +838,7 @@
   gint          i, row;
   gint		crow;
   gint 		color;
-  proto_tree   *protocol_tree;
+  proto_tree   *protocol_tree = NULL;
 
   fdata->num = cf->count;
 
@@ -887,9 +891,17 @@
 	proto_tree_free(protocol_tree);
   }
   else {
-	dissect_packet(buf, fdata, NULL);
+#ifdef HAVE_DLFCN_H
+	if (plugin_list)
+	    protocol_tree = proto_tree_create_root();
+#endif
+	dissect_packet(buf, fdata, protocol_tree);
 	fdata->passed_dfilter = TRUE;
 	color = -1;
+#ifdef HAVE_DLFCN_H
+	if (protocol_tree)
+	    proto_tree_free(protocol_tree);
+#endif
   }
   if (fdata->passed_dfilter) {
     /* If we don't have the time stamp of the previous displayed packet,
diff -Nru ethereal/gtk/Makefile.am ethereal.plug/gtk/Makefile.am
--- ethereal/gtk/Makefile.am	Mon Nov  8 07:53:19 1999
+++ ethereal.plug/gtk/Makefile.am	Wed Nov 10 22:29:10 1999
@@ -53,6 +53,7 @@
 	menu.h		\
 	prefs_dlg.c	\
 	prefs_dlg.h	\
+	plugins_dlg.c	\
 	print_dlg.c	\
 	print_prefs.c   \
 	print_prefs.h	\
diff -Nru ethereal/gtk/keys.h ethereal.plug/gtk/keys.h
--- ethereal/gtk/keys.h	Thu Sep 30 00:19:24 1999
+++ ethereal.plug/gtk/keys.h	Wed Nov 10 22:29:10 1999
@@ -37,4 +37,6 @@
 #define PRINT_FILE_TE_KEY         "printer_file_entry"
 #define PRINT_DEST_RB_KEY         "printer_destination_radio_button"
 
+#define PLUGINS_DFILTER_TE        "plugins_dfilter_te"
+
 #endif
diff -Nru ethereal/gtk/main.h ethereal.plug/gtk/main.h
--- ethereal/gtk/main.h	Fri Oct  8 09:29:42 1999
+++ ethereal.plug/gtk/main.h	Wed Nov 10 22:29:10 1999
@@ -64,6 +64,9 @@
 void file_reload_cmd_cb(GtkWidget *, gpointer);
 void file_print_cmd_cb(GtkWidget *, gpointer);
 void file_print_packet_cmd_cb(GtkWidget *, gpointer);
+#ifdef HAVE_DLFCN_H
+void file_plugins_cmd_cb(GtkWidget *, gpointer);
+#endif
 void expand_all_cb(GtkWidget *, gpointer);
 void collapse_all_cb(GtkWidget *, gpointer);
 
diff -Nru ethereal/gtk/menu.c ethereal.plug/gtk/menu.c
--- ethereal/gtk/menu.c	Wed Nov 10 22:28:41 1999
+++ ethereal.plug/gtk/menu.c	Wed Nov 10 22:29:10 1999
@@ -83,6 +83,10 @@
   {"/File/Save _As...", NULL, GTK_MENU_FUNC(file_save_as_cmd_cb), 0, NULL},
   {"/File/_Reload", "<control>R", GTK_MENU_FUNC(file_reload_cmd_cb), 0, NULL},
   {"/File/<separator>", NULL, NULL, 0, "<Separator>"},
+#ifdef HAVE_DLFCN_H
+  {"/File/Plu_gins...", "<control>G", GTK_MENU_FUNC(file_plugins_cmd_cb), 0, NULL},
+  {"/File/<separator>", NULL, NULL, 0, "<Separator>"},
+#endif
   {"/File/Print...", NULL, GTK_MENU_FUNC(file_print_cmd_cb), 0, NULL},
   {"/File/Print Pac_ket", "<control>P", GTK_MENU_FUNC(file_print_packet_cmd_cb), 0, NULL},
   {"/File/<separator>", NULL, NULL, 0, "<Separator>"},
diff -Nru ethereal/gtk/plugins_dlg.c ethereal.plug/gtk/plugins_dlg.c
--- ethereal/gtk/plugins_dlg.c	Thu Jan  1 01:00:00 1970
+++ ethereal.plug/gtk/plugins_dlg.c	Wed Nov 10 22:29:10 1999
@@ -0,0 +1,461 @@
+/* plugins_dlg.c
+ * Dialog boxes for plugins
+ *
+ * Ethereal - Network traffic analyzer
+ * By Gerald Combs <gerald@xxxxxxxx>
+ * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef HAVE_DLFCN_H
+
+#include <errno.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <stdlib.h>
+#include <dlfcn.h>
+
+#ifndef __GLOBALS_H__
+#include "globals.h"
+#endif
+
+#ifndef __PLUGINS_H__
+#include "plugins.h"
+#endif
+
+#ifndef __KEYS_H__
+#include "keys.h"
+#endif
+
+#ifndef __PREFS_DLG_H__
+#include "prefs_dlg.h"
+#endif
+
+#ifndef __UTIL_H__
+#include "util.h"
+#endif
+
+static gint selected_row;
+static gchar *selected_name;
+static gchar *selected_version;
+static gchar *selected_enabled;
+static gchar std_plug_dir[] = "/usr/share/ethereal/plugins";
+static gchar local_plug_dir[] = "/usr/local/share/ethereal/plugins";
+static gchar *user_plug_dir = NULL;
+
+static void plugins_close_cb(GtkWidget *, gpointer);
+static void plugins_scan(GtkWidget *, const char *);
+static void plugins_clist_select_cb(GtkWidget *, gint, gint,
+	GdkEventButton *, gpointer);
+static void plugins_clist_unselect_cb(GtkWidget *, gint, gint,
+	GdkEventButton *, gpointer);
+static void plugins_enable_cb(GtkWidget *, gpointer);
+static void plugins_details_cb(GtkWidget *, gpointer);
+static void details_close_cb(GtkWidget *, gpointer);
+
+void
+file_plugins_cmd_cb(GtkWidget *widget, gpointer data)
+{
+    GtkWidget *plugins_window;
+    GtkWidget *main_vbox;
+    GtkWidget *main_frame;
+    GtkWidget *frame_hbox;
+    GtkWidget *scrolledwindow;
+    GtkWidget *plugins_clist;
+    GtkWidget *frame_vbnbox;
+    GtkWidget *enable_bn, *details_bn;
+    GtkWidget *main_hbnbox;
+    GtkWidget *close_bn;
+    gchar     *titles[] = {"Name", "Description", "Version", "Enabled"};
+
+    plugins_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+    gtk_window_set_title(GTK_WINDOW(plugins_window), "Ethereal: Plugins");
+
+    main_vbox = gtk_vbox_new(FALSE, 0);
+    gtk_container_add(GTK_CONTAINER(plugins_window), main_vbox);
+    gtk_widget_show(main_vbox);
+
+    main_frame = gtk_frame_new("Plugins List");
+    gtk_box_pack_start(GTK_BOX(main_vbox), main_frame, TRUE, TRUE, 0);
+    gtk_container_set_border_width(GTK_CONTAINER(main_frame), 10);
+    gtk_widget_show(main_frame);
+
+    frame_hbox = gtk_hbox_new(FALSE,0);
+    gtk_container_add(GTK_CONTAINER(main_frame), frame_hbox);
+    gtk_container_set_border_width(GTK_CONTAINER(frame_hbox), 5);
+    gtk_widget_show(frame_hbox);
+
+    scrolledwindow = gtk_scrolled_window_new(NULL, NULL);
+    gtk_box_pack_start(GTK_BOX(frame_hbox), scrolledwindow, TRUE, TRUE, 0);
+    gtk_widget_set_usize(scrolledwindow, 400, 150);
+    gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolledwindow),
+	    GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+    gtk_widget_show(scrolledwindow);
+
+    plugins_clist = gtk_clist_new_with_titles(4, titles);
+    gtk_container_add(GTK_CONTAINER(scrolledwindow), plugins_clist);
+    gtk_clist_set_selection_mode(GTK_CLIST(plugins_clist), GTK_SELECTION_SINGLE);
+    gtk_clist_column_titles_passive(GTK_CLIST(plugins_clist));
+    gtk_clist_column_titles_show(GTK_CLIST(plugins_clist));
+    gtk_clist_set_column_auto_resize(GTK_CLIST(plugins_clist), 0, TRUE);
+    gtk_clist_set_column_auto_resize(GTK_CLIST(plugins_clist), 1, TRUE);
+    gtk_clist_set_column_auto_resize(GTK_CLIST(plugins_clist), 2, TRUE);
+    gtk_clist_set_column_auto_resize(GTK_CLIST(plugins_clist), 3, TRUE);
+    plugins_scan(plugins_clist, std_plug_dir);
+    plugins_scan(plugins_clist, local_plug_dir);
+    if (!user_plug_dir)
+    {
+	user_plug_dir = (gchar *)g_malloc(strlen(getenv("HOME")) + 19);
+	sprintf(user_plug_dir, "%s/.ethereal/plugins", getenv("HOME"));
+    }
+    plugins_scan(plugins_clist, user_plug_dir);
+    gtk_signal_connect(GTK_OBJECT(plugins_clist), "select_row",
+	    GTK_SIGNAL_FUNC(plugins_clist_select_cb), NULL);
+    gtk_signal_connect(GTK_OBJECT(plugins_clist), "unselect_row",
+	    GTK_SIGNAL_FUNC(plugins_clist_unselect_cb), NULL);
+    gtk_widget_show(plugins_clist);
+    selected_row = -1;
+
+    frame_vbnbox = gtk_vbutton_box_new();
+    gtk_box_pack_start(GTK_BOX(frame_hbox), frame_vbnbox, FALSE, TRUE, 0);
+    gtk_container_set_border_width(GTK_CONTAINER(frame_vbnbox), 20);
+    gtk_button_box_set_layout(GTK_BUTTON_BOX(frame_vbnbox), GTK_BUTTONBOX_START);
+    gtk_widget_show(frame_vbnbox);
+
+    enable_bn = gtk_button_new_with_label("Enable");
+    gtk_container_add(GTK_CONTAINER(frame_vbnbox), enable_bn);
+    gtk_signal_connect(GTK_OBJECT(enable_bn), "clicked",
+	    GTK_SIGNAL_FUNC(plugins_enable_cb), GTK_OBJECT(plugins_clist));
+    gtk_widget_show(enable_bn);
+    details_bn = gtk_button_new_with_label("Details");
+    gtk_container_add(GTK_CONTAINER(frame_vbnbox), details_bn);
+    gtk_signal_connect(GTK_OBJECT(details_bn), "clicked",
+	    GTK_SIGNAL_FUNC(plugins_details_cb), GTK_OBJECT(plugins_clist));
+    gtk_widget_show(details_bn);
+
+    main_hbnbox = gtk_hbutton_box_new();
+    gtk_box_pack_start(GTK_BOX(main_vbox), main_hbnbox, FALSE, TRUE, 0);
+    gtk_container_set_border_width(GTK_CONTAINER(main_hbnbox), 10);
+    gtk_widget_show(main_hbnbox);
+
+    close_bn = gtk_button_new_with_label("Close");
+    gtk_container_add(GTK_CONTAINER(main_hbnbox), close_bn);
+    gtk_widget_show(close_bn);
+    gtk_signal_connect(GTK_OBJECT(close_bn), "clicked",
+	    GTK_SIGNAL_FUNC(plugins_close_cb), GTK_OBJECT(plugins_window));
+
+    gtk_widget_show(plugins_window);
+}
+
+/*
+ * scan /usr/share/ethereal/plugins, /usr/local/share/ethereal/plugins and
+ * ~/.ethereal/plugins and fill the clist widget
+ */
+static void
+plugins_scan(GtkWidget *clist, const char *dirname)
+{
+    DIR           *dir;             /* scanned directory */
+    struct dirent *file;            /* current file */
+    gchar          filename[512];   /* current file name */
+    void          *handle;          /* handle returned by dlopen */
+    gchar         *plugent[4];      /* new entry added in clist */
+    gint           row;             /* index of the new row */
+
+    if ((dir = opendir(dirname)) != NULL)
+    {
+	while ((file = readdir(dir)) != NULL)
+	{
+	    sprintf(filename, "%s/%s", dirname, file->d_name);
+
+	    if ((handle = dlopen(filename, RTLD_LAZY)) == NULL) continue;
+	    /* plugin name */
+	    plugent[0] = (gchar *)file->d_name;
+	    /* plugin description */
+	    if ((plugent[1] = (gchar *)dlsym(handle, "desc")) == NULL)
+	    {
+		dlclose(handle);
+		continue;
+	    }
+	    /* plugin version */
+	    if ((plugent[2] = (gchar *)dlsym(handle, "version")) == NULL)
+	    {
+		dlclose(handle);
+		continue;
+	    }
+	    /* check if plugin already loaded */
+	    if (is_enabled(plugent[0], plugent[2]))
+		plugent[3] = "Yes";
+	    else
+		plugent[3] = "No";
+	    row = gtk_clist_append(GTK_CLIST(clist), plugent);
+	    gtk_clist_set_row_data(GTK_CLIST(clist), row, (gpointer)dirname);
+	    dlclose(handle);
+	}
+	closedir(dir);
+    }
+}
+
+static void
+plugins_close_cb(GtkWidget *close_bt, gpointer parent_w)
+{
+    gtk_grab_remove(GTK_WIDGET(parent_w));
+    gtk_widget_destroy(GTK_WIDGET(parent_w));
+}
+
+void plugins_clist_select_cb(GtkWidget *clist, gint row, gint column,
+	GdkEventButton *event, gpointer data)
+{
+    selected_row = row;
+    gtk_clist_get_text(GTK_CLIST(clist), selected_row, 0, &selected_name);
+    gtk_clist_get_text(GTK_CLIST(clist), selected_row, 2, &selected_version);
+    gtk_clist_get_text(GTK_CLIST(clist), selected_row, 3, &selected_enabled);
+}
+
+void plugins_clist_unselect_cb(GtkWidget *clist, gint row, gint column,
+	GdkEventButton *event, gpointer data)
+{
+    selected_row = -1;
+}
+
+static void
+plugins_enable_cb(GtkWidget *button, gpointer clist)
+{
+    gchar     *pl_name, *dirname;
+    void      *handle;
+    gchar     *version, *protocol;
+    gchar     *filter_string;
+    dfilter   *filter = NULL;
+    void     (*dissector) (const u_char *, int, frame_data *, proto_tree *);
+    void     (*proto_init) ();
+
+    /* nothing selected */
+    if (selected_row == -1) return;
+    /* already enabled */
+    if (!strcmp(selected_enabled, "Yes")) return;
+
+    dirname = (gchar *)gtk_clist_get_row_data(GTK_CLIST(clist), selected_row);
+    if (!dirname) return;
+
+    pl_name = g_strdup_printf("%s/%s", dirname, selected_name);
+
+    if ((handle = dlopen(pl_name, RTLD_LAZY)) == NULL) {
+	simple_dialog(ESD_TYPE_WARN, NULL, "Can't load plugin");
+	g_free(pl_name);
+	return;
+    }
+
+    if ((version = (gchar *)dlsym(handle, "version")) == NULL)
+    {
+	simple_dialog(ESD_TYPE_WARN, NULL, "Invalid plugin");
+	dlclose(handle);
+	g_free(pl_name);
+	return;
+    }
+    if ((protocol = (gchar *)dlsym(handle, "protocol")) == NULL)
+    {
+	simple_dialog(ESD_TYPE_WARN, NULL, "Invalid plugin");
+	dlclose(handle);
+	g_free(pl_name);
+	return;
+    }
+    if ((filter_string = (gchar *)dlsym(handle, "filter_string")) == NULL)
+    {
+	simple_dialog(ESD_TYPE_WARN, NULL, "Invalid plugin");
+	dlclose(handle);
+	g_free(pl_name);
+	return;
+    }
+    if (dfilter_compile(filter_string, &filter) != 0) {
+	simple_dialog(ESD_TYPE_WARN, NULL, dfilter_error_msg);
+	dlclose(handle);
+	g_free(pl_name);
+	return;
+    }
+    if ((dissector = (void (*)(const u_char *, int,
+			frame_data *,
+			proto_tree *)) dlsym(handle, "dissector")) == NULL)
+    {
+	simple_dialog(ESD_TYPE_WARN, NULL, "Invalid plugin");
+	if (filter != NULL)
+	    dfilter_destroy(filter);
+	dlclose(handle);
+	g_free(pl_name);
+	return;
+    }
+    if ((proto_init = (void (*)()) dlsym(handle, "proto_init")) == NULL)
+    {
+	simple_dialog(ESD_TYPE_WARN, NULL, "Invalid plugin");
+	if (filter != NULL)
+	    dfilter_destroy(filter);
+	dlclose(handle);
+	g_free(pl_name);
+	return;
+    }
+
+    if (enable_plugin(handle, g_strdup(selected_name), version, protocol,
+		      filter_string, filter, dissector))
+    {
+	simple_dialog(ESD_TYPE_WARN, NULL, "Can't load new plugin");
+	if (filter != NULL)
+	    dfilter_destroy(filter);
+	dlclose(handle);
+	g_free(pl_name);
+	return;
+    }
+    proto_init();
+
+    gtk_clist_set_text(GTK_CLIST(clist), selected_row, 3, "Yes");
+    g_free(pl_name);
+}
+
+static void
+plugins_details_cb(GtkWidget *button, gpointer clist)
+{
+    gchar     *pl_name, *dirname;
+    GtkWidget *details_window;
+    GtkWidget *details_vbox;
+    GtkWidget *details_frame;
+    GtkWidget *frame_vbox;
+    GtkWidget *details_clist;
+    GtkWidget *frame_hbox;
+    GtkWidget *filter_label;
+    GtkWidget *filter_entry;
+    GtkWidget *details_hbnbox;
+    GtkWidget *close_bn;
+    gchar     *item[2];
+    void      *handle;
+    gchar     *filter_string;
+
+    if (selected_row == -1) return;
+    dirname = (gchar *)gtk_clist_get_row_data(GTK_CLIST(clist), selected_row);
+
+    details_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+    gtk_window_set_title(GTK_WINDOW(details_window), "Ethereal: Plugins Details");
+    gtk_window_set_modal(GTK_WINDOW(details_window), TRUE);
+
+    details_vbox = gtk_vbox_new(FALSE, 0);
+    gtk_container_add(GTK_CONTAINER(details_window), details_vbox);
+    gtk_widget_show(details_vbox);
+
+    details_frame = gtk_frame_new("Plugin Details");
+    gtk_box_pack_start(GTK_BOX(details_vbox), details_frame, TRUE, TRUE, 0);
+    gtk_container_set_border_width(GTK_CONTAINER(details_frame), 10);
+    gtk_widget_show(details_frame);
+
+    frame_vbox = gtk_vbox_new(FALSE, 0);
+    gtk_container_add(GTK_CONTAINER(details_frame), frame_vbox);
+    gtk_container_set_border_width(GTK_CONTAINER(frame_vbox), 5);
+    gtk_widget_show(frame_vbox);
+
+    details_clist = gtk_clist_new(2);
+    gtk_box_pack_start(GTK_BOX(frame_vbox), details_clist, TRUE, TRUE, 0);
+    gtk_clist_set_column_auto_resize(GTK_CLIST(details_clist), 0, TRUE);
+    gtk_clist_set_column_auto_resize(GTK_CLIST(details_clist), 1, TRUE);
+    item[0] = "Directory";
+    item[1] = dirname;
+    gtk_clist_append(GTK_CLIST(details_clist), item);
+    item[0] = "Plugin name";
+    item[1] = selected_name;
+    gtk_clist_append(GTK_CLIST(details_clist), item);
+    item[0] = "Plugin version";
+    item[1] = selected_version;
+    gtk_clist_append(GTK_CLIST(details_clist), item);
+    gtk_widget_show(details_clist);
+
+    frame_hbox = gtk_hbox_new(FALSE, 0);
+    gtk_box_pack_start(GTK_BOX(frame_vbox), frame_hbox, TRUE, TRUE, 0);
+    gtk_widget_show(frame_hbox);
+
+    filter_label = gtk_label_new("Filter");
+    gtk_box_pack_start(GTK_BOX(frame_hbox), filter_label, TRUE, TRUE, 0);
+    gtk_widget_show(filter_label);
+
+    filter_entry = gtk_entry_new();
+    gtk_object_set_data(GTK_OBJECT(details_window), PLUGINS_DFILTER_TE,
+	                filter_entry);
+    gtk_box_pack_start(GTK_BOX(frame_hbox), filter_entry, TRUE, TRUE, 0);
+    if (!strcmp(selected_enabled, "Yes"))
+    {
+	gtk_entry_set_text(GTK_ENTRY(filter_entry),
+		find_filter_string(selected_name, selected_version));
+	gtk_entry_set_editable(GTK_ENTRY(filter_entry), TRUE);
+    }
+    else
+    {
+	pl_name = g_strdup_printf("%s/%s", dirname, selected_name);
+	if ((handle = dlopen(pl_name, RTLD_LAZY)) == NULL) {
+	    gtk_entry_set_text(GTK_ENTRY(filter_entry),
+		    "Can't load filter_string from plugin");
+	}
+	else if ((filter_string = (gchar *)dlsym(handle, "filter_string")) == NULL)
+	{
+	    gtk_entry_set_text(GTK_ENTRY(filter_entry),
+		    "Can't load filter_string from plugin");
+	    dlclose(handle);
+	}
+	else
+	{
+	    gtk_entry_set_text(GTK_ENTRY(filter_entry), filter_string);
+	    dlclose(handle);
+	}
+	gtk_entry_set_editable(GTK_ENTRY(filter_entry), FALSE);
+	g_free(pl_name);
+    }
+    gtk_widget_show(filter_entry);
+
+    details_hbnbox = gtk_hbutton_box_new();
+    gtk_box_pack_start(GTK_BOX(details_vbox), details_hbnbox, FALSE, TRUE, 0);
+    gtk_container_set_border_width(GTK_CONTAINER(details_hbnbox), 10);
+    gtk_widget_show(details_hbnbox);
+
+    close_bn = gtk_button_new_with_label("Close");
+    gtk_container_add(GTK_CONTAINER(details_hbnbox), close_bn);
+    gtk_widget_show(close_bn);
+    gtk_signal_connect(GTK_OBJECT(close_bn), "clicked",
+	    GTK_SIGNAL_FUNC(details_close_cb), GTK_OBJECT(details_window));
+
+    gtk_widget_show(details_window);
+}
+
+static void
+details_close_cb(GtkWidget *close_bt, gpointer parent_w)
+{
+    GtkWidget *filter_entry;
+    gchar     *filter_string;
+    dfilter   *filter = NULL;
+
+    if (!strcmp(selected_enabled, "Yes"))
+    {
+	filter_entry = gtk_object_get_data(GTK_OBJECT(parent_w), PLUGINS_DFILTER_TE);
+	filter_string = gtk_entry_get_text(GTK_ENTRY(filter_entry));
+	if (dfilter_compile(filter_string, &filter) != 0)
+	{
+	    simple_dialog(ESD_TYPE_WARN, NULL, dfilter_error_msg);
+	}
+	else
+	    plugin_replace_filter(selected_name, selected_version,
+		                  filter_string, filter);
+    }
+    gtk_grab_remove(GTK_WIDGET(parent_w));
+    gtk_widget_destroy(GTK_WIDGET(parent_w));
+}
+
+#endif
diff -Nru ethereal/packet-tcp.c ethereal.plug/packet-tcp.c
--- ethereal/packet-tcp.c	Wed Nov 10 22:28:40 1999
+++ ethereal.plug/packet-tcp.c	Wed Nov 10 22:29:10 1999
@@ -37,7 +37,7 @@
 
 #include <stdio.h>
 #include <glib.h>
-#include "packet.h"
+#include "globals.h"
 #include "resolv.h"
 #include "follow.h"
 #include "util.h"
@@ -51,6 +51,10 @@
 # include "snprintf.h"
 #endif
 
+#ifdef HAVE_DLFCN_H
+#include "plugins.h"
+#endif
+
 #ifndef __PACKET_IP_H__
 #include "packet-ip.h"
 #endif
@@ -469,6 +473,22 @@
   /* Check the packet length to see if there's more data
      (it could be an ACK-only packet) */
   if (packet_max > offset) {
+#ifdef HAVE_DLFCN_H
+    plugin *pt_plug = plugin_list;
+
+    if (pt_plug) {
+      while (pt_plug) {
+        if (!strcmp(pt_plug->protocol, "tcp")) {
+	  if (tree && dfilter_apply(pt_plug->filter, tree, pd)) {
+	    pt_plug->dissector(pd, offset, fd, tree);
+	    goto dissect_end;
+	  }
+	}
+	pt_plug = pt_plug->next;
+      }
+    }
+#endif
+
     /* XXX - this should be handled the way UDP handles this, with a table
        of port numbers to which stuff can be added */
 #define PORT_IS(port)	(th.th_sport == port || th.th_dport == port)
@@ -526,6 +546,8 @@
     }
   }
  
+dissect_end:
+
   if( data_out_file ) {
     reassemble_tcp( th.th_seq,		/* sequence number */
         ( pi.len - offset ),		/* data length */
diff -Nru ethereal/plugins.c ethereal.plug/plugins.c
--- ethereal/plugins.c	Thu Jan  1 01:00:00 1970
+++ ethereal.plug/plugins.c	Wed Nov 10 22:29:10 1999
@@ -0,0 +1,122 @@
+/* plugins.c
+ * definitions for plugins structures
+ *
+ * Ethereal - Network traffic analyzer
+ * By Gerald Combs <gerald@xxxxxxxx>
+ * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#ifdef HAVE_DLFCN_H
+
+#include <time.h>
+
+#include "globals.h"
+
+#include "plugins.h"
+
+plugin *plugin_list;
+
+int
+enable_plugin(void *handle, gchar *name, gchar *version, gchar *protocol,
+	      gchar *filter_string, dfilter *filter,
+	      void (*dissector) (const u_char *,
+	                         int,
+				 frame_data *,
+				 proto_tree *))
+{
+    plugin *new_plug, *pt_plug;
+
+    new_plug = (plugin *)g_malloc(sizeof(plugin));
+    if (new_plug == 0) return -1;
+
+    pt_plug = plugin_list;
+    if (!pt_plug)
+        plugin_list = new_plug;
+    else
+    {
+	while (pt_plug->next) pt_plug = pt_plug->next;
+	pt_plug->next = new_plug;
+    }
+
+    new_plug->handle = handle;
+    new_plug->name = name;
+    new_plug->version = version;
+    new_plug->protocol = protocol;
+    new_plug->filter_string = g_strdup(filter_string);
+    new_plug->filter = filter;
+    new_plug->dissector = dissector;
+    new_plug->next = NULL;
+    return 0;
+}
+
+gboolean
+is_enabled(const gchar *name, const gchar *version)
+{
+    plugin *pt_plug;
+
+    pt_plug = plugin_list;
+    while (pt_plug)
+    {
+	if (!strcmp(pt_plug->name, name) && !strcmp(pt_plug->version, version))
+	    return TRUE;
+	pt_plug = pt_plug->next;
+    }
+    return FALSE;
+}
+
+gchar *
+find_filter_string(const gchar *name, const gchar *version)
+{
+    plugin *pt_plug;
+
+    pt_plug = plugin_list;
+    while (pt_plug)
+    {
+	if (!strcmp(pt_plug->name, name) && !strcmp(pt_plug->version, version))
+	    return pt_plug->filter_string;
+	pt_plug = pt_plug->next;
+    }
+    return NULL;
+}
+
+void
+plugin_replace_filter(const gchar *name, const gchar *version,
+	const gchar *filter_string, dfilter *filter)
+{
+    plugin *pt_plug;
+
+    pt_plug = plugin_list;
+    while (pt_plug)
+    {
+	if (!strcmp(pt_plug->name, name) && !strcmp(pt_plug->version, version))
+	{
+	    g_free(pt_plug->filter_string);
+	    pt_plug->filter_string = g_strdup(filter_string);
+	    dfilter_destroy(pt_plug->filter);
+	    pt_plug->filter = filter;
+	    return;
+	}
+	pt_plug = pt_plug->next;
+    }
+}
+
+#endif
diff -Nru ethereal/plugins.h ethereal.plug/plugins.h
--- ethereal/plugins.h	Thu Jan  1 01:00:00 1970
+++ ethereal.plug/plugins.h	Wed Nov 10 22:29:10 1999
@@ -0,0 +1,49 @@
+/* plugins.h
+ * definitions for plugins structures
+ *
+ * Ethereal - Network traffic analyzer
+ * By Gerald Combs <gerald@xxxxxxxx>
+ * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#ifndef __PLUGINS_H__
+#define __PLUGINS_H__
+
+typedef struct _plugin {
+    void    *handle;          /* handle returned by dlopen */
+    gchar   *name;            /* plugin name */
+    gchar   *version;         /* plugin version */
+    gchar   *protocol;        /* protocol which should call the dissector
+			       * for this plugin eg "tcp" */
+    gchar   *filter_string;   /* display filter string matching frames for
+			       * which the dissector should be used */
+    dfilter *filter;          /* compiled display filter */
+    /* the dissector */
+    void (*dissector) (const u_char *, int, frame_data *, proto_tree *);
+    struct _plugin *next;     /* forward link */
+} plugin;
+
+extern plugin *plugin_list;
+
+int enable_plugin(void *, gchar *, gchar *, gchar *, gchar *, dfilter *,
+	          void (*) (const u_char *, int, frame_data *, proto_tree *));
+gboolean is_enabled(const gchar *, const gchar *);
+gchar *find_filter_string(const gchar *, const gchar *);
+void plugin_replace_filter(const gchar *, const gchar *, const gchar *, dfilter *);
+
+#endif /* __PLUGINS_H__ */



-- 
"Hi.  This is Dan Cassidy's answering machine.  Please leave your name and 
number... and after I've doctored the tape, your message will implicate you
 in a federal crime and be brought to the attention of the F.B.I... BEEEP"
 -- Blue Devil comics