/* Copyright (C) 2000 - 2004 Christian Kreibich . Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies of the Software and its documentation and acknowledgment shall be given in the documentation and software packages that this Software was used. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static GList *proto_plugins = NULL; /* list */ static ND_ProtoPlugin *proto_plugin_new(char *filename); static void proto_plugin_scan(const char *dirname); static gboolean proto_plugin_hook_up(ND_ProtoPlugin *p); static void proto_plugin_load(void); static void proto_plugin_setup_gui(void); static int proto_plugin_cmp(ND_ProtoPlugin *p1, char *filename); static const char * proto_plugin_dummy_name(void) { return _("Unnamed Plugin."); } static const char * proto_plugin_dummy_description(void) { return _("No description available."); } static const char * proto_plugin_dummy_author(void) { return _("No author(s) specified."); } static const char * proto_plugin_dummy_version(void) { return _("No version specified."); } static int proto_plugin_dummy_op(void) { return 0; } static LND_Protocol * proto_plugin_dummy_init(void) { return NULL; } static ND_ProtoPlugin * proto_plugin_new(char *filename) { ND_ProtoPlugin *plugin; plugin = (ND_ProtoPlugin*) g_new0(ND_ProtoPlugin, 1); D_ASSERT_PTR(plugin); if (!plugin) return NULL; if (filename) plugin->filename = g_strdup(filename); plugin->name = proto_plugin_dummy_name; plugin->description = proto_plugin_dummy_description; plugin->author = proto_plugin_dummy_author; plugin->version = proto_plugin_dummy_version; plugin->init = proto_plugin_dummy_init; plugin->cleanup = proto_plugin_dummy_op; return (plugin); } static void proto_plugin_free(ND_ProtoPlugin *plugin) { if (!plugin) return; lt_dlclose(plugin->lt); g_free(plugin->filename); g_free(plugin); } static int proto_plugin_cmp(ND_ProtoPlugin *p1, char *filename) { if (!p1 || !filename) return (-1); return (strcmp(p1->filename, filename)); } static void proto_plugin_scan(const char *dir) { DIR *dirp; struct dirent *de; char *dot; struct stat st; char path[MAXPATHLEN]; D(("Scanning '%s' for protocols\n", dir)); if (! (dirp = opendir(dir))) return; for (de = readdir(dirp); de; de = readdir(dirp)) { g_snprintf(path, MAXPATHLEN, "%s/%s", dir, de->d_name); if (stat(path, &st) != 0) { D(("Could not stat %s\n", path)); continue; } if (! S_ISREG(st.st_mode)) { D(("Skipping %s, not a regular file.\n", path)); continue; } /* Chop off any file extension, if found. libltdl takes * care of that. */ if ( (dot = strrchr(path, '.'))) *dot = '\0'; if (!g_list_find_custom(proto_plugins, path, (GCompareFunc)proto_plugin_cmp)) { proto_plugins = g_list_append(proto_plugins, proto_plugin_new(path)); } } closedir(dirp); } static gboolean proto_plugin_hook_up(ND_ProtoPlugin *plugin) { ND_Protocol *proto_gui; lt_ptr_t sym; int i; if ((sym = lt_dlsym(plugin->lt, "name")) != NULL) plugin->name = sym; if ((sym = lt_dlsym(plugin->lt, "description")) != NULL) plugin->description = sym; if ((sym = lt_dlsym(plugin->lt, "author")) != NULL) plugin->author = sym; if ((sym = lt_dlsym(plugin->lt, "version")) != NULL) plugin->version = sym; if ((sym = lt_dlsym(plugin->lt, "init")) != NULL) plugin->init = sym; if ((sym = lt_dlsym(plugin->lt, "cleanup")) != NULL) plugin->cleanup = sym; D(("Hooking up protocol %s\n", plugin->name())); /* Call the init routine the plugin provides: */ if (! (plugin->proto = plugin->init())) { D(("No plugin available for a GUI\n")); return FALSE; } proto_gui = nd_proto_get(plugin->proto); /* If the plugin provides a header fields table, calculate the header size */ if (proto_gui->fields) { for (i = 0, proto_gui->header_size = 0; proto_gui->fields[i].label; i++) proto_gui->header_size += proto_gui->fields[i].bits; } /* Hook in the plugin: */ proto_gui->plugin = plugin; return TRUE; } static gint proto_plugin_strcmp(gconstpointer a, gconstpointer b) { ND_ProtoPlugin *p1 = (ND_ProtoPlugin *) a; ND_ProtoPlugin *p2 = (ND_ProtoPlugin *) b; return strcmp(p1->name(), p2->name()); } static void proto_plugin_load(void) { GList *l, *l2; ND_ProtoPlugin *plugin; char s[MAXPATHLEN]; for (l = g_list_first(proto_plugins); l; l = g_list_next(l)) { plugin = (ND_ProtoPlugin *) l->data; if (! (plugin->lt = lt_dlopenext(plugin->filename)) || ! proto_plugin_hook_up(plugin)) { if (! nd_runtime_options.show_plugins) { g_snprintf(s, MAXPATHLEN, _("Unable to load protocol plugin '%s'.\n" "If this plugin depends on other plugins,\n" "make sure you have those installed."), (plugin->name != proto_plugin_dummy_name ? plugin->name() : plugin->filename)); nd_dialog_message(_("Plugin error"), s, FALSE); } l->data = NULL; proto_plugin_free(plugin); } } /* We may have deleted some plugins above that failed to initialize. * Clear out those list items in a separate iteration. */ for (l = g_list_first(proto_plugins); l; ) { if (l->data == NULL) { l2 = l; l = g_list_next(l); proto_plugins = g_list_remove_link(proto_plugins, l2); g_list_free_1(l2); } else { l = g_list_next(l); } } /* Now sort the list of plugins alphanumerically, * so that we automatically get sorted menus etc. */ proto_plugins = g_list_sort(proto_plugins, proto_plugin_strcmp); } static void proto_plugin_setup_gui(void) { GtkWidget *about_protocols, *menu, *item; GList *l; ND_ProtoPlugin *plugin; /* Hook in protocol menus: */ ND_GTK_GET(about_protocols, nd_toplevel_window, "about_protocols"); menu = gtk_menu_new(); gtk_widget_ref (menu); gtk_object_set_data_full (GTK_OBJECT (nd_toplevel_window), "about_protocols_menu", menu, (GtkDestroyNotify) gtk_widget_unref); gtk_menu_item_set_submenu (GTK_MENU_ITEM (about_protocols), menu); for (l = g_list_first(proto_plugins); l; l = g_list_next(l)) { plugin = (ND_ProtoPlugin*)l->data; item = gtk_menu_item_new_with_label(plugin->name()); gtk_widget_ref(item); gtk_object_set_data_full (GTK_OBJECT (menu), plugin->name(), item, (GtkDestroyNotify) gtk_widget_unref); gtk_widget_show(item); gtk_object_set_data(GTK_OBJECT(item), "plugin", plugin); gtk_container_add(GTK_CONTAINER(menu), item); gtk_signal_connect (GTK_OBJECT (item), "activate", GTK_SIGNAL_FUNC (on_about_proto_activate), NULL); nd_gui_proto_menu_register(plugin->proto); } } void nd_proto_plugin_init(void) { D_ENTER; if (lt_dlinit() != 0) { fprintf(stderr, "Could not initialize libltdl -- exiting.\n"); exit(-1); } proto_plugin_scan(nd_prefs_get_proto_dir_user()); proto_plugin_scan(nd_prefs_get_proto_dir_global()); proto_plugin_load(); proto_plugin_setup_gui(); D_RETURN; } const char * nd_proto_plugin_get_description(ND_ProtoPlugin *plugin) { if (!plugin) return (NULL); return (plugin->description()); } const char * nd_proto_plugin_get_author(ND_ProtoPlugin *plugin) { if (!plugin) return (NULL); return (plugin->author()); } const char * nd_proto_plugin_get_name(ND_ProtoPlugin *plugin) { if (!plugin) return (NULL); return (plugin->name()); } const char * nd_proto_plugin_get_version(ND_ProtoPlugin *plugin) { if (!plugin) return (NULL); return (plugin->version()); } void nd_proto_plugin_show_about(ND_ProtoPlugin *plugin) { char s[MAXPATHLEN]; GtkWidget *w; GtkWidget *label; D_ASSERT_PTR(plugin); if (!plugin) return; w = create_protocol_about_dialog(); g_snprintf(s, MAXPATHLEN, "%s, %s.", plugin->name(), plugin->version()); ND_GTK_GET(label, w, "proto_name_label"); gtk_label_set_text(GTK_LABEL(label), s); g_snprintf(s, MAXPATHLEN, _("Author: %s"), plugin->author()); ND_GTK_GET(label, w, "proto_author_label"); gtk_label_set_text(GTK_LABEL(label), s); ND_GTK_GET(label, w, "proto_description_label"); gtk_label_set_text(GTK_LABEL(label), plugin->description()); gtk_widget_show(w); } void nd_proto_plugin_foreach(ND_ProtoPluginFunc callback, void *user_data) { GList *l; if (!callback) return; for (l = g_list_first(proto_plugins); l; l = g_list_next(l)) callback((ND_ProtoPlugin *)l->data, user_data); }