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