---
src/call-forwarding.c | 266 +++++++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 260 insertions(+), 6 deletions(-)
diff --git a/src/call-forwarding.c b/src/call-forwarding.c
index ce03c40..bb345a6 100644
--- a/src/call-forwarding.c
+++ b/src/call-forwarding.c
@@ -34,6 +34,7 @@
#include "ofono.h"
#include "common.h"
+#include "simutil.h"
#define CALL_FORWARDING_FLAG_CACHED 0x1
@@ -58,6 +59,12 @@ struct ofono_call_forwarding {
int query_next;
int query_end;
struct cf_ss_request *ss_req;
+ struct ofono_sim *sim;
+ unsigned char cfis_record_id;
+ unsigned char cfis_indicator;
+ ofono_bool_t cphs_cff_present;
+ ofono_bool_t status_on_sim;
+ ofono_bool_t online;
struct ofono_ussd *ussd;
unsigned int ussd_watch;
const struct ofono_call_forwarding_driver *driver;
@@ -202,6 +209,85 @@ static const char *cf_type_lut[] = {
"AllConditional"
};
+static void sim_cfis_update_cb(int ok, void *data)
+{
+ if (!ok)
+ ofono_info("Failed to update EFcfis");
+}
+
+static void sim_cphs_cff_update_cb(int ok, void *data)
+{
+ if (!ok)
+ ofono_info("Failed to update EFcphs-cff");
+}
+
+static void sim_set_cf_indicator(struct ofono_call_forwarding *cf)
+{
+ gboolean cfu_voice = FALSE;
+ struct ofono_call_forwarding_condition *cond = NULL;
+ GSList *l;
+
+ /*
+ * For now we only support Voice, although Fax & all Data
+ * basic services are applicable as well.
+ */
+ for (l = cf->cf_conditions[0]; l; l = l->next) {
+ cond = l->data;
+
+ if ((cond->cls & BEARER_CLASS_VOICE) &&
+ (strlen(cond->phone_number.number) > 0)) {
+ cfu_voice = TRUE;
+ break;
+ }
+ }
+
+ if (cfu_voice == cf->status_on_sim)
+ return;
+
+ cf->status_on_sim = cfu_voice;
+
+ if (cf->cfis_record_id) {
+ unsigned char data[16];
+ int number_len;
+
+ memset(data, 0xff, sizeof(data));
+
+ /* Profile Identifier */
+ data[0] = 0x01;
+
+ if (cfu_voice) {
+ number_len = strlen(cond->phone_number.number);
+
+ /* CFU indicator Status - Voice */
+ data[1] = (cf->cfis_indicator |= 0x01);
+ number_len = (number_len + 1) / 2;
+ data[2] = number_len + 1;
+ data[3] = cond->phone_number.type;
+
+ sim_encode_bcd_number(cond->phone_number.number,
+ data + 4);
+
+ } else
+ data[1] = (cf->cfis_indicator &= 0xFE);
+
+ ofono_sim_write(cf->sim, SIM_EFCFIS_FILEID,
+ sim_cfis_update_cb,
+ OFONO_SIM_FILE_STRUCTURE_FIXED,
+ cf->cfis_record_id, data,
+ sizeof(data), cf);
+ return;
+ }
+
+ if (cf->cphs_cff_present) {
+ unsigned char cff_voice = cfu_voice ? 0x0A : 0x05;
+
+ ofono_sim_write(cf->sim, SIM_EF_CPHS_CFF_FILEID,
+ sim_cphs_cff_update_cb,
+ OFONO_SIM_FILE_STRUCTURE_TRANSPARENT,
+ 0, &cff_voice, sizeof(cff_voice), cf);
+ }
+}
+
static void set_new_cond_list(struct ofono_call_forwarding *cf,
int type, GSList *list)
{
@@ -372,6 +458,7 @@ static DBusMessage *cf_get_properties_reply(DBusMessage
*msg,
DBusMessageIter iter;
DBusMessageIter dict;
int i;
+ dbus_bool_t status;
reply = dbus_message_new_method_return(msg);
@@ -384,10 +471,21 @@ static DBusMessage *cf_get_properties_reply(DBusMessage
*msg,
OFONO_PROPERTIES_ARRAY_SIGNATURE,
&dict);
- for (i = 0; i < 4; i++)
- property_append_cf_conditions(&dict, cf->cf_conditions[i],
+ if (cf->online == TRUE) {
+ for (i = 0; i < 4; i++)
+ property_append_cf_conditions(&dict,
+ cf->cf_conditions[i],
BEARER_CLASS_VOICE,
cf_type_lut[i]);
+ } else if (cf->status_on_sim == TRUE)
+ property_append_cf_conditions(&dict,
+ cf->cf_conditions[CALL_FORWARDING_TYPE_UNCONDITIONAL],
+ BEARER_CLASS_VOICE,
+ cf_type_lut[CALL_FORWARDING_TYPE_UNCONDITIONAL]);
+
+ status = cf->status_on_sim;
+ ofono_dbus_dict_append(&dict, "ForwardingFlagOnSim", DBUS_TYPE_BOOLEAN,
+ &status);
dbus_message_iter_close_container(&iter, &dict);
@@ -413,7 +511,15 @@ static void get_query_cf_callback(const struct ofono_error
*error, int total,
}
if (cf->query_next == CALL_FORWARDING_TYPE_NOT_REACHABLE) {
- DBusMessage *reply = cf_get_properties_reply(cf->pending, cf);
+ DBusMessage *reply;
+
+ /*
+ * This is to make sure the information received from
+ * network is in sync with the information present in SIM/USIM
+ */
+ sim_set_cf_indicator(cf);
+
+ reply = cf_get_properties_reply(cf->pending, cf);
__ofono_dbus_pending_reply(&cf->pending, reply);
return;
}
@@ -433,7 +539,8 @@ static DBusMessage *cf_get_properties(DBusConnection *conn,
DBusMessage *msg,
{
struct ofono_call_forwarding *cf = data;
- if (cf->flags & CALL_FORWARDING_FLAG_CACHED)
+ if ((cf->flags & CALL_FORWARDING_FLAG_CACHED) ||
+ cf->online == FALSE)
return cf_get_properties_reply(msg, cf);
if (!cf->driver->query)
@@ -536,7 +643,8 @@ static void set_query_cf_callback(const struct ofono_error
*error, int total,
if (cf->query_next != cf->query_end) {
cf->query_next++;
set_query_next_cf_cond(cf);
- }
+ } else
+ sim_set_cf_indicator(cf);
}
static void set_query_next_cf_cond(struct ofono_call_forwarding *cf)
@@ -597,6 +705,9 @@ static DBusMessage *cf_set_property(DBusConnection *conn,
DBusMessage *msg,
int cls;
int type;
+ if (cf->online == FALSE)
+ return __ofono_error_not_available(msg);
+
if (__ofono_call_forwarding_is_busy(cf) ||
__ofono_ussd_is_busy(cf->ussd))
return __ofono_error_busy(msg);
@@ -864,7 +975,8 @@ static void ss_set_query_cf_callback(const struct
ofono_error *error, int total,
if (cf->query_next != cf->query_end) {
cf->query_next++;
ss_set_query_next_cf_cond(cf);
- }
+ } else
+ sim_set_cf_indicator(cf);
}
static void ss_set_query_next_cf_cond(struct ofono_call_forwarding *cf)
@@ -1112,6 +1224,128 @@ gboolean __ofono_call_forwarding_is_busy(struct
ofono_call_forwarding *cf)
return cf->pending ? TRUE : FALSE;
}
+static void sim_cfis_read_cb(int ok, int total_length, int record,
+ const unsigned char *data,
+ int record_length, void *userdata)
+{
+ struct ofono_call_forwarding *cf = userdata;
+ DBusConnection *conn = ofono_dbus_get_connection();
+ const char *path = __ofono_atom_get_path(cf->atom);
+
+ if (!ok || record_length < 16 || total_length < record_length) {
+ cf->cfis_indicator = 0;
+ cf->cfis_record_id = 0;
+ return;
+ }
+
+ /*
+ * Multiple Subscriber Profile number which can have values 1-4.
+ * Profile id 1 is assumed as the current profile.
+ */
+ if (data[0] != 1)
+ return;
+
+ cf->cfis_record_id = record;
+
+ /* CFU indicator status */
+ cf->cfis_indicator = data[1];
+
+ /*
+ * For now we only support Voice, although Fax & all Data
+ * basic services are applicable as well.
+ */
+ if (cf->cfis_indicator & 0x01) {
+ int ton_npi;
+ int number_len;
+ const char *number;
+ char attr[64];
+ struct ofono_call_forwarding_condition *cond;
+ GSList *l = NULL;
+ dbus_bool_t status;
+
+ number_len = data[2];
+ ton_npi = data[3];
+
+ if (number_len > 11 || ton_npi == 0xff)
+ return;
+
+ cond = g_try_new0(struct ofono_call_forwarding_condition, 1);
+ if (cond == NULL)
+ return;
+
+ status = cf->status_on_sim = TRUE;
+ cond->status = status;
+ cond->cls = BEARER_CLASS_VOICE;
+ cond->time = 0;
+ cond->phone_number.type = ton_npi;
+
+ sim_extract_bcd_number(data + 4, number_len - 1,
+ cond->phone_number.number);
+ number = phone_number_to_string(&cond->phone_number);
+
+ snprintf(attr, sizeof(attr), "%s%s",
+ bearer_class_to_string(BEARER_CLASS_VOICE),
+ cf_type_lut[CALL_FORWARDING_TYPE_UNCONDITIONAL]);
+
+ cf->cf_conditions[CALL_FORWARDING_TYPE_UNCONDITIONAL] =
+ g_slist_append(l, cond);
+
+ ofono_dbus_signal_property_changed(conn, path,
+ OFONO_CALL_FORWARDING_INTERFACE,
+ attr, DBUS_TYPE_STRING,
+ &number);
+
+ ofono_dbus_signal_property_changed(conn, path,
+ OFONO_CALL_FORWARDING_INTERFACE,
+ "ForwardingFlagOnSim",
+ DBUS_TYPE_BOOLEAN,
+ &status);
+ }
+}
+
+static void sim_cphs_cff_read_cb(int ok, int total_length, int record,
+ const unsigned char *data,
+ int record_length, void *userdata)
+{
+ struct ofono_call_forwarding *cf = userdata;
+ DBusConnection *conn = ofono_dbus_get_connection();
+ const char *path = __ofono_atom_get_path(cf->atom);
+ dbus_bool_t cfu_voice;
+
+ if (!ok || total_length < 1) {
+ cf->cphs_cff_present = FALSE;
+ return;
+ }
+
+ cf->cphs_cff_present = TRUE;
+
+ /*
+ * For now we only support Voice, although Fax & all Data
+ * basic services are applicable as well.
+ */
+ cfu_voice = cf->status_on_sim = ((data[0] & 0xf) == 0xa);
+
+ ofono_dbus_signal_property_changed(conn, path,
+ OFONO_CALL_FORWARDING_INTERFACE,
+ "ForwardingFlagOnSim",
+ DBUS_TYPE_BOOLEAN,
+ &cfu_voice);
+}
+
+static void sim_read_cf_indicator(struct ofono_call_forwarding *cf)
+{
+ if (__ofono_sim_service_available(cf->sim,
+ SIM_UST_SERVICE_CFIS,
+ SIM_SST_SERVICE_CFIS) == TRUE)
+ ofono_sim_read(cf->sim, SIM_EFCFIS_FILEID,
+ OFONO_SIM_FILE_STRUCTURE_FIXED,
+ sim_cfis_read_cb, cf);
+ else
+ ofono_sim_read(cf->sim, SIM_EF_CPHS_CFF_FILEID,
+ OFONO_SIM_FILE_STRUCTURE_TRANSPARENT,
+ sim_cphs_cff_read_cb, cf);
+}
+
int ofono_call_forwarding_driver_register(const struct
ofono_call_forwarding_driver *d)
{
DBG("driver: %p, name: %s", d, d->name);
@@ -1201,6 +1435,13 @@ struct ofono_call_forwarding
*ofono_call_forwarding_create(struct ofono_modem *m
return cf;
}
+static void modem_online_status_changed(ofono_bool_t online, void *data)
+{
+ struct ofono_call_forwarding *cf = data;
+
+ cf->online = online;
+}
+
static void ussd_watch(struct ofono_atom *atom,
enum ofono_atom_watch_condition cond, void *data)
{
@@ -1220,6 +1461,7 @@ void ofono_call_forwarding_register(struct
ofono_call_forwarding *cf)
DBusConnection *conn = ofono_dbus_get_connection();
const char *path = __ofono_atom_get_path(cf->atom);
struct ofono_modem *modem = __ofono_atom_get_modem(cf->atom);
+ struct ofono_atom *sim_atom;
struct ofono_atom *ussd_atom;
if (!g_dbus_register_interface(conn, path,
@@ -1234,6 +1476,18 @@ void ofono_call_forwarding_register(struct
ofono_call_forwarding *cf)
ofono_modem_add_interface(modem, OFONO_CALL_FORWARDING_INTERFACE);
+ sim_atom = __ofono_modem_find_atom(modem, OFONO_ATOM_TYPE_SIM);
+
+ if (sim_atom) {
+ cf->sim = __ofono_atom_get_data(sim_atom);
+
+ if (ofono_sim_get_state(cf->sim) == OFONO_SIM_STATE_READY)
+ sim_read_cf_indicator(cf);
+ }
+
+ __ofono_modem_add_online_watch(modem, modem_online_status_changed,
+ cf, NULL);
+
cf->ussd_watch = __ofono_modem_add_atom_watch(modem,
OFONO_ATOM_TYPE_USSD,
ussd_watch, cf, NULL);
--
1.7.0.4
_______________________________________________
ofono mailing list
[email protected]
http://lists.ofono.org/listinfo/ofono