~ubuntu-branches/ubuntu/natty/icedtea-web/natty-updates

« back to all changes in this revision

Viewing changes to .pc/icedtea-web-CVE-2012-3422.patch/plugin/icedteanp/IcedTeaNPPlugin.cc

  • Committer: Package Import Robot
  • Author(s): Steve Beattie
  • Date: 2012-07-28 19:30:09 UTC
  • mfrom: (19.1.4 natty-security)
  • Revision ID: package-import@ubuntu.com-20120728193009-zcmbosnyj2paykr9
Tags: 1.2-2ubuntu0.11.04.2
* SECURITY UPDATE: uninitialized pointer use flaw
  - debian/patches/icedtea-web-CVE-2012-3422.patch: check for empty
    instance_to_id_map hash and return error if so.
  - CVE-2012-3422
* SECURITY UPDATE: incorrect handling of non NULL terminated strings
  - debian/patches/icedtea-web-CVE-2012-3423.patch: ensure NPVariant
    NPStrings are NULL terminated.
  - CVE-2012-3423

Show diffs side-by-side

added added

removed removed

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