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