dbus-gobject.c

00001 /* -*- mode: C; c-file-style: "gnu" -*- */
00002 /* dbus-gobject.c Exporting a GObject remotely
00003  *
00004  * Copyright (C) 2003, 2004, 2005 Red Hat, Inc.
00005  * Copyright (C) 2005 Nokia
00006  *
00007  * Licensed under the Academic Free License version 2.1
00008  *
00009  * This program is free software; you can redistribute it and/or modify
00010  * it under the terms of the GNU General Public License as published by
00011  * the Free Software Foundation; either version 2 of the License, or
00012  * (at your option) any later version.
00013  *
00014  * This program is distributed in the hope that it will be useful,
00015  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00016  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017  * GNU General Public License for more details.
00018  *
00019  * You should have received a copy of the GNU General Public License
00020  * along with this program; if not, write to the Free Software
00021  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00022  *
00023  */
00024 
00025 #include <config.h>
00026 #include <gobject/gvaluecollector.h>
00027 #include <dbus/dbus-glib.h>
00028 #include <dbus/dbus-glib-lowlevel.h>
00029 #include "dbus-gtest.h"
00030 #include "dbus-gutils.h"
00031 #include "dbus-gobject.h"
00032 #include "dbus-gsignature.h"
00033 #include "dbus-gvalue.h"
00034 #include "dbus-gmarshal.h"
00035 #include "dbus-gvalue-utils.h"
00036 #include <string.h>
00037 
00038 typedef struct
00039 {
00040   char *default_iface;
00041   GType code_enum;
00042 } DBusGErrorInfo;
00043 
00044 static GStaticRWLock globals_lock = G_STATIC_RW_LOCK_INIT;
00045 static GHashTable *marshal_table = NULL;
00046 static GData *error_metadata = NULL;
00047 
00048 static char*
00049 uscore_to_wincaps (const char *uscore)
00050 {
00051   const char *p;
00052   GString *str;
00053   gboolean last_was_uscore;
00054 
00055   last_was_uscore = TRUE;
00056   
00057   str = g_string_new (NULL);
00058   p = uscore;
00059   while (p && *p)
00060     {
00061       if (*p == '-' || *p == '_')
00062         {
00063           last_was_uscore = TRUE;
00064         }
00065       else
00066         {
00067           if (last_was_uscore)
00068             {
00069               g_string_append_c (str, g_ascii_toupper (*p));
00070               last_was_uscore = FALSE;
00071             }
00072           else
00073             g_string_append_c (str, *p);
00074         }
00075       ++p;
00076     }
00077 
00078   return g_string_free (str, FALSE);
00079 }
00080 
00081 static const char *
00082 string_table_next (const char *table)
00083 {
00084   return (table + (strlen (table) + 1));
00085 }
00086 
00087 static const char *
00088 string_table_lookup (const char *table, int index)
00089 {
00090   const char *ret;
00091 
00092   ret = table;
00093 
00094   while (index--)
00095     ret = string_table_next (ret);
00096 
00097   return ret;
00098 }
00099 
00100 static const char *
00101 get_method_data (const DBusGObjectInfo *object,
00102                  const DBusGMethodInfo *method)
00103 {
00104   return object->data + method->data_offset;
00105 }
00106 
00107 static char *
00108 object_error_domain_prefix_from_object_info (const DBusGObjectInfo *info)
00109 {
00110   /* FIXME */
00111   return NULL;
00112 }
00113 
00114 static char *
00115 object_error_code_from_object_info (const DBusGObjectInfo *info, GQuark domain, gint code)
00116 {
00117   /* FIXME */
00118   return NULL;
00119 }
00120 
00121 static const char *
00122 method_interface_from_object_info (const DBusGObjectInfo *object,
00123                               const DBusGMethodInfo *method)
00124 {
00125   return string_table_lookup (get_method_data (object, method), 0);
00126 }
00127 
00128 static const char *
00129 method_name_from_object_info (const DBusGObjectInfo *object,
00130                               const DBusGMethodInfo *method)
00131 {
00132   return string_table_lookup (get_method_data (object, method), 1);
00133 }
00134 
00135 static const char *
00136 method_arg_info_from_object_info (const DBusGObjectInfo *object,
00137                                   const DBusGMethodInfo *method)
00138 {
00139   return string_table_lookup (get_method_data (object, method), 3);/*RB was 2*/
00140 }
00141 
00142 typedef enum
00143 {
00144   RETVAL_NONE,    
00145   RETVAL_NOERROR,    
00146   RETVAL_ERROR
00147 } RetvalType;
00148 
00149 static const char *
00150 arg_iterate (const char    *data,
00151              const char   **name,
00152              gboolean      *in,
00153              gboolean      *constval,
00154              RetvalType    *retval,
00155              const char   **type)
00156 {
00157   gboolean inarg;
00158 
00159   if (name)
00160     *name = data;
00161 
00162   data = string_table_next (data);
00163   switch (*data)
00164     {
00165     case 'I':
00166       inarg = TRUE;
00167       break;
00168     case 'O':
00169       inarg = FALSE;
00170       break;
00171     default:
00172       g_warning ("invalid arg direction '%c'", *data);
00173       inarg = FALSE;
00174       break;
00175     }
00176   if (in)
00177     *in = inarg;
00178 
00179   if (!inarg)
00180     {
00181       data = string_table_next (data);
00182       switch (*data)
00183         {
00184         case 'F':
00185           if (constval)
00186             *constval = FALSE;
00187           break;
00188         case 'C':
00189           if (constval)
00190             *constval = TRUE;
00191           break;
00192         default:
00193           g_warning ("invalid arg const value '%c'", *data);
00194           break;
00195         }
00196       data = string_table_next (data);
00197       switch (*data)
00198         {
00199         case 'N':
00200           if (retval)
00201             *retval = RETVAL_NONE;
00202           break;
00203         case 'E':
00204           if (retval)
00205             *retval = RETVAL_ERROR;
00206           break;
00207         case 'R':
00208           if (retval)
00209             *retval = RETVAL_NOERROR;
00210           break;
00211         default:
00212           g_warning ("invalid arg ret value '%c'", *data);
00213           break;
00214         }
00215     }
00216   else
00217     {
00218       if (constval)
00219         *constval = FALSE;
00220       if (retval)
00221         *retval = FALSE;
00222     }
00223   
00224   data = string_table_next (data);
00225   if (type)
00226     *type = data;
00227 
00228   return string_table_next (data);
00229 }
00230 
00231 static char *
00232 method_dir_signature_from_object_info (const DBusGObjectInfo *object,
00233                                        const DBusGMethodInfo *method,
00234                                        gboolean               in)
00235 {
00236   const char *arg;
00237   GString *ret;
00238 
00239   arg = method_arg_info_from_object_info (object, method);
00240 
00241   ret = g_string_new (NULL);
00242 
00243   while (*arg)
00244     {
00245       const char *name;
00246       gboolean arg_in;
00247       const char *type;
00248 
00249       arg = arg_iterate (arg, &name, &arg_in, NULL, NULL, &type);
00250 
00251       if (arg_in == in)
00252         g_string_append (ret, type);
00253     }
00254 
00255   return g_string_free (ret, FALSE);
00256 }
00257 
00258 static char *
00259 method_input_signature_from_object_info (const DBusGObjectInfo *object,
00260                                          const DBusGMethodInfo *method)
00261 {
00262   return method_dir_signature_from_object_info (object, method, TRUE);
00263 }
00264 
00265 static char *
00266 method_output_signature_from_object_info (const DBusGObjectInfo *object,
00267                                           const DBusGMethodInfo *method)
00268 {
00269   return method_dir_signature_from_object_info (object, method, FALSE);
00270 }
00271 
00272 static const char *
00273 propsig_iterate (const char *data, const char **iface, const char **name)
00274 {
00275   *iface = data;
00276 
00277   data = string_table_next (data);
00278   *name = data;
00279 
00280   return string_table_next (data);
00281 }
00282 
00283 static GQuark
00284 dbus_g_object_type_dbus_metadata_quark (void)
00285 {
00286   static GQuark quark;
00287 
00288   if (!quark)
00289     quark = g_quark_from_static_string ("DBusGObjectTypeDBusMetadataQuark");
00290   return quark;
00291 }
00292 
00293 static GList *
00294 lookup_object_info (GObject *object)
00295 {
00296   GType *interfaces, *p;
00297   GList *info_list = NULL;
00298   const DBusGObjectInfo *info;
00299   GType classtype;
00300 
00301   interfaces = g_type_interfaces (G_TYPE_FROM_INSTANCE (object), NULL);
00302 
00303   for (p = interfaces; *p != 0; p++)
00304     {
00305       info = g_type_get_qdata (*p, dbus_g_object_type_dbus_metadata_quark ());
00306       if (info != NULL && info->format_version >= 0)
00307           info_list = g_list_prepend (info_list, (gpointer) info);
00308     }
00309 
00310   g_free (interfaces);
00311 
00312   for (classtype = G_TYPE_FROM_INSTANCE (object); classtype != 0; classtype = g_type_parent (classtype))
00313     {
00314       info = g_type_get_qdata (classtype, dbus_g_object_type_dbus_metadata_quark ());
00315       if (info != NULL && info->format_version >= 0)
00316           info_list = g_list_prepend (info_list, (gpointer) info);
00317     }
00318 
00319   /* if needed only:
00320   return g_list_reverse (info_list);
00321   */
00322   
00323   return info_list;
00324 }
00325 
00326 static void
00327 gobject_unregister_function (DBusConnection  *connection,
00328                              void            *user_data)
00329 {
00330   GObject *object;
00331 
00332   object = G_OBJECT (user_data);
00333 
00334   /* FIXME */
00335 
00336 }
00337 
00338 typedef struct
00339 {
00340   GString *xml;
00341   GType gtype;
00342   const DBusGObjectInfo *object_info;
00343 } DBusGLibWriteIterfaceData;
00344 
00345 typedef struct
00346 {
00347   GSList *methods;
00348   GSList *signals;
00349   GSList *properties;
00350 } DBusGLibWriteInterfaceValues;
00351 
00352 static void
00353 write_interface (gpointer key, gpointer val, gpointer user_data)
00354 {
00355   const char *name;
00356   GSList *methods;
00357   GSList *signals;
00358   GSList *properties;
00359   GString *xml;
00360   const DBusGObjectInfo *object_info;
00361   DBusGLibWriteIterfaceData *data;
00362   DBusGLibWriteInterfaceValues *values;
00363 
00364   name = key;
00365 
00366   values = val;
00367   methods = values->methods;
00368   signals = values->signals;
00369   properties = values->properties;
00370 
00371   data = user_data;
00372   xml = data->xml;
00373   object_info = data->object_info;
00374 
00375   g_string_append_printf (xml, "  <interface name=\"%s\">\n", name);
00376 
00377   /* FIXME: recurse to parent types ? */
00378   for (; methods; methods = methods->next)
00379     {
00380       DBusGMethodInfo *method;
00381       const char *args;
00382       method = methods->data;
00383 
00384       g_string_append_printf (xml, "    <method name=\"%s\">\n",
00385                               method_name_from_object_info (object_info, method));
00386 
00387       args = method_arg_info_from_object_info (object_info, method);
00388 
00389       while (*args)
00390         {
00391           const char *name;
00392           gboolean arg_in;
00393           const char *type;
00394           
00395           args = arg_iterate (args, &name, &arg_in, NULL, NULL, &type);
00396 
00397           /* FIXME - handle container types */
00398           g_string_append_printf (xml, "      <arg name=\"%s\" type=\"%s\" direction=\"%s\"/>\n",
00399                                   name, type, arg_in ? "in" : "out");
00400 
00401         }
00402       g_string_append (xml, "    </method>\n");
00403 
00404     }
00405   g_slist_free (values->methods);
00406 
00407   for (; signals; signals = signals->next)
00408     {
00409       guint id;
00410       guint arg;
00411       const char *signame;
00412       GSignalQuery query;
00413       char *s;
00414 
00415       signame = signals->data;
00416 
00417       s = _dbus_gutils_wincaps_to_uscore (signame);
00418       
00419       id = g_signal_lookup (s, data->gtype);
00420       g_assert (id != 0);
00421 
00422       g_signal_query (id, &query);
00423       g_assert (query.return_type == G_TYPE_NONE);
00424 
00425       g_string_append_printf (xml, "    <signal name=\"%s\">\n", signame);
00426 
00427       for (arg = 0; arg < query.n_params; arg++)
00428         {
00429           char *dbus_type = _dbus_gtype_to_signature (query.param_types[arg]);
00430 
00431           g_assert (dbus_type != NULL);
00432 
00433           g_string_append (xml, "      <arg type=\"");
00434           g_string_append (xml, dbus_type);
00435           g_string_append (xml, "\"/>\n");
00436           g_free (dbus_type);
00437         }
00438 
00439       g_string_append (xml, "    </signal>\n");
00440       g_free (s);
00441     }
00442   g_slist_free (values->signals);
00443 
00444   for (; properties; properties = properties->next)
00445     {
00446       const char *propname;
00447       GParamSpec *spec;
00448       char *dbus_type;
00449       gboolean can_set;
00450       gboolean can_get;
00451       char *s;
00452 
00453       propname = properties->data;
00454       spec = NULL;
00455 
00456       s = _dbus_gutils_wincaps_to_uscore (propname);
00457 
00458       spec = g_object_class_find_property (g_type_class_peek (data->gtype), s);
00459       g_assert (spec != NULL);
00460       g_free (s);
00461       
00462       dbus_type = _dbus_gtype_to_signature (G_PARAM_SPEC_VALUE_TYPE (spec));
00463       g_assert (dbus_type != NULL);
00464       
00465       can_set = ((spec->flags & G_PARAM_WRITABLE) != 0 &&
00466                  (spec->flags & G_PARAM_CONSTRUCT_ONLY) == 0);
00467       
00468       can_get = (spec->flags & G_PARAM_READABLE) != 0;
00469       
00470       if (can_set || can_get)
00471         {
00472           g_string_append_printf (xml, "    <property name=\"%s\" ", propname);
00473           g_string_append (xml, "type=\"");
00474           g_string_append (xml, dbus_type);
00475           g_string_append (xml, "\" access=\"");
00476 
00477           if (can_set && can_get)
00478             g_string_append (xml, "readwrite");
00479           else if (can_get)
00480             g_string_append (xml, "read");
00481           else
00482             {
00483               g_assert (can_set);
00484               g_string_append (xml, "write");
00485             }
00486           
00487           g_string_append (xml, "\"/>\n");
00488         }
00489       
00490       g_free (dbus_type);
00491     }
00492   g_slist_free (values->properties);
00493 
00494   g_free (values);
00495   g_string_append (xml, "  </interface>\n");
00496 }
00497 
00498 static DBusGLibWriteInterfaceValues *
00499 lookup_values (GHashTable *interfaces, const char *method_interface)
00500 {
00501   DBusGLibWriteInterfaceValues *values;
00502   if ((values = g_hash_table_lookup (interfaces, (gpointer) method_interface)) == NULL)
00503     {
00504       values = g_new0 (DBusGLibWriteInterfaceValues, 1);
00505       g_hash_table_insert (interfaces, (gpointer) method_interface, values);
00506     }
00507   return values;
00508 }
00509 
00510 static void
00511 introspect_interfaces (GObject *object, GString *xml)
00512 {
00513   GList *info_list;
00514   const GList *info_list_walk;
00515   const DBusGObjectInfo *info;
00516   DBusGLibWriteIterfaceData data;
00517   int i;
00518   GHashTable *interfaces;
00519   DBusGLibWriteInterfaceValues *values;
00520   const char *propsig;
00521 
00522   info_list = lookup_object_info (object);
00523 
00524   g_assert (info_list != NULL);
00525 
00526   /* Gather a list of all interfaces, indexed into their methods */
00527   for (info_list_walk = info_list; info_list_walk != NULL; info_list_walk = g_list_next (info_list_walk))
00528     {
00529       info = (DBusGObjectInfo *) info_list_walk->data;
00530       interfaces = g_hash_table_new (g_str_hash, g_str_equal);
00531       
00532       g_assert (info != NULL);
00533 
00534       for (i = 0; i < info->n_method_infos; i++)
00535         {
00536           const char *method_name;
00537           const char *method_interface;
00538           const char *method_args;
00539           const DBusGMethodInfo *method;
00540 
00541           method = &(info->method_infos[i]);
00542 
00543           method_interface = method_interface_from_object_info (info, method);
00544           method_name = method_name_from_object_info (info, method);
00545           method_args = method_arg_info_from_object_info (info, method);
00546 
00547           values = lookup_values (interfaces, method_interface);
00548           values->methods = g_slist_prepend (values->methods, (gpointer) method);
00549         }
00550 
00551       propsig = info->exported_signals;
00552       while (*propsig)
00553         {
00554           const char *iface;
00555           const char *signame;
00556 
00557           propsig = propsig_iterate (propsig, &iface, &signame);
00558 
00559           values = lookup_values (interfaces, iface);
00560           values->signals = g_slist_prepend (values->signals, (gpointer) signame);
00561         }
00562 
00563       propsig = info->exported_properties;
00564       while (*propsig)
00565         {
00566           const char *iface;
00567           const char *propname;
00568 
00569           propsig = propsig_iterate (propsig, &iface, &propname);
00570 
00571           values = lookup_values (interfaces, iface);
00572           values->properties = g_slist_prepend (values->properties, (gpointer) propname);
00573         }
00574       
00575       memset (&data, 0, sizeof (data));
00576       data.xml = xml;
00577       data.gtype = G_TYPE_FROM_INSTANCE (object);
00578       data.object_info = info;
00579 
00580       g_hash_table_foreach (interfaces, write_interface, &data);
00581       g_hash_table_destroy (interfaces);
00582     }
00583 
00584   g_list_free (info_list);
00585 }
00586 
00587 static DBusHandlerResult
00588 handle_introspect (DBusConnection *connection,
00589                    DBusMessage    *message,
00590                    GObject        *object)
00591 {
00592   GString *xml;
00593   unsigned int i;
00594   DBusMessage *ret;
00595   char **children;
00596   
00597   if (!dbus_connection_list_registered (connection, 
00598                                         dbus_message_get_path (message),
00599                                         &children))
00600     g_error ("Out of memory");
00601   
00602   xml = g_string_new (NULL);
00603 
00604   g_string_append (xml, DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE);
00605   
00606   g_string_append (xml, "<node>\n");
00607 
00608   /* We are introspectable, though I guess that was pretty obvious */
00609   g_string_append_printf (xml, "  <interface name=\"%s\">\n", DBUS_INTERFACE_INTROSPECTABLE);
00610   g_string_append (xml, "    <method name=\"Introspect\">\n");
00611   g_string_append_printf (xml, "      <arg name=\"data\" direction=\"out\" type=\"%s\"/>\n", DBUS_TYPE_STRING_AS_STRING);
00612   g_string_append (xml, "    </method>\n");
00613   g_string_append (xml, "  </interface>\n");
00614 
00615   /* We support get/set/getall properties */
00616   g_string_append_printf (xml, "  <interface name=\"%s\">\n", DBUS_INTERFACE_PROPERTIES);
00617   g_string_append (xml, "    <method name=\"Get\">\n");
00618   g_string_append_printf (xml, "      <arg name=\"interface\" direction=\"in\" type=\"%s\"/>\n", DBUS_TYPE_STRING_AS_STRING);
00619   g_string_append_printf (xml, "      <arg name=\"propname\" direction=\"in\" type=\"%s\"/>\n", DBUS_TYPE_STRING_AS_STRING);
00620   g_string_append_printf (xml, "      <arg name=\"value\" direction=\"out\" type=\"%s\"/>\n", DBUS_TYPE_VARIANT_AS_STRING);
00621   g_string_append (xml, "    </method>\n");
00622   g_string_append (xml, "    <method name=\"Set\">\n");
00623   g_string_append_printf (xml, "      <arg name=\"interface\" direction=\"in\" type=\"%s\"/>\n", DBUS_TYPE_STRING_AS_STRING);
00624   g_string_append_printf (xml, "      <arg name=\"propname\" direction=\"in\" type=\"%s\"/>\n", DBUS_TYPE_STRING_AS_STRING);
00625   g_string_append_printf (xml, "      <arg name=\"value\" direction=\"in\" type=\"%s\"/>\n", DBUS_TYPE_VARIANT_AS_STRING);
00626   g_string_append (xml, "    </method>\n");
00627   g_string_append (xml, "    <method name=\"GetAll\">\n");
00628   g_string_append_printf (xml, "      <arg name=\"interface\" direction=\"in\" type=\"%s\"/>\n", DBUS_TYPE_STRING_AS_STRING);
00629   g_string_append_printf (xml, "      <arg name=\"props\" direction=\"out\" type=\"%s\"/>\n",
00630                           DBUS_TYPE_ARRAY_AS_STRING
00631                           DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
00632                             DBUS_TYPE_STRING_AS_STRING
00633                             DBUS_TYPE_VARIANT_AS_STRING
00634                           DBUS_DICT_ENTRY_END_CHAR_AS_STRING
00635                           );
00636 
00637   g_string_append (xml, "    </method>\n");
00638   g_string_append (xml, "  </interface>\n");
00639   
00640   introspect_interfaces (object, xml);
00641 
00642   /* Append child nodes */
00643   for (i = 0; children[i]; i++)
00644       g_string_append_printf (xml, "  <node name=\"%s\"/>\n",
00645                               children[i]);
00646   
00647   /* Close the XML, and send it to the requesting app */
00648   g_string_append (xml, "</node>\n");
00649 
00650   ret = dbus_message_new_method_return (message);
00651   if (ret == NULL)
00652     g_error ("Out of memory");
00653 
00654   dbus_message_append_args (ret,
00655                             DBUS_TYPE_STRING, &xml->str,
00656                             DBUS_TYPE_INVALID);
00657 
00658   dbus_connection_send (connection, ret, NULL);
00659   dbus_message_unref (ret);
00660 
00661   g_string_free (xml, TRUE);
00662 
00663   dbus_free_string_array (children);
00664   
00665   return DBUS_HANDLER_RESULT_HANDLED;
00666 }
00667 
00668 static DBusMessage*
00669 set_object_property (DBusConnection  *connection,
00670                      DBusMessage     *message,
00671                      DBusMessageIter *iter,
00672                      GObject         *object,
00673                      GParamSpec      *pspec)
00674 {
00675   GValue value = { 0, };
00676   DBusMessage *ret;
00677   DBusMessageIter sub;
00678   DBusGValueMarshalCtx context;
00679 
00680   dbus_message_iter_recurse (iter, &sub);
00681 
00682   context.recursion_depth = 0;
00683   context.gconnection = DBUS_G_CONNECTION_FROM_CONNECTION (connection);
00684   context.proxy = NULL;
00685 
00686   g_value_init (&value, pspec->value_type);
00687   if (_dbus_gvalue_demarshal (&context, &sub, &value, NULL))
00688     {
00689       g_object_set_property (object,
00690                              pspec->name,
00691                              &value);
00692 
00693       g_value_unset (&value);
00694 
00695       ret = dbus_message_new_method_return (message);
00696       if (ret == NULL)
00697         g_error ("out of memory");
00698     }
00699   else
00700     {
00701       ret = dbus_message_new_error (message,
00702                                     DBUS_ERROR_INVALID_ARGS,
00703                                     "Argument's D-BUS type can't be converted to a GType");
00704       if (ret == NULL)
00705         g_error ("out of memory");
00706     }
00707 
00708   return ret;
00709 }
00710 
00711 static DBusMessage*
00712 get_object_property (DBusConnection *connection,
00713                      DBusMessage    *message,
00714                      GObject        *object,
00715                      GParamSpec     *pspec)
00716 {
00717   GType value_gtype;
00718   GValue value = {0, };
00719   gchar *variant_sig;
00720   DBusMessage *ret;
00721   DBusMessageIter iter, subiter;
00722 
00723   ret = dbus_message_new_method_return (message);
00724   if (ret == NULL)
00725     g_error ("out of memory");
00726 
00727 
00728   g_value_init (&value, pspec->value_type);
00729   g_object_get_property (object, pspec->name, &value);
00730 
00731   variant_sig = _dbus_gvalue_to_signature (&value);
00732   if (variant_sig == NULL)
00733     {
00734       value_gtype = G_VALUE_TYPE (&value);
00735       g_warning ("Cannot marshal type \"%s\" in variant", g_type_name (value_gtype));
00736       g_value_unset (&value);
00737       return ret;
00738     }
00739 
00740   dbus_message_iter_init_append (ret, &iter);
00741   if (!dbus_message_iter_open_container (&iter,
00742                                          DBUS_TYPE_VARIANT,
00743                                          variant_sig,
00744                                          &subiter))
00745     {
00746       g_free (variant_sig);
00747       g_value_unset (&value);
00748       return ret;
00749     }
00750 
00751   if (!_dbus_gvalue_marshal (&subiter, &value))
00752     {
00753       dbus_message_unref (ret);
00754       ret = dbus_message_new_error (message,
00755                                     DBUS_ERROR_UNKNOWN_METHOD,
00756                                     "Can't convert GType of object property to a D-BUS type");
00757     }
00758 
00759   dbus_message_iter_close_container (&iter, &subiter);
00760 
00761   g_value_unset (&value);
00762   g_free (variant_sig);
00763 
00764   return ret;
00765 }
00766 
00767 static DBusMessage*
00768 get_all_object_properties (DBusConnection        *connection,
00769                            DBusMessage           *message,
00770                            const DBusGObjectInfo *object_info,
00771                            GObject               *object)
00772 {
00773   DBusMessage *ret;
00774   DBusMessageIter iter_ret;
00775   DBusMessageIter iter_dict;
00776   DBusMessageIter iter_dict_entry;
00777   DBusMessageIter iter_dict_value;
00778   const char *p;
00779   char *uscore_propname;
00780 
00781   ret = dbus_message_new_method_return (message);
00782   if (ret == NULL)
00783     goto oom;
00784 
00785   dbus_message_iter_init_append (ret, &iter_ret);
00786 
00787   if (!dbus_message_iter_open_container (&iter_ret,
00788                                          DBUS_TYPE_ARRAY,
00789                                          DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
00790                                          DBUS_TYPE_STRING_AS_STRING
00791                                          DBUS_TYPE_VARIANT_AS_STRING
00792                                          DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
00793                                          &iter_dict))
00794     goto oom;
00795 
00796   p = object_info->exported_properties;
00797   while (p != NULL && *p != '\0')
00798     {
00799       const char *prop_ifname;
00800       const char *prop_name;
00801       GParamSpec *pspec;
00802       GType value_gtype;
00803       GValue value = {0, };
00804       gchar *variant_sig;
00805 
00806       prop_ifname = p;
00807 
00808       while (*p != '\0')
00809         p++;
00810       p++;
00811       if (*p == '\0') {
00812         g_warning ("malformed exported_properties in object_info");
00813         break;
00814       }
00815       prop_name = p;
00816       while (*p != '\0')
00817         p++;
00818       p++;
00819 
00820       uscore_propname = _dbus_gutils_wincaps_to_uscore (prop_name);
00821 
00822       pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (object), uscore_propname);
00823       if (pspec == NULL)
00824         {
00825           g_warning ("introspection data references non-existing property %s", uscore_propname);
00826           g_free (uscore_propname);
00827           continue;
00828         }
00829 
00830       g_free (uscore_propname);
00831 
00832       g_value_init (&value, pspec->value_type);
00833       g_object_get_property (object, pspec->name, &value);
00834 
00835       variant_sig = _dbus_gvalue_to_signature (&value);
00836       if (variant_sig == NULL)
00837         {
00838           value_gtype = G_VALUE_TYPE (&value);
00839           g_warning ("Cannot marshal type \"%s\" in variant", g_type_name (value_gtype));
00840           g_value_unset (&value);
00841           continue;
00842         }
00843 
00844       if (!dbus_message_iter_open_container (&iter_dict,
00845                                              DBUS_TYPE_DICT_ENTRY,
00846                                              NULL,
00847                                              &iter_dict_entry))
00848         goto oom;
00849       if (!dbus_message_iter_append_basic (&iter_dict_entry, DBUS_TYPE_STRING, &prop_name))
00850         goto oom;
00851 
00852       if (!dbus_message_iter_open_container (&iter_dict_entry,
00853                                              DBUS_TYPE_VARIANT,
00854                                              variant_sig,
00855                                              &iter_dict_value))
00856         goto oom;
00857 
00858       if (!_dbus_gvalue_marshal (&iter_dict_value, &value))
00859         goto oom;
00860 
00861       if (!dbus_message_iter_close_container (&iter_dict_entry,
00862                                               &iter_dict_value))
00863         goto oom;
00864       if (!dbus_message_iter_close_container (&iter_dict, &iter_dict_entry))
00865         goto oom;
00866 
00867       g_value_unset (&value);
00868       g_free (variant_sig);
00869   }
00870 
00871   if (!dbus_message_iter_close_container (&iter_ret, &iter_dict))
00872     goto oom;
00873 
00874   return ret;
00875 
00876  oom:
00877   g_error ("out of memory");
00878 }
00879 
00880 static gboolean
00881 lookup_object_and_method (GObject      *object,
00882                           DBusMessage  *message,
00883                           const DBusGObjectInfo **object_ret,
00884                           const DBusGMethodInfo **method_ret)
00885 {
00886   const char *interface;
00887   const char *member;
00888   const char *signature;
00889   GList *info_list;
00890   const GList *info_list_walk;
00891   const DBusGObjectInfo *info;
00892   int i;
00893 
00894   interface = dbus_message_get_interface (message);
00895   member = dbus_message_get_member (message);
00896   signature = dbus_message_get_signature (message);
00897 
00898   info_list = lookup_object_info (object);
00899   
00900   for (info_list_walk = info_list; info_list_walk != NULL; info_list_walk = g_list_next (info_list_walk))
00901     {
00902       info = (DBusGObjectInfo *) info_list_walk->data;
00903       *object_ret = info;
00904 
00905       for (i = 0; i < info->n_method_infos; i++)
00906         {
00907           const char *expected_member;
00908           const char *expected_interface;
00909           char *expected_signature;
00910           const DBusGMethodInfo *method;
00911 
00912           method = &(info->method_infos[i]);
00913 
00914           /* Check method interface/name and input signature */ 
00915           expected_interface = method_interface_from_object_info (*object_ret, method);
00916           expected_member = method_name_from_object_info (*object_ret, method);
00917           expected_signature = method_input_signature_from_object_info (*object_ret, method);
00918 
00919           if ((interface == NULL
00920               || strcmp (expected_interface, interface) == 0)
00921               && strcmp (expected_member, member) == 0
00922               && strcmp (expected_signature, signature) == 0)
00923             {
00924               g_free (expected_signature);
00925               *method_ret = method;
00926               g_list_free (info_list);
00927               return TRUE;
00928             }
00929             g_free (expected_signature);
00930         }
00931     }
00932 
00933   if (info_list)
00934     g_list_free (info_list);
00935 
00936   return FALSE;
00937 }
00938 
00939 static char *
00940 gerror_domaincode_to_dbus_error_name (const DBusGObjectInfo *object_info,
00941                                       const char *msg_interface,
00942                                       GQuark domain, gint code)
00943 {
00944   const char *domain_str;
00945   const char *code_str;
00946   GString *dbus_error_name;
00947 
00948   domain_str = object_error_domain_prefix_from_object_info (object_info);
00949   code_str = object_error_code_from_object_info (object_info, domain, code);
00950 
00951   if (!domain_str || !code_str)
00952     {
00953       DBusGErrorInfo *info;
00954 
00955       g_static_rw_lock_reader_lock (&globals_lock);
00956 
00957       if (error_metadata != NULL)
00958         info = g_datalist_id_get_data (&error_metadata, domain);
00959       else
00960         info = NULL;
00961 
00962       g_static_rw_lock_reader_unlock (&globals_lock);
00963 
00964       if (info)
00965         {
00966           GEnumValue *value;
00967           GEnumClass *klass;
00968 
00969           klass = g_type_class_ref (info->code_enum);
00970           value = g_enum_get_value (klass, code);
00971           g_type_class_unref (klass);
00972 
00973           domain_str = info->default_iface;
00974           code_str = value->value_nick;
00975         }
00976     }
00977 
00978   if (!domain_str)
00979     domain_str = msg_interface;
00980 
00981   if (!domain_str || !code_str)
00982     {
00983       /* If we can't map it sensibly, make up an error name */
00984       char *domain_from_quark;
00985       
00986       dbus_error_name = g_string_new ("org.freedesktop.DBus.GLib.UnmappedError.");
00987 
00988       domain_from_quark = uscore_to_wincaps (g_quark_to_string (domain));
00989       g_string_append (dbus_error_name, domain_from_quark);
00990       g_free (domain_from_quark);
00991         
00992       g_string_append_printf (dbus_error_name, ".Code%d", code);
00993     }
00994   else
00995     {
00996       dbus_error_name = g_string_new (domain_str);
00997       g_string_append_c (dbus_error_name, '.');
00998       g_string_append (dbus_error_name, code_str);
00999     }
01000 
01001   return g_string_free (dbus_error_name, FALSE);
01002 }
01003 
01004 static DBusMessage *
01005 gerror_to_dbus_error_message (const DBusGObjectInfo *object_info,
01006                               DBusMessage     *message,
01007                               GError          *error)
01008 {
01009   DBusMessage *reply;
01010 
01011   if (!error)
01012     {
01013       char *error_msg;
01014       
01015       error_msg = g_strdup_printf ("Method invoked for %s returned FALSE but did not set error", dbus_message_get_member (message));
01016       reply = dbus_message_new_error (message, "org.freedesktop.DBus.GLib.ErrorError", error_msg);
01017       g_free (error_msg);
01018     }
01019   else
01020     {
01021       if (error->domain == DBUS_GERROR)
01022         reply = dbus_message_new_error (message,
01023                                         dbus_g_error_get_name (error),
01024                                         error->message);
01025       else
01026         {
01027           char *error_name;
01028           error_name = gerror_domaincode_to_dbus_error_name (object_info,
01029                                                              dbus_message_get_interface (message),
01030                                                              error->domain, error->code);
01031           reply = dbus_message_new_error (message, error_name, error->message);
01032           g_free (error_name); 
01033         }
01034     }
01035   return reply;
01036 }
01037 
01051 struct _DBusGMethodInvocation {
01052   DBusGConnection *connection; 
01053   DBusGMessage *message; 
01054   const DBusGObjectInfo *object; 
01055   const DBusGMethodInfo *method; 
01056 };
01057 
01058 static DBusHandlerResult
01059 invoke_object_method (GObject         *object,
01060                       const DBusGObjectInfo *object_info,
01061                       const DBusGMethodInfo *method,
01062                       DBusConnection  *connection,
01063                       DBusMessage     *message)
01064 {
01065   gboolean had_error, call_only;
01066   GError *gerror;
01067   GValueArray *value_array;
01068   GValue return_value = {0,};
01069   GClosure closure;
01070   char *in_signature;
01071   GArray *out_param_values = NULL;
01072   GValueArray *out_param_gvalues = NULL;
01073   int out_param_count;
01074   int out_param_pos, out_param_gvalue_pos;
01075   DBusHandlerResult result;
01076   DBusMessage *reply;
01077   gboolean have_retval;
01078   gboolean retval_signals_error;
01079   gboolean retval_is_synthetic;
01080   gboolean retval_is_constant;
01081   const char *arg_metadata;
01082 
01083   gerror = NULL;
01084 
01085   /* Determine whether or not this method should be invoked in a new
01086      thread
01087    */
01088   if (strcmp (string_table_lookup (get_method_data (object_info, method), 2), "A") == 0)
01089     call_only = TRUE;
01090   else
01091     call_only = FALSE;
01092 
01093   have_retval = FALSE;
01094   retval_signals_error = FALSE;
01095   retval_is_synthetic = FALSE;
01096   retval_is_constant = FALSE;
01097 
01098   /* This is evil.  We do this to work around the fact that
01099    * the generated glib marshallers check a flag in the closure object
01100    * which we don't care about.  We don't need/want to create
01101    * a new closure for each invocation.
01102    */
01103   memset (&closure, 0, sizeof (closure));
01104 
01105   in_signature = method_input_signature_from_object_info (object_info, method); 
01106   
01107   /* Convert method IN parameters to GValueArray */
01108   {
01109     GArray *types_array;
01110     guint n_params;
01111     const GType *types;
01112     DBusGValueMarshalCtx context;
01113     GError *error = NULL;
01114     
01115     context.recursion_depth = 0;
01116     context.gconnection = DBUS_G_CONNECTION_FROM_CONNECTION (connection);
01117     context.proxy = NULL;
01118 
01119     types_array = _dbus_gtypes_from_arg_signature (in_signature, FALSE);
01120     n_params = types_array->len;
01121     types = (const GType*) types_array->data;
01122 
01123     value_array = _dbus_gvalue_demarshal_message (&context, message, n_params, types, &error);
01124     if (value_array == NULL)
01125       {
01126         g_free (in_signature); 
01127         g_array_free (types_array, TRUE);
01128         reply = dbus_message_new_error (message, "org.freedesktop.DBus.GLib.ErrorError", error->message);
01129         dbus_connection_send (connection, reply, NULL);
01130         dbus_message_unref (reply);
01131         g_error_free (error);
01132         return DBUS_HANDLER_RESULT_HANDLED;
01133       }
01134     g_array_free (types_array, TRUE);
01135   }
01136 
01137   /* Prepend object as first argument */ 
01138   g_value_array_prepend (value_array, NULL);
01139   g_value_init (g_value_array_get_nth (value_array, 0), G_TYPE_OBJECT);
01140   g_value_set_object (g_value_array_get_nth (value_array, 0), object);
01141   
01142   if (call_only)
01143     {
01144       GValue context_value = {0,};
01145       DBusGMethodInvocation *context;
01146       context = g_new (DBusGMethodInvocation, 1);
01147       context->connection = dbus_g_connection_ref (DBUS_G_CONNECTION_FROM_CONNECTION (connection));
01148       context->message = dbus_g_message_ref (DBUS_G_MESSAGE_FROM_MESSAGE (message));
01149       context->object = object_info;
01150       context->method = method;
01151       g_value_init (&context_value, G_TYPE_POINTER);
01152       g_value_set_pointer (&context_value, context);
01153       g_value_array_append (value_array, &context_value);
01154     }
01155   else
01156     {
01157       RetvalType retval;
01158       gboolean arg_in;
01159       gboolean arg_const;
01160       const char *argsig;
01161 
01162       arg_metadata = method_arg_info_from_object_info (object_info, method);
01163       
01164       /* Count number of output parameters, and look for a return value */
01165       out_param_count = 0;
01166       while (*arg_metadata)
01167         {
01168           arg_metadata = arg_iterate (arg_metadata, NULL, &arg_in, &arg_const, &retval, &argsig);
01169           if (arg_in)
01170             continue;
01171           if (retval != RETVAL_NONE)
01172             {
01173               DBusSignatureIter tmp_sigiter;
01174               /* This is the function return value */
01175               g_assert (!have_retval);
01176               have_retval = TRUE;
01177               retval_is_synthetic = FALSE;
01178 
01179               switch (retval)
01180                 {
01181                 case RETVAL_NONE:
01182                   g_assert_not_reached ();
01183                   break;
01184                 case RETVAL_NOERROR:
01185                   retval_signals_error = FALSE;
01186                   break;
01187                 case RETVAL_ERROR:
01188                   retval_signals_error = TRUE;
01189                   break;
01190                 }
01191 
01192               retval_is_constant = arg_const;
01193 
01194               /* Initialize our return GValue with the specified type */
01195               dbus_signature_iter_init (&tmp_sigiter, argsig);
01196               g_value_init (&return_value, _dbus_gtype_from_signature_iter (&tmp_sigiter, FALSE));
01197             }
01198           else
01199             {
01200               /* It's a regular output value */
01201               out_param_count++;
01202             }
01203         }
01204 
01205       /* For compatibility, if we haven't found a return value, we assume
01206        * the function returns a gboolean for signalling an error
01207        * (and therefore also takes a GError).  We also note that it
01208        * is a "synthetic" return value; i.e. we aren't going to be
01209        * sending it over the bus, it's just to signal an error.
01210        */
01211       if (!have_retval)
01212         {
01213           have_retval = TRUE;
01214           retval_is_synthetic = TRUE;
01215           retval_signals_error = TRUE;
01216           g_value_init (&return_value, G_TYPE_BOOLEAN);
01217         }
01218 
01219       /* Create an array to store the actual values of OUT parameters
01220        * (other than the real function return, if any).  Then, create
01221        * a GValue boxed POINTER to each of those values, and append to
01222        * the invocation, so the method can return the OUT parameters.
01223        */
01224       out_param_values = g_array_sized_new (FALSE, TRUE, sizeof (GTypeCValue), out_param_count);
01225 
01226       /* We have a special array of GValues for toplevel GValue return
01227        * types.
01228        */
01229       out_param_gvalues = g_value_array_new (out_param_count);
01230       out_param_pos = 0;
01231       out_param_gvalue_pos = 0;
01232 
01233       /* Reset argument metadata pointer */
01234       arg_metadata = method_arg_info_from_object_info (object_info, method);
01235       
01236       /* Iterate over output arguments again, this time allocating space for
01237        * them as appopriate.
01238        */
01239       while (*arg_metadata)
01240         {
01241           GValue value = {0, };
01242           GTypeCValue storage;
01243           DBusSignatureIter tmp_sigiter;
01244           GType current_gtype;
01245 
01246           arg_metadata = arg_iterate (arg_metadata, NULL, &arg_in, NULL, &retval, &argsig);
01247           /* Skip over input arguments and the return value, if any */
01248           if (arg_in || retval != RETVAL_NONE)
01249             continue;
01250 
01251           dbus_signature_iter_init (&tmp_sigiter, argsig);
01252           current_gtype = _dbus_gtype_from_signature_iter (&tmp_sigiter, FALSE);
01253 
01254           g_value_init (&value, G_TYPE_POINTER);
01255 
01256           /* We special case variants to make method invocation a bit nicer */
01257           if (current_gtype != G_TYPE_VALUE)
01258             {
01259               memset (&storage, 0, sizeof (storage));
01260               g_array_append_val (out_param_values, storage);
01261               g_value_set_pointer (&value, &(g_array_index (out_param_values, GTypeCValue, out_param_pos)));
01262               out_param_pos++;
01263             }
01264           else
01265             {
01266               g_value_array_append (out_param_gvalues, NULL);
01267               g_value_set_pointer (&value, out_param_gvalues->values + out_param_gvalue_pos);
01268               out_param_gvalue_pos++;
01269             }
01270           g_value_array_append (value_array, &value);
01271         }
01272     }
01273 
01274   /* Append GError as final argument if necessary */
01275   if (retval_signals_error)
01276     {
01277       g_assert (have_retval);
01278       g_value_array_append (value_array, NULL);
01279       g_value_init (g_value_array_get_nth (value_array, value_array->n_values - 1), G_TYPE_POINTER);
01280       g_value_set_pointer (g_value_array_get_nth (value_array, value_array->n_values - 1), &gerror);
01281     }
01282   
01283   /* Actually invoke method */
01284   method->marshaller (&closure, have_retval ? &return_value : NULL,
01285                       value_array->n_values,
01286                       value_array->values,
01287                       NULL, method->function);
01288   if (call_only)
01289     {
01290       result = DBUS_HANDLER_RESULT_HANDLED;
01291       goto done;
01292     }
01293   if (retval_signals_error)
01294     had_error = _dbus_gvalue_signals_error (&return_value);
01295   else
01296     had_error = FALSE;
01297 
01298   if (!had_error)
01299     {
01300       DBusMessageIter iter;
01301 
01302       reply = dbus_message_new_method_return (message);
01303       if (reply == NULL)
01304         goto nomem;
01305 
01306       /* Append output arguments to reply */
01307       dbus_message_iter_init_append (reply, &iter);
01308 
01309       /* First, append the return value, unless it's synthetic */
01310       if (have_retval && !retval_is_synthetic)
01311         {
01312           if (!_dbus_gvalue_marshal (&iter, &return_value))
01313             goto nomem;
01314           if (!retval_is_constant)
01315             g_value_unset (&return_value);
01316         }
01317 
01318       /* Grab the argument metadata and iterate over it */
01319       arg_metadata = method_arg_info_from_object_info (object_info, method);
01320       
01321       /* Now append any remaining return values */
01322       out_param_pos = 0;
01323       out_param_gvalue_pos = 0;
01324       while (*arg_metadata)
01325         {
01326           GValue gvalue = {0, };
01327           const char *arg_name;
01328           gboolean arg_in;
01329           gboolean constval;
01330           RetvalType retval;
01331           const char *arg_signature;
01332           DBusSignatureIter argsigiter;
01333 
01334           do
01335             {
01336               /* Iterate over only output values; skip over input
01337                  arguments and the return value */
01338               arg_metadata = arg_iterate (arg_metadata, &arg_name, &arg_in, &constval, &retval, &arg_signature);
01339             }
01340           while ((arg_in || retval != RETVAL_NONE) && *arg_metadata);
01341 
01342           /* If the last argument we saw was input or the return
01343            * value, we must be done iterating over output arguments.
01344            */
01345           if (arg_in || retval != RETVAL_NONE)
01346             break;
01347 
01348           dbus_signature_iter_init (&argsigiter, arg_signature);
01349           
01350           g_value_init (&gvalue, _dbus_gtype_from_signature_iter (&argsigiter, FALSE));
01351           if (G_VALUE_TYPE (&gvalue) != G_TYPE_VALUE)
01352             {
01353               if (!_dbus_gvalue_take (&gvalue,
01354                                      &(g_array_index (out_param_values, GTypeCValue, out_param_pos))))
01355                 g_assert_not_reached ();
01356               out_param_pos++;
01357             }
01358           else
01359             {
01360               g_value_set_static_boxed (&gvalue, out_param_gvalues->values + out_param_gvalue_pos);
01361               out_param_gvalue_pos++;
01362             }
01363               
01364           if (!_dbus_gvalue_marshal (&iter, &gvalue))
01365             goto nomem;
01366           /* Here we actually free the allocated value; we
01367            * took ownership of it with _dbus_gvalue_take, unless
01368            * an annotation has specified this value as constant.
01369            */
01370           if (!constval)
01371             g_value_unset (&gvalue);
01372         }
01373     }
01374   else
01375     reply = gerror_to_dbus_error_message (object_info, message, gerror);
01376 
01377   if (reply)
01378     {
01379       dbus_connection_send (connection, reply, NULL);
01380       dbus_message_unref (reply);
01381     }
01382 
01383   result = DBUS_HANDLER_RESULT_HANDLED;
01384  done:
01385   g_free (in_signature);
01386   if (!call_only)
01387     {
01388       g_array_free (out_param_values, TRUE);
01389       g_value_array_free (out_param_gvalues);
01390     }
01391   g_value_array_free (value_array);
01392   return result;
01393  nomem:
01394   result = DBUS_HANDLER_RESULT_NEED_MEMORY;
01395   goto done;
01396 }
01397 
01398 static DBusHandlerResult
01399 gobject_message_function (DBusConnection  *connection,
01400                           DBusMessage     *message,
01401                           void            *user_data)
01402 {
01403   GParamSpec *pspec;
01404   GObject *object;
01405   gboolean setter;
01406   gboolean getter;
01407   gboolean getall;
01408   char *s;
01409   const char *wincaps_propname;
01410   /* const char *wincaps_propiface; */
01411   DBusMessageIter iter;
01412   const DBusGMethodInfo *method;
01413   const DBusGObjectInfo *object_info;
01414   DBusMessage *ret;
01415 
01416   object = G_OBJECT (user_data);
01417 
01418   if (dbus_message_is_method_call (message,
01419                                    DBUS_INTERFACE_INTROSPECTABLE,
01420                                    "Introspect"))
01421     return handle_introspect (connection, message, object);
01422 
01423   /* Try the metainfo, which lets us invoke methods */
01424   object_info = NULL;
01425   if (lookup_object_and_method (object, message, &object_info, &method))
01426     return invoke_object_method (object, object_info, method, connection, message);
01427 
01428   /* If no metainfo, we can still do properties and signals
01429    * via standard GLib introspection
01430    */
01431   getter = FALSE;
01432   setter = FALSE;
01433   getall = FALSE;
01434   if (dbus_message_is_method_call (message,
01435                                    DBUS_INTERFACE_PROPERTIES,
01436                                    "Get"))
01437     getter = TRUE;
01438   else if (dbus_message_is_method_call (message,
01439                                         DBUS_INTERFACE_PROPERTIES,
01440                                         "Set"))
01441     setter = TRUE;
01442   else if (dbus_message_is_method_call (message,
01443                                    DBUS_INTERFACE_PROPERTIES,
01444                                    "GetAll"))
01445     getall = TRUE;
01446 
01447   if (!(setter || getter || getall))
01448     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
01449 
01450   ret = NULL;
01451 
01452   dbus_message_iter_init (message, &iter);
01453 
01454   if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_STRING)
01455     {
01456       g_warning ("Property get or set does not have an interface string as first arg\n");
01457       return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
01458     }
01459   /* We never use the interface name; if we did, we'd need to
01460    * remember that it can be empty string for "pick one for me"
01461    */
01462   /* dbus_message_iter_get_basic (&iter, &wincaps_propiface); */
01463   dbus_message_iter_next (&iter);
01464 
01465   if (getall)
01466     {
01467       if (object_info != NULL)
01468           ret = get_all_object_properties (connection, message, object_info, object);
01469       else
01470           return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
01471     }
01472   else if (getter || setter)
01473     {
01474       if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_STRING)
01475         {
01476           g_warning ("Property get or set does not have a property name string as second arg\n");
01477           return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
01478         }
01479       dbus_message_iter_get_basic (&iter, &wincaps_propname);
01480       dbus_message_iter_next (&iter);
01481 
01482       s = _dbus_gutils_wincaps_to_uscore (wincaps_propname);
01483 
01484       pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (object),
01485                                             s);
01486 
01487       g_free (s);
01488 
01489       if (pspec != NULL)
01490         {
01491           if (setter)
01492             {
01493               if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_VARIANT)
01494                 {
01495                   g_warning ("Property set does not have a variant value as third arg\n");
01496                   return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
01497                 }
01498 
01499               ret = set_object_property (connection, message, &iter,
01500                                          object, pspec);
01501               dbus_message_iter_next (&iter);
01502             }
01503           else if (getter)
01504             {
01505               ret = get_object_property (connection, message,
01506                                          object, pspec);
01507             }
01508           else
01509             {
01510               g_assert_not_reached ();
01511               ret = NULL;
01512             }
01513         }
01514       else
01515         {
01516           ret = dbus_message_new_error_printf (message,
01517                                                DBUS_ERROR_INVALID_ARGS,
01518                                                "No such property %s", wincaps_propname);
01519         }
01520     }
01521 
01522   g_assert (ret != NULL);
01523 
01524   if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_INVALID)
01525     g_warning ("Property get, set or set all had too many arguments\n");
01526 
01527   dbus_connection_send (connection, ret, NULL);
01528   dbus_message_unref (ret);
01529   return DBUS_HANDLER_RESULT_HANDLED;
01530 }
01531 
01532 static const DBusObjectPathVTable gobject_dbus_vtable = {
01533   gobject_unregister_function,
01534   gobject_message_function,
01535   NULL
01536 };
01537 
01538 typedef struct {
01539   GClosure         closure;
01540   DBusGConnection *connection;
01541   GObject         *object;
01542   const char      *signame;
01543   const char      *sigiface;
01544 } DBusGSignalClosure;
01545 
01546 static GClosure *
01547 dbus_g_signal_closure_new (DBusGConnection *connection,
01548                            GObject         *object,
01549                            const char      *signame,
01550                            const char      *sigiface)
01551 {
01552   DBusGSignalClosure *closure;
01553   
01554   closure = (DBusGSignalClosure*) g_closure_new_simple (sizeof (DBusGSignalClosure), NULL);
01555 
01556   closure->connection = dbus_g_connection_ref (connection);
01557   closure->object = object;
01558   closure->signame = signame;
01559   closure->sigiface = sigiface;
01560   return (GClosure*) closure;
01561 }
01562 
01563 static void
01564 dbus_g_signal_closure_finalize (gpointer data,
01565                                 GClosure *closure)
01566 {
01567   DBusGSignalClosure *sigclosure = (DBusGSignalClosure *) closure;
01568 
01569   dbus_g_connection_unref (sigclosure->connection);
01570 }
01571 
01572 static void
01573 signal_emitter_marshaller (GClosure        *closure,
01574                            GValue          *retval,
01575                            guint            n_param_values,
01576                            const GValue    *param_values,
01577                            gpointer         invocation_hint,
01578                            gpointer         marshal_data)
01579 {
01580   DBusGSignalClosure *sigclosure;
01581   DBusMessage *signal;
01582   DBusMessageIter iter;
01583   guint i;
01584   const char *path;
01585 
01586   sigclosure = (DBusGSignalClosure *) closure;
01587   
01588   g_assert (retval == NULL);
01589 
01590   path = _dbus_gobject_get_path (sigclosure->object);
01591 
01592   g_assert (path != NULL);
01593 
01594   signal = dbus_message_new_signal (path,
01595                                     sigclosure->sigiface,
01596                                     sigclosure->signame);
01597   if (!signal)
01598     {
01599       g_error ("out of memory");
01600       return;
01601     }
01602 
01603   dbus_message_iter_init_append (signal, &iter);
01604 
01605   /* First argument is the object itself, and we can't marshall that */
01606   for (i = 1; i < n_param_values; i++)
01607     {
01608       if (!_dbus_gvalue_marshal (&iter,
01609                                 (GValue *) (&(param_values[i]))))
01610         {
01611           g_warning ("failed to marshal parameter %d for signal %s",
01612                      i, sigclosure->signame);
01613           goto out;
01614         }
01615     }
01616   dbus_connection_send (DBUS_CONNECTION_FROM_G_CONNECTION (sigclosure->connection),
01617                         signal, NULL);
01618  out:
01619   dbus_message_unref (signal);
01620 }
01621 
01622 static void
01623 export_signals (DBusGConnection *connection, const GList *info_list, GObject *object)
01624 {
01625   GType gtype;
01626   const char *sigdata;
01627   const char *iface;
01628   const char *signame;
01629   const DBusGObjectInfo *info;
01630 
01631   gtype = G_TYPE_FROM_INSTANCE (object);
01632 
01633   for (; info_list != NULL; info_list = g_list_next (info_list))
01634     {
01635       info = (DBusGObjectInfo *) info_list->data;
01636       
01637       sigdata = info->exported_signals;
01638       
01639       while (*sigdata != '\0')
01640         {
01641           guint id;
01642           GSignalQuery query;
01643           GClosure *closure;
01644           char *s;
01645 
01646           sigdata = propsig_iterate (sigdata, &iface, &signame);
01647           
01648           s = _dbus_gutils_wincaps_to_uscore (signame);
01649 
01650           id = g_signal_lookup (s, gtype);
01651           if (id == 0)
01652             {
01653               g_warning ("signal \"%s\" (from \"%s\") exported but not found in object class \"%s\"",
01654                      s, signame, g_type_name (gtype));
01655               g_free (s);
01656               continue;
01657             }
01658 
01659           g_signal_query (id, &query);
01660 
01661           if (query.return_type != G_TYPE_NONE)
01662             {
01663               g_warning ("Not exporting signal \"%s\" for object class \"%s\" as it has a return type \"%s\"",
01664                      s, g_type_name (gtype), g_type_name (query.return_type));
01665               g_free (s);
01666               continue; /* FIXME: these could be listed as methods ? */
01667             }
01668           
01669           closure = dbus_g_signal_closure_new (connection, object, signame, (char*) iface);
01670           g_closure_set_marshal (closure, signal_emitter_marshaller);
01671 
01672           g_signal_connect_closure_by_id (object,
01673                           id,
01674                           0,
01675                           closure,
01676                           FALSE);
01677 
01678           g_closure_add_finalize_notifier (closure, NULL,
01679                            dbus_g_signal_closure_finalize);
01680           g_free (s);
01681         }
01682     }
01683 }
01684 
01685 static gint
01686 dbus_error_to_gerror_code (const char *derr)
01687 {
01688   if (0) ; 
01689   else if (!strcmp (derr,  DBUS_ERROR_FAILED  )) 
01690     return  DBUS_GERROR_FAILED ;
01691   else if (!strcmp (derr,  DBUS_ERROR_NO_MEMORY  )) 
01692     return  DBUS_GERROR_NO_MEMORY ;
01693   else if (!strcmp (derr,  DBUS_ERROR_SERVICE_UNKNOWN  )) 
01694     return  DBUS_GERROR_SERVICE_UNKNOWN ;
01695   else if (!strcmp (derr,  DBUS_ERROR_NAME_HAS_NO_OWNER  )) 
01696     return  DBUS_GERROR_NAME_HAS_NO_OWNER ;
01697   else if (!strcmp (derr,  DBUS_ERROR_NO_REPLY  )) 
01698     return  DBUS_GERROR_NO_REPLY ;
01699   else if (!strcmp (derr,  DBUS_ERROR_IO_ERROR  )) 
01700     return  DBUS_GERROR_IO_ERROR ;
01701   else if (!strcmp (derr,  DBUS_ERROR_BAD_ADDRESS  )) 
01702     return  DBUS_GERROR_BAD_ADDRESS ;
01703   else if (!strcmp (derr,  DBUS_ERROR_NOT_SUPPORTED  )) 
01704     return  DBUS_GERROR_NOT_SUPPORTED ;
01705   else if (!strcmp (derr,  DBUS_ERROR_LIMITS_EXCEEDED  )) 
01706     return  DBUS_GERROR_LIMITS_EXCEEDED ;
01707   else if (!strcmp (derr,  DBUS_ERROR_ACCESS_DENIED  )) 
01708     return  DBUS_GERROR_ACCESS_DENIED ;
01709   else if (!strcmp (derr,  DBUS_ERROR_AUTH_FAILED  )) 
01710     return  DBUS_GERROR_AUTH_FAILED ;
01711   else if (!strcmp (derr,  DBUS_ERROR_NO_SERVER  )) 
01712     return  DBUS_GERROR_NO_SERVER ;
01713   else if (!strcmp (derr,  DBUS_ERROR_TIMEOUT  )) 
01714     return  DBUS_GERROR_TIMEOUT ;
01715   else if (!strcmp (derr,  DBUS_ERROR_NO_NETWORK  )) 
01716     return  DBUS_GERROR_NO_NETWORK ;
01717   else if (!strcmp (derr,  DBUS_ERROR_ADDRESS_IN_USE  )) 
01718     return  DBUS_GERROR_ADDRESS_IN_USE ;
01719   else if (!strcmp (derr,  DBUS_ERROR_DISCONNECTED  )) 
01720     return  DBUS_GERROR_DISCONNECTED ;
01721   else if (!strcmp (derr,  DBUS_ERROR_INVALID_ARGS  )) 
01722     return  DBUS_GERROR_INVALID_ARGS ;
01723   else if (!strcmp (derr,  DBUS_ERROR_FILE_NOT_FOUND  )) 
01724     return  DBUS_GERROR_FILE_NOT_FOUND ;
01725   else if (!strcmp (derr,  DBUS_ERROR_FILE_EXISTS  )) 
01726     return  DBUS_GERROR_FILE_EXISTS ;
01727   else if (!strcmp (derr,  DBUS_ERROR_UNKNOWN_METHOD  )) 
01728     return  DBUS_GERROR_UNKNOWN_METHOD ;
01729   else if (!strcmp (derr,  DBUS_ERROR_TIMED_OUT  )) 
01730     return  DBUS_GERROR_TIMED_OUT ;
01731   else if (!strcmp (derr,  DBUS_ERROR_MATCH_RULE_NOT_FOUND  )) 
01732     return  DBUS_GERROR_MATCH_RULE_NOT_FOUND ;
01733   else if (!strcmp (derr,  DBUS_ERROR_MATCH_RULE_INVALID  )) 
01734     return  DBUS_GERROR_MATCH_RULE_INVALID ;
01735   else if (!strcmp (derr,  DBUS_ERROR_SPAWN_EXEC_FAILED  )) 
01736     return  DBUS_GERROR_SPAWN_EXEC_FAILED ;
01737   else if (!strcmp (derr,  DBUS_ERROR_SPAWN_FORK_FAILED  )) 
01738     return  DBUS_GERROR_SPAWN_FORK_FAILED ;
01739   else if (!strcmp (derr,  DBUS_ERROR_SPAWN_CHILD_EXITED  )) 
01740     return  DBUS_GERROR_SPAWN_CHILD_EXITED ;
01741   else if (!strcmp (derr,  DBUS_ERROR_SPAWN_CHILD_SIGNALED  )) 
01742     return  DBUS_GERROR_SPAWN_CHILD_SIGNALED ;
01743   else if (!strcmp (derr,  DBUS_ERROR_SPAWN_FAILED  )) 
01744     return  DBUS_GERROR_SPAWN_FAILED ;
01745   else if (!strcmp (derr,  DBUS_ERROR_UNIX_PROCESS_ID_UNKNOWN  )) 
01746     return  DBUS_GERROR_UNIX_PROCESS_ID_UNKNOWN ;
01747   else if (!strcmp (derr,  DBUS_ERROR_INVALID_SIGNATURE  )) 
01748     return  DBUS_GERROR_INVALID_SIGNATURE ;
01749   else if (!strcmp (derr,  DBUS_ERROR_INVALID_FILE_CONTENT  )) 
01750     return  DBUS_GERROR_INVALID_FILE_CONTENT ;
01751   else if (!strcmp (derr,  DBUS_ERROR_SELINUX_SECURITY_CONTEXT_UNKNOWN  )) 
01752     return  DBUS_GERROR_SELINUX_SECURITY_CONTEXT_UNKNOWN ;
01753   else
01754     return DBUS_GERROR_REMOTE_EXCEPTION;
01755 }
01756 
01779 void
01780 dbus_set_g_error (GError    **gerror,
01781                   DBusError  *error)
01782 {
01783   int code;
01784 
01785   code = dbus_error_to_gerror_code (error->name);
01786   if (code != DBUS_GERROR_REMOTE_EXCEPTION)
01787     g_set_error (gerror, DBUS_GERROR,
01788                  code,
01789                  "%s",
01790                  error->message);
01791   else
01792     g_set_error (gerror, DBUS_GERROR,
01793                  code,
01794                  "%s%c%s",
01795                  error->message ? error->message : "",
01796                  '\0',
01797                  error->name);
01798 }
01799 
01800 static void
01801 dbus_g_error_info_free (gpointer p)
01802 {
01803   DBusGErrorInfo *info;
01804 
01805   info = p;
01806 
01807   g_free (info->default_iface);
01808   g_free (info);
01809 }
01810 
01835 void
01836 dbus_g_object_type_install_info (GType                  object_type,
01837                                  const DBusGObjectInfo *info)
01838 {
01839   g_return_if_fail (G_TYPE_IS_CLASSED (object_type) || G_TYPE_IS_INTERFACE (object_type));
01840 
01841   _dbus_g_value_types_init ();
01842 
01843   g_type_set_qdata (object_type,
01844                     dbus_g_object_type_dbus_metadata_quark (),
01845                     (gpointer) info);
01846 }
01847 
01858 void
01859 dbus_g_error_domain_register (GQuark                domain,
01860                               const char           *default_iface,
01861                               GType                 code_enum)
01862 {
01863   DBusGErrorInfo *info;
01864   
01865   g_return_if_fail (g_quark_to_string (domain) != NULL);
01866   g_return_if_fail (code_enum != G_TYPE_INVALID);
01867   g_return_if_fail (G_TYPE_FUNDAMENTAL (code_enum) == G_TYPE_ENUM);
01868 
01869   g_static_rw_lock_writer_lock (&globals_lock);
01870 
01871   if (error_metadata == NULL)
01872     g_datalist_init (&error_metadata);
01873 
01874   info = g_datalist_id_get_data (&error_metadata, domain);
01875 
01876   if (info != NULL)
01877     {
01878       g_warning ("Metadata for error domain \"%s\" already registered\n",
01879                  g_quark_to_string (domain));
01880     }
01881   else
01882     {
01883       info = g_new0 (DBusGErrorInfo, 1);
01884       info->default_iface = g_strdup (default_iface);
01885       info->code_enum = code_enum;
01886 
01887       g_datalist_id_set_data_full (&error_metadata,
01888                                    domain,
01889                                    info,
01890                                    dbus_g_error_info_free);
01891     }
01892 
01893   g_static_rw_lock_writer_unlock (&globals_lock);
01894 }
01895 
01896 static void
01897 unregister_gobject (DBusGConnection *connection, GObject *dead)
01898 {
01899   char *path;
01900   path = g_object_steal_data (dead, "dbus_glib_object_path");
01901   dbus_connection_unregister_object_path (DBUS_CONNECTION_FROM_G_CONNECTION (connection), path);
01902   g_free (path);
01903 }
01904 
01919 void
01920 dbus_g_connection_register_g_object (DBusGConnection       *connection,
01921                                      const char            *at_path,
01922                                      GObject               *object)
01923 {
01924   GList *info_list;
01925   g_return_if_fail (connection != NULL);
01926   g_return_if_fail (at_path != NULL);
01927   g_return_if_fail (G_IS_OBJECT (object));
01928 
01929   info_list = lookup_object_info (object);
01930   if (info_list == NULL)
01931     {
01932       g_warning ("No introspection data registered for object class \"%s\"",
01933                  g_type_name (G_TYPE_FROM_INSTANCE (object)));
01934       return;
01935     }
01936 
01937   if (!dbus_connection_register_object_path (DBUS_CONNECTION_FROM_G_CONNECTION (connection),
01938                                              at_path,
01939                                              &gobject_dbus_vtable,
01940                                              object))
01941     {
01942       g_error ("Failed to register GObject with DBusConnection");
01943       return;
01944     }
01945 
01946   export_signals (connection, info_list, object);
01947   g_list_free (info_list);
01948 
01949   g_object_set_data (object, "dbus_glib_object_path", g_strdup (at_path));
01950   g_object_weak_ref (object, (GWeakNotify)unregister_gobject, connection);
01951 }
01952 
01962 GObject *
01963 dbus_g_connection_lookup_g_object (DBusGConnection       *connection,
01964                                    const char            *at_path)
01965 {
01966   gpointer ret;
01967   if (!dbus_connection_get_object_path_data (DBUS_CONNECTION_FROM_G_CONNECTION (connection), at_path, &ret))
01968     return NULL;
01969   return ret;
01970 }
01971 
01972 typedef struct {
01973   GType    rettype;
01974   guint    n_params;
01975   GType   *params;
01976 } DBusGFuncSignature;
01977 
01978 static guint
01979 funcsig_hash (gconstpointer key)
01980 {
01981   const DBusGFuncSignature *sig = key;
01982   GType *types;
01983   guint ret;
01984   guint i;
01985 
01986   ret = sig->rettype;
01987   types = sig->params;
01988 
01989   for (i = 0; i < sig->n_params; i++)
01990     {
01991       ret += (int) (*types);
01992       types++;
01993     }
01994       
01995   return ret;
01996 }
01997 
01998 static gboolean
01999 funcsig_equal (gconstpointer aval,
02000                gconstpointer bval)
02001 {
02002   const DBusGFuncSignature *a = aval;
02003   const DBusGFuncSignature *b = bval;
02004   const GType *atypes;
02005   const GType *btypes;
02006   guint i;
02007 
02008   if (a->rettype != b->rettype
02009       || a->n_params != b->n_params)
02010     return FALSE;
02011 
02012   atypes = a->params;
02013   btypes = b->params;
02014 
02015   for (i = 0; i < a->n_params; i++)
02016     {
02017       if (*btypes != *atypes)
02018         return FALSE;
02019       atypes++;
02020       btypes++;
02021     }
02022       
02023   return TRUE;
02024 }
02025 
02026 static void
02027 funcsig_free (DBusGFuncSignature *sig)
02028 {
02029   g_free (sig->params);
02030   g_free (sig);
02031 }
02032 
02033 GClosureMarshal
02034 _dbus_gobject_lookup_marshaller (GType        rettype,
02035                                  guint        n_params,
02036                                  const GType *param_types)
02037 {
02038   GClosureMarshal ret;
02039   DBusGFuncSignature sig;
02040   GType *params;
02041   guint i;
02042 
02043   /* Convert to fundamental types */
02044   rettype = G_TYPE_FUNDAMENTAL (rettype);
02045   params = g_new (GType, n_params);
02046   for (i = 0; i < n_params; i++)
02047     params[i] = G_TYPE_FUNDAMENTAL (param_types[i]);
02048 
02049   sig.rettype = rettype;
02050   sig.n_params = n_params;
02051   sig.params = params;
02052   
02053   g_static_rw_lock_reader_lock (&globals_lock);
02054 
02055   if (marshal_table)
02056     ret = g_hash_table_lookup (marshal_table, &sig);
02057   else
02058     ret = NULL;
02059 
02060   g_static_rw_lock_reader_unlock (&globals_lock);
02061 
02062   if (ret == NULL)
02063     {
02064       if (rettype == G_TYPE_NONE)
02065         {
02066           if (n_params == 0)
02067             ret = g_cclosure_marshal_VOID__VOID;
02068           else if (n_params == 1)
02069             {
02070               switch (params[0])
02071                 {
02072                 case G_TYPE_BOOLEAN:
02073                   ret = g_cclosure_marshal_VOID__BOOLEAN;
02074                   break;
02075                 case G_TYPE_UCHAR:
02076                   ret = g_cclosure_marshal_VOID__UCHAR;
02077                   break;
02078                 case G_TYPE_INT:
02079                   ret = g_cclosure_marshal_VOID__INT;
02080                   break;
02081                 case G_TYPE_UINT:
02082                   ret = g_cclosure_marshal_VOID__UINT;
02083                   break;
02084                 case G_TYPE_DOUBLE:
02085                   ret = g_cclosure_marshal_VOID__DOUBLE;
02086                   break;
02087                 case G_TYPE_STRING:
02088                   ret = g_cclosure_marshal_VOID__STRING;
02089                   break;
02090                 case G_TYPE_BOXED:
02091                   ret = g_cclosure_marshal_VOID__BOXED;
02092                   break;
02093                 }
02094             }
02095           else if (n_params == 3
02096                    && params[0] == G_TYPE_STRING
02097                    && params[1] == G_TYPE_STRING
02098                    && params[2] == G_TYPE_STRING)
02099             {
02100               ret = _dbus_g_marshal_NONE__STRING_STRING_STRING;
02101             }
02102         }
02103     }
02104 
02105   g_free (params);
02106   return ret;
02107 }
02108 
02121 void
02122 dbus_g_object_register_marshaller (GClosureMarshal  marshaller,
02123                                    GType            rettype,
02124                                    ...)
02125 {
02126   va_list args;
02127   GArray *types;
02128   GType gtype;
02129 
02130   va_start (args, rettype);
02131 
02132   types = g_array_new (TRUE, TRUE, sizeof (GType));
02133 
02134   while ((gtype = va_arg (args, GType)) != G_TYPE_INVALID)
02135     g_array_append_val (types, gtype);
02136 
02137   dbus_g_object_register_marshaller_array (marshaller, rettype,
02138                                            types->len, (GType*) types->data);
02139 
02140   g_array_free (types, TRUE);
02141   va_end (args);
02142 }
02143 
02154 void
02155 dbus_g_object_register_marshaller_array (GClosureMarshal  marshaller,
02156                                          GType            rettype,
02157                                          guint            n_types,
02158                                          const GType*     types)
02159 {
02160   DBusGFuncSignature *sig;
02161   guint i;
02162 
02163   g_static_rw_lock_writer_lock (&globals_lock);
02164 
02165   if (marshal_table == NULL)
02166     marshal_table = g_hash_table_new_full (funcsig_hash,
02167                                            funcsig_equal,
02168                                            (GDestroyNotify) funcsig_free,
02169                                            NULL);
02170   sig = g_new0 (DBusGFuncSignature, 1);
02171   sig->rettype = G_TYPE_FUNDAMENTAL (rettype);
02172   sig->n_params = n_types;
02173   sig->params = g_new (GType, n_types);
02174   for (i = 0; i < n_types; i++)
02175     sig->params[i] = G_TYPE_FUNDAMENTAL (types[i]);
02176 
02177   g_hash_table_insert (marshal_table, sig, marshaller);
02178 
02179   g_static_rw_lock_writer_unlock (&globals_lock);
02180 }
02181 
02194 gchar *
02195 dbus_g_method_get_sender (DBusGMethodInvocation *context)
02196 {
02197   const gchar *sender;
02198 
02199   sender = dbus_message_get_sender (dbus_g_message_get_message (context->message));
02200 
02201   if (sender == NULL)
02202     return NULL;
02203     
02204   return strdup (sender);
02205 }
02206 
02217 DBusMessage *
02218 dbus_g_method_get_reply (DBusGMethodInvocation *context)
02219 {
02220   return dbus_message_new_method_return (dbus_g_message_get_message (context->message));
02221 }
02222 
02232 void
02233 dbus_g_method_send_reply (DBusGMethodInvocation *context, DBusMessage *reply)
02234 {
02235   dbus_connection_send (dbus_g_connection_get_connection (context->connection), reply, NULL);
02236   dbus_message_unref (reply);
02237 
02238   dbus_g_connection_unref (context->connection);
02239   dbus_g_message_unref (context->message);
02240   g_free (context);
02241 }
02242 
02243 
02251 void
02252 dbus_g_method_return (DBusGMethodInvocation *context, ...)
02253 {
02254   DBusMessage *reply;
02255   DBusMessageIter iter;
02256   va_list args;
02257   char *out_sig;
02258   GArray *argsig;
02259   guint i;
02260 
02261   reply = dbus_message_new_method_return (dbus_g_message_get_message (context->message));
02262   out_sig = method_output_signature_from_object_info (context->object, context->method);
02263   argsig = _dbus_gtypes_from_arg_signature (out_sig, FALSE);
02264 
02265   dbus_message_iter_init_append (reply, &iter);
02266 
02267   va_start (args, context);
02268   for (i = 0; i < argsig->len; i++)
02269     {
02270       GValue value = {0,};
02271       char *error;
02272       g_value_init (&value, g_array_index (argsig, GType, i));
02273       error = NULL;
02274       G_VALUE_COLLECT (&value, args, G_VALUE_NOCOPY_CONTENTS, &error);
02275       if (error)
02276         {
02277           g_warning(error);
02278           g_free (error);
02279         }
02280       _dbus_gvalue_marshal (&iter, &value);
02281     }
02282   va_end (args);
02283 
02284   dbus_connection_send (dbus_g_connection_get_connection (context->connection), reply, NULL);
02285   dbus_message_unref (reply);
02286 
02287   dbus_g_connection_unref (context->connection);
02288   dbus_g_message_unref (context->message);
02289   g_free (context);
02290   g_free (out_sig);
02291   g_array_free (argsig, TRUE);
02292 }
02293 
02302 void
02303 dbus_g_method_return_error (DBusGMethodInvocation *context, GError *error)
02304 {
02305   DBusMessage *reply;
02306   reply = gerror_to_dbus_error_message (context->object, dbus_g_message_get_message (context->message), error);
02307   dbus_connection_send (dbus_g_connection_get_connection (context->connection), reply, NULL);
02308   dbus_message_unref (reply);
02309   
02310   dbus_g_connection_unref (context->connection);
02311   dbus_g_message_unref (context->message);
02312   g_free (context);
02313 }
02314 
02315 const char * _dbus_gobject_get_path (GObject *obj)
02316 {
02317   return g_object_get_data (obj, "dbus_glib_object_path");
02318 }
02319 
02320 #ifdef DBUS_BUILD_TESTS
02321 #include <stdlib.h>
02322 
02323 static void
02324 _dummy_function (void)
02325 {
02326 }
02327 
02328 /* Data structures copied from one generated by current dbus-binding-tool;
02329  * we need to support this layout forever
02330  */
02331 static const DBusGMethodInfo dbus_glib_internal_test_methods[] = {
02332   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 0 },
02333   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 49 },
02334   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 117 },
02335   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 191 },
02336   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 270 },
02337   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 320 },
02338   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 391 },
02339   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 495 },
02340   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 623 },
02341   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 693 },
02342   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 765 },
02343   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 838 },
02344   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 911 },
02345   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 988 },
02346   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 1064 },
02347   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 1140 },
02348   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 1204 },
02349   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 1278 },
02350   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 1347 },
02351   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 1408 },
02352   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 1460 },
02353   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 1533 },
02354   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 1588 },
02355   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 1647 },
02356   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 1730 },
02357   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 1784 },
02358   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 1833 },
02359   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 1895 },
02360   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 1947 },
02361   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 1999 },
02362 };
02363 
02364 const DBusGObjectInfo dbus_glib_internal_test_object_info = {
02365   0,
02366   dbus_glib_internal_test_methods,
02367   30,
02368 "org.freedesktop.DBus.Tests.MyObject\0DoNothing\0S\0\0org.freedesktop.DBus.Tests.MyObject\0Increment\0S\0x\0I\0u\0arg1\0O\0F\0N\0u\0\0org.freedesktop.DBus.Tests.MyObject\0IncrementRetval\0S\0x\0I\0u\0arg1\0O\0F\0R\0u\0\0org.freedesktop.DBus.Tests.MyObject\0IncrementRetvalError\0S\0x\0I\0u\0arg1\0O\0F\0E\0u\0\0org.freedesktop.DBus.Tests.MyObject\0ThrowError\0S\0\0org.freedesktop.DBus.Tests.MyObject\0Uppercase\0S\0arg0\0I\0s\0arg1\0O\0F\0N\0s\0\0org.freedesktop.DBus.Tests.MyObject\0ManyArgs\0S\0x\0I\0u\0str\0I\0s\0trouble\0I\0d\0d_ret\0O\0F\0N\0d\0str_ret\0O\0F\0N\0s\0\0org.freedesktop.DBus.Tests.MyObject\0ManyReturn\0S\0arg0\0O\0F\0N\0u\0arg1\0O\0F\0N\0s\0arg2\0O\0F\0N\0i\0arg3\0O\0F\0N\0u\0arg4\0O\0F\0N\0u\0arg5\0O\0C\0N\0s\0\0org.freedesktop.DBus.Tests.MyObject\0Stringify\0S\0val\0I\0v\0arg1\0O\0F\0N\0s\0\0org.freedesktop.DBus.Tests.MyObject\0Unstringify\0S\0val\0I\0s\0arg1\0O\0F\0N\0v\0\0org.freedesktop.DBus.Tests.MyObject\0Recursive1\0S\0arg0\0I\0au\0arg1\0O\0F\0N\0u\0\0org.freedesktop.DBus.Tests.MyObject\0Recursive2\0S\0arg0\0I\0u\0arg1\0O\0F\0N\0au\0\0org.freedesktop.DBus.Tests.MyObject\0ManyUppercase\0S\0arg0\0I\0as\0arg1\0O\0F\0N\0as\0\0org.freedesktop.DBus.Tests.MyObject\0StrHashLen\0S\0arg0\0I\0a{ss}\0arg1\0O\0F\0N\0u\0\0org.freedesktop.DBus.Tests.MyObject\0SendCar\0S\0arg0\0I\0(suv)\0arg1\0O\0F\0N\0(uo)\0\0org.freedesktop.DBus.Tests.MyObject\0GetHash\0S\0arg0\0O\0F\0N\0a{ss}\0\0org.freedesktop.DBus.Tests.MyObject\0RecArrays\0S\0val\0I\0aas\0arg1\0O\0F\0N\0aau\0\0org.freedesktop.DBus.Tests.MyObject\0Objpath\0S\0arg0\0I\0o\0arg1\0O\0C\0N\0o\0\0org.freedesktop.DBus.Tests.MyObject\0GetObjs\0S\0arg0\0O\0F\0N\0ao\0\0org.freedesktop.DBus.Tests.MyObject\0IncrementVal\0S\0\0org.freedesktop.DBus.Tests.MyObject\0AsyncIncrement\0A\0x\0I\0u\0arg1\0O\0F\0N\0u\0\0org.freedesktop.DBus.Tests.MyObject\0AsyncThrowError\0A\0\0org.freedesktop.DBus.Tests.MyObject\0GetVal\0S\0arg0\0O\0F\0N\0u\0\0org.freedesktop.DBus.Tests.MyObject\0ManyStringify\0S\0arg0\0I\0a{sv}\0arg1\0O\0F\0N\0a{sv}\0\0org.freedesktop.DBus.Tests.MyObject\0EmitFrobnicate\0S\0\0org.freedesktop.DBus.Tests.MyObject\0Terminate\0S\0\0org.freedesktop.DBus.Tests.FooObject\0GetValue\0S\0arg0\0O\0F\0N\0u\0\0org.freedesktop.DBus.Tests.FooObject\0EmitSignals\0S\0\0org.freedesktop.DBus.Tests.FooObject\0EmitSignal2\0S\0\0org.freedesktop.DBus.Tests.FooObject\0Terminate\0S\0\0\0",
02369 "org.freedesktop.DBus.Tests.MyObject\0Frobnicate\0org.freedesktop.DBus.Tests.FooObject\0Sig0\0org.freedesktop.DBus.Tests.FooObject\0Sig1\0org.freedesktop.DBus.Tests.FooObject\0Sig2\0\0",
02370 "\0"
02371 };
02372 
02373 
02379 gboolean
02380 _dbus_gobject_test (const char *test_data_dir)
02381 {
02382   int i;
02383   const char *arg;
02384   const char *arg_name;
02385   gboolean arg_in;
02386   gboolean constval;
02387   RetvalType retval;
02388   const char *arg_signature;
02389   const char *sigdata;
02390   const char *iface;
02391   const char *signame;
02392   
02393   static struct { const char *wincaps; const char *uscore; } name_pairs[] = {
02394     { "SetFoo", "set_foo" },
02395     { "Foo", "foo" },
02396     { "GetFooBar", "get_foo_bar" },
02397     { "Hello", "hello" }
02398     
02399     /* Impossible-to-handle cases */
02400     /* { "FrobateUIHandler", "frobate_ui_handler" } */
02401   };
02402 
02403   /* Test lookup in our hardcoded object info; if these tests fail
02404    * then it likely means you changed the generated object info in an
02405    * incompatible way and broke the lookup functions.  In that case
02406    * you need to bump the version and use a new structure instead. */
02407   /* DoNothing */
02408   arg = method_arg_info_from_object_info (&dbus_glib_internal_test_object_info,
02409                                           &(dbus_glib_internal_test_methods[0]));
02410   g_assert (*arg == '\0');
02411 
02412   /* Increment */
02413   arg = method_arg_info_from_object_info (&dbus_glib_internal_test_object_info,
02414                                           &(dbus_glib_internal_test_methods[1]));
02415   g_assert (*arg != '\0');
02416   arg = arg_iterate (arg, &arg_name, &arg_in, &constval, &retval, &arg_signature);
02417   g_assert (!strcmp (arg_name, "x"));
02418   g_assert (arg_in == TRUE);
02419   g_assert (!strcmp (arg_signature, "u"));
02420   g_assert (*arg != '\0');
02421   arg = arg_iterate (arg, &arg_name, &arg_in, &constval, &retval, &arg_signature);
02422   g_assert (arg_in == FALSE);
02423   g_assert (retval == RETVAL_NONE);
02424   g_assert (!strcmp (arg_signature, "u"));
02425   g_assert (*arg == '\0');
02426 
02427   /* IncrementRetval */
02428   arg = method_arg_info_from_object_info (&dbus_glib_internal_test_object_info,
02429                                           &(dbus_glib_internal_test_methods[2]));
02430   g_assert (*arg != '\0');
02431   arg = arg_iterate (arg, &arg_name, &arg_in, &constval, &retval, &arg_signature);
02432   g_assert (!strcmp (arg_name, "x"));
02433   g_assert (arg_in == TRUE);
02434   g_assert (!strcmp (arg_signature, "u"));
02435   g_assert (*arg != '\0');
02436   arg = arg_iterate (arg, &arg_name, &arg_in, &constval, &retval, &arg_signature);
02437   g_assert (retval == RETVAL_NOERROR);
02438   g_assert (arg_in == FALSE);
02439   g_assert (!strcmp (arg_signature, "u"));
02440   g_assert (*arg == '\0');
02441 
02442   /* IncrementRetvalError */
02443   arg = method_arg_info_from_object_info (&dbus_glib_internal_test_object_info,
02444                                           &(dbus_glib_internal_test_methods[3]));
02445   g_assert (*arg != '\0');
02446   arg = arg_iterate (arg, &arg_name, &arg_in, &constval, &retval, &arg_signature);
02447   g_assert (!strcmp (arg_name, "x"));
02448   g_assert (arg_in == TRUE);
02449   g_assert (!strcmp (arg_signature, "u"));
02450   g_assert (*arg != '\0');
02451   arg = arg_iterate (arg, &arg_name, &arg_in, &constval, &retval, &arg_signature);
02452   g_assert (retval == RETVAL_ERROR);
02453   g_assert (arg_in == FALSE);
02454   g_assert (!strcmp (arg_signature, "u"));
02455   g_assert (*arg == '\0');
02456   
02457   /* Stringify */
02458   arg = method_arg_info_from_object_info (&dbus_glib_internal_test_object_info,
02459                                           &(dbus_glib_internal_test_methods[8]));
02460   g_assert (*arg != '\0');
02461   arg = arg_iterate (arg, &arg_name, &arg_in, &constval, &retval, &arg_signature);
02462   g_assert (!strcmp (arg_name, "val"));
02463   g_assert (arg_in == TRUE);
02464   g_assert (!strcmp (arg_signature, "v"));
02465   g_assert (*arg != '\0');
02466   arg = arg_iterate (arg, &arg_name, &arg_in, &constval, &retval, &arg_signature);
02467   g_assert (retval == RETVAL_NONE);
02468   g_assert (arg_in == FALSE);
02469   g_assert (!strcmp (arg_signature, "s"));
02470   g_assert (*arg == '\0');
02471 
02472   sigdata = dbus_glib_internal_test_object_info.exported_signals;
02473   g_assert (*sigdata != '\0');
02474   sigdata = propsig_iterate (sigdata, &iface, &signame);
02475   g_assert (!strcmp (iface, "org.freedesktop.DBus.Tests.MyObject"));
02476   g_assert (!strcmp (signame, "Frobnicate"));
02477   g_assert (*sigdata != '\0');
02478   sigdata = propsig_iterate (sigdata, &iface, &signame);
02479   g_assert (!strcmp (iface, "org.freedesktop.DBus.Tests.FooObject"));
02480   g_assert (!strcmp (signame, "Sig0"));
02481   g_assert (*sigdata != '\0');
02482   sigdata = propsig_iterate (sigdata, &iface, &signame);
02483   g_assert (!strcmp (iface, "org.freedesktop.DBus.Tests.FooObject"));
02484   g_assert (!strcmp (signame, "Sig1"));
02485   g_assert (*sigdata != '\0');
02486   sigdata = propsig_iterate (sigdata, &iface, &signame);
02487   g_assert (!strcmp (iface, "org.freedesktop.DBus.Tests.FooObject"));
02488   g_assert (!strcmp (signame, "Sig2"));
02489   g_assert (*sigdata == '\0');
02490   
02491 
02492   i = 0;
02493   while (i < (int) G_N_ELEMENTS (name_pairs))
02494     {
02495       char *uscore;
02496       char *wincaps;
02497 
02498       uscore = _dbus_gutils_wincaps_to_uscore (name_pairs[i].wincaps);
02499       wincaps = uscore_to_wincaps (name_pairs[i].uscore);
02500 
02501       if (strcmp (uscore, name_pairs[i].uscore) != 0)
02502         {
02503           g_printerr ("\"%s\" should have been converted to \"%s\" not \"%s\"\n",
02504                       name_pairs[i].wincaps, name_pairs[i].uscore,
02505                       uscore);
02506           exit (1);
02507         }
02508       
02509       if (strcmp (wincaps, name_pairs[i].wincaps) != 0)
02510         {
02511           g_printerr ("\"%s\" should have been converted to \"%s\" not \"%s\"\n",
02512                       name_pairs[i].uscore, name_pairs[i].wincaps,
02513                       wincaps);
02514           exit (1);
02515         }
02516       
02517       g_free (uscore);
02518       g_free (wincaps);
02519 
02520       ++i;
02521     }
02522   
02523   return TRUE;
02524 }
02525 
02526 #endif /* DBUS_BUILD_TESTS */

Generated on Tue Feb 24 16:47:59 2009 for D-BUSGLibBindings by  doxygen 1.5.1