Version bump
[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                 sms->destination = ctx->destination;
1517                 sms->message = ctx->message;
1518                 sms->timestamp = time(NULL);
1519                 if (ctx->cb)
1520                         ctx->cb((void *)ctx->data, OFONO_ERROR_NONE, sms);
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         if (!ofono_voice_is_online()) {
1991                 ofono_powered_set(EINA_TRUE, NULL, NULL);
1992                 return;
1993         }
1994 }
1995
1996 static void _modem_added(void *data __UNUSED__, DBusMessage *msg)
1997 {
1998         DBusMessageIter iter, properties;
1999         const char *path;
2000
2001         if (!msg || !dbus_message_iter_init(msg, &iter)) {
2002                 ERR("Could not handle message %p", msg);
2003                 return;
2004         }
2005
2006         dbus_message_iter_get_basic(&iter, &path);
2007
2008         dbus_message_iter_next(&iter);
2009         dbus_message_iter_recurse(&iter, &properties);
2010
2011         _modem_add(path, &properties);
2012 }
2013
2014 static void _modem_removed(void *data __UNUSED__, DBusMessage *msg)
2015 {
2016         DBusError err;
2017         const char *path;
2018
2019         if (!msg) {
2020                 ERR("Could not handle message %p", msg);
2021                 return;
2022         }
2023
2024         dbus_error_init(&err);
2025         if (!dbus_message_get_args(msg, &err, DBUS_TYPE_OBJECT_PATH,
2026                                         &path, NULL)) {
2027                 ERR("Could not get ModemRemoved arguments: %s: %s",
2028                         err.name, err.message);
2029                 dbus_error_free(&err);
2030                 return;
2031         }
2032
2033         _modem_remove(path);
2034 }
2035
2036 static void _modem_property_changed(void *data __UNUSED__, DBusMessage *msg)
2037 {
2038         const char *path;
2039         OFono_Modem *m;
2040         DBusMessageIter iter, value;
2041         const char *key;
2042
2043         if (!msg || !dbus_message_iter_init(msg, &iter)) {
2044                 ERR("Could not handle message %p", msg);
2045                 return;
2046         }
2047
2048         path = dbus_message_get_path(msg);
2049         DBG("path=%s", path);
2050
2051         m = eina_hash_find(modems, path);
2052         if (!m) {
2053                 DBG("Modem is unknown (%s)", path);
2054                 return;
2055         }
2056
2057         dbus_message_iter_get_basic(&iter, &key);
2058         dbus_message_iter_next(&iter);
2059         dbus_message_iter_recurse(&iter, &value);
2060         _modem_property_update(m, key, &value);
2061
2062         _notify_ofono_callbacks_modem_list(cbs_modem_changed);
2063 }
2064
2065 static void _modems_load(void)
2066 {
2067         DBusMessage *msg = dbus_message_new_method_call(
2068                 bus_id, "/", OFONO_PREFIX OFONO_MANAGER_IFACE, "GetModems");
2069
2070         if (pc_get_modems)
2071                 dbus_pending_call_cancel(pc_get_modems);
2072
2073         DBG("Get modems");
2074         pc_get_modems = e_dbus_message_send(
2075                 bus_conn, msg, _ofono_modems_get_reply, -1, NULL);
2076         dbus_message_unref(msg);
2077 }
2078
2079 static void _ofono_connected(const char *id)
2080 {
2081         free(bus_id);
2082         bus_id = strdup(id);
2083
2084         sig_modem_added = e_dbus_signal_handler_add(
2085                 bus_conn, bus_id, "/",
2086                 OFONO_PREFIX OFONO_MANAGER_IFACE,
2087                 "ModemAdded",
2088                 _modem_added, NULL);
2089
2090         sig_modem_removed = e_dbus_signal_handler_add(
2091                 bus_conn, bus_id, "/",
2092                 OFONO_PREFIX OFONO_MANAGER_IFACE,
2093                 "ModemRemoved",
2094                 _modem_removed, NULL);
2095
2096         sig_modem_prop_changed = e_dbus_signal_handler_add(
2097                 bus_conn, bus_id, NULL,
2098                 OFONO_PREFIX OFONO_MODEM_IFACE,
2099                 "PropertyChanged",
2100                 _modem_property_changed, NULL);
2101
2102         _modems_load();
2103
2104         _notify_ofono_callbacks_modem_list(cbs_modem_connected);
2105 }
2106
2107 static void _ofono_disconnected(void)
2108 {
2109         eina_hash_free_buckets(modems);
2110
2111         if (sig_modem_added) {
2112                 e_dbus_signal_handler_del(bus_conn, sig_modem_added);
2113                 sig_modem_added = NULL;
2114         }
2115
2116         if (sig_modem_removed) {
2117                 e_dbus_signal_handler_del(bus_conn, sig_modem_removed);
2118                 sig_modem_removed = NULL;
2119         }
2120
2121         if (sig_modem_prop_changed) {
2122                 e_dbus_signal_handler_del(bus_conn, sig_modem_prop_changed);
2123                 sig_modem_prop_changed = NULL;
2124         }
2125
2126         if (bus_id) {
2127                 _notify_ofono_callbacks_modem_list(cbs_modem_disconnected);
2128                 free(bus_id);
2129                 bus_id = NULL;
2130         }
2131 }
2132
2133 static void _name_owner_changed(void *data __UNUSED__, DBusMessage *msg)
2134 {
2135         DBusError err;
2136         const char *name, *from, *to;
2137
2138         dbus_error_init(&err);
2139         if (!dbus_message_get_args(msg, &err,
2140                                         DBUS_TYPE_STRING, &name,
2141                                         DBUS_TYPE_STRING, &from,
2142                                         DBUS_TYPE_STRING, &to,
2143                                         DBUS_TYPE_INVALID)) {
2144                 ERR("Could not get NameOwnerChanged arguments: %s: %s",
2145                         err.name, err.message);
2146                 dbus_error_free(&err);
2147                 return;
2148         }
2149
2150         if (strcmp(name, bus_name) != 0)
2151                 return;
2152
2153         DBG("NameOwnerChanged %s from=%s to=%s", name, from, to);
2154
2155         if (from[0] == '\0' && to[0] != '\0') {
2156                 INF("oFono appeared as %s", to);
2157                 _ofono_connected(to);
2158         } else if (from[0] != '\0' && to[0] == '\0') {
2159                 INF("oFono disappeared from %s", from);
2160                 _ofono_disconnected();
2161         }
2162 }
2163
2164 static void _ofono_get_name_owner(void *data __UNUSED__, DBusMessage *msg, DBusError *err)
2165 {
2166         DBusMessageIter itr;
2167         const char *id;
2168
2169         if (!msg) {
2170                 if (err)
2171                         ERR("%s: %s", err->name, err->message);
2172                 else
2173                         ERR("No message");
2174                 return;
2175         }
2176
2177         dbus_message_iter_init(msg, &itr);
2178         dbus_message_iter_get_basic(&itr, &id);
2179         if (!id || id[0] == '\0') {
2180                 ERR("No name owner fo %s!", bus_name);
2181                 return;
2182         }
2183
2184         INF("oFono bus id: %s", id);
2185         _ofono_connected(id);
2186 }
2187
2188 OFono_Pending *ofono_modem_change_pin(const char *what, const char *old,
2189                                         const char *new, OFono_Simple_Cb cb,
2190                                         const void *data)
2191 {
2192         OFono_Simple_Cb_Context *ctx = NULL;
2193         OFono_Error err = OFONO_ERROR_OFFLINE;
2194         OFono_Pending *p;
2195         DBusMessage *msg;
2196         OFono_Modem *m = _modem_selected_get();
2197         EINA_SAFETY_ON_NULL_GOTO(m, error);
2198         EINA_SAFETY_ON_NULL_GOTO(what, error);
2199         EINA_SAFETY_ON_NULL_GOTO(old, error);
2200         EINA_SAFETY_ON_NULL_GOTO(new, error);
2201
2202         if ((m->interfaces & OFONO_API_SIM) == 0)
2203                 goto error;
2204         err = OFONO_ERROR_FAILED;
2205
2206         if (cb) {
2207                 ctx = calloc(1, sizeof(OFono_Simple_Cb_Context));
2208                 EINA_SAFETY_ON_NULL_GOTO(ctx, error);
2209                 ctx->cb = cb;
2210                 ctx->data = data;
2211         }
2212
2213         msg = dbus_message_new_method_call(
2214                 bus_id, m->base.path, OFONO_PREFIX OFONO_SIM_IFACE,
2215                 "ChangePin");
2216         if (!msg)
2217                 goto error;
2218
2219         if (!dbus_message_append_args(msg, DBUS_TYPE_STRING, &what,
2220                                         DBUS_TYPE_STRING, &old,
2221                                         DBUS_TYPE_STRING, &new,
2222                                         DBUS_TYPE_INVALID))
2223                 goto error_message;
2224
2225         INF("ChangePin(%s, %s, %s)", what, old, new);
2226         p = _bus_object_message_send(&m->base, msg, _ofono_simple_reply, ctx);
2227         return p;
2228
2229 error_message:
2230         dbus_message_unref(msg);
2231 error:
2232         if (cb)
2233                 cb((void *)data, err);
2234         free(ctx);
2235         return NULL;
2236 }
2237
2238 OFono_Pending *ofono_modem_reset_pin(const char *what, const char *puk,
2239                                         const char *new, OFono_Simple_Cb cb,
2240                                         const void *data)
2241 {
2242         OFono_Simple_Cb_Context *ctx = NULL;
2243         OFono_Error err = OFONO_ERROR_OFFLINE;
2244         OFono_Pending *p;
2245         DBusMessage *msg;
2246         OFono_Modem *m = _modem_selected_get();
2247         EINA_SAFETY_ON_NULL_GOTO(m, error);
2248         EINA_SAFETY_ON_NULL_GOTO(what, error);
2249         EINA_SAFETY_ON_NULL_GOTO(puk, error);
2250         EINA_SAFETY_ON_NULL_GOTO(new, error);
2251
2252         if ((m->interfaces & OFONO_API_SIM) == 0)
2253                 goto error;
2254         err = OFONO_ERROR_FAILED;
2255
2256         if (cb) {
2257                 ctx = calloc(1, sizeof(OFono_Simple_Cb_Context));
2258                 EINA_SAFETY_ON_NULL_GOTO(ctx, error);
2259                 ctx->cb = cb;
2260                 ctx->data = data;
2261         }
2262
2263         msg = dbus_message_new_method_call(
2264                 bus_id, m->base.path, OFONO_PREFIX OFONO_SIM_IFACE, "ResetPin");
2265         if (!msg)
2266                 goto error;
2267
2268         if (!dbus_message_append_args(msg, DBUS_TYPE_STRING, &what,
2269                                         DBUS_TYPE_STRING, &puk,
2270                                         DBUS_TYPE_STRING, &new,
2271                                         DBUS_TYPE_INVALID))
2272                 goto error_message;
2273
2274         INF("ResetPin(%s, %s, %s)", what, puk, new);
2275         p = _bus_object_message_send(&m->base, msg, _ofono_simple_reply, ctx);
2276         return p;
2277
2278 error_message:
2279         dbus_message_unref(msg);
2280 error:
2281         if (cb)
2282                 cb((void *)data, err);
2283         free(ctx);
2284         return NULL;
2285 }
2286
2287 static OFono_Pending *_ofono_modem_property_set(char *property,
2288                                                 int type, void *value,
2289                                                 OFono_Simple_Cb cb,
2290                                                 const void *data)
2291 {
2292         OFono_Pending *p;
2293         OFono_Simple_Cb_Context *ctx = NULL;
2294         DBusMessage *msg;
2295         DBusMessageIter iter, variant;
2296         OFono_Modem *found_path = NULL, *found_hfp = NULL, *m;
2297         Eina_Iterator *itr;
2298
2299         if (modem_selected)
2300                 m = modem_selected;
2301         else {
2302                 itr = eina_hash_iterator_data_new(modems);
2303                 EINA_ITERATOR_FOREACH(itr, m) {
2304                         if (m->ignored)
2305                                 continue;
2306
2307                     if ((modem_path_wanted) && (!found_path)) {
2308                                 DBG("m=%s, wanted=%s", m->base.path, modem_path_wanted);
2309                                 if (m->base.path == modem_path_wanted) {
2310                                         found_path = m;
2311                                         break;
2312                                 }
2313                         }
2314
2315                         if (!found_hfp) {
2316                                 DBG("m=%#x, mask=%#x, previous=%s "
2317                                         "(online=%d, powered=%d)",
2318                                         m->interfaces, modem_api_mask,
2319                                         found_hfp ? found_hfp->base.path : "",
2320                                         found_hfp ? found_hfp->online : 0,
2321                                         found_hfp ? found_hfp->powered : 0);
2322                                         if (strncmp(m->base.path, "/hfp", 4) == 0)
2323                                                 found_hfp = m;
2324                         }
2325                 }
2326                 eina_iterator_free(itr);
2327                 m = found_path ? found_path : found_hfp;
2328         }
2329
2330         if (!m)
2331                 return NULL;
2332
2333         char type_to_send[2] = { type , DBUS_TYPE_INVALID };
2334
2335         EINA_SAFETY_ON_NULL_GOTO(m, error_no_dbus_message);
2336
2337         if (cb) {
2338                 ctx = calloc(1, sizeof(OFono_Simple_Cb_Context));
2339                 EINA_SAFETY_ON_NULL_GOTO(ctx, error_no_dbus_message);
2340                 ctx->cb = cb;
2341                 ctx->data = data;
2342         }
2343
2344         msg = dbus_message_new_method_call(bus_id, m->base.path,
2345                                                                                 OFONO_PREFIX OFONO_MODEM_IFACE,
2346                                                                                 "SetProperty");
2347         if (!msg)
2348                 goto error_no_dbus_message;
2349
2350         if (!dbus_message_append_args(msg, DBUS_TYPE_STRING, &property,
2351                                                                         DBUS_TYPE_INVALID))
2352                 goto error_message_args;
2353
2354         dbus_message_iter_init_append(msg, &iter);
2355
2356         if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT,
2357                                                                                         type_to_send, &variant))
2358                 goto error_message_args;
2359
2360         if (!dbus_message_iter_append_basic(&variant, type, value) ||
2361                         !dbus_message_iter_close_container(&iter, &variant)) {
2362                 dbus_message_iter_abandon_container(&iter, &variant);
2363                 goto error_message_args;
2364         }
2365
2366         INF("%s.SetProperty(%s)", OFONO_MODEM_IFACE, property);
2367         p = _bus_object_message_send(&m->base, msg, _ofono_simple_reply, ctx);
2368         return p;
2369
2370 error_message_args:
2371         dbus_message_unref(msg);
2372
2373 error_no_dbus_message:
2374         if (cb)
2375                 cb((void *)data, OFONO_ERROR_FAILED);
2376         free(ctx);
2377         return NULL;
2378 }
2379
2380 OFono_Pending *ofono_powered_set(Eina_Bool powered, OFono_Simple_Cb cb,
2381                                 const void *data)
2382 {
2383         dbus_bool_t dbus_powered = !!powered;
2384
2385         return  _ofono_modem_property_set("Powered", DBUS_TYPE_BOOLEAN,
2386                 &dbus_powered, cb, data);
2387 }
2388
2389 Eina_Bool ofono_powered_get(void)
2390 {
2391         OFono_Modem *m = _modem_selected_get();
2392         EINA_SAFETY_ON_NULL_RETURN_VAL(m, EINA_FALSE);
2393         return m->powered;
2394 }
2395
2396 static char *_ss_initiate_convert_ussd(const char *type __UNUSED__,
2397                                         DBusMessageIter *itr)
2398 {
2399         const char *ussd_response;
2400
2401         if (dbus_message_iter_get_arg_type(itr) != DBUS_TYPE_STRING) {
2402                 ERR("Invalid type: %c (expected: %c)",
2403                         dbus_message_iter_get_arg_type(itr), DBUS_TYPE_STRING);
2404                 return NULL;
2405         }
2406         dbus_message_iter_get_basic(itr, &ussd_response);
2407         EINA_SAFETY_ON_NULL_RETURN_VAL(ussd_response, NULL);
2408         return strdup(ussd_response);
2409 }
2410
2411 static void _ss_initiate_cb_dict_convert(Eina_Strbuf *buf,
2412                                                 DBusMessageIter *dict)
2413 {
2414         for (; dbus_message_iter_get_arg_type(dict) == DBUS_TYPE_DICT_ENTRY;
2415                         dbus_message_iter_next(dict)) {
2416                 DBusMessageIter e, v;
2417                 const char *key, *value;
2418
2419                 dbus_message_iter_recurse(dict, &e);
2420                 dbus_message_iter_get_basic(&e, &key);
2421
2422                 dbus_message_iter_next(&e);
2423                 dbus_message_iter_recurse(&e, &v);
2424                 dbus_message_iter_get_basic(&v, &value);
2425
2426                 eina_strbuf_append_printf(buf, "&nbsp;&nbsp;&nbsp;%s=%s<br>",
2427                                                 key, value);
2428         }
2429 }
2430
2431 static char *_ss_initiate_convert_call1(const char *type, DBusMessageIter *itr)
2432 {
2433         DBusMessageIter array, dict;
2434         const char *ss_op, *service;
2435         Eina_Strbuf *buf;
2436         char *str;
2437
2438         dbus_message_iter_recurse(itr, &array);
2439
2440         if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_STRING) {
2441                 ERR("Invalid type: %c (expected: %c)",
2442                         dbus_message_iter_get_arg_type(&array),
2443                         DBUS_TYPE_STRING);
2444                 return NULL;
2445         }
2446         dbus_message_iter_get_basic(&array, &ss_op);
2447         EINA_SAFETY_ON_NULL_RETURN_VAL(ss_op, NULL);
2448
2449         if (!dbus_message_iter_next(&array)) {
2450                 ERR("Missing %s service", type);
2451                 return NULL;
2452         }
2453
2454         if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_STRING) {
2455                 ERR("Invalid type: %c (expected: %c)",
2456                         dbus_message_iter_get_arg_type(&array),
2457                         DBUS_TYPE_STRING);
2458                 return NULL;
2459         }
2460         dbus_message_iter_get_basic(&array, &service);
2461         EINA_SAFETY_ON_NULL_RETURN_VAL(service, NULL);
2462
2463         if (!dbus_message_iter_next(&array)) {
2464                 ERR("Missing %s information", type);
2465                 return NULL;
2466         }
2467
2468         buf = eina_strbuf_new();
2469         eina_strbuf_append_printf(buf, "<b>%s %s=%s</b><br><br>",
2470                                         type, ss_op, service);
2471
2472         dbus_message_iter_recurse(&array, &dict);
2473         _ss_initiate_cb_dict_convert(buf, &dict);
2474
2475         str = eina_strbuf_string_steal(buf);
2476         eina_strbuf_free(buf);
2477         return str;
2478 }
2479
2480 static char *_ss_initiate_convert_call_waiting(const char *type,
2481                                                 DBusMessageIter *itr)
2482 {
2483         DBusMessageIter array, dict;
2484         const char *ss_op;
2485         Eina_Strbuf *buf;
2486         char *str;
2487
2488         dbus_message_iter_recurse(itr, &array);
2489
2490         if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_STRING) {
2491                 ERR("Invalid type: %c (expected: %c)",
2492                         dbus_message_iter_get_arg_type(&array),
2493                         DBUS_TYPE_STRING);
2494                 return NULL;
2495         }
2496         dbus_message_iter_get_basic(&array, &ss_op);
2497         EINA_SAFETY_ON_NULL_RETURN_VAL(ss_op, NULL);
2498
2499         if (!dbus_message_iter_next(&array)) {
2500                 ERR("Missing %s information", type);
2501                 return NULL;
2502         }
2503
2504         buf = eina_strbuf_new();
2505         eina_strbuf_append_printf(buf, "<b>%s %s</b><br><br>",
2506                                         type, ss_op);
2507
2508         dbus_message_iter_recurse(&array, &dict);
2509         _ss_initiate_cb_dict_convert(buf, &dict);
2510
2511         str = eina_strbuf_string_steal(buf);
2512         eina_strbuf_free(buf);
2513         return str;
2514 }
2515
2516 static char *_ss_initiate_convert_call2(const char *type,
2517                                                 DBusMessageIter *itr)
2518 {
2519         DBusMessageIter array;
2520         const char *ss_op, *status;
2521         Eina_Strbuf *buf;
2522         char *str;
2523
2524         dbus_message_iter_recurse(itr, &array);
2525
2526         if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_STRING) {
2527                 ERR("Invalid type: %c (expected: %c)",
2528                         dbus_message_iter_get_arg_type(&array),
2529                         DBUS_TYPE_STRING);
2530                 return NULL;
2531         }
2532         dbus_message_iter_get_basic(&array, &ss_op);
2533         EINA_SAFETY_ON_NULL_RETURN_VAL(ss_op, NULL);
2534
2535         if (!dbus_message_iter_next(&array)) {
2536                 ERR("Missing %s status", type);
2537                 return NULL;
2538         }
2539
2540         if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_STRING) {
2541                 ERR("Invalid type: %c (expected: %c)",
2542                         dbus_message_iter_get_arg_type(&array),
2543                         DBUS_TYPE_STRING);
2544                 return NULL;
2545         }
2546         dbus_message_iter_get_basic(&array, &status);
2547         EINA_SAFETY_ON_NULL_RETURN_VAL(status, NULL);
2548
2549         buf = eina_strbuf_new();
2550         eina_strbuf_append_printf(buf, "<b>%s:</b><br><br>%s=%s",
2551                                         type, ss_op, status);
2552
2553         str = eina_strbuf_string_steal(buf);
2554         eina_strbuf_free(buf);
2555         return str;
2556 }
2557
2558 static const struct SS_Initiate_Convert_Map {
2559         const char *type;
2560         size_t typelen;
2561         char *(*convert)(const char *type, DBusMessageIter *itr);
2562 } ss_initiate_convert_map[] = {
2563 #define MAP(type, conv) {type, sizeof(type) - 1, conv}
2564         MAP("USSD", _ss_initiate_convert_ussd),
2565         MAP("CallBarring", _ss_initiate_convert_call1),
2566         MAP("CallForwarding", _ss_initiate_convert_call1),
2567         MAP("CallWaiting", _ss_initiate_convert_call_waiting),
2568         MAP("CallingLinePresentation", _ss_initiate_convert_call2),
2569         MAP("ConnectedLinePresentation", _ss_initiate_convert_call2),
2570         MAP("CallingLineRestriction", _ss_initiate_convert_call2),
2571         MAP("ConnectedLineRestriction", _ss_initiate_convert_call2),
2572 #undef MAP
2573         {NULL, 0, NULL}
2574 };
2575
2576 static char *_ss_initiate_convert(DBusMessage *msg)
2577 {
2578         DBusMessageIter array, variant;
2579         const struct SS_Initiate_Convert_Map *citr;
2580         const char *type = NULL;
2581         size_t typelen;
2582
2583         if (!dbus_message_iter_init(msg, &array))
2584                 goto error;
2585
2586         if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_STRING) {
2587                 ERR("Invalid type for first argument: %c (expected: %c)",
2588                         dbus_message_iter_get_arg_type(&array),
2589                         DBUS_TYPE_STRING);
2590                 goto error;
2591         }
2592         dbus_message_iter_get_basic(&array, &type);
2593         if (!type) {
2594                 ERR("Couldn't get SupplementaryServices.Initiate type");
2595                 goto error;
2596         }
2597         DBG("type: %s", type);
2598
2599         if (!dbus_message_iter_next(&array)) {
2600                 ERR("Couldn't get SupplementaryServices.Initiate payload");
2601                 goto error;
2602         }
2603         dbus_message_iter_recurse(&array, &variant);
2604
2605         typelen = strlen(type);
2606         for (citr = ss_initiate_convert_map; citr->type != NULL; citr++) {
2607                 if ((citr->typelen == typelen) &&
2608                         (memcmp(citr->type, type, typelen) == 0)) {
2609                         return citr->convert(type, &variant);
2610                 }
2611         }
2612         ERR("Could not convert SupplementaryServices.Initiate type %s", type);
2613
2614 error:
2615         return NULL;
2616 }
2617
2618 OFono_Pending *ofono_ss_initiate(const char *command, OFono_String_Cb cb, const void *data)
2619 {
2620         OFono_String_Cb_Context *ctx = NULL;
2621         OFono_Error err = OFONO_ERROR_OFFLINE;
2622         OFono_Pending *p;
2623         DBusMessage *msg;
2624         OFono_Modem *m = _modem_selected_get();
2625         EINA_SAFETY_ON_NULL_GOTO(m, error);
2626         EINA_SAFETY_ON_NULL_GOTO(command, error);
2627
2628         if ((m->interfaces & OFONO_API_SUPPL_SERV) == 0)
2629                 goto error;
2630         err = OFONO_ERROR_FAILED;
2631
2632         ctx = calloc(1, sizeof(OFono_String_Cb_Context));
2633         EINA_SAFETY_ON_NULL_GOTO(ctx, error);
2634         ctx->cb = cb;
2635         ctx->data = data;
2636         ctx->name = OFONO_PREFIX OFONO_SUPPL_SERV_IFACE ".Initiate";
2637         ctx->convert = _ss_initiate_convert;
2638
2639         msg = dbus_message_new_method_call(
2640                 bus_id, m->base.path, OFONO_PREFIX OFONO_SUPPL_SERV_IFACE,
2641                 "Initiate");
2642         if (!msg)
2643                 goto error;
2644
2645         if (!dbus_message_append_args(msg, DBUS_TYPE_STRING, &command,
2646                                         DBUS_TYPE_INVALID))
2647                 goto error_message;
2648
2649         INF("SupplementaryServices.Initiate(%s)", command);
2650         p = _bus_object_message_send(&m->base, msg, _ofono_string_reply, ctx);
2651         return p;
2652
2653 error_message:
2654         dbus_message_unref(msg);
2655 error:
2656         if (cb)
2657                 cb((void *)data, err, NULL);
2658         free(ctx);
2659         return NULL;
2660 }
2661
2662 static char *_ussd_respond_convert(DBusMessage *msg)
2663 {
2664         DBusMessageIter itr;
2665         const char *s;
2666
2667         if (!msg || !dbus_message_iter_init(msg, &itr)) {
2668                 ERR("Could not handle message %p", msg);
2669                 return NULL;
2670         }
2671
2672         if (dbus_message_iter_get_arg_type(&itr) != DBUS_TYPE_STRING) {
2673                 ERR("Invalid type: %c (expected: %c)",
2674                         dbus_message_iter_get_arg_type(&itr), DBUS_TYPE_STRING);
2675                 return NULL;
2676         }
2677         dbus_message_iter_get_basic(&itr, &s);
2678         EINA_SAFETY_ON_NULL_RETURN_VAL(s, NULL);
2679         return strdup(s);
2680 }
2681
2682 OFono_Pending *ofono_ussd_respond(const char *string,
2683                                         OFono_String_Cb cb, const void *data)
2684 {
2685         OFono_String_Cb_Context *ctx = NULL;
2686         OFono_Error err = OFONO_ERROR_OFFLINE;
2687         OFono_Pending *p;
2688         DBusMessage *msg;
2689         OFono_Modem *m = _modem_selected_get();
2690         EINA_SAFETY_ON_NULL_GOTO(m, error);
2691         EINA_SAFETY_ON_NULL_GOTO(string, error);
2692
2693         if ((m->interfaces & OFONO_API_SUPPL_SERV) == 0)
2694                 goto error;
2695         err = OFONO_ERROR_FAILED;
2696
2697         ctx = calloc(1, sizeof(OFono_String_Cb_Context));
2698         EINA_SAFETY_ON_NULL_GOTO(ctx, error);
2699         ctx->cb = cb;
2700         ctx->data = data;
2701         ctx->name = OFONO_PREFIX OFONO_SUPPL_SERV_IFACE ".Initiate";
2702         ctx->convert = _ussd_respond_convert;
2703
2704         msg = dbus_message_new_method_call(
2705                 bus_id, m->base.path, OFONO_PREFIX OFONO_SUPPL_SERV_IFACE,
2706                 "Respond");
2707         if (!msg)
2708                 goto error;
2709
2710         if (!dbus_message_append_args(msg, DBUS_TYPE_STRING, &string,
2711                                         DBUS_TYPE_INVALID))
2712                 goto error_message;
2713
2714         INF("SupplementaryServices.Respond(%s)", string);
2715         p = _bus_object_message_send(&m->base, msg, _ofono_string_reply, ctx);
2716         return p;
2717
2718 error_message:
2719         dbus_message_unref(msg);
2720 error:
2721         if (cb)
2722                 cb((void *)data, err, NULL);
2723         free(ctx);
2724         return NULL;
2725 }
2726
2727 OFono_Pending *ofono_ussd_cancel(OFono_Simple_Cb cb, const void *data)
2728 {
2729         return _ofono_simple_do(OFONO_API_SUPPL_SERV, "Cancel", cb, data);
2730 }
2731
2732 static void _ofono_dial_reply(void *data, DBusMessage *msg, DBusError *err)
2733 {
2734         OFono_Call_Cb_Context *ctx = data;
2735         OFono_Call *c = NULL;
2736         OFono_Error oe = OFONO_ERROR_NONE;
2737
2738         if (!msg) {
2739                 DBG("%s: %s", err->name, err->message);
2740                 oe = _ofono_error_parse(err->name);
2741         } else {
2742                 DBusError e;
2743                 const char *path;
2744                 dbus_error_init(&e);
2745                 if (!dbus_message_get_args(msg, &e, DBUS_TYPE_OBJECT_PATH,
2746                                                 &path, DBUS_TYPE_INVALID)) {
2747                         ERR("Could not get Dial reply: %s: %s",
2748                                 e.name, e.message);
2749                         dbus_error_free(&e);
2750                         oe = OFONO_ERROR_FAILED;
2751                 } else {
2752                         c = eina_hash_find(ctx->modem->calls, path);
2753                         DBG("path=%s, existing call=%p", path, c);
2754                         if (!c) {
2755                                 c = _call_pending_add(ctx->modem, path, ctx);
2756                                 if (c) {
2757                                         /* ctx->cb will be dispatched on
2758                                          * CallAdded signal handler.
2759                                          */
2760                                         return;
2761                                 }
2762                         }
2763
2764                         ERR("Could not find call %s", path);
2765                         oe = OFONO_ERROR_FAILED;
2766                 }
2767         }
2768
2769         if (ctx->cb)
2770                 ctx->cb((void *)ctx->data, oe, c);
2771
2772         free(ctx);
2773 }
2774
2775 OFono_Pending *ofono_dial(const char *number, const char *hide_callerid,
2776                                 OFono_Call_Cb cb, const void *data)
2777 {
2778         OFono_Call_Cb_Context *ctx = NULL;
2779         OFono_Error err = OFONO_ERROR_OFFLINE;
2780         OFono_Pending *p;
2781         DBusMessage *msg;
2782         OFono_Modem *m = _modem_selected_get();
2783         EINA_SAFETY_ON_NULL_GOTO(m, error);
2784
2785
2786         if ((m->interfaces & OFONO_API_VOICE) == 0)
2787                 goto error;
2788         err = OFONO_ERROR_FAILED;
2789
2790         if (!hide_callerid)
2791                 hide_callerid = "";
2792
2793         ctx = calloc(1, sizeof(OFono_Call_Cb_Context));
2794         EINA_SAFETY_ON_NULL_GOTO(ctx, error);
2795         ctx->cb = cb;
2796         ctx->data = data;
2797         ctx->name = OFONO_PREFIX OFONO_VOICE_IFACE ".Dial";
2798         ctx->modem = m;
2799
2800         msg = dbus_message_new_method_call(
2801                 bus_id, m->base.path, OFONO_PREFIX OFONO_VOICE_IFACE, "Dial");
2802         if (!msg)
2803                 goto error;
2804
2805         if (!dbus_message_append_args(msg, DBUS_TYPE_STRING, &number,
2806                                         DBUS_TYPE_STRING, &hide_callerid,
2807                                         DBUS_TYPE_INVALID))
2808                 goto error_message;
2809
2810         INF("Dial(%s, %s)", number, hide_callerid);
2811         p = _bus_object_message_send(&m->base, msg, _ofono_dial_reply, ctx);
2812         return p;
2813
2814 error_message:
2815         dbus_message_unref(msg);
2816 error:
2817         if (cb)
2818                 cb((void *)data, err, NULL);
2819         free(ctx);
2820         return NULL;
2821 }
2822
2823 static OFono_Pending *_ofono_simple_do(OFono_API api, const char *method,
2824                                         OFono_Simple_Cb cb, const void *data)
2825 {
2826         OFono_Simple_Cb_Context *ctx = NULL;
2827         OFono_Error err = OFONO_ERROR_OFFLINE;
2828         OFono_Pending *p;
2829         DBusMessage *msg;
2830         char iface[128] = "";
2831         const struct API_Interface_Map *itr;
2832         OFono_Modem *m = _modem_selected_get();
2833         EINA_SAFETY_ON_NULL_GOTO(m, error);
2834         EINA_SAFETY_ON_NULL_GOTO(method, error);
2835
2836         if ((m->interfaces & api) == 0)
2837                 goto error;
2838         err = OFONO_ERROR_FAILED;
2839
2840         for (itr = api_iface_map; itr->name != NULL; itr++) {
2841                 if (itr->bit == api) {
2842                         snprintf(iface, sizeof(iface), "%s%s",
2843                                         OFONO_PREFIX, itr->name);
2844                         break;
2845                 }
2846         }
2847         if (iface[0] == '\0') {
2848                 ERR("Could not map api %d to interface name!", api);
2849                 goto error;
2850         }
2851
2852         if (cb) {
2853                 ctx = calloc(1, sizeof(OFono_Simple_Cb_Context));
2854                 EINA_SAFETY_ON_NULL_GOTO(ctx, error);
2855                 ctx->cb = cb;
2856                 ctx->data = data;
2857         }
2858
2859         msg = dbus_message_new_method_call(bus_id, m->base.path, iface, method);
2860         if (!msg)
2861                 goto error;
2862
2863         INF("%s.%s()", iface, method);
2864         p = _bus_object_message_send(&m->base, msg, _ofono_simple_reply, ctx);
2865         return p;
2866
2867 error:
2868         if (cb)
2869                 cb((void *)data, err);
2870         free(ctx);
2871         return NULL;
2872 }
2873
2874 OFono_Pending *ofono_transfer(OFono_Simple_Cb cb, const void *data)
2875 {
2876         return _ofono_simple_do(OFONO_API_VOICE, "Transfer", cb, data);
2877 }
2878
2879 OFono_Pending *ofono_swap_calls(OFono_Simple_Cb cb, const void *data)
2880 {
2881         return _ofono_simple_do(OFONO_API_VOICE, "SwapCalls", cb, data);
2882 }
2883
2884 OFono_Pending *ofono_release_and_answer(OFono_Simple_Cb cb, const void *data)
2885 {
2886         return _ofono_simple_do(OFONO_API_VOICE, "ReleaseAndAnswer", cb, data);
2887 }
2888
2889 OFono_Pending *ofono_release_and_swap(OFono_Simple_Cb cb, const void *data)
2890 {
2891         return _ofono_simple_do(OFONO_API_VOICE, "ReleaseAndSwap", cb, data);
2892 }
2893
2894 OFono_Pending *ofono_hold_and_answer(OFono_Simple_Cb cb, const void *data)
2895 {
2896         return _ofono_simple_do(OFONO_API_VOICE, "HoldAndAnswer", cb, data);
2897 }
2898
2899 OFono_Pending *ofono_hangup_all(OFono_Simple_Cb cb, const void *data)
2900 {
2901         return _ofono_simple_do(OFONO_API_VOICE, "HangupAll", cb, data);
2902 }
2903
2904 const char *ofono_modem_serial_get(void)
2905 {
2906         OFono_Modem *m = _modem_selected_get();
2907         EINA_SAFETY_ON_NULL_RETURN_VAL(m, NULL);
2908         return m->serial;
2909 }
2910
2911 void ofono_modem_api_require(const char *spec)
2912 {
2913         unsigned int api_mask = 0;
2914         const char *name = spec;
2915
2916         EINA_SAFETY_ON_NULL_RETURN(spec);
2917
2918         do {
2919                 const struct API_Interface_Map *itr;
2920                 const char *p;
2921                 unsigned int namelen;
2922
2923                 p = strchr(name, ',');
2924                 if (p)
2925                         namelen = p - name;
2926                 else
2927                         namelen = strlen(name);
2928
2929                 for (itr = api_iface_map; itr->name != NULL; itr++) {
2930                         if ((itr->namelen == namelen) &&
2931                                 (memcmp(itr->name, name, namelen) == 0)) {
2932                                 api_mask |= itr->bit;
2933                                 break;
2934                         }
2935                 }
2936                 if (itr->name == NULL)
2937                         WRN("Unknown oFono API: %.*s", namelen, name);
2938
2939                 if (p)
2940                         name = p + 1;
2941                 else
2942                         name = NULL;
2943         } while (name);
2944
2945         if (api_mask)
2946                 DBG("API parsed: '%s' = %#x", spec, api_mask);
2947         else {
2948                 ERR("Could not parse API: %s", spec);
2949                 return;
2950         }
2951
2952         if (modem_api_mask == api_mask)
2953                 return;
2954         modem_api_mask = api_mask;
2955         modem_selected = NULL;
2956 }
2957
2958 void ofono_modem_api_list(FILE *fp, const char *prefix, const char *suffix)
2959 {
2960         const struct API_Interface_Map *itr;
2961         for (itr = api_iface_map; itr->name != NULL; itr++)
2962                 fprintf(fp, "%s%s%s", prefix, itr->name, suffix);
2963 }
2964
2965 void ofono_modem_type_require(const char *spec)
2966 {
2967         Eina_List *lst = NULL;
2968         const char *name = spec;
2969
2970         EINA_SAFETY_ON_NULL_RETURN(spec);
2971
2972         do {
2973                 const char **itr;
2974                 const char *p;
2975                 unsigned int namelen;
2976
2977                 p = strchr(name, ',');
2978                 if (p)
2979                         namelen = p - name;
2980                 else
2981                         namelen = strlen(name);
2982
2983                 for (itr = known_modem_types; *itr != NULL; itr++) {
2984                         unsigned int itrlen = strlen(*itr);
2985                         if ((itrlen == namelen) &&
2986                                 (memcmp(*itr, name, namelen) == 0)) {
2987                                 lst = eina_list_append(lst, *itr);
2988                                 break;
2989                         }
2990                 }
2991                 if (*itr == NULL)
2992                         WRN("Unknown oFono type: %.*s", namelen, name);
2993
2994                 if (p)
2995                         name = p + 1;
2996                 else
2997                         name = NULL;
2998         } while (name);
2999
3000         if (lst)
3001                 DBG("Type parsed: '%s'", spec);
3002         else {
3003                 ERR("Could not parse type: %s", spec);
3004                 return;
3005         }
3006
3007         eina_list_free(modem_types);
3008         modem_types = lst;
3009         modem_selected = NULL;
3010 }
3011
3012 void ofono_modem_type_list(FILE *fp, const char *prefix, const char *suffix)
3013 {
3014         const char **itr;
3015         for (itr = known_modem_types; *itr != NULL; itr++)
3016                 fprintf(fp, "%s%s%s", prefix, *itr, suffix);
3017 }
3018
3019 void ofono_modem_path_wanted_set(const char *path)
3020 {
3021         if (eina_stringshare_replace(&modem_path_wanted, path))
3022                 modem_selected = NULL;
3023 }
3024
3025 unsigned int ofono_modem_api_get(void)
3026 {
3027         OFono_Modem *m = _modem_selected_get();
3028         EINA_SAFETY_ON_NULL_RETURN_VAL(m, 0);
3029         return m->interfaces;
3030 }
3031
3032 Eina_Bool ofono_init(void)
3033 {
3034         tzset();
3035
3036         if (!elm_need_e_dbus()) {
3037                 CRITICAL("Elementary does not support DBus.");
3038                 return EINA_FALSE;
3039         }
3040
3041         bus_conn = e_dbus_bus_get(DBUS_BUS_SYSTEM);
3042         if (!bus_conn) {
3043                 CRITICAL("Could not get DBus System Bus");
3044                 return EINA_FALSE;
3045         }
3046
3047         modems = eina_hash_string_small_new(EINA_FREE_CB(_modem_free));
3048         EINA_SAFETY_ON_NULL_RETURN_VAL(modems, EINA_FALSE);
3049
3050         e_dbus_signal_handler_add(bus_conn, E_DBUS_FDO_BUS, E_DBUS_FDO_PATH,
3051                                         E_DBUS_FDO_INTERFACE,
3052                                         "NameOwnerChanged",
3053                                         _name_owner_changed, NULL);
3054
3055         e_dbus_get_name_owner(bus_conn, bus_name, _ofono_get_name_owner, NULL);
3056
3057         return EINA_TRUE;
3058 }
3059
3060 void ofono_shutdown(void)
3061 {
3062         if (pc_get_modems) {
3063                 dbus_pending_call_cancel(pc_get_modems);
3064                 pc_get_modems = NULL;
3065         }
3066
3067         _ofono_disconnected();
3068         eina_stringshare_replace(&modem_path_wanted, NULL);
3069
3070         eina_hash_free(modems);
3071         modems = NULL;
3072
3073         eina_list_free(modem_types);
3074 }
3075
3076 static OFono_Pending *_ofono_call_volume_property_set(char *property,
3077                                                         int type, void *value,
3078                                                         OFono_Simple_Cb cb,
3079                                                         const void *data)
3080 {
3081         OFono_Pending *p;
3082         OFono_Simple_Cb_Context *ctx = NULL;
3083         DBusMessage *msg;
3084         DBusMessageIter iter, variant;
3085         OFono_Modem *m = _modem_selected_get();
3086         char type_to_send[2] = { type , DBUS_TYPE_INVALID };
3087
3088         EINA_SAFETY_ON_NULL_GOTO(m, error_no_dbus_message);
3089
3090         if (cb) {
3091                 ctx = calloc(1, sizeof(OFono_Simple_Cb_Context));
3092                 EINA_SAFETY_ON_NULL_GOTO(ctx, error_no_dbus_message);
3093                 ctx->cb = cb;
3094                 ctx->data = data;
3095         }
3096
3097         msg = dbus_message_new_method_call(bus_id, m->base.path,
3098                                            OFONO_PREFIX OFONO_CALL_VOL_IFACE,
3099                                            "SetProperty");
3100         if (!msg)
3101                 goto error_no_dbus_message;
3102
3103         if (!dbus_message_append_args(msg, DBUS_TYPE_STRING, &property,
3104                                  DBUS_TYPE_INVALID))
3105                 goto error_message_args;
3106
3107         dbus_message_iter_init_append(msg, &iter);
3108
3109         if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT,
3110                                          type_to_send, &variant))
3111                 goto error_message_args;
3112
3113         if (!dbus_message_iter_append_basic(&variant, type, value) ||
3114                         !dbus_message_iter_close_container(&iter, &variant)) {
3115                 dbus_message_iter_abandon_container(&iter, &variant);
3116                 goto error_message_args;
3117         }
3118
3119         INF("%s.SetProperty(%s)", OFONO_CALL_VOL_IFACE, property);
3120         p = _bus_object_message_send(&m->base, msg, _ofono_simple_reply, ctx);
3121         return p;
3122
3123 error_message_args:
3124         dbus_message_unref(msg);
3125
3126 error_no_dbus_message:
3127         if (cb)
3128                 cb((void *)data, OFONO_ERROR_FAILED);
3129         free(ctx);
3130         return NULL;
3131 }
3132
3133 OFono_Pending *ofono_mute_set(Eina_Bool mute, OFono_Simple_Cb cb,
3134                                 const void *data)
3135 {
3136         dbus_bool_t dbus_mute = !!mute;
3137
3138         return  _ofono_call_volume_property_set("Muted", DBUS_TYPE_BOOLEAN,
3139                                                 &dbus_mute, cb, data);
3140 }
3141
3142 Eina_Bool ofono_mute_get(void)
3143 {
3144         OFono_Modem *m = _modem_selected_get();
3145         EINA_SAFETY_ON_NULL_RETURN_VAL(m, EINA_FALSE);
3146         return m->muted;
3147 }
3148
3149 OFono_Pending *ofono_volume_speaker_set(unsigned char volume,
3150                                         OFono_Simple_Cb cb,
3151                                         const void *data)
3152 {
3153
3154         return _ofono_call_volume_property_set("SpeakerVolume", DBUS_TYPE_BYTE,
3155                                                 &volume, cb, data);
3156 }
3157
3158 unsigned char ofono_volume_speaker_get(void)
3159 {
3160         OFono_Modem *m = _modem_selected_get();
3161         EINA_SAFETY_ON_NULL_RETURN_VAL(m, 0);
3162         return m->speaker_volume;
3163 }
3164
3165 OFono_Pending *ofono_volume_microphone_set(unsigned char volume,
3166                                                 OFono_Simple_Cb cb,
3167                                                 const void *data)
3168 {
3169         return _ofono_call_volume_property_set("MicrophoneVolume",
3170                                                 DBUS_TYPE_BYTE, &volume, cb,
3171                                                 data);
3172 }
3173
3174 unsigned char ofono_volume_microphone_get(void)
3175 {
3176         OFono_Modem *m = _modem_selected_get();
3177         EINA_SAFETY_ON_NULL_RETURN_VAL(m, 0);
3178         return m->microphone_volume;
3179 }
3180
3181 Eina_Bool ofono_voicemail_waiting_get(void)
3182 {
3183         OFono_Modem *m = _modem_selected_get();
3184         EINA_SAFETY_ON_NULL_RETURN_VAL(m, EINA_FALSE);
3185         return m->voicemail_waiting;
3186 }
3187
3188 unsigned char ofono_voicemail_count_get(void)
3189 {
3190         OFono_Modem *m = _modem_selected_get();
3191         EINA_SAFETY_ON_NULL_RETURN_VAL(m, 0);
3192         return m->voicemail_count;
3193 }
3194
3195 const char *ofono_voicemail_number_get(void)
3196 {
3197         OFono_Modem *m = _modem_selected_get();
3198         EINA_SAFETY_ON_NULL_RETURN_VAL(m, NULL);
3199         return m->voicemail_number;
3200 }
3201
3202 OFono_USSD_State ofono_ussd_state_get(void)
3203 {
3204         OFono_Modem *m = _modem_selected_get();
3205         EINA_SAFETY_ON_NULL_RETURN_VAL(m, OFONO_USSD_STATE_IDLE);
3206         return m->ussd_state;
3207 }
3208
3209 const char *ofono_service_center_address_get(void)
3210 {
3211         OFono_Modem *m = _modem_selected_get();
3212         EINA_SAFETY_ON_NULL_RETURN_VAL(m, NULL);
3213         return m->serv_center_addr;
3214 }
3215
3216 Eina_Bool ofono_use_delivery_reports_get(void)
3217 {
3218         OFono_Modem *m = _modem_selected_get();
3219         EINA_SAFETY_ON_NULL_RETURN_VAL(m, EINA_FALSE);
3220         return m->use_delivery_reports;
3221 }
3222
3223 const char *ofono_message_bearer_get(void)
3224 {
3225         OFono_Modem *m = _modem_selected_get();
3226         EINA_SAFETY_ON_NULL_RETURN_VAL(m, NULL);
3227         return m->msg_bearer;
3228 }
3229
3230 const char *ofono_message_alphabet_get(void)
3231 {
3232         OFono_Modem *m = _modem_selected_get();
3233         EINA_SAFETY_ON_NULL_RETURN_VAL(m, NULL);
3234         return m->msg_alphabet;
3235 }
3236
3237 OFono_Sent_SMS_State ofono_sent_sms_state_get(const OFono_Sent_SMS *sms)
3238 {
3239         EINA_SAFETY_ON_NULL_RETURN_VAL(sms, OFONO_SENT_SMS_STATE_FAILED);
3240         return sms->state;
3241 }
3242
3243 const char *ofono_sent_sms_destination_get(const OFono_Sent_SMS *sms)
3244 {
3245         EINA_SAFETY_ON_NULL_RETURN_VAL(sms, NULL);
3246         return sms->destination;
3247 }
3248
3249 const char *ofono_sent_sms_message_get(const OFono_Sent_SMS *sms)
3250 {
3251         EINA_SAFETY_ON_NULL_RETURN_VAL(sms, NULL);
3252         return sms->message;
3253 }
3254
3255 time_t ofono_sent_sms_timestamp_get(const OFono_Sent_SMS *sms)
3256 {
3257         EINA_SAFETY_ON_NULL_RETURN_VAL(sms, 0);
3258         return sms->timestamp;
3259 }
3260
3261 OFono_Pending *ofono_sent_sms_cancel(OFono_Sent_SMS *sms, OFono_Simple_Cb cb,
3262                                         const void *data)
3263 {
3264         OFono_Simple_Cb_Context *ctx = NULL;
3265         OFono_Error err = OFONO_ERROR_OFFLINE;
3266         OFono_Pending *p;
3267         DBusMessage *msg;
3268
3269         if (cb) {
3270                 ctx = calloc(1, sizeof(OFono_Simple_Cb_Context));
3271                 EINA_SAFETY_ON_NULL_GOTO(ctx, error);
3272                 ctx->cb = cb;
3273                 ctx->data = data;
3274         }
3275
3276         msg = dbus_message_new_method_call(bus_id, sms->base.path,
3277                                                 OFONO_PREFIX "Message",
3278                                                 "Cancel");
3279         if (!msg)
3280                 goto error;
3281
3282         INF("Cancel(%s)", sms->base.path);
3283         p = _bus_object_message_send(&sms->base, msg, _ofono_simple_reply, ctx);
3284         return p;
3285
3286 error:
3287         if (cb)
3288                 cb((void *)data, err);
3289         free(ctx);
3290         return NULL;
3291 }
3292
3293 static void _ofono_sms_send_reply(void *data, DBusMessage *msg, DBusError *err)
3294 {
3295         OFono_Sent_SMS_Cb_Context *ctx = data;
3296         OFono_Sent_SMS *sms = NULL;
3297         OFono_Error oe = OFONO_ERROR_NONE;
3298
3299         if (!msg) {
3300                 DBG("%s: %s", err->name, err->message);
3301                 oe = _ofono_error_parse(err->name);
3302         } else {
3303                 DBusError e;
3304                 const char *path;
3305                 dbus_error_init(&e);
3306                 if (!dbus_message_get_args(msg, &e, DBUS_TYPE_OBJECT_PATH,
3307                                                 &path, DBUS_TYPE_INVALID)) {
3308                         ERR("Could not get SendMessage reply: %s: %s",
3309                                 e.name, e.message);
3310                         dbus_error_free(&e);
3311                         oe = OFONO_ERROR_FAILED;
3312                 } else {
3313                         sms = eina_hash_find(ctx->modem->sent_sms, path);
3314                         DBG("path=%s, existing sms=%p", path, sms);
3315                         if (!sms) {
3316                                 sms = _sent_sms_pending_add(ctx->modem, path,
3317                                                                 ctx);
3318                                 if (sms) {
3319                                         /* ctx->cb will be dispatched on
3320                                          * MessageAdded signal handler.
3321                                          */
3322                                         return;
3323                                 }
3324                         }
3325
3326                         ERR("Could not find sms %s", path);
3327                         oe = OFONO_ERROR_FAILED;
3328                 }
3329         }
3330
3331         if (ctx->cb)
3332                 ctx->cb((void *)ctx->data, oe, sms);
3333
3334         eina_stringshare_del(ctx->destination);
3335         eina_stringshare_del(ctx->message);
3336         free(ctx);
3337 }
3338
3339 OFono_Pending *ofono_sms_send(const char *number, const char *message,
3340                                 OFono_Sent_SMS_Cb cb, const void *data)
3341 {
3342         OFono_Sent_SMS_Cb_Context *ctx = NULL;
3343         OFono_Error err = OFONO_ERROR_OFFLINE;
3344         OFono_Pending *p;
3345         DBusMessage *msg;
3346         OFono_Modem *m = _modem_selected_get();
3347         EINA_SAFETY_ON_NULL_GOTO(m, error);
3348         EINA_SAFETY_ON_NULL_GOTO(number, error);
3349         EINA_SAFETY_ON_NULL_GOTO(message, error);
3350
3351         if ((m->interfaces & OFONO_API_MSG) == 0)
3352                 goto error;
3353         err = OFONO_ERROR_FAILED;
3354
3355         ctx = calloc(1, sizeof(OFono_Sent_SMS_Cb_Context));
3356         EINA_SAFETY_ON_NULL_GOTO(ctx, error);
3357         ctx->cb = cb;
3358         ctx->data = data;
3359         ctx->modem = m;
3360         ctx->destination = eina_stringshare_add(number);
3361         ctx->message = eina_stringshare_add(message);
3362
3363         msg = dbus_message_new_method_call(
3364                 bus_id, m->base.path, OFONO_PREFIX OFONO_MSG_IFACE,
3365                 "SendMessage");
3366         if (!msg)
3367                 goto error_setup;
3368
3369         if (!dbus_message_append_args(msg, DBUS_TYPE_STRING, &number,
3370                                         DBUS_TYPE_STRING, &message,
3371                                         DBUS_TYPE_INVALID))
3372                 goto error_message;
3373
3374         INF("SendMessage(%s, %s)", number, message);
3375         p = _bus_object_message_send(&m->base, msg, _ofono_sms_send_reply, ctx);
3376         return p;
3377
3378 error_message:
3379         dbus_message_unref(msg);
3380 error_setup:
3381         eina_stringshare_del(ctx->destination);
3382         eina_stringshare_del(ctx->message);
3383 error:
3384         if (cb)
3385                 cb((void *)data, err, NULL);
3386         free(ctx);
3387         return NULL;
3388 }
3389
3390 OFono_Pending *ofono_tones_send(const char *tones,
3391                                                 OFono_Simple_Cb cb,
3392                                                 const void *data)
3393 {
3394         OFono_Pending *p;
3395         DBusMessage *msg;
3396         OFono_Simple_Cb_Context *ctx = NULL;
3397         OFono_Modem *m = _modem_selected_get();
3398
3399         EINA_SAFETY_ON_NULL_GOTO(m, error_no_dbus_message);
3400
3401         if (cb) {
3402                 ctx = calloc(1, sizeof(OFono_Simple_Cb_Context));
3403                 EINA_SAFETY_ON_NULL_GOTO(ctx, error_no_dbus_message);
3404                 ctx->cb = cb;
3405                 ctx->data = data;
3406         }
3407
3408         msg = dbus_message_new_method_call(
3409                                 bus_id, m->base.path,
3410                                 OFONO_PREFIX OFONO_VOICE_IFACE,
3411                                 "SendTones");
3412         if (!msg)
3413                 goto error_no_dbus_message;
3414
3415         if (!dbus_message_append_args(msg, DBUS_TYPE_STRING, &tones,
3416                                       DBUS_TYPE_INVALID))
3417                 goto error_message_args;
3418
3419         INF("SendTones(%s)", tones);
3420         p = _bus_object_message_send(&m->base, msg, _ofono_simple_reply, ctx);
3421         return p;
3422
3423 error_message_args:
3424         dbus_message_unref(msg);
3425
3426 error_no_dbus_message:
3427         if (cb)
3428                 cb((void *)data, OFONO_ERROR_FAILED);
3429         free(ctx);
3430         return NULL;
3431 }
3432
3433 OFono_Pending *ofono_multiparty_create(OFono_Simple_Cb cb,
3434                                         const void *data)
3435 {
3436         return _ofono_multiparty("CreateMultiparty", cb, data);
3437 }
3438
3439 OFono_Pending *ofono_multiparty_hangup(OFono_Simple_Cb cb, const void *data)
3440 {
3441         return _ofono_multiparty("HangupMultiparty", cb, data);
3442 }
3443
3444 OFono_Pending *ofono_private_chat(OFono_Call *c, OFono_Simple_Cb cb,
3445                                         const void *data)
3446 {
3447         OFono_Pending *p;
3448         DBusMessage *msg;
3449         OFono_Simple_Cb_Context *ctx = NULL;
3450         OFono_Modem *m = _modem_selected_get();
3451
3452         EINA_SAFETY_ON_NULL_GOTO(m, error_no_message);
3453         EINA_SAFETY_ON_NULL_GOTO(c, error_no_message);
3454
3455         if (cb) {
3456                 ctx = calloc(1, sizeof(OFono_Simple_Cb_Context));
3457                 EINA_SAFETY_ON_NULL_GOTO(ctx, error_no_message);
3458                 ctx->cb = cb;
3459                 ctx->data = data;
3460         }
3461
3462         msg = dbus_message_new_method_call(
3463                                 bus_id, m->base.path,
3464                                 OFONO_PREFIX OFONO_VOICE_IFACE,
3465                                 "PrivateChat");
3466
3467         if (!msg)
3468                 goto error_no_message;
3469
3470         if (!dbus_message_append_args(msg, DBUS_TYPE_OBJECT_PATH,
3471                                         &(c->base.path), DBUS_TYPE_INVALID))
3472                 goto error_message_append;
3473
3474         INF("PrivateChat(%s)", c->base.path);
3475         p = _bus_object_message_send(&m->base, msg, _ofono_simple_reply, ctx);
3476         return p;
3477
3478 error_message_append:
3479         dbus_message_unref(msg);
3480 error_no_message:
3481         if (cb)
3482                 cb((void *)data, OFONO_ERROR_FAILED);
3483         free(ctx);
3484         return NULL;
3485 }
3486
3487 static OFono_Callback_List_Modem_Node * _ofono_callback_modem_node_create(
3488         void (*cb)(void *data),const void *data)
3489 {
3490         OFono_Callback_List_Modem_Node *node_new;
3491
3492         node_new = calloc(1, sizeof(OFono_Callback_List_Modem_Node));
3493         EINA_SAFETY_ON_NULL_RETURN_VAL(node_new, NULL);
3494
3495         node_new->cb_data = data;
3496         node_new->cb = cb;
3497
3498         return node_new;
3499 }
3500
3501 OFono_Callback_List_Modem_Node *
3502 ofono_modem_conected_cb_add(void (*cb)(void *data), const void *data)
3503 {
3504         OFono_Callback_List_Modem_Node *node;
3505
3506         EINA_SAFETY_ON_NULL_RETURN_VAL(cb, NULL);
3507         node = _ofono_callback_modem_node_create(cb, data);
3508         EINA_SAFETY_ON_NULL_RETURN_VAL(node, NULL);
3509
3510         cbs_modem_connected = eina_inlist_append(cbs_modem_connected,
3511                                                         EINA_INLIST_GET(node));
3512
3513         return node;
3514 }
3515
3516 OFono_Callback_List_Modem_Node *
3517 ofono_modem_disconnected_cb_add(void (*cb)(void *data), const void *data)
3518 {
3519         OFono_Callback_List_Modem_Node *node;
3520
3521         EINA_SAFETY_ON_NULL_RETURN_VAL(cb, NULL);
3522         node = _ofono_callback_modem_node_create(cb, data);
3523         EINA_SAFETY_ON_NULL_RETURN_VAL(node, NULL);
3524
3525         cbs_modem_disconnected = eina_inlist_append(cbs_modem_disconnected,
3526                                                         EINA_INLIST_GET(node));
3527
3528         return node;
3529 }
3530
3531 OFono_Callback_List_Modem_Node *
3532 ofono_modem_changed_cb_add(void (*cb)(void *data), const void *data)
3533 {
3534         OFono_Callback_List_Modem_Node *node;
3535
3536         EINA_SAFETY_ON_NULL_RETURN_VAL(cb, NULL);
3537         node = _ofono_callback_modem_node_create(cb, data);
3538         EINA_SAFETY_ON_NULL_RETURN_VAL(node, NULL);
3539
3540         cbs_modem_changed = eina_inlist_append(cbs_modem_changed,
3541                                                 EINA_INLIST_GET(node));
3542
3543         return node;
3544 }
3545
3546 static void _ofono_callback_modem_list_delete(Eina_Inlist **list,
3547                                         OFono_Callback_List_Modem_Node *node)
3548 {
3549         EINA_SAFETY_ON_NULL_RETURN(*list);
3550         *list = eina_inlist_remove(*list, EINA_INLIST_GET(node));
3551         free(node);
3552 }
3553
3554 void ofono_modem_changed_cb_del(OFono_Callback_List_Modem_Node *node)
3555 {
3556         EINA_SAFETY_ON_NULL_RETURN(node);
3557         _ofono_callback_modem_list_delete(&cbs_modem_changed, node);
3558 }
3559
3560 void ofono_modem_disconnected_cb_del(OFono_Callback_List_Modem_Node *node)
3561 {
3562         EINA_SAFETY_ON_NULL_RETURN(node);
3563         _ofono_callback_modem_list_delete(&cbs_modem_disconnected, node);
3564 }
3565
3566 void ofono_modem_connected_cb_del(OFono_Callback_List_Modem_Node *node)
3567 {
3568         EINA_SAFETY_ON_NULL_RETURN(node);
3569         _ofono_callback_modem_list_delete(&cbs_modem_connected, node);
3570 }
3571
3572 static OFono_Callback_List_Call_Node *_ofono_callback_call_node_create(
3573         void (*cb)(void *data, OFono_Call *call),const void *data)
3574 {
3575         OFono_Callback_List_Call_Node *node;
3576
3577         node = calloc(1, sizeof(OFono_Callback_List_Call_Node));
3578         EINA_SAFETY_ON_NULL_RETURN_VAL(node, NULL);
3579
3580         node->cb_data = data;
3581         node->cb = cb;
3582
3583         return node;
3584 }
3585
3586 static OFono_Callback_List_Call_Disconnected_Node *
3587 _ofono_callback_call_disconnected_node_create(
3588         void (*cb)(void *data, OFono_Call *call, const char *reason),
3589         const void *data)
3590 {
3591         OFono_Callback_List_Call_Disconnected_Node *node;
3592
3593         node = calloc(1, sizeof(OFono_Callback_List_Call_Disconnected_Node));
3594         EINA_SAFETY_ON_NULL_RETURN_VAL(node, NULL);
3595
3596         node->cb_data = data;
3597         node->cb = cb;
3598
3599         return node;
3600 }
3601
3602 static OFono_Callback_List_USSD_Notify_Node *
3603 _ofono_callback_ussd_notify_node_create(
3604         void (*cb)(void *data, Eina_Bool needs_reply, const char *msg),
3605         const void *data)
3606 {
3607         OFono_Callback_List_USSD_Notify_Node *node;
3608
3609         node = calloc(1, sizeof(OFono_Callback_List_USSD_Notify_Node));
3610         EINA_SAFETY_ON_NULL_RETURN_VAL(node, NULL);
3611
3612         node->cb_data = data;
3613         node->cb = cb;
3614
3615         return node;
3616 }
3617
3618 OFono_Callback_List_Call_Node *ofono_call_added_cb_add(
3619         void (*cb)(void *data,OFono_Call *call), const void *data)
3620 {
3621         OFono_Callback_List_Call_Node *node;
3622
3623         EINA_SAFETY_ON_NULL_RETURN_VAL(cb, NULL);
3624         node = _ofono_callback_call_node_create(cb, data);
3625         EINA_SAFETY_ON_NULL_RETURN_VAL(node, NULL);
3626
3627         cbs_call_added = eina_inlist_append(cbs_call_added,
3628                                                 EINA_INLIST_GET(node));
3629
3630         return node;
3631 }
3632
3633 OFono_Callback_List_Call_Node *ofono_call_removed_cb_add(
3634         void (*cb)(void *data, OFono_Call *call), const void *data)
3635 {
3636         OFono_Callback_List_Call_Node *node;
3637
3638         EINA_SAFETY_ON_NULL_RETURN_VAL(cb, NULL);
3639         node = _ofono_callback_call_node_create(cb, data);
3640         EINA_SAFETY_ON_NULL_RETURN_VAL(node, NULL);
3641
3642         cbs_call_removed = eina_inlist_append(cbs_call_removed,
3643                                                 EINA_INLIST_GET(node));
3644
3645         return node;
3646 }
3647
3648 OFono_Callback_List_Call_Node *ofono_call_changed_cb_add(
3649         void (*cb)(void *data, OFono_Call *call), const void *data)
3650 {
3651         OFono_Callback_List_Call_Node *node;
3652
3653         EINA_SAFETY_ON_NULL_RETURN_VAL(cb, NULL);
3654         node = _ofono_callback_call_node_create(cb, data);
3655         EINA_SAFETY_ON_NULL_RETURN_VAL(node, NULL);
3656
3657         cbs_call_changed = eina_inlist_append(cbs_call_changed,
3658                                                 EINA_INLIST_GET(node));
3659
3660         return node;
3661 }
3662
3663 OFono_Callback_List_Call_Disconnected_Node *ofono_call_disconnected_cb_add(
3664         void (*cb)(void *data, OFono_Call *call, const char *reason),
3665         const void *data)
3666 {
3667         OFono_Callback_List_Call_Disconnected_Node *node;
3668
3669         EINA_SAFETY_ON_NULL_RETURN_VAL(cb, NULL);
3670         node = _ofono_callback_call_disconnected_node_create(cb, data);
3671         EINA_SAFETY_ON_NULL_RETURN_VAL(node, NULL);
3672
3673         cbs_call_disconnected = eina_inlist_append(cbs_call_disconnected,
3674                                                         EINA_INLIST_GET(node));
3675
3676         return node;
3677 }
3678
3679 OFono_Callback_List_USSD_Notify_Node *ofono_ussd_notify_cb_add(
3680         void (*cb)(void *data, Eina_Bool needs_reply, const char *msg),
3681         const void *data)
3682 {
3683         OFono_Callback_List_USSD_Notify_Node *node;
3684
3685         EINA_SAFETY_ON_NULL_RETURN_VAL(cb, NULL);
3686         node = _ofono_callback_ussd_notify_node_create(cb, data);
3687         EINA_SAFETY_ON_NULL_RETURN_VAL(node, NULL);
3688
3689         cbs_ussd_notify = eina_inlist_append(cbs_ussd_notify,
3690                                                 EINA_INLIST_GET(node));
3691
3692         return node;
3693 }
3694
3695 static void _ofono_callback_call_list_delete(Eina_Inlist **list,
3696                                         OFono_Callback_List_Call_Node *node)
3697 {
3698         EINA_SAFETY_ON_NULL_RETURN(*list);
3699         *list = eina_inlist_remove(*list, EINA_INLIST_GET(node));
3700         free(node);
3701 }
3702
3703 void ofono_call_changed_cb_del(OFono_Callback_List_Call_Node *node)
3704 {
3705         EINA_SAFETY_ON_NULL_RETURN(node);
3706         _ofono_callback_call_list_delete(&cbs_call_changed, node);
3707 }
3708
3709 void ofono_call_disconnected_cb_del(
3710         OFono_Callback_List_Call_Disconnected_Node *node)
3711 {
3712         EINA_SAFETY_ON_NULL_RETURN(node);
3713         EINA_SAFETY_ON_NULL_RETURN(cbs_call_disconnected);
3714         cbs_call_disconnected = eina_inlist_remove(cbs_call_disconnected,
3715                                                         EINA_INLIST_GET(node));
3716         free(node);
3717 }
3718
3719 void ofono_ussd_notify_cb_del(OFono_Callback_List_USSD_Notify_Node *node)
3720 {
3721         EINA_SAFETY_ON_NULL_RETURN(node);
3722         EINA_SAFETY_ON_NULL_RETURN(cbs_ussd_notify);
3723         cbs_ussd_notify = eina_inlist_remove(cbs_ussd_notify,
3724                                                 EINA_INLIST_GET(node));
3725         free(node);
3726 }
3727
3728 void ofono_call_added_cb_del(OFono_Callback_List_Call_Node *node)
3729 {
3730         EINA_SAFETY_ON_NULL_RETURN(node);
3731         _ofono_callback_call_list_delete(&cbs_call_added, node);
3732 }
3733
3734 void ofono_call_removed_cb_del(OFono_Callback_List_Call_Node *node)
3735 {
3736         EINA_SAFETY_ON_NULL_RETURN(node);
3737         _ofono_callback_call_list_delete(&cbs_call_removed, node);
3738 }
3739
3740 OFono_Callback_List_Sent_SMS_Node *
3741 ofono_sent_sms_changed_cb_add(OFono_Sent_SMS_Cb cb, const void *data)
3742 {
3743         OFono_Callback_List_Sent_SMS_Node *node;
3744
3745         EINA_SAFETY_ON_NULL_RETURN_VAL(cb, NULL);
3746         node = calloc(1, sizeof(OFono_Callback_List_Sent_SMS_Node));
3747         EINA_SAFETY_ON_NULL_RETURN_VAL(node, NULL);
3748         node->cb = cb;
3749         node->cb_data = data;
3750
3751         cbs_sent_sms_changed = eina_inlist_append(cbs_sent_sms_changed,
3752                                                         EINA_INLIST_GET(node));
3753
3754         return node;
3755 }
3756
3757 void ofono_sent_sms_changed_cb_del(OFono_Callback_List_Sent_SMS_Node *node)
3758 {
3759         EINA_SAFETY_ON_NULL_RETURN(node);
3760         cbs_sent_sms_changed = eina_inlist_remove(cbs_sent_sms_changed,
3761                                                         EINA_INLIST_GET(node));
3762         free(node);
3763 }
3764
3765 OFono_Callback_List_Incoming_SMS_Node *
3766 ofono_incoming_sms_cb_add(OFono_Incoming_SMS_Cb cb, const void *data)
3767 {
3768         OFono_Callback_List_Incoming_SMS_Node *node;
3769
3770         EINA_SAFETY_ON_NULL_RETURN_VAL(cb, NULL);
3771         node = calloc(1, sizeof(OFono_Callback_List_Incoming_SMS_Node));
3772         EINA_SAFETY_ON_NULL_RETURN_VAL(node, NULL);
3773         node->cb = cb;
3774         node->cb_data = data;
3775
3776         cbs_incoming_sms = eina_inlist_append(cbs_incoming_sms,
3777                                                 EINA_INLIST_GET(node));
3778
3779         return node;
3780 }
3781
3782 void ofono_incoming_sms_cb_del(OFono_Callback_List_Incoming_SMS_Node *node)
3783 {
3784         EINA_SAFETY_ON_NULL_RETURN(node);
3785         cbs_incoming_sms = eina_inlist_remove(cbs_incoming_sms,
3786                                                 EINA_INLIST_GET(node));
3787         free(node);
3788 }
3789
3790 Eina_Bool ofono_voice_is_online(void)
3791 {
3792         OFono_Modem *m = _modem_selected_get();
3793
3794         /* The modem is expected to be NULL here, because maybe
3795          * OFono isn't up yet.
3796          */
3797         if (!m)
3798                 return EINA_FALSE;
3799
3800         if (m->interfaces & OFONO_API_VOICE)
3801                 return EINA_TRUE;
3802
3803         return EINA_FALSE;
3804 }