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

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

icedtea-web: Disable pipe input callback on error to prevent spamming.

This fixes 100% CPU load in case of some communication error between
the plugin and appviewer.

File size: 82.5 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#ifdef __OS2__
1235 // G_IO_ERR/HUP is not reported on file/pipe handles, simulate it
1236 condition = (GIOCondition) (condition | G_IO_ERR);
1237#endif
1238 } else
1239 {
1240 consume_message(message);
1241 }
1242
1243 g_free (message);
1244 message = NULL;
1245
1246 keep_installed = TRUE;
1247 }
1248
1249 if (condition & (G_IO_ERR | G_IO_HUP))
1250 {
1251 PLUGIN_DEBUG ("appletviewer has stopped.\n");
1252 keep_installed = FALSE;
1253 }
1254
1255 PLUGIN_DEBUG ("plugin_in_pipe_callback return\n");
1256
1257 return keep_installed;
1258}
1259
1260void consume_message(gchar* message) {
1261
1262 PLUGIN_DEBUG (" PIPE: plugin read: %s\n", message);
1263
1264 if (g_str_has_prefix (message, "instance"))
1265 {
1266
1267 ITNPPluginData* data;
1268 gchar** parts = g_strsplit (message, " ", -1);
1269 guint parts_sz = g_strv_length (parts);
1270
1271 int instance_id = atoi(parts[1]);
1272 NPP instance = (NPP) g_hash_table_lookup(id_to_instance_map,
1273 GINT_TO_POINTER(instance_id));
1274
1275 if (instance_id > 0 && !instance)
1276 {
1277 PLUGIN_DEBUG("Instance %d is not active. Refusing to consume message \"%s\"\n", instance_id, message);
1278 return;
1279 }
1280 else if (instance)
1281 {
1282 data = (ITNPPluginData*) instance->pdata;
1283 }
1284
1285 if (g_str_has_prefix (parts[2], "status"))
1286 {
1287
1288 // clear the "instance X status" parts
1289 sprintf(parts[0], "");
1290 sprintf(parts[1], "");
1291 sprintf(parts[2], "");
1292
1293 // join the rest
1294 gchar* status_message = g_strjoinv(" ", parts);
1295 PLUGIN_DEBUG ("plugin_in_pipe_callback: setting status %s\n", status_message);
1296 (*browser_functions.status) (data->owner, status_message);
1297
1298 g_free(status_message);
1299 status_message = NULL;
1300 }
1301 else if (g_str_has_prefix (parts[1], "internal"))
1302 {
1303 //s->post(message);
1304 }
1305 else
1306 {
1307 // All other messages are posted to the bus, and subscribers are
1308 // expected to take care of them. They better!
1309
1310 java_to_plugin_bus->post(message);
1311 }
1312
1313 g_strfreev (parts);
1314 parts = NULL;
1315 }
1316 else if (g_str_has_prefix (message, "context"))
1317 {
1318 java_to_plugin_bus->post(message);
1319 }
1320 else if (g_str_has_prefix (message, "plugin "))
1321 {
1322 // internal plugin related message
1323 gchar** parts = g_strsplit (message, " ", 5);
1324 if (g_str_has_prefix(parts[1], "PluginProxyInfo"))
1325 {
1326 gchar* proxy;
1327 uint32_t len;
1328
1329 gchar* decoded_url = (gchar*) calloc(strlen(parts[4]) + 1, sizeof(gchar));
1330 IcedTeaPluginUtilities::decodeURL(parts[4], &decoded_url);
1331 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);
1332
1333 gchar* proxy_info;
1334
1335#if MOZILLA_VERSION_COLLAPSED < 1090100
1336 proxy = (char*) malloc(sizeof(char)*2048);
1337#endif
1338
1339 proxy_info = g_strconcat ("plugin PluginProxyInfo reference ", parts[3], " ", NULL);
1340 if (get_proxy_info(decoded_url, &proxy, &len) == NPERR_NO_ERROR)
1341 {
1342 proxy_info = g_strconcat (proxy_info, proxy, NULL);
1343 }
1344
1345 PLUGIN_DEBUG("Proxy info: %s\n", proxy_info);
1346 plugin_send_message_to_appletviewer(proxy_info);
1347
1348 g_free(decoded_url);
1349 decoded_url = NULL;
1350 g_free(proxy_info);
1351 proxy_info = NULL;
1352
1353#if MOZILLA_VERSION_COLLAPSED < 1090100
1354 g_free(proxy);
1355 proxy = NULL;
1356#endif
1357
1358 } else if (g_str_has_prefix(parts[1], "PluginCookieInfo"))
1359 {
1360 gchar* decoded_url = (gchar*) calloc(strlen(parts[4])+1, sizeof(gchar));
1361 IcedTeaPluginUtilities::decodeURL(parts[4], &decoded_url);
1362
1363 gchar* cookie_info = g_strconcat ("plugin PluginCookieInfo reference ", parts[3], " ", NULL);
1364 gchar* cookie_string;
1365 uint32_t len;
1366 if (get_cookie_info(decoded_url, &cookie_string, &len) == NPERR_NO_ERROR)
1367 {
1368 cookie_info = g_strconcat (cookie_info, cookie_string, NULL);
1369 }
1370
1371 PLUGIN_DEBUG("Cookie info: %s\n", cookie_info);
1372 plugin_send_message_to_appletviewer(cookie_info);
1373
1374 g_free(decoded_url);
1375 decoded_url = NULL;
1376 g_free(cookie_info);
1377 cookie_info = NULL;
1378 }
1379 }
1380 else
1381 {
1382 g_print (" Unable to handle message: %s\n", message);
1383 }
1384}
1385
1386void get_instance_from_id(int id, NPP& instance)
1387{
1388 instance = (NPP) g_hash_table_lookup(id_to_instance_map,
1389 GINT_TO_POINTER(id));
1390}
1391
1392int get_id_from_instance(NPP instance)
1393{
1394 int id = GPOINTER_TO_INT(g_hash_table_lookup(instance_to_id_map,
1395 instance));
1396 PLUGIN_DEBUG("Returning id %d for instance %p\n", id, instance);
1397 return id;
1398}
1399
1400NPError
1401get_proxy_info(const char* siteAddr, char** proxy, uint32_t* len)
1402{
1403#if MOZILLA_VERSION_COLLAPSED < 1090100
1404 nsresult rv;
1405
1406 // Initialize service variables
1407 nsCOMPtr<nsIProtocolProxyService> proxy_svc = do_GetService("@mozilla.org/network/protocol-proxy-service;1", &rv);
1408
1409 if (!proxy_svc) {
1410 printf("Cannot initialize proxy service\n");
1411 return NPERR_GENERIC_ERROR;
1412 }
1413
1414 nsCOMPtr<nsIIOService> io_svc = do_GetService("@mozilla.org/network/io-service;1", &rv);
1415
1416 if (NS_FAILED(rv) || !io_svc) {
1417 printf("Cannot initialize io service\n");
1418 return NPERR_GENERIC_ERROR;
1419 }
1420
1421 // uri which needs to be accessed
1422 nsCOMPtr<nsIURI> uri;
1423 io_svc->NewURI(nsCString(siteAddr), NULL, NULL, getter_AddRefs(uri));
1424
1425 // find the proxy address if any
1426 nsCOMPtr<nsIProxyInfo> info;
1427 proxy_svc->Resolve(uri, 0, getter_AddRefs(info));
1428
1429 // if there is no proxy found, return immediately
1430 if (!info) {
1431 PLUGIN_DEBUG("%s does not need a proxy\n", siteAddr);
1432 return NPERR_GENERIC_ERROR;
1433 }
1434
1435 // if proxy info is available, extract it
1436 nsCString phost;
1437 PRInt32 pport;
1438 nsCString ptype;
1439
1440 info->GetHost(phost);
1441 info->GetPort(&pport);
1442 info->GetType(ptype);
1443
1444 // resolve the proxy address to an IP
1445 nsCOMPtr<nsIDNSService> dns_svc = do_GetService("@mozilla.org/network/dns-service;1", &rv);
1446
1447 if (!dns_svc) {
1448 printf("Cannot initialize DNS service\n");
1449 return NPERR_GENERIC_ERROR;
1450 }
1451
1452 nsCOMPtr<nsIDNSRecord> record;
1453 dns_svc->Resolve(phost, 0U, getter_AddRefs(record));
1454
1455 // TODO: Add support for multiple ips
1456 nsDependentCString ipAddr;
1457 record->GetNextAddrAsString(ipAddr);
1458
1459 if (!strcmp(ptype.get(), "http"))
1460 {
1461 snprintf(*proxy, sizeof(char)*1024, "%s %s:%d", "PROXY", ipAddr.get(), pport);
1462 } else
1463 {
1464 snprintf(*proxy, sizeof(char)*1024, "%s %s:%d", "SOCKS", ipAddr.get(), pport);
1465 }
1466
1467 *len = strlen(*proxy);
1468
1469 PLUGIN_DEBUG("Proxy info for %s: %s\n", siteAddr, *proxy);
1470
1471#else
1472
1473 if (browser_functions.getvalueforurl)
1474 {
1475
1476 // As in get_cookie_info, we use the first active instance
1477 GHashTableIter iter;
1478 gpointer id, instance;
1479
1480 g_hash_table_iter_init (&iter, instance_to_id_map);
1481 g_hash_table_iter_next (&iter, &instance, &id);
1482
1483 browser_functions.getvalueforurl((NPP) instance, NPNURLVProxy, siteAddr, proxy, len);
1484 } else
1485 {
1486 return NPERR_GENERIC_ERROR;
1487 }
1488#endif
1489
1490 return NPERR_NO_ERROR;
1491}
1492
1493// plugin_out_pipe_callback is called when the appletviewer crashes or
1494// is killed. It may be called after data has been destroyed in which
1495// case it simply returns FALSE to remove itself from the glib main
1496// loop.
1497static gboolean
1498plugin_out_pipe_callback (GIOChannel* source,
1499 GIOCondition condition,
1500 gpointer plugin_data)
1501{
1502 PLUGIN_DEBUG ("plugin_out_pipe_callback\n");
1503
1504 ITNPPluginData* data = (ITNPPluginData*) plugin_data;
1505
1506 PLUGIN_DEBUG ("plugin_out_pipe_callback: appletviewer has stopped.\n");
1507
1508 PLUGIN_DEBUG ("plugin_out_pipe_callback return\n");
1509
1510 return FALSE;
1511}
1512
1513// remove all components from LD_LIBRARY_PATH, which start with
1514// MOZILLA_FIVE_HOME; firefox has its own NSS based security provider,
1515// which conflicts with the one configured in nss.cfg.
1516static gchar*
1517plugin_filter_ld_library_path(gchar *path_old)
1518{
1519 gchar *moz_home = g_strdup (g_getenv ("MOZILLA_FIVE_HOME"));
1520 gchar *moz_prefix;
1521 gchar *path_new;
1522 gchar** components;
1523 int i1, i2;
1524
1525 if (moz_home == NULL || path_old == NULL || strlen (path_old) == 0)
1526 return path_old;
1527 if (g_str_has_suffix (moz_home, "/"))
1528 moz_home[strlen (moz_home - 1)] = '\0';
1529 moz_prefix = g_strconcat (moz_home, "/", NULL);
1530
1531 components = g_strsplit (path_old, ":", -1);
1532 for (i1 = 0, i2 = 0; components[i1] != NULL; i1++)
1533 {
1534 if (g_strcmp0 (components[i1], moz_home) == 0
1535 || g_str_has_prefix (components[i1], moz_home))
1536 components[i2] = components[i1];
1537 else
1538 components[i2++] = components[i1];
1539 }
1540 components[i2] = NULL;
1541
1542 if (i1 > i2)
1543 path_new = g_strjoinv (":", components);
1544 g_strfreev (components);
1545 g_free (moz_home);
1546 g_free (moz_prefix);
1547 g_free (path_old);
1548
1549 if (path_new == NULL || strlen (path_new) == 0)
1550 {
1551 PLUGIN_DEBUG("Unset LD_LIBRARY_PATH\n");
1552 return NULL;
1553 }
1554 else
1555 {
1556 PLUGIN_DEBUG ("Set LD_LIBRARY_PATH: %s\n", path_new);
1557 return path_new;
1558 }
1559}
1560
1561// build the environment to pass to the external plugin process
1562static gchar**
1563plugin_filter_environment(void)
1564{
1565 gchar **var_names = g_listenv();
1566 gchar **new_env = (gchar**) malloc(sizeof(gchar*) * (g_strv_length (var_names) + 1));
1567 int i_var, i_env;
1568
1569 for (i_var = 0, i_env = 0; var_names[i_var] != NULL; i_var++)
1570 {
1571 gchar *env_value = g_strdup (g_getenv (var_names[i_var]));
1572
1573 if (g_str_has_prefix (var_names[i_var], "LD_LIBRARY_PATH"))
1574 env_value = plugin_filter_ld_library_path (env_value);
1575 if (env_value != NULL)
1576 {
1577 new_env[i_env++] = g_strdup_printf ("%s=%s", var_names[i_var], env_value);
1578 g_free (env_value);
1579 }
1580 }
1581 new_env[i_env] = NULL;
1582 return new_env;
1583}
1584
1585static NPError
1586plugin_test_appletviewer ()
1587{
1588 PLUGIN_DEBUG ("plugin_test_appletviewer: %s\n", appletviewer_executable);
1589 NPError error = NPERR_NO_ERROR;
1590
1591 gchar* command_line[3] = { NULL, NULL, NULL };
1592 gchar** environment;
1593
1594 command_line[0] = g_strdup (appletviewer_executable);
1595 command_line[1] = g_strdup("-version");
1596 command_line[2] = NULL;
1597
1598 environment = plugin_filter_environment();
1599
1600 if (!g_spawn_async (NULL, command_line, environment,
1601 (GSpawnFlags) 0,
1602 NULL, NULL, NULL, &channel_error))
1603 {
1604 if (channel_error)
1605 {
1606 PLUGIN_ERROR_TWO ("Failed to spawn applet viewer",
1607 channel_error->message);
1608 g_error_free (channel_error);
1609 channel_error = NULL;
1610 }
1611 else
1612 PLUGIN_ERROR ("Failed to spawn applet viewer");
1613 error = NPERR_GENERIC_ERROR;
1614 }
1615
1616 g_strfreev (environment);
1617
1618 g_free (command_line[0]);
1619 command_line[0] = NULL;
1620 g_free (command_line[1]);
1621 command_line[1] = NULL;
1622 g_free (command_line[2]);
1623 command_line[2] = NULL;
1624
1625 PLUGIN_DEBUG ("plugin_test_appletviewer return\n");
1626 return error;
1627}
1628
1629static NPError
1630plugin_start_appletviewer (ITNPPluginData* data)
1631{
1632 PLUGIN_DEBUG ("plugin_start_appletviewer\n");
1633 NPError error = NPERR_NO_ERROR;
1634
1635 gchar** command_line;
1636 gchar** environment;
1637
1638 int cmd_num = 0;
1639 if (plugin_debug)
1640 {
1641 command_line = (gchar**) malloc(sizeof(gchar*)*11);
1642 command_line[cmd_num++] = g_strdup(appletviewer_executable);
1643 command_line[cmd_num++] = g_strdup_printf(PLUGIN_BOOTCLASSPATH);
1644 // set the classpath to avoid using the default (cwd).
1645 command_line[cmd_num++] = g_strdup("-classpath");
1646 command_line[cmd_num++] = g_strdup_printf("%s/lib/rt.jar", ICEDTEA_WEB_JRE);
1647 command_line[cmd_num++] = g_strdup("-Xdebug");
1648 command_line[cmd_num++] = g_strdup("-Xnoagent");
1649 if (plugin_debug_suspend)
1650 {
1651 command_line[cmd_num++] = g_strdup("-Xrunjdwp:transport="DT_SOCKET_DLL",address=8787,server=y,suspend=y");
1652 } else
1653 {
1654 command_line[cmd_num++] = g_strdup("-Xrunjdwp:transport="DT_SOCKET_DLL",address=8787,server=y,suspend=n");
1655 }
1656 command_line[cmd_num++] = g_strdup("sun.applet.PluginMain");
1657#ifdef __OS2__
1658 command_line[cmd_num++] = g_strdup_printf("%d", out_pipe [1]);
1659 command_line[cmd_num++] = g_strdup_printf("%d", in_pipe [1]);
1660#else
1661 command_line[cmd_num++] = g_strdup(out_pipe_name);
1662 command_line[cmd_num++] = g_strdup(in_pipe_name);
1663#endif
1664 command_line[cmd_num] = NULL;
1665 } else
1666 {
1667 command_line = (gchar**) malloc(sizeof(gchar*)*8);
1668 command_line[cmd_num++] = g_strdup(appletviewer_executable);
1669 command_line[cmd_num++] = g_strdup_printf(PLUGIN_BOOTCLASSPATH);
1670 command_line[cmd_num++] = g_strdup("-classpath");
1671 command_line[cmd_num++] = g_strdup_printf("%s/lib/rt.jar", ICEDTEA_WEB_JRE);
1672 command_line[cmd_num++] = g_strdup("sun.applet.PluginMain");
1673#ifdef __OS2__
1674 command_line[cmd_num++] = g_strdup_printf("%d", out_pipe [1]);
1675 command_line[cmd_num++] = g_strdup_printf("%d", in_pipe [1]);
1676#else
1677 command_line[cmd_num++] = g_strdup(out_pipe_name);
1678 command_line[cmd_num++] = g_strdup(in_pipe_name);
1679#endif
1680 command_line[cmd_num] = NULL;
1681 }
1682
1683 environment = plugin_filter_environment();
1684
1685#ifdef __OS2__
1686 int flags = G_SPAWN_LEAVE_DESCRIPTORS_OPEN | G_SPAWN_DO_NOT_REAP_CHILD;
1687#else
1688 int flags = G_SPAWN_DO_NOT_REAP_CHILD;
1689#endif
1690
1691 if (!g_spawn_async (NULL, command_line, environment,
1692 (GSpawnFlags) flags,
1693 NULL, NULL, &appletviewer_pid, &channel_error))
1694 {
1695 if (channel_error)
1696 {
1697 PLUGIN_ERROR_TWO ("Failed to spawn applet viewer",
1698 channel_error->message);
1699 g_error_free (channel_error);
1700 channel_error = NULL;
1701 }
1702 else
1703 PLUGIN_ERROR ("Failed to spawn applet viewer");
1704 error = NPERR_GENERIC_ERROR;
1705 }
1706
1707 // make sure we get an error rather than crash the browser when talking to the
1708 // jvm process if it dies unexpectedly (we do it here since g_spawn() is known
1709 // to reset SIGPIPE handler to SIG_DFL)
1710 signal (SIGPIPE, SIG_IGN);
1711
1712 g_strfreev (environment);
1713
1714 for (int i = 0; i < cmd_num; i++) {
1715 g_free (command_line[i]);
1716 command_line[i] = NULL;
1717 }
1718
1719 g_free(command_line);
1720 command_line = NULL;
1721
1722 if (appletviewer_pid)
1723 {
1724 PLUGIN_DEBUG("Initialized VM with pid=%d\n", appletviewer_pid);
1725 appletviewer_watch_id = g_child_watch_add(appletviewer_pid, (GChildWatchFunc) appletviewer_monitor, (gpointer) appletviewer_pid);
1726 }
1727
1728
1729 PLUGIN_DEBUG ("plugin_start_appletviewer return\n");
1730 return error;
1731}
1732
1733/*
1734 * Replaces certain characters (\r, \n, etc) with HTML escape equivalents.
1735 *
1736 * Return string is allocated on the heap. Caller assumes responsibility
1737 * for freeing the memory via free()
1738 */
1739static char*
1740encode_string(char* to_encode)
1741{
1742
1743 // Do nothing for an empty string
1744 if (to_encode == '\0')
1745 return to_encode;
1746
1747 // worst case scenario -> all characters are newlines or
1748 // returns, each of which translates to 5 substitutions
1749 char* encoded = (char*) calloc(((strlen(to_encode)*5)+1), sizeof(char));
1750
1751 strcpy(encoded, "");
1752
1753 for (int i=0; i < strlen(to_encode); i++)
1754 {
1755 if (to_encode[i] == '\r')
1756 encoded = strcat(encoded, "&#13;");
1757 else if (to_encode[i] == '\n')
1758 encoded = strcat(encoded, "&#10;");
1759 else if (to_encode[i] == '>')
1760 encoded = strcat(encoded, "&gt;");
1761 else if (to_encode[i] == '<')
1762 encoded = strcat(encoded, "&lt;");
1763 else if (to_encode[i] == '&')
1764 encoded = strcat(encoded, "&amp;");
1765 else if (to_encode[i] == '"')
1766 encoded = strcat(encoded, "&quot;");
1767 else
1768 {
1769 char* orig_char = (char*) calloc(2, sizeof(char));
1770 orig_char[0] = to_encode[i];
1771 orig_char[1] = '\0';
1772
1773 strcat(encoded, orig_char);
1774
1775 free(orig_char);
1776 orig_char = NULL;
1777 }
1778 }
1779
1780 return encoded;
1781}
1782
1783// Build up the applet tag string that we'll send to the applet
1784// viewer.
1785static gchar*
1786plugin_create_applet_tag (int16_t argc, char* argn[], char* argv[])
1787{
1788 PLUGIN_DEBUG ("plugin_create_applet_tag\n");
1789
1790 gchar* applet_tag = g_strdup ("<EMBED ");
1791 gchar* parameters = g_strdup ("");
1792
1793 for (int16_t i = 0; i < argc; i++)
1794 {
1795 gchar* argn_escaped = encode_string(argn[i]);
1796 gchar* argv_escaped = encode_string(argv[i]);
1797
1798 if (!g_ascii_strcasecmp (argn_escaped, "code"))
1799 {
1800 gchar* code = g_strdup_printf ("CODE=\"%s\" ", argv_escaped);
1801 applet_tag = g_strconcat (applet_tag, code, NULL);
1802 g_free (code);
1803 code = NULL;
1804 }
1805 else if (!g_ascii_strcasecmp (argn_escaped, "java_code"))
1806 {
1807 gchar* java_code = g_strdup_printf ("JAVA_CODE=\"%s\" ", argv_escaped);
1808 applet_tag = g_strconcat (applet_tag, java_code, NULL);
1809 g_free (java_code);
1810 java_code = NULL;
1811 }
1812 else if (!g_ascii_strcasecmp (argn_escaped, "codebase"))
1813 {
1814 gchar* codebase = g_strdup_printf ("CODEBASE=\"%s\" ", argv_escaped);
1815 applet_tag = g_strconcat (applet_tag, codebase, NULL);
1816 g_free (codebase);
1817 codebase = NULL;
1818 }
1819 else if (!g_ascii_strcasecmp (argn_escaped, "java_codebase"))
1820 {
1821 gchar* java_codebase = g_strdup_printf ("JAVA_CODEBASE=\"%s\" ", argv_escaped);
1822 applet_tag = g_strconcat (applet_tag, java_codebase, NULL);
1823 g_free (java_codebase);
1824 java_codebase = NULL;
1825 }
1826 else if (!g_ascii_strcasecmp (argn_escaped, "classid"))
1827 {
1828 gchar* classid = g_strdup_printf ("CLASSID=\"%s\" ", argv_escaped);
1829 applet_tag = g_strconcat (applet_tag, classid, NULL);
1830 g_free (classid);
1831 classid = NULL;
1832 }
1833 else if (!g_ascii_strcasecmp (argn_escaped, "archive"))
1834 {
1835 gchar* archive = g_strdup_printf ("ARCHIVE=\"%s\" ", argv_escaped);
1836 applet_tag = g_strconcat (applet_tag, archive, NULL);
1837 g_free (archive);
1838 archive = NULL;
1839 }
1840 else if (!g_ascii_strcasecmp (argn_escaped, "java_archive"))
1841 {
1842 gchar* java_archive = g_strdup_printf ("JAVA_ARCHIVE=\"%s\" ", argv_escaped);
1843 applet_tag = g_strconcat (applet_tag, java_archive, NULL);
1844 g_free (java_archive);
1845 java_archive = NULL;
1846 }
1847 else if (!g_ascii_strcasecmp (argn_escaped, "width"))
1848 {
1849 gchar* width = g_strdup_printf ("width=\"%s\" ", argv_escaped);
1850 applet_tag = g_strconcat (applet_tag, width, NULL);
1851 g_free (width);
1852 width = NULL;
1853 }
1854 else if (!g_ascii_strcasecmp (argn_escaped, "height"))
1855 {
1856 gchar* height = g_strdup_printf ("height=\"%s\" ", argv_escaped);
1857 applet_tag = g_strconcat (applet_tag, height, NULL);
1858 g_free (height);
1859 height = NULL;
1860 }
1861 else
1862 {
1863
1864 if (argv_escaped != '\0')
1865 {
1866 parameters = g_strconcat (parameters, "<PARAM NAME=\"", argn_escaped,
1867 "\" VALUE=\"", argv_escaped, "\">", NULL);
1868 }
1869 }
1870
1871 free(argn_escaped);
1872 free(argv_escaped);
1873
1874 argn_escaped = NULL;
1875 argv_escaped = NULL;
1876 }
1877
1878 applet_tag = g_strconcat (applet_tag, ">", parameters, "</EMBED>", NULL);
1879
1880 g_free (parameters);
1881 parameters = NULL;
1882
1883 PLUGIN_DEBUG ("plugin_create_applet_tag return\n");
1884
1885 return applet_tag;
1886}
1887
1888// plugin_send_message_to_appletviewer must be called while holding
1889// data->appletviewer_mutex.
1890void
1891plugin_send_message_to_appletviewer (gchar const* message)
1892{
1893 PLUGIN_DEBUG ("plugin_send_message_to_appletviewer\n");
1894
1895 if (jvm_up)
1896 {
1897 gchar* newline_message = NULL;
1898 gsize bytes_written = 0;
1899
1900 // Send message to appletviewer.
1901 newline_message = g_strdup_printf ("%s\n", message);
1902
1903 // g_io_channel_write_chars will return something other than
1904 // G_IO_STATUS_NORMAL if not all the data is written. In that
1905 // case we fail rather than retrying.
1906 if (g_io_channel_write_chars (out_to_appletviewer,
1907 newline_message, -1, &bytes_written,
1908 &channel_error)
1909 != G_IO_STATUS_NORMAL)
1910 {
1911 if (channel_error)
1912 {
1913 PLUGIN_ERROR_TWO ("Failed to write bytes to output channel",
1914 channel_error->message);
1915 g_error_free (channel_error);
1916 channel_error = NULL;
1917 }
1918 else
1919 PLUGIN_ERROR ("Failed to write bytes to output channel");
1920 }
1921
1922 if (g_io_channel_flush (out_to_appletviewer, &channel_error)
1923 != G_IO_STATUS_NORMAL)
1924 {
1925 if (channel_error)
1926 {
1927 PLUGIN_ERROR_TWO ("Failed to flush bytes to output channel",
1928 channel_error->message);
1929 g_error_free (channel_error);
1930 channel_error = NULL;
1931 }
1932 else
1933 PLUGIN_ERROR ("Failed to flush bytes to output channel");
1934 }
1935 g_free (newline_message);
1936 newline_message = NULL;
1937
1938 PLUGIN_DEBUG (" PIPE: plugin wrote: %s\n", message);
1939 }
1940
1941 PLUGIN_DEBUG ("plugin_send_message_to_appletviewer return\n");
1942}
1943
1944/*
1945 * Sends the initialization message (handle/size/url) to the plugin
1946 */
1947void
1948plugin_send_initialization_message(char* instance, gulong handle,
1949 int width, int height, char* url)
1950{
1951 PLUGIN_DEBUG ("plugin_send_initialization_message\n");
1952
1953 gchar *window_message = g_strdup_printf ("instance %s handle %ld width %d height %d %s",
1954 instance, handle, width, height, url);
1955 plugin_send_message_to_appletviewer (window_message);
1956 g_free (window_message);
1957 window_message = NULL;
1958
1959 PLUGIN_DEBUG ("plugin_send_initialization_message return\n");
1960}
1961
1962
1963// Stop the appletviewer process. When this is called the
1964// appletviewer can be in any of three states: running, crashed or
1965// hung. If the appletviewer is running then sending it "shutdown"
1966// will cause it to exit. This will cause
1967// plugin_out_pipe_callback/plugin_in_pipe_callback to be called and
1968// the input and output channels to be shut down. If the appletviewer
1969// has crashed then plugin_out_pipe_callback/plugin_in_pipe_callback
1970// would already have been called and data->appletviewer_alive cleared
1971// in which case this function simply returns. If the appletviewer is
1972// hung then this function will be successful and the input and output
1973// watches will be removed by plugin_data_destroy.
1974// plugin_stop_appletviewer must be called with
1975// data->appletviewer_mutex held.
1976static void
1977plugin_stop_appletviewer ()
1978{
1979 PLUGIN_DEBUG ("plugin_stop_appletviewer\n");
1980
1981 if (jvm_up)
1982 {
1983 // Shut down the appletviewer.
1984 gsize bytes_written = 0;
1985
1986 if (out_to_appletviewer)
1987 {
1988 if (g_io_channel_write_chars (out_to_appletviewer, "shutdown",
1989 -1, &bytes_written, &channel_error)
1990 != G_IO_STATUS_NORMAL)
1991 {
1992 if (channel_error)
1993 {
1994 PLUGIN_ERROR_TWO ("Failed to write shutdown message to"
1995 " appletviewer", channel_error->message);
1996 g_error_free (channel_error);
1997 channel_error = NULL;
1998 }
1999 else
2000 PLUGIN_ERROR ("Failed to write shutdown message to");
2001 }
2002
2003 if (g_io_channel_flush (out_to_appletviewer, &channel_error)
2004 != G_IO_STATUS_NORMAL)
2005 {
2006 if (channel_error)
2007 {
2008 PLUGIN_ERROR_TWO ("Failed to write shutdown message to"
2009 " appletviewer", channel_error->message);
2010 g_error_free (channel_error);
2011 channel_error = NULL;
2012 }
2013 else
2014 PLUGIN_ERROR ("Failed to write shutdown message to");
2015 }
2016
2017 if (g_io_channel_shutdown (out_to_appletviewer,
2018 TRUE, &channel_error)
2019 != G_IO_STATUS_NORMAL)
2020 {
2021 if (channel_error)
2022 {
2023 PLUGIN_ERROR_TWO ("Failed to shut down appletviewer"
2024 " output channel", channel_error->message);
2025 g_error_free (channel_error);
2026 channel_error = NULL;
2027 }
2028 else
2029 PLUGIN_ERROR ("Failed to shut down appletviewer");
2030 }
2031 }
2032
2033 if (in_from_appletviewer)
2034 {
2035 if (g_io_channel_shutdown (in_from_appletviewer,
2036 TRUE, &channel_error)
2037 != G_IO_STATUS_NORMAL)
2038 {
2039 if (channel_error)
2040 {
2041 PLUGIN_ERROR_TWO ("Failed to shut down appletviewer"
2042 " input channel", channel_error->message);
2043 g_error_free (channel_error);
2044 channel_error = NULL;
2045 }
2046 else
2047 PLUGIN_ERROR ("Failed to shut down appletviewer");
2048 }
2049 }
2050 }
2051
2052 jvm_up = FALSE;
2053 sleep(2); /* Needed to prevent crashes during debug (when JDWP port is not freed by the kernel right away) */
2054
2055 PLUGIN_DEBUG ("plugin_stop_appletviewer return\n");
2056}
2057
2058static void appletviewer_monitor(GPid pid, gint status, gpointer data)
2059{
2060 PLUGIN_DEBUG ("appletviewer_monitor\n");
2061 jvm_up = FALSE;
2062 pid = -1;
2063 PLUGIN_DEBUG ("appletviewer_monitor return\n");
2064}
2065
2066static void
2067plugin_data_destroy (NPP instance)
2068{
2069 PLUGIN_DEBUG ("plugin_data_destroy\n");
2070
2071 ITNPPluginData* tofree = (ITNPPluginData*) instance->pdata;
2072
2073 // Remove instance from map
2074 gpointer id_ptr = g_hash_table_lookup(instance_to_id_map, instance);
2075
2076 if (id_ptr)
2077 {
2078 gint id = GPOINTER_TO_INT(id_ptr);
2079 g_hash_table_remove(instance_to_id_map, instance);
2080 g_hash_table_remove(id_to_instance_map, id_ptr);
2081 }
2082
2083 tofree->window_handle = NULL;
2084 tofree->window_height = 0;
2085 tofree->window_width = 0;
2086
2087 // cleanup_appletviewer_mutex:
2088 g_free (tofree->appletviewer_mutex);
2089 tofree->appletviewer_mutex = NULL;
2090
2091 // cleanup_instance_string:
2092 g_free (tofree->instance_id);
2093 tofree->instance_id = NULL;
2094
2095 // cleanup applet tag
2096 g_free (tofree->applet_tag);
2097 tofree->applet_tag = NULL;
2098
2099 g_free(tofree->source);
2100 tofree->source = NULL;
2101
2102 // cleanup_data:
2103 // Eliminate back-pointer to plugin instance.
2104 tofree->owner = NULL;
2105 (*browser_functions.memfree) (tofree);
2106 tofree = NULL;
2107
2108 PLUGIN_DEBUG ("plugin_data_destroy return\n");
2109}
2110
2111static NPError
2112plugin_get_entry_points (NPPluginFuncs* pluginTable)
2113{
2114 // Ensure that the plugin function table we've received is large
2115 // enough to store the number of functions that we may provide.
2116 if (pluginTable->size < sizeof (NPPluginFuncs))
2117 {
2118 PLUGIN_ERROR ("Invalid plugin function table.");
2119
2120 return NPERR_INVALID_FUNCTABLE_ERROR;
2121 }
2122
2123 // Return to the browser the plugin functions that we implement.
2124 pluginTable->version = (NP_VERSION_MAJOR << 8) + NP_VERSION_MINOR;
2125 pluginTable->size = sizeof (NPPluginFuncs);
2126
2127#if MOZILLA_VERSION_COLLAPSED < 1090100
2128 pluginTable->newp = NewNPP_NewProc (ITNP_New);
2129 pluginTable->destroy = NewNPP_DestroyProc (ITNP_Destroy);
2130 pluginTable->setwindow = NewNPP_SetWindowProc (ITNP_SetWindow);
2131 pluginTable->newstream = NewNPP_NewStreamProc (ITNP_NewStream);
2132 pluginTable->destroystream = NewNPP_DestroyStreamProc (ITNP_DestroyStream);
2133 pluginTable->asfile = NewNPP_StreamAsFileProc (ITNP_StreamAsFile);
2134 pluginTable->writeready = NewNPP_WriteReadyProc (ITNP_WriteReady);
2135 pluginTable->write = NewNPP_WriteProc (ITNP_Write);
2136 pluginTable->print = NewNPP_PrintProc (ITNP_Print);
2137 pluginTable->urlnotify = NewNPP_URLNotifyProc (ITNP_URLNotify);
2138 pluginTable->getvalue = NewNPP_GetValueProc (ITNP_GetValue);
2139#else
2140 pluginTable->newp = NPP_NewProcPtr (ITNP_New);
2141 pluginTable->destroy = NPP_DestroyProcPtr (ITNP_Destroy);
2142 pluginTable->setwindow = NPP_SetWindowProcPtr (ITNP_SetWindow);
2143 pluginTable->newstream = NPP_NewStreamProcPtr (ITNP_NewStream);
2144 pluginTable->destroystream = NPP_DestroyStreamProcPtr (ITNP_DestroyStream);
2145 pluginTable->asfile = NPP_StreamAsFileProcPtr (ITNP_StreamAsFile);
2146 pluginTable->writeready = NPP_WriteReadyProcPtr (ITNP_WriteReady);
2147 pluginTable->write = NPP_WriteProcPtr (ITNP_Write);
2148 pluginTable->print = NPP_PrintProcPtr (ITNP_Print);
2149 pluginTable->urlnotify = NPP_URLNotifyProcPtr (ITNP_URLNotify);
2150 pluginTable->getvalue = NPP_GetValueProcPtr (ITNP_GetValue);
2151#endif
2152
2153 return NPERR_NO_ERROR;
2154}
2155
2156// FACTORY FUNCTIONS
2157
2158// Provides the browser with pointers to the plugin functions that we
2159// implement and initializes a local table with browser functions that
2160// we may wish to call. Called once, after browser startup and before
2161// the first plugin instance is created.
2162// The field 'initialized' is set to true once this function has
2163// finished. If 'initialized' is already true at the beginning of
2164// this function, then it is evident that NP_Initialize has already
2165// been called. There is no need to call this function more than once and
2166// this workaround avoids any duplicate calls.
2167NPError
2168#if defined(_WIN32) || defined (__OS2__)
2169OSCALL NP_Initialize (NPNetscapeFuncs* browserTable)
2170#else
2171OSCALL NP_Initialize (NPNetscapeFuncs* browserTable, NPPluginFuncs* pluginTable)
2172#endif
2173{
2174 PLUGIN_DEBUG ("NP_Initialize\n");
2175
2176#if defined(_WIN32) || defined (__OS2__)
2177 if (browserTable == NULL)
2178 {
2179 PLUGIN_ERROR ("Browser function table is NULL.");
2180
2181 return NPERR_INVALID_FUNCTABLE_ERROR;
2182 }
2183#else
2184 if ((browserTable == NULL) || (pluginTable == NULL))
2185 {
2186 PLUGIN_ERROR ("Browser or plugin function table is NULL.");
2187
2188 return NPERR_INVALID_FUNCTABLE_ERROR;
2189 }
2190#endif
2191
2192 // Ensure that the major version of the plugin API that the browser
2193 // expects is not more recent than the major version of the API that
2194 // we've implemented.
2195 if ((browserTable->version >> 8) > NP_VERSION_MAJOR)
2196 {
2197 PLUGIN_ERROR ("Incompatible version.");
2198
2199 return NPERR_INCOMPATIBLE_VERSION_ERROR;
2200 }
2201
2202 // Ensure that the browser function table is large enough to store
2203 // the number of browser functions that we may use.
2204 if (browserTable->size < sizeof (NPNetscapeFuncs))
2205 {
2206 fprintf (stderr, "ERROR: Invalid browser function table. Some functionality may be restricted.\n");
2207 }
2208
2209 // Store in a local table the browser functions that we may use.
2210 browser_functions.size = browserTable->size;
2211 browser_functions.version = browserTable->version;
2212 browser_functions.geturlnotify = browserTable->geturlnotify;
2213 browser_functions.geturl = browserTable->geturl;
2214 browser_functions.posturlnotify = browserTable->posturlnotify;
2215 browser_functions.posturl = browserTable->posturl;
2216 browser_functions.requestread = browserTable->requestread;
2217 browser_functions.newstream = browserTable->newstream;
2218 browser_functions.write = browserTable->write;
2219 browser_functions.destroystream = browserTable->destroystream;
2220 browser_functions.status = browserTable->status;
2221 browser_functions.uagent = browserTable->uagent;
2222 browser_functions.memalloc = browserTable->memalloc;
2223 browser_functions.memfree = browserTable->memfree;
2224 browser_functions.memflush = browserTable->memflush;
2225 browser_functions.reloadplugins = browserTable->reloadplugins;
2226 browser_functions.getJavaEnv = browserTable->getJavaEnv;
2227 browser_functions.getJavaPeer = browserTable->getJavaPeer;
2228 browser_functions.getvalue = browserTable->getvalue;
2229 browser_functions.setvalue = browserTable->setvalue;
2230 browser_functions.invalidaterect = browserTable->invalidaterect;
2231 browser_functions.invalidateregion = browserTable->invalidateregion;
2232 browser_functions.forceredraw = browserTable->forceredraw;
2233 browser_functions.getstringidentifier = browserTable->getstringidentifier;
2234 browser_functions.getstringidentifiers = browserTable->getstringidentifiers;
2235 browser_functions.getintidentifier = browserTable->getintidentifier;
2236 browser_functions.identifierisstring = browserTable->identifierisstring;
2237 browser_functions.utf8fromidentifier = browserTable->utf8fromidentifier;
2238 browser_functions.intfromidentifier = browserTable->intfromidentifier;
2239 browser_functions.createobject = browserTable->createobject;
2240 browser_functions.retainobject = browserTable->retainobject;
2241 browser_functions.releaseobject = browserTable->releaseobject;
2242 browser_functions.invoke = browserTable->invoke;
2243 browser_functions.invokeDefault = browserTable->invokeDefault;
2244 browser_functions.evaluate = browserTable->evaluate;
2245 browser_functions.getproperty = browserTable->getproperty;
2246 browser_functions.setproperty = browserTable->setproperty;
2247 browser_functions.removeproperty = browserTable->removeproperty;
2248 browser_functions.hasproperty = browserTable->hasproperty;
2249 browser_functions.hasmethod = browserTable->hasmethod;
2250 browser_functions.releasevariantvalue = browserTable->releasevariantvalue;
2251 browser_functions.setexception = browserTable->setexception;
2252 browser_functions.pluginthreadasynccall = browserTable->pluginthreadasynccall;
2253#if MOZILLA_VERSION_COLLAPSED >= 1090100
2254 browser_functions.getvalueforurl = browserTable->getvalueforurl;
2255 browser_functions.setvalueforurl = browserTable->setvalueforurl;
2256#endif
2257
2258 NPError np_error = NPERR_NO_ERROR;
2259#if !defined(_WIN32) && !defined (__OS2__)
2260 np_error = plugin_get_entry_points (pluginTable);
2261 if (np_error != NPERR_NO_ERROR)
2262 return np_error;
2263#endif
2264
2265 // Re-setting the above tables multiple times is OK (as the
2266 // browser may change its function locations). However
2267 // anything beyond this point should only run once.
2268 if (initialized)
2269 return NPERR_NO_ERROR;
2270
2271#ifdef __OS2__
2272 // perform OS-specific initialization
2273 if (!init_os())
2274 {
2275 PLUGIN_ERROR ("Failed to perform OS-specific initialization.");
2276 return NPERR_GENERIC_ERROR;
2277 }
2278#endif
2279
2280#ifndef __OS2__
2281 // Make sure the plugin data directory exists, creating it if
2282 // necessary.
2283 data_directory = g_strconcat (P_tmpdir, 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 // If P_tmpdir does not exist, try /tmp directly
2291
2292 if (!g_file_test (data_directory,
2293 (GFileTest) (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)))
2294 {
2295 data_directory = g_strconcat ("/tmp", NULL);
2296 if (!data_directory)
2297 {
2298 PLUGIN_ERROR ("Failed to create data directory name.");
2299 return NPERR_OUT_OF_MEMORY_ERROR;
2300 }
2301
2302 }
2303
2304 data_directory = g_strconcat (data_directory, "/icedteaplugin-", getenv("USER"), NULL);
2305
2306 if (!data_directory)
2307 {
2308 PLUGIN_ERROR ("Failed to create data directory name.");
2309 return NPERR_OUT_OF_MEMORY_ERROR;
2310 }
2311
2312 // Now create a icedteaplugin subdir
2313 if (!g_file_test (data_directory,
2314 (GFileTest) (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)))
2315 {
2316 int file_error = 0;
2317
2318 file_error = g_mkdir (data_directory, 0700);
2319 if (file_error != 0)
2320 {
2321 PLUGIN_ERROR_THREE ("Failed to create data directory",
2322 data_directory,
2323 strerror (errno));
2324 np_error = NPERR_GENERIC_ERROR;
2325 goto cleanup_data_directory;
2326 }
2327 }
2328
2329
2330 // If data directory doesn't exit by this point, bail
2331 if (!g_file_test (data_directory,
2332 (GFileTest) (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)))
2333 {
2334 PLUGIN_ERROR_THREE ("Temp directory does not exist: ",
2335 data_directory,
2336 strerror (errno));
2337
2338 np_error = NPERR_GENERIC_ERROR;
2339 goto cleanup_data_directory;
2340
2341 }
2342#endif
2343
2344 // Set appletviewer_executable.
2345 gchar* filename = g_strdup(ICEDTEA_WEB_JRE);
2346 appletviewer_executable = g_strdup_printf ("%s/bin/java",
2347 filename);
2348 PLUGIN_DEBUG("Executing java at %s\n", appletviewer_executable);
2349 if (!appletviewer_executable)
2350 {
2351 PLUGIN_ERROR ("Failed to create appletviewer executable name.");
2352 np_error = NPERR_OUT_OF_MEMORY_ERROR;
2353 goto cleanup_filename;
2354 }
2355
2356 np_error = plugin_test_appletviewer ();
2357 if (np_error != NPERR_NO_ERROR)
2358 {
2359 plugin_display_failure_dialog ();
2360 goto cleanup_appletviewer_executable;
2361 }
2362 g_free (filename);
2363
2364 // Initialize threads (needed for mutexes).
2365 if (!g_thread_supported ())
2366 g_thread_init (NULL);
2367
2368#ifdef __OS2__
2369 if (!g_main_context_os2_start_pm_integration (NULL))
2370 {
2371 PLUGIN_DEBUG ("Failed to integrate with PM");
2372 np_error = NPERR_GENERIC_ERROR;
2373 goto cleanup_appletviewer_executable;
2374 }
2375#endif
2376
2377 plugin_instance_mutex = g_mutex_new ();
2378
2379 PLUGIN_DEBUG ("NP_Initialize: using %s\n", appletviewer_executable);
2380
2381 plugin_req_proc = new PluginRequestProcessor();
2382 java_req_proc = new JavaMessageSender();
2383
2384 java_to_plugin_bus = new MessageBus();
2385 plugin_to_java_bus = new MessageBus();
2386
2387 java_to_plugin_bus->subscribe(plugin_req_proc);
2388 plugin_to_java_bus->subscribe(java_req_proc);
2389
2390#ifdef __OS2__
2391 queue_processor_data1.processor = plugin_req_proc;
2392 queue_processor_data2.processor = plugin_req_proc;
2393 queue_processor_data3.processor = plugin_req_proc;
2394 pthread_create (&plugin_request_processor_thread1, NULL, &queue_processor, (void*) &queue_processor_data1);
2395 pthread_create (&plugin_request_processor_thread2, NULL, &queue_processor, (void*) &queue_processor_data2);
2396 pthread_create (&plugin_request_processor_thread3, NULL, &queue_processor, (void*) &queue_processor_data3);
2397#else
2398 pthread_create (&plugin_request_processor_thread1, NULL, &queue_processor, (void*) plugin_req_proc);
2399 pthread_create (&plugin_request_processor_thread2, NULL, &queue_processor, (void*) plugin_req_proc);
2400 pthread_create (&plugin_request_processor_thread3, NULL, &queue_processor, (void*) plugin_req_proc);
2401#endif
2402
2403 itnp_plugin_thread_id = pthread_self();
2404
2405 pthread_mutexattr_t attribute;
2406 pthread_mutexattr_init(&attribute);
2407 pthread_mutexattr_settype(&attribute, PTHREAD_MUTEX_RECURSIVE);
2408 pthread_mutex_init(&pluginAsyncCallMutex, &attribute);
2409 pthread_mutexattr_destroy(&attribute);
2410
2411 initialized = true;
2412
2413 PLUGIN_DEBUG ("NP_Initialize return\n");
2414
2415 return NPERR_NO_ERROR;
2416
2417 cleanup_appletviewer_executable:
2418 if (appletviewer_executable)
2419 {
2420 g_free (appletviewer_executable);
2421 appletviewer_executable = NULL;
2422 }
2423
2424 cleanup_filename:
2425 if (filename)
2426 {
2427 g_free (filename);
2428 filename = NULL;
2429 }
2430
2431 cleanup_data_directory:
2432 if (data_directory)
2433 {
2434 g_free (data_directory);
2435 data_directory = NULL;
2436 }
2437
2438
2439 return np_error;
2440}
2441
2442#if defined(_WIN32) || defined (__OS2__)
2443NPError
2444OSCALL NP_GetEntryPoints (NPPluginFuncs* pluginTable)
2445{
2446 PLUGIN_DEBUG ("NP_GetEntryPoints\n");
2447
2448 if (pluginTable == NULL)
2449 {
2450 PLUGIN_ERROR ("Plugin function table is NULL.");
2451
2452 return NPERR_INVALID_FUNCTABLE_ERROR;
2453 }
2454
2455 return plugin_get_entry_points (pluginTable);
2456}
2457#endif
2458
2459// Returns a string describing the MIME type that this plugin
2460// handles.
2461const char*
2462OSCALL NP_GetMIMEDescription ()
2463{
2464 PLUGIN_DEBUG ("NP_GetMIMEDescription\n");
2465
2466 PLUGIN_DEBUG ("NP_GetMIMEDescription return\n");
2467
2468 return PLUGIN_MIME_DESC;
2469}
2470
2471// Returns a value relevant to the plugin as a whole. The browser
2472// calls this function to obtain information about the plugin.
2473NPError
2474OSCALL NP_GetValue (void* future, NPPVariable variable, void* value)
2475{
2476 PLUGIN_DEBUG ("NP_GetValue\n");
2477
2478 NPError result = NPERR_NO_ERROR;
2479 gchar** char_value = (gchar**) value;
2480
2481 switch (variable)
2482 {
2483 case NPPVpluginNameString:
2484 PLUGIN_DEBUG ("NP_GetValue: returning plugin name.\n");
2485 *char_value = g_strdup (PLUGIN_FULL_NAME);
2486 break;
2487
2488 case NPPVpluginDescriptionString:
2489 PLUGIN_DEBUG ("NP_GetValue: returning plugin description.\n");
2490 *char_value = g_strdup (PLUGIN_DESC);
2491 break;
2492
2493 default:
2494 PLUGIN_ERROR ("Unknown plugin value requested.");
2495 result = NPERR_GENERIC_ERROR;
2496 break;
2497 }
2498
2499 PLUGIN_DEBUG ("NP_GetValue return\n");
2500
2501 return result;
2502}
2503
2504// Shuts down the plugin. Called after the last plugin instance is
2505// destroyed.
2506NPError
2507OSCALL NP_Shutdown (void)
2508{
2509 PLUGIN_DEBUG ("NP_Shutdown\n");
2510
2511#ifdef __OS2__
2512 g_main_context_os2_stop_pm_integration (NULL);
2513#endif
2514
2515 // Free mutex.
2516 if (plugin_instance_mutex)
2517 {
2518 g_mutex_free (plugin_instance_mutex);
2519 plugin_instance_mutex = NULL;
2520 }
2521
2522 if (data_directory)
2523 {
2524 g_free (data_directory);
2525 data_directory = NULL;
2526 }
2527
2528 if (appletviewer_executable)
2529 {
2530 g_free (appletviewer_executable);
2531 appletviewer_executable = NULL;
2532 }
2533
2534 // stop the appletviewer
2535 plugin_stop_appletviewer();
2536
2537 // remove monitor
2538 if (appletviewer_watch_id != -1)
2539 g_source_remove(appletviewer_watch_id);
2540
2541 // Removing a source is harmless if it fails since it just means the
2542 // source has already been removed.
2543 g_source_remove (in_watch_source);
2544 in_watch_source = 0;
2545
2546 // cleanup_in_from_appletviewer:
2547 if (in_from_appletviewer)
2548 g_io_channel_unref (in_from_appletviewer);
2549 in_from_appletviewer = NULL;
2550
2551 // cleanup_out_watch_source:
2552 g_source_remove (out_watch_source);
2553 out_watch_source = 0;
2554
2555 // cleanup_out_to_appletviewer:
2556 if (out_to_appletviewer)
2557 g_io_channel_unref (out_to_appletviewer);
2558 out_to_appletviewer = NULL;
2559
2560 // cleanup_out_pipe:
2561#ifdef __OS2__
2562 CLOSE_FD (out_pipe [0]);
2563 CLOSE_FD (out_pipe [1]);
2564#else
2565 // Delete output pipe.
2566 PLUGIN_DEBUG ("NP_Shutdown: deleting output fifo: %s\n", out_pipe_name);
2567 unlink (out_pipe_name);
2568 PLUGIN_DEBUG ("NP_Shutdown: deleted output fifo: %s\n", out_pipe_name);
2569
2570 // cleanup_out_pipe_name:
2571 g_free (out_pipe_name);
2572 out_pipe_name = NULL;
2573#endif
2574
2575 // cleanup_in_pipe:
2576#ifdef __OS2__
2577 CLOSE_FD (in_pipe [0]);
2578 CLOSE_FD (in_pipe [1]);
2579#else
2580 // Delete input pipe.
2581 PLUGIN_DEBUG ("NP_Shutdown: deleting input fifo: %s\n", in_pipe_name);
2582 unlink (in_pipe_name);
2583 PLUGIN_DEBUG ("NP_Shutdown: deleted input fifo: %s\n", in_pipe_name);
2584
2585 // cleanup_in_pipe_name:
2586 g_free (in_pipe_name);
2587 in_pipe_name = NULL;
2588#endif
2589
2590 // Destroy the call queue mutex
2591 pthread_mutex_destroy(&pluginAsyncCallMutex);
2592
2593#ifdef __OS2__
2594 // perform OS-specific uninitialization
2595 done_os();
2596#endif
2597
2598 initialized = false;
2599
2600#ifdef __OS2__
2601 // pthread_cancel() isn't implemented on OS?2, so use an old good flag
2602 queue_processor_data1.stopRequested = true;
2603 queue_processor_data2.stopRequested = true;
2604 queue_processor_data3.stopRequested = true;
2605 pthread_cond_broadcast(&cond_message_available);
2606#else
2607 pthread_cancel(plugin_request_processor_thread1);
2608 pthread_cancel(plugin_request_processor_thread2);
2609 pthread_cancel(plugin_request_processor_thread3);
2610#endif
2611
2612 pthread_join(plugin_request_processor_thread1, NULL);
2613 pthread_join(plugin_request_processor_thread2, NULL);
2614 pthread_join(plugin_request_processor_thread3, NULL);
2615
2616 java_to_plugin_bus->unSubscribe(plugin_req_proc);
2617 plugin_to_java_bus->unSubscribe(java_req_proc);
2618 //internal_bus->unSubscribe(java_req_proc);
2619 //internal_bus->unSubscribe(plugin_req_proc);
2620
2621 delete plugin_req_proc;
2622 delete java_req_proc;
2623 delete java_to_plugin_bus;
2624 delete plugin_to_java_bus;
2625 //delete internal_bus;
2626
2627 PLUGIN_DEBUG ("NP_Shutdown return\n");
2628
2629 return NPERR_NO_ERROR;
2630}
2631
2632NPObject*
2633get_scriptable_object(NPP instance)
2634{
2635 NPObject* obj;
2636 ITNPPluginData* data = (ITNPPluginData*) instance->pdata;
2637
2638 if (data->is_applet_instance) // dummy instance/package?
2639 {
2640 JavaRequestProcessor java_request = JavaRequestProcessor();
2641 JavaResultData* java_result;
2642 std::string instance_id = std::string();
2643 std::string applet_class_id = std::string();
2644
2645 int id = get_id_from_instance(instance);
2646 gchar* id_str = g_strdup_printf ("%d", id);
2647
2648 // Some browsers.. (e.g. chromium) don't call NPP_SetWindow
2649 // for 0x0 plugins and therefore require initialization with
2650 // a 0 handle
2651 if (!data->window_handle)
2652 {
2653 plugin_send_initialization_message(data->instance_id, 0, 0, 0, data->applet_tag);
2654 }
2655
2656 java_result = java_request.getAppletObjectInstance(id_str);
2657
2658 g_free(id_str);
2659
2660 if (java_result->error_occurred)
2661 {
2662 printf("Error: Unable to fetch applet instance id from Java side.\n");
2663 return NULL;
2664 }
2665
2666 instance_id.append(*(java_result->return_string));
2667
2668 java_result = java_request.getClassID(instance_id);
2669
2670 if (java_result->error_occurred)
2671 {
2672 printf("Error: Unable to fetch applet instance id from Java side.\n");
2673 return NULL;
2674 }
2675
2676 applet_class_id.append(*(java_result->return_string));
2677
2678 obj = IcedTeaScriptableJavaPackageObject::get_scriptable_java_object(instance, applet_class_id, instance_id, false);
2679
2680 } else
2681 {
2682 obj = IcedTeaScriptablePluginObject::get_scriptable_java_package_object(instance, "");
2683 }
2684
2685 return obj;
2686}
2687
2688NPObject*
2689allocate_scriptable_object(NPP npp, NPClass *aClass)
2690{
2691 PLUGIN_DEBUG("Allocating new scriptable object\n");
2692 return new IcedTeaScriptablePluginObject(npp);
2693}
2694
2695#ifdef __OS2__
2696
2697// Make sure static initializers in the plugin DLL are called
2698
2699static APIENTRY void cleanup(ULONG ulReason)
2700{
2701 __ctordtorTerm();
2702 _CRT_term();
2703 DosExitList(EXLST_EXIT, cleanup);
2704}
2705
2706unsigned long _System _DLL_InitTerm(unsigned long hModule,
2707 unsigned long ulFlag)
2708{
2709 APIRET arc;
2710
2711 if (ulFlag == 0)
2712 {
2713 arc = DosExitList (EXLST_ADD, cleanup);
2714 if (arc != NO_ERROR)
2715 return 0;
2716
2717 if (_CRT_init() != 0) // failure?
2718 return 0;
2719 __ctordtorInit();
2720 }
2721
2722 return 1;
2723}
2724
2725#endif /* __OS2__ */
Note: See TracBrowser for help on using the repository browser.