]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/wpa_supplicant/dbus_dict_helpers.c
update to 0.6.8
[FreeBSD/FreeBSD.git] / contrib / wpa_supplicant / dbus_dict_helpers.c
1 /*
2  * WPA Supplicant / dbus-based control interface
3  * Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc.
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 as
7  * published by the Free Software Foundation.
8  *
9  * Alternatively, this software may be distributed under the terms of BSD
10  * license.
11  *
12  * See README and COPYING for more details.
13  */
14
15 #include <dbus/dbus.h>
16 #include <string.h>
17 #include <stdio.h>
18 #include <stdlib.h>
19
20 #include "common.h"
21 #include "dbus_dict_helpers.h"
22
23
24 /**
25  * Start a dict in a dbus message.  Should be paired with a call to
26  * {@link wpa_dbus_dict_close_write}.
27  *
28  * @param iter A valid dbus message iterator
29  * @param iter_dict (out) A dict iterator to pass to further dict functions
30  * @return TRUE on success, FALSE on failure
31  *
32  */
33 dbus_bool_t wpa_dbus_dict_open_write(DBusMessageIter *iter,
34                                      DBusMessageIter *iter_dict)
35 {
36         dbus_bool_t result;
37
38         if (!iter || !iter_dict)
39                 return FALSE;
40
41         result = dbus_message_iter_open_container(
42                 iter,
43                 DBUS_TYPE_ARRAY,
44                 DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
45                 DBUS_TYPE_STRING_AS_STRING
46                 DBUS_TYPE_VARIANT_AS_STRING
47                 DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
48                 iter_dict);
49         return result;
50 }
51
52
53 /**
54  * End a dict element in a dbus message.  Should be paired with
55  * a call to {@link wpa_dbus_dict_open_write}.
56  *
57  * @param iter valid dbus message iterator, same as passed to
58  *    wpa_dbus_dict_open_write()
59  * @param iter_dict a dbus dict iterator returned from
60  *    {@link wpa_dbus_dict_open_write}
61  * @return TRUE on success, FALSE on failure
62  *
63  */
64 dbus_bool_t wpa_dbus_dict_close_write(DBusMessageIter *iter,
65                                       DBusMessageIter *iter_dict)
66 {
67         if (!iter || !iter_dict)
68                 return FALSE;
69
70         return dbus_message_iter_close_container(iter, iter_dict);
71 }
72
73
74 static const char * _wpa_get_type_as_string_from_type(const int type)
75 {
76         switch(type) {
77         case DBUS_TYPE_BYTE:
78                 return DBUS_TYPE_BYTE_AS_STRING;
79         case DBUS_TYPE_BOOLEAN:
80                 return DBUS_TYPE_BOOLEAN_AS_STRING;
81         case DBUS_TYPE_INT16:
82                 return DBUS_TYPE_INT16_AS_STRING;
83         case DBUS_TYPE_UINT16:
84                 return DBUS_TYPE_UINT16_AS_STRING;
85         case DBUS_TYPE_INT32:
86                 return DBUS_TYPE_INT32_AS_STRING;
87         case DBUS_TYPE_UINT32:
88                 return DBUS_TYPE_UINT32_AS_STRING;
89         case DBUS_TYPE_INT64:
90                 return DBUS_TYPE_INT64_AS_STRING;
91         case DBUS_TYPE_UINT64:
92                 return DBUS_TYPE_UINT64_AS_STRING;
93         case DBUS_TYPE_DOUBLE:
94                 return DBUS_TYPE_DOUBLE_AS_STRING;
95         case DBUS_TYPE_STRING:
96                 return DBUS_TYPE_STRING_AS_STRING;
97         case DBUS_TYPE_OBJECT_PATH:
98                 return DBUS_TYPE_OBJECT_PATH_AS_STRING;
99         case DBUS_TYPE_ARRAY:
100                 return DBUS_TYPE_ARRAY_AS_STRING;
101         default:
102                 return NULL;
103         }
104 }
105
106
107 static dbus_bool_t _wpa_dbus_add_dict_entry_start(
108         DBusMessageIter *iter_dict, DBusMessageIter *iter_dict_entry,
109         const char *key, const int value_type)
110 {
111         if (!dbus_message_iter_open_container(iter_dict,
112                                               DBUS_TYPE_DICT_ENTRY, NULL,
113                                               iter_dict_entry))
114                 return FALSE;
115
116         if (!dbus_message_iter_append_basic(iter_dict_entry, DBUS_TYPE_STRING,
117                                             &key))
118                 return FALSE;
119
120         return TRUE;
121 }
122
123
124 static dbus_bool_t _wpa_dbus_add_dict_entry_end(
125         DBusMessageIter *iter_dict, DBusMessageIter *iter_dict_entry,
126         DBusMessageIter *iter_dict_val)
127 {
128         if (!dbus_message_iter_close_container(iter_dict_entry, iter_dict_val))
129                 return FALSE;
130         if (!dbus_message_iter_close_container(iter_dict, iter_dict_entry))
131                 return FALSE;
132
133         return TRUE;
134 }
135
136
137 static dbus_bool_t _wpa_dbus_add_dict_entry_basic(DBusMessageIter *iter_dict,
138                                                   const char *key,
139                                                   const int value_type,
140                                                   const void *value)
141 {
142         DBusMessageIter iter_dict_entry, iter_dict_val;
143         const char *type_as_string = NULL;
144
145         type_as_string = _wpa_get_type_as_string_from_type(value_type);
146         if (!type_as_string)
147                 return FALSE;
148
149         if (!_wpa_dbus_add_dict_entry_start(iter_dict, &iter_dict_entry,
150                                             key, value_type))
151                 return FALSE;
152
153         if (!dbus_message_iter_open_container(&iter_dict_entry,
154                                               DBUS_TYPE_VARIANT,
155                                               type_as_string, &iter_dict_val))
156                 return FALSE;
157
158         if (!dbus_message_iter_append_basic(&iter_dict_val, value_type, value))
159                 return FALSE;
160
161         if (!_wpa_dbus_add_dict_entry_end(iter_dict, &iter_dict_entry,
162                                           &iter_dict_val))
163                 return FALSE;
164
165         return TRUE;
166 }
167
168
169 static dbus_bool_t _wpa_dbus_add_dict_entry_byte_array(
170         DBusMessageIter *iter_dict, const char *key,
171         const char *value, const dbus_uint32_t value_len)
172 {
173         DBusMessageIter iter_dict_entry, iter_dict_val, iter_array;
174         dbus_uint32_t i;
175
176         if (!_wpa_dbus_add_dict_entry_start(iter_dict, &iter_dict_entry,
177                                             key, DBUS_TYPE_ARRAY))
178                 return FALSE;
179
180         if (!dbus_message_iter_open_container(&iter_dict_entry,
181                                               DBUS_TYPE_VARIANT,
182                                               DBUS_TYPE_ARRAY_AS_STRING
183                                               DBUS_TYPE_BYTE_AS_STRING,
184                                               &iter_dict_val))
185                 return FALSE;
186
187         if (!dbus_message_iter_open_container(&iter_dict_val, DBUS_TYPE_ARRAY,
188                                               DBUS_TYPE_BYTE_AS_STRING,
189                                               &iter_array))
190                 return FALSE;
191
192         for (i = 0; i < value_len; i++) {
193                 if (!dbus_message_iter_append_basic(&iter_array,
194                                                     DBUS_TYPE_BYTE,
195                                                     &(value[i])))
196                         return FALSE;
197         }
198
199         if (!dbus_message_iter_close_container(&iter_dict_val, &iter_array))
200                 return FALSE;
201
202         if (!_wpa_dbus_add_dict_entry_end(iter_dict, &iter_dict_entry,
203                                           &iter_dict_val))
204                 return FALSE;
205
206         return TRUE;
207 }
208
209
210 /**
211  * Add a string entry to the dict.
212  *
213  * @param iter_dict A valid DBusMessageIter returned from
214  *    {@link wpa_dbus_dict_open_write}
215  * @param key The key of the dict item
216  * @param value The string value
217  * @return TRUE on success, FALSE on failure
218  *
219  */
220 dbus_bool_t wpa_dbus_dict_append_string(DBusMessageIter *iter_dict,
221                                         const char *key, const char *value)
222 {
223         if (!key || !value)
224                 return FALSE;
225         return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_STRING,
226                                               &value);
227 }
228
229
230 /**
231  * Add a byte entry to the dict.
232  *
233  * @param iter_dict A valid DBusMessageIter returned from
234  *    {@link wpa_dbus_dict_open_write}
235  * @param key The key of the dict item
236  * @param value The byte value
237  * @return TRUE on success, FALSE on failure
238  *
239  */
240 dbus_bool_t wpa_dbus_dict_append_byte(DBusMessageIter *iter_dict,
241                                       const char *key, const char value)
242 {
243         if (!key)
244                 return FALSE;
245         return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_BYTE,
246                                               &value);
247 }
248
249
250 /**
251  * Add a boolean entry to the dict.
252  *
253  * @param iter_dict A valid DBusMessageIter returned from
254  *    {@link wpa_dbus_dict_open_write}
255  * @param key The key of the dict item
256  * @param value The boolean value
257  * @return TRUE on success, FALSE on failure
258  *
259  */
260 dbus_bool_t wpa_dbus_dict_append_bool(DBusMessageIter *iter_dict,
261                                       const char *key, const dbus_bool_t value)
262 {
263         if (!key)
264                 return FALSE;
265         return _wpa_dbus_add_dict_entry_basic(iter_dict, key,
266                                               DBUS_TYPE_BOOLEAN, &value);
267 }
268
269
270 /**
271  * Add a 16-bit signed integer entry to the dict.
272  *
273  * @param iter_dict A valid DBusMessageIter returned from
274  *    {@link wpa_dbus_dict_open_write}
275  * @param key The key of the dict item
276  * @param value The 16-bit signed integer value
277  * @return TRUE on success, FALSE on failure
278  *
279  */
280 dbus_bool_t wpa_dbus_dict_append_int16(DBusMessageIter *iter_dict,
281                                        const char *key,
282                                        const dbus_int16_t value)
283 {
284         if (!key)
285                 return FALSE;
286         return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_INT16,
287                                               &value);
288 }
289
290
291 /**
292  * Add a 16-bit unsigned integer entry to the dict.
293  *
294  * @param iter_dict A valid DBusMessageIter returned from
295  *    {@link wpa_dbus_dict_open_write}
296  * @param key The key of the dict item
297  * @param value The 16-bit unsigned integer value
298  * @return TRUE on success, FALSE on failure
299  *
300  */
301 dbus_bool_t wpa_dbus_dict_append_uint16(DBusMessageIter *iter_dict,
302                                         const char *key,
303                                         const dbus_uint16_t value)
304 {
305         if (!key)
306                 return FALSE;
307         return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_UINT16,
308                                               &value);
309 }
310
311
312 /**
313  * Add a 32-bit signed integer to the dict.
314  *
315  * @param iter_dict A valid DBusMessageIter returned from
316  *    {@link wpa_dbus_dict_open_write}
317  * @param key The key of the dict item
318  * @param value The 32-bit signed integer value
319  * @return TRUE on success, FALSE on failure
320  *
321  */
322 dbus_bool_t wpa_dbus_dict_append_int32(DBusMessageIter *iter_dict,
323                                        const char *key,
324                                        const dbus_int32_t value)
325 {
326         if (!key)
327                 return FALSE;
328         return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_INT32,
329                                               &value);
330 }
331
332
333 /**
334  * Add a 32-bit unsigned integer entry to the dict.
335  *
336  * @param iter_dict A valid DBusMessageIter returned from
337  *    {@link wpa_dbus_dict_open_write}
338  * @param key The key of the dict item
339  * @param value The 32-bit unsigned integer value
340  * @return TRUE on success, FALSE on failure
341  *
342  */
343 dbus_bool_t wpa_dbus_dict_append_uint32(DBusMessageIter *iter_dict,
344                                         const char *key,
345                                         const dbus_uint32_t value)
346 {
347         if (!key)
348                 return FALSE;
349         return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_UINT32,
350                                               &value);
351 }
352
353
354 /**
355  * Add a 64-bit integer entry to the dict.
356  *
357  * @param iter_dict A valid DBusMessageIter returned from
358  *    {@link wpa_dbus_dict_open_write}
359  * @param key The key of the dict item
360  * @param value The 64-bit integer value
361  * @return TRUE on success, FALSE on failure
362  *
363  */
364 dbus_bool_t wpa_dbus_dict_append_int64(DBusMessageIter *iter_dict,
365                                        const char *key,
366                                        const dbus_int64_t value)
367 {
368         if (!key)
369                 return FALSE;
370         return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_INT64,
371                                               &value);
372 }
373
374
375 /**
376  * Add a 64-bit unsigned integer entry to the dict.
377  *
378  * @param iter_dict A valid DBusMessageIter returned from
379  *    {@link wpa_dbus_dict_open_write}
380  * @param key The key of the dict item
381  * @param value The 64-bit unsigned integer value
382  * @return TRUE on success, FALSE on failure
383  *
384  */
385 dbus_bool_t wpa_dbus_dict_append_uint64(DBusMessageIter *iter_dict,
386                                         const char *key,
387                                         const dbus_uint64_t value)
388 {
389         if (!key)
390                 return FALSE;
391         return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_UINT64,
392                                               &value);
393 }
394
395
396 /**
397  * Add a double-precision floating point entry to the dict.
398  *
399  * @param iter_dict A valid DBusMessageIter returned from
400  *    {@link wpa_dbus_dict_open_write}
401  * @param key The key of the dict item
402  * @param value The double-precision floating point value
403  * @return TRUE on success, FALSE on failure
404  *
405  */
406 dbus_bool_t wpa_dbus_dict_append_double(DBusMessageIter *iter_dict,
407                                         const char * key,
408                                         const double value)
409 {
410         if (!key)
411                 return FALSE;
412         return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_DOUBLE,
413                                               &value);
414 }
415
416
417 /**
418  * Add a DBus object path entry to the dict.
419  *
420  * @param iter_dict A valid DBusMessageIter returned from
421  *    {@link wpa_dbus_dict_open_write}
422  * @param key The key of the dict item
423  * @param value The DBus object path value
424  * @return TRUE on success, FALSE on failure
425  *
426  */
427 dbus_bool_t wpa_dbus_dict_append_object_path(DBusMessageIter *iter_dict,
428                                              const char *key,
429                                              const char *value)
430 {
431         if (!key || !value)
432                 return FALSE;
433         return _wpa_dbus_add_dict_entry_basic(iter_dict, key,
434                                               DBUS_TYPE_OBJECT_PATH, &value);
435 }
436
437
438 /**
439  * Add a byte array entry to the dict.
440  *
441  * @param iter_dict A valid DBusMessageIter returned from
442  *    {@link wpa_dbus_dict_open_write}
443  * @param key The key of the dict item
444  * @param value The byte array
445  * @param value_len The length of the byte array, in bytes
446  * @return TRUE on success, FALSE on failure
447  *
448  */
449 dbus_bool_t wpa_dbus_dict_append_byte_array(DBusMessageIter *iter_dict,
450                                             const char *key,
451                                             const char *value,
452                                             const dbus_uint32_t value_len)
453 {
454         if (!key)
455                 return FALSE;
456         if (!value && (value_len != 0))
457                 return FALSE;
458         return _wpa_dbus_add_dict_entry_byte_array(iter_dict, key, value,
459                                                    value_len);
460 }
461
462
463 /**
464  * Begin a string array entry in the dict
465  *
466  * @param iter_dict A valid DBusMessageIter returned from
467  *                  {@link nmu_dbus_dict_open_write}
468  * @param key The key of the dict item
469  * @param iter_dict_entry A private DBusMessageIter provided by the caller to
470  *                        be passed to {@link wpa_dbus_dict_end_string_array}
471  * @param iter_dict_val A private DBusMessageIter provided by the caller to
472  *                      be passed to {@link wpa_dbus_dict_end_string_array}
473  * @param iter_array On return, the DBusMessageIter to be passed to 
474  *                   {@link wpa_dbus_dict_string_array_add_element}
475  * @return TRUE on success, FALSE on failure
476  *
477  */
478 dbus_bool_t wpa_dbus_dict_begin_string_array(DBusMessageIter *iter_dict,
479                                              const char *key,
480                                              DBusMessageIter *iter_dict_entry,
481                                              DBusMessageIter *iter_dict_val,
482                                              DBusMessageIter *iter_array)
483 {
484         if (!iter_dict || !iter_dict_entry || !iter_dict_val || !iter_array)
485                 return FALSE;
486
487         if (!_wpa_dbus_add_dict_entry_start(iter_dict, iter_dict_entry,
488                                             key, DBUS_TYPE_ARRAY))
489                 return FALSE;
490
491         if (!dbus_message_iter_open_container(iter_dict_entry,
492                                               DBUS_TYPE_VARIANT,
493                                               DBUS_TYPE_ARRAY_AS_STRING
494                                               DBUS_TYPE_STRING_AS_STRING,
495                                               iter_dict_val))
496                 return FALSE;
497
498         if (!dbus_message_iter_open_container(iter_dict_val, DBUS_TYPE_ARRAY,
499                                               DBUS_TYPE_BYTE_AS_STRING,
500                                               iter_array))
501                 return FALSE;
502
503         return TRUE;
504 }
505
506
507 /**
508  * Add a single string element to a string array dict entry
509  *
510  * @param iter_array A valid DBusMessageIter returned from
511  *                   {@link wpa_dbus_dict_begin_string_array}'s
512  *                   iter_array parameter
513  * @param elem The string element to be added to the dict entry's string array
514  * @return TRUE on success, FALSE on failure
515  *
516  */
517 dbus_bool_t wpa_dbus_dict_string_array_add_element(DBusMessageIter *iter_array,
518                                                    const char *elem)
519 {
520         if (!iter_array || !elem)
521                 return FALSE;
522
523         return dbus_message_iter_append_basic(iter_array, DBUS_TYPE_STRING,
524                                               &elem);
525 }
526
527
528 /**
529  * End a string array dict entry
530  *
531  * @param iter_dict A valid DBusMessageIter returned from
532  *                  {@link nmu_dbus_dict_open_write}
533  * @param iter_dict_entry A private DBusMessageIter returned from
534  *                        {@link wpa_dbus_dict_end_string_array}
535  * @param iter_dict_val A private DBusMessageIter returned from
536  *                      {@link wpa_dbus_dict_end_string_array}
537  * @param iter_array A DBusMessageIter returned from
538  *                   {@link wpa_dbus_dict_end_string_array}
539  * @return TRUE on success, FALSE on failure
540  *
541  */
542 dbus_bool_t wpa_dbus_dict_end_string_array(DBusMessageIter *iter_dict,
543                                            DBusMessageIter *iter_dict_entry,
544                                            DBusMessageIter *iter_dict_val,
545                                            DBusMessageIter *iter_array)
546 {
547         if (!iter_dict || !iter_dict_entry || !iter_dict_val || !iter_array)
548                 return FALSE;
549
550         if (!dbus_message_iter_close_container(iter_dict_val, iter_array))
551                 return FALSE;
552
553         if (!_wpa_dbus_add_dict_entry_end(iter_dict, iter_dict_entry,
554                                           iter_dict_val))
555                 return FALSE;
556
557         return TRUE;
558 }
559
560
561 /**
562  * Convenience function to add an entire string array to the dict.
563  *
564  * @param iter_dict A valid DBusMessageIter returned from
565  *                  {@link nmu_dbus_dict_open_write}
566  * @param key The key of the dict item
567  * @param items The array of strings
568  * @param num_items The number of strings in the array
569  * @return TRUE on success, FALSE on failure
570  *
571  */
572 dbus_bool_t wpa_dbus_dict_append_string_array(DBusMessageIter *iter_dict,
573                                               const char *key,
574                                               const char **items,
575                                               const dbus_uint32_t num_items)
576 {
577         DBusMessageIter iter_dict_entry, iter_dict_val, iter_array;
578         dbus_uint32_t i;
579
580         if (!key)
581                 return FALSE;
582         if (!items && (num_items != 0))
583                 return FALSE;
584
585         if (!wpa_dbus_dict_begin_string_array(iter_dict, key,
586                                               &iter_dict_entry, &iter_dict_val,
587                                               &iter_array))
588                 return FALSE;
589
590         for (i = 0; i < num_items; i++) {
591                 if (!wpa_dbus_dict_string_array_add_element(&iter_array,
592                                                             items[i]))
593                         return FALSE;
594         }
595
596         if (!wpa_dbus_dict_end_string_array(iter_dict, &iter_dict_entry,
597                                             &iter_dict_val, &iter_array))
598                 return FALSE;
599
600         return TRUE;
601 }
602
603
604 /*****************************************************/
605 /* Stuff for reading dicts                           */
606 /*****************************************************/
607
608 /**
609  * Start reading from a dbus dict.
610  *
611  * @param iter A valid DBusMessageIter pointing to the start of the dict
612  * @param iter_dict (out) A DBusMessageIter to be passed to
613  *    {@link wpa_dbus_dict_read_next_entry}
614  * @return TRUE on success, FALSE on failure
615  *
616  */
617 dbus_bool_t wpa_dbus_dict_open_read(DBusMessageIter *iter,
618                                     DBusMessageIter *iter_dict)
619 {
620         if (!iter || !iter_dict)
621                 return FALSE;
622
623         if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY ||
624             dbus_message_iter_get_element_type(iter) != DBUS_TYPE_DICT_ENTRY)
625                 return FALSE;
626
627         dbus_message_iter_recurse(iter, iter_dict);
628         return TRUE;
629 }
630
631
632 #define BYTE_ARRAY_CHUNK_SIZE 34
633 #define BYTE_ARRAY_ITEM_SIZE (sizeof (char))
634
635 static dbus_bool_t _wpa_dbus_dict_entry_get_byte_array(
636         DBusMessageIter *iter, int array_type,
637         struct wpa_dbus_dict_entry *entry)
638 {
639         dbus_uint32_t count = 0;
640         dbus_bool_t success = FALSE;
641         char *buffer;
642
643         entry->bytearray_value = NULL;
644         entry->array_type = DBUS_TYPE_BYTE;
645
646         buffer = wpa_zalloc(BYTE_ARRAY_ITEM_SIZE * BYTE_ARRAY_CHUNK_SIZE);
647         if (!buffer) {
648                 perror("_wpa_dbus_dict_entry_get_byte_array[dbus]: out of "
649                        "memory");
650                 goto done;
651         }
652
653         entry->bytearray_value = buffer;
654         entry->array_len = 0;
655         while (dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_BYTE) {
656                 char byte;
657
658                 if ((count % BYTE_ARRAY_CHUNK_SIZE) == 0 && count != 0) {
659                         buffer = realloc(buffer, BYTE_ARRAY_ITEM_SIZE *
660                                          (count + BYTE_ARRAY_CHUNK_SIZE));
661                         if (buffer == NULL) {
662                                 perror("_wpa_dbus_dict_entry_get_byte_array["
663                                        "dbus] out of memory trying to "
664                                        "retrieve the string array");
665                                 goto done;
666                         }
667                 }
668                 entry->bytearray_value = buffer;
669
670                 dbus_message_iter_get_basic(iter, &byte);
671                 entry->bytearray_value[count] = byte;
672                 entry->array_len = ++count;
673                 dbus_message_iter_next(iter);
674         }
675
676         /* Zero-length arrays are valid. */
677         if (entry->array_len == 0) {
678                 free(entry->bytearray_value);
679                 entry->bytearray_value = NULL;
680         }
681
682         success = TRUE;
683
684 done:
685         return success;
686 }
687
688
689 #define STR_ARRAY_CHUNK_SIZE 8
690 #define STR_ARRAY_ITEM_SIZE (sizeof (char *))
691
692 static dbus_bool_t _wpa_dbus_dict_entry_get_string_array(
693         DBusMessageIter *iter, int array_type,
694         struct wpa_dbus_dict_entry *entry)
695 {
696         dbus_uint32_t count = 0;
697         dbus_bool_t success = FALSE;
698         char **buffer;
699
700         entry->strarray_value = NULL;
701         entry->array_type = DBUS_TYPE_STRING;
702
703         buffer = wpa_zalloc(STR_ARRAY_ITEM_SIZE * STR_ARRAY_CHUNK_SIZE);
704         if (buffer == NULL) {
705                 perror("_wpa_dbus_dict_entry_get_string_array[dbus] out of "
706                        "memory trying to retrieve a string array");
707                 goto done;
708         }
709
710         entry->strarray_value = buffer;
711         entry->array_len = 0;
712         while (dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_STRING) {
713                 const char *value;
714                 char *str;
715
716                 if ((count % STR_ARRAY_CHUNK_SIZE) == 0 && count != 0) {
717                         buffer = realloc(buffer, STR_ARRAY_ITEM_SIZE *
718                                          (count + STR_ARRAY_CHUNK_SIZE));
719                         if (buffer == NULL) {
720                                 perror("_wpa_dbus_dict_entry_get_string_array["
721                                        "dbus] out of memory trying to "
722                                        "retrieve the string array");
723                                 goto done;
724                         }
725                 }
726                 entry->strarray_value = buffer;
727
728                 dbus_message_iter_get_basic(iter, &value);
729                 str = strdup(value);
730                 if (str == NULL) {
731                         perror("_wpa_dbus_dict_entry_get_string_array[dbus] "
732                                "out of memory trying to duplicate the string "
733                                "array");
734                         goto done;
735                 }
736                 entry->strarray_value[count] = str;
737                 entry->array_len = ++count;
738                 dbus_message_iter_next(iter);
739         }
740
741         /* Zero-length arrays are valid. */
742         if (entry->array_len == 0) {
743                 free(entry->strarray_value);
744                 entry->strarray_value = NULL;
745         }
746
747         success = TRUE;
748
749 done:
750         return success;
751 }
752
753
754 static dbus_bool_t _wpa_dbus_dict_entry_get_array(
755         DBusMessageIter *iter_dict_val, struct wpa_dbus_dict_entry *entry)
756 {
757         int array_type = dbus_message_iter_get_element_type(iter_dict_val);
758         dbus_bool_t success = FALSE;
759         DBusMessageIter iter_array;
760
761         if (!entry)
762                 return FALSE;
763
764         dbus_message_iter_recurse(iter_dict_val, &iter_array);
765
766         switch (array_type) {
767         case DBUS_TYPE_BYTE:
768                 success = _wpa_dbus_dict_entry_get_byte_array(&iter_array,
769                                                               array_type,
770                                                               entry);
771                 break;
772         case DBUS_TYPE_STRING:
773                 success = _wpa_dbus_dict_entry_get_string_array(&iter_array,
774                                                                 array_type,
775                                                                 entry);
776                 break;
777         default:
778                 break;
779         }
780
781         return success;
782 }
783
784
785 static dbus_bool_t _wpa_dbus_dict_fill_value_from_variant(
786         struct wpa_dbus_dict_entry *entry, DBusMessageIter *iter_dict_val)
787 {
788         dbus_bool_t success = TRUE;
789
790         switch (entry->type) {
791         case DBUS_TYPE_STRING: {
792                 const char *v;
793                 dbus_message_iter_get_basic(iter_dict_val, &v);
794                 entry->str_value = strdup(v);
795                 break;
796         }
797         case DBUS_TYPE_BOOLEAN: {
798                 dbus_bool_t v;
799                 dbus_message_iter_get_basic(iter_dict_val, &v);
800                 entry->bool_value = v;
801                 break;
802         }
803         case DBUS_TYPE_BYTE: {
804                 char v;
805                 dbus_message_iter_get_basic(iter_dict_val, &v);
806                 entry->byte_value = v;
807                 break;
808         }
809         case DBUS_TYPE_INT16: {
810                 dbus_int16_t v;
811                 dbus_message_iter_get_basic(iter_dict_val, &v);
812                 entry->int16_value = v;
813                 break;
814         }
815         case DBUS_TYPE_UINT16: {
816                 dbus_uint16_t v;
817                 dbus_message_iter_get_basic(iter_dict_val, &v);
818                 entry->uint16_value = v;
819                 break;
820         }
821         case DBUS_TYPE_INT32: {
822                 dbus_int32_t v;
823                 dbus_message_iter_get_basic(iter_dict_val, &v);
824                 entry->int32_value = v;
825                 break;
826         }
827         case DBUS_TYPE_UINT32: {
828                 dbus_uint32_t v;
829                 dbus_message_iter_get_basic(iter_dict_val, &v);
830                 entry->uint32_value = v;
831                 break;
832         }
833         case DBUS_TYPE_INT64: {
834                 dbus_int64_t v;
835                 dbus_message_iter_get_basic(iter_dict_val, &v);
836                 entry->int64_value = v;
837                 break;
838         }
839         case DBUS_TYPE_UINT64: {
840                 dbus_uint64_t v;
841                 dbus_message_iter_get_basic(iter_dict_val, &v);
842                 entry->uint64_value = v;
843                 break;
844         }
845         case DBUS_TYPE_DOUBLE: {
846                 double v;
847                 dbus_message_iter_get_basic(iter_dict_val, &v);
848                 entry->double_value = v;
849                 break;
850         }
851         case DBUS_TYPE_OBJECT_PATH: {
852                 char *v;
853                 dbus_message_iter_get_basic(iter_dict_val, &v);
854                 entry->str_value = strdup(v);
855                 break;
856         }
857         case DBUS_TYPE_ARRAY: {
858                 success = _wpa_dbus_dict_entry_get_array(iter_dict_val, entry);
859                 break;
860         }
861         default:
862                 success = FALSE;
863                 break;
864         }
865
866         return success;
867 }
868
869
870 /**
871  * Read the current key/value entry from the dict.  Entries are dynamically
872  * allocated when needed and must be freed after use with the
873  * {@link wpa_dbus_dict_entry_clear} function.
874  *
875  * The returned entry object will be filled with the type and value of the next
876  * entry in the dict, or the type will be DBUS_TYPE_INVALID if an error
877  * occurred.
878  *
879  * @param iter_dict A valid DBusMessageIter returned from
880  *    {@link wpa_dbus_dict_open_read}
881  * @param entry A valid dict entry object into which the dict key and value
882  *    will be placed
883  * @return TRUE on success, FALSE on failure
884  *
885  */
886 dbus_bool_t wpa_dbus_dict_get_entry(DBusMessageIter *iter_dict,
887                                     struct wpa_dbus_dict_entry * entry)
888 {
889         DBusMessageIter iter_dict_entry, iter_dict_val;
890         int type;
891         const char *key;
892
893         if (!iter_dict || !entry)
894                 goto error;
895
896         if (dbus_message_iter_get_arg_type(iter_dict) != DBUS_TYPE_DICT_ENTRY)
897                 goto error;
898
899         dbus_message_iter_recurse(iter_dict, &iter_dict_entry);
900         dbus_message_iter_get_basic(&iter_dict_entry, &key);
901         entry->key = key;
902
903         if (!dbus_message_iter_next(&iter_dict_entry))
904                 goto error;
905         type = dbus_message_iter_get_arg_type(&iter_dict_entry);
906         if (type != DBUS_TYPE_VARIANT)
907                 goto error;
908
909         dbus_message_iter_recurse(&iter_dict_entry, &iter_dict_val);
910         entry->type = dbus_message_iter_get_arg_type(&iter_dict_val);
911         if (!_wpa_dbus_dict_fill_value_from_variant(entry, &iter_dict_val))
912                 goto error;
913
914         dbus_message_iter_next(iter_dict);
915         return TRUE;
916
917 error:
918         if (entry) {
919                 wpa_dbus_dict_entry_clear(entry);
920                 entry->type = DBUS_TYPE_INVALID;
921                 entry->array_type = DBUS_TYPE_INVALID;
922         }
923
924         return FALSE;
925 }
926
927
928 /**
929  * Return whether or not there are additional dictionary entries.
930  *
931  * @param iter_dict A valid DBusMessageIter returned from
932  *    {@link wpa_dbus_dict_open_read}
933  * @return TRUE if more dict entries exists, FALSE if no more dict entries
934  * exist
935  */
936 dbus_bool_t wpa_dbus_dict_has_dict_entry(DBusMessageIter *iter_dict)
937 {
938         if (!iter_dict) {
939                 perror("wpa_dbus_dict_has_dict_entry[dbus]: out of memory");
940                 return FALSE;
941         }
942         return dbus_message_iter_get_arg_type(iter_dict) ==
943                 DBUS_TYPE_DICT_ENTRY;
944 }
945
946
947 /**
948  * Free any memory used by the entry object.
949  *
950  * @param entry The entry object
951  */
952 void wpa_dbus_dict_entry_clear(struct wpa_dbus_dict_entry *entry)
953 {
954         if (!entry)
955                 return;
956         switch (entry->type) {
957         case DBUS_TYPE_OBJECT_PATH:
958         case DBUS_TYPE_STRING:
959                 free(entry->str_value);
960                 break;
961         case DBUS_TYPE_ARRAY:
962                 switch (entry->array_type) {
963                 case DBUS_TYPE_BYTE: {
964                                 free(entry->bytearray_value);
965                                 break;
966                         }
967                 case DBUS_TYPE_STRING: {
968                                 unsigned int i;
969                                 for (i = 0; i < entry->array_len; i++)
970                                         free(entry->strarray_value[i]);
971                                 free(entry->strarray_value);
972                                 break;
973                         }
974                 }
975                 break;
976         }
977
978         memset(entry, 0, sizeof(struct wpa_dbus_dict_entry));
979 }