summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/Makefile.am2
-rw-r--r--drivers/atmodem/at.h3
-rw-r--r--drivers/atmodem/atmodem.c2
-rw-r--r--drivers/atmodem/call-settings.c107
-rw-r--r--drivers/atmodem/call-waiting.c158
-rw-r--r--src/Makefile.am2
-rw-r--r--src/call-settings.c380
-rw-r--r--src/call-waiting.c528
-rw-r--r--src/driver.h15
9 files changed, 477 insertions, 720 deletions
diff --git a/drivers/Makefile.am b/drivers/Makefile.am
index 5ade3e04..709b5816 100644
--- a/drivers/Makefile.am
+++ b/drivers/Makefile.am
@@ -6,7 +6,7 @@ builtin_cflags =
builtin_modules += atmodem
builtin_sources += atmodem/atmodem.c atmodem/at.h \
atmodem/session.h atmodem/session.c \
- atmodem/call-settings.c atmodem/call-waiting.c \
+ atmodem/call-settings.c \
atmodem/call-forwarding.c atmodem/call-meter.c \
atmodem/network-registration.c atmodem/sim.c \
atmodem/ussd.c atmodem/voicecall.c \
diff --git a/drivers/atmodem/at.h b/drivers/atmodem/at.h
index 4907be7a..de38a893 100644
--- a/drivers/atmodem/at.h
+++ b/drivers/atmodem/at.h
@@ -73,9 +73,6 @@ extern void at_network_registration_exit(struct ofono_modem *modem);
extern void at_call_forwarding_init(struct ofono_modem *modem);
extern void at_call_forwarding_exit(struct ofono_modem *modem);
-extern void at_call_waiting_init(struct ofono_modem *modem);
-extern void at_call_waiting_exit(struct ofono_modem *modem);
-
extern void at_call_settings_init(struct ofono_modem *modem);
extern void at_call_settings_exit(struct ofono_modem *modem);
diff --git a/drivers/atmodem/atmodem.c b/drivers/atmodem/atmodem.c
index 8f14bc01..2d87a8ad 100644
--- a/drivers/atmodem/atmodem.c
+++ b/drivers/atmodem/atmodem.c
@@ -103,7 +103,6 @@ static void manager_free(gpointer user)
struct at_data *at = l->data;
at_call_forwarding_exit(at->modem);
- at_call_waiting_exit(at->modem);
at_call_settings_exit(at->modem);
at_network_registration_exit(at->modem);
at_voicecall_exit(at->modem);
@@ -341,7 +340,6 @@ static void create_cb(GIOChannel *io, gboolean success, gpointer user)
at_sim_init(at->modem);
at_call_forwarding_init(at->modem);
at_call_settings_init(at->modem);
- at_call_waiting_init(at->modem);
at_network_registration_init(at->modem);
at_voicecall_init(at->modem);
at_call_meter_init(at->modem);
diff --git a/drivers/atmodem/call-settings.c b/drivers/atmodem/call-settings.c
index aaed4441..30420cec 100644
--- a/drivers/atmodem/call-settings.c
+++ b/drivers/atmodem/call-settings.c
@@ -42,6 +42,109 @@ static const char *none_prefix[] = { NULL };
static const char *clir_prefix[] = { "+CLIR:", NULL };
static const char *colp_prefix[] = { "+COLP:", NULL };
static const char *clip_prefix[] = { "+CLIP:", NULL };
+static const char *ccwa_prefix[] = { "+CCWA:", NULL };
+
+static void ccwa_query_cb(gboolean ok, GAtResult *result, gpointer user_data)
+{
+ struct cb_data *cbd = user_data;
+ ofono_call_waiting_status_cb_t cb = cbd->cb;
+ int conditions = 0;
+ int status;
+ int cls;
+ struct ofono_error error;
+ GAtResultIter iter;
+
+ dump_response("ccwa_query_cb", ok, result);
+ decode_at_error(&error, g_at_result_final_response(result));
+
+ if (!ok)
+ goto out;
+
+ g_at_result_iter_init(&iter, result);
+
+ while (g_at_result_iter_next(&iter, "+CCWA:")) {
+ g_at_result_iter_next_number(&iter, &status);
+ g_at_result_iter_next_number(&iter, &cls);
+
+ if (status == 1)
+ conditions |= cls;
+ }
+
+ ofono_debug("CW enabled for: %d", conditions);
+
+out:
+ cb(&error, conditions, cbd->data);
+}
+
+static void at_ccwa_query(struct ofono_modem *modem, int cls,
+ ofono_call_waiting_status_cb_t cb, void *data)
+{
+ struct at_data *at = ofono_modem_userdata(modem);
+ struct cb_data *cbd = cb_data_new(modem, cb, data);
+ char buf[64];
+
+ if (!cbd)
+ goto error;
+
+ cbd->user = GINT_TO_POINTER(cls);
+
+ if (cls == 7)
+ sprintf(buf, "AT+CCWA=1,2");
+ else
+ sprintf(buf, "AT+CCWA=1,2,%d", cls);
+
+ if (g_at_chat_send(at->parser, buf, ccwa_prefix,
+ ccwa_query_cb, cbd, g_free) > 0)
+ return;
+
+error:
+ if (cbd)
+ g_free(cbd);
+
+ {
+ DECLARE_FAILURE(error);
+ cb(&error, 0, data);
+ }
+}
+
+static void ccwa_set_cb(gboolean ok, GAtResult *result, gpointer user_data)
+{
+ struct cb_data *cbd = user_data;
+ ofono_generic_cb_t cb = cbd->cb;
+ struct ofono_error error;
+
+ dump_response("ccwa_set_cb", ok, result);
+ decode_at_error(&error, g_at_result_final_response(result));
+
+ cb(&error, cbd->data);
+}
+
+static void at_ccwa_set(struct ofono_modem *modem, int mode, int cls,
+ ofono_generic_cb_t cb, void *data)
+{
+ struct at_data *at = ofono_modem_userdata(modem);
+ struct cb_data *cbd = cb_data_new(modem, cb, data);
+ char buf[64];
+
+ if (!cbd)
+ goto error;
+
+ sprintf(buf, "AT+CCWA=1,%d,%d", mode, cls);
+
+ if (g_at_chat_send(at->parser, buf, none_prefix,
+ ccwa_set_cb, cbd, g_free) > 0)
+ return;
+
+error:
+ if (cbd)
+ g_free(cbd);
+
+ {
+ DECLARE_FAILURE(error);
+ cb(&error, data);
+ }
+}
+
static void clip_query_cb(gboolean ok, GAtResult *result, gpointer user_data)
{
@@ -257,7 +360,9 @@ static struct ofono_call_settings_ops ops = {
.colp_query = at_colp_query,
.clir_query = at_clir_query,
.clir_set = at_clir_set,
- .colr_query = NULL
+ .colr_query = NULL,
+ .cw_query = at_ccwa_query,
+ .cw_set = at_ccwa_set,
};
void at_call_settings_init(struct ofono_modem *modem)
diff --git a/drivers/atmodem/call-waiting.c b/drivers/atmodem/call-waiting.c
deleted file mode 100644
index 2e978d59..00000000
--- a/drivers/atmodem/call-waiting.c
+++ /dev/null
@@ -1,158 +0,0 @@
-/*
- *
- * oFono - Open Source Telephony
- *
- * Copyright (C) 2008-2009 Intel Corporation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#define _GNU_SOURCE
-#include <string.h>
-#include <stdlib.h>
-#include <stdio.h>
-
-#include <glib.h>
-
-#include <ofono/log.h>
-#include "driver.h"
-
-#include "gatchat.h"
-#include "gatresult.h"
-
-#include "at.h"
-
-static const char *none_prefix[] = { NULL };
-static const char *ccwa_prefix[] = { "+CCWA:", NULL };
-
-static void ccwa_query_cb(gboolean ok, GAtResult *result, gpointer user_data)
-{
- struct cb_data *cbd = user_data;
- ofono_call_waiting_status_cb_t cb = cbd->cb;
- int conditions = 0;
- int status;
- int cls;
- struct ofono_error error;
- GAtResultIter iter;
-
- dump_response("ccwa_query_cb", ok, result);
- decode_at_error(&error, g_at_result_final_response(result));
-
- if (!ok)
- goto out;
-
- g_at_result_iter_init(&iter, result);
-
- while (g_at_result_iter_next(&iter, "+CCWA:")) {
- g_at_result_iter_next_number(&iter, &status);
- g_at_result_iter_next_number(&iter, &cls);
-
- if (status == 1)
- conditions |= cls;
- }
-
- ofono_debug("CW enabled for: %d", conditions);
-
-out:
- cb(&error, conditions, cbd->data);
-}
-
-static void at_ccwa_query(struct ofono_modem *modem, int cls,
- ofono_call_waiting_status_cb_t cb, void *data)
-{
- struct at_data *at = ofono_modem_userdata(modem);
- struct cb_data *cbd = cb_data_new(modem, cb, data);
- char buf[64];
-
- if (!cbd)
- goto error;
-
- cbd->user = GINT_TO_POINTER(cls);
-
- if (cls == 7)
- sprintf(buf, "AT+CCWA=1,2");
- else
- sprintf(buf, "AT+CCWA=1,2,%d", cls);
-
- if (g_at_chat_send(at->parser, buf, ccwa_prefix,
- ccwa_query_cb, cbd, g_free) > 0)
- return;
-
-error:
- if (cbd)
- g_free(cbd);
-
- {
- DECLARE_FAILURE(error);
- cb(&error, 0, data);
- }
-}
-
-static void ccwa_set_cb(gboolean ok, GAtResult *result, gpointer user_data)
-{
- struct cb_data *cbd = user_data;
- ofono_generic_cb_t cb = cbd->cb;
- struct ofono_error error;
-
- dump_response("ccwa_set_cb", ok, result);
- decode_at_error(&error, g_at_result_final_response(result));
-
- cb(&error, cbd->data);
-}
-
-static void at_ccwa_set(struct ofono_modem *modem, int mode, int cls,
- ofono_generic_cb_t cb, void *data)
-{
- struct at_data *at = ofono_modem_userdata(modem);
- struct cb_data *cbd = cb_data_new(modem, cb, data);
- char buf[64];
-
- if (!cbd)
- goto error;
-
- sprintf(buf, "AT+CCWA=1,%d,%d", mode, cls);
-
- if (g_at_chat_send(at->parser, buf, none_prefix,
- ccwa_set_cb, cbd, g_free) > 0)
- return;
-
-error:
- if (cbd)
- g_free(cbd);
-
- {
- DECLARE_FAILURE(error);
- cb(&error, data);
- }
-}
-
-static struct ofono_call_waiting_ops ops = {
- .query = at_ccwa_query,
- .set = at_ccwa_set
-};
-
-void at_call_waiting_init(struct ofono_modem *modem)
-{
- ofono_call_waiting_register(modem, &ops);
-}
-
-void at_call_waiting_exit(struct ofono_modem *modem)
-{
- ofono_call_waiting_unregister(modem);
-}
diff --git a/src/Makefile.am b/src/Makefile.am
index 28dcc774..2f3ad7f9 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -11,7 +11,7 @@ ofonod_SOURCES = main.c ofono.h log.c plugin.c \
driver.h modem.h modem.c common.h common.c \
manager.c dbus-gsm.h dbus-gsm.c util.h util.c \
network.c voicecall.c ussd.h ussd.c \
- call-settings.c call-waiting.c call-forwarding.c call-meter.c \
+ call-settings.c call-forwarding.c call-meter.c \
smsutil.h smsutil.c cssn.h cssn.c call-barring.c sim.h sim.c
ofonod_LDADD = $(top_builddir)/plugins/libbuiltin.la \
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);
diff --git a/src/call-waiting.c b/src/call-waiting.c
deleted file mode 100644
index 29773b8b..00000000
--- a/src/call-waiting.c
+++ /dev/null
@@ -1,528 +0,0 @@
-/*
- *
- * oFono - Open Source Telephony
- *
- * Copyright (C) 2008-2009 Intel Corporation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <string.h>
-#include <stdlib.h>
-#include <stdio.h>
-
-#include <dbus/dbus.h>
-#include <glib.h>
-#include <gdbus.h>
-
-#include "ofono.h"
-
-#include "driver.h"
-#include "common.h"
-#include "dbus-gsm.h"
-#include "modem.h"
-#include "ussd.h"
-
-#define CALL_WAITING_INTERFACE "org.ofono.CallWaiting"
-
-#define CALL_WAITING_FLAG_CACHED 0x1
-
-struct call_waiting_data {
- struct ofono_call_waiting_ops *ops;
- int flags;
- DBusMessage *pending;
- int conditions;
- int ss_req_type;
- int ss_req_cls;
-};
-
-static void cw_register_ss_controls(struct ofono_modem *modem);
-static void cw_unregister_ss_controls(struct ofono_modem *modem);
-
-static struct call_waiting_data *call_waiting_create()
-{
- struct call_waiting_data *r;
-
- r = g_new0(struct call_waiting_data, 1);
-
- return r;
-}
-
-static void call_waiting_destroy(gpointer data)
-{
- struct ofono_modem *modem = data;
- struct call_waiting_data *cw = modem->call_waiting;
-
- cw_unregister_ss_controls(modem);
-
- g_free(cw);
-}
-
-static void update_conditions(struct ofono_modem *modem, int new_conditions,
- int mask)
-{
- struct call_waiting_data *cw = modem->call_waiting;
- 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 ((cw->conditions & j) == (new_conditions & j))
- continue;
-
- if (new_conditions & j)
- value = "enabled";
- else
- value = "disabled";
-
- sprintf(buf, "%s", bearer_class_to_string(j));
- dbus_gsm_signal_property_changed(conn, modem->path,
- CALL_WAITING_INTERFACE,
- buf, DBUS_TYPE_STRING,
- &value);
- }
-
- cw->conditions = new_conditions;
-}
-
-static void property_append_cw_conditions(DBusMessageIter *dict,
- int conditions, int mask)
-{
- int i;
- const char *prop;
- const char *value;
-
- for (i = 1; i <= BEARER_CLASS_PAD; i = i << 1) {
- if (!(mask & i))
- continue;
-
- prop = 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_ss_query_reply(struct ofono_modem *modem)
-{
- struct call_waiting_data *cw = modem->call_waiting;
- const char *sig = "(sa{sv})";
- const char *ss_type = ss_control_type_to_string(cw->ss_req_type);
- const char *context = "CallWaiting";
- DBusMessageIter iter;
- DBusMessageIter var;
- DBusMessageIter vstruct;
- DBusMessageIter dict;
- DBusMessage *reply;
-
- reply = dbus_message_new_method_return(cw->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, cw->conditions, cw->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(&cw->pending, reply);
-}
-
-static void cw_ss_query_callback(const struct ofono_error *error, int status,
- void *data)
-{
- struct ofono_modem *modem = data;
- struct call_waiting_data *cw = modem->call_waiting;
-
- if (error->type != OFONO_ERROR_TYPE_NO_ERROR) {
- ofono_debug("setting CW via SS failed");
-
- cw->flags &= ~CALL_WAITING_FLAG_CACHED;
- dbus_gsm_pending_reply(&cw->pending,
- dbus_gsm_failed(cw->pending));
-
- return;
- }
-
- update_conditions(modem, status, BEARER_CLASS_VOICE);
- cw->flags |= CALL_WAITING_FLAG_CACHED;
-
- generate_ss_query_reply(modem);
-}
-
-static void cw_ss_set_callback(const struct ofono_error *error, void *data)
-{
- struct ofono_modem *modem = data;
- struct call_waiting_data *cw = modem->call_waiting;
- int cls;
-
- if (error->type != OFONO_ERROR_TYPE_NO_ERROR) {
- ofono_debug("setting CW via SS failed");
- dbus_gsm_pending_reply(&cw->pending,
- dbus_gsm_failed(cw->pending));
-
- return;
- }
-
- cls = cw->ss_req_cls | BEARER_CLASS_DEFAULT;
-
- cw->ops->query(modem, cw->ss_req_cls, 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_waiting_data *cw = modem->call_waiting;
- DBusConnection *conn = dbus_gsm_connection();
- int cls = BEARER_CLASS_SS_DEFAULT;
- DBusMessage *reply;
-
- if (!cw)
- return FALSE;
-
- if (strcmp(sc, "43"))
- return FALSE;
-
- if (cw->pending) {
- reply = dbus_gsm_busy(msg);
- goto error;
- }
-
- if (strlen(sib) || strlen(sib) || strlen(dn))
- goto bad_format;
-
- if ((type == SS_CONTROL_TYPE_QUERY && !cw->ops->query) ||
- (type != SS_CONTROL_TYPE_QUERY && !cw->ops->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;
- }
-
- cw->ss_req_cls = cls;
- cw->pending = dbus_message_ref(msg);
-
- cls = BEARER_CLASS_DEFAULT;
-
- switch (type) {
- case SS_CONTROL_TYPE_REGISTRATION:
- case SS_CONTROL_TYPE_ACTIVATION:
- cw->ss_req_type = SS_CONTROL_TYPE_ACTIVATION;
- cw->ops->set(modem, 1, cls, cw_ss_set_callback, modem);
- break;
-
- case SS_CONTROL_TYPE_QUERY:
- cw->ss_req_type = SS_CONTROL_TYPE_QUERY;
- cw->ops->query(modem, cls, cw_ss_query_callback, modem);
- break;
-
- case SS_CONTROL_TYPE_DEACTIVATION:
- case SS_CONTROL_TYPE_ERASURE:
- cw->ss_req_type = SS_CONTROL_TYPE_DEACTIVATION;
- cw->ops->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 cw_register_ss_controls(struct ofono_modem *modem)
-{
- ss_control_register(modem, "43", cw_ss_control);
-}
-
-static void cw_unregister_ss_controls(struct ofono_modem *modem)
-{
- ss_control_unregister(modem, "43", cw_ss_control);
-}
-
-static DBusMessage *generate_get_properties_reply(struct ofono_modem *modem,
- DBusMessage *msg)
-{
- struct call_waiting_data *cw = modem->call_waiting;
- DBusMessage *reply;
- DBusMessageIter iter;
- DBusMessageIter dict;
-
- reply = dbus_message_new_method_return(msg);
-
- if (!reply)
- return NULL;
-
- dbus_message_iter_init_append(reply, &iter);
-
- dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
- PROPERTIES_ARRAY_SIGNATURE,
- &dict);
-
- property_append_cw_conditions(&dict, cw->conditions,
- BEARER_CLASS_VOICE);
-
- dbus_message_iter_close_container(&iter, &dict);
-
- return reply;
-}
-
-static void cw_query_callback(const struct ofono_error *error, int status,
- void *data)
-{
- struct ofono_modem *modem = data;
- struct call_waiting_data *cw = modem->call_waiting;
-
- if (error->type != OFONO_ERROR_TYPE_NO_ERROR) {
- ofono_debug("Error during cw query");
- goto out;
- }
-
- update_conditions(modem, status, BEARER_CLASS_VOICE);
- cw->flags |= CALL_WAITING_FLAG_CACHED;
-
-out:
- if (cw->pending) {
- DBusMessage *reply;
-
- reply = generate_get_properties_reply(modem, cw->pending);
- dbus_gsm_pending_reply(&cw->pending, reply);
- }
-}
-
-static DBusMessage *cw_get_properties(DBusConnection *conn, DBusMessage *msg,
- void *data)
-{
- struct ofono_modem *modem = data;
- struct call_waiting_data *cw = modem->call_waiting;
-
- if (cw->pending)
- return dbus_gsm_busy(msg);
-
- if (!cw->ops->query)
- return dbus_gsm_not_implemented(msg);
-
- if (cw->flags & CALL_WAITING_FLAG_CACHED)
- return generate_get_properties_reply(modem, msg);
-
- cw->pending = dbus_message_ref(msg);
-
- cw->ops->query(modem, BEARER_CLASS_DEFAULT, cw_query_callback, modem);
-
- return NULL;
-}
-
-static void set_query_callback(const struct ofono_error *error, int status,
- void *data)
-{
- struct ofono_modem *modem = data;
- struct call_waiting_data *cw = modem->call_waiting;
-
- if (error->type != OFONO_ERROR_TYPE_NO_ERROR) {
- ofono_error("CW set succeeded, but query failed!");
- cw->flags &= ~CALL_WAITING_FLAG_CACHED;
-
- dbus_gsm_pending_reply(&cw->pending,
- dbus_gsm_failed(cw->pending));
- return;
- }
-
- dbus_gsm_pending_reply(&cw->pending,
- dbus_message_new_method_return(cw->pending));
-
- update_conditions(modem, status, BEARER_CLASS_VOICE);
-}
-
-static void set_callback(const struct ofono_error *error, void *data)
-{
- struct ofono_modem *modem = data;
- struct call_waiting_data *cw = modem->call_waiting;
-
- if (error->type != OFONO_ERROR_TYPE_NO_ERROR) {
- ofono_debug("Error occurred during CW set");
-
- dbus_gsm_pending_reply(&cw->pending,
- dbus_gsm_failed(cw->pending));
-
- return;
- }
-
- cw->ops->query(modem, BEARER_CLASS_DEFAULT, set_query_callback, modem);
-}
-
-static DBusMessage *cw_set_property(DBusConnection *conn, DBusMessage *msg,
- void *data)
-{
- struct ofono_modem *modem = data;
- struct call_waiting_data *cw = modem->call_waiting;
- DBusMessageIter iter;
- DBusMessageIter var;
- const char *property;
- int i;
-
- if (cw->pending)
- return dbus_gsm_busy(msg);
-
- if (!cw->ops->set)
- return dbus_gsm_not_implemented(msg);
-
- if (!dbus_message_iter_init(msg, &iter))
- return dbus_gsm_invalid_args(msg);
-
- if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
- return dbus_gsm_invalid_args(msg);
-
- dbus_message_iter_get_basic(&iter, &property);
- dbus_message_iter_next(&iter);
-
- if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
- return dbus_gsm_invalid_args(msg);
-
- dbus_message_iter_recurse(&iter, &var);
-
- for (i = 1; i < BEARER_CLASS_SMS; i = i << 1)
- if (!strcmp(property, bearer_class_to_string(i)))
- break;
-
- if (i < BEARER_CLASS_SMS) {
- const char *value;
- int status;
-
- if (dbus_message_iter_get_arg_type(&var) != DBUS_TYPE_STRING)
- return dbus_gsm_invalid_format(msg);
-
- dbus_message_iter_get_basic(&var, &value);
-
- if (!strcmp(value, "enabled"))
- status = 1;
- else if (!strcmp(value, "disabled"))
- status = 0;
- else
- return dbus_gsm_invalid_format(msg);
-
- cw->pending = dbus_message_ref(msg);
-
- cw->ops->set(modem, status, i, set_callback, modem);
- }
-
- return dbus_gsm_invalid_args(msg);
-}
-
-static GDBusMethodTable cw_methods[] = {
- { "GetProperties", "", "a{sv}", cw_get_properties,
- G_DBUS_METHOD_FLAG_ASYNC },
- { "SetProperty", "sv", "", cw_set_property,
- G_DBUS_METHOD_FLAG_ASYNC },
- { }
-};
-
-static GDBusSignalTable cw_signals[] = {
- { "PropertyChanged", "sv" },
- { }
-};
-
-int ofono_call_waiting_register(struct ofono_modem *modem,
- struct ofono_call_waiting_ops *ops)
-{
- DBusConnection *conn = dbus_gsm_connection();
-
- if (modem == NULL)
- return -1;
-
- if (ops == NULL)
- return -1;
-
- modem->call_waiting = call_waiting_create();
-
- if (!modem->call_waiting)
- return -1;
-
- modem->call_waiting->ops = ops;
-
- if (!g_dbus_register_interface(conn, modem->path,
- CALL_WAITING_INTERFACE,
- cw_methods, cw_signals, NULL,
- modem, call_waiting_destroy)) {
- ofono_error("Could not register CallWaiting %s", modem->path);
- call_waiting_destroy(modem);
-
- return -1;
- }
-
- ofono_debug("Registered call waiting interface");
-
- cw_register_ss_controls(modem);
-
- modem_add_interface(modem, CALL_WAITING_INTERFACE);
- return 0;
-}
-
-void ofono_call_waiting_unregister(struct ofono_modem *modem)
-{
- struct call_waiting_data *cw = modem->call_waiting;
- DBusConnection *conn = dbus_gsm_connection();
-
- if (!cw)
- return;
-
- modem_remove_interface(modem, CALL_WAITING_INTERFACE);
- g_dbus_unregister_interface(conn, modem->path,
- CALL_WAITING_INTERFACE);
-
- modem->call_waiting = NULL;
-}
diff --git a/src/driver.h b/src/driver.h
index 4a5dac38..b1883a29 100644
--- a/src/driver.h
+++ b/src/driver.h
@@ -312,23 +312,16 @@ struct ofono_call_settings_ops {
ofono_call_setting_status_cb_t cb, void *data);
void (*clir_set)(struct ofono_modem *modem, int mode, ofono_generic_cb_t cb,
void *data);
+ void (*cw_query)(struct ofono_modem *modem, int cls,
+ ofono_call_waiting_status_cb_t cb, void *data);
+ void (*cw_set)(struct ofono_modem *modem, int mode, int cls,
+ ofono_generic_cb_t cb, void *data);
};
int ofono_call_settings_register(struct ofono_modem *modem,
struct ofono_call_settings_ops *ops);
void ofono_call_settings_unregister(struct ofono_modem *modem);
-struct ofono_call_waiting_ops {
- void (*query)(struct ofono_modem *modem, int cls,
- ofono_call_waiting_status_cb_t cb, void *data);
- void (*set)(struct ofono_modem *modem, int mode, int cls,
- ofono_generic_cb_t cb, void *data);
-};
-
-int ofono_call_waiting_register(struct ofono_modem *modem,
- struct ofono_call_waiting_ops *ops);
-void ofono_call_waiting_unregister(struct ofono_modem *modem);
-
struct ofono_call_meter_ops {
void (*call_meter_query)(struct ofono_modem *modem,
ofono_call_meter_query_cb_t cb, void *data);