3739ccb516c7fc15db2adc5f9c61ff5c51aceca8
[browser-dbus-bridge.git] / html / dbus.js
1 /**
2  * DBus.js, a JS wrapper for the Browser D-Bus Bridge
3  * Copyright (c) 2008-2009  Movial Creative Technologies Inc
4  *
5  * Contact: Movial Creative Technologies Inc, <info@movial.com>
6  * Authors: Lauri Mylläri, <lauri.myllari@movial.com>
7  *          Kalle Vahlman, <kalle.vahlman@movial.com>
8  *          Ehsun Amanolahi, <ehsun.amanolahi@movial.com>
9  *
10  * Permission is hereby granted, free of charge, to any person
11  * obtaining a copy of this software and associated documentation
12  * files (the "Software"), to deal in the Software without
13  * restriction, including without limitation the rights to use,
14  * copy, modify, merge, publish, distribute, sublicense, and/or sell
15  * copies of the Software, and to permit persons to whom the
16  * Software is furnished to do so, subject to the following
17  * conditions:
18  *
19  * The above copyright notice and this permission notice shall be
20  * included in all copies or substantial portions of the Software.
21  *
22  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
24  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
26  * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
27  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
28  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
29  * OTHER DEALINGS IN THE SOFTWARE.
30  */
31
32 /**
33  * @fileOverview The Browser D-Bus Bridge JavaScript API.
34  * @author <a href="mailto:kalle.vahlman@movial.com">Kalle Vahlman</a>
35  * @author <a href="mailto:lauri.myllari@movial.com">Lauri Mylläri</a>
36  * @author <a href="mailto:ehsun.amanolahi@movial.com">Ehsun Amanolahi</a>
37  * @version 1.0
38  */
39
40 if (!window.DBus)
41 {
42     /**
43      * This is the Gecko wrapping for the Browser D-Bus Bridge API
44      * You can use the XPCOM API directly, but the Bridge API
45      *  - is easier to use
46      *  - has few utility features over the "raw" API (like introspection)
47      *  - generally feels a bit more JavaScriptish (hopefully)
48      */
49
50     /**
51      * @private
52      * For readability
53      */
54     var ep = netscape.security.PrivilegeManager.enablePrivilege;
55     ep("UniversalXPConnect");
56     var cc = Components.classes;
57     var ci = Components.interfaces;
58
59     /**
60      * @private
61      * Utility function that creates a wrapper function which handles signature
62      * conversion from wrapper(argarray) to method(arg1, ..., argN) and sets
63      * 'this' to point to the user-specified object. This is mainly used to
64      * convert the variant arrays from the XPCOM service to callback arguments.
65      */
66     var unWrap = function(method, user_data) {
67         return function() {
68             if (method){
69                 method.apply(user_data, arguments[0]);
70             }
71         };
72     };
73
74     /**
75      * @private
76      * Returns a function to create an nsIVariant carrying the given value
77      * as the specified variant type.
78      */
79     var makeVariantMaker = function(variant_type) {
80         return function(val) {
81             ep("UniversalXPConnect");
82             var variant = cc["@mozilla.org/variant;1"].createInstance(ci.nsIWritableVariant);
83             variant['setAs' + variant_type](val);
84             return variant;
85         };
86         return ret;
87     };
88
89     /**
90      * @class The Browser D-Bus Bridge API.
91      * <h2>About</h2>
92      * <p>The Browser D-Bus Bridge is a JavaScript
93      * <a href="http://dbus.freedesktop.org">D-Bus</a> bindings implementation
94      * for web browsers. The Bridge allows privileged JavaScript code to talk to
95      * the D-Bus, both session and system bus (if not prohibited by the D-Bus
96      * configuration).
97      * <p>Since the implementation differs between web browser
98      * engines, the Bridge defines and implements a unified API (referred to as
99      * "the Bridge API") to access D-Bus. While you can always use the
100      * implementation-specific APIs, their stability is not guaranteed. They
101      * also might not support extra features of the Bridge API
102      * (like introspection).
103      * <h2>Notes about types</h2>
104      * <p>The D-Bus specification introduces 16 distinct data types of which 12
105      * are "simple" types and 4 are container types. This is a bit of a problem
106      * since JavaScript inherenetly only supports five basic types; Boolean,
107      * Number, String, Array and Object. There are three ways how the Bridge
108      * solves this problem: signatures, autodetection and conversion methods.
109      * <p>Every D-Bus message includes a
110      * <a href="http://dbus.freedesktop.org/doc/dbus-specification.html
111      * #message-protocol-signatures">signature</a> specifying the types of the
112      * data it carries. This information has three sources: for signals the
113      * received D-Bus message itself, the introspection data of a service and
114      * the user of the Bridge API.
115      * <p>When the signature is known, the Bridge knows what type the arguments
116      * should be and can (try to) automatically convert the data to the right
117      * destination type.
118      * <p>If there is no signature information available, the Bridge tries to
119      * autodetect the signature. Since there are only five basic types in
120      * JavaScript, this only works with the following:
121      * <ul>
122      * <li>JavaScript Boolean to DBUS_TYPE_BOOLEAN
123      * <li>JavaScript Number to DBUS_TYPE_DOUBLE
124      * <li>JavaScript String to DBUS_TYPE_BOOLEAN
125      * <li>JavaScript Array to DBUS_TYPE_ARRAY
126      * <li>JavaScript Object to D-Bus DICT type (properties as key-value pairs)
127      * </ul>
128      * <p>The rest of the types need to be "marked" as specific D-Bus types with
129      * the conversion methods. The methods are implementation specific, which
130      * means you cannot rely on the return value of the conversion methods. They
131      * are meant to only be used when passing arguments to method calls or
132      * signals. You will also never be given such object by the Bridge in
133      * callbacks, all D-Bus message arguments are converted to one of the five
134      * JavaScript types before handing them to the callback.
135      * <p>This means that
136      * for example the ObjectPath and Signature types are simply strings in the
137      * callback. Other exceptions are Structs and Variants. D-Bus Structs are
138      * basically just a way to implement a mixed-type array, so they are
139      * represented as such in the Bridge API. Variants are a container type that
140      * allows any type of content (the type is encoded along with the value),
141      * but since JavaScript values have no static typing it is always passed as
142      * the contained value to the callbacks.
143      * <h2>Getting started</h2>
144      * <p>To get started with using the Bridge, continue to the
145      * <a href="#constructor">details section of the main class</a>.<br>
146      * @description The D-Bus singleton class.
147      * <p>The D-Bus Bridge API is based on a singleton class called DBus,
148      * through which all operations are made. To get this singleton to your web
149      * application, include the <em>dbus.js</em> in the <em>head</em> section:
150      * <p><code>&lt;script type='text/javascript' src='dbus.js'>&lt;/script>
151      * </code>
152      * <p>The DBus singleton is instantiated by <em>dbus.js</em> as a member of
153      * the global 'window' object. In other type of applications the
154      * <em>dbus.js</em> needs to be loaded and executed in whatever way is
155      * available before the Bridge API can be used.
156      * <p>The example code in this documentation uses an imaginary
157      * <em>Notes</em> service which is specified below. The specification is in
158      * <a href="http://dbus.freedesktop.org/doc/dbus-specification.html
159      * #introspection-format">the introspection data format</a>
160      * of D-Bus, the same type of data which you get by introspecting a service.
161      * <p>The preferred method of accessing a D-Bus service is to create an
162      * <em>interface object</em> with the <a href="#getInterface">
163      * dbus.getInterface()</a> method. It will automatically map an interface
164      * of a service that supports the <em>org.freedesktop.DBus.Introspectable
165      * </em> interface to a JavaSript object. If the service does not support
166      * introspection, you need to use the <a href="#getMethod">dbus.getMethod()
167      * </a> and <a href="#getSignal">dbus.getSignal()</a> methods directly to
168      * use the service.
169      * <pre class="code">
170      * <caption>The imaginary Notes interface specification</caption>
171      *
172      * &lt;?xml version="1.0" encoding="UTF-8"?>
173      * &lt;node name="/org/movial/Notes">
174      *   &lt;interface name="org.movial.Notes">
175      *
176      *     &lt;!--
177      *       Adds a new note from a dictionary. The key "topic" is a string
178      *       to define what the note is about, the rest of the keys are freeform
179      *       content shown as a definition list in the note. Returns an ID to
180      *       identify the note later.
181      *      -->
182      *     &lt;method name="AddNote">
183      *       &lt;arg name="note_content" type="a{sv}" direction="in" />
184      *       &lt;arg name="note_id" type="u" direction="out" />
185      *     &lt;/method>
186      *
187      *     &lt;!-- Removes the note specified by the id. -->
188      *     &lt;method name="RemoveNote">
189      *       &lt;arg name="note_id" type="u" direction="in" />
190      *     &lt;/method>
191      *
192      *     &lt;!-- Emitted when a note is added -->
193      *     &lt;signal name="NoteAdded">
194      *       &lt;arg name="note_id" type="u" direction="out" />
195      *       &lt;arg name="note_content" type="a{sv}" direction="out" />
196      *     &lt;/signal>
197      *
198      *     &lt;!-- Emitted when a note is removed -->
199      *     &lt;signal name="NoteRemoved">
200      *       &lt;arg name="note_id" type="u" direction="out" />
201      *     &lt;/signal>
202      *
203      *   &lt;/interface>
204      * &lt;/node>
205      *
206      * </pre>
207      */
208     DBus = function() {
209
210         ep("UniversalXPConnect");
211         this.dbus = cc["@movial.com/dbus/service;1"].getService();
212         this.dbus = this.dbus.QueryInterface(Components.interfaces.IDBusService);
213
214         // Mirror static properties
215         DBus.prototype.SYSTEM = this.dbus.SYSTEM;
216         DBus.prototype.SESSION = this.dbus.SESSION;
217
218     };
219
220     // Methods for non-variant and non-automatic type conversions
221
222     /**
223      * Converts the given value to a D-Bus UInt32
224      * @function
225      * @param val Value to convert
226      * @returns An object encapsulating a D-Bus value. It is not possible to
227      * convert the return value back to the original value.
228      */
229     DBus.prototype.UInt32 = makeVariantMaker("Uint32");
230
231     /**
232      * Converts the given value to a D-Bus Int32
233      * @function
234      * @param val Value to convert
235      * @returns An object encapsulating a D-Bus value. It is not possible to
236      * convert the return value back to the original value.
237      */
238     DBus.prototype.Int32 = makeVariantMaker("Int32");
239
240     /**
241      * Converts the given value to a D-Bus UInt16
242      * @function
243      * @param val Value to convert
244      * @returns An object encapsulating a D-Bus value. It is not possible to
245      * convert the return value back to the original value.
246      */
247     DBus.prototype.UInt16 = makeVariantMaker("Uint16");
248
249     /**
250      * Converts the given value to a D-Bus Int16
251      * @function
252      * @param val Value to convert
253      * @returns An object encapsulating a D-Bus value. It is not possible to
254      * convert the return value back to the original value.
255      */
256     DBus.prototype.Int16 = makeVariantMaker("Int16");
257
258     /**
259      * Converts the given value to a D-Bus UInt64
260      * @function
261      * @param val Value to convert
262      * @returns An object encapsulating a D-Bus value. It is not possible to
263      * convert the return value back to the original value.
264      */
265     DBus.prototype.UInt64 = makeVariantMaker("Uint64");
266
267     /**
268      * Converts the given value to a D-Bus Int64
269      * @function
270      * @param val Value to convert
271      * @returns An object encapsulating a D-Bus value. It is not possible to
272      * convert the return value back to the original value.
273      */
274     DBus.prototype.Int64 = makeVariantMaker("Int64");
275
276     /**
277      * Converts the given value to a D-Bus Byte
278      * @function
279      * @param val Value to convert
280      * @returns An object encapsulating a D-Bus value. It is not possible to
281      * convert the return value back to the original value.
282      */
283     DBus.prototype.Byte = makeVariantMaker("Int8");
284
285     /**
286      * Converts the given value to a D-Bus ObjectPath
287      * @function
288      * @param val Value to convert
289      * @returns An object encapsulating a D-Bus value. It is not possible to
290      * convert the return value back to the original value.
291      */
292     DBus.prototype.ObjectPath = function(val) {
293       ep("UniversalXPConnect");
294       var carrier = cc["@movial.com/dbus/datacarrier;1"].createInstance(ci.IDBusDataCarrier);
295       carrier.type = "o";
296       carrier.value = val;
297       return carrier;
298     };
299
300     /**
301      * Converts the given value to a D-Bus Signature
302      * @function
303      * @param val Value to convert
304      * @returns An object encapsulating a D-Bus value. It is not possible to
305      * convert the return value back to the original value.
306      */
307     DBus.prototype.Signature = function(val) {
308       ep("UniversalXPConnect");
309       var carrier = cc["@movial.com/dbus/datacarrier;1"].createInstance(ci.IDBusDataCarrier);
310       carrier.type = "g";
311       carrier.value = val;
312       return carrier;
313     };
314
315     /**
316      * Converts the given value to a D-Bus Variant
317      * @function
318      * @param val Value to convert
319      * @returns An object encapsulating a D-Bus value. It is not possible to
320      * convert the return value back to the original value.
321      */
322     DBus.prototype.Variant = function(sig, val) {
323       ep("UniversalXPConnect");
324       var carrier = cc["@movial.com/dbus/datacarrier;1"].createInstance(ci.IDBusDataCarrier);
325       carrier.type = "v";
326       carrier.signature = sig;
327       carrier.value = val;
328       return carrier;
329     };
330
331     /**
332      * Converts the given value to a D-Bus Struct
333      * @function
334      * @param val Value to convert
335      * @returns An object encapsulating a D-Bus value. It is not possible to
336      * convert the return value back to the original value.
337      */
338     DBus.prototype.Struct = function(val) {
339       ep("UniversalXPConnect");
340       var carrier = cc["@movial.com/dbus/datacarrier;1"].createInstance(ci.IDBusDataCarrier);
341       carrier.type = "r";
342       carrier.value = val;
343       return carrier;
344     };
345
346     // Lowlevel Bridge API methods
347
348     /**
349      *  Acquire a D-Bus Method object.
350      *  @description <p>D-Bus method calls are handled as objects in the
351      *  Bridge. You can instantiate a method object once and reuse it for
352      *  multiple calls of the method. Method objects have two properties to
353      *  wich you can set callback functions, <em>onreply</em> and
354      *  <em>onerror</em>. The arguments of the callback functions depend
355      *  on the interface specification.
356      *  <p>The <em>onreply</em> callback is called when the method call has
357      *  been made successfully and an reply message has beed received. The
358      *  arguments of the callback depend on the interface specification.
359      *  <p>The <em>onerror</em> callback is called when either the method
360      *  call could not be made (due to wrong parameters or for other reasons)
361      *  or the method call has been made, but resulted in an error message to
362      *  be received.
363      *  <p>By default, the method calls are made asynchronously. If a
364      *  synchronous method call is desired (so that the method call waits for
365      *  a reply before returning), the <em>async</em> property can be set
366      *  to <em>false</em>. As the call depends on reply from a separate
367      *  process and can potentially take long to execute, synchronous calls
368      *  should be avoided in order to not block the calling process (and thus
369      *  possibly cause an unresponsive UI).
370      *  @example
371      *  <caption>Using the signal objects</caption>
372      *  var addNote = dbus.getMethod(dbus.SESSION, 'org.movial.Notes',
373      *                                '/org/movial/Notes', 'AddNote');
374      *  var noteID = -1;
375      *  addNote.onreply = function(id){
376      *    // The example reply message has signature of 'u'
377      *    noteID = id;
378      *  };
379      *  addNote.onerror = function(error, message) {
380      *    // Error callbacks always have a name as the first argument and
381      *    // possibly a descriptive message or other arguments following it.
382      *    var msgstr = error;
383      *    if (message) {
384      *      msgstr += ': ' + message;
385      *    }
386      *    alert('Adding a note failed!\n' + msgstr);
387      *  };
388      *  // The signature of this method is 'a{sv}'. Dicts are mapped to
389      *  // JavaScript Object class so we construct the argument using the
390      *  // object construction notation. Variants are a container type which
391      *  // holds any single complete type inside, but in the Bridge API they
392      *  // are usually simply represented by their value.
393      *  addNote( { "topic": "hot", "amount": 42 } );
394      *
395      *  (... later ...)
396      *
397      *  var removeNote = dbus.getMethod(dbus.SESSION, 'org.movial.Notes',
398      *                                  '/org/movial/Notes', 'RemoveNote');
399      *  // This time we choose not to care if it succeeds or not so we don't
400      *  // supply onreply or onerror functions. This allows the actual D-Bus
401      *  // message to be sent as "no reply expected" message.
402      *  removeNote(noteID);
403      *  @function
404      *  @param bus dbus.SESSION or dbus.SYSTEM
405      *  @param {String} dest destination service
406      *  @param {String} path path of the object implementing the interface
407      *  @param {String} method_name name of the method to acquire
408      *  @param {String} inter interface to acquire
409      *  @param {String} signature signature of the method, may be null
410      *  @param {Object} data object to use as <em>this</em> in callbacks
411      *  @returns {DBus.Method} method object or null on errors
412      */
413     DBus.prototype.getMethod = function(bustype,
414                                         destination,
415                                         object_path,
416                                         method_name,
417                                         inter,
418                                         signature,
419                                         user_data) {
420
421         /**
422          * @private
423          * A wrapper function for method calls
424          * Executes the actual call through the XPCOM interface
425          */
426         var method = function() {
427             ep("UniversalXPConnect");
428             try {
429               // The Array.prototype dance converts the "sort of Array but not
430               // quite" 'arguments' to a real Array object
431               method.dbusmethod.doCall(Array.prototype.slice.call(arguments),
432                                        arguments.length);
433             } catch (e) {
434               if (method._onerror) {
435                 method._onerror.apply(method.user_data, [e.toString()]);
436               }
437             }
438         };
439
440         // Store the user specified "this" object
441         method.user_data = user_data;
442
443         // Create the XPCOM method object
444         ep("UniversalXPConnect");
445         method.dbusmethod = this.dbus.getMethod(bustype,
446                                                 destination,
447                                                 object_path,
448                                                 method_name,
449                                                 inter,
450                                                 signature);
451
452         /* XXX: Hmm? onreply and onerror are undefined here, no? */
453         method.dbusmethod.onReply = unWrap(method.onreply, method.user_data);
454         method.dbusmethod.onError = unWrap(method.onerror, method.user_data);
455
456         // Watch the onreply property and assign the callback through our
457         // wrapper
458         method.watch("onreply", function(id, oldval, newval) {
459             ep("UniversalXPConnect");
460             method.dbusmethod.onReply = unWrap(newval, method.user_data);
461         });
462
463         // Ditto for onerror
464         method.watch("onerror", function(id, oldval, newval) {
465             ep("UniversalXPConnect");
466             method.dbusmethod.onError = unWrap(newval, method.user_data);
467             // We need to shadow the property for some reason...
468             method._onerror = newval;
469         });
470
471         // Mirror the async property
472         method.async = true;
473         method.watch("async", function(id, oldval, newval) {
474             ep("UniversalXPConnect");
475             method.dbusmethod.async = newval;
476         });
477
478         return method;
479     };
480
481     /**
482      *  Acquire a D-Bus Signal object.
483      *  @description <p>D-Bus signals are handled as objects in the Bridge. You
484      *  can instantiate a signal object once and reuse it for multiple sessions
485      *  of listening to the signal.
486      *  <p> The <em>enabled</em> property controls whether the signal is being
487      *  listened to or not. In D-Bus terms, setting <em>enabled</em> to true
488      *  adds a match rule with the specified arguments and setting it to false
489      *  removes it.
490      *  <p>The <em>onemit</em> property should be the function to call when
491      *  when the signal is emitted on the message bus. The arguments of the
492      *  callback depend on the interface specification. You can provide an
493      *  object as the last argument for <em>getSignal()</em> which will be
494      *  used as the <em>this</em> object in the callback.
495      *  @example
496      *  <caption>Using the signal objects</caption>
497      *  var noteAdded = dbus.getSignal(dbus.SESSION,
498      *                                'org.movial.Notes', 'NoteAdded',
499      *                                null, null, null);
500      *  noteAdded.onemit = function(args) {
501      *    // The signature of this signal is 'a{sv}'. 'args' is thus an object
502      *    // and we can use the . accessor to get the values (variants are
503      *    // always presented by their values in callbacks) since we know the
504      *    // hash keys.
505      *    alert(args.topic + "\n" + args.amount);
506      *  };
507      *  noteAdded.enabled = true;
508      *
509      *  (... later ...)
510      *
511      *  // We are temporarily not interested in the signal so we disable it
512      *  noteAdded.enabled = false;
513      *  @function
514      *  @param bus dbus.SESSION or dbus.SYSTEM
515      *  @param {String} inter interface where the signal is
516      *  @param {String} signal_name name of the signal
517      *  @param {String} sender sender to filter by, usually null.
518      *  @param {String} path object path to filter by, usually null.
519      *  @param {Object} data object to use as <em>this</em> in the callback
520      *  @returns {DBus.Signal} signal object or null on errors
521      */
522     DBus.prototype.getSignal = function(bustype,
523                                         inter,
524                                         signal_name,
525                                         sender,
526                                         object_path,
527                                         user_data) {
528         var signal = {};
529
530         // Create the XPCOM signal object
531         ep("UniversalXPConnect");
532         signal.dbussignal = this.dbus.getSignal(bustype,
533                                                 inter,
534                                                 signal_name,
535                                                 sender,
536                                                 object_path);
537
538         // Store user-specified "this" for callbacks
539         signal.user_data = user_data;
540
541         // XXX: ummm.... onemit == undefined?
542         signal.dbussignal.onEmit = unWrap(signal.onemit, signal.user_data);
543
544         // Watch the onemit property for wrapping
545         signal.watch("onemit", function(id, oldval, newval) {
546             ep("UniversalXPConnect");
547             signal.dbussignal.onEmit = unWrap(newval, signal.user_data);
548         });
549
550         // Watch the enabled property for wrapping
551         signal.enabled = false;
552         signal.watch("enabled", function(id, oldval, newval) {
553             ep("UniversalXPConnect");
554             signal.dbussignal.enabled = newval;
555         });
556
557         return signal;
558     };
559
560     /**
561      *  Emit a signal.
562      *  @description <p>Sends a signal message to the D-Bus.
563      *  @example
564      *  var notifyArgs = { "topic" : "hot", "amount" : 42 };
565      *  var nodeID = generateNewIDForNote();
566      *  if (!dbus.emitSignal(dbus.SESSION, '/org/movial/Notes',
567      *                       'org.movial.Notes', 'NoteAdded',
568      *                       'ua{sv}', noteID, notifyArgs)) {
569      *    alert("Signal emission failed!");
570      *  };
571      *  @function
572      *  @param bus dbus.SESSION or dbus.SYSTEM
573      *  @param {String} path object path that is sending the signal
574      *  @param {String} inter interface where the signal is
575      *  @param {String} signal_name name of the signal
576      *  @param {String} signature signature of the signal, may be null
577      *  @param arg1 first argument for the signal
578      *  @param ...
579      *  @param argN last argument for the signal
580      *  @returns Boolean indicating if the emission was done succesfully
581      */
582     DBus.prototype.emitSignal = function() {
583         var args = Array.prototype.splice.call(arguments, 5);
584         ep("UniversalXPConnect");
585         this.dbus.emitSignal(arguments[0], arguments[1],
586                              arguments[2], arguments[3],
587                              arguments[4], args, args.length);
588     };
589
590 }
591
592 /**
593  * @private
594  * Parses the interface description XML to a JS object
595  */
596 DBus.prototype.parseInterface = function(doc, bus, dest, path, inter){
597     var ret = {};
598     var temp = doc.getElementsByTagName("interface");
599     //interesting interface is last
600     for( var i = temp.length - 1; i >=0; i--){
601         if( temp[i].getAttribute("name") != inter ) { continue; }
602         //method name
603         var methods = temp[i].getElementsByTagName("method");
604         for ( var j = 0, jl = methods.length; j < jl; j ++){
605             var name = methods[j].getAttribute("name");
606             //params
607             var args = methods[j].getElementsByTagName("arg");
608             var type = [];
609
610             for( var z = 0, zl = args.length; z < zl; z ++){
611
612                 if(  args[z].getAttribute("direction") == "in"){
613                     type.push(args[z].getAttribute("type") );
614                 }
615
616             }
617             ret[name] = dbus.getMethod(bus, dest, path,
618                                        name, inter, type.join(""), ret );
619         }
620
621         //signals
622         var signals = temp[i].getElementsByTagName("signal");
623         for ( var j = 0, jl = signals.length; j < jl; j ++){
624             name = signals[j].getAttribute("name");
625             ret[name] = dbus.getSignal(bus,
626                                        inter, name, null,
627                                        this.object_path, ret);
628             ret[name].enabled = false;
629             ret[name].onemit = null;
630         }
631         ret.xml = (new XMLSerializer()).serializeToString(doc);
632         return ret;
633         // break; //interface found
634     }
635     return null;
636 };
637
638 /**
639  *  Acquire an interface object through Introspection.
640  *  <p>Uses the <em>Introspect</em> method on the standard
641  *  <em>org.freedesktop.DBus.Introspectable</em> interface to map a given
642  *  D-Bus interface to a JavaScript object. All methods and signals of that
643  *  interface will be available as members of the object. You can refer to the
644  *  <a href="#getMethod">getMethod()</a> and
645  *  <a href="#getSignal">getSignal()</a> documentation to learn how to use the
646  *  method and signal objects. The produced object is provided as <em>this</em>
647  *  in the methods and signals.
648  *  <p>Note that introspecting is not done asynchronously (to avoid requiring
649  *  a callback to retrieve the interface object) so the <em>getInterface()</em>
650  *  call will block until the service responds.
651  *  @example
652  *  <caption>Using the interface objects</caption>
653  *  var notes = dbus.getInterface(dbus.SESSION,
654  *                                'org.movial.Notes', '/org/movial/Notes',
655  *                                'org.movial.Notes');
656  *
657  *  // Set up listening to the "NoteAdded" signal.
658  *  notes.NoteAdded.onemit = function(args) {
659  *    // The signature of this signal is 'a{sv}'. 'args' is thus an object
660  *    // and we can use the . accessor to get the values (variants are
661  *    // always presented by their values in callbacks) since we know the
662  *    // hash keys.
663  *    alert(args.topic + "\n" + args.amount);
664  *  };
665  *  notes.NoteAdded.enabled = true;
666  *
667  *  // Add a note
668  *  var noteID = -1;
669  *  notes.AddNote.onreply = function(id){
670  *   // The example reply message has signature of 'u'
671  *    noteID = id;
672  *  };
673  *  notes.AddNote.onerror = function(error, message) {
674  *    // Error callbacks always have a name as the first argument and
675  *    // possibly a descriptive message or other arguments following it.
676  *    var msgstr = error;
677  *    if (message) {
678  *      msgstr += ': ' + message;
679  *    }
680  *    alert('Adding a note failed!\n' + msgstr);
681  *  };
682  *  // The signature of this method is 'a{sv}'. Dicts are mapped to
683  *  // JavaScript Object class so we construct the argument using the
684  *  // object construction notation. Variants are a container type which
685  *  // holds any single complete type inside, but in the Bridge API they
686  *  // are usually simply represented by their value.
687  *  notes.AddNote( { "topic": "hot", "amount": 42 } );
688  *
689  *  (... later ...)
690  *
691  *  // Remove the note we added earlier
692  *  notes.RemoveNote( noteID );
693  *  @param bus dbus.SESSION or dbus.SYSTEM
694  *  @param {String} dest destination service
695  *  @param {String} path object path
696  *  @param {String} inter interface to acquire
697  *  @returns {DBus.Interface} an object representing a D-Bus interface
698  */
699 DBus.prototype.getInterface = function(bus, dest, path, inter){
700     var doc = null;
701     var introspect = dbus.getMethod(bus, dest, path,
702                                     "Introspect",
703                                     "org.freedesktop.DBus.Introspectable" );
704     /**
705      * @private
706      */
707     introspect.onreply = function(s){
708         doc = s.replace(/^\s*|\s*$/g,"");
709     };
710     /**
711      * @private
712      */
713     introspect.onerror = function(s){
714         doc = null;
715     };
716     introspect.async = false;
717     introspect();
718
719     if (doc === null) {
720         return null;
721     }
722
723     doc = (new DOMParser()).parseFromString(doc, "text/xml");
724
725     return dbus.parseInterface(doc, bus, dest, path, inter);
726 };
727
728 /**
729  * Conversion functions for default conversion types
730  * These are offered mainly just for completeness, there is usually no point in
731  * actually using them...
732  */
733
734 /**
735  * Converts the given value to a D-Bus Boolean
736  * @param val Value to convert
737  * @returns An object encapsulating a D-Bus value. It is not possible to
738  * convert the return value back to the original value.
739  */
740 DBus.prototype.Boolean = function (val) { return Boolean(val); };
741
742 /**
743  * Converts the given value to a D-Bus Double (the JS Number type)
744  * @param val Value to convert
745  * @returns An object encapsulating a D-Bus value. It is not possible to
746  * convert the return value back to the original value.
747  */
748 DBus.prototype.Double = function (val) { return Number(val); };
749
750 /**
751  * Converts the given value to a D-Bus String
752  * @param val Value to convert
753  * @returns An object encapsulating a D-Bus value. It is not possible to
754  * convert the return value back to the original value.
755  */
756 DBus.prototype.String = function (val) { return String(val); };
757
758 /**
759  * Converts the given value to a D-Bus Array
760  * @param val Value to convert
761  * @returns An object encapsulating a D-Bus value. It is not possible to
762  * convert the return value back to the original value.
763  */
764 DBus.prototype.Array = function (val) { return val; };
765
766 /**
767  * Converts the given value to a D-Bus Dict
768  * @param val Value to convert
769  * @returns An object encapsulating a D-Bus value. It is not possible to
770  * convert the return value back to the original value.
771  */
772 DBus.prototype.Dict = function (val) { return val; };
773
774 // Instantiate the Bridge API singleton
775 try {
776   window.dbus = new DBus();
777 } catch (e) {
778   window.dbus = null;
779 }