aboutsummaryrefslogtreecommitdiffstats
path: root/plugin/icedteanp
diff options
context:
space:
mode:
Diffstat (limited to 'plugin/icedteanp')
-rw-r--r--plugin/icedteanp/IcedTeaJavaRequestProcessor.cc1392
-rw-r--r--plugin/icedteanp/IcedTeaJavaRequestProcessor.h233
-rw-r--r--plugin/icedteanp/IcedTeaNPPlugin.cc2453
-rw-r--r--plugin/icedteanp/IcedTeaNPPlugin.h136
-rw-r--r--plugin/icedteanp/IcedTeaPluginRequestProcessor.cc988
-rw-r--r--plugin/icedteanp/IcedTeaPluginRequestProcessor.h146
-rw-r--r--plugin/icedteanp/IcedTeaPluginUtils.cc1047
-rw-r--r--plugin/icedteanp/IcedTeaPluginUtils.h296
-rw-r--r--plugin/icedteanp/IcedTeaRunnable.cc75
-rw-r--r--plugin/icedteanp/IcedTeaRunnable.h104
-rw-r--r--plugin/icedteanp/IcedTeaScriptablePluginObject.cc897
-rw-r--r--plugin/icedteanp/IcedTeaScriptablePluginObject.h212
-rw-r--r--plugin/icedteanp/java/netscape/javascript/JSException.java140
-rw-r--r--plugin/icedteanp/java/netscape/javascript/JSObject.java297
-rw-r--r--plugin/icedteanp/java/netscape/javascript/JSObjectCreatePermission.java47
-rw-r--r--plugin/icedteanp/java/netscape/javascript/JSProxy.java58
-rw-r--r--plugin/icedteanp/java/netscape/javascript/JSRunnable.java72
-rw-r--r--plugin/icedteanp/java/netscape/javascript/JSUtil.java59
-rw-r--r--plugin/icedteanp/java/netscape/security/ForbiddenTargetException.java52
-rw-r--r--plugin/icedteanp/java/sun/applet/AppletSecurityContextManager.java71
-rw-r--r--plugin/icedteanp/java/sun/applet/GetMemberPluginCallRequest.java63
-rw-r--r--plugin/icedteanp/java/sun/applet/GetWindowPluginCallRequest.java65
-rw-r--r--plugin/icedteanp/java/sun/applet/JavaConsole.java365
-rw-r--r--plugin/icedteanp/java/sun/applet/MethodOverloadResolver.java696
-rw-r--r--plugin/icedteanp/java/sun/applet/PasswordAuthenticationDialog.java241
-rw-r--r--plugin/icedteanp/java/sun/applet/PluginAppletSecurityContext.java1505
-rw-r--r--plugin/icedteanp/java/sun/applet/PluginAppletViewer.java2056
-rw-r--r--plugin/icedteanp/java/sun/applet/PluginCallRequest.java89
-rw-r--r--plugin/icedteanp/java/sun/applet/PluginCallRequestFactory.java61
-rw-r--r--plugin/icedteanp/java/sun/applet/PluginClassLoader.java51
-rw-r--r--plugin/icedteanp/java/sun/applet/PluginCookieInfoRequest.java74
-rw-r--r--plugin/icedteanp/java/sun/applet/PluginCookieManager.java88
-rw-r--r--plugin/icedteanp/java/sun/applet/PluginDebug.java51
-rw-r--r--plugin/icedteanp/java/sun/applet/PluginException.java53
-rw-r--r--plugin/icedteanp/java/sun/applet/PluginMain.java319
-rw-r--r--plugin/icedteanp/java/sun/applet/PluginMessageConsumer.java268
-rw-r--r--plugin/icedteanp/java/sun/applet/PluginMessageHandlerWorker.java147
-rw-r--r--plugin/icedteanp/java/sun/applet/PluginObjectStore.java132
-rw-r--r--plugin/icedteanp/java/sun/applet/PluginProxyInfoRequest.java81
-rw-r--r--plugin/icedteanp/java/sun/applet/PluginProxySelector.java195
-rw-r--r--plugin/icedteanp/java/sun/applet/PluginStreamHandler.java454
-rw-r--r--plugin/icedteanp/java/sun/applet/RequestQueue.java77
-rw-r--r--plugin/icedteanp/java/sun/applet/TestEnv.java172
-rw-r--r--plugin/icedteanp/java/sun/applet/VoidPluginCallRequest.java54
44 files changed, 16132 insertions, 0 deletions
diff --git a/plugin/icedteanp/IcedTeaJavaRequestProcessor.cc b/plugin/icedteanp/IcedTeaJavaRequestProcessor.cc
new file mode 100644
index 0000000..8b5b8a3
--- /dev/null
+++ b/plugin/icedteanp/IcedTeaJavaRequestProcessor.cc
@@ -0,0 +1,1392 @@
+/* IcedTeaJavaRequestProcessor.cc
+
+ Copyright (C) 2009, 2010 Red Hat
+
+This file is part of IcedTea.
+
+IcedTea is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+IcedTea is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with IcedTea; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+#include <typeinfo>
+
+#include "IcedTeaJavaRequestProcessor.h"
+#include "IcedTeaScriptablePluginObject.h"
+
+/*
+ * This class processes LiveConnect requests from JavaScript to Java.
+ *
+ * It sends the requests to Java, gets the return information, and sends it
+ * back to the browser/JavaScript
+ */
+
+/**
+ * Processes return information from JavaSide (return messages of requests)
+ *
+ * @param message The message request to process
+ * @return boolean indicating whether the message is serviceable by this object
+ */
+
+bool
+JavaRequestProcessor::newMessageOnBus(const char* message)
+{
+
+ // Anything we are waiting for _MUST_ have and instance id and reference #
+ std::vector<std::string*>* message_parts = IcedTeaPluginUtilities::strSplit(message, " ");
+
+ IcedTeaPluginUtilities::printStringPtrVector("JavaRequest::newMessageOnBus:", message_parts);
+
+ if (*(message_parts->at(0)) == "context" && *(message_parts->at(2)) == "reference")
+ if (atoi(message_parts->at(1)->c_str()) == this->instance && atoi(message_parts->at(3)->c_str()) == this->reference)
+ {
+ // Gather the results
+
+ // Let's get errors out of the way first
+ if (!message_parts->at(4)->find("Error"))
+ {
+ for (int i=5; i < message_parts->size(); i++)
+ {
+ result->error_msg->append(*(message_parts->at(i)));
+ result->error_msg->append(" ");
+ }
+
+ printf("Error on Java side: %s\n", result->error_msg->c_str());
+
+ result->error_occurred = true;
+ result_ready = true;
+ }
+ else if (!message_parts->at(4)->find("GetStringUTFChars") ||
+ !message_parts->at(4)->find("GetToStringValue"))
+ {
+ // first item is length, and it is radix 10
+ int length = strtol(message_parts->at(5)->c_str(), NULL, 10);
+
+ IcedTeaPluginUtilities::getUTF8String(length, 6 /* start at */, message_parts, result->return_string);
+ result_ready = true;
+ }
+ else if (!message_parts->at(4)->find("GetStringChars")) // GetStringChars (UTF-16LE/UCS-2)
+ {
+ // first item is length, and it is radix 10
+ int length = strtol(message_parts->at(5)->c_str(), NULL, 10);
+
+ IcedTeaPluginUtilities::getUTF16LEString(length, 6 /* start at */, message_parts, result->return_wstring);
+ result_ready = true;
+ } else if (!message_parts->at(4)->find("FindClass") ||
+ !message_parts->at(4)->find("GetClassName") ||
+ !message_parts->at(4)->find("GetClassID") ||
+ !message_parts->at(4)->find("GetMethodID") ||
+ !message_parts->at(4)->find("GetStaticMethodID") ||
+ !message_parts->at(4)->find("GetObjectClass") ||
+ !message_parts->at(4)->find("NewObject") ||
+ !message_parts->at(4)->find("NewStringUTF") ||
+ !message_parts->at(4)->find("HasPackage") ||
+ !message_parts->at(4)->find("HasMethod") ||
+ !message_parts->at(4)->find("HasField") ||
+ !message_parts->at(4)->find("GetStaticFieldID") ||
+ !message_parts->at(4)->find("GetFieldID") ||
+ !message_parts->at(4)->find("GetJavaObject") ||
+ !message_parts->at(4)->find("IsInstanceOf") ||
+ !message_parts->at(4)->find("NewArray"))
+ {
+ result->return_identifier = atoi(message_parts->at(5)->c_str());
+ result->return_string->append(*(message_parts->at(5))); // store it as a string as well, for easy access
+ result_ready = true;
+ } else if (!message_parts->at(4)->find("DeleteLocalRef") ||
+ !message_parts->at(4)->find("NewGlobalRef"))
+ {
+ result_ready = true; // nothing else to do
+ } else if (!message_parts->at(4)->find("CallMethod") ||
+ !message_parts->at(4)->find("CallStaticMethod") ||
+ !message_parts->at(4)->find("GetField") ||
+ !message_parts->at(4)->find("GetStaticField") ||
+ !message_parts->at(4)->find("GetValue") ||
+ !message_parts->at(4)->find("GetObjectArrayElement"))
+ {
+
+ if (!message_parts->at(5)->find("literalreturn"))
+ {
+ // literal returns don't have a corresponding jni id
+ result->return_identifier = 0;
+ result->return_string->append(*(message_parts->at(5)));
+ result->return_string->append(" ");
+ result->return_string->append(*(message_parts->at(6)));
+
+ } else
+ {
+ // Else it is a complex object
+
+ result->return_identifier = atoi(message_parts->at(5)->c_str());
+ result->return_string->append(*(message_parts->at(5))); // store it as a string as well, for easy access
+ }
+
+ result_ready = true;
+ } else if (!message_parts->at(4)->find("GetArrayLength"))
+ {
+ result->return_identifier = 0; // length is not an "identifier"
+ result->return_string->append(*(message_parts->at(5)));
+ result_ready = true;
+ } else if (!message_parts->at(4)->find("SetField") ||
+ !message_parts->at(4)->find("SetObjectArrayElement"))
+ {
+
+ // nothing to do
+
+ result->return_identifier = 0;
+ result_ready = true;
+ }
+
+ IcedTeaPluginUtilities::freeStringPtrVector(message_parts);
+ return true;
+ }
+
+ IcedTeaPluginUtilities::freeStringPtrVector(message_parts);
+ return false;
+}
+
+/**
+ * Constructor.
+ *
+ * Initializes the result data structure (heap)
+ */
+
+JavaRequestProcessor::JavaRequestProcessor()
+{
+ PLUGIN_DEBUG("JavaRequestProcessor constructor\n");
+
+ // caller frees this
+ result = new JavaResultData();
+ result->error_msg = new std::string();
+ result->return_identifier = 0;
+ result->return_string = new std::string();
+ result->return_wstring = new std::wstring();
+ result->error_occurred = false;
+
+ result_ready = false;
+}
+
+/**
+ * Destructor
+ *
+ * Frees memory used by the result struct
+ */
+
+JavaRequestProcessor::~JavaRequestProcessor()
+{
+ PLUGIN_DEBUG("JavaRequestProcessor::~JavaRequestProcessor\n");
+
+ if (result)
+ {
+ if (result->error_msg)
+ delete result->error_msg;
+
+ if (result->return_string)
+ delete result->return_string;
+
+ if (result->return_wstring)
+ delete result->return_wstring;
+
+ delete result;
+ }
+}
+
+/**
+ * Resets the results
+ */
+void
+JavaRequestProcessor::resetResult()
+{
+ // caller frees this
+ result->error_msg->clear();
+ result->return_identifier = 0;
+ result->return_string->clear();
+ result->return_wstring->clear();
+ result->error_occurred = false;
+
+ result_ready = false;
+}
+
+void
+JavaRequestProcessor::postAndWaitForResponse(std::string message)
+{
+ struct timespec t;
+ clock_gettime(CLOCK_REALTIME, &t);
+ t.tv_sec += REQUESTTIMEOUT; // 1 minute timeout
+
+ // Clear the result
+ resetResult();
+
+ java_to_plugin_bus->subscribe(this);
+ plugin_to_java_bus->post(message.c_str());
+
+ // Wait for result to be filled in.
+ struct timespec curr_t;
+
+ do
+ {
+ clock_gettime(CLOCK_REALTIME, &curr_t);
+
+ if (!result_ready && (curr_t.tv_sec < t.tv_sec))
+ {
+ if (g_main_context_pending(NULL))
+ g_main_context_iteration(NULL, false);
+ else
+ usleep(200);
+ }
+ else
+ break;
+
+ } while (1);
+
+ if (curr_t.tv_sec >= t.tv_sec)
+ {
+ result->error_occurred = true;
+ result->error_msg->append("Error: Timed out when waiting for response");
+
+ // Report error
+ PLUGIN_DEBUG("Error: Timed out when waiting for response to %s\n", message.c_str());
+ }
+
+ java_to_plugin_bus->unSubscribe(this);
+}
+
+/**
+ * Given an object id, fetches the toString() value from Java
+ *
+ * @param object_id The ID of the object
+ * @return A JavaResultData struct containing the result of the request
+ */
+
+JavaResultData*
+JavaRequestProcessor::getToStringValue(std::string object_id)
+{
+ std::string message = std::string();
+
+ this->instance = 0; // context is always 0 (needed for java-side backwards compat.)
+ this->reference = IcedTeaPluginUtilities::getReference();
+
+ IcedTeaPluginUtilities::constructMessagePrefix(0, reference, &message);
+
+ message.append(" GetToStringValue "); // get it in UTF8
+ message.append(object_id);
+
+ postAndWaitForResponse(message);
+
+ IcedTeaPluginUtilities::releaseReference();
+
+ return result;
+}
+
+/**
+ * Given an object id, fetches the value of that ID from Java
+ *
+ * @param object_id The ID of the object
+ * @return A JavaResultData struct containing the result of the request
+ */
+
+JavaResultData*
+JavaRequestProcessor::getValue(std::string object_id)
+{
+ std::string message = std::string();
+
+ this->instance = 0; // context is always 0 (needed for java-side backwards compat.)
+ this->reference = IcedTeaPluginUtilities::getReference();
+
+ IcedTeaPluginUtilities::constructMessagePrefix(0, reference, &message);
+
+ message.append(" GetValue "); // get it in UTF8
+ message.append(object_id);
+
+ postAndWaitForResponse(message);
+
+ IcedTeaPluginUtilities::releaseReference();
+
+ return result;
+}
+
+/**
+ * Given a string id, fetches the actual string from Java side
+ *
+ * @param string_id The ID of the string
+ * @return A JavaResultData struct containing the result of the request
+ */
+
+JavaResultData*
+JavaRequestProcessor::getString(std::string string_id)
+{
+ std::string message = std::string();
+
+ this->instance = 0; // context is always 0 (needed for java-side backwards compat.)
+ this->reference = IcedTeaPluginUtilities::getReference();
+
+ IcedTeaPluginUtilities::constructMessagePrefix(0, reference, &message);
+
+ message.append(" GetStringUTFChars "); // get it in UTF8
+ message.append(string_id);
+
+ postAndWaitForResponse(message);
+
+ IcedTeaPluginUtilities::releaseReference();
+
+ return result;
+}
+
+/**
+ * Decrements reference count by 1
+ *
+ * @param object_id The ID of the object
+ */
+
+void
+JavaRequestProcessor::deleteReference(std::string object_id)
+{
+ std::string message = std::string();
+
+ this->instance = 0; // context is always 0 (needed for java-side backwards compat.)
+ this->reference = IcedTeaPluginUtilities::getReference();
+
+ IcedTeaPluginUtilities::constructMessagePrefix(0, reference, &message);
+
+ message.append(" DeleteLocalRef ");
+ message.append(object_id);
+
+ postAndWaitForResponse(message);
+
+ IcedTeaPluginUtilities::releaseReference();
+}
+
+/**
+ * Increments reference count by 1
+ *
+ * @param object_id The ID of the object
+ */
+
+void
+JavaRequestProcessor::addReference(std::string object_id)
+{
+ std::string message = std::string();
+
+ this->instance = 0; // context is always 0 (needed for java-side backwards compat.)
+ this->reference = IcedTeaPluginUtilities::getReference();
+
+ IcedTeaPluginUtilities::constructMessagePrefix(0, reference, &message);
+
+ message.append(" NewGlobalRef ");
+ message.append(object_id);
+
+ postAndWaitForResponse(message);
+
+ IcedTeaPluginUtilities::releaseReference();
+
+}
+
+JavaResultData*
+JavaRequestProcessor::findClass(int plugin_instance_id,
+ std::string name)
+{
+ std::string message = std::string();
+ std::string plugin_instance_id_str = std::string();
+
+ IcedTeaPluginUtilities::itoa(plugin_instance_id, &plugin_instance_id_str);
+
+ this->instance = 0; // context is always 0 (needed for java-side backwards compat.)
+ this->reference = IcedTeaPluginUtilities::getReference();
+
+ IcedTeaPluginUtilities::constructMessagePrefix(0, reference, &message);
+
+ message.append(" FindClass ");
+ message.append(plugin_instance_id_str);
+ message.append(" ");
+ message.append(name);
+
+ postAndWaitForResponse(message);
+
+ return result;
+}
+
+JavaResultData*
+JavaRequestProcessor::getClassName(std::string objectID)
+{
+ std::string message = std::string();
+
+ this->instance = 0; // context is always 0 (needed for java-side backwards compat.)
+ this->reference = IcedTeaPluginUtilities::getReference();
+
+ IcedTeaPluginUtilities::constructMessagePrefix(0, reference, &message);
+
+ message.append(" GetClassName ");
+ message.append(objectID);
+
+ postAndWaitForResponse(message);
+
+ return result;
+}
+
+JavaResultData*
+JavaRequestProcessor::getClassID(std::string objectID)
+{
+ std::string message = std::string();
+
+ this->instance = 0; // context is always 0 (needed for java-side backwards compat.)
+ this->reference = IcedTeaPluginUtilities::getReference();
+
+ IcedTeaPluginUtilities::constructMessagePrefix(0, reference, &message);
+
+ message.append(" GetClassID ");
+ message.append(objectID);
+
+ postAndWaitForResponse(message);
+
+ return result;
+}
+
+JavaResultData*
+JavaRequestProcessor::getArrayLength(std::string objectID)
+{
+ std::string message = std::string();
+
+ this->instance = 0; // context is always 0 (needed for java-side backwards compat.)
+ this->reference = IcedTeaPluginUtilities::getReference();
+
+ IcedTeaPluginUtilities::constructMessagePrefix(0, reference, &message);
+
+ message.append(" GetArrayLength ");
+ message.append(objectID);
+
+ postAndWaitForResponse(message);
+
+ return result;
+}
+
+JavaResultData*
+JavaRequestProcessor::getSlot(std::string objectID, std::string index)
+{
+ std::string message = std::string();
+ this->instance = 0; // context is always 0 (needed for java-side backwards compat.)
+ this->reference = IcedTeaPluginUtilities::getReference();
+
+ IcedTeaPluginUtilities::constructMessagePrefix(0, reference, &message);
+
+ message.append(" GetObjectArrayElement ");
+ message.append(objectID);
+ message.append(" ");
+ message.append(index);
+
+ postAndWaitForResponse(message);
+
+ return result;
+}
+
+JavaResultData*
+JavaRequestProcessor::setSlot(std::string objectID,
+ std::string index,
+ std::string value_id)
+{
+ std::string message = std::string();
+
+ this->instance = 0; // context is always 0 (needed for java-side backwards compat.)
+ this->reference = IcedTeaPluginUtilities::getReference();
+
+ IcedTeaPluginUtilities::constructMessagePrefix(0, reference, &message);
+
+ message.append(" SetObjectArrayElement ");
+ message.append(objectID);
+ message.append(" ");
+ message.append(index);
+ message.append(" ");
+ message.append(value_id);
+
+ postAndWaitForResponse(message);
+
+ IcedTeaPluginUtilities::releaseReference();
+
+ return result;
+}
+
+JavaResultData*
+JavaRequestProcessor::newArray(std::string array_class,
+ std::string length)
+{
+ std::string message = std::string();
+
+ this->instance = 0; // context is always 0 (needed for java-side backwards compat.)
+ this->reference = IcedTeaPluginUtilities::getReference();
+
+ IcedTeaPluginUtilities::constructMessagePrefix(0, reference, &message);
+
+ message.append(" NewArray ");
+ message.append(array_class);
+ message.append(" ");
+ message.append(length);
+
+ postAndWaitForResponse(message);
+
+ IcedTeaPluginUtilities::releaseReference();
+
+ return result;
+}
+
+JavaResultData*
+JavaRequestProcessor::getFieldID(std::string classID, std::string fieldName)
+{
+ JavaResultData* java_result;
+ JavaRequestProcessor* java_request = new JavaRequestProcessor();
+ std::string message = std::string();
+
+ java_result = java_request->newString(fieldName);
+
+ this->instance = 0; // context is always 0 (needed for java-side backwards compat.)
+ this->reference = IcedTeaPluginUtilities::getReference();
+
+ IcedTeaPluginUtilities::constructMessagePrefix(0, reference, &message);
+ message.append(" GetFieldID ");
+ message.append(classID);
+ message.append(" ");
+ message.append(java_result->return_string->c_str());
+
+ postAndWaitForResponse(message);
+
+ IcedTeaPluginUtilities::releaseReference();
+
+ delete java_request;
+
+ return result;
+}
+
+JavaResultData*
+JavaRequestProcessor::getStaticFieldID(std::string classID, std::string fieldName)
+{
+ JavaResultData* java_result;
+ JavaRequestProcessor* java_request = new JavaRequestProcessor();
+ std::string message = std::string();
+
+ java_result = java_request->newString(fieldName);
+
+ this->instance = 0; // context is always 0 (needed for java-side backwards compat.)
+ this->reference = IcedTeaPluginUtilities::getReference();
+
+ IcedTeaPluginUtilities::constructMessagePrefix(0, reference, &message);
+ message.append(" GetStaticFieldID ");
+ message.append(classID);
+ message.append(" ");
+ message.append(java_result->return_string->c_str());
+
+ postAndWaitForResponse(message);
+
+ IcedTeaPluginUtilities::releaseReference();
+
+ delete java_request;
+
+ return result;
+}
+
+JavaResultData*
+JavaRequestProcessor::getField(std::string source,
+ std::string classID,
+ std::string objectID,
+ std::string fieldName)
+{
+ JavaResultData* java_result;
+ JavaRequestProcessor* java_request = new JavaRequestProcessor();
+ std::string message = std::string();
+
+ java_result = java_request->getFieldID(classID, fieldName);
+
+ this->instance = 0; // context is always 0 (needed for java-side backwards compat.)
+ this->reference = IcedTeaPluginUtilities::getReference();
+
+ IcedTeaPluginUtilities::constructMessagePrefix(0, reference, source, &message);
+ message.append(" GetField ");
+ message.append(objectID);
+ message.append(" ");
+ message.append(java_result->return_string->c_str());
+
+ postAndWaitForResponse(message);
+
+ IcedTeaPluginUtilities::releaseReference();
+
+ delete java_request;
+
+ return result;
+}
+
+JavaResultData*
+JavaRequestProcessor::getStaticField(std::string source, std::string classID,
+ std::string fieldName)
+{
+ JavaResultData* java_result;
+ JavaRequestProcessor* java_request = new JavaRequestProcessor();
+ std::string message = std::string();
+
+ java_result = java_request->getStaticFieldID(classID, fieldName);
+
+ this->instance = 0; // context is always 0 (needed for java-side backwards compat.)
+ this->reference = IcedTeaPluginUtilities::getReference();
+
+ IcedTeaPluginUtilities::constructMessagePrefix(0, reference, source, &message);
+ message.append(" GetStaticField ");
+ message.append(classID);
+ message.append(" ");
+ message.append(java_result->return_string->c_str());
+
+ postAndWaitForResponse(message);
+
+ IcedTeaPluginUtilities::releaseReference();
+
+ delete java_request;
+
+ return result;
+}
+
+
+JavaResultData*
+JavaRequestProcessor::set(std::string source,
+ bool isStatic,
+ std::string classID,
+ std::string objectID,
+ std::string fieldName,
+ std::string value_id)
+{
+ JavaResultData* java_result;
+ JavaRequestProcessor java_request = JavaRequestProcessor();
+ std::string message = std::string();
+
+ java_result = java_request.getFieldID(classID, fieldName);
+
+ this->instance = 0; // context is always 0 (needed for java-side backwards compat.)
+ this->reference = IcedTeaPluginUtilities::getReference();
+
+ IcedTeaPluginUtilities::constructMessagePrefix(0, reference, source, &message);
+
+ if (isStatic)
+ {
+ message.append(" SetStaticField ");
+ message.append(classID);
+ } else
+ {
+ message.append(" SetField ");
+ message.append(objectID);
+ }
+
+ message.append(" ");
+ message.append(java_result->return_string->c_str());
+ message.append(" ");
+ message.append(value_id);
+
+ postAndWaitForResponse(message);
+
+ IcedTeaPluginUtilities::releaseReference();
+
+ return result;
+}
+
+JavaResultData*
+JavaRequestProcessor::setStaticField(std::string source,
+ std::string classID,
+ std::string fieldName,
+ std::string value_id)
+{
+ return set(source, true, classID, "", fieldName, value_id);
+}
+
+JavaResultData*
+JavaRequestProcessor::setField(std::string source,
+ std::string classID,
+ std::string objectID,
+ std::string fieldName,
+ std::string value_id)
+{
+ return set(source, false, classID, objectID, fieldName, value_id);
+}
+
+JavaResultData*
+JavaRequestProcessor::getMethodID(std::string classID, NPIdentifier methodName,
+ std::vector<std::string> args)
+{
+ JavaRequestProcessor* java_request;
+ std::string message = std::string();
+ std::string* signature;
+
+ signature = new std::string();
+ *signature += "(";
+
+ // FIXME: Need to determine how to extract array types and complex java objects
+ for (int i=0; i < args.size(); i++)
+ {
+ *signature += args[i];
+ }
+
+ *signature += ")";
+
+ this->instance = 0; // context is always 0 (needed for java-side backwards compat.)
+ this->reference = IcedTeaPluginUtilities::getReference();
+
+ IcedTeaPluginUtilities::constructMessagePrefix(0, reference, &message);
+ message += " GetMethodID ";
+ message += classID;
+ message += " ";
+ message += browser_functions.utf8fromidentifier(methodName);
+ message += " ";
+ message += *signature;
+
+ postAndWaitForResponse(message);
+
+ IcedTeaPluginUtilities::releaseReference();
+ delete signature;
+
+ return result;
+}
+
+JavaResultData*
+JavaRequestProcessor::getStaticMethodID(std::string classID, NPIdentifier methodName,
+ std::vector<std::string> args)
+{
+ JavaRequestProcessor* java_request;
+ std::string message = std::string();
+ std::string* signature;
+
+ signature = new std::string();
+ *signature += "(";
+
+ // FIXME: Need to determine how to extract array types and complex java objects
+ for (int i=0; i < args.size(); i++)
+ {
+ *signature += args[i];
+ }
+
+ *signature += ")";
+
+ this->instance = 0; // context is always 0 (needed for java-side backwards compat.)
+ this->reference = IcedTeaPluginUtilities::getReference();
+
+ IcedTeaPluginUtilities::constructMessagePrefix(0, reference, &message);
+ message += " GetStaticMethodID ";
+ message += classID;
+ message += " ";
+ message += browser_functions.utf8fromidentifier(methodName);
+ message += " ";
+ message += *signature;
+
+ postAndWaitForResponse(message);
+
+ IcedTeaPluginUtilities::releaseReference();
+ delete signature;
+
+ return result;
+}
+
+void
+getArrayTypeForJava(NPP instance, NPVariant element, std::string* type)
+{
+
+ if (NPVARIANT_IS_BOOLEAN(element)) {
+ type->append("string");
+ } else if (NPVARIANT_IS_INT32(element)) {
+ type->append("string");
+ } else if (NPVARIANT_IS_DOUBLE(element)) {
+ type->append("string");
+ } else if (NPVARIANT_IS_STRING(element)) {
+ type->append("string");
+ } else if (NPVARIANT_IS_OBJECT(element)) {
+
+ NPObject* first_element_obj = NPVARIANT_TO_OBJECT(element);
+ if (IcedTeaScriptableJavaPackageObject::is_valid_java_object(first_element_obj))
+ {
+ std::string class_id = std::string(((IcedTeaScriptableJavaObject*) first_element_obj)->getClassID());
+ type->append(class_id);
+ } else
+ {
+ type->append("jsobject");
+ }
+ } else {
+ type->append("jsobject"); // Else it is a string
+ }
+}
+
+void
+createJavaObjectFromVariant(NPP instance, NPVariant variant, std::string* id)
+{
+ JavaResultData* java_result;
+
+ std::string className;
+ std::string jsObjectClassID = std::string();
+ std::string jsObjectConstructorID = std::string();
+
+ std::string stringArg = std::string();
+ std::vector<std::string> args = std::vector<std::string>();
+
+ JavaRequestProcessor java_request = JavaRequestProcessor();
+ bool alreadyCreated = false;
+
+ if (NPVARIANT_IS_VOID(variant))
+ {
+ PLUGIN_DEBUG("VOID %d\n", variant);
+ id->append("0");
+ return; // no need to go further
+ } else if (NPVARIANT_IS_NULL(variant))
+ {
+ PLUGIN_DEBUG("NULL\n", variant);
+ id->append("0");
+ return; // no need to go further
+ } else if (NPVARIANT_IS_BOOLEAN(variant))
+ {
+ className = "java.lang.Boolean";
+
+ if (NPVARIANT_TO_BOOLEAN(variant))
+ stringArg = "true";
+ else
+ stringArg = "false";
+
+ } else if (NPVARIANT_IS_INT32(variant))
+ {
+ className = "java.lang.Integer";
+
+ char* valueStr = (char*) malloc(sizeof(char)*32);
+ sprintf(valueStr, "%d", NPVARIANT_TO_INT32(variant));
+ stringArg += valueStr;
+ free(valueStr);
+ } else if (NPVARIANT_IS_DOUBLE(variant))
+ {
+ className = "java.lang.Double";
+
+ char* valueStr = (char*) malloc(sizeof(char)*1024);
+ sprintf(valueStr, "%f", NPVARIANT_TO_DOUBLE(variant));
+ stringArg += valueStr;
+ free(valueStr);
+ } else if (NPVARIANT_IS_STRING(variant))
+ {
+ className = "java.lang.String";
+#if MOZILLA_VERSION_COLLAPSED < 1090200
+ stringArg += NPVARIANT_TO_STRING(variant).utf8characters;
+#else
+ stringArg += NPVARIANT_TO_STRING(variant).UTF8Characters;
+#endif
+ } else if (NPVARIANT_IS_OBJECT(variant))
+ {
+
+ NPObject* obj = NPVARIANT_TO_OBJECT(variant);
+ if (IcedTeaScriptableJavaPackageObject::is_valid_java_object(obj))
+ {
+ PLUGIN_DEBUG("NPObject is a Java object\n");
+ alreadyCreated = true;
+ } else
+ {
+ PLUGIN_DEBUG("NPObject is not a Java object\n");
+ NPIdentifier length_id = browser_functions.getstringidentifier("length");
+
+ // FIXME: We currently only handle <= 2 dim arrays. Do we really need more though?
+
+ // Is it an array?
+ if (IcedTeaPluginUtilities::isObjectJSArray(instance, obj)) {
+ PLUGIN_DEBUG("NPObject is an array\n");
+
+ std::string array_id = std::string();
+ std::string java_array_type = std::string();
+ NPVariant length = NPVariant();
+ browser_functions.getproperty(instance, obj, length_id, &length);
+
+ std::string length_str = std::string();
+ IcedTeaPluginUtilities::itoa(NPVARIANT_TO_INT32(length), &length_str);
+
+ if (NPVARIANT_TO_INT32(length) > 0)
+ {
+ NPIdentifier id_0 = browser_functions.getintidentifier(0);
+ NPVariant first_element = NPVariant();
+ browser_functions.getproperty(instance, obj, id_0, &first_element);
+
+ // Check for multi-dim array
+ if (NPVARIANT_IS_OBJECT(first_element) &&
+ IcedTeaPluginUtilities::isObjectJSArray(instance, NPVARIANT_TO_OBJECT(first_element))) {
+
+ NPVariant first_nested_element = NPVariant();
+ browser_functions.getproperty(instance, NPVARIANT_TO_OBJECT(first_element), id_0, &first_nested_element);
+
+ getArrayTypeForJava(instance, first_nested_element, &java_array_type);
+
+ length_str.append(" 0"); // secondary array is created on the fly
+ } else
+ {
+ getArrayTypeForJava(instance, first_element, &java_array_type);
+ }
+ } else
+ java_array_type.append("jsobject");
+
+ java_result = java_request.newArray(java_array_type, length_str);
+
+ if (java_result->error_occurred) {
+ printf("Unable to create array\n");
+ id->append("-1");
+ return;
+ }
+
+ id->append(*(java_result->return_string));
+
+ NPIdentifier index_id = NPIdentifier();
+ for (int i=0; i < NPVARIANT_TO_INT32(length); i++)
+ {
+ NPVariant value = NPVariant();
+
+ index_id = browser_functions.getintidentifier(i);
+ browser_functions.getproperty(instance, obj, index_id, &value);
+
+ std::string value_id = std::string();
+ createJavaObjectFromVariant(instance, value, &value_id);
+
+ if (value_id == "-1") {
+ printf("Unable to populate array\n");
+ id->clear();
+ id->append("-1");
+ return;
+ }
+
+ std::string value_str = std::string();
+ IcedTeaPluginUtilities::itoa(i, &value_str);
+ java_result = java_request.setSlot(*id, value_str, value_id);
+
+ }
+
+ // Got here => no errors above. We're good to return!
+ return;
+ } else // Else it is not an array
+ {
+
+ NPVariant* variant_copy = new NPVariant();
+ OBJECT_TO_NPVARIANT(NPVARIANT_TO_OBJECT(variant), *variant_copy);
+
+ className = "netscape.javascript.JSObject";
+ IcedTeaPluginUtilities::JSIDToString(variant_copy, &stringArg);
+ browser_functions.retainobject(NPVARIANT_TO_OBJECT(variant));
+
+ std::string jsObjectClassID = std::string();
+ std::string jsObjectConstructorID = std::string();
+ std::vector<std::string> args = std::vector<std::string>();
+
+ java_result = java_request.findClass(0, "netscape.javascript.JSObject");
+
+ // the result we want is in result_string (assuming there was no error)
+ if (java_result->error_occurred)
+ {
+ printf("Unable to get JSObject class id\n");
+ id->clear();
+ id->append("-1");
+ return;
+ }
+
+ jsObjectClassID.append(*(java_result->return_string));
+ args.push_back("J");
+
+ java_result = java_request.getMethodID(jsObjectClassID,
+ browser_functions.getstringidentifier("<init>"),
+ args);
+
+ // the result we want is in result_string (assuming there was no error)
+ if (java_result->error_occurred)
+ {
+ printf("Unable to get JSObject constructor id\n");
+ id->clear();
+ id->append("-1");
+ return;
+ }
+
+ jsObjectConstructorID.append(*(java_result->return_string));
+
+ // We have the method id. Now create a new object.
+
+ args.clear();
+ args.push_back(stringArg);
+ java_result = java_request.newObjectWithConstructor("",
+ jsObjectClassID,
+ jsObjectConstructorID,
+ args);
+
+ // Store the instance ID for future reference
+ IcedTeaPluginUtilities::storeInstanceID(variant_copy, instance);
+
+ // the result we want is in result_string (assuming there was no error)
+ // the result we want is in result_string (assuming there was no error)
+ if (java_result->error_occurred)
+ {
+ printf("Unable to create JSObject\n");
+ id->clear();
+ id->append("-1");
+ return;
+ }
+
+ id->append(*(java_result->return_string));
+ return;
+ }
+ }
+ }
+
+ if (!alreadyCreated) {
+ java_result = java_request.findClass(0, className);
+
+ // the result we want is in result_string (assuming there was no error)
+ if (java_result->error_occurred) {
+ printf("Unable to find classid for %s\n", className.c_str());
+ id->append("-1");
+ return;
+ }
+
+ jsObjectClassID.append(*(java_result->return_string));
+
+ std::string stringClassName = "Ljava/lang/String;";
+ args.push_back(stringClassName);
+
+ java_result = java_request.getMethodID(jsObjectClassID,
+ browser_functions.getstringidentifier("<init>"), args);
+
+ // the result we want is in result_string (assuming there was no error)
+ if (java_result->error_occurred) {
+ printf("Unable to find string constructor for %s\n", className.c_str());
+ id->append("-1");
+ return;
+ }
+
+ jsObjectConstructorID.append(*(java_result->return_string));
+
+ // We have class id and constructor ID. So we know we can create the
+ // object.. now create the string that will be provided as the arg
+ java_result = java_request.newString(stringArg);
+
+ if (java_result->error_occurred) {
+ printf("Unable to create requested object\n");
+ id->append("-1");
+ return;
+ }
+
+ // Create the object
+ args.clear();
+ std::string arg = std::string();
+ arg.append(*(java_result->return_string));
+ args.push_back(arg);
+ java_result = java_request.newObjectWithConstructor("[System]", jsObjectClassID, jsObjectConstructorID, args);
+
+ if (java_result->error_occurred) {
+ printf("Unable to create requested object\n");
+ id->append("-1");
+ return;
+ }
+
+
+ id->append(*(java_result->return_string));
+
+ } else {
+ // Else already created
+
+ std::string classId = std::string(((IcedTeaScriptableJavaObject*) NPVARIANT_TO_OBJECT(variant))->getClassID());
+ std::string instanceId = std::string(((IcedTeaScriptableJavaObject*) NPVARIANT_TO_OBJECT(variant))->getInstanceID());
+
+ if (instanceId.length() == 0)
+ id->append(classId.c_str());
+ else
+ id->append(instanceId.c_str());
+ }
+
+}
+
+JavaResultData*
+JavaRequestProcessor::callStaticMethod(std::string source, std::string classID,
+ std::string methodName,
+ std::vector<std::string> args)
+{
+ return call(source, true, classID, methodName, args);
+}
+
+JavaResultData*
+JavaRequestProcessor::callMethod(std::string source,
+ std::string objectID, std::string methodName,
+ std::vector<std::string> args)
+{
+ return call(source, false, objectID, methodName, args);
+}
+
+JavaResultData*
+JavaRequestProcessor::call(std::string source,
+ bool isStatic, std::string objectID,
+ std::string methodName,
+ std::vector<std::string> args)
+{
+ std::string message = std::string();
+ this->instance = 0; // context is always 0 (needed for java-side backwards compat.)
+ this->reference = IcedTeaPluginUtilities::getReference();
+
+ IcedTeaPluginUtilities::constructMessagePrefix(0, reference, source, &message);
+
+ if (isStatic)
+ message += " CallStaticMethod ";
+ else
+ message += " CallMethod ";
+
+ message += objectID;
+ message += " ";
+ message += methodName;
+ message += " ";
+
+ for (int i=0; i < args.size(); i++)
+ {
+ message += args[i];
+ message += " ";
+ }
+
+ postAndWaitForResponse(message);
+
+ IcedTeaPluginUtilities::releaseReference();
+
+ return result;
+}
+
+JavaResultData*
+JavaRequestProcessor::getObjectClass(std::string objectID)
+{
+ JavaRequestProcessor* java_request;
+ std::string message = std::string();
+
+ this->instance = 0; // context is always 0 (needed for java-side backwards compat.)
+ this->reference = IcedTeaPluginUtilities::getReference();
+
+ IcedTeaPluginUtilities::constructMessagePrefix(0, reference, &message);
+ message += " GetObjectClass ";
+ message += objectID;
+
+ postAndWaitForResponse(message);
+
+ IcedTeaPluginUtilities::releaseReference();
+
+ return result;
+}
+
+JavaResultData*
+JavaRequestProcessor::newObject(std::string source, std::string classID,
+ std::vector<std::string> args)
+{
+ JavaRequestProcessor* java_request;
+ std::string message = std::string();
+
+ this->instance = 0; // context is always 0 (needed for java-side backwards compat.)
+ this->reference = IcedTeaPluginUtilities::getReference();
+
+ IcedTeaPluginUtilities::constructMessagePrefix(0, reference, source, &message);
+ message += " NewObject ";
+ message += classID;
+ message += " ";
+
+ for (int i=0; i < args.size(); i++)
+ {
+ message += args[i];
+ message += " ";
+ }
+
+ postAndWaitForResponse(message);
+
+ IcedTeaPluginUtilities::releaseReference();
+
+ return result;
+}
+
+JavaResultData*
+JavaRequestProcessor::newObjectWithConstructor(std::string source, std::string classID,
+ std::string methodID,
+ std::vector<std::string> args)
+{
+ JavaRequestProcessor* java_request;
+ std::string message = std::string();
+
+ this->instance = 0; // context is always 0 (needed for java-side backwards compat.)
+ this->reference = IcedTeaPluginUtilities::getReference();
+
+ IcedTeaPluginUtilities::constructMessagePrefix(0, reference, source, &message);
+ message += " NewObjectWithConstructor ";
+ message += classID;
+ message += " ";
+ message += methodID;
+ message += " ";
+
+ for (int i=0; i < args.size(); i++)
+ {
+ message += args[i];
+ message += " ";
+ }
+
+ postAndWaitForResponse(message);
+
+ IcedTeaPluginUtilities::releaseReference();
+
+ return result;
+}
+
+JavaResultData*
+JavaRequestProcessor::newString(std::string str)
+{
+ std::string utf_string = std::string();
+ std::string message = std::string();
+
+ IcedTeaPluginUtilities::convertStringToUTF8(&str, &utf_string);
+
+ this->instance = 0; // context is always 0 (needed for java-side backwards compat.)
+ this->reference = IcedTeaPluginUtilities::getReference();
+
+ IcedTeaPluginUtilities::constructMessagePrefix(0, reference, &message);
+ message.append(" NewStringUTF ");
+ message.append(utf_string);
+
+ postAndWaitForResponse(message);
+
+ IcedTeaPluginUtilities::releaseReference();
+
+ return result;
+}
+
+JavaResultData*
+JavaRequestProcessor::hasPackage(int plugin_instance_id,
+ std::string package_name)
+{
+ JavaResultData* java_result;
+ JavaRequestProcessor* java_request = new JavaRequestProcessor();
+ std::string message = std::string();
+ std::string plugin_instance_id_str = std::string();
+ IcedTeaPluginUtilities::itoa(plugin_instance_id, &plugin_instance_id_str);
+
+ java_result = java_request->newString(package_name);
+
+ this->instance = 0; // context is always 0 (needed for java-side backwards compat.)
+ this->reference = IcedTeaPluginUtilities::getReference();
+
+ IcedTeaPluginUtilities::constructMessagePrefix(0, reference, &message);
+ message.append(" HasPackage ");
+ message.append(plugin_instance_id_str);
+ message.append(" ");
+ message.append(java_result->return_string->c_str());
+
+ postAndWaitForResponse(message);
+
+ IcedTeaPluginUtilities::releaseReference();
+
+ delete java_request;
+
+ return result;
+}
+
+JavaResultData*
+JavaRequestProcessor::hasMethod(std::string classID, std::string method_name)
+{
+ JavaResultData* java_result;
+ JavaRequestProcessor* java_request = new JavaRequestProcessor();
+ std::string message = std::string();
+
+ java_result = java_request->newString(method_name);
+
+ this->instance = 0; // context is always 0 (needed for java-side backwards compat.)
+ this->reference = IcedTeaPluginUtilities::getReference();
+
+ IcedTeaPluginUtilities::constructMessagePrefix(0, reference, &message);
+ message.append(" HasMethod ");
+ message.append(classID);
+ message.append(" ");
+ message.append(java_result->return_string->c_str());
+
+ postAndWaitForResponse(message);
+
+ IcedTeaPluginUtilities::releaseReference();
+
+ delete java_request;
+
+ return result;
+}
+
+JavaResultData*
+JavaRequestProcessor::hasField(std::string classID, std::string method_name)
+{
+ JavaResultData* java_result;
+ JavaRequestProcessor java_request = JavaRequestProcessor();
+ std::string message = std::string();
+
+ java_result = java_request.newString(method_name);
+
+ this->instance = 0; // context is always 0 (needed for java-side backwards compat.)
+ this->reference = IcedTeaPluginUtilities::getReference();
+
+ IcedTeaPluginUtilities::constructMessagePrefix(0, reference, &message);
+ message.append(" HasField ");
+ message.append(classID);
+ message.append(" ");
+ message.append(java_result->return_string->c_str());
+
+ postAndWaitForResponse(message);
+
+ IcedTeaPluginUtilities::releaseReference();
+
+ return result;
+}
+
+JavaResultData*
+JavaRequestProcessor::isInstanceOf(std::string objectID, std::string classID)
+{
+ std::string message = std::string();
+
+ this->instance = 0; // context is always 0 (needed for java-side backwards compat.)
+ this->reference = IcedTeaPluginUtilities::getReference();
+
+ IcedTeaPluginUtilities::constructMessagePrefix(0, reference, &message);
+ message.append(" IsInstanceOf ");
+ message.append(objectID);
+ message.append(" ");
+ message.append(classID);
+
+ postAndWaitForResponse(message);
+
+ IcedTeaPluginUtilities::releaseReference();
+
+ return result;
+}
+
+JavaResultData*
+JavaRequestProcessor::getAppletObjectInstance(std::string instanceID)
+{
+ std::string message = std::string();
+ std::string ref_str = std::string();
+
+ this->instance = 0;
+ this->reference = IcedTeaPluginUtilities::getReference();
+ IcedTeaPluginUtilities::itoa(reference, &ref_str);
+
+ message = "instance ";
+ message += instanceID;
+ message += " reference ";
+ message += ref_str;
+ message += " GetJavaObject";
+
+ postAndWaitForResponse(message);
+
+ IcedTeaPluginUtilities::releaseReference();
+
+ return result;
+}
+
diff --git a/plugin/icedteanp/IcedTeaJavaRequestProcessor.h b/plugin/icedteanp/IcedTeaJavaRequestProcessor.h
new file mode 100644
index 0000000..63223fd
--- /dev/null
+++ b/plugin/icedteanp/IcedTeaJavaRequestProcessor.h
@@ -0,0 +1,233 @@
+/* IcedTeaJavaRequestProcessor.h
+
+ Copyright (C) 2009, 2010 Red Hat
+
+This file is part of IcedTea.
+
+IcedTea is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+IcedTea is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with IcedTea; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+#ifndef ICEDTEAJAVAREQUEST_H_
+#define ICEDTEAJAVAREQUEST_H_
+
+#include <errno.h>
+#include <stdlib.h>
+#include <vector>
+
+#include "IcedTeaNPPlugin.h"
+#include "IcedTeaPluginUtils.h"
+
+#define REQUESTTIMEOUT 180
+
+/*
+ * This struct holds data specific to a Java operation requested by the plugin
+ */
+typedef struct java_request
+{
+ // Instance id (if applicable)
+ int instance;
+
+ // Context id (if applicable)
+ int context;
+
+ // request specific data
+ std::vector<std::string>* data;
+
+ // source of the request
+ std::string* source;
+
+} JavaRequest;
+
+/* Creates a argument on java-side with appropriate type */
+void createJavaObjectFromVariant(NPP instance, NPVariant variant, std::string* id);
+
+/* Returns the type of array based on the given element */
+void getArrayTypeForJava(NPP instance, NPVariant element, std::string* type);
+
+class JavaRequestProcessor : BusSubscriber
+{
+ private:
+ // instance and references are constant throughout this objects
+ // lifecycle
+ int instance;
+ int reference;
+ bool result_ready;
+ JavaResultData* result;
+
+ /* Post message on bus and wait */
+ void postAndWaitForResponse(std::string message);
+
+ // Call a method, static or otherwise, depending on supplied arg
+ JavaResultData* call(std::string source, bool isStatic,
+ std::string objectID, std::string methodName,
+ std::vector<std::string> args);
+
+ // Set a static/non-static field to given value
+ JavaResultData* set(std::string source,
+ bool isStatic,
+ std::string classID,
+ std::string objectID,
+ std::string fieldName,
+ std::string value_id);
+
+ /* Resets the results */
+ void resetResult();
+
+ public:
+ JavaRequestProcessor();
+ ~JavaRequestProcessor();
+ virtual bool newMessageOnBus(const char* message);
+
+ /* Increments reference count by 1 */
+ void addReference(std::string object_id);
+
+ /* Decrements reference count by 1 */
+ void deleteReference(std::string object_id);
+
+ /* Returns the toString() value, given an object identifier */
+ JavaResultData* getToStringValue(std::string object_id);
+
+ /* Returns the value, given an object identifier */
+ JavaResultData* getValue(std::string object_id);
+
+ /* Returns the string, given the identifier */
+ JavaResultData* getString(std::string string_id);
+
+ /* Returns the field object */
+ JavaResultData* getField(std::string source,
+ std::string classID,
+ std::string objectID,
+ std::string fieldName);
+
+ /* Returns the static field object */
+ JavaResultData* getStaticField(std::string source,
+ std::string classID,
+ std::string fieldName);
+
+ /* Sets the field object */
+ JavaResultData* setField(std::string source,
+ std::string classID,
+ std::string objectID,
+ std::string fieldName,
+ std::string value_id);
+
+ /* Sets the static field object */
+ JavaResultData* setStaticField(std::string source,
+ std::string classID,
+ std::string fieldName,
+ std::string value_id);
+
+ /* Returns the field id */
+ JavaResultData* getFieldID(std::string classID, std::string fieldName);
+
+ /* Returns the static field id */
+ JavaResultData* getStaticFieldID(std::string classID, std::string fieldName);
+
+ /* Returns the method id */
+ JavaResultData* getMethodID(std::string classID, NPIdentifier methodName,
+ std::vector<std::string> args);
+
+ /* Returns the static method id */
+ JavaResultData* getStaticMethodID(std::string classID, NPIdentifier methodName,
+ std::vector<std::string> args);
+
+ /* Calls a static method */
+ JavaResultData* callStaticMethod(std::string source,
+ std::string classID,
+ std::string methodName,
+ std::vector<std::string> args);
+
+ /* Calls a method on an instance */
+ JavaResultData* callMethod(std::string source,
+ std::string objectID,
+ std::string methodName,
+ std::vector<std::string> args);
+
+ /* Returns the class of the given object */
+ JavaResultData* getObjectClass(std::string objectID);
+
+ /* Creates a new object with choosable constructor */
+ JavaResultData* newObject(std::string source,
+ std::string classID,
+ std::vector<std::string> args);
+
+ /* Creates a new object when constructor is undetermined */
+ JavaResultData* newObjectWithConstructor(std::string source, std::string classID,
+ std::string methodID,
+ std::vector<std::string> args);
+
+ /* Returns the class ID */
+ JavaResultData* findClass(int plugin_instance_id,
+ std::string name);
+
+ /* Returns the type class name */
+ JavaResultData* getClassName(std::string objectID);
+
+ /* Returns the type class id */
+ JavaResultData* getClassID(std::string objectID);
+
+ /* Returns the length of the array object. -1 if not found */
+ JavaResultData* getArrayLength(std::string objectID);
+
+ /* Returns the item at the given index for the array */
+ JavaResultData* getSlot(std::string objectID, std::string index);
+
+ /* Sets the item at the given index to the given value */
+ JavaResultData* setSlot(std::string objectID,
+ std::string index,
+ std::string value_id);
+
+ /* Creates a new array of given length */
+ JavaResultData* newArray(std::string component_class,
+ std::string length);
+
+ /* Creates a new string in the Java store */
+ JavaResultData* newString(std::string str);
+
+ /* Check if package exists */
+ JavaResultData* hasPackage(int plugin_instance_id,
+ std::string package_name);
+
+ /* Check if method exists */
+ JavaResultData* hasMethod(std::string classID, std::string method_name);
+
+ /* Check if field exists */
+ JavaResultData* hasField(std::string classID, std::string method_name);
+
+ /* Check if given object is instance of given class */
+ JavaResultData* isInstanceOf(std::string objectID, std::string classID);
+
+ /* Returns the instance ID of the java applet */
+ JavaResultData* getAppletObjectInstance(std::string instanceID);
+};
+
+#endif /* ICEDTEAJAVAREQUESTPROCESSOR_H_ */
diff --git a/plugin/icedteanp/IcedTeaNPPlugin.cc b/plugin/icedteanp/IcedTeaNPPlugin.cc
new file mode 100644
index 0000000..ac40103
--- /dev/null
+++ b/plugin/icedteanp/IcedTeaNPPlugin.cc
@@ -0,0 +1,2453 @@
+/* IcedTeaNPPlugin.cc -- web browser plugin to execute Java applets
+ Copyright (C) 2003, 2004, 2006, 2007 Free Software Foundation, Inc.
+ Copyright (C) 2009, 2010 Red Hat
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+// System includes.
+#include <dlfcn.h>
+#include <errno.h>
+#include <libgen.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+// Liveconnect extension
+#include "IcedTeaScriptablePluginObject.h"
+#include "IcedTeaNPPlugin.h"
+
+#if MOZILLA_VERSION_COLLAPSED < 1090100
+// Documentbase retrieval includes.
+#include <nsIPluginInstance.h>
+#include <nsIPluginInstancePeer.h>
+#include <nsIPluginTagInfo2.h>
+
+// API's into Mozilla
+#include <nsCOMPtr.h>
+#include <nsICookieService.h>
+#include <nsIDNSRecord.h>
+#include <nsIDNSService.h>
+#include <nsINetUtil.h>
+#include <nsIProxyInfo.h>
+#include <nsIProtocolProxyService.h>
+#include <nsIScriptSecurityManager.h>
+#include <nsIIOService.h>
+#include <nsIURI.h>
+#include <nsNetCID.h>
+#include <nsStringAPI.h>
+#include <nsServiceManagerUtils.h>
+#endif
+
+// Error reporting macros.
+#define PLUGIN_ERROR(message) \
+ g_printerr ("%s:%d: thread %p: Error: %s\n", __FILE__, __LINE__, \
+ g_thread_self (), message)
+
+#define PLUGIN_ERROR_TWO(first, second) \
+ g_printerr ("%s:%d: thread %p: Error: %s: %s\n", __FILE__, __LINE__, \
+ g_thread_self (), first, second)
+
+#define PLUGIN_ERROR_THREE(first, second, third) \
+ g_printerr ("%s:%d: thread %p: Error: %s: %s: %s\n", __FILE__, \
+ __LINE__, g_thread_self (), first, second, third)
+
+// Plugin information passed to about:plugins.
+#define PLUGIN_NAME "IcedTea NPR Web Browser Plugin (using " PLUGIN_VERSION ")"
+#define PLUGIN_DESC "The " PLUGIN_NAME " executes Java applets."
+
+#define PLUGIN_MIME_DESC \
+ "application/x-java-vm:class,jar:IcedTea;" \
+ "application/x-java-applet:class,jar:IcedTea;" \
+ "application/x-java-applet;version=1.1:class,jar:IcedTea;" \
+ "application/x-java-applet;version=1.1.1:class,jar:IcedTea;" \
+ "application/x-java-applet;version=1.1.2:class,jar:IcedTea;" \
+ "application/x-java-applet;version=1.1.3:class,jar:IcedTea;" \
+ "application/x-java-applet;version=1.2:class,jar:IcedTea;" \
+ "application/x-java-applet;version=1.2.1:class,jar:IcedTea;" \
+ "application/x-java-applet;version=1.2.2:class,jar:IcedTea;" \
+ "application/x-java-applet;version=1.3:class,jar:IcedTea;" \
+ "application/x-java-applet;version=1.3.1:class,jar:IcedTea;" \
+ "application/x-java-applet;version=1.4:class,jar:IcedTea;" \
+ "application/x-java-applet;version=1.4.1:class,jar:IcedTea;" \
+ "application/x-java-applet;version=1.4.2:class,jar:IcedTea;" \
+ "application/x-java-applet;version=1.5:class,jar:IcedTea;" \
+ "application/x-java-applet;version=1.6:class,jar:IcedTea;" \
+ "application/x-java-applet;jpi-version=1.6.0_" JDK_UPDATE_VERSION ":class,jar:IcedTea;" \
+ "application/x-java-bean:class,jar:IcedTea;" \
+ "application/x-java-bean;version=1.1:class,jar:IcedTea;" \
+ "application/x-java-bean;version=1.1.1:class,jar:IcedTea;" \
+ "application/x-java-bean;version=1.1.2:class,jar:IcedTea;" \
+ "application/x-java-bean;version=1.1.3:class,jar:IcedTea;" \
+ "application/x-java-bean;version=1.2:class,jar:IcedTea;" \
+ "application/x-java-bean;version=1.2.1:class,jar:IcedTea;" \
+ "application/x-java-bean;version=1.2.2:class,jar:IcedTea;" \
+ "application/x-java-bean;version=1.3:class,jar:IcedTea;" \
+ "application/x-java-bean;version=1.3.1:class,jar:IcedTea;" \
+ "application/x-java-bean;version=1.4:class,jar:IcedTea;" \
+ "application/x-java-bean;version=1.4.1:class,jar:IcedTea;" \
+ "application/x-java-bean;version=1.4.2:class,jar:IcedTea;" \
+ "application/x-java-bean;version=1.5:class,jar:IcedTea;" \
+ "application/x-java-bean;version=1.6:class,jar:IcedTea;" \
+ "application/x-java-bean;jpi-version=1.6.0_" JDK_UPDATE_VERSION ":class,jar:IcedTea;" \
+ "application/x-java-vm-npruntime::IcedTea;"
+
+#define PLUGIN_URL NS_INLINE_PLUGIN_CONTRACTID_PREFIX NS_JVM_MIME_TYPE
+#define PLUGIN_MIME_TYPE "application/x-java-vm"
+#define PLUGIN_FILE_EXTS "class,jar,zip"
+#define PLUGIN_MIME_COUNT 1
+
+#define FAILURE_MESSAGE "icedteanp plugin error: Failed to run %s." \
+ " For more detail rerun \"firefox -g\" in a terminal window."
+
+#if MOZILLA_VERSION_COLLAPSED < 1090100
+// Documentbase retrieval required definition.
+static NS_DEFINE_IID (kIPluginTagInfo2IID, NS_IPLUGINTAGINFO2_IID);
+#endif
+
+// Data directory for plugin.
+static gchar* data_directory = NULL;
+
+// Fully-qualified appletviewer executable.
+static gchar* appletviewer_executable = NULL;
+
+// Applet viewer input channel (needs to be static because it is used in plugin_in_pipe_callback)
+static GIOChannel* in_from_appletviewer = NULL;
+
+// Applet viewer input pipe name.
+gchar* in_pipe_name;
+
+// Applet viewer input watch source.
+gint in_watch_source;
+
+// Applet viewer output pipe name.
+gchar* out_pipe_name;
+
+// Applet viewer output watch source.
+gint out_watch_source;
+
+// Applet viewer output channel.
+GIOChannel* out_to_appletviewer;
+
+// Tracks jvm status
+gboolean jvm_up = FALSE;
+
+// Keeps track of initialization. NP_Initialize should only be
+// called once.
+gboolean initialized = false;
+
+// browser functions into mozilla
+NPNetscapeFuncs browser_functions;
+
+// Various message buses carrying information to/from Java, and internally
+MessageBus* plugin_to_java_bus;
+MessageBus* java_to_plugin_bus;
+//MessageBus* internal_bus = new MessageBus();
+
+// Processor for plugin requests
+PluginRequestProcessor* plugin_req_proc;
+
+// Sends messages to Java over the bus
+JavaMessageSender* java_req_proc;
+
+#if MOZILLA_VERSION_COLLAPSED < 1090100
+// Documentbase retrieval type-punning union.
+typedef union
+{
+ void** void_field;
+ nsIPluginTagInfo2** info_field;
+} info_union;
+#endif
+
+// Static instance helper functions.
+// Have the browser allocate a new ITNPPluginData structure.
+static void plugin_data_new (ITNPPluginData** data);
+// Retrieve the current document's documentbase.
+static gchar* plugin_get_documentbase (NPP instance);
+// Notify the user that the appletviewer is not installed correctly.
+static void plugin_display_failure_dialog ();
+// Callback used to monitor input pipe status.
+static gboolean plugin_in_pipe_callback (GIOChannel* source,
+ GIOCondition condition,
+ gpointer plugin_data);
+// Callback used to monitor output pipe status.
+static gboolean plugin_out_pipe_callback (GIOChannel* source,
+ GIOCondition condition,
+ gpointer plugin_data);
+static NPError plugin_start_appletviewer (ITNPPluginData* data);
+static gchar* plugin_create_applet_tag (int16_t argc, char* argn[],
+ char* argv[]);
+static void plugin_stop_appletviewer ();
+// Uninitialize ITNPPluginData structure
+static void plugin_data_destroy (NPP instance);
+
+NPError get_cookie_info(const char* siteAddr, char** cookieString, uint32_t* len);
+NPError get_proxy_info(const char* siteAddr, char** proxy, uint32_t* len);
+void consume_message(gchar* message);
+void start_jvm_if_needed();
+static void appletviewer_monitor(GPid pid, gint status, gpointer data);
+
+// Global instance counter.
+// Mutex to protect plugin_instance_counter.
+static GMutex* plugin_instance_mutex = NULL;
+// A global variable for reporting GLib errors. This must be free'd
+// and set to NULL after each use.
+static GError* channel_error = NULL;
+
+static GHashTable* instance_to_id_map = g_hash_table_new(NULL, NULL);
+static GHashTable* id_to_instance_map = g_hash_table_new(NULL, NULL);
+static gint instance_counter = 1;
+static GPid appletviewer_pid = -1;
+static guint appletviewer_watch_id = -1;
+
+int plugin_debug = getenv ("ICEDTEAPLUGIN_DEBUG") != NULL;
+
+pthread_cond_t cond_message_available = PTHREAD_COND_INITIALIZER;
+
+// Functions prefixed by ITNP_ are instance functions. They are called
+// by the browser and operate on instances of ITNPPluginData.
+// Functions prefixed by plugin_ are static helper functions.
+// Functions prefixed by NP_ are factory functions. They are called
+// by the browser and provide functionality needed to create plugin
+// instances.
+
+// INSTANCE FUNCTIONS
+
+// Creates a new icedtea np plugin instance. This function creates a
+// ITNPPluginData* and stores it in instance->pdata. The following
+// ITNPPluginData fiels are initialized: instance_id, in_pipe_name,
+// in_from_appletviewer, in_watch_source, out_pipe_name,
+// out_to_appletviewer, out_watch_source, appletviewer_mutex, owner,
+// appletviewer_alive. In addition two pipe files are created. All
+// of those fields must be properly destroyed, and the pipes deleted,
+// by ITNP_Destroy. If an error occurs during initialization then this
+// function will free anything that's been allocated so far, set
+// instance->pdata to NULL and return an error code.
+NPError
+ITNP_New (NPMIMEType pluginType, NPP instance, uint16_t mode,
+ int16_t argc, char* argn[], char* argv[],
+ NPSavedData* saved)
+{
+ PLUGIN_DEBUG("ITNP_New\n");
+
+ static NPObject *window_ptr;
+ NPIdentifier identifier;
+ NPVariant member_ptr;
+ browser_functions.getvalue(instance, NPNVWindowNPObject, &window_ptr);
+ identifier = browser_functions.getstringidentifier("document");
+ if (!browser_functions.hasproperty(instance, window_ptr, identifier))
+ {
+ printf("%s not found!\n", "document");
+ }
+ browser_functions.getproperty(instance, window_ptr, identifier, &member_ptr);
+
+ PLUGIN_DEBUG("Got variant %p\n", &member_ptr);
+
+
+ NPError np_error = NPERR_NO_ERROR;
+ ITNPPluginData* data = NULL;
+
+ gchar* documentbase = NULL;
+ gchar* read_message = NULL;
+ gchar* applet_tag = NULL;
+ gchar* cookie_info = NULL;
+
+ NPObject* npPluginObj = NULL;
+
+ if (!instance)
+ {
+ PLUGIN_ERROR ("Browser-provided instance pointer is NULL.");
+ np_error = NPERR_INVALID_INSTANCE_ERROR;
+ goto cleanup_done;
+ }
+
+ // data
+ plugin_data_new (&data);
+ if (data == NULL)
+ {
+ PLUGIN_ERROR ("Failed to allocate plugin data.");
+ np_error = NPERR_OUT_OF_MEMORY_ERROR;
+ goto cleanup_done;
+ }
+
+ // start the jvm if needed
+ start_jvm_if_needed();
+
+ // Initialize data->instance_id.
+ //
+ // instance_id should be unique for this process so we use a
+ // combination of getpid and plugin_instance_counter.
+ //
+ // Critical region. Reference and increment plugin_instance_counter
+ // global.
+ g_mutex_lock (plugin_instance_mutex);
+
+ // data->instance_id
+ data->instance_id = g_strdup_printf ("%d",
+ instance_counter);
+
+ g_mutex_unlock (plugin_instance_mutex);
+
+ // data->appletviewer_mutex
+ data->appletviewer_mutex = g_mutex_new ();
+
+ g_mutex_lock (data->appletviewer_mutex);
+
+ // Documentbase retrieval.
+ documentbase = plugin_get_documentbase (instance);
+ if (documentbase && argc != 0)
+ {
+ // Send applet tag message to appletviewer.
+ applet_tag = plugin_create_applet_tag (argc, argn, argv);
+
+ data->applet_tag = (gchar*) malloc(strlen(applet_tag)*sizeof(gchar) + strlen(documentbase)*sizeof(gchar) + 32);
+ g_sprintf(data->applet_tag, "tag %s %s", documentbase, applet_tag);
+
+ data->is_applet_instance = true;
+ }
+
+ if (argc == 0)
+ {
+ data->is_applet_instance = false;
+ }
+
+ g_mutex_unlock (data->appletviewer_mutex);
+
+ // If initialization succeeded entirely then we store the plugin
+ // data in the instance structure and return. Otherwise we free the
+ // data we've allocated so far and set instance->pdata to NULL.
+
+ // Set back-pointer to owner instance.
+ data->owner = instance;
+
+ // source of this instance
+ // don't use documentbase, it is cleared later
+ data->source = plugin_get_documentbase(instance);
+
+ instance->pdata = data;
+
+ goto cleanup_done;
+
+ cleanup_appletviewer_mutex:
+ g_free (data->appletviewer_mutex);
+ data->appletviewer_mutex = NULL;
+
+ // cleanup_instance_string:
+ g_free (data->instance_id);
+ data->instance_id = NULL;
+
+ // cleanup applet tag:
+ g_free (data->applet_tag);
+ data->applet_tag = NULL;
+
+ // cleanup_data:
+ // Eliminate back-pointer to plugin instance.
+ data->owner = NULL;
+ (*browser_functions.memfree) (data);
+ data = NULL;
+
+ // Initialization failed so return a NULL pointer for the browser
+ // data.
+ instance->pdata = NULL;
+
+ cleanup_done:
+ g_free (applet_tag);
+ applet_tag = NULL;
+ g_free (read_message);
+ read_message = NULL;
+ g_free (documentbase);
+ documentbase = NULL;
+
+ // store an identifier for this plugin
+ PLUGIN_DEBUG("Mapping id %d and instance %p\n", instance_counter, instance);
+ g_hash_table_insert(instance_to_id_map, instance, GINT_TO_POINTER(instance_counter));
+ g_hash_table_insert(id_to_instance_map, GINT_TO_POINTER(instance_counter), instance);
+ instance_counter++;
+
+ PLUGIN_DEBUG ("ITNP_New return\n");
+
+ return np_error;
+}
+
+// Starts the JVM if it is not already running
+void start_jvm_if_needed()
+{
+
+ // This is asynchronized function. It must
+ // have exclusivity when running.
+
+ GMutex *vm_start_mutex = g_mutex_new();
+ g_mutex_lock(vm_start_mutex);
+
+ PLUGIN_DEBUG("Checking JVM status...\n");
+
+ // If the jvm is already up, do nothing
+ if (jvm_up)
+ {
+ PLUGIN_DEBUG("JVM is up. Returning.\n");
+ return;
+ }
+
+ PLUGIN_DEBUG("No JVM is running. Attempting to start one...\n");
+
+ NPError np_error = NPERR_NO_ERROR;
+ ITNPPluginData* data = NULL;
+
+ // Create appletviewer-to-plugin pipe which we refer to as the input
+ // pipe.
+
+ // in_pipe_name
+ in_pipe_name = g_strdup_printf ("%s/%d-icedteanp-appletviewer-to-plugin",
+ data_directory, getpid());
+ if (!in_pipe_name)
+ {
+ PLUGIN_ERROR ("Failed to create input pipe name.");
+ np_error = NPERR_OUT_OF_MEMORY_ERROR;
+ // If in_pipe_name is NULL then the g_free at
+ // cleanup_in_pipe_name will simply return.
+ goto cleanup_in_pipe_name;
+ }
+
+ // clean up any older pip
+ unlink (in_pipe_name);
+
+ PLUGIN_DEBUG ("ITNP_New: creating input fifo: %s\n", in_pipe_name);
+ if (mkfifo (in_pipe_name, 0600) == -1 && errno != EEXIST)
+ {
+ PLUGIN_ERROR_TWO ("Failed to create input pipe", strerror (errno));
+ np_error = NPERR_GENERIC_ERROR;
+ goto cleanup_in_pipe_name;
+ }
+ PLUGIN_DEBUG ("ITNP_New: created input fifo: %s\n", in_pipe_name);
+
+ // Create plugin-to-appletviewer pipe which we refer to as the
+ // output pipe.
+
+ // out_pipe_name
+ out_pipe_name = g_strdup_printf ("%s/%d-icedteanp-plugin-to-appletviewer",
+ data_directory, getpid());
+
+ if (!out_pipe_name)
+ {
+ PLUGIN_ERROR ("Failed to create output pipe name.");
+ np_error = NPERR_OUT_OF_MEMORY_ERROR;
+ goto cleanup_out_pipe_name;
+ }
+
+ // clean up any older pip
+ unlink (out_pipe_name);
+
+ PLUGIN_DEBUG ("ITNP_New: creating output fifo: %s\n", out_pipe_name);
+ if (mkfifo (out_pipe_name, 0600) == -1 && errno != EEXIST)
+ {
+ PLUGIN_ERROR_TWO ("Failed to create output pipe", strerror (errno));
+ np_error = NPERR_GENERIC_ERROR;
+ goto cleanup_out_pipe_name;
+ }
+ PLUGIN_DEBUG ("ITNP_New: created output fifo: %s\n", out_pipe_name);
+
+ // Start a separate appletviewer process for each applet, even if
+ // there are multiple applets in the same page. We may need to
+ // change this behaviour if we find pages with multiple applets that
+ // rely on being run in the same VM.
+
+ np_error = plugin_start_appletviewer (data);
+
+ // Create plugin-to-appletviewer channel. The default encoding for
+ // the file is UTF-8.
+ // out_to_appletviewer
+ out_to_appletviewer = g_io_channel_new_file (out_pipe_name,
+ "w", &channel_error);
+ if (!out_to_appletviewer)
+ {
+ if (channel_error)
+ {
+ PLUGIN_ERROR_TWO ("Failed to create output channel",
+ channel_error->message);
+ g_error_free (channel_error);
+ channel_error = NULL;
+ }
+ else
+ PLUGIN_ERROR ("Failed to create output channel");
+
+ np_error = NPERR_GENERIC_ERROR;
+ goto cleanup_out_to_appletviewer;
+ }
+
+ // Watch for hangup and error signals on the output pipe.
+ out_watch_source =
+ g_io_add_watch (out_to_appletviewer,
+ (GIOCondition) (G_IO_ERR | G_IO_HUP),
+ plugin_out_pipe_callback, (gpointer) out_to_appletviewer);
+
+ // Create appletviewer-to-plugin channel. The default encoding for
+ // the file is UTF-8.
+ // in_from_appletviewer
+ in_from_appletviewer = g_io_channel_new_file (in_pipe_name,
+ "r", &channel_error);
+ if (!in_from_appletviewer)
+ {
+ if (channel_error)
+ {
+ PLUGIN_ERROR_TWO ("Failed to create input channel",
+ channel_error->message);
+ g_error_free (channel_error);
+ channel_error = NULL;
+ }
+ else
+ PLUGIN_ERROR ("Failed to create input channel");
+
+ np_error = NPERR_GENERIC_ERROR;
+ goto cleanup_in_from_appletviewer;
+ }
+
+ // Watch for hangup and error signals on the input pipe.
+ in_watch_source =
+ g_io_add_watch (in_from_appletviewer,
+ (GIOCondition) (G_IO_IN | G_IO_ERR | G_IO_HUP),
+ plugin_in_pipe_callback, (gpointer) in_from_appletviewer);
+
+ jvm_up = TRUE;
+
+ goto done;
+
+ // Free allocated data
+
+ cleanup_in_watch_source:
+ // Removing a source is harmless if it fails since it just means the
+ // source has already been removed.
+ g_source_remove (in_watch_source);
+ in_watch_source = 0;
+
+ cleanup_in_from_appletviewer:
+ if (in_from_appletviewer)
+ g_io_channel_unref (in_from_appletviewer);
+ in_from_appletviewer = NULL;
+
+ // cleanup_out_watch_source:
+ g_source_remove (out_watch_source);
+ out_watch_source = 0;
+
+ cleanup_out_to_appletviewer:
+ if (out_to_appletviewer)
+ g_io_channel_unref (out_to_appletviewer);
+ out_to_appletviewer = NULL;
+
+ // cleanup_out_pipe:
+ // Delete output pipe.
+ PLUGIN_DEBUG ("ITNP_New: deleting input fifo: %s\n", in_pipe_name);
+ unlink (out_pipe_name);
+ PLUGIN_DEBUG ("ITNP_New: deleted input fifo: %s\n", in_pipe_name);
+
+ cleanup_out_pipe_name:
+ g_free (out_pipe_name);
+ out_pipe_name = NULL;
+
+ // cleanup_in_pipe:
+ // Delete input pipe.
+ PLUGIN_DEBUG ("ITNP_New: deleting output fifo: %s\n", out_pipe_name);
+ unlink (in_pipe_name);
+ PLUGIN_DEBUG ("ITNP_New: deleted output fifo: %s\n", out_pipe_name);
+
+ cleanup_in_pipe_name:
+ g_free (in_pipe_name);
+ in_pipe_name = NULL;
+
+ done:
+
+ // Now other threads may re-enter.. unlock the mutex
+ g_mutex_unlock(vm_start_mutex);
+
+}
+
+NPError
+ITNP_GetValue (NPP instance, NPPVariable variable, void* value)
+{
+ PLUGIN_DEBUG ("ITNP_GetValue\n");
+
+ NPError np_error = NPERR_NO_ERROR;
+
+ switch (variable)
+ {
+ // This plugin needs XEmbed support.
+ case NPPVpluginNeedsXEmbed:
+ {
+ PLUGIN_DEBUG ("ITNP_GetValue: returning TRUE for NeedsXEmbed.\n");
+ bool* bool_value = (bool*) value;
+ *bool_value = true;
+ }
+ break;
+ case NPPVpluginScriptableNPObject:
+ {
+ *(NPObject **)value = get_scriptable_object(instance);
+ }
+ break;
+ default:
+ PLUGIN_ERROR ("Unknown plugin value requested.");
+ np_error = NPERR_GENERIC_ERROR;
+ break;
+ }
+
+ PLUGIN_DEBUG ("ITNP_GetValue return\n");
+
+ return np_error;
+}
+
+NPError
+ITNP_Destroy (NPP instance, NPSavedData** save)
+{
+ PLUGIN_DEBUG ("ITNP_Destroy %p\n", instance);
+
+ ITNPPluginData* data = (ITNPPluginData*) instance->pdata;
+
+ int id = get_id_from_instance(instance);
+
+ // Let Java know that this applet needs to be destroyed
+ gchar* msg = (gchar*) g_malloc(512*sizeof(gchar)); // 512 is more than enough. We need < 100
+ g_sprintf(msg, "instance %d destroy", id);
+ plugin_send_message_to_appletviewer(msg);
+ g_free(msg);
+ msg = NULL;
+
+ if (data)
+ {
+ // Free plugin data.
+ plugin_data_destroy (instance);
+ }
+
+ g_hash_table_remove(instance_to_id_map, instance);
+ g_hash_table_remove(id_to_instance_map, GINT_TO_POINTER(id));
+
+ IcedTeaPluginUtilities::invalidateInstance(instance);
+
+ PLUGIN_DEBUG ("ITNP_Destroy return\n");
+
+ return NPERR_NO_ERROR;
+}
+
+NPError
+ITNP_SetWindow (NPP instance, NPWindow* window)
+{
+ PLUGIN_DEBUG ("ITNP_SetWindow\n");
+
+ if (instance == NULL)
+ {
+ PLUGIN_ERROR ("Invalid instance.");
+
+ return NPERR_INVALID_INSTANCE_ERROR;
+ }
+
+ gpointer id_ptr = g_hash_table_lookup(instance_to_id_map, instance);
+
+ gint id = 0;
+ if (id_ptr)
+ {
+ id = GPOINTER_TO_INT(id_ptr);
+ }
+
+ ITNPPluginData* data = (ITNPPluginData*) instance->pdata;
+
+ // Simply return if we receive a NULL window.
+ if ((window == NULL) || (window->window == NULL))
+ {
+ PLUGIN_DEBUG ("ITNP_SetWindow: got NULL window.\n");
+
+ return NPERR_NO_ERROR;
+ }
+
+ if (data->window_handle)
+ {
+ // The window already exists.
+ if (data->window_handle == window->window)
+ {
+ // The parent window is the same as in previous calls.
+ PLUGIN_DEBUG ("ITNP_SetWindow: window already exists.\n");
+
+ // Critical region. Read data->appletviewer_mutex and send
+ // a message to the appletviewer.
+ g_mutex_lock (data->appletviewer_mutex);
+
+ if (jvm_up)
+ {
+ gboolean dim_changed = FALSE;
+
+ // The window is the same as it was for the last
+ // SetWindow call.
+ if (window->width != data->window_width)
+ {
+ PLUGIN_DEBUG ("ITNP_SetWindow: window width changed.\n");
+ // The width of the plugin window has changed.
+
+ // Store the new width.
+ data->window_width = window->width;
+ dim_changed = TRUE;
+ }
+
+ if (window->height != data->window_height)
+ {
+ PLUGIN_DEBUG ("ITNP_SetWindow: window height changed.\n");
+ // The height of the plugin window has changed.
+
+ // Store the new height.
+ data->window_height = window->height;
+
+ dim_changed = TRUE;
+ }
+
+ if (dim_changed) {
+ gchar* message = g_strdup_printf ("instance %d width %d height %d",
+ id, window->width, window->height);
+ plugin_send_message_to_appletviewer (message);
+ g_free (message);
+ message = NULL;
+ }
+
+
+ }
+ else
+ {
+ // The appletviewer is not running.
+ PLUGIN_DEBUG ("ITNP_SetWindow: appletviewer is not running.\n");
+ }
+
+ g_mutex_unlock (data->appletviewer_mutex);
+ }
+ else
+ {
+ // The parent window has changed. This branch does run but
+ // doing nothing in response seems to be sufficient.
+ PLUGIN_DEBUG ("ITNP_SetWindow: parent window changed.\n");
+ }
+ }
+ else
+ {
+ // Else this is initialization
+ PLUGIN_DEBUG ("ITNP_SetWindow: setting window.\n");
+
+ // Critical region. Send messages to appletviewer.
+ g_mutex_lock (data->appletviewer_mutex);
+
+ // Store the window handle and dimensions
+ data->window_handle = window->window;
+ data->window_width = window->width;
+ data->window_height = window->height;
+
+ // Now we have everything. Send this data to the Java side
+
+ gchar* instance_msg = g_strdup_printf ("instance %s handle %ld width %d height %d %s",
+ data->instance_id,
+ (gulong) data->window_handle,
+ data->window_width,
+ data->window_height,
+ data->applet_tag);
+
+ plugin_send_message_to_appletviewer (instance_msg);
+
+ g_free(instance_msg);
+ instance_msg = NULL;
+
+ g_mutex_unlock (data->appletviewer_mutex);
+
+ }
+
+ PLUGIN_DEBUG ("ITNP_SetWindow return\n");
+
+ return NPERR_NO_ERROR;
+}
+
+NPError
+ITNP_NewStream (NPP instance, NPMIMEType type, NPStream* stream,
+ NPBool seekable, uint16_t* stype)
+{
+ PLUGIN_DEBUG ("ITNP_NewStream\n");
+
+ PLUGIN_DEBUG ("ITNP_NewStream return\n");
+
+ return NPERR_GENERIC_ERROR;
+}
+
+void
+ITNP_StreamAsFile (NPP instance, NPStream* stream, const char* filename)
+{
+ PLUGIN_DEBUG ("ITNP_StreamAsFile\n");
+
+ PLUGIN_DEBUG ("ITNP_StreamAsFile return\n");
+}
+
+NPError
+ITNP_DestroyStream (NPP instance, NPStream* stream, NPReason reason)
+{
+ PLUGIN_DEBUG ("ITNP_DestroyStream\n");
+
+ PLUGIN_DEBUG ("ITNP_DestroyStream return\n");
+
+ return NPERR_NO_ERROR;
+}
+
+int32_t
+ITNP_WriteReady (NPP instance, NPStream* stream)
+{
+ PLUGIN_DEBUG ("ITNP_WriteReady\n");
+
+ PLUGIN_DEBUG ("ITNP_WriteReady return\n");
+
+ return 0;
+}
+
+int32_t
+ITNP_Write (NPP instance, NPStream* stream, int32_t offset, int32_t len,
+ void* buffer)
+{
+ PLUGIN_DEBUG ("ITNP_Write\n");
+
+ PLUGIN_DEBUG ("ITNP_Write return\n");
+
+ return 0;
+}
+
+void
+ITNP_Print (NPP instance, NPPrint* platformPrint)
+{
+ PLUGIN_DEBUG ("ITNP_Print\n");
+
+ PLUGIN_DEBUG ("ITNP_Print return\n");
+}
+
+int16_t
+ITNP_HandleEvent (NPP instance, void* event)
+{
+ PLUGIN_DEBUG ("ITNP_HandleEvent\n");
+
+ PLUGIN_DEBUG ("ITNP_HandleEvent return\n");
+
+ return 0;
+}
+
+void
+ITNP_URLNotify (NPP instance, const char* url, NPReason reason,
+ void* notifyData)
+{
+ PLUGIN_DEBUG ("ITNP_URLNotify\n");
+
+ PLUGIN_DEBUG ("ITNP_URLNotify return\n");
+}
+
+NPError
+get_cookie_info(const char* siteAddr, char** cookieString, uint32_t* len)
+{
+#if MOZILLA_VERSION_COLLAPSED < 1090100
+ nsresult rv;
+ nsCOMPtr<nsIScriptSecurityManager> sec_man =
+ do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
+
+ if (!sec_man) {
+ return NPERR_GENERIC_ERROR;
+ }
+
+ nsCOMPtr<nsIIOService> io_svc = do_GetService("@mozilla.org/network/io-service;1", &rv);
+
+ if (NS_FAILED(rv) || !io_svc) {
+ return NPERR_GENERIC_ERROR;
+ }
+
+ nsCOMPtr<nsIURI> uri;
+ io_svc->NewURI(nsCString(siteAddr), NULL, NULL, getter_AddRefs(uri));
+
+ nsCOMPtr<nsICookieService> cookie_svc = do_GetService("@mozilla.org/cookieService;1", &rv);
+
+ if (NS_FAILED(rv) || !cookie_svc) {
+ return NPERR_GENERIC_ERROR;
+ }
+
+ rv = cookie_svc->GetCookieString(uri, NULL, cookieString);
+
+ if (NS_FAILED(rv) || !*cookieString) {
+ return NPERR_GENERIC_ERROR;
+ }
+
+#else
+
+ // getvalueforurl needs an NPP instance. Quite frankly, there is no easy way
+ // to know which instance needs the information, as applets on Java side can
+ // be multi-threaded and the thread making a proxy.cookie request cannot be
+ // easily tracked.
+
+ // Fortunately, XULRunner does not care about the instance as long as it is
+ // valid. So we just pick the first valid one and use it. Proxy/Cookie
+ // information is not instance specific anyway, it is URL specific.
+
+ if (browser_functions.getvalueforurl)
+ {
+ GHashTableIter iter;
+ gpointer id, instance;
+
+ g_hash_table_iter_init (&iter, instance_to_id_map);
+ g_hash_table_iter_next (&iter, &instance, &id);
+
+ return browser_functions.getvalueforurl((NPP) instance, NPNURLVCookie, siteAddr, cookieString, len);
+ } else
+ {
+ return NPERR_GENERIC_ERROR;
+ }
+
+#endif
+
+ return NPERR_NO_ERROR;
+}
+
+// HELPER FUNCTIONS
+
+static void
+plugin_data_new (ITNPPluginData** data)
+{
+ PLUGIN_DEBUG ("plugin_data_new\n");
+
+ *data = (ITNPPluginData*)
+ (*browser_functions.memalloc) (sizeof (struct ITNPPluginData));
+
+ // appletviewer_alive is false until the applet viewer is spawned.
+ if (*data)
+ memset (*data, 0, sizeof (struct ITNPPluginData));
+
+ PLUGIN_DEBUG ("plugin_data_new return\n");
+}
+
+
+
+// Documentbase retrieval. This function gets the current document's
+// documentbase. This function relies on browser-private data so it
+// will only work when the plugin is loaded in a Mozilla-based
+// browser. We could not find a way to retrieve the documentbase
+// using the original Netscape plugin API so we use the XPCOM API
+// instead.
+#if MOZILLA_VERSION_COLLAPSED < 1090100
+static gchar*
+plugin_get_documentbase (NPP instance)
+{
+ PLUGIN_DEBUG ("plugin_get_documentbase\n");
+
+ nsIPluginInstance* xpcom_instance = NULL;
+ nsIPluginInstancePeer* peer = NULL;
+ nsresult result = 0;
+ nsIPluginTagInfo2* pluginTagInfo2 = NULL;
+ info_union u = { NULL };
+ char const* documentbase = NULL;
+ gchar* documentbase_copy = NULL;
+
+ xpcom_instance = (nsIPluginInstance*) (instance->ndata);
+ if (!xpcom_instance)
+ {
+ PLUGIN_ERROR ("xpcom_instance is NULL.");
+ goto cleanup_done;
+ }
+
+ xpcom_instance->GetPeer (&peer);
+ if (!peer)
+ {
+ PLUGIN_ERROR ("peer is NULL.");
+ goto cleanup_done;
+ }
+
+ u.info_field = &pluginTagInfo2;
+
+ result = peer->QueryInterface (kIPluginTagInfo2IID,
+ u.void_field);
+ if (result || !pluginTagInfo2)
+ {
+ PLUGIN_ERROR ("pluginTagInfo2 retrieval failed.");
+ goto cleanup_peer;
+ }
+
+ pluginTagInfo2->GetDocumentBase (&documentbase);
+
+ if (!documentbase)
+ {
+ // NULL => dummy instantiation for LiveConnect
+ goto cleanup_plugintaginfo2;
+ }
+
+ documentbase_copy = g_strdup (documentbase);
+
+ // Release references.
+ cleanup_plugintaginfo2:
+ NS_RELEASE (pluginTagInfo2);
+
+ cleanup_peer:
+ NS_RELEASE (peer);
+
+ cleanup_done:
+ PLUGIN_DEBUG ("plugin_get_documentbase return\n");
+
+ PLUGIN_DEBUG("plugin_get_documentbase returning: %s\n", documentbase_copy);
+ return documentbase_copy;
+}
+#else
+static gchar*
+plugin_get_documentbase (NPP instance)
+{
+ PLUGIN_DEBUG ("plugin_get_documentbase\n");
+
+ char const* documentbase = NULL;
+ gchar* documentbase_copy = NULL;
+
+ // FIXME: This method is not ideal, but there are no known NPAPI call
+ // for this. See thread for more information:
+ // http://www.mail-archive.com/[email protected]/msg04844.html
+
+ // Additionally, since it is insecure, we cannot use it for making
+ // security decisions.
+ NPObject* window;
+ browser_functions.getvalue(instance, NPNVWindowNPObject, &window);
+
+ NPVariant location;
+ NPIdentifier location_id = browser_functions.getstringidentifier("location");
+ browser_functions.getproperty(instance, window, location_id, &location);
+
+ NPVariant href;
+ NPIdentifier href_id = browser_functions.getstringidentifier("href");
+ browser_functions.getproperty(instance, NPVARIANT_TO_OBJECT(location),
+ href_id, &href);
+
+ // Strip everything after the last "/"
+#if MOZILLA_VERSION_COLLAPSED < 1090200
+ gchar** parts = g_strsplit (NPVARIANT_TO_STRING(href).utf8characters, "/", -1);
+#else
+ gchar** parts = g_strsplit (NPVARIANT_TO_STRING(href).UTF8Characters, "/", -1);
+#endif
+ guint parts_sz = g_strv_length (parts);
+
+ std::string location_str;
+ for (int i=0; i < parts_sz - 1; i++)
+ {
+ location_str += parts[i];
+ location_str += "/";
+ }
+
+ documentbase_copy = g_strdup (location_str.c_str());
+
+ // Release references.
+ browser_functions.releasevariantvalue(&href);
+ browser_functions.releasevariantvalue(&location);
+ cleanup_done:
+ PLUGIN_DEBUG ("plugin_get_documentbase return\n");
+ PLUGIN_DEBUG("plugin_get_documentbase returning: %s\n", documentbase_copy);
+
+ return documentbase_copy;
+}
+#endif
+
+// This function displays an error message if the appletviewer has not
+// been installed correctly.
+static void
+plugin_display_failure_dialog ()
+{
+ GtkWidget* dialog = NULL;
+
+ PLUGIN_DEBUG ("plugin_display_failure_dialog\n");
+
+ dialog = gtk_message_dialog_new (NULL,
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_CLOSE,
+ FAILURE_MESSAGE,
+ appletviewer_executable);
+ gtk_widget_show_all (dialog);
+ gtk_dialog_run (GTK_DIALOG (dialog));
+ gtk_widget_destroy (dialog);
+
+ PLUGIN_DEBUG ("plugin_display_failure_dialog return\n");
+}
+
+
+
+// plugin_in_pipe_callback is called when data is available on the
+// input pipe, or when the appletviewer crashes or is killed. It may
+// be called after data has been destroyed in which case it simply
+// returns FALSE to remove itself from the glib main loop.
+static gboolean
+plugin_in_pipe_callback (GIOChannel* source,
+ GIOCondition condition,
+ gpointer plugin_data)
+{
+ PLUGIN_DEBUG ("plugin_in_pipe_callback\n");
+
+ gboolean keep_installed = TRUE;
+
+ if (condition & G_IO_IN)
+ {
+ gchar* message = NULL;
+
+ if (g_io_channel_read_line (in_from_appletviewer,
+ &message, NULL, NULL,
+ &channel_error)
+ != G_IO_STATUS_NORMAL)
+ {
+ if (channel_error)
+ {
+ PLUGIN_ERROR_TWO ("Failed to read line from input channel",
+ channel_error->message);
+ g_error_free (channel_error);
+ channel_error = NULL;
+ }
+ else
+ PLUGIN_ERROR ("Failed to read line from input channel");
+ } else
+ {
+ consume_message(message);
+ }
+
+ g_free (message);
+ message = NULL;
+
+ keep_installed = TRUE;
+ }
+
+ if (condition & (G_IO_ERR | G_IO_HUP))
+ {
+ PLUGIN_DEBUG ("appletviewer has stopped.\n");
+ keep_installed = FALSE;
+ }
+
+ PLUGIN_DEBUG ("plugin_in_pipe_callback return\n");
+
+ return keep_installed;
+}
+
+void consume_message(gchar* message) {
+
+ PLUGIN_DEBUG (" PIPE: plugin read: %s\n", message);
+
+ if (g_str_has_prefix (message, "instance"))
+ {
+
+ ITNPPluginData* data;
+ gchar** parts = g_strsplit (message, " ", -1);
+ guint parts_sz = g_strv_length (parts);
+
+ int instance_id = atoi(parts[1]);
+ NPP instance = (NPP) g_hash_table_lookup(id_to_instance_map,
+ GINT_TO_POINTER(instance_id));
+
+ if (instance_id > 0 && !instance)
+ {
+ PLUGIN_DEBUG("Instance %d is not active. Refusing to consume message \"%s\"\n", instance_id, message);
+ return;
+ }
+ else if (instance)
+ {
+ data = (ITNPPluginData*) instance->pdata;
+ }
+
+ if (g_str_has_prefix (parts[2], "url"))
+ {
+ // Open the URL in a new browser window.
+ gchar* decoded_url = (gchar*) calloc(strlen(parts[3]) + 1, sizeof(gchar));
+ IcedTeaPluginUtilities::decodeURL(parts[3], &decoded_url);
+
+ PLUGIN_DEBUG ("plugin_in_pipe_callback: opening URL %s\n", decoded_url);
+ PLUGIN_DEBUG ("plugin_in_pipe_callback: URL target %s\n", parts[4]);
+
+ NPError np_error =
+ (*browser_functions.geturl) (data->owner, decoded_url, parts[4]);
+
+
+ if (np_error != NPERR_NO_ERROR)
+ PLUGIN_ERROR ("Failed to load URL.");
+
+ g_free(decoded_url);
+ decoded_url = NULL;
+ }
+ else if (g_str_has_prefix (parts[2], "status"))
+ {
+
+ // clear the "instance X status" parts
+ sprintf(parts[0], "");
+ sprintf(parts[1], "");
+ sprintf(parts[2], "");
+
+ // join the rest
+ gchar* status_message = g_strjoinv(" ", parts);
+ PLUGIN_DEBUG ("plugin_in_pipe_callback: setting status %s\n", status_message);
+ (*browser_functions.status) (data->owner, status_message);
+
+ g_free(status_message);
+ status_message = NULL;
+ }
+ else if (g_str_has_prefix (parts[1], "internal"))
+ {
+ //s->post(message);
+ }
+ else
+ {
+ // All other messages are posted to the bus, and subscribers are
+ // expected to take care of them. They better!
+
+ java_to_plugin_bus->post(message);
+ }
+
+ g_strfreev (parts);
+ parts = NULL;
+ }
+ else if (g_str_has_prefix (message, "context"))
+ {
+ java_to_plugin_bus->post(message);
+ }
+ else if (g_str_has_prefix (message, "plugin "))
+ {
+ // internal plugin related message
+ gchar** parts = g_strsplit (message, " ", 5);
+ if (g_str_has_prefix(parts[1], "PluginProxyInfo"))
+ {
+ gchar* proxy;
+ uint32_t len;
+
+ gchar* decoded_url = (gchar*) calloc(strlen(parts[4]) + 1, sizeof(gchar));
+ IcedTeaPluginUtilities::decodeURL(parts[4], &decoded_url);
+ 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);
+
+ gchar* proxy_info;
+
+#if MOZILLA_VERSION_COLLAPSED < 1090100
+ proxy = (char*) malloc(sizeof(char)*2048);
+#endif
+
+ proxy_info = g_strconcat ("plugin PluginProxyInfo reference ", parts[3], " ", NULL);
+ if (get_proxy_info(decoded_url, &proxy, &len) == NPERR_NO_ERROR)
+ {
+ proxy_info = g_strconcat (proxy_info, proxy, NULL);
+ }
+
+ PLUGIN_DEBUG("Proxy info: %s\n", proxy_info);
+ plugin_send_message_to_appletviewer(proxy_info);
+
+ g_free(decoded_url);
+ decoded_url = NULL;
+ g_free(proxy_info);
+ proxy_info = NULL;
+
+#if MOZILLA_VERSION_COLLAPSED < 1090100
+ g_free(proxy);
+ proxy = NULL;
+#endif
+
+ } else if (g_str_has_prefix(parts[1], "PluginCookieInfo"))
+ {
+ gchar* decoded_url = (gchar*) calloc(strlen(parts[4])+1, sizeof(gchar));
+ IcedTeaPluginUtilities::decodeURL(parts[4], &decoded_url);
+
+ gchar* cookie_info = g_strconcat ("plugin PluginCookieInfo reference ", parts[3], " ", NULL);
+ gchar* cookie_string;
+ uint32_t len;
+ if (get_cookie_info(decoded_url, &cookie_string, &len) == NPERR_NO_ERROR)
+ {
+ cookie_info = g_strconcat (cookie_info, cookie_string, NULL);
+ }
+
+ PLUGIN_DEBUG("Cookie info: %s\n", cookie_info);
+ plugin_send_message_to_appletviewer(cookie_info);
+
+ g_free(decoded_url);
+ decoded_url = NULL;
+ g_free(cookie_info);
+ cookie_info = NULL;
+ }
+ }
+ else
+ {
+ g_print (" Unable to handle message: %s\n", message);
+ }
+}
+
+void get_instance_from_id(int id, NPP& instance)
+{
+ instance = (NPP) g_hash_table_lookup(id_to_instance_map,
+ GINT_TO_POINTER(id));
+}
+
+int get_id_from_instance(NPP instance)
+{
+ int id = GPOINTER_TO_INT(g_hash_table_lookup(instance_to_id_map,
+ instance));
+ PLUGIN_DEBUG("Returning id %d for instance %p\n", id, instance);
+ return id;
+}
+
+NPError
+get_proxy_info(const char* siteAddr, char** proxy, uint32_t* len)
+{
+#if MOZILLA_VERSION_COLLAPSED < 1090100
+ nsresult rv;
+
+ // Initialize service variables
+ nsCOMPtr<nsIProtocolProxyService> proxy_svc = do_GetService("@mozilla.org/network/protocol-proxy-service;1", &rv);
+
+ if (!proxy_svc) {
+ printf("Cannot initialize proxy service\n");
+ return NPERR_GENERIC_ERROR;
+ }
+
+ nsCOMPtr<nsIIOService> io_svc = do_GetService("@mozilla.org/network/io-service;1", &rv);
+
+ if (NS_FAILED(rv) || !io_svc) {
+ printf("Cannot initialize io service\n");
+ return NPERR_GENERIC_ERROR;
+ }
+
+ // uri which needs to be accessed
+ nsCOMPtr<nsIURI> uri;
+ io_svc->NewURI(nsCString(siteAddr), NULL, NULL, getter_AddRefs(uri));
+
+ // find the proxy address if any
+ nsCOMPtr<nsIProxyInfo> info;
+ proxy_svc->Resolve(uri, 0, getter_AddRefs(info));
+
+ // if there is no proxy found, return immediately
+ if (!info) {
+ PLUGIN_DEBUG("%s does not need a proxy\n", siteAddr);
+ return NPERR_GENERIC_ERROR;
+ }
+
+ // if proxy info is available, extract it
+ nsCString phost;
+ PRInt32 pport;
+ nsCString ptype;
+
+ info->GetHost(phost);
+ info->GetPort(&pport);
+ info->GetType(ptype);
+
+ // resolve the proxy address to an IP
+ nsCOMPtr<nsIDNSService> dns_svc = do_GetService("@mozilla.org/network/dns-service;1", &rv);
+
+ if (!dns_svc) {
+ printf("Cannot initialize DNS service\n");
+ return NPERR_GENERIC_ERROR;
+ }
+
+ nsCOMPtr<nsIDNSRecord> record;
+ dns_svc->Resolve(phost, 0U, getter_AddRefs(record));
+
+ // TODO: Add support for multiple ips
+ nsDependentCString ipAddr;
+ record->GetNextAddrAsString(ipAddr);
+
+ if (!strcmp(ptype.get(), "http"))
+ {
+ snprintf(*proxy, sizeof(char)*1024, "%s %s:%d", "PROXY", ipAddr.get(), pport);
+ } else
+ {
+ snprintf(*proxy, sizeof(char)*1024, "%s %s:%d", "SOCKS", ipAddr.get(), pport);
+ }
+
+ *len = strlen(*proxy);
+
+ PLUGIN_DEBUG("Proxy info for %s: %s\n", siteAddr, *proxy);
+
+#else
+
+ if (browser_functions.getvalueforurl)
+ {
+
+ // As in get_cookie_info, we use the first active instance
+ GHashTableIter iter;
+ gpointer id, instance;
+
+ g_hash_table_iter_init (&iter, instance_to_id_map);
+ g_hash_table_iter_next (&iter, &instance, &id);
+
+ browser_functions.getvalueforurl((NPP) instance, NPNURLVProxy, siteAddr, proxy, len);
+ } else
+ {
+ return NPERR_GENERIC_ERROR;
+ }
+#endif
+
+ return NPERR_NO_ERROR;
+}
+
+// plugin_out_pipe_callback is called when the appletviewer crashes or
+// is killed. It may be called after data has been destroyed in which
+// case it simply returns FALSE to remove itself from the glib main
+// loop.
+static gboolean
+plugin_out_pipe_callback (GIOChannel* source,
+ GIOCondition condition,
+ gpointer plugin_data)
+{
+ PLUGIN_DEBUG ("plugin_out_pipe_callback\n");
+
+ ITNPPluginData* data = (ITNPPluginData*) plugin_data;
+
+ PLUGIN_DEBUG ("plugin_out_pipe_callback: appletviewer has stopped.\n");
+
+ PLUGIN_DEBUG ("plugin_out_pipe_callback return\n");
+
+ return FALSE;
+}
+
+// remove all components from LD_LIBRARY_PATH, which start with
+// MOZILLA_FIVE_HOME; firefox has its own NSS based security provider,
+// which conflicts with the one configured in nss.cfg.
+static gchar*
+plugin_filter_ld_library_path(gchar *path_old)
+{
+ gchar *moz_home = g_strdup (g_getenv ("MOZILLA_FIVE_HOME"));
+ gchar *moz_prefix;
+ gchar *path_new;
+ gchar** components;
+ int i1, i2;
+
+ if (moz_home == NULL || path_old == NULL || strlen (path_old) == 0)
+ return path_old;
+ if (g_str_has_suffix (moz_home, "/"))
+ moz_home[strlen (moz_home - 1)] = '\0';
+ moz_prefix = g_strconcat (moz_home, "/", NULL);
+
+ components = g_strsplit (path_old, ":", -1);
+ for (i1 = 0, i2 = 0; components[i1] != NULL; i1++)
+ {
+ if (g_strcmp0 (components[i1], moz_home) == 0
+ || g_str_has_prefix (components[i1], moz_home))
+ components[i2] = components[i1];
+ else
+ components[i2++] = components[i1];
+ }
+ components[i2] = NULL;
+
+ if (i1 > i2)
+ path_new = g_strjoinv (":", components);
+ g_strfreev (components);
+ g_free (moz_home);
+ g_free (moz_prefix);
+ g_free (path_old);
+
+ if (path_new == NULL || strlen (path_new) == 0)
+ {
+ PLUGIN_DEBUG("Unset LD_LIBRARY_PATH\n");
+ return NULL;
+ }
+ else
+ {
+ PLUGIN_DEBUG ("Set LD_LIBRARY_PATH: %s\n", path_new);
+ return path_new;
+ }
+}
+
+// build the environment to pass to the external plugin process
+static gchar**
+plugin_filter_environment(void)
+{
+ gchar **var_names = g_listenv();
+ gchar **new_env = (gchar**) malloc(sizeof(gchar*) * (g_strv_length (var_names) + 1));
+ int i_var, i_env;
+
+ for (i_var = 0, i_env = 0; var_names[i_var] != NULL; i_var++)
+ {
+ gchar *env_value = g_strdup (g_getenv (var_names[i_var]));
+
+ if (g_str_has_prefix (var_names[i_var], "LD_LIBRARY_PATH"))
+ env_value = plugin_filter_ld_library_path (env_value);
+ if (env_value != NULL)
+ {
+ new_env[i_env++] = g_strdup_printf ("%s=%s", var_names[i_var], env_value);
+ g_free (env_value);
+ }
+ }
+ new_env[i_env] = NULL;
+ return new_env;
+}
+
+static NPError
+plugin_test_appletviewer ()
+{
+ PLUGIN_DEBUG ("plugin_test_appletviewer: %s\n", appletviewer_executable);
+ NPError error = NPERR_NO_ERROR;
+
+ gchar* command_line[3] = { NULL, NULL, NULL };
+ gchar** environment;
+
+ command_line[0] = g_strdup (appletviewer_executable);
+ command_line[1] = g_strdup("-version");
+ command_line[2] = NULL;
+
+ environment = plugin_filter_environment();
+
+ if (!g_spawn_async (NULL, command_line, environment,
+ (GSpawnFlags) 0,
+ NULL, NULL, NULL, &channel_error))
+ {
+ if (channel_error)
+ {
+ PLUGIN_ERROR_TWO ("Failed to spawn applet viewer",
+ channel_error->message);
+ g_error_free (channel_error);
+ channel_error = NULL;
+ }
+ else
+ PLUGIN_ERROR ("Failed to spawn applet viewer");
+ error = NPERR_GENERIC_ERROR;
+ }
+
+ g_strfreev (environment);
+
+ g_free (command_line[0]);
+ command_line[0] = NULL;
+ g_free (command_line[1]);
+ command_line[1] = NULL;
+ g_free (command_line[2]);
+ command_line[2] = NULL;
+
+ PLUGIN_DEBUG ("plugin_test_appletviewer return\n");
+ return error;
+}
+
+static NPError
+plugin_start_appletviewer (ITNPPluginData* data)
+{
+ PLUGIN_DEBUG ("plugin_start_appletviewer\n");
+ NPError error = NPERR_NO_ERROR;
+
+ gchar** command_line;
+ gchar** environment;
+
+ if (plugin_debug)
+ {
+ command_line = (gchar**) malloc(sizeof(gchar*)*8);
+ command_line[0] = g_strdup(appletviewer_executable);
+ command_line[1] = g_strdup("-Xdebug");
+ command_line[2] = g_strdup("-Xnoagent");
+ command_line[3] = g_strdup("-Xrunjdwp:transport=dt_socket,address=8787,server=y,suspend=n");
+ command_line[4] = g_strdup("sun.applet.PluginMain");
+ command_line[5] = g_strdup(out_pipe_name);
+ command_line[6] = g_strdup(in_pipe_name);
+ command_line[7] = NULL;
+ } else
+ {
+ command_line = (gchar**) malloc(sizeof(gchar*)*5);
+ command_line[0] = g_strdup(appletviewer_executable);
+ command_line[1] = g_strdup("sun.applet.PluginMain");
+ command_line[2] = g_strdup(out_pipe_name);
+ command_line[3] = g_strdup(in_pipe_name);
+ command_line[4] = NULL;
+ }
+
+ environment = plugin_filter_environment();
+
+ if (!g_spawn_async (NULL, command_line, environment,
+ (GSpawnFlags) G_SPAWN_DO_NOT_REAP_CHILD,
+ NULL, NULL, &appletviewer_pid, &channel_error))
+ {
+ if (channel_error)
+ {
+ PLUGIN_ERROR_TWO ("Failed to spawn applet viewer",
+ channel_error->message);
+ g_error_free (channel_error);
+ channel_error = NULL;
+ }
+ else
+ PLUGIN_ERROR ("Failed to spawn applet viewer");
+ error = NPERR_GENERIC_ERROR;
+ }
+
+ g_strfreev (environment);
+
+ g_free (command_line[0]);
+ command_line[0] = NULL;
+ g_free (command_line[1]);
+ command_line[1] = NULL;
+
+ if (plugin_debug)
+ {
+ g_free (command_line[2]);
+ command_line[2] = NULL;
+ g_free (command_line[3]);
+ command_line[3] = NULL;
+ g_free (command_line[4]);
+ command_line[4] = NULL;
+ g_free (command_line[5]);
+ command_line[5] = NULL;
+ }
+
+ g_free(command_line);
+ command_line = NULL;
+
+ if (appletviewer_pid)
+ {
+ PLUGIN_DEBUG("Initialized VM with pid=%d\n", appletviewer_pid);
+ appletviewer_watch_id = g_child_watch_add(appletviewer_pid, (GChildWatchFunc) appletviewer_monitor, (gpointer) appletviewer_pid);
+ }
+
+
+ PLUGIN_DEBUG ("plugin_start_appletviewer return\n");
+ return error;
+}
+
+// Build up the applet tag string that we'll send to the applet
+// viewer.
+static gchar*
+plugin_create_applet_tag (int16_t argc, char* argn[], char* argv[])
+{
+ PLUGIN_DEBUG ("plugin_create_applet_tag\n");
+
+ gchar* applet_tag = g_strdup ("<EMBED ");
+ gchar* parameters = g_strdup ("");
+
+ for (int16_t i = 0; i < argc; i++)
+ {
+ if (!g_ascii_strcasecmp (argn[i], "code"))
+ {
+ gchar* code = g_strdup_printf ("CODE=\"%s\" ", argv[i]);
+ applet_tag = g_strconcat (applet_tag, code, NULL);
+ g_free (code);
+ code = NULL;
+ }
+ else if (!g_ascii_strcasecmp (argn[i], "java_code"))
+ {
+ gchar* java_code = g_strdup_printf ("JAVA_CODE=\"%s\" ", argv[i]);
+ applet_tag = g_strconcat (applet_tag, java_code, NULL);
+ g_free (java_code);
+ java_code = NULL;
+ }
+ else if (!g_ascii_strcasecmp (argn[i], "codebase"))
+ {
+ gchar* codebase = g_strdup_printf ("CODEBASE=\"%s\" ", argv[i]);
+ applet_tag = g_strconcat (applet_tag, codebase, NULL);
+ g_free (codebase);
+ codebase = NULL;
+ }
+ else if (!g_ascii_strcasecmp (argn[i], "java_codebase"))
+ {
+ gchar* java_codebase = g_strdup_printf ("JAVA_CODEBASE=\"%s\" ", argv[i]);
+ applet_tag = g_strconcat (applet_tag, java_codebase, NULL);
+ g_free (java_codebase);
+ java_codebase = NULL;
+ }
+ else if (!g_ascii_strcasecmp (argn[i], "classid"))
+ {
+ gchar* classid = g_strdup_printf ("CLASSID=\"%s\" ", argv[i]);
+ applet_tag = g_strconcat (applet_tag, classid, NULL);
+ g_free (classid);
+ classid = NULL;
+ }
+ else if (!g_ascii_strcasecmp (argn[i], "archive"))
+ {
+ gchar* archive = g_strdup_printf ("ARCHIVE=\"%s\" ", argv[i]);
+ applet_tag = g_strconcat (applet_tag, archive, NULL);
+ g_free (archive);
+ archive = NULL;
+ }
+ else if (!g_ascii_strcasecmp (argn[i], "java_archive"))
+ {
+ gchar* java_archive = g_strdup_printf ("JAVA_ARCHIVE=\"%s\" ", argv[i]);
+ applet_tag = g_strconcat (applet_tag, java_archive, NULL);
+ g_free (java_archive);
+ java_archive = NULL;
+ }
+ else if (!g_ascii_strcasecmp (argn[i], "width"))
+ {
+ gchar* width = g_strdup_printf ("width=\"%s\" ", argv[i]);
+ applet_tag = g_strconcat (applet_tag, width, NULL);
+ g_free (width);
+ width = NULL;
+ }
+ else if (!g_ascii_strcasecmp (argn[i], "height"))
+ {
+ gchar* height = g_strdup_printf ("height=\"%s\" ", argv[i]);
+ applet_tag = g_strconcat (applet_tag, height, NULL);
+ g_free (height);
+ height = NULL;
+ }
+ else
+ {
+ // Escape the parameter value so that line termination
+ // characters will pass through the pipe.
+ if (argv[i] != '\0')
+ {
+ // worst case scenario -> all characters are newlines or
+ // returns, each of which translates to 5 substitutions
+ char* escaped = (char*) calloc(((strlen(argv[i])*5)+1), sizeof(char));
+
+ strcpy(escaped, "");
+ for (int j=0; j < strlen(argv[i]); j++)
+ {
+ if (argv[i][j] == '\r')
+ strcat(escaped, "&#13;");
+ else if (argv[i][j] == '\n')
+ strcat(escaped, "&#10;");
+ else if (argv[i][j] == '>')
+ strcat(escaped, "&gt;");
+ else if (argv[i][j] == '<')
+ strcat(escaped, "&lt;");
+ else if (argv[i][j] == '&')
+ strcat(escaped, "&amp;");
+ else
+ {
+ char* orig_char = (char*) calloc(2, sizeof(char));
+ orig_char[0] = argv[i][j];
+ orig_char[1] = '\0';
+
+ strcat(escaped, orig_char);
+
+ free(orig_char);
+ orig_char = NULL;
+ }
+ }
+
+ parameters = g_strconcat (parameters, "<PARAM NAME=\"", argn[i],
+ "\" VALUE=\"", escaped, "\">", NULL);
+
+ free (escaped);
+ escaped = NULL;
+ }
+ }
+ }
+
+ applet_tag = g_strconcat (applet_tag, ">", parameters, "</EMBED>", NULL);
+
+ g_free (parameters);
+ parameters = NULL;
+
+ PLUGIN_DEBUG ("plugin_create_applet_tag return\n");
+
+ return applet_tag;
+}
+
+// plugin_send_message_to_appletviewer must be called while holding
+// data->appletviewer_mutex.
+void
+plugin_send_message_to_appletviewer (gchar const* message)
+{
+ PLUGIN_DEBUG ("plugin_send_message_to_appletviewer\n");
+
+ if (jvm_up)
+ {
+ gchar* newline_message = NULL;
+ gsize bytes_written = 0;
+
+ // Send message to appletviewer.
+ newline_message = g_strdup_printf ("%s\n", message);
+
+ // g_io_channel_write_chars will return something other than
+ // G_IO_STATUS_NORMAL if not all the data is written. In that
+ // case we fail rather than retrying.
+ if (g_io_channel_write_chars (out_to_appletviewer,
+ newline_message, -1, &bytes_written,
+ &channel_error)
+ != G_IO_STATUS_NORMAL)
+ {
+ if (channel_error)
+ {
+ PLUGIN_ERROR_TWO ("Failed to write bytes to output channel",
+ channel_error->message);
+ g_error_free (channel_error);
+ channel_error = NULL;
+ }
+ else
+ PLUGIN_ERROR ("Failed to write bytes to output channel");
+ }
+
+ if (g_io_channel_flush (out_to_appletviewer, &channel_error)
+ != G_IO_STATUS_NORMAL)
+ {
+ if (channel_error)
+ {
+ PLUGIN_ERROR_TWO ("Failed to flush bytes to output channel",
+ channel_error->message);
+ g_error_free (channel_error);
+ channel_error = NULL;
+ }
+ else
+ PLUGIN_ERROR ("Failed to flush bytes to output channel");
+ }
+ g_free (newline_message);
+ newline_message = NULL;
+
+ PLUGIN_DEBUG (" PIPE: plugin wrote: %s\n", message);
+ }
+
+ PLUGIN_DEBUG ("plugin_send_message_to_appletviewer return\n");
+}
+
+// Stop the appletviewer process. When this is called the
+// appletviewer can be in any of three states: running, crashed or
+// hung. If the appletviewer is running then sending it "shutdown"
+// will cause it to exit. This will cause
+// plugin_out_pipe_callback/plugin_in_pipe_callback to be called and
+// the input and output channels to be shut down. If the appletviewer
+// has crashed then plugin_out_pipe_callback/plugin_in_pipe_callback
+// would already have been called and data->appletviewer_alive cleared
+// in which case this function simply returns. If the appletviewer is
+// hung then this function will be successful and the input and output
+// watches will be removed by plugin_data_destroy.
+// plugin_stop_appletviewer must be called with
+// data->appletviewer_mutex held.
+static void
+plugin_stop_appletviewer ()
+{
+ PLUGIN_DEBUG ("plugin_stop_appletviewer\n");
+
+ if (jvm_up)
+ {
+ // Shut down the appletviewer.
+ gsize bytes_written = 0;
+
+ if (out_to_appletviewer)
+ {
+ if (g_io_channel_write_chars (out_to_appletviewer, "shutdown",
+ -1, &bytes_written, &channel_error)
+ != G_IO_STATUS_NORMAL)
+ {
+ if (channel_error)
+ {
+ PLUGIN_ERROR_TWO ("Failed to write shutdown message to"
+ " appletviewer", channel_error->message);
+ g_error_free (channel_error);
+ channel_error = NULL;
+ }
+ else
+ PLUGIN_ERROR ("Failed to write shutdown message to");
+ }
+
+ if (g_io_channel_flush (out_to_appletviewer, &channel_error)
+ != G_IO_STATUS_NORMAL)
+ {
+ if (channel_error)
+ {
+ PLUGIN_ERROR_TWO ("Failed to write shutdown message to"
+ " appletviewer", channel_error->message);
+ g_error_free (channel_error);
+ channel_error = NULL;
+ }
+ else
+ PLUGIN_ERROR ("Failed to write shutdown message to");
+ }
+
+ if (g_io_channel_shutdown (out_to_appletviewer,
+ TRUE, &channel_error)
+ != G_IO_STATUS_NORMAL)
+ {
+ if (channel_error)
+ {
+ PLUGIN_ERROR_TWO ("Failed to shut down appletviewer"
+ " output channel", channel_error->message);
+ g_error_free (channel_error);
+ channel_error = NULL;
+ }
+ else
+ PLUGIN_ERROR ("Failed to shut down appletviewer");
+ }
+ }
+
+ if (in_from_appletviewer)
+ {
+ if (g_io_channel_shutdown (in_from_appletviewer,
+ TRUE, &channel_error)
+ != G_IO_STATUS_NORMAL)
+ {
+ if (channel_error)
+ {
+ PLUGIN_ERROR_TWO ("Failed to shut down appletviewer"
+ " input channel", channel_error->message);
+ g_error_free (channel_error);
+ channel_error = NULL;
+ }
+ else
+ PLUGIN_ERROR ("Failed to shut down appletviewer");
+ }
+ }
+ }
+
+ jvm_up = FALSE;
+ sleep(2); /* Needed to prevent crashes during debug (when JDWP port is not freed by the kernel right away) */
+
+ PLUGIN_DEBUG ("plugin_stop_appletviewer return\n");
+}
+
+static void appletviewer_monitor(GPid pid, gint status, gpointer data)
+{
+ PLUGIN_DEBUG ("appletviewer_monitor\n");
+ jvm_up = FALSE;
+ pid = -1;
+ PLUGIN_DEBUG ("appletviewer_monitor return\n");
+}
+
+static void
+plugin_data_destroy (NPP instance)
+{
+ PLUGIN_DEBUG ("plugin_data_destroy\n");
+
+ ITNPPluginData* tofree = (ITNPPluginData*) instance->pdata;
+
+ // Remove instance from map
+ gpointer id_ptr = g_hash_table_lookup(instance_to_id_map, instance);
+
+ if (id_ptr)
+ {
+ gint id = GPOINTER_TO_INT(id_ptr);
+ g_hash_table_remove(instance_to_id_map, instance);
+ g_hash_table_remove(id_to_instance_map, id_ptr);
+ }
+
+ tofree->window_handle = NULL;
+ tofree->window_height = 0;
+ tofree->window_width = 0;
+
+ // cleanup_appletviewer_mutex:
+ g_free (tofree->appletviewer_mutex);
+ tofree->appletviewer_mutex = NULL;
+
+ // cleanup_instance_string:
+ g_free (tofree->instance_id);
+ tofree->instance_id = NULL;
+
+ // cleanup applet tag
+ g_free (tofree->applet_tag);
+ tofree->applet_tag = NULL;
+
+ g_free(tofree->source);
+ tofree->source = NULL;
+
+ // cleanup_data:
+ // Eliminate back-pointer to plugin instance.
+ tofree->owner = NULL;
+ (*browser_functions.memfree) (tofree);
+ tofree = NULL;
+
+ PLUGIN_DEBUG ("plugin_data_destroy return\n");
+}
+
+// FACTORY FUNCTIONS
+
+// Provides the browser with pointers to the plugin functions that we
+// implement and initializes a local table with browser functions that
+// we may wish to call. Called once, after browser startup and before
+// the first plugin instance is created.
+// The field 'initialized' is set to true once this function has
+// finished. If 'initialized' is already true at the beginning of
+// this function, then it is evident that NP_Initialize has already
+// been called. There is no need to call this function more than once and
+// this workaround avoids any duplicate calls.
+NPError
+NP_Initialize (NPNetscapeFuncs* browserTable, NPPluginFuncs* pluginTable)
+{
+ PLUGIN_DEBUG ("NP_Initialize\n");
+
+ if (initialized)
+ return NPERR_NO_ERROR;
+ else if ((browserTable == NULL) || (pluginTable == NULL))
+ {
+ PLUGIN_ERROR ("Browser or plugin function table is NULL.");
+
+ return NPERR_INVALID_FUNCTABLE_ERROR;
+ }
+
+ // Ensure that the major version of the plugin API that the browser
+ // expects is not more recent than the major version of the API that
+ // we've implemented.
+ if ((browserTable->version >> 8) > NP_VERSION_MAJOR)
+ {
+ PLUGIN_ERROR ("Incompatible version.");
+
+ return NPERR_INCOMPATIBLE_VERSION_ERROR;
+ }
+
+ // Ensure that the plugin function table we've received is large
+ // enough to store the number of functions that we may provide.
+ if (pluginTable->size < sizeof (NPPluginFuncs))
+ {
+ PLUGIN_ERROR ("Invalid plugin function table.");
+
+ return NPERR_INVALID_FUNCTABLE_ERROR;
+ }
+
+ // Ensure that the browser function table is large enough to store
+ // the number of browser functions that we may use.
+ if (browserTable->size < sizeof (NPNetscapeFuncs))
+ {
+ fprintf (stderr, "ERROR: Invalid browser function table. Some functionality may be restricted.\n");
+ }
+
+ // Store in a local table the browser functions that we may use.
+ browser_functions.size = browserTable->size;
+ browser_functions.version = browserTable->version;
+ browser_functions.geturlnotify = browserTable->geturlnotify;
+ browser_functions.geturl = browserTable->geturl;
+ browser_functions.posturlnotify = browserTable->posturlnotify;
+ browser_functions.posturl = browserTable->posturl;
+ browser_functions.requestread = browserTable->requestread;
+ browser_functions.newstream = browserTable->newstream;
+ browser_functions.write = browserTable->write;
+ browser_functions.destroystream = browserTable->destroystream;
+ browser_functions.status = browserTable->status;
+ browser_functions.uagent = browserTable->uagent;
+ browser_functions.memalloc = browserTable->memalloc;
+ browser_functions.memfree = browserTable->memfree;
+ browser_functions.memflush = browserTable->memflush;
+ browser_functions.reloadplugins = browserTable->reloadplugins;
+ browser_functions.getJavaEnv = browserTable->getJavaEnv;
+ browser_functions.getJavaPeer = browserTable->getJavaPeer;
+ browser_functions.getvalue = browserTable->getvalue;
+ browser_functions.setvalue = browserTable->setvalue;
+ browser_functions.invalidaterect = browserTable->invalidaterect;
+ browser_functions.invalidateregion = browserTable->invalidateregion;
+ browser_functions.forceredraw = browserTable->forceredraw;
+ browser_functions.getstringidentifier = browserTable->getstringidentifier;
+ browser_functions.getstringidentifiers = browserTable->getstringidentifiers;
+ browser_functions.getintidentifier = browserTable->getintidentifier;
+ browser_functions.identifierisstring = browserTable->identifierisstring;
+ browser_functions.utf8fromidentifier = browserTable->utf8fromidentifier;
+ browser_functions.intfromidentifier = browserTable->intfromidentifier;
+ browser_functions.createobject = browserTable->createobject;
+ browser_functions.retainobject = browserTable->retainobject;
+ browser_functions.releaseobject = browserTable->releaseobject;
+ browser_functions.invoke = browserTable->invoke;
+ browser_functions.invokeDefault = browserTable->invokeDefault;
+ browser_functions.evaluate = browserTable->evaluate;
+ browser_functions.getproperty = browserTable->getproperty;
+ browser_functions.setproperty = browserTable->setproperty;
+ browser_functions.removeproperty = browserTable->removeproperty;
+ browser_functions.hasproperty = browserTable->hasproperty;
+ browser_functions.hasmethod = browserTable->hasmethod;
+ browser_functions.releasevariantvalue = browserTable->releasevariantvalue;
+ browser_functions.setexception = browserTable->setexception;
+ browser_functions.pluginthreadasynccall = browserTable->pluginthreadasynccall;
+#if MOZILLA_VERSION_COLLAPSED >= 1090100
+ browser_functions.getvalueforurl = browserTable->getvalueforurl;
+ browser_functions.setvalueforurl = browserTable->setvalueforurl;
+#endif
+
+ // Return to the browser the plugin functions that we implement.
+ pluginTable->version = (NP_VERSION_MAJOR << 8) + NP_VERSION_MINOR;
+ pluginTable->size = sizeof (NPPluginFuncs);
+
+#if MOZILLA_VERSION_COLLAPSED < 1090100
+ pluginTable->newp = NewNPP_NewProc (ITNP_New);
+ pluginTable->destroy = NewNPP_DestroyProc (ITNP_Destroy);
+ pluginTable->setwindow = NewNPP_SetWindowProc (ITNP_SetWindow);
+ pluginTable->newstream = NewNPP_NewStreamProc (ITNP_NewStream);
+ pluginTable->destroystream = NewNPP_DestroyStreamProc (ITNP_DestroyStream);
+ pluginTable->asfile = NewNPP_StreamAsFileProc (ITNP_StreamAsFile);
+ pluginTable->writeready = NewNPP_WriteReadyProc (ITNP_WriteReady);
+ pluginTable->write = NewNPP_WriteProc (ITNP_Write);
+ pluginTable->print = NewNPP_PrintProc (ITNP_Print);
+ pluginTable->urlnotify = NewNPP_URLNotifyProc (ITNP_URLNotify);
+ pluginTable->getvalue = NewNPP_GetValueProc (ITNP_GetValue);
+#else
+ pluginTable->newp = NPP_NewProcPtr (ITNP_New);
+ pluginTable->destroy = NPP_DestroyProcPtr (ITNP_Destroy);
+ pluginTable->setwindow = NPP_SetWindowProcPtr (ITNP_SetWindow);
+ pluginTable->newstream = NPP_NewStreamProcPtr (ITNP_NewStream);
+ pluginTable->destroystream = NPP_DestroyStreamProcPtr (ITNP_DestroyStream);
+ pluginTable->asfile = NPP_StreamAsFileProcPtr (ITNP_StreamAsFile);
+ pluginTable->writeready = NPP_WriteReadyProcPtr (ITNP_WriteReady);
+ pluginTable->write = NPP_WriteProcPtr (ITNP_Write);
+ pluginTable->print = NPP_PrintProcPtr (ITNP_Print);
+ pluginTable->urlnotify = NPP_URLNotifyProcPtr (ITNP_URLNotify);
+ pluginTable->getvalue = NPP_GetValueProcPtr (ITNP_GetValue);
+#endif
+
+ // Make sure the plugin data directory exists, creating it if
+ // necessary.
+ data_directory = g_strconcat (P_tmpdir, NULL);
+ if (!data_directory)
+ {
+ PLUGIN_ERROR ("Failed to create data directory name.");
+ return NPERR_OUT_OF_MEMORY_ERROR;
+ }
+ NPError np_error = NPERR_NO_ERROR;
+ gchar* filename = NULL;
+
+ // If P_tmpdir does not exist, try /tmp directly
+
+ if (!g_file_test (data_directory,
+ (GFileTest) (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)))
+ {
+ int file_error = 0;
+
+ data_directory = g_strconcat ("/tmp", NULL);
+ if (!data_directory)
+ {
+ PLUGIN_ERROR ("Failed to create data directory name.");
+ return NPERR_OUT_OF_MEMORY_ERROR;
+ }
+
+ }
+
+ data_directory = g_strconcat (data_directory, "/icedteaplugin-", getenv("USER"), NULL);
+
+ if (!data_directory)
+ {
+ PLUGIN_ERROR ("Failed to create data directory name.");
+ return NPERR_OUT_OF_MEMORY_ERROR;
+ }
+
+ // Now create a icedteaplugin subdir
+ if (!g_file_test (data_directory,
+ (GFileTest) (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)))
+ {
+ int file_error = 0;
+
+ file_error = g_mkdir (data_directory, 0700);
+ if (file_error != 0)
+ {
+ PLUGIN_ERROR_THREE ("Failed to create data directory",
+ data_directory,
+ strerror (errno));
+ np_error = NPERR_GENERIC_ERROR;
+ goto cleanup_data_directory;
+ }
+ }
+
+
+ // If data directory doesn't exit by this point, bail
+ if (!g_file_test (data_directory,
+ (GFileTest) (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)))
+ {
+ PLUGIN_ERROR_THREE ("Temp directory does not exist: ",
+ data_directory,
+ strerror (errno));
+
+ np_error = NPERR_GENERIC_ERROR;
+ goto cleanup_data_directory;
+
+ }
+
+ // Set appletviewer_executable.
+ Dl_info info;
+ int filename_size;
+ if (dladdr ((const void*) ITNP_New, &info) == 0)
+ {
+ PLUGIN_ERROR_TWO ("Failed to determine plugin shared object filename",
+ dlerror ());
+ np_error = NPERR_GENERIC_ERROR;
+ goto cleanup_data_directory;
+ }
+ filename = (gchar*) malloc(sizeof(gchar)*1024);
+ filename_size = readlink(info.dli_fname, filename, 1023);
+ if (filename_size >= 0)
+ {
+ filename[filename_size] = '\0';
+ }
+
+ if (!filename)
+ {
+ PLUGIN_ERROR ("Failed to create plugin shared object filename.");
+ np_error = NPERR_OUT_OF_MEMORY_ERROR;
+ goto cleanup_data_directory;
+ }
+
+ if (filename_size <= 0)
+ {
+ free(filename);
+ filename = g_strdup(info.dli_fname);
+ }
+
+ appletviewer_executable = g_strdup_printf ("%s/../../bin/java",
+ dirname (filename));
+ PLUGIN_DEBUG(".so is located at: %s and the link points to: %s. Executing java from dir %s to run %s\n", info.dli_fname, filename, dirname (filename), appletviewer_executable);
+ if (!appletviewer_executable)
+ {
+ PLUGIN_ERROR ("Failed to create appletviewer executable name.");
+ np_error = NPERR_OUT_OF_MEMORY_ERROR;
+ goto cleanup_filename;
+ }
+
+ np_error = plugin_test_appletviewer ();
+ if (np_error != NPERR_NO_ERROR)
+ {
+ plugin_display_failure_dialog ();
+ goto cleanup_appletviewer_executable;
+ }
+ g_free (filename);
+
+ initialized = true;
+
+ // Initialize threads (needed for mutexes).
+ if (!g_thread_supported ())
+ g_thread_init (NULL);
+
+ plugin_instance_mutex = g_mutex_new ();
+
+ PLUGIN_DEBUG ("NP_Initialize: using %s\n", appletviewer_executable);
+
+ PLUGIN_DEBUG ("NP_Initialize return\n");
+
+ plugin_req_proc = new PluginRequestProcessor();
+ java_req_proc = new JavaMessageSender();
+
+ java_to_plugin_bus = new MessageBus();
+ plugin_to_java_bus = new MessageBus();
+
+ java_to_plugin_bus->subscribe(plugin_req_proc);
+ plugin_to_java_bus->subscribe(java_req_proc);
+
+ pthread_create (&plugin_request_processor_thread1, NULL, &queue_processor, (void*) plugin_req_proc);
+ pthread_create (&plugin_request_processor_thread2, NULL, &queue_processor, (void*) plugin_req_proc);
+ pthread_create (&plugin_request_processor_thread3, NULL, &queue_processor, (void*) plugin_req_proc);
+
+ return NPERR_NO_ERROR;
+
+ cleanup_appletviewer_executable:
+ if (appletviewer_executable)
+ {
+ g_free (appletviewer_executable);
+ appletviewer_executable = NULL;
+ }
+
+ cleanup_filename:
+ if (filename)
+ {
+ g_free (filename);
+ filename = NULL;
+ }
+
+ cleanup_data_directory:
+ if (data_directory)
+ {
+ g_free (data_directory);
+ data_directory = NULL;
+ }
+
+
+ return np_error;
+}
+
+// Returns a string describing the MIME type that this plugin
+// handles.
+char*
+NP_GetMIMEDescription ()
+{
+ PLUGIN_DEBUG ("NP_GetMIMEDescription\n");
+
+ PLUGIN_DEBUG ("NP_GetMIMEDescription return\n");
+
+ return (char*) PLUGIN_MIME_DESC;
+}
+
+// Returns a value relevant to the plugin as a whole. The browser
+// calls this function to obtain information about the plugin.
+NPError
+NP_GetValue (void* future, NPPVariable variable, void* value)
+{
+ PLUGIN_DEBUG ("NP_GetValue\n");
+
+ NPError result = NPERR_NO_ERROR;
+ gchar** char_value = (gchar**) value;
+
+ switch (variable)
+ {
+ case NPPVpluginNameString:
+ PLUGIN_DEBUG ("NP_GetValue: returning plugin name.\n");
+ *char_value = g_strdup (PLUGIN_NAME);
+ break;
+
+ case NPPVpluginDescriptionString:
+ PLUGIN_DEBUG ("NP_GetValue: returning plugin description.\n");
+ *char_value = g_strdup (PLUGIN_DESC);
+ break;
+
+ default:
+ PLUGIN_ERROR ("Unknown plugin value requested.");
+ result = NPERR_GENERIC_ERROR;
+ break;
+ }
+
+ PLUGIN_DEBUG ("NP_GetValue return\n");
+
+ return result;
+}
+
+// Shuts down the plugin. Called after the last plugin instance is
+// destroyed.
+NPError
+NP_Shutdown (void)
+{
+ PLUGIN_DEBUG ("NP_Shutdown\n");
+
+ // Free mutex.
+ if (plugin_instance_mutex)
+ {
+ g_mutex_free (plugin_instance_mutex);
+ plugin_instance_mutex = NULL;
+ }
+
+ if (data_directory)
+ {
+ g_free (data_directory);
+ data_directory = NULL;
+ }
+
+ if (appletviewer_executable)
+ {
+ g_free (appletviewer_executable);
+ appletviewer_executable = NULL;
+ }
+
+ // stop the appletviewer
+ plugin_stop_appletviewer();
+
+ // remove monitor
+ if (appletviewer_watch_id != -1)
+ g_source_remove(appletviewer_watch_id);
+
+ // Removing a source is harmless if it fails since it just means the
+ // source has already been removed.
+ g_source_remove (in_watch_source);
+ in_watch_source = 0;
+
+ // cleanup_in_from_appletviewer:
+ if (in_from_appletviewer)
+ g_io_channel_unref (in_from_appletviewer);
+ in_from_appletviewer = NULL;
+
+ // cleanup_out_watch_source:
+ g_source_remove (out_watch_source);
+ out_watch_source = 0;
+
+ // cleanup_out_to_appletviewer:
+ if (out_to_appletviewer)
+ g_io_channel_unref (out_to_appletviewer);
+ out_to_appletviewer = NULL;
+
+ // cleanup_out_pipe:
+ // Delete output pipe.
+ PLUGIN_DEBUG ("NP_Shutdown: deleting output fifo: %s\n", out_pipe_name);
+ unlink (out_pipe_name);
+ PLUGIN_DEBUG ("NP_Shutdown: deleted output fifo: %s\n", out_pipe_name);
+
+ // cleanup_out_pipe_name:
+ g_free (out_pipe_name);
+ out_pipe_name = NULL;
+
+ // cleanup_in_pipe:
+ // Delete input pipe.
+ PLUGIN_DEBUG ("NP_Shutdown: deleting input fifo: %s\n", in_pipe_name);
+ unlink (in_pipe_name);
+ PLUGIN_DEBUG ("NP_Shutdown: deleted input fifo: %s\n", in_pipe_name);
+
+ // cleanup_in_pipe_name:
+ g_free (in_pipe_name);
+ in_pipe_name = NULL;
+
+ initialized = false;
+
+ pthread_cancel(plugin_request_processor_thread1);
+ pthread_cancel(plugin_request_processor_thread2);
+ pthread_cancel(plugin_request_processor_thread3);
+
+ java_to_plugin_bus->unSubscribe(plugin_req_proc);
+ plugin_to_java_bus->unSubscribe(java_req_proc);
+ //internal_bus->unSubscribe(java_req_proc);
+ //internal_bus->unSubscribe(plugin_req_proc);
+
+ delete plugin_req_proc;
+ delete java_req_proc;
+ delete java_to_plugin_bus;
+ delete plugin_to_java_bus;
+ //delete internal_bus;
+
+ PLUGIN_DEBUG ("NP_Shutdown return\n");
+
+ return NPERR_NO_ERROR;
+}
+
+NPObject*
+get_scriptable_object(NPP instance)
+{
+ NPObject* obj;
+ ITNPPluginData* data = (ITNPPluginData*) instance->pdata;
+
+ if (data->is_applet_instance) // dummy instance/package?
+ {
+ JavaRequestProcessor java_request = JavaRequestProcessor();
+ JavaResultData* java_result;
+ std::string instance_id = std::string();
+ std::string applet_class_id = std::string();
+
+ int id = get_id_from_instance(instance);
+ gchar* id_str = g_strdup_printf ("%d", id);
+
+ // Some browsers.. (e.g. chromium) don't call NPP_SetWindow
+ // for 0x0 plugins and therefore require initialization with
+ // a 0 handle
+ if (!data->window_handle)
+ {
+ data->window_handle = 0;
+ gchar *window_message = g_strdup_printf ("instance %s handle %d",
+ id_str, 0);
+ plugin_send_message_to_appletviewer (window_message);
+ g_free (window_message);
+ }
+
+ java_result = java_request.getAppletObjectInstance(id_str);
+
+ g_free(id_str);
+
+ if (java_result->error_occurred)
+ {
+ printf("Error: Unable to fetch applet instance id from Java side.\n");
+ return NULL;
+ }
+
+ instance_id.append(*(java_result->return_string));
+
+ java_result = java_request.getClassID(instance_id);
+
+ if (java_result->error_occurred)
+ {
+ printf("Error: Unable to fetch applet instance id from Java side.\n");
+ return NULL;
+ }
+
+ applet_class_id.append(*(java_result->return_string));
+
+ obj = IcedTeaScriptableJavaPackageObject::get_scriptable_java_object(instance, applet_class_id, instance_id, false);
+
+ } else
+ {
+ obj = IcedTeaScriptablePluginObject::get_scriptable_java_package_object(instance, "");
+ }
+
+ return obj;
+}
+
+NPObject*
+allocate_scriptable_object(NPP npp, NPClass *aClass)
+{
+ PLUGIN_DEBUG("Allocating new scriptable object\n");
+ return new IcedTeaScriptablePluginObject(npp);
+}
diff --git a/plugin/icedteanp/IcedTeaNPPlugin.h b/plugin/icedteanp/IcedTeaNPPlugin.h
new file mode 100644
index 0000000..18d1765
--- /dev/null
+++ b/plugin/icedteanp/IcedTeaNPPlugin.h
@@ -0,0 +1,136 @@
+/* IcedTeaNPPlugin.h
+
+ Copyright (C) 2009, 2010 Red Hat
+
+This file is part of IcedTea.
+
+IcedTea is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+IcedTea is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with IcedTea; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+#ifndef __ICEDTEANPPLUGIN_H__
+#define __ICEDTEANPPLUGIN_H__
+
+#if MOZILLA_VERSION_COLLAPSED < 1090100
+#include <nsThreadUtils.h>
+#else
+#include <npapi.h>
+#include <npruntime.h>
+#include <npfunctions.h>
+#endif
+
+// GLib includes.
+#include <glib.h>
+#include <glib/gstdio.h>
+
+// GTK includes.
+#include <gtk/gtk.h>
+
+#include "IcedTeaPluginUtils.h"
+#include "IcedTeaPluginRequestProcessor.h"
+
+// Work around across some chromium issues
+#define CHROMIUM_WORKAROUND
+
+// ITNPPluginData stores all the data associated with a single plugin
+// instance. A separate plugin instance is created for each <APPLET>
+// tag. For now, each plugin instance spawns its own applet viewer
+// process but this may need to change if we find pages containing
+// multiple applets that expect to be running in the same VM.
+struct ITNPPluginData
+{
+ // A unique identifier for this plugin window.
+ gchar* instance_id;
+ // The applet tag sent to Java side
+ gchar* applet_tag;
+ // Mutex to protect appletviewer_alive.
+ GMutex* appletviewer_mutex;
+ // Back-pointer to the plugin instance to which this data belongs.
+ // This should not be freed but instead simply set to NULL.
+ NPP owner;
+ // The address of the plugin window. This should not be freed but
+ // instead simply set to NULL.
+ gpointer window_handle;
+ // The last plugin window width sent to us by the browser.
+ guint32 window_width;
+ // The last plugin window height sent to us by the browser.
+ guint32 window_height;
+ // The source location for this instance
+ gchar* source;
+ // If this is an actual applet instance, or a dummy instance for static calls
+ bool is_applet_instance;
+};
+
+// Queue processing threads
+static pthread_t plugin_request_processor_thread1;
+static pthread_t plugin_request_processor_thread2;
+static pthread_t plugin_request_processor_thread3;
+
+// Condition on which the queue processor waits
+extern pthread_cond_t cond_message_available;
+
+// debug switch
+extern int plugin_debug;
+
+// Browser function table.
+extern NPNetscapeFuncs browser_functions;
+
+// messages to the java side
+extern MessageBus* plugin_to_java_bus;
+
+// messages from the java side
+extern MessageBus* java_to_plugin_bus;
+
+// internal messages (e.g ones that need processing in main thread)
+//extern MessageBus* internal_bus;
+
+// subscribes to plugin_to_java_bus and sends messages over the link
+extern JavaMessageSender java_request_processor;
+
+// processes requests made to the plugin
+extern PluginRequestProcessor plugin_request_processor;
+
+/* Given an instance pointer, return its id */
+void get_instance_from_id(int id, NPP& instance);
+
+/* Given an instance id, return its pointer */
+int get_id_from_instance(NPP instance);
+
+/* Sends a message to the appletviewer */
+void plugin_send_message_to_appletviewer(gchar const* message);
+
+/* Returns an appropriate (package/object) scriptable npobject */
+NPObject* get_scriptable_object(NPP instance);
+
+/* Creates a new scriptable plugin object and returns it */
+NPObject* allocate_scriptable_object(NPP npp, NPClass *aClass);
+
+#endif /* __ICEDTEANPPLUGIN_H__ */
diff --git a/plugin/icedteanp/IcedTeaPluginRequestProcessor.cc b/plugin/icedteanp/IcedTeaPluginRequestProcessor.cc
new file mode 100644
index 0000000..373be59
--- /dev/null
+++ b/plugin/icedteanp/IcedTeaPluginRequestProcessor.cc
@@ -0,0 +1,988 @@
+/* IcedTeaPluginRequestProcessor.cc
+
+ Copyright (C) 2009, 2010 Red Hat
+
+This file is part of IcedTea.
+
+IcedTea is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+IcedTea is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with IcedTea; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+#include <typeinfo>
+
+#include "IcedTeaScriptablePluginObject.h"
+#include "IcedTeaNPPlugin.h"
+#include "IcedTeaPluginRequestProcessor.h"
+
+/*
+ * This class processes requests made by Java. The requests include pointer
+ * information, script execution and variable get/set
+ */
+
+// Initialize static members used by the queue processing framework
+pthread_mutex_t message_queue_mutex = PTHREAD_MUTEX_INITIALIZER;
+pthread_mutex_t syn_write_mutex = PTHREAD_MUTEX_INITIALIZER;
+std::vector< std::vector<std::string*>* >* message_queue = new std::vector< std::vector<std::string*>* >();
+
+/**
+ * PluginRequestProcessor constructor.
+ *
+ * Initializes various complex data structures used by the class.
+ */
+
+PluginRequestProcessor::PluginRequestProcessor()
+{
+ this->pendingRequests = new std::map<pthread_t, uintmax_t>();
+
+ internal_req_ref_counter = 0;
+}
+
+/**
+ * PluginRequestProcessor destructor.
+ *
+ * Frees memory used by complex objects.
+ */
+
+PluginRequestProcessor::~PluginRequestProcessor()
+{
+ PLUGIN_DEBUG("PluginRequestProcessor::~PluginRequestProcessor\n");
+
+ if (pendingRequests)
+ delete pendingRequests;
+}
+
+/**
+ * Processes plugin (C++ side) requests from the Java side, and internally.
+ *
+ * @param message The message request to process
+ * @return boolean indicating whether the message is serviceable by this object
+ */
+
+bool
+PluginRequestProcessor::newMessageOnBus(const char* message)
+{
+ PLUGIN_DEBUG("PluginRequestProcessor processing %s\n", message);
+
+ std::string* type;
+ std::string* command;
+ int counter = 0;
+
+ std::vector<std::string*>* message_parts = IcedTeaPluginUtilities::strSplit(message, " ");
+
+ std::vector<std::string*>::iterator the_iterator;
+ the_iterator = message_parts->begin();
+
+ IcedTeaPluginUtilities::printStringPtrVector("PluginRequestProcessor::newMessageOnBus:", message_parts);
+
+ type = message_parts->at(0);
+ command = message_parts->at(4);
+
+ if (!type->find("instance"))
+ {
+ if (!command->find("GetWindow"))
+ {
+ // Window can be queried from the main thread only. And this call
+ // returns immediately, so we do it in the same thread.
+ this->sendWindow(message_parts);
+ return true;
+ } else if (!command->find("GetMember") ||
+ !command->find("SetMember") ||
+ !command->find("ToString") ||
+ !command->find("Call") ||
+ !command->find("GetSlot") ||
+ !command->find("SetSlot") ||
+ !command->find("Eval") ||
+ !command->find("Finalize"))
+ {
+
+ // Update queue synchronously
+ pthread_mutex_lock(&message_queue_mutex);
+ message_queue->push_back(message_parts);
+ pthread_mutex_unlock(&message_queue_mutex);
+
+ // Broadcast that a message is now available
+ pthread_cond_broadcast(&cond_message_available);
+
+ return true;
+ }
+
+ }
+
+ IcedTeaPluginUtilities::freeStringPtrVector(message_parts);
+
+ // If we got here, it means we couldn't process the message. Let the caller know.
+ return false;
+}
+
+/**
+ * Sends the window pointer to the Java side.
+ *
+ * @param message_parts The request message.
+ */
+
+void
+PluginRequestProcessor::sendWindow(std::vector<std::string*>* message_parts)
+{
+ std::string* type;
+ std::string* command;
+ int reference;
+ std::string response = std::string();
+ std::string window_ptr_str = std::string();
+ NPVariant* variant = new NPVariant();
+ static NPObject* window_ptr;
+ int id;
+
+ type = message_parts->at(0);
+ id = atoi(message_parts->at(1)->c_str());
+ reference = atoi(message_parts->at(3)->c_str());
+ command = message_parts->at(4);
+
+ NPP instance;
+ get_instance_from_id(id, instance);
+
+ browser_functions.getvalue(instance, NPNVWindowNPObject, &window_ptr);
+ PLUGIN_DEBUG("ID=%d, Instance=%p, WindowPTR = %p\n", id, instance, window_ptr);
+
+ OBJECT_TO_NPVARIANT(window_ptr, *variant);
+ browser_functions.retainobject(window_ptr);
+ IcedTeaPluginUtilities::JSIDToString(variant, &window_ptr_str);
+
+ // We need the context 0 for backwards compatibility with the Java side
+ IcedTeaPluginUtilities::constructMessagePrefix(0, reference, &response);
+ response += " JavaScriptGetWindow ";
+ response += window_ptr_str;
+
+ plugin_to_java_bus->post(response.c_str());
+
+ // store the instance pointer for future reference
+ IcedTeaPluginUtilities::storeInstanceID(variant, instance);
+}
+
+/**
+ * Evaluates the given script
+ *
+ * @param message_parts The request message.
+ */
+
+void
+PluginRequestProcessor::eval(std::vector<std::string*>* message_parts)
+{
+ JavaRequestProcessor request_processor = JavaRequestProcessor();
+ JavaResultData* java_result;
+
+ NPVariant* window_ptr;
+ NPP instance;
+ std::string script;
+ NPVariant result;
+ int reference;
+ std::string response = std::string();
+ std::string return_type = std::string();
+ int id;
+
+ reference = atoi(message_parts->at(3)->c_str());
+ window_ptr = (NPVariant*) IcedTeaPluginUtilities::stringToJSID(message_parts->at(5));
+ instance = IcedTeaPluginUtilities::getInstanceFromMemberPtr(window_ptr);
+
+ java_result = request_processor.getString(*(message_parts->at(6)));
+ CHECK_JAVA_RESULT(java_result);
+ script.append(*(java_result->return_string));
+
+ AsyncCallThreadData thread_data = AsyncCallThreadData();
+ thread_data.result_ready = false;
+ thread_data.parameters = std::vector<void*>();
+ thread_data.result = std::string();
+
+ thread_data.parameters.push_back(instance);
+ thread_data.parameters.push_back(NPVARIANT_TO_OBJECT(*window_ptr));
+ thread_data.parameters.push_back(&script);
+
+#ifdef CHROMIUM_WORKAROUND
+ // Workaround for chromium
+ _eval(&thread_data);
+
+ if (!thread_data.call_successful)
+ {
+#endif
+ thread_data.result_ready = false;
+ browser_functions.pluginthreadasynccall(instance, &_eval, &thread_data);
+
+ while (!thread_data.result_ready) usleep(2000); // Wait till result is ready
+#ifdef CHROMIUM_WORKAROUND
+ }
+#endif
+
+ NPVariant* result_variant = (NPVariant*) IcedTeaPluginUtilities::stringToJSID(thread_data.result);
+ std::string result_variant_jniid = std::string();
+ createJavaObjectFromVariant(instance, *result_variant, &result_variant_jniid);
+
+ IcedTeaPluginUtilities::constructMessagePrefix(0, reference, &response);
+ response += " JavaScriptEval ";
+ response += result_variant_jniid;
+
+ plugin_to_java_bus->post(response.c_str());
+}
+
+/**
+ * Calls the given javascript script
+ *
+ * @param message_parts The request message.
+ */
+
+void
+PluginRequestProcessor::call(std::vector<std::string*>* message_parts)
+{
+ NPP instance;
+ std::string* window_ptr_str;
+ NPVariant* window_ptr;
+ int reference;
+ std::string window_function_name;
+ std::vector<NPVariant> args = std::vector<NPVariant>();
+ std::vector<std::string> arg_ids = std::vector<std::string>();
+ int arg_count;
+ std::string response = std::string();
+ JavaRequestProcessor java_request = JavaRequestProcessor();
+ JavaResultData* java_result;
+
+ reference = atoi(message_parts->at(3)->c_str());
+
+ // window
+ window_ptr_str = message_parts->at(5);
+ window_ptr = (NPVariant*) IcedTeaPluginUtilities::stringToJSID(window_ptr_str);
+
+ // instance
+ instance = IcedTeaPluginUtilities::getInstanceFromMemberPtr(window_ptr);
+
+ // function name
+ java_result = java_request.getString(*(message_parts->at(6)));
+ CHECK_JAVA_RESULT(java_result);
+ window_function_name.append(*(java_result->return_string));
+
+ // arguments
+ for (int i=7; i < message_parts->size(); i++)
+ {
+ arg_ids.push_back(*(message_parts->at(i)));
+ }
+
+ // determine arguments
+ for (int i=0; i < arg_ids.size(); i++)
+ {
+ NPVariant* variant = new NPVariant();
+ java_result = java_request.getValue(arg_ids[i]);
+ CHECK_JAVA_RESULT(java_result);
+
+ IcedTeaPluginUtilities::javaResultToNPVariant(instance, java_result->return_string, variant);
+
+ args.push_back(*variant);
+ }
+
+ arg_count = args.size();
+ NPVariant *args_array = (NPVariant*) malloc(sizeof(NPVariant)*args.size());
+ for (int i=0; i < args.size(); i++)
+ args_array[i] = args[i];
+
+ AsyncCallThreadData thread_data = AsyncCallThreadData();
+ thread_data.result_ready = false;
+ thread_data.parameters = std::vector<void*>();
+ thread_data.result = std::string();
+
+ thread_data.parameters.push_back(instance);
+ thread_data.parameters.push_back(NPVARIANT_TO_OBJECT(*window_ptr));
+ thread_data.parameters.push_back(&window_function_name);
+ thread_data.parameters.push_back(&arg_count);
+ thread_data.parameters.push_back(args_array);
+
+#ifdef CHROMIUM_WORKAROUND
+ // Workaround for chromium
+ _call(&thread_data);
+
+ if (!thread_data.call_successful)
+ {
+#endif
+ thread_data.result_ready = false;
+ browser_functions.pluginthreadasynccall(instance, &_call, &thread_data);
+
+ while (!thread_data.result_ready) usleep(2000); // wait till ready
+#ifdef CHROMIUM_WORKAROUND
+ }
+#endif
+
+ NPVariant* result_variant = (NPVariant*) IcedTeaPluginUtilities::stringToJSID(thread_data.result);
+ std::string result_variant_jniid = std::string();
+
+ if (result_variant)
+ {
+ createJavaObjectFromVariant(instance, *result_variant, &result_variant_jniid);
+ } else
+ {
+ result_variant_jniid = "0";
+ }
+
+ IcedTeaPluginUtilities::constructMessagePrefix(0, reference, &response);
+ response += " JavaScriptCall ";
+ response += result_variant_jniid;
+
+ plugin_to_java_bus->post(response.c_str());
+
+ cleanup:
+ free(args_array);
+}
+
+/**
+ * Sends the string value of the requested variable
+ *
+ * @param message_parts The request message.
+ */
+void
+PluginRequestProcessor::sendString(std::vector<std::string*>* message_parts)
+{
+ std::string variant_ptr;
+ NPVariant* variant;
+ JavaRequestProcessor java_request = JavaRequestProcessor();
+ JavaResultData* java_result;
+ int reference;
+ std::string response = std::string();
+
+ reference = atoi(message_parts->at(3)->c_str());
+ variant_ptr = *(message_parts->at(5));
+
+ variant = (NPVariant*) IcedTeaPluginUtilities::stringToJSID(variant_ptr);
+ AsyncCallThreadData thread_data = AsyncCallThreadData();
+ thread_data.result_ready = false;
+ thread_data.parameters = std::vector<void*>();
+ thread_data.result = std::string();
+
+ NPP instance = IcedTeaPluginUtilities::getInstanceFromMemberPtr(variant);
+ thread_data.parameters.push_back(instance);
+ thread_data.parameters.push_back(variant);
+
+#ifdef CHROMIUM_WORKAROUND
+ // Workaround for chromium
+ _getString(&thread_data);
+
+ if (!thread_data.call_successful)
+ {
+#endif
+ thread_data.result_ready = false;
+ browser_functions.pluginthreadasynccall(instance, &_getString, &thread_data);
+ while (!thread_data.result_ready) usleep(2000); // wait till ready
+#ifdef CHROMIUM_WORKAROUND
+ }
+#endif
+
+ // We need the context 0 for backwards compatibility with the Java side
+ IcedTeaPluginUtilities::constructMessagePrefix(0, reference, &response);
+ response += " JavaScriptToString ";
+ response += thread_data.result;
+
+ plugin_to_java_bus->post(response.c_str());
+
+ cleanup:
+
+ pthread_mutex_lock(&tc_mutex);
+ thread_count--;
+ pthread_mutex_unlock(&tc_mutex);
+}
+
+/**
+ * Sets variable to given value
+ *
+ * @param message_parts The request message.
+ */
+
+void
+PluginRequestProcessor::setMember(std::vector<std::string*>* message_parts)
+{
+ std::string propertyNameID;
+ std::string value = std::string();
+ std::string response = std::string();
+ int reference;
+
+ NPP instance;
+ NPVariant* member;
+ NPIdentifier property_identifier;
+
+ JavaRequestProcessor java_request = JavaRequestProcessor();
+ JavaResultData* java_result;
+
+ IcedTeaPluginUtilities::printStringPtrVector("PluginRequestProcessor::_setMember - ", message_parts);
+
+ reference = atoi(message_parts->at(3)->c_str());
+
+ member = (NPVariant*) (IcedTeaPluginUtilities::stringToJSID(*(message_parts->at(5))));
+ propertyNameID = *(message_parts->at(6));
+
+ if (*(message_parts->at(7)) == "literalreturn")
+ {
+ value.append(*(message_parts->at(7)));
+ value.append(" ");
+ value.append(*(message_parts->at(8)));
+ } else
+ {
+ value.append(*(message_parts->at(7)));
+ }
+
+ instance = IcedTeaPluginUtilities::getInstanceFromMemberPtr(member);
+
+ if (*(message_parts->at(4)) == "SetSlot")
+ {
+ property_identifier = browser_functions.getintidentifier(atoi(message_parts->at(6)->c_str()));
+ } else
+ {
+ java_result = java_request.getString(propertyNameID);
+
+ // the result we want is in result_string (assuming there was no error)
+ if (java_result->error_occurred)
+ {
+ printf("Unable to get member name for setMember. Error occurred: %s\n", java_result->error_msg);
+ //goto cleanup;
+ }
+
+ property_identifier = browser_functions.getstringidentifier(java_result->return_string->c_str());
+ }
+
+ AsyncCallThreadData thread_data = AsyncCallThreadData();
+ thread_data.result_ready = false;
+ thread_data.parameters = std::vector<void*>();
+ thread_data.result = std::string();
+
+ thread_data.parameters.push_back(instance);
+ thread_data.parameters.push_back(NPVARIANT_TO_OBJECT(*member));
+ thread_data.parameters.push_back(&property_identifier);
+ thread_data.parameters.push_back(&value);
+
+#ifdef CHROMIUM_WORKAROUND
+ // Workaround for chromium
+ _setMember(&thread_data);
+
+ if (!thread_data.call_successful)
+ {
+#endif
+ thread_data.result_ready = false;
+ browser_functions.pluginthreadasynccall(instance, &_setMember, &thread_data);
+
+ while (!thread_data.result_ready) usleep(2000); // wait till ready
+#ifdef CHROMIUM_WORKAROUND
+ }
+#endif
+
+ IcedTeaPluginUtilities::constructMessagePrefix(0, reference, &response);
+ response.append(" JavaScriptSetMember ");
+ plugin_to_java_bus->post(response.c_str());
+
+ cleanup:
+
+ // property_name, type and value are deleted by _setMember
+ pthread_mutex_lock(&tc_mutex);
+ thread_count--;
+ pthread_mutex_unlock(&tc_mutex);
+}
+
+/**
+ * Sends request member pointer to the Java side.
+ *
+ * This is a static function, called in another thread. Since certain data
+ * can only be requested from the main thread in Mozilla, this function
+ * does whatever it can seperately, and then makes an internal request that
+ * causes _sendMember to do the rest of the work.
+ *
+ * @param message_parts The request message
+ */
+
+void
+PluginRequestProcessor::sendMember(std::vector<std::string*>* message_parts)
+{
+ // member initialization
+ std::vector<std::string> args;
+ JavaRequestProcessor java_request = JavaRequestProcessor();
+ JavaResultData* java_result;
+ NPVariant* parent_ptr;
+
+ //int reference;
+ std::string member_id = std::string();
+ std::string jsObjectClassID = std::string();
+ std::string jsObjectConstructorID = std::string();
+ std::string response = std::string();
+
+ NPIdentifier member_identifier;
+
+ int method_id;
+ int instance_id;
+ int reference;
+
+ // debug printout of parent thread data
+ IcedTeaPluginUtilities::printStringPtrVector("PluginRequestProcessor::getMember:", message_parts);
+
+ reference = atoi(message_parts->at(3)->c_str());
+
+ // store info in local variables for easy access
+ instance_id = atoi(message_parts->at(1)->c_str());
+ parent_ptr = (NPVariant*) (IcedTeaPluginUtilities::stringToJSID(message_parts->at(5)));
+ member_id.append(*(message_parts->at(6)));
+
+ /** Request data from Java if necessary **/
+ if (*(message_parts->at(4)) == "GetSlot")
+ {
+ member_identifier = browser_functions.getintidentifier(atoi(member_id.c_str()));
+ } else
+ {
+ // make a new request for getString, to get the name of the identifier
+ java_result = java_request.getString(member_id);
+
+ // the result we want is in result_string (assuming there was no error)
+ if (java_result->error_occurred)
+ {
+ printf("Unable to process getMember request. Error occurred: %s\n", java_result->error_msg);
+ //goto cleanup;
+ }
+
+ member_identifier = browser_functions.getstringidentifier(java_result->return_string->c_str());
+ }
+
+ AsyncCallThreadData thread_data = AsyncCallThreadData();
+ thread_data.result_ready = false;
+ thread_data.parameters = std::vector<void*>();
+ thread_data.result = std::string();
+
+ NPP instance = IcedTeaPluginUtilities::getInstanceFromMemberPtr(parent_ptr);
+ thread_data.parameters.push_back(instance);
+ thread_data.parameters.push_back(NPVARIANT_TO_OBJECT(*parent_ptr));
+ thread_data.parameters.push_back(&member_identifier);
+
+#ifdef CHROMIUM_WORKAROUND
+ // Workaround for chromium
+ _getMember(&thread_data);
+
+ if (!thread_data.call_successful)
+ {
+#endif
+ thread_data.result_ready = false;
+ browser_functions.pluginthreadasynccall(instance, &_getMember, &thread_data);
+
+ while (!thread_data.result_ready) usleep(2000); // wait till ready
+
+#ifdef CHROMIUM_WORKAROUND
+ }
+#endif
+
+ PLUGIN_DEBUG("Member PTR after internal request: %s\n", thread_data.result.c_str());
+
+ java_result = java_request.findClass(0, "netscape.javascript.JSObject");
+
+ // the result we want is in result_string (assuming there was no error)
+ if (java_result->error_occurred)
+ {
+ printf("Unable to process getMember request. Error occurred: %s\n", java_result->error_msg);
+ //goto cleanup;
+ }
+
+ jsObjectClassID.append(*(java_result->return_string));
+
+ args = std::vector<std::string>();
+ std::string longArg = "J";
+ args.push_back(longArg);
+
+ java_result = java_request.getMethodID(jsObjectClassID,
+ browser_functions.getstringidentifier("<init>"),
+ args);
+
+ // the result we want is in result_string (assuming there was no error)
+ if (java_result->error_occurred)
+ {
+ printf("Unable to process getMember request. Error occurred: %s\n", java_result->error_msg);
+ //goto cleanup;
+ }
+
+ jsObjectConstructorID.append(*(java_result->return_string));
+
+ // We have the method id. Now create a new object.
+
+ args.clear();
+ args.push_back(thread_data.result);
+ java_result = java_request.newObjectWithConstructor("",
+ jsObjectClassID,
+ jsObjectConstructorID,
+ args);
+
+ // the result we want is in result_string (assuming there was no error)
+ if (java_result->error_occurred)
+ {
+ printf("Unable to process getMember request. Error occurred: %s\n", java_result->error_msg);
+ //goto cleanup;
+ }
+
+
+ IcedTeaPluginUtilities::constructMessagePrefix(0, reference, &response);
+ if (*(message_parts->at(2)) == "GetSlot")
+ {
+ response.append(" JavaScriptGetMember ");
+ } else {
+ response.append(" JavaScriptGetSlot ");
+ }
+ response.append(java_result->return_string->c_str());
+ plugin_to_java_bus->post(response.c_str());
+
+
+ // Now be a good citizen and help keep the heap free of garbage
+ cleanup:
+
+ pthread_mutex_lock(&tc_mutex);
+ thread_count--;
+ pthread_mutex_unlock(&tc_mutex);
+}
+
+/**
+ * Decrements reference count to given object
+ *
+ * @param message_parts The request message.
+ */
+
+void
+PluginRequestProcessor::finalize(std::vector<std::string*>* message_parts)
+{
+ std::string* type;
+ std::string* command;
+ int reference;
+ std::string response = std::string();
+ std::string* variant_ptr_str;
+ NPVariant* variant_ptr;
+ NPObject* window_ptr;
+ int id;
+
+ type = message_parts->at(0);
+ id = atoi(message_parts->at(1)->c_str());
+ reference = atoi(message_parts->at(3)->c_str());
+ variant_ptr_str = message_parts->at(5);
+
+ NPP instance;
+ get_instance_from_id(id, instance);
+
+ variant_ptr = (NPVariant*) IcedTeaPluginUtilities::stringToJSID(variant_ptr_str);
+ window_ptr = NPVARIANT_TO_OBJECT(*variant_ptr);
+ browser_functions.releaseobject(window_ptr);
+
+ // remove reference
+ IcedTeaPluginUtilities::removeInstanceID(variant_ptr);
+
+ // clear memory
+ free(variant_ptr);
+
+ // We need the context 0 for backwards compatibility with the Java side
+ IcedTeaPluginUtilities::constructMessagePrefix(0, reference, &response);
+ response += " JavaScriptFinalize";
+
+ plugin_to_java_bus->post(response.c_str());
+}
+
+
+void*
+queue_processor(void* data)
+{
+
+ PluginRequestProcessor* processor = (PluginRequestProcessor*) data;
+ std::vector<std::string*>* message_parts = NULL;
+ std::string command;
+ pthread_mutex_t wait_mutex = PTHREAD_MUTEX_INITIALIZER; // This is needed for API compat. and is unused
+
+ PLUGIN_DEBUG("Queue processor initialized. Queue = %p\n", message_queue);
+
+ while (true)
+ {
+ pthread_mutex_lock(&message_queue_mutex);
+ if (message_queue->size() > 0)
+ {
+ message_parts = message_queue->front();
+ message_queue->erase(message_queue->begin());
+ }
+ pthread_mutex_unlock(&message_queue_mutex);
+
+ if (message_parts)
+ {
+ command = *(message_parts->at(4));
+
+ if (command == "GetMember")
+ {
+ processor->sendMember(message_parts);
+ } else if (command == "ToString")
+ {
+ processor->sendString(message_parts);
+ } else if (command == "SetMember")
+ {
+ // write methods are synchronized
+ pthread_mutex_lock(&syn_write_mutex);
+ processor->setMember(message_parts);
+ pthread_mutex_unlock(&syn_write_mutex);
+ } else if (command == "Call")
+ {
+ // write methods are synchronized
+ pthread_mutex_lock(&syn_write_mutex);
+ processor->call(message_parts);
+ pthread_mutex_unlock(&syn_write_mutex);
+ } else if (command == "Eval")
+ {
+ // write methods are synchronized
+ pthread_mutex_lock(&syn_write_mutex);
+ processor->eval(message_parts);
+ pthread_mutex_unlock(&syn_write_mutex);
+ } else if (command == "GetSlot")
+ {
+ // write methods are synchronized
+ pthread_mutex_lock(&syn_write_mutex);
+ processor->sendMember(message_parts);
+ pthread_mutex_unlock(&syn_write_mutex);
+ } else if (command == "SetSlot")
+ {
+ // write methods are synchronized
+ pthread_mutex_lock(&syn_write_mutex);
+ processor->setMember(message_parts);
+ pthread_mutex_unlock(&syn_write_mutex);
+ } else if (command == "Finalize")
+ {
+ // write methods are synchronized
+ pthread_mutex_lock(&syn_write_mutex);
+ processor->finalize(message_parts);
+ pthread_mutex_unlock(&syn_write_mutex);
+ } else
+ {
+ // Nothing matched
+ IcedTeaPluginUtilities::printStringPtrVector("Error: Unable to process message: ", message_parts);
+ }
+
+ // Free memory for message_parts
+ IcedTeaPluginUtilities::freeStringPtrVector(message_parts);
+
+ } else
+ {
+ pthread_cond_wait(&cond_message_available, &wait_mutex);
+ pthread_testcancel();
+ }
+
+ message_parts = NULL;
+ }
+
+ PLUGIN_DEBUG("Queue processing stopped.\n");
+}
+
+/******************************************
+ * Functions delegated to the main thread *
+ ******************************************/
+
+void
+_setMember(void* data)
+{
+ std::string* value;
+
+ NPP instance;
+ NPVariant value_variant = NPVariant();
+ NPObject* member;
+ NPIdentifier* property;
+
+ std::vector<void*> parameters = ((AsyncCallThreadData*) data)->parameters;
+ instance = (NPP) parameters.at(0);
+ member = (NPObject*) parameters.at(1);
+ property = (NPIdentifier*) parameters.at(2);
+ value = (std::string*) parameters.at(3);
+
+ PLUGIN_DEBUG("Setting %s on instance %p, object %p to value %s\n", browser_functions.utf8fromidentifier(*property), instance, member, value->c_str());
+
+ IcedTeaPluginUtilities::javaResultToNPVariant(instance, value, &value_variant);
+
+ ((AsyncCallThreadData*) data)->call_successful = browser_functions.setproperty(instance, member, *property, &value_variant);
+
+ ((AsyncCallThreadData*) data)->result_ready = true;
+}
+
+void
+_getMember(void* data)
+{
+ NPObject* parent_ptr;
+ NPVariant* member_ptr = new NPVariant();
+ std::string member_ptr_str = std::string();
+ NPP instance;
+
+ std::vector<void*> parameters = ((AsyncCallThreadData*) data)->parameters;
+
+ instance = (NPP) parameters.at(0);
+ parent_ptr = (NPObject*) parameters.at(1);
+ NPIdentifier* member_identifier = (NPIdentifier*) parameters.at(2);
+
+ // Get the NPVariant corresponding to this member
+ PLUGIN_DEBUG("Looking for %p %p %p (%s)\n", instance, parent_ptr, member_identifier, browser_functions.utf8fromidentifier(*member_identifier));
+
+ if (!browser_functions.hasproperty(instance, parent_ptr, *member_identifier))
+ {
+ printf("%s not found!\n", browser_functions.utf8fromidentifier(*member_identifier));
+ }
+ ((AsyncCallThreadData*) data)->call_successful = browser_functions.getproperty(instance, parent_ptr, *member_identifier, member_ptr);
+
+ IcedTeaPluginUtilities::printNPVariant(*member_ptr);
+
+ if (((AsyncCallThreadData*) data)->call_successful)
+ {
+ IcedTeaPluginUtilities::JSIDToString(member_ptr, &member_ptr_str);
+ ((AsyncCallThreadData*) data)->result.append(member_ptr_str);
+ }
+ ((AsyncCallThreadData*) data)->result_ready = true;
+
+ // store member -> instance link
+ IcedTeaPluginUtilities::storeInstanceID(member_ptr, instance);
+
+ PLUGIN_DEBUG("_getMember returning.\n");
+}
+
+void
+_eval(void* data)
+{
+ NPP instance;
+ NPObject* window_ptr;
+ std::string* script_str;
+ NPIdentifier script_identifier;
+ NPString script = NPString();
+ NPVariant* eval_result = new NPVariant();
+ std::string eval_result_ptr_str = std::string();
+
+ PLUGIN_DEBUG("_eval called\n");
+
+ std::vector<void*>* call_data = (std::vector<void*>*) data;
+
+ instance = (NPP) call_data->at(0);
+ window_ptr = (NPObject*) call_data->at(1);
+ script_str = (std::string*) call_data->at(2);
+
+#if MOZILLA_VERSION_COLLAPSED < 1090200
+ script.utf8characters = script_str->c_str();
+ script.utf8length = script_str->size();
+
+ PLUGIN_DEBUG("Evaluating: %s\n", script.utf8characters);
+#else
+ script.UTF8Characters = script_str->c_str();
+ script.UTF8Length = script_str->size();
+
+ PLUGIN_DEBUG("Evaluating: %s\n", script.UTF8Characters);
+#endif
+
+ ((AsyncCallThreadData*) data)->call_successful = browser_functions.evaluate(instance, window_ptr, &script, eval_result);
+ IcedTeaPluginUtilities::printNPVariant(*eval_result);
+
+ if (((AsyncCallThreadData*) data)->call_successful)
+ {
+ IcedTeaPluginUtilities::JSIDToString(eval_result, &eval_result_ptr_str);
+ ((AsyncCallThreadData*) data)->result.append(eval_result_ptr_str);
+ }
+ ((AsyncCallThreadData*) data)->result_ready = true;
+
+ PLUGIN_DEBUG("_eval returning\n");
+}
+
+
+void
+_call(void* data)
+{
+ NPP instance;
+ NPObject* window_ptr;
+ std::string* function_name;
+ NPIdentifier function;
+ int* arg_count;
+ NPVariant* args;
+ NPVariant* call_result = new NPVariant();
+ std::string call_result_ptr_str = std::string();
+
+ PLUGIN_DEBUG("_call called\n");
+
+ std::vector<void*>* call_data = (std::vector<void*>*) data;
+
+ instance = (NPP) call_data->at(0);
+ window_ptr = (NPObject*) call_data->at(1);
+ function_name = (std::string*) call_data->at(2);
+
+ function = browser_functions.getstringidentifier(function_name->c_str());
+ arg_count = (int*) call_data->at(3);
+ args = (NPVariant*) call_data->at(4);
+
+ for (int i=0; i < *arg_count; i++) {
+ IcedTeaPluginUtilities::printNPVariant(args[i]);
+ }
+
+ PLUGIN_DEBUG("_calling\n");
+ ((AsyncCallThreadData*) data)->call_successful = browser_functions.invoke(instance, window_ptr, function, args, *arg_count, call_result);
+ PLUGIN_DEBUG("_called\n");
+
+ IcedTeaPluginUtilities::printNPVariant(*call_result);
+
+ if (((AsyncCallThreadData*) data)->call_successful)
+ {
+ IcedTeaPluginUtilities::JSIDToString(call_result, &call_result_ptr_str);
+ ((AsyncCallThreadData*) data)->result.append(call_result_ptr_str);
+ }
+
+ ((AsyncCallThreadData*) data)->result_ready = true;
+
+ PLUGIN_DEBUG("_call returning\n");
+}
+
+void
+_getString(void* data)
+{
+ NPP instance;
+ NPObject* object;
+ NPIdentifier toString = browser_functions.getstringidentifier("toString");
+ NPVariant tostring_result;
+ std::string result = std::string();
+
+ std::vector<void*>* call_data = (std::vector<void*>*) data;
+ instance = (NPP) call_data->at(0);
+ NPVariant* variant = (NPVariant*) call_data->at(1);
+
+ PLUGIN_DEBUG("_getString called with %p and %p\n", instance, variant);
+
+ if (NPVARIANT_IS_OBJECT(*variant))
+ {
+ ((AsyncCallThreadData*) data)->call_successful = browser_functions.invoke(instance, NPVARIANT_TO_OBJECT(*variant), toString, NULL, 0, &tostring_result);
+ }
+ else
+ {
+ IcedTeaPluginUtilities::NPVariantToString(*variant, &result);
+ tostring_result = NPVariant();
+ STRINGZ_TO_NPVARIANT(result.c_str(), tostring_result);
+ ((AsyncCallThreadData*) data)->call_successful = true;
+ }
+
+ PLUGIN_DEBUG("ToString result: ");
+ IcedTeaPluginUtilities::printNPVariant(tostring_result);
+
+ if (((AsyncCallThreadData*) data)->call_successful)
+ {
+ createJavaObjectFromVariant(instance, tostring_result, &(((AsyncCallThreadData*) data)->result));
+ }
+ ((AsyncCallThreadData*) data)->result_ready = true;
+
+ PLUGIN_DEBUG("_getString returning\n");
+}
+
diff --git a/plugin/icedteanp/IcedTeaPluginRequestProcessor.h b/plugin/icedteanp/IcedTeaPluginRequestProcessor.h
new file mode 100644
index 0000000..4d31248
--- /dev/null
+++ b/plugin/icedteanp/IcedTeaPluginRequestProcessor.h
@@ -0,0 +1,146 @@
+/* IcedTeaPluginRequestProcessor.h
+
+ Copyright (C) 2009, 2010 Red Hat
+
+This file is part of IcedTea.
+
+IcedTea is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+IcedTea is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with IcedTea; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+#ifndef __ICEDTEAPLUGINREQUESTPROCESSOR_H__
+#define __ICEDTEAPLUGINREQUESTPROCESSOR_H__
+
+#include <map>
+#include <stdio.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include <time.h>
+
+#include <npapi.h>
+
+#if MOZILLA_VERSION_COLLAPSED < 1090100
+#include <npupp.h>
+#else
+#include <npapi.h>
+#include <npruntime.h>
+#endif
+
+#include "IcedTeaPluginUtils.h"
+#include "IcedTeaJavaRequestProcessor.h"
+
+/**
+ * Data structure passed to functions called in a new thread.
+ */
+
+typedef struct async_call_thread_data
+{
+ std::vector<void*> parameters;
+ std::string result;
+ bool result_ready;
+ bool call_successful;
+} AsyncCallThreadData;
+
+/* Internal request reference counter */
+static long internal_req_ref_counter;
+
+/* Given a value and type, performs the appropriate Java->JS type
+ * mapping and puts it in the given variant */
+
+static void convertToNPVariant(std::string value, std::string type, NPVariant* result_variant);
+
+// Internal methods that need to run in main thread
+void _getMember(void* data);
+void _setMember(void* data);
+void _call(void* data);
+void _eval(void* data);
+void _getString(void* data);
+
+static pthread_mutex_t tc_mutex = PTHREAD_MUTEX_INITIALIZER;
+static int thread_count = 0;
+
+void* queue_processor(void* data);
+
+/* Mutex to ensure that the request queue is accessed synchronously */
+extern pthread_mutex_t message_queue_mutex;
+
+/* Mutex to ensure synchronized writes */
+extern pthread_mutex_t syn_write_mutex;
+
+/* Queue for holding messages that get processed in a separate thread */
+extern std::vector< std::vector<std::string*>* >* message_queue;
+
+/**
+ * Processes requests made TO the plugin (by java or anyone else)
+ */
+class PluginRequestProcessor : public BusSubscriber
+{
+ private:
+
+ /* Requests that are still pending */
+ std::map<pthread_t, uintmax_t>* pendingRequests;
+
+ /* Dispatch request processing to a new thread for asynch. processing */
+ void dispatch(void* func_ptr (void*), std::vector<std::string>* message, std::string* src);
+
+ /* Send main window pointer to Java */
+ void sendWindow(std::vector<std::string*>* message_parts);
+
+ /* Stores the variant on java side */
+ void storeVariantInJava(NPVariant variant, std::string* result);
+
+ public:
+ PluginRequestProcessor(); /* Constructor */
+ ~PluginRequestProcessor(); /* Destructor */
+
+ /* Process new requests (if applicable) */
+ virtual bool newMessageOnBus(const char* message);
+
+ /* Send member ID to Java */
+ void sendMember(std::vector<std::string*>* message_parts);
+
+ /* Set member to given value */
+ void setMember(std::vector<std::string*>* message_parts);
+
+ /* Send string value of requested object */
+ void sendString(std::vector<std::string*>* message_parts);
+
+ /* Evaluate the given script */
+ void eval(std::vector<std::string*>* message_parts);
+
+ /* Evaluate the given script */
+ void call(std::vector<std::string*>* message_parts);
+
+ /* Decrements reference count for given object */
+ void finalize(std::vector<std::string*>* message_parts);
+};
+
+#endif // __ICEDTEAPLUGINREQUESTPROCESSOR_H__
diff --git a/plugin/icedteanp/IcedTeaPluginUtils.cc b/plugin/icedteanp/IcedTeaPluginUtils.cc
new file mode 100644
index 0000000..501cd32
--- /dev/null
+++ b/plugin/icedteanp/IcedTeaPluginUtils.cc
@@ -0,0 +1,1047 @@
+/* IcedTeaPluginUtils.cc
+
+ Copyright (C) 2009, 2010 Red Hat
+
+This file is part of IcedTea.
+
+IcedTea is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+IcedTea is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with IcedTea; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+#include "IcedTeaNPPlugin.h"
+#include "IcedTeaScriptablePluginObject.h"
+#include "IcedTeaPluginUtils.h"
+
+/**
+ * Misc. utility functions used by the plugin
+ */
+
+/***********************************************
+ * Begin IcedTeaPluginUtilities implementation *
+************************************************/
+
+// Initialize static variables
+int IcedTeaPluginUtilities::reference = -1;
+pthread_mutex_t IcedTeaPluginUtilities::reference_mutex = PTHREAD_MUTEX_INITIALIZER;
+std::map<void*, NPP>* IcedTeaPluginUtilities::instance_map = new std::map<void*, NPP>();
+std::map<std::string, NPObject*>* IcedTeaPluginUtilities::object_map = new std::map<std::string, NPObject*>();
+
+/**
+ * Given a context number, constructs a message prefix to send to Java
+ *
+ * @param context The context of the request
+ * @return The string prefix (allocated on heap)
+ */
+
+void
+IcedTeaPluginUtilities::constructMessagePrefix(int context, std::string *result)
+{
+ std::string context_str = std::string();
+
+ itoa(context, &context_str);
+
+ result->append("context ");
+ result->append(context_str);
+ result->append(" reference -1");
+
+}
+
+/**
+ * Given a context number, and reference number, constructs a message prefix to
+ * send to Java
+ *
+ * @param context The context of the request
+ * @param rerefence The reference number of the request
+ * @param result The message
+ */
+
+void
+IcedTeaPluginUtilities::constructMessagePrefix(int context, int reference, std::string* result)
+{
+ // Until security is implemented, use file:// source for _everything_
+
+ std::string context_str = std::string();
+ std::string reference_str = std::string();
+
+ itoa(context, &context_str);
+ itoa(reference, &reference_str);
+
+ *result += "context ";
+ result->append(context_str);
+ *result += " reference ";
+ result->append(reference_str);
+}
+
+/**
+ * Given a context number, reference number, and source location, constructs
+ * a message prefix to send to Java
+ *
+ * @param context The context of the request
+ * @param rerefence The reference number of the request
+ * @param address The address for the script that made the request
+ * @param result The message
+ */
+
+void
+IcedTeaPluginUtilities::constructMessagePrefix(int context, int reference,
+ std::string address,
+ std::string* result)
+{
+ std::string context_str = std::string();
+ std::string reference_str = std::string();
+
+ itoa(context, &context_str);
+ itoa(reference, &reference_str);
+
+ *result += "context ";
+ result->append(context_str);
+ *result += " reference ";
+ result->append(reference_str);
+
+ if (address.length() > 0)
+ {
+ *result += " src ";
+ result->append(address);
+ }
+}
+
+/**
+ * Returns a string representation of a void pointer
+ *
+ * @param id The pointer
+ * @param result The string representation
+ */
+
+void
+IcedTeaPluginUtilities::JSIDToString(void* id, std::string* result)
+{
+
+ char* id_str = (char*) malloc(sizeof(char)*20); // max = long long = 8446744073709551615 == 19 chars
+
+ if (sizeof(void*) == sizeof(long long))
+ {
+ sprintf(id_str, "%llu", id);
+ }
+ else
+ {
+ sprintf(id_str, "%lu", id); // else use long
+ }
+
+ result->append(id_str);
+
+ PLUGIN_DEBUG("Converting pointer %p to %s\n", id, id_str);
+ free(id_str);
+}
+
+/**
+ * Returns a void pointer from a string representation
+ *
+ * @param id_str The string representation
+ * @return The pointer
+ */
+
+void*
+IcedTeaPluginUtilities::stringToJSID(std::string id_str)
+{
+ void* ptr;
+ if (sizeof(void*) == sizeof(long long))
+ {
+ PLUGIN_DEBUG("Casting (long long) \"%s\" -- %llu\n", id_str.c_str(), strtoull(id_str.c_str(), NULL, 0));
+ ptr = reinterpret_cast <void*> ((unsigned long long) strtoull(id_str.c_str(), NULL, 0));
+ } else
+ {
+ PLUGIN_DEBUG("Casting (long) \"%s\" -- %lu\n", id_str.c_str(), strtoul(id_str.c_str(), NULL, 0));
+ ptr = reinterpret_cast <void*> ((unsigned long) strtoul(id_str.c_str(), NULL, 0));
+ }
+
+ PLUGIN_DEBUG("Casted: %p\n", ptr);
+
+ return ptr;
+}
+
+/**
+ * Returns a void pointer from a string representation
+ *
+ * @param id_str The pointer to the string representation
+ * @return The pointer
+ */
+
+void*
+IcedTeaPluginUtilities::stringToJSID(std::string* id_str)
+{
+ void* ptr;
+ if (sizeof(void*) == sizeof(long long))
+ {
+ PLUGIN_DEBUG("Casting (long long) \"%s\" -- %llu\n", id_str->c_str(), strtoull(id_str->c_str(), NULL, 0));
+ ptr = reinterpret_cast <void*> ((unsigned long long) strtoull(id_str->c_str(), NULL, 0));
+ } else
+ {
+ PLUGIN_DEBUG("Casting (long) \"%s\" -- %lu\n", id_str->c_str(), strtoul(id_str->c_str(), NULL, 0));
+ ptr = reinterpret_cast <void*> ((unsigned long) strtoul(id_str->c_str(), NULL, 0));
+ }
+
+ PLUGIN_DEBUG("Casted: %p\n", ptr);
+
+ return ptr;
+}
+
+/**
+ * Increments the global reference number and returns it.
+ *
+ * This function is thread-safe.
+ */
+int
+IcedTeaPluginUtilities::getReference()
+{
+ pthread_mutex_lock(&reference_mutex);
+
+ // If we are nearing the max, reset
+ if (reference < -0x7FFFFFFF + 10) {
+ reference = -1;
+ }
+
+ reference--;
+ pthread_mutex_unlock(&reference_mutex);
+
+ return reference;
+}
+
+/**
+ * Decrements the global reference number.
+ *
+ * This function is thread-safe.
+ */
+void
+IcedTeaPluginUtilities::releaseReference()
+{
+ // do nothing for now
+}
+
+/**
+ * Converts integer to char*
+ *
+ * @param i The integer to convert to ascii
+ * @param result The resulting string
+ */
+void
+IcedTeaPluginUtilities::itoa(int i, std::string* result)
+{
+ // largest possible integer is 10 digits long
+ char* int_str = (char*) malloc(sizeof(char)*11);
+ sprintf(int_str, "%d", i);
+ result->append(int_str);
+
+ free(int_str);
+}
+
+/**
+ * Frees memory from a string* vector
+ *
+ * The vector deconstructor will only delete string pointers upon being
+ * called. This function frees the associated string memory as well.
+ *
+ * @param v The vector whose strings are to be freed
+ */
+void
+IcedTeaPluginUtilities::freeStringPtrVector(std::vector<std::string*>* v)
+{
+ if (v)
+ {
+ for (int i=0; i < v->size(); i++) {
+ delete v->at(i);
+ }
+
+ delete v;
+ }
+
+}
+
+/**
+ * Given a string, splits it on the given delimiters.
+ *
+ * @param str The string to split
+ * @param The delimiters to split on
+ * @return A string vector containing the aplit components
+ */
+
+std::vector<std::string*>*
+IcedTeaPluginUtilities::strSplit(const char* str, const char* delim)
+{
+ std::vector<std::string*>* v = new std::vector<std::string*>();
+ v->reserve(strlen(str)/2);
+ char* copy;
+
+ // Tokening is done on a copy
+ copy = (char*) malloc (sizeof(char)*strlen(str) + 1);
+ strcpy(copy, str);
+
+ char* tok_ptr;
+ tok_ptr = strtok (copy, delim);
+
+ while (tok_ptr != NULL)
+ {
+ // Allocation on heap since caller has no way to knowing how much will
+ // be needed. Make sure caller cleans up!
+ std::string* s = new std::string();
+ s->append(tok_ptr);
+ v->push_back(s);
+ tok_ptr = strtok (NULL, " ");
+ }
+
+ return v;
+}
+
+/**
+ * Given a unicode byte array, converts it to a UTF8 string
+ *
+ * The actual contents in the array may be surrounded by other data.
+ *
+ * e.g. with length 5, begin = 3,
+ * unicode_byte_array = "37 28 5 48 45 4c 4c 4f 9e 47":
+ *
+ * We'd start at 3 i.e. "48" and go on for 5 i.e. upto and including "4f".
+ * So we convert "48 45 4c 4c 4f" which is "hello"
+ *
+ * @param length The length of the string
+ * @param begin Where in the array to begin conversion
+ * @param result_unicode_str The return variable in which the
+ * converted string is placed
+ */
+
+void
+IcedTeaPluginUtilities::getUTF8String(int length, int begin, std::vector<std::string*>* unicode_byte_array, std::string* result_unicode_str)
+{
+ result_unicode_str->clear();
+ result_unicode_str->reserve(unicode_byte_array->size()/2);
+ for (int i = begin; i < begin+length; i++)
+ result_unicode_str->push_back((char) strtol(unicode_byte_array->at(i)->c_str(), NULL, 16));
+
+ PLUGIN_DEBUG("Converted UTF-8 string: %s. Length=%d\n", result_unicode_str->c_str(), result_unicode_str->length());
+}
+
+/**
+ * Given a UTF8 string, converts it to a space delimited string of hex characters
+ *
+ * The first element in the return array is the length of the string
+ *
+ * e.g. "hello" would convert to: "5 48 45 4c 4c 4f"
+ *
+ * @param str The string to convert
+ * @param urt_str The result
+ */
+
+void
+IcedTeaPluginUtilities::convertStringToUTF8(std::string* str, std::string* utf_str)
+{
+ std::ostringstream ostream;
+
+ std::string length = std::string();
+ itoa(str->length(), &length);
+
+ ostream << length;
+
+ // UTF-8 characters are 4-bytes max + space + '\0'
+ char* hex_value = (char*) malloc(sizeof(char)*10);
+
+ for (int i = 0; i < str->length(); i++)
+ {
+ sprintf(hex_value, " %hx", str->at(i));
+ ostream << hex_value;
+ }
+
+ utf_str->clear();
+ *utf_str = ostream.str();
+
+ free(hex_value);
+ PLUGIN_DEBUG("Converted %s to UTF-8 string %s\n", str->c_str(), utf_str->c_str());
+}
+
+/**
+ * Given a unicode byte array, converts it to a UTF16LE/UCS-2 string
+ *
+ * This works in a manner similar to getUTF8String, except that it reads 2
+ * slots for each byte.
+ *
+ * @param length The length of the string
+ * @param begin Where in the array to begin conversion
+ * @param result_unicode_str The return variable in which the
+ * converted string is placed
+ */
+void
+IcedTeaPluginUtilities::getUTF16LEString(int length, int begin, std::vector<std::string*>* unicode_byte_array, std::wstring* result_unicode_str)
+{
+
+ wchar_t c;
+
+ if (plugin_debug) printf("Converted UTF-16LE string: ");
+
+ result_unicode_str->clear();
+ for (int i = begin; i < begin+length; i+=2)
+ {
+ int low = strtol(unicode_byte_array->at(i)->c_str(), NULL, 16);
+ int high = strtol(unicode_byte_array->at(i+1)->c_str(), NULL, 16);
+
+ c = ((high << 8) | low);
+
+ if ((c >= 'a' && c <= 'z') ||
+ (c >= 'A' && c <= 'Z') ||
+ (c >= '0' && c <= '9'))
+ {
+ if (plugin_debug) printf("%c", c);
+ }
+
+ result_unicode_str->push_back(c);
+ }
+
+ // not routing via debug print macros due to wide-string issues
+ if (plugin_debug) printf(". Length=%d\n", result_unicode_str->length());
+}
+
+/*
+ * Prints the given string vector (if debug is true)
+ *
+ * @param prefix The prefix to print before printing the vector contents
+ * @param cv The string vector whose contents are to be printed
+ */
+void
+IcedTeaPluginUtilities::printStringVector(const char* prefix, std::vector<std::string>* str_vector)
+{
+
+ // This is a CPU intensive function. Run only if debugging
+ if (!plugin_debug)
+ return;
+
+ std::string* str = new std::string();
+ *str += "{ ";
+ for (int i=0; i < str_vector->size(); i++)
+ {
+ *str += str_vector->at(i);
+
+ if (i != str_vector->size() - 1)
+ *str += ", ";
+ }
+
+ *str += " }";
+
+ PLUGIN_DEBUG("%s %s\n", prefix, str->c_str());
+
+ delete str;
+}
+
+const gchar*
+IcedTeaPluginUtilities::getSourceFromInstance(NPP instance)
+{
+ // At the moment, src cannot be securely fetched via NPAPI
+ // See:
+ // http://www.mail-archive.com/[email protected]/msg04872.html
+
+ // Since we use the insecure window.location.href attribute to compute
+ // source, we cannot use it to make security decisions. Therefore,
+ // instance associated source will always return empty
+
+ //ITNPPluginData* data = (ITNPPluginData*) instance->pdata;
+ //return (data->source) ? data->source : "";
+
+ return "http://null.null";
+}
+
+/**
+ * Stores a window pointer <-> instance mapping
+ *
+ * @param member_ptr The pointer key
+ * @param instance The instance to associate with this pointer
+ */
+
+void
+IcedTeaPluginUtilities::storeInstanceID(void* member_ptr, NPP instance)
+{
+ PLUGIN_DEBUG("Storing instance %p with key %p\n", instance, member_ptr);
+ instance_map->insert(std::make_pair(member_ptr, instance));
+}
+
+/**
+ * Removes a window pointer <-> instance mapping
+ *
+ * @param member_ptr The key to remove
+ */
+
+void
+IcedTeaPluginUtilities::removeInstanceID(void* member_ptr)
+{
+ PLUGIN_DEBUG("Removing key %p from instance map\n", member_ptr);
+ instance_map->erase(member_ptr);
+}
+
+/**
+ * Removes all mappings to a given instance, and all associated objects
+ */
+void
+IcedTeaPluginUtilities::invalidateInstance(NPP instance)
+{
+ PLUGIN_DEBUG("Invalidating instance %p\n", instance);
+
+ std::map<void*,NPP>::iterator iterator;
+
+ for (iterator = instance_map->begin(); iterator != instance_map->end(); iterator++)
+ {
+ if ((*iterator).second == instance)
+ {
+ instance_map->erase((*iterator).first);
+ }
+ }
+}
+
+/**
+ * Given the window pointer, returns the instance associated with it
+ *
+ * @param member_ptr The pointer key
+ * @return The associated instance
+ */
+
+NPP
+IcedTeaPluginUtilities::getInstanceFromMemberPtr(void* member_ptr)
+{
+
+ NPP instance = NULL;
+ PLUGIN_DEBUG("getInstanceFromMemberPtr looking for %p\n", member_ptr);
+
+ std::map<void*, NPP>::iterator iterator = instance_map->find(member_ptr);
+
+ if (iterator != instance_map->end())
+ {
+ instance = instance_map->find(member_ptr)->second;
+ PLUGIN_DEBUG("getInstanceFromMemberPtr found %p. Instance = %p\n", member_ptr, instance);
+ }
+
+ return instance;
+}
+
+/**
+ * Given a java id key ('classid:instanceid'), returns the associated valid NPObject, if any
+ *
+ * @param key the key
+ * @return The associated active NPObject, NULL otherwise
+ */
+
+NPObject*
+IcedTeaPluginUtilities::getNPObjectFromJavaKey(std::string key)
+{
+
+ NPObject* object = NULL;
+ PLUGIN_DEBUG("getNPObjectFromJavaKey looking for %s\n", key.c_str());
+
+ std::map<std::string, NPObject*>::iterator iterator = object_map->find(key);
+
+ if (iterator != object_map->end())
+ {
+ NPObject* mapped_object = object_map->find(key)->second;
+
+ if (getInstanceFromMemberPtr(mapped_object) != NULL)
+ {
+ object = mapped_object;
+ PLUGIN_DEBUG("getNPObjectFromJavaKey found %s. NPObject = %p\n", key.c_str(), object);
+ }
+ }
+
+ return object;
+}
+
+/**
+ * Stores a java id key <-> NPObject mapping
+ *
+ * @param key The Java ID Key
+ * @param object The object to map to
+ */
+
+void
+IcedTeaPluginUtilities::storeObjectMapping(std::string key, NPObject* object)
+{
+ PLUGIN_DEBUG("Storing object %p with key %s\n", object, key.c_str());
+ object_map->insert(std::make_pair(key, object));
+}
+
+/**
+ * Removes a java id key <-> NPObject mapping
+ *
+ * @param key The key to remove
+ */
+
+void
+IcedTeaPluginUtilities::removeObjectMapping(std::string key)
+{
+ PLUGIN_DEBUG("Removing key %s from object map\n", key.c_str());
+ object_map->erase(key);
+}
+
+/*
+ * Similar to printStringVector, but takes a vector of string pointers instead
+ *
+ * @param prefix The prefix to print before printing the vector contents
+ * @param cv The string* vector whose contents are to be printed
+ */
+
+void
+IcedTeaPluginUtilities::printStringPtrVector(const char* prefix, std::vector<std::string*>* str_ptr_vector)
+{
+ // This is a CPU intensive function. Run only if debugging
+ if (!plugin_debug)
+ return;
+
+ std::string* str = new std::string();
+ *str += "{ ";
+ for (int i=0; i < str_ptr_vector->size(); i++)
+ {
+ *str += *(str_ptr_vector->at(i));
+
+ if (i != str_ptr_vector->size() - 1)
+ *str += ", ";
+ }
+
+ *str += " }";
+
+ PLUGIN_DEBUG("%s %s\n", prefix, str->c_str());
+
+ delete str;
+}
+
+void
+IcedTeaPluginUtilities::printNPVariant(NPVariant variant)
+{
+ // This is a CPU intensive function. Run only if debugging
+ if (!plugin_debug)
+ return;
+
+ if (NPVARIANT_IS_VOID(variant))
+ {
+ PLUGIN_DEBUG("VOID %d\n", variant);
+ }
+ else if (NPVARIANT_IS_NULL(variant))
+ {
+ PLUGIN_DEBUG("NULL\n", variant);
+ }
+ else if (NPVARIANT_IS_BOOLEAN(variant))
+ {
+ PLUGIN_DEBUG("BOOL: %d\n", NPVARIANT_TO_BOOLEAN(variant));
+ }
+ else if (NPVARIANT_IS_INT32(variant))
+ {
+ PLUGIN_DEBUG("INT32: %d\n", NPVARIANT_TO_INT32(variant));
+ }
+ else if (NPVARIANT_IS_DOUBLE(variant))
+ {
+ PLUGIN_DEBUG("DOUBLE: %f\n", NPVARIANT_TO_DOUBLE(variant));
+ }
+ else if (NPVARIANT_IS_STRING(variant))
+ {
+#if MOZILLA_VERSION_COLLAPSED < 1090200
+ PLUGIN_DEBUG("STRING: %s\n", NPVARIANT_TO_STRING(variant).utf8characters);
+#else
+ PLUGIN_DEBUG("STRING: %s\n", NPVARIANT_TO_STRING(variant).UTF8Characters);
+#endif
+ }
+ else
+ {
+ PLUGIN_DEBUG("OBJ: %p\n", NPVARIANT_TO_OBJECT(variant));
+ }
+}
+
+void
+IcedTeaPluginUtilities::NPVariantToString(NPVariant variant, std::string* result)
+{
+ char* str = (char*) malloc(sizeof(char)*32); // enough for everything except string
+
+ if (NPVARIANT_IS_VOID(variant))
+ {
+ sprintf(str, "%p", variant);
+ }
+ else if (NPVARIANT_IS_NULL(variant))
+ {
+ sprintf(str, "NULL");
+ }
+ else if (NPVARIANT_IS_BOOLEAN(variant))
+ {
+ if (NPVARIANT_TO_BOOLEAN(variant))
+ sprintf(str, "true");
+ else
+ sprintf(str, "false");
+ }
+ else if (NPVARIANT_IS_INT32(variant))
+ {
+ sprintf(str, "%d", NPVARIANT_TO_INT32(variant));
+ }
+ else if (NPVARIANT_IS_DOUBLE(variant))
+ {
+ sprintf(str, "%f", NPVARIANT_TO_DOUBLE(variant));;
+ }
+ else if (NPVARIANT_IS_STRING(variant))
+ {
+ free(str);
+#if MOZILLA_VERSION_COLLAPSED < 1090200
+ str = (char*) malloc(sizeof(char)*NPVARIANT_TO_STRING(variant).utf8length);
+ sprintf(str, "%s", NPVARIANT_TO_STRING(variant).utf8characters);
+#else
+ str = (char*) malloc(sizeof(char)*NPVARIANT_TO_STRING(variant).UTF8Length);
+ sprintf(str, "%s", NPVARIANT_TO_STRING(variant).UTF8Characters);
+#endif
+ }
+ else
+ {
+ sprintf(str, "[Object %p]", variant);
+ }
+
+ result->append(str);
+ free(str);
+}
+
+bool
+IcedTeaPluginUtilities::javaResultToNPVariant(NPP instance,
+ std::string* java_value,
+ NPVariant* variant)
+{
+ JavaRequestProcessor java_request = JavaRequestProcessor();
+ JavaResultData* java_result;
+
+ if (java_value->find("literalreturn") == 0)
+ {
+ // 'literalreturn ' == 14 to skip
+ std::string value = java_value->substr(14);
+
+ // VOID/BOOLEAN/NUMBER
+
+ if (value == "void")
+ {
+ PLUGIN_DEBUG("Method call returned void\n");
+ VOID_TO_NPVARIANT(*variant);
+ } else if (value == "null")
+ {
+ PLUGIN_DEBUG("Method call returned null\n");
+ NULL_TO_NPVARIANT(*variant);
+ }else if (value == "true")
+ {
+ PLUGIN_DEBUG("Method call returned a boolean (true)\n");
+ BOOLEAN_TO_NPVARIANT(true, *variant);
+ } else if (value == "false")
+ {
+ PLUGIN_DEBUG("Method call returned a boolean (false)\n");
+ BOOLEAN_TO_NPVARIANT(false, *variant);
+ } else
+ {
+ double d = strtod(value.c_str(), NULL);
+
+ // See if it is convertible to int
+ if (value.find(".") != std::string::npos ||
+ d < -(0x7fffffffL - 1L) ||
+ d > 0x7fffffffL)
+ {
+ PLUGIN_DEBUG("Method call returned a double %f\n", d);
+ DOUBLE_TO_NPVARIANT(d, *variant);
+ } else
+ {
+ int32_t i = (int32_t) d;
+ PLUGIN_DEBUG("Method call returned an int %d\n", i);
+ INT32_TO_NPVARIANT(i, *variant);
+ }
+ }
+ } else {
+ // Else this is a complex java object
+
+ // To keep code a little bit cleaner, we create variables with proper descriptive names
+ std::string return_obj_instance_id = std::string();
+ std::string return_obj_class_id = std::string();
+ std::string return_obj_class_name = std::string();
+ return_obj_instance_id.append(*java_value);
+
+ // Find out the class name first, because string is a special case
+ java_result = java_request.getClassName(return_obj_instance_id);
+
+ if (java_result->error_occurred)
+ {
+ return false;
+ }
+
+ return_obj_class_name.append(*(java_result->return_string));
+
+ if (return_obj_class_name == "java.lang.String")
+ {
+ // String is a special case as NPVariant can handle it directly
+ java_result = java_request.getString(return_obj_instance_id);
+
+ if (java_result->error_occurred)
+ {
+ return false;
+ }
+
+ // needs to be on the heap
+ NPUTF8* return_str = (NPUTF8*) malloc(sizeof(NPUTF8)*java_result->return_string->size() + 1);
+ strcpy(return_str, java_result->return_string->c_str());
+
+ PLUGIN_DEBUG("Method call returned a string: \"%s\"\n", return_str);
+ STRINGZ_TO_NPVARIANT(return_str, *variant);
+
+ } else {
+
+ // Else this is a regular class. Reference the class object so
+ // we can construct an NPObject with it and the instance
+ java_result = java_request.getClassID(return_obj_instance_id);
+
+ if (java_result->error_occurred)
+ {
+ return false;
+ }
+
+ return_obj_class_id.append(*(java_result->return_string));
+
+ NPObject* obj;
+
+ if (return_obj_class_name.find('[') == 0) // array
+ obj = IcedTeaScriptableJavaPackageObject::get_scriptable_java_object(
+ instance,
+ return_obj_class_id, return_obj_instance_id, true);
+ else
+ obj = IcedTeaScriptableJavaPackageObject::get_scriptable_java_object(
+ instance,
+ return_obj_class_id, return_obj_instance_id, false);
+
+ OBJECT_TO_NPVARIANT(obj, *variant);
+ }
+ }
+
+ return true;
+}
+
+bool
+IcedTeaPluginUtilities::isObjectJSArray(NPP instance, NPObject* object)
+{
+
+ NPVariant constructor_v = NPVariant();
+ NPIdentifier constructor_id = browser_functions.getstringidentifier("constructor");
+ browser_functions.getproperty(instance, object, constructor_id, &constructor_v);
+ IcedTeaPluginUtilities::printNPVariant(constructor_v);
+
+ // void constructor => not an array
+ if (NPVARIANT_IS_VOID(constructor_v))
+ return false;
+
+ NPObject* constructor = NPVARIANT_TO_OBJECT(constructor_v);
+
+ NPVariant constructor_str;
+ NPIdentifier toString = browser_functions.getstringidentifier("toString");
+ browser_functions.invoke(instance, constructor, toString, NULL, 0, &constructor_str);
+ IcedTeaPluginUtilities::printNPVariant(constructor_str);
+
+ std::string constructor_name = std::string();
+
+#if MOZILLA_VERSION_COLLAPSED < 1090200
+ constructor_name.append(NPVARIANT_TO_STRING(constructor_str).utf8characters);
+#else
+ constructor_name.append(NPVARIANT_TO_STRING(constructor_str).UTF8Characters);
+#endif
+
+ PLUGIN_DEBUG("Constructor for NPObject is %s\n", constructor_name.c_str());
+
+ return constructor_name.find("function Array") == 0;
+}
+
+void
+IcedTeaPluginUtilities::decodeURL(const gchar* url, gchar** decoded_url)
+{
+
+ PLUGIN_DEBUG("GOT URL: %s -- %s\n", url, *decoded_url);
+ int length = strlen(url);
+ for (int i=0; i < length; i++)
+ {
+ if (url[i] == '%' && i < length - 2)
+ {
+ unsigned char code1 = (unsigned char) url[i+1];
+ unsigned char code2 = (unsigned char) url[i+2];
+
+ if (!IS_VALID_HEX(&code1) || !IS_VALID_HEX(&code2))
+ continue;
+
+ // Convert hex value to integer
+ int converted1 = HEX_TO_INT(&code1);
+ int converted2 = HEX_TO_INT(&code2);
+
+ // bitshift 4 to simulate *16
+ int value = (converted1 << 4) + converted2;
+ char decoded = value;
+
+ strncat(*decoded_url, &decoded, 1);
+
+ i += 2;
+ } else
+ {
+ strncat(*decoded_url, &url[i], 1);
+ }
+ }
+
+ PLUGIN_DEBUG("SENDING URL: %s\n", *decoded_url);
+}
+
+/******************************************
+ * Begin JavaMessageSender implementation *
+ ******************************************
+ *
+ * This implementation is very simple and is therefore folded into this file
+ * rather than a new one.
+ */
+
+/**
+ * Sends to the Java side
+ *
+ * @param message The message to send.
+ * @param returns whether the message was consumable (always true)
+ */
+
+bool
+JavaMessageSender::newMessageOnBus(const char* message)
+{
+ char* msg = (char*) malloc(sizeof(char)*strlen(message) + 1);
+ strcpy(msg, message);
+ plugin_send_message_to_appletviewer(msg);
+
+ free(msg);
+ msg = NULL;
+
+ // Always successful
+ return true;
+}
+
+/***********************************
+ * Begin MessageBus implementation *
+ ***********************************/
+
+/**
+ * Constructor.
+ *
+ * Initializes the mutexes needed by the other functions.
+ */
+MessageBus::MessageBus()
+{
+ int ret;
+
+ ret = pthread_mutex_init(&subscriber_mutex, NULL);
+
+ if(ret)
+ PLUGIN_DEBUG("Error: Unable to initialize subscriber mutex: %d\n", ret);
+
+ ret = pthread_mutex_init(&msg_queue_mutex, NULL);
+ if(ret)
+ PLUGIN_DEBUG("Error: Unable to initialize message queue mutex: %d\n", ret);
+
+ PLUGIN_DEBUG("Mutexs %p and %p initialized\n", &subscriber_mutex, &msg_queue_mutex);
+}
+
+/**
+ * Destructor.
+ *
+ * Destroy the mutexes initialized by the constructor.
+ */
+
+MessageBus::~MessageBus()
+{
+ PLUGIN_DEBUG("MessageBus::~MessageBus\n");
+
+ int ret;
+
+ ret = pthread_mutex_destroy(&subscriber_mutex);
+ if(ret)
+ PLUGIN_DEBUG("Error: Unable to destroy subscriber mutex: %d\n", ret);
+
+ ret = pthread_mutex_destroy(&msg_queue_mutex);
+ if(ret)
+ PLUGIN_DEBUG("Error: Unable to destroy message queue mutex: %d\n", ret);
+}
+
+/**
+ * Adds the given BusSubscriber as a subscriber to self
+ *
+ * @param b The BusSubscriber to subscribe
+ */
+void
+MessageBus::subscribe(BusSubscriber* b)
+{
+ // Applets may initialize in parallel. So lock before pushing.
+
+ PLUGIN_DEBUG("Subscribing %p to bus %p\n", b, this);
+ pthread_mutex_lock(&subscriber_mutex);
+ subscribers.push_back(b);
+ pthread_mutex_unlock(&subscriber_mutex);
+}
+
+/**
+ * Removes the given BusSubscriber from the subscriber list
+ *
+ * @param b The BusSubscriber to ubsubscribe
+ */
+void
+MessageBus::unSubscribe(BusSubscriber* b)
+{
+ // Applets may initialize in parallel. So lock before pushing.
+
+ PLUGIN_DEBUG("Un-subscribing %p from bus %p\n", b, this);
+ pthread_mutex_lock(&subscriber_mutex);
+ subscribers.remove(b);
+ pthread_mutex_unlock(&subscriber_mutex);
+}
+
+/**
+ * Notifies all subscribers with the given message
+ *
+ * @param message The message to send to the subscribers
+ */
+void
+MessageBus::post(const char* message)
+{
+ char* msg = (char*) malloc(sizeof(char)*strlen(message) + 1);
+ bool message_consumed = false;
+
+ // consumer frees this memory
+ strcpy(msg, message);
+
+ PLUGIN_DEBUG("Trying to lock %p...\n", &msg_queue_mutex);
+ pthread_mutex_lock(&subscriber_mutex);
+
+ PLUGIN_DEBUG("Message %s received on bus. Notifying subscribers.\n", msg);
+
+ std::list<BusSubscriber*>::const_iterator i;
+ for( i = subscribers.begin(); i != subscribers.end() && !message_consumed; ++i ) {
+ PLUGIN_DEBUG("Notifying subscriber %p of %s\n", *i, msg);
+ message_consumed = ((BusSubscriber*) *i)->newMessageOnBus(msg);
+ }
+
+ pthread_mutex_unlock(&subscriber_mutex);
+
+ if (!message_consumed)
+ PLUGIN_DEBUG("Warning: No consumer found for message %s\n", msg);
+
+ PLUGIN_DEBUG("%p unlocked...\n", &msg_queue_mutex);
+}
diff --git a/plugin/icedteanp/IcedTeaPluginUtils.h b/plugin/icedteanp/IcedTeaPluginUtils.h
new file mode 100644
index 0000000..8584fb8
--- /dev/null
+++ b/plugin/icedteanp/IcedTeaPluginUtils.h
@@ -0,0 +1,296 @@
+/* IcedTeaPluginUtils.h
+
+ Copyright (C) 2009, 2010 Red Hat
+
+This file is part of IcedTea.
+
+IcedTea is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+IcedTea is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with IcedTea; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+/**
+ * Utility classes for the IcedTeaPlugin
+ */
+
+#ifndef __ICEDTEAPLUGINUTILS_H__
+#define __ICEDTEAPLUGINUTILS_H__
+
+#include <pthread.h>
+#include <stdio.h>
+
+#include <cstring>
+#include <iostream>
+#include <list>
+#include <map>
+#include <queue>
+#include <sstream>
+#include <string>
+#include <vector>
+
+#include <npapi.h>
+
+#if MOZILLA_VERSION_COLLAPSED < 1090100
+#include <npupp.h>
+#else
+#include <npapi.h>
+#include <npruntime.h>
+#endif
+
+#include "IcedTeaNPPlugin.h"
+
+#define PLUGIN_DEBUG(...) \
+ do \
+ { \
+ if (plugin_debug) \
+ { \
+ fprintf (stderr, "ITNPP Thread# %ld: ", pthread_self()); \
+ fprintf (stderr, __VA_ARGS__); \
+ } \
+ } while (0)
+
+#define CHECK_JAVA_RESULT(result_data) \
+{ \
+ if (((JavaResultData*) result_data)->error_occurred) \
+ { \
+ printf("Error: Error occurred on Java side: %s.\n", \
+ ((JavaResultData*) result_data)->error_msg->c_str()); \
+ return; \
+ } \
+}
+
+#define HEX_TO_INT(c) \
+ ((*c >= 'a') ? *c - 'a' + 10 : \
+ (*c >= 'A') ? *c - 'A' + 10 : \
+ *c - '0')
+
+#define IS_VALID_HEX(c) \
+ ((*c >= '0' && *c <= '9') || \
+ (*c >= 'a' && *c <= 'f') || \
+ (*c >= 'A' && *c <= 'F'))
+
+/*
+ * This struct holds data specific to a Java operation requested by the plugin
+ */
+typedef struct java_result_data
+{
+
+ // Return identifier (if applicable)
+ int return_identifier;
+
+ // Return string (if applicable)
+ std::string* return_string;
+
+ // Return wide/mb string (if applicable)
+ std::wstring* return_wstring;
+
+ // Error message (if an error occurred)
+ std::string* error_msg;
+
+ // Boolean indicating if an error occurred
+ bool error_occurred;
+
+} JavaResultData;
+
+/*
+ * Misc. utility functions
+ *
+ * This class is never instantiated and should contain static functions only
+ */
+
+class IcedTeaPluginUtilities
+{
+
+ private:
+ static int reference; /* Reference count */
+
+ /* Mutex lock for updating reference count */
+ static pthread_mutex_t reference_mutex;
+
+ /* Map holding window pointer<->instance relationships */
+ static std::map<void*, NPP>* instance_map;
+
+ /* Map holding java-side-obj-key->NPObject relationship */
+ static std::map<std::string, NPObject*>* object_map;
+
+ public:
+
+ /* Constructs message prefix with given context */
+ static void constructMessagePrefix(int context,
+ std::string* result);
+
+ /* Constructs message prefix with given context and reference */
+ static void constructMessagePrefix(int context, int reference,
+ std::string* result);
+
+ /* Constructs message prefix with given context, reference and src */
+ static void constructMessagePrefix(int context, int reference,
+ std::string address,
+ std::string* result);
+
+ /* Converts given pointer to a string representation */
+ static void JSIDToString(void* id, std::string* result);
+
+ /* Converts the given string representation to a pointer */
+ static void* stringToJSID(std::string id_str);
+ static void* stringToJSID(std::string* id_str);
+
+ /* Increments reference count and returns it */
+ static int getReference();
+
+ /* Decrements reference count */
+ static void releaseReference();
+
+ /* Converts the given integer to a string */
+ static void itoa(int i, std::string* result);
+
+ /* Frees the given vector and the strings that its contents point to */
+ static void freeStringPtrVector(std::vector<std::string*>* v);
+
+ /* Splits the given string based on the delimiter provided */
+ static std::vector<std::string*>* strSplit(const char* str,
+ const char* delim);
+
+ /* Converts given unicode integer byte array to UTF8 string */
+ static void getUTF8String(int length, int begin,
+ std::vector<std::string*>* unicode_byte_array,
+ std::string* result_unicode_str);
+
+ /* Converts given UTF8 string to unicode integer byte array */
+ static void convertStringToUTF8(std::string* str,
+ std::string* utf_str);
+
+ /* Converts given unicode integer byte array to UTF16LE/UCS-2 string */
+ static void getUTF16LEString(int length, int begin,
+ std::vector<std::string*>* unicode_byte_array,
+ std::wstring* result_unicode_str);
+
+ /* Prints contents of given string vector */
+ static void printStringVector(const char* prefix, std::vector<std::string>* cv);
+
+ /* Prints contents of given string pointer vector */
+ static void printStringPtrVector(const char* prefix, std::vector<std::string*>* cv);
+
+ static std::string* variantToClassName(NPVariant variant);
+
+ static void printNPVariant(NPVariant variant);
+
+ static void NPVariantToString(NPVariant variant, std::string* result);
+
+ static bool javaResultToNPVariant(NPP instance,
+ std::string* java_result,
+ NPVariant* variant);
+
+ static const gchar* getSourceFromInstance(NPP instance);
+
+ static void storeInstanceID(void* member_ptr, NPP instance);
+
+ static void removeInstanceID(void* member_ptr);
+
+ static NPP getInstanceFromMemberPtr(void* member_ptr);
+
+ static NPObject* getNPObjectFromJavaKey(std::string key);
+
+ static void storeObjectMapping(std::string key, NPObject* object);
+
+ static void removeObjectMapping(std::string key);
+
+ static void invalidateInstance(NPP instance);
+
+ static bool isObjectJSArray(NPP instance, NPObject* object);
+
+ static void decodeURL(const char* url, char** decoded_url);
+};
+
+/*
+ * A bus subscriber interface. Implementors must implement the newMessageOnBus
+ * method.
+ */
+class BusSubscriber
+{
+ private:
+
+ public:
+ BusSubscriber() {}
+
+ /* Notifies this subscriber that a new message as arrived */
+ virtual bool newMessageOnBus(const char* message) = 0;
+};
+
+/*
+ * This implementation is very simple and is therefore folded into this file
+ * rather than a new one.
+ */
+class JavaMessageSender : public BusSubscriber
+{
+ private:
+ public:
+
+ /* Sends given message to Java side */
+ virtual bool newMessageOnBus(const char* message);
+};
+
+/*
+ * Represents a message bus.
+ * The bus can also have subscribers who are notified when a new message
+ * arrives.
+ */
+class MessageBus
+{
+ private:
+ /* Mutex for locking the message queue */
+ pthread_mutex_t msg_queue_mutex;
+
+ /* Mutex used when adjusting subscriber list */
+ pthread_mutex_t subscriber_mutex;
+
+ /* Subscriber list */
+ std::list<BusSubscriber*> subscribers;
+
+ /* Queued messages */
+ std::queue<char*> msgQueue;
+
+ public:
+ MessageBus();
+
+ ~MessageBus();
+
+ /* subscribe to this bus */
+ void subscribe(BusSubscriber* b);
+
+ /* unsubscribe from this bus */
+ void unSubscribe(BusSubscriber* b);
+
+ /* Post a message on to the bus (it is safe to free the message pointer
+ after this function returns) */
+ void post(const char* message);
+};
+
+#endif // __ICEDTEAPLUGINUTILS_H__
diff --git a/plugin/icedteanp/IcedTeaRunnable.cc b/plugin/icedteanp/IcedTeaRunnable.cc
new file mode 100644
index 0000000..6f92c89
--- /dev/null
+++ b/plugin/icedteanp/IcedTeaRunnable.cc
@@ -0,0 +1,75 @@
+/* IcedTeaRunnable.cc
+
+ Copyright (C) 2009, 2010 Red Hat
+
+This file is part of IcedTea.
+
+IcedTea is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+IcedTea is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with IcedTea; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+#include <stdio.h>
+#include "IcedTeaRunnable.h"
+
+NS_IMPL_ISUPPORTS1 (IcedTeaRunnable, nsIRunnable)
+
+IcedTeaRunnable::IcedTeaRunnable ()
+{
+}
+
+IcedTeaRunnable::~IcedTeaRunnable ()
+{
+}
+
+NS_IMETHODIMP
+IcedTeaRunnable::Run ()
+{
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+IcedTeaRunnableMethod::IcedTeaRunnableMethod (Method method, void* thread_data, void* result)
+: method (method),
+ thread_data(thread_data),
+ result(result)
+{
+}
+
+IcedTeaRunnableMethod::~IcedTeaRunnableMethod ()
+{
+ }
+
+NS_IMETHODIMP
+IcedTeaRunnableMethod::Run ()
+{
+ printf("Running method...\n");
+ (*method) (thread_data, result);
+ return NS_OK;
+}
diff --git a/plugin/icedteanp/IcedTeaRunnable.h b/plugin/icedteanp/IcedTeaRunnable.h
new file mode 100644
index 0000000..d6e7a82
--- /dev/null
+++ b/plugin/icedteanp/IcedTeaRunnable.h
@@ -0,0 +1,104 @@
+/* IcedTeaRunnable.h
+
+ Copyright (C) 2009, 2010 Red Hat
+
+This file is part of IcedTea.
+
+IcedTea is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+IcedTea is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with IcedTea; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+#ifndef __ICEDTEARUNNABLE_H__
+#define __ICEDTEARUNNABLE_H__
+
+#define MOZILLA 1
+#if MOZILLA
+
+#if MOZILLA_VERSION_COLLAPSED < 1090100
+#include <nsIRunnable.h>
+#include <string>
+#endif
+
+/*
+ * This struct holds the result from the main-thread dispatched method
+ */
+typedef struct result_data
+{
+ // Return identifier (if applicable)
+ int return_identifier;
+
+ // Return string (if applicable)
+ std::string* return_string;
+
+ // Return wide/mb string (if applicable)
+ std::wstring* return_wstring;
+
+ // Error message (if an error occurred)
+ std::string* error_msg;
+
+ // Boolean indicating if an error occurred
+ bool error_occured;
+
+ // If this result is ready
+ bool result_ready;
+
+} ResultData;
+
+class IcedTeaRunnable : public nsIRunnable
+{
+public:
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSIRUNNABLE
+
+ IcedTeaRunnable ();
+
+ ~IcedTeaRunnable ();
+};
+
+class IcedTeaRunnableMethod : public IcedTeaRunnable
+{
+public:
+
+ typedef void* (*Method) (void*, void*);
+
+ IcedTeaRunnableMethod (Method, void* thread_data, void* result);
+ NS_IMETHOD Run ();
+
+ ~IcedTeaRunnableMethod ();
+
+ Method method;
+ void* thread_data;
+ void* result;
+};
+
+#endif /* MOZILLA */
+
+#endif /* __ICEDTEARUNNABLE_H__ */
diff --git a/plugin/icedteanp/IcedTeaScriptablePluginObject.cc b/plugin/icedteanp/IcedTeaScriptablePluginObject.cc
new file mode 100644
index 0000000..e482941
--- /dev/null
+++ b/plugin/icedteanp/IcedTeaScriptablePluginObject.cc
@@ -0,0 +1,897 @@
+/* IcedTeaScriptablePluginObject.cc
+
+ Copyright (C) 2009, 2010 Red Hat
+
+This file is part of IcedTea.
+
+IcedTea is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+IcedTea is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with IcedTea; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+#include <typeinfo>
+
+#include "IcedTeaScriptablePluginObject.h"
+
+IcedTeaScriptablePluginObject::IcedTeaScriptablePluginObject(NPP instance)
+{
+ this->instance = instance;
+ IcedTeaPluginUtilities::storeInstanceID(this, instance);
+}
+
+void
+IcedTeaScriptablePluginObject::deAllocate(NPObject *npobj)
+{
+ printf ("** Unimplemented: IcedTeaScriptablePluginObject::deAllocate %p\n", npobj);
+}
+
+void
+IcedTeaScriptablePluginObject::invalidate(NPObject *npobj)
+{
+ printf ("** Unimplemented: IcedTeaScriptablePluginObject::invalidate %p\n", npobj);
+}
+
+bool
+IcedTeaScriptablePluginObject::hasMethod(NPObject *npobj, NPIdentifier name)
+{
+ printf ("** Unimplemented: IcedTeaScriptablePluginObject::hasMethod %p\n", npobj);
+ return false;
+}
+
+bool
+IcedTeaScriptablePluginObject::invoke(NPObject *npobj, NPIdentifier name, const NPVariant *args,
+ uint32_t argCount,NPVariant *result)
+{
+ printf ("** Unimplemented: IcedTeaScriptablePluginObject::invoke %p\n", npobj);
+ return false;
+}
+
+bool
+IcedTeaScriptablePluginObject::invokeDefault(NPObject *npobj, const NPVariant *args,
+ uint32_t argCount, NPVariant *result)
+{
+ printf ("** Unimplemented: IcedTeaScriptablePluginObject::invokeDefault %p\n", npobj);
+ return false;
+}
+
+bool
+IcedTeaScriptablePluginObject::hasProperty(NPObject *npobj, NPIdentifier name)
+{
+ printf ("** Unimplemented: IcedTeaScriptablePluginObject::hasProperty %p\n", npobj);
+ return false;
+}
+
+bool
+IcedTeaScriptablePluginObject::getProperty(NPObject *npobj, NPIdentifier name, NPVariant *result)
+{
+ // Package request?
+ if (!strcmp(browser_functions.utf8fromidentifier(name), "java"))
+ {
+ //NPObject* obj = IcedTeaScriptablePluginObject::get_scriptable_java_package_object(getInstanceFromMemberPtr(npobj), name);
+ //OBJECT_TO_NPVARIANT(obj, *result);
+
+ //printf ("Filling variant %p with object %p\n", result);
+ }
+
+ return false;
+}
+
+bool
+IcedTeaScriptablePluginObject::setProperty(NPObject *npobj, NPIdentifier name, const NPVariant *value)
+{
+ printf ("** Unimplemented: IcedTeaScriptablePluginObject::setProperty %p\n", npobj);
+ return false;
+}
+
+bool
+IcedTeaScriptablePluginObject::removeProperty(NPObject *npobj, NPIdentifier name)
+{
+ printf ("** Unimplemented: IcedTeaScriptablePluginObject::removeProperty %p\n", npobj);
+ return false;
+}
+
+bool
+IcedTeaScriptablePluginObject::enumerate(NPObject *npobj, NPIdentifier **value, uint32_t *count)
+{
+ printf ("** Unimplemented: IcedTeaScriptablePluginObject::enumerate %p\n", npobj);
+ return false;
+}
+
+bool
+IcedTeaScriptablePluginObject::construct(NPObject *npobj, const NPVariant *args, uint32_t argCount,
+ NPVariant *result)
+{
+ printf ("** Unimplemented: IcedTeaScriptablePluginObject::construct %p\n", npobj);
+ return false;
+}
+
+NPObject*
+allocate_scriptable_jp_object(NPP npp, NPClass *aClass)
+{
+ PLUGIN_DEBUG("Allocating new scriptable Java Package object\n");
+ return new IcedTeaScriptableJavaPackageObject(npp);
+}
+
+NPObject*
+IcedTeaScriptablePluginObject::get_scriptable_java_package_object(NPP instance, const NPUTF8* name)
+{
+
+ NPObject* scriptable_object;
+
+ NPClass* np_class = new NPClass();
+ np_class->structVersion = NP_CLASS_STRUCT_VERSION;
+ np_class->allocate = allocate_scriptable_jp_object;
+ np_class->deallocate = IcedTeaScriptableJavaPackageObject::deAllocate;
+ np_class->invalidate = IcedTeaScriptableJavaPackageObject::invalidate;
+ np_class->hasMethod = IcedTeaScriptableJavaPackageObject::hasMethod;
+ np_class->invoke = IcedTeaScriptableJavaPackageObject::invoke;
+ np_class->invokeDefault = IcedTeaScriptableJavaPackageObject::invokeDefault;
+ np_class->hasProperty = IcedTeaScriptableJavaPackageObject::hasProperty;
+ np_class->getProperty = IcedTeaScriptableJavaPackageObject::getProperty;
+ np_class->setProperty = IcedTeaScriptableJavaPackageObject::setProperty;
+ np_class->removeProperty = IcedTeaScriptableJavaPackageObject::removeProperty;
+ np_class->enumerate = IcedTeaScriptableJavaPackageObject::enumerate;
+ np_class->construct = IcedTeaScriptableJavaPackageObject::construct;
+
+ scriptable_object = browser_functions.createobject(instance, np_class);
+ PLUGIN_DEBUG("Returning new scriptable package class: %p from instance %p with name %s\n", scriptable_object, instance, name);
+
+ ((IcedTeaScriptableJavaPackageObject*) scriptable_object)->setPackageName(name);
+
+ IcedTeaPluginUtilities::storeInstanceID(scriptable_object, instance);
+
+ return scriptable_object;
+}
+
+IcedTeaScriptableJavaPackageObject::IcedTeaScriptableJavaPackageObject(NPP instance)
+{
+ PLUGIN_DEBUG("Constructing new scriptable java package object\n");
+ this->instance = instance;
+ this->package_name = new std::string();
+}
+
+IcedTeaScriptableJavaPackageObject::~IcedTeaScriptableJavaPackageObject()
+{
+ delete this->package_name;
+}
+
+void
+IcedTeaScriptableJavaPackageObject::setPackageName(const NPUTF8* name)
+{
+ this->package_name->append(name);
+}
+
+std::string
+IcedTeaScriptableJavaPackageObject::getPackageName()
+{
+ return this->package_name->c_str();
+}
+
+void
+IcedTeaScriptableJavaPackageObject::deAllocate(NPObject *npobj)
+{
+ browser_functions.releaseobject(npobj);
+}
+
+void
+IcedTeaScriptableJavaPackageObject::invalidate(NPObject *npobj)
+{
+ // nothing to do for these
+}
+
+bool
+IcedTeaScriptableJavaPackageObject::hasMethod(NPObject *npobj, NPIdentifier name)
+{
+ // Silly caller. Methods are for objects!
+ return false;
+}
+
+bool
+IcedTeaScriptableJavaPackageObject::invoke(NPObject *npobj, NPIdentifier name, const NPVariant *args,
+ uint32_t argCount,NPVariant *result)
+{
+ printf ("** Unimplemented: IcedTeaScriptableJavaPackageObject::invoke %p\n", npobj);
+ return false;
+}
+
+bool
+IcedTeaScriptableJavaPackageObject::invokeDefault(NPObject *npobj, const NPVariant *args,
+ uint32_t argCount, NPVariant *result)
+{
+ printf ("** Unimplemented: IcedTeaScriptableJavaPackageObject::invokeDefault %p\n", npobj);
+ return false;
+}
+
+bool
+IcedTeaScriptableJavaPackageObject::hasProperty(NPObject *npobj, NPIdentifier name)
+{
+ PLUGIN_DEBUG("IcedTeaScriptableJavaPackageObject::hasProperty %s\n", browser_functions.utf8fromidentifier(name));
+
+ bool hasProperty = false;
+ JavaResultData* java_result;
+ JavaRequestProcessor* java_request = new JavaRequestProcessor();
+ NPP instance = IcedTeaPluginUtilities::getInstanceFromMemberPtr(npobj);
+ int plugin_instance_id = get_id_from_instance(instance);
+
+ PLUGIN_DEBUG("Object package name: \"%s\"\n", ((IcedTeaScriptableJavaPackageObject*) npobj)->getPackageName().c_str());
+
+ // "^java" is always a package
+ if (((IcedTeaScriptableJavaPackageObject*) npobj)->getPackageName().length() == 0 &&
+ ( !strcmp(browser_functions.utf8fromidentifier(name), "java") ||
+ !strcmp(browser_functions.utf8fromidentifier(name), "javax")))
+ {
+ return true;
+ }
+
+ std::string property_name = ((IcedTeaScriptableJavaPackageObject*) npobj)->getPackageName();
+ if (property_name.length() > 0)
+ property_name += ".";
+ property_name += browser_functions.utf8fromidentifier(name);
+
+ PLUGIN_DEBUG("Looking for name \"%s\"\n", property_name.c_str());
+
+ java_result = java_request->hasPackage(plugin_instance_id, property_name);
+
+ if (!java_result->error_occurred && java_result->return_identifier != 0) hasProperty = true;
+
+ // No such package. Do we have a class with that name?
+ if (!hasProperty)
+ {
+ java_result = java_request->findClass(plugin_instance_id, property_name);
+ }
+
+ if (java_result->return_identifier != 0) hasProperty = true;
+
+ delete java_request;
+
+ return hasProperty;
+}
+
+bool
+IcedTeaScriptableJavaPackageObject::getProperty(NPObject *npobj, NPIdentifier name, NPVariant *result)
+{
+
+ PLUGIN_DEBUG("IcedTeaScriptableJavaPackageObject::getProperty %s\n", browser_functions.utf8fromidentifier(name));
+
+ if (!browser_functions.utf8fromidentifier(name))
+ return false;
+
+ bool isPropertyClass = false;
+ JavaResultData* java_result;
+ JavaRequestProcessor java_request = JavaRequestProcessor();
+ NPP instance = IcedTeaPluginUtilities::getInstanceFromMemberPtr(npobj);
+ int plugin_instance_id = get_id_from_instance(instance);
+
+ std::string property_name = ((IcedTeaScriptableJavaPackageObject*) npobj)->getPackageName();
+ if (property_name.length() > 0)
+ property_name += ".";
+ property_name += browser_functions.utf8fromidentifier(name);
+
+ java_result = java_request.findClass(plugin_instance_id, property_name);
+ isPropertyClass = (java_result->return_identifier == 0);
+
+ //NPIdentifier property = browser_functions.getstringidentifier(property_name.c_str());
+
+ NPObject* obj;
+
+ if (isPropertyClass)
+ {
+ PLUGIN_DEBUG("Returning package object\n");
+ obj = IcedTeaScriptablePluginObject::get_scriptable_java_package_object(
+ IcedTeaPluginUtilities::getInstanceFromMemberPtr(npobj),
+ property_name.c_str());
+ }
+ else
+ {
+ PLUGIN_DEBUG("Returning Java object\n");
+ obj = IcedTeaScriptableJavaPackageObject::get_scriptable_java_object(
+ IcedTeaPluginUtilities::getInstanceFromMemberPtr(npobj),
+ *(java_result->return_string), "0", false);
+ }
+
+ OBJECT_TO_NPVARIANT(obj, *result);
+
+ return true;
+}
+
+bool
+IcedTeaScriptableJavaPackageObject::setProperty(NPObject *npobj, NPIdentifier name, const NPVariant *value)
+{
+ // Can't be going around setting properties on namespaces.. that's madness!
+ return false;
+}
+
+bool
+IcedTeaScriptableJavaPackageObject::removeProperty(NPObject *npobj, NPIdentifier name)
+{
+ printf ("** Unimplemented: IcedTeaScriptableJavaPackageObject::removeProperty %p\n", npobj);
+ return false;
+}
+
+bool
+IcedTeaScriptableJavaPackageObject::enumerate(NPObject *npobj, NPIdentifier **value, uint32_t *count)
+{
+ printf ("** Unimplemented: IcedTeaScriptableJavaPackageObject::enumerate %p\n", npobj);
+ return false;
+}
+
+bool
+IcedTeaScriptableJavaPackageObject::construct(NPObject *npobj, const NPVariant *args, uint32_t argCount,
+ NPVariant *result)
+{
+ printf ("** Unimplemented: IcedTeaScriptableJavaPackageObject::construct %p\n", npobj);
+ return false;
+}
+
+NPObject*
+allocate_scriptable_java_object(NPP npp, NPClass *aClass)
+{
+ PLUGIN_DEBUG("Allocating new scriptable Java object\n");
+ return new IcedTeaScriptableJavaObject(npp);
+}
+
+NPObject*
+IcedTeaScriptableJavaPackageObject::get_scriptable_java_object(NPP instance,
+ std::string class_id,
+ std::string instance_id,
+ bool isArray)
+{
+ NPObject* scriptable_object;
+
+ std::string obj_key = std::string();
+ obj_key += class_id;
+ obj_key += ":";
+ obj_key += instance_id;
+
+ PLUGIN_DEBUG("get_scriptable_java_object searching for %s...\n", obj_key.c_str());
+ scriptable_object = IcedTeaPluginUtilities::getNPObjectFromJavaKey(obj_key);
+
+ if (scriptable_object != NULL)
+ {
+ PLUGIN_DEBUG("Returning existing object %p\n", scriptable_object);
+ browser_functions.retainobject(scriptable_object);
+ return scriptable_object;
+ }
+
+
+ NPClass* np_class = new NPClass();
+ np_class->structVersion = NP_CLASS_STRUCT_VERSION;
+ np_class->allocate = allocate_scriptable_java_object;
+ np_class->deallocate = IcedTeaScriptableJavaObject::deAllocate;
+ np_class->invalidate = IcedTeaScriptableJavaObject::invalidate;
+ np_class->hasMethod = IcedTeaScriptableJavaObject::hasMethod;
+ np_class->invoke = IcedTeaScriptableJavaObject::invoke;
+ np_class->invokeDefault = IcedTeaScriptableJavaObject::invokeDefault;
+ np_class->hasProperty = IcedTeaScriptableJavaObject::hasProperty;
+ np_class->getProperty = IcedTeaScriptableJavaObject::getProperty;
+ np_class->setProperty = IcedTeaScriptableJavaObject::setProperty;
+ np_class->removeProperty = IcedTeaScriptableJavaObject::removeProperty;
+ np_class->enumerate = IcedTeaScriptableJavaObject::enumerate;
+ np_class->construct = IcedTeaScriptableJavaObject::construct;
+
+ // try to create normally
+ scriptable_object = browser_functions.createobject(instance, np_class);
+
+ // didn't work? try creating asynch
+ if (!scriptable_object)
+ {
+ AsyncCallThreadData thread_data = AsyncCallThreadData();
+ thread_data.result_ready = false;
+ thread_data.parameters = std::vector<void*>();
+ thread_data.result = std::string();
+
+ thread_data.parameters.push_back(instance);
+ thread_data.parameters.push_back(np_class);
+ thread_data.parameters.push_back(&scriptable_object);
+
+ browser_functions.pluginthreadasynccall(instance, &_createAndRetainJavaObject, &thread_data);
+
+ while (!thread_data.result_ready) usleep(2000); // wait till ready
+ } else
+ {
+ // Else retain object and continue
+ browser_functions.retainobject(scriptable_object);
+ }
+
+ PLUGIN_DEBUG("Constructed new Java Object with classid=%s, instanceid=%s, isArray=%d and scriptable_object=%p\n", class_id.c_str(), instance_id.c_str(), isArray, scriptable_object);
+
+ ((IcedTeaScriptableJavaObject*) scriptable_object)->setClassIdentifier(class_id);
+ ((IcedTeaScriptableJavaObject*) scriptable_object)->setIsArray(isArray);
+
+ if (instance_id != "0")
+ ((IcedTeaScriptableJavaObject*) scriptable_object)->setInstanceIdentifier(instance_id);
+
+ IcedTeaPluginUtilities::storeInstanceID(scriptable_object, instance);
+ IcedTeaPluginUtilities::storeObjectMapping(obj_key, scriptable_object);
+
+ PLUGIN_DEBUG("Inserting into object_map key %s->%p\n", obj_key.c_str(), scriptable_object);
+ return scriptable_object;
+}
+
+/* Creates and retains a scriptable java object (intended to be called asynch.) */
+void
+_createAndRetainJavaObject(void* data)
+{
+ PLUGIN_DEBUG("Asynchronously creating/retaining object ...\n");
+
+ std::vector<void*> parameters = ((AsyncCallThreadData*) data)->parameters;
+ NPP instance = (NPP) parameters.at(0);
+ NPClass* np_class = (NPClass*) parameters.at(1);
+ NPObject** scriptable_object = (NPObject**) parameters.at(2);
+
+ *scriptable_object = browser_functions.createobject(instance, np_class);
+ browser_functions.retainobject(*scriptable_object);
+
+ ((AsyncCallThreadData*) data)->result_ready = true;
+}
+
+bool
+IcedTeaScriptableJavaPackageObject::is_valid_java_object(NPObject* object_ptr) {
+ return IcedTeaPluginUtilities::getInstanceFromMemberPtr(object_ptr) != NULL;
+}
+
+IcedTeaScriptableJavaObject::IcedTeaScriptableJavaObject(NPP instance)
+{
+ this->instance = instance;
+ this->class_id = new std::string();
+ this->instance_id = new std::string();
+}
+
+IcedTeaScriptableJavaObject::~IcedTeaScriptableJavaObject()
+{
+ delete this->class_id;
+ delete this->instance_id;
+}
+
+void
+IcedTeaScriptableJavaObject::setClassIdentifier(std::string class_id)
+{
+ this->class_id->append(class_id);
+}
+
+void
+IcedTeaScriptableJavaObject::setInstanceIdentifier(std::string instance_id)
+{
+ this->instance_id->append(instance_id);
+}
+
+void
+IcedTeaScriptableJavaObject::setIsArray(bool isArray)
+{
+ this->isObjectArray = isArray;
+}
+
+void
+IcedTeaScriptableJavaObject::deAllocate(NPObject *npobj)
+{
+ browser_functions.releaseobject(npobj);
+}
+
+void
+IcedTeaScriptableJavaObject::invalidate(NPObject *npobj)
+{
+ IcedTeaPluginUtilities::removeInstanceID(npobj);
+
+ std::string obj_key = std::string();
+ obj_key += ((IcedTeaScriptableJavaObject*) npobj)->getClassID();
+ obj_key += ":";
+ obj_key += ((IcedTeaScriptableJavaObject*) npobj)->getInstanceID();
+
+ IcedTeaPluginUtilities::removeObjectMapping(obj_key);
+}
+
+bool
+IcedTeaScriptableJavaObject::hasMethod(NPObject *npobj, NPIdentifier name)
+{
+ PLUGIN_DEBUG("IcedTeaScriptableJavaObject::hasMethod %s (ival=%d)\n", browser_functions.utf8fromidentifier(name), browser_functions.intfromidentifier(name));
+ bool hasMethod = false;
+
+ // If object is an array and requested "method" may be a number, check for it first
+ if ( !((IcedTeaScriptableJavaObject*) npobj)->isArray() ||
+ (browser_functions.intfromidentifier(name) < 0))
+ {
+
+ if (!browser_functions.utf8fromidentifier(name))
+ return false;
+
+ JavaResultData* java_result;
+ JavaRequestProcessor java_request = JavaRequestProcessor();
+
+ std::string classId = std::string(((IcedTeaScriptableJavaObject*) npobj)->getClassID());
+ std::string methodName = browser_functions.utf8fromidentifier(name);
+
+ java_result = java_request.hasMethod(classId, methodName);
+ hasMethod = java_result->return_identifier != 0;
+ }
+
+ PLUGIN_DEBUG("IcedTeaScriptableJavaObject::hasMethod returning %d\n", hasMethod);
+ return hasMethod;
+}
+
+bool
+IcedTeaScriptableJavaObject::invoke(NPObject *npobj, NPIdentifier name, const NPVariant *args,
+ uint32_t argCount, NPVariant *result)
+{
+ NPUTF8* method_name = browser_functions.utf8fromidentifier(name);
+
+ // Extract arg type array
+ PLUGIN_DEBUG("IcedTeaScriptableJavaObject::invoke %s. Args follow.\n", method_name);
+ for (int i=0; i < argCount; i++)
+ {
+ IcedTeaPluginUtilities::printNPVariant(args[i]);
+ }
+
+ JavaResultData* java_result;
+ JavaRequestProcessor java_request = JavaRequestProcessor();
+
+ NPObject* obj;
+ std::string instance_id = ((IcedTeaScriptableJavaObject*) npobj)->getInstanceID();
+ std::string class_id = ((IcedTeaScriptableJavaObject*) npobj)->getClassID();
+ std::string callee;
+ std::string source;
+
+ NPP instance = IcedTeaPluginUtilities::getInstanceFromMemberPtr(npobj);
+
+ // First, load the arguments into the java-side table
+ std::string id = std::string();
+ std::vector<std::string> arg_ids = std::vector<std::string>();
+ for (int i=0; i < argCount; i++) {
+ id.clear();
+ createJavaObjectFromVariant(instance, args[i], &id);
+
+ if (id == "-1")
+ {
+ printf("Unable to create arguments on Java side\n");
+ return false;
+ }
+
+ arg_ids.push_back(id);
+ }
+
+ if (instance_id.length() == 0) // Static
+ {
+ PLUGIN_DEBUG("Calling static method\n");
+ callee = ((IcedTeaScriptableJavaObject*) npobj)->getClassID();
+ java_result = java_request.callStaticMethod(
+ IcedTeaPluginUtilities::getSourceFromInstance(instance),
+ callee, browser_functions.utf8fromidentifier(name), arg_ids);
+ } else
+ {
+ PLUGIN_DEBUG("Calling method normally\n");
+ callee = ((IcedTeaScriptableJavaObject*) npobj)->getInstanceID();
+ java_result = java_request.callMethod(
+ IcedTeaPluginUtilities::getSourceFromInstance(instance),
+ callee, browser_functions.utf8fromidentifier(name), arg_ids);
+ }
+
+ if (java_result->error_occurred)
+ {
+ // error message must be allocated on heap
+ char* error_msg = (char*) malloc(java_result->error_msg->length()*sizeof(char));
+ strcpy(error_msg, java_result->error_msg->c_str());
+ browser_functions.setexception(npobj, error_msg);
+ return false;
+ }
+
+ PLUGIN_DEBUG("IcedTeaScriptableJavaObject::invoke converting and returning.\n");
+ return IcedTeaPluginUtilities::javaResultToNPVariant(instance, java_result->return_string, result);
+}
+
+bool
+IcedTeaScriptableJavaObject::invokeDefault(NPObject *npobj, const NPVariant *args,
+ uint32_t argCount, NPVariant *result)
+{
+ printf ("** Unimplemented: IcedTeaScriptableJavaObject::invokeDefault %p\n", npobj);
+ return false;
+}
+
+bool
+IcedTeaScriptableJavaObject::hasProperty(NPObject *npobj, NPIdentifier name)
+{
+ PLUGIN_DEBUG("IcedTeaScriptableJavaObject::hasProperty %s (ival=%d)\n", browser_functions.utf8fromidentifier(name), browser_functions.intfromidentifier(name));
+ bool hasProperty = false;
+
+ // If it is an array, only length and indexes are valid
+ if (((IcedTeaScriptableJavaObject*) npobj)->isArray())
+ {
+ if (browser_functions.intfromidentifier(name) >= 0 ||
+ !strcmp(browser_functions.utf8fromidentifier(name), "length"))
+ hasProperty = true;
+
+ } else
+ {
+
+ if (!browser_functions.utf8fromidentifier(name))
+ return false;
+
+ if (!strcmp(browser_functions.utf8fromidentifier(name), "Packages"))
+ {
+ hasProperty = true;
+ } else {
+
+ JavaResultData* java_result;
+ JavaRequestProcessor java_request = JavaRequestProcessor();
+
+ std::string class_id = std::string(((IcedTeaScriptableJavaObject*) npobj)->getClassID());
+ std::string fieldName = browser_functions.utf8fromidentifier(name);
+
+ java_result = java_request.hasField(class_id, fieldName);
+
+ hasProperty = java_result->return_identifier != 0;
+ }
+ }
+
+ PLUGIN_DEBUG("IcedTeaScriptableJavaObject::hasProperty returning %d\n", hasProperty);
+ return hasProperty;
+}
+
+bool
+IcedTeaScriptableJavaObject::getProperty(NPObject *npobj, NPIdentifier name, NPVariant *result)
+{
+ PLUGIN_DEBUG("IcedTeaScriptableJavaObject::getProperty %s (ival=%d)\n", browser_functions.utf8fromidentifier(name), browser_functions.intfromidentifier(name));
+
+ bool isPropertyClass = false;
+ JavaResultData* java_result;
+ JavaRequestProcessor java_request = JavaRequestProcessor();
+
+ NPObject* obj;
+ std::string instance_id = ((IcedTeaScriptableJavaObject*) npobj)->getInstanceID();
+ std::string class_id = ((IcedTeaScriptableJavaObject*) npobj)->getClassID();
+ NPP instance = ((IcedTeaScriptableJavaObject*) npobj)->getInstance();
+
+ if (instance_id.length() > 0) // Could be an array or a simple object
+ {
+ // If array and requesting length
+ if ( ((IcedTeaScriptableJavaObject*) npobj)->isArray() &&
+ browser_functions.utf8fromidentifier(name) &&
+ !strcmp(browser_functions.utf8fromidentifier(name), "length"))
+ {
+ java_result = java_request.getArrayLength(instance_id);
+ } else if ( ((IcedTeaScriptableJavaObject*) npobj)->isArray() &&
+ browser_functions.intfromidentifier(name) >= 0) // else if array and requesting index
+ {
+
+ java_result = java_request.getArrayLength(instance_id);
+ if (java_result->error_occurred)
+ {
+ printf("ERROR: Couldn't fetch array length\n");
+ return false;
+ }
+
+ int length = atoi(java_result->return_string->c_str());
+
+ // Access beyond size?
+ if (browser_functions.intfromidentifier(name) >= length)
+ {
+ VOID_TO_NPVARIANT(*result);
+ return true;
+ }
+
+ std::string index = std::string();
+ IcedTeaPluginUtilities::itoa(browser_functions.intfromidentifier(name), &index);
+ java_result = java_request.getSlot(instance_id, index);
+
+ } else // Everything else
+ {
+ if (!browser_functions.utf8fromidentifier(name))
+ return false;
+
+ if (!strcmp(browser_functions.utf8fromidentifier(name), "Packages"))
+ {
+ NPObject* pkgObject = IcedTeaScriptablePluginObject::get_scriptable_java_package_object(instance, "");
+ OBJECT_TO_NPVARIANT(pkgObject, *result);
+ return true;
+ }
+
+ java_result = java_request.getField(
+ IcedTeaPluginUtilities::getSourceFromInstance(instance),
+ class_id, instance_id, browser_functions.utf8fromidentifier(name));
+ }
+ }
+ else
+ {
+ if (!browser_functions.utf8fromidentifier(name))
+ return true;
+
+ java_result = java_request.getStaticField(
+ IcedTeaPluginUtilities::getSourceFromInstance(instance),
+ class_id, browser_functions.utf8fromidentifier(name));
+ }
+
+ if (java_result->error_occurred)
+ {
+ return false;
+ }
+
+ PLUGIN_DEBUG("IcedTeaScriptableJavaObject::getProperty converting and returning.\n");
+ return IcedTeaPluginUtilities::javaResultToNPVariant(instance, java_result->return_string, result);
+}
+
+bool
+IcedTeaScriptableJavaObject::setProperty(NPObject *npobj, NPIdentifier name, const NPVariant *value)
+{
+ PLUGIN_DEBUG("IcedTeaScriptableJavaObject::setProperty %s (ival=%d) to:\n", browser_functions.utf8fromidentifier(name), browser_functions.intfromidentifier(name));
+ IcedTeaPluginUtilities::printNPVariant(*value);
+
+ bool isPropertyClass = false;
+ JavaResultData* java_result;
+ JavaRequestProcessor java_request = JavaRequestProcessor();
+
+ NPObject* obj;
+ std::string instance_id = ((IcedTeaScriptableJavaObject*) npobj)->getInstanceID();
+ std::string class_id = ((IcedTeaScriptableJavaObject*) npobj)->getClassID();
+
+ NPP instance = IcedTeaPluginUtilities::getInstanceFromMemberPtr(npobj);
+
+ if (instance_id.length() > 0) // Could be an array or a simple object
+ {
+ // If array
+ if ( ((IcedTeaScriptableJavaObject*) npobj)->isArray() &&
+ browser_functions.utf8fromidentifier(name) &&
+ !strcmp(browser_functions.utf8fromidentifier(name), "length"))
+ {
+ printf("ERROR: Array length is not a modifiable property\n");
+ return false;
+ } else if ( ((IcedTeaScriptableJavaObject*) npobj)->isArray() &&
+ browser_functions.intfromidentifier(name) >= 0) // else if array and requesting index
+ {
+
+ java_result = java_request.getArrayLength(instance_id);
+ if (java_result->error_occurred)
+ {
+ printf("ERROR: Couldn't fetch array length\n");
+ return false;
+ }
+
+ int length = atoi(java_result->return_string->c_str());
+
+ // Access beyond size?
+ if (browser_functions.intfromidentifier(name) >= length)
+ {
+ return true;
+ }
+
+ std::string index = std::string();
+ IcedTeaPluginUtilities::itoa(browser_functions.intfromidentifier(name), &index);
+
+ std::string value_id = std::string();
+ createJavaObjectFromVariant(instance, *value, &value_id);
+
+ java_result = java_request.setSlot(instance_id, index, value_id);
+
+ } else // Everything else
+ {
+ std::string value_id = std::string();
+ createJavaObjectFromVariant(instance, *value, &value_id);
+
+ java_result = java_request.setField(
+ IcedTeaPluginUtilities::getSourceFromInstance(instance),
+ class_id, instance_id, browser_functions.utf8fromidentifier(name), value_id);
+ }
+ }
+ else
+ {
+ std::string value_id = std::string();
+ createJavaObjectFromVariant(instance, *value, &value_id);
+
+ java_result = java_request.setStaticField(
+ IcedTeaPluginUtilities::getSourceFromInstance(instance),
+ class_id, browser_functions.utf8fromidentifier(name), value_id);
+ }
+
+ if (java_result->error_occurred)
+ {
+ return false;
+ }
+
+ PLUGIN_DEBUG("IcedTeaScriptableJavaObject::setProperty returning.\n");
+ return true;
+}
+
+bool
+IcedTeaScriptableJavaObject::removeProperty(NPObject *npobj, NPIdentifier name)
+{
+ printf ("** Unimplemented: IcedTeaScriptableJavaObject::removeProperty %p\n", npobj);
+ return false;
+}
+
+bool
+IcedTeaScriptableJavaObject::enumerate(NPObject *npobj, NPIdentifier **value, uint32_t *count)
+{
+ printf ("** Unimplemented: IcedTeaScriptableJavaObject::enumerate %p\n", npobj);
+ return false;
+}
+
+bool
+IcedTeaScriptableJavaObject::construct(NPObject *npobj, const NPVariant *args, uint32_t argCount,
+ NPVariant *result)
+{
+ // Extract arg type array
+ PLUGIN_DEBUG("IcedTeaScriptableJavaObject::construct %s. Args follow.\n", ((IcedTeaScriptableJavaObject*) npobj)->getClassID().c_str());
+ for (int i=0; i < argCount; i++)
+ {
+ IcedTeaPluginUtilities::printNPVariant(args[i]);
+ }
+
+ JavaResultData* java_result;
+ JavaRequestProcessor java_request = JavaRequestProcessor();
+
+ NPObject* obj;
+ std::string class_id = ((IcedTeaScriptableJavaObject*) npobj)->getClassID();
+ NPP instance = IcedTeaPluginUtilities::getInstanceFromMemberPtr(npobj);
+
+ // First, load the arguments into the java-side table
+ std::string id = std::string();
+ std::vector<std::string> arg_ids = std::vector<std::string>();
+ for (int i=0; i < argCount; i++) {
+ id.clear();
+ createJavaObjectFromVariant(instance, args[i], &id);
+ if (id == "0")
+ {
+ // error message must be allocated on heap
+ char* error_msg = (char*) malloc(1024*sizeof(char));
+ strcpy(error_msg, "Unable to create argument on Java side");
+
+ browser_functions.setexception(npobj, error_msg);
+ return false;
+ }
+
+ arg_ids.push_back(id);
+ }
+
+ java_result = java_request.newObject(
+ IcedTeaPluginUtilities::getSourceFromInstance(instance),
+ class_id,
+ arg_ids);
+
+ if (java_result->error_occurred)
+ {
+ // error message must be allocated on heap
+ int length = java_result->error_msg->length();
+ char* error_msg = (char*) malloc((length+1)*sizeof(char));
+ strcpy(error_msg, java_result->error_msg->c_str());
+
+ browser_functions.setexception(npobj, error_msg);
+ return false;
+ }
+
+ std::string return_obj_instance_id = std::string();
+ std::string return_obj_class_id = class_id;
+ return_obj_instance_id.append(*(java_result->return_string));
+
+ obj = IcedTeaScriptableJavaPackageObject::get_scriptable_java_object(
+ IcedTeaPluginUtilities::getInstanceFromMemberPtr(npobj),
+ return_obj_class_id, return_obj_instance_id, false);
+
+ OBJECT_TO_NPVARIANT(obj, *result);
+
+ PLUGIN_DEBUG("IcedTeaScriptableJavaObject::construct returning.\n");
+ return true;
+}
diff --git a/plugin/icedteanp/IcedTeaScriptablePluginObject.h b/plugin/icedteanp/IcedTeaScriptablePluginObject.h
new file mode 100644
index 0000000..a4933ed
--- /dev/null
+++ b/plugin/icedteanp/IcedTeaScriptablePluginObject.h
@@ -0,0 +1,212 @@
+/* IcedTeaScriptablePluginObject.h
+
+ Copyright (C) 2009, 2010 Red Hat
+
+This file is part of IcedTea.
+
+IcedTea is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+IcedTea is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with IcedTea; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+#ifndef __ICEDTEASCRIPTABLEPLUGINOBJECT_H_
+#define __ICEDTEASCRIPTABLEPLUGINOBJECT_H_
+
+#if MOZILLA_VERSION_COLLAPSED < 1090100
+#include "npupp.h"
+#else
+#include <npapi.h>
+#include <npruntime.h>
+#endif
+
+#include "IcedTeaJavaRequestProcessor.h"
+#include "IcedTeaNPPlugin.h"
+
+/**
+ * IcedTeaScriptablePluginObject, an extended NPObject that implements
+ * static functions whose pointers are supplied to NPClass.
+ */
+
+class IcedTeaScriptablePluginObject: public NPObject
+{
+
+ private:
+ NPP instance;
+
+ public:
+ IcedTeaScriptablePluginObject(NPP instance);
+
+ static void deAllocate(NPObject *npobj);
+
+ static void invalidate(NPObject *npobj);
+
+ static bool hasMethod(NPObject *npobj, NPIdentifier name);
+
+ static bool invoke(NPObject *npobj, NPIdentifier name,
+ const NPVariant *args, uint32_t argCount, NPVariant *result);
+
+ static bool invokeDefault(NPObject *npobj, const NPVariant *args,
+ uint32_t argCount, NPVariant *result);
+
+ static bool hasProperty(NPObject *npobj, NPIdentifier name);
+
+ static bool getProperty(NPObject *npobj, NPIdentifier name,
+ NPVariant *result);
+
+ static bool setProperty(NPObject *npobj, NPIdentifier name,
+ const NPVariant *value);
+
+ static bool removeProperty(NPObject *npobj, NPIdentifier name);
+
+ static bool enumerate(NPObject *npobj, NPIdentifier **value,
+ uint32_t *count);
+
+ static bool construct(NPObject *npobj, const NPVariant *args,
+ uint32_t argCount, NPVariant *result);
+
+ static NPObject* get_scriptable_java_package_object(NPP instance, const NPUTF8* name);
+};
+
+NPObject* allocate_scriptable_jp_object(NPP npp, NPClass *aClass);
+
+class IcedTeaScriptableJavaPackageObject: public NPObject
+{
+
+ private:
+ NPP instance;
+ std::string* package_name;
+
+ public:
+ IcedTeaScriptableJavaPackageObject(NPP instance);
+
+ ~IcedTeaScriptableJavaPackageObject();
+
+ void setPackageName(const NPUTF8* name);
+
+ std::string getPackageName();
+
+ static void deAllocate(NPObject *npobj);
+
+ static void invalidate(NPObject *npobj);
+
+ static bool hasMethod(NPObject *npobj, NPIdentifier name);
+
+ static bool invoke(NPObject *npobj, NPIdentifier name,
+ const NPVariant *args, uint32_t argCount, NPVariant *result);
+
+ static bool invokeDefault(NPObject *npobj, const NPVariant *args,
+ uint32_t argCount, NPVariant *result);
+
+ static bool hasProperty(NPObject *npobj, NPIdentifier name);
+
+ static bool getProperty(NPObject *npobj, NPIdentifier name,
+ NPVariant *result);
+
+ static bool setProperty(NPObject *npobj, NPIdentifier name,
+ const NPVariant *value);
+
+ static bool removeProperty(NPObject *npobj, NPIdentifier name);
+
+ static bool enumerate(NPObject *npobj, NPIdentifier **value,
+ uint32_t *count);
+
+ static bool construct(NPObject *npobj, const NPVariant *args,
+ uint32_t argCount, NPVariant *result);
+
+ static NPObject* get_scriptable_java_object(NPP instance,
+ std::string class_id,
+ std::string instance_id,
+ bool isArray);
+
+ static bool is_valid_java_object(NPObject* object_ptr);
+};
+
+class IcedTeaScriptableJavaObject: public NPObject
+{
+
+ private:
+ NPP instance;
+ bool isObjectArray;
+ std::string* class_id;
+ std::string* instance_id;
+
+ public:
+ IcedTeaScriptableJavaObject(NPP instance);
+
+ ~IcedTeaScriptableJavaObject();
+
+ void setClassIdentifier(std::string class_id);
+
+ void setInstanceIdentifier(std::string instance_id);
+
+ void setIsArray(bool isArray);
+
+ std::string getClassID() { return *class_id; }
+
+ std::string getInstanceID() { return *instance_id; }
+
+ NPP getInstance() { return instance; }
+
+ bool isArray() { return isObjectArray; }
+
+ static void deAllocate(NPObject *npobj);
+
+ static void invalidate(NPObject *npobj);
+
+ static bool hasMethod(NPObject *npobj, NPIdentifier name);
+
+ static bool invoke(NPObject *npobj, NPIdentifier name,
+ const NPVariant *args, uint32_t argCount, NPVariant *result);
+
+ static bool invokeDefault(NPObject *npobj, const NPVariant *args,
+ uint32_t argCount, NPVariant *result);
+
+ static bool hasProperty(NPObject *npobj, NPIdentifier name);
+
+ static bool getProperty(NPObject *npobj, NPIdentifier name,
+ NPVariant *result);
+
+ static bool setProperty(NPObject *npobj, NPIdentifier name,
+ const NPVariant *value);
+
+ static bool removeProperty(NPObject *npobj, NPIdentifier name);
+
+ static bool enumerate(NPObject *npobj, NPIdentifier **value,
+ uint32_t *count);
+
+ static bool construct(NPObject *npobj, const NPVariant *args,
+ uint32_t argCount, NPVariant *result);
+};
+
+/* Creates and retains a scriptable java object (intended to be called asynch.) */
+
+void _createAndRetainJavaObject(void* data);
+
+#endif /* __ICEDTEASCRIPTABLEPLUGINOBJECT_H_ */
diff --git a/plugin/icedteanp/java/netscape/javascript/JSException.java b/plugin/icedteanp/java/netscape/javascript/JSException.java
new file mode 100644
index 0000000..96ba310
--- /dev/null
+++ b/plugin/icedteanp/java/netscape/javascript/JSException.java
@@ -0,0 +1,140 @@
+/* -*- Mode: Java; tab-width: 8; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+package netscape.javascript;
+
+/**
+ * JSException is an exception which is thrown when JavaScript code
+ * returns an error.
+ */
+
+public
+class JSException extends RuntimeException {
+ public static final int EXCEPTION_TYPE_EMPTY = -1;
+ public static final int EXCEPTION_TYPE_VOID = 0;
+ public static final int EXCEPTION_TYPE_OBJECT = 1;
+ public static final int EXCEPTION_TYPE_FUNCTION = 2;
+ public static final int EXCEPTION_TYPE_STRING = 3;
+ public static final int EXCEPTION_TYPE_NUMBER = 4;
+ public static final int EXCEPTION_TYPE_BOOLEAN = 5;
+ public static final int EXCEPTION_TYPE_ERROR = 6;
+
+ public String filename;
+ public int lineno;
+ public String source;
+ public int tokenIndex;
+ public int wrappedExceptionType;
+ public Object wrappedException;
+
+ /**
+ * Constructs a JSException without a detail message.
+ * A detail message is a String that describes this particular exception.
+ *
+ * @deprecated Not for public use in future versions.
+ */
+ public JSException() {
+ super();
+ filename = "unknown";
+ lineno = 0;
+ source = "";
+ tokenIndex = 0;
+ wrappedExceptionType = EXCEPTION_TYPE_EMPTY;
+ }
+
+ /**
+ * Constructs a JSException with a detail message.
+ * A detail message is a String that describes this particular exception.
+ * @param s the detail message
+ *
+ * @deprecated Not for public use in future versions.
+ */
+ public JSException(String s) {
+ super(s);
+ filename = "unknown";
+ lineno = 0;
+ source = "";
+ tokenIndex = 0;
+ wrappedExceptionType = EXCEPTION_TYPE_EMPTY;
+ }
+
+ /**
+ * Constructs a JSException with a wrapped JavaScript exception object.
+ * This constructor needs to be public so that Java users can throw
+ * exceptions to JS cleanly.
+ */
+ public JSException(int wrappedExceptionType, Object wrappedException) {
+ super();
+ this.wrappedExceptionType = wrappedExceptionType;
+ this.wrappedException = wrappedException;
+ }
+
+ /**
+ * Constructs a JSException with a detail message and all the
+ * other info that usually comes with a JavaScript error.
+ * @param s the detail message
+ *
+ * @deprecated Not for public use in future versions.
+ */
+ public JSException(String s, String filename, int lineno,
+ String source, int tokenIndex) {
+ super(s);
+ this.filename = filename;
+ this.lineno = lineno;
+ this.source = source;
+ this.tokenIndex = tokenIndex;
+ wrappedExceptionType = EXCEPTION_TYPE_EMPTY;
+ }
+
+ /**
+ * Instance method getWrappedExceptionType returns the int mapping of the
+ * type of the wrappedException Object.
+ */
+ public int getWrappedExceptionType() {
+ return wrappedExceptionType;
+ }
+
+ /**
+ * Instance method getWrappedException.
+ */
+ public Object getWrappedException() {
+ return wrappedException;
+ }
+
+}
+
diff --git a/plugin/icedteanp/java/netscape/javascript/JSObject.java b/plugin/icedteanp/java/netscape/javascript/JSObject.java
new file mode 100644
index 0000000..74158c2
--- /dev/null
+++ b/plugin/icedteanp/java/netscape/javascript/JSObject.java
@@ -0,0 +1,297 @@
+/* -*- Mode: Java; tab-width: 8; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/* more doc todo:
+ * threads
+ * gc
+ *
+ *
+ */
+
+package netscape.javascript;
+
+import java.applet.Applet;
+import java.security.AccessControlContext;
+import java.security.AccessControlException;
+import java.security.AccessController;
+import java.security.BasicPermission;
+
+import sun.applet.PluginAppletViewer;
+import sun.applet.PluginDebug;
+
+
+
+/**
+ * JSObject allows Java to manipulate objects that are
+ * defined in JavaScript.
+ * Values passed from Java to JavaScript are converted as
+ * follows:<ul>
+ * <li>JSObject is converted to the original JavaScript object
+ * <li>Any other Java object is converted to a JavaScript wrapper,
+ * which can be used to access methods and fields of the java object.
+ * Converting this wrapper to a string will call the toString method
+ * on the original object, converting to a number will call the
+ * doubleValue method if possible and fail otherwise. Converting
+ * to a boolean will try to call the booleanValue method in the
+ * same way.
+ * <li>Java arrays are wrapped with a JavaScript object that understands
+ * array.length and array[index]
+ * <li>A Java boolean is converted to a JavaScript boolean
+ * <li>Java byte, char, short, int, long, float, and double are converted
+ * to JavaScript numbers
+ * </ul>
+ * Values passed from JavaScript to Java are converted as follows:<ul>
+ * <li>objects which are wrappers around java objects are unwrapped
+ * <li>other objects are wrapped with a JSObject
+ * <li>strings, numbers and booleans are converted to String, Double,
+ * and Boolean objects respectively
+ * </ul>
+ * This means that all JavaScript values show up as some kind
+ * of java.lang.Object in Java. In order to make much use of them,
+ * you will have to cast them to the appropriate subclass of Object,
+ * e.g. <code>(String) window.getMember("name");</code> or
+ * <code>(JSObject) window.getMember("document");</code>.
+ */
+public final class JSObject {
+ /* the internal object data */
+ private long internal;
+
+ /**
+ * initialize
+ */
+ private static void initClass() {
+ PluginDebug.debug ("JSObject.initClass");
+ }
+
+ static {
+ PluginDebug.debug ("JSObject INITIALIZER");
+ }
+
+ /**
+ * it is illegal to construct a JSObject manually
+ */
+ public JSObject(int jsobj_addr) {
+ this((long) jsobj_addr);
+ }
+
+ /**
+ * it is illegal to construct a JSObject manually
+ */
+ public JSObject(String jsobj_addr) {
+ this((long) Long.parseLong(jsobj_addr));
+ }
+
+ public JSObject(long jsobj_addr) {
+
+ // See if the caller has permission
+
+ try {
+ AccessController.getContext().checkPermission(new JSObjectCreatePermission());
+ } catch (AccessControlException ace) {
+
+ // If not, only caller with JSObject.getWindow on the stack may
+ // make this call unprivileged.
+
+ // Although this check is inefficient, it should happen only once
+ // during applet init, so we look the other way
+
+ StackTraceElement[] stack = Thread.currentThread().getStackTrace();
+ boolean mayProceed = false;
+
+ for (int i=0; i < stack.length; i++) {
+ if (stack[i].getClassName().equals("netscape.javascript.JSObject") &&
+ stack[i].getMethodName().equals("getWindow")) {
+ mayProceed = true;
+ }
+ }
+
+ if (!mayProceed) throw ace;
+ }
+
+ PluginDebug.debug ("JSObject long CONSTRUCTOR");
+ internal = jsobj_addr;
+ }
+
+ /**
+ * Retrieves a named member of a JavaScript object.
+ * Equivalent to "this.<i>name</i>" in JavaScript.
+ */
+ public Object getMember(String name)
+ {
+ PluginDebug.debug ("JSObject.getMember " + name);
+
+ Object o = PluginAppletViewer.getMember(internal, name);
+ PluginDebug.debug ("JSObject.getMember GOT " + o);
+ return o;
+ }
+
+
+ /**
+ * Retrieves an indexed member of a JavaScript object.
+ * Equivalent to "this[<i>index</i>]" in JavaScript.
+ */
+ // public Object getMember(int index) { return getSlot(index); }
+ public Object getSlot(int index)
+ {
+ PluginDebug.debug ("JSObject.getSlot " + index);
+
+ return PluginAppletViewer.getSlot(internal, index);
+ }
+
+
+ /**
+ * Sets a named member of a JavaScript object.
+ * Equivalent to "this.<i>name</i> = <i>value</i>" in JavaScript.
+ */
+ public void setMember(String name, Object value)
+ {
+ PluginDebug.debug ("JSObject.setMember " + name + " " + value);
+
+ PluginAppletViewer.setMember(internal, name, value);
+ }
+
+ /**
+ * Sets an indexed member of a JavaScript object.
+ * Equivalent to "this[<i>index</i>] = <i>value</i>" in JavaScript.
+ */
+ // public void setMember(int index, Object value) {
+ // setSlot(index, value);
+ // }
+ public void setSlot(int index, Object value)
+ {
+ PluginDebug.debug ("JSObject.setSlot " + index + " " + value);
+
+ PluginAppletViewer.setSlot(internal, index, value);
+ }
+
+
+ // TODO: toString, finalize.
+
+ /**
+ * Removes a named member of a JavaScript object.
+ */
+ public void removeMember(String name)
+ {
+ PluginDebug.debug ("JSObject.removeMember " + name);
+
+ PluginAppletViewer.removeMember(internal, name);
+ }
+
+
+ /**
+ * Calls a JavaScript method.
+ * Equivalent to "this.<i>methodName</i>(<i>args</i>[0], <i>args</i>[1], ...)" in JavaScript.
+ */
+ public Object call(String methodName, Object args[])
+ {
+ if (args == null)
+ args = new Object[0];
+
+ PluginDebug.debug ("JSObject.call " + methodName);
+ for (int i = 0; i < args.length; i++)
+ PluginDebug.debug (" " + args[i]);
+ PluginDebug.debug("");
+ return PluginAppletViewer.call(internal, methodName, args);
+ }
+
+
+ /**
+ * Evaluates a JavaScript expression. The expression is a string
+ * of JavaScript source code which will be evaluated in the context
+ * given by "this".
+ */
+ public Object eval(String s)
+ {
+ PluginDebug.debug("JSObject.eval " + s);
+ return PluginAppletViewer.eval(internal, s);
+ }
+
+
+ /**
+ * Converts a JSObject to a String.
+ */
+ public String toString()
+ {
+ PluginDebug.debug("JSObject.toString");
+ return PluginAppletViewer.javascriptToString(internal);
+ }
+
+
+ // should use some sort of identifier rather than String
+ // is "property" the right word?
+ // native String[] listProperties();
+
+
+ /**
+ * get a JSObject for the window containing the given applet
+ */
+ public static JSObject getWindow(Applet applet)
+ {
+ PluginDebug.debug("JSObject.getWindow");
+ // FIXME: handle long case as well.
+ long internal = 0;
+ internal = ((PluginAppletViewer)
+ applet.getAppletContext()).getWindow();
+ PluginDebug.debug ("GOT IT: " + internal);
+ return new JSObject((long) internal);
+ }
+
+
+ /**
+ * Finalization decrements the reference count on the corresponding
+ * JavaScript object.
+ */
+ protected void finalize()
+ {
+ PluginDebug.debug("JSObject.finalize ");
+ PluginAppletViewer.JavaScriptFinalize(internal);
+ }
+
+
+ /**
+ * Override java.lang.Object.equals() because identity is not preserved
+ * with instances of JSObject.
+ */
+ public boolean equals(Object obj)
+ {
+ PluginDebug.debug("JSObject.equals " + obj);
+
+ return false;
+ }
+}
diff --git a/plugin/icedteanp/java/netscape/javascript/JSObjectCreatePermission.java b/plugin/icedteanp/java/netscape/javascript/JSObjectCreatePermission.java
new file mode 100644
index 0000000..f8e510f
--- /dev/null
+++ b/plugin/icedteanp/java/netscape/javascript/JSObjectCreatePermission.java
@@ -0,0 +1,47 @@
+/* JSObjectCreatePermission.java
+ Copyright (C) 2009 Red Hat
+
+This file is part of IcedTea.
+
+IcedTea is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+IcedTea is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with IcedTea; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package netscape.javascript;
+
+import java.security.BasicPermission;
+
+
+public class JSObjectCreatePermission extends BasicPermission {
+ public JSObjectCreatePermission() {
+ super("JSObjectCreate");
+ }
+}
diff --git a/plugin/icedteanp/java/netscape/javascript/JSProxy.java b/plugin/icedteanp/java/netscape/javascript/JSProxy.java
new file mode 100644
index 0000000..e4f1f6e
--- /dev/null
+++ b/plugin/icedteanp/java/netscape/javascript/JSProxy.java
@@ -0,0 +1,58 @@
+/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/**
+ * The JSProxy interface allows applets and plugins to
+ * share javascript contexts.
+ */
+
+package netscape.javascript;
+import java.applet.Applet;
+
+public interface JSProxy {
+ Object getMember(JSObject jso, String name);
+ Object getSlot(JSObject jso, int index);
+ void setMember(JSObject jso, String name, Object value);
+ void setSlot(JSObject jso, int index, Object value);
+ void removeMember(JSObject jso, String name);
+ Object call(JSObject jso, String methodName, Object args[]);
+ Object eval(JSObject jso, String s);
+ String toString(JSObject jso);
+ JSObject getWindow(Applet applet);
+}
diff --git a/plugin/icedteanp/java/netscape/javascript/JSRunnable.java b/plugin/icedteanp/java/netscape/javascript/JSRunnable.java
new file mode 100644
index 0000000..8f1cf72
--- /dev/null
+++ b/plugin/icedteanp/java/netscape/javascript/JSRunnable.java
@@ -0,0 +1,72 @@
+/* -*- Mode: Java; tab-width: 8; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+package netscape.javascript;
+
+import sun.applet.PluginDebug;
+
+/**
+ * Runs a JavaScript object with a run() method in a separate thread.
+ */
+public class JSRunnable implements Runnable {
+ private JSObject runnable;
+
+ public JSRunnable(JSObject runnable) {
+ this.runnable = runnable;
+ synchronized(this) {
+ new Thread(this).start();
+ try {
+ this.wait();
+ } catch (InterruptedException ie) {
+ }
+ }
+ }
+
+ public void run() {
+ try {
+ runnable.call("run", null);
+ synchronized(this) {
+ notifyAll();
+ }
+ } catch (Throwable t) {
+ PluginDebug.debug(t.toString());
+ t.printStackTrace(System.err);
+ }
+ }
+}
diff --git a/plugin/icedteanp/java/netscape/javascript/JSUtil.java b/plugin/icedteanp/java/netscape/javascript/JSUtil.java
new file mode 100644
index 0000000..47bc6e6
--- /dev/null
+++ b/plugin/icedteanp/java/netscape/javascript/JSUtil.java
@@ -0,0 +1,59 @@
+/* -*- Mode: Java; tab-width: 8; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+/* ** */
+
+package netscape.javascript;
+import java.io.*;
+
+public class JSUtil {
+
+ /* Return the stack trace of an exception or error as a String */
+ public static String getStackTrace(Throwable t) {
+ ByteArrayOutputStream captureStream;
+ PrintWriter p;
+
+ captureStream = new ByteArrayOutputStream();
+ p = new PrintWriter(captureStream);
+
+ t.printStackTrace(p);
+ p.flush();
+
+ return captureStream.toString();
+ }
+}
diff --git a/plugin/icedteanp/java/netscape/security/ForbiddenTargetException.java b/plugin/icedteanp/java/netscape/security/ForbiddenTargetException.java
new file mode 100644
index 0000000..c7ce827
--- /dev/null
+++ b/plugin/icedteanp/java/netscape/security/ForbiddenTargetException.java
@@ -0,0 +1,52 @@
+/* ForbiddenTargetException.java
+ Copyright (C) 2010 Red Hat
+
+This file is part of IcedTea.
+
+IcedTea is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+IcedTea is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with IcedTea; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package netscape.security;
+
+public class ForbiddenTargetException extends RuntimeException{
+
+ private static final long serialVersionUID = 1271219852541058396L;
+
+ public ForbiddenTargetException() {
+ super();
+ }
+
+ public ForbiddenTargetException(String s) {
+ super(s);
+ }
+
+}
diff --git a/plugin/icedteanp/java/sun/applet/AppletSecurityContextManager.java b/plugin/icedteanp/java/sun/applet/AppletSecurityContextManager.java
new file mode 100644
index 0000000..3820aa4
--- /dev/null
+++ b/plugin/icedteanp/java/sun/applet/AppletSecurityContextManager.java
@@ -0,0 +1,71 @@
+/* VoidPluginCallRequest -- represent Java-to-JavaScript requests
+ Copyright (C) 2008 Red Hat
+
+This file is part of IcedTea.
+
+IcedTea is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+IcedTea is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with IcedTea; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package sun.applet;
+
+import java.security.AccessControlContext;
+import java.util.HashMap;
+
+public class AppletSecurityContextManager {
+
+ // Context identifier -> PluginAppletSecurityContext object.
+ // FIXME: make private
+ private static HashMap<Integer, PluginAppletSecurityContext> contexts = new HashMap();
+
+ public static void addContext(int identifier, PluginAppletSecurityContext context) {
+ contexts.put(identifier, context);
+ }
+
+ public static PluginAppletSecurityContext getSecurityContext(int identifier) {
+ return contexts.get(identifier);
+ }
+
+ public static void dumpStore(int identifier) {
+ contexts.get(identifier).dumpStore();
+ }
+
+ public static void handleMessage(int identifier, int reference, String src, String[] privileges, String message) {
+ PluginDebug.debug(identifier + " -- " + src + " -- " + reference + " -- " + message + " CONTEXT= " + contexts.get(identifier));
+ AccessControlContext callContext = null;
+
+ privileges = privileges != null ? privileges : new String[0];
+ callContext = contexts.get(identifier).getAccessControlContext(privileges, src);
+
+ contexts.get(identifier).handleMessage(reference, src, callContext, message);
+ }
+}
diff --git a/plugin/icedteanp/java/sun/applet/GetMemberPluginCallRequest.java b/plugin/icedteanp/java/sun/applet/GetMemberPluginCallRequest.java
new file mode 100644
index 0000000..7a0a623
--- /dev/null
+++ b/plugin/icedteanp/java/sun/applet/GetMemberPluginCallRequest.java
@@ -0,0 +1,63 @@
+/* GetMemberPluginCallRequest -- represent Java-to-JavaScript requests
+ Copyright (C) 2008 Red Hat
+
+This file is part of IcedTea.
+
+IcedTea is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+IcedTea is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with IcedTea; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package sun.applet;
+
+
+public class GetMemberPluginCallRequest extends PluginCallRequest {
+ Object object = null;
+
+ public GetMemberPluginCallRequest(String message, Long reference) {
+ super(message, reference);
+ PluginDebug.debug ("GetMemberPluginCall " + message);
+ }
+
+ public void parseReturn(String message) {
+ PluginDebug.debug ("GetMemberParseReturn GOT: " + message);
+ String[] args = message.split(" ");
+ // FIXME: Is it even possible to distinguish between null and void
+ // here?
+ if (args[3] != "null" && args[3] != "void")
+ object = AppletSecurityContextManager.getSecurityContext(0).getObject(Integer.parseInt(args[3]));
+ setDone(true);
+ }
+
+ public Object getObject() {
+ return this.object;
+ }
+}
+
diff --git a/plugin/icedteanp/java/sun/applet/GetWindowPluginCallRequest.java b/plugin/icedteanp/java/sun/applet/GetWindowPluginCallRequest.java
new file mode 100644
index 0000000..9c13726
--- /dev/null
+++ b/plugin/icedteanp/java/sun/applet/GetWindowPluginCallRequest.java
@@ -0,0 +1,65 @@
+/* GetWindowPluginCallRequest -- represent Java-to-JavaScript requests
+ Copyright (C) 2008 Red Hat
+
+This file is part of IcedTea.
+
+IcedTea is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+IcedTea is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with IcedTea; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package sun.applet;
+
+import java.security.AccessControlContext;
+import java.security.ProtectionDomain;
+
+
+
+public class GetWindowPluginCallRequest extends PluginCallRequest {
+ // FIXME: look into int vs long JavaScript internal values.
+ long internal;
+
+ public GetWindowPluginCallRequest(String message, Long reference) {
+ super(message, reference);
+ }
+
+ public void parseReturn(String message) {
+ PluginDebug.debug ("GetWindowParseReturn GOT: " + message);
+ String[] args = message.split(" ");
+ // FIXME: add thread ID to messages to support multiple
+ // threads using the netscape.javascript package.
+ internal = Long.parseLong(args[3]);
+ setDone(true);
+ }
+
+ public Long getObject() {
+ return this.internal;
+ }
+}
diff --git a/plugin/icedteanp/java/sun/applet/JavaConsole.java b/plugin/icedteanp/java/sun/applet/JavaConsole.java
new file mode 100644
index 0000000..768be7b
--- /dev/null
+++ b/plugin/icedteanp/java/sun/applet/JavaConsole.java
@@ -0,0 +1,365 @@
+/* JavaConsole -- A java console for the plugin
+ Copyright (C) 2009 Red Hat
+
+This file is part of IcedTea.
+
+IcedTea is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+IcedTea is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with IcedTea; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package sun.applet;
+
+import java.awt.Dimension;
+import java.awt.Font;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+
+import javax.swing.JButton;
+import javax.swing.JFrame;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JSplitPane;
+import javax.swing.JTextArea;
+import javax.swing.SwingUtilities;
+import javax.swing.UIManager;
+import javax.swing.border.EmptyBorder;
+import javax.swing.border.TitledBorder;
+
+/**
+ * A simple Java console for IcedTeaPlugin
+ *
+ */
+public class JavaConsole {
+
+ private boolean initialized = false;
+
+ JFrame consoleWindow;
+ JTextArea stdErrText;
+ JTextArea stdOutText;
+
+ /**
+ * Initialize the console
+ */
+ public void initialize() {
+
+ try {
+ UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ consoleWindow = new JFrame("Java Console");
+
+ JPanel contentPanel = new JPanel();
+ contentPanel.setLayout(new GridBagLayout());
+
+ GridBagConstraints c;
+
+ Font monoSpace = new Font("Monospaced", Font.PLAIN, 12);
+
+ /* std out */
+
+ stdOutText = new JTextArea();
+ JScrollPane stdOutScrollPane = new JScrollPane(stdOutText);
+ stdOutScrollPane.setBorder(new TitledBorder(
+ new EmptyBorder(5, 5, 5, 5), "System.out"));
+ stdOutText.setEditable(false);
+ stdOutText.setFont(monoSpace);
+
+ TextAreaUpdater stdOutUpdater = new TextAreaUpdater(new File(
+ PluginMain.PLUGIN_STDOUT_FILE), stdOutText);
+ stdOutUpdater.setName("IcedteaPlugin Console Thread(System.out)");
+
+ /* std err */
+
+ stdErrText = new JTextArea();
+ JScrollPane stdErrScrollPane = new JScrollPane(stdErrText);
+ stdErrScrollPane.setBorder(new TitledBorder(
+ new EmptyBorder(5, 5, 5, 5), "System.err"));
+ stdErrText.setEditable(false);
+ stdErrText.setFont(monoSpace);
+
+ TextAreaUpdater stdErrUpdater = new TextAreaUpdater(new File(
+ PluginMain.PLUGIN_STDERR_FILE), stdErrText);
+ stdErrUpdater.setName("IcedteaPlugin Console Thread(System.err)");
+
+ JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,
+ stdOutScrollPane, stdErrScrollPane);
+
+ c = new GridBagConstraints();
+ c.fill = GridBagConstraints.BOTH;
+ c.gridheight = 10;
+ c.weighty = 1;
+
+ contentPanel.add(splitPane, c);
+
+ /* buttons */
+
+ c = new GridBagConstraints();
+ c.gridy = 10;
+ c.gridheight = 1;
+ c.weightx = 0.5;
+ c.weighty = 0;
+
+ JPanel buttonPanel = new JPanel();
+ contentPanel.add(buttonPanel, c);
+
+ JButton gcButton = new JButton("Run GC");
+ buttonPanel.add(gcButton);
+ gcButton.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ printMemoryInfo();
+ System.out.print("Performing Garbage Collection....");
+ System.gc();
+ System.out.println("Done");
+ printMemoryInfo();
+ }
+
+ });
+
+ JButton finalizersButton = new JButton("Run Finalizers");
+ buttonPanel.add(finalizersButton);
+ finalizersButton.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ printMemoryInfo();
+ System.out.print("Running finalization....");
+ Runtime.getRuntime().runFinalization();
+ System.out.println("Done");
+ printMemoryInfo();
+ }
+ });
+
+ JButton memoryButton = new JButton("Memory Info");
+ buttonPanel.add(memoryButton);
+ memoryButton.addActionListener(new ActionListener() {
+
+ public void actionPerformed(ActionEvent e) {
+ printMemoryInfo();
+ }
+
+ });
+
+ JButton systemPropertiesButton = new JButton("System Properties");
+ buttonPanel.add(systemPropertiesButton);
+ systemPropertiesButton.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ printSystemProperties();
+ }
+
+ });
+
+ JButton classloadersButton = new JButton("Classloaders");
+ buttonPanel.add(classloadersButton);
+ classloadersButton.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ printClassLoaders();
+ }
+
+ });
+
+ JButton threadListButton = new JButton("Thread List");
+ buttonPanel.add(threadListButton);
+ threadListButton.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ printThreadInfo();
+ }
+
+ });
+
+ JButton closeButton = new JButton("Close");
+ buttonPanel.add(closeButton);
+ closeButton.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ SwingUtilities.invokeLater(new Runnable() {
+ public void run() {
+ hideConsole();
+ }
+ });
+ }
+ });
+
+ stdOutUpdater.start();
+ stdErrUpdater.start();
+
+ consoleWindow.add(contentPanel);
+ consoleWindow.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);
+ consoleWindow.pack();
+ consoleWindow.setSize(new Dimension(900, 600));
+ consoleWindow.setMinimumSize(new Dimension(900, 300));
+
+ initialized = true;
+
+ splitPane.setDividerLocation(0.5);
+ splitPane.setResizeWeight(0.5);
+ }
+
+ public void showConsole() {
+
+ if (!initialized) {
+ initialize();
+ }
+
+ consoleWindow.setVisible(true);
+ }
+
+ public void hideConsole() {
+ consoleWindow.setVisible(false);
+ }
+
+ protected void printSystemProperties() {
+
+ System.out.println(" ----");
+ System.out.println("System Properties:");
+ System.out.println();
+ Properties p = System.getProperties();
+ Set<Object> keys = p.keySet();
+ for (Object key : keys) {
+ System.out.println(key.toString() + ": " + p.get(key));
+ }
+
+ System.out.println(" ----");
+ }
+
+ private void printClassLoaders() {
+ System.out.println(" ----");
+ System.out.println("Available Classloaders: ");
+ Set<String> loaders = PluginAppletSecurityContext.getLoaderInfo().keySet();
+ for (String loader: loaders) {
+ System.out.println(loader + "\n"
+ + " codebase = "
+ + PluginAppletSecurityContext.getLoaderInfo().get(loader));
+ }
+ System.out.println(" ----");
+ }
+
+ private void printMemoryInfo() {
+ System.out.println(" ----- ");
+ System.out.println(" Memory Info:");
+ System.out.println(" Max Memory: "
+ + String.format("%1$10d", Runtime.getRuntime().maxMemory()));
+ System.out.println(" Total Memory: "
+ + String.format("%1$10d", Runtime.getRuntime().totalMemory()));
+ System.out.println(" Free Memory: "
+ + String.format("%1$10d", Runtime.getRuntime().freeMemory()));
+ System.out.println(" ----");
+
+ }
+
+ private void printThreadInfo() {
+ Map<Thread, StackTraceElement[]> map = Thread.getAllStackTraces();
+ Set<Thread> keys = map.keySet();
+ for (Thread key : keys) {
+ System.out.println("Thread " + key.getId() + ": " + key.getName());
+ for (StackTraceElement element : map.get(key)) {
+ System.out.println(" " + element);
+ }
+
+ }
+ }
+
+ public static void main(String[] args) {
+
+ final JavaConsole console = new JavaConsole();
+
+ boolean toShowConsole = false;
+
+ for (int i = 0; i < args.length; i++) {
+ if (args[i] == "--show-console") {
+ toShowConsole = true;
+ }
+ }
+
+ if (toShowConsole) {
+ SwingUtilities.invokeLater(new Runnable() {
+ public void run() {
+ console.showConsole();
+ }
+ });
+ }
+
+ }
+
+ /**
+ * This thread updates the text on a JTextArea based on the text in a file
+ */
+ class TextAreaUpdater extends Thread {
+
+ File fileToRead;
+ JTextArea outputTextArea;
+
+ public TextAreaUpdater(File file, JTextArea textArea) {
+ fileToRead = file;
+ outputTextArea = textArea;
+ setDaemon(true);
+ }
+
+ public void run() {
+
+ try {
+ BufferedReader reader = new BufferedReader(new FileReader(
+ fileToRead));
+ String line;
+ while (true) {
+ while ((line = reader.readLine()) != null) {
+ outputTextArea.insert(line + "\n", outputTextArea
+ .getDocument().getLength());
+ outputTextArea.setCaretPosition(outputTextArea
+ .getText().length());
+ }
+ Thread.sleep(1000);
+ }
+
+ } catch (FileNotFoundException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ } catch (IOException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ Thread.currentThread().interrupt();
+ }
+
+ }
+
+ }
+
+}
diff --git a/plugin/icedteanp/java/sun/applet/MethodOverloadResolver.java b/plugin/icedteanp/java/sun/applet/MethodOverloadResolver.java
new file mode 100644
index 0000000..bb41e27
--- /dev/null
+++ b/plugin/icedteanp/java/sun/applet/MethodOverloadResolver.java
@@ -0,0 +1,696 @@
+/* MethodOverloadResolver -- Resolves overloaded methods
+ Copyright (C) 2009 Red Hat
+
+This file is part of IcedTea.
+
+IcedTea is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+IcedTea is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with IcedTea; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package sun.applet;
+
+import java.lang.reflect.Array;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+
+/*
+ * This class resolved overloaded methods in Java objects using a cost
+ * based-approach as described here:
+ *
+ * http://java.sun.com/javase/6/webnotes/6u10/plugin2/liveconnect/#OVERLOADED_METHODS
+ */
+
+public class MethodOverloadResolver {
+
+ private static boolean debugging = false;
+
+ public static void main(String[] args) {
+ testMethodResolver();
+ }
+
+ public static void testMethodResolver() {
+ debugging = true;
+
+ ArrayList<Object[]> list = new ArrayList<Object[]>(20);
+ FooClass fc = new FooClass();
+
+ // Numeric to java primitive
+ // foo_i has Integer and int params
+ String s1 = "foo_string_int(S,I)";
+ String s1a = "foo_string_int(S,S)";
+ Object[] o1 = { fc.getClass(), "foo_string_int", "blah", 42 };
+ list.add(o1);
+ Object[] o1a = { fc.getClass(), "foo_string_int", "blah", "42.42" };
+ list.add(o1a);
+
+ // Null to non-primitive type
+ // foo_i is overloaded with Integer and int
+ String s2 = "foo_string_int(N)";
+ Object[] o2 = { fc.getClass(), "foo_string_int", "blah", null };
+ list.add(o2);
+
+ // foo_jsobj is overloaded with JSObject and String params
+ String s3 = "foo_jsobj(LLowCostSignatureComputer/JSObject;)";
+ Object[] o3 = { fc.getClass(), "foo_jsobj", new JSObject() };
+ list.add(o3);
+
+ // foo_classtype is overloaded with Number and Integer
+ String s4 = "foo_classtype(Ljava/lang/Integer;)";
+ Object[] o4 = { fc.getClass(), "foo_classtype", 42 };
+ list.add(o4);
+
+ // foo_multiprim is overloaded with int, long and float types
+ String s5 = "foo_multiprim(I)";
+ String s6 = "foo_multiprim(F)";
+ String s6a = "foo_multiprim(D)";
+
+ Object[] o5 = { fc.getClass(), "foo_multiprim", new Integer(42) };
+ Object[] o6 = { fc.getClass(), "foo_multiprim", new Float(42.42) };
+ Object[] o6a = { fc.getClass(), "foo_multiprim", new Double(42.42) };
+ list.add(o5);
+ list.add(o6);
+ list.add(o6a);
+
+ // foo_float has float, String and JSObject type
+ String s7 = "foo_float(I)";
+ Object[] o7 = { fc.getClass(), "foo_float", new Integer(42) };
+ list.add(o7);
+
+ // foo_multiprim(float) is what this should convert
+ String s8 = "foo_float(S)";
+ Object[] o8 = { fc.getClass(), "foo_float", "42" };
+ list.add(o8);
+
+ // foo_class is overloaded with BarClass 2 and 3
+ String s9 = "foo_class(LLowCostSignatureComputer/BarClass3;)";
+ Object[] o9 = { fc.getClass(), "foo_class", new BarClass3() };
+ list.add(o9);
+
+ // foo_strandbyteonly takes string and byte
+ String s10 = "foo_strandbyteonly(I)";
+ Object[] o10 = { fc.getClass(), "foo_strandbyteonly", 42 };
+ list.add(o10);
+
+ // JSOBject to string
+ String s11 = "foo_strandbyteonly(LLowCostSignatureComputer/JSObject;)";
+ Object[] o11 = { fc.getClass(), "foo_strandbyteonly", new JSObject() };
+ list.add(o11);
+
+ // jsobject to string and int to float
+ String s12 = "foo_str_and_float(S,I)";
+ Object[] o12 = { fc.getClass(), "foo_str_and_float", new JSObject(), new Integer(42) };
+ list.add(o12);
+
+ // call for which no match will be found
+ String s13 = "foo_int_only(JSObject)";
+ Object[] o13 = { fc.getClass(), "foo_int_only", new JSObject() };
+ list.add(o13);
+
+ // method with no args
+ String s14 = "foo_noargs()";
+ Object[] o14 = { fc.getClass(), "foo_noargs" };
+ list.add(o14);
+
+ // method which takes a primitive bool, given a Boolean
+ String s15 = "foo_boolonly()";
+ Object[] o15 = { fc.getClass(), "foo_boolonly", new Boolean(true) };
+ list.add(o15);
+
+ for (Object[] o : list) {
+ Object[] methodAndArgs = getMatchingMethod(o);
+ if (debugging)
+ if (methodAndArgs != null)
+ System.out.println("Best match: " + methodAndArgs[0] + "\n");
+ else
+ System.out.println("No match found.\n");
+
+ }
+
+ }
+
+ /*
+ * Cost based overload resolution algorithm based on cost rules specified here:
+ *
+ * http://java.sun.com/javase/6/webnotes/6u10/plugin2/liveconnect/#OVERLOADED_METHODS
+ */
+
+ public static Object[] getMatchingMethod(Object[] callList) {
+ Object[] ret = null;
+ Class c = (Class) callList[0];
+ String methodName = (String) callList[1];
+
+ Method[] matchingMethods = getMatchingMethods(c, methodName, callList.length - 2);
+
+ if (debugging)
+ System.out.println("getMatchingMethod called with: " + printList(callList));
+
+ int lowestCost = Integer.MAX_VALUE;
+
+ ArrayList<Object> paramList = new ArrayList<Object>();
+
+ for (Method matchingMethod : matchingMethods) {
+
+ int methodCost = 0;
+ Class[] paramTypes = matchingMethod.getParameterTypes();
+ Object[] methodAndArgs = new Object[paramTypes.length + 1];
+ methodAndArgs[0] = matchingMethod;
+
+ // Figure out which of the matched methods best represents what we
+ // want
+ for (int i = 0; i < paramTypes.length; i++) {
+ Class paramTypeClass = paramTypes[i];
+ Object suppliedParam = callList[i + 2];
+ Class suppliedParamClass = suppliedParam != null ? suppliedParam
+ .getClass()
+ : null;
+
+ Object[] costAndCastedObj = getCostAndCastedObject(
+ suppliedParam, paramTypeClass);
+ methodCost += (Integer) costAndCastedObj[0];
+
+ if ((Integer) costAndCastedObj[0] < 0) break;
+
+ Object castedObj = paramTypeClass.isPrimitive() ? costAndCastedObj[1]
+ : paramTypeClass.cast(costAndCastedObj[1]);
+ methodAndArgs[i + 1] = castedObj;
+
+ Class castedObjClass = castedObj == null ? null : castedObj
+ .getClass();
+ Boolean castedObjIsPrim = castedObj == null ? null : castedObj
+ .getClass().isPrimitive();
+
+ if (debugging)
+ System.out.println("Param " + i + " of method "
+ + matchingMethod + " has cost "
+ + (Integer) costAndCastedObj[0]
+ + " original param type " + suppliedParamClass
+ + " casted to " + castedObjClass + " isPrimitive="
+ + castedObjIsPrim + " value " + castedObj);
+ }
+
+ if ((methodCost > 0 && methodCost < lowestCost) ||
+ paramTypes.length == 0) {
+ ret = methodAndArgs;
+ lowestCost = methodCost;
+ }
+
+ }
+
+ return ret;
+ }
+
+ public static Object[] getMatchingConstructor(Object[] callList) {
+ Object[] ret = null;
+ Class c = (Class) callList[0];
+
+ Constructor[] matchingConstructors = getMatchingConstructors(c, callList.length - 1);
+
+ if (debugging)
+ System.out.println("getMatchingConstructor called with: " + printList(callList));
+
+ int lowestCost = Integer.MAX_VALUE;
+
+ ArrayList<Object> paramList = new ArrayList<Object>();
+
+ for (Constructor matchingConstructor : matchingConstructors) {
+
+ int constructorCost = 0;
+ Class[] paramTypes = matchingConstructor.getParameterTypes();
+ Object[] constructorAndArgs = new Object[paramTypes.length + 1];
+ constructorAndArgs[0] = matchingConstructor;
+
+ // Figure out which of the matched methods best represents what we
+ // want
+ for (int i = 0; i < paramTypes.length; i++) {
+ Class paramTypeClass = paramTypes[i];
+ Object suppliedParam = callList[i + 1];
+ Class suppliedParamClass = suppliedParam != null ? suppliedParam
+ .getClass()
+ : null;
+
+ Object[] costAndCastedObj = getCostAndCastedObject(
+ suppliedParam, paramTypeClass);
+ constructorCost += (Integer) costAndCastedObj[0];
+
+ if ((Integer) costAndCastedObj[0] < 0) break;
+
+ Object castedObj = paramTypeClass.isPrimitive() ? costAndCastedObj[1]
+ : paramTypeClass.cast(costAndCastedObj[1]);
+ constructorAndArgs[i + 1] = castedObj;
+
+ Class castedObjClass = castedObj == null ? null : castedObj
+ .getClass();
+ Boolean castedObjIsPrim = castedObj == null ? null : castedObj
+ .getClass().isPrimitive();
+
+ if (debugging)
+ System.out.println("Param " + i + " of constructor "
+ + matchingConstructor + " has cost "
+ + (Integer) costAndCastedObj[0]
+ + " original param type " + suppliedParamClass
+ + " casted to " + castedObjClass + " isPrimitive="
+ + castedObjIsPrim + " value " + castedObj);
+ }
+
+ if ((constructorCost > 0 && constructorCost < lowestCost) ||
+ paramTypes.length == 0) {
+ ret = constructorAndArgs;
+ lowestCost = constructorCost;
+ }
+ }
+
+ return ret;
+ }
+
+ public static Object[] getCostAndCastedObject(Object suppliedParam, Class paramTypeClass) {
+
+ Object[] ret = new Object[2];
+ Integer cost = new Integer(0);
+ Object castedObj;
+
+ Class suppliedParamClass = suppliedParam != null ? suppliedParam.getClass() : null ;
+
+ // Either both are an array, or neither are
+ boolean suppliedParamIsArray = suppliedParamClass != null && suppliedParamClass.isArray();
+ if (paramTypeClass.isArray() != suppliedParamIsArray &&
+ !paramTypeClass.equals(Object.class) &&
+ !paramTypeClass.equals(String.class)) {
+ ret[0] = Integer.MIN_VALUE; // Not allowed
+ ret[1] = suppliedParam;
+ return ret;
+ }
+
+ // If param type is an array, supplied obj must be an array, Object or String (guaranteed by checks above)
+ // If it is an array, we need to copy/cast as we scan the array
+ // If it an object, we return "as is" [Everything can be narrowed to an object, cost=6]
+ // If it is a string, we need to convert according to the JS engine rules
+
+ if (paramTypeClass.isArray()) {
+
+ Object newArray = Array.newInstance(paramTypeClass.getComponentType(), Array.getLength(suppliedParam));
+ for (int i=0; i < Array.getLength(suppliedParam); i++) {
+ Object original = Array.get(suppliedParam, i);
+
+ // When dealing with arrays, we represent empty slots with
+ // null. We need to convert this to 0 before recursive
+ // calling, since normal transformation does not allow
+ // null -> primitive
+
+ if (original == null && paramTypeClass.getComponentType().isPrimitive())
+ original = 0;
+
+ Object[] costAndCastedObject = getCostAndCastedObject(original, paramTypeClass.getComponentType());
+
+ if ((Integer) costAndCastedObject[0] < 0) {
+ ret[0] = Integer.MIN_VALUE; // Not allowed
+ ret[1] = suppliedParam;
+ return ret;
+ }
+
+ Array.set(newArray, i, costAndCastedObject[1]);
+ }
+
+ ret[0] = 9;
+ ret[1] = newArray;
+ return ret;
+ }
+
+ if (suppliedParamIsArray && paramTypeClass.equals(String.class)) {
+
+ ret[0] = 9;
+ ret[1] = getArrayAsString(suppliedParam);
+ return ret;
+ }
+
+ // If this is null, there are only 2 possible cases
+ if (suppliedParamClass == null) {
+ castedObj = null; // if value is null.. well, it is null
+
+ if (!paramTypeClass.isPrimitive()) {
+ cost += 2; // Null to any non-primitive type
+ } else {
+ cost = Integer.MIN_VALUE; // Null to primitive not allowed
+ }
+ } else if (paramTypeClass.isPrimitive() && paramTypeClass.equals(getPrimitive(suppliedParam))) {
+ cost += 1; // Numeric type to the analogous Java primitive type
+ castedObj = suppliedParam; // Let auto-boxing handle it
+ } else if (suppliedParamClass.equals(paramTypeClass)) {
+ cost += 3; // Class type to Class type where the types are equal
+ castedObj = suppliedParam;
+ } else if (isNum(suppliedParam) &&
+ (paramTypeClass.isPrimitive() ||
+ java.lang.Number.class.isAssignableFrom(paramTypeClass) ||
+ java.lang.Character.class.isAssignableFrom(paramTypeClass) ||
+ java.lang.Byte.class.isAssignableFrom(paramTypeClass)
+ )
+ ) {
+ cost += 4; // Numeric type to a different primitive type
+
+ if (suppliedParam.toString().equals("true"))
+ suppliedParam = "1";
+ else if (suppliedParam.toString().equals("false"))
+ suppliedParam = "0";
+
+ if (paramTypeClass.equals(Boolean.TYPE))
+ castedObj = getNum(suppliedParam.toString(), paramTypeClass).doubleValue() != 0D;
+ else if (paramTypeClass.equals(Character.TYPE))
+ castedObj = (char) Short.decode(suppliedParam.toString()).shortValue();
+ else
+ castedObj = getNum(suppliedParam.toString(), paramTypeClass);
+ } else if (suppliedParam instanceof java.lang.String &&
+ isNum(suppliedParam) &&
+ (paramTypeClass.isInstance(java.lang.Number.class) ||
+ paramTypeClass.isInstance(java.lang.Character.class) ||
+ paramTypeClass.isInstance(java.lang.Byte.class) ||
+ paramTypeClass.isPrimitive())
+ ) {
+ cost += 5; // String to numeric type
+
+ if (suppliedParam.toString().equals("true"))
+ suppliedParam = "1";
+ else if (suppliedParam.toString().equals("false"))
+ suppliedParam = "0";
+
+ if (paramTypeClass.equals(Character.TYPE))
+ castedObj = (char) Short.decode(suppliedParam.toString()).shortValue();
+ else
+ castedObj = getNum(suppliedParam.toString(), paramTypeClass);
+ } else if (suppliedParam instanceof java.lang.String &&
+ (paramTypeClass.equals(java.lang.Boolean.class) ||
+ paramTypeClass.equals(java.lang.Boolean.TYPE))
+ ){
+
+ cost += 5; // Same cost as above
+ castedObj = new Boolean(suppliedParam.toString().length() > 0);
+ } else if (paramTypeClass.isAssignableFrom(suppliedParamClass)) {
+ cost += 6; // Class type to superclass type;
+ castedObj = paramTypeClass.cast(suppliedParam);
+ } else if (paramTypeClass.equals(String.class)) {
+ cost += 7; // Any Java value to String
+ castedObj = suppliedParam.toString();
+ } else if (suppliedParam instanceof JSObject &&
+ paramTypeClass.isArray()) {
+ cost += 8; // JSObject to Java array
+ castedObj = (JSObject) suppliedParam;
+ } else {
+ cost = Integer.MIN_VALUE; // Not allowed
+ castedObj = suppliedParam;
+ }
+
+ ret[0] = cost;
+ ret[1] = castedObj;
+
+ return ret;
+
+ }
+
+ private static Method[] getMatchingMethods(Class c, String name, int paramCount) {
+ Method[] allMethods = c.getMethods();
+ ArrayList<Method> matchingMethods = new ArrayList(5);
+
+ for (Method m: allMethods) {
+ if (m.getName().equals(name) && m.getParameterTypes().length == paramCount)
+ matchingMethods.add(m);
+ }
+
+ return matchingMethods.toArray(new Method[0]);
+ }
+
+ private static Constructor[] getMatchingConstructors(Class c, int paramCount) {
+ Constructor[] allConstructors = c.getConstructors();
+ ArrayList<Constructor> matchingConstructors = new ArrayList<Constructor>(5);
+
+ for (Constructor cs: allConstructors) {
+ if (cs.getParameterTypes().length == paramCount)
+ matchingConstructors.add(cs);
+ }
+
+ return matchingConstructors.toArray(new Constructor[0]);
+ }
+
+ private static Class getPrimitive(Object o) {
+
+ if (o instanceof java.lang.Byte) {
+ return java.lang.Byte.TYPE;
+ } else if (o instanceof java.lang.Character) {
+ return java.lang.Character.TYPE;
+ } else if (o instanceof java.lang.Short) {
+ return java.lang.Short.TYPE;
+ } else if (o instanceof java.lang.Integer) {
+ return java.lang.Integer.TYPE;
+ } else if (o instanceof java.lang.Long) {
+ return java.lang.Long.TYPE;
+ } else if (o instanceof java.lang.Float) {
+ return java.lang.Float.TYPE;
+ } else if (o instanceof java.lang.Double) {
+ return java.lang.Double.TYPE;
+ } else if (o instanceof java.lang.Boolean) {
+ return java.lang.Boolean.TYPE;
+ }
+
+ return o.getClass();
+ }
+
+ private static boolean isNum (Object o) {
+
+ if (o instanceof java.lang.Number)
+ return true;
+
+ // Boolean is changeable to number as well
+ if (o instanceof java.lang.Boolean)
+ return true;
+
+ // At this point, it _has_ to be a string else automatically
+ // return false
+ if (!(o instanceof java.lang.String))
+ return false;
+
+ try {
+ Long.parseLong((String) o); // whole number test
+ return true;
+ } catch (NumberFormatException nfe) {}
+
+ try {
+ Float.parseFloat((String) o); // decimal
+ return true;
+ } catch (NumberFormatException nfe) {}
+
+
+ return false;
+ }
+
+ private static Number getNum (String s, Class c) throws NumberFormatException {
+
+ Number n;
+ if (s.contains("."))
+ n = new Double(s);
+ else
+ n = new Long(s);
+
+ // See if we need to collapse first
+ if (c.equals(java.lang.Integer.class) ||
+ c.equals(java.lang.Integer.TYPE)) {
+ return n.intValue();
+ }
+
+ if (c.equals(java.lang.Long.class) ||
+ c.equals(java.lang.Long.TYPE)) {
+ return n.longValue();
+ }
+
+ if (c.equals(java.lang.Short.class) ||
+ c.equals(java.lang.Short.TYPE)) {
+ return n.shortValue();
+ }
+
+ if (c.equals(java.lang.Float.class) ||
+ c.equals(java.lang.Float.TYPE)) {
+ return n.floatValue();
+ }
+
+ if (c.equals(java.lang.Double.class) ||
+ c.equals(java.lang.Double.TYPE)) {
+ return n.doubleValue();
+ }
+
+ if (c.equals(java.lang.Byte.class) ||
+ c.equals(java.lang.Byte.TYPE)) {
+ return n.byteValue();
+ }
+
+ return n;
+ }
+
+ private static String printList (Object[] oList) {
+
+ String ret = "";
+
+ ret += "{ ";
+ for (Object o : oList) {
+
+ String oStr = o != null ? o.toString() + " [" + o.getClass() + "]" : "null";
+
+ ret += oStr;
+ ret += ", ";
+ }
+ ret = ret.substring(0, ret.length()-2); // remove last ", "
+ ret += " }";
+
+ return ret;
+ }
+
+ private static String getArrayAsString(Object array) {
+ // We are guaranteed that supplied object is a String
+
+ String ret = new String();
+
+ for (int i=0; i < Array.getLength(array); i++) {
+ Object element = Array.get(array, i);
+
+ if (element != null) {
+ if (element.getClass().isArray()) {
+ ret += getArrayAsString(element);
+ } else {
+ ret += element;
+ }
+ }
+
+ ret += ",";
+ }
+
+ // Trim the final ","
+ if (ret.length() > 0) {
+ ret = ret.substring(0, ret.length() - 1);
+ }
+
+ return ret;
+ }
+}
+
+/** Begin test classes **/
+
+class FooClass {
+
+ public FooClass() {}
+
+ public FooClass(Boolean b, int i) {}
+
+ public FooClass(Boolean b, Integer i) {}
+
+ public FooClass(Boolean b, short s) {}
+
+ public FooClass(String s, int i) {}
+
+ public FooClass(String s, Integer i) {}
+
+ public FooClass(java.lang.Number num) {}
+
+ public FooClass(java.lang.Integer integer) {}
+
+ public FooClass(long l) {}
+
+ public FooClass(double d) {}
+
+ public FooClass(float f) {}
+
+ public FooClass(JSObject j) {}
+
+ public FooClass(BarClass1 b) {}
+
+ public FooClass(BarClass2 b) {}
+
+ public FooClass(String s) {}
+
+ public FooClass(byte b) {}
+
+ public FooClass(String s, Float f) {}
+
+ public FooClass (int i) {}
+
+ public void FooClass() {}
+
+ public void FooClass(boolean b) {}
+
+
+ public void foo(Boolean b, int i) {}
+
+ public void foo(Boolean b, Integer i) {}
+
+ public void foo(Boolean b, short s) {}
+
+ public void foo_string_int(String s, int i) {}
+
+ public void foo_string_int(String s, Integer i) {}
+
+ public void foo_jsobj(JSObject j) {}
+
+ public void foo_jsobj(String s) {}
+
+ public void foo_classtype(java.lang.Number num) {}
+
+ public void foo_classtype(java.lang.Integer integer) {}
+
+ public void foo_multiprim(int i) {}
+
+ public void foo_multiprim(long l) {}
+
+ public void foo_multiprim(float f) {}
+
+ public void foo_multiprim(double d) {}
+
+ public void foo_float(float f) {}
+
+ public void foo_float(String s) {}
+
+ public void foo_float(JSObject j) {}
+
+ public void foo_class(BarClass1 b) {}
+
+ public void foo_class(BarClass2 b) {}
+
+ public void foo_strandbyteonly(String s) {}
+
+ public void foo_strandbyteonly(byte b) {}
+
+ public void foo_str_and_float(String s, Float f) {}
+
+ public void foo_int_only (int i) {}
+
+ public void foo_noargs() {}
+
+ public void foo_boolonly(boolean b) {}
+}
+
+class BarClass1 {}
+class BarClass2 extends BarClass1 {}
+class BarClass3 extends BarClass2 {}
+class JSObject {}
diff --git a/plugin/icedteanp/java/sun/applet/PasswordAuthenticationDialog.java b/plugin/icedteanp/java/sun/applet/PasswordAuthenticationDialog.java
new file mode 100644
index 0000000..843603e
--- /dev/null
+++ b/plugin/icedteanp/java/sun/applet/PasswordAuthenticationDialog.java
@@ -0,0 +1,241 @@
+/* PasswordAuthenticationDialog -- requests authentication information from users
+ Copyright (C) 2009 Red Hat
+
+This file is part of IcedTea.
+
+IcedTea is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+IcedTea is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with IcedTea; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package sun.applet;
+
+import java.awt.Dimension;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.Insets;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.net.PasswordAuthentication;
+
+import javax.swing.JButton;
+import javax.swing.JDialog;
+import javax.swing.JLabel;
+import javax.swing.JPasswordField;
+import javax.swing.JTextField;
+import javax.swing.SwingUtilities;
+
+/**
+ * Modal non-minimizable dialog to request http authentication credentials
+ */
+
+public class PasswordAuthenticationDialog extends JDialog {
+
+ private JLabel jlInfo = new JLabel("");
+ private JTextField jtfUserName = new JTextField();
+ private JPasswordField jpfPassword = new JPasswordField();
+ private boolean userCancelled;
+
+ public PasswordAuthenticationDialog() {
+ initialize();
+ }
+
+ /**
+ * Initialized the dialog components
+ */
+
+ public void initialize() {
+
+ setTitle("IcedTea Java Plugin - Authorization needed to proceed");
+
+ setLayout(new GridBagLayout());
+
+ JLabel jlUserName = new JLabel("Username: ");
+ JLabel jlPassword = new JLabel("Password: ");
+ JButton jbOK = new JButton("OK");
+ JButton jbCancel = new JButton("Cancel");
+
+ jtfUserName.setSize(20, 10);
+ jpfPassword.setSize(20, 10);
+
+ GridBagConstraints c;
+
+ c = new GridBagConstraints();
+ c.fill = c.HORIZONTAL;
+ c.gridx = 0;
+ c.gridy = 0;
+ c.gridwidth = 2;
+ c.insets = new Insets(10, 5, 3, 3);
+ add(jlInfo, c);
+
+ c = new GridBagConstraints();
+ c.gridx = 0;
+ c.gridy = 1;
+ c.insets = new Insets(10, 5, 3, 3);
+ add(jlUserName, c);
+
+ c = new GridBagConstraints();
+ c.fill = c.HORIZONTAL;
+ c.gridx = 1;
+ c.gridy = 1;
+ c.insets = new Insets(10, 5, 3, 3);
+ c.weightx = 1.0;
+ add(jtfUserName, c);
+
+
+ c = new GridBagConstraints();
+ c.gridx = 0;
+ c.gridy = 2;
+ c.insets = new Insets(5, 5, 3, 3);
+ add(jlPassword, c);
+
+ c = new GridBagConstraints();
+ c.fill = c.HORIZONTAL;
+ c.gridx = 1;
+ c.gridy = 2;
+ c.insets = new Insets(5, 5, 3, 3);
+ c.weightx = 1.0;
+ add(jpfPassword, c);
+
+ c = new GridBagConstraints();
+ c.anchor = c.SOUTHEAST;
+ c.gridx = 1;
+ c.gridy = 3;
+ c.insets = new Insets(5, 5, 3, 70);
+ c.weightx = 0.0;
+ add(jbCancel, c);
+
+ c = new GridBagConstraints();
+ c.anchor = c.SOUTHEAST;
+ c.gridx = 1;
+ c.gridy = 3;
+ c.insets = new Insets(5, 5, 3, 3);
+ c.weightx = 0.0;
+ add(jbOK, c);
+
+ setMinimumSize(new Dimension(400,150));
+ setMaximumSize(new Dimension(1024,150));
+ setAlwaysOnTop(true);
+
+ setSize(400,150);
+ setLocationRelativeTo(null);
+
+ // OK => read supplied info and pass it on
+ jbOK.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ userCancelled = false;
+ dispose();
+ }
+ });
+
+ // Cancel => discard supplied info and pass on an empty auth
+ jbCancel.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ userCancelled = true;
+ dispose();
+ }
+ });
+
+ // "return" key in either user or password field => OK
+
+ jtfUserName.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ userCancelled = false;
+ dispose();
+ }
+ });
+
+ jpfPassword.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ userCancelled = false;
+ dispose();
+ }
+ });
+ }
+
+ /**
+ * Present a dialog to the user asking them for authentication information
+ *
+ * @param hostThe host for with authentication is needed
+ * @param port The port being accessed
+ * @param prompt The prompt (realm) as presented by the server
+ * @param type The type of server (proxy/web)
+ * @return PasswordAuthentication containing the credentials (empty credentials if user cancelled)
+ */
+ protected PasswordAuthentication askUser(String host, int port, String prompt, String type) {
+ PasswordAuthentication auth = null;
+
+ host += port != -1 ? ":" + port : "";
+
+ // This frame is reusable. So reset everything first.
+ userCancelled = true;
+ jlInfo.setText("<html>The " + type + " server at " + host + " is requesting authentication. It says \"" + prompt + "\"</html>");
+
+ try {
+ SwingUtilities.invokeAndWait( new Runnable() {
+ public void run() {
+ // show dialog to user
+ setVisible(true);
+ }
+ });
+
+ PluginDebug.debug("password dialog shown");
+
+ // wait until dialog is gone
+ while (this.isShowing()) {
+ try {
+ Thread.sleep(200);
+ } catch (InterruptedException ie) {
+ }
+ }
+
+ PluginDebug.debug("password dialog closed");
+
+ if (!userCancelled) {
+ auth = new PasswordAuthentication(jtfUserName.getText(), jpfPassword.getText().toCharArray());
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+
+ // Nothing else we can do. Empty auth will be returned
+ }
+
+ return auth;
+ }
+
+ public static void main(String[] args) {
+ PasswordAuthenticationDialog frame = new PasswordAuthenticationDialog();
+
+ PasswordAuthentication auth = frame.askUser("127.0.0.1", 3128, "Password for local proxy", "proxy");
+
+ System.err.println("Auth info: " + auth.getUserName() + ":" + new String(auth.getPassword()));
+ System.exit(0);
+ }
+}
diff --git a/plugin/icedteanp/java/sun/applet/PluginAppletSecurityContext.java b/plugin/icedteanp/java/sun/applet/PluginAppletSecurityContext.java
new file mode 100644
index 0000000..bef2bd8
--- /dev/null
+++ b/plugin/icedteanp/java/sun/applet/PluginAppletSecurityContext.java
@@ -0,0 +1,1505 @@
+/* PluginAppletSecurityContext -- execute plugin JNI messages
+ Copyright (C) 2008 Red Hat
+
+This file is part of IcedTea.
+
+IcedTea is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+IcedTea is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with IcedTea; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package sun.applet;
+
+import java.io.File;
+import java.lang.reflect.Array;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.security.AccessControlContext;
+import java.security.AccessControlException;
+import java.security.AccessController;
+import java.security.AllPermission;
+import java.security.BasicPermission;
+import java.security.CodeSource;
+import java.security.Permissions;
+import java.security.PrivilegedAction;
+import java.security.ProtectionDomain;
+import java.text.DecimalFormat;
+import java.util.ArrayList;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Map;
+
+import javax.swing.text.html.HTMLDocument.HTMLReader.IsindexAction;
+
+import net.sourceforge.jnlp.runtime.JNLPRuntime;
+import netscape.javascript.JSObjectCreatePermission;
+
+
+
+class Signature {
+ private String signature;
+ private int currentIndex;
+ private List<Class> typeList;
+ private static final char ARRAY = '[';
+ private static final char OBJECT = 'L';
+ private static final char SIGNATURE_ENDCLASS = ';';
+ private static final char SIGNATURE_FUNC = '(';
+ private static final char SIGNATURE_ENDFUNC = ')';
+ private static final char VOID = 'V';
+ private static final char BOOLEAN = 'Z';
+ private static final char BYTE = 'B';
+ private static final char CHARACTER = 'C';
+ private static final char SHORT = 'S';
+ private static final char INTEGER = 'I';
+ private static final char LONG = 'J';
+ private static final char FLOAT = 'F';
+ private static final char DOUBLE = 'D';
+
+ private String nextTypeName() {
+ char key = signature.charAt(currentIndex++);
+
+ switch (key) {
+ case ARRAY:
+ return nextTypeName() + "[]";
+
+ case OBJECT:
+ int endClass = signature.indexOf(SIGNATURE_ENDCLASS, currentIndex);
+ String retVal = signature.substring(currentIndex, endClass);
+ retVal = retVal.replace('/', '.');
+ currentIndex = endClass + 1;
+ return retVal;
+
+ // FIXME: generated bytecode with classes named after
+ // primitives will not work in this scheme -- those
+ // classes will be incorrectly treated as primitive
+ // types.
+ case VOID:
+ return "void";
+ case BOOLEAN:
+ return "boolean";
+ case BYTE:
+ return "byte";
+ case CHARACTER:
+ return "char";
+ case SHORT:
+ return "short";
+ case INTEGER:
+ return "int";
+ case LONG:
+ return "long";
+ case FLOAT:
+ return "float";
+ case DOUBLE:
+ return "double";
+
+ case SIGNATURE_ENDFUNC:
+ return null;
+
+ case SIGNATURE_FUNC:
+ return nextTypeName();
+
+ default:
+ throw new IllegalArgumentException(
+ "Invalid JNI signature character '" + key + "'");
+ }
+ }
+
+ public Signature(String signature, ClassLoader cl) {
+ this.signature = signature;
+ currentIndex = 0;
+ typeList = new ArrayList<Class>(10);
+
+ String elem;
+ while (currentIndex < signature.length()) {
+ elem = nextTypeName();
+
+ if (elem == null) // end of signature
+ continue;
+
+ // System.out.println ("NEXT TYPE: " + elem);
+ Class primitive = primitiveNameToType(elem);
+ if (primitive != null)
+ typeList.add(primitive);
+ else {
+ // System.out.println ("HERE1");
+ int dimsize = 0;
+ int n = elem.indexOf('[');
+ if (n != -1) {
+ // System.out.println ("HERE2");
+ String arrayType = elem.substring(0, n);
+ dimsize++;
+ n = elem.indexOf('[', n + 1);
+ // System.out.println ("HERE2.5");
+ while (n != -1) {
+ dimsize++;
+ n = elem.indexOf('[', n + 1);
+ // System.out.println ("HERE2.8");
+ }
+ int[] dims = new int[dimsize];
+ primitive = primitiveNameToType(arrayType);
+ // System.out.println ("HERE3");
+ if (primitive != null) {
+ typeList.add(Array.newInstance(primitive, dims)
+ .getClass());
+ // System.out.println ("HERE4");
+ } else
+ typeList.add(Array.newInstance(
+ getClass(arrayType, cl), dims).getClass());
+ } else {
+ typeList.add(getClass(elem, cl));
+ }
+ }
+ }
+ if (signature.length() < 2) {
+ throw new IllegalArgumentException("Invalid JNI signature '"
+ + signature + "'");
+ }
+ }
+
+ public static Class getClass(String name, ClassLoader cl) {
+
+ Class c = null;
+
+ try {
+ c = Class.forName(name);
+ } catch (ClassNotFoundException cnfe) {
+
+ PluginDebug.debug("Class " + name + " not found in primordial loader. Looking in " + cl);
+ try {
+ c = cl.loadClass(name);
+ } catch (ClassNotFoundException e) {
+ throw (new RuntimeException(new ClassNotFoundException("Unable to find class " + name)));
+ }
+ }
+
+ return c;
+ }
+
+ public static Class primitiveNameToType(String name) {
+ if (name.equals("void"))
+ return Void.TYPE;
+ else if (name.equals("boolean"))
+ return Boolean.TYPE;
+ else if (name.equals("byte"))
+ return Byte.TYPE;
+ else if (name.equals("char"))
+ return Character.TYPE;
+ else if (name.equals("short"))
+ return Short.TYPE;
+ else if (name.equals("int"))
+ return Integer.TYPE;
+ else if (name.equals("long"))
+ return Long.TYPE;
+ else if (name.equals("float"))
+ return Float.TYPE;
+ else if (name.equals("double"))
+ return Double.TYPE;
+ else
+ return null;
+ }
+
+ public Class[] getClassArray() {
+ return typeList.subList(0, typeList.size()).toArray(new Class[] {});
+ }
+}
+
+public class PluginAppletSecurityContext {
+
+ private static Hashtable<ClassLoader, URL> classLoaders = new Hashtable<ClassLoader, URL>();
+ private static Hashtable<Integer, ClassLoader> instanceClassLoaders = new Hashtable<Integer, ClassLoader>();
+
+ // FIXME: make private
+ public PluginObjectStore store = new PluginObjectStore();
+ private Throwable throwable = null;
+ private ClassLoader liveconnectLoader = ClassLoader.getSystemClassLoader();
+ int identifier = 0;
+
+ public static PluginStreamHandler streamhandler;
+
+ long startTime = 0;
+
+ public PluginAppletSecurityContext(int identifier) {
+ this.identifier = identifier;
+
+ // also, override the basedir, use a different one for the plugin
+ File f = new File(System.getProperty("user.home") + "/.icedteaplugin/");
+ f.mkdir();
+ JNLPRuntime.setBaseDir(f);
+
+ // We need a security manager.. and since there is a good chance that
+ // an applet will be loaded at some point, we should make it the SM
+ // that JNLPRuntime will try to install
+ if (System.getSecurityManager() == null) {
+ JNLPRuntime.initialize(/* isApplication */ false);
+ }
+
+ JNLPRuntime.disableExit();
+
+ URL u = null;
+ try {
+ u = new URL("file://");
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+
+ this.classLoaders.put(liveconnectLoader, u);
+ }
+
+ private static <V> V parseCall(String s, ClassLoader cl, Class<V> c) {
+ if (c == Integer.class)
+ return (V) new Integer(s);
+ else if (c == String.class)
+ return (V) new String(s);
+ else if (c == Signature.class)
+ return (V) new Signature(s, cl);
+ else
+ throw new RuntimeException("Unexpected call value.");
+ }
+
+ private Object parseArgs(String s, Class c) {
+ if (c == Boolean.TYPE || c == Boolean.class)
+ return new Boolean(s);
+ else if (c == Byte.TYPE || c == Byte.class)
+ return new Byte(s);
+ else if (c == Character.TYPE || c == Character.class) {
+ String[] bytes = s.split("_");
+ int low = Integer.parseInt(bytes[0]);
+ int high = Integer.parseInt(bytes[1]);
+ int full = ((high << 8) & 0x0ff00) | (low & 0x0ff);
+ return new Character((char) full);
+ } else if (c == Short.TYPE || c == Short.class)
+ return new Short(s);
+ else if (c == Integer.TYPE || c == Integer.class)
+ return new Integer(s);
+ else if (c == Long.TYPE || c == Long.class)
+ return new Long(s);
+ else if (c == Float.TYPE || c == Float.class)
+ return new Float(s);
+ else if (c == Double.TYPE || c == Double.class)
+ return new Double(s);
+ else
+ return store.getObject(new Integer(s));
+ }
+
+ public void associateSrc(ClassLoader cl, URL src) {
+ PluginDebug.debug("Associating " + cl + " with " + src);
+ this.classLoaders.put(cl, src);
+ }
+
+ public void associateInstance(Integer i, ClassLoader cl) {
+ PluginDebug.debug("Associating " + cl + " with instance " + i);
+ this.instanceClassLoaders.put(i, cl);
+ }
+
+ public static void setStreamhandler(PluginStreamHandler sh) {
+ streamhandler = sh;
+ }
+
+ public static Map<String, String> getLoaderInfo() {
+ Hashtable<String, String> map = new Hashtable<String, String>();
+
+ for (ClassLoader loader : PluginAppletSecurityContext.classLoaders.keySet()) {
+ map.put(loader.getClass().getName(), classLoaders.get(loader).toString());
+ }
+
+ return map;
+ }
+
+ public void handleMessage(int reference, String src, AccessControlContext callContext, String message) {
+
+ startTime = new java.util.Date().getTime();
+
+ try {
+ if (message.startsWith("FindClass")) {
+ ClassLoader cl = null;
+ Class c = null;
+ cl = liveconnectLoader;
+ String[] args = message.split(" ");
+ Integer instance = new Integer(args[1]);
+ String className = args[2].replace('/', '.');
+ PluginDebug.debug("Searching for class " + className + " in " + cl);
+
+ try {
+ c = cl.loadClass(className);
+ store.reference(c);
+ write(reference, "FindClass " + store.getIdentifier(c));
+ } catch (ClassNotFoundException cnfe) {
+
+ cl = this.instanceClassLoaders.get(instance);
+ PluginDebug.debug("Not found. Looking in " + cl);
+
+ if (instance != 0 && cl != null) {
+ try {
+ c = cl.loadClass(className);
+ store.reference(c);
+ write(reference, "FindClass " + store.getIdentifier(c));
+ } catch (ClassNotFoundException cnfe2) {
+ write(reference, "FindClass 0");
+ }
+ } else {
+ write(reference, "FindClass 0");
+ }
+ }
+
+ } else if (message.startsWith("GetStaticMethodID")
+ || message.startsWith("GetMethodID")) {
+ String[] args = message.split(" ");
+ Integer classID = parseCall(args[1], null, Integer.class);
+ String methodName = parseCall(args[2], null, String.class);
+ Signature signature = parseCall(args[3], ((Class) store.getObject(classID)).getClassLoader(), Signature.class);
+ Object[] a = signature.getClassArray();
+
+ Class c;
+
+ if (message.startsWith("GetStaticMethodID") ||
+ methodName.equals("<init>") ||
+ methodName.equals("<clinit>"))
+ c = (Class) store.getObject(classID);
+ else
+ c = store.getObject(classID).getClass();
+
+ Method m = null;
+ Constructor cs = null;
+ Object o = null;
+ if (methodName.equals("<init>")
+ || methodName.equals("<clinit>")) {
+ o = cs = c.getConstructor(signature.getClassArray());
+ store.reference(cs);
+ } else {
+ o = m = c.getMethod(methodName, signature.getClassArray());
+ store.reference(m);
+ }
+ PluginDebug.debug(o + " has id " + store.getIdentifier(o));
+ write(reference, args[0] + " " + store.getIdentifier(o));
+ } else if (message.startsWith("GetStaticFieldID")
+ || message.startsWith("GetFieldID")) {
+ String[] args = message.split(" ");
+ Integer classID = parseCall(args[1], null, Integer.class);
+ Integer fieldID = parseCall(args[2], null, Integer.class);
+ String fieldName = (String) store.getObject(fieldID);
+
+ Class c = (Class) store.getObject(classID);
+
+ PluginDebug.debug("GetStaticFieldID/GetFieldID got class=" + c.getName());
+
+ Field f = null;
+ f = c.getField(fieldName);
+
+ store.reference(f);
+
+ write(reference, "GetStaticFieldID " + store.getIdentifier(f));
+ } else if (message.startsWith("GetStaticField")) {
+ String[] args = message.split(" ");
+ String type = parseCall(args[1], null, String.class);
+ Integer classID = parseCall(args[1], null, Integer.class);
+ Integer fieldID = parseCall(args[2], null, Integer.class);
+
+ final Class c = (Class) store.getObject(classID);
+ final Field f = (Field) store.getObject(fieldID);
+
+ AccessControlContext acc = callContext != null ? callContext : getClosedAccessControlContext();
+ checkPermission(src, c, acc);
+
+ Object ret = AccessController.doPrivileged(new PrivilegedAction<Object> () {
+ public Object run() {
+ try {
+ return f.get(c);
+ } catch (Throwable t) {
+ return t;
+ }
+ }
+ }, acc);
+
+ if (ret instanceof Throwable)
+ throw (Throwable) ret;
+
+ if (ret == null) {
+ write(reference, "GetStaticField literalreturn null");
+ } else if (f.getType() == Boolean.TYPE
+ || f.getType() == Byte.TYPE
+ || f.getType() == Short.TYPE
+ || f.getType() == Integer.TYPE
+ || f.getType() == Long.TYPE) {
+ write(reference, "GetStaticField literalreturn " + ret);
+ } else if (f.getType() == Float.TYPE
+ || f.getType() == Double.TYPE) {
+ write(reference, "GetStaticField literalreturn " + String.format("%308.308e", ret));
+ } else if (f.getType() == Character.TYPE) {
+ write(reference, "GetStaticField literalreturn " + (int) (Character) ret);
+ } else {
+ // Track returned object.
+ store.reference(ret);
+ write(reference, "GetStaticField " + store.getIdentifier(ret));
+ }
+ } else if (message.startsWith("GetValue")) {
+ String[] args = message.split(" ");
+ Integer index = parseCall(args[1], null, Integer.class);
+
+ Object ret = store.getObject(index);
+
+ if (ret == null) {
+ write(reference, "GetValue literalreturn null");
+ } else if (ret.getClass() == Boolean.TYPE
+ || ret.getClass() == Boolean.class
+ || ret.getClass() == Byte.TYPE
+ || ret.getClass() == Byte.class
+ || ret.getClass() == Short.TYPE
+ || ret.getClass() == Short.class
+ || ret.getClass() == Integer.TYPE
+ || ret.getClass() == Integer.class
+ || ret.getClass() == Long.TYPE
+ || ret.getClass() == Long.class) {
+ write(reference, "GetValue literalreturn " + ret);
+ } else if (ret.getClass() == Float.TYPE
+ || ret.getClass() == Float.class
+ || ret.getClass() == Double.TYPE
+ || ret.getClass() == Double.class) {
+ write(reference, "GetValue literalreturn " + String.format("%308.308e", ret));
+ } else if (ret.getClass() == Character.TYPE
+ || ret.getClass() == Character.class) {
+ write(reference, "GetValue literalreturn " + (int) (Character) ret);
+ } else {
+ // Track returned object.
+ store.reference(ret);
+ write(reference, "GetValue " + store.getIdentifier(ret));
+ }
+ } else if (message.startsWith("SetStaticField") ||
+ message.startsWith("SetField")) {
+ String[] args = message.split(" ");
+ Integer classOrObjectID = parseCall(args[1], null, Integer.class);
+ Integer fieldID = parseCall(args[2], null, Integer.class);
+ Object value = store.getObject(parseCall(args[3], null, Integer.class));
+
+ final Object o = store.getObject(classOrObjectID);
+ final Field f = (Field) store.getObject(fieldID);
+
+ final Object fValue = MethodOverloadResolver.getCostAndCastedObject(value, f.getType())[1];
+
+ AccessControlContext acc = callContext != null ? callContext : getClosedAccessControlContext();
+ checkPermission(src,
+ message.startsWith("SetStaticField") ? (Class) o : o.getClass(),
+ acc);
+
+ Object ret = AccessController.doPrivileged(new PrivilegedAction<Object> () {
+ public Object run() {
+ try {
+ f.set(o, fValue);
+ } catch (Throwable t) {
+ return t;
+ }
+
+ return null;
+ }
+ }, acc);
+
+ if (ret instanceof Throwable)
+ throw (Throwable) ret;
+
+ write(reference, "SetField");
+ } else if (message.startsWith("GetObjectArrayElement")) {
+ String[] args = message.split(" ");
+ Integer arrayID = parseCall(args[1], null, Integer.class);
+ Integer index = parseCall(args[2], null, Integer.class);
+
+ Object ret = Array.get(store.getObject(arrayID), index);
+ Class retClass = store.getObject(arrayID).getClass().getComponentType(); // prevent auto-boxing influence
+
+ if (ret == null) {
+ write(reference, "GetObjectArrayElement literalreturn null");
+ } else if (retClass == Boolean.TYPE
+ || retClass == Byte.TYPE
+ || retClass == Short.TYPE
+ || retClass== Integer.TYPE
+ || retClass== Long.TYPE) {
+ write(reference, "GetObjectArrayElement literalreturn " + ret);
+ } else if (retClass == Float.TYPE
+ || retClass == Double.TYPE) {
+ write(reference, "GetObjectArrayElement literalreturn " + String.format("%308.308e", ret));
+ } else if (retClass == Character.TYPE) {
+ write(reference, "GetObjectArrayElement literalreturn " + (int) (Character) ret);
+ } else {
+ // Track returned object.
+ store.reference(ret);
+ write(reference, "GetObjectArrayElement " + store.getIdentifier(ret));
+ }
+
+ } else if (message.startsWith("SetObjectArrayElement")) {
+ String[] args = message.split(" ");
+ Integer arrayID = parseCall(args[1], null, Integer.class);
+ Integer index = parseCall(args[2], null, Integer.class);
+ Integer objectID = parseCall(args[3], null, Integer.class);
+
+ Object value = store.getObject(objectID);
+
+ // Cast the object to appropriate type before insertion
+ value = MethodOverloadResolver.getCostAndCastedObject(value, store.getObject(arrayID).getClass().getComponentType())[1];
+
+ //if (value == null &&
+ // store.getObject(arrayID).getClass().getComponentType().isPrimitive()) {
+ // value = 0;
+ //}
+
+ Array.set(store.getObject(arrayID), index, value);
+
+ write(reference, "SetObjectArrayElement");
+ } else if (message.startsWith("GetArrayLength")) {
+ String[] args = message.split(" ");
+ Integer arrayID = parseCall(args[1], null, Integer.class);
+
+ //System.out.println("ARRAYID: " + arrayID);
+ Object o = (Object) store.getObject(arrayID);
+ int len = 0;
+ len = Array.getLength(o);
+ // System.out.println ("Returning array length: " + len);
+
+ // System.out.println ("array length: " + o + " " + len);
+ write(reference, "GetArrayLength " + Array.getLength(o));
+ } else if (message.startsWith("GetField")) {
+ String[] args = message.split(" ");
+ String type = parseCall(args[1], null, String.class);
+ Integer objectID = parseCall(args[1], null, Integer.class);
+ Integer fieldID = parseCall(args[2], null, Integer.class);
+
+ final Object o = (Object) store.getObject(objectID);
+ final Field f = (Field) store.getObject(fieldID);
+
+ AccessControlContext acc = callContext != null ? callContext : getClosedAccessControlContext();
+ checkPermission(src, o.getClass(), acc);
+
+ Object ret = AccessController.doPrivileged(new PrivilegedAction<Object> () {
+ public Object run() {
+ try {
+ return f.get(o);
+ } catch (Throwable t) {
+ return t;
+ }
+ }
+ }, acc);
+
+ if (ret instanceof Throwable)
+ throw (Throwable) ret;
+
+ if (ret == null) {
+ write(reference, "GetField literalreturn null");
+ } else if (f.getType() == Boolean.TYPE
+ || f.getType() == Byte.TYPE
+ || f.getType() == Short.TYPE
+ || f.getType() == Integer.TYPE
+ || f.getType() == Long.TYPE) {
+ write(reference, "GetField literalreturn " + ret);
+ } else if (f.getType() == Float.TYPE
+ || f.getType() == Double.TYPE) {
+ write(reference, "GetField literalreturn " + String.format("%308.308e", ret));
+ } else if (f.getType() == Character.TYPE) {
+ write(reference, "GetField literalreturn " + (int) (Character) ret);
+ } else {
+ // Track returned object.
+ store.reference(ret);
+ write(reference, "GetField " + store.getIdentifier(ret));
+ }
+
+ } else if (message.startsWith("GetObjectClass")) {
+ int oid = Integer.parseInt(message.substring("GetObjectClass"
+ .length() + 1));
+ // System.out.println ("GETTING CLASS FOR: " + oid);
+ Class c = store.getObject(oid).getClass();
+ // System.out.println (" OBJ: " + store.getObject(oid));
+ // System.out.println (" CLS: " + c);
+ store.reference(c);
+
+ write(reference, "GetObjectClass " + store.getIdentifier(c));
+ } else if (message.startsWith("CallMethod") ||
+ message.startsWith("CallStaticMethod")) {
+ String[] args = message.split(" ");
+ Integer objectID = parseCall(args[1], null, Integer.class);
+ String methodName = parseCall(args[2], null, String.class);
+ Object o = null;
+ Class c;
+
+ if (message.startsWith("CallMethod")) {
+ o = (Object) store.getObject(objectID);
+ c = o.getClass();
+ } else {
+ c = (Class) store.getObject(objectID);
+ }
+
+ // length -3 to discard first 3, + 2 for holding object
+ // and method name
+ Object[] arguments = new Object[args.length - 1];
+ arguments[0] = c;
+ arguments[1] = methodName;
+ for (int i = 0; i < args.length - 3; i++) {
+ arguments[i+2] = store.getObject(parseCall(args[3 + i], null, Integer.class));
+ PluginDebug.debug("GOT ARG: " + arguments[i+2]);
+ }
+
+ Object[] matchingMethodAndArgs = MethodOverloadResolver.getMatchingMethod(arguments);
+
+ if (matchingMethodAndArgs == null) {
+ write(reference, "Error: No suitable method named " + methodName + " with matching args found");
+ return;
+ }
+
+ final Method m = (Method) matchingMethodAndArgs[0];
+ Object[] castedArgs = new Object[matchingMethodAndArgs.length - 1];
+ for (int i=0; i < castedArgs.length; i++) {
+ castedArgs[i] = matchingMethodAndArgs[i+1];
+ }
+
+ String collapsedArgs = "";
+ for (Object arg : castedArgs) {
+ collapsedArgs += " " + arg;
+ }
+
+ PluginDebug.debug("Calling method " + m + " on object " + o
+ + " (" + c + ") with " + collapsedArgs);
+
+ AccessControlContext acc = callContext != null ? callContext : getClosedAccessControlContext();
+ checkPermission(src, c, acc);
+
+ final Object[] fArguments = castedArgs;
+ final Object callableObject = o;
+ // Set the method accessible prior to calling. See:
+ // http://forums.sun.com/thread.jspa?threadID=332001&start=15&tstart=0
+ m.setAccessible(true);
+ Object ret = AccessController.doPrivileged(new PrivilegedAction<Object> () {
+ public Object run() {
+ try {
+ return m.invoke(callableObject, fArguments);
+ } catch (Throwable t) {
+ return t;
+ }
+ }
+ }, acc);
+
+ if (ret instanceof Throwable)
+ throw (Throwable) ret;
+
+ String retO;
+ if (ret == null) {
+ retO = "null";
+ } else {
+ retO = m.getReturnType().toString();
+ }
+
+ PluginDebug.debug("Calling " + m + " on " + o + " with "
+ + collapsedArgs + " and that returned: " + ret
+ + " of type " + retO);
+
+ if (m.getReturnType().equals(java.lang.Void.class) ||
+ m.getReturnType().equals(java.lang.Void.TYPE)) {
+ write(reference, "CallMethod literalreturn void");
+ } else if (ret == null) {
+ write(reference, "CallMethod literalreturn null");
+ } else if (m.getReturnType() == Boolean.TYPE
+ || m.getReturnType() == Byte.TYPE
+ || m.getReturnType() == Short.TYPE
+ || m.getReturnType() == Integer.TYPE
+ || m.getReturnType() == Long.TYPE) {
+ write(reference, "CallMethod literalreturn " + ret);
+ } else if (m.getReturnType() == Float.TYPE
+ || m.getReturnType() == Double.TYPE) {
+ write(reference, "CallMethod literalreturn " + String.format("%308.308e", ret));
+ } else if (m.getReturnType() == Character.TYPE) {
+ write(reference, "CallMethod literalreturn " + (int) (Character) ret);
+ } else {
+ // Track returned object.
+ store.reference(ret);
+ write(reference, "CallMethod " + store.getIdentifier(ret));
+ }
+ } else if (message.startsWith("GetSuperclass")) {
+ String[] args = message.split(" ");
+ Integer classID = parseCall(args[1], null, Integer.class);
+ Class c = null;
+ Class ret = null;
+
+ c = (Class) store.getObject(classID);
+ ret = c.getSuperclass();
+ store.reference(ret);
+
+ write(reference, "GetSuperclass " + store.getIdentifier(ret));
+ } else if (message.startsWith("IsAssignableFrom")) {
+ String[] args = message.split(" ");
+ Integer classID = parseCall(args[1], null, Integer.class);
+ Integer superclassID = parseCall(args[2], null, Integer.class);
+
+ boolean result = false;
+ Class clz = (Class) store.getObject(classID);
+ Class sup = (Class) store.getObject(superclassID);
+
+ result = sup.isAssignableFrom(clz);
+
+ write(reference, "IsAssignableFrom " + (result ? "1" : "0"));
+ } else if (message.startsWith("IsInstanceOf")) {
+ String[] args = message.split(" ");
+ Integer objectID = parseCall(args[1], null, Integer.class);
+ Integer classID = parseCall(args[2], null, Integer.class);
+
+ boolean result = false;
+ Object o = (Object) store.getObject(objectID);
+ Class c = (Class) store.getObject(classID);
+
+ result = c.isInstance(o);
+
+ write(reference, "IsInstanceOf " + (result ? "1" : "0"));
+ } else if (message.startsWith("GetStringUTFLength")) {
+ String[] args = message.split(" ");
+ Integer stringID = parseCall(args[1], null, Integer.class);
+
+ String o = null;
+ byte[] b = null;
+ o = (String) store.getObject(stringID);
+ b = o.getBytes("UTF-8");
+ // System.out.println ("STRING UTF-8 LENGTH: " + o + " " +
+ // b.length);
+
+ write(reference, "GetStringUTFLength " + o.length());
+ } else if (message.startsWith("GetStringLength")) {
+ String[] args = message.split(" ");
+ Integer stringID = parseCall(args[1], null, Integer.class);
+
+ String o = null;
+ byte[] b = null;
+ o = (String) store.getObject(stringID);
+ b = o.getBytes("UTF-16LE");
+ // System.out.println ("STRING UTF-16 LENGTH: " + o + " " +
+ // b.length);
+
+ // System.out.println ("Java: GetStringLength " + b.length);
+ write(reference, "GetStringLength " + o.length());
+ } else if (message.startsWith("GetStringUTFChars")) {
+ String[] args = message.split(" ");
+ Integer stringID = parseCall(args[1], null, Integer.class);
+
+ String o = null;
+ byte[] b = null;
+ StringBuffer buf = null;
+ o = (String) store.getObject(stringID);
+ b = o.getBytes("UTF-8");
+ buf = new StringBuffer(b.length * 2);
+ buf.append(b.length);
+ for (int i = 0; i < b.length; i++)
+ buf
+ .append(" "
+ + Integer
+ .toString(((int) b[i]) & 0x0ff, 16));
+
+ // System.out.println ("Java: GetStringUTFChars: " + o);
+ // //System.out.println ("String UTF BYTES: " + buf);
+ write(reference, "GetStringUTFChars " + buf);
+ } else if (message.startsWith("GetStringChars")) {
+ String[] args = message.split(" ");
+ Integer stringID = parseCall(args[1], null, Integer.class);
+
+ String o = null;
+ byte[] b = null;
+ StringBuffer buf = null;
+ o = (String) store.getObject(stringID);
+ // FIXME: LiveConnect uses UCS-2.
+ b = o.getBytes("UTF-16LE");
+ buf = new StringBuffer(b.length * 2);
+ buf.append(b.length);
+ for (int i = 0; i < b.length; i++)
+ buf
+ .append(" "
+ + Integer
+ .toString(((int) b[i]) & 0x0ff, 16));
+
+ PluginDebug.debug("Java: GetStringChars: " + o);
+ PluginDebug.debug(" String BYTES: " + buf);
+ write(reference, "GetStringChars " + buf);
+ } else if (message.startsWith("GetToStringValue")) {
+ String[] args = message.split(" ");
+ Integer objectID = parseCall(args[1], null, Integer.class);
+
+ String o = null;
+ byte[] b = null;
+ StringBuffer buf = null;
+ o = store.getObject(objectID).toString();
+ b = o.getBytes("UTF-8");
+ buf = new StringBuffer(b.length * 2);
+ buf.append(b.length);
+ for (int i = 0; i < b.length; i++)
+ buf
+ .append(" "
+ + Integer
+ .toString(((int) b[i]) & 0x0ff, 16));
+
+ write(reference, "GetToStringValue " + buf);
+ } else if (message.startsWith("NewArray")) {
+ String[] args = message.split(" ");
+ String type = parseCall(args[1], null, String.class);
+ Integer length = parseCall(args[2], null, Integer.class);
+
+ // System.out.println ("CALLING: NewArray: " + type + " " +
+ // length + " "
+ // + Signature.primitiveNameToType(type));
+
+ Object newArray = null;
+
+ Class c;
+ if (type.equals("bool")) {
+ c = Boolean.class;
+ } else if (type.equals("double")) {
+ c = Double.class;
+ } else if (type.equals("int")) {
+ c = Integer.class;
+ } else if (type.equals("string")) {
+ c = String.class;
+ } else if (isInt(type)) {
+ c = (Class) store.getObject(Integer.parseInt(type));
+ } else {
+ c = JSObject.class;
+ }
+
+ if (args.length > 3)
+ newArray = Array.newInstance(c, new int[] { length, parseCall(args[3], null, Integer.class)});
+ else
+ newArray = Array.newInstance(c, length);
+
+ store.reference(newArray);
+ write(reference, "NewArray " + store.getIdentifier(newArray));
+ } else if (message.startsWith("HasMethod")) {
+ String[] args = message.split(" ");
+ Integer classNameID = parseCall(args[1], null, Integer.class);
+ Integer methodNameID = parseCall(args[2], null, Integer.class);
+
+ Class c = (Class) store.getObject(classNameID);
+ String methodName = (String) store.getObject(methodNameID);
+
+ Method method = null;
+ Method[] classMethods = c.getMethods();
+ for (Method m: classMethods) {
+ if (m.getName().equals(methodName)) {
+ method = m;
+ break;
+ }
+ }
+
+ int hasMethod = (method != null) ? 1 : 0;
+
+ write(reference, "HasMethod " + hasMethod);
+ } else if (message.startsWith("HasPackage")) {
+ String[] args = message.split(" ");
+ Integer instance = parseCall(args[1], null, Integer.class);
+ Integer nameID = parseCall(args[2], null, Integer.class);
+ String pkgName = (String) store.getObject(nameID);
+
+ Package pkg = Package.getPackage(pkgName);
+ int hasPkg = (pkg != null) ? 1 : 0;
+
+ write(reference, "HasPackage " + hasPkg);
+
+ } else if (message.startsWith("HasField")) {
+ String[] args = message.split(" ");
+ Integer classNameID = parseCall(args[1], null, Integer.class);
+ Integer fieldNameID = parseCall(args[2], null, Integer.class);
+
+ Class c = (Class) store.getObject(classNameID);
+ String fieldName = (String) store.getObject(fieldNameID);
+
+ Field field = null;
+ Field[] classFields = c.getFields();
+ for (Field f: classFields) {
+ if (f.getName().equals(fieldName)) {
+ field = f;
+ break;
+ }
+ }
+
+ int hasField = (field != null) ? 1 : 0;
+
+ write(reference, "HasField " + hasField);
+ } else if (message.startsWith("NewObjectArray")) {
+ String[] args = message.split(" ");
+ Integer length = parseCall(args[1], null, Integer.class);
+ Integer classID = parseCall(args[2], null, Integer.class);
+ Integer objectID = parseCall(args[3], null, Integer.class);
+
+ // System.out.println ("CALLING: NewObjectArray: " +
+ // classID + " " + length + " "
+ // + objectID);
+
+ Object newArray = null;
+ newArray = Array.newInstance((Class) store.getObject(classID),
+ length);
+
+ Object[] array = (Object[]) newArray;
+ for (int i = 0; i < array.length; i++)
+ array[i] = store.getObject(objectID);
+ store.reference(newArray);
+ write(reference, "NewObjectArray "
+ + store.getIdentifier(newArray));
+ } else if (message.startsWith("NewObjectWithConstructor")) {
+
+ String[] args = message.split(" ");
+ Integer classID = parseCall(args[1], null, Integer.class);
+ Integer methodID = parseCall(args[2], null, Integer.class);
+
+ final Constructor m = (Constructor) store.getObject(methodID);
+ Class[] argTypes = m.getParameterTypes();
+
+ // System.out.println ("NEWOBJ: HERE1");
+ Object[] arguments = new Object[argTypes.length];
+ // System.out.println ("NEWOBJ: HERE2");
+ for (int i = 0; i < argTypes.length; i++) {
+ arguments[i] = parseArgs(args[3 + i], argTypes[i]);
+ // System.out.println ("NEWOBJ: GOT ARG: " + arguments[i]);
+ }
+
+ final Object[] fArguments = arguments;
+ AccessControlContext acc = callContext != null ? callContext : getClosedAccessControlContext();
+
+ Class c = (Class) store.getObject(classID);
+ checkPermission(src, c, acc);
+
+ Object ret = AccessController.doPrivileged(new PrivilegedAction<Object> () {
+ public Object run() {
+ try {
+ return m.newInstance(fArguments);
+ } catch (Throwable t) {
+ return t;
+ }
+ }
+ }, acc);
+
+ if (ret instanceof Throwable)
+ throw (Throwable) ret;
+
+ store.reference(ret);
+
+ write(reference, "NewObject " + store.getIdentifier(ret));
+
+ } else if (message.startsWith("NewObject")) {
+ String[] args = message.split(" ");
+ Integer classID = parseCall(args[1], null, Integer.class);
+ Class c = (Class) store.getObject(classID);
+ final Constructor cons;
+ final Object[] fArguments;
+
+ Object[] arguments = new Object[args.length - 1];
+ arguments[0] = c;
+ for (int i = 0; i < args.length - 2; i++) {
+ arguments[i + 1] = store.getObject(parseCall(args[2 + i],
+ null, Integer.class));
+ PluginDebug.debug("GOT ARG: " + arguments[i + 1]);
+ }
+
+ Object[] matchingConstructorAndArgs = MethodOverloadResolver
+ .getMatchingConstructor(arguments);
+
+ if (matchingConstructorAndArgs == null) {
+ write(reference,
+ "Error: No suitable constructor with matching args found");
+ return;
+ }
+
+ Object[] castedArgs = new Object[matchingConstructorAndArgs.length - 1];
+ for (int i = 0; i < castedArgs.length; i++) {
+ castedArgs[i] = matchingConstructorAndArgs[i + 1];
+ }
+
+ cons = (Constructor) matchingConstructorAndArgs[0];
+ fArguments = castedArgs;
+
+ String collapsedArgs = "";
+ for (Object arg : fArguments) {
+ collapsedArgs += " " + arg.toString();
+ }
+
+ PluginDebug.debug("Calling constructor on class " + c +
+ " with " + collapsedArgs);
+
+ AccessControlContext acc = callContext != null ? callContext : getClosedAccessControlContext();
+ checkPermission(src, c, acc);
+
+ Object ret = AccessController.doPrivileged(new PrivilegedAction<Object> () {
+ public Object run() {
+ try {
+ return cons.newInstance(fArguments);
+ } catch (Throwable t) {
+ return t;
+ }
+ }
+ }, acc);
+
+ if (ret instanceof Throwable)
+ throw (Throwable) ret;
+
+ store.reference(ret);
+
+ write(reference, "NewObject " + store.getIdentifier(ret));
+
+ } else if (message.startsWith("NewStringUTF")) {
+ PluginDebug.debug("MESSAGE: " + message);
+ String[] args = message.split(" ");
+ int length = new Integer(args[1]);
+ byte[] byteArray = new byte[length];
+ String ret = null;
+ int i = 0;
+ int j = 2;
+ int c;
+ while (i < length) {
+ c = Integer.parseInt(args[j++], 16);
+ byteArray[i++] = (byte) c;
+ }
+
+ ret = new String(byteArray, "UTF-8");
+ PluginDebug.debug("NEWSTRINGUTF: " + ret);
+
+ store.reference(ret);
+ write(reference, "NewStringUTF " + store.getIdentifier(ret));
+ } else if (message.startsWith("NewString")) {
+ PluginDebug.debug("MESSAGE: " + message);
+ String[] args = message.split(" ");
+ Integer strlength = parseCall(args[1], null, Integer.class);
+ int bytelength = 2 * strlength;
+ byte[] byteArray = new byte[bytelength];
+ String ret = null;
+ for (int i = 0; i < strlength; i++) {
+ int c = parseCall(args[2 + i], null, Integer.class);
+ PluginDebug.debug("char " + i + " " + c);
+ // Low.
+ byteArray[2 * i] = (byte) (c & 0x0ff);
+ // High.
+ byteArray[2 * i + 1] = (byte) ((c >> 8) & 0x0ff);
+ }
+ ret = new String(byteArray, 0, bytelength, "UTF-16LE");
+ PluginDebug.debug("NEWSTRING: " + ret);
+
+ // System.out.println ("NEWOBJ: CALLED: " + ret);
+ // System.out.println ("NEWOBJ: CALLED: " +
+ // store.getObject(ret));
+ store.reference(ret);
+ write(reference, "NewString " + store.getIdentifier(ret));
+
+ } else if (message.startsWith("ExceptionOccurred")) {
+ PluginDebug.debug("EXCEPTION: " + throwable);
+ if (throwable != null)
+ store.reference(throwable);
+ write(reference, "ExceptionOccurred "
+ + store.getIdentifier(throwable));
+ } else if (message.startsWith("ExceptionClear")) {
+ if (throwable != null && store.contains(throwable))
+ store.unreference(store.getIdentifier(throwable));
+ throwable = null;
+ write(reference, "ExceptionClear");
+ } else if (message.startsWith("DeleteGlobalRef")) {
+ String[] args = message.split(" ");
+ Integer id = parseCall(args[1], null, Integer.class);
+ store.unreference(id);
+ write(reference, "DeleteGlobalRef");
+ } else if (message.startsWith("DeleteLocalRef")) {
+ String[] args = message.split(" ");
+ Integer id = parseCall(args[1], null, Integer.class);
+ store.unreference(id);
+ write(reference, "DeleteLocalRef");
+ } else if (message.startsWith("NewGlobalRef")) {
+ String[] args = message.split(" ");
+ Integer id = parseCall(args[1], null, Integer.class);
+ store.reference(store.getObject(id));
+ write(reference, "NewGlobalRef " + id);
+ } else if (message.startsWith("GetClassName")) {
+ String[] args = message.split(" ");
+ Integer objectID = parseCall(args[1], null, Integer.class);
+ Object o = (Object) store.getObject(objectID);
+ write(reference, "GetClassName " + o.getClass().getName());
+ } else if (message.startsWith("GetClassID")) {
+ String[] args = message.split(" ");
+ Integer objectID = parseCall(args[1], null, Integer.class);
+ store.reference(store.getObject(objectID).getClass());
+ write(reference, "GetClassID " + store.getIdentifier(store.getObject(objectID).getClass()));
+ }
+ } catch (Throwable t) {
+ t.printStackTrace();
+ String msg = t.getCause() != null ? t.getCause().getMessage() : t.getMessage();
+
+ // add an identifier string to let javaside know of the type of error
+ // check for cause as well, since the top level exception will be InvocationTargetException in most cases
+ if (t instanceof AccessControlException || t.getCause() instanceof AccessControlException) {
+ msg = "LiveConnectPermissionNeeded " + msg;
+ }
+
+ write(reference, " Error " + msg);
+
+ // ExceptionOccured is only called after Callmethod() by mozilla. So
+ // for exceptions that are not related to CallMethod, we need a way
+ // to log them. This is how we do it.. send an error message to the
+ // c++ side to let it know that something went wrong, and it will do
+ // the right thing to let mozilla know
+
+ // Store the cause as the actual exception. This is needed because
+ // the exception we get here will always be an
+ // "InvocationTargetException" due to the use of reflection above
+ if (message.startsWith("CallMethod") || message.startsWith("CallStaticMethod"))
+ throwable = t.getCause();
+ }
+
+ }
+
+ /**
+ * Checks if the calling script is allowed to access the specified class
+ *
+ * @param jsSrc The source of the script
+ * @param target The target class that the script is trying to access
+ * @param acc AccessControlContext for this execution
+ * @throws AccessControlException If the script has insufficient permissions
+ */
+ public void checkPermission(String jsSrc, Class target, AccessControlContext acc) throws AccessControlException {
+ // NPRuntime does not allow cross-site calling. We therefore always
+ // allow this, for the time being
+ return;
+ }
+
+ private void write(int reference, String message) {
+ PluginDebug.debug("appletviewer writing " + message);
+ streamhandler.write("context " + identifier + " reference " + reference
+ + " " + message);
+ }
+
+ public void prePopulateLCClasses() {
+
+ int classID;
+
+ prepopulateClass("netscape/javascript/JSObject");
+ classID = prepopulateClass("netscape/javascript/JSException");
+ prepopulateMethod(classID, "<init>", "(Ljava/lang/String;Ljava/lang/String;ILjava/lang/String;I)");
+ prepopulateMethod(classID, "<init>", "(ILjava/lang/Object;)");
+ prepopulateField(classID, "lineno");
+ prepopulateField(classID, "tokenIndex");
+ prepopulateField(classID, "source");
+ prepopulateField(classID, "filename");
+ prepopulateField(classID, "wrappedExceptionType");
+ prepopulateField(classID, "wrappedException");
+
+ classID = prepopulateClass("netscape/javascript/JSUtil");
+ prepopulateMethod(classID, "getStackTrace", "(Ljava/lang/Throwable;)");
+
+ prepopulateClass("java/lang/Object");
+ classID = prepopulateClass("java/lang/Class");
+ prepopulateMethod(classID, "getMethods", "()");
+ prepopulateMethod(classID, "getConstructors", "()");
+ prepopulateMethod(classID, "getFields", "()");
+ prepopulateMethod(classID, "getName", "()");
+ prepopulateMethod(classID, "isArray", "()");
+ prepopulateMethod(classID, "getComponentType", "()");
+ prepopulateMethod(classID, "getModifiers", "()");
+
+
+ classID = prepopulateClass("java/lang/reflect/Method");
+ prepopulateMethod(classID, "getName", "()");
+ prepopulateMethod(classID, "getParameterTypes", "()");
+ prepopulateMethod(classID, "getReturnType", "()");
+ prepopulateMethod(classID, "getModifiers", "()");
+
+ classID = prepopulateClass("java/lang/reflect/Constructor");
+ prepopulateMethod(classID, "getParameterTypes", "()");
+ prepopulateMethod(classID, "getModifiers", "()");
+
+ classID = prepopulateClass("java/lang/reflect/Field");
+ prepopulateMethod(classID, "getName", "()");
+ prepopulateMethod(classID, "getType", "()");
+ prepopulateMethod(classID, "getModifiers", "()");
+
+ classID = prepopulateClass("java/lang/reflect/Array");
+ prepopulateMethod(classID, "newInstance", "(Ljava/lang/Class;I)");
+
+ classID = prepopulateClass("java/lang/Throwable");
+ prepopulateMethod(classID, "toString", "()");
+ prepopulateMethod(classID, "getMessage", "()");
+
+ classID = prepopulateClass("java/lang/System");
+ prepopulateMethod(classID, "identityHashCode", "(Ljava/lang/Object;)");
+
+ classID = prepopulateClass("java/lang/Boolean");
+ prepopulateMethod(classID, "booleanValue", "()");
+ prepopulateMethod(classID, "<init>", "(Z)");
+
+ classID = prepopulateClass("java/lang/Double");
+ prepopulateMethod(classID, "doubleValue", "()");
+ prepopulateMethod(classID, "<init>", "(D)");
+
+ classID = prepopulateClass("java/lang/Void");
+ prepopulateField(classID, "TYPE");
+
+ prepopulateClass("java/lang/String");
+ prepopulateClass("java/applet/Applet");
+ }
+
+ private int prepopulateClass(String name) {
+ name = name.replace('/', '.');
+ ClassLoader cl = liveconnectLoader;
+ Class c = null;
+
+ try {
+ c = cl.loadClass(name);
+ store.reference(c);
+ } catch (ClassNotFoundException cnfe) {
+ // do nothing ... this should never happen
+ cnfe.printStackTrace();
+ }
+
+ return store.getIdentifier(c);
+ }
+
+ private int prepopulateMethod(int classID, String methodName, String signatureStr) {
+ Signature signature = parseCall(signatureStr, ((Class) store.getObject(classID)).getClassLoader(), Signature.class);
+ Object[] a = signature.getClassArray();
+
+ Class c = (Class) store.getObject(classID);
+ Method m = null;
+ Constructor cs = null;
+ Object o = null;
+
+ try {
+ if (methodName.equals("<init>")
+ || methodName.equals("<clinit>")) {
+ o = cs = c.getConstructor(signature.getClassArray());
+ store.reference(cs);
+ } else {
+ o = m = c.getMethod(methodName, signature.getClassArray());
+ store.reference(m);
+ }
+ } catch (NoSuchMethodException e) {
+ // should never happen
+ e.printStackTrace();
+ }
+
+ return store.getIdentifier(m);
+ }
+
+ private int prepopulateField(int classID, String fieldName) {
+
+ Class c = (Class) store.getObject(classID);
+ Field f = null;
+ try {
+ f = c.getField(fieldName);
+ } catch (SecurityException e) {
+ // should never happen
+ e.printStackTrace();
+ } catch (NoSuchFieldException e) {
+ // should never happen
+ e.printStackTrace();
+ }
+
+ store.reference(f);
+ return store.getIdentifier(f);
+ }
+
+ public void dumpStore() {
+ store.dump();
+ }
+
+ public Object getObject(int identifier) {
+ return store.getObject(identifier);
+ }
+
+ public int getIdentifier(Object o) {
+ return store.getIdentifier(o);
+ }
+
+ public void store(Object o) {
+ store.reference(o);
+ }
+
+ /**
+ * Returns a "closed" AccessControlContext i.e. no permissions to get out of sandbox.
+ */
+ public AccessControlContext getClosedAccessControlContext() {
+ // Deny everything
+ Permissions p = new Permissions();
+ ProtectionDomain pd = new ProtectionDomain(null, p);
+ return new AccessControlContext(new ProtectionDomain[] {pd});
+ }
+
+ public AccessControlContext getAccessControlContext(String[] nsPrivilegeList, String src) {
+
+/*
+ for (int i=0; i < nsPrivilegeList.length; i++) {
+ String privilege = nsPrivilegeList[i];
+
+ if (privilege.equals("UniversalAccept")) {
+ SocketPermission sp = new SocketPermission("*", "accept,resolve");
+ grantedPermissions.add(sp);
+ } else if (privilege.equals("UniversalAwtEventQueueAccess")) {
+ AWTPermission awtp = new AWTPermission("accessEventQueue");
+ grantedPermissions.add(awtp);
+ } else if (privilege.equals("UniversalConnect")) {
+ SocketPermission sp = new SocketPermission("*", "connect,resolve");
+ grantedPermissions.add(sp);
+ } else if (privilege.equals("UniversalListen")) {
+ SocketPermission sp = new SocketPermission("*", "listen,resolve");
+ grantedPermissions.add(sp);
+ } else if (privilege.equals("UniversalExecAccess")) {
+ FilePermission fp = new FilePermission("<<ALL FILES>>", "execute");
+ RuntimePermission rtp = new RuntimePermission("setIO");
+ grantedPermissions.add(fp);
+ grantedPermissions.add(rtp);
+ } else if (privilege.equals("UniversalExitAccess")) {
+ // Doesn't matter what the permissions are. Do not allow VM to exit.. we
+ // use a single VM for the entire browser lifecycle once invoked, we
+ // cannot let it exit
+
+ //RuntimePermission rtp = new RuntimePermission("exitVM.*");
+ //grantedPermissions.add(rtp);
+ } else if (privilege.equals("UniversalFileDelete")) {
+ FilePermission fp = new FilePermission("<<ALL FILES>>", "delete");
+ grantedPermissions.add(fp);
+ } else if (privilege.equals("UniversalFileRead")) {
+ FilePermission fp = new FilePermission("<<ALL FILES>>", "read");
+ grantedPermissions.add(fp);
+ } else if (privilege.equals("UniversalFileWrite")) {
+ FilePermission fp = new FilePermission("<<ALL FILES>>", "write");
+ grantedPermissions.add(fp);
+ } else if (privilege.equals("UniversalFdRead")) {
+ RuntimePermission rtp = new RuntimePermission("readFileDescriptor");
+ grantedPermissions.add(rtp);
+ } else if (privilege.equals("UniversalFdWrite")) {
+ RuntimePermission rtp = new RuntimePermission("writeFileDescriptor");
+ grantedPermissions.add(rtp);
+ } else if (privilege.equals("UniversalLinkAccess")) {
+ RuntimePermission rtp = new RuntimePermission("loadLibrary.*");
+ grantedPermissions.add(rtp);
+ } else if (privilege.equals("UniversalListen")) {
+ SocketPermission sp = new SocketPermission("*", "listen");
+ grantedPermissions.add(sp);
+ } else if (privilege.equals("UniversalMulticast")) {
+ SocketPermission sp = new SocketPermission("*", "accept,connect,resolve");
+ grantedPermissions.add(sp);
+ } else if (privilege.equals("UniversalPackageAccess")) {
+ RuntimePermission rtp = new RuntimePermission("defineClassInPackage.*");
+ grantedPermissions.add(rtp);
+ } else if (privilege.equals("UniversalPackageDefinition")) {
+ RuntimePermission rtp = new RuntimePermission("accessClassInPackage.*");
+ grantedPermissions.add(rtp);
+ } else if (privilege.equals("UniversalPrintJobAccess")) {
+ RuntimePermission rtp = new RuntimePermission("queuePrintJob");
+ grantedPermissions.add(rtp);
+ } else if (privilege.equals("UniversalPropertyRead")) {
+ PropertyPermission pp = new PropertyPermission("*", "read");
+ grantedPermissions.add(pp);
+ } else if (privilege.equals("UniversalPropertyWrite")) {
+ PropertyPermission pp = new PropertyPermission("*", "write");
+ grantedPermissions.add(pp);
+ } else if (privilege.equals("UniversalSetFactory")) {
+ RuntimePermission rtp = new RuntimePermission("setFactory");
+ grantedPermissions.add(rtp);
+ } else if (privilege.equals("UniversalSystemClipboardAccess")) {
+ AWTPermission awtp = new AWTPermission("accessClipboard");
+ grantedPermissions.add(awtp);
+ } else if (privilege.equals("UniversalThreadAccess")) {
+ RuntimePermission rtp1 = new RuntimePermission("modifyThread");
+ RuntimePermission rtp2 = new RuntimePermission("stopThread");
+ grantedPermissions.add(rtp1);
+ grantedPermissions.add(rtp2);
+ } else if (privilege.equals("UniversalThreadGroupAccess")) {
+ RuntimePermission rtp1 = new RuntimePermission("modifyThreadGroup");
+ RuntimePermission rtp2 = new RuntimePermission("modifyThread");
+ RuntimePermission rtp3 = new RuntimePermission("stopThread");
+ grantedPermissions.add(rtp1);
+ grantedPermissions.add(rtp2);
+ grantedPermissions.add(rtp3);
+ } else if (privilege.equals("UniversalTopLevelWindow")) {
+ AWTPermission awtp = new AWTPermission("topLevelWindow");
+ grantedPermissions.add(awtp);
+ } else if (privilege.equals("UniversalBrowserRead")) {
+ BrowserReadPermission bp = new BrowserReadPermission();
+ grantedPermissions.add(bp);
+ } else if (privilege.equals("UniversalJavaPermissions")) {
+ AllPermission ap = new AllPermission();
+ grantedPermissions.add(ap);
+ }
+ }
+
+ // what to do with these is unknown: UniversalConnectWithRedirect, UniversalDialogModality, UniversalSendMail, LimitedInstall, FullInstall, SilentInstall
+*/
+
+ Permissions grantedPermissions = new Permissions();
+
+ for (int i=0; i < nsPrivilegeList.length; i++) {
+ String privilege = nsPrivilegeList[i];
+
+ if (privilege.equals("UniversalBrowserRead")) {
+ BrowserReadPermission bp = new BrowserReadPermission();
+ grantedPermissions.add(bp);
+ } else if (privilege.equals("UniversalJavaPermission")) {
+ AllPermission ap = new AllPermission();
+ grantedPermissions.add(ap);
+ }
+ }
+
+ CodeSource cs = new CodeSource((URL) null, (java.security.cert.Certificate [])null);
+
+ if (src != null && src.length() > 0) {
+ try {
+ cs = new CodeSource(new URL(src + "/"), (java.security.cert.Certificate[]) null);
+ } catch (MalformedURLException mfue) {
+ // do nothing
+ }
+
+ if (src.equals("[System]"))
+ grantedPermissions.add(new JSObjectCreatePermission());
+
+ } else {
+ JSObjectCreatePermission perm = new JSObjectCreatePermission();
+ grantedPermissions.add(perm);
+ }
+
+ ProtectionDomain pd = new ProtectionDomain(cs, grantedPermissions, null, null);
+
+ // Add to hashmap
+ return new AccessControlContext(new ProtectionDomain[] {pd});
+ }
+
+ // private static final == inline
+ private static final boolean isInt(Object o) {
+ boolean isInt = false;
+
+ try {
+ Integer.parseInt((String) o);
+ isInt = true;
+ } catch (Exception e) {
+ // don't care
+ }
+
+ return isInt;
+ }
+
+ class BrowserReadPermission extends BasicPermission {
+ public BrowserReadPermission() {
+ super("browserRead");
+ }
+ }
+
+}
diff --git a/plugin/icedteanp/java/sun/applet/PluginAppletViewer.java b/plugin/icedteanp/java/sun/applet/PluginAppletViewer.java
new file mode 100644
index 0000000..382ff7b
--- /dev/null
+++ b/plugin/icedteanp/java/sun/applet/PluginAppletViewer.java
@@ -0,0 +1,2056 @@
+/* PluginAppletViewer -- Handles embedding of the applet panel
+ Copyright (C) 2008 Red Hat
+
+This file is part of IcedTea.
+
+IcedTea is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+IcedTea is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with IcedTea; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+/*
+ * Copyright 1995-2004 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+ package sun.applet;
+
+ import java.applet.Applet;
+import java.applet.AppletContext;
+import java.applet.AudioClip;
+import java.awt.Dimension;
+import java.awt.Frame;
+import java.awt.Graphics;
+import java.awt.Image;
+import java.awt.Insets;
+import java.awt.Label;
+import java.awt.Toolkit;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.awt.event.WindowListener;
+import java.awt.print.PageFormat;
+import java.awt.print.Printable;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.PrintStream;
+import java.io.Reader;
+import java.io.StringReader;
+import java.io.UnsupportedEncodingException;
+import java.lang.reflect.InvocationTargetException;
+import java.net.MalformedURLException;
+import java.net.SocketPermission;
+import java.net.URI;
+import java.net.URL;
+import java.security.AccessController;
+import java.security.AllPermission;
+import java.security.PrivilegedAction;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Vector;
+
+import javax.swing.SwingUtilities;
+
+import net.sourceforge.jnlp.NetxPanel;
+import net.sourceforge.jnlp.runtime.JNLPClassLoader;
+import sun.awt.AppContext;
+import sun.awt.SunToolkit;
+import sun.awt.X11.XEmbeddedFrame;
+import sun.misc.Ref;
+
+import com.sun.jndi.toolkit.url.UrlUtil;
+
+ /**
+ * Lets us construct one using unix-style one shot behaviors
+ */
+
+ class PluginAppletPanelFactory
+ {
+
+ public AppletPanel createPanel(PluginStreamHandler streamhandler,
+ int identifier,
+ long handle, int x, int y,
+ final URL doc, final Hashtable atts) {
+
+ AppletViewerPanel panel = (AppletViewerPanel) AccessController.doPrivileged(new PrivilegedAction() {
+ public Object run() {
+ try {
+ AppletPanel panel = new NetxPanel(doc, atts, false);
+ AppletViewerPanel.debug("Using NetX panel");
+ PluginDebug.debug(atts.toString());
+ return panel;
+ } catch (Exception ex) {
+ AppletViewerPanel.debug("Unable to start NetX applet - defaulting to Sun applet", ex);
+ return new AppletViewerPanel(doc, atts);
+ }
+ }
+ });
+
+
+
+ // create the frame.
+ PluginAppletViewer.reFrame(null, identifier, System.out, handle, panel);
+
+ panel.init();
+
+ // Start the applet
+ initEventQueue(panel);
+
+ // Applet initialized. Find out it's classloader and add it to the list
+ String portComponent = doc.getPort() != -1 ? ":" + doc.getPort() : "";
+ String codeBase = doc.getProtocol() + "://" + doc.getHost() + portComponent;
+
+ if (atts.get("codebase") != null) {
+ try {
+ URL appletSrcURL = new URL(codeBase + (String) atts.get("codebase"));
+ codeBase = appletSrcURL.getProtocol() + "://" + appletSrcURL.getHost();
+ } catch (MalformedURLException mfue) {
+ // do nothing
+ }
+ }
+
+
+ // Wait for the panel to initialize
+ // (happens in a separate thread)
+ Applet a;
+
+ // Wait for panel to come alive
+ int maxWait = PluginAppletViewer.APPLET_TIMEOUT; // wait for panel to come alive
+ int wait = 0;
+ while ((panel == null) || (!((NetxPanel) panel).isAlive() && wait < maxWait)) {
+ try {
+ Thread.sleep(50);
+ wait += 50;
+ } catch (InterruptedException ie) {
+ // just wait
+ }
+ }
+
+ // Wait for the panel to initialize
+ // (happens in a separate thread)
+ while (panel.getApplet() == null &&
+ ((NetxPanel) panel).isAlive()) {
+ try {
+ Thread.sleep(50);
+ PluginDebug.debug("Waiting for applet to initialize...");
+ } catch (InterruptedException ie) {
+ // just wait
+ }
+ }
+
+ a = panel.getApplet();
+
+ // Still null?
+ if (panel.getApplet() == null) {
+ streamhandler.write("instance " + identifier + " reference " + -1 + " fatalError " + "Initialization failed");
+ return null;
+ }
+
+ PluginDebug.debug("Applet " + a.getClass() + " initialized");
+ streamhandler.write("instance " + identifier + " reference 0 initialized");
+
+ AppletSecurityContextManager.getSecurityContext(0).associateSrc(((NetxPanel) panel).getAppletClassLoader(), doc);
+ AppletSecurityContextManager.getSecurityContext(0).associateInstance(identifier, ((NetxPanel) panel).getAppletClassLoader());
+
+ return panel;
+ }
+
+ public boolean isStandalone()
+ {
+ return false;
+ }
+
+ /**
+ * Send the initial set of events to the appletviewer event queue.
+ * On start-up the current behaviour is to load the applet and call
+ * Applet.init() and Applet.start().
+ */
+ private void initEventQueue(AppletPanel panel) {
+ // appletviewer.send.event is an undocumented and unsupported system
+ // property which is used exclusively for testing purposes.
+ PrivilegedAction pa = new PrivilegedAction() {
+ public Object run() {
+ return System.getProperty("appletviewer.send.event");
+ }
+ };
+ String eventList = (String) AccessController.doPrivileged(pa);
+
+ if (eventList == null) {
+ // Add the standard events onto the event queue.
+ panel.sendEvent(AppletPanel.APPLET_LOAD);
+ panel.sendEvent(AppletPanel.APPLET_INIT);
+ panel.sendEvent(AppletPanel.APPLET_START);
+ } else {
+ // We're testing AppletViewer. Force the specified set of events
+ // onto the event queue, wait for the events to be processed, and
+ // exit.
+
+ // The list of events that will be executed is provided as a
+ // ","-separated list. No error-checking will be done on the list.
+ String [] events = splitSeparator(",", eventList);
+
+ for (int i = 0; i < events.length; i++) {
+ PluginDebug.debug("Adding event to queue: " + events[i]);
+ if (events[i].equals("dispose"))
+ panel.sendEvent(AppletPanel.APPLET_DISPOSE);
+ else if (events[i].equals("load"))
+ panel.sendEvent(AppletPanel.APPLET_LOAD);
+ else if (events[i].equals("init"))
+ panel.sendEvent(AppletPanel.APPLET_INIT);
+ else if (events[i].equals("start"))
+ panel.sendEvent(AppletPanel.APPLET_START);
+ else if (events[i].equals("stop"))
+ panel.sendEvent(AppletPanel.APPLET_STOP);
+ else if (events[i].equals("destroy"))
+ panel.sendEvent(AppletPanel.APPLET_DESTROY);
+ else if (events[i].equals("quit"))
+ panel.sendEvent(AppletPanel.APPLET_QUIT);
+ else if (events[i].equals("error"))
+ panel.sendEvent(AppletPanel.APPLET_ERROR);
+ else
+ // non-fatal error if we get an unrecognized event
+ PluginDebug.debug("Unrecognized event name: " + events[i]);
+ }
+
+ while (!panel.emptyEventQueue()) ;
+ }
+ }
+
+
+ /**
+ * Split a string based on the presence of a specified separator. Returns
+ * an array of arbitrary length. The end of each element in the array is
+ * indicated by the separator of the end of the string. If there is a
+ * separator immediately before the end of the string, the final element
+ * will be empty. None of the strings will contain the separator. Useful
+ * when separating strings such as "foo/bar/bas" using separator "/".
+ *
+ * @param sep The separator.
+ * @param s The string to split.
+ * @return An array of strings. Each string in the array is determined
+ * by the location of the provided sep in the original string,
+ * s. Whitespace not stripped.
+ */
+ private String [] splitSeparator(String sep, String s) {
+ Vector v = new Vector();
+ int tokenStart = 0;
+ int tokenEnd = 0;
+
+ while ((tokenEnd = s.indexOf(sep, tokenStart)) != -1) {
+ v.addElement(s.substring(tokenStart, tokenEnd));
+ tokenStart = tokenEnd+1;
+ }
+ // Add the final element.
+ v.addElement(s.substring(tokenStart));
+
+ String [] retVal = new String[v.size()];
+ v.copyInto(retVal);
+ return retVal;
+ }
+ }
+
+ class PluginParseRequest
+ {
+ long handle;
+ String tag;
+ String documentbase;
+ }
+
+ /*
+ */
+ // FIXME: declare JSProxy implementation
+ public class PluginAppletViewer extends XEmbeddedFrame
+ implements AppletContext, Printable {
+ /**
+ * Some constants...
+ */
+ private static String defaultSaveFile = "Applet.ser";
+
+ private static enum PAV_INIT_STATUS {PRE_INIT, IN_INIT, INIT_COMPLETE, INACTIVE};
+
+ /**
+ * The panel in which the applet is being displayed.
+ */
+ AppletViewerPanel panel;
+
+ /**
+ * The status line.
+ */
+ Label label;
+
+ /**
+ * output status messages to this stream
+ */
+
+ PrintStream statusMsgStream;
+
+ int identifier;
+
+ private static HashMap<Integer, PluginParseRequest> requests =
+ new HashMap();
+
+ // Instance identifier -> PluginAppletViewer object.
+ private static HashMap<Integer, PluginAppletViewer> applets =
+ new HashMap();
+
+ private static PluginStreamHandler streamhandler;
+
+ private static PluginCallRequestFactory requestFactory;
+
+ private static HashMap<Integer, PAV_INIT_STATUS> status =
+ new HashMap<Integer,PAV_INIT_STATUS>();
+
+
+ private long handle = 0;
+ private WindowListener windowEventListener = null;
+ private AppletEventListener appletEventListener = null;
+
+ public static final int APPLET_TIMEOUT = 180000;
+
+ private static Long requestIdentityCounter = 0L;
+
+ /**
+ * Null constructor to allow instantiation via newInstance()
+ */
+ public PluginAppletViewer() {
+ }
+
+ public static void reFrame(PluginAppletViewer oldFrame,
+ int identifier, PrintStream statusMsgStream,
+ long handle, AppletViewerPanel panel) {
+
+ PluginDebug.debug("Reframing " + panel);
+
+ // SecurityManager MUST be set, and only privileged code may call reFrame()
+ System.getSecurityManager().checkPermission(new AllPermission());
+
+ // Same handle => nothing to do
+ if (oldFrame != null && handle == oldFrame.handle)
+ return;
+
+ PluginAppletViewer newFrame = new PluginAppletViewer(handle, identifier, statusMsgStream, panel);
+
+ if (oldFrame != null) {
+ applets.remove(oldFrame.identifier);
+ oldFrame.removeWindowListener(oldFrame.windowEventListener);
+ panel.removeAppletListener(oldFrame.appletEventListener);
+ oldFrame.remove(panel);
+ oldFrame.dispose();
+ }
+
+ newFrame.add("Center", panel);
+ newFrame.pack();
+
+ newFrame.appletEventListener = new AppletEventListener(newFrame, newFrame);
+ panel.addAppletListener(newFrame.appletEventListener);
+
+ applets.put(identifier, newFrame);
+
+ // dispose oldframe if necessary
+ if (oldFrame != null) {
+ oldFrame.dispose();
+ }
+
+ PluginDebug.debug(panel + " reframed");
+ }
+
+ /**
+ * Create new plugin appletviewer frame
+ */
+ private PluginAppletViewer(long handle, final int identifier,
+ PrintStream statusMsgStream,
+ AppletViewerPanel appletPanel) {
+
+ super(handle, true);
+ this.statusMsgStream = statusMsgStream;
+ this.identifier = identifier;
+ this.panel = appletPanel;
+
+ if (!appletPanels.contains(panel))
+ appletPanels.addElement(panel);
+
+ windowEventListener = new WindowAdapter() {
+
+ public void windowClosing(WindowEvent evt) {
+ appletClose();
+ }
+
+ public void windowIconified(WindowEvent evt) {
+ appletStop();
+ }
+
+ public void windowDeiconified(WindowEvent evt) {
+ appletStart();
+ }
+ };
+
+ addWindowListener(windowEventListener);
+
+ }
+
+ private static class AppletEventListener implements AppletListener
+ {
+ final Frame frame;
+ final PluginAppletViewer appletViewer;
+
+ public AppletEventListener(Frame frame, PluginAppletViewer appletViewer)
+ {
+ this.frame = frame;
+ this.appletViewer = appletViewer;
+ }
+
+ public void appletStateChanged(AppletEvent evt)
+ {
+ AppletPanel src = (AppletPanel)evt.getSource();
+
+ switch (evt.getID()) {
+ case AppletPanel.APPLET_RESIZE: {
+ if(src != null) {
+ appletViewer.resize(appletViewer.preferredSize());
+ appletViewer.validate();
+ }
+ break;
+ }
+ case AppletPanel.APPLET_LOADING_COMPLETED: {
+ Applet a = src.getApplet(); // sun.applet.AppletPanel
+
+ // Fixed #4754451: Applet can have methods running on main
+ // thread event queue.
+ //
+ // The cause of this bug is that the frame of the applet
+ // is created in main thread group. Thus, when certain
+ // AWT/Swing events are generated, the events will be
+ // dispatched through the wrong event dispatch thread.
+ //
+ // To fix this, we rearrange the AppContext with the frame,
+ // so the proper event queue will be looked up.
+ //
+ // Swing also maintains a Frame list for the AppContext,
+ // so we will have to rearrange it as well.
+ //
+ if (a != null)
+ AppletPanel.changeFrameAppContext(frame, SunToolkit.targetToAppContext(a));
+ else
+ AppletPanel.changeFrameAppContext(frame, AppContext.getAppContext());
+
+ status.put(appletViewer.identifier, PAV_INIT_STATUS.INIT_COMPLETE);
+
+ break;
+ }
+ }
+ }
+ }
+
+ public static void setStreamhandler(PluginStreamHandler sh) {
+ streamhandler = sh;
+ }
+
+ public static void setPluginCallRequestFactory(PluginCallRequestFactory rf) {
+ requestFactory = rf;
+ }
+
+ /**
+ * Handle an incoming message from the plugin.
+ */
+ public static void handleMessage(int identifier, int reference, String message)
+ {
+
+ PluginDebug.debug("PAV handling: " + message);
+
+ try {
+ if (message.startsWith("handle")) {
+
+ // Extract the information from the message
+ String[] msgParts = new String[4];
+ for (int i=0; i < 3; i++) {
+ int spaceLocation = message.indexOf(' ');
+ int nextSpaceLocation = message.indexOf(' ', spaceLocation+1);
+ msgParts[i] = message.substring(spaceLocation + 1, nextSpaceLocation);
+ message = message.substring(nextSpaceLocation + 1);
+ }
+
+ long handle = Long.parseLong(msgParts[0]);
+ String width = msgParts[1];
+ String height = msgParts[2];
+
+ int spaceLocation = message.indexOf(' ', "tag".length()+1);
+ String documentBase =
+ UrlUtil.decode(message.substring("tag".length() + 1, spaceLocation));
+ String tag = message.substring(spaceLocation+1);
+
+ PluginDebug.debug ("Handle = " + handle + "\n" +
+ "Width = " + width + "\n" +
+ "Height = " + height + "\n" +
+ "DocumentBase = " + documentBase + "\n" +
+ "Tag = " + tag);
+
+ status.put(identifier, PAV_INIT_STATUS.PRE_INIT);
+ PluginAppletViewer.parse
+ (identifier, handle, width, height,
+ new StringReader(tag),
+ new URL(documentBase));
+
+
+ int maxWait = APPLET_TIMEOUT; // wait for applet to fully load
+ int wait = 0;
+ while (!status.get(identifier).equals(PAV_INIT_STATUS.INIT_COMPLETE) &&
+ (wait < maxWait)) {
+
+ try {
+ Thread.sleep(50);
+ wait += 50;
+ } catch (InterruptedException ie) {
+ // just wait
+ }
+ }
+
+ if (!status.get(identifier).equals(PAV_INIT_STATUS.INIT_COMPLETE))
+ throw new Exception("Applet initialization timeout");
+
+ } else {
+ PluginDebug.debug ("Handling message: " + message + " instance " + identifier + " " + Thread.currentThread());
+
+ // Wait till initialization finishes
+ while (!applets.containsKey(identifier) &&
+ (
+ !status.containsKey(identifier) ||
+ status.get(identifier).equals(PAV_INIT_STATUS.PRE_INIT)
+ )
+ );
+
+ // don't bother processing further for inactive applets
+ if (status.get(identifier).equals(PAV_INIT_STATUS.INACTIVE))
+ return;
+
+ applets.get(identifier).handleMessage(reference, message);
+ }
+ } catch (Exception e) {
+
+ e.printStackTrace();
+
+ // If an exception happened during pre-init, we need to update status
+ if (status.get(identifier).equals(PAV_INIT_STATUS.PRE_INIT))
+ status.put(identifier, PAV_INIT_STATUS.INACTIVE);
+
+ throw new RuntimeException("Failed to handle message: " +
+ message + " for instance " + identifier, e);
+ }
+ }
+
+ public void handleMessage(int reference, String message)
+ {
+ if (message.startsWith("width")) {
+
+ // Wait for panel to come alive
+ int maxWait = APPLET_TIMEOUT; // wait for panel to come alive
+ int wait = 0;
+ while (!status.get(identifier).equals(PAV_INIT_STATUS.INIT_COMPLETE) && wait < maxWait) {
+
+ try {
+ Thread.sleep(50);
+ wait += 50;
+ } catch (InterruptedException ie) {
+ // just wait
+ }
+ }
+
+
+ // 0 => width, 1=> width_value, 2 => height, 3=> height_value
+ String[] dimMsg = message.split(" ");
+
+ final int height = (int) (Integer.parseInt(dimMsg[3]));
+ final int width = (int) (Integer.parseInt(dimMsg[1]));
+
+ if (panel instanceof NetxPanel)
+ ((NetxPanel) panel).updateSizeInAtts(height, width);
+
+ try {
+ SwingUtilities.invokeAndWait(new Runnable() {
+ public void run() {
+
+ setSize(width, height);
+
+ // There is a rather odd drawing bug whereby resizing
+ // the panel makes no difference on initial call
+ // because the panel thinks that it is already the
+ // right size. Validation has no effect there either.
+ // So we work around by setting size to 1, validating,
+ // and then setting to the right size and validating
+ // again. This is not very efficient, and there is
+ // probably a better way -- but resizing happens
+ // quite infrequently, so for now this is how we do it
+
+ panel.setSize(1,1);
+ panel.validate();
+
+ panel.setSize(width, height);
+ panel.validate();
+
+ panel.applet.resize(width, height);
+ panel.applet.validate();
+ }
+ });
+ } catch (InterruptedException e) {
+ // do nothing
+ e.printStackTrace();
+ } catch (InvocationTargetException e) {
+ // do nothing
+ e.printStackTrace();
+ }
+
+ } else if (message.startsWith("destroy")) {
+ dispose();
+ status.put(identifier, PAV_INIT_STATUS.INACTIVE);
+ } else if (message.startsWith("GetJavaObject")) {
+
+ // FIXME: how do we determine what security context this
+ // object should belong to?
+ Object o;
+
+ // Wait for panel to come alive
+ int maxWait = APPLET_TIMEOUT; // wait for panel to come alive
+ int wait = 0;
+ while ((panel == null) || (!((NetxPanel) panel).isAlive() && wait < maxWait)) {
+ try {
+ Thread.sleep(50);
+ wait += 50;
+ } catch (InterruptedException ie) {
+ // just wait
+ }
+ }
+
+ // Wait for the panel to initialize
+ // (happens in a separate thread)
+ while (panel.getApplet() == null &&
+ ((NetxPanel) panel).isAlive()) {
+ try {
+ Thread.sleep(50);
+ PluginDebug.debug("Waiting for applet to initialize...");
+ } catch (InterruptedException ie) {
+ // just wait
+ }
+ }
+
+ PluginDebug.debug(panel + " -- " + panel.getApplet() + " -- " + ((NetxPanel) panel).isAlive());
+
+ // Still null?
+ if (panel.getApplet() == null) {
+ this.streamhandler.write("instance " + identifier + " reference " + -1 + " fatalError " + "Initialization failed");
+ return;
+ }
+
+ o = panel.getApplet();
+ PluginDebug.debug ("Looking for object " + o + " panel is " + panel);
+ AppletSecurityContextManager.getSecurityContext(0).store(o);
+ PluginDebug.debug ("WRITING 1: " + "context 0 reference " + reference + " GetJavaObject "
+ + AppletSecurityContextManager.getSecurityContext(0).getIdentifier(o));
+ streamhandler.write("context 0 reference " + reference + " GetJavaObject "
+ + AppletSecurityContextManager.getSecurityContext(0).getIdentifier(o));
+ PluginDebug.debug ("WRITING 1 DONE");
+ }
+ }
+
+ // FIXME: Kind of hackish way to ensure synchronized re-drawing
+ private synchronized void forceredraw() {
+ doLayout();
+ }
+
+ /*
+ * Methods for java.applet.AppletContext
+ */
+
+ private static Map audioClips = new HashMap();
+
+ /**
+ * Get an audio clip.
+ */
+ public AudioClip getAudioClip(URL url) {
+ checkConnect(url);
+ synchronized (audioClips) {
+ AudioClip clip = (AudioClip)audioClips.get(url);
+ if (clip == null) {
+ audioClips.put(url, clip = new AppletAudioClip(url));
+ }
+ return clip;
+ }
+ }
+
+ private static Map imageRefs = new HashMap();
+
+ /**
+ * Get an image.
+ */
+ public Image getImage(URL url) {
+ return getCachedImage(url);
+ }
+
+ private Image getCachedImage(URL url) {
+ // System.getSecurityManager().checkConnection(url.getHost(), url.getPort());
+ return (Image)getCachedImageRef(url).get();
+ }
+
+ /**
+ * Get an image ref.
+ */
+ private synchronized Ref getCachedImageRef(URL url) {
+ PluginDebug.debug("getCachedImageRef() searching for " + url);
+
+ try {
+
+ String originalURL = url.toString();
+ String codeBase = panel.getCodeBase().toString();
+
+ if (originalURL.startsWith(codeBase)) {
+
+ PluginDebug.debug("getCachedImageRef() got URL = " + url);
+ PluginDebug.debug("getCachedImageRef() plugin codebase = " + codeBase);
+
+ // try to fetch it locally
+ if (panel instanceof NetxPanel) {
+
+ URL localURL = null;
+
+ String resourceName = originalURL.substring(codeBase.length());
+ JNLPClassLoader loader = (JNLPClassLoader) ((NetxPanel) panel).getAppletClassLoader();
+
+ if (loader.resourceAvailableLocally(resourceName))
+ localURL = loader.getResource(resourceName);
+
+ url = localURL != null ? localURL : url;
+ }
+ }
+
+ PluginDebug.debug("getCachedImageRef() getting img from URL = " + url);
+
+ synchronized (imageRefs) {
+ AppletImageRef ref = (AppletImageRef)imageRefs.get(url);
+ if (ref == null) {
+ ref = new AppletImageRef(url);
+ imageRefs.put(url, ref);
+ }
+ return ref;
+ }
+ } catch (Exception e) {
+ System.err.println("Error occurred when trying to fetch image:");
+ e.printStackTrace();
+ return null;
+ }
+ }
+
+ /**
+ * Flush the image cache.
+ */
+ static void flushImageCache() {
+ imageRefs.clear();
+ }
+
+ static Vector appletPanels = new Vector();
+
+ /**
+ * Get an applet by name.
+ */
+ public Applet getApplet(String name) {
+ name = name.toLowerCase();
+ SocketPermission panelSp =
+ new SocketPermission(panel.getCodeBase().getHost(), "connect");
+ for (Enumeration e = appletPanels.elements() ; e.hasMoreElements() ;) {
+ AppletPanel p = (AppletPanel)e.nextElement();
+ String param = p.getParameter("name");
+ if (param != null) {
+ param = param.toLowerCase();
+ }
+ if (name.equals(param) &&
+ p.getDocumentBase().equals(panel.getDocumentBase())) {
+
+ SocketPermission sp =
+ new SocketPermission(p.getCodeBase().getHost(), "connect");
+
+ if (panelSp.implies(sp)) {
+ return p.applet;
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Return an enumeration of all the accessible
+ * applets on this page.
+ */
+ public Enumeration getApplets() {
+ Vector v = new Vector();
+ SocketPermission panelSp =
+ new SocketPermission(panel.getCodeBase().getHost(), "connect");
+
+ for (Enumeration e = appletPanels.elements() ; e.hasMoreElements() ;) {
+ AppletPanel p = (AppletPanel)e.nextElement();
+ if (p.getDocumentBase().equals(panel.getDocumentBase())) {
+
+ SocketPermission sp =
+ new SocketPermission(p.getCodeBase().getHost(), "connect");
+ if (panelSp.implies(sp)) {
+ v.addElement(p.applet);
+ }
+ }
+ }
+ return v.elements();
+ }
+
+ /**
+ * Ignore.
+ */
+ public void showDocument(URL url) {
+ PluginDebug.debug("Showing document...");
+ showDocument(url, "_self");
+ }
+
+ /**
+ * Ignore.
+ */
+ public void showDocument(URL url, String target) {
+ try {
+ // FIXME: change to postCallRequest
+ write("url " + UrlUtil.encode(url.toString(), "UTF-8") + " " + target);
+ } catch (IOException exception) {
+ // Deliberately ignore IOException. showDocument may be
+ // called from threads other than the main thread after
+ // streamhandler.pluginOutputStream has been closed.
+ }
+ }
+
+ /**
+ * Show status.
+ */
+ public void showStatus(String status) {
+ try {
+ // FIXME: change to postCallRequest
+ // For statuses, we cannot have a newline
+ status = status.replace("\n", " ");
+ write("status " + status);
+ } catch (IOException exception) {
+ // Deliberately ignore IOException. showStatus may be
+ // called from threads other than the main thread after
+ // streamhandler.pluginOutputStream has been closed.
+ }
+ }
+
+ /**
+ * Returns an incremental number (unique identifier) for a message.
+ * If identifier hits Long.MAX_VALUE it loops back starting at 0.
+ *
+ * @return A unique Long identifier for the request
+ */
+ private static Long getRequestIdentifier() {
+ synchronized (requestIdentityCounter) {
+
+ if (requestIdentityCounter == Long.MAX_VALUE)
+ requestIdentityCounter = 0L;
+
+ return requestIdentityCounter++;
+ }
+ }
+
+ public long getWindow() {
+ PluginDebug.debug ("STARTING getWindow");
+ Long reference = getRequestIdentifier();
+
+ PluginCallRequest request = requestFactory.getPluginCallRequest("window",
+ "instance " + identifier + " reference " +
+ + reference + " " + "GetWindow", reference);
+
+ PluginDebug.debug ("STARTING postCallRequest");
+ streamhandler.postCallRequest(request);
+ PluginDebug.debug ("STARTING postCallRequest done");
+ streamhandler.write(request.getMessage());
+ try {
+ PluginDebug.debug ("wait request 1");
+ synchronized(request) {
+ PluginDebug.debug ("wait request 2");
+ while ((Long) request.getObject() == 0)
+ request.wait();
+ PluginDebug.debug ("wait request 3");
+ }
+ } catch (InterruptedException e) {
+ throw new RuntimeException("Interrupted waiting for call request.",
+ e);
+ }
+
+ PluginDebug.debug ("STARTING getWindow DONE");
+ return (Long) request.getObject();
+ }
+
+ // FIXME: make private, access via reflection.
+ public static Object getMember(long internal, String name)
+ {
+ AppletSecurityContextManager.getSecurityContext(0).store(name);
+ int nameID = AppletSecurityContextManager.getSecurityContext(0).getIdentifier(name);
+ Long reference = getRequestIdentifier();
+
+ // Prefix with dummy instance for convenience.
+ PluginCallRequest request = requestFactory.getPluginCallRequest("member",
+ "instance " + 0 + " reference " + reference + " GetMember " +
+ internal + " " + nameID, reference);
+
+ streamhandler.postCallRequest(request);
+ streamhandler.write(request.getMessage());
+ try {
+ PluginDebug.debug ("wait getMEM request 1");
+ synchronized(request) {
+ PluginDebug.debug ("wait getMEM request 2");
+ while (request.isDone() == false)
+ request.wait();
+ PluginDebug.debug ("wait getMEM request 3 GOT: " + request.getObject().getClass());
+ }
+ } catch (InterruptedException e) {
+ throw new RuntimeException("Interrupted waiting for call request.",
+ e);
+ }
+ PluginDebug.debug (" getMember DONE");
+ return request.getObject();
+ }
+
+ public static void setMember(long internal, String name, Object value) {
+ System.err.println("Setting to class " + value.getClass() + ":" + value.getClass().isPrimitive());
+ AppletSecurityContextManager.getSecurityContext(0).store(name);
+ int nameID = AppletSecurityContextManager.getSecurityContext(0).getIdentifier(name);
+ Long reference = getRequestIdentifier();
+
+ // work on a copy of value, as we don't want to be manipulating
+ // complex objects
+ String valueToSetTo;
+ if (value instanceof java.lang.Byte ||
+ value instanceof java.lang.Character ||
+ value instanceof java.lang.Short ||
+ value instanceof java.lang.Integer ||
+ value instanceof java.lang.Long ||
+ value instanceof java.lang.Float ||
+ value instanceof java.lang.Double ||
+ value instanceof java.lang.Boolean) {
+
+ valueToSetTo = "literalreturn " + value.toString();
+
+ // Character -> Str results in str value.. we need int value as
+ // per specs.
+ if (value instanceof java.lang.Character) {
+ valueToSetTo = "literalreturn " + (int) ((java.lang.Character) value).charValue();
+ } else if (value instanceof Float ||
+ value instanceof Double) {
+ valueToSetTo = "literalreturn " + String.format("%308.308e", value);
+ }
+
+ } else {
+ AppletSecurityContextManager.getSecurityContext(0).store(value);
+ valueToSetTo = Integer.toString(AppletSecurityContextManager.getSecurityContext(0).getIdentifier(value));
+ }
+
+ // Prefix with dummy instance for convenience.
+ PluginCallRequest request = requestFactory.getPluginCallRequest("void",
+ "instance " + 0 + " reference " + reference + " SetMember " +
+ internal + " " + nameID + " " + valueToSetTo, reference);
+
+ streamhandler.postCallRequest(request);
+ streamhandler.write(request.getMessage());
+ try {
+ PluginDebug.debug ("wait setMem request: " + request.getMessage());
+ PluginDebug.debug ("wait setMem request 1");
+ synchronized(request) {
+ PluginDebug.debug ("wait setMem request 2");
+ while (request.isDone() == false)
+ request.wait();
+ PluginDebug.debug ("wait setMem request 3");
+ }
+ } catch (InterruptedException e) {
+ throw new RuntimeException("Interrupted waiting for call request.",
+ e);
+ }
+ PluginDebug.debug (" setMember DONE");
+ }
+
+ // FIXME: handle long index as well.
+ public static void setSlot(long internal, int index, Object value) {
+ AppletSecurityContextManager.getSecurityContext(0).store(value);
+ Long reference = getRequestIdentifier();
+
+ // work on a copy of value, as we don't want to be manipulating
+ // complex objects
+ String valueToSetTo;
+ if (value instanceof java.lang.Byte ||
+ value instanceof java.lang.Character ||
+ value instanceof java.lang.Short ||
+ value instanceof java.lang.Integer ||
+ value instanceof java.lang.Long ||
+ value instanceof java.lang.Float ||
+ value instanceof java.lang.Double ||
+ value instanceof java.lang.Boolean) {
+
+ valueToSetTo = "literalreturn " + value.toString();
+
+ // Character -> Str results in str value.. we need int value as
+ // per specs.
+ if (value instanceof java.lang.Character) {
+ valueToSetTo = "literalreturn " + (int) ((java.lang.Character) value).charValue();
+ } else if (value instanceof Float ||
+ value instanceof Double) {
+ valueToSetTo = "literalreturn " + String.format("%308.308e", value);
+ }
+
+ } else {
+ AppletSecurityContextManager.getSecurityContext(0).store(value);
+ valueToSetTo = Integer.toString(AppletSecurityContextManager.getSecurityContext(0).getIdentifier(value));
+ }
+
+ // Prefix with dummy instance for convenience.
+ PluginCallRequest request = requestFactory.getPluginCallRequest("void",
+ "instance " + 0 + " reference " + reference + " SetSlot " +
+ internal + " " + index + " " + valueToSetTo, reference);
+
+ streamhandler.postCallRequest(request);
+ streamhandler.write(request.getMessage());
+ try {
+ PluginDebug.debug ("wait setSlot request 1");
+ synchronized(request) {
+ PluginDebug.debug ("wait setSlot request 2");
+ while (request.isDone() == false)
+ request.wait();
+ PluginDebug.debug ("wait setSlot request 3");
+ }
+ } catch (InterruptedException e) {
+ throw new RuntimeException("Interrupted waiting for call request.",
+ e);
+ }
+ PluginDebug.debug (" setSlot DONE");
+ }
+
+ public static Object getSlot(long internal, int index)
+ {
+ Long reference = getRequestIdentifier();
+
+ // Prefix with dummy instance for convenience.
+ PluginCallRequest request = requestFactory.getPluginCallRequest("member",
+ "instance " + 0 + " reference " + reference + " GetSlot " +
+ internal + " " + index, reference);
+ streamhandler.postCallRequest(request);
+ streamhandler.write(request.getMessage());
+ try {
+ PluginDebug.debug ("wait getSlot request 1");
+ synchronized(request) {
+ PluginDebug.debug ("wait getSlot request 2");
+ while (request.isDone() == false)
+ request.wait();
+ PluginDebug.debug ("wait getSlot request 3");
+ }
+ } catch (InterruptedException e) {
+ throw new RuntimeException("Interrupted waiting for call request.",
+ e);
+ }
+ PluginDebug.debug (" getSlot DONE");
+ return request.getObject();
+ }
+
+ public static Object eval(long internal, String s)
+ {
+ AppletSecurityContextManager.getSecurityContext(0).store(s);
+ int stringID = AppletSecurityContextManager.getSecurityContext(0).getIdentifier(s);
+ Long reference = getRequestIdentifier();
+
+ // Prefix with dummy instance for convenience.
+ // FIXME: rename GetMemberPluginCallRequest ObjectPluginCallRequest.
+ PluginCallRequest request = requestFactory.getPluginCallRequest("member",
+ "instance " + 0 + " reference " + reference + " Eval " +
+ internal + " " + stringID, reference);
+ streamhandler.postCallRequest(request);
+ streamhandler.write(request.getMessage());
+ try {
+ PluginDebug.debug ("wait eval request 1");
+ synchronized(request) {
+ PluginDebug.debug ("wait eval request 2");
+ while (request.isDone() == false)
+ request.wait();
+ PluginDebug.debug ("wait eval request 3");
+ }
+ } catch (InterruptedException e) {
+ throw new RuntimeException("Interrupted waiting for call request.",
+ e);
+ }
+ PluginDebug.debug (" getSlot DONE");
+ return request.getObject();
+ }
+
+ public static void removeMember (long internal, String name) {
+ AppletSecurityContextManager.getSecurityContext(0).store(name);
+ int nameID = AppletSecurityContextManager.getSecurityContext(0).getIdentifier(name);
+ Long reference = getRequestIdentifier();
+
+ // Prefix with dummy instance for convenience.
+ PluginCallRequest request = requestFactory.getPluginCallRequest("void",
+ "instance " + 0 + " reference " + reference + " RemoveMember " +
+ internal + " " + nameID, reference);
+
+ streamhandler.postCallRequest(request);
+ streamhandler.write(request.getMessage());
+ try {
+ PluginDebug.debug ("wait removeMember request 1");
+ synchronized(request) {
+ PluginDebug.debug ("wait removeMember request 2");
+ while (request.isDone() == false)
+ request.wait();
+ PluginDebug.debug ("wait removeMember request 3");
+ }
+ } catch (InterruptedException e) {
+ throw new RuntimeException("Interrupted waiting for call request.",
+ e);
+ }
+ PluginDebug.debug (" RemoveMember DONE");
+ }
+
+ public static Object call(long internal, String name, Object args[])
+ {
+ // FIXME: when is this removed from the object store?
+ // FIXME: reference should return the ID.
+ // FIXME: convenience method for this long line.
+ AppletSecurityContextManager.getSecurityContext(0).store(name);
+ int nameID = AppletSecurityContextManager.getSecurityContext(0).getIdentifier(name);
+ Long reference = getRequestIdentifier();
+
+ String argIDs = "";
+ for (Object arg : args)
+ {
+ AppletSecurityContextManager.getSecurityContext(0).store(arg);
+ argIDs += AppletSecurityContextManager.getSecurityContext(0).getIdentifier(arg) + " ";
+ }
+ argIDs = argIDs.trim();
+
+ // Prefix with dummy instance for convenience.
+ PluginCallRequest request = requestFactory.getPluginCallRequest("member",
+ "instance " + 0 + " reference " + reference + " Call " +
+ internal + " " + nameID + " " + argIDs, reference);
+
+ streamhandler.postCallRequest(request);
+ streamhandler.write(request.getMessage());
+ try {
+ PluginDebug.debug ("wait call request 1");
+ synchronized(request) {
+ PluginDebug.debug ("wait call request 2");
+ while (request.isDone() == false)
+ request.wait();
+ PluginDebug.debug ("wait call request 3");
+ }
+ } catch (InterruptedException e) {
+ throw new RuntimeException("Interrupted waiting for call request.",
+ e);
+ }
+ PluginDebug.debug (" Call DONE");
+ return request.getObject();
+ }
+
+ public static Object requestPluginCookieInfo(URI uri) {
+
+ PluginCallRequest request;
+ Long reference = getRequestIdentifier();
+
+ try
+ {
+ String encodedURI = UrlUtil.encode(uri.toString(), "UTF-8");
+ request = requestFactory.getPluginCallRequest("cookieinfo",
+ "plugin PluginCookieInfo " + "reference " + reference +
+ " " + encodedURI, reference);
+
+ } catch (UnsupportedEncodingException e)
+ {
+ e.printStackTrace();
+ return null;
+ }
+
+ PluginMessageConsumer.registerPriorityWait(reference);
+ streamhandler.postCallRequest(request);
+ streamhandler.write(request.getMessage());
+ try {
+ PluginDebug.debug ("wait cookieinfo request 1");
+ synchronized(request) {
+ PluginDebug.debug ("wait cookieinfo request 2");
+ while (request.isDone() == false)
+ request.wait();
+ PluginDebug.debug ("wait cookieinfo request 3");
+ }
+ } catch (InterruptedException e) {
+ throw new RuntimeException("Interrupted waiting for cookieinfo request.",
+ e);
+ }
+ PluginDebug.debug (" Cookieinfo DONE");
+ return request.getObject();
+ }
+
+ public static Object requestPluginProxyInfo(URI uri) {
+
+ String requestURI = null;
+ Long reference = getRequestIdentifier();
+
+ try {
+
+ // there is no easy way to get SOCKS proxy info. So, we tell mozilla that we want proxy for
+ // an HTTP uri in case of non http/ftp protocols. If we get back a SOCKS proxy, we can
+ // use that, if we get back an http proxy, we fallback to DIRECT connect
+
+ String scheme = uri.getScheme();
+ String port = uri.getPort() != -1 ? ":" + uri.getPort() : "";
+ if (!uri.getScheme().startsWith("http") && !uri.getScheme().equals("ftp"))
+ scheme = "http";
+
+ requestURI = UrlUtil.encode(scheme + "://" + uri.getHost() + port + "/" + uri.getPath(), "UTF-8");
+ } catch (Exception e) {
+ PluginDebug.debug("Cannot construct URL from " + uri.toString() + " ... falling back to DIRECT proxy");
+ e.printStackTrace();
+ return null;
+ }
+
+ PluginCallRequest request = requestFactory.getPluginCallRequest("proxyinfo",
+ "plugin PluginProxyInfo reference " + reference + " " +
+ requestURI, reference);
+
+ PluginMessageConsumer.registerPriorityWait(reference);
+ streamhandler.postCallRequest(request);
+ streamhandler.write(request.getMessage());
+ try {
+ PluginDebug.debug ("wait call request 1");
+ synchronized(request) {
+ PluginDebug.debug ("wait call request 2");
+ while (request.isDone() == false)
+ request.wait();
+ PluginDebug.debug ("wait call request 3");
+ }
+ } catch (InterruptedException e) {
+ throw new RuntimeException("Interrupted waiting for call request.",
+ e);
+ }
+ PluginDebug.debug (" Call DONE");
+ return request.getObject();
+ }
+
+ public static void JavaScriptFinalize(long internal)
+ {
+ Long reference = getRequestIdentifier();
+
+ // Prefix with dummy instance for convenience.
+ PluginCallRequest request = requestFactory.getPluginCallRequest("void",
+ "instance " + 0 + " reference " + reference + " Finalize " +
+ internal, reference);
+
+ streamhandler.postCallRequest(request);
+ streamhandler.write(request.getMessage());
+ try {
+ PluginDebug.debug ("wait finalize request 1");
+ synchronized(request) {
+ PluginDebug.debug ("wait finalize request 2");
+ while (request.isDone() == false)
+ request.wait();
+ PluginDebug.debug ("wait finalize request 3");
+ }
+ } catch (InterruptedException e) {
+ throw new RuntimeException("Interrupted waiting for call request.",
+ e);
+ }
+ PluginDebug.debug (" finalize DONE");
+ }
+
+ public static String javascriptToString(long internal)
+ {
+ Long reference = getRequestIdentifier();
+
+ // Prefix with dummy instance for convenience.
+ PluginCallRequest request = requestFactory.getPluginCallRequest("member",
+ "instance " + 0 + " reference " + reference + " ToString " +
+ internal, reference);
+
+ streamhandler.postCallRequest(request);
+ streamhandler.write(request.getMessage());
+ try {
+ PluginDebug.debug ("wait ToString request 1");
+ synchronized(request) {
+ PluginDebug.debug ("wait ToString request 2");
+ while (request.isDone() == false)
+ request.wait();
+ PluginDebug.debug ("wait ToString request 3");
+ }
+ } catch (InterruptedException e) {
+ throw new RuntimeException("Interrupted waiting for call request.",
+ e);
+ }
+ PluginDebug.debug (" ToString DONE");
+ return (String) request.getObject();
+ }
+
+ // FIXME: make this private and access it from JSObject using
+ // reflection.
+ private void write(String message) throws IOException {
+ PluginDebug.debug ("WRITING 2: " + "instance " + identifier + " " + message);
+ streamhandler.write("instance " + identifier + " " + message);
+ PluginDebug.debug ("WRITING 2 DONE");
+ }
+
+ public void setStream(String key, InputStream stream)throws IOException{
+ // We do nothing.
+ }
+
+ public InputStream getStream(String key){
+ // We do nothing.
+ return null;
+ }
+
+ public Iterator getStreamKeys(){
+ // We do nothing.
+ return null;
+ }
+
+ /**
+ * System parameters.
+ */
+ static Hashtable systemParam = new Hashtable();
+
+ static {
+ systemParam.put("codebase", "codebase");
+ systemParam.put("code", "code");
+ systemParam.put("alt", "alt");
+ systemParam.put("width", "width");
+ systemParam.put("height", "height");
+ systemParam.put("align", "align");
+ systemParam.put("vspace", "vspace");
+ systemParam.put("hspace", "hspace");
+ }
+
+ /**
+ * Print the HTML tag.
+ */
+ public static void printTag(PrintStream out, Hashtable atts) {
+ out.print("<applet");
+
+ String v = (String)atts.get("codebase");
+ if (v != null) {
+ out.print(" codebase=\"" + v + "\"");
+ }
+
+ v = (String)atts.get("code");
+ if (v == null) {
+ v = "applet.class";
+ }
+ out.print(" code=\"" + v + "\"");
+ v = (String)atts.get("width");
+ if (v == null) {
+ v = "150";
+ }
+ out.print(" width=" + v);
+
+ v = (String)atts.get("height");
+ if (v == null) {
+ v = "100";
+ }
+ out.print(" height=" + v);
+
+ v = (String)atts.get("name");
+ if (v != null) {
+ out.print(" name=\"" + v + "\"");
+ }
+ out.println(">");
+
+ // A very slow sorting algorithm
+ int len = atts.size();
+ String params[] = new String[len];
+ len = 0;
+ for (Enumeration e = atts.keys() ; e.hasMoreElements() ;) {
+ String param = (String)e.nextElement();
+ int i = 0;
+ for (; i < len ; i++) {
+ if (params[i].compareTo(param) >= 0) {
+ break;
+ }
+ }
+ System.arraycopy(params, i, params, i + 1, len - i);
+ params[i] = param;
+ len++;
+ }
+
+ for (int i = 0 ; i < len ; i++) {
+ String param = params[i];
+ if (systemParam.get(param) == null) {
+ out.println("<param name=" + param +
+ " value=\"" + atts.get(param) + "\">");
+ }
+ }
+ out.println("</applet>");
+ }
+
+ /**
+ * Make sure the atrributes are uptodate.
+ */
+ public void updateAtts() {
+ Dimension d = panel.size();
+ Insets in = panel.insets();
+ panel.atts.put("width",
+ new Integer(d.width - (in.left + in.right)).toString());
+ panel.atts.put("height",
+ new Integer(d.height - (in.top + in.bottom)).toString());
+ }
+
+ /**
+ * Restart the applet.
+ */
+ void appletRestart() {
+ panel.sendEvent(AppletPanel.APPLET_STOP);
+ panel.sendEvent(AppletPanel.APPLET_DESTROY);
+ panel.sendEvent(AppletPanel.APPLET_INIT);
+ panel.sendEvent(AppletPanel.APPLET_START);
+ }
+
+ /**
+ * Reload the applet.
+ */
+ void appletReload() {
+ panel.sendEvent(AppletPanel.APPLET_STOP);
+ panel.sendEvent(AppletPanel.APPLET_DESTROY);
+ panel.sendEvent(AppletPanel.APPLET_DISPOSE);
+
+ /**
+ * Fixed #4501142: Classlaoder sharing policy doesn't
+ * take "archive" into account. This will be overridden
+ * by Java Plug-in. [stanleyh]
+ */
+ AppletPanel.flushClassLoader(panel.getClassLoaderCacheKey());
+
+ /*
+ * Make sure we don't have two threads running through the event queue
+ * at the same time.
+ */
+ try {
+ panel.joinAppletThread();
+ panel.release();
+ } catch (InterruptedException e) {
+ return; // abort the reload
+ }
+
+ AccessController.doPrivileged(new PrivilegedAction() {
+ public Object run() {
+ panel.createAppletThread();
+ return null;
+ }
+ });
+
+ panel.sendEvent(AppletPanel.APPLET_LOAD);
+ panel.sendEvent(AppletPanel.APPLET_INIT);
+ panel.sendEvent(AppletPanel.APPLET_START);
+ }
+
+ public int print(Graphics graphics, PageFormat pf, int pageIndex) {
+ return Printable.NO_SUCH_PAGE;
+ }
+
+ /**
+ * Start the applet.
+ */
+ void appletStart() {
+ panel.sendEvent(AppletPanel.APPLET_START);
+ }
+
+ /**
+ * Stop the applet.
+ */
+ void appletStop() {
+ panel.sendEvent(AppletPanel.APPLET_STOP);
+ }
+
+ /**
+ * Shutdown a viewer.
+ * Stop, Destroy, Dispose and Quit a viewer
+ */
+ private void appletShutdown(AppletPanel p) {
+ p.sendEvent(AppletPanel.APPLET_STOP);
+ p.sendEvent(AppletPanel.APPLET_DESTROY);
+ p.sendEvent(AppletPanel.APPLET_DISPOSE);
+ p.sendEvent(AppletPanel.APPLET_QUIT);
+ }
+
+ /**
+ * Close this viewer.
+ * Stop, Destroy, Dispose and Quit an AppletView, then
+ * reclaim resources and exit the program if this is
+ * the last applet.
+ */
+ void appletClose() {
+
+ // The caller thread is event dispatch thread, so
+ // spawn a new thread to avoid blocking the event queue
+ // when calling appletShutdown.
+ //
+ final AppletPanel p = panel;
+
+ new Thread(new Runnable()
+ {
+ public void run()
+ {
+ ThreadGroup tg = ((JNLPClassLoader) p.applet.getClass().getClassLoader()).getApplication().getThreadGroup();
+
+ appletShutdown(p);
+ appletPanels.removeElement(p);
+ dispose();
+
+ if (tg.activeCount() > 0)
+ tg.stop();
+
+ if (countApplets() == 0) {
+ appletSystemExit();
+ }
+ }
+ }).start();
+
+ status.put(identifier, PAV_INIT_STATUS.INACTIVE);
+ }
+
+ /**
+ * Exit the program.
+ * Exit from the program (if not stand alone) - do no clean-up
+ */
+ private void appletSystemExit() {
+ // Do nothing. Exit is handled by another
+ // block of code, called when _all_ applets are gone
+ }
+
+ /**
+ * How many applets are running?
+ */
+
+ public static int countApplets() {
+ return appletPanels.size();
+ }
+
+
+ /**
+ * Scan spaces.
+ */
+ public static void skipSpace(int[] c, Reader in) throws IOException {
+ while ((c[0] >= 0) &&
+ ((c[0] == ' ') || (c[0] == '\t') || (c[0] == '\n') || (c[0] == '\r'))) {
+ c[0] = in.read();
+ }
+ }
+
+ /**
+ * Scan identifier
+ */
+ public static String scanIdentifier(int[] c, Reader in) throws IOException {
+ StringBuffer buf = new StringBuffer();
+
+ if (c[0] == '!') {
+ // Technically, we should be scanning for '!--' but we are reading
+ // from a stream, and there is no way to peek ahead. That said,
+ // a ! at this point can only mean comment here afaik, so we
+ // should be okay
+ skipComment(c, in);
+ return "";
+ }
+
+ while (true) {
+ if (((c[0] >= 'a') && (c[0] <= 'z')) ||
+ ((c[0] >= 'A') && (c[0] <= 'Z')) ||
+ ((c[0] >= '0') && (c[0] <= '9')) || (c[0] == '_')) {
+ buf.append((char)c[0]);
+ c[0] = in.read();
+ } else {
+ return buf.toString();
+ }
+ }
+ }
+
+ public static void skipComment(int[] c, Reader in) throws IOException {
+ StringBuffer buf = new StringBuffer();
+ boolean commentHeaderPassed = false;
+ c[0] = in.read();
+ buf.append((char)c[0]);
+
+ while (true) {
+ if (c[0] == '-' && (c[0] = in.read()) == '-') {
+ buf.append((char)c[0]);
+ if (commentHeaderPassed) {
+ // -- encountered ... is > next?
+ if ((c[0] = in.read()) == '>') {
+ buf.append((char)c[0]);
+
+ PluginDebug.debug("Comment skipped: " + buf.toString());
+
+ // comment skipped.
+ return;
+ }
+ } else {
+ // first -- is part of <!-- ... , just mark that we have passed it
+ commentHeaderPassed = true;
+ }
+
+ } else if (commentHeaderPassed == false) {
+ buf.append((char)c[0]);
+ PluginDebug.debug("Warning: Attempted to skip comment, but this tag does not appear to be a comment: " + buf.toString());
+ return;
+ }
+
+ c[0] = in.read();
+ buf.append((char)c[0]);
+ }
+ }
+
+ /**
+ * Scan tag
+ */
+ public static Hashtable scanTag(int[] c, Reader in) throws IOException {
+ Hashtable atts = new Hashtable();
+ skipSpace(c, in);
+ while (c[0] >= 0 && c[0] != '>') {
+ String att = scanIdentifier(c, in);
+ String val = "";
+ skipSpace(c, in);
+ if (c[0] == '=') {
+ int quote = -1;
+ c[0] = in.read();
+ skipSpace(c, in);
+ if ((c[0] == '\'') || (c[0] == '\"')) {
+ quote = c[0];
+ c[0] = in.read();
+ }
+ StringBuffer buf = new StringBuffer();
+ while ((c[0] > 0) &&
+ (((quote < 0) && (c[0] != ' ') && (c[0] != '\t') &&
+ (c[0] != '\n') && (c[0] != '\r') && (c[0] != '>'))
+ || ((quote >= 0) && (c[0] != quote)))) {
+ buf.append((char)c[0]);
+ c[0] = in.read();
+ }
+ if (c[0] == quote) {
+ c[0] = in.read();
+ }
+ skipSpace(c, in);
+ val = buf.toString();
+ }
+
+ att = att.replace("&gt;", ">");
+ att = att.replace("&lt;", "<");
+ att = att.replace("&amp;", "&");
+ att = att.replace("&#10;", "\n");
+ att = att.replace("&#13;", "\r");
+
+ val = val.replace("&gt;", ">");
+ val = val.replace("&lt;", "<");
+ val = val.replace("&amp;", "&");
+ val = val.replace("&#10;", "\n");
+ val = val.replace("&#13;", "\r");
+
+ PluginDebug.debug("PUT " + att + " = '" + val + "'");
+ atts.put(att.toLowerCase(java.util.Locale.ENGLISH), val);
+
+ while (true) {
+ if ((c[0] == '>') || (c[0] < 0) ||
+ ((c[0] >= 'a') && (c[0] <= 'z')) ||
+ ((c[0] >= 'A') && (c[0] <= 'Z')) ||
+ ((c[0] >= '0') && (c[0] <= '9')) || (c[0] == '_'))
+ break;
+ c[0] = in.read();
+ }
+ //skipSpace(in);
+ }
+ return atts;
+ }
+
+ // private static final == inline
+ private static final boolean isInt(Object o) {
+ boolean isInt = false;
+
+ try {
+ Integer.parseInt((String) o);
+ isInt = true;
+ } catch (Exception e) {
+ // don't care
+ }
+
+ return isInt;
+ }
+
+ /* values used for placement of AppletViewer's frames */
+ private static int x = 0;
+ private static int y = 0;
+ private static final int XDELTA = 30;
+ private static final int YDELTA = XDELTA;
+
+ static String encoding = null;
+
+ static private Reader makeReader(InputStream is) {
+ if (encoding != null) {
+ try {
+ return new BufferedReader(new InputStreamReader(is, encoding));
+ } catch (IOException x) { }
+ }
+ InputStreamReader r = new InputStreamReader(is);
+ encoding = r.getEncoding();
+ return new BufferedReader(r);
+ }
+
+ /**
+ * Scan an html file for <applet> tags
+ */
+ public static void parse(int identifier, long handle, String width, String height, Reader in, URL url, String enc)
+ throws IOException {
+ encoding = enc;
+ parse(identifier, handle, width, height, in, url, System.out, new PluginAppletPanelFactory());
+ }
+
+ public static void parse(int identifier, long handle, String width, String height, Reader in, URL url)
+ throws IOException {
+
+ final int fIdentifier = identifier;
+ final long fHandle = handle;
+ final String fWidth = width;
+ final String fHeight = height;
+ final Reader fIn = in;
+ final URL fUrl = url;
+ PrivilegedAction pa = new PrivilegedAction() {
+ public Object run() {
+ try {
+ parse(fIdentifier, fHandle, fWidth, fHeight, fIn, fUrl, System.out, new PluginAppletPanelFactory());
+ } catch (IOException ioe) {
+ return ioe;
+ }
+
+ return null;
+ }
+ };
+
+ Object ret = AccessController.doPrivileged(pa);
+ if (ret instanceof IOException) {
+ throw (IOException) ret;
+ }
+ }
+
+ public static void parse(int identifier, long handle, String width,
+ String height, Reader in, URL url,
+ PrintStream statusMsgStream,
+ PluginAppletPanelFactory factory)
+ throws IOException
+ {
+ // <OBJECT> <EMBED> tag flags
+ boolean isAppletTag = false;
+ boolean isObjectTag = false;
+ boolean isEmbedTag = false;
+ boolean objectTagAlreadyParsed = false;
+ // The current character
+ // FIXME: This is an evil hack to force pass-by-reference.. the
+ // parsing code needs to be rewritten from scratch to prevent such
+ //a need
+ int[] c = new int[1];
+
+ // warning messages
+ String requiresNameWarning = amh.getMessage("parse.warning.requiresname");
+ String paramOutsideWarning = amh.getMessage("parse.warning.paramoutside");
+ String appletRequiresCodeWarning = amh.getMessage("parse.warning.applet.requirescode");
+ String appletRequiresHeightWarning = amh.getMessage("parse.warning.applet.requiresheight");
+ String appletRequiresWidthWarning = amh.getMessage("parse.warning.applet.requireswidth");
+ String objectRequiresCodeWarning = amh.getMessage("parse.warning.object.requirescode");
+ String objectRequiresHeightWarning = amh.getMessage("parse.warning.object.requiresheight");
+ String objectRequiresWidthWarning = amh.getMessage("parse.warning.object.requireswidth");
+ String embedRequiresCodeWarning = amh.getMessage("parse.warning.embed.requirescode");
+ String embedRequiresHeightWarning = amh.getMessage("parse.warning.embed.requiresheight");
+ String embedRequiresWidthWarning = amh.getMessage("parse.warning.embed.requireswidth");
+ String appNotLongerSupportedWarning = amh.getMessage("parse.warning.appnotLongersupported");
+
+ java.net.URLConnection conn = url.openConnection();
+ /* The original URL may have been redirected - this
+ * sets it to whatever URL/codebase we ended up getting
+ */
+ url = conn.getURL();
+
+ int ydisp = 1;
+ Hashtable atts = null;
+
+ while(true) {
+ c[0] = in.read();
+ if (c[0] == -1)
+ break;
+
+ if (c[0] == '<') {
+ c[0] = in.read();
+ if (c[0] == '/') {
+ c[0] = in.read();
+ String nm = scanIdentifier(c, in);
+ if (nm.equalsIgnoreCase("applet") ||
+ nm.equalsIgnoreCase("object") ||
+ nm.equalsIgnoreCase("embed")) {
+
+ // We can't test for a code tag until </OBJECT>
+ // because it is a parameter, not an attribute.
+ if(isObjectTag) {
+ if (atts.get("code") == null && atts.get("object") == null) {
+ statusMsgStream.println(objectRequiresCodeWarning);
+ atts = null;
+ }
+ }
+
+ if (atts != null) {
+ // XXX 5/18 In general this code just simply
+ // shouldn't be part of parsing. It's presence
+ // causes things to be a little too much of a
+ // hack.
+
+ // Let user know we are starting up
+ streamhandler.write("instance " + identifier + " status " + amh.getMessage("status.start"));
+ factory.createPanel(streamhandler, identifier, handle, x, y, url, atts);
+
+ x += XDELTA;
+ y += YDELTA;
+ // make sure we don't go too far!
+ Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
+ if ((x > d.width - 300) || (y > d.height - 300)) {
+ x = 0;
+ y = 2 * ydisp * YDELTA;
+ ydisp++;
+ }
+ }
+ atts = null;
+ isAppletTag = false;
+ isObjectTag = false;
+ isEmbedTag = false;
+ }
+ }
+ else {
+ String nm = scanIdentifier(c, in);
+ if (nm.equalsIgnoreCase("param")) {
+ Hashtable t = scanTag(c, in);
+ String att = (String)t.get("name");
+
+ if (atts.containsKey(att))
+ continue;
+
+ if (att == null) {
+ statusMsgStream.println(requiresNameWarning);
+ } else {
+ String val = (String)t.get("value");
+ if (val == null) {
+ statusMsgStream.println(requiresNameWarning);
+ } else if (atts != null) {
+ att = att.replace("&gt;", ">");
+ att = att.replace("&lt;", "<");
+ att = att.replace("&amp;", "&");
+ att = att.replace("&#10;", "\n");
+ att = att.replace("&#13;", "\r");
+ att = att.replace("&quot;", "\"");
+
+ val = val.replace("&gt;", ">");
+ val = val.replace("&lt;", "<");
+ val = val.replace("&amp;", "&");
+ val = val.replace("&#10;", "\n");
+ val = val.replace("&#13;", "\r");
+ val = val.replace("&quot;", "\"");
+ PluginDebug.debug("PUT " + att + " = " + val);
+ atts.put(att.toLowerCase(), val);
+ } else {
+ statusMsgStream.println(paramOutsideWarning);
+ }
+ }
+ }
+ else if (nm.equalsIgnoreCase("applet")) {
+ isAppletTag = true;
+ atts = scanTag(c, in);
+
+ // If there is a classid and no code tag present, transform it to code tag
+ if (atts.get("code") == null && atts.get("classid") != null && !((String) atts.get("classid")).startsWith("clsid:")) {
+ atts.put("code", atts.get("classid"));
+ }
+
+ // remove java: from code tag
+ if (atts.get("code") != null && ((String) atts.get("code")).startsWith("java:")) {
+ atts.put("code", ((String) atts.get("code")).substring(5));
+ }
+
+ if (atts.get("code") == null && atts.get("object") == null) {
+ statusMsgStream.println(appletRequiresCodeWarning);
+ atts = null;
+ }
+
+ if (atts.get("width") == null || !isInt(atts.get("width"))) {
+ atts.put("width", width);
+ }
+
+ if (atts.get("height") == null || !isInt(atts.get("height"))) {
+ atts.put("height", height);
+ }
+ }
+ else if (nm.equalsIgnoreCase("object")) {
+ isObjectTag = true;
+
+ // Once code is set, additional nested objects are ignored
+ if (!objectTagAlreadyParsed) {
+ objectTagAlreadyParsed = true;
+ atts = scanTag(c, in);
+ }
+
+ // If there is a classid and no code tag present, transform it to code tag
+ if (atts.get("code") == null && atts.get("classid") != null && !((String) atts.get("classid")).startsWith("clsid:")) {
+ atts.put("code", atts.get("classid"));
+ }
+
+ // remove java: from code tag
+ if (atts.get("code") != null && ((String) atts.get("code")).startsWith("java:")) {
+ atts.put("code", ((String) atts.get("code")).substring(5));
+ }
+
+ // java_* aliases override older names:
+ // http://java.sun.com/j2se/1.4.2/docs/guide/plugin/developer_guide/using_tags.html#in-ie
+ if (atts.get("java_code") != null) {
+ atts.put("code", ((String) atts.get("java_code")));
+ }
+
+ if (atts.containsKey("code")) {
+ objectTagAlreadyParsed = true;
+ }
+
+ if (atts.get("java_codebase") != null) {
+ atts.put("codebase", ((String) atts.get("java_codebase")));
+ }
+
+ if (atts.get("java_archive") != null) {
+ atts.put("archive", ((String) atts.get("java_archive")));
+ }
+
+ if (atts.get("java_object") != null) {
+ atts.put("object", ((String) atts.get("java_object")));
+ }
+
+ if (atts.get("java_type") != null) {
+ atts.put("type", ((String) atts.get("java_type")));
+ }
+
+ if (atts.get("width") == null || !isInt(atts.get("width"))) {
+ atts.put("width", width);
+ }
+
+ if (atts.get("height") == null || !isInt(atts.get("height"))) {
+ atts.put("height", height);
+ }
+ }
+ else if (nm.equalsIgnoreCase("embed")) {
+ isEmbedTag = true;
+ atts = scanTag(c, in);
+
+ // If there is a classid and no code tag present, transform it to code tag
+ if (atts.get("code") == null && atts.get("classid") != null && !((String) atts.get("classid")).startsWith("clsid:")) {
+ atts.put("code", atts.get("classid"));
+ }
+
+ // remove java: from code tag
+ if (atts.get("code") != null && ((String) atts.get("code")).startsWith("java:")) {
+ atts.put("code", ((String) atts.get("code")).substring(5));
+ }
+
+ // java_* aliases override older names:
+ // http://java.sun.com/j2se/1.4.2/docs/guide/plugin/developer_guide/using_tags.html#in-nav
+ if (atts.get("java_code") != null) {
+ atts.put("code", ((String) atts.get("java_code")));
+ }
+
+ if (atts.get("java_codebase") != null) {
+ atts.put("codebase", ((String) atts.get("java_codebase")));
+ }
+
+ if (atts.get("java_archive") != null) {
+ atts.put("archive", ((String) atts.get("java_archive")));
+ }
+
+ if (atts.get("java_object") != null) {
+ atts.put("object", ((String) atts.get("java_object")));
+ }
+
+ if (atts.get("java_type") != null) {
+ atts.put("type", ((String) atts.get("java_type")));
+ }
+
+ if (atts.get("code") == null && atts.get("object") == null) {
+ statusMsgStream.println(embedRequiresCodeWarning);
+ atts = null;
+ }
+
+ if (atts.get("width") == null || !isInt(atts.get("width"))) {
+ atts.put("width", width);
+ }
+
+ if (atts.get("height") == null || !isInt(atts.get("height"))) {
+ atts.put("height", height);
+ }
+ }
+ }
+ }
+ }
+ in.close();
+ }
+
+
+ private static AppletMessageHandler amh = new AppletMessageHandler("appletviewer");
+
+ private static void checkConnect(URL url)
+ {
+ SecurityManager security = System.getSecurityManager();
+ if (security != null) {
+ try {
+ java.security.Permission perm =
+ url.openConnection().getPermission();
+ if (perm != null)
+ security.checkPermission(perm);
+ else
+ security.checkConnect(url.getHost(), url.getPort());
+ } catch (java.io.IOException ioe) {
+ security.checkConnect(url.getHost(), url.getPort());
+ }
+ }
+ }
+ }
diff --git a/plugin/icedteanp/java/sun/applet/PluginCallRequest.java b/plugin/icedteanp/java/sun/applet/PluginCallRequest.java
new file mode 100644
index 0000000..a4f01a7
--- /dev/null
+++ b/plugin/icedteanp/java/sun/applet/PluginCallRequest.java
@@ -0,0 +1,89 @@
+/* PluginCallRequest -- represent Java-to-JavaScript requests
+ Copyright (C) 2008 Red Hat
+
+This file is part of IcedTea.
+
+IcedTea is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+IcedTea is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with IcedTea; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package sun.applet;
+
+import java.security.AccessControlContext;
+import java.security.ProtectionDomain;
+
+// FIXME: for each type of request extend a new (anonymous?)
+// PluginCallRequest.
+public abstract class PluginCallRequest {
+ String message;
+ Long reference;
+ PluginCallRequest next;
+ boolean done = false;
+
+ public PluginCallRequest(String message, Long reference) {
+ this.message = message;
+ this.reference = reference;
+ }
+
+ public String getMessage() {
+ return this.message;
+ }
+
+ public boolean isDone() {
+ return this.done;
+ }
+
+ public boolean setDone(boolean done) {
+ return this.done = done;
+ }
+
+ public void setNext(PluginCallRequest next) {
+ this.next = next;
+ }
+
+ public PluginCallRequest getNext() {
+ return this.next;
+ }
+
+ /**
+ * Returns whether the given message is serviceable by this object
+ *
+ * @param message The message to service
+ * @return boolean indicating if message is serviceable
+ */
+ public boolean serviceable(String message) {
+ return message.contains("reference " + reference);
+ }
+
+ public abstract void parseReturn(String message);
+
+ public abstract Object getObject();
+}
diff --git a/plugin/icedteanp/java/sun/applet/PluginCallRequestFactory.java b/plugin/icedteanp/java/sun/applet/PluginCallRequestFactory.java
new file mode 100644
index 0000000..69cec35
--- /dev/null
+++ b/plugin/icedteanp/java/sun/applet/PluginCallRequestFactory.java
@@ -0,0 +1,61 @@
+/* VoidPluginCallRequest -- represent Java-to-JavaScript requests
+ Copyright (C) 2008 Red Hat
+
+This file is part of IcedTea.
+
+IcedTea is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+IcedTea is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with IcedTea; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package sun.applet;
+
+
+public class PluginCallRequestFactory {
+
+ public PluginCallRequest getPluginCallRequest(String id, String message, Long reference) {
+
+ if (id == "member") {
+ return new GetMemberPluginCallRequest(message, reference);
+ } else if (id == "void") {
+ return new VoidPluginCallRequest(message, reference);
+ } else if (id == "window") {
+ return new GetWindowPluginCallRequest(message, reference);
+ } else if (id == "proxyinfo") {
+ return new PluginProxyInfoRequest(message, reference);
+ } else if (id == "cookieinfo") {
+ return new PluginCookieInfoRequest(message, reference);
+ } else {
+ throw new RuntimeException ("Unknown plugin call request type requested from factory");
+ }
+ }
+
+}
diff --git a/plugin/icedteanp/java/sun/applet/PluginClassLoader.java b/plugin/icedteanp/java/sun/applet/PluginClassLoader.java
new file mode 100644
index 0000000..5965d0d
--- /dev/null
+++ b/plugin/icedteanp/java/sun/applet/PluginClassLoader.java
@@ -0,0 +1,51 @@
+/* VoidPluginCallRequest -- represent Java-to-JavaScript requests
+ Copyright (C) 2008 Red Hat
+
+This file is part of IcedTea.
+
+IcedTea is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+IcedTea is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with IcedTea; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package sun.applet;
+
+public class PluginClassLoader extends ClassLoader {
+
+ public PluginClassLoader() {
+ super();
+ }
+
+ public Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
+ return super.loadClass(name, resolve);
+ }
+
+}
diff --git a/plugin/icedteanp/java/sun/applet/PluginCookieInfoRequest.java b/plugin/icedteanp/java/sun/applet/PluginCookieInfoRequest.java
new file mode 100644
index 0000000..c08d9f5
--- /dev/null
+++ b/plugin/icedteanp/java/sun/applet/PluginCookieInfoRequest.java
@@ -0,0 +1,74 @@
+/* PluginCookieInfoRequest -- Object representing a request for cookie information from the browser
+ Copyright (C) 2009 Red Hat
+
+This file is part of IcedTea.
+
+IcedTea is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+IcedTea is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with IcedTea; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package sun.applet;
+
+
+/**
+ * This class represents a request object for cookie information for a given URI
+ */
+
+public class PluginCookieInfoRequest extends PluginCallRequest {
+
+ String cookieString = new String();
+
+ public PluginCookieInfoRequest(String message, Long reference) {
+ super(message, reference);
+ }
+
+ public void parseReturn(String cookieInfo) {
+
+ // try to parse the proxy information. If things go wrong, do nothing ..
+ // this will keep internal = null which forces a direct connection
+
+ PluginDebug.debug ("PluginCookieInfoRequest GOT: " + cookieInfo);
+
+ // Skip the first 5 components. We are guaranteed 5 components,
+ // so no index -1 to worry about
+ cookieInfo = cookieInfo.substring(cookieInfo.indexOf(' ')+1);
+ cookieInfo = cookieInfo.substring(cookieInfo.indexOf(' ')+1);
+ cookieInfo = cookieInfo.substring(cookieInfo.indexOf(' ')+1);
+ cookieInfo = cookieInfo.substring(cookieInfo.indexOf(' ')+1);
+ cookieString = cookieInfo.substring(cookieInfo.indexOf(' ')+1);
+
+ setDone(true);
+ }
+
+ public String getObject() {
+ return this.cookieString;
+ }
+}
diff --git a/plugin/icedteanp/java/sun/applet/PluginCookieManager.java b/plugin/icedteanp/java/sun/applet/PluginCookieManager.java
new file mode 100644
index 0000000..233cfa9
--- /dev/null
+++ b/plugin/icedteanp/java/sun/applet/PluginCookieManager.java
@@ -0,0 +1,88 @@
+/* PluginCookieManager -- Cookie manager for the plugin
+ Copyright (C) 2009 Red Hat
+
+This file is part of IcedTea.
+
+IcedTea is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+IcedTea is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with IcedTea; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package sun.applet;
+
+import java.io.IOException;
+import java.net.CookieManager;
+import java.net.HttpCookie;
+import java.net.URI;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+public class PluginCookieManager extends CookieManager
+{
+ public Map<String, List<String>> get(URI uri,
+ Map<String, List<String>> requestHeaders) throws IOException {
+ // pre-condition check
+ if (uri == null || requestHeaders == null) {
+ throw new IllegalArgumentException("Argument is null");
+ }
+
+ Map<String, List<String>> cookieMap = new java.util.HashMap<String, List<String>>();
+
+ String cookies = (String) PluginAppletViewer
+ .requestPluginCookieInfo(uri);
+ List<String> cookieHeader = new java.util.ArrayList<String>();
+
+ if (cookies != null && cookies.length() > 0)
+ cookieHeader.add(cookies);
+
+ // Add anything else that mozilla didn't add
+ for (HttpCookie cookie : getCookieStore().get(uri)) {
+ // apply path-matches rule (RFC 2965 sec. 3.3.4)
+ if (pathMatches(uri.getPath(), cookie.getPath())) {
+ cookieHeader.add(cookie.toString());
+ }
+ }
+
+ cookieMap.put("Cookie", cookieHeader);
+ return Collections.unmodifiableMap(cookieMap);
+ }
+
+ private boolean pathMatches(String path, String pathToMatchWith) {
+ if (path == pathToMatchWith)
+ return true;
+ if (path == null || pathToMatchWith == null)
+ return false;
+ if (path.startsWith(pathToMatchWith))
+ return true;
+
+ return false;
+ }
+}
diff --git a/plugin/icedteanp/java/sun/applet/PluginDebug.java b/plugin/icedteanp/java/sun/applet/PluginDebug.java
new file mode 100644
index 0000000..60e2bd0
--- /dev/null
+++ b/plugin/icedteanp/java/sun/applet/PluginDebug.java
@@ -0,0 +1,51 @@
+/* VoidPluginCallRequest -- represent Java-to-JavaScript requests
+ Copyright (C) 2008 Red Hat
+
+This file is part of IcedTea.
+
+IcedTea is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+IcedTea is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with IcedTea; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package sun.applet;
+
+import java.io.*;
+
+public class PluginDebug {
+
+ static final boolean DEBUG = System.getenv().containsKey("ICEDTEAPLUGIN_DEBUG");
+
+ public static void debug(String message) {
+ if (DEBUG)
+ System.err.println(message);
+ }
+}
diff --git a/plugin/icedteanp/java/sun/applet/PluginException.java b/plugin/icedteanp/java/sun/applet/PluginException.java
new file mode 100644
index 0000000..0f6e660
--- /dev/null
+++ b/plugin/icedteanp/java/sun/applet/PluginException.java
@@ -0,0 +1,53 @@
+/* VoidPluginCallRequest -- represent Java-to-JavaScript requests
+ Copyright (C) 2008 Red Hat
+
+This file is part of IcedTea.
+
+IcedTea is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+IcedTea is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with IcedTea; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package sun.applet;
+
+
+public class PluginException extends Exception {
+
+ public PluginException (PluginStreamHandler sh, int instance, int reference, Throwable t) {
+ t.printStackTrace();
+ this.setStackTrace(t.getStackTrace());
+
+ AppletSecurityContextManager.dumpStore(0);
+
+ String message = "instance " + instance + " reference " + reference + " Error " + t.getMessage();
+ sh.write(message);
+ }
+}
diff --git a/plugin/icedteanp/java/sun/applet/PluginMain.java b/plugin/icedteanp/java/sun/applet/PluginMain.java
new file mode 100644
index 0000000..bce87b2
--- /dev/null
+++ b/plugin/icedteanp/java/sun/applet/PluginMain.java
@@ -0,0 +1,319 @@
+/* VoidPluginCallRequest -- represent Java-to-JavaScript requests
+ Copyright (C) 2008 Red Hat
+
+This file is part of IcedTea.
+
+IcedTea is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+IcedTea is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with IcedTea; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+/*
+ * Copyright 1999-2006 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.applet;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.net.Authenticator;
+import java.net.CookieHandler;
+import java.net.CookieManager;
+import java.net.PasswordAuthentication;
+import java.net.ProxySelector;
+import java.util.Enumeration;
+import java.util.Properties;
+
+import javax.net.ssl.HttpsURLConnection;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLSocketFactory;
+import javax.net.ssl.TrustManager;
+
+import net.sourceforge.jnlp.security.VariableX509TrustManager;
+
+/**
+ * The main entry point into PluginAppletViewer.
+ */
+public class PluginMain
+{
+
+ // the files where stdout/stderr are sent to
+ public static final String PLUGIN_STDERR_FILE = System.getProperty("user.home") + "/.icedteaplugin/java.stderr";
+ public static final String PLUGIN_STDOUT_FILE = System.getProperty("user.home") + "/.icedteaplugin/java.stdout";
+
+ final boolean redirectStreams = System.getenv().containsKey("ICEDTEAPLUGIN_DEBUG");
+ static PluginStreamHandler streamHandler;
+
+ // This is used in init(). Getting rid of this is desirable but depends
+ // on whether the property that uses it is necessary/standard.
+ public static final String theVersion = System.getProperty("java.version");
+
+ private PluginAppletSecurityContext securityContext;
+
+ /**
+ * The main entry point into AppletViewer.
+ */
+ public static void main(String args[])
+ throws IOException
+ {
+ if (args.length != 2 || !(new File(args[0]).exists()) || !(new File(args[1]).exists())) {
+ System.err.println("Invalid pipe names provided. Refusing to proceed.");
+ System.exit(1);
+ }
+
+ try {
+ PluginMain pm = new PluginMain(args[0], args[1]);
+ } catch (Exception e) {
+ e.printStackTrace();
+ System.err.println("Something very bad happened. I don't know what to do, so I am going to exit :(");
+ System.exit(1);
+ }
+ }
+
+ public PluginMain(String inPipe, String outPipe) {
+
+ try {
+ File errFile = new File(PLUGIN_STDERR_FILE);
+ File outFile = new File(PLUGIN_STDOUT_FILE);
+
+ System.setErr(new TeeOutputStream(new FileOutputStream(errFile), System.err));
+ System.setOut(new TeeOutputStream(new FileOutputStream(outFile), System.out));
+ } catch (Exception e) {
+ PluginDebug.debug("Unable to redirect streams");
+ e.printStackTrace();
+ }
+
+ connect(inPipe, outPipe);
+
+ securityContext = new PluginAppletSecurityContext(0);
+ securityContext.prePopulateLCClasses();
+ securityContext.setStreamhandler(streamHandler);
+ AppletSecurityContextManager.addContext(0, securityContext);
+
+ PluginAppletViewer.setStreamhandler(streamHandler);
+ PluginAppletViewer.setPluginCallRequestFactory(new PluginCallRequestFactory());
+
+ init();
+
+ // Streams set. Start processing.
+ streamHandler.startProcessing();
+ }
+
+ public void connect(String inPipe, String outPipe) {
+ try {
+ streamHandler = new PluginStreamHandler(new FileInputStream(inPipe), new FileOutputStream(outPipe));
+ PluginDebug.debug("Streams initialized");
+ } catch (IOException ioe) {
+ ioe.printStackTrace();
+ }
+ }
+
+ private static void init() {
+ Properties avProps = new Properties();
+
+ // ADD OTHER RANDOM PROPERTIES
+ // XXX 5/18 need to revisit why these are here, is there some
+ // standard for what is available?
+
+ // Standard browser properties
+ avProps.put("browser", "sun.applet.AppletViewer");
+ avProps.put("browser.version", "1.06");
+ avProps.put("browser.vendor", "Sun Microsystems Inc.");
+ avProps.put("http.agent", "Java(tm) 2 SDK, Standard Edition v" + theVersion);
+
+ // Define which packages can be extended by applets
+ // XXX 5/19 probably not needed, not checked in AppletSecurity
+ avProps.put("package.restrict.definition.java", "true");
+ avProps.put("package.restrict.definition.sun", "true");
+
+ // Define which properties can be read by applets.
+ // A property named by "key" can be read only when its twin
+ // property "key.applet" is true. The following ten properties
+ // are open by default. Any other property can be explicitly
+ // opened up by the browser user by calling appletviewer with
+ // -J-Dkey.applet=true
+ avProps.put("java.version.applet", "true");
+ avProps.put("java.vendor.applet", "true");
+ avProps.put("java.vendor.url.applet", "true");
+ avProps.put("java.class.version.applet", "true");
+ avProps.put("os.name.applet", "true");
+ avProps.put("os.version.applet", "true");
+ avProps.put("os.arch.applet", "true");
+ avProps.put("file.separator.applet", "true");
+ avProps.put("path.separator.applet", "true");
+ avProps.put("line.separator.applet", "true");
+
+ avProps.put("javaplugin.nodotversion", "160_17");
+ avProps.put("javaplugin.version", "1.6.0_17");
+ avProps.put("javaplugin.vm.options", "");
+
+ // Read in the System properties. If something is going to be
+ // over-written, warn about it.
+ Properties sysProps = System.getProperties();
+ for (Enumeration e = sysProps.propertyNames(); e.hasMoreElements(); ) {
+ String key = (String) e.nextElement();
+ String val = (String) sysProps.getProperty(key);
+ avProps.setProperty(key, val);
+ }
+
+ // INSTALL THE PROPERTY LIST
+ System.setProperties(avProps);
+
+
+ try {
+ SSLSocketFactory sslSocketFactory;
+ SSLContext context = SSLContext.getInstance("SSL");
+ TrustManager[] trust = new TrustManager[] { VariableX509TrustManager.getInstance() };
+ context.init(null, trust, null);
+ sslSocketFactory = context.getSocketFactory();
+
+ HttpsURLConnection.setDefaultSSLSocketFactory(sslSocketFactory);
+ } catch (Exception e) {
+ System.err.println("Unable to set SSLSocketfactory (may _prevent_ access to sites that should be trusted)! Continuing anyway...");
+ e.printStackTrace();
+ }
+
+ // plug in a custom authenticator and proxy selector
+ Authenticator.setDefault(new CustomAuthenticator());
+ ProxySelector.setDefault(new PluginProxySelector());
+
+ CookieManager ckManager = new PluginCookieManager();
+ CookieHandler.setDefault(ckManager);
+ }
+
+ static boolean messageAvailable() {
+ return streamHandler.messageAvailable();
+ }
+
+ static String getMessage() {
+ return streamHandler.getMessage();
+ }
+
+ static class CustomAuthenticator extends Authenticator {
+
+ public PasswordAuthentication getPasswordAuthentication() {
+
+ // No security check is required here, because the only way to
+ // set parameters for which auth info is needed
+ // (Authenticator:requestPasswordAuthentication()), has a security
+ // check
+
+ String type = this.getRequestorType() == RequestorType.PROXY ? "proxy" : "web";
+
+ // request auth info from user
+ PasswordAuthenticationDialog pwDialog = new PasswordAuthenticationDialog();
+ PasswordAuthentication auth = pwDialog.askUser(this.getRequestingHost(), this.getRequestingPort(), this.getRequestingPrompt(), type);
+
+ // send it along
+ return auth;
+ }
+ }
+
+ /**
+ * Behaves like the 'tee' command, sends output to both actual std stream and a
+ * file
+ */
+ class TeeOutputStream extends PrintStream {
+
+ // Everthing written to TeeOutputStream is written to this file
+ PrintStream logFile;
+
+ public TeeOutputStream(FileOutputStream fileOutputStream,
+ PrintStream stdStream) {
+ super(stdStream);
+ logFile = new PrintStream(fileOutputStream);
+ }
+
+ @Override
+ public boolean checkError() {
+ boolean thisError = super.checkError();
+ boolean fileError = logFile.checkError();
+
+ return thisError || fileError;
+ }
+
+ @Override
+ public void close() {
+ logFile.close();
+ super.close();
+ }
+
+ @Override
+ public void flush() {
+ logFile.flush();
+ super.flush();
+ }
+
+ /*
+ * The big ones: these do the actual writing
+ */
+
+ @Override
+ public void write(byte[] buf, int off, int len) {
+ logFile.write(buf, off, len);
+
+ if (!redirectStreams)
+ super.write(buf, off, len);
+ }
+
+ @Override
+ public void write(int b) {
+ logFile.write(b);
+
+ if (!redirectStreams)
+ super.write(b);
+ }
+ }
+
+}
diff --git a/plugin/icedteanp/java/sun/applet/PluginMessageConsumer.java b/plugin/icedteanp/java/sun/applet/PluginMessageConsumer.java
new file mode 100644
index 0000000..0bc5dda
--- /dev/null
+++ b/plugin/icedteanp/java/sun/applet/PluginMessageConsumer.java
@@ -0,0 +1,268 @@
+/* VoidPluginCallRequest -- represent Java-to-JavaScript requests
+ Copyright (C) 2008 Red Hat
+
+This file is part of IcedTea.
+
+IcedTea is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+IcedTea is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with IcedTea; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package sun.applet;
+
+import java.util.ArrayList;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.Set;
+
+class PluginMessageConsumer {
+
+ private static int MAX_PARALLEL_INITS = 1;
+
+ // Each initialization requires 5 responses (tag, handle, width, proxy, cookie)
+ // before the message stack unlocks/collapses. This works out well because we
+ // want to allow upto 5 parallel tasks anyway
+ private static int MAX_WORKERS = MAX_PARALLEL_INITS*4;
+ private static int PRIORITY_WORKERS = MAX_PARALLEL_INITS*2;
+
+ private static Hashtable<Integer, PluginMessageHandlerWorker> initWorkers = new Hashtable<Integer, PluginMessageHandlerWorker>(2);
+
+ LinkedList<String> readQueue = new LinkedList<String>();
+ private static LinkedList<String> priorityWaitQueue = new LinkedList<String>();
+ ArrayList<PluginMessageHandlerWorker> workers = new ArrayList<PluginMessageHandlerWorker>();
+ PluginStreamHandler streamHandler = null;
+ AppletSecurity as;
+ ConsumerThread consumerThread = new ConsumerThread();
+ private static ArrayList<Integer> processedIds = new ArrayList<Integer>();
+
+ /**
+ * Registers a reference to wait for. Responses to registered priority
+ * references get handled by priority worker if normal workers are busy.
+ *
+ * @param reference The reference to give priority to
+ */
+ public static void registerPriorityWait(Long reference) {
+ PluginDebug.debug("Registering priority for reference " + reference);
+ registerPriorityWait("reference " + reference.toString());
+ }
+
+ /**
+ * Registers a string to wait for.
+ *
+ * @param searchString the string to look for in a response
+ */
+ public static void registerPriorityWait(String searchString) {
+ PluginDebug.debug("Registering priority for string " + searchString);
+ synchronized (priorityWaitQueue) {
+ if (!priorityWaitQueue.contains(searchString))
+ priorityWaitQueue.add(searchString);
+ }
+ }
+
+ /**
+ * Unregisters a priority reference to wait for.
+ *
+ * @param reference The reference to remove
+ */
+ public static void unRegisterPriorityWait(Long reference) {
+ unRegisterPriorityWait(reference.toString());
+ }
+
+ /**
+ * Unregisters a priority string to wait for.
+ *
+ * @param searchString The string to unregister from the priority list
+ */
+ public static void unRegisterPriorityWait(String searchString) {
+ synchronized (priorityWaitQueue) {
+ priorityWaitQueue.remove(searchString);
+ }
+ }
+
+ /**
+ * Returns the reference for this message. This method assumes that
+ * the message has a reference number.
+ *
+ * @param The message
+ * @return the reference number
+ */
+ private Long getReference(String[] msgParts) {
+ return Long.parseLong(msgParts[3]);
+ }
+
+ public PluginMessageConsumer(PluginStreamHandler streamHandler) {
+
+ as = new AppletSecurity();
+ this.streamHandler = streamHandler;
+ this.consumerThread.start();
+ }
+
+ private String getPriorityStrIfPriority(String message) {
+
+ synchronized (priorityWaitQueue) {
+ Iterator<String> it = priorityWaitQueue.iterator();
+
+ while (it.hasNext()) {
+ String priorityStr = it.next();
+ if (message.indexOf(priorityStr) > 0)
+ return priorityStr;
+ }
+ }
+
+ return null;
+ }
+
+ private boolean isInInit(Integer instanceNum) {
+ return initWorkers.containsKey(instanceNum);
+ }
+
+ private void addToInitWorkers(Integer instanceNum, PluginMessageHandlerWorker worker) {
+ synchronized(initWorkers) {
+ initWorkers.put(instanceNum, worker);
+ }
+ }
+
+
+ public void notifyWorkerIsFree(PluginMessageHandlerWorker worker) {
+ synchronized (initWorkers) {
+ Iterator<Integer> i = initWorkers.keySet().iterator();
+ while (i.hasNext()) {
+ Integer key = i.next();
+ if (initWorkers.get(key).equals(worker)) {
+ processedIds.add(key);
+ initWorkers.remove(key);
+ }
+ }
+ }
+
+ consumerThread.interrupt();
+ }
+
+ public void queue(String message) {
+ synchronized(readQueue) {
+ readQueue.addLast(message);
+ }
+
+ // Wake that lazy consumer thread
+ consumerThread.interrupt();
+ }
+
+ protected class ConsumerThread extends Thread {
+ public void run() {
+
+ while (true) {
+
+ String message = null;
+
+ synchronized(readQueue) {
+ message = readQueue.poll();
+ }
+
+ if (message != null) {
+
+ String[] msgParts = message.split(" ");
+
+
+ String priorityStr = getPriorityStrIfPriority(message);
+ boolean isPriorityResponse = (priorityStr != null);
+
+ //PluginDebug.debug("Message " + message + " (priority=" + isPriorityResponse + ") ready to be processed. Looking for free worker...");
+ final PluginMessageHandlerWorker worker = getFreeWorker(isPriorityResponse);
+
+ if (worker == null) {
+ synchronized(readQueue) {
+ readQueue.addLast(message);
+ }
+
+ continue; // re-loop to try next msg
+ }
+
+ if (msgParts[2].equals("tag"))
+ addToInitWorkers((new Integer(msgParts[1])), worker);
+
+ if (isPriorityResponse) {
+ unRegisterPriorityWait(priorityStr);
+ }
+
+ worker.setmessage(message);
+ worker.interrupt();
+
+ } else {
+ try {
+ Thread.sleep(1000);
+ } catch (InterruptedException ie) {}
+ }
+ }
+ }
+ }
+
+ private PluginMessageHandlerWorker getFreeWorker(boolean prioritized) {
+
+ for (PluginMessageHandlerWorker worker: workers) {
+ if (worker.isFree(prioritized)) {
+ PluginDebug.debug("Found free worker (" + worker.isPriority() + ") with id " + worker.getWorkerId());
+ // mark it busy before returning
+ worker.busy();
+ return worker;
+ }
+ }
+
+ // If we have less than MAX_WORKERS, create a new worker
+ if (workers.size() <= MAX_WORKERS) {
+ PluginMessageHandlerWorker worker = null;
+
+ if (workers.size() < (MAX_WORKERS - PRIORITY_WORKERS)) {
+ PluginDebug.debug("Cannot find free worker, creating worker " + workers.size());
+ worker = new PluginMessageHandlerWorker(this, streamHandler, workers.size(), as, false);
+ } else if (prioritized) {
+ PluginDebug.debug("Cannot find free worker, creating priority worker " + workers.size());
+ worker = new PluginMessageHandlerWorker(this, streamHandler, workers.size(), as, true);
+ } else {
+ return null;
+ }
+
+ worker.start();
+ worker.busy();
+ workers.add(worker);
+ return worker;
+
+ }
+
+ // No workers available. Better luck next time!
+ return null;
+ }
+
+ private void dumpWorkerStatus() {
+ for (PluginMessageHandlerWorker worker: workers) {
+ PluginDebug.debug(worker.toString());
+ }
+ }
+}
diff --git a/plugin/icedteanp/java/sun/applet/PluginMessageHandlerWorker.java b/plugin/icedteanp/java/sun/applet/PluginMessageHandlerWorker.java
new file mode 100644
index 0000000..30714c4
--- /dev/null
+++ b/plugin/icedteanp/java/sun/applet/PluginMessageHandlerWorker.java
@@ -0,0 +1,147 @@
+/* VoidPluginCallRequest -- represent Java-to-JavaScript requests
+ Copyright (C) 2008 Red Hat
+
+This file is part of IcedTea.
+
+IcedTea is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+IcedTea is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with IcedTea; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package sun.applet;
+
+
+class PluginMessageHandlerWorker extends Thread {
+
+ private boolean free = true;
+ private boolean isPriorityWorker = false;
+ private int id;
+ private String message = null;
+ private SecurityManager sm;
+ PluginStreamHandler streamHandler = null;
+ PluginMessageConsumer consumer = null;
+
+ public PluginMessageHandlerWorker(
+ PluginMessageConsumer consumer,
+ PluginStreamHandler streamHandler, int id,
+ SecurityManager sm, boolean isPriorityWorker) {
+
+ this.id = id;
+ this.streamHandler = streamHandler;
+ this.sm = sm;
+ this.isPriorityWorker = isPriorityWorker;
+ this.consumer = consumer;
+
+ PluginDebug.debug("Worker " + this.id + " (priority=" + isPriorityWorker + ") created.");
+ }
+
+ public void setmessage(String message) {
+ this.message = message;
+ }
+
+ public void run() {
+ while (true) {
+
+ if (message != null) {
+
+ PluginDebug.debug("Consumer (priority=" + isPriorityWorker + ") thread " + id + " consuming " + message);
+
+ // ideally, whoever returns things object should mark it
+ // busy first, but just in case..
+ busy();
+
+ try {
+ streamHandler.handleMessage(message);
+ } catch (PluginException pe) {
+ /*
+ catch the exception and DO NOTHING. The plugin should take over after
+ this error and let the user know. We don't quit because otherwise the
+ exception will spread to the rest of the applets which is a no-no
+ */
+ }
+
+ this.message = null;
+
+ PluginDebug.debug("Consumption (priority=" + isPriorityWorker + ") completed by consumer thread " + id);
+
+ // mark ourselves free again
+ free();
+
+ } else {
+
+ // Sleep when there is nothing to do
+ try {
+ Thread.sleep(Integer.MAX_VALUE);
+ PluginDebug.debug("Consumer thread " + id + " sleeping...");
+ } catch (InterruptedException ie) {
+ PluginDebug.debug("Consumer thread " + id + " woken...");
+ // nothing.. someone woke us up, see if there
+ // is work to do
+ }
+ }
+ }
+ }
+
+
+
+ public int getWorkerId() {
+ return id;
+ }
+
+ public void busy() {
+ synchronized (this) {
+ this.free = false;
+ }
+ }
+
+ public void free() {
+ synchronized (this) {
+ this.free = true;
+
+ // Signal the consumer that we are done in case it was waiting
+ consumer.notifyWorkerIsFree(this);
+ }
+ }
+
+ public boolean isPriority() {
+ return isPriorityWorker;
+ }
+
+ public boolean isFree(boolean prioritized) {
+ synchronized (this) {
+ return free && (prioritized == isPriorityWorker);
+ }
+ }
+
+ public String toString() {
+ return "Worker #" + this.id + "/IsPriority=" + this.isPriorityWorker + "/IsFree=" + this.free + "/Message=" + message;
+ }
+}
diff --git a/plugin/icedteanp/java/sun/applet/PluginObjectStore.java b/plugin/icedteanp/java/sun/applet/PluginObjectStore.java
new file mode 100644
index 0000000..b744744
--- /dev/null
+++ b/plugin/icedteanp/java/sun/applet/PluginObjectStore.java
@@ -0,0 +1,132 @@
+/* PluginObjectStore -- manage identifier-to-object mapping
+ Copyright (C) 2008 Red Hat
+
+This file is part of IcedTea.
+
+IcedTea is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+IcedTea is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with IcedTea; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package sun.applet;
+
+import java.util.*;
+import java.lang.reflect.*;
+import java.io.*;
+
+public class PluginObjectStore
+{
+ private static HashMap<Integer, Object> objects = new HashMap();
+ private static HashMap<Integer, Integer> counts = new HashMap();
+ private static HashMap<Object, Integer> identifiers = new HashMap();
+ // FIXME:
+ //
+ // IF uniqueID == MAX_LONG, uniqueID =
+ // 0 && wrapped = true
+ //
+ // if (wrapped), check if
+ // objects.get(uniqueID) returns null
+ //
+ // if yes, use uniqueID, if no,
+ // uniqueID++ and keep checking
+ // or:
+ // stack of available ids:
+ // derefed id -> derefed id -> nextUniqueIdentifier
+ private static int nextUniqueIdentifier = 1;
+
+ public Object getObject(Integer identifier) {
+ return objects.get(identifier);
+ }
+
+ public Integer getIdentifier(Object object) {
+ if (object == null)
+ return 0;
+ return identifiers.get(object);
+ }
+
+ public boolean contains(Object object) {
+ if (object == null)
+ return identifiers.containsKey(object);
+
+ return false;
+ }
+
+ public boolean contains(int identifier) {
+ return objects.containsKey(identifier);
+ }
+
+ public void reference(Object object) {
+ Integer identifier = identifiers.get(object);
+ if (identifier == null) {
+ objects.put(nextUniqueIdentifier, object);
+ counts.put(nextUniqueIdentifier, 1);
+ identifiers.put(object, nextUniqueIdentifier);
+ //System.out.println("JAVA ADDED: " + nextUniqueIdentifier);
+ //System.out.println("JAVA REFERENCED: " + nextUniqueIdentifier
+ // + " to: 1");
+ nextUniqueIdentifier++;
+ } else {
+ counts.put(identifier, counts.get(identifier) + 1);
+ //System.out.println("JAVA REFERENCED: " + identifier +
+ // " to: " + counts.get(identifier));
+ }
+ }
+
+ public void unreference(int identifier) {
+ Integer currentCount = counts.get(identifier);
+ if (currentCount == null) {
+ //System.out.println("ERROR UNREFERENCING: " + identifier);
+ return;
+ }
+ if (currentCount == 1) {
+ //System.out.println("JAVA DEREFERENCED: " + identifier
+ // + " to: 0");
+ Object object = objects.get(identifier);
+ objects.remove(identifier);
+ counts.remove(identifier);
+ identifiers.remove(object);
+ //System.out.println("JAVA REMOVED: " + identifier);
+ } else {
+ counts.put(identifier, currentCount - 1);
+ //System.out.println("JAVA DEREFERENCED: " +
+ // identifier + " to: " +
+ // counts.get(identifier));
+ }
+ }
+
+ public void dump() {
+ Iterator i = objects.keySet().iterator();
+ while (i.hasNext()) {
+ Object key = i.next();
+ PluginDebug.debug(key + "::" + objects.get(key));
+ }
+ }
+}
+
diff --git a/plugin/icedteanp/java/sun/applet/PluginProxyInfoRequest.java b/plugin/icedteanp/java/sun/applet/PluginProxyInfoRequest.java
new file mode 100644
index 0000000..674f11d
--- /dev/null
+++ b/plugin/icedteanp/java/sun/applet/PluginProxyInfoRequest.java
@@ -0,0 +1,81 @@
+/* PluginProxyInfoRequest -- Object representing a request for proxy information from the browser
+ Copyright (C) 2009 Red Hat
+
+This file is part of IcedTea.
+
+IcedTea is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+IcedTea is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with IcedTea; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package sun.applet;
+
+import java.net.MalformedURLException;
+import java.net.URI;
+
+/**
+ * This class represents a request object for proxy information for a given URI
+ */
+
+public class PluginProxyInfoRequest extends PluginCallRequest {
+
+ URI internal = null;
+
+ public PluginProxyInfoRequest(String message, Long reference) {
+ super(message, reference);
+ }
+
+ public void parseReturn(String proxyInfo) {
+
+ // try to parse the proxy information. If things go wrong, do nothing ..
+ // this will keep internal = null which forces a direct connection
+
+ PluginDebug.debug ("PluginProxyInfoRequest GOT: " + proxyInfo);
+ String[] messageComponents = proxyInfo.split(" ");
+
+ try {
+ String protocol = messageComponents[4].equals("PROXY") ? "http" : "socks";
+ String host = messageComponents[5].split(":")[0];
+ int port = Integer.parseInt(messageComponents[5].split(":")[1]);
+
+ internal = new URI(protocol, null, host, port, null, null, null);
+ } catch (ArrayIndexOutOfBoundsException aioobe) {
+ // Nothing.. this is expected if there is no proxy
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ setDone(true);
+ }
+
+ public URI getObject() {
+ return this.internal;
+ }
+}
diff --git a/plugin/icedteanp/java/sun/applet/PluginProxySelector.java b/plugin/icedteanp/java/sun/applet/PluginProxySelector.java
new file mode 100644
index 0000000..dff8ded
--- /dev/null
+++ b/plugin/icedteanp/java/sun/applet/PluginProxySelector.java
@@ -0,0 +1,195 @@
+/* PluginProxySelector -- proxy selector for all connections from applets and the plugin
+ Copyright (C) 2009 Red Hat
+
+This file is part of IcedTea.
+
+IcedTea is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+IcedTea is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with IcedTea; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package sun.applet;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.Proxy;
+import java.net.ProxySelector;
+import java.net.SocketAddress;
+import java.net.URI;
+import java.util.Date;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+/**
+ * Proxy selector implementation for plugin network functions.
+ *
+ * This class fetches proxy information from the web browser and
+ * uses that information in the context of all network connection
+ * (plugin specific and applet connections) as applicable
+ *
+ */
+
+public class PluginProxySelector extends ProxySelector {
+
+ private TimedHashMap<String, Proxy> proxyCache = new TimedHashMap<String, Proxy>();
+
+
+ @Override
+ public void connectFailed(URI uri, SocketAddress sa, IOException ioe) {
+ // If the connection fails, there is little we can do here. Just print the exception
+ ioe.printStackTrace();
+ }
+
+ /**
+ * Selects the appropriate proxy (or DIRECT connection method) for the given URI
+ *
+ * @param uri The URI being accessed
+ * @return A list of Proxy objects that are usable for this URI
+ */
+ @Override
+ public List<Proxy> select(URI uri) {
+
+ List<Proxy> proxyList = new ArrayList<Proxy>();
+
+ // check cache first
+ Proxy cachedProxy = checkCache(uri);
+ if (cachedProxy != null) {
+ proxyList.add(cachedProxy);
+ return proxyList;
+ }
+
+ // Nothing usable in cache. Fetch info from browser
+ Proxy proxy = Proxy.NO_PROXY;
+ Object o = PluginAppletViewer.requestPluginProxyInfo(uri);
+
+ // If the browser returned anything, try to parse it. If anything in the try block fails, the fallback is direct connection
+ try {
+ if (o != null) {
+ PluginDebug.debug("Proxy URI = " + o);
+ URI proxyURI = (URI) o;
+
+ // If origin uri is http/ftp, we're good. If origin uri is not that, the proxy _must_ be socks, else we fallback to direct
+ if (uri.getScheme().startsWith("http") || uri.getScheme().equals("ftp") || proxyURI.getScheme().startsWith("socks")) {
+
+ Proxy.Type type = proxyURI.getScheme().equals("http") ? Proxy.Type.HTTP : Proxy.Type.SOCKS;
+ InetSocketAddress socketAddr = new InetSocketAddress(proxyURI.getHost(), proxyURI.getPort());
+
+ proxy = new Proxy(type, socketAddr);
+
+ String uriKey = uri.getScheme() + "://" + uri.getHost();
+ proxyCache.put(uriKey, proxy);
+ } else {
+ PluginDebug.debug("Proxy " + proxyURI + " cannot be used for " + uri + ". Falling back to DIRECT");
+ }
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ proxyList.add(proxy);
+
+ PluginDebug.debug("Proxy for " + uri.toString() + " is " + proxy);
+
+ return proxyList;
+ }
+
+ /**
+ * Checks to see if proxy information is already cached.
+ *
+ * @param uri The URI to check
+ * @return The cached Proxy. null if there is no suitable cached proxy.
+ */
+ private Proxy checkCache(URI uri) {
+
+ String uriKey = uri.getScheme() + "://" + uri.getHost();
+ if (proxyCache.get(uriKey) != null) {
+ return proxyCache.get(uriKey);
+ }
+
+ return null;
+ }
+
+ /**
+ * Simple utility class that extends HashMap by adding an expiry to the entries.
+ *
+ * This map stores entries, and returns them only if the entries were last accessed within time t=10 seconds
+ *
+ * @param <K> The key type
+ * @param <V> The Object type
+ */
+
+ private class TimedHashMap<K,V> extends HashMap<K,V> {
+
+ HashMap<K, Long> timeStamps = new HashMap<K, Long>();
+ Long expiry = 10000L;
+
+ /**
+ * Store the item in the map and associate a timestamp with it
+ *
+ * @param key The key
+ * @param value The value to store
+ */
+ public V put(K key, V value) {
+ timeStamps.put(key, new Date().getTime());
+ return super.put(key, value);
+ }
+
+ /**
+ * Return cached item if it has not already expired.
+ *
+ * Before returning, this method also resets the "last accessed"
+ * time for this entry, so it is good for another 10 seconds
+ *
+ * @param key The key
+ */
+ public V get(Object key) {
+
+ Long now = new Date().getTime();
+
+ if (super.containsKey(key)) {
+ Long age = now - timeStamps.get(key);
+
+ // Item exists. If it has not expired, renew its access time and return it
+ if (age <= expiry) {
+ PluginDebug.debug("Returning proxy " + super.get(key) + " from cache for " + key);
+ timeStamps.put((K) key, (new Date()).getTime());
+ return super.get(key);
+ } else {
+ PluginDebug.debug("Proxy cache for " + key + " has expired (age=" + age/1000.0 + " seconds)");
+ }
+ }
+
+ return null;
+ }
+ }
+
+}
diff --git a/plugin/icedteanp/java/sun/applet/PluginStreamHandler.java b/plugin/icedteanp/java/sun/applet/PluginStreamHandler.java
new file mode 100644
index 0000000..eb5b11a
--- /dev/null
+++ b/plugin/icedteanp/java/sun/applet/PluginStreamHandler.java
@@ -0,0 +1,454 @@
+/* VoidPluginCallRequest -- represent Java-to-JavaScript requests
+ Copyright (C) 2008 Red Hat
+
+This file is part of IcedTea.
+
+IcedTea is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+IcedTea is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with IcedTea; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package sun.applet;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.StreamTokenizer;
+import java.net.MalformedURLException;
+import java.nio.charset.Charset;
+import java.util.Date;
+import java.util.LinkedList;
+
+import javax.swing.SwingUtilities;
+
+
+public class PluginStreamHandler {
+
+ private BufferedReader pluginInputReader;
+ private StreamTokenizer pluginInputTokenizer;
+ private BufferedWriter pluginOutputWriter;
+
+ private RequestQueue queue = new RequestQueue();
+
+ private JavaConsole console = new JavaConsole();
+
+ LinkedList<String> writeQueue = new LinkedList<String>();
+
+ PluginMessageConsumer consumer;
+ Boolean shuttingDown = false;
+
+ PluginAppletViewer pav;
+
+ static Date d = new Date();
+ static long startTime = d.getTime();
+ static long totalWait = 0;
+
+ public PluginStreamHandler(InputStream inputstream, OutputStream outputstream)
+ throws MalformedURLException, IOException
+ {
+
+ PluginDebug.debug("Current context CL=" + Thread.currentThread().getContextClassLoader());
+ try {
+ pav = (PluginAppletViewer) ClassLoader.getSystemClassLoader().loadClass("sun.applet.PluginAppletViewer").newInstance();
+ PluginDebug.debug("Loaded: " + pav + " CL=" + pav.getClass().getClassLoader());
+ } catch (InstantiationException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ } catch (IllegalAccessException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ } catch (ClassNotFoundException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+
+ PluginDebug.debug("Creating consumer...");
+ consumer = new PluginMessageConsumer(this);
+
+ // Set up input and output pipes. Use UTF-8 encoding.
+ pluginInputReader =
+ new BufferedReader(new InputStreamReader(inputstream,
+ Charset.forName("UTF-8")));
+ /*pluginInputTokenizer = new StreamTokenizer(pluginInputReader);
+ pluginInputTokenizer.resetSyntax();
+ pluginInputTokenizer.whitespaceChars('\u0000', '\u0000');
+ pluginInputTokenizer.wordChars('\u0001', '\u00FF');*/
+ pluginOutputWriter =
+ new BufferedWriter(new OutputStreamWriter
+ (outputstream, Charset.forName("UTF-8")));
+
+ /*
+ while(true) {
+ String message = read();
+ PluginDebug.debug(message);
+ handleMessage(message);
+ // TODO:
+ // write(queue.peek());
+ }
+ */
+ }
+
+ public void startProcessing() {
+
+ Thread listenerThread = new Thread() {
+
+ public void run() {
+
+ while (true) {
+
+ PluginDebug.debug("Waiting for data...");
+
+ long b4 = new Date().getTime();
+
+ String s = read();
+
+ long after = new Date().getTime();
+
+ totalWait += (after - b4);
+ //System.err.println("Total wait time: " + totalWait);
+
+ if (s != null) {
+ consumer.queue(s);
+ } else {
+ try {
+ // Close input/output channels to plugin.
+ pluginInputReader.close();
+ pluginOutputWriter.close();
+ } catch (IOException exception) {
+ // Deliberately ignore IOException caused by broken
+ // pipe since plugin may have already detached.
+ }
+ AppletSecurityContextManager.dumpStore(0);
+ PluginDebug.debug("APPLETVIEWER: exiting appletviewer");
+ System.exit(0);
+ }
+
+/*
+ int readChar = -1;
+ // blocking read, discard first character
+ try {
+ readChar = pluginInputReader.read();
+ } catch (IOException ioe) {
+ // plugin may have detached
+ }
+
+ // if not disconnected
+ if (readChar != -1) {
+ String s = read();
+ PluginDebug.debug("Got data, consuming " + s);
+ consumer.consume(s);
+ } else {
+ try {
+ // Close input/output channels to plugin.
+ pluginInputReader.close();
+ pluginOutputWriter.close();
+ } catch (IOException exception) {
+ // Deliberately ignore IOException caused by broken
+ // pipe since plugin may have already detached.
+ }
+ AppletSecurityContextManager.dumpStore(0);
+ PluginDebug.debug("APPLETVIEWER: exiting appletviewer");
+ System.exit(0);
+ }
+*/
+ }
+ }
+ };
+
+ listenerThread.start();
+ }
+
+ public void handleMessage(String message) throws PluginException {
+
+ int nextIndex = 0;
+ int reference = -1;
+ String src = null;
+ String[] privileges = null;
+ String rest = "";
+
+ String[] msgComponents = message.split(" ");
+
+ if (msgComponents.length < 2)
+ return;
+
+ if (msgComponents[0].startsWith("plugin")) {
+ handlePluginMessage(message);
+ return;
+ }
+
+ // type and identifier are guaranteed to be there
+ String type = msgComponents[0];
+ final int identifier = Integer.parseInt(msgComponents[1]);
+ nextIndex = 2;
+
+ // reference, src and privileges are optional components,
+ // and are guaranteed to be in that order, if they occur
+
+ // is there a reference ?
+ if (msgComponents[nextIndex].equals("reference")) {
+ reference = Integer.parseInt(msgComponents[nextIndex+1]);
+ nextIndex += 2;
+ }
+
+ // is there a src?
+ if (msgComponents[nextIndex].equals("src")) {
+ src = msgComponents[nextIndex+1];
+ nextIndex += 2;
+ }
+
+ // is there a privileges?
+ if (msgComponents[nextIndex].equals("privileges")) {
+ String privs = msgComponents[nextIndex+1];
+ privileges = privs.split(",");
+ nextIndex += 2;
+ }
+
+ // rest
+ for (int i=nextIndex; i < msgComponents.length; i++) {
+ rest += msgComponents[i];
+ rest += " ";
+ }
+
+ rest = rest.trim();
+
+ try {
+
+ PluginDebug.debug("Breakdown -- type: " + type + " identifier: " + identifier + " reference: " + reference + " src: " + src + " privileges: " + privileges + " rest: \"" + rest + "\"");
+
+ if (rest.contains("JavaScriptGetWindow")
+ || rest.contains("JavaScriptGetMember")
+ || rest.contains("JavaScriptSetMember")
+ || rest.contains("JavaScriptGetSlot")
+ || rest.contains("JavaScriptSetSlot")
+ || rest.contains("JavaScriptEval")
+ || rest.contains("JavaScriptRemoveMember")
+ || rest.contains("JavaScriptCall")
+ || rest.contains("JavaScriptFinalize")
+ || rest.contains("JavaScriptToString")) {
+
+ finishCallRequest("reference " + reference + " " + rest);
+ return;
+ }
+
+ final int freference = reference;
+ final String frest = rest;
+
+ if (type.equals("instance")) {
+ PluginAppletViewer.handleMessage(identifier, freference,frest);
+ } else if (type.equals("context")) {
+ PluginDebug.debug("Sending to PASC: " + identifier + "/" + reference + " and " + rest);
+ AppletSecurityContextManager.handleMessage(identifier, reference, src, privileges, rest);
+ }
+ } catch (Exception e) {
+ throw new PluginException(this, identifier, reference, e);
+ }
+ }
+
+ private void handlePluginMessage(String message) {
+ if (message.equals("plugin showconsole")) {
+ showConsole();
+ } else if (message.equals("plugin hideconsole")) {
+ hideConsole();
+ } else {
+ // else this is something that was specifically requested
+ finishCallRequest(message);
+ }
+ }
+
+ public void postCallRequest(PluginCallRequest request) {
+ synchronized(queue) {
+ queue.post(request);
+ }
+ }
+
+ private void finishCallRequest(String message) {
+ PluginDebug.debug ("DISPATCHCALLREQUESTS 1");
+ synchronized(queue) {
+ PluginDebug.debug ("DISPATCHCALLREQUESTS 2");
+ PluginCallRequest request = queue.pop();
+
+ // make sure we give the message to the right request
+ // in the queue.. for the love of God, MAKE SURE!
+
+ // first let's be efficient.. if there was only one
+ // request in queue, we're already set
+ if (queue.size() != 0) {
+
+ int size = queue.size();
+ int count = 0;
+
+ while (!request.serviceable(message)) {
+
+ PluginDebug.debug(request + " cannot service " + message);
+
+ // something is very wrong.. we have a message to
+ // process, but no one to service it
+ if (count >= size) {
+ throw new RuntimeException("Unable to find processor for message " + message);
+ }
+
+ // post request at the end of the queue
+ queue.post(request);
+
+ // Look at the next request
+ request = queue.pop();
+
+ count++;
+ }
+
+ }
+
+ PluginDebug.debug ("DISPATCHCALLREQUESTS 3");
+ if (request != null) {
+ PluginDebug.debug ("DISPATCHCALLREQUESTS 5");
+ synchronized(request) {
+ request.parseReturn(message);
+ request.notifyAll();
+ }
+ PluginDebug.debug ("DISPATCHCALLREQUESTS 6");
+ PluginDebug.debug ("DISPATCHCALLREQUESTS 7");
+ }
+ }
+ PluginDebug.debug ("DISPATCHCALLREQUESTS 8");
+ }
+
+ /**
+ * Read string from plugin.
+ *
+ * @return the read string
+ *
+ * @exception IOException if an error occurs
+ */
+ private String read()
+ {
+ String message = null;
+
+ try {
+ message = pluginInputReader.readLine();
+ PluginDebug.debug(" PIPE: appletviewer read: " + message);
+
+ if (message == null || message.equals("shutdown")) {
+ synchronized(shuttingDown) {
+ shuttingDown = true;
+ }
+ try {
+ // Close input/output channels to plugin.
+ pluginInputReader.close();
+ pluginOutputWriter.close();
+ } catch (IOException exception) {
+ // Deliberately ignore IOException caused by broken
+ // pipe since plugin may have already detached.
+ }
+ AppletSecurityContextManager.dumpStore(0);
+ PluginDebug.debug("APPLETVIEWER: exiting appletviewer");
+ System.exit(0);
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+
+ return message;
+ }
+
+ /**
+ * Write string to plugin.
+ *
+ * @param message the message to write
+ *
+ * @exception IOException if an error occurs
+ */
+ public void write(String message)
+ {
+
+ PluginDebug.debug(" PIPE: appletviewer wrote: " + message);
+ synchronized(pluginOutputWriter) {
+ try {
+ pluginOutputWriter.write(message + "\n", 0, message.length());
+ pluginOutputWriter.write(0);
+ pluginOutputWriter.flush();
+ } catch (IOException e) {
+ // if we are shutting down, ignore write failures as
+ // pipe may have closed
+ synchronized(shuttingDown) {
+ if (!shuttingDown) {
+ e.printStackTrace();
+ }
+ }
+
+ // either ways, if the pipe is broken, there is nothing
+ // we can do anymore. Don't hang around.
+ PluginDebug.debug("Unable to write to PIPE. APPLETVIEWER exiting");
+ System.exit(1);
+ }
+ }
+
+ return;
+ /*
+ synchronized(writeQueue) {
+ writeQueue.add(message);
+ PluginDebug.debug(" PIPE: appletviewer wrote: " + message);
+ }
+ */
+
+ }
+
+ public boolean messageAvailable() {
+ return writeQueue.size() != 0;
+ }
+
+ public String getMessage() {
+ synchronized(writeQueue) {
+ String ret = writeQueue.size() > 0 ? writeQueue.poll() : "";
+ return ret;
+ }
+ }
+
+ private void showConsole() {
+ SwingUtilities.invokeLater(new Runnable() {
+ public void run() {
+ console.showConsole();
+ }
+ });
+ }
+
+ private void hideConsole() {
+ SwingUtilities.invokeLater(new Runnable() {
+ public void run() {
+ console.hideConsole();
+ }
+ });
+ }
+}
diff --git a/plugin/icedteanp/java/sun/applet/RequestQueue.java b/plugin/icedteanp/java/sun/applet/RequestQueue.java
new file mode 100644
index 0000000..87dc54f
--- /dev/null
+++ b/plugin/icedteanp/java/sun/applet/RequestQueue.java
@@ -0,0 +1,77 @@
+/* VoidPluginCallRequest -- represent Java-to-JavaScript requests
+ Copyright (C) 2008 Red Hat
+
+This file is part of IcedTea.
+
+IcedTea is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+IcedTea is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with IcedTea; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package sun.applet;
+
+
+public class RequestQueue {
+ PluginCallRequest head = null;
+ PluginCallRequest tail = null;
+ private int size = 0;
+
+ public void post(PluginCallRequest request) {
+ PluginDebug.debug("Securitymanager=" + System.getSecurityManager());
+ if (head == null) {
+ head = tail = request;
+ tail.setNext(null);
+ } else {
+ tail.setNext(request);
+ tail = request;
+ tail.setNext(null);
+ }
+
+ size++;
+ }
+
+ public PluginCallRequest pop() {
+ if (head == null)
+ return null;
+
+ PluginCallRequest ret = head;
+ head = head.getNext();
+ ret.setNext(null);
+
+ size--;
+
+ return ret;
+ }
+
+ public int size() {
+ return size;
+ }
+}
diff --git a/plugin/icedteanp/java/sun/applet/TestEnv.java b/plugin/icedteanp/java/sun/applet/TestEnv.java
new file mode 100644
index 0000000..08b74ce
--- /dev/null
+++ b/plugin/icedteanp/java/sun/applet/TestEnv.java
@@ -0,0 +1,172 @@
+/* TestEnv -- test JavaScript-to-Java calls
+ Copyright (C) 2008 Red Hat
+
+This file is part of IcedTea.
+
+IcedTea is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+IcedTea is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with IcedTea; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package sun.applet;
+
+public class TestEnv
+{
+ public static int intField = 103;
+ public int intInstanceField = 7822;
+ public String stringField = "hello";
+ // z <musical G clef> <chinese water>
+ public String complexStringField = "z\uD834\uDD1E\u6C34";
+
+ public static void TestIt() {
+ PluginDebug.debug("TestIt");
+ }
+
+ public static void TestItBool(boolean arg) {
+ PluginDebug.debug("TestItBool: " + arg);
+ }
+
+ public static void TestItByte(byte arg) {
+ PluginDebug.debug("TestItByte: " + arg);
+ }
+
+ public static void TestItChar(char arg) {
+ PluginDebug.debug("TestItChar: " + arg);
+ }
+
+ public static void TestItShort(short arg) {
+ PluginDebug.debug("TestItShort: " + arg);
+ }
+
+ public static void TestItInt(int arg) {
+ PluginDebug.debug("TestItInt: " + arg);
+ }
+
+ public static void TestItLong(long arg) {
+ PluginDebug.debug("TestItLong: " + arg);
+ }
+
+ public static void TestItFloat(float arg) {
+ PluginDebug.debug("TestItFloat: " + arg);
+ }
+
+ public static void TestItDouble(double arg) {
+ PluginDebug.debug("TestItDouble: " + arg);
+ }
+
+ public static void TestItObject(TestEnv arg) {
+ PluginDebug.debug("TestItObject: " + arg);
+ }
+
+ public static void TestItObjectString(String arg) {
+ PluginDebug.debug("TestItObjectString: " + arg);
+ }
+
+ public static void TestItIntArray(int[] arg) {
+ PluginDebug.debug("TestItIntArray: " + arg);
+ for (int i = 0; i < arg.length; i++)
+ PluginDebug.debug ("ELEMENT: " + i + " " + arg[i]);
+ }
+
+ public static void TestItObjectArray(String[] arg) {
+ PluginDebug.debug("TestItObjectArray: " + arg);
+ for (int i = 0; i < arg.length; i++)
+ PluginDebug.debug ("ELEMENT: " + i + " " + arg[i]);
+ }
+
+ public static void TestItObjectArrayMulti(String[][] arg) {
+ PluginDebug.debug("TestItObjectArrayMulti: " + arg);
+ for (int i = 0; i < arg.length; i++)
+ for (int j = 0; j < arg[i].length; j++)
+ PluginDebug.debug ("ELEMENT: " + i + " " + j + " " + arg[i][j]);
+ }
+
+ public static boolean TestItBoolReturnTrue() {
+ return true;
+ }
+
+ public static boolean TestItBoolReturnFalse() {
+ return false;
+ }
+
+ public static byte TestItByteReturn() {
+ return (byte) 0xfe;
+ }
+
+ public static char TestItCharReturn() {
+ return 'K';
+ }
+
+ public static char TestItCharUnicodeReturn() {
+ return '\u6C34';
+ }
+
+ public static short TestItShortReturn() {
+ return 23;
+ }
+
+ public static int TestItIntReturn() {
+ return 3445;
+ }
+
+ public static long TestItLongReturn() {
+ return 3242883;
+ }
+
+ public static float TestItFloatReturn() {
+ return 9.21E4f;
+ }
+
+ public static double TestItDoubleReturn() {
+ return 8.33E88;
+ }
+
+ public static Object TestItObjectReturn() {
+ return new String("Thomas");
+ }
+
+ public static int[] TestItIntArrayReturn() {
+ return new int[] { 6, 7, 8 };
+ }
+
+ public static String[] TestItObjectArrayReturn() {
+ return new String[] { "Thomas", "Brigitte" };
+ }
+
+ public static String[][] TestItObjectArrayMultiReturn() {
+ return new String[][] { {"Thomas", "Brigitte"},
+ {"Lindsay", "Michael"} };
+ }
+
+ public int TestItIntInstance(int arg) {
+ PluginDebug.debug("TestItIntInstance: " + this + " " + arg);
+ return 899;
+ }
+}
diff --git a/plugin/icedteanp/java/sun/applet/VoidPluginCallRequest.java b/plugin/icedteanp/java/sun/applet/VoidPluginCallRequest.java
new file mode 100644
index 0000000..0bacc6c
--- /dev/null
+++ b/plugin/icedteanp/java/sun/applet/VoidPluginCallRequest.java
@@ -0,0 +1,54 @@
+/* VoidPluginCallRequest -- represent Java-to-JavaScript requests
+ Copyright (C) 2008 Red Hat
+
+This file is part of IcedTea.
+
+IcedTea is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+IcedTea is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with IcedTea; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package sun.applet;
+
+
+public class VoidPluginCallRequest extends PluginCallRequest {
+ public VoidPluginCallRequest(String message, Long reference) {
+ super(message, reference);
+ PluginDebug.debug ("VoidPluginCall " + message);
+ }
+
+ public void parseReturn(String message) {
+ setDone(true);
+ }
+
+ public Object getObject() {
+ return null;
+ }
+}