source: trunk/icedtea-web/plugin/icedteanp/IcedTeaNPPlugin.cc@ 433

Last change on this file since 433 was 433, checked in by dmik, 11 years ago

icedtea-web: Fix java search failure due to silly typo.

File size: 78.4 KB
Line 
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
4
5This file is part of GNU Classpath.
6
7GNU Classpath is free software; you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation; either version 2, or (at your option)
10any later version.
11
12GNU Classpath is distributed in the hope that it will be useful, but
13WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GNU Classpath; see the file COPYING. If not, write to the
19Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
2002110-1301 USA.
21
22Linking this library statically or dynamically with other modules is
23making a combined work based on this library. Thus, the terms and
24conditions of the GNU General Public License cover the whole
25combination.
26
27As a special exception, the copyright holders of this library give you
28permission to link this library with independent modules to produce an
29executable, regardless of the license terms of these independent
30modules, and to copy and distribute the resulting executable under
31terms of your choice, provided that you also meet, for each linked
32independent module, the terms and conditions of the license of that
33module. An independent module is a module which is not derived from
34or based on this library. If you modify this library, you may extend
35this exception to your version of the library, but you are not
36obligated to do so. If you do not wish to do so, delete this
37exception statement from your version. */
38
39#ifdef __OS2__
40// OS/2 includes.
41#define INCL_DOSPROCESS
42#define INCL_DOSERRORS
43#define INCL_WINDIALOG
44#include <os2.h>
45#include <emx/startup.h>
46#include <sys/socket.h>
47#include <fcntl.h>
48#include <sstream>
49#include "OS_OS2.h"
50#endif
51
52// System includes.
53#include <dlfcn.h>
54#include <unistd.h>
55#include <fcntl.h>
56#include <dirent.h>
57#include <errno.h>
58#include <libgen.h>
59#include <stdio.h>
60#include <stdlib.h>
61#include <string.h>
62#include <string>
63#include <sys/stat.h>
64#include <sys/types.h>
65#include <unistd.h>
66#include <new>
67
68//IcedTea-plugin includes
69#include "IcedTeaPluginUtils.h"
70#include "IcedTeaParseProperties.h"
71// Liveconnect extension
72#include "IcedTeaScriptablePluginObject.h"
73#include "IcedTeaNPPlugin.h"
74
75#ifdef __OS2__
76#define DT_SOCKET_DLL "jdtsock"
77#else
78#define DT_SOCKET_DLL "dt_socket"
79#endif
80
81// Plugin information passed to about:plugins.
82#define PLUGIN_FULL_NAME PLUGIN_NAME " (using " PLUGIN_VERSION ")"
83#define PLUGIN_DESC "The <a href=\"" PACKAGE_URL "\">" PLUGIN_NAME "</a> executes Java applets."
84
85#ifdef HAVE_JAVA7
86 #define JPI_VERSION "1.7.0_" JDK_UPDATE_VERSION
87 #define PLUGIN_APPLET_MIME_DESC7 \
88 "application/x-java-applet;version=1.7:class,jar:IcedTea;"
89 #define PLUGIN_BEAN_MIME_DESC7 \
90 "application/x-java-bean;version=1.7:class,jar:IcedTea;"
91#else
92 #define JPI_VERSION "1.6.0_" JDK_UPDATE_VERSION
93 #define PLUGIN_APPLET_MIME_DESC7
94 #define PLUGIN_BEAN_MIME_DESC7
95#endif
96
97#define PLUGIN_MIME_DESC \
98 "application/x-java-vm:class,jar:IcedTea;" \
99 "application/x-java-applet:class,jar:IcedTea;" \
100 "application/x-java-applet;version=1.1:class,jar:IcedTea;" \
101 "application/x-java-applet;version=1.1.1:class,jar:IcedTea;" \
102 "application/x-java-applet;version=1.1.2:class,jar:IcedTea;" \
103 "application/x-java-applet;version=1.1.3:class,jar:IcedTea;" \
104 "application/x-java-applet;version=1.2:class,jar:IcedTea;" \
105 "application/x-java-applet;version=1.2.1:class,jar:IcedTea;" \
106 "application/x-java-applet;version=1.2.2:class,jar:IcedTea;" \
107 "application/x-java-applet;version=1.3:class,jar:IcedTea;" \
108 "application/x-java-applet;version=1.3.1:class,jar:IcedTea;" \
109 "application/x-java-applet;version=1.4:class,jar:IcedTea;" \
110 "application/x-java-applet;version=1.4.1:class,jar:IcedTea;" \
111 "application/x-java-applet;version=1.4.2:class,jar:IcedTea;" \
112 "application/x-java-applet;version=1.5:class,jar:IcedTea;" \
113 "application/x-java-applet;version=1.6:class,jar:IcedTea;" \
114 PLUGIN_APPLET_MIME_DESC7 \
115 "application/x-java-applet;jpi-version=" JPI_VERSION ":class,jar:IcedTea;" \
116 "application/x-java-bean:class,jar:IcedTea;" \
117 "application/x-java-bean;version=1.1:class,jar:IcedTea;" \
118 "application/x-java-bean;version=1.1.1:class,jar:IcedTea;" \
119 "application/x-java-bean;version=1.1.2:class,jar:IcedTea;" \
120 "application/x-java-bean;version=1.1.3:class,jar:IcedTea;" \
121 "application/x-java-bean;version=1.2:class,jar:IcedTea;" \
122 "application/x-java-bean;version=1.2.1:class,jar:IcedTea;" \
123 "application/x-java-bean;version=1.2.2:class,jar:IcedTea;" \
124 "application/x-java-bean;version=1.3:class,jar:IcedTea;" \
125 "application/x-java-bean;version=1.3.1:class,jar:IcedTea;" \
126 "application/x-java-bean;version=1.4:class,jar:IcedTea;" \
127 "application/x-java-bean;version=1.4.1:class,jar:IcedTea;" \
128 "application/x-java-bean;version=1.4.2:class,jar:IcedTea;" \
129 "application/x-java-bean;version=1.5:class,jar:IcedTea;" \
130 "application/x-java-bean;version=1.6:class,jar:IcedTea;" \
131 PLUGIN_BEAN_MIME_DESC7 \
132 "application/x-java-bean;jpi-version=" JPI_VERSION ":class,jar:IcedTea;" \
133 "application/x-java-vm-npruntime::IcedTea;"
134
135#define PLUGIN_URL NS_INLINE_PLUGIN_CONTRACTID_PREFIX NS_JVM_MIME_TYPE
136#define PLUGIN_MIME_TYPE "application/x-java-vm"
137#define PLUGIN_FILE_EXTS "class,jar,zip"
138#define PLUGIN_MIME_COUNT 1
139
140#define FAILURE_MESSAGE "icedteanp plugin error: Failed to run %s." \
141 " For more detail rerun \"firefox -g\" in a terminal window."
142
143// Data directory for plugin.
144static std::string data_directory;
145static DIR *data_directory_descriptor;
146
147// Fully-qualified appletviewer default executable and rt.jar
148static const char* appletviewer_default_executable = ICEDTEA_WEB_JRE "/bin/java";
149static const char* appletviewer_default_rtjar = ICEDTEA_WEB_JRE "/lib/rt.jar";
150
151// Applet viewer input channel (needs to be static because it is used in plugin_in_pipe_callback)
152static GIOChannel* in_from_appletviewer = NULL;
153
154#ifdef __OS2__
155#define CLOSE_FD(fd) do { if (fd != -1) { close (fd); fd = -1; } } while (0)
156#endif
157
158#ifdef __OS2__
159int in_pipe[2] = { -1 };
160#else
161// Applet viewer input pipe name.
162gchar* in_pipe_name;
163#endif
164
165// Applet viewer input watch source.
166gint in_watch_source;
167
168#ifdef __OS2__
169int out_pipe[2] = { -1 };
170#else
171// Applet viewer output pipe name.
172gchar* out_pipe_name;
173#endif
174
175// Applet viewer debug pipe name.
176gchar* debug_pipe_name = NULL;
177
178// Applet viewer output watch source.
179gint out_watch_source;
180
181// Thread ID of plug-in thread
182pthread_t itnp_plugin_thread_id;
183
184// Mutex to lock async call queue
185pthread_mutex_t pluginAsyncCallMutex;
186
187/*to sync pipe to apletviewer console*/
188pthread_mutex_t debug_pipe_lock = PTHREAD_MUTEX_INITIALIZER;
189
190// Applet viewer output channel.
191GIOChannel* out_to_appletviewer;
192
193// Applet viewer debug channel.
194GIOChannel* debug_to_appletviewer = NULL;
195
196// Tracks jvm status
197gboolean jvm_up = FALSE;
198
199// Keeps track of initialization. NP_Initialize should only be
200// called once.
201gboolean initialized = false;
202
203// browser functions into mozilla
204NPNetscapeFuncs browser_functions;
205
206// Various message buses carrying information to/from Java, and internally
207MessageBus* plugin_to_java_bus;
208MessageBus* java_to_plugin_bus;
209//MessageBus* internal_bus = new MessageBus();
210
211// Processor for plugin requests
212PluginRequestProcessor* plugin_req_proc;
213
214// Sends messages to Java over the bus
215JavaMessageSender* java_req_proc;
216
217// Queue processing threads
218static pthread_t plugin_request_processor_thread1;
219static pthread_t plugin_request_processor_thread2;
220static pthread_t plugin_request_processor_thread3;
221
222#ifdef __OS2__
223static QueueProcessorData queue_processor_data1 = { NULL, false };
224static QueueProcessorData queue_processor_data2 = { NULL, false };
225static QueueProcessorData queue_processor_data3 = { NULL, false };
226#endif
227
228// Static instance helper functions.
229// Retrieve the current document's documentbase.
230static std::string plugin_get_documentbase (NPP instance);
231// Callback used to monitor input pipe status.
232static gboolean plugin_in_pipe_callback (GIOChannel* source,
233 GIOCondition condition,
234 gpointer plugin_data);
235// Callback used to monitor output pipe status.
236static gboolean plugin_out_pipe_callback (GIOChannel* source,
237 GIOCondition condition,
238 gpointer plugin_data);
239std::string plugin_parameters_string (int argc, char* argn[], char* argv[]);
240static void plugin_stop_appletviewer ();
241
242NPError get_cookie_info(const char* siteAddr, char** cookieString, uint32_t* len);
243NPError get_proxy_info(const char* siteAddr, char** proxy, uint32_t* len);
244void consume_message(gchar* message);
245static void appletviewer_monitor(GPid pid, gint status, gpointer data);
246void plugin_send_initialization_message(char* instance, gulong handle,
247 int width, int height,
248 char* url);
249/* Returns JVM options set in itw-settings */
250std::vector<std::string*>* get_jvm_args();
251
252// Global instance counter.
253// Mutex to protect plugin_instance_counter.
254static GMutex* plugin_instance_mutex = NULL;
255// A global variable for reporting GLib errors. This must be free'd
256// and set to NULL after each use.
257static GError* channel_error = NULL;
258
259static GHashTable* instance_to_id_map = g_hash_table_new(NULL, NULL);
260static GHashTable* id_to_instance_map = g_hash_table_new(NULL, NULL);
261static gint instance_counter = 1;
262static GPid appletviewer_pid = -1;
263static guint appletviewer_watch_id = -1;
264
265bool debug_initiated = false;
266int plugin_debug = getenv ("ICEDTEAPLUGIN_DEBUG") != NULL;
267bool plugin_debug_headers = false;
268bool plugin_debug_to_file = false ;
269bool plugin_debug_to_streams = true ;
270bool plugin_debug_to_system = false;
271bool plugin_debug_to_console = true;
272FILE * plugin_file_log;
273std::string plugin_file_log_name;
274
275int plugin_debug_suspend = (getenv("ICEDTEAPLUGIN_DEBUG") != NULL) &&
276 (strcmp(getenv("ICEDTEAPLUGIN_DEBUG"), "suspend") == 0);
277
278
279#ifdef LEGACY_GLIB
280// Returns key from first item stored in hashtable
281gboolean
282find_first_item_in_hash_table(gpointer key, gpointer value, gpointer user_data)
283{
284 user_data = key;
285 return (gboolean)TRUE;
286}
287
288int
289g_strcmp0(char *str1, char *str2)
290{
291 if (str1 != NULL)
292 return str2 != NULL ? strcmp(str1, str2) : 1;
293 else // str1 == NULL
294 return str2 != NULL ? 1 : 0;
295}
296
297
298#endif
299
300static std::string get_plugin_executable(){
301 std::string custom_jre;
302 bool custom_jre_defined = find_custom_jre(custom_jre);
303 if (custom_jre_defined) {
304 if (IcedTeaPluginUtilities::file_exists(custom_jre+"/bin/java")){
305 return custom_jre+"/bin/java";
306 } else {
307 PLUGIN_ERROR("Your custom jre (/bin/java check) %s is not valid. Please fix %s in your %s. In attempt to run using default one. \n", custom_jre.c_str(), custom_jre_key.c_str(), default_file_ITW_deploy_props_name.c_str());
308 }
309 }
310#ifdef __OS2__
311 custom_jre = icedtea_web_jre_dir();
312 if (custom_jre.length())
313 return custom_jre+"/bin/java";
314#endif
315 return appletviewer_default_executable;
316}
317
318static std::string get_plugin_rt_jar(){
319 std::string custom_jre;
320 bool custom_jre_defined = find_custom_jre(custom_jre);
321 if (custom_jre_defined) {
322 if (IcedTeaPluginUtilities::file_exists(custom_jre+"/lib/rt.jar")){
323 return custom_jre+"/lib/rt.jar";
324 } else {
325 PLUGIN_ERROR("Your custom jre (/lib/rt.jar check) %s is not valid. Please fix %s in your %s. In attempt to run using default one. \n", custom_jre.c_str(), custom_jre_key.c_str(), default_file_ITW_deploy_props_name.c_str());
326 }
327 }
328#ifdef __OS2__
329 custom_jre = icedtea_web_jre_dir();
330 if (custom_jre.length())
331 return custom_jre+"/lib/rt.jar";
332#endif
333 return appletviewer_default_rtjar;
334}
335
336static void cleanUpDir(){
337 //free data_directory descriptor
338 if (data_directory_descriptor != NULL) {
339 closedir(data_directory_descriptor);
340 }
341 //clean up pipes directory
342 PLUGIN_DEBUG ("Removing runtime directory %s \n", data_directory.c_str());
343 int removed = rmdir(data_directory.c_str());
344 if (removed != 0) {
345 PLUGIN_ERROR ("Failed to remove runtime directory %s, because of %s \n", data_directory.c_str(), strerror(errno));
346 } else {
347 PLUGIN_DEBUG ("Removed runtime directory %s \n", data_directory.c_str());
348 }
349 data_directory_descriptor = NULL;
350}
351/*
352 * Find first member in GHashTable* depending on version of glib
353 */
354gpointer getFirstInTableInstance(GHashTable* table)
355{
356 gpointer id, instance;
357 #ifndef LEGACY_GLIB
358 GHashTableIter iter;
359 g_hash_table_iter_init (&iter, table);
360 g_hash_table_iter_next (&iter, &instance, &id);
361 #else
362 g_hash_table_find(table, (GHRFunc)find_first_item_in_hash_table, &instance);
363 #endif
364 return instance;
365}
366
367// Functions prefixed by ITNP_ are instance functions. They are called
368// by the browser and operate on instances of ITNPPluginData.
369// Functions prefixed by plugin_ are static helper functions.
370// Functions prefixed by NP_ are factory functions. They are called
371// by the browser and provide functionality needed to create plugin
372// instances.
373
374// INSTANCE FUNCTIONS
375
376// Creates a new icedtea np plugin instance. This function creates a
377// ITNPPluginData* and stores it in instance->pdata. The following
378// ITNPPluginData fields are initialized: instance_id, in_pipe_name,
379// in_from_appletviewer, in_watch_source, out_pipe_name,
380// out_to_appletviewer, out_watch_source, appletviewer_mutex, owner,
381// appletviewer_alive. In addition two pipe files are created. All
382// of those fields must be properly destroyed, and the pipes deleted,
383// by ITNP_Destroy. If an error occurs during initialization then this
384// function will free anything that's been allocated so far, set
385// instance->pdata to NULL and return an error code.
386NPError
387ITNP_New (NPMIMEType pluginType, NPP instance, uint16_t mode,
388 int16_t argc, char* argn[], char* argv[],
389 NPSavedData* saved)
390{
391 PLUGIN_DEBUG("ITNP_New\n");
392
393 static NPObject *window_ptr;
394 NPIdentifier identifier;
395 NPVariant member_ptr;
396 browser_functions.getvalue(instance, NPNVWindowNPObject, &window_ptr);
397 identifier = browser_functions.getstringidentifier("document");
398 if (!browser_functions.hasproperty(instance, window_ptr, identifier))
399 {
400 PLUGIN_ERROR("%s not found!\n", "document");
401 }
402 browser_functions.getproperty(instance, window_ptr, identifier, &member_ptr);
403
404 PLUGIN_DEBUG("Got variant %p\n", &member_ptr);
405
406 if (!instance)
407 {
408 PLUGIN_ERROR ("Browser-provided instance pointer is NULL.\n");
409 return NPERR_INVALID_INSTANCE_ERROR;
410 }
411
412 // data
413 ITNPPluginData* data = plugin_data_new ();
414 if (data == NULL)
415 {
416 PLUGIN_ERROR ("Failed to allocate plugin data.\n");
417 return NPERR_OUT_OF_MEMORY_ERROR;
418 }
419
420 // start the jvm if needed
421 NPError startup_error = start_jvm_if_needed();
422 if (startup_error != NPERR_NO_ERROR) {
423 PLUGIN_ERROR ("Failed to start JVM\n");
424 return startup_error;
425 }
426
427 // Initialize data->instance_id.
428 //
429 // instance_id should be unique for this process so we use a
430 // combination of getpid and plugin_instance_counter.
431 //
432 // Critical region. Reference and increment plugin_instance_counter
433 // global.
434 g_mutex_lock (plugin_instance_mutex);
435
436 // data->instance_id
437 data->instance_id = g_strdup_printf ("%d",
438 instance_counter);
439
440 g_mutex_unlock (plugin_instance_mutex);
441
442 // data->appletviewer_mutex
443 data->appletviewer_mutex = g_mutex_new ();
444
445 g_mutex_lock (data->appletviewer_mutex);
446
447 std::string documentbase = plugin_get_documentbase (instance);
448 // Documentbase retrieval.
449 if (argc != 0)
450 {
451 // Send parameters to appletviewer.
452 std::string params_string = plugin_parameters_string(argc, argn, argv);
453
454 data->parameters_string = g_strdup_printf("tag %s %s", documentbase.c_str(), params_string.c_str());
455
456 data->is_applet_instance = true;
457 }
458 else
459 {
460 data->is_applet_instance = false;
461 }
462
463 g_mutex_unlock (data->appletviewer_mutex);
464
465 // If initialization succeeded entirely then we store the plugin
466 // data in the instance structure and return. Otherwise we free the
467 // data we've allocated so far and set instance->pdata to NULL.
468
469 // Set back-pointer to owner instance.
470 data->owner = instance;
471
472 // source of this instance
473 // don't use documentbase, it is cleared later
474 data->source = plugin_get_documentbase(instance);
475
476 instance->pdata = data;
477
478 // store an identifier for this plugin
479 PLUGIN_DEBUG("Mapping id %d and instance %p\n", instance_counter, instance);
480 g_hash_table_insert(instance_to_id_map, instance, GINT_TO_POINTER(instance_counter));
481 g_hash_table_insert(id_to_instance_map, GINT_TO_POINTER(instance_counter), instance);
482 instance_counter++;
483
484 PLUGIN_DEBUG ("ITNP_New return\n");
485
486 return NPERR_NO_ERROR;
487}
488
489// Starts the JVM if it is not already running
490NPError start_jvm_if_needed()
491{
492
493 // This is asynchronized function. It must
494 // have exclusivity when running.
495
496 GMutex *vm_start_mutex = g_mutex_new();
497 g_mutex_lock(vm_start_mutex);
498
499 PLUGIN_DEBUG("Checking JVM status...\n");
500
501 // If the jvm is already up, do nothing
502 if (jvm_up)
503 {
504 PLUGIN_DEBUG("JVM is up. Returning.\n");
505 return NPERR_NO_ERROR;
506 }
507
508 PLUGIN_DEBUG("No JVM is running. Attempting to start one...\n");
509
510 NPError np_error = NPERR_NO_ERROR;
511 ITNPPluginData* data = NULL;
512
513 // Create appletviewer-to-plugin pipe which we refer to as the input
514 // pipe.
515
516#ifdef __OS2__
517 if (socketpair (AF_LOCAL, SOCK_STREAM, 0, in_pipe) == -1)
518 {
519 PLUGIN_ERROR ("Failed to create input pipe", strerror (errno));
520 np_error = NPERR_GENERIC_ERROR;
521 goto cleanup_in_pipe;
522 }
523 PLUGIN_DEBUG ("ITNP_New: created input fifo: %d/%d\n", in_pipe [0], in_pipe [1]);
524#else
525 // in_pipe_name
526 in_pipe_name = g_strdup_printf ("%s/%d-icedteanp-appletviewer-to-plugin",
527 data_directory.c_str(), getpid());
528 if (!in_pipe_name)
529 {
530 PLUGIN_ERROR ("Failed to create input pipe name.\n");
531 np_error = NPERR_OUT_OF_MEMORY_ERROR;
532 // If in_pipe_name is NULL then the g_free at
533 // cleanup_in_pipe_name will simply return.
534 goto cleanup_in_pipe_name;
535 }
536
537 // clean up any older pip
538 unlink (in_pipe_name);
539
540 PLUGIN_DEBUG ("ITNP_New: creating input fifo: %s\n", in_pipe_name);
541 if (mkfifo (in_pipe_name, 0600) == -1 && errno != EEXIST)
542 {
543 PLUGIN_ERROR ("Failed to create input pipe\n", strerror (errno));
544 np_error = NPERR_GENERIC_ERROR;
545 goto cleanup_in_pipe_name;
546 }
547 PLUGIN_DEBUG ("ITNP_New: created input fifo: %s\n", in_pipe_name);
548#endif
549
550 // Create plugin-to-appletviewer pipe which we refer to as the
551 // output pipe.
552
553#ifdef __OS2__
554 if (socketpair (AF_LOCAL, SOCK_STREAM, 0, out_pipe) == -1)
555 {
556 PLUGIN_ERROR ("Failed to create output pipe", strerror (errno));
557 np_error = NPERR_GENERIC_ERROR;
558 goto cleanup_out_pipe;
559 }
560 PLUGIN_DEBUG ("ITNP_New: created output fifo: %d/%d\n", out_pipe [0], out_pipe [1]);
561#else
562 // out_pipe_name
563 out_pipe_name = g_strdup_printf ("%s/%d-icedteanp-plugin-to-appletviewer",
564 data_directory.c_str(), getpid());
565
566 if (!out_pipe_name)
567 {
568 PLUGIN_ERROR ("Failed to create output pipe name.\n");
569 np_error = NPERR_OUT_OF_MEMORY_ERROR;
570 goto cleanup_out_pipe_name;
571 }
572
573 // clean up any older pip
574 unlink (out_pipe_name);
575
576 PLUGIN_DEBUG ("ITNP_New: creating output fifo: %s\n", out_pipe_name);
577 if (mkfifo (out_pipe_name, 0600) == -1 && errno != EEXIST)
578 {
579 PLUGIN_ERROR ("Failed to create output pipe\n", strerror (errno));
580 np_error = NPERR_GENERIC_ERROR;
581 goto cleanup_out_pipe_name;
582 }
583 PLUGIN_DEBUG ("ITNP_New: created output fifo: %s\n", out_pipe_name);
584#endif
585
586 // Create plugin-debug-to-appletviewer pipe which we refer to as the
587 // debug pipe.
588 initialize_debug();//should be already initialized, but...
589 if (plugin_debug_to_console){
590 // debug_pipe_name
591 debug_pipe_name = g_strdup_printf ("%s/%d-icedteanp-plugin-debug-to-appletviewer",
592 data_directory.c_str(), getpid());
593
594 if (!debug_pipe_name)
595 {
596 PLUGIN_ERROR ("Failed to create debug pipe name.\n");
597 np_error = NPERR_OUT_OF_MEMORY_ERROR;
598 goto cleanup_debug_pipe_name;
599 }
600
601 // clean up any older pip
602 unlink (debug_pipe_name);
603
604 PLUGIN_DEBUG ("ITNP_New: creating debug fifo: %s\n", debug_pipe_name);
605 if (mkfifo (debug_pipe_name, 0600) == -1 && errno != EEXIST)
606 {
607 PLUGIN_ERROR ("Failed to create debug pipe\n", strerror (errno));
608 np_error = NPERR_GENERIC_ERROR;
609 goto cleanup_debug_pipe_name;
610 }
611 PLUGIN_DEBUG ("ITNP_New: created debug fifo: %s\n", debug_pipe_name);
612 }
613
614 // Start a separate appletviewer process for each applet, even if
615 // there are multiple applets in the same page. We may need to
616 // change this behaviour if we find pages with multiple applets that
617 // rely on being run in the same VM.
618
619#ifdef __OS2__
620 // make sure parent ends are not inherited by the child (otherwise read() on
621 // the child's side will not be aborted when the parent closes its end)
622 fcntl (in_pipe [0], F_SETFD, FD_CLOEXEC);
623 fcntl (out_pipe [0], F_SETFD, FD_CLOEXEC);
624#endif
625
626 np_error = plugin_start_appletviewer (data);
627
628#ifdef __OS2__
629 // close child ends of the pipes (not needed)
630 CLOSE_FD (in_pipe [1]);
631 CLOSE_FD (out_pipe [1]);
632#endif
633
634 // Create plugin-to-appletviewer channel. The default encoding for
635 // the file is UTF-8.
636 // out_to_appletviewer
637#ifdef __OS2__
638 out_to_appletviewer = g_io_channel_unix_new (out_pipe [0]);
639#else
640 out_to_appletviewer = g_io_channel_new_file (out_pipe_name,
641 "w", &channel_error);
642#endif
643 if (!out_to_appletviewer)
644 {
645 if (channel_error)
646 {
647 PLUGIN_ERROR ("Failed to create output channel, '%s'\n",
648 channel_error->message);
649 g_error_free (channel_error);
650 channel_error = NULL;
651 }
652 else
653 PLUGIN_ERROR ("Failed to create output channel\n");
654
655 np_error = NPERR_GENERIC_ERROR;
656 goto cleanup_out_to_appletviewer;
657 }
658
659 // Watch for hangup and error signals on the output pipe.
660 out_watch_source =
661 g_io_add_watch (out_to_appletviewer,
662 (GIOCondition) (G_IO_ERR | G_IO_HUP),
663 plugin_out_pipe_callback, (gpointer) out_to_appletviewer);
664
665 // Create appletviewer-to-plugin channel. The default encoding for
666 // the file is UTF-8.
667 // in_from_appletviewer
668#ifdef __OS2__
669 in_from_appletviewer = g_io_channel_unix_new (in_pipe [0]);
670#else
671 in_from_appletviewer = g_io_channel_new_file (in_pipe_name,
672 "r", &channel_error);
673#endif
674 if (!in_from_appletviewer)
675 {
676 if (channel_error)
677 {
678 PLUGIN_ERROR ("Failed to create input channel, '%s'\n",
679 channel_error->message);
680 g_error_free (channel_error);
681 channel_error = NULL;
682 }
683 else
684 PLUGIN_ERROR ("Failed to create input channel\n");
685
686 np_error = NPERR_GENERIC_ERROR;
687 goto cleanup_in_from_appletviewer;
688 }
689
690 // Watch for hangup and error signals on the input pipe.
691 in_watch_source =
692 g_io_add_watch (in_from_appletviewer,
693 (GIOCondition) (G_IO_IN | G_IO_ERR | G_IO_HUP),
694 plugin_in_pipe_callback, (gpointer) in_from_appletviewer);
695
696 // Create plugin-to-appletviewer console debug channel. The default encoding for
697 // the file is UTF-8.
698 // debug_to_appletviewer
699 if (plugin_debug_to_console){
700 debug_to_appletviewer = g_io_channel_new_file (debug_pipe_name,
701 "w", &channel_error);
702 if (!debug_to_appletviewer)
703 {
704 if (channel_error)
705 {
706 PLUGIN_ERROR ("Failed to debug output channel, '%s'\n",
707 channel_error->message);
708 g_error_free (channel_error);
709 channel_error = NULL;
710 }
711 else
712 PLUGIN_ERROR ("Failed to create debug channel\n");
713
714 np_error = NPERR_GENERIC_ERROR;
715 goto cleanup_debug_to_appletviewer;
716 }
717 }
718
719 jvm_up = TRUE;
720
721 if (plugin_debug_to_console){
722 //jvm is up, we can start console producer thread
723 pthread_t debug_to_console_consumer;
724 pthread_create(&debug_to_console_consumer,NULL,&flush_pre_init_messages,NULL);
725 }
726 goto done;
727
728 // Free allocated data in case of error
729 cleanup_debug_to_appletviewer:
730 if (plugin_debug_to_console){
731 if (debug_to_appletviewer)
732 g_io_channel_unref (debug_to_appletviewer);
733 debug_to_appletviewer = NULL;
734 }
735
736 cleanup_in_watch_source:
737 // Removing a source is harmless if it fails since it just means the
738 // source has already been removed.
739 g_source_remove (in_watch_source);
740 in_watch_source = 0;
741
742 cleanup_in_from_appletviewer:
743 if (in_from_appletviewer)
744 g_io_channel_unref (in_from_appletviewer);
745 in_from_appletviewer = NULL;
746
747 // cleanup_out_watch_source:
748 g_source_remove (out_watch_source);
749 out_watch_source = 0;
750
751 cleanup_out_to_appletviewer:
752 if (out_to_appletviewer)
753 g_io_channel_unref (out_to_appletviewer);
754 out_to_appletviewer = NULL;
755
756 if (plugin_debug_to_console){
757 // cleanup_debug_pipe:
758 // Delete output pipe.
759 PLUGIN_DEBUG ("ITNP_New: deleting debug fifo: %s\n", debug_pipe_name);
760 unlink (debug_pipe_name);
761 PLUGIN_DEBUG ("ITNP_New: deleted debug fifo: %s\n", debug_pipe_name);
762 }
763 cleanup_debug_pipe_name:
764 if (plugin_debug_to_console){
765 g_free (debug_pipe_name);
766 debug_pipe_name = NULL;
767 }
768
769
770
771 // cleanup_out_pipe:
772#ifdef __OS2__
773 cleanup_out_pipe:
774 CLOSE_FD (out_pipe [0]);
775 CLOSE_FD (out_pipe [1]);
776#else
777 // Delete output pipe.
778 PLUGIN_DEBUG ("ITNP_New: deleting output fifo: %s\n", out_pipe_name);
779 unlink (out_pipe_name);
780 PLUGIN_DEBUG ("ITNP_New: deleted output fifo: %s\n", out_pipe_name);
781
782 cleanup_out_pipe_name:
783 g_free (out_pipe_name);
784 out_pipe_name = NULL;
785#endif
786
787 // cleanup_in_pipe:
788#ifdef __OS2__
789 cleanup_in_pipe:
790 CLOSE_FD (in_pipe [0]);
791 CLOSE_FD (in_pipe [1]);
792#else
793 // Delete input pipe.
794 PLUGIN_DEBUG ("ITNP_New: deleting input fifo: %s\n", in_pipe_name);
795 unlink (in_pipe_name);
796 PLUGIN_DEBUG ("ITNP_New: deleted input fifo: %s\n", in_pipe_name);
797
798 cleanup_in_pipe_name:
799 g_free (in_pipe_name);
800 in_pipe_name = NULL;
801#endif
802
803 cleanUpDir();
804 done:
805
806 IcedTeaPluginUtilities::printDebugStatus();
807 // Now other threads may re-enter.. unlock the mutex
808 g_mutex_unlock(vm_start_mutex);
809 return np_error;
810
811}
812
813NPError
814ITNP_GetValue (NPP instance, NPPVariable variable, void* value)
815{
816 PLUGIN_DEBUG ("ITNP_GetValue\n");
817
818 NPError np_error = NPERR_NO_ERROR;
819
820 switch (variable)
821 {
822 // This plugin needs XEmbed support.
823 case NPPVpluginNeedsXEmbed:
824 {
825 PLUGIN_DEBUG ("ITNP_GetValue: returning TRUE for NeedsXEmbed.\n");
826 bool* bool_value = (bool*) value;
827 *bool_value = true;
828 }
829 break;
830 case NPPVpluginScriptableNPObject:
831 {
832 *(NPObject **)value = get_scriptable_object(instance);
833 }
834 break;
835 default:
836 PLUGIN_ERROR ("Unknown plugin value requested.\n");
837 np_error = NPERR_GENERIC_ERROR;
838 break;
839 }
840
841 PLUGIN_DEBUG ("ITNP_GetValue return\n");
842
843 return np_error;
844}
845
846NPError
847ITNP_Destroy (NPP instance, NPSavedData** save)
848{
849 PLUGIN_DEBUG ("ITNP_Destroy %p\n", instance);
850
851 ITNPPluginData* data = (ITNPPluginData*) instance->pdata;
852
853 int id = get_id_from_instance(instance);
854
855 // Let Java know that this applet needs to be destroyed
856 gchar* msg = (gchar*) g_malloc(512*sizeof(gchar)); // 512 is more than enough. We need < 100
857 g_sprintf(msg, "instance %d destroy", id);
858 plugin_send_message_to_appletviewer(msg);
859 g_free(msg);
860 msg = NULL;
861
862 if (data)
863 {
864 // Free plugin data.
865 plugin_data_destroy (instance);
866 }
867
868 g_hash_table_remove(instance_to_id_map, instance);
869 g_hash_table_remove(id_to_instance_map, GINT_TO_POINTER(id));
870
871 IcedTeaPluginUtilities::invalidateInstance(instance);
872
873 PLUGIN_DEBUG ("ITNP_Destroy return\n");
874
875 return NPERR_NO_ERROR;
876}
877
878NPError
879ITNP_SetWindow (NPP instance, NPWindow* window)
880{
881 PLUGIN_DEBUG ("ITNP_SetWindow\n");
882
883 if (instance == NULL)
884 {
885 PLUGIN_ERROR ("Invalid instance.\n");
886
887 return NPERR_INVALID_INSTANCE_ERROR;
888 }
889
890 gpointer id_ptr = g_hash_table_lookup(instance_to_id_map, instance);
891
892 gint id = 0;
893 if (id_ptr)
894 {
895 id = GPOINTER_TO_INT(id_ptr);
896 }
897
898 ITNPPluginData* data = (ITNPPluginData*) instance->pdata;
899
900 // Simply return if we receive a NULL window.
901 if ((window == NULL) || (window->window == NULL))
902 {
903 PLUGIN_DEBUG ("ITNP_SetWindow: got NULL window.\n");
904
905 return NPERR_NO_ERROR;
906 }
907
908#ifdef __OS2__
909 void *wnd = wrap_window_handle (window->window);
910 if (!wnd)
911 return NPERR_GENERIC_ERROR;
912
913 PLUGIN_DEBUG ("ITNP_SetWindow: wrapped window handle %d (%x) in %d (%x)\n",
914 window->window, window->window, wnd, wnd);
915#endif
916
917 if (data->window_handle)
918 {
919 // The window already exists.
920 if (data->window_handle == wnd)
921 {
922 // The parent window is the same as in previous calls.
923 PLUGIN_DEBUG ("ITNP_SetWindow: window already exists.\n");
924
925 // Critical region. Read data->appletviewer_mutex and send
926 // a message to the appletviewer.
927 g_mutex_lock (data->appletviewer_mutex);
928
929 if (jvm_up)
930 {
931 gboolean dim_changed = FALSE;
932
933 // The window is the same as it was for the last
934 // SetWindow call.
935 if (window->width != data->window_width)
936 {
937 PLUGIN_DEBUG ("ITNP_SetWindow: window width changed.\n");
938 // The width of the plugin window has changed.
939
940 // Store the new width.
941 data->window_width = window->width;
942 dim_changed = TRUE;
943 }
944
945 if (window->height != data->window_height)
946 {
947 PLUGIN_DEBUG ("ITNP_SetWindow: window height changed.\n");
948 // The height of the plugin window has changed.
949
950 // Store the new height.
951 data->window_height = window->height;
952
953 dim_changed = TRUE;
954 }
955
956 if (dim_changed) {
957 gchar* message = g_strdup_printf ("instance %d width %d height %d",
958 id, window->width, window->height);
959 plugin_send_message_to_appletviewer (message);
960 g_free (message);
961 message = NULL;
962 }
963
964
965 }
966 else
967 {
968 // The appletviewer is not running.
969 PLUGIN_DEBUG ("ITNP_SetWindow: appletviewer is not running.\n");
970 }
971
972 g_mutex_unlock (data->appletviewer_mutex);
973 }
974 else
975 {
976 // The parent window has changed. This branch does run but
977 // doing nothing in response seems to be sufficient.
978 PLUGIN_DEBUG ("ITNP_SetWindow: parent window changed.\n");
979 }
980 }
981 else
982 {
983
984 // Else this is initialization
985 PLUGIN_DEBUG ("ITNP_SetWindow: setting window.\n");
986
987 // Critical region. Send messages to appletviewer.
988 g_mutex_lock (data->appletviewer_mutex);
989
990 // Store the window handle and dimensions
991 data->window_handle = wnd;
992 data->window_width = window->width;
993 data->window_height = window->height;
994
995 // Now we have everything. Send this data to the Java side
996 plugin_send_initialization_message(
997 data->instance_id, (gulong) data->window_handle,
998 data->window_width, data->window_height, data->parameters_string);
999
1000 g_mutex_unlock (data->appletviewer_mutex);
1001
1002 }
1003
1004 PLUGIN_DEBUG ("ITNP_SetWindow return\n");
1005
1006 return NPERR_NO_ERROR;
1007}
1008
1009NPError
1010ITNP_NewStream (NPP instance, NPMIMEType type, NPStream* stream,
1011 NPBool seekable, uint16_t* stype)
1012{
1013 PLUGIN_DEBUG ("ITNP_NewStream\n");
1014
1015 PLUGIN_DEBUG ("ITNP_NewStream return\n");
1016
1017 return NPERR_GENERIC_ERROR;
1018}
1019
1020void
1021ITNP_StreamAsFile (NPP instance, NPStream* stream, const char* filename)
1022{
1023 PLUGIN_DEBUG ("ITNP_StreamAsFile\n");
1024
1025 PLUGIN_DEBUG ("ITNP_StreamAsFile return\n");
1026}
1027
1028NPError
1029ITNP_DestroyStream (NPP instance, NPStream* stream, NPReason reason)
1030{
1031 PLUGIN_DEBUG ("ITNP_DestroyStream\n");
1032
1033 PLUGIN_DEBUG ("ITNP_DestroyStream return\n");
1034
1035 return NPERR_NO_ERROR;
1036}
1037
1038int32_t
1039ITNP_WriteReady (NPP instance, NPStream* stream)
1040{
1041 PLUGIN_DEBUG ("ITNP_WriteReady\n");
1042
1043 PLUGIN_DEBUG ("ITNP_WriteReady return\n");
1044
1045 return 0;
1046}
1047
1048int32_t
1049ITNP_Write (NPP instance, NPStream* stream, int32_t offset, int32_t len,
1050 void* buffer)
1051{
1052 PLUGIN_DEBUG ("ITNP_Write\n");
1053
1054 PLUGIN_DEBUG ("ITNP_Write return\n");
1055
1056 return 0;
1057}
1058
1059void
1060ITNP_Print (NPP instance, NPPrint* platformPrint)
1061{
1062 PLUGIN_DEBUG ("ITNP_Print\n");
1063
1064 PLUGIN_DEBUG ("ITNP_Print return\n");
1065}
1066
1067int16_t
1068ITNP_HandleEvent (NPP instance, void* event)
1069{
1070 PLUGIN_DEBUG ("ITNP_HandleEvent\n");
1071
1072 PLUGIN_DEBUG ("ITNP_HandleEvent return\n");
1073
1074 return 0;
1075}
1076
1077void
1078ITNP_URLNotify (NPP instance, const char* url, NPReason reason,
1079 void* notifyData)
1080{
1081 PLUGIN_DEBUG ("ITNP_URLNotify\n");
1082
1083 PLUGIN_DEBUG ("ITNP_URLNotify return\n");
1084}
1085
1086NPError
1087get_cookie_info(const char* siteAddr, char** cookieString, uint32_t* len)
1088{
1089 // Only attempt to perform this operation if there is a valid plugin instance
1090 if (g_hash_table_size(instance_to_id_map) <= 0)
1091 {
1092 return NPERR_GENERIC_ERROR;
1093 }
1094 // getvalueforurl needs an NPP instance. Quite frankly, there is no easy way
1095 // to know which instance needs the information, as applets on Java side can
1096 // be multi-threaded and the thread making a proxy.cookie request cannot be
1097 // easily tracked.
1098
1099 // Fortunately, XULRunner does not care about the instance as long as it is
1100 // valid. So we just pick the first valid one and use it. Proxy/Cookie
1101 // information is not instance specific anyway, it is URL specific.
1102
1103 if (browser_functions.getvalueforurl)
1104 {
1105 gpointer instance=getFirstInTableInstance(instance_to_id_map);
1106 return browser_functions.getvalueforurl((NPP) instance, NPNURLVCookie, siteAddr, cookieString, len);
1107 } else
1108 {
1109 return NPERR_GENERIC_ERROR;
1110 }
1111
1112 return NPERR_NO_ERROR;
1113}
1114
1115static NPError
1116set_cookie_info(const char* siteAddr, const char* cookieString, uint32_t len)
1117{
1118 // Only attempt to perform this operation if there is a valid plugin instance
1119 if (g_hash_table_size(instance_to_id_map) > 0 && browser_functions.getvalueforurl)
1120 {
1121 // We arbitrarily use the first valid instance we can grab
1122 // For an explanation of the logic behind this, see get_cookie_info
1123 gpointer instance = getFirstInTableInstance(instance_to_id_map);
1124 return browser_functions.setvalueforurl((NPP) instance, NPNURLVCookie, siteAddr, cookieString, len);
1125 }
1126
1127 return NPERR_GENERIC_ERROR;;
1128}
1129
1130// HELPER FUNCTIONS
1131
1132ITNPPluginData*
1133plugin_data_new ()
1134{
1135 PLUGIN_DEBUG ("plugin_data_new\n");
1136
1137 ITNPPluginData* data = (ITNPPluginData*)browser_functions.memalloc(sizeof (struct ITNPPluginData));
1138
1139 if (data)
1140 {
1141 // Call constructor on allocated data
1142 new (data) ITNPPluginData();
1143 }
1144 PLUGIN_DEBUG ("plugin_data_new return\n");
1145
1146 return data;
1147}
1148
1149
1150
1151// Documentbase retrieval. This function gets the current document's
1152// documentbase. This function relies on browser-private data so it
1153// will only work when the plugin is loaded in a Mozilla-based
1154// browser.
1155static std::string
1156plugin_get_documentbase (NPP instance)
1157{
1158 PLUGIN_DEBUG ("plugin_get_documentbase\n");
1159
1160 // FIXME: This method is not ideal, but there are no known NPAPI call
1161 // for this. See thread for more information:
1162 // http://www.mail-archive.com/chromium-dev@googlegroups.com/msg04844.html
1163
1164 // Additionally, since it is insecure, we cannot use it for making
1165 // security decisions.
1166 NPObject* window;
1167 browser_functions.getvalue(instance, NPNVWindowNPObject, &window);
1168
1169 NPVariant location;
1170 NPIdentifier location_id = browser_functions.getstringidentifier("location");
1171 browser_functions.getproperty(instance, window, location_id, &location);
1172
1173 NPVariant href;
1174 NPIdentifier href_id = browser_functions.getstringidentifier("href");
1175 browser_functions.getproperty(instance, NPVARIANT_TO_OBJECT(location),
1176 href_id, &href);
1177
1178 std::string href_str = IcedTeaPluginUtilities::NPVariantAsString(href);
1179
1180 // Release references.
1181 browser_functions.releasevariantvalue(&href);
1182 browser_functions.releasevariantvalue(&location);
1183
1184 PLUGIN_DEBUG ("plugin_get_documentbase return\n");
1185 PLUGIN_DEBUG("plugin_get_documentbase returning: %s\n", href_str.c_str());
1186
1187 return href_str;
1188}
1189
1190// plugin_in_pipe_callback is called when data is available on the
1191// input pipe, or when the appletviewer crashes or is killed. It may
1192// be called after data has been destroyed in which case it simply
1193// returns FALSE to remove itself from the glib main loop.
1194static gboolean
1195plugin_in_pipe_callback (GIOChannel* source,
1196 GIOCondition condition,
1197 gpointer plugin_data)
1198{
1199 PLUGIN_DEBUG ("plugin_in_pipe_callback\n");
1200
1201 gboolean keep_installed = TRUE;
1202
1203 if (condition & G_IO_IN)
1204 {
1205 gchar* message = NULL;
1206
1207 if (g_io_channel_read_line (in_from_appletviewer,
1208 &message, NULL, NULL,
1209 &channel_error)
1210 != G_IO_STATUS_NORMAL)
1211 {
1212 if (channel_error)
1213 {
1214 PLUGIN_ERROR ("Failed to read line from input channel, %s\n",
1215 channel_error->message);
1216 g_error_free (channel_error);
1217 channel_error = NULL;
1218 }
1219 else
1220 PLUGIN_ERROR ("Failed to read line from input channel\n");
1221#ifdef __OS2__
1222 // G_IO_ERR/HUP is not reported on file/pipe handles, simulate it
1223 condition = (GIOCondition) (condition | G_IO_ERR);
1224#endif
1225 } else
1226 {
1227 consume_message(message);
1228 }
1229
1230 g_free (message);
1231 message = NULL;
1232
1233 keep_installed = TRUE;
1234 }
1235
1236 if (condition & (G_IO_ERR | G_IO_HUP))
1237 {
1238 PLUGIN_DEBUG ("appletviewer has stopped.\n");
1239 keep_installed = FALSE;
1240 }
1241
1242 PLUGIN_DEBUG ("plugin_in_pipe_callback return\n");
1243
1244 return keep_installed;
1245}
1246
1247static
1248void consume_plugin_message(gchar* message) {
1249 // internal plugin related message
1250 gchar** parts = g_strsplit (message, " ", 5);
1251 if (g_str_has_prefix(parts[1], "PluginProxyInfo"))
1252 {
1253 gchar* proxy = NULL;
1254 uint32_t len;
1255
1256 gchar* decoded_url = (gchar*) calloc(strlen(parts[4]) + 1, sizeof(gchar));
1257 IcedTeaPluginUtilities::decodeURL(parts[4], &decoded_url);
1258 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);
1259
1260 gchar* proxy_info;
1261
1262 proxy_info = g_strconcat ("plugin PluginProxyInfo reference ", parts[3], " ", NULL);
1263 if (get_proxy_info(decoded_url, &proxy, &len) == NPERR_NO_ERROR)
1264 {
1265 proxy_info = g_strconcat (proxy_info, proxy, NULL);
1266 }
1267
1268 PLUGIN_DEBUG("Proxy info: %s\n", proxy_info);
1269 plugin_send_message_to_appletviewer(proxy_info);
1270
1271 free(decoded_url);
1272 decoded_url = NULL;
1273 g_free(proxy_info);
1274 proxy_info = NULL;
1275
1276 g_free(proxy);
1277 proxy = NULL;
1278
1279 } else if (g_str_has_prefix(parts[1], "PluginCookieInfo"))
1280 {
1281 gchar* decoded_url = (gchar*) calloc(strlen(parts[4])+1, sizeof(gchar));
1282 IcedTeaPluginUtilities::decodeURL(parts[4], &decoded_url);
1283
1284 gchar* cookie_info = g_strconcat ("plugin PluginCookieInfo reference ", parts[3], " ", NULL);
1285 gchar* cookie_string = NULL;
1286 uint32_t len;
1287 if (get_cookie_info(decoded_url, &cookie_string, &len) == NPERR_NO_ERROR)
1288 {
1289 cookie_info = g_strconcat (cookie_info, cookie_string, NULL);
1290 }
1291
1292 PLUGIN_DEBUG("Cookie info: %s\n", cookie_info);
1293 plugin_send_message_to_appletviewer(cookie_info);
1294
1295 free(decoded_url);
1296 decoded_url = NULL;
1297 g_free(cookie_info);
1298 cookie_info = NULL;
1299 g_free(cookie_string);
1300 cookie_string = NULL;
1301 } else if (g_str_has_prefix(parts[1], "PluginSetCookie"))
1302 {
1303 // Message structure: plugin PluginSetCookie reference -1 <url> <cookie>
1304 gchar** cookie_parts = g_strsplit (message, " ", 6);
1305
1306 if (g_strv_length(cookie_parts) < 6)
1307 {
1308 g_strfreev (parts);
1309 g_strfreev (cookie_parts);
1310 return; // Defensive, message _should_ be properly formatted
1311 }
1312
1313 gchar* decoded_url = (gchar*) calloc(strlen(cookie_parts[4])+1, sizeof(gchar));
1314 IcedTeaPluginUtilities::decodeURL(cookie_parts[4], &decoded_url);
1315
1316 gchar* cookie_string = cookie_parts[5];
1317 uint32_t len = strlen(cookie_string);
1318 if (set_cookie_info(decoded_url, cookie_string, len) == NPERR_NO_ERROR)
1319 {
1320 PLUGIN_DEBUG("Setting cookie for URL %s to %s\n", decoded_url, cookie_string);
1321 } else
1322 {
1323 PLUGIN_DEBUG("Not able to set cookie for URL %s to %s\n", decoded_url, cookie_string);
1324 }
1325
1326 free(decoded_url);
1327 decoded_url = NULL;
1328 g_strfreev (cookie_parts);
1329 cookie_parts = NULL;
1330 }
1331
1332 g_strfreev (parts);
1333 parts = NULL;
1334}
1335
1336void consume_message(gchar* message) {
1337
1338 PLUGIN_DEBUG (" PIPE: plugin read: %s\n", message);
1339
1340 if (g_str_has_prefix (message, "instance"))
1341 {
1342
1343 ITNPPluginData* data;
1344 gchar** parts = g_strsplit (message, " ", -1);
1345 guint parts_sz = g_strv_length (parts);
1346
1347 int instance_id = atoi(parts[1]);
1348 NPP instance = (NPP) g_hash_table_lookup(id_to_instance_map,
1349 GINT_TO_POINTER(instance_id));
1350
1351 if (instance_id > 0 && !instance)
1352 {
1353 PLUGIN_DEBUG("Instance %d is not active. Refusing to consume message \"%s\"\n", instance_id, message);
1354 return;
1355 }
1356 else if (instance)
1357 {
1358 data = (ITNPPluginData*) instance->pdata;
1359 }
1360
1361 if (g_str_has_prefix (parts[2], "status"))
1362 {
1363
1364 // clear the "instance X status" parts
1365 strcpy(parts[0], "");
1366 strcpy(parts[1], "");
1367 strcpy(parts[2], "");
1368
1369 // join the rest
1370 gchar* status_message = g_strjoinv(" ", parts);
1371 PLUGIN_DEBUG ("plugin_in_pipe_callback: setting status %s\n", status_message);
1372 (*browser_functions.status) (data->owner, status_message);
1373
1374 g_free(status_message);
1375 status_message = NULL;
1376 }
1377 else if (g_str_has_prefix (parts[1], "internal"))
1378 {
1379 //s->post(message);
1380 }
1381 else
1382 {
1383 // All other messages are posted to the bus, and subscribers are
1384 // expected to take care of them. They better!
1385
1386 java_to_plugin_bus->post(message);
1387 }
1388
1389 g_strfreev (parts);
1390 parts = NULL;
1391 }
1392 else if (g_str_has_prefix (message, "context"))
1393 {
1394 java_to_plugin_bus->post(message);
1395 }
1396 else if (g_str_has_prefix (message, "plugin "))
1397 {
1398 consume_plugin_message(message);
1399 }
1400 else
1401 {
1402 g_print (" Unable to handle message: %s\n", message);
1403 }
1404
1405}
1406
1407void get_instance_from_id(int id, NPP& instance)
1408{
1409 instance = (NPP) g_hash_table_lookup(id_to_instance_map,
1410 GINT_TO_POINTER(id));
1411}
1412
1413int get_id_from_instance(NPP instance)
1414{
1415 int id = GPOINTER_TO_INT(g_hash_table_lookup(instance_to_id_map,
1416 instance));
1417 PLUGIN_DEBUG("Returning id %d for instance %p\n", id, instance);
1418 return id;
1419}
1420
1421NPError
1422get_proxy_info(const char* siteAddr, char** proxy, uint32_t* len)
1423{
1424 // Only attempt to perform this operation if there is a valid plugin instance
1425 if (g_hash_table_size(instance_to_id_map) <= 0)
1426 {
1427 return NPERR_GENERIC_ERROR;
1428 }
1429 if (browser_functions.getvalueforurl)
1430 {
1431
1432 // As in get_cookie_info, we use the first active instance
1433 gpointer instance=getFirstInTableInstance(instance_to_id_map);
1434 browser_functions.getvalueforurl((NPP) instance, NPNURLVProxy, siteAddr, proxy, len);
1435 } else
1436 {
1437 return NPERR_GENERIC_ERROR;
1438 }
1439
1440 return NPERR_NO_ERROR;
1441}
1442
1443// plugin_out_pipe_callback is called when the appletviewer crashes or
1444// is killed. It may be called after data has been destroyed in which
1445// case it simply returns FALSE to remove itself from the glib main
1446// loop.
1447static gboolean
1448plugin_out_pipe_callback (GIOChannel* source,
1449 GIOCondition condition,
1450 gpointer plugin_data)
1451{
1452 PLUGIN_DEBUG ("plugin_out_pipe_callback\n");
1453
1454 ITNPPluginData* data = (ITNPPluginData*) plugin_data;
1455
1456 PLUGIN_DEBUG ("plugin_out_pipe_callback: appletviewer has stopped.\n");
1457
1458 PLUGIN_DEBUG ("plugin_out_pipe_callback return\n");
1459
1460 return FALSE;
1461}
1462
1463// remove all components from LD_LIBRARY_PATH, which start with
1464// MOZILLA_FIVE_HOME; firefox has its own NSS based security provider,
1465// which conflicts with the one configured in nss.cfg.
1466static gchar*
1467plugin_filter_ld_library_path(gchar *path_old)
1468{
1469 gchar *moz_home = g_strdup (g_getenv ("MOZILLA_FIVE_HOME"));
1470 gchar *moz_prefix;
1471 gchar *path_new;
1472 gchar** components;
1473 int i1, i2;
1474
1475 if (moz_home == NULL || path_old == NULL || strlen (path_old) == 0)
1476 return path_old;
1477 if (g_str_has_suffix (moz_home, "/"))
1478 moz_home[strlen (moz_home - 1)] = '\0';
1479 moz_prefix = g_strconcat (moz_home, "/", NULL);
1480
1481 components = g_strsplit (path_old, ":", -1);
1482 for (i1 = 0, i2 = 0; components[i1] != NULL; i1++)
1483 {
1484 if (g_strcmp0 (components[i1], moz_home) == 0
1485 || g_str_has_prefix (components[i1], moz_home))
1486 components[i2] = components[i1];
1487 else
1488 components[i2++] = components[i1];
1489 }
1490 components[i2] = NULL;
1491
1492 if (i1 > i2)
1493 path_new = g_strjoinv (":", components);
1494 g_strfreev (components);
1495 g_free (moz_home);
1496 g_free (moz_prefix);
1497 g_free (path_old);
1498
1499 if (path_new == NULL || strlen (path_new) == 0)
1500 {
1501 PLUGIN_DEBUG("Unset LD_LIBRARY_PATH\n");
1502 return NULL;
1503 }
1504 else
1505 {
1506 PLUGIN_DEBUG ("Set LD_LIBRARY_PATH: %s\n", path_new);
1507 return path_new;
1508 }
1509}
1510
1511// build the environment to pass to the external plugin process
1512static gchar**
1513plugin_filter_environment(void)
1514{
1515 gchar **var_names = g_listenv();
1516 gchar **new_env = (gchar**) malloc(sizeof(gchar*) * (g_strv_length (var_names) + 1));
1517 int i_var, i_env;
1518
1519 for (i_var = 0, i_env = 0; var_names[i_var] != NULL; i_var++)
1520 {
1521 gchar *env_value = g_strdup (g_getenv (var_names[i_var]));
1522
1523 if (g_str_has_prefix (var_names[i_var], "LD_LIBRARY_PATH"))
1524 env_value = plugin_filter_ld_library_path (env_value);
1525 if (env_value != NULL)
1526 {
1527 new_env[i_env++] = g_strdup_printf ("%s=%s", var_names[i_var], env_value);
1528 g_free (env_value);
1529 }
1530 }
1531 new_env[i_env] = NULL;
1532 return new_env;
1533}
1534
1535static NPError
1536plugin_test_appletviewer ()
1537{
1538
1539 PLUGIN_DEBUG ("plugin_test_appletviewer: %s\n", get_plugin_executable().c_str());
1540 NPError error = NPERR_NO_ERROR;
1541
1542 gchar* command_line[3] = { NULL, NULL, NULL };
1543 gchar** environment;
1544
1545 command_line[0] = g_strdup (get_plugin_executable().c_str());
1546 command_line[1] = g_strdup("-version");
1547 command_line[2] = NULL;
1548
1549 environment = plugin_filter_environment();
1550
1551 if (!g_spawn_async (NULL, command_line, environment,
1552 (GSpawnFlags) 0,
1553 NULL, NULL, NULL, &channel_error))
1554 {
1555 if (channel_error)
1556 {
1557 PLUGIN_ERROR ("Failed to spawn applet viewer %s\n",
1558 channel_error->message);
1559 g_error_free (channel_error);
1560 channel_error = NULL;
1561 }
1562 else
1563 PLUGIN_ERROR ("Failed to spawn applet viewer\n");
1564 error = NPERR_GENERIC_ERROR;
1565 }
1566
1567 g_strfreev (environment);
1568
1569 g_free (command_line[0]);
1570 command_line[0] = NULL;
1571 g_free (command_line[1]);
1572 command_line[1] = NULL;
1573 g_free (command_line[2]);
1574 command_line[2] = NULL;
1575
1576 PLUGIN_DEBUG ("plugin_test_appletviewer return\n");
1577 return error;
1578}
1579
1580NPError
1581plugin_start_appletviewer (ITNPPluginData* data)
1582{
1583 PLUGIN_DEBUG ("plugin_start_appletviewer\n");
1584 NPError error = NPERR_NO_ERROR;
1585
1586 std::vector<std::string> command_line;
1587 gchar** environment = NULL;
1588 std::vector<std::string*>* jvm_args = get_jvm_args();
1589
1590 // Construct command line parameters
1591
1592 command_line.push_back(get_plugin_executable());
1593
1594 //Add JVM args to command_line
1595 for (int i = 0; i < jvm_args->size(); i++)
1596 {
1597 command_line.push_back(*jvm_args->at(i));
1598 }
1599
1600#ifdef __OS2__
1601 {
1602 std::string path = PLUGIN_BOOTCLASSPATH;
1603 static const std::string datadir = "@DATADIR@";
1604 size_t pos = 0;
1605 while ((pos = path.find(datadir, pos)) != std::string::npos) {
1606 path.replace(pos, datadir.length(), icedtea_web_data_dir());
1607 pos += datadir.length();
1608 }
1609 command_line.push_back(path);
1610 }
1611#else
1612 command_line.push_back(PLUGIN_BOOTCLASSPATH);
1613#endif
1614 // set the classpath to avoid using the default (cwd).
1615 command_line.push_back("-classpath");
1616 command_line.push_back(get_plugin_rt_jar());
1617
1618 // Enable coverage agent if we are running instrumented plugin
1619#ifdef COVERAGE_AGENT
1620 command_line.push_back(COVERAGE_AGENT);
1621#endif
1622
1623 if (plugin_debug)
1624 {
1625 command_line.push_back("-Xdebug");
1626 command_line.push_back("-Xnoagent");
1627
1628 //Debug flags
1629 std::string debug_flags = "-Xrunjdwp:transport="DT_SOCKET_DLL",address=8787,server=y,";
1630 debug_flags += plugin_debug_suspend ? "suspend=y" : "suspend=n";
1631 command_line.push_back(debug_flags);
1632 }
1633
1634 command_line.push_back("sun.applet.PluginMain");
1635#ifdef __OS2__
1636 command_line.push_back(static_cast<std::ostringstream &>(std::ostringstream() << out_pipe[1]).str());
1637 command_line.push_back(static_cast<std::ostringstream &>(std::ostringstream() << in_pipe[1]).str());
1638#else
1639 command_line.push_back(out_pipe_name);
1640 command_line.push_back(in_pipe_name);
1641#endif
1642 if (plugin_debug_to_console){
1643 command_line.push_back(debug_pipe_name);
1644 }
1645
1646 // Finished command line parameters
1647
1648 environment = plugin_filter_environment();
1649 std::vector<gchar*> vector_gchar = IcedTeaPluginUtilities::vectorStringToVectorGchar(&command_line);
1650 gchar **command_line_args = &vector_gchar[0];
1651
1652 if (!g_spawn_async (NULL, command_line_args, environment,
1653#ifdef __OS2__
1654 (GSpawnFlags) (G_SPAWN_LEAVE_DESCRIPTORS_OPEN | G_SPAWN_DO_NOT_REAP_CHILD),
1655#else
1656 (GSpawnFlags) G_SPAWN_DO_NOT_REAP_CHILD,
1657#endif
1658 NULL, NULL, &appletviewer_pid, &channel_error))
1659 {
1660 if (channel_error)
1661 {
1662 PLUGIN_ERROR ("Failed to spawn applet viewer %s\n",
1663 channel_error->message);
1664 g_error_free (channel_error);
1665 channel_error = NULL;
1666 }
1667 else
1668 PLUGIN_ERROR ("Failed to spawn applet viewer\n");
1669 error = NPERR_GENERIC_ERROR;
1670 }
1671
1672 // make sure we get an error rather than crash the browser when talking to the
1673 // jvm process if it dies unexpectedly (we do it here since g_spawn() is known
1674 // to reset SIGPIPE handler to SIG_DFL)
1675 signal (SIGPIPE, SIG_IGN);
1676
1677 //Free memory
1678 g_strfreev(environment);
1679 IcedTeaPluginUtilities::freeStringPtrVector(jvm_args);
1680 jvm_args = NULL;
1681 command_line_args = NULL;
1682
1683 if (appletviewer_pid)
1684 {
1685 PLUGIN_DEBUG("Initialized VM with pid=%d\n", appletviewer_pid);
1686 appletviewer_watch_id = g_child_watch_add(appletviewer_pid, (GChildWatchFunc) appletviewer_monitor, (gpointer) appletviewer_pid);
1687 }
1688
1689
1690 PLUGIN_DEBUG ("plugin_start_appletviewer return\n");
1691 return error;
1692}
1693
1694/*
1695 * Returns JVM options set in itw-settings
1696 */
1697std::vector<std::string*>*
1698get_jvm_args()
1699{
1700 std::string output;
1701 std::vector<std::string*>* tokenOutput = NULL;
1702 bool args_defined = read_deploy_property_value("deployment.plugin.jvm.arguments", output);
1703 if (!args_defined){
1704 return new std::vector<std::string*>();
1705 }
1706 tokenOutput = IcedTeaPluginUtilities::strSplit(output.c_str(), " \n");
1707 return tokenOutput;
1708}
1709
1710
1711/*
1712 * Escape characters for passing to Java.
1713 * "\n" for new line, "\\" for "\", "\:" for ";"
1714 */
1715std::string
1716escape_parameter_string(const char* to_encode) {
1717 std::string encoded;
1718
1719 if (to_encode == NULL)
1720 {
1721 return encoded;
1722 }
1723
1724 size_t length = strlen(to_encode);
1725 for (int i = 0; i < length; i++)
1726 {
1727 if (to_encode[i] == '\n')
1728 encoded += "\\n";
1729 else if (to_encode[i] == '\\')
1730 encoded += "\\\\";
1731 else if (to_encode[i] == ';')
1732 encoded += "\\:";
1733 else
1734 encoded += to_encode[i];
1735 }
1736
1737 return encoded;
1738}
1739
1740/*
1741 * Build a string containing an encoded list of parameters to send to the applet viewer.
1742 * The parameters are separated as 'key1;value1;key2;value2;'. As well, they are
1743 * separated and escaped as:
1744 * "\n" for new line, "\\" for "\", "\:" for ";"
1745 */
1746std::string
1747plugin_parameters_string (int argc, char* argn[], char* argv[])
1748{
1749 PLUGIN_DEBUG ("plugin_parameters_string\n");
1750
1751 std::string parameters;
1752
1753 for (int i = 0; i < argc; i++)
1754 {
1755 if (argv[i] != NULL)
1756 {
1757 std::string name_escaped = escape_parameter_string(argn[i]);
1758 std::string value_escaped = escape_parameter_string(argv[i]);
1759
1760 //Encode parameters and send as 'key1;value1;key2;value2;' etc
1761 parameters += name_escaped;
1762 parameters += ';';
1763 parameters += value_escaped;
1764 parameters += ';';
1765 }
1766 }
1767
1768 PLUGIN_DEBUG ("plugin_parameters_string return\n");
1769
1770 return parameters;
1771}
1772
1773// plugin_send_message_to_appletviewer must be called while holding
1774// data->appletviewer_mutex.
1775void
1776plugin_send_message_to_appletviewer (gchar const* message)
1777{
1778 PLUGIN_DEBUG ("plugin_send_message_to_appletviewer\n");
1779
1780 if (jvm_up)
1781 {
1782 gchar* newline_message = NULL;
1783 gsize bytes_written = 0;
1784
1785 // Send message to appletviewer.
1786 newline_message = g_strdup_printf ("%s\n", message);
1787
1788 // g_io_channel_write_chars will return something other than
1789 // G_IO_STATUS_NORMAL if not all the data is written. In that
1790 // case we fail rather than retrying.
1791 if (g_io_channel_write_chars (out_to_appletviewer,
1792 newline_message, -1, &bytes_written,
1793 &channel_error)
1794 != G_IO_STATUS_NORMAL)
1795 {
1796 if (channel_error)
1797 {
1798 PLUGIN_ERROR ("Failed to write bytes to output channel '%s' \n",
1799 channel_error->message);
1800 g_error_free (channel_error);
1801 channel_error = NULL;
1802 }
1803 else
1804 PLUGIN_ERROR ("Failed to write bytes to output channel for %s", newline_message);
1805 }
1806
1807 if (g_io_channel_flush (out_to_appletviewer, &channel_error)
1808 != G_IO_STATUS_NORMAL)
1809 {
1810 if (channel_error)
1811 {
1812 PLUGIN_ERROR ("Failed to flush bytes to output channel '%s'\n",
1813 channel_error->message);
1814 g_error_free (channel_error);
1815 channel_error = NULL;
1816 }
1817 else
1818 PLUGIN_ERROR ("Failed to flush bytes to output channel for %s", newline_message);
1819 }
1820 g_free (newline_message);
1821 newline_message = NULL;
1822
1823 PLUGIN_DEBUG (" PIPE: plugin wrote(?): %s\n", message);
1824 }
1825
1826 PLUGIN_DEBUG ("plugin_send_message_to_appletviewer return\n");
1827}
1828
1829// unlike like plugin_send_message_to_appletviewer
1830// do not debug
1831// do not error
1832// do not have its own line end
1833// is accesed by only one thread
1834// have own pipe
1835// jvm must be up
1836void
1837plugin_send_message_to_appletviewer_console (gchar const* newline_message)
1838{
1839 gsize bytes_written = 0;
1840 if (g_io_channel_write_chars (debug_to_appletviewer,
1841 newline_message, -1, &bytes_written,
1842 &channel_error) != G_IO_STATUS_NORMAL) {
1843 if (channel_error) {
1844 //error must be freed
1845 g_error_free (channel_error);
1846 channel_error = NULL;
1847 }
1848 }
1849}
1850//flush only when its full
1851void flush_plugin_send_message_to_appletviewer_console (){
1852 if (g_io_channel_flush (debug_to_appletviewer, &channel_error)
1853 != G_IO_STATUS_NORMAL) {
1854 if (channel_error) {
1855 g_error_free (channel_error);
1856 channel_error = NULL;
1857 }
1858 }
1859}
1860
1861/*
1862 * Sends the initialization message (handle/size/url) to the plugin
1863 */
1864void
1865plugin_send_initialization_message(char* instance, gulong handle,
1866 int width, int height, char* url)
1867{
1868 PLUGIN_DEBUG ("plugin_send_initialization_message\n");
1869
1870 gchar *window_message = g_strdup_printf ("instance %s handle %ld width %d height %d %s",
1871 instance, handle, width, height, url);
1872 plugin_send_message_to_appletviewer (window_message);
1873 g_free (window_message);
1874 window_message = NULL;
1875
1876 PLUGIN_DEBUG ("plugin_send_initialization_message return\n");
1877}
1878
1879
1880// Stop the appletviewer process. When this is called the
1881// appletviewer can be in any of three states: running, crashed or
1882// hung. If the appletviewer is running then sending it "shutdown"
1883// will cause it to exit. This will cause
1884// plugin_out_pipe_callback/plugin_in_pipe_callback to be called and
1885// the input and output channels to be shut down. If the appletviewer
1886// has crashed then plugin_out_pipe_callback/plugin_in_pipe_callback
1887// would already have been called and data->appletviewer_alive cleared
1888// in which case this function simply returns. If the appletviewer is
1889// hung then this function will be successful and the input and output
1890// watches will be removed by plugin_data_destroy.
1891// plugin_stop_appletviewer must be called with
1892// data->appletviewer_mutex held.
1893static void
1894plugin_stop_appletviewer ()
1895{
1896 PLUGIN_DEBUG ("plugin_stop_appletviewer\n");
1897
1898 if (jvm_up)
1899 {
1900 // Shut down the appletviewer.
1901 gsize bytes_written = 0;
1902
1903 if (out_to_appletviewer)
1904 {
1905 if (g_io_channel_write_chars (out_to_appletviewer, "shutdown",
1906 -1, &bytes_written, &channel_error)
1907 != G_IO_STATUS_NORMAL)
1908 {
1909 if (channel_error)
1910 {
1911 PLUGIN_ERROR ("Failed to write shutdown message to "
1912 " appletviewer, %s \n", channel_error->message);
1913 g_error_free (channel_error);
1914 channel_error = NULL;
1915 }
1916 else
1917 PLUGIN_ERROR ("Failed to write shutdown message to\n");
1918 }
1919
1920 if (g_io_channel_flush (out_to_appletviewer, &channel_error)
1921 != G_IO_STATUS_NORMAL)
1922 {
1923 if (channel_error)
1924 {
1925 PLUGIN_ERROR ("Failed to write shutdown message to"
1926 " appletviewer %s \n", channel_error->message);
1927 g_error_free (channel_error);
1928 channel_error = NULL;
1929 }
1930 else
1931 PLUGIN_ERROR ("Failed to write shutdown message to\n");
1932 }
1933
1934 if (g_io_channel_shutdown (out_to_appletviewer,
1935 TRUE, &channel_error)
1936 != G_IO_STATUS_NORMAL)
1937 {
1938 if (channel_error)
1939 {
1940 PLUGIN_ERROR ("Failed to shut down appletviewer"
1941 " output channel %s \n", channel_error->message);
1942 g_error_free (channel_error);
1943 channel_error = NULL;
1944 }
1945 else
1946 PLUGIN_ERROR ("Failed to shut down appletviewer\n");
1947 }
1948 }
1949
1950 if (in_from_appletviewer)
1951 {
1952 if (g_io_channel_shutdown (in_from_appletviewer,
1953 TRUE, &channel_error)
1954 != G_IO_STATUS_NORMAL)
1955 {
1956 if (channel_error)
1957 {
1958 PLUGIN_ERROR ("Failed to shut down appletviewer"
1959 " input channel %s \n", channel_error->message);
1960 g_error_free (channel_error);
1961 channel_error = NULL;
1962 }
1963 else
1964 PLUGIN_ERROR ("Failed to shut down appletviewer\n");
1965 }
1966 }
1967 }
1968
1969 jvm_up = FALSE;
1970 sleep(2); /* Needed to prevent crashes during debug (when JDWP port is not freed by the kernel right away) */
1971
1972 PLUGIN_DEBUG ("plugin_stop_appletviewer return\n");
1973}
1974
1975static void appletviewer_monitor(GPid pid, gint status, gpointer data)
1976{
1977 PLUGIN_DEBUG ("appletviewer_monitor\n");
1978 jvm_up = FALSE;
1979 pid = -1;
1980 PLUGIN_DEBUG ("appletviewer_monitor return\n");
1981}
1982
1983void
1984plugin_data_destroy (NPP instance)
1985{
1986 PLUGIN_DEBUG ("plugin_data_destroy\n");
1987
1988 ITNPPluginData* tofree = (ITNPPluginData*) instance->pdata;
1989
1990 // Remove instance from map
1991 gpointer id_ptr = g_hash_table_lookup(instance_to_id_map, instance);
1992
1993 if (id_ptr)
1994 {
1995 gint id = GPOINTER_TO_INT(id_ptr);
1996 g_hash_table_remove(instance_to_id_map, instance);
1997 g_hash_table_remove(id_to_instance_map, id_ptr);
1998 }
1999
2000 /* Explicitly call destructor */
2001 tofree->~ITNPPluginData();
2002
2003 (*browser_functions.memfree) (tofree);
2004
2005 PLUGIN_DEBUG ("plugin_data_destroy return\n");
2006}
2007
2008static bool
2009initialize_browser_functions(const NPNetscapeFuncs* browserTable)
2010{
2011#define NPNETSCAPEFUNCS_LAST_FIELD_USED (browserTable->setvalueforurl)
2012
2013 //Determine the size in bytes, as a difference of the address past the last used field
2014 //And the browser table address
2015 size_t usedSize = (char*)(1 + &NPNETSCAPEFUNCS_LAST_FIELD_USED) - (char*)browserTable;
2016
2017 // compare the reported size versus the size we required
2018 if (browserTable->size < usedSize)
2019 {
2020 return false;
2021 }
2022
2023 //Ensure any unused fields are NULL
2024 memset(&browser_functions, 0, sizeof(NPNetscapeFuncs));
2025
2026 //browserTable->size can be larger than sizeof(NPNetscapeFuncs) (PR1106)
2027 size_t copySize = browserTable->size < sizeof(NPNetscapeFuncs) ?
2028 browserTable->size : sizeof(NPNetscapeFuncs);
2029
2030 //Copy fields according to given size
2031 memcpy(&browser_functions, browserTable, copySize);
2032
2033 return true;
2034}
2035
2036/* Set the plugin table to the correct contents, taking care not to write past
2037 * the provided object space */
2038static bool
2039initialize_plugin_table(NPPluginFuncs* pluginTable)
2040{
2041#define NPPLUGINFUNCS_LAST_FIELD_USED (pluginTable->getvalue)
2042
2043 //Determine the size in bytes, as a difference of the address past the last used field
2044 //And the browser table address
2045 size_t usedSize = (char*)(1 + &NPPLUGINFUNCS_LAST_FIELD_USED) - (char*)pluginTable;
2046
2047 // compare the reported size versus the size we required
2048 if (pluginTable->size < usedSize)
2049 return false;
2050
2051 pluginTable->version = (NP_VERSION_MAJOR << 8) + NP_VERSION_MINOR;
2052 pluginTable->size = sizeof (NPPluginFuncs);
2053 pluginTable->newp = NPP_NewProcPtr (ITNP_New);
2054 pluginTable->destroy = NPP_DestroyProcPtr (ITNP_Destroy);
2055 pluginTable->setwindow = NPP_SetWindowProcPtr (ITNP_SetWindow);
2056 pluginTable->newstream = NPP_NewStreamProcPtr (ITNP_NewStream);
2057 pluginTable->destroystream = NPP_DestroyStreamProcPtr (ITNP_DestroyStream);
2058 pluginTable->asfile = NPP_StreamAsFileProcPtr (ITNP_StreamAsFile);
2059 pluginTable->writeready = NPP_WriteReadyProcPtr (ITNP_WriteReady);
2060 pluginTable->write = NPP_WriteProcPtr (ITNP_Write);
2061 pluginTable->print = NPP_PrintProcPtr (ITNP_Print);
2062 pluginTable->urlnotify = NPP_URLNotifyProcPtr (ITNP_URLNotify);
2063 pluginTable->getvalue = NPP_GetValueProcPtr (ITNP_GetValue);
2064
2065 return true;
2066}
2067
2068// Make sure the plugin data directory exists, creating it if necessary.
2069NPError
2070initialize_data_directory()
2071{
2072
2073 data_directory = IcedTeaPluginUtilities::getRuntimePath() + "/icedteaplugin-";
2074 if (getenv("USER") != NULL) {
2075 data_directory = data_directory + getenv("USER") + "-";
2076 }
2077 data_directory += "XXXXXX";
2078 // Now create a icedteaplugin subdir
2079 char fileNameX[data_directory.length()+1];
2080 std::strcpy (fileNameX, data_directory.c_str());
2081 char * fileName = mkdtemp(fileNameX);
2082 if (fileName == NULL) {
2083 PLUGIN_ERROR ("Failed to create data directory %s, %s\n",
2084 data_directory.c_str(),
2085 strerror (errno));
2086 return NPERR_GENERIC_ERROR;
2087 }
2088 data_directory = std::string(fileName);
2089
2090 //open uniques icedteaplugin subdir for one single run
2091 data_directory_descriptor = opendir(data_directory.c_str());
2092 if (data_directory_descriptor == NULL) {
2093 PLUGIN_ERROR ("Failed to open data directory %s %s\n",
2094 data_directory.c_str(), strerror (errno));
2095 return NPERR_GENERIC_ERROR;
2096 }
2097
2098 return NPERR_NO_ERROR;
2099}
2100
2101// FACTORY FUNCTIONS
2102
2103// Provides the browser with pointers to the plugin functions that we
2104// implement and initializes a local table with browser functions that
2105// we may wish to call. Called once, after browser startup and before
2106// the first plugin instance is created.
2107// The field 'initialized' is set to true once this function has
2108// finished. If 'initialized' is already true at the beginning of
2109// this function, then it is evident that NP_Initialize has already
2110// been called. There is no need to call this function more than once and
2111// this workaround avoids any duplicate calls.
2112__attribute__ ((visibility ("default")))
2113NPError
2114#if defined(_WIN32) || defined (__OS2__)
2115OSCALL NP_Initialize (NPNetscapeFuncs* browserTable)
2116#else
2117OSCALL NP_Initialize (NPNetscapeFuncs* browserTable, NPPluginFuncs* pluginTable)
2118#endif
2119{
2120 PLUGIN_DEBUG ("NP_Initialize\n");
2121
2122#if defined(_WIN32) || defined (__OS2__)
2123 if (browserTable == NULL)
2124 {
2125 PLUGIN_ERROR ("Browser function table is NULL.");
2126
2127 return NPERR_INVALID_FUNCTABLE_ERROR;
2128 }
2129#else
2130 if ((browserTable == NULL) || (pluginTable == NULL))
2131 {
2132 PLUGIN_ERROR ("Browser or plugin function table is NULL.\n");
2133
2134 return NPERR_INVALID_FUNCTABLE_ERROR;
2135 }
2136#endif
2137
2138 // Ensure that the major version of the plugin API that the browser
2139 // expects is not more recent than the major version of the API that
2140 // we've implemented.
2141 if ((browserTable->version >> 8) > NP_VERSION_MAJOR)
2142 {
2143 PLUGIN_ERROR ("Incompatible version.\n");
2144
2145 return NPERR_INCOMPATIBLE_VERSION_ERROR;
2146 }
2147
2148 // Copy into a global table (browser_functions) the browser functions that we may use.
2149 // If the browser functions needed change, update NPNETSCAPEFUNCS_LAST_FIELD_USED
2150 // within this function
2151 bool browser_functions_supported = initialize_browser_functions(browserTable);
2152
2153 // Check if everything we rely on is supported
2154 if ( !browser_functions_supported )
2155 {
2156 PLUGIN_ERROR ("Invalid browser function table.\n");
2157
2158 return NPERR_INVALID_FUNCTABLE_ERROR;
2159 }
2160
2161#if !defined(_WIN32) && !defined (__OS2__)
2162 // Return to the browser the plugin functions that we implement.
2163 // If the plugin functions needed change, update NPPLUGINFUNCS_LAST_FIELD_USED
2164 // within this function
2165 bool plugin_functions_supported = initialize_plugin_table(pluginTable);
2166
2167 // Check if everything we rely on is supported
2168 if ( !plugin_functions_supported )
2169 {
2170 PLUGIN_ERROR ("Invalid plugin function table.\n");
2171
2172 return NPERR_INVALID_FUNCTABLE_ERROR;
2173 }
2174#endif
2175
2176 // Re-setting the above tables multiple times is OK (as the
2177 // browser may change its function locations). However
2178 // anything beyond this point should only run once.
2179 if (initialized)
2180 return NPERR_NO_ERROR;
2181
2182#ifdef __OS2__
2183 // perform OS-specific initialization
2184 if (!init_os())
2185 {
2186 PLUGIN_ERROR ("Failed to perform OS-specific initialization.");
2187 return NPERR_GENERIC_ERROR;
2188 }
2189#endif
2190
2191 NPError np_error = NPERR_NO_ERROR;
2192#ifndef __OS2__
2193 // create directory for pipes
2194 np_error = initialize_data_directory();
2195 if (np_error != NPERR_NO_ERROR)
2196 {
2197 PLUGIN_ERROR("Unable to create data directory %s\n", data_directory.c_str());
2198 return np_error;
2199 }
2200#endif
2201
2202 // Set appletviewer_executable.
2203 PLUGIN_DEBUG("Executing java at %s\n", get_plugin_executable().c_str());
2204 np_error = plugin_test_appletviewer ();
2205 if (np_error != NPERR_NO_ERROR)
2206 {
2207 PLUGIN_ERROR("Unable to find java executable %s\n", get_plugin_executable().c_str());
2208 return np_error;
2209 }
2210
2211 // Initialize threads (needed for mutexes).
2212 if (!g_thread_supported ())
2213 g_thread_init (NULL);
2214
2215#ifdef __OS2__
2216 if (!g_main_context_os2_start_pm_integration (NULL))
2217 {
2218 PLUGIN_DEBUG ("Failed to integrate with PM");
2219 return NPERR_GENERIC_ERROR;
2220 }
2221#endif
2222
2223 plugin_instance_mutex = g_mutex_new ();
2224
2225 PLUGIN_DEBUG ("NP_Initialize: using %s\n", get_plugin_executable().c_str());
2226
2227 plugin_req_proc = new PluginRequestProcessor();
2228 java_req_proc = new JavaMessageSender();
2229
2230 java_to_plugin_bus = new MessageBus();
2231 plugin_to_java_bus = new MessageBus();
2232
2233 java_to_plugin_bus->subscribe(plugin_req_proc);
2234 plugin_to_java_bus->subscribe(java_req_proc);
2235
2236#ifdef __OS2__
2237 queue_processor_data1.processor = plugin_req_proc;
2238 queue_processor_data2.processor = plugin_req_proc;
2239 queue_processor_data3.processor = plugin_req_proc;
2240 pthread_create (&plugin_request_processor_thread1, NULL, &queue_processor, (void*) &queue_processor_data1);
2241 pthread_create (&plugin_request_processor_thread2, NULL, &queue_processor, (void*) &queue_processor_data2);
2242 pthread_create (&plugin_request_processor_thread3, NULL, &queue_processor, (void*) &queue_processor_data3);
2243#else
2244 pthread_create (&plugin_request_processor_thread1, NULL, &queue_processor, (void*) plugin_req_proc);
2245 pthread_create (&plugin_request_processor_thread2, NULL, &queue_processor, (void*) plugin_req_proc);
2246 pthread_create (&plugin_request_processor_thread3, NULL, &queue_processor, (void*) plugin_req_proc);
2247#endif
2248
2249 itnp_plugin_thread_id = pthread_self();
2250
2251 pthread_mutexattr_t attribute;
2252 pthread_mutexattr_init(&attribute);
2253 pthread_mutexattr_settype(&attribute, PTHREAD_MUTEX_RECURSIVE);
2254 pthread_mutex_init(&pluginAsyncCallMutex, &attribute);
2255 pthread_mutexattr_destroy(&attribute);
2256
2257 initialized = true;
2258
2259 PLUGIN_DEBUG ("NP_Initialize return\n");
2260
2261 return NPERR_NO_ERROR;
2262}
2263
2264#if defined(_WIN32) || defined (__OS2__)
2265NPError
2266OSCALL NP_GetEntryPoints (NPPluginFuncs* pluginTable)
2267{
2268 PLUGIN_DEBUG ("NP_GetEntryPoints\n");
2269
2270 if (pluginTable == NULL)
2271 {
2272 PLUGIN_ERROR ("Plugin function table is NULL.");
2273
2274 return NPERR_INVALID_FUNCTABLE_ERROR;
2275 }
2276
2277 // Return to the browser the plugin functions that we implement.
2278 // If the plugin functions needed change, update NPPLUGINFUNCS_LAST_FIELD_USED
2279 // within this function
2280 bool plugin_functions_supported = initialize_plugin_table(pluginTable);
2281
2282 // Check if everything we rely on is supported
2283 if ( !plugin_functions_supported )
2284 {
2285 PLUGIN_ERROR ("Invalid plugin function table.");
2286
2287 return NPERR_INVALID_FUNCTABLE_ERROR;
2288 }
2289
2290 return NPERR_NO_ERROR;
2291}
2292#endif
2293
2294// Returns a string describing the MIME type that this plugin
2295// handles.
2296__attribute__ ((visibility ("default")))
2297#ifdef LEGACY_XULRUNNERAPI
2298 char*
2299#else
2300 const char*
2301#endif
2302OSCALL NP_GetMIMEDescription ()
2303{
2304 //this function is called severaltimes between lunches
2305 PLUGIN_DEBUG ("NP_GetMIMEDescription\n");
2306
2307 PLUGIN_DEBUG ("NP_GetMIMEDescription return\n");
2308
2309 return PLUGIN_MIME_DESC;
2310}
2311
2312// Returns a value relevant to the plugin as a whole. The browser
2313// calls this function to obtain information about the plugin.
2314__attribute__ ((visibility ("default")))
2315NPError
2316OSCALL NP_GetValue (void* future, NPPVariable variable, void* value)
2317{
2318 PLUGIN_DEBUG ("NP_GetValue\n");
2319
2320 NPError result = NPERR_NO_ERROR;
2321 gchar** char_value = (gchar**) value;
2322
2323 switch (variable)
2324 {
2325 case NPPVpluginNameString:
2326 PLUGIN_DEBUG ("NP_GetValue: returning plugin name.\n");
2327 *char_value = g_strdup (PLUGIN_FULL_NAME);
2328 break;
2329
2330 case NPPVpluginDescriptionString:
2331 PLUGIN_DEBUG ("NP_GetValue: returning plugin description.\n");
2332 *char_value = g_strdup (PLUGIN_DESC);
2333 break;
2334
2335 default:
2336 PLUGIN_ERROR ("Unknown plugin value requested.\n");
2337 result = NPERR_GENERIC_ERROR;
2338 break;
2339 }
2340
2341 PLUGIN_DEBUG ("NP_GetValue return\n");
2342
2343 return result;
2344}
2345
2346// Shuts down the plugin. Called after the last plugin instance is
2347// destroyed.
2348__attribute__ ((visibility ("default")))
2349NPError
2350OSCALL NP_Shutdown (void)
2351{
2352 PLUGIN_DEBUG ("NP_Shutdown\n");
2353
2354#ifdef __OS2__
2355 g_main_context_os2_stop_pm_integration (NULL);
2356#endif
2357
2358 // Free mutex.
2359 if (plugin_instance_mutex)
2360 {
2361 g_mutex_free (plugin_instance_mutex);
2362 plugin_instance_mutex = NULL;
2363 }
2364
2365 // stop the appletviewer
2366 plugin_stop_appletviewer();
2367
2368 // remove monitor
2369 if (appletviewer_watch_id != -1)
2370 g_source_remove(appletviewer_watch_id);
2371
2372 // Removing a source is harmless if it fails since it just means the
2373 // source has already been removed.
2374 g_source_remove (in_watch_source);
2375 in_watch_source = 0;
2376
2377 // cleanup_in_from_appletviewer:
2378 if (in_from_appletviewer)
2379 g_io_channel_unref (in_from_appletviewer);
2380 in_from_appletviewer = NULL;
2381
2382 // cleanup_out_watch_source:
2383 g_source_remove (out_watch_source);
2384 out_watch_source = 0;
2385
2386 // cleanup_out_to_appletviewer:
2387 if (out_to_appletviewer)
2388 g_io_channel_unref (out_to_appletviewer);
2389 out_to_appletviewer = NULL;
2390
2391 // cleanup_out_pipe:
2392#ifdef __OS2__
2393 CLOSE_FD (out_pipe [0]);
2394 CLOSE_FD (out_pipe [1]);
2395#else
2396 // Delete output pipe.
2397 PLUGIN_DEBUG ("NP_Shutdown: deleting output fifo: %s\n", out_pipe_name);
2398 unlink (out_pipe_name);
2399 PLUGIN_DEBUG ("NP_Shutdown: deleted output fifo: %s\n", out_pipe_name);
2400
2401 // cleanup_out_pipe_name:
2402 g_free (out_pipe_name);
2403 out_pipe_name = NULL;
2404#endif
2405
2406 // cleanup_in_pipe:
2407#ifdef __OS2__
2408 CLOSE_FD (in_pipe [0]);
2409 CLOSE_FD (in_pipe [1]);
2410#else
2411 // Delete input pipe.
2412 PLUGIN_DEBUG ("NP_Shutdown: deleting input fifo: %s\n", in_pipe_name);
2413 unlink (in_pipe_name);
2414 PLUGIN_DEBUG ("NP_Shutdown: deleted input fifo: %s\n", in_pipe_name);
2415
2416 // cleanup_in_pipe_name:
2417 g_free (in_pipe_name);
2418 in_pipe_name = NULL;
2419#endif
2420
2421 if (plugin_debug_to_console){
2422 //jvm_up is now false
2423 if (g_io_channel_shutdown (debug_to_appletviewer,
2424 TRUE, &channel_error)
2425 != G_IO_STATUS_NORMAL)
2426 {
2427 if (channel_error)
2428 {
2429 PLUGIN_ERROR ("Failed to shut down appletviewer"
2430 " debug channel\n", channel_error->message);
2431 g_error_free (channel_error);
2432 channel_error = NULL;
2433 }
2434 else
2435 PLUGIN_ERROR ("Failed to shut down debug to appletviewer\n");
2436 }
2437 // cleanup_out_to_appletviewer:
2438 if (debug_to_appletviewer)
2439 g_io_channel_unref (debug_to_appletviewer);
2440 out_to_appletviewer = NULL;
2441 // cleanup_debug_pipe:
2442 // Delete debug pipe.
2443 PLUGIN_DEBUG ("NP_Shutdown: deleting debug fifo: %s\n", debug_pipe_name);
2444 unlink (debug_pipe_name);
2445 PLUGIN_DEBUG ("NP_Shutdown: deleted debug fifo: %s\n", debug_pipe_name);
2446 // cleanup_out_pipe_name:
2447 g_free (debug_pipe_name);
2448 debug_pipe_name = NULL;
2449 }
2450
2451 // Destroy the call queue mutex
2452 pthread_mutex_destroy(&pluginAsyncCallMutex);
2453
2454#ifdef __OS2__
2455 // perform OS-specific uninitialization
2456 done_os();
2457#endif
2458
2459 initialized = false;
2460
2461#ifdef __OS2__
2462 // pthread_cancel() isn't implemented on OS/2, so use an old good flag
2463 queue_processor_data1.stopRequested = true;
2464 queue_processor_data2.stopRequested = true;
2465 queue_processor_data3.stopRequested = true;
2466 plugin_req_proc->cancelWait();
2467#else
2468 pthread_cancel(plugin_request_processor_thread1);
2469 pthread_cancel(plugin_request_processor_thread2);
2470 pthread_cancel(plugin_request_processor_thread3);
2471#endif
2472
2473 pthread_join(plugin_request_processor_thread1, NULL);
2474 pthread_join(plugin_request_processor_thread2, NULL);
2475 pthread_join(plugin_request_processor_thread3, NULL);
2476
2477 java_to_plugin_bus->unSubscribe(plugin_req_proc);
2478 plugin_to_java_bus->unSubscribe(java_req_proc);
2479 //internal_bus->unSubscribe(java_req_proc);
2480 //internal_bus->unSubscribe(plugin_req_proc);
2481
2482 delete plugin_req_proc;
2483 delete java_req_proc;
2484 delete java_to_plugin_bus;
2485 delete plugin_to_java_bus;
2486 //delete internal_bus;
2487
2488 cleanUpDir();
2489
2490 PLUGIN_DEBUG ("NP_Shutdown return\n");
2491
2492 if (plugin_debug_to_file){
2493 fflush (plugin_file_log);
2494 //fclose (plugin_file_log);
2495 //keep writing untill possible!
2496 }
2497
2498 return NPERR_NO_ERROR;
2499}
2500
2501NPObject*
2502get_scriptable_object(NPP instance)
2503{
2504 NPObject* obj;
2505 ITNPPluginData* data = (ITNPPluginData*) instance->pdata;
2506
2507 if (data->is_applet_instance) // dummy instance/package?
2508 {
2509 JavaRequestProcessor java_request = JavaRequestProcessor();
2510 JavaResultData* java_result;
2511 std::string instance_id = std::string();
2512 std::string applet_class_id = std::string();
2513
2514 int id = get_id_from_instance(instance);
2515 gchar* id_str = g_strdup_printf ("%d", id);
2516
2517 // Some browsers.. (e.g. chromium) don't call NPP_SetWindow
2518 // for 0x0 plugins and therefore require initialization with
2519 // a 0 handle
2520 if (!data->window_handle)
2521 {
2522 plugin_send_initialization_message(data->instance_id, 0, 0, 0, data->parameters_string);
2523 }
2524
2525 java_result = java_request.getAppletObjectInstance(id_str);
2526
2527 g_free(id_str);
2528
2529 if (java_result->error_occurred)
2530 {
2531 PLUGIN_ERROR("Error: Unable to fetch applet instance id from Java side.\n");
2532 return NULL;
2533 }
2534
2535 instance_id.append(*(java_result->return_string));
2536
2537 java_result = java_request.getClassID(instance_id);
2538
2539 if (java_result->error_occurred)
2540 {
2541 PLUGIN_ERROR("Error: Unable to fetch applet instance id from Java side.\n");
2542 return NULL;
2543 }
2544
2545 applet_class_id.append(*(java_result->return_string));
2546
2547 obj = IcedTeaScriptableJavaObject::get_scriptable_java_object(instance, applet_class_id, instance_id, false);
2548
2549 } else
2550 {
2551 obj = IcedTeaScriptableJavaPackageObject::get_scriptable_java_package_object(instance, "");
2552 }
2553
2554 return obj;
2555}
2556
2557NPObject*
2558allocate_scriptable_object(NPP npp, NPClass *aClass)
2559{
2560 PLUGIN_DEBUG("Allocating new scriptable object\n");
2561 return new IcedTeaScriptablePluginObject(npp);
2562}
2563
2564#ifdef __OS2__
2565
2566// Make sure static initializers in the plugin DLL are called
2567
2568static APIENTRY void cleanup(ULONG ulReason)
2569{
2570 __ctordtorTerm();
2571 _CRT_term();
2572 DosExitList(EXLST_EXIT, cleanup);
2573}
2574
2575unsigned long _System _DLL_InitTerm(unsigned long hModule,
2576 unsigned long ulFlag)
2577{
2578 APIRET arc;
2579
2580 if (ulFlag == 0)
2581 {
2582 arc = DosExitList (EXLST_ADD, cleanup);
2583 if (arc != NO_ERROR)
2584 return 0;
2585
2586 if (_CRT_init() != 0) // failure?
2587 return 0;
2588 __ctordtorInit();
2589 }
2590
2591 return 1;
2592}
2593
2594#endif /* __OS2__ */
Note: See TracBrowser for help on using the repository browser.