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