4 #include <Elementary.h>
11 typedef struct _OFono_Modem OFono_Modem;
12 typedef struct _OFono_Bus_Object OFono_Bus_Object;
14 static const char bus_name[] = "org.ofono";
16 static const char *known_modem_types[] = {"hfp", "sap", "hardware", NULL};
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;
30 static void _ofono_call_volume_properties_get(OFono_Modem *m);
32 struct _OFono_Callback_List_Modem_Node
35 void (*cb)(void *data);
39 struct _OFono_Callback_List_Call_Node
42 void (*cb)(void *data, OFono_Call *call);
46 struct _OFono_Callback_List_Call_Disconnected_Node
49 void (*cb)(void *data, OFono_Call *call, const char *reason);
53 static Eina_Inlist *cbs_modem_changed = NULL;
54 static Eina_Inlist *cbs_modem_connected = NULL;
55 static Eina_Inlist *cbs_modem_disconnected = NULL;
57 static Eina_Inlist *cbs_call_changed = NULL;
58 static Eina_Inlist *cbs_call_added = NULL;
59 static Eina_Inlist *cbs_call_disconnected = NULL;
60 static Eina_Inlist *cbs_call_removed = NULL;
62 #define OFONO_SERVICE "org.ofono"
64 #define OFONO_PREFIX OFONO_SERVICE "."
65 #define OFONO_MODEM_IFACE "Modem"
66 #define OFONO_MANAGER_IFACE "Manager"
67 #define OFONO_SIM_IFACE "SimManager"
68 #define OFONO_NETREG_IFACE "NetworkRegistration"
69 #define OFONO_VOICE_IFACE "VoiceCallManager"
70 #define OFONO_MSG_IFACE "MessageManager"
71 #define OFONO_MSG_WAITING_IFACE "MessageWaiting"
72 #define OFONO_SMART_MSG_IFACE "SmartMessaging"
73 #define OFONO_STK_IFACE "SimToolkit"
75 #define OFONO_CALL_FW_IFACE "CallForwarding"
76 #define OFONO_CALL_VOL_IFACE "CallVolume"
77 #define OFONO_CALL_METER_IFACE "CallMeter"
78 #define OFONO_CALL_SET_IFACE "CallSettings"
79 #define OFONO_CALL_BAR_IFACE "CallBarring"
80 #define OFONO_SUPPL_SERV_IFACE "SupplementaryServices"
81 #define OFONO_TXT_TEL_IFACE "TextTelephony"
82 #define OFONO_CELL_BROAD_IFACE "CellBroadcast"
83 #define OFONO_CONNMAN_IFACE "ConnectionManager"
84 #define OFONO_PUSH_NOTIF_IFACE "PushNotification"
85 #define OFONO_PHONEBOOK_IFACE "Phonebook"
86 #define OFONO_ASN_IFACE "AssistedSatelliteNavigation"
88 static const struct API_Interface_Map {
93 #define MAP(bit, name) {bit, name, sizeof(name) - 1}
94 MAP(OFONO_API_SIM, OFONO_SIM_IFACE),
95 MAP(OFONO_API_NETREG, OFONO_NETREG_IFACE),
96 MAP(OFONO_API_VOICE, OFONO_VOICE_IFACE),
97 MAP(OFONO_API_MSG, OFONO_MSG_IFACE),
98 MAP(OFONO_API_MSG_WAITING, OFONO_MSG_WAITING_IFACE),
99 MAP(OFONO_API_SMART_MSG, OFONO_SMART_MSG_IFACE),
100 MAP(OFONO_API_STK, OFONO_STK_IFACE),
101 MAP(OFONO_API_CALL_FW, OFONO_CALL_FW_IFACE),
102 MAP(OFONO_API_CALL_VOL, OFONO_CALL_VOL_IFACE),
103 MAP(OFONO_API_CALL_METER, OFONO_CALL_METER_IFACE),
104 MAP(OFONO_API_CALL_SET, OFONO_CALL_SET_IFACE),
105 MAP(OFONO_API_CALL_BAR, OFONO_CALL_BAR_IFACE),
106 MAP(OFONO_API_SUPPL_SERV, OFONO_SUPPL_SERV_IFACE),
107 MAP(OFONO_API_TXT_TEL, OFONO_TXT_TEL_IFACE),
108 MAP(OFONO_API_CELL_BROAD, OFONO_CELL_BROAD_IFACE),
109 MAP(OFONO_API_CONNMAN, OFONO_CONNMAN_IFACE),
110 MAP(OFONO_API_PUSH_NOTIF, OFONO_PUSH_NOTIF_IFACE),
111 MAP(OFONO_API_PHONEBOOK, OFONO_PHONEBOOK_IFACE),
112 MAP(OFONO_API_ASN, OFONO_ASN_IFACE),
117 static Eina_Bool _dbus_bool_get(DBusMessageIter *itr)
120 dbus_message_iter_get_basic(itr, &val);
124 static const struct Error_Map {
129 #define MAP(id, name) {id, name, sizeof(name) - 1}
130 MAP(OFONO_ERROR_FAILED, "Failed"),
131 MAP(OFONO_ERROR_DOES_NOT_EXIST, "DoesNotExist"),
132 MAP(OFONO_ERROR_IN_PROGRESS, "InProgress"),
133 MAP(OFONO_ERROR_IN_USE, "InUse"),
134 MAP(OFONO_ERROR_INVALID_ARGS, "InvalidArguments"),
135 MAP(OFONO_ERROR_INVALID_FORMAT, "InvalidFormat"),
136 MAP(OFONO_ERROR_ACCESS_DENIED, "AccessDenied"),
137 MAP(OFONO_ERROR_ATTACH_IN_PROGRESS, "AttachInProgress"),
138 MAP(OFONO_ERROR_INCORRECT_PASSWORD, "IncorrectPassword"),
139 MAP(OFONO_ERROR_NOT_ACTIVE, "NotActive"),
140 MAP(OFONO_ERROR_NOT_ALLOWED, "NotAllowed"),
141 MAP(OFONO_ERROR_NOT_ATTACHED, "NotAttached"),
142 MAP(OFONO_ERROR_NOT_AVAILABLE, "NotAvailable"),
143 MAP(OFONO_ERROR_NOT_FOUND, "NotFound"),
144 MAP(OFONO_ERROR_NOT_IMPLEMENTED, "NotImplemented"),
145 MAP(OFONO_ERROR_NOT_RECOGNIZED, "NotRecognized"),
146 MAP(OFONO_ERROR_NOT_REGISTERED, "NotRegistered"),
147 MAP(OFONO_ERROR_NOT_SUPPORTED, "NotSupported"),
148 MAP(OFONO_ERROR_SIM_NOT_READY, "SimNotReady"),
149 MAP(OFONO_ERROR_STK, "SimToolkit"),
150 MAP(OFONO_ERROR_TIMEDOUT, "Timedout"),
155 static OFono_Error _ofono_error_parse(const char *name)
157 size_t namelen, prefixlen = sizeof(OFONO_PREFIX) - 1;
158 const struct Error_Map *itr;
160 /* whenever interfaces are not there due modem being offline */
161 if (strcmp(name, "org.freedesktop.DBus.Error.UnknownMethod") == 0)
162 return OFONO_ERROR_OFFLINE;
164 if (strncmp(name, OFONO_PREFIX, prefixlen) != 0)
165 return OFONO_ERROR_FAILED;
168 namelen = strlen(name);
169 for (itr = error_map; itr->name != NULL; itr++)
170 if ((itr->namelen == namelen) &&
171 (memcmp(name, itr->name, namelen) == 0))
174 return OFONO_ERROR_FAILED;
177 typedef struct _OFono_Simple_Cb_Context
181 } OFono_Simple_Cb_Context;
183 static void _ofono_simple_reply(void *data, DBusMessage *msg __UNUSED__,
186 OFono_Simple_Cb_Context *ctx = data;
187 OFono_Error e = OFONO_ERROR_NONE;
189 if (dbus_error_is_set(err)) {
190 DBG("%s: %s", err->name, err->message);
191 e = _ofono_error_parse(err->name);
195 ctx->cb((void *)ctx->data, e);
200 typedef struct _OFono_String_Cb_Context
205 char *(*convert)(DBusMessage *msg);
206 } OFono_String_Cb_Context;
208 static void _ofono_string_reply(void *data, DBusMessage *msg, DBusError *err)
210 OFono_String_Cb_Context *ctx = data;
211 OFono_Error e = OFONO_ERROR_NONE;
214 if (dbus_error_is_set(err)) {
215 DBG("%s: %s", err->name, err->message);
216 e = _ofono_error_parse(err->name);
218 str = ctx->convert(msg);
220 e = OFONO_ERROR_NOT_SUPPORTED;
224 ctx->cb((void *)ctx->data, e, str);
226 DBG("%s %s", ctx->name, str);
232 struct _OFono_Pending
235 DBusPendingCall *pending;
236 E_DBus_Method_Return_Cb cb;
241 struct _OFono_Bus_Object
244 Eina_Inlist *dbus_pending; /* of OFono_Pending */
245 Eina_List *dbus_signals; /* of E_DBus_Signal_Handler */
248 static void _notify_ofono_callbacks_call_list(Eina_Inlist *list,
251 OFono_Callback_List_Call_Node *node;
253 EINA_INLIST_FOREACH(list, node)
254 node->cb((void *) node->cb_data, call);
257 static void _notify_ofono_callbacks_call_disconnected_list(Eina_Inlist *list,
261 OFono_Callback_List_Call_Disconnected_Node *node;
263 EINA_INLIST_FOREACH(list, node)
264 node->cb((void *) node->cb_data, call, reason);
267 static void _bus_object_free(OFono_Bus_Object *o)
269 E_DBus_Signal_Handler *sh;
271 eina_stringshare_del(o->path);
273 while (o->dbus_pending) {
274 ofono_pending_cancel(
275 EINA_INLIST_CONTAINER_GET(o->dbus_pending,
279 EINA_LIST_FREE(o->dbus_signals, sh)
280 e_dbus_signal_handler_del(bus_conn, sh);
285 static void _bus_object_message_send_reply(void *data, DBusMessage *reply,
288 OFono_Pending *p = data;
289 OFono_Bus_Object *o = p->owner;
292 p->cb(p->data, reply, err);
294 o->dbus_pending = eina_inlist_remove(o->dbus_pending,
299 static OFono_Pending *_bus_object_message_send(OFono_Bus_Object *o,
301 E_DBus_Method_Return_Cb cb,
305 EINA_SAFETY_ON_NULL_GOTO(o, error);
306 EINA_SAFETY_ON_NULL_GOTO(msg, error);
308 p = calloc(1, sizeof(OFono_Pending));
309 EINA_SAFETY_ON_NULL_GOTO(p, error);
315 p->pending = e_dbus_message_send(
316 bus_conn, msg, _bus_object_message_send_reply, -1, p);
317 EINA_SAFETY_ON_NULL_GOTO(p->pending, error_send);
319 o->dbus_pending = eina_inlist_append(o->dbus_pending,
321 dbus_message_unref(msg);
329 dbus_error_init(&err);
330 dbus_set_error(&err, "Failed", "call setup failed.");
331 cb(data, NULL, &err);
333 dbus_message_unref(msg);
337 void ofono_pending_cancel(OFono_Pending *p)
341 EINA_SAFETY_ON_NULL_RETURN(p);
344 o->dbus_pending = eina_inlist_remove(o->dbus_pending,
350 dbus_error_init(&err);
351 dbus_set_error(&err, "Canceled",
352 "Pending method call was canceled.");
353 p->cb(p->data, NULL, &err);
355 dbus_pending_call_cancel(p->pending);
359 static void _bus_object_signal_listen(OFono_Bus_Object *o, const char *iface,
360 const char *name, E_DBus_Signal_Cb cb,
363 E_DBus_Signal_Handler *sh = e_dbus_signal_handler_add(
364 bus_conn, bus_id, o->path, iface, name, cb, data);
365 EINA_SAFETY_ON_NULL_RETURN(sh);
367 o->dbus_signals = eina_list_append(o->dbus_signals, sh);
372 OFono_Bus_Object base;
374 const char *incoming_line;
377 time_t full_start_time;
378 OFono_Call_State state;
379 Eina_Bool multiparty : 1;
380 Eina_Bool emergency : 1;
385 OFono_Bus_Object base;
389 unsigned int interfaces;
390 unsigned char strength;
391 unsigned char data_strength;
392 unsigned char speaker_volume;
393 unsigned char microphone_volume;
394 Eina_Bool ignored : 1;
395 Eina_Bool powered : 1;
396 Eina_Bool online : 1;
397 Eina_Bool roaming : 1;
401 static OFono_Call *_call_new(const char *path)
403 OFono_Call *c = calloc(1, sizeof(OFono_Call));
404 EINA_SAFETY_ON_NULL_RETURN_VAL(c, NULL);
406 c->base.path = eina_stringshare_add(path);
407 EINA_SAFETY_ON_NULL_GOTO(c->base.path, error_path);
409 c->start_time = -1.0;
418 static void _call_free(OFono_Call *c)
420 DBG("c=%p %s", c, c->base.path);
422 _notify_ofono_callbacks_call_list(cbs_call_removed, c);
424 eina_stringshare_del(c->line_id);
425 eina_stringshare_del(c->incoming_line);
426 eina_stringshare_del(c->name);
428 _bus_object_free(&c->base);
431 static OFono_Call_State _call_state_parse(const char *str)
433 if (strcmp(str, "active") == 0)
434 return OFONO_CALL_STATE_ACTIVE;
435 else if (strcmp(str, "held") == 0)
436 return OFONO_CALL_STATE_HELD;
437 else if (strcmp(str, "dialing") == 0)
438 return OFONO_CALL_STATE_DIALING;
439 else if (strcmp(str, "alerting") == 0)
440 return OFONO_CALL_STATE_ALERTING;
441 else if (strcmp(str, "incoming") == 0)
442 return OFONO_CALL_STATE_INCOMING;
443 else if (strcmp(str, "waiting") == 0)
444 return OFONO_CALL_STATE_WAITING;
445 else if (strcmp(str, "disconnected") == 0)
446 return OFONO_CALL_STATE_DISCONNECTED;
448 ERR("unknown call state: %s", str);
449 return OFONO_CALL_STATE_DISCONNECTED;
452 static time_t _ofono_time_parse(const char *str)
457 memset(&tm, 0, sizeof(tm));
459 strptime(str, "%Y-%m-%dT%H:%M:%S%z", &tm);
460 zonediff = tm.tm_gmtoff; /* mktime resets it */
462 return mktime(&tm) - zonediff - timezone;
465 static void _call_property_update(OFono_Call *c, const char *key,
466 DBusMessageIter *value)
468 if (strcmp(key, "LineIdentification") == 0) {
470 dbus_message_iter_get_basic(value, &str);
471 DBG("%s LineIdentification %s", c->base.path, str);
472 eina_stringshare_replace(&c->line_id, str);
473 } else if (strcmp(key, "IncomingLine") == 0) {
475 dbus_message_iter_get_basic(value, &str);
476 DBG("%s IncomingLine %s", c->base.path, str);
477 eina_stringshare_replace(&c->incoming_line, str);
478 } else if (strcmp(key, "State") == 0) {
480 OFono_Call_State state;
481 dbus_message_iter_get_basic(value, &str);
482 state = _call_state_parse(str);
483 DBG("%s State %s (%d)", c->base.path, str, state);
485 if (state == OFONO_CALL_STATE_ACTIVE) {
486 if (c->start_time < 0.0)
487 c->start_time = ecore_loop_time_get();
488 if (c->full_start_time == 0)
489 c->full_start_time = time(NULL);
491 } else if (strcmp(key, "Name") == 0) {
493 dbus_message_iter_get_basic(value, &str);
494 DBG("%s Name %s", c->base.path, str);
495 eina_stringshare_replace(&c->name, str);
496 } else if (strcmp(key, "Multiparty") == 0) {
498 dbus_message_iter_get_basic(value, &v);
499 DBG("%s Multiparty %d", c->base.path, v);
501 } else if (strcmp(key, "Emergency") == 0) {
503 dbus_message_iter_get_basic(value, &v);
504 DBG("%s Emergency %d", c->base.path, v);
506 } else if (strcmp(key, "StartTime") == 0) {
507 const char *ts = NULL;
510 dbus_message_iter_get_basic(value, &ts);
512 st = _ofono_time_parse(ts);
514 lt = ecore_loop_time_get();
515 c->start_time = st - ut + lt;
516 c->full_start_time = st;
517 DBG("%s StartTime %f (%s)", c->base.path, c->start_time, ts);
519 DBG("%s %s (unused property)", c->base.path, key);
522 static void _call_property_changed(void *data, DBusMessage *msg)
524 OFono_Call *c = data;
525 DBusMessageIter iter, value;
528 if (!msg || !dbus_message_iter_init(msg, &iter)) {
529 ERR("Could not handle message %p", msg);
533 DBG("path=%s", c->base.path);
535 dbus_message_iter_get_basic(&iter, &key);
536 dbus_message_iter_next(&iter);
537 dbus_message_iter_recurse(&iter, &value);
538 _call_property_update(c, key, &value);
540 _notify_ofono_callbacks_call_list(cbs_call_changed, c);
543 static void _call_disconnect_reason(void *data, DBusMessage *msg)
545 OFono_Call *c = data;
554 DBG("path=%s", c->base.path);
556 dbus_error_init(&err);
557 if (!dbus_message_get_args(msg, &err, DBUS_TYPE_STRING, &reason,
558 DBUS_TYPE_INVALID)) {
559 ERR("Could not get DisconnectReason arguments: %s: %s",
560 err.name, err.message);
561 dbus_error_free(&err);
565 _notify_ofono_callbacks_call_disconnected_list(cbs_call_disconnected,
569 static void _call_add(OFono_Modem *m, const char *path, DBusMessageIter *prop)
573 DBG("path=%s", path);
575 c = eina_hash_find(m->calls, path);
577 DBG("Call already exists %p (%s)", c, path);
578 goto update_properties;
582 EINA_SAFETY_ON_NULL_RETURN(c);
583 eina_hash_add(m->calls, c->base.path, c);
585 _bus_object_signal_listen(&c->base,
586 OFONO_PREFIX "VoiceCall",
588 _call_disconnect_reason, c);
589 _bus_object_signal_listen(&c->base,
590 OFONO_PREFIX "VoiceCall",
592 _call_property_changed, c);
594 _notify_ofono_callbacks_call_list(cbs_call_added, c);
599 for (; dbus_message_iter_get_arg_type(prop) == DBUS_TYPE_DICT_ENTRY;
600 dbus_message_iter_next(prop)) {
601 DBusMessageIter entry, value;
604 dbus_message_iter_recurse(prop, &entry);
605 dbus_message_iter_get_basic(&entry, &key);
607 dbus_message_iter_next(&entry);
608 dbus_message_iter_recurse(&entry, &value);
610 _call_property_update(c, key, &value);
613 _notify_ofono_callbacks_call_list(cbs_call_changed, c);
616 static void _call_remove(OFono_Modem *m, const char *path)
618 DBG("path=%s", path);
619 eina_hash_del_by_key(m->calls, path);
622 static void _call_added(void *data, DBusMessage *msg)
624 OFono_Modem *m = data;
625 DBusMessageIter iter, properties;
628 if (!msg || !dbus_message_iter_init(msg, &iter)) {
629 ERR("Could not handle message %p", msg);
633 dbus_message_iter_get_basic(&iter, &path);
635 dbus_message_iter_next(&iter);
636 dbus_message_iter_recurse(&iter, &properties);
638 _call_add(m, path, &properties);
641 static void _call_removed(void *data, DBusMessage *msg)
643 OFono_Modem *m = data;
648 ERR("Could not handle message %p", msg);
652 dbus_error_init(&err);
653 if (!dbus_message_get_args(msg, &err, DBUS_TYPE_OBJECT_PATH,
655 ERR("Could not get CallRemoved arguments: %s: %s",
656 err.name, err.message);
657 dbus_error_free(&err);
661 _call_remove(m, path);
664 static OFono_Modem *_modem_selected_get(void)
666 OFono_Modem *found_path = NULL, *found_api = NULL, *m;
667 unsigned int online = 0, powered = 0;
671 return modem_selected;
673 itr = eina_hash_iterator_data_new(modems);
674 EINA_ITERATOR_FOREACH(itr, m) {
683 if ((modem_path_wanted) && (!found_path)) {
684 DBG("m=%s, wanted=%s", m->base.path, modem_path_wanted);
685 if (m->base.path == modem_path_wanted) {
692 DBG("m=%#x, mask=%#x", m->interfaces, modem_api_mask);
693 if ((m->interfaces & modem_api_mask) == modem_api_mask)
697 eina_iterator_free(itr);
699 INF("found_path=%s, found_api=%s, wanted_path=%s, api_mask=%#x",
700 found_path ? found_path->base.path : "",
701 found_api ? found_api->base.path: "",
702 modem_path_wanted ? modem_path_wanted : "",
706 ERR("No modems powered! Run connman or test/enable-modem");
708 WRN("No modems online! Run connman or test/online-modem");
710 modem_selected = found_path ? found_path : found_api;
711 return modem_selected;
714 static OFono_Pending *_ofono_multiparty(const char *method,
715 OFono_Simple_Cb cb, const void *data)
720 OFono_Simple_Cb_Context *ctx = NULL;
721 OFono_Modem *m = _modem_selected_get();
723 EINA_SAFETY_ON_NULL_GOTO(m, error_no_message);
726 ctx = calloc(1, sizeof(OFono_Simple_Cb_Context));
727 EINA_SAFETY_ON_NULL_GOTO(ctx, error_no_message);
732 msg = dbus_message_new_method_call(
733 bus_id, m->base.path,
734 OFONO_PREFIX OFONO_VOICE_IFACE,
738 goto error_no_message;
740 if (!dbus_message_append_args(msg, DBUS_TYPE_INVALID))
741 goto error_message_append;
744 p = _bus_object_message_send(&m->base, msg, _ofono_simple_reply, ctx);
748 error_message_append:
749 dbus_message_unref(msg);
752 cb((void *)data, OFONO_ERROR_FAILED);
757 OFono_Pending *ofono_call_hangup(OFono_Call *c, OFono_Simple_Cb cb,
760 OFono_Simple_Cb_Context *ctx = NULL;
764 EINA_SAFETY_ON_NULL_RETURN_VAL(c, NULL);
767 ctx = calloc(1, sizeof(OFono_Simple_Cb_Context));
768 EINA_SAFETY_ON_NULL_GOTO(ctx, error);
773 msg = dbus_message_new_method_call(
774 bus_id, c->base.path, OFONO_PREFIX "VoiceCall", "Hangup");
778 INF("Hangup(%s)", c->base.path);
779 p = _bus_object_message_send(&c->base, msg, _ofono_simple_reply, ctx);
784 cb((void *)data, OFONO_ERROR_FAILED);
789 OFono_Pending *ofono_call_answer(OFono_Call *c, OFono_Simple_Cb cb,
792 OFono_Simple_Cb_Context *ctx = NULL;
796 EINA_SAFETY_ON_NULL_RETURN_VAL(c, NULL);
799 ctx = calloc(1, sizeof(OFono_Simple_Cb_Context));
800 EINA_SAFETY_ON_NULL_GOTO(ctx, error);
805 msg = dbus_message_new_method_call(
806 bus_id, c->base.path, OFONO_PREFIX "VoiceCall", "Answer");
810 INF("Answer(%s)", c->base.path);
811 p = _bus_object_message_send(&c->base, msg, _ofono_simple_reply, ctx);
816 cb((void *)data, OFONO_ERROR_FAILED);
821 OFono_Call_State ofono_call_state_get(const OFono_Call *c)
823 EINA_SAFETY_ON_NULL_RETURN_VAL(c, OFONO_CALL_STATE_DISCONNECTED);
827 const char *ofono_call_name_get(const OFono_Call *c)
829 EINA_SAFETY_ON_NULL_RETURN_VAL(c, NULL);
833 const char *ofono_call_line_id_get(const OFono_Call *c)
835 EINA_SAFETY_ON_NULL_RETURN_VAL(c, NULL);
839 Eina_Bool ofono_call_multiparty_get(const OFono_Call *c)
841 EINA_SAFETY_ON_NULL_RETURN_VAL(c, EINA_FALSE);
842 return c->multiparty;
845 double ofono_call_start_time_get(const OFono_Call *c)
847 EINA_SAFETY_ON_NULL_RETURN_VAL(c, -1.0);
848 return c->start_time;
851 time_t ofono_call_full_start_time_get(const OFono_Call *c)
853 EINA_SAFETY_ON_NULL_RETURN_VAL(c, 0);
854 return c->full_start_time;
857 static void _ofono_calls_get_reply(void *data, DBusMessage *msg,
860 OFono_Modem *m = data;
861 DBusMessageIter array, dict;
865 ERR("%s: %s", err->name, err->message);
871 eina_hash_free_buckets(m->calls);
873 if (!dbus_message_iter_init(msg, &array)) {
874 ERR("Could not get calls");
878 dbus_message_iter_recurse(&array, &dict);
879 for (; dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_STRUCT;
880 dbus_message_iter_next(&dict)) {
881 DBusMessageIter value, properties;
884 dbus_message_iter_recurse(&dict, &value);
885 dbus_message_iter_get_basic(&value, &path);
887 dbus_message_iter_next(&value);
888 dbus_message_iter_recurse(&value, &properties);
890 _call_add(m, path, &properties);
894 static void _modem_calls_load(OFono_Modem *m)
896 DBusMessage *msg = dbus_message_new_method_call(
897 bus_id, m->base.path, OFONO_PREFIX OFONO_VOICE_IFACE,
900 DBG("Get calls of %s", m->base.path);
901 _bus_object_message_send(&m->base, msg, _ofono_calls_get_reply, m);
904 static OFono_Modem *_modem_new(const char *path)
906 OFono_Modem *m = calloc(1, sizeof(OFono_Modem));
907 EINA_SAFETY_ON_NULL_RETURN_VAL(m, NULL);
909 m->base.path = eina_stringshare_add(path);
910 EINA_SAFETY_ON_NULL_GOTO(m->base.path, error_path);
912 m->calls = eina_hash_string_small_new(EINA_FREE_CB(_call_free));
913 EINA_SAFETY_ON_NULL_GOTO(m->calls, error_calls);
918 eina_stringshare_del(m->base.path);
924 static void _modem_free(OFono_Modem *m)
926 DBG("m=%p %s", m, m->base.path);
928 if (modem_selected == m)
929 modem_selected = NULL;
931 eina_stringshare_del(m->name);
932 eina_stringshare_del(m->serial);
934 eina_hash_free(m->calls);
936 _bus_object_free(&m->base);
940 static void _call_volume_property_update(OFono_Modem *m, const char *prop_name,
941 DBusMessageIter *iter)
944 if (strcmp(prop_name, "Muted") == 0) {
945 m->muted = _dbus_bool_get(iter);
946 DBG("%s Muted %d", m->base.path, m->muted);
947 } else if (strcmp(prop_name, "SpeakerVolume") == 0) {
948 dbus_message_iter_get_basic(iter, &m->speaker_volume);
949 DBG("%s Speaker Volume %hhu", m->base.path, m->speaker_volume);
950 } else if (strcmp(prop_name, "MicrophoneVolume") == 0) {
951 dbus_message_iter_get_basic(iter, &m->microphone_volume);
952 DBG("%s Microphone Volume %hhu", m->base.path, m->speaker_volume);
956 static void _notify_ofono_callbacks_modem_list(Eina_Inlist *list)
958 OFono_Callback_List_Modem_Node *node;
960 EINA_INLIST_FOREACH(list, node)
961 node->cb((void *) node->cb_data);
964 static void _call_volume_property_changed(void *data, DBusMessage *msg)
966 OFono_Modem *m = data;
967 DBusMessageIter iter, variant_iter;
968 const char *prop_name;
970 if (!msg || !dbus_message_iter_init(msg, &iter)) {
971 ERR("Could not handle message %p", msg);
975 dbus_message_iter_get_basic(&iter, &prop_name);
976 dbus_message_iter_next(&iter);
977 dbus_message_iter_recurse(&iter, &variant_iter);
978 _call_volume_property_update(m, prop_name, &variant_iter);
980 _notify_ofono_callbacks_modem_list(cbs_modem_changed);
983 static unsigned int _modem_interfaces_extract(DBusMessageIter *array)
985 DBusMessageIter entry;
986 unsigned int interfaces = 0;
988 dbus_message_iter_recurse(array, &entry);
989 for (; dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_STRING;
990 dbus_message_iter_next(&entry)) {
991 const struct API_Interface_Map *itr;
995 dbus_message_iter_get_basic(&entry, &name);
997 if (strncmp(name, OFONO_PREFIX, strlen(OFONO_PREFIX)) != 0)
1000 name += strlen(OFONO_PREFIX);
1001 namelen = strlen(name);
1003 DBG("interface: %s", name);
1004 for (itr = api_iface_map; itr->name != NULL; itr++) {
1005 if ((itr->namelen == namelen) &&
1006 (memcmp(itr->name, name, namelen) == 0)) {
1007 interfaces |= itr->bit;
1011 if (itr->name == NULL)
1012 WRN("ignored %s", name);
1018 static void _modem_update_interfaces(OFono_Modem *m, unsigned int ifaces)
1021 if (((m->interfaces & OFONO_API_CALL_VOL) == 0) &&
1022 (ifaces & OFONO_API_CALL_VOL) == OFONO_API_CALL_VOL)
1023 _ofono_call_volume_properties_get(m);
1026 static void _modem_property_update(OFono_Modem *m, const char *key,
1027 DBusMessageIter *value)
1029 if (strcmp(key, "Powered") == 0) {
1030 m->powered = _dbus_bool_get(value);
1031 DBG("%s Powered %d", m->base.path, m->powered);
1032 } else if (strcmp(key, "Online") == 0) {
1033 m->online = _dbus_bool_get(value);
1034 DBG("%s Online %d", m->base.path, m->online);
1035 } else if (strcmp(key, "Interfaces") == 0) {
1036 unsigned int ifaces = _modem_interfaces_extract(value);
1037 DBG("%s Interfaces 0x%02x", m->base.path, ifaces);
1038 if (m->interfaces != ifaces) {
1039 _modem_update_interfaces(m, ifaces);
1040 m->interfaces = ifaces;
1042 if (modem_selected && modem_path_wanted &&
1043 modem_selected->base.path != modem_path_wanted)
1044 modem_selected = NULL;
1046 } else if (strcmp(key, "Serial") == 0) {
1048 dbus_message_iter_get_basic(value, &serial);
1049 DBG("%s Serial %s", m->base.path, serial);
1050 eina_stringshare_replace(&m->serial, serial);
1051 } else if (strcmp(key, "Type") == 0) {
1053 dbus_message_iter_get_basic(value, &type);
1054 DBG("%s Type %s", m->base.path, type);
1057 m->ignored = EINA_FALSE;
1061 m->ignored = EINA_TRUE;
1062 EINA_LIST_FOREACH(modem_types, n, t) {
1063 if (strcmp(t, type) == 0) {
1064 m->ignored = EINA_FALSE;
1069 INF("Modem %s type %s is ignored",
1070 m->base.path, type);
1073 DBG("%s %s (unused property)", m->base.path, key);
1075 _notify_ofono_callbacks_modem_list(cbs_modem_changed);
1078 static void _ofono_call_volume_properties_get_reply(void *data,
1082 OFono_Modem *m = data;
1083 DBusMessageIter iter, prop;
1085 if (dbus_error_is_set(err)) {
1086 DBG("%s: %s", err->name, err->message);
1090 dbus_message_iter_init(msg, &iter);
1091 dbus_message_iter_recurse(&iter, &prop);
1093 for (; dbus_message_iter_get_arg_type(&prop) == DBUS_TYPE_DICT_ENTRY;
1094 dbus_message_iter_next(&prop)) {
1095 DBusMessageIter entry, value;
1098 dbus_message_iter_recurse(&prop, &entry);
1099 dbus_message_iter_get_basic(&entry, &key);
1101 dbus_message_iter_next(&entry);
1102 dbus_message_iter_recurse(&entry, &value);
1103 _call_volume_property_update(m, key, &value);
1107 static void _ofono_call_volume_properties_get(OFono_Modem *m)
1110 msg = dbus_message_new_method_call(bus_id, m->base.path,
1112 OFONO_CALL_VOL_IFACE,
1117 _bus_object_message_send(&m->base, msg,
1118 _ofono_call_volume_properties_get_reply, m);
1121 static void _modem_add(const char *path, DBusMessageIter *prop)
1125 DBG("path=%s", path);
1127 m = eina_hash_find(modems, path);
1129 DBG("Modem already exists %p (%s)", m, path);
1130 goto update_properties;
1133 m = _modem_new(path);
1134 EINA_SAFETY_ON_NULL_RETURN(m);
1135 eina_hash_add(modems, m->base.path, m);
1137 _bus_object_signal_listen(&m->base, OFONO_PREFIX OFONO_VOICE_IFACE,
1138 "CallAdded", _call_added, m);
1139 _bus_object_signal_listen(&m->base, OFONO_PREFIX OFONO_VOICE_IFACE,
1140 "CallRemoved", _call_removed, m);
1141 _bus_object_signal_listen(&m->base, OFONO_PREFIX OFONO_CALL_VOL_IFACE,
1143 _call_volume_property_changed, m);
1145 /* TODO: do we need to listen to BarringActive or Forwarded? */
1147 if (modem_selected && modem_path_wanted &&
1148 modem_selected->base.path != modem_path_wanted)
1149 modem_selected = NULL;
1154 for (; dbus_message_iter_get_arg_type(prop) == DBUS_TYPE_DICT_ENTRY;
1155 dbus_message_iter_next(prop)) {
1156 DBusMessageIter entry, value;
1159 dbus_message_iter_recurse(prop, &entry);
1160 dbus_message_iter_get_basic(&entry, &key);
1162 dbus_message_iter_next(&entry);
1163 dbus_message_iter_recurse(&entry, &value);
1165 _modem_property_update(m, key, &value);
1168 if (m->interfaces & OFONO_API_VOICE)
1169 _modem_calls_load(m);
1172 static void _modem_remove(const char *path)
1174 DBG("path=%s", path);
1175 eina_hash_del_by_key(modems, path);
1178 static void _ofono_modems_get_reply(void *data __UNUSED__, DBusMessage *msg,
1181 DBusMessageIter array, dict;
1183 pc_get_modems = NULL;
1187 ERR("%s: %s", err->name, err->message);
1193 EINA_SAFETY_ON_NULL_RETURN(modems);
1194 eina_hash_free_buckets(modems);
1196 if (!dbus_message_iter_init(msg, &array)) {
1197 ERR("Could not get modems");
1201 dbus_message_iter_recurse(&array, &dict);
1202 for (; dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_STRUCT;
1203 dbus_message_iter_next(&dict)) {
1204 DBusMessageIter value, properties;
1207 dbus_message_iter_recurse(&dict, &value);
1208 dbus_message_iter_get_basic(&value, &path);
1210 dbus_message_iter_next(&value);
1211 dbus_message_iter_recurse(&value, &properties);
1213 _modem_add(path, &properties);
1217 static void _modem_added(void *data __UNUSED__, DBusMessage *msg)
1219 DBusMessageIter iter, properties;
1222 if (!msg || !dbus_message_iter_init(msg, &iter)) {
1223 ERR("Could not handle message %p", msg);
1227 dbus_message_iter_get_basic(&iter, &path);
1229 dbus_message_iter_next(&iter);
1230 dbus_message_iter_recurse(&iter, &properties);
1232 _modem_add(path, &properties);
1235 static void _modem_removed(void *data __UNUSED__, DBusMessage *msg)
1241 ERR("Could not handle message %p", msg);
1245 dbus_error_init(&err);
1246 if (!dbus_message_get_args(msg, &err, DBUS_TYPE_OBJECT_PATH,
1248 ERR("Could not get ModemRemoved arguments: %s: %s",
1249 err.name, err.message);
1250 dbus_error_free(&err);
1254 _modem_remove(path);
1257 static void _modem_property_changed(void *data __UNUSED__, DBusMessage *msg)
1261 DBusMessageIter iter, value;
1264 if (!msg || !dbus_message_iter_init(msg, &iter)) {
1265 ERR("Could not handle message %p", msg);
1269 path = dbus_message_get_path(msg);
1270 DBG("path=%s", path);
1272 m = eina_hash_find(modems, path);
1274 DBG("Modem is unknown (%s)", path);
1278 dbus_message_iter_get_basic(&iter, &key);
1279 dbus_message_iter_next(&iter);
1280 dbus_message_iter_recurse(&iter, &value);
1281 _modem_property_update(m, key, &value);
1284 static void _modems_load(void)
1286 DBusMessage *msg = dbus_message_new_method_call(
1287 bus_id, "/", OFONO_PREFIX OFONO_MANAGER_IFACE, "GetModems");
1290 dbus_pending_call_cancel(pc_get_modems);
1293 pc_get_modems = e_dbus_message_send(
1294 bus_conn, msg, _ofono_modems_get_reply, -1, NULL);
1295 dbus_message_unref(msg);
1298 static void _ofono_connected(const char *id)
1301 bus_id = strdup(id);
1303 sig_modem_added = e_dbus_signal_handler_add(
1304 bus_conn, bus_id, "/",
1305 OFONO_PREFIX OFONO_MANAGER_IFACE,
1307 _modem_added, NULL);
1309 sig_modem_removed = e_dbus_signal_handler_add(
1310 bus_conn, bus_id, "/",
1311 OFONO_PREFIX OFONO_MANAGER_IFACE,
1313 _modem_removed, NULL);
1315 sig_modem_prop_changed = e_dbus_signal_handler_add(
1316 bus_conn, bus_id, NULL,
1317 OFONO_PREFIX OFONO_MODEM_IFACE,
1319 _modem_property_changed, NULL);
1323 _notify_ofono_callbacks_modem_list(cbs_modem_connected);
1326 static void _ofono_disconnected(void)
1328 eina_hash_free_buckets(modems);
1330 if (sig_modem_added) {
1331 e_dbus_signal_handler_del(bus_conn, sig_modem_added);
1332 sig_modem_added = NULL;
1335 if (sig_modem_removed) {
1336 e_dbus_signal_handler_del(bus_conn, sig_modem_removed);
1337 sig_modem_removed = NULL;
1340 if (sig_modem_prop_changed) {
1341 e_dbus_signal_handler_del(bus_conn, sig_modem_prop_changed);
1342 sig_modem_prop_changed = NULL;
1346 _notify_ofono_callbacks_modem_list(cbs_modem_disconnected);
1352 static void _name_owner_changed(void *data __UNUSED__, DBusMessage *msg)
1355 const char *name, *from, *to;
1357 dbus_error_init(&err);
1358 if (!dbus_message_get_args(msg, &err,
1359 DBUS_TYPE_STRING, &name,
1360 DBUS_TYPE_STRING, &from,
1361 DBUS_TYPE_STRING, &to,
1362 DBUS_TYPE_INVALID)) {
1363 ERR("Could not get NameOwnerChanged arguments: %s: %s",
1364 err.name, err.message);
1365 dbus_error_free(&err);
1369 if (strcmp(name, bus_name) != 0)
1372 DBG("NameOwnerChanged %s from=%s to=%s", name, from, to);
1374 if (from[0] == '\0' && to[0] != '\0') {
1375 INF("oFono appeared as %s", to);
1376 _ofono_connected(to);
1377 } else if (from[0] != '\0' && to[0] == '\0') {
1378 INF("oFono disappeared from %s", from);
1379 _ofono_disconnected();
1383 static void _ofono_get_name_owner(void *data __UNUSED__, DBusMessage *msg, DBusError *err)
1385 DBusMessageIter itr;
1390 ERR("%s: %s", err->name, err->message);
1396 dbus_message_iter_init(msg, &itr);
1397 dbus_message_iter_get_basic(&itr, &id);
1398 if (!id || id[0] == '\0') {
1399 ERR("No name owner fo %s!", bus_name);
1403 INF("oFono bus id: %s", id);
1404 _ofono_connected(id);
1407 OFono_Pending *ofono_modem_change_pin(const char *what, const char *old,
1408 const char *new, OFono_Simple_Cb cb,
1411 OFono_Simple_Cb_Context *ctx = NULL;
1412 OFono_Error err = OFONO_ERROR_OFFLINE;
1415 OFono_Modem *m = _modem_selected_get();
1416 EINA_SAFETY_ON_NULL_GOTO(m, error);
1417 EINA_SAFETY_ON_NULL_GOTO(what, error);
1418 EINA_SAFETY_ON_NULL_GOTO(old, error);
1419 EINA_SAFETY_ON_NULL_GOTO(new, error);
1421 if ((m->interfaces & OFONO_API_SIM) == 0)
1423 err = OFONO_ERROR_FAILED;
1426 ctx = calloc(1, sizeof(OFono_Simple_Cb_Context));
1427 EINA_SAFETY_ON_NULL_GOTO(ctx, error);
1432 msg = dbus_message_new_method_call(
1433 bus_id, m->base.path, OFONO_PREFIX OFONO_SIM_IFACE,
1438 if (!dbus_message_append_args(msg, DBUS_TYPE_STRING, &what,
1439 DBUS_TYPE_STRING, &old,
1440 DBUS_TYPE_STRING, &new,
1444 INF("ChangePin(%s, %s, %s)", what, old, new);
1445 p = _bus_object_message_send(&m->base, msg, _ofono_simple_reply, ctx);
1449 dbus_message_unref(msg);
1452 cb((void *)data, err);
1457 OFono_Pending *ofono_modem_reset_pin(const char *what, const char *puk,
1458 const char *new, OFono_Simple_Cb cb,
1461 OFono_Simple_Cb_Context *ctx = NULL;
1462 OFono_Error err = OFONO_ERROR_OFFLINE;
1465 OFono_Modem *m = _modem_selected_get();
1466 EINA_SAFETY_ON_NULL_GOTO(m, error);
1467 EINA_SAFETY_ON_NULL_GOTO(what, error);
1468 EINA_SAFETY_ON_NULL_GOTO(puk, error);
1469 EINA_SAFETY_ON_NULL_GOTO(new, error);
1471 if ((m->interfaces & OFONO_API_SIM) == 0)
1473 err = OFONO_ERROR_FAILED;
1476 ctx = calloc(1, sizeof(OFono_Simple_Cb_Context));
1477 EINA_SAFETY_ON_NULL_GOTO(ctx, error);
1482 msg = dbus_message_new_method_call(
1483 bus_id, m->base.path, OFONO_PREFIX OFONO_SIM_IFACE, "ResetPin");
1487 if (!dbus_message_append_args(msg, DBUS_TYPE_STRING, &what,
1488 DBUS_TYPE_STRING, &puk,
1489 DBUS_TYPE_STRING, &new,
1493 INF("ResetPin(%s, %s, %s)", what, puk, new);
1494 p = _bus_object_message_send(&m->base, msg, _ofono_simple_reply, ctx);
1498 dbus_message_unref(msg);
1501 cb((void *)data, err);
1506 static char *_ss_initiate_convert_ussd(const char *type __UNUSED__,
1507 DBusMessageIter *itr)
1509 const char *ussd_response;
1511 if (dbus_message_iter_get_arg_type(itr) != DBUS_TYPE_STRING) {
1512 ERR("Invalid type: %c (expected: %c)",
1513 dbus_message_iter_get_arg_type(itr), DBUS_TYPE_STRING);
1516 dbus_message_iter_get_basic(itr, &ussd_response);
1517 EINA_SAFETY_ON_NULL_RETURN_VAL(ussd_response, NULL);
1518 return strdup(ussd_response);
1521 static void _ss_initiate_cb_dict_convert(Eina_Strbuf *buf,
1522 DBusMessageIter *dict)
1524 for (; dbus_message_iter_get_arg_type(dict) == DBUS_TYPE_DICT_ENTRY;
1525 dbus_message_iter_next(dict)) {
1526 DBusMessageIter e, v;
1527 const char *key, *value;
1529 dbus_message_iter_recurse(dict, &e);
1530 dbus_message_iter_get_basic(&e, &key);
1532 dbus_message_iter_next(&e);
1533 dbus_message_iter_recurse(&e, &v);
1534 dbus_message_iter_get_basic(&v, &value);
1536 eina_strbuf_append_printf(buf, " %s=%s<br>",
1541 static char *_ss_initiate_convert_call1(const char *type, DBusMessageIter *itr)
1543 DBusMessageIter array, dict;
1544 const char *ss_op, *service;
1548 dbus_message_iter_recurse(itr, &array);
1550 if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_STRING) {
1551 ERR("Invalid type: %c (expected: %c)",
1552 dbus_message_iter_get_arg_type(&array),
1556 dbus_message_iter_get_basic(&array, &ss_op);
1557 EINA_SAFETY_ON_NULL_RETURN_VAL(ss_op, NULL);
1559 if (!dbus_message_iter_next(&array)) {
1560 ERR("Missing %s service", type);
1564 if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_STRING) {
1565 ERR("Invalid type: %c (expected: %c)",
1566 dbus_message_iter_get_arg_type(&array),
1570 dbus_message_iter_get_basic(&array, &service);
1571 EINA_SAFETY_ON_NULL_RETURN_VAL(service, NULL);
1573 if (!dbus_message_iter_next(&array)) {
1574 ERR("Missing %s information", type);
1578 buf = eina_strbuf_new();
1579 eina_strbuf_append_printf(buf, "<b>%s %s=%s</b><br><br>",
1580 type, ss_op, service);
1582 dbus_message_iter_recurse(&array, &dict);
1583 _ss_initiate_cb_dict_convert(buf, &dict);
1585 str = eina_strbuf_string_steal(buf);
1586 eina_strbuf_free(buf);
1590 static char *_ss_initiate_convert_call_waiting(const char *type,
1591 DBusMessageIter *itr)
1593 DBusMessageIter array, dict;
1598 dbus_message_iter_recurse(itr, &array);
1600 if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_STRING) {
1601 ERR("Invalid type: %c (expected: %c)",
1602 dbus_message_iter_get_arg_type(&array),
1606 dbus_message_iter_get_basic(&array, &ss_op);
1607 EINA_SAFETY_ON_NULL_RETURN_VAL(ss_op, NULL);
1609 if (!dbus_message_iter_next(&array)) {
1610 ERR("Missing %s information", type);
1614 buf = eina_strbuf_new();
1615 eina_strbuf_append_printf(buf, "<b>%s %s</b><br><br>",
1618 dbus_message_iter_recurse(&array, &dict);
1619 _ss_initiate_cb_dict_convert(buf, &dict);
1621 str = eina_strbuf_string_steal(buf);
1622 eina_strbuf_free(buf);
1626 static char *_ss_initiate_convert_call2(const char *type,
1627 DBusMessageIter *itr)
1629 DBusMessageIter array;
1630 const char *ss_op, *status;
1634 dbus_message_iter_recurse(itr, &array);
1636 if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_STRING) {
1637 ERR("Invalid type: %c (expected: %c)",
1638 dbus_message_iter_get_arg_type(&array),
1642 dbus_message_iter_get_basic(&array, &ss_op);
1643 EINA_SAFETY_ON_NULL_RETURN_VAL(ss_op, NULL);
1645 if (!dbus_message_iter_next(&array)) {
1646 ERR("Missing %s status", type);
1650 if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_STRING) {
1651 ERR("Invalid type: %c (expected: %c)",
1652 dbus_message_iter_get_arg_type(&array),
1656 dbus_message_iter_get_basic(&array, &status);
1657 EINA_SAFETY_ON_NULL_RETURN_VAL(status, NULL);
1659 buf = eina_strbuf_new();
1660 eina_strbuf_append_printf(buf, "<b>%s:</b><br><br>%s=%s",
1661 type, ss_op, status);
1663 str = eina_strbuf_string_steal(buf);
1664 eina_strbuf_free(buf);
1668 static const struct SS_Initiate_Convert_Map {
1671 char *(*convert)(const char *type, DBusMessageIter *itr);
1672 } ss_initiate_convert_map[] = {
1673 #define MAP(type, conv) {type, sizeof(type) - 1, conv}
1674 MAP("USSD", _ss_initiate_convert_ussd),
1675 MAP("CallBarring", _ss_initiate_convert_call1),
1676 MAP("CallForwarding", _ss_initiate_convert_call1),
1677 MAP("CallWaiting", _ss_initiate_convert_call_waiting),
1678 MAP("CallingLinePresentation", _ss_initiate_convert_call2),
1679 MAP("ConnectedLinePresentation", _ss_initiate_convert_call2),
1680 MAP("CallingLineRestriction", _ss_initiate_convert_call2),
1681 MAP("ConnectedLineRestriction", _ss_initiate_convert_call2),
1686 static char *_ss_initiate_convert(DBusMessage *msg)
1688 DBusMessageIter array, variant;
1689 const struct SS_Initiate_Convert_Map *citr;
1690 const char *type = NULL;
1693 if (!dbus_message_iter_init(msg, &array))
1696 if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_STRING) {
1697 ERR("Invalid type for first argument: %c (expected: %c)",
1698 dbus_message_iter_get_arg_type(&array),
1702 dbus_message_iter_get_basic(&array, &type);
1704 ERR("Couldn't get SupplementaryServices.Initiate type");
1707 DBG("type: %s", type);
1709 if (!dbus_message_iter_next(&array)) {
1710 ERR("Couldn't get SupplementaryServices.Initiate payload");
1713 dbus_message_iter_recurse(&array, &variant);
1715 typelen = strlen(type);
1716 for (citr = ss_initiate_convert_map; citr->type != NULL; citr++) {
1717 if ((citr->typelen == typelen) &&
1718 (memcmp(citr->type, type, typelen) == 0)) {
1719 return citr->convert(type, &variant);
1722 ERR("Could not convert SupplementaryServices.Initiate type %s", type);
1728 OFono_Pending *ofono_ss_initiate(const char *command, OFono_String_Cb cb, const void *data)
1730 OFono_String_Cb_Context *ctx = NULL;
1731 OFono_Error err = OFONO_ERROR_OFFLINE;
1734 OFono_Modem *m = _modem_selected_get();
1735 EINA_SAFETY_ON_NULL_GOTO(m, error);
1736 EINA_SAFETY_ON_NULL_GOTO(command, error);
1738 if ((m->interfaces & OFONO_API_SUPPL_SERV) == 0)
1740 err = OFONO_ERROR_FAILED;
1742 ctx = calloc(1, sizeof(OFono_String_Cb_Context));
1743 EINA_SAFETY_ON_NULL_GOTO(ctx, error);
1746 ctx->name = OFONO_PREFIX OFONO_SUPPL_SERV_IFACE ".Initiate";
1747 ctx->convert = _ss_initiate_convert;
1749 msg = dbus_message_new_method_call(
1750 bus_id, m->base.path, OFONO_PREFIX OFONO_SUPPL_SERV_IFACE,
1755 if (!dbus_message_append_args(msg, DBUS_TYPE_STRING, &command,
1759 INF("SupplementaryServices.Initiate(%s)", command);
1760 p = _bus_object_message_send(&m->base, msg, _ofono_string_reply, ctx);
1764 dbus_message_unref(msg);
1767 cb((void *)data, err, NULL);
1772 typedef struct _OFono_Call_Cb_Context
1778 } OFono_Call_Cb_Context;
1780 static void _ofono_dial_reply(void *data, DBusMessage *msg, DBusError *err)
1782 OFono_Call_Cb_Context *ctx = data;
1783 OFono_Call *c = NULL;
1784 OFono_Error oe = OFONO_ERROR_NONE;
1787 DBG("%s: %s", err->name, err->message);
1788 oe = _ofono_error_parse(err->name);
1792 dbus_error_init(&e);
1793 if (!dbus_message_get_args(msg, &e, DBUS_TYPE_OBJECT_PATH,
1794 &path, DBUS_TYPE_INVALID)) {
1795 ERR("Could not get Dial reply: %s: %s",
1797 dbus_error_free(&e);
1798 oe = OFONO_ERROR_FAILED;
1800 c = eina_hash_find(ctx->modem->calls, path);
1802 _call_add(ctx->modem, path, NULL);
1803 c = eina_hash_find(ctx->modem->calls, path);
1806 ERR("Could not find call %s", path);
1807 oe = OFONO_ERROR_FAILED;
1813 ctx->cb((void *)ctx->data, oe, c);
1818 OFono_Pending *ofono_dial(const char *number, const char *hide_callerid,
1819 OFono_Call_Cb cb, const void *data)
1821 OFono_Call_Cb_Context *ctx = NULL;
1822 OFono_Error err = OFONO_ERROR_OFFLINE;
1825 OFono_Modem *m = _modem_selected_get();
1826 EINA_SAFETY_ON_NULL_GOTO(m, error);
1829 if ((m->interfaces & OFONO_API_VOICE) == 0)
1831 err = OFONO_ERROR_FAILED;
1836 ctx = calloc(1, sizeof(OFono_Call_Cb_Context));
1837 EINA_SAFETY_ON_NULL_GOTO(ctx, error);
1840 ctx->name = OFONO_PREFIX OFONO_VOICE_IFACE ".Dial";
1843 msg = dbus_message_new_method_call(
1844 bus_id, m->base.path, OFONO_PREFIX OFONO_VOICE_IFACE, "Dial");
1848 if (!dbus_message_append_args(msg, DBUS_TYPE_STRING, &number,
1849 DBUS_TYPE_STRING, &hide_callerid,
1853 INF("Dial(%s, %s)", number, hide_callerid);
1854 p = _bus_object_message_send(&m->base, msg, _ofono_dial_reply, ctx);
1858 dbus_message_unref(msg);
1861 cb((void *)data, err, NULL);
1866 static OFono_Pending *_ofono_simple_do(OFono_API api, const char *method,
1867 OFono_Simple_Cb cb, const void *data)
1869 OFono_Simple_Cb_Context *ctx = NULL;
1870 OFono_Error err = OFONO_ERROR_OFFLINE;
1873 char iface[128] = "";
1874 const struct API_Interface_Map *itr;
1875 OFono_Modem *m = _modem_selected_get();
1876 EINA_SAFETY_ON_NULL_GOTO(m, error);
1877 EINA_SAFETY_ON_NULL_GOTO(method, error);
1879 if ((m->interfaces & api) == 0)
1881 err = OFONO_ERROR_FAILED;
1883 for (itr = api_iface_map; itr->name != NULL; itr++) {
1884 if (itr->bit == api) {
1885 snprintf(iface, sizeof(iface), "%s%s",
1886 OFONO_PREFIX, itr->name);
1890 if (iface[0] == '\0') {
1891 ERR("Could not map api %d to interface name!", api);
1896 ctx = calloc(1, sizeof(OFono_Simple_Cb_Context));
1897 EINA_SAFETY_ON_NULL_GOTO(ctx, error);
1902 msg = dbus_message_new_method_call(bus_id, m->base.path, iface, method);
1906 INF("%s.%s()", iface, method);
1907 p = _bus_object_message_send(&m->base, msg, _ofono_simple_reply, ctx);
1912 cb((void *)data, err);
1917 OFono_Pending *ofono_transfer(OFono_Simple_Cb cb, const void *data)
1919 return _ofono_simple_do(OFONO_API_VOICE, "Transfer", cb, data);
1922 OFono_Pending *ofono_swap_calls(OFono_Simple_Cb cb, const void *data)
1924 return _ofono_simple_do(OFONO_API_VOICE, "SwapCalls", cb, data);
1927 OFono_Pending *ofono_release_and_answer(OFono_Simple_Cb cb, const void *data)
1929 return _ofono_simple_do(OFONO_API_VOICE, "ReleaseAndAnswer", cb, data);
1932 OFono_Pending *ofono_release_and_swap(OFono_Simple_Cb cb, const void *data)
1934 return _ofono_simple_do(OFONO_API_VOICE, "ReleaseAndSwap", cb, data);
1937 OFono_Pending *ofono_hold_and_answer(OFono_Simple_Cb cb, const void *data)
1939 return _ofono_simple_do(OFONO_API_VOICE, "HoldAndAnswer", cb, data);
1942 OFono_Pending *ofono_hangup_all(OFono_Simple_Cb cb, const void *data)
1944 return _ofono_simple_do(OFONO_API_VOICE, "HangupAll", cb, data);
1947 const char *ofono_modem_serial_get(void)
1949 OFono_Modem *m = _modem_selected_get();
1950 EINA_SAFETY_ON_NULL_RETURN_VAL(m, NULL);
1954 void ofono_modem_api_require(const char *spec)
1956 unsigned int api_mask = 0;
1957 const char *name = spec;
1959 EINA_SAFETY_ON_NULL_RETURN(spec);
1962 const struct API_Interface_Map *itr;
1964 unsigned int namelen;
1966 p = strchr(name, ',');
1970 namelen = strlen(name);
1972 for (itr = api_iface_map; itr->name != NULL; itr++) {
1973 if ((itr->namelen == namelen) &&
1974 (memcmp(itr->name, name, namelen) == 0)) {
1975 api_mask |= itr->bit;
1979 if (itr->name == NULL)
1980 WRN("Unknown oFono API: %.*s", namelen, name);
1989 DBG("API parsed: '%s' = %#x", spec, api_mask);
1991 ERR("Could not parse API: %s", spec);
1995 if (modem_api_mask == api_mask)
1997 modem_api_mask = api_mask;
1998 modem_selected = NULL;
2001 void ofono_modem_api_list(FILE *fp, const char *prefix, const char *suffix)
2003 const struct API_Interface_Map *itr;
2004 for (itr = api_iface_map; itr->name != NULL; itr++)
2005 fprintf(fp, "%s%s%s", prefix, itr->name, suffix);
2008 void ofono_modem_type_require(const char *spec)
2010 Eina_List *lst = NULL;
2011 const char *name = spec;
2013 EINA_SAFETY_ON_NULL_RETURN(spec);
2018 unsigned int namelen;
2020 p = strchr(name, ',');
2024 namelen = strlen(name);
2026 for (itr = known_modem_types; *itr != NULL; itr++) {
2027 unsigned int itrlen = strlen(*itr);
2028 if ((itrlen == namelen) &&
2029 (memcmp(*itr, name, namelen) == 0)) {
2030 lst = eina_list_append(lst, *itr);
2035 WRN("Unknown oFono type: %.*s", namelen, name);
2044 DBG("Type parsed: '%s'", spec);
2046 ERR("Could not parse type: %s", spec);
2050 eina_list_free(modem_types);
2052 modem_selected = NULL;
2055 void ofono_modem_type_list(FILE *fp, const char *prefix, const char *suffix)
2058 for (itr = known_modem_types; *itr != NULL; itr++)
2059 fprintf(fp, "%s%s%s", prefix, *itr, suffix);
2062 void ofono_modem_path_wanted_set(const char *path)
2064 if (eina_stringshare_replace(&modem_path_wanted, path))
2065 modem_selected = NULL;
2068 Eina_Bool ofono_init(void)
2072 if (!elm_need_e_dbus()) {
2073 CRITICAL("Elementary does not support DBus.");
2077 bus_conn = e_dbus_bus_get(DBUS_BUS_SYSTEM);
2079 CRITICAL("Could not get DBus System Bus");
2083 modems = eina_hash_string_small_new(EINA_FREE_CB(_modem_free));
2084 EINA_SAFETY_ON_NULL_RETURN_VAL(modems, EINA_FALSE);
2086 e_dbus_signal_handler_add(bus_conn, E_DBUS_FDO_BUS, E_DBUS_FDO_PATH,
2087 E_DBUS_FDO_INTERFACE,
2089 _name_owner_changed, NULL);
2091 e_dbus_get_name_owner(bus_conn, bus_name, _ofono_get_name_owner, NULL);
2096 void ofono_shutdown(void)
2098 if (pc_get_modems) {
2099 dbus_pending_call_cancel(pc_get_modems);
2100 pc_get_modems = NULL;
2103 _ofono_disconnected();
2104 eina_stringshare_replace(&modem_path_wanted, NULL);
2106 eina_hash_free(modems);
2109 eina_list_free(modem_types);
2112 static OFono_Pending *_ofono_call_volume_property_set(char *property,
2113 int type, void *value,
2118 OFono_Simple_Cb_Context *ctx = NULL;
2120 DBusMessageIter iter, variant;
2121 OFono_Modem *m = _modem_selected_get();
2122 char type_to_send[2] = { type , DBUS_TYPE_INVALID };
2124 EINA_SAFETY_ON_NULL_GOTO(m, error_no_dbus_message);
2127 ctx = calloc(1, sizeof(OFono_Simple_Cb_Context));
2128 EINA_SAFETY_ON_NULL_GOTO(ctx, error_no_dbus_message);
2133 msg = dbus_message_new_method_call(bus_id, m->base.path,
2134 OFONO_PREFIX OFONO_CALL_VOL_IFACE,
2137 goto error_no_dbus_message;
2139 if (!dbus_message_append_args(msg, DBUS_TYPE_STRING, &property,
2141 goto error_message_args;
2143 dbus_message_iter_init_append(msg, &iter);
2145 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT,
2146 type_to_send, &variant))
2147 goto error_message_args;
2149 if (!dbus_message_iter_append_basic(&variant, type, value) ||
2150 !dbus_message_iter_close_container(&iter, &variant)) {
2151 dbus_message_iter_abandon_container(&iter, &variant);
2152 goto error_message_args;
2155 INF("%s.SetProperty(%s)", OFONO_CALL_VOL_IFACE, property);
2156 p = _bus_object_message_send(&m->base, msg, _ofono_simple_reply, ctx);
2160 dbus_message_unref(msg);
2162 error_no_dbus_message:
2164 cb((void *)data, OFONO_ERROR_FAILED);
2169 OFono_Pending *ofono_mute_set(Eina_Bool mute, OFono_Simple_Cb cb,
2172 dbus_bool_t dbus_mute = !!mute;
2174 return _ofono_call_volume_property_set("Muted", DBUS_TYPE_BOOLEAN,
2175 &dbus_mute, cb, data);
2178 Eina_Bool ofono_mute_get(void)
2180 OFono_Modem *m = _modem_selected_get();
2181 EINA_SAFETY_ON_NULL_RETURN_VAL(m, EINA_FALSE);
2185 OFono_Pending *ofono_volume_speaker_set(unsigned char volume,
2190 return _ofono_call_volume_property_set("SpeakerVolume", DBUS_TYPE_BYTE,
2194 unsigned char ofono_volume_speaker_get(void)
2196 OFono_Modem *m = _modem_selected_get();
2197 EINA_SAFETY_ON_NULL_RETURN_VAL(m, 0);
2198 return m->speaker_volume;
2201 OFono_Pending *ofono_volume_microphone_set(unsigned char volume,
2205 return _ofono_call_volume_property_set("MicrophoneVolume",
2206 DBUS_TYPE_BYTE, &volume, cb,
2210 unsigned char ofono_volume_microphone_get(void)
2212 OFono_Modem *m = _modem_selected_get();
2213 EINA_SAFETY_ON_NULL_RETURN_VAL(m, 0);
2214 return m->microphone_volume;
2217 OFono_Pending *ofono_tones_send(const char *tones,
2223 OFono_Simple_Cb_Context *ctx = NULL;
2224 OFono_Modem *m = _modem_selected_get();
2226 EINA_SAFETY_ON_NULL_GOTO(m, error_no_dbus_message);
2229 ctx = calloc(1, sizeof(OFono_Simple_Cb_Context));
2230 EINA_SAFETY_ON_NULL_GOTO(ctx, error_no_dbus_message);
2235 msg = dbus_message_new_method_call(
2236 bus_id, m->base.path,
2237 OFONO_PREFIX OFONO_VOICE_IFACE,
2240 goto error_no_dbus_message;
2242 if (!dbus_message_append_args(msg, DBUS_TYPE_STRING, &tones,
2244 goto error_message_args;
2246 INF("SendTones(%s)", tones);
2247 p = _bus_object_message_send(&m->base, msg, _ofono_simple_reply, ctx);
2251 dbus_message_unref(msg);
2253 error_no_dbus_message:
2255 cb((void *)data, OFONO_ERROR_FAILED);
2260 OFono_Pending *ofono_multiparty_create(OFono_Simple_Cb cb,
2263 return _ofono_multiparty("CreateMultiparty", cb, data);
2266 OFono_Pending *ofono_multiparty_hangup(OFono_Simple_Cb cb, const void *data)
2268 return _ofono_multiparty("HangupMultiparty", cb, data);
2271 OFono_Pending *ofono_private_chat(OFono_Call *c, OFono_Simple_Cb cb,
2276 OFono_Simple_Cb_Context *ctx = NULL;
2277 OFono_Modem *m = _modem_selected_get();
2279 EINA_SAFETY_ON_NULL_GOTO(m, error_no_message);
2280 EINA_SAFETY_ON_NULL_GOTO(c, error_no_message);
2283 ctx = calloc(1, sizeof(OFono_Simple_Cb_Context));
2284 EINA_SAFETY_ON_NULL_GOTO(ctx, error_no_message);
2289 msg = dbus_message_new_method_call(
2290 bus_id, m->base.path,
2291 OFONO_PREFIX OFONO_VOICE_IFACE,
2295 goto error_no_message;
2297 if (!dbus_message_append_args(msg, DBUS_TYPE_OBJECT_PATH,
2298 &(c->base.path), DBUS_TYPE_INVALID))
2299 goto error_message_append;
2301 INF("PrivateChat(%s)", c->base.path);
2302 p = _bus_object_message_send(&m->base, msg, _ofono_simple_reply, ctx);
2305 error_message_append:
2306 dbus_message_unref(msg);
2309 cb((void *)data, OFONO_ERROR_FAILED);
2314 static OFono_Callback_List_Modem_Node * _ofono_callback_modem_node_create(
2315 void (*cb)(void *data),const void *data)
2317 OFono_Callback_List_Modem_Node *node_new;
2319 node_new = calloc(1, sizeof(OFono_Callback_List_Modem_Node));
2320 EINA_SAFETY_ON_NULL_RETURN_VAL(node_new, NULL);
2322 node_new->cb_data = data;
2328 OFono_Callback_List_Modem_Node *
2329 ofono_modem_conected_cb_add(void (*cb)(void *data), const void *data)
2331 OFono_Callback_List_Modem_Node *node;
2333 EINA_SAFETY_ON_NULL_RETURN_VAL(cb, NULL);
2334 node = _ofono_callback_modem_node_create(cb, data);
2335 EINA_SAFETY_ON_NULL_RETURN_VAL(node, NULL);
2337 cbs_modem_connected = eina_inlist_append(cbs_modem_connected,
2338 EINA_INLIST_GET(node));
2343 OFono_Callback_List_Modem_Node *
2344 ofono_modem_disconnected_cb_add(void (*cb)(void *data), const void *data)
2346 OFono_Callback_List_Modem_Node *node;
2348 EINA_SAFETY_ON_NULL_RETURN_VAL(cb, NULL);
2349 node = _ofono_callback_modem_node_create(cb, data);
2350 EINA_SAFETY_ON_NULL_RETURN_VAL(node, NULL);
2352 cbs_modem_disconnected = eina_inlist_append(cbs_modem_disconnected,
2353 EINA_INLIST_GET(node));
2358 OFono_Callback_List_Modem_Node *
2359 ofono_modem_changed_cb_add(void (*cb)(void *data), const void *data)
2361 OFono_Callback_List_Modem_Node *node;
2363 EINA_SAFETY_ON_NULL_RETURN_VAL(cb, NULL);
2364 node = _ofono_callback_modem_node_create(cb, data);
2365 EINA_SAFETY_ON_NULL_RETURN_VAL(node, NULL);
2367 cbs_modem_changed = eina_inlist_append(cbs_modem_changed,
2368 EINA_INLIST_GET(node));
2373 static void _ofono_callback_modem_list_delete(Eina_Inlist **list,
2374 OFono_Callback_List_Modem_Node *node)
2376 EINA_SAFETY_ON_NULL_RETURN(*list);
2377 *list = eina_inlist_remove(*list, EINA_INLIST_GET(node));
2381 void ofono_modem_changed_cb_del(OFono_Callback_List_Modem_Node *node)
2383 EINA_SAFETY_ON_NULL_RETURN(node);
2384 _ofono_callback_modem_list_delete(&cbs_modem_changed, node);
2387 void ofono_modem_disconnected_cb_del(OFono_Callback_List_Modem_Node *node)
2389 EINA_SAFETY_ON_NULL_RETURN(node);
2390 _ofono_callback_modem_list_delete(&cbs_modem_disconnected, node);
2393 void ofono_modem_connected_cb_del(OFono_Callback_List_Modem_Node *node)
2395 EINA_SAFETY_ON_NULL_RETURN(node);
2396 _ofono_callback_modem_list_delete(&cbs_modem_connected, node);
2399 static OFono_Callback_List_Call_Node *_ofono_callback_call_node_create(
2400 void (*cb)(void *data, OFono_Call *call),const void *data)
2402 OFono_Callback_List_Call_Node *node;
2404 node = calloc(1, sizeof(OFono_Callback_List_Call_Node));
2405 EINA_SAFETY_ON_NULL_RETURN_VAL(node, NULL);
2407 node->cb_data = data;
2413 static OFono_Callback_List_Call_Disconnected_Node *
2414 _ofono_callback_call_disconnected_node_create(
2415 void (*cb)(void *data, OFono_Call *call, const char *reason),
2418 OFono_Callback_List_Call_Disconnected_Node *node;
2420 node = calloc(1, sizeof(OFono_Callback_List_Call_Disconnected_Node));
2421 EINA_SAFETY_ON_NULL_RETURN_VAL(node, NULL);
2423 node->cb_data = data;
2429 OFono_Callback_List_Call_Node *ofono_call_added_cb_add(
2430 void (*cb)(void *data,OFono_Call *call), const void *data)
2432 OFono_Callback_List_Call_Node *node;
2434 EINA_SAFETY_ON_NULL_RETURN_VAL(cb, NULL);
2435 node = _ofono_callback_call_node_create(cb, data);
2436 EINA_SAFETY_ON_NULL_RETURN_VAL(node, NULL);
2438 cbs_call_added = eina_inlist_append(cbs_call_added,
2439 EINA_INLIST_GET(node));
2444 OFono_Callback_List_Call_Node *ofono_call_removed_cb_add(
2445 void (*cb)(void *data, OFono_Call *call), const void *data)
2447 OFono_Callback_List_Call_Node *node;
2449 EINA_SAFETY_ON_NULL_RETURN_VAL(cb, NULL);
2450 node = _ofono_callback_call_node_create(cb, data);
2451 EINA_SAFETY_ON_NULL_RETURN_VAL(node, NULL);
2453 cbs_call_removed = eina_inlist_append(cbs_call_removed,
2454 EINA_INLIST_GET(node));
2459 OFono_Callback_List_Call_Node *ofono_call_changed_cb_add(
2460 void (*cb)(void *data, OFono_Call *call), const void *data)
2462 OFono_Callback_List_Call_Node *node;
2464 EINA_SAFETY_ON_NULL_RETURN_VAL(cb, NULL);
2465 node = _ofono_callback_call_node_create(cb, data);
2466 EINA_SAFETY_ON_NULL_RETURN_VAL(node, NULL);
2468 cbs_call_changed = eina_inlist_append(cbs_call_changed,
2469 EINA_INLIST_GET(node));
2474 OFono_Callback_List_Call_Disconnected_Node *ofono_call_disconnected_cb_add(
2475 void (*cb)(void *data, OFono_Call *call, const char *reason),
2478 OFono_Callback_List_Call_Disconnected_Node *node;
2480 EINA_SAFETY_ON_NULL_RETURN_VAL(cb, NULL);
2481 node = _ofono_callback_call_disconnected_node_create(cb, data);
2482 EINA_SAFETY_ON_NULL_RETURN_VAL(node, NULL);
2484 cbs_call_disconnected = eina_inlist_append(cbs_call_disconnected,
2485 EINA_INLIST_GET(node));
2490 static void _ofono_callback_call_list_delete(Eina_Inlist **list,
2491 OFono_Callback_List_Call_Node *node)
2493 EINA_SAFETY_ON_NULL_RETURN(*list);
2494 *list = eina_inlist_remove(*list, EINA_INLIST_GET(node));
2498 void ofono_call_changed_cb_del(OFono_Callback_List_Call_Node *node)
2500 EINA_SAFETY_ON_NULL_RETURN(node);
2501 _ofono_callback_call_list_delete(&cbs_call_changed, node);
2504 void ofono_call_disconnected_cb_del(
2505 OFono_Callback_List_Call_Disconnected_Node *node)
2507 EINA_SAFETY_ON_NULL_RETURN(node);
2508 EINA_SAFETY_ON_NULL_RETURN(cbs_call_disconnected);
2509 cbs_call_disconnected = eina_inlist_remove(cbs_call_disconnected,
2510 EINA_INLIST_GET(node));
2514 void ofono_call_added_cb_del(OFono_Callback_List_Call_Node *node)
2516 EINA_SAFETY_ON_NULL_RETURN(node);
2517 _ofono_callback_call_list_delete(&cbs_call_added, node);
2520 void ofono_call_removed_cb_del(OFono_Callback_List_Call_Node *node)
2522 EINA_SAFETY_ON_NULL_RETURN(node);
2523 _ofono_callback_call_list_delete(&cbs_call_removed, node);