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

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

icedtea-web: Make sure descriptors of started java process are preserved.

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