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