summaryrefslogtreecommitdiffstats
path: root/src/call-settings.c
diff options
context:
space:
mode:
authorDenis Kenzior <denkenz@gmail.com>2009-05-28 13:50:25 -0500
committerDenis Kenzior <denkenz@gmail.com>2009-05-28 18:28:40 -0500
commit699752eaf15c97e8ea53cfd24dd0e19549ffd712 (patch)
tree89b454618fed92ada6561accd77c3d14b2387063 /src/call-settings.c
parent99b01eba7f103aa76d90a93905175d0c11fb8f8a (diff)
downloadofono-699752eaf15c97e8ea53cfd24dd0e19549ffd712.tar.bz2
Squash CallWaiting onto CallSettings interface
The CallWaiting interface had one settable attribute after the latest set of refactoring. Squash it onto the CallSettings interface where it belonged in the first place
Diffstat (limited to 'src/call-settings.c')
-rw-r--r--src/call-settings.c380
1 files changed, 365 insertions, 15 deletions
diff --git a/src/call-settings.c b/src/call-settings.c
index c540baa9..97f4124a 100644
--- a/src/call-settings.c
+++ b/src/call-settings.c
@@ -25,6 +25,7 @@
#include <string.h>
#include <stdio.h>
+#include <stdlib.h>
#include <dbus/dbus.h>
#include <glib.h>
@@ -42,6 +43,14 @@
#define CALL_SETTINGS_FLAG_CACHED 0x1
+enum call_setting_type {
+ CALL_SETTING_TYPE_CLIP = 0,
+ CALL_SETTING_TYPE_COLP,
+ CALL_SETTING_TYPE_COLR,
+ CALL_SETTING_TYPE_CLIR,
+ CALL_SETTING_TYPE_CW
+};
+
struct call_settings_data {
struct ofono_call_settings_ops *ops;
int clir;
@@ -49,17 +58,12 @@ struct call_settings_data {
int clip;
int colp;
int clir_setting;
+ int cw;
int flags;
DBusMessage *pending;
int ss_req_type;
- int call_setting_type;
-};
-
-enum call_setting_type {
- CALL_SETTING_TYPE_CLIP = 0,
- CALL_SETTING_TYPE_COLP,
- CALL_SETTING_TYPE_COLR,
- CALL_SETTING_TYPE_CLIR
+ int ss_req_cls;
+ enum call_setting_type ss_setting;
};
static void cs_register_ss_controls(struct ofono_modem *modem);
@@ -215,6 +219,36 @@ static void set_colr(struct ofono_modem *modem, int colr)
}
}
+static void set_cw(struct ofono_modem *modem, int new_cw, int mask)
+{
+ struct call_settings_data *cs = modem->call_settings;
+ DBusConnection *conn = dbus_gsm_connection();
+ char buf[64];
+ int j;
+ const char *value;
+
+ for (j = 1; j <= BEARER_CLASS_PAD; j = j << 1) {
+ if ((j & mask) == 0)
+ continue;
+
+ if ((cs->cw & j) == (new_cw & j))
+ continue;
+
+ if (new_cw & j)
+ value = "enabled";
+ else
+ value = "disabled";
+
+ sprintf(buf, "%sCallWaiting", bearer_class_to_string(j));
+ dbus_gsm_signal_property_changed(conn, modem->path,
+ CALL_SETTINGS_INTERFACE,
+ buf, DBUS_TYPE_STRING,
+ &value);
+ }
+
+ cs->cw = new_cw;
+}
+
static struct call_settings_data *call_settings_create()
{
struct call_settings_data *r;
@@ -243,6 +277,190 @@ static void call_settings_destroy(gpointer data)
g_free(cs);
}
+static void property_append_cw_conditions(DBusMessageIter *dict,
+ int conditions, int mask)
+{
+ int i;
+ char prop[128];
+ const char *value;
+
+ for (i = 1; i <= BEARER_CLASS_PAD; i = i << 1) {
+ if (!(mask & i))
+ continue;
+
+ sprintf(prop, "%sCallWaiting", bearer_class_to_string(i));
+
+ if (conditions & i)
+ value = "enabled";
+ else
+ value = "disabled";
+
+ dbus_gsm_dict_append(dict, prop, DBUS_TYPE_STRING, &value);
+ }
+}
+
+static void generate_cw_ss_query_reply(struct ofono_modem *modem)
+{
+ struct call_settings_data *cs = modem->call_settings;
+ const char *sig = "(sa{sv})";
+ const char *ss_type = ss_control_type_to_string(cs->ss_req_type);
+ const char *context = "CallWaiting";
+ DBusMessageIter iter;
+ DBusMessageIter var;
+ DBusMessageIter vstruct;
+ DBusMessageIter dict;
+ DBusMessage *reply;
+
+ reply = dbus_message_new_method_return(cs->pending);
+
+ dbus_message_iter_init_append(reply, &iter);
+
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &context);
+
+ dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT, sig, &var);
+
+ dbus_message_iter_open_container(&var, DBUS_TYPE_STRUCT, NULL,
+ &vstruct);
+
+ dbus_message_iter_append_basic(&vstruct, DBUS_TYPE_STRING,
+ &ss_type);
+
+ dbus_message_iter_open_container(&vstruct, DBUS_TYPE_ARRAY,
+ PROPERTIES_ARRAY_SIGNATURE, &dict);
+
+ property_append_cw_conditions(&dict, cs->cw, cs->ss_req_cls);
+
+ dbus_message_iter_close_container(&vstruct, &dict);
+
+ dbus_message_iter_close_container(&var, &vstruct);
+
+ dbus_message_iter_close_container(&iter, &var);
+
+ dbus_gsm_pending_reply(&cs->pending, reply);
+}
+
+static void cw_ss_query_callback(const struct ofono_error *error, int status,
+ void *data)
+{
+ struct ofono_modem *modem = data;
+ struct call_settings_data *cs = modem->call_settings;
+
+ if (error->type != OFONO_ERROR_TYPE_NO_ERROR) {
+ ofono_debug("setting CW via SS failed");
+
+ cs->flags &= ~CALL_SETTINGS_FLAG_CACHED;
+ dbus_gsm_pending_reply(&cs->pending,
+ dbus_gsm_failed(cs->pending));
+
+ return;
+ }
+
+ set_cw(modem, status, BEARER_CLASS_VOICE);
+
+ generate_cw_ss_query_reply(modem);
+}
+
+static void cw_ss_set_callback(const struct ofono_error *error, void *data)
+{
+ struct ofono_modem *modem = data;
+ struct call_settings_data *cs = modem->call_settings;
+
+ if (error->type != OFONO_ERROR_TYPE_NO_ERROR) {
+ ofono_debug("setting CW via SS failed");
+ dbus_gsm_pending_reply(&cs->pending,
+ dbus_gsm_failed(cs->pending));
+
+ return;
+ }
+
+ cs->ops->cw_query(modem, BEARER_CLASS_DEFAULT,
+ cw_ss_query_callback, modem);
+}
+
+static gboolean cw_ss_control(struct ofono_modem *modem, int type,
+ const char *sc, const char *sia,
+ const char *sib, const char *sic,
+ const char *dn, DBusMessage *msg)
+{
+ struct call_settings_data *cs = modem->call_settings;
+ DBusConnection *conn = dbus_gsm_connection();
+ int cls = BEARER_CLASS_SS_DEFAULT;
+ DBusMessage *reply;
+
+ if (!cs)
+ return FALSE;
+
+ if (strcmp(sc, "43"))
+ return FALSE;
+
+ if (cs->pending) {
+ reply = dbus_gsm_busy(msg);
+ goto error;
+ }
+
+ if (strlen(sib) || strlen(sib) || strlen(dn))
+ goto bad_format;
+
+ if ((type == SS_CONTROL_TYPE_QUERY && !cs->ops->cw_query) ||
+ (type != SS_CONTROL_TYPE_QUERY && !cs->ops->cw_set)) {
+ reply = dbus_gsm_not_implemented(msg);
+ goto error;
+ }
+
+ if (strlen(sia) > 0) {
+ long service_code;
+ char *end;
+
+ service_code = strtoul(sia, &end, 10);
+
+ if (end == sia || *end != '\0')
+ goto bad_format;
+
+ cls = mmi_service_code_to_bearer_class(service_code);
+ if (cls == 0)
+ goto bad_format;
+ }
+
+ cs->ss_req_cls = cls;
+ cs->pending = dbus_message_ref(msg);
+
+ /* For the default case use the more readily accepted value */
+ if (cls == BEARER_CLASS_SS_DEFAULT)
+ cls = BEARER_CLASS_DEFAULT;
+
+ switch (type) {
+ case SS_CONTROL_TYPE_REGISTRATION:
+ case SS_CONTROL_TYPE_ACTIVATION:
+ cs->ss_req_type = SS_CONTROL_TYPE_ACTIVATION;
+ cs->ops->cw_set(modem, 1, cls, cw_ss_set_callback, modem);
+ break;
+
+ case SS_CONTROL_TYPE_QUERY:
+ cs->ss_req_type = SS_CONTROL_TYPE_QUERY;
+ /* Always query the entire set, SMS not applicable
+ * according to 22.004 Appendix A, so CLASS_DEFAULT
+ * is safe to use here
+ */
+ cs->ops->cw_query(modem, BEARER_CLASS_DEFAULT,
+ cw_ss_query_callback, modem);
+ break;
+
+ case SS_CONTROL_TYPE_DEACTIVATION:
+ case SS_CONTROL_TYPE_ERASURE:
+ cs->ss_req_type = SS_CONTROL_TYPE_DEACTIVATION;
+ cs->ops->cw_set(modem, 0, cls, cw_ss_set_callback, modem);
+ break;
+ }
+
+ return TRUE;
+
+bad_format:
+ reply = dbus_gsm_invalid_format(msg);
+error:
+ g_dbus_send_message(conn, reply);
+ return TRUE;
+}
+
static void generate_ss_query_reply(struct ofono_modem *modem,
const char *context, const char *value)
{
@@ -293,7 +511,7 @@ static void clip_colp_colr_ss_query_cb(const struct ofono_error *error,
return;
}
- switch (cs->call_setting_type) {
+ switch (cs->ss_setting) {
case CALL_SETTING_TYPE_CLIP:
set_clip(modem, status);
value = clip_status_to_string(status);
@@ -343,13 +561,13 @@ static gboolean clip_colp_colr_ss(struct ofono_modem *modem, int type,
}
if (!strcmp(sc, "30")) {
- cs->call_setting_type = CALL_SETTING_TYPE_CLIP;
+ cs->ss_setting = CALL_SETTING_TYPE_CLIP;
query_op = cs->ops->clip_query;
} else if (!strcmp(sc, "76")) {
- cs->call_setting_type = CALL_SETTING_TYPE_COLP;
+ cs->ss_setting = CALL_SETTING_TYPE_COLP;
query_op = cs->ops->colp_query;
} else if (!strcmp(sc, "77")) {
- cs->call_setting_type = CALL_SETTING_TYPE_COLR;
+ cs->ss_setting = CALL_SETTING_TYPE_COLR;
query_op = cs->ops->colr_query;
} else
return FALSE;
@@ -484,7 +702,7 @@ static gboolean clir_ss_control(struct ofono_modem *modem, int type,
return TRUE;
}
- cs->call_setting_type = CALL_SETTING_TYPE_CLIR;
+ cs->ss_setting = CALL_SETTING_TYPE_CLIR;
cs->pending = dbus_message_ref(msg);
switch (type) {
@@ -520,6 +738,8 @@ static void cs_register_ss_controls(struct ofono_modem *modem)
ss_control_register(modem, "31", clir_ss_control);
ss_control_register(modem, "76", clip_colp_colr_ss);
+ ss_control_register(modem, "43", cw_ss_control);
+
if (cs->ops->colr_query)
ss_control_register(modem, "77", clip_colp_colr_ss);
}
@@ -532,6 +752,8 @@ static void cs_unregister_ss_controls(struct ofono_modem *modem)
ss_control_unregister(modem, "31", clir_ss_control);
ss_control_unregister(modem, "76", clip_colp_colr_ss);
+ ss_control_unregister(modem, "43", cw_ss_control);
+
if (cs->ops->colr_query)
ss_control_unregister(modem, "77", clip_colp_colr_ss);
}
@@ -575,6 +797,8 @@ static DBusMessage *generate_get_properties_reply(struct ofono_modem *modem,
str = hide_callerid_to_string(cs->clir_setting);
dbus_gsm_dict_append(&dict, "HideCallerId", DBUS_TYPE_STRING, &str);
+ property_append_cw_conditions(&dict, cs->cw, BEARER_CLASS_VOICE);
+
dbus_message_iter_close_container(&iter, &dict);
return reply;
@@ -702,6 +926,33 @@ static gboolean query_colr(gpointer user)
return FALSE;
}
+static void cs_cw_callback(const struct ofono_error *error, int status,
+ void *data)
+{
+ struct ofono_modem *modem = data;
+
+ if (error->type == OFONO_ERROR_TYPE_NO_ERROR)
+ set_cw(modem, status, BEARER_CLASS_VOICE);
+
+ g_timeout_add(0, query_colr, modem);
+}
+
+static gboolean query_cw(gpointer user)
+{
+ struct ofono_modem *modem = user;
+ struct call_settings_data *cs = modem->call_settings;
+
+ if (!cs->ops->cw_query) {
+ query_colr(modem);
+ return FALSE;
+ }
+
+ cs->ops->cw_query(modem, BEARER_CLASS_DEFAULT,
+ cs_cw_callback, modem);
+
+ return FALSE;
+}
+
static DBusMessage *cs_get_properties(DBusConnection *conn, DBusMessage *msg,
void *data)
{
@@ -717,7 +968,7 @@ static DBusMessage *cs_get_properties(DBusConnection *conn, DBusMessage *msg,
/* Query the settings and report back */
cs->pending = dbus_message_ref(msg);
- query_colr(modem);
+ query_cw(modem);
return NULL;
}
@@ -734,7 +985,7 @@ static void clir_set_query_callback(const struct ofono_error *error,
return;
if (error->type != OFONO_ERROR_TYPE_NO_ERROR) {
- ofono_error("setting clir was successful, but the query was not");
+ ofono_error("set clir successful, but the query was not");
cs->flags &= ~CALL_SETTINGS_FLAG_CACHED;
@@ -793,6 +1044,95 @@ static DBusMessage *set_clir(DBusMessage *msg, struct ofono_modem *modem,
return NULL;
}
+static void cw_set_query_callback(const struct ofono_error *error, int status,
+ void *data)
+{
+ struct ofono_modem *modem = data;
+ struct call_settings_data *cs = modem->call_settings;
+
+ if (error->type != OFONO_ERROR_TYPE_NO_ERROR) {
+ ofono_error("CW set succeeded, but query failed!");
+
+ cs->flags &= ~CALL_SETTINGS_FLAG_CACHED;
+
+ dbus_gsm_pending_reply(&cs->pending,
+ dbus_gsm_failed(cs->pending));
+ return;
+ }
+
+ dbus_gsm_pending_reply(&cs->pending,
+ dbus_message_new_method_return(cs->pending));
+
+ set_cw(modem, status, BEARER_CLASS_VOICE);
+}
+
+static void cw_set_callback(const struct ofono_error *error, void *data)
+{
+ struct ofono_modem *modem = data;
+ struct call_settings_data *cs = modem->call_settings;
+
+ if (error->type != OFONO_ERROR_TYPE_NO_ERROR) {
+ ofono_debug("Error occurred during CW set");
+
+ dbus_gsm_pending_reply(&cs->pending,
+ dbus_gsm_failed(cs->pending));
+
+ return;
+ }
+
+ cs->ops->cw_query(modem, BEARER_CLASS_DEFAULT,
+ cw_set_query_callback, modem);
+}
+
+static DBusMessage *set_cw_req(DBusMessage *msg, struct ofono_modem *modem,
+ const char *setting, int cls)
+{
+ struct call_settings_data *cs = modem->call_settings;
+ int cw;
+
+ if (cs->ops->cw_set == NULL)
+ return dbus_gsm_not_implemented(msg);
+
+ if (!strcmp(setting, "enabled"))
+ cw = 1;
+ else if (!strcmp(setting, "disabled"))
+ cw = 0;
+ else
+ return dbus_gsm_invalid_format(msg);
+
+ cs->pending = dbus_message_ref(msg);
+
+ cs->ops->cw_set(modem, cw, cls, cw_set_callback, modem);
+
+ return NULL;
+}
+
+static gboolean is_cw_property(const char *property, int mask, int *out_cls)
+{
+ int i;
+ int len;
+ const char *prefix;
+
+ for (i = 1; i <= BEARER_CLASS_PAD; i = i << 1) {
+ if ((i & mask) == 0)
+ continue;
+
+ prefix = bearer_class_to_string(i);
+
+ len = strlen(prefix);
+
+ if (strncmp(property, prefix, len))
+ continue;
+
+ if (!strcmp(property+len, "CallWaiting")) {
+ *out_cls = i;
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
static DBusMessage *cs_set_property(DBusConnection *conn, DBusMessage *msg,
void *data)
{
@@ -801,6 +1141,7 @@ static DBusMessage *cs_set_property(DBusConnection *conn, DBusMessage *msg,
DBusMessageIter iter;
DBusMessageIter var;
const char *property;
+ int cls;
if (cs->pending)
return dbus_gsm_busy(msg);
@@ -828,6 +1169,15 @@ static DBusMessage *cs_set_property(DBusConnection *conn, DBusMessage *msg,
dbus_message_iter_get_basic(&var, &setting);
return set_clir(msg, modem, setting);
+ } else if (is_cw_property(property, BEARER_CLASS_VOICE, &cls)) {
+ const char *setting;
+
+ if (dbus_message_iter_get_arg_type(&var) != DBUS_TYPE_STRING)
+ return dbus_gsm_invalid_format(msg);
+
+ dbus_message_iter_get_basic(&var, &setting);
+
+ return set_cw_req(msg, modem, setting, cls);
}
return dbus_gsm_invalid_args(msg);