Compare commits

...

26 Commits

Author SHA1 Message Date
Slava Monich
490a9c06f4 [unit] Improved ril_util.c test coverage 2018-01-22 11:57:17 +02:00
Slava Monich
320b3f4605 Merge branch 'sim_info' into 'master'
A few corner cases for cached SIM info

See merge request !165
2018-01-22 09:40:40 +00:00
Slava Monich
e35dae17d9 Merge branch 'aid_pin' into 'master'
Don't require AID for SIM pin requests

See merge request !164
2018-01-22 09:39:55 +00:00
Slava Monich
f4522f4a00 [unit] Added test-sailfish_sim_info_dbus
Tests sailfish_sim_info_dbus.c

  Lines:     93/96  96.9 %
  Functions: 16/16 100.0 %
  Branches:  16/20  80.0 %
2018-01-22 02:02:29 +02:00
Slava Monich
ce85c94426 [unit] Improved test coverage for sailfish_sim_info.c 2018-01-21 20:03:40 +02:00
Slava Monich
4027bdc04e [ril] A few corner cases for cached SIM info
Cached SPN needs to be reset too when SIM card is removed.
2018-01-21 20:02:10 +02:00
Slava Monich
c57f99bf01 [ril] Don't require AID for SIM pin requests. Fixes JB#40837
Some adaptations (namely, MTK) don't provide AID for GSM app but
don't seem to require it either.
2018-01-19 20:56:15 +02:00
Slava Monich
54d610ce6a Merge branch 'vendor' into 'master'
MTK support

See merge request !156
2018-01-18 21:34:14 +00:00
Slava Monich
f7f9e32743 unit: Improve idmap.c unit test coverage
This brings function, line and branch coverage for idmap.c to 100%
2018-01-18 23:29:21 +02:00
Slava Monich
8c9e370486 [ril] Support for vendor extensions. JB#39612 2018-01-18 17:34:41 +02:00
Slava Monich
19b80236f6 [ofono] gprs: Add __ofono_gprs_context_settings_by_type 2018-01-18 17:34:40 +02:00
Slava Monich
2ec6fc749d [unit] Added test-sailfish_cell_info_dbus
Tests sailfish_cell_info_dbus.c

  Lines:     215/220  97.7 %
  Functions: 25/25   100.0 %
  Branches:  72/88    81.8 %
2018-01-18 13:34:41 +02:00
Slava Monich
0a3bdd20f4 [ril] Validate dbus_bool_t
libdbus crashes and burns when boolean value is not 0 or 1
2018-01-18 13:27:46 +02:00
Slava Monich
284919e76a Merge branch 'jb40756' into 'master'
Don't repeat cell info requests indefinitely

See merge request !163
2018-01-17 15:14:20 +00:00
Slava Monich
ddcbb89fa1 [ril] Don't repeat cell info requests indefinitely. Fixes JB#40756
If they fail, they typically keep on failing forever. Repeating the
requests doesn't do any good, it's just draining the battery.
2018-01-17 17:11:59 +02:00
Slava Monich
5ec6b8e7ec [test] Improve sailfish_manager.c test coverage 2018-01-04 12:09:34 +02:00
Slava Monich
f94681f6f6 Merge branch 'iccid_watch' into 'master'
Properly reset cached SIM info after removal

See merge request !162
2018-01-04 10:08:35 +00:00
Slava Monich
de8edc84fa [ofono] Properly reset cached SIM info after removal. Fixes JB#39810
sailfish_watch expected to be notified by ofono of every ICCID or IMSI
change, however it wasn't happening when SIM card was getting removed.
That messed things up.
2018-01-03 16:45:39 +02:00
Slava Monich
90faf1b3a5 Merge branch 'fac_timeout' into 'master'
Make sure SIM_IO and QUERY_FACILITY_LOCK requests get completed

See merge request !161
2018-01-02 09:40:11 +00:00
Slava Monich
2b139b6974 [ril] Make sure SIM_IO and QUERY_FACILITY_LOCK get completed
ofono becomes very unhappy if they don't. Also, completion
is required in order to eventually reset SIM I/O active flag.
If doesn't make sense to keep it on forever.
2017-12-25 18:23:57 +02:00
Slava Monich
168f193efb Merge branch 'refresh' into 'master'
Handle SIM reset

See merge request !160
2017-12-08 21:09:15 +00:00
Slava Monich
32d8b5ccfc sim: Don't submit parallel EFpl reads
In addition to not doing unnecessary SIM I/O, this fixes memory leaks
like this one:

==10096== 74 (56 direct, 18 indirect) bytes in 2 blocks are definitely lost in loss record 1,252 of 1,342
==10096==    at 0x4841BF0: calloc (vg_replace_malloc.c)
==10096==    by 0x4B03117: g_malloc0 (gmem.c)
==10096==    by 0xF83DF: concat_lang_prefs (sim.c)
==10096==    by 0xF8697: sim_efpl_read_cb (sim.c)
==10096==    by 0x12CBF7: sim_fs_op_read_block_cb (simfs.c)
2017-12-09 00:06:26 +03:00
Slava Monich
f400ceff80 Merge branch 'sms-filter-api-version' into 'master'
sms-filter: Add api_version field

See merge request !159
2017-12-08 12:37:05 +00:00
Slava Monich
2186c60630 [ril] Handle SIM reset. Fixes JB#40010
This happens when we receive a proactive Refresh command from SIM Tookit
which is generated by some SIMs when people are moving between home and
roaming networks.
2017-12-08 15:26:44 +03:00
Slava Monich
d5fb195e2f [ofono] sms-filter: Added api_version field. JB#37478
This makes it possible to keep using old plugins even if
struct ofono_sms_filter gets extended with new callbacks.
2017-12-08 15:22:16 +03:00
Slava Monich
cbb08079d2 [ril] Housekeeping
Removed some unused stuff
2017-12-07 17:23:22 +03:00
34 changed files with 3692 additions and 208 deletions

2
ofono/.gitignore vendored
View File

@@ -48,8 +48,10 @@ unit/test-rilmodem-cs
unit/test-rilmodem-gprs
unit/test-rilmodem-sms
unit/test-sailfish_cell_info
unit/test-sailfish_cell_info_dbus
unit/test-sailfish_manager
unit/test-sailfish_sim_info
unit/test-sailfish_sim_info_dbus
unit/test-sms-filter
unit/test-*.log
unit/test-*.trs

View File

@@ -166,8 +166,12 @@ builtin_sources += drivers/ril/ril_call_barring.c \
drivers/ril/ril_stk.c \
drivers/ril/ril_ussd.c \
drivers/ril/ril_util.c \
drivers/ril/ril_vendor.c \
drivers/ril/ril_voicecall.c
# Vendor specific extensions
builtin_sources += drivers/ril/ril_vendor_mtk.c
if DATAFILES
dist_conf_DATA += drivers/ril/ril_subscription.conf
endif
@@ -912,11 +916,24 @@ if SAILFISH_MANAGER
unit_test_sailfish_cell_info_SOURCES = unit/test-sailfish_cell_info.c \
plugins/sailfish_manager/sailfish_cell_info.c
unit_test_sailfish_cell_info_CFLAGS = $(AM_CFLAGS) $(COVERAGE_OPT) \
-Iplugins/sailfish_cell_info
-Iplugins/sailfish_manager
unit_test_sailfish_cell_info_LDADD = @GLIB_LIBS@ -ldl
unit_objects += $(unit_test_sailfish_cell_info_OBJECTS)
unit_tests += unit/test-sailfish_cell_info
unit_test_sailfish_cell_info_dbus_SOURCES = unit/test-dbus.c \
unit/test-sailfish_cell_info_dbus.c \
unit/fake_sailfish_cell_info.c \
plugins/sailfish_manager/sailfish_cell_info.c \
plugins/sailfish_manager/sailfish_cell_info_dbus.c \
gdbus/object.c \
src/dbus.c src/log.c
unit_test_sailfish_cell_info_dbus_CFLAGS = $(AM_CFLAGS) $(COVERAGE_OPT) \
@DBUS_GLIB_CFLAGS@ -Iplugins/sailfish_manager
unit_test_sailfish_cell_info_dbus_LDADD = @DBUS_GLIB_LIBS@ @GLIB_LIBS@ -ldl
unit_objects += $(unit_test_sailfish_cell_info_dbus_OBJECTS)
unit_tests += unit/test-sailfish_cell_info_dbus
unit_test_sailfish_sim_info_SOURCES = unit/test-sailfish_sim_info.c \
unit/fake_sailfish_watch.c \
plugins/sailfish_manager/sailfish_sim_info.c \
@@ -927,6 +944,19 @@ unit_test_sailfish_sim_info_LDADD = @GLIB_LIBS@ -ldl
unit_objects += $(unit_test_sailfish_sim_info_OBJECTS)
unit_tests += unit/test-sailfish_sim_info
unit_test_sailfish_sim_info_dbus_SOURCES = unit/test-sailfish_sim_info_dbus.c \
unit/test-dbus.c unit/fake_sailfish_watch.c \
plugins/sailfish_manager/sailfish_sim_info.c \
plugins/sailfish_manager/sailfish_sim_info_dbus.c \
gdbus/object.c \
src/dbus.c src/storage.c src/watch.c src/log.c
unit_test_sailfish_sim_info_dbus_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS) \
@DBUS_GLIB_CFLAGS@ -DSTORAGEDIR='"/tmp/ofono"' \
-Iplugins/sailfish_manager
unit_test_sailfish_sim_info_dbus_LDADD = @DBUS_GLIB_LIBS@ @GLIB_LIBS@ -ldl
unit_objects += $(unit_test_sailfish_sim_info_dbus_OBJECTS)
unit_tests += unit/test-sailfish_sim_info_dbus
unit_test_sailfish_manager_SOURCES = unit/test-sailfish_manager.c \
unit/fake_sailfish_watch.c \
plugins/sailfish_manager/sailfish_manager.c \

View File

@@ -184,8 +184,8 @@ AC_ARG_ENABLE(sailfish-rilmodem, AC_HELP_STRING([--enable-sailfish-rilmodem],
AM_CONDITIONAL(SAILFISH_RILMODEM, test "${enable_sailfish_rilmodem}" != "no")
if (test "${enable_sailfish_rilmodem}" = "yes"); then
PKG_CHECK_MODULES(GRILIO, libgrilio >= 1.0.18, dummy=yes,
AC_MSG_ERROR(libgrilio >= 1.0.18 is required))
PKG_CHECK_MODULES(GRILIO, libgrilio >= 1.0.20, dummy=yes,
AC_MSG_ERROR(libgrilio >= 1.0.20 is required))
PKG_CHECK_MODULES(GLIBUTIL, libglibutil >= 1.0.23, dummy=yes,
AC_MSG_ERROR(libglibutil >= 1.0.23 is required))
PKG_CHECK_MODULES(LIBMCE, libmce-glib >= 1.0.5, dummy=yes,
@@ -202,6 +202,13 @@ AC_ARG_ENABLE(sailfish-manager,
[enable_sailfish_manager=${enableval}])
AM_CONDITIONAL(SAILFISH_MANAGER, test "${enable_sailfish_manager}" = "yes")
if (test "${enable_sailfish_manager}" = "yes"); then
PKG_CHECK_MODULES(DBUS_GLIB, dbus-glib-1, dummy=yes,
AC_MSG_ERROR(dbus-glib is required by unit tests))
AC_SUBST(DBUS_GLIB_CFLAGS)
AC_SUBST(DBUS_GLIB_LIBS)
fi
AC_ARG_ENABLE(add-remove-context, AC_HELP_STRING([--disable-add-remove-context],
[don't allow to add or remove connection context over D-Bus]), [
if (test "${enableval}" = "no"); then

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2016-2017 Jolla Ltd.
* Copyright (C) 2016-2018 Jolla Ltd.
*
* 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
@@ -27,6 +27,7 @@
#define DISPLAY_ON_UPDATE_RATE (1000) /* 1 sec */
#define DISPLAY_OFF_UPDATE_RATE (60000) /* 1 min */
#define MAX_RETRIES (5)
typedef GObjectClass RilCellInfoClass;
typedef struct ril_cell_info RilCellInfo;
@@ -296,8 +297,8 @@ static void ril_cell_info_list_cb(GRilIoChannel *io, int status,
DBG_(self, "");
GASSERT(self->query_id);
self->query_id = 0;
ril_cell_info_update_cells(self, ril_cell_info_parse_list
(io->ril_version, data, len));
ril_cell_info_update_cells(self, (status == RIL_E_SUCCESS) ?
ril_cell_info_parse_list(io->ril_version, data, len) : NULL);
}
static void ril_cell_info_set_rate_cb(GRilIoChannel *io, int status,
@@ -314,7 +315,7 @@ static void ril_cell_info_query(struct ril_cell_info *self)
{
GRilIoRequest *req = grilio_request_new();
grilio_request_set_retry(req, RIL_RETRY_MS, -1);
grilio_request_set_retry(req, RIL_RETRY_MS, MAX_RETRIES);
grilio_channel_cancel_request(self->io, self->query_id, FALSE);
self->query_id = grilio_channel_send_request_full(self->io, req,
RIL_REQUEST_GET_CELL_INFO_LIST, ril_cell_info_list_cb,
@@ -328,7 +329,7 @@ static void ril_cell_info_set_rate(struct ril_cell_info *self, int ms)
grilio_request_append_int32(req, 1);
grilio_request_append_int32(req, ms);
grilio_request_set_retry(req, RIL_RETRY_MS, -1);
grilio_request_set_retry(req, RIL_RETRY_MS, MAX_RETRIES);
grilio_channel_cancel_request(self->io, self->set_rate_id, FALSE);
self->set_rate_id = grilio_channel_send_request_full(self->io, req,
RIL_REQUEST_SET_UNSOL_CELL_INFO_LIST_RATE,
@@ -338,18 +339,16 @@ static void ril_cell_info_set_rate(struct ril_cell_info *self, int ms)
static void ril_cell_info_update_rate(struct ril_cell_info *self)
{
ril_cell_info_set_rate(self,
(self->display->state == MCE_DISPLAY_STATE_OFF) ?
DISPLAY_OFF_UPDATE_RATE : DISPLAY_ON_UPDATE_RATE);
if (self->sim_card_ready) {
ril_cell_info_set_rate(self,
(self->display->state == MCE_DISPLAY_STATE_OFF) ?
DISPLAY_OFF_UPDATE_RATE : DISPLAY_ON_UPDATE_RATE);
}
}
static void ril_cell_info_display_state_cb(MceDisplay *display, void *arg)
{
struct ril_cell_info *self = RIL_CELL_INFO(arg);
if (self->sim_card_ready) {
ril_cell_info_update_rate(self);
}
ril_cell_info_update_rate(RIL_CELL_INFO(arg));
}
static void ril_cell_info_refresh(struct ril_cell_info *self)
@@ -373,16 +372,11 @@ static void ril_cell_info_radio_state_cb(struct ril_radio *radio, void *arg)
static void ril_cell_info_sim_status_cb(struct ril_sim_card *sim, void *arg)
{
struct ril_cell_info *self = RIL_CELL_INFO(arg);
const gboolean sim_card_was_ready = self->sim_card_ready;
DBG_(self, "%sready", ril_sim_card_ready(sim) ? "" : "not ");
self->sim_card_ready = ril_sim_card_ready(sim);
if (self->sim_card_ready != sim_card_was_ready) {
ril_cell_info_refresh(self);
if (self->sim_card_ready) {
ril_cell_info_update_rate(self);
}
}
DBG_(self, "%sready", self->sim_card_ready ? "" : "not ");
ril_cell_info_refresh(self);
ril_cell_info_update_rate(self);
}
/* sailfish_cell_info interface callbacks */
@@ -483,10 +477,8 @@ struct sailfish_cell_info *ril_cell_info_new(GRilIoChannel *io,
ril_sim_card_add_status_changed_handler(self->sim_card,
ril_cell_info_sim_status_cb, self);
self->sim_card_ready = ril_sim_card_ready(sim_card);
if (self->sim_card_ready) {
ril_cell_info_query(self);
ril_cell_info_update_rate(self);
}
ril_cell_info_refresh(self);
ril_cell_info_update_rate(self);
return &self->info;
}

View File

@@ -18,6 +18,7 @@
#include "ril_network.h"
#include "ril_sim_settings.h"
#include "ril_util.h"
#include "ril_vendor.h"
#include "ril_log.h"
#include <gutil_strv.h>
@@ -207,10 +208,15 @@ GRilIoRequest *ril_request_deactivate_data_call_new(int cid)
* ril_data_call
*==========================================================================*/
static struct ril_data_call *ril_data_call_new()
{
return g_new0(struct ril_data_call, 1);
}
struct ril_data_call *ril_data_call_dup(const struct ril_data_call *call)
{
if (call) {
struct ril_data_call *dc = g_new0(struct ril_data_call, 1);
struct ril_data_call *dc = ril_data_call_new();
dc->cid = call->cid;
dc->status = call->status;
dc->active = call->active;
@@ -227,13 +233,18 @@ struct ril_data_call *ril_data_call_dup(const struct ril_data_call *call)
}
}
static void ril_data_call_destroy(struct ril_data_call *call)
{
g_free(call->ifname);
g_strfreev(call->dnses);
g_strfreev(call->addresses);
g_strfreev(call->gateways);
}
void ril_data_call_free(struct ril_data_call *call)
{
if (call) {
g_free(call->ifname);
g_strfreev(call->dnses);
g_strfreev(call->addresses);
g_strfreev(call->gateways);
ril_data_call_destroy(call);
g_free(call);
}
}
@@ -251,7 +262,7 @@ static void ril_data_call_list_free(struct ril_data_call_list *list)
}
}
static gint ril_data_call_parse_compare(gconstpointer a, gconstpointer b)
static gint ril_data_call_compare(gconstpointer a, gconstpointer b)
{
const struct ril_data_call *ca = a;
const struct ril_data_call *cb = b;
@@ -265,7 +276,7 @@ static gint ril_data_call_parse_compare(gconstpointer a, gconstpointer b)
}
}
static const char *ril_data_ofono_protocol_to_ril(enum ofono_gprs_proto proto)
const char *ril_data_ofono_protocol_to_ril(enum ofono_gprs_proto proto)
{
switch (proto) {
case OFONO_GPRS_PROTO_IPV6:
@@ -279,7 +290,7 @@ static const char *ril_data_ofono_protocol_to_ril(enum ofono_gprs_proto proto)
}
}
static int ril_data_protocol_to_ofono(gchar *str)
int ril_data_protocol_to_ofono(const gchar *str)
{
if (str) {
if (!strcmp(str, PROTO_IPV6_STR)) {
@@ -293,14 +304,13 @@ static int ril_data_protocol_to_ofono(gchar *str)
return -1;
}
static struct ril_data_call *ril_data_call_parse(int version,
GRilIoParser *rilp)
static gboolean ril_data_call_parse_default(struct ril_data_call *call,
int version, GRilIoParser *rilp)
{
int prot;
char *prot_str;
guint32 status = PDP_FAIL_ERROR_UNSPECIFIED;
guint32 active = RIL_DATA_CALL_INACTIVE;
struct ril_data_call *call = g_new0(struct ril_data_call, 1);
/* RIL_Data_Call_Response_v6 (see ril.h) */
grilio_parser_get_uint32(rilp, &status);
@@ -335,13 +345,48 @@ static struct ril_data_call *ril_data_call_parse(int version,
}
g_free(prot_str);
return call;
return TRUE;
}
static struct ril_data_call *ril_data_call_parse(struct ril_vendor_hook *hook,
int version, GRilIoParser *parser)
{
GRilIoParser copy = *parser;
struct ril_data_call *call = ril_data_call_new();
gboolean parsed = ril_vendor_hook_data_call_parse(hook, call,
version, parser);
if (!parsed) {
/* Try the default parser */
ril_data_call_destroy(call);
memset(call, 0, sizeof(*call));
parsed = ril_data_call_parse_default(call, version, &copy);
}
if (parsed) {
DBG("[status=%d,retry=%d,cid=%d,active=%d,type=%s,ifname=%s,"
"mtu=%d,address=%s,dns=%s %s,gateways=%s]",
call->status, call->retry_time,
call->cid, call->active,
ril_data_ofono_protocol_to_ril(call->prot),
call->ifname, call->mtu,
call->addresses ? call->addresses[0] : NULL,
call->dnses ? call->dnses[0] : NULL,
(call->dnses && call->dnses[0] &&
call->dnses[1]) ? call->dnses[1] : "",
call->gateways ? call->gateways[0] : NULL);
return call;
} else {
ril_data_call_free(call);
return NULL;
}
}
static struct ril_data_call_list *ril_data_call_list_parse(const void *data,
guint len, enum ril_data_call_format format)
guint len, struct ril_vendor_hook *hook,
enum ril_data_call_format format)
{
unsigned int version, n, i;
guint32 version, n;
GRilIoParser rilp;
grilio_parser_init(&rilp, data, len);
@@ -358,26 +403,23 @@ static struct ril_data_call_list *ril_data_call_list_parse(const void *data,
list->version = format;
}
for (i = 0; i < n && !grilio_parser_at_end(&rilp); i++) {
struct ril_data_call *call =
ril_data_call_parse(list->version, &rilp);
if (n > 0) {
guint i, clen = grilio_parser_bytes_remaining(&rilp)/n;
DBG("[status=%d,retry=%d,cid=%d,"
"active=%d,type=%s,ifname=%s,mtu=%d,"
"address=%s, dns=%s %s,gateways=%s]",
call->status, call->retry_time,
call->cid, call->active,
ril_data_ofono_protocol_to_ril(call->prot),
call->ifname, call->mtu,
call->addresses ? call->addresses[0] : NULL,
call->dnses ? call->dnses[0] : NULL,
(call->dnses && call->dnses[0] &&
call->dnses[1]) ? call->dnses[1] : "",
call->gateways ? call->gateways[0] : NULL);
for (i = 0; i < n; i++) {
GRilIoParser callp;
struct ril_data_call *call;
list->num++;
list->calls = g_slist_insert_sorted(list->calls, call,
ril_data_call_parse_compare);
grilio_parser_get_data(&rilp, &callp, clen);
call = ril_data_call_parse(hook, list->version,
&callp);
if (call) {
list->num++;
list->calls = g_slist_insert_sorted
(list->calls, call,
ril_data_call_compare);
}
}
}
if (list->calls) {
@@ -471,7 +513,7 @@ static int ril_data_call_list_move_calls(struct ril_data_call_list *dest,
dest->num++;
src->calls = g_slist_delete_link(src->calls, l);
dest->calls = g_slist_insert_sorted(dest->calls,
call, ril_data_call_parse_compare);
call, ril_data_call_compare);
}
l = next;
@@ -527,7 +569,7 @@ static void ril_data_call_list_changed_cb(GRilIoChannel *io, guint event,
}
ril_data_set_calls(self, ril_data_call_list_parse(data, len,
priv->options.data_call_format));
priv->vendor_hook, priv->options.data_call_format));
}
static void ril_data_query_data_calls_cb(GRilIoChannel *io, int ril_status,
@@ -544,7 +586,7 @@ static void ril_data_query_data_calls_cb(GRilIoChannel *io, int ril_status,
priv->query_id = 0;
if (ril_status == RIL_E_SUCCESS) {
ril_data_set_calls(self, ril_data_call_list_parse(data, len,
priv->options.data_call_format));
priv->vendor_hook, priv->options.data_call_format));
} else {
/* RADIO_NOT_AVAILABLE == no calls */
ril_data_set_calls(self, NULL);
@@ -750,7 +792,7 @@ static void ril_data_call_setup_cb(GRilIoChannel *io, int ril_status,
if (ril_status == RIL_E_SUCCESS) {
list = ril_data_call_list_parse(data, len,
priv->options.data_call_format);
priv->vendor_hook, priv->options.data_call_format);
}
if (list) {
@@ -854,19 +896,23 @@ static gboolean ril_data_call_setup_submit(struct ril_data_request *req)
}
}
/*
* TODO: add comments about tethering, other non-public
* profiles...
*/
ioreq = grilio_request_new();
grilio_request_append_int32(ioreq, 7 /* Parameter count */);
grilio_request_append_format(ioreq, "%d", tech);
grilio_request_append_utf8(ioreq, DATA_PROFILE_DEFAULT_STR);
grilio_request_append_utf8(ioreq, setup->apn);
grilio_request_append_utf8(ioreq, setup->username);
grilio_request_append_utf8(ioreq, setup->password);
grilio_request_append_format(ioreq, "%d", auth);
grilio_request_append_utf8(ioreq, proto_str);
/* Give vendor code a chance to build a vendor specific packet */
ioreq = ril_vendor_hook_data_call_req(priv->vendor_hook, tech,
DATA_PROFILE_DEFAULT_STR, setup->apn, setup->username,
setup->password, auth, proto_str);
if (!ioreq) {
/* The default one */
ioreq = grilio_request_new();
grilio_request_append_int32(ioreq, 7 /* Parameter count */);
grilio_request_append_format(ioreq, "%d", tech);
grilio_request_append_utf8(ioreq, DATA_PROFILE_DEFAULT_STR);
grilio_request_append_utf8(ioreq, setup->apn);
grilio_request_append_utf8(ioreq, setup->username);
grilio_request_append_utf8(ioreq, setup->password);
grilio_request_append_format(ioreq, "%d", auth);
grilio_request_append_utf8(ioreq, proto_str);
}
GASSERT(!req->pending_id);
req->pending_id = grilio_queue_send_request_full(priv->q, ioreq,
@@ -1114,7 +1160,8 @@ static gint ril_data_compare_cb(gconstpointer a, gconstpointer b)
struct ril_data *ril_data_new(struct ril_data_manager *dm, const char *name,
struct ril_radio *radio, struct ril_network *network,
GRilIoChannel *io, const struct ril_data_options *options,
const struct ril_slot_config *config)
const struct ril_slot_config *config,
struct ril_vendor_hook *vendor_hook)
{
GASSERT(dm);
if (G_LIKELY(dm)) {
@@ -1147,6 +1194,7 @@ struct ril_data *ril_data_new(struct ril_data_manager *dm, const char *name,
priv->dm = ril_data_manager_ref(dm);
priv->radio = ril_radio_ref(radio);
priv->network = ril_network_ref(network);
priv->vendor_hook = ril_vendor_hook_ref(vendor_hook);
priv->io_event_id = grilio_channel_add_unsol_event_handler(io,
ril_data_call_list_changed_cb,
RIL_UNSOL_DATA_CALL_LIST_CHANGED, self);
@@ -1457,6 +1505,7 @@ static void ril_data_finalize(GObject *object)
ril_network_unref(priv->network);
ril_data_manager_unref(priv->dm);
ril_data_call_list_free(self->data_calls);
ril_vendor_hook_unref(priv->vendor_hook);
G_OBJECT_CLASS(ril_data_parent_class)->finalize(object);
}

View File

@@ -96,7 +96,8 @@ typedef void (*ril_data_call_deactivate_cb_t)(struct ril_data *data,
struct ril_data *ril_data_new(struct ril_data_manager *dm, const char *name,
struct ril_radio *radio, struct ril_network *network,
GRilIoChannel *io, const struct ril_data_options *options,
const struct ril_slot_config *config);
const struct ril_slot_config *config,
struct ril_vendor_hook *vendor_hook);
struct ril_data *ril_data_ref(struct ril_data *data);
void ril_data_unref(struct ril_data *data);
gboolean ril_data_allowed(struct ril_data *data);
@@ -124,6 +125,9 @@ struct ril_data_call *ril_data_call_dup(const struct ril_data_call *call);
struct ril_data_call *ril_data_call_find(struct ril_data_call_list *list,
int cid);
const char *ril_data_ofono_protocol_to_ril(enum ofono_gprs_proto proto);
int ril_data_protocol_to_ofono(const gchar *str);
/* Constructors of various kinds of RIL requests */
GRilIoRequest *ril_request_allow_data_new(gboolean allow);
GRilIoRequest *ril_request_deactivate_data_call_new(int cid);

View File

@@ -58,8 +58,6 @@ struct ril_modem_data {
char *imeisv;
char *imei;
char *ecclist_file;
gboolean pre_sim_done;
gboolean allow_data;
gulong imsi_event_id;
guint online_check_id;
@@ -249,7 +247,6 @@ static void ril_modem_pre_sim(struct ofono_modem *modem)
struct ril_modem_data *md = ril_modem_data_from_ofono(modem);
DBG("%s", ofono_modem_get_path(modem));
md->pre_sim_done = TRUE;
ofono_devinfo_create(modem, 0, RILMODEM_DRIVER, md);
ofono_sim_create(modem, 0, RILMODEM_DRIVER, md);
if (md->modem.config.enable_voicecall) {

View File

@@ -24,6 +24,7 @@
#include "ril_radio_caps.h"
#include "ril_data.h"
#include "ril_util.h"
#include "ril_vendor.h"
#include "ril_log.h"
#include <sailfish_manager.h>
@@ -102,6 +103,7 @@
#define RILCONF_ALLOW_DATA_REQ "allowDataReq"
#define RILCONF_EMPTY_PIN_QUERY "emptyPinQuery"
#define RILCONF_DATA_CALL_FORMAT "dataCallFormat"
#define RILCONF_VENDOR_DRIVER "vendorDriver"
#define RILCONF_DATA_CALL_RETRY_LIMIT "dataCallRetryLimit"
#define RILCONF_DATA_CALL_RETRY_DELAY "dataCallRetryDelay"
#define RILCONF_LOCAL_HANGUP_REASONS "localHangupReasons"
@@ -184,6 +186,8 @@ typedef struct sailfish_slot_impl {
struct ril_sim_card *sim_card;
struct ril_sim_settings *sim_settings;
struct ril_oem_raw *oem_raw;
const struct ril_vendor_driver *vendor;
struct ril_vendor_hook *vendor_hook;
struct ril_data *data;
gboolean legacy_imei_query;
guint start_timeout;
@@ -397,6 +401,11 @@ static void ril_plugin_shutdown_slot(ril_slot *slot, gboolean kill_io)
slot->received_sim_status = FALSE;
}
if (slot->vendor_hook) {
ril_vendor_hook_unref(slot->vendor_hook);
slot->vendor_hook = NULL;
}
if (slot->io) {
int i;
@@ -715,10 +724,12 @@ static void ril_plugin_caps_switch_aborted(struct ril_radio_caps_manager *mgr,
static void ril_plugin_trace(GRilIoChannel *io, GRILIO_PACKET_TYPE type,
guint id, guint code, const void *data, guint data_len, void *user_data)
{
static const GLogModule *log_module = &ril_debug_trace_module;
ril_slot *slot = user_data;
struct ril_vendor_hook *hook = slot->vendor_hook;
static const GLogModule* log_module = &ril_debug_trace_module;
const char *prefix = io->name ? io->name : "";
const char dir = (type == GRILIO_PACKET_REQ) ? '<' : '>';
const char *scode;
const char *scode = NULL;
switch (type) {
case GRILIO_PACKET_REQ:
@@ -726,7 +737,10 @@ static void ril_plugin_trace(GRilIoChannel *io, GRILIO_PACKET_TYPE type,
code == RIL_REQUEST_V9_SET_UICC_SUBSCRIPTION) {
scode = "V9_SET_UICC_SUBSCRIPTION";
} else {
scode = ril_request_to_string(code);
scode = ril_vendor_hook_request_to_string(hook, code);
if (!scode) {
scode = ril_request_to_string(code);
}
}
gutil_log(log_module, GLOG_LEVEL_VERBOSE, "%s%c [%08x] %s",
prefix, dir, id, scode);
@@ -742,8 +756,12 @@ static void ril_plugin_trace(GRilIoChannel *io, GRILIO_PACKET_TYPE type,
break;
case GRILIO_PACKET_UNSOL:
case GRILIO_PACKET_UNSOL_ACK_EXP:
scode = ril_vendor_hook_event_to_string(hook, code);
if (!scode) {
scode = ril_unsol_event_to_string(code);
}
gutil_log(log_module, GLOG_LEVEL_VERBOSE, "%s%c %s",
prefix, dir, ril_unsol_event_to_string(code));
prefix, dir, scode);
break;
}
}
@@ -939,6 +957,10 @@ static void ril_plugin_slot_connected(ril_slot *slot)
*/
ril_plugin_start_imei_query(slot, TRUE, -1);
GASSERT(!slot->vendor_hook);
slot->vendor_hook = ril_vendor_create_hook(slot->vendor, slot->io,
slot->path, &slot->config);
GASSERT(!slot->radio);
slot->radio = ril_radio_new(slot->io);
@@ -965,7 +987,7 @@ static void ril_plugin_slot_connected(ril_slot *slot)
GASSERT(!slot->data);
slot->data = ril_data_new(plugin->data_manager, log_prefix,
slot->radio, slot->network, slot->io, &slot->data_opt,
&slot->config);
&slot->config, slot->vendor_hook);
GASSERT(!slot->cell_info);
if (slot->io->ril_version >= 9) {
@@ -1175,6 +1197,23 @@ static ril_slot *ril_plugin_slot_new_take(char *sockpath, char *path,
return slot;
}
static void ril_plugin_slot_apply_vendor_defaults(ril_slot *slot)
{
if (slot->vendor) {
struct ril_slot_config *config = &slot->config;
struct ril_vendor_defaults defaults;
/* Let the vendor extension to adjust (some) defaults */
memset(&defaults, 0, sizeof(defaults));
defaults.empty_pin_query = config->empty_pin_query;
defaults.legacy_imei_query = slot->legacy_imei_query;
ril_vendor_get_defaults(slot->vendor, &defaults);
config->empty_pin_query = defaults.empty_pin_query;
slot->legacy_imei_query = defaults.legacy_imei_query;
}
}
static ril_slot *ril_plugin_slot_new(const char *sockpath, const char *path,
const char *name, guint slot_index)
{
@@ -1244,6 +1283,25 @@ static ril_slot *ril_plugin_parse_config_group(GKeyFile *file,
DBG("%s: " RILCONF_SLOT " %u", group, config->slot);
}
/* vendorDriver */
sval = ril_config_get_string(file, group, RILCONF_VENDOR_DRIVER);
if (sval) {
const struct ril_vendor_driver *vendor;
RIL_VENDOR_DRIVER_FOREACH(vendor) {
if (!strcasecmp(vendor->name, sval)) {
DBG("%s: " RILCONF_VENDOR_DRIVER " %s", group,
sval);
slot->vendor = vendor;
ril_plugin_slot_apply_vendor_defaults(slot);
break;
}
}
if (!slot->vendor) {
ofono_warn("Unknown vendor '%s'", sval);
}
g_free(sval);
}
/* startTimeout */
if (ril_config_get_integer(file, group, RILCONF_START_TIMEOUT,
&ival) && ival >= 0) {

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2015-2017 Jolla Ltd.
* Copyright (C) 2015-2018 Jolla Ltd.
*
* 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
@@ -18,11 +18,15 @@
#include "ril_util.h"
#include "ril_log.h"
#include "sailfish_watch.h"
#include "simutil.h"
#include "util.h"
#include "ofono.h"
#define SIM_STATE_CHANGE_TIMEOUT_SECS (5)
#define FAC_LOCK_QUERY_TIMEOUT_SECS (10)
#define FAC_LOCK_QUERY_RETRIES (1)
#define SIM_IO_TIMEOUT_SECS (20)
#define EF_STATUS_INVALIDATED 0
#define EF_STATUS_VALID 1
@@ -75,13 +79,16 @@ struct ril_sim {
int retries[OFONO_SIM_PASSWORD_INVALID];
gboolean empty_pin_query_allowed;
gboolean inserted;
guint idle_id;
guint idle_id; /* Used by register and SIM reset callbacks */
gulong card_event_id[SIM_CARD_EVENT_COUNT];
guint query_pin_retries_id;
const char *log_prefix;
char *allocated_log_prefix;
struct sailfish_watch *watch;
gulong sim_state_watch_id;
/* query_passwd_state context */
ofono_sim_passwd_cb_t query_passwd_state_cb;
void *query_passwd_state_cb_data;
@@ -485,6 +492,7 @@ static void ril_sim_request_io(struct ril_sim *sd, guint cmd, int fileid,
grilio_request_append_utf8(req, ril_sim_app_id(sd));
grilio_request_set_blocking(req, TRUE);
grilio_request_set_timeout(req, SIM_IO_TIMEOUT_SECS * 1000);
cbd->req_id = grilio_queue_send_request_full(sd->q, req,
RIL_REQUEST_SIM_IO, cb, ril_sim_cbd_free, cbd);
ril_sim_card_sim_io_started(sd->card, cbd->req_id);
@@ -850,6 +858,34 @@ static void ril_sim_status_changed_cb(struct ril_sim_card *sc, void *user_data)
}
}
static gboolean ril_sim_reinsert_cb(gpointer data)
{
struct ril_sim *sd = data;
const enum ofono_sim_state state = ofono_sim_get_state(sd->watch->sim);
GASSERT(sd->idle_id);
sd->idle_id = 0;
if (state == OFONO_SIM_STATE_RESETTING && sd->inserted) {
DBG_(sd, "reinserting SIM");
ofono_sim_inserted_notify(sd->sim, TRUE);
}
return G_SOURCE_REMOVE;
}
static void ril_sim_state_changed_cb(struct sailfish_watch *watch, void *data)
{
struct ril_sim *sd = data;
const enum ofono_sim_state state = ofono_sim_get_state(watch->sim);
DBG_(sd, "%d %d", state, sd->inserted);
if (state == OFONO_SIM_STATE_RESETTING && sd->inserted &&
!sd->idle_id) {
sd->idle_id = g_idle_add(ril_sim_reinsert_cb, sd);
}
}
static int ril_sim_parse_retry_count(const void *data, guint len)
{
int retry_count = -1;
@@ -864,10 +900,14 @@ static int ril_sim_parse_retry_count(const void *data, guint len)
static GRilIoRequest *ril_sim_enter_sim_pin_req(struct ril_sim *sd,
const char *pin)
{
const char *app_id = ril_sim_app_id(sd);
if (app_id) {
if (sd->card->app) {
/*
* If there's no AID then so be it... Some
* adaptations (namely, MTK) don't provide it
* but don't seem to require it either.
*/
GRilIoRequest *req = grilio_request_array_utf8_new(2,
pin, app_id);
pin, sd->card->app->aid);
grilio_request_set_blocking(req, TRUE);
return req;
@@ -1356,6 +1396,13 @@ static void ril_sim_query_facility_lock_cb(GRilIoChannel *io, int status,
cb(ril_error_failure(&error), FALSE, cbd->data);
}
static gboolean ril_sim_query_facility_lock_retry(GRilIoRequest* req,
int ril_status, const void* response_data,
guint response_len, void* user_data)
{
return (ril_status == GRILIO_STATUS_TIMEOUT);
}
static void ril_sim_query_facility_lock(struct ofono_sim *sim,
enum ofono_sim_password_type type,
ofono_query_facility_lock_cb_t cb, void *data)
@@ -1366,6 +1413,11 @@ static void ril_sim_query_facility_lock(struct ofono_sim *sim,
GRilIoRequest *req = grilio_request_array_utf8_new(4,
type_str, "", "0" /* class */, ril_sim_app_id(sd));
/* Make sure that this request gets completed sooner or later */
grilio_request_set_timeout(req, FAC_LOCK_QUERY_TIMEOUT_SECS * 1000);
grilio_request_set_retry(req, RIL_RETRY_MS, FAC_LOCK_QUERY_RETRIES);
grilio_request_set_retry_func(req, ril_sim_query_facility_lock_retry);
DBG_(sd, "%s", type_str);
cbd->req_id = grilio_queue_send_request_full(sd->q, req,
RIL_REQUEST_QUERY_FACILITY_LOCK, ril_sim_query_facility_lock_cb,
@@ -1391,6 +1443,9 @@ static gboolean ril_sim_register(gpointer user)
sd->card_event_id[SIM_CARD_APP_EVENT] =
ril_sim_card_add_app_changed_handler(sd->card,
ril_sim_app_changed_cb, sd);
sd->sim_state_watch_id =
sailfish_watch_add_sim_state_changed_handler(sd->watch,
ril_sim_state_changed_cb, sd);
/* Check the current state */
ril_sim_status_changed_cb(sd->card, sd);
@@ -1409,6 +1464,7 @@ static int ril_sim_probe(struct ofono_sim *sim, unsigned int vendor,
sd->io = grilio_channel_ref(ril_modem_io(modem));
sd->card = ril_sim_card_ref(modem->sim_card);
sd->q = grilio_queue_new(sd->io);
sd->watch = sailfish_watch_new(ril_modem_get_path(modem));
if (modem->log_prefix && modem->log_prefix[0]) {
sd->log_prefix = sd->allocated_log_prefix =
@@ -1445,6 +1501,9 @@ static void ril_sim_remove(struct ofono_sim *sim)
sd->query_passwd_state_sim_status_refresh_id);
}
sailfish_watch_remove_handler(sd->watch, sd->sim_state_watch_id);
sailfish_watch_unref(sd->watch);
ril_sim_card_remove_handlers(sd->card, sd->card_event_id,
G_N_ELEMENTS(sd->card_event_id));
ril_sim_card_unref(sd->card);

View File

@@ -41,10 +41,12 @@ struct ofono_sim;
#define RIL_RETRY_MS (RIL_RETRY_SECS*1000)
struct ril_data;
struct ril_data_call;
struct ril_modem;
struct ril_radio;
struct ril_network;
struct ril_sim_card;
struct ril_vendor_hook;
struct ril_slot_config {
guint slot;

View File

@@ -0,0 +1,165 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2016-2017 Jolla Ltd.
*
* 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.
*/
#include "ril_vendor.h"
#include "ril_log.h"
struct ril_vendor_hook *ril_vendor_create_hook
(const struct ril_vendor_driver *vendor, GRilIoChannel *io,
const char *path, const struct ril_slot_config *config)
{
if (vendor) {
const void *data = vendor->driver_data;
/*
* NOTE: we are looking for the callback in the base but
* keeping the original driver data.
*/
while (!vendor->create_hook && vendor->base) {
vendor = vendor->base;
}
if (vendor->create_hook) {
return vendor->create_hook(data, io, path, config);
}
}
return NULL;
}
struct ril_vendor_hook *ril_vendor_hook_init(struct ril_vendor_hook *self,
const struct ril_vendor_hook_proc *proc)
{
self->proc = proc;
g_atomic_int_set(&self->ref_count, 1);
return self;
}
struct ril_vendor_hook *ril_vendor_hook_ref(struct ril_vendor_hook *self)
{
if (self) {
GASSERT(self->ref_count > 0);
g_atomic_int_inc(&self->ref_count);
}
return self;
}
static void ril_vendor_hook_free(struct ril_vendor_hook *self)
{
const struct ril_vendor_hook_proc *proc = self->proc;
while (!proc->free && proc->base) {
proc = proc->base;
}
if (proc->free) {
proc->free(self);
}
}
void ril_vendor_hook_unref(struct ril_vendor_hook *self)
{
if (self) {
GASSERT(self->ref_count > 0);
if (g_atomic_int_dec_and_test(&self->ref_count)) {
ril_vendor_hook_free(self);
}
}
}
void ril_vendor_get_defaults(const struct ril_vendor_driver *vendor,
struct ril_vendor_defaults *defaults)
{
if (vendor) {
while (!vendor->get_defaults && vendor->base) {
vendor = vendor->base;
}
if (vendor->get_defaults) {
vendor->get_defaults(defaults);
}
}
}
const char *ril_vendor_hook_request_to_string(struct ril_vendor_hook *self,
guint request)
{
if (self) {
const struct ril_vendor_hook_proc *proc = self->proc;
while (!proc->request_to_string && proc->base) {
proc = proc->base;
}
if (proc->request_to_string) {
return proc->request_to_string(self, request);
}
}
return NULL;
}
const char *ril_vendor_hook_event_to_string(struct ril_vendor_hook *self,
guint event)
{
if (self) {
const struct ril_vendor_hook_proc *proc = self->proc;
while (!proc->event_to_string && proc->base) {
proc = proc->base;
}
if (proc->event_to_string) {
return proc->event_to_string(self, event);
}
}
return NULL;
}
GRilIoRequest *ril_vendor_hook_data_call_req(struct ril_vendor_hook *self,
int tech, const char *profile, const char *apn,
const char *username, const char *password,
enum ril_auth auth, const char *proto)
{
if (self) {
const struct ril_vendor_hook_proc *proc = self->proc;
while (!proc->data_call_req && proc->base) {
proc = proc->base;
}
if (proc->data_call_req) {
return proc->data_call_req(self, tech, profile, apn,
username, password, auth, proto);
}
}
return NULL;
}
gboolean ril_vendor_hook_data_call_parse(struct ril_vendor_hook *self,
struct ril_data_call *call, int ver, GRilIoParser *rilp)
{
if (self) {
const struct ril_vendor_hook_proc *proc = self->proc;
while (!proc->data_call_parse && proc->base) {
proc = proc->base;
}
if (proc->data_call_parse) {
return proc->data_call_parse(self, call, ver, rilp);
}
}
return FALSE;
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

@@ -0,0 +1,97 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2016-2017 Jolla Ltd.
*
* 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.
*/
#ifndef RIL_VENDOR_H
#define RIL_VENDOR_H
#include "ril_types.h"
struct ril_vendor_defaults {
gboolean empty_pin_query;
gboolean legacy_imei_query;
};
struct ril_vendor_driver {
const char *name;
const void *driver_data;
const struct ril_vendor_driver *base;
void (*get_defaults)(struct ril_vendor_defaults *defaults);
struct ril_vendor_hook *(*create_hook)(const void *driver_data,
GRilIoChannel *io, const char *path,
const struct ril_slot_config *cfg);
};
struct ril_vendor_hook_proc {
const struct ril_vendor_hook_proc *base;
void (*free)(struct ril_vendor_hook *hook);
const char *(*request_to_string)(struct ril_vendor_hook *hook,
guint request);
const char *(*event_to_string)(struct ril_vendor_hook *hook,
guint event);
GRilIoRequest *(*data_call_req)(struct ril_vendor_hook *hook,
int tech, const char *profile, const char *apn,
const char *username, const char *password,
enum ril_auth auth, const char *proto);
gboolean (*data_call_parse)(struct ril_vendor_hook *hook,
struct ril_data_call *call, int version,
GRilIoParser *rilp);
};
struct ril_vendor_hook {
const struct ril_vendor_hook_proc *proc;
gint ref_count;
};
struct ril_vendor_hook *ril_vendor_create_hook
(const struct ril_vendor_driver *vendor, GRilIoChannel *io,
const char *path, const struct ril_slot_config *cfg);
void ril_vendor_get_defaults(const struct ril_vendor_driver *vendor,
struct ril_vendor_defaults *defaults);
struct ril_vendor_hook *ril_vendor_hook_init(struct ril_vendor_hook *hook,
const struct ril_vendor_hook_proc *proc);
struct ril_vendor_hook *ril_vendor_hook_ref(struct ril_vendor_hook *hook);
void ril_vendor_hook_unref(struct ril_vendor_hook *hook);
const char *ril_vendor_hook_request_to_string(struct ril_vendor_hook *hook,
guint request);
const char *ril_vendor_hook_event_to_string(struct ril_vendor_hook *hook,
guint event);
GRilIoRequest *ril_vendor_hook_data_call_req(struct ril_vendor_hook *hook,
int tech, const char *profile, const char *apn,
const char *username, const char *password,
enum ril_auth auth, const char *proto);
gboolean ril_vendor_hook_data_call_parse(struct ril_vendor_hook *hook,
struct ril_data_call *call, int version,
GRilIoParser *rilp);
/* Put vendor driver descriptors to the "__vendor" section */
#define RIL_VENDOR_DRIVER_DEFINE(name) \
const struct ril_vendor_driver name \
__attribute__((used, section("__vendor"))) =
#define RIL_VENDOR_DRIVER_FOREACH(var) \
for ((var) = __start___vendor; (var) < __stop___vendor; (var)++)
extern const struct ril_vendor_driver __start___vendor[];
extern const struct ril_vendor_driver __stop___vendor[];
#endif /* RIL_VENDOR_H */
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

@@ -0,0 +1,488 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2016-2017 Jolla Ltd.
*
* 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.
*/
#include "ril_plugin.h"
#include "ril_vendor.h"
#include "ril_data.h"
#include "ril_log.h"
#include "sailfish_watch.h"
#include <grilio_channel.h>
#include <grilio_parser.h>
#include <grilio_request.h>
#include <grilio_queue.h>
#include <gutil_macros.h>
#include "ofono.h"
enum ril_mtk_watch_events {
WATCH_EVENT_SIM_CHANGED,
WATCH_EVENT_COUNT
};
enum ril_mtk_events {
MTK_EVENT_REGISTRATION_SUSPENDED,
MTK_EVENT_SET_ATTACH_APN,
MTK_EVENT_COUNT
};
struct ril_vendor_hook_mtk {
struct ril_vendor_hook hook;
const struct ril_mtk_msg *msg;
GRilIoQueue *q;
GRilIoChannel *io;
struct sailfish_watch *watch;
gulong ril_event_id[MTK_EVENT_COUNT];
guint slot;
};
/* driver_data point this this: */
struct ril_vendor_mtk_driver_data {
const char *name;
const struct ril_mtk_msg *msg;
const struct ril_vendor_hook_proc *proc;
};
/* MTK specific RIL messages (actual codes differ from model to model!) */
struct ril_mtk_msg {
guint request_resume_registration;
guint unsol_network_info;
guint unsol_ps_network_state_changed;
guint unsol_registration_suspended;
guint unsol_ims_registration_info;
guint unsol_volte_eps_network_feature_support;
guint unsol_emergency_bearer_support_notify;
guint unsol_set_attach_apn;
};
/* Fly FS522 Cirrus 14 */
static const struct ril_mtk_msg mtk_msg_mt6737 = {
.request_resume_registration = 2050,
.unsol_network_info = 3001,
.unsol_ps_network_state_changed = 3012,
.unsol_registration_suspended = 3021,
.unsol_ims_registration_info = 3029,
.unsol_volte_eps_network_feature_support = 3042,
.unsol_emergency_bearer_support_notify = 3052,
.unsol_set_attach_apn = 3065
};
/* MT8735 Tablet */
static const struct ril_mtk_msg mtk_msg_mt8735 = {
.request_resume_registration = 2065,
.unsol_network_info = 3001,
.unsol_ps_network_state_changed = 3015,
.unsol_ims_registration_info = 3033,
.unsol_volte_eps_network_feature_support = 3048,
.unsol_emergency_bearer_support_notify = 3059,
.unsol_registration_suspended = 3024
};
static inline struct ril_vendor_hook_mtk *ril_vendor_hook_mtk_cast
(struct ril_vendor_hook *hook)
{
return G_CAST(hook, struct ril_vendor_hook_mtk, hook);
}
static const char *ril_vendor_mtk_request_to_string
(struct ril_vendor_hook *hook, guint request)
{
struct ril_vendor_hook_mtk *self = ril_vendor_hook_mtk_cast(hook);
const struct ril_mtk_msg *msg = self->msg;
if (request == msg->request_resume_registration) {
return "MTK_RESUME_REGISTRATION";
} else {
return NULL;
}
}
static const char *ril_vendor_mtk_event_to_string(struct ril_vendor_hook *hook,
guint event)
{
struct ril_vendor_hook_mtk *self = ril_vendor_hook_mtk_cast(hook);
const struct ril_mtk_msg *msg = self->msg;
if (event == msg->unsol_network_info) {
return "MTK_NETWORK_INFO";
} else if (event == msg->unsol_ps_network_state_changed) {
return "MTK_PS_NETWORK_STATE_CHANGED";
} else if (event == msg->unsol_registration_suspended) {
return "MTK_REGISTRATION_SUSPENDED";
} else if (event == msg->unsol_ims_registration_info) {
return "MTK_IMS_REGISTRATION_INFO";
} else if (event == msg->unsol_volte_eps_network_feature_support) {
return "MTK_VOLTE_EPS_NETWORK_FEATURE_SUPPORT";
} else if (event == msg->unsol_emergency_bearer_support_notify) {
return "MTK_EMERGENCY_BEARER_SUPPORT_NOTIFY";
} else if (event == msg->unsol_set_attach_apn) {
return "MTK_SET_ATTACH_APN";
} else {
return NULL;
}
}
static void ril_vendor_mtk_registration_suspended(GRilIoChannel *io, guint id,
const void *data, guint len, void *user_data)
{
struct ril_vendor_hook_mtk *self = user_data;
const struct ril_mtk_msg *msg = self->msg;
GRilIoParser rilp;
int session_id;
GASSERT(id == msg->unsol_registration_suspended);
grilio_parser_init(&rilp, data, len);
if (grilio_parser_get_int32(&rilp, NULL) &&
grilio_parser_get_int32(&rilp, &session_id)) {
GRilIoRequest* req = grilio_request_new();
DBG("slot=%u,session_id=%d", self->slot, session_id);
grilio_request_append_int32(req, 1);
grilio_request_append_int32(req, session_id);
grilio_queue_send_request(self->q, req,
msg->request_resume_registration);
grilio_request_unref(req);
}
}
static void ril_vendor_mtk_set_attach_apn(GRilIoChannel *io, guint id,
const void *data, guint len, void *user_data)
{
struct ril_vendor_hook_mtk *self = user_data;
struct sailfish_watch *watch = self->watch;
struct ofono_atom * gprs_atom = __ofono_modem_find_atom(watch->modem,
OFONO_ATOM_TYPE_GPRS);
struct ofono_gprs *gprs = gprs_atom ?
__ofono_atom_get_data(gprs_atom) : NULL;
const struct ofono_gprs_primary_context *pc =
(gprs && watch->imsi) ?
__ofono_gprs_context_settings_by_type(gprs,
OFONO_GPRS_CONTEXT_TYPE_INTERNET) : NULL;
/* authtype, username, password */
if (pc) {
GRilIoRequest *req = grilio_request_new();
const char *proto = ril_data_ofono_protocol_to_ril(pc->proto);
DBG("%s",pc->apn);
grilio_request_append_utf8(req, pc->apn); /* apn */
grilio_request_append_utf8(req, proto); /* protocol */
grilio_request_append_utf8(req, proto); /* roamingProtocol */
if (pc->username[0]) {
int auth;
switch (pc->auth_method) {
case OFONO_GPRS_AUTH_METHOD_ANY:
auth = RIL_AUTH_BOTH;
break;
case OFONO_GPRS_AUTH_METHOD_NONE:
auth = RIL_AUTH_NONE;
break;
case OFONO_GPRS_AUTH_METHOD_CHAP:
auth = RIL_AUTH_CHAP;
break;
case OFONO_GPRS_AUTH_METHOD_PAP:
auth = RIL_AUTH_PAP;
break;
default:
auth = RIL_AUTH_NONE;
break;
}
grilio_request_append_int32(req, auth);
grilio_request_append_utf8(req, pc->username);
grilio_request_append_utf8(req, pc->password);
} else {
grilio_request_append_int32(req, RIL_AUTH_NONE);
grilio_request_append_utf8(req, "");
grilio_request_append_utf8(req, "");
}
grilio_request_append_utf8(req, ""); /* operatorNumeric */
grilio_request_append_int32(req, FALSE); /* canHandleIms */
grilio_request_append_int32(req, 0); /* Some sort of count */
grilio_queue_send_request(self->q, req,
RIL_REQUEST_SET_INITIAL_ATTACH_APN);
grilio_request_unref(req);
}
}
static GRilIoRequest* ril_vendor_mtk_data_call_req
(struct ril_vendor_hook *hook, int tech, const char *profile,
const char *apn, const char *username, const char *password,
enum ril_auth auth, const char *proto)
{
struct ril_vendor_hook_mtk *self = ril_vendor_hook_mtk_cast(hook);
GRilIoRequest *req = grilio_request_new();
grilio_request_append_int32(req, 8); /* Number of parameters */
grilio_request_append_format(req, "%d", tech);
grilio_request_append_utf8(req, profile);
grilio_request_append_utf8(req, apn);
grilio_request_append_utf8(req, username);
grilio_request_append_utf8(req, password);
grilio_request_append_format(req, "%d", auth);
grilio_request_append_utf8(req, proto);
grilio_request_append_format(req, "%d", self->slot+1);
return req;
}
static gboolean ril_vendor_mtk_data_call_parse_v6(struct ril_vendor_hook *hook,
struct ril_data_call *call, int version,
GRilIoParser *rilp)
{
if (version < 11) {
int prot;
char *prot_str;
guint32 status = PDP_FAIL_ERROR_UNSPECIFIED;
guint32 active = RIL_DATA_CALL_INACTIVE;
/* RIL_Data_Call_Response_v6 with MTK specific additions */
grilio_parser_get_uint32(rilp, &status);
grilio_parser_get_int32(rilp, &call->retry_time);
grilio_parser_get_int32(rilp, &call->cid);
grilio_parser_get_uint32(rilp, &active);
grilio_parser_get_int32(rilp, &call->mtu); /* MTK specific */
prot_str = grilio_parser_get_utf8(rilp);
prot = ril_data_protocol_to_ofono(prot_str);
g_free(prot_str);
if (prot >= 0) {
call->ifname = grilio_parser_get_utf8(rilp);
call->addresses = grilio_parser_split_utf8(rilp, " ");
call->dnses = grilio_parser_split_utf8(rilp, " ");
call->gateways = grilio_parser_split_utf8(rilp, " ");
if (call->ifname && call->addresses) {
call->prot = prot;
call->status = status;
call->active = active;
return TRUE;
}
}
}
return FALSE;
}
static void ril_vendor_mtk_get_defaults(struct ril_vendor_defaults *defaults)
{
defaults->empty_pin_query = FALSE;
defaults->legacy_imei_query = TRUE;
}
static struct ril_vendor_hook *ril_vendor_mtk_create_hook_from_data
(const void *driver_data, GRilIoChannel *io, const char *path,
const struct ril_slot_config *config)
{
const struct ril_vendor_mtk_driver_data *mtk_driver_data = driver_data;
const struct ril_mtk_msg *msg = mtk_driver_data->msg;
struct ril_vendor_hook_mtk *self =
g_new0(struct ril_vendor_hook_mtk, 1);
self->msg = msg;
self->q = grilio_queue_new(io);
self->io = grilio_channel_ref(io);
self->watch = sailfish_watch_new(path);
self->slot = config->slot;
self->ril_event_id[MTK_EVENT_REGISTRATION_SUSPENDED] =
grilio_channel_add_unsol_event_handler(self->io,
ril_vendor_mtk_registration_suspended,
msg->unsol_registration_suspended, self);
if (msg->unsol_set_attach_apn) {
self->ril_event_id[MTK_EVENT_SET_ATTACH_APN] =
grilio_channel_add_unsol_event_handler(self->io,
ril_vendor_mtk_set_attach_apn,
msg->unsol_set_attach_apn, self);
}
DBG("%s slot %u", mtk_driver_data->name, self->slot);
return ril_vendor_hook_init(&self->hook, mtk_driver_data->proc);
}
static void ril_vendor_mtk_free(struct ril_vendor_hook *hook)
{
struct ril_vendor_hook_mtk *self = ril_vendor_hook_mtk_cast(hook);
DBG("slot %u", self->slot);
grilio_queue_cancel_all(self->q, FALSE);
grilio_channel_remove_all_handlers(self->io, self->ril_event_id);
grilio_queue_unref(self->q);
grilio_channel_unref(self->io);
sailfish_watch_unref(self->watch);
g_free(self);
}
static const struct ril_vendor_hook_proc ril_vendor_mtk_hook_base_proc = {
.free = ril_vendor_mtk_free,
.request_to_string = ril_vendor_mtk_request_to_string,
.event_to_string = ril_vendor_mtk_event_to_string,
.data_call_req = ril_vendor_mtk_data_call_req
};
static const struct ril_vendor_driver ril_vendor_mtk_base = {
.get_defaults = ril_vendor_mtk_get_defaults,
.create_hook = ril_vendor_mtk_create_hook_from_data
};
static const struct ril_vendor_mtk_driver_data ril_vendor_mtk_mt6737_data = {
.name = "MT6737",
.msg = &mtk_msg_mt6737,
.proc = &ril_vendor_mtk_hook_base_proc
};
static struct ril_vendor_hook_proc ril_vendor_mtk_mt8735_proc = {
.base = &ril_vendor_mtk_hook_base_proc,
.data_call_parse = ril_vendor_mtk_data_call_parse_v6
};
static const struct ril_vendor_mtk_driver_data ril_vendor_mtk_mt8735_data = {
.name = "MT8735",
.msg = &mtk_msg_mt8735,
.proc = &ril_vendor_mtk_mt8735_proc
};
RIL_VENDOR_DRIVER_DEFINE(ril_vendor_driver_mt6737) {
.name = "mt6737t",
.driver_data = &ril_vendor_mtk_mt6737_data,
.base = &ril_vendor_mtk_base
};
RIL_VENDOR_DRIVER_DEFINE(ril_vendor_driver_mt8735) {
.name = "mt8735",
.driver_data = &ril_vendor_mtk_mt8735_data,
.base = &ril_vendor_mtk_base
};
#define DEFAULT_MTK_DRIVER (&ril_vendor_driver_mt6737)
static const struct ril_vendor_driver *mtk_hw_drivers [] = {
&ril_vendor_driver_mt6737,
&ril_vendor_driver_mt8735
};
/* Automatic driver selection based on /proc/cpuinfo */
static GString *ril_vendor_mtk_read_line(GString *buf, FILE *f)
{
int c = fgetc(f);
g_string_truncate(buf, 0);
if (c != EOF) {
/* Read the line char by char until we hit EOF or EOL */
while (c != EOF && c != '\r' && c != '\n') {
g_string_append_c(buf, c);
c = fgetc(f);
}
/* Skip EOL characters */
while (c != EOF && (c == '\r' || c == '\n')) {
c = fgetc(f);
}
/* Unget the last char (the first char of the next line) */
if (c != EOF) {
ungetc(c, f);
}
return buf;
}
return NULL;
}
static char *ril_vendor_mtk_hardware()
{
FILE *f = fopen("/proc/cpuinfo", "r");
char *hardware = NULL;
if (f) {
const char prefix[] = "Hardware\t:";
const gsize prefix_len = sizeof(prefix) - 1;
GString *buf = g_string_new("");
/* Find the "Hardware:" line */
while (ril_vendor_mtk_read_line(buf, f) &&
strncmp(buf->str, prefix, prefix_len));
if (buf->len > prefix_len) {
/* Erase the prefix */
g_string_erase(buf, 0, prefix_len);
/* Remove trailing whitespaces */
while (buf->len > 0 &&
g_ascii_isspace(buf->str[buf->len - 1])) {
g_string_truncate(buf, buf->len - 1);
}
/* Extract the last word */
if (buf->len > 0) {
gsize pos = buf->len;
while (pos > 0 &&
!g_ascii_isspace(buf->str[pos - 1])) {
pos--;
}
if (buf->str[pos]) {
hardware = g_strdup(buf->str + pos);
DBG("Hardware: %s", hardware);
}
}
}
g_string_free(buf, TRUE);
fclose(f);
}
return hardware;
}
static const struct ril_vendor_driver *ril_vendor_mtk_detect()
{
const struct ril_vendor_driver *driver = DEFAULT_MTK_DRIVER;
char *hw = ril_vendor_mtk_hardware();
if (hw) {
guint i;
for (i = 0; i < G_N_ELEMENTS(mtk_hw_drivers); i++) {
if (!strcasecmp(mtk_hw_drivers[i]->name, hw)) {
driver = mtk_hw_drivers[i];
DBG("Driver: %s", driver->name);
break;
}
}
g_free(hw);
}
return driver;
}
static struct ril_vendor_hook *ril_vendor_mtk_create_hook_auto
(const void *driver_data, GRilIoChannel *io, const char *path,
const struct ril_slot_config *cfg)
{
return ril_vendor_create_hook(ril_vendor_mtk_detect(), io, path, cfg);
}
RIL_VENDOR_DRIVER_DEFINE(ril_vendor_driver_mtk) {
.name = "mtk",
.get_defaults = ril_vendor_mtk_get_defaults,
.create_hook = ril_vendor_mtk_create_hook_auto
};
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

@@ -119,6 +119,13 @@ typedef void (*ofono_sms_filter_recv_datagram_cb_t)
#define OFONO_SMS_FILTER_PRIORITY_DEFAULT (0)
#define OFONO_SMS_FILTER_PRIORITY_HIGH (100)
/*
* The api_version field makes it possible to keep using old plugins
* even if struct ofono_sms_filter gets extended with new callbacks.
*/
#define OFONO_SMS_FILTER_API_VERSION (0)
/*
* The filter callbacks either invoke the completion callback directly
* or return the id of the cancellable asynchronous operation (but never
@@ -135,6 +142,7 @@ typedef void (*ofono_sms_filter_recv_datagram_cb_t)
*/
struct ofono_sms_filter {
const char *name;
int api_version; /* OFONO_SMS_FILTER_API_VERSION */
int priority;
unsigned int (*filter_send_text)(struct ofono_modem *modem,
const struct ofono_sms_address *addr,

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2016-2017 Jolla Ltd.
* Copyright (C) 2016-2018 Jolla Ltd.
*
* 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
@@ -178,7 +178,7 @@ static void sailfish_cell_info_dbus_append_type(DBusMessageIter *it,
static void sailfish_cell_info_dbus_append_registered(DBusMessageIter *it,
const struct sailfish_cell_entry *entry)
{
dbus_bool_t registered = entry->cell.registered;
const dbus_bool_t registered = (entry->cell.registered != FALSE);
dbus_message_iter_append_basic(it, DBUS_TYPE_BOOLEAN, &registered);
}
@@ -279,8 +279,8 @@ static const GDBusSignalTable sailfish_cell_info_dbus_cell_signals[] = {
{ }
};
static struct sailfish_cell_entry *sailfish_cell_info_dbus_find_id(
struct sailfish_cell_info_dbus *dbus, guint id)
static struct sailfish_cell_entry *sailfish_cell_info_dbus_find_id
(struct sailfish_cell_info_dbus *dbus, guint id)
{
GSList *l;
for (l = dbus->entries; l; l = l->next) {
@@ -376,7 +376,7 @@ static void sailfish_cell_info_dbus_property_changed
sailfish_cell_info_dbus_cell_properties(cell->type, &n);
if (mask & SAILFISH_CELL_PROPERTY_REGISTERED) {
dbus_bool_t registered = cell->registered;
const dbus_bool_t registered = (cell->registered != FALSE);
g_dbus_emit_signal(dbus->conn, entry->path,
CELL_DBUS_INTERFACE,
CELL_DBUS_REGISTERED_CHANGED_SIGNAL,

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony
*
* Copyright (C) 2017 Jolla Ltd.
* Copyright (C) 2017-2018 Jolla Ltd.
*
* 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
@@ -795,9 +795,6 @@ void sailfish_manager_set_sim_state(struct sailfish_slot *s,
slot->pub.sim_present = present;
sailfish_manager_dbus_signal_sim(p->dbus,
slot->index, present);
if (!present) {
sailfish_sim_info_invalidate(slot->siminfo);
}
sailfish_manager_update_modem_paths_full(p);
}

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony
*
* Copyright (C) 2017 Jolla Ltd.
* Copyright (C) 2017-2018 Jolla Ltd.
*
* 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
@@ -65,6 +65,7 @@ struct sailfish_sim_info_priv {
guint netreg_status_watch_id;
gboolean update_imsi_cache;
gboolean update_iccid_map;
int queued_signals;
};
enum sailfish_sim_info_signal {
@@ -94,12 +95,37 @@ G_DEFINE_TYPE(SailfishSimInfo, sailfish_sim_info, G_TYPE_OBJECT)
/* Skip the leading slash from the modem path: */
#define DBG_(obj,fmt,args...) DBG("%s " fmt, (obj)->path+1, ##args)
static int sailfish_sim_info_signal_bit(enum sailfish_sim_info_signal id)
{
return (1 << id);
}
static void sailfish_sim_info_signal_emit(struct sailfish_sim_info *self,
enum sailfish_sim_info_signal id)
{
self->priv->queued_signals &= ~sailfish_sim_info_signal_bit(id);
g_signal_emit(self, sailfish_sim_info_signals[id], 0);
}
static void sailfish_sim_info_signal_queue(struct sailfish_sim_info *self,
enum sailfish_sim_info_signal id)
{
self->priv->queued_signals |= sailfish_sim_info_signal_bit(id);
}
static void sailfish_sim_info_emit_queued_signals
(struct sailfish_sim_info *self)
{
struct sailfish_sim_info_priv *priv = self->priv;
int i;
for (i = 0; priv->queued_signals && i < SIGNAL_COUNT; i++) {
if (priv->queued_signals & sailfish_sim_info_signal_bit(i)) {
sailfish_sim_info_signal_emit(self, i);
}
}
}
static void sailfish_sim_info_update_imsi_cache(struct sailfish_sim_info *self)
{
struct sailfish_sim_info_priv *priv = self->priv;
@@ -178,8 +204,15 @@ static void sailfish_sim_info_update_public_spn(struct sailfish_sim_info *self)
if (g_strcmp0(priv->public_spn, spn)) {
g_free(priv->public_spn);
self->spn = priv->public_spn = g_strdup(spn);
sailfish_sim_info_signal_emit(self, SIGNAL_SPN_CHANGED);
if (spn && spn[0]) {
DBG_(self, "public spn \"%s\"", spn);
priv->public_spn = g_strdup(spn);
} else {
DBG_(self, "no public spn");
priv->public_spn = NULL;
}
self->spn = priv->public_spn;
sailfish_sim_info_signal_queue(self, SIGNAL_SPN_CHANGED);
}
}
@@ -188,16 +221,13 @@ static void sailfish_sim_info_set_cached_spn(struct sailfish_sim_info *self,
{
struct sailfish_sim_info_priv *priv = self->priv;
GASSERT(spn);
if (g_strcmp0(priv->cached_spn, spn)) {
DBG_(self, "%s", spn);
g_free(priv->cached_spn);
if (spn) {
DBG_(self, "cached spn \"%s\"", spn);
priv->cached_spn = g_strdup(spn);
priv->update_imsi_cache = TRUE;
sailfish_sim_info_update_imsi_cache(self);
} else {
priv->cached_spn = NULL;
}
priv->cached_spn = g_strdup(spn);
priv->update_imsi_cache = TRUE;
sailfish_sim_info_update_imsi_cache(self);
sailfish_sim_info_update_public_spn(self);
}
}
@@ -207,6 +237,7 @@ static void sailfish_sim_info_set_spn(struct sailfish_sim_info *self,
{
struct sailfish_sim_info_priv *priv = self->priv;
GASSERT(spn);
if (g_strcmp0(priv->sim_spn, spn)) {
DBG_(self, "%s", spn);
g_free(priv->sim_spn);
@@ -254,29 +285,24 @@ static void sailfish_sim_info_update_default_spn(struct sailfish_sim_info *self)
}
}
static void sailfish_sim_info_set_imsi(struct sailfish_sim_info *self,
const char *imsi)
static void sailfish_sim_info_update_imsi(struct sailfish_sim_info *self)
{
struct sailfish_sim_info_priv *priv = self->priv;
const char *imsi = priv->watch->imsi;
if (g_strcmp0(priv->imsi, imsi)) {
/* IMSI only gets reset when ICCID disappears, ignore NULL IMSI here */
if (imsi && imsi[0] && g_strcmp0(priv->imsi, imsi)) {
DBG_(self, "%s", imsi);
g_free(priv->imsi);
self->imsi = priv->imsi = g_strdup(imsi);
priv->update_iccid_map = TRUE;
sailfish_sim_info_update_iccid_map(self);
sailfish_sim_info_update_imsi_cache(self);
sailfish_sim_info_signal_emit(self, SIGNAL_IMSI_CHANGED);
sailfish_sim_info_signal_queue(self, SIGNAL_IMSI_CHANGED);
}
}
static void sailfish_sim_info_update_imsi(struct sailfish_sim_info *self)
{
struct sailfish_watch *watch = self->priv->watch;
if (watch->imsi && watch->imsi[0]) {
sailfish_sim_info_set_imsi(self, watch->imsi);
}
/* Check if MCC/MNC have changed */
sailfish_sim_info_update_default_spn(self);
}
static void sailfish_sim_info_network_check(struct sailfish_sim_info *self)
@@ -333,7 +359,8 @@ static void sailfish_sim_info_load_cache(struct sailfish_sim_info *self)
self->imsi = priv->imsi = imsi;
DBG_(self, "imsi[%s] = %s", priv->iccid, imsi);
sailfish_sim_info_update_iccid_map(self);
sailfish_sim_info_signal_emit(self,
sailfish_sim_info_update_default_spn(self);
sailfish_sim_info_signal_queue(self,
SIGNAL_IMSI_CHANGED);
} else if (imsi) {
g_free(imsi);
@@ -378,38 +405,32 @@ static void sailfish_sim_info_set_iccid(struct sailfish_sim_info *self,
if (g_strcmp0(priv->iccid, iccid)) {
g_free(priv->iccid);
self->iccid = priv->iccid = g_strdup(iccid);
sailfish_sim_info_signal_emit(self, SIGNAL_ICCID_CHANGED);
sailfish_sim_info_signal_queue(self, SIGNAL_ICCID_CHANGED);
if (iccid) {
sailfish_sim_info_load_cache(self);
} else {
DBG_(self, "no more iccid");
if (priv->imsi) {
g_free(priv->imsi);
self->imsi = priv->imsi = NULL;
sailfish_sim_info_signal_emit(self,
sailfish_sim_info_signal_queue(self,
SIGNAL_IMSI_CHANGED);
}
if (priv->sim_spn) {
g_free(priv->sim_spn);
priv->sim_spn = NULL;
sailfish_sim_info_set_cached_spn(self, NULL);
}
if (priv->cached_spn) {
g_free(priv->cached_spn);
priv->cached_spn = NULL;
}
/* No more default SPN too */
priv->default_spn[0] = 0;
sailfish_sim_info_update_public_spn(self);
}
}
}
static void sailfish_sim_info_sim_watch_cb(struct sailfish_watch *watch,
void *data)
{
struct sailfish_sim_info *self = SAILFISH_SIMINFO(data);
struct ofono_sim *sim = self->priv->watch->sim;
sailfish_sim_info_update_default_spn(self);
if (ofono_sim_get_state(sim) == OFONO_SIM_STATE_NOT_PRESENT) {
sailfish_sim_info_set_iccid(self, NULL);
}
sailfish_sim_info_network_check(self);
}
static void sailfish_sim_info_iccid_watch_cb(struct sailfish_watch *watch,
void *data)
{
@@ -417,24 +438,34 @@ static void sailfish_sim_info_iccid_watch_cb(struct sailfish_watch *watch,
DBG_(self, "%s", watch->iccid);
sailfish_sim_info_set_iccid(self, watch->iccid);
sailfish_sim_info_emit_queued_signals(self);
}
static void sailfish_sim_info_imsi_watch_cb(struct sailfish_watch *watch,
void *data)
{
sailfish_sim_info_update_imsi(SAILFISH_SIMINFO(data));
struct sailfish_sim_info *self = SAILFISH_SIMINFO(data);
sailfish_sim_info_update_imsi(self);
sailfish_sim_info_emit_queued_signals(self);
}
static void sailfish_sim_info_spn_watch_cb(struct sailfish_watch *watch,
void *data)
{
sailfish_sim_info_update_spn(SAILFISH_SIMINFO(data));
struct sailfish_sim_info *self = SAILFISH_SIMINFO(data);
sailfish_sim_info_update_spn(self);
sailfish_sim_info_emit_queued_signals(self);
}
static void sailfish_sim_info_netreg_watch(int status, int lac, int ci,
int tech, const char *mcc, const char *mnc, void *data)
{
sailfish_sim_info_network_check(SAILFISH_SIMINFO(data));
struct sailfish_sim_info *self = SAILFISH_SIMINFO(data);
sailfish_sim_info_network_check(self);
sailfish_sim_info_emit_queued_signals(self);
}
static void sailfish_sim_info_netreg_watch_done(void *data)
@@ -475,7 +506,10 @@ static void sailfish_sim_info_set_netreg(struct sailfish_sim_info *self,
static void sailfish_sim_info_netreg_changed(struct sailfish_watch *watch,
void *data)
{
sailfish_sim_info_set_netreg(SAILFISH_SIMINFO(data), watch->netreg);
struct sailfish_sim_info *self = SAILFISH_SIMINFO(data);
sailfish_sim_info_set_netreg(self, watch->netreg);
sailfish_sim_info_emit_queued_signals(self);
}
struct sailfish_sim_info *sailfish_sim_info_new(const char *path)
@@ -490,12 +524,6 @@ struct sailfish_sim_info *sailfish_sim_info_new(const char *path)
priv = self->priv;
priv->watch = watch;
self->path = watch->path;
priv->watch_event_id[WATCH_EVENT_SIM] =
sailfish_watch_add_sim_changed_handler(watch,
sailfish_sim_info_sim_watch_cb, self);
priv->watch_event_id[WATCH_EVENT_SIM_STATE] =
sailfish_watch_add_sim_state_changed_handler(watch,
sailfish_sim_info_sim_watch_cb, self);
priv->watch_event_id[WATCH_EVENT_ICCID] =
sailfish_watch_add_iccid_changed_handler(watch,
sailfish_sim_info_iccid_watch_cb, self);
@@ -513,6 +541,9 @@ struct sailfish_sim_info *sailfish_sim_info_new(const char *path)
sailfish_sim_info_update_imsi(self);
sailfish_sim_info_update_spn(self);
sailfish_sim_info_network_check(self);
/* Clear queued events, if any */
priv->queued_signals = 0;
}
return self;
}
@@ -534,13 +565,6 @@ void sailfish_sim_info_unref(struct sailfish_sim_info *self)
}
}
void sailfish_sim_info_invalidate(struct sailfish_sim_info *self)
{
if (self) {
sailfish_sim_info_set_iccid(self, NULL);
}
}
gulong sailfish_sim_info_add_iccid_changed_handler(struct sailfish_sim_info *s,
sailfish_sim_info_cb_t cb, void *arg)
{

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony
*
* Copyright (C) 2017 Jolla Ltd.
* Copyright (C) 2017-2018 Jolla Ltd.
*
* 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
@@ -48,7 +48,6 @@ typedef void (*sailfish_sim_info_cb_t)(struct sailfish_sim_info *si,
struct sailfish_sim_info *sailfish_sim_info_new(const char *path);
struct sailfish_sim_info *sailfish_sim_info_ref(struct sailfish_sim_info *si);
void sailfish_sim_info_unref(struct sailfish_sim_info *si);
void sailfish_sim_info_invalidate(struct sailfish_sim_info *si);
gulong sailfish_sim_info_add_iccid_changed_handler(struct sailfish_sim_info *si,
sailfish_sim_info_cb_t cb, void *user_data);
gulong sailfish_sim_info_add_imsi_changed_handler(struct sailfish_sim_info *si,

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony
*
* Copyright (C) 2017 Jolla Ltd.
* Copyright (C) 2017-2018 Jolla Ltd.
*
* 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
@@ -126,24 +126,6 @@ static inline void sailfish_watch_resume_signals(struct sailfish_watch *self)
sailfish_watch_emit_queued_signals(self);
}
static void sailfish_watch_sim_state_notify(enum ofono_sim_state new_state,
void *user_data)
{
struct sailfish_watch *self = SAILFISH_WATCH(user_data);
sailfish_watch_signal_queue(self, SIGNAL_SIM_STATE_CHANGED);
sailfish_watch_emit_queued_signals(self);
}
static void sailfish_watch_sim_state_destroy(void *user_data)
{
struct sailfish_watch *self = SAILFISH_WATCH(user_data);
struct sailfish_watch_priv *priv = self->priv;
GASSERT(priv->sim_state_watch_id);
priv->sim_state_watch_id = 0;
}
static void sailfish_watch_iccid_update(struct sailfish_watch *self,
const char *iccid)
{
@@ -238,6 +220,35 @@ static void sailfish_watch_imsi_destroy(void *user_data)
priv->imsi_watch_id = 0;
}
static void sailfish_watch_sim_state_notify(enum ofono_sim_state new_state,
void *user_data)
{
struct sailfish_watch *self = SAILFISH_WATCH(user_data);
/*
* ofono core doesn't notify SIM watches when SIM card gets removed.
* So we have to reset things here based on the SIM state.
*/
if (new_state == OFONO_SIM_STATE_NOT_PRESENT) {
sailfish_watch_iccid_update(self, NULL);
}
if (new_state != OFONO_SIM_STATE_READY) {
sailfish_watch_imsi_update(self, NULL);
sailfish_watch_spn_update(self, NULL);
}
sailfish_watch_signal_queue(self, SIGNAL_SIM_STATE_CHANGED);
sailfish_watch_emit_queued_signals(self);
}
static void sailfish_watch_sim_state_destroy(void *user_data)
{
struct sailfish_watch *self = SAILFISH_WATCH(user_data);
struct sailfish_watch_priv *priv = self->priv;
GASSERT(priv->sim_state_watch_id);
priv->sim_state_watch_id = 0;
}
static void sailfish_watch_set_sim(struct sailfish_watch *self,
struct ofono_sim *sim)
{
@@ -271,6 +282,11 @@ static void sailfish_watch_set_sim(struct sailfish_watch *self,
self->sim = sim;
sailfish_watch_signal_queue(self, SIGNAL_SIM_CHANGED);
sailfish_watch_suspend_signals(self);
/* Reset the current state */
sailfish_watch_iccid_update(self, NULL);
sailfish_watch_imsi_update(self, NULL);
sailfish_watch_spn_update(self, NULL);
if (sim) {
priv->sim_state_watch_id =
ofono_sim_add_state_watch(sim,
@@ -293,12 +309,6 @@ static void sailfish_watch_set_sim(struct sailfish_watch *self,
ofono_sim_add_imsi_watch(self->sim,
sailfish_watch_imsi_notify, self,
sailfish_watch_imsi_destroy);
} else {
/* And these will just queue the signals
* if necessary */
sailfish_watch_iccid_update(self, NULL);
sailfish_watch_imsi_update(self, NULL);
sailfish_watch_spn_update(self, NULL);
}
/* Emit the pending signals. */

View File

@@ -3770,3 +3770,21 @@ gboolean __ofono_gprs_get_roaming_allowed(struct ofono_gprs *gprs)
{
return gprs->roaming_allowed;
}
const struct ofono_gprs_primary_context *__ofono_gprs_context_settings_by_type
(struct ofono_gprs *gprs, enum ofono_gprs_context_type type)
{
GSList *l;
if (!gprs)
return NULL;
for (l = gprs->contexts; l; l = l->next) {
struct pri_context *ctx = l->data;
if (type == OFONO_GPRS_CONTEXT_TYPE_ANY || type == ctx->type)
return &ctx->context;
}
return NULL;
}

View File

@@ -277,6 +277,10 @@ gboolean __ofono_call_settings_is_busy(struct ofono_call_settings *cs);
gboolean __ofono_gprs_get_roaming_allowed(struct ofono_gprs *gprs);
#include <ofono/gprs-context.h>
const struct ofono_gprs_primary_context *__ofono_gprs_context_settings_by_type
(struct ofono_gprs *gprs, enum ofono_gprs_context_type type);
#include <ofono/radio-settings.h>
#include <ofono/audio-settings.h>
#include <ofono/ctm.h>

View File

@@ -2207,6 +2207,9 @@ static void sim_efli_efpl_changed(int id, void *userdata)
if (sim->efli != NULL) /* This shouldn't happen */
return;
if (sim->language_prefs_update)
return;
if (sim->language_prefs) {
g_strfreev(sim->language_prefs);
sim->language_prefs = NULL;

View File

@@ -20,8 +20,10 @@ TESTS="\
test-ril_util \
test-sms-filter \
test-sailfish_cell_info \
test-sailfish_cell_info_dbus \
test-sailfish_manager \
test-sailfish_sim_info"
test-sailfish_sim_info \
test-sailfish_sim_info_dbus"
pushd `dirname $0` > /dev/null
TEST_DIR="$PWD"

View File

@@ -0,0 +1,181 @@
/*
* oFono - Open Source Telephony
*
* Copyright (C) 2017 Jolla Ltd.
*
* 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.
*/
#include "fake_sailfish_cell_info.h"
#include <gutil_macros.h>
#include <glib-object.h>
typedef GObjectClass FakeCellInfoClass;
typedef struct fake_cell_info {
GObject object;
struct sailfish_cell_info info;
} FakeCellInfo;
typedef struct fake_cell_info_signal_data {
sailfish_cell_info_cb_t cb;
void *arg;
} FakeCellInfoSignalData;
enum fake_cell_info_signal {
SIGNAL_CELLS_CHANGED,
SIGNAL_COUNT
};
static guint fake_cell_info_signals[SIGNAL_COUNT] = { 0 };
G_DEFINE_TYPE(FakeCellInfo, fake_cell_info, G_TYPE_OBJECT)
#define FAKE_CELL_INFO_TYPE (fake_cell_info_get_type())
#define FAKE_CELL_INFO(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),\
FAKE_CELL_INFO_TYPE, FakeCellInfo))
#define SIGNAL_CELLS_CHANGED_NAME "fake-cell-info-cells-changed"
static FakeCellInfo *fake_cell_info_cast(struct sailfish_cell_info *info)
{
return G_CAST(info, FakeCellInfo, info);
}
static void fake_cell_info_ref_proc(struct sailfish_cell_info *info)
{
g_object_ref(fake_cell_info_cast(info));
}
static void fake_cell_info_unref_proc(struct sailfish_cell_info *info)
{
g_object_unref(fake_cell_info_cast(info));
}
static void fake_cell_info_cells_changed_cb(FakeCellInfo *self, void *data)
{
FakeCellInfoSignalData *signal_data = data;
signal_data->cb(&self->info, signal_data->arg);
}
static void fake_cell_info_cells_disconnect_notify(gpointer data,
GClosure *closure)
{
g_free(data);
}
static gulong fake_cell_info_add_cells_changed_handler_proc
(struct sailfish_cell_info *info,
sailfish_cell_info_cb_t cb, void *arg)
{
if (cb) {
FakeCellInfoSignalData *data =
g_new0(FakeCellInfoSignalData, 1);
data->cb = cb;
data->arg = arg;
return g_signal_connect_data(fake_cell_info_cast(info),
SIGNAL_CELLS_CHANGED_NAME,
G_CALLBACK(fake_cell_info_cells_changed_cb),
data, fake_cell_info_cells_disconnect_notify,
G_CONNECT_AFTER);
} else {
return 0;
}
}
static void fake_cell_info_remove_handler_proc(struct sailfish_cell_info *info,
gulong id)
{
if (id) {
g_signal_handler_disconnect(fake_cell_info_cast(info), id);
}
}
static void fake_cell_info_init(FakeCellInfo *self)
{
}
static void fake_cell_info_finalize(GObject *object)
{
FakeCellInfo *self = FAKE_CELL_INFO(object);
fake_cell_info_remove_all_cells(&self->info);
G_OBJECT_CLASS(fake_cell_info_parent_class)->finalize(object);
}
static void fake_cell_info_class_init(FakeCellInfoClass *klass)
{
G_OBJECT_CLASS(klass)->finalize = fake_cell_info_finalize;
fake_cell_info_signals[SIGNAL_CELLS_CHANGED] =
g_signal_new(SIGNAL_CELLS_CHANGED_NAME,
G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_FIRST,
0, NULL, NULL, NULL, G_TYPE_NONE, 0);
}
struct sailfish_cell_info *fake_cell_info_new()
{
static const struct sailfish_cell_info_proc fake_cell_info_proc = {
fake_cell_info_ref_proc,
fake_cell_info_unref_proc,
fake_cell_info_add_cells_changed_handler_proc,
fake_cell_info_remove_handler_proc
};
FakeCellInfo *self = g_object_new(FAKE_CELL_INFO_TYPE, 0);
self->info.proc = &fake_cell_info_proc;
return &self->info;
}
void fake_cell_info_add_cell(struct sailfish_cell_info *info,
const struct sailfish_cell* cell)
{
info->cells = g_slist_append(info->cells,
g_memdup(cell, sizeof(*cell)));
}
gboolean fake_cell_info_remove_cell(struct sailfish_cell_info *info,
const struct sailfish_cell* cell)
{
GSList *l;
for (l = info->cells; l; l = l->next) {
struct sailfish_cell *known_cell = l->data;
if (!memcmp(cell, known_cell, sizeof(*cell))) {
info->cells = g_slist_remove(info->cells, known_cell);
g_free(known_cell);
return TRUE;
}
}
return FALSE;
}
void fake_cell_info_remove_all_cells(struct sailfish_cell_info *info)
{
g_slist_free_full(info->cells, g_free);
info->cells = NULL;
}
void fake_cell_info_cells_changed(struct sailfish_cell_info *info)
{
g_signal_emit(fake_cell_info_cast(info), fake_cell_info_signals
[SIGNAL_CELLS_CHANGED], 0);
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

@@ -0,0 +1,37 @@
/*
* oFono - Open Source Telephony
*
* Copyright (C) 2018 Jolla Ltd.
*
* 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.
*/
#ifndef SAILFISH_FAKE_CELL_INFO_H
#define SAILFISH_FAKE_CELL_INFO_H
#include "sailfish_cell_info.h"
struct sailfish_cell_info *fake_cell_info_new(void);
void fake_cell_info_add_cell(struct sailfish_cell_info *info,
const struct sailfish_cell* cell);
gboolean fake_cell_info_remove_cell(struct sailfish_cell_info *info,
const struct sailfish_cell* cell);
void fake_cell_info_remove_all_cells(struct sailfish_cell_info *info);
void fake_cell_info_cells_changed(struct sailfish_cell_info *info);
#endif /* FAKE_SAILFISH_CELL_INFO_H */
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

357
ofono/unit/test-dbus.c Normal file
View File

@@ -0,0 +1,357 @@
/*
* oFono - Open Source Telephony
*
* Copyright (C) 2018 Jolla Ltd.
*
* 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.
*/
#include "test-dbus.h"
#include "ofono.h"
#include <dbus/dbus-glib-lowlevel.h>
struct test_polkit_auth_check {
void (*function)(dbus_bool_t authorized, void *user_data);
void *user_data;
};
struct test_dbus_watch {
struct test_dbus_watch *next;
guint id;
DBusConnection *connection;
GDBusWatchFunction disconnect;
GDBusDestroyFunction destroy;
void *user_data;
};
struct test_dbus_watch *test_dbus_watch_list;
static unsigned int test_last_id;
static gboolean polkit_check_authorization_cb(gpointer data)
{
struct test_polkit_auth_check *check = data;
check->function(TRUE, check->user_data);
g_free(check);
return G_SOURCE_REMOVE;
}
int polkit_check_authorization(DBusConnection *conn,
const char *action, gboolean interaction,
void (*function)(dbus_bool_t authorized, void *user_data),
void *user_data, int timeout)
{
struct test_polkit_auth_check *check =
g_new(struct test_polkit_auth_check, 1);
check->function = function;
check->user_data = user_data;
g_idle_add(polkit_check_authorization_cb, check);
return 0;
}
static guint test_dbus_add_watch(DBusConnection *connection,
GDBusWatchFunction disconnect, GDBusDestroyFunction destroy,
void *user_data)
{
struct test_dbus_watch *watch = g_new0(struct test_dbus_watch, 1);
test_last_id++;
watch->id = test_last_id;
watch->connection = dbus_connection_ref(connection);
watch->disconnect = disconnect;
watch->destroy = destroy;
watch->user_data = user_data;
watch->next = test_dbus_watch_list;
test_dbus_watch_list = watch;
return test_last_id;
}
static gboolean test_dbus_watch_disconnect_one(void)
{
struct test_dbus_watch *watch = test_dbus_watch_list;
while (watch) {
if (watch->disconnect) {
GDBusWatchFunction disconnect = watch->disconnect;
watch->disconnect = NULL;
disconnect(watch->connection, watch->user_data);
return TRUE;
}
watch = watch->next;
}
return FALSE;
}
void test_dbus_watch_disconnect_all(void)
{
while (test_dbus_watch_disconnect_one());
}
static void test_dbus_watch_free(struct test_dbus_watch *watch)
{
if (watch->destroy) {
watch->destroy(watch->user_data);
}
dbus_connection_unref(watch->connection);
g_free(watch);
}
static gboolean test_dbus_watch_remove_one(void)
{
struct test_dbus_watch *watch = test_dbus_watch_list;
if (watch) {
test_dbus_watch_list = watch->next;
test_dbus_watch_free(watch);
return TRUE;
}
return FALSE;
}
void test_dbus_watch_remove_all(void)
{
while (test_dbus_watch_remove_one());
}
guint g_dbus_add_signal_watch(DBusConnection *connection, const char *sender,
const char *path, const char *interface, const char *member,
GDBusSignalFunction function, void *user_data,
GDBusDestroyFunction destroy)
{
return test_dbus_add_watch(connection, NULL, destroy, user_data);
}
gboolean g_dbus_remove_watch(DBusConnection *connection, guint id)
{
struct test_dbus_watch *prev = NULL;
struct test_dbus_watch *watch = test_dbus_watch_list;
while (watch) {
if (watch->id == id) {
if (prev) {
prev->next = watch->next;
} else {
test_dbus_watch_list = watch->next;
}
test_dbus_watch_free(watch);
return TRUE;
}
prev = watch;
watch = watch->next;
}
ofono_warn("Unexpected id %u", id);
return FALSE;
}
static gboolean test_dbus_loop_quit(gpointer data)
{
g_main_loop_quit(data);
return G_SOURCE_REMOVE;
}
static void test_dbus_loop_quit_later(GMainLoop *loop)
{
g_idle_add(test_dbus_loop_quit, loop);
}
DBusMessage *test_dbus_find_signal(struct test_dbus_context *test,
const char *path, const char *iface, const char *member)
{
GSList *l;
for (l = test->client_signals; l; l = l->next) {
DBusMessage *msg = l->data;
if (!g_strcmp0(dbus_message_get_interface(msg), iface) &&
!g_strcmp0(dbus_message_get_member(msg), member) &&
!g_strcmp0(dbus_message_get_path(msg), path)) {
return msg;
}
}
return NULL;
}
DBusMessage *test_dbus_take_signal(struct test_dbus_context *test,
const char *path, const char *iface, const char *member)
{
DBusMessage *m = test_dbus_find_signal(test, path, iface, member);
if (m) {
test->client_signals = g_slist_remove(test->client_signals, m);
return m;
}
return NULL;
}
int test_dbus_get_int32(DBusMessageIter *it)
{
dbus_uint32_t value;
g_assert(dbus_message_iter_get_arg_type(it) == DBUS_TYPE_INT32);
dbus_message_iter_get_basic(it, &value);
dbus_message_iter_next(it);
return value;
}
gboolean test_dbus_get_bool(DBusMessageIter *it)
{
dbus_bool_t value;
g_assert(dbus_message_iter_get_arg_type(it) == DBUS_TYPE_BOOLEAN);
dbus_message_iter_get_basic(it, &value);
dbus_message_iter_next(it);
return value;
}
const char *test_dbus_get_string(DBusMessageIter *it)
{
const char *value;
g_assert(dbus_message_iter_get_arg_type(it) == DBUS_TYPE_STRING);
dbus_message_iter_get_basic(it, &value);
dbus_message_iter_next(it);
return value;
}
const char *test_dbus_get_object_path(DBusMessageIter *it)
{
const char *value;
g_assert(dbus_message_iter_get_arg_type(it) == DBUS_TYPE_OBJECT_PATH);
dbus_message_iter_get_basic(it, &value);
dbus_message_iter_next(it);
return value;
}
void test_dbus_expect_empty_reply(DBusPendingCall *call, void *data)
{
struct test_dbus_context *test = data;
DBusMessage *reply = dbus_pending_call_steal_reply(call);
DBusMessageIter it;
DBG("");
g_assert(dbus_message_get_type(reply) ==
DBUS_MESSAGE_TYPE_METHOD_RETURN);
dbus_message_iter_init(reply, &it);
g_assert(dbus_message_iter_get_arg_type(&it) == DBUS_TYPE_INVALID);
dbus_message_unref(reply);
dbus_pending_call_unref(call);
test_dbus_loop_quit_later(test->loop);
}
void test_dbus_check_string_reply(DBusPendingCall *call, const char *str)
{
DBusMessage *reply = dbus_pending_call_steal_reply(call);
DBusMessageIter it;
DBG("");
g_assert(dbus_message_get_type(reply) ==
DBUS_MESSAGE_TYPE_METHOD_RETURN);
dbus_message_iter_init(reply, &it);
g_assert(!g_strcmp0(test_dbus_get_string(&it), str));
g_assert(dbus_message_iter_get_arg_type(&it) == DBUS_TYPE_INVALID);
dbus_message_unref(reply);
}
void test_dbus_message_unref(gpointer data)
{
dbus_message_unref(data);
}
static DBusHandlerResult test_dbus_client_message_cb(DBusConnection *conn,
DBusMessage *msg, void *data)
{
struct test_dbus_context *test = data;
if (dbus_message_get_type(msg) == DBUS_MESSAGE_TYPE_SIGNAL) {
DBG("signal %s.%s \"%s\"", dbus_message_get_interface(msg),
dbus_message_get_member(msg),
dbus_message_get_path(msg));
test->client_signals = g_slist_append(test->client_signals,
dbus_message_ref(msg));
return DBUS_HANDLER_RESULT_HANDLED;
} else {
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
}
static void test_dbus_connection_cb(DBusServer *server, DBusConnection *conn,
void *data)
{
struct test_dbus_context *test = data;
DBG("");
g_assert(!test->server_connection);
test->server_connection = dbus_connection_ref(conn);
dbus_connection_setup_with_g_main(test->server_connection,
g_main_loop_get_context(test->loop));
/* Start the test */
__ofono_dbus_init(test->server_connection);
test->start(test);
}
void test_dbus_setup(struct test_dbus_context *test)
{
char *address;
GMainContext *context;
test->loop = g_main_loop_new(NULL, TRUE);
context = g_main_loop_get_context(test->loop);
test->server = dbus_server_listen("unix:runtime=yes;unix:tmpdir=/tmp",
NULL);
g_assert(test->server);
address = dbus_server_get_address(test->server);
DBG("listening on %s", address);
dbus_server_setup_with_g_main(test->server, context);
dbus_server_set_new_connection_function(test->server,
test_dbus_connection_cb, test, NULL);
test->client_connection = dbus_connection_open_private(address, NULL);
g_assert(test->client_connection);
dbus_connection_setup_with_g_main(test->client_connection, context);
g_assert(dbus_connection_add_filter(test->client_connection,
test_dbus_client_message_cb, test, NULL));
DBG("connected on %s", address);
dbus_free(address);
}
void test_dbus_shutdown(struct test_dbus_context *test)
{
test_dbus_watch_disconnect_all();
test_dbus_watch_remove_all();
__ofono_dbus_cleanup();
if (test->server_connection) {
dbus_connection_close(test->server_connection);
dbus_connection_unref(test->server_connection);
}
dbus_connection_close(test->client_connection);
dbus_connection_unref(test->client_connection);
dbus_server_disconnect(test->server);
dbus_server_unref(test->server);
g_main_loop_unref(test->loop);
g_slist_free_full(test->client_signals, test_dbus_message_unref);
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

58
ofono/unit/test-dbus.h Normal file
View File

@@ -0,0 +1,58 @@
/*
* oFono - Open Source Telephony
*
* Copyright (C) 2018 Jolla Ltd.
*
* 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.
*/
#ifndef TEST_DBUS_H
#define TEST_DBUS_H
#include <ofono/gdbus.h>
struct test_dbus_context {
GMainLoop *loop;
DBusServer *server;
DBusConnection *server_connection;
DBusConnection *client_connection;
GSList* client_signals;
void (*start)(struct test_dbus_context *test);
guint timeout_id;
};
void test_dbus_setup(struct test_dbus_context *context);
void test_dbus_shutdown(struct test_dbus_context *context);
void test_dbus_watch_disconnect_all(void);
void test_dbus_watch_remove_all(void);
int test_dbus_get_int32(DBusMessageIter *it);
gboolean test_dbus_get_bool(DBusMessageIter *it);
const char *test_dbus_get_string(DBusMessageIter *it);
const char *test_dbus_get_object_path(DBusMessageIter *it);
void test_dbus_check_string_reply(DBusPendingCall *call, const char *str);
void test_dbus_expect_empty_reply(DBusPendingCall *call, void *data);
DBusMessage *test_dbus_find_signal(struct test_dbus_context *test,
const char *path, const char *iface, const char *member);
DBusMessage *test_dbus_take_signal(struct test_dbus_context *test,
const char *path, const char *iface, const char *member);
#endif /* TEST_DBUS_H */
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

@@ -35,9 +35,12 @@ static void test_alloc(void)
idmap = idmap_new(2);
g_assert(idmap);
g_assert(idmap_get_min(idmap) == 1);
bit = idmap_alloc(idmap);
g_assert(bit == 1);
g_assert(idmap_find(idmap, bit));
g_assert(!idmap_find(idmap, idmap_get_max(idmap) + 1));
bit = idmap_alloc(idmap);
g_assert(bit == 2);
@@ -62,6 +65,12 @@ static void test_alloc(void)
bit = idmap_alloc(idmap);
g_assert(bit == 1);
idmap_put(idmap, 1);
idmap_take(idmap, 1);
idmap_take(idmap, 3);
bit = idmap_alloc(idmap);
g_assert(bit == 2);
idmap_free(idmap);
}
@@ -80,9 +89,24 @@ static void test_alloc_next(void)
bit = idmap_alloc_next(idmap, 255);
g_assert(bit == 1);
while (idmap_alloc(idmap) < (sizeof(unsigned long) * 8) + 1);
bit = idmap_alloc_next(idmap, 1);
g_assert(bit == (sizeof(unsigned long) * 8) + 2);
idmap_free(idmap);
idmap = idmap_new(2);
g_assert(idmap);
g_assert(idmap_alloc_next(idmap, 0) == 3);
g_assert(idmap_alloc_next(idmap, 3) == 3);
bit = idmap_alloc_next(idmap, 1);
g_assert(bit == 2);
bit = idmap_alloc_next(idmap, 2);
g_assert(bit == 1);
idmap_free(idmap);
}

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony
*
* Copyright (C) 2017 Jolla Ltd.
* Copyright (C) 2017-2018 Jolla Ltd.
*
* 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
@@ -102,6 +102,20 @@ void test_parse_int(void)
g_assert(!ril_parse_int("0xffffffff", 0, &value));
}
void test_strings(void)
{
g_assert(!g_strcmp0(ril_error_to_string(RIL_E_SUCCESS), "OK"));
g_assert(!g_strcmp0(ril_error_to_string(2147483647), "2147483647"));
g_assert(!g_strcmp0(ril_request_to_string(RIL_RESPONSE_ACKNOWLEDGEMENT),
"RESPONSE_ACK"));
g_assert(!g_strcmp0(ril_request_to_string(2147483647),
"RIL_REQUEST_2147483647"));
g_assert(!g_strcmp0(ril_unsol_event_to_string(2147483647),
"RIL_UNSOL_2147483647"));
g_assert(!g_strcmp0(ril_radio_state_to_string(2147483647),
"2147483647 (?)"));
}
#define TEST_(name) "/ril_util/" name
int main(int argc, char *argv[])
@@ -115,6 +129,7 @@ int main(int argc, char *argv[])
g_test_add_func(TEST_("parse_tech"), test_parse_tech);
g_test_add_func(TEST_("parse_mcc_mnc"), test_parse_mcc_mnc);
g_test_add_func(TEST_("parse_int"), test_parse_int);
g_test_add_func(TEST_("strings"), test_strings);
return g_test_run();
}

View File

@@ -0,0 +1,979 @@
/*
* oFono - Open Source Telephony
*
* Copyright (C) 2018 Jolla Ltd.
*
* 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.
*/
#include "test-dbus.h"
#include "sailfish_cell_info.h"
#include "sailfish_cell_info_dbus.h"
#include "fake_sailfish_cell_info.h"
#include <gutil_log.h>
#include <gutil_macros.h>
#include "ofono.h"
#define TEST_TIMEOUT (10) /* seconds */
#define TEST_MODEM_PATH "/test"
#define TEST_SENDER ":1.0"
#define CELL_INFO_DBUS_INTERFACE "org.nemomobile.ofono.CellInfo"
#define CELL_INFO_DBUS_CELLS_ADDED_SIGNAL "CellsAdded"
#define CELL_INFO_DBUS_CELLS_REMOVED_SIGNAL "CellsRemoved"
#define CELL_DBUS_INTERFACE_VERSION (1)
#define CELL_DBUS_INTERFACE "org.nemomobile.ofono.Cell"
#define CELL_DBUS_REGISTERED_CHANGED_SIGNAL "RegisteredChanged"
#define CELL_DBUS_PROPERTY_CHANGED_SIGNAL "PropertyChanged"
#define CELL_DBUS_REMOVED_SIGNAL "Removed"
static gboolean test_debug;
/* Stubs (ofono) */
struct ofono_modem {
const char *path;
};
const char *ofono_modem_get_path(struct ofono_modem *modem)
{
return modem->path;
}
void ofono_modem_add_interface(struct ofono_modem *modem, const char *iface)
{
DBG("%s %s", modem->path, iface);
}
/* ==== common ==== */
static gboolean test_timeout(gpointer param)
{
g_assert(!"TIMEOUT");
return G_SOURCE_REMOVE;
}
static guint test_setup_timeout(void)
{
if (!test_debug) {
return 0;
} else {
return g_timeout_add_seconds(TEST_TIMEOUT, test_timeout, NULL);
}
}
static gboolean test_loop_quit(gpointer data)
{
g_main_loop_quit(data);
return G_SOURCE_REMOVE;
}
static void test_loop_quit_later(GMainLoop *loop)
{
g_idle_add(test_loop_quit, loop);
}
static DBusMessage *test_new_cell_info_call(const char *method)
{
DBusMessage *msg = dbus_message_new_method_call(NULL, TEST_MODEM_PATH,
CELL_INFO_DBUS_INTERFACE, method);
g_assert(dbus_message_set_sender(msg, TEST_SENDER));
return msg;
}
static DBusMessage *test_new_cell_call(const char *path, const char *method)
{
DBusMessage *msg = dbus_message_new_method_call(NULL, path,
CELL_DBUS_INTERFACE, method);
g_assert(dbus_message_set_sender(msg, TEST_SENDER));
return msg;
}
static void test_submit_get_all_call(DBusConnection* connection,
const char *cell_path, DBusPendingCallNotifyFunction notify,
void *data)
{
DBusMessage *msg;
DBusPendingCall* call;
msg = test_new_cell_call(cell_path, "GetAll");
g_assert(dbus_connection_send_with_reply(connection, msg, &call,
DBUS_TIMEOUT_INFINITE));
dbus_pending_call_set_notify(call, notify, data, NULL);
dbus_message_unref(msg);
}
static void test_check_object_path_array_va(DBusMessageIter *it,
const char *path1, va_list va)
{
DBusMessageIter array;
g_assert(dbus_message_iter_get_arg_type(it) == DBUS_TYPE_ARRAY);
dbus_message_iter_recurse(it, &array);
dbus_message_iter_next(it);
if (path1) {
const char *path;
g_assert(!g_strcmp0(test_dbus_get_object_path(&array), path1));
while ((path = va_arg(va, char*)) != NULL) {
g_assert(!g_strcmp0(test_dbus_get_object_path(&array),
path));
}
}
g_assert(dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_INVALID);
g_assert(dbus_message_iter_get_arg_type(it) == DBUS_TYPE_INVALID);
}
static void test_check_object_path_array(DBusMessageIter *it,
const char *path1, ...)
{
va_list va;
va_start(va, path1);
test_check_object_path_array_va(it, path1, va);
va_end(va);
}
static void test_check_get_cells_reply(DBusPendingCall *call,
const char *path1, ...)
{
DBusMessage *reply = dbus_pending_call_steal_reply(call);
DBusMessageIter it;
va_list va;
g_assert(dbus_message_get_type(reply) ==
DBUS_MESSAGE_TYPE_METHOD_RETURN);
dbus_message_iter_init(reply, &it);
va_start(va, path1);
test_check_object_path_array_va(&it, path1, va);
va_end(va);
dbus_message_unref(reply);
}
static void test_check_get_all_reply(DBusPendingCall *call,
const struct sailfish_cell *cell, const char *type)
{
DBusMessage *reply = dbus_pending_call_steal_reply(call);
DBusMessageIter it, array;
g_assert(dbus_message_get_type(reply) ==
DBUS_MESSAGE_TYPE_METHOD_RETURN);
dbus_message_iter_init(reply, &it);
g_assert(test_dbus_get_int32(&it) == CELL_DBUS_INTERFACE_VERSION);
g_assert(!g_strcmp0(test_dbus_get_string(&it), type));
g_assert(test_dbus_get_bool(&it) == (cell->registered != FALSE));
g_assert(dbus_message_iter_get_arg_type(&it) == DBUS_TYPE_ARRAY);
dbus_message_iter_recurse(&it, &array);
dbus_message_iter_next(&it);
/* Validate the properties? */
g_assert(dbus_message_iter_get_arg_type(&it) == DBUS_TYPE_INVALID);
dbus_message_unref(reply);
}
static struct sailfish_cell *test_cell_init_gsm1(struct sailfish_cell *cell)
{
struct sailfish_cell_info_gsm *gsm = &cell->info.gsm;
memset(cell, 0, sizeof(*cell));
cell->type = SAILFISH_CELL_TYPE_GSM;
cell->registered = TRUE;
gsm->mcc = 244;
gsm->mnc = 5;
gsm->lac = 9007;
gsm->cid = 42335;
gsm->arfcn = INT_MAX;
gsm->bsic = INT_MAX;
gsm->signalStrength = 26;
gsm->bitErrorRate = 99;
gsm->timingAdvance = INT_MAX;
return cell;
}
static struct sailfish_cell *test_cell_init_gsm2(struct sailfish_cell *cell)
{
struct sailfish_cell_info_gsm *gsm = &cell->info.gsm;
memset(cell, 0, sizeof(*cell));
cell->type = SAILFISH_CELL_TYPE_GSM;
cell->registered = FALSE;
gsm->mcc = 244;
gsm->mnc = 5;
gsm->lac = 9007;
gsm->cid = 35600;
gsm->arfcn = INT_MAX;
gsm->bsic = INT_MAX;
gsm->signalStrength = 8;
gsm->bitErrorRate = 99;
gsm->timingAdvance = INT_MAX;
return cell;
}
static struct sailfish_cell *test_cell_init_wcdma1(struct sailfish_cell *cell)
{
struct sailfish_cell_info_wcdma *wcdma = &cell->info.wcdma;
memset(cell, 0, sizeof(*cell));
cell->type = SAILFISH_CELL_TYPE_WCDMA;
cell->registered = TRUE;
wcdma->mcc = 250;
wcdma->mnc = 99;
wcdma->lac = 14760;
wcdma->cid = 149331616;
wcdma->psc = 371;
wcdma->uarfcn = INT_MAX;
wcdma->signalStrength = 4;
wcdma->bitErrorRate = 99;
return cell;
}
static struct sailfish_cell *test_cell_init_wcdma2(struct sailfish_cell *cell)
{
struct sailfish_cell_info_wcdma *wcdma = &cell->info.wcdma;
memset(cell, 0, sizeof(*cell));
cell->type = SAILFISH_CELL_TYPE_WCDMA;
cell->registered = FALSE;
wcdma->mcc = INT_MAX;
wcdma->mnc = INT_MAX;
wcdma->lac = INT_MAX;
wcdma->cid = INT_MAX;
wcdma->psc = INT_MAX;
wcdma->uarfcn = INT_MAX;
wcdma->signalStrength = 5;
wcdma->bitErrorRate = 99;
return cell;
}
static struct sailfish_cell *test_cell_init_lte(struct sailfish_cell *cell)
{
struct sailfish_cell_info_lte *lte = &cell->info.lte;
memset(cell, 0, sizeof(*cell));
cell->type = SAILFISH_CELL_TYPE_LTE;
cell->registered = TRUE;
lte->mcc = 244;
lte->mnc = 91;
lte->ci = 36591883;
lte->pci = 309;
lte->tac = 4030;
lte->earfcn = INT_MAX;
lte->signalStrength = 17;
lte->rsrp = 106;
lte->rsrq = 6;
lte->rssnr = INT_MAX;
lte->cqi = INT_MAX;
lte->timingAdvance = INT_MAX;
return cell;
}
/* ==== Misc ==== */
static void test_misc(void)
{
struct ofono_modem modem;
modem.path = TEST_MODEM_PATH;
/* NULL resistance */
g_assert(!sailfish_cell_info_dbus_new(NULL, NULL));
g_assert(!sailfish_cell_info_dbus_new(&modem, NULL));
sailfish_cell_info_dbus_free(NULL);
/* Calling __ofono_dbus_cleanup() without __ofono_dbus_init() is ok */
__ofono_dbus_cleanup();
}
/* ==== GetCells ==== */
struct test_get_cells_data {
struct ofono_modem modem;
struct test_dbus_context context;
struct sailfish_cell_info *info;
struct sailfish_cell_info_dbus *dbus;
};
static void test_get_cells_call(struct test_get_cells_data *test,
DBusPendingCallNotifyFunction notify)
{
DBusPendingCall *call;
DBusConnection *connection = test->context.client_connection;
DBusMessage *msg = test_new_cell_info_call("GetCells");
g_assert(dbus_connection_send_with_reply(connection, msg, &call,
DBUS_TIMEOUT_INFINITE));
dbus_pending_call_set_notify(call, notify, test, NULL);
dbus_message_unref(msg);
}
static void test_get_cells_start_reply3(DBusPendingCall *call, void *data)
{
struct test_get_cells_data *test = data;
DBusMessageIter it;
DBusMessage *signal = test_dbus_take_signal(&test->context,
test->modem.path, CELL_INFO_DBUS_INTERFACE,
CELL_INFO_DBUS_CELLS_REMOVED_SIGNAL);
DBG("");
test_check_get_cells_reply(call, "/test/cell_1", NULL);
dbus_pending_call_unref(call);
/* Validate the signal */
g_assert(signal);
dbus_message_iter_init(signal, &it);
test_check_object_path_array(&it, "/test/cell_0", NULL);
dbus_message_unref(signal);
test_loop_quit_later(test->context.loop);
}
static void test_get_cells_start_reply2(DBusPendingCall *call, void *data)
{
struct test_get_cells_data *test = data;
const char *cell_added = "/test/cell_1";
struct sailfish_cell cell;
DBusMessageIter it;
DBusMessage *signal = test_dbus_take_signal(&test->context,
test->modem.path, CELL_INFO_DBUS_INTERFACE,
CELL_INFO_DBUS_CELLS_ADDED_SIGNAL);
DBG("");
test_check_get_cells_reply(call, "/test/cell_0", cell_added, NULL);
dbus_pending_call_unref(call);
/* Validate the signal */
g_assert(signal);
dbus_message_iter_init(signal, &it);
test_check_object_path_array(&it, cell_added, NULL);
dbus_message_unref(signal);
/* Remove "/test/cell_0" */
g_assert(fake_cell_info_remove_cell(test->info,
test_cell_init_gsm1(&cell)));
fake_cell_info_cells_changed(test->info);
test_get_cells_call(test, test_get_cells_start_reply3);
}
static void test_get_cells_start_reply1(DBusPendingCall *call, void *data)
{
struct test_get_cells_data *test = data;
struct sailfish_cell cell;
DBG("");
test_check_get_cells_reply(call, "/test/cell_0", NULL);
dbus_pending_call_unref(call);
/* Add "/test/cell_1" */
fake_cell_info_add_cell(test->info, test_cell_init_gsm2(&cell));
fake_cell_info_cells_changed(test->info);
test_get_cells_call(test, test_get_cells_start_reply2);
}
static void test_get_cells_start(struct test_dbus_context *context)
{
struct sailfish_cell cell;
struct test_get_cells_data *test =
G_CAST(context, struct test_get_cells_data, context);
DBG("");
test->info = fake_cell_info_new();
fake_cell_info_add_cell(test->info, test_cell_init_gsm1(&cell));
test->dbus = sailfish_cell_info_dbus_new(&test->modem, test->info);
g_assert(test->dbus);
test_get_cells_call(test, test_get_cells_start_reply1);
}
static void test_get_cells(void)
{
struct test_get_cells_data test;
guint timeout = test_setup_timeout();
memset(&test, 0, sizeof(test));
test.modem.path = TEST_MODEM_PATH;
test.context.start = test_get_cells_start;
test_dbus_setup(&test.context);
g_main_loop_run(test.context.loop);
sailfish_cell_info_unref(test.info);
sailfish_cell_info_dbus_free(test.dbus);
test_dbus_shutdown(&test.context);
if (timeout) {
g_source_remove(timeout);
}
}
/* ==== GetAll ==== */
struct test_get_all_data {
struct ofono_modem modem;
struct test_dbus_context context;
struct sailfish_cell_info_dbus *dbus;
struct sailfish_cell cell;
const char *type;
};
static void test_get_all_reply(DBusPendingCall *call, void *data)
{
struct test_get_all_data *test = data;
DBG("");
test_check_get_all_reply(call, &test->cell, test->type);
dbus_pending_call_unref(call);
test_loop_quit_later(test->context.loop);
}
static void test_get_all_start(struct test_dbus_context *context)
{
struct sailfish_cell_info *info;
struct test_get_all_data *test =
G_CAST(context, struct test_get_all_data, context);
DBG("");
info = fake_cell_info_new();
fake_cell_info_add_cell(info, &test->cell);
test->dbus = sailfish_cell_info_dbus_new(&test->modem, info);
g_assert(test->dbus);
sailfish_cell_info_unref(info);
test_submit_get_all_call(context->client_connection, "/test/cell_0",
test_get_all_reply, test);
}
static void test_get_all(const struct sailfish_cell *cell, const char *type)
{
struct test_get_all_data test;
guint timeout = test_setup_timeout();
memset(&test, 0, sizeof(test));
test.modem.path = TEST_MODEM_PATH;
test.context.start = test_get_all_start;
test.cell = *cell;
test.type = type;
test_dbus_setup(&test.context);
g_main_loop_run(test.context.loop);
sailfish_cell_info_dbus_free(test.dbus);
test_dbus_shutdown(&test.context);
if (timeout) {
g_source_remove(timeout);
}
}
static void test_get_all1(void)
{
struct sailfish_cell cell;
test_get_all(test_cell_init_gsm1(&cell), "gsm");
}
static void test_get_all2(void)
{
struct sailfish_cell cell;
test_get_all(test_cell_init_wcdma2(&cell), "wcdma");
}
static void test_get_all3(void)
{
struct sailfish_cell cell;
test_get_all(test_cell_init_lte(&cell), "lte");
}
static void test_get_all4(void)
{
struct sailfish_cell cell;
/* Invalid cell */
memset(&cell, 0xff, sizeof(cell));
test_get_all(&cell, "unknown");
}
/* ==== GetInterfaceVersion ==== */
struct test_get_version_data {
struct ofono_modem modem;
struct test_dbus_context context;
struct sailfish_cell_info_dbus *dbus;
};
static void test_get_version_reply(DBusPendingCall *call, void *data)
{
struct test_get_version_data *test = data;
DBusMessage *reply = dbus_pending_call_steal_reply(call);
dbus_int32_t version;
DBG("");
g_assert(dbus_message_get_type(reply) ==
DBUS_MESSAGE_TYPE_METHOD_RETURN);
g_assert(dbus_message_get_args(reply, NULL,
DBUS_TYPE_INT32, &version,
DBUS_TYPE_INVALID));
g_assert(version == CELL_DBUS_INTERFACE_VERSION);
dbus_message_unref(reply);
dbus_pending_call_unref(call);
test_loop_quit_later(test->context.loop);
}
static void test_get_version_start(struct test_dbus_context *context)
{
DBusPendingCall *call;
DBusMessage *msg;
struct sailfish_cell cell;
struct sailfish_cell_info *info;
struct test_get_version_data *test =
G_CAST(context, struct test_get_version_data, context);
DBG("");
info = fake_cell_info_new();
fake_cell_info_add_cell(info, test_cell_init_gsm1(&cell));
test->dbus = sailfish_cell_info_dbus_new(&test->modem, info);
g_assert(test->dbus);
sailfish_cell_info_unref(info);
msg = test_new_cell_call("/test/cell_0", "GetInterfaceVersion");
g_assert(dbus_connection_send_with_reply(context->client_connection,
msg, &call, DBUS_TIMEOUT_INFINITE));
dbus_pending_call_set_notify(call, test_get_version_reply, test, NULL);
dbus_message_unref(msg);
}
static void test_get_version(void)
{
struct test_get_version_data test;
guint timeout = test_setup_timeout();
memset(&test, 0, sizeof(test));
test.modem.path = TEST_MODEM_PATH;
test.context.start = test_get_version_start;
test_dbus_setup(&test.context);
g_main_loop_run(test.context.loop);
sailfish_cell_info_dbus_free(test.dbus);
test_dbus_shutdown(&test.context);
if (timeout) {
g_source_remove(timeout);
}
}
/* ==== GetType ==== */
struct test_get_type_data {
struct ofono_modem modem;
struct test_dbus_context context;
struct sailfish_cell_info_dbus *dbus;
};
static void test_get_type_reply(DBusPendingCall *call, void *data)
{
struct test_get_type_data *test = data;
DBusMessage *reply = dbus_pending_call_steal_reply(call);
DBusMessageIter it;
DBG("");
g_assert(dbus_message_get_type(reply) ==
DBUS_MESSAGE_TYPE_METHOD_RETURN);
dbus_message_iter_init(reply, &it);
g_assert(!g_strcmp0(test_dbus_get_string(&it), "wcdma"));
g_assert(dbus_message_iter_get_arg_type(&it) == DBUS_TYPE_INVALID);
dbus_message_unref(reply);
dbus_pending_call_unref(call);
test_loop_quit_later(test->context.loop);
}
static void test_get_type_start(struct test_dbus_context *context)
{
DBusPendingCall *call;
DBusMessage *msg;
struct sailfish_cell cell;
struct sailfish_cell_info *info;
struct test_get_type_data *test =
G_CAST(context, struct test_get_type_data, context);
DBG("");
info = fake_cell_info_new();
fake_cell_info_add_cell(info, test_cell_init_wcdma1(&cell));
test->dbus = sailfish_cell_info_dbus_new(&test->modem, info);
g_assert(test->dbus);
sailfish_cell_info_unref(info);
msg = test_new_cell_call("/test/cell_0", "GetType");
g_assert(dbus_connection_send_with_reply(context->client_connection,
msg, &call, DBUS_TIMEOUT_INFINITE));
dbus_pending_call_set_notify(call, test_get_type_reply, test, NULL);
dbus_message_unref(msg);
}
static void test_get_type(void)
{
struct test_get_type_data test;
guint timeout = test_setup_timeout();
memset(&test, 0, sizeof(test));
test.modem.path = TEST_MODEM_PATH;
test.context.start = test_get_type_start;
test_dbus_setup(&test.context);
g_main_loop_run(test.context.loop);
sailfish_cell_info_dbus_free(test.dbus);
test_dbus_shutdown(&test.context);
if (timeout) {
g_source_remove(timeout);
}
}
/* ==== GetRegistered ==== */
struct test_get_registered_data {
struct ofono_modem modem;
struct test_dbus_context context;
struct sailfish_cell_info_dbus *dbus;
};
static void test_get_registered_reply(DBusPendingCall *call, void *data)
{
struct test_get_registered_data *test = data;
DBusMessage *reply = dbus_pending_call_steal_reply(call);
DBusMessageIter it;
DBG("");
g_assert(dbus_message_get_type(reply) ==
DBUS_MESSAGE_TYPE_METHOD_RETURN);
dbus_message_iter_init(reply, &it);
g_assert(test_dbus_get_bool(&it) == TRUE);
g_assert(dbus_message_iter_get_arg_type(&it) == DBUS_TYPE_INVALID);
dbus_message_unref(reply);
dbus_pending_call_unref(call);
test_loop_quit_later(test->context.loop);
}
static void test_get_registered_start(struct test_dbus_context *context)
{
DBusPendingCall *call;
DBusMessage *msg;
struct sailfish_cell cell;
struct sailfish_cell_info *info;
struct test_get_registered_data *test =
G_CAST(context, struct test_get_registered_data, context);
DBG("");
info = fake_cell_info_new();
fake_cell_info_add_cell(info, test_cell_init_wcdma1(&cell));
test->dbus = sailfish_cell_info_dbus_new(&test->modem, info);
g_assert(test->dbus);
sailfish_cell_info_unref(info);
msg = test_new_cell_call("/test/cell_0", "GetRegistered");
g_assert(dbus_connection_send_with_reply(context->client_connection,
msg, &call, DBUS_TIMEOUT_INFINITE));
dbus_pending_call_set_notify(call, test_get_registered_reply, test,
NULL);
dbus_message_unref(msg);
}
static void test_get_registered(void)
{
struct test_get_registered_data test;
guint timeout = test_setup_timeout();
memset(&test, 0, sizeof(test));
test.modem.path = TEST_MODEM_PATH;
test.context.start = test_get_registered_start;
test_dbus_setup(&test.context);
g_main_loop_run(test.context.loop);
sailfish_cell_info_dbus_free(test.dbus);
test_dbus_shutdown(&test.context);
if (timeout) {
g_source_remove(timeout);
}
}
/* ==== GetProperties ==== */
struct test_get_properties_data {
struct ofono_modem modem;
struct test_dbus_context context;
struct sailfish_cell_info_dbus *dbus;
};
static void test_get_properties_reply(DBusPendingCall *call, void *data)
{
struct test_get_properties_data *test = data;
DBusMessage *reply = dbus_pending_call_steal_reply(call);
DBusMessageIter it, array;
DBG("");
g_assert(dbus_message_get_type(reply) ==
DBUS_MESSAGE_TYPE_METHOD_RETURN);
dbus_message_iter_init(reply, &it);
g_assert(dbus_message_iter_get_arg_type(&it) == DBUS_TYPE_ARRAY);
dbus_message_iter_recurse(&it, &array);
dbus_message_iter_next(&it);
/* Validate the properties? */
g_assert(dbus_message_iter_get_arg_type(&it) == DBUS_TYPE_INVALID);
dbus_message_unref(reply);
dbus_pending_call_unref(call);
test_loop_quit_later(test->context.loop);
}
static void test_get_properties_start(struct test_dbus_context *context)
{
DBusPendingCall *call;
DBusMessage *msg;
struct sailfish_cell cell;
struct sailfish_cell_info *info;
struct test_get_properties_data *test =
G_CAST(context, struct test_get_properties_data, context);
DBG("");
info = fake_cell_info_new();
fake_cell_info_add_cell(info, test_cell_init_wcdma2(&cell));
test->dbus = sailfish_cell_info_dbus_new(&test->modem, info);
g_assert(test->dbus);
sailfish_cell_info_unref(info);
msg = test_new_cell_call("/test/cell_0", "GetProperties");
g_assert(dbus_connection_send_with_reply(context->client_connection,
msg, &call, DBUS_TIMEOUT_INFINITE));
dbus_pending_call_set_notify(call, test_get_properties_reply, test,
NULL);
dbus_message_unref(msg);
}
static void test_get_properties(void)
{
struct test_get_properties_data test;
guint timeout = test_setup_timeout();
memset(&test, 0, sizeof(test));
test.modem.path = TEST_MODEM_PATH;
test.context.start = test_get_properties_start;
test_dbus_setup(&test.context);
g_main_loop_run(test.context.loop);
sailfish_cell_info_dbus_free(test.dbus);
test_dbus_shutdown(&test.context);
if (timeout) {
g_source_remove(timeout);
}
}
/* ==== RegisteredChanged ==== */
struct test_registered_changed_data {
struct ofono_modem modem;
struct test_dbus_context context;
struct sailfish_cell_info *info;
struct sailfish_cell_info_dbus *dbus;
struct sailfish_cell cell;
const char *type;
const char *cell_path;
};
static void test_registered_changed_reply(DBusPendingCall *call, void *data)
{
struct test_registered_changed_data *test = data;
DBG("");
test_check_get_all_reply(call, &test->cell, test->type);
dbus_pending_call_unref(call);
test_loop_quit_later(test->context.loop);
}
static void test_registered_changed_start(struct test_dbus_context *context)
{
struct test_registered_changed_data *test =
G_CAST(context, struct test_registered_changed_data, context);
struct sailfish_cell *first_cell;
DBG("");
test->info = fake_cell_info_new();
fake_cell_info_add_cell(test->info, &test->cell);
test->dbus = sailfish_cell_info_dbus_new(&test->modem, test->info);
g_assert(test->dbus);
/* Trigger "RegisteredChanged" signal */
first_cell = test->info->cells->data;
test->cell.registered =
first_cell->registered = !first_cell->registered;
fake_cell_info_cells_changed(test->info);
test_submit_get_all_call(context->client_connection, test->cell_path,
test_registered_changed_reply, test);
}
static void test_registered_changed(void)
{
struct test_registered_changed_data test;
guint timeout = test_setup_timeout();
memset(&test, 0, sizeof(test));
test.modem.path = TEST_MODEM_PATH;
test.context.start = test_registered_changed_start;
test_cell_init_gsm1(&test.cell);
test.type = "gsm";
test.cell_path = "/test/cell_0";
test_dbus_setup(&test.context);
g_main_loop_run(test.context.loop);
/* We must have received "RegisteredChanged" signal */
g_assert(test_dbus_find_signal(&test.context, test.cell_path,
CELL_DBUS_INTERFACE, CELL_DBUS_REGISTERED_CHANGED_SIGNAL));
sailfish_cell_info_unref(test.info);
sailfish_cell_info_dbus_free(test.dbus);
test_dbus_shutdown(&test.context);
if (timeout) {
g_source_remove(timeout);
}
}
/* ==== PropertyChanged ==== */
struct test_property_changed_data {
struct ofono_modem modem;
struct test_dbus_context context;
struct sailfish_cell_info *info;
struct sailfish_cell_info_dbus *dbus;
struct sailfish_cell cell;
const char *type;
const char *cell_path;
};
static void test_property_changed_reply1(DBusPendingCall *call, void *data)
{
struct test_property_changed_data *test = data;
DBG("");
test_check_get_all_reply(call, &test->cell, test->type);
dbus_pending_call_unref(call);
test_loop_quit_later(test->context.loop);
}
static void test_property_changed_start(struct test_dbus_context *context)
{
struct test_property_changed_data *test =
G_CAST(context, struct test_property_changed_data, context);
struct sailfish_cell *first_cell;
DBG("");
test->info = fake_cell_info_new();
fake_cell_info_add_cell(test->info, &test->cell);
test->dbus = sailfish_cell_info_dbus_new(&test->modem, test->info);
g_assert(test->dbus);
/* Trigger "PropertyChanged" signal */
first_cell = test->info->cells->data;
test->cell.info.gsm.signalStrength =
(++(first_cell->info.gsm.signalStrength));
fake_cell_info_cells_changed(test->info);
test_submit_get_all_call(context->client_connection, test->cell_path,
test_property_changed_reply1, test);
}
static void test_property_changed(void)
{
struct test_property_changed_data test;
guint timeout = test_setup_timeout();
memset(&test, 0, sizeof(test));
test.modem.path = TEST_MODEM_PATH;
test.context.start = test_property_changed_start;
test_cell_init_gsm1(&test.cell);
test.type = "gsm";
test.cell_path = "/test/cell_0";
test_dbus_setup(&test.context);
g_main_loop_run(test.context.loop);
/* We must have received "PropertyChanged" signal */
g_assert(test_dbus_find_signal(&test.context, test.cell_path,
CELL_DBUS_INTERFACE, CELL_DBUS_PROPERTY_CHANGED_SIGNAL));
sailfish_cell_info_unref(test.info);
sailfish_cell_info_dbus_free(test.dbus);
test_dbus_shutdown(&test.context);
if (timeout) {
g_source_remove(timeout);
}
}
#define TEST_(name) "/sailfish_cell_info_dbus/" name
int main(int argc, char *argv[])
{
int i;
g_test_init(&argc, &argv, NULL);
for (i=1; i<argc; i++) {
const char *arg = argv[i];
if (!strcmp(arg, "-d") || !strcmp(arg, "--debug")) {
test_debug = TRUE;
} else {
GWARN("Unsupported command line option %s", arg);
}
}
gutil_log_timestamp = FALSE;
gutil_log_default.level = g_test_verbose() ?
GLOG_LEVEL_VERBOSE : GLOG_LEVEL_NONE;
__ofono_log_init("test-sailfish_cell_info_dbus",
g_test_verbose() ? "*" : NULL,
FALSE, FALSE);
g_test_add_func(TEST_("Misc"), test_misc);
g_test_add_func(TEST_("GetCells"), test_get_cells);
g_test_add_func(TEST_("GetAll1"), test_get_all1);
g_test_add_func(TEST_("GetAll2"), test_get_all2);
g_test_add_func(TEST_("GetAll3"), test_get_all3);
g_test_add_func(TEST_("GetAll4"), test_get_all4);
g_test_add_func(TEST_("GetInterfaceVersion"), test_get_version);
g_test_add_func(TEST_("GetType"), test_get_type);
g_test_add_func(TEST_("GetRegistered"), test_get_registered);
g_test_add_func(TEST_("GetProperties"), test_get_properties);
g_test_add_func(TEST_("RegisteredChanged"), test_registered_changed);
g_test_add_func(TEST_("PropertyChanged"), test_property_changed);
return g_test_run();
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony
*
* Copyright (C) 2017 Jolla Ltd.
* Copyright (C) 2017-2018 Jolla Ltd.
*
* 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
@@ -919,9 +919,11 @@ static gboolean test_voice_sim_done(gpointer user_data)
g_assert(!g_strcmp0(m->default_voice_path, TEST_PATH));
/* Remove the SIM */
fake_sailfish_watch_set_ofono_sim(w, NULL);
fake_sailfish_watch_emit_queued_signals(w);
fake_sailfish_watch_set_ofono_iccid(w, NULL);
fake_sailfish_watch_set_ofono_imsi(w, NULL);
fake_sailfish_watch_set_ofono_spn(w, NULL);
sailfish_manager_set_sim_state(s->handle, SAILFISH_SIM_STATE_ABSENT);
fake_sailfish_watch_emit_queued_signals(w);
g_assert(!m->slots[0]->sim_present);
g_assert(!g_strcmp0(m->default_voice_imsi, TEST_IMSI));
g_assert(!m->default_voice_path);
@@ -1240,6 +1242,24 @@ static gboolean test_multisim_done(gpointer user_data)
g_assert(!m->default_data_imsi);
g_assert(!m->default_data_path);
/* But there is automatic voice SIM selection */
g_assert(!m->default_voice_imsi);
g_assert(!g_strcmp0(m->default_voice_path, TEST_PATH));
/* Switch the voice SIM back and forth */
fake_sailfish_manager_dbus.cb.set_default_voice_imsi(m, TEST_IMSI);
g_assert(!g_strcmp0(m->default_voice_imsi, TEST_IMSI));
g_assert(!g_strcmp0(m->default_voice_path, TEST_PATH));
fake_sailfish_manager_dbus.cb.set_default_voice_imsi(m, TEST_IMSI_1);
g_assert(!g_strcmp0(m->default_voice_imsi, TEST_IMSI_1));
g_assert(!g_strcmp0(m->default_voice_path, TEST_PATH_1));
/* test_1 remains the current voice slot */
fake_sailfish_manager_dbus.cb.set_default_voice_imsi(m, NULL);
g_assert(!m->default_voice_imsi);
g_assert(!g_strcmp0(m->default_voice_path, TEST_PATH_1));
/* Reserve the first slot for data */
fake_sailfish_manager_dbus.cb.set_default_data_imsi(m, TEST_IMSI);
g_assert(s->data_role == SAILFISH_DATA_ROLE_INTERNET);

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony
*
* Copyright (C) 2017 Jolla Ltd.
* Copyright (C) 2017-2018 Jolla Ltd.
*
* 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
@@ -27,8 +27,10 @@
#include <unistd.h>
#define TEST_PATH "/test"
#define TEST_ICCID "1111111111111111111"
#define TEST_ICCID "0000000000000000000"
#define TEST_IMSI "244120000000000"
#define TEST_ICCID_1 "1111111111111111111"
#define TEST_IMSI_1 "244120000000001"
#define TEST_MCC "244"
#define TEST_MNC "12"
#define TEST_DEFAULT_SPN TEST_MCC TEST_MNC
@@ -171,6 +173,18 @@ static void netreg_notify_status_watches(struct ofono_netreg *netreg)
}
}
static void test_remove_sim(struct ofono_sim* sim, struct sailfish_watch *watch)
{
sim->mcc = NULL;
sim->mnc = NULL;
sim->state = OFONO_SIM_STATE_NOT_PRESENT;
fake_sailfish_watch_signal_queue(watch, WATCH_SIGNAL_IMSI_CHANGED);
fake_sailfish_watch_signal_queue(watch, WATCH_SIGNAL_SIM_STATE_CHANGED);
fake_sailfish_watch_set_ofono_iccid(watch, NULL);
fake_sailfish_watch_set_ofono_imsi(watch, NULL);
fake_sailfish_watch_set_ofono_spn(watch, NULL);
fake_sailfish_watch_emit_queued_signals(watch);
}
/* Test cases */
@@ -182,7 +196,6 @@ static void test_basic(void)
g_assert(!sailfish_sim_info_new(NULL));
g_assert(!sailfish_sim_info_ref(NULL));
sailfish_sim_info_unref(NULL);
sailfish_sim_info_invalidate(NULL);
g_assert(!sailfish_sim_info_add_iccid_changed_handler(NULL,NULL,NULL));
g_assert(!sailfish_sim_info_add_imsi_changed_handler(NULL,NULL,NULL));
g_assert(!sailfish_sim_info_add_spn_changed_handler(NULL,NULL,NULL));
@@ -192,7 +205,6 @@ static void test_basic(void)
/* Very basic things (mostly to improve code coverage) */
si = sailfish_sim_info_new("/test");
g_assert(si);
sailfish_sim_info_invalidate(si);
g_assert(!sailfish_sim_info_add_iccid_changed_handler(si,NULL,NULL));
g_assert(!sailfish_sim_info_add_imsi_changed_handler(si,NULL,NULL));
g_assert(!sailfish_sim_info_add_spn_changed_handler(si,NULL,NULL));
@@ -241,6 +253,9 @@ static void test_cache(void)
g_assert(!count[SIM_INFO_SIGNAL_ICCID_CHANGED]);
g_assert(!count[SIM_INFO_SIGNAL_IMSI_CHANGED]);
g_assert(!count[SIM_INFO_SIGNAL_SPN_CHANGED]);
g_assert(!si->iccid);
g_assert(!si->imsi);
g_assert(!si->spn);
fake_sailfish_watch_set_ofono_iccid(w, TEST_ICCID);
fake_sailfish_watch_emit_queued_signals(w);
@@ -258,7 +273,7 @@ static void test_cache(void)
g_assert(!count[SIM_INFO_SIGNAL_SPN_CHANGED]);
g_assert(count[SIM_INFO_SIGNAL_IMSI_CHANGED] == 1);
count[SIM_INFO_SIGNAL_IMSI_CHANGED] = 0;
/* ICCID mape appears */
/* ICCID map appears */
g_assert(stat(ICCID_MAP, &st) == 0);
g_assert(S_ISREG(st.st_mode));
/* But no cache yet */
@@ -268,12 +283,46 @@ static void test_cache(void)
sim.mcc = TEST_MCC;
sim.mnc = TEST_MNC;
sim.state = OFONO_SIM_STATE_READY;
fake_sailfish_watch_signal_queue(w, WATCH_SIGNAL_IMSI_CHANGED);
fake_sailfish_watch_signal_queue(w, WATCH_SIGNAL_SIM_STATE_CHANGED);
fake_sailfish_watch_emit_queued_signals(w);
g_assert(!g_strcmp0(si->spn, TEST_DEFAULT_SPN));
g_assert(count[SIM_INFO_SIGNAL_SPN_CHANGED] == 1);
count[SIM_INFO_SIGNAL_SPN_CHANGED] = 0;
/* Remove the SIM and insert it again */
test_remove_sim(&sim, w);
g_assert(count[SIM_INFO_SIGNAL_ICCID_CHANGED] == 1);
g_assert(count[SIM_INFO_SIGNAL_IMSI_CHANGED] == 1);
g_assert(count[SIM_INFO_SIGNAL_SPN_CHANGED] == 1);
g_assert(!si->iccid);
g_assert(!si->imsi);
g_assert(!si->spn);
memset(count, 0, sizeof(count));
sim.state = OFONO_SIM_STATE_INSERTED;
fake_sailfish_watch_signal_queue(w, WATCH_SIGNAL_SIM_STATE_CHANGED);
fake_sailfish_watch_emit_queued_signals(w);
g_assert(!count[SIM_INFO_SIGNAL_ICCID_CHANGED]);
g_assert(!count[SIM_INFO_SIGNAL_IMSI_CHANGED]);
g_assert(!count[SIM_INFO_SIGNAL_SPN_CHANGED]);
sim.mcc = TEST_MCC;
sim.mnc = TEST_MNC;
sim.state = OFONO_SIM_STATE_READY;
fake_sailfish_watch_signal_queue(w, WATCH_SIGNAL_SIM_STATE_CHANGED);
fake_sailfish_watch_set_ofono_iccid(w, TEST_ICCID);
fake_sailfish_watch_emit_queued_signals(w);
/* IMSI gets loaded from the cache file */
g_assert(!g_strcmp0(si->iccid, TEST_ICCID));
g_assert(!g_strcmp0(si->imsi, TEST_IMSI));
g_assert(!g_strcmp0(si->spn, TEST_DEFAULT_SPN));
g_assert(count[SIM_INFO_SIGNAL_ICCID_CHANGED] == 1);
g_assert(count[SIM_INFO_SIGNAL_IMSI_CHANGED] == 1);
g_assert(count[SIM_INFO_SIGNAL_SPN_CHANGED] == 1);
memset(count, 0, sizeof(count));
/* Replace default SPN with the real one */
fake_sailfish_watch_set_ofono_spn(w, TEST_SPN);
fake_sailfish_watch_emit_queued_signals(w);
@@ -286,24 +335,39 @@ static void test_cache(void)
g_assert(stat(SIM_CACHE, &st) == 0);
g_assert(S_ISREG(st.st_mode));
/* Reset the information */
sim.mcc = NULL;
sim.mnc = NULL;
sim.state = OFONO_SIM_STATE_NOT_PRESENT;
/* Stray events have no effect */
fake_sailfish_watch_signal_queue(w, WATCH_SIGNAL_SPN_CHANGED);
fake_sailfish_watch_signal_queue(w, WATCH_SIGNAL_IMSI_CHANGED);
fake_sailfish_watch_signal_queue(w, WATCH_SIGNAL_ICCID_CHANGED);
fake_sailfish_watch_signal_queue(w, WATCH_SIGNAL_SIM_STATE_CHANGED);
fake_sailfish_watch_set_ofono_iccid(w, NULL);
fake_sailfish_watch_set_ofono_imsi(w, NULL);
fake_sailfish_watch_set_ofono_spn(w, NULL);
fake_sailfish_watch_emit_queued_signals(w);
g_assert(!count[SIM_INFO_SIGNAL_ICCID_CHANGED]);
g_assert(!count[SIM_INFO_SIGNAL_IMSI_CHANGED]);
g_assert(!count[SIM_INFO_SIGNAL_SPN_CHANGED]);
/* Empty SPN and IMSI are ignored too */
fake_sailfish_watch_set_ofono_imsi(w, "");
fake_sailfish_watch_set_ofono_spn(w, "");
fake_sailfish_watch_emit_queued_signals(w);
g_assert(!count[SIM_INFO_SIGNAL_ICCID_CHANGED]);
g_assert(!count[SIM_INFO_SIGNAL_IMSI_CHANGED]);
g_assert(!count[SIM_INFO_SIGNAL_SPN_CHANGED]);
/* Reset the information */
test_remove_sim(&sim, w);
g_assert(count[SIM_INFO_SIGNAL_ICCID_CHANGED] == 1);
g_assert(count[SIM_INFO_SIGNAL_IMSI_CHANGED] == 1);
g_assert(count[SIM_INFO_SIGNAL_SPN_CHANGED] == 1);
g_assert(!si->iccid);
g_assert(!si->imsi);
g_assert(!si->spn);
memset(count, 0, sizeof(count));
/* Set ICCID again, that will load the cached information */
sim.mcc = NULL;
sim.mnc = NULL;
sim.state = OFONO_SIM_STATE_INSERTED;
fake_sailfish_watch_signal_queue(w, WATCH_SIGNAL_ICCID_CHANGED);
fake_sailfish_watch_signal_queue(w, WATCH_SIGNAL_SIM_STATE_CHANGED);
fake_sailfish_watch_set_ofono_iccid(w, TEST_ICCID);
fake_sailfish_watch_emit_queued_signals(w);
@@ -315,12 +379,75 @@ static void test_cache(void)
g_assert(count[SIM_INFO_SIGNAL_SPN_CHANGED] == 1);
memset(count, 0, sizeof(count));
sailfish_sim_info_remove_handler(si, id[SIM_INFO_SIGNAL_SPN_CHANGED]);
id[SIM_INFO_SIGNAL_SPN_CHANGED] = 0;
sailfish_sim_info_invalidate(si);
/* Replace the SIM with a different one */
test_remove_sim(&sim, w);
g_assert(count[SIM_INFO_SIGNAL_ICCID_CHANGED] == 1);
g_assert(count[SIM_INFO_SIGNAL_IMSI_CHANGED] == 1);
g_assert(count[SIM_INFO_SIGNAL_SPN_CHANGED] == 1);
g_assert(!si->iccid);
g_assert(!si->imsi);
g_assert(!si->iccid);
g_assert(!si->spn);
memset(count, 0, sizeof(count));
sim.state = OFONO_SIM_STATE_INSERTED;
fake_sailfish_watch_signal_queue(w, WATCH_SIGNAL_SIM_STATE_CHANGED);
fake_sailfish_watch_emit_queued_signals(w);
g_assert(!count[SIM_INFO_SIGNAL_ICCID_CHANGED]);
g_assert(!count[SIM_INFO_SIGNAL_IMSI_CHANGED]);
g_assert(!count[SIM_INFO_SIGNAL_SPN_CHANGED]);
sim.mcc = TEST_MCC;
sim.mnc = TEST_MNC;
sim.state = OFONO_SIM_STATE_READY;
fake_sailfish_watch_signal_queue(w, WATCH_SIGNAL_SIM_STATE_CHANGED);
fake_sailfish_watch_set_ofono_iccid(w, TEST_ICCID_1);
fake_sailfish_watch_set_ofono_imsi(w, TEST_IMSI_1);
fake_sailfish_watch_emit_queued_signals(w);
g_assert(!g_strcmp0(si->iccid, TEST_ICCID_1));
g_assert(!g_strcmp0(si->imsi, TEST_IMSI_1));
g_assert(!g_strcmp0(si->spn, TEST_DEFAULT_SPN));
g_assert(count[SIM_INFO_SIGNAL_ICCID_CHANGED] == 1);
g_assert(count[SIM_INFO_SIGNAL_IMSI_CHANGED] == 1);
g_assert(count[SIM_INFO_SIGNAL_SPN_CHANGED] == 1);
memset(count, 0, sizeof(count));
/* And then insert back the previous one */
test_remove_sim(&sim, w);
memset(count, 0, sizeof(count));
sim.state = OFONO_SIM_STATE_INSERTED;
fake_sailfish_watch_signal_queue(w, WATCH_SIGNAL_SIM_STATE_CHANGED);
fake_sailfish_watch_emit_queued_signals(w);
sim.mcc = TEST_MCC;
sim.mnc = TEST_MNC;
sim.state = OFONO_SIM_STATE_READY;
fake_sailfish_watch_signal_queue(w, WATCH_SIGNAL_SIM_STATE_CHANGED);
fake_sailfish_watch_set_ofono_iccid(w, TEST_ICCID);
fake_sailfish_watch_set_ofono_imsi(w, TEST_IMSI);
fake_sailfish_watch_emit_queued_signals(w);
g_assert(!g_strcmp0(si->iccid, TEST_ICCID));
g_assert(!g_strcmp0(si->imsi, TEST_IMSI));
g_assert(!g_strcmp0(si->spn, TEST_SPN));
g_assert(count[SIM_INFO_SIGNAL_ICCID_CHANGED] == 1);
g_assert(count[SIM_INFO_SIGNAL_IMSI_CHANGED] == 1);
g_assert(count[SIM_INFO_SIGNAL_SPN_CHANGED] == 1);
memset(count, 0, sizeof(count));
/* Make sure that removed handler doesn't get invoked */
sailfish_sim_info_remove_handler(si, id[SIM_INFO_SIGNAL_SPN_CHANGED]);
id[SIM_INFO_SIGNAL_SPN_CHANGED] = 0;
sim.mcc = NULL;
sim.mnc = NULL;
sim.state = OFONO_SIM_STATE_NOT_PRESENT;
fake_sailfish_watch_signal_queue(w, WATCH_SIGNAL_IMSI_CHANGED);
fake_sailfish_watch_signal_queue(w, WATCH_SIGNAL_SIM_STATE_CHANGED);
fake_sailfish_watch_set_ofono_iccid(w, NULL);
fake_sailfish_watch_set_ofono_imsi(w, NULL);
fake_sailfish_watch_set_ofono_spn(w, NULL);
fake_sailfish_watch_emit_queued_signals(w);
g_assert(count[SIM_INFO_SIGNAL_ICCID_CHANGED] == 1);
g_assert(count[SIM_INFO_SIGNAL_IMSI_CHANGED] == 1);
g_assert(!count[SIM_INFO_SIGNAL_SPN_CHANGED]); /* removed ^ */

View File

@@ -0,0 +1,670 @@
/*
* oFono - Open Source Telephony
*
* Copyright (C) 2018 Jolla Ltd.
*
* 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.
*/
#include "test-dbus.h"
#include "fake_sailfish_watch.h"
#include "sailfish_sim_info.h"
#include <gutil_log.h>
#include <gutil_macros.h>
#include "ofono.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#define TEST_TIMEOUT (10) /* seconds */
#define TEST_MODEM_PATH "/test"
#define TEST_ICCID "0000000000000000000"
#define TEST_IMSI "244120000000000"
#define TEST_MCC "244"
#define TEST_MNC "12"
#define TEST_DEFAULT_SPN TEST_MCC TEST_MNC
#define TEST_SPN "Test"
#define SIM_INFO_DBUS_INTERFACE "org.nemomobile.ofono.SimInfo"
#define SIM_INFO_DBUS_INTERFACE_VERSION (1)
#define SIM_INFO_DBUS_ICCID_CHANGED_SIGNAL "CardIdentifierChanged"
#define SIM_INFO_DBUS_IMSI_CHANGED_SIGNAL "SubscriberIdentityChanged"
#define SIM_INFO_DBUS_SPN_CHANGED_SIGNAL "ServiceProviderNameChanged"
static gboolean test_debug;
/* Fake ofono_sim */
struct ofono_sim {
const char *mcc;
const char *mnc;
const char *spn;
enum ofono_sim_state state;
};
enum ofono_sim_state ofono_sim_get_state(struct ofono_sim *sim)
{
return sim ? sim->state : OFONO_SIM_STATE_NOT_PRESENT;
}
const char *ofono_sim_get_mcc(struct ofono_sim *sim)
{
return sim ? sim->mcc : NULL;
}
const char *ofono_sim_get_mnc(struct ofono_sim *sim)
{
return sim ? sim->mnc : NULL;
}
/* Stubs (ofono) */
struct ofono_modem {
const char *path;
GSList *iflist;
struct ofono_sim sim;
};
const char *ofono_modem_get_path(struct ofono_modem *modem)
{
return modem->path;
}
static gint test_strcmp(gconstpointer a, gconstpointer b)
{
return g_strcmp0(a, b);
}
static char *test_find_interface(struct ofono_modem *modem, const char *iface)
{
GSList *l = g_slist_find_custom(modem->iflist, iface, test_strcmp);
return l ? l->data : NULL;
}
void ofono_modem_add_interface(struct ofono_modem *modem, const char *iface)
{
if (iface && !test_find_interface(modem, iface)) {
DBG("%s %s", modem->path, iface);
modem->iflist = g_slist_append(modem->iflist, g_strdup(iface));
}
}
void ofono_modem_remove_interface(struct ofono_modem *modem, const char *iface)
{
char *found = test_find_interface(modem, iface);
if (found) {
DBG("%s %s", modem->path, iface);
modem->iflist = g_slist_remove(modem->iflist, found);
g_free(found);
}
}
/* Fake ofono_netreg */
struct ofono_netreg {
const char *mcc;
const char *mnc;
const char *name;
int location;
int cellid;
enum ofono_radio_access_mode technology;
int status;
struct ofono_watchlist *status_watches;
};
int ofono_netreg_get_status(struct ofono_netreg *netreg)
{
return netreg ? (int) netreg->status : -1;
}
const char *ofono_netreg_get_mcc(struct ofono_netreg *netreg)
{
return netreg ? netreg->mcc : NULL;
}
const char *ofono_netreg_get_mnc(struct ofono_netreg *netreg)
{
return netreg ? netreg->mnc : NULL;
}
const char *ofono_netreg_get_name(struct ofono_netreg *netreg)
{
return netreg ? netreg->name : NULL;
}
unsigned int __ofono_netreg_add_status_watch(struct ofono_netreg *netreg,
ofono_netreg_status_notify_cb_t notify,
void *data, ofono_destroy_func destroy)
{
struct ofono_watchlist_item *item =
g_new0(struct ofono_watchlist_item, 1);
DBG("%p", netreg);
g_assert(netreg);
g_assert(notify);
item->notify = notify;
item->destroy = destroy;
item->notify_data = data;
return __ofono_watchlist_add_item(netreg->status_watches, item);
}
gboolean __ofono_netreg_remove_status_watch(struct ofono_netreg *netreg,
unsigned int id)
{
return __ofono_watchlist_remove_item(netreg->status_watches, id);
}
/* Utilities */
static int rmdir_r(const char *path)
{
DIR *d = opendir(path);
if (d) {
const struct dirent *p;
int r = 0;
while (!r && (p = readdir(d))) {
char *buf;
struct stat st;
if (!strcmp(p->d_name, ".") ||
!strcmp(p->d_name, "..")) {
continue;
}
buf = g_strdup_printf("%s/%s", path, p->d_name);
if (!stat(buf, &st)) {
r = S_ISDIR(st.st_mode) ? rmdir_r(buf) :
unlink(buf);
}
g_free(buf);
}
closedir(d);
return r ? r : rmdir(path);
} else {
return -1;
}
}
/* ==== common ==== */
static gboolean test_timeout(gpointer param)
{
g_assert(!"TIMEOUT");
return G_SOURCE_REMOVE;
}
static guint test_setup_timeout(void)
{
if (!test_debug) {
return 0;
} else {
return g_timeout_add_seconds(TEST_TIMEOUT, test_timeout, NULL);
}
}
static gboolean test_loop_quit(gpointer data)
{
g_main_loop_quit(data);
return G_SOURCE_REMOVE;
}
static void test_loop_quit_later(GMainLoop *loop)
{
g_idle_add(test_loop_quit, loop);
}
/* ==== Misc ==== */
static void test_misc(void)
{
/* NULL resistance */
g_assert(!sailfish_sim_info_dbus_new_path(NULL));
sailfish_sim_info_dbus_free(NULL);
}
/* ==== GetAll ==== */
struct test_get_all_data {
struct ofono_modem modem;
struct test_dbus_context context;
struct sailfish_sim_info_dbus *dbus;
struct sailfish_watch *watch;
const char *iccid;
};
static void test_submit_get_all_call(struct test_get_all_data *test,
DBusPendingCallNotifyFunction notify)
{
DBusPendingCall *call;
DBusConnection* connection = test->context.client_connection;
DBusMessage *msg = dbus_message_new_method_call(NULL, test->modem.path,
SIM_INFO_DBUS_INTERFACE, "GetAll");
g_assert(dbus_connection_send_with_reply(connection, msg, &call,
DBUS_TIMEOUT_INFINITE));
dbus_pending_call_set_notify(call, notify, test, NULL);
dbus_message_unref(msg);
}
static void test_check_get_all_reply(struct test_get_all_data *test,
DBusPendingCall *call)
{
DBusMessage *reply = dbus_pending_call_steal_reply(call);
DBusMessageIter it;
g_assert(dbus_message_get_type(reply) ==
DBUS_MESSAGE_TYPE_METHOD_RETURN);
dbus_message_iter_init(reply, &it);
g_assert(test_dbus_get_int32(&it) == SIM_INFO_DBUS_INTERFACE_VERSION);
g_assert(!g_strcmp0(test_dbus_get_string(&it), test->iccid));
g_assert(!g_strcmp0(test_dbus_get_string(&it), ""));
g_assert(!g_strcmp0(test_dbus_get_string(&it), ""));
g_assert(dbus_message_iter_get_arg_type(&it) == DBUS_TYPE_INVALID);
dbus_message_unref(reply);
}
static void test_get_all_reply(DBusPendingCall *call, void *data)
{
struct test_get_all_data *test = data;
DBG("");
test_check_get_all_reply(test, call);
dbus_pending_call_unref(call);
test_loop_quit_later(test->context.loop);
}
static void test_get_all1_start(struct test_dbus_context *context)
{
struct test_get_all_data *test =
G_CAST(context, struct test_get_all_data, context);
const char *path = test->modem.path;
DBG("");
test->dbus = sailfish_sim_info_dbus_new_path(path);
g_assert(test->dbus);
test_submit_get_all_call(test, test_get_all_reply);
}
static void test_get_all1(void)
{
struct test_get_all_data test;
guint timeout = test_setup_timeout();
rmdir_r(STORAGEDIR);
memset(&test, 0, sizeof(test));
test.modem.path = TEST_MODEM_PATH;
test.context.start = test_get_all1_start;
test.watch = sailfish_watch_new(test.modem.path);
test.watch->modem = &test.modem;
test.iccid = "";
test_dbus_setup(&test.context);
g_main_loop_run(test.context.loop);
sailfish_watch_unref(test.watch);
sailfish_sim_info_dbus_free(test.dbus);
test_dbus_shutdown(&test.context);
if (timeout) {
g_source_remove(timeout);
}
rmdir_r(STORAGEDIR);
}
/* ==== GetAll2 ==== */
static void test_get_all2_start(struct test_dbus_context *context)
{
struct test_get_all_data *test =
G_CAST(context, struct test_get_all_data, context);
const char *path = test->modem.path;
struct sailfish_watch *watch = test->watch;
DBG("");
test->dbus = sailfish_sim_info_dbus_new_path(path);
g_assert(test->dbus);
/* Tell sailfish_watch that we have a modem */
test->watch->modem = &test->modem;
fake_sailfish_watch_set_ofono_sim(watch, &test->modem.sim);
fake_sailfish_watch_set_ofono_iccid(watch, test->iccid);
fake_sailfish_watch_signal_queue(watch, WATCH_SIGNAL_MODEM_CHANGED);
fake_sailfish_watch_emit_queued_signals(watch);
test_submit_get_all_call(test, test_get_all_reply);
}
static void test_get_all2(void)
{
struct test_get_all_data test;
guint timeout = test_setup_timeout();
rmdir_r(STORAGEDIR);
memset(&test, 0, sizeof(test));
test.modem.path = TEST_MODEM_PATH;
test.context.start = test_get_all2_start;
test.watch = sailfish_watch_new(test.modem.path);
test.iccid = TEST_ICCID;
test_dbus_setup(&test.context);
g_main_loop_run(test.context.loop);
/* "CardIdentifierChanged" is expected */
g_assert(test_dbus_find_signal(&test.context, test.modem.path,
SIM_INFO_DBUS_INTERFACE, SIM_INFO_DBUS_ICCID_CHANGED_SIGNAL));
sailfish_watch_unref(test.watch);
sailfish_sim_info_dbus_free(test.dbus);
test_dbus_shutdown(&test.context);
if (timeout) {
g_source_remove(timeout);
}
rmdir_r(STORAGEDIR);
}
/* ==== GetInterfaceVersion ==== */
struct test_get_version_data {
struct ofono_modem modem;
struct test_dbus_context context;
struct sailfish_sim_info_dbus *dbus;
};
static void test_get_version_reply(DBusPendingCall *call, void *data)
{
struct test_get_version_data *test = data;
DBusMessage *reply = dbus_pending_call_steal_reply(call);
DBusMessageIter it;
DBG("");
g_assert(dbus_message_get_type(reply) ==
DBUS_MESSAGE_TYPE_METHOD_RETURN);
dbus_message_iter_init(reply, &it);
g_assert(test_dbus_get_int32(&it) == SIM_INFO_DBUS_INTERFACE_VERSION);
g_assert(dbus_message_iter_get_arg_type(&it) == DBUS_TYPE_INVALID);
dbus_message_unref(reply);
dbus_pending_call_unref(call);
test_loop_quit_later(test->context.loop);
}
static void test_get_version_start(struct test_dbus_context *context)
{
DBusMessage *msg;
DBusPendingCall *call;
struct test_get_version_data *test =
G_CAST(context, struct test_get_version_data, context);
const char *path = test->modem.path;
DBG("");
test->dbus = sailfish_sim_info_dbus_new_path(path);
g_assert(test->dbus);
msg = dbus_message_new_method_call(NULL, test->modem.path,
SIM_INFO_DBUS_INTERFACE, "GetInterfaceVersion");
g_assert(dbus_connection_send_with_reply(context->client_connection,
msg, &call, DBUS_TIMEOUT_INFINITE));
dbus_pending_call_set_notify(call, test_get_version_reply, test, NULL);
dbus_message_unref(msg);
}
static void test_get_version(void)
{
struct test_get_version_data test;
guint timeout = test_setup_timeout();
memset(&test, 0, sizeof(test));
test.modem.path = TEST_MODEM_PATH;
test.context.start = test_get_version_start;
test_dbus_setup(&test.context);
g_main_loop_run(test.context.loop);
sailfish_sim_info_dbus_free(test.dbus);
test_dbus_shutdown(&test.context);
if (timeout) {
g_source_remove(timeout);
}
}
/* ==== GetCardIdentifier ==== */
struct test_get_iccid_data {
struct ofono_modem modem;
struct test_dbus_context context;
struct sailfish_sim_info_dbus *dbus;
struct sailfish_watch *watch;
const char *iccid;
const char *result;
};
static void test_get_iccid_reply(DBusPendingCall *call, void *data)
{
struct test_get_iccid_data *test = data;
DBG("");
test_dbus_check_string_reply(call, test->result);
dbus_pending_call_unref(call);
test_loop_quit_later(test->context.loop);
}
static void test_get_iccid_start(struct test_dbus_context *context)
{
DBusMessage *msg;
DBusPendingCall *call;
struct test_get_iccid_data *test =
G_CAST(context, struct test_get_iccid_data, context);
const char *path = test->modem.path;
DBG("");
test->dbus = sailfish_sim_info_dbus_new_path(path);
fake_sailfish_watch_set_ofono_iccid(test->watch, test->iccid);
fake_sailfish_watch_emit_queued_signals(test->watch);
g_assert(test->dbus);
msg = dbus_message_new_method_call(NULL, test->modem.path,
SIM_INFO_DBUS_INTERFACE, "GetCardIdentifier");
g_assert(dbus_connection_send_with_reply(context->client_connection,
msg, &call, DBUS_TIMEOUT_INFINITE));
dbus_pending_call_set_notify(call, test_get_iccid_reply, test, NULL);
dbus_message_unref(msg);
}
static void test_get_iccid(const char *init_iccid, const char *set_iccid,
const char *result)
{
struct test_get_iccid_data test;
guint timeout = test_setup_timeout();
memset(&test, 0, sizeof(test));
test.iccid = set_iccid;
test.result = result;
test.modem.path = TEST_MODEM_PATH;
test.context.start = test_get_iccid_start;
test.watch = sailfish_watch_new(test.modem.path);
test.watch->modem = &test.modem;
fake_sailfish_watch_set_ofono_iccid(test.watch, init_iccid);
fake_sailfish_watch_emit_queued_signals(test.watch);
test_dbus_setup(&test.context);
g_main_loop_run(test.context.loop);
/* "CardIdentifierChanged" is expected */
g_assert(test_dbus_find_signal(&test.context, test.modem.path,
SIM_INFO_DBUS_INTERFACE, SIM_INFO_DBUS_ICCID_CHANGED_SIGNAL));
sailfish_watch_unref(test.watch);
sailfish_sim_info_dbus_free(test.dbus);
test_dbus_shutdown(&test.context);
if (timeout) {
g_source_remove(timeout);
}
}
static void test_get_iccid1(void)
{
test_get_iccid(NULL, TEST_ICCID, TEST_ICCID);
}
/* ==== GetCardIdentifier2 ==== */
static void test_get_iccid2(void)
{
test_get_iccid(TEST_ICCID, NULL, "");
}
/* ==== GetSubscriberIdentity ==== */
struct test_get_string_data {
struct ofono_modem modem;
struct test_dbus_context context;
struct sailfish_sim_info_dbus *dbus;
struct sailfish_watch *watch;
const char *method;
const char *result;
};
static void test_get_string_reply(DBusPendingCall *call, void *data)
{
struct test_get_string_data *test = data;
DBG("");
test_dbus_check_string_reply(call, test->result);
dbus_pending_call_unref(call);
test_loop_quit_later(test->context.loop);
}
static void test_get_string_start(struct test_dbus_context *context)
{
DBusMessage *msg;
DBusPendingCall *call;
struct test_get_string_data *test =
G_CAST(context, struct test_get_string_data, context);
const char *path = test->modem.path;
struct ofono_sim *sim = &test->modem.sim;
struct sailfish_watch *watch = test->watch;
DBG("%s", test->method);
test->dbus = sailfish_sim_info_dbus_new_path(path);
sim->mcc = TEST_MCC;
sim->mnc = TEST_MNC;
sim->state = OFONO_SIM_STATE_READY;
fake_sailfish_watch_signal_queue(watch, WATCH_SIGNAL_SIM_STATE_CHANGED);
fake_sailfish_watch_set_ofono_imsi(watch, TEST_IMSI);
fake_sailfish_watch_emit_queued_signals(watch);
g_assert(test->dbus);
msg = dbus_message_new_method_call(NULL, test->modem.path,
SIM_INFO_DBUS_INTERFACE, test->method);
g_assert(dbus_connection_send_with_reply(context->client_connection,
msg, &call, DBUS_TIMEOUT_INFINITE));
dbus_pending_call_set_notify(call, test_get_string_reply, test, NULL);
dbus_message_unref(msg);
}
static void test_get_string(const char *method, const char *result)
{
struct test_get_string_data test;
guint timeout = test_setup_timeout();
rmdir_r(STORAGEDIR);
memset(&test, 0, sizeof(test));
test.method = method;
test.result = result;
test.modem.path = TEST_MODEM_PATH;
test.context.start = test_get_string_start;
test.watch = sailfish_watch_new(test.modem.path);
test.watch->modem = &test.modem;
fake_sailfish_watch_set_ofono_iccid(test.watch, TEST_ICCID);
fake_sailfish_watch_set_ofono_sim(test.watch, &test.modem.sim);
fake_sailfish_watch_emit_queued_signals(test.watch);
test_dbus_setup(&test.context);
g_main_loop_run(test.context.loop);
/* Verify signals */
g_assert(test_dbus_find_signal(&test.context, test.modem.path,
SIM_INFO_DBUS_INTERFACE, SIM_INFO_DBUS_IMSI_CHANGED_SIGNAL));
g_assert(test_dbus_find_signal(&test.context, test.modem.path,
SIM_INFO_DBUS_INTERFACE, SIM_INFO_DBUS_SPN_CHANGED_SIGNAL));
sailfish_watch_unref(test.watch);
sailfish_sim_info_dbus_free(test.dbus);
test_dbus_shutdown(&test.context);
if (timeout) {
g_source_remove(timeout);
}
rmdir_r(STORAGEDIR);
}
static void test_get_imsi(void)
{
test_get_string("GetSubscriberIdentity", TEST_IMSI);
}
/* ==== GetServiceProviderName ==== */
static void test_get_spn(void)
{
test_get_string("GetServiceProviderName", TEST_DEFAULT_SPN);
}
#define TEST_(name) "/sailfish_sim_info_dbus/" name
int main(int argc, char *argv[])
{
int i;
g_test_init(&argc, &argv, NULL);
for (i=1; i<argc; i++) {
const char *arg = argv[i];
if (!strcmp(arg, "-d") || !strcmp(arg, "--debug")) {
test_debug = TRUE;
} else {
GWARN("Unsupported command line option %s", arg);
}
}
gutil_log_timestamp = FALSE;
gutil_log_default.level = g_test_verbose() ?
GLOG_LEVEL_VERBOSE : GLOG_LEVEL_NONE;
__ofono_log_init("test-sailfish_sim_info_dbus",
g_test_verbose() ? "*" : NULL,
FALSE, FALSE);
g_test_add_func(TEST_("Misc"), test_misc);
g_test_add_func(TEST_("GetAll1"), test_get_all1);
g_test_add_func(TEST_("GetAll2"), test_get_all2);
g_test_add_func(TEST_("GetInterfaceVersion"), test_get_version);
g_test_add_func(TEST_("GetCardIdentifier1"), test_get_iccid1);
g_test_add_func(TEST_("GetCardIdentifier2"), test_get_iccid2);
g_test_add_func(TEST_("GetSubscriberIdentity"), test_get_imsi);
g_test_add_func(TEST_("GetServiceProviderName"), test_get_spn);
return g_test_run();
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

@@ -10,17 +10,18 @@ Source: %{name}-%{version}.tar.bz2
Requires: dbus
Requires: systemd
Requires: ofono-configs
Requires: libgrilio >= 1.0.16
Requires: libgrilio >= 1.0.20
Requires: libglibutil >= 1.0.23
Requires: mobile-broadband-provider-info
Requires(preun): systemd
Requires(post): systemd
Requires(postun): systemd
BuildRequires: pkgconfig(dbus-1)
BuildRequires: pkgconfig(dbus-glib-1)
BuildRequires: pkgconfig(glib-2.0)
BuildRequires: pkgconfig(libudev) >= 145
BuildRequires: pkgconfig(libwspcodec) >= 2.0
BuildRequires: pkgconfig(libgrilio) >= 1.0.18
BuildRequires: pkgconfig(libgrilio) >= 1.0.20
BuildRequires: pkgconfig(libglibutil) >= 1.0.23
BuildRequires: pkgconfig(libdbuslogserver-dbus)
BuildRequires: pkgconfig(libmce-glib) >= 1.0.5