diff options
author | Andrew John Hughes <gnu_andrew@member.fsf.org> | 2006-06-11 18:23:15 +0000 |
---|---|---|
committer | Andrew John Hughes <gnu_andrew@member.fsf.org> | 2006-06-11 18:23:15 +0000 |
commit | 35d18ccf396a6cfdcbe5bbdf38df7d01852250bc (patch) | |
tree | 562e6d161a8957db8a46900b46f661c5e52e1a34 /native/plugin | |
parent | c5877847749d21bdf84e33929ffa52a56e5c6ca0 (diff) | |
download | classpath-35d18ccf396a6cfdcbe5bbdf38df7d01852250bc.tar.gz |
2006-06-11 Andrew John Hughes <gnu_andrew@member.fsf.org>
* Merge of HEAD-->generics between
2006/05/29 and 2006/06/11.
Diffstat (limited to 'native/plugin')
-rw-r--r-- | native/plugin/Makefile.am | 14 | ||||
-rw-r--r-- | native/plugin/gcjwebplugin.cc | 575 |
2 files changed, 479 insertions, 110 deletions
diff --git a/native/plugin/Makefile.am b/native/plugin/Makefile.am index 7358381eb..e1331fe45 100644 --- a/native/plugin/Makefile.am +++ b/native/plugin/Makefile.am @@ -4,15 +4,15 @@ libgcjwebplugin_la_SOURCES = gcjwebplugin.cc libgcjwebplugin_la_CXXFLAGS = \ -Wall -DAPPLETVIEWER_EXECUTABLE="\"$(bindir)/appletviewer\"" \ - $(MOZILLA_CFLAGS) $(GLIB_CFLAGS) + $(MOZILLA_CFLAGS) $(GLIB_CFLAGS) $(GTK_CFLAGS) libgcjwebplugin_la_LDFLAGS = -avoid-version \ - $(GLIB_LIBS) \ + $(GLIB_LIBS) $(GTK_LIBS) \ -lstdc++ -install-libLTLIBRARIES: $(lib_LTLIBRARIES) - $(INSTALL) -d -m0755 $(DESTDIR)@PLUGIN_DIR@ - $(INSTALL) .libs/libgcjwebplugin.so $(DESTDIR)@PLUGIN_DIR@ +install-plugin: $(lib_LTLIBRARIES) + $(INSTALL) -d -m0755 $(DESTDIR)$(PLUGIN_DIR) + $(INSTALL) .libs/libgcjwebplugin.so $(DESTDIR)$(PLUGIN_DIR) -uninstall-libLTLIBRARIES: - rm -f $(DESTDIR)@PLUGIN_DIR@/libgcjwebplugin.so +uninstall-plugin: + rm -f $(DESTDIR)$(PLUGIN_DIR)/libgcjwebplugin.so diff --git a/native/plugin/gcjwebplugin.cc b/native/plugin/gcjwebplugin.cc index bbb9809be..ad65c7ef1 100644 --- a/native/plugin/gcjwebplugin.cc +++ b/native/plugin/gcjwebplugin.cc @@ -49,6 +49,10 @@ exception statement from your version. */ // GLib includes. #include <glib.h> +#include <glib/gstdio.h> + +// GTK includes. +#include <gtk/gtk.h> // gcjwebplugin includes. #include "config.h" @@ -75,6 +79,10 @@ exception statement from your version. */ g_printerr ("%s:%d: thread %p: Error: %s: %s\n", __FILE__, __LINE__, \ g_thread_self (), first, second) +#define PLUGIN_ERROR_THREE(first, second, third) \ + g_printerr ("%s:%d: thread %p: Error: %s: %s: %s\n", __FILE__, \ + __LINE__, g_thread_self (), first, second, third) + // Plugin information passed to about:plugins. #define PLUGIN_NAME "GCJ Web Browser Plugin" #define PLUGIN_DESC "The " PLUGIN_NAME " executes Java applets." @@ -113,8 +121,25 @@ exception statement from your version. */ #define PLUGIN_FILE_EXTS "class,jar,zip" #define PLUGIN_MIME_COUNT 1 -// Directory in which named pipes are created. -#define PIPE_DIRECTORY "/tmp" +// Security dialog messages. +#define RESPONSE_TRUST_APPLET "Trust Applet" +#define RESPONSE_TRUST_APPLET_ADD_TO_LIST "Trust Applet and Add to Whitelist" +#define SECURITY_WARNING \ + "%s wants to load an applet.\n" \ + "GNU Classpath's security implementation is not complete.\n" \ + "HOSTILE APPLETS WILL STEAL AND/OR DESTROY YOUR DATA!\n" +#define SECURITY_DESCRIPTION \ + "Click \"Cancel\" if you do not trust the source of this applet.\n" \ + "Click \"Trust Applet\" to load and run this applet now.\n" \ + "Click \"Trust Applet and Add To Whitelist\" to always load" \ + " and run this applet from now on, without asking.\n" \ + "The whitelist is a list of the URLs from which you trust" \ + " applets.\n" \ + "Your whitelist file is \" %s \"." +#define FAILURE_MESSAGE \ + "This page wants to load an applet.\n" \ + "The appletviewer is missing or not installed properly in \"" \ + APPLETVIEWER_EXECUTABLE "\"." // Documentbase retrieval required definition. static NS_DEFINE_IID (kIPluginTagInfo2IID, NS_IPLUGINTAGINFO2_IID); @@ -122,6 +147,16 @@ static NS_DEFINE_IID (kIPluginTagInfo2IID, NS_IPLUGINTAGINFO2_IID); // Browser function table. static NPNetscapeFuncs browserFunctions; +// Data directory for plugin. +static gchar* data_directory; + +// Whitelist filename +static gchar* whitelist_filename; + +// Keeps track of initialization. NP_Initialize should only be +// called once. +gboolean initialized = false; + // GCJPluginData stores all the data associated with a single plugin // instance. A separate plugin instance is created for each <APPLET> // tag. For now, each plugin instance spawns its own applet viewer @@ -173,6 +208,12 @@ typedef union static void plugin_data_new (GCJPluginData** data); // Documentbase retrieval. static gchar* plugin_get_documentbase (NPP instance); +// plugin failure handling. +static bool plugin_failed (); +// Whitelist handling. +static bool plugin_user_trusts_documentbase (char* documentbase); +static bool plugin_ask_user_about_documentbase (char* documentbase); +static void plugin_add_documentbase_to_whitelist (char* documentbase); // Callback used to monitor input pipe status. static gboolean plugin_in_pipe_callback (GIOChannel* source, GIOCondition condition, @@ -181,7 +222,7 @@ static gboolean plugin_in_pipe_callback (GIOChannel* source, static gboolean plugin_out_pipe_callback (GIOChannel* source, GIOCondition condition, gpointer plugin_data); -static void plugin_start_appletviewer (GCJPluginData* data); +static NPError plugin_start_appletviewer (GCJPluginData* data); static gchar* plugin_create_applet_tag (int16 argc, char* argn[], char* argv[]); static void plugin_send_message_to_appletviewer (GCJPluginData* data, @@ -195,6 +236,11 @@ static void plugin_data_destroy (GCJPluginData** data); static GMutex* plugin_instance_mutex = NULL; // A counter used to create uniquely named pipes. static gulong plugin_instance_counter = 0; +// The user's documentbase whitelist. +static GIOChannel* whitelist_file = NULL; +// A global variable for reporting GLib errors. This must be free'd +// and set to NULL after each use. +static GError* channel_error = NULL; // Functions prefixed by GCJ_ are instance functions. They are called // by the browser and operate on instances of GCJPluginData. @@ -224,7 +270,7 @@ GCJ_New (NPMIMEType pluginType, NPP instance, uint16 mode, NPError np_error = NPERR_NO_ERROR; GCJPluginData* data = NULL; - GError* channel_error = NULL; + gchar* documentbase = NULL; gchar* read_message = NULL; gchar* applet_tag = NULL; @@ -278,13 +324,19 @@ GCJ_New (NPMIMEType pluginType, NPP instance, uint16 mode, goto cleanup_appletviewer_mutex; } + if (!plugin_user_trusts_documentbase (documentbase)) + { + PLUGIN_ERROR ("User does not trust applet."); + np_error = NPERR_GENERIC_ERROR; + goto cleanup_appletviewer_mutex; + } + // Create appletviewer-to-plugin pipe which we refer to as the input // pipe. // data->in_pipe_name - data->in_pipe_name = g_strdup_printf (PIPE_DIRECTORY - "/gcj-%s-appletviewer-to-plugin", - data->instance_string); + data->in_pipe_name = g_strdup_printf ("%s/gcj-%s-appletviewer-to-plugin", + data_directory, data->instance_string); if (!data->in_pipe_name) { PLUGIN_ERROR ("Failed to create input pipe name."); @@ -305,9 +357,8 @@ GCJ_New (NPMIMEType pluginType, NPP instance, uint16 mode, // output pipe. // data->out_pipe_name - data->out_pipe_name = g_strdup_printf (PIPE_DIRECTORY - "/gcj-%s-plugin-to-appletviewer", - data->instance_string); + data->out_pipe_name = g_strdup_printf ("%s/gcj-%s-plugin-to-appletviewer", + data_directory, data->instance_string); if (!data->out_pipe_name) { @@ -332,9 +383,17 @@ GCJ_New (NPMIMEType pluginType, NPP instance, uint16 mode, // appletviewer, create the IO channels and install the channel // watch callbacks. g_mutex_lock (data->appletviewer_mutex); - - plugin_start_appletviewer (data); - + + np_error = plugin_start_appletviewer (data); + + // If the appletviewer is not installed, then a dialog box will + // show up and the plugin will be killed. + if (np_error != NPERR_NO_ERROR) + { + if (plugin_failed ()) + goto cleanup_applet_failure; + } + // Create plugin-to-appletviewer channel. The default encoding for // the file is UTF-8. // data->out_to_appletviewer @@ -342,16 +401,19 @@ GCJ_New (NPMIMEType pluginType, NPP instance, uint16 mode, "w", &channel_error); if (!data->out_to_appletviewer) { - PLUGIN_ERROR_TWO ("Failed to create output channel", - channel_error->message); + if (channel_error) + { + PLUGIN_ERROR_TWO ("Failed to create output channel", + channel_error->message); + g_error_free (channel_error); + channel_error = NULL; + } + else + PLUGIN_ERROR ("Failed to create output channel"); + np_error = NPERR_GENERIC_ERROR; goto cleanup_out_to_appletviewer; } - if (channel_error) - { - g_error_free (channel_error); - channel_error = NULL; - } // Watch for hangup and error signals on the output pipe. data->out_watch_source = @@ -366,16 +428,19 @@ GCJ_New (NPMIMEType pluginType, NPP instance, uint16 mode, "r", &channel_error); if (!data->in_from_appletviewer) { - PLUGIN_ERROR_TWO ("Failed to create input channel", - channel_error->message); + if (channel_error) + { + PLUGIN_ERROR_TWO ("Failed to create input channel", + channel_error->message); + g_error_free (channel_error); + channel_error = NULL; + } + else + PLUGIN_ERROR ("Failed to create input channel"); + np_error = NPERR_GENERIC_ERROR; goto cleanup_in_from_appletviewer; } - if (channel_error) - { - g_error_free (channel_error); - channel_error = NULL; - } // Watch for hangup and error signals on the input pipe. data->in_watch_source = @@ -390,16 +455,19 @@ GCJ_New (NPMIMEType pluginType, NPP instance, uint16 mode, &channel_error) != G_IO_STATUS_NORMAL) { - PLUGIN_ERROR_TWO ("Receiving confirmation from appletviewer failed", - channel_error->message); + if (channel_error) + { + PLUGIN_ERROR_TWO ("Receiving confirmation from appletviewer failed", + channel_error->message); + g_error_free (channel_error); + channel_error = NULL; + } + else + PLUGIN_ERROR ("Receiving confirmation from appletviewer failed"); + np_error = NPERR_GENERIC_ERROR; goto cleanup_in_watch_source; } - if (channel_error) - { - g_error_free (channel_error); - channel_error = NULL; - } PLUGIN_DEBUG ("GCJ_New: got confirmation that appletviewer is running."); data->appletviewer_alive = TRUE; @@ -448,7 +516,8 @@ GCJ_New (NPMIMEType pluginType, NPP instance, uint16 mode, // cleanup_out_pipe: // Delete output pipe. unlink (data->out_pipe_name); - + + cleanup_applet_failure: cleanup_out_pipe_name: g_free (data->out_pipe_name); data->out_pipe_name = NULL; @@ -480,7 +549,6 @@ GCJ_New (NPMIMEType pluginType, NPP instance, uint16 mode, instance->pdata = NULL; cleanup_done: - g_free (tag_message); tag_message = NULL; g_free (applet_tag); @@ -602,6 +670,7 @@ GCJ_SetWindow (NPP instance, NPWindow* window) window->width); plugin_send_message_to_appletviewer (data, width_message); g_free (width_message); + width_message = NULL; // Store the new width. data->window_width = window->width; @@ -619,6 +688,7 @@ GCJ_SetWindow (NPP instance, NPWindow* window) window->height); plugin_send_message_to_appletviewer (data, height_message); g_free (height_message); + height_message = NULL; // Store the new height. data->window_height = window->height; @@ -651,6 +721,7 @@ GCJ_SetWindow (NPP instance, NPWindow* window) (gulong) window->window); plugin_send_message_to_appletviewer (data, window_message); g_free (window_message); + window_message = NULL; g_mutex_unlock (data->appletviewer_mutex); @@ -833,6 +904,201 @@ plugin_get_documentbase (NPP instance) return documentbase_copy; } +// This function shows a error message if the appletviewer has +// not been installed. It returns true, if the user presses the +// ok button. +static bool +plugin_failed () +{ + GtkWidget* dialog = NULL; + GtkWidget* ok_button = NULL; + + dialog = gtk_message_dialog_new (NULL, + GTK_DIALOG_MODAL, + GTK_MESSAGE_WARNING, + GTK_BUTTONS_NONE, + FAILURE_MESSAGE); + ok_button = gtk_dialog_add_button (GTK_DIALOG (dialog), + GTK_STOCK_OK, + GTK_RESPONSE_OK); + gtk_widget_show_all (dialog); + if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) + { + gtk_widget_destroy (dialog); + return true; + } + return false; +} + +// plugin_user_trusts_documentbase returns true if the given +// documentbase is in the documentbase whitelist. Otherwise it asks +// the user if he trusts the given documentbase by calling +// plugin_ask_user_about_documentbase. +static bool +plugin_user_trusts_documentbase (char* documentbase) +{ + bool applet_in_whitelist = false; + + // Check if documentbase is in whitelist. + while (true) + { + gchar* whitelist_entry = NULL; + gchar* newline_documentbase = NULL; + + // If reading fails, break out of this loop with + // applet_in_whitelist still set to false. + if (g_io_channel_read_line (whitelist_file, &whitelist_entry, + NULL, NULL, &channel_error) + != G_IO_STATUS_NORMAL) + { + if (channel_error) + { + PLUGIN_ERROR_TWO ("Failed to read line from whitelist file", + channel_error->message); + g_error_free (channel_error); + channel_error = NULL; + } + else + PLUGIN_ERROR ("Failed to open whitelist file."); + g_free (whitelist_entry); + whitelist_entry = NULL; + break; + } + + newline_documentbase = g_strdup_printf ("%s\n", documentbase); + if (!strcmp (newline_documentbase, whitelist_entry)) + { + applet_in_whitelist = true; + g_free (newline_documentbase); + newline_documentbase = NULL; + g_free (whitelist_entry); + whitelist_entry = NULL; + break; + } + g_free (whitelist_entry); + whitelist_entry = NULL; + g_free (newline_documentbase); + newline_documentbase = NULL; + } + + return applet_in_whitelist ? true + : plugin_ask_user_about_documentbase (documentbase); +} + +// plugin_add_documentbase_to_whitelist adds the given documentbase to +// the user's documentbase whitelist. +static void +plugin_add_documentbase_to_whitelist (char* documentbase) +{ + gsize bytes_written = 0; + char* newline_documentbase = NULL; + GIOStatus status = G_IO_STATUS_NORMAL; + + newline_documentbase = g_strdup_printf ("%s\n", documentbase); + status = g_io_channel_write_chars (whitelist_file, + newline_documentbase, -1, &bytes_written, + &channel_error); + g_free (newline_documentbase); + newline_documentbase = NULL; + + if (status != G_IO_STATUS_NORMAL) + { + if (channel_error) + { + PLUGIN_ERROR_TWO ("Error writing to whitelist file", + channel_error->message); + g_error_free (channel_error); + channel_error = NULL; + } + else + PLUGIN_ERROR ("Error writing to whitelist file."); + } + + if (g_io_channel_flush (whitelist_file, &channel_error) + != G_IO_STATUS_NORMAL) + { + if (channel_error) + { + PLUGIN_ERROR_TWO ("Failed to write whitelist file", + channel_error->message); + g_error_free (channel_error); + channel_error = NULL; + } + else + PLUGIN_ERROR ("Failed to write whitelist file."); + } + + if (g_io_channel_shutdown (whitelist_file, TRUE, &channel_error) + != G_IO_STATUS_NORMAL) + { + if (channel_error) + { + PLUGIN_ERROR_TWO ("Failed to close whitelist file", + channel_error->message); + g_error_free (channel_error); + channel_error = NULL; + } + else + PLUGIN_ERROR ("Failed to close whitelist file."); + } +} + +// plugin_ask_user_about_documentbase puts up a dialog box that asks if the +// user trusts applets from this documentbase. The user has three +// options: "Cancel", "Trust Applet" and "Trust Applet and Add to +// Whitelist". If the user selects Cancel (the default) then a +// generic error code is returned from GCJ_New, telling the browser +// that the applet failed to load. If the user selects "Trust Applet" +// then plugin loading proceeds. If the user selects "Trust Applet +// and Add to Whitelist" then this documentbase is added to the user's +// applet whitelist and plugin loading proceeds. +static bool +plugin_ask_user_about_documentbase (char* documentbase) +{ + GtkWidget* dialog = NULL; + GtkWidget* ok_button = NULL; + GtkWidget* cancel_button = NULL; + GtkWidget* whitelist_button = NULL; + gint dialog_response = GTK_RESPONSE_NONE; + + dialog = gtk_message_dialog_new (NULL, + GTK_DIALOG_MODAL, + GTK_MESSAGE_WARNING, + GTK_BUTTONS_NONE, + SECURITY_WARNING, + documentbase); + gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), + SECURITY_DESCRIPTION, whitelist_filename); + + cancel_button = gtk_dialog_add_button (GTK_DIALOG (dialog), + GTK_STOCK_CANCEL, + GTK_RESPONSE_CANCEL); + ok_button = gtk_dialog_add_button (GTK_DIALOG (dialog), + RESPONSE_TRUST_APPLET, + GTK_RESPONSE_OK); + whitelist_button = gtk_dialog_add_button (GTK_DIALOG (dialog), + RESPONSE_TRUST_APPLET_ADD_TO_LIST, + GTK_RESPONSE_APPLY); + gtk_widget_grab_focus (cancel_button); + + gtk_widget_show_all (dialog); + dialog_response = gtk_dialog_run (GTK_DIALOG (dialog)); + gtk_widget_destroy (dialog); + if (dialog_response == GTK_RESPONSE_CANCEL) + { + // The user does not trust this documentbase. + return false; + } + else if (dialog_response == GTK_RESPONSE_APPLY) + { + // The user wants this documentbase added to his documentbase + // whitelist. + plugin_add_documentbase_to_whitelist (documentbase); + } + // The user trusts this documentbase. + return true; +} + // plugin_in_pipe_callback is called when data is available on the // input pipe, or when the appletviewer crashes or is killed. It may // be called after data has been destroyed in which case it simply @@ -858,7 +1124,6 @@ plugin_in_pipe_callback (GIOChannel* source, if (condition & G_IO_IN) { - GError* channel_error = NULL; gchar* message = NULL; if (g_io_channel_read_line (data->in_from_appletviewer, @@ -866,8 +1131,15 @@ plugin_in_pipe_callback (GIOChannel* source, &channel_error) != G_IO_STATUS_NORMAL) { - PLUGIN_ERROR_TWO ("Failed to read line from input channel", - channel_error->message); + if (channel_error) + { + PLUGIN_ERROR_TWO ("Failed to read line from input channel", + channel_error->message); + g_error_free (channel_error); + channel_error = NULL; + } + else + PLUGIN_ERROR ("Failed to read line from input channel"); } else { @@ -899,12 +1171,6 @@ plugin_in_pipe_callback (GIOChannel* source, g_print (" PIPE: plugin read %s\n", message); } - if (channel_error) - { - g_error_free (channel_error); - channel_error = NULL; - } - g_free (message); message = NULL; @@ -958,14 +1224,14 @@ plugin_out_pipe_callback (GIOChannel* source, return FALSE; } -static void +static NPError plugin_start_appletviewer (GCJPluginData* data) { PLUGIN_DEBUG ("plugin_start_appletviewer"); - + NPError error = NPERR_NO_ERROR; + if (!data->appletviewer_alive) { - GError* spawn_error = NULL; gchar* command_line[3] = { NULL, NULL, NULL }; command_line[0] = g_strdup (APPLETVIEWER_EXECUTABLE); @@ -977,25 +1243,32 @@ plugin_start_appletviewer (GCJPluginData* data) command_line[2] = NULL; if (!g_spawn_async (NULL, command_line, NULL, (GSpawnFlags) 0, - NULL, NULL, NULL, &spawn_error)) + NULL, NULL, NULL, &channel_error)) { - PLUGIN_ERROR_TWO ("Failed to spawn applet viewer", - spawn_error->message); + if (channel_error) + { + PLUGIN_ERROR_TWO ("Failed to spawn applet viewer", + channel_error->message); + g_error_free (channel_error); + channel_error = NULL; + } + else + PLUGIN_ERROR ("Failed to spawn applet viewer"); + error = NPERR_GENERIC_ERROR; goto cleanup; } cleanup: g_free (command_line[0]); + command_line[0] = NULL; g_free (command_line[1]); + command_line[1] = NULL; g_free (command_line[2]); - if (spawn_error) - { - g_error_free (spawn_error); - spawn_error = NULL; - } + command_line[2] = NULL; } PLUGIN_DEBUG ("plugin_start_appletviewer return"); + return error; } // Build up the applet tag string that we'll send to the applet @@ -1015,30 +1288,35 @@ plugin_create_applet_tag (int16 argc, char* argn[], char* argv[]) gchar* code = g_strdup_printf ("CODE=\"%s\" ", argv[i]); applet_tag = g_strconcat (applet_tag, code, NULL); g_free (code); + code = NULL; } else if (!g_ascii_strcasecmp (argn[i], "codebase")) { gchar* codebase = g_strdup_printf ("CODEBASE=\"%s\" ", argv[i]); applet_tag = g_strconcat (applet_tag, codebase, NULL); g_free (codebase); + codebase = NULL; } else if (!g_ascii_strcasecmp (argn[i], "archive")) { gchar* archive = g_strdup_printf ("ARCHIVE=\"%s\" ", argv[i]); applet_tag = g_strconcat (applet_tag, archive, NULL); g_free (archive); + archive = NULL; } else if (!g_ascii_strcasecmp (argn[i], "width")) { gchar* width = g_strdup_printf ("WIDTH=\"%s\" ", argv[i]); applet_tag = g_strconcat (applet_tag, width, NULL); g_free (width); + width = NULL; } else if (!g_ascii_strcasecmp (argn[i], "height")) { gchar* height = g_strdup_printf ("HEIGHT=\"%s\" ", argv[i]); applet_tag = g_strconcat (applet_tag, height, NULL); g_free (height); + height = NULL; } else { @@ -1046,10 +1324,14 @@ plugin_create_applet_tag (int16 argc, char* argn[], char* argv[]) // characters will pass through the pipe. if (argv[i] != '\0') { - gchar* escaped = g_strescape (argv[i], NULL); + gchar* escaped = NULL; + + escaped = g_strescape (argv[i], NULL); parameters = g_strconcat (parameters, "<PARAM NAME=\"", argn[i], "\" VALUE=\"", escaped, "\">", NULL); + g_free (escaped); + escaped = NULL; } } } @@ -1073,7 +1355,6 @@ plugin_send_message_to_appletviewer (GCJPluginData* data, gchar const* message) if (data->appletviewer_alive) { - GError* channel_error = NULL; gchar* newline_message = NULL; gsize bytes_written = 0; @@ -1086,27 +1367,34 @@ plugin_send_message_to_appletviewer (GCJPluginData* data, gchar const* message) if (g_io_channel_write_chars (data->out_to_appletviewer, newline_message, -1, &bytes_written, &channel_error) - != G_IO_STATUS_NORMAL) - PLUGIN_ERROR_TWO ("Failed to write bytes to output channel", - channel_error->message); - - if (channel_error) + != G_IO_STATUS_NORMAL) { - g_error_free (channel_error); - channel_error = NULL; - } + if (channel_error) + { + PLUGIN_ERROR_TWO ("Failed to write bytes to output channel", + channel_error->message); + g_error_free (channel_error); + channel_error = NULL; + } + else + PLUGIN_ERROR ("Failed to write bytes to output channel"); + } if (g_io_channel_flush (data->out_to_appletviewer, &channel_error) != G_IO_STATUS_NORMAL) - PLUGIN_ERROR_TWO ("Failed to flush bytes to output channel", - channel_error->message); - - if (channel_error) { - g_error_free (channel_error); - channel_error = NULL; + if (channel_error) + { + PLUGIN_ERROR_TWO ("Failed to flush bytes to output channel", + channel_error->message); + g_error_free (channel_error); + channel_error = NULL; + } + else + PLUGIN_ERROR ("Failed to flush bytes to output channel"); } g_free (newline_message); + newline_message = NULL; g_print (" PIPE: plugin wrote %s\n", message); } @@ -1135,7 +1423,6 @@ plugin_stop_appletviewer (GCJPluginData* data) if (data->appletviewer_alive) { // Shut down the appletviewer. - GError* channel_error = NULL; gsize bytes_written = 0; if (data->out_to_appletviewer) @@ -1143,36 +1430,45 @@ plugin_stop_appletviewer (GCJPluginData* data) if (g_io_channel_write_chars (data->out_to_appletviewer, "shutdown", -1, &bytes_written, &channel_error) != G_IO_STATUS_NORMAL) - PLUGIN_ERROR_TWO ("Failed to write shutdown message to" - " appletviewer", channel_error->message); - - if (channel_error) { - g_error_free (channel_error); - channel_error = NULL; + if (channel_error) + { + PLUGIN_ERROR_TWO ("Failed to write shutdown message to" + " appletviewer", channel_error->message); + g_error_free (channel_error); + channel_error = NULL; + } + else + PLUGIN_ERROR ("Failed to write shutdown message to"); } if (g_io_channel_flush (data->out_to_appletviewer, &channel_error) != G_IO_STATUS_NORMAL) - PLUGIN_ERROR_TWO ("Failed to write shutdown message to" - " appletviewer", channel_error->message); - - if (channel_error) { - g_error_free (channel_error); - channel_error = NULL; + if (channel_error) + { + PLUGIN_ERROR_TWO ("Failed to write shutdown message to" + " appletviewer", channel_error->message); + g_error_free (channel_error); + channel_error = NULL; + } + else + PLUGIN_ERROR ("Failed to write shutdown message to"); } if (g_io_channel_shutdown (data->out_to_appletviewer, TRUE, &channel_error) != G_IO_STATUS_NORMAL) - PLUGIN_ERROR_TWO ("Failed to shut down appletviewer" - " output channel", channel_error->message); - - if (channel_error) { - g_error_free (channel_error); - channel_error = NULL; + if (channel_error) + { + PLUGIN_ERROR_TWO ("Failed to shut down appletviewer" + " output channel", channel_error->message); + g_error_free (channel_error); + channel_error = NULL; + } + else + PLUGIN_ERROR ("Failed to shut down appletviewer"); } } @@ -1181,13 +1477,16 @@ plugin_stop_appletviewer (GCJPluginData* data) if (g_io_channel_shutdown (data->in_from_appletviewer, TRUE, &channel_error) != G_IO_STATUS_NORMAL) - PLUGIN_ERROR_TWO ("Failed to shut down appletviewer" - " input channel", channel_error->message); - - if (channel_error) { - g_error_free (channel_error); - channel_error = NULL; + if (channel_error) + { + PLUGIN_ERROR_TWO ("Failed to shut down appletviewer" + " input channel", channel_error->message); + g_error_free (channel_error); + channel_error = NULL; + } + else + PLUGIN_ERROR ("Failed to shut down appletviewer"); } } } @@ -1267,18 +1566,25 @@ plugin_data_destroy (GCJPluginData** data) // implement and initializes a local table with browser functions that // we may wish to call. Called once, after browser startup and before // the first plugin instance is created. +// The field 'initialized' is set to true once this function has +// finished. If 'initialized' is already true at the beginning of +// this function, then it is evident that NP_Initialize has already +// been called. There is no need to call this function more than once and +// this workaround avoids any duplicate calls. NPError NP_Initialize (NPNetscapeFuncs* browserTable, NPPluginFuncs* pluginTable) { PLUGIN_DEBUG ("NP_Initialize"); - - if ((browserTable == NULL) || (pluginTable == NULL)) + + if (initialized) + return NPERR_NO_ERROR; + else if ((browserTable == NULL) || (pluginTable == NULL)) { PLUGIN_ERROR ("Browser or plugin function table is NULL."); return NPERR_INVALID_FUNCTABLE_ERROR; } - + // Ensure that the major version of the plugin API that the browser // expects is not more recent than the major version of the API that // we've implemented. @@ -1307,6 +1613,45 @@ NP_Initialize (NPNetscapeFuncs* browserTable, NPPluginFuncs* pluginTable) return NPERR_INVALID_FUNCTABLE_ERROR; } + data_directory = g_strconcat(getenv("HOME"), "/.gcjwebplugin", NULL); + whitelist_filename = g_strconcat (data_directory, "/whitelist.txt", NULL); + // Make sure the plugin data directory exists, creating it if + // necessary. + if (!g_file_test (data_directory, + (GFileTest) (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) + { + int file_error = 0; + + file_error = g_mkdir (data_directory, 0700); + if (file_error != 0) + { + PLUGIN_ERROR_THREE ("Failed to create data directory", + data_directory, + strerror (errno)); + return NPERR_GENERIC_ERROR; + } + } + + // Open the user's documentbase whitelist. + whitelist_file = g_io_channel_new_file (whitelist_filename, + "a+", &channel_error); + if (!whitelist_file) + { + if (channel_error) + { + PLUGIN_ERROR_THREE ("Failed to open whitelist file", + whitelist_filename, + channel_error->message); + g_error_free (channel_error); + channel_error = NULL; + } + else + PLUGIN_ERROR_TWO ("Failed to open whitelist file", + whitelist_filename); + + return NPERR_GENERIC_ERROR; + } + // Store in a local table the browser functions that we may use. browserFunctions.version = browserTable->version; browserFunctions.size = browserTable->size; @@ -1339,7 +1684,8 @@ NP_Initialize (NPNetscapeFuncs* browserTable, NPPluginFuncs* pluginTable) pluginTable->print = NewNPP_PrintProc (GCJ_Print); pluginTable->urlnotify = NewNPP_URLNotifyProc (GCJ_URLNotify); pluginTable->getvalue = NewNPP_GetValueProc (GCJ_GetValue); - + + initialized = true; plugin_instance_mutex = g_mutex_new (); PLUGIN_DEBUG ("NP_Initialize: using " APPLETVIEWER_EXECUTABLE "."); @@ -1402,9 +1748,32 @@ NP_Shutdown (void) PLUGIN_DEBUG ("NP_Shutdown"); // Free mutex. - g_mutex_free (plugin_instance_mutex); - plugin_instance_mutex = NULL; + if (plugin_instance_mutex) + { + g_mutex_free (plugin_instance_mutex); + plugin_instance_mutex = NULL; + } + if (whitelist_file) + { + g_io_channel_close (whitelist_file); + whitelist_file = NULL; + } + + if (data_directory) + { + g_free (data_directory); + data_directory = NULL; + } + + if (whitelist_filename) + { + g_free (whitelist_filename); + whitelist_filename = NULL; + } + + initialized = false; + PLUGIN_DEBUG ("NP_Shutdown return"); return NPERR_NO_ERROR; |