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

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

icedtea-web: DT_SOCKET DLL is JDTSOCK.DLL on OS/2.

File size: 81.1 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 if (!g_spawn_async (NULL, command_line, environment,
1666 (GSpawnFlags) G_SPAWN_DO_NOT_REAP_CHILD,
1667 NULL, NULL, &appletviewer_pid, &channel_error))
1668 {
1669 if (channel_error)
1670 {
1671 PLUGIN_ERROR_TWO ("Failed to spawn applet viewer",
1672 channel_error->message);
1673 g_error_free (channel_error);
1674 channel_error = NULL;
1675 }
1676 else
1677 PLUGIN_ERROR ("Failed to spawn applet viewer");
1678 error = NPERR_GENERIC_ERROR;
1679 }
1680
1681 // make sure we get an error rather than crash the browser when talking to the
1682 // jvm process if it dies unexpectedly (we do it here since g_spawn() is known
1683 // to reset SIGPIPE handler to SIG_DFL)
1684 signal (SIGPIPE, SIG_IGN);
1685
1686 g_strfreev (environment);
1687
1688 for (int i = 0; i < cmd_num; i++) {
1689 g_free (command_line[i]);
1690 command_line[i] = NULL;
1691 }
1692
1693 g_free(command_line);
1694 command_line = NULL;
1695
1696 if (appletviewer_pid)
1697 {
1698 PLUGIN_DEBUG("Initialized VM with pid=%d\n", appletviewer_pid);
1699 appletviewer_watch_id = g_child_watch_add(appletviewer_pid, (GChildWatchFunc) appletviewer_monitor, (gpointer) appletviewer_pid);
1700 }
1701
1702
1703 PLUGIN_DEBUG ("plugin_start_appletviewer return\n");
1704 return error;
1705}
1706
1707/*
1708 * Replaces certain characters (\r, \n, etc) with HTML escape equivalents.
1709 *
1710 * Return string is allocated on the heap. Caller assumes responsibility
1711 * for freeing the memory via free()
1712 */
1713static char*
1714encode_string(char* to_encode)
1715{
1716
1717 // Do nothing for an empty string
1718 if (to_encode == '\0')
1719 return to_encode;
1720
1721 // worst case scenario -> all characters are newlines or
1722 // returns, each of which translates to 5 substitutions
1723 char* encoded = (char*) calloc(((strlen(to_encode)*5)+1), sizeof(char));
1724
1725 strcpy(encoded, "");
1726
1727 for (int i=0; i < strlen(to_encode); i++)
1728 {
1729 if (to_encode[i] == '\r')
1730 encoded = strcat(encoded, "&#13;");
1731 else if (to_encode[i] == '\n')
1732 encoded = strcat(encoded, "&#10;");
1733 else if (to_encode[i] == '>')
1734 encoded = strcat(encoded, "&gt;");
1735 else if (to_encode[i] == '<')
1736 encoded = strcat(encoded, "&lt;");
1737 else if (to_encode[i] == '&')
1738 encoded = strcat(encoded, "&amp;");
1739 else if (to_encode[i] == '"')
1740 encoded = strcat(encoded, "&quot;");
1741 else
1742 {
1743 char* orig_char = (char*) calloc(2, sizeof(char));
1744 orig_char[0] = to_encode[i];
1745 orig_char[1] = '\0';
1746
1747 strcat(encoded, orig_char);
1748
1749 free(orig_char);
1750 orig_char = NULL;
1751 }
1752 }
1753
1754 return encoded;
1755}
1756
1757// Build up the applet tag string that we'll send to the applet
1758// viewer.
1759static gchar*
1760plugin_create_applet_tag (int16_t argc, char* argn[], char* argv[])
1761{
1762 PLUGIN_DEBUG ("plugin_create_applet_tag\n");
1763
1764 gchar* applet_tag = g_strdup ("<EMBED ");
1765 gchar* parameters = g_strdup ("");
1766
1767 for (int16_t i = 0; i < argc; i++)
1768 {
1769 gchar* argn_escaped = encode_string(argn[i]);
1770 gchar* argv_escaped = encode_string(argv[i]);
1771
1772 if (!g_ascii_strcasecmp (argn_escaped, "code"))
1773 {
1774 gchar* code = g_strdup_printf ("CODE=\"%s\" ", argv_escaped);
1775 applet_tag = g_strconcat (applet_tag, code, NULL);
1776 g_free (code);
1777 code = NULL;
1778 }
1779 else if (!g_ascii_strcasecmp (argn_escaped, "java_code"))
1780 {
1781 gchar* java_code = g_strdup_printf ("JAVA_CODE=\"%s\" ", argv_escaped);
1782 applet_tag = g_strconcat (applet_tag, java_code, NULL);
1783 g_free (java_code);
1784 java_code = NULL;
1785 }
1786 else if (!g_ascii_strcasecmp (argn_escaped, "codebase"))
1787 {
1788 gchar* codebase = g_strdup_printf ("CODEBASE=\"%s\" ", argv_escaped);
1789 applet_tag = g_strconcat (applet_tag, codebase, NULL);
1790 g_free (codebase);
1791 codebase = NULL;
1792 }
1793 else if (!g_ascii_strcasecmp (argn_escaped, "java_codebase"))
1794 {
1795 gchar* java_codebase = g_strdup_printf ("JAVA_CODEBASE=\"%s\" ", argv_escaped);
1796 applet_tag = g_strconcat (applet_tag, java_codebase, NULL);
1797 g_free (java_codebase);
1798 java_codebase = NULL;
1799 }
1800 else if (!g_ascii_strcasecmp (argn_escaped, "classid"))
1801 {
1802 gchar* classid = g_strdup_printf ("CLASSID=\"%s\" ", argv_escaped);
1803 applet_tag = g_strconcat (applet_tag, classid, NULL);
1804 g_free (classid);
1805 classid = NULL;
1806 }
1807 else if (!g_ascii_strcasecmp (argn_escaped, "archive"))
1808 {
1809 gchar* archive = g_strdup_printf ("ARCHIVE=\"%s\" ", argv_escaped);
1810 applet_tag = g_strconcat (applet_tag, archive, NULL);
1811 g_free (archive);
1812 archive = NULL;
1813 }
1814 else if (!g_ascii_strcasecmp (argn_escaped, "java_archive"))
1815 {
1816 gchar* java_archive = g_strdup_printf ("JAVA_ARCHIVE=\"%s\" ", argv_escaped);
1817 applet_tag = g_strconcat (applet_tag, java_archive, NULL);
1818 g_free (java_archive);
1819 java_archive = NULL;
1820 }
1821 else if (!g_ascii_strcasecmp (argn_escaped, "width"))
1822 {
1823 gchar* width = g_strdup_printf ("width=\"%s\" ", argv_escaped);
1824 applet_tag = g_strconcat (applet_tag, width, NULL);
1825 g_free (width);
1826 width = NULL;
1827 }
1828 else if (!g_ascii_strcasecmp (argn_escaped, "height"))
1829 {
1830 gchar* height = g_strdup_printf ("height=\"%s\" ", argv_escaped);
1831 applet_tag = g_strconcat (applet_tag, height, NULL);
1832 g_free (height);
1833 height = NULL;
1834 }
1835 else
1836 {
1837
1838 if (argv_escaped != '\0')
1839 {
1840 parameters = g_strconcat (parameters, "<PARAM NAME=\"", argn_escaped,
1841 "\" VALUE=\"", argv_escaped, "\">", NULL);
1842 }
1843 }
1844
1845 free(argn_escaped);
1846 free(argv_escaped);
1847
1848 argn_escaped = NULL;
1849 argv_escaped = NULL;
1850 }
1851
1852 applet_tag = g_strconcat (applet_tag, ">", parameters, "</EMBED>", NULL);
1853
1854 g_free (parameters);
1855 parameters = NULL;
1856
1857 PLUGIN_DEBUG ("plugin_create_applet_tag return\n");
1858
1859 return applet_tag;
1860}
1861
1862// plugin_send_message_to_appletviewer must be called while holding
1863// data->appletviewer_mutex.
1864void
1865plugin_send_message_to_appletviewer (gchar const* message)
1866{
1867 PLUGIN_DEBUG ("plugin_send_message_to_appletviewer\n");
1868
1869 if (jvm_up)
1870 {
1871 gchar* newline_message = NULL;
1872 gsize bytes_written = 0;
1873
1874 // Send message to appletviewer.
1875 newline_message = g_strdup_printf ("%s\n", message);
1876
1877 // g_io_channel_write_chars will return something other than
1878 // G_IO_STATUS_NORMAL if not all the data is written. In that
1879 // case we fail rather than retrying.
1880 if (g_io_channel_write_chars (out_to_appletviewer,
1881 newline_message, -1, &bytes_written,
1882 &channel_error)
1883 != G_IO_STATUS_NORMAL)
1884 {
1885 if (channel_error)
1886 {
1887 PLUGIN_ERROR_TWO ("Failed to write bytes to output channel",
1888 channel_error->message);
1889 g_error_free (channel_error);
1890 channel_error = NULL;
1891 }
1892 else
1893 PLUGIN_ERROR ("Failed to write bytes to output channel");
1894 }
1895
1896 if (g_io_channel_flush (out_to_appletviewer, &channel_error)
1897 != G_IO_STATUS_NORMAL)
1898 {
1899 if (channel_error)
1900 {
1901 PLUGIN_ERROR_TWO ("Failed to flush bytes to output channel",
1902 channel_error->message);
1903 g_error_free (channel_error);
1904 channel_error = NULL;
1905 }
1906 else
1907 PLUGIN_ERROR ("Failed to flush bytes to output channel");
1908 }
1909 g_free (newline_message);
1910 newline_message = NULL;
1911
1912 PLUGIN_DEBUG (" PIPE: plugin wrote: %s\n", message);
1913 }
1914
1915 PLUGIN_DEBUG ("plugin_send_message_to_appletviewer return\n");
1916}
1917
1918/*
1919 * Sends the initialization message (handle/size/url) to the plugin
1920 */
1921void
1922plugin_send_initialization_message(char* instance, gulong handle,
1923 int width, int height, char* url)
1924{
1925 PLUGIN_DEBUG ("plugin_send_initialization_message\n");
1926
1927 gchar *window_message = g_strdup_printf ("instance %s handle %ld width %d height %d %s",
1928 instance, handle, width, height, url);
1929 plugin_send_message_to_appletviewer (window_message);
1930 g_free (window_message);
1931 window_message = NULL;
1932
1933 PLUGIN_DEBUG ("plugin_send_initialization_message return\n");
1934}
1935
1936
1937// Stop the appletviewer process. When this is called the
1938// appletviewer can be in any of three states: running, crashed or
1939// hung. If the appletviewer is running then sending it "shutdown"
1940// will cause it to exit. This will cause
1941// plugin_out_pipe_callback/plugin_in_pipe_callback to be called and
1942// the input and output channels to be shut down. If the appletviewer
1943// has crashed then plugin_out_pipe_callback/plugin_in_pipe_callback
1944// would already have been called and data->appletviewer_alive cleared
1945// in which case this function simply returns. If the appletviewer is
1946// hung then this function will be successful and the input and output
1947// watches will be removed by plugin_data_destroy.
1948// plugin_stop_appletviewer must be called with
1949// data->appletviewer_mutex held.
1950static void
1951plugin_stop_appletviewer ()
1952{
1953 PLUGIN_DEBUG ("plugin_stop_appletviewer\n");
1954
1955 if (jvm_up)
1956 {
1957 // Shut down the appletviewer.
1958 gsize bytes_written = 0;
1959
1960 if (out_to_appletviewer)
1961 {
1962 if (g_io_channel_write_chars (out_to_appletviewer, "shutdown",
1963 -1, &bytes_written, &channel_error)
1964 != G_IO_STATUS_NORMAL)
1965 {
1966 if (channel_error)
1967 {
1968 PLUGIN_ERROR_TWO ("Failed to write shutdown message to"
1969 " appletviewer", channel_error->message);
1970 g_error_free (channel_error);
1971 channel_error = NULL;
1972 }
1973 else
1974 PLUGIN_ERROR ("Failed to write shutdown message to");
1975 }
1976
1977 if (g_io_channel_flush (out_to_appletviewer, &channel_error)
1978 != G_IO_STATUS_NORMAL)
1979 {
1980 if (channel_error)
1981 {
1982 PLUGIN_ERROR_TWO ("Failed to write shutdown message to"
1983 " appletviewer", channel_error->message);
1984 g_error_free (channel_error);
1985 channel_error = NULL;
1986 }
1987 else
1988 PLUGIN_ERROR ("Failed to write shutdown message to");
1989 }
1990
1991 if (g_io_channel_shutdown (out_to_appletviewer,
1992 TRUE, &channel_error)
1993 != G_IO_STATUS_NORMAL)
1994 {
1995 if (channel_error)
1996 {
1997 PLUGIN_ERROR_TWO ("Failed to shut down appletviewer"
1998 " output channel", channel_error->message);
1999 g_error_free (channel_error);
2000 channel_error = NULL;
2001 }
2002 else
2003 PLUGIN_ERROR ("Failed to shut down appletviewer");
2004 }
2005 }
2006
2007 if (in_from_appletviewer)
2008 {
2009 if (g_io_channel_shutdown (in_from_appletviewer,
2010 TRUE, &channel_error)
2011 != G_IO_STATUS_NORMAL)
2012 {
2013 if (channel_error)
2014 {
2015 PLUGIN_ERROR_TWO ("Failed to shut down appletviewer"
2016 " input channel", channel_error->message);
2017 g_error_free (channel_error);
2018 channel_error = NULL;
2019 }
2020 else
2021 PLUGIN_ERROR ("Failed to shut down appletviewer");
2022 }
2023 }
2024 }
2025
2026 jvm_up = FALSE;
2027 sleep(2); /* Needed to prevent crashes during debug (when JDWP port is not freed by the kernel right away) */
2028
2029 PLUGIN_DEBUG ("plugin_stop_appletviewer return\n");
2030}
2031
2032static void appletviewer_monitor(GPid pid, gint status, gpointer data)
2033{
2034 PLUGIN_DEBUG ("appletviewer_monitor\n");
2035 jvm_up = FALSE;
2036 pid = -1;
2037 PLUGIN_DEBUG ("appletviewer_monitor return\n");
2038}
2039
2040static void
2041plugin_data_destroy (NPP instance)
2042{
2043 PLUGIN_DEBUG ("plugin_data_destroy\n");
2044
2045 ITNPPluginData* tofree = (ITNPPluginData*) instance->pdata;
2046
2047 // Remove instance from map
2048 gpointer id_ptr = g_hash_table_lookup(instance_to_id_map, instance);
2049
2050 if (id_ptr)
2051 {
2052 gint id = GPOINTER_TO_INT(id_ptr);
2053 g_hash_table_remove(instance_to_id_map, instance);
2054 g_hash_table_remove(id_to_instance_map, id_ptr);
2055 }
2056
2057 tofree->window_handle = NULL;
2058 tofree->window_height = 0;
2059 tofree->window_width = 0;
2060
2061 // cleanup_appletviewer_mutex:
2062 g_free (tofree->appletviewer_mutex);
2063 tofree->appletviewer_mutex = NULL;
2064
2065 // cleanup_instance_string:
2066 g_free (tofree->instance_id);
2067 tofree->instance_id = NULL;
2068
2069 // cleanup applet tag
2070 g_free (tofree->applet_tag);
2071 tofree->applet_tag = NULL;
2072
2073 g_free(tofree->source);
2074 tofree->source = NULL;
2075
2076 // cleanup_data:
2077 // Eliminate back-pointer to plugin instance.
2078 tofree->owner = NULL;
2079 (*browser_functions.memfree) (tofree);
2080 tofree = NULL;
2081
2082 PLUGIN_DEBUG ("plugin_data_destroy return\n");
2083}
2084
2085static NPError
2086plugin_get_entry_points (NPPluginFuncs* pluginTable)
2087{
2088 // Ensure that the plugin function table we've received is large
2089 // enough to store the number of functions that we may provide.
2090 if (pluginTable->size < sizeof (NPPluginFuncs))
2091 {
2092 PLUGIN_ERROR ("Invalid plugin function table.");
2093
2094 return NPERR_INVALID_FUNCTABLE_ERROR;
2095 }
2096
2097 // Return to the browser the plugin functions that we implement.
2098 pluginTable->version = (NP_VERSION_MAJOR << 8) + NP_VERSION_MINOR;
2099 pluginTable->size = sizeof (NPPluginFuncs);
2100
2101#if MOZILLA_VERSION_COLLAPSED < 1090100
2102 pluginTable->newp = NewNPP_NewProc (ITNP_New);
2103 pluginTable->destroy = NewNPP_DestroyProc (ITNP_Destroy);
2104 pluginTable->setwindow = NewNPP_SetWindowProc (ITNP_SetWindow);
2105 pluginTable->newstream = NewNPP_NewStreamProc (ITNP_NewStream);
2106 pluginTable->destroystream = NewNPP_DestroyStreamProc (ITNP_DestroyStream);
2107 pluginTable->asfile = NewNPP_StreamAsFileProc (ITNP_StreamAsFile);
2108 pluginTable->writeready = NewNPP_WriteReadyProc (ITNP_WriteReady);
2109 pluginTable->write = NewNPP_WriteProc (ITNP_Write);
2110 pluginTable->print = NewNPP_PrintProc (ITNP_Print);
2111 pluginTable->urlnotify = NewNPP_URLNotifyProc (ITNP_URLNotify);
2112 pluginTable->getvalue = NewNPP_GetValueProc (ITNP_GetValue);
2113#else
2114 pluginTable->newp = NPP_NewProcPtr (ITNP_New);
2115 pluginTable->destroy = NPP_DestroyProcPtr (ITNP_Destroy);
2116 pluginTable->setwindow = NPP_SetWindowProcPtr (ITNP_SetWindow);
2117 pluginTable->newstream = NPP_NewStreamProcPtr (ITNP_NewStream);
2118 pluginTable->destroystream = NPP_DestroyStreamProcPtr (ITNP_DestroyStream);
2119 pluginTable->asfile = NPP_StreamAsFileProcPtr (ITNP_StreamAsFile);
2120 pluginTable->writeready = NPP_WriteReadyProcPtr (ITNP_WriteReady);
2121 pluginTable->write = NPP_WriteProcPtr (ITNP_Write);
2122 pluginTable->print = NPP_PrintProcPtr (ITNP_Print);
2123 pluginTable->urlnotify = NPP_URLNotifyProcPtr (ITNP_URLNotify);
2124 pluginTable->getvalue = NPP_GetValueProcPtr (ITNP_GetValue);
2125#endif
2126
2127 return NPERR_NO_ERROR;
2128}
2129
2130// FACTORY FUNCTIONS
2131
2132// Provides the browser with pointers to the plugin functions that we
2133// implement and initializes a local table with browser functions that
2134// we may wish to call. Called once, after browser startup and before
2135// the first plugin instance is created.
2136// The field 'initialized' is set to true once this function has
2137// finished. If 'initialized' is already true at the beginning of
2138// this function, then it is evident that NP_Initialize has already
2139// been called. There is no need to call this function more than once and
2140// this workaround avoids any duplicate calls.
2141NPError
2142#if defined(_WIN32) || defined (__OS2__)
2143OSCALL NP_Initialize (NPNetscapeFuncs* browserTable)
2144#else
2145OSCALL NP_Initialize (NPNetscapeFuncs* browserTable, NPPluginFuncs* pluginTable)
2146#endif
2147{
2148 PLUGIN_DEBUG ("NP_Initialize\n");
2149
2150#if defined(_WIN32) || defined (__OS2__)
2151 if (browserTable == NULL)
2152 {
2153 PLUGIN_ERROR ("Browser function table is NULL.");
2154
2155 return NPERR_INVALID_FUNCTABLE_ERROR;
2156 }
2157#else
2158 if ((browserTable == NULL) || (pluginTable == NULL))
2159 {
2160 PLUGIN_ERROR ("Browser or plugin function table is NULL.");
2161
2162 return NPERR_INVALID_FUNCTABLE_ERROR;
2163 }
2164#endif
2165
2166 // Ensure that the major version of the plugin API that the browser
2167 // expects is not more recent than the major version of the API that
2168 // we've implemented.
2169 if ((browserTable->version >> 8) > NP_VERSION_MAJOR)
2170 {
2171 PLUGIN_ERROR ("Incompatible version.");
2172
2173 return NPERR_INCOMPATIBLE_VERSION_ERROR;
2174 }
2175
2176 // Ensure that the browser function table is large enough to store
2177 // the number of browser functions that we may use.
2178 if (browserTable->size < sizeof (NPNetscapeFuncs))
2179 {
2180 fprintf (stderr, "ERROR: Invalid browser function table. Some functionality may be restricted.\n");
2181 }
2182
2183 // Store in a local table the browser functions that we may use.
2184 browser_functions.size = browserTable->size;
2185 browser_functions.version = browserTable->version;
2186 browser_functions.geturlnotify = browserTable->geturlnotify;
2187 browser_functions.geturl = browserTable->geturl;
2188 browser_functions.posturlnotify = browserTable->posturlnotify;
2189 browser_functions.posturl = browserTable->posturl;
2190 browser_functions.requestread = browserTable->requestread;
2191 browser_functions.newstream = browserTable->newstream;
2192 browser_functions.write = browserTable->write;
2193 browser_functions.destroystream = browserTable->destroystream;
2194 browser_functions.status = browserTable->status;
2195 browser_functions.uagent = browserTable->uagent;
2196 browser_functions.memalloc = browserTable->memalloc;
2197 browser_functions.memfree = browserTable->memfree;
2198 browser_functions.memflush = browserTable->memflush;
2199 browser_functions.reloadplugins = browserTable->reloadplugins;
2200 browser_functions.getJavaEnv = browserTable->getJavaEnv;
2201 browser_functions.getJavaPeer = browserTable->getJavaPeer;
2202 browser_functions.getvalue = browserTable->getvalue;
2203 browser_functions.setvalue = browserTable->setvalue;
2204 browser_functions.invalidaterect = browserTable->invalidaterect;
2205 browser_functions.invalidateregion = browserTable->invalidateregion;
2206 browser_functions.forceredraw = browserTable->forceredraw;
2207 browser_functions.getstringidentifier = browserTable->getstringidentifier;
2208 browser_functions.getstringidentifiers = browserTable->getstringidentifiers;
2209 browser_functions.getintidentifier = browserTable->getintidentifier;
2210 browser_functions.identifierisstring = browserTable->identifierisstring;
2211 browser_functions.utf8fromidentifier = browserTable->utf8fromidentifier;
2212 browser_functions.intfromidentifier = browserTable->intfromidentifier;
2213 browser_functions.createobject = browserTable->createobject;
2214 browser_functions.retainobject = browserTable->retainobject;
2215 browser_functions.releaseobject = browserTable->releaseobject;
2216 browser_functions.invoke = browserTable->invoke;
2217 browser_functions.invokeDefault = browserTable->invokeDefault;
2218 browser_functions.evaluate = browserTable->evaluate;
2219 browser_functions.getproperty = browserTable->getproperty;
2220 browser_functions.setproperty = browserTable->setproperty;
2221 browser_functions.removeproperty = browserTable->removeproperty;
2222 browser_functions.hasproperty = browserTable->hasproperty;
2223 browser_functions.hasmethod = browserTable->hasmethod;
2224 browser_functions.releasevariantvalue = browserTable->releasevariantvalue;
2225 browser_functions.setexception = browserTable->setexception;
2226 browser_functions.pluginthreadasynccall = browserTable->pluginthreadasynccall;
2227#if MOZILLA_VERSION_COLLAPSED >= 1090100
2228 browser_functions.getvalueforurl = browserTable->getvalueforurl;
2229 browser_functions.setvalueforurl = browserTable->setvalueforurl;
2230#endif
2231
2232 NPError np_error = NPERR_NO_ERROR;
2233#if !defined(_WIN32) && !defined (__OS2__)
2234 np_error = plugin_get_entry_points (pluginTable);
2235 if (np_error != NPERR_NO_ERROR)
2236 return np_error;
2237#endif
2238
2239 // Re-setting the above tables multiple times is OK (as the
2240 // browser may change its function locations). However
2241 // anything beyond this point should only run once.
2242 if (initialized)
2243 return NPERR_NO_ERROR;
2244
2245 // Make sure the plugin data directory exists, creating it if
2246 // necessary.
2247 data_directory = g_strconcat (P_tmpdir, NULL);
2248 if (!data_directory)
2249 {
2250 PLUGIN_ERROR ("Failed to create data directory name.");
2251 return NPERR_OUT_OF_MEMORY_ERROR;
2252 }
2253 gchar* filename = NULL;
2254
2255 // If P_tmpdir does not exist, try /tmp directly
2256
2257 if (!g_file_test (data_directory,
2258 (GFileTest) (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)))
2259 {
2260 int file_error = 0;
2261
2262 data_directory = g_strconcat ("/tmp", NULL);
2263 if (!data_directory)
2264 {
2265 PLUGIN_ERROR ("Failed to create data directory name.");
2266 return NPERR_OUT_OF_MEMORY_ERROR;
2267 }
2268
2269 }
2270
2271 data_directory = g_strconcat (data_directory, "/icedteaplugin-", getenv("USER"), NULL);
2272
2273 if (!data_directory)
2274 {
2275 PLUGIN_ERROR ("Failed to create data directory name.");
2276 return NPERR_OUT_OF_MEMORY_ERROR;
2277 }
2278
2279 // Now create a icedteaplugin subdir
2280 if (!g_file_test (data_directory,
2281 (GFileTest) (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)))
2282 {
2283 int file_error = 0;
2284
2285 file_error = g_mkdir (data_directory, 0700);
2286 if (file_error != 0)
2287 {
2288 PLUGIN_ERROR_THREE ("Failed to create data directory",
2289 data_directory,
2290 strerror (errno));
2291 np_error = NPERR_GENERIC_ERROR;
2292 goto cleanup_data_directory;
2293 }
2294 }
2295
2296
2297 // If data directory doesn't exit by this point, bail
2298 if (!g_file_test (data_directory,
2299 (GFileTest) (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)))
2300 {
2301 PLUGIN_ERROR_THREE ("Temp directory does not exist: ",
2302 data_directory,
2303 strerror (errno));
2304
2305 np_error = NPERR_GENERIC_ERROR;
2306 goto cleanup_data_directory;
2307
2308 }
2309
2310 // Set appletviewer_executable.
2311 filename = g_strdup(ICEDTEA_WEB_JRE);
2312 appletviewer_executable = g_strdup_printf ("%s/bin/java",
2313 filename);
2314 PLUGIN_DEBUG("Executing java at %s\n", appletviewer_executable);
2315 if (!appletviewer_executable)
2316 {
2317 PLUGIN_ERROR ("Failed to create appletviewer executable name.");
2318 np_error = NPERR_OUT_OF_MEMORY_ERROR;
2319 goto cleanup_filename;
2320 }
2321
2322 np_error = plugin_test_appletviewer ();
2323 if (np_error != NPERR_NO_ERROR)
2324 {
2325 plugin_display_failure_dialog ();
2326 goto cleanup_appletviewer_executable;
2327 }
2328 g_free (filename);
2329
2330 initialized = true;
2331
2332 // Initialize threads (needed for mutexes).
2333 if (!g_thread_supported ())
2334 g_thread_init (NULL);
2335
2336 plugin_instance_mutex = g_mutex_new ();
2337
2338 PLUGIN_DEBUG ("NP_Initialize: using %s\n", appletviewer_executable);
2339
2340 plugin_req_proc = new PluginRequestProcessor();
2341 java_req_proc = new JavaMessageSender();
2342
2343 java_to_plugin_bus = new MessageBus();
2344 plugin_to_java_bus = new MessageBus();
2345
2346 java_to_plugin_bus->subscribe(plugin_req_proc);
2347 plugin_to_java_bus->subscribe(java_req_proc);
2348
2349#ifdef __OS2__
2350 queue_processor_data1.processor = plugin_req_proc;
2351 queue_processor_data2.processor = plugin_req_proc;
2352 queue_processor_data3.processor = plugin_req_proc;
2353 pthread_create (&plugin_request_processor_thread1, NULL, &queue_processor, (void*) &queue_processor_data1);
2354 pthread_create (&plugin_request_processor_thread2, NULL, &queue_processor, (void*) &queue_processor_data2);
2355 pthread_create (&plugin_request_processor_thread3, NULL, &queue_processor, (void*) &queue_processor_data3);
2356#else
2357 pthread_create (&plugin_request_processor_thread1, NULL, &queue_processor, (void*) plugin_req_proc);
2358 pthread_create (&plugin_request_processor_thread2, NULL, &queue_processor, (void*) plugin_req_proc);
2359 pthread_create (&plugin_request_processor_thread3, NULL, &queue_processor, (void*) plugin_req_proc);
2360#endif
2361
2362 itnp_plugin_thread_id = pthread_self();
2363
2364 pthread_mutexattr_t attribute;
2365 pthread_mutexattr_init(&attribute);
2366 pthread_mutexattr_settype(&attribute, PTHREAD_MUTEX_RECURSIVE);
2367 pthread_mutex_init(&pluginAsyncCallMutex, &attribute);
2368 pthread_mutexattr_destroy(&attribute);
2369
2370 PLUGIN_DEBUG ("NP_Initialize return\n");
2371
2372 return NPERR_NO_ERROR;
2373
2374 cleanup_appletviewer_executable:
2375 if (appletviewer_executable)
2376 {
2377 g_free (appletviewer_executable);
2378 appletviewer_executable = NULL;
2379 }
2380
2381 cleanup_filename:
2382 if (filename)
2383 {
2384 g_free (filename);
2385 filename = NULL;
2386 }
2387
2388 cleanup_data_directory:
2389 if (data_directory)
2390 {
2391 g_free (data_directory);
2392 data_directory = NULL;
2393 }
2394
2395
2396 return np_error;
2397}
2398
2399#if defined(_WIN32) || defined (__OS2__)
2400NPError
2401OSCALL NP_GetEntryPoints (NPPluginFuncs* pluginTable)
2402{
2403 PLUGIN_DEBUG ("NP_GetEntryPoints\n");
2404
2405 if (pluginTable == NULL)
2406 {
2407 PLUGIN_ERROR ("Plugin function table is NULL.");
2408
2409 return NPERR_INVALID_FUNCTABLE_ERROR;
2410 }
2411
2412 return plugin_get_entry_points (pluginTable);
2413}
2414#endif
2415
2416// Returns a string describing the MIME type that this plugin
2417// handles.
2418const char*
2419OSCALL NP_GetMIMEDescription ()
2420{
2421 PLUGIN_DEBUG ("NP_GetMIMEDescription\n");
2422
2423 PLUGIN_DEBUG ("NP_GetMIMEDescription return\n");
2424
2425 return PLUGIN_MIME_DESC;
2426}
2427
2428// Returns a value relevant to the plugin as a whole. The browser
2429// calls this function to obtain information about the plugin.
2430NPError
2431OSCALL NP_GetValue (void* future, NPPVariable variable, void* value)
2432{
2433 PLUGIN_DEBUG ("NP_GetValue\n");
2434
2435 NPError result = NPERR_NO_ERROR;
2436 gchar** char_value = (gchar**) value;
2437
2438 switch (variable)
2439 {
2440 case NPPVpluginNameString:
2441 PLUGIN_DEBUG ("NP_GetValue: returning plugin name.\n");
2442 *char_value = g_strdup (PLUGIN_FULL_NAME);
2443 break;
2444
2445 case NPPVpluginDescriptionString:
2446 PLUGIN_DEBUG ("NP_GetValue: returning plugin description.\n");
2447 *char_value = g_strdup (PLUGIN_DESC);
2448 break;
2449
2450 default:
2451 PLUGIN_ERROR ("Unknown plugin value requested.");
2452 result = NPERR_GENERIC_ERROR;
2453 break;
2454 }
2455
2456 PLUGIN_DEBUG ("NP_GetValue return\n");
2457
2458 return result;
2459}
2460
2461// Shuts down the plugin. Called after the last plugin instance is
2462// destroyed.
2463NPError
2464OSCALL NP_Shutdown (void)
2465{
2466 PLUGIN_DEBUG ("NP_Shutdown\n");
2467
2468 // Free mutex.
2469 if (plugin_instance_mutex)
2470 {
2471 g_mutex_free (plugin_instance_mutex);
2472 plugin_instance_mutex = NULL;
2473 }
2474
2475 if (data_directory)
2476 {
2477 g_free (data_directory);
2478 data_directory = NULL;
2479 }
2480
2481 if (appletviewer_executable)
2482 {
2483 g_free (appletviewer_executable);
2484 appletviewer_executable = NULL;
2485 }
2486
2487 // stop the appletviewer
2488 plugin_stop_appletviewer();
2489
2490 // remove monitor
2491 if (appletviewer_watch_id != -1)
2492 g_source_remove(appletviewer_watch_id);
2493
2494 // Removing a source is harmless if it fails since it just means the
2495 // source has already been removed.
2496 g_source_remove (in_watch_source);
2497 in_watch_source = 0;
2498
2499 // cleanup_in_from_appletviewer:
2500 if (in_from_appletviewer)
2501 g_io_channel_unref (in_from_appletviewer);
2502 in_from_appletviewer = NULL;
2503
2504 // cleanup_out_watch_source:
2505 g_source_remove (out_watch_source);
2506 out_watch_source = 0;
2507
2508 // cleanup_out_to_appletviewer:
2509 if (out_to_appletviewer)
2510 g_io_channel_unref (out_to_appletviewer);
2511 out_to_appletviewer = NULL;
2512
2513 // cleanup_out_pipe:
2514#ifdef __OS2__
2515 CLOSE_FD (out_pipe [0]);
2516 CLOSE_FD (out_pipe [1]);
2517#else
2518 // Delete output pipe.
2519 PLUGIN_DEBUG ("NP_Shutdown: deleting output fifo: %s\n", out_pipe_name);
2520 unlink (out_pipe_name);
2521 PLUGIN_DEBUG ("NP_Shutdown: deleted output fifo: %s\n", out_pipe_name);
2522
2523 // cleanup_out_pipe_name:
2524 g_free (out_pipe_name);
2525 out_pipe_name = NULL;
2526#endif
2527
2528 // cleanup_in_pipe:
2529#ifdef __OS2__
2530 CLOSE_FD (in_pipe [0]);
2531 CLOSE_FD (in_pipe [1]);
2532#else
2533 // Delete input pipe.
2534 PLUGIN_DEBUG ("NP_Shutdown: deleting input fifo: %s\n", in_pipe_name);
2535 unlink (in_pipe_name);
2536 PLUGIN_DEBUG ("NP_Shutdown: deleted input fifo: %s\n", in_pipe_name);
2537
2538 // cleanup_in_pipe_name:
2539 g_free (in_pipe_name);
2540 in_pipe_name = NULL;
2541#endif
2542
2543 // Destroy the call queue mutex
2544 pthread_mutex_destroy(&pluginAsyncCallMutex);
2545
2546 initialized = false;
2547
2548#ifdef __OS2__
2549 // pthread_cancel() isn't implemented on OS?2, so use an old good flag
2550 queue_processor_data1.stopRequested = true;
2551 queue_processor_data2.stopRequested = true;
2552 queue_processor_data3.stopRequested = true;
2553 pthread_cond_broadcast(&cond_message_available);
2554#else
2555 pthread_cancel(plugin_request_processor_thread1);
2556 pthread_cancel(plugin_request_processor_thread2);
2557 pthread_cancel(plugin_request_processor_thread3);
2558#endif
2559
2560 pthread_join(plugin_request_processor_thread1, NULL);
2561 pthread_join(plugin_request_processor_thread2, NULL);
2562 pthread_join(plugin_request_processor_thread3, NULL);
2563
2564 java_to_plugin_bus->unSubscribe(plugin_req_proc);
2565 plugin_to_java_bus->unSubscribe(java_req_proc);
2566 //internal_bus->unSubscribe(java_req_proc);
2567 //internal_bus->unSubscribe(plugin_req_proc);
2568
2569 delete plugin_req_proc;
2570 delete java_req_proc;
2571 delete java_to_plugin_bus;
2572 delete plugin_to_java_bus;
2573 //delete internal_bus;
2574
2575 PLUGIN_DEBUG ("NP_Shutdown return\n");
2576
2577 return NPERR_NO_ERROR;
2578}
2579
2580NPObject*
2581get_scriptable_object(NPP instance)
2582{
2583 NPObject* obj;
2584 ITNPPluginData* data = (ITNPPluginData*) instance->pdata;
2585
2586 if (data->is_applet_instance) // dummy instance/package?
2587 {
2588 JavaRequestProcessor java_request = JavaRequestProcessor();
2589 JavaResultData* java_result;
2590 std::string instance_id = std::string();
2591 std::string applet_class_id = std::string();
2592
2593 int id = get_id_from_instance(instance);
2594 gchar* id_str = g_strdup_printf ("%d", id);
2595
2596 // Some browsers.. (e.g. chromium) don't call NPP_SetWindow
2597 // for 0x0 plugins and therefore require initialization with
2598 // a 0 handle
2599 if (!data->window_handle)
2600 {
2601 plugin_send_initialization_message(data->instance_id, 0, 0, 0, data->applet_tag);
2602 }
2603
2604 java_result = java_request.getAppletObjectInstance(id_str);
2605
2606 g_free(id_str);
2607
2608 if (java_result->error_occurred)
2609 {
2610 printf("Error: Unable to fetch applet instance id from Java side.\n");
2611 return NULL;
2612 }
2613
2614 instance_id.append(*(java_result->return_string));
2615
2616 java_result = java_request.getClassID(instance_id);
2617
2618 if (java_result->error_occurred)
2619 {
2620 printf("Error: Unable to fetch applet instance id from Java side.\n");
2621 return NULL;
2622 }
2623
2624 applet_class_id.append(*(java_result->return_string));
2625
2626 obj = IcedTeaScriptableJavaPackageObject::get_scriptable_java_object(instance, applet_class_id, instance_id, false);
2627
2628 } else
2629 {
2630 obj = IcedTeaScriptablePluginObject::get_scriptable_java_package_object(instance, "");
2631 }
2632
2633 return obj;
2634}
2635
2636NPObject*
2637allocate_scriptable_object(NPP npp, NPClass *aClass)
2638{
2639 PLUGIN_DEBUG("Allocating new scriptable object\n");
2640 return new IcedTeaScriptablePluginObject(npp);
2641}
2642
2643#ifdef __OS2__
2644
2645// Make sure static initializers in the plugin DLL are called
2646
2647static APIENTRY void cleanup(ULONG ulReason)
2648{
2649 __ctordtorTerm();
2650 _CRT_term();
2651 DosExitList(EXLST_EXIT, cleanup);
2652}
2653
2654unsigned long _System _DLL_InitTerm(unsigned long hModule,
2655 unsigned long ulFlag)
2656{
2657 APIRET arc;
2658
2659 if (ulFlag == 0)
2660 {
2661 arc = DosExitList (EXLST_ADD, cleanup);
2662 if (arc != NO_ERROR)
2663 return 0;
2664
2665 if (_CRT_init() != 0) // failure?
2666 return 0;
2667 __ctordtorInit();
2668 }
2669
2670 return 1;
2671}
2672
2673#endif /* __OS2__ */
Note: See TracBrowser for help on using the repository browser.