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 /* TODO: Not like this :( */
35 static DBusConnection *session;
36 static DBusConnection *system;
37 static JSGlobalContextRef gcontext = NULL;
41 /* Getters for the bus type properties */
43 JSValueRef _get_bus_type (JSContextRef context,
45 JSStringRef propertyName,
46 JSValueRef *exception)
48 if (JSStringIsEqualToUTF8CString(propertyName, "SESSION"))
50 return JSValueMakeNumber(context, DBUS_BUS_SESSION);
52 if (JSStringIsEqualToUTF8CString(propertyName, "SYSTEM"))
54 return JSValueMakeNumber(context, DBUS_BUS_SYSTEM);
57 return JSValueMakeUndefined(context);
62 JSStaticValue dbus_jsclass_staticvalues[] =
64 { "SESSION", _get_bus_type, NULL, kJSPropertyAttributeReadOnly },
65 { "SYSTEM", _get_bus_type, NULL, kJSPropertyAttributeReadOnly },
66 { NULL, NULL, NULL, 0 }
70 void _number_finalize (JSObjectRef object)
72 g_free(JSObjectGetPrivate(object));
76 JSValueRef _get_number_object (JSContextRef context,
78 JSObjectRef thisObject,
80 const JSValueRef arguments[],
81 JSValueRef *exception,
82 JSClassRef number_class)
86 if (argumentCount != 1)
88 /* TODO: set exception */
89 return JSValueMakeUndefined(context);
92 /* dbus_uint64_t should be large enough to hold any number so we just
93 * carry the value in private data as a pointer to dbus_uint64_t.
94 * The object class tells us later which type it is.
96 value = g_new0(dbus_uint64_t, 1);
97 *value = (dbus_uint64_t)JSValueToNumber(context, arguments[0], NULL);
99 return JSObjectMake(context, number_class, value);
102 JSValueRef _convert_number_object(JSContextRef context,
105 JSValueRef* exception)
107 /* FIXME: this isn't called at all... */
108 g_debug("%s(%p to %d)", __FUNCTION__, object, type);
114 dbus_uint64_t value = jsvalue_to_number_value(context, object, NULL);
115 return JSValueMakeNumber(context, (double)value);
122 dbus_uint64_t value = jsvalue_to_number_value(context, object, NULL);
123 str = g_strdup_printf("%llu", value);
124 jsstr = JSStringCreateWithUTF8CString(str);
126 jsvalue = JSValueMakeString(context, jsstr);
127 JSStringRelease(jsstr);
137 #define MAKE_NUMBER_CLASS_AND_GETTER(classname, shortname) \
138 static const JSClassDefinition shortname ##_jsclass_def = \
140 0, kJSClassAttributeNone, classname, \
141 NULL, NULL, NULL, NULL, _number_finalize, NULL, NULL, \
142 NULL, NULL, NULL, NULL, NULL, NULL, _convert_number_object \
145 static JSValueRef _get_ ##shortname (JSContextRef context, \
146 JSObjectRef function, \
147 JSObjectRef thisObject, \
148 size_t argumentCount, \
149 const JSValueRef arguments[], \
150 JSValueRef *exception) \
152 return _get_number_object(context, function, thisObject, \
153 argumentCount, arguments, exception, \
154 (JSClassRef)jsclass_lookup(&shortname ##_jsclass_def)); \
157 MAKE_NUMBER_CLASS_AND_GETTER("DBusUInt32", uint32)
158 MAKE_NUMBER_CLASS_AND_GETTER("DBusInt32", int32)
159 MAKE_NUMBER_CLASS_AND_GETTER("DBusByte", byte)
160 MAKE_NUMBER_CLASS_AND_GETTER("DBusUInt64", uint64)
161 MAKE_NUMBER_CLASS_AND_GETTER("DBusInt64", int64)
162 MAKE_NUMBER_CLASS_AND_GETTER("DBusUInt16", uint16)
163 MAKE_NUMBER_CLASS_AND_GETTER("DBusInt16", int16)
168 void _variant_finalize (JSObjectRef object)
170 variant_data_t *data = (variant_data_t *)JSObjectGetPrivate(object);
171 g_assert(data != NULL);
172 g_free(data->signature);
173 JSValueUnprotect(gcontext, data->value);
177 static const JSClassDefinition variant_jsclass_def =
179 0, kJSClassAttributeNone, "DBusVariant",
180 NULL, NULL, NULL, NULL, _variant_finalize, NULL, NULL,
181 NULL, NULL, NULL, NULL, NULL, NULL, NULL
185 JSValueRef _construct_variant (JSContextRef context,
186 JSObjectRef function,
187 JSObjectRef thisObject,
188 size_t argumentCount,
189 const JSValueRef arguments[],
190 JSValueRef *exception)
192 variant_data_t *data;
194 if (argumentCount < 2)
196 /* TODO: set exception */
197 return JSValueMakeUndefined(context);
200 data = g_new0(variant_data_t, 1);
201 data->signature = string_from_jsvalue(context, arguments[0]);
202 data->value = arguments[1];
203 JSValueProtect(context, data->value);
205 return JSObjectMake(context, (JSClassRef)jsclass_lookup(&variant_jsclass_def), (void*)data);
208 static const JSClassDefinition struct_jsclass_def =
210 0, kJSClassAttributeNone, "DBusStruct",
211 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
212 NULL, NULL, NULL, NULL, NULL, NULL, NULL
216 JSValueRef _construct_struct (JSContextRef context,
217 JSObjectRef function,
218 JSObjectRef thisObject,
219 size_t argumentCount,
220 const JSValueRef arguments[],
221 JSValueRef *exception)
223 if (argumentCount != 1)
225 /* TODO: set exception */
226 return JSValueMakeUndefined(context);
229 /* Just carry the object in private data */
230 return JSObjectMake(context,
231 (JSClassRef)jsclass_lookup(&struct_jsclass_def),
232 (void*)arguments[0]);
235 static const JSClassDefinition object_path_jsclass_def =
237 0, kJSClassAttributeNone, "DBusObjectPath",
238 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
239 NULL, NULL, NULL, NULL, NULL, NULL, NULL
243 gboolean is_valid_path (const char *path)
245 const char *this = path;
246 const char *prev = this;
248 if (path == NULL || strlen(path) == 0)
251 /* MUST begin with zero */
255 /* The path is guranteed to be null-terminated */
256 while (*this != '\0')
258 /* Two slashes can't be together */
259 if (*this == '/' && *prev == '/')
262 } else if (!(((*this) >= '0' && (*this) <= '9') ||
263 ((*this) >= 'A' && (*this) <= 'Z') ||
264 ((*this) >= 'a' && (*this) <= 'z') ||
265 (*this) == '_' || (*this) == '/')) {
276 JSValueRef _construct_object_path (JSContextRef context,
277 JSObjectRef function,
278 JSObjectRef thisObject,
279 size_t argumentCount,
280 const JSValueRef arguments[],
281 JSValueRef *exception)
285 if (argumentCount != 1)
287 /* TODO: set exception */
288 return JSValueMakeUndefined(context);
291 /* D-Bus doesn't like invalid object paths _at all_, so instead of risking
292 * disconnection, we'll validate the path now.
294 path = string_from_jsvalue(context, arguments[0]);
295 if (!is_valid_path(path))
297 g_free((gpointer)path);
298 /* TODO: set exception */
299 return JSValueMakeUndefined(context);
301 g_free((gpointer)path);
303 /* Just carry the value in private data */
304 return JSObjectMake(context,
305 (JSClassRef)jsclass_lookup(&object_path_jsclass_def),
306 (void*)arguments[0]);
309 static const JSClassDefinition signature_jsclass_def =
311 0, kJSClassAttributeNone, "DBusSignature",
312 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
313 NULL, NULL, NULL, NULL, NULL, NULL, NULL
317 JSValueRef _construct_signature (JSContextRef context,
318 JSObjectRef function,
319 JSObjectRef thisObject,
320 size_t argumentCount,
321 const JSValueRef arguments[],
322 JSValueRef *exception)
324 if (argumentCount != 1)
326 /* TODO: set exception */
327 return JSValueMakeUndefined(context);
330 /* Just carry the value in private data */
331 return JSObjectMake(context,
332 (JSClassRef)jsclass_lookup(&signature_jsclass_def),
333 (void*)arguments[0]);
336 #define JSVALUE_TO_CONNECTION(ctx, val) (JSValueToNumber(ctx, val, NULL) == DBUS_BUS_SYSTEM) ? system : session
339 JSValueRef getMethod (JSContextRef context,
340 JSObjectRef function,
341 JSObjectRef thisObject,
342 size_t argumentCount,
343 const JSValueRef arguments[],
344 JSValueRef *exception)
346 JSGlobalContextRef global_context = JSObjectGetPrivate(thisObject);
348 if (argumentCount < 4)
350 /* TODO: set exception */
351 return JSValueMakeUndefined(context);
354 return jscorebus_create_method(global_context,
355 JSVALUE_TO_CONNECTION(context, arguments[0]),
356 string_from_jsvalue(context, arguments[1]),
357 string_from_jsvalue(context, arguments[2]),
358 string_from_jsvalue(context, arguments[3]),
360 string_from_jsvalue(context, arguments[4])
363 string_from_jsvalue(context, arguments[5])
366 JSValueToObject(context, arguments[6], NULL)
372 JSValueRef getSignal (JSContextRef context,
373 JSObjectRef function,
374 JSObjectRef thisObject,
375 size_t argumentCount,
376 const JSValueRef arguments[],
377 JSValueRef *exception)
379 JSGlobalContextRef global_context = JSObjectGetPrivate(thisObject);
381 if (argumentCount < 3)
383 /* TODO: set exception */
384 return JSValueMakeUndefined(context);
387 return jscorebus_create_signal(global_context,
388 JSVALUE_TO_CONNECTION(context, arguments[0]),
389 string_from_jsvalue(context, arguments[1]),
390 string_from_jsvalue(context, arguments[2]),
392 string_from_jsvalue(context, arguments[3])
395 string_from_jsvalue(context, arguments[4])
398 JSValueToObject(context, arguments[5], NULL)
404 JSValueRef emitSignal (JSContextRef context,
405 JSObjectRef function,
406 JSObjectRef thisObject,
407 size_t argumentCount,
408 const JSValueRef arguments[],
409 JSValueRef *exception)
411 DBusMessage *message;
412 DBusConnection *connection;
418 if (argumentCount < 4)
420 /* TODO: set exception */
421 g_warning("Not enough arguments for emitSignal");
422 return JSValueMakeBoolean(context, FALSE);
425 connection = JSVALUE_TO_CONNECTION(context, arguments[0]);
426 path = string_from_jsvalue(context, arguments[1]);
427 interface = string_from_jsvalue(context, arguments[2]);
428 member = string_from_jsvalue(context, arguments[3]);
430 if (connection == NULL || path == NULL
431 || interface == NULL || member == NULL)
436 g_warning("Buggy application: Required emitSignal() argument was null");
437 return JSValueMakeBoolean(context, FALSE);
440 message = dbus_message_new_signal(path, interface, member);
448 return JSValueMakeBoolean(context, FALSE);
451 if (argumentCount > 5)
455 DBusMessageIter iter;
457 /* "Splice" the array */
458 args = g_new(JSValueRef, argumentCount - 5);
460 for (i = 5; i < argumentCount; i++)
461 args[c++] = arguments[i];
463 /* Push arguments to the message */
464 signature = string_from_jsvalue(context, arguments[4]);
465 dbus_message_iter_init_append (message, &iter);
466 if (!jsvalue_array_append_to_message_iter(context,
470 /* TODO: set exception */
471 for (i = 0; i < c; i++)
475 dbus_message_unref(message);
476 return JSValueMakeBoolean(context, FALSE);
479 for (i = 0; i < c; i++)
485 if (dbus_connection_send(connection, message, NULL))
487 dbus_message_unref(message);
488 return JSValueMakeBoolean(context, TRUE);
491 dbus_message_unref(message);
492 return JSValueMakeBoolean(context, FALSE);
496 void dbus_finalize(JSObjectRef object)
498 JSObjectSetPrivate(object, NULL);
502 JSStaticFunction dbus_jsclass_staticfuncs[] =
504 /* Type constructors */
505 { "Int32", _get_int32, kJSPropertyAttributeReadOnly },
506 { "UInt32", _get_uint32, kJSPropertyAttributeReadOnly },
507 { "Byte", _get_byte, kJSPropertyAttributeReadOnly },
508 { "Int64", _get_int64, kJSPropertyAttributeReadOnly },
509 { "UInt64", _get_uint64, kJSPropertyAttributeReadOnly },
510 { "Int16", _get_int16, kJSPropertyAttributeReadOnly },
511 { "UInt16", _get_uint16, kJSPropertyAttributeReadOnly },
512 { "ObjectPath", _construct_object_path, kJSPropertyAttributeReadOnly },
513 { "Signature", _construct_signature, kJSPropertyAttributeReadOnly },
514 { "Variant", _construct_variant, kJSPropertyAttributeReadOnly },
515 { "Struct", _construct_struct, kJSPropertyAttributeReadOnly },
518 { "getMethod", getMethod, kJSPropertyAttributeReadOnly },
519 { "getSignal", getSignal, kJSPropertyAttributeReadOnly },
520 { "emitSignal", emitSignal, kJSPropertyAttributeReadOnly },
525 JSObjectRef dbus_constructor (JSContextRef context,
526 JSObjectRef constructor,
527 size_t argumentCount,
528 const JSValueRef arguments[],
529 JSValueRef* exception);
533 JSClassDefinition dbus_jsclass_def =
536 kJSClassAttributeNone,
540 dbus_jsclass_staticvalues,
541 dbus_jsclass_staticfuncs,
559 JSObjectRef dbus_constructor (JSContextRef context,
560 JSObjectRef constructor,
561 size_t argumentCount,
562 const JSValueRef arguments[],
563 JSValueRef* exception)
565 return JSObjectMake(context,
566 (JSClassRef)jsclass_lookup(&dbus_jsclass_def),
574 void jscorebus_init(DBusConnection *psession, DBusConnection *psystem)
579 jsclassdef_insert("DBus", &dbus_jsclass_def);
581 #define INIT_NUMBER_CLASS(name, def, type, num) \
582 jsclassdef_insert(name, def); \
583 jscorebus_number_class_names[num] = name; \
584 jscorebus_number_class_types[num] = type;
586 INIT_NUMBER_CLASS("DBusInt32", &int32_jsclass_def, DBUS_TYPE_INT32, 0);
587 INIT_NUMBER_CLASS("DBusUInt32", &uint32_jsclass_def, DBUS_TYPE_UINT32, 1);
588 INIT_NUMBER_CLASS("DBusByte", &byte_jsclass_def, DBUS_TYPE_BYTE, 3);
589 INIT_NUMBER_CLASS("DBusUInt64", &uint64_jsclass_def, DBUS_TYPE_UINT64, 4);
590 INIT_NUMBER_CLASS("DBusInt64", &int64_jsclass_def, DBUS_TYPE_INT64, 5);
591 INIT_NUMBER_CLASS("DBusUInt16", &uint16_jsclass_def, DBUS_TYPE_UINT16, 6);
592 INIT_NUMBER_CLASS("DBusInt16", &int16_jsclass_def, DBUS_TYPE_INT16, 7);
594 jsclassdef_insert("DBusObjectPath", &object_path_jsclass_def);
595 jsclassdef_insert("DBusSignature", &signature_jsclass_def);
597 jsclassdef_insert("DBusVariant", &variant_jsclass_def);
598 jsclassdef_insert("DBusStruct", &struct_jsclass_def);
602 void jscorebus_export(JSGlobalContextRef context)
604 JSObjectRef globalObject;
608 dbus = JSObjectMakeConstructor(context,
609 (JSClassRef)jsclass_lookup(&dbus_jsclass_def),
613 globalObject = JSContextGetGlobalObject(context);
614 jsstr = JSStringCreateWithUTF8CString("DBus");
615 JSObjectSetProperty(context, globalObject,
617 kJSPropertyAttributeNone, NULL);
618 JSStringRelease(jsstr);