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

Last change on this file since 384 was 384, checked in by dmik, 13 years ago

icedtea-web: Make sure parent ends of pipes are not inherited by child.

This is necessary for read() on the child's side to abort when the parent
closes its ends. This fixes the JAVA process hang when the browser
terminates.

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