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