Several changes in the contacts layout tab and accross the App.
[profile/ivi/lemolo.git] / dialer / ofono.c
1 #ifdef HAVE_CONFIG_H
2 #include "config.h"
3 #endif
4 #include <Elementary.h>
5
6 #include "ofono.h"
7 #include "log.h"
8
9 #include <time.h>
10
11 typedef struct _OFono_Modem OFono_Modem;
12 typedef struct _OFono_Bus_Object OFono_Bus_Object;
13
14 static const char bus_name[] = "org.ofono";
15
16 static const char *known_modem_types[] = {"hfp", "sap", "hardware", NULL};
17
18 static E_DBus_Connection *bus_conn = NULL;
19 static char *bus_id = NULL;
20 static Eina_Hash *modems = NULL;
21 static OFono_Modem *modem_selected = NULL;
22 static const char *modem_path_wanted = NULL;
23 static unsigned int modem_api_mask = 0;
24 static Eina_List *modem_types = NULL;
25 static E_DBus_Signal_Handler *sig_modem_added = NULL;
26 static E_DBus_Signal_Handler *sig_modem_removed = NULL;
27 static E_DBus_Signal_Handler *sig_modem_prop_changed = NULL;
28 static DBusPendingCall *pc_get_modems = NULL;
29
30 static void _ofono_call_volume_properties_get(OFono_Modem *m);
31
32 struct _OFono_Callback_List_Modem_Node
33 {
34         EINA_INLIST;
35         void (*cb)(void *data);
36         const void *cb_data;
37 };
38
39 struct _OFono_Callback_List_Call_Node
40 {
41         EINA_INLIST;
42         void (*cb)(void *data, OFono_Call *call);
43         const void *cb_data;
44 };
45
46 struct _OFono_Callback_List_Call_Disconnected_Node
47 {
48         EINA_INLIST;
49         void (*cb)(void *data, OFono_Call *call, const char *reason);
50         const void *cb_data;
51 };
52
53 static Eina_Inlist *cbs_modem_changed = NULL;
54 static Eina_Inlist *cbs_modem_connected = NULL;
55 static Eina_Inlist *cbs_modem_disconnected = NULL;
56
57 static Eina_Inlist *cbs_call_changed = NULL;
58 static Eina_Inlist *cbs_call_added = NULL;
59 static Eina_Inlist *cbs_call_disconnected = NULL;
60 static Eina_Inlist *cbs_call_removed = NULL;
61
62 #define OFONO_SERVICE                   "org.ofono"
63
64 #define OFONO_PREFIX                    OFONO_SERVICE "."
65 #define OFONO_MODEM_IFACE               "Modem"
66 #define OFONO_MANAGER_IFACE             "Manager"
67 #define OFONO_SIM_IFACE                 "SimManager"
68 #define OFONO_NETREG_IFACE              "NetworkRegistration"
69 #define OFONO_VOICE_IFACE               "VoiceCallManager"
70 #define OFONO_MSG_IFACE                 "MessageManager"
71 #define OFONO_MSG_WAITING_IFACE         "MessageWaiting"
72 #define OFONO_SMART_MSG_IFACE           "SmartMessaging"
73 #define OFONO_STK_IFACE                 "SimToolkit"
74
75 #define OFONO_CALL_FW_IFACE             "CallForwarding"
76 #define OFONO_CALL_VOL_IFACE            "CallVolume"
77 #define OFONO_CALL_METER_IFACE          "CallMeter"
78 #define OFONO_CALL_SET_IFACE            "CallSettings"
79 #define OFONO_CALL_BAR_IFACE            "CallBarring"
80 #define OFONO_SUPPL_SERV_IFACE          "SupplementaryServices"
81 #define OFONO_TXT_TEL_IFACE             "TextTelephony"
82 #define OFONO_CELL_BROAD_IFACE          "CellBroadcast"
83 #define OFONO_CONNMAN_IFACE             "ConnectionManager"
84 #define OFONO_PUSH_NOTIF_IFACE          "PushNotification"
85 #define OFONO_PHONEBOOK_IFACE           "Phonebook"
86 #define OFONO_ASN_IFACE                 "AssistedSatelliteNavigation"
87
88 static const struct API_Interface_Map {
89         unsigned int bit;
90         const char *name;
91         size_t namelen;
92 } api_iface_map[] = {
93 #define MAP(bit, name) {bit, name, sizeof(name) - 1}
94         MAP(OFONO_API_SIM, OFONO_SIM_IFACE),
95         MAP(OFONO_API_NETREG, OFONO_NETREG_IFACE),
96         MAP(OFONO_API_VOICE, OFONO_VOICE_IFACE),
97         MAP(OFONO_API_MSG, OFONO_MSG_IFACE),
98         MAP(OFONO_API_MSG_WAITING, OFONO_MSG_WAITING_IFACE),
99         MAP(OFONO_API_SMART_MSG, OFONO_SMART_MSG_IFACE),
100         MAP(OFONO_API_STK, OFONO_STK_IFACE),
101         MAP(OFONO_API_CALL_FW, OFONO_CALL_FW_IFACE),
102         MAP(OFONO_API_CALL_VOL, OFONO_CALL_VOL_IFACE),
103         MAP(OFONO_API_CALL_METER, OFONO_CALL_METER_IFACE),
104         MAP(OFONO_API_CALL_SET, OFONO_CALL_SET_IFACE),
105         MAP(OFONO_API_CALL_BAR, OFONO_CALL_BAR_IFACE),
106         MAP(OFONO_API_SUPPL_SERV, OFONO_SUPPL_SERV_IFACE),
107         MAP(OFONO_API_TXT_TEL, OFONO_TXT_TEL_IFACE),
108         MAP(OFONO_API_CELL_BROAD, OFONO_CELL_BROAD_IFACE),
109         MAP(OFONO_API_CONNMAN, OFONO_CONNMAN_IFACE),
110         MAP(OFONO_API_PUSH_NOTIF, OFONO_PUSH_NOTIF_IFACE),
111         MAP(OFONO_API_PHONEBOOK, OFONO_PHONEBOOK_IFACE),
112         MAP(OFONO_API_ASN, OFONO_ASN_IFACE),
113 #undef MAP
114         {0, NULL, 0}
115 };
116
117 static Eina_Bool _dbus_bool_get(DBusMessageIter *itr)
118 {
119         dbus_bool_t val;
120         dbus_message_iter_get_basic(itr, &val);
121         return val;
122 }
123
124 static const struct Error_Map {
125         OFono_Error id;
126         const char *name;
127         size_t namelen;
128 } error_map[] = {
129 #define MAP(id, name) {id, name, sizeof(name) - 1}
130         MAP(OFONO_ERROR_FAILED, "Failed"),
131         MAP(OFONO_ERROR_DOES_NOT_EXIST, "DoesNotExist"),
132         MAP(OFONO_ERROR_IN_PROGRESS, "InProgress"),
133         MAP(OFONO_ERROR_IN_USE, "InUse"),
134         MAP(OFONO_ERROR_INVALID_ARGS, "InvalidArguments"),
135         MAP(OFONO_ERROR_INVALID_FORMAT, "InvalidFormat"),
136         MAP(OFONO_ERROR_ACCESS_DENIED, "AccessDenied"),
137         MAP(OFONO_ERROR_ATTACH_IN_PROGRESS, "AttachInProgress"),
138         MAP(OFONO_ERROR_INCORRECT_PASSWORD, "IncorrectPassword"),
139         MAP(OFONO_ERROR_NOT_ACTIVE, "NotActive"),
140         MAP(OFONO_ERROR_NOT_ALLOWED, "NotAllowed"),
141         MAP(OFONO_ERROR_NOT_ATTACHED, "NotAttached"),
142         MAP(OFONO_ERROR_NOT_AVAILABLE, "NotAvailable"),
143         MAP(OFONO_ERROR_NOT_FOUND, "NotFound"),
144         MAP(OFONO_ERROR_NOT_IMPLEMENTED, "NotImplemented"),
145         MAP(OFONO_ERROR_NOT_RECOGNIZED, "NotRecognized"),
146         MAP(OFONO_ERROR_NOT_REGISTERED, "NotRegistered"),
147         MAP(OFONO_ERROR_NOT_SUPPORTED, "NotSupported"),
148         MAP(OFONO_ERROR_SIM_NOT_READY, "SimNotReady"),
149         MAP(OFONO_ERROR_STK, "SimToolkit"),
150         MAP(OFONO_ERROR_TIMEDOUT, "Timedout"),
151 #undef MAP
152         {0, NULL, 0}
153 };
154
155 static OFono_Error _ofono_error_parse(const char *name)
156 {
157         size_t namelen, prefixlen = sizeof(OFONO_PREFIX) - 1;
158         const struct Error_Map *itr;
159
160         /* whenever interfaces are not there due modem being offline */
161         if (strcmp(name, "org.freedesktop.DBus.Error.UnknownMethod") == 0)
162                 return OFONO_ERROR_OFFLINE;
163
164         if (strncmp(name, OFONO_PREFIX, prefixlen) != 0)
165                 return OFONO_ERROR_FAILED;
166
167         name += prefixlen;
168         namelen = strlen(name);
169         for (itr = error_map; itr->name != NULL; itr++)
170                 if ((itr->namelen == namelen) &&
171                         (memcmp(name, itr->name, namelen) == 0))
172                         return itr->id;
173
174         return OFONO_ERROR_FAILED;
175 }
176
177 typedef struct _OFono_Simple_Cb_Context
178 {
179         OFono_Simple_Cb cb;
180         const void *data;
181 } OFono_Simple_Cb_Context;
182
183 static void _ofono_simple_reply(void *data, DBusMessage *msg __UNUSED__,
184                                 DBusError *err)
185 {
186         OFono_Simple_Cb_Context *ctx = data;
187         OFono_Error e = OFONO_ERROR_NONE;
188
189         if (dbus_error_is_set(err)) {
190                 DBG("%s: %s", err->name, err->message);
191                 e = _ofono_error_parse(err->name);
192         }
193
194         if (ctx) {
195                 ctx->cb((void *)ctx->data, e);
196                 free(ctx);
197         }
198 }
199
200 typedef struct _OFono_String_Cb_Context
201 {
202         OFono_String_Cb cb;
203         const void *data;
204         const char *name;
205         char *(*convert)(DBusMessage *msg);
206 } OFono_String_Cb_Context;
207
208 static void _ofono_string_reply(void *data, DBusMessage *msg, DBusError *err)
209 {
210         OFono_String_Cb_Context *ctx = data;
211         OFono_Error e = OFONO_ERROR_NONE;
212         char *str = NULL;
213
214         if (dbus_error_is_set(err)) {
215                 DBG("%s: %s", err->name, err->message);
216                 e = _ofono_error_parse(err->name);
217         } else {
218                 str = ctx->convert(msg);
219                 if (!str)
220                         e = OFONO_ERROR_NOT_SUPPORTED;
221         }
222
223         if (ctx->cb)
224                 ctx->cb((void *)ctx->data, e, str);
225         else
226                 DBG("%s %s", ctx->name, str);
227
228         free(str);
229         free(ctx);
230 }
231
232 struct _OFono_Pending
233 {
234         EINA_INLIST;
235         DBusPendingCall *pending;
236         E_DBus_Method_Return_Cb cb;
237         void *data;
238         void *owner;
239 };
240
241 struct _OFono_Bus_Object
242 {
243         const char *path;
244         Eina_Inlist *dbus_pending; /* of OFono_Pending */
245         Eina_List *dbus_signals; /* of E_DBus_Signal_Handler */
246 };
247
248 static void _notify_ofono_callbacks_call_list(Eina_Inlist *list,
249                                                 OFono_Call *call)
250 {
251         OFono_Callback_List_Call_Node *node;
252
253         EINA_INLIST_FOREACH(list, node)
254                 node->cb((void *) node->cb_data, call);
255 }
256
257 static void _notify_ofono_callbacks_call_disconnected_list(Eina_Inlist *list,
258                                                                 OFono_Call *call,
259                                                                 const char *reason)
260 {
261         OFono_Callback_List_Call_Disconnected_Node *node;
262
263         EINA_INLIST_FOREACH(list, node)
264                 node->cb((void *) node->cb_data, call, reason);
265 }
266
267 static void _bus_object_free(OFono_Bus_Object *o)
268 {
269         E_DBus_Signal_Handler *sh;
270
271         eina_stringshare_del(o->path);
272
273         while (o->dbus_pending) {
274                 ofono_pending_cancel(
275                         EINA_INLIST_CONTAINER_GET(o->dbus_pending,
276                                                         OFono_Pending));
277         }
278
279         EINA_LIST_FREE(o->dbus_signals, sh)
280                 e_dbus_signal_handler_del(bus_conn, sh);
281
282         free(o);
283 }
284
285 static void _bus_object_message_send_reply(void *data, DBusMessage *reply,
286                                                 DBusError *err)
287 {
288         OFono_Pending *p = data;
289         OFono_Bus_Object *o = p->owner;
290
291         if (p->cb)
292                 p->cb(p->data, reply, err);
293
294         o->dbus_pending = eina_inlist_remove(o->dbus_pending,
295                                                 EINA_INLIST_GET(p));
296         free(p);
297 }
298
299 static OFono_Pending *_bus_object_message_send(OFono_Bus_Object *o,
300                                                 DBusMessage *msg,
301                                                 E_DBus_Method_Return_Cb cb,
302                                                 void *data)
303 {
304         OFono_Pending *p;
305         EINA_SAFETY_ON_NULL_GOTO(o, error);
306         EINA_SAFETY_ON_NULL_GOTO(msg, error);
307
308         p = calloc(1, sizeof(OFono_Pending));
309         EINA_SAFETY_ON_NULL_GOTO(p, error);
310
311         p->owner = o;
312         p->cb = cb;
313         p->data = data;
314
315         p->pending = e_dbus_message_send(
316                 bus_conn, msg, _bus_object_message_send_reply, -1, p);
317         EINA_SAFETY_ON_NULL_GOTO(p->pending, error_send);
318
319         o->dbus_pending = eina_inlist_append(o->dbus_pending,
320                                                 EINA_INLIST_GET(p));
321         dbus_message_unref(msg);
322         return p;
323
324 error_send:
325         free(p);
326 error:
327         if (cb) {
328                 DBusError err;
329                 dbus_error_init(&err);
330                 dbus_set_error(&err, "Failed", "call setup failed.");
331                 cb(data, NULL, &err);
332         }
333         dbus_message_unref(msg);
334         return NULL;
335 }
336
337 void ofono_pending_cancel(OFono_Pending *p)
338 {
339         OFono_Bus_Object *o;
340
341         EINA_SAFETY_ON_NULL_RETURN(p);
342
343         o = p->owner;
344         o->dbus_pending = eina_inlist_remove(o->dbus_pending,
345                                                 EINA_INLIST_GET(p));
346
347         if (p->cb) {
348                 DBusError err;
349
350                 dbus_error_init(&err);
351                 dbus_set_error(&err, "Canceled",
352                                 "Pending method call was canceled.");
353                 p->cb(p->data, NULL, &err);
354         }
355         dbus_pending_call_cancel(p->pending);
356         free(p);
357 }
358
359 static void _bus_object_signal_listen(OFono_Bus_Object *o, const char *iface,
360                                         const char *name, E_DBus_Signal_Cb cb,
361                                         void *data)
362 {
363         E_DBus_Signal_Handler *sh = e_dbus_signal_handler_add(
364                 bus_conn, bus_id, o->path, iface, name, cb, data);
365         EINA_SAFETY_ON_NULL_RETURN(sh);
366
367         o->dbus_signals = eina_list_append(o->dbus_signals, sh);
368 }
369
370 struct _OFono_Call
371 {
372         OFono_Bus_Object base;
373         const char *line_id;
374         const char *incoming_line;
375         const char *name;
376         double start_time;
377         time_t full_start_time;
378         OFono_Call_State state;
379         Eina_Bool multiparty : 1;
380         Eina_Bool emergency : 1;
381 };
382
383 struct _OFono_Modem
384 {
385         OFono_Bus_Object base;
386         const char *name;
387         const char *serial;
388         Eina_Hash *calls;
389         unsigned int interfaces;
390         unsigned char strength;
391         unsigned char data_strength;
392         unsigned char speaker_volume;
393         unsigned char microphone_volume;
394         Eina_Bool ignored : 1;
395         Eina_Bool powered : 1;
396         Eina_Bool online : 1;
397         Eina_Bool roaming : 1;
398         Eina_Bool muted : 1;
399 };
400
401 static OFono_Call *_call_new(const char *path)
402 {
403         OFono_Call *c = calloc(1, sizeof(OFono_Call));
404         EINA_SAFETY_ON_NULL_RETURN_VAL(c, NULL);
405
406         c->base.path = eina_stringshare_add(path);
407         EINA_SAFETY_ON_NULL_GOTO(c->base.path, error_path);
408
409         c->start_time = -1.0;
410
411         return c;
412
413 error_path:
414         free(c);
415         return NULL;
416 }
417
418 static void _call_free(OFono_Call *c)
419 {
420         DBG("c=%p %s", c, c->base.path);
421
422         _notify_ofono_callbacks_call_list(cbs_call_removed, c);
423
424         eina_stringshare_del(c->line_id);
425         eina_stringshare_del(c->incoming_line);
426         eina_stringshare_del(c->name);
427
428         _bus_object_free(&c->base);
429 }
430
431 static OFono_Call_State _call_state_parse(const char *str)
432 {
433         if (strcmp(str, "active") == 0)
434                 return OFONO_CALL_STATE_ACTIVE;
435         else if (strcmp(str, "held") == 0)
436                 return OFONO_CALL_STATE_HELD;
437         else if (strcmp(str, "dialing") == 0)
438                 return OFONO_CALL_STATE_DIALING;
439         else if (strcmp(str, "alerting") == 0)
440                 return OFONO_CALL_STATE_ALERTING;
441         else if (strcmp(str, "incoming") == 0)
442                 return OFONO_CALL_STATE_INCOMING;
443         else if (strcmp(str, "waiting") == 0)
444                 return OFONO_CALL_STATE_WAITING;
445         else if (strcmp(str, "disconnected") == 0)
446                 return OFONO_CALL_STATE_DISCONNECTED;
447
448         ERR("unknown call state: %s", str);
449         return OFONO_CALL_STATE_DISCONNECTED;
450 }
451
452 static time_t _ofono_time_parse(const char *str)
453 {
454         const char *end;
455         struct tm tm;
456         time_t zonediff = 0;
457
458         memset(&tm, 0, sizeof(tm));
459
460         /* strptime() does not use %z, we must use it */
461         end = strptime(str, "%Y-%m-%dT%H:%M:%S", &tm);
462         if (end) {
463                 int direction, hour, minute, info = atoi(end);
464                 if (info > 0)
465                         direction = 1;
466                 else {
467                         direction = -1;
468                         info = -info;
469                 }
470                 hour = info / 100;
471                 minute = info % 100;
472                 zonediff = direction * (hour * 3600 + minute * 60);
473         }
474
475         return mktime(&tm) - zonediff - timezone;
476 }
477
478 static void _call_property_update(OFono_Call *c, const char *key,
479                                         DBusMessageIter *value)
480 {
481         if (strcmp(key, "LineIdentification") == 0) {
482                 const char *str;
483                 dbus_message_iter_get_basic(value, &str);
484                 DBG("%s LineIdentification %s", c->base.path, str);
485                 eina_stringshare_replace(&c->line_id, str);
486         } else if (strcmp(key, "IncomingLine") == 0) {
487                 const char *str;
488                 dbus_message_iter_get_basic(value, &str);
489                 DBG("%s IncomingLine %s", c->base.path, str);
490                 eina_stringshare_replace(&c->incoming_line, str);
491         } else if (strcmp(key, "State") == 0) {
492                 const char *str;
493                 OFono_Call_State state;
494                 dbus_message_iter_get_basic(value, &str);
495                 state = _call_state_parse(str);
496                 DBG("%s State %s (%d)", c->base.path, str, state);
497                 c->state = state;
498                 if (state == OFONO_CALL_STATE_ACTIVE) {
499                         if (c->start_time < 0.0)
500                                 c->start_time = ecore_loop_time_get();
501                         if (c->full_start_time == 0)
502                                 c->full_start_time = time(NULL);
503                 }
504         } else if (strcmp(key, "Name") == 0) {
505                 const char *str;
506                 dbus_message_iter_get_basic(value, &str);
507                 DBG("%s Name %s", c->base.path, str);
508                 eina_stringshare_replace(&c->name, str);
509         } else if (strcmp(key, "Multiparty") == 0) {
510                 dbus_bool_t v;
511                 dbus_message_iter_get_basic(value, &v);
512                 DBG("%s Multiparty %d", c->base.path, v);
513                 c->multiparty = v;
514         } else if (strcmp(key, "Emergency") == 0) {
515                 dbus_bool_t v;
516                 dbus_message_iter_get_basic(value, &v);
517                 DBG("%s Emergency %d", c->base.path, v);
518                 c->emergency = v;
519         } else if (strcmp(key, "StartTime") == 0) {
520                 const char *ts = NULL;
521                 time_t st, ut;
522                 double lt;
523                 dbus_message_iter_get_basic(value, &ts);
524
525                 st = _ofono_time_parse(ts);
526                 ut = time(NULL);
527                 lt = ecore_loop_time_get();
528                 c->start_time = st - ut + lt;
529                 c->full_start_time = st;
530                 DBG("%s StartTime %f (%s)", c->base.path, c->start_time, ts);
531         } else
532                 DBG("%s %s (unused property)", c->base.path, key);
533 }
534
535 static void _call_property_changed(void *data, DBusMessage *msg)
536 {
537         OFono_Call *c = data;
538         DBusMessageIter iter, value;
539         const char *key;
540
541         if (!msg || !dbus_message_iter_init(msg, &iter)) {
542                 ERR("Could not handle message %p", msg);
543                 return;
544         }
545
546         DBG("path=%s", c->base.path);
547
548         dbus_message_iter_get_basic(&iter, &key);
549         dbus_message_iter_next(&iter);
550         dbus_message_iter_recurse(&iter, &value);
551         _call_property_update(c, key, &value);
552
553         _notify_ofono_callbacks_call_list(cbs_call_changed, c);
554 }
555
556 static void _call_disconnect_reason(void *data, DBusMessage *msg)
557 {
558         OFono_Call *c = data;
559         DBusError err;
560         const char *reason;
561
562         if (!msg) {
563                 ERR("No message");
564                 return;
565         }
566
567         DBG("path=%s", c->base.path);
568
569         dbus_error_init(&err);
570         if (!dbus_message_get_args(msg, &err, DBUS_TYPE_STRING, &reason,
571                                         DBUS_TYPE_INVALID)) {
572                 ERR("Could not get DisconnectReason arguments: %s: %s",
573                         err.name, err.message);
574                 dbus_error_free(&err);
575                 return;
576         }
577
578         _notify_ofono_callbacks_call_disconnected_list(cbs_call_disconnected,
579                                                         c, reason);
580 }
581
582 static void _call_add(OFono_Modem *m, const char *path, DBusMessageIter *prop)
583 {
584         OFono_Call *c;
585
586         DBG("path=%s", path);
587
588         c = eina_hash_find(m->calls, path);
589         if (c) {
590                 DBG("Call already exists %p (%s)", c, path);
591                 goto update_properties;
592         }
593
594         c = _call_new(path);
595         EINA_SAFETY_ON_NULL_RETURN(c);
596         eina_hash_add(m->calls, c->base.path, c);
597
598         _bus_object_signal_listen(&c->base,
599                                         OFONO_PREFIX "VoiceCall",
600                                         "DisconnectReason",
601                                         _call_disconnect_reason, c);
602         _bus_object_signal_listen(&c->base,
603                                         OFONO_PREFIX "VoiceCall",
604                                         "PropertyChanged",
605                                         _call_property_changed, c);
606
607         _notify_ofono_callbacks_call_list(cbs_call_added, c);
608
609 update_properties:
610         if (!prop)
611                 return;
612         for (; dbus_message_iter_get_arg_type(prop) == DBUS_TYPE_DICT_ENTRY;
613                         dbus_message_iter_next(prop)) {
614                 DBusMessageIter entry, value;
615                 const char *key;
616
617                 dbus_message_iter_recurse(prop, &entry);
618                 dbus_message_iter_get_basic(&entry, &key);
619
620                 dbus_message_iter_next(&entry);
621                 dbus_message_iter_recurse(&entry, &value);
622
623                 _call_property_update(c, key, &value);
624         }
625
626         _notify_ofono_callbacks_call_list(cbs_call_changed, c);
627 }
628
629 static void _call_remove(OFono_Modem *m, const char *path)
630 {
631         DBG("path=%s", path);
632         eina_hash_del_by_key(m->calls, path);
633 }
634
635 static void _call_added(void *data, DBusMessage *msg)
636 {
637         OFono_Modem *m = data;
638         DBusMessageIter iter, properties;
639         const char *path;
640
641         if (!msg || !dbus_message_iter_init(msg, &iter)) {
642                 ERR("Could not handle message %p", msg);
643                 return;
644         }
645
646         dbus_message_iter_get_basic(&iter, &path);
647
648         dbus_message_iter_next(&iter);
649         dbus_message_iter_recurse(&iter, &properties);
650
651         _call_add(m, path, &properties);
652 }
653
654 static void _call_removed(void *data, DBusMessage *msg)
655 {
656         OFono_Modem *m = data;
657         DBusError err;
658         const char *path;
659
660         if (!msg) {
661                 ERR("Could not handle message %p", msg);
662                 return;
663         }
664
665         dbus_error_init(&err);
666         if (!dbus_message_get_args(msg, &err, DBUS_TYPE_OBJECT_PATH,
667                                         &path, NULL)) {
668                 ERR("Could not get CallRemoved arguments: %s: %s",
669                         err.name, err.message);
670                 dbus_error_free(&err);
671                 return;
672         }
673
674         _call_remove(m, path);
675 }
676
677 static OFono_Modem *_modem_selected_get(void)
678 {
679         OFono_Modem *found_path = NULL, *found_api = NULL, *m;
680         unsigned int online = 0, powered = 0;
681         Eina_Iterator *itr;
682
683         if (modem_selected)
684                 return modem_selected;
685
686         itr = eina_hash_iterator_data_new(modems);
687         EINA_ITERATOR_FOREACH(itr, m) {
688                 if (m->ignored)
689                         continue;
690
691                 if (m->online)
692                         online++;
693                 if (m->powered)
694                         powered++;
695
696                 if ((modem_path_wanted) && (!found_path)) {
697                         DBG("m=%s, wanted=%s", m->base.path, modem_path_wanted);
698                         if (m->base.path == modem_path_wanted) {
699                                 found_path = m;
700                                 break;
701                         }
702                 }
703
704                 if (!found_api) {
705                         DBG("m=%#x, mask=%#x", m->interfaces, modem_api_mask);
706                         if ((m->interfaces & modem_api_mask) == modem_api_mask)
707                                 found_api = m;
708                 }
709         }
710         eina_iterator_free(itr);
711
712         INF("found_path=%s, found_api=%s, wanted_path=%s, api_mask=%#x",
713                 found_path ? found_path->base.path : "",
714                 found_api ? found_api->base.path: "",
715                 modem_path_wanted ? modem_path_wanted : "",
716                 modem_api_mask);
717
718         if (!powered)
719                 ERR("No modems powered! Run connman or test/enable-modem");
720         if (!online)
721                 WRN("No modems online! Run connman or test/online-modem");
722
723         modem_selected = found_path ? found_path : found_api;
724         return modem_selected;
725 }
726
727 static OFono_Pending *_ofono_multiparty(const char *method,
728                                         OFono_Simple_Cb cb, const void *data)
729 {
730
731         OFono_Pending *p;
732         DBusMessage *msg;
733         OFono_Simple_Cb_Context *ctx = NULL;
734         OFono_Modem *m = _modem_selected_get();
735
736         EINA_SAFETY_ON_NULL_GOTO(m, error_no_message);
737
738         if (cb) {
739                 ctx = calloc(1, sizeof(OFono_Simple_Cb_Context));
740                 EINA_SAFETY_ON_NULL_GOTO(ctx, error_no_message);
741                 ctx->cb = cb;
742                 ctx->data = data;
743         }
744
745         msg = dbus_message_new_method_call(
746                                 bus_id, m->base.path,
747                                 OFONO_PREFIX OFONO_VOICE_IFACE,
748                                 method);
749
750         if (!msg)
751                 goto error_no_message;
752
753         if (!dbus_message_append_args(msg, DBUS_TYPE_INVALID))
754                 goto error_message_append;
755
756         INF("%s()", method);
757         p = _bus_object_message_send(&m->base, msg, _ofono_simple_reply, ctx);
758
759         return p;
760
761 error_message_append:
762         dbus_message_unref(msg);
763 error_no_message:
764         if (cb)
765                 cb((void *)data, OFONO_ERROR_FAILED);
766         free(ctx);
767         return NULL;
768 }
769
770 OFono_Pending *ofono_call_hangup(OFono_Call *c, OFono_Simple_Cb cb,
771                                         const void *data)
772 {
773         OFono_Simple_Cb_Context *ctx = NULL;
774         OFono_Pending *p;
775         DBusMessage *msg;
776
777         EINA_SAFETY_ON_NULL_RETURN_VAL(c, NULL);
778
779         if (cb) {
780                 ctx = calloc(1, sizeof(OFono_Simple_Cb_Context));
781                 EINA_SAFETY_ON_NULL_GOTO(ctx, error);
782                 ctx->cb = cb;
783                 ctx->data = data;
784         }
785
786         msg = dbus_message_new_method_call(
787                 bus_id, c->base.path, OFONO_PREFIX "VoiceCall", "Hangup");
788         if (!msg)
789                 goto error;
790
791         INF("Hangup(%s)", c->base.path);
792         p = _bus_object_message_send(&c->base, msg, _ofono_simple_reply, ctx);
793         return p;
794
795 error:
796         if (cb)
797                 cb((void *)data, OFONO_ERROR_FAILED);
798         free(ctx);
799         return NULL;
800 }
801
802 OFono_Pending *ofono_call_answer(OFono_Call *c, OFono_Simple_Cb cb,
803                                         const void *data)
804 {
805         OFono_Simple_Cb_Context *ctx = NULL;
806         OFono_Pending *p;
807         DBusMessage *msg;
808
809         EINA_SAFETY_ON_NULL_RETURN_VAL(c, NULL);
810
811         if (cb) {
812                 ctx = calloc(1, sizeof(OFono_Simple_Cb_Context));
813                 EINA_SAFETY_ON_NULL_GOTO(ctx, error);
814                 ctx->cb = cb;
815                 ctx->data = data;
816         }
817
818         msg = dbus_message_new_method_call(
819                 bus_id, c->base.path, OFONO_PREFIX "VoiceCall", "Answer");
820         if (!msg)
821                 goto error;
822
823         INF("Answer(%s)", c->base.path);
824         p = _bus_object_message_send(&c->base, msg, _ofono_simple_reply, ctx);
825         return p;
826
827 error:
828         if (cb)
829                 cb((void *)data, OFONO_ERROR_FAILED);
830         free(ctx);
831         return NULL;
832 }
833
834 OFono_Call_State ofono_call_state_get(const OFono_Call *c)
835 {
836         EINA_SAFETY_ON_NULL_RETURN_VAL(c, OFONO_CALL_STATE_DISCONNECTED);
837         return c->state;
838 }
839
840 const char *ofono_call_name_get(const OFono_Call *c)
841 {
842         EINA_SAFETY_ON_NULL_RETURN_VAL(c, NULL);
843         return c->name;
844 }
845
846 const char *ofono_call_line_id_get(const OFono_Call *c)
847 {
848         EINA_SAFETY_ON_NULL_RETURN_VAL(c, NULL);
849         return c->line_id;
850 }
851
852 Eina_Bool ofono_call_multiparty_get(const OFono_Call *c)
853 {
854         EINA_SAFETY_ON_NULL_RETURN_VAL(c, EINA_FALSE);
855         return c->multiparty;
856 }
857
858 double ofono_call_start_time_get(const OFono_Call *c)
859 {
860         EINA_SAFETY_ON_NULL_RETURN_VAL(c, -1.0);
861         return c->start_time;
862 }
863
864 time_t ofono_call_full_start_time_get(const OFono_Call *c)
865 {
866         EINA_SAFETY_ON_NULL_RETURN_VAL(c, 0);
867         return c->full_start_time;
868 }
869
870 static void _ofono_calls_get_reply(void *data, DBusMessage *msg,
871                                         DBusError *err)
872 {
873         OFono_Modem *m = data;
874         DBusMessageIter array, dict;
875
876         if (!msg) {
877                 if (err)
878                         ERR("%s: %s", err->name, err->message);
879                 else
880                         ERR("No message");
881                 return;
882         }
883
884         eina_hash_free_buckets(m->calls);
885
886         if (!dbus_message_iter_init(msg, &array)) {
887                 ERR("Could not get calls");
888                 return;
889         }
890
891         dbus_message_iter_recurse(&array, &dict);
892         for (; dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_STRUCT;
893                         dbus_message_iter_next(&dict)) {
894                 DBusMessageIter value, properties;
895                 const char *path;
896
897                 dbus_message_iter_recurse(&dict, &value);
898                 dbus_message_iter_get_basic(&value, &path);
899
900                 dbus_message_iter_next(&value);
901                 dbus_message_iter_recurse(&value, &properties);
902
903                 _call_add(m, path, &properties);
904         }
905 }
906
907 static void _modem_calls_load(OFono_Modem *m)
908 {
909         DBusMessage *msg = dbus_message_new_method_call(
910                 bus_id, m->base.path, OFONO_PREFIX OFONO_VOICE_IFACE,
911                 "GetCalls");
912
913         DBG("Get calls of %s", m->base.path);
914         _bus_object_message_send(&m->base, msg, _ofono_calls_get_reply, m);
915 }
916
917 static OFono_Modem *_modem_new(const char *path)
918 {
919         OFono_Modem *m = calloc(1, sizeof(OFono_Modem));
920         EINA_SAFETY_ON_NULL_RETURN_VAL(m, NULL);
921
922         m->base.path = eina_stringshare_add(path);
923         EINA_SAFETY_ON_NULL_GOTO(m->base.path, error_path);
924
925         m->calls = eina_hash_string_small_new(EINA_FREE_CB(_call_free));
926         EINA_SAFETY_ON_NULL_GOTO(m->calls, error_calls);
927
928         return m;
929
930 error_calls:
931         eina_stringshare_del(m->base.path);
932 error_path:
933         free(m);
934         return NULL;
935 }
936
937 static void _modem_free(OFono_Modem *m)
938 {
939         DBG("m=%p %s", m, m->base.path);
940
941         if (modem_selected == m)
942                 modem_selected = NULL;
943
944         eina_stringshare_del(m->name);
945         eina_stringshare_del(m->serial);
946
947         eina_hash_free(m->calls);
948
949         _bus_object_free(&m->base);
950 }
951
952
953 static void _call_volume_property_update(OFono_Modem *m, const char *prop_name,
954                                                 DBusMessageIter *iter)
955 {
956
957         if (strcmp(prop_name, "Muted") == 0) {
958                 m->muted = _dbus_bool_get(iter);
959                 DBG("%s Muted %d", m->base.path, m->muted);
960         } else if (strcmp(prop_name, "SpeakerVolume") == 0) {
961                 dbus_message_iter_get_basic(iter, &m->speaker_volume);
962                 DBG("%s Speaker Volume %hhu", m->base.path, m->speaker_volume);
963         } else if (strcmp(prop_name, "MicrophoneVolume") == 0) {
964                 dbus_message_iter_get_basic(iter, &m->microphone_volume);
965                 DBG("%s Microphone Volume %hhu", m->base.path, m->speaker_volume);
966         }
967 }
968
969 static void _notify_ofono_callbacks_modem_list(Eina_Inlist *list)
970 {
971         OFono_Callback_List_Modem_Node *node;
972
973         EINA_INLIST_FOREACH(list, node)
974                 node->cb((void *) node->cb_data);
975 }
976
977 static void _call_volume_property_changed(void *data, DBusMessage *msg)
978 {
979         OFono_Modem *m = data;
980         DBusMessageIter iter, variant_iter;
981         const char *prop_name;
982
983         if (!msg || !dbus_message_iter_init(msg, &iter)) {
984                 ERR("Could not handle message %p", msg);
985                 return;
986         }
987
988         dbus_message_iter_get_basic(&iter, &prop_name);
989         dbus_message_iter_next(&iter);
990         dbus_message_iter_recurse(&iter, &variant_iter);
991         _call_volume_property_update(m, prop_name, &variant_iter);
992
993         _notify_ofono_callbacks_modem_list(cbs_modem_changed);
994 }
995
996 static unsigned int _modem_interfaces_extract(DBusMessageIter *array)
997 {
998         DBusMessageIter entry;
999         unsigned int interfaces = 0;
1000
1001         dbus_message_iter_recurse(array, &entry);
1002         for (; dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_STRING;
1003                         dbus_message_iter_next(&entry)) {
1004                 const struct API_Interface_Map *itr;
1005                 const char *name;
1006                 size_t namelen;
1007
1008                 dbus_message_iter_get_basic(&entry, &name);
1009
1010                 if (strncmp(name, OFONO_PREFIX, strlen(OFONO_PREFIX)) != 0)
1011                         continue;
1012
1013                 name += strlen(OFONO_PREFIX);
1014                 namelen = strlen(name);
1015
1016                 DBG("interface: %s", name);
1017                 for (itr = api_iface_map; itr->name != NULL; itr++) {
1018                         if ((itr->namelen == namelen) &&
1019                                 (memcmp(itr->name, name, namelen) == 0)) {
1020                                 interfaces |= itr->bit;
1021                                 break;
1022                         }
1023                 }
1024                 if (itr->name == NULL)
1025                         WRN("ignored %s", name);
1026         }
1027
1028         return interfaces;
1029 }
1030
1031 static void _modem_update_interfaces(OFono_Modem *m, unsigned int ifaces)
1032 {
1033
1034         if (((m->interfaces & OFONO_API_CALL_VOL) == 0) &&
1035                 (ifaces & OFONO_API_CALL_VOL) == OFONO_API_CALL_VOL)
1036                 _ofono_call_volume_properties_get(m);
1037 }
1038
1039 static void _modem_property_update(OFono_Modem *m, const char *key,
1040                                         DBusMessageIter *value)
1041 {
1042         if (strcmp(key, "Powered") == 0) {
1043                 m->powered = _dbus_bool_get(value);
1044                 DBG("%s Powered %d", m->base.path, m->powered);
1045         } else if (strcmp(key, "Online") == 0) {
1046                 m->online = _dbus_bool_get(value);
1047                 DBG("%s Online %d", m->base.path, m->online);
1048         } else if (strcmp(key, "Interfaces") == 0) {
1049                 unsigned int ifaces = _modem_interfaces_extract(value);
1050                 DBG("%s Interfaces 0x%02x", m->base.path, ifaces);
1051                 if (m->interfaces != ifaces) {
1052                         _modem_update_interfaces(m, ifaces);
1053                         m->interfaces = ifaces;
1054
1055                         if (modem_selected && modem_path_wanted &&
1056                                 modem_selected->base.path != modem_path_wanted)
1057                                 modem_selected = NULL;
1058                 }
1059         } else if (strcmp(key, "Serial") == 0) {
1060                 const char *serial;
1061                 dbus_message_iter_get_basic(value, &serial);
1062                 DBG("%s Serial %s", m->base.path, serial);
1063                 eina_stringshare_replace(&m->serial, serial);
1064         } else if (strcmp(key, "Type") == 0) {
1065                 const char *type;
1066                 dbus_message_iter_get_basic(value, &type);
1067                 DBG("%s Type %s", m->base.path, type);
1068
1069                 if (!modem_types)
1070                         m->ignored = EINA_FALSE;
1071                 else {
1072                         const Eina_List *n;
1073                         const char *t;
1074                         m->ignored = EINA_TRUE;
1075                         EINA_LIST_FOREACH(modem_types, n, t) {
1076                                 if (strcmp(t, type) == 0) {
1077                                         m->ignored = EINA_FALSE;
1078                                         break;
1079                                 }
1080                         }
1081                         if (m->ignored)
1082                                 INF("Modem %s type %s is ignored",
1083                                         m->base.path, type);
1084                 }
1085         } else
1086                 DBG("%s %s (unused property)", m->base.path, key);
1087
1088         _notify_ofono_callbacks_modem_list(cbs_modem_changed);
1089 }
1090
1091 static void _ofono_call_volume_properties_get_reply(void *data,
1092                                                         DBusMessage *msg,
1093                                                         DBusError *err)
1094 {
1095         OFono_Modem *m = data;
1096         DBusMessageIter iter, prop;
1097
1098         if (dbus_error_is_set(err)) {
1099                 DBG("%s: %s", err->name, err->message);
1100                 return;
1101         }
1102
1103         dbus_message_iter_init(msg, &iter);
1104         dbus_message_iter_recurse(&iter, &prop);
1105
1106         for (; dbus_message_iter_get_arg_type(&prop) == DBUS_TYPE_DICT_ENTRY;
1107              dbus_message_iter_next(&prop)) {
1108                 DBusMessageIter entry, value;
1109                 const char *key;
1110
1111                 dbus_message_iter_recurse(&prop, &entry);
1112                 dbus_message_iter_get_basic(&entry, &key);
1113
1114                 dbus_message_iter_next(&entry);
1115                 dbus_message_iter_recurse(&entry, &value);
1116                 _call_volume_property_update(m, key, &value);
1117         }
1118 }
1119
1120 static void _ofono_call_volume_properties_get(OFono_Modem *m)
1121 {
1122         DBusMessage *msg;
1123         msg = dbus_message_new_method_call(bus_id, m->base.path,
1124                                                 OFONO_PREFIX
1125                                                 OFONO_CALL_VOL_IFACE,
1126                                                 "GetProperties");
1127         if (!msg)
1128                 return;
1129
1130         _bus_object_message_send(&m->base, msg,
1131                                 _ofono_call_volume_properties_get_reply, m);
1132 }
1133
1134 static void _modem_add(const char *path, DBusMessageIter *prop)
1135 {
1136         OFono_Modem *m;
1137
1138         DBG("path=%s", path);
1139
1140         m = eina_hash_find(modems, path);
1141         if (m) {
1142                 DBG("Modem already exists %p (%s)", m, path);
1143                 goto update_properties;
1144         }
1145
1146         m = _modem_new(path);
1147         EINA_SAFETY_ON_NULL_RETURN(m);
1148         eina_hash_add(modems, m->base.path, m);
1149
1150         _bus_object_signal_listen(&m->base, OFONO_PREFIX OFONO_VOICE_IFACE,
1151                                         "CallAdded", _call_added, m);
1152         _bus_object_signal_listen(&m->base, OFONO_PREFIX OFONO_VOICE_IFACE,
1153                                         "CallRemoved", _call_removed, m);
1154         _bus_object_signal_listen(&m->base, OFONO_PREFIX OFONO_CALL_VOL_IFACE,
1155                                         "PropertyChanged",
1156                                         _call_volume_property_changed, m);
1157
1158         /* TODO: do we need to listen to BarringActive or Forwarded? */
1159
1160         if (modem_selected && modem_path_wanted &&
1161                 modem_selected->base.path != modem_path_wanted)
1162                 modem_selected = NULL;
1163
1164 update_properties:
1165         if (!prop)
1166                 return;
1167         for (; dbus_message_iter_get_arg_type(prop) == DBUS_TYPE_DICT_ENTRY;
1168                         dbus_message_iter_next(prop)) {
1169                 DBusMessageIter entry, value;
1170                 const char *key;
1171
1172                 dbus_message_iter_recurse(prop, &entry);
1173                 dbus_message_iter_get_basic(&entry, &key);
1174
1175                 dbus_message_iter_next(&entry);
1176                 dbus_message_iter_recurse(&entry, &value);
1177
1178                 _modem_property_update(m, key, &value);
1179         }
1180
1181         if (m->interfaces & OFONO_API_VOICE)
1182                 _modem_calls_load(m);
1183 }
1184
1185 static void _modem_remove(const char *path)
1186 {
1187         DBG("path=%s", path);
1188         eina_hash_del_by_key(modems, path);
1189 }
1190
1191 static void _ofono_modems_get_reply(void *data __UNUSED__, DBusMessage *msg,
1192                                         DBusError *err)
1193 {
1194         DBusMessageIter array, dict;
1195
1196         pc_get_modems = NULL;
1197
1198         if (!msg) {
1199                 if (err)
1200                         ERR("%s: %s", err->name, err->message);
1201                 else
1202                         ERR("No message");
1203                 return;
1204         }
1205
1206         EINA_SAFETY_ON_NULL_RETURN(modems);
1207         eina_hash_free_buckets(modems);
1208
1209         if (!dbus_message_iter_init(msg, &array)) {
1210                 ERR("Could not get modems");
1211                 return;
1212         }
1213
1214         dbus_message_iter_recurse(&array, &dict);
1215         for (; dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_STRUCT;
1216                         dbus_message_iter_next(&dict)) {
1217                 DBusMessageIter value, properties;
1218                 const char *path;
1219
1220                 dbus_message_iter_recurse(&dict, &value);
1221                 dbus_message_iter_get_basic(&value, &path);
1222
1223                 dbus_message_iter_next(&value);
1224                 dbus_message_iter_recurse(&value, &properties);
1225
1226                 _modem_add(path, &properties);
1227         }
1228 }
1229
1230 static void _modem_added(void *data __UNUSED__, DBusMessage *msg)
1231 {
1232         DBusMessageIter iter, properties;
1233         const char *path;
1234
1235         if (!msg || !dbus_message_iter_init(msg, &iter)) {
1236                 ERR("Could not handle message %p", msg);
1237                 return;
1238         }
1239
1240         dbus_message_iter_get_basic(&iter, &path);
1241
1242         dbus_message_iter_next(&iter);
1243         dbus_message_iter_recurse(&iter, &properties);
1244
1245         _modem_add(path, &properties);
1246 }
1247
1248 static void _modem_removed(void *data __UNUSED__, DBusMessage *msg)
1249 {
1250         DBusError err;
1251         const char *path;
1252
1253         if (!msg) {
1254                 ERR("Could not handle message %p", msg);
1255                 return;
1256         }
1257
1258         dbus_error_init(&err);
1259         if (!dbus_message_get_args(msg, &err, DBUS_TYPE_OBJECT_PATH,
1260                                         &path, NULL)) {
1261                 ERR("Could not get ModemRemoved arguments: %s: %s",
1262                         err.name, err.message);
1263                 dbus_error_free(&err);
1264                 return;
1265         }
1266
1267         _modem_remove(path);
1268 }
1269
1270 static void _modem_property_changed(void *data __UNUSED__, DBusMessage *msg)
1271 {
1272         const char *path;
1273         OFono_Modem *m;
1274         DBusMessageIter iter, value;
1275         const char *key;
1276
1277         if (!msg || !dbus_message_iter_init(msg, &iter)) {
1278                 ERR("Could not handle message %p", msg);
1279                 return;
1280         }
1281
1282         path = dbus_message_get_path(msg);
1283         DBG("path=%s", path);
1284
1285         m = eina_hash_find(modems, path);
1286         if (!m) {
1287                 DBG("Modem is unknown (%s)", path);
1288                 return;
1289         }
1290
1291         dbus_message_iter_get_basic(&iter, &key);
1292         dbus_message_iter_next(&iter);
1293         dbus_message_iter_recurse(&iter, &value);
1294         _modem_property_update(m, key, &value);
1295 }
1296
1297 static void _modems_load(void)
1298 {
1299         DBusMessage *msg = dbus_message_new_method_call(
1300                 bus_id, "/", OFONO_PREFIX OFONO_MANAGER_IFACE, "GetModems");
1301
1302         if (pc_get_modems)
1303                 dbus_pending_call_cancel(pc_get_modems);
1304
1305         DBG("Get modems");
1306         pc_get_modems = e_dbus_message_send(
1307                 bus_conn, msg, _ofono_modems_get_reply, -1, NULL);
1308         dbus_message_unref(msg);
1309 }
1310
1311 static void _ofono_connected(const char *id)
1312 {
1313         free(bus_id);
1314         bus_id = strdup(id);
1315
1316         sig_modem_added = e_dbus_signal_handler_add(
1317                 bus_conn, bus_id, "/",
1318                 OFONO_PREFIX OFONO_MANAGER_IFACE,
1319                 "ModemAdded",
1320                 _modem_added, NULL);
1321
1322         sig_modem_removed = e_dbus_signal_handler_add(
1323                 bus_conn, bus_id, "/",
1324                 OFONO_PREFIX OFONO_MANAGER_IFACE,
1325                 "ModemRemoved",
1326                 _modem_removed, NULL);
1327
1328         sig_modem_prop_changed = e_dbus_signal_handler_add(
1329                 bus_conn, bus_id, NULL,
1330                 OFONO_PREFIX OFONO_MODEM_IFACE,
1331                 "PropertyChanged",
1332                 _modem_property_changed, NULL);
1333
1334         _modems_load();
1335
1336         _notify_ofono_callbacks_modem_list(cbs_modem_connected);
1337 }
1338
1339 static void _ofono_disconnected(void)
1340 {
1341         eina_hash_free_buckets(modems);
1342
1343         if (sig_modem_added) {
1344                 e_dbus_signal_handler_del(bus_conn, sig_modem_added);
1345                 sig_modem_added = NULL;
1346         }
1347
1348         if (sig_modem_removed) {
1349                 e_dbus_signal_handler_del(bus_conn, sig_modem_removed);
1350                 sig_modem_removed = NULL;
1351         }
1352
1353         if (sig_modem_prop_changed) {
1354                 e_dbus_signal_handler_del(bus_conn, sig_modem_prop_changed);
1355                 sig_modem_prop_changed = NULL;
1356         }
1357
1358         if (bus_id) {
1359                 _notify_ofono_callbacks_modem_list(cbs_modem_disconnected);
1360                 free(bus_id);
1361                 bus_id = NULL;
1362         }
1363 }
1364
1365 static void _name_owner_changed(void *data __UNUSED__, DBusMessage *msg)
1366 {
1367         DBusError err;
1368         const char *name, *from, *to;
1369
1370         dbus_error_init(&err);
1371         if (!dbus_message_get_args(msg, &err,
1372                                         DBUS_TYPE_STRING, &name,
1373                                         DBUS_TYPE_STRING, &from,
1374                                         DBUS_TYPE_STRING, &to,
1375                                         DBUS_TYPE_INVALID)) {
1376                 ERR("Could not get NameOwnerChanged arguments: %s: %s",
1377                         err.name, err.message);
1378                 dbus_error_free(&err);
1379                 return;
1380         }
1381
1382         if (strcmp(name, bus_name) != 0)
1383                 return;
1384
1385         DBG("NameOwnerChanged %s from=%s to=%s", name, from, to);
1386
1387         if (from[0] == '\0' && to[0] != '\0') {
1388                 INF("oFono appeared as %s", to);
1389                 _ofono_connected(to);
1390         } else if (from[0] != '\0' && to[0] == '\0') {
1391                 INF("oFono disappeared from %s", from);
1392                 _ofono_disconnected();
1393         }
1394 }
1395
1396 static void _ofono_get_name_owner(void *data __UNUSED__, DBusMessage *msg, DBusError *err)
1397 {
1398         DBusMessageIter itr;
1399         const char *id;
1400
1401         if (!msg) {
1402                 if (err)
1403                         ERR("%s: %s", err->name, err->message);
1404                 else
1405                         ERR("No message");
1406                 return;
1407         }
1408
1409         dbus_message_iter_init(msg, &itr);
1410         dbus_message_iter_get_basic(&itr, &id);
1411         if (!id || id[0] == '\0') {
1412                 ERR("No name owner fo %s!", bus_name);
1413                 return;
1414         }
1415
1416         INF("oFono bus id: %s", id);
1417         _ofono_connected(id);
1418 }
1419
1420 OFono_Pending *ofono_modem_change_pin(const char *what, const char *old,
1421                                         const char *new, OFono_Simple_Cb cb,
1422                                         const void *data)
1423 {
1424         OFono_Simple_Cb_Context *ctx = NULL;
1425         OFono_Error err = OFONO_ERROR_OFFLINE;
1426         OFono_Pending *p;
1427         DBusMessage *msg;
1428         OFono_Modem *m = _modem_selected_get();
1429         EINA_SAFETY_ON_NULL_GOTO(m, error);
1430         EINA_SAFETY_ON_NULL_GOTO(what, error);
1431         EINA_SAFETY_ON_NULL_GOTO(old, error);
1432         EINA_SAFETY_ON_NULL_GOTO(new, error);
1433
1434         if ((m->interfaces & OFONO_API_SIM) == 0)
1435                 goto error;
1436         err = OFONO_ERROR_FAILED;
1437
1438         if (cb) {
1439                 ctx = calloc(1, sizeof(OFono_Simple_Cb_Context));
1440                 EINA_SAFETY_ON_NULL_GOTO(ctx, error);
1441                 ctx->cb = cb;
1442                 ctx->data = data;
1443         }
1444
1445         msg = dbus_message_new_method_call(
1446                 bus_id, m->base.path, OFONO_PREFIX OFONO_SIM_IFACE,
1447                 "ChangePin");
1448         if (!msg)
1449                 goto error;
1450
1451         if (!dbus_message_append_args(msg, DBUS_TYPE_STRING, &what,
1452                                         DBUS_TYPE_STRING, &old,
1453                                         DBUS_TYPE_STRING, &new,
1454                                         DBUS_TYPE_INVALID))
1455                 goto error_message;
1456
1457         INF("ChangePin(%s, %s, %s)", what, old, new);
1458         p = _bus_object_message_send(&m->base, msg, _ofono_simple_reply, ctx);
1459         return p;
1460
1461 error_message:
1462         dbus_message_unref(msg);
1463 error:
1464         if (cb)
1465                 cb((void *)data, err);
1466         free(ctx);
1467         return NULL;
1468 }
1469
1470 OFono_Pending *ofono_modem_reset_pin(const char *what, const char *puk,
1471                                         const char *new, OFono_Simple_Cb cb,
1472                                         const void *data)
1473 {
1474         OFono_Simple_Cb_Context *ctx = NULL;
1475         OFono_Error err = OFONO_ERROR_OFFLINE;
1476         OFono_Pending *p;
1477         DBusMessage *msg;
1478         OFono_Modem *m = _modem_selected_get();
1479         EINA_SAFETY_ON_NULL_GOTO(m, error);
1480         EINA_SAFETY_ON_NULL_GOTO(what, error);
1481         EINA_SAFETY_ON_NULL_GOTO(puk, error);
1482         EINA_SAFETY_ON_NULL_GOTO(new, error);
1483
1484         if ((m->interfaces & OFONO_API_SIM) == 0)
1485                 goto error;
1486         err = OFONO_ERROR_FAILED;
1487
1488         if (cb) {
1489                 ctx = calloc(1, sizeof(OFono_Simple_Cb_Context));
1490                 EINA_SAFETY_ON_NULL_GOTO(ctx, error);
1491                 ctx->cb = cb;
1492                 ctx->data = data;
1493         }
1494
1495         msg = dbus_message_new_method_call(
1496                 bus_id, m->base.path, OFONO_PREFIX OFONO_SIM_IFACE, "ResetPin");
1497         if (!msg)
1498                 goto error;
1499
1500         if (!dbus_message_append_args(msg, DBUS_TYPE_STRING, &what,
1501                                         DBUS_TYPE_STRING, &puk,
1502                                         DBUS_TYPE_STRING, &new,
1503                                         DBUS_TYPE_INVALID))
1504                 goto error_message;
1505
1506         INF("ResetPin(%s, %s, %s)", what, puk, new);
1507         p = _bus_object_message_send(&m->base, msg, _ofono_simple_reply, ctx);
1508         return p;
1509
1510 error_message:
1511         dbus_message_unref(msg);
1512 error:
1513         if (cb)
1514                 cb((void *)data, err);
1515         free(ctx);
1516         return NULL;
1517 }
1518
1519 static char *_ss_initiate_convert_ussd(const char *type __UNUSED__,
1520                                         DBusMessageIter *itr)
1521 {
1522         const char *ussd_response;
1523
1524         if (dbus_message_iter_get_arg_type(itr) != DBUS_TYPE_STRING) {
1525                 ERR("Invalid type: %c (expected: %c)",
1526                         dbus_message_iter_get_arg_type(itr), DBUS_TYPE_STRING);
1527                 return NULL;
1528         }
1529         dbus_message_iter_get_basic(itr, &ussd_response);
1530         EINA_SAFETY_ON_NULL_RETURN_VAL(ussd_response, NULL);
1531         return strdup(ussd_response);
1532 }
1533
1534 static void _ss_initiate_cb_dict_convert(Eina_Strbuf *buf,
1535                                                 DBusMessageIter *dict)
1536 {
1537         for (; dbus_message_iter_get_arg_type(dict) == DBUS_TYPE_DICT_ENTRY;
1538                         dbus_message_iter_next(dict)) {
1539                 DBusMessageIter e, v;
1540                 const char *key, *value;
1541
1542                 dbus_message_iter_recurse(dict, &e);
1543                 dbus_message_iter_get_basic(&e, &key);
1544
1545                 dbus_message_iter_next(&e);
1546                 dbus_message_iter_recurse(&e, &v);
1547                 dbus_message_iter_get_basic(&v, &value);
1548
1549                 eina_strbuf_append_printf(buf, "&nbsp;&nbsp;&nbsp;%s=%s<br>",
1550                                                 key, value);
1551         }
1552 }
1553
1554 static char *_ss_initiate_convert_call1(const char *type, DBusMessageIter *itr)
1555 {
1556         DBusMessageIter array, dict;
1557         const char *ss_op, *service;
1558         Eina_Strbuf *buf;
1559         char *str;
1560
1561         dbus_message_iter_recurse(itr, &array);
1562
1563         if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_STRING) {
1564                 ERR("Invalid type: %c (expected: %c)",
1565                         dbus_message_iter_get_arg_type(&array),
1566                         DBUS_TYPE_STRING);
1567                 return NULL;
1568         }
1569         dbus_message_iter_get_basic(&array, &ss_op);
1570         EINA_SAFETY_ON_NULL_RETURN_VAL(ss_op, NULL);
1571
1572         if (!dbus_message_iter_next(&array)) {
1573                 ERR("Missing %s service", type);
1574                 return NULL;
1575         }
1576
1577         if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_STRING) {
1578                 ERR("Invalid type: %c (expected: %c)",
1579                         dbus_message_iter_get_arg_type(&array),
1580                         DBUS_TYPE_STRING);
1581                 return NULL;
1582         }
1583         dbus_message_iter_get_basic(&array, &service);
1584         EINA_SAFETY_ON_NULL_RETURN_VAL(service, NULL);
1585
1586         if (!dbus_message_iter_next(&array)) {
1587                 ERR("Missing %s information", type);
1588                 return NULL;
1589         }
1590
1591         buf = eina_strbuf_new();
1592         eina_strbuf_append_printf(buf, "<b>%s %s=%s</b><br><br>",
1593                                         type, ss_op, service);
1594
1595         dbus_message_iter_recurse(&array, &dict);
1596         _ss_initiate_cb_dict_convert(buf, &dict);
1597
1598         str = eina_strbuf_string_steal(buf);
1599         eina_strbuf_free(buf);
1600         return str;
1601 }
1602
1603 static char *_ss_initiate_convert_call_waiting(const char *type,
1604                                                 DBusMessageIter *itr)
1605 {
1606         DBusMessageIter array, dict;
1607         const char *ss_op;
1608         Eina_Strbuf *buf;
1609         char *str;
1610
1611         dbus_message_iter_recurse(itr, &array);
1612
1613         if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_STRING) {
1614                 ERR("Invalid type: %c (expected: %c)",
1615                         dbus_message_iter_get_arg_type(&array),
1616                         DBUS_TYPE_STRING);
1617                 return NULL;
1618         }
1619         dbus_message_iter_get_basic(&array, &ss_op);
1620         EINA_SAFETY_ON_NULL_RETURN_VAL(ss_op, NULL);
1621
1622         if (!dbus_message_iter_next(&array)) {
1623                 ERR("Missing %s information", type);
1624                 return NULL;
1625         }
1626
1627         buf = eina_strbuf_new();
1628         eina_strbuf_append_printf(buf, "<b>%s %s</b><br><br>",
1629                                         type, ss_op);
1630
1631         dbus_message_iter_recurse(&array, &dict);
1632         _ss_initiate_cb_dict_convert(buf, &dict);
1633
1634         str = eina_strbuf_string_steal(buf);
1635         eina_strbuf_free(buf);
1636         return str;
1637 }
1638
1639 static char *_ss_initiate_convert_call2(const char *type,
1640                                                 DBusMessageIter *itr)
1641 {
1642         DBusMessageIter array;
1643         const char *ss_op, *status;
1644         Eina_Strbuf *buf;
1645         char *str;
1646
1647         dbus_message_iter_recurse(itr, &array);
1648
1649         if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_STRING) {
1650                 ERR("Invalid type: %c (expected: %c)",
1651                         dbus_message_iter_get_arg_type(&array),
1652                         DBUS_TYPE_STRING);
1653                 return NULL;
1654         }
1655         dbus_message_iter_get_basic(&array, &ss_op);
1656         EINA_SAFETY_ON_NULL_RETURN_VAL(ss_op, NULL);
1657
1658         if (!dbus_message_iter_next(&array)) {
1659                 ERR("Missing %s status", type);
1660                 return NULL;
1661         }
1662
1663         if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_STRING) {
1664                 ERR("Invalid type: %c (expected: %c)",
1665                         dbus_message_iter_get_arg_type(&array),
1666                         DBUS_TYPE_STRING);
1667                 return NULL;
1668         }
1669         dbus_message_iter_get_basic(&array, &status);
1670         EINA_SAFETY_ON_NULL_RETURN_VAL(status, NULL);
1671
1672         buf = eina_strbuf_new();
1673         eina_strbuf_append_printf(buf, "<b>%s:</b><br><br>%s=%s",
1674                                         type, ss_op, status);
1675
1676         str = eina_strbuf_string_steal(buf);
1677         eina_strbuf_free(buf);
1678         return str;
1679 }
1680
1681 static const struct SS_Initiate_Convert_Map {
1682         const char *type;
1683         size_t typelen;
1684         char *(*convert)(const char *type, DBusMessageIter *itr);
1685 } ss_initiate_convert_map[] = {
1686 #define MAP(type, conv) {type, sizeof(type) - 1, conv}
1687         MAP("USSD", _ss_initiate_convert_ussd),
1688         MAP("CallBarring", _ss_initiate_convert_call1),
1689         MAP("CallForwarding", _ss_initiate_convert_call1),
1690         MAP("CallWaiting", _ss_initiate_convert_call_waiting),
1691         MAP("CallingLinePresentation", _ss_initiate_convert_call2),
1692         MAP("ConnectedLinePresentation", _ss_initiate_convert_call2),
1693         MAP("CallingLineRestriction", _ss_initiate_convert_call2),
1694         MAP("ConnectedLineRestriction", _ss_initiate_convert_call2),
1695 #undef MAP
1696         {NULL, 0, NULL}
1697 };
1698
1699 static char *_ss_initiate_convert(DBusMessage *msg)
1700 {
1701         DBusMessageIter array, variant;
1702         const struct SS_Initiate_Convert_Map *citr;
1703         const char *type = NULL;
1704         size_t typelen;
1705
1706         if (!dbus_message_iter_init(msg, &array))
1707                 goto error;
1708
1709         if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_STRING) {
1710                 ERR("Invalid type for first argument: %c (expected: %c)",
1711                         dbus_message_iter_get_arg_type(&array),
1712                         DBUS_TYPE_STRING);
1713                 goto error;
1714         }
1715         dbus_message_iter_get_basic(&array, &type);
1716         if (!type) {
1717                 ERR("Couldn't get SupplementaryServices.Initiate type");
1718                 goto error;
1719         }
1720         DBG("type: %s", type);
1721
1722         if (!dbus_message_iter_next(&array)) {
1723                 ERR("Couldn't get SupplementaryServices.Initiate payload");
1724                 goto error;
1725         }
1726         dbus_message_iter_recurse(&array, &variant);
1727
1728         typelen = strlen(type);
1729         for (citr = ss_initiate_convert_map; citr->type != NULL; citr++) {
1730                 if ((citr->typelen == typelen) &&
1731                         (memcmp(citr->type, type, typelen) == 0)) {
1732                         return citr->convert(type, &variant);
1733                 }
1734         }
1735         ERR("Could not convert SupplementaryServices.Initiate type %s", type);
1736
1737 error:
1738         return NULL;
1739 }
1740
1741 OFono_Pending *ofono_ss_initiate(const char *command, OFono_String_Cb cb, const void *data)
1742 {
1743         OFono_String_Cb_Context *ctx = NULL;
1744         OFono_Error err = OFONO_ERROR_OFFLINE;
1745         OFono_Pending *p;
1746         DBusMessage *msg;
1747         OFono_Modem *m = _modem_selected_get();
1748         EINA_SAFETY_ON_NULL_GOTO(m, error);
1749         EINA_SAFETY_ON_NULL_GOTO(command, error);
1750
1751         if ((m->interfaces & OFONO_API_SUPPL_SERV) == 0)
1752                 goto error;
1753         err = OFONO_ERROR_FAILED;
1754
1755         ctx = calloc(1, sizeof(OFono_String_Cb_Context));
1756         EINA_SAFETY_ON_NULL_GOTO(ctx, error);
1757         ctx->cb = cb;
1758         ctx->data = data;
1759         ctx->name = OFONO_PREFIX OFONO_SUPPL_SERV_IFACE ".Initiate";
1760         ctx->convert = _ss_initiate_convert;
1761
1762         msg = dbus_message_new_method_call(
1763                 bus_id, m->base.path, OFONO_PREFIX OFONO_SUPPL_SERV_IFACE,
1764                 "Initiate");
1765         if (!msg)
1766                 goto error;
1767
1768         if (!dbus_message_append_args(msg, DBUS_TYPE_STRING, &command,
1769                                         DBUS_TYPE_INVALID))
1770                 goto error_message;
1771
1772         INF("SupplementaryServices.Initiate(%s)", command);
1773         p = _bus_object_message_send(&m->base, msg, _ofono_string_reply, ctx);
1774         return p;
1775
1776 error_message:
1777         dbus_message_unref(msg);
1778 error:
1779         if (cb)
1780                 cb((void *)data, err, NULL);
1781         free(ctx);
1782         return NULL;
1783 }
1784
1785 typedef struct _OFono_Call_Cb_Context
1786 {
1787         OFono_Call_Cb cb;
1788         OFono_Modem *modem;
1789         const void *data;
1790         const char *name;
1791 } OFono_Call_Cb_Context;
1792
1793 static void _ofono_dial_reply(void *data, DBusMessage *msg, DBusError *err)
1794 {
1795         OFono_Call_Cb_Context *ctx = data;
1796         OFono_Call *c = NULL;
1797         OFono_Error oe = OFONO_ERROR_NONE;
1798
1799         if (!msg) {
1800                 DBG("%s: %s", err->name, err->message);
1801                 oe = _ofono_error_parse(err->name);
1802         } else {
1803                 DBusError e;
1804                 const char *path;
1805                 dbus_error_init(&e);
1806                 if (!dbus_message_get_args(msg, &e, DBUS_TYPE_OBJECT_PATH,
1807                                                 &path, DBUS_TYPE_INVALID)) {
1808                         ERR("Could not get Dial reply: %s: %s",
1809                                 e.name, e.message);
1810                         dbus_error_free(&e);
1811                         oe = OFONO_ERROR_FAILED;
1812                 } else {
1813                         c = eina_hash_find(ctx->modem->calls, path);
1814                         if (!c) {
1815                                 _call_add(ctx->modem, path, NULL);
1816                                 c = eina_hash_find(ctx->modem->calls, path);
1817                         }
1818                         if (!c) {
1819                                 ERR("Could not find call %s", path);
1820                                 oe = OFONO_ERROR_FAILED;
1821                         }
1822                 }
1823         }
1824
1825         if (ctx->cb)
1826                 ctx->cb((void *)ctx->data, oe, c);
1827
1828         free(ctx);
1829 }
1830
1831 OFono_Pending *ofono_dial(const char *number, const char *hide_callerid,
1832                                 OFono_Call_Cb cb, const void *data)
1833 {
1834         OFono_Call_Cb_Context *ctx = NULL;
1835         OFono_Error err = OFONO_ERROR_OFFLINE;
1836         OFono_Pending *p;
1837         DBusMessage *msg;
1838         OFono_Modem *m = _modem_selected_get();
1839         EINA_SAFETY_ON_NULL_GOTO(m, error);
1840
1841
1842         if ((m->interfaces & OFONO_API_VOICE) == 0)
1843                 goto error;
1844         err = OFONO_ERROR_FAILED;
1845
1846         if (!hide_callerid)
1847                 hide_callerid = "";
1848
1849         ctx = calloc(1, sizeof(OFono_Call_Cb_Context));
1850         EINA_SAFETY_ON_NULL_GOTO(ctx, error);
1851         ctx->cb = cb;
1852         ctx->data = data;
1853         ctx->name = OFONO_PREFIX OFONO_VOICE_IFACE ".Dial";
1854         ctx->modem = m;
1855
1856         msg = dbus_message_new_method_call(
1857                 bus_id, m->base.path, OFONO_PREFIX OFONO_VOICE_IFACE, "Dial");
1858         if (!msg)
1859                 goto error;
1860
1861         if (!dbus_message_append_args(msg, DBUS_TYPE_STRING, &number,
1862                                         DBUS_TYPE_STRING, &hide_callerid,
1863                                         DBUS_TYPE_INVALID))
1864                 goto error_message;
1865
1866         INF("Dial(%s, %s)", number, hide_callerid);
1867         p = _bus_object_message_send(&m->base, msg, _ofono_dial_reply, ctx);
1868         return p;
1869
1870 error_message:
1871         dbus_message_unref(msg);
1872 error:
1873         if (cb)
1874                 cb((void *)data, err, NULL);
1875         free(ctx);
1876         return NULL;
1877 }
1878
1879 static OFono_Pending *_ofono_simple_do(OFono_API api, const char *method,
1880                                         OFono_Simple_Cb cb, const void *data)
1881 {
1882         OFono_Simple_Cb_Context *ctx = NULL;
1883         OFono_Error err = OFONO_ERROR_OFFLINE;
1884         OFono_Pending *p;
1885         DBusMessage *msg;
1886         char iface[128] = "";
1887         const struct API_Interface_Map *itr;
1888         OFono_Modem *m = _modem_selected_get();
1889         EINA_SAFETY_ON_NULL_GOTO(m, error);
1890         EINA_SAFETY_ON_NULL_GOTO(method, error);
1891
1892         if ((m->interfaces & api) == 0)
1893                 goto error;
1894         err = OFONO_ERROR_FAILED;
1895
1896         for (itr = api_iface_map; itr->name != NULL; itr++) {
1897                 if (itr->bit == api) {
1898                         snprintf(iface, sizeof(iface), "%s%s",
1899                                         OFONO_PREFIX, itr->name);
1900                         break;
1901                 }
1902         }
1903         if (iface[0] == '\0') {
1904                 ERR("Could not map api %d to interface name!", api);
1905                 goto error;
1906         }
1907
1908         if (cb) {
1909                 ctx = calloc(1, sizeof(OFono_Simple_Cb_Context));
1910                 EINA_SAFETY_ON_NULL_GOTO(ctx, error);
1911                 ctx->cb = cb;
1912                 ctx->data = data;
1913         }
1914
1915         msg = dbus_message_new_method_call(bus_id, m->base.path, iface, method);
1916         if (!msg)
1917                 goto error;
1918
1919         INF("%s.%s()", iface, method);
1920         p = _bus_object_message_send(&m->base, msg, _ofono_simple_reply, ctx);
1921         return p;
1922
1923 error:
1924         if (cb)
1925                 cb((void *)data, err);
1926         free(ctx);
1927         return NULL;
1928 }
1929
1930 OFono_Pending *ofono_transfer(OFono_Simple_Cb cb, const void *data)
1931 {
1932         return _ofono_simple_do(OFONO_API_VOICE, "Transfer", cb, data);
1933 }
1934
1935 OFono_Pending *ofono_swap_calls(OFono_Simple_Cb cb, const void *data)
1936 {
1937         return _ofono_simple_do(OFONO_API_VOICE, "SwapCalls", cb, data);
1938 }
1939
1940 OFono_Pending *ofono_release_and_answer(OFono_Simple_Cb cb, const void *data)
1941 {
1942         return _ofono_simple_do(OFONO_API_VOICE, "ReleaseAndAnswer", cb, data);
1943 }
1944
1945 OFono_Pending *ofono_hold_and_answer(OFono_Simple_Cb cb, const void *data)
1946 {
1947         return _ofono_simple_do(OFONO_API_VOICE, "HoldAndAnswer", cb, data);
1948 }
1949
1950 OFono_Pending *ofono_hangup_all(OFono_Simple_Cb cb, const void *data)
1951 {
1952         return _ofono_simple_do(OFONO_API_VOICE, "HangupAll", cb, data);
1953 }
1954
1955 const char *ofono_modem_serial_get(void)
1956 {
1957         OFono_Modem *m = _modem_selected_get();
1958         EINA_SAFETY_ON_NULL_RETURN_VAL(m, NULL);
1959         return m->serial;
1960 }
1961
1962 void ofono_modem_api_require(const char *spec)
1963 {
1964         unsigned int api_mask = 0;
1965         const char *name = spec;
1966
1967         EINA_SAFETY_ON_NULL_RETURN(spec);
1968
1969         do {
1970                 const struct API_Interface_Map *itr;
1971                 const char *p;
1972                 unsigned int namelen;
1973
1974                 p = strchr(name, ',');
1975                 if (p)
1976                         namelen = p - name;
1977                 else
1978                         namelen = strlen(name);
1979
1980                 for (itr = api_iface_map; itr->name != NULL; itr++) {
1981                         if ((itr->namelen == namelen) &&
1982                                 (memcmp(itr->name, name, namelen) == 0)) {
1983                                 api_mask |= itr->bit;
1984                                 break;
1985                         }
1986                 }
1987                 if (itr->name == NULL)
1988                         WRN("Unknown oFono API: %.*s", namelen, name);
1989
1990                 if (p)
1991                         name = p + 1;
1992                 else
1993                         name = NULL;
1994         } while (name);
1995
1996         if (api_mask)
1997                 DBG("API parsed: '%s' = %#x", spec, api_mask);
1998         else {
1999                 ERR("Could not parse API: %s", spec);
2000                 return;
2001         }
2002
2003         if (modem_api_mask == api_mask)
2004                 return;
2005         modem_api_mask = api_mask;
2006         modem_selected = NULL;
2007 }
2008
2009 void ofono_modem_api_list(FILE *fp, const char *prefix, const char *suffix)
2010 {
2011         const struct API_Interface_Map *itr;
2012         for (itr = api_iface_map; itr->name != NULL; itr++)
2013                 fprintf(fp, "%s%s%s", prefix, itr->name, suffix);
2014 }
2015
2016 void ofono_modem_type_require(const char *spec)
2017 {
2018         Eina_List *lst = NULL;
2019         const char *name = spec;
2020
2021         EINA_SAFETY_ON_NULL_RETURN(spec);
2022
2023         do {
2024                 const char **itr;
2025                 const char *p;
2026                 unsigned int namelen;
2027
2028                 p = strchr(name, ',');
2029                 if (p)
2030                         namelen = p - name;
2031                 else
2032                         namelen = strlen(name);
2033
2034                 for (itr = known_modem_types; *itr != NULL; itr++) {
2035                         unsigned int itrlen = strlen(*itr);
2036                         if ((itrlen == namelen) &&
2037                                 (memcmp(*itr, name, namelen) == 0)) {
2038                                 lst = eina_list_append(lst, *itr);
2039                                 break;
2040                         }
2041                 }
2042                 if (*itr == NULL)
2043                         WRN("Unknown oFono type: %.*s", namelen, name);
2044
2045                 if (p)
2046                         name = p + 1;
2047                 else
2048                         name = NULL;
2049         } while (name);
2050
2051         if (lst)
2052                 DBG("Type parsed: '%s'", spec);
2053         else {
2054                 ERR("Could not parse type: %s", spec);
2055                 return;
2056         }
2057
2058         eina_list_free(modem_types);
2059         modem_types = lst;
2060         modem_selected = NULL;
2061 }
2062
2063 void ofono_modem_type_list(FILE *fp, const char *prefix, const char *suffix)
2064 {
2065         const char **itr;
2066         for (itr = known_modem_types; *itr != NULL; itr++)
2067                 fprintf(fp, "%s%s%s", prefix, *itr, suffix);
2068 }
2069
2070 void ofono_modem_path_wanted_set(const char *path)
2071 {
2072         if (eina_stringshare_replace(&modem_path_wanted, path))
2073                 modem_selected = NULL;
2074 }
2075
2076 Eina_Bool ofono_init(void)
2077 {
2078         tzset();
2079
2080         if (!elm_need_e_dbus()) {
2081                 CRITICAL("Elementary does not support DBus.");
2082                 return EINA_FALSE;
2083         }
2084
2085         bus_conn = e_dbus_bus_get(DBUS_BUS_SYSTEM);
2086         if (!bus_conn) {
2087                 CRITICAL("Could not get DBus System Bus");
2088                 return EINA_FALSE;
2089         }
2090
2091         modems = eina_hash_string_small_new(EINA_FREE_CB(_modem_free));
2092         EINA_SAFETY_ON_NULL_RETURN_VAL(modems, EINA_FALSE);
2093
2094         e_dbus_signal_handler_add(bus_conn, E_DBUS_FDO_BUS, E_DBUS_FDO_PATH,
2095                                         E_DBUS_FDO_INTERFACE,
2096                                         "NameOwnerChanged",
2097                                         _name_owner_changed, NULL);
2098
2099         e_dbus_get_name_owner(bus_conn, bus_name, _ofono_get_name_owner, NULL);
2100
2101         return EINA_TRUE;
2102 }
2103
2104 void ofono_shutdown(void)
2105 {
2106         if (pc_get_modems) {
2107                 dbus_pending_call_cancel(pc_get_modems);
2108                 pc_get_modems = NULL;
2109         }
2110
2111         _ofono_disconnected();
2112         eina_stringshare_replace(&modem_path_wanted, NULL);
2113
2114         eina_hash_free(modems);
2115         modems = NULL;
2116
2117         eina_list_free(modem_types);
2118 }
2119
2120 static OFono_Pending *_ofono_call_volume_property_set(char *property,
2121                                                         int type, void *value,
2122                                                         OFono_Simple_Cb cb,
2123                                                         const void *data)
2124 {
2125         OFono_Pending *p;
2126         OFono_Simple_Cb_Context *ctx = NULL;
2127         DBusMessage *msg;
2128         DBusMessageIter iter, variant;
2129         OFono_Modem *m = _modem_selected_get();
2130         char type_to_send[2] = { type , DBUS_TYPE_INVALID };
2131
2132         EINA_SAFETY_ON_NULL_GOTO(m, error_no_dbus_message);
2133
2134         if (cb) {
2135                 ctx = calloc(1, sizeof(OFono_Simple_Cb_Context));
2136                 EINA_SAFETY_ON_NULL_GOTO(ctx, error_no_dbus_message);
2137                 ctx->cb = cb;
2138                 ctx->data = data;
2139         }
2140
2141         msg = dbus_message_new_method_call(bus_id, m->base.path,
2142                                            OFONO_PREFIX OFONO_CALL_VOL_IFACE,
2143                                            "SetProperty");
2144         if (!msg)
2145                 goto error_no_dbus_message;
2146
2147         if (!dbus_message_append_args(msg, DBUS_TYPE_STRING, &property,
2148                                  DBUS_TYPE_INVALID))
2149                 goto error_message_args;
2150
2151         dbus_message_iter_init_append(msg, &iter);
2152
2153         if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT,
2154                                          type_to_send, &variant))
2155                 goto error_message_args;
2156
2157         if (!dbus_message_iter_append_basic(&variant, type, value) ||
2158                         !dbus_message_iter_close_container(&iter, &variant)) {
2159                 dbus_message_iter_abandon_container(&iter, &variant);
2160                 goto error_message_args;
2161         }
2162
2163         INF("%s.SetProperty(%s)", OFONO_CALL_VOL_IFACE, property);
2164         p = _bus_object_message_send(&m->base, msg, _ofono_simple_reply, ctx);
2165         return p;
2166
2167 error_message_args:
2168         dbus_message_unref(msg);
2169
2170 error_no_dbus_message:
2171         if (cb)
2172                 cb((void *)data, OFONO_ERROR_FAILED);
2173         free(ctx);
2174         return NULL;
2175 }
2176
2177 OFono_Pending *ofono_mute_set(Eina_Bool mute, OFono_Simple_Cb cb,
2178                                 const void *data)
2179 {
2180         dbus_bool_t dbus_mute = !!mute;
2181
2182         return  _ofono_call_volume_property_set("Muted", DBUS_TYPE_BOOLEAN,
2183                                                 &dbus_mute, cb, data);
2184 }
2185
2186 Eina_Bool ofono_mute_get(void)
2187 {
2188         OFono_Modem *m = _modem_selected_get();
2189         EINA_SAFETY_ON_NULL_RETURN_VAL(m, EINA_FALSE);
2190         return m->muted;
2191 }
2192
2193 OFono_Pending *ofono_volume_speaker_set(unsigned char volume,
2194                                         OFono_Simple_Cb cb,
2195                                         const void *data)
2196 {
2197
2198         return _ofono_call_volume_property_set("SpeakerVolume", DBUS_TYPE_BYTE,
2199                                                 &volume, cb, data);
2200 }
2201
2202 unsigned char ofono_volume_speaker_get(void)
2203 {
2204         OFono_Modem *m = _modem_selected_get();
2205         EINA_SAFETY_ON_NULL_RETURN_VAL(m, 0);
2206         return m->speaker_volume;
2207 }
2208
2209 OFono_Pending *ofono_volume_microphone_set(unsigned char volume,
2210                                                 OFono_Simple_Cb cb,
2211                                                 const void *data)
2212 {
2213         return _ofono_call_volume_property_set("MicrophoneVolume",
2214                                                 DBUS_TYPE_BYTE, &volume, cb,
2215                                                 data);
2216 }
2217
2218 unsigned char ofono_volume_microphone_get(void)
2219 {
2220         OFono_Modem *m = _modem_selected_get();
2221         EINA_SAFETY_ON_NULL_RETURN_VAL(m, 0);
2222         return m->microphone_volume;
2223 }
2224
2225 OFono_Pending *ofono_tones_send(const char *tones,
2226                                                 OFono_Simple_Cb cb,
2227                                                 const void *data)
2228 {
2229         OFono_Pending *p;
2230         DBusMessage *msg;
2231         OFono_Simple_Cb_Context *ctx = NULL;
2232         OFono_Modem *m = _modem_selected_get();
2233
2234         EINA_SAFETY_ON_NULL_GOTO(m, error_no_dbus_message);
2235
2236         if (cb) {
2237                 ctx = calloc(1, sizeof(OFono_Simple_Cb_Context));
2238                 EINA_SAFETY_ON_NULL_GOTO(ctx, error_no_dbus_message);
2239                 ctx->cb = cb;
2240                 ctx->data = data;
2241         }
2242
2243         msg = dbus_message_new_method_call(
2244                                 bus_id, m->base.path,
2245                                 OFONO_PREFIX OFONO_VOICE_IFACE,
2246                                 "SendTones");
2247         if (!msg)
2248                 goto error_no_dbus_message;
2249
2250         if (!dbus_message_append_args(msg, DBUS_TYPE_STRING, &tones,
2251                                       DBUS_TYPE_INVALID))
2252                 goto error_message_args;
2253
2254         INF("SendTones(%s)", tones);
2255         p = _bus_object_message_send(&m->base, msg, _ofono_simple_reply, ctx);
2256         return p;
2257
2258 error_message_args:
2259         dbus_message_unref(msg);
2260
2261 error_no_dbus_message:
2262         if (cb)
2263                 cb((void *)data, OFONO_ERROR_FAILED);
2264         free(ctx);
2265         return NULL;
2266 }
2267
2268 OFono_Pending *ofono_multiparty_create(OFono_Simple_Cb cb,
2269                                         const void *data)
2270 {
2271         return _ofono_multiparty("CreateMultiparty", cb, data);
2272 }
2273
2274 OFono_Pending *ofono_multiparty_hangup(OFono_Simple_Cb cb, const void *data)
2275 {
2276         return _ofono_multiparty("HangupMultiparty", cb, data);
2277 }
2278
2279 OFono_Pending *ofono_private_chat(OFono_Call *c, OFono_Simple_Cb cb,
2280                                         const void *data)
2281 {
2282         OFono_Pending *p;
2283         DBusMessage *msg;
2284         OFono_Simple_Cb_Context *ctx = NULL;
2285         OFono_Modem *m = _modem_selected_get();
2286
2287         EINA_SAFETY_ON_NULL_GOTO(m, error_no_message);
2288         EINA_SAFETY_ON_NULL_GOTO(c, error_no_message);
2289
2290         if (cb) {
2291                 ctx = calloc(1, sizeof(OFono_Simple_Cb_Context));
2292                 EINA_SAFETY_ON_NULL_GOTO(ctx, error_no_message);
2293                 ctx->cb = cb;
2294                 ctx->data = data;
2295         }
2296
2297         msg = dbus_message_new_method_call(
2298                                 bus_id, m->base.path,
2299                                 OFONO_PREFIX OFONO_VOICE_IFACE,
2300                                 "PrivateChat");
2301
2302         if (!msg)
2303                 goto error_no_message;
2304
2305         if (!dbus_message_append_args(msg, DBUS_TYPE_OBJECT_PATH,
2306                                         &(c->base.path), DBUS_TYPE_INVALID))
2307                 goto error_message_append;
2308
2309         INF("PrivateChat(%s)", c->base.path);
2310         p = _bus_object_message_send(&m->base, msg, _ofono_simple_reply, ctx);
2311         return p;
2312
2313 error_message_append:
2314         dbus_message_unref(msg);
2315 error_no_message:
2316         if (cb)
2317                 cb((void *)data, OFONO_ERROR_FAILED);
2318         free(ctx);
2319         return NULL;
2320 }
2321
2322 static OFono_Callback_List_Modem_Node * _ofono_callback_modem_node_create(
2323         void (*cb)(void *data),const void *data)
2324 {
2325         OFono_Callback_List_Modem_Node *node_new;
2326
2327         node_new = calloc(1, sizeof(OFono_Callback_List_Modem_Node));
2328         EINA_SAFETY_ON_NULL_RETURN_VAL(node_new, NULL);
2329
2330         node_new->cb_data = data;
2331         node_new->cb = cb;
2332
2333         return node_new;
2334 }
2335
2336 OFono_Callback_List_Modem_Node *
2337 ofono_modem_conected_cb_add(void (*cb)(void *data), const void *data)
2338 {
2339         OFono_Callback_List_Modem_Node *node;
2340
2341         EINA_SAFETY_ON_NULL_RETURN_VAL(cb, NULL);
2342         node = _ofono_callback_modem_node_create(cb, data);
2343         EINA_SAFETY_ON_NULL_RETURN_VAL(node, NULL);
2344
2345         cbs_modem_connected = eina_inlist_append(cbs_modem_connected,
2346                                                         EINA_INLIST_GET(node));
2347
2348         return node;
2349 }
2350
2351 OFono_Callback_List_Modem_Node *
2352 ofono_modem_disconnected_cb_add(void (*cb)(void *data), const void *data)
2353 {
2354         OFono_Callback_List_Modem_Node *node;
2355
2356         EINA_SAFETY_ON_NULL_RETURN_VAL(cb, NULL);
2357         node = _ofono_callback_modem_node_create(cb, data);
2358         EINA_SAFETY_ON_NULL_RETURN_VAL(node, NULL);
2359
2360         cbs_modem_disconnected = eina_inlist_append(cbs_modem_disconnected,
2361                                                         EINA_INLIST_GET(node));
2362
2363         return node;
2364 }
2365
2366 OFono_Callback_List_Modem_Node *
2367 ofono_modem_changed_cb_add(void (*cb)(void *data), const void *data)
2368 {
2369         OFono_Callback_List_Modem_Node *node;
2370
2371         EINA_SAFETY_ON_NULL_RETURN_VAL(cb, NULL);
2372         node = _ofono_callback_modem_node_create(cb, data);
2373         EINA_SAFETY_ON_NULL_RETURN_VAL(node, NULL);
2374
2375         cbs_modem_changed = eina_inlist_append(cbs_modem_changed,
2376                                                 EINA_INLIST_GET(node));
2377
2378         return node;
2379 }
2380
2381 static void _ofono_callback_modem_list_delete(Eina_Inlist **list,
2382                                         OFono_Callback_List_Modem_Node *node)
2383 {
2384         EINA_SAFETY_ON_NULL_RETURN(*list);
2385         *list = eina_inlist_remove(*list, EINA_INLIST_GET(node));
2386         free(node);
2387 }
2388
2389 void ofono_modem_changed_cb_del(OFono_Callback_List_Modem_Node *node)
2390 {
2391         EINA_SAFETY_ON_NULL_RETURN(node);
2392         _ofono_callback_modem_list_delete(&cbs_modem_changed, node);
2393 }
2394
2395 void ofono_modem_disconnected_cb_del(OFono_Callback_List_Modem_Node *node)
2396 {
2397         EINA_SAFETY_ON_NULL_RETURN(node);
2398         _ofono_callback_modem_list_delete(&cbs_modem_disconnected, node);
2399 }
2400
2401 void ofono_modem_connected_cb_del(OFono_Callback_List_Modem_Node *node)
2402 {
2403         EINA_SAFETY_ON_NULL_RETURN(node);
2404         _ofono_callback_modem_list_delete(&cbs_modem_connected, node);
2405 }
2406
2407 static OFono_Callback_List_Call_Node *_ofono_callback_call_node_create(
2408         void (*cb)(void *data, OFono_Call *call),const void *data)
2409 {
2410         OFono_Callback_List_Call_Node *node;
2411
2412         node = calloc(1, sizeof(OFono_Callback_List_Call_Node));
2413         EINA_SAFETY_ON_NULL_RETURN_VAL(node, NULL);
2414
2415         node->cb_data = data;
2416         node->cb = cb;
2417
2418         return node;
2419 }
2420
2421 static OFono_Callback_List_Call_Disconnected_Node *
2422 _ofono_callback_call_disconnected_node_create(
2423         void (*cb)(void *data, OFono_Call *call, const char *reason),
2424         const void *data)
2425 {
2426         OFono_Callback_List_Call_Disconnected_Node *node;
2427
2428         node = calloc(1, sizeof(OFono_Callback_List_Call_Disconnected_Node));
2429         EINA_SAFETY_ON_NULL_RETURN_VAL(node, NULL);
2430
2431         node->cb_data = data;
2432         node->cb = cb;
2433
2434         return node;
2435 }
2436
2437 OFono_Callback_List_Call_Node *ofono_call_added_cb_add(
2438         void (*cb)(void *data,OFono_Call *call), const void *data)
2439 {
2440         OFono_Callback_List_Call_Node *node;
2441
2442         EINA_SAFETY_ON_NULL_RETURN_VAL(cb, NULL);
2443         node = _ofono_callback_call_node_create(cb, data);
2444         EINA_SAFETY_ON_NULL_RETURN_VAL(node, NULL);
2445
2446         cbs_call_added = eina_inlist_append(cbs_call_added,
2447                                                 EINA_INLIST_GET(node));
2448
2449         return node;
2450 }
2451
2452 OFono_Callback_List_Call_Node *ofono_call_removed_cb_add(
2453         void (*cb)(void *data, OFono_Call *call), const void *data)
2454 {
2455         OFono_Callback_List_Call_Node *node;
2456
2457         EINA_SAFETY_ON_NULL_RETURN_VAL(cb, NULL);
2458         node = _ofono_callback_call_node_create(cb, data);
2459         EINA_SAFETY_ON_NULL_RETURN_VAL(node, NULL);
2460
2461         cbs_call_removed = eina_inlist_append(cbs_call_removed,
2462                                                 EINA_INLIST_GET(node));
2463
2464         return node;
2465 }
2466
2467 OFono_Callback_List_Call_Node *ofono_call_changed_cb_add(
2468         void (*cb)(void *data, OFono_Call *call), const void *data)
2469 {
2470         OFono_Callback_List_Call_Node *node;
2471
2472         EINA_SAFETY_ON_NULL_RETURN_VAL(cb, NULL);
2473         node = _ofono_callback_call_node_create(cb, data);
2474         EINA_SAFETY_ON_NULL_RETURN_VAL(node, NULL);
2475
2476         cbs_call_changed = eina_inlist_append(cbs_call_changed,
2477                                                 EINA_INLIST_GET(node));
2478
2479         return node;
2480 }
2481
2482 OFono_Callback_List_Call_Disconnected_Node *ofono_call_disconnected_cb_add(
2483         void (*cb)(void *data, OFono_Call *call, const char *reason),
2484         const void *data)
2485 {
2486         OFono_Callback_List_Call_Disconnected_Node *node;
2487
2488         EINA_SAFETY_ON_NULL_RETURN_VAL(cb, NULL);
2489         node = _ofono_callback_call_disconnected_node_create(cb, data);
2490         EINA_SAFETY_ON_NULL_RETURN_VAL(node, NULL);
2491
2492         cbs_call_disconnected = eina_inlist_append(cbs_call_disconnected,
2493                                                         EINA_INLIST_GET(node));
2494
2495         return node;
2496 }
2497
2498 static void _ofono_callback_call_list_delete(Eina_Inlist **list,
2499                                         OFono_Callback_List_Call_Node *node)
2500 {
2501         EINA_SAFETY_ON_NULL_RETURN(*list);
2502         *list = eina_inlist_remove(*list, EINA_INLIST_GET(node));
2503         free(node);
2504 }
2505
2506 void ofono_call_changed_cb_del(OFono_Callback_List_Call_Node *node)
2507 {
2508         EINA_SAFETY_ON_NULL_RETURN(node);
2509         _ofono_callback_call_list_delete(&cbs_call_changed, node);
2510 }
2511
2512 void ofono_call_disconnected_cb_del(
2513         OFono_Callback_List_Call_Disconnected_Node *node)
2514 {
2515         EINA_SAFETY_ON_NULL_RETURN(node);
2516         EINA_SAFETY_ON_NULL_RETURN(cbs_call_disconnected);
2517         cbs_call_disconnected = eina_inlist_remove(cbs_call_disconnected,
2518                                                         EINA_INLIST_GET(node));
2519         free(node);
2520 }
2521
2522 void ofono_call_added_cb_del(OFono_Callback_List_Call_Node *node)
2523 {
2524         EINA_SAFETY_ON_NULL_RETURN(node);
2525         _ofono_callback_call_list_delete(&cbs_call_added, node);
2526 }
2527
2528 void ofono_call_removed_cb_del(OFono_Callback_List_Call_Node *node)
2529 {
2530         EINA_SAFETY_ON_NULL_RETURN(node);
2531         _ofono_callback_call_list_delete(&cbs_call_removed, node);
2532 }