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

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

icedtea-web: Port plugin to OS/2.

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