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

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

icedtea-web: Pass file descriptors to JVM process rather than pipe names.

Pipes on OS/2 don't have real FS entries so the Unix approach wouldn't work.

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