aboutsummaryrefslogtreecommitdiffstats
path: root/plugin/icedteanp/IcedTeaPluginRequestProcessor.cc
diff options
context:
space:
mode:
Diffstat (limited to 'plugin/icedteanp/IcedTeaPluginRequestProcessor.cc')
-rw-r--r--plugin/icedteanp/IcedTeaPluginRequestProcessor.cc988
1 files changed, 988 insertions, 0 deletions
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");
+}
+