Signed-off-by: Andras Domokos <andras.domo...@nokia.com> --- include/voicecall.h | 12 +++ src/voicecall.c | 221 ++++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 215 insertions(+), 18 deletions(-)
diff --git a/include/voicecall.h b/include/voicecall.h index 2356fcf..d530148 100644 --- a/include/voicecall.h +++ b/include/voicecall.h @@ -38,6 +38,9 @@ typedef void (*ofono_call_list_cb_t)(const struct ofono_error *error, const struct ofono_call *call_list, void *data); +typedef void (*ofono_voicecall_emergency_notify_cb_t)(ofono_bool_t state, + void *data); + /* Voice call related functionality, including ATD, ATA, +CHLD, CTFR, CLCC * and VTS. * @@ -116,6 +119,15 @@ void ofono_voicecall_set_data(struct ofono_voicecall *vc, void *data); void *ofono_voicecall_get_data(struct ofono_voicecall *vc); int ofono_voicecall_get_next_callid(struct ofono_voicecall *vc); +unsigned int __ofono_voicecall_add_emergency_watch(struct ofono_voicecall *vc, + ofono_voicecall_emergency_notify_cb_t notify, + void *data, ofono_destroy_func destroy); +void __ofono_voicecall_remove_emergency_watch(struct ofono_voicecall *vc, + unsigned int id); +ofono_bool_t ofono_voicecall_get_emergency_state(struct ofono_voicecall *vc); +void __ofono_voicecall_set_emergency_state(struct ofono_voicecall *vc, + int state); + #ifdef __cplusplus } #endif diff --git a/src/voicecall.c b/src/voicecall.c index 7b5fe3b..a619b30 100644 --- a/src/voicecall.c +++ b/src/voicecall.c @@ -25,6 +25,7 @@ #include <string.h> #include <stdio.h> +#include <stdlib.h> #include <time.h> #include <errno.h> #include <stdint.h> @@ -56,6 +57,9 @@ struct ofono_voicecall { void *driver_data; struct ofono_atom *atom; struct dial_request *dial_req; + struct ofono_watchlist *emergency_watches; + unsigned int emergency_state; + unsigned int modem_state_watch; }; struct voicecall { @@ -85,6 +89,8 @@ static const char *default_en_list_no_sim[] = { "119", "118", "999", "110", static void generic_callback(const struct ofono_error *error, void *data); static void multirelease_callback(const struct ofono_error *err, void *data); +static const char *voicecall_build_path(struct ofono_voicecall *vc, + const struct ofono_call *call); static gint call_compare_by_id(gconstpointer a, gconstpointer b) { @@ -121,6 +127,145 @@ static void add_to_en_list(GSList **l, const char **list) *l = g_slist_prepend(*l, g_strdup(list[i++])); } +static gint number_compare(gconstpointer a, gconstpointer b) +{ + const char *s1 = a, *s2 = b; + return strcmp(s1, s2); +} + +static ofono_bool_t emergency_number(struct ofono_voicecall *vc, + const char *number) +{ + if (!number) + return FALSE; + + return g_slist_find_custom(vc->en_list, + number, number_compare) ? TRUE : FALSE; +} + +static void notify_emergency_watches(struct ofono_voicecall *vc, + ofono_bool_t state) +{ + struct ofono_watchlist_item *item; + GSList *l; + ofono_voicecall_emergency_notify_cb_t notify; + + if (vc->emergency_watches == NULL) + return; + + for (l = vc->emergency_watches->items; l; l = l->next) { + item = l->data; + notify = item->notify; + notify(state, item->notify_data); + } +} + +unsigned int __ofono_voicecall_add_emergency_watch(struct ofono_voicecall *vc, + ofono_voicecall_emergency_notify_cb_t notify, + void *data, ofono_destroy_func destroy) +{ + struct ofono_watchlist_item *item; + + if (vc == NULL || notify == NULL) + return 0; + + item = g_new0(struct ofono_watchlist_item, 1); + + item->notify = notify; + item->destroy = destroy; + item->notify_data = data; + + return __ofono_watchlist_add_item(vc->emergency_watches, item); +} + +void __ofono_voicecall_remove_emergency_watch(struct ofono_voicecall *vc, + unsigned int id) +{ + __ofono_watchlist_remove_item(vc->emergency_watches, id); +} + +ofono_bool_t ofono_voicecall_get_emergency_state(struct ofono_voicecall *vc) +{ + return vc->emergency_state ? 1 : 0; +} + +void __ofono_voicecall_inc_emergency_state(struct ofono_voicecall *vc) +{ + DBusConnection *conn = ofono_dbus_get_connection(); + const char *path = __ofono_atom_get_path(vc->atom); + gboolean state = TRUE; + + if (!vc->emergency_state++) { + ofono_dbus_signal_property_changed(conn, path, + OFONO_VOICECALL_INTERFACE, + "EmergencyMode", + DBUS_TYPE_BOOLEAN, + &state); + notify_emergency_watches(vc, state); + } +} + +void __ofono_voicecall_dec_emergency_state(struct ofono_voicecall *vc) +{ + DBusConnection *conn = ofono_dbus_get_connection(); + const char *path = __ofono_atom_get_path(vc->atom); + gboolean state = FALSE; + + if (!--vc->emergency_state) { + ofono_dbus_signal_property_changed(conn, path, + OFONO_VOICECALL_INTERFACE, + "EmergencyMode", + DBUS_TYPE_BOOLEAN, + &state); + notify_emergency_watches(vc, state); + } +} + +static ofono_bool_t clir_string_to_clir(const char *clirstr, + enum ofono_clir_option *clir); +static void manager_dial_callback(const struct ofono_error *error, void *data); +static void modem_state_watch(enum ofono_modem_state state, void *data) +{ + struct ofono_voicecall *vc = data; + struct ofono_modem *modem = __ofono_atom_get_modem(vc->atom); + DBusMessage *reply; + const char *number; + struct ofono_phone_number ph; + const char *clirstr; + enum ofono_clir_option clir; + + if (!vc->pending) + return; + + if (strcmp(dbus_message_get_member(vc->pending), "Dial")) + return; + + if (dbus_message_get_args(vc->pending, NULL, DBUS_TYPE_STRING, &number, + DBUS_TYPE_STRING, &clirstr, + DBUS_TYPE_INVALID) == FALSE) { + reply = __ofono_error_invalid_args(vc->pending); + __ofono_dbus_pending_reply(&vc->pending, reply); + return; + } + + /* don't care here about non-emergency calls */ + if (!emergency_number(vc, number)) + return; + + if (!ofono_modem_get_online(modem)) { + reply = __ofono_error_failed(vc->pending); + __ofono_dbus_pending_reply(&vc->pending, reply); + __ofono_voicecall_dec_emergency_state(vc); + return; + } + + clir_string_to_clir(clirstr, &clir); + string_to_phone_number(number, &ph); + + vc->driver->dial(vc, &ph, clir, OFONO_CUG_OPTION_DEFAULT, + manager_dial_callback, vc); +} + static const char *disconnect_reason_to_string(enum ofono_disconnect_reason r) { switch (r) { @@ -718,7 +863,8 @@ static gboolean voicecalls_can_dtmf(struct ofono_voicecall *vc) return FALSE; } -static gboolean voicecalls_have_with_status(struct ofono_voicecall *vc, int status) +static gboolean voicecalls_have_with_status(struct ofono_voicecall *vc, + int status) { GSList *l; struct voicecall *v; @@ -918,6 +1064,7 @@ static DBusMessage *manager_get_properties(DBusConnection *conn, int i; GSList *l; char **list; + ofono_bool_t emergency_state; reply = dbus_message_new_method_return(msg); @@ -930,6 +1077,10 @@ static DBusMessage *manager_get_properties(DBusConnection *conn, OFONO_PROPERTIES_ARRAY_SIGNATURE, &dict); + emergency_state = ofono_voicecall_get_emergency_state(vc); + ofono_dbus_dict_append(&dict, "EmergencyMode", + DBUS_TYPE_BOOLEAN, &emergency_state); + /* property EmergencyNumbers */ list = g_new0(char *, g_slist_length(vc->en_list) + 1); @@ -1066,8 +1217,11 @@ static void manager_dial_callback(const struct ofono_error *error, void *data) dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID); - } else + } else { + if (emergency_number(vc, number)) + __ofono_voicecall_dec_emergency_state(vc); reply = __ofono_error_failed(vc->pending); + } __ofono_dbus_pending_reply(&vc->pending, reply); @@ -1118,6 +1272,14 @@ static DBusMessage *manager_dial(DBusConnection *conn, string_to_phone_number(number, &ph); + if (emergency_number(vc, number)) { + struct ofono_modem *modem = __ofono_atom_get_modem(vc->atom); + ofono_bool_t online = ofono_modem_get_online(modem); + __ofono_voicecall_inc_emergency_state(vc); + if (!online) + return NULL; + } + vc->driver->dial(vc, &ph, clir, OFONO_CUG_OPTION_DEFAULT, manager_dial_callback, vc); @@ -1667,7 +1829,7 @@ void ofono_voicecall_disconnected(struct ofono_voicecall *vc, int id, { struct ofono_modem *modem = __ofono_atom_get_modem(vc->atom); GSList *l; - struct voicecall *call; + struct voicecall *v; time_t ts; enum call_status prev_status; @@ -1684,48 +1846,52 @@ void ofono_voicecall_disconnected(struct ofono_voicecall *vc, int id, return; } - call = l->data; + v = l->data; ts = time(NULL); - prev_status = call->call->status; + prev_status = v->call->status; l = g_slist_find_custom(vc->multiparty_list, GUINT_TO_POINTER(id), call_compare_by_id); if (l) { vc->multiparty_list = - g_slist_remove(vc->multiparty_list, call); + g_slist_remove(vc->multiparty_list, v); if (vc->multiparty_list->next == NULL) { /* Size == 1 */ - struct voicecall *v = vc->multiparty_list->data; + struct voicecall *v2 = vc->multiparty_list->data; - voicecall_emit_multiparty(v, FALSE); + voicecall_emit_multiparty(v2, FALSE); g_slist_free(vc->multiparty_list); vc->multiparty_list = 0; } } - vc->release_list = g_slist_remove(vc->release_list, call); + vc->release_list = g_slist_remove(vc->release_list, v); if (reason != OFONO_DISCONNECT_REASON_UNKNOWN) - voicecall_emit_disconnect_reason(call, reason); + voicecall_emit_disconnect_reason(v, reason); - voicecall_set_call_status(call, CALL_STATUS_DISCONNECTED); + voicecall_set_call_status(v, CALL_STATUS_DISCONNECTED); - if (!call->untracked) { + if (!v->untracked) { if (prev_status == CALL_STATUS_INCOMING || prev_status == CALL_STATUS_WAITING) - __ofono_history_call_missed(modem, call->call, ts); + __ofono_history_call_missed(modem, v->call, ts); else - __ofono_history_call_ended(modem, call->call, - call->detect_time, ts); + __ofono_history_call_ended(modem, v->call, + v->detect_time, ts); } - voicecalls_emit_call_removed(vc, call); + voicecalls_emit_call_removed(vc, v); + + if (emergency_number(vc, + phone_number_to_string(&v->call->phone_number))) + __ofono_voicecall_dec_emergency_state(vc); - voicecall_dbus_unregister(vc, call); + voicecall_dbus_unregister(vc, v); - vc->call_list = g_slist_remove(vc->call_list, call); + vc->call_list = g_slist_remove(vc->call_list, v); } void ofono_voicecall_notify(struct ofono_voicecall *vc, @@ -1969,6 +2135,9 @@ static void voicecall_unregister(struct ofono_atom *atom) vc->sim_watch = 0; } + __ofono_watchlist_free(vc->emergency_watches); + vc->emergency_watches = NULL; + if (vc->dial_req) dial_request_finish(vc); @@ -1985,6 +2154,7 @@ static void voicecall_unregister(struct ofono_atom *atom) static void voicecall_remove(struct ofono_atom *atom) { struct ofono_voicecall *vc = __ofono_atom_get_data(atom); + struct ofono_modem *modem = __ofono_atom_get_modem(atom); DBG("atom: %p", atom); @@ -2012,6 +2182,11 @@ static void voicecall_remove(struct ofono_atom *atom) vc->sim = NULL; } + if (vc->modem_state_watch) { + __ofono_modem_remove_state_watch(modem, vc->modem_state_watch); + vc->modem_state_watch = 0; + } + g_free(vc); } @@ -2122,6 +2297,10 @@ void ofono_voicecall_register(struct ofono_voicecall *vc) } ofono_modem_add_interface(modem, OFONO_VOICECALL_MANAGER_INTERFACE); + vc->emergency_watches = __ofono_watchlist_new(g_free); + vc->modem_state_watch = __ofono_modem_add_state_watch(modem, + modem_state_watch, + vc, NULL); /* * Start out with the 22.101 mandated numbers, if we have a SIM and @@ -2208,6 +2387,9 @@ static void dial_request_cb(const struct ofono_error *error, void *data) if (v == NULL) { dial_request_finish(vc); + if (emergency_number(vc, + phone_number_to_string(&vc->dial_req->ph))) + __ofono_voicecall_inc_emergency_state(vc); return; } @@ -2233,6 +2415,9 @@ static void dial_request_cb(const struct ofono_error *error, void *data) static void dial_request(struct ofono_voicecall *vc) { + if (emergency_number(vc, phone_number_to_string(&vc->dial_req->ph))) + __ofono_voicecall_inc_emergency_state(vc); + vc->driver->dial(vc, &vc->dial_req->ph, OFONO_CLIR_OPTION_DEFAULT, OFONO_CUG_OPTION_DEFAULT, dial_request_cb, vc); } -- 1.7.0.4 _______________________________________________ ofono mailing list ofono@ofono.org http://lists.ofono.org/listinfo/ofono