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)
458 memset(&tm, 0, sizeof(tm));
460 /* strptime() does not use %z, we must use it */
461 end = strptime(str, "%Y-%m-%dT%H:%M:%S", &tm);
463 int direction, hour, minute, info = atoi(end);
472 zonediff = direction * (hour * 3600 + minute * 60);
475 return mktime(&tm) - zonediff - timezone;
478 static void _call_property_update(OFono_Call *c, const char *key,
479 DBusMessageIter *value)
481 if (strcmp(key, "LineIdentification") == 0) {
483 dbus_message_iter_get_basic(value, &str);
484 DBG("%s LineIdentification %s", c->base.path, str);
485 eina_stringshare_replace(&c->line_id, str);
486 } else if (strcmp(key, "IncomingLine") == 0) {
488 dbus_message_iter_get_basic(value, &str);
489 DBG("%s IncomingLine %s", c->base.path, str);
490 eina_stringshare_replace(&c->incoming_line, str);
491 } else if (strcmp(key, "State") == 0) {
493 OFono_Call_State state;
494 dbus_message_iter_get_basic(value, &str);
495 state = _call_state_parse(str);
496 DBG("%s State %s (%d)", c->base.path, str, state);
498 if (state == OFONO_CALL_STATE_ACTIVE) {
499 if (c->start_time < 0.0)
500 c->start_time = ecore_loop_time_get();
501 if (c->full_start_time == 0)
502 c->full_start_time = time(NULL);
504 } else if (strcmp(key, "Name") == 0) {
506 dbus_message_iter_get_basic(value, &str);
507 DBG("%s Name %s", c->base.path, str);
508 eina_stringshare_replace(&c->name, str);
509 } else if (strcmp(key, "Multiparty") == 0) {
511 dbus_message_iter_get_basic(value, &v);
512 DBG("%s Multiparty %d", c->base.path, v);
514 } else if (strcmp(key, "Emergency") == 0) {
516 dbus_message_iter_get_basic(value, &v);
517 DBG("%s Emergency %d", c->base.path, v);
519 } else if (strcmp(key, "StartTime") == 0) {
520 const char *ts = NULL;
523 dbus_message_iter_get_basic(value, &ts);
525 st = _ofono_time_parse(ts);
527 lt = ecore_loop_time_get();
528 c->start_time = st - ut + lt;
529 c->full_start_time = st;
530 DBG("%s StartTime %f (%s)", c->base.path, c->start_time, ts);
532 DBG("%s %s (unused property)", c->base.path, key);
535 static void _call_property_changed(void *data, DBusMessage *msg)
537 OFono_Call *c = data;
538 DBusMessageIter iter, value;
541 if (!msg || !dbus_message_iter_init(msg, &iter)) {
542 ERR("Could not handle message %p", msg);
546 DBG("path=%s", c->base.path);
548 dbus_message_iter_get_basic(&iter, &key);
549 dbus_message_iter_next(&iter);
550 dbus_message_iter_recurse(&iter, &value);
551 _call_property_update(c, key, &value);
553 _notify_ofono_callbacks_call_list(cbs_call_changed, c);
556 static void _call_disconnect_reason(void *data, DBusMessage *msg)
558 OFono_Call *c = data;
567 DBG("path=%s", c->base.path);
569 dbus_error_init(&err);
570 if (!dbus_message_get_args(msg, &err, DBUS_TYPE_STRING, &reason,
571 DBUS_TYPE_INVALID)) {
572 ERR("Could not get DisconnectReason arguments: %s: %s",
573 err.name, err.message);
574 dbus_error_free(&err);
578 _notify_ofono_callbacks_call_disconnected_list(cbs_call_disconnected,
582 static void _call_add(OFono_Modem *m, const char *path, DBusMessageIter *prop)
586 DBG("path=%s", path);
588 c = eina_hash_find(m->calls, path);
590 DBG("Call already exists %p (%s)", c, path);
591 goto update_properties;
595 EINA_SAFETY_ON_NULL_RETURN(c);
596 eina_hash_add(m->calls, c->base.path, c);
598 _bus_object_signal_listen(&c->base,
599 OFONO_PREFIX "VoiceCall",
601 _call_disconnect_reason, c);
602 _bus_object_signal_listen(&c->base,
603 OFONO_PREFIX "VoiceCall",
605 _call_property_changed, c);
607 _notify_ofono_callbacks_call_list(cbs_call_added, c);
612 for (; dbus_message_iter_get_arg_type(prop) == DBUS_TYPE_DICT_ENTRY;
613 dbus_message_iter_next(prop)) {
614 DBusMessageIter entry, value;
617 dbus_message_iter_recurse(prop, &entry);
618 dbus_message_iter_get_basic(&entry, &key);
620 dbus_message_iter_next(&entry);
621 dbus_message_iter_recurse(&entry, &value);
623 _call_property_update(c, key, &value);
626 _notify_ofono_callbacks_call_list(cbs_call_changed, c);
629 static void _call_remove(OFono_Modem *m, const char *path)
631 DBG("path=%s", path);
632 eina_hash_del_by_key(m->calls, path);
635 static void _call_added(void *data, DBusMessage *msg)
637 OFono_Modem *m = data;
638 DBusMessageIter iter, properties;
641 if (!msg || !dbus_message_iter_init(msg, &iter)) {
642 ERR("Could not handle message %p", msg);
646 dbus_message_iter_get_basic(&iter, &path);
648 dbus_message_iter_next(&iter);
649 dbus_message_iter_recurse(&iter, &properties);
651 _call_add(m, path, &properties);
654 static void _call_removed(void *data, DBusMessage *msg)
656 OFono_Modem *m = data;
661 ERR("Could not handle message %p", msg);
665 dbus_error_init(&err);
666 if (!dbus_message_get_args(msg, &err, DBUS_TYPE_OBJECT_PATH,
668 ERR("Could not get CallRemoved arguments: %s: %s",
669 err.name, err.message);
670 dbus_error_free(&err);
674 _call_remove(m, path);
677 static OFono_Modem *_modem_selected_get(void)
679 OFono_Modem *found_path = NULL, *found_api = NULL, *m;
680 unsigned int online = 0, powered = 0;
684 return modem_selected;
686 itr = eina_hash_iterator_data_new(modems);
687 EINA_ITERATOR_FOREACH(itr, m) {
696 if ((modem_path_wanted) && (!found_path)) {
697 DBG("m=%s, wanted=%s", m->base.path, modem_path_wanted);
698 if (m->base.path == modem_path_wanted) {
705 DBG("m=%#x, mask=%#x", m->interfaces, modem_api_mask);
706 if ((m->interfaces & modem_api_mask) == modem_api_mask)
710 eina_iterator_free(itr);
712 INF("found_path=%s, found_api=%s, wanted_path=%s, api_mask=%#x",
713 found_path ? found_path->base.path : "",
714 found_api ? found_api->base.path: "",
715 modem_path_wanted ? modem_path_wanted : "",
719 ERR("No modems powered! Run connman or test/enable-modem");
721 WRN("No modems online! Run connman or test/online-modem");
723 modem_selected = found_path ? found_path : found_api;
724 return modem_selected;
727 static OFono_Pending *_ofono_multiparty(const char *method,
728 OFono_Simple_Cb cb, const void *data)
733 OFono_Simple_Cb_Context *ctx = NULL;
734 OFono_Modem *m = _modem_selected_get();
736 EINA_SAFETY_ON_NULL_GOTO(m, error_no_message);
739 ctx = calloc(1, sizeof(OFono_Simple_Cb_Context));
740 EINA_SAFETY_ON_NULL_GOTO(ctx, error_no_message);
745 msg = dbus_message_new_method_call(
746 bus_id, m->base.path,
747 OFONO_PREFIX OFONO_VOICE_IFACE,
751 goto error_no_message;
753 if (!dbus_message_append_args(msg, DBUS_TYPE_INVALID))
754 goto error_message_append;
757 p = _bus_object_message_send(&m->base, msg, _ofono_simple_reply, ctx);
761 error_message_append:
762 dbus_message_unref(msg);
765 cb((void *)data, OFONO_ERROR_FAILED);
770 OFono_Pending *ofono_call_hangup(OFono_Call *c, OFono_Simple_Cb cb,
773 OFono_Simple_Cb_Context *ctx = NULL;
777 EINA_SAFETY_ON_NULL_RETURN_VAL(c, NULL);
780 ctx = calloc(1, sizeof(OFono_Simple_Cb_Context));
781 EINA_SAFETY_ON_NULL_GOTO(ctx, error);
786 msg = dbus_message_new_method_call(
787 bus_id, c->base.path, OFONO_PREFIX "VoiceCall", "Hangup");
791 INF("Hangup(%s)", c->base.path);
792 p = _bus_object_message_send(&c->base, msg, _ofono_simple_reply, ctx);
797 cb((void *)data, OFONO_ERROR_FAILED);
802 OFono_Pending *ofono_call_answer(OFono_Call *c, OFono_Simple_Cb cb,
805 OFono_Simple_Cb_Context *ctx = NULL;
809 EINA_SAFETY_ON_NULL_RETURN_VAL(c, NULL);
812 ctx = calloc(1, sizeof(OFono_Simple_Cb_Context));
813 EINA_SAFETY_ON_NULL_GOTO(ctx, error);
818 msg = dbus_message_new_method_call(
819 bus_id, c->base.path, OFONO_PREFIX "VoiceCall", "Answer");
823 INF("Answer(%s)", c->base.path);
824 p = _bus_object_message_send(&c->base, msg, _ofono_simple_reply, ctx);
829 cb((void *)data, OFONO_ERROR_FAILED);
834 OFono_Call_State ofono_call_state_get(const OFono_Call *c)
836 EINA_SAFETY_ON_NULL_RETURN_VAL(c, OFONO_CALL_STATE_DISCONNECTED);
840 const char *ofono_call_name_get(const OFono_Call *c)
842 EINA_SAFETY_ON_NULL_RETURN_VAL(c, NULL);
846 const char *ofono_call_line_id_get(const OFono_Call *c)
848 EINA_SAFETY_ON_NULL_RETURN_VAL(c, NULL);
852 Eina_Bool ofono_call_multiparty_get(const OFono_Call *c)
854 EINA_SAFETY_ON_NULL_RETURN_VAL(c, EINA_FALSE);
855 return c->multiparty;
858 double ofono_call_start_time_get(const OFono_Call *c)
860 EINA_SAFETY_ON_NULL_RETURN_VAL(c, -1.0);
861 return c->start_time;
864 time_t ofono_call_full_start_time_get(const OFono_Call *c)
866 EINA_SAFETY_ON_NULL_RETURN_VAL(c, 0);
867 return c->full_start_time;
870 static void _ofono_calls_get_reply(void *data, DBusMessage *msg,
873 OFono_Modem *m = data;
874 DBusMessageIter array, dict;
878 ERR("%s: %s", err->name, err->message);
884 eina_hash_free_buckets(m->calls);
886 if (!dbus_message_iter_init(msg, &array)) {
887 ERR("Could not get calls");
891 dbus_message_iter_recurse(&array, &dict);
892 for (; dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_STRUCT;
893 dbus_message_iter_next(&dict)) {
894 DBusMessageIter value, properties;
897 dbus_message_iter_recurse(&dict, &value);
898 dbus_message_iter_get_basic(&value, &path);
900 dbus_message_iter_next(&value);
901 dbus_message_iter_recurse(&value, &properties);
903 _call_add(m, path, &properties);
907 static void _modem_calls_load(OFono_Modem *m)
909 DBusMessage *msg = dbus_message_new_method_call(
910 bus_id, m->base.path, OFONO_PREFIX OFONO_VOICE_IFACE,
913 DBG("Get calls of %s", m->base.path);
914 _bus_object_message_send(&m->base, msg, _ofono_calls_get_reply, m);
917 static OFono_Modem *_modem_new(const char *path)
919 OFono_Modem *m = calloc(1, sizeof(OFono_Modem));
920 EINA_SAFETY_ON_NULL_RETURN_VAL(m, NULL);
922 m->base.path = eina_stringshare_add(path);
923 EINA_SAFETY_ON_NULL_GOTO(m->base.path, error_path);
925 m->calls = eina_hash_string_small_new(EINA_FREE_CB(_call_free));
926 EINA_SAFETY_ON_NULL_GOTO(m->calls, error_calls);
931 eina_stringshare_del(m->base.path);
937 static void _modem_free(OFono_Modem *m)
939 DBG("m=%p %s", m, m->base.path);
941 if (modem_selected == m)
942 modem_selected = NULL;
944 eina_stringshare_del(m->name);
945 eina_stringshare_del(m->serial);
947 eina_hash_free(m->calls);
949 _bus_object_free(&m->base);
953 static void _call_volume_property_update(OFono_Modem *m, const char *prop_name,
954 DBusMessageIter *iter)
957 if (strcmp(prop_name, "Muted") == 0) {
958 m->muted = _dbus_bool_get(iter);
959 DBG("%s Muted %d", m->base.path, m->muted);
960 } else if (strcmp(prop_name, "SpeakerVolume") == 0) {
961 dbus_message_iter_get_basic(iter, &m->speaker_volume);
962 DBG("%s Speaker Volume %hhu", m->base.path, m->speaker_volume);
963 } else if (strcmp(prop_name, "MicrophoneVolume") == 0) {
964 dbus_message_iter_get_basic(iter, &m->microphone_volume);
965 DBG("%s Microphone Volume %hhu", m->base.path, m->speaker_volume);
969 static void _notify_ofono_callbacks_modem_list(Eina_Inlist *list)
971 OFono_Callback_List_Modem_Node *node;
973 EINA_INLIST_FOREACH(list, node)
974 node->cb((void *) node->cb_data);
977 static void _call_volume_property_changed(void *data, DBusMessage *msg)
979 OFono_Modem *m = data;
980 DBusMessageIter iter, variant_iter;
981 const char *prop_name;
983 if (!msg || !dbus_message_iter_init(msg, &iter)) {
984 ERR("Could not handle message %p", msg);
988 dbus_message_iter_get_basic(&iter, &prop_name);
989 dbus_message_iter_next(&iter);
990 dbus_message_iter_recurse(&iter, &variant_iter);
991 _call_volume_property_update(m, prop_name, &variant_iter);
993 _notify_ofono_callbacks_modem_list(cbs_modem_changed);
996 static unsigned int _modem_interfaces_extract(DBusMessageIter *array)
998 DBusMessageIter entry;
999 unsigned int interfaces = 0;
1001 dbus_message_iter_recurse(array, &entry);
1002 for (; dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_STRING;
1003 dbus_message_iter_next(&entry)) {
1004 const struct API_Interface_Map *itr;
1008 dbus_message_iter_get_basic(&entry, &name);
1010 if (strncmp(name, OFONO_PREFIX, strlen(OFONO_PREFIX)) != 0)
1013 name += strlen(OFONO_PREFIX);
1014 namelen = strlen(name);
1016 DBG("interface: %s", name);
1017 for (itr = api_iface_map; itr->name != NULL; itr++) {
1018 if ((itr->namelen == namelen) &&
1019 (memcmp(itr->name, name, namelen) == 0)) {
1020 interfaces |= itr->bit;
1024 if (itr->name == NULL)
1025 WRN("ignored %s", name);
1031 static void _modem_update_interfaces(OFono_Modem *m, unsigned int ifaces)
1034 if (((m->interfaces & OFONO_API_CALL_VOL) == 0) &&
1035 (ifaces & OFONO_API_CALL_VOL) == OFONO_API_CALL_VOL)
1036 _ofono_call_volume_properties_get(m);
1039 static void _modem_property_update(OFono_Modem *m, const char *key,
1040 DBusMessageIter *value)
1042 if (strcmp(key, "Powered") == 0) {
1043 m->powered = _dbus_bool_get(value);
1044 DBG("%s Powered %d", m->base.path, m->powered);
1045 } else if (strcmp(key, "Online") == 0) {
1046 m->online = _dbus_bool_get(value);
1047 DBG("%s Online %d", m->base.path, m->online);
1048 } else if (strcmp(key, "Interfaces") == 0) {
1049 unsigned int ifaces = _modem_interfaces_extract(value);
1050 DBG("%s Interfaces 0x%02x", m->base.path, ifaces);
1051 if (m->interfaces != ifaces) {
1052 _modem_update_interfaces(m, ifaces);
1053 m->interfaces = ifaces;
1055 if (modem_selected && modem_path_wanted &&
1056 modem_selected->base.path != modem_path_wanted)
1057 modem_selected = NULL;
1059 } else if (strcmp(key, "Serial") == 0) {
1061 dbus_message_iter_get_basic(value, &serial);
1062 DBG("%s Serial %s", m->base.path, serial);
1063 eina_stringshare_replace(&m->serial, serial);
1064 } else if (strcmp(key, "Type") == 0) {
1066 dbus_message_iter_get_basic(value, &type);
1067 DBG("%s Type %s", m->base.path, type);
1070 m->ignored = EINA_FALSE;
1074 m->ignored = EINA_TRUE;
1075 EINA_LIST_FOREACH(modem_types, n, t) {
1076 if (strcmp(t, type) == 0) {
1077 m->ignored = EINA_FALSE;
1082 INF("Modem %s type %s is ignored",
1083 m->base.path, type);
1086 DBG("%s %s (unused property)", m->base.path, key);
1088 _notify_ofono_callbacks_modem_list(cbs_modem_changed);
1091 static void _ofono_call_volume_properties_get_reply(void *data,
1095 OFono_Modem *m = data;
1096 DBusMessageIter iter, prop;
1098 if (dbus_error_is_set(err)) {
1099 DBG("%s: %s", err->name, err->message);
1103 dbus_message_iter_init(msg, &iter);
1104 dbus_message_iter_recurse(&iter, &prop);
1106 for (; dbus_message_iter_get_arg_type(&prop) == DBUS_TYPE_DICT_ENTRY;
1107 dbus_message_iter_next(&prop)) {
1108 DBusMessageIter entry, value;
1111 dbus_message_iter_recurse(&prop, &entry);
1112 dbus_message_iter_get_basic(&entry, &key);
1114 dbus_message_iter_next(&entry);
1115 dbus_message_iter_recurse(&entry, &value);
1116 _call_volume_property_update(m, key, &value);
1120 static void _ofono_call_volume_properties_get(OFono_Modem *m)
1123 msg = dbus_message_new_method_call(bus_id, m->base.path,
1125 OFONO_CALL_VOL_IFACE,
1130 _bus_object_message_send(&m->base, msg,
1131 _ofono_call_volume_properties_get_reply, m);
1134 static void _modem_add(const char *path, DBusMessageIter *prop)
1138 DBG("path=%s", path);
1140 m = eina_hash_find(modems, path);
1142 DBG("Modem already exists %p (%s)", m, path);
1143 goto update_properties;
1146 m = _modem_new(path);
1147 EINA_SAFETY_ON_NULL_RETURN(m);
1148 eina_hash_add(modems, m->base.path, m);
1150 _bus_object_signal_listen(&m->base, OFONO_PREFIX OFONO_VOICE_IFACE,
1151 "CallAdded", _call_added, m);
1152 _bus_object_signal_listen(&m->base, OFONO_PREFIX OFONO_VOICE_IFACE,
1153 "CallRemoved", _call_removed, m);
1154 _bus_object_signal_listen(&m->base, OFONO_PREFIX OFONO_CALL_VOL_IFACE,
1156 _call_volume_property_changed, m);
1158 /* TODO: do we need to listen to BarringActive or Forwarded? */
1160 if (modem_selected && modem_path_wanted &&
1161 modem_selected->base.path != modem_path_wanted)
1162 modem_selected = NULL;
1167 for (; dbus_message_iter_get_arg_type(prop) == DBUS_TYPE_DICT_ENTRY;
1168 dbus_message_iter_next(prop)) {
1169 DBusMessageIter entry, value;
1172 dbus_message_iter_recurse(prop, &entry);
1173 dbus_message_iter_get_basic(&entry, &key);
1175 dbus_message_iter_next(&entry);
1176 dbus_message_iter_recurse(&entry, &value);
1178 _modem_property_update(m, key, &value);
1181 if (m->interfaces & OFONO_API_VOICE)
1182 _modem_calls_load(m);
1185 static void _modem_remove(const char *path)
1187 DBG("path=%s", path);
1188 eina_hash_del_by_key(modems, path);
1191 static void _ofono_modems_get_reply(void *data __UNUSED__, DBusMessage *msg,
1194 DBusMessageIter array, dict;
1196 pc_get_modems = NULL;
1200 ERR("%s: %s", err->name, err->message);
1206 EINA_SAFETY_ON_NULL_RETURN(modems);
1207 eina_hash_free_buckets(modems);
1209 if (!dbus_message_iter_init(msg, &array)) {
1210 ERR("Could not get modems");
1214 dbus_message_iter_recurse(&array, &dict);
1215 for (; dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_STRUCT;
1216 dbus_message_iter_next(&dict)) {
1217 DBusMessageIter value, properties;
1220 dbus_message_iter_recurse(&dict, &value);
1221 dbus_message_iter_get_basic(&value, &path);
1223 dbus_message_iter_next(&value);
1224 dbus_message_iter_recurse(&value, &properties);
1226 _modem_add(path, &properties);
1230 static void _modem_added(void *data __UNUSED__, DBusMessage *msg)
1232 DBusMessageIter iter, properties;
1235 if (!msg || !dbus_message_iter_init(msg, &iter)) {
1236 ERR("Could not handle message %p", msg);
1240 dbus_message_iter_get_basic(&iter, &path);
1242 dbus_message_iter_next(&iter);
1243 dbus_message_iter_recurse(&iter, &properties);
1245 _modem_add(path, &properties);
1248 static void _modem_removed(void *data __UNUSED__, DBusMessage *msg)
1254 ERR("Could not handle message %p", msg);
1258 dbus_error_init(&err);
1259 if (!dbus_message_get_args(msg, &err, DBUS_TYPE_OBJECT_PATH,
1261 ERR("Could not get ModemRemoved arguments: %s: %s",
1262 err.name, err.message);
1263 dbus_error_free(&err);
1267 _modem_remove(path);
1270 static void _modem_property_changed(void *data __UNUSED__, DBusMessage *msg)
1274 DBusMessageIter iter, value;
1277 if (!msg || !dbus_message_iter_init(msg, &iter)) {
1278 ERR("Could not handle message %p", msg);
1282 path = dbus_message_get_path(msg);
1283 DBG("path=%s", path);
1285 m = eina_hash_find(modems, path);
1287 DBG("Modem is unknown (%s)", path);
1291 dbus_message_iter_get_basic(&iter, &key);
1292 dbus_message_iter_next(&iter);
1293 dbus_message_iter_recurse(&iter, &value);
1294 _modem_property_update(m, key, &value);
1297 static void _modems_load(void)
1299 DBusMessage *msg = dbus_message_new_method_call(
1300 bus_id, "/", OFONO_PREFIX OFONO_MANAGER_IFACE, "GetModems");
1303 dbus_pending_call_cancel(pc_get_modems);
1306 pc_get_modems = e_dbus_message_send(
1307 bus_conn, msg, _ofono_modems_get_reply, -1, NULL);
1308 dbus_message_unref(msg);
1311 static void _ofono_connected(const char *id)
1314 bus_id = strdup(id);
1316 sig_modem_added = e_dbus_signal_handler_add(
1317 bus_conn, bus_id, "/",
1318 OFONO_PREFIX OFONO_MANAGER_IFACE,
1320 _modem_added, NULL);
1322 sig_modem_removed = e_dbus_signal_handler_add(
1323 bus_conn, bus_id, "/",
1324 OFONO_PREFIX OFONO_MANAGER_IFACE,
1326 _modem_removed, NULL);
1328 sig_modem_prop_changed = e_dbus_signal_handler_add(
1329 bus_conn, bus_id, NULL,
1330 OFONO_PREFIX OFONO_MODEM_IFACE,
1332 _modem_property_changed, NULL);
1336 _notify_ofono_callbacks_modem_list(cbs_modem_connected);
1339 static void _ofono_disconnected(void)
1341 eina_hash_free_buckets(modems);
1343 if (sig_modem_added) {
1344 e_dbus_signal_handler_del(bus_conn, sig_modem_added);
1345 sig_modem_added = NULL;
1348 if (sig_modem_removed) {
1349 e_dbus_signal_handler_del(bus_conn, sig_modem_removed);
1350 sig_modem_removed = NULL;
1353 if (sig_modem_prop_changed) {
1354 e_dbus_signal_handler_del(bus_conn, sig_modem_prop_changed);
1355 sig_modem_prop_changed = NULL;
1359 _notify_ofono_callbacks_modem_list(cbs_modem_disconnected);
1365 static void _name_owner_changed(void *data __UNUSED__, DBusMessage *msg)
1368 const char *name, *from, *to;
1370 dbus_error_init(&err);
1371 if (!dbus_message_get_args(msg, &err,
1372 DBUS_TYPE_STRING, &name,
1373 DBUS_TYPE_STRING, &from,
1374 DBUS_TYPE_STRING, &to,
1375 DBUS_TYPE_INVALID)) {
1376 ERR("Could not get NameOwnerChanged arguments: %s: %s",
1377 err.name, err.message);
1378 dbus_error_free(&err);
1382 if (strcmp(name, bus_name) != 0)
1385 DBG("NameOwnerChanged %s from=%s to=%s", name, from, to);
1387 if (from[0] == '\0' && to[0] != '\0') {
1388 INF("oFono appeared as %s", to);
1389 _ofono_connected(to);
1390 } else if (from[0] != '\0' && to[0] == '\0') {
1391 INF("oFono disappeared from %s", from);
1392 _ofono_disconnected();
1396 static void _ofono_get_name_owner(void *data __UNUSED__, DBusMessage *msg, DBusError *err)
1398 DBusMessageIter itr;
1403 ERR("%s: %s", err->name, err->message);
1409 dbus_message_iter_init(msg, &itr);
1410 dbus_message_iter_get_basic(&itr, &id);
1411 if (!id || id[0] == '\0') {
1412 ERR("No name owner fo %s!", bus_name);
1416 INF("oFono bus id: %s", id);
1417 _ofono_connected(id);
1420 OFono_Pending *ofono_modem_change_pin(const char *what, const char *old,
1421 const char *new, OFono_Simple_Cb cb,
1424 OFono_Simple_Cb_Context *ctx = NULL;
1425 OFono_Error err = OFONO_ERROR_OFFLINE;
1428 OFono_Modem *m = _modem_selected_get();
1429 EINA_SAFETY_ON_NULL_GOTO(m, error);
1430 EINA_SAFETY_ON_NULL_GOTO(what, error);
1431 EINA_SAFETY_ON_NULL_GOTO(old, error);
1432 EINA_SAFETY_ON_NULL_GOTO(new, error);
1434 if ((m->interfaces & OFONO_API_SIM) == 0)
1436 err = OFONO_ERROR_FAILED;
1439 ctx = calloc(1, sizeof(OFono_Simple_Cb_Context));
1440 EINA_SAFETY_ON_NULL_GOTO(ctx, error);
1445 msg = dbus_message_new_method_call(
1446 bus_id, m->base.path, OFONO_PREFIX OFONO_SIM_IFACE,
1451 if (!dbus_message_append_args(msg, DBUS_TYPE_STRING, &what,
1452 DBUS_TYPE_STRING, &old,
1453 DBUS_TYPE_STRING, &new,
1457 INF("ChangePin(%s, %s, %s)", what, old, new);
1458 p = _bus_object_message_send(&m->base, msg, _ofono_simple_reply, ctx);
1462 dbus_message_unref(msg);
1465 cb((void *)data, err);
1470 OFono_Pending *ofono_modem_reset_pin(const char *what, const char *puk,
1471 const char *new, OFono_Simple_Cb cb,
1474 OFono_Simple_Cb_Context *ctx = NULL;
1475 OFono_Error err = OFONO_ERROR_OFFLINE;
1478 OFono_Modem *m = _modem_selected_get();
1479 EINA_SAFETY_ON_NULL_GOTO(m, error);
1480 EINA_SAFETY_ON_NULL_GOTO(what, error);
1481 EINA_SAFETY_ON_NULL_GOTO(puk, error);
1482 EINA_SAFETY_ON_NULL_GOTO(new, error);
1484 if ((m->interfaces & OFONO_API_SIM) == 0)
1486 err = OFONO_ERROR_FAILED;
1489 ctx = calloc(1, sizeof(OFono_Simple_Cb_Context));
1490 EINA_SAFETY_ON_NULL_GOTO(ctx, error);
1495 msg = dbus_message_new_method_call(
1496 bus_id, m->base.path, OFONO_PREFIX OFONO_SIM_IFACE, "ResetPin");
1500 if (!dbus_message_append_args(msg, DBUS_TYPE_STRING, &what,
1501 DBUS_TYPE_STRING, &puk,
1502 DBUS_TYPE_STRING, &new,
1506 INF("ResetPin(%s, %s, %s)", what, puk, new);
1507 p = _bus_object_message_send(&m->base, msg, _ofono_simple_reply, ctx);
1511 dbus_message_unref(msg);
1514 cb((void *)data, err);
1519 static char *_ss_initiate_convert_ussd(const char *type __UNUSED__,
1520 DBusMessageIter *itr)
1522 const char *ussd_response;
1524 if (dbus_message_iter_get_arg_type(itr) != DBUS_TYPE_STRING) {
1525 ERR("Invalid type: %c (expected: %c)",
1526 dbus_message_iter_get_arg_type(itr), DBUS_TYPE_STRING);
1529 dbus_message_iter_get_basic(itr, &ussd_response);
1530 EINA_SAFETY_ON_NULL_RETURN_VAL(ussd_response, NULL);
1531 return strdup(ussd_response);
1534 static void _ss_initiate_cb_dict_convert(Eina_Strbuf *buf,
1535 DBusMessageIter *dict)
1537 for (; dbus_message_iter_get_arg_type(dict) == DBUS_TYPE_DICT_ENTRY;
1538 dbus_message_iter_next(dict)) {
1539 DBusMessageIter e, v;
1540 const char *key, *value;
1542 dbus_message_iter_recurse(dict, &e);
1543 dbus_message_iter_get_basic(&e, &key);
1545 dbus_message_iter_next(&e);
1546 dbus_message_iter_recurse(&e, &v);
1547 dbus_message_iter_get_basic(&v, &value);
1549 eina_strbuf_append_printf(buf, " %s=%s<br>",
1554 static char *_ss_initiate_convert_call1(const char *type, DBusMessageIter *itr)
1556 DBusMessageIter array, dict;
1557 const char *ss_op, *service;
1561 dbus_message_iter_recurse(itr, &array);
1563 if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_STRING) {
1564 ERR("Invalid type: %c (expected: %c)",
1565 dbus_message_iter_get_arg_type(&array),
1569 dbus_message_iter_get_basic(&array, &ss_op);
1570 EINA_SAFETY_ON_NULL_RETURN_VAL(ss_op, NULL);
1572 if (!dbus_message_iter_next(&array)) {
1573 ERR("Missing %s service", type);
1577 if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_STRING) {
1578 ERR("Invalid type: %c (expected: %c)",
1579 dbus_message_iter_get_arg_type(&array),
1583 dbus_message_iter_get_basic(&array, &service);
1584 EINA_SAFETY_ON_NULL_RETURN_VAL(service, NULL);
1586 if (!dbus_message_iter_next(&array)) {
1587 ERR("Missing %s information", type);
1591 buf = eina_strbuf_new();
1592 eina_strbuf_append_printf(buf, "<b>%s %s=%s</b><br><br>",
1593 type, ss_op, service);
1595 dbus_message_iter_recurse(&array, &dict);
1596 _ss_initiate_cb_dict_convert(buf, &dict);
1598 str = eina_strbuf_string_steal(buf);
1599 eina_strbuf_free(buf);
1603 static char *_ss_initiate_convert_call_waiting(const char *type,
1604 DBusMessageIter *itr)
1606 DBusMessageIter array, dict;
1611 dbus_message_iter_recurse(itr, &array);
1613 if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_STRING) {
1614 ERR("Invalid type: %c (expected: %c)",
1615 dbus_message_iter_get_arg_type(&array),
1619 dbus_message_iter_get_basic(&array, &ss_op);
1620 EINA_SAFETY_ON_NULL_RETURN_VAL(ss_op, NULL);
1622 if (!dbus_message_iter_next(&array)) {
1623 ERR("Missing %s information", type);
1627 buf = eina_strbuf_new();
1628 eina_strbuf_append_printf(buf, "<b>%s %s</b><br><br>",
1631 dbus_message_iter_recurse(&array, &dict);
1632 _ss_initiate_cb_dict_convert(buf, &dict);
1634 str = eina_strbuf_string_steal(buf);
1635 eina_strbuf_free(buf);
1639 static char *_ss_initiate_convert_call2(const char *type,
1640 DBusMessageIter *itr)
1642 DBusMessageIter array;
1643 const char *ss_op, *status;
1647 dbus_message_iter_recurse(itr, &array);
1649 if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_STRING) {
1650 ERR("Invalid type: %c (expected: %c)",
1651 dbus_message_iter_get_arg_type(&array),
1655 dbus_message_iter_get_basic(&array, &ss_op);
1656 EINA_SAFETY_ON_NULL_RETURN_VAL(ss_op, NULL);
1658 if (!dbus_message_iter_next(&array)) {
1659 ERR("Missing %s status", type);
1663 if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_STRING) {
1664 ERR("Invalid type: %c (expected: %c)",
1665 dbus_message_iter_get_arg_type(&array),
1669 dbus_message_iter_get_basic(&array, &status);
1670 EINA_SAFETY_ON_NULL_RETURN_VAL(status, NULL);
1672 buf = eina_strbuf_new();
1673 eina_strbuf_append_printf(buf, "<b>%s:</b><br><br>%s=%s",
1674 type, ss_op, status);
1676 str = eina_strbuf_string_steal(buf);
1677 eina_strbuf_free(buf);
1681 static const struct SS_Initiate_Convert_Map {
1684 char *(*convert)(const char *type, DBusMessageIter *itr);
1685 } ss_initiate_convert_map[] = {
1686 #define MAP(type, conv) {type, sizeof(type) - 1, conv}
1687 MAP("USSD", _ss_initiate_convert_ussd),
1688 MAP("CallBarring", _ss_initiate_convert_call1),
1689 MAP("CallForwarding", _ss_initiate_convert_call1),
1690 MAP("CallWaiting", _ss_initiate_convert_call_waiting),
1691 MAP("CallingLinePresentation", _ss_initiate_convert_call2),
1692 MAP("ConnectedLinePresentation", _ss_initiate_convert_call2),
1693 MAP("CallingLineRestriction", _ss_initiate_convert_call2),
1694 MAP("ConnectedLineRestriction", _ss_initiate_convert_call2),
1699 static char *_ss_initiate_convert(DBusMessage *msg)
1701 DBusMessageIter array, variant;
1702 const struct SS_Initiate_Convert_Map *citr;
1703 const char *type = NULL;
1706 if (!dbus_message_iter_init(msg, &array))
1709 if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_STRING) {
1710 ERR("Invalid type for first argument: %c (expected: %c)",
1711 dbus_message_iter_get_arg_type(&array),
1715 dbus_message_iter_get_basic(&array, &type);
1717 ERR("Couldn't get SupplementaryServices.Initiate type");
1720 DBG("type: %s", type);
1722 if (!dbus_message_iter_next(&array)) {
1723 ERR("Couldn't get SupplementaryServices.Initiate payload");
1726 dbus_message_iter_recurse(&array, &variant);
1728 typelen = strlen(type);
1729 for (citr = ss_initiate_convert_map; citr->type != NULL; citr++) {
1730 if ((citr->typelen == typelen) &&
1731 (memcmp(citr->type, type, typelen) == 0)) {
1732 return citr->convert(type, &variant);
1735 ERR("Could not convert SupplementaryServices.Initiate type %s", type);
1741 OFono_Pending *ofono_ss_initiate(const char *command, OFono_String_Cb cb, const void *data)
1743 OFono_String_Cb_Context *ctx = NULL;
1744 OFono_Error err = OFONO_ERROR_OFFLINE;
1747 OFono_Modem *m = _modem_selected_get();
1748 EINA_SAFETY_ON_NULL_GOTO(m, error);
1749 EINA_SAFETY_ON_NULL_GOTO(command, error);
1751 if ((m->interfaces & OFONO_API_SUPPL_SERV) == 0)
1753 err = OFONO_ERROR_FAILED;
1755 ctx = calloc(1, sizeof(OFono_String_Cb_Context));
1756 EINA_SAFETY_ON_NULL_GOTO(ctx, error);
1759 ctx->name = OFONO_PREFIX OFONO_SUPPL_SERV_IFACE ".Initiate";
1760 ctx->convert = _ss_initiate_convert;
1762 msg = dbus_message_new_method_call(
1763 bus_id, m->base.path, OFONO_PREFIX OFONO_SUPPL_SERV_IFACE,
1768 if (!dbus_message_append_args(msg, DBUS_TYPE_STRING, &command,
1772 INF("SupplementaryServices.Initiate(%s)", command);
1773 p = _bus_object_message_send(&m->base, msg, _ofono_string_reply, ctx);
1777 dbus_message_unref(msg);
1780 cb((void *)data, err, NULL);
1785 typedef struct _OFono_Call_Cb_Context
1791 } OFono_Call_Cb_Context;
1793 static void _ofono_dial_reply(void *data, DBusMessage *msg, DBusError *err)
1795 OFono_Call_Cb_Context *ctx = data;
1796 OFono_Call *c = NULL;
1797 OFono_Error oe = OFONO_ERROR_NONE;
1800 DBG("%s: %s", err->name, err->message);
1801 oe = _ofono_error_parse(err->name);
1805 dbus_error_init(&e);
1806 if (!dbus_message_get_args(msg, &e, DBUS_TYPE_OBJECT_PATH,
1807 &path, DBUS_TYPE_INVALID)) {
1808 ERR("Could not get Dial reply: %s: %s",
1810 dbus_error_free(&e);
1811 oe = OFONO_ERROR_FAILED;
1813 c = eina_hash_find(ctx->modem->calls, path);
1815 _call_add(ctx->modem, path, NULL);
1816 c = eina_hash_find(ctx->modem->calls, path);
1819 ERR("Could not find call %s", path);
1820 oe = OFONO_ERROR_FAILED;
1826 ctx->cb((void *)ctx->data, oe, c);
1831 OFono_Pending *ofono_dial(const char *number, const char *hide_callerid,
1832 OFono_Call_Cb cb, const void *data)
1834 OFono_Call_Cb_Context *ctx = NULL;
1835 OFono_Error err = OFONO_ERROR_OFFLINE;
1838 OFono_Modem *m = _modem_selected_get();
1839 EINA_SAFETY_ON_NULL_GOTO(m, error);
1842 if ((m->interfaces & OFONO_API_VOICE) == 0)
1844 err = OFONO_ERROR_FAILED;
1849 ctx = calloc(1, sizeof(OFono_Call_Cb_Context));
1850 EINA_SAFETY_ON_NULL_GOTO(ctx, error);
1853 ctx->name = OFONO_PREFIX OFONO_VOICE_IFACE ".Dial";
1856 msg = dbus_message_new_method_call(
1857 bus_id, m->base.path, OFONO_PREFIX OFONO_VOICE_IFACE, "Dial");
1861 if (!dbus_message_append_args(msg, DBUS_TYPE_STRING, &number,
1862 DBUS_TYPE_STRING, &hide_callerid,
1866 INF("Dial(%s, %s)", number, hide_callerid);
1867 p = _bus_object_message_send(&m->base, msg, _ofono_dial_reply, ctx);
1871 dbus_message_unref(msg);
1874 cb((void *)data, err, NULL);
1879 static OFono_Pending *_ofono_simple_do(OFono_API api, const char *method,
1880 OFono_Simple_Cb cb, const void *data)
1882 OFono_Simple_Cb_Context *ctx = NULL;
1883 OFono_Error err = OFONO_ERROR_OFFLINE;
1886 char iface[128] = "";
1887 const struct API_Interface_Map *itr;
1888 OFono_Modem *m = _modem_selected_get();
1889 EINA_SAFETY_ON_NULL_GOTO(m, error);
1890 EINA_SAFETY_ON_NULL_GOTO(method, error);
1892 if ((m->interfaces & api) == 0)
1894 err = OFONO_ERROR_FAILED;
1896 for (itr = api_iface_map; itr->name != NULL; itr++) {
1897 if (itr->bit == api) {
1898 snprintf(iface, sizeof(iface), "%s%s",
1899 OFONO_PREFIX, itr->name);
1903 if (iface[0] == '\0') {
1904 ERR("Could not map api %d to interface name!", api);
1909 ctx = calloc(1, sizeof(OFono_Simple_Cb_Context));
1910 EINA_SAFETY_ON_NULL_GOTO(ctx, error);
1915 msg = dbus_message_new_method_call(bus_id, m->base.path, iface, method);
1919 INF("%s.%s()", iface, method);
1920 p = _bus_object_message_send(&m->base, msg, _ofono_simple_reply, ctx);
1925 cb((void *)data, err);
1930 OFono_Pending *ofono_transfer(OFono_Simple_Cb cb, const void *data)
1932 return _ofono_simple_do(OFONO_API_VOICE, "Transfer", cb, data);
1935 OFono_Pending *ofono_swap_calls(OFono_Simple_Cb cb, const void *data)
1937 return _ofono_simple_do(OFONO_API_VOICE, "SwapCalls", cb, data);
1940 OFono_Pending *ofono_release_and_answer(OFono_Simple_Cb cb, const void *data)
1942 return _ofono_simple_do(OFONO_API_VOICE, "ReleaseAndAnswer", cb, data);
1945 OFono_Pending *ofono_hold_and_answer(OFono_Simple_Cb cb, const void *data)
1947 return _ofono_simple_do(OFONO_API_VOICE, "HoldAndAnswer", cb, data);
1950 OFono_Pending *ofono_hangup_all(OFono_Simple_Cb cb, const void *data)
1952 return _ofono_simple_do(OFONO_API_VOICE, "HangupAll", cb, data);
1955 const char *ofono_modem_serial_get(void)
1957 OFono_Modem *m = _modem_selected_get();
1958 EINA_SAFETY_ON_NULL_RETURN_VAL(m, NULL);
1962 void ofono_modem_api_require(const char *spec)
1964 unsigned int api_mask = 0;
1965 const char *name = spec;
1967 EINA_SAFETY_ON_NULL_RETURN(spec);
1970 const struct API_Interface_Map *itr;
1972 unsigned int namelen;
1974 p = strchr(name, ',');
1978 namelen = strlen(name);
1980 for (itr = api_iface_map; itr->name != NULL; itr++) {
1981 if ((itr->namelen == namelen) &&
1982 (memcmp(itr->name, name, namelen) == 0)) {
1983 api_mask |= itr->bit;
1987 if (itr->name == NULL)
1988 WRN("Unknown oFono API: %.*s", namelen, name);
1997 DBG("API parsed: '%s' = %#x", spec, api_mask);
1999 ERR("Could not parse API: %s", spec);
2003 if (modem_api_mask == api_mask)
2005 modem_api_mask = api_mask;
2006 modem_selected = NULL;
2009 void ofono_modem_api_list(FILE *fp, const char *prefix, const char *suffix)
2011 const struct API_Interface_Map *itr;
2012 for (itr = api_iface_map; itr->name != NULL; itr++)
2013 fprintf(fp, "%s%s%s", prefix, itr->name, suffix);
2016 void ofono_modem_type_require(const char *spec)
2018 Eina_List *lst = NULL;
2019 const char *name = spec;
2021 EINA_SAFETY_ON_NULL_RETURN(spec);
2026 unsigned int namelen;
2028 p = strchr(name, ',');
2032 namelen = strlen(name);
2034 for (itr = known_modem_types; *itr != NULL; itr++) {
2035 unsigned int itrlen = strlen(*itr);
2036 if ((itrlen == namelen) &&
2037 (memcmp(*itr, name, namelen) == 0)) {
2038 lst = eina_list_append(lst, *itr);
2043 WRN("Unknown oFono type: %.*s", namelen, name);
2052 DBG("Type parsed: '%s'", spec);
2054 ERR("Could not parse type: %s", spec);
2058 eina_list_free(modem_types);
2060 modem_selected = NULL;
2063 void ofono_modem_type_list(FILE *fp, const char *prefix, const char *suffix)
2066 for (itr = known_modem_types; *itr != NULL; itr++)
2067 fprintf(fp, "%s%s%s", prefix, *itr, suffix);
2070 void ofono_modem_path_wanted_set(const char *path)
2072 if (eina_stringshare_replace(&modem_path_wanted, path))
2073 modem_selected = NULL;
2076 Eina_Bool ofono_init(void)
2080 if (!elm_need_e_dbus()) {
2081 CRITICAL("Elementary does not support DBus.");
2085 bus_conn = e_dbus_bus_get(DBUS_BUS_SYSTEM);
2087 CRITICAL("Could not get DBus System Bus");
2091 modems = eina_hash_string_small_new(EINA_FREE_CB(_modem_free));
2092 EINA_SAFETY_ON_NULL_RETURN_VAL(modems, EINA_FALSE);
2094 e_dbus_signal_handler_add(bus_conn, E_DBUS_FDO_BUS, E_DBUS_FDO_PATH,
2095 E_DBUS_FDO_INTERFACE,
2097 _name_owner_changed, NULL);
2099 e_dbus_get_name_owner(bus_conn, bus_name, _ofono_get_name_owner, NULL);
2104 void ofono_shutdown(void)
2106 if (pc_get_modems) {
2107 dbus_pending_call_cancel(pc_get_modems);
2108 pc_get_modems = NULL;
2111 _ofono_disconnected();
2112 eina_stringshare_replace(&modem_path_wanted, NULL);
2114 eina_hash_free(modems);
2117 eina_list_free(modem_types);
2120 static OFono_Pending *_ofono_call_volume_property_set(char *property,
2121 int type, void *value,
2126 OFono_Simple_Cb_Context *ctx = NULL;
2128 DBusMessageIter iter, variant;
2129 OFono_Modem *m = _modem_selected_get();
2130 char type_to_send[2] = { type , DBUS_TYPE_INVALID };
2132 EINA_SAFETY_ON_NULL_GOTO(m, error_no_dbus_message);
2135 ctx = calloc(1, sizeof(OFono_Simple_Cb_Context));
2136 EINA_SAFETY_ON_NULL_GOTO(ctx, error_no_dbus_message);
2141 msg = dbus_message_new_method_call(bus_id, m->base.path,
2142 OFONO_PREFIX OFONO_CALL_VOL_IFACE,
2145 goto error_no_dbus_message;
2147 if (!dbus_message_append_args(msg, DBUS_TYPE_STRING, &property,
2149 goto error_message_args;
2151 dbus_message_iter_init_append(msg, &iter);
2153 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT,
2154 type_to_send, &variant))
2155 goto error_message_args;
2157 if (!dbus_message_iter_append_basic(&variant, type, value) ||
2158 !dbus_message_iter_close_container(&iter, &variant)) {
2159 dbus_message_iter_abandon_container(&iter, &variant);
2160 goto error_message_args;
2163 INF("%s.SetProperty(%s)", OFONO_CALL_VOL_IFACE, property);
2164 p = _bus_object_message_send(&m->base, msg, _ofono_simple_reply, ctx);
2168 dbus_message_unref(msg);
2170 error_no_dbus_message:
2172 cb((void *)data, OFONO_ERROR_FAILED);
2177 OFono_Pending *ofono_mute_set(Eina_Bool mute, OFono_Simple_Cb cb,
2180 dbus_bool_t dbus_mute = !!mute;
2182 return _ofono_call_volume_property_set("Muted", DBUS_TYPE_BOOLEAN,
2183 &dbus_mute, cb, data);
2186 Eina_Bool ofono_mute_get(void)
2188 OFono_Modem *m = _modem_selected_get();
2189 EINA_SAFETY_ON_NULL_RETURN_VAL(m, EINA_FALSE);
2193 OFono_Pending *ofono_volume_speaker_set(unsigned char volume,
2198 return _ofono_call_volume_property_set("SpeakerVolume", DBUS_TYPE_BYTE,
2202 unsigned char ofono_volume_speaker_get(void)
2204 OFono_Modem *m = _modem_selected_get();
2205 EINA_SAFETY_ON_NULL_RETURN_VAL(m, 0);
2206 return m->speaker_volume;
2209 OFono_Pending *ofono_volume_microphone_set(unsigned char volume,
2213 return _ofono_call_volume_property_set("MicrophoneVolume",
2214 DBUS_TYPE_BYTE, &volume, cb,
2218 unsigned char ofono_volume_microphone_get(void)
2220 OFono_Modem *m = _modem_selected_get();
2221 EINA_SAFETY_ON_NULL_RETURN_VAL(m, 0);
2222 return m->microphone_volume;
2225 OFono_Pending *ofono_tones_send(const char *tones,
2231 OFono_Simple_Cb_Context *ctx = NULL;
2232 OFono_Modem *m = _modem_selected_get();
2234 EINA_SAFETY_ON_NULL_GOTO(m, error_no_dbus_message);
2237 ctx = calloc(1, sizeof(OFono_Simple_Cb_Context));
2238 EINA_SAFETY_ON_NULL_GOTO(ctx, error_no_dbus_message);
2243 msg = dbus_message_new_method_call(
2244 bus_id, m->base.path,
2245 OFONO_PREFIX OFONO_VOICE_IFACE,
2248 goto error_no_dbus_message;
2250 if (!dbus_message_append_args(msg, DBUS_TYPE_STRING, &tones,
2252 goto error_message_args;
2254 INF("SendTones(%s)", tones);
2255 p = _bus_object_message_send(&m->base, msg, _ofono_simple_reply, ctx);
2259 dbus_message_unref(msg);
2261 error_no_dbus_message:
2263 cb((void *)data, OFONO_ERROR_FAILED);
2268 OFono_Pending *ofono_multiparty_create(OFono_Simple_Cb cb,
2271 return _ofono_multiparty("CreateMultiparty", cb, data);
2274 OFono_Pending *ofono_multiparty_hangup(OFono_Simple_Cb cb, const void *data)
2276 return _ofono_multiparty("HangupMultiparty", cb, data);
2279 OFono_Pending *ofono_private_chat(OFono_Call *c, OFono_Simple_Cb cb,
2284 OFono_Simple_Cb_Context *ctx = NULL;
2285 OFono_Modem *m = _modem_selected_get();
2287 EINA_SAFETY_ON_NULL_GOTO(m, error_no_message);
2288 EINA_SAFETY_ON_NULL_GOTO(c, error_no_message);
2291 ctx = calloc(1, sizeof(OFono_Simple_Cb_Context));
2292 EINA_SAFETY_ON_NULL_GOTO(ctx, error_no_message);
2297 msg = dbus_message_new_method_call(
2298 bus_id, m->base.path,
2299 OFONO_PREFIX OFONO_VOICE_IFACE,
2303 goto error_no_message;
2305 if (!dbus_message_append_args(msg, DBUS_TYPE_OBJECT_PATH,
2306 &(c->base.path), DBUS_TYPE_INVALID))
2307 goto error_message_append;
2309 INF("PrivateChat(%s)", c->base.path);
2310 p = _bus_object_message_send(&m->base, msg, _ofono_simple_reply, ctx);
2313 error_message_append:
2314 dbus_message_unref(msg);
2317 cb((void *)data, OFONO_ERROR_FAILED);
2322 static OFono_Callback_List_Modem_Node * _ofono_callback_modem_node_create(
2323 void (*cb)(void *data),const void *data)
2325 OFono_Callback_List_Modem_Node *node_new;
2327 node_new = calloc(1, sizeof(OFono_Callback_List_Modem_Node));
2328 EINA_SAFETY_ON_NULL_RETURN_VAL(node_new, NULL);
2330 node_new->cb_data = data;
2336 OFono_Callback_List_Modem_Node *
2337 ofono_modem_conected_cb_add(void (*cb)(void *data), const void *data)
2339 OFono_Callback_List_Modem_Node *node;
2341 EINA_SAFETY_ON_NULL_RETURN_VAL(cb, NULL);
2342 node = _ofono_callback_modem_node_create(cb, data);
2343 EINA_SAFETY_ON_NULL_RETURN_VAL(node, NULL);
2345 cbs_modem_connected = eina_inlist_append(cbs_modem_connected,
2346 EINA_INLIST_GET(node));
2351 OFono_Callback_List_Modem_Node *
2352 ofono_modem_disconnected_cb_add(void (*cb)(void *data), const void *data)
2354 OFono_Callback_List_Modem_Node *node;
2356 EINA_SAFETY_ON_NULL_RETURN_VAL(cb, NULL);
2357 node = _ofono_callback_modem_node_create(cb, data);
2358 EINA_SAFETY_ON_NULL_RETURN_VAL(node, NULL);
2360 cbs_modem_disconnected = eina_inlist_append(cbs_modem_disconnected,
2361 EINA_INLIST_GET(node));
2366 OFono_Callback_List_Modem_Node *
2367 ofono_modem_changed_cb_add(void (*cb)(void *data), const void *data)
2369 OFono_Callback_List_Modem_Node *node;
2371 EINA_SAFETY_ON_NULL_RETURN_VAL(cb, NULL);
2372 node = _ofono_callback_modem_node_create(cb, data);
2373 EINA_SAFETY_ON_NULL_RETURN_VAL(node, NULL);
2375 cbs_modem_changed = eina_inlist_append(cbs_modem_changed,
2376 EINA_INLIST_GET(node));
2381 static void _ofono_callback_modem_list_delete(Eina_Inlist **list,
2382 OFono_Callback_List_Modem_Node *node)
2384 EINA_SAFETY_ON_NULL_RETURN(*list);
2385 *list = eina_inlist_remove(*list, EINA_INLIST_GET(node));
2389 void ofono_modem_changed_cb_del(OFono_Callback_List_Modem_Node *node)
2391 EINA_SAFETY_ON_NULL_RETURN(node);
2392 _ofono_callback_modem_list_delete(&cbs_modem_changed, node);
2395 void ofono_modem_disconnected_cb_del(OFono_Callback_List_Modem_Node *node)
2397 EINA_SAFETY_ON_NULL_RETURN(node);
2398 _ofono_callback_modem_list_delete(&cbs_modem_disconnected, node);
2401 void ofono_modem_connected_cb_del(OFono_Callback_List_Modem_Node *node)
2403 EINA_SAFETY_ON_NULL_RETURN(node);
2404 _ofono_callback_modem_list_delete(&cbs_modem_connected, node);
2407 static OFono_Callback_List_Call_Node *_ofono_callback_call_node_create(
2408 void (*cb)(void *data, OFono_Call *call),const void *data)
2410 OFono_Callback_List_Call_Node *node;
2412 node = calloc(1, sizeof(OFono_Callback_List_Call_Node));
2413 EINA_SAFETY_ON_NULL_RETURN_VAL(node, NULL);
2415 node->cb_data = data;
2421 static OFono_Callback_List_Call_Disconnected_Node *
2422 _ofono_callback_call_disconnected_node_create(
2423 void (*cb)(void *data, OFono_Call *call, const char *reason),
2426 OFono_Callback_List_Call_Disconnected_Node *node;
2428 node = calloc(1, sizeof(OFono_Callback_List_Call_Disconnected_Node));
2429 EINA_SAFETY_ON_NULL_RETURN_VAL(node, NULL);
2431 node->cb_data = data;
2437 OFono_Callback_List_Call_Node *ofono_call_added_cb_add(
2438 void (*cb)(void *data,OFono_Call *call), const void *data)
2440 OFono_Callback_List_Call_Node *node;
2442 EINA_SAFETY_ON_NULL_RETURN_VAL(cb, NULL);
2443 node = _ofono_callback_call_node_create(cb, data);
2444 EINA_SAFETY_ON_NULL_RETURN_VAL(node, NULL);
2446 cbs_call_added = eina_inlist_append(cbs_call_added,
2447 EINA_INLIST_GET(node));
2452 OFono_Callback_List_Call_Node *ofono_call_removed_cb_add(
2453 void (*cb)(void *data, OFono_Call *call), const void *data)
2455 OFono_Callback_List_Call_Node *node;
2457 EINA_SAFETY_ON_NULL_RETURN_VAL(cb, NULL);
2458 node = _ofono_callback_call_node_create(cb, data);
2459 EINA_SAFETY_ON_NULL_RETURN_VAL(node, NULL);
2461 cbs_call_removed = eina_inlist_append(cbs_call_removed,
2462 EINA_INLIST_GET(node));
2467 OFono_Callback_List_Call_Node *ofono_call_changed_cb_add(
2468 void (*cb)(void *data, OFono_Call *call), const void *data)
2470 OFono_Callback_List_Call_Node *node;
2472 EINA_SAFETY_ON_NULL_RETURN_VAL(cb, NULL);
2473 node = _ofono_callback_call_node_create(cb, data);
2474 EINA_SAFETY_ON_NULL_RETURN_VAL(node, NULL);
2476 cbs_call_changed = eina_inlist_append(cbs_call_changed,
2477 EINA_INLIST_GET(node));
2482 OFono_Callback_List_Call_Disconnected_Node *ofono_call_disconnected_cb_add(
2483 void (*cb)(void *data, OFono_Call *call, const char *reason),
2486 OFono_Callback_List_Call_Disconnected_Node *node;
2488 EINA_SAFETY_ON_NULL_RETURN_VAL(cb, NULL);
2489 node = _ofono_callback_call_disconnected_node_create(cb, data);
2490 EINA_SAFETY_ON_NULL_RETURN_VAL(node, NULL);
2492 cbs_call_disconnected = eina_inlist_append(cbs_call_disconnected,
2493 EINA_INLIST_GET(node));
2498 static void _ofono_callback_call_list_delete(Eina_Inlist **list,
2499 OFono_Callback_List_Call_Node *node)
2501 EINA_SAFETY_ON_NULL_RETURN(*list);
2502 *list = eina_inlist_remove(*list, EINA_INLIST_GET(node));
2506 void ofono_call_changed_cb_del(OFono_Callback_List_Call_Node *node)
2508 EINA_SAFETY_ON_NULL_RETURN(node);
2509 _ofono_callback_call_list_delete(&cbs_call_changed, node);
2512 void ofono_call_disconnected_cb_del(
2513 OFono_Callback_List_Call_Disconnected_Node *node)
2515 EINA_SAFETY_ON_NULL_RETURN(node);
2516 EINA_SAFETY_ON_NULL_RETURN(cbs_call_disconnected);
2517 cbs_call_disconnected = eina_inlist_remove(cbs_call_disconnected,
2518 EINA_INLIST_GET(node));
2522 void ofono_call_added_cb_del(OFono_Callback_List_Call_Node *node)
2524 EINA_SAFETY_ON_NULL_RETURN(node);
2525 _ofono_callback_call_list_delete(&cbs_call_added, node);
2528 void ofono_call_removed_cb_del(OFono_Callback_List_Call_Node *node)
2530 EINA_SAFETY_ON_NULL_RETURN(node);
2531 _ofono_callback_call_list_delete(&cbs_call_removed, node);