1
/* IcedTeaNPPlugin.cc -- web browser plugin to execute Java applets
2
Copyright (C) 2003, 2004, 2006, 2007 Free Software Foundation, Inc.
3
Copyright (C) 2009, 2010 Red Hat
5
This file is part of GNU Classpath.
7
GNU Classpath is free software; you can redistribute it and/or modify
8
it under the terms of the GNU General Public License as published by
9
the Free Software Foundation; either version 2, or (at your option)
12
GNU Classpath is distributed in the hope that it will be useful, but
13
WITHOUT ANY WARRANTY; without even the implied warranty of
14
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15
General Public License for more details.
17
You should have received a copy of the GNU General Public License
18
along with GNU Classpath; see the file COPYING. If not, write to the
19
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
22
Linking this library statically or dynamically with other modules is
23
making a combined work based on this library. Thus, the terms and
24
conditions of the GNU General Public License cover the whole
27
As a special exception, the copyright holders of this library give you
28
permission to link this library with independent modules to produce an
29
executable, regardless of the license terms of these independent
30
modules, and to copy and distribute the resulting executable under
31
terms of your choice, provided that you also meet, for each linked
32
independent module, the terms and conditions of the license of that
33
module. An independent module is a module which is not derived from
34
or based on this library. If you modify this library, you may extend
35
this exception to your version of the library, but you are not
36
obligated to do so. If you do not wish to do so, delete this
37
exception statement from your version. */
47
#include <sys/types.h>
50
// Liveconnect extension
51
#include "IcedTeaScriptablePluginObject.h"
52
#include "IcedTeaNPPlugin.h"
54
#if MOZILLA_VERSION_COLLAPSED < 1090100
55
// Documentbase retrieval includes.
56
#include <nsIPluginInstance.h>
57
#include <nsIPluginInstancePeer.h>
58
#include <nsIPluginTagInfo2.h>
62
#include <nsICookieService.h>
63
#include <nsIDNSRecord.h>
64
#include <nsIDNSService.h>
65
#include <nsINetUtil.h>
66
#include <nsIProxyInfo.h>
67
#include <nsIProtocolProxyService.h>
68
#include <nsIScriptSecurityManager.h>
69
#include <nsIIOService.h>
72
#include <nsStringAPI.h>
73
#include <nsServiceManagerUtils.h>
76
// Error reporting macros.
77
#define PLUGIN_ERROR(message) \
78
g_printerr ("%s:%d: thread %p: Error: %s\n", __FILE__, __LINE__, \
79
g_thread_self (), message)
81
#define PLUGIN_ERROR_TWO(first, second) \
82
g_printerr ("%s:%d: thread %p: Error: %s: %s\n", __FILE__, __LINE__, \
83
g_thread_self (), first, second)
85
#define PLUGIN_ERROR_THREE(first, second, third) \
86
g_printerr ("%s:%d: thread %p: Error: %s: %s: %s\n", __FILE__, \
87
__LINE__, g_thread_self (), first, second, third)
89
// Plugin information passed to about:plugins.
90
#define PLUGIN_FULL_NAME PLUGIN_NAME " (using " PLUGIN_VERSION ")"
91
#define PLUGIN_DESC "The <a href=\"" PACKAGE_URL "\">" PLUGIN_NAME "</a> executes Java applets."
94
#define JPI_VERSION "1.7.0_" JDK_UPDATE_VERSION
95
#define PLUGIN_APPLET_MIME_DESC7 \
96
"application/x-java-applet;version=1.7:class,jar:IcedTea;"
97
#define PLUGIN_BEAN_MIME_DESC7 \
98
"application/x-java-bean;version=1.7:class,jar:IcedTea;"
100
#define JPI_VERSION "1.6.0_" JDK_UPDATE_VERSION
101
#define PLUGIN_APPLET_MIME_DESC7
102
#define PLUGIN_BEAN_MIME_DESC7
105
#define PLUGIN_MIME_DESC \
106
"application/x-java-vm:class,jar:IcedTea;" \
107
"application/x-java-applet:class,jar:IcedTea;" \
108
"application/x-java-applet;version=1.1:class,jar:IcedTea;" \
109
"application/x-java-applet;version=1.1.1:class,jar:IcedTea;" \
110
"application/x-java-applet;version=1.1.2:class,jar:IcedTea;" \
111
"application/x-java-applet;version=1.1.3:class,jar:IcedTea;" \
112
"application/x-java-applet;version=1.2:class,jar:IcedTea;" \
113
"application/x-java-applet;version=1.2.1:class,jar:IcedTea;" \
114
"application/x-java-applet;version=1.2.2:class,jar:IcedTea;" \
115
"application/x-java-applet;version=1.3:class,jar:IcedTea;" \
116
"application/x-java-applet;version=1.3.1:class,jar:IcedTea;" \
117
"application/x-java-applet;version=1.4:class,jar:IcedTea;" \
118
"application/x-java-applet;version=1.4.1:class,jar:IcedTea;" \
119
"application/x-java-applet;version=1.4.2:class,jar:IcedTea;" \
120
"application/x-java-applet;version=1.5:class,jar:IcedTea;" \
121
"application/x-java-applet;version=1.6:class,jar:IcedTea;" \
122
PLUGIN_APPLET_MIME_DESC7 \
123
"application/x-java-applet;jpi-version=" JPI_VERSION ":class,jar:IcedTea;" \
124
"application/x-java-bean:class,jar:IcedTea;" \
125
"application/x-java-bean;version=1.1:class,jar:IcedTea;" \
126
"application/x-java-bean;version=1.1.1:class,jar:IcedTea;" \
127
"application/x-java-bean;version=1.1.2:class,jar:IcedTea;" \
128
"application/x-java-bean;version=1.1.3:class,jar:IcedTea;" \
129
"application/x-java-bean;version=1.2:class,jar:IcedTea;" \
130
"application/x-java-bean;version=1.2.1:class,jar:IcedTea;" \
131
"application/x-java-bean;version=1.2.2:class,jar:IcedTea;" \
132
"application/x-java-bean;version=1.3:class,jar:IcedTea;" \
133
"application/x-java-bean;version=1.3.1:class,jar:IcedTea;" \
134
"application/x-java-bean;version=1.4:class,jar:IcedTea;" \
135
"application/x-java-bean;version=1.4.1:class,jar:IcedTea;" \
136
"application/x-java-bean;version=1.4.2:class,jar:IcedTea;" \
137
"application/x-java-bean;version=1.5:class,jar:IcedTea;" \
138
"application/x-java-bean;version=1.6:class,jar:IcedTea;" \
139
PLUGIN_BEAN_MIME_DESC7 \
140
"application/x-java-bean;jpi-version=" JPI_VERSION ":class,jar:IcedTea;" \
141
"application/x-java-vm-npruntime::IcedTea;"
143
#define PLUGIN_URL NS_INLINE_PLUGIN_CONTRACTID_PREFIX NS_JVM_MIME_TYPE
144
#define PLUGIN_MIME_TYPE "application/x-java-vm"
145
#define PLUGIN_FILE_EXTS "class,jar,zip"
146
#define PLUGIN_MIME_COUNT 1
148
#define FAILURE_MESSAGE "icedteanp plugin error: Failed to run %s." \
149
" For more detail rerun \"firefox -g\" in a terminal window."
151
#if MOZILLA_VERSION_COLLAPSED < 1090100
152
// Documentbase retrieval required definition.
153
static NS_DEFINE_IID (kIPluginTagInfo2IID, NS_IPLUGINTAGINFO2_IID);
156
// Data directory for plugin.
157
static gchar* data_directory = NULL;
159
// Fully-qualified appletviewer executable.
160
static gchar* appletviewer_executable = NULL;
162
// Applet viewer input channel (needs to be static because it is used in plugin_in_pipe_callback)
163
static GIOChannel* in_from_appletviewer = NULL;
165
// Applet viewer input pipe name.
168
// Applet viewer input watch source.
169
gint in_watch_source;
171
// Applet viewer output pipe name.
172
gchar* out_pipe_name;
174
// Applet viewer output watch source.
175
gint out_watch_source;
177
// Thread ID of plug-in thread
178
pthread_t itnp_plugin_thread_id;
180
// Mutex to lock async call queue
181
pthread_mutex_t pluginAsyncCallMutex;
183
// Applet viewer output channel.
184
GIOChannel* out_to_appletviewer;
187
gboolean jvm_up = FALSE;
189
// Keeps track of initialization. NP_Initialize should only be
191
gboolean initialized = false;
193
// browser functions into mozilla
194
NPNetscapeFuncs browser_functions;
196
// Various message buses carrying information to/from Java, and internally
197
MessageBus* plugin_to_java_bus;
198
MessageBus* java_to_plugin_bus;
199
//MessageBus* internal_bus = new MessageBus();
201
// Processor for plugin requests
202
PluginRequestProcessor* plugin_req_proc;
204
// Sends messages to Java over the bus
205
JavaMessageSender* java_req_proc;
207
#if MOZILLA_VERSION_COLLAPSED < 1090100
208
// Documentbase retrieval type-punning union.
212
nsIPluginTagInfo2** info_field;
216
// Static instance helper functions.
217
// Have the browser allocate a new ITNPPluginData structure.
218
static void plugin_data_new (ITNPPluginData** data);
219
// Retrieve the current document's documentbase.
220
static gchar* plugin_get_documentbase (NPP instance);
221
// Notify the user that the appletviewer is not installed correctly.
222
static void plugin_display_failure_dialog ();
223
// Callback used to monitor input pipe status.
224
static gboolean plugin_in_pipe_callback (GIOChannel* source,
225
GIOCondition condition,
226
gpointer plugin_data);
227
// Callback used to monitor output pipe status.
228
static gboolean plugin_out_pipe_callback (GIOChannel* source,
229
GIOCondition condition,
230
gpointer plugin_data);
231
static NPError plugin_start_appletviewer (ITNPPluginData* data);
232
static gchar* plugin_create_applet_tag (int16_t argc, char* argn[],
234
static void plugin_stop_appletviewer ();
235
// Uninitialize ITNPPluginData structure
236
static void plugin_data_destroy (NPP instance);
238
NPError get_cookie_info(const char* siteAddr, char** cookieString, uint32_t* len);
239
NPError get_proxy_info(const char* siteAddr, char** proxy, uint32_t* len);
240
void consume_message(gchar* message);
241
void start_jvm_if_needed();
242
static void appletviewer_monitor(GPid pid, gint status, gpointer data);
243
void plugin_send_initialization_message(char* instance, gulong handle,
244
int width, int height,
247
// Global instance counter.
248
// Mutex to protect plugin_instance_counter.
249
static GMutex* plugin_instance_mutex = NULL;
250
// A global variable for reporting GLib errors. This must be free'd
251
// and set to NULL after each use.
252
static GError* channel_error = NULL;
254
static GHashTable* instance_to_id_map = g_hash_table_new(NULL, NULL);
255
static GHashTable* id_to_instance_map = g_hash_table_new(NULL, NULL);
256
static gint instance_counter = 1;
257
static GPid appletviewer_pid = -1;
258
static guint appletviewer_watch_id = -1;
260
int plugin_debug = getenv ("ICEDTEAPLUGIN_DEBUG") != NULL;
261
int plugin_debug_suspend = (getenv("ICEDTEAPLUGIN_DEBUG") != NULL) &&
262
(strcmp(getenv("ICEDTEAPLUGIN_DEBUG"), "suspend") == 0);
264
pthread_cond_t cond_message_available = PTHREAD_COND_INITIALIZER;
268
// Returns key from first item stored in hashtable
270
find_first_item_in_hash_table(gpointer key, gpointer value, gpointer user_data)
273
return (gboolean)TRUE;
277
g_strcmp0(char *str1, char *str2)
280
return str2 != NULL ? strcmp(str1, str2) : 1;
282
return str2 != NULL ? 1 : 0;
290
* Find first member in GHashTable* depending on version of glib
292
gpointer getFirstInTableInstance(GHashTable* table)
294
gpointer id, instance;
297
g_hash_table_iter_init (&iter, table);
298
g_hash_table_iter_next (&iter, &instance, &id);
300
g_hash_table_find(table, (GHRFunc)find_first_item_in_hash_table, &instance);
305
// Functions prefixed by ITNP_ are instance functions. They are called
306
// by the browser and operate on instances of ITNPPluginData.
307
// Functions prefixed by plugin_ are static helper functions.
308
// Functions prefixed by NP_ are factory functions. They are called
309
// by the browser and provide functionality needed to create plugin
312
// INSTANCE FUNCTIONS
314
// Creates a new icedtea np plugin instance. This function creates a
315
// ITNPPluginData* and stores it in instance->pdata. The following
316
// ITNPPluginData fiels are initialized: instance_id, in_pipe_name,
317
// in_from_appletviewer, in_watch_source, out_pipe_name,
318
// out_to_appletviewer, out_watch_source, appletviewer_mutex, owner,
319
// appletviewer_alive. In addition two pipe files are created. All
320
// of those fields must be properly destroyed, and the pipes deleted,
321
// by ITNP_Destroy. If an error occurs during initialization then this
322
// function will free anything that's been allocated so far, set
323
// instance->pdata to NULL and return an error code.
325
ITNP_New (NPMIMEType pluginType, NPP instance, uint16_t mode,
326
int16_t argc, char* argn[], char* argv[],
329
PLUGIN_DEBUG("ITNP_New\n");
331
static NPObject *window_ptr;
332
NPIdentifier identifier;
333
NPVariant member_ptr;
334
browser_functions.getvalue(instance, NPNVWindowNPObject, &window_ptr);
335
identifier = browser_functions.getstringidentifier("document");
336
if (!browser_functions.hasproperty(instance, window_ptr, identifier))
338
printf("%s not found!\n", "document");
340
browser_functions.getproperty(instance, window_ptr, identifier, &member_ptr);
342
PLUGIN_DEBUG("Got variant %p\n", &member_ptr);
345
NPError np_error = NPERR_NO_ERROR;
346
ITNPPluginData* data = NULL;
348
gchar* documentbase = NULL;
349
gchar* read_message = NULL;
350
gchar* applet_tag = NULL;
351
gchar* cookie_info = NULL;
353
NPObject* npPluginObj = NULL;
357
PLUGIN_ERROR ("Browser-provided instance pointer is NULL.");
358
np_error = NPERR_INVALID_INSTANCE_ERROR;
363
plugin_data_new (&data);
366
PLUGIN_ERROR ("Failed to allocate plugin data.");
367
np_error = NPERR_OUT_OF_MEMORY_ERROR;
371
// start the jvm if needed
372
start_jvm_if_needed();
374
// Initialize data->instance_id.
376
// instance_id should be unique for this process so we use a
377
// combination of getpid and plugin_instance_counter.
379
// Critical region. Reference and increment plugin_instance_counter
381
g_mutex_lock (plugin_instance_mutex);
384
data->instance_id = g_strdup_printf ("%d",
387
g_mutex_unlock (plugin_instance_mutex);
389
// data->appletviewer_mutex
390
data->appletviewer_mutex = g_mutex_new ();
392
g_mutex_lock (data->appletviewer_mutex);
394
// Documentbase retrieval.
395
documentbase = plugin_get_documentbase (instance);
396
if (documentbase && argc != 0)
398
// Send applet tag message to appletviewer.
399
applet_tag = plugin_create_applet_tag (argc, argn, argv);
401
data->applet_tag = (gchar*) malloc(strlen(applet_tag)*sizeof(gchar) + strlen(documentbase)*sizeof(gchar) + 32);
402
g_sprintf(data->applet_tag, "tag %s %s", documentbase, applet_tag);
404
data->is_applet_instance = true;
409
data->is_applet_instance = false;
412
g_mutex_unlock (data->appletviewer_mutex);
414
// If initialization succeeded entirely then we store the plugin
415
// data in the instance structure and return. Otherwise we free the
416
// data we've allocated so far and set instance->pdata to NULL.
418
// Set back-pointer to owner instance.
419
data->owner = instance;
421
// source of this instance
422
// don't use documentbase, it is cleared later
423
data->source = plugin_get_documentbase(instance);
425
instance->pdata = data;
429
cleanup_appletviewer_mutex:
430
g_free (data->appletviewer_mutex);
431
data->appletviewer_mutex = NULL;
433
// cleanup_instance_string:
434
g_free (data->instance_id);
435
data->instance_id = NULL;
437
// cleanup applet tag:
438
g_free (data->applet_tag);
439
data->applet_tag = NULL;
442
// Eliminate back-pointer to plugin instance.
444
(*browser_functions.memfree) (data);
447
// Initialization failed so return a NULL pointer for the browser
449
instance->pdata = NULL;
454
g_free (read_message);
456
g_free (documentbase);
459
// store an identifier for this plugin
460
PLUGIN_DEBUG("Mapping id %d and instance %p\n", instance_counter, instance);
461
g_hash_table_insert(instance_to_id_map, instance, GINT_TO_POINTER(instance_counter));
462
g_hash_table_insert(id_to_instance_map, GINT_TO_POINTER(instance_counter), instance);
465
PLUGIN_DEBUG ("ITNP_New return\n");
470
// Starts the JVM if it is not already running
471
void start_jvm_if_needed()
474
// This is asynchronized function. It must
475
// have exclusivity when running.
477
GMutex *vm_start_mutex = g_mutex_new();
478
g_mutex_lock(vm_start_mutex);
480
PLUGIN_DEBUG("Checking JVM status...\n");
482
// If the jvm is already up, do nothing
485
PLUGIN_DEBUG("JVM is up. Returning.\n");
489
PLUGIN_DEBUG("No JVM is running. Attempting to start one...\n");
491
NPError np_error = NPERR_NO_ERROR;
492
ITNPPluginData* data = NULL;
494
// Create appletviewer-to-plugin pipe which we refer to as the input
498
in_pipe_name = g_strdup_printf ("%s/%d-icedteanp-appletviewer-to-plugin",
499
data_directory, getpid());
502
PLUGIN_ERROR ("Failed to create input pipe name.");
503
np_error = NPERR_OUT_OF_MEMORY_ERROR;
504
// If in_pipe_name is NULL then the g_free at
505
// cleanup_in_pipe_name will simply return.
506
goto cleanup_in_pipe_name;
509
// clean up any older pip
510
unlink (in_pipe_name);
512
PLUGIN_DEBUG ("ITNP_New: creating input fifo: %s\n", in_pipe_name);
513
if (mkfifo (in_pipe_name, 0600) == -1 && errno != EEXIST)
515
PLUGIN_ERROR_TWO ("Failed to create input pipe", strerror (errno));
516
np_error = NPERR_GENERIC_ERROR;
517
goto cleanup_in_pipe_name;
519
PLUGIN_DEBUG ("ITNP_New: created input fifo: %s\n", in_pipe_name);
521
// Create plugin-to-appletviewer pipe which we refer to as the
525
out_pipe_name = g_strdup_printf ("%s/%d-icedteanp-plugin-to-appletviewer",
526
data_directory, getpid());
530
PLUGIN_ERROR ("Failed to create output pipe name.");
531
np_error = NPERR_OUT_OF_MEMORY_ERROR;
532
goto cleanup_out_pipe_name;
535
// clean up any older pip
536
unlink (out_pipe_name);
538
PLUGIN_DEBUG ("ITNP_New: creating output fifo: %s\n", out_pipe_name);
539
if (mkfifo (out_pipe_name, 0600) == -1 && errno != EEXIST)
541
PLUGIN_ERROR_TWO ("Failed to create output pipe", strerror (errno));
542
np_error = NPERR_GENERIC_ERROR;
543
goto cleanup_out_pipe_name;
545
PLUGIN_DEBUG ("ITNP_New: created output fifo: %s\n", out_pipe_name);
547
// Start a separate appletviewer process for each applet, even if
548
// there are multiple applets in the same page. We may need to
549
// change this behaviour if we find pages with multiple applets that
550
// rely on being run in the same VM.
552
np_error = plugin_start_appletviewer (data);
554
// Create plugin-to-appletviewer channel. The default encoding for
555
// the file is UTF-8.
556
// out_to_appletviewer
557
out_to_appletviewer = g_io_channel_new_file (out_pipe_name,
558
"w", &channel_error);
559
if (!out_to_appletviewer)
563
PLUGIN_ERROR_TWO ("Failed to create output channel",
564
channel_error->message);
565
g_error_free (channel_error);
566
channel_error = NULL;
569
PLUGIN_ERROR ("Failed to create output channel");
571
np_error = NPERR_GENERIC_ERROR;
572
goto cleanup_out_to_appletviewer;
575
// Watch for hangup and error signals on the output pipe.
577
g_io_add_watch (out_to_appletviewer,
578
(GIOCondition) (G_IO_ERR | G_IO_HUP),
579
plugin_out_pipe_callback, (gpointer) out_to_appletviewer);
581
// Create appletviewer-to-plugin channel. The default encoding for
582
// the file is UTF-8.
583
// in_from_appletviewer
584
in_from_appletviewer = g_io_channel_new_file (in_pipe_name,
585
"r", &channel_error);
586
if (!in_from_appletviewer)
590
PLUGIN_ERROR_TWO ("Failed to create input channel",
591
channel_error->message);
592
g_error_free (channel_error);
593
channel_error = NULL;
596
PLUGIN_ERROR ("Failed to create input channel");
598
np_error = NPERR_GENERIC_ERROR;
599
goto cleanup_in_from_appletviewer;
602
// Watch for hangup and error signals on the input pipe.
604
g_io_add_watch (in_from_appletviewer,
605
(GIOCondition) (G_IO_IN | G_IO_ERR | G_IO_HUP),
606
plugin_in_pipe_callback, (gpointer) in_from_appletviewer);
612
// Free allocated data
614
cleanup_in_watch_source:
615
// Removing a source is harmless if it fails since it just means the
616
// source has already been removed.
617
g_source_remove (in_watch_source);
620
cleanup_in_from_appletviewer:
621
if (in_from_appletviewer)
622
g_io_channel_unref (in_from_appletviewer);
623
in_from_appletviewer = NULL;
625
// cleanup_out_watch_source:
626
g_source_remove (out_watch_source);
627
out_watch_source = 0;
629
cleanup_out_to_appletviewer:
630
if (out_to_appletviewer)
631
g_io_channel_unref (out_to_appletviewer);
632
out_to_appletviewer = NULL;
635
// Delete output pipe.
636
PLUGIN_DEBUG ("ITNP_New: deleting input fifo: %s\n", in_pipe_name);
637
unlink (out_pipe_name);
638
PLUGIN_DEBUG ("ITNP_New: deleted input fifo: %s\n", in_pipe_name);
640
cleanup_out_pipe_name:
641
g_free (out_pipe_name);
642
out_pipe_name = NULL;
645
// Delete input pipe.
646
PLUGIN_DEBUG ("ITNP_New: deleting output fifo: %s\n", out_pipe_name);
647
unlink (in_pipe_name);
648
PLUGIN_DEBUG ("ITNP_New: deleted output fifo: %s\n", out_pipe_name);
650
cleanup_in_pipe_name:
651
g_free (in_pipe_name);
656
// Now other threads may re-enter.. unlock the mutex
657
g_mutex_unlock(vm_start_mutex);
662
ITNP_GetValue (NPP instance, NPPVariable variable, void* value)
664
PLUGIN_DEBUG ("ITNP_GetValue\n");
666
NPError np_error = NPERR_NO_ERROR;
670
// This plugin needs XEmbed support.
671
case NPPVpluginNeedsXEmbed:
673
PLUGIN_DEBUG ("ITNP_GetValue: returning TRUE for NeedsXEmbed.\n");
674
bool* bool_value = (bool*) value;
678
case NPPVpluginScriptableNPObject:
680
*(NPObject **)value = get_scriptable_object(instance);
684
PLUGIN_ERROR ("Unknown plugin value requested.");
685
np_error = NPERR_GENERIC_ERROR;
689
PLUGIN_DEBUG ("ITNP_GetValue return\n");
695
ITNP_Destroy (NPP instance, NPSavedData** save)
697
PLUGIN_DEBUG ("ITNP_Destroy %p\n", instance);
699
ITNPPluginData* data = (ITNPPluginData*) instance->pdata;
701
int id = get_id_from_instance(instance);
703
// Let Java know that this applet needs to be destroyed
704
gchar* msg = (gchar*) g_malloc(512*sizeof(gchar)); // 512 is more than enough. We need < 100
705
g_sprintf(msg, "instance %d destroy", id);
706
plugin_send_message_to_appletviewer(msg);
713
plugin_data_destroy (instance);
716
g_hash_table_remove(instance_to_id_map, instance);
717
g_hash_table_remove(id_to_instance_map, GINT_TO_POINTER(id));
719
IcedTeaPluginUtilities::invalidateInstance(instance);
721
PLUGIN_DEBUG ("ITNP_Destroy return\n");
723
return NPERR_NO_ERROR;
727
ITNP_SetWindow (NPP instance, NPWindow* window)
729
PLUGIN_DEBUG ("ITNP_SetWindow\n");
731
if (instance == NULL)
733
PLUGIN_ERROR ("Invalid instance.");
735
return NPERR_INVALID_INSTANCE_ERROR;
738
gpointer id_ptr = g_hash_table_lookup(instance_to_id_map, instance);
743
id = GPOINTER_TO_INT(id_ptr);
746
ITNPPluginData* data = (ITNPPluginData*) instance->pdata;
748
// Simply return if we receive a NULL window.
749
if ((window == NULL) || (window->window == NULL))
751
PLUGIN_DEBUG ("ITNP_SetWindow: got NULL window.\n");
753
return NPERR_NO_ERROR;
756
if (data->window_handle)
758
// The window already exists.
759
if (data->window_handle == window->window)
761
// The parent window is the same as in previous calls.
762
PLUGIN_DEBUG ("ITNP_SetWindow: window already exists.\n");
764
// Critical region. Read data->appletviewer_mutex and send
765
// a message to the appletviewer.
766
g_mutex_lock (data->appletviewer_mutex);
770
gboolean dim_changed = FALSE;
772
// The window is the same as it was for the last
774
if (window->width != data->window_width)
776
PLUGIN_DEBUG ("ITNP_SetWindow: window width changed.\n");
777
// The width of the plugin window has changed.
779
// Store the new width.
780
data->window_width = window->width;
784
if (window->height != data->window_height)
786
PLUGIN_DEBUG ("ITNP_SetWindow: window height changed.\n");
787
// The height of the plugin window has changed.
789
// Store the new height.
790
data->window_height = window->height;
796
gchar* message = g_strdup_printf ("instance %d width %d height %d",
797
id, window->width, window->height);
798
plugin_send_message_to_appletviewer (message);
807
// The appletviewer is not running.
808
PLUGIN_DEBUG ("ITNP_SetWindow: appletviewer is not running.\n");
811
g_mutex_unlock (data->appletviewer_mutex);
815
// The parent window has changed. This branch does run but
816
// doing nothing in response seems to be sufficient.
817
PLUGIN_DEBUG ("ITNP_SetWindow: parent window changed.\n");
823
// Else this is initialization
824
PLUGIN_DEBUG ("ITNP_SetWindow: setting window.\n");
826
// Critical region. Send messages to appletviewer.
827
g_mutex_lock (data->appletviewer_mutex);
829
// Store the window handle and dimensions
830
data->window_handle = window->window;
831
data->window_width = window->width;
832
data->window_height = window->height;
834
// Now we have everything. Send this data to the Java side
835
plugin_send_initialization_message(
836
data->instance_id, (gulong) data->window_handle,
837
data->window_width, data->window_height, data->applet_tag);
839
g_mutex_unlock (data->appletviewer_mutex);
843
PLUGIN_DEBUG ("ITNP_SetWindow return\n");
845
return NPERR_NO_ERROR;
849
ITNP_NewStream (NPP instance, NPMIMEType type, NPStream* stream,
850
NPBool seekable, uint16_t* stype)
852
PLUGIN_DEBUG ("ITNP_NewStream\n");
854
PLUGIN_DEBUG ("ITNP_NewStream return\n");
856
return NPERR_GENERIC_ERROR;
860
ITNP_StreamAsFile (NPP instance, NPStream* stream, const char* filename)
862
PLUGIN_DEBUG ("ITNP_StreamAsFile\n");
864
PLUGIN_DEBUG ("ITNP_StreamAsFile return\n");
868
ITNP_DestroyStream (NPP instance, NPStream* stream, NPReason reason)
870
PLUGIN_DEBUG ("ITNP_DestroyStream\n");
872
PLUGIN_DEBUG ("ITNP_DestroyStream return\n");
874
return NPERR_NO_ERROR;
878
ITNP_WriteReady (NPP instance, NPStream* stream)
880
PLUGIN_DEBUG ("ITNP_WriteReady\n");
882
PLUGIN_DEBUG ("ITNP_WriteReady return\n");
888
ITNP_Write (NPP instance, NPStream* stream, int32_t offset, int32_t len,
891
PLUGIN_DEBUG ("ITNP_Write\n");
893
PLUGIN_DEBUG ("ITNP_Write return\n");
899
ITNP_Print (NPP instance, NPPrint* platformPrint)
901
PLUGIN_DEBUG ("ITNP_Print\n");
903
PLUGIN_DEBUG ("ITNP_Print return\n");
907
ITNP_HandleEvent (NPP instance, void* event)
909
PLUGIN_DEBUG ("ITNP_HandleEvent\n");
911
PLUGIN_DEBUG ("ITNP_HandleEvent return\n");
917
ITNP_URLNotify (NPP instance, const char* url, NPReason reason,
920
PLUGIN_DEBUG ("ITNP_URLNotify\n");
922
PLUGIN_DEBUG ("ITNP_URLNotify return\n");
926
get_cookie_info(const char* siteAddr, char** cookieString, uint32_t* len)
928
#if MOZILLA_VERSION_COLLAPSED < 1090100
930
nsCOMPtr<nsIScriptSecurityManager> sec_man =
931
do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
934
return NPERR_GENERIC_ERROR;
937
nsCOMPtr<nsIIOService> io_svc = do_GetService("@mozilla.org/network/io-service;1", &rv);
939
if (NS_FAILED(rv) || !io_svc) {
940
return NPERR_GENERIC_ERROR;
943
nsCOMPtr<nsIURI> uri;
944
io_svc->NewURI(nsCString(siteAddr), NULL, NULL, getter_AddRefs(uri));
946
nsCOMPtr<nsICookieService> cookie_svc = do_GetService("@mozilla.org/cookieService;1", &rv);
948
if (NS_FAILED(rv) || !cookie_svc) {
949
return NPERR_GENERIC_ERROR;
952
rv = cookie_svc->GetCookieString(uri, NULL, cookieString);
954
if (NS_FAILED(rv) || !*cookieString) {
955
return NPERR_GENERIC_ERROR;
960
// getvalueforurl needs an NPP instance. Quite frankly, there is no easy way
961
// to know which instance needs the information, as applets on Java side can
962
// be multi-threaded and the thread making a proxy.cookie request cannot be
965
// Fortunately, XULRunner does not care about the instance as long as it is
966
// valid. So we just pick the first valid one and use it. Proxy/Cookie
967
// information is not instance specific anyway, it is URL specific.
969
if (browser_functions.getvalueforurl)
971
gpointer instance=getFirstInTableInstance(instance_to_id_map);
972
return browser_functions.getvalueforurl((NPP) instance, NPNURLVCookie, siteAddr, cookieString, len);
975
return NPERR_GENERIC_ERROR;
980
return NPERR_NO_ERROR;
986
plugin_data_new (ITNPPluginData** data)
988
PLUGIN_DEBUG ("plugin_data_new\n");
990
*data = (ITNPPluginData*)
991
(*browser_functions.memalloc) (sizeof (struct ITNPPluginData));
993
// appletviewer_alive is false until the applet viewer is spawned.
995
memset (*data, 0, sizeof (struct ITNPPluginData));
997
PLUGIN_DEBUG ("plugin_data_new return\n");
1002
// Documentbase retrieval. This function gets the current document's
1003
// documentbase. This function relies on browser-private data so it
1004
// will only work when the plugin is loaded in a Mozilla-based
1005
// browser. We could not find a way to retrieve the documentbase
1006
// using the original Netscape plugin API so we use the XPCOM API
1008
#if MOZILLA_VERSION_COLLAPSED < 1090100
1010
plugin_get_documentbase (NPP instance)
1012
PLUGIN_DEBUG ("plugin_get_documentbase\n");
1014
nsIPluginInstance* xpcom_instance = NULL;
1015
nsIPluginInstancePeer* peer = NULL;
1016
nsresult result = 0;
1017
nsIPluginTagInfo2* pluginTagInfo2 = NULL;
1018
info_union u = { NULL };
1019
char const* documentbase = NULL;
1020
gchar* documentbase_copy = NULL;
1022
xpcom_instance = (nsIPluginInstance*) (instance->ndata);
1023
if (!xpcom_instance)
1025
PLUGIN_ERROR ("xpcom_instance is NULL.");
1029
xpcom_instance->GetPeer (&peer);
1032
PLUGIN_ERROR ("peer is NULL.");
1036
u.info_field = &pluginTagInfo2;
1038
result = peer->QueryInterface (kIPluginTagInfo2IID,
1040
if (result || !pluginTagInfo2)
1042
PLUGIN_ERROR ("pluginTagInfo2 retrieval failed.");
1046
pluginTagInfo2->GetDocumentBase (&documentbase);
1050
// NULL => dummy instantiation for LiveConnect
1051
goto cleanup_plugintaginfo2;
1054
documentbase_copy = g_strdup (documentbase);
1056
// Release references.
1057
cleanup_plugintaginfo2:
1058
NS_RELEASE (pluginTagInfo2);
1064
PLUGIN_DEBUG ("plugin_get_documentbase return\n");
1066
PLUGIN_DEBUG("plugin_get_documentbase returning: %s\n", documentbase_copy);
1067
return documentbase_copy;
1071
plugin_get_documentbase (NPP instance)
1073
PLUGIN_DEBUG ("plugin_get_documentbase\n");
1075
char const* documentbase = NULL;
1076
gchar* documentbase_copy = NULL;
1078
// FIXME: This method is not ideal, but there are no known NPAPI call
1079
// for this. See thread for more information:
1080
// http://www.mail-archive.com/chromium-dev@googlegroups.com/msg04844.html
1082
// Additionally, since it is insecure, we cannot use it for making
1083
// security decisions.
1085
browser_functions.getvalue(instance, NPNVWindowNPObject, &window);
1088
NPIdentifier location_id = browser_functions.getstringidentifier("location");
1089
browser_functions.getproperty(instance, window, location_id, &location);
1092
NPIdentifier href_id = browser_functions.getstringidentifier("href");
1093
browser_functions.getproperty(instance, NPVARIANT_TO_OBJECT(location),
1096
// Strip everything after the last "/"
1097
#if MOZILLA_VERSION_COLLAPSED < 1090200
1098
gchar** parts = g_strsplit (NPVARIANT_TO_STRING(href).utf8characters, "/", -1);
1100
gchar** parts = g_strsplit (NPVARIANT_TO_STRING(href).UTF8Characters, "/", -1);
1102
guint parts_sz = g_strv_length (parts);
1104
std::string location_str;
1105
for (int i=0; i < parts_sz - 1; i++)
1107
location_str += parts[i];
1108
location_str += "/";
1111
documentbase_copy = g_strdup (location_str.c_str());
1113
// Release references.
1114
browser_functions.releasevariantvalue(&href);
1115
browser_functions.releasevariantvalue(&location);
1117
PLUGIN_DEBUG ("plugin_get_documentbase return\n");
1118
PLUGIN_DEBUG("plugin_get_documentbase returning: %s\n", documentbase_copy);
1120
return documentbase_copy;
1124
// This function displays an error message if the appletviewer has not
1125
// been installed correctly.
1127
plugin_display_failure_dialog ()
1129
GtkWidget* dialog = NULL;
1131
PLUGIN_DEBUG ("plugin_display_failure_dialog\n");
1133
dialog = gtk_message_dialog_new (NULL,
1134
GTK_DIALOG_DESTROY_WITH_PARENT,
1138
appletviewer_executable);
1139
gtk_widget_show_all (dialog);
1140
gtk_dialog_run (GTK_DIALOG (dialog));
1141
gtk_widget_destroy (dialog);
1143
PLUGIN_DEBUG ("plugin_display_failure_dialog return\n");
1148
// plugin_in_pipe_callback is called when data is available on the
1149
// input pipe, or when the appletviewer crashes or is killed. It may
1150
// be called after data has been destroyed in which case it simply
1151
// returns FALSE to remove itself from the glib main loop.
1153
plugin_in_pipe_callback (GIOChannel* source,
1154
GIOCondition condition,
1155
gpointer plugin_data)
1157
PLUGIN_DEBUG ("plugin_in_pipe_callback\n");
1159
gboolean keep_installed = TRUE;
1161
if (condition & G_IO_IN)
1163
gchar* message = NULL;
1165
if (g_io_channel_read_line (in_from_appletviewer,
1166
&message, NULL, NULL,
1168
!= G_IO_STATUS_NORMAL)
1172
PLUGIN_ERROR_TWO ("Failed to read line from input channel",
1173
channel_error->message);
1174
g_error_free (channel_error);
1175
channel_error = NULL;
1178
PLUGIN_ERROR ("Failed to read line from input channel");
1181
consume_message(message);
1187
keep_installed = TRUE;
1190
if (condition & (G_IO_ERR | G_IO_HUP))
1192
PLUGIN_DEBUG ("appletviewer has stopped.\n");
1193
keep_installed = FALSE;
1196
PLUGIN_DEBUG ("plugin_in_pipe_callback return\n");
1198
return keep_installed;
1201
void consume_message(gchar* message) {
1203
PLUGIN_DEBUG (" PIPE: plugin read: %s\n", message);
1205
if (g_str_has_prefix (message, "instance"))
1208
ITNPPluginData* data;
1209
gchar** parts = g_strsplit (message, " ", -1);
1210
guint parts_sz = g_strv_length (parts);
1212
int instance_id = atoi(parts[1]);
1213
NPP instance = (NPP) g_hash_table_lookup(id_to_instance_map,
1214
GINT_TO_POINTER(instance_id));
1216
if (instance_id > 0 && !instance)
1218
PLUGIN_DEBUG("Instance %d is not active. Refusing to consume message \"%s\"\n", instance_id, message);
1223
data = (ITNPPluginData*) instance->pdata;
1226
if (g_str_has_prefix (parts[2], "status"))
1229
// clear the "instance X status" parts
1230
sprintf(parts[0], "");
1231
sprintf(parts[1], "");
1232
sprintf(parts[2], "");
1235
gchar* status_message = g_strjoinv(" ", parts);
1236
PLUGIN_DEBUG ("plugin_in_pipe_callback: setting status %s\n", status_message);
1237
(*browser_functions.status) (data->owner, status_message);
1239
g_free(status_message);
1240
status_message = NULL;
1242
else if (g_str_has_prefix (parts[1], "internal"))
1248
// All other messages are posted to the bus, and subscribers are
1249
// expected to take care of them. They better!
1251
java_to_plugin_bus->post(message);
1257
else if (g_str_has_prefix (message, "context"))
1259
java_to_plugin_bus->post(message);
1261
else if (g_str_has_prefix (message, "plugin "))
1263
// internal plugin related message
1264
gchar** parts = g_strsplit (message, " ", 5);
1265
if (g_str_has_prefix(parts[1], "PluginProxyInfo"))
1270
gchar* decoded_url = (gchar*) calloc(strlen(parts[4]) + 1, sizeof(gchar));
1271
IcedTeaPluginUtilities::decodeURL(parts[4], &decoded_url);
1272
PLUGIN_DEBUG("parts[0]=%s, parts[1]=%s, reference, parts[3]=%s, parts[4]=%s -- decoded_url=%s\n", parts[0], parts[1], parts[3], parts[4], decoded_url);
1276
#if MOZILLA_VERSION_COLLAPSED < 1090100
1277
proxy = (char*) malloc(sizeof(char)*2048);
1280
proxy_info = g_strconcat ("plugin PluginProxyInfo reference ", parts[3], " ", NULL);
1281
if (get_proxy_info(decoded_url, &proxy, &len) == NPERR_NO_ERROR)
1283
proxy_info = g_strconcat (proxy_info, proxy, NULL);
1286
PLUGIN_DEBUG("Proxy info: %s\n", proxy_info);
1287
plugin_send_message_to_appletviewer(proxy_info);
1289
g_free(decoded_url);
1294
#if MOZILLA_VERSION_COLLAPSED < 1090100
1299
} else if (g_str_has_prefix(parts[1], "PluginCookieInfo"))
1301
gchar* decoded_url = (gchar*) calloc(strlen(parts[4])+1, sizeof(gchar));
1302
IcedTeaPluginUtilities::decodeURL(parts[4], &decoded_url);
1304
gchar* cookie_info = g_strconcat ("plugin PluginCookieInfo reference ", parts[3], " ", NULL);
1305
gchar* cookie_string;
1307
if (get_cookie_info(decoded_url, &cookie_string, &len) == NPERR_NO_ERROR)
1309
cookie_info = g_strconcat (cookie_info, cookie_string, NULL);
1312
PLUGIN_DEBUG("Cookie info: %s\n", cookie_info);
1313
plugin_send_message_to_appletviewer(cookie_info);
1315
g_free(decoded_url);
1317
g_free(cookie_info);
1323
g_print (" Unable to handle message: %s\n", message);
1327
void get_instance_from_id(int id, NPP& instance)
1329
instance = (NPP) g_hash_table_lookup(id_to_instance_map,
1330
GINT_TO_POINTER(id));
1333
int get_id_from_instance(NPP instance)
1335
int id = GPOINTER_TO_INT(g_hash_table_lookup(instance_to_id_map,
1337
PLUGIN_DEBUG("Returning id %d for instance %p\n", id, instance);
1342
get_proxy_info(const char* siteAddr, char** proxy, uint32_t* len)
1344
#if MOZILLA_VERSION_COLLAPSED < 1090100
1347
// Initialize service variables
1348
nsCOMPtr<nsIProtocolProxyService> proxy_svc = do_GetService("@mozilla.org/network/protocol-proxy-service;1", &rv);
1351
printf("Cannot initialize proxy service\n");
1352
return NPERR_GENERIC_ERROR;
1355
nsCOMPtr<nsIIOService> io_svc = do_GetService("@mozilla.org/network/io-service;1", &rv);
1357
if (NS_FAILED(rv) || !io_svc) {
1358
printf("Cannot initialize io service\n");
1359
return NPERR_GENERIC_ERROR;
1362
// uri which needs to be accessed
1363
nsCOMPtr<nsIURI> uri;
1364
io_svc->NewURI(nsCString(siteAddr), NULL, NULL, getter_AddRefs(uri));
1366
// find the proxy address if any
1367
nsCOMPtr<nsIProxyInfo> info;
1368
proxy_svc->Resolve(uri, 0, getter_AddRefs(info));
1370
// if there is no proxy found, return immediately
1372
PLUGIN_DEBUG("%s does not need a proxy\n", siteAddr);
1373
return NPERR_GENERIC_ERROR;
1376
// if proxy info is available, extract it
1381
info->GetHost(phost);
1382
info->GetPort(&pport);
1383
info->GetType(ptype);
1385
// resolve the proxy address to an IP
1386
nsCOMPtr<nsIDNSService> dns_svc = do_GetService("@mozilla.org/network/dns-service;1", &rv);
1389
printf("Cannot initialize DNS service\n");
1390
return NPERR_GENERIC_ERROR;
1393
nsCOMPtr<nsIDNSRecord> record;
1394
dns_svc->Resolve(phost, 0U, getter_AddRefs(record));
1396
// TODO: Add support for multiple ips
1397
nsDependentCString ipAddr;
1398
record->GetNextAddrAsString(ipAddr);
1400
if (!strcmp(ptype.get(), "http"))
1402
snprintf(*proxy, sizeof(char)*1024, "%s %s:%d", "PROXY", ipAddr.get(), pport);
1405
snprintf(*proxy, sizeof(char)*1024, "%s %s:%d", "SOCKS", ipAddr.get(), pport);
1408
*len = strlen(*proxy);
1410
PLUGIN_DEBUG("Proxy info for %s: %s\n", siteAddr, *proxy);
1414
if (browser_functions.getvalueforurl)
1417
// As in get_cookie_info, we use the first active instance
1418
gpointer instance=getFirstInTableInstance(instance_to_id_map);
1419
browser_functions.getvalueforurl((NPP) instance, NPNURLVProxy, siteAddr, proxy, len);
1422
return NPERR_GENERIC_ERROR;
1426
return NPERR_NO_ERROR;
1429
// plugin_out_pipe_callback is called when the appletviewer crashes or
1430
// is killed. It may be called after data has been destroyed in which
1431
// case it simply returns FALSE to remove itself from the glib main
1434
plugin_out_pipe_callback (GIOChannel* source,
1435
GIOCondition condition,
1436
gpointer plugin_data)
1438
PLUGIN_DEBUG ("plugin_out_pipe_callback\n");
1440
ITNPPluginData* data = (ITNPPluginData*) plugin_data;
1442
PLUGIN_DEBUG ("plugin_out_pipe_callback: appletviewer has stopped.\n");
1444
PLUGIN_DEBUG ("plugin_out_pipe_callback return\n");
1449
// remove all components from LD_LIBRARY_PATH, which start with
1450
// MOZILLA_FIVE_HOME; firefox has its own NSS based security provider,
1451
// which conflicts with the one configured in nss.cfg.
1453
plugin_filter_ld_library_path(gchar *path_old)
1455
gchar *moz_home = g_strdup (g_getenv ("MOZILLA_FIVE_HOME"));
1461
if (moz_home == NULL || path_old == NULL || strlen (path_old) == 0)
1463
if (g_str_has_suffix (moz_home, "/"))
1464
moz_home[strlen (moz_home - 1)] = '\0';
1465
moz_prefix = g_strconcat (moz_home, "/", NULL);
1467
components = g_strsplit (path_old, ":", -1);
1468
for (i1 = 0, i2 = 0; components[i1] != NULL; i1++)
1470
if (g_strcmp0 (components[i1], moz_home) == 0
1471
|| g_str_has_prefix (components[i1], moz_home))
1472
components[i2] = components[i1];
1474
components[i2++] = components[i1];
1476
components[i2] = NULL;
1479
path_new = g_strjoinv (":", components);
1480
g_strfreev (components);
1482
g_free (moz_prefix);
1485
if (path_new == NULL || strlen (path_new) == 0)
1487
PLUGIN_DEBUG("Unset LD_LIBRARY_PATH\n");
1492
PLUGIN_DEBUG ("Set LD_LIBRARY_PATH: %s\n", path_new);
1497
// build the environment to pass to the external plugin process
1499
plugin_filter_environment(void)
1501
gchar **var_names = g_listenv();
1502
gchar **new_env = (gchar**) malloc(sizeof(gchar*) * (g_strv_length (var_names) + 1));
1505
for (i_var = 0, i_env = 0; var_names[i_var] != NULL; i_var++)
1507
gchar *env_value = g_strdup (g_getenv (var_names[i_var]));
1509
if (g_str_has_prefix (var_names[i_var], "LD_LIBRARY_PATH"))
1510
env_value = plugin_filter_ld_library_path (env_value);
1511
if (env_value != NULL)
1513
new_env[i_env++] = g_strdup_printf ("%s=%s", var_names[i_var], env_value);
1517
new_env[i_env] = NULL;
1522
plugin_test_appletviewer ()
1524
PLUGIN_DEBUG ("plugin_test_appletviewer: %s\n", appletviewer_executable);
1525
NPError error = NPERR_NO_ERROR;
1527
gchar* command_line[3] = { NULL, NULL, NULL };
1528
gchar** environment;
1530
command_line[0] = g_strdup (appletviewer_executable);
1531
command_line[1] = g_strdup("-version");
1532
command_line[2] = NULL;
1534
environment = plugin_filter_environment();
1536
if (!g_spawn_async (NULL, command_line, environment,
1538
NULL, NULL, NULL, &channel_error))
1542
PLUGIN_ERROR_TWO ("Failed to spawn applet viewer",
1543
channel_error->message);
1544
g_error_free (channel_error);
1545
channel_error = NULL;
1548
PLUGIN_ERROR ("Failed to spawn applet viewer");
1549
error = NPERR_GENERIC_ERROR;
1552
g_strfreev (environment);
1554
g_free (command_line[0]);
1555
command_line[0] = NULL;
1556
g_free (command_line[1]);
1557
command_line[1] = NULL;
1558
g_free (command_line[2]);
1559
command_line[2] = NULL;
1561
PLUGIN_DEBUG ("plugin_test_appletviewer return\n");
1566
plugin_start_appletviewer (ITNPPluginData* data)
1568
PLUGIN_DEBUG ("plugin_start_appletviewer\n");
1569
NPError error = NPERR_NO_ERROR;
1571
gchar** command_line;
1572
gchar** environment;
1577
command_line = (gchar**) malloc(sizeof(gchar*)*11);
1578
command_line[cmd_num++] = g_strdup(appletviewer_executable);
1579
command_line[cmd_num++] = g_strdup(PLUGIN_BOOTCLASSPATH);
1580
// set the classpath to avoid using the default (cwd).
1581
command_line[cmd_num++] = g_strdup("-classpath");
1582
command_line[cmd_num++] = g_strdup_printf("%s/lib/rt.jar", ICEDTEA_WEB_JRE);
1583
command_line[cmd_num++] = g_strdup("-Xdebug");
1584
command_line[cmd_num++] = g_strdup("-Xnoagent");
1585
if (plugin_debug_suspend)
1587
command_line[cmd_num++] = g_strdup("-Xrunjdwp:transport=dt_socket,address=8787,server=y,suspend=y");
1590
command_line[cmd_num++] = g_strdup("-Xrunjdwp:transport=dt_socket,address=8787,server=y,suspend=n");
1592
command_line[cmd_num++] = g_strdup("sun.applet.PluginMain");
1593
command_line[cmd_num++] = g_strdup(out_pipe_name);
1594
command_line[cmd_num++] = g_strdup(in_pipe_name);
1595
command_line[cmd_num] = NULL;
1598
command_line = (gchar**) malloc(sizeof(gchar*)*8);
1599
command_line[cmd_num++] = g_strdup(appletviewer_executable);
1600
command_line[cmd_num++] = g_strdup(PLUGIN_BOOTCLASSPATH);
1601
command_line[cmd_num++] = g_strdup("-classpath");
1602
command_line[cmd_num++] = g_strdup_printf("%s/lib/rt.jar", ICEDTEA_WEB_JRE);
1603
command_line[cmd_num++] = g_strdup("sun.applet.PluginMain");
1604
command_line[cmd_num++] = g_strdup(out_pipe_name);
1605
command_line[cmd_num++] = g_strdup(in_pipe_name);
1606
command_line[cmd_num] = NULL;
1609
environment = plugin_filter_environment();
1611
if (!g_spawn_async (NULL, command_line, environment,
1612
(GSpawnFlags) G_SPAWN_DO_NOT_REAP_CHILD,
1613
NULL, NULL, &appletviewer_pid, &channel_error))
1617
PLUGIN_ERROR_TWO ("Failed to spawn applet viewer",
1618
channel_error->message);
1619
g_error_free (channel_error);
1620
channel_error = NULL;
1623
PLUGIN_ERROR ("Failed to spawn applet viewer");
1624
error = NPERR_GENERIC_ERROR;
1627
g_strfreev (environment);
1629
for (int i = 0; i < cmd_num; i++) {
1630
g_free (command_line[i]);
1631
command_line[i] = NULL;
1634
g_free(command_line);
1635
command_line = NULL;
1637
if (appletviewer_pid)
1639
PLUGIN_DEBUG("Initialized VM with pid=%d\n", appletviewer_pid);
1640
appletviewer_watch_id = g_child_watch_add(appletviewer_pid, (GChildWatchFunc) appletviewer_monitor, (gpointer) appletviewer_pid);
1644
PLUGIN_DEBUG ("plugin_start_appletviewer return\n");
1649
* Replaces certain characters (\r, \n, etc) with HTML escape equivalents.
1651
* Return string is allocated on the heap. Caller assumes responsibility
1652
* for freeing the memory via free()
1655
encode_string(char* to_encode)
1658
// Do nothing for an empty string
1659
if (to_encode == '\0')
1662
// worst case scenario -> all characters are newlines or
1663
// returns, each of which translates to 5 substitutions
1664
char* encoded = (char*) calloc(((strlen(to_encode)*5)+1), sizeof(char));
1666
strcpy(encoded, "");
1668
for (int i=0; i < strlen(to_encode); i++)
1670
if (to_encode[i] == '\r')
1671
encoded = strcat(encoded, " ");
1672
else if (to_encode[i] == '\n')
1673
encoded = strcat(encoded, " ");
1674
else if (to_encode[i] == '>')
1675
encoded = strcat(encoded, ">");
1676
else if (to_encode[i] == '<')
1677
encoded = strcat(encoded, "<");
1678
else if (to_encode[i] == '&')
1679
encoded = strcat(encoded, "&");
1680
else if (to_encode[i] == '"')
1681
encoded = strcat(encoded, """);
1684
char* orig_char = (char*) calloc(2, sizeof(char));
1685
orig_char[0] = to_encode[i];
1686
orig_char[1] = '\0';
1688
strcat(encoded, orig_char);
1698
// Build up the applet tag string that we'll send to the applet
1701
plugin_create_applet_tag (int16_t argc, char* argn[], char* argv[])
1703
PLUGIN_DEBUG ("plugin_create_applet_tag\n");
1705
gchar* applet_tag = g_strdup ("<EMBED ");
1706
gchar* parameters = g_strdup ("");
1708
for (int16_t i = 0; i < argc; i++)
1710
gchar* argn_escaped = encode_string(argn[i]);
1711
gchar* argv_escaped = encode_string(argv[i]);
1713
if (!g_ascii_strcasecmp (argn_escaped, "code"))
1715
gchar* code = g_strdup_printf ("CODE=\"%s\" ", argv_escaped);
1716
applet_tag = g_strconcat (applet_tag, code, NULL);
1720
else if (!g_ascii_strcasecmp (argn_escaped, "java_code"))
1722
gchar* java_code = g_strdup_printf ("JAVA_CODE=\"%s\" ", argv_escaped);
1723
applet_tag = g_strconcat (applet_tag, java_code, NULL);
1727
else if (!g_ascii_strcasecmp (argn_escaped, "codebase"))
1729
gchar* codebase = g_strdup_printf ("CODEBASE=\"%s\" ", argv_escaped);
1730
applet_tag = g_strconcat (applet_tag, codebase, NULL);
1734
else if (!g_ascii_strcasecmp (argn_escaped, "java_codebase"))
1736
gchar* java_codebase = g_strdup_printf ("JAVA_CODEBASE=\"%s\" ", argv_escaped);
1737
applet_tag = g_strconcat (applet_tag, java_codebase, NULL);
1738
g_free (java_codebase);
1739
java_codebase = NULL;
1741
else if (!g_ascii_strcasecmp (argn_escaped, "classid"))
1743
gchar* classid = g_strdup_printf ("CLASSID=\"%s\" ", argv_escaped);
1744
applet_tag = g_strconcat (applet_tag, classid, NULL);
1748
else if (!g_ascii_strcasecmp (argn_escaped, "archive"))
1750
gchar* archive = g_strdup_printf ("ARCHIVE=\"%s\" ", argv_escaped);
1751
applet_tag = g_strconcat (applet_tag, archive, NULL);
1755
else if (!g_ascii_strcasecmp (argn_escaped, "java_archive"))
1757
gchar* java_archive = g_strdup_printf ("JAVA_ARCHIVE=\"%s\" ", argv_escaped);
1758
applet_tag = g_strconcat (applet_tag, java_archive, NULL);
1759
g_free (java_archive);
1760
java_archive = NULL;
1762
else if (!g_ascii_strcasecmp (argn_escaped, "width"))
1764
gchar* width = g_strdup_printf ("width=\"%s\" ", argv_escaped);
1765
applet_tag = g_strconcat (applet_tag, width, NULL);
1769
else if (!g_ascii_strcasecmp (argn_escaped, "height"))
1771
gchar* height = g_strdup_printf ("height=\"%s\" ", argv_escaped);
1772
applet_tag = g_strconcat (applet_tag, height, NULL);
1779
if (argv_escaped != '\0')
1781
parameters = g_strconcat (parameters, "<PARAM NAME=\"", argn_escaped,
1782
"\" VALUE=\"", argv_escaped, "\">", NULL);
1789
argn_escaped = NULL;
1790
argv_escaped = NULL;
1793
applet_tag = g_strconcat (applet_tag, ">", parameters, "</EMBED>", NULL);
1795
g_free (parameters);
1798
PLUGIN_DEBUG ("plugin_create_applet_tag return\n");
1803
// plugin_send_message_to_appletviewer must be called while holding
1804
// data->appletviewer_mutex.
1806
plugin_send_message_to_appletviewer (gchar const* message)
1808
PLUGIN_DEBUG ("plugin_send_message_to_appletviewer\n");
1812
gchar* newline_message = NULL;
1813
gsize bytes_written = 0;
1815
// Send message to appletviewer.
1816
newline_message = g_strdup_printf ("%s\n", message);
1818
// g_io_channel_write_chars will return something other than
1819
// G_IO_STATUS_NORMAL if not all the data is written. In that
1820
// case we fail rather than retrying.
1821
if (g_io_channel_write_chars (out_to_appletviewer,
1822
newline_message, -1, &bytes_written,
1824
!= G_IO_STATUS_NORMAL)
1828
PLUGIN_ERROR_TWO ("Failed to write bytes to output channel",
1829
channel_error->message);
1830
g_error_free (channel_error);
1831
channel_error = NULL;
1834
PLUGIN_ERROR ("Failed to write bytes to output channel");
1837
if (g_io_channel_flush (out_to_appletviewer, &channel_error)
1838
!= G_IO_STATUS_NORMAL)
1842
PLUGIN_ERROR_TWO ("Failed to flush bytes to output channel",
1843
channel_error->message);
1844
g_error_free (channel_error);
1845
channel_error = NULL;
1848
PLUGIN_ERROR ("Failed to flush bytes to output channel");
1850
g_free (newline_message);
1851
newline_message = NULL;
1853
PLUGIN_DEBUG (" PIPE: plugin wrote: %s\n", message);
1856
PLUGIN_DEBUG ("plugin_send_message_to_appletviewer return\n");
1860
* Sends the initialization message (handle/size/url) to the plugin
1863
plugin_send_initialization_message(char* instance, gulong handle,
1864
int width, int height, char* url)
1866
PLUGIN_DEBUG ("plugin_send_initialization_message\n");
1868
gchar *window_message = g_strdup_printf ("instance %s handle %ld width %d height %d %s",
1869
instance, handle, width, height, url);
1870
plugin_send_message_to_appletviewer (window_message);
1871
g_free (window_message);
1872
window_message = NULL;
1874
PLUGIN_DEBUG ("plugin_send_initialization_message return\n");
1878
// Stop the appletviewer process. When this is called the
1879
// appletviewer can be in any of three states: running, crashed or
1880
// hung. If the appletviewer is running then sending it "shutdown"
1881
// will cause it to exit. This will cause
1882
// plugin_out_pipe_callback/plugin_in_pipe_callback to be called and
1883
// the input and output channels to be shut down. If the appletviewer
1884
// has crashed then plugin_out_pipe_callback/plugin_in_pipe_callback
1885
// would already have been called and data->appletviewer_alive cleared
1886
// in which case this function simply returns. If the appletviewer is
1887
// hung then this function will be successful and the input and output
1888
// watches will be removed by plugin_data_destroy.
1889
// plugin_stop_appletviewer must be called with
1890
// data->appletviewer_mutex held.
1892
plugin_stop_appletviewer ()
1894
PLUGIN_DEBUG ("plugin_stop_appletviewer\n");
1898
// Shut down the appletviewer.
1899
gsize bytes_written = 0;
1901
if (out_to_appletviewer)
1903
if (g_io_channel_write_chars (out_to_appletviewer, "shutdown",
1904
-1, &bytes_written, &channel_error)
1905
!= G_IO_STATUS_NORMAL)
1909
PLUGIN_ERROR_TWO ("Failed to write shutdown message to"
1910
" appletviewer", channel_error->message);
1911
g_error_free (channel_error);
1912
channel_error = NULL;
1915
PLUGIN_ERROR ("Failed to write shutdown message to");
1918
if (g_io_channel_flush (out_to_appletviewer, &channel_error)
1919
!= G_IO_STATUS_NORMAL)
1923
PLUGIN_ERROR_TWO ("Failed to write shutdown message to"
1924
" appletviewer", channel_error->message);
1925
g_error_free (channel_error);
1926
channel_error = NULL;
1929
PLUGIN_ERROR ("Failed to write shutdown message to");
1932
if (g_io_channel_shutdown (out_to_appletviewer,
1933
TRUE, &channel_error)
1934
!= G_IO_STATUS_NORMAL)
1938
PLUGIN_ERROR_TWO ("Failed to shut down appletviewer"
1939
" output channel", channel_error->message);
1940
g_error_free (channel_error);
1941
channel_error = NULL;
1944
PLUGIN_ERROR ("Failed to shut down appletviewer");
1948
if (in_from_appletviewer)
1950
if (g_io_channel_shutdown (in_from_appletviewer,
1951
TRUE, &channel_error)
1952
!= G_IO_STATUS_NORMAL)
1956
PLUGIN_ERROR_TWO ("Failed to shut down appletviewer"
1957
" input channel", channel_error->message);
1958
g_error_free (channel_error);
1959
channel_error = NULL;
1962
PLUGIN_ERROR ("Failed to shut down appletviewer");
1968
sleep(2); /* Needed to prevent crashes during debug (when JDWP port is not freed by the kernel right away) */
1970
PLUGIN_DEBUG ("plugin_stop_appletviewer return\n");
1973
static void appletviewer_monitor(GPid pid, gint status, gpointer data)
1975
PLUGIN_DEBUG ("appletviewer_monitor\n");
1978
PLUGIN_DEBUG ("appletviewer_monitor return\n");
1982
plugin_data_destroy (NPP instance)
1984
PLUGIN_DEBUG ("plugin_data_destroy\n");
1986
ITNPPluginData* tofree = (ITNPPluginData*) instance->pdata;
1988
// Remove instance from map
1989
gpointer id_ptr = g_hash_table_lookup(instance_to_id_map, instance);
1993
gint id = GPOINTER_TO_INT(id_ptr);
1994
g_hash_table_remove(instance_to_id_map, instance);
1995
g_hash_table_remove(id_to_instance_map, id_ptr);
1998
tofree->window_handle = NULL;
1999
tofree->window_height = 0;
2000
tofree->window_width = 0;
2002
// cleanup_appletviewer_mutex:
2003
g_free (tofree->appletviewer_mutex);
2004
tofree->appletviewer_mutex = NULL;
2006
// cleanup_instance_string:
2007
g_free (tofree->instance_id);
2008
tofree->instance_id = NULL;
2010
// cleanup applet tag
2011
g_free (tofree->applet_tag);
2012
tofree->applet_tag = NULL;
2014
g_free(tofree->source);
2015
tofree->source = NULL;
2018
// Eliminate back-pointer to plugin instance.
2019
tofree->owner = NULL;
2020
(*browser_functions.memfree) (tofree);
2023
PLUGIN_DEBUG ("plugin_data_destroy return\n");
2026
// FACTORY FUNCTIONS
2028
// Provides the browser with pointers to the plugin functions that we
2029
// implement and initializes a local table with browser functions that
2030
// we may wish to call. Called once, after browser startup and before
2031
// the first plugin instance is created.
2032
// The field 'initialized' is set to true once this function has
2033
// finished. If 'initialized' is already true at the beginning of
2034
// this function, then it is evident that NP_Initialize has already
2035
// been called. There is no need to call this function more than once and
2036
// this workaround avoids any duplicate calls.
2038
NP_Initialize (NPNetscapeFuncs* browserTable, NPPluginFuncs* pluginTable)
2040
PLUGIN_DEBUG ("NP_Initialize\n");
2042
if ((browserTable == NULL) || (pluginTable == NULL))
2044
PLUGIN_ERROR ("Browser or plugin function table is NULL.");
2046
return NPERR_INVALID_FUNCTABLE_ERROR;
2049
// Ensure that the major version of the plugin API that the browser
2050
// expects is not more recent than the major version of the API that
2051
// we've implemented.
2052
if ((browserTable->version >> 8) > NP_VERSION_MAJOR)
2054
PLUGIN_ERROR ("Incompatible version.");
2056
return NPERR_INCOMPATIBLE_VERSION_ERROR;
2059
// Ensure that the plugin function table we've received is large
2060
// enough to store the number of functions that we may provide.
2061
if (pluginTable->size < sizeof (NPPluginFuncs))
2063
PLUGIN_ERROR ("Invalid plugin function table.");
2065
return NPERR_INVALID_FUNCTABLE_ERROR;
2068
// Ensure that the browser function table is large enough to store
2069
// the number of browser functions that we may use.
2070
if (browserTable->size < sizeof (NPNetscapeFuncs))
2072
fprintf (stderr, "ERROR: Invalid browser function table. Some functionality may be restricted.\n");
2075
// Store in a local table the browser functions that we may use.
2076
browser_functions.size = browserTable->size;
2077
browser_functions.version = browserTable->version;
2078
browser_functions.geturlnotify = browserTable->geturlnotify;
2079
browser_functions.geturl = browserTable->geturl;
2080
browser_functions.posturlnotify = browserTable->posturlnotify;
2081
browser_functions.posturl = browserTable->posturl;
2082
browser_functions.requestread = browserTable->requestread;
2083
browser_functions.newstream = browserTable->newstream;
2084
browser_functions.write = browserTable->write;
2085
browser_functions.destroystream = browserTable->destroystream;
2086
browser_functions.status = browserTable->status;
2087
browser_functions.uagent = browserTable->uagent;
2088
browser_functions.memalloc = browserTable->memalloc;
2089
browser_functions.memfree = browserTable->memfree;
2090
browser_functions.memflush = browserTable->memflush;
2091
browser_functions.reloadplugins = browserTable->reloadplugins;
2092
browser_functions.getJavaEnv = browserTable->getJavaEnv;
2093
browser_functions.getJavaPeer = browserTable->getJavaPeer;
2094
browser_functions.getvalue = browserTable->getvalue;
2095
browser_functions.setvalue = browserTable->setvalue;
2096
browser_functions.invalidaterect = browserTable->invalidaterect;
2097
browser_functions.invalidateregion = browserTable->invalidateregion;
2098
browser_functions.forceredraw = browserTable->forceredraw;
2099
browser_functions.getstringidentifier = browserTable->getstringidentifier;
2100
browser_functions.getstringidentifiers = browserTable->getstringidentifiers;
2101
browser_functions.getintidentifier = browserTable->getintidentifier;
2102
browser_functions.identifierisstring = browserTable->identifierisstring;
2103
browser_functions.utf8fromidentifier = browserTable->utf8fromidentifier;
2104
browser_functions.intfromidentifier = browserTable->intfromidentifier;
2105
browser_functions.createobject = browserTable->createobject;
2106
browser_functions.retainobject = browserTable->retainobject;
2107
browser_functions.releaseobject = browserTable->releaseobject;
2108
browser_functions.invoke = browserTable->invoke;
2109
browser_functions.invokeDefault = browserTable->invokeDefault;
2110
browser_functions.evaluate = browserTable->evaluate;
2111
browser_functions.getproperty = browserTable->getproperty;
2112
browser_functions.setproperty = browserTable->setproperty;
2113
browser_functions.removeproperty = browserTable->removeproperty;
2114
browser_functions.hasproperty = browserTable->hasproperty;
2115
browser_functions.hasmethod = browserTable->hasmethod;
2116
browser_functions.releasevariantvalue = browserTable->releasevariantvalue;
2117
browser_functions.setexception = browserTable->setexception;
2118
browser_functions.pluginthreadasynccall = browserTable->pluginthreadasynccall;
2119
#if MOZILLA_VERSION_COLLAPSED >= 1090100
2120
browser_functions.getvalueforurl = browserTable->getvalueforurl;
2121
browser_functions.setvalueforurl = browserTable->setvalueforurl;
2124
// Return to the browser the plugin functions that we implement.
2125
pluginTable->version = (NP_VERSION_MAJOR << 8) + NP_VERSION_MINOR;
2126
pluginTable->size = sizeof (NPPluginFuncs);
2128
#if MOZILLA_VERSION_COLLAPSED < 1090100
2129
pluginTable->newp = NewNPP_NewProc (ITNP_New);
2130
pluginTable->destroy = NewNPP_DestroyProc (ITNP_Destroy);
2131
pluginTable->setwindow = NewNPP_SetWindowProc (ITNP_SetWindow);
2132
pluginTable->newstream = NewNPP_NewStreamProc (ITNP_NewStream);
2133
pluginTable->destroystream = NewNPP_DestroyStreamProc (ITNP_DestroyStream);
2134
pluginTable->asfile = NewNPP_StreamAsFileProc (ITNP_StreamAsFile);
2135
pluginTable->writeready = NewNPP_WriteReadyProc (ITNP_WriteReady);
2136
pluginTable->write = NewNPP_WriteProc (ITNP_Write);
2137
pluginTable->print = NewNPP_PrintProc (ITNP_Print);
2138
pluginTable->urlnotify = NewNPP_URLNotifyProc (ITNP_URLNotify);
2139
pluginTable->getvalue = NewNPP_GetValueProc (ITNP_GetValue);
2141
pluginTable->newp = NPP_NewProcPtr (ITNP_New);
2142
pluginTable->destroy = NPP_DestroyProcPtr (ITNP_Destroy);
2143
pluginTable->setwindow = NPP_SetWindowProcPtr (ITNP_SetWindow);
2144
pluginTable->newstream = NPP_NewStreamProcPtr (ITNP_NewStream);
2145
pluginTable->destroystream = NPP_DestroyStreamProcPtr (ITNP_DestroyStream);
2146
pluginTable->asfile = NPP_StreamAsFileProcPtr (ITNP_StreamAsFile);
2147
pluginTable->writeready = NPP_WriteReadyProcPtr (ITNP_WriteReady);
2148
pluginTable->write = NPP_WriteProcPtr (ITNP_Write);
2149
pluginTable->print = NPP_PrintProcPtr (ITNP_Print);
2150
pluginTable->urlnotify = NPP_URLNotifyProcPtr (ITNP_URLNotify);
2151
pluginTable->getvalue = NPP_GetValueProcPtr (ITNP_GetValue);
2154
// Re-setting the above tables multiple times is OK (as the
2155
// browser may change its function locations). However
2156
// anything beyond this point should only run once.
2158
return NPERR_NO_ERROR;
2160
// Make sure the plugin data directory exists, creating it if
2162
data_directory = g_strconcat (P_tmpdir, NULL);
2163
if (!data_directory)
2165
PLUGIN_ERROR ("Failed to create data directory name.");
2166
return NPERR_OUT_OF_MEMORY_ERROR;
2168
NPError np_error = NPERR_NO_ERROR;
2169
gchar* filename = NULL;
2171
// If P_tmpdir does not exist, try /tmp directly
2173
if (!g_file_test (data_directory,
2174
(GFileTest) (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)))
2178
data_directory = g_strconcat ("/tmp", NULL);
2179
if (!data_directory)
2181
PLUGIN_ERROR ("Failed to create data directory name.");
2182
return NPERR_OUT_OF_MEMORY_ERROR;
2187
data_directory = g_strconcat (data_directory, "/icedteaplugin-", getenv("USER"), NULL);
2189
if (!data_directory)
2191
PLUGIN_ERROR ("Failed to create data directory name.");
2192
return NPERR_OUT_OF_MEMORY_ERROR;
2195
// Now create a icedteaplugin subdir
2196
if (!g_file_test (data_directory,
2197
(GFileTest) (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)))
2201
file_error = g_mkdir (data_directory, 0700);
2202
if (file_error != 0)
2204
PLUGIN_ERROR_THREE ("Failed to create data directory",
2207
np_error = NPERR_GENERIC_ERROR;
2208
goto cleanup_data_directory;
2213
// If data directory doesn't exit by this point, bail
2214
if (!g_file_test (data_directory,
2215
(GFileTest) (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)))
2217
PLUGIN_ERROR_THREE ("Temp directory does not exist: ",
2221
np_error = NPERR_GENERIC_ERROR;
2222
goto cleanup_data_directory;
2226
// Set appletviewer_executable.
2227
filename = g_strdup(ICEDTEA_WEB_JRE);
2228
appletviewer_executable = g_strdup_printf ("%s/bin/java",
2230
PLUGIN_DEBUG("Executing java at %s\n", appletviewer_executable);
2231
if (!appletviewer_executable)
2233
PLUGIN_ERROR ("Failed to create appletviewer executable name.");
2234
np_error = NPERR_OUT_OF_MEMORY_ERROR;
2235
goto cleanup_filename;
2238
np_error = plugin_test_appletviewer ();
2239
if (np_error != NPERR_NO_ERROR)
2241
plugin_display_failure_dialog ();
2242
goto cleanup_appletviewer_executable;
2248
// Initialize threads (needed for mutexes).
2249
if (!g_thread_supported ())
2250
g_thread_init (NULL);
2252
plugin_instance_mutex = g_mutex_new ();
2254
PLUGIN_DEBUG ("NP_Initialize: using %s\n", appletviewer_executable);
2256
plugin_req_proc = new PluginRequestProcessor();
2257
java_req_proc = new JavaMessageSender();
2259
java_to_plugin_bus = new MessageBus();
2260
plugin_to_java_bus = new MessageBus();
2262
java_to_plugin_bus->subscribe(plugin_req_proc);
2263
plugin_to_java_bus->subscribe(java_req_proc);
2265
pthread_create (&plugin_request_processor_thread1, NULL, &queue_processor, (void*) plugin_req_proc);
2266
pthread_create (&plugin_request_processor_thread2, NULL, &queue_processor, (void*) plugin_req_proc);
2267
pthread_create (&plugin_request_processor_thread3, NULL, &queue_processor, (void*) plugin_req_proc);
2269
itnp_plugin_thread_id = pthread_self();
2271
pthread_mutexattr_t attribute;
2272
pthread_mutexattr_init(&attribute);
2273
pthread_mutexattr_settype(&attribute, PTHREAD_MUTEX_RECURSIVE);
2274
pthread_mutex_init(&pluginAsyncCallMutex, &attribute);
2275
pthread_mutexattr_destroy(&attribute);
2277
PLUGIN_DEBUG ("NP_Initialize return\n");
2279
return NPERR_NO_ERROR;
2281
cleanup_appletviewer_executable:
2282
if (appletviewer_executable)
2284
g_free (appletviewer_executable);
2285
appletviewer_executable = NULL;
2295
cleanup_data_directory:
2298
g_free (data_directory);
2299
data_directory = NULL;
2306
// Returns a string describing the MIME type that this plugin
2308
#ifdef LEGACY_XULRUNNERAPI
2313
NP_GetMIMEDescription ()
2315
PLUGIN_DEBUG ("NP_GetMIMEDescription\n");
2317
PLUGIN_DEBUG ("NP_GetMIMEDescription return\n");
2319
return (char*) PLUGIN_MIME_DESC;
2322
// Returns a value relevant to the plugin as a whole. The browser
2323
// calls this function to obtain information about the plugin.
2325
NP_GetValue (void* future, NPPVariable variable, void* value)
2327
PLUGIN_DEBUG ("NP_GetValue\n");
2329
NPError result = NPERR_NO_ERROR;
2330
gchar** char_value = (gchar**) value;
2334
case NPPVpluginNameString:
2335
PLUGIN_DEBUG ("NP_GetValue: returning plugin name.\n");
2336
*char_value = g_strdup (PLUGIN_FULL_NAME);
2339
case NPPVpluginDescriptionString:
2340
PLUGIN_DEBUG ("NP_GetValue: returning plugin description.\n");
2341
*char_value = g_strdup (PLUGIN_DESC);
2345
PLUGIN_ERROR ("Unknown plugin value requested.");
2346
result = NPERR_GENERIC_ERROR;
2350
PLUGIN_DEBUG ("NP_GetValue return\n");
2355
// Shuts down the plugin. Called after the last plugin instance is
2360
PLUGIN_DEBUG ("NP_Shutdown\n");
2363
if (plugin_instance_mutex)
2365
g_mutex_free (plugin_instance_mutex);
2366
plugin_instance_mutex = NULL;
2371
g_free (data_directory);
2372
data_directory = NULL;
2375
if (appletviewer_executable)
2377
g_free (appletviewer_executable);
2378
appletviewer_executable = NULL;
2381
// stop the appletviewer
2382
plugin_stop_appletviewer();
2385
if (appletviewer_watch_id != -1)
2386
g_source_remove(appletviewer_watch_id);
2388
// Removing a source is harmless if it fails since it just means the
2389
// source has already been removed.
2390
g_source_remove (in_watch_source);
2391
in_watch_source = 0;
2393
// cleanup_in_from_appletviewer:
2394
if (in_from_appletviewer)
2395
g_io_channel_unref (in_from_appletviewer);
2396
in_from_appletviewer = NULL;
2398
// cleanup_out_watch_source:
2399
g_source_remove (out_watch_source);
2400
out_watch_source = 0;
2402
// cleanup_out_to_appletviewer:
2403
if (out_to_appletviewer)
2404
g_io_channel_unref (out_to_appletviewer);
2405
out_to_appletviewer = NULL;
2407
// cleanup_out_pipe:
2408
// Delete output pipe.
2409
PLUGIN_DEBUG ("NP_Shutdown: deleting output fifo: %s\n", out_pipe_name);
2410
unlink (out_pipe_name);
2411
PLUGIN_DEBUG ("NP_Shutdown: deleted output fifo: %s\n", out_pipe_name);
2413
// cleanup_out_pipe_name:
2414
g_free (out_pipe_name);
2415
out_pipe_name = NULL;
2418
// Delete input pipe.
2419
PLUGIN_DEBUG ("NP_Shutdown: deleting input fifo: %s\n", in_pipe_name);
2420
unlink (in_pipe_name);
2421
PLUGIN_DEBUG ("NP_Shutdown: deleted input fifo: %s\n", in_pipe_name);
2423
// cleanup_in_pipe_name:
2424
g_free (in_pipe_name);
2425
in_pipe_name = NULL;
2427
// Destroy the call queue mutex
2428
pthread_mutex_destroy(&pluginAsyncCallMutex);
2430
initialized = false;
2432
pthread_cancel(plugin_request_processor_thread1);
2433
pthread_cancel(plugin_request_processor_thread2);
2434
pthread_cancel(plugin_request_processor_thread3);
2436
pthread_join(plugin_request_processor_thread1, NULL);
2437
pthread_join(plugin_request_processor_thread2, NULL);
2438
pthread_join(plugin_request_processor_thread3, NULL);
2440
java_to_plugin_bus->unSubscribe(plugin_req_proc);
2441
plugin_to_java_bus->unSubscribe(java_req_proc);
2442
//internal_bus->unSubscribe(java_req_proc);
2443
//internal_bus->unSubscribe(plugin_req_proc);
2445
delete plugin_req_proc;
2446
delete java_req_proc;
2447
delete java_to_plugin_bus;
2448
delete plugin_to_java_bus;
2449
//delete internal_bus;
2451
PLUGIN_DEBUG ("NP_Shutdown return\n");
2453
return NPERR_NO_ERROR;
2457
get_scriptable_object(NPP instance)
2460
ITNPPluginData* data = (ITNPPluginData*) instance->pdata;
2462
if (data->is_applet_instance) // dummy instance/package?
2464
JavaRequestProcessor java_request = JavaRequestProcessor();
2465
JavaResultData* java_result;
2466
std::string instance_id = std::string();
2467
std::string applet_class_id = std::string();
2469
int id = get_id_from_instance(instance);
2470
gchar* id_str = g_strdup_printf ("%d", id);
2472
// Some browsers.. (e.g. chromium) don't call NPP_SetWindow
2473
// for 0x0 plugins and therefore require initialization with
2475
if (!data->window_handle)
2477
plugin_send_initialization_message(data->instance_id, 0, 0, 0, data->applet_tag);
2480
java_result = java_request.getAppletObjectInstance(id_str);
2484
if (java_result->error_occurred)
2486
printf("Error: Unable to fetch applet instance id from Java side.\n");
2490
instance_id.append(*(java_result->return_string));
2492
java_result = java_request.getClassID(instance_id);
2494
if (java_result->error_occurred)
2496
printf("Error: Unable to fetch applet instance id from Java side.\n");
2500
applet_class_id.append(*(java_result->return_string));
2502
obj = IcedTeaScriptableJavaPackageObject::get_scriptable_java_object(instance, applet_class_id, instance_id, false);
2506
obj = IcedTeaScriptablePluginObject::get_scriptable_java_package_object(instance, "");
2513
allocate_scriptable_object(NPP npp, NPClass *aClass)
2515
PLUGIN_DEBUG("Allocating new scriptable object\n");
2516
return new IcedTeaScriptablePluginObject(npp);