block: Add mmc inserted & removed popup
[platform/core/system/storaged.git] / src / shared / dbus.c
1 /*
2  * storaged
3  * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License"),
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16 */
17
18
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <stdbool.h>
22 #include <stdint.h>
23 #include <errno.h>
24
25 #include "storaged_common.h"
26 #include "log.h"
27 #include "dbus.h"
28
29 /* 10 seconds */
30 #define DBUS_REPLY_TIMEOUT      (10000)
31
32 int check_systemd_active(void)
33 {
34         int ret = FALSE;
35         GVariant *msg = NULL;
36         GVariant *var = NULL;
37         char *state;
38
39         _I("%s %s", "org.freedesktop.systemd1.Unit", "ActiveState");
40
41         msg = dbus_method_sync_with_reply_var("org.freedesktop.systemd1",
42                         "/org/freedesktop/systemd1/unit/default_2etarget",
43                         "org.freedesktop.DBus.Properties",
44                         "Get", g_variant_new("(ss)", "org.freedesktop.systemd1.Unit", "ActiveState"));
45         if (!msg)
46                 return -EBADMSG;
47
48         if (!dh_get_param_from_var(msg, "(v)", &var)) {
49                 _E("reply is not variant type");
50                 ret = -EBADMSG;
51                 goto out;
52         }
53         if (!dh_get_param_from_var(var, "(s)", &state)) {
54                 _E("variant doesn't have string (%s)", g_variant_get_type_string(var));
55                 ret = -EBADMSG;
56                 goto out;
57         }
58
59         if (strncmp(state, "active", 6) == 0)
60                 ret = TRUE;
61
62         g_free(state);
63 out:
64         if (var)
65                 g_variant_unref(var);
66         if (msg)
67                 g_variant_unref(msg);
68
69         return ret;
70 }
71
72 static GBusType g_default_bus_type = G_BUS_TYPE_SYSTEM;
73 pthread_mutex_t g_mutex = PTHREAD_MUTEX_INITIALIZER;
74
75 void dbus_handle_set_default_bus_type(GBusType bus_type)
76 {
77         if (bus_type != G_BUS_TYPE_SYSTEM && bus_type != G_BUS_TYPE_SESSION)
78                 return ;
79
80         pthread_mutex_lock(&g_mutex);
81         g_default_bus_type = bus_type;
82         pthread_mutex_unlock(&g_mutex);
83 }
84
85 GBusType dbus_handle_get_default_bus_type(void)
86 {
87         GBusType type;
88
89         pthread_mutex_lock(&g_mutex);
90         type = g_default_bus_type;
91         pthread_mutex_unlock(&g_mutex);
92
93         return type;
94 }
95
96 typedef struct {
97         const char *bus_name;
98         guint id;
99 } dbus_name;
100
101 /* basic information */
102 typedef struct {
103         GDBusConnection *conn;
104         GBusType bus_type;
105         gboolean priv;
106         GList *list_names; // dbus_name
107         GList *list_object; /* dbus_object_handle_s */
108         pthread_mutex_t mutex;// = PTHREAD_MUTEX_INITIALIZER;
109 } dbus_handle_s;
110
111 /* path + interfaces */
112 typedef struct {
113         dbus_handle_s *dh;                              /* dbus handle */
114         const char *path;
115         GList *list_ifaces;                                     /* dbus_interface_s */
116 } dbus_object_handle_s;
117
118 typedef struct {
119         dbus_object_handle_s *oh;
120         const char *name;
121         GList *list_methods; // const dbus_method_s;
122         guint reg_id;
123         int modified;
124 } dbus_interface_s;
125
126 #define get_dh_from_oh(oh) ((dbus_object_handle_s*)oh)->dh
127
128 static dbus_handle_s g_dh[2];
129
130 static dbus_handle_s *_dbus_handle_get_connection(GBusType bus_type);
131
132 dbus_handle_s * _dbus_handle_get_default_connection(void)
133 {
134         return _dbus_handle_get_connection(dbus_handle_get_default_bus_type());
135 }
136
137 #define dbus_handle_lock(handle) do {\
138         assert(handle);\
139         pthread_mutex_lock(&((handle)->mutex));\
140 } while (0);
141
142 #define dbus_handle_unlock(handle) do {\
143         assert(handle);\
144         pthread_mutex_unlock(&(handle)->mutex);\
145 } while (0);
146
147 #define dcl_dbus_handle() dbus_handle_s *dh = (dbus_handle_s *)handle;
148 #define dcl_dbus_handle_null_check() dbus_handle_s *dh = (dbus_handle_s *)handle;\
149         if (!dh) {\
150         _E("dbus handle is null\n");\
151         return 0;\
152         }
153
154 dbus_object_handle_s * _dbus_handle_lookup_object(GList *list_obj, const char *obj_path);
155 dbus_interface_s * _dbus_handle_lookup_interface(GList *list_iface, const char *iface_name);
156 dbus_method_s * _dbus_handle_lookup_method(GList *list_methods, const char *method_name);
157 static GVariant* _append_variant(const char *signature, const char *param[]);
158
159 dbus_interface_s *_iface_u_to_s(const dbus_interface_u *iface_u)
160 {
161         dbus_interface_s *iface = NULL;
162
163         if (!iface_u || !iface_u->methods) {
164                 _E("param is null");
165                 return NULL;
166         }
167
168         iface = (dbus_interface_s *)calloc(1, sizeof(dbus_interface_s));
169         if (!iface) {
170                 _E("failed to calloc");
171                 return NULL;
172         }
173
174         iface->name = iface_u->name;
175         iface->modified = TRUE;
176
177         for (int i = 0 ; i < iface_u->nr_methods; ++i) {
178                 //_D("attached %s:%p", iface_u->methods[i].member, iface_u->methods[i].func);
179                 iface->list_methods = g_list_prepend(iface->list_methods, (void*)(iface_u->methods + i));
180         }
181
182         return iface;
183 }
184
185 static GDBusConnection * _get_bus(GBusType bus_type)
186 {
187         GDBusConnection *conn = NULL;
188         GError *err = NULL;
189
190         if (bus_type != G_BUS_TYPE_SYSTEM && bus_type != G_BUS_TYPE_SESSION) {
191                 _E("Wrong bus_type %d", bus_type);
192                 return NULL;
193         }
194
195         conn = g_bus_get_sync(bus_type, NULL, &err);
196         if (!conn || err) {
197                 _E("failed to get bus:type:%d, %s\n", bus_type, err->message);
198                 g_error_free(err);
199                 return NULL;
200         }
201
202         return conn;
203 }
204
205 static GDBusConnection * _get_bus_private(GBusType bus_type)
206 {
207         GError *err = NULL;
208         GDBusConnection *conn = NULL;
209         const char * address;
210
211         if (bus_type != G_BUS_TYPE_SYSTEM && bus_type != G_BUS_TYPE_SESSION) {
212                 _E("Wrong bus_type %d", bus_type);
213                 return NULL;
214         }
215
216         address = g_dbus_address_get_for_bus_sync(bus_type, NULL, &err);
217         if (!address || err) {
218                 _E("failed to get bus address\n");
219                 g_error_free(err);
220                 return NULL;
221         }
222
223         conn = g_dbus_connection_new_for_address_sync(address,
224                                                                                 (GDBusConnectionFlags) (G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT |
225                                                                                 G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION),
226                                                                                 NULL, /* GDBusAuthObserver */
227                                                                                 NULL,
228                                                                                 &err);
229         if (!conn || err) {
230                 _E("failed to get private bus\n");
231                 g_error_free(err);
232                 return NULL;
233         }
234
235         return conn;
236 }
237
238 /* ref cout is 1 */
239 static dbus_handle_s *_dbus_handle_get_connection(GBusType bus_type)
240 {
241         int ibus = bus_type - 1;
242         dbus_handle_s *dh = NULL;
243
244         if (bus_type != G_BUS_TYPE_SYSTEM && bus_type != G_BUS_TYPE_SESSION) {
245                 _E("Unknown bus type %d", bus_type);
246                 return NULL;
247         }
248         dh = &g_dh[ibus];
249
250         dbus_handle_lock(dh);
251
252         if (!dh->conn) {
253                 dh->conn = _get_bus(bus_type);
254                 dh->priv = FALSE;
255                 dh->bus_type = bus_type;
256                 if (!dh->conn)
257                         dh = NULL;
258         }
259
260         dbus_handle_unlock(dh);
261
262         return dh;
263 }
264
265 /* ref cout is 1 */
266 static dbus_handle_s *_dbus_handle_get_connection_private(GBusType bus_type)
267 {
268         dbus_handle_s * dh;
269
270         if (bus_type != G_BUS_TYPE_SYSTEM && bus_type != G_BUS_TYPE_SESSION) {
271                 _E("Unknown bus type %d", bus_type);
272                 return NULL;
273         }
274
275         dh = (dbus_handle_s *)calloc(1, sizeof(dbus_handle_s));
276         if (!dh) {
277                 _E("failed to allocate memory for dbus handle");
278                 return NULL;
279         }
280
281         dbus_handle_lock(dh);
282
283         if (!dh->conn) {
284                 dh->conn = _get_bus_private(bus_type);
285                 dh->bus_type = bus_type;
286                 if (!dh->conn)
287                         goto err;
288         }
289
290         dbus_handle_unlock(dh);
291
292         return dh;
293 err:
294         if (dh) {
295                 dbus_handle_unlock(dh);
296                 free(dh);
297         }
298         return NULL;
299 }
300
301 dbus_handle_h dbus_handle_get_connection(GBusType bus_type, gboolean priv)
302 {
303         dbus_handle_s *dh = NULL;
304
305         if (bus_type != G_BUS_TYPE_SYSTEM && bus_type != G_BUS_TYPE_SESSION) {
306                 _E("Wrong bus_type %d\n", bus_type);
307                 return dh;
308         }
309
310         /* private */
311         if (priv)
312                 dh = _dbus_handle_get_connection_private(bus_type);
313         /* shared */
314         else
315                 dh = _dbus_handle_get_connection(bus_type);
316
317         return dh;
318 }
319
320 static void _dbus_handle_add_bus_name(dbus_handle_s *handle, const char *name, guint id)
321 {
322         dbus_name *dn = NULL;
323         int locked = 0;
324
325         if (!handle || !name || !id)
326                 return ;
327
328         dn = (dbus_name*)calloc(1, sizeof(dbus_name));
329         if (!dn) {
330                 _E("failed to calloc");
331                 assert(0);
332         }
333         dn->bus_name = name;
334         dn->id = id;
335
336         // todo : delete lock ?
337         locked = pthread_mutex_trylock(&handle->mutex);
338         if (locked != 0 && locked != EBUSY) {
339                 _E("failed to lock %d\n", locked);
340                 assert(0);
341         }
342
343         handle->list_names = g_list_prepend(handle->list_names, dn);
344
345         // todo : delete lock ?
346         if (locked != EBUSY)
347                 dbus_handle_unlock(handle);
348 }
349
350 static gint _compare_dbus_name(gconstpointer a, gconstpointer b)
351 {
352         const char *bus_name = ((dbus_name *)a)->bus_name;
353         if (!bus_name || !b)
354                 return -1;
355         return strcmp(bus_name, (const char *)b);
356 }
357
358 dbus_name * _dbus_handle_lookup_dbus_name(GList *list_name, const char *bus_name)
359 {
360         if (!list_name || !bus_name)
361                 return NULL;
362
363         GList *item = g_list_find_custom(list_name, bus_name, _compare_dbus_name);
364         if (!item)
365                 return NULL;
366
367         return (dbus_name *)item->data;
368 }
369
370 #define dh_to_ds(x) ((dbus_handle_s*)x)
371
372 /* remove dbus_name from dbus handle */
373 static void _dbus_handle_remove_bus_name(dbus_handle_s *handle, const char *bus_name)
374 {
375         dcl_dbus_handle();
376         dbus_name *dn = NULL;
377
378         if (!bus_name) {
379                 _E("wrong bus_name %s", bus_name);
380                 return ;
381         }
382         if (!dh) {
383                 dh = _dbus_handle_get_default_connection();
384                 if (!dh) {
385                         _E("failed to get default connection, bustype:%d", (int)dbus_handle_get_default_bus_type());
386                         return ;
387                 }
388         }
389
390         dbus_handle_lock(dh);
391         dn = _dbus_handle_lookup_dbus_name(dh->list_names, bus_name);
392         if (!dn) {
393                 _E("failed to find dbus name %s", bus_name);
394                 goto out;
395         }
396         dh->list_names = g_list_remove(dh->list_names, dn);
397         free(dn);
398 out:
399         dbus_handle_unlock(dh);
400 }
401
402 static void _name_acquired(GDBusConnection *connection, const gchar *name, gpointer user_data)
403 {
404         dbus_handle_s *dh = (dbus_handle_s *)user_data;
405
406         _D("name %s", name);
407
408         if (!dh) {
409                 _E("%s:%d:dbus handle is null\n", __func__, __LINE__);
410                 return ;
411         }
412         // todo: add bus name?
413         //dh->bus_name = name;
414 }
415
416 static void _name_lost(GDBusConnection *connection, const gchar *name, gpointer user_data)
417 {
418         _E("%s:%d:%s\n", __func__, __LINE__, name);
419         dbus_handle_s *dh = (dbus_handle_s *)user_data;
420         if (!dh) {
421                 _E("%s:%d:dbus handle is null\n", __func__, __LINE__);
422                 return ;
423         }
424         _dbus_handle_remove_bus_name(dh, name);
425 }
426
427 int dbus_handle_request_bus_name(dbus_handle_h handle, const char *bus_name)
428 {
429         dcl_dbus_handle();
430         int id = -1;
431         GList *item = NULL;
432
433         if (!bus_name) {
434                 _E("bus_name is NULL");
435                 return -1;
436         }
437
438         /* get shared connection */
439         if (!dh) {
440                 dh = _dbus_handle_get_default_connection();
441                 if (!dh) {
442                         _E("failed to get default connection, bustype:%d", (int)dbus_handle_get_default_bus_type());
443                         return -1;
444                 }
445         }
446
447         dbus_handle_lock(dh);
448         if (!dh->conn) {
449                 _E("failed to register name: connection is null\n");
450                 goto out;
451         }
452
453         /* todo : search name on connection */
454         item = g_list_find_custom(dh->list_names, bus_name, _compare_dbus_name);
455         if (item) {
456                 id = ((dbus_name*)(item->data))->id;
457                 _E("name already exist:%u", id);
458                 goto out;
459         }
460
461         id = g_bus_own_name_on_connection(dh->conn, bus_name, G_BUS_NAME_OWNER_FLAGS_NONE, _name_acquired, _name_lost, dh, NULL);
462         if (!id) {
463                 _E("failed to own name:%s\n", bus_name);
464                 goto out;
465         }
466
467         _dbus_handle_add_bus_name(dh, bus_name, id);
468
469 out:
470         dbus_handle_unlock(dh);
471         return id;
472 }
473
474 int dbus_handle_release_bus_name(dbus_handle_h handle, const char *bus_name)
475 {
476         dcl_dbus_handle();
477         dbus_name *dn = NULL;
478
479         if (!bus_name) {
480                 _E("Wrong bus name");
481                 return -1;
482         }
483
484         if (!dh) {
485                 dh = _dbus_handle_get_default_connection();
486                 if (!dh) {
487                         _E("failed to get default connection, bustype:%d", (int)dbus_handle_get_default_bus_type());
488                         return -1;
489                 }
490         }
491
492         dn = _dbus_handle_lookup_dbus_name(dh->list_names, bus_name);
493         if (!dn) {
494                 _E("failed to find bus_name %s on dbus handle", bus_name);
495                 return -1;
496         }
497
498         _E("unown name %d", dn->id);
499         /* _name_lost handler is disabled by g_bus_unown_name : ubuntu */
500         g_bus_unown_name(dn->id);
501
502         dbus_handle_lock(dh);
503         dh->list_names = g_list_remove(dh->list_names, dn);
504         free(dn);
505         dbus_handle_unlock(dh);
506
507         return 0;
508 }
509
510 int dbus_handle_free_connection(dbus_handle_h handle)
511 {
512         dcl_dbus_handle();
513         dbus_handle_s *pdh = NULL;
514         GError *err = NULL;
515         GList *item = NULL;
516
517         if (!dh) {
518                 dh = _dbus_handle_get_default_connection();
519                 if (!dh) {
520                         _E("failed to get default connection, bustype:%d", (int)dbus_handle_get_default_bus_type());
521                         return -1;
522                 }
523         }
524
525         if (!dh->conn) {
526                 _E("connection is NULL");
527                 return 0;
528         }
529
530         pdh = dh;
531
532         /* disable dbus handler */
533         dbus_handle_lock(dh);
534         if (!pdh->conn) {
535                 _E("conn is null");
536                 free(pdh);
537                 return 0;
538         }
539
540         /* flush everything */
541         if (!g_dbus_connection_flush_sync(pdh->conn, NULL, &err)) {
542                 _E("failed to flush %s\n", err->message);
543                 g_error_free(err);
544                 err = NULL;
545         }
546
547         _D("list_names %u", g_list_length(pdh->list_names));
548
549         /* unown every well-knwon name */
550         if (pdh->list_names) {
551                 dbus_name *dn = NULL;
552                 for (item = g_list_first(pdh->list_names); item != NULL; item = g_list_next(item)) {
553                         dn = (dbus_name *)item->data;
554                         if (!dn)
555                                 continue;
556
557                         /* _name_lost handler is disabled by g_bus_unown_name : ubuntu */
558                         _D("unown name id : %u", dn->id);
559                         g_bus_unown_name(dn->id);
560                         free(dn);
561                 }
562                 g_list_free(pdh->list_names);
563                 pdh->list_names = NULL;
564         }
565
566         _D("list_object %u", g_list_length(pdh->list_object));
567
568         /* unregister every object */
569         if (pdh->list_object) {
570                 dbus_object_handle_s * oh = NULL;
571                 //g_list_foreach(pdh->list_object, [] (gpointer data, gpointer user_data) {}, NULL);
572                 for (item = g_list_first(pdh->list_object); item != NULL; item = g_list_next(item)) {
573                         oh = (dbus_object_handle_s *)item->data;
574                         if (!oh || !oh->list_ifaces)
575                                 continue;
576
577                         _D("delete object path %s", oh->path);
578
579                         /* unregister every interface, method handles */
580                         for (GList *iface = g_list_first(oh->list_ifaces); iface != NULL; iface = g_list_next(iface)) {
581                                 dbus_interface_s *ih = (dbus_interface_s *)iface->data;
582                                 if (!ih)
583                                         continue;
584
585                                 _D("delete object iface %s", ih->name);
586
587                                 if (ih->reg_id)
588                                         g_dbus_connection_unregister_object(pdh->conn, ih->reg_id);
589                         }
590                 }
591         }
592
593         /* close connection */
594         if (pdh->priv) {
595                 _E("close private connection\n");
596
597                 if (!g_dbus_connection_close_sync(pdh->conn, NULL, &err)) {
598                         _E("Error closing connection %s\n", err->message);
599                         g_error_free(err);
600                         err = NULL;
601                 }
602         }
603
604         /* _free_func_object callback free the data */
605         //assert(g_list_length(pdh->list_names) == 0);
606         //assert(g_list_length(pdh->list_object) == 0);
607
608         g_object_unref(pdh->conn);
609
610         dbus_handle_unlock(dh);
611
612         if (dh->priv)
613                 free(dh);
614
615         return 0;
616
617         // todo: signal ?
618 }
619
620 #define buf_cal_free_space(size, nwrite) ((size - nwrite - 1) > 0 ? (size - nwrite - 1) : 0)
621 #define buf_block_size 8192
622
623 #define buf_check_space_realloc(buf, nwrite, buf_len) do {\
624         if ((nwrite >= buf_len - 1024)) {\
625                 if (buf_len >= buf_block_size * 10) {\
626                         _E("buf is too big to allocate. %d", buf_len);\
627                 } else {\
628                         _E("buf_check_space_realloc");\
629                         char *tmp = NULL;\
630                         buf_len += buf_block_size;\
631                         tmp = (char *)realloc(buf, buf_len);\
632                         if (!tmp) {\
633                                 _E("failed to realloc");\
634                         } else\
635                                 buf = tmp;\
636                 } \
637         } \
638 } while (0);
639
640 static int _check_brace(const char * expr)
641 {
642         int len = 0;
643         char qu[128];
644         int qucnt = 0;
645
646         if (!expr)
647                 return -1;
648
649         len = strlen(expr);
650
651         if (expr[0] != '(' && expr[0] != '{')
652                 return -1;
653
654         for (int i = 0 ; i < len; ++i) {
655
656                 if (expr[i] == '(' || expr[i] == '{') {
657                         qu[qucnt++] = expr[i];
658                         if (qucnt >= sizeof(qu)) {
659                                 _E("queue is too large. %s", expr);
660                                 return -1;
661                         }
662                         continue;
663                 }
664
665                 if (expr[i] == ')' || expr[i] == '}') {
666                         char ch;
667
668                         if (qucnt > 0)
669                                 ch = qu[qucnt-1];
670                         else
671                                 return -1;
672
673                         if (expr[i] == ')') {
674                                 if (ch == '(') {
675                                         --qucnt;
676                                 } else
677                                         return -1;
678                         } else if (expr[i] == '}') {
679                                 if (ch == '{') {
680                                         --qucnt;
681                                 } else
682                                         return -1;
683                         } else
684                                 return -1;
685
686                         if (qucnt == 0) {
687                                 return i + 1;
688                         }
689                 }
690         }
691
692         return -1;
693 }
694
695 static int _get_xml_from_interfaces(char **xml, const dbus_interface_s *interfaces)
696 {
697         int nwrite = 0;
698         int len_args;
699         char *buf = NULL;
700         const dbus_method_s *pmethod;
701         int buf_len = buf_block_size;
702
703         if (!interfaces) {
704                 _E("interfaces is null");
705                 return -1;
706         }
707
708         // todo : check dbus naming rule for interface name. ?
709         if (!interfaces->name) {
710                 _E("wrong interface name");
711                 return -1;
712         }
713         if (!interfaces->list_methods) {
714                 _E("no methods");
715                 return -1;
716         }
717
718         buf = (char *)malloc(buf_len);
719         if (!buf) {
720                 _E("buf is null. not enough memory\n");
721                 return -1;
722         }
723
724         nwrite += snprintf(buf + nwrite, buf_cal_free_space(buf_len, nwrite), "<node>""\n""\t""<interface name='%s'>""\n", interfaces->name);
725
726         /* members */
727         for (GList *item = g_list_first(interfaces->list_methods); item != NULL; item = g_list_next(item)) {
728                 pmethod = (const dbus_method_s *)item->data;
729                 if (!pmethod)
730                         continue;
731
732                 /* check free space of buf */
733                 buf_check_space_realloc(buf, nwrite, buf_len);
734
735                 if (pmethod->signature_in == NULL && pmethod->signature_out == NULL) {
736                         nwrite += snprintf(buf + nwrite, buf_cal_free_space(buf_len, nwrite), "\t\t""<method name='%s'/>""\n", pmethod->member);
737                         continue;
738                 }
739
740                 /* <method name='###'> */
741                 nwrite += snprintf(buf + nwrite, buf_cal_free_space(buf_len, nwrite), "\t\t""<method name='%s'>""\n", pmethod->member);
742
743                 /* in args */
744                 len_args = pmethod->signature_in ? strlen(pmethod->signature_in) : 0;
745                 for (int m = 0; m < len_args; ++m) {
746                         // todo
747                         // array a(), as, ay ?
748                         if (pmethod->signature_in[m] == 'a') {
749                                 int ei; //end index
750                                 ei = _check_brace(pmethod->signature_in + m + 1);
751                                 if (ei > 0) {
752                                         char tmp[128] = {0,};
753                                         strncpy(tmp, pmethod->signature_in + m, ei + 1);
754                                         nwrite += snprintf(buf + nwrite, buf_cal_free_space(buf_len, nwrite), "\t\t\t""<arg type='%s' name='arg%d' direction='in'/>""\n", tmp, m);
755                                         m += ei;
756                                         continue;
757                                 } else {
758                                         nwrite += snprintf(buf + nwrite, buf_cal_free_space(buf_len, nwrite), "\t\t\t""<arg type='%c%c' name='arg%d' direction='in'/>""\n", pmethod->signature_in[m], pmethod->signature_in[m+1], m);
759                                         m += 1;
760                                         continue;
761                                 }
762                         }
763                         nwrite += snprintf(buf + nwrite, buf_cal_free_space(buf_len, nwrite), "\t\t\t""<arg type='%c' name='arg%d' direction='in'/>""\n", pmethod->signature_in[m], m);
764                 }
765
766                 /* out args */
767                 len_args = pmethod->signature_out ? strlen(pmethod->signature_out) : 0;
768                 for (int m = 0; m < len_args; ++m) {
769                         // array
770                         // todo: container type
771                         if (pmethod->signature_out[m] == 'a') {
772                                 int ei; //end index
773                                 ei = _check_brace(pmethod->signature_out + m + 1);
774                                 if (ei > 0) {
775                                         char tmp[128] = {0,};
776                                         strncpy(tmp, pmethod->signature_out + m, ei + 1);
777                                         nwrite += snprintf(buf + nwrite, buf_cal_free_space(buf_len, nwrite), "\t\t\t""<arg type='%s' name='arg%d' direction='out'/>""\n", tmp, m);
778                                         m += ei;
779                                         continue;
780                                 } else {
781                                         nwrite += snprintf(buf + nwrite, buf_cal_free_space(buf_len, nwrite), "\t\t\t""<arg type='%c%c' name='arg%d' direction='out'/>""\n", pmethod->signature_out[m], pmethod->signature_out[m+1], m);
782                                         m += 1;
783                                         continue;
784                                 }
785                         }
786                         nwrite += snprintf(buf + nwrite, buf_cal_free_space(buf_len, nwrite), "\t\t\t""<arg type='%c' name='arg%d' direction='out'/>""\n", pmethod->signature_out[m], m);
787                 }
788
789                 /* </method> */
790                 nwrite += snprintf(buf + nwrite, buf_cal_free_space(buf_len, nwrite), "\t\t""</method>""\n");
791         }
792
793         nwrite += snprintf(buf + nwrite, buf_cal_free_space(buf_len, nwrite), "\t""</interface>""\n""</node>""");
794
795         *xml = buf;
796
797         /* todo: delete log */
798 #if 0
799         if (nwrite <= 512)
800                 _E("%s", buf);
801         else
802                 _E("%s", buf + nwrite - 512);
803 #endif
804         return 0;
805 }
806
807 static gint _compare_dbus_object(gconstpointer a, gconstpointer b)
808 {
809         dbus_object_handle_s * pa = (dbus_object_handle_s *)a;
810         if (!pa->path || !((const char*)b))
811                 return -1;
812         return strcmp(pa->path, (const char*)b);
813 }
814
815 static gint _compare_dbus_interface(gconstpointer a, gconstpointer b)
816 {
817         dbus_interface_s * pa = (dbus_interface_s *)a;
818         if (!pa->name || !((const char*)b))
819                 return -1;
820         return strcmp(pa->name, (const char*)b);
821 }
822
823 static gint _compare_dbus_interface_by_id(gconstpointer a, gconstpointer b)
824 {
825         dbus_interface_s * pa = (dbus_interface_s *)a;
826         if (!pa->reg_id || !((guint*)b))
827                 return -1;
828         return !(pa->reg_id == *((guint*)b));
829 }
830
831 static gint _compare_dbus_method(gconstpointer a, gconstpointer b)
832 {
833         dbus_method_s *pa = (dbus_method_s*)a;
834         if (!pa->member || !((const char*)b))
835                 return -1;
836         return strcmp(pa->member, (const char*)b);
837 }
838
839 dbus_object_handle_s * _dbus_handle_lookup_object(GList *list_obj, const char *obj_path)
840 {
841         if (!list_obj || !obj_path)
842                 return NULL;
843
844         GList *item = g_list_find_custom(list_obj, obj_path, _compare_dbus_object);
845         if (!item)
846                 return NULL;
847
848         return (dbus_object_handle_s *)item->data;
849 }
850
851 dbus_interface_s * _dbus_handle_lookup_interface(GList *list_iface, const char *iface_name)
852 {
853         if (!list_iface || !iface_name)
854                 return NULL;
855
856         GList *item = g_list_find_custom(list_iface, iface_name, _compare_dbus_interface);
857         if (!item)
858                 return NULL;
859
860         return (dbus_interface_s *)item->data;
861 }
862
863 dbus_interface_s * _dbus_handle_lookup_interface_by_id(GList *list_iface, guint id)
864 {
865         if (!list_iface || !id)
866                 return NULL;
867
868         GList *item = g_list_find_custom(list_iface, &id, _compare_dbus_interface_by_id);
869         if (!item)
870                 return NULL;
871
872         return (dbus_interface_s *)item->data;
873 }
874
875 dbus_method_s * _dbus_handle_lookup_method(GList *list_methods, const char *method_name)
876 {
877         if (!list_methods || !method_name)
878                 return NULL;
879
880         GList *item = g_list_find_custom(list_methods, method_name, _compare_dbus_method);
881         if (!item)
882                 return NULL;
883
884         return (dbus_method_s *)item->data;
885 }
886
887 static void _free_func_object(gpointer data)
888 {
889         dbus_interface_s *ih = (dbus_interface_s *)data;
890         dbus_object_handle_s *oh = NULL;
891
892         if (!ih) {
893                 _E("interface handle is null");
894                 assert(0); // something wrong
895                 return ;
896         }
897
898         _E("unregister interface %s", ih->name);
899
900         /* just free list, not data(static dbus_method_s) */
901         g_list_free(ih->list_methods);
902
903         oh = ih->oh;
904         if (!oh) {
905                 _E("object handle is null");
906                 assert(0); // something wrong
907                 return ;
908         }
909
910         /* remove ih from list_ifaces */
911         oh->list_ifaces = g_list_remove(oh->list_ifaces, ih);
912
913         /* interface_s is copy of interface_u */
914         free(ih);
915
916         /* remove oh from list_object */
917         if (!oh->list_ifaces) {
918                 oh->dh->list_object = g_list_remove(oh->dh->list_object, oh);
919                 free(oh);
920         }
921 }
922
923 static int _dbus_handle_attach_object(dbus_handle_s *dh, const char *obj_path, dbus_interface_s *iface)
924 {
925         dbus_object_handle_s *oh = NULL;
926
927         if (!dh || !obj_path || !iface) {
928                 _E("failed to attache object. wrong parameter");
929                 return -1;
930         }
931
932         /* find object handle */
933         if (dh->list_object)
934                 oh = _dbus_handle_lookup_object(dh->list_object, obj_path);
935
936         if (!oh) {
937                 oh = (dbus_object_handle_s*)calloc(1, sizeof(dbus_object_handle_s));
938                 if (!oh) {
939                         _E("failed to calloc");
940                         return -1;
941                 }
942                 oh->dh = dh;
943                 oh->path = obj_path;
944
945                 /* attach object */
946                 dh->list_object = g_list_prepend(dh->list_object, oh);
947         }
948
949         iface->oh = oh;
950         /* attach interface */
951         oh->list_ifaces = g_list_prepend(oh->list_ifaces, iface);
952
953         return 0;
954 }
955
956 /* libgio verify path and interface */
957 static void _method_call_handler(GDBusConnection *conn,
958         const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
959         GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
960 {
961         dbus_interface_s *iface_s = (dbus_interface_s *)user_data;
962         const dbus_method_s *methods;
963         GVariant *result = NULL;
964
965         /* todo: ghash ? */
966         methods = _dbus_handle_lookup_method(iface_s->list_methods, name);
967         if (methods) {
968                 result = methods->func(conn, sender, path, iface, name, param, invocation, get_dh_from_oh(iface_s->oh));
969
970                 /* async, maybe they will reply...maybe.. */
971                 if (!result) {
972                         _E("finish method handle : NULL");
973                         return ;
974                 }
975         } else {
976                 _E("no methods");
977         }
978
979         g_dbus_method_invocation_return_value(invocation, result);
980         //if (g_variant_is_of_type(result, G_VARIANT_TYPE_TUPLE)) {
981         //      //_E("TUPLE %s", g_variant_get_type_string(result));
982         //      g_dbus_method_invocation_return_value(invocation, result);
983         //}
984         //else if (g_variant_is_container(result)) {
985         //      /* todo: we don't have any plan to using variant type for reply */
986         //      _E("CONTAINER %s", g_variant_get_type_string(result));
987         //      g_dbus_method_invocation_return_value(invocation, result);
988         //      //g_dbus_method_invocation_return_value(invocation, g_variant_new("(v)", result));
989         //} else {
990         //      _E("Type is not Container : %s", g_variant_get_type_string(result));
991         //}
992 }
993
994 static GDBusInterfaceVTable path_vtable = {_method_call_handler};
995
996
997 /*
998 before register object, attach object into dbus handle
999 _dbus_handle_attach_object()
1000 */
1001 static int _dbus_handle_register_dbus_object(dbus_handle_h handle, const char *obj_path, dbus_interface_s *iface)
1002 {
1003         dcl_dbus_handle();
1004         int ret = 0;
1005         char *buf = NULL;
1006         GError *err = NULL;
1007         GDBusNodeInfo * nodeinfo = NULL;
1008         GDBusInterfaceInfo *ifaceinfo = NULL;
1009
1010         if (!obj_path || !iface) {
1011                 _E("wrong parameter\n");
1012                 return -1;
1013         }
1014         if (!dh) {
1015                 dh = _dbus_handle_get_default_connection();
1016                 if (!dh) {
1017                         _E("failed to get default connection, bustype:%d", (int)dbus_handle_get_default_bus_type());
1018                         return -1;
1019                 }
1020         }
1021         if (!dh->conn) {
1022                 _E("connection is null\n");
1023                 return -1;
1024         }
1025
1026         ret = _get_xml_from_interfaces(&buf, iface);
1027         if (ret < 0) {
1028                 _E("failed to make xml format");
1029                 goto err;
1030         }
1031
1032         /* todo: delete this */
1033 #if 0
1034         if (strlen(buf) <= 512) {
1035                 _E("%s", buf);
1036         } else {
1037                 _E("%s", buf + strlen(buf) - 512);
1038         }
1039 #endif
1040
1041         nodeinfo = g_dbus_node_info_new_for_xml(buf, &err);
1042         if (!nodeinfo || err) {
1043                 _E("failed to make introspection data:err:%s:xml:%s\n", err->message, buf);
1044                 ret = -1;
1045                 goto err;
1046         }
1047
1048         ifaceinfo = g_dbus_node_info_lookup_interface(nodeinfo, iface->name);
1049         if (!ifaceinfo) {
1050                 _E("failed to g_dbus_node_info_lookup_interface");
1051                 ret = -1;
1052                 goto err;
1053         }
1054
1055         /*
1056                 path own single interface
1057                 if interface is already registered, then failed.
1058                 g_dbus_connection_register_object ref(ifaceinfo) now, unref if object is unregistered
1059         */
1060         ret = g_dbus_connection_register_object(dh->conn, obj_path, ifaceinfo/*ref 2*/, &path_vtable, (void*)iface,
1061                 _free_func_object,
1062                 &err);
1063         if (err) {
1064                 _E("failed to register object:err:%s:\n", err->message);
1065                 ret = -1;
1066                 goto err;
1067         }
1068
1069         iface->reg_id = ret;
1070         iface->modified = FALSE;
1071
1072 err:
1073         /* todo: detach object */
1074         //_dbus_handle_detach_object(dh, obj_path, iface);
1075         /* attach interface before register object */
1076         /*ret = _dbus_handle_detach_object(dh, obj_path, iface);
1077         if (ret < 0) {
1078                 _E("failed to attach object");
1079                 goto err;
1080         }*/
1081
1082         if (nodeinfo)
1083                 g_dbus_node_info_unref(nodeinfo);
1084         if (buf)
1085                 free(buf);
1086         if (err)
1087                 g_error_free(err);
1088
1089         return ret;
1090 }
1091
1092 /*
1093 register same interface at once
1094
1095 if interface is constructed by multiple methods,
1096 also it is not possible to make methods struct at once,
1097
1098 use dbus_handle_add_dbus_object(), dbus_handle_register_dbus_object_all().
1099
1100 return reg_id
1101 */
1102 int dbus_handle_register_dbus_object(dbus_handle_h handle, const char *obj_path, const dbus_interface_u *iface_u)
1103 {
1104         dcl_dbus_handle();
1105         int ret = 0;
1106         dbus_interface_s *iface = NULL;
1107
1108         if (!obj_path || !iface_u) {
1109                 _E("wrong parameter\n");
1110                 return -1;
1111         }
1112         if (!dh) {
1113                 dh = _dbus_handle_get_default_connection();
1114                 if (!dh) {
1115                         _E("failed to get default connection, bustype:%d", (int)dbus_handle_get_default_bus_type());
1116                         return -1;
1117                 }
1118         }
1119         if (!dh->conn) {
1120                 _E("connection is null\n");
1121                 return -1;
1122         }
1123
1124         /* check registered interface */
1125         if (dh->list_object) {
1126                 dbus_object_handle_s *oh = _dbus_handle_lookup_object(dh->list_object, obj_path);
1127                 if (oh) {
1128                         dbus_interface_s *ih = _dbus_handle_lookup_interface(oh->list_ifaces, iface_u->name);
1129                         if (ih) {
1130                                 _E("path %s, interface %s already registered", obj_path, iface_u->name);
1131                                 return -1;
1132                         }
1133                 }
1134         }
1135
1136         iface = _iface_u_to_s(iface_u);
1137         if (!iface) {
1138                 _E("failed to _iface_u_to_s");
1139                 return -1;
1140         }
1141
1142         /* attach interface before register object */
1143         ret = _dbus_handle_attach_object(dh, obj_path, iface);
1144         if (ret < 0) {
1145                 _E("failed to attach object");
1146                 goto err;
1147         }
1148
1149         ret = _dbus_handle_register_dbus_object(dh, obj_path, iface);
1150         if (ret <= 0) {
1151                 _E("failed to register dbus object%d", ret);
1152                 goto err;
1153         }
1154 err:
1155         return ret;
1156 }
1157
1158 int dbus_handle_unregister_dbus_object(dbus_handle_h handle, const char *obj_path)
1159 {
1160         dcl_dbus_handle();
1161         dbus_object_handle_s *oh = NULL;
1162         int ret = 0;
1163
1164         if (!obj_path) {
1165                 return -1;
1166         }
1167         if (!dh) {
1168                 dh = _dbus_handle_get_default_connection();
1169                 if (!dh) {
1170                         _E("failed to get default connection, bustype:%d", (int)dbus_handle_get_default_bus_type());
1171                         return -1;
1172                 }
1173         }
1174         if (!dh->list_object) {
1175                 _E("list_object is empty");
1176                 return 0;
1177         }
1178
1179         oh = _dbus_handle_lookup_object(dh->list_object, obj_path);
1180         if (!oh) {
1181                 _E("no object with name %s", obj_path);
1182                 return -1;
1183         }
1184
1185         /* unregister every interface of object*/
1186         for (GList *item = g_list_first(oh->list_ifaces); item != NULL; item = g_list_next(item)) {
1187                 dbus_interface_s *ih = item->data;
1188                 if (!ih) {
1189                         _E("this is error");
1190                         assert(0);
1191                 }
1192
1193                 /* remove ih from list_ifaces */
1194                 if (!ih->reg_id) {
1195                         item = g_list_previous(item);
1196
1197                         /* remove and free link */
1198                         oh->list_ifaces = g_list_remove(oh->list_ifaces, ih);
1199
1200                         /* free list_methods */
1201                         g_list_free(ih->list_methods);
1202
1203                         /* free data */
1204                         free(ih);
1205                         continue;
1206                 }
1207
1208                 /* unregister object by id */
1209                 ret = g_dbus_connection_unregister_object(dh->conn, ih->reg_id);
1210                 if (!ret)
1211                         _E("failed to unregister object %s, interface %s, regid %d", oh->path, ih->name, ih->reg_id);
1212         }
1213
1214         return 0;
1215 }
1216
1217 /*
1218 add object temporarily.
1219 dbus_handle_register_dbus_object_all will register every objects on connection.
1220
1221 return registered method count
1222 */
1223 int dbus_handle_add_dbus_object(dbus_handle_h handle, const char *obj_path, const dbus_interface_u *iface_u)
1224 {
1225         dcl_dbus_handle();
1226         dbus_object_handle_s *oh = NULL;
1227         dbus_interface_s *ih = NULL;
1228         int cnt;
1229
1230         if (!obj_path || !iface_u) {
1231                 _E("wrong parameter path %s, iface_u %p\n", obj_path, iface_u);
1232                 return -1;
1233         }
1234         if (iface_u && (!iface_u->name || !iface_u->methods)) {
1235                 _E("wrong parameter path %s, iface_u %p\n", obj_path, iface_u);
1236                 return -1;
1237         }
1238
1239         cnt = iface_u->nr_methods;
1240
1241         if (!dh) {
1242                 dh = _dbus_handle_get_default_connection();
1243                 if (!dh) {
1244                         _E("failed to get default connection, bustype:%d", (int)dbus_handle_get_default_bus_type());
1245                         return -1;
1246                 }
1247         }
1248
1249         if (!dh->conn) {
1250                 _E("failed to register method. connection is null\n");
1251                 return -1;
1252         }
1253
1254         /* if there are no object list, just add */
1255         if (!dh->list_object) {
1256                 if (_dbus_handle_attach_object(dh, obj_path, _iface_u_to_s(iface_u))) {
1257                         _E("failed to attach object");
1258                         return -1;
1259                 }
1260                 goto out;
1261         }
1262
1263         oh = _dbus_handle_lookup_object(dh->list_object, obj_path);
1264         /* if there are no matched object, just add */
1265         if (!oh) {
1266                 if (_dbus_handle_attach_object(dh, obj_path, _iface_u_to_s(iface_u))) {
1267                         _E("failed to attach object");
1268                         return -1;
1269                 }
1270                 goto out;
1271         }
1272
1273         /* this is an error, interface must have one or more item ? */
1274         if (!oh->list_ifaces) {
1275                 _E("error. list_ifaces is null\n");
1276                 assert(0);
1277                 goto out;
1278         }
1279
1280         ih = _dbus_handle_lookup_interface(oh->list_ifaces, iface_u->name);
1281         /* if there are no matched interface, just add */
1282         if (!ih) {
1283                 if (_dbus_handle_attach_object(dh, obj_path, _iface_u_to_s(iface_u))) {
1284                         _E("failed to attach object");
1285                         return -1;
1286                 }
1287                 goto out;
1288         }
1289
1290         /*  todo:
1291                 1. unregister interface
1292                 2. update interface and methods
1293                 3. register interface
1294         */
1295         if (ih->reg_id) {
1296                 _E("interface already registered, ignore new interface");
1297                 return -1;
1298         }
1299
1300         /* attach new methods */
1301         cnt = 0;
1302         for (int i = 0; i < iface_u->nr_methods; ++i) {
1303                 GList *item = g_list_find_custom(g_list_first(ih->list_methods), iface_u->methods[i].member, _compare_dbus_method);
1304                 if (!item) {
1305                         //_D("attached %s", iface_u->methods[i].member);
1306                         ih->list_methods = g_list_prepend(ih->list_methods, (void*)(iface_u->methods + i));
1307                         ++cnt;
1308                 }
1309         }
1310
1311         if (cnt)
1312                 ih->modified = TRUE;
1313
1314 out:
1315         /*todo: delete debugging log */
1316         //if (dh && dh->list_object)
1317         //      _D("obj list len %d", g_list_length(dh->list_object));
1318         //if (oh && oh->list_ifaces)
1319         //      _D("iface list len %d", g_list_length(oh->list_ifaces));
1320         //if (ih && ih->list_methods)
1321         //      _D("method list len %d", g_list_length(ih->list_methods));
1322
1323         return cnt;
1324 }
1325
1326 int dbus_handle_register_dbus_object_all(dbus_handle_h handle)
1327 {
1328         dcl_dbus_handle();
1329         dbus_object_handle_s *oh = NULL;
1330         dbus_interface_s *ih = NULL;
1331         int ret = 0;
1332
1333         if (!dh) {
1334                 dh = _dbus_handle_get_default_connection();
1335                 if (!dh) {
1336                         _E("failed to get default connection, bustype:%d", (int)dbus_handle_get_default_bus_type());
1337                         return -1;
1338                 }
1339         }
1340         if (!dh->conn) {
1341                 _E("connection is null\n");
1342                 return -1;
1343         }
1344
1345         if (!dh->list_object) {
1346                 _E("obj list is empty");
1347                 return -1;
1348         }
1349
1350         /*if (dh && dh->list_object)
1351                 _D("obj list len %d", g_list_length(dh->list_object));*/
1352
1353         for (GList *item = g_list_first(dh->list_object); item != NULL; item = g_list_next(item)) {
1354                 oh = (dbus_object_handle_s *)item->data;
1355
1356                 if (!oh) {
1357                         _E("something wrong");
1358                         assert(0);
1359                 }
1360                 if (!oh->list_ifaces) {
1361                         _E("path %s: list_ifaces are null", oh->path);
1362                         goto err;
1363                 }
1364
1365                 //_D("iface list len %d", g_list_length(oh->list_ifaces));
1366
1367                 for (GList *li = g_list_first(oh->list_ifaces); li != NULL; li = g_list_next(li)) {
1368                         ih = (dbus_interface_s *)li->data;
1369
1370                         /* if there are no modification, goto next */
1371                         if (!ih->modified)
1372                                 continue;
1373
1374                         /* todo: if already registered interface, unregister first */
1375
1376                         /*_E("interface %s:", ih->name);
1377                         if (ih && ih->list_methods)
1378                                 _D("method list len %d", g_list_length(ih->list_methods));*/
1379
1380                         ret = _dbus_handle_register_dbus_object(dh, oh->path, ih);
1381                         if (ret <= 0)
1382                                 _E("failed to register dbus object%d", ret);
1383
1384                 }
1385         }
1386         return 0;
1387 err:
1388
1389         // todo: delete all updates
1390
1391         return -1;
1392 }
1393
1394 static void _free_func_signal(gpointer data)
1395 {
1396         //_D("free signal subscribe");
1397 }
1398
1399 guint subscribe_dbus_signal(dbus_handle_h handle, const char *path,
1400                                                         const char *iface, const char *name,
1401                                                         GDBusSignalCallback cb, void *data,
1402                                                         destroy_notified free_func)
1403 {
1404         dcl_dbus_handle();
1405
1406         if (!dh) {
1407                 dh = _dbus_handle_get_default_connection();
1408                 if (!dh) {
1409                         _E("failed to get default connection, bustype:%d", (int)dbus_handle_get_default_bus_type());
1410                         return 0;
1411                 }
1412         }
1413
1414         if (!dh->conn) {
1415                 _E("connection is null. check bus status");
1416                 return 0;
1417         }
1418         return g_dbus_connection_signal_subscribe(dh->conn, NULL, iface, name, path, NULL, G_DBUS_SIGNAL_FLAGS_NONE, cb, data, _free_func_signal);
1419 }
1420
1421 void unsubscribe_dbus_signal(dbus_handle_h handle, guint id)
1422 {
1423         dcl_dbus_handle();
1424         if (!dh) {
1425                 dh = _dbus_handle_get_default_connection();
1426                 if (!dh) {
1427                         _E("failed to get default connection, bustype:%d", (int)dbus_handle_get_default_bus_type());
1428                         return ;
1429                 }
1430         }
1431
1432         if (!dh->conn) {
1433                 _E("connection is null. check bus status");
1434                 return ;
1435         }
1436
1437         g_dbus_connection_signal_unsubscribe(dh->conn, id);
1438 }
1439
1440 int _check_type_string_is_container(const char *signature)
1441 {
1442         if (!signature)
1443                 return FALSE;
1444
1445         switch (signature[0]) {
1446         case 'a':
1447         case 'm':
1448         case 'r':
1449         case '(':
1450         case '{':
1451         case 'v':
1452                 return TRUE;
1453         default:
1454                 return FALSE;
1455         }
1456
1457         return TRUE;
1458 }
1459
1460 GVariant *dbus_handle_make_simple_array(const char *sig, int *param)
1461 {
1462         GVariantBuilder *builder = NULL;
1463         GVariant *var = NULL;
1464         char format[256];
1465         int i = 0;
1466
1467         builder = g_variant_builder_new(G_VARIANT_TYPE(sig));
1468         if (!builder) {
1469                 _E("failed to g_variant_builder_new");
1470                 return NULL;
1471         }
1472
1473         while (param[i])
1474                 g_variant_builder_add(builder, "i", param[i++]);
1475
1476         snprintf(format, sizeof(format) - 1, "(%s)", sig);
1477         var = g_variant_new(format, builder);
1478         g_variant_builder_unref(builder);
1479         return var;
1480 }
1481
1482 /* todo: looks like garbage... */
1483 static GVariant* _append_variant(const char *signature, const char *param[])
1484 {
1485         char *ch;
1486         int i;
1487         int pi;
1488         int int_type;
1489         gboolean bool_type;
1490         unsigned long long int64_type;
1491         GVariant *ret;
1492         int len;
1493         char container[255];// The maximum length of a signature is 255.
1494         const char *sig = signature;
1495         GVariantBuilder *builder = NULL;
1496
1497         if (!signature || !param)
1498                 return 0;
1499
1500         /* workaround for user fault "(i) != i" but we treat this as same signature */
1501         /* G_VARIANT_TYPE("si") return NULL */
1502         /* todo: actually user have to use correct signature */
1503         if (!_check_type_string_is_container(signature)) {
1504                 snprintf(container, sizeof(container) - 1, "(%s)", signature);
1505                 sig = container;
1506         }
1507         if (!g_variant_type_is_container(G_VARIANT_TYPE(sig))) {
1508                 _E("signature (%s) is not container type", signature);
1509         }
1510
1511         builder = g_variant_builder_new(G_VARIANT_TYPE(sig));
1512         len = strlen(sig);
1513         pi = 0;
1514         for (ch = (char *)sig, i = 0; i < len; ++i, ++ch) {
1515                 switch (*ch) {
1516                 case '(':
1517                 case ')':
1518                         continue;
1519                 case 'b':
1520                         bool_type = (atoi(param[pi++]) == 0 ? FALSE : TRUE);
1521                         g_variant_builder_add(builder, "b", bool_type);
1522                         break;
1523                 case 'i':
1524                         int_type = atoi(param[pi++]);
1525                         g_variant_builder_add(builder, "i", int_type);
1526                         break;
1527                 case 'u':
1528                         int_type = strtoul(param[pi++], NULL, 10);
1529                         g_variant_builder_add(builder, "u", int_type);
1530                         break;
1531                 case 't':
1532                         int64_type = atoll(param[pi++]);
1533                         g_variant_builder_add(builder, "t", int64_type);
1534                         break;
1535                 case 's':
1536                         g_variant_builder_add(builder, "s", param[pi++]);
1537                         break;
1538                 case 'a':
1539                         ++ch;
1540                         switch (*ch) {
1541                         case 'y':
1542                                 g_variant_builder_add(builder, "^ay", param[pi++]);
1543                                 ++i;
1544                                 break;
1545                         default:
1546                                 break;
1547                         }
1548                         break;
1549                 default:
1550                         break;
1551                 }
1552         }
1553         ret = g_variant_builder_end(builder);
1554         g_variant_builder_clear(builder);
1555         g_variant_builder_unref(builder);
1556
1557         return ret;
1558 }
1559
1560 int dbus_handle_broadcast_dbus_signal(const char *path,
1561                                                                 const char *iface, const char *name,
1562                                                                 const char *signature, const char *param[])
1563 {
1564         dbus_handle_s *dh = NULL;
1565         GError *err = NULL;
1566         gboolean ret = 0;
1567         GVariant *var = NULL;
1568
1569         dh = _dbus_handle_get_default_connection();
1570         if (!dh) {
1571                 _E("failed to get default connection, bustype:%d", (int)dbus_handle_get_default_bus_type());
1572                 return -1;
1573         }
1574
1575         if (signature && param)
1576                 var = _append_variant(signature, param);
1577         ret = g_dbus_connection_emit_signal(dh->conn, NULL, path, iface, name, var, &err);
1578         if (err) {
1579                 _E("%d %s\n", ret, err ? err->message : NULL);
1580                 g_error_free(err);
1581         }
1582
1583         return ret;
1584 }
1585
1586 int dbus_handle_broadcast_dbus_signal_var(const char *path,
1587                                                                                         const char *iface, const char *name,
1588                                                                                         GVariant *param)
1589 {
1590         dbus_handle_s *dh = NULL;
1591         GError *err = NULL;
1592         gboolean ret = 0;
1593
1594         dh = _dbus_handle_get_default_connection();
1595         if (!dh) {
1596                 _E("failed to get default connection, bustype:%d", (int)dbus_handle_get_default_bus_type());
1597                 return -1;
1598         }
1599
1600         ret = g_dbus_connection_emit_signal(dh->conn, NULL, path, iface, name, param, &err);
1601         if (err) {
1602                 _E("%d %s\n", ret, err ? err->message : NULL);
1603                 g_error_free(err);
1604         }
1605
1606         return ret;
1607 }
1608
1609 GVariant *dbus_method_sync_with_reply(const char *dest, const char *path,
1610                                                                                 const char *iface, const char *method,
1611                                                                                 const char *signature, const char *param[])
1612 {
1613         GError *err = NULL;
1614         GVariant * var = NULL;
1615         GVariant * ret = NULL;
1616         dbus_handle_s *dh = NULL;
1617
1618         if (!dest || !path || !iface || !method) {
1619                 _E("wrong parameters dest(%s) path(%s) iface(%s) method(%s)", dest, path, iface, method);
1620                 return NULL;
1621         }
1622
1623         dh = _dbus_handle_get_default_connection();
1624         if (!dh) {
1625                 _E("failed to get default connection, bustype:%d", (int)dbus_handle_get_default_bus_type());
1626                 return NULL;
1627         }
1628
1629         if (signature && param)
1630                 var = _append_variant(signature, param);
1631
1632         ret = g_dbus_connection_call_sync(dh->conn,
1633                 dest, path, iface, method,
1634                 var, NULL, G_DBUS_CALL_FLAGS_NONE, DBUS_REPLY_TIMEOUT, NULL, &err);
1635         if (!ret || err) {
1636                 if (err) {
1637                         _E("failed to g_dbus_connection_call_sync:%s", err->message);
1638                         g_error_free(err);
1639                 } else {
1640                         _E("failed to g_dbus_connection_call_sync");
1641                         g_variant_unref(var);
1642                 }
1643                 return NULL;
1644         }
1645
1646         return ret;
1647 }
1648
1649 GVariant *dbus_method_sync_with_reply_var(const char *dest, const char *path,
1650         const char *iface, const char *method, GVariant *var)
1651 {
1652         GError *err = NULL;
1653         GVariant * ret = NULL;
1654         dbus_handle_s *dh = NULL;
1655
1656         if (!dest || !path || !iface || !method) {
1657                 _E("wrong parameters dest(%s) path(%s) iface(%s) method(%s)", dest, path, iface, method);
1658                 if (var)
1659                         g_variant_unref(var);
1660                 return NULL;
1661         }
1662
1663         dh = _dbus_handle_get_default_connection();
1664         if (!dh) {
1665                 _E("failed to get default connection, bustype:%d", (int)dbus_handle_get_default_bus_type());
1666                 if (var)
1667                         g_variant_unref(var);
1668                 return NULL;
1669         }
1670
1671         ret = g_dbus_connection_call_sync(dh->conn,
1672                                                                                 dest, path, iface, method,
1673                                                                                 var, NULL, G_DBUS_CALL_FLAGS_NONE, DBUS_REPLY_TIMEOUT, NULL, &err);
1674         if (!ret || err) {
1675                 if (err) {
1676                         _E("failed to g_dbus_connection_call_sync:%s", err->message);
1677                         g_error_free(err);
1678                 } else {
1679                         _E("failed to g_dbus_connection_call_sync");
1680                 }
1681                 return NULL;
1682         }
1683
1684         return ret;
1685 }
1686
1687 GVariant *dbus_method_sync_with_reply_var_timeout(const char *dest, const char *path,
1688         const char *iface, const char *method, GVariant *var, int timeout)
1689 {
1690         GError *err = NULL;
1691         GVariant * ret = NULL;
1692         dbus_handle_s *dh = NULL;
1693
1694         if (!dest || !path || !iface || !method) {
1695                 _E("wrong parameters dest(%s) path(%s) iface(%s) method(%s)", dest, path, iface, method);
1696                 if (var)
1697                         g_variant_unref(var);
1698                 return NULL;
1699         }
1700
1701         dh = _dbus_handle_get_default_connection();
1702         if (!dh) {
1703                 _E("failed to get default connection, bustype:%d", (int)dbus_handle_get_default_bus_type());
1704                 if (var)
1705                         g_variant_unref(var);
1706                 return NULL;
1707         }
1708
1709         ret = g_dbus_connection_call_sync(dh->conn,
1710                                                                                 dest, path, iface, method,
1711                                                                                 var, NULL, G_DBUS_CALL_FLAGS_NONE, timeout, NULL, &err);
1712         if (!ret || err) {
1713                 if (err) {
1714                         _E("failed to g_dbus_connection_call_sync:%s", err->message);
1715                         g_error_free(err);
1716                 } else {
1717                         _E("failed to g_dbus_connection_call_sync");
1718                 }
1719                 return NULL;
1720         }
1721
1722         return ret;
1723 }
1724
1725 gint* dbus_handle_get_unix_fd_list(GDBusMethodInvocation *invocation, int *size)
1726 {
1727         GUnixFDList *fd_list = NULL;
1728         int length = 0;
1729
1730         fd_list = g_dbus_message_get_unix_fd_list(g_dbus_method_invocation_get_message(invocation));
1731
1732         if (!fd_list) {
1733                 _E("failed to g_unix_fd_list_get_length: fd_list is null");
1734                 return NULL;
1735         }
1736
1737         length = g_unix_fd_list_get_length(fd_list);
1738         if (length == 0) {
1739                 _E("failed to g_unix_fd_list_get_length: list size is 0");
1740                 return NULL;
1741         }
1742         if (size)
1743                 *size = length;
1744
1745         return g_unix_fd_list_steal_fds(fd_list, NULL);
1746 }
1747
1748 GVariant *dbus_method_with_unix_fd_list_sync_with_reply(const char *dest, const char *path,
1749                                                                                                                 const char *iface, const char *method,
1750                                                                                                                 const char *signature, const char *param[],
1751                                                                                                                 int *in_fdlist, int in_size,
1752                                                                                                                 int **out_fdlist, int *out_size)
1753 {
1754         GError *err = NULL;
1755         GVariant * var = NULL;
1756         GVariant * ret = NULL;
1757         dbus_handle_s *dh = NULL;
1758         GDBusProxy *proxy = NULL;
1759         GUnixFDList *g_infdlist = NULL;
1760         GUnixFDList *g_outfdlist = NULL;
1761
1762         if (!dest || !path || !iface || !method) {
1763                 _E("wrong parameters dest(%s) path(%s) iface(%s) method(%s)", dest, path, iface, method);
1764                 return NULL;
1765         }
1766         if (in_fdlist && in_size == 0) {
1767                 _E("wrong in_fdlist is not null but in_size is 0");
1768                 return NULL;
1769         }
1770
1771         dh = _dbus_handle_get_default_connection();
1772         if (!dh) {
1773                 _E("failed to get default connection, bustype:%d", (int)dbus_handle_get_default_bus_type());
1774                 return NULL;
1775         }
1776
1777         if (signature && param)
1778                 var = _append_variant(signature, param);
1779
1780         proxy = g_dbus_proxy_new_sync(dh->conn, G_DBUS_PROXY_FLAGS_NONE, NULL, dest, path, iface, NULL, &err);
1781         if (!proxy) {
1782                 if (err) {
1783                         _E("failed to proxy_new_sync(%s)\n", err->message);
1784                         g_error_free(err);
1785                 } else {
1786                         _E("failed to proxy_new_sync\n");
1787                         if (var)
1788                                 g_variant_unref(var);
1789                 }
1790         }
1791
1792         /* append fd */
1793         if (in_fdlist) {
1794                 g_infdlist = g_unix_fd_list_new_from_array(in_fdlist, in_size);
1795                 if (!g_infdlist) {
1796                         _E("failed to g_unix_fd_list_new_from_array\n");
1797                         goto out;
1798                 }
1799                 //g_infdlist = g_unix_fd_list_new();
1800                 //if (g_unix_fd_list_append(g_infdlist, in_fdlist[0], &err) < 0) {
1801         }
1802
1803         ret = g_dbus_proxy_call_with_unix_fd_list_sync(proxy, method, var, G_DBUS_CALL_FLAGS_NONE, -1,
1804                 g_infdlist, &g_outfdlist, NULL, &err);
1805         if (!ret || err) {
1806                 if (err) {
1807                         _E("failed to g_dbus_proxy_call_with_unix_fd_list_sync:%s", err->message);
1808                         g_error_free(err);
1809                 } else {
1810                         _E("failed to g_dbus_proxy_call_with_unix_fd_list_sync:");
1811                         if (var)
1812                                 g_variant_unref(var);
1813                         if (g_infdlist)
1814                                 g_object_unref(g_infdlist);
1815                 }
1816                 goto out;
1817         }
1818
1819         /* fds to out array */
1820         if (g_outfdlist) {
1821                 *out_size = g_unix_fd_list_get_length(g_outfdlist);
1822                 if (*out_size == 0)
1823                         goto out;
1824
1825                 *out_fdlist = g_unix_fd_list_steal_fds(g_outfdlist, NULL);
1826         }
1827
1828 out:
1829         if (g_outfdlist)
1830                 g_object_unref(g_outfdlist);
1831         if (proxy)
1832                 g_object_unref(proxy);
1833
1834         return ret;
1835 }
1836
1837 GVariant *dbus_method_with_unix_fd_list_sync_with_reply_var(const char *dest, const char *path,
1838                                                                                                                         const char *iface, const char *method,
1839                                                                                                                         GVariant *param,
1840                                                                                                                         int *in_fdlist, int in_size,
1841                                                                                                                         int **out_fdlist, int *out_size)
1842 {
1843         GError *err = NULL;
1844         GVariant * ret = NULL;
1845         dbus_handle_s *dh = NULL;
1846         GDBusProxy *proxy = NULL;
1847         GUnixFDList *g_infdlist = NULL;
1848         GUnixFDList *g_outfdlist = NULL;
1849
1850         if (!dest || !path || !iface || !method) {
1851                 _E("wrong parameters dest(%s) path(%s) iface(%s) method(%s)", dest, path, iface, method);
1852                 return NULL;
1853         }
1854         if (in_fdlist && in_size == 0) {
1855                 _E("wrong in_fdlist is not null but in_size is 0");
1856                 return NULL;
1857         }
1858
1859         dh = _dbus_handle_get_default_connection();
1860         if (!dh) {
1861                 _E("failed to get default connection, bustype:%d", (int)dbus_handle_get_default_bus_type());
1862                 return NULL;
1863         }
1864
1865         proxy = g_dbus_proxy_new_sync(dh->conn, G_DBUS_PROXY_FLAGS_NONE, NULL, dest, path, iface, NULL, &err);
1866         if (!proxy) {
1867                 if (err) {
1868                         _E("failed to proxy_new_sync(%s)\n", err->message);
1869                         g_error_free(err);
1870                 } else {
1871                         _E("failed to proxy_new_sync\n");
1872                         if (param)
1873                                 g_variant_unref(param);
1874                 }
1875                 goto out;
1876         }
1877
1878         /* append fd */
1879         if (in_fdlist) {
1880                 g_infdlist = g_unix_fd_list_new_from_array(in_fdlist, in_size);
1881                 if (!g_infdlist) {
1882                         _E("failed to g_unix_fd_list_new_from_array\n");
1883                         goto out;
1884                 }
1885                 //g_infdlist = g_unix_fd_list_new();
1886                 //if (g_unix_fd_list_append(g_infdlist, in_fdlist[0], &err) < 0) {
1887         }
1888
1889         /* send message */
1890         ret = g_dbus_proxy_call_with_unix_fd_list_sync(proxy, method, param, G_DBUS_CALL_FLAGS_NONE, -1,
1891                 g_infdlist, &g_outfdlist, NULL, &err);
1892         if (!ret || err) {
1893                 if (err) {
1894                         _E("failed to g_dbus_proxy_call_with_unix_fd_list_sync:%s", err->message);
1895                         g_error_free(err);
1896                 } else {
1897                         _E("failed to g_dbus_proxy_call_with_unix_fd_list_sync:");
1898                         if (param)
1899                                 g_variant_unref(param);
1900                         if (g_infdlist)
1901                                 g_object_unref(g_infdlist);
1902                 }
1903                 goto out;
1904         }
1905
1906         /* copy fds to out array */
1907         if (g_outfdlist) {
1908                 *out_size = g_unix_fd_list_get_length(g_outfdlist);
1909                 if (*out_size == 0)
1910                         goto out;
1911                 *out_fdlist = g_unix_fd_list_steal_fds(g_outfdlist, NULL);
1912         }
1913 out:
1914         if (g_outfdlist)
1915                 g_object_unref(g_outfdlist);
1916         if (proxy)
1917                 g_object_unref(proxy);
1918         return ret;
1919 }
1920
1921 int dbus_method_sync(const char *dest, const char *path,
1922                                                 const char *iface, const char *method,
1923                                                 const char *signature, const char *param[])
1924 {
1925         int result;
1926         gboolean result_bool;
1927         GVariant *reply = NULL;
1928
1929         if (!dest || !path || !iface || !method) {
1930                 _E("wrong parameters dest(%s) path(%s) iface(%s) method(%s)", dest, path, iface, method);
1931                 return -1;
1932         }
1933
1934         reply = dbus_method_sync_with_reply(dest, path, iface, method, signature, param);
1935         if (!reply)
1936                 return -ECOMM;
1937
1938         if (g_strcmp0("(i)", g_variant_get_type_string(reply)) == 0) {
1939                 g_variant_get(reply, "(i)", &result);
1940         } else if (g_strcmp0("(b)", g_variant_get_type_string(reply)) == 0) {
1941                 g_variant_get(reply, "(b)", &result_bool);
1942                 result = (int)result_bool;
1943         } else {
1944                 result = -ENOMSG;
1945         }
1946
1947         g_variant_unref(reply);
1948
1949         return result;
1950 }
1951
1952 int dbus_method_sync_var(const char *dest, const char *path,
1953         const char *iface, const char *method, GVariant *param)
1954 {
1955         int result;
1956         gboolean result_bool;
1957         GVariant *reply = NULL;
1958
1959         if (!dest || !path || !iface || !method) {
1960                 _E("wrong parameters dest(%s) path(%s) iface(%s) method(%s)", dest, path, iface, method);
1961                 return -1;
1962         }
1963
1964         reply = dbus_method_sync_with_reply_var(dest, path, iface, method, param);
1965         if (!reply)
1966                 return -ECOMM;
1967
1968         if (g_strcmp0("(i)", g_variant_get_type_string(reply)) == 0) {
1969                 g_variant_get(reply, "(i)", &result);
1970         } else if (g_strcmp0("(b)", g_variant_get_type_string(reply)) == 0) {
1971                 g_variant_get(reply, "(b)", &result_bool);
1972                 result = (int)result_bool;
1973         } else {
1974                 result = -ENOMSG;
1975         }
1976
1977         g_variant_unref(reply);
1978
1979         return result;
1980 }
1981
1982 int dbus_method_sync_timeout(const char *dest, const char *path,
1983                                                                 const char *iface, const char *method,
1984                                                                 const char *signature, const char *param[], int timeout)
1985 {
1986         dbus_handle_s *dh = NULL;
1987         GError *err = NULL;
1988         GVariant * var = NULL;
1989         GVariant * reply = NULL;
1990         int result = 0;
1991
1992         if (!dest || !path || !iface || !method) {
1993                 _E("wrong parameters dest(%s) path(%s) iface(%s) method(%s)", dest, path, iface, method);
1994                 return -1;
1995         }
1996
1997         dh = _dbus_handle_get_default_connection();
1998         if (!dh) {
1999                 _E("failed to get default connection, bustype:%d", (int)dbus_handle_get_default_bus_type());
2000                 return -EPERM;
2001         }
2002
2003         if (signature && param)
2004                 var = _append_variant(signature, param);
2005
2006         reply = g_dbus_connection_call_sync(dh->conn,
2007                                                                                 dest, path, iface, method,
2008                                                                                 var, NULL, G_DBUS_CALL_FLAGS_NONE, timeout, NULL, &err);
2009         if (!reply || err) {
2010                 _E("failed to g_dbus_connection_call_sync:%s", err->message);
2011                 g_error_free(err);
2012                 return -1;
2013         }
2014
2015         if (g_strcmp0("(i)", g_variant_get_type_string(reply)) == 0)
2016                 g_variant_get(reply, "(i)", &result);
2017         else
2018                 result = -ENOMSG;
2019
2020         g_variant_unref(reply);
2021
2022         return result;
2023 }
2024
2025 int dbus_method_sync_pairs(const char *dest, const char *path,
2026                                                         const char *iface, const char *method,
2027                                                         int num, va_list args)
2028 {
2029         GError *err = NULL;
2030         GVariant * reply = NULL;
2031         char *key, *value;
2032         int ret = 0;
2033         GVariant *var;
2034         GVariantBuilder *builder;
2035         dbus_handle_s *dh = NULL;
2036
2037         if (!dest || !path || !iface || !method) {
2038                 _E("wrong parameters dest(%s) path(%s) iface(%s) method(%s)", dest, path, iface, method);
2039                 return -1;
2040         }
2041
2042         dh = _dbus_handle_get_default_connection();
2043         if (!dh) {
2044                 _E("failed to get default connection, bustype:%d", (int)dbus_handle_get_default_bus_type());
2045                 return -1;
2046         }
2047
2048         builder = g_variant_builder_new(G_VARIANT_TYPE("a{ss}"));
2049
2050         for (int i = 0 ; i < num ; i = i + 2) {
2051                 key = va_arg(args, char *);
2052                 value = va_arg(args, char *);
2053                 _I("key(%s), value(%s)", key, value);
2054                 g_variant_builder_add(builder, "{ss}", key, value);
2055         }
2056
2057         var = g_variant_new("(a{ss})", builder);
2058         g_variant_builder_unref(builder);
2059
2060         reply = g_dbus_connection_call_sync(dh->conn,
2061                 dest, path, iface, method,
2062                 var, NULL, G_DBUS_CALL_FLAGS_NONE, DBUS_REPLY_TIMEOUT, NULL, &err);
2063         if (!reply || err) {
2064                 _E("failed to g_dbus_connection_call_sync");
2065                 return -1;
2066         }
2067
2068         if (g_strcmp0("(i)", g_variant_get_type_string(reply)) == 0)
2069                 g_variant_get(reply, "(i)", &ret);
2070         else
2071                 ret = -ENOMSG;
2072
2073         g_variant_unref(reply);
2074
2075         return ret;
2076 }
2077
2078 int dbus_method_async_pairs(const char *dest, const char *path,
2079         const char *iface, const char *method,
2080         int num, va_list args)
2081 {
2082         char *key, *value;
2083         GVariant *var;
2084         GVariantBuilder *builder;
2085         dbus_handle_s *dh = NULL;
2086
2087         if (!dest || !path || !iface || !method) {
2088                 _E("wrong parameters dest(%s) path(%s) iface(%s) method(%s)", dest, path, iface, method);
2089                 return -1;
2090         }
2091
2092         dh = _dbus_handle_get_default_connection();
2093         if (!dh) {
2094                 _E("failed to get default connection, bustype:%d", (int)dbus_handle_get_default_bus_type());
2095                 return -1;
2096         }
2097
2098         // dict
2099         builder = g_variant_builder_new(G_VARIANT_TYPE("a{ss}"));
2100
2101         for (int i = 0 ; i < num ; i = i + 2) {
2102                 key = va_arg(args, char *);
2103                 value = va_arg(args, char *);
2104                 _I("key(%s), value(%s)", key, value);
2105                 g_variant_builder_add(builder, "{ss}", key, value);
2106         }
2107
2108         var = g_variant_new("(a{ss})", builder);
2109         g_variant_builder_unref(builder);
2110
2111         g_dbus_connection_call(dh->conn, dest, path, iface, method,
2112                 var, NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL,
2113                 NULL,
2114                 NULL);
2115
2116         return 0;
2117 }
2118
2119 int dbus_method_async(const char *dest, const char *path,
2120         const char *iface, const char *method,
2121         const char *signature, const char *param[])
2122 {
2123         GVariant * var = NULL;
2124         dbus_handle_s *dh = NULL;
2125
2126         if (!dest || !path || !iface || !method) {
2127                 _E("wrong parameters dest(%s) path(%s) iface(%s) method(%s)", dest, path, iface, method);
2128                 return -1;
2129         }
2130
2131         dh = _dbus_handle_get_default_connection();
2132         if (!dh) {
2133                 _E("failed to get default connection, bustype:%d", (int)dbus_handle_get_default_bus_type());
2134                 return -1;
2135         }
2136
2137         if (signature && param)
2138                 var = _append_variant(signature, param);
2139
2140         g_dbus_connection_call(dh->conn, dest, path, iface, method,
2141                                                         var, NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL,
2142                                                         NULL,
2143                                                         NULL);
2144
2145         return 0;
2146 }
2147
2148 int dbus_method_async_var(const char *dest, const char *path,
2149         const char *iface, const char *method, GVariant *param)
2150 {
2151         dbus_handle_s *dh = NULL;
2152
2153         if (!dest || !path || !iface || !method) {
2154                 _E("wrong parameters dest(%s) path(%s) iface(%s) method(%s)", dest, path, iface, method);
2155                 return -1;
2156         }
2157
2158         dh = _dbus_handle_get_default_connection();
2159         if (!dh) {
2160                 _E("failed to get default connection, bustype:%d", (int)dbus_handle_get_default_bus_type());
2161                 return -1;
2162         }
2163
2164         g_dbus_connection_call(dh->conn, dest, path, iface, method,
2165                 param, NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL,
2166                 NULL,
2167                 NULL);
2168
2169         return 0;
2170 }
2171
2172 /* callback should free gvariant */
2173 static void _cb_pending(GDBusConnection *conn,
2174                                                 GAsyncResult    *res,
2175                                                 gpointer         user_data)
2176 {
2177         GVariant *reply = NULL;
2178         GError *err = NULL;
2179         pending_call_data *data = (pending_call_data *)user_data;
2180
2181         reply = g_dbus_connection_call_finish(conn, res, &err);
2182         if (!reply || err) {
2183                 if (err) {
2184                         _E("no message : [%s]", err->message);
2185                         g_error_free(err);
2186                 } else {
2187                         _E("no message");
2188                 }
2189
2190                 if (data && data->func)
2191                         data->func(NULL, data->data, err);
2192                 goto out;
2193         }
2194
2195         if (data && data->func)
2196                 data->func(reply, data->data, err);
2197 out:
2198         if (data)
2199                 free(data);
2200 }
2201
2202 int dbus_method_async_with_reply(const char *dest,
2203                                                                         const char *path,
2204                                                                         const char *iface,
2205                                                                         const char *method,
2206                                                                         const char *signature,
2207                                                                         const char *param[],
2208                                                                         dbus_pending_cb cb,
2209                                                                         int timeout_msec,
2210                                                                         void *data)
2211 {
2212         dbus_handle_s *dh = NULL;
2213         pending_call_data *pdata = NULL;
2214         GVariant * var = NULL;
2215         int ret = 0;
2216
2217         if (!dest || !path || !iface || !method) {
2218                 _E("wrong parameters dest(%s) path(%s) iface(%s) method(%s)", dest, path, iface, method);
2219                 return -1;
2220         }
2221
2222         if (timeout_msec < -1) {
2223                 _E("wrong timeout %d", timeout_msec);
2224                 return -1;
2225         }
2226
2227         dh = _dbus_handle_get_default_connection();
2228         if (!dh) {
2229                 _E("failed to get default connection, bustype:%d", (int)dbus_handle_get_default_bus_type());
2230                 return -EPERM;
2231         }
2232
2233         if (signature && param)
2234                 var = _append_variant(signature, param);
2235
2236         if (cb) {
2237                 pdata = (pending_call_data*)malloc(sizeof(pending_call_data));
2238                 if (!pdata) {
2239                         ret = -ENOMEM;
2240                         goto err;
2241                 }
2242
2243                 pdata->func = cb;
2244                 pdata->data = data;
2245         }
2246         g_dbus_connection_call(dh->conn, dest, path, iface, method,
2247                                                         var, NULL, G_DBUS_CALL_FLAGS_NONE, timeout_msec, NULL,
2248                                                         (GAsyncReadyCallback)_cb_pending,
2249                                                         pdata);
2250
2251         return ret;
2252 err:
2253         if (var)
2254                 g_variant_unref(var);
2255         return ret;
2256 }
2257
2258 int dbus_method_async_with_reply_var(const char *dest,
2259                                                                                 const char *path,
2260                                                                                 const char *iface,
2261                                                                                 const char *method,
2262                                                                                 GVariant *param,
2263                                                                                 dbus_pending_cb cb,
2264                                                                                 int timeout_msec,
2265                                                                                 void *data)
2266 {
2267         dbus_handle_s *dh = NULL;
2268         pending_call_data *pdata = NULL;
2269         int ret = 0;
2270
2271         if (!dest || !path || !iface || !method) {
2272                 _E("wrong parameters dest(%s) path(%s) iface(%s) method(%s)", dest, path, iface, method);
2273                 return -1;
2274         }
2275
2276         if (timeout_msec < -1) {
2277                 _E("wrong timeout %d", timeout_msec);
2278                 return -1;
2279         }
2280
2281         dh = _dbus_handle_get_default_connection();
2282         if (!dh) {
2283                 _E("failed to get default connection, bustype:%d", (int)dbus_handle_get_default_bus_type());
2284                 return -EPERM;
2285         }
2286
2287         if (cb) {
2288                 pdata = (pending_call_data*)malloc(sizeof(pending_call_data));
2289                 if (!pdata) {
2290                         ret = -ENOMEM;
2291                         goto err;
2292                 }
2293
2294                 pdata->func = cb;
2295                 pdata->data = data;
2296         }
2297         g_dbus_connection_call(dh->conn, dest, path, iface, method,
2298                 param, NULL, G_DBUS_CALL_FLAGS_NONE, timeout_msec, NULL,
2299                 (GAsyncReadyCallback)_cb_pending,
2300                 pdata);
2301
2302         return ret;
2303 err:
2304         if (param)
2305                 g_variant_unref(param);
2306         return ret;
2307 }
2308
2309 int dbus_connection_get_sender_pid(GDBusConnection *conn, const char * sender)
2310 {
2311         GError *err = NULL;
2312         GVariant *vret = NULL;
2313         pid_t pid = 0;
2314
2315         if (!conn) {
2316                 _E("connection is null");
2317                 return -1;
2318         }
2319         if (!sender) {
2320                 _E("sender is null");
2321                 return -1;
2322         }
2323
2324         vret = g_dbus_connection_call_sync(conn,
2325                 "org.freedesktop.DBus", "/", "org.freedesktop.DBus", "GetConnectionUnixProcessID",
2326                 g_variant_new("(s)", sender),
2327                 NULL,
2328                 G_DBUS_CALL_FLAGS_NONE,
2329                 DBUS_REPLY_TIMEOUT,
2330                 NULL,
2331                 &err);
2332         if (!vret || err) {
2333                 _E("failed to g_dbus_connection_call_sync:%s", err->message);
2334                 g_error_free(err);
2335                 return -1;
2336         }
2337
2338         g_variant_get(vret, "(u)", &pid);
2339         g_variant_unref(vret);
2340
2341         return pid;
2342 }
2343
2344 int dbus_handle_get_sender_pid(dbus_handle_h handle, const char * sender)
2345 {
2346         dcl_dbus_handle();
2347
2348         if (!dh) {
2349                 dh = _dbus_handle_get_default_connection();
2350                 if (!dh) {
2351                         _E("failed to get default connection, bustype:%d", (int)dbus_handle_get_default_bus_type());
2352                         return -1;
2353                 }
2354         }
2355         if (!dh->conn) {
2356                 _E("wrong dbus handle. connection is null");
2357                 assert(0);
2358                 return -1;
2359         }
2360
2361         return dbus_connection_get_sender_pid(dh->conn, sender);
2362 }
2363
2364 int dbus_handle_get_sender_credentials(dbus_handle_h handle, const char *name, GDBusCredentials *creds)
2365 {
2366         dcl_dbus_handle();
2367         GVariant *vret = NULL;
2368         GError *err = NULL;
2369         GVariantIter *iter = NULL;
2370         char * item;
2371         GVariant *sub;
2372
2373         if (!dh) {
2374                 dh = _dbus_handle_get_default_connection();
2375                 if (!dh) {
2376                         _E("failed to get default connection, bustype:%d", (int)dbus_handle_get_default_bus_type());
2377                         return -1;
2378                 }
2379         }
2380         vret = g_dbus_connection_call_sync(dh->conn, DBUS_BUS_NAME, DBUS_OBJECT_PATH, DBUS_INTERFACE_NAME,
2381                 "GetConnectionCredentials", g_variant_new("(s)", name), NULL, G_DBUS_CALL_FLAGS_NONE, DBUS_REPLY_TIMEOUT, NULL, &err);
2382         if (!vret || err) {
2383                 _E("failed to g_dbus_connection_call_sync:%s", err->message);
2384                 return -1;
2385         }
2386
2387         g_variant_get(vret, "(a{sv})", &iter);
2388
2389         while (g_variant_iter_loop(iter, "{sv}", &item, &sub)) {
2390                 if (!g_strcmp0(item, "UnixUserID")) {
2391                         g_variant_get(sub, "u", &creds->uid);
2392                         _D("UnixUserID %u", creds->uid);
2393                 } else if (!g_strcmp0(item, "ProcessID")) {
2394                         g_variant_get(sub, "u", &creds->pid);
2395                         _D("ProcessID %u", creds->pid);
2396                 } else if (!g_strcmp0(item, "LinuxSecurityLabel")) {
2397                         g_variant_get(sub, "^ay", &creds->sec_label);
2398                         _D("%s", creds->sec_label);
2399                 }
2400         }
2401
2402         if (iter)
2403                 g_variant_iter_free(iter);
2404         if (vret)
2405                 g_variant_unref(vret);
2406
2407         return 0;
2408 }
2409
2410 void _destroy_notify_watch_name(gpointer data)
2411 {
2412         if (data)
2413                 free(data);
2414 }
2415
2416 int dbus_handle_watch_name(const char *name,
2417                                                         GBusNameAppearedCallback  name_appeared_handler,
2418                                                         GBusNameVanishedCallback  name_vanished_handler,
2419                                                         void *user_data)
2420 {
2421         guint id = 0;
2422
2423         if (!name) {
2424                 _E("wrong name name %s", name);
2425                 return -1;
2426         }
2427         if (!name_appeared_handler && !name_vanished_handler) {
2428                 _E("both function pointers are null");
2429                 return -1;
2430         }
2431
2432         id = g_bus_watch_name(dbus_handle_get_default_bus_type(), name, G_BUS_NAME_WATCHER_FLAGS_NONE, name_appeared_handler, name_vanished_handler, user_data, _destroy_notify_watch_name);
2433         if (!id) {
2434                 _E("failed to g_bus_watch_name");
2435                 return -1;
2436         }
2437
2438         return id;
2439 }
2440
2441 void dbus_handle_unwatch_name(guint id)
2442 {
2443         if (id == 0) {
2444                 _E("wrong id %d", id);
2445                 return;
2446         }
2447         g_bus_unwatch_name(id);
2448 }
2449
2450 int _get_cmdline_name(pid_t pid, char *cmdline, size_t cmdline_size)
2451 {
2452         int fd, ret;
2453         char buf[PATH_MAX + 1];
2454         char *filename;
2455
2456         snprintf(buf, sizeof(buf), "/proc/%d/cmdline", pid);
2457         fd = open(buf, O_RDONLY);
2458         if (fd < 0) {
2459                 errno = ESRCH;
2460                 return -1;
2461         }
2462
2463         ret = read(fd, buf, PATH_MAX);
2464         close(fd);
2465         if (ret < 0)
2466                 return -1;
2467
2468         buf[PATH_MAX] = '\0';
2469
2470         filename = strrchr(buf, '/');
2471         if (filename == NULL)
2472                 filename = buf;
2473         else
2474                 filename = filename + 1;
2475
2476         if (cmdline_size < strlen(filename) + 1) {
2477                 errno = EOVERFLOW;
2478                 return -1;
2479         }
2480
2481         strncpy(cmdline, filename, cmdline_size - 1);
2482         cmdline[cmdline_size - 1] = '\0';
2483         return 0;
2484 }
2485
2486 // g_strfreev(strv)
2487 char **dbus_handle_get_owner_list(dbus_handle_h handle, const char *bus_name)
2488 {
2489         dcl_dbus_handle();
2490         GError *err = NULL;
2491         GVariant *vret = NULL;
2492         GVariantIter *iter = NULL;
2493         gchar **strv = NULL;
2494         gchar *str = NULL;
2495         int i = 0;
2496
2497         if (!bus_name) {
2498                 _E("wrong parameter bus_name(%s)", bus_name);
2499                 return NULL;
2500         }
2501
2502         if (!dh) {
2503                 dh = _dbus_handle_get_default_connection();
2504                 if (!dh) {
2505                         _E("failed to get default connection, bustype:%d", (int)dbus_handle_get_default_bus_type());
2506                         return NULL;
2507                 }
2508         }
2509
2510         vret = g_dbus_connection_call_sync(dh->conn,
2511                 "org.freedesktop.DBus", "/", "org.freedesktop.DBus", "ListQueuedOwners",
2512                 g_variant_new("(s)", bus_name),
2513                 NULL,
2514                 G_DBUS_CALL_FLAGS_NONE,
2515                 DBUS_REPLY_TIMEOUT,
2516                 NULL,
2517                 &err);
2518         if (!vret || err) {
2519                 _E("failed to g_dbus_connection_call_sync:%s", err->message);
2520                 g_error_free(err);
2521                 return NULL;
2522         }
2523
2524         g_variant_get(vret, "(as)", &iter);
2525         strv = g_new(gchar *, g_variant_iter_n_children(iter) + 1);
2526
2527         i = 0;
2528         while (g_variant_iter_loop(iter, "s", &str))
2529                 strv[i++] = g_strdup(str);
2530         strv[i] = NULL;
2531
2532         g_variant_iter_free(iter);
2533         g_variant_unref(vret);
2534
2535         return strv;
2536 }
2537
2538 void dbush_handle_check_owner_name(dbus_handle_h handle, const char *owner_name)
2539 {
2540         dcl_dbus_handle();
2541         char exe_name[PATH_MAX];
2542         int pid;
2543         char **strv = NULL;
2544         int i;
2545
2546         if (!dh) {
2547                 dh = _dbus_handle_get_default_connection();
2548                 if (!dh) {
2549                         _E("failed to get default connection, bustype:%d", (int)dbus_handle_get_default_bus_type());
2550                         return ;
2551                 }
2552         }
2553
2554         strv = dbus_handle_get_owner_list(dh, owner_name);
2555         if (!strv) {
2556                 _E("failed to get owner list of %s", owner_name);
2557                 return ;
2558         }
2559
2560         for (i = 0; strv[i] != NULL; ++i) {
2561                 pid = dbus_handle_get_sender_pid(dh, strv[i]);
2562                 if (_get_cmdline_name(pid, exe_name, PATH_MAX) != 0)
2563                         break;
2564                 _I("%s(%d)", exe_name, pid);
2565         }
2566
2567         g_strfreev(strv);
2568 }
2569
2570 dbus_handle_h dbus_handle_init(GBusType type, const char* bus_name)
2571 {
2572         dbus_handle_h handle = NULL;
2573         int i, ret = 0;
2574
2575         if (!bus_name) {
2576                 _E("Wrong bus name, %s", bus_name);
2577                 return NULL;
2578         }
2579
2580         // todo: do we need retry ? - booting time
2581         for (i = 0 ; i < 3; ++i) {
2582                 handle = dbus_handle_get_connection(type, FALSE);
2583                 if (handle)
2584                         break;
2585                 usleep(5000);
2586         }
2587         ret = dbus_handle_request_bus_name(handle, bus_name);
2588         if (ret <= 0)
2589                 goto out;
2590
2591         dbush_handle_check_owner_name(NULL, bus_name);
2592
2593         return handle;
2594
2595 out:
2596         return NULL;
2597 }
2598