[xpcom] Fix signal emission checks to actually iterate through the
[browser-dbus-bridge.git] / xpcom-dbusservice / DBusService.cpp
index 96ae0a4..51fef8c 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright © 2008 Movial Creative Technologies Inc
  *  Contact: Movial Creative Technologies Inc, <info@movial.com>
- *  Authors: Lauri Mylläri, <lauri.myllari@movial.fi>
+ *  Authors: Lauri Mylläri, <lauri.myllari@movial.com>
  *           Kalle Vahlman, <kalle.vahlman@movial.com>
  *
  * The contents of this file are subject to the Mozilla Public License
 #include "nsIGenericFactory.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsComponentManagerUtils.h"
+#include "nsServiceManagerUtils.h"
 
 #include "nsEmbedString.h"
 #include "nsIMutableArray.h"
 #include "nsArrayUtils.h"
+#include "nsIXPConnect.h"
 
 #include "IDBusService.h"
 
 #include "DBusService.h"
 #include "DBusMethod.h"
 #include "DBusSignal.h"
+#include "DBusDataCarrier.h"
 #include "DBusMarshaling.h"
 
 #include "bdb-debug.h"
@@ -64,7 +67,8 @@ DBusService::DBusService() :
     mSystemBus(nsnull),
     mSessionBus(nsnull),
     mSystemBusHasFilter(PR_FALSE),
-    mSessionBusHasFilter(PR_FALSE)
+    mSessionBusHasFilter(PR_FALSE),
+    mInsideEmit(PR_FALSE)
 {
     BDBLOG(("DBusService::DBusService()\n"));
     mSystemBusSignalObservers.Init();
@@ -124,7 +128,8 @@ DBusService::GetSignal(PRUint32 aBusType,
                                          aInterfaceName,
                                          aSignalName,
                                          aSender,
-                                         aObjectPath);
+                                         aObjectPath,
+                                         GetCurrentJSContext());
 
     NS_ENSURE_TRUE(signal, NS_ERROR_OUT_OF_MEMORY);
 
@@ -164,7 +169,8 @@ DBusService::GetMethod(PRUint32 aBusType,
                                          aObjectPath,
                                          aMethodName,
                                          aInterfaceName,
-                                         aSignature);
+                                         aSignature,
+                                         GetCurrentJSContext());
 
     NS_ENSURE_TRUE(method, NS_ERROR_OUT_OF_MEMORY);
 
@@ -173,6 +179,106 @@ DBusService::GetMethod(PRUint32 aBusType,
     return NS_OK;
 }
 
+NS_IMETHODIMP DBusService::EmitSignal(PRUint32 busType,
+                                      const nsACString & objectPath,
+                                      const nsACString & interfaceName,
+                                      const nsACString & signalName,
+                                      const nsACString & aSignature,
+                                      nsIVariant **args,
+                                      PRUint32 count,
+                                      PRBool *_retval)
+{
+    DBusMessage *msg;
+    DBusMessageIter msg_iter;
+    DBusConnection *conn;
+    nsCAutoString signature;
+
+    conn = GetConnection(busType);
+
+    if (!conn)
+    {
+        BDBLOG(("DBusService::EmitSignal()): invalid bus type %d\n",
+               busType));
+        return NS_ERROR_ILLEGAL_VALUE;
+    }
+
+    if (objectPath.IsEmpty()
+     || interfaceName.IsEmpty()
+     || signalName.IsEmpty())
+    {
+        BDBLOG(("DBusService::EmitSignal()): invalid signal arguments\n"));
+        return NS_ERROR_ILLEGAL_VALUE;
+    }
+
+    msg = dbus_message_new_signal(PromiseFlatCString(objectPath).get(),
+                                  PromiseFlatCString(interfaceName).get(),
+                                  PromiseFlatCString(signalName).get());
+    dbus_message_iter_init_append(msg, &msg_iter);
+
+    if (count > 0)
+    {
+        JSContext *cx = GetCurrentJSContext();
+
+        if (aSignature.Equals(""))
+        {
+            for (PRUint32 i = 0; i < count; i++)
+            {
+                // no method signature specified, guess argument types
+                nsCOMPtr<nsIVariant> data = args[i];
+                nsCAutoString tmpsig;
+
+                getSignatureFromVariant(cx, data, tmpsig);
+                BDBLOG(("  aArgs[%02d]       : signature \"%s\"\n",
+                       i,
+                       PromiseFlatCString(tmpsig).get()));
+                signature.Append(tmpsig);
+
+            }
+        } else {
+            signature.Assign(aSignature);
+        }
+
+        if (dbus_signature_validate(PromiseFlatCString(signature).get(), nsnull))
+        {
+            DBusSignatureIter sig_iter;
+            int current_type;
+            int i = 0;
+
+            BDBLOG(("  signature \"%s\"\n", PromiseFlatCString(signature).get()));
+
+            dbus_signature_iter_init(&sig_iter, PromiseFlatCString(signature).get());
+            while ((current_type = dbus_signature_iter_get_current_type(&sig_iter)) != DBUS_TYPE_INVALID)
+            {
+                char *element_signature = dbus_signature_iter_get_signature(&sig_iter);
+                BDBLOG(("  element \"%s\" from signature\n", element_signature));
+                BDBLOG(("  type %c from signature\n", current_type));
+
+                addVariantToIter(cx, args[i], &msg_iter, &sig_iter);
+
+                i++;
+                dbus_free(element_signature);
+                dbus_signature_iter_next(&sig_iter);
+            }
+        }
+        else
+        {
+            BDBLOG(("  invalid signature \"%s\"\n", PromiseFlatCString(signature).get()));
+            dbus_message_unref(msg);
+            return NS_ERROR_ILLEGAL_VALUE;
+        }
+    }
+
+    if (dbus_connection_send(conn, msg, NULL))
+    {
+        dbus_message_unref(msg);
+        return NS_OK;
+    }
+        
+    dbus_message_unref(msg);
+    return NS_ERROR_UNEXPECTED;
+}
+
 DBusPendingCall *DBusService::SendWithReply(PRUint32 aConnType,
                                             DBusMessage *aMessage,
                                             PRUint32 aTimeout)
@@ -242,7 +348,7 @@ DBusHandlerResult _signal_filter(DBusConnection *connection,
         BDBLOG(("  got observerList\n"));
         DBusService *service = DBusService::GetSingleton();
         
-        for (PRInt32 i = 0; i < observerList->Length(); ++i) {
+        for (PRUint32 i = 0; i < observerList->Length(); ++i) {
             nsCAutoString t;
             nsCOMPtr<IDBusSignal> signal = do_QueryReferent((*observerList)[i]);
             signal->GetInterfaceName(t);
@@ -254,14 +360,14 @@ DBusHandlerResult _signal_filter(DBusConnection *connection,
             if (!t.IsEmpty() && !t.Equals(dbus_message_get_sender(message)))
             {
                 BDBLOG(("    sender does not match\n"));
-                break;
+                continue;
             }
             signal->GetObjectPath(t);
             BDBLOG(("    object    : %s\n", PromiseFlatCString(t).get()));
             if (!t.IsEmpty() && !t.Equals(dbus_message_get_path(message)))
             {
                 BDBLOG(("    objectPath does not match\n"));
-                break;
+                continue;
             }
 
             /* do callback */
@@ -270,7 +376,9 @@ DBusHandlerResult _signal_filter(DBusConnection *connection,
             nsCOMPtr<nsIMutableArray> args_array;
 
             dbus_message_iter_init(message, &iter);
-            args_array = getArrayFromIter(&iter);
+            JSContext *cx;
+            signal->GetJSContext(&cx);
+            args_array = getArrayFromIter(cx, &iter);
 
             PRUint32 arg_items;
             args_array->GetLength(&arg_items);
@@ -279,7 +387,7 @@ DBusHandlerResult _signal_filter(DBusConnection *connection,
             /* arguments are packed as an array into an nsIVariant */
             nsIVariant **callback_args = new nsIVariant*[arg_items];
             nsCOMPtr<nsIWritableVariant> args = do_CreateInstance("@mozilla.org/variant;1");
-            for (int i = 0; i < arg_items; i++)
+            for (PRUint32 i = 0; i < arg_items; i++)
             {
                 nsCOMPtr<nsIVariant> arg = do_QueryElementAt(args_array, i);
                 callback_args[i] = arg;
@@ -289,7 +397,7 @@ DBusHandlerResult _signal_filter(DBusConnection *connection,
                              &NS_GET_IID(nsIVariant),
                              arg_items,
                              callback_args);
-            for (int i = 0; i < arg_items; i++)
+            for (PRUint32 i = 0; i < arg_items; i++)
                 NS_RELEASE(callback_args[i]);
             delete[] callback_args;
 
@@ -450,7 +558,7 @@ void DBusService::RemoveSignalObserver(IDBusSignal *aSignal)
         BDBLOG(("  got observerList\n"));
         nsCOMPtr<nsISupportsWeakReference> weakRefable = do_QueryInterface(aSignal);
         nsWeakPtr weakPtr = getter_AddRefs(NS_GetWeakReference(weakRefable));
-        for (PRInt32 i = 0; i < observerList->Length(); ++i) {
+        for (PRUint32 i = 0; i < observerList->Length(); ++i) {
             nsCAutoString t;
             nsCAutoString ob;
             nsCOMPtr<IDBusSignal> signal = do_QueryReferent((*observerList)[i]);
@@ -463,7 +571,7 @@ void DBusService::RemoveSignalObserver(IDBusSignal *aSignal)
         }
         BDBLOG(("  call observerList->RemoveElement\n"));
         observerList->RemoveElement(weakPtr);
-        for (PRInt32 i = 0; i < observerList->Length(); ++i) {
+        for (PRUint32 i = 0; i < observerList->Length(); ++i) {
             nsCAutoString t;
             nsCAutoString ob;
             nsCOMPtr<IDBusSignal> signal = do_QueryReferent((*observerList)[i]);
@@ -497,6 +605,35 @@ void DBusService::RemoveSignalObserver(IDBusSignal *aSignal)
     }
 }
 
+JSContext *DBusService::GetCurrentJSContext()
+{
+    // try to get a JS context (code borrowed from xpcsample1.cpp)
+
+    // get the xpconnect service
+    nsresult rv;
+    nsCOMPtr<nsIXPConnect> xpc(do_GetService(nsIXPConnect::GetCID(), &rv));
+    if(NS_FAILED(rv))
+        return nsnull;
+    BDBLOG(("    got nsIXPConnect\n"));
+
+    // get the xpconnect native call context
+    nsAXPCNativeCallContext *callContext = nsnull;
+    xpc->GetCurrentNativeCallContext(&callContext);
+    if(!callContext)
+    {
+    BDBLOG(("    callContext :(\n"));
+        return nsnull;
+    }
+    // Get JSContext of current call
+    JSContext* cx;
+    rv = callContext->GetJSContext(&cx);
+    if(NS_FAILED(rv) || !cx)
+        return nsnull;
+    BDBLOG(("    got JSContext\n"));
+
+    return cx;
+}
+
 DBusConnection *DBusService::GetConnection(PRUint32 aConnType)
 {
     BDBLOG(("DBusService::GetConnection(%d)\n", aConnType));
@@ -555,32 +692,36 @@ DBusService::GetSingleton()
 //
 
 NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(DBusService, DBusService::GetSingleton);
+NS_GENERIC_FACTORY_CONSTRUCTOR(DBusDataCarrier);
 
 static const nsModuleComponentInfo components[] =
 {
     {
         "DBus service",
         DBUSSERVICE_CID,
-        "@movial.fi/dbus/service;1",
+        "@movial.com/dbus/service;1",
         DBusServiceConstructor
     },
     {
         "DBus method",
         DBUSMETHOD_CID,
-        "@movial.fi/dbus/method;1",
+        "@movial.com/dbus/method;1",
         nsnull
     },
     {
         "DBus signal",
         DBUSSIGNAL_CID,
-        "@movial.fi/dbus/signal;1",
+        "@movial.com/dbus/signal;1",
         nsnull
+    },
+    {
+        "DBus data carrier",
+        DBUSDATACARRIER_CID,
+        "@movial.com/dbus/datacarrier;1",
+        DBusDataCarrierConstructor
     }
 };
 
 NS_IMPL_NSGETMODULE(nsDBusServiceModule, components);
 
-
-
-
 /* vim: set cindent ts=4 et sw=4: */