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

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

Merge icedtea-web v1.3 to trunk.

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