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

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

icedtea-web: Use g_main_context_os2_start_pm_integration() on OS/2.

This is to make sure that GLib events are handled correctly when the main
PM message loop is run externally WRT the plugin code (e.g. by Firefox).

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