2 * Browser D-Bus Bridge, XPCOM version
4 * Copyright © 2008 Movial Creative Technologies Inc
5 * Contact: Movial Creative Technologies Inc, <info@movial.com>
6 * Authors: Lauri Mylläri, <lauri.myllari@movial.fi>
7 * Kalle Vahlman, <kalle.vahlman@movial.com>
9 * The contents of this file are subject to the Mozilla Public License
10 * Version 1.1 (the "License"); you may not use this file except in
11 * compliance with the License. You may obtain a copy of the License at
12 * http://www.mozilla.org/MPL/
14 * Software distributed under the License is distributed on an "AS IS"
15 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
16 * License for the specific language governing rights and limitations
19 * The Original Code is the Browser D-Bus Bridge, XPCOM version.
21 * The Initial Developer of the Original Code is Movial Creative Technologies
22 * Inc. Portions created by Initial Developer are Copyright (C) 2008
23 * Movial Creative Technologies Inc. All Rights Reserved.
28 #include <dbus/dbus.h>
30 #include "nsComponentManagerUtils.h"
31 #include "nsIMutableArray.h"
32 #include "nsArrayUtils.h"
33 #include "nsISupportsPrimitives.h"
34 #include "nsIProperties.h"
36 #include "IDBusService.h"
37 #include "DBusMethod.h"
38 #include "DBusMarshaling.h"
40 #include "bdb-debug.h"
43 // helper declarations
46 static void DoCallBack(IDBusMethod *aCallback, DBusMessage *aReply);
47 static void ReplyHandler(DBusPendingCall *pending, void *user_data);
50 // DBusMethod implementation
53 NS_IMPL_ISUPPORTS1(DBusMethod, IDBusMethod)
55 DBusMethod::DBusMethod(DBusService *aDBusService,
57 const nsACString& aDestination,
58 const nsACString& aObjectPath,
59 const nsACString& aMethodName,
60 const nsACString& aInterfaceName,
61 const nsACString& aSignature) :
62 mDBusService(aDBusService),
64 mDestination(aDestination),
67 mInterface(aInterfaceName),
68 mSignature(aSignature),
71 mErrorCallback(nsnull)
73 BDBLOG(("DBusMethod::DBusMethod()\n"));
74 BDBLOG((" aBusType : %d\n", aBusType));
75 BDBLOG((" aDestination : %s\n", PromiseFlatCString(aDestination).get()));
76 BDBLOG((" aObjectPath : %s\n", PromiseFlatCString(aObjectPath).get()));
77 BDBLOG((" aMethodName : %s\n", PromiseFlatCString(aMethodName).get()));
78 BDBLOG((" aInterfaceName : %s\n", PromiseFlatCString(aInterfaceName).get()));
79 BDBLOG((" aSignature : %s\n", PromiseFlatCString(aSignature).get()));
83 DBusMethod::~DBusMethod()
85 BDBLOG(("DBusMethod::~DBusMethod()\n"));
87 NS_RELEASE(mCallback);
89 NS_RELEASE(mErrorCallback);
93 DBusMethod::GetAsync(PRBool *aAsync)
100 DBusMethod::SetAsync(PRBool aAsync)
102 BDBLOG(("DBusMethod::SetAsync(%s)\n", aAsync ? "true" : "false"));
108 DBusMethod::GetOnReply(IDBusMethodCallback **aOnReply)
110 *aOnReply = mCallback;
111 NS_IF_ADDREF(*aOnReply);
116 DBusMethod::SetOnReply(IDBusMethodCallback *aOnReply)
118 BDBLOG(("DBusMethod::SetOnReply(%08x)\n", aOnReply));
120 NS_RELEASE(mCallback);
121 mCallback = aOnReply;
122 NS_IF_ADDREF(mCallback);
127 DBusMethod::GetOnError(IDBusMethodCallback **aOnError)
129 *aOnError = mErrorCallback;
130 NS_IF_ADDREF(*aOnError);
135 DBusMethod::SetOnError(IDBusMethodCallback *aOnError)
137 BDBLOG(("DBusMethod::SetOnError(%08x)\n", aOnError));
139 NS_RELEASE(mErrorCallback);
140 mErrorCallback = aOnError;
141 NS_IF_ADDREF(mErrorCallback);
146 ReplyHandler(DBusPendingCall *pending, void *user_data)
149 nsCOMPtr<IDBusMethod> method = (IDBusMethod *) user_data;
151 reply = dbus_pending_call_steal_reply(pending);
152 DoCallBack(method, reply);
153 dbus_message_unref(reply);
158 DoCallBack(IDBusMethod *aMethod, DBusMessage *aReply)
160 DBusMessageIter iter;
162 nsCOMPtr<nsIMutableArray> reply_args;
163 nsCOMPtr<IDBusMethodCallback> callback;
165 int msg_type = dbus_message_get_type(aReply);
167 dbus_message_iter_init(aReply, &iter);
169 reply_args = getArrayFromIter(&iter);
173 case DBUS_MESSAGE_TYPE_METHOD_RETURN:
175 BDBLOG((" got method reply\n"));
176 aMethod->GetOnReply(getter_AddRefs(callback));
179 case DBUS_MESSAGE_TYPE_ERROR:
181 BDBLOG((" got an error message: %s\n", dbus_message_get_error_name(aReply)));
182 aMethod->GetOnError(getter_AddRefs(callback));
184 /* insert error name as first callback argument */
185 nsCOMPtr<nsIWritableVariant> error_name = do_CreateInstance("@mozilla.org/variant;1");
186 error_name->SetAsString(dbus_message_get_error_name(aReply));
187 reply_args->InsertElementAt(error_name, 0, PR_FALSE);
193 BDBLOG((" got unhandled message of type %d\n", msg_type));
198 PRUint32 reply_items;
199 reply_args->GetLength(&reply_items);
200 BDBLOG((" reply_args: %d items\n", reply_items));
204 /* arguments are packed as an array into an nsIVariant */
205 nsIVariant **callback_args = new nsIVariant*[reply_items];
206 nsCOMPtr<nsIWritableVariant> args = do_CreateInstance("@mozilla.org/variant;1");
207 for (int i = 0; i < reply_items; i++)
209 nsCOMPtr<nsIVariant> arg = do_QueryElementAt(reply_args, i);
210 callback_args[i] = arg;
213 args->SetAsArray(nsIDataType::VTYPE_INTERFACE_IS,
214 &NS_GET_IID(nsIVariant),
217 for (int i = 0; i < reply_items; i++)
218 NS_RELEASE(callback_args[i]);
219 delete[] callback_args;
220 callback->OnReply(args);
225 DBusMethod::DoCall(nsIVariant **aArgs, PRUint32 aCount)
228 DBusMessageIter msg_iter;
229 nsCAutoString signature;
231 BDBLOG(("DBusMethod::DoCall()\n"));
232 BDBLOG((" aCount : %d\n", aCount));
234 msg = dbus_message_new_method_call(PromiseFlatCString(mDestination).get(),
235 PromiseFlatCString(mObject).get(),
236 PromiseFlatCString(mInterface).get(),
237 PromiseFlatCString(mMethod).get());
238 dbus_message_iter_init_append(msg, &msg_iter);
240 if (mSignature.Equals(""))
242 // FIXME - is it necessary to clear the string?
243 signature.Assign("");
244 for (int i = 0; i < aCount; i++)
246 // no method signature specified, guess argument types
247 nsCOMPtr<nsIVariant> data = aArgs[i];
248 nsCAutoString tmpsig;
250 getSignatureFromVariant(data, tmpsig);
251 BDBLOG((" aArgs[%02d] : signature \"%s\"\n",
253 PromiseFlatCString(tmpsig).get()));
254 signature.Append(tmpsig);
256 } /* for (int i = 0; i < aCount; i++) */
257 } /* if (mSignature.Equals("")) */
260 signature.Assign(mSignature);
263 if (dbus_signature_validate(PromiseFlatCString(signature).get(), nsnull))
265 DBusSignatureIter sig_iter;
269 BDBLOG((" signature \"%s\"\n", PromiseFlatCString(signature).get()));
271 dbus_signature_iter_init(&sig_iter, PromiseFlatCString(signature).get());
272 while ((current_type = dbus_signature_iter_get_current_type(&sig_iter)) != DBUS_TYPE_INVALID)
274 char *element_signature = dbus_signature_iter_get_signature(&sig_iter);
275 BDBLOG((" element \"%s\" from signature\n", element_signature));
276 BDBLOG((" type %c from signature\n", current_type));
278 addVariantToIter(aArgs[i], &msg_iter, &sig_iter);
281 dbus_free(element_signature);
282 dbus_signature_iter_next(&sig_iter);
287 BDBLOG((" invalid signature \"%s\"\n", PromiseFlatCString(signature).get()));
288 return NS_ERROR_ILLEGAL_VALUE;
291 // Sanity-check: make sure that the signature we think we are sending matches
292 // that of the message
294 if (!signature.Equals(dbus_message_get_signature(msg)))
296 BDBLOG((" signature mismatch! Expected '%s', got '%s'\n",
297 PromiseFlatCString(signature).get(),
298 dbus_message_get_signature(msg)));
299 return NS_ERROR_ILLEGAL_VALUE;
302 DBusPendingCall *pending = mDBusService->SendWithReply(mBusType,
309 /* FIXME - do we need to AddRef "this" */
310 BDBLOG((" do async reply callback\n"));
311 dbus_pending_call_set_notify(pending,
319 BDBLOG((" do sync reply callback\n"));
320 dbus_pending_call_block(pending);
321 reply = dbus_pending_call_steal_reply (pending);
322 dbus_pending_call_unref (pending);
323 DoCallBack(this, reply);
324 dbus_message_unref(reply);
329 return NS_ERROR_OUT_OF_MEMORY;
332 dbus_message_unref(msg);
337 /* vim: set cindent ts=4 et sw=4: */