e_nms_connection_get_settings()
[framework/uifw/edbus.git] / src / lib / nm / e_nm_util.c
1 #include "E_Nm.h"
2 #include "e_nm_private.h"
3 #include "E_DBus.h"
4 #include <string.h>
5 #include <Ecore_Data.h>
6
7 #define CHECK_SIGNATURE(msg, err, sig)                       \
8   if (dbus_error_is_set((err)))                              \
9   {                                                          \
10     printf("Error: %s - %s\n", (err)->name, (err)->message); \
11     return NULL;                                             \
12   }                                                          \
13                                                              \
14   if (!dbus_message_has_signature((msg), (sig)))             \
15   {                                                          \
16     dbus_set_error((err), DBUS_ERROR_INVALID_SIGNATURE, ""); \
17     return NULL;                                             \
18   }
19
20 static E_NM_Property *property_string(DBusMessageIter *iter, const char *sig, void *value);
21 static E_NM_Property *property_basic(DBusMessageIter *iter, const char *sig, void *value);
22 static E_NM_Property *property_variant(DBusMessageIter *iter, const char *sig, void *value);
23 static E_NM_Property *property_array(DBusMessageIter *iter, const char *sig, void *value);
24 static void           property_free(E_NM_Property *prop);
25
26 typedef E_NM_Property *(*Property_Cb)(DBusMessageIter *iter, const char *sig, void *value);
27
28 typedef struct Sig_Property Sig_Property;
29 struct Sig_Property
30 {
31   const char *sig;
32   Property_Cb func;
33 };
34
35 static Sig_Property sigs[] = {
36   { .sig = "s", property_string },
37   { .sig = "o", property_string },
38   { .sig = "u", property_basic },
39   { .sig = "b", property_basic },
40   { .sig = "y", property_basic },
41   { .sig = "t", property_basic },
42   { .sig = "v", property_variant },
43   { .sig = "a", property_array },
44   { .sig = "as", property_array },
45   { .sig = "ao", property_array },
46   { .sig = "ay", property_array },
47   { .sig = "au", property_array },
48   { .sig = "aau", property_array },
49   { .sig = NULL }
50 };
51
52 static Property_Cb
53 find_property_cb(const char *sig)
54 {
55   Sig_Property *t;
56
57   if (!sig) return NULL;
58
59   for (t = sigs; t->sig; t++)
60   {
61     if (!strcmp(t->sig, sig))
62       return t->func;
63   }
64   fprintf(stderr, "Missing property parser for sig: %s\n", sig);
65   return NULL;
66 }
67
68 static Property *
69 find_property(const char *name, Property *properties)
70 {
71   Property *p;
72
73   if (!name) return NULL;
74
75   for (p = properties; p->name; p++)
76   {
77     if (!strcmp(p->name, name))
78       return p;
79   }
80   return NULL;
81 }
82
83 static E_NM_Property *
84 property_string(DBusMessageIter *iter, const char *sig, void *value)
85 {
86   const char    *str;
87   E_NM_Property *prop = NULL;
88
89   if ((value) && (!sig))
90   {
91     printf("Error: Can't have value and no sig\n");
92     return NULL;
93   }
94   dbus_message_iter_get_basic(iter, &str);
95   if (sig)
96   {
97     if (!check_arg_type(iter, sig[0])) return NULL;
98     if (!value) value = &prop;
99   }
100   else
101   {
102     prop = malloc(sizeof(E_NM_Property));
103     prop->type = dbus_message_iter_get_arg_type(iter);
104     value = &prop->s;
105   }
106   *((char **)value) = strdup(str);
107
108   return prop;
109 }
110
111 static E_NM_Property *
112 property_basic(DBusMessageIter *iter, const char *sig, void *value)
113 {
114   E_NM_Property *prop = NULL;
115
116   if ((value) && (!sig))
117   {
118     printf("Error: Can't have value and no sig\n");
119     return NULL;
120   }
121   if (sig)
122   {
123     if (!check_arg_type(iter, sig[0])) return NULL;
124     if (!value)
125     {
126       // TODO: Only alloc right size
127       prop = malloc(sizeof(long long));
128       value = prop;
129     }
130   }
131   else
132   {
133     prop = malloc(sizeof(E_NM_Property));
134     prop->type = dbus_message_iter_get_arg_type(iter);
135     value = prop;
136   }
137   dbus_message_iter_get_basic(iter, value);
138
139   return prop;
140 }
141
142 static E_NM_Property *
143 property_variant(DBusMessageIter *iter, const char *sig, void *value)
144 {
145   DBusMessageIter v_iter;
146   Property_Cb     func;
147   char            tmp[2];
148
149   if (!check_arg_type(iter, 'v')) return NULL;
150   dbus_message_iter_recurse(iter, &v_iter);
151   tmp[0] = dbus_message_iter_get_arg_type(&v_iter);
152   tmp[1] = 0;
153   func = find_property_cb(tmp);
154   if (!func) return NULL;
155   return (*func)(&v_iter, NULL, NULL);
156 }
157
158 static E_NM_Property *
159 property_array(DBusMessageIter *iter, const char *sig, void *value)
160 {
161   DBusMessageIter   a_iter;
162   Ecore_List      **list;
163   Property_Cb       func;
164   E_NM_Property    *prop = NULL;
165   const char       *subsig = NULL;
166
167   if ((value) && (!sig))
168   {
169     printf("Error: Can't have value and no sig\n");
170     return NULL;
171   }
172
173   dbus_message_iter_recurse(iter, &a_iter);
174   if (sig)
175   {
176
177     if (!check_arg_type(iter, sig[0])) return NULL;
178     subsig = (sig + 1);
179     func = find_property_cb(subsig);
180     if (!func) return NULL;
181     if (!value) value = &prop;
182     list = (Ecore_List **)value;
183     *list = ecore_list_new();
184     if (subsig[0] == 'a') 
185       ecore_list_free_cb_set(*list, ECORE_FREE_CB(ecore_list_destroy));
186     else
187       ecore_list_free_cb_set(*list, free);
188   }
189   else
190   {
191     char tmp[] = { dbus_message_iter_get_arg_type(&a_iter), 0 };
192     func = find_property_cb(tmp);
193     if (!func) return NULL;
194     prop = malloc(sizeof(E_NM_Property));
195     prop->type = dbus_message_iter_get_arg_type(iter);
196     list = (Ecore_List **)&prop->a;
197     *list = ecore_list_new();
198     ecore_list_free_cb_set(*list, ECORE_FREE_CB(property_free));
199   }
200
201   while (dbus_message_iter_get_arg_type(&a_iter) != DBUS_TYPE_INVALID)
202   {
203     void *subprop;
204
205     subprop = (*func)(&a_iter, subsig, NULL);
206     if (subprop) ecore_list_append(*list, subprop);
207     dbus_message_iter_next(&a_iter);
208   }
209
210   return prop;
211 }
212
213 static void
214 property_free(E_NM_Property *prop)
215 {
216   if (!prop) return;
217   if ((prop->type == 's') || (prop->type == 'o'))
218     free(prop->s);
219   else if (prop->type == 'a')
220     ecore_list_destroy(prop->a);
221   free(prop);
222 }
223
224 void
225 property(void *data, DBusMessage *msg, DBusError *err)
226 {
227   DBusMessageIter  iter, v_iter;
228   Property_Data   *d;
229   void            *value;
230   Property_Cb      func = NULL;
231
232   d = data;
233   if (dbus_error_is_set(err))
234   {
235     printf("Error: %s - %s\n", err->name, err->message);
236     goto error;
237   }
238   if (!dbus_message_has_signature(msg, "v")) goto error;
239   dbus_message_iter_init(msg, &iter);
240   dbus_message_iter_recurse(&iter, &v_iter);
241   if (d->property->func)
242   {
243     d->property->func(d, &v_iter);
244     return;
245   }
246
247   value = ((char *)d->reply + d->property->offset);
248   func = find_property_cb(d->property->sig);
249   if (func) (*func)(&v_iter, d->property->sig, value);
250
251   d->property++;
252   if (d->property->name)
253     e_nm_device_properties_get(d->nmi->conn, d->object, d->property->name, property, d);
254   else
255   {
256     if (d->cb_func) d->cb_func(d->data, d->reply);
257     property_data_free(d);
258   }
259   return;
260
261 error:
262   if (d->reply) free(d->reply); /* TODO: Correct free for object */
263   if (d->cb_func) d->cb_func(d->data, NULL);
264   property_data_free(d);
265 }
266
267 void
268 parse_properties(void *data, Property *properties, DBusMessage *msg)
269 {
270   DBusMessageIter iter, a_iter;
271
272   if (!dbus_message_has_signature(msg, "a{sv}")) return;
273
274   dbus_message_iter_init(msg, &iter);
275
276   dbus_message_iter_recurse(&iter, &a_iter);
277   while (dbus_message_iter_get_arg_type(&a_iter) != DBUS_TYPE_INVALID)
278   {
279     DBusMessageIter d_iter, v_iter;
280     Property *p;
281     Property_Cb func;
282     const char *name;
283     void *value;
284
285     dbus_message_iter_recurse(&a_iter, &d_iter);
286     if (!check_arg_type(&d_iter, 's')) return;
287     dbus_message_iter_get_basic(&d_iter, &name);
288
289     dbus_message_iter_next(&d_iter);
290     if (!check_arg_type(&d_iter, 'v')) return;
291     dbus_message_iter_recurse(&d_iter, &v_iter);
292
293     p = find_property(name, properties);
294     if (!p) goto next;
295     value = ((char *)data + p->offset);
296     func = find_property_cb(p->sig);
297     if (!func) goto next;
298     func(&v_iter, p->sig, value);
299
300 next:
301     dbus_message_iter_next(&a_iter);
302   }
303 }
304
305 /**
306  * @internal
307  * @brief Generic callback for methods that return nothing
308  */
309 void *
310 cb_nm_generic(DBusMessage *msg, DBusError *err)
311 {
312   return NULL;
313 }
314
315 /**
316  * @internal
317  * @brief Generic free for methods
318  */
319 void
320 free_nm_generic(void *data)
321 {
322   if (!data) return;
323   free(data);
324 }
325
326 /**
327  * @internal
328  * @brief Callback for methods that return DBUS_TYPE_INT32
329  */
330 void *
331 cb_nm_int32(DBusMessage *msg, DBusError *err)
332 {
333   dbus_int32_t *i;
334
335   CHECK_SIGNATURE(msg, err, "i");
336
337   i = malloc(sizeof(dbus_int32_t));
338   /* Actually emit the integer */
339   dbus_message_get_args(msg, err,
340                         DBUS_TYPE_INT32, i,
341                         DBUS_TYPE_INVALID);
342
343   return i;
344 }
345
346 /**
347  * @internal
348  * @brief Callback for methods that return DBUS_TYPE_UINT32
349  */
350 void *
351 cb_nm_uint32(DBusMessage *msg, DBusError *err)
352 {
353   dbus_uint32_t *i;
354
355   CHECK_SIGNATURE(msg, err, "u");
356
357   i = malloc(sizeof(dbus_uint32_t));
358   /* Actually emit the unsigned integer */
359   dbus_message_get_args(msg, err,
360                         DBUS_TYPE_UINT32, i,
361                         DBUS_TYPE_INVALID);
362
363   return i;
364 }
365
366 /**
367  * @internal
368  * @brief Callback for methods that return DBUS_TYPE_BOOLEAN
369  */
370 void *
371 cb_nm_boolean(DBusMessage *msg, DBusError *err)
372 {
373   dbus_bool_t *i;
374
375   CHECK_SIGNATURE(msg, err, "b");
376
377   i = malloc(sizeof(dbus_bool_t));
378   /* Actually emit the unsigned integer */
379   dbus_message_get_args(msg, err,
380                         DBUS_TYPE_BOOLEAN, i,
381                         DBUS_TYPE_INVALID);
382   
383   return i;
384 }
385
386 /**
387  * @internal
388  * @brief Callback for methods returning a single object path
389  */
390 void *
391 cb_nm_object_path(DBusMessage *msg, DBusError *err)
392 {
393   char *str;
394
395   CHECK_SIGNATURE(msg, err, "o");
396
397   /* Actually emit the object_path */
398   dbus_message_get_args(msg, err,
399                         DBUS_TYPE_OBJECT_PATH, &str,
400                         DBUS_TYPE_INVALID);
401
402   return str;
403 }
404
405
406 /**
407  * @internal
408  * @brief Callback for methods returning a list of object paths
409  */
410 void *
411 cb_nm_object_path_list(DBusMessage *msg, DBusError *err)
412 {
413   Ecore_List *devices;
414   DBusMessageIter iter, sub;
415
416   CHECK_SIGNATURE(msg, err, "ao");
417
418   dbus_message_iter_init(msg, &iter);
419
420   devices = ecore_list_new();
421   dbus_message_iter_recurse(&iter, &sub);
422   while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID)
423   {
424     char *dev = NULL;
425
426     if (!check_arg_type(&sub, 'o')) goto error;
427     dbus_message_iter_get_basic(&sub, &dev);
428     if (dev) ecore_list_append(devices, dev);
429     dbus_message_iter_next(&sub);
430   }
431
432   return devices;
433 error:
434   ecore_list_destroy(devices);
435   return NULL;
436 }
437
438 void
439 free_nm_object_path_list(void *data)
440 {
441   Ecore_List *list = data;
442
443   if (list) ecore_list_destroy(list);
444 }
445
446 void *
447 cb_nm_settings(DBusMessage *msg, DBusError *err)
448 {
449   Ecore_Hash *settings;
450   DBusMessageIter iter, a_iter;
451
452   CHECK_SIGNATURE(msg, err, "a{sa{sv}}");
453
454   dbus_message_iter_init(msg, &iter);
455
456   settings = ecore_hash_new(ecore_str_hash, ecore_str_compare);
457   ecore_hash_free_key_cb_set(settings, free);
458   ecore_hash_free_value_cb_set(settings, ECORE_FREE_CB(ecore_hash_destroy));
459   dbus_message_iter_recurse(&iter, &a_iter);
460   while (dbus_message_iter_get_arg_type(&a_iter) != DBUS_TYPE_INVALID)
461   {
462     DBusMessageIter  d_iter, a2_iter;
463     E_NM_Property   *prop;
464     const char      *name;
465     Ecore_Hash      *value;
466
467     dbus_message_iter_recurse(&a_iter, &d_iter);
468     if (!check_arg_type(&d_iter, 's')) goto error;
469     dbus_message_iter_get_basic(&d_iter, &name);
470
471     dbus_message_iter_next(&d_iter);
472     if (!check_arg_type(&d_iter, 'a')) goto error;
473     dbus_message_iter_recurse(&d_iter, &a2_iter);
474
475     value = ecore_hash_new(ecore_str_hash, ecore_str_compare);
476     ecore_hash_free_key_cb_set(value, free);
477     ecore_hash_free_value_cb_set(value, ECORE_FREE_CB(property_free));
478     ecore_hash_set(settings, strdup(name), value);
479     while (dbus_message_iter_get_arg_type(&a2_iter) != DBUS_TYPE_INVALID)
480     {
481       dbus_message_iter_recurse(&a2_iter, &d_iter);
482       if (!check_arg_type(&d_iter, 's')) goto error;
483       dbus_message_iter_get_basic(&d_iter, &name);
484       dbus_message_iter_next(&d_iter);
485       if (!check_arg_type(&d_iter, 'v')) goto error;
486       prop = property_variant(&d_iter, NULL, NULL);
487       if (prop) ecore_hash_set(value, strdup(name), prop);
488       dbus_message_iter_next(&a2_iter);
489     }
490
491     dbus_message_iter_next(&a_iter);
492   }
493
494   return settings;
495 error:
496   ecore_hash_destroy(settings);
497   return NULL;
498 }
499
500 void
501 free_nm_settings(void *data)
502 {
503   Ecore_Hash *hash = data;
504
505   if (hash) ecore_hash_destroy(hash);
506 }
507
508 int
509 check_arg_type(DBusMessageIter *iter, char type)
510 {
511   char sig;
512  
513   sig = dbus_message_iter_get_arg_type(iter);
514   return sig == type;
515 }
516
517 void
518 property_data_free(Property_Data *data)
519 {
520   if (data->object) free(data->object);
521   free(data);
522 }
523
524 const char *
525 ip4_address2str(unsigned int address)
526 {
527   static char buf[16];
528
529   snprintf(buf, sizeof(buf), "%u.%u.%u.%u",
530            ((address      ) & 0xff),
531            ((address >> 8 ) & 0xff),
532            ((address >> 16) & 0xff),
533            ((address >> 24) & 0xff));
534   return buf;
535 }