Import the XPCOM version
authorKalle Vahlman <kalle.vahlman@movial.com>
Mon, 3 Nov 2008 13:04:32 +0000 (15:04 +0200)
committerKalle Vahlman <kalle.vahlman@movial.com>
Mon, 3 Nov 2008 13:04:32 +0000 (15:04 +0200)
xpcom-dbusservice/DBusMarshaling.cpp [new file with mode: 0644]
xpcom-dbusservice/DBusMarshaling.h [new file with mode: 0644]
xpcom-dbusservice/DBusMethod.cpp [new file with mode: 0644]
xpcom-dbusservice/DBusMethod.h [new file with mode: 0644]
xpcom-dbusservice/DBusService.cpp [new file with mode: 0644]
xpcom-dbusservice/DBusService.h [new file with mode: 0644]
xpcom-dbusservice/DBusSignal.cpp [new file with mode: 0644]
xpcom-dbusservice/DBusSignal.h [new file with mode: 0644]
xpcom-dbusservice/IDBusService.idl [new file with mode: 0644]
xpcom-dbusservice/bdb-debug.h [new file with mode: 0644]
xpcom-dbusservice/build.mk [new file with mode: 0644]

diff --git a/xpcom-dbusservice/DBusMarshaling.cpp b/xpcom-dbusservice/DBusMarshaling.cpp
new file mode 100644 (file)
index 0000000..6a20087
--- /dev/null
@@ -0,0 +1,1166 @@
+/**
+ * Browser D-Bus Bridge, XPCOM version
+ *
+ * Copyright © 2008 Movial Creative Technologies Inc
+ *  Contact: Movial Creative Technologies Inc, <info@movial.com>
+ *  Authors: Lauri Mylläri, <lauri.myllari@movial.fi>
+ *           Kalle Vahlman, <kalle.vahlman@movial.com>
+ *
+ * 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 the Browser D-Bus Bridge, XPCOM version.
+ *
+ * The Initial Developer of the Original Code is Movial Creative Technologies
+ * Inc. Portions created by Initial Developer are Copyright (C) 2008
+ * Movial Creative Technologies Inc. All Rights Reserved.
+ *
+ */
+
+#include <stdio.h>
+
+#include "nsEmbedString.h"
+#include "nsComponentManagerUtils.h"
+#include "nsServiceManagerUtils.h"
+#include "nsArrayUtils.h"
+#include "nsMemory.h"
+#include "nsISupportsPrimitives.h"
+#include "nsIProperties.h"
+#include "nsIXPConnect.h"
+
+#include "DBusMarshaling.h"
+
+#include "bdb-debug.h"
+
+void addArrayDataToIter(void *data_ptr, PRUint32 count, PRUint16 type, DBusMessageIter *aIter, DBusSignatureIter *aSigIter);
+void addJSValueToIter(JSContext *cx, jsval *aValue, DBusMessageIter *aIter, DBusSignatureIter *aSigIter);
+
+static void
+listJSObjectProperties(JSContext *cx, JSObject *js_obj)
+{
+    JSIdArray *props = JS_Enumerate(cx, js_obj);
+    if (props)
+    {
+        BDBLOG(("  listJSObjectProperties: got JSIdArray with %i props\n", props->length));
+
+        for (int i = 0; i < props->length; i++)
+        {
+            jsval v;
+            const PRUnichar *name;
+            JS_IdToValue( cx, props->vector[i], &v );
+            JSString *prop_string = JS_ValueToString(cx, v);
+            name = reinterpret_cast<const PRUnichar*>(JS_GetStringChars(prop_string));
+            nsDependentString name_s(name);
+            const char *utf8prop = NS_ConvertUTF16toUTF8(name_s).get();
+            BDBLOG(("    property %s\n", utf8prop));
+
+            jsval value;
+            if (JS_LookupUCProperty(cx,
+                                    js_obj,
+                                    JS_GetStringChars(prop_string),
+                                    JS_GetStringLength(prop_string),
+                                    &value) == JS_TRUE)
+            {
+                JSString *val_string = JS_ValueToString(cx, value);
+                const PRUnichar *valstr = reinterpret_cast<const PRUnichar*>(JS_GetStringChars(val_string));
+                nsDependentString val_s(valstr);
+                const char *utf8val = NS_ConvertUTF16toUTF8(val_s).get();
+                BDBLOG(("    value %s\n", utf8val));
+            }
+        }
+        JS_DestroyIdArray(cx, props);
+    }
+}
+
+void
+getSignatureFromJSValue(JSContext *cx, jsval *aValue, nsCString &aResult)
+{
+    aResult.Assign(DBUS_TYPE_INVALID_AS_STRING);
+
+    if (JSVAL_IS_BOOLEAN(*aValue))
+        aResult.Assign(DBUS_TYPE_BOOLEAN_AS_STRING);
+    else if (JSVAL_IS_INT(*aValue))
+        aResult.Assign(DBUS_TYPE_INT32_AS_STRING);
+    else if (JSVAL_IS_DOUBLE(*aValue))
+        aResult.Assign(DBUS_TYPE_DOUBLE_AS_STRING);
+    else if (JSVAL_IS_STRING(*aValue))
+        aResult.Assign(DBUS_TYPE_STRING_AS_STRING);
+    else if (JSVAL_IS_OBJECT(*aValue) && JS_IsArrayObject(cx, JSVAL_TO_OBJECT(*aValue)))
+    {
+        // guess element type from first property value
+
+        JSIdArray *props = JS_Enumerate(cx, JSVAL_TO_OBJECT(*aValue));
+        if (props)
+        {
+            BDBLOG(("    got JSIdArray\n"));
+            aResult.Assign(DBUS_TYPE_ARRAY_AS_STRING);
+
+            // get key signature from first property name
+            jsval propname;
+            nsCAutoString tmpsig;
+            JS_IdToValue(cx, props->vector[0], &propname);
+
+            jsval propvalue;
+            JSString *prop_string = JS_ValueToString(cx, propname);
+            if (JS_LookupUCProperty(cx,
+                                    JSVAL_TO_OBJECT(*aValue),
+                                    JS_GetStringChars(prop_string),
+                                    JS_GetStringLength(prop_string),
+                                    &propvalue) == JS_TRUE)
+            {
+                getSignatureFromJSValue(cx, &propvalue, tmpsig);
+                aResult.Append(tmpsig);
+            }
+            else
+            {
+                // FIXME - could not find property value??
+                // assume string to keep signature valid
+                aResult.Append(DBUS_TYPE_STRING_AS_STRING);
+            }
+            JS_DestroyIdArray(cx, props);
+        }
+
+    }
+    else if (JSVAL_IS_OBJECT(*aValue))
+    {
+        nsISupports* supports;
+        JSClass* clazz;
+        JSObject* parent;
+        JSObject* glob = JSVAL_TO_OBJECT(*aValue);
+
+        clazz = JS_GET_CLASS(cx, JS_GetParent(cx, glob));
+
+        if (!clazz ||
+            !(clazz->flags & JSCLASS_HAS_PRIVATE) ||
+            !(clazz->flags & JSCLASS_PRIVATE_IS_NSISUPPORTS) ||
+            !(supports = (nsISupports*) JS_GetPrivate(cx, glob))) {
+
+            BDBLOG(("  getSignatureFromJSValue: could not find nsISupports inside object, assume dictionary\n"));
+
+            // try to enumerate object properties
+            JSIdArray *props = JS_Enumerate(cx, glob);
+            if (props)
+            {
+                BDBLOG(("    got JSIdArray with %i props\n", props->length));
+                aResult.Assign(DBUS_TYPE_ARRAY_AS_STRING);
+                aResult.Append(DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING);
+
+                // get key signature from first property name
+                jsval propname;
+                nsCAutoString tmpsig;
+                JS_IdToValue(cx, props->vector[0], &propname);
+                getSignatureFromJSValue(cx, &propname, tmpsig);
+                aResult.Append(tmpsig);
+
+                jsval propvalue;
+                JSString *prop_string = JS_ValueToString(cx, propname);
+                if (JS_LookupUCProperty(cx,
+                                        glob,
+                                        JS_GetStringChars(prop_string),
+                                        JS_GetStringLength(prop_string),
+                                        &propvalue) == JS_TRUE)
+                {
+                    getSignatureFromJSValue(cx, &propvalue, tmpsig);
+                    aResult.Append(tmpsig);
+                }
+                else
+                {
+                    // FIXME - could not find property value??
+                    // assume string to keep signature valid
+                    aResult.Append(DBUS_TYPE_STRING_AS_STRING);
+                }
+                aResult.Append(DBUS_DICT_ENTRY_END_CHAR_AS_STRING);
+                JS_DestroyIdArray(cx, props);
+            }
+
+        }
+        else
+        {
+            BDBLOG(("  getSignatureFromJSValue: clazz->name %s\n", clazz->name));
+            // test argument for nsIXPConnectWrappedNative
+            nsCOMPtr<nsIXPConnectWrappedNative> wrappednative = do_QueryInterface(supports);
+            if (wrappednative)
+            {
+                BDBLOG(("  getSignatureFromJSValue: got nsIXPConnectWrappedNative\n"));
+                nsCOMPtr<nsIVariant> variant = do_QueryInterface(wrappednative->Native());
+                if (variant)
+                {
+                    BDBLOG(("    found wrapped variant\n"));
+                    getSignatureFromVariant(variant, aResult);
+                    return;
+                }
+            }
+            // use string type as fallback
+            aResult.Assign(DBUS_TYPE_STRING_AS_STRING);
+            return;
+        }
+
+    }
+}
+
+void
+getSignatureFromVariantType(PRUint16 aType, nsCString &aResult)
+{
+    switch (aType) {
+        case nsIDataType::VTYPE_BOOL:
+            aResult.Assign(DBUS_TYPE_BOOLEAN_AS_STRING);
+            return;
+        case nsIDataType::VTYPE_INT8: /* FIXME - check sign issues;
+                                         dbus supports only unsigned 8bit */
+        case nsIDataType::VTYPE_UINT8:
+            aResult.Assign(DBUS_TYPE_BYTE_AS_STRING);
+            return;
+        case nsIDataType::VTYPE_INT16:
+            aResult.Assign(DBUS_TYPE_INT16_AS_STRING);
+            return;
+        case nsIDataType::VTYPE_UINT16:
+            aResult.Assign(DBUS_TYPE_UINT16_AS_STRING);
+            return;
+        case nsIDataType::VTYPE_INT32:
+            aResult.Assign(DBUS_TYPE_INT32_AS_STRING);
+            return;
+        case nsIDataType::VTYPE_UINT32:
+            aResult.Assign(DBUS_TYPE_UINT32_AS_STRING);
+            return;
+        case nsIDataType::VTYPE_INT64:
+            aResult.Assign(DBUS_TYPE_INT64_AS_STRING);
+            return;
+        case nsIDataType::VTYPE_UINT64:
+            aResult.Assign(DBUS_TYPE_UINT64_AS_STRING);
+            return;
+        case nsIDataType::VTYPE_DOUBLE:
+            aResult.Assign(DBUS_TYPE_DOUBLE_AS_STRING);
+            return;
+        case nsIDataType::VTYPE_VOID:
+            // FIXME - assume that string is the best representation
+        case nsIDataType::VTYPE_WSTRING_SIZE_IS:
+        case nsIDataType::VTYPE_WCHAR_STR:
+            aResult.Assign(DBUS_TYPE_STRING_AS_STRING);
+            return;
+        default:
+            BDBLOG(("  getSignatureFromVariantType: %d not a simple type\n", aType));
+            aResult.Assign(DBUS_TYPE_INVALID_AS_STRING);
+    }
+}
+
+void
+getSignatureFromVariant(nsIVariant *aVariant, nsCString &aResult)
+{
+    aResult.Assign(DBUS_TYPE_INVALID_AS_STRING);
+
+    PRUint16 dataType;
+    aVariant->GetDataType(&dataType);
+
+    switch (dataType) {
+        case nsIDataType::VTYPE_VOID:
+        case nsIDataType::VTYPE_BOOL:
+        case nsIDataType::VTYPE_INT8:
+        case nsIDataType::VTYPE_UINT8:
+        case nsIDataType::VTYPE_INT16:
+        case nsIDataType::VTYPE_UINT16:
+        case nsIDataType::VTYPE_INT32:
+        case nsIDataType::VTYPE_UINT32:
+        case nsIDataType::VTYPE_INT64:
+        case nsIDataType::VTYPE_UINT64:
+        case nsIDataType::VTYPE_DOUBLE:
+        case nsIDataType::VTYPE_WSTRING_SIZE_IS:
+        case nsIDataType::VTYPE_WCHAR_STR:
+        {
+            PRUint32 val = 0;
+            aVariant->GetAsUint32(&val);
+            BDBLOG(("  getSignatureFromVariant: simple type %i:%i\n", dataType, val));
+            getSignatureFromVariantType(dataType, aResult);
+            break;
+        }
+        case nsIDataType::VTYPE_ARRAY:
+        {
+            BDBLOG(("  getSignatureFromVariant: array\n"));
+
+            // need to recurse into array
+            PRUint16 type = 0;
+            nsIID iid;
+            PRUint32 count = 0;
+            void *data_ptr = nsnull;
+
+            aVariant->GetAsArray(&type,
+                                 &iid,
+                                 &count,
+                                 &data_ptr);
+
+            BDBLOG(("  getSignatureFromVariant: got %d elements of type %d\n", count, type));
+
+            nsCAutoString elementsig;
+
+            if (type == nsIDataType::VTYPE_INTERFACE_IS)
+            {
+                // get element signature from first element
+                nsISupports *element = ((nsISupports **)data_ptr)[0];
+                getSignatureFromISupports(element, elementsig);
+            }
+            else if (type == nsIDataType::VTYPE_ARRAY)
+            {
+                // FIXME - can this happen?
+                BDBLOG(("    element type array, don't know how to handle\n"));
+            }
+            else
+            {
+                getSignatureFromVariantType(type, elementsig);
+            }
+
+            aResult.Assign(DBUS_TYPE_ARRAY_AS_STRING);
+            aResult.Append(elementsig);
+
+            nsMemory::Free(data_ptr);
+            break;
+        }
+        case nsIDataType::VTYPE_INTERFACE_IS:
+        {
+            BDBLOG(("  getSignatureFromVariant: interface\n"));
+            nsCOMPtr<nsISupports> is;
+            nsIID *iid;
+            aVariant->GetAsInterface(&iid, getter_AddRefs(is));
+            getSignatureFromISupports(is, aResult);
+            break;
+        }
+        default:
+        {
+            BDBLOG(("  getSignatureFromVariant: unknown type %d\n", dataType));
+            break;
+        }
+    }
+}
+
+void
+getSignatureFromISupports(nsISupports *aISupports, nsCString &aResult)
+{
+    aResult.Assign(DBUS_TYPE_INVALID_AS_STRING);
+
+    // test argument for nsIVariant
+    nsCOMPtr<nsIVariant> variant = do_QueryInterface(aISupports);
+    if (variant)
+    {
+        BDBLOG(("  getSignatureFromISupports: nsIVariant\n"));
+        getSignatureFromVariant(variant, aResult);
+        return;
+    }
+
+    // test argument for nsIXPConnectWrappedJS
+    nsCOMPtr<nsIXPConnectWrappedJS> wrapped = do_QueryInterface(aISupports);
+    if (wrapped)
+    {
+        BDBLOG(("  getSignatureFromISupports: nsIXPConnectWrappedJS\n"));
+        JSObject *js_obj = nsnull;
+        if (NS_SUCCEEDED(wrapped->GetJSObject(&js_obj)))
+        {
+            // 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;
+            BDBLOG(("    got nsIXPConnect\n"));
+
+            // get the xpconnect native call context
+            nsAXPCNativeCallContext *callContext = nsnull;
+            xpc->GetCurrentNativeCallContext(&callContext);
+            if(!callContext)
+                return;
+
+            // Get JSContext of current call
+            JSContext* cx;
+            rv = callContext->GetJSContext(&cx);
+            if(NS_FAILED(rv) || !cx)
+                return;
+            BDBLOG(("    got JSContext\n"));
+
+            jsval obj_as_jsval = OBJECT_TO_JSVAL(js_obj);
+            getSignatureFromJSValue(cx, &obj_as_jsval, aResult);
+        }
+    }
+}
+
+void
+addVariantToIter(nsIVariant *aVariant, DBusMessageIter *aIter, DBusSignatureIter *aSigIter)
+{
+    char *element_signature = dbus_signature_iter_get_signature(aSigIter);
+    int element_type = dbus_signature_iter_get_current_type(aSigIter);
+
+    PRUint16 variant_type;
+    aVariant->GetDataType(&variant_type);
+
+    printf("addVariantToIter: signature \"%s\", type %c, variant type: %i\n",
+           element_signature,
+           element_type,
+           variant_type);
+
+    if (dbus_type_is_basic(element_type))
+    {
+        BDBLOG(("  add basic type from variant\n"));
+        addBasicTypeToIter(aVariant, aIter, element_type);
+    }
+    else if (element_type == DBUS_TYPE_ARRAY)
+    {
+        if (dbus_signature_iter_get_element_type(aSigIter) == DBUS_TYPE_DICT_ENTRY)
+        {
+            /* TODO: Support for non-JS Dicts */
+            
+          BDBLOG(("  add dict from variant\n"));
+
+            nsCOMPtr<nsISupports> is;
+            nsIID *iid;
+            // Reported by a leak, dunno why?
+            aVariant->GetAsInterface(&iid, getter_AddRefs(is));
+
+            // test argument for nsIXPConnectWrappedJS
+            nsCOMPtr<nsIXPConnectWrappedJS> wrapped = do_QueryInterface(is);
+            if (wrapped)
+            {
+                BDBLOG(("  Found XPConnect object\n"));
+                JSObject *js_obj = nsnull;
+                if (NS_SUCCEEDED(wrapped->GetJSObject(&js_obj)))
+                {
+                    // 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;
+                    BDBLOG(("    got nsIXPConnect\n"));
+
+                    // get the xpconnect native call context
+                    nsAXPCNativeCallContext *callContext = nsnull;
+                    xpc->GetCurrentNativeCallContext(&callContext);
+                    if(!callContext)
+                        return;
+
+                    // Get JSContext of current call
+                    JSContext* cx;
+                    rv = callContext->GetJSContext(&cx);
+                    if(NS_FAILED(rv) || !cx)
+                        return;
+                    BDBLOG(("    got JSContext\n"));
+
+                    jsval obj_as_jsval = OBJECT_TO_JSVAL(js_obj);
+
+                    // try to enumerate object properties
+                    JSIdArray *props = JS_Enumerate(cx, js_obj);
+                    if (props)
+                    {
+                        BDBLOG(("    got JSIdArray with %i props\n", props->length));
+                        
+                        // Start the array container
+                        DBusMessageIter childIter;
+                        DBusSignatureIter childSigIter;
+                        DBusSignatureIter dictSigIter;
+                        dbus_signature_iter_recurse(aSigIter, &childSigIter);
+                        dbus_message_iter_open_container(aIter, DBUS_TYPE_ARRAY,
+                            dbus_signature_iter_get_signature(&childSigIter),
+                            &childIter);
+
+                        // Skip the dict signature iter to the value type
+                        dbus_signature_iter_recurse(&childSigIter, &dictSigIter);
+                        dbus_signature_iter_next(&dictSigIter); // key type
+
+                        for (int p = 0; p < props->length; p++)
+                        {
+                            // get key signature from first property name
+                            jsval propname;
+                            nsCAutoString tmpsig;
+                            JS_IdToValue(cx, props->vector[p], &propname);
+
+                            // Start the dict container
+                            DBusMessageIter dictIter;
+                            dbus_message_iter_open_container(&childIter, DBUS_TYPE_DICT_ENTRY,
+                                                             NULL, &dictIter);
+
+                            JSString *prop_string = JS_ValueToString(cx, propname);
+                            const char *cstr = NS_ConvertUTF16toUTF8(JS_GetStringChars(prop_string),
+                                                               JS_GetStringLength(prop_string)).get();
+                            // TODO: we only use strings as keys currently, although
+                            // the spec allows any basic type to be a key and we
+                            // probably *could* use the property index.
+                            dbus_message_iter_append_basic(&dictIter,
+                                                           DBUS_TYPE_STRING,
+                                                           &cstr);
+
+                            jsval propvalue;
+                            if (JS_LookupUCProperty(cx,
+                                                    js_obj,
+                                                    JS_GetStringChars(prop_string),
+                                                    JS_GetStringLength(prop_string),
+                                                    &propvalue) == JS_TRUE)
+                            {
+                                addJSValueToIter(cx, &propvalue, &dictIter, &dictSigIter);
+                            }
+                            
+                            // Close the dict entry container
+                            dbus_message_iter_close_container(&childIter, &dictIter);
+                        }
+
+                        // Close the array container
+                        dbus_message_iter_close_container(aIter, &childIter);
+
+                        JS_DestroyIdArray(cx, props);
+                    }
+                }
+            }
+        } else {
+          BDBLOG(("  add array from variant\n"));
+
+            // need to recurse into array
+            PRUint16 type = 0;
+            nsIID iid;
+            PRUint32 count = 0;
+            void *data_ptr = nsnull;
+
+            DBusSignatureIter aChildSigIter;
+            dbus_signature_iter_recurse(aSigIter, &aChildSigIter);
+
+            char *array_signature = dbus_signature_iter_get_signature(&aChildSigIter);
+
+            aVariant->GetAsArray(&type,
+                                 &iid,
+                                 &count,
+                                 &data_ptr);
+
+            BDBLOG(("  getSignatureFromVariant: got %d elements of type %d\n", count, type));
+            BDBLOG(("  getSignatureFromVariant: got array signature %s\n", array_signature));
+
+            DBusMessageIter arrayIter;
+            if (dbus_message_iter_open_container(aIter, DBUS_TYPE_ARRAY,
+                                                 array_signature, &arrayIter))
+            {
+                addArrayDataToIter(data_ptr, count, type, &arrayIter, &aChildSigIter);
+                dbus_message_iter_close_container(aIter, &arrayIter);
+            }
+
+            nsMemory::Free(data_ptr);
+        }
+    }
+    else if (element_type == DBUS_TYPE_STRUCT)
+    {
+        BDBLOG(("  add struct from variant\n"));
+    }
+    else
+    {
+        BDBLOG(("  unhandled\n"));
+    }
+
+    dbus_free(element_signature);
+}
+
+static
+int is_valid_path (const char *path)
+{
+  const char *cur = path;
+  const char *prev = cur;
+  
+  if (strlen(path) == 0)
+    return FALSE;
+  
+  /* MUST begin with zero */
+  if (*cur++ != '/')
+    return FALSE;
+  
+  /* The path is guranteed to be null-terminated */
+  while (*cur != '\0')
+  {
+    /* Two slashes can't be together */
+    if (*cur == '/' && *prev == '/')
+    {
+      return FALSE;
+    } else if (!(((*cur) >= '0' && (*cur) <= '9') ||
+                 ((*cur) >= 'A' && (*cur) <= 'Z') ||
+                 ((*cur) >= 'a' && (*cur) <= 'z') ||
+                  (*cur) == '_' || (*cur) == '/')) {
+      return FALSE;
+    }
+    prev = cur;
+    cur++;
+  }
+  
+  return TRUE;
+}
+
+
+void addBasicTypeToIter(nsIVariant *aVariant, DBusMessageIter *aIter, int aDBusType)
+{
+
+    PRUint16 dataType;
+    aVariant->GetDataType(&dataType);
+
+    /* If we got passed an nsISupports, query the variant iface from it and recurse */
+    if (dataType == nsIDataType::VTYPE_INTERFACE_IS)
+    {
+        nsCOMPtr<nsISupports> is;
+        nsIID *iid;
+        if (NS_FAILED(aVariant->GetAsInterface(&iid, getter_AddRefs(is))))
+            return;
+
+        nsCOMPtr<nsIVariant> myVariant = do_QueryInterface(is);
+        if (myVariant)
+            addBasicTypeToIter(myVariant, aIter, aDBusType);
+
+        return;
+    }
+
+    switch (aDBusType)
+    {
+        case DBUS_TYPE_BOOLEAN:
+        {
+            PRBool val;
+            if (NS_FAILED(aVariant->GetAsBool(&val)))
+              return;
+            BDBLOG(("  arg       : BOOLEAN %s\n", val ? "true" : "false"));
+            dbus_message_iter_append_basic(aIter,
+                                           aDBusType,
+                                           &val);
+            break;
+        }
+        case DBUS_TYPE_BYTE:
+        case DBUS_TYPE_INT16:
+        case DBUS_TYPE_UINT16:
+        case DBUS_TYPE_INT32:
+        case DBUS_TYPE_UINT32:
+        {
+            PRUint32 val;
+            if (NS_FAILED(aVariant->GetAsUint32(&val)))
+              return;
+
+            BDBLOG(("  arg       : INT(8|16|32) (%c) %d:%d\n", aDBusType, dataType, val));
+            dbus_message_iter_append_basic(aIter,
+                                           aDBusType,
+                                           &val);
+            break;
+        }
+        case DBUS_TYPE_INT64:
+        {
+            PRInt64 val = 0;
+            if (NS_FAILED(aVariant->GetAsInt64(&val)))
+                return;
+            BDBLOG(("  arg       : INT64 %lld\n", val));
+            dbus_message_iter_append_basic(aIter,
+                                           aDBusType,
+                                           &val);
+            break;
+        }
+        case DBUS_TYPE_UINT64:
+        {
+            PRUint64 val;
+            if (NS_FAILED(aVariant->GetAsUint64(&val)))
+                return;
+            BDBLOG(("  arg       : UINT64 %llu\n", val));
+            dbus_message_iter_append_basic(aIter,
+                                           aDBusType,
+                                           &val);
+            break;
+        }
+        case DBUS_TYPE_DOUBLE:
+        {
+            double val;
+            if (NS_FAILED(aVariant->GetAsDouble(&val)))
+                return;
+            BDBLOG(("  arg       : DOUBLE (%c) %f\n", aDBusType, val));
+            dbus_message_iter_append_basic(aIter,
+                                           aDBusType,
+                                           &val);
+            break;
+        }
+        case DBUS_TYPE_STRING:
+        case DBUS_TYPE_OBJECT_PATH:
+        case DBUS_TYPE_SIGNATURE:
+        {
+            /* FIXME - handle utf-8 conversion */
+            nsCAutoString val;
+            const char *val_ptr;
+            if (NS_FAILED(aVariant->GetAsAUTF8String(val)))
+                return;
+
+            val_ptr = PromiseFlatCString(val).get();
+            BDBLOG(("  arg       : STRING '%s'\n", val_ptr));
+            if (aDBusType == DBUS_TYPE_OBJECT_PATH
+             && !is_valid_path(val_ptr))
+                return;
+
+            dbus_message_iter_append_basic(aIter, aDBusType, &val_ptr);
+            break;
+        }
+        default:
+        {
+            BDBLOG(("  addBasicTypeToIter: unhandled DBus type %d!\n", aDBusType));
+            break;
+        }
+    }
+}
+
+void addArrayDataToIter(void *data_ptr, PRUint32 count, PRUint16 type, DBusMessageIter *aIter, DBusSignatureIter *aSigIter)
+{
+    int aDBusType = dbus_signature_iter_get_current_type(aSigIter);
+    BDBLOG(("addArrayDataToIter: appending %d elements of type %d '%c'\n", count, type, aDBusType));
+
+    switch (type)
+    {
+#define ADD_DATA \
+            for (int i = 0; i < count; i++) \
+                dbus_message_iter_append_basic(aIter, aDBusType, data+i)
+        case nsIDataType::VTYPE_INT8:
+        case nsIDataType::VTYPE_UINT8:
+        {
+            char *data = (char *)data_ptr;
+            ADD_DATA;
+            break;
+        }
+        case nsIDataType::VTYPE_INT16:
+        case nsIDataType::VTYPE_UINT16:
+        {
+            PRInt16 *data = (PRInt16 *)data_ptr;
+            ADD_DATA;
+            break;
+        }
+        case nsIDataType::VTYPE_INT32:
+        case nsIDataType::VTYPE_UINT32:
+        {
+            PRInt32 *data = (PRInt32 *)data_ptr;
+            ADD_DATA;
+            break;
+        }
+        case nsIDataType::VTYPE_INT64:
+        case nsIDataType::VTYPE_UINT64:
+        {
+            PRInt64 *data = (PRInt64 *)data_ptr;
+            ADD_DATA;
+            break;
+        }
+        case nsIDataType::VTYPE_DOUBLE:
+        {
+            double *data = (double *)data_ptr;
+            ADD_DATA;
+            break;
+        }
+        case nsIDataType::VTYPE_WCHAR_STR:
+        {
+            PRUnichar **data = (PRUnichar **)data_ptr;
+            for (int i = 0; i < count; i++)
+            {
+                const char *val_ptr;
+                nsCAutoString val = NS_ConvertUTF16toUTF8(data[i]);
+
+                val_ptr = PromiseFlatCString(val).get();
+                BDBLOG(("  arg       : STRING '%s'\n", val_ptr));
+                if (aDBusType == DBUS_TYPE_OBJECT_PATH
+                 && !is_valid_path(val_ptr))
+                    return;
+
+                dbus_message_iter_append_basic(aIter, aDBusType, &val_ptr);
+            }
+            break;
+        }
+        case nsIDataType::VTYPE_INTERFACE_IS:
+        {
+            nsISupports **data = (nsISupports **)data_ptr;
+            for (int i = 0; i < count; i++)
+            {
+                nsCOMPtr<nsIVariant> data_variant = do_QueryInterface(data[i]);
+                if (data_variant)
+                    addVariantToIter(data_variant, aIter, aSigIter);
+                else
+                    BDBLOG(("  interface not nsIVariant\n"));
+            }
+            break;
+        }
+        default:
+        {
+            BDBLOG(("addArrayDataToIter: unhandled array data type %d\n", type));
+            break;
+        }
+#undef ADD_DATA
+    }
+}
+
+void
+addJSValueToIter(JSContext *cx, jsval *aValue, DBusMessageIter *aIter, DBusSignatureIter *aSigIter)
+{
+
+    int dbusType = dbus_signature_iter_get_current_type(aSigIter);
+
+    BDBLOG(("%s(%c, %s)\n", __FUNCTION__, dbusType,
+           dbus_signature_iter_get_signature(aSigIter)));
+
+    // Using the expected type instead of the actual allows autoconversion
+    switch (dbusType)
+    {
+        case DBUS_TYPE_BOOLEAN:
+        {
+            JSBool b = JS_FALSE;
+            if (JS_ValueToBoolean(cx, *aValue, &b))
+            {
+                dbus_message_iter_append_basic(aIter, DBUS_TYPE_BOOLEAN, &b);
+            }
+            else
+            {
+                BDBLOG(("%s(): Could not fetch boolean from jsvalue\n", __FUNCTION__));
+            }
+            
+            
+            break;
+        }
+        case DBUS_TYPE_BYTE:
+        case DBUS_TYPE_INT16:
+        case DBUS_TYPE_UINT16:
+        case DBUS_TYPE_INT32:
+        case DBUS_TYPE_UINT32:
+        case DBUS_TYPE_INT64:
+        case DBUS_TYPE_UINT64:
+        case DBUS_TYPE_DOUBLE:
+        {
+            jsdouble d = 0;
+            
+            if (JS_ValueToNumber(cx, *aValue, &d))
+            {
+                dbus_message_iter_append_basic(aIter, dbusType, &d);
+            }
+            else
+            {
+                BDBLOG(("%s(): Could not fetch boolean from jsvalue\n", __FUNCTION__));
+            }
+
+            break;
+        }
+        case DBUS_TYPE_STRING:
+        case DBUS_TYPE_OBJECT_PATH:
+        case DBUS_TYPE_SIGNATURE:
+        {
+            JSString *prop_string = JS_ValueToString(cx, *aValue);
+            const char *cstr = NS_ConvertUTF16toUTF8(JS_GetStringChars(prop_string),
+                                                     JS_GetStringLength(prop_string)).get();
+            dbus_message_iter_append_basic(aIter, dbusType, &cstr);
+            break;
+        }
+        case DBUS_TYPE_ARRAY:
+        {
+            if (JSVAL_IS_OBJECT(*aValue) && JS_IsArrayObject(cx, JSVAL_TO_OBJECT(*aValue)))
+            {
+                JSIdArray *props = JS_Enumerate(cx, JSVAL_TO_OBJECT(*aValue));
+                if (props)
+                {
+                    BDBLOG(("    got JSIdArray\n"));
+
+                    // Open container
+                    DBusSignatureIter arraySigIter;
+                    dbus_signature_iter_recurse(aSigIter, &arraySigIter);
+                    char *array_sig = dbus_signature_iter_get_signature(&arraySigIter);
+                    
+                    DBusMessageIter arrayIter;
+                    dbus_message_iter_open_container(aIter, DBUS_TYPE_ARRAY,
+                                                     array_sig, &arrayIter);
+                    dbus_free(array_sig);
+                    
+                    for (int p = 0; p < props->length; p++)
+                    {
+                        int type = dbus_signature_iter_get_current_type(&arraySigIter);
+                        jsval propname;
+                        JS_IdToValue(cx, props->vector[p], &propname);
+                        
+                        jsval propvalue;
+                        JSString *prop_string = JS_ValueToString(cx, propname);
+                        if (JS_LookupUCProperty(cx,
+                                                JSVAL_TO_OBJECT(*aValue),
+                                                JS_GetStringChars(prop_string),
+                                                JS_GetStringLength(prop_string),
+                                                &propvalue) == JS_TRUE)
+                        {
+                            addJSValueToIter(cx, &propvalue, &arrayIter, &arraySigIter);
+                        } else {
+                            break;
+                        }
+                        
+                        dbus_signature_iter_next(&arraySigIter);
+                    }
+                    
+                    dbus_message_iter_close_container(aIter, &arrayIter);
+                    JS_DestroyIdArray(cx, props);
+                }
+            }
+            
+            break;
+        }
+        default:
+            BDBLOG(("Don't know how to convert type '%c'\n", dbus_signature_iter_get_current_type(aSigIter)));
+            break;
+   }
+}
+
+void getJSValueFromIter(JSContext* cx, DBusMessageIter *aIter, int aDBusType, jsval *v)
+{
+
+    switch (aDBusType)
+    {
+        case DBUS_TYPE_STRING:
+        case DBUS_TYPE_OBJECT_PATH:
+        case DBUS_TYPE_SIGNATURE:
+        {
+            char *val = nsnull;
+            dbus_message_iter_get_basic(aIter, &val);
+            if (val != nsnull)
+            {
+                JSString *str = JS_NewStringCopyN(cx, val, strlen(val));
+                *v = STRING_TO_JSVAL(str);
+            }
+            break;
+        }
+        case DBUS_TYPE_BYTE:
+        case DBUS_TYPE_INT16:
+        case DBUS_TYPE_UINT16:
+        case DBUS_TYPE_INT32:
+        case DBUS_TYPE_UINT32:
+        case DBUS_TYPE_INT64:
+        case DBUS_TYPE_UINT64:
+        case DBUS_TYPE_DOUBLE:
+        {
+            dbus_uint64_t val = 0;
+            dbus_message_iter_get_basic(aIter, &val);
+            if (!JS_NewNumberValue(cx, (jsdouble)val, v))
+            {
+                printf("%s: Number conversion from %c failed\n", __FUNCTION__,
+                       aDBusType);
+            }
+            break;
+        }
+        case DBUS_TYPE_ARRAY:
+        {
+            // FIXME: implement!
+/*            
+            nsTArray<jsval> elems;
+            
+            // recurse to container
+            
+            // iterate over array elements
+            do
+            {
+                getJSValueFromIter
+                
+            } while (iter_next);
+
+            // Create an Array object with the elements
+            JSObject *array = JS_NewArrayObject(cx, 0, NULL);
+*/            
+            break;
+        }
+        case DBUS_TYPE_STRUCT:
+        default:
+        {
+            BDBLOG(("%s: Unhandled type %c\n", __FUNCTION__, aDBusType));
+        }
+    }
+
+    return;
+}
+
+already_AddRefed<nsIWritableVariant> getVariantFromIter(DBusMessageIter *aIter, int aDBusType)
+{
+    nsCOMPtr<nsIWritableVariant> variant = do_CreateInstance("@mozilla.org/variant;1");
+    nsIWritableVariant *retval;
+
+    switch (aDBusType)
+    {
+        case DBUS_TYPE_BOOLEAN:
+        {
+            PRUint32 val = 0;
+            BDBLOG(("    arg type BOOLEAN: "));
+            dbus_message_iter_get_basic(aIter, &val);
+            BDBLOG(("%d\n", val));
+            variant->SetAsBool(val);
+            break;
+        }
+
+        case DBUS_TYPE_BYTE:
+        case DBUS_TYPE_INT16:
+        case DBUS_TYPE_UINT16:
+        case DBUS_TYPE_INT32:
+        case DBUS_TYPE_UINT32:
+        {
+            PRUint32 val = 0;
+            BDBLOG(("    arg type INT: "));
+            dbus_message_iter_get_basic(aIter, &val);
+            BDBLOG(("%d\n", val));
+            variant->SetAsUint32(val);
+            break;
+        }
+        case DBUS_TYPE_INT64:
+        {
+            PRInt64 val;
+            BDBLOG(("    arg type INT64: "));
+            dbus_message_iter_get_basic(aIter, &val);
+            BDBLOG(("%lld\n", val));
+            variant->SetAsInt64(val);
+            break;
+        }
+        case DBUS_TYPE_UINT64:
+        {
+            PRUint64 val;
+            BDBLOG(("    arg type UINT64: "));
+            dbus_message_iter_get_basic(aIter, &val);
+            BDBLOG(("%llu\n", val));
+            variant->SetAsUint64(val);
+            break;
+        }
+        case DBUS_TYPE_DOUBLE:
+        {
+            double val;
+            BDBLOG(("    arg type DOUBLE: "));
+            dbus_message_iter_get_basic(aIter, &val);
+            BDBLOG(("%f\n", val));
+            variant->SetAsDouble(val);
+            break;
+        }
+        case DBUS_TYPE_STRING:
+        case DBUS_TYPE_OBJECT_PATH:
+        case DBUS_TYPE_SIGNATURE:
+        {
+            const char *tmp;
+            BDBLOG(("    arg type STRING/OBJECT_PATH/SIGNATURE: "));
+            dbus_message_iter_get_basic(aIter, &tmp);
+            nsDependentCString val(tmp);
+            BDBLOG(("\"%s\"\n", PromiseFlatCString(val).get()));
+            variant->SetAsAUTF8String(val);
+            break;
+        }
+        case DBUS_TYPE_ARRAY:
+        {
+            if (dbus_message_iter_get_element_type(aIter) == DBUS_TYPE_DICT_ENTRY)
+            {
+                BDBLOG(("    arg type ARRAY with DICT_ENTRY\n"));
+
+                // 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
+                // FIXME: this doesn't work for signals since there's no
+                // active context there...
+                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"));
+
+                // Construct a JS Object
+                JSObject *obj = JS_NewObject(cx, nsnull, nsnull, nsnull);
+                
+                // Set the properties
+                DBusMessageIter array_iter;
+                dbus_message_iter_recurse(aIter, &array_iter);
+                
+                do
+                {
+                    DBusMessageIter dict_iter;
+                    char *key = nsnull;
+                    dbus_message_iter_recurse(&array_iter, &dict_iter);
+                    dbus_message_iter_get_basic(&dict_iter, &key);
+                    BDBLOG(("    found key %s\n", key ? key : "null"));
+                    dbus_message_iter_next(&dict_iter);
+                    int value_type = dbus_message_iter_get_arg_type(&dict_iter);
+                    BDBLOG(("    found value type %c\n", value_type));
+                    jsval v;
+                    getJSValueFromIter(cx, &dict_iter, value_type, &v);
+                    JS_SetProperty(cx, obj, key, &v);
+                    
+                } while (dbus_message_iter_next(&array_iter));
+                
+                // Convert to variant and return
+                nsIVariant *var = nsnull;
+                nsresult rs = xpc->JSToVariant(cx, OBJECT_TO_JSVAL(obj), &var);
+                variant->SetFromVariant(var);
+                var = nsnull;
+                NS_ADDREF(retval = variant);
+                
+                return retval;
+            }
+            else
+            {
+        
+                DBusMessageIter array_iter;
+                nsCOMPtr<nsIMutableArray> items;
+                PRUint32 item_count;
+
+                BDBLOG(("    arg type ARRAY\n"));
+                dbus_message_iter_recurse(aIter, &array_iter);
+                items = getArrayFromIter(&array_iter);
+                items->GetLength(&item_count);
+                BDBLOG(("    array: %d items\n", item_count));
+
+                nsIVariant **item_array = new nsIVariant*[item_count];
+                for (int i = 0; i < item_count; i++)
+                {
+                    nsCOMPtr<nsIVariant> item = do_QueryElementAt(items, i);
+                    item_array[i] = item;
+                    NS_ADDREF(item);
+                }
+                variant->SetAsArray(nsIDataType::VTYPE_INTERFACE_IS,
+                                    &NS_GET_IID(nsIVariant),
+                                    item_count,
+                                    item_array);
+                for (int i = 0; i < item_count; i++)
+                    NS_RELEASE(item_array[i]);
+                delete[] item_array;
+            }
+            break;
+        }
+        default:
+        {
+            BDBLOG(("    arg type '%c' (%d)\n", aDBusType, aDBusType));
+            return nsnull;
+        }
+    }
+
+    NS_ADDREF(retval = variant);
+    return retval;
+}
+
+already_AddRefed<nsIMutableArray> getArrayFromIter(DBusMessageIter *aIter)
+{
+    int current_type;
+    nsCOMPtr<nsIMutableArray> array = do_CreateInstance("@mozilla.org/array;1");
+    nsIMutableArray *retval;
+
+    BDBLOG(("  ++ enter getArrayFromIter\n"));
+
+    while ((current_type = dbus_message_iter_get_arg_type(aIter)) != DBUS_TYPE_INVALID)
+    {
+        nsCOMPtr<nsIWritableVariant> variant = getVariantFromIter(aIter, current_type);
+        if (variant)
+            array->AppendElement(variant, PR_FALSE);
+        else
+            BDBLOG(("    arg type '%c' (%d) not handled\n", current_type, current_type));
+
+        dbus_message_iter_next(aIter);
+    }
+    NS_ADDREF(retval = array);
+    BDBLOG(("  ++ leave getArrayFromIter\n"));
+    return retval;
+}
+
+/* vim: set cindent ts=4 et sw=4: */
diff --git a/xpcom-dbusservice/DBusMarshaling.h b/xpcom-dbusservice/DBusMarshaling.h
new file mode 100644 (file)
index 0000000..8b96379
--- /dev/null
@@ -0,0 +1,60 @@
+/**
+ * Browser D-Bus Bridge, XPCOM version
+ *
+ * Copyright © 2008 Movial Creative Technologies Inc
+ *  Contact: Movial Creative Technologies Inc, <info@movial.com>
+ *  Authors: Lauri Mylläri, <lauri.myllari@movial.fi>
+ *           Kalle Vahlman, <kalle.vahlman@movial.com>
+ *
+ * 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 the Browser D-Bus Bridge, XPCOM version.
+ *
+ * The Initial Developer of the Original Code is Movial Creative Technologies
+ * Inc. Portions created by Initial Developer are Copyright (C) 2008
+ * Movial Creative Technologies Inc. All Rights Reserved.
+ *
+ */
+
+#ifndef __DBUSMARSHALING_H__
+#define __DBUSMARSHALING_H__
+
+#include <dbus/dbus.h>
+
+#include "nsIVariant.h"
+#include "nsIMutableArray.h"
+
+#include "jsapi.h"
+#include "jsarray.h"
+#include "jsobj.h"
+
+void getSignatureFromJSValue(JSContext *cx, jsval *aValue, nsCString &aResult);
+
+void getSignatureFromVariantType(PRUint16 aType, nsCString &aResult);
+
+void getSignatureFromVariant(nsIVariant *aVariant, nsCString &aResult);
+
+void getSignatureFromISupports(nsISupports *aISupports, nsCString &aResult);
+
+// --------------------------- OLD STUFF ---------------------------
+//
+int getDBusType(nsIVariant *aVariant);
+
+already_AddRefed<nsIMutableArray> getArrayFromIter(DBusMessageIter *aIter);
+
+already_AddRefed<nsIWritableVariant> getVariantFromIter(DBusMessageIter *aIter, int aDBusType);
+
+void addArrayToIter(nsIVariant *aVariant, DBusMessageIter *aIter, int aDBusType);
+
+void addVariantToIter(nsIVariant *aVariant, DBusMessageIter *aIter, DBusSignatureIter *aSigIter);
+void addBasicTypeToIter(nsIVariant *aVariant, DBusMessageIter *aIter, int aDBusType);
+
+#endif
diff --git a/xpcom-dbusservice/DBusMethod.cpp b/xpcom-dbusservice/DBusMethod.cpp
new file mode 100644 (file)
index 0000000..6fd0eaf
--- /dev/null
@@ -0,0 +1,326 @@
+/**
+ * Browser D-Bus Bridge, XPCOM version
+ *
+ * Copyright © 2008 Movial Creative Technologies Inc
+ *  Contact: Movial Creative Technologies Inc, <info@movial.com>
+ *  Authors: Lauri Mylläri, <lauri.myllari@movial.fi>
+ *           Kalle Vahlman, <kalle.vahlman@movial.com>
+ *
+ * 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 the Browser D-Bus Bridge, XPCOM version.
+ *
+ * The Initial Developer of the Original Code is Movial Creative Technologies
+ * Inc. Portions created by Initial Developer are Copyright (C) 2008
+ * Movial Creative Technologies Inc. All Rights Reserved.
+ *
+ */
+
+#include <stdio.h>
+#include <dbus/dbus.h>
+
+#include "nsComponentManagerUtils.h"
+#include "nsIMutableArray.h"
+#include "nsArrayUtils.h"
+#include "nsISupportsPrimitives.h"
+#include "nsIProperties.h"
+
+#include "IDBusService.h"
+#include "DBusMethod.h"
+#include "DBusMarshaling.h"
+
+#include "bdb-debug.h"
+
+//
+// helper declarations
+//
+
+static void DoCallBack(IDBusMethod *aCallback, DBusMessage *aReply);
+static void ReplyHandler(DBusPendingCall *pending, void *user_data);
+
+//
+// DBusMethod implementation
+//
+
+NS_IMPL_ISUPPORTS1(DBusMethod, IDBusMethod)
+
+DBusMethod::DBusMethod(DBusService *aDBusService,
+                       PRUint32 aBusType,
+                       const nsACString& aDestination,
+                       const nsACString& aObjectPath,
+                       const nsACString& aMethodName,
+                       const nsACString& aInterfaceName,
+                       const nsACString& aSignature) :
+    mDBusService(aDBusService),
+    mBusType(aBusType),
+    mDestination(aDestination),
+    mObject(aObjectPath),
+    mMethod(aMethodName),
+    mInterface(aInterfaceName),
+    mSignature(aSignature),
+    mAsync(PR_TRUE),
+    mCallback(nsnull),
+    mErrorCallback(nsnull)
+{
+    BDBLOG(("DBusMethod::DBusMethod()\n"));
+    BDBLOG(("  aBusType          : %d\n", aBusType));
+    BDBLOG(("  aDestination      : %s\n", PromiseFlatCString(aDestination).get()));
+    BDBLOG(("  aObjectPath       : %s\n", PromiseFlatCString(aObjectPath).get()));
+    BDBLOG(("  aMethodName       : %s\n", PromiseFlatCString(aMethodName).get()));
+    BDBLOG(("  aInterfaceName    : %s\n", PromiseFlatCString(aInterfaceName).get()));
+    BDBLOG(("  aSignature        : %s\n", PromiseFlatCString(aSignature).get()));
+
+}
+
+DBusMethod::~DBusMethod()
+{
+    BDBLOG(("DBusMethod::~DBusMethod()\n"));
+    if (mCallback)
+        NS_RELEASE(mCallback);
+    if (mErrorCallback)
+        NS_RELEASE(mErrorCallback);
+}
+
+NS_IMETHODIMP
+DBusMethod::GetAsync(PRBool *aAsync)
+{
+    *aAsync = mAsync;
+    return NS_OK;
+}
+
+NS_IMETHODIMP
+DBusMethod::SetAsync(PRBool aAsync)
+{
+    BDBLOG(("DBusMethod::SetAsync(%s)\n", aAsync ? "true" : "false"));
+    mAsync = aAsync;
+    return NS_OK;
+}
+
+NS_IMETHODIMP
+DBusMethod::GetOnReply(IDBusMethodCallback **aOnReply)
+{
+    *aOnReply = mCallback;
+    NS_IF_ADDREF(*aOnReply);
+    return NS_OK;
+}
+
+NS_IMETHODIMP
+DBusMethod::SetOnReply(IDBusMethodCallback *aOnReply)
+{
+    BDBLOG(("DBusMethod::SetOnReply(%08x)\n", aOnReply));
+    if (mCallback)
+        NS_RELEASE(mCallback);
+    mCallback = aOnReply;
+    NS_IF_ADDREF(mCallback);
+    return NS_OK;
+}
+
+NS_IMETHODIMP
+DBusMethod::GetOnError(IDBusMethodCallback **aOnError)
+{
+    *aOnError = mErrorCallback;
+    NS_IF_ADDREF(*aOnError);
+    return NS_OK;
+}
+
+NS_IMETHODIMP
+DBusMethod::SetOnError(IDBusMethodCallback *aOnError)
+{
+    BDBLOG(("DBusMethod::SetOnError(%08x)\n", aOnError));
+    if (mErrorCallback)
+        NS_RELEASE(mErrorCallback);
+    mErrorCallback = aOnError;
+    NS_IF_ADDREF(mErrorCallback);
+    return NS_OK;
+}
+
+static void
+ReplyHandler(DBusPendingCall *pending, void *user_data)
+{
+    DBusMessage *reply;
+    nsCOMPtr<IDBusMethod> method = (IDBusMethod *) user_data;
+
+    reply = dbus_pending_call_steal_reply(pending);
+    DoCallBack(method, reply);
+    dbus_message_unref(reply);
+}
+
+
+static void
+DoCallBack(IDBusMethod *aMethod, DBusMessage *aReply)
+{
+    DBusMessageIter iter;
+    int current_type;
+    nsCOMPtr<nsIMutableArray> reply_args;
+    nsCOMPtr<IDBusMethodCallback> callback;
+
+    int msg_type = dbus_message_get_type(aReply);
+
+    dbus_message_iter_init(aReply, &iter);
+
+    reply_args = getArrayFromIter(&iter);
+
+    switch (msg_type)
+    {
+        case DBUS_MESSAGE_TYPE_METHOD_RETURN:
+        {
+            BDBLOG(("  got method reply\n"));
+            aMethod->GetOnReply(getter_AddRefs(callback));
+            break;
+        }
+        case DBUS_MESSAGE_TYPE_ERROR:
+        {
+            BDBLOG(("  got an error message: %s\n", dbus_message_get_error_name(aReply)));
+            aMethod->GetOnError(getter_AddRefs(callback));
+
+            /* insert error name as first callback argument */
+            nsCOMPtr<nsIWritableVariant> error_name = do_CreateInstance("@mozilla.org/variant;1");
+            error_name->SetAsString(dbus_message_get_error_name(aReply));
+            reply_args->InsertElementAt(error_name, 0, PR_FALSE);
+
+            break;
+        }
+        default:
+        {
+            BDBLOG(("  got unhandled message of type %d\n", msg_type));
+            break;
+        }
+    }
+
+    PRUint32 reply_items;
+    reply_args->GetLength(&reply_items);
+    BDBLOG(("  reply_args: %d items\n", reply_items));
+
+    if (callback)
+    {
+        /* arguments are packed as an array into an nsIVariant */
+        nsIVariant **callback_args = new nsIVariant*[reply_items];
+        nsCOMPtr<nsIWritableVariant> args = do_CreateInstance("@mozilla.org/variant;1");
+        for (int i = 0; i < reply_items; i++)
+        {
+            nsCOMPtr<nsIVariant> arg = do_QueryElementAt(reply_args, i);
+            callback_args[i] = arg;
+            NS_ADDREF(arg);
+        }
+        args->SetAsArray(nsIDataType::VTYPE_INTERFACE_IS,
+                         &NS_GET_IID(nsIVariant),
+                         reply_items,
+                         callback_args);
+        for (int i = 0; i < reply_items; i++)
+            NS_RELEASE(callback_args[i]);
+        delete[] callback_args;
+        callback->OnReply(args);
+    }
+}
+
+NS_IMETHODIMP
+DBusMethod::DoCall(nsIVariant **aArgs, PRUint32 aCount)
+{
+    DBusMessage *msg;
+    DBusMessageIter msg_iter;
+    nsCAutoString signature;
+
+    BDBLOG(("DBusMethod::DoCall()\n"));
+    BDBLOG(("  aCount          : %d\n", aCount));
+
+    msg = dbus_message_new_method_call(PromiseFlatCString(mDestination).get(),
+                                       PromiseFlatCString(mObject).get(),
+                                       PromiseFlatCString(mInterface).get(),
+                                       PromiseFlatCString(mMethod).get());
+    dbus_message_iter_init_append(msg, &msg_iter);
+
+    if (mSignature.Equals(""))
+    {
+        // FIXME - is it necessary to clear the string?
+        signature.Assign("");
+        for (int i = 0; i < aCount; i++)
+        {
+            // no method signature specified, guess argument types
+            nsCOMPtr<nsIVariant> data = aArgs[i];
+            nsCAutoString tmpsig;
+
+            getSignatureFromVariant(data, tmpsig);
+            BDBLOG(("  aArgs[%02d]       : signature \"%s\"\n",
+                   i,
+                   PromiseFlatCString(tmpsig).get()));
+            signature.Append(tmpsig);
+
+        } /* for (int i = 0; i < aCount; i++) */
+    } /* if (mSignature.Equals("")) */
+    else
+    {
+        signature.Assign(mSignature);
+    }
+
+    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(aArgs[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()));
+        return NS_ERROR_ILLEGAL_VALUE;
+    }
+
+    DBusPendingCall *pending = mDBusService->SendWithReply(mBusType,
+                                                           msg,
+                                                           -1);
+    if (pending)
+    {
+        if (mAsync)
+        {
+            /* FIXME - do we need to AddRef "this" */
+            BDBLOG(("  do async reply callback\n"));
+            dbus_pending_call_set_notify(pending,
+                                         ReplyHandler,
+                                         this,
+                                         nsnull);
+        }
+        else
+        {
+            DBusMessage *reply;
+            BDBLOG(("  do sync reply callback\n"));
+            dbus_pending_call_block(pending);
+            reply = dbus_pending_call_steal_reply (pending);
+            dbus_pending_call_unref (pending);
+            DoCallBack(this, reply);
+            dbus_message_unref(reply);
+        }
+    }
+    else
+    {
+        return NS_ERROR_OUT_OF_MEMORY;
+    }
+
+    dbus_message_unref(msg);
+    return NS_OK;
+}
+
+
+/* vim: set cindent ts=4 et sw=4: */
diff --git a/xpcom-dbusservice/DBusMethod.h b/xpcom-dbusservice/DBusMethod.h
new file mode 100644 (file)
index 0000000..feb63a4
--- /dev/null
@@ -0,0 +1,81 @@
+/**
+ * Browser D-Bus Bridge, XPCOM version
+ *
+ * Copyright © 2008 Movial Creative Technologies Inc
+ *  Contact: Movial Creative Technologies Inc, <info@movial.com>
+ *  Authors: Lauri Mylläri, <lauri.myllari@movial.fi>
+ *
+ * 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 the Browser D-Bus Bridge, XPCOM version.
+ *
+ * The Initial Developer of the Original Code is Movial Creative Technologies
+ * Inc. Portions created by Initial Developer are Copyright (C) 2008
+ * Movial Creative Technologies Inc. All Rights Reserved.
+ *
+ */
+
+#ifndef __DBUSMETHOD_H__
+#define __DBUSMETHOD_H__
+
+#include "nsEmbedString.h"
+#include "nsIWeakReference.h"
+#include "nsIWeakReferenceUtils.h"
+#include "nsIVariant.h"
+
+#include "DBusService.h"
+
+//
+// DBusMethod declarations
+//
+
+#define DBUSMETHOD_CID \
+{ \
+    0x2832f621, \
+    0xad9b, \
+    0x4034, \
+    0x91, 0x0b, 0xcd, 0x8e, 0xea, 0xdf, 0x5c, 0x42 \
+}
+
+class DBusMethod : public IDBusMethod
+{
+public:
+    NS_DECL_ISUPPORTS
+    NS_DECL_IDBUSMETHOD
+
+    DBusMethod(DBusService *aDBusService,
+               PRUint32 aBusType,
+               const nsACString& aDestination,
+               const nsACString& aObjectPath,
+               const nsACString& aMethodName,
+               const nsACString& aInterfaceName,
+               const nsACString& aSignature);
+
+private:
+    ~DBusMethod();
+
+protected:
+    DBusService *mDBusService;
+    PRUint32    mBusType;
+    nsCString   mDestination;
+    nsCString   mObject;
+    nsCString   mInterface;
+    nsCString   mMethod;
+    nsCString   mSignature;
+    PRBool      mAsync;
+    IDBusMethodCallback *mCallback;
+    IDBusMethodCallback *mErrorCallback;
+};
+
+
+#endif /* __DBUSMETHOD_H__ */
+
+/* vim: set cindent ts=4 et sw=4: */
diff --git a/xpcom-dbusservice/DBusService.cpp b/xpcom-dbusservice/DBusService.cpp
new file mode 100644 (file)
index 0000000..3de68b5
--- /dev/null
@@ -0,0 +1,586 @@
+/**
+ * Browser D-Bus Bridge, XPCOM version
+ *
+ * Copyright © 2008 Movial Creative Technologies Inc
+ *  Contact: Movial Creative Technologies Inc, <info@movial.com>
+ *  Authors: Lauri Mylläri, <lauri.myllari@movial.fi>
+ *           Kalle Vahlman, <kalle.vahlman@movial.com>
+ *
+ * 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 the Browser D-Bus Bridge, XPCOM version.
+ *
+ * The Initial Developer of the Original Code is Movial Creative Technologies
+ * Inc. Portions created by Initial Developer are Copyright (C) 2008
+ * Movial Creative Technologies Inc. All Rights Reserved.
+ *
+ */
+
+#include <stdio.h>
+#include <glib.h>
+#include <dbus/dbus-glib-lowlevel.h>
+#include <dbus/dbus-glib.h>
+
+
+#include "nsIGenericFactory.h"
+#include "nsIInterfaceRequestorUtils.h"
+#include "nsComponentManagerUtils.h"
+
+#include "nsEmbedString.h"
+#include "nsIMutableArray.h"
+#include "nsArrayUtils.h"
+
+#include "IDBusService.h"
+
+#include "DBusService.h"
+#include "DBusMethod.h"
+#include "DBusSignal.h"
+#include "DBusMarshaling.h"
+
+#include "bdb-debug.h"
+
+//
+// DBusService implementation
+//
+
+static
+DBusHandlerResult _signal_filter(DBusConnection *connection,
+                                 DBusMessage *message,
+                                 void *user_data);
+
+static DBusService *gDBusService = nsnull;
+
+NS_IMPL_ISUPPORTS1(DBusService, IDBusService);
+
+DBusService::DBusService() :
+    mSystemBus(nsnull),
+    mSessionBus(nsnull),
+    mSystemBusHasFilter(PR_FALSE),
+    mSessionBusHasFilter(PR_FALSE)
+{
+    BDBLOG(("DBusService::DBusService()\n"));
+    mSystemBusSignalObservers.Init();
+    mSessionBusSignalObservers.Init();
+}
+
+DBusService::~DBusService()
+{
+    BDBLOG(("DBusService::~DBusService()\n"));
+    /* FIXME - check if connections need to be released */
+}
+
+NS_IMETHODIMP
+DBusService::GetSignal(PRUint32 aBusType,
+                       const nsACString& aInterfaceName,
+                       const nsACString& aSignalName,
+                       const nsACString& aSender,
+                       const nsACString& aObjectPath,
+                       IDBusSignal **_retval)
+{
+    nsClassHashtable<nsCStringHashKey, nsTArray<nsWeakPtr> > *signalObservers = nsnull;
+    *_retval = nsnull;
+
+    GetConnection(aBusType);
+
+    if (aBusType == SYSTEM)
+    {
+        if (!mSystemBusHasFilter)
+        {
+            signalObservers = &mSystemBusSignalObservers;
+            mSystemBusHasFilter = PR_TRUE;
+        }
+    }
+    else if (aBusType == SESSION)
+    {
+        if (!mSessionBusHasFilter)
+        {
+            signalObservers = &mSessionBusSignalObservers;
+            mSessionBusHasFilter = PR_TRUE;
+        }
+    }
+    else
+    {
+        BDBLOG(("DBusService::GetSignal(): unknown bus type %d\n", aBusType));
+        return NS_ERROR_ILLEGAL_VALUE;
+    }
+
+    /* add filter only once for each connection */
+    if (signalObservers)
+        dbus_connection_add_filter(GetConnection(aBusType),
+                                   _signal_filter,
+                                   signalObservers,
+                                   nsnull);
+
+    IDBusSignal *signal = new DBusSignal(this,
+                                         aBusType,
+                                         aInterfaceName,
+                                         aSignalName,
+                                         aSender,
+                                         aObjectPath);
+
+    NS_ENSURE_TRUE(signal, NS_ERROR_OUT_OF_MEMORY);
+
+    NS_ADDREF(*_retval = signal);
+
+    return NS_OK;
+}
+
+NS_IMETHODIMP
+DBusService::GetMethod(PRUint32 aBusType,
+                       const nsACString& aDestination,
+                       const nsACString& aObjectPath,
+                       const nsACString& aMethodName,
+                       const nsACString& aInterfaceName,
+                       const nsACString& aSignature,
+                       IDBusMethod **_retval)
+{
+    *_retval = nsnull;
+
+    if (!GetConnection(aBusType))
+    {
+        BDBLOG(("DBusService::GetMethod()): invalid bus type %d\n",
+               aBusType));
+        return NS_ERROR_ILLEGAL_VALUE;
+    }
+
+    if (!dbus_signature_validate(PromiseFlatCString(aSignature).get(), nsnull))
+    {
+        BDBLOG(("DBusService::GetMethod()): invalid method signature '%s'\n",
+               PromiseFlatCString(aSignature).get()));
+        return NS_ERROR_ILLEGAL_VALUE;
+    }
+
+    IDBusMethod *method = new DBusMethod(this,
+                                         aBusType,
+                                         aDestination,
+                                         aObjectPath,
+                                         aMethodName,
+                                         aInterfaceName,
+                                         aSignature);
+
+    NS_ENSURE_TRUE(method, NS_ERROR_OUT_OF_MEMORY);
+
+    NS_ADDREF(*_retval = method);
+
+    return NS_OK;
+}
+
+DBusPendingCall *DBusService::SendWithReply(PRUint32 aConnType,
+                                            DBusMessage *aMessage,
+                                            PRUint32 aTimeout)
+{
+    DBusPendingCall *retval = nsnull;
+    DBusConnection *conn = GetConnection(aConnType);
+
+    if (!conn)
+        return nsnull;
+
+    if (!dbus_connection_send_with_reply(conn,
+                                         aMessage,
+                                         &retval,
+                                         aTimeout))
+        return nsnull;
+
+    return retval;
+}
+
+DBusMessage *DBusService::SendWithReplyAndBlock(PRUint32 aConnType,
+                                                DBusMessage *aMessage,
+                                                PRUint32 aTimeout,
+                                                DBusError *aError)
+{
+    DBusConnection *conn = GetConnection(aConnType);
+
+    if (!conn)
+        return nsnull;
+
+    return dbus_connection_send_with_reply_and_block(conn,
+                                                     aMessage,
+                                                     aTimeout,
+                                                     aError);
+}
+
+static
+DBusHandlerResult _signal_filter(DBusConnection *connection,
+                                 DBusMessage *message,
+                                 void *user_data)
+{
+    if (dbus_message_get_type(message) != DBUS_MESSAGE_TYPE_SIGNAL)
+    {
+        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+    }
+
+    nsClassHashtable<nsCStringHashKey, nsTArray<nsWeakPtr> > *observerHash =
+        (nsClassHashtable<nsCStringHashKey, nsTArray<nsWeakPtr> > *) user_data;
+
+    printf("_signal_filter: %s.%s\n",
+           dbus_message_get_interface(message),
+           dbus_message_get_member(message));
+
+    nsCAutoString observerKey;
+
+    observerKey.Assign(dbus_message_get_interface(message));
+    observerKey.Append(NS_LITERAL_CSTRING("."));
+    observerKey.Append(dbus_message_get_member(message));
+
+    printf("  observerKey: '%s'\n",
+           PromiseFlatCString(observerKey).get());
+
+    nsTArray<nsWeakPtr> *observerList = nsnull;
+
+    observerHash->Get(observerKey, &observerList);
+    if (observerList)
+    {
+        BDBLOG(("  got observerList\n"));
+        DBusService *service = DBusService::GetSingleton();
+        
+        for (PRInt32 i = 0; i < observerList->Length(); ++i) {
+            nsCAutoString t;
+            nsCOMPtr<IDBusSignal> signal = do_QueryReferent((*observerList)[i]);
+            signal->GetInterfaceName(t);
+            BDBLOG(("    interface : %s\n", PromiseFlatCString(t).get()));
+            signal->GetSignalName(t);
+            BDBLOG(("    signal    : %s\n", PromiseFlatCString(t).get()));
+            signal->GetSender(t);
+            BDBLOG(("    sender    : %s\n", PromiseFlatCString(t).get()));
+            if (!t.IsEmpty() && !t.Equals(dbus_message_get_sender(message)))
+            {
+                BDBLOG(("    sender does not match\n"));
+                break;
+            }
+            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;
+            }
+
+            /* do callback */
+
+            DBusMessageIter iter;
+            nsCOMPtr<nsIMutableArray> args_array;
+
+            dbus_message_iter_init(message, &iter);
+            args_array = getArrayFromIter(&iter);
+
+            PRUint32 arg_items;
+            args_array->GetLength(&arg_items);
+            BDBLOG(("  arg_items: %d items\n", arg_items));
+
+            /* 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++)
+            {
+                nsCOMPtr<nsIVariant> arg = do_QueryElementAt(args_array, i);
+                callback_args[i] = arg;
+                NS_ADDREF(arg);
+            }
+            args->SetAsArray(nsIDataType::VTYPE_INTERFACE_IS,
+                             &NS_GET_IID(nsIVariant),
+                             arg_items,
+                             callback_args);
+            for (int i = 0; i < arg_items; i++)
+                NS_RELEASE(callback_args[i]);
+            delete[] callback_args;
+
+            nsCOMPtr<IDBusSignalObserver> callback;
+            signal->GetOnEmit(getter_AddRefs(callback));
+
+            service->SetInsideEmit(TRUE);
+            callback->OnSignal(args);
+            service->SetInsideEmit(FALSE);
+
+        }
+        
+        /* Check if we have queued observer changes */
+        service->CheckSignalObserverQueue();
+        
+        return DBUS_HANDLER_RESULT_HANDLED;
+    }
+    else
+    {
+        BDBLOG(("  no observer found\n"));
+        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+    }
+}
+
+static
+void BuildRule(IDBusSignal *aSignal, nsACString& aRetval)
+{
+    nsCAutoString tmp;
+
+    aRetval.Assign(NS_LITERAL_CSTRING("type='signal',interface='"));
+    aSignal->GetInterfaceName(tmp);
+    aRetval.Append(tmp);
+    aRetval.Append(NS_LITERAL_CSTRING("',member='"));
+    aSignal->GetSignalName(tmp);
+    aRetval.Append(tmp);
+    aRetval.Append(NS_LITERAL_CSTRING("'"));
+}
+
+void DBusService::CheckSignalObserverQueue()
+{
+    BDBLOG((__FUNCTION__));
+
+    PRUint32 i = mRemovedSignals.Length();
+    while (i-- > 0)
+    {
+        RemoveSignalObserver(mRemovedSignals[i]);
+        mRemovedSignals.RemoveElementAt(i);
+    }
+    i = mAddedSignals.Length();
+    while (i-- > 0)
+    {
+        AddSignalObserver(mAddedSignals[i]);
+        mAddedSignals.RemoveElementAt(i);
+    }
+}
+
+void DBusService::AddSignalObserver(IDBusSignal *aSignal)
+{
+    nsClassHashtable<nsCStringHashKey, nsTArray<nsWeakPtr> > *signalObservers = nsnull;
+    nsCAutoString observerKey;
+    nsCAutoString tmp;
+
+    if (mInsideEmit)
+    {
+        mAddedSignals.AppendElement(aSignal);
+        return;
+    }
+
+    BDBLOG(("DBusService::AddSignalObserver()\n"));
+
+    aSignal->GetInterfaceName(tmp);
+    BDBLOG(("  aInterface : %s\n", PromiseFlatCString(tmp).get()));
+    observerKey.Assign(tmp);
+    observerKey.Append(".");
+
+    aSignal->GetSignalName(tmp);
+    BDBLOG(("  aSignal    : %s\n", PromiseFlatCString(tmp).get()));
+    observerKey.Append(tmp);
+
+    BDBLOG(("  observerKey: %s\n", PromiseFlatCString(observerKey).get()));
+
+    nsTArray<nsWeakPtr> *observerList = nsnull;
+
+    PRUint32 bus_type = 0;
+    aSignal->GetBusType(&bus_type);
+    if (bus_type == SYSTEM)
+        signalObservers = &mSystemBusSignalObservers;
+    else if (bus_type == SESSION)
+        signalObservers = &mSessionBusSignalObservers;
+    signalObservers->Get(observerKey, &observerList);
+    if (observerList)
+    {
+        /* append to list */
+        BDBLOG(("  got observerList\n"));
+        nsCOMPtr<nsISupportsWeakReference> weakRefable = do_QueryInterface(aSignal);
+        nsWeakPtr weakPtr = getter_AddRefs(NS_GetWeakReference(weakRefable));
+        observerList->AppendElement(weakPtr);
+    }
+    else
+    {
+        /* create a new list */
+        BDBLOG(("  no observerList found\n"));
+        observerList = new nsTArray<nsWeakPtr>;
+        nsCOMPtr<nsISupportsWeakReference> weakRefable = do_QueryInterface(aSignal);
+        nsWeakPtr weakPtr = getter_AddRefs(NS_GetWeakReference(weakRefable));
+        observerList->AppendElement(weakPtr);
+        signalObservers->Put(observerKey, observerList);
+        
+        /* add match rule for interface.signal */
+        PRUint32 busType;
+        nsCAutoString matchRule;
+
+        aSignal->GetBusType(&busType);
+        BuildRule(aSignal, matchRule);
+        BDBLOG(("  new match rule: %s\n", PromiseFlatCString(matchRule).get()));
+        dbus_bus_add_match(GetConnection(busType),
+                           PromiseFlatCString(matchRule).get(),
+                           nsnull);
+    }
+}
+
+void DBusService::RemoveSignalObserver(IDBusSignal *aSignal)
+{
+    nsClassHashtable<nsCStringHashKey, nsTArray<nsWeakPtr> > *signalObservers = nsnull;
+    nsCAutoString observerKey;
+    nsCAutoString tmp;
+
+    if (mInsideEmit)
+    {
+        mRemovedSignals.AppendElement(aSignal);
+        return;
+    }
+
+    BDBLOG(("DBusService::RemoveSignalObserver()\n"));
+
+    aSignal->GetInterfaceName(tmp);
+    BDBLOG(("  aInterface : %s\n", PromiseFlatCString(tmp).get()));
+    observerKey.Assign(tmp);
+    observerKey.Append(".");
+
+    aSignal->GetSignalName(tmp);
+    BDBLOG(("  aSignal    : %s\n", PromiseFlatCString(tmp).get()));
+    observerKey.Append(tmp);
+
+    BDBLOG(("  observerKey: %s\n", PromiseFlatCString(observerKey).get()));
+
+    nsTArray<nsWeakPtr> *observerList = nsnull;
+
+    PRUint32 bus_type = 0;
+    aSignal->GetBusType(&bus_type);
+    if (bus_type == SYSTEM)
+        signalObservers = &mSystemBusSignalObservers;
+    else if (bus_type == SESSION)
+        signalObservers = &mSessionBusSignalObservers;
+    signalObservers->Get(observerKey, &observerList);
+    if (observerList)
+    {
+        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) {
+            nsCAutoString t;
+            nsCAutoString ob;
+            nsCOMPtr<IDBusSignal> signal = do_QueryReferent((*observerList)[i]);
+            signal->GetInterfaceName(t);
+            ob.Assign(t);
+            ob.Append(".");
+            signal->GetSignalName(t);
+            ob.Append(t);
+            BDBLOG(("    signal : %s\n", PromiseFlatCString(ob).get()));
+        }
+        BDBLOG(("  call observerList->RemoveElement\n"));
+        observerList->RemoveElement(weakPtr);
+        for (PRInt32 i = 0; i < observerList->Length(); ++i) {
+            nsCAutoString t;
+            nsCAutoString ob;
+            nsCOMPtr<IDBusSignal> signal = do_QueryReferent((*observerList)[i]);
+            signal->GetInterfaceName(t);
+            ob.Assign(t);
+            ob.Append(".");
+            signal->GetSignalName(t);
+            ob.Append(t);
+            BDBLOG(("    signal : %s\n", PromiseFlatCString(ob).get()));
+        }
+
+        // if list is empty, remove match rule
+        if (observerList->Length() == 0)
+        {
+            PRUint32 busType;
+            nsCAutoString matchRule;
+
+            aSignal->GetBusType(&busType);
+            BuildRule(aSignal, matchRule);
+            BDBLOG(("  remove match rule: %s\n", PromiseFlatCString(matchRule).get()));
+            dbus_bus_remove_match(GetConnection(busType),
+                                  PromiseFlatCString(matchRule).get(),
+                                  nsnull);
+            signalObservers->Remove(observerKey); 
+        }
+        BDBLOG(("  done\n"));
+    }
+    else
+    {
+        BDBLOG(("  ERROR: no observerList found!\n"));
+    }
+}
+
+DBusConnection *DBusService::GetConnection(PRUint32 aConnType)
+{
+    BDBLOG(("DBusService::GetConnection(%d)\n", aConnType));
+
+    if (aConnType == SYSTEM)
+    {
+        if (mSystemBus == nsnull)
+        {
+            mSystemBus = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
+            if (!mSystemBus)
+                return nsnull;
+            dbus_connection_set_exit_on_disconnect(mSystemBus, PR_FALSE);
+            dbus_connection_setup_with_g_main(mSystemBus, NULL);
+        }
+        return mSystemBus;
+    }
+    else if (aConnType == SESSION)
+    {
+        if (mSessionBus == nsnull)
+        {
+            mSessionBus = dbus_bus_get(DBUS_BUS_SESSION, NULL);
+            if (!mSessionBus)
+                return nsnull;
+            dbus_connection_set_exit_on_disconnect(mSessionBus, PR_FALSE);
+            dbus_connection_setup_with_g_main(mSessionBus, NULL);
+        }
+        return mSessionBus;
+    }
+    return nsnull;
+}
+
+DBusService *
+DBusService::GetSingleton()
+{
+    BDBLOG(("DBusService::GetSingleton() called: "));
+
+    if (!gDBusService)
+    {
+        BDBLOG(("creating new DBusService\n"));
+        gDBusService = new DBusService();
+    }
+
+    if (gDBusService)
+    {
+        BDBLOG(("adding reference to existing DBusService\n"));
+        NS_ADDREF(gDBusService);
+    }
+
+    return gDBusService;
+}
+
+
+
+//
+// Module implementation
+//
+
+NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(DBusService, DBusService::GetSingleton);
+
+static const nsModuleComponentInfo components[] =
+{
+    {
+        "DBus service",
+        DBUSSERVICE_CID,
+        "@movial.fi/dbus/service;1",
+        DBusServiceConstructor
+    },
+    {
+        "DBus method",
+        DBUSMETHOD_CID,
+        "@movial.fi/dbus/method;1",
+        nsnull
+    },
+    {
+        "DBus signal",
+        DBUSSIGNAL_CID,
+        "@movial.fi/dbus/signal;1",
+        nsnull
+    }
+};
+
+NS_IMPL_NSGETMODULE(nsDBusServiceModule, components);
+
+
+
+
+/* vim: set cindent ts=4 et sw=4: */
diff --git a/xpcom-dbusservice/DBusService.h b/xpcom-dbusservice/DBusService.h
new file mode 100644 (file)
index 0000000..a0619ce
--- /dev/null
@@ -0,0 +1,98 @@
+/**
+ * Browser D-Bus Bridge, XPCOM version
+ *
+ * Copyright © 2008 Movial Creative Technologies Inc
+ *  Contact: Movial Creative Technologies Inc, <info@movial.com>
+ *  Authors: Lauri Mylläri, <lauri.myllari@movial.fi>
+ *           Kalle Vahlman, <kalle.vahlman@movial.com>
+ *
+ * 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 the Browser D-Bus Bridge, XPCOM version.
+ *
+ * The Initial Developer of the Original Code is Movial Creative Technologies
+ * Inc. Portions created by Initial Developer are Copyright (C) 2008
+ * Movial Creative Technologies Inc. All Rights Reserved.
+ *
+ */
+
+#ifndef __DBUSSERVICE_H__
+#define __DBUSSERVICE_H__
+
+#include <dbus/dbus-glib-lowlevel.h>
+
+#include "nsTArray.h"
+#include "nsCOMArray.h"
+#include "nsIWeakReference.h"
+#include "nsIWeakReferenceUtils.h"
+
+typedef PRUint8 uint8; /* otherwise pldhash.h:199 is sad */
+#include "nsClassHashtable.h"
+
+//
+// DBusService declarations
+//
+
+#define DBUSSERVICE_CID \
+{ \
+    0xe3b49db1, \
+    0x5754, \
+    0x4330, \
+    0x92, 0xcd, 0xab, 0xe8, 0xf7, 0xea, 0x54, 0x3d \
+}
+
+class DBusService : public IDBusService
+{
+public:
+    NS_DECL_ISUPPORTS
+    NS_DECL_IDBUSSERVICE
+
+    static DBusService *GetSingleton();
+
+    DBusService();
+
+    DBusMessage *SendWithReplyAndBlock(PRUint32 aConnType,
+                                       DBusMessage *aMessage,
+                                       PRUint32 aTimeout,
+                                       DBusError *aError);
+    DBusPendingCall *SendWithReply(PRUint32 aConnType,
+                                   DBusMessage *aMessage,
+                                   PRUint32 aTimeout);
+    void AddSignalObserver(IDBusSignal *aSignal);
+    void RemoveSignalObserver(IDBusSignal *aSignal);
+    
+    void SetInsideEmit(PRBool inside) { mInsideEmit = inside; };
+    void CheckSignalObserverQueue();
+    
+private:
+    ~DBusService();
+
+    DBusConnection *GetConnection(PRUint32 aConnType);
+
+    DBusConnection *mSystemBus;
+    DBusConnection *mSessionBus;
+
+    nsClassHashtable<nsCStringHashKey, nsTArray<nsWeakPtr> > mSystemBusSignalObservers;
+    nsClassHashtable<nsCStringHashKey, nsTArray<nsWeakPtr> > mSessionBusSignalObservers;
+    PRBool mSystemBusHasFilter;
+    PRBool mSessionBusHasFilter;
+    
+    /* We need to queue changes to signal observers within onemit callbacks
+     * so that we don't alter the list while iterating over it...
+     */
+    PRBool mInsideEmit;
+    nsTArray<IDBusSignal*> mRemovedSignals;
+    nsTArray<IDBusSignal*> mAddedSignals;
+};
+
+#endif /* __DBUSSERVICE_H__ */
+
+/* vim: set cindent ts=4 et sw=4: */
diff --git a/xpcom-dbusservice/DBusSignal.cpp b/xpcom-dbusservice/DBusSignal.cpp
new file mode 100644 (file)
index 0000000..6ec5b97
--- /dev/null
@@ -0,0 +1,183 @@
+/**
+ * Browser D-Bus Bridge, XPCOM version
+ *
+ * Copyright © 2008 Movial Creative Technologies Inc
+ *  Contact: Movial Creative Technologies Inc, <info@movial.com>
+ *  Authors: Lauri Mylläri, <lauri.myllari@movial.fi>
+ *           Kalle Vahlman, <kalle.vahlman@movial.com>
+ *
+ * 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 the Browser D-Bus Bridge, XPCOM version.
+ *
+ * The Initial Developer of the Original Code is Movial Creative Technologies
+ * Inc. Portions created by Initial Developer are Copyright (C) 2008
+ * Movial Creative Technologies Inc. All Rights Reserved.
+ *
+ */
+
+#include <stdio.h>
+
+#include "IDBusService.h"
+
+#include "DBusSignal.h"
+
+#include "bdb-debug.h"
+
+
+//
+// DBusSignal implementation
+//
+
+NS_IMPL_ISUPPORTS2(DBusSignal, IDBusSignal, nsISupportsWeakReference)
+
+DBusSignal::DBusSignal(DBusService *aDBusService,
+                       PRUint32 aBusType,
+                       const nsACString& aInterface,
+                       const nsACString& aSignal,
+                       const nsACString& aSender,
+                       const nsACString& aObject) :
+    mDBusService(aDBusService),
+    mBusType(aBusType),
+    mInterface(aInterface),
+    mSignal(aSignal),
+    mSender(aSender),
+    mObject(aObject),
+    mCallback(0),
+    mEnabled(PR_FALSE),
+    mFilterActive(PR_FALSE)
+{
+    BDBLOG(("DBusSignal::DBusSignal()\n"));
+    BDBLOG(("  mBusType   : %d\n", mBusType));
+    BDBLOG(("  aInterface : %s\n", PromiseFlatCString(aInterface).get()));
+    BDBLOG(("  aSignal    : %s\n", PromiseFlatCString(aSignal).get()));
+    BDBLOG(("  aSender    : %s\n", PromiseFlatCString(aSender).get()));
+    BDBLOG(("  aObject    : %s\n", PromiseFlatCString(aObject).get()));
+    BDBLOG(("  mEnabled   : %d\n", mEnabled));
+}
+
+DBusSignal::~DBusSignal()
+{
+    BDBLOG(("DBusSignal::~DBusSignal()\n"));
+    if (mFilterActive)
+        filterDisable();
+    if (mCallback)
+        NS_RELEASE(mCallback);
+}
+
+NS_IMETHODIMP
+DBusSignal::GetOnEmit(IDBusSignalObserver **aCallback)
+{
+    BDBLOG(("DBusSignal::GetOnEmit()\n"));
+    NS_IF_ADDREF(*aCallback = mCallback);
+    return NS_OK;
+}
+
+NS_IMETHODIMP
+DBusSignal::SetOnEmit(IDBusSignalObserver *aCallback)
+{
+    BDBLOG(("DBusSignal::SetOnEmit(%08x)\n", aCallback));
+    if (mCallback)
+    {
+        if (mFilterActive)
+            filterDisable();
+        NS_RELEASE(mCallback);
+    }
+    mCallback = aCallback;
+    NS_IF_ADDREF(mCallback);
+    if (mEnabled && mCallback)
+        filterEnable();
+    return NS_OK;
+}
+
+NS_IMETHODIMP
+DBusSignal::GetEnabled(PRBool *aEnabled)
+{
+    BDBLOG(("DBusSignal::GetEnabled()\n"));
+    *aEnabled = mEnabled;
+    return NS_OK;
+}
+
+NS_IMETHODIMP
+DBusSignal::SetEnabled(PRBool aEnabled)
+{
+    BDBLOG(("DBusSignal::SetEnabled(%s)\n", aEnabled ? "PR_TRUE" : "PR_FALSE"));
+
+    if (aEnabled && !mCallback)
+    {
+        BDBLOG(("  ERROR: trying to enable with no onEmit set!\n"));
+        return NS_ERROR_NOT_AVAILABLE;
+    }
+
+    /* change filter state if necessary */
+    if (mFilterActive && !aEnabled)
+        filterDisable();
+    if (!mFilterActive && aEnabled && mCallback)
+        filterEnable();
+
+    mEnabled = aEnabled;
+
+}
+
+NS_IMETHODIMP
+DBusSignal::GetBusType(PRUint32 *aBusType)
+{
+    *aBusType = mBusType;
+    return NS_OK;
+}
+
+NS_IMETHODIMP
+DBusSignal::GetInterfaceName(nsACString& aInterface)
+{
+    aInterface.Assign(mInterface);
+    return NS_OK;
+}
+
+NS_IMETHODIMP
+DBusSignal::GetSignalName(nsACString& aSignal)
+{
+    aSignal.Assign(mSignal);
+    return NS_OK;
+}
+
+NS_IMETHODIMP
+DBusSignal::GetSender(nsACString& aSender)
+{
+    aSender.Assign(mSender);
+    return NS_OK;
+}
+
+NS_IMETHODIMP
+DBusSignal::GetObjectPath(nsACString& aObject)
+{
+    aObject.Assign(mObject);
+    return NS_OK;
+}
+
+void
+DBusSignal::filterEnable()
+{
+    BDBLOG(("DBusSignal::filterEnable()\n"));
+    mFilterActive = PR_TRUE;
+
+    mDBusService->AddSignalObserver(this);
+}
+
+void
+DBusSignal::filterDisable()
+{
+    BDBLOG(("DBusSignal::filterDisable()\n"));
+    mFilterActive = PR_FALSE;
+    
+    mDBusService->RemoveSignalObserver(this);
+}
+
+/* vim: set cindent ts=4 et sw=4: */
diff --git a/xpcom-dbusservice/DBusSignal.h b/xpcom-dbusservice/DBusSignal.h
new file mode 100644 (file)
index 0000000..e60e7d2
--- /dev/null
@@ -0,0 +1,80 @@
+/**
+ * Browser D-Bus Bridge, XPCOM version
+ *
+ * Copyright © 2008 Movial Creative Technologies Inc
+ *  Contact: Movial Creative Technologies Inc, <info@movial.com>
+ *  Authors: Lauri Mylläri, <lauri.myllari@movial.fi>
+ *
+ * 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 the Browser D-Bus Bridge, XPCOM version.
+ *
+ * The Initial Developer of the Original Code is Movial Creative Technologies
+ * Inc. Portions created by Initial Developer are Copyright (C) 2008
+ * Movial Creative Technologies Inc. All Rights Reserved.
+ *
+ */
+
+#ifndef __DBUSSIGNAL_H__
+#define __DBUSSIGNAL_H__
+
+#include "nsEmbedString.h"
+#include "nsWeakReference.h"
+
+#include "DBusService.h"
+
+//
+// DBusSignal declarations
+//
+
+#define DBUSSIGNAL_CID \
+{ \
+    0xde515b88, \
+    0xb8a0, \
+    0x416e, \
+    0xb4, 0x38, 0x52, 0x4e, 0xf7, 0x96, 0xfb, 0x13 \
+}
+
+class DBusSignal : public IDBusSignal, public nsSupportsWeakReference
+{
+public:
+    NS_DECL_ISUPPORTS
+    NS_DECL_IDBUSSIGNAL
+
+    DBusSignal(DBusService *aDBusService,
+               PRUint32 aBusType,
+               const nsACString& aInterface,
+               const nsACString& aSignal,
+               const nsACString& aSender,
+               const nsACString& aObject);
+
+private:
+    ~DBusSignal();
+
+    void filterEnable();
+    void filterDisable();
+
+protected:
+    DBusService *mDBusService;
+    PRUint32 mBusType;
+    const nsCString mInterface;
+    const nsCString mSignal;
+    const nsCString mSender;
+    const nsCString mObject;
+    IDBusSignalObserver *mCallback;
+    PRBool mEnabled;
+    PRBool mFilterActive;
+};
+
+
+#endif /* __DBUSSIGNAL_H__ */
+
+/* vim: set cindent ts=4 et sw=4: */
diff --git a/xpcom-dbusservice/IDBusService.idl b/xpcom-dbusservice/IDBusService.idl
new file mode 100644 (file)
index 0000000..4289f30
--- /dev/null
@@ -0,0 +1,91 @@
+/**
+ * Browser D-Bus Bridge, XPCOM version
+ *
+ * Copyright © 2008 Movial Creative Technologies Inc
+ *  Contact: Movial Creative Technologies Inc, <info@movial.com>
+ *  Authors: Lauri Mylläri, <lauri.myllari@movial.fi>
+ *
+ * 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 the Browser D-Bus Bridge, XPCOM version.
+ *
+ * The Initial Developer of the Original Code is Movial Creative Technologies
+ * Inc. Portions created by Initial Developer are Copyright (C) 2008
+ * Movial Creative Technologies Inc. All Rights Reserved.
+ *
+ */
+
+#include "nsISupports.idl"
+#include "nsIWeakReference.idl"
+#include "nsIVariant.idl"
+#include "nsIArray.idl"
+
+[function, scriptable, uuid(8eeddd8d-6e82-438a-9451-753f92bef2db)]
+interface IDBusMethodCallback : nsISupports
+{
+        void onReply(in nsIVariant args);
+};
+
+[scriptable, uuid(71fd21e1-ca1b-4d42-9435-a32382532820)]
+interface IDBusMethod : nsISupports
+{
+        attribute boolean async;
+        attribute IDBusMethodCallback onReply;
+        attribute IDBusMethodCallback onError;
+
+        void doCall([array, size_is(count)] in nsIVariant args,
+                    in PRUint32 count);
+};
+
+[function, scriptable, uuid(0f87e70b-af7b-44c0-b0a3-1df8e3fa66da)]
+interface IDBusSignalObserver : nsISupports
+{
+        void onSignal(in nsIVariant args);
+                      
+};
+
+[scriptable, uuid(d8107805-9980-46ed-bccf-f3e6ac9fe989)]
+interface IDBusSignal : nsISupports
+{
+        attribute IDBusSignalObserver onEmit;
+        attribute boolean enabled;
+
+        readonly attribute PRUint32 busType;
+        readonly attribute ACString interfaceName;
+        readonly attribute ACString signalName;
+        readonly attribute ACString sender;
+        readonly attribute ACString objectPath;
+};
+
+[scriptable, uuid(084b9397-0d6b-4c2c-93f9-f929f6b6e9e7)]
+interface IDBusService : nsISupports
+{
+        const PRUint32 SYSTEM = 0;
+        const PRUint32 SESSION = 1;
+
+        IDBusSignal getSignal(in PRUint32 busType,
+                              in ACString interfaceName,
+                              in ACString signalName,
+                              in ACString sender,
+                              in ACString objectPath);
+
+        IDBusMethod getMethod(in PRUint32 busType,
+                              in ACString destination,
+                              in ACString objectPath,
+                              in ACString methodName,
+                              in ACString interfaceName,
+                              in ACString signature);
+
+};
+
+
+
+/* vim: set cindent ts=8 et sw=8: */
diff --git a/xpcom-dbusservice/bdb-debug.h b/xpcom-dbusservice/bdb-debug.h
new file mode 100644 (file)
index 0000000..cf667a6
--- /dev/null
@@ -0,0 +1,35 @@
+/**
+ * Browser D-Bus Bridge, XPCOM version
+ *
+ * Copyright © 2008 Movial Creative Technologies Inc
+ *  Contact: Movial Creative Technologies Inc, <info@movial.com>
+ *  Authors: Kalle Vahlman, <kalle.vahlman@movial.com>
+ *
+ * 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 the Browser D-Bus Bridge, XPCOM version.
+ *
+ * The Initial Developer of the Original Code is Movial Creative Technologies
+ * Inc. Portions created by Initial Developer are Copyright (C) 2008
+ * Movial Creative Technologies Inc. All Rights Reserved.
+ *
+ */
+
+#ifndef __BDB_DEBUG_H__
+#define __BDB_DEBUG_H__
+
+#ifdef DEBUG
+# define BDBLOG(x) printf x
+#else
+# define BDBLOG(x)
+#endif
+
+#endif // __BDB_DEBUG_H__
diff --git a/xpcom-dbusservice/build.mk b/xpcom-dbusservice/build.mk
new file mode 100644 (file)
index 0000000..08b14f4
--- /dev/null
@@ -0,0 +1,52 @@
+NAME   = dbusservice
+SOURCES        = $(wildcard xpcom-dbusservice/*.cpp)
+
+PKGS   = dbus-glib-1
+
+# These are wild guesses, but should be close
+GECKO_PREFIX = $(shell pkg-config --variable=prefix mozilla-plugin)
+GECKO_COMPONENT_DIR := $(shell ls -d $(GECKO_PREFIX)/lib/xulrunner-[0-9]* | head -1)/components
+GECKO_SDK_PATH := $(shell pkg-config --variable=sdkdir mozilla-plugin)
+XPIDL  = $(GECKO_SDK_PATH)/bin/xpidl
+PLUGINDIR := $(GECKO_COMPONENT_DIR)
+
+CFLAGS += -I$(GECKO_SDK_PATH)/include \
+          -I$(GECKO_SDK_PATH)/include/xpcom \
+          -I$(GECKO_SDK_PATH)/include/nspr \
+          -I$(GECKO_SDK_PATH)/include/string \
+          -I$(GECKO_SDK_PATH)/include/embedstring \
+          -I$(GECKO_SDK_PATH)/include/xpconnect \
+          -I$(GECKO_SDK_PATH)/include/js \
+          -I$(O)/include \
+          -DNO_NSPR_10_SUPPORT
+
+CFLAGS += -fno-rtti -fno-exceptions -fshort-wchar
+
+LDFLAGS        += -L$(GECKO_SDK_PATH)/lib
+LIBS   += -lxpcomglue_s -lnspr4 -lplds4
+
+include build/plugin.mk
+
+$(O)/include/IDBusService.h: xpcom-dbusservice/IDBusService.idl
+       $(call echo,Generate,$@)
+       @mkdir -p $(dir $@)
+       @$(XPIDL) -I $(GECKO_SDK_PATH)/idl -m header -e $@ $<
+
+$(O)/xpt/dbusservice.xpt: xpcom-dbusservice/IDBusService.idl
+       $(call echo,Generate,$@)
+       @mkdir -p $(dir $@)
+       @$(XPIDL) -I $(GECKO_SDK_PATH)/idl -m typelib -e $@ $<
+
+$(PIC_OBJECTS) $(OBJECTS): $(O)/include/IDBusService.h $(O)/xpt/dbusservice.xpt
+
+install:: install-xpt
+
+install-xpt:
+ifneq ($(wildcard $(O_PLUGIN)),)
+       mkdir -p $(DEST_PLUGINDIR)
+       cp $(O)/xpt/dbusservice.xpt $(DEST_PLUGINDIR)/
+else
+       @echo XPCOM D-Bus service has not been built, not installing
+endif
+
+.PHONY: install-xpt