[kdbus] KDBUS_ITEM_PAYLOAD_OFF items are (once again) relative to msg header
[platform/upstream/glib.git] / gio / tests / gdbus-testserver.c
1 #include <gio/gio.h>
2 #include <stdlib.h>
3
4 static GDBusNodeInfo *introspection_data = NULL;
5 static GMainLoop *loop = NULL;
6 static GHashTable *properties = NULL;
7
8 static const gchar introspection_xml[] =
9   "<node>"
10   "  <interface name='com.example.Frob'>"
11   "    <method name='Quit'>"
12   "    </method>"
13   "    <method name='TestArrayOfStringTypes'>"
14   "      <arg direction='in'  type='as' name='val_string' />"
15   "      <arg direction='in'  type='ao' name='val_objpath' />"
16   "      <arg direction='in'  type='ag' name='val_signature' />"
17   "      <arg direction='out' type='as' />"
18   "      <arg direction='out' type='ao' />"
19   "      <arg direction='out' type='ag' />"
20   "    </method>"
21   "    <method name='TestPrimitiveTypes'>"
22   "      <arg direction='in'  type='y' name='val_byte' />"
23   "      <arg direction='in'  type='b' name='val_boolean' />"
24   "      <arg direction='in'  type='n' name='val_int16' />"
25   "      <arg direction='in'  type='q' name='val_uint16' />"
26   "      <arg direction='in'  type='i' name='val_int32' />"
27   "      <arg direction='in'  type='u' name='val_uint32' />"
28   "      <arg direction='in'  type='x' name='val_int64' />"
29   "      <arg direction='in'  type='t' name='val_uint64' />"
30   "      <arg direction='in'  type='d' name='val_double' />"
31   "      <arg direction='in'  type='s' name='val_string' />"
32   "      <arg direction='in'  type='o' name='val_objpath' />"
33   "      <arg direction='in'  type='g' name='val_signature' />"
34   "      <arg direction='out' type='y' />"
35   "      <arg direction='out' type='b' />"
36   "      <arg direction='out' type='n' />"
37   "      <arg direction='out' type='q' />"
38   "      <arg direction='out' type='i' />"
39   "      <arg direction='out' type='u' />"
40   "      <arg direction='out' type='x' />"
41   "      <arg direction='out' type='t' />"
42   "      <arg direction='out' type='d' />"
43   "      <arg direction='out' type='s' />"
44   "      <arg direction='out' type='o' />"
45   "      <arg direction='out' type='g' />"
46   "    </method>"
47   "    <method name='EmitSignal'>"
48   "      <arg direction='in'  type='s' name='str1' />"
49   "      <arg direction='in'  type='o' name='objpath1' />"
50   "    </method>"
51   "    <method name='TestArrayOfPrimitiveTypes'>"
52   "      <arg direction='in'  type='ay' name='val_byte' />"
53   "      <arg direction='in'  type='ab' name='val_boolean' />"
54   "      <arg direction='in'  type='an' name='val_int16' />"
55   "      <arg direction='in'  type='aq' name='val_uint16' />"
56   "      <arg direction='in'  type='ai' name='val_int32' />"
57   "      <arg direction='in'  type='au' name='val_uint32' />"
58   "      <arg direction='in'  type='ax' name='val_int64' />"
59   "      <arg direction='in'  type='at' name='val_uint64' />"
60   "      <arg direction='in'  type='ad' name='val_double' />"
61   "      <arg direction='out' type='ay' />"
62   "      <arg direction='out' type='ab' />"
63   "      <arg direction='out' type='an' />"
64   "      <arg direction='out' type='aq' />"
65   "      <arg direction='out' type='ai' />"
66   "      <arg direction='out' type='au' />"
67   "      <arg direction='out' type='ax' />"
68   "      <arg direction='out' type='at' />"
69   "      <arg direction='out' type='ad' />"
70   "    </method>"
71   "    <method name='FrobSetProperty'>"
72   "      <arg direction='in'  type='s' name='prop_name' />"
73   "      <arg direction='in'  type='v' name='prop_value' />"
74   "    </method>"
75   "    <signal name='TestSignal'>"
76   "      <arg type='s' name='str1' />"
77   "      <arg type='o' name='objpath1' />"
78   "      <arg type='v' name='variant1' />"
79   "    </signal>"
80   "    <method name='TestComplexArrays'>"
81   "      <arg direction='in'  type='a(ii)' name='aii' />"
82   "      <arg direction='in'  type='aa(ii)' name='aaii' />"
83   "      <arg direction='in'  type='aas' name='aas' />"
84   "      <arg direction='in'  type='aa{ss}' name='ahashes' />"
85   "      <arg direction='in'  type='aay' name='aay' />"
86   "      <arg direction='in'  type='av' name='av' />"
87   "      <arg direction='in'  type='aav' name='aav' />"
88   "      <arg direction='out' type='a(ii)' />"
89   "      <arg direction='out' type='aa(ii)' />"
90   "      <arg direction='out' type='aas' />"
91   "      <arg direction='out' type='aa{ss}' />"
92   "      <arg direction='out' type='aay' />"
93   "      <arg direction='out' type='av' />"
94   "      <arg direction='out' type='aav' />"
95   "    </method>"
96   "    <method name='TestVariant'>"
97   "      <arg direction='in'  type='v' name='v' />"
98   "      <arg direction='in'  type='b' name='modify' />"
99   "      <arg direction='out' type='v' />"
100   "    </method>"
101   "    <method name='FrobInvalidateProperty'>"
102   "      <arg direction='in'  type='s' name='new_value' />"
103   "    </method>"
104   "    <method name='HelloWorld'>"
105   "      <arg direction='in'  type='s' name='hello_message' />"
106   "      <arg direction='out' type='s' />"
107   "    </method>"
108   "    <method name='PairReturn'>"
109   "      <arg direction='out' type='s' />"
110   "      <arg direction='out' type='u' />"
111   "    </method>"
112   "    <method name='TestStructureTypes'>"
113   "      <arg direction='in'  type='(ii)' name='s1' />"
114   "      <arg direction='in'  type='(s(ii)aya{ss})' name='s2' />"
115   "      <arg direction='out' type='(ii)' />"
116   "      <arg direction='out' type='(s(ii)aya{ss})' />"
117   "    </method>"
118   "    <method name='EmitSignal2'>"
119   "    </method>"
120   "    <method name='DoubleHelloWorld'>"
121   "      <arg direction='in'  type='s' name='hello1' />"
122   "      <arg direction='in'  type='s' name='hello2' />"
123   "      <arg direction='out' type='s' />"
124   "      <arg direction='out' type='s' />"
125   "    </method>"
126   "    <method name='Sleep'>"
127   "      <arg direction='in'  type='i' name='msec' />"
128   "    </method>"
129   "    <method name='TestHashTables'>"
130   "      <arg direction='in'  type='a{yy}' name='hyy' />"
131   "      <arg direction='in'  type='a{bb}' name='hbb' />"
132   "      <arg direction='in'  type='a{nn}' name='hnn' />"
133   "      <arg direction='in'  type='a{qq}' name='hqq' />"
134   "      <arg direction='in'  type='a{ii}' name='hii' />"
135   "      <arg direction='in'  type='a{uu}' name='huu' />"
136   "      <arg direction='in'  type='a{xx}' name='hxx' />"
137   "      <arg direction='in'  type='a{tt}' name='htt' />"
138   "      <arg direction='in'  type='a{dd}' name='hdd' />"
139   "      <arg direction='in'  type='a{ss}' name='hss' />"
140   "      <arg direction='in'  type='a{oo}' name='hoo' />"
141   "      <arg direction='in'  type='a{gg}' name='hgg' />"
142   "      <arg direction='out' type='a{yy}' />"
143   "      <arg direction='out' type='a{bb}' />"
144   "      <arg direction='out' type='a{nn}' />"
145   "      <arg direction='out' type='a{qq}' />"
146   "      <arg direction='out' type='a{ii}' />"
147   "      <arg direction='out' type='a{uu}' />"
148   "      <arg direction='out' type='a{xx}' />"
149   "      <arg direction='out' type='a{tt}' />"
150   "      <arg direction='out' type='a{dd}' />"
151   "      <arg direction='out' type='a{ss}' />"
152   "      <arg direction='out' type='a{oo}' />"
153   "      <arg direction='out' type='a{gg}' />"
154   "    </method>"
155   "    <signal name='TestSignal2'>"
156   "      <arg type='i' name='int1' />"
157   "    </signal>"
158   "    <method name='TestComplexHashTables'>"
159   "      <arg direction='in'  type='a{s(ii)}' name='h_str_to_pair' />"
160   "      <arg direction='in'  type='a{sv}' name='h_str_to_variant' />"
161   "      <arg direction='in'  type='a{sav}' name='h_str_to_av' />"
162   "      <arg direction='in'  type='a{saav}' name='h_str_to_aav' />"
163   "      <arg direction='in'  type='a{sa(ii)}' name='h_str_to_array_of_pairs' />"
164   "      <arg direction='in'  type='a{sa{ss}}' name='hash_of_hashes' />"
165   "      <arg direction='out' type='a{s(ii)}' />"
166   "      <arg direction='out' type='a{sv}' />"
167   "      <arg direction='out' type='a{sav}' />"
168   "      <arg direction='out' type='a{saav}' />"
169   "      <arg direction='out' type='a{sa(ii)}' />"
170   "      <arg direction='out' type='a{sa{ss}}' />"
171   "    </method>"
172   "    <property type='y' name='y' access='readwrite' />"
173   "    <property type='b' name='b' access='readwrite' />"
174   "    <property type='n' name='n' access='readwrite' />"
175   "    <property type='q' name='q' access='readwrite' />"
176   "    <property type='i' name='i' access='readwrite' />"
177   "    <property type='u' name='u' access='readwrite' />"
178   "    <property type='x' name='x' access='readwrite' />"
179   "    <property type='t' name='t' access='readwrite' />"
180   "    <property type='d' name='d' access='readwrite' />"
181   "    <property type='s' name='s' access='readwrite' />"
182   "    <property type='o' name='o' access='readwrite' />"
183   "    <property type='ay' name='ay' access='readwrite' />"
184   "    <property type='ab' name='ab' access='readwrite' />"
185   "    <property type='an' name='an' access='readwrite' />"
186   "    <property type='aq' name='aq' access='readwrite' />"
187   "    <property type='ai' name='ai' access='readwrite' />"
188   "    <property type='au' name='au' access='readwrite' />"
189   "    <property type='ax' name='ax' access='readwrite' />"
190   "    <property type='at' name='at' access='readwrite' />"
191   "    <property type='ad' name='ad' access='readwrite' />"
192   "    <property type='as' name='as' access='readwrite' />"
193   "    <property type='ao' name='ao' access='readwrite' />"
194   "    <property type='s' name='foo' access='readwrite' />"
195   "    <property type='s' name='PropertyThatWillBeInvalidated' access='readwrite' />"
196   "  </interface>"
197   "</node>";
198
199 static gboolean
200 end_sleep (gpointer data)
201 {
202   GDBusMethodInvocation *invocation = data;
203
204   g_dbus_method_invocation_return_value (invocation, NULL);
205   g_object_unref (invocation);
206
207   return G_SOURCE_REMOVE;
208 }
209
210 static void
211 handle_method_call (GDBusConnection       *connection,
212                     const gchar           *sender,
213                     const gchar           *object_path,
214                     const gchar           *interface_name,
215                     const gchar           *method_name,
216                     GVariant              *parameters,
217                     GDBusMethodInvocation *invocation,
218                     gpointer               user_data)
219 {
220   if (g_strcmp0 (method_name, "HelloWorld") == 0)
221     {
222       const gchar *greeting;
223
224       g_variant_get (parameters, "(&s)", &greeting);
225       if (g_strcmp0 (greeting, "Yo") == 0)
226         {
227           g_dbus_method_invocation_return_dbus_error (invocation,
228                                                       "com.example.TestException",
229                                                       "Yo is not a proper greeting");
230         }
231       else
232         {
233           gchar *response;
234           response = g_strdup_printf ("You greeted me with '%s'. Thanks!", greeting);
235           g_dbus_method_invocation_return_value (invocation,
236                                                  g_variant_new ("(s)", response));
237           g_free ( response);
238         }
239     }
240   else if (g_strcmp0 (method_name, "DoubleHelloWorld") == 0)
241     {
242       const gchar *hello1, *hello2;
243       gchar *reply1, *reply2;
244
245       g_variant_get (parameters, "(&s&s)", &hello1, &hello2);
246       reply1 = g_strdup_printf ("You greeted me with '%s'. Thanks!", hello1);
247       reply2 = g_strdup_printf ("Yo dawg, you uttered '%s'. Thanks!", hello2);
248       g_dbus_method_invocation_return_value (invocation,
249                                              g_variant_new ("(ss)", reply1, reply2));
250       g_free (reply1);
251       g_free (reply2);
252     }
253   else if (g_strcmp0 (method_name, "PairReturn") == 0)
254     {
255       g_dbus_method_invocation_return_value (invocation,
256                                              g_variant_new ("(su)", "foo", 42));
257     }
258   else if (g_strcmp0 (method_name, "TestPrimitiveTypes") == 0)
259     {
260       guchar val_byte;
261       gboolean val_boolean;
262       gint16 val_int16;
263       guint16 val_uint16;
264       gint32 val_int32;
265       guint32 val_uint32;
266       gint64 val_int64;
267       guint64 val_uint64;
268       gdouble val_double;
269       const gchar *val_string;
270       const gchar *val_objpath;
271       const gchar *val_signature;
272       gchar *ret_string;
273       gchar *ret_objpath;
274       gchar *ret_signature;
275
276       g_variant_get (parameters, "(ybnqiuxtd&s&o&g)",
277                      &val_byte,
278                      &val_boolean,
279                      &val_int16,
280                      &val_uint16,
281                      &val_int32,
282                      &val_uint32,
283                      &val_int64,
284                      &val_uint64,
285                      &val_double,
286                      &val_string,
287                      &val_objpath,
288                      &val_signature);
289
290       ret_string = g_strconcat (val_string, val_string, NULL);
291       ret_objpath = g_strconcat (val_objpath, "/modified", NULL);
292       ret_signature = g_strconcat (val_signature, val_signature, NULL);
293
294       g_dbus_method_invocation_return_value (invocation,
295           g_variant_new ("(ybnqiuxtdsog)",
296                          val_byte + 1,
297                          !val_boolean,
298                          val_int16 + 1,
299                          val_uint16 + 1,
300                          val_int32 + 1,
301                          val_uint32 + 1,
302                          val_int64 + 1,
303                          val_uint64 + 1,
304                          - val_double + 0.123,
305                          ret_string,
306                          ret_objpath,
307                          ret_signature));
308
309       g_free (ret_string);
310       g_free (ret_objpath);
311       g_free (ret_signature);
312     }
313   else if (g_strcmp0 (method_name, "TestArrayOfPrimitiveTypes") == 0)
314     {
315       GVariant *v;
316       const guchar *bytes;
317       const gint16 *int16s;
318       const guint16 *uint16s;
319       const gint32 *int32s;
320       const guint32 *uint32s;
321       const gint64 *int64s;
322       const guint64 *uint64s;
323       const gdouble *doubles;
324       gsize n_elts;
325       gint i, j;
326       GVariantBuilder ret;
327
328       g_variant_builder_init (&ret, G_VARIANT_TYPE ("(ayabanaqaiauaxatad)"));
329
330       v = g_variant_get_child_value (parameters, 0);
331       bytes = g_variant_get_fixed_array (v, &n_elts, 1);
332       g_variant_builder_open (&ret, G_VARIANT_TYPE ("ay"));
333       for (j = 0; j < 2; j++)
334         for (i = 0; i < n_elts; i++)
335           g_variant_builder_add (&ret, "y", bytes[i]);
336       g_variant_builder_close (&ret);
337       g_variant_unref (v);
338
339       v = g_variant_get_child_value (parameters, 1);
340       bytes = g_variant_get_fixed_array (v, &n_elts, 1);
341       g_variant_builder_open (&ret, G_VARIANT_TYPE ("ab"));
342       for (j = 0; j < 2; j++)
343         for (i = 0; i < n_elts; i++)
344           g_variant_builder_add (&ret, "b", (gboolean)bytes[i]);
345       g_variant_builder_close (&ret);
346       g_variant_unref (v);
347
348       v = g_variant_get_child_value (parameters, 2);
349       int16s = g_variant_get_fixed_array (v, &n_elts, 2);
350       g_variant_builder_open (&ret, G_VARIANT_TYPE ("an"));
351       for (j = 0; j < 2; j++)
352         for (i = 0; i < n_elts; i++)
353           g_variant_builder_add (&ret, "n", int16s[i]);
354       g_variant_builder_close (&ret);
355       g_variant_unref (v);
356
357       v = g_variant_get_child_value (parameters, 3);
358       uint16s = g_variant_get_fixed_array (v, &n_elts, 2);
359       g_variant_builder_open (&ret, G_VARIANT_TYPE ("aq"));
360       for (j = 0; j < 2; j++)
361         for (i = 0; i < n_elts; i++)
362           g_variant_builder_add (&ret, "q", uint16s[i]);
363       g_variant_builder_close (&ret);
364       g_variant_unref (v);
365
366       v = g_variant_get_child_value (parameters, 4);
367       int32s = g_variant_get_fixed_array (v, &n_elts, 4);
368       g_variant_builder_open (&ret, G_VARIANT_TYPE ("ai"));
369       for (j = 0; j < 2; j++)
370         for (i = 0; i < n_elts; i++)
371           g_variant_builder_add (&ret, "i", int32s[i]);
372       g_variant_builder_close (&ret);
373       g_variant_unref (v);
374
375       v = g_variant_get_child_value (parameters, 5);
376       uint32s = g_variant_get_fixed_array (v, &n_elts, 4);
377       g_variant_builder_open (&ret, G_VARIANT_TYPE ("au"));
378       for (j = 0; j < 2; j++)
379         for (i = 0; i < n_elts; i++)
380           g_variant_builder_add (&ret, "u", uint32s[i]);
381       g_variant_builder_close (&ret);
382       g_variant_unref (v);
383
384       v = g_variant_get_child_value (parameters, 6);
385       int64s = g_variant_get_fixed_array (v, &n_elts, 8);
386       g_variant_builder_open (&ret, G_VARIANT_TYPE ("ax"));
387       for (j = 0; j < 2; j++)
388         for (i = 0; i < n_elts; i++)
389           g_variant_builder_add (&ret, "x", int64s[i]);
390       g_variant_builder_close (&ret);
391       g_variant_unref (v);
392
393       v = g_variant_get_child_value (parameters, 7);
394       uint64s = g_variant_get_fixed_array (v, &n_elts, 8);
395       g_variant_builder_open (&ret, G_VARIANT_TYPE ("at"));
396       for (j = 0; j < 2; j++)
397         for (i = 0; i < n_elts; i++)
398           g_variant_builder_add (&ret, "t", uint64s[i]);
399       g_variant_builder_close (&ret);
400       g_variant_unref (v);
401
402       v = g_variant_get_child_value (parameters, 8);
403       doubles = g_variant_get_fixed_array (v, &n_elts, sizeof (gdouble));
404       g_variant_builder_open (&ret, G_VARIANT_TYPE ("ad"));
405       for (j = 0; j < 2; j++)
406         for (i = 0; i < n_elts; i++)
407           g_variant_builder_add (&ret, "d", doubles[i]);
408       g_variant_builder_close (&ret);
409       g_variant_unref (v);
410
411       g_dbus_method_invocation_return_value (invocation,
412                                              g_variant_builder_end (&ret));
413     }
414   else if (g_strcmp0 (method_name, "TestArrayOfStringTypes") == 0)
415     {
416       GVariantIter *iter1;
417       GVariantIter *iter2;
418       GVariantIter *iter3;
419       GVariantIter *iter;
420       GVariantBuilder ret;
421       const gchar *s;
422       gint i;
423
424       g_variant_builder_init (&ret, G_VARIANT_TYPE ("(asaoag)"));
425       g_variant_get (parameters, "(asaoag)", &iter1, &iter2, &iter3);
426
427       g_variant_builder_open (&ret, G_VARIANT_TYPE ("as"));
428       for (i = 0; i < 2; i++)
429         {
430           iter = g_variant_iter_copy (iter1);
431           while (g_variant_iter_loop (iter, "s", &s))
432             g_variant_builder_add (&ret, "s", s);
433           g_variant_iter_free (iter);
434         }
435       g_variant_builder_close (&ret);
436
437       g_variant_builder_open (&ret, G_VARIANT_TYPE ("ao"));
438       for (i = 0; i < 2; i++)
439         {
440           iter = g_variant_iter_copy (iter1);
441           while (g_variant_iter_loop (iter, "o", &s))
442             g_variant_builder_add (&ret, "o", s);
443           g_variant_iter_free (iter);
444         }
445       g_variant_builder_close (&ret);
446
447       g_variant_builder_open (&ret, G_VARIANT_TYPE ("ag"));
448       for (i = 0; i < 2; i++)
449         {
450           iter = g_variant_iter_copy (iter1);
451           while (g_variant_iter_loop (iter, "g", &s))
452             g_variant_builder_add (&ret, "g", s);
453           g_variant_iter_free (iter);
454         }
455       g_variant_builder_close (&ret);
456
457       g_variant_iter_free (iter1);
458       g_variant_iter_free (iter2);
459       g_variant_iter_free (iter3);
460
461       g_dbus_method_invocation_return_value (invocation,
462                                              g_variant_builder_end (&ret));
463     }
464   else if (g_strcmp0 (method_name, "TestHashTables") == 0)
465     {
466       GVariant *v;
467       GVariantIter iter;
468       GVariantBuilder ret;
469       guint8 y1, y2;
470       gboolean b1, b2;
471       gint16 n1, n2;
472       guint16 q1, q2;
473       gint i1, i2;
474       guint u1, u2;
475       gint64 x1, x2;
476       guint64 t1, t2;
477       gdouble d1, d2;
478       gchar *s1, *s2;
479
480       g_variant_builder_init (&ret, G_VARIANT_TYPE ("(a{yy}a{bb}a{nn}a{qq}a{ii}a{uu}a{xx}a{tt}a{dd}a{ss}a{oo}a{gg})"));
481
482       g_variant_builder_open (&ret, G_VARIANT_TYPE ("a{yy}"));
483       v = g_variant_get_child_value (parameters, 0);
484       g_variant_iter_init (&iter, v);
485       while (g_variant_iter_loop (&iter, "yy", &y1, &y2))
486         g_variant_builder_add (&ret, "{yy}", y1 * 2, (y2 * 3) & 255);
487       g_variant_unref (v);
488       g_variant_builder_close (&ret);
489
490       g_variant_builder_open (&ret, G_VARIANT_TYPE ("a{bb}"));
491       v = g_variant_get_child_value (parameters, 1);
492       g_variant_iter_init (&iter, v);
493       while (g_variant_iter_loop (&iter, "bb", &b1, &b2))
494         g_variant_builder_add (&ret, "{bb}", b1, TRUE);
495       g_variant_unref (v);
496       g_variant_builder_close (&ret);
497
498       g_variant_builder_open (&ret, G_VARIANT_TYPE ("a{nn}"));
499       v = g_variant_get_child_value (parameters, 2);
500       g_variant_iter_init (&iter, v);
501       while (g_variant_iter_loop (&iter, "nn", &n1, &n2))
502         g_variant_builder_add (&ret, "{nn}", n1 * 2, n2 * 3);
503       g_variant_unref (v);
504       g_variant_builder_close (&ret);
505
506       g_variant_builder_open (&ret, G_VARIANT_TYPE ("a{qq}"));
507       v = g_variant_get_child_value (parameters, 3);
508       g_variant_iter_init (&iter, v);
509       while (g_variant_iter_loop (&iter, "qq", &q1, &q2))
510         g_variant_builder_add (&ret, "{qq}", q1 * 2, q2 * 3);
511       g_variant_unref (v);
512       g_variant_builder_close (&ret);
513
514       g_variant_builder_open (&ret, G_VARIANT_TYPE ("a{ii}"));
515       v = g_variant_get_child_value (parameters, 4);
516       g_variant_iter_init (&iter, v);
517       while (g_variant_iter_loop (&iter, "ii", &i1, &i2))
518         g_variant_builder_add (&ret, "{ii}", i1 * 2, i2 * 3);
519       g_variant_unref (v);
520       g_variant_builder_close (&ret);
521
522       g_variant_builder_open (&ret, G_VARIANT_TYPE ("a{uu}"));
523       v = g_variant_get_child_value (parameters, 5);
524       g_variant_iter_init (&iter, v);
525       while (g_variant_iter_loop (&iter, "uu", &u1, &u2))
526         g_variant_builder_add (&ret, "{uu}", u1 * 2, u2 * 3);
527       g_variant_unref (v);
528       g_variant_builder_close (&ret);
529
530       g_variant_builder_open (&ret, G_VARIANT_TYPE ("a{xx}"));
531       v = g_variant_get_child_value (parameters, 6);
532       g_variant_iter_init (&iter, v);
533       while (g_variant_iter_loop (&iter, "xx", &x1, &x2))
534         g_variant_builder_add (&ret, "{xx}", x1 + 2, x2  + 1);
535       g_variant_unref (v);
536       g_variant_builder_close (&ret);
537
538       g_variant_builder_open (&ret, G_VARIANT_TYPE ("a{tt}"));
539       v = g_variant_get_child_value (parameters, 7);
540       g_variant_iter_init (&iter, v);
541       while (g_variant_iter_loop (&iter, "tt", &t1, &t2))
542         g_variant_builder_add (&ret, "{tt}", t1 + 2, t2  + 1);
543       g_variant_unref (v);
544       g_variant_builder_close (&ret);
545
546       g_variant_builder_open (&ret, G_VARIANT_TYPE ("a{dd}"));
547       v = g_variant_get_child_value (parameters, 8);
548       g_variant_iter_init (&iter, v);
549       while (g_variant_iter_loop (&iter, "dd", &d1, &d2))
550         g_variant_builder_add (&ret, "{dd}", d1 + 2.5, d2  + 5.0);
551       g_variant_unref (v);
552       g_variant_builder_close (&ret);
553
554       g_variant_builder_open (&ret, G_VARIANT_TYPE ("a{ss}"));
555       v = g_variant_get_child_value (parameters, 9);
556       g_variant_iter_init (&iter, v);
557       while (g_variant_iter_loop (&iter, "ss", &s1, &s2))
558         {
559           gchar *tmp1, *tmp2;
560           tmp1 = g_strconcat (s1, "mod", NULL);
561           tmp2 = g_strconcat (s2, s2, NULL);
562           g_variant_builder_add (&ret, "{ss}", tmp1, tmp2);
563           g_free (tmp1);
564           g_free (tmp2);
565         }
566       g_variant_unref (v);
567       g_variant_builder_close (&ret);
568
569       g_variant_builder_open (&ret, G_VARIANT_TYPE ("a{oo}"));
570       v = g_variant_get_child_value (parameters, 10);
571       g_variant_iter_init (&iter, v);
572       while (g_variant_iter_loop (&iter, "oo", &s1, &s2))
573         {
574           gchar *tmp1, *tmp2;
575           tmp1 = g_strconcat (s1, "/mod", NULL);
576           tmp2 = g_strconcat (s2, "/mod2", NULL);
577           g_variant_builder_add (&ret, "{oo}", tmp1, tmp2);
578           g_free (tmp1);
579           g_free (tmp2);
580         }
581       g_variant_unref (v);
582       g_variant_builder_close (&ret);
583
584       g_variant_builder_open (&ret, G_VARIANT_TYPE ("a{gg}"));
585       v = g_variant_get_child_value (parameters, 11);
586       g_variant_iter_init (&iter, v);
587       while (g_variant_iter_loop (&iter, "gg", &s1, &s2))
588         {
589           gchar *tmp1, *tmp2;
590           tmp1 = g_strconcat (s1, "assgit", NULL);
591           tmp2 = g_strconcat (s2, s2, NULL);
592           g_variant_builder_add (&ret, "{gg}", tmp1, tmp2);
593           g_free (tmp1);
594           g_free (tmp2);
595         }
596       g_variant_unref (v);
597       g_variant_builder_close (&ret);
598
599       g_dbus_method_invocation_return_value (invocation,
600                                              g_variant_builder_end (&ret));
601     }
602   else if (g_strcmp0 (method_name, "TestStructureTypes") == 0)
603     {
604       gint x, y, x1, y1;
605       const gchar *desc;
606       GVariantIter *iter1, *iter2;
607       gchar *desc_ret;
608       GVariantBuilder ret1, ret2;
609       GVariantIter *iter;
610       GVariant *v;
611       gchar *s1, *s2;
612
613       g_variant_get (parameters, "((ii)(&s(ii)aya{ss}))",
614                      &x, &y, &desc, &x1, &y1, &iter1, &iter2);
615
616       desc_ret = g_strconcat (desc, "... in bed!", NULL);
617
618       g_variant_builder_init (&ret1, G_VARIANT_TYPE ("ay"));
619       iter = g_variant_iter_copy (iter1);
620       while (g_variant_iter_loop (iter1, "y", &v))
621         g_variant_builder_add (&ret1, "y", v);
622       while (g_variant_iter_loop (iter, "y", &v))
623         g_variant_builder_add (&ret1, "y", v);
624       g_variant_iter_free (iter);
625       g_variant_iter_free (iter1);
626
627       g_variant_builder_init (&ret2, G_VARIANT_TYPE ("a{ss}"));
628       while (g_variant_iter_loop (iter1, "ss", &s1, &s2))
629         {
630           gchar *tmp;
631           tmp = g_strconcat (s2, " ... in bed!", NULL);
632           g_variant_builder_add (&ret1, "{ss}", s1, tmp);
633           g_free (tmp);
634         }
635       g_variant_iter_free (iter2);
636
637       g_dbus_method_invocation_return_value (invocation,
638            g_variant_new ("((ii)(&s(ii)aya{ss}))",
639                           x + 1, y + 1, desc_ret, x1 + 2, y1 + 2,
640                           &ret1, &ret2));
641
642       g_free (desc_ret);
643     }
644   else if (g_strcmp0 (method_name, "TestVariant") == 0)
645     {
646       GVariant *v;
647       gboolean modify;
648       GVariant *ret;
649
650       g_variant_get (parameters, "(vb)", &v, &modify);
651
652       /* FIXME handle more cases */
653       if (modify)
654         {
655           if (g_variant_is_of_type (v, G_VARIANT_TYPE_BOOLEAN))
656             {
657               ret = g_variant_new_boolean (FALSE);
658             }
659           else if (g_variant_is_of_type (v, G_VARIANT_TYPE_TUPLE))
660             {
661               ret = g_variant_new ("(si)", "other struct", 100);
662             }
663           else
664             g_assert_not_reached ();
665         }
666       else
667         ret = v;
668
669       g_dbus_method_invocation_return_value (invocation, ret);
670       g_variant_unref (v);
671     }
672   else if (g_strcmp0 (method_name, "TestComplexArrays") == 0)
673     {
674       /* FIXME */
675       g_dbus_method_invocation_return_value (invocation, parameters);
676     }
677   else if (g_strcmp0 (method_name, "TestComplexHashTables") == 0)
678     {
679       /* FIXME */
680       g_dbus_method_invocation_return_value (invocation, parameters);
681     }
682   else if (g_strcmp0 (method_name, "FrobSetProperty") == 0)
683     {
684       gchar *name;
685       GVariant *value;
686       g_variant_get (parameters, "(sv)", &name, &value);
687       g_hash_table_replace (properties, name, value);
688       g_dbus_connection_emit_signal (connection,
689                                      NULL,
690                                      "/com/example/TestObject",
691                                      "org.freedesktop.DBus.Properties",
692                                      "PropertiesChanged",
693                                      g_variant_new_parsed ("('com.example.Frob', [{%s, %v}], @as [])", name, value),
694                                      NULL);
695       g_dbus_method_invocation_return_value (invocation, NULL);
696     }
697   else if (g_strcmp0 (method_name, "FrobInvalidateProperty") == 0)
698     {
699       const gchar *value;
700       g_variant_get (parameters, "(&s)", &value);
701       g_hash_table_replace (properties, g_strdup ("PropertyThatWillBeInvalidated"), g_variant_ref_sink (g_variant_new_string (value)));
702
703       g_dbus_connection_emit_signal (connection,
704                                      NULL,
705                                      "/com/example/TestObject",
706                                      "org.freedesktop.DBus.Properties",
707                                      "PropertiesChanged",
708                                      g_variant_new_parsed ("('com.example.Frob', @a{sv} [], ['PropertyThatWillBeInvalidated'])"),
709                                      NULL);
710       g_dbus_method_invocation_return_value (invocation, NULL);
711     }
712   else if (g_strcmp0 (method_name, "EmitSignal") == 0)
713     {
714       const gchar *str;
715       const gchar *path;
716       gchar *str_ret;
717       gchar *path_ret;
718       g_variant_get (parameters, "(&s&o)", &str, &path);
719       str_ret = g_strconcat (str, " .. in bed!", NULL);
720       path_ret = g_strconcat (path, "/in/bed", NULL);
721       g_dbus_connection_emit_signal (connection,
722                                      NULL,
723                                      "/com/example/TestObject",
724                                      "com.example.Frob",
725                                      "TestSignal",
726                                      g_variant_new_parsed ("(%s, %o, <'a variant'>)", str_ret, path_ret),
727                                      NULL);
728       g_free (str_ret);
729       g_free (path_ret);
730       g_dbus_method_invocation_return_value (invocation, NULL);
731     }
732   else if (g_strcmp0 (method_name, "EmitSignal2") == 0)
733     {
734       g_dbus_connection_emit_signal (connection,
735                                      NULL,
736                                      "/com/example/TestObject",
737                                      "com.example.Frob",
738                                      "TestSignal2",
739                                      g_variant_new_parsed ("(42, )"),
740                                      NULL);
741       g_dbus_method_invocation_return_value (invocation, NULL);
742     }
743   else if (g_strcmp0 (method_name, "Sleep") == 0)
744     {
745       gint msec;
746
747       g_variant_get (parameters, "(i)", &msec);
748
749       g_timeout_add ((guint)msec, end_sleep, g_object_ref (invocation));
750     }
751   else if (g_strcmp0 (method_name, "Quit") == 0)
752     {
753       g_dbus_method_invocation_return_value (invocation, NULL);
754       g_main_loop_quit (loop);
755     }
756 }
757
758 static GVariant *
759 handle_get_property (GDBusConnection  *connection,
760                      const gchar      *sender,
761                      const gchar      *object_path,
762                      const gchar      *interface_name,
763                      const gchar      *property_name,
764                      GError          **error,
765                      gpointer          user_data)
766 {
767   GVariant *ret;
768
769   ret = g_hash_table_lookup (properties, property_name);
770   if (ret)
771     {
772       g_assert (!g_variant_is_floating (ret));
773       g_variant_ref (ret);
774     }
775   else
776     {
777       g_set_error (error,
778                    G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
779                    "no such property: %s", property_name);
780     }
781
782   return ret;
783 }
784
785 static gboolean
786 handle_set_property (GDBusConnection  *connection,
787                      const gchar      *sender,
788                      const gchar      *object_path,
789                      const gchar      *interface_name,
790                      const gchar      *property_name,
791                      GVariant         *value,
792                      GError          **error,
793                      gpointer          user_data)
794 {
795   g_set_error (error,
796                G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
797                "SetProperty not implemented");
798   return FALSE;
799 }
800
801 static const GDBusInterfaceVTable interface_vtable =
802 {
803   handle_method_call,
804   handle_get_property,
805   handle_set_property
806 };
807
808 static void
809 on_bus_acquired (GDBusConnection *connection,
810                  const gchar     *name,
811                  gpointer         user_data)
812 {
813   guint id;
814
815   id = g_dbus_connection_register_object (connection,
816                                           "/com/example/TestObject",
817                                           introspection_data->interfaces[0],
818                                           &interface_vtable,
819                                           NULL,
820                                           NULL,
821                                           NULL);
822   g_assert (id > 0);
823 }
824
825 static void
826 on_name_acquired (GDBusConnection *connection,
827                   const gchar     *name,
828                   gpointer         user_data)
829 {
830 }
831
832 static void
833 on_name_lost (GDBusConnection *connection,
834               const gchar     *name,
835               gpointer         user_data)
836 {
837   exit (1);
838 }
839
840 int
841 main (int argc, char *argv[])
842 {
843   guint owner_id;
844
845   introspection_data = g_dbus_node_info_new_for_xml (introspection_xml, NULL);
846   properties = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify)g_variant_unref);
847   g_hash_table_insert (properties, g_strdup ("y"), g_variant_ref_sink (g_variant_new_byte (1)));
848   g_hash_table_insert (properties, g_strdup ("b"), g_variant_ref_sink (g_variant_new_boolean (TRUE)));
849   g_hash_table_insert (properties, g_strdup ("n"), g_variant_ref_sink (g_variant_new_int16 (2)));
850   g_hash_table_insert (properties, g_strdup ("q"), g_variant_ref_sink (g_variant_new_uint16 (3)));
851   g_hash_table_insert (properties, g_strdup ("i"), g_variant_ref_sink (g_variant_new_int32 (4)));
852   g_hash_table_insert (properties, g_strdup ("u"), g_variant_ref_sink (g_variant_new_uint32 (5)));
853   g_hash_table_insert (properties, g_strdup ("x"), g_variant_ref_sink (g_variant_new_int64 (6)));
854   g_hash_table_insert (properties, g_strdup ("t"), g_variant_ref_sink (g_variant_new_uint64 (7)));
855   g_hash_table_insert (properties, g_strdup ("d"), g_variant_ref_sink (g_variant_new_double (7.5)));
856   g_hash_table_insert (properties, g_strdup ("s"), g_variant_ref_sink (g_variant_new_string ("a string")));
857   g_hash_table_insert (properties, g_strdup ("o"), g_variant_ref_sink (g_variant_new_object_path ("/some/path")));
858   g_hash_table_insert (properties, g_strdup ("ay"), g_variant_ref_sink (g_variant_new_parsed ("[@y 1, @y 11]")));
859   g_hash_table_insert (properties, g_strdup ("ab"), g_variant_ref_sink (g_variant_new_parsed ("[true, false]")));
860   g_hash_table_insert (properties, g_strdup ("an"), g_variant_ref_sink (g_variant_new_parsed ("[@n 2, @n 12]")));
861   g_hash_table_insert (properties, g_strdup ("aq"), g_variant_ref_sink (g_variant_new_parsed ("[@q 3, @q 13]")));
862   g_hash_table_insert (properties, g_strdup ("ai"), g_variant_ref_sink (g_variant_new_parsed ("[@i 4, @i 14]")));
863   g_hash_table_insert (properties, g_strdup ("au"), g_variant_ref_sink (g_variant_new_parsed ("[@u 5, @u 15]")));
864   g_hash_table_insert (properties, g_strdup ("ax"), g_variant_ref_sink (g_variant_new_parsed ("[@x 6, @x 16]")));
865   g_hash_table_insert (properties, g_strdup ("at"), g_variant_ref_sink (g_variant_new_parsed ("[@t 7, @t 17]")));
866   g_hash_table_insert (properties, g_strdup ("ad"), g_variant_ref_sink (g_variant_new_parsed ("[7.5, 17.5]")));
867   g_hash_table_insert (properties, g_strdup ("as"), g_variant_ref_sink (g_variant_new_parsed ("['a string', 'another string']")));
868   g_hash_table_insert (properties, g_strdup ("ao"), g_variant_ref_sink (g_variant_new_parsed ("[@o '/some/path', @o '/another/path']")));
869   g_hash_table_insert (properties, g_strdup ("foo"), g_variant_ref_sink (g_variant_new_string ("a frobbed string")));
870   g_hash_table_insert (properties, g_strdup ("PropertyThatWillBeInvalidated"), g_variant_ref_sink (g_variant_new_string ("InitialValue")));
871
872   owner_id = g_bus_own_name (G_BUS_TYPE_SESSION,
873                              "com.example.TestService",
874                              G_BUS_NAME_OWNER_FLAGS_NONE,
875                              on_bus_acquired,
876                              on_name_acquired,
877                              on_name_lost,
878                              NULL,
879                              NULL);
880
881   loop = g_main_loop_new (NULL, FALSE);
882   g_main_loop_run (loop);
883
884   g_bus_unown_name (owner_id);
885
886   g_dbus_node_info_unref (introspection_data);
887
888   return 0;
889 }