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

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

icedtea-web: Export OS/2 plugin entry points.

File size: 77.5 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 | MB_MOVEABLE);
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
2002static NPError
2003plugin_get_entry_points (NPPluginFuncs* pluginTable)
2004{
2005 // Ensure that the plugin function table we've received is large
2006 // enough to store the number of functions that we may provide.
2007 if (pluginTable->size < sizeof (NPPluginFuncs))
2008 {
2009 PLUGIN_ERROR ("Invalid plugin function table.");
2010
2011 return NPERR_INVALID_FUNCTABLE_ERROR;
2012 }
2013
2014 // Return to the browser the plugin functions that we implement.
2015 pluginTable->version = (NP_VERSION_MAJOR << 8) + NP_VERSION_MINOR;
2016 pluginTable->size = sizeof (NPPluginFuncs);
2017
2018#if MOZILLA_VERSION_COLLAPSED < 1090100
2019 pluginTable->newp = NewNPP_NewProc (ITNP_New);
2020 pluginTable->destroy = NewNPP_DestroyProc (ITNP_Destroy);
2021 pluginTable->setwindow = NewNPP_SetWindowProc (ITNP_SetWindow);
2022 pluginTable->newstream = NewNPP_NewStreamProc (ITNP_NewStream);
2023 pluginTable->destroystream = NewNPP_DestroyStreamProc (ITNP_DestroyStream);
2024 pluginTable->asfile = NewNPP_StreamAsFileProc (ITNP_StreamAsFile);
2025 pluginTable->writeready = NewNPP_WriteReadyProc (ITNP_WriteReady);
2026 pluginTable->write = NewNPP_WriteProc (ITNP_Write);
2027 pluginTable->print = NewNPP_PrintProc (ITNP_Print);
2028 pluginTable->urlnotify = NewNPP_URLNotifyProc (ITNP_URLNotify);
2029 pluginTable->getvalue = NewNPP_GetValueProc (ITNP_GetValue);
2030#else
2031 pluginTable->newp = NPP_NewProcPtr (ITNP_New);
2032 pluginTable->destroy = NPP_DestroyProcPtr (ITNP_Destroy);
2033 pluginTable->setwindow = NPP_SetWindowProcPtr (ITNP_SetWindow);
2034 pluginTable->newstream = NPP_NewStreamProcPtr (ITNP_NewStream);
2035 pluginTable->destroystream = NPP_DestroyStreamProcPtr (ITNP_DestroyStream);
2036 pluginTable->asfile = NPP_StreamAsFileProcPtr (ITNP_StreamAsFile);
2037 pluginTable->writeready = NPP_WriteReadyProcPtr (ITNP_WriteReady);
2038 pluginTable->write = NPP_WriteProcPtr (ITNP_Write);
2039 pluginTable->print = NPP_PrintProcPtr (ITNP_Print);
2040 pluginTable->urlnotify = NPP_URLNotifyProcPtr (ITNP_URLNotify);
2041 pluginTable->getvalue = NPP_GetValueProcPtr (ITNP_GetValue);
2042#endif
2043
2044 return NPERR_NO_ERROR;
2045}
2046
2047// FACTORY FUNCTIONS
2048
2049// Provides the browser with pointers to the plugin functions that we
2050// implement and initializes a local table with browser functions that
2051// we may wish to call. Called once, after browser startup and before
2052// the first plugin instance is created.
2053// The field 'initialized' is set to true once this function has
2054// finished. If 'initialized' is already true at the beginning of
2055// this function, then it is evident that NP_Initialize has already
2056// been called. There is no need to call this function more than once and
2057// this workaround avoids any duplicate calls.
2058NPError
2059#if defined(_WIN32) || defined (__OS2__)
2060OSCALL NP_Initialize (NPNetscapeFuncs* browserTable)
2061#else
2062OSCALL NP_Initialize (NPNetscapeFuncs* browserTable, NPPluginFuncs* pluginTable)
2063#endif
2064{
2065 PLUGIN_DEBUG ("NP_Initialize\n");
2066
2067#if defined(_WIN32) || defined (__OS2__)
2068 if (browserTable == NULL)
2069 {
2070 PLUGIN_ERROR ("Browser function table is NULL.");
2071
2072 return NPERR_INVALID_FUNCTABLE_ERROR;
2073 }
2074#else
2075 if ((browserTable == NULL) || (pluginTable == NULL))
2076 {
2077 PLUGIN_ERROR ("Browser or plugin function table is NULL.");
2078
2079 return NPERR_INVALID_FUNCTABLE_ERROR;
2080 }
2081#endif
2082
2083 // Ensure that the major version of the plugin API that the browser
2084 // expects is not more recent than the major version of the API that
2085 // we've implemented.
2086 if ((browserTable->version >> 8) > NP_VERSION_MAJOR)
2087 {
2088 PLUGIN_ERROR ("Incompatible version.");
2089
2090 return NPERR_INCOMPATIBLE_VERSION_ERROR;
2091 }
2092
2093 // Ensure that the browser function table is large enough to store
2094 // the number of browser functions that we may use.
2095 if (browserTable->size < sizeof (NPNetscapeFuncs))
2096 {
2097 fprintf (stderr, "ERROR: Invalid browser function table. Some functionality may be restricted.\n");
2098 }
2099
2100 // Store in a local table the browser functions that we may use.
2101 browser_functions.size = browserTable->size;
2102 browser_functions.version = browserTable->version;
2103 browser_functions.geturlnotify = browserTable->geturlnotify;
2104 browser_functions.geturl = browserTable->geturl;
2105 browser_functions.posturlnotify = browserTable->posturlnotify;
2106 browser_functions.posturl = browserTable->posturl;
2107 browser_functions.requestread = browserTable->requestread;
2108 browser_functions.newstream = browserTable->newstream;
2109 browser_functions.write = browserTable->write;
2110 browser_functions.destroystream = browserTable->destroystream;
2111 browser_functions.status = browserTable->status;
2112 browser_functions.uagent = browserTable->uagent;
2113 browser_functions.memalloc = browserTable->memalloc;
2114 browser_functions.memfree = browserTable->memfree;
2115 browser_functions.memflush = browserTable->memflush;
2116 browser_functions.reloadplugins = browserTable->reloadplugins;
2117 browser_functions.getJavaEnv = browserTable->getJavaEnv;
2118 browser_functions.getJavaPeer = browserTable->getJavaPeer;
2119 browser_functions.getvalue = browserTable->getvalue;
2120 browser_functions.setvalue = browserTable->setvalue;
2121 browser_functions.invalidaterect = browserTable->invalidaterect;
2122 browser_functions.invalidateregion = browserTable->invalidateregion;
2123 browser_functions.forceredraw = browserTable->forceredraw;
2124 browser_functions.getstringidentifier = browserTable->getstringidentifier;
2125 browser_functions.getstringidentifiers = browserTable->getstringidentifiers;
2126 browser_functions.getintidentifier = browserTable->getintidentifier;
2127 browser_functions.identifierisstring = browserTable->identifierisstring;
2128 browser_functions.utf8fromidentifier = browserTable->utf8fromidentifier;
2129 browser_functions.intfromidentifier = browserTable->intfromidentifier;
2130 browser_functions.createobject = browserTable->createobject;
2131 browser_functions.retainobject = browserTable->retainobject;
2132 browser_functions.releaseobject = browserTable->releaseobject;
2133 browser_functions.invoke = browserTable->invoke;
2134 browser_functions.invokeDefault = browserTable->invokeDefault;
2135 browser_functions.evaluate = browserTable->evaluate;
2136 browser_functions.getproperty = browserTable->getproperty;
2137 browser_functions.setproperty = browserTable->setproperty;
2138 browser_functions.removeproperty = browserTable->removeproperty;
2139 browser_functions.hasproperty = browserTable->hasproperty;
2140 browser_functions.hasmethod = browserTable->hasmethod;
2141 browser_functions.releasevariantvalue = browserTable->releasevariantvalue;
2142 browser_functions.setexception = browserTable->setexception;
2143 browser_functions.pluginthreadasynccall = browserTable->pluginthreadasynccall;
2144#if MOZILLA_VERSION_COLLAPSED >= 1090100
2145 browser_functions.getvalueforurl = browserTable->getvalueforurl;
2146 browser_functions.setvalueforurl = browserTable->setvalueforurl;
2147#endif
2148
2149 NPError np_error = NPERR_NO_ERROR;
2150#if !defined(_WIN32) && !defined (__OS2__)
2151 np_error = plugin_get_entry_points (pluginTable);
2152 if (np_error != NPERR_NO_ERROR)
2153 return np_error;
2154#endif
2155
2156 // Re-setting the above tables multiple times is OK (as the
2157 // browser may change its function locations). However
2158 // anything beyond this point should only run once.
2159 if (initialized)
2160 return NPERR_NO_ERROR;
2161
2162 // Make sure the plugin data directory exists, creating it if
2163 // necessary.
2164 data_directory = g_strconcat (P_tmpdir, NULL);
2165 if (!data_directory)
2166 {
2167 PLUGIN_ERROR ("Failed to create data directory name.");
2168 return NPERR_OUT_OF_MEMORY_ERROR;
2169 }
2170 gchar* filename = NULL;
2171
2172 // If P_tmpdir does not exist, try /tmp directly
2173
2174 if (!g_file_test (data_directory,
2175 (GFileTest) (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)))
2176 {
2177 int file_error = 0;
2178
2179 data_directory = g_strconcat ("/tmp", NULL);
2180 if (!data_directory)
2181 {
2182 PLUGIN_ERROR ("Failed to create data directory name.");
2183 return NPERR_OUT_OF_MEMORY_ERROR;
2184 }
2185
2186 }
2187
2188 data_directory = g_strconcat (data_directory, "/icedteaplugin-", getenv("USER"), NULL);
2189
2190 if (!data_directory)
2191 {
2192 PLUGIN_ERROR ("Failed to create data directory name.");
2193 return NPERR_OUT_OF_MEMORY_ERROR;
2194 }
2195
2196 // Now create a icedteaplugin subdir
2197 if (!g_file_test (data_directory,
2198 (GFileTest) (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)))
2199 {
2200 int file_error = 0;
2201
2202 file_error = g_mkdir (data_directory, 0700);
2203 if (file_error != 0)
2204 {
2205 PLUGIN_ERROR_THREE ("Failed to create data directory",
2206 data_directory,
2207 strerror (errno));
2208 np_error = NPERR_GENERIC_ERROR;
2209 goto cleanup_data_directory;
2210 }
2211 }
2212
2213
2214 // If data directory doesn't exit by this point, bail
2215 if (!g_file_test (data_directory,
2216 (GFileTest) (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)))
2217 {
2218 PLUGIN_ERROR_THREE ("Temp directory does not exist: ",
2219 data_directory,
2220 strerror (errno));
2221
2222 np_error = NPERR_GENERIC_ERROR;
2223 goto cleanup_data_directory;
2224
2225 }
2226
2227 // Set appletviewer_executable.
2228 filename = g_strdup(ICEDTEA_WEB_JRE);
2229 appletviewer_executable = g_strdup_printf ("%s/bin/java",
2230 filename);
2231 PLUGIN_DEBUG("Executing java at %s\n", appletviewer_executable);
2232 if (!appletviewer_executable)
2233 {
2234 PLUGIN_ERROR ("Failed to create appletviewer executable name.");
2235 np_error = NPERR_OUT_OF_MEMORY_ERROR;
2236 goto cleanup_filename;
2237 }
2238
2239 np_error = plugin_test_appletviewer ();
2240 if (np_error != NPERR_NO_ERROR)
2241 {
2242 plugin_display_failure_dialog ();
2243 goto cleanup_appletviewer_executable;
2244 }
2245 g_free (filename);
2246
2247 initialized = true;
2248
2249 // Initialize threads (needed for mutexes).
2250 if (!g_thread_supported ())
2251 g_thread_init (NULL);
2252
2253 plugin_instance_mutex = g_mutex_new ();
2254
2255 PLUGIN_DEBUG ("NP_Initialize: using %s\n", appletviewer_executable);
2256
2257 plugin_req_proc = new PluginRequestProcessor();
2258 java_req_proc = new JavaMessageSender();
2259
2260 java_to_plugin_bus = new MessageBus();
2261 plugin_to_java_bus = new MessageBus();
2262
2263 java_to_plugin_bus->subscribe(plugin_req_proc);
2264 plugin_to_java_bus->subscribe(java_req_proc);
2265
2266 pthread_create (&plugin_request_processor_thread1, NULL, &queue_processor, (void*) plugin_req_proc);
2267 pthread_create (&plugin_request_processor_thread2, NULL, &queue_processor, (void*) plugin_req_proc);
2268 pthread_create (&plugin_request_processor_thread3, NULL, &queue_processor, (void*) plugin_req_proc);
2269
2270 itnp_plugin_thread_id = pthread_self();
2271
2272 pthread_mutexattr_t attribute;
2273 pthread_mutexattr_init(&attribute);
2274 pthread_mutexattr_settype(&attribute, PTHREAD_MUTEX_RECURSIVE);
2275 pthread_mutex_init(&pluginAsyncCallMutex, &attribute);
2276 pthread_mutexattr_destroy(&attribute);
2277
2278 PLUGIN_DEBUG ("NP_Initialize return\n");
2279
2280 return NPERR_NO_ERROR;
2281
2282 cleanup_appletviewer_executable:
2283 if (appletviewer_executable)
2284 {
2285 g_free (appletviewer_executable);
2286 appletviewer_executable = NULL;
2287 }
2288
2289 cleanup_filename:
2290 if (filename)
2291 {
2292 g_free (filename);
2293 filename = NULL;
2294 }
2295
2296 cleanup_data_directory:
2297 if (data_directory)
2298 {
2299 g_free (data_directory);
2300 data_directory = NULL;
2301 }
2302
2303
2304 return np_error;
2305}
2306
2307#if defined(_WIN32) || defined (__OS2__)
2308NPError
2309OSCALL NP_GetEntryPoints (NPPluginFuncs* pluginTable)
2310{
2311 PLUGIN_DEBUG ("NP_GetEntryPoints\n");
2312
2313 if (pluginTable == NULL)
2314 {
2315 PLUGIN_ERROR ("Plugin function table is NULL.");
2316
2317 return NPERR_INVALID_FUNCTABLE_ERROR;
2318 }
2319
2320 return plugin_get_entry_points (pluginTable);
2321}
2322#endif
2323
2324// Returns a string describing the MIME type that this plugin
2325// handles.
2326const char*
2327OSCALL NP_GetMIMEDescription ()
2328{
2329 PLUGIN_DEBUG ("NP_GetMIMEDescription\n");
2330
2331 PLUGIN_DEBUG ("NP_GetMIMEDescription return\n");
2332
2333 return PLUGIN_MIME_DESC;
2334}
2335
2336// Returns a value relevant to the plugin as a whole. The browser
2337// calls this function to obtain information about the plugin.
2338NPError
2339OSCALL NP_GetValue (void* future, NPPVariable variable, void* value)
2340{
2341 PLUGIN_DEBUG ("NP_GetValue\n");
2342
2343 NPError result = NPERR_NO_ERROR;
2344 gchar** char_value = (gchar**) value;
2345
2346 switch (variable)
2347 {
2348 case NPPVpluginNameString:
2349 PLUGIN_DEBUG ("NP_GetValue: returning plugin name.\n");
2350 *char_value = g_strdup (PLUGIN_FULL_NAME);
2351 break;
2352
2353 case NPPVpluginDescriptionString:
2354 PLUGIN_DEBUG ("NP_GetValue: returning plugin description.\n");
2355 *char_value = g_strdup (PLUGIN_DESC);
2356 break;
2357
2358 default:
2359 PLUGIN_ERROR ("Unknown plugin value requested.");
2360 result = NPERR_GENERIC_ERROR;
2361 break;
2362 }
2363
2364 PLUGIN_DEBUG ("NP_GetValue return\n");
2365
2366 return result;
2367}
2368
2369// Shuts down the plugin. Called after the last plugin instance is
2370// destroyed.
2371NPError
2372OSCALL NP_Shutdown (void)
2373{
2374 PLUGIN_DEBUG ("NP_Shutdown\n");
2375
2376 // Free mutex.
2377 if (plugin_instance_mutex)
2378 {
2379 g_mutex_free (plugin_instance_mutex);
2380 plugin_instance_mutex = NULL;
2381 }
2382
2383 if (data_directory)
2384 {
2385 g_free (data_directory);
2386 data_directory = NULL;
2387 }
2388
2389 if (appletviewer_executable)
2390 {
2391 g_free (appletviewer_executable);
2392 appletviewer_executable = NULL;
2393 }
2394
2395 // stop the appletviewer
2396 plugin_stop_appletviewer();
2397
2398 // remove monitor
2399 if (appletviewer_watch_id != -1)
2400 g_source_remove(appletviewer_watch_id);
2401
2402 // Removing a source is harmless if it fails since it just means the
2403 // source has already been removed.
2404 g_source_remove (in_watch_source);
2405 in_watch_source = 0;
2406
2407 // cleanup_in_from_appletviewer:
2408 if (in_from_appletviewer)
2409 g_io_channel_unref (in_from_appletviewer);
2410 in_from_appletviewer = NULL;
2411
2412 // cleanup_out_watch_source:
2413 g_source_remove (out_watch_source);
2414 out_watch_source = 0;
2415
2416 // cleanup_out_to_appletviewer:
2417 if (out_to_appletviewer)
2418 g_io_channel_unref (out_to_appletviewer);
2419 out_to_appletviewer = NULL;
2420
2421 // cleanup_out_pipe:
2422 // Delete output pipe.
2423 PLUGIN_DEBUG ("NP_Shutdown: deleting output fifo: %s\n", out_pipe_name);
2424 unlink (out_pipe_name);
2425 PLUGIN_DEBUG ("NP_Shutdown: deleted output fifo: %s\n", out_pipe_name);
2426
2427 // cleanup_out_pipe_name:
2428 g_free (out_pipe_name);
2429 out_pipe_name = NULL;
2430
2431 // cleanup_in_pipe:
2432 // Delete input pipe.
2433 PLUGIN_DEBUG ("NP_Shutdown: deleting input fifo: %s\n", in_pipe_name);
2434 unlink (in_pipe_name);
2435 PLUGIN_DEBUG ("NP_Shutdown: deleted input fifo: %s\n", in_pipe_name);
2436
2437 // cleanup_in_pipe_name:
2438 g_free (in_pipe_name);
2439 in_pipe_name = NULL;
2440
2441 // Destroy the call queue mutex
2442 pthread_mutex_destroy(&pluginAsyncCallMutex);
2443
2444 initialized = false;
2445
2446 pthread_cancel(plugin_request_processor_thread1);
2447 pthread_cancel(plugin_request_processor_thread2);
2448 pthread_cancel(plugin_request_processor_thread3);
2449
2450 pthread_join(plugin_request_processor_thread1, NULL);
2451 pthread_join(plugin_request_processor_thread2, NULL);
2452 pthread_join(plugin_request_processor_thread3, NULL);
2453
2454 java_to_plugin_bus->unSubscribe(plugin_req_proc);
2455 plugin_to_java_bus->unSubscribe(java_req_proc);
2456 //internal_bus->unSubscribe(java_req_proc);
2457 //internal_bus->unSubscribe(plugin_req_proc);
2458
2459 delete plugin_req_proc;
2460 delete java_req_proc;
2461 delete java_to_plugin_bus;
2462 delete plugin_to_java_bus;
2463 //delete internal_bus;
2464
2465 PLUGIN_DEBUG ("NP_Shutdown return\n");
2466
2467 return NPERR_NO_ERROR;
2468}
2469
2470NPObject*
2471get_scriptable_object(NPP instance)
2472{
2473 NPObject* obj;
2474 ITNPPluginData* data = (ITNPPluginData*) instance->pdata;
2475
2476 if (data->is_applet_instance) // dummy instance/package?
2477 {
2478 JavaRequestProcessor java_request = JavaRequestProcessor();
2479 JavaResultData* java_result;
2480 std::string instance_id = std::string();
2481 std::string applet_class_id = std::string();
2482
2483 int id = get_id_from_instance(instance);
2484 gchar* id_str = g_strdup_printf ("%d", id);
2485
2486 // Some browsers.. (e.g. chromium) don't call NPP_SetWindow
2487 // for 0x0 plugins and therefore require initialization with
2488 // a 0 handle
2489 if (!data->window_handle)
2490 {
2491 plugin_send_initialization_message(data->instance_id, 0, 0, 0, data->applet_tag);
2492 }
2493
2494 java_result = java_request.getAppletObjectInstance(id_str);
2495
2496 g_free(id_str);
2497
2498 if (java_result->error_occurred)
2499 {
2500 printf("Error: Unable to fetch applet instance id from Java side.\n");
2501 return NULL;
2502 }
2503
2504 instance_id.append(*(java_result->return_string));
2505
2506 java_result = java_request.getClassID(instance_id);
2507
2508 if (java_result->error_occurred)
2509 {
2510 printf("Error: Unable to fetch applet instance id from Java side.\n");
2511 return NULL;
2512 }
2513
2514 applet_class_id.append(*(java_result->return_string));
2515
2516 obj = IcedTeaScriptableJavaPackageObject::get_scriptable_java_object(instance, applet_class_id, instance_id, false);
2517
2518 } else
2519 {
2520 obj = IcedTeaScriptablePluginObject::get_scriptable_java_package_object(instance, "");
2521 }
2522
2523 return obj;
2524}
2525
2526NPObject*
2527allocate_scriptable_object(NPP npp, NPClass *aClass)
2528{
2529 PLUGIN_DEBUG("Allocating new scriptable object\n");
2530 return new IcedTeaScriptablePluginObject(npp);
2531}
Note: See TracBrowser for help on using the repository browser.