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
This commit is contained in:
Denis Kenzior 2009-05-28 13:50:25 -05:00
parent 99b01eba7f
commit 699752eaf1
9 changed files with 477 additions and 720 deletions

View File

@ -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 \

View File

@ -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);

View File

@ -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);

View File

@ -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)

View File

@ -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);
}

View File

@ -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 \

View File

@ -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);

View File

@ -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;
}

View File

@ -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);