Compare commits

...

7 Commits

Author SHA1 Message Date
Slava Monich
47fd559c1b Merge pull request #36 from monich/jb58727
Remove event source after closing BT socket
2022-09-08 01:18:26 +03:00
Slava Monich
8fa9a7068f [hfp_ag_bluez5] Remove event source after closing BT socket. JB#58727
Otherwise GIOChannel stays alive and glib main loop keeps polling
invalid fd and eating up CPU time.
2022-09-07 17:21:24 +03:00
Slava Monich
10c1d7ac75 [ims] Tweak the treatment of the default Registration value
To handle the case if it's not IMS_REG_AUTO
2022-05-09 17:57:41 +03:00
Slava Monich
81ad45dfd9 Merge pull request #33 from monich/ims
org.ofono.IpMultimediaSystem D-Bus API tweaks
2022-04-21 04:33:24 +03:00
Slava Monich
0e27cf811b [ims] Extend org.ofono.IpMultimediaSystem D-Bus API. JB#57999
The following property has been added to the API:

	string Registration [readwrite, Sailfish OS specific]

		The IMS registration strategy. Valid values are:

			"disabled" keep registration off
			"enabled"  manual registration
			"auto"     keep registration on

		The Register() method, if implemented, will fail
		with [service].Error.NotAllowed if the value of
		this property is "disabled".
2022-04-21 03:40:28 +03:00
Slava Monich
5ec5081b7d [watch] Added reg_tech watch. JB#57999 2022-04-20 20:23:02 +03:00
Slava Monich
d2cae30a03 [ims] D-Bus access control for org.ofono.IpMultimediaSystem. JB#57408 2022-04-14 01:28:01 +03:00
10 changed files with 667 additions and 129 deletions

View File

@@ -16,7 +16,7 @@ Methods dict GetProperties()
changeable. On success a PropertyChanged signal changeable. On success a PropertyChanged signal
will be emitted. will be emitted.
Possible Errors: [service].Error.InProgress Possible Errors: [service].Error.AccessDenied
[service].Error.InvalidArguments [service].Error.InvalidArguments
[service].Error.Failed [service].Error.Failed
@@ -27,8 +27,10 @@ Methods dict GetProperties()
initiated successfully. The actual registration state initiated successfully. The actual registration state
will be reflected by the 'Registered' property. will be reflected by the 'Registered' property.
Possible Errors: [service].Error.InProgress Possible Errors: [service].Error.AccessDenied
[service].Error.NotAllowed
[service].Error.NotImplemented [service].Error.NotImplemented
[service].Error.Failed
void Unregister() void Unregister()
@@ -37,8 +39,9 @@ Methods dict GetProperties()
be initiated successfully. The actual unregistration be initiated successfully. The actual unregistration
state will be reflected by the 'Registered' property. state will be reflected by the 'Registered' property.
Possible Errors: [service].Error.InProgress Possible Errors: [service].Error.AccessDenied
[service].Error.NotImplemented [service].Error.NotImplemented
[service].Error.Failed
Signals PropertyChanged(string property, variant value) Signals PropertyChanged(string property, variant value)
@@ -57,3 +60,15 @@ Properties boolean Registered [readonly]
boolean SmsCapable [readonly, optional] boolean SmsCapable [readonly, optional]
Boolean representing whether SMS-over-IMS is available. Boolean representing whether SMS-over-IMS is available.
string Registration [readwrite, Sailfish OS specific]
The IMS registration strategy. Valid values are:
"disabled" keep registration off
"enabled" manual registration
"auto" keep registration on
The Register() method, if implemented, will fail
with [service].Error.NotAllowed if the value of
this property is "disabled".

View File

@@ -41,6 +41,8 @@ enum ofono_dbus_access_intf {
OFONO_DBUS_ACCESS_INTF_RADIOSETTINGS, /* org.ofono.RadioSettings */ OFONO_DBUS_ACCESS_INTF_RADIOSETTINGS, /* org.ofono.RadioSettings */
OFONO_DBUS_ACCESS_INTF_STK, /* org.ofono.SimToolkit */ OFONO_DBUS_ACCESS_INTF_STK, /* org.ofono.SimToolkit */
OFONO_DBUS_ACCESS_INTF_OEMRAW, /* org.ofono.OemRaw */ OFONO_DBUS_ACCESS_INTF_OEMRAW, /* org.ofono.OemRaw */
/* Since 1.29+git3 */
OFONO_DBUS_ACCESS_INTF_IMS, /* org.ofono.IpMultimediaSystem */
OFONO_DBUS_ACCESS_INTF_COUNT OFONO_DBUS_ACCESS_INTF_COUNT
}; };
@@ -132,6 +134,15 @@ enum ofono_dbus_access_oemraw_method {
OFONO_DBUS_ACCESS_OEMRAW_METHOD_COUNT OFONO_DBUS_ACCESS_OEMRAW_METHOD_COUNT
}; };
/* OFONO_DBUS_ACCESS_INTF_IMS */
enum ofono_dbus_access_ims_method {
/* Since 1.29+git3 */
OFONO_DBUS_ACCESS_IMS_SET_PROPERTY,
OFONO_DBUS_ACCESS_IMS_REGISTER,
OFONO_DBUS_ACCESS_IMS_UNREGISTER,
OFONO_DBUS_ACCESS_IMS_METHOD_COUNT
};
#define OFONO_DBUS_ACCESS_PRIORITY_LOW (-100) #define OFONO_DBUS_ACCESS_PRIORITY_LOW (-100)
#define OFONO_DBUS_ACCESS_PRIORITY_DEFAULT (0) #define OFONO_DBUS_ACCESS_PRIORITY_DEFAULT (0)
#define OFONO_DBUS_ACCESS_PRIORITY_HIGH (100) #define OFONO_DBUS_ACCESS_PRIORITY_HIGH (100)
@@ -159,7 +170,7 @@ const char *ofono_dbus_access_intf_name(enum ofono_dbus_access_intf intf);
const char *ofono_dbus_access_method_name(enum ofono_dbus_access_intf intf, const char *ofono_dbus_access_method_name(enum ofono_dbus_access_intf intf,
int method); int method);
/* Since mer/1.24+git2 */ /* Since 1.24+git2 */
ofono_bool_t ofono_dbus_access_method_allowed(const char *sender, ofono_bool_t ofono_dbus_access_method_allowed(const char *sender,
enum ofono_dbus_access_intf iface, int method, const char *arg); enum ofono_dbus_access_intf iface, int method, const char *arg);

View File

@@ -1,7 +1,7 @@
/* /*
* oFono - Open Source Telephony * oFono - Open Source Telephony
* *
* Copyright (C) 2017-2021 Jolla Ltd. * Copyright (C) 2017-2022 Jolla Ltd.
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License version 2 as
@@ -36,13 +36,15 @@ struct ofono_watch {
const char *spn; const char *spn;
/* OFONO_ATOM_TYPE_NETREG */ /* OFONO_ATOM_TYPE_NETREG */
struct ofono_netreg *netreg; struct ofono_netreg *netreg;
/* Since mer/1.21+git47 */ /* Since 1.21+git47 */
enum ofono_netreg_status reg_status; enum ofono_netreg_status reg_status;
const char *reg_mcc; const char *reg_mcc;
const char *reg_mnc; const char *reg_mnc;
const char *reg_name; const char *reg_name;
/* OFONO_ATOM_TYPE_GPRS */ /* OFONO_ATOM_TYPE_GPRS */
struct ofono_gprs *gprs; struct ofono_gprs *gprs;
/* Since 1.29+git3 */
enum ofono_access_technology reg_tech;
}; };
typedef void (*ofono_watch_cb_t)(struct ofono_watch *w, void *user_data); typedef void (*ofono_watch_cb_t)(struct ofono_watch *w, void *user_data);
@@ -78,7 +80,7 @@ void ofono_watch_remove_handlers(struct ofono_watch *w, unsigned long *ids,
#define ofono_watch_remove_all_handlers(w,ids) \ #define ofono_watch_remove_all_handlers(w,ids) \
ofono_watch_remove_handlers(w, ids, sizeof(ids)/sizeof((ids)[0])) ofono_watch_remove_handlers(w, ids, sizeof(ids)/sizeof((ids)[0]))
/* Since mer/1.21+git47 */ /* Since 1.21+git47 */
unsigned long ofono_watch_add_reg_status_changed_handler(struct ofono_watch *w, unsigned long ofono_watch_add_reg_status_changed_handler(struct ofono_watch *w,
ofono_watch_cb_t cb, void *user_data); ofono_watch_cb_t cb, void *user_data);
unsigned long ofono_watch_add_reg_mcc_changed_handler(struct ofono_watch *w, unsigned long ofono_watch_add_reg_mcc_changed_handler(struct ofono_watch *w,
@@ -93,6 +95,10 @@ unsigned long ofono_watch_add_gprs_settings_changed_handler
(struct ofono_watch *watch, ofono_watch_gprs_settings_cb_t cb, (struct ofono_watch *watch, ofono_watch_gprs_settings_cb_t cb,
void *user_data); void *user_data);
/* Since 1.29+git3 */
unsigned long ofono_watch_add_reg_tech_changed_handler(struct ofono_watch *w,
ofono_watch_cb_t cb, void *user_data);
#endif /* OFONO_WATCH_H */ #endif /* OFONO_WATCH_H */
/* /*

View File

@@ -2,6 +2,7 @@
* oFono - Open Source Telephony * oFono - Open Source Telephony
* *
* Copyright (C) 2011 Intel Corporation. All rights reserved. * Copyright (C) 2011 Intel Corporation. All rights reserved.
* Copyright (C) 2018-2022 Jolla Ltd. All rights reserved.
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License version 2 as
@@ -52,6 +53,11 @@ typedef struct GAtResult GAtResult;
#define HFP_AG_DRIVER "hfp-ag-driver" #define HFP_AG_DRIVER "hfp-ag-driver"
struct watch_fd {
guint id;
int fd;
};
static gboolean hfp_ag_enabled; static gboolean hfp_ag_enabled;
static guint service_watch_id; static guint service_watch_id;
static guint modemwatch_id; static guint modemwatch_id;
@@ -145,11 +151,12 @@ static struct ofono_handsfree_card_driver hfp_ag_driver = {
static void connection_destroy(gpointer data) static void connection_destroy(gpointer data)
{ {
int fd = GPOINTER_TO_INT(data); struct watch_fd *watch = data;
DBG("fd %d", fd); DBG("fd %d", watch->fd);
close(fd); g_source_remove(watch->id);
g_free(watch);
} }
static gboolean io_hup_cb(GIOChannel *io, GIOCondition cond, gpointer data) static gboolean io_hup_cb(GIOChannel *io, GIOCondition cond, gpointer data)
@@ -169,7 +176,8 @@ static DBusMessage *profile_new_connection(DBusConnection *conn,
DBusMessageIter entry; DBusMessageIter entry;
const char *device; const char *device;
GIOChannel *io; GIOChannel *io;
int fd, fd_dup; int fd;
struct watch_fd *watch;
struct sockaddr_rc saddr; struct sockaddr_rc saddr;
socklen_t optlen; socklen_t optlen;
struct ofono_emulator *em; struct ofono_emulator *em;
@@ -252,10 +260,12 @@ static DBusMessage *profile_new_connection(DBusConnection *conn,
emulator = em; emulator = em;
ofono_emulator_register(em, fd); ofono_emulator_register(em, fd);
fd_dup = dup(fd); watch = g_new(struct watch_fd, 1);
io = g_io_channel_unix_new(fd_dup); watch->fd = dup(fd);
g_io_add_watch_full(io, G_PRIORITY_DEFAULT, G_IO_HUP, io_hup_cb, io = g_io_channel_unix_new(watch->fd);
g_strdup(device), g_free); g_io_channel_set_close_on_unref(io, TRUE);
watch->id = g_io_add_watch_full(io, G_PRIORITY_DEFAULT, G_IO_HUP,
io_hup_cb, g_strdup(device), g_free);
g_io_channel_unref(io); g_io_channel_unref(io);
card = ofono_handsfree_card_create(0, card = ofono_handsfree_card_create(0,
@@ -269,8 +279,7 @@ static DBusMessage *profile_new_connection(DBusConnection *conn,
ofono_emulator_set_handsfree_card(em, card); ofono_emulator_set_handsfree_card(em, card);
g_hash_table_insert(connection_hash, g_strdup(device), g_hash_table_insert(connection_hash, g_strdup(device), watch);
GINT_TO_POINTER(fd_dup));
return dbus_message_new_method_return(msg); return dbus_message_new_method_return(msg);
@@ -304,7 +313,7 @@ static DBusMessage *profile_disconnection(DBusConnection *conn,
{ {
DBusMessageIter iter; DBusMessageIter iter;
const char *device; const char *device;
gpointer fd; struct watch_fd *watch;
DBG("Profile handler RequestDisconnection"); DBG("Profile handler RequestDisconnection");
@@ -318,11 +327,11 @@ static DBusMessage *profile_disconnection(DBusConnection *conn,
DBG("%s", device); DBG("%s", device);
fd = g_hash_table_lookup(connection_hash, device); watch = g_hash_table_lookup(connection_hash, device);
if (fd == NULL) if (watch == NULL)
goto invalid; goto invalid;
shutdown(GPOINTER_TO_INT(fd), SHUT_RDWR); shutdown(watch->fd, SHUT_RDWR);
g_hash_table_remove(connection_hash, device); g_hash_table_remove(connection_hash, device);

View File

@@ -46,6 +46,8 @@ const char *ofono_dbus_access_intf_name(enum ofono_dbus_access_intf intf)
return OFONO_STK_INTERFACE; return OFONO_STK_INTERFACE;
case OFONO_DBUS_ACCESS_INTF_OEMRAW: case OFONO_DBUS_ACCESS_INTF_OEMRAW:
return "org.ofono.OemRaw"; return "org.ofono.OemRaw";
case OFONO_DBUS_ACCESS_INTF_IMS:
return OFONO_IMS_INTERFACE;
case OFONO_DBUS_ACCESS_INTF_COUNT: case OFONO_DBUS_ACCESS_INTF_COUNT:
break; break;
} }
@@ -188,6 +190,18 @@ const char *ofono_dbus_access_method_name(enum ofono_dbus_access_intf intf,
break; break;
} }
break; break;
case OFONO_DBUS_ACCESS_INTF_IMS:
switch ((enum ofono_dbus_access_ims_method)method) {
case OFONO_DBUS_ACCESS_IMS_SET_PROPERTY:
return "SetProperty";
case OFONO_DBUS_ACCESS_IMS_REGISTER:
return "Register";
case OFONO_DBUS_ACCESS_IMS_UNREGISTER:
return "Unregister";
case OFONO_DBUS_ACCESS_IMS_METHOD_COUNT:
break;
}
break;
case OFONO_DBUS_ACCESS_INTF_COUNT: case OFONO_DBUS_ACCESS_INTF_COUNT:
break; break;
} }

View File

@@ -36,21 +36,342 @@
#include "ofono.h" #include "ofono.h"
#include "common.h" #include "common.h"
#include "storage.h"
#include "dbus-queue.h"
#define VOICE_CAPABLE_FLAG OFONO_IMS_VOICE_CAPABLE #define VOICE_CAPABLE_FLAG OFONO_IMS_VOICE_CAPABLE
#define SMS_CAPABLE_FLAG OFONO_IMS_SMS_CAPABLE #define SMS_CAPABLE_FLAG OFONO_IMS_SMS_CAPABLE
#define RECHECK_TIMEOUT_SEC (10)
enum ims_reg_strategy {
IMS_REG_DISABLED,
IMS_REG_ENABLED,
IMS_REG_AUTO
#define IMS_REG_DEFAULT IMS_REG_AUTO
};
enum ims_watch_events {
WATCH_EVENT_REG_TECH,
WATCH_EVENT_IMSI,
WATCH_EVENT_COUNT
};
struct ims_call;
struct ofono_ims { struct ofono_ims {
int reg_info; int reg_info;
int ext_info; int ext_info;
const struct ofono_ims_driver *driver; const struct ofono_ims_driver *driver;
void *driver_data; void *driver_data;
struct ofono_atom *atom; struct ofono_atom *atom;
DBusMessage *pending; struct ofono_watch *watch;
struct ofono_dbus_queue *q;
struct ims_call *pending;
struct ims_call *tail;
enum ims_reg_strategy reg_strategy;
gboolean reg_check_pending;
gulong watch_id[WATCH_EVENT_COUNT];
char *imsi;
GKeyFile *settings;
guint recheck_timeout_id;
}; };
/* Calls to the driver are serialized */
typedef void (*ims_cb_t)(void);
typedef void (*ims_submit_cb_t)(struct ims_call *call);
struct ims_call {
struct ims_call *next;
struct ofono_ims *ims;
ims_submit_cb_t submit;
union {
ofono_ims_register_cb_t register_cb;
ofono_ims_status_cb_t status_cb;
ims_cb_t fn;
} cb;
void *data;
};
#define CALLBACK(f) ((ims_cb_t)(f))
#define REGISTRATION_PROP "Registration"
#define SETTINGS_STORE "ims"
#define SETTINGS_GROUP "Settings"
#define REGISTRATION_KEY REGISTRATION_PROP
static GSList *g_drivers = NULL; static GSList *g_drivers = NULL;
static const char *reg_strategy_name[] = { "disabled", "enabled", "auto" };
static gboolean ims_registration_recheck_cb(gpointer user_data);
static gboolean ims_ret_strategy_from_string(const char *str,
enum ims_reg_strategy *value)
{
if (str) {
int i;
for (i = 0; i < G_N_ELEMENTS(reg_strategy_name); i++) {
if (!g_strcmp0(str, reg_strategy_name[i])) {
*value = i;
return TRUE;
}
}
}
return FALSE;
}
static inline gboolean ims_dbus_access_allowed(DBusMessage *msg,
enum ofono_dbus_access_ims_method method)
{
return ofono_dbus_access_method_allowed(dbus_message_get_sender(msg),
OFONO_DBUS_ACCESS_INTF_IMS, method, NULL);
}
static void ims_call_done(struct ims_call *call)
{
struct ofono_ims *ims = call->ims;
ims->pending = call->next;
g_slice_free(struct ims_call, call);
if (ims->pending) {
ims->pending->submit(ims->pending);
} else {
ims->tail = NULL;
}
}
static void ims_call_submit(struct ofono_ims *ims, ims_submit_cb_t submit,
ims_cb_t cb, void *data)
{
struct ims_call *call = g_slice_new0(struct ims_call);
call->ims = ims;
call->submit = submit;
call->cb.fn = cb;
call->data = data;
if (ims->pending) {
ims->tail->next = call;
ims->tail = call;
} else {
ims->pending = ims->tail = call;
submit(call);
}
}
static void ims_call_register_cb(const struct ofono_error *error, void *data)
{
struct ims_call *call = data;
if (call->cb.register_cb)
call->cb.register_cb(error, call->data);
ims_call_done(call);
}
static void ims_call_status_cb(const struct ofono_error *error,
int reg_info, int ext_info,
void *data)
{
struct ims_call *call = data;
if (call->cb.status_cb)
call->cb.status_cb(error, reg_info, ext_info, call->data);
ims_call_done(call);
}
static void ims_call_submit_registration_status(struct ims_call *call)
{
struct ofono_ims *ims = call->ims;
ims->driver->registration_status(ims, ims_call_status_cb, call);
}
static void ims_call_submit_register(struct ims_call *call)
{
struct ofono_ims *ims = call->ims;
ims->driver->ims_register(ims, ims_call_register_cb, call);
}
static void ims_call_submit_unregister(struct ims_call *call)
{
struct ofono_ims *ims = call->ims;
ims->driver->ims_unregister(ims, ims_call_register_cb, call);
}
static void ims_call_registration_status(struct ofono_ims *ims,
ofono_ims_status_cb_t cb, void *data)
{
ims_call_submit(ims, ims_call_submit_registration_status,
CALLBACK(cb), data);
}
static void ims_call_register(struct ofono_ims *ims,
ofono_ims_register_cb_t cb, void *data)
{
ims_call_submit(ims, ims_call_submit_register, CALLBACK(cb), data);
}
static void ims_call_unregister(struct ofono_ims *ims,
ofono_ims_register_cb_t cb, void *data)
{
ims_call_submit(ims, ims_call_submit_unregister, CALLBACK(cb), data);
}
static gboolean ims_supported_reg_tech(struct ofono_ims *ims)
{
return ims->watch &&
ims->watch->reg_tech >= OFONO_ACCESS_TECHNOLOGY_EUTRAN;
}
static void ims_registration_check(struct ofono_ims *ims)
{
if (!ims->reg_check_pending)
return;
ims->reg_check_pending = FALSE;
if (ims->recheck_timeout_id) {
g_source_remove(ims->recheck_timeout_id);
ims->recheck_timeout_id = 0;
}
DBG("checking ims state");
switch (ims->reg_strategy) {
case IMS_REG_DISABLED:
/* Keep registration off */
if (ims->reg_info && ims->driver &&
ims->driver->ims_unregister) {
DBG("auto-unregistering");
ims_call_unregister(ims, NULL, NULL);
ims->recheck_timeout_id =
g_timeout_add_seconds(RECHECK_TIMEOUT_SEC,
ims_registration_recheck_cb, ims);
} else {
DBG("ims is disabled, leaving it unregistered");
}
return;
case IMS_REG_ENABLED:
/* Any state is acceptable */
DBG("ims is enabled, no action needed");
return;
case IMS_REG_AUTO:
break;
}
/* Keep registration on (default behavior) */
if (!ims->reg_info && ims_supported_reg_tech(ims) &&
ims->driver && ims->driver->ims_register) {
DBG("auto-registering");
ims_call_register(ims, NULL, NULL);
ims->recheck_timeout_id =
g_timeout_add_seconds(RECHECK_TIMEOUT_SEC,
ims_registration_recheck_cb, ims);
} else {
DBG("leaving ims registered");
}
}
static gboolean ims_registration_recheck_cb(gpointer user_data)
{
struct ofono_ims *ims = user_data;
ims->recheck_timeout_id = 0;
ims_registration_check(ims);
return G_SOURCE_REMOVE;
}
static void ims_reg_tech_changed(struct ofono_watch *watch, void *data)
{
struct ofono_ims *ims = data;
ims->reg_check_pending = TRUE;
ims_registration_check(ims);
}
static void ims_set_reg_strategy(struct ofono_ims *ims,
enum ims_reg_strategy value)
{
if (ims->reg_strategy != value) {
const char *path = __ofono_atom_get_path(ims->atom);
DBusConnection *conn = ofono_dbus_get_connection();
DBG("ims %s", reg_strategy_name[value]);
ims->reg_strategy = value;
ims->reg_check_pending = TRUE;
if (ims->settings) {
g_key_file_set_string(ims->settings, SETTINGS_GROUP,
REGISTRATION_KEY, reg_strategy_name[value]);
storage_sync(ims->imsi, SETTINGS_STORE, ims->settings);
}
ofono_dbus_signal_property_changed(conn, path,
OFONO_IMS_INTERFACE,
REGISTRATION_PROP, DBUS_TYPE_STRING,
reg_strategy_name + ims->reg_strategy);
}
}
static gboolean ims_imsi_check(struct ofono_ims *ims)
{
const char* imsi = ims->watch ? ims->watch->imsi : NULL;
if (g_strcmp0(ims->imsi, imsi)) {
if (ims->imsi) {
storage_close(ims->imsi, SETTINGS_STORE,
ims->settings, TRUE);
g_free(ims->imsi);
}
if (imsi) {
ims->settings = storage_open(imsi, SETTINGS_STORE);
ims->imsi = g_strdup(imsi);
} else {
ims->settings = NULL;
ims->imsi = NULL;
}
return TRUE;
}
return FALSE;
}
static void ims_apply_settings(struct ofono_ims *ims)
{
char* str;
if (!ims->settings)
return;
str = g_key_file_get_string(ims->settings, SETTINGS_GROUP,
REGISTRATION_KEY, NULL);
if (str) {
enum ims_reg_strategy ims_reg = IMS_REG_DEFAULT;
if (ims_ret_strategy_from_string(str, &ims_reg))
ims_set_reg_strategy(ims, ims_reg);
g_free(str);
}
}
static void ims_imsi_changed(struct ofono_watch *watch, void *data)
{
struct ofono_ims *ims = data;
if (ims_imsi_check(ims)) {
ims_apply_settings(ims);
ims_registration_check(ims);
}
}
static DBusMessage *ims_get_properties(DBusConnection *conn, static DBusMessage *ims_get_properties(DBusConnection *conn,
DBusMessage *msg, void *data) DBusMessage *msg, void *data)
{ {
@@ -72,6 +393,8 @@ static DBusMessage *ims_get_properties(DBusConnection *conn,
value = ims->reg_info ? TRUE : FALSE; value = ims->reg_info ? TRUE : FALSE;
ofono_dbus_dict_append(&dict, "Registered", DBUS_TYPE_BOOLEAN, &value); ofono_dbus_dict_append(&dict, "Registered", DBUS_TYPE_BOOLEAN, &value);
ofono_dbus_dict_append(&dict, REGISTRATION_PROP, DBUS_TYPE_STRING,
reg_strategy_name + ims->reg_strategy);
if (ims->ext_info != -1) { if (ims->ext_info != -1) {
value = ims->ext_info & VOICE_CAPABLE_FLAG ? TRUE : FALSE; value = ims->ext_info & VOICE_CAPABLE_FLAG ? TRUE : FALSE;
@@ -88,6 +411,50 @@ static DBusMessage *ims_get_properties(DBusConnection *conn,
return reply; return reply;
} }
static DBusMessage *ims_set_property(DBusConnection *conn,
DBusMessage *msg, void *data)
{
struct ofono_ims *ims = data;
DBusMessageIter iter;
DBusMessageIter var;
const char *property;
if (!ims_dbus_access_allowed(msg, OFONO_DBUS_ACCESS_IMS_SET_PROPERTY))
return __ofono_error_access_denied(msg);
if (!dbus_message_iter_init(msg, &iter))
return __ofono_error_invalid_args(msg);
if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
return __ofono_error_invalid_args(msg);
dbus_message_iter_get_basic(&iter, &property);
dbus_message_iter_next(&iter);
if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
return __ofono_error_invalid_args(msg);
dbus_message_iter_recurse(&iter, &var);
if (!g_strcmp0(property, REGISTRATION_PROP)) {
const char *str = NULL;
enum ims_reg_strategy value = IMS_REG_DEFAULT;
if (dbus_message_iter_get_arg_type(&var) != DBUS_TYPE_STRING)
return __ofono_error_invalid_args(msg);
dbus_message_iter_get_basic(&var, &str);
if (ims_ret_strategy_from_string(str, &value)) {
ims_set_reg_strategy(ims, value);
ims_registration_check(ims);
return dbus_message_new_method_return(msg);
}
}
return __ofono_error_invalid_args(msg);
}
static void ims_set_sms_capable(struct ofono_ims *ims, ofono_bool_t status) static void ims_set_sms_capable(struct ofono_ims *ims, ofono_bool_t status)
{ {
const char *path = __ofono_atom_get_path(ims->atom); const char *path = __ofono_atom_get_path(ims->atom);
@@ -155,6 +522,7 @@ void ofono_ims_status_notify(struct ofono_ims *ims, int reg_info, int ext_info)
if (ims->ext_info == ext_info && ims->reg_info == reg_info) if (ims->ext_info == ext_info && ims->reg_info == reg_info)
return; return;
ims->reg_check_pending = TRUE;
new_reg_info = reg_info ? TRUE : FALSE; new_reg_info = reg_info ? TRUE : FALSE;
ims_set_registered(ims, new_reg_info); ims_set_registered(ims, new_reg_info);
@@ -170,38 +538,26 @@ void ofono_ims_status_notify(struct ofono_ims *ims, int reg_info, int ext_info)
skip: skip:
ims->reg_info = reg_info; ims->reg_info = reg_info;
ims->ext_info = ext_info; ims->ext_info = ext_info;
} ims_registration_check(ims);
static void registration_status_cb(const struct ofono_error *error,
int reg_info, int ext_info,
void *data)
{
struct ofono_ims *ims = data;
if (error->type != OFONO_ERROR_TYPE_NO_ERROR) {
DBG("Error during IMS registration/unregistration");
return;
}
ofono_ims_status_notify(ims, reg_info, ext_info);
} }
static void register_cb(const struct ofono_error *error, void *data) static void register_cb(const struct ofono_error *error, void *data)
{ {
struct ofono_ims *ims = data; struct ofono_ims *ims = data;
DBusMessage *reply;
if (error->type == OFONO_ERROR_TYPE_NO_ERROR) if (error->type == OFONO_ERROR_TYPE_NO_ERROR)
reply = dbus_message_new_method_return(ims->pending); __ofono_dbus_queue_reply_ok(ims->q);
else else
reply = __ofono_error_failed(ims->pending); __ofono_dbus_queue_reply_failed(ims->q);
}
__ofono_dbus_pending_reply(&ims->pending, reply); static DBusMessage *ofono_ims_register_fn(DBusMessage *msg, void *data)
{
struct ofono_ims *ims = data;
if (ims->driver->registration_status == NULL) ims_call_register(ims, register_cb, ims);
return;
ims->driver->registration_status(ims, registration_status_cb, ims); return NULL;
} }
static DBusMessage *ofono_ims_send_register(DBusConnection *conn, static DBusMessage *ofono_ims_send_register(DBusConnection *conn,
@@ -209,15 +565,25 @@ static DBusMessage *ofono_ims_send_register(DBusConnection *conn,
{ {
struct ofono_ims *ims = data; struct ofono_ims *ims = data;
if (ims->pending) if (!ims_dbus_access_allowed(msg, OFONO_DBUS_ACCESS_IMS_REGISTER))
return __ofono_error_busy(msg); return __ofono_error_access_denied(msg);
if (ims->driver->ims_register == NULL) if (!ims->driver || !ims->driver->ims_register)
return __ofono_error_not_implemented(msg); return __ofono_error_not_implemented(msg);
ims->pending = dbus_message_ref(msg); if (ims->reg_strategy == IMS_REG_DISABLED)
return __ofono_error_not_allowed(msg);
ims->driver->ims_register(ims, register_cb, ims); __ofono_dbus_queue_request(ims->q, ofono_ims_register_fn, msg, ims);
return NULL;
}
static DBusMessage *ofono_ims_unregister_fn(DBusMessage *msg, void *data)
{
struct ofono_ims *ims = data;
ims_call_unregister(ims, register_cb, ims);
return NULL; return NULL;
} }
@@ -227,15 +593,13 @@ static DBusMessage *ofono_ims_unregister(DBusConnection *conn,
{ {
struct ofono_ims *ims = data; struct ofono_ims *ims = data;
if (ims->pending) if (!ims_dbus_access_allowed(msg, OFONO_DBUS_ACCESS_IMS_UNREGISTER))
return __ofono_error_busy(msg); return __ofono_error_access_denied(msg);
if (ims->driver->ims_unregister == NULL) if (!ims->driver || !ims->driver->ims_unregister)
return __ofono_error_not_implemented(msg); return __ofono_error_not_implemented(msg);
ims->pending = dbus_message_ref(msg); __ofono_dbus_queue_request(ims->q, ofono_ims_unregister_fn, msg, ims);
ims->driver->ims_unregister(ims, register_cb, ims);
return NULL; return NULL;
} }
@@ -244,6 +608,9 @@ static const GDBusMethodTable ims_methods[] = {
{ GDBUS_METHOD("GetProperties", { GDBUS_METHOD("GetProperties",
NULL, GDBUS_ARGS({ "properties", "a{sv}" }), NULL, GDBUS_ARGS({ "properties", "a{sv}" }),
ims_get_properties) }, ims_get_properties) },
{ GDBUS_METHOD("SetProperty",
GDBUS_ARGS({ "property", "s" }, { "value", "v" }),
NULL, ims_set_property) },
{ GDBUS_ASYNC_METHOD("Register", NULL, NULL, { GDBUS_ASYNC_METHOD("Register", NULL, NULL,
ofono_ims_send_register) }, ofono_ims_send_register) },
{ GDBUS_ASYNC_METHOD("Unregister", NULL, NULL, { GDBUS_ASYNC_METHOD("Unregister", NULL, NULL,
@@ -269,6 +636,25 @@ static void ims_atom_remove(struct ofono_atom *atom)
if (ims->driver && ims->driver->remove) if (ims->driver && ims->driver->remove)
ims->driver->remove(ims); ims->driver->remove(ims);
while (ims->pending) {
struct ims_call *call = ims->pending;
ims->pending = call->next;
g_slice_free(struct ims_call, call);
}
if (ims->imsi) {
storage_close(ims->imsi, SETTINGS_STORE, ims->settings, TRUE);
g_free(ims->imsi);
}
if (ims->recheck_timeout_id) {
g_source_remove(ims->recheck_timeout_id);
}
__ofono_dbus_queue_free(ims->q);
ofono_watch_remove_all_handlers(ims->watch, ims->watch_id);
ofono_watch_unref(ims->watch);
g_free(ims); g_free(ims);
} }
@@ -291,6 +677,9 @@ struct ofono_ims *ofono_ims_create(struct ofono_modem *modem,
ims->reg_info = 0; ims->reg_info = 0;
ims->ext_info = -1; ims->ext_info = -1;
ims->reg_strategy = IMS_REG_DEFAULT;
ims->reg_check_pending = TRUE;
ims->q = __ofono_dbus_queue_new();
for (l = g_drivers; l; l = l->next) { for (l = g_drivers; l; l = l->next) {
const struct ofono_ims_driver *drv = l->data; const struct ofono_ims_driver *drv = l->data;
@@ -354,8 +743,21 @@ static void ofono_ims_finish_register(struct ofono_ims *ims)
return; return;
} }
ims->watch = ofono_watch_new(path);
ims->watch_id[WATCH_EVENT_REG_TECH] =
ofono_watch_add_reg_tech_changed_handler(ims->watch,
ims_reg_tech_changed, ims);
ims->watch_id[WATCH_EVENT_IMSI] =
ofono_watch_add_imsi_changed_handler(ims->watch,
ims_imsi_changed, ims);
ofono_modem_add_interface(modem, OFONO_IMS_INTERFACE); ofono_modem_add_interface(modem, OFONO_IMS_INTERFACE);
__ofono_atom_register(ims->atom, ims_atom_unregister); __ofono_atom_register(ims->atom, ims_atom_unregister);
ims->reg_check_pending = TRUE;
ims_imsi_check(ims);
ims_apply_settings(ims);
ims_registration_check(ims);
} }
static void registration_init_cb(const struct ofono_error *error, static void registration_init_cb(const struct ofono_error *error,
@@ -374,12 +776,12 @@ static void registration_init_cb(const struct ofono_error *error,
void ofono_ims_register(struct ofono_ims *ims) void ofono_ims_register(struct ofono_ims *ims)
{ {
if (!ims->driver->registration_status) { if (!ims->driver || !ims->driver->registration_status) {
ofono_ims_finish_register(ims); ofono_ims_finish_register(ims);
return; return;
} }
ims->driver->registration_status(ims, registration_init_cb, ims); ims_call_registration_status(ims, registration_init_cb, ims);
} }
void ofono_ims_remove(struct ofono_ims *ims) void ofono_ims_remove(struct ofono_ims *ims)

View File

@@ -1,7 +1,7 @@
/* /*
* oFono - Open Source Telephony * oFono - Open Source Telephony
* *
* Copyright (C) 2017-2021 Jolla Ltd. * Copyright (C) 2017-2022 Jolla Ltd.
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License version 2 as
@@ -41,6 +41,7 @@ struct ofono_watch_object {
guint imsi_watch_id; guint imsi_watch_id;
guint spn_watch_id; guint spn_watch_id;
guint netreg_watch_id; guint netreg_watch_id;
guint netreg_status_watch_id;
guint gprs_watch_id; guint gprs_watch_id;
}; };
@@ -67,6 +68,7 @@ enum ofono_watch_signal {
SIGNAL_REG_MCC_CHANGED, SIGNAL_REG_MCC_CHANGED,
SIGNAL_REG_MNC_CHANGED, SIGNAL_REG_MNC_CHANGED,
SIGNAL_REG_NAME_CHANGED, SIGNAL_REG_NAME_CHANGED,
SIGNAL_REG_TECH_CHANGED,
SIGNAL_GPRS_CHANGED, SIGNAL_GPRS_CHANGED,
SIGNAL_GPRS_SETTINGS_CHANGED, SIGNAL_GPRS_SETTINGS_CHANGED,
SIGNAL_COUNT SIGNAL_COUNT
@@ -84,6 +86,7 @@ enum ofono_watch_signal {
#define SIGNAL_REG_MCC_CHANGED_NAME "ofono-watch-reg-mcc-changed" #define SIGNAL_REG_MCC_CHANGED_NAME "ofono-watch-reg-mcc-changed"
#define SIGNAL_REG_MNC_CHANGED_NAME "ofono-watch-reg-mnc-changed" #define SIGNAL_REG_MNC_CHANGED_NAME "ofono-watch-reg-mnc-changed"
#define SIGNAL_REG_NAME_CHANGED_NAME "ofono-watch-reg-name-changed" #define SIGNAL_REG_NAME_CHANGED_NAME "ofono-watch-reg-name-changed"
#define SIGNAL_REG_TECH_CHANGED_NAME "ofono-watch-reg-tech-changed"
#define SIGNAL_GPRS_CHANGED_NAME "ofono-watch-gprs-changed" #define SIGNAL_GPRS_CHANGED_NAME "ofono-watch-gprs-changed"
#define SIGNAL_GPRS_SETTINGS_CHANGED_NAME "ofono-watch-gprs-settings-changed" #define SIGNAL_GPRS_SETTINGS_CHANGED_NAME "ofono-watch-gprs-settings-changed"
@@ -134,11 +137,13 @@ static void ofono_watch_emit_queued_signals(struct ofono_watch_object *self)
{ {
int i; int i;
g_object_ref(self);
for (i = 0; self->queued_signals && i < SIGNAL_COUNT; i++) { for (i = 0; self->queued_signals && i < SIGNAL_COUNT; i++) {
if (self->queued_signals & ofono_watch_signal_bit(i)) { if (self->queued_signals & ofono_watch_signal_bit(i)) {
ofono_watch_signal_emit(self, i); ofono_watch_signal_emit(self, i);
} }
} }
g_object_unref(self);
} }
static void ofono_watch_iccid_update(struct ofono_watch_object *self, static void ofono_watch_iccid_update(struct ofono_watch_object *self,
@@ -349,6 +354,7 @@ static void ofono_watch_netreg_update(struct ofono_watch_object *self)
struct ofono_watch *watch = &self->pub; struct ofono_watch *watch = &self->pub;
struct ofono_netreg *netreg = watch->netreg; struct ofono_netreg *netreg = watch->netreg;
enum ofono_netreg_status status = ofono_netreg_get_status(netreg); enum ofono_netreg_status status = ofono_netreg_get_status(netreg);
enum ofono_access_technology act = ofono_netreg_get_technology(netreg);
const char *mcc = ofono_netreg_get_mcc(netreg); const char *mcc = ofono_netreg_get_mcc(netreg);
const char *mnc = ofono_netreg_get_mnc(netreg); const char *mnc = ofono_netreg_get_mnc(netreg);
const char *name = ofono_netreg_get_name(netreg); const char *name = ofono_netreg_get_name(netreg);
@@ -357,6 +363,10 @@ static void ofono_watch_netreg_update(struct ofono_watch_object *self)
watch->reg_status = status; watch->reg_status = status;
ofono_watch_signal_queue(self, SIGNAL_REG_STATUS_CHANGED); ofono_watch_signal_queue(self, SIGNAL_REG_STATUS_CHANGED);
} }
if (watch->reg_tech != act) {
watch->reg_tech = act;
ofono_watch_signal_queue(self, SIGNAL_REG_TECH_CHANGED);
}
if (g_strcmp0(self->reg_mcc, mcc)) { if (g_strcmp0(self->reg_mcc, mcc)) {
g_free(self->reg_mcc); g_free(self->reg_mcc);
watch->reg_mcc = self->reg_mcc = g_strdup(mcc); watch->reg_mcc = self->reg_mcc = g_strdup(mcc);
@@ -374,17 +384,49 @@ static void ofono_watch_netreg_update(struct ofono_watch_object *self)
} }
} }
static void ofono_watch_netreg_status_notify(int status, int lac, int ci,
int tech, const char *mcc, const char *mnc, void *user_data)
{
struct ofono_watch_object *self = OFONO_WATCH_OBJECT(user_data);
ofono_watch_netreg_update(self);
ofono_watch_emit_queued_signals(self);
}
static void ofono_watch_netreg_status_destroy(void *user_data)
{
struct ofono_watch_object *self = OFONO_WATCH_OBJECT(user_data);
ASSERT(self->netreg_status_watch_id);
self->netreg_status_watch_id = 0;
}
static void ofono_watch_set_netreg(struct ofono_watch_object *self, static void ofono_watch_set_netreg(struct ofono_watch_object *self,
struct ofono_netreg *netreg) struct ofono_netreg *netreg)
{ {
struct ofono_watch *watch = &self->pub; struct ofono_watch *watch = &self->pub;
if (watch->netreg != netreg) { if (watch->netreg != netreg) {
if (self->netreg_status_watch_id) {
__ofono_netreg_remove_status_watch(watch->netreg,
self->netreg_status_watch_id);
/* The destroy callback clears it */
ASSERT(!self->netreg_status_watch_id);
}
watch->netreg = netreg; watch->netreg = netreg;
ofono_watch_signal_queue(self, SIGNAL_NETREG_CHANGED); ofono_watch_signal_queue(self, SIGNAL_NETREG_CHANGED);
if (netreg) {
self->netreg_status_watch_id =
__ofono_netreg_add_status_watch(netreg,
ofono_watch_netreg_status_notify, self,
ofono_watch_netreg_status_destroy);
}
ofono_watch_netreg_update(self);
ofono_watch_emit_queued_signals(self);
} }
ofono_watch_netreg_update(self);
ofono_watch_emit_queued_signals(self);
} }
static void ofono_watch_netreg_notify(struct ofono_atom *atom, static void ofono_watch_netreg_notify(struct ofono_atom *atom,
@@ -417,6 +459,7 @@ static void ofono_watch_set_gprs(struct ofono_watch_object *self,
if (watch->gprs != gprs) { if (watch->gprs != gprs) {
watch->gprs = gprs; watch->gprs = gprs;
ofono_watch_signal_queue(self, SIGNAL_GPRS_CHANGED); ofono_watch_signal_queue(self, SIGNAL_GPRS_CHANGED);
ofono_watch_emit_queued_signals(self); ofono_watch_emit_queued_signals(self);
} }
@@ -730,6 +773,7 @@ ADD_SIGNAL_HANDLER_PROC(reg_status,REG_STATUS)
ADD_SIGNAL_HANDLER_PROC(reg_mcc,REG_MCC) ADD_SIGNAL_HANDLER_PROC(reg_mcc,REG_MCC)
ADD_SIGNAL_HANDLER_PROC(reg_mnc,REG_MNC) ADD_SIGNAL_HANDLER_PROC(reg_mnc,REG_MNC)
ADD_SIGNAL_HANDLER_PROC(reg_name,REG_NAME) ADD_SIGNAL_HANDLER_PROC(reg_name,REG_NAME)
ADD_SIGNAL_HANDLER_PROC(reg_tech,REG_TECH)
ADD_SIGNAL_HANDLER_PROC(gprs,GPRS) ADD_SIGNAL_HANDLER_PROC(gprs,GPRS)
static void ofono_watch_gprs_settings_signal_cb(struct ofono_watch_object *src, static void ofono_watch_gprs_settings_signal_cb(struct ofono_watch_object *src,
@@ -775,21 +819,6 @@ void ofono_watch_remove_handlers(struct ofono_watch *watch, unsigned long *ids,
} }
} }
void __ofono_watch_netreg_changed(const char *path)
{
if (path && ofono_watch_table) {
struct ofono_watch_object *self =
g_hash_table_lookup(ofono_watch_table, path);
if (self) {
g_object_ref(self);
ofono_watch_netreg_update(self);
ofono_watch_emit_queued_signals(self);
g_object_unref(self);
}
}
}
void __ofono_watch_gprs_settings_changed(const char *path, void __ofono_watch_gprs_settings_changed(const char *path,
enum ofono_gprs_context_type type, enum ofono_gprs_context_type type,
const struct ofono_gprs_primary_context *settings) const struct ofono_gprs_primary_context *settings)
@@ -813,6 +842,7 @@ static void ofono_watch_object_init(struct ofono_watch_object *self)
struct ofono_watch *watch = &self->pub; struct ofono_watch *watch = &self->pub;
watch->reg_status = OFONO_NETREG_STATUS_NONE; watch->reg_status = OFONO_NETREG_STATUS_NONE;
watch->reg_tech = OFONO_ACCESS_TECHNOLOGY_NONE;
} }
static void ofono_watch_object_finalize(GObject *object) static void ofono_watch_object_finalize(GObject *object)
@@ -847,6 +877,7 @@ static void ofono_watch_object_class_init(OfonoWatchObjectClass *klass)
NEW_SIGNAL(klass, REG_MCC); NEW_SIGNAL(klass, REG_MCC);
NEW_SIGNAL(klass, REG_MNC); NEW_SIGNAL(klass, REG_MNC);
NEW_SIGNAL(klass, REG_NAME); NEW_SIGNAL(klass, REG_NAME);
NEW_SIGNAL(klass, REG_TECH);
NEW_SIGNAL(klass, GPRS); NEW_SIGNAL(klass, GPRS);
ofono_watch_signals[SIGNAL_GPRS_SETTINGS_CHANGED] = ofono_watch_signals[SIGNAL_GPRS_SETTINGS_CHANGED] =
g_signal_new(SIGNAL_GPRS_SETTINGS_CHANGED_NAME, g_signal_new(SIGNAL_GPRS_SETTINGS_CHANGED_NAME,

View File

@@ -1,7 +1,7 @@
/* /*
* oFono - Open Source Telephony * oFono - Open Source Telephony
* *
* Copyright (C) 2019 Jolla Ltd. * Copyright (C) 2019-2022 Jolla Ltd.
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License version 2 as
@@ -18,7 +18,6 @@
#include <ofono/watch.h> #include <ofono/watch.h>
void __ofono_watch_netreg_changed(const char *path);
void __ofono_watch_gprs_settings_changed(const char *path, void __ofono_watch_gprs_settings_changed(const char *path,
enum ofono_gprs_context_type type, enum ofono_gprs_context_type type,
const struct ofono_gprs_primary_context *settings); const struct ofono_gprs_primary_context *settings);

View File

@@ -1,7 +1,7 @@
/* /*
* oFono - Open Source Telephony * oFono - Open Source Telephony
* *
* Copyright (C) 2019-2021 Jolla Ltd. * Copyright (C) 2019-2022 Jolla Ltd.
* Copyright (C) 2020 Open Mobile Platform LLC. * Copyright (C) 2020 Open Mobile Platform LLC.
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
@@ -122,6 +122,9 @@ static const struct test_method_name_data method_name_tests[] = {
},{ },{
OFONO_DBUS_ACCESS_INTF_OEMRAW, OFONO_DBUS_ACCESS_INTF_OEMRAW,
OFONO_DBUS_ACCESS_OEMRAW_METHOD_COUNT OFONO_DBUS_ACCESS_OEMRAW_METHOD_COUNT
},{
OFONO_DBUS_ACCESS_INTF_IMS,
OFONO_DBUS_ACCESS_IMS_METHOD_COUNT
} }
}; };

View File

@@ -1,7 +1,7 @@
/* /*
* oFono - Open Source Telephony * oFono - Open Source Telephony
* *
* Copyright (C) 2018-2019 Jolla Ltd. * Copyright (C) 2018-2022 Jolla Ltd.
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License version 2 as
@@ -57,17 +57,25 @@ struct ofono_gprs {
struct ofono_netreg { struct ofono_netreg {
struct ofono_atom atom; struct ofono_atom atom;
struct ofono_watchlist *status_watches;
enum ofono_netreg_status status; enum ofono_netreg_status status;
enum ofono_access_technology tech;
const char *mcc; const char *mcc;
const char *mnc; const char *mnc;
const char *name; const char *name;
}; };
int ofono_netreg_get_status(struct ofono_netreg *netreg) enum ofono_netreg_status ofono_netreg_get_status(struct ofono_netreg *netreg)
{ {
return netreg ? netreg->status : OFONO_NETREG_STATUS_NONE; return netreg ? netreg->status : OFONO_NETREG_STATUS_NONE;
} }
enum ofono_access_technology
ofono_netreg_get_technology (struct ofono_netreg *netreg)
{
return netreg ? netreg->tech : OFONO_ACCESS_TECHNOLOGY_NONE;
}
const char *ofono_netreg_get_mcc(struct ofono_netreg *netreg) const char *ofono_netreg_get_mcc(struct ofono_netreg *netreg)
{ {
return netreg ? netreg->mcc : NULL; return netreg ? netreg->mcc : NULL;
@@ -83,6 +91,44 @@ const char *ofono_netreg_get_name(struct ofono_netreg *netreg)
return netreg ? netreg->name : NULL; return netreg ? netreg->name : NULL;
} }
static void netreg_notify(struct ofono_netreg *netreg)
{
GSList *l;
for (l = netreg->status_watches->items; l; l = l->next) {
struct ofono_watchlist_item *item = l->data;
ofono_netreg_status_notify_cb_t notify = item->notify;
notify(netreg->status, -1, -1, netreg->tech, netreg->mcc,
netreg->mnc, item->notify_data);
}
}
static unsigned int add_watch_item(struct ofono_watchlist *list,
void *notify, void *data, ofono_destroy_func destroy)
{
struct ofono_watchlist_item *watch =
g_new0(struct ofono_watchlist_item, 1);
watch->notify = notify;
watch->destroy = destroy;
watch->notify_data = data;
return __ofono_watchlist_add_item(list, watch);
}
unsigned int __ofono_netreg_add_status_watch(struct ofono_netreg *netreg,
ofono_netreg_status_notify_cb_t notify,
void *data, ofono_destroy_func destroy)
{
return add_watch_item(netreg->status_watches, notify, data, destroy);
}
gboolean __ofono_netreg_remove_status_watch(struct ofono_netreg *netreg,
unsigned int id)
{
return __ofono_watchlist_remove_item(netreg->status_watches, id);
}
/* Fake ofono_sim */ /* Fake ofono_sim */
struct ofono_sim { struct ofono_sim {
@@ -98,18 +144,6 @@ struct ofono_sim {
struct ofono_watchlist *state_watches; struct ofono_watchlist *state_watches;
}; };
static unsigned int add_watch_item(struct ofono_watchlist *list,
void *notify, void *data, ofono_destroy_func destroy)
{
struct ofono_watchlist_item *watch =
g_new0(struct ofono_watchlist_item, 1);
watch->notify = notify;
watch->destroy = destroy;
watch->notify_data = data;
return __ofono_watchlist_add_item(list, watch);
}
unsigned int ofono_sim_add_iccid_watch(struct ofono_sim *sim, unsigned int ofono_sim_add_iccid_watch(struct ofono_sim *sim,
ofono_sim_iccid_event_cb_t cb, void *data, ofono_sim_iccid_event_cb_t cb, void *data,
ofono_destroy_func destroy) ofono_destroy_func destroy)
@@ -342,7 +376,7 @@ unsigned int __ofono_modem_add_atom_watch(struct ofono_modem *modem,
return id; return id;
} }
static void call_watches(struct ofono_atom *atom, static void atom_notify(struct ofono_atom *atom,
enum ofono_atom_watch_condition cond) enum ofono_atom_watch_condition cond)
{ {
GSList *l; GSList *l;
@@ -400,7 +434,7 @@ static void test_modem_register_atom(struct ofono_modem *modem,
if (!atom->registered) { if (!atom->registered) {
atom->registered = TRUE; atom->registered = TRUE;
modem->atoms = g_slist_append(modem->atoms, atom); modem->atoms = g_slist_append(modem->atoms, atom);
call_watches(atom, OFONO_ATOM_WATCH_CONDITION_REGISTERED); atom_notify(atom, OFONO_ATOM_WATCH_CONDITION_REGISTERED);
} }
} }
@@ -409,7 +443,7 @@ static void test_modem_unregister_atom(struct ofono_modem *modem,
{ {
if (atom->registered) { if (atom->registered) {
atom->registered = FALSE; atom->registered = FALSE;
call_watches(atom, OFONO_ATOM_WATCH_CONDITION_UNREGISTERED); atom_notify(atom, OFONO_ATOM_WATCH_CONDITION_UNREGISTERED);
modem->atoms = g_slist_remove(modem->atoms, atom); modem->atoms = g_slist_remove(modem->atoms, atom);
} }
} }
@@ -428,6 +462,9 @@ static void test_modem_init1(struct ofono_modem *modem, const char *path)
netreg->atom.type = OFONO_ATOM_TYPE_NETREG; netreg->atom.type = OFONO_ATOM_TYPE_NETREG;
netreg->atom.modem = modem; netreg->atom.modem = modem;
netreg->atom.data = netreg; netreg->atom.data = netreg;
netreg->status = OFONO_NETREG_STATUS_NOT_REGISTERED;
netreg->tech = OFONO_ACCESS_TECHNOLOGY_NONE;
netreg->status_watches = __ofono_watchlist_new(g_free);
gprs->atom.type = OFONO_ATOM_TYPE_GPRS; gprs->atom.type = OFONO_ATOM_TYPE_GPRS;
gprs->atom.modem = modem; gprs->atom.modem = modem;
@@ -455,15 +492,17 @@ static void test_modem_init(struct ofono_modem *modem)
static void test_modem_shutdown(struct ofono_modem *modem) static void test_modem_shutdown(struct ofono_modem *modem)
{ {
struct ofono_sim *sim = &modem->sim; struct ofono_sim *sim = &modem->sim;
struct ofono_netreg *netreg = &modem->netreg;
call_modemwatches(modem, FALSE); call_modemwatches(modem, FALSE);
g_modem_list = g_slist_remove(g_modem_list, modem); g_modem_list = g_slist_remove(g_modem_list, modem);
g_slist_free(modem->atoms); g_slist_free(modem->atoms);
__ofono_watchlist_free(sim->iccid_watches); __ofono_watchlist_free(sim->iccid_watches);
__ofono_watchlist_free(sim->imsi_watches); __ofono_watchlist_free(sim->imsi_watches);
__ofono_watchlist_free(sim->state_watches); __ofono_watchlist_free(sim->state_watches);
__ofono_watchlist_free(sim->spn_watches); __ofono_watchlist_free(sim->spn_watches);
__ofono_watchlist_free(netreg->status_watches);
__ofono_watchlist_free(modem->atom_watches); __ofono_watchlist_free(modem->atom_watches);
__ofono_watchlist_free(modem->online_watches); __ofono_watchlist_free(modem->online_watches);
} }
@@ -504,8 +543,6 @@ static void test_basic(void)
NULL, NULL)); NULL, NULL));
ofono_watch_remove_handler(NULL, 0); ofono_watch_remove_handler(NULL, 0);
ofono_watch_remove_handlers(NULL, NULL, 0); ofono_watch_remove_handlers(NULL, NULL, 0);
__ofono_watch_netreg_changed(NULL);
__ofono_watch_netreg_changed(TEST_PATH);
__ofono_watch_gprs_settings_changed __ofono_watch_gprs_settings_changed
(NULL, OFONO_GPRS_CONTEXT_TYPE_ANY, NULL); (NULL, OFONO_GPRS_CONTEXT_TYPE_ANY, NULL);
__ofono_watch_gprs_settings_changed __ofono_watch_gprs_settings_changed
@@ -623,7 +660,7 @@ static void test_netreg(void)
struct ofono_watch *watch; struct ofono_watch *watch;
struct ofono_modem modem; struct ofono_modem modem;
struct ofono_netreg *netreg = &modem.netreg; struct ofono_netreg *netreg = &modem.netreg;
gulong id[5]; gulong id[6];
int n[G_N_ELEMENTS(id)]; int n[G_N_ELEMENTS(id)];
#define NETREG 0 #define NETREG 0
@@ -631,8 +668,7 @@ static void test_netreg(void)
#define REG_MCC 2 #define REG_MCC 2
#define REG_MNC 3 #define REG_MNC 3
#define REG_NAME 4 #define REG_NAME 4
#define REG_TECH 5
__ofono_watch_netreg_changed(TEST_PATH); /* No effect (yet) */
memset(&modem, 0, sizeof(modem)); memset(&modem, 0, sizeof(modem));
__ofono_modemwatch_init(); __ofono_modemwatch_init();
@@ -652,16 +688,20 @@ static void test_netreg(void)
(watch, test_inc_cb, n + REG_MNC); (watch, test_inc_cb, n + REG_MNC);
id[REG_NAME] = ofono_watch_add_reg_name_changed_handler id[REG_NAME] = ofono_watch_add_reg_name_changed_handler
(watch, test_inc_cb, n + REG_NAME); (watch, test_inc_cb, n + REG_NAME);
id[REG_TECH] = ofono_watch_add_reg_tech_changed_handler
(watch, test_inc_cb, n + REG_TECH);
test_modem_register_atom(&modem, &netreg->atom); test_modem_register_atom(&modem, &netreg->atom);
g_assert(watch->netreg == netreg); g_assert(watch->netreg == netreg);
g_assert(watch->reg_status == netreg->status); g_assert_cmpint(watch->reg_status, == ,netreg->status);
g_assert(n[NETREG] == 1); g_assert_cmpint(watch->reg_tech, == ,netreg->tech);
g_assert(n[REG_STATUS] == 1); g_assert_cmpint(n[NETREG], == ,1);
g_assert_cmpint(n[REG_STATUS], == ,1);
g_assert_cmpint(n[REG_TECH], == ,0);
n[NETREG] = 0; n[NETREG] = 0;
n[REG_STATUS] = 0; n[REG_STATUS] = 0;
netreg->status++; netreg->status++;
__ofono_watch_netreg_changed(TEST_PATH); netreg_notify(netreg);
g_assert(watch->reg_status == netreg->status); g_assert(watch->reg_status == netreg->status);
g_assert(n[REG_STATUS] == 1); g_assert(n[REG_STATUS] == 1);
n[REG_STATUS] = 0; n[REG_STATUS] = 0;
@@ -669,31 +709,35 @@ static void test_netreg(void)
netreg->mcc = TEST_MCC; netreg->mcc = TEST_MCC;
netreg->mnc = TEST_MNC; netreg->mnc = TEST_MNC;
netreg->name = TEST_NAME; netreg->name = TEST_NAME;
__ofono_watch_netreg_changed(TEST_PATH); netreg->tech = OFONO_ACCESS_TECHNOLOGY_EUTRAN;
__ofono_watch_netreg_changed(TEST_PATH); /* This one has no effect */ netreg_notify(netreg);
__ofono_watch_netreg_changed(TEST_PATH_1); /* This one too */ netreg_notify(netreg); /* This one has no effect */
g_assert(!n[REG_STATUS]); g_assert_cmpint(n[REG_STATUS], == ,0);
g_assert(n[REG_MCC] == 1); g_assert_cmpint(n[REG_MCC], == ,1);
g_assert(n[REG_MNC] == 1); g_assert_cmpint(n[REG_MNC], == ,1);
g_assert(n[REG_NAME] == 1); g_assert_cmpint(n[REG_NAME], == ,1);
g_assert(!g_strcmp0(watch->reg_mcc, netreg->mcc)); g_assert_cmpint(n[REG_TECH], == ,1);
g_assert(!g_strcmp0(watch->reg_mnc, netreg->mnc)); g_assert_cmpstr(watch->reg_mcc, == ,netreg->mcc);
g_assert(!g_strcmp0(watch->reg_name, netreg->name)); g_assert_cmpstr(watch->reg_mnc, == ,netreg->mnc);
g_assert_cmpstr(watch->reg_name, == ,netreg->name);
n[REG_MCC] = 0; n[REG_MCC] = 0;
n[REG_MNC] = 0; n[REG_MNC] = 0;
n[REG_NAME] = 0; n[REG_NAME] = 0;
n[REG_TECH] = 0;
test_modem_unregister_atom(&modem, &netreg->atom); test_modem_unregister_atom(&modem, &netreg->atom);
g_assert(!watch->netreg); g_assert(!watch->netreg);
g_assert(watch->reg_status == OFONO_NETREG_STATUS_NONE); g_assert_cmpint(watch->reg_status, == ,OFONO_NETREG_STATUS_NONE);
g_assert_cmpint(watch->reg_tech, == ,OFONO_ACCESS_TECHNOLOGY_NONE);
g_assert(!watch->reg_mcc); g_assert(!watch->reg_mcc);
g_assert(!watch->reg_mnc); g_assert(!watch->reg_mnc);
g_assert(!watch->reg_name); g_assert(!watch->reg_name);
g_assert(n[NETREG] == 1); g_assert_cmpint(n[NETREG], == ,1);
g_assert(n[REG_STATUS] == 1); g_assert_cmpint(n[REG_STATUS], == ,1);
g_assert(n[REG_MCC] == 1); g_assert_cmpint(n[REG_MCC], == ,1);
g_assert(n[REG_MNC] == 1); g_assert_cmpint(n[REG_MNC], == ,1);
g_assert(n[REG_NAME] == 1); g_assert_cmpint(n[REG_NAME], == ,1);
g_assert_cmpint(n[REG_TECH], == ,1);
memset(n, 0, sizeof(n)); memset(n, 0, sizeof(n));
netreg->mcc = NULL; netreg->mcc = NULL;
@@ -702,20 +746,24 @@ static void test_netreg(void)
test_modem_register_atom(&modem, &netreg->atom); test_modem_register_atom(&modem, &netreg->atom);
g_assert(watch->netreg == netreg); g_assert(watch->netreg == netreg);
g_assert(watch->reg_status == netreg->status); g_assert_cmpint(watch->reg_status, == ,netreg->status);
g_assert(n[NETREG] == 1); g_assert_cmpint(watch->reg_tech, == ,netreg->tech);
g_assert(n[REG_STATUS] == 1); g_assert_cmpint(n[NETREG], == ,1);
g_assert_cmpint(n[REG_STATUS], == ,1);
n[NETREG] = 0; n[NETREG] = 0;
n[REG_STATUS] = 0; n[REG_STATUS] = 0;
n[REG_TECH] = 0;
test_modem_shutdown(&modem); test_modem_shutdown(&modem);
g_assert(!watch->netreg); g_assert(!watch->netreg);
g_assert(watch->reg_status == OFONO_NETREG_STATUS_NONE); g_assert_cmpint(watch->reg_status, == ,OFONO_NETREG_STATUS_NONE);
g_assert(n[NETREG] == 1); g_assert_cmpint(watch->reg_tech, == ,OFONO_ACCESS_TECHNOLOGY_NONE);
g_assert(n[REG_STATUS] == 1); g_assert_cmpint(n[NETREG], == ,1);
g_assert(!n[REG_MCC]); g_assert_cmpint(n[REG_STATUS], == ,1);
g_assert(!n[REG_MNC]); g_assert_cmpint(n[REG_TECH], == ,1);
g_assert(!n[REG_NAME]); g_assert_cmpint(n[REG_MCC], == ,0);
g_assert_cmpint(n[REG_MNC], == ,0);
g_assert_cmpint(n[REG_NAME], == ,0);
ofono_watch_remove_all_handlers(watch, id); ofono_watch_remove_all_handlers(watch, id);
ofono_watch_unref(watch); ofono_watch_unref(watch);