2 * Browser D-Bus Bridge, JavaScriptCore version
4 * Copyright © 2008 Movial Creative Technologies Inc
5 * Contact: Movial Creative Technologies Inc, <info@movial.com>
6 * Authors: Kalle Vahlman, <kalle.vahlman@movial.com>
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
26 #include <dbus/dbus.h>
27 #include <JavaScriptCore/JavaScript.h>
29 #include "jscorebus-marshal.h"
30 #include "jscorebus-method.h"
31 #include "jscorebus-signal.h"
34 static DBusConnection *session;
35 static DBusConnection *system;
38 /* Getters for the bus type properties */
40 JSValueRef _get_bus_type (JSContextRef context,
42 JSStringRef propertyName,
43 JSValueRef *exception)
45 if (JSStringIsEqualToUTF8CString(propertyName, "SESSION"))
47 return JSValueMakeNumber(context, DBUS_BUS_SESSION);
49 if (JSStringIsEqualToUTF8CString(propertyName, "SYSTEM"))
51 return JSValueMakeNumber(context, DBUS_BUS_SYSTEM);
54 return JSValueMakeUndefined(context);
59 JSStaticValue dbus_jsclass_staticvalues[] =
61 { "SESSION", _get_bus_type, NULL, kJSPropertyAttributeReadOnly },
62 { "SYSTEM", _get_bus_type, NULL, kJSPropertyAttributeReadOnly },
63 { NULL, NULL, NULL, 0 }
67 void _number_finalize (JSObjectRef object)
69 g_free(JSObjectGetPrivate(object));
73 JSValueRef _get_number_object (JSContextRef context,
75 JSObjectRef thisObject,
77 const JSValueRef arguments[],
78 JSValueRef *exception,
79 JSClassRef number_class)
83 if (argumentCount != 1)
85 /* TODO: set exception */
86 return JSValueMakeUndefined(context);
89 /* dbus_uint64_t should be large enough to hold any number so we just
90 * carry the value in private data as a pointer to dbus_uint64_t.
91 * The object class tells us later which type it is.
93 value = g_new0(dbus_uint64_t, 1);
94 *value = (dbus_uint64_t)JSValueToNumber(context, arguments[0], NULL);
96 return JSObjectMake(context, number_class, value);
99 JSValueRef _convert_number_object(JSContextRef context,
102 JSValueRef* exception)
104 /* FIXME: this isn't called at all... */
105 g_debug("%s(%p to %d)", __FUNCTION__, object, type);
111 dbus_uint64_t value = jsvalue_to_number_value(context, object, NULL);
112 return JSValueMakeNumber(context, (double)value);
119 dbus_uint64_t value = jsvalue_to_number_value(context, object, NULL);
120 str = g_strdup_printf("%llu", value);
121 jsstr = JSStringCreateWithUTF8CString(str);
123 jsvalue = JSValueMakeString(context, jsstr);
124 JSStringRelease(jsstr);
134 #define MAKE_NUMBER_CLASS_AND_GETTER(classname, shortname) \
135 static const JSClassDefinition shortname ##_jsclass_def = \
137 0, kJSClassAttributeNone, classname, \
138 NULL, NULL, NULL, NULL, _number_finalize, NULL, NULL, \
139 NULL, NULL, NULL, NULL, NULL, NULL, _convert_number_object \
142 static JSValueRef _get_ ##shortname (JSContextRef context, \
143 JSObjectRef function, \
144 JSObjectRef thisObject, \
145 size_t argumentCount, \
146 const JSValueRef arguments[], \
147 JSValueRef *exception) \
149 return _get_number_object(context, function, thisObject, \
150 argumentCount, arguments, exception, \
151 (JSClassRef)jsclass_lookup(&shortname ##_jsclass_def)); \
154 MAKE_NUMBER_CLASS_AND_GETTER("DBusUInt32", uint32)
155 MAKE_NUMBER_CLASS_AND_GETTER("DBusInt32", int32)
156 MAKE_NUMBER_CLASS_AND_GETTER("DBusDouble", double)
157 MAKE_NUMBER_CLASS_AND_GETTER("DBusByte", byte)
158 MAKE_NUMBER_CLASS_AND_GETTER("DBusUInt64", uint64)
159 MAKE_NUMBER_CLASS_AND_GETTER("DBusInt64", int64)
160 MAKE_NUMBER_CLASS_AND_GETTER("DBusUInt16", uint16)
161 MAKE_NUMBER_CLASS_AND_GETTER("DBusInt16", int16)
163 static const JSClassDefinition variant_jsclass_def =
165 0, kJSClassAttributeNone, "DBusVariant",
166 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
167 NULL, NULL, NULL, NULL, NULL, NULL, NULL
171 JSValueRef _construct_variant (JSContextRef context,
172 JSObjectRef function,
173 JSObjectRef thisObject,
174 size_t argumentCount,
175 const JSValueRef arguments[],
176 JSValueRef *exception)
179 if (argumentCount != 1)
181 /* TODO: set exception */
182 return JSValueMakeUndefined(context);
185 /* Just carry the value in private data */
186 return JSObjectMake(context, (JSClassRef)jsclass_lookup(&variant_jsclass_def), (void*)arguments[0]);
189 static const JSClassDefinition struct_jsclass_def =
191 0, kJSClassAttributeNone, "DBusStruct",
192 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
193 NULL, NULL, NULL, NULL, NULL, NULL, NULL
197 JSValueRef _construct_struct (JSContextRef context,
198 JSObjectRef function,
199 JSObjectRef thisObject,
200 size_t argumentCount,
201 const JSValueRef arguments[],
202 JSValueRef *exception)
204 if (argumentCount != 1)
206 /* TODO: set exception */
207 return JSValueMakeUndefined(context);
210 /* Just carry the object in private data */
211 return JSObjectMake(context,
212 (JSClassRef)jsclass_lookup(&struct_jsclass_def),
213 (void*)arguments[0]);
216 static const JSClassDefinition object_path_jsclass_def =
218 0, kJSClassAttributeNone, "DBusObjectPath",
219 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
220 NULL, NULL, NULL, NULL, NULL, NULL, NULL
224 gboolean is_valid_path (const char *path)
226 const char *this = path;
227 const char *prev = this;
229 if (strlen(path) == 0)
232 /* MUST begin with zero */
236 /* The path is guranteed to be null-terminated */
237 while (*this != '\0')
239 /* Two slashes can't be together */
240 if (*this == '/' && *prev == '/')
243 } else if (!(((*this) >= '0' && (*this) <= '9') ||
244 ((*this) >= 'A' && (*this) <= 'Z') ||
245 ((*this) >= 'a' && (*this) <= 'z') ||
246 (*this) == '_' || (*this) == '/')) {
257 JSValueRef _construct_object_path (JSContextRef context,
258 JSObjectRef function,
259 JSObjectRef thisObject,
260 size_t argumentCount,
261 const JSValueRef arguments[],
262 JSValueRef *exception)
266 if (argumentCount != 1)
268 /* TODO: set exception */
269 return JSValueMakeUndefined(context);
272 /* D-Bus doesn't like invalid object paths _at all_, so instead of risking
273 * disconnection, we'll validate the path now.
275 path = string_from_jsvalue(context, arguments[0]);
276 if (!is_valid_path(path))
278 g_free((gpointer)path);
279 /* TODO: set exception */
280 return JSValueMakeUndefined(context);
282 g_free((gpointer)path);
284 /* Just carry the value in private data */
285 return JSObjectMake(context,
286 (JSClassRef)jsclass_lookup(&object_path_jsclass_def),
287 (void*)arguments[0]);
290 static const JSClassDefinition signature_jsclass_def =
292 0, kJSClassAttributeNone, "DBusSignature",
293 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
294 NULL, NULL, NULL, NULL, NULL, NULL, NULL
298 JSValueRef _construct_signature (JSContextRef context,
299 JSObjectRef function,
300 JSObjectRef thisObject,
301 size_t argumentCount,
302 const JSValueRef arguments[],
303 JSValueRef *exception)
305 if (argumentCount != 1)
307 /* TODO: set exception */
308 return JSValueMakeUndefined(context);
311 /* Just carry the value in private data */
312 return JSObjectMake(context,
313 (JSClassRef)jsclass_lookup(&signature_jsclass_def),
314 (void*)arguments[0]);
317 #define JSVALUE_TO_CONNECTION(ctx, val) (JSValueToNumber(ctx, val, NULL) == DBUS_BUS_SYSTEM) ? system : session
320 JSValueRef getMethod (JSContextRef context,
321 JSObjectRef function,
322 JSObjectRef thisObject,
323 size_t argumentCount,
324 const JSValueRef arguments[],
325 JSValueRef *exception)
327 JSGlobalContextRef global_context = JSObjectGetPrivate(thisObject);
329 if (argumentCount < 4)
331 /* TODO: set exception */
332 return JSValueMakeUndefined(context);
335 return jscorebus_create_method(global_context,
336 JSVALUE_TO_CONNECTION(context, arguments[0]),
337 string_from_jsvalue(context, arguments[1]),
338 string_from_jsvalue(context, arguments[2]),
339 string_from_jsvalue(context, arguments[3]),
341 string_from_jsvalue(context, arguments[4])
344 string_from_jsvalue(context, arguments[5])
347 JSValueToObject(context, arguments[6], NULL)
353 JSValueRef getSignal (JSContextRef context,
354 JSObjectRef function,
355 JSObjectRef thisObject,
356 size_t argumentCount,
357 const JSValueRef arguments[],
358 JSValueRef *exception)
360 JSGlobalContextRef global_context = JSObjectGetPrivate(thisObject);
362 if (argumentCount < 3)
364 /* TODO: set exception */
365 return JSValueMakeUndefined(context);
368 return jscorebus_create_signal(global_context,
369 JSVALUE_TO_CONNECTION(context, arguments[0]),
370 string_from_jsvalue(context, arguments[1]),
371 string_from_jsvalue(context, arguments[2]),
373 string_from_jsvalue(context, arguments[3])
376 string_from_jsvalue(context, arguments[4])
379 JSValueToObject(context, arguments[5], NULL)
385 JSValueRef emitSignal (JSContextRef context,
386 JSObjectRef function,
387 JSObjectRef thisObject,
388 size_t argumentCount,
389 const JSValueRef arguments[],
390 JSValueRef *exception)
392 DBusMessage *message;
393 DBusConnection *connection;
399 if (argumentCount < 4)
401 /* TODO: set exception */
402 g_warning("Not enough arguments for emitSignal");
403 return JSValueMakeBoolean(context, FALSE);
406 connection = JSVALUE_TO_CONNECTION(context, arguments[0]);
407 path = string_from_jsvalue(context, arguments[1]);
408 interface = string_from_jsvalue(context, arguments[2]);
409 member = string_from_jsvalue(context, arguments[3]);
411 if (connection == NULL || path == NULL
412 || interface == NULL || member == NULL)
417 g_warning("Buggy application: Required emitSignal() argument was null");
418 return JSValueMakeBoolean(context, FALSE);
421 message = dbus_message_new_signal(path, interface, member);
429 return JSValueMakeBoolean(context, FALSE);
432 if (argumentCount > 5)
436 DBusMessageIter iter;
438 /* "Splice" the array */
439 args = g_new(JSValueRef, argumentCount - 5);
441 for (i = 5; i < argumentCount; i++)
442 args[c++] = arguments[i];
444 /* Push arguments to the message */
445 signature = string_from_jsvalue(context, arguments[4]);
446 dbus_message_iter_init_append (message, &iter);
447 if (!jsvalue_array_append_to_message_iter(context,
451 /* TODO: set exception */
452 for (i = 0; i < c; i++)
456 dbus_message_unref(message);
457 return JSValueMakeBoolean(context, FALSE);
460 for (i = 0; i < c; i++)
466 if (dbus_connection_send(connection, message, NULL))
468 dbus_message_unref(message);
469 return JSValueMakeBoolean(context, TRUE);
472 dbus_message_unref(message);
473 return JSValueMakeBoolean(context, FALSE);
477 void dbus_finalize(JSObjectRef object)
480 JSObjectSetPrivate(object, NULL);
484 JSStaticFunction dbus_jsclass_staticfuncs[] =
486 /* Type constructors */
487 { "Int32", _get_int32, kJSPropertyAttributeReadOnly },
488 { "UInt32", _get_uint32, kJSPropertyAttributeReadOnly },
489 { "Double", _get_double, kJSPropertyAttributeReadOnly },
490 { "Byte", _get_byte, kJSPropertyAttributeReadOnly },
491 { "Int64", _get_int64, kJSPropertyAttributeReadOnly },
492 { "UInt64", _get_uint64, kJSPropertyAttributeReadOnly },
493 { "Int16", _get_int16, kJSPropertyAttributeReadOnly },
494 { "UInt16", _get_uint16, kJSPropertyAttributeReadOnly },
495 { "ObjectPath", _construct_object_path, kJSPropertyAttributeReadOnly },
496 { "Signature", _construct_signature, kJSPropertyAttributeReadOnly },
497 { "Variant", _construct_variant, kJSPropertyAttributeReadOnly },
498 { "Struct", _construct_struct, kJSPropertyAttributeReadOnly },
501 { "getMethod", getMethod, kJSPropertyAttributeReadOnly },
502 { "getSignal", getSignal, kJSPropertyAttributeReadOnly },
503 { "emitSignal", emitSignal, kJSPropertyAttributeReadOnly },
509 JSClassDefinition dbus_jsclass_def =
512 kJSClassAttributeNone,
516 dbus_jsclass_staticvalues,
517 dbus_jsclass_staticfuncs,
538 void jscorebus_init(DBusConnection *psession, DBusConnection *psystem)
543 #define INIT_NUMBER_CLASS(name, def, type, num) \
544 jsclassdef_insert(name, def); \
545 jscorebus_number_class_names[num] = name; \
546 jscorebus_number_class_types[num] = type;
548 INIT_NUMBER_CLASS("DBusInt32", &int32_jsclass_def, DBUS_TYPE_INT32, 0);
549 INIT_NUMBER_CLASS("DBusUInt32", &uint32_jsclass_def, DBUS_TYPE_UINT32, 1);
550 INIT_NUMBER_CLASS("DBusDouble", &double_jsclass_def, DBUS_TYPE_DOUBLE, 2);
551 INIT_NUMBER_CLASS("DBusByte", &byte_jsclass_def, DBUS_TYPE_BYTE, 3);
552 INIT_NUMBER_CLASS("DBusUInt64", &uint64_jsclass_def, DBUS_TYPE_UINT64, 4);
553 INIT_NUMBER_CLASS("DBusInt64", &int64_jsclass_def, DBUS_TYPE_INT64, 5);
554 INIT_NUMBER_CLASS("DBusUInt16", &uint16_jsclass_def, DBUS_TYPE_UINT16, 6);
555 INIT_NUMBER_CLASS("DBusInt16", &int16_jsclass_def, DBUS_TYPE_INT16, 7);
557 jsclassdef_insert("DBusObjectPath", &object_path_jsclass_def);
558 jsclassdef_insert("DBusSignature", &signature_jsclass_def);
560 jsclassdef_insert("DBusVariant", &variant_jsclass_def);
561 jsclassdef_insert("DBusStruct", &struct_jsclass_def);
565 void jscorebus_export(JSGlobalContextRef context)
567 JSObjectRef globalObject;
570 JSClassRef dbus_jsclass;
572 // global_context = context;
574 dbus_jsclass = JSClassCreate(&dbus_jsclass_def);
575 dbus = JSObjectMake(context, dbus_jsclass, context);
577 globalObject = JSContextGetGlobalObject(context);
578 jsstr = JSStringCreateWithUTF8CString("DBus");
579 JSObjectSetProperty(context, globalObject,
581 kJSPropertyAttributeNone, NULL);