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

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

vendor: Add icedtea-web v1.1.2 to current.

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