mirror of
https://github.com/sailfishos/ofono
synced 2025-11-24 11:29:46 +08:00
Compare commits
122 Commits
mer/1.19+g
...
upgrade-2.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b5ed6d16db | ||
|
|
fd0a1a9adb | ||
|
|
49efa5bd18 | ||
|
|
e4a08ddb3f | ||
|
|
b92ddd870e | ||
|
|
09fa97c53a | ||
|
|
3eaa8a46bd | ||
|
|
4401319136 | ||
|
|
472ddcf0b1 | ||
|
|
b7e0f276a1 | ||
|
|
5d251aea3a | ||
|
|
cdc0065284 | ||
|
|
6d65dc5bf0 | ||
|
|
5d02c0bba4 | ||
|
|
b99513e080 | ||
|
|
3cf328c781 | ||
|
|
bce68611a1 | ||
|
|
cc497feee7 | ||
|
|
725606af8d | ||
|
|
52db6e5459 | ||
|
|
83441bc203 | ||
|
|
4054f09b60 | ||
|
|
38aa8cff87 | ||
|
|
4959292938 | ||
|
|
c69cea52cf | ||
|
|
4e0b8f7b48 | ||
|
|
9c87063c4a | ||
|
|
dc5a87f4f2 | ||
|
|
ecd35181a3 | ||
|
|
96d6daf67e | ||
|
|
e9702f6ec1 | ||
|
|
0746c615bc | ||
|
|
970020a3b0 | ||
|
|
f3d5e3d5c6 | ||
|
|
bb880ab14a | ||
|
|
922d5e17ee | ||
|
|
7886ce04a1 | ||
|
|
5213398826 | ||
|
|
0bbcc127be | ||
|
|
f7db0a0459 | ||
|
|
2d18086c80 | ||
|
|
0f4560c2eb | ||
|
|
7d80344d6b | ||
|
|
c0c4148099 | ||
|
|
34755f1a79 | ||
|
|
282d560c37 | ||
|
|
e4bca84876 | ||
|
|
aa0ded78b0 | ||
|
|
eb15b12caf | ||
|
|
81b5c716e2 | ||
|
|
33c330988f | ||
|
|
910057a265 | ||
|
|
19f0f8d96e | ||
|
|
f1f3c17c4c | ||
|
|
29d891cbce | ||
|
|
89fa0d5d6a | ||
|
|
c382d9f456 | ||
|
|
b209b6bee6 | ||
|
|
ee3323e98b | ||
|
|
9200e387e1 | ||
|
|
2bc58a7f6f | ||
|
|
35079b11fe | ||
|
|
955d5882b2 | ||
|
|
2583fa99ce | ||
|
|
b8bb15ce9c | ||
|
|
cbf24c7b08 | ||
|
|
a4c4d1526e | ||
|
|
18d1a8834a | ||
|
|
8343d96db5 | ||
|
|
415fce9368 | ||
|
|
33257a139d | ||
|
|
f580867c12 | ||
|
|
edaba80ad1 | ||
|
|
e68314b07d | ||
|
|
d13e48b638 | ||
|
|
e0edfca358 | ||
|
|
7cd2075ada | ||
|
|
3ccacfd5f7 | ||
|
|
5ee13f8e2c | ||
|
|
6ab9dcb553 | ||
|
|
102061107a | ||
|
|
2bb7d629f5 | ||
|
|
5ce01787e8 | ||
|
|
1d57cb0e73 | ||
|
|
3d84c0a120 | ||
|
|
091cf21c0b | ||
|
|
351ac1e9db | ||
|
|
b7481a918f | ||
|
|
e1e4381105 | ||
|
|
cc3ca52e61 | ||
|
|
a71779ea2a | ||
|
|
a9d2849bbb | ||
|
|
ca29c8e538 | ||
|
|
85fe1b7174 | ||
|
|
56e0d9dffa | ||
|
|
6867ba65cb | ||
|
|
6199eaa4d8 | ||
|
|
fabdd6799c | ||
|
|
1219ab6a3f | ||
|
|
85a956d9eb | ||
|
|
c83d992a3b | ||
|
|
b22027017c | ||
|
|
1fa137b36d | ||
|
|
cfd837b1db | ||
|
|
735ad21e89 | ||
|
|
c9078404de | ||
|
|
e375195c92 | ||
|
|
ef5610f741 | ||
|
|
aef9bbd3e0 | ||
|
|
c6eb410f21 | ||
|
|
08b3ea3d0f | ||
|
|
2978862417 | ||
|
|
19228c9e67 | ||
|
|
9be791d531 | ||
|
|
6b9eb7bf8f | ||
|
|
01f8989aee | ||
|
|
2f5efaf591 | ||
|
|
ca1d06c37a | ||
|
|
5f45928a84 | ||
|
|
19f74e6c85 | ||
|
|
41d5cfcab2 | ||
|
|
357c5db580 |
19
ofono/.gitignore
vendored
19
ofono/.gitignore
vendored
@@ -42,13 +42,32 @@ unit/test-mux
|
||||
unit/test-caif
|
||||
unit/test-stkutil
|
||||
unit/test-cdmasms
|
||||
unit/test-ril_util
|
||||
unit/test-rilmodem-cb
|
||||
unit/test-rilmodem-cs
|
||||
unit/test-rilmodem-gprs
|
||||
unit/test-rilmodem-sms
|
||||
unit/test-sailfish_cell_info
|
||||
unit/test-sailfish_manager
|
||||
unit/test-sailfish_sim_info
|
||||
unit/test-*.log
|
||||
unit/test-*.trs
|
||||
|
||||
unit/test-grilreply
|
||||
unit/test-grilrequest
|
||||
unit/test-grilunsol
|
||||
unit/test-provision
|
||||
unit/html
|
||||
|
||||
plugins/sailfish_manager/*.gcda
|
||||
plugins/sailfish_manager/*.gcno
|
||||
drivers/*/*.gcda
|
||||
drivers/*/*.gcno
|
||||
drivers/*/*.gcov
|
||||
*/*.gcda
|
||||
*/*.gcno
|
||||
*/*.gcov
|
||||
|
||||
tools/huawei-audio
|
||||
tools/auto-enable
|
||||
tools/get-location
|
||||
|
||||
@@ -27,6 +27,11 @@ pkginclude_HEADERS = include/log.h include/plugin.h include/history.h \
|
||||
|
||||
nodist_pkginclude_HEADERS = include/version.h
|
||||
|
||||
if SAILFISH_MANAGER
|
||||
nodist_pkginclude_HEADERS += include/sailfish_cell_info.h \
|
||||
include/sailfish_manager.h include/sailfish_watch.h
|
||||
endif
|
||||
|
||||
local_headers = $(foreach file,$(pkginclude_HEADERS) \
|
||||
$(nodist_pkginclude_HEADERS), \
|
||||
include/ofono/$(notdir $(file)))
|
||||
@@ -116,8 +121,19 @@ builtin_modules += udevng
|
||||
builtin_sources += plugins/udevng.c
|
||||
endif
|
||||
|
||||
if SAILFISH_MANAGER
|
||||
builtin_modules += sailfish_manager
|
||||
builtin_sources += plugins/sailfish_manager/sailfish_cell_info.c \
|
||||
plugins/sailfish_manager/sailfish_cell_info_dbus.c \
|
||||
plugins/sailfish_manager/sailfish_manager.c \
|
||||
plugins/sailfish_manager/sailfish_manager_dbus.c \
|
||||
plugins/sailfish_manager/sailfish_sim_info.c \
|
||||
plugins/sailfish_manager/sailfish_sim_info_dbus.c \
|
||||
plugins/sailfish_manager/sailfish_watch.c
|
||||
endif
|
||||
|
||||
if RILMODEM
|
||||
if JOLLA_RILMODEM
|
||||
if SAILFISH_RILMODEM
|
||||
|
||||
builtin_modules += ril
|
||||
builtin_sources += drivers/ril/ril_call_barring.c \
|
||||
@@ -125,7 +141,6 @@ builtin_sources += drivers/ril/ril_call_barring.c \
|
||||
drivers/ril/ril_call_settings.c \
|
||||
drivers/ril/ril_call_volume.c \
|
||||
drivers/ril/ril_cell_info.c \
|
||||
drivers/ril/ril_cell_info_dbus.c \
|
||||
drivers/ril/ril_config.c \
|
||||
drivers/ril/ril_cbs.c \
|
||||
drivers/ril/ril_data.c \
|
||||
@@ -134,20 +149,17 @@ builtin_sources += drivers/ril/ril_call_barring.c \
|
||||
drivers/ril/ril_gprs.c \
|
||||
drivers/ril/ril_gprs_context.c \
|
||||
drivers/ril/ril_modem.c \
|
||||
drivers/ril/ril_mtu.c \
|
||||
drivers/ril/ril_netmon.c \
|
||||
drivers/ril/ril_netreg.c \
|
||||
drivers/ril/ril_network.c \
|
||||
drivers/ril/ril_oem_raw.c \
|
||||
drivers/ril/ril_phonebook.c \
|
||||
drivers/ril/ril_plugin.c \
|
||||
drivers/ril/ril_plugin_dbus.c \
|
||||
drivers/ril/ril_radio.c \
|
||||
drivers/ril/ril_radio_caps.c \
|
||||
drivers/ril/ril_radio_settings.c \
|
||||
drivers/ril/ril_sim.c \
|
||||
drivers/ril/ril_sim_card.c \
|
||||
drivers/ril/ril_sim_info.c \
|
||||
drivers/ril/ril_sim_info_dbus.c \
|
||||
drivers/ril/ril_sim_settings.c \
|
||||
drivers/ril/ril_sms.c \
|
||||
drivers/ril/ril_stk.c \
|
||||
@@ -575,6 +587,11 @@ builtin_sources += plugins/bluez5.c plugins/bluez5.h
|
||||
|
||||
builtin_modules += hfp_ag_bluez5
|
||||
builtin_sources += plugins/hfp_ag_bluez5.c plugins/bluez5.h
|
||||
|
||||
if SAILFISH_BT
|
||||
builtin_modules += sfos_bt
|
||||
builtin_sources += plugins/sailfish_bt.c
|
||||
endif
|
||||
endif
|
||||
|
||||
if UPOWER
|
||||
@@ -588,11 +605,25 @@ builtin_modules += nettime
|
||||
builtin_sources += plugins/nettime.c
|
||||
endif
|
||||
|
||||
if SAILFISH_DEBUGLOG
|
||||
builtin_modules += debuglog
|
||||
builtin_sources += plugins/sailfish_debuglog.c
|
||||
endif
|
||||
|
||||
if SAILFISH_PROVISION
|
||||
builtin_sources += plugins/sailfish_provision.c
|
||||
PROVISION = 1
|
||||
else
|
||||
if PROVISION
|
||||
builtin_sources += plugins/provision.c
|
||||
endif
|
||||
endif
|
||||
|
||||
if PROVISION
|
||||
builtin_sources += plugins/mbpi.h plugins/mbpi.c
|
||||
|
||||
builtin_modules += provision
|
||||
builtin_sources += plugins/provision.h plugins/provision.c
|
||||
builtin_sources += plugins/provision.h
|
||||
|
||||
builtin_modules += cdma_provision
|
||||
builtin_sources += plugins/cdma-provision.c
|
||||
@@ -630,16 +661,9 @@ builtin_sources += plugins/smart-messaging.c
|
||||
builtin_modules += push_notification
|
||||
builtin_sources += plugins/push-notification.c
|
||||
|
||||
if PUSHFORWARDER
|
||||
builtin_modules += push_forwarder
|
||||
builtin_sources += plugins/push-forwarder.c
|
||||
builtin_cflags += @WSPCODEC_CFLAGS@
|
||||
builtin_libadd += @WSPCODEC_LIBS@
|
||||
endif
|
||||
|
||||
if DEBUGLOG
|
||||
builtin_modules += debuglog
|
||||
builtin_sources += plugins/debuglog.c
|
||||
if SAILFISH_PUSHFORWARDER
|
||||
builtin_modules += pushforwarder
|
||||
builtin_sources += plugins/sailfish_pushforwarder.c
|
||||
endif
|
||||
|
||||
builtin_modules += sms_history
|
||||
@@ -651,6 +675,7 @@ builtin_sources += plugins/allowed-apns.c
|
||||
sbin_PROGRAMS = src/ofonod
|
||||
|
||||
src_ofonod_SOURCES = $(builtin_sources) $(gatchat_sources) src/ofono.ver \
|
||||
src/mtu-watch.c \
|
||||
src/main.c src/ofono.h src/log.c src/plugin.c \
|
||||
src/modem.c src/common.h src/common.c \
|
||||
src/manager.c src/dbus.c src/util.h src/util.c \
|
||||
@@ -844,6 +869,9 @@ EXTRA_DIST = src/genbuiltin plugins/ofono.rules plugins/ofono-speedup.rules \
|
||||
|
||||
dist_man_MANS = doc/ofonod.8
|
||||
|
||||
if TEST_COVERAGE
|
||||
COVERAGE_OPT = --coverage
|
||||
endif
|
||||
|
||||
unit_objects =
|
||||
|
||||
@@ -852,9 +880,51 @@ unit_tests = unit/test-common unit/test-util unit/test-idmap \
|
||||
unit/test-sms unit/test-cdmasms \
|
||||
unit/test-provision
|
||||
|
||||
if RILMODEM
|
||||
if JOLLA_RILMODEM
|
||||
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
|
||||
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_sim_info_SOURCES = unit/test-sailfish_sim_info.c \
|
||||
unit/fake_sailfish_watch.c \
|
||||
plugins/sailfish_manager/sailfish_sim_info.c \
|
||||
src/storage.c src/watch.c src/log.c
|
||||
unit_test_sailfish_sim_info_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS) \
|
||||
-DSTORAGEDIR='"/tmp/ofono"' -Iplugins/sailfish_manager
|
||||
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_manager_SOURCES = unit/test-sailfish_manager.c \
|
||||
unit/fake_sailfish_watch.c \
|
||||
plugins/sailfish_manager/sailfish_manager.c \
|
||||
plugins/sailfish_manager/sailfish_cell_info.c \
|
||||
plugins/sailfish_manager/sailfish_sim_info.c \
|
||||
src/storage.c src/log.c
|
||||
unit_test_sailfish_manager_CFLAGS = $(AM_CFLAGS) $(COVERAGE_OPT) \
|
||||
-DSTORAGEDIR='"/tmp/ofono"' -Iplugins/sailfish_manager
|
||||
unit_test_sailfish_manager_LDADD = @GLIB_LIBS@ -ldl
|
||||
unit_objects += $(unit_test_sailfish_manager_OBJECTS)
|
||||
unit_tests += unit/test-sailfish_manager
|
||||
|
||||
endif
|
||||
|
||||
if RILMODEM
|
||||
if SAILFISH_RILMODEM
|
||||
|
||||
unit_test_ril_util_SOURCES = unit/test-ril_util.c drivers/ril/ril_util.c \
|
||||
src/log.c
|
||||
unit_test_ril_util_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
|
||||
unit_test_ril_util_LDADD = @GLIB_LIBS@ -ldl
|
||||
unit_objects += $(unit_test_ril_util_OBJECTS)
|
||||
unit_tests += unit/test-ril_util
|
||||
|
||||
else
|
||||
unit_tests += unit/test-rilmodem-cs \
|
||||
unit/test-rilmodem-cs \
|
||||
unit/test-rilmodem-sms \
|
||||
@@ -868,19 +938,23 @@ noinst_PROGRAMS = $(unit_tests) \
|
||||
unit/test-sms-root unit/test-mux unit/test-caif
|
||||
|
||||
unit_test_common_SOURCES = unit/test-common.c src/common.c src/util.c
|
||||
unit_test_common_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
|
||||
unit_test_common_LDADD = @GLIB_LIBS@
|
||||
unit_objects += $(unit_test_common_OBJECTS)
|
||||
|
||||
unit_test_util_SOURCES = unit/test-util.c src/util.c
|
||||
unit_test_util_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
|
||||
unit_test_util_LDADD = @GLIB_LIBS@
|
||||
unit_objects += $(unit_test_utils_OBJECTS)
|
||||
|
||||
unit_test_idmap_SOURCES = unit/test-idmap.c src/idmap.c
|
||||
unit_test_idmap_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
|
||||
unit_test_idmap_LDADD = @GLIB_LIBS@
|
||||
unit_objects += $(unit_test_idmap_OBJECTS)
|
||||
|
||||
unit_test_simutil_SOURCES = unit/test-simutil.c src/util.c \
|
||||
src/simutil.c src/smsutil.c src/storage.c
|
||||
unit_test_simutil_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
|
||||
unit_test_simutil_LDADD = @GLIB_LIBS@
|
||||
unit_objects += $(unit_test_simutil_OBJECTS)
|
||||
|
||||
@@ -888,19 +962,23 @@ unit_test_stkutil_SOURCES = unit/test-stkutil.c unit/stk-test-data.h \
|
||||
src/util.c \
|
||||
src/storage.c src/smsutil.c \
|
||||
src/simutil.c src/stkutil.c
|
||||
unit_test_stkutil_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
|
||||
unit_test_stkutil_LDADD = @GLIB_LIBS@
|
||||
unit_objects += $(unit_test_stkutil_OBJECTS)
|
||||
|
||||
unit_test_sms_SOURCES = unit/test-sms.c src/util.c src/smsutil.c src/storage.c
|
||||
unit_test_sms_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
|
||||
unit_test_sms_LDADD = @GLIB_LIBS@
|
||||
unit_objects += $(unit_test_sms_OBJECTS)
|
||||
|
||||
unit_test_cdmasms_SOURCES = unit/test-cdmasms.c src/cdma-smsutil.c
|
||||
unit_test_cdmasms_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
|
||||
unit_test_cdmasms_LDADD = @GLIB_LIBS@
|
||||
unit_objects += $(unit_test_cdmasms_OBJECTS)
|
||||
|
||||
unit_test_sms_root_SOURCES = unit/test-sms-root.c \
|
||||
src/util.c src/smsutil.c src/storage.c
|
||||
unit_test_sms_root_CFLAGS = -DSTORAGEDIR='"/tmp/ofono"' $(COVERAGE_OPT) $(AM_CFLAGS)
|
||||
unit_test_sms_root_LDADD = @GLIB_LIBS@
|
||||
unit_objects += $(unit_test_sms_root_OBJECTS)
|
||||
|
||||
@@ -911,13 +989,15 @@ unit_objects += $(unit_test_mux_OBJECTS)
|
||||
unit_test_caif_SOURCES = unit/test-caif.c $(gatchat_sources) \
|
||||
drivers/stemodem/caif_socket.h \
|
||||
drivers/stemodem/if_caif.h
|
||||
unit_test_caif_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
|
||||
unit_test_caif_LDADD = @GLIB_LIBS@
|
||||
unit_objects += $(unit_test_caif_OBJECTS)
|
||||
|
||||
unit_test_provision_SOURCES = unit/test-provision.c \
|
||||
plugins/provision.h plugins/provision.c \
|
||||
plugins/mbpi.c src/gprs-provision.c \
|
||||
src/log.c
|
||||
plugins/provision.h plugins/mbpi.c \
|
||||
plugins/sailfish_provision.c \
|
||||
src/gprs-provision.c src/log.c
|
||||
unit_test_provision_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
|
||||
unit_test_provision_LDADD = @GLIB_LIBS@ -ldl
|
||||
unit_objects += $(unit_test_provision_OBJECTS)
|
||||
|
||||
|
||||
@@ -69,6 +69,16 @@ PKG_CHECK_MODULES(GLIB, glib-2.0 >= 2.32, dummy=yes,
|
||||
AC_SUBST(GLIB_CFLAGS)
|
||||
AC_SUBST(GLIB_LIBS)
|
||||
|
||||
PKG_CHECK_MODULES(GOBJECT, gobject-2.0, dummy=yes,
|
||||
AC_MSG_ERROR(GObject is required))
|
||||
GLIB_CFLAGS="$GLIB_CFLAGS $GOBJECT_CFLAGS"
|
||||
GLIB_LIBS="$GLIB_LIBS $GOBJECT_LIBS"
|
||||
|
||||
PKG_CHECK_MODULES(GIO, gio-2.0, dummy=yes,
|
||||
AC_MSG_ERROR(GIO is required))
|
||||
GLIB_CFLAGS="$GLIB_CFLAGS $GIO_CFLAGS"
|
||||
GLIB_LIBS="$GLIB_LIBS $GIO_LIBS"
|
||||
|
||||
if (test "${enable_threads}" = "yes"); then
|
||||
AC_DEFINE(NEED_THREADS, 1, [Define if threading support is required])
|
||||
PKG_CHECK_MODULES(GTHREAD, gthread-2.0 >= 2.16, dummy=yes,
|
||||
@@ -167,22 +177,44 @@ AC_ARG_ENABLE(rilmodem, AC_HELP_STRING([--disable-rilmodem],
|
||||
[enable_rilmodem=${enableval}])
|
||||
AM_CONDITIONAL(RILMODEM, test "${enable_rilmodem}" != "no")
|
||||
|
||||
AC_ARG_ENABLE(jolla-rilmodem,
|
||||
AC_HELP_STRING([--enable-jolla-rilmodem], [enable Jolla RIL modem]),
|
||||
[enable_jolla_rilmodem=${enableval}], [enable_jolla_rilmodem="no"])
|
||||
AM_CONDITIONAL(JOLLA_RILMODEM, test "${enable_jolla_rilmodem}" != "no")
|
||||
AC_ARG_ENABLE(sailfish-rilmodem, AC_HELP_STRING([--enable-sailfish-rilmodem],
|
||||
[enable Sailfish RIL modem]),
|
||||
[enable_sailfish_rilmodem=${enableval}],
|
||||
[enable_sailfish_rilmodem="no"])
|
||||
AM_CONDITIONAL(SAILFISH_RILMODEM, test "${enable_sailfish_rilmodem}" != "no")
|
||||
|
||||
if (test "${enable_jolla_rilmodem}" = "yes"); then
|
||||
PKG_CHECK_MODULES(GRILIO, libgrilio >= 1.0.6, dummy=yes,
|
||||
AC_MSG_ERROR(libgrilio >= 1.0.6 is required))
|
||||
PKG_CHECK_MODULES(GLIBUTIL, libglibutil >= 1.0.5, dummy=yes,
|
||||
AC_MSG_ERROR(libglibutil >= 1.0.5 is required))
|
||||
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(GLIBUTIL, libglibutil >= 1.0.23, dummy=yes,
|
||||
AC_MSG_ERROR(libglibutil >= 1.0.23 is required))
|
||||
PKG_CHECK_MODULES(LIBMCE, libmce-glib, dummy=yes,
|
||||
AC_MSG_ERROR(libmce-glib is required))
|
||||
CFLAGS="$CFLAGS $GRILIO_CFLAGS $GLIBUTIL_CFLAGS $LIBMCE_CFLAGS"
|
||||
LIBS="$LIBS $GRILIO_LIBS $GLIBUTIL_LIBS $LIBMCE_LIBS"
|
||||
CFLAGS="$CFLAGS $GRILIO_CFLAGS $LIBMCE_CFLAGS"
|
||||
LIBS="$LIBS $GRILIO_LIBS $LIBMCE_LIBS"
|
||||
enable_sailfish_manager=yes
|
||||
need_glibutil=yes
|
||||
fi
|
||||
|
||||
AC_ARG_ENABLE(sailfish-manager,
|
||||
AC_HELP_STRING([--enable-sailfish-manager],
|
||||
[enable Sailfish OS modem manager plugin]),
|
||||
[enable_sailfish_manager=${enableval}])
|
||||
AM_CONDITIONAL(SAILFISH_MANAGER, test "${enable_sailfish_manager}" = "yes")
|
||||
|
||||
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
|
||||
CFLAGS="$CFLAGS -DDISABLE_ADD_REMOVE_CONTEXT"
|
||||
fi
|
||||
])
|
||||
|
||||
AC_ARG_ENABLE(test-coverage,
|
||||
AC_HELP_STRING([--enable-test-coverage], [enable test code coverage]),
|
||||
[enable_test_coverage=${enableval}],
|
||||
[enable_test_coverage="no"])
|
||||
AM_CONDITIONAL(TEST_COVERAGE, test "${enable_test_coverage}" != "no")
|
||||
|
||||
AC_ARG_ENABLE(qmimodem, AC_HELP_STRING([--disable-qmimodem],
|
||||
[disable Qualcomm QMI modem support]),
|
||||
[enable_qmimodem=${enableval}])
|
||||
@@ -206,6 +238,16 @@ fi
|
||||
AM_CONDITIONAL(BLUEZ4, test "${enable_bluetooth}" != "no" && test "${enable_bluez4}" = "yes")
|
||||
AM_CONDITIONAL(BLUETOOTH, test "${enable_bluetooth}" != "no")
|
||||
|
||||
AC_ARG_ENABLE(sailfish-bt, AC_HELP_STRING([--enable-sailfish-bt],
|
||||
[enable Sailfish OS Bluetooth plugin]),
|
||||
[enable_sailfish_bt=${enableval}])
|
||||
AM_CONDITIONAL(SAILFISH_BT, test "${enable_sailfish_bt}" = "yes")
|
||||
|
||||
AC_ARG_ENABLE(sailfish-provision, AC_HELP_STRING([--enable-sailfish-provision],
|
||||
[enable Sailfish OS provisioning plugin]),
|
||||
[enable_sailfish_provision=${enableval}])
|
||||
AM_CONDITIONAL(SAILFISH_PROVISION, test "${enable_sailfish_provision=$}" = "yes")
|
||||
|
||||
AC_ARG_ENABLE(nettime, AC_HELP_STRING([--disable-nettime],
|
||||
[disable Nettime plugin]),
|
||||
[enable_nettime=${enableval}])
|
||||
@@ -248,28 +290,38 @@ AC_ARG_ENABLE(datafiles, AC_HELP_STRING([--disable-datafiles],
|
||||
[enable_datafiles=${enableval}])
|
||||
AM_CONDITIONAL(DATAFILES, test "${enable_datafiles}" != "no")
|
||||
|
||||
AC_ARG_ENABLE(pushforwarder, AC_HELP_STRING([--disable-pushforwarder],
|
||||
[disable Push Forwarder plugin]),
|
||||
[enable_pushforwarder=${enableval}])
|
||||
AM_CONDITIONAL(PUSHFORWARDER, test "${enable_pushforwarder}" != "no")
|
||||
if (test "${enable_pushforwarder}" != "no"); then
|
||||
AC_ARG_ENABLE(sailfish-pushforwarder, AC_HELP_STRING([--enable-sailfish-pushforwarder],
|
||||
[enable Sailfish OS push forwarder plugin]),
|
||||
[enable_sailfish_pushforwarder=${enableval}],
|
||||
[enable_sailfish_pushforwarder="no"])
|
||||
AM_CONDITIONAL(SAILFISH_PUSHFORWARDER, test "${enable_sailfish_pushforwarder}" != "no")
|
||||
if (test "${enable_sailfish_pushforwarder}" != "no"); then
|
||||
PKG_CHECK_MODULES(GLIBUTIL, libglibutil >= 1.0.15, dummy=yes,
|
||||
AC_MSG_ERROR(libglibutil >= 1.0.15 is required))
|
||||
PKG_CHECK_MODULES(WSPCODEC, libwspcodec >= 2.0, dummy=yes,
|
||||
AC_MSG_ERROR(WSP decoder is required))
|
||||
AC_SUBST(WSPCODEC_CFLAGS)
|
||||
AC_SUBST(WSPCODEC_LIBS)
|
||||
AC_MSG_ERROR(WSP decoder is required))
|
||||
CFLAGS="$CFLAGS $WSPCODEC_CFLAGS"
|
||||
LIBS="$LIBS $WSPCODEC_LIBS"
|
||||
need_glibutil=yes
|
||||
fi
|
||||
|
||||
AC_ARG_ENABLE(debuglog,
|
||||
AC_HELP_STRING([--enable-debuglog], [enable log control plugin]),
|
||||
[enable_debuglog=${enableval}], [enable_debuglog="no"])
|
||||
AM_CONDITIONAL(DEBUGLOG, test "${enable_debuglog}" != "no")
|
||||
if (test "${enable_debuglog}" = "yes"); then
|
||||
AC_ARG_ENABLE(sailfish-debuglog, AC_HELP_STRING([--enable-sailfish-debuglog],
|
||||
[enable Sailfish OS debug log plugin]),
|
||||
[enable_sailfish_debuglog=${enableval}],
|
||||
[enable_sailfish_debuglog="no"])
|
||||
AM_CONDITIONAL(SAILFISH_DEBUGLOG, test "${enable_sailfish_debuglog}" != "no")
|
||||
if (test "${enable_sailfish_debuglog}" = "yes"); then
|
||||
PKG_CHECK_MODULES(DBUSLOG, libdbuslogserver-dbus, dummy=yes,
|
||||
AC_MSG_ERROR(libdbuslogserver-dbus is required))
|
||||
CFLAGS="$CFLAGS $DBUSLOG_CFLAGS"
|
||||
LIBS="$LIBS $DBUSLOG_LIBS"
|
||||
fi
|
||||
|
||||
if (test "${need_glibutil}" = "yes"); then
|
||||
CFLAGS="$CFLAGS $GLIBUTIL_CFLAGS"
|
||||
LIBS="$LIBS $GLIBUTIL_LIBS"
|
||||
fi
|
||||
|
||||
if (test "${prefix}" = "NONE"); then
|
||||
dnl no prefix and no localstatedir, so default to /var
|
||||
if (test "$localstatedir" = '${prefix}/var'); then
|
||||
@@ -284,7 +336,7 @@ if (test "$localstatedir" = '${prefix}/var'); then
|
||||
else
|
||||
storagedir="${localstatedir}/lib/ofono"
|
||||
fi
|
||||
AC_DEFINE_UNQUOTED(STORAGEDIR, "${storagedir}",
|
||||
AC_DEFINE_UNQUOTED(DEFAULT_STORAGEDIR, "${storagedir}",
|
||||
[Directory for the storage files])
|
||||
|
||||
if (test "$sysconfdir" = '${prefix}/etc'); then
|
||||
|
||||
@@ -247,6 +247,8 @@ static void at_gprs_activate_primary(struct ofono_gprs_context *gc,
|
||||
|
||||
/* We only support CHAP and PAP */
|
||||
switch (ctx->auth_method) {
|
||||
case OFONO_GPRS_AUTH_METHOD_ANY:
|
||||
case OFONO_GPRS_AUTH_METHOD_NONE:
|
||||
case OFONO_GPRS_AUTH_METHOD_CHAP:
|
||||
gcd->auth_method = G_AT_PPP_AUTH_METHOD_CHAP;
|
||||
break;
|
||||
@@ -294,6 +296,8 @@ static void at_gprs_activate_primary(struct ofono_gprs_context *gc,
|
||||
* prefix, this is the least invasive place to set it.
|
||||
*/
|
||||
switch (ctx->auth_method) {
|
||||
case OFONO_GPRS_AUTH_METHOD_ANY:
|
||||
case OFONO_GPRS_AUTH_METHOD_NONE:
|
||||
case OFONO_GPRS_AUTH_METHOD_CHAP:
|
||||
snprintf(buf + len, sizeof(buf) - len - 3,
|
||||
",\"CHAP:%s\"", ctx->apn);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015 Jolla Ltd.
|
||||
* Copyright (C) 2015-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
|
||||
@@ -16,7 +16,6 @@
|
||||
#include "ril_plugin.h"
|
||||
#include "ril_util.h"
|
||||
#include "ril_log.h"
|
||||
#include "ril_constants.h"
|
||||
|
||||
#include "common.h"
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2016 Jolla Ltd.
|
||||
* Copyright (C) 2015-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
|
||||
@@ -16,7 +16,6 @@
|
||||
#include "ril_plugin.h"
|
||||
#include "ril_util.h"
|
||||
#include "ril_log.h"
|
||||
#include "ril_constants.h"
|
||||
|
||||
#include "common.h"
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015 Jolla Ltd.
|
||||
* Copyright (C) 2015-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
|
||||
@@ -16,7 +16,6 @@
|
||||
#include "ril_plugin.h"
|
||||
#include "ril_util.h"
|
||||
#include "ril_log.h"
|
||||
#include "ril_constants.h"
|
||||
|
||||
#include "common.h"
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015 Jolla Ltd.
|
||||
* Copyright (C) 2015-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
|
||||
@@ -16,7 +16,6 @@
|
||||
#include "ril_plugin.h"
|
||||
#include "ril_util.h"
|
||||
#include "ril_log.h"
|
||||
#include "ril_constants.h"
|
||||
|
||||
struct ril_call_volume {
|
||||
struct ofono_call_volume *v;
|
||||
|
||||
@@ -184,11 +184,14 @@ static int ril_cbs_probe(struct ofono_cbs *cbs, unsigned int vendor,
|
||||
cd->q = grilio_queue_new(cd->io);
|
||||
|
||||
/*
|
||||
* RIL_REQUEST_GSM_GET_BROADCAST_SMS_CONFIG often fails at startup.
|
||||
* We may have to retry a few times.
|
||||
* RIL_REQUEST_GSM_GET_BROADCAST_SMS_CONFIG often fails at startup
|
||||
* especially if other RIL requests are running in parallel. We may
|
||||
* have to retry a few times. Also, make it blocking in order to
|
||||
* improve the chance of success.
|
||||
*/
|
||||
grilio_request_set_retry(req, RIL_CBS_CHECK_RETRY_MS,
|
||||
RIL_CBS_CHECK_RETRY_COUNT);
|
||||
grilio_request_set_blocking(req, TRUE);
|
||||
grilio_queue_send_request_full(cd->q, req,
|
||||
RIL_REQUEST_GSM_GET_BROADCAST_SMS_CONFIG,
|
||||
ril_cbs_probe_done_cb, NULL, cd);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2016 Jolla Ltd.
|
||||
* 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
|
||||
@@ -31,7 +31,9 @@
|
||||
typedef GObjectClass RilCellInfoClass;
|
||||
typedef struct ril_cell_info RilCellInfo;
|
||||
|
||||
struct ril_cell_info_priv {
|
||||
struct ril_cell_info {
|
||||
GObject object;
|
||||
struct sailfish_cell_info info;
|
||||
GRilIoChannel *io;
|
||||
MceDisplay *display;
|
||||
struct ril_radio *radio;
|
||||
@@ -60,63 +62,22 @@ G_DEFINE_TYPE(RilCellInfo, ril_cell_info, G_TYPE_OBJECT)
|
||||
#define RIL_CELL_INFO(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),\
|
||||
RIL_CELL_INFO_TYPE, RilCellInfo))
|
||||
|
||||
#define DBG_(self,fmt,args...) DBG("%s" fmt, (self)->priv->log_prefix, ##args)
|
||||
#define DBG_(self,fmt,args...) DBG("%s" fmt, (self)->log_prefix, ##args)
|
||||
|
||||
gint ril_cell_compare_location(const struct ril_cell *c1,
|
||||
const struct ril_cell *c2)
|
||||
static inline void ril_cell_free(struct sailfish_cell *cell)
|
||||
{
|
||||
if (c1 && c2) {
|
||||
if (c1->type != c2->type) {
|
||||
return c1->type - c2->type;
|
||||
} else if (c1->type == RIL_CELL_INFO_TYPE_GSM) {
|
||||
const struct ril_cell_info_gsm *g1 = &c1->info.gsm;
|
||||
const struct ril_cell_info_gsm *g2 = &c2->info.gsm;
|
||||
|
||||
if (g1->lac != g2->lac) {
|
||||
return g1->lac - g2->lac;
|
||||
} else {
|
||||
return g1->cid - g2->cid;
|
||||
}
|
||||
} else if (c2->type == RIL_CELL_INFO_TYPE_WCDMA) {
|
||||
const struct ril_cell_info_wcdma *w1 = &c1->info.wcdma;
|
||||
const struct ril_cell_info_wcdma *w2 = &c2->info.wcdma;
|
||||
|
||||
if (w1->lac != w2->lac) {
|
||||
return w1->lac - w2->lac;
|
||||
} else {
|
||||
return w1->cid - w2->cid;
|
||||
}
|
||||
} else {
|
||||
const struct ril_cell_info_lte *l1 = &c1->info.lte;
|
||||
const struct ril_cell_info_lte *l2 = &c2->info.lte;
|
||||
|
||||
GASSERT(c1->type == RIL_CELL_INFO_TYPE_LTE);
|
||||
if (l1->ci != l2->ci) {
|
||||
return l1->ci - l2->ci;
|
||||
} else if (l1->pci != l2->pci) {
|
||||
return l1->pci - l2->pci;
|
||||
} else {
|
||||
return l1->tac - l2->tac;
|
||||
}
|
||||
}
|
||||
} else if (c1) {
|
||||
return 1;
|
||||
} else if (c2) {
|
||||
return -1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
g_slice_free(struct sailfish_cell, cell);
|
||||
}
|
||||
|
||||
gint ril_cell_compare_func(gconstpointer v1, gconstpointer v2)
|
||||
static void ril_cell_free1(gpointer cell)
|
||||
{
|
||||
return ril_cell_compare_location(v1, v2);
|
||||
ril_cell_free(cell);
|
||||
}
|
||||
|
||||
static gboolean ril_cell_info_list_identical(GSList *l1, GSList *l2)
|
||||
{
|
||||
while (l1 && l2) {
|
||||
if (memcmp(l1->data, l2->data, sizeof(struct ril_cell))) {
|
||||
if (memcmp(l1->data, l2->data, sizeof(struct sailfish_cell))) {
|
||||
return FALSE;
|
||||
}
|
||||
l1 = l1->next;
|
||||
@@ -127,80 +88,101 @@ static gboolean ril_cell_info_list_identical(GSList *l1, GSList *l2)
|
||||
|
||||
static void ril_cell_info_update_cells(struct ril_cell_info *self, GSList *l)
|
||||
{
|
||||
if (!ril_cell_info_list_identical(self->cells, l)) {
|
||||
g_slist_free_full(self->cells, g_free);
|
||||
self->cells = l;
|
||||
g_signal_emit(self, ril_cell_info_signals[
|
||||
SIGNAL_CELLS_CHANGED], 0);
|
||||
if (!ril_cell_info_list_identical(self->info.cells, l)) {
|
||||
g_slist_free_full(self->info.cells, ril_cell_free1);
|
||||
self->info.cells = l;
|
||||
g_signal_emit(self, ril_cell_info_signals
|
||||
[SIGNAL_CELLS_CHANGED], 0);
|
||||
} else {
|
||||
g_slist_free_full(l, g_free);
|
||||
g_slist_free_full(l, ril_cell_free1);
|
||||
}
|
||||
}
|
||||
|
||||
static struct ril_cell *ril_cell_info_parse_cell_gsm(GRilIoParser *rilp,
|
||||
gboolean registered)
|
||||
static struct sailfish_cell *ril_cell_info_parse_cell_gsm(GRilIoParser *rilp,
|
||||
guint version, gboolean registered)
|
||||
{
|
||||
struct ril_cell *cell = g_new0(struct ril_cell, 1);
|
||||
struct ril_cell_info_gsm *gsm = &cell->info.gsm;
|
||||
struct sailfish_cell *cell = g_slice_new0(struct sailfish_cell);
|
||||
struct sailfish_cell_info_gsm *gsm = &cell->info.gsm;
|
||||
|
||||
/* Optional RIL_CellIdentityGsm_v12 part */
|
||||
gsm->arfcn = INT_MAX;
|
||||
gsm->bsic = INT_MAX;
|
||||
/* Optional RIL_GSM_SignalStrength_v12 part */
|
||||
gsm->timingAdvance = INT_MAX;
|
||||
/* RIL_CellIdentityGsm */
|
||||
if (grilio_parser_get_int32(rilp, &gsm->mcc) &&
|
||||
grilio_parser_get_int32(rilp, &gsm->mnc) &&
|
||||
grilio_parser_get_int32(rilp, &gsm->lac) &&
|
||||
grilio_parser_get_int32(rilp, &gsm->cid) &&
|
||||
(version < 12 || /* RIL_CellIdentityGsm_v12 part */
|
||||
(grilio_parser_get_int32(rilp, &gsm->arfcn) &&
|
||||
grilio_parser_get_int32(rilp, &gsm->bsic))) &&
|
||||
/* RIL_GW_SignalStrength */
|
||||
grilio_parser_get_int32(rilp, &gsm->signalStrength) &&
|
||||
grilio_parser_get_int32(rilp, &gsm->bitErrorRate)) {
|
||||
DBG("[gsm] reg=%d,mcc=%d,mnc=%d,lac=%d,cid=%d,"
|
||||
"strength=%d,err=%d", registered, gsm->mcc, gsm->mnc,
|
||||
gsm->lac, gsm->cid, gsm->signalStrength,
|
||||
gsm->bitErrorRate);
|
||||
cell->type = RIL_CELL_INFO_TYPE_GSM;
|
||||
grilio_parser_get_int32(rilp, &gsm->bitErrorRate) &&
|
||||
(version < 12 || /* RIL_GSM_SignalStrength_v12 part */
|
||||
grilio_parser_get_int32(rilp, &gsm->timingAdvance))) {
|
||||
DBG("[gsm] reg=%d,mcc=%d,mnc=%d,lac=%d,cid=%d,arfcn=%d,"
|
||||
"bsic=%d,strength=%d,err=%d,t=%d", registered,
|
||||
gsm->mcc, gsm->mnc, gsm->lac, gsm->cid, gsm->arfcn,
|
||||
gsm->bsic, gsm->signalStrength, gsm->bitErrorRate,
|
||||
gsm->timingAdvance);
|
||||
cell->type = SAILFISH_CELL_TYPE_GSM;
|
||||
cell->registered = registered;
|
||||
return cell;
|
||||
}
|
||||
|
||||
ofono_error("failed to parse GSM cell info");
|
||||
g_free(cell);
|
||||
ril_cell_free(cell);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct ril_cell *ril_cell_info_parse_cell_wcdma(GRilIoParser *rilp,
|
||||
gboolean registered)
|
||||
static struct sailfish_cell *ril_cell_info_parse_cell_wcdma(GRilIoParser *rilp,
|
||||
guint version, gboolean registered)
|
||||
{
|
||||
struct ril_cell *cell = g_new0(struct ril_cell, 1);
|
||||
struct ril_cell_info_wcdma *wcdma = &cell->info.wcdma;
|
||||
struct sailfish_cell *cell = g_slice_new0(struct sailfish_cell);
|
||||
struct sailfish_cell_info_wcdma *wcdma = &cell->info.wcdma;
|
||||
|
||||
/* Optional RIL_CellIdentityWcdma_v12 part */
|
||||
wcdma->uarfcn = INT_MAX;
|
||||
if (grilio_parser_get_int32(rilp, &wcdma->mcc) &&
|
||||
grilio_parser_get_int32(rilp, &wcdma->mnc) &&
|
||||
grilio_parser_get_int32(rilp, &wcdma->lac) &&
|
||||
grilio_parser_get_int32(rilp, &wcdma->cid) &&
|
||||
grilio_parser_get_int32(rilp, &wcdma->psc) &&
|
||||
(version < 12 || /* RIL_CellIdentityWcdma_v12 part */
|
||||
grilio_parser_get_int32(rilp, &wcdma->uarfcn)) &&
|
||||
grilio_parser_get_int32(rilp, &wcdma->signalStrength) &&
|
||||
grilio_parser_get_int32(rilp, &wcdma->bitErrorRate)) {
|
||||
DBG("[wcdma] reg=%d,mcc=%d,mnc=%d,lac=%d,cid=%d,psc=%d,"
|
||||
"strength=%d,err=%d", registered, wcdma->mcc,
|
||||
wcdma->mnc, wcdma->lac, wcdma->cid, wcdma->psc,
|
||||
wcdma->signalStrength, wcdma->bitErrorRate);
|
||||
cell->type = RIL_CELL_INFO_TYPE_WCDMA;
|
||||
cell->type = SAILFISH_CELL_TYPE_WCDMA;
|
||||
cell->registered = registered;
|
||||
return cell;
|
||||
}
|
||||
|
||||
ofono_error("failed to parse WCDMA cell info");
|
||||
g_free(cell);
|
||||
ril_cell_free(cell);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct ril_cell *ril_cell_info_parse_cell_lte(GRilIoParser *rilp,
|
||||
gboolean registered)
|
||||
static struct sailfish_cell *ril_cell_info_parse_cell_lte(GRilIoParser *rilp,
|
||||
guint version, gboolean registered)
|
||||
{
|
||||
struct ril_cell *cell = g_new0(struct ril_cell, 1);
|
||||
struct ril_cell_info_lte *lte = &cell->info.lte;
|
||||
struct sailfish_cell *cell = g_slice_new0(struct sailfish_cell);
|
||||
struct sailfish_cell_info_lte *lte = &cell->info.lte;
|
||||
|
||||
/* Optional RIL_CellIdentityLte_v12 part */
|
||||
lte->earfcn = INT_MAX;
|
||||
if (grilio_parser_get_int32(rilp, <e->mcc) &&
|
||||
grilio_parser_get_int32(rilp, <e->mnc) &&
|
||||
grilio_parser_get_int32(rilp, <e->ci) &&
|
||||
grilio_parser_get_int32(rilp, <e->pci) &&
|
||||
grilio_parser_get_int32(rilp, <e->tac) &&
|
||||
(version < 12 || /* RIL_CellIdentityLte_v12 part */
|
||||
grilio_parser_get_int32(rilp, <e->earfcn)) &&
|
||||
grilio_parser_get_int32(rilp, <e->signalStrength) &&
|
||||
grilio_parser_get_int32(rilp, <e->rsrp) &&
|
||||
grilio_parser_get_int32(rilp, <e->rsrq) &&
|
||||
@@ -208,40 +190,44 @@ static struct ril_cell *ril_cell_info_parse_cell_lte(GRilIoParser *rilp,
|
||||
grilio_parser_get_int32(rilp, <e->cqi) &&
|
||||
grilio_parser_get_int32(rilp, <e->timingAdvance)) {
|
||||
DBG("[lte] reg=%d,mcc=%d,mnc=%d,ci=%d,pci=%d,tac=%d,"
|
||||
"strength=%d,rsrp=%d,rsrq=0x%x,rssnr=0x%x,cqi=%d,"
|
||||
"strength=%d,rsrp=%d,rsrq=%d,rssnr=%d,cqi=%d,"
|
||||
"t=0x%x", registered, lte->mcc, lte->mnc, lte->ci,
|
||||
lte->pci, lte->tac, lte->signalStrength, lte->rsrp,
|
||||
lte->rsrq, lte->rssnr, lte->cqi, lte->timingAdvance);
|
||||
cell->type = RIL_CELL_INFO_TYPE_LTE;
|
||||
cell->type = SAILFISH_CELL_TYPE_LTE;
|
||||
cell->registered = registered;
|
||||
return cell;
|
||||
}
|
||||
|
||||
ofono_error("failed to parse LTE cell info");
|
||||
g_free(cell);
|
||||
ril_cell_free(cell);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static enum ril_cell_info_type ril_cell_info_parse_cell(GRilIoParser *rilp,
|
||||
struct ril_cell **cell_ptr)
|
||||
static gboolean ril_cell_info_parse_cell(GRilIoParser *rilp, guint v,
|
||||
struct sailfish_cell **cell_ptr)
|
||||
{
|
||||
int type, reg;
|
||||
|
||||
if (grilio_parser_get_int32(rilp, &type) &&
|
||||
grilio_parser_get_int32(rilp, ®) &&
|
||||
/* Skip timestamp */
|
||||
grilio_parser_get_int32_array(rilp, NULL, 3)) {
|
||||
int skip = 0;
|
||||
struct ril_cell *cell = NULL;
|
||||
struct sailfish_cell *cell = NULL;
|
||||
|
||||
/* Normalize the boolean value */
|
||||
reg = (reg != FALSE);
|
||||
|
||||
switch (type) {
|
||||
case RIL_CELL_INFO_TYPE_GSM:
|
||||
cell = ril_cell_info_parse_cell_gsm(rilp, reg);
|
||||
cell = ril_cell_info_parse_cell_gsm(rilp, v, reg);
|
||||
break;
|
||||
case RIL_CELL_INFO_TYPE_WCDMA:
|
||||
cell = ril_cell_info_parse_cell_wcdma(rilp, reg);
|
||||
cell = ril_cell_info_parse_cell_wcdma(rilp, v, reg);
|
||||
break;
|
||||
case RIL_CELL_INFO_TYPE_LTE:
|
||||
cell = ril_cell_info_parse_cell_lte(rilp, reg);
|
||||
cell = ril_cell_info_parse_cell_lte(rilp, v, reg);
|
||||
break;
|
||||
case RIL_CELL_INFO_TYPE_CDMA:
|
||||
skip = 10;
|
||||
@@ -256,20 +242,20 @@ static enum ril_cell_info_type ril_cell_info_parse_cell(GRilIoParser *rilp,
|
||||
|
||||
if (cell) {
|
||||
*cell_ptr = cell;
|
||||
return type;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (skip && grilio_parser_get_int32_array(rilp, NULL, skip)) {
|
||||
*cell_ptr = NULL;
|
||||
return type;
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
*cell_ptr = NULL;
|
||||
return RIL_CELL_INFO_TYPE_NONE;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static GSList *ril_cell_info_parse_list(const void *data, guint len)
|
||||
static GSList *ril_cell_info_parse_list(guint v, const void *data, guint len)
|
||||
{
|
||||
GSList *l = NULL;
|
||||
GRilIoParser rilp;
|
||||
@@ -277,17 +263,18 @@ static GSList *ril_cell_info_parse_list(const void *data, guint len)
|
||||
|
||||
grilio_parser_init(&rilp, data, len);
|
||||
if (grilio_parser_get_int32(&rilp, &n) && n > 0) {
|
||||
struct ril_cell *c;
|
||||
struct sailfish_cell *c;
|
||||
|
||||
DBG("%d cell(s):", n);
|
||||
for (i=0; i<n && ril_cell_info_parse_cell(&rilp, &c); i++) {
|
||||
for (i=0; i<n && ril_cell_info_parse_cell(&rilp, v, &c); i++) {
|
||||
if (c) {
|
||||
l = g_slist_insert_sorted(l, c,
|
||||
ril_cell_compare_func);
|
||||
sailfish_cell_compare_func);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GASSERT(grilio_parser_at_end(&rilp));
|
||||
return l;
|
||||
}
|
||||
|
||||
@@ -297,40 +284,39 @@ static void ril_cell_info_list_changed_cb(GRilIoChannel *io, guint code,
|
||||
struct ril_cell_info *self = RIL_CELL_INFO(user_data);
|
||||
|
||||
DBG_(self, "");
|
||||
ril_cell_info_update_cells(self, ril_cell_info_parse_list(data, len));
|
||||
ril_cell_info_update_cells(self, ril_cell_info_parse_list
|
||||
(io->ril_version, data, len));
|
||||
}
|
||||
|
||||
static void ril_cell_info_list_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_cell_info *self = RIL_CELL_INFO(user_data);
|
||||
struct ril_cell_info_priv *priv = self->priv;
|
||||
|
||||
DBG_(self, "");
|
||||
GASSERT(priv->query_id);
|
||||
priv->query_id = 0;
|
||||
ril_cell_info_update_cells(self, ril_cell_info_parse_list(data, len));
|
||||
GASSERT(self->query_id);
|
||||
self->query_id = 0;
|
||||
ril_cell_info_update_cells(self, ril_cell_info_parse_list
|
||||
(io->ril_version, data, len));
|
||||
}
|
||||
|
||||
static void ril_cell_info_set_rate_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_cell_info *self = RIL_CELL_INFO(user_data);
|
||||
struct ril_cell_info_priv *priv = self->priv;
|
||||
|
||||
DBG_(self, "");
|
||||
GASSERT(priv->set_rate_id);
|
||||
priv->set_rate_id = 0;
|
||||
GASSERT(self->set_rate_id);
|
||||
self->set_rate_id = 0;
|
||||
}
|
||||
|
||||
static void ril_cell_info_query(struct ril_cell_info *self)
|
||||
{
|
||||
struct ril_cell_info_priv *priv = self->priv;
|
||||
GRilIoRequest *req = grilio_request_new();
|
||||
|
||||
grilio_request_set_retry(req, RIL_RETRY_MS, -1);
|
||||
grilio_channel_cancel_request(priv->io, priv->query_id, FALSE);
|
||||
priv->query_id = grilio_channel_send_request_full(priv->io, req,
|
||||
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,
|
||||
NULL, self);
|
||||
grilio_request_unref(req);
|
||||
@@ -338,14 +324,13 @@ static void ril_cell_info_query(struct ril_cell_info *self)
|
||||
|
||||
static void ril_cell_info_set_rate(struct ril_cell_info *self, int ms)
|
||||
{
|
||||
struct ril_cell_info_priv *priv = self->priv;
|
||||
GRilIoRequest *req = grilio_request_sized_new(8);
|
||||
|
||||
grilio_request_append_int32(req, 1);
|
||||
grilio_request_append_int32(req, ms);
|
||||
grilio_request_set_retry(req, RIL_RETRY_MS, -1);
|
||||
grilio_channel_cancel_request(priv->io, priv->set_rate_id, FALSE);
|
||||
priv->set_rate_id = grilio_channel_send_request_full(priv->io, req,
|
||||
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,
|
||||
ril_cell_info_set_rate_cb, NULL, self);
|
||||
grilio_request_unref(req);
|
||||
@@ -353,29 +338,24 @@ 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)
|
||||
{
|
||||
struct ril_cell_info_priv *priv = self->priv;
|
||||
|
||||
ril_cell_info_set_rate(self,
|
||||
(priv->display->state == MCE_DISPLAY_STATE_OFF) ?
|
||||
(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);
|
||||
struct ril_cell_info_priv *priv = self->priv;
|
||||
|
||||
if (priv->sim_card_ready) {
|
||||
if (self->sim_card_ready) {
|
||||
ril_cell_info_update_rate(self);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_cell_info_refresh(struct ril_cell_info *self)
|
||||
{
|
||||
struct ril_cell_info_priv *priv = self->priv;
|
||||
|
||||
/* RIL_REQUEST_GET_CELL_INFO_LIST fails without SIM card */
|
||||
if (priv->radio->state == RADIO_STATE_ON && priv->sim_card_ready) {
|
||||
if (self->radio->state == RADIO_STATE_ON && self->sim_card_ready) {
|
||||
ril_cell_info_query(self);
|
||||
} else {
|
||||
ril_cell_info_update_cells(self, NULL);
|
||||
@@ -393,124 +373,160 @@ 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);
|
||||
struct ril_cell_info_priv *priv = self->priv;
|
||||
const gboolean sim_card_was_ready = priv->sim_card_ready;
|
||||
const gboolean sim_card_was_ready = self->sim_card_ready;
|
||||
|
||||
DBG_(self, "%sready", ril_sim_card_ready(sim) ? "" : "not ");
|
||||
priv->sim_card_ready = ril_sim_card_ready(sim);
|
||||
if (priv->sim_card_ready != sim_card_was_ready) {
|
||||
self->sim_card_ready = ril_sim_card_ready(sim);
|
||||
if (self->sim_card_ready != sim_card_was_ready) {
|
||||
ril_cell_info_refresh(self);
|
||||
if (priv->sim_card_ready) {
|
||||
if (self->sim_card_ready) {
|
||||
ril_cell_info_update_rate(self);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gulong ril_cell_info_add_cells_changed_handler(struct ril_cell_info *self,
|
||||
ril_cell_info_cb_t cb, void *arg)
|
||||
/* sailfish_cell_info interface callbacks */
|
||||
|
||||
struct ril_cell_info_signal_data {
|
||||
sailfish_cell_info_cb_t cb;
|
||||
void *arg;
|
||||
};
|
||||
|
||||
static inline struct ril_cell_info *ril_cell_info_cast
|
||||
(struct sailfish_cell_info *info)
|
||||
{
|
||||
return (G_LIKELY(self) && G_LIKELY(cb)) ? g_signal_connect(self,
|
||||
SIGNAL_CELLS_CHANGED_NAME, G_CALLBACK(cb), arg) : 0;
|
||||
return G_CAST(info, struct ril_cell_info, info);
|
||||
}
|
||||
|
||||
void ril_cell_info_remove_handler(struct ril_cell_info *self, gulong id)
|
||||
static void ril_cell_info_ref_proc(struct sailfish_cell_info *info)
|
||||
{
|
||||
if (G_LIKELY(self) && G_LIKELY(id)) {
|
||||
g_signal_handler_disconnect(self, id);
|
||||
g_object_ref(ril_cell_info_cast(info));
|
||||
}
|
||||
|
||||
static void ril_cell_info_unref_proc(struct sailfish_cell_info *info)
|
||||
{
|
||||
g_object_unref(ril_cell_info_cast(info));
|
||||
}
|
||||
|
||||
static void ril_cell_info_cells_changed_cb(struct ril_cell_info *self,
|
||||
void *user_data)
|
||||
{
|
||||
struct ril_cell_info_signal_data *data = user_data;
|
||||
|
||||
data->cb(&self->info, data->arg);
|
||||
}
|
||||
|
||||
static void ril_cell_info_cells_disconnect_notify(gpointer data,
|
||||
GClosure *closure)
|
||||
{
|
||||
g_slice_free1(sizeof(struct ril_cell_info_signal_data), data);
|
||||
}
|
||||
|
||||
static gulong ril_cell_info_add_cells_changed_handler_proc
|
||||
(struct sailfish_cell_info *info,
|
||||
sailfish_cell_info_cb_t cb, void *arg)
|
||||
{
|
||||
if (cb) {
|
||||
struct ril_cell_info_signal_data *data =
|
||||
g_slice_new(struct ril_cell_info_signal_data);
|
||||
|
||||
data->cb = cb;
|
||||
data->arg = arg;
|
||||
return g_signal_connect_data(ril_cell_info_cast(info),
|
||||
SIGNAL_CELLS_CHANGED_NAME,
|
||||
G_CALLBACK(ril_cell_info_cells_changed_cb),
|
||||
data, ril_cell_info_cells_disconnect_notify,
|
||||
G_CONNECT_AFTER);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
struct ril_cell_info *ril_cell_info_new(GRilIoChannel *io,
|
||||
static void ril_cell_info_remove_handler_proc(struct sailfish_cell_info *info,
|
||||
gulong id)
|
||||
{
|
||||
if (G_LIKELY(id)) {
|
||||
g_signal_handler_disconnect(ril_cell_info_cast(info), id);
|
||||
}
|
||||
}
|
||||
|
||||
struct sailfish_cell_info *ril_cell_info_new(GRilIoChannel *io,
|
||||
const char *log_prefix, MceDisplay *display,
|
||||
struct ril_radio *radio, struct ril_sim_card *sim_card)
|
||||
{
|
||||
struct ril_cell_info *self = g_object_new(RIL_CELL_INFO_TYPE, 0);
|
||||
struct ril_cell_info_priv *priv = self->priv;
|
||||
static const struct sailfish_cell_info_proc ril_cell_info_proc = {
|
||||
ril_cell_info_ref_proc,
|
||||
ril_cell_info_unref_proc,
|
||||
ril_cell_info_add_cells_changed_handler_proc,
|
||||
ril_cell_info_remove_handler_proc
|
||||
};
|
||||
|
||||
priv->io = grilio_channel_ref(io);
|
||||
priv->display = mce_display_ref(display);
|
||||
priv->radio = ril_radio_ref(radio);
|
||||
priv->sim_card = ril_sim_card_ref(sim_card);
|
||||
priv->log_prefix = (log_prefix && log_prefix[0]) ?
|
||||
struct ril_cell_info *self = g_object_new(RIL_CELL_INFO_TYPE, 0);
|
||||
|
||||
self->info.proc = &ril_cell_info_proc;
|
||||
self->io = grilio_channel_ref(io);
|
||||
self->display = mce_display_ref(display);
|
||||
self->radio = ril_radio_ref(radio);
|
||||
self->sim_card = ril_sim_card_ref(sim_card);
|
||||
self->log_prefix = (log_prefix && log_prefix[0]) ?
|
||||
g_strconcat(log_prefix, " ", NULL) : g_strdup("");
|
||||
DBG_(self, "");
|
||||
priv->event_id = grilio_channel_add_unsol_event_handler(priv->io,
|
||||
self->event_id = grilio_channel_add_unsol_event_handler(self->io,
|
||||
ril_cell_info_list_changed_cb, RIL_UNSOL_CELL_INFO_LIST, self);
|
||||
priv->display_state_event_id =
|
||||
self->display_state_event_id =
|
||||
mce_display_add_state_changed_handler(display,
|
||||
ril_cell_info_display_state_cb, self);
|
||||
priv->radio_state_event_id =
|
||||
self->radio_state_event_id =
|
||||
ril_radio_add_state_changed_handler(radio,
|
||||
ril_cell_info_radio_state_cb, self);
|
||||
priv->sim_status_event_id =
|
||||
ril_sim_card_add_status_changed_handler(priv->sim_card,
|
||||
self->sim_status_event_id =
|
||||
ril_sim_card_add_status_changed_handler(self->sim_card,
|
||||
ril_cell_info_sim_status_cb, self);
|
||||
priv->sim_card_ready = ril_sim_card_ready(sim_card);
|
||||
if (priv->sim_card_ready) {
|
||||
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);
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
struct ril_cell_info *ril_cell_info_ref(struct ril_cell_info *self)
|
||||
{
|
||||
if (G_LIKELY(self)) {
|
||||
g_object_ref(RIL_CELL_INFO(self));
|
||||
return self;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void ril_cell_info_unref(struct ril_cell_info *self)
|
||||
{
|
||||
if (G_LIKELY(self)) {
|
||||
g_object_unref(RIL_CELL_INFO(self));
|
||||
}
|
||||
return &self->info;
|
||||
}
|
||||
|
||||
static void ril_cell_info_init(struct ril_cell_info *self)
|
||||
{
|
||||
self->priv = G_TYPE_INSTANCE_GET_PRIVATE(self, RIL_CELL_INFO_TYPE,
|
||||
struct ril_cell_info_priv);
|
||||
}
|
||||
|
||||
static void ril_cell_info_dispose(GObject *object)
|
||||
{
|
||||
struct ril_cell_info *self = RIL_CELL_INFO(object);
|
||||
struct ril_cell_info_priv *priv = self->priv;
|
||||
|
||||
grilio_channel_remove_handlers(priv->io, &priv->event_id, 1);
|
||||
if (priv->query_id) {
|
||||
grilio_channel_cancel_request(priv->io, priv->query_id, FALSE);
|
||||
priv->query_id = 0;
|
||||
grilio_channel_remove_handlers(self->io, &self->event_id, 1);
|
||||
if (self->query_id) {
|
||||
grilio_channel_cancel_request(self->io, self->query_id, FALSE);
|
||||
self->query_id = 0;
|
||||
}
|
||||
if (priv->set_rate_id) {
|
||||
grilio_channel_cancel_request(priv->io, priv->set_rate_id,
|
||||
if (self->set_rate_id) {
|
||||
grilio_channel_cancel_request(self->io, self->set_rate_id,
|
||||
FALSE);
|
||||
priv->set_rate_id = 0;
|
||||
self->set_rate_id = 0;
|
||||
}
|
||||
gutil_disconnect_handlers(priv->display,
|
||||
&priv->display_state_event_id, 1);
|
||||
ril_radio_remove_handlers(priv->radio, &priv->radio_state_event_id, 1);
|
||||
ril_sim_card_remove_handlers(priv->sim_card,
|
||||
&priv->sim_status_event_id, 1);
|
||||
gutil_disconnect_handlers(self->display,
|
||||
&self->display_state_event_id, 1);
|
||||
ril_radio_remove_handlers(self->radio, &self->radio_state_event_id, 1);
|
||||
ril_sim_card_remove_handlers(self->sim_card,
|
||||
&self->sim_status_event_id, 1);
|
||||
G_OBJECT_CLASS(ril_cell_info_parent_class)->dispose(object);
|
||||
}
|
||||
|
||||
static void ril_cell_info_finalize(GObject *object)
|
||||
{
|
||||
struct ril_cell_info *self = RIL_CELL_INFO(object);
|
||||
struct ril_cell_info_priv *priv = self->priv;
|
||||
|
||||
DBG_(self, "");
|
||||
g_free(priv->log_prefix);
|
||||
grilio_channel_unref(priv->io);
|
||||
mce_display_unref(priv->display);
|
||||
ril_radio_unref(priv->radio);
|
||||
ril_sim_card_unref(priv->sim_card);
|
||||
g_slist_free_full(self->cells, g_free);
|
||||
g_free(self->log_prefix);
|
||||
grilio_channel_unref(self->io);
|
||||
mce_display_unref(self->display);
|
||||
ril_radio_unref(self->radio);
|
||||
ril_sim_card_unref(self->sim_card);
|
||||
g_slist_free_full(self->info.cells, ril_cell_free1);
|
||||
G_OBJECT_CLASS(ril_cell_info_parent_class)->finalize(object);
|
||||
}
|
||||
|
||||
@@ -520,7 +536,6 @@ static void ril_cell_info_class_init(RilCellInfoClass *klass)
|
||||
|
||||
object_class->dispose = ril_cell_info_dispose;
|
||||
object_class->finalize = ril_cell_info_finalize;
|
||||
g_type_class_add_private(klass, sizeof(struct ril_cell_info_priv));
|
||||
ril_cell_info_signals[SIGNAL_CELLS_CHANGED] =
|
||||
g_signal_new(SIGNAL_CELLS_CHANGED_NAME,
|
||||
G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_FIRST,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2016 Jolla Ltd.
|
||||
* 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
|
||||
@@ -18,40 +18,11 @@
|
||||
|
||||
#include "ril_types.h"
|
||||
#include <mce_display.h>
|
||||
#include <sailfish_cell_info.h>
|
||||
|
||||
struct ril_cell {
|
||||
enum ril_cell_info_type type;
|
||||
gboolean registered;
|
||||
union {
|
||||
struct ril_cell_info_gsm gsm;
|
||||
struct ril_cell_info_wcdma wcdma;
|
||||
struct ril_cell_info_lte lte;
|
||||
} info;
|
||||
};
|
||||
|
||||
struct ril_cell_info_priv;
|
||||
struct ril_cell_info {
|
||||
GObject object;
|
||||
struct ril_cell_info_priv *priv;
|
||||
GSList *cells;
|
||||
};
|
||||
|
||||
typedef void (*ril_cell_info_cb_t)(struct ril_cell_info *info, void *arg);
|
||||
|
||||
gint ril_cell_compare_func(gconstpointer v1, gconstpointer v2);
|
||||
gint ril_cell_compare_location(const struct ril_cell *c1,
|
||||
const struct ril_cell *c2);
|
||||
|
||||
struct ril_cell_info *ril_cell_info_new(GRilIoChannel *io,
|
||||
struct sailfish_cell_info *ril_cell_info_new(GRilIoChannel *io,
|
||||
const char *log_prefix, MceDisplay *display,
|
||||
struct ril_radio *radio, struct ril_sim_card *sim_card);
|
||||
struct ril_cell_info *ril_cell_info_ref(struct ril_cell_info *info);
|
||||
void ril_cell_info_unref(struct ril_cell_info *info);
|
||||
struct ril_cell *ril_cell_find_cell(struct ril_cell_info *info,
|
||||
const struct ril_cell *cell);
|
||||
gulong ril_cell_info_add_cells_changed_handler(struct ril_cell_info *info,
|
||||
ril_cell_info_cb_t cb, void *arg);
|
||||
void ril_cell_info_remove_handler(struct ril_cell_info *info, gulong id);
|
||||
|
||||
#endif /* RIL_CELL_INFO_H */
|
||||
|
||||
|
||||
@@ -1,586 +0,0 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2016 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_cell_info.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
#include <ofono/dbus.h>
|
||||
|
||||
#include <gdbus.h>
|
||||
|
||||
struct ril_cell_entry {
|
||||
guint cell_id;
|
||||
char *path;
|
||||
struct ril_cell cell;
|
||||
};
|
||||
|
||||
struct ril_cell_info_dbus {
|
||||
struct ril_modem *md;
|
||||
struct ril_cell_info *info;
|
||||
DBusConnection *conn;
|
||||
char *path;
|
||||
gulong handler_id;
|
||||
guint next_cell_id;
|
||||
GSList *entries;
|
||||
};
|
||||
|
||||
#define RIL_CELL_INFO_DBUS_INTERFACE "org.nemomobile.ofono.CellInfo"
|
||||
#define RIL_CELL_INFO_DBUS_CELLS_ADDED_SIGNAL "CellsAdded"
|
||||
#define RIL_CELL_INFO_DBUS_CELLS_REMOVED_SIGNAL "CellsRemoved"
|
||||
|
||||
#define RIL_CELL_DBUS_INTERFACE_VERSION (1)
|
||||
#define RIL_CELL_DBUS_INTERFACE "org.nemomobile.ofono.Cell"
|
||||
#define RIL_CELL_DBUS_REGISTERED_CHANGED_SIGNAL "RegisteredChanged"
|
||||
#define RIL_CELL_DBUS_PROPERTY_CHANGED_SIGNAL "PropertyChanged"
|
||||
#define RIL_CELL_DBUS_REMOVED_SIGNAL "Removed"
|
||||
|
||||
struct ril_cell_property {
|
||||
const char *name;
|
||||
glong off;
|
||||
int flag;
|
||||
};
|
||||
|
||||
#define RIL_CELL_GSM_PROPERTY(value,name) \
|
||||
{ #name, G_STRUCT_OFFSET(struct ril_cell_info_gsm,name), value }
|
||||
#define RIL_CELL_WCDMA_PROPERTY(value,name) \
|
||||
{ #name, G_STRUCT_OFFSET(struct ril_cell_info_wcdma,name), value }
|
||||
#define RIL_CELL_LTE_PROPERTY(value,name) \
|
||||
{ #name, G_STRUCT_OFFSET(struct ril_cell_info_lte,name), value }
|
||||
|
||||
static const struct ril_cell_property ril_cell_gsm_properties [] = {
|
||||
RIL_CELL_GSM_PROPERTY(0x01,mcc),
|
||||
RIL_CELL_GSM_PROPERTY(0x02,mnc),
|
||||
RIL_CELL_GSM_PROPERTY(0x04,lac),
|
||||
RIL_CELL_GSM_PROPERTY(0x08,cid),
|
||||
RIL_CELL_GSM_PROPERTY(0x10,signalStrength),
|
||||
RIL_CELL_GSM_PROPERTY(0x20,bitErrorRate)
|
||||
};
|
||||
|
||||
static const struct ril_cell_property ril_cell_wcdma_properties [] = {
|
||||
RIL_CELL_WCDMA_PROPERTY(0x01,mcc),
|
||||
RIL_CELL_WCDMA_PROPERTY(0x02,mnc),
|
||||
RIL_CELL_WCDMA_PROPERTY(0x04,lac),
|
||||
RIL_CELL_WCDMA_PROPERTY(0x08,cid),
|
||||
RIL_CELL_WCDMA_PROPERTY(0x10,psc),
|
||||
RIL_CELL_WCDMA_PROPERTY(0x20,signalStrength),
|
||||
RIL_CELL_WCDMA_PROPERTY(0x40,bitErrorRate)
|
||||
};
|
||||
|
||||
static const struct ril_cell_property ril_cell_lte_properties [] = {
|
||||
RIL_CELL_LTE_PROPERTY(0x001,mcc),
|
||||
RIL_CELL_LTE_PROPERTY(0x002,mnc),
|
||||
RIL_CELL_LTE_PROPERTY(0x004,ci),
|
||||
RIL_CELL_LTE_PROPERTY(0x008,pci),
|
||||
RIL_CELL_LTE_PROPERTY(0x010,tac),
|
||||
RIL_CELL_LTE_PROPERTY(0x020,signalStrength),
|
||||
RIL_CELL_LTE_PROPERTY(0x040,rsrp),
|
||||
RIL_CELL_LTE_PROPERTY(0x080,rsrq),
|
||||
RIL_CELL_LTE_PROPERTY(0x100,rssnr),
|
||||
RIL_CELL_LTE_PROPERTY(0x200,cqi),
|
||||
RIL_CELL_LTE_PROPERTY(0x400,timingAdvance)
|
||||
};
|
||||
|
||||
#define RIL_CELL_PROPERTY_REGISTERED 0x1000
|
||||
|
||||
typedef void (*ril_cell_info_dbus_append_fn)(DBusMessageIter *it,
|
||||
const struct ril_cell_entry *entry);
|
||||
|
||||
static const char *ril_cell_info_dbus_cell_type_str(enum ril_cell_info_type t)
|
||||
{
|
||||
switch (t) {
|
||||
case RIL_CELL_INFO_TYPE_GSM:
|
||||
return "gsm";
|
||||
case RIL_CELL_INFO_TYPE_CDMA:
|
||||
return "cdma";
|
||||
case RIL_CELL_INFO_TYPE_LTE:
|
||||
return "lte";
|
||||
case RIL_CELL_INFO_TYPE_WCDMA:
|
||||
return "wcdma";
|
||||
case RIL_CELL_INFO_TYPE_TD_SCDMA:
|
||||
return "tdscdma";
|
||||
case RIL_CELL_INFO_TYPE_NONE:
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
};
|
||||
|
||||
static const struct ril_cell_property *ril_cell_info_dbus_cell_properties(
|
||||
enum ril_cell_info_type type, int *count)
|
||||
{
|
||||
switch (type) {
|
||||
case RIL_CELL_INFO_TYPE_GSM:
|
||||
*count = G_N_ELEMENTS(ril_cell_gsm_properties);
|
||||
return ril_cell_gsm_properties;
|
||||
case RIL_CELL_INFO_TYPE_WCDMA:
|
||||
*count = G_N_ELEMENTS(ril_cell_wcdma_properties);
|
||||
return ril_cell_wcdma_properties;
|
||||
case RIL_CELL_INFO_TYPE_LTE:
|
||||
*count = G_N_ELEMENTS(ril_cell_lte_properties);
|
||||
return ril_cell_lte_properties;
|
||||
default:
|
||||
*count = 0;
|
||||
return NULL;
|
||||
}
|
||||
};
|
||||
|
||||
static void ril_cell_info_destroy_entry(struct ril_cell_entry *entry)
|
||||
{
|
||||
if (entry) {
|
||||
g_free(entry->path);
|
||||
g_free(entry);
|
||||
}
|
||||
}
|
||||
|
||||
static DBusMessage *ril_cell_info_dbus_reply(DBusMessage *msg,
|
||||
const struct ril_cell_entry *entry,
|
||||
ril_cell_info_dbus_append_fn append)
|
||||
{
|
||||
DBusMessage *reply = dbus_message_new_method_return(msg);
|
||||
DBusMessageIter it;
|
||||
|
||||
dbus_message_iter_init_append(reply, &it);
|
||||
append(&it, entry);
|
||||
return reply;
|
||||
}
|
||||
|
||||
static void ril_cell_info_dbus_append_version(DBusMessageIter *it,
|
||||
const struct ril_cell_entry *entry)
|
||||
{
|
||||
dbus_int32_t version = RIL_CELL_DBUS_INTERFACE_VERSION;
|
||||
|
||||
dbus_message_iter_append_basic(it, DBUS_TYPE_INT32, &version);
|
||||
}
|
||||
|
||||
static void ril_cell_info_dbus_append_type(DBusMessageIter *it,
|
||||
const struct ril_cell_entry *entry)
|
||||
{
|
||||
const char *type = ril_cell_info_dbus_cell_type_str(entry->cell.type);
|
||||
|
||||
dbus_message_iter_append_basic(it, DBUS_TYPE_STRING, &type);
|
||||
}
|
||||
|
||||
static void ril_cell_info_dbus_append_registered(DBusMessageIter *it,
|
||||
const struct ril_cell_entry *entry)
|
||||
{
|
||||
dbus_bool_t registered = entry->cell.registered;
|
||||
|
||||
dbus_message_iter_append_basic(it, DBUS_TYPE_BOOLEAN, ®istered);
|
||||
}
|
||||
|
||||
static void ril_cell_info_dbus_append_properties(DBusMessageIter *it,
|
||||
const struct ril_cell_entry *entry)
|
||||
{
|
||||
int i, n;
|
||||
DBusMessageIter dict;
|
||||
const struct ril_cell *cell = &entry->cell;
|
||||
const struct ril_cell_property *prop =
|
||||
ril_cell_info_dbus_cell_properties(cell->type, &n);
|
||||
|
||||
dbus_message_iter_open_container(it, DBUS_TYPE_ARRAY, "{sv}", &dict);
|
||||
for (i = 0; i < n; i++) {
|
||||
gint32 value = G_STRUCT_MEMBER(int, &cell->info, prop[i].off);
|
||||
if (value != INT_MAX) {
|
||||
ofono_dbus_dict_append(&dict, prop[i].name,
|
||||
DBUS_TYPE_INT32, &value);
|
||||
}
|
||||
}
|
||||
dbus_message_iter_close_container(it, &dict);
|
||||
}
|
||||
|
||||
static void ril_cell_info_dbus_append_all(DBusMessageIter *it,
|
||||
const struct ril_cell_entry *entry)
|
||||
{
|
||||
ril_cell_info_dbus_append_version(it, entry);
|
||||
ril_cell_info_dbus_append_type(it, entry);
|
||||
ril_cell_info_dbus_append_registered(it, entry);
|
||||
ril_cell_info_dbus_append_properties(it, entry);
|
||||
}
|
||||
|
||||
static DBusMessage *ril_cell_info_dbus_cell_get_all(DBusConnection *conn,
|
||||
DBusMessage *msg, void *data)
|
||||
{
|
||||
return ril_cell_info_dbus_reply(msg, (struct ril_cell_entry*)data,
|
||||
ril_cell_info_dbus_append_all);
|
||||
}
|
||||
|
||||
static DBusMessage *ril_cell_info_dbus_cell_get_version(DBusConnection *conn,
|
||||
DBusMessage *msg, void *data)
|
||||
{
|
||||
return ril_cell_info_dbus_reply(msg, (struct ril_cell_entry*)data,
|
||||
ril_cell_info_dbus_append_version);
|
||||
}
|
||||
|
||||
static DBusMessage *ril_cell_info_dbus_cell_get_type(DBusConnection *conn,
|
||||
DBusMessage *msg, void *data)
|
||||
{
|
||||
return ril_cell_info_dbus_reply(msg, (struct ril_cell_entry*)data,
|
||||
ril_cell_info_dbus_append_type);
|
||||
}
|
||||
|
||||
static DBusMessage *ril_cell_info_dbus_cell_get_registered(DBusConnection *conn,
|
||||
DBusMessage *msg, void *data)
|
||||
{
|
||||
return ril_cell_info_dbus_reply(msg, (struct ril_cell_entry*)data,
|
||||
ril_cell_info_dbus_append_registered);
|
||||
}
|
||||
|
||||
static DBusMessage *ril_cell_info_dbus_cell_get_properties(DBusConnection *conn,
|
||||
DBusMessage *msg, void *data)
|
||||
{
|
||||
return ril_cell_info_dbus_reply(msg, (struct ril_cell_entry*)data,
|
||||
ril_cell_info_dbus_append_properties);
|
||||
}
|
||||
|
||||
static const GDBusMethodTable ril_cell_info_dbus_cell_methods[] = {
|
||||
{ GDBUS_METHOD("GetAll", NULL,
|
||||
GDBUS_ARGS({ "version", "i" },
|
||||
{ "type", "s" },
|
||||
{ "registered", "b" },
|
||||
{ "properties", "a{sv}" }),
|
||||
ril_cell_info_dbus_cell_get_all) },
|
||||
{ GDBUS_METHOD("GetInterfaceVersion", NULL,
|
||||
GDBUS_ARGS({ "version", "i" }),
|
||||
ril_cell_info_dbus_cell_get_version) },
|
||||
{ GDBUS_METHOD("GetType", NULL,
|
||||
GDBUS_ARGS({ "type", "s" }),
|
||||
ril_cell_info_dbus_cell_get_type) },
|
||||
{ GDBUS_METHOD("GetRegistered", NULL,
|
||||
GDBUS_ARGS({ "registered", "b" }),
|
||||
ril_cell_info_dbus_cell_get_registered) },
|
||||
{ GDBUS_METHOD("GetProperties", NULL,
|
||||
GDBUS_ARGS({ "properties", "a{sv}" }),
|
||||
ril_cell_info_dbus_cell_get_properties) },
|
||||
{ }
|
||||
};
|
||||
|
||||
static const GDBusSignalTable ril_cell_info_dbus_cell_signals[] = {
|
||||
{ GDBUS_SIGNAL(RIL_CELL_DBUS_REGISTERED_CHANGED_SIGNAL,
|
||||
GDBUS_ARGS({ "registered", "b" })) },
|
||||
{ GDBUS_SIGNAL(RIL_CELL_DBUS_PROPERTY_CHANGED_SIGNAL,
|
||||
GDBUS_ARGS({ "name", "s" }, { "value", "v" })) },
|
||||
{ GDBUS_SIGNAL(RIL_CELL_DBUS_REMOVED_SIGNAL,
|
||||
GDBUS_ARGS({})) },
|
||||
{ }
|
||||
};
|
||||
|
||||
static struct ril_cell_entry *ril_cell_info_dbus_find_id(
|
||||
struct ril_cell_info_dbus *dbus, guint id)
|
||||
{
|
||||
GSList *l;
|
||||
for (l = dbus->entries; l; l = l->next) {
|
||||
struct ril_cell_entry *entry = l->data;
|
||||
if (entry->cell_id == id) {
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static guint ril_cell_info_dbus_next_cell_id(struct ril_cell_info_dbus *dbus)
|
||||
{
|
||||
while (ril_cell_info_dbus_find_id(dbus, dbus->next_cell_id)) {
|
||||
dbus->next_cell_id++;
|
||||
}
|
||||
return dbus->next_cell_id++;
|
||||
}
|
||||
|
||||
static struct ril_cell_entry *ril_cell_info_dbus_find_cell(
|
||||
struct ril_cell_info_dbus *dbus, const struct ril_cell *cell)
|
||||
{
|
||||
if (cell) {
|
||||
GSList *l;
|
||||
for (l = dbus->entries; l; l = l->next) {
|
||||
struct ril_cell_entry *entry = l->data;
|
||||
if (!ril_cell_compare_location(&entry->cell, cell)) {
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void ril_cell_info_dbus_emit_path_list(struct ril_cell_info_dbus *dbus,
|
||||
const char *name, GPtrArray *list)
|
||||
{
|
||||
guint i;
|
||||
DBusMessageIter it, array;
|
||||
DBusMessage *signal = dbus_message_new_signal(dbus->path,
|
||||
RIL_CELL_INFO_DBUS_INTERFACE, name);
|
||||
|
||||
dbus_message_iter_init_append(signal, &it);
|
||||
dbus_message_iter_open_container(&it, DBUS_TYPE_ARRAY, "o", &array);
|
||||
for (i = 0; i < list->len; i++) {
|
||||
const char* path = list->pdata[i];
|
||||
dbus_message_iter_append_basic(&array, DBUS_TYPE_OBJECT_PATH,
|
||||
&path);
|
||||
}
|
||||
dbus_message_iter_close_container(&it, &array);
|
||||
|
||||
g_dbus_send_message(dbus->conn, signal);
|
||||
}
|
||||
|
||||
static int ril_cell_info_dbus_compare(const struct ril_cell *c1,
|
||||
const struct ril_cell *c2)
|
||||
{
|
||||
if (c1->type == c2->type) {
|
||||
int i, n, mask = 0;
|
||||
const struct ril_cell_property *prop =
|
||||
ril_cell_info_dbus_cell_properties(c1->type, &n);
|
||||
|
||||
if (c1->registered != c2->registered) {
|
||||
mask |= RIL_CELL_PROPERTY_REGISTERED;
|
||||
}
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
const glong offset = prop[i].off;
|
||||
gint32 v1 = G_STRUCT_MEMBER(int, &c1->info, offset);
|
||||
gint32 v2 = G_STRUCT_MEMBER(int, &c2->info, offset);
|
||||
if (v1 != v2) {
|
||||
mask |= prop[i].flag;
|
||||
}
|
||||
}
|
||||
|
||||
return mask;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_cell_info_dbus_property_changed(struct ril_cell_info_dbus *dbus,
|
||||
const struct ril_cell_entry *entry, int mask)
|
||||
{
|
||||
int i, n;
|
||||
const struct ril_cell *cell = &entry->cell;
|
||||
const struct ril_cell_property *prop =
|
||||
ril_cell_info_dbus_cell_properties(cell->type, &n);
|
||||
|
||||
if (mask & RIL_CELL_PROPERTY_REGISTERED) {
|
||||
dbus_bool_t registered = cell->registered;
|
||||
g_dbus_emit_signal(dbus->conn, entry->path,
|
||||
RIL_CELL_DBUS_INTERFACE,
|
||||
RIL_CELL_DBUS_REGISTERED_CHANGED_SIGNAL,
|
||||
DBUS_TYPE_BOOLEAN, ®istered, DBUS_TYPE_INVALID);
|
||||
mask &= ~RIL_CELL_PROPERTY_REGISTERED;
|
||||
}
|
||||
|
||||
for (i = 0; i < n && mask; i++) {
|
||||
if (mask & prop[i].flag) {
|
||||
ofono_dbus_signal_property_changed(dbus->conn,
|
||||
entry->path, RIL_CELL_DBUS_INTERFACE,
|
||||
prop[i].name, DBUS_TYPE_INT32,
|
||||
G_STRUCT_MEMBER_P(&cell->info, prop[i].off));
|
||||
mask &= ~prop[i].flag;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_cell_info_dbus_update_entries(struct ril_cell_info_dbus *dbus,
|
||||
gboolean emit_signals)
|
||||
{
|
||||
GSList *l;
|
||||
GPtrArray* added = NULL;
|
||||
GPtrArray* removed = NULL;
|
||||
|
||||
/* Remove non-existent cells */
|
||||
l = dbus->entries;
|
||||
while (l) {
|
||||
GSList *next = l->next;
|
||||
struct ril_cell_entry *entry = l->data;
|
||||
if (!g_slist_find_custom(dbus->info->cells, &entry->cell,
|
||||
ril_cell_compare_func)) {
|
||||
DBG("%s removed", entry->path);
|
||||
dbus->entries = g_slist_delete_link(dbus->entries, l);
|
||||
g_dbus_emit_signal(dbus->conn, entry->path,
|
||||
RIL_CELL_DBUS_INTERFACE,
|
||||
RIL_CELL_DBUS_REMOVED_SIGNAL,
|
||||
DBUS_TYPE_INVALID);
|
||||
g_dbus_unregister_interface(dbus->conn, entry->path,
|
||||
RIL_CELL_DBUS_INTERFACE);
|
||||
if (emit_signals) {
|
||||
if (!removed) {
|
||||
removed =
|
||||
g_ptr_array_new_with_free_func(
|
||||
g_free);
|
||||
}
|
||||
/* Steal the path */
|
||||
g_ptr_array_add(removed, entry->path);
|
||||
entry->path = NULL;
|
||||
}
|
||||
ril_cell_info_destroy_entry(entry);
|
||||
}
|
||||
l = next;
|
||||
}
|
||||
|
||||
/* Add new cells */
|
||||
for (l = dbus->info->cells; l; l = l->next) {
|
||||
const struct ril_cell *cell = l->data;
|
||||
struct ril_cell_entry *entry =
|
||||
ril_cell_info_dbus_find_cell(dbus, cell);
|
||||
|
||||
if (entry) {
|
||||
if (emit_signals) {
|
||||
int diff = ril_cell_info_dbus_compare(cell,
|
||||
&entry->cell);
|
||||
entry->cell = *cell;
|
||||
ril_cell_info_dbus_property_changed(dbus,
|
||||
entry, diff);
|
||||
} else {
|
||||
entry->cell = *cell;
|
||||
}
|
||||
} else {
|
||||
entry = g_new0(struct ril_cell_entry, 1);
|
||||
entry->cell = *cell;
|
||||
entry->cell_id = ril_cell_info_dbus_next_cell_id(dbus);
|
||||
entry->path = g_strdup_printf("%s/cell_%u", dbus->path,
|
||||
entry->cell_id);
|
||||
dbus->entries = g_slist_append(dbus->entries, entry);
|
||||
DBG("%s added", entry->path);
|
||||
g_dbus_register_interface(dbus->conn, entry->path,
|
||||
RIL_CELL_DBUS_INTERFACE,
|
||||
ril_cell_info_dbus_cell_methods,
|
||||
ril_cell_info_dbus_cell_signals, NULL,
|
||||
entry, NULL);
|
||||
if (emit_signals) {
|
||||
if (!added) {
|
||||
added = g_ptr_array_new();
|
||||
}
|
||||
g_ptr_array_add(added, entry->path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (removed) {
|
||||
ril_cell_info_dbus_emit_path_list(dbus,
|
||||
RIL_CELL_INFO_DBUS_CELLS_REMOVED_SIGNAL, removed);
|
||||
g_ptr_array_free(removed, TRUE);
|
||||
}
|
||||
|
||||
if (added) {
|
||||
ril_cell_info_dbus_emit_path_list(dbus,
|
||||
RIL_CELL_INFO_DBUS_CELLS_ADDED_SIGNAL, added);
|
||||
g_ptr_array_free(added, TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_cell_info_dbus_cells_changed_cb(struct ril_cell_info *info,
|
||||
void *arg)
|
||||
{
|
||||
DBG("");
|
||||
ril_cell_info_dbus_update_entries((struct ril_cell_info_dbus *)arg,
|
||||
TRUE);
|
||||
}
|
||||
|
||||
static DBusMessage *ril_cell_info_dbus_get_cells(DBusConnection *conn,
|
||||
DBusMessage *msg, void *data)
|
||||
{
|
||||
struct ril_cell_info_dbus *dbus = data;
|
||||
DBusMessage *reply = dbus_message_new_method_return(msg);
|
||||
DBusMessageIter it, array;
|
||||
GSList *l;
|
||||
|
||||
dbus_message_iter_init_append(reply, &it);
|
||||
dbus_message_iter_open_container(&it, DBUS_TYPE_ARRAY, "o", &array);
|
||||
for (l = dbus->entries; l; l = l->next) {
|
||||
const struct ril_cell_entry *entry = l->data;
|
||||
dbus_message_iter_append_basic(&array, DBUS_TYPE_OBJECT_PATH,
|
||||
&entry->path);
|
||||
}
|
||||
dbus_message_iter_close_container(&it, &array);
|
||||
return reply;
|
||||
}
|
||||
|
||||
static const GDBusMethodTable ril_cell_info_dbus_methods[] = {
|
||||
{ GDBUS_METHOD("GetCells", NULL,
|
||||
GDBUS_ARGS({ "paths", "ao" }),
|
||||
ril_cell_info_dbus_get_cells) },
|
||||
{ }
|
||||
};
|
||||
|
||||
static const GDBusSignalTable ril_cell_info_dbus_signals[] = {
|
||||
{ GDBUS_SIGNAL(RIL_CELL_INFO_DBUS_CELLS_ADDED_SIGNAL,
|
||||
GDBUS_ARGS({ "paths", "ao" })) },
|
||||
{ GDBUS_SIGNAL(RIL_CELL_INFO_DBUS_CELLS_REMOVED_SIGNAL,
|
||||
GDBUS_ARGS({ "paths", "ao" })) },
|
||||
{ }
|
||||
};
|
||||
|
||||
struct ril_cell_info_dbus *ril_cell_info_dbus_new(struct ril_modem *md,
|
||||
struct ril_cell_info *info)
|
||||
{
|
||||
struct ril_cell_info_dbus *dbus = g_new0(struct ril_cell_info_dbus, 1);
|
||||
|
||||
DBG("%s", ril_modem_get_path(md));
|
||||
dbus->md = md;
|
||||
dbus->path = g_strdup(ril_modem_get_path(md));
|
||||
dbus->conn = dbus_connection_ref(ofono_dbus_get_connection());
|
||||
dbus->info = ril_cell_info_ref(info);
|
||||
dbus->handler_id = ril_cell_info_add_cells_changed_handler(info,
|
||||
ril_cell_info_dbus_cells_changed_cb, dbus);
|
||||
|
||||
/* Register D-Bus interface */
|
||||
if (g_dbus_register_interface(dbus->conn, dbus->path,
|
||||
RIL_CELL_INFO_DBUS_INTERFACE, ril_cell_info_dbus_methods,
|
||||
ril_cell_info_dbus_signals, NULL, dbus, NULL)) {
|
||||
ofono_modem_add_interface(md->ofono,
|
||||
RIL_CELL_INFO_DBUS_INTERFACE);
|
||||
ril_cell_info_dbus_update_entries(dbus, FALSE);
|
||||
return dbus;
|
||||
} else {
|
||||
ofono_error("RIL D-Bus register failed");
|
||||
ril_cell_info_dbus_free(dbus);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void ril_cell_info_dbus_free(struct ril_cell_info_dbus *dbus)
|
||||
{
|
||||
if (dbus) {
|
||||
GSList *l;
|
||||
|
||||
DBG("%s", dbus->path);
|
||||
g_dbus_unregister_interface(dbus->conn, dbus->path,
|
||||
RIL_CELL_INFO_DBUS_INTERFACE);
|
||||
ofono_modem_remove_interface(dbus->md->ofono,
|
||||
RIL_CELL_INFO_DBUS_INTERFACE);
|
||||
|
||||
/* Unregister cells */
|
||||
l = dbus->entries;
|
||||
while (l) {
|
||||
struct ril_cell_entry *entry = l->data;
|
||||
g_dbus_unregister_interface(dbus->conn, entry->path,
|
||||
RIL_CELL_DBUS_INTERFACE);
|
||||
ril_cell_info_destroy_entry(entry);
|
||||
l = l->next;
|
||||
}
|
||||
g_slist_free(dbus->entries);
|
||||
|
||||
dbus_connection_unref(dbus->conn);
|
||||
|
||||
ril_cell_info_remove_handler(dbus->info, dbus->handler_id);
|
||||
ril_cell_info_unref(dbus->info);
|
||||
|
||||
g_free(dbus->path);
|
||||
g_free(dbus);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2016 Jolla Ltd.
|
||||
* Copyright (C) 2015-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
|
||||
@@ -14,10 +14,15 @@
|
||||
*/
|
||||
|
||||
#include "ril_config.h"
|
||||
#include "ril_util.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
#include <gutil_intarray.h>
|
||||
#include <gutil_ints.h>
|
||||
|
||||
/* Utilities for parsing ril_subscription.conf */
|
||||
|
||||
char* ril_config_get_string(GKeyFile *file, const char *group, const char *key)
|
||||
char *ril_config_get_string(GKeyFile *file, const char *group, const char *key)
|
||||
{
|
||||
char *val = g_key_file_get_string(file, group, key, NULL);
|
||||
|
||||
@@ -29,6 +34,31 @@ char* ril_config_get_string(GKeyFile *file, const char *group, const char *key)
|
||||
return val;
|
||||
}
|
||||
|
||||
char **ril_config_get_strings(GKeyFile *file, const char *group,
|
||||
const char *key, char delimiter)
|
||||
{
|
||||
char *str = ril_config_get_string(file, group, key);
|
||||
|
||||
if (str) {
|
||||
char **strv, **p;
|
||||
char delimiter_str[2];
|
||||
|
||||
delimiter_str[0] = delimiter;
|
||||
delimiter_str[1] = 0;
|
||||
strv = g_strsplit(str, delimiter_str, -1);
|
||||
|
||||
/* Strip whitespaces */
|
||||
for (p = strv; *p; p++) {
|
||||
*p = g_strstrip(*p);
|
||||
}
|
||||
|
||||
g_free(str);
|
||||
return strv;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
gboolean ril_config_get_integer(GKeyFile *file, const char *group,
|
||||
const char *key, int *out_value)
|
||||
{
|
||||
@@ -106,6 +136,93 @@ gboolean ril_config_get_flag(GKeyFile *file, const char *group,
|
||||
}
|
||||
}
|
||||
|
||||
gboolean ril_config_get_enum(GKeyFile *file, const char *group,
|
||||
const char *key, int *result,
|
||||
const char *name, int value, ...)
|
||||
{
|
||||
char *str = ril_config_get_string(file, group, key);
|
||||
|
||||
if (str) {
|
||||
/*
|
||||
* Some people are thinking that # is a comment
|
||||
* anywhere on the line, not just at the beginning
|
||||
*/
|
||||
char *comment = strchr(str, '#');
|
||||
|
||||
if (comment) *comment = 0;
|
||||
g_strstrip(str);
|
||||
if (strcasecmp(str, name)) {
|
||||
va_list args;
|
||||
va_start(args, value);
|
||||
while ((name = va_arg(args, char*)) != NULL) {
|
||||
value = va_arg(args, int);
|
||||
if (!strcasecmp(str, name)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
if (!name) {
|
||||
ofono_error("Invalid %s config value (%s)", key, str);
|
||||
}
|
||||
|
||||
g_free(str);
|
||||
|
||||
if (name) {
|
||||
if (result) {
|
||||
*result = value;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
GUtilInts *ril_config_get_ints(GKeyFile *file, const char *group,
|
||||
const char *key)
|
||||
{
|
||||
char *value = ril_config_get_string(file, group, key);
|
||||
|
||||
if (value) {
|
||||
char **values = g_strsplit(value, ",", -1);
|
||||
char **ptr = values;
|
||||
GUtilIntArray *array = gutil_int_array_new();
|
||||
|
||||
while (*ptr) {
|
||||
int val;
|
||||
|
||||
if (ril_parse_int(*ptr++, 0, &val)) {
|
||||
gutil_int_array_append(array, val);
|
||||
}
|
||||
}
|
||||
|
||||
g_free(value);
|
||||
g_strfreev(values);
|
||||
return gutil_int_array_free_to_ints(array);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *ril_config_ints_to_string(GUtilInts *ints, char separator)
|
||||
{
|
||||
if (ints) {
|
||||
guint i, n;
|
||||
const int *data = gutil_ints_get_data(ints, &n);
|
||||
GString *buf = g_string_new(NULL);
|
||||
|
||||
for (i=0; i<n; i++) {
|
||||
if (buf->len > 0) {
|
||||
g_string_append_c(buf, separator);
|
||||
}
|
||||
g_string_append_printf(buf, "%d", data[i]);
|
||||
}
|
||||
return g_string_free(buf, FALSE);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2016 Jolla Ltd.
|
||||
* Copyright (C) 2015-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
|
||||
@@ -22,13 +22,22 @@
|
||||
|
||||
#define RILCONF_SETTINGS_GROUP "Settings"
|
||||
|
||||
char* ril_config_get_string(GKeyFile *file, const char *group, const char *key);
|
||||
char *ril_config_get_string(GKeyFile *file, const char *group,
|
||||
const char *key);
|
||||
char **ril_config_get_strings(GKeyFile *file, const char *group,
|
||||
const char *key, char delimiter);
|
||||
gboolean ril_config_get_integer(GKeyFile *file, const char *group,
|
||||
const char *key, int *value);
|
||||
gboolean ril_config_get_boolean(GKeyFile *file, const char *group,
|
||||
const char *key, gboolean *value);
|
||||
gboolean ril_config_get_flag(GKeyFile *file, const char *group,
|
||||
const char *key, int flag, int *flags);
|
||||
gboolean ril_config_get_enum(GKeyFile *file, const char *group,
|
||||
const char *key, int *result,
|
||||
const char *name, int value, ...);
|
||||
GUtilInts *ril_config_get_ints(GKeyFile *file, const char *group,
|
||||
const char *key);
|
||||
char *ril_config_ints_to_string(GUtilInts *ints, char separator);
|
||||
|
||||
#endif /* RIL_CONFIG_H */
|
||||
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
/*
|
||||
*
|
||||
* RIL constants adopted from AOSP's header:
|
||||
*
|
||||
* /hardware/ril/reference_ril/ril.h
|
||||
*
|
||||
* Copyright (C) 2013 Canonical Ltd.
|
||||
* Copyright (C) 2013-2016 Jolla Ltd.
|
||||
* Copyright (C) 2013-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
|
||||
@@ -20,37 +19,70 @@
|
||||
#ifndef __RIL_CONSTANTS_H
|
||||
#define __RIL_CONSTANTS_H 1
|
||||
|
||||
#define RIL_MAX_UUID_LENGTH 64
|
||||
|
||||
/* Error Codes */
|
||||
#define RIL_E_SUCCESS 0
|
||||
#define RIL_E_RADIO_NOT_AVAILABLE 1
|
||||
#define RIL_E_GENERIC_FAILURE 2
|
||||
#define RIL_E_PASSWORD_INCORRECT 3
|
||||
#define RIL_E_SIM_PIN2 4
|
||||
#define RIL_E_SIM_PUK2 5
|
||||
#define RIL_E_REQUEST_NOT_SUPPORTED 6
|
||||
#define RIL_E_CANCELLED 7
|
||||
#define RIL_E_OP_NOT_ALLOWED_DURING_VOICE_CALL 8
|
||||
#define RIL_E_OP_NOT_ALLOWED_BEFORE_REG_TO_NW 9
|
||||
#define RIL_E_SMS_SEND_FAIL_RETRY 10
|
||||
#define RIL_E_SIM_ABSENT 11
|
||||
#define RIL_E_SUBSCRIPTION_NOT_AVAILABLE 12
|
||||
#define RIL_E_MODE_NOT_SUPPORTED 13
|
||||
#define RIL_E_FDN_CHECK_FAILURE 14
|
||||
#define RIL_E_ILLEGAL_SIM_OR_ME 15
|
||||
#define RIL_E_UNUSED 16
|
||||
#define RIL_E_DIAL_MODIFIED_TO_USSD 17
|
||||
#define RIL_E_DIAL_MODIFIED_TO_SS 18
|
||||
#define RIL_E_DIAL_MODIFIED_TO_DIAL 19
|
||||
#define RIL_E_USSD_MODIFIED_TO_DIAL 20
|
||||
#define RIL_E_USSD_MODIFIED_TO_SS 21
|
||||
#define RIL_E_USSD_MODIFIED_TO_USSD 22
|
||||
#define RIL_E_SS_MODIFIED_TO_DIAL 23
|
||||
#define RIL_E_SS_MODIFIED_TO_USSD 24
|
||||
#define RIL_E_SS_MODIFIED_TO_SS 25
|
||||
#define RIL_E_SUBSCRIPTION_NOT_SUPPORTED 26
|
||||
#define RIL_E_MISSING_RESOURCE 27
|
||||
#define RIL_E_NO_SUCH_ELEMENT 28
|
||||
#define RIL_E_INVALID_PARAMETER 29
|
||||
enum ril_status {
|
||||
RIL_E_SUCCESS = 0,
|
||||
RIL_E_RADIO_NOT_AVAILABLE = 1,
|
||||
RIL_E_GENERIC_FAILURE = 2,
|
||||
RIL_E_PASSWORD_INCORRECT = 3,
|
||||
RIL_E_SIM_PIN2 = 4,
|
||||
RIL_E_SIM_PUK2 = 5,
|
||||
RIL_E_REQUEST_NOT_SUPPORTED = 6,
|
||||
RIL_E_CANCELLED = 7,
|
||||
RIL_E_OP_NOT_ALLOWED_DURING_VOICE_CALL = 8,
|
||||
RIL_E_OP_NOT_ALLOWED_BEFORE_REG_TO_NW = 9,
|
||||
RIL_E_SMS_SEND_FAIL_RETRY = 10,
|
||||
RIL_E_SIM_ABSENT = 11,
|
||||
RIL_E_SUBSCRIPTION_NOT_AVAILABLE = 12,
|
||||
RIL_E_MODE_NOT_SUPPORTED = 13,
|
||||
RIL_E_FDN_CHECK_FAILURE = 14,
|
||||
RIL_E_ILLEGAL_SIM_OR_ME = 15,
|
||||
RIL_E_MISSING_RESOURCE = 16,
|
||||
RIL_E_NO_SUCH_ELEMENT = 17,
|
||||
RIL_E_DIAL_MODIFIED_TO_USSD = 18,
|
||||
RIL_E_DIAL_MODIFIED_TO_SS = 19,
|
||||
RIL_E_DIAL_MODIFIED_TO_DIAL = 20,
|
||||
RIL_E_USSD_MODIFIED_TO_DIAL = 21,
|
||||
RIL_E_USSD_MODIFIED_TO_SS = 22,
|
||||
RIL_E_USSD_MODIFIED_TO_USSD = 23,
|
||||
RIL_E_SS_MODIFIED_TO_DIAL = 24,
|
||||
RIL_E_SS_MODIFIED_TO_USSD = 25,
|
||||
RIL_E_SUBSCRIPTION_NOT_SUPPORTED = 26,
|
||||
RIL_E_SS_MODIFIED_TO_SS = 27,
|
||||
RIL_E_LCE_NOT_SUPPORTED = 36,
|
||||
RIL_E_NO_MEMORY = 37,
|
||||
RIL_E_INTERNAL_ERR = 38,
|
||||
RIL_E_SYSTEM_ERR = 39,
|
||||
RIL_E_MODEM_ERR = 40,
|
||||
RIL_E_INVALID_STATE = 41,
|
||||
RIL_E_NO_RESOURCES = 42,
|
||||
RIL_E_SIM_ERR = 43,
|
||||
RIL_E_INVALID_ARGUMENTS = 44,
|
||||
RIL_E_INVALID_SIM_STATE = 45,
|
||||
RIL_E_INVALID_MODEM_STATE = 46,
|
||||
RIL_E_INVALID_CALL_ID = 47,
|
||||
RIL_E_NO_SMS_TO_ACK = 48,
|
||||
RIL_E_NETWORK_ERR = 49,
|
||||
RIL_E_REQUEST_RATE_LIMITED = 50,
|
||||
RIL_E_SIM_BUSY = 51,
|
||||
RIL_E_SIM_FULL = 52,
|
||||
RIL_E_NETWORK_REJECT = 53,
|
||||
RIL_E_OPERATION_NOT_ALLOWED = 54,
|
||||
RIL_E_EMPTY_RECORD = 55,
|
||||
RIL_E_INVALID_SMS_FORMAT = 56,
|
||||
RIL_E_ENCODING_ERR = 57,
|
||||
RIL_E_INVALID_SMSC_ADDRESS = 58,
|
||||
RIL_E_NO_SUCH_ENTRY = 59,
|
||||
RIL_E_NETWORK_NOT_READY = 60,
|
||||
RIL_E_NOT_PROVISIONED = 61,
|
||||
RIL_E_NO_SUBSCRIPTION = 62,
|
||||
RIL_E_NO_NETWORK_FOUND = 63,
|
||||
RIL_E_DEVICE_IN_USE = 64,
|
||||
RIL_E_ABORTED = 65,
|
||||
RIL_E_INVALID_RESPONSE = 66
|
||||
};
|
||||
|
||||
/* call states */
|
||||
enum ril_call_state {
|
||||
@@ -114,49 +146,125 @@ enum ril_radio_tech {
|
||||
RADIO_TECH_HSPAP = 15,
|
||||
RADIO_TECH_GSM = 16,
|
||||
RADIO_TECH_TD_SCDMA = 17,
|
||||
RADIO_TECH_IWLAN = 18
|
||||
RADIO_TECH_IWLAN = 18,
|
||||
RADIO_TECH_LTE_CA = 19
|
||||
};
|
||||
|
||||
/* Radio capabilities */
|
||||
enum ril_radio_access_family {
|
||||
RAF_GPRS = (1 << RADIO_TECH_GPRS),
|
||||
RAF_EDGE = (1 << RADIO_TECH_EDGE),
|
||||
RAF_UMTS = (1 << RADIO_TECH_UMTS),
|
||||
RAF_IS95A = (1 << RADIO_TECH_IS95A),
|
||||
RAF_IS95B = (1 << RADIO_TECH_IS95B),
|
||||
RAF_1xRTT = (1 << RADIO_TECH_1xRTT),
|
||||
RAF_EVDO_0 = (1 << RADIO_TECH_EVDO_0),
|
||||
RAF_EVDO_A = (1 << RADIO_TECH_EVDO_A),
|
||||
RAF_HSDPA = (1 << RADIO_TECH_HSDPA),
|
||||
RAF_HSUPA = (1 << RADIO_TECH_HSUPA),
|
||||
RAF_HSPA = (1 << RADIO_TECH_HSPA),
|
||||
RAF_EVDO_B = (1 << RADIO_TECH_EVDO_B),
|
||||
RAF_EHRPD = (1 << RADIO_TECH_EHRPD),
|
||||
RAF_LTE = (1 << RADIO_TECH_LTE),
|
||||
RAF_HSPAP = (1 << RADIO_TECH_HSPAP),
|
||||
RAF_GSM = (1 << RADIO_TECH_GSM),
|
||||
RAF_TD_SCDMA = (1 << RADIO_TECH_TD_SCDMA),
|
||||
RAF_LTE_CA = (1 << RADIO_TECH_LTE_CA)
|
||||
};
|
||||
|
||||
enum ril_radio_capability_phase {
|
||||
RC_PHASE_CONFIGURED = 0,
|
||||
RC_PHASE_START = 1,
|
||||
RC_PHASE_APPLY = 2,
|
||||
RC_PHASE_UNSOL_RSP = 3,
|
||||
RC_PHASE_FINISH = 4
|
||||
};
|
||||
|
||||
enum ril_radio_capability_status {
|
||||
RC_STATUS_NONE = 0,
|
||||
RC_STATUS_SUCCESS = 1,
|
||||
RC_STATUS_FAIL = 2
|
||||
};
|
||||
|
||||
#define RIL_RADIO_CAPABILITY_VERSION 1
|
||||
|
||||
struct ril_radio_capability {
|
||||
int version;
|
||||
int session;
|
||||
enum ril_radio_capability_phase phase;
|
||||
enum ril_radio_access_family rat;
|
||||
char logicalModemUuid[RIL_MAX_UUID_LENGTH];
|
||||
int status;
|
||||
};
|
||||
|
||||
enum ril_uicc_subscription_action {
|
||||
RIL_UICC_SUBSCRIPTION_DEACTIVATE = 0,
|
||||
RIL_UICC_SUBSCRIPTION_ACTIVATE = 1
|
||||
};
|
||||
|
||||
/* See RIL_REQUEST_LAST_CALL_FAIL_CAUSE */
|
||||
#define CALL_FAIL_UNOBTAINABLE_NUMBER 1
|
||||
#define CALL_FAIL_NORMAL 16
|
||||
#define CALL_FAIL_BUSY 17
|
||||
#define CALL_FAIL_CONGESTION 34
|
||||
#define CALL_FAIL_ACM_LIMIT_EXCEEDED 68
|
||||
#define CALL_FAIL_CALL_BARRED 240
|
||||
#define CALL_FAIL_FDN_BLOCKED 241
|
||||
#define CALL_FAIL_IMSI_UNKNOWN_IN_VLR 242
|
||||
#define CALL_FAIL_IMEI_NOT_ACCEPTED 243
|
||||
#define CALL_FAIL_DIAL_MODIFIED_TO_USSD 244
|
||||
#define CALL_FAIL_DIAL_MODIFIED_TO_SS 245
|
||||
#define CALL_FAIL_DIAL_MODIFIED_TO_DIAL 246
|
||||
#define CALL_FAIL_CDMA_LOCKED_UNTIL_POWER_CYCLE 1000
|
||||
#define CALL_FAIL_CDMA_DROP 1001
|
||||
#define CALL_FAIL_CDMA_INTERCEPT 1002
|
||||
#define CALL_FAIL_CDMA_REORDER 1003
|
||||
#define CALL_FAIL_CDMA_SO_REJECT 1004
|
||||
#define CALL_FAIL_CDMA_RETRY_ORDER 1005
|
||||
#define CALL_FAIL_CDMA_ACCESS_FAILURE 1006
|
||||
#define CALL_FAIL_CDMA_PREEMPTED 1007
|
||||
#define CALL_FAIL_CDMA_NOT_EMERGENCY 1008
|
||||
#define CALL_FAIL_CDMA_ACCESS_BLOCKED 1009
|
||||
#define CALL_FAIL_ERROR_UNSPECIFIED 0xffff
|
||||
enum ril_call_fail_cause {
|
||||
CALL_FAIL_UNOBTAINABLE_NUMBER = 1,
|
||||
CALL_FAIL_NO_ROUTE_TO_DESTINATION = 3,
|
||||
CALL_FAIL_CHANNEL_UNACCEPTABLE = 6,
|
||||
CALL_FAIL_OPERATOR_DETERMINED_BARRING = 8,
|
||||
CALL_FAIL_NORMAL = 16,
|
||||
CALL_FAIL_BUSY = 17,
|
||||
CALL_FAIL_NO_USER_RESPONDING = 18,
|
||||
CALL_FAIL_NO_ANSWER_FROM_USER = 19,
|
||||
CALL_FAIL_CALL_REJECTED = 21,
|
||||
CALL_FAIL_NUMBER_CHANGED = 22,
|
||||
CALL_FAIL_DESTINATION_OUT_OF_ORDER = 27,
|
||||
CALL_FAIL_INVALID_NUMBER_FORMAT = 28,
|
||||
CALL_FAIL_FACILITY_REJECTED = 29,
|
||||
CALL_FAIL_RESP_TO_STATUS_ENQUIRY = 30,
|
||||
CALL_FAIL_NORMAL_UNSPECIFIED = 31,
|
||||
CALL_FAIL_CONGESTION = 34,
|
||||
CALL_FAIL_NETWORK_OUT_OF_ORDER = 38,
|
||||
CALL_FAIL_TEMPORARY_FAILURE = 41,
|
||||
CALL_FAIL_SWITCHING_EQUIPMENT_CONGESTION = 42,
|
||||
CALL_FAIL_ACCESS_INFORMATION_DISCARDED = 43,
|
||||
CALL_FAIL_REQUESTED_CIRCUIT_OR_CHANNEL_NOT_AVAILABLE = 44,
|
||||
CALL_FAIL_RESOURCES_UNAVAILABLE_OR_UNSPECIFIED = 47,
|
||||
CALL_FAIL_QOS_UNAVAILABLE = 49,
|
||||
CALL_FAIL_REQUESTED_FACILITY_NOT_SUBSCRIBED = 50,
|
||||
CALL_FAIL_INCOMING_CALLS_BARRED_WITHIN_CUG = 55,
|
||||
CALL_FAIL_BEARER_CAPABILITY_NOT_AUTHORIZED = 57,
|
||||
CALL_FAIL_BEARER_CAPABILITY_UNAVAILABLE = 58,
|
||||
CALL_FAIL_SERVICE_OPTION_NOT_AVAILABLE = 63,
|
||||
CALL_FAIL_BEARER_SERVICE_NOT_IMPLEMENTED = 65,
|
||||
CALL_FAIL_ACM_LIMIT_EXCEEDED = 68,
|
||||
CALL_FAIL_REQUESTED_FACILITY_NOT_IMPLEMENTED = 69,
|
||||
CALL_FAIL_ONLY_DIGITAL_INFORMATION_BEARER_AVAILABLE = 70,
|
||||
CALL_FAIL_SERVICE_OR_OPTION_NOT_IMPLEMENTED = 79,
|
||||
CALL_FAIL_INVALID_TRANSACTION_IDENTIFIER = 81,
|
||||
CALL_FAIL_USER_NOT_MEMBER_OF_CUG = 87,
|
||||
CALL_FAIL_INCOMPATIBLE_DESTINATION = 88,
|
||||
CALL_FAIL_INVALID_TRANSIT_NW_SELECTION = 91,
|
||||
CALL_FAIL_SEMANTICALLY_INCORRECT_MESSAGE = 95,
|
||||
CALL_FAIL_INVALID_MANDATORY_INFORMATION = 96,
|
||||
CALL_FAIL_MESSAGE_TYPE_NON_IMPLEMENTED = 97,
|
||||
CALL_FAIL_MESSAGE_TYPE_NOT_COMPATIBLE_WITH_PROTOCOL_STATE = 98,
|
||||
CALL_FAIL_INFORMATION_ELEMENT_NON_EXISTENT = 99,
|
||||
CALL_FAIL_CONDITIONAL_IE_ERROR = 100,
|
||||
CALL_FAIL_MESSAGE_NOT_COMPATIBLE_WITH_PROTOCOL_STATE = 101,
|
||||
CALL_FAIL_RECOVERY_ON_TIMER_EXPIRED = 102,
|
||||
CALL_FAIL_PROTOCOL_ERROR_UNSPECIFIED = 111,
|
||||
CALL_FAIL_INTERWORKING_UNSPECIFIED = 127,
|
||||
CALL_FAIL_CALL_BARRED = 240,
|
||||
CALL_FAIL_FDN_BLOCKED = 241,
|
||||
CALL_FAIL_IMSI_UNKNOWN_IN_VLR = 242,
|
||||
CALL_FAIL_IMEI_NOT_ACCEPTED = 243,
|
||||
CALL_FAIL_DIAL_MODIFIED_TO_USSD = 244,
|
||||
CALL_FAIL_DIAL_MODIFIED_TO_SS = 245,
|
||||
CALL_FAIL_DIAL_MODIFIED_TO_DIAL = 246,
|
||||
CALL_FAIL_ERROR_UNSPECIFIED = 0xffff,
|
||||
|
||||
/* Not defined in ril.h but valid 3GPP specific cause values
|
||||
* for call control. See 3GPP TS 24.008 Annex H. */
|
||||
#define CALL_FAIL_NO_ROUTE_TO_DESTINATION 3
|
||||
#define CALL_FAIL_CHANNEL_UNACCEPTABLE 6
|
||||
#define CALL_FAIL_OPERATOR_DETERMINED_BARRING 8
|
||||
#define CALL_FAIL_NO_USER_RESPONDING 18
|
||||
#define CALL_FAIL_USER_ALERTING_NO_ANSWER 19
|
||||
#define CALL_FAIL_CALL_REJECTED 21
|
||||
#define CALL_FAIL_NUMBER_CHANGED 22
|
||||
#define CALL_FAIL_ANONYMOUS_CALL_REJECTION 24
|
||||
#define CALL_FAIL_PRE_EMPTION 25
|
||||
#define CALL_FAIL_DESTINATION_OUT_OF_ORDER 27
|
||||
#define CALL_FAIL_INCOMPLETE_NUMBER 28
|
||||
#define CALL_FAIL_FACILITY_REJECTED 29
|
||||
#define CALL_FAIL_NORMAL_UNSPECIFIED 31
|
||||
CALL_FAIL_ANONYMOUS_CALL_REJECTION = 24,
|
||||
CALL_FAIL_PRE_EMPTION = 25
|
||||
};
|
||||
|
||||
enum ril_data_call_fail_cause {
|
||||
PDP_FAIL_NONE = 0,
|
||||
@@ -287,40 +395,7 @@ enum ril_cell_info_type {
|
||||
RIL_CELL_INFO_TYPE_TD_SCDMA = 5
|
||||
};
|
||||
|
||||
struct ril_cell_info_gsm {
|
||||
int mcc; /* Mobile Country Code (0..999) */
|
||||
int mnc; /* Mobile Network Code (0..999) */
|
||||
int lac; /* Location Area Code (0..65535) */
|
||||
int cid; /* GSM Cell Identity (0..65535) TS 27.007 */
|
||||
int signalStrength; /* (0-31, 99) TS 27.007 */
|
||||
int bitErrorRate; /* (0-7, 99) TS 27.007 */
|
||||
};
|
||||
|
||||
struct ril_cell_info_wcdma {
|
||||
int mcc; /* Mobile Country Code (0..999) */
|
||||
int mnc; /* Mobile Network Code (0..999) */
|
||||
int lac; /* Location Area Code (0..65535) */
|
||||
int cid; /* UMTS Cell Identity (0..268435455) TS 25.331 */
|
||||
int psc; /* Primary Scrambling Code (0..511) TS 25.331) */
|
||||
int signalStrength; /* (0-31, 99) TS 27.007 */
|
||||
int bitErrorRate; /* (0-7, 99) TS 27.007 */
|
||||
};
|
||||
|
||||
struct ril_cell_info_lte {
|
||||
int mcc; /* Mobile Country Code (0..999) */
|
||||
int mnc; /* Mobile Network Code (0..999) */
|
||||
int ci; /* Cell Identity */
|
||||
int pci; /* Physical cell id (0..503) */
|
||||
int tac; /* Tracking area code */
|
||||
int signalStrength; /* (0-31, 99) TS 27.007 8.5 */
|
||||
int rsrp; /* Reference Signal Receive Power TS 36.133 */
|
||||
int rsrq; /* Reference Signal Receive Quality TS 36.133 */
|
||||
int rssnr; /* Reference Signal-to-Noise Ratio TS 36.101*/
|
||||
int cqi; /* Channel Quality Indicator TS 36.101 */
|
||||
int timingAdvance; /* (Distance = 300m/us) TS 36.321 */
|
||||
};
|
||||
|
||||
/* RIL Request Messages */
|
||||
/* RIL Request Messages, ofono -> rild */
|
||||
#define RIL_REQUEST_GET_SIM_STATUS 1
|
||||
#define RIL_REQUEST_ENTER_SIM_PIN 2
|
||||
#define RIL_REQUEST_ENTER_SIM_PUK 3
|
||||
@@ -455,7 +530,7 @@ struct ril_cell_info_lte {
|
||||
#define RIL_REQUEST_GET_RADIO_CAPABILITY 130
|
||||
#define RIL_REQUEST_SET_RADIO_CAPABILITY 131
|
||||
|
||||
/* RIL Unsolicited Messages */
|
||||
/* RIL Unsolicited Messages, rild -> ofono */
|
||||
#define RIL_UNSOL_RESPONSE_BASE 1000
|
||||
#define RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED 1000
|
||||
#define RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED 1001
|
||||
@@ -503,6 +578,9 @@ struct ril_cell_info_lte {
|
||||
#define RIL_UNSOL_ON_SS 1043
|
||||
#define RIL_UNSOL_STK_CC_ALPHA_NOTIFY 1044
|
||||
|
||||
/* A special request, ofono -> rild */
|
||||
#define RIL_RESPONSE_ACKNOWLEDGEMENT 800
|
||||
|
||||
/* Suplementary services Service class*/
|
||||
#define SERVICE_CLASS_NONE 0
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2016 Jolla Ltd.
|
||||
* 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
|
||||
@@ -27,9 +27,7 @@
|
||||
#include <grilio_parser.h>
|
||||
#include <grilio_request.h>
|
||||
|
||||
#define SETUP_DATA_CALL_PARAMS 7
|
||||
#define DATA_PROFILE_DEFAULT_STR "0"
|
||||
#define DEACTIVATE_DATA_CALL_PARAMS 2
|
||||
|
||||
#define PROTO_IP_STR "IP"
|
||||
#define PROTO_IPV6_STR "IPV6"
|
||||
@@ -170,9 +168,9 @@ struct ril_data_request_deact {
|
||||
int cid;
|
||||
};
|
||||
|
||||
struct ril_data_request_2g {
|
||||
struct ril_data_request_allow_data {
|
||||
struct ril_data_request req;
|
||||
gulong handler_id;
|
||||
gboolean allow;
|
||||
};
|
||||
|
||||
static void ril_data_manager_check_data(struct ril_data_manager *dm);
|
||||
@@ -184,6 +182,26 @@ static void ril_data_signal_emit(struct ril_data *self, enum ril_data_signal id)
|
||||
g_signal_emit(self, ril_data_signals[id], 0);
|
||||
}
|
||||
|
||||
/*==========================================================================*
|
||||
* RIL requests
|
||||
*==========================================================================*/
|
||||
|
||||
GRilIoRequest *ril_request_allow_data_new(gboolean allow)
|
||||
{
|
||||
return grilio_request_array_int32_new(1, allow);
|
||||
}
|
||||
|
||||
GRilIoRequest *ril_request_deactivate_data_call_new(int cid)
|
||||
{
|
||||
GRilIoRequest *req = grilio_request_new();
|
||||
|
||||
grilio_request_append_int32(req, 2 /* Parameter count */);
|
||||
grilio_request_append_format(req, "%d", cid);
|
||||
grilio_request_append_format(req, "%d",
|
||||
RIL_DEACTIVATE_DATA_CALL_NO_REASON);
|
||||
return req;
|
||||
}
|
||||
|
||||
/*==========================================================================*
|
||||
* ril_data_call
|
||||
*==========================================================================*/
|
||||
@@ -787,8 +805,8 @@ static gboolean ril_data_call_setup_submit(struct ril_data_request *req)
|
||||
G_CAST(req, struct ril_data_request_setup, req);
|
||||
struct ril_data_priv *priv = req->data->priv;
|
||||
const char *proto_str = ril_data_ofono_protocol_to_ril(setup->proto);
|
||||
GRilIoRequest* ioreq;
|
||||
int tech, auth;
|
||||
GRilIoRequest *ioreq;
|
||||
int tech, auth = RIL_AUTH_NONE;
|
||||
|
||||
GASSERT(proto_str);
|
||||
|
||||
@@ -811,21 +829,29 @@ static gboolean ril_data_call_setup_submit(struct ril_data_request *req)
|
||||
tech = RADIO_TECH_HSPA;
|
||||
}
|
||||
|
||||
/*
|
||||
* We do the same as in $AOSP/frameworks/opt/telephony/src/java/com/
|
||||
* android/internal/telephony/dataconnection/DataConnection.java,
|
||||
* onConnect(), and use authentication or not depending on whether
|
||||
* the user field is empty or not.
|
||||
*/
|
||||
auth = (setup->username && setup->username[0]) ?
|
||||
RIL_AUTH_BOTH : RIL_AUTH_NONE;
|
||||
if (setup->username && setup->username[0]) {
|
||||
switch (setup->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;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO: add comments about tethering, other non-public
|
||||
* profiles...
|
||||
*/
|
||||
ioreq = grilio_request_new();
|
||||
grilio_request_append_int32(ioreq, SETUP_DATA_CALL_PARAMS);
|
||||
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);
|
||||
@@ -924,6 +950,10 @@ static void ril_data_call_deact_cb(GRilIoChannel *io, int ril_status,
|
||||
ril_data_call_free(call);
|
||||
ril_data_signal_emit(data, SIGNAL_CALLS_CHANGED);
|
||||
}
|
||||
} else {
|
||||
/* Something seems to be slightly broken, request the
|
||||
* current state */
|
||||
ril_data_poll_call_state(data);
|
||||
}
|
||||
|
||||
if (req->cb.deact) {
|
||||
@@ -938,12 +968,8 @@ static gboolean ril_data_call_deact_submit(struct ril_data_request *req)
|
||||
struct ril_data_request_deact *deact =
|
||||
G_CAST(req, struct ril_data_request_deact, req);
|
||||
struct ril_data_priv *priv = req->data->priv;
|
||||
GRilIoRequest* ioreq = grilio_request_new();
|
||||
|
||||
grilio_request_append_int32(ioreq, DEACTIVATE_DATA_CALL_PARAMS);
|
||||
grilio_request_append_format(ioreq, "%d", deact->cid);
|
||||
grilio_request_append_format(ioreq, "%d",
|
||||
RIL_DEACTIVATE_DATA_CALL_NO_REASON);
|
||||
GRilIoRequest *ioreq =
|
||||
ril_request_deactivate_data_call_new(deact->cid);
|
||||
|
||||
req->pending_id = grilio_queue_send_request_full(priv->q, ioreq,
|
||||
RIL_REQUEST_DEACTIVATE_DATA_CALL,
|
||||
@@ -975,15 +1001,6 @@ static struct ril_data_request *ril_data_call_deact_new(struct ril_data *data,
|
||||
* ril_data_allow_request
|
||||
*==========================================================================*/
|
||||
|
||||
static GRilIoRequest *ril_data_allow_req(gboolean allow)
|
||||
{
|
||||
GRilIoRequest *req = grilio_request_sized_new(8);
|
||||
|
||||
grilio_request_append_int32(req, 1);
|
||||
grilio_request_append_int32(req, allow != FALSE);
|
||||
return req;
|
||||
}
|
||||
|
||||
static void ril_data_allow_cb(GRilIoChannel *io, int ril_status,
|
||||
const void *req_data, guint len, void *user_data)
|
||||
{
|
||||
@@ -993,13 +1010,22 @@ static void ril_data_allow_cb(GRilIoChannel *io, int ril_status,
|
||||
|
||||
ril_data_request_completed(req);
|
||||
|
||||
if (ril_status == RIL_E_SUCCESS &&
|
||||
(priv->flags & RIL_DATA_FLAG_ALLOWED)) {
|
||||
GASSERT(!ril_data_allowed(data));
|
||||
priv->flags |= RIL_DATA_FLAG_ON;
|
||||
GASSERT(ril_data_allowed(data));
|
||||
DBG_(data, "data on");
|
||||
ril_data_signal_emit(data, SIGNAL_ALLOW_CHANGED);
|
||||
if (ril_status == RIL_E_SUCCESS) {
|
||||
const gboolean was_allowed = ril_data_allowed(data);
|
||||
struct ril_data_request_allow_data *ad =
|
||||
G_CAST(req, struct ril_data_request_allow_data, req);
|
||||
|
||||
if (ad->allow) {
|
||||
priv->flags |= RIL_DATA_FLAG_ON;
|
||||
DBG_(data, "data on");
|
||||
} else {
|
||||
priv->flags &= ~RIL_DATA_FLAG_ON;
|
||||
DBG_(data, "data off");
|
||||
}
|
||||
|
||||
if (ril_data_allowed(data) != was_allowed) {
|
||||
ril_data_signal_emit(data, SIGNAL_ALLOW_CHANGED);
|
||||
}
|
||||
}
|
||||
|
||||
ril_data_request_finish(req);
|
||||
@@ -1007,25 +1033,32 @@ static void ril_data_allow_cb(GRilIoChannel *io, int ril_status,
|
||||
|
||||
static gboolean ril_data_allow_submit(struct ril_data_request *req)
|
||||
{
|
||||
GRilIoRequest *ioreq = ril_data_allow_req(TRUE);
|
||||
struct ril_data_request_allow_data *ad =
|
||||
G_CAST(req, struct ril_data_request_allow_data, req);
|
||||
GRilIoRequest *ioreq = ril_request_allow_data_new(ad->allow);
|
||||
struct ril_data_priv *priv = req->data->priv;
|
||||
|
||||
grilio_request_set_retry(ioreq, RIL_RETRY_SECS*1000, -1);
|
||||
grilio_request_set_blocking(ioreq, TRUE);
|
||||
req->pending_id = grilio_queue_send_request_full(priv->q, ioreq,
|
||||
RIL_REQUEST_ALLOW_DATA, ril_data_allow_cb, NULL, req);
|
||||
grilio_request_unref(ioreq);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static struct ril_data_request *ril_data_allow_new(struct ril_data *data)
|
||||
static struct ril_data_request *ril_data_allow_new(struct ril_data *data,
|
||||
gboolean allow)
|
||||
{
|
||||
struct ril_data_request *req = g_new0(struct ril_data_request, 1);
|
||||
struct ril_data_request_allow_data *ad =
|
||||
g_new0(struct ril_data_request_allow_data, 1);
|
||||
struct ril_data_request *req = &ad->req;
|
||||
|
||||
req->name = "ALLOW_DATA";
|
||||
req->data = data;
|
||||
req->submit = ril_data_allow_submit;
|
||||
req->cancel = ril_data_request_cancel_io;
|
||||
req->flags = DATA_REQUEST_FLAG_CANCEL_WHEN_DISALLOWED;
|
||||
ad->allow = allow;
|
||||
return req;
|
||||
}
|
||||
|
||||
@@ -1080,12 +1113,11 @@ struct ril_data *ril_data_new(struct ril_data_manager *dm, const char *name,
|
||||
struct ril_data *self = g_object_new(RIL_DATA_TYPE, NULL);
|
||||
struct ril_data_priv *priv = self->priv;
|
||||
struct ril_sim_settings *settings = network->settings;
|
||||
GRilIoRequest *req = grilio_request_new();
|
||||
|
||||
priv->options = *options;
|
||||
switch (priv->options.allow_data) {
|
||||
case RIL_ALLOW_DATA_ON:
|
||||
case RIL_ALLOW_DATA_OFF:
|
||||
case RIL_ALLOW_DATA_ENABLED:
|
||||
case RIL_ALLOW_DATA_DISABLED:
|
||||
break;
|
||||
default:
|
||||
/*
|
||||
@@ -1093,7 +1125,8 @@ struct ril_data *ril_data_new(struct ril_data_manager *dm, const char *name,
|
||||
* RIL_VERSION was 10
|
||||
*/
|
||||
priv->options.allow_data = (io->ril_version > 10) ?
|
||||
RIL_ALLOW_DATA_ON : RIL_ALLOW_DATA_OFF;
|
||||
RIL_ALLOW_DATA_ENABLED :
|
||||
RIL_ALLOW_DATA_DISABLED;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1118,12 +1151,7 @@ struct ril_data *ril_data_new(struct ril_data_manager *dm, const char *name,
|
||||
ril_data_settings_changed, self);
|
||||
|
||||
/* Request the current state */
|
||||
grilio_request_set_retry(req, RIL_RETRY_SECS*1000, -1);
|
||||
priv->query_id = grilio_queue_send_request_full(priv->q, req,
|
||||
RIL_REQUEST_DATA_CALL_LIST,
|
||||
ril_data_query_data_calls_cb,
|
||||
NULL, self);
|
||||
grilio_request_unref(req);
|
||||
ril_data_poll_call_state(self);
|
||||
|
||||
/* Order data contexts according to slot numbers */
|
||||
dm->data_list = g_slist_insert_sorted(dm->data_list, self,
|
||||
@@ -1134,6 +1162,25 @@ struct ril_data *ril_data_new(struct ril_data_manager *dm, const char *name,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void ril_data_poll_call_state(struct ril_data *self)
|
||||
{
|
||||
if (G_LIKELY(self)) {
|
||||
struct ril_data_priv *priv = self->priv;
|
||||
|
||||
if (!priv->query_id) {
|
||||
GRilIoRequest *req = grilio_request_new();
|
||||
|
||||
grilio_request_set_retry(req, RIL_RETRY_SECS*1000, -1);
|
||||
priv->query_id =
|
||||
grilio_queue_send_request_full(priv->q, req,
|
||||
RIL_REQUEST_DATA_CALL_LIST,
|
||||
ril_data_query_data_calls_cb,
|
||||
NULL, self);
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct ril_data *ril_data_ref(struct ril_data *self)
|
||||
{
|
||||
if (G_LIKELY(self)) {
|
||||
@@ -1180,8 +1227,7 @@ static void ril_data_power_update(struct ril_data *self)
|
||||
{
|
||||
struct ril_data_priv *priv = self->priv;
|
||||
|
||||
if (priv->pending_req || priv->req_queue ||
|
||||
(priv->flags & RIL_DATA_FLAG_ALLOWED)) {
|
||||
if (priv->pending_req || priv->req_queue) {
|
||||
ril_radio_power_on(priv->radio, self);
|
||||
} else {
|
||||
ril_radio_power_off(priv->radio, self);
|
||||
@@ -1211,10 +1257,11 @@ static void ril_data_cancel_requests(struct ril_data *self,
|
||||
static void ril_data_disallow(struct ril_data *self)
|
||||
{
|
||||
struct ril_data_priv *priv = self->priv;
|
||||
const gboolean was_allowed = ril_data_allowed(self);
|
||||
|
||||
DBG_(self, "disallowed");
|
||||
GASSERT(priv->flags & RIL_DATA_FLAG_ALLOWED);
|
||||
priv->flags &= ~(RIL_DATA_FLAG_ALLOWED | RIL_DATA_FLAG_ON);
|
||||
priv->flags &= ~RIL_DATA_FLAG_ALLOWED;
|
||||
|
||||
/*
|
||||
* Cancel all requests that can be canceled.
|
||||
@@ -1227,7 +1274,20 @@ static void ril_data_disallow(struct ril_data *self)
|
||||
* requests are already pending? That's quite unlikely though)
|
||||
*/
|
||||
ril_data_deactivate_all(self);
|
||||
ril_data_power_update(self);
|
||||
|
||||
if (priv->options.allow_data == RIL_ALLOW_DATA_ENABLED) {
|
||||
/* Tell rild that the data is now disabled */
|
||||
ril_data_request_queue(ril_data_allow_new(self, FALSE));
|
||||
} else {
|
||||
priv->flags &= ~RIL_DATA_FLAG_ON;
|
||||
GASSERT(!ril_data_allowed(self));
|
||||
DBG_(self, "data off");
|
||||
ril_data_power_update(self);
|
||||
}
|
||||
|
||||
if (ril_data_allowed(self) != was_allowed) {
|
||||
ril_data_signal_emit(self, SIGNAL_ALLOW_CHANGED);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_data_max_speed_cb(gpointer data, gpointer max_speed)
|
||||
@@ -1244,12 +1304,7 @@ static void ril_data_disallow_cb(gpointer data_ptr, gpointer allowed)
|
||||
struct ril_data *data = data_ptr;
|
||||
|
||||
if (data->priv->flags & RIL_DATA_FLAG_ALLOWED) {
|
||||
const gboolean was_allowed = ril_data_allowed(data);
|
||||
ril_data_disallow(data);
|
||||
if (was_allowed) {
|
||||
ril_data_signal_emit(data,
|
||||
SIGNAL_ALLOW_CHANGED);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1303,13 +1358,7 @@ void ril_data_allow(struct ril_data *self, enum ril_data_role role)
|
||||
}
|
||||
} else {
|
||||
if (priv->flags & RIL_DATA_FLAG_ALLOWED) {
|
||||
gboolean was_allowed = ril_data_allowed(self);
|
||||
|
||||
ril_data_disallow(self);
|
||||
if (was_allowed) {
|
||||
ril_data_signal_emit(self,
|
||||
SIGNAL_ALLOW_CHANGED);
|
||||
}
|
||||
ril_data_manager_check_data(dm);
|
||||
}
|
||||
}
|
||||
@@ -1538,9 +1587,8 @@ static void ril_data_manager_switch_data_on(struct ril_data_manager *self,
|
||||
OFONO_RADIO_ACCESS_MODE_ANY, TRUE);
|
||||
}
|
||||
|
||||
|
||||
if (priv->options.allow_data == RIL_ALLOW_DATA_ON) {
|
||||
ril_data_request_queue(ril_data_allow_new(data));
|
||||
if (priv->options.allow_data == RIL_ALLOW_DATA_ENABLED) {
|
||||
ril_data_request_queue(ril_data_allow_new(data, TRUE));
|
||||
} else {
|
||||
priv->flags |= RIL_DATA_FLAG_ON;
|
||||
GASSERT(ril_data_allowed(data));
|
||||
@@ -1563,6 +1611,16 @@ static void ril_data_manager_check_data(struct ril_data_manager *self)
|
||||
}
|
||||
}
|
||||
|
||||
void ril_data_manager_assert_data_on(struct ril_data_manager *self)
|
||||
{
|
||||
if (self) {
|
||||
struct ril_data *data = ril_data_manager_allowed(self);
|
||||
if (data) {
|
||||
ril_data_request_queue(ril_data_allow_new(data, TRUE));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2016 Jolla Ltd.
|
||||
* 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
|
||||
@@ -56,8 +56,8 @@ enum ril_data_manager_flags {
|
||||
|
||||
enum ril_data_allow_data_opt {
|
||||
RIL_ALLOW_DATA_AUTO,
|
||||
RIL_ALLOW_DATA_ON,
|
||||
RIL_ALLOW_DATA_OFF
|
||||
RIL_ALLOW_DATA_ENABLED,
|
||||
RIL_ALLOW_DATA_DISABLED
|
||||
};
|
||||
|
||||
enum ril_data_call_format {
|
||||
@@ -84,6 +84,7 @@ struct ril_data_manager;
|
||||
struct ril_data_manager *ril_data_manager_new(enum ril_data_manager_flags flg);
|
||||
struct ril_data_manager *ril_data_manager_ref(struct ril_data_manager *dm);
|
||||
void ril_data_manager_unref(struct ril_data_manager *dm);
|
||||
void ril_data_manager_assert_data_on(struct ril_data_manager *dm);
|
||||
|
||||
typedef void (*ril_data_cb_t)(struct ril_data *data, void *arg);
|
||||
typedef void (*ril_data_call_setup_cb_t)(struct ril_data *data,
|
||||
@@ -99,6 +100,7 @@ struct ril_data *ril_data_new(struct ril_data_manager *dm, const char *name,
|
||||
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);
|
||||
void ril_data_poll_call_state(struct ril_data *data);
|
||||
|
||||
gulong ril_data_add_allow_changed_handler(struct ril_data *data,
|
||||
ril_data_cb_t cb, void *arg);
|
||||
@@ -122,6 +124,10 @@ 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);
|
||||
|
||||
/* Constructors of various kinds of RIL requests */
|
||||
GRilIoRequest *ril_request_allow_data_new(gboolean allow);
|
||||
GRilIoRequest *ril_request_deactivate_data_call_new(int cid);
|
||||
|
||||
#endif /* RIL_DATA_H */
|
||||
|
||||
/*
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2016 Jolla Ltd.
|
||||
* Copyright (C) 2015-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
|
||||
@@ -17,16 +17,24 @@
|
||||
#include "ril_util.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
#include <gutil_idlequeue.h>
|
||||
|
||||
/*
|
||||
* TODO: No public RIL api to query manufacturer or model.
|
||||
* Check where to get, could /system/build.prop be updated to have good values?
|
||||
*/
|
||||
|
||||
enum ril_devinfo_cb_tag {
|
||||
DEVINFO_QUERY_SERIAL = 1,
|
||||
DEVINFO_QUERY_SVN
|
||||
};
|
||||
|
||||
struct ril_devinfo {
|
||||
struct ofono_devinfo *info;
|
||||
GRilIoQueue *q;
|
||||
guint register_id;
|
||||
guint imei_id;
|
||||
GUtilIdleQueue *iq;
|
||||
char *log_prefix;
|
||||
char *imeisv;
|
||||
char *imei;
|
||||
};
|
||||
|
||||
@@ -36,6 +44,7 @@ struct ril_devinfo_cbd {
|
||||
gpointer data;
|
||||
};
|
||||
|
||||
#define DBG_(self,fmt,args...) DBG("%s" fmt, (self)->log_prefix, ##args)
|
||||
#define ril_devinfo_cbd_free g_free
|
||||
|
||||
static inline struct ril_devinfo *ril_devinfo_get_data(
|
||||
@@ -62,7 +71,7 @@ static void ril_devinfo_query_unsupported(struct ofono_devinfo *info,
|
||||
cb(ril_error_failure(&error), "", data);
|
||||
}
|
||||
|
||||
static void ril_devinfo_query_cb(GRilIoChannel *io, int status,
|
||||
static void ril_devinfo_query_revision_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ofono_error error;
|
||||
@@ -73,7 +82,7 @@ static void ril_devinfo_query_cb(GRilIoChannel *io, int status,
|
||||
GRilIoParser rilp;
|
||||
grilio_parser_init(&rilp, data, len);
|
||||
res = grilio_parser_get_utf8(&rilp);
|
||||
DBG("%s", res);
|
||||
DBG_(cbd->di, "%s", res);
|
||||
cbd->cb(ril_error_ok(&error), res ? res : "", cbd->data);
|
||||
g_free(res);
|
||||
} else {
|
||||
@@ -86,23 +95,46 @@ static void ril_devinfo_query_revision(struct ofono_devinfo *info,
|
||||
{
|
||||
struct ril_devinfo *di = ril_devinfo_get_data(info);
|
||||
|
||||
DBG("");
|
||||
grilio_queue_send_request_full(di->q, NULL, RIL_REQUEST_BASEBAND_VERSION,
|
||||
ril_devinfo_query_cb, ril_devinfo_cbd_free,
|
||||
DBG_(di, "");
|
||||
grilio_queue_send_request_full(di->q, NULL,
|
||||
RIL_REQUEST_BASEBAND_VERSION,
|
||||
ril_devinfo_query_revision_cb,
|
||||
ril_devinfo_cbd_free,
|
||||
ril_devinfo_cbd_new(di, cb, data));
|
||||
}
|
||||
|
||||
static gboolean ril_devinfo_query_serial_cb(void *user_data)
|
||||
static void ril_devinfo_query_serial_cb(gpointer user_data)
|
||||
{
|
||||
struct ril_devinfo_cbd *cbd = user_data;
|
||||
struct ril_devinfo *di = cbd->di;
|
||||
struct ofono_error error;
|
||||
|
||||
GASSERT(di->imei_id);
|
||||
di->imei_id = 0;
|
||||
|
||||
DBG_(di, "%s", di->imei);
|
||||
cbd->cb(ril_error_ok(&error), di->imei, cbd->data);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void ril_devinfo_query_svn_cb(gpointer user_data)
|
||||
{
|
||||
struct ril_devinfo_cbd *cbd = user_data;
|
||||
struct ril_devinfo *di = cbd->di;
|
||||
struct ofono_error error;
|
||||
|
||||
DBG_(di, "%s", di->imeisv);
|
||||
if (di->imeisv && di->imeisv[0]) {
|
||||
cbd->cb(ril_error_ok(&error), di->imeisv, cbd->data);
|
||||
} else {
|
||||
cbd->cb(ril_error_failure(&error), "", cbd->data);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_devinfo_query(struct ril_devinfo *di,
|
||||
enum ril_devinfo_cb_tag tag, GUtilIdleFunc fn,
|
||||
ofono_devinfo_query_cb_t cb, void *data)
|
||||
{
|
||||
GVERIFY_FALSE(gutil_idle_queue_cancel_tag(di->iq, tag));
|
||||
gutil_idle_queue_add_tag_full(di->iq, tag, fn,
|
||||
ril_devinfo_cbd_new(di, cb, data),
|
||||
ril_devinfo_cbd_free);
|
||||
}
|
||||
|
||||
static void ril_devinfo_query_serial(struct ofono_devinfo *info,
|
||||
@@ -111,29 +143,28 @@ static void ril_devinfo_query_serial(struct ofono_devinfo *info,
|
||||
{
|
||||
struct ril_devinfo *di = ril_devinfo_get_data(info);
|
||||
|
||||
GASSERT(!di->imei_id);
|
||||
if (di->imei_id) {
|
||||
g_source_remove(di->imei_id);
|
||||
di->imei_id = 0;
|
||||
}
|
||||
|
||||
DBG("%s", di->imei);
|
||||
di->imei_id = g_idle_add_full(G_PRIORITY_DEFAULT_IDLE,
|
||||
ril_devinfo_query_serial_cb,
|
||||
ril_devinfo_cbd_new(di, cb, data),
|
||||
ril_devinfo_cbd_free);
|
||||
DBG_(di, "");
|
||||
ril_devinfo_query(di, DEVINFO_QUERY_SERIAL,
|
||||
ril_devinfo_query_serial_cb, cb, data);
|
||||
}
|
||||
|
||||
static gboolean ril_devinfo_register(gpointer user_data)
|
||||
static void ril_devinfo_query_svn(struct ofono_devinfo *info,
|
||||
ofono_devinfo_query_cb_t cb,
|
||||
void *data)
|
||||
{
|
||||
struct ril_devinfo *di = ril_devinfo_get_data(info);
|
||||
|
||||
DBG_(di, "");
|
||||
ril_devinfo_query(di, DEVINFO_QUERY_SVN,
|
||||
ril_devinfo_query_svn_cb, cb, data);
|
||||
}
|
||||
|
||||
static void ril_devinfo_register(gpointer user_data)
|
||||
{
|
||||
struct ril_devinfo *di = user_data;
|
||||
|
||||
DBG("");
|
||||
di->register_id = 0;
|
||||
DBG_(di, "");
|
||||
ofono_devinfo_register(di->info);
|
||||
|
||||
/* This makes the timeout a single-shot */
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static int ril_devinfo_probe(struct ofono_devinfo *info, unsigned int vendor,
|
||||
@@ -142,13 +173,18 @@ static int ril_devinfo_probe(struct ofono_devinfo *info, unsigned int vendor,
|
||||
struct ril_modem *modem = data;
|
||||
struct ril_devinfo *di = g_new0(struct ril_devinfo, 1);
|
||||
|
||||
DBG("%s %s %p", ril_modem_get_path(modem), modem->imei, di);
|
||||
di->log_prefix = (modem->log_prefix && modem->log_prefix[0]) ?
|
||||
g_strconcat(modem->log_prefix, " ", NULL) : g_strdup("");
|
||||
|
||||
DBG_(di, "%s", modem->imei);
|
||||
GASSERT(modem->imei);
|
||||
|
||||
di->q = grilio_queue_new(ril_modem_io(modem));
|
||||
di->info = info;
|
||||
di->imeisv = g_strdup(modem->imeisv);
|
||||
di->imei = g_strdup(modem->imei);
|
||||
|
||||
di->register_id = g_idle_add(ril_devinfo_register, di);
|
||||
di->iq = gutil_idle_queue_new();
|
||||
gutil_idle_queue_add(di->iq, ril_devinfo_register, di);
|
||||
ofono_devinfo_set_data(info, di);
|
||||
return 0;
|
||||
}
|
||||
@@ -157,19 +193,14 @@ static void ril_devinfo_remove(struct ofono_devinfo *info)
|
||||
{
|
||||
struct ril_devinfo *di = ril_devinfo_get_data(info);
|
||||
|
||||
DBG("%p", di);
|
||||
DBG_(di, "");
|
||||
ofono_devinfo_set_data(info, NULL);
|
||||
|
||||
if (di->register_id > 0) {
|
||||
g_source_remove(di->register_id);
|
||||
}
|
||||
|
||||
if (di->imei_id > 0) {
|
||||
g_source_remove(di->imei_id);
|
||||
}
|
||||
|
||||
gutil_idle_queue_cancel_all(di->iq);
|
||||
gutil_idle_queue_unref(di->iq);
|
||||
grilio_queue_cancel_all(di->q, FALSE);
|
||||
grilio_queue_unref(di->q);
|
||||
g_free(di->log_prefix);
|
||||
g_free(di->imeisv);
|
||||
g_free(di->imei);
|
||||
g_free(di);
|
||||
}
|
||||
@@ -178,10 +209,11 @@ const struct ofono_devinfo_driver ril_devinfo_driver = {
|
||||
.name = RILMODEM_DRIVER,
|
||||
.probe = ril_devinfo_probe,
|
||||
.remove = ril_devinfo_remove,
|
||||
.query_manufacturer = ril_devinfo_query_unsupported,
|
||||
/* query_revision won't be called if query_model is missing */
|
||||
.query_model = ril_devinfo_query_unsupported,
|
||||
.query_revision = ril_devinfo_query_revision,
|
||||
.query_serial = ril_devinfo_query_serial
|
||||
.query_serial = ril_devinfo_query_serial,
|
||||
.query_svn = ril_devinfo_query_svn
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2016 Jolla Ltd.
|
||||
* Copyright (C) 2015-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
|
||||
@@ -17,7 +17,6 @@
|
||||
#include "ril_network.h"
|
||||
#include "ril_data.h"
|
||||
#include "ril_util.h"
|
||||
#include "ril_mtu.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
#include <gutil_strv.h>
|
||||
@@ -25,6 +24,7 @@
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "mtu-watch.h"
|
||||
|
||||
#define CTX_ID_NONE ((unsigned int)(-1))
|
||||
|
||||
@@ -43,7 +43,7 @@ struct ril_gprs_context {
|
||||
struct ril_data *data;
|
||||
guint active_ctx_cid;
|
||||
gulong calls_changed_id;
|
||||
struct ril_mtu_watch *mtu_watch;
|
||||
struct mtu_watch *mtu_watch;
|
||||
struct ril_data_call *active_call;
|
||||
struct ril_gprs_context_call activate;
|
||||
struct ril_gprs_context_call deactivate;
|
||||
@@ -95,7 +95,7 @@ static void ril_gprs_context_free_active_call(struct ril_gprs_context *gcd)
|
||||
gcd->calls_changed_id = 0;
|
||||
}
|
||||
if (gcd->mtu_watch) {
|
||||
ril_mtu_watch_free(gcd->mtu_watch);
|
||||
mtu_watch_free(gcd->mtu_watch);
|
||||
gcd->mtu_watch = NULL;
|
||||
}
|
||||
}
|
||||
@@ -107,9 +107,9 @@ static void ril_gprs_context_set_active_call(struct ril_gprs_context *gcd,
|
||||
ril_data_call_free(gcd->active_call);
|
||||
gcd->active_call = ril_data_call_dup(call);
|
||||
if (!gcd->mtu_watch) {
|
||||
gcd->mtu_watch = ril_mtu_watch_new(MAX_MTU);
|
||||
gcd->mtu_watch = mtu_watch_new(MAX_MTU);
|
||||
}
|
||||
ril_mtu_watch_set_ifname(gcd->mtu_watch, call->ifname);
|
||||
mtu_watch_set_ifname(gcd->mtu_watch, call->ifname);
|
||||
} else {
|
||||
ril_gprs_context_free_active_call(gcd);
|
||||
}
|
||||
@@ -575,7 +575,7 @@ static void ril_gprs_context_remove(struct ofono_gprs_context *gc)
|
||||
ril_data_unref(gcd->data);
|
||||
ril_network_unref(gcd->network);
|
||||
ril_data_call_free(gcd->active_call);
|
||||
ril_mtu_watch_free(gcd->mtu_watch);
|
||||
mtu_watch_free(gcd->mtu_watch);
|
||||
g_free(gcd);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2016 Jolla Ltd.
|
||||
* Copyright (C) 2015-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
|
||||
@@ -25,6 +25,8 @@
|
||||
|
||||
#include "ofono.h"
|
||||
|
||||
#include "sailfish_watch.h"
|
||||
|
||||
#define MAX_PDP_CONTEXTS (2)
|
||||
#define ONLINE_TIMEOUT_SECS (15) /* 20 sec is hardcoded in ofono core */
|
||||
|
||||
@@ -50,24 +52,20 @@ struct ril_modem_online_request {
|
||||
|
||||
struct ril_modem_data {
|
||||
struct ril_modem modem;
|
||||
struct sailfish_watch *watch;
|
||||
GRilIoQueue *q;
|
||||
char *log_prefix;
|
||||
char *imeisv;
|
||||
char *imei;
|
||||
char *ecclist_file;
|
||||
gboolean pre_sim_done;
|
||||
gboolean allow_data;
|
||||
gulong sim_imsi_event_id;
|
||||
gulong imsi_event_id;
|
||||
|
||||
guint online_check_id;
|
||||
enum ril_modem_power_state power_state;
|
||||
gulong radio_state_event_id;
|
||||
|
||||
ril_modem_cb_t removed_cb;
|
||||
void *removed_cb_data;
|
||||
|
||||
ril_modem_online_cb_t online_cb;
|
||||
void *online_cb_data;
|
||||
|
||||
struct ril_modem_online_request set_online;
|
||||
struct ril_modem_online_request set_offline;
|
||||
};
|
||||
@@ -83,11 +81,6 @@ static struct ril_modem_data *ril_modem_data_from_ofono(struct ofono_modem *o)
|
||||
return md;
|
||||
}
|
||||
|
||||
static struct ril_modem_data *ril_modem_data_from_modem(struct ril_modem *m)
|
||||
{
|
||||
return m ? G_CAST(m, struct ril_modem_data, modem) : NULL;
|
||||
}
|
||||
|
||||
static void *ril_modem_get_atom_data(struct ril_modem *modem,
|
||||
enum ofono_atom_type type)
|
||||
{
|
||||
@@ -131,24 +124,6 @@ void ril_modem_delete(struct ril_modem *md)
|
||||
}
|
||||
}
|
||||
|
||||
void ril_modem_set_removed_cb(struct ril_modem *modem, ril_modem_cb_t cb,
|
||||
void *data)
|
||||
{
|
||||
struct ril_modem_data *md = ril_modem_data_from_modem(modem);
|
||||
|
||||
md->removed_cb = cb;
|
||||
md->removed_cb_data = data;
|
||||
}
|
||||
|
||||
void ril_modem_set_online_cb(struct ril_modem *modem, ril_modem_online_cb_t cb,
|
||||
void *data)
|
||||
{
|
||||
struct ril_modem_data *md = ril_modem_data_from_modem(modem);
|
||||
|
||||
md->online_cb = cb;
|
||||
md->online_cb_data = data;
|
||||
}
|
||||
|
||||
static void ril_modem_online_request_ok(struct ril_modem_online_request *req)
|
||||
{
|
||||
if (req->timeout_id) {
|
||||
@@ -233,7 +208,7 @@ static void ril_modem_schedule_online_check(struct ril_modem_data *md)
|
||||
static void ril_modem_update_radio_settings(struct ril_modem_data *md)
|
||||
{
|
||||
struct ril_modem *m = &md->modem;
|
||||
if (m->radio->state == RADIO_STATE_ON && m->sim_settings->imsi) {
|
||||
if (m->radio->state == RADIO_STATE_ON && md->watch->imsi) {
|
||||
/* radio-settings.c assumes that IMSI is available */
|
||||
if (!ril_modem_radio_settings(m)) {
|
||||
DBG_(md, "initializing radio settings interface");
|
||||
@@ -261,11 +236,11 @@ static void ril_modem_radio_state_cb(struct ril_radio *radio, void *data)
|
||||
ril_modem_update_online_state(md);
|
||||
}
|
||||
|
||||
static void ril_modem_imsi_cb(struct ril_sim_settings *settings, void *data)
|
||||
static void ril_modem_imsi_cb(struct sailfish_watch *watch, void *data)
|
||||
{
|
||||
struct ril_modem_data *md = data;
|
||||
|
||||
GASSERT(md->modem.sim_settings == settings);
|
||||
GASSERT(md->watch == watch);
|
||||
ril_modem_update_radio_settings(md);
|
||||
}
|
||||
|
||||
@@ -277,7 +252,9 @@ static void ril_modem_pre_sim(struct ofono_modem *modem)
|
||||
md->pre_sim_done = TRUE;
|
||||
ofono_devinfo_create(modem, 0, RILMODEM_DRIVER, md);
|
||||
ofono_sim_create(modem, 0, RILMODEM_DRIVER, md);
|
||||
ofono_voicecall_create(modem, 0, RILMODEM_DRIVER, md);
|
||||
if (md->modem.config.enable_voicecall) {
|
||||
ofono_voicecall_create(modem, 0, RILMODEM_DRIVER, md);
|
||||
}
|
||||
if (!md->radio_state_event_id) {
|
||||
md->radio_state_event_id =
|
||||
ril_radio_add_state_changed_handler(md->modem.radio,
|
||||
@@ -331,20 +308,18 @@ static void ril_modem_set_online(struct ofono_modem *modem, ofono_bool_t online,
|
||||
ofono_modem_online_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_modem_data *md = ril_modem_data_from_ofono(modem);
|
||||
struct ril_radio *radio = md->modem.radio;
|
||||
struct ril_modem_online_request *req;
|
||||
|
||||
DBG("%s going %sline", ofono_modem_get_path(modem),
|
||||
online ? "on" : "off");
|
||||
|
||||
if (md->online_cb) {
|
||||
md->online_cb(&md->modem, online, md->online_cb_data);
|
||||
}
|
||||
|
||||
ril_radio_set_online(radio, online);
|
||||
if (online) {
|
||||
ril_radio_power_on(md->modem.radio, RADIO_POWER_TAG(md));
|
||||
ril_radio_power_on(radio, RADIO_POWER_TAG(md));
|
||||
req = &md->set_online;
|
||||
} else {
|
||||
ril_radio_power_off(md->modem.radio, RADIO_POWER_TAG(md));
|
||||
ril_radio_power_off(radio, RADIO_POWER_TAG(md));
|
||||
req = &md->set_offline;
|
||||
}
|
||||
|
||||
@@ -393,25 +368,16 @@ static void ril_modem_remove(struct ofono_modem *ofono)
|
||||
struct ril_modem *modem = &md->modem;
|
||||
|
||||
DBG("%s", ril_modem_get_path(modem));
|
||||
if (md->removed_cb) {
|
||||
ril_modem_cb_t cb = md->removed_cb;
|
||||
void *data = md->removed_cb_data;
|
||||
|
||||
md->removed_cb = NULL;
|
||||
md->removed_cb_data = NULL;
|
||||
cb(modem, data);
|
||||
}
|
||||
|
||||
ofono_modem_set_data(ofono, NULL);
|
||||
|
||||
ril_radio_remove_handler(modem->radio, md->radio_state_event_id);
|
||||
ril_radio_power_off(modem->radio, RADIO_POWER_TAG(md));
|
||||
ril_radio_unref(modem->radio);
|
||||
|
||||
ril_sim_settings_remove_handler(modem->sim_settings,
|
||||
md->sim_imsi_event_id);
|
||||
ril_sim_settings_unref(modem->sim_settings);
|
||||
|
||||
sailfish_watch_remove_handler(md->watch, md->imsi_event_id);
|
||||
sailfish_watch_unref(md->watch);
|
||||
|
||||
if (md->online_check_id) {
|
||||
g_source_remove(md->online_check_id);
|
||||
}
|
||||
@@ -426,25 +392,28 @@ static void ril_modem_remove(struct ofono_modem *ofono)
|
||||
|
||||
ril_network_unref(modem->network);
|
||||
ril_sim_card_unref(modem->sim_card);
|
||||
ril_cell_info_unref(modem->cell_info);
|
||||
ril_data_unref(modem->data);
|
||||
sailfish_cell_info_unref(modem->cell_info);
|
||||
grilio_channel_unref(modem->io);
|
||||
grilio_queue_cancel_all(md->q, FALSE);
|
||||
grilio_queue_unref(md->q);
|
||||
g_free(md->ecclist_file);
|
||||
g_free(md->log_prefix);
|
||||
g_free(md->imeisv);
|
||||
g_free(md->imei);
|
||||
g_free(md);
|
||||
}
|
||||
|
||||
struct ril_modem *ril_modem_create(GRilIoChannel *io, const char *log_prefix,
|
||||
const struct ril_slot_info *slot, struct ril_radio *radio,
|
||||
struct ril_network *network, struct ril_sim_card *card,
|
||||
struct ril_data *data, struct ril_sim_settings *settings,
|
||||
struct ril_cell_info *cell_info)
|
||||
const char *path, const char *imei, const char *imeisv,
|
||||
const char *ecclist_file, const struct ril_slot_config *config,
|
||||
struct ril_radio *radio, struct ril_network *network,
|
||||
struct ril_sim_card *card, struct ril_data *data,
|
||||
struct ril_sim_settings *settings,
|
||||
struct sailfish_cell_info *cell_info)
|
||||
{
|
||||
/* Skip the slash from the path, it looks like "/ril_0" */
|
||||
struct ofono_modem *ofono = ofono_modem_create(slot->path + 1,
|
||||
struct ofono_modem *ofono = ofono_modem_create(path + 1,
|
||||
RILMODEM_DRIVER);
|
||||
if (ofono) {
|
||||
int err;
|
||||
@@ -455,14 +424,14 @@ struct ril_modem *ril_modem_create(GRilIoChannel *io, const char *log_prefix,
|
||||
* ril_plugin.c must wait until IMEI becomes known before
|
||||
* creating the modem
|
||||
*/
|
||||
GASSERT(slot->imei);
|
||||
GASSERT(imei);
|
||||
|
||||
/* Copy config */
|
||||
modem->config = *slot->config;
|
||||
modem->imei = md->imei = g_strdup(slot->imei);
|
||||
modem->log_prefix = log_prefix;
|
||||
modem->ecclist_file =
|
||||
md->ecclist_file = g_strdup(slot->ecclist_file);
|
||||
modem->config = *config;
|
||||
modem->imei = md->imei = g_strdup(imei);
|
||||
modem->imeisv = md->imeisv = g_strdup(imeisv);
|
||||
modem->log_prefix = log_prefix; /* No need to strdup */
|
||||
modem->ecclist_file = ecclist_file; /* No need to strdup */
|
||||
md->log_prefix = (log_prefix && log_prefix[0]) ?
|
||||
g_strconcat(log_prefix, " ", NULL) : g_strdup("");
|
||||
|
||||
@@ -471,18 +440,14 @@ struct ril_modem *ril_modem_create(GRilIoChannel *io, const char *log_prefix,
|
||||
modem->network = ril_network_ref(network);
|
||||
modem->sim_card = ril_sim_card_ref(card);
|
||||
modem->sim_settings = ril_sim_settings_ref(settings);
|
||||
modem->cell_info = ril_cell_info_ref(cell_info);
|
||||
modem->cell_info = sailfish_cell_info_ref(cell_info);
|
||||
modem->data = ril_data_ref(data);
|
||||
modem->io = grilio_channel_ref(io);
|
||||
md->q = grilio_queue_new(io);
|
||||
md->watch = sailfish_watch_new(path);
|
||||
|
||||
/*
|
||||
* modem->sim_settings->imsi follows IMSI known to the ofono
|
||||
* core, unlike ril_sim_info->imsi which may point to the
|
||||
* cached IMSI even before the PIN code is entered.
|
||||
*/
|
||||
md->sim_imsi_event_id =
|
||||
ril_sim_settings_add_imsi_changed_handler(settings,
|
||||
md->imsi_event_id =
|
||||
sailfish_watch_add_imsi_changed_handler(md->watch,
|
||||
ril_modem_imsi_cb, md);
|
||||
|
||||
md->set_online.md = md;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2016 Jolla Ltd.
|
||||
* 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
|
||||
@@ -14,15 +14,16 @@
|
||||
*/
|
||||
|
||||
#include "ril_plugin.h"
|
||||
#include "ril_cell_info.h"
|
||||
#include "ril_util.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
#include <sailfish_cell_info.h>
|
||||
|
||||
#include "ofono.h"
|
||||
|
||||
struct ril_netmon {
|
||||
struct ofono_netmon *netmon;
|
||||
struct ril_cell_info *cell_info;
|
||||
struct sailfish_cell_info *cell_info;
|
||||
guint register_id;
|
||||
};
|
||||
|
||||
@@ -50,7 +51,7 @@ static void ril_netmon_format_mccmnc(char *s_mcc, char *s_mnc, int mcc, int mnc)
|
||||
}
|
||||
|
||||
static void ril_netmon_notify_gsm(struct ofono_netmon *netmon,
|
||||
const struct ril_cell_info_gsm *gsm)
|
||||
const struct sailfish_cell_info_gsm *gsm)
|
||||
{
|
||||
char mcc[OFONO_MAX_MCC_LENGTH + 1];
|
||||
char mnc[OFONO_MAX_MNC_LENGTH + 1];
|
||||
@@ -68,7 +69,7 @@ static void ril_netmon_notify_gsm(struct ofono_netmon *netmon,
|
||||
}
|
||||
|
||||
static void ril_netmon_notify_wcdma(struct ofono_netmon *netmon,
|
||||
const struct ril_cell_info_wcdma *wcdma)
|
||||
const struct sailfish_cell_info_wcdma *wcdma)
|
||||
{
|
||||
char mcc[OFONO_MAX_MCC_LENGTH + 1];
|
||||
char mnc[OFONO_MAX_MNC_LENGTH + 1];
|
||||
@@ -87,7 +88,7 @@ static void ril_netmon_notify_wcdma(struct ofono_netmon *netmon,
|
||||
}
|
||||
|
||||
static void ril_netmon_notify_lte(struct ofono_netmon *netmon,
|
||||
const struct ril_cell_info_lte *lte)
|
||||
const struct sailfish_cell_info_lte *lte)
|
||||
{
|
||||
char mcc[OFONO_MAX_MCC_LENGTH + 1];
|
||||
char mnc[OFONO_MAX_MNC_LENGTH + 1];
|
||||
@@ -111,19 +112,19 @@ static void ril_netmon_request_update(struct ofono_netmon *netmon,
|
||||
GSList *l;
|
||||
|
||||
for (l = nm->cell_info->cells; l; l = l->next) {
|
||||
const struct ril_cell *cell = l->data;
|
||||
const struct sailfish_cell *cell = l->data;
|
||||
|
||||
if (cell->registered) {
|
||||
switch (cell->type) {
|
||||
case RIL_CELL_INFO_TYPE_GSM:
|
||||
case SAILFISH_CELL_TYPE_GSM:
|
||||
ril_netmon_notify_gsm(netmon,
|
||||
&cell->info.gsm);
|
||||
break;
|
||||
case RIL_CELL_INFO_TYPE_WCDMA:
|
||||
case SAILFISH_CELL_TYPE_WCDMA:
|
||||
ril_netmon_notify_wcdma(netmon,
|
||||
&cell->info.wcdma);
|
||||
break;
|
||||
case RIL_CELL_INFO_TYPE_LTE:
|
||||
case SAILFISH_CELL_TYPE_LTE:
|
||||
ril_netmon_notify_lte(netmon,
|
||||
&cell->info.lte);
|
||||
break;
|
||||
@@ -156,7 +157,7 @@ static int ril_netmon_probe(struct ofono_netmon *netmon, unsigned int vendor,
|
||||
if (modem->cell_info) {
|
||||
struct ril_netmon *nm = g_slice_new0(struct ril_netmon);
|
||||
|
||||
nm->cell_info = ril_cell_info_ref(modem->cell_info);
|
||||
nm->cell_info = sailfish_cell_info_ref(modem->cell_info);
|
||||
nm->netmon = netmon;
|
||||
|
||||
ofono_netmon_set_data(netmon, nm);
|
||||
@@ -182,7 +183,7 @@ static void ril_netmon_remove(struct ofono_netmon *netmon)
|
||||
g_source_remove(nm->register_id);
|
||||
}
|
||||
|
||||
ril_cell_info_unref(nm->cell_info);
|
||||
sailfish_cell_info_unref(nm->cell_info);
|
||||
g_slice_free(struct ril_netmon, nm);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2016 Jolla Ltd.
|
||||
* Copyright (C) 2015-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
|
||||
@@ -47,12 +47,17 @@ enum ril_network_radio_event {
|
||||
RADIO_EVENT_COUNT
|
||||
};
|
||||
|
||||
enum ril_network_unsol_event {
|
||||
UNSOL_EVENT_NETWORK_STATE,
|
||||
UNSOL_EVENT_RADIO_CAPABILITY,
|
||||
UNSOL_EVENT_COUNT
|
||||
};
|
||||
|
||||
struct ril_network_priv {
|
||||
GRilIoChannel *io;
|
||||
GRilIoQueue *q;
|
||||
struct ril_radio *radio;
|
||||
struct ril_sim_card *sim_card;
|
||||
enum ofono_radio_access_mode max_pref_mode;
|
||||
int rat;
|
||||
char *log_prefix;
|
||||
guint operator_poll_id;
|
||||
@@ -61,11 +66,12 @@ struct ril_network_priv {
|
||||
guint timer[TIMER_COUNT];
|
||||
gulong query_rat_id;
|
||||
gulong set_rat_id;
|
||||
gulong ril_event_id;
|
||||
gulong unsol_event_id[UNSOL_EVENT_COUNT];
|
||||
gulong settings_event_id;
|
||||
gulong sim_status_event_id;
|
||||
gulong radio_event_id[RADIO_EVENT_COUNT];
|
||||
struct ofono_network_operator operator;
|
||||
gboolean assert_rat;
|
||||
};
|
||||
|
||||
enum ril_network_signal {
|
||||
@@ -73,13 +79,15 @@ enum ril_network_signal {
|
||||
SIGNAL_VOICE_STATE_CHANGED,
|
||||
SIGNAL_DATA_STATE_CHANGED,
|
||||
SIGNAL_PREF_MODE_CHANGED,
|
||||
SIGNAL_MAX_PREF_MODE_CHANGED,
|
||||
SIGNAL_COUNT
|
||||
};
|
||||
|
||||
#define SIGNAL_OPERATOR_CHANGED_NAME "ril-network-operator-changed"
|
||||
#define SIGNAL_VOICE_STATE_CHANGED_NAME "ril-network-voice-state-changed"
|
||||
#define SIGNAL_DATA_STATE_CHANGED_NAME "ril-network-data-state-changed"
|
||||
#define SIGNAL_PREF_MODE_CHANGED_NAME "ril-network-pref-mode-changed"
|
||||
#define SIGNAL_OPERATOR_CHANGED_NAME "ril-network-operator-changed"
|
||||
#define SIGNAL_VOICE_STATE_CHANGED_NAME "ril-network-voice-state-changed"
|
||||
#define SIGNAL_DATA_STATE_CHANGED_NAME "ril-network-data-state-changed"
|
||||
#define SIGNAL_PREF_MODE_CHANGED_NAME "ril-network-pref-mode-changed"
|
||||
#define SIGNAL_MAX_PREF_MODE_CHANGED_NAME "ril-network-max-pref-mode-changed"
|
||||
|
||||
static guint ril_network_signals[SIGNAL_COUNT] = { 0 };
|
||||
|
||||
@@ -200,8 +208,14 @@ static gboolean ril_network_parse_response(struct ril_network *self,
|
||||
reg->max_calls = 2;
|
||||
}
|
||||
|
||||
reg->lac = slac ? strtol(slac, NULL, 16) : -1;
|
||||
reg->ci = sci ? strtol(sci, NULL, 16) : -1;
|
||||
if (!ril_parse_int(slac, 16, ®->lac)) {
|
||||
reg->lac = -1;
|
||||
}
|
||||
|
||||
if (!ril_parse_int(sci, 16, ®->ci)) {
|
||||
reg->ci = -1;
|
||||
}
|
||||
|
||||
reg->access_tech = ril_parse_tech(stech, ®->ril_tech);
|
||||
|
||||
DBG_(self, "%s,%s,%s,%d,%s,%s,%s",
|
||||
@@ -420,13 +434,16 @@ static int ril_network_mode_to_rat(struct ril_network *self,
|
||||
switch (mode) {
|
||||
case OFONO_RADIO_ACCESS_MODE_ANY:
|
||||
case OFONO_RADIO_ACCESS_MODE_LTE:
|
||||
if (self->settings->enable_4g) {
|
||||
if (self->settings->techs & OFONO_RADIO_ACCESS_MODE_LTE) {
|
||||
return PREF_NET_TYPE_LTE_GSM_WCDMA;
|
||||
}
|
||||
/* no break */
|
||||
default:
|
||||
case OFONO_RADIO_ACCESS_MODE_UMTS:
|
||||
return PREF_NET_TYPE_GSM_WCDMA_AUTO;
|
||||
if (self->settings->techs & OFONO_RADIO_ACCESS_MODE_UMTS) {
|
||||
return PREF_NET_TYPE_GSM_WCDMA_AUTO;
|
||||
}
|
||||
/* no break */
|
||||
case OFONO_RADIO_ACCESS_MODE_GSM:
|
||||
return PREF_NET_TYPE_GSM_ONLY;
|
||||
}
|
||||
@@ -447,7 +464,7 @@ static int ril_network_pref_mode_expected(struct ril_network *self)
|
||||
* it becomes necessary.
|
||||
*/
|
||||
const enum ofono_radio_access_mode max_pref_mode =
|
||||
(priv->radio->state == RADIO_STATE_ON) ? priv->max_pref_mode :
|
||||
(priv->radio->state == RADIO_STATE_ON) ? self->max_pref_mode :
|
||||
OFONO_RADIO_ACCESS_MODE_GSM;
|
||||
|
||||
/*
|
||||
@@ -486,7 +503,7 @@ static gboolean ril_network_set_rat_holdoff_cb(gpointer user_data)
|
||||
* and SIM card state change callbacks will schedule a new check
|
||||
* when it's appropriate.
|
||||
*/
|
||||
if (priv->rat != rat) {
|
||||
if (priv->rat != rat || priv->assert_rat) {
|
||||
if (ril_network_can_set_pref_mode(self)) {
|
||||
ril_network_set_pref_mode(self, rat);
|
||||
} else {
|
||||
@@ -527,6 +544,9 @@ static void ril_network_set_pref_mode(struct ril_network *self, int rat)
|
||||
ril_network_set_pref_mode_cb, NULL, self);
|
||||
grilio_request_unref(req);
|
||||
|
||||
/* We have submitted the request, clear the assertion flag */
|
||||
priv->assert_rat = FALSE;
|
||||
|
||||
/* Don't do it too often */
|
||||
GASSERT(!priv->timer[TIMER_SET_RAT_HOLDOFF]);
|
||||
priv->timer[TIMER_SET_RAT_HOLDOFF] =
|
||||
@@ -554,8 +574,7 @@ static void ril_network_check_pref_mode(struct ril_network *self,
|
||||
ril_network_stop_timer(self, TIMER_SET_RAT_HOLDOFF);
|
||||
}
|
||||
|
||||
if (priv->rat != rat) {
|
||||
/* Something isn't right, we need to fix it */
|
||||
if (priv->rat != rat || priv->assert_rat) {
|
||||
if (!priv->timer[TIMER_SET_RAT_HOLDOFF]) {
|
||||
ril_network_set_pref_mode(self, rat);
|
||||
} else {
|
||||
@@ -644,17 +663,25 @@ void ril_network_set_max_pref_mode(struct ril_network *self,
|
||||
enum ofono_radio_access_mode max_mode,
|
||||
gboolean force_check)
|
||||
{
|
||||
if (G_LIKELY(self)) {
|
||||
struct ril_network_priv *priv = self->priv;
|
||||
if (priv->max_pref_mode != max_mode || force_check) {
|
||||
if (self && (self->max_pref_mode != max_mode || force_check)) {
|
||||
if (self->max_pref_mode != max_mode) {
|
||||
DBG_(self, "rat mode %d (%s)", max_mode,
|
||||
ofono_radio_access_mode_to_string(max_mode));
|
||||
priv->max_pref_mode = max_mode;
|
||||
ril_network_check_pref_mode(self, TRUE);
|
||||
self->max_pref_mode = max_mode;
|
||||
ril_network_emit(self, SIGNAL_MAX_PREF_MODE_CHANGED);
|
||||
}
|
||||
ril_network_check_pref_mode(self, TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
void ril_network_assert_pref_mode(struct ril_network *self, gboolean immediate)
|
||||
{
|
||||
struct ril_network_priv *priv = self->priv;
|
||||
|
||||
priv->assert_rat = TRUE;
|
||||
ril_network_check_pref_mode(self, immediate);
|
||||
}
|
||||
|
||||
gulong ril_network_add_operator_changed_handler(struct ril_network *self,
|
||||
ril_network_cb_t cb, void *arg)
|
||||
{
|
||||
@@ -683,6 +710,13 @@ gulong ril_network_add_pref_mode_changed_handler(struct ril_network *self,
|
||||
SIGNAL_PREF_MODE_CHANGED_NAME, G_CALLBACK(cb), arg) : 0;
|
||||
}
|
||||
|
||||
gulong ril_network_add_max_pref_mode_changed_handler(struct ril_network *self,
|
||||
ril_network_cb_t cb, void *arg)
|
||||
{
|
||||
return (G_LIKELY(self) && G_LIKELY(cb)) ? g_signal_connect(self,
|
||||
SIGNAL_MAX_PREF_MODE_CHANGED_NAME, G_CALLBACK(cb), arg) : 0;
|
||||
}
|
||||
|
||||
void ril_network_remove_handler(struct ril_network *self, gulong id)
|
||||
{
|
||||
if (G_LIKELY(self) && G_LIKELY(id)) {
|
||||
@@ -695,7 +729,7 @@ void ril_network_remove_handlers(struct ril_network *self, gulong *ids, int n)
|
||||
gutil_disconnect_handlers(self, ids, n);
|
||||
}
|
||||
|
||||
static void ril_network_voice_state_changed_cb(GRilIoChannel *io, guint code,
|
||||
static void ril_network_state_changed_cb(GRilIoChannel *io, guint code,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_network *self = RIL_NETWORK(user_data);
|
||||
@@ -705,6 +739,16 @@ static void ril_network_voice_state_changed_cb(GRilIoChannel *io, guint code,
|
||||
ril_network_poll_state(self);
|
||||
}
|
||||
|
||||
static void ril_network_radio_capability_changed_cb(GRilIoChannel *io,
|
||||
guint code, const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_network *self = RIL_NETWORK(user_data);
|
||||
|
||||
DBG_(self, "");
|
||||
GASSERT(code == RIL_UNSOL_RADIO_CAPABILITY);
|
||||
ril_network_assert_pref_mode(self, FALSE);
|
||||
}
|
||||
|
||||
static void ril_network_radio_state_cb(struct ril_radio *radio, void *data)
|
||||
{
|
||||
struct ril_network *self = RIL_NETWORK(data);
|
||||
@@ -767,8 +811,9 @@ static void ril_network_sim_status_changed_cb(struct ril_sim_card *sc,
|
||||
}
|
||||
}
|
||||
|
||||
struct ril_network *ril_network_new(GRilIoChannel *io, const char *log_prefix,
|
||||
struct ril_radio *radio, struct ril_sim_card *sim_card,
|
||||
struct ril_network *ril_network_new(const char *path, GRilIoChannel *io,
|
||||
const char *log_prefix, struct ril_radio *radio,
|
||||
struct ril_sim_card *sim_card,
|
||||
struct ril_sim_settings *settings)
|
||||
{
|
||||
struct ril_network *self = g_object_new(RIL_NETWORK_TYPE, NULL);
|
||||
@@ -782,9 +827,14 @@ struct ril_network *ril_network_new(GRilIoChannel *io, const char *log_prefix,
|
||||
priv->log_prefix = (log_prefix && log_prefix[0]) ?
|
||||
g_strconcat(log_prefix, " ", NULL) : g_strdup("");
|
||||
DBG_(self, "");
|
||||
priv->ril_event_id = grilio_channel_add_unsol_event_handler(priv->io,
|
||||
ril_network_voice_state_changed_cb,
|
||||
priv->unsol_event_id[UNSOL_EVENT_NETWORK_STATE] =
|
||||
grilio_channel_add_unsol_event_handler(priv->io,
|
||||
ril_network_state_changed_cb,
|
||||
RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED, self);
|
||||
priv->unsol_event_id[UNSOL_EVENT_RADIO_CAPABILITY] =
|
||||
grilio_channel_add_unsol_event_handler(priv->io,
|
||||
ril_network_radio_capability_changed_cb,
|
||||
RIL_UNSOL_RADIO_CAPABILITY, self);
|
||||
priv->radio_event_id[RADIO_EVENT_STATE_CHANGED] =
|
||||
ril_radio_add_state_changed_handler(priv->radio,
|
||||
ril_network_radio_state_cb, self);
|
||||
@@ -840,57 +890,45 @@ static void ril_network_init(struct ril_network *self)
|
||||
priv->rat = -1;
|
||||
}
|
||||
|
||||
static void ril_network_dispose(GObject *object)
|
||||
static void ril_network_finalize(GObject *object)
|
||||
{
|
||||
struct ril_network *self = RIL_NETWORK(object);
|
||||
struct ril_network_priv *priv = self->priv;
|
||||
enum ril_network_timer tid;
|
||||
|
||||
grilio_channel_remove_handlers(priv->io, &priv->ril_event_id, 1);
|
||||
ril_radio_remove_handlers(priv->radio, priv->radio_event_id,
|
||||
G_N_ELEMENTS(priv->radio_event_id));
|
||||
ril_sim_settings_remove_handlers(self->settings,
|
||||
&priv->settings_event_id, 1);
|
||||
ril_sim_card_remove_handlers(priv->sim_card,
|
||||
&priv->sim_status_event_id, 1);
|
||||
DBG_(self, "");
|
||||
|
||||
for (tid=0; tid<TIMER_COUNT; tid++) {
|
||||
ril_network_stop_timer(self, tid);
|
||||
}
|
||||
|
||||
grilio_queue_cancel_all(priv->q, FALSE);
|
||||
priv->set_rat_id = 0;
|
||||
priv->query_rat_id = 0;
|
||||
grilio_channel_remove_handlers(priv->io, priv->unsol_event_id,
|
||||
G_N_ELEMENTS(priv->unsol_event_id));
|
||||
|
||||
G_OBJECT_CLASS(ril_network_parent_class)->dispose(object);
|
||||
}
|
||||
|
||||
static void ril_network_finalize(GObject *object)
|
||||
{
|
||||
struct ril_network *self = RIL_NETWORK(object);
|
||||
struct ril_network_priv *priv = self->priv;
|
||||
|
||||
DBG_(self, "");
|
||||
g_free(priv->log_prefix);
|
||||
grilio_channel_unref(priv->io);
|
||||
grilio_queue_unref(priv->q);
|
||||
ril_radio_remove_all_handlers(priv->radio, priv->radio_event_id);
|
||||
ril_radio_unref(priv->radio);
|
||||
ril_sim_card_remove_handler(priv->sim_card,
|
||||
priv->sim_status_event_id);
|
||||
ril_sim_card_unref(priv->sim_card);
|
||||
ril_sim_settings_remove_handler(self->settings,
|
||||
priv->settings_event_id);
|
||||
ril_sim_settings_unref(self->settings);
|
||||
g_free(priv->log_prefix);
|
||||
G_OBJECT_CLASS(ril_network_parent_class)->finalize(object);
|
||||
}
|
||||
|
||||
static void ril_network_class_init(RilNetworkClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS(klass);
|
||||
|
||||
object_class->dispose = ril_network_dispose;
|
||||
object_class->finalize = ril_network_finalize;
|
||||
G_OBJECT_CLASS(klass)->finalize = ril_network_finalize;
|
||||
g_type_class_add_private(klass, sizeof(struct ril_network_priv));
|
||||
RIL_NETWORK_SIGNAL(klass, OPERATOR);
|
||||
RIL_NETWORK_SIGNAL(klass, VOICE_STATE);
|
||||
RIL_NETWORK_SIGNAL(klass, DATA_STATE);
|
||||
RIL_NETWORK_SIGNAL(klass, PREF_MODE);
|
||||
RIL_NETWORK_SIGNAL(klass, MAX_PREF_MODE);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2016 Jolla Ltd.
|
||||
* Copyright (C) 2015-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
|
||||
@@ -18,8 +18,6 @@
|
||||
|
||||
#include "ril_types.h"
|
||||
|
||||
#include <ofono/radio-settings.h>
|
||||
|
||||
struct ofono_network_operator;
|
||||
|
||||
struct ril_registration_state {
|
||||
@@ -38,14 +36,16 @@ struct ril_network {
|
||||
struct ril_registration_state data;
|
||||
const struct ofono_network_operator *operator;
|
||||
enum ofono_radio_access_mode pref_mode;
|
||||
enum ofono_radio_access_mode max_pref_mode;
|
||||
struct ril_sim_settings *settings;
|
||||
};
|
||||
|
||||
struct ofono_sim;
|
||||
typedef void (*ril_network_cb_t)(struct ril_network *net, void *arg);
|
||||
|
||||
struct ril_network *ril_network_new(GRilIoChannel *io, const char *log_prefix,
|
||||
struct ril_radio *radio, struct ril_sim_card *sim_card,
|
||||
struct ril_network *ril_network_new(const char *path, GRilIoChannel *io,
|
||||
const char *log_prefix, struct ril_radio *radio,
|
||||
struct ril_sim_card *sim_card,
|
||||
struct ril_sim_settings *settings);
|
||||
struct ril_network *ril_network_ref(struct ril_network *net);
|
||||
void ril_network_unref(struct ril_network *net);
|
||||
@@ -53,6 +53,7 @@ void ril_network_unref(struct ril_network *net);
|
||||
void ril_network_set_max_pref_mode(struct ril_network *net,
|
||||
enum ofono_radio_access_mode max_pref_mode,
|
||||
gboolean force_check);
|
||||
void ril_network_assert_pref_mode(struct ril_network *net, gboolean immediate);
|
||||
gulong ril_network_add_operator_changed_handler(struct ril_network *net,
|
||||
ril_network_cb_t cb, void *arg);
|
||||
gulong ril_network_add_voice_state_changed_handler(struct ril_network *net,
|
||||
@@ -61,6 +62,8 @@ gulong ril_network_add_data_state_changed_handler(struct ril_network *net,
|
||||
ril_network_cb_t cb, void *arg);
|
||||
gulong ril_network_add_pref_mode_changed_handler(struct ril_network *net,
|
||||
ril_network_cb_t cb, void *arg);
|
||||
gulong ril_network_add_max_pref_mode_changed_handler(struct ril_network *net,
|
||||
ril_network_cb_t cb, void *arg);
|
||||
void ril_network_remove_handler(struct ril_network *net, gulong id);
|
||||
void ril_network_remove_handlers(struct ril_network *net, gulong *ids, int n);
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2016 Jolla Ltd.
|
||||
* Copyright (C) 2015-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
|
||||
@@ -24,7 +24,6 @@
|
||||
#define RIL_OEM_RAW_TIMEOUT (60*1000) /* 60 sec */
|
||||
|
||||
struct ril_oem_raw {
|
||||
struct ril_modem *modem;
|
||||
GRilIoQueue *q;
|
||||
DBusConnection *conn;
|
||||
char *path;
|
||||
@@ -118,7 +117,6 @@ struct ril_oem_raw *ril_oem_raw_new(struct ril_modem *modem,
|
||||
struct ril_oem_raw *oem = g_new0(struct ril_oem_raw, 1);
|
||||
|
||||
DBG("%s", ril_modem_get_path(modem));
|
||||
oem->modem = modem;
|
||||
oem->path = g_strdup(ril_modem_get_path(modem));
|
||||
oem->conn = dbus_connection_ref(ofono_dbus_get_connection());
|
||||
oem->q = grilio_queue_new(ril_modem_io(modem));
|
||||
@@ -144,8 +142,6 @@ void ril_oem_raw_free(struct ril_oem_raw *oem)
|
||||
DBG("%s", oem->path);
|
||||
g_dbus_unregister_interface(oem->conn, oem->path,
|
||||
RIL_OEM_RAW_INTERFACE);
|
||||
ofono_modem_remove_interface(oem->modem->ofono,
|
||||
RIL_OEM_RAW_INTERFACE);
|
||||
dbus_connection_unref(oem->conn);
|
||||
|
||||
grilio_queue_cancel_all(oem->q, TRUE);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2016 Jolla Ltd.
|
||||
* Copyright (C) 2015-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
|
||||
@@ -17,6 +17,7 @@
|
||||
#define RIL_PLUGIN_H
|
||||
|
||||
#include "ril_types.h"
|
||||
#include "sailfish_manager.h"
|
||||
|
||||
#include <ofono/modem.h>
|
||||
#include <ofono/call-barring.h>
|
||||
@@ -43,100 +44,38 @@
|
||||
|
||||
#define RILMODEM_DRIVER "ril"
|
||||
|
||||
typedef struct ril_slot_info const *ril_slot_info_ptr;
|
||||
|
||||
struct ril_slot_info {
|
||||
const char *path;
|
||||
const char *imei;
|
||||
const char *ecclist_file;
|
||||
gboolean enabled;
|
||||
gboolean sim_present;
|
||||
const struct ril_slot_config *config;
|
||||
};
|
||||
|
||||
struct ril_plugin {
|
||||
const char *mms_imsi;
|
||||
const char *mms_path;
|
||||
const char *default_voice_imsi;
|
||||
const char *default_data_imsi;
|
||||
const char *default_voice_path;
|
||||
const char *default_data_path;
|
||||
const ril_slot_info_ptr *slots;
|
||||
gboolean ready;
|
||||
};
|
||||
|
||||
struct ril_modem {
|
||||
GRilIoChannel *io;
|
||||
const char *imei;
|
||||
const char *imeisv;
|
||||
const char *log_prefix;
|
||||
const char *ecclist_file;
|
||||
struct ofono_modem *ofono;
|
||||
struct sailfish_cell_info *cell_info;
|
||||
struct ril_radio *radio;
|
||||
struct ril_data *data;
|
||||
struct ril_network *network;
|
||||
struct ril_sim_card *sim_card;
|
||||
struct ril_sim_settings *sim_settings;
|
||||
struct ril_cell_info *cell_info;
|
||||
struct ril_slot_config config;
|
||||
};
|
||||
|
||||
#define RIL_PLUGIN_SIGNAL_VOICE_IMSI (0x01)
|
||||
#define RIL_PLUGIN_SIGNAL_DATA_IMSI (0x02)
|
||||
#define RIL_PLUGIN_SIGNAL_VOICE_PATH (0x04)
|
||||
#define RIL_PLUGIN_SIGNAL_DATA_PATH (0x08)
|
||||
#define RIL_PLUGIN_SIGNAL_ENABLED_SLOTS (0x10)
|
||||
#define RIL_PLUGIN_SIGNAL_MMS_IMSI (0x20)
|
||||
#define RIL_PLUGIN_SIGNAL_MMS_PATH (0x40)
|
||||
#define RIL_PLUGIN_SIGNAL_READY (0x80)
|
||||
|
||||
typedef void (*ril_modem_cb_t)(struct ril_modem *modem, void *data);
|
||||
typedef void (*ril_modem_online_cb_t)(struct ril_modem *modem, gboolean online,
|
||||
void *data);
|
||||
|
||||
void ril_plugin_set_enabled_slots(struct ril_plugin *plugin, char **slots);
|
||||
gboolean ril_plugin_set_mms_imsi(struct ril_plugin *plugin, const char *imsi);
|
||||
void ril_plugin_set_default_voice_imsi(struct ril_plugin *plugin,
|
||||
const char *imsi);
|
||||
void ril_plugin_set_default_data_imsi(struct ril_plugin *plugin,
|
||||
const char *imsi);
|
||||
|
||||
struct ril_oem_raw;
|
||||
struct ril_oem_raw *ril_oem_raw_new(struct ril_modem *md,
|
||||
struct ril_oem_raw *ril_oem_raw_new(struct ril_modem *modem,
|
||||
const char *log_prefix);
|
||||
void ril_oem_raw_free(struct ril_oem_raw *raw);
|
||||
|
||||
struct ril_sim_info_dbus;
|
||||
struct ril_sim_info_dbus *ril_sim_info_dbus_new(struct ril_modem *md,
|
||||
struct ril_sim_info *info);
|
||||
void ril_sim_info_dbus_free(struct ril_sim_info_dbus *dbus);
|
||||
|
||||
struct ril_cell_info_dbus;
|
||||
struct ril_cell_info_dbus *ril_cell_info_dbus_new(struct ril_modem *md,
|
||||
struct ril_cell_info *info);
|
||||
void ril_cell_info_dbus_free(struct ril_cell_info_dbus *dbus);
|
||||
|
||||
struct ril_plugin_dbus;
|
||||
struct ril_plugin_dbus *ril_plugin_dbus_new(struct ril_plugin *plugin);
|
||||
void ril_plugin_dbus_free(struct ril_plugin_dbus *dbus);
|
||||
void ril_plugin_dbus_block_imei_requests(struct ril_plugin_dbus *dbus,
|
||||
gboolean clock);
|
||||
void ril_plugin_dbus_signal(struct ril_plugin_dbus *dbus, int mask);
|
||||
void ril_plugin_dbus_signal_sim(struct ril_plugin_dbus *dbus, int index,
|
||||
gboolean present);
|
||||
|
||||
struct ril_modem *ril_modem_create(GRilIoChannel *io, const char *log_prefix,
|
||||
const struct ril_slot_info *slot, struct ril_radio *radio,
|
||||
struct ril_network *network, struct ril_sim_card *card,
|
||||
struct ril_data *data, struct ril_sim_settings *settings,
|
||||
struct ril_cell_info *cell_info);
|
||||
const char *path, const char *imei, const char *imeisv,
|
||||
const char *ecclist_file, const struct ril_slot_config *config,
|
||||
struct ril_radio *radio, struct ril_network *network,
|
||||
struct ril_sim_card *card, struct ril_data *data,
|
||||
struct ril_sim_settings *settings,
|
||||
struct sailfish_cell_info *cell_info);
|
||||
void ril_modem_delete(struct ril_modem *modem);
|
||||
struct ofono_sim *ril_modem_ofono_sim(struct ril_modem *modem);
|
||||
struct ofono_gprs *ril_modem_ofono_gprs(struct ril_modem *modem);
|
||||
struct ofono_netreg *ril_modem_ofono_netreg(struct ril_modem *modem);
|
||||
void ril_modem_set_removed_cb(struct ril_modem *modem, ril_modem_cb_t cb,
|
||||
void *data);
|
||||
void ril_modem_set_online_cb(struct ril_modem *modem, ril_modem_online_cb_t cb,
|
||||
void *data);
|
||||
|
||||
#define ril_modem_get_path(modem) ofono_modem_get_path((modem)->ofono)
|
||||
#define ril_modem_4g_enabled(modem) ((modem)->config.enable_4g)
|
||||
@@ -144,7 +83,7 @@ void ril_modem_set_online_cb(struct ril_modem *modem, ril_modem_online_cb_t cb,
|
||||
#define ril_modem_io(modem) ((modem)->io)
|
||||
|
||||
int ril_sim_app_type(struct ofono_sim *sim);
|
||||
int ril_netreg_check_if_really_roaming(struct ofono_netreg *netreg, gint status);
|
||||
int ril_netreg_check_if_really_roaming(struct ofono_netreg *reg, gint status);
|
||||
|
||||
extern const struct ofono_call_barring_driver ril_call_barring_driver;
|
||||
extern const struct ofono_call_forwarding_driver ril_call_forwarding_driver;
|
||||
|
||||
@@ -1,851 +0,0 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2016 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 <ofono/log.h>
|
||||
#include <ofono/dbus.h>
|
||||
|
||||
#include <gutil_strv.h>
|
||||
#include <gutil_log.h>
|
||||
#include <gdbus.h>
|
||||
|
||||
#include "ofono.h"
|
||||
|
||||
typedef void (*ril_plugin_dbus_append_fn)(DBusMessageIter *it,
|
||||
struct ril_plugin_dbus *dbus);
|
||||
typedef gboolean (*ril_plugin_dbus_slot_select_fn)
|
||||
(const struct ril_slot_info *slot);
|
||||
typedef const char *(*ril_plugin_dbus_slot_string_fn)
|
||||
(const struct ril_slot_info *slot);
|
||||
|
||||
struct ril_plugin_dbus_request {
|
||||
DBusMessage *msg;
|
||||
ril_plugin_dbus_append_fn fn;
|
||||
};
|
||||
|
||||
struct ril_plugin_dbus {
|
||||
struct ril_plugin *plugin;
|
||||
DBusConnection *conn;
|
||||
gboolean block_imei_req;
|
||||
GSList *blocked_imei_req;
|
||||
guint mms_watch;
|
||||
};
|
||||
|
||||
#define RIL_DBUS_PATH "/"
|
||||
#define RIL_DBUS_INTERFACE "org.nemomobile.ofono.ModemManager"
|
||||
#define RIL_DBUS_INTERFACE_VERSION (5)
|
||||
|
||||
#define RIL_DBUS_SIGNAL_ENABLED_MODEMS_CHANGED "EnabledModemsChanged"
|
||||
#define RIL_DBUS_SIGNAL_PRESENT_SIMS_CHANGED "PresentSimsChanged"
|
||||
#define RIL_DBUS_SIGNAL_DEFAULT_VOICE_SIM_CHANGED "DefaultVoiceSimChanged"
|
||||
#define RIL_DBUS_SIGNAL_DEFAULT_DATA_SIM_CHANGED "DefaultDataSimChanged"
|
||||
#define RIL_DBUS_SIGNAL_DEFAULT_VOICE_MODEM_CHANGED "DefaultVoiceModemChanged"
|
||||
#define RIL_DBUS_SIGNAL_DEFAULT_DATA_MODEM_CHANGED "DefaultDataModemChanged"
|
||||
#define RIL_DBUS_SIGNAL_MMS_SIM_CHANGED "MmsSimChanged"
|
||||
#define RIL_DBUS_SIGNAL_MMS_MODEM_CHANGED "MmsModemChanged"
|
||||
#define RIL_DBUS_SIGNAL_READY_CHANGED "ReadyChanged"
|
||||
#define RIL_DBUS_IMSI_AUTO "auto"
|
||||
|
||||
static gboolean ril_plugin_dbus_enabled(const struct ril_slot_info *slot)
|
||||
{
|
||||
return slot->enabled;
|
||||
}
|
||||
|
||||
static gboolean ril_plugin_dbus_present(const struct ril_slot_info *slot)
|
||||
{
|
||||
return slot->sim_present;
|
||||
}
|
||||
|
||||
static const char *ril_plugin_dbus_imei(const struct ril_slot_info *slot)
|
||||
{
|
||||
return slot->imei;
|
||||
}
|
||||
|
||||
static void ril_plugin_dbus_append_path_array(DBusMessageIter *it,
|
||||
struct ril_plugin_dbus *dbus, ril_plugin_dbus_slot_select_fn selector)
|
||||
{
|
||||
DBusMessageIter array;
|
||||
const struct ril_slot_info *const *ptr = dbus->plugin->slots;
|
||||
|
||||
dbus_message_iter_open_container(it, DBUS_TYPE_ARRAY,
|
||||
DBUS_TYPE_OBJECT_PATH_AS_STRING, &array);
|
||||
|
||||
while (*ptr) {
|
||||
const struct ril_slot_info *slot = *ptr++;
|
||||
if (!selector || selector(slot)) {
|
||||
const char *path = slot->path;
|
||||
dbus_message_iter_append_basic(&array,
|
||||
DBUS_TYPE_OBJECT_PATH, &path);
|
||||
}
|
||||
}
|
||||
|
||||
dbus_message_iter_close_container(it, &array);
|
||||
}
|
||||
|
||||
static void ril_plugin_dbus_append_string_array(DBusMessageIter *it,
|
||||
struct ril_plugin_dbus *dbus, ril_plugin_dbus_slot_string_fn fn)
|
||||
{
|
||||
DBusMessageIter array;
|
||||
const struct ril_slot_info *const *ptr = dbus->plugin->slots;
|
||||
|
||||
dbus_message_iter_open_container(it, DBUS_TYPE_ARRAY,
|
||||
DBUS_TYPE_STRING_AS_STRING, &array);
|
||||
|
||||
while (*ptr) {
|
||||
const struct ril_slot_info *slot = *ptr++;
|
||||
const char *str = fn(slot);
|
||||
|
||||
if (!str) str = "";
|
||||
dbus_message_iter_append_basic(&array, DBUS_TYPE_STRING, &str);
|
||||
}
|
||||
|
||||
dbus_message_iter_close_container(it, &array);
|
||||
}
|
||||
|
||||
static void ril_plugin_dbus_append_boolean_array(DBusMessageIter *it,
|
||||
struct ril_plugin_dbus *dbus, ril_plugin_dbus_slot_select_fn value)
|
||||
{
|
||||
DBusMessageIter array;
|
||||
const struct ril_slot_info *const *ptr = dbus->plugin->slots;
|
||||
|
||||
dbus_message_iter_open_container(it, DBUS_TYPE_ARRAY,
|
||||
DBUS_TYPE_BOOLEAN_AS_STRING, &array);
|
||||
|
||||
while (*ptr) {
|
||||
const struct ril_slot_info *slot = *ptr++;
|
||||
dbus_bool_t b = value(slot);
|
||||
|
||||
dbus_message_iter_append_basic(&array, DBUS_TYPE_BOOLEAN, &b);
|
||||
}
|
||||
|
||||
dbus_message_iter_close_container(it, &array);
|
||||
}
|
||||
|
||||
static void ril_plugin_dbus_append_boolean(DBusMessageIter *it, dbus_bool_t b)
|
||||
{
|
||||
dbus_message_iter_append_basic(it, DBUS_TYPE_BOOLEAN, &b);
|
||||
}
|
||||
|
||||
static void ril_plugin_dbus_append_string(DBusMessageIter *it, const char *str)
|
||||
{
|
||||
if (!str) str = "";
|
||||
dbus_message_iter_append_basic(it, DBUS_TYPE_STRING, &str);
|
||||
}
|
||||
|
||||
static void ril_plugin_dbus_append_imsi(DBusMessageIter *it, const char *imsi)
|
||||
{
|
||||
if (!imsi) imsi = RIL_DBUS_IMSI_AUTO;
|
||||
dbus_message_iter_append_basic(it, DBUS_TYPE_STRING, &imsi);
|
||||
}
|
||||
|
||||
static void ril_plugin_dbus_append_path(DBusMessageIter *it, const char *path)
|
||||
{
|
||||
if (!path) path = "";
|
||||
/* It's DBUS_TYPE_STRING because DBUS_TYPE_OBJECT_PATH can't be empty */
|
||||
dbus_message_iter_append_basic(it, DBUS_TYPE_STRING, &path);
|
||||
}
|
||||
|
||||
static void ril_plugin_dbus_message_append_path_array(DBusMessage *msg,
|
||||
struct ril_plugin_dbus *dbus, ril_plugin_dbus_slot_select_fn fn)
|
||||
{
|
||||
DBusMessageIter iter;
|
||||
|
||||
dbus_message_iter_init_append(msg, &iter);
|
||||
ril_plugin_dbus_append_path_array(&iter, dbus, fn);
|
||||
}
|
||||
|
||||
static void ril_plugin_dbus_signal_path_array(struct ril_plugin_dbus *dbus,
|
||||
const char *name, ril_plugin_dbus_slot_select_fn fn)
|
||||
{
|
||||
DBusMessage *signal = dbus_message_new_signal(RIL_DBUS_PATH,
|
||||
RIL_DBUS_INTERFACE, name);
|
||||
|
||||
ril_plugin_dbus_message_append_path_array(signal, dbus, fn);
|
||||
g_dbus_send_message(dbus->conn, signal);
|
||||
}
|
||||
|
||||
static inline void ril_plugin_dbus_signal_imsi(struct ril_plugin_dbus *dbus,
|
||||
const char *name, const char *imsi)
|
||||
{
|
||||
if (!imsi) imsi = RIL_DBUS_IMSI_AUTO;
|
||||
g_dbus_emit_signal(dbus->conn, RIL_DBUS_PATH, RIL_DBUS_INTERFACE,
|
||||
name, DBUS_TYPE_STRING, &imsi, DBUS_TYPE_INVALID);
|
||||
}
|
||||
|
||||
static inline void ril_plugin_dbus_signal_string(struct ril_plugin_dbus *dbus,
|
||||
const char *name, const char *str)
|
||||
{
|
||||
if (!str) str = "";
|
||||
g_dbus_emit_signal(dbus->conn, RIL_DBUS_PATH, RIL_DBUS_INTERFACE,
|
||||
name, DBUS_TYPE_STRING, &str, DBUS_TYPE_INVALID);
|
||||
}
|
||||
|
||||
static inline void ril_plugin_dbus_signal_boolean(struct ril_plugin_dbus *dbus,
|
||||
const char *name, dbus_bool_t value)
|
||||
{
|
||||
g_dbus_emit_signal(dbus->conn, RIL_DBUS_PATH, RIL_DBUS_INTERFACE,
|
||||
name, DBUS_TYPE_BOOLEAN, &value, DBUS_TYPE_INVALID);
|
||||
}
|
||||
|
||||
void ril_plugin_dbus_signal(struct ril_plugin_dbus *dbus, int mask)
|
||||
{
|
||||
if (dbus) {
|
||||
if (mask & RIL_PLUGIN_SIGNAL_VOICE_IMSI) {
|
||||
ril_plugin_dbus_signal_imsi(dbus,
|
||||
RIL_DBUS_SIGNAL_DEFAULT_VOICE_SIM_CHANGED,
|
||||
dbus->plugin->default_voice_imsi);
|
||||
}
|
||||
if (mask & RIL_PLUGIN_SIGNAL_DATA_IMSI) {
|
||||
ril_plugin_dbus_signal_imsi(dbus,
|
||||
RIL_DBUS_SIGNAL_DEFAULT_DATA_SIM_CHANGED,
|
||||
dbus->plugin->default_data_imsi);
|
||||
}
|
||||
if (mask & RIL_PLUGIN_SIGNAL_MMS_IMSI) {
|
||||
ril_plugin_dbus_signal_string(dbus,
|
||||
RIL_DBUS_SIGNAL_MMS_SIM_CHANGED,
|
||||
dbus->plugin->mms_imsi);
|
||||
}
|
||||
if (mask & RIL_PLUGIN_SIGNAL_ENABLED_SLOTS) {
|
||||
ril_plugin_dbus_signal_path_array(dbus,
|
||||
RIL_DBUS_SIGNAL_ENABLED_MODEMS_CHANGED,
|
||||
ril_plugin_dbus_enabled);
|
||||
}
|
||||
if (mask & RIL_PLUGIN_SIGNAL_VOICE_PATH) {
|
||||
ril_plugin_dbus_signal_string(dbus,
|
||||
RIL_DBUS_SIGNAL_DEFAULT_VOICE_MODEM_CHANGED,
|
||||
dbus->plugin->default_voice_path);
|
||||
}
|
||||
if (mask & RIL_PLUGIN_SIGNAL_DATA_PATH) {
|
||||
ril_plugin_dbus_signal_string(dbus,
|
||||
RIL_DBUS_SIGNAL_DEFAULT_DATA_MODEM_CHANGED,
|
||||
dbus->plugin->default_data_path);
|
||||
}
|
||||
if (mask & RIL_PLUGIN_SIGNAL_MMS_PATH) {
|
||||
ril_plugin_dbus_signal_string(dbus,
|
||||
RIL_DBUS_SIGNAL_MMS_MODEM_CHANGED,
|
||||
dbus->plugin->mms_path);
|
||||
}
|
||||
if (mask & RIL_PLUGIN_SIGNAL_READY) {
|
||||
ril_plugin_dbus_signal_boolean(dbus,
|
||||
RIL_DBUS_SIGNAL_READY_CHANGED,
|
||||
dbus->plugin->ready);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ril_plugin_dbus_signal_sim(struct ril_plugin_dbus *dbus, int index,
|
||||
gboolean present)
|
||||
{
|
||||
dbus_bool_t value = present;
|
||||
g_dbus_emit_signal(dbus->conn, RIL_DBUS_PATH, RIL_DBUS_INTERFACE,
|
||||
RIL_DBUS_SIGNAL_PRESENT_SIMS_CHANGED,
|
||||
DBUS_TYPE_INT32, &index,
|
||||
DBUS_TYPE_BOOLEAN, &value,
|
||||
DBUS_TYPE_INVALID);
|
||||
}
|
||||
|
||||
static DBusMessage *ril_plugin_dbus_reply_with_path_array(DBusMessage *msg,
|
||||
struct ril_plugin_dbus *dbus, ril_plugin_dbus_slot_select_fn fn)
|
||||
{
|
||||
DBusMessage *reply = dbus_message_new_method_return(msg);
|
||||
|
||||
ril_plugin_dbus_message_append_path_array(reply, dbus, fn);
|
||||
return reply;
|
||||
}
|
||||
|
||||
static DBusMessage *ril_plugin_dbus_reply(DBusMessage *msg,
|
||||
struct ril_plugin_dbus *dbus, ril_plugin_dbus_append_fn append)
|
||||
{
|
||||
DBusMessage *reply = dbus_message_new_method_return(msg);
|
||||
DBusMessageIter iter;
|
||||
|
||||
dbus_message_iter_init_append(reply, &iter);
|
||||
append(&iter, dbus);
|
||||
return reply;
|
||||
}
|
||||
|
||||
static void ril_plugin_dbus_unblock_request(gpointer data, gpointer user_data)
|
||||
{
|
||||
struct ril_plugin_dbus_request *req = data;
|
||||
|
||||
DBG("unblocking IMEI request %p", req);
|
||||
__ofono_dbus_pending_reply(&req->msg, ril_plugin_dbus_reply(req->msg,
|
||||
(struct ril_plugin_dbus *)user_data, req->fn));
|
||||
g_free(req);
|
||||
}
|
||||
|
||||
static void ril_plugin_dbus_cancel_request(gpointer data)
|
||||
{
|
||||
struct ril_plugin_dbus_request *req = data;
|
||||
|
||||
DBG("canceling IMEI request %p", req);
|
||||
__ofono_dbus_pending_reply(&req->msg, __ofono_error_canceled(req->msg));
|
||||
g_free(req);
|
||||
}
|
||||
|
||||
void ril_plugin_dbus_block_imei_requests(struct ril_plugin_dbus *dbus,
|
||||
gboolean block)
|
||||
{
|
||||
dbus->block_imei_req = block;
|
||||
if (!block && dbus->blocked_imei_req) {
|
||||
g_slist_foreach(dbus->blocked_imei_req,
|
||||
ril_plugin_dbus_unblock_request, dbus);
|
||||
g_slist_free(dbus->blocked_imei_req);
|
||||
dbus->blocked_imei_req = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static DBusMessage *ril_plugin_dbus_imei_reply(DBusMessage *msg,
|
||||
struct ril_plugin_dbus *dbus, ril_plugin_dbus_append_fn fn)
|
||||
{
|
||||
if (dbus->block_imei_req) {
|
||||
struct ril_plugin_dbus_request *req =
|
||||
g_new(struct ril_plugin_dbus_request, 1);
|
||||
|
||||
req->msg = dbus_message_ref(msg);
|
||||
req->fn = fn;
|
||||
dbus->blocked_imei_req = g_slist_append(dbus->blocked_imei_req,
|
||||
req);
|
||||
DBG("blocking IMEI request %p", req);
|
||||
return NULL;
|
||||
} else {
|
||||
return ril_plugin_dbus_reply(msg, dbus, fn);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_plugin_dbus_append_version(DBusMessageIter *it,
|
||||
struct ril_plugin_dbus *dbus)
|
||||
{
|
||||
dbus_int32_t version = RIL_DBUS_INTERFACE_VERSION;
|
||||
|
||||
dbus_message_iter_append_basic(it, DBUS_TYPE_INT32, &version);
|
||||
}
|
||||
|
||||
static void ril_plugin_dbus_append_all(DBusMessageIter *it,
|
||||
struct ril_plugin_dbus *dbus)
|
||||
{
|
||||
ril_plugin_dbus_append_version(it, dbus);
|
||||
ril_plugin_dbus_append_path_array(it, dbus, NULL);
|
||||
ril_plugin_dbus_append_path_array(it, dbus, ril_plugin_dbus_enabled);
|
||||
ril_plugin_dbus_append_imsi(it, dbus->plugin->default_data_imsi);
|
||||
ril_plugin_dbus_append_imsi(it, dbus->plugin->default_voice_imsi);
|
||||
ril_plugin_dbus_append_path(it, dbus->plugin->default_data_path);
|
||||
ril_plugin_dbus_append_path(it, dbus->plugin->default_voice_path);
|
||||
}
|
||||
|
||||
static void ril_plugin_dbus_append_all2(DBusMessageIter *it,
|
||||
struct ril_plugin_dbus *dbus)
|
||||
{
|
||||
ril_plugin_dbus_append_all(it, dbus);
|
||||
ril_plugin_dbus_append_boolean_array(it, dbus, ril_plugin_dbus_present);
|
||||
}
|
||||
|
||||
static void ril_plugin_dbus_append_all3(DBusMessageIter *it,
|
||||
struct ril_plugin_dbus *dbus)
|
||||
{
|
||||
ril_plugin_dbus_append_all2(it, dbus);
|
||||
ril_plugin_dbus_append_string_array(it, dbus, ril_plugin_dbus_imei);
|
||||
}
|
||||
|
||||
static void ril_plugin_dbus_append_all4(DBusMessageIter *it,
|
||||
struct ril_plugin_dbus *dbus)
|
||||
{
|
||||
ril_plugin_dbus_append_all3(it, dbus);
|
||||
ril_plugin_dbus_append_string(it, dbus->plugin->mms_imsi);
|
||||
ril_plugin_dbus_append_path(it, dbus->plugin->mms_path);
|
||||
}
|
||||
|
||||
static void ril_plugin_dbus_append_all5(DBusMessageIter *it,
|
||||
struct ril_plugin_dbus *dbus)
|
||||
{
|
||||
ril_plugin_dbus_append_all4(it, dbus);
|
||||
ril_plugin_dbus_append_boolean(it, dbus->plugin->ready);
|
||||
}
|
||||
|
||||
static DBusMessage *ril_plugin_dbus_get_all(DBusConnection *conn,
|
||||
DBusMessage *msg, void *data)
|
||||
{
|
||||
return ril_plugin_dbus_reply(msg, (struct ril_plugin_dbus *)data,
|
||||
ril_plugin_dbus_append_all);
|
||||
}
|
||||
|
||||
static DBusMessage *ril_plugin_dbus_get_all2(DBusConnection *conn,
|
||||
DBusMessage *msg, void *data)
|
||||
{
|
||||
return ril_plugin_dbus_reply(msg, (struct ril_plugin_dbus *)data,
|
||||
ril_plugin_dbus_append_all2);
|
||||
}
|
||||
|
||||
static DBusMessage *ril_plugin_dbus_get_all3(DBusConnection *conn,
|
||||
DBusMessage *msg, void *data)
|
||||
{
|
||||
return ril_plugin_dbus_imei_reply(msg, (struct ril_plugin_dbus *)data,
|
||||
ril_plugin_dbus_append_all3);
|
||||
}
|
||||
|
||||
static DBusMessage *ril_plugin_dbus_get_all4(DBusConnection *conn,
|
||||
DBusMessage *msg, void *data)
|
||||
{
|
||||
return ril_plugin_dbus_imei_reply(msg, (struct ril_plugin_dbus *)data,
|
||||
ril_plugin_dbus_append_all4);
|
||||
}
|
||||
|
||||
static DBusMessage *ril_plugin_dbus_get_all5(DBusConnection *conn,
|
||||
DBusMessage *msg, void *data)
|
||||
{
|
||||
return ril_plugin_dbus_imei_reply(msg, (struct ril_plugin_dbus *)data,
|
||||
ril_plugin_dbus_append_all5);
|
||||
}
|
||||
|
||||
static DBusMessage *ril_plugin_dbus_get_interface_version(DBusConnection *conn,
|
||||
DBusMessage *msg, void *data)
|
||||
{
|
||||
return ril_plugin_dbus_reply(msg, (struct ril_plugin_dbus *)data,
|
||||
ril_plugin_dbus_append_version);
|
||||
}
|
||||
|
||||
static DBusMessage *ril_plugin_dbus_get_available_modems(DBusConnection *conn,
|
||||
DBusMessage *msg, void *data)
|
||||
{
|
||||
return ril_plugin_dbus_reply_with_path_array(msg,
|
||||
(struct ril_plugin_dbus *)data, NULL);
|
||||
}
|
||||
|
||||
static DBusMessage *ril_plugin_dbus_get_enabled_modems(DBusConnection *conn,
|
||||
DBusMessage *msg, void *data)
|
||||
{
|
||||
return ril_plugin_dbus_reply_with_path_array(msg,
|
||||
(struct ril_plugin_dbus *)data, ril_plugin_dbus_enabled);
|
||||
}
|
||||
|
||||
static void ril_plugin_dbus_append_present_sims(DBusMessageIter *it,
|
||||
struct ril_plugin_dbus *dbus)
|
||||
{
|
||||
ril_plugin_dbus_append_boolean_array(it, dbus, ril_plugin_dbus_present);
|
||||
}
|
||||
|
||||
static DBusMessage *ril_plugin_dbus_get_present_sims(DBusConnection *conn,
|
||||
DBusMessage *msg, void *data)
|
||||
{
|
||||
return ril_plugin_dbus_reply(msg, (struct ril_plugin_dbus *)data,
|
||||
ril_plugin_dbus_append_present_sims);
|
||||
}
|
||||
|
||||
static void ril_plugin_dbus_append_imei_array(DBusMessageIter *it,
|
||||
struct ril_plugin_dbus *dbus)
|
||||
{
|
||||
ril_plugin_dbus_append_string_array(it, dbus, ril_plugin_dbus_imei);
|
||||
}
|
||||
|
||||
static DBusMessage *ril_plugin_dbus_get_imei(DBusConnection *conn,
|
||||
DBusMessage *msg, void *data)
|
||||
{
|
||||
return ril_plugin_dbus_imei_reply(msg, (struct ril_plugin_dbus *)data,
|
||||
ril_plugin_dbus_append_imei_array);
|
||||
}
|
||||
|
||||
static DBusMessage *ril_plugin_dbus_reply_with_string(DBusMessage *msg,
|
||||
const char *str)
|
||||
{
|
||||
DBusMessage *reply = dbus_message_new_method_return(msg);
|
||||
DBusMessageIter iter;
|
||||
|
||||
dbus_message_iter_init_append(reply, &iter);
|
||||
ril_plugin_dbus_append_string(&iter, str);
|
||||
return reply;
|
||||
}
|
||||
|
||||
static DBusMessage *ril_plugin_dbus_reply_with_imsi(DBusMessage *msg,
|
||||
const char *imsi)
|
||||
{
|
||||
DBusMessage *reply = dbus_message_new_method_return(msg);
|
||||
DBusMessageIter iter;
|
||||
|
||||
dbus_message_iter_init_append(reply, &iter);
|
||||
ril_plugin_dbus_append_imsi(&iter, imsi);
|
||||
return reply;
|
||||
}
|
||||
|
||||
static DBusMessage *ril_plugin_dbus_get_default_data_sim(DBusConnection *conn,
|
||||
DBusMessage *msg, void *data)
|
||||
{
|
||||
struct ril_plugin_dbus *dbus = data;
|
||||
|
||||
return ril_plugin_dbus_reply_with_imsi(msg,
|
||||
dbus->plugin->default_data_imsi);
|
||||
}
|
||||
|
||||
static DBusMessage *ril_plugin_dbus_get_default_voice_sim(DBusConnection *conn,
|
||||
DBusMessage *msg, void *data)
|
||||
{
|
||||
struct ril_plugin_dbus *dbus = data;
|
||||
|
||||
return ril_plugin_dbus_reply_with_imsi(msg,
|
||||
dbus->plugin->default_voice_imsi);
|
||||
}
|
||||
|
||||
static DBusMessage *ril_plugin_dbus_get_mms_sim(DBusConnection *conn,
|
||||
DBusMessage *msg, void *data)
|
||||
{
|
||||
struct ril_plugin_dbus *dbus = data;
|
||||
|
||||
return ril_plugin_dbus_reply_with_string(msg, dbus->plugin->mms_imsi);
|
||||
}
|
||||
|
||||
static DBusMessage *ril_plugin_dbus_reply_with_path(DBusMessage *msg,
|
||||
const char *path)
|
||||
{
|
||||
DBusMessage *reply = dbus_message_new_method_return(msg);
|
||||
DBusMessageIter iter;
|
||||
|
||||
dbus_message_iter_init_append(reply, &iter);
|
||||
ril_plugin_dbus_append_path(&iter, path);
|
||||
return reply;
|
||||
}
|
||||
|
||||
static DBusMessage *ril_plugin_dbus_get_default_data_modem(DBusConnection *conn,
|
||||
DBusMessage *msg, void *data)
|
||||
{
|
||||
struct ril_plugin_dbus *dbus = data;
|
||||
|
||||
return ril_plugin_dbus_reply_with_path(msg,
|
||||
dbus->plugin->default_data_path);
|
||||
}
|
||||
|
||||
static DBusMessage *ril_plugin_dbus_get_default_voice_modem(DBusConnection *conn,
|
||||
DBusMessage *msg, void *data)
|
||||
{
|
||||
struct ril_plugin_dbus *dbus = data;
|
||||
|
||||
return ril_plugin_dbus_reply_with_path(msg,
|
||||
dbus->plugin->default_voice_path);
|
||||
}
|
||||
|
||||
static DBusMessage *ril_plugin_dbus_get_mms_modem(DBusConnection *conn,
|
||||
DBusMessage *msg, void *data)
|
||||
{
|
||||
struct ril_plugin_dbus *dbus = data;
|
||||
|
||||
return ril_plugin_dbus_reply_with_path(msg, dbus->plugin->mms_path);
|
||||
}
|
||||
|
||||
static DBusMessage *ril_plugin_dbus_get_ready(DBusConnection *conn,
|
||||
DBusMessage *msg, void *data)
|
||||
{
|
||||
struct ril_plugin_dbus *dbus = data;
|
||||
DBusMessage *reply = dbus_message_new_method_return(msg);
|
||||
DBusMessageIter it;
|
||||
|
||||
dbus_message_iter_init_append(reply, &it);
|
||||
ril_plugin_dbus_append_boolean(&it, dbus->plugin->ready);
|
||||
return reply;
|
||||
}
|
||||
|
||||
static DBusMessage *ril_plugin_dbus_set_enabled_modems(DBusConnection *conn,
|
||||
DBusMessage *msg, void *data)
|
||||
{
|
||||
struct ril_plugin_dbus *dbus = data;
|
||||
DBusMessageIter iter;
|
||||
|
||||
dbus_message_iter_init(msg, &iter);
|
||||
if (dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_ARRAY) {
|
||||
char **paths = NULL;
|
||||
DBusMessageIter array;
|
||||
|
||||
dbus_message_iter_recurse(&iter, &array);
|
||||
while (dbus_message_iter_get_arg_type(&array) ==
|
||||
DBUS_TYPE_OBJECT_PATH) {
|
||||
DBusBasicValue value;
|
||||
|
||||
dbus_message_iter_get_basic(&array, &value);
|
||||
paths = gutil_strv_add(paths, value.str);
|
||||
dbus_message_iter_next(&array);
|
||||
}
|
||||
|
||||
ril_plugin_set_enabled_slots(dbus->plugin, paths);
|
||||
g_strfreev(paths);
|
||||
return dbus_message_new_method_return(msg);
|
||||
} else {
|
||||
return __ofono_error_invalid_args(msg);
|
||||
}
|
||||
}
|
||||
|
||||
static DBusMessage *ril_plugin_dbus_set_imsi(struct ril_plugin_dbus *dbus,
|
||||
DBusMessage *msg, void (*apply)(struct ril_plugin *plugin,
|
||||
const char *imsi))
|
||||
{
|
||||
DBusMessageIter iter;
|
||||
|
||||
dbus_message_iter_init(msg, &iter);
|
||||
if (dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_STRING) {
|
||||
DBusBasicValue value;
|
||||
const char *imsi;
|
||||
|
||||
dbus_message_iter_get_basic(&iter, &value);
|
||||
imsi = value.str;
|
||||
if (!g_strcmp0(imsi, RIL_DBUS_IMSI_AUTO)) imsi = NULL;
|
||||
apply(dbus->plugin, imsi);
|
||||
return dbus_message_new_method_return(msg);
|
||||
} else {
|
||||
return __ofono_error_invalid_args(msg);
|
||||
}
|
||||
}
|
||||
|
||||
static DBusMessage *ril_plugin_dbus_set_default_voice_sim(DBusConnection *conn,
|
||||
DBusMessage *msg, void *data)
|
||||
{
|
||||
struct ril_plugin_dbus *dbus = data;
|
||||
|
||||
GASSERT(conn == dbus->conn);
|
||||
return ril_plugin_dbus_set_imsi(dbus, msg,
|
||||
ril_plugin_set_default_voice_imsi);
|
||||
}
|
||||
|
||||
static DBusMessage *ril_plugin_dbus_set_default_data_sim(DBusConnection *conn,
|
||||
DBusMessage *msg, void *data)
|
||||
{
|
||||
struct ril_plugin_dbus *dbus = data;
|
||||
|
||||
GASSERT(conn == dbus->conn);
|
||||
return ril_plugin_dbus_set_imsi(dbus, msg,
|
||||
ril_plugin_set_default_data_imsi);
|
||||
}
|
||||
|
||||
static void ril_plugin_dbus_mms_disconnect(DBusConnection *conn, void *data)
|
||||
{
|
||||
struct ril_plugin_dbus *dbus = data;
|
||||
|
||||
dbus->mms_watch = 0;
|
||||
if (dbus->plugin->mms_imsi) {
|
||||
DBG("MMS client is gone");
|
||||
ril_plugin_set_mms_imsi(dbus->plugin, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static DBusMessage *ril_plugin_dbus_set_mms_sim(DBusConnection *conn,
|
||||
DBusMessage *msg, void *data)
|
||||
{
|
||||
DBusMessageIter iter;
|
||||
struct ril_plugin_dbus *dbus = data;
|
||||
|
||||
GASSERT(conn == dbus->conn);
|
||||
dbus_message_iter_init(msg, &iter);
|
||||
if (dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_STRING) {
|
||||
DBusBasicValue value;
|
||||
const char *imsi;
|
||||
|
||||
dbus_message_iter_get_basic(&iter, &value);
|
||||
imsi = value.str;
|
||||
|
||||
/*
|
||||
* MMS IMSI is not persistent and has to be eventually
|
||||
* reset by the client or cleaned up if the client
|
||||
* unexpectedly disappears.
|
||||
*/
|
||||
if (ril_plugin_set_mms_imsi(dbus->plugin, imsi)) {
|
||||
|
||||
/*
|
||||
* Clear the previous MMS owner
|
||||
*/
|
||||
if (dbus->mms_watch) {
|
||||
g_dbus_remove_watch(dbus->conn, dbus->mms_watch);
|
||||
dbus->mms_watch = 0;
|
||||
}
|
||||
|
||||
if (dbus->plugin->mms_imsi &&
|
||||
dbus->plugin->mms_imsi[0]) {
|
||||
/*
|
||||
* This client becomes the owner
|
||||
*/
|
||||
DBG("Owner: %s", dbus_message_get_sender(msg));
|
||||
dbus->mms_watch =
|
||||
g_dbus_add_disconnect_watch(dbus->conn,
|
||||
dbus_message_get_sender(msg),
|
||||
ril_plugin_dbus_mms_disconnect,
|
||||
dbus, NULL);
|
||||
}
|
||||
|
||||
return ril_plugin_dbus_reply_with_string(msg,
|
||||
dbus->plugin->mms_path);
|
||||
} else {
|
||||
return __ofono_error_not_available(msg);
|
||||
}
|
||||
} else {
|
||||
return __ofono_error_invalid_args(msg);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* The client can call GetInterfaceVersion followed by the appropriate
|
||||
* GetAllx call to get all settings in two steps. Alternatively, it can
|
||||
* call GetAll followed by GetAllx based on the interface version returned
|
||||
* by GetAll. In either case, two D-Bus calls are required, unless the
|
||||
* client is willing to make the assumption about the ofono version it's
|
||||
* talking to.
|
||||
*/
|
||||
|
||||
#define RIL_DBUS_GET_ALL_ARGS \
|
||||
{"version", "i" }, \
|
||||
{"availableModems", "ao" }, \
|
||||
{"enabledModems", "ao" }, \
|
||||
{"defaultDataSim", "s" }, \
|
||||
{"defaultVoiceSim", "s" }, \
|
||||
{"defaultDataModem", "s" }, \
|
||||
{"defaultVoiceModem" , "s"}
|
||||
#define RIL_DBUS_GET_ALL2_ARGS \
|
||||
RIL_DBUS_GET_ALL_ARGS, \
|
||||
{"presentSims" , "ab"}
|
||||
#define RIL_DBUS_GET_ALL3_ARGS \
|
||||
RIL_DBUS_GET_ALL2_ARGS, \
|
||||
{"imei" , "as"}
|
||||
#define RIL_DBUS_GET_ALL4_ARGS \
|
||||
RIL_DBUS_GET_ALL3_ARGS, \
|
||||
{"mmsSim", "s" }, \
|
||||
{"mmsModem" , "s"}
|
||||
#define RIL_DBUS_GET_ALL5_ARGS \
|
||||
RIL_DBUS_GET_ALL4_ARGS, \
|
||||
{"ready" , "b"}
|
||||
|
||||
static const GDBusMethodTable ril_plugin_dbus_methods[] = {
|
||||
{ GDBUS_METHOD("GetAll",
|
||||
NULL, GDBUS_ARGS(RIL_DBUS_GET_ALL_ARGS),
|
||||
ril_plugin_dbus_get_all) },
|
||||
{ GDBUS_METHOD("GetAll2",
|
||||
NULL, GDBUS_ARGS(RIL_DBUS_GET_ALL2_ARGS),
|
||||
ril_plugin_dbus_get_all2) },
|
||||
{ GDBUS_ASYNC_METHOD("GetAll3",
|
||||
NULL, GDBUS_ARGS(RIL_DBUS_GET_ALL3_ARGS),
|
||||
ril_plugin_dbus_get_all3) },
|
||||
{ GDBUS_ASYNC_METHOD("GetAll4",
|
||||
NULL, GDBUS_ARGS(RIL_DBUS_GET_ALL4_ARGS),
|
||||
ril_plugin_dbus_get_all4) },
|
||||
{ GDBUS_ASYNC_METHOD("GetAll5",
|
||||
NULL, GDBUS_ARGS(RIL_DBUS_GET_ALL5_ARGS),
|
||||
ril_plugin_dbus_get_all5) },
|
||||
{ GDBUS_METHOD("GetInterfaceVersion",
|
||||
NULL, GDBUS_ARGS({ "version", "i" }),
|
||||
ril_plugin_dbus_get_interface_version) },
|
||||
{ GDBUS_METHOD("GetAvailableModems",
|
||||
NULL, GDBUS_ARGS({ "modems", "ao" }),
|
||||
ril_plugin_dbus_get_available_modems) },
|
||||
{ GDBUS_METHOD("GetEnabledModems",
|
||||
NULL, GDBUS_ARGS({ "modems", "ao" }),
|
||||
ril_plugin_dbus_get_enabled_modems) },
|
||||
{ GDBUS_METHOD("GetPresentSims",
|
||||
NULL, GDBUS_ARGS({ "presentSims", "ab" }),
|
||||
ril_plugin_dbus_get_present_sims) },
|
||||
{ GDBUS_ASYNC_METHOD("GetIMEI",
|
||||
NULL, GDBUS_ARGS({ "imei", "as" }),
|
||||
ril_plugin_dbus_get_imei) },
|
||||
{ GDBUS_METHOD("GetDefaultDataSim",
|
||||
NULL, GDBUS_ARGS({ "imsi", "s" }),
|
||||
ril_plugin_dbus_get_default_data_sim) },
|
||||
{ GDBUS_METHOD("GetDefaultVoiceSim",
|
||||
NULL, GDBUS_ARGS({ "imsi", "s" }),
|
||||
ril_plugin_dbus_get_default_voice_sim) },
|
||||
{ GDBUS_METHOD("GetMmsSim",
|
||||
NULL, GDBUS_ARGS({ "imsi", "s" }),
|
||||
ril_plugin_dbus_get_mms_sim) },
|
||||
{ GDBUS_METHOD("GetDefaultDataModem",
|
||||
NULL, GDBUS_ARGS({ "path", "s" }),
|
||||
ril_plugin_dbus_get_default_data_modem) },
|
||||
{ GDBUS_METHOD("GetDefaultVoiceModem",
|
||||
NULL, GDBUS_ARGS({ "path", "s" }),
|
||||
ril_plugin_dbus_get_default_voice_modem) },
|
||||
{ GDBUS_METHOD("GetMmsModem",
|
||||
NULL, GDBUS_ARGS({ "path", "s" }),
|
||||
ril_plugin_dbus_get_mms_modem) },
|
||||
{ GDBUS_METHOD("GetReady",
|
||||
NULL, GDBUS_ARGS({ "ready", "b" }),
|
||||
ril_plugin_dbus_get_ready) },
|
||||
{ GDBUS_METHOD("SetEnabledModems",
|
||||
GDBUS_ARGS({ "modems", "ao" }), NULL,
|
||||
ril_plugin_dbus_set_enabled_modems) },
|
||||
{ GDBUS_METHOD("SetDefaultDataSim",
|
||||
GDBUS_ARGS({ "imsi", "s" }), NULL,
|
||||
ril_plugin_dbus_set_default_data_sim) },
|
||||
{ GDBUS_METHOD("SetDefaultVoiceSim",
|
||||
GDBUS_ARGS({ "imsi", "s" }), NULL,
|
||||
ril_plugin_dbus_set_default_voice_sim) },
|
||||
{ GDBUS_METHOD("SetMmsSim",
|
||||
GDBUS_ARGS({ "imsi", "s" }), NULL,
|
||||
ril_plugin_dbus_set_mms_sim) },
|
||||
{ }
|
||||
};
|
||||
|
||||
static const GDBusSignalTable ril_plugin_dbus_signals[] = {
|
||||
{ GDBUS_SIGNAL(RIL_DBUS_SIGNAL_ENABLED_MODEMS_CHANGED,
|
||||
GDBUS_ARGS({ "modems", "ao" })) },
|
||||
{ GDBUS_SIGNAL(RIL_DBUS_SIGNAL_PRESENT_SIMS_CHANGED,
|
||||
GDBUS_ARGS({"index", "i" },
|
||||
{"present" , "b"})) },
|
||||
{ GDBUS_SIGNAL(RIL_DBUS_SIGNAL_DEFAULT_DATA_SIM_CHANGED,
|
||||
GDBUS_ARGS({ "imsi", "s" })) },
|
||||
{ GDBUS_SIGNAL(RIL_DBUS_SIGNAL_DEFAULT_VOICE_SIM_CHANGED,
|
||||
GDBUS_ARGS({ "imsi", "s" })) },
|
||||
{ GDBUS_SIGNAL(RIL_DBUS_SIGNAL_DEFAULT_DATA_MODEM_CHANGED,
|
||||
GDBUS_ARGS({ "path", "s" })) },
|
||||
{ GDBUS_SIGNAL(RIL_DBUS_SIGNAL_DEFAULT_VOICE_MODEM_CHANGED,
|
||||
GDBUS_ARGS({ "path", "s" })) },
|
||||
{ GDBUS_SIGNAL(RIL_DBUS_SIGNAL_MMS_SIM_CHANGED,
|
||||
GDBUS_ARGS({ "imsi", "s" })) },
|
||||
{ GDBUS_SIGNAL(RIL_DBUS_SIGNAL_MMS_MODEM_CHANGED,
|
||||
GDBUS_ARGS({ "path", "s" })) },
|
||||
{ GDBUS_SIGNAL(RIL_DBUS_SIGNAL_READY_CHANGED,
|
||||
GDBUS_ARGS({ "ready", "b" })) },
|
||||
{ }
|
||||
};
|
||||
|
||||
struct ril_plugin_dbus *ril_plugin_dbus_new(struct ril_plugin *plugin)
|
||||
{
|
||||
struct ril_plugin_dbus *dbus = g_new0(struct ril_plugin_dbus, 1);
|
||||
|
||||
dbus->conn = dbus_connection_ref(ofono_dbus_get_connection());
|
||||
dbus->plugin = plugin;
|
||||
if (g_dbus_register_interface(dbus->conn, RIL_DBUS_PATH,
|
||||
RIL_DBUS_INTERFACE, ril_plugin_dbus_methods,
|
||||
ril_plugin_dbus_signals, NULL, dbus, NULL)) {
|
||||
return dbus;
|
||||
} else {
|
||||
ofono_error("RIL D-Bus register failed");
|
||||
ril_plugin_dbus_free(dbus);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void ril_plugin_dbus_free(struct ril_plugin_dbus *dbus)
|
||||
{
|
||||
if (dbus) {
|
||||
if (dbus->mms_watch) {
|
||||
g_dbus_remove_watch(dbus->conn, dbus->mms_watch);
|
||||
}
|
||||
|
||||
g_slist_free_full(dbus->blocked_imei_req,
|
||||
ril_plugin_dbus_cancel_request);
|
||||
g_dbus_unregister_interface(dbus->conn, RIL_DBUS_PATH,
|
||||
RIL_DBUS_INTERFACE);
|
||||
dbus_connection_unref(dbus->conn);
|
||||
g_free(dbus);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2016 Jolla Ltd.
|
||||
* Copyright (C) 2015-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
|
||||
@@ -99,13 +99,14 @@ static inline void ril_radio_emit_signal(struct ril_radio *self,
|
||||
|
||||
static gboolean ril_radio_power_request_retry_cb(gpointer user_data)
|
||||
{
|
||||
struct ril_radio *self = user_data;
|
||||
struct ril_radio *self = RIL_RADIO(user_data);
|
||||
struct ril_radio_priv *priv = self->priv;
|
||||
|
||||
DBG("%s", priv->log_prefix);
|
||||
GASSERT(priv->retry_id);
|
||||
priv->retry_id = 0;
|
||||
ril_radio_submit_power_request(self, ril_radio_power_should_be_on(self));
|
||||
ril_radio_submit_power_request(self,
|
||||
ril_radio_power_should_be_on(self));
|
||||
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
@@ -126,7 +127,7 @@ static void ril_radio_check_state(struct ril_radio *self)
|
||||
struct ril_radio_priv *priv = self->priv;
|
||||
|
||||
if (!priv->pending_id) {
|
||||
const gboolean should_be_on = ril_radio_power_should_be_on(self);
|
||||
gboolean should_be_on = ril_radio_power_should_be_on(self);
|
||||
|
||||
if (ril_radio_state_on(self->priv->last_known_state) ==
|
||||
should_be_on) {
|
||||
@@ -157,7 +158,7 @@ static void ril_radio_check_state(struct ril_radio *self)
|
||||
static void ril_radio_power_request_cb(GRilIoChannel *channel, int ril_status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_radio *self = user_data;
|
||||
struct ril_radio *self = RIL_RADIO(user_data);
|
||||
struct ril_radio_priv *priv = self->priv;
|
||||
|
||||
GASSERT(priv->pending_id);
|
||||
@@ -177,11 +178,17 @@ static void ril_radio_power_request_cb(GRilIoChannel *channel, int ril_status,
|
||||
|
||||
static void ril_radio_submit_power_request(struct ril_radio *self, gboolean on)
|
||||
{
|
||||
/*
|
||||
* RIL_REQUEST_RADIO_POWER
|
||||
*
|
||||
* "data" is int *
|
||||
* ((int *)data)[0] is > 0 for "Radio On"
|
||||
* ((int *)data)[0] is == 0 for "Radio Off"
|
||||
*
|
||||
* "response" is NULL
|
||||
**/
|
||||
GRilIoRequest *req = grilio_request_array_int32_new(1, on);
|
||||
struct ril_radio_priv *priv = self->priv;
|
||||
GRilIoRequest *req = grilio_request_sized_new(8);
|
||||
|
||||
grilio_request_append_int32(req, 1);
|
||||
grilio_request_append_int32(req, on); /* Radio ON=1, OFF=0 */
|
||||
|
||||
priv->next_state_valid = FALSE;
|
||||
priv->next_state = on;
|
||||
@@ -189,8 +196,10 @@ static void ril_radio_submit_power_request(struct ril_radio *self, gboolean on)
|
||||
ril_radio_cancel_retry(self);
|
||||
|
||||
GASSERT(!priv->pending_id);
|
||||
grilio_request_set_blocking(req, TRUE);
|
||||
priv->pending_id = grilio_queue_send_request_full(priv->q, req,
|
||||
RIL_REQUEST_RADIO_POWER, ril_radio_power_request_cb, NULL, self);
|
||||
RIL_REQUEST_RADIO_POWER, ril_radio_power_request_cb,
|
||||
NULL, self);
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
@@ -330,7 +339,7 @@ enum ril_radio_state ril_radio_state_parse(const void *data, guint len)
|
||||
static void ril_radio_state_changed(GRilIoChannel *io, guint code,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_radio *self = user_data;
|
||||
struct ril_radio *self = RIL_RADIO(user_data);
|
||||
enum ril_radio_state radio_state = ril_radio_state_parse(data, len);
|
||||
|
||||
GASSERT(code == RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2016 Jolla Ltd.
|
||||
* Copyright (C) 2015-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
|
||||
@@ -44,6 +44,9 @@ void ril_radio_remove_handler(struct ril_radio *radio, gulong id);
|
||||
void ril_radio_remove_handlers(struct ril_radio *radio, gulong *ids, int n);
|
||||
enum ril_radio_state ril_radio_state_parse(const void *data, guint len);
|
||||
|
||||
#define ril_radio_remove_all_handlers(r,ids) \
|
||||
ril_radio_remove_handlers(r, ids, G_N_ELEMENTS(ids))
|
||||
|
||||
#endif /* RIL_RADIO_H */
|
||||
|
||||
/*
|
||||
|
||||
1416
ofono/drivers/ril/ril_radio_caps.c
Normal file
1416
ofono/drivers/ril/ril_radio_caps.c
Normal file
File diff suppressed because it is too large
Load Diff
66
ofono/drivers/ril/ril_radio_caps.h
Normal file
66
ofono/drivers/ril/ril_radio_caps.h
Normal file
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef RIL_RADIO_CAPS_H
|
||||
#define RIL_RADIO_CAPS_H
|
||||
|
||||
#include "ril_types.h"
|
||||
|
||||
struct ril_data_manager;
|
||||
struct ril_radio_caps;
|
||||
struct ril_radio_caps_manager;
|
||||
struct ril_radio_capability;
|
||||
|
||||
typedef void (*ril_radio_caps_manager_cb_t)(struct ril_radio_caps_manager *mgr,
|
||||
void *user_data);
|
||||
/* ril_radio_capability pointer is NULL if functionality is unsupported */
|
||||
typedef void (*ril_radio_caps_check_cb_t)
|
||||
(const struct ril_radio_capability *cap, void *user_data);
|
||||
|
||||
/* The check can be cancelled with grilio_channel_cancel_request */
|
||||
guint ril_radio_caps_check(GRilIoChannel *io, ril_radio_caps_check_cb_t cb,
|
||||
void *user_data);
|
||||
|
||||
/* There should be a single ril_radio_caps_manager shared by all all modems */
|
||||
struct ril_radio_caps_manager *ril_radio_caps_manager_new
|
||||
(struct ril_data_manager *dm);
|
||||
struct ril_radio_caps_manager *ril_radio_caps_manager_ref
|
||||
(struct ril_radio_caps_manager *mgr);
|
||||
void ril_radio_caps_manager_unref(struct ril_radio_caps_manager *mgr);
|
||||
gulong ril_radio_caps_manager_add_aborted_handler
|
||||
(struct ril_radio_caps_manager *mgr,
|
||||
ril_radio_caps_manager_cb_t cb, void *arg);
|
||||
void ril_radio_caps_manager_remove_handler(struct ril_radio_caps_manager *mgr,
|
||||
gulong id);
|
||||
|
||||
/* And one ril_radio_caps object per modem */
|
||||
struct ril_radio_caps *ril_radio_caps_new(struct ril_radio_caps_manager *mgr,
|
||||
const char *log_prefix, GRilIoChannel *io,
|
||||
struct ril_data *data, struct ril_radio *radio,
|
||||
struct ril_sim_card *sim, struct ril_network *net,
|
||||
const struct ril_slot_config *config,
|
||||
const struct ril_radio_capability *cap);
|
||||
struct ril_radio_caps *ril_radio_caps_ref(struct ril_radio_caps *caps);
|
||||
void ril_radio_caps_unref(struct ril_radio_caps *caps);
|
||||
|
||||
#endif /* RIL_RADIO_CAPS_H */
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2016 Jolla Ltd.
|
||||
* Copyright (C) 2015-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
|
||||
@@ -17,7 +17,6 @@
|
||||
#include "ril_sim_settings.h"
|
||||
#include "ril_util.h"
|
||||
#include "ril_log.h"
|
||||
#include "ril_constants.h"
|
||||
|
||||
struct ril_radio_settings {
|
||||
struct ofono_radio_settings *rs;
|
||||
@@ -113,15 +112,11 @@ static gboolean ril_radio_settings_query_available_rats_cb(gpointer data)
|
||||
struct ofono_error error;
|
||||
struct ril_radio_settings_cbd *cbd = data;
|
||||
struct ril_radio_settings *rsd = cbd->rsd;
|
||||
guint rats = OFONO_RADIO_ACCESS_MODE_GSM | OFONO_RADIO_ACCESS_MODE_UMTS;
|
||||
|
||||
if (cbd->rsd->settings->enable_4g) {
|
||||
rats |= OFONO_RADIO_ACCESS_MODE_LTE;
|
||||
}
|
||||
|
||||
GASSERT(cbd->rsd->source_id);
|
||||
GASSERT(rsd->source_id);
|
||||
rsd->source_id = 0;
|
||||
cbd->cb.available_rats(ril_error_ok(&error), rats, cbd->data);
|
||||
cbd->cb.available_rats(ril_error_ok(&error), rsd->settings->techs,
|
||||
cbd->data);
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
@@ -132,8 +127,8 @@ static void ril_radio_settings_query_available_rats(
|
||||
struct ril_radio_settings *rsd = ril_radio_settings_get_data(rs);
|
||||
|
||||
DBG_(rsd, "");
|
||||
ril_radio_settings_later(rsd, ril_radio_settings_query_available_rats_cb,
|
||||
cb, data);
|
||||
ril_radio_settings_later(rsd,
|
||||
ril_radio_settings_query_available_rats_cb, cb, data);
|
||||
}
|
||||
|
||||
static gboolean ril_radio_settings_register(gpointer user_data)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2016 Jolla Ltd.
|
||||
* Copyright (C) 2015-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
|
||||
@@ -40,13 +40,6 @@
|
||||
/* FID/path of SIM/USIM root directory */
|
||||
#define ROOTMF "3F00"
|
||||
|
||||
/* RIL_Request* parameter counts */
|
||||
#define GET_IMSI_NUM_PARAMS 1
|
||||
#define ENTER_SIM_PIN_PARAMS 2
|
||||
#define SET_FACILITY_LOCK_PARAMS 5
|
||||
#define ENTER_SIM_PUK_PARAMS 3
|
||||
#define CHANGE_SIM_PIN_PARAMS 3
|
||||
|
||||
/* P2 coding (modes) for READ RECORD and UPDATE RECORD (see TS 102.221) */
|
||||
#define MODE_SELECTED (0x00) /* Currently selected EF */
|
||||
#define MODE_CURRENT (0x04) /* P1='00' denotes the current record */
|
||||
@@ -65,6 +58,13 @@
|
||||
*
|
||||
* The same applies to the app_type.
|
||||
*/
|
||||
|
||||
enum ril_sim_card_event {
|
||||
SIM_CARD_STATUS_EVENT,
|
||||
SIM_CARD_APP_EVENT,
|
||||
SIM_CARD_EVENT_COUNT
|
||||
};
|
||||
|
||||
struct ril_sim {
|
||||
GRilIoChannel *io;
|
||||
GRilIoQueue *q;
|
||||
@@ -76,7 +76,8 @@ struct ril_sim {
|
||||
gboolean empty_pin_query_allowed;
|
||||
gboolean inserted;
|
||||
guint idle_id;
|
||||
gulong card_status_id;
|
||||
gulong card_event_id[SIM_CARD_EVENT_COUNT];
|
||||
guint query_pin_retries_id;
|
||||
|
||||
const char *log_prefix;
|
||||
char *allocated_log_prefix;
|
||||
@@ -85,6 +86,7 @@ struct ril_sim {
|
||||
ofono_sim_passwd_cb_t query_passwd_state_cb;
|
||||
void *query_passwd_state_cb_data;
|
||||
guint query_passwd_state_timeout_id;
|
||||
gulong query_passwd_state_sim_status_refresh_id;
|
||||
};
|
||||
|
||||
struct ril_sim_io_response {
|
||||
@@ -100,11 +102,11 @@ struct ril_sim_cbd {
|
||||
ofono_sim_read_cb_t read;
|
||||
ofono_sim_write_cb_t write;
|
||||
ofono_sim_imsi_cb_t imsi;
|
||||
ofono_sim_pin_retries_cb_t retries;
|
||||
ofono_query_facility_lock_cb_t query_facility_lock;
|
||||
gpointer ptr;
|
||||
} cb;
|
||||
gpointer data;
|
||||
guint req_id;
|
||||
};
|
||||
|
||||
struct ril_sim_pin_cbd {
|
||||
@@ -119,6 +121,49 @@ struct ril_sim_pin_cbd {
|
||||
gulong card_status_id;
|
||||
};
|
||||
|
||||
struct ril_sim_retry_query_cbd {
|
||||
struct ril_sim *sd;
|
||||
ofono_sim_pin_retries_cb_t cb;
|
||||
void *data;
|
||||
guint query_index;
|
||||
};
|
||||
|
||||
struct ril_sim_retry_query {
|
||||
const char *name;
|
||||
enum ofono_sim_password_type passwd_type;
|
||||
guint req_code;
|
||||
GRilIoRequest *(*new_req)(struct ril_sim *sd);
|
||||
};
|
||||
|
||||
static GRilIoRequest *ril_sim_empty_sim_pin_req(struct ril_sim *sd);
|
||||
static GRilIoRequest *ril_sim_empty_sim_puk_req(struct ril_sim *sd);
|
||||
static void ril_sim_query_retry_count_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data);
|
||||
|
||||
static const struct ril_sim_retry_query ril_sim_retry_query_types[] = {
|
||||
{
|
||||
"pin",
|
||||
OFONO_SIM_PASSWORD_SIM_PIN,
|
||||
RIL_REQUEST_ENTER_SIM_PIN,
|
||||
ril_sim_empty_sim_pin_req
|
||||
},{
|
||||
"pin2",
|
||||
OFONO_SIM_PASSWORD_SIM_PIN2,
|
||||
RIL_REQUEST_ENTER_SIM_PIN2,
|
||||
ril_sim_empty_sim_pin_req
|
||||
},{
|
||||
"puk",
|
||||
OFONO_SIM_PASSWORD_SIM_PUK,
|
||||
RIL_REQUEST_ENTER_SIM_PUK,
|
||||
ril_sim_empty_sim_puk_req
|
||||
},{
|
||||
"puk2",
|
||||
OFONO_SIM_PASSWORD_SIM_PUK2,
|
||||
RIL_REQUEST_ENTER_SIM_PUK2,
|
||||
ril_sim_empty_sim_puk_req
|
||||
}
|
||||
};
|
||||
|
||||
#define DBG_(sd,fmt,args...) DBG("%s" fmt, (sd)->log_prefix, ##args)
|
||||
|
||||
#define ril_sim_cbd_free g_free
|
||||
@@ -378,6 +423,7 @@ static void ril_sim_file_info_cb(GRilIoChannel *io, int status,
|
||||
struct ofono_error error;
|
||||
|
||||
DBG_(sd, "");
|
||||
ril_sim_card_sim_io_finished(sd->card, cbd->req_id);
|
||||
|
||||
ril_error_init_failure(&error);
|
||||
res = ril_sim_parse_io_response(data, len);
|
||||
@@ -438,8 +484,10 @@ static void ril_sim_request_io(struct ril_sim *sd, guint cmd, int fileid,
|
||||
grilio_request_append_utf8(req, NULL); /* pin2; only for writes */
|
||||
grilio_request_append_utf8(req, ril_sim_app_id(sd));
|
||||
|
||||
grilio_queue_send_request_full(sd->q, req, RIL_REQUEST_SIM_IO,
|
||||
cb, ril_sim_cbd_free, cbd);
|
||||
grilio_request_set_blocking(req, TRUE);
|
||||
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);
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
@@ -461,6 +509,8 @@ static void ril_sim_read_cb(GRilIoChannel *io, int status,
|
||||
struct ofono_error err;
|
||||
|
||||
DBG_(cbd->sd, "");
|
||||
ril_sim_card_sim_io_finished(cbd->sd->card, cbd->req_id);
|
||||
|
||||
res = ril_sim_parse_io_response(data, len);
|
||||
if (ril_sim_io_response_ok(res) && status == RIL_E_SUCCESS) {
|
||||
cb(ril_error_ok(&err), res->data, res->data_len, cbd->data);
|
||||
@@ -514,6 +564,8 @@ static void ril_sim_write_cb(GRilIoChannel *io, int status,
|
||||
struct ofono_error err;
|
||||
|
||||
DBG_(cbd->sd, "");
|
||||
ril_sim_card_sim_io_finished(cbd->sd->card, cbd->req_id);
|
||||
|
||||
res = ril_sim_parse_io_response(data, len);
|
||||
if (ril_sim_io_response_ok(res) && status == RIL_E_SUCCESS) {
|
||||
cb(ril_error_ok(&err), cbd->data);
|
||||
@@ -574,6 +626,8 @@ static void ril_sim_get_imsi_cb(GRilIoChannel *io, int status,
|
||||
ofono_sim_imsi_cb_t cb = cbd->cb.imsi;
|
||||
struct ofono_error error;
|
||||
|
||||
ril_sim_card_sim_io_finished(cbd->sd->card, cbd->req_id);
|
||||
|
||||
if (status == RIL_E_SUCCESS) {
|
||||
gchar *imsi;
|
||||
GRilIoParser rilp;
|
||||
@@ -598,11 +652,11 @@ static void ril_sim_read_imsi(struct ofono_sim *sim, ofono_sim_imsi_cb_t cb,
|
||||
void *data)
|
||||
{
|
||||
struct ril_sim *sd = ril_sim_get_data(sim);
|
||||
GRilIoRequest *req = grilio_request_sized_new(60);
|
||||
const char *app_id = ril_sim_app_id(sd);
|
||||
struct ril_sim_cbd *cbd = ril_sim_cbd_new(sd, cb, data);
|
||||
GRilIoRequest *req = grilio_request_array_utf8_new(1, app_id);
|
||||
|
||||
DBG_(sd, "%s", ril_sim_app_id(sd));
|
||||
grilio_request_append_int32(req, GET_IMSI_NUM_PARAMS);
|
||||
grilio_request_append_utf8(req, ril_sim_app_id(sd));
|
||||
DBG_(sd, "%s", app_id);
|
||||
|
||||
/*
|
||||
* If we fail the .read_imsi call, ofono gets into "Unable to
|
||||
@@ -610,9 +664,11 @@ static void ril_sim_read_imsi(struct ofono_sim *sim, ofono_sim_imsi_cb_t cb,
|
||||
* on failure.
|
||||
*/
|
||||
grilio_request_set_retry(req, RIL_RETRY_MS, -1);
|
||||
grilio_queue_send_request_full(sd->q, req, RIL_REQUEST_GET_IMSI,
|
||||
ril_sim_get_imsi_cb, ril_sim_cbd_free,
|
||||
ril_sim_cbd_new(sd, cb, data));
|
||||
grilio_request_set_blocking(req, TRUE);
|
||||
cbd->req_id = grilio_queue_send_request_full(sd->q, req,
|
||||
RIL_REQUEST_GET_IMSI, ril_sim_get_imsi_cb,
|
||||
ril_sim_cbd_free, cbd);
|
||||
ril_sim_card_sim_io_started(sd->card, cbd->req_id);
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
@@ -691,6 +747,12 @@ static void ril_sim_finish_passwd_state_query(struct ril_sim *sd,
|
||||
sd->query_passwd_state_timeout_id = 0;
|
||||
}
|
||||
|
||||
if (sd->query_passwd_state_sim_status_refresh_id) {
|
||||
ril_sim_card_remove_handler(sd->card,
|
||||
sd->query_passwd_state_sim_status_refresh_id);
|
||||
sd->query_passwd_state_sim_status_refresh_id = 0;
|
||||
}
|
||||
|
||||
if (sd->query_passwd_state_cb) {
|
||||
ofono_sim_passwd_cb_t cb = sd->query_passwd_state_cb;
|
||||
void *data = sd->query_passwd_state_cb_data;
|
||||
@@ -709,6 +771,34 @@ static void ril_sim_finish_passwd_state_query(struct ril_sim *sd,
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_sim_check_perm_lock(struct ril_sim *sd)
|
||||
{
|
||||
struct ril_sim_card *sc = sd->card;
|
||||
|
||||
/*
|
||||
* Zero number of retries in the PUK state indicates to the ofono
|
||||
* client that the card is permanently locked. This is different
|
||||
* from the case when the number of retries is negative (which
|
||||
* means that PUK is required but the number of remaining attempts
|
||||
* is not available).
|
||||
*/
|
||||
if (sc->app && sc->app->app_state == RIL_APPSTATE_PUK &&
|
||||
sc->app->pin1_state == RIL_PINSTATE_ENABLED_PERM_BLOCKED) {
|
||||
|
||||
/*
|
||||
* It makes no sense for RIL to return non-zero number of
|
||||
* remaining attempts in PERM_LOCKED state. So when we get
|
||||
* here, the number of retries has to be negative (unknown)
|
||||
* or zero. Otherwise, something must be broken.
|
||||
*/
|
||||
GASSERT(sd->retries[OFONO_SIM_PASSWORD_SIM_PUK] <= 0);
|
||||
if (sd->retries[OFONO_SIM_PASSWORD_SIM_PUK] < 0) {
|
||||
sd->retries[OFONO_SIM_PASSWORD_SIM_PUK] = 0;
|
||||
DBG_(sd, "SIM card is locked");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_sim_invalidate_passwd_state(struct ril_sim *sd)
|
||||
{
|
||||
guint i;
|
||||
@@ -718,10 +808,16 @@ static void ril_sim_invalidate_passwd_state(struct ril_sim *sd)
|
||||
sd->retries[i] = -1;
|
||||
}
|
||||
|
||||
ril_sim_check_perm_lock(sd);
|
||||
ril_sim_finish_passwd_state_query(sd, OFONO_SIM_PASSWORD_INVALID);
|
||||
}
|
||||
|
||||
static void ril_sim_status_cb(struct ril_sim_card *sc, void *user_data)
|
||||
static void ril_sim_app_changed_cb(struct ril_sim_card *sc, void *user_data)
|
||||
{
|
||||
ril_sim_check_perm_lock((struct ril_sim *)user_data);
|
||||
}
|
||||
|
||||
static void ril_sim_status_changed_cb(struct ril_sim_card *sc, void *user_data)
|
||||
{
|
||||
struct ril_sim *sd = user_data;
|
||||
|
||||
@@ -730,6 +826,7 @@ static void ril_sim_status_cb(struct ril_sim_card *sc, void *user_data)
|
||||
if (sc->app) {
|
||||
enum ofono_sim_password_type ps;
|
||||
|
||||
ril_sim_check_perm_lock(sd);
|
||||
if (!sd->inserted) {
|
||||
sd->inserted = TRUE;
|
||||
ofono_info("SIM card OK");
|
||||
@@ -764,14 +861,28 @@ static int ril_sim_parse_retry_count(const void *data, guint len)
|
||||
return retry_count;
|
||||
}
|
||||
|
||||
static GRilIoRequest *ril_sim_enter_sim_req(struct ril_sim *sd, const char *pw)
|
||||
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) {
|
||||
GRilIoRequest *req = grilio_request_new();
|
||||
grilio_request_append_int32(req, ENTER_SIM_PIN_PARAMS);
|
||||
grilio_request_append_utf8(req, pw);
|
||||
grilio_request_append_utf8(req, app_id);
|
||||
GRilIoRequest *req = grilio_request_array_utf8_new(2,
|
||||
pin, app_id);
|
||||
|
||||
grilio_request_set_blocking(req, TRUE);
|
||||
return req;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static GRilIoRequest *ril_sim_enter_sim_puk_req(struct ril_sim *sd,
|
||||
const char *puk, const char *pin)
|
||||
{
|
||||
const char *app_id = ril_sim_app_id(sd);
|
||||
if (app_id) {
|
||||
GRilIoRequest *req = grilio_request_array_utf8_new(3,
|
||||
puk, pin, app_id);
|
||||
grilio_request_set_blocking(req, TRUE);
|
||||
return req;
|
||||
}
|
||||
return NULL;
|
||||
@@ -781,63 +892,90 @@ static GRilIoRequest *ril_sim_enter_sim_req(struct ril_sim *sd, const char *pw)
|
||||
* Some RIL implementations allow to query the retry count
|
||||
* by sending the empty pin in any state.
|
||||
*/
|
||||
static void ril_sim_query_pin2_retries_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
|
||||
static GRilIoRequest *ril_sim_empty_sim_pin_req(struct ril_sim *sd)
|
||||
{
|
||||
struct ril_sim_cbd *cbd = user_data;
|
||||
struct ril_sim *sd = cbd->sd;
|
||||
ofono_sim_pin_retries_cb_t cb = cbd->cb.retries;
|
||||
struct ofono_error error;
|
||||
|
||||
if (status == RIL_E_SUCCESS) {
|
||||
const int retry_count = ril_sim_parse_retry_count(data, len);
|
||||
DBG_(sd, "pin2 retry_count=%d", retry_count);
|
||||
sd->retries[OFONO_SIM_PASSWORD_SIM_PIN2] = retry_count;
|
||||
} else {
|
||||
ofono_error("pin2 retry query is not supported");
|
||||
sd->empty_pin_query_allowed = FALSE;
|
||||
}
|
||||
|
||||
cb(ril_error_ok(&error), sd->retries, cbd->data);
|
||||
return ril_sim_enter_sim_pin_req(sd, "");
|
||||
}
|
||||
|
||||
static gboolean ril_sim_query_pin2_retry_count(struct ril_sim *sd,
|
||||
static GRilIoRequest *ril_sim_empty_sim_puk_req(struct ril_sim *sd)
|
||||
{
|
||||
return ril_sim_enter_sim_puk_req(sd, "", "");
|
||||
}
|
||||
|
||||
static struct ril_sim_retry_query_cbd *ril_sim_retry_query_cbd_new(
|
||||
struct ril_sim *sd, guint query_index,
|
||||
ofono_sim_pin_retries_cb_t cb, void *data)
|
||||
{
|
||||
if (sd->empty_pin_query_allowed &&
|
||||
sd->retries[OFONO_SIM_PASSWORD_SIM_PIN2] < 0) {
|
||||
GRilIoRequest *req = ril_sim_enter_sim_req(sd, "");
|
||||
if (req) {
|
||||
DBG_(sd, "querying pin2 retry count...");
|
||||
grilio_queue_send_request_full(sd->q, req,
|
||||
RIL_REQUEST_ENTER_SIM_PIN2,
|
||||
ril_sim_query_pin2_retries_cb,
|
||||
ril_sim_cbd_free,
|
||||
ril_sim_cbd_new(sd, cb, data));
|
||||
grilio_request_unref(req);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
struct ril_sim_retry_query_cbd *cbd =
|
||||
g_new(struct ril_sim_retry_query_cbd, 1);
|
||||
|
||||
cbd->sd = sd;
|
||||
cbd->cb = cb;
|
||||
cbd->data = data;
|
||||
cbd->query_index = query_index;
|
||||
return cbd;
|
||||
}
|
||||
|
||||
static void ril_sim_query_pin_retries_cb(GRilIoChannel *io, int status,
|
||||
static gboolean ril_sim_query_retry_count(struct ril_sim *sd,
|
||||
guint start_index, ofono_sim_pin_retries_cb_t cb, void *data)
|
||||
{
|
||||
guint id = 0;
|
||||
|
||||
if (sd->empty_pin_query_allowed) {
|
||||
guint i = start_index;
|
||||
|
||||
/* Find the first unknown retry count that we can query. */
|
||||
while (i < G_N_ELEMENTS(ril_sim_retry_query_types)) {
|
||||
const struct ril_sim_retry_query *query =
|
||||
ril_sim_retry_query_types + i;
|
||||
|
||||
if (sd->retries[query->passwd_type] < 0) {
|
||||
GRilIoRequest *req = query->new_req(sd);
|
||||
|
||||
if (req) {
|
||||
DBG_(sd, "querying %s retry count...",
|
||||
query->name);
|
||||
id = grilio_queue_send_request_full(
|
||||
sd->q, req, query->req_code,
|
||||
ril_sim_query_retry_count_cb,
|
||||
g_free,
|
||||
ril_sim_retry_query_cbd_new(
|
||||
sd, i, cb, data));
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
static void ril_sim_query_retry_count_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_sim_cbd *cbd = user_data;
|
||||
struct ril_sim_retry_query_cbd *cbd = user_data;
|
||||
struct ril_sim *sd = cbd->sd;
|
||||
ofono_sim_pin_retries_cb_t cb = cbd->cb.retries;
|
||||
struct ofono_error error;
|
||||
|
||||
GASSERT(sd->query_pin_retries_id);
|
||||
sd->query_pin_retries_id = 0;
|
||||
|
||||
if (status == RIL_E_SUCCESS) {
|
||||
const int retry_count = ril_sim_parse_retry_count(data, len);
|
||||
DBG_(sd, "pin retry_count=%d", retry_count);
|
||||
sd->retries[OFONO_SIM_PASSWORD_SIM_PIN] = retry_count;
|
||||
if (ril_sim_query_pin2_retry_count(sd, cb, cbd->data)) {
|
||||
/*
|
||||
* ril_sim_query_pin2_retries_cb will invoke
|
||||
* the completion callback
|
||||
*/
|
||||
const struct ril_sim_retry_query *query =
|
||||
ril_sim_retry_query_types + cbd->query_index;
|
||||
|
||||
DBG_(sd, "%s retry_count=%d", query->name, retry_count);
|
||||
sd->retries[query->passwd_type] = retry_count;
|
||||
|
||||
/* Submit the next request */
|
||||
if ((sd->query_pin_retries_id =
|
||||
ril_sim_query_retry_count(sd, cbd->query_index + 1,
|
||||
cbd->cb, cbd->data)) != 0) {
|
||||
/* The next request is pending */
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
@@ -845,43 +983,32 @@ static void ril_sim_query_pin_retries_cb(GRilIoChannel *io, int status,
|
||||
sd->empty_pin_query_allowed = FALSE;
|
||||
}
|
||||
|
||||
cb(ril_error_ok(&error), sd->retries, cbd->data);
|
||||
}
|
||||
|
||||
static gboolean ril_sim_query_pin_retry_count(struct ril_sim *sd,
|
||||
ofono_sim_pin_retries_cb_t cb, void *data)
|
||||
{
|
||||
if (sd->empty_pin_query_allowed &&
|
||||
sd->retries[OFONO_SIM_PASSWORD_SIM_PIN] < 0) {
|
||||
GRilIoRequest *req = ril_sim_enter_sim_req(sd, "");
|
||||
if (req) {
|
||||
DBG_(sd, "querying pin retry count...");
|
||||
grilio_queue_send_request_full(sd->q, req,
|
||||
RIL_REQUEST_ENTER_SIM_PIN,
|
||||
ril_sim_query_pin_retries_cb,
|
||||
ril_sim_cbd_free,
|
||||
ril_sim_cbd_new(sd, cb, data));
|
||||
grilio_request_unref(req);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
cbd->cb(ril_error_ok(&error), sd->retries, cbd->data);
|
||||
}
|
||||
|
||||
static void ril_sim_query_pin_retries(struct ofono_sim *sim,
|
||||
ofono_sim_pin_retries_cb_t cb, void *data)
|
||||
{
|
||||
struct ofono_error error;
|
||||
struct ril_sim *sd = ril_sim_get_data(sim);
|
||||
|
||||
DBG_(sd, "");
|
||||
if (ril_sim_query_pin_retry_count(sd, cb, data) ||
|
||||
ril_sim_query_pin2_retry_count(sd, cb, data)) {
|
||||
/* Wait for completion of PIN and then PIN2 query */
|
||||
return;
|
||||
}
|
||||
grilio_queue_cancel_request(sd->q, sd->query_pin_retries_id, FALSE);
|
||||
sd->query_pin_retries_id = ril_sim_query_retry_count(sd, 0, cb, data);
|
||||
if (!sd->query_pin_retries_id) {
|
||||
struct ofono_error error;
|
||||
|
||||
cb(ril_error_ok(&error), sd->retries, data);
|
||||
/* Nothing to wait for */
|
||||
cb(ril_error_ok(&error), sd->retries, data);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_sim_query_passwd_state_complete_cb(struct ril_sim_card *sc,
|
||||
void *user_data)
|
||||
{
|
||||
struct ril_sim *sd = user_data;
|
||||
|
||||
GASSERT(sd->query_passwd_state_sim_status_refresh_id);
|
||||
ril_sim_finish_passwd_state_query(sd, ril_sim_passwd_state(sd));
|
||||
}
|
||||
|
||||
static gboolean ril_sim_query_passwd_state_timeout_cb(gpointer user_data)
|
||||
@@ -899,29 +1026,41 @@ static void ril_sim_query_passwd_state(struct ofono_sim *sim,
|
||||
ofono_sim_passwd_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_sim *sd = ril_sim_get_data(sim);
|
||||
enum ofono_sim_password_type passwd_state = ril_sim_passwd_state(sd);
|
||||
struct ofono_error error;
|
||||
|
||||
if (sd->query_passwd_state_timeout_id) {
|
||||
g_source_remove(sd->query_passwd_state_timeout_id);
|
||||
sd->query_passwd_state_timeout_id = 0;
|
||||
}
|
||||
|
||||
if (passwd_state != OFONO_SIM_PASSWORD_INVALID) {
|
||||
DBG_(sd, "%d", passwd_state);
|
||||
sd->query_passwd_state_cb = NULL;
|
||||
sd->query_passwd_state_cb_data = NULL;
|
||||
sd->ofono_passwd_state = passwd_state;
|
||||
cb(ril_error_ok(&error), passwd_state, data);
|
||||
if (!sd->query_passwd_state_sim_status_refresh_id) {
|
||||
ril_sim_card_remove_handler(sd->card,
|
||||
sd->query_passwd_state_sim_status_refresh_id);
|
||||
sd->query_passwd_state_sim_status_refresh_id = 0;
|
||||
}
|
||||
|
||||
/* Always request fresh status, just in case. */
|
||||
ril_sim_card_request_status(sd->card);
|
||||
sd->query_passwd_state_cb = cb;
|
||||
sd->query_passwd_state_cb_data = data;
|
||||
|
||||
if (ril_sim_passwd_state(sd) != OFONO_SIM_PASSWORD_INVALID) {
|
||||
/* Just wait for GET_SIM_STATUS completion */
|
||||
DBG_(sd, "waiting for SIM status query to complete");
|
||||
sd->query_passwd_state_sim_status_refresh_id =
|
||||
ril_sim_card_add_status_received_handler(sd->card,
|
||||
ril_sim_query_passwd_state_complete_cb, sd);
|
||||
} else {
|
||||
/* Wait for the state to change */
|
||||
DBG_(sd, "waiting for the SIM state to change");
|
||||
sd->query_passwd_state_cb = cb;
|
||||
sd->query_passwd_state_cb_data = data;
|
||||
sd->query_passwd_state_timeout_id =
|
||||
g_timeout_add_seconds(SIM_STATE_CHANGE_TIMEOUT_SECS,
|
||||
ril_sim_query_passwd_state_timeout_cb, sd);
|
||||
}
|
||||
|
||||
/*
|
||||
* We still need to complete the request somehow, even if
|
||||
* GET_STATUS never completes or SIM status never changes.
|
||||
*/
|
||||
sd->query_passwd_state_timeout_id =
|
||||
g_timeout_add_seconds(SIM_STATE_CHANGE_TIMEOUT_SECS,
|
||||
ril_sim_query_passwd_state_timeout_cb, sd);
|
||||
}
|
||||
|
||||
static gboolean ril_sim_pin_change_state_timeout_cb(gpointer user_data)
|
||||
@@ -971,20 +1110,30 @@ static void ril_sim_pin_change_state_cb(GRilIoChannel *io, int ril_status,
|
||||
struct ril_sim_pin_cbd *cbd = user_data;
|
||||
struct ril_sim *sd = cbd->sd;
|
||||
const int retry_count = ril_sim_parse_retry_count(data, len);
|
||||
enum ofono_sim_password_type type = cbd->passwd_type;
|
||||
|
||||
DBG_(sd, "result=%d passwd_type=%d retry_count=%d",
|
||||
ril_status, cbd->passwd_type, retry_count);
|
||||
|
||||
if (ril_status == RIL_E_SUCCESS && retry_count == 0 &&
|
||||
sd->empty_pin_query_allowed &&
|
||||
(cbd->passwd_type == OFONO_SIM_PASSWORD_SIM_PIN ||
|
||||
cbd->passwd_type == OFONO_SIM_PASSWORD_SIM_PIN2)) {
|
||||
/* Will query it */
|
||||
sd->retries[cbd->passwd_type] = -1;
|
||||
if (ril_status == RIL_E_SUCCESS && retry_count == 0) {
|
||||
enum ofono_sim_password_type associated_pin =
|
||||
__ofono_sim_puk2pin(type);
|
||||
/*
|
||||
* If PIN/PUK request has succeeded, zero retry count
|
||||
* makes no sense, we have to assume that it's unknown.
|
||||
* If it can be queried, it will be queried later. If
|
||||
* it can't be queried it will remain unknown.
|
||||
*/
|
||||
sd->retries[type] = -1;
|
||||
if (associated_pin != OFONO_SIM_PASSWORD_INVALID) {
|
||||
/* Successful PUK requests affect PIN retry count */
|
||||
sd->retries[associated_pin] = -1;
|
||||
}
|
||||
} else {
|
||||
sd->retries[cbd->passwd_type] = retry_count;
|
||||
sd->retries[type] = retry_count;
|
||||
}
|
||||
|
||||
ril_sim_check_perm_lock(sd);
|
||||
cbd->ril_status = ril_status;
|
||||
if (cbd->card_status_id && (!cbd->state_event_count ||
|
||||
ril_sim_app_in_transient_state(sd))) {
|
||||
@@ -1014,6 +1163,13 @@ static void ril_sim_pin_change_state_cb(GRilIoChannel *io, int ril_status,
|
||||
} else {
|
||||
cbd->cb(ril_error_failure(&error), cbd->data);
|
||||
}
|
||||
|
||||
/* To avoid assert in ril_sim_pin_req_done: */
|
||||
if (cbd->card_status_id) {
|
||||
ril_sim_card_remove_handler(cbd->card,
|
||||
cbd->card_status_id);
|
||||
cbd->card_status_id = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1021,18 +1177,21 @@ static void ril_sim_pin_send(struct ofono_sim *sim, const char *passwd,
|
||||
ofono_sim_lock_unlock_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_sim *sd = ril_sim_get_data(sim);
|
||||
GRilIoRequest *req = grilio_request_new();
|
||||
GRilIoRequest *req = ril_sim_enter_sim_pin_req(sd, passwd);
|
||||
|
||||
grilio_request_append_int32(req, ENTER_SIM_PIN_PARAMS);
|
||||
grilio_request_append_utf8(req, passwd);
|
||||
grilio_request_append_utf8(req, ril_sim_app_id(sd));
|
||||
if (req) {
|
||||
DBG_(sd, "%s,aid=%s", passwd, ril_sim_app_id(sd));
|
||||
grilio_queue_send_request_full(sd->q, req,
|
||||
RIL_REQUEST_ENTER_SIM_PIN, ril_sim_pin_change_state_cb,
|
||||
ril_sim_pin_req_done, ril_sim_pin_cbd_new(sd,
|
||||
OFONO_SIM_PASSWORD_SIM_PIN, TRUE, cb, data));
|
||||
grilio_request_unref(req);
|
||||
} else {
|
||||
struct ofono_error error;
|
||||
|
||||
DBG_(sd, "%s,aid=%s", passwd, ril_sim_app_id(sd));
|
||||
grilio_queue_send_request_full(sd->q, req, RIL_REQUEST_ENTER_SIM_PIN,
|
||||
ril_sim_pin_change_state_cb, ril_sim_pin_req_done,
|
||||
ril_sim_pin_cbd_new(sd, OFONO_SIM_PASSWORD_SIM_PIN,
|
||||
TRUE, cb, data));
|
||||
grilio_request_unref(req);
|
||||
DBG_(sd, "sorry");
|
||||
cb(ril_error_failure(&error), data);
|
||||
}
|
||||
}
|
||||
|
||||
static guint ril_perso_change_state(struct ofono_sim *sim,
|
||||
@@ -1100,26 +1259,23 @@ static void ril_sim_pin_change_state(struct ofono_sim *sim,
|
||||
const char *passwd, ofono_sim_lock_unlock_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_sim *sd = ril_sim_get_data(sim);
|
||||
struct ofono_error error;
|
||||
const char *app_id = ril_sim_app_id(sd);
|
||||
const char *type_str = ril_sim_facility_code(passwd_type);
|
||||
struct ofono_error error;
|
||||
guint id = 0;
|
||||
|
||||
DBG_(sd, "%d,%s,%d,%s,0,aid=%s", passwd_type, type_str, enable, passwd,
|
||||
ril_sim_app_id(sd));
|
||||
DBG_(sd, "%d,%s,%d,%s,0,aid=%s", passwd_type, type_str,
|
||||
enable, passwd, app_id);
|
||||
|
||||
if (passwd_type == OFONO_SIM_PASSWORD_PHNET_PIN) {
|
||||
id = ril_perso_change_state(sim, passwd_type, enable, passwd,
|
||||
cb, data);
|
||||
} else if (type_str) {
|
||||
GRilIoRequest *req = grilio_request_new();
|
||||
grilio_request_append_int32(req, SET_FACILITY_LOCK_PARAMS);
|
||||
grilio_request_append_utf8(req, type_str);
|
||||
grilio_request_append_utf8(req, enable ?
|
||||
RIL_FACILITY_LOCK : RIL_FACILITY_UNLOCK);
|
||||
grilio_request_append_utf8(req, passwd);
|
||||
grilio_request_append_utf8(req, "0"); /* class */
|
||||
grilio_request_append_utf8(req, ril_sim_app_id(sd));
|
||||
GRilIoRequest *req = grilio_request_array_utf8_new(5, type_str,
|
||||
enable ? RIL_FACILITY_LOCK : RIL_FACILITY_UNLOCK,
|
||||
passwd, "0" /* class */, app_id);
|
||||
|
||||
grilio_request_set_blocking(req, TRUE);
|
||||
id = grilio_queue_send_request_full(sd->q, req,
|
||||
RIL_REQUEST_SET_FACILITY_LOCK,
|
||||
ril_sim_pin_change_state_cb, ril_sim_pin_req_done,
|
||||
@@ -1137,19 +1293,22 @@ static void ril_sim_pin_send_puk(struct ofono_sim *sim,
|
||||
ofono_sim_lock_unlock_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_sim *sd = ril_sim_get_data(sim);
|
||||
GRilIoRequest *req = grilio_request_sized_new(60);
|
||||
GRilIoRequest *req = ril_sim_enter_sim_puk_req(sd, puk, passwd);
|
||||
|
||||
grilio_request_append_int32(req, ENTER_SIM_PUK_PARAMS);
|
||||
grilio_request_append_utf8(req, puk);
|
||||
grilio_request_append_utf8(req, passwd);
|
||||
grilio_request_append_utf8(req, ril_sim_app_id(sd));
|
||||
if (req) {
|
||||
DBG_(sd, "puk=%s,pin=%s,aid=%s", puk, passwd,
|
||||
ril_sim_app_id(sd));
|
||||
grilio_queue_send_request_full(sd->q, req,
|
||||
RIL_REQUEST_ENTER_SIM_PUK, ril_sim_pin_change_state_cb,
|
||||
ril_sim_pin_req_done, ril_sim_pin_cbd_new(sd,
|
||||
OFONO_SIM_PASSWORD_SIM_PUK, TRUE, cb, data));
|
||||
grilio_request_unref(req);
|
||||
} else {
|
||||
struct ofono_error error;
|
||||
|
||||
DBG_(sd, "puk=%s,pin=%s,aid=%s", puk, passwd, ril_sim_app_id(sd));
|
||||
grilio_queue_send_request_full(sd->q, req, RIL_REQUEST_ENTER_SIM_PUK,
|
||||
ril_sim_pin_change_state_cb, ril_sim_pin_req_done,
|
||||
ril_sim_pin_cbd_new(sd, OFONO_SIM_PASSWORD_SIM_PUK,
|
||||
TRUE, cb, data));
|
||||
grilio_request_unref(req);
|
||||
DBG_(sd, "sorry");
|
||||
cb(ril_error_failure(&error), data);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_sim_change_passwd(struct ofono_sim *sim,
|
||||
@@ -1158,15 +1317,12 @@ static void ril_sim_change_passwd(struct ofono_sim *sim,
|
||||
ofono_sim_lock_unlock_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_sim *sd = ril_sim_get_data(sim);
|
||||
GRilIoRequest *req = grilio_request_sized_new(60);
|
||||
const char *app_id = ril_sim_app_id(sd);
|
||||
GRilIoRequest *req = grilio_request_array_utf8_new(3,
|
||||
old_passwd, new_passwd, app_id);
|
||||
|
||||
grilio_request_append_int32(req, CHANGE_SIM_PIN_PARAMS);
|
||||
grilio_request_append_utf8(req, old_passwd);
|
||||
grilio_request_append_utf8(req, new_passwd);
|
||||
grilio_request_append_utf8(req, ril_sim_app_id(sd));
|
||||
|
||||
DBG_(sd, "old=%s,new=%s,aid=%s", old_passwd, new_passwd,
|
||||
ril_sim_app_id(sd));
|
||||
DBG_(sd, "old=%s,new=%s,aid=%s", old_passwd, new_passwd, app_id);
|
||||
grilio_request_set_blocking(req, TRUE);
|
||||
grilio_queue_send_request_full(sd->q, req,
|
||||
(passwd_type == OFONO_SIM_PASSWORD_SIM_PIN2) ?
|
||||
RIL_REQUEST_CHANGE_SIM_PIN2 : RIL_REQUEST_CHANGE_SIM_PIN,
|
||||
@@ -1182,6 +1338,8 @@ static void ril_sim_query_facility_lock_cb(GRilIoChannel *io, int status,
|
||||
struct ril_sim_cbd *cbd = user_data;
|
||||
ofono_query_facility_lock_cb_t cb = cbd->cb.query_facility_lock;
|
||||
|
||||
ril_sim_card_sim_io_finished(cbd->sd->card, cbd->req_id);
|
||||
|
||||
if (status == RIL_E_SUCCESS) {
|
||||
int locked = 0;
|
||||
GRilIoParser rilp;
|
||||
@@ -1203,18 +1361,16 @@ static void ril_sim_query_facility_lock(struct ofono_sim *sim,
|
||||
ofono_query_facility_lock_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_sim *sd = ril_sim_get_data(sim);
|
||||
GRilIoRequest *req = grilio_request_new();
|
||||
const char *type_str = ril_sim_facility_code(type);
|
||||
struct ril_sim_cbd *cbd = ril_sim_cbd_new(sd, cb, data);
|
||||
GRilIoRequest *req = grilio_request_array_utf8_new(4,
|
||||
type_str, "", "0" /* class */, ril_sim_app_id(sd));
|
||||
|
||||
DBG_(sd, "%s", type_str);
|
||||
grilio_request_append_int32(req, 4);
|
||||
grilio_request_append_utf8(req, type_str);
|
||||
grilio_request_append_utf8(req, "");
|
||||
grilio_request_append_utf8(req, "0"); /* class */
|
||||
grilio_request_append_utf8(req, ril_sim_app_id(sd));
|
||||
grilio_queue_send_request_full(sd->q, req,
|
||||
cbd->req_id = grilio_queue_send_request_full(sd->q, req,
|
||||
RIL_REQUEST_QUERY_FACILITY_LOCK, ril_sim_query_facility_lock_cb,
|
||||
ril_sim_cbd_free, ril_sim_cbd_new(sd, cb, data));
|
||||
ril_sim_cbd_free, cbd);
|
||||
ril_sim_card_sim_io_started(sd->card, cbd->req_id);
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
@@ -1229,11 +1385,15 @@ static gboolean ril_sim_register(gpointer user)
|
||||
ofono_sim_register(sd->sim);
|
||||
|
||||
/* Register for change notifications */
|
||||
sd->card_status_id = ril_sim_card_add_status_changed_handler(sd->card,
|
||||
ril_sim_status_cb, sd);
|
||||
sd->card_event_id[SIM_CARD_STATUS_EVENT] =
|
||||
ril_sim_card_add_status_changed_handler(sd->card,
|
||||
ril_sim_status_changed_cb, sd);
|
||||
sd->card_event_id[SIM_CARD_APP_EVENT] =
|
||||
ril_sim_card_add_app_changed_handler(sd->card,
|
||||
ril_sim_app_changed_cb, sd);
|
||||
|
||||
/* Check the current state */
|
||||
ril_sim_status_cb(sd->card, sd);
|
||||
ril_sim_status_changed_cb(sd->card, sd);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
@@ -1280,7 +1440,13 @@ static void ril_sim_remove(struct ofono_sim *sim)
|
||||
g_source_remove(sd->query_passwd_state_timeout_id);
|
||||
}
|
||||
|
||||
ril_sim_card_remove_handler(sd->card, sd->card_status_id);
|
||||
if (sd->query_passwd_state_sim_status_refresh_id) {
|
||||
ril_sim_card_remove_handler(sd->card,
|
||||
sd->query_passwd_state_sim_status_refresh_id);
|
||||
}
|
||||
|
||||
ril_sim_card_remove_handlers(sd->card, sd->card_event_id,
|
||||
G_N_ELEMENTS(sd->card_event_id));
|
||||
ril_sim_card_unref(sd->card);
|
||||
|
||||
grilio_channel_unref(sd->io);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2016 Jolla Ltd.
|
||||
* Copyright (C) 2015-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
|
||||
@@ -24,6 +24,15 @@
|
||||
|
||||
#include <gutil_misc.h>
|
||||
|
||||
#define UICC_SUBSCRIPTION_TIMEOUT_MS (30000)
|
||||
|
||||
/* SIM I/O idle timeout is measured in the number of idle loops.
|
||||
* When active SIM I/O is going on, the idle loop count very rarely
|
||||
* exceeds 1 between the requests, so 10 is more than enough. Idle
|
||||
* loop is actually more accurate criteria than a timeout because
|
||||
* it doesn't depend that much on the system load. */
|
||||
#define SIM_IO_IDLE_LOOPS (10)
|
||||
|
||||
typedef GObjectClass RilSimCardClass;
|
||||
typedef struct ril_sim_card RilSimCard;
|
||||
|
||||
@@ -38,7 +47,11 @@ struct ril_sim_card_priv {
|
||||
GRilIoQueue *q;
|
||||
int flags;
|
||||
guint status_req_id;
|
||||
guint sub_req_id;
|
||||
gulong event_id[EVENT_COUNT];
|
||||
guint sim_io_idle_id;
|
||||
guint sim_io_idle_count;
|
||||
GHashTable* sim_io_pending;
|
||||
};
|
||||
|
||||
enum ril_sim_card_signal {
|
||||
@@ -46,13 +59,15 @@ enum ril_sim_card_signal {
|
||||
SIGNAL_STATUS_CHANGED,
|
||||
SIGNAL_STATE_CHANGED,
|
||||
SIGNAL_APP_CHANGED,
|
||||
SIGNAL_SIM_IO_ACTIVE_CHANGED,
|
||||
SIGNAL_COUNT
|
||||
};
|
||||
|
||||
#define SIGNAL_STATUS_RECEIVED_NAME "ril-simcard-status-received"
|
||||
#define SIGNAL_STATUS_CHANGED_NAME "ril-simcard-status-changed"
|
||||
#define SIGNAL_STATE_CHANGED_NAME "ril-simcard-state-changed"
|
||||
#define SIGNAL_APP_CHANGED_NAME "ril-simcard-app-changed"
|
||||
#define SIGNAL_STATUS_RECEIVED_NAME "ril-simcard-status-received"
|
||||
#define SIGNAL_STATUS_CHANGED_NAME "ril-simcard-status-changed"
|
||||
#define SIGNAL_STATE_CHANGED_NAME "ril-simcard-state-changed"
|
||||
#define SIGNAL_APP_CHANGED_NAME "ril-simcard-app-changed"
|
||||
#define SIGNAL_SIM_IO_ACTIVE_CHANGED_NAME "ril-simcard-sim-io-active-changed"
|
||||
|
||||
static guint ril_sim_card_signals[SIGNAL_COUNT] = { 0 };
|
||||
|
||||
@@ -61,11 +76,16 @@ G_DEFINE_TYPE(RilSimCard, ril_sim_card, G_TYPE_OBJECT)
|
||||
#define RIL_SIMCARD(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), \
|
||||
RIL_SIMCARD_TYPE, RilSimCard))
|
||||
|
||||
#define NEW_SIGNAL(klass,name) NEW_SIGNAL_(klass,name##_CHANGED)
|
||||
#define NEW_SIGNAL_(klass,name) \
|
||||
ril_sim_card_signals[SIGNAL_##name] = \
|
||||
g_signal_new(SIGNAL_##name##_NAME, \
|
||||
G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_FIRST, \
|
||||
0, NULL, NULL, NULL, G_TYPE_NONE, 0)
|
||||
|
||||
#define RIL_SIMCARD_STATE_CHANGED (0x01)
|
||||
#define RIL_SIMCARD_STATUS_CHANGED (0x02)
|
||||
|
||||
static void ril_sim_card_request_status(struct ril_sim_card *self);
|
||||
|
||||
static gboolean ril_sim_card_app_equal(const struct ril_sim_card_app *a1,
|
||||
const struct ril_sim_card_app *a2)
|
||||
{
|
||||
@@ -137,22 +157,65 @@ static void ril_sim_card_status_free(struct ril_sim_card_status *status)
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_sim_card_subscribe(struct ril_sim_card *self,
|
||||
int app_index, int sub_status)
|
||||
static void ril_sim_card_subscription_done(struct ril_sim_card *self)
|
||||
{
|
||||
struct ril_sim_card_priv *priv = self->priv;
|
||||
|
||||
if (priv->sub_req_id) {
|
||||
/* Some RILs never reply to SET_UICC_SUBSCRIPTION requst,
|
||||
* so we better drop rather than cancel it (so that it gets
|
||||
* removed from the list of pending requests) */
|
||||
grilio_channel_drop_request(priv->io, priv->sub_req_id);
|
||||
priv->sub_req_id = 0;
|
||||
}
|
||||
grilio_queue_transaction_finish(priv->q);
|
||||
}
|
||||
|
||||
static void ril_sim_card_subscribe_cb(GRilIoChannel* io, int status,
|
||||
const void* data, guint len, void* user_data)
|
||||
{
|
||||
struct ril_sim_card *self = RIL_SIMCARD(user_data);
|
||||
struct ril_sim_card_priv *priv = self->priv;
|
||||
|
||||
GASSERT(status == GRILIO_STATUS_OK);
|
||||
GASSERT(priv->sub_req_id);
|
||||
priv->sub_req_id = 0;
|
||||
DBG("UICC subscription OK for slot %u", self->slot);
|
||||
ril_sim_card_subscription_done(self);
|
||||
}
|
||||
|
||||
static void ril_sim_card_subscribe(struct ril_sim_card *self, int app_index,
|
||||
enum ril_uicc_subscription_action sub_action)
|
||||
{
|
||||
struct ril_sim_card_priv *priv = self->priv;
|
||||
GRilIoRequest *req = grilio_request_sized_new(16);
|
||||
const guint sub_id = self->slot;
|
||||
guint code;
|
||||
|
||||
DBG("%u,%d,%u,%d", self->slot, app_index, sub_id, sub_status);
|
||||
DBG("%u,%d,%u,%d", self->slot, app_index, sub_id, sub_action);
|
||||
grilio_request_append_int32(req, self->slot);
|
||||
grilio_request_append_int32(req, app_index);
|
||||
grilio_request_append_int32(req, sub_id);
|
||||
grilio_request_append_int32(req, sub_status);
|
||||
grilio_queue_send_request(priv->q, req, (priv->io->ril_version <= 9 &&
|
||||
grilio_request_append_int32(req, sub_action);
|
||||
|
||||
grilio_request_set_retry(req, 0, -1);
|
||||
grilio_request_set_timeout(req, UICC_SUBSCRIPTION_TIMEOUT_MS);
|
||||
code = (priv->io->ril_version <= 9 &&
|
||||
(priv->flags & RIL_SIM_CARD_V9_UICC_SUBSCRIPTION_WORKAROUND)) ?
|
||||
RIL_REQUEST_V9_SET_UICC_SUBSCRIPTION :
|
||||
RIL_REQUEST_SET_UICC_SUBSCRIPTION);
|
||||
RIL_REQUEST_V9_SET_UICC_SUBSCRIPTION :
|
||||
RIL_REQUEST_SET_UICC_SUBSCRIPTION;
|
||||
if (priv->sub_req_id) {
|
||||
/* Some RILs never reply to SET_UICC_SUBSCRIPTION requst,
|
||||
* so we better drop rather than cancel it (so that it gets
|
||||
* removed from the list of pending requests) */
|
||||
grilio_channel_drop_request(priv->io, priv->sub_req_id);
|
||||
}
|
||||
|
||||
/* Don't allow any requests other that GET_SIM_STATUS until
|
||||
* we are done with the subscription */
|
||||
grilio_queue_transaction_start(priv->q);
|
||||
priv->sub_req_id = grilio_queue_send_request_full(priv->q,
|
||||
req, code, ril_sim_card_subscribe_cb, NULL, self);
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
@@ -185,14 +248,17 @@ static void ril_sim_card_update_app(struct ril_sim_card *self)
|
||||
if (status->gsm_umts_index >= 0 &&
|
||||
status->gsm_umts_index < status->num_apps) {
|
||||
app_index = status->gsm_umts_index;
|
||||
ril_sim_card_subscription_done(self);
|
||||
} else {
|
||||
app_index = ril_sim_card_select_app(status);
|
||||
if (app_index >= 0) {
|
||||
ril_sim_card_subscribe(self, app_index, 1);
|
||||
ril_sim_card_subscribe(self, app_index,
|
||||
RIL_UICC_SUBSCRIPTION_ACTIVATE);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
app_index = -1;
|
||||
ril_sim_card_subscription_done(self);
|
||||
}
|
||||
|
||||
if (app_index >= 0 &&
|
||||
@@ -203,8 +269,8 @@ static void ril_sim_card_update_app(struct ril_sim_card *self)
|
||||
}
|
||||
|
||||
if (!ril_sim_card_app_equal(old_app, self->app)) {
|
||||
g_signal_emit(self,
|
||||
ril_sim_card_signals[SIGNAL_APP_CHANGED], 0);
|
||||
g_signal_emit(self, ril_sim_card_signals
|
||||
[SIGNAL_APP_CHANGED], 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -218,23 +284,23 @@ static void ril_sim_card_update_status(struct ril_sim_card *self,
|
||||
|
||||
self->status = status;
|
||||
ril_sim_card_update_app(self);
|
||||
g_signal_emit(self, ril_sim_card_signals[
|
||||
SIGNAL_STATUS_RECEIVED], 0);
|
||||
g_signal_emit(self, ril_sim_card_signals
|
||||
[SIGNAL_STATUS_RECEIVED], 0);
|
||||
if (diff & RIL_SIMCARD_STATUS_CHANGED) {
|
||||
DBG("status changed");
|
||||
g_signal_emit(self, ril_sim_card_signals[
|
||||
SIGNAL_STATUS_CHANGED], 0);
|
||||
g_signal_emit(self, ril_sim_card_signals
|
||||
[SIGNAL_STATUS_CHANGED], 0);
|
||||
}
|
||||
if (diff & RIL_SIMCARD_STATE_CHANGED) {
|
||||
DBG("state changed");
|
||||
g_signal_emit(self, ril_sim_card_signals[
|
||||
SIGNAL_STATE_CHANGED], 0);
|
||||
g_signal_emit(self, ril_sim_card_signals
|
||||
[SIGNAL_STATE_CHANGED], 0);
|
||||
}
|
||||
ril_sim_card_status_free(old_status);
|
||||
} else {
|
||||
ril_sim_card_status_free(status);
|
||||
g_signal_emit(self, ril_sim_card_signals[
|
||||
SIGNAL_STATUS_RECEIVED], 0);
|
||||
g_signal_emit(self, ril_sim_card_signals
|
||||
[SIGNAL_STATUS_RECEIVED], 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -317,7 +383,8 @@ static struct ril_sim_card_status *ril_sim_card_status_parse(const void *data,
|
||||
status->num_apps = num_apps;
|
||||
|
||||
if (num_apps > 0) {
|
||||
status->apps = g_new0(struct ril_sim_card_app, num_apps);
|
||||
status->apps =
|
||||
g_new0(struct ril_sim_card_app, num_apps);
|
||||
}
|
||||
|
||||
for (i = 0; i < num_apps; i++) {
|
||||
@@ -338,6 +405,7 @@ static struct ril_sim_card_status *ril_sim_card_status_parse(const void *data,
|
||||
}
|
||||
|
||||
if (i == num_apps) {
|
||||
GASSERT(grilio_parser_at_end(&rilp));
|
||||
return status;
|
||||
} else {
|
||||
ril_sim_card_status_free(status);
|
||||
@@ -349,7 +417,7 @@ static struct ril_sim_card_status *ril_sim_card_status_parse(const void *data,
|
||||
static void ril_sim_card_status_cb(GRilIoChannel *io, int ril_status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_sim_card *self = user_data;
|
||||
struct ril_sim_card *self = RIL_SIMCARD(user_data);
|
||||
struct ril_sim_card_priv *priv = self->priv;
|
||||
|
||||
GASSERT(priv->status_req_id);
|
||||
@@ -365,28 +433,105 @@ static void ril_sim_card_status_cb(GRilIoChannel *io, int ril_status,
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_sim_card_request_status(struct ril_sim_card *self)
|
||||
void ril_sim_card_request_status(struct ril_sim_card *self)
|
||||
{
|
||||
struct ril_sim_card_priv *priv = self->priv;
|
||||
if (G_LIKELY(self)) {
|
||||
struct ril_sim_card_priv *priv = self->priv;
|
||||
|
||||
if (priv->status_req_id) {
|
||||
/* Retry right away, don't wait for retry timeout to expire */
|
||||
grilio_channel_retry_request(priv->io, priv->status_req_id);
|
||||
} else {
|
||||
GRilIoRequest* req = grilio_request_new();
|
||||
if (priv->status_req_id) {
|
||||
/* Retry right away, don't wait for retry
|
||||
* timeout to expire */
|
||||
grilio_channel_retry_request(priv->io,
|
||||
priv->status_req_id);
|
||||
} else {
|
||||
GRilIoRequest* req = grilio_request_new();
|
||||
|
||||
grilio_request_set_retry(req, RIL_RETRY_SECS*1000, -1);
|
||||
priv->status_req_id = grilio_queue_send_request_full(priv->q,
|
||||
grilio_request_set_retry(req, RIL_RETRY_SECS*1000, -1);
|
||||
priv->status_req_id =
|
||||
grilio_queue_send_request_full(priv->q,
|
||||
req, RIL_REQUEST_GET_SIM_STATUS,
|
||||
ril_sim_card_status_cb, NULL, self);
|
||||
grilio_request_unref(req);
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_sim_card_update_sim_io_active(struct ril_sim_card *self)
|
||||
{
|
||||
/* SIM I/O is considered active for certain period of time after
|
||||
* the last request has completed. That's because SIM_IO requests
|
||||
* are usually submitted in large quantities and quick succession.
|
||||
* Some RILs don't like being bothered while they are doing SIM I/O
|
||||
* and some time after that too. That sucks but what else can we
|
||||
* do about it? */
|
||||
struct ril_sim_card_priv *priv = self->priv;
|
||||
const gboolean active = priv->sim_io_idle_id ||
|
||||
g_hash_table_size(priv->sim_io_pending);
|
||||
|
||||
if (self->sim_io_active != active) {
|
||||
self->sim_io_active = active;
|
||||
DBG("SIM I/O for slot %u is %sactive", self->slot,
|
||||
active ? "" : "in");
|
||||
g_signal_emit(self, ril_sim_card_signals
|
||||
[SIGNAL_SIM_IO_ACTIVE_CHANGED], 0);
|
||||
}
|
||||
}
|
||||
|
||||
void ril_sim_card_sim_io_started(struct ril_sim_card *self, guint id)
|
||||
{
|
||||
if (G_LIKELY(self) && G_LIKELY(id)) {
|
||||
struct ril_sim_card_priv *priv = self->priv;
|
||||
gpointer key = GINT_TO_POINTER(id);
|
||||
|
||||
g_hash_table_insert(priv->sim_io_pending, key, key);
|
||||
if (priv->sim_io_idle_id) {
|
||||
g_source_remove(priv->sim_io_idle_id);
|
||||
priv->sim_io_idle_id = 0;
|
||||
priv->sim_io_idle_count = 0;
|
||||
}
|
||||
ril_sim_card_update_sim_io_active(self);
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean ril_sim_card_sim_io_idle_cb(gpointer user_data)
|
||||
{
|
||||
struct ril_sim_card *self = RIL_SIMCARD(user_data);
|
||||
struct ril_sim_card_priv *priv = self->priv;
|
||||
|
||||
if (++(priv->sim_io_idle_count) >= SIM_IO_IDLE_LOOPS) {
|
||||
priv->sim_io_idle_id = 0;
|
||||
priv->sim_io_idle_count = 0;
|
||||
ril_sim_card_update_sim_io_active(self);
|
||||
return G_SOURCE_REMOVE;
|
||||
} else {
|
||||
return G_SOURCE_CONTINUE;
|
||||
}
|
||||
}
|
||||
|
||||
void ril_sim_card_sim_io_finished(struct ril_sim_card *self, guint id)
|
||||
{
|
||||
if (G_LIKELY(self) && G_LIKELY(id)) {
|
||||
struct ril_sim_card_priv *priv = self->priv;
|
||||
gpointer key = GINT_TO_POINTER(id);
|
||||
|
||||
if (g_hash_table_remove(priv->sim_io_pending, key) &&
|
||||
!g_hash_table_size(priv->sim_io_pending)) {
|
||||
/* Reset the idle loop count */
|
||||
if (priv->sim_io_idle_id) {
|
||||
g_source_remove(priv->sim_io_idle_id);
|
||||
priv->sim_io_idle_count = 0;
|
||||
}
|
||||
priv->sim_io_idle_id =
|
||||
g_idle_add(ril_sim_card_sim_io_idle_cb, self);
|
||||
}
|
||||
ril_sim_card_update_sim_io_active(self);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_sim_card_status_changed(GRilIoChannel *io, guint code,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_sim_card *self = user_data;
|
||||
struct ril_sim_card *self = RIL_SIMCARD(user_data);
|
||||
|
||||
ril_sim_card_request_status(self);
|
||||
}
|
||||
@@ -474,6 +619,13 @@ gulong ril_sim_card_add_app_changed_handler(struct ril_sim_card *self,
|
||||
SIGNAL_APP_CHANGED_NAME, G_CALLBACK(cb), arg) : 0;
|
||||
}
|
||||
|
||||
gulong ril_sim_card_add_sim_io_active_changed_handler(struct ril_sim_card *self,
|
||||
ril_sim_card_cb_t cb, void *arg)
|
||||
{
|
||||
return (G_LIKELY(self) && G_LIKELY(cb)) ? g_signal_connect(self,
|
||||
SIGNAL_SIM_IO_ACTIVE_CHANGED_NAME, G_CALLBACK(cb), arg) : 0;
|
||||
}
|
||||
|
||||
void ril_sim_card_remove_handler(struct ril_sim_card *self, gulong id)
|
||||
{
|
||||
if (G_LIKELY(self) && G_LIKELY(id)) {
|
||||
@@ -488,8 +640,11 @@ void ril_sim_card_remove_handlers(struct ril_sim_card *self, gulong *ids, int n)
|
||||
|
||||
static void ril_sim_card_init(struct ril_sim_card *self)
|
||||
{
|
||||
self->priv = G_TYPE_INSTANCE_GET_PRIVATE(self, RIL_SIMCARD_TYPE,
|
||||
struct ril_sim_card_priv);
|
||||
struct ril_sim_card_priv *priv = G_TYPE_INSTANCE_GET_PRIVATE(self,
|
||||
RIL_SIMCARD_TYPE, struct ril_sim_card_priv);
|
||||
|
||||
self->priv = priv;
|
||||
priv->sim_io_pending = g_hash_table_new(g_direct_hash, g_direct_equal);
|
||||
}
|
||||
|
||||
static void ril_sim_card_dispose(GObject *object)
|
||||
@@ -507,6 +662,10 @@ static void ril_sim_card_finalize(GObject *object)
|
||||
struct ril_sim_card *self = RIL_SIMCARD(object);
|
||||
struct ril_sim_card_priv *priv = self->priv;
|
||||
|
||||
if (priv->sim_io_idle_id) {
|
||||
g_source_remove(priv->sim_io_idle_id);
|
||||
}
|
||||
g_hash_table_destroy(priv->sim_io_pending);
|
||||
grilio_channel_unref(priv->io);
|
||||
grilio_queue_unref(priv->q);
|
||||
ril_sim_card_status_free(self->status);
|
||||
@@ -520,22 +679,11 @@ static void ril_sim_card_class_init(RilSimCardClass *klass)
|
||||
object_class->dispose = ril_sim_card_dispose;
|
||||
object_class->finalize = ril_sim_card_finalize;
|
||||
g_type_class_add_private(klass, sizeof(struct ril_sim_card_priv));
|
||||
ril_sim_card_signals[SIGNAL_STATUS_RECEIVED] =
|
||||
g_signal_new(SIGNAL_STATUS_RECEIVED_NAME,
|
||||
G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_FIRST,
|
||||
0, NULL, NULL, NULL, G_TYPE_NONE, 0);
|
||||
ril_sim_card_signals[SIGNAL_STATUS_CHANGED] =
|
||||
g_signal_new(SIGNAL_STATUS_CHANGED_NAME,
|
||||
G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_FIRST,
|
||||
0, NULL, NULL, NULL, G_TYPE_NONE, 0);
|
||||
ril_sim_card_signals[SIGNAL_STATE_CHANGED] =
|
||||
g_signal_new(SIGNAL_STATE_CHANGED_NAME,
|
||||
G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_FIRST,
|
||||
0, NULL, NULL, NULL, G_TYPE_NONE, 0);
|
||||
ril_sim_card_signals[SIGNAL_APP_CHANGED] =
|
||||
g_signal_new(SIGNAL_APP_CHANGED_NAME,
|
||||
G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_FIRST,
|
||||
0, NULL, NULL, NULL, G_TYPE_NONE, 0);
|
||||
NEW_SIGNAL_(klass,STATUS_RECEIVED);
|
||||
NEW_SIGNAL(klass,STATUS);
|
||||
NEW_SIGNAL(klass,STATE);
|
||||
NEW_SIGNAL(klass,APP);
|
||||
NEW_SIGNAL(klass,SIM_IO_ACTIVE);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2016 Jolla Ltd.
|
||||
* Copyright (C) 2015-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
|
||||
@@ -44,6 +44,7 @@ struct ril_sim_card {
|
||||
struct ril_sim_card_priv *priv;
|
||||
struct ril_sim_card_status *status;
|
||||
const struct ril_sim_card_app *app;
|
||||
gboolean sim_io_active;
|
||||
guint slot;
|
||||
};
|
||||
|
||||
@@ -55,6 +56,9 @@ typedef void (*ril_sim_card_cb_t)(struct ril_sim_card *sc, void *arg);
|
||||
struct ril_sim_card *ril_sim_card_new(GRilIoChannel *io, guint slot, int flags);
|
||||
struct ril_sim_card *ril_sim_card_ref(struct ril_sim_card *sc);
|
||||
void ril_sim_card_unref(struct ril_sim_card *sc);
|
||||
void ril_sim_card_request_status(struct ril_sim_card *sc);
|
||||
void ril_sim_card_sim_io_started(struct ril_sim_card *sc, guint id);
|
||||
void ril_sim_card_sim_io_finished(struct ril_sim_card *sc, guint id);
|
||||
gboolean ril_sim_card_ready(struct ril_sim_card *sc);
|
||||
gulong ril_sim_card_add_status_received_handler(struct ril_sim_card *sc,
|
||||
ril_sim_card_cb_t cb, void *arg);
|
||||
@@ -64,6 +68,8 @@ gulong ril_sim_card_add_state_changed_handler(struct ril_sim_card *sc,
|
||||
ril_sim_card_cb_t cb, void *arg);
|
||||
gulong ril_sim_card_add_app_changed_handler(struct ril_sim_card *sc,
|
||||
ril_sim_card_cb_t cb, void *arg);
|
||||
gulong ril_sim_card_add_sim_io_active_changed_handler(struct ril_sim_card *sc,
|
||||
ril_sim_card_cb_t cb, void *arg);
|
||||
void ril_sim_card_remove_handler(struct ril_sim_card *sc, gulong id);
|
||||
void ril_sim_card_remove_handlers(struct ril_sim_card *sc, gulong *ids, int n);
|
||||
|
||||
|
||||
@@ -1,668 +0,0 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2016 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_sim_info.h"
|
||||
#include "ril_network.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
#include <ofono/sim.h>
|
||||
|
||||
#include "ofono.h"
|
||||
#include "storage.h"
|
||||
|
||||
#define RIL_SIM_INFO_STORE "cache"
|
||||
#define RIL_SIM_INFO_STORE_GROUP "sim"
|
||||
#define RIL_SIM_INFO_STORE_SPN "spn"
|
||||
|
||||
/* ICCID -> IMSI map */
|
||||
#define RIL_SIM_ICCID_MAP "iccidmap"
|
||||
#define RIL_SIM_ICCID_MAP_IMSI "imsi"
|
||||
|
||||
#define RIL_SIM_DEFAULT_SPN_BUFSIZE 8
|
||||
G_STATIC_ASSERT(RIL_SIM_DEFAULT_SPN_BUFSIZE >= \
|
||||
OFONO_MAX_MCC_LENGTH + OFONO_MAX_MNC_LENGTH + 1);
|
||||
|
||||
typedef GObjectClass RilSimInfoClass;
|
||||
typedef struct ril_sim_info RilSimInfo;
|
||||
|
||||
typedef void (*ril_sim_info_remove_cb_t)(struct ofono_sim *sim,
|
||||
unsigned int id);
|
||||
typedef void (*ril_sim_info_set_value_cb_t)(struct ril_sim_info *info,
|
||||
const char *value);
|
||||
|
||||
struct ril_sim_info_watch {
|
||||
ril_sim_info_set_value_cb_t set_value;
|
||||
ril_sim_info_remove_cb_t remove;
|
||||
struct ril_sim_info *info;
|
||||
unsigned int id;
|
||||
};
|
||||
|
||||
struct ril_sim_info_priv {
|
||||
char *log_prefix;
|
||||
char *iccid;
|
||||
char *imsi;
|
||||
char *cached_spn;
|
||||
char *sim_spn;
|
||||
char *public_spn;
|
||||
char default_spn[RIL_SIM_DEFAULT_SPN_BUFSIZE];
|
||||
int public_spn_block;
|
||||
struct ofono_sim *sim;
|
||||
struct ril_sim_info_watch state_watch;
|
||||
struct ril_sim_info_watch iccid_watch;
|
||||
struct ril_sim_info_watch imsi_watch;
|
||||
struct ril_sim_info_watch spn_watch;
|
||||
struct ril_network *network;
|
||||
gulong network_operator_changed_id;
|
||||
gboolean update_imsi_cache;
|
||||
gboolean update_iccid_map;
|
||||
};
|
||||
|
||||
enum ril_sim_info_signal {
|
||||
SIGNAL_ICCID_CHANGED,
|
||||
SIGNAL_IMSI_CHANGED,
|
||||
SIGNAL_SPN_CHANGED,
|
||||
SIGNAL_COUNT
|
||||
};
|
||||
|
||||
#define SIGNAL_ICCID_CHANGED_NAME "ril-sim-info-iccid-changed"
|
||||
#define SIGNAL_IMSI_CHANGED_NAME "ril-sim-info-imsi-changed"
|
||||
#define SIGNAL_SPN_CHANGED_NAME "ril-sim-info-spn-changed"
|
||||
|
||||
static guint ril_sim_info_signals[SIGNAL_COUNT] = { 0 };
|
||||
|
||||
G_DEFINE_TYPE(RilSimInfo, ril_sim_info, G_TYPE_OBJECT)
|
||||
#define RIL_SIMINFO_TYPE (ril_sim_info_get_type())
|
||||
#define RIL_SIMINFO(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),\
|
||||
RIL_SIMINFO_TYPE, RilSimInfo))
|
||||
|
||||
#define NEW_SIGNAL(klass,name) \
|
||||
ril_sim_info_signals[SIGNAL_##name##_CHANGED] = \
|
||||
g_signal_new(SIGNAL_##name##_CHANGED_NAME, \
|
||||
G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_FIRST, \
|
||||
0, NULL, NULL, NULL, G_TYPE_NONE, 0)
|
||||
|
||||
#define DBG_(info,fmt,args...) DBG("%s" fmt, (info)->priv->log_prefix, ##args)
|
||||
|
||||
static void ril_sim_info_signal_emit(struct ril_sim_info *self,
|
||||
enum ril_sim_info_signal id)
|
||||
{
|
||||
g_signal_emit(self, ril_sim_info_signals[id], 0);
|
||||
}
|
||||
|
||||
static void ril_sim_info_watch_remove(struct ril_sim_info_watch *watch)
|
||||
{
|
||||
if (watch->id) {
|
||||
struct ril_sim_info_priv *priv = watch->info->priv;
|
||||
|
||||
GASSERT(priv->sim);
|
||||
if (priv->sim) {
|
||||
watch->remove(priv->sim, watch->id);
|
||||
GASSERT(!watch->id);
|
||||
}
|
||||
|
||||
watch->id = 0;
|
||||
}
|
||||
|
||||
if (watch->set_value) {
|
||||
watch->set_value(watch->info, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_sim_info_remove_spn_watch(struct ofono_sim *sim,
|
||||
unsigned int id)
|
||||
{
|
||||
ofono_sim_remove_spn_watch(sim, &id);
|
||||
}
|
||||
|
||||
static void ril_sim_info_update_imsi_cache(struct ril_sim_info *self)
|
||||
{
|
||||
struct ril_sim_info_priv *priv = self->priv;
|
||||
|
||||
if (priv->update_imsi_cache && priv->imsi && priv->imsi[0] &&
|
||||
priv->cached_spn && priv->cached_spn[0]) {
|
||||
gboolean save = FALSE;
|
||||
const char *store = RIL_SIM_INFO_STORE;
|
||||
GKeyFile *cache = storage_open(priv->imsi, store);
|
||||
char *spn = g_key_file_get_string(cache,
|
||||
RIL_SIM_INFO_STORE_GROUP,
|
||||
RIL_SIM_INFO_STORE_SPN, NULL);
|
||||
|
||||
if (g_strcmp0(priv->cached_spn, spn)) {
|
||||
save = TRUE;
|
||||
g_key_file_set_string(cache, RIL_SIM_INFO_STORE_GROUP,
|
||||
RIL_SIM_INFO_STORE_SPN, priv->cached_spn);
|
||||
}
|
||||
|
||||
/*
|
||||
* Since we are most likely running on flash which
|
||||
* supports a limited number of writes, don't overwrite
|
||||
* the file unless something has actually changed.
|
||||
*/
|
||||
if (save) {
|
||||
DBG_(self, "updating " STORAGEDIR "/%s/%s",
|
||||
priv->imsi, store);
|
||||
storage_close(priv->imsi, store, cache, TRUE);
|
||||
} else {
|
||||
g_key_file_free(cache);
|
||||
}
|
||||
|
||||
g_free(spn);
|
||||
priv->update_imsi_cache = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_sim_info_update_iccid_map(struct ril_sim_info *self)
|
||||
{
|
||||
struct ril_sim_info_priv *priv = self->priv;
|
||||
|
||||
if (priv->update_iccid_map && priv->iccid && priv->iccid[0] &&
|
||||
priv->imsi && priv->imsi[0]) {
|
||||
const char *store = RIL_SIM_ICCID_MAP;
|
||||
GKeyFile *map = storage_open(NULL, store);
|
||||
char *imsi = g_key_file_get_string(map, RIL_SIM_ICCID_MAP_IMSI,
|
||||
priv->iccid, NULL);
|
||||
|
||||
/*
|
||||
* Since we are most likely running on flash which
|
||||
* supports a limited number of writes, don't overwrite
|
||||
* the file unless something has actually changed.
|
||||
*/
|
||||
if (g_strcmp0(imsi, priv->imsi)) {
|
||||
DBG_(self, "updating " STORAGEDIR "/%s", store);
|
||||
g_key_file_set_string(map, RIL_SIM_ICCID_MAP_IMSI,
|
||||
priv->iccid, priv->imsi);
|
||||
storage_close(NULL, store, map, TRUE);
|
||||
} else {
|
||||
g_key_file_free(map);
|
||||
}
|
||||
|
||||
g_free(imsi);
|
||||
priv->update_iccid_map = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_sim_info_set_imsi(struct ril_sim_info *self, const char *imsi)
|
||||
{
|
||||
struct ril_sim_info_priv *priv = self->priv;
|
||||
|
||||
if (g_strcmp0(priv->imsi, imsi)) {
|
||||
g_free(priv->imsi);
|
||||
self->imsi = priv->imsi = g_strdup(imsi);
|
||||
priv->update_iccid_map = TRUE;
|
||||
ril_sim_info_update_iccid_map(self);
|
||||
ril_sim_info_update_imsi_cache(self);
|
||||
ril_sim_info_signal_emit(self, SIGNAL_IMSI_CHANGED);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_sim_info_update_public_spn(struct ril_sim_info *self)
|
||||
{
|
||||
struct ril_sim_info_priv *priv = self->priv;
|
||||
|
||||
GASSERT(priv->public_spn_block >= 0);
|
||||
if (!priv->public_spn_block) {
|
||||
const char *spn = priv->sim_spn ? priv->sim_spn :
|
||||
priv->cached_spn ? priv->cached_spn :
|
||||
priv->default_spn;
|
||||
|
||||
if (g_strcmp0(priv->public_spn, spn)) {
|
||||
g_free(priv->public_spn);
|
||||
self->spn = priv->public_spn = g_strdup(spn);
|
||||
ril_sim_info_signal_emit(self, SIGNAL_SPN_CHANGED);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_sim_info_set_cached_spn(struct ril_sim_info *self,
|
||||
const char *spn)
|
||||
{
|
||||
struct ril_sim_info_priv *priv = self->priv;
|
||||
|
||||
if (g_strcmp0(priv->cached_spn, 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;
|
||||
ril_sim_info_update_imsi_cache(self);
|
||||
} else {
|
||||
priv->cached_spn = NULL;
|
||||
}
|
||||
ril_sim_info_update_public_spn(self);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_sim_info_set_sim_spn(struct ril_sim_info *self,
|
||||
const char *spn)
|
||||
{
|
||||
struct ril_sim_info_priv *priv = self->priv;
|
||||
|
||||
if (g_strcmp0(priv->sim_spn, spn)) {
|
||||
g_free(priv->sim_spn);
|
||||
priv->sim_spn = g_strdup(spn);
|
||||
priv->update_imsi_cache = TRUE;
|
||||
ril_sim_info_set_cached_spn(self, spn);
|
||||
ril_sim_info_update_imsi_cache(self);
|
||||
ril_sim_info_update_public_spn(self);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_sim_info_update_default_spn(struct ril_sim_info *self)
|
||||
{
|
||||
struct ril_sim_info_priv *priv = self->priv;
|
||||
char buf[RIL_SIM_DEFAULT_SPN_BUFSIZE];
|
||||
const char *mcc = NULL;
|
||||
const char *mnc = NULL;
|
||||
|
||||
if (priv->sim &&
|
||||
ofono_sim_get_state(priv->sim) == OFONO_SIM_STATE_READY) {
|
||||
mcc = ofono_sim_get_mcc(priv->sim);
|
||||
mnc = ofono_sim_get_mnc(priv->sim);
|
||||
}
|
||||
|
||||
if (mcc && mnc) {
|
||||
snprintf(buf, RIL_SIM_DEFAULT_SPN_BUFSIZE, "%s%s", mcc, mnc);
|
||||
buf[RIL_SIM_DEFAULT_SPN_BUFSIZE - 1] = 0;
|
||||
} else {
|
||||
buf[0] = 0;
|
||||
}
|
||||
|
||||
if (strcmp(buf, priv->default_spn)) {
|
||||
strncpy(priv->default_spn, buf, RIL_SIM_DEFAULT_SPN_BUFSIZE);
|
||||
DBG_(self, "default spn \"%s\"", priv->default_spn);
|
||||
ril_sim_info_update_public_spn(self);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_sim_info_network_check(struct ril_sim_info *self)
|
||||
{
|
||||
struct ril_sim_info_priv *priv = self->priv;
|
||||
|
||||
if (priv->network && priv->network->operator && priv->sim &&
|
||||
ofono_sim_get_state(priv->sim) == OFONO_SIM_STATE_READY) {
|
||||
const char *mcc = ofono_sim_get_mcc(priv->sim);
|
||||
const char *mnc = ofono_sim_get_mnc(priv->sim);
|
||||
const struct ofono_network_operator *op =
|
||||
priv->network->operator;
|
||||
|
||||
if (mcc && mcc[0] && !strcmp(mcc, op->mcc) &&
|
||||
mnc && mnc[0] && !strcmp(mnc, op->mnc)) {
|
||||
|
||||
/*
|
||||
* If EFspn is present then sim_spn should be set
|
||||
* before we get registered with the network.
|
||||
*/
|
||||
DBG_(self, "home network \"%s\"", op->name);
|
||||
if (!priv->sim_spn) {
|
||||
ril_sim_info_set_cached_spn(self, op->name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_sim_info_network_operator_changed(struct ril_network *network,
|
||||
void *user_data)
|
||||
{
|
||||
struct ril_sim_info *self = RIL_SIMINFO(user_data);
|
||||
|
||||
DBG_(self, "");
|
||||
ril_sim_info_network_check(self);
|
||||
}
|
||||
|
||||
static void ril_sim_info_load_cache(struct ril_sim_info *self)
|
||||
{
|
||||
struct ril_sim_info_priv *priv = self->priv;
|
||||
|
||||
if (priv->iccid && priv->iccid[0]) {
|
||||
GKeyFile *map = storage_open(NULL, RIL_SIM_ICCID_MAP);
|
||||
char *imsi = g_key_file_get_string(map, RIL_SIM_ICCID_MAP_IMSI,
|
||||
priv->iccid, NULL);
|
||||
g_key_file_free(map);
|
||||
|
||||
if (imsi && imsi[0] && g_strcmp0(priv->imsi, imsi)) {
|
||||
if (priv->imsi && priv->imsi[0]) {
|
||||
/* Need to update ICCID -> IMSI map */
|
||||
DBG_(self, "IMSI changed %s -> %s",
|
||||
priv->imsi, imsi);
|
||||
priv->update_imsi_cache = TRUE;
|
||||
}
|
||||
g_free(priv->imsi);
|
||||
self->imsi = priv->imsi = imsi;
|
||||
DBG_(self, "imsi[%s] = %s", priv->iccid, imsi);
|
||||
ril_sim_info_update_iccid_map(self);
|
||||
ril_sim_info_signal_emit(self, SIGNAL_IMSI_CHANGED);
|
||||
} else if (imsi) {
|
||||
g_free(imsi);
|
||||
} else {
|
||||
DBG_(self, "no imsi for iccid %s", priv->iccid);
|
||||
}
|
||||
}
|
||||
|
||||
if (priv->imsi && priv->imsi[0]) {
|
||||
GKeyFile *cache = storage_open(priv->imsi, RIL_SIM_INFO_STORE);
|
||||
char *spn = g_key_file_get_string(cache,
|
||||
RIL_SIM_INFO_STORE_GROUP,
|
||||
RIL_SIM_INFO_STORE_SPN, NULL);
|
||||
g_key_file_free(cache);
|
||||
|
||||
if (spn && spn[0] && g_strcmp0(priv->cached_spn, spn)) {
|
||||
if (priv->cached_spn && priv->cached_spn[0]) {
|
||||
/* Need to update the cache file */
|
||||
DBG_(self, "spn changing %s -> %s",
|
||||
priv->cached_spn, spn);
|
||||
priv->update_imsi_cache = TRUE;
|
||||
}
|
||||
g_free(priv->cached_spn);
|
||||
priv->cached_spn = spn;
|
||||
DBG_(self, "spn[%s] = \"%s\"", priv->imsi, spn);
|
||||
ril_sim_info_update_imsi_cache(self);
|
||||
ril_sim_info_update_public_spn(self);
|
||||
} else if (spn) {
|
||||
g_free(spn);
|
||||
} else {
|
||||
DBG_(self, "no spn for imsi %s", priv->imsi);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_sim_info_set_iccid(struct ril_sim_info *self, const char *iccid)
|
||||
{
|
||||
struct ril_sim_info_priv *priv = self->priv;
|
||||
|
||||
if (g_strcmp0(priv->iccid, iccid)) {
|
||||
g_free(priv->iccid);
|
||||
self->iccid = priv->iccid = g_strdup(iccid);
|
||||
ril_sim_info_signal_emit(self, SIGNAL_ICCID_CHANGED);
|
||||
if (iccid) {
|
||||
ril_sim_info_load_cache(self);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_sim_info_imsi_watch_cb(const char *imsi, void *data)
|
||||
{
|
||||
struct ril_sim_info_watch *watch = data;
|
||||
|
||||
DBG_(watch->info, "%s", imsi);
|
||||
ril_sim_info_set_imsi(watch->info, imsi);
|
||||
}
|
||||
|
||||
static void ril_sim_info_spn_watch_cb(const char *spn, const char *dc,
|
||||
void *data)
|
||||
{
|
||||
struct ril_sim_info_watch *watch = data;
|
||||
|
||||
DBG_(watch->info, "%s", spn);
|
||||
ril_sim_info_set_sim_spn(watch->info, spn);
|
||||
}
|
||||
|
||||
static void ril_sim_info_iccid_watch_cb(const char *iccid, void *data)
|
||||
{
|
||||
struct ril_sim_info_watch *watch = data;
|
||||
|
||||
DBG_(watch->info, "%s", iccid);
|
||||
ril_sim_info_set_iccid(watch->info, iccid);
|
||||
}
|
||||
|
||||
static void ril_sim_info_watch_done(void *data)
|
||||
{
|
||||
struct ril_sim_info_watch *watch = data;
|
||||
|
||||
GASSERT(watch->id);
|
||||
watch->id = 0;
|
||||
}
|
||||
|
||||
static void ril_sim_info_handle_sim_state(struct ril_sim_info *self,
|
||||
enum ofono_sim_state state)
|
||||
{
|
||||
struct ril_sim_info_priv *priv = self->priv;
|
||||
struct ril_sim_info_watch *watch;
|
||||
|
||||
DBG_(self, "%d", state);
|
||||
|
||||
switch (state) {
|
||||
case OFONO_SIM_STATE_READY:
|
||||
/* SPN */
|
||||
watch = &priv->spn_watch;
|
||||
if (!watch->id) {
|
||||
ofono_sim_add_spn_watch(priv->sim, &watch->id,
|
||||
ril_sim_info_spn_watch_cb, watch,
|
||||
ril_sim_info_watch_done);
|
||||
GASSERT(priv->spn_watch.id);
|
||||
}
|
||||
/* IMSI */
|
||||
watch = &priv->imsi_watch;
|
||||
if (!watch->id) {
|
||||
watch->id = ofono_sim_add_imsi_watch(priv->sim,
|
||||
ril_sim_info_imsi_watch_cb, watch,
|
||||
ril_sim_info_watch_done);
|
||||
GASSERT(watch->id);
|
||||
}
|
||||
/* no break */
|
||||
case OFONO_SIM_STATE_INSERTED:
|
||||
case OFONO_SIM_STATE_LOCKED_OUT:
|
||||
/* ICCID */
|
||||
watch = &priv->iccid_watch;
|
||||
if (!watch->id) {
|
||||
watch->id = ofono_sim_add_iccid_watch(priv->sim,
|
||||
ril_sim_info_iccid_watch_cb, watch,
|
||||
ril_sim_info_watch_done);
|
||||
GASSERT(watch->id);
|
||||
}
|
||||
break;
|
||||
case OFONO_SIM_STATE_NOT_PRESENT:
|
||||
case OFONO_SIM_STATE_RESETTING:
|
||||
ril_sim_info_watch_remove(&priv->spn_watch);
|
||||
ril_sim_info_watch_remove(&priv->imsi_watch);
|
||||
ril_sim_info_watch_remove(&priv->iccid_watch);
|
||||
break;
|
||||
}
|
||||
|
||||
ril_sim_info_update_default_spn(self);
|
||||
ril_sim_info_network_check(self);
|
||||
}
|
||||
|
||||
static void ril_sim_info_state_watch_cb(enum ofono_sim_state new_state,
|
||||
void *data)
|
||||
{
|
||||
struct ril_sim_info_watch *watch = data;
|
||||
ril_sim_info_handle_sim_state(watch->info, new_state);
|
||||
}
|
||||
|
||||
struct ril_sim_info *ril_sim_info_new(const char *log_prefix)
|
||||
{
|
||||
struct ril_sim_info *self = g_object_new(RIL_SIMINFO_TYPE, NULL);
|
||||
|
||||
self->priv->log_prefix = (log_prefix && log_prefix[0]) ?
|
||||
g_strconcat(log_prefix, " ", NULL) : g_strdup("");
|
||||
return self;
|
||||
}
|
||||
|
||||
struct ril_sim_info *ril_sim_info_ref(struct ril_sim_info *self)
|
||||
{
|
||||
if (G_LIKELY(self)) {
|
||||
g_object_ref(RIL_SIMINFO(self));
|
||||
return self;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void ril_sim_info_unref(struct ril_sim_info *self)
|
||||
{
|
||||
if (G_LIKELY(self)) {
|
||||
g_object_unref(RIL_SIMINFO(self));
|
||||
}
|
||||
}
|
||||
|
||||
void ril_sim_info_set_ofono_sim(struct ril_sim_info *self,
|
||||
struct ofono_sim *sim)
|
||||
{
|
||||
if (G_LIKELY(self)) {
|
||||
struct ril_sim_info_priv *priv = self->priv;
|
||||
|
||||
if (priv->sim != sim) {
|
||||
priv->public_spn_block++;
|
||||
ril_sim_info_watch_remove(&priv->state_watch);
|
||||
ril_sim_info_watch_remove(&priv->iccid_watch);
|
||||
ril_sim_info_watch_remove(&priv->imsi_watch);
|
||||
ril_sim_info_watch_remove(&priv->spn_watch);
|
||||
|
||||
priv->update_imsi_cache = FALSE;
|
||||
priv->update_iccid_map = FALSE;
|
||||
priv->sim = sim;
|
||||
|
||||
if (sim) {
|
||||
priv->state_watch.id =
|
||||
ofono_sim_add_state_watch(sim,
|
||||
ril_sim_info_state_watch_cb,
|
||||
&priv->state_watch,
|
||||
ril_sim_info_watch_done);
|
||||
GASSERT(priv->state_watch.id);
|
||||
DBG_(self, "attached to sim");
|
||||
ril_sim_info_handle_sim_state(self,
|
||||
ofono_sim_get_state(sim));
|
||||
} else {
|
||||
DBG_(self, "detached from sim");
|
||||
ril_sim_info_update_default_spn(self);
|
||||
ril_sim_info_network_check(self);
|
||||
}
|
||||
|
||||
priv->public_spn_block--;
|
||||
ril_sim_info_update_public_spn(self);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ril_sim_info_set_network(struct ril_sim_info *self,
|
||||
struct ril_network *network)
|
||||
{
|
||||
if (G_LIKELY(self) && self->priv->network != network) {
|
||||
struct ril_sim_info_priv *priv = self->priv;
|
||||
|
||||
if (priv->network) {
|
||||
ril_network_remove_handlers(priv->network,
|
||||
&priv->network_operator_changed_id, 1);
|
||||
ril_network_unref(priv->network);
|
||||
}
|
||||
if (network) {
|
||||
priv->network_operator_changed_id =
|
||||
ril_network_add_operator_changed_handler(network,
|
||||
ril_sim_info_network_operator_changed,
|
||||
self);
|
||||
priv->network = ril_network_ref(network);
|
||||
ril_sim_info_network_check(self);
|
||||
} else {
|
||||
priv->network = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gulong ril_sim_info_add_iccid_changed_handler(struct ril_sim_info *self,
|
||||
ril_sim_info_cb_t cb, void *arg)
|
||||
{
|
||||
return (G_LIKELY(self) && G_LIKELY(cb)) ? g_signal_connect(self,
|
||||
SIGNAL_ICCID_CHANGED_NAME, G_CALLBACK(cb), arg) : 0;
|
||||
}
|
||||
|
||||
gulong ril_sim_info_add_imsi_changed_handler(struct ril_sim_info *self,
|
||||
ril_sim_info_cb_t cb, void *arg)
|
||||
{
|
||||
return (G_LIKELY(self) && G_LIKELY(cb)) ? g_signal_connect(self,
|
||||
SIGNAL_IMSI_CHANGED_NAME, G_CALLBACK(cb), arg) : 0;
|
||||
}
|
||||
|
||||
gulong ril_sim_info_add_spn_changed_handler(struct ril_sim_info *self,
|
||||
ril_sim_info_cb_t cb, void *arg)
|
||||
{
|
||||
return (G_LIKELY(self) && G_LIKELY(cb)) ? g_signal_connect(self,
|
||||
SIGNAL_SPN_CHANGED_NAME, G_CALLBACK(cb), arg) : 0;
|
||||
}
|
||||
|
||||
void ril_sim_info_remove_handler(struct ril_sim_info *self, gulong id)
|
||||
{
|
||||
if (G_LIKELY(self) && G_LIKELY(id)) {
|
||||
g_signal_handler_disconnect(self, id);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_sim_info_watch_init(struct ril_sim_info *self,
|
||||
struct ril_sim_info_watch *watch,
|
||||
ril_sim_info_set_value_cb_t set_value,
|
||||
ril_sim_info_remove_cb_t remove)
|
||||
{
|
||||
watch->info = self;
|
||||
watch->set_value = set_value;
|
||||
watch->remove = remove;
|
||||
}
|
||||
|
||||
static void ril_sim_info_init(struct ril_sim_info *self)
|
||||
{
|
||||
struct ril_sim_info_priv *priv = G_TYPE_INSTANCE_GET_PRIVATE(self,
|
||||
RIL_SIMINFO_TYPE, struct ril_sim_info_priv);
|
||||
|
||||
self->priv = priv;
|
||||
ril_sim_info_watch_init(self, &priv->state_watch,
|
||||
NULL, ofono_sim_remove_state_watch);
|
||||
ril_sim_info_watch_init(self, &priv->iccid_watch,
|
||||
ril_sim_info_set_iccid, ofono_sim_remove_iccid_watch);
|
||||
ril_sim_info_watch_init(self, &priv->imsi_watch,
|
||||
ril_sim_info_set_imsi, ofono_sim_remove_imsi_watch);
|
||||
ril_sim_info_watch_init(self, &priv->spn_watch,
|
||||
ril_sim_info_set_sim_spn, ril_sim_info_remove_spn_watch);
|
||||
}
|
||||
|
||||
static void ril_sim_info_dispose(GObject *object)
|
||||
{
|
||||
struct ril_sim_info *self = RIL_SIMINFO(object);
|
||||
|
||||
ril_sim_info_set_ofono_sim(self, NULL);
|
||||
ril_sim_info_set_network(self, NULL);
|
||||
G_OBJECT_CLASS(ril_sim_info_parent_class)->dispose(object);
|
||||
}
|
||||
|
||||
static void ril_sim_info_finalize(GObject *object)
|
||||
{
|
||||
struct ril_sim_info *self = RIL_SIMINFO(object);
|
||||
struct ril_sim_info_priv *priv = self->priv;
|
||||
|
||||
g_free(priv->log_prefix);
|
||||
g_free(priv->cached_spn);
|
||||
g_free(priv->public_spn);
|
||||
GASSERT(!priv->iccid);
|
||||
GASSERT(!priv->imsi);
|
||||
GASSERT(!priv->sim_spn);
|
||||
G_OBJECT_CLASS(ril_sim_info_parent_class)->finalize(object);
|
||||
}
|
||||
|
||||
static void ril_sim_info_class_init(RilSimInfoClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS(klass);
|
||||
|
||||
object_class->dispose = ril_sim_info_dispose;
|
||||
object_class->finalize = ril_sim_info_finalize;
|
||||
g_type_class_add_private(klass, sizeof(struct ril_sim_info_priv));
|
||||
NEW_SIGNAL(klass, ICCID);
|
||||
NEW_SIGNAL(klass, IMSI);
|
||||
NEW_SIGNAL(klass, SPN);
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
@@ -1,243 +0,0 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2016 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_sim_info.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
#include <ofono/dbus.h>
|
||||
|
||||
#include <gdbus.h>
|
||||
|
||||
#include "ofono.h"
|
||||
#include "storage.h"
|
||||
|
||||
enum sim_info_event_id {
|
||||
SIM_INFO_EVENT_ICCID,
|
||||
SIM_INFO_EVENT_IMSI,
|
||||
SIM_INFO_EVENT_SPN,
|
||||
SIM_INFO_EVENT_COUNT
|
||||
};
|
||||
|
||||
struct ril_sim_info_dbus {
|
||||
struct ril_modem *md;
|
||||
struct ril_sim_info *info;
|
||||
DBusConnection *conn;
|
||||
char *path;
|
||||
gulong handler_id[SIM_INFO_EVENT_COUNT];
|
||||
};
|
||||
|
||||
#define RIL_SIM_INFO_DBUS_INTERFACE "org.nemomobile.ofono.SimInfo"
|
||||
#define RIL_SIM_INFO_DBUS_INTERFACE_VERSION (1)
|
||||
|
||||
#define RIL_SIM_INFO_DBUS_ICCID_CHANGED_SIGNAL "CardIdentifierChanged"
|
||||
#define RIL_SIM_INFO_DBUS_IMSI_CHANGED_SIGNAL "SubscriberIdentityChanged"
|
||||
#define RIL_SIM_INFO_DBUS_SPN_CHANGED_SIGNAL "ServiceProviderNameChanged"
|
||||
|
||||
static void ril_sim_info_dbus_append_string(DBusMessageIter *it, const char *s)
|
||||
{
|
||||
if (!s) s = "";
|
||||
dbus_message_iter_append_basic(it, DBUS_TYPE_STRING, &s);
|
||||
}
|
||||
|
||||
static DBusMessage *ril_sim_info_dbus_reply_with_string(DBusMessage *msg,
|
||||
const char *str)
|
||||
{
|
||||
DBusMessage *reply = dbus_message_new_method_return(msg);
|
||||
DBusMessageIter iter;
|
||||
|
||||
dbus_message_iter_init_append(reply, &iter);
|
||||
ril_sim_info_dbus_append_string(&iter, str);
|
||||
return reply;
|
||||
}
|
||||
|
||||
static DBusMessage *ril_sim_info_dbus_get_all(DBusConnection *conn,
|
||||
DBusMessage *msg, void *data)
|
||||
{
|
||||
struct ril_sim_info_dbus *dbus = data;
|
||||
struct ril_sim_info *info = dbus->info;
|
||||
DBusMessage *reply = dbus_message_new_method_return(msg);
|
||||
const dbus_int32_t version = RIL_SIM_INFO_DBUS_INTERFACE_VERSION;
|
||||
DBusMessageIter iter;
|
||||
|
||||
dbus_message_iter_init_append(reply, &iter);
|
||||
dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &version);
|
||||
ril_sim_info_dbus_append_string(&iter, info->iccid);
|
||||
ril_sim_info_dbus_append_string(&iter, info->imsi);
|
||||
ril_sim_info_dbus_append_string(&iter, info->spn);
|
||||
return reply;
|
||||
}
|
||||
|
||||
static DBusMessage *ril_sim_info_dbus_get_version(DBusConnection *dc,
|
||||
DBusMessage *msg, void *data)
|
||||
{
|
||||
DBusMessage *reply = dbus_message_new_method_return(msg);
|
||||
dbus_int32_t version = RIL_SIM_INFO_DBUS_INTERFACE_VERSION;
|
||||
DBusMessageIter iter;
|
||||
|
||||
dbus_message_iter_init_append(reply, &iter);
|
||||
dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &version);
|
||||
return reply;
|
||||
}
|
||||
|
||||
static DBusMessage *ril_sim_info_dbus_get_iccid(DBusConnection *conn,
|
||||
DBusMessage *msg, void *data)
|
||||
{
|
||||
struct ril_sim_info_dbus *dbus = data;
|
||||
return ril_sim_info_dbus_reply_with_string(msg, dbus->info->iccid);
|
||||
}
|
||||
|
||||
static DBusMessage *ril_sim_info_dbus_get_imsi(DBusConnection *conn,
|
||||
DBusMessage *msg, void *data)
|
||||
{
|
||||
struct ril_sim_info_dbus *dbus = data;
|
||||
return ril_sim_info_dbus_reply_with_string(msg, dbus->info->imsi);
|
||||
}
|
||||
|
||||
static DBusMessage *ril_sim_info_dbus_get_spn(DBusConnection *conn,
|
||||
DBusMessage *msg, void *data)
|
||||
{
|
||||
struct ril_sim_info_dbus *dbus = data;
|
||||
return ril_sim_info_dbus_reply_with_string(msg, dbus->info->spn);
|
||||
}
|
||||
|
||||
static const GDBusMethodTable ril_sim_info_dbus_methods[] = {
|
||||
{ GDBUS_METHOD("GetAll",
|
||||
NULL, GDBUS_ARGS({"version", "i" },
|
||||
{"iccid", "s" },
|
||||
{"imsi", "s" },
|
||||
{"spn" , "s"}),
|
||||
ril_sim_info_dbus_get_all) },
|
||||
{ GDBUS_METHOD("GetInterfaceVersion",
|
||||
NULL, GDBUS_ARGS({ "version", "i" }),
|
||||
ril_sim_info_dbus_get_version) },
|
||||
{ GDBUS_METHOD("GetCardIdentifier",
|
||||
NULL, GDBUS_ARGS({ "iccid", "s" }),
|
||||
ril_sim_info_dbus_get_iccid) },
|
||||
{ GDBUS_METHOD("GetSubscriberIdentity",
|
||||
NULL, GDBUS_ARGS({ "imsi", "s" }),
|
||||
ril_sim_info_dbus_get_imsi) },
|
||||
{ GDBUS_METHOD("GetServiceProviderName",
|
||||
NULL, GDBUS_ARGS({ "spn", "s" }),
|
||||
ril_sim_info_dbus_get_spn) },
|
||||
{ }
|
||||
};
|
||||
|
||||
static const GDBusSignalTable ril_sim_info_dbus_signals[] = {
|
||||
{ GDBUS_SIGNAL(RIL_SIM_INFO_DBUS_ICCID_CHANGED_SIGNAL,
|
||||
GDBUS_ARGS({ "iccid", "s" })) },
|
||||
{ GDBUS_SIGNAL(RIL_SIM_INFO_DBUS_IMSI_CHANGED_SIGNAL,
|
||||
GDBUS_ARGS({ "imsi", "s" })) },
|
||||
{ GDBUS_SIGNAL(RIL_SIM_INFO_DBUS_SPN_CHANGED_SIGNAL,
|
||||
GDBUS_ARGS({ "spn", "s" })) },
|
||||
{ }
|
||||
};
|
||||
|
||||
static void ril_sim_info_dbus_emit(struct ril_sim_info_dbus *dbus,
|
||||
const char *signal, const char *value)
|
||||
{
|
||||
const char *arg = value;
|
||||
if (!arg) arg = "";
|
||||
g_dbus_emit_signal(dbus->conn, dbus->path, RIL_SIM_INFO_DBUS_INTERFACE,
|
||||
signal, DBUS_TYPE_STRING, &arg, DBUS_TYPE_INVALID);
|
||||
}
|
||||
|
||||
static void ril_sim_info_dbus_iccid_cb(struct ril_sim_info *info, void *arg)
|
||||
{
|
||||
struct ril_sim_info_dbus *dbus = arg;
|
||||
ril_sim_info_dbus_emit(dbus, RIL_SIM_INFO_DBUS_ICCID_CHANGED_SIGNAL,
|
||||
info->iccid);
|
||||
}
|
||||
|
||||
static void ril_sim_info_dbus_imsi_cb(struct ril_sim_info *info, void *arg)
|
||||
{
|
||||
struct ril_sim_info_dbus *dbus = arg;
|
||||
ril_sim_info_dbus_emit(dbus, RIL_SIM_INFO_DBUS_IMSI_CHANGED_SIGNAL,
|
||||
info->imsi);
|
||||
}
|
||||
|
||||
static void ril_sim_info_dbus_spn_cb(struct ril_sim_info *info, void *arg)
|
||||
{
|
||||
struct ril_sim_info_dbus *dbus = arg;
|
||||
ril_sim_info_dbus_emit(dbus, RIL_SIM_INFO_DBUS_SPN_CHANGED_SIGNAL,
|
||||
info->spn);
|
||||
}
|
||||
|
||||
struct ril_sim_info_dbus *ril_sim_info_dbus_new(struct ril_modem *md,
|
||||
struct ril_sim_info *info)
|
||||
{
|
||||
struct ril_sim_info_dbus *dbus = g_new0(struct ril_sim_info_dbus, 1);
|
||||
|
||||
DBG("%s", ril_modem_get_path(md));
|
||||
dbus->md = md;
|
||||
dbus->path = g_strdup(ril_modem_get_path(md));
|
||||
dbus->info = ril_sim_info_ref(info);
|
||||
dbus->conn = dbus_connection_ref(ofono_dbus_get_connection());
|
||||
|
||||
/* Register D-Bus interface */
|
||||
if (g_dbus_register_interface(dbus->conn, dbus->path,
|
||||
RIL_SIM_INFO_DBUS_INTERFACE, ril_sim_info_dbus_methods,
|
||||
ril_sim_info_dbus_signals, NULL, dbus, NULL)) {
|
||||
ofono_modem_add_interface(md->ofono,
|
||||
RIL_SIM_INFO_DBUS_INTERFACE);
|
||||
|
||||
dbus->handler_id[SIM_INFO_EVENT_ICCID] =
|
||||
ril_sim_info_add_iccid_changed_handler(info,
|
||||
ril_sim_info_dbus_iccid_cb, dbus);
|
||||
dbus->handler_id[SIM_INFO_EVENT_IMSI] =
|
||||
ril_sim_info_add_imsi_changed_handler(info,
|
||||
ril_sim_info_dbus_imsi_cb, dbus);
|
||||
dbus->handler_id[SIM_INFO_EVENT_SPN] =
|
||||
ril_sim_info_add_spn_changed_handler(info,
|
||||
ril_sim_info_dbus_spn_cb, dbus);
|
||||
|
||||
return dbus;
|
||||
} else {
|
||||
ofono_error("CellInfo D-Bus register failed");
|
||||
ril_sim_info_dbus_free(dbus);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void ril_sim_info_dbus_free(struct ril_sim_info_dbus *dbus)
|
||||
{
|
||||
if (dbus) {
|
||||
unsigned int i;
|
||||
|
||||
DBG("%s", dbus->path);
|
||||
g_dbus_unregister_interface(dbus->conn, dbus->path,
|
||||
RIL_SIM_INFO_DBUS_INTERFACE);
|
||||
ofono_modem_remove_interface(dbus->md->ofono,
|
||||
RIL_SIM_INFO_DBUS_INTERFACE);
|
||||
dbus_connection_unref(dbus->conn);
|
||||
|
||||
for (i=0; i<G_N_ELEMENTS(dbus->handler_id); i++) {
|
||||
ril_sim_info_remove_handler(dbus->info,
|
||||
dbus->handler_id[i]);
|
||||
}
|
||||
ril_sim_info_unref(dbus->info);
|
||||
|
||||
g_free(dbus->path);
|
||||
g_free(dbus);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2016 Jolla Ltd.
|
||||
* 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
|
||||
@@ -16,26 +16,31 @@
|
||||
#include "ril_sim_settings.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
#include "sailfish_watch.h"
|
||||
|
||||
#include <gutil_misc.h>
|
||||
|
||||
#include <ofono/sim.h>
|
||||
|
||||
#include "ofono.h"
|
||||
#include "storage.h"
|
||||
|
||||
#define RIL_SIM_STORE "ril"
|
||||
#define RIL_SIM_STORE_GROUP "Settings"
|
||||
#define RIL_SIM_STORE_PREF_MODE "TechnologyPreference"
|
||||
|
||||
#define RIL_SIM_STORE_PREF_MODE_DEFAULT(self) ((self)->enable_4g ? \
|
||||
OFONO_RADIO_ACCESS_MODE_LTE : OFONO_RADIO_ACCESS_MODE_UMTS)
|
||||
#define RIL_PREF_MODE_DEFAULT(self) (\
|
||||
((self)->techs & OFONO_RADIO_ACCESS_MODE_LTE) ? \
|
||||
OFONO_RADIO_ACCESS_MODE_LTE : \
|
||||
((self)->techs & OFONO_RADIO_ACCESS_MODE_UMTS) ? \
|
||||
OFONO_RADIO_ACCESS_MODE_UMTS : \
|
||||
OFONO_RADIO_ACCESS_MODE_GSM)
|
||||
|
||||
typedef GObjectClass RilSimSettingsClass;
|
||||
typedef struct ril_sim_settings RilSimSettings;
|
||||
|
||||
enum sailfish_watch_events {
|
||||
WATCH_EVENT_IMSI,
|
||||
WATCH_EVENT_COUNT
|
||||
};
|
||||
|
||||
struct ril_sim_settings_priv {
|
||||
struct ofono_sim *sim;
|
||||
guint imsi_watch_id;
|
||||
guint state_watch_id;
|
||||
gulong watch_event_id[WATCH_EVENT_COUNT];
|
||||
struct sailfish_watch *watch;
|
||||
GKeyFile *storage;
|
||||
char *imsi;
|
||||
};
|
||||
@@ -62,176 +67,77 @@ G_DEFINE_TYPE(RilSimSettings, ril_sim_settings, G_TYPE_OBJECT)
|
||||
G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_FIRST, \
|
||||
0, NULL, NULL, NULL, G_TYPE_NONE, 0)
|
||||
|
||||
/* Skip the leading slash from the modem path: */
|
||||
#define DBG_(obj,fmt,args...) DBG("%s " fmt, (obj)->path+1, ##args)
|
||||
|
||||
static void ril_sim_settings_signal_emit(struct ril_sim_settings *self,
|
||||
enum ril_sim_settings_signal id)
|
||||
{
|
||||
g_signal_emit(self, ril_sim_settings_signals[id], 0);
|
||||
}
|
||||
|
||||
static void ril_sim_settings_reload(struct ril_sim_settings *self)
|
||||
{
|
||||
struct ril_sim_settings_priv *priv = self->priv;
|
||||
|
||||
if (priv->storage) {
|
||||
g_key_file_free(priv->storage);
|
||||
priv->storage = NULL;
|
||||
}
|
||||
|
||||
if (priv->imsi) {
|
||||
char *mode_str;
|
||||
enum ofono_radio_access_mode mode;
|
||||
priv->storage = storage_open(priv->imsi, RIL_SIM_STORE);
|
||||
mode_str = g_key_file_get_string(priv->storage,
|
||||
RIL_SIM_STORE_GROUP, RIL_SIM_STORE_PREF_MODE, NULL);
|
||||
if (ofono_radio_access_mode_from_string(mode_str, &mode)) {
|
||||
if (!self->enable_4g &&
|
||||
mode == OFONO_RADIO_ACCESS_MODE_LTE) {
|
||||
mode = OFONO_RADIO_ACCESS_MODE_ANY;
|
||||
}
|
||||
} else {
|
||||
mode = OFONO_RADIO_ACCESS_MODE_ANY;
|
||||
}
|
||||
if (mode == OFONO_RADIO_ACCESS_MODE_ANY) {
|
||||
self->pref_mode = RIL_SIM_STORE_PREF_MODE_DEFAULT(self);
|
||||
} else {
|
||||
self->pref_mode = mode;
|
||||
}
|
||||
g_free(mode_str);
|
||||
}
|
||||
}
|
||||
|
||||
void ril_sim_settings_set_pref_mode(struct ril_sim_settings *self,
|
||||
enum ofono_radio_access_mode mode)
|
||||
{
|
||||
if (G_LIKELY(self) && self->pref_mode != mode) {
|
||||
struct ril_sim_settings_priv *priv = self->priv;
|
||||
const char *mode_str = ofono_radio_access_mode_to_string(mode);
|
||||
|
||||
GASSERT(priv->storage);
|
||||
if (mode_str) {
|
||||
if (priv->storage) {
|
||||
g_key_file_set_string(priv->storage,
|
||||
RIL_SIM_STORE_GROUP,
|
||||
RIL_SIM_STORE_PREF_MODE, mode_str);
|
||||
storage_sync(self->imsi, RIL_SIM_STORE,
|
||||
priv->storage);
|
||||
}
|
||||
self->pref_mode = mode;
|
||||
ril_sim_settings_signal_emit(self,
|
||||
SIGNAL_PREF_MODE_CHANGED);
|
||||
}
|
||||
self->pref_mode = mode;
|
||||
ril_sim_settings_signal_emit(self, SIGNAL_PREF_MODE_CHANGED);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_sim_settings_set_imsi(struct ril_sim_settings *self,
|
||||
const char *imsi)
|
||||
{
|
||||
struct ril_sim_settings_priv *priv = self->priv;
|
||||
if (g_strcmp0(priv->imsi, imsi)) {
|
||||
enum ofono_radio_access_mode prev_mode = self->pref_mode;
|
||||
g_free(priv->imsi);
|
||||
self->imsi = priv->imsi = g_strdup(imsi);
|
||||
ril_sim_settings_reload(self);
|
||||
ril_sim_settings_signal_emit(self, SIGNAL_IMSI_CHANGED);
|
||||
if (prev_mode != self->pref_mode) {
|
||||
ril_sim_settings_signal_emit(self,
|
||||
SIGNAL_PREF_MODE_CHANGED);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_sim_settings_imsi_watch_cb(const char *imsi, void *user_data)
|
||||
{
|
||||
ril_sim_settings_set_imsi(RIL_SIM_SETTINGS(user_data), imsi);
|
||||
}
|
||||
|
||||
static void ril_sim_settings_imsi_watch_done(void *user_data)
|
||||
{
|
||||
struct ril_sim_settings *self = RIL_SIM_SETTINGS(user_data);
|
||||
struct ril_sim_settings_priv *priv = self->priv;
|
||||
|
||||
GASSERT(priv->imsi_watch_id);
|
||||
priv->imsi_watch_id = 0;
|
||||
}
|
||||
|
||||
static void ril_sim_settings_state_check(struct ril_sim_settings *self,
|
||||
enum ofono_sim_state new_state)
|
||||
{
|
||||
if (new_state != OFONO_SIM_STATE_READY) {
|
||||
ril_sim_settings_set_imsi(self, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_sim_settings_state_watch(enum ofono_sim_state new_state,
|
||||
static void ril_sim_settings_imsi_changed(struct sailfish_watch *watch,
|
||||
void *user_data)
|
||||
{
|
||||
ril_sim_settings_state_check(RIL_SIM_SETTINGS(user_data), new_state);
|
||||
}
|
||||
|
||||
static void ril_sim_settings_state_watch_done(void *user_data)
|
||||
{
|
||||
struct ril_sim_settings *self = RIL_SIM_SETTINGS(user_data);
|
||||
struct ril_sim_settings_priv *priv = self->priv;
|
||||
|
||||
GASSERT(priv->state_watch_id);
|
||||
priv->state_watch_id = 0;
|
||||
}
|
||||
|
||||
void ril_sim_settings_set_ofono_sim(struct ril_sim_settings *self,
|
||||
struct ofono_sim *sim)
|
||||
{
|
||||
if (G_LIKELY(self)) {
|
||||
struct ril_sim_settings_priv *priv = self->priv;
|
||||
if (priv->sim != sim) {
|
||||
GASSERT(priv->sim || !priv->imsi_watch_id);
|
||||
if (priv->imsi_watch_id) {
|
||||
ofono_sim_remove_imsi_watch(priv->sim,
|
||||
priv->imsi_watch_id);
|
||||
/*
|
||||
* ril_sim_settings_imsi_watch_done
|
||||
* clears it
|
||||
*/
|
||||
GASSERT(!priv->imsi_watch_id);
|
||||
}
|
||||
if (priv->state_watch_id) {
|
||||
ofono_sim_remove_state_watch(priv->sim,
|
||||
priv->state_watch_id);
|
||||
/*
|
||||
* ril_sim_settings_state_watch_done
|
||||
* clears it
|
||||
*/
|
||||
GASSERT(!priv->state_watch_id);
|
||||
}
|
||||
priv->sim = sim;
|
||||
if (sim) {
|
||||
priv->state_watch_id =
|
||||
ofono_sim_add_state_watch(sim,
|
||||
ril_sim_settings_state_watch, self,
|
||||
ril_sim_settings_state_watch_done);
|
||||
GASSERT(priv->state_watch_id);
|
||||
ril_sim_settings_state_check(self,
|
||||
ofono_sim_get_state(sim));
|
||||
/*
|
||||
* ofono_sim_add_imsi_watch immediately
|
||||
* calls the event callback if IMSI is
|
||||
* already known. It's useless though
|
||||
* because we still have to check the
|
||||
* current state in case if IMSI is not
|
||||
* available yet.
|
||||
*/
|
||||
priv->imsi_watch_id =
|
||||
ofono_sim_add_imsi_watch(priv->sim,
|
||||
ril_sim_settings_imsi_watch_cb, self,
|
||||
ril_sim_settings_imsi_watch_done);
|
||||
GASSERT(priv->state_watch_id);
|
||||
}
|
||||
/* Luckily, ofono_sim_get_imsi handles NULL pointer */
|
||||
ril_sim_settings_set_imsi(self,
|
||||
ofono_sim_get_imsi(sim));
|
||||
}
|
||||
if (g_strcmp0(priv->imsi, watch->imsi)) {
|
||||
g_free(priv->imsi);
|
||||
self->imsi = priv->imsi = g_strdup(watch->imsi);
|
||||
ril_sim_settings_signal_emit(self, SIGNAL_IMSI_CHANGED);
|
||||
}
|
||||
}
|
||||
|
||||
struct ril_sim_settings *ril_sim_settings_new(const char *path,
|
||||
enum ofono_radio_access_mode techs)
|
||||
{
|
||||
struct ril_sim_settings *self = NULL;
|
||||
|
||||
if (G_LIKELY(path)) {
|
||||
struct ril_sim_settings_priv *priv;
|
||||
|
||||
self = g_object_new(RIL_SIM_SETTINGS_TYPE, NULL);
|
||||
priv = self->priv;
|
||||
self->techs = techs;
|
||||
self->pref_mode = RIL_PREF_MODE_DEFAULT(self);
|
||||
priv->watch = sailfish_watch_new(path);
|
||||
priv->watch_event_id[WATCH_EVENT_IMSI] =
|
||||
sailfish_watch_add_imsi_changed_handler(priv->watch,
|
||||
ril_sim_settings_imsi_changed, self);
|
||||
self->imsi = priv->imsi = g_strdup(priv->watch->imsi);
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
struct ril_sim_settings *ril_sim_settings_ref(struct ril_sim_settings *self)
|
||||
{
|
||||
if (G_LIKELY(self)) {
|
||||
g_object_ref(RIL_SIM_SETTINGS(self));
|
||||
return self;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void ril_sim_settings_unref(struct ril_sim_settings *self)
|
||||
{
|
||||
if (G_LIKELY(self)) {
|
||||
g_object_unref(RIL_SIM_SETTINGS(self));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
gulong ril_sim_settings_add_imsi_changed_handler(struct ril_sim_settings *self,
|
||||
ril_sim_settings_cb_t cb, void *arg)
|
||||
{
|
||||
@@ -260,51 +166,26 @@ void ril_sim_settings_remove_handlers(struct ril_sim_settings *self,
|
||||
gutil_disconnect_handlers(self, ids, count);
|
||||
}
|
||||
|
||||
struct ril_sim_settings *ril_sim_settings_new(const struct ril_slot_config *sc)
|
||||
{
|
||||
struct ril_sim_settings *self = g_object_new(RIL_SIM_SETTINGS_TYPE, 0);
|
||||
self->enable_4g = sc->enable_4g;
|
||||
self->slot = sc->slot;
|
||||
self->pref_mode = RIL_SIM_STORE_PREF_MODE_DEFAULT(self);
|
||||
return self;
|
||||
}
|
||||
|
||||
struct ril_sim_settings *ril_sim_settings_ref(struct ril_sim_settings *self)
|
||||
{
|
||||
if (G_LIKELY(self)) {
|
||||
g_object_ref(RIL_SIM_SETTINGS(self));
|
||||
return self;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void ril_sim_settings_unref(struct ril_sim_settings *self)
|
||||
{
|
||||
if (G_LIKELY(self)) {
|
||||
g_object_unref(RIL_SIM_SETTINGS(self));
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_sim_settings_init(struct ril_sim_settings *self)
|
||||
{
|
||||
self->priv = G_TYPE_INSTANCE_GET_PRIVATE(self, RIL_SIM_SETTINGS_TYPE,
|
||||
struct ril_sim_settings_priv);
|
||||
}
|
||||
|
||||
static void ril_sim_settings_dispose(GObject *object)
|
||||
static void ril_sim_settings_finalize(GObject *object)
|
||||
{
|
||||
struct ril_sim_settings *self = RIL_SIM_SETTINGS(object);
|
||||
struct ril_sim_settings_priv *priv = self->priv;
|
||||
|
||||
ril_sim_settings_set_ofono_sim(self, NULL);
|
||||
G_OBJECT_CLASS(ril_sim_settings_parent_class)->dispose(object);
|
||||
sailfish_watch_remove_all_handlers(priv->watch, priv->watch_event_id);
|
||||
sailfish_watch_unref(priv->watch);
|
||||
g_free(priv->imsi);
|
||||
G_OBJECT_CLASS(ril_sim_settings_parent_class)->finalize(object);
|
||||
}
|
||||
|
||||
static void ril_sim_settings_class_init(RilSimSettingsClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS(klass);
|
||||
|
||||
object_class->dispose = ril_sim_settings_dispose;
|
||||
G_OBJECT_CLASS(klass)->finalize = ril_sim_settings_finalize;
|
||||
g_type_class_add_private(klass, sizeof(struct ril_sim_settings_priv));
|
||||
NEW_SIGNAL(klass, IMSI);
|
||||
NEW_SIGNAL(klass, PREF_MODE);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2016 Jolla Ltd.
|
||||
* 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
|
||||
@@ -18,22 +18,20 @@
|
||||
|
||||
#include "ril_types.h"
|
||||
|
||||
#include <ofono/radio-settings.h>
|
||||
|
||||
struct ril_sim_settings_priv;
|
||||
|
||||
struct ril_sim_settings {
|
||||
GObject object;
|
||||
struct ril_sim_settings_priv *priv;
|
||||
gboolean enable_4g;
|
||||
guint slot;
|
||||
const char *imsi;
|
||||
enum ofono_radio_access_mode techs;
|
||||
enum ofono_radio_access_mode pref_mode;
|
||||
};
|
||||
|
||||
typedef void (*ril_sim_settings_cb_t)(struct ril_sim_settings *s, void *arg);
|
||||
|
||||
struct ril_sim_settings *ril_sim_settings_new(const struct ril_slot_config *sc);
|
||||
struct ril_sim_settings *ril_sim_settings_new(const char *path,
|
||||
enum ofono_radio_access_mode techs);
|
||||
struct ril_sim_settings *ril_sim_settings_ref(struct ril_sim_settings *s);
|
||||
void ril_sim_settings_unref(struct ril_sim_settings *s);
|
||||
void ril_sim_settings_set_ofono_sim(struct ril_sim_settings *s,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2016 Jolla Ltd.
|
||||
* Copyright (C) 2015-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
|
||||
@@ -14,7 +14,6 @@
|
||||
*/
|
||||
|
||||
#include "ril_plugin.h"
|
||||
#include "ril_constants.h"
|
||||
#include "ril_util.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
@@ -255,8 +254,9 @@ static void ril_sms_submit(struct ofono_sms *sms, const unsigned char *pdu,
|
||||
|
||||
DBG("%s", tpdu);
|
||||
grilio_queue_send_request_full(sd->q, req,
|
||||
RIL_REQUEST_SEND_SMS, ril_sms_submit_cb,
|
||||
ril_sms_cbd_free, ril_sms_cbd_new(sd, cb, data));
|
||||
mms ? RIL_REQUEST_SEND_SMS_EXPECT_MORE : RIL_REQUEST_SEND_SMS,
|
||||
ril_sms_submit_cb, ril_sms_cbd_free,
|
||||
ril_sms_cbd_new(sd, cb, data));
|
||||
grilio_request_unref(req);
|
||||
g_free(tpdu);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015 Jolla Ltd.
|
||||
* Copyright (C) 2015-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
|
||||
@@ -16,7 +16,6 @@
|
||||
#include "ril_plugin.h"
|
||||
#include "ril_util.h"
|
||||
#include "ril_log.h"
|
||||
#include "ril_constants.h"
|
||||
|
||||
#include "util.h"
|
||||
|
||||
|
||||
@@ -21,6 +21,13 @@
|
||||
#
|
||||
#EmptyConfig=false
|
||||
|
||||
# User and group for the ofono process. RIL clients are typically
|
||||
# expected to run under radio:radio.
|
||||
#
|
||||
# Default is radio:radio
|
||||
#
|
||||
#Identity=radio:radio
|
||||
|
||||
# If the phone has more than one SIM slot, the 3G/LTE module may be
|
||||
# shared by all modems, meaning that only one of the slots can use
|
||||
# 3G/LTE. In order to "hand 4G over" to the other slot, the modem
|
||||
@@ -35,6 +42,17 @@
|
||||
#
|
||||
#3GLTEHandover=true
|
||||
|
||||
# RIL_REQUEST_SET_RADIO_CAPABILITY may or may not be supported by your RIL.
|
||||
# This option allows you to forcibly enable or disable use of this request.
|
||||
# It's involved in 3G/LTE handover between the modems, meaning that it only
|
||||
# makes sense if you have more than one slot.
|
||||
#
|
||||
# Possible values are auto, on and off
|
||||
#
|
||||
# Default is auto (enable for RIL version >= 11)
|
||||
#
|
||||
#SetRadioCapability=auto
|
||||
|
||||
[ril_0]
|
||||
|
||||
# Required entry, defines the RIL socket path
|
||||
@@ -67,9 +85,15 @@ socket=/dev/socket/rild
|
||||
#
|
||||
#timeout=0
|
||||
|
||||
# Setting this one to false would disable 4G technology selection.
|
||||
# Comma-separated list of radio technologies supported by the modem.
|
||||
# Valid technologies are "gsm", "umts" and "lte". The special value
|
||||
# "all" means that all technologies are supported.
|
||||
#
|
||||
# By default 4G is enabled
|
||||
# The default is all
|
||||
#
|
||||
#technologies=all
|
||||
|
||||
# This one is deprecated, use the technologies entry instead (above).
|
||||
#
|
||||
#enable4G=true
|
||||
|
||||
@@ -100,7 +124,7 @@ socket=/dev/socket/rild
|
||||
# This option allows you to forcibly enable or disable use of this request.
|
||||
# Possible values are auto, on and off
|
||||
#
|
||||
# Default is auto (usage based on the RIL version)
|
||||
# Default is auto (enable for RIL version >= 11)
|
||||
#
|
||||
#allowDataReq=auto
|
||||
|
||||
@@ -142,3 +166,31 @@ socket=/dev/socket/rild
|
||||
# Default is 200 ms
|
||||
#
|
||||
#dataCallRetryDelay=200
|
||||
|
||||
# Additional local and remote hangup reasons. Remote reasons are checked
|
||||
# first. Normally, RIL plugin figures it out automatically. You would only
|
||||
# need to define these if your RIL does something unusual.
|
||||
#
|
||||
# No default
|
||||
#
|
||||
#remoteHangupReasons=20
|
||||
#localHangupReasons=23
|
||||
|
||||
# Voice call support. Some devices like USB modems and tablets don't support
|
||||
# voice calls. By default, voice calls are enabled and this option allows you
|
||||
# to disable voice call handling.
|
||||
#
|
||||
# Default true
|
||||
#
|
||||
#enableVoicecall=true
|
||||
|
||||
# Timeout for the modem to show up, in milliseconds. Those that don't
|
||||
# show up before this timeout expires, will be dropped (ignored).
|
||||
#
|
||||
# In some fairly rare cases it makes sense to shorten this timeout for
|
||||
# optional modems (which may or may not be available), to speed up the
|
||||
# boot up process.
|
||||
#
|
||||
# The default is 20000 (20 seconds)
|
||||
#
|
||||
#startTimeout=20000
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2016 Jolla Ltd.
|
||||
* Copyright (C) 2015-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
|
||||
@@ -23,11 +23,12 @@
|
||||
#include <grilio_types.h>
|
||||
#include <gutil_macros.h>
|
||||
|
||||
#include <ofono/types.h>
|
||||
|
||||
struct ofono_modem;
|
||||
struct ofono_sim;
|
||||
|
||||
#include <ofono/types.h>
|
||||
#include <ofono/radio-settings.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
@@ -39,20 +40,19 @@ struct ofono_sim;
|
||||
#define RIL_RETRY_SECS (2)
|
||||
#define RIL_RETRY_MS (RIL_RETRY_SECS*1000)
|
||||
|
||||
struct ril_mce;
|
||||
struct ril_data;
|
||||
struct ril_modem;
|
||||
struct ril_radio;
|
||||
struct ril_network;
|
||||
struct ril_sim_card;
|
||||
struct ril_sim_info;
|
||||
struct ril_sim_settings;
|
||||
struct ril_cell_info;
|
||||
|
||||
struct ril_slot_config {
|
||||
guint slot;
|
||||
gboolean enable_4g;
|
||||
enum ofono_radio_access_mode techs;
|
||||
gboolean empty_pin_query;
|
||||
gboolean enable_voicecall;
|
||||
GUtilInts *local_hangup_reasons;
|
||||
GUtilInts *remote_hangup_reasons;
|
||||
};
|
||||
|
||||
#endif /* RIL_TYPES_H */
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2016 Jolla Ltd.
|
||||
* Copyright (C) 2015-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
|
||||
@@ -16,7 +16,6 @@
|
||||
#include "ril_plugin.h"
|
||||
#include "ril_util.h"
|
||||
#include "ril_log.h"
|
||||
#include "ril_constants.h"
|
||||
|
||||
#include "smsutil.h"
|
||||
#include "util.h"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2016 Jolla Ltd.
|
||||
* Copyright (C) 2015-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
|
||||
@@ -20,6 +20,8 @@
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "netreg.h"
|
||||
@@ -48,7 +50,8 @@ const char *ril_error_to_string(int error)
|
||||
RIL_E_(MODE_NOT_SUPPORTED);
|
||||
RIL_E_(FDN_CHECK_FAILURE);
|
||||
RIL_E_(ILLEGAL_SIM_OR_ME);
|
||||
RIL_E_(UNUSED);
|
||||
RIL_E_(MISSING_RESOURCE);
|
||||
RIL_E_(NO_SUCH_ELEMENT);
|
||||
RIL_E_(DIAL_MODIFIED_TO_USSD);
|
||||
RIL_E_(DIAL_MODIFIED_TO_SS);
|
||||
RIL_E_(DIAL_MODIFIED_TO_DIAL);
|
||||
@@ -57,11 +60,39 @@ const char *ril_error_to_string(int error)
|
||||
RIL_E_(USSD_MODIFIED_TO_USSD);
|
||||
RIL_E_(SS_MODIFIED_TO_DIAL);
|
||||
RIL_E_(SS_MODIFIED_TO_USSD);
|
||||
RIL_E_(SS_MODIFIED_TO_SS);
|
||||
RIL_E_(SUBSCRIPTION_NOT_SUPPORTED);
|
||||
RIL_E_(MISSING_RESOURCE);
|
||||
RIL_E_(NO_SUCH_ELEMENT);
|
||||
RIL_E_(INVALID_PARAMETER);
|
||||
RIL_E_(SS_MODIFIED_TO_SS);
|
||||
RIL_E_(LCE_NOT_SUPPORTED);
|
||||
RIL_E_(NO_MEMORY);
|
||||
RIL_E_(INTERNAL_ERR);
|
||||
RIL_E_(SYSTEM_ERR);
|
||||
RIL_E_(MODEM_ERR);
|
||||
RIL_E_(INVALID_STATE);
|
||||
RIL_E_(NO_RESOURCES);
|
||||
RIL_E_(SIM_ERR);
|
||||
RIL_E_(INVALID_ARGUMENTS);
|
||||
RIL_E_(INVALID_SIM_STATE);
|
||||
RIL_E_(INVALID_MODEM_STATE);
|
||||
RIL_E_(INVALID_CALL_ID);
|
||||
RIL_E_(NO_SMS_TO_ACK);
|
||||
RIL_E_(NETWORK_ERR);
|
||||
RIL_E_(REQUEST_RATE_LIMITED);
|
||||
RIL_E_(SIM_BUSY);
|
||||
RIL_E_(SIM_FULL);
|
||||
RIL_E_(NETWORK_REJECT);
|
||||
RIL_E_(OPERATION_NOT_ALLOWED);
|
||||
RIL_E_(EMPTY_RECORD);
|
||||
RIL_E_(INVALID_SMS_FORMAT);
|
||||
RIL_E_(ENCODING_ERR);
|
||||
RIL_E_(INVALID_SMSC_ADDRESS);
|
||||
RIL_E_(NO_SUCH_ENTRY);
|
||||
RIL_E_(NETWORK_NOT_READY);
|
||||
RIL_E_(NOT_PROVISIONED);
|
||||
RIL_E_(NO_SUBSCRIPTION);
|
||||
RIL_E_(NO_NETWORK_FOUND);
|
||||
RIL_E_(DEVICE_IN_USE);
|
||||
RIL_E_(ABORTED);
|
||||
RIL_E_(INVALID_RESPONSE);
|
||||
default:
|
||||
snprintf(unknown, sizeof(unknown), "%d", error);
|
||||
return unknown;
|
||||
@@ -204,6 +235,8 @@ const char *ril_request_to_string(guint request)
|
||||
RIL_REQUEST_(SHUTDOWN);
|
||||
RIL_REQUEST_(GET_RADIO_CAPABILITY);
|
||||
RIL_REQUEST_(SET_RADIO_CAPABILITY);
|
||||
case RIL_RESPONSE_ACKNOWLEDGEMENT:
|
||||
return "RESPONSE_ACK";
|
||||
default:
|
||||
snprintf(unknown, sizeof(unknown), "RIL_REQUEST_%d", request);
|
||||
return unknown;
|
||||
@@ -293,8 +326,7 @@ int ril_parse_tech(const char *stech, int *ril_tech)
|
||||
{
|
||||
int access_tech = -1;
|
||||
int tech = -1;
|
||||
if (stech && stech[0]) {
|
||||
tech = atoi(stech);
|
||||
if (ril_parse_int(stech, 0, &tech)) {
|
||||
switch (tech) {
|
||||
case RADIO_TECH_GPRS:
|
||||
case RADIO_TECH_GSM:
|
||||
@@ -351,8 +383,8 @@ gboolean ril_parse_mcc_mnc(const char *str, struct ofono_network_operator *op)
|
||||
|
||||
if (i == OFONO_MAX_MCC_LENGTH) {
|
||||
/* Usually 2 but sometimes 3 digit network code */
|
||||
for (i=0;
|
||||
i<OFONO_MAX_MNC_LENGTH && *ptr && isdigit(*ptr);
|
||||
for (i = 0;
|
||||
i < OFONO_MAX_MNC_LENGTH && *ptr && isdigit(*ptr);
|
||||
i++) {
|
||||
op->mnc[i] = *ptr++;
|
||||
}
|
||||
@@ -379,6 +411,26 @@ gboolean ril_parse_mcc_mnc(const char *str, struct ofono_network_operator *op)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gboolean ril_parse_int(const char *str, int base, int *value)
|
||||
{
|
||||
gboolean ok = FALSE;
|
||||
|
||||
if (str && str[0]) {
|
||||
char *str2 = g_strstrip(g_strdup(str));
|
||||
char *end = str2;
|
||||
long l;
|
||||
|
||||
errno = 0;
|
||||
l = strtol(str2, &end, base);
|
||||
ok = !*end && errno != ERANGE && l >= INT_MIN && l <= INT_MAX;
|
||||
if (ok && value) {
|
||||
*value = (int)l;
|
||||
}
|
||||
g_free(str2);
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2016 Jolla Ltd.
|
||||
* Copyright (C) 2015-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
|
||||
@@ -26,6 +26,7 @@ const char *ril_unsol_event_to_string(guint event);
|
||||
const char *ril_radio_state_to_string(int radio_state);
|
||||
int ril_parse_tech(const char *stech, int *ril_tech);
|
||||
gboolean ril_parse_mcc_mnc(const char *str, struct ofono_network_operator *op);
|
||||
gboolean ril_parse_int(const char *str, int base, int *value);
|
||||
|
||||
#define ril_error_init_ok(err) \
|
||||
((err)->error = 0, (err)->type = OFONO_ERROR_TYPE_NO_ERROR)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2015-2016 Jolla Ltd.
|
||||
* Copyright (C) 2015-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
|
||||
@@ -14,17 +14,21 @@
|
||||
*/
|
||||
|
||||
#include "ril_plugin.h"
|
||||
#include "ril_constants.h"
|
||||
#include "ril_ecclist.h"
|
||||
#include "ril_util.h"
|
||||
#include "ril_log.h"
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#include <gutil_ints.h>
|
||||
#include <gutil_ring.h>
|
||||
#include <gutil_idlequeue.h>
|
||||
#include <gutil_intarray.h>
|
||||
|
||||
#define FLAG_NEED_CLIP 1
|
||||
|
||||
#define VOICECALL_BLOCK_TIMEOUT_MS (5*1000)
|
||||
|
||||
enum ril_voicecall_events {
|
||||
VOICECALL_EVENT_CALL_STATE_CHANGED,
|
||||
VOICECALL_EVENT_SUPP_SVC_NOTIFICATION,
|
||||
@@ -38,12 +42,14 @@ struct ril_voicecall {
|
||||
GRilIoQueue *q;
|
||||
struct ofono_voicecall *vc;
|
||||
struct ril_ecclist *ecclist;
|
||||
unsigned int local_release;
|
||||
unsigned char flags;
|
||||
ofono_voicecall_cb_t cb;
|
||||
void *data;
|
||||
guint timer_id;
|
||||
GUtilRing* dtmf_queue;
|
||||
GUtilIntArray *local_release_ids;
|
||||
GUtilIdleQueue *idleq;
|
||||
GUtilRing *dtmf_queue;
|
||||
GUtilInts *local_hangup_reasons;
|
||||
GUtilInts *remote_hangup_reasons;
|
||||
guint send_dtmf_id;
|
||||
guint clcc_poll_id;
|
||||
gulong event_id[VOICECALL_EVENT_COUNT];
|
||||
@@ -52,35 +58,48 @@ struct ril_voicecall {
|
||||
gulong ecclist_change_id;
|
||||
};
|
||||
|
||||
struct ril_voicecall_change_state_req {
|
||||
struct ril_voicecall_request_data {
|
||||
int ref_count;
|
||||
int pending_call_count;
|
||||
int success;
|
||||
struct ofono_voicecall *vc;
|
||||
ofono_voicecall_cb_t cb;
|
||||
gpointer data;
|
||||
int affected_types;
|
||||
};
|
||||
|
||||
struct lastcause_req {
|
||||
struct ofono_voicecall *vc;
|
||||
struct ril_voicecall *vd;
|
||||
int id;
|
||||
};
|
||||
|
||||
static void ril_voicecall_send_one_dtmf(struct ril_voicecall *vd);
|
||||
static void ril_voicecall_clear_dtmf_queue(struct ril_voicecall *vd);
|
||||
|
||||
/*
|
||||
* structs ofono_voicecall and voicecall are fully defined
|
||||
* in src/voicecall.c; we need (read) access to the
|
||||
* call objects, so partially redefine them here.
|
||||
*/
|
||||
struct ofono_voicecall {
|
||||
GSList *call_list;
|
||||
/* ... */
|
||||
};
|
||||
struct ril_voicecall_request_data *ril_voicecall_request_data_new
|
||||
(struct ofono_voicecall *vc, ofono_voicecall_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_voicecall_request_data *req =
|
||||
g_slice_new0(struct ril_voicecall_request_data);
|
||||
|
||||
struct voicecall {
|
||||
struct ofono_call *call;
|
||||
/* ... */
|
||||
};
|
||||
req->ref_count = 1;
|
||||
req->vc = vc;
|
||||
req->cb = cb;
|
||||
req->data = data;
|
||||
return req;
|
||||
}
|
||||
|
||||
static void ril_voicecall_request_data_unref
|
||||
(struct ril_voicecall_request_data *req)
|
||||
{
|
||||
if (!--req->ref_count) {
|
||||
g_slice_free(struct ril_voicecall_request_data, req);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_voicecall_request_data_free(gpointer data)
|
||||
{
|
||||
ril_voicecall_request_data_unref(data);
|
||||
}
|
||||
|
||||
static inline struct ril_voicecall *ril_voicecall_get_data(
|
||||
struct ofono_voicecall *vc)
|
||||
@@ -166,38 +185,76 @@ static GSList *ril_voicecall_parse_clcc(const void *data, guint len)
|
||||
}
|
||||
|
||||
/* Valid call statuses have value >= 0 */
|
||||
static int call_status_with_id(struct ofono_voicecall *vc, int id)
|
||||
static int ril_voicecall_status_with_id(struct ofono_voicecall *vc,
|
||||
unsigned int id)
|
||||
{
|
||||
GSList *l;
|
||||
struct voicecall *v;
|
||||
struct ofono_call *call = ofono_voicecall_find_call(vc, id);
|
||||
|
||||
GASSERT(vc);
|
||||
return call ? call->status : -1;
|
||||
}
|
||||
|
||||
for (l = vc->call_list; l; l = l->next) {
|
||||
v = l->data;
|
||||
if (v->call->id == id) {
|
||||
return v->call->status;
|
||||
/* Tries to parse the payload as a uint followed by a string */
|
||||
static int ril_voicecall_parse_lastcause_1(const void *data, guint len)
|
||||
{
|
||||
int result = -1;
|
||||
|
||||
if (len > 8) {
|
||||
int code;
|
||||
char *msg = NULL;
|
||||
GRilIoParser rilp;
|
||||
|
||||
grilio_parser_init(&rilp, data, len);
|
||||
if (grilio_parser_get_int32(&rilp, &code) && code >= 0 &&
|
||||
(msg = grilio_parser_get_utf8(&rilp)) &&
|
||||
grilio_parser_at_end(&rilp)) {
|
||||
DBG("%d \"%s\"", code, msg);
|
||||
result = code;
|
||||
}
|
||||
g_free(msg);
|
||||
}
|
||||
|
||||
return -1;
|
||||
return result;
|
||||
}
|
||||
|
||||
static void ril_voicecall_lastcause_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct lastcause_req *reqdata = user_data;
|
||||
struct ofono_voicecall *vc = reqdata->vc;
|
||||
int tmp;
|
||||
struct ril_voicecall *vd = reqdata->vd;
|
||||
struct ofono_voicecall *vc = vd->vc;
|
||||
int id = reqdata->id;
|
||||
int call_status;
|
||||
|
||||
enum ofono_disconnect_reason reason = OFONO_DISCONNECT_REASON_ERROR;
|
||||
int last_cause = CALL_FAIL_ERROR_UNSPECIFIED;
|
||||
GRilIoParser rilp;
|
||||
grilio_parser_init(&rilp, data, len);
|
||||
if (grilio_parser_get_int32(&rilp, &tmp) && tmp > 0) {
|
||||
grilio_parser_get_int32(&rilp, &last_cause);
|
||||
int last_cause;
|
||||
|
||||
/*
|
||||
* According to ril.h:
|
||||
*
|
||||
* "response" is a "int *"
|
||||
* ((int *)response)[0] is RIL_LastCallFailCause. GSM failure
|
||||
* reasons are mapped to cause codes defined in TS 24.008 Annex H
|
||||
* where possible.
|
||||
*
|
||||
* However some RILs feel free to invent their own formats,
|
||||
* try those first.
|
||||
*/
|
||||
|
||||
last_cause = ril_voicecall_parse_lastcause_1(data, len);
|
||||
if (last_cause < 0) {
|
||||
GRilIoParser rilp;
|
||||
int num, code;
|
||||
|
||||
/* Default format described in ril.h */
|
||||
grilio_parser_init(&rilp, data, len);
|
||||
if (grilio_parser_get_int32(&rilp, &num) && num == 1 &&
|
||||
grilio_parser_get_int32(&rilp, &code) &&
|
||||
grilio_parser_at_end(&rilp)) {
|
||||
last_cause = code;
|
||||
} else {
|
||||
ofono_warn("Unable to parse last call fail cause");
|
||||
last_cause = CALL_FAIL_ERROR_UNSPECIFIED;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -208,7 +265,14 @@ static void ril_voicecall_lastcause_cb(GRilIoChannel *io, int status,
|
||||
* CALL_FAIL_ERROR_UNSPECIFIED, and thus indistinguishable
|
||||
* from a network failure.
|
||||
*/
|
||||
switch (last_cause) {
|
||||
if (gutil_ints_contains(vd->remote_hangup_reasons, last_cause)) {
|
||||
DBG("hangup cause %d => remote hangup", last_cause);
|
||||
reason = OFONO_DISCONNECT_REASON_REMOTE_HANGUP;
|
||||
} else if (gutil_ints_contains(vd->local_hangup_reasons, last_cause)) {
|
||||
DBG("hangup cause %d => local hangup", last_cause);
|
||||
reason = OFONO_DISCONNECT_REASON_LOCAL_HANGUP;
|
||||
} else {
|
||||
switch (last_cause) {
|
||||
case CALL_FAIL_UNOBTAINABLE_NUMBER:
|
||||
case CALL_FAIL_NORMAL:
|
||||
case CALL_FAIL_BUSY:
|
||||
@@ -216,19 +280,19 @@ static void ril_voicecall_lastcause_cb(GRilIoChannel *io, int status,
|
||||
case CALL_FAIL_CHANNEL_UNACCEPTABLE:
|
||||
case CALL_FAIL_OPERATOR_DETERMINED_BARRING:
|
||||
case CALL_FAIL_NO_USER_RESPONDING:
|
||||
case CALL_FAIL_USER_ALERTING_NO_ANSWER:
|
||||
case CALL_FAIL_NO_ANSWER_FROM_USER:
|
||||
case CALL_FAIL_CALL_REJECTED:
|
||||
case CALL_FAIL_NUMBER_CHANGED:
|
||||
case CALL_FAIL_ANONYMOUS_CALL_REJECTION:
|
||||
case CALL_FAIL_PRE_EMPTION:
|
||||
case CALL_FAIL_DESTINATION_OUT_OF_ORDER:
|
||||
case CALL_FAIL_INCOMPLETE_NUMBER:
|
||||
case CALL_FAIL_INVALID_NUMBER_FORMAT:
|
||||
case CALL_FAIL_FACILITY_REJECTED:
|
||||
reason = OFONO_DISCONNECT_REASON_REMOTE_HANGUP;
|
||||
break;
|
||||
|
||||
case CALL_FAIL_NORMAL_UNSPECIFIED:
|
||||
call_status = call_status_with_id(vc, id);
|
||||
call_status = ril_voicecall_status_with_id(vc, id);
|
||||
if (call_status == CALL_STATUS_ACTIVE ||
|
||||
call_status == CALL_STATUS_HELD ||
|
||||
call_status == CALL_STATUS_DIALING ||
|
||||
@@ -240,9 +304,10 @@ static void ril_voicecall_lastcause_cb(GRilIoChannel *io, int status,
|
||||
break;
|
||||
|
||||
case CALL_FAIL_ERROR_UNSPECIFIED:
|
||||
call_status = call_status_with_id(vc, id);
|
||||
call_status = ril_voicecall_status_with_id(vc, id);
|
||||
if (call_status == CALL_STATUS_DIALING ||
|
||||
call_status == CALL_STATUS_ALERTING) {
|
||||
call_status == CALL_STATUS_ALERTING ||
|
||||
call_status == CALL_STATUS_INCOMING) {
|
||||
reason = OFONO_DISCONNECT_REASON_REMOTE_HANGUP;
|
||||
}
|
||||
break;
|
||||
@@ -250,6 +315,7 @@ static void ril_voicecall_lastcause_cb(GRilIoChannel *io, int status,
|
||||
default:
|
||||
reason = OFONO_DISCONNECT_REASON_ERROR;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ofono_info("Call %d ended with RIL cause %d -> ofono reason %d",
|
||||
@@ -285,7 +351,9 @@ static void ril_voicecall_clcc_poll_cb(GRilIoChannel *io, int status,
|
||||
struct ofono_call *oc = o ? o->data : NULL;
|
||||
|
||||
if (oc && (nc == NULL || (nc->id > oc->id))) {
|
||||
if (vd->local_release & (1 << oc->id)) {
|
||||
/* old call is gone */
|
||||
if (gutil_int_array_remove_all_fast(
|
||||
vd->local_release_ids, oc->id)) {
|
||||
ofono_voicecall_disconnected(vd->vc, oc->id,
|
||||
OFONO_DISCONNECT_REASON_LOCAL_HANGUP,
|
||||
NULL);
|
||||
@@ -295,7 +363,7 @@ static void ril_voicecall_clcc_poll_cb(GRilIoChannel *io, int status,
|
||||
struct lastcause_req *reqdata =
|
||||
g_new0(struct lastcause_req, 1);
|
||||
|
||||
reqdata->vc = vd->vc;
|
||||
reqdata->vd = vd;
|
||||
reqdata->id = oc->id;
|
||||
grilio_queue_send_request_full(vd->q, NULL,
|
||||
RIL_REQUEST_LAST_CALL_FAIL_CAUSE,
|
||||
@@ -365,9 +433,7 @@ static void ril_voicecall_clcc_poll_cb(GRilIoChannel *io, int status,
|
||||
}
|
||||
|
||||
g_slist_free_full(vd->calls, g_free);
|
||||
|
||||
vd->calls = calls;
|
||||
vd->local_release = 0;
|
||||
}
|
||||
|
||||
static void ril_voicecall_clcc_poll(struct ril_voicecall *vd)
|
||||
@@ -386,52 +452,47 @@ static void ril_voicecall_clcc_poll(struct ril_voicecall *vd)
|
||||
static void ril_voicecall_request_cb(GRilIoChannel *io, int status,
|
||||
const void *data, guint len, void *user_data)
|
||||
{
|
||||
struct ril_voicecall_change_state_req *req = user_data;
|
||||
struct ril_voicecall_request_data *req = user_data;
|
||||
struct ril_voicecall *vd = ril_voicecall_get_data(req->vc);
|
||||
struct ofono_error error;
|
||||
|
||||
if (status == RIL_E_SUCCESS) {
|
||||
GSList *l;
|
||||
|
||||
if (req->affected_types) {
|
||||
for (l = vd->calls; l; l = l->next) {
|
||||
struct ofono_call *call = l->data;
|
||||
|
||||
if (req->affected_types & (1 << call->status)) {
|
||||
vd->local_release |= (1 << call->id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ril_error_init_ok(&error);
|
||||
} else {
|
||||
ofono_error("generic fail");
|
||||
ril_error_init_failure(&error);
|
||||
}
|
||||
|
||||
ril_voicecall_clcc_poll(vd);
|
||||
|
||||
/* We have to callback after we schedule a poll if required */
|
||||
if (req->cb) {
|
||||
/*
|
||||
* The ofono API call is considered successful if at least one
|
||||
* associated RIL request succeeds.
|
||||
*/
|
||||
if (status == RIL_E_SUCCESS) {
|
||||
req->success++;
|
||||
}
|
||||
|
||||
/*
|
||||
* Only invoke the callback if this is the last request associated
|
||||
* with this ofono api call (pending call count becomes zero).
|
||||
*/
|
||||
GASSERT(req->pending_call_count > 0);
|
||||
if (!--req->pending_call_count && req->cb) {
|
||||
struct ofono_error error;
|
||||
|
||||
if (req->success) {
|
||||
ril_error_init_ok(&error);
|
||||
} else {
|
||||
ril_error_init_failure(&error);
|
||||
}
|
||||
|
||||
req->cb(&error, req->data);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_voicecall_request(const guint rreq, struct ofono_voicecall *vc,
|
||||
unsigned int affected_types, GRilIoRequest *ioreq,
|
||||
ofono_voicecall_cb_t cb, void *data)
|
||||
static void ril_voicecall_request(const guint code, struct ofono_voicecall *vc,
|
||||
GRilIoRequest *req, ofono_voicecall_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_voicecall *vd = ril_voicecall_get_data(vc);
|
||||
struct ril_voicecall_change_state_req *req;
|
||||
struct ril_voicecall_request_data *req_data =
|
||||
ril_voicecall_request_data_new(vc, cb, data);
|
||||
|
||||
req = g_new0(struct ril_voicecall_change_state_req, 1);
|
||||
req->vc = vc;
|
||||
req->cb = cb;
|
||||
req->data = data;
|
||||
req->affected_types = affected_types;
|
||||
|
||||
grilio_queue_send_request_full(vd->q, ioreq, rreq,
|
||||
ril_voicecall_request_cb, g_free, req);
|
||||
req_data->pending_call_count++;
|
||||
grilio_queue_send_request_full(ril_voicecall_get_data(vc)->q, req,
|
||||
code, ril_voicecall_request_cb,
|
||||
ril_voicecall_request_data_free, req_data);
|
||||
}
|
||||
|
||||
static void ril_voicecall_dial_cb(GRilIoChannel *io, int status,
|
||||
@@ -489,47 +550,68 @@ static void ril_voicecall_dial(struct ofono_voicecall *vc,
|
||||
grilio_request_unref(req);
|
||||
}
|
||||
|
||||
static void ril_voicecall_submit_hangup_req(struct ofono_voicecall *vc,
|
||||
int id, struct ril_voicecall_request_data *req)
|
||||
{
|
||||
struct ril_voicecall *vd = ril_voicecall_get_data(vc);
|
||||
GRilIoRequest *ioreq = grilio_request_array_int32_new(1, id);
|
||||
|
||||
/* Append the call id to the list of calls being released locally */
|
||||
GASSERT(!gutil_int_array_contains(vd->local_release_ids, id));
|
||||
gutil_int_array_append(vd->local_release_ids, id);
|
||||
|
||||
/* Send request to RIL. ril_voicecall_request_data_free will unref
|
||||
* the request data */
|
||||
req->ref_count++;
|
||||
req->pending_call_count++;
|
||||
grilio_queue_send_request_full(vd->q, ioreq, RIL_REQUEST_HANGUP,
|
||||
ril_voicecall_request_cb,
|
||||
ril_voicecall_request_data_free, req);
|
||||
grilio_request_unref(ioreq);
|
||||
}
|
||||
|
||||
static void ril_voicecall_hangup_all(struct ofono_voicecall *vc,
|
||||
ofono_voicecall_cb_t cb, void *data)
|
||||
{
|
||||
struct ril_voicecall *vd = ril_voicecall_get_data(vc);
|
||||
struct ofono_error error;
|
||||
GSList *l;
|
||||
|
||||
for (l = vd->calls; l; l = l->next) {
|
||||
struct ofono_call *call = l->data;
|
||||
GRilIoRequest *req = grilio_request_sized_new(8);
|
||||
if (vd->calls) {
|
||||
GSList *l;
|
||||
struct ril_voicecall_request_data *req =
|
||||
ril_voicecall_request_data_new(vc, cb, data);
|
||||
|
||||
/* TODO: Hangup just the active ones once we have call
|
||||
* state tracking (otherwise it can't handle ringing) */
|
||||
DBG("Hanging up call with id %d", call->id);
|
||||
grilio_request_append_int32(req, 1); /* Always 1 - AT+CHLD=1x */
|
||||
grilio_request_append_int32(req, call->id);
|
||||
/*
|
||||
* Here the idea is that we submit (potentially) multiple
|
||||
* hangup requests to RIL and invoke the callback after
|
||||
* the last request has completed (pending call count
|
||||
* becomes zero).
|
||||
*/
|
||||
for (l = vd->calls; l; l = l->next) {
|
||||
struct ofono_call *call = l->data;
|
||||
|
||||
/* Send request to RIL */
|
||||
ril_voicecall_request(RIL_REQUEST_HANGUP, vc, 0x3f, req,
|
||||
NULL, NULL);
|
||||
grilio_request_unref(req);
|
||||
/* Send request to RIL */
|
||||
DBG("Hanging up call with id %d", call->id);
|
||||
ril_voicecall_submit_hangup_req(vc, call->id, req);
|
||||
}
|
||||
|
||||
/* Release our reference */
|
||||
ril_voicecall_request_data_unref(req);
|
||||
} else {
|
||||
/* No calls */
|
||||
struct ofono_error error;
|
||||
cb(ril_error_ok(&error), data);
|
||||
}
|
||||
|
||||
/* TODO: Deal in case of an error at hungup */
|
||||
cb(ril_error_ok(&error), data);
|
||||
}
|
||||
|
||||
static void ril_voicecall_hangup_specific(struct ofono_voicecall *vc,
|
||||
static void ril_voicecall_release_specific(struct ofono_voicecall *vc,
|
||||
int id, ofono_voicecall_cb_t cb, void *data)
|
||||
{
|
||||
GRilIoRequest *req = grilio_request_sized_new(8);
|
||||
struct ofono_error error;
|
||||
struct ril_voicecall_request_data *req =
|
||||
ril_voicecall_request_data_new(vc, cb, data);
|
||||
|
||||
DBG("Hanging up call with id %d", id);
|
||||
grilio_request_append_int32(req, 1); /* Always 1 - AT+CHLD=1x */
|
||||
grilio_request_append_int32(req, id);
|
||||
|
||||
/* Send request to RIL */
|
||||
ril_voicecall_request(RIL_REQUEST_HANGUP, vc, 0x3f, req, NULL, NULL);
|
||||
grilio_request_unref(req);
|
||||
cb(ril_error_ok(&error), data);
|
||||
ril_voicecall_submit_hangup_req(vc, id, req);
|
||||
ril_voicecall_request_data_unref(req);
|
||||
}
|
||||
|
||||
static void ril_voicecall_call_state_changed_event(GRilIoChannel *io,
|
||||
@@ -584,7 +666,7 @@ static void ril_voicecall_answer(struct ofono_voicecall *vc,
|
||||
{
|
||||
/* Send request to RIL */
|
||||
DBG("Answering current call");
|
||||
ril_voicecall_request(RIL_REQUEST_ANSWER, vc, 0, NULL, cb, data);
|
||||
ril_voicecall_request(RIL_REQUEST_ANSWER, vc, NULL, cb, data);
|
||||
}
|
||||
|
||||
static void ril_voicecall_send_dtmf_cb(GRilIoChannel *io, int status,
|
||||
@@ -653,29 +735,25 @@ static void ril_voicecall_clear_dtmf_queue(struct ril_voicecall *vd)
|
||||
static void ril_voicecall_create_multiparty(struct ofono_voicecall *vc,
|
||||
ofono_voicecall_cb_t cb, void *data)
|
||||
{
|
||||
ril_voicecall_request(RIL_REQUEST_CONFERENCE,
|
||||
vc, 0, NULL, cb, data);
|
||||
ril_voicecall_request(RIL_REQUEST_CONFERENCE, vc, NULL, cb, data);
|
||||
}
|
||||
|
||||
static void ril_voicecall_transfer(struct ofono_voicecall *vc,
|
||||
ofono_voicecall_cb_t cb, void *data)
|
||||
{
|
||||
ril_voicecall_request(RIL_REQUEST_EXPLICIT_CALL_TRANSFER,
|
||||
vc, 0, NULL, cb, data);
|
||||
vc, NULL, cb, data);
|
||||
}
|
||||
|
||||
static void ril_voicecall_private_chat(struct ofono_voicecall *vc, int id,
|
||||
ofono_voicecall_cb_t cb, void *data)
|
||||
{
|
||||
GRilIoRequest *req = grilio_request_sized_new(8);
|
||||
GRilIoRequest *req = grilio_request_array_int32_new(1, id);
|
||||
struct ofono_error error;
|
||||
|
||||
DBG("Private chat with id %d", id);
|
||||
grilio_request_append_int32(req, 1);
|
||||
grilio_request_append_int32(req, id);
|
||||
|
||||
ril_voicecall_request(RIL_REQUEST_SEPARATE_CONNECTION,
|
||||
vc, 0, req, NULL, NULL);
|
||||
vc, req, NULL, NULL);
|
||||
grilio_request_unref(req);
|
||||
cb(ril_error_ok(&error), data);
|
||||
}
|
||||
@@ -683,51 +761,52 @@ static void ril_voicecall_private_chat(struct ofono_voicecall *vc, int id,
|
||||
static void ril_voicecall_swap_without_accept(struct ofono_voicecall *vc,
|
||||
ofono_voicecall_cb_t cb, void *data)
|
||||
{
|
||||
DBG("");
|
||||
ril_voicecall_request(RIL_REQUEST_SWITCH_HOLDING_AND_ACTIVE,
|
||||
vc, 0, NULL, cb, data);
|
||||
vc, NULL, cb, data);
|
||||
}
|
||||
|
||||
static void ril_voicecall_hold_all_active(struct ofono_voicecall *vc,
|
||||
ofono_voicecall_cb_t cb, void *data)
|
||||
{
|
||||
DBG("");
|
||||
ril_voicecall_request(RIL_REQUEST_SWITCH_HOLDING_AND_ACTIVE,
|
||||
vc, 0, NULL, cb, data);
|
||||
vc, NULL, cb, data);
|
||||
}
|
||||
|
||||
static void ril_voicecall_release_all_held(struct ofono_voicecall *vc,
|
||||
ofono_voicecall_cb_t cb, void *data)
|
||||
{
|
||||
DBG("");
|
||||
ril_voicecall_request(RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND,
|
||||
vc, 0, NULL, cb, data);
|
||||
vc, NULL, cb, data);
|
||||
}
|
||||
|
||||
static void ril_voicecall_release_all_active(struct ofono_voicecall *vc,
|
||||
ofono_voicecall_cb_t cb, void *data)
|
||||
{
|
||||
DBG("");
|
||||
ril_voicecall_request(RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND,
|
||||
vc, 0, NULL, cb, data);
|
||||
vc, NULL, cb, data);
|
||||
}
|
||||
|
||||
static void ril_voicecall_set_udub(struct ofono_voicecall *vc,
|
||||
ofono_voicecall_cb_t cb, void *data)
|
||||
{
|
||||
DBG("");
|
||||
ril_voicecall_request(RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND,
|
||||
vc, 0, NULL, cb, data);
|
||||
vc, NULL, cb, data);
|
||||
}
|
||||
|
||||
static gboolean ril_voicecall_enable_supp_svc(struct ril_voicecall *vd)
|
||||
static void ril_voicecall_enable_supp_svc(struct ril_voicecall *vd)
|
||||
{
|
||||
GRilIoRequest *req = grilio_request_sized_new(8);
|
||||
|
||||
grilio_request_append_int32(req, 1); /* size of array */
|
||||
grilio_request_append_int32(req, 1); /* notifications enabled */
|
||||
GRilIoRequest *req = grilio_request_array_int32_new(1, 1);
|
||||
|
||||
grilio_request_set_timeout(req, VOICECALL_BLOCK_TIMEOUT_MS);
|
||||
grilio_request_set_blocking(req, TRUE);
|
||||
grilio_queue_send_request(vd->q, req,
|
||||
RIL_REQUEST_SET_SUPP_SVC_NOTIFICATION);
|
||||
grilio_request_unref(req);
|
||||
|
||||
/* Makes this a single shot */
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void ril_voicecall_ringback_tone_event(GRilIoChannel *io,
|
||||
@@ -755,12 +834,10 @@ static void ril_voicecall_ecclist_changed(struct ril_ecclist *list, void *data)
|
||||
ofono_voicecall_en_list_notify(vd->vc, vd->ecclist->list);
|
||||
}
|
||||
|
||||
static gboolean ril_delayed_register(gpointer user_data)
|
||||
static void ril_voicecall_register(gpointer user_data)
|
||||
{
|
||||
struct ril_voicecall *vd = user_data;
|
||||
|
||||
GASSERT(vd->timer_id);
|
||||
vd->timer_id = 0;
|
||||
ofono_voicecall_register(vd->vc);
|
||||
|
||||
/* Emergency Call Codes */
|
||||
@@ -794,15 +871,13 @@ static gboolean ril_delayed_register(gpointer user_data)
|
||||
grilio_channel_add_unsol_event_handler(vd->io,
|
||||
ril_voicecall_ringback_tone_event,
|
||||
RIL_UNSOL_RINGBACK_TONE, vd);
|
||||
|
||||
/* This makes the timeout a single-shot */
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static int ril_voicecall_probe(struct ofono_voicecall *vc, unsigned int vendor,
|
||||
void *data)
|
||||
{
|
||||
struct ril_modem *modem = data;
|
||||
const struct ril_slot_config *cfg = &modem->config;
|
||||
struct ril_voicecall *vd;
|
||||
|
||||
DBG("");
|
||||
@@ -810,13 +885,17 @@ static int ril_voicecall_probe(struct ofono_voicecall *vc, unsigned int vendor,
|
||||
vd->io = grilio_channel_ref(ril_modem_io(modem));
|
||||
vd->q = grilio_queue_new(vd->io);
|
||||
vd->dtmf_queue = gutil_ring_new();
|
||||
vd->local_hangup_reasons = gutil_ints_ref(cfg->local_hangup_reasons);
|
||||
vd->remote_hangup_reasons = gutil_ints_ref(cfg->remote_hangup_reasons);
|
||||
vd->local_release_ids = gutil_int_array_new();
|
||||
vd->idleq = gutil_idle_queue_new();
|
||||
vd->vc = vc;
|
||||
vd->timer_id = g_idle_add(ril_delayed_register, vd);
|
||||
if (modem->ecclist_file) {
|
||||
vd->ecclist = ril_ecclist_new(modem->ecclist_file);
|
||||
}
|
||||
ril_voicecall_clear_dtmf_queue(vd);
|
||||
ofono_voicecall_set_data(vc, vd);
|
||||
gutil_idle_queue_add(vd->idleq, ril_voicecall_register, vd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -828,10 +907,6 @@ static void ril_voicecall_remove(struct ofono_voicecall *vc)
|
||||
ofono_voicecall_set_data(vc, NULL);
|
||||
g_slist_free_full(vd->calls, g_free);
|
||||
|
||||
if (vd->timer_id > 0) {
|
||||
g_source_remove(vd->timer_id);
|
||||
}
|
||||
|
||||
ril_ecclist_remove_handler(vd->ecclist, vd->ecclist_change_id);
|
||||
ril_ecclist_unref(vd->ecclist);
|
||||
|
||||
@@ -841,6 +916,10 @@ static void ril_voicecall_remove(struct ofono_voicecall *vc)
|
||||
grilio_queue_cancel_all(vd->q, FALSE);
|
||||
grilio_queue_unref(vd->q);
|
||||
gutil_ring_unref(vd->dtmf_queue);
|
||||
gutil_ints_unref(vd->local_hangup_reasons);
|
||||
gutil_ints_unref(vd->remote_hangup_reasons);
|
||||
gutil_int_array_free(vd->local_release_ids, TRUE);
|
||||
gutil_idle_queue_free(vd->idleq);
|
||||
g_free(vd);
|
||||
}
|
||||
|
||||
@@ -851,7 +930,7 @@ const struct ofono_voicecall_driver ril_voicecall_driver = {
|
||||
.dial = ril_voicecall_dial,
|
||||
.answer = ril_voicecall_answer,
|
||||
.hangup_all = ril_voicecall_hangup_all,
|
||||
.release_specific = ril_voicecall_hangup_specific,
|
||||
.release_specific = ril_voicecall_release_specific,
|
||||
.send_tones = ril_voicecall_send_dtmf,
|
||||
.create_multiparty = ril_voicecall_create_multiparty,
|
||||
.transfer = ril_voicecall_transfer,
|
||||
|
||||
@@ -261,6 +261,7 @@ static void ublox_send_uauthreq(struct ofono_gprs_context *gc,
|
||||
case OFONO_GPRS_AUTH_METHOD_PAP:
|
||||
auth = 1;
|
||||
break;
|
||||
case OFONO_GPRS_AUTH_METHOD_ANY:
|
||||
case OFONO_GPRS_AUTH_METHOD_CHAP:
|
||||
auth = 2;
|
||||
break;
|
||||
|
||||
@@ -49,7 +49,9 @@ enum ofono_gprs_context_type {
|
||||
};
|
||||
|
||||
enum ofono_gprs_auth_method {
|
||||
OFONO_GPRS_AUTH_METHOD_CHAP = 0,
|
||||
OFONO_GPRS_AUTH_METHOD_ANY = 0,
|
||||
OFONO_GPRS_AUTH_METHOD_NONE,
|
||||
OFONO_GPRS_AUTH_METHOD_CHAP,
|
||||
OFONO_GPRS_AUTH_METHOD_PAP,
|
||||
};
|
||||
|
||||
|
||||
@@ -71,11 +71,12 @@ struct ofono_debug_desc {
|
||||
.file = __FILE__, .flags = OFONO_DEBUG_FLAG_DEFAULT, \
|
||||
}; \
|
||||
if (__ofono_debug_desc.flags & OFONO_DEBUG_FLAG_PRINT) \
|
||||
__ofono_dbg(&__ofono_debug_desc, "%s() " fmt, \
|
||||
ofono_dbg(&__ofono_debug_desc, "%s() " fmt, \
|
||||
__FUNCTION__ , ## arg); \
|
||||
} while (0)
|
||||
|
||||
void __ofono_dbg(const struct ofono_debug_desc *desc, const char *format, ...)
|
||||
extern void ofono_dbg(const struct ofono_debug_desc *desc,
|
||||
const char *format, ...)
|
||||
__attribute__((format(printf, 2, 3)));
|
||||
|
||||
typedef void (*ofono_log_hook_cb_t)(const struct ofono_debug_desc *desc,
|
||||
|
||||
@@ -114,6 +114,7 @@ int ofono_netreg_get_status(struct ofono_netreg *netreg);
|
||||
int ofono_netreg_get_technology(struct ofono_netreg *netreg);
|
||||
const char *ofono_netreg_get_mcc(struct ofono_netreg *netreg);
|
||||
const char *ofono_netreg_get_mnc(struct ofono_netreg *netreg);
|
||||
const char *ofono_netreg_get_name(struct ofono_netreg *netreg);
|
||||
struct sim_spdi *ofono_netreg_get_spdi(struct ofono_netreg *netreg);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
114
ofono/include/sailfish_cell_info.h
Normal file
114
ofono/include/sailfish_cell_info.h
Normal file
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef SAILFISH_CELL_INFO_H
|
||||
#define SAILFISH_CELL_INFO_H
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
enum sailfish_cell_type {
|
||||
SAILFISH_CELL_TYPE_GSM,
|
||||
SAILFISH_CELL_TYPE_WCDMA,
|
||||
SAILFISH_CELL_TYPE_LTE
|
||||
};
|
||||
|
||||
struct sailfish_cell_info_gsm {
|
||||
int mcc; /* Mobile Country Code (0..999) */
|
||||
int mnc; /* Mobile Network Code (0..999) */
|
||||
int lac; /* Location Area Code (0..65535) */
|
||||
int cid; /* GSM Cell Identity (0..65535) TS 27.007 */
|
||||
int arfcn; /* 16-bit GSM Absolute RF channel number */
|
||||
int bsic; /* 6-bit Base Station Identity Code */
|
||||
int signalStrength; /* (0-31, 99) TS 27.007 */
|
||||
int bitErrorRate; /* (0-7, 99) TS 27.007 */
|
||||
int timingAdvance; /* Timing Advance. 1 period = 48/13 us */
|
||||
};
|
||||
|
||||
struct sailfish_cell_info_wcdma {
|
||||
int mcc; /* Mobile Country Code (0..999) */
|
||||
int mnc; /* Mobile Network Code (0..999) */
|
||||
int lac; /* Location Area Code (0..65535) */
|
||||
int cid; /* UMTS Cell Identity (0..268435455) TS 25.331 */
|
||||
int psc; /* Primary Scrambling Code (0..511) TS 25.331) */
|
||||
int uarfcn; /* 16-bit UMTS Absolute RF Channel Number */
|
||||
int signalStrength; /* (0-31, 99) TS 27.007 */
|
||||
int bitErrorRate; /* (0-7, 99) TS 27.007 */
|
||||
};
|
||||
|
||||
struct sailfish_cell_info_lte {
|
||||
int mcc; /* Mobile Country Code (0..999) */
|
||||
int mnc; /* Mobile Network Code (0..999) */
|
||||
int ci; /* Cell Identity */
|
||||
int pci; /* Physical cell id (0..503) */
|
||||
int tac; /* Tracking area code */
|
||||
int earfcn; /* 18-bit LTE Absolute RC Channel Number */
|
||||
int signalStrength; /* (0-31, 99) TS 27.007 8.5 */
|
||||
int rsrp; /* Reference Signal Receive Power TS 36.133 */
|
||||
int rsrq; /* Reference Signal Receive Quality TS 36.133 */
|
||||
int rssnr; /* Reference Signal-to-Noise Ratio TS 36.101*/
|
||||
int cqi; /* Channel Quality Indicator TS 36.101 */
|
||||
int timingAdvance; /* (Distance = 300m/us) TS 36.321 */
|
||||
};
|
||||
|
||||
struct sailfish_cell {
|
||||
enum sailfish_cell_type type;
|
||||
gboolean registered;
|
||||
union {
|
||||
struct sailfish_cell_info_gsm gsm;
|
||||
struct sailfish_cell_info_wcdma wcdma;
|
||||
struct sailfish_cell_info_lte lte;
|
||||
} info;
|
||||
};
|
||||
|
||||
struct sailfish_cell_info {
|
||||
const struct sailfish_cell_info_proc *proc;
|
||||
GSList *cells;
|
||||
};
|
||||
|
||||
typedef void (*sailfish_cell_info_cb_t)(struct sailfish_cell_info *info,
|
||||
void *arg);
|
||||
|
||||
struct sailfish_cell_info_proc {
|
||||
void (*ref)(struct sailfish_cell_info *info);
|
||||
void (*unref)(struct sailfish_cell_info *info);
|
||||
gulong (*add_cells_changed_handler)(struct sailfish_cell_info *info,
|
||||
sailfish_cell_info_cb_t cb, void *arg);
|
||||
void (*remove_handler)(struct sailfish_cell_info *info, gulong id);
|
||||
};
|
||||
|
||||
/* Utilities */
|
||||
gint sailfish_cell_compare_func(gconstpointer v1, gconstpointer v2);
|
||||
gint sailfish_cell_compare_location(const struct sailfish_cell *c1,
|
||||
const struct sailfish_cell *c2);
|
||||
|
||||
/* Cell info object API */
|
||||
struct sailfish_cell_info *sailfish_cell_info_ref
|
||||
(struct sailfish_cell_info *info);
|
||||
void sailfish_cell_info_unref(struct sailfish_cell_info *info);
|
||||
gulong sailfish_cell_info_add_cells_changed_handler
|
||||
(struct sailfish_cell_info *info,
|
||||
sailfish_cell_info_cb_t cb, void *arg);
|
||||
void sailfish_cell_info_remove_handler(struct sailfish_cell_info *info,
|
||||
gulong id);
|
||||
|
||||
#endif /* SAILFISH_CELINFO_H */
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
125
ofono/include/sailfish_manager.h
Normal file
125
ofono/include/sailfish_manager.h
Normal file
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef SAILFISH_MANAGER_H
|
||||
#define SAILFISH_MANAGER_H
|
||||
|
||||
struct ofono_modem;
|
||||
|
||||
#include <ofono/types.h>
|
||||
#include <ofono/radio-settings.h>
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
struct sailfish_manager;
|
||||
struct sailfish_slot;
|
||||
struct sailfish_slot_impl;
|
||||
struct sailfish_slot_driver;
|
||||
struct sailfish_slot_driver_reg;
|
||||
struct sailfish_slot_manager;
|
||||
struct sailfish_slot_manager_impl;
|
||||
struct sailfish_cell_info;
|
||||
|
||||
typedef void (*sailfish_slot_manager_impl_cb_t)
|
||||
(struct sailfish_slot_manager_impl *impl, void *user_data);
|
||||
|
||||
typedef struct sailfish_slot {
|
||||
const char *path;
|
||||
const char *imei;
|
||||
const char *imeisv;
|
||||
gboolean sim_present;
|
||||
gboolean enabled;
|
||||
} const *sailfish_slot_ptr;
|
||||
|
||||
struct sailfish_manager {
|
||||
const char *mms_imsi;
|
||||
const char *mms_path;
|
||||
const char *default_voice_imsi;
|
||||
const char *default_data_imsi;
|
||||
const char *default_voice_path;
|
||||
const char *default_data_path;
|
||||
const sailfish_slot_ptr *slots;
|
||||
gboolean ready;
|
||||
};
|
||||
|
||||
enum sailfish_sim_state {
|
||||
SAILFISH_SIM_STATE_UNKNOWN,
|
||||
SAILFISH_SIM_STATE_ABSENT,
|
||||
SAILFISH_SIM_STATE_PRESENT,
|
||||
SAILFISH_SIM_STATE_ERROR
|
||||
};
|
||||
|
||||
enum sailfish_data_role {
|
||||
SAILFISH_DATA_ROLE_NONE, /* Data not allowed */
|
||||
SAILFISH_DATA_ROLE_MMS, /* Data is allowed at any speed */
|
||||
SAILFISH_DATA_ROLE_INTERNET /* Data is allowed at full speed */
|
||||
};
|
||||
|
||||
/* Register/unregister the driver */
|
||||
struct sailfish_slot_driver_reg *sailfish_slot_driver_register
|
||||
(const struct sailfish_slot_driver *d);
|
||||
void sailfish_slot_driver_unregister(struct sailfish_slot_driver_reg *r);
|
||||
|
||||
/* For use by the driver implementations */
|
||||
void sailfish_manager_foreach_slot_manager
|
||||
(struct sailfish_slot_driver_reg *r,
|
||||
sailfish_slot_manager_impl_cb_t cb, void *user_data);
|
||||
struct sailfish_slot *sailfish_manager_slot_add
|
||||
(struct sailfish_slot_manager *m, struct sailfish_slot_impl *i,
|
||||
const char *path, enum ofono_radio_access_mode techs,
|
||||
const char *imei, const char *imeisv,
|
||||
enum sailfish_sim_state sim_state);
|
||||
void sailfish_manager_imei_obtained(struct sailfish_slot *s, const char *imei);
|
||||
void sailfish_manager_imeisv_obtained(struct sailfish_slot *s,
|
||||
const char *imeisv);
|
||||
void sailfish_manager_set_sim_state(struct sailfish_slot *s,
|
||||
enum sailfish_sim_state state);
|
||||
void sailfish_slot_manager_started(struct sailfish_slot_manager *m);
|
||||
void sailfish_manager_slot_error(struct sailfish_slot *s, const char *key,
|
||||
const char *message);
|
||||
void sailfish_manager_error(struct sailfish_slot_manager *m, const char *key,
|
||||
const char *message);
|
||||
void sailfish_manager_set_cell_info(struct sailfish_slot *s,
|
||||
struct sailfish_cell_info *ci);
|
||||
|
||||
/* Callbacks provided by slot plugins */
|
||||
struct sailfish_slot_driver {
|
||||
const char *name;
|
||||
int priority;
|
||||
|
||||
/* Slot manager methods */
|
||||
struct sailfish_slot_manager_impl *(*manager_create)
|
||||
(struct sailfish_slot_manager *m);
|
||||
guint (*manager_start)(struct sailfish_slot_manager_impl *s);
|
||||
void (*manager_cancel_start)(struct sailfish_slot_manager_impl *s,
|
||||
guint id);
|
||||
void (*manager_free)(struct sailfish_slot_manager_impl *s);
|
||||
|
||||
/* Slot methods */
|
||||
void (*slot_enabled_changed)(struct sailfish_slot_impl *s);
|
||||
void (*slot_set_data_role)(struct sailfish_slot_impl *s,
|
||||
enum sailfish_data_role role);
|
||||
void (*slot_free)(struct sailfish_slot_impl *s);
|
||||
};
|
||||
|
||||
#endif /* SAILFISH_MANAGER_H */
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
81
ofono/include/sailfish_watch.h
Normal file
81
ofono/include/sailfish_watch.h
Normal file
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef SAILFISH_WATCH_H
|
||||
#define SAILFISH_WATCH_H
|
||||
|
||||
struct ofono_modem;
|
||||
struct ofono_sim;
|
||||
struct ofono_netreg;
|
||||
|
||||
#include <glib.h>
|
||||
#include <glib-object.h>
|
||||
|
||||
/* This object watches ofono modem and various related things */
|
||||
struct sailfish_watch_priv;
|
||||
struct sailfish_watch {
|
||||
GObject object;
|
||||
struct sailfish_watch_priv *priv;
|
||||
const char *path;
|
||||
/* Modem */
|
||||
struct ofono_modem *modem;
|
||||
gboolean online;
|
||||
/* OFONO_ATOM_TYPE_SIM */
|
||||
struct ofono_sim *sim;
|
||||
const char *iccid;
|
||||
const char *imsi;
|
||||
const char *spn;
|
||||
/* OFONO_ATOM_TYPE_NETREG */
|
||||
struct ofono_netreg *netreg;
|
||||
};
|
||||
|
||||
typedef void (*sailfish_watch_cb_t)(struct sailfish_watch *w, void *user_data);
|
||||
|
||||
struct sailfish_watch *sailfish_watch_new(const char *path);
|
||||
struct sailfish_watch *sailfish_watch_ref(struct sailfish_watch *w);
|
||||
void sailfish_watch_unref(struct sailfish_watch *w);
|
||||
|
||||
gulong sailfish_watch_add_modem_changed_handler(struct sailfish_watch *w,
|
||||
sailfish_watch_cb_t cb, void *user_data);
|
||||
gulong sailfish_watch_add_online_changed_handler(struct sailfish_watch *w,
|
||||
sailfish_watch_cb_t cb, void *user_data);
|
||||
gulong sailfish_watch_add_sim_changed_handler(struct sailfish_watch *w,
|
||||
sailfish_watch_cb_t cb, void *user_data);
|
||||
gulong sailfish_watch_add_sim_state_changed_handler(struct sailfish_watch *w,
|
||||
sailfish_watch_cb_t cb, void *user_data);
|
||||
gulong sailfish_watch_add_iccid_changed_handler(struct sailfish_watch *w,
|
||||
sailfish_watch_cb_t cb, void *user_data);
|
||||
gulong sailfish_watch_add_imsi_changed_handler(struct sailfish_watch *w,
|
||||
sailfish_watch_cb_t cb, void *user_data);
|
||||
gulong sailfish_watch_add_spn_changed_handler(struct sailfish_watch *w,
|
||||
sailfish_watch_cb_t cb, void *user_data);
|
||||
gulong sailfish_watch_add_netreg_changed_handler(struct sailfish_watch *w,
|
||||
sailfish_watch_cb_t cb, void *user_data);
|
||||
void sailfish_watch_remove_handler(struct sailfish_watch *w, gulong id);
|
||||
void sailfish_watch_remove_handlers(struct sailfish_watch *w, gulong *ids,
|
||||
int count);
|
||||
|
||||
#define sailfish_watch_remove_all_handlers(w,ids) \
|
||||
sailfish_watch_remove_handlers(w, ids, G_N_ELEMENTS(ids))
|
||||
|
||||
#endif /* SAILFISH_WATCH_H */
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
@@ -172,6 +172,8 @@ void ofono_voicecall_ssn_mt_notify(struct ofono_voicecall *vc, unsigned int id,
|
||||
int code, int index,
|
||||
const struct ofono_phone_number *ph);
|
||||
|
||||
struct ofono_call *ofono_voicecall_find_call(struct ofono_voicecall *vc,
|
||||
unsigned int id);
|
||||
void ofono_voicecall_ringback_tone_notify(struct ofono_voicecall *vc,
|
||||
const ofono_bool_t playTone);
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
|
||||
* Copyright (C) 2015-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
|
||||
@@ -53,6 +54,9 @@ const char *mbpi_database = MBPI_DATABASE;
|
||||
enum ofono_gprs_proto mbpi_default_internet_proto = OFONO_GPRS_PROTO_IPV4V6;
|
||||
enum ofono_gprs_proto mbpi_default_mms_proto = OFONO_GPRS_PROTO_IP;
|
||||
enum ofono_gprs_proto mbpi_default_proto = OFONO_GPRS_PROTO_IP;
|
||||
enum ofono_gprs_auth_method mbpi_default_auth_method = OFONO_GPRS_AUTH_METHOD_ANY;
|
||||
|
||||
#define OFONO_GPRS_AUTH_METHOD_UNSPECIFIED ((enum ofono_gprs_auth_method)(-1))
|
||||
|
||||
#define _(x) case x: return (#x)
|
||||
|
||||
@@ -142,6 +146,39 @@ static const GMarkupParser text_parser = {
|
||||
NULL,
|
||||
};
|
||||
|
||||
static void protocol_start(GMarkupParseContext *context,
|
||||
const gchar **attribute_names,
|
||||
const gchar **attribute_values,
|
||||
enum ofono_gprs_proto *proto,
|
||||
GError **error)
|
||||
{
|
||||
const char *text = NULL;
|
||||
int i;
|
||||
|
||||
for (i = 0; attribute_names[i]; i++)
|
||||
if (g_str_equal(attribute_names[i], "type") == TRUE)
|
||||
text = attribute_values[i];
|
||||
|
||||
if (text == NULL) {
|
||||
mbpi_g_set_error(context, error, G_MARKUP_ERROR,
|
||||
G_MARKUP_ERROR_MISSING_ATTRIBUTE,
|
||||
"Missing attribute: type");
|
||||
return;
|
||||
}
|
||||
|
||||
if (strcmp(text, "ip") == 0)
|
||||
*proto = OFONO_GPRS_PROTO_IP;
|
||||
else if (strcmp(text, "ipv6") == 0)
|
||||
*proto = OFONO_GPRS_PROTO_IPV6;
|
||||
else if (strcmp(text, "ipv4v6") == 0)
|
||||
*proto = OFONO_GPRS_PROTO_IPV4V6;
|
||||
else
|
||||
mbpi_g_set_error(context, error, G_MARKUP_ERROR,
|
||||
G_MARKUP_ERROR_UNKNOWN_ATTRIBUTE,
|
||||
"Unknown authentication method: %s",
|
||||
text);
|
||||
}
|
||||
|
||||
static void authentication_start(GMarkupParseContext *context,
|
||||
const gchar **attribute_names,
|
||||
const gchar **attribute_values,
|
||||
@@ -166,6 +203,10 @@ static void authentication_start(GMarkupParseContext *context,
|
||||
*auth_method = OFONO_GPRS_AUTH_METHOD_CHAP;
|
||||
else if (strcmp(text, "pap") == 0)
|
||||
*auth_method = OFONO_GPRS_AUTH_METHOD_PAP;
|
||||
else if (strcmp(text, "any") == 0)
|
||||
*auth_method = OFONO_GPRS_AUTH_METHOD_ANY;
|
||||
else if (strcmp(text, "none") == 0)
|
||||
*auth_method = OFONO_GPRS_AUTH_METHOD_NONE;
|
||||
else
|
||||
mbpi_g_set_error(context, error, G_MARKUP_ERROR,
|
||||
G_MARKUP_ERROR_UNKNOWN_ATTRIBUTE,
|
||||
@@ -221,6 +262,9 @@ static void apn_start(GMarkupParseContext *context, const gchar *element_name,
|
||||
else if (g_str_equal(element_name, "password"))
|
||||
g_markup_parse_context_push(context, &text_parser,
|
||||
&apn->password);
|
||||
else if (g_str_equal(element_name, "protocol"))
|
||||
protocol_start(context, attribute_names,
|
||||
attribute_values, &apn->proto, error);
|
||||
else if (g_str_equal(element_name, "authentication"))
|
||||
authentication_start(context, attribute_names,
|
||||
attribute_values, &apn->auth_method, error);
|
||||
@@ -344,7 +388,7 @@ static void apn_handler(GMarkupParseContext *context, struct gsm_data *gsm,
|
||||
ap->apn = g_strdup(apn);
|
||||
ap->type = OFONO_GPRS_CONTEXT_TYPE_INTERNET;
|
||||
ap->proto = mbpi_default_proto;
|
||||
ap->auth_method = OFONO_GPRS_AUTH_METHOD_CHAP;
|
||||
ap->auth_method = OFONO_GPRS_AUTH_METHOD_UNSPECIFIED;
|
||||
|
||||
g_markup_parse_context_push(context, &apn_parser, ap);
|
||||
}
|
||||
@@ -414,6 +458,17 @@ static void gsm_end(GMarkupParseContext *context, const gchar *element_name,
|
||||
if (ap == NULL)
|
||||
return;
|
||||
|
||||
/* Fix the authentication method if none was specified */
|
||||
if (ap->auth_method == OFONO_GPRS_AUTH_METHOD_UNSPECIFIED) {
|
||||
if ((!ap->username || !ap->username[0]) &&
|
||||
(!ap->password || !ap->password[0])) {
|
||||
/* No username or password => no authentication */
|
||||
ap->auth_method = OFONO_GPRS_AUTH_METHOD_NONE;
|
||||
} else {
|
||||
ap->auth_method = mbpi_default_auth_method;
|
||||
}
|
||||
}
|
||||
|
||||
if (gsm->allow_duplicates == FALSE) {
|
||||
GSList *l;
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@ extern const char *mbpi_database;
|
||||
extern enum ofono_gprs_proto mbpi_default_internet_proto;
|
||||
extern enum ofono_gprs_proto mbpi_default_mms_proto;
|
||||
extern enum ofono_gprs_proto mbpi_default_proto;
|
||||
extern enum ofono_gprs_auth_method mbpi_default_auth_method;
|
||||
|
||||
const char *mbpi_ap_type(enum ofono_gprs_context_type type);
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
|
||||
* Copyright (C) 2013-2016 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
|
||||
@@ -24,7 +23,6 @@
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
@@ -37,114 +35,9 @@
|
||||
#include <ofono/modem.h>
|
||||
#include <ofono/gprs-provision.h>
|
||||
|
||||
#include "provision.h"
|
||||
#include "mbpi.h"
|
||||
|
||||
struct provision_ap_defaults {
|
||||
enum ofono_gprs_context_type type;
|
||||
const char *name;
|
||||
const char *apn;
|
||||
};
|
||||
|
||||
static gboolean provision_match_name(const struct ofono_gprs_provision_data *ap,
|
||||
const char* spn)
|
||||
{
|
||||
return (ap->provider_name && strcasestr(ap->provider_name, spn)) ||
|
||||
(ap->name && strcasestr(ap->name, spn)) ||
|
||||
(ap->apn && strcasestr(ap->apn, spn));
|
||||
}
|
||||
|
||||
static void provision_free_ap(gpointer data)
|
||||
{
|
||||
mbpi_ap_free(data);
|
||||
}
|
||||
|
||||
static gint provision_compare_ap(gconstpointer a, gconstpointer b, gpointer data)
|
||||
{
|
||||
const struct ofono_gprs_provision_data *ap1 = a;
|
||||
const struct ofono_gprs_provision_data *ap2 = b;
|
||||
const char* spn = data;
|
||||
|
||||
if (spn) {
|
||||
const gboolean match1 = provision_match_name(ap1, spn);
|
||||
const gboolean match2 = provision_match_name(ap2, spn);
|
||||
if (match1 && !match2) {
|
||||
return -1;
|
||||
} else if (match2 && !match1) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (ap1->provider_primary && !ap2->provider_primary) {
|
||||
return -1;
|
||||
} else if (ap2->provider_primary && !ap1->provider_primary) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Picks best ap, deletes the rest. Creates one if necessary */
|
||||
static GSList *provision_pick_best_ap(GSList *list, const char* spn,
|
||||
const enum ofono_gprs_proto default_proto,
|
||||
const struct provision_ap_defaults *defaults)
|
||||
{
|
||||
/* Sort the list */
|
||||
list = g_slist_sort_with_data(list, provision_compare_ap, (void*)spn);
|
||||
if (list) {
|
||||
/* Pick the best one, delete the rest */
|
||||
GSList *best = list;
|
||||
g_slist_free_full(g_slist_remove_link(list, best),
|
||||
provision_free_ap);
|
||||
return best;
|
||||
} else {
|
||||
/* or create one from the default data */
|
||||
struct ofono_gprs_provision_data *ap =
|
||||
g_new0(struct ofono_gprs_provision_data, 1);
|
||||
|
||||
ap->proto = default_proto;
|
||||
ap->type = defaults->type;
|
||||
ap->name = g_strdup(defaults->name);
|
||||
ap->apn = g_strdup(defaults->apn);
|
||||
return g_slist_append(NULL, ap);
|
||||
}
|
||||
}
|
||||
|
||||
/* Returns the list containing exactly one INTERNET and one MMS access point */
|
||||
static GSList *provision_normalize_apn_list(GSList *apns, const char* spn)
|
||||
{
|
||||
static const struct provision_ap_defaults internet_defaults =
|
||||
{ OFONO_GPRS_CONTEXT_TYPE_INTERNET, "Internet", "internet" };
|
||||
static const struct provision_ap_defaults mms_defaults =
|
||||
{ OFONO_GPRS_CONTEXT_TYPE_MMS, "MMS", "mms" };
|
||||
|
||||
GSList *internet_apns = NULL;
|
||||
GSList *mms_apns = NULL;
|
||||
|
||||
/* Split internet and mms apns, delete all others */
|
||||
while (apns) {
|
||||
GSList *link = apns;
|
||||
struct ofono_gprs_provision_data *ap = link->data;
|
||||
|
||||
apns = g_slist_remove_link(apns, link);
|
||||
if (ap->type == OFONO_GPRS_CONTEXT_TYPE_INTERNET) {
|
||||
internet_apns = g_slist_concat(internet_apns, link);
|
||||
} else if (ap->type == OFONO_GPRS_CONTEXT_TYPE_MMS) {
|
||||
mms_apns = g_slist_concat(mms_apns, link);
|
||||
} else {
|
||||
g_slist_free_full(link, provision_free_ap);
|
||||
}
|
||||
}
|
||||
|
||||
/* Pick the best ap of each type and concatenate them */
|
||||
return g_slist_concat(
|
||||
provision_pick_best_ap(internet_apns, spn,
|
||||
mbpi_default_internet_proto, &internet_defaults),
|
||||
provision_pick_best_ap(mms_apns, spn,
|
||||
mbpi_default_mms_proto, &mms_defaults));
|
||||
}
|
||||
|
||||
int provision_get_settings(const char *mcc, const char *mnc,
|
||||
static int provision_get_settings(const char *mcc, const char *mnc,
|
||||
const char *spn,
|
||||
struct ofono_gprs_provision_data **settings,
|
||||
int *count)
|
||||
@@ -155,26 +48,21 @@ int provision_get_settings(const char *mcc, const char *mnc,
|
||||
int ap_count;
|
||||
int i;
|
||||
|
||||
ofono_info("Provisioning for MCC %s, MNC %s, SPN '%s'", mcc, mnc, spn);
|
||||
DBG("Provisioning for MCC %s, MNC %s, SPN '%s'", mcc, mnc, spn);
|
||||
|
||||
/*
|
||||
* Passing FALSE to mbpi_lookup_apn() would return
|
||||
* an empty list if duplicates are found.
|
||||
*/
|
||||
apns = mbpi_lookup_apn(mcc, mnc, TRUE, &error);
|
||||
if (error != NULL) {
|
||||
ofono_error("%s", error->message);
|
||||
g_error_free(error);
|
||||
}
|
||||
apns = mbpi_lookup_apn(mcc, mnc, FALSE, &error);
|
||||
if (apns == NULL) {
|
||||
if (error != NULL) {
|
||||
ofono_error("%s", error->message);
|
||||
g_error_free(error);
|
||||
}
|
||||
|
||||
ofono_info("Found %d APs in MBPI", g_slist_length(apns));
|
||||
apns = provision_normalize_apn_list(apns, spn);
|
||||
if (apns == NULL)
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
ap_count = g_slist_length(apns);
|
||||
|
||||
ofono_info("Provisioning %d APs", ap_count);
|
||||
DBG("Found %d APs", ap_count);
|
||||
|
||||
*settings = g_try_new0(struct ofono_gprs_provision_data, ap_count);
|
||||
if (*settings == NULL) {
|
||||
@@ -193,11 +81,11 @@ int provision_get_settings(const char *mcc, const char *mnc,
|
||||
for (l = apns, i = 0; l; l = l->next, i++) {
|
||||
struct ofono_gprs_provision_data *ap = l->data;
|
||||
|
||||
ofono_info("Name: '%s'", ap->name);
|
||||
ofono_info("APN: '%s'", ap->apn);
|
||||
ofono_info("Type: %s", mbpi_ap_type(ap->type));
|
||||
ofono_info("Username: '%s'", ap->username);
|
||||
ofono_info("Password: '%s'", ap->password);
|
||||
DBG("Name: '%s'", ap->name);
|
||||
DBG("APN: '%s'", ap->apn);
|
||||
DBG("Type: %s", mbpi_ap_type(ap->type));
|
||||
DBG("Username: '%s'", ap->username);
|
||||
DBG("Password: '%s'", ap->password);
|
||||
|
||||
memcpy(*settings + i, ap,
|
||||
sizeof(struct ofono_gprs_provision_data));
|
||||
|
||||
362
ofono/plugins/sailfish_bt.c
Normal file
362
ofono/plugins/sailfish_bt.c
Normal file
@@ -0,0 +1,362 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2017 Jolla Ltd. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <stdint.h>
|
||||
#include <glib.h>
|
||||
#include <ofono.h>
|
||||
#include <gdbus.h>
|
||||
|
||||
#define OFONO_API_SUBJECT_TO_CHANGE
|
||||
#include <ofono/plugin.h>
|
||||
#include <ofono/log.h>
|
||||
|
||||
#define SFOS_BT_DBUS_CV_INTERFACE "org.nemomobile.ofono.bluetooth.CallVolume"
|
||||
#define HFP_CALL_VOLUME_MAX 15
|
||||
|
||||
struct sfos_bt {
|
||||
unsigned int emu_watch;
|
||||
struct ofono_modem *modem;
|
||||
struct ofono_emulator *em;
|
||||
unsigned char speaker_volume;
|
||||
unsigned char microphone_volume;
|
||||
};
|
||||
|
||||
static GSList *modems;
|
||||
static guint modemwatch_id;
|
||||
|
||||
static void set_hfp_microphone_volume(struct sfos_bt *sfos_bt,
|
||||
unsigned char gain)
|
||||
{
|
||||
char buf[64];
|
||||
|
||||
snprintf(buf, sizeof(buf), "+VGM:%d", (int) gain);
|
||||
ofono_emulator_send_unsolicited(sfos_bt->em, buf);
|
||||
}
|
||||
|
||||
static void set_hfp_speaker_volume(struct sfos_bt *sfos_bt,
|
||||
unsigned char gain)
|
||||
{
|
||||
char buf[64];
|
||||
|
||||
snprintf(buf, sizeof(buf), "+VGS:%d", (int) gain);
|
||||
ofono_emulator_send_unsolicited(sfos_bt->em, buf);
|
||||
}
|
||||
|
||||
static DBusMessage *cv_set_property(DBusConnection *conn, DBusMessage *msg,
|
||||
void *data)
|
||||
{
|
||||
struct sfos_bt *sfos_bt = data;
|
||||
DBusMessageIter iter;
|
||||
DBusMessageIter var;
|
||||
const char *property;
|
||||
|
||||
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_str_equal(property, "SpeakerVolume") == TRUE) {
|
||||
unsigned char gain;
|
||||
|
||||
if (dbus_message_iter_get_arg_type(&var) != DBUS_TYPE_BYTE)
|
||||
return __ofono_error_invalid_args(msg);
|
||||
|
||||
dbus_message_iter_get_basic(&var, &gain);
|
||||
|
||||
if (gain > HFP_CALL_VOLUME_MAX)
|
||||
return __ofono_error_invalid_format(msg);
|
||||
|
||||
if (gain == sfos_bt->speaker_volume)
|
||||
return dbus_message_new_method_return(msg);
|
||||
|
||||
DBG("SpeakerVolume:%d", gain);
|
||||
sfos_bt->speaker_volume = gain;
|
||||
set_hfp_speaker_volume(sfos_bt, gain);
|
||||
|
||||
return dbus_message_new_method_return(msg);
|
||||
|
||||
} else if (g_str_equal(property, "MicrophoneVolume") == TRUE) {
|
||||
unsigned char gain;
|
||||
|
||||
if (dbus_message_iter_get_arg_type(&var) != DBUS_TYPE_BYTE)
|
||||
return __ofono_error_invalid_args(msg);
|
||||
|
||||
dbus_message_iter_get_basic(&var, &gain);
|
||||
|
||||
if (gain > HFP_CALL_VOLUME_MAX)
|
||||
return __ofono_error_invalid_format(msg);
|
||||
|
||||
if (gain == sfos_bt->microphone_volume)
|
||||
return dbus_message_new_method_return(msg);
|
||||
|
||||
DBG("MicrophoneVolume:%d", gain);
|
||||
sfos_bt->microphone_volume = gain;
|
||||
set_hfp_microphone_volume(sfos_bt, gain);
|
||||
|
||||
return dbus_message_new_method_return(msg);
|
||||
|
||||
} else if (g_str_equal(property, "Muted") == TRUE) {
|
||||
unsigned char gain;
|
||||
dbus_bool_t muted;
|
||||
|
||||
/*Remove when supported*/
|
||||
return __ofono_error_not_implemented(msg);
|
||||
|
||||
if (dbus_message_iter_get_arg_type(&var) != DBUS_TYPE_BOOLEAN)
|
||||
return __ofono_error_invalid_args(msg);
|
||||
|
||||
dbus_message_iter_get_basic(&var, &muted);
|
||||
|
||||
if (muted)
|
||||
gain = 0;
|
||||
else
|
||||
gain = 7;/* rather gain = sfos->old_mic_vol */
|
||||
|
||||
if (gain == sfos_bt->microphone_volume)
|
||||
return dbus_message_new_method_return(msg);
|
||||
|
||||
sfos_bt->microphone_volume = gain;
|
||||
set_hfp_microphone_volume(sfos_bt, gain);
|
||||
|
||||
return dbus_message_new_method_return(msg);
|
||||
}
|
||||
|
||||
return __ofono_error_invalid_args(msg);
|
||||
}
|
||||
|
||||
static const GDBusMethodTable cv_methods[] = {
|
||||
{ GDBUS_METHOD("SetProperty",
|
||||
GDBUS_ARGS({ "property", "s" }, { "value", "v" }),
|
||||
NULL, cv_set_property) },
|
||||
{ }
|
||||
};
|
||||
|
||||
static const GDBusSignalTable cv_signals[] = {
|
||||
{ GDBUS_SIGNAL("PropertyChanged",
|
||||
GDBUS_ARGS({ "property", "s" }, { "value", "v" })) },
|
||||
{ }
|
||||
};
|
||||
|
||||
int sfos_bt_call_volume_set(struct ofono_modem *modem, unsigned char volume,
|
||||
const char *gain)
|
||||
{
|
||||
DBusConnection *conn = ofono_dbus_get_connection();
|
||||
const char *path = ofono_modem_get_path(modem);
|
||||
|
||||
return ofono_dbus_signal_property_changed(conn, path,
|
||||
SFOS_BT_DBUS_CV_INTERFACE,
|
||||
gain,
|
||||
DBUS_TYPE_BYTE, &volume);
|
||||
}
|
||||
|
||||
static void set_gain(struct ofono_emulator *em,
|
||||
struct ofono_emulator_request *req,
|
||||
void *userdata, const char *gain)
|
||||
{
|
||||
struct sfos_bt *sfos_bt = userdata;
|
||||
struct ofono_modem *modem = sfos_bt->modem;
|
||||
struct ofono_error result;
|
||||
unsigned char volume;
|
||||
int val;
|
||||
result.error = 0;
|
||||
|
||||
switch (ofono_emulator_request_get_type(req)) {
|
||||
case OFONO_EMULATOR_REQUEST_TYPE_SET:
|
||||
if (ofono_emulator_request_next_number(req, &val) == FALSE)
|
||||
goto fail;
|
||||
|
||||
if (val < 0 || val > 0xffff || val > HFP_CALL_VOLUME_MAX)
|
||||
goto fail;
|
||||
|
||||
DBG("gain:%d", val);
|
||||
|
||||
volume = (unsigned char) val;
|
||||
if (sfos_bt_call_volume_set(modem, volume, gain)<= 0)
|
||||
goto fail;
|
||||
|
||||
if (!g_strcmp0(gain, "SpeakerVolume"))
|
||||
sfos_bt->speaker_volume = volume;
|
||||
else
|
||||
sfos_bt->microphone_volume = volume;
|
||||
|
||||
result.type = OFONO_ERROR_TYPE_NO_ERROR;
|
||||
ofono_emulator_send_final(em, &result);
|
||||
break;
|
||||
|
||||
default:
|
||||
fail:
|
||||
result.type = OFONO_ERROR_TYPE_FAILURE;
|
||||
ofono_emulator_send_final(em, &result);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void sfos_bt_vgm_cb(struct ofono_emulator *em,
|
||||
struct ofono_emulator_request *req, void *userdata)
|
||||
{
|
||||
const char *gain = "MicrophoneVolume";
|
||||
set_gain(em, req, userdata, gain);
|
||||
}
|
||||
|
||||
static void sfos_bt_vgs_cb(struct ofono_emulator *em,
|
||||
struct ofono_emulator_request *req, void *userdata)
|
||||
{
|
||||
const char *gain = "SpeakerVolume";
|
||||
set_gain(em, req, userdata, gain);
|
||||
}
|
||||
|
||||
void sfos_bt_cv_dbus_new(struct sfos_bt *sfos_bt)
|
||||
{
|
||||
DBusConnection *conn = ofono_dbus_get_connection();
|
||||
struct ofono_modem *modem = sfos_bt->modem;
|
||||
const char *path = ofono_modem_get_path(modem);
|
||||
|
||||
if (g_dbus_register_interface(conn, path,
|
||||
SFOS_BT_DBUS_CV_INTERFACE, cv_methods,
|
||||
cv_signals, NULL, sfos_bt, NULL)){
|
||||
ofono_modem_add_interface(modem,SFOS_BT_DBUS_CV_INTERFACE);
|
||||
return;
|
||||
}
|
||||
|
||||
ofono_error("D-Bus register failed");
|
||||
}
|
||||
|
||||
static void sfos_bt_remove_handler(struct ofono_emulator *em)
|
||||
{
|
||||
ofono_emulator_remove_handler(em, "+VGS");
|
||||
ofono_emulator_remove_handler(em, "+VGM");
|
||||
}
|
||||
|
||||
void sfos_bt_cv_dbus_free(struct sfos_bt *sfos_bt)
|
||||
{
|
||||
DBusConnection *conn = ofono_dbus_get_connection();
|
||||
struct ofono_modem *modem = sfos_bt->modem;
|
||||
const char *path = ofono_modem_get_path(modem);
|
||||
ofono_modem_remove_interface(modem, SFOS_BT_DBUS_CV_INTERFACE);
|
||||
g_dbus_unregister_interface(conn, path,
|
||||
SFOS_BT_DBUS_CV_INTERFACE);
|
||||
}
|
||||
|
||||
static void sfos_bt_emu_watch_cb(struct ofono_atom *atom,
|
||||
enum ofono_atom_watch_condition cond,
|
||||
void *data)
|
||||
{
|
||||
struct sfos_bt *sfos_bt = data;
|
||||
|
||||
if (cond == OFONO_ATOM_WATCH_CONDITION_REGISTERED){
|
||||
sfos_bt->em = __ofono_atom_get_data(atom);
|
||||
sfos_bt_cv_dbus_new(sfos_bt);
|
||||
ofono_emulator_add_handler(sfos_bt->em, "+VGS",
|
||||
sfos_bt_vgs_cb, sfos_bt, NULL);
|
||||
ofono_emulator_add_handler(sfos_bt->em, "+VGM",
|
||||
sfos_bt_vgm_cb, sfos_bt, NULL);
|
||||
} else {
|
||||
sfos_bt_cv_dbus_free(sfos_bt);
|
||||
sfos_bt_remove_handler(sfos_bt->em);
|
||||
sfos_bt->em = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void sfos_bt_emu_watch_destroy(void *data)
|
||||
{
|
||||
struct sfos_bt *sfos_bt = data;
|
||||
|
||||
sfos_bt->emu_watch = 0;
|
||||
}
|
||||
|
||||
static void sfos_bt_free(void *data)
|
||||
{
|
||||
struct sfos_bt *sfos_bt = data;
|
||||
|
||||
if (sfos_bt->emu_watch)
|
||||
__ofono_modem_remove_atom_watch(sfos_bt->modem,
|
||||
sfos_bt->emu_watch);
|
||||
|
||||
if (sfos_bt->em) {
|
||||
sfos_bt_cv_dbus_free(sfos_bt);
|
||||
sfos_bt_remove_handler(sfos_bt->em);
|
||||
}
|
||||
|
||||
g_free(sfos_bt);
|
||||
}
|
||||
|
||||
static gint sfos_bt_find_modem(gconstpointer listdata, gconstpointer modem)
|
||||
{
|
||||
const struct sfos_bt *sfos_bt = listdata;
|
||||
|
||||
return (sfos_bt->modem != modem);
|
||||
}
|
||||
|
||||
static void modem_watch(struct ofono_modem *modem, gboolean added, void *user)
|
||||
{
|
||||
struct sfos_bt *sfos_bt;
|
||||
DBG("modem: %p, added: %d", modem, added);
|
||||
|
||||
if (added) {
|
||||
sfos_bt = g_new0(struct sfos_bt, 1);
|
||||
modems = g_slist_append(modems, sfos_bt);
|
||||
sfos_bt->emu_watch = __ofono_modem_add_atom_watch(modem,
|
||||
OFONO_ATOM_TYPE_EMULATOR_HFP, sfos_bt_emu_watch_cb,
|
||||
sfos_bt, sfos_bt_emu_watch_destroy);
|
||||
sfos_bt->modem = modem;
|
||||
} else {
|
||||
GSList *link = g_slist_find_custom(modems, modem,
|
||||
sfos_bt_find_modem);
|
||||
if (link) {
|
||||
sfos_bt_free(link->data);
|
||||
modems = g_slist_delete_link(modems, link);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void call_modemwatch(struct ofono_modem *modem, void *user)
|
||||
{
|
||||
modem_watch(modem, TRUE, user);
|
||||
}
|
||||
|
||||
static int sfos_bt_init(void)
|
||||
{
|
||||
modemwatch_id = __ofono_modemwatch_add(modem_watch, NULL, NULL);
|
||||
__ofono_modem_foreach(call_modemwatch, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void sfos_bt_exit(void)
|
||||
{
|
||||
DBG("");
|
||||
__ofono_modemwatch_remove(modemwatch_id);
|
||||
g_slist_free_full(modems, sfos_bt_free);
|
||||
}
|
||||
|
||||
OFONO_PLUGIN_DEFINE(sfos_bt, "Sailfish OS Bluetooth Plugin", VERSION,
|
||||
OFONO_PLUGIN_PRIORITY_DEFAULT,
|
||||
sfos_bt_init, sfos_bt_exit)
|
||||
129
ofono/plugins/sailfish_manager/sailfish_cell_info.c
Normal file
129
ofono/plugins/sailfish_manager/sailfish_cell_info.c
Normal file
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
* 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 <sailfish_cell_info.h>
|
||||
|
||||
#include <gutil_log.h>
|
||||
|
||||
gint sailfish_cell_compare_location(const struct sailfish_cell *c1,
|
||||
const struct sailfish_cell *c2)
|
||||
{
|
||||
if (c1 && c2) {
|
||||
if (c1->type != c2->type) {
|
||||
return c1->type - c2->type;
|
||||
} else if (c1->type == SAILFISH_CELL_TYPE_GSM) {
|
||||
const struct sailfish_cell_info_gsm *g1;
|
||||
const struct sailfish_cell_info_gsm *g2;
|
||||
|
||||
g1 = &c1->info.gsm;
|
||||
g2 = &c2->info.gsm;
|
||||
if (g1->mcc != g2->mcc) {
|
||||
return g1->mcc - g2->mcc;
|
||||
} else if (g1->mnc != g2->mnc) {
|
||||
return g1->mnc - g2->mnc;
|
||||
} else if (g1->lac != g2->lac) {
|
||||
return g1->lac - g2->lac;
|
||||
} else {
|
||||
return g1->cid - g2->cid;
|
||||
}
|
||||
} else if (c2->type == SAILFISH_CELL_TYPE_WCDMA) {
|
||||
const struct sailfish_cell_info_wcdma *w1;
|
||||
const struct sailfish_cell_info_wcdma *w2;
|
||||
|
||||
w1 = &c1->info.wcdma;
|
||||
w2 = &c2->info.wcdma;
|
||||
if (w1->mcc != w2->mcc) {
|
||||
return w1->mcc - w2->mcc;
|
||||
} else if (w1->mnc != w2->mnc) {
|
||||
return w1->mnc - w2->mnc;
|
||||
} else if (w1->lac != w2->lac) {
|
||||
return w1->lac - w2->lac;
|
||||
} else {
|
||||
return w1->cid - w2->cid;
|
||||
}
|
||||
} else {
|
||||
const struct sailfish_cell_info_lte *l1 =
|
||||
&c1->info.lte;
|
||||
const struct sailfish_cell_info_lte *l2 =
|
||||
&c2->info.lte;
|
||||
|
||||
GASSERT(c1->type == SAILFISH_CELL_TYPE_LTE);
|
||||
l1 = &c1->info.lte;
|
||||
l2 = &c2->info.lte;
|
||||
if (l1->mcc != l2->mcc) {
|
||||
return l1->mcc - l2->mcc;
|
||||
} else if (l1->mnc != l2->mnc) {
|
||||
return l1->mnc - l2->mnc;
|
||||
} else if (l1->ci != l2->ci) {
|
||||
return l1->ci - l2->ci;
|
||||
} else if (l1->pci != l2->pci) {
|
||||
return l1->pci - l2->pci;
|
||||
} else {
|
||||
return l1->tac - l2->tac;
|
||||
}
|
||||
}
|
||||
} else if (c1) {
|
||||
return 1;
|
||||
} else if (c2) {
|
||||
return -1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
gint sailfish_cell_compare_func(gconstpointer v1, gconstpointer v2)
|
||||
{
|
||||
return sailfish_cell_compare_location(v1, v2);
|
||||
}
|
||||
|
||||
struct sailfish_cell_info *sailfish_cell_info_ref
|
||||
(struct sailfish_cell_info *info)
|
||||
{
|
||||
if (info) {
|
||||
info->proc->ref(info);
|
||||
return info;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void sailfish_cell_info_unref(struct sailfish_cell_info *info)
|
||||
{
|
||||
if (info) {
|
||||
info->proc->unref(info);
|
||||
}
|
||||
}
|
||||
|
||||
gulong sailfish_cell_info_add_cells_changed_handler
|
||||
(struct sailfish_cell_info *info,
|
||||
sailfish_cell_info_cb_t cb, void *arg)
|
||||
{
|
||||
return info ? info->proc->add_cells_changed_handler(info, cb, arg) : 0;
|
||||
}
|
||||
|
||||
void sailfish_cell_info_remove_handler(struct sailfish_cell_info *info,
|
||||
gulong id)
|
||||
{
|
||||
if (info) {
|
||||
info->proc->remove_handler(info, id);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
598
ofono/plugins/sailfish_manager/sailfish_cell_info_dbus.c
Normal file
598
ofono/plugins/sailfish_manager/sailfish_cell_info_dbus.c
Normal file
@@ -0,0 +1,598 @@
|
||||
/*
|
||||
* 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 "sailfish_cell_info_dbus.h"
|
||||
#include "sailfish_cell_info.h"
|
||||
|
||||
#include <ofono/modem.h>
|
||||
#include <ofono/dbus.h>
|
||||
#include <ofono/log.h>
|
||||
|
||||
#include <gdbus.h>
|
||||
|
||||
struct sailfish_cell_entry {
|
||||
guint cell_id;
|
||||
char *path;
|
||||
struct sailfish_cell cell;
|
||||
};
|
||||
|
||||
struct sailfish_cell_info_dbus {
|
||||
struct sailfish_cell_info *info;
|
||||
DBusConnection *conn;
|
||||
char *path;
|
||||
gulong handler_id;
|
||||
guint next_cell_id;
|
||||
GSList *entries;
|
||||
};
|
||||
|
||||
#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"
|
||||
|
||||
struct sailfish_cell_property {
|
||||
const char *name;
|
||||
glong off;
|
||||
int flag;
|
||||
};
|
||||
|
||||
#define CELL_GSM_PROPERTY(value,name) \
|
||||
{ #name, G_STRUCT_OFFSET(struct sailfish_cell_info_gsm,name), value }
|
||||
#define CELL_WCDMA_PROPERTY(value,name) \
|
||||
{ #name, G_STRUCT_OFFSET(struct sailfish_cell_info_wcdma,name), value }
|
||||
#define CELL_LTE_PROPERTY(value,name) \
|
||||
{ #name, G_STRUCT_OFFSET(struct sailfish_cell_info_lte,name), value }
|
||||
|
||||
static const struct sailfish_cell_property sailfish_cell_gsm_properties [] = {
|
||||
CELL_GSM_PROPERTY(0x001,mcc),
|
||||
CELL_GSM_PROPERTY(0x002,mnc),
|
||||
CELL_GSM_PROPERTY(0x004,lac),
|
||||
CELL_GSM_PROPERTY(0x008,cid),
|
||||
CELL_GSM_PROPERTY(0x010,arfcn),
|
||||
CELL_GSM_PROPERTY(0x020,bsic),
|
||||
CELL_GSM_PROPERTY(0x040,signalStrength),
|
||||
CELL_GSM_PROPERTY(0x080,bitErrorRate),
|
||||
CELL_GSM_PROPERTY(0x100,timingAdvance)
|
||||
};
|
||||
|
||||
static const struct sailfish_cell_property sailfish_cell_wcdma_properties [] = {
|
||||
CELL_WCDMA_PROPERTY(0x01,mcc),
|
||||
CELL_WCDMA_PROPERTY(0x02,mnc),
|
||||
CELL_WCDMA_PROPERTY(0x04,lac),
|
||||
CELL_WCDMA_PROPERTY(0x08,cid),
|
||||
CELL_WCDMA_PROPERTY(0x10,psc),
|
||||
CELL_WCDMA_PROPERTY(0x20,uarfcn),
|
||||
CELL_WCDMA_PROPERTY(0x40,signalStrength),
|
||||
CELL_WCDMA_PROPERTY(0x80,bitErrorRate)
|
||||
};
|
||||
|
||||
static const struct sailfish_cell_property sailfish_cell_lte_properties [] = {
|
||||
CELL_LTE_PROPERTY(0x001,mcc),
|
||||
CELL_LTE_PROPERTY(0x002,mnc),
|
||||
CELL_LTE_PROPERTY(0x004,ci),
|
||||
CELL_LTE_PROPERTY(0x008,pci),
|
||||
CELL_LTE_PROPERTY(0x010,tac),
|
||||
CELL_LTE_PROPERTY(0x020,earfcn),
|
||||
CELL_LTE_PROPERTY(0x040,signalStrength),
|
||||
CELL_LTE_PROPERTY(0x080,rsrp),
|
||||
CELL_LTE_PROPERTY(0x100,rsrq),
|
||||
CELL_LTE_PROPERTY(0x200,rssnr),
|
||||
CELL_LTE_PROPERTY(0x400,cqi),
|
||||
CELL_LTE_PROPERTY(0x800,timingAdvance)
|
||||
};
|
||||
|
||||
#define SAILFISH_CELL_PROPERTY_REGISTERED 0x1000
|
||||
|
||||
typedef void (*sailfish_cell_info_dbus_append_fn)(DBusMessageIter *it,
|
||||
const struct sailfish_cell_entry *entry);
|
||||
|
||||
static const char *sailfish_cell_info_dbus_cell_type_str
|
||||
(enum sailfish_cell_type type)
|
||||
{
|
||||
switch (type) {
|
||||
case SAILFISH_CELL_TYPE_GSM:
|
||||
return "gsm";
|
||||
case SAILFISH_CELL_TYPE_WCDMA:
|
||||
return "wcdma";
|
||||
case SAILFISH_CELL_TYPE_LTE:
|
||||
return "lte";
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
};
|
||||
|
||||
static const struct sailfish_cell_property *
|
||||
sailfish_cell_info_dbus_cell_properties(
|
||||
enum sailfish_cell_type type, int *count)
|
||||
{
|
||||
switch (type) {
|
||||
case SAILFISH_CELL_TYPE_GSM:
|
||||
*count = G_N_ELEMENTS(sailfish_cell_gsm_properties);
|
||||
return sailfish_cell_gsm_properties;
|
||||
case SAILFISH_CELL_TYPE_WCDMA:
|
||||
*count = G_N_ELEMENTS(sailfish_cell_wcdma_properties);
|
||||
return sailfish_cell_wcdma_properties;
|
||||
case SAILFISH_CELL_TYPE_LTE:
|
||||
*count = G_N_ELEMENTS(sailfish_cell_lte_properties);
|
||||
return sailfish_cell_lte_properties;
|
||||
default:
|
||||
*count = 0;
|
||||
return NULL;
|
||||
}
|
||||
};
|
||||
|
||||
static void sailfish_cell_info_destroy_entry(struct sailfish_cell_entry *entry)
|
||||
{
|
||||
if (entry) {
|
||||
g_free(entry->path);
|
||||
g_free(entry);
|
||||
}
|
||||
}
|
||||
|
||||
static DBusMessage *sailfish_cell_info_dbus_reply(DBusMessage *msg,
|
||||
const struct sailfish_cell_entry *entry,
|
||||
sailfish_cell_info_dbus_append_fn append)
|
||||
{
|
||||
DBusMessage *reply = dbus_message_new_method_return(msg);
|
||||
DBusMessageIter it;
|
||||
|
||||
dbus_message_iter_init_append(reply, &it);
|
||||
append(&it, entry);
|
||||
return reply;
|
||||
}
|
||||
|
||||
static void sailfish_cell_info_dbus_append_version(DBusMessageIter *it,
|
||||
const struct sailfish_cell_entry *entry)
|
||||
{
|
||||
dbus_int32_t version = CELL_DBUS_INTERFACE_VERSION;
|
||||
|
||||
dbus_message_iter_append_basic(it, DBUS_TYPE_INT32, &version);
|
||||
}
|
||||
|
||||
static void sailfish_cell_info_dbus_append_type(DBusMessageIter *it,
|
||||
const struct sailfish_cell_entry *entry)
|
||||
{
|
||||
const char *type =
|
||||
sailfish_cell_info_dbus_cell_type_str(entry->cell.type);
|
||||
|
||||
dbus_message_iter_append_basic(it, DBUS_TYPE_STRING, &type);
|
||||
}
|
||||
|
||||
static void sailfish_cell_info_dbus_append_registered(DBusMessageIter *it,
|
||||
const struct sailfish_cell_entry *entry)
|
||||
{
|
||||
dbus_bool_t registered = entry->cell.registered;
|
||||
|
||||
dbus_message_iter_append_basic(it, DBUS_TYPE_BOOLEAN, ®istered);
|
||||
}
|
||||
|
||||
static void sailfish_cell_info_dbus_append_properties(DBusMessageIter *it,
|
||||
const struct sailfish_cell_entry *entry)
|
||||
{
|
||||
int i, n;
|
||||
DBusMessageIter dict;
|
||||
const struct sailfish_cell *cell = &entry->cell;
|
||||
const struct sailfish_cell_property *prop =
|
||||
sailfish_cell_info_dbus_cell_properties(cell->type, &n);
|
||||
|
||||
dbus_message_iter_open_container(it, DBUS_TYPE_ARRAY, "{sv}", &dict);
|
||||
for (i = 0; i < n; i++) {
|
||||
gint32 value = G_STRUCT_MEMBER(int, &cell->info, prop[i].off);
|
||||
if (value != INT_MAX) {
|
||||
ofono_dbus_dict_append(&dict, prop[i].name,
|
||||
DBUS_TYPE_INT32, &value);
|
||||
}
|
||||
}
|
||||
dbus_message_iter_close_container(it, &dict);
|
||||
}
|
||||
|
||||
static void sailfish_cell_info_dbus_append_all(DBusMessageIter *it,
|
||||
const struct sailfish_cell_entry *entry)
|
||||
{
|
||||
sailfish_cell_info_dbus_append_version(it, entry);
|
||||
sailfish_cell_info_dbus_append_type(it, entry);
|
||||
sailfish_cell_info_dbus_append_registered(it, entry);
|
||||
sailfish_cell_info_dbus_append_properties(it, entry);
|
||||
}
|
||||
|
||||
static DBusMessage *sailfish_cell_info_dbus_cell_get_all
|
||||
(DBusConnection *conn, DBusMessage *msg, void *data)
|
||||
{
|
||||
return sailfish_cell_info_dbus_reply(msg, (struct sailfish_cell_entry*)
|
||||
data, sailfish_cell_info_dbus_append_all);
|
||||
}
|
||||
|
||||
static DBusMessage *sailfish_cell_info_dbus_cell_get_version
|
||||
(DBusConnection *conn, DBusMessage *msg, void *data)
|
||||
{
|
||||
return sailfish_cell_info_dbus_reply(msg, (struct sailfish_cell_entry*)
|
||||
data, sailfish_cell_info_dbus_append_version);
|
||||
}
|
||||
|
||||
static DBusMessage *sailfish_cell_info_dbus_cell_get_type
|
||||
(DBusConnection *conn, DBusMessage *msg, void *data)
|
||||
{
|
||||
return sailfish_cell_info_dbus_reply(msg, (struct sailfish_cell_entry*)
|
||||
data, sailfish_cell_info_dbus_append_type);
|
||||
}
|
||||
|
||||
static DBusMessage *sailfish_cell_info_dbus_cell_get_registered
|
||||
(DBusConnection *conn, DBusMessage *msg, void *data)
|
||||
{
|
||||
return sailfish_cell_info_dbus_reply(msg, (struct sailfish_cell_entry*)
|
||||
data, sailfish_cell_info_dbus_append_registered);
|
||||
}
|
||||
|
||||
static DBusMessage *sailfish_cell_info_dbus_cell_get_properties
|
||||
(DBusConnection *conn, DBusMessage *msg, void *data)
|
||||
{
|
||||
return sailfish_cell_info_dbus_reply(msg, (struct sailfish_cell_entry*)
|
||||
data, sailfish_cell_info_dbus_append_properties);
|
||||
}
|
||||
|
||||
static const GDBusMethodTable sailfish_cell_info_dbus_cell_methods[] = {
|
||||
{ GDBUS_METHOD("GetAll", NULL,
|
||||
GDBUS_ARGS({ "version", "i" },
|
||||
{ "type", "s" },
|
||||
{ "registered", "b" },
|
||||
{ "properties", "a{sv}" }),
|
||||
sailfish_cell_info_dbus_cell_get_all) },
|
||||
{ GDBUS_METHOD("GetInterfaceVersion", NULL,
|
||||
GDBUS_ARGS({ "version", "i" }),
|
||||
sailfish_cell_info_dbus_cell_get_version) },
|
||||
{ GDBUS_METHOD("GetType", NULL,
|
||||
GDBUS_ARGS({ "type", "s" }),
|
||||
sailfish_cell_info_dbus_cell_get_type) },
|
||||
{ GDBUS_METHOD("GetRegistered", NULL,
|
||||
GDBUS_ARGS({ "registered", "b" }),
|
||||
sailfish_cell_info_dbus_cell_get_registered) },
|
||||
{ GDBUS_METHOD("GetProperties", NULL,
|
||||
GDBUS_ARGS({ "properties", "a{sv}" }),
|
||||
sailfish_cell_info_dbus_cell_get_properties) },
|
||||
{ }
|
||||
};
|
||||
|
||||
static const GDBusSignalTable sailfish_cell_info_dbus_cell_signals[] = {
|
||||
{ GDBUS_SIGNAL(CELL_DBUS_REGISTERED_CHANGED_SIGNAL,
|
||||
GDBUS_ARGS({ "registered", "b" })) },
|
||||
{ GDBUS_SIGNAL(CELL_DBUS_PROPERTY_CHANGED_SIGNAL,
|
||||
GDBUS_ARGS({ "name", "s" }, { "value", "v" })) },
|
||||
{ GDBUS_SIGNAL(CELL_DBUS_REMOVED_SIGNAL,
|
||||
GDBUS_ARGS({})) },
|
||||
{ }
|
||||
};
|
||||
|
||||
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) {
|
||||
struct sailfish_cell_entry *entry = l->data;
|
||||
if (entry->cell_id == id) {
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static guint sailfish_cell_info_dbus_next_cell_id
|
||||
(struct sailfish_cell_info_dbus *dbus)
|
||||
{
|
||||
while (sailfish_cell_info_dbus_find_id(dbus, dbus->next_cell_id)) {
|
||||
dbus->next_cell_id++;
|
||||
}
|
||||
return dbus->next_cell_id++;
|
||||
}
|
||||
|
||||
static struct sailfish_cell_entry *sailfish_cell_info_dbus_find_cell
|
||||
(struct sailfish_cell_info_dbus *dbus,
|
||||
const struct sailfish_cell *cell)
|
||||
{
|
||||
if (cell) {
|
||||
GSList *l;
|
||||
for (l = dbus->entries; l; l = l->next) {
|
||||
struct sailfish_cell_entry *entry = l->data;
|
||||
if (!sailfish_cell_compare_location(&entry->cell,
|
||||
cell)) {
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void sailfish_cell_info_dbus_emit_path_list
|
||||
(struct sailfish_cell_info_dbus *dbus, const char *name,
|
||||
GPtrArray *list)
|
||||
{
|
||||
guint i;
|
||||
DBusMessageIter it, array;
|
||||
DBusMessage *signal = dbus_message_new_signal(dbus->path,
|
||||
CELL_INFO_DBUS_INTERFACE, name);
|
||||
|
||||
dbus_message_iter_init_append(signal, &it);
|
||||
dbus_message_iter_open_container(&it, DBUS_TYPE_ARRAY, "o", &array);
|
||||
for (i = 0; i < list->len; i++) {
|
||||
const char* path = list->pdata[i];
|
||||
dbus_message_iter_append_basic(&array, DBUS_TYPE_OBJECT_PATH,
|
||||
&path);
|
||||
}
|
||||
dbus_message_iter_close_container(&it, &array);
|
||||
|
||||
g_dbus_send_message(dbus->conn, signal);
|
||||
}
|
||||
|
||||
static int sailfish_cell_info_dbus_compare(const struct sailfish_cell *c1,
|
||||
const struct sailfish_cell *c2)
|
||||
{
|
||||
if (c1->type == c2->type) {
|
||||
int i, n, mask = 0;
|
||||
const struct sailfish_cell_property *prop =
|
||||
sailfish_cell_info_dbus_cell_properties(c1->type, &n);
|
||||
|
||||
if (c1->registered != c2->registered) {
|
||||
mask |= SAILFISH_CELL_PROPERTY_REGISTERED;
|
||||
}
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
const glong offset = prop[i].off;
|
||||
gint32 v1 = G_STRUCT_MEMBER(int, &c1->info, offset);
|
||||
gint32 v2 = G_STRUCT_MEMBER(int, &c2->info, offset);
|
||||
if (v1 != v2) {
|
||||
mask |= prop[i].flag;
|
||||
}
|
||||
}
|
||||
|
||||
return mask;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static void sailfish_cell_info_dbus_property_changed
|
||||
(struct sailfish_cell_info_dbus *dbus,
|
||||
const struct sailfish_cell_entry *entry, int mask)
|
||||
{
|
||||
int i, n;
|
||||
const struct sailfish_cell *cell = &entry->cell;
|
||||
const struct sailfish_cell_property *prop =
|
||||
sailfish_cell_info_dbus_cell_properties(cell->type, &n);
|
||||
|
||||
if (mask & SAILFISH_CELL_PROPERTY_REGISTERED) {
|
||||
dbus_bool_t registered = cell->registered;
|
||||
g_dbus_emit_signal(dbus->conn, entry->path,
|
||||
CELL_DBUS_INTERFACE,
|
||||
CELL_DBUS_REGISTERED_CHANGED_SIGNAL,
|
||||
DBUS_TYPE_BOOLEAN, ®istered, DBUS_TYPE_INVALID);
|
||||
mask &= ~SAILFISH_CELL_PROPERTY_REGISTERED;
|
||||
}
|
||||
|
||||
for (i = 0; i < n && mask; i++) {
|
||||
if (mask & prop[i].flag) {
|
||||
ofono_dbus_signal_property_changed(dbus->conn,
|
||||
entry->path, CELL_DBUS_INTERFACE,
|
||||
prop[i].name, DBUS_TYPE_INT32,
|
||||
G_STRUCT_MEMBER_P(&cell->info, prop[i].off));
|
||||
mask &= ~prop[i].flag;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void sailfish_cell_info_dbus_update_entries
|
||||
(struct sailfish_cell_info_dbus *dbus, gboolean emit_signals)
|
||||
{
|
||||
GSList *l;
|
||||
GPtrArray* added = NULL;
|
||||
GPtrArray* removed = NULL;
|
||||
|
||||
/* Remove non-existent cells */
|
||||
l = dbus->entries;
|
||||
while (l) {
|
||||
GSList *next = l->next;
|
||||
struct sailfish_cell_entry *entry = l->data;
|
||||
if (!g_slist_find_custom(dbus->info->cells, &entry->cell,
|
||||
sailfish_cell_compare_func)) {
|
||||
DBG("%s removed", entry->path);
|
||||
dbus->entries = g_slist_delete_link(dbus->entries, l);
|
||||
g_dbus_emit_signal(dbus->conn, entry->path,
|
||||
CELL_DBUS_INTERFACE,
|
||||
CELL_DBUS_REMOVED_SIGNAL,
|
||||
DBUS_TYPE_INVALID);
|
||||
g_dbus_unregister_interface(dbus->conn, entry->path,
|
||||
CELL_DBUS_INTERFACE);
|
||||
if (emit_signals) {
|
||||
if (!removed) {
|
||||
removed =
|
||||
g_ptr_array_new_with_free_func(
|
||||
g_free);
|
||||
}
|
||||
/* Steal the path */
|
||||
g_ptr_array_add(removed, entry->path);
|
||||
entry->path = NULL;
|
||||
}
|
||||
sailfish_cell_info_destroy_entry(entry);
|
||||
}
|
||||
l = next;
|
||||
}
|
||||
|
||||
/* Add new cells */
|
||||
for (l = dbus->info->cells; l; l = l->next) {
|
||||
const struct sailfish_cell *cell = l->data;
|
||||
struct sailfish_cell_entry *entry =
|
||||
sailfish_cell_info_dbus_find_cell(dbus, cell);
|
||||
|
||||
if (entry) {
|
||||
if (emit_signals) {
|
||||
int diff = sailfish_cell_info_dbus_compare(cell,
|
||||
&entry->cell);
|
||||
entry->cell = *cell;
|
||||
sailfish_cell_info_dbus_property_changed(dbus,
|
||||
entry, diff);
|
||||
} else {
|
||||
entry->cell = *cell;
|
||||
}
|
||||
} else {
|
||||
entry = g_new0(struct sailfish_cell_entry, 1);
|
||||
entry->cell = *cell;
|
||||
entry->cell_id =
|
||||
sailfish_cell_info_dbus_next_cell_id(dbus);
|
||||
entry->path = g_strdup_printf("%s/cell_%u", dbus->path,
|
||||
entry->cell_id);
|
||||
dbus->entries = g_slist_append(dbus->entries, entry);
|
||||
DBG("%s added", entry->path);
|
||||
g_dbus_register_interface(dbus->conn, entry->path,
|
||||
CELL_DBUS_INTERFACE,
|
||||
sailfish_cell_info_dbus_cell_methods,
|
||||
sailfish_cell_info_dbus_cell_signals, NULL,
|
||||
entry, NULL);
|
||||
if (emit_signals) {
|
||||
if (!added) {
|
||||
added = g_ptr_array_new();
|
||||
}
|
||||
g_ptr_array_add(added, entry->path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (removed) {
|
||||
sailfish_cell_info_dbus_emit_path_list(dbus,
|
||||
CELL_INFO_DBUS_CELLS_REMOVED_SIGNAL, removed);
|
||||
g_ptr_array_free(removed, TRUE);
|
||||
}
|
||||
|
||||
if (added) {
|
||||
sailfish_cell_info_dbus_emit_path_list(dbus,
|
||||
CELL_INFO_DBUS_CELLS_ADDED_SIGNAL, added);
|
||||
g_ptr_array_free(added, TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
static void sailfish_cell_info_dbus_cells_changed_cb
|
||||
(struct sailfish_cell_info *info, void *arg)
|
||||
{
|
||||
DBG("");
|
||||
sailfish_cell_info_dbus_update_entries
|
||||
((struct sailfish_cell_info_dbus *)arg, TRUE);
|
||||
}
|
||||
|
||||
static DBusMessage *sailfish_cell_info_dbus_get_cells(DBusConnection *conn,
|
||||
DBusMessage *msg, void *data)
|
||||
{
|
||||
struct sailfish_cell_info_dbus *dbus = data;
|
||||
DBusMessage *reply = dbus_message_new_method_return(msg);
|
||||
DBusMessageIter it, array;
|
||||
GSList *l;
|
||||
|
||||
dbus_message_iter_init_append(reply, &it);
|
||||
dbus_message_iter_open_container(&it, DBUS_TYPE_ARRAY, "o", &array);
|
||||
for (l = dbus->entries; l; l = l->next) {
|
||||
const struct sailfish_cell_entry *entry = l->data;
|
||||
dbus_message_iter_append_basic(&array, DBUS_TYPE_OBJECT_PATH,
|
||||
&entry->path);
|
||||
}
|
||||
dbus_message_iter_close_container(&it, &array);
|
||||
return reply;
|
||||
}
|
||||
|
||||
static const GDBusMethodTable sailfish_cell_info_dbus_methods[] = {
|
||||
{ GDBUS_METHOD("GetCells", NULL,
|
||||
GDBUS_ARGS({ "paths", "ao" }),
|
||||
sailfish_cell_info_dbus_get_cells) },
|
||||
{ }
|
||||
};
|
||||
|
||||
static const GDBusSignalTable sailfish_cell_info_dbus_signals[] = {
|
||||
{ GDBUS_SIGNAL(CELL_INFO_DBUS_CELLS_ADDED_SIGNAL,
|
||||
GDBUS_ARGS({ "paths", "ao" })) },
|
||||
{ GDBUS_SIGNAL(CELL_INFO_DBUS_CELLS_REMOVED_SIGNAL,
|
||||
GDBUS_ARGS({ "paths", "ao" })) },
|
||||
{ }
|
||||
};
|
||||
|
||||
struct sailfish_cell_info_dbus *sailfish_cell_info_dbus_new
|
||||
(struct ofono_modem *modem, struct sailfish_cell_info *info)
|
||||
{
|
||||
if (modem && info) {
|
||||
struct sailfish_cell_info_dbus *dbus =
|
||||
g_new0(struct sailfish_cell_info_dbus, 1);
|
||||
|
||||
DBG("%s", ofono_modem_get_path(modem));
|
||||
dbus->path = g_strdup(ofono_modem_get_path(modem));
|
||||
dbus->conn = dbus_connection_ref(ofono_dbus_get_connection());
|
||||
dbus->info = sailfish_cell_info_ref(info);
|
||||
dbus->handler_id =
|
||||
sailfish_cell_info_add_cells_changed_handler(info,
|
||||
sailfish_cell_info_dbus_cells_changed_cb, dbus);
|
||||
|
||||
/* Register D-Bus interface */
|
||||
if (g_dbus_register_interface(dbus->conn, dbus->path,
|
||||
CELL_INFO_DBUS_INTERFACE,
|
||||
sailfish_cell_info_dbus_methods,
|
||||
sailfish_cell_info_dbus_signals,
|
||||
NULL, dbus, NULL)) {
|
||||
ofono_modem_add_interface(modem,
|
||||
CELL_INFO_DBUS_INTERFACE);
|
||||
sailfish_cell_info_dbus_update_entries(dbus, FALSE);
|
||||
return dbus;
|
||||
} else {
|
||||
ofono_error("CellInfo D-Bus register failed");
|
||||
sailfish_cell_info_dbus_free(dbus);
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void sailfish_cell_info_dbus_free(struct sailfish_cell_info_dbus *dbus)
|
||||
{
|
||||
if (dbus) {
|
||||
GSList *l;
|
||||
|
||||
DBG("%s", dbus->path);
|
||||
g_dbus_unregister_interface(dbus->conn, dbus->path,
|
||||
CELL_INFO_DBUS_INTERFACE);
|
||||
|
||||
/* Unregister cells */
|
||||
l = dbus->entries;
|
||||
while (l) {
|
||||
struct sailfish_cell_entry *entry = l->data;
|
||||
g_dbus_unregister_interface(dbus->conn, entry->path,
|
||||
CELL_DBUS_INTERFACE);
|
||||
sailfish_cell_info_destroy_entry(entry);
|
||||
l = l->next;
|
||||
}
|
||||
g_slist_free(dbus->entries);
|
||||
|
||||
dbus_connection_unref(dbus->conn);
|
||||
|
||||
sailfish_cell_info_remove_handler(dbus->info, dbus->handler_id);
|
||||
sailfish_cell_info_unref(dbus->info);
|
||||
|
||||
g_free(dbus->path);
|
||||
g_free(dbus);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
*
|
||||
* Copyright (C) 2016 Jolla Ltd.
|
||||
* 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
|
||||
@@ -13,16 +13,19 @@
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef RIL_MTU_H
|
||||
#define RIL_MTU_H
|
||||
#ifndef SAILFISH_CELL_INFO_DBUS_H
|
||||
#define SAILFISH_CELL_INFO_DBUS_H
|
||||
|
||||
#include "ril_types.h"
|
||||
struct ofono_modem;
|
||||
|
||||
struct ril_mtu_watch *ril_mtu_watch_new(int max_mtu);
|
||||
void ril_mtu_watch_free(struct ril_mtu_watch *mw);
|
||||
void ril_mtu_watch_set_ifname(struct ril_mtu_watch *mw, const char *ifname);
|
||||
struct sailfish_cell_info;
|
||||
struct sailfish_cell_info_dbus;
|
||||
|
||||
#endif /* RIL_MTU_H */
|
||||
struct sailfish_cell_info_dbus *sailfish_cell_info_dbus_new
|
||||
(struct ofono_modem *modem, struct sailfish_cell_info *info);
|
||||
void sailfish_cell_info_dbus_free(struct sailfish_cell_info_dbus *dbus);
|
||||
|
||||
#endif /* SAILFISH_CELL_INFO_DBUS_H */
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
1386
ofono/plugins/sailfish_manager/sailfish_manager.c
Normal file
1386
ofono/plugins/sailfish_manager/sailfish_manager.c
Normal file
File diff suppressed because it is too large
Load Diff
1174
ofono/plugins/sailfish_manager/sailfish_manager_dbus.c
Normal file
1174
ofono/plugins/sailfish_manager/sailfish_manager_dbus.c
Normal file
File diff suppressed because it is too large
Load Diff
77
ofono/plugins/sailfish_manager/sailfish_manager_dbus.h
Normal file
77
ofono/plugins/sailfish_manager/sailfish_manager_dbus.h
Normal file
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* 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 SAILFISH_MANAGER_DBUS_H
|
||||
#define SAILFISH_MANAGER_DBUS_H
|
||||
|
||||
#include <sailfish_manager.h>
|
||||
|
||||
struct sailfish_manager_dbus;
|
||||
|
||||
enum sailfish_manager_dbus_block {
|
||||
SAILFISH_MANAGER_DBUS_BLOCK_NONE = 0,
|
||||
SAILFISH_MANAGER_DBUS_BLOCK_MODEM = 0x01,
|
||||
SAILFISH_MANAGER_DBUS_BLOCK_IMEI = 0x02,
|
||||
SAILFISH_MANAGER_DBUS_BLOCK_ALL = 0x03
|
||||
};
|
||||
|
||||
enum sailfish_manager_dbus_signal {
|
||||
SAILFISH_MANAGER_SIGNAL_NONE = 0,
|
||||
SAILFISH_MANAGER_SIGNAL_VOICE_IMSI = 0x01,
|
||||
SAILFISH_MANAGER_SIGNAL_DATA_IMSI = 0x02,
|
||||
SAILFISH_MANAGER_SIGNAL_VOICE_PATH = 0x04,
|
||||
SAILFISH_MANAGER_SIGNAL_DATA_PATH = 0x08,
|
||||
SAILFISH_MANAGER_SIGNAL_ENABLED_SLOTS = 0x10,
|
||||
SAILFISH_MANAGER_SIGNAL_MMS_IMSI = 0x20,
|
||||
SAILFISH_MANAGER_SIGNAL_MMS_PATH = 0x40,
|
||||
SAILFISH_MANAGER_SIGNAL_READY = 0x80
|
||||
};
|
||||
|
||||
/* Functionality provided by sailfish_manager to sailfish_manager_dbus */
|
||||
struct sailfish_manager_dbus_cb {
|
||||
GHashTable *(*get_errors)(struct sailfish_manager *m);
|
||||
GHashTable *(*get_slot_errors)(const struct sailfish_slot *s);
|
||||
void (*set_enabled_slots)(struct sailfish_manager *m, char **slots);
|
||||
gboolean (*set_mms_imsi)(struct sailfish_manager *m, const char *imsi);
|
||||
void (*set_default_voice_imsi)(struct sailfish_manager *m,
|
||||
const char *imsi);
|
||||
void (*set_default_data_imsi)(struct sailfish_manager *m,
|
||||
const char *imsi);
|
||||
};
|
||||
|
||||
struct sailfish_manager_dbus *sailfish_manager_dbus_new
|
||||
(struct sailfish_manager *m,
|
||||
const struct sailfish_manager_dbus_cb *cb);
|
||||
void sailfish_manager_dbus_free(struct sailfish_manager_dbus *d);
|
||||
void sailfish_manager_dbus_set_block(struct sailfish_manager_dbus *d,
|
||||
enum sailfish_manager_dbus_block b);
|
||||
void sailfish_manager_dbus_signal(struct sailfish_manager_dbus *d,
|
||||
enum sailfish_manager_dbus_signal m);
|
||||
void sailfish_manager_dbus_signal_sim(struct sailfish_manager_dbus *d,
|
||||
int index, gboolean present);
|
||||
void sailfish_manager_dbus_signal_error(struct sailfish_manager_dbus *d,
|
||||
const char *id, const char *message);
|
||||
void sailfish_manager_dbus_signal_modem_error(struct sailfish_manager_dbus *d,
|
||||
int index, const char *id, const char *msg);
|
||||
|
||||
#endif /* SAILFISH_MANAGER_DBUS_H */
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
614
ofono/plugins/sailfish_manager/sailfish_sim_info.c
Normal file
614
ofono/plugins/sailfish_manager/sailfish_sim_info.c
Normal file
@@ -0,0 +1,614 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include "sailfish_sim_info.h"
|
||||
#include "sailfish_watch.h"
|
||||
|
||||
#include <gutil_misc.h>
|
||||
#include <gutil_log.h>
|
||||
|
||||
#include "ofono.h"
|
||||
#include "common.h"
|
||||
#include "storage.h"
|
||||
|
||||
#define SAILFISH_SIM_INFO_STORE "cache"
|
||||
#define SAILFISH_SIM_INFO_STORE_GROUP "sim"
|
||||
#define SAILFISH_SIM_INFO_STORE_SPN "spn"
|
||||
|
||||
/* ICCID -> IMSI map */
|
||||
#define SAILFISH_SIM_ICCID_MAP "iccidmap"
|
||||
#define SAILFISH_SIM_ICCID_MAP_IMSI "imsi"
|
||||
|
||||
#define DEFAULT_SPN_BUFSIZE 8
|
||||
G_STATIC_ASSERT(DEFAULT_SPN_BUFSIZE >= \
|
||||
OFONO_MAX_MCC_LENGTH + OFONO_MAX_MNC_LENGTH + 1);
|
||||
|
||||
typedef GObjectClass SailfishSimInfoClass;
|
||||
typedef struct sailfish_sim_info SailfishSimInfo;
|
||||
|
||||
enum sailfish_watch_events {
|
||||
WATCH_EVENT_SIM,
|
||||
WATCH_EVENT_SIM_STATE,
|
||||
WATCH_EVENT_ICCID,
|
||||
WATCH_EVENT_IMSI,
|
||||
WATCH_EVENT_SPN,
|
||||
WATCH_EVENT_NETREG,
|
||||
WATCH_EVENT_COUNT
|
||||
};
|
||||
|
||||
struct sailfish_sim_info_priv {
|
||||
struct sailfish_watch *watch;
|
||||
struct ofono_netreg *netreg;
|
||||
char *iccid;
|
||||
char *imsi;
|
||||
char *cached_spn;
|
||||
char *sim_spn;
|
||||
char *public_spn;
|
||||
char default_spn[DEFAULT_SPN_BUFSIZE];
|
||||
gulong watch_event_id[WATCH_EVENT_COUNT];
|
||||
guint netreg_status_watch_id;
|
||||
gboolean update_imsi_cache;
|
||||
gboolean update_iccid_map;
|
||||
};
|
||||
|
||||
enum sailfish_sim_info_signal {
|
||||
SIGNAL_ICCID_CHANGED,
|
||||
SIGNAL_IMSI_CHANGED,
|
||||
SIGNAL_SPN_CHANGED,
|
||||
SIGNAL_COUNT
|
||||
};
|
||||
|
||||
#define SIGNAL_ICCID_CHANGED_NAME "sailfish-siminfo-iccid-changed"
|
||||
#define SIGNAL_IMSI_CHANGED_NAME "sailfish-siminfo-imsi-changed"
|
||||
#define SIGNAL_SPN_CHANGED_NAME "sailfish-siminfo-spn-changed"
|
||||
|
||||
static guint sailfish_sim_info_signals[SIGNAL_COUNT] = { 0 };
|
||||
|
||||
G_DEFINE_TYPE(SailfishSimInfo, sailfish_sim_info, G_TYPE_OBJECT)
|
||||
#define SAILFISH_SIMINFO_TYPE (sailfish_sim_info_get_type())
|
||||
#define SAILFISH_SIMINFO(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),\
|
||||
SAILFISH_SIMINFO_TYPE, SailfishSimInfo))
|
||||
|
||||
#define NEW_SIGNAL(klass,name) \
|
||||
sailfish_sim_info_signals[SIGNAL_##name##_CHANGED] = \
|
||||
g_signal_new(SIGNAL_##name##_CHANGED_NAME, \
|
||||
G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_FIRST, \
|
||||
0, NULL, NULL, NULL, G_TYPE_NONE, 0)
|
||||
|
||||
/* Skip the leading slash from the modem path: */
|
||||
#define DBG_(obj,fmt,args...) DBG("%s " fmt, (obj)->path+1, ##args)
|
||||
|
||||
static void sailfish_sim_info_signal_emit(struct sailfish_sim_info *self,
|
||||
enum sailfish_sim_info_signal id)
|
||||
{
|
||||
g_signal_emit(self, sailfish_sim_info_signals[id], 0);
|
||||
}
|
||||
|
||||
static void sailfish_sim_info_update_imsi_cache(struct sailfish_sim_info *self)
|
||||
{
|
||||
struct sailfish_sim_info_priv *priv = self->priv;
|
||||
|
||||
if (priv->update_imsi_cache && priv->imsi && priv->imsi[0] &&
|
||||
priv->cached_spn && priv->cached_spn[0]) {
|
||||
gboolean save = FALSE;
|
||||
const char *store = SAILFISH_SIM_INFO_STORE;
|
||||
GKeyFile *cache = storage_open(priv->imsi, store);
|
||||
char *spn = g_key_file_get_string(cache,
|
||||
SAILFISH_SIM_INFO_STORE_GROUP,
|
||||
SAILFISH_SIM_INFO_STORE_SPN, NULL);
|
||||
|
||||
if (g_strcmp0(priv->cached_spn, spn)) {
|
||||
save = TRUE;
|
||||
g_key_file_set_string(cache,
|
||||
SAILFISH_SIM_INFO_STORE_GROUP,
|
||||
SAILFISH_SIM_INFO_STORE_SPN,
|
||||
priv->cached_spn);
|
||||
}
|
||||
|
||||
/*
|
||||
* Since we are most likely running on flash which
|
||||
* supports a limited number of writes, don't overwrite
|
||||
* the file unless something has actually changed.
|
||||
*/
|
||||
if (save) {
|
||||
DBG_(self, "updating " STORAGEDIR "/%s/%s",
|
||||
priv->imsi, store);
|
||||
storage_close(priv->imsi, store, cache, TRUE);
|
||||
} else {
|
||||
g_key_file_free(cache);
|
||||
}
|
||||
|
||||
g_free(spn);
|
||||
priv->update_imsi_cache = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static void sailfish_sim_info_update_iccid_map(struct sailfish_sim_info *self)
|
||||
{
|
||||
struct sailfish_sim_info_priv *priv = self->priv;
|
||||
|
||||
if (priv->update_iccid_map && priv->iccid && priv->iccid[0] &&
|
||||
priv->imsi && priv->imsi[0]) {
|
||||
const char *store = SAILFISH_SIM_ICCID_MAP;
|
||||
GKeyFile *map = storage_open(NULL, store);
|
||||
char *imsi = g_key_file_get_string(map,
|
||||
SAILFISH_SIM_ICCID_MAP_IMSI, priv->iccid, NULL);
|
||||
|
||||
/*
|
||||
* Since we are most likely running on flash which
|
||||
* supports a limited number of writes, don't overwrite
|
||||
* the file unless something has actually changed.
|
||||
*/
|
||||
if (g_strcmp0(imsi, priv->imsi)) {
|
||||
DBG_(self, "updating " STORAGEDIR "/%s", store);
|
||||
g_key_file_set_string(map, SAILFISH_SIM_ICCID_MAP_IMSI,
|
||||
priv->iccid, priv->imsi);
|
||||
storage_close(NULL, store, map, TRUE);
|
||||
} else {
|
||||
g_key_file_free(map);
|
||||
}
|
||||
|
||||
g_free(imsi);
|
||||
priv->update_iccid_map = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static void sailfish_sim_info_update_public_spn(struct sailfish_sim_info *self)
|
||||
{
|
||||
struct sailfish_sim_info_priv *priv = self->priv;
|
||||
const char *spn = priv->sim_spn ? priv->sim_spn :
|
||||
priv->cached_spn ? priv->cached_spn :
|
||||
priv->default_spn;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
static void sailfish_sim_info_set_cached_spn(struct sailfish_sim_info *self,
|
||||
const char *spn)
|
||||
{
|
||||
struct sailfish_sim_info_priv *priv = self->priv;
|
||||
|
||||
if (g_strcmp0(priv->cached_spn, 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;
|
||||
}
|
||||
sailfish_sim_info_update_public_spn(self);
|
||||
}
|
||||
}
|
||||
|
||||
static void sailfish_sim_info_set_spn(struct sailfish_sim_info *self,
|
||||
const char *spn)
|
||||
{
|
||||
struct sailfish_sim_info_priv *priv = self->priv;
|
||||
|
||||
if (g_strcmp0(priv->sim_spn, spn)) {
|
||||
DBG_(self, "%s", spn);
|
||||
g_free(priv->sim_spn);
|
||||
priv->sim_spn = g_strdup(spn);
|
||||
priv->update_imsi_cache = TRUE;
|
||||
sailfish_sim_info_set_cached_spn(self, spn);
|
||||
sailfish_sim_info_update_imsi_cache(self);
|
||||
sailfish_sim_info_update_public_spn(self);
|
||||
}
|
||||
}
|
||||
|
||||
static void sailfish_sim_info_update_spn(struct sailfish_sim_info *self)
|
||||
{
|
||||
struct sailfish_watch *watch = self->priv->watch;
|
||||
|
||||
if (watch->spn && watch->spn[0]) {
|
||||
sailfish_sim_info_set_spn(self, watch->spn);
|
||||
}
|
||||
}
|
||||
|
||||
static void sailfish_sim_info_update_default_spn(struct sailfish_sim_info *self)
|
||||
{
|
||||
struct sailfish_sim_info_priv *priv = self->priv;
|
||||
struct ofono_sim *sim = priv->watch->sim;
|
||||
char buf[DEFAULT_SPN_BUFSIZE];
|
||||
const char *mcc = NULL;
|
||||
const char *mnc = NULL;
|
||||
|
||||
if (sim && ofono_sim_get_state(sim) == OFONO_SIM_STATE_READY) {
|
||||
mcc = ofono_sim_get_mcc(sim);
|
||||
mnc = ofono_sim_get_mnc(sim);
|
||||
}
|
||||
|
||||
if (mcc && mnc) {
|
||||
snprintf(buf, DEFAULT_SPN_BUFSIZE, "%s%s", mcc, mnc);
|
||||
buf[DEFAULT_SPN_BUFSIZE - 1] = 0;
|
||||
} else {
|
||||
buf[0] = 0;
|
||||
}
|
||||
|
||||
if (strcmp(buf, priv->default_spn)) {
|
||||
strncpy(priv->default_spn, buf, DEFAULT_SPN_BUFSIZE);
|
||||
DBG_(self, "default spn \"%s\"", priv->default_spn);
|
||||
sailfish_sim_info_update_public_spn(self);
|
||||
}
|
||||
}
|
||||
|
||||
static void sailfish_sim_info_set_imsi(struct sailfish_sim_info *self,
|
||||
const char *imsi)
|
||||
{
|
||||
struct sailfish_sim_info_priv *priv = self->priv;
|
||||
|
||||
if (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);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
static void sailfish_sim_info_network_check(struct sailfish_sim_info *self)
|
||||
{
|
||||
struct sailfish_sim_info_priv *priv = self->priv;
|
||||
struct ofono_sim *sim = priv->watch->sim;
|
||||
enum network_registration_status reg_status =
|
||||
ofono_netreg_get_status(priv->netreg);
|
||||
|
||||
if (sim && ofono_sim_get_state(sim) == OFONO_SIM_STATE_READY &&
|
||||
(reg_status == NETWORK_REGISTRATION_STATUS_REGISTERED ||
|
||||
reg_status == NETWORK_REGISTRATION_STATUS_ROAMING)) {
|
||||
const char *sim_mcc = ofono_sim_get_mcc(sim);
|
||||
const char *sim_mnc = ofono_sim_get_mnc(sim);
|
||||
const char *net_mcc = ofono_netreg_get_mcc(priv->netreg);
|
||||
const char *net_mnc = ofono_netreg_get_mnc(priv->netreg);
|
||||
const char *name = ofono_netreg_get_name(priv->netreg);
|
||||
|
||||
if (sim_mcc && sim_mcc[0] && sim_mnc && sim_mnc[0] &&
|
||||
net_mcc && net_mcc[0] && net_mnc && net_mnc[0] &&
|
||||
name && name[0] && !strcmp(sim_mcc, net_mcc) &&
|
||||
!strcmp(sim_mnc, net_mnc)) {
|
||||
|
||||
/*
|
||||
* If EFspn is present then sim_spn should be set
|
||||
* before we get registered with the network.
|
||||
*/
|
||||
DBG_(self, "home network \"%s\"", name);
|
||||
if (!priv->sim_spn) {
|
||||
sailfish_sim_info_set_cached_spn(self, name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void sailfish_sim_info_load_cache(struct sailfish_sim_info *self)
|
||||
{
|
||||
struct sailfish_sim_info_priv *priv = self->priv;
|
||||
|
||||
if (priv->iccid && priv->iccid[0]) {
|
||||
GKeyFile *map = storage_open(NULL, SAILFISH_SIM_ICCID_MAP);
|
||||
char *imsi = g_key_file_get_string(map,
|
||||
SAILFISH_SIM_ICCID_MAP_IMSI, priv->iccid, NULL);
|
||||
g_key_file_free(map);
|
||||
|
||||
if (imsi && imsi[0] && g_strcmp0(priv->imsi, imsi)) {
|
||||
if (priv->imsi && priv->imsi[0]) {
|
||||
/* Need to update ICCID -> IMSI map */
|
||||
DBG_(self, "IMSI changed %s -> %s",
|
||||
priv->imsi, imsi);
|
||||
priv->update_imsi_cache = TRUE;
|
||||
}
|
||||
g_free(priv->imsi);
|
||||
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,
|
||||
SIGNAL_IMSI_CHANGED);
|
||||
} else if (imsi) {
|
||||
g_free(imsi);
|
||||
} else {
|
||||
DBG_(self, "no imsi for iccid %s", priv->iccid);
|
||||
}
|
||||
}
|
||||
|
||||
if (priv->imsi && priv->imsi[0]) {
|
||||
GKeyFile *cache = storage_open(priv->imsi,
|
||||
SAILFISH_SIM_INFO_STORE);
|
||||
char *spn = g_key_file_get_string(cache,
|
||||
SAILFISH_SIM_INFO_STORE_GROUP,
|
||||
SAILFISH_SIM_INFO_STORE_SPN, NULL);
|
||||
g_key_file_free(cache);
|
||||
|
||||
if (spn && spn[0] && g_strcmp0(priv->cached_spn, spn)) {
|
||||
if (priv->cached_spn && priv->cached_spn[0]) {
|
||||
/* Need to update the cache file */
|
||||
DBG_(self, "spn changing %s -> %s",
|
||||
priv->cached_spn, spn);
|
||||
priv->update_imsi_cache = TRUE;
|
||||
}
|
||||
g_free(priv->cached_spn);
|
||||
priv->cached_spn = spn;
|
||||
DBG_(self, "spn[%s] = \"%s\"", priv->imsi, spn);
|
||||
sailfish_sim_info_update_imsi_cache(self);
|
||||
sailfish_sim_info_update_public_spn(self);
|
||||
} else if (spn) {
|
||||
g_free(spn);
|
||||
} else {
|
||||
DBG_(self, "no spn for imsi %s", priv->imsi);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void sailfish_sim_info_set_iccid(struct sailfish_sim_info *self,
|
||||
const char *iccid)
|
||||
{
|
||||
struct sailfish_sim_info_priv *priv = self->priv;
|
||||
|
||||
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);
|
||||
if (iccid) {
|
||||
sailfish_sim_info_load_cache(self);
|
||||
} else {
|
||||
if (priv->imsi) {
|
||||
g_free(priv->imsi);
|
||||
self->imsi = priv->imsi = NULL;
|
||||
sailfish_sim_info_signal_emit(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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
struct sailfish_sim_info *self = SAILFISH_SIMINFO(data);
|
||||
|
||||
DBG_(self, "%s", watch->iccid);
|
||||
sailfish_sim_info_set_iccid(self, watch->iccid);
|
||||
}
|
||||
|
||||
static void sailfish_sim_info_imsi_watch_cb(struct sailfish_watch *watch,
|
||||
void *data)
|
||||
{
|
||||
sailfish_sim_info_update_imsi(SAILFISH_SIMINFO(data));
|
||||
}
|
||||
|
||||
static void sailfish_sim_info_spn_watch_cb(struct sailfish_watch *watch,
|
||||
void *data)
|
||||
{
|
||||
sailfish_sim_info_update_spn(SAILFISH_SIMINFO(data));
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
static void sailfish_sim_info_netreg_watch_done(void *data)
|
||||
{
|
||||
struct sailfish_sim_info *self = SAILFISH_SIMINFO(data);
|
||||
struct sailfish_sim_info_priv *priv = self->priv;
|
||||
|
||||
GASSERT(priv->netreg_status_watch_id);
|
||||
priv->netreg_status_watch_id = 0;
|
||||
}
|
||||
|
||||
static void sailfish_sim_info_set_netreg(struct sailfish_sim_info *self,
|
||||
struct ofono_netreg *netreg)
|
||||
{
|
||||
struct sailfish_sim_info_priv *priv = self->priv;
|
||||
|
||||
if (priv->netreg != netreg) {
|
||||
if (netreg) {
|
||||
DBG_(self, "netreg attached");
|
||||
priv->netreg = netreg;
|
||||
priv->netreg_status_watch_id =
|
||||
__ofono_netreg_add_status_watch(netreg,
|
||||
sailfish_sim_info_netreg_watch, self,
|
||||
sailfish_sim_info_netreg_watch_done);
|
||||
sailfish_sim_info_network_check(self);
|
||||
} else if (priv->netreg) {
|
||||
if (priv->netreg_status_watch_id) {
|
||||
__ofono_netreg_remove_status_watch(priv->netreg,
|
||||
priv->netreg_status_watch_id);
|
||||
GASSERT(!priv->netreg_status_watch_id);
|
||||
}
|
||||
DBG_(self, "netreg detached");
|
||||
priv->netreg = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 *sailfish_sim_info_new(const char *path)
|
||||
{
|
||||
struct sailfish_sim_info *self = NULL;
|
||||
|
||||
if (path) {
|
||||
struct sailfish_watch *watch = sailfish_watch_new(path);
|
||||
struct sailfish_sim_info_priv *priv;
|
||||
|
||||
self = g_object_new(SAILFISH_SIMINFO_TYPE, NULL);
|
||||
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);
|
||||
priv->watch_event_id[WATCH_EVENT_IMSI] =
|
||||
sailfish_watch_add_imsi_changed_handler(watch,
|
||||
sailfish_sim_info_imsi_watch_cb, self);
|
||||
priv->watch_event_id[WATCH_EVENT_SPN] =
|
||||
sailfish_watch_add_spn_changed_handler(watch,
|
||||
sailfish_sim_info_spn_watch_cb, self);
|
||||
priv->watch_event_id[WATCH_EVENT_NETREG] =
|
||||
sailfish_watch_add_netreg_changed_handler(watch,
|
||||
sailfish_sim_info_netreg_changed, self);
|
||||
sailfish_sim_info_set_iccid(self, watch->iccid);
|
||||
sailfish_sim_info_set_netreg(self, watch->netreg);
|
||||
sailfish_sim_info_update_imsi(self);
|
||||
sailfish_sim_info_update_spn(self);
|
||||
sailfish_sim_info_network_check(self);
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
struct sailfish_sim_info *sailfish_sim_info_ref(struct sailfish_sim_info *self)
|
||||
{
|
||||
if (self) {
|
||||
g_object_ref(SAILFISH_SIMINFO(self));
|
||||
return self;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void sailfish_sim_info_unref(struct sailfish_sim_info *self)
|
||||
{
|
||||
if (self) {
|
||||
g_object_unref(SAILFISH_SIMINFO(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)
|
||||
{
|
||||
return (s && cb) ? g_signal_connect(s, SIGNAL_ICCID_CHANGED_NAME,
|
||||
G_CALLBACK(cb), arg) : 0;
|
||||
}
|
||||
|
||||
gulong sailfish_sim_info_add_imsi_changed_handler(struct sailfish_sim_info *s,
|
||||
sailfish_sim_info_cb_t cb, void *arg)
|
||||
{
|
||||
return (s && cb) ? g_signal_connect(s, SIGNAL_IMSI_CHANGED_NAME,
|
||||
G_CALLBACK(cb), arg) : 0;
|
||||
}
|
||||
|
||||
gulong sailfish_sim_info_add_spn_changed_handler(struct sailfish_sim_info *s,
|
||||
sailfish_sim_info_cb_t cb, void *arg)
|
||||
{
|
||||
return (s && cb) ? g_signal_connect(s, SIGNAL_SPN_CHANGED_NAME,
|
||||
G_CALLBACK(cb), arg) : 0;
|
||||
}
|
||||
|
||||
void sailfish_sim_info_remove_handler(struct sailfish_sim_info *s, gulong id)
|
||||
{
|
||||
if (s && id) {
|
||||
g_signal_handler_disconnect(s, id);
|
||||
}
|
||||
}
|
||||
|
||||
void sailfish_sim_info_remove_handlers(struct sailfish_sim_info *self,
|
||||
gulong *ids, int count)
|
||||
{
|
||||
gutil_disconnect_handlers(self, ids, count);
|
||||
}
|
||||
|
||||
static void sailfish_sim_info_init(struct sailfish_sim_info *self)
|
||||
{
|
||||
self->priv = G_TYPE_INSTANCE_GET_PRIVATE(self, SAILFISH_SIMINFO_TYPE,
|
||||
struct sailfish_sim_info_priv);
|
||||
}
|
||||
|
||||
static void sailfish_sim_info_finalize(GObject *object)
|
||||
{
|
||||
struct sailfish_sim_info *self = SAILFISH_SIMINFO(object);
|
||||
struct sailfish_sim_info_priv *priv = self->priv;
|
||||
|
||||
sailfish_watch_remove_all_handlers(priv->watch, priv->watch_event_id);
|
||||
sailfish_watch_unref(priv->watch);
|
||||
g_free(priv->iccid);
|
||||
g_free(priv->imsi);
|
||||
g_free(priv->sim_spn);
|
||||
g_free(priv->cached_spn);
|
||||
g_free(priv->public_spn);
|
||||
G_OBJECT_CLASS(sailfish_sim_info_parent_class)->finalize(object);
|
||||
}
|
||||
|
||||
static void sailfish_sim_info_class_init(SailfishSimInfoClass *klass)
|
||||
{
|
||||
G_OBJECT_CLASS(klass)->finalize = sailfish_sim_info_finalize;
|
||||
g_type_class_add_private(klass, sizeof(struct sailfish_sim_info_priv));
|
||||
NEW_SIGNAL(klass, ICCID);
|
||||
NEW_SIGNAL(klass, IMSI);
|
||||
NEW_SIGNAL(klass, SPN);
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
81
ofono/plugins/sailfish_manager/sailfish_sim_info.h
Normal file
81
ofono/plugins/sailfish_manager/sailfish_sim_info.h
Normal file
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef SAILFISH_SIM_INFO_H
|
||||
#define SAILFISH_SIM_INFO_H
|
||||
|
||||
#include <ofono/types.h>
|
||||
|
||||
#include <glib.h>
|
||||
#include <glib-object.h>
|
||||
|
||||
/*
|
||||
* Note that iccid, imsi and spn provided by this class can be cached,
|
||||
* i.e. become available before the pin code is entered and before those
|
||||
* are known to the ofono core. That's the whole purpose of this thing.
|
||||
*
|
||||
* If you need to follow imsi known to the ofono core, you can use
|
||||
* sailfish_sim_settings for that (or fight with ofono imsi watchers
|
||||
* directly).
|
||||
*/
|
||||
struct ofono_modem;
|
||||
struct sailfish_sim_info_priv;
|
||||
struct sailfish_sim_info {
|
||||
GObject object;
|
||||
struct sailfish_sim_info_priv *priv;
|
||||
const char *path;
|
||||
const char *iccid;
|
||||
const char *imsi;
|
||||
const char *spn;
|
||||
};
|
||||
|
||||
typedef void (*sailfish_sim_info_cb_t)(struct sailfish_sim_info *si,
|
||||
void *user_data);
|
||||
|
||||
/* SIM info object associated with the particular slot */
|
||||
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,
|
||||
sailfish_sim_info_cb_t cb, void *user_data);
|
||||
gulong sailfish_sim_info_add_spn_changed_handler(struct sailfish_sim_info *si,
|
||||
sailfish_sim_info_cb_t cb, void *user_data);
|
||||
void sailfish_sim_info_remove_handler(struct sailfish_sim_info *si, gulong id);
|
||||
void sailfish_sim_info_remove_handlers(struct sailfish_sim_info *si,
|
||||
gulong *ids, int count);
|
||||
|
||||
#define sailfish_sim_info_remove_all_handlers(si,ids) \
|
||||
sailfish_sim_info_remove_handlers(si, ids, G_N_ELEMENTS(ids))
|
||||
|
||||
/* And the D-Bus interface for it */
|
||||
struct sailfish_sim_info_dbus;
|
||||
struct sailfish_sim_info_dbus *sailfish_sim_info_dbus_new
|
||||
(struct sailfish_sim_info *si);
|
||||
struct sailfish_sim_info_dbus *sailfish_sim_info_dbus_new_path
|
||||
(const char *path);
|
||||
void sailfish_sim_info_dbus_free(struct sailfish_sim_info_dbus *dbus);
|
||||
|
||||
#endif /* SAILFISH_SIM_INFO_H */
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
296
ofono/plugins/sailfish_manager/sailfish_sim_info_dbus.c
Normal file
296
ofono/plugins/sailfish_manager/sailfish_sim_info_dbus.c
Normal file
@@ -0,0 +1,296 @@
|
||||
/*
|
||||
* 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 "sailfish_sim_info.h"
|
||||
#include "sailfish_watch.h"
|
||||
|
||||
#include <ofono/dbus.h>
|
||||
|
||||
#include <gdbus.h>
|
||||
|
||||
#include "ofono.h"
|
||||
|
||||
enum watch_event_id {
|
||||
WATCH_EVENT_MODEM,
|
||||
WATCH_EVENT_COUNT
|
||||
};
|
||||
|
||||
enum sim_info_event_id {
|
||||
SIM_INFO_EVENT_ICCID,
|
||||
SIM_INFO_EVENT_IMSI,
|
||||
SIM_INFO_EVENT_SPN,
|
||||
SIM_INFO_EVENT_COUNT
|
||||
};
|
||||
|
||||
struct sailfish_sim_info_dbus {
|
||||
struct sailfish_sim_info *info;
|
||||
struct sailfish_watch *watch;
|
||||
DBusConnection *conn;
|
||||
gulong watch_event_id[WATCH_EVENT_COUNT];
|
||||
gulong info_event_id[SIM_INFO_EVENT_COUNT];
|
||||
};
|
||||
|
||||
#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 void sailfish_sim_info_dbus_append_version(DBusMessageIter *it)
|
||||
{
|
||||
const dbus_int32_t version = SIM_INFO_DBUS_INTERFACE_VERSION;
|
||||
|
||||
dbus_message_iter_append_basic(it, DBUS_TYPE_INT32, &version);
|
||||
}
|
||||
|
||||
static void sailfish_sim_info_dbus_append_string(DBusMessageIter *it,
|
||||
const char *str)
|
||||
{
|
||||
if (!str) str = "";
|
||||
dbus_message_iter_append_basic(it, DBUS_TYPE_STRING, &str);
|
||||
}
|
||||
|
||||
static DBusMessage *sailfish_sim_info_dbus_reply_with_string(DBusMessage *msg,
|
||||
const char *str)
|
||||
{
|
||||
DBusMessage *reply = dbus_message_new_method_return(msg);
|
||||
DBusMessageIter iter;
|
||||
|
||||
dbus_message_iter_init_append(reply, &iter);
|
||||
sailfish_sim_info_dbus_append_string(&iter, str);
|
||||
return reply;
|
||||
}
|
||||
|
||||
static DBusMessage *sailfish_sim_info_dbus_get_all(DBusConnection *conn,
|
||||
DBusMessage *msg, void *data)
|
||||
{
|
||||
struct sailfish_sim_info_dbus *dbus = data;
|
||||
struct sailfish_sim_info *info = dbus->info;
|
||||
DBusMessage *reply = dbus_message_new_method_return(msg);
|
||||
DBusMessageIter it;
|
||||
|
||||
dbus_message_iter_init_append(reply, &it);
|
||||
sailfish_sim_info_dbus_append_version(&it);
|
||||
sailfish_sim_info_dbus_append_string(&it, info->iccid);
|
||||
sailfish_sim_info_dbus_append_string(&it, info->imsi);
|
||||
sailfish_sim_info_dbus_append_string(&it, info->spn);
|
||||
return reply;
|
||||
}
|
||||
|
||||
static DBusMessage *sailfish_sim_info_dbus_get_version(DBusConnection *dc,
|
||||
DBusMessage *msg, void *data)
|
||||
{
|
||||
DBusMessage *reply = dbus_message_new_method_return(msg);
|
||||
DBusMessageIter it;
|
||||
|
||||
dbus_message_iter_init_append(reply, &it);
|
||||
sailfish_sim_info_dbus_append_version(&it);
|
||||
return reply;
|
||||
}
|
||||
|
||||
static DBusMessage *sailfish_sim_info_dbus_get_iccid(DBusConnection *conn,
|
||||
DBusMessage *msg, void *data)
|
||||
{
|
||||
struct sailfish_sim_info_dbus *dbus = data;
|
||||
|
||||
return sailfish_sim_info_dbus_reply_with_string(msg, dbus->info->iccid);
|
||||
}
|
||||
|
||||
static DBusMessage *sailfish_sim_info_dbus_get_imsi(DBusConnection *conn,
|
||||
DBusMessage *msg, void *data)
|
||||
{
|
||||
struct sailfish_sim_info_dbus *dbus = data;
|
||||
|
||||
return sailfish_sim_info_dbus_reply_with_string(msg, dbus->info->imsi);
|
||||
}
|
||||
|
||||
static DBusMessage *sailfish_sim_info_dbus_get_spn(DBusConnection *conn,
|
||||
DBusMessage *msg, void *data)
|
||||
{
|
||||
struct sailfish_sim_info_dbus *dbus = data;
|
||||
|
||||
return sailfish_sim_info_dbus_reply_with_string(msg, dbus->info->spn);
|
||||
}
|
||||
|
||||
#define SIM_INFO_DBUS_VERSION_ARG {"version", "i"}
|
||||
#define SIM_INFO_DBUS_ICCID_ARG {"iccid", "s"}
|
||||
#define SIM_INFO_DBUS_IMSI_ARG {"imsi", "s"}
|
||||
#define SIM_INFO_DBUS_SPN_ARG {"spn" , "s"}
|
||||
|
||||
#define SIM_INFO_DBUS_GET_ALL_ARGS \
|
||||
SIM_INFO_DBUS_VERSION_ARG, \
|
||||
SIM_INFO_DBUS_ICCID_ARG, \
|
||||
SIM_INFO_DBUS_IMSI_ARG, \
|
||||
SIM_INFO_DBUS_SPN_ARG
|
||||
|
||||
static const GDBusMethodTable sailfish_sim_info_dbus_methods[] = {
|
||||
{ GDBUS_METHOD("GetAll",
|
||||
NULL, GDBUS_ARGS(SIM_INFO_DBUS_GET_ALL_ARGS),
|
||||
sailfish_sim_info_dbus_get_all) },
|
||||
{ GDBUS_METHOD("GetInterfaceVersion",
|
||||
NULL, GDBUS_ARGS(SIM_INFO_DBUS_VERSION_ARG),
|
||||
sailfish_sim_info_dbus_get_version) },
|
||||
{ GDBUS_METHOD("GetCardIdentifier",
|
||||
NULL, GDBUS_ARGS(SIM_INFO_DBUS_ICCID_ARG),
|
||||
sailfish_sim_info_dbus_get_iccid) },
|
||||
{ GDBUS_METHOD("GetSubscriberIdentity",
|
||||
NULL, GDBUS_ARGS(SIM_INFO_DBUS_IMSI_ARG),
|
||||
sailfish_sim_info_dbus_get_imsi) },
|
||||
{ GDBUS_METHOD("GetServiceProviderName",
|
||||
NULL, GDBUS_ARGS(SIM_INFO_DBUS_SPN_ARG),
|
||||
sailfish_sim_info_dbus_get_spn) },
|
||||
{ }
|
||||
};
|
||||
|
||||
static const GDBusSignalTable sailfish_sim_info_dbus_signals[] = {
|
||||
{ GDBUS_SIGNAL(SIM_INFO_DBUS_ICCID_CHANGED_SIGNAL,
|
||||
GDBUS_ARGS(SIM_INFO_DBUS_ICCID_ARG)) },
|
||||
{ GDBUS_SIGNAL(SIM_INFO_DBUS_IMSI_CHANGED_SIGNAL,
|
||||
GDBUS_ARGS(SIM_INFO_DBUS_IMSI_ARG)) },
|
||||
{ GDBUS_SIGNAL(SIM_INFO_DBUS_SPN_CHANGED_SIGNAL,
|
||||
GDBUS_ARGS(SIM_INFO_DBUS_SPN_ARG)) },
|
||||
{ }
|
||||
};
|
||||
|
||||
static void sailfish_sim_info_dbus_modem_cb(struct sailfish_watch *watch,
|
||||
void *data)
|
||||
{
|
||||
if (watch->modem) {
|
||||
ofono_modem_add_interface(watch->modem,
|
||||
SIM_INFO_DBUS_INTERFACE);
|
||||
}
|
||||
}
|
||||
|
||||
static void sailfish_sim_info_dbus_emit(struct sailfish_sim_info_dbus *dbus,
|
||||
const char *signal, const char *value)
|
||||
{
|
||||
const char *arg = value;
|
||||
|
||||
if (!arg) arg = "";
|
||||
g_dbus_emit_signal(dbus->conn, dbus->info->path,
|
||||
SIM_INFO_DBUS_INTERFACE, signal,
|
||||
DBUS_TYPE_STRING, &arg, DBUS_TYPE_INVALID);
|
||||
}
|
||||
|
||||
static void sailfish_sim_info_dbus_iccid_cb(struct sailfish_sim_info *info,
|
||||
void *data)
|
||||
{
|
||||
sailfish_sim_info_dbus_emit((struct sailfish_sim_info_dbus *)data,
|
||||
SIM_INFO_DBUS_ICCID_CHANGED_SIGNAL, info->iccid);
|
||||
}
|
||||
|
||||
static void sailfish_sim_info_dbus_imsi_cb(struct sailfish_sim_info *info,
|
||||
void *data)
|
||||
{
|
||||
sailfish_sim_info_dbus_emit((struct sailfish_sim_info_dbus *)data,
|
||||
SIM_INFO_DBUS_IMSI_CHANGED_SIGNAL, info->imsi);
|
||||
}
|
||||
|
||||
static void sailfish_sim_info_dbus_spn_cb(struct sailfish_sim_info *info,
|
||||
void *data)
|
||||
{
|
||||
sailfish_sim_info_dbus_emit((struct sailfish_sim_info_dbus *)data,
|
||||
SIM_INFO_DBUS_SPN_CHANGED_SIGNAL, info->spn);
|
||||
}
|
||||
|
||||
struct sailfish_sim_info_dbus *sailfish_sim_info_dbus_new
|
||||
(struct sailfish_sim_info *info)
|
||||
{
|
||||
struct sailfish_sim_info_dbus *dbus =
|
||||
g_slice_new0(struct sailfish_sim_info_dbus);
|
||||
|
||||
DBG("%s", info->path);
|
||||
dbus->info = sailfish_sim_info_ref(info);
|
||||
dbus->watch = sailfish_watch_new(info->path);
|
||||
dbus->conn = dbus_connection_ref(ofono_dbus_get_connection());
|
||||
|
||||
/* Register D-Bus interface */
|
||||
if (g_dbus_register_interface(dbus->conn, dbus->info->path,
|
||||
SIM_INFO_DBUS_INTERFACE,
|
||||
sailfish_sim_info_dbus_methods,
|
||||
sailfish_sim_info_dbus_signals,
|
||||
NULL, dbus, NULL)) {
|
||||
if (dbus->watch->modem) {
|
||||
ofono_modem_add_interface(dbus->watch->modem,
|
||||
SIM_INFO_DBUS_INTERFACE);
|
||||
}
|
||||
|
||||
dbus->watch_event_id[WATCH_EVENT_MODEM] =
|
||||
sailfish_watch_add_modem_changed_handler(dbus->watch,
|
||||
sailfish_sim_info_dbus_modem_cb, dbus);
|
||||
dbus->info_event_id[SIM_INFO_EVENT_ICCID] =
|
||||
sailfish_sim_info_add_iccid_changed_handler(info,
|
||||
sailfish_sim_info_dbus_iccid_cb, dbus);
|
||||
dbus->info_event_id[SIM_INFO_EVENT_IMSI] =
|
||||
sailfish_sim_info_add_imsi_changed_handler(info,
|
||||
sailfish_sim_info_dbus_imsi_cb, dbus);
|
||||
dbus->info_event_id[SIM_INFO_EVENT_SPN] =
|
||||
sailfish_sim_info_add_spn_changed_handler(info,
|
||||
sailfish_sim_info_dbus_spn_cb, dbus);
|
||||
|
||||
return dbus;
|
||||
} else {
|
||||
ofono_error("SimInfo D-Bus register failed");
|
||||
sailfish_sim_info_dbus_free(dbus);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
struct sailfish_sim_info_dbus *sailfish_sim_info_dbus_new_path
|
||||
(const char *path)
|
||||
{
|
||||
struct sailfish_sim_info_dbus *dbus = NULL;
|
||||
struct sailfish_sim_info *info = sailfish_sim_info_new(path);
|
||||
|
||||
if (info) {
|
||||
dbus = sailfish_sim_info_dbus_new(info);
|
||||
sailfish_sim_info_unref(info);
|
||||
}
|
||||
|
||||
return dbus;
|
||||
}
|
||||
|
||||
void sailfish_sim_info_dbus_free(struct sailfish_sim_info_dbus *dbus)
|
||||
{
|
||||
if (dbus) {
|
||||
DBG("%s", dbus->info->path);
|
||||
g_dbus_unregister_interface(dbus->conn, dbus->info->path,
|
||||
SIM_INFO_DBUS_INTERFACE);
|
||||
if (dbus->watch->modem) {
|
||||
ofono_modem_remove_interface(dbus->watch->modem,
|
||||
SIM_INFO_DBUS_INTERFACE);
|
||||
}
|
||||
dbus_connection_unref(dbus->conn);
|
||||
|
||||
sailfish_watch_remove_all_handlers(dbus->watch,
|
||||
dbus->watch_event_id);
|
||||
sailfish_watch_unref(dbus->watch);
|
||||
|
||||
sailfish_sim_info_remove_all_handlers(dbus->info,
|
||||
dbus->info_event_id);
|
||||
sailfish_sim_info_unref(dbus->info);
|
||||
|
||||
g_slice_free(struct sailfish_sim_info_dbus, dbus);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
680
ofono/plugins/sailfish_manager/sailfish_watch.c
Normal file
680
ofono/plugins/sailfish_manager/sailfish_watch.c
Normal file
@@ -0,0 +1,680 @@
|
||||
/*
|
||||
* 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 "sailfish_watch.h"
|
||||
|
||||
#include <gutil_misc.h>
|
||||
#include <gutil_log.h>
|
||||
|
||||
#include "ofono.h"
|
||||
|
||||
typedef GObjectClass SailfishWatchClass;
|
||||
typedef struct sailfish_watch SailfishWatch;
|
||||
|
||||
struct sailfish_watch_priv {
|
||||
char *path;
|
||||
char *iccid;
|
||||
char *imsi;
|
||||
char *spn;
|
||||
int signals_suspended;
|
||||
int queued_signals;
|
||||
guint modem_watch_id;
|
||||
guint online_watch_id;
|
||||
guint sim_watch_id;
|
||||
guint sim_state_watch_id;
|
||||
guint iccid_watch_id;
|
||||
guint imsi_watch_id;
|
||||
guint spn_watch_id;
|
||||
guint netreg_watch_id;
|
||||
};
|
||||
|
||||
enum sailfish_watch_signal {
|
||||
SIGNAL_MODEM_CHANGED,
|
||||
SIGNAL_ONLINE_CHANGED,
|
||||
SIGNAL_SIM_CHANGED,
|
||||
SIGNAL_SIM_STATE_CHANGED,
|
||||
SIGNAL_ICCID_CHANGED,
|
||||
SIGNAL_IMSI_CHANGED,
|
||||
SIGNAL_SPN_CHANGED,
|
||||
SIGNAL_NETREG_CHANGED,
|
||||
SIGNAL_COUNT
|
||||
};
|
||||
|
||||
#define SIGNAL_MODEM_CHANGED_NAME "sailfish-watch-modem-changed"
|
||||
#define SIGNAL_ONLINE_CHANGED_NAME "sailfish-watch-online-changed"
|
||||
#define SIGNAL_SIM_CHANGED_NAME "sailfish-watch-sim-changed"
|
||||
#define SIGNAL_SIM_STATE_CHANGED_NAME "sailfish-watch-sim-state-changed"
|
||||
#define SIGNAL_ICCID_CHANGED_NAME "sailfish-watch-iccid-changed"
|
||||
#define SIGNAL_IMSI_CHANGED_NAME "sailfish-watch-imsi-changed"
|
||||
#define SIGNAL_SPN_CHANGED_NAME "sailfish-watch-spn-changed"
|
||||
#define SIGNAL_NETREG_CHANGED_NAME "sailfish-watch-netreg-changed"
|
||||
|
||||
static guint sailfish_watch_signals[SIGNAL_COUNT] = { 0 };
|
||||
static GHashTable* sailfish_watch_table = NULL;
|
||||
|
||||
G_DEFINE_TYPE(SailfishWatch, sailfish_watch, G_TYPE_OBJECT)
|
||||
#define SAILFISH_WATCH_TYPE (sailfish_watch_get_type())
|
||||
#define SAILFISH_WATCH(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),\
|
||||
SAILFISH_WATCH_TYPE, SailfishWatch))
|
||||
|
||||
#define NEW_SIGNAL(klass,name) \
|
||||
sailfish_watch_signals[SIGNAL_##name##_CHANGED] = \
|
||||
g_signal_new(SIGNAL_##name##_CHANGED_NAME, \
|
||||
G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_FIRST, \
|
||||
0, NULL, NULL, NULL, G_TYPE_NONE, 0)
|
||||
|
||||
/* Skip the leading slash from the modem path: */
|
||||
#define DBG_(obj,fmt,args...) DBG("%s " fmt, (obj)->path+1, ##args)
|
||||
|
||||
static inline int sailfish_watch_signal_bit(enum sailfish_watch_signal id)
|
||||
{
|
||||
return (1 << id);
|
||||
}
|
||||
|
||||
static inline void sailfish_watch_signal_emit(struct sailfish_watch *self,
|
||||
enum sailfish_watch_signal id)
|
||||
{
|
||||
self->priv->queued_signals &= ~sailfish_watch_signal_bit(id);
|
||||
g_signal_emit(self, sailfish_watch_signals[id], 0);
|
||||
}
|
||||
|
||||
static inline void sailfish_watch_signal_queue(struct sailfish_watch *self,
|
||||
enum sailfish_watch_signal id)
|
||||
{
|
||||
self->priv->queued_signals |= sailfish_watch_signal_bit(id);
|
||||
}
|
||||
|
||||
static void sailfish_watch_emit_queued_signals(struct sailfish_watch *self)
|
||||
{
|
||||
struct sailfish_watch_priv *priv = self->priv;
|
||||
|
||||
if (priv->signals_suspended < 1) {
|
||||
int i;
|
||||
|
||||
for (i = 0; priv->queued_signals && i < SIGNAL_COUNT; i++) {
|
||||
if (priv->queued_signals &
|
||||
sailfish_watch_signal_bit(i)) {
|
||||
sailfish_watch_signal_emit(self, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline void sailfish_watch_suspend_signals(struct sailfish_watch *self)
|
||||
{
|
||||
self->priv->signals_suspended++;
|
||||
}
|
||||
|
||||
static inline void sailfish_watch_resume_signals(struct sailfish_watch *self)
|
||||
{
|
||||
struct sailfish_watch_priv *priv = self->priv;
|
||||
|
||||
GASSERT(priv->signals_suspended > 0);
|
||||
priv->signals_suspended--;
|
||||
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)
|
||||
{
|
||||
struct sailfish_watch_priv *priv = self->priv;
|
||||
|
||||
if (g_strcmp0(priv->iccid, iccid)) {
|
||||
g_free(priv->iccid);
|
||||
self->iccid = priv->iccid = g_strdup(iccid);
|
||||
sailfish_watch_signal_queue(self, SIGNAL_ICCID_CHANGED);
|
||||
}
|
||||
}
|
||||
|
||||
static void sailfish_watch_iccid_notify(const char *iccid, void *user_data)
|
||||
{
|
||||
struct sailfish_watch *self = SAILFISH_WATCH(user_data);
|
||||
|
||||
sailfish_watch_iccid_update(self, iccid);
|
||||
sailfish_watch_emit_queued_signals(self);
|
||||
}
|
||||
|
||||
static void sailfish_watch_iccid_destroy(void *user_data)
|
||||
{
|
||||
struct sailfish_watch *self = SAILFISH_WATCH(user_data);
|
||||
struct sailfish_watch_priv *priv = self->priv;
|
||||
|
||||
GASSERT(priv->iccid_watch_id);
|
||||
priv->iccid_watch_id = 0;
|
||||
}
|
||||
|
||||
static void sailfish_watch_spn_update(struct sailfish_watch *self,
|
||||
const char *spn)
|
||||
{
|
||||
struct sailfish_watch_priv *priv = self->priv;
|
||||
|
||||
if (g_strcmp0(priv->spn, spn)) {
|
||||
g_free(priv->spn);
|
||||
self->spn = priv->spn = g_strdup(spn);
|
||||
sailfish_watch_signal_queue(self, SIGNAL_SPN_CHANGED);
|
||||
}
|
||||
}
|
||||
|
||||
static void sailfish_watch_spn_notify(const char *spn, const char *dc,
|
||||
void *user_data)
|
||||
{
|
||||
struct sailfish_watch *self = SAILFISH_WATCH(user_data);
|
||||
|
||||
sailfish_watch_spn_update(self, spn);
|
||||
sailfish_watch_emit_queued_signals(self);
|
||||
}
|
||||
|
||||
static void sailfish_watch_spn_destroy(void *user_data)
|
||||
{
|
||||
struct sailfish_watch *self = SAILFISH_WATCH(user_data);
|
||||
struct sailfish_watch_priv *priv = self->priv;
|
||||
|
||||
GASSERT(priv->spn_watch_id);
|
||||
priv->spn_watch_id = 0;
|
||||
}
|
||||
|
||||
static void sailfish_watch_imsi_update(struct sailfish_watch *self,
|
||||
const char *imsi)
|
||||
{
|
||||
struct sailfish_watch_priv *priv = self->priv;
|
||||
|
||||
if (g_strcmp0(priv->imsi, imsi)) {
|
||||
g_free(priv->imsi);
|
||||
self->imsi = priv->imsi = g_strdup(imsi);
|
||||
sailfish_watch_signal_queue(self, SIGNAL_IMSI_CHANGED);
|
||||
/* ofono core crashes if we add spn watch too early */
|
||||
if (imsi) {
|
||||
ofono_sim_add_spn_watch(self->sim, &priv->spn_watch_id,
|
||||
sailfish_watch_spn_notify, self,
|
||||
sailfish_watch_spn_destroy);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void sailfish_watch_imsi_notify(const char *imsi, void *user_data)
|
||||
{
|
||||
struct sailfish_watch *self = SAILFISH_WATCH(user_data);
|
||||
|
||||
sailfish_watch_imsi_update(self, imsi);
|
||||
sailfish_watch_emit_queued_signals(self);
|
||||
}
|
||||
|
||||
static void sailfish_watch_imsi_destroy(void *user_data)
|
||||
{
|
||||
struct sailfish_watch *self = SAILFISH_WATCH(user_data);
|
||||
struct sailfish_watch_priv *priv = self->priv;
|
||||
|
||||
GASSERT(priv->imsi_watch_id);
|
||||
priv->imsi_watch_id = 0;
|
||||
}
|
||||
|
||||
static void sailfish_watch_set_sim(struct sailfish_watch *self,
|
||||
struct ofono_sim *sim)
|
||||
{
|
||||
if (self->sim != sim) {
|
||||
struct sailfish_watch_priv *priv = self->priv;
|
||||
|
||||
if (priv->sim_state_watch_id) {
|
||||
ofono_sim_remove_state_watch(self->sim,
|
||||
priv->sim_state_watch_id);
|
||||
/* The destroy callback clears it */
|
||||
GASSERT(!priv->sim_state_watch_id);
|
||||
}
|
||||
if (priv->iccid_watch_id) {
|
||||
ofono_sim_remove_iccid_watch(self->sim,
|
||||
priv->iccid_watch_id);
|
||||
/* The destroy callback clears it */
|
||||
GASSERT(!priv->iccid_watch_id);
|
||||
}
|
||||
if (priv->imsi_watch_id) {
|
||||
ofono_sim_remove_imsi_watch(self->sim,
|
||||
priv->imsi_watch_id);
|
||||
/* The destroy callback clears it */
|
||||
GASSERT(!priv->imsi_watch_id);
|
||||
}
|
||||
if (priv->spn_watch_id) {
|
||||
ofono_sim_remove_spn_watch(self->sim,
|
||||
&priv->spn_watch_id);
|
||||
/* The destroy callback clears it */
|
||||
GASSERT(!priv->spn_watch_id);
|
||||
}
|
||||
self->sim = sim;
|
||||
sailfish_watch_signal_queue(self, SIGNAL_SIM_CHANGED);
|
||||
sailfish_watch_suspend_signals(self);
|
||||
if (sim) {
|
||||
priv->sim_state_watch_id =
|
||||
ofono_sim_add_state_watch(sim,
|
||||
sailfish_watch_sim_state_notify, self,
|
||||
sailfish_watch_sim_state_destroy);
|
||||
/*
|
||||
* Unlike ofono_sim_add_state_watch, the rest
|
||||
* of ofono_sim_add_xxx_watch functions call the
|
||||
* notify callback if the value is already known
|
||||
* to the ofono core.
|
||||
*
|
||||
* Also note that ofono core crashes if we add
|
||||
* spn watch too early.
|
||||
*/
|
||||
priv->iccid_watch_id =
|
||||
ofono_sim_add_iccid_watch(self->sim,
|
||||
sailfish_watch_iccid_notify, self,
|
||||
sailfish_watch_iccid_destroy);
|
||||
priv->imsi_watch_id =
|
||||
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. */
|
||||
sailfish_watch_resume_signals(self);
|
||||
}
|
||||
}
|
||||
|
||||
static void sailfish_watch_sim_notify(struct ofono_atom *atom,
|
||||
enum ofono_atom_watch_condition cond, void *user_data)
|
||||
{
|
||||
struct sailfish_watch *self = SAILFISH_WATCH(user_data);
|
||||
|
||||
if (cond == OFONO_ATOM_WATCH_CONDITION_REGISTERED) {
|
||||
struct ofono_sim *sim = __ofono_atom_get_data(atom);
|
||||
|
||||
DBG_(self, "sim registered");
|
||||
sailfish_watch_set_sim(self, sim);
|
||||
} else if (cond == OFONO_ATOM_WATCH_CONDITION_UNREGISTERED) {
|
||||
DBG_(self, "sim unregistered");
|
||||
sailfish_watch_set_sim(self, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static void sailfish_watch_sim_destroy(void *user_data)
|
||||
{
|
||||
struct sailfish_watch *self = SAILFISH_WATCH(user_data);
|
||||
|
||||
self->priv->sim_watch_id = 0;
|
||||
}
|
||||
|
||||
static void sailfish_watch_set_netreg(struct sailfish_watch *self,
|
||||
struct ofono_netreg *netreg)
|
||||
{
|
||||
if (self->netreg != netreg) {
|
||||
self->netreg = netreg;
|
||||
sailfish_watch_signal_emit(self, SIGNAL_NETREG_CHANGED);
|
||||
}
|
||||
}
|
||||
|
||||
static void sailfish_watch_netreg_notify(struct ofono_atom *atom,
|
||||
enum ofono_atom_watch_condition cond, void *user_data)
|
||||
{
|
||||
struct sailfish_watch *self = SAILFISH_WATCH(user_data);
|
||||
|
||||
if (cond == OFONO_ATOM_WATCH_CONDITION_REGISTERED) {
|
||||
struct ofono_netreg *netreg = __ofono_atom_get_data(atom);
|
||||
|
||||
DBG_(self, "netreg registered");
|
||||
sailfish_watch_set_netreg(self, netreg);
|
||||
} else if (cond == OFONO_ATOM_WATCH_CONDITION_UNREGISTERED) {
|
||||
DBG_(self, "netreg unregistered");
|
||||
sailfish_watch_set_netreg(self, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static void sailfish_watch_netreg_destroy(void *user_data)
|
||||
{
|
||||
struct sailfish_watch *self = SAILFISH_WATCH(user_data);
|
||||
|
||||
self->priv->netreg_watch_id = 0;
|
||||
}
|
||||
|
||||
static void sailfish_watch_online_update(struct sailfish_watch *self,
|
||||
gboolean online)
|
||||
{
|
||||
if (self->online != online) {
|
||||
self->online = online;
|
||||
sailfish_watch_signal_queue(self, SIGNAL_ONLINE_CHANGED);
|
||||
}
|
||||
}
|
||||
|
||||
static void sailfish_watch_online_notify(struct ofono_modem *modem,
|
||||
ofono_bool_t online, void *user_data)
|
||||
{
|
||||
struct sailfish_watch *self = SAILFISH_WATCH(user_data);
|
||||
|
||||
GASSERT(self->modem == modem);
|
||||
GASSERT(online == ofono_modem_get_online(modem));
|
||||
sailfish_watch_online_update(self, online);
|
||||
sailfish_watch_emit_queued_signals(self);
|
||||
}
|
||||
|
||||
static void sailfish_watch_online_destroy(void *user_data)
|
||||
{
|
||||
struct sailfish_watch *self = SAILFISH_WATCH(user_data);
|
||||
|
||||
self->priv->online_watch_id = 0;
|
||||
}
|
||||
|
||||
static void sailfish_watch_setup_modem(struct sailfish_watch *self)
|
||||
{
|
||||
struct sailfish_watch_priv *priv = self->priv;
|
||||
|
||||
GASSERT(!priv->online_watch_id);
|
||||
priv->online_watch_id =
|
||||
__ofono_modem_add_online_watch(self->modem,
|
||||
sailfish_watch_online_notify, self,
|
||||
sailfish_watch_online_destroy);
|
||||
|
||||
/* __ofono_modem_add_atom_watch() calls the notify callback if the
|
||||
* atom is already registered */
|
||||
GASSERT(!priv->sim_watch_id);
|
||||
priv->sim_watch_id = __ofono_modem_add_atom_watch(self->modem,
|
||||
OFONO_ATOM_TYPE_SIM, sailfish_watch_sim_notify,
|
||||
self, sailfish_watch_sim_destroy);
|
||||
|
||||
GASSERT(!priv->netreg_watch_id);
|
||||
priv->netreg_watch_id = __ofono_modem_add_atom_watch(self->modem,
|
||||
OFONO_ATOM_TYPE_NETREG, sailfish_watch_netreg_notify,
|
||||
self, sailfish_watch_netreg_destroy);
|
||||
}
|
||||
|
||||
static void sailfish_watch_cleanup_modem(struct sailfish_watch *self,
|
||||
struct ofono_modem *modem)
|
||||
{
|
||||
/* Caller checks the self->modem isn't NULL */
|
||||
struct sailfish_watch_priv *priv = self->priv;
|
||||
|
||||
if (priv->online_watch_id) {
|
||||
__ofono_modem_remove_online_watch(modem,
|
||||
priv->online_watch_id);
|
||||
GASSERT(!priv->online_watch_id);
|
||||
}
|
||||
|
||||
if (priv->sim_watch_id) {
|
||||
__ofono_modem_remove_atom_watch(modem, priv->sim_watch_id);
|
||||
GASSERT(!priv->sim_watch_id);
|
||||
}
|
||||
|
||||
if (priv->netreg_watch_id) {
|
||||
__ofono_modem_remove_atom_watch(modem, priv->netreg_watch_id);
|
||||
GASSERT(!priv->netreg_watch_id);
|
||||
}
|
||||
|
||||
sailfish_watch_set_sim(self, NULL);
|
||||
sailfish_watch_set_netreg(self, NULL);
|
||||
}
|
||||
|
||||
static void sailfish_watch_set_modem(struct sailfish_watch *self,
|
||||
struct ofono_modem *modem)
|
||||
{
|
||||
if (self->modem != modem) {
|
||||
struct ofono_modem *old_modem = self->modem;
|
||||
|
||||
self->modem = modem;
|
||||
sailfish_watch_signal_queue(self, SIGNAL_MODEM_CHANGED);
|
||||
if (old_modem) {
|
||||
sailfish_watch_cleanup_modem(self, old_modem);
|
||||
}
|
||||
if (modem) {
|
||||
sailfish_watch_setup_modem(self);
|
||||
}
|
||||
sailfish_watch_emit_queued_signals(self);
|
||||
}
|
||||
}
|
||||
|
||||
static void sailfish_watch_modem_notify(struct ofono_modem *modem,
|
||||
gboolean added, void *user_data)
|
||||
{
|
||||
struct sailfish_watch *self = SAILFISH_WATCH(user_data);
|
||||
|
||||
if (added) {
|
||||
if (!g_strcmp0(self->path, ofono_modem_get_path(modem))) {
|
||||
sailfish_watch_set_modem(self, modem);
|
||||
}
|
||||
} else if (self->modem == modem) {
|
||||
sailfish_watch_set_modem(self, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static void sailfish_watch_modem_destroy(void *user_data)
|
||||
{
|
||||
struct sailfish_watch *self = SAILFISH_WATCH(user_data);
|
||||
|
||||
self->priv->modem_watch_id = 0;
|
||||
}
|
||||
|
||||
static ofono_bool_t sailfish_watch_modem_find(struct ofono_modem *modem,
|
||||
void *user_data)
|
||||
{
|
||||
struct sailfish_watch *self = SAILFISH_WATCH(user_data);
|
||||
|
||||
if (!g_strcmp0(self->path, ofono_modem_get_path(modem))) {
|
||||
self->modem = modem;
|
||||
sailfish_watch_setup_modem(self);
|
||||
return TRUE;
|
||||
} else {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static void sailfish_watch_initialize(struct sailfish_watch *self,
|
||||
const char *path)
|
||||
{
|
||||
struct sailfish_watch_priv *priv = self->priv;
|
||||
|
||||
self->path = priv->path = g_strdup(path);
|
||||
ofono_modem_find(sailfish_watch_modem_find, self);
|
||||
self->online = ofono_modem_get_online(self->modem);
|
||||
priv->modem_watch_id =
|
||||
__ofono_modemwatch_add(sailfish_watch_modem_notify, self,
|
||||
sailfish_watch_modem_destroy);
|
||||
}
|
||||
|
||||
static void sailfish_watch_destroyed(gpointer key, GObject* obj)
|
||||
{
|
||||
GASSERT(sailfish_watch_table);
|
||||
DBG("%s", (char*)key);
|
||||
if (sailfish_watch_table) {
|
||||
GASSERT(g_hash_table_lookup(sailfish_watch_table, key) == obj);
|
||||
g_hash_table_remove(sailfish_watch_table, key);
|
||||
if (g_hash_table_size(sailfish_watch_table) == 0) {
|
||||
g_hash_table_unref(sailfish_watch_table);
|
||||
sailfish_watch_table = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct sailfish_watch *sailfish_watch_new(const char *path)
|
||||
{
|
||||
struct sailfish_watch *watch = NULL;
|
||||
|
||||
if (path) {
|
||||
if (sailfish_watch_table) {
|
||||
watch = sailfish_watch_ref(g_hash_table_lookup(
|
||||
sailfish_watch_table, path));
|
||||
}
|
||||
if (!watch) {
|
||||
char* key = g_strdup(path);
|
||||
|
||||
watch = g_object_new(SAILFISH_WATCH_TYPE, NULL);
|
||||
sailfish_watch_initialize(watch, path);
|
||||
if (!sailfish_watch_table) {
|
||||
/* Create the table on demand */
|
||||
sailfish_watch_table =
|
||||
g_hash_table_new_full(g_str_hash,
|
||||
g_str_equal, g_free, NULL);
|
||||
}
|
||||
g_hash_table_replace(sailfish_watch_table, key, watch);
|
||||
g_object_weak_ref(G_OBJECT(watch),
|
||||
sailfish_watch_destroyed, key);
|
||||
DBG_(watch, "created");
|
||||
}
|
||||
}
|
||||
return watch;
|
||||
}
|
||||
|
||||
struct sailfish_watch *sailfish_watch_ref(struct sailfish_watch *self)
|
||||
{
|
||||
if (self) {
|
||||
g_object_ref(SAILFISH_WATCH(self));
|
||||
return self;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void sailfish_watch_unref(struct sailfish_watch *self)
|
||||
{
|
||||
if (self) {
|
||||
g_object_unref(SAILFISH_WATCH(self));
|
||||
}
|
||||
}
|
||||
|
||||
gulong sailfish_watch_add_modem_changed_handler(struct sailfish_watch *self,
|
||||
sailfish_watch_cb_t cb, void *user_data)
|
||||
{
|
||||
return (self && cb) ? g_signal_connect(self,
|
||||
SIGNAL_MODEM_CHANGED_NAME, G_CALLBACK(cb), user_data) : 0;
|
||||
}
|
||||
|
||||
gulong sailfish_watch_add_online_changed_handler(struct sailfish_watch *self,
|
||||
sailfish_watch_cb_t cb, void *user_data)
|
||||
{
|
||||
return (self && cb) ? g_signal_connect(self,
|
||||
SIGNAL_ONLINE_CHANGED_NAME, G_CALLBACK(cb), user_data) : 0;
|
||||
}
|
||||
|
||||
gulong sailfish_watch_add_sim_changed_handler(struct sailfish_watch *self,
|
||||
sailfish_watch_cb_t cb, void *user_data)
|
||||
{
|
||||
return (self && cb) ? g_signal_connect(self,
|
||||
SIGNAL_SIM_CHANGED_NAME, G_CALLBACK(cb), user_data) : 0;
|
||||
}
|
||||
|
||||
gulong sailfish_watch_add_sim_state_changed_handler(struct sailfish_watch *self,
|
||||
sailfish_watch_cb_t cb, void *user_data)
|
||||
{
|
||||
return (self && cb) ? g_signal_connect(self,
|
||||
SIGNAL_SIM_STATE_CHANGED_NAME, G_CALLBACK(cb), user_data) : 0;
|
||||
}
|
||||
|
||||
gulong sailfish_watch_add_iccid_changed_handler(struct sailfish_watch *self,
|
||||
sailfish_watch_cb_t cb, void *user_data)
|
||||
{
|
||||
return (self && cb) ? g_signal_connect(self,
|
||||
SIGNAL_ICCID_CHANGED_NAME, G_CALLBACK(cb), user_data) : 0;
|
||||
}
|
||||
|
||||
gulong sailfish_watch_add_imsi_changed_handler(struct sailfish_watch *self,
|
||||
sailfish_watch_cb_t cb, void *user_data)
|
||||
{
|
||||
return (self && cb) ? g_signal_connect(self,
|
||||
SIGNAL_IMSI_CHANGED_NAME, G_CALLBACK(cb), user_data) : 0;
|
||||
}
|
||||
|
||||
gulong sailfish_watch_add_spn_changed_handler(struct sailfish_watch *self,
|
||||
sailfish_watch_cb_t cb, void *user_data)
|
||||
{
|
||||
return (self && cb) ? g_signal_connect(self,
|
||||
SIGNAL_SPN_CHANGED_NAME, G_CALLBACK(cb), user_data) : 0;
|
||||
}
|
||||
|
||||
gulong sailfish_watch_add_netreg_changed_handler(struct sailfish_watch *self,
|
||||
sailfish_watch_cb_t cb, void *user_data)
|
||||
{
|
||||
return (self && cb) ? g_signal_connect(self,
|
||||
SIGNAL_NETREG_CHANGED_NAME, G_CALLBACK(cb), user_data) : 0;
|
||||
}
|
||||
|
||||
void sailfish_watch_remove_handler(struct sailfish_watch *self, gulong id)
|
||||
{
|
||||
if (self && id) {
|
||||
g_signal_handler_disconnect(self, id);
|
||||
}
|
||||
}
|
||||
|
||||
void sailfish_watch_remove_handlers(struct sailfish_watch *self, gulong *ids,
|
||||
int count)
|
||||
{
|
||||
gutil_disconnect_handlers(self, ids, count);
|
||||
}
|
||||
|
||||
static void sailfish_watch_init(struct sailfish_watch *self)
|
||||
{
|
||||
self->priv = G_TYPE_INSTANCE_GET_PRIVATE(self, SAILFISH_WATCH_TYPE,
|
||||
struct sailfish_watch_priv);
|
||||
}
|
||||
|
||||
static void sailfish_watch_finalize(GObject *object)
|
||||
{
|
||||
struct sailfish_watch *self = SAILFISH_WATCH(object);
|
||||
struct sailfish_watch_priv *priv = self->priv;
|
||||
|
||||
if (self->modem) {
|
||||
struct ofono_modem *modem = self->modem;
|
||||
|
||||
self->modem = NULL;
|
||||
sailfish_watch_cleanup_modem(self, modem);
|
||||
}
|
||||
if (priv->modem_watch_id) {
|
||||
__ofono_modemwatch_remove(priv->modem_watch_id);
|
||||
GASSERT(!priv->modem_watch_id);
|
||||
}
|
||||
g_free(priv->path);
|
||||
G_OBJECT_CLASS(sailfish_watch_parent_class)->finalize(object);
|
||||
}
|
||||
|
||||
static void sailfish_watch_class_init(SailfishWatchClass *klass)
|
||||
{
|
||||
G_OBJECT_CLASS(klass)->finalize = sailfish_watch_finalize;
|
||||
g_type_class_add_private(klass, sizeof(struct sailfish_watch_priv));
|
||||
NEW_SIGNAL(klass, MODEM);
|
||||
NEW_SIGNAL(klass, ONLINE);
|
||||
NEW_SIGNAL(klass, SIM);
|
||||
NEW_SIGNAL(klass, SIM_STATE);
|
||||
NEW_SIGNAL(klass, ICCID);
|
||||
NEW_SIGNAL(klass, IMSI);
|
||||
NEW_SIGNAL(klass, SPN);
|
||||
NEW_SIGNAL(klass, NETREG);
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
251
ofono/plugins/sailfish_provision.c
Normal file
251
ofono/plugins/sailfish_provision.c
Normal file
@@ -0,0 +1,251 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
|
||||
* Copyright (C) 2013-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.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#define OFONO_API_SUBJECT_TO_CHANGE
|
||||
#include <ofono/log.h>
|
||||
#include <ofono/plugin.h>
|
||||
#include <ofono/modem.h>
|
||||
#include <ofono/gprs-provision.h>
|
||||
|
||||
#include "provision.h"
|
||||
#include "mbpi.h"
|
||||
|
||||
struct provision_ap_defaults {
|
||||
enum ofono_gprs_context_type type;
|
||||
const char *name;
|
||||
const char *apn;
|
||||
};
|
||||
|
||||
static gint provision_match_strings(const char *s1, const char *s2)
|
||||
{
|
||||
gint match = 0;
|
||||
|
||||
/* Caller checks s2 for NULL */
|
||||
if (s1) {
|
||||
const gssize len1 = strlen(s1);
|
||||
const gssize len2 = strlen(s2);
|
||||
|
||||
if (len1 == len2 && !strcmp(s1, s2)) {
|
||||
/* Best match ever */
|
||||
match = 3;
|
||||
} else if (g_utf8_validate(s1, len1, NULL) &&
|
||||
g_utf8_validate(s2, len2, NULL)) {
|
||||
char *d1 = g_utf8_strdown(s1, len1);
|
||||
char *d2 = g_utf8_strdown(s2, len2);
|
||||
|
||||
if (len1 == len2 && !strcmp(d1, d2)) {
|
||||
/* Case insensitive match */
|
||||
match = 2;
|
||||
} else if ((len1 > len2 && strstr(d1, d2)) ||
|
||||
(len2 > len1 && strstr(d2, d1))) {
|
||||
/* Partial case insensitive match */
|
||||
match = 1;
|
||||
}
|
||||
|
||||
g_free(d1);
|
||||
g_free(d2);
|
||||
}
|
||||
}
|
||||
|
||||
return match;
|
||||
}
|
||||
static gint provision_match_spn(const struct ofono_gprs_provision_data *ap,
|
||||
const char *spn)
|
||||
{
|
||||
return provision_match_strings(ap->provider_name, spn) * 4 +
|
||||
provision_match_strings(ap->name, spn);
|
||||
}
|
||||
|
||||
static void provision_free_ap(gpointer data)
|
||||
{
|
||||
mbpi_ap_free(data);
|
||||
}
|
||||
|
||||
static gint provision_compare_ap(gconstpointer a, gconstpointer b,
|
||||
gpointer data)
|
||||
{
|
||||
const struct ofono_gprs_provision_data *ap1 = a;
|
||||
const struct ofono_gprs_provision_data *ap2 = b;
|
||||
const char *spn = data;
|
||||
|
||||
if (spn) {
|
||||
const gint result = provision_match_spn(ap2, spn) -
|
||||
provision_match_spn(ap1, spn);
|
||||
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
if (ap1->provider_primary && !ap2->provider_primary) {
|
||||
return -1;
|
||||
} else if (ap2->provider_primary && !ap1->provider_primary) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Picks best ap, deletes the rest. Creates one if necessary */
|
||||
static GSList *provision_pick_best_ap(GSList *list, const char *spn,
|
||||
const enum ofono_gprs_proto default_proto,
|
||||
const struct provision_ap_defaults *defaults)
|
||||
{
|
||||
/* Sort the list */
|
||||
list = g_slist_sort_with_data(list, provision_compare_ap, (void*)spn);
|
||||
if (list) {
|
||||
/* Pick the best one, delete the rest */
|
||||
GSList *best = list;
|
||||
g_slist_free_full(g_slist_remove_link(list, best),
|
||||
provision_free_ap);
|
||||
return best;
|
||||
} else {
|
||||
/* or create one from the default data */
|
||||
struct ofono_gprs_provision_data *ap =
|
||||
g_new0(struct ofono_gprs_provision_data, 1);
|
||||
|
||||
ap->proto = default_proto;
|
||||
ap->type = defaults->type;
|
||||
ap->name = g_strdup(defaults->name);
|
||||
ap->apn = g_strdup(defaults->apn);
|
||||
ap->auth_method = OFONO_GPRS_AUTH_METHOD_NONE;
|
||||
return g_slist_append(NULL, ap);
|
||||
}
|
||||
}
|
||||
|
||||
/* Returns the list containing exactly one INTERNET and one MMS access point */
|
||||
static GSList *provision_normalize_apn_list(GSList *apns, const char *spn)
|
||||
{
|
||||
static const struct provision_ap_defaults internet_defaults =
|
||||
{ OFONO_GPRS_CONTEXT_TYPE_INTERNET, "Internet", "internet" };
|
||||
static const struct provision_ap_defaults mms_defaults =
|
||||
{ OFONO_GPRS_CONTEXT_TYPE_MMS, "MMS", "mms" };
|
||||
|
||||
GSList *internet_apns = NULL;
|
||||
GSList *mms_apns = NULL;
|
||||
|
||||
/* Split internet and mms apns, delete all others */
|
||||
while (apns) {
|
||||
GSList *link = apns;
|
||||
struct ofono_gprs_provision_data *ap = link->data;
|
||||
|
||||
apns = g_slist_remove_link(apns, link);
|
||||
if (ap->type == OFONO_GPRS_CONTEXT_TYPE_INTERNET) {
|
||||
internet_apns = g_slist_concat(internet_apns, link);
|
||||
} else if (ap->type == OFONO_GPRS_CONTEXT_TYPE_MMS) {
|
||||
mms_apns = g_slist_concat(mms_apns, link);
|
||||
} else {
|
||||
g_slist_free_full(link, provision_free_ap);
|
||||
}
|
||||
}
|
||||
|
||||
/* Pick the best ap of each type and concatenate them */
|
||||
return g_slist_concat(
|
||||
provision_pick_best_ap(internet_apns, spn,
|
||||
mbpi_default_internet_proto, &internet_defaults),
|
||||
provision_pick_best_ap(mms_apns, spn,
|
||||
mbpi_default_mms_proto, &mms_defaults));
|
||||
}
|
||||
|
||||
int provision_get_settings(const char *mcc, const char *mnc,
|
||||
const char *spn,
|
||||
struct ofono_gprs_provision_data **settings,
|
||||
int *count)
|
||||
{
|
||||
GSList *l;
|
||||
GSList *apns;
|
||||
GError *error = NULL;
|
||||
int ap_count;
|
||||
int i;
|
||||
|
||||
ofono_info("Provisioning for MCC %s, MNC %s, SPN '%s'", mcc, mnc, spn);
|
||||
|
||||
/*
|
||||
* Passing FALSE to mbpi_lookup_apn() would return
|
||||
* an empty list if duplicates are found.
|
||||
*/
|
||||
apns = mbpi_lookup_apn(mcc, mnc, TRUE, &error);
|
||||
if (error != NULL) {
|
||||
ofono_error("%s", error->message);
|
||||
g_error_free(error);
|
||||
}
|
||||
|
||||
DBG("Found %d APs in MBPI", g_slist_length(apns));
|
||||
apns = provision_normalize_apn_list(apns, spn);
|
||||
ap_count = g_slist_length(apns);
|
||||
|
||||
DBG("Provisioning %d APs", ap_count);
|
||||
*settings = g_new0(struct ofono_gprs_provision_data, ap_count);
|
||||
*count = ap_count;
|
||||
|
||||
for (l = apns, i = 0; l; l = l->next, i++) {
|
||||
struct ofono_gprs_provision_data *ap = l->data;
|
||||
|
||||
ofono_info("Name: '%s'", ap->name);
|
||||
ofono_info(" APN: '%s'", ap->apn);
|
||||
ofono_info(" Type: %s", mbpi_ap_type(ap->type));
|
||||
ofono_info(" Username: '%s'", ap->username);
|
||||
ofono_info(" Password: '%s'", ap->password);
|
||||
|
||||
memcpy(*settings + i, ap,
|
||||
sizeof(struct ofono_gprs_provision_data));
|
||||
|
||||
g_free(ap);
|
||||
}
|
||||
|
||||
g_slist_free(apns);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct ofono_gprs_provision_driver provision_driver = {
|
||||
.name = "Provisioning",
|
||||
.get_settings = provision_get_settings
|
||||
};
|
||||
|
||||
static int provision_init(void)
|
||||
{
|
||||
DBG("");
|
||||
return ofono_gprs_provision_driver_register(&provision_driver);
|
||||
}
|
||||
|
||||
static void provision_exit(void)
|
||||
{
|
||||
DBG("");
|
||||
ofono_gprs_provision_driver_unregister(&provision_driver);
|
||||
}
|
||||
|
||||
OFONO_PLUGIN_DEFINE(provision, "Provisioning Plugin", VERSION,
|
||||
OFONO_PLUGIN_PRIORITY_DEFAULT,
|
||||
provision_init, provision_exit)
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2013-2014 Jolla Ltd.
|
||||
* Copyright (C) 2013-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
|
||||
@@ -9,17 +9,13 @@
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <glib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <gutil_inotify.h>
|
||||
#include <sys/inotify.h>
|
||||
#include <wspcodec.h>
|
||||
|
||||
@@ -75,10 +71,7 @@ struct push_datagram_handler {
|
||||
static GSList *handlers;
|
||||
static GSList *modems;
|
||||
static unsigned int modem_watch_id;
|
||||
static int inotify_fd = -1;
|
||||
static int inotify_watch_id = -1;
|
||||
static guint inotify_watch_source_id;
|
||||
static GIOChannel *inotify_watch_channel;
|
||||
static GUtilInotifyWatchCallback *inotify_cb;
|
||||
|
||||
static void pf_notify_handler(struct push_datagram_handler *h,
|
||||
const char *imsi, const char *from, const struct tm *remote,
|
||||
@@ -277,10 +270,7 @@ static void pf_modem_watch(struct ofono_modem *modem,
|
||||
if (added != FALSE) {
|
||||
struct pf_modem *pm;
|
||||
|
||||
pm = g_try_new0(struct pf_modem, 1);
|
||||
if (pm == NULL)
|
||||
return;
|
||||
|
||||
pm = g_new0(struct pf_modem, 1);
|
||||
pm->modem = modem;
|
||||
pm->sms_watch_id = __ofono_modem_add_atom_watch(modem,
|
||||
OFONO_ATOM_TYPE_SMS, pf_sms_watch, pm,
|
||||
@@ -349,10 +339,7 @@ static void pf_parse_handler(GKeyFile *conf, const char *g)
|
||||
if (path == NULL)
|
||||
goto no_path;
|
||||
|
||||
h = g_try_new0(struct push_datagram_handler, 1);
|
||||
if (h == NULL)
|
||||
goto no_memory;
|
||||
|
||||
h = g_new0(struct push_datagram_handler, 1);
|
||||
h->name = g_strdup(g);
|
||||
h->interface = interface;
|
||||
h->service = service;
|
||||
@@ -385,9 +372,6 @@ static void pf_parse_handler(GKeyFile *conf, const char *g)
|
||||
handlers = g_slist_append(handlers, h);
|
||||
return;
|
||||
|
||||
no_memory:
|
||||
g_free(path);
|
||||
|
||||
no_path:
|
||||
g_free(method);
|
||||
|
||||
@@ -448,30 +432,11 @@ static void pf_parse_config(void)
|
||||
g_dir_close(dir);
|
||||
}
|
||||
|
||||
static gboolean pf_inotify(GIOChannel *gio, GIOCondition c, gpointer data)
|
||||
static void pf_inotify(GUtilInotifyWatch *watch, guint mask, guint cookie,
|
||||
const char *name, void *user_data)
|
||||
{
|
||||
int avail;
|
||||
gsize len;
|
||||
void *buf;
|
||||
GError *error;
|
||||
|
||||
if (ioctl(inotify_fd, FIONREAD, &avail) < 0)
|
||||
return FALSE;
|
||||
|
||||
buf = g_try_malloc(avail);
|
||||
if (buf == NULL)
|
||||
return FALSE;
|
||||
|
||||
error = NULL;
|
||||
if (g_io_channel_read_chars(gio, buf, avail, &len, &error) !=
|
||||
G_IO_STATUS_NORMAL) {
|
||||
g_free(buf);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
DBG("'%s' changed (0x%04x)", name, mask);
|
||||
pf_parse_config();
|
||||
g_free(buf);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static int pf_plugin_init(void)
|
||||
@@ -480,37 +445,8 @@ static int pf_plugin_init(void)
|
||||
pf_parse_config();
|
||||
modem_watch_id = __ofono_modemwatch_add(pf_modem_watch, NULL, NULL);
|
||||
__ofono_modem_foreach(pf_modem_init, NULL);
|
||||
inotify_fd = inotify_init();
|
||||
if (inotify_fd < 0)
|
||||
return 0;
|
||||
|
||||
inotify_watch_id = inotify_add_watch(inotify_fd,
|
||||
PF_CONFIG_DIR,
|
||||
IN_CLOSE_WRITE | IN_DELETE | IN_MOVE);
|
||||
if (inotify_watch_id < 0)
|
||||
goto no_inotify_watch_id;
|
||||
|
||||
inotify_watch_channel = g_io_channel_unix_new(inotify_fd);
|
||||
if (inotify_watch_channel == NULL)
|
||||
goto no_inotify_watch_channel;
|
||||
|
||||
g_io_channel_set_encoding(inotify_watch_channel, NULL, NULL);
|
||||
g_io_channel_set_buffered(inotify_watch_channel, FALSE);
|
||||
inotify_watch_source_id = g_io_add_watch(inotify_watch_channel,
|
||||
G_IO_IN, pf_inotify, NULL);
|
||||
if (inotify_watch_source_id != 0)
|
||||
return 0;
|
||||
|
||||
g_io_channel_unref(inotify_watch_channel);
|
||||
inotify_watch_channel = NULL;
|
||||
|
||||
no_inotify_watch_channel:
|
||||
inotify_rm_watch(inotify_fd, inotify_watch_id);
|
||||
inotify_watch_id = -1;
|
||||
|
||||
no_inotify_watch_id:
|
||||
close(inotify_fd);
|
||||
inotify_fd = -1;
|
||||
inotify_cb = gutil_inotify_watch_callback_new(PF_CONFIG_DIR,
|
||||
IN_CLOSE_WRITE | IN_DELETE | IN_MOVE, pf_inotify, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -523,19 +459,18 @@ static void pf_plugin_exit(void)
|
||||
modems = NULL;
|
||||
g_slist_free_full(handlers, pf_free_handler);
|
||||
handlers = NULL;
|
||||
if (inotify_watch_source_id == 0)
|
||||
return;
|
||||
|
||||
g_source_remove(inotify_watch_source_id);
|
||||
inotify_watch_source_id = 0;
|
||||
g_io_channel_unref(inotify_watch_channel);
|
||||
inotify_watch_channel = NULL;
|
||||
inotify_rm_watch(inotify_fd, inotify_watch_id);
|
||||
inotify_watch_id = -1;
|
||||
close(inotify_fd);
|
||||
inotify_fd = -1;
|
||||
gutil_inotify_watch_callback_free(inotify_cb);
|
||||
inotify_cb = NULL;
|
||||
}
|
||||
|
||||
OFONO_PLUGIN_DEFINE(push_forwarder, "Push Forwarder Plugin", VERSION,
|
||||
OFONO_PLUGIN_DEFINE(pushforwarder, "Push Forwarder Plugin", VERSION,
|
||||
OFONO_PLUGIN_PRIORITY_DEFAULT, pf_plugin_init,
|
||||
pf_plugin_exit)
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
@@ -34,6 +34,7 @@
|
||||
#include <net/route.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include <glib.h>
|
||||
#include <gdbus.h>
|
||||
@@ -258,6 +259,10 @@ static gboolean gprs_proto_from_string(const char *str,
|
||||
static const char *gprs_auth_method_to_string(enum ofono_gprs_auth_method auth)
|
||||
{
|
||||
switch (auth) {
|
||||
case OFONO_GPRS_AUTH_METHOD_ANY:
|
||||
return "any";
|
||||
case OFONO_GPRS_AUTH_METHOD_NONE:
|
||||
return "none";
|
||||
case OFONO_GPRS_AUTH_METHOD_CHAP:
|
||||
return "chap";
|
||||
case OFONO_GPRS_AUTH_METHOD_PAP:
|
||||
@@ -276,6 +281,12 @@ static gboolean gprs_auth_method_from_string(const char *str,
|
||||
} else if (g_str_equal(str, "pap")) {
|
||||
*auth = OFONO_GPRS_AUTH_METHOD_PAP;
|
||||
return TRUE;
|
||||
} else if (g_str_equal(str, "any")) {
|
||||
*auth = OFONO_GPRS_AUTH_METHOD_ANY;
|
||||
return TRUE;
|
||||
} else if (g_str_equal(str, "none")) {
|
||||
*auth = OFONO_GPRS_AUTH_METHOD_NONE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
@@ -641,7 +652,48 @@ static gboolean pri_parse_proxy(struct pri_context *ctx, const char *proxy)
|
||||
}
|
||||
|
||||
g_free(ctx->proxy_host);
|
||||
ctx->proxy_host = g_strdup(host);
|
||||
ctx->proxy_host = NULL;
|
||||
|
||||
if (host[0] == '0' || strstr(host, ".0")) {
|
||||
/*
|
||||
* Some operators provide IP address of the MMS proxy
|
||||
* prepending zeros to each number shorter then 3 digits,
|
||||
* e.g. "192.168.094.023" instead of "192.168.94.23".
|
||||
* That may look nicer but it's actually wrong because
|
||||
* the numbers starting with zeros are interpreted as
|
||||
* octal numbers. In the example above 023 actually means
|
||||
* 16 and 094 is not a valid number at all.
|
||||
*
|
||||
* In addition to publishing these broken settings on their
|
||||
* web sites, some of the operators send them over the air,
|
||||
* in which case we can't even blame the user for entering
|
||||
* an invalid IP address. We better be prepared to deal with
|
||||
* those.
|
||||
*
|
||||
* Since nobody in the world seems to be actually using the
|
||||
* octal notation to write an IP address, let's remove the
|
||||
* leading zeros if we find them in the host part of the MMS
|
||||
* proxy URL.
|
||||
*/
|
||||
char** parts = g_strsplit(host, ".", -1);
|
||||
guint count = g_strv_length(parts);
|
||||
if (count == 4) {
|
||||
char** ptr = parts;
|
||||
while (*ptr) {
|
||||
char* part = *ptr;
|
||||
while (part[0] == '0' && isdigit(part[1])) {
|
||||
memmove(part, part+1, strlen(part));
|
||||
}
|
||||
*ptr++ = part;
|
||||
}
|
||||
ctx->proxy_host = g_strjoinv(".", parts);
|
||||
DBG("%s => %s", host, ctx->proxy_host);
|
||||
}
|
||||
g_strfreev(parts);
|
||||
}
|
||||
|
||||
if (!ctx->proxy_host)
|
||||
ctx->proxy_host = g_strdup(host);
|
||||
|
||||
g_free(scheme);
|
||||
return TRUE;
|
||||
@@ -892,6 +944,13 @@ static void pri_reset_context_properties(struct pri_context *ctx,
|
||||
gprs_proto_to_string(ctx->context.proto));
|
||||
}
|
||||
|
||||
if (ctx->context.auth_method != ap->auth_method) {
|
||||
ctx->context.auth_method = ap->auth_method;
|
||||
changed = TRUE;
|
||||
pri_str_signal_change(ctx, "AuthenticationMethod",
|
||||
gprs_auth_method_to_string(ctx->context.auth_method));
|
||||
}
|
||||
|
||||
if (ap->type == OFONO_GPRS_CONTEXT_TYPE_MMS) {
|
||||
if (pri_str_update(ctx->message_proxy, ap->message_proxy,
|
||||
sizeof(ctx->message_proxy))) {
|
||||
@@ -2274,6 +2333,11 @@ static DBusMessage *gprs_add_context(DBusConnection *conn,
|
||||
const char *path;
|
||||
enum ofono_gprs_context_type type;
|
||||
|
||||
#ifdef DISABLE_ADD_REMOVE_CONTEXT
|
||||
ofono_error("AddContext not allowed");
|
||||
return __ofono_error_not_supported(msg);
|
||||
#endif
|
||||
|
||||
if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &typestr,
|
||||
DBUS_TYPE_INVALID))
|
||||
return __ofono_error_invalid_args(msg);
|
||||
@@ -2355,6 +2419,11 @@ static DBusMessage *gprs_remove_context(DBusConnection *conn,
|
||||
const char *path;
|
||||
const char *atompath;
|
||||
|
||||
#ifdef DISABLE_ADD_REMOVE_CONTEXT
|
||||
ofono_error("RemoveContext not allowed");
|
||||
return __ofono_error_not_supported(msg);
|
||||
#endif
|
||||
|
||||
if (gprs->pending)
|
||||
return __ofono_error_busy(msg);
|
||||
|
||||
|
||||
@@ -143,7 +143,7 @@ void ofono_debug(const char *format, ...)
|
||||
}
|
||||
}
|
||||
|
||||
void __ofono_dbg(const struct ofono_debug_desc *desc, const char *format, ...)
|
||||
void ofono_dbg(const struct ofono_debug_desc *desc, const char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - RIL-based devices
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* Copyright (C) 2016 Jolla Ltd.
|
||||
* 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
|
||||
@@ -13,16 +13,23 @@
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "ril_mtu.h"
|
||||
#include "ril_log.h"
|
||||
#include "mtu-watch.h"
|
||||
|
||||
#include <net/if.h>
|
||||
#include <ofono/log.h>
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/types.h>
|
||||
#include <net/if.h>
|
||||
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
|
||||
struct ril_mtu_watch {
|
||||
struct mtu_watch {
|
||||
int max_mtu;
|
||||
char *ifname;
|
||||
void *buf;
|
||||
@@ -32,7 +39,7 @@ struct ril_mtu_watch {
|
||||
int fd;
|
||||
};
|
||||
|
||||
static void ril_mtu_watch_limit_mtu(struct ril_mtu_watch *self)
|
||||
static void mtu_watch_limit_mtu(struct mtu_watch *self)
|
||||
{
|
||||
int fd = socket(PF_INET, SOCK_DGRAM, 0);
|
||||
if (fd >= 0) {
|
||||
@@ -52,7 +59,7 @@ static void ril_mtu_watch_limit_mtu(struct ril_mtu_watch *self)
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_mtu_watch_handle_rtattr(struct ril_mtu_watch *self,
|
||||
static void mtu_watch_handle_rtattr(struct mtu_watch *self,
|
||||
const struct rtattr *rta, int len)
|
||||
{
|
||||
int mtu = 0;
|
||||
@@ -70,43 +77,43 @@ static void ril_mtu_watch_handle_rtattr(struct ril_mtu_watch *self,
|
||||
}
|
||||
if (mtu > self->max_mtu && !g_strcmp0(ifname, self->ifname)) {
|
||||
DBG("%s %d", ifname, mtu);
|
||||
ril_mtu_watch_limit_mtu(self);
|
||||
mtu_watch_limit_mtu(self);
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_mtu_watch_handle_ifinfomsg(struct ril_mtu_watch *self,
|
||||
static void mtu_watch_handle_ifinfomsg(struct mtu_watch *self,
|
||||
const struct ifinfomsg *ifi, int len)
|
||||
{
|
||||
if (ifi->ifi_flags & IFF_UP) {
|
||||
const struct rtattr *rta = IFLA_RTA(ifi);
|
||||
ril_mtu_watch_handle_rtattr(self, rta,
|
||||
mtu_watch_handle_rtattr(self, rta,
|
||||
len - ((char*)rta - (char*)ifi));
|
||||
}
|
||||
}
|
||||
|
||||
static void ril_mtu_watch_handle_nlmsg(struct ril_mtu_watch *self,
|
||||
static void mtu_watch_handle_nlmsg(struct mtu_watch *self,
|
||||
const struct nlmsghdr *hdr, int len)
|
||||
{
|
||||
while (len > 0 && NLMSG_OK(hdr, len)) {
|
||||
if (hdr->nlmsg_type == RTM_NEWLINK) {
|
||||
ril_mtu_watch_handle_ifinfomsg(self, NLMSG_DATA(hdr),
|
||||
mtu_watch_handle_ifinfomsg(self, NLMSG_DATA(hdr),
|
||||
IFLA_PAYLOAD(hdr));
|
||||
}
|
||||
hdr = NLMSG_NEXT(hdr, len);
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean ril_mtu_watch_event(GIOChannel *ch, GIOCondition cond,
|
||||
static gboolean mtu_watch_event(GIOChannel *ch, GIOCondition cond,
|
||||
gpointer data)
|
||||
{
|
||||
struct ril_mtu_watch *self = data;
|
||||
struct mtu_watch *self = data;
|
||||
struct sockaddr_nl addr;
|
||||
socklen_t addrlen = sizeof(addr);
|
||||
ssize_t result = recvfrom(self->fd, self->buf, self->bufsize, 0,
|
||||
(struct sockaddr *)&addr, &addrlen);
|
||||
if (result > 0) {
|
||||
if (!addr.nl_pid) {
|
||||
ril_mtu_watch_handle_nlmsg(self, self->buf, result);
|
||||
mtu_watch_handle_nlmsg(self, self->buf, result);
|
||||
}
|
||||
return G_SOURCE_CONTINUE;
|
||||
} else if (result == 0 || errno == EINTR || errno == EAGAIN) {
|
||||
@@ -118,9 +125,8 @@ static gboolean ril_mtu_watch_event(GIOChannel *ch, GIOCondition cond,
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean ril_mtu_watch_open_socket(struct ril_mtu_watch *self)
|
||||
static gboolean mtu_watch_open_socket(struct mtu_watch *self)
|
||||
{
|
||||
GASSERT(self->fd < 0);
|
||||
self->fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
|
||||
if (self->fd >= 0) {
|
||||
struct sockaddr_nl nl;
|
||||
@@ -140,20 +146,18 @@ static gboolean ril_mtu_watch_open_socket(struct ril_mtu_watch *self)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean ril_mtu_watch_start(struct ril_mtu_watch *self)
|
||||
static gboolean mtu_watch_start(struct mtu_watch *self)
|
||||
{
|
||||
if (self->fd >= 0) {
|
||||
return TRUE;
|
||||
} else if (ril_mtu_watch_open_socket(self)) {
|
||||
GASSERT(!self->channel);
|
||||
GASSERT(!self->io_watch);
|
||||
} else if (mtu_watch_open_socket(self)) {
|
||||
self->channel = g_io_channel_unix_new(self->fd);
|
||||
if (self->channel) {
|
||||
g_io_channel_set_encoding(self->channel, NULL, NULL);
|
||||
g_io_channel_set_buffered(self->channel, FALSE);
|
||||
self->io_watch = g_io_add_watch(self->channel,
|
||||
G_IO_IN | G_IO_NVAL | G_IO_HUP,
|
||||
ril_mtu_watch_event, self);
|
||||
mtu_watch_event, self);
|
||||
return TRUE;
|
||||
}
|
||||
close(self->fd);
|
||||
@@ -162,7 +166,7 @@ static gboolean ril_mtu_watch_start(struct ril_mtu_watch *self)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void ril_mtu_watch_stop(struct ril_mtu_watch *self)
|
||||
static void mtu_watch_stop(struct mtu_watch *self)
|
||||
{
|
||||
if (self->io_watch) {
|
||||
g_source_remove(self->io_watch);
|
||||
@@ -179,9 +183,9 @@ static void ril_mtu_watch_stop(struct ril_mtu_watch *self)
|
||||
}
|
||||
}
|
||||
|
||||
struct ril_mtu_watch *ril_mtu_watch_new(int max_mtu)
|
||||
struct mtu_watch *mtu_watch_new(int max_mtu)
|
||||
{
|
||||
struct ril_mtu_watch *self = g_new0(struct ril_mtu_watch, 1);
|
||||
struct mtu_watch *self = g_new0(struct mtu_watch, 1);
|
||||
self->fd = -1;
|
||||
self->max_mtu = max_mtu;
|
||||
self->bufsize = 4096;
|
||||
@@ -189,35 +193,27 @@ struct ril_mtu_watch *ril_mtu_watch_new(int max_mtu)
|
||||
return self;
|
||||
}
|
||||
|
||||
void ril_mtu_watch_free(struct ril_mtu_watch *self)
|
||||
void mtu_watch_free(struct mtu_watch *self)
|
||||
{
|
||||
if (self) {
|
||||
ril_mtu_watch_stop(self);
|
||||
mtu_watch_stop(self);
|
||||
g_free(self->ifname);
|
||||
g_free(self->buf);
|
||||
g_free(self);
|
||||
}
|
||||
}
|
||||
|
||||
void ril_mtu_watch_set_ifname(struct ril_mtu_watch *self, const char *ifname)
|
||||
void mtu_watch_set_ifname(struct mtu_watch *self, const char *ifname)
|
||||
{
|
||||
if (self && g_strcmp0(self->ifname, ifname)) {
|
||||
g_free(self->ifname);
|
||||
if (ifname) {
|
||||
self->ifname = g_strdup(ifname);
|
||||
ril_mtu_watch_limit_mtu(self);
|
||||
ril_mtu_watch_start(self);
|
||||
mtu_watch_limit_mtu(self);
|
||||
mtu_watch_start(self);
|
||||
} else {
|
||||
self->ifname = NULL;
|
||||
ril_mtu_watch_stop(self);
|
||||
mtu_watch_stop(self);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
25
ofono/src/mtu-watch.h
Normal file
25
ofono/src/mtu-watch.h
Normal file
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony
|
||||
*
|
||||
* 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 MTU_WATCH_H
|
||||
#define MTU_WATCH_H
|
||||
|
||||
struct mtu_watch;
|
||||
|
||||
struct mtu_watch *mtu_watch_new(int max_mtu);
|
||||
void mtu_watch_free(struct mtu_watch *mw);
|
||||
void mtu_watch_set_ifname(struct mtu_watch *mw, const char *ifname);
|
||||
|
||||
#endif /* MTU_WATCH_H */
|
||||
@@ -1828,6 +1828,17 @@ const char *ofono_netreg_get_mnc(struct ofono_netreg *netreg)
|
||||
return netreg->current_operator->mnc;
|
||||
}
|
||||
|
||||
const char *ofono_netreg_get_name(struct ofono_netreg *netreg)
|
||||
{
|
||||
if (netreg == NULL)
|
||||
return NULL;
|
||||
|
||||
if (netreg->current_operator == NULL)
|
||||
return NULL;
|
||||
|
||||
return netreg->current_operator->name;
|
||||
}
|
||||
|
||||
struct sim_spdi *ofono_netreg_get_spdi(struct ofono_netreg *netreg)
|
||||
{
|
||||
if (netreg == NULL)
|
||||
|
||||
@@ -386,6 +386,9 @@ void __ofono_sim_refresh(struct ofono_sim *sim, GSList *file_list,
|
||||
|
||||
void __ofono_sim_recheck_pin(struct ofono_sim *sim);
|
||||
|
||||
enum ofono_sim_password_type __ofono_sim_puk2pin(
|
||||
enum ofono_sim_password_type type);
|
||||
|
||||
#include <ofono/stk.h>
|
||||
|
||||
typedef void (*__ofono_sms_sim_download_cb_t)(ofono_bool_t ok,
|
||||
|
||||
@@ -889,9 +889,13 @@ static void radio_load_settings(struct ofono_radio_settings *rs,
|
||||
"GsmBand", rs->band_gsm);
|
||||
}
|
||||
|
||||
if (error) {
|
||||
g_error_free(error);
|
||||
error = NULL;
|
||||
}
|
||||
|
||||
rs->pending_band_gsm = rs->band_gsm;
|
||||
|
||||
error = NULL;
|
||||
rs->band_umts = g_key_file_get_integer(rs->settings, SETTINGS_GROUP,
|
||||
"UmtsBand", &error);
|
||||
|
||||
@@ -901,9 +905,13 @@ static void radio_load_settings(struct ofono_radio_settings *rs,
|
||||
"UmtsBand", rs->band_umts);
|
||||
}
|
||||
|
||||
if (error) {
|
||||
g_error_free(error);
|
||||
error = NULL;
|
||||
}
|
||||
|
||||
rs->pending_band_umts = rs->band_umts;
|
||||
|
||||
error = NULL;
|
||||
rs->mode = g_key_file_get_integer(rs->settings, SETTINGS_GROUP,
|
||||
"TechnologyPreference", &error);
|
||||
|
||||
@@ -913,6 +921,11 @@ static void radio_load_settings(struct ofono_radio_settings *rs,
|
||||
"TechnologyPreference", rs->mode);
|
||||
}
|
||||
|
||||
if (error) {
|
||||
g_error_free(error);
|
||||
error = NULL;
|
||||
}
|
||||
|
||||
DBG("TechnologyPreference: %d", rs->mode);
|
||||
DBG("GsmBand: %d", rs->band_gsm);
|
||||
DBG("UmtsBand: %d", rs->band_umts);
|
||||
|
||||
@@ -197,7 +197,10 @@ static gboolean password_is_pin(enum ofono_sim_password_type type)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static enum ofono_sim_password_type puk2pin(enum ofono_sim_password_type type)
|
||||
#define puk2pin(type) __ofono_sim_puk2pin(type)
|
||||
|
||||
enum ofono_sim_password_type __ofono_sim_puk2pin(
|
||||
enum ofono_sim_password_type type)
|
||||
{
|
||||
switch (type) {
|
||||
case OFONO_SIM_PASSWORD_SIM_PUK:
|
||||
|
||||
@@ -226,6 +226,9 @@ void sim_fs_notify_file_watches(struct sim_fs *fs, int id)
|
||||
struct ofono_sim_context *context = l->data;
|
||||
GSList *k;
|
||||
|
||||
if (context->file_watches == NULL)
|
||||
continue;
|
||||
|
||||
for (k = context->file_watches->items; k; k = k->next) {
|
||||
struct file_watch *w = k->data;
|
||||
ofono_sim_file_changed_cb_t notify = w->item.notify;
|
||||
|
||||
@@ -1182,7 +1182,8 @@ static gboolean compute_incoming_msgid(GSList *sms_list,
|
||||
static void dispatch_app_datagram(struct ofono_sms *sms,
|
||||
const struct ofono_uuid *uuid,
|
||||
int dst, int src,
|
||||
unsigned char *buf, unsigned len,
|
||||
const unsigned char *buf,
|
||||
unsigned int len,
|
||||
const struct sms_address *addr,
|
||||
const struct sms_scts *scts)
|
||||
{
|
||||
|
||||
@@ -4134,12 +4134,13 @@ char *cbs_decode_text(GSList *cbs_list, char *iso639_lang)
|
||||
*/
|
||||
for (; i < written; i++, bufsize++) {
|
||||
if (unpacked[i] == '\r') {
|
||||
int t;
|
||||
int j;
|
||||
|
||||
t = strspn((const char *) unpacked + i,
|
||||
"\r");
|
||||
for (j = i + 1; j < written; j++)
|
||||
if (unpacked[j] != '\r')
|
||||
break;
|
||||
|
||||
if (t + i == written)
|
||||
if (j == written)
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -28,6 +28,11 @@
|
||||
#include <fcntl.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
/* STORAGEDIR may need to be redefined in unit tests */
|
||||
#ifndef STORAGEDIR
|
||||
# define STORAGEDIR DEFAULT_STORAGEDIR
|
||||
#endif
|
||||
|
||||
int create_dirs(const char *filename, const mode_t mode);
|
||||
|
||||
ssize_t read_file(unsigned char *buffer, size_t len,
|
||||
|
||||
@@ -514,6 +514,20 @@ void ofono_ussd_notify(struct ofono_ussd *ussd, int status, int dcs,
|
||||
DBUS_TYPE_STRING, &str, DBUS_TYPE_INVALID);
|
||||
|
||||
ussd_change_state(ussd, new_state);
|
||||
goto free;
|
||||
} else if (ussd->state == USSD_STATE_USER_ACTION &&
|
||||
status != OFONO_USSD_STATUS_ACTION_REQUIRED) {
|
||||
ussd_change_state(ussd, USSD_STATE_IDLE);
|
||||
|
||||
if (status == OFONO_USSD_STATUS_NOTIFY && str && str[0]) {
|
||||
const char *path = __ofono_atom_get_path(ussd->atom);
|
||||
|
||||
g_dbus_emit_signal(conn, path,
|
||||
OFONO_SUPPLEMENTARY_SERVICES_INTERFACE,
|
||||
"NotificationReceived", DBUS_TYPE_STRING,
|
||||
&str, DBUS_TYPE_INVALID);
|
||||
}
|
||||
|
||||
goto free;
|
||||
} else {
|
||||
ofono_error("Received an unsolicited USSD but can't handle.");
|
||||
|
||||
@@ -3748,6 +3748,15 @@ int ofono_voicecall_get_next_callid(struct ofono_voicecall *vc)
|
||||
return __ofono_modem_callid_next(modem);
|
||||
}
|
||||
|
||||
struct ofono_call *ofono_voicecall_find_call(struct ofono_voicecall *vc,
|
||||
unsigned int id)
|
||||
{
|
||||
GSList *l = g_slist_find_custom(vc->call_list, GUINT_TO_POINTER(id),
|
||||
call_compare_by_id);
|
||||
|
||||
return l ? ((struct voicecall *)l->data)->call : NULL;
|
||||
}
|
||||
|
||||
ofono_bool_t __ofono_voicecall_is_busy(struct ofono_voicecall *vc,
|
||||
enum ofono_voicecall_interaction type)
|
||||
{
|
||||
|
||||
62
ofono/unit/coverage
Executable file
62
ofono/unit/coverage
Executable file
@@ -0,0 +1,62 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# Script to generate unit test coverage report, requires lcov:
|
||||
#
|
||||
# http://ltp.sourceforge.net/coverage/lcov.php
|
||||
#
|
||||
|
||||
# Tests with coverage enabled:
|
||||
TESTS="\
|
||||
test-common \
|
||||
test-util \
|
||||
test-idmap \
|
||||
test-simutil \
|
||||
test-stkutil \
|
||||
test-sms \
|
||||
test-cdmasms \
|
||||
test-sms-root \
|
||||
test-caif \
|
||||
test-provision \
|
||||
test-ril_util \
|
||||
test-sailfish_cell_info \
|
||||
test-sailfish_manager \
|
||||
test-sailfish_sim_info"
|
||||
|
||||
pushd `dirname $0` > /dev/null
|
||||
TEST_DIR="$PWD"
|
||||
pushd .. > /dev/null
|
||||
BASE_DIR="$PWD"
|
||||
popd > /dev/null
|
||||
popd > /dev/null
|
||||
|
||||
FULL_COV="$TEST_DIR/full.gcov"
|
||||
DRIVERS_COV="$TEST_DIR/drivers.gcov"
|
||||
PLUGINS_COV="$TEST_DIR/plugins.gcov"
|
||||
SRC_COV="$TEST_DIR/src.gcov"
|
||||
OUT="$TEST_DIR/html"
|
||||
|
||||
# Clean everything up
|
||||
find "$BASE_DIR" -name "*.gcda" -exec rm {} \;
|
||||
rm -f "$FULL_COV" "$DRIVERS_COV" "$PLUGINS_COV" "$SRC_COV"
|
||||
rm -fr "$OUT"
|
||||
|
||||
# Run the tests
|
||||
for t in $TESTS ; do
|
||||
pushd "$TEST_DIR" > /dev/null
|
||||
"$TEST_DIR/$t"
|
||||
RC=$?
|
||||
popd > /dev/null
|
||||
[ $RC = 0 ] || exit 1
|
||||
done
|
||||
|
||||
# LCOV 1.10 has branch coverage disabled per default
|
||||
LCOV_OPT="--rc lcov_branch_coverage=1"
|
||||
GENHTML_OPT="--branch-coverage"
|
||||
|
||||
lcov $LCOV_OPT -c -d "$BASE_DIR" -o "$FULL_COV" || exit 1
|
||||
lcov $LCOV_OPT -e "$FULL_COV" "$BASE_DIR/drivers/*" -o "$DRIVERS_COV" || exit 1
|
||||
lcov $LCOV_OPT -e "$FULL_COV" "$BASE_DIR/plugins/*" -o "$PLUGINS_COV" || exit 1
|
||||
lcov $LCOV_OPT -e "$FULL_COV" "$BASE_DIR/src/*" -o "$SRC_COV" || exit 1
|
||||
genhtml $GENHTML_OPT -t ofono "$DRIVERS_COV" "$PLUGINS_COV" "$SRC_COV" --output-directory "$OUT" || exit 1
|
||||
|
||||
echo Coverage report: $OUT/index.html
|
||||
326
ofono/unit/fake_sailfish_watch.c
Normal file
326
ofono/unit/fake_sailfish_watch.c
Normal file
@@ -0,0 +1,326 @@
|
||||
/*
|
||||
* 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_watch.h"
|
||||
|
||||
#include <gutil_misc.h>
|
||||
#include <gutil_log.h>
|
||||
|
||||
#include "ofono.h"
|
||||
|
||||
typedef GObjectClass SailfishWatchClass;
|
||||
typedef struct sailfish_watch SailfishWatch;
|
||||
|
||||
struct sailfish_watch_priv {
|
||||
char *path;
|
||||
char *iccid;
|
||||
char *imsi;
|
||||
char *spn;
|
||||
int queued_signals;
|
||||
};
|
||||
|
||||
#define SIGNAL_MODEM_CHANGED_NAME "sailfish-watch-modem-changed"
|
||||
#define SIGNAL_ONLINE_CHANGED_NAME "sailfish-watch-online-changed"
|
||||
#define SIGNAL_SIM_CHANGED_NAME "sailfish-watch-sim-changed"
|
||||
#define SIGNAL_SIM_STATE_CHANGED_NAME "sailfish-watch-sim-state-changed"
|
||||
#define SIGNAL_ICCID_CHANGED_NAME "sailfish-watch-iccid-changed"
|
||||
#define SIGNAL_IMSI_CHANGED_NAME "sailfish-watch-imsi-changed"
|
||||
#define SIGNAL_SPN_CHANGED_NAME "sailfish-watch-spn-changed"
|
||||
#define SIGNAL_NETREG_CHANGED_NAME "sailfish-watch-netreg-changed"
|
||||
|
||||
static guint sailfish_watch_signals[WATCH_SIGNAL_COUNT] = { 0 };
|
||||
static GHashTable* sailfish_watch_table = NULL;
|
||||
|
||||
G_DEFINE_TYPE(SailfishWatch, sailfish_watch, G_TYPE_OBJECT)
|
||||
#define SAILFISH_WATCH_TYPE (sailfish_watch_get_type())
|
||||
#define SAILFISH_WATCH(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),\
|
||||
SAILFISH_WATCH_TYPE, SailfishWatch))
|
||||
|
||||
#define NEW_SIGNAL(klass,name) \
|
||||
sailfish_watch_signals[WATCH_SIGNAL_##name##_CHANGED] = \
|
||||
g_signal_new(SIGNAL_##name##_CHANGED_NAME, \
|
||||
G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_FIRST, \
|
||||
0, NULL, NULL, NULL, G_TYPE_NONE, 0)
|
||||
|
||||
#define DBG_(obj,fmt,args...) DBG("%s " fmt, (obj)->path+1, ##args)
|
||||
|
||||
static inline int sailfish_watch_signal_bit(enum sailfish_watch_signal id)
|
||||
{
|
||||
return (1 << id);
|
||||
}
|
||||
|
||||
static inline void sailfish_watch_signal_emit(struct sailfish_watch *self,
|
||||
enum sailfish_watch_signal id)
|
||||
{
|
||||
self->priv->queued_signals &= ~sailfish_watch_signal_bit(id);
|
||||
g_signal_emit(self, sailfish_watch_signals[id], 0);
|
||||
}
|
||||
|
||||
void fake_sailfish_watch_signal_queue(struct sailfish_watch *self,
|
||||
enum sailfish_watch_signal id)
|
||||
{
|
||||
self->priv->queued_signals |= sailfish_watch_signal_bit(id);
|
||||
}
|
||||
|
||||
void fake_sailfish_watch_emit_queued_signals(struct sailfish_watch *self)
|
||||
{
|
||||
struct sailfish_watch_priv *priv = self->priv;
|
||||
int i;
|
||||
|
||||
for (i = 0; priv->queued_signals && i < WATCH_SIGNAL_COUNT; i++) {
|
||||
if (priv->queued_signals & sailfish_watch_signal_bit(i)) {
|
||||
sailfish_watch_signal_emit(self, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void fake_sailfish_watch_set_ofono_iccid(struct sailfish_watch *self,
|
||||
const char *iccid)
|
||||
{
|
||||
struct sailfish_watch_priv *priv = self->priv;
|
||||
|
||||
if (g_strcmp0(priv->iccid, iccid)) {
|
||||
g_free(priv->iccid);
|
||||
self->iccid = priv->iccid = g_strdup(iccid);
|
||||
fake_sailfish_watch_signal_queue(self,
|
||||
WATCH_SIGNAL_ICCID_CHANGED);
|
||||
}
|
||||
}
|
||||
|
||||
void fake_sailfish_watch_set_ofono_imsi(struct sailfish_watch *self,
|
||||
const char *imsi)
|
||||
{
|
||||
struct sailfish_watch_priv *priv = self->priv;
|
||||
|
||||
if (g_strcmp0(priv->imsi, imsi)) {
|
||||
g_free(priv->imsi);
|
||||
self->imsi = priv->imsi = g_strdup(imsi);
|
||||
fake_sailfish_watch_signal_queue(self,
|
||||
WATCH_SIGNAL_IMSI_CHANGED);
|
||||
}
|
||||
}
|
||||
|
||||
void fake_sailfish_watch_set_ofono_spn(struct sailfish_watch *self,
|
||||
const char *spn)
|
||||
{
|
||||
struct sailfish_watch_priv *priv = self->priv;
|
||||
|
||||
if (g_strcmp0(priv->spn, spn)) {
|
||||
g_free(priv->spn);
|
||||
self->spn = priv->spn = g_strdup(spn);
|
||||
fake_sailfish_watch_signal_queue(self,
|
||||
WATCH_SIGNAL_SPN_CHANGED);
|
||||
}
|
||||
}
|
||||
|
||||
void fake_sailfish_watch_set_ofono_sim(struct sailfish_watch *self,
|
||||
struct ofono_sim *sim)
|
||||
{
|
||||
if (self->sim != sim) {
|
||||
self->sim = sim;
|
||||
fake_sailfish_watch_signal_queue(self,
|
||||
WATCH_SIGNAL_SIM_CHANGED);
|
||||
if (!sim) {
|
||||
fake_sailfish_watch_set_ofono_iccid(self, NULL);
|
||||
fake_sailfish_watch_set_ofono_imsi(self, NULL);
|
||||
fake_sailfish_watch_set_ofono_spn(self, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void fake_sailfish_watch_set_ofono_netreg(struct sailfish_watch *self,
|
||||
struct ofono_netreg *netreg)
|
||||
{
|
||||
if (self->netreg != netreg) {
|
||||
self->netreg = netreg;
|
||||
fake_sailfish_watch_signal_queue(self,
|
||||
WATCH_SIGNAL_NETREG_CHANGED);
|
||||
}
|
||||
}
|
||||
|
||||
static void sailfish_watch_initialize(struct sailfish_watch *self,
|
||||
const char *path)
|
||||
{
|
||||
struct sailfish_watch_priv *priv = self->priv;
|
||||
|
||||
self->path = priv->path = g_strdup(path);
|
||||
}
|
||||
|
||||
static void sailfish_watch_destroyed(gpointer key, GObject* obj)
|
||||
{
|
||||
GASSERT(sailfish_watch_table);
|
||||
DBG("%s", (char*)key);
|
||||
if (sailfish_watch_table) {
|
||||
GASSERT(g_hash_table_lookup(sailfish_watch_table, key) == obj);
|
||||
g_hash_table_remove(sailfish_watch_table, key);
|
||||
if (g_hash_table_size(sailfish_watch_table) == 0) {
|
||||
g_hash_table_unref(sailfish_watch_table);
|
||||
sailfish_watch_table = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct sailfish_watch *sailfish_watch_new(const char *path)
|
||||
{
|
||||
struct sailfish_watch *watch = NULL;
|
||||
|
||||
if (path) {
|
||||
if (sailfish_watch_table) {
|
||||
watch = sailfish_watch_ref(g_hash_table_lookup(
|
||||
sailfish_watch_table, path));
|
||||
}
|
||||
if (!watch) {
|
||||
char* key = g_strdup(path);
|
||||
|
||||
watch = g_object_new(SAILFISH_WATCH_TYPE, NULL);
|
||||
sailfish_watch_initialize(watch, path);
|
||||
if (!sailfish_watch_table) {
|
||||
/* Create the table on demand */
|
||||
sailfish_watch_table =
|
||||
g_hash_table_new_full(g_str_hash,
|
||||
g_str_equal, g_free, NULL);
|
||||
}
|
||||
g_hash_table_replace(sailfish_watch_table, key, watch);
|
||||
g_object_weak_ref(G_OBJECT(watch),
|
||||
sailfish_watch_destroyed, key);
|
||||
DBG_(watch, "created");
|
||||
}
|
||||
}
|
||||
return watch;
|
||||
}
|
||||
|
||||
struct sailfish_watch *sailfish_watch_ref(struct sailfish_watch *self)
|
||||
{
|
||||
if (self) {
|
||||
g_object_ref(SAILFISH_WATCH(self));
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
void sailfish_watch_unref(struct sailfish_watch *self)
|
||||
{
|
||||
if (self) {
|
||||
g_object_unref(SAILFISH_WATCH(self));
|
||||
}
|
||||
}
|
||||
|
||||
gulong sailfish_watch_add_modem_changed_handler(struct sailfish_watch *self,
|
||||
sailfish_watch_cb_t cb, void *user_data)
|
||||
{
|
||||
return (self && cb) ? g_signal_connect(self,
|
||||
SIGNAL_MODEM_CHANGED_NAME, G_CALLBACK(cb), user_data) : 0;
|
||||
}
|
||||
|
||||
gulong sailfish_watch_add_online_changed_handler(struct sailfish_watch *self,
|
||||
sailfish_watch_cb_t cb, void *user_data)
|
||||
{
|
||||
return (self && cb) ? g_signal_connect(self,
|
||||
SIGNAL_ONLINE_CHANGED_NAME, G_CALLBACK(cb), user_data) : 0;
|
||||
}
|
||||
|
||||
gulong sailfish_watch_add_sim_changed_handler(struct sailfish_watch *self,
|
||||
sailfish_watch_cb_t cb, void *user_data)
|
||||
{
|
||||
return (self && cb) ? g_signal_connect(self,
|
||||
SIGNAL_SIM_CHANGED_NAME, G_CALLBACK(cb), user_data) : 0;
|
||||
}
|
||||
|
||||
gulong sailfish_watch_add_sim_state_changed_handler(struct sailfish_watch *self,
|
||||
sailfish_watch_cb_t cb, void *user_data)
|
||||
{
|
||||
return (self && cb) ? g_signal_connect(self,
|
||||
SIGNAL_SIM_STATE_CHANGED_NAME, G_CALLBACK(cb), user_data) : 0;
|
||||
}
|
||||
|
||||
gulong sailfish_watch_add_iccid_changed_handler(struct sailfish_watch *self,
|
||||
sailfish_watch_cb_t cb, void *user_data)
|
||||
{
|
||||
return (self && cb) ? g_signal_connect(self,
|
||||
SIGNAL_ICCID_CHANGED_NAME, G_CALLBACK(cb), user_data) : 0;
|
||||
}
|
||||
|
||||
gulong sailfish_watch_add_imsi_changed_handler(struct sailfish_watch *self,
|
||||
sailfish_watch_cb_t cb, void *user_data)
|
||||
{
|
||||
return (self && cb) ? g_signal_connect(self,
|
||||
SIGNAL_IMSI_CHANGED_NAME, G_CALLBACK(cb), user_data) : 0;
|
||||
}
|
||||
|
||||
gulong sailfish_watch_add_spn_changed_handler(struct sailfish_watch *self,
|
||||
sailfish_watch_cb_t cb, void *user_data)
|
||||
{
|
||||
return (self && cb) ? g_signal_connect(self,
|
||||
SIGNAL_SPN_CHANGED_NAME, G_CALLBACK(cb), user_data) : 0;
|
||||
}
|
||||
|
||||
gulong sailfish_watch_add_netreg_changed_handler(struct sailfish_watch *self,
|
||||
sailfish_watch_cb_t cb, void *user_data)
|
||||
{
|
||||
return (self && cb) ? g_signal_connect(self,
|
||||
SIGNAL_NETREG_CHANGED_NAME, G_CALLBACK(cb), user_data) : 0;
|
||||
}
|
||||
|
||||
void sailfish_watch_remove_handler(struct sailfish_watch *self, gulong id)
|
||||
{
|
||||
if (self && id) {
|
||||
g_signal_handler_disconnect(self, id);
|
||||
}
|
||||
}
|
||||
|
||||
void sailfish_watch_remove_handlers(struct sailfish_watch *self, gulong *ids,
|
||||
int count)
|
||||
{
|
||||
gutil_disconnect_handlers(self, ids, count);
|
||||
}
|
||||
|
||||
static void sailfish_watch_init(struct sailfish_watch *self)
|
||||
{
|
||||
self->priv = G_TYPE_INSTANCE_GET_PRIVATE(self, SAILFISH_WATCH_TYPE,
|
||||
struct sailfish_watch_priv);
|
||||
}
|
||||
|
||||
static void sailfish_watch_finalize(GObject *object)
|
||||
{
|
||||
struct sailfish_watch *self = SAILFISH_WATCH(object);
|
||||
struct sailfish_watch_priv *priv = self->priv;
|
||||
|
||||
g_free(priv->path);
|
||||
g_free(priv->iccid);
|
||||
g_free(priv->imsi);
|
||||
g_free(priv->spn);
|
||||
G_OBJECT_CLASS(sailfish_watch_parent_class)->finalize(object);
|
||||
}
|
||||
|
||||
static void sailfish_watch_class_init(SailfishWatchClass *klass)
|
||||
{
|
||||
G_OBJECT_CLASS(klass)->finalize = sailfish_watch_finalize;
|
||||
g_type_class_add_private(klass, sizeof(struct sailfish_watch_priv));
|
||||
NEW_SIGNAL(klass, MODEM);
|
||||
NEW_SIGNAL(klass, ONLINE);
|
||||
NEW_SIGNAL(klass, SIM);
|
||||
NEW_SIGNAL(klass, SIM_STATE);
|
||||
NEW_SIGNAL(klass, ICCID);
|
||||
NEW_SIGNAL(klass, IMSI);
|
||||
NEW_SIGNAL(klass, SPN);
|
||||
NEW_SIGNAL(klass, NETREG);
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
55
ofono/unit/fake_sailfish_watch.h
Normal file
55
ofono/unit/fake_sailfish_watch.h
Normal file
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef SAILFISH_FAKE_WATCH_H
|
||||
#define SAILFISH_FAKE_WATCH_H
|
||||
|
||||
#include "sailfish_watch.h"
|
||||
|
||||
enum sailfish_watch_signal {
|
||||
WATCH_SIGNAL_MODEM_CHANGED,
|
||||
WATCH_SIGNAL_ONLINE_CHANGED,
|
||||
WATCH_SIGNAL_SIM_CHANGED,
|
||||
WATCH_SIGNAL_SIM_STATE_CHANGED,
|
||||
WATCH_SIGNAL_ICCID_CHANGED,
|
||||
WATCH_SIGNAL_IMSI_CHANGED,
|
||||
WATCH_SIGNAL_SPN_CHANGED,
|
||||
WATCH_SIGNAL_NETREG_CHANGED,
|
||||
WATCH_SIGNAL_COUNT
|
||||
};
|
||||
|
||||
void fake_sailfish_watch_signal_queue(struct sailfish_watch *watch,
|
||||
enum sailfish_watch_signal id);
|
||||
void fake_sailfish_watch_emit_queued_signals(struct sailfish_watch *watch);
|
||||
void fake_sailfish_watch_set_ofono_sim(struct sailfish_watch *watch,
|
||||
struct ofono_sim *sim);
|
||||
void fake_sailfish_watch_set_ofono_iccid(struct sailfish_watch *watch,
|
||||
const char *iccid);
|
||||
void fake_sailfish_watch_set_ofono_imsi(struct sailfish_watch *watch,
|
||||
const char *imsi);
|
||||
void fake_sailfish_watch_set_ofono_spn(struct sailfish_watch *watch,
|
||||
const char *spn);
|
||||
void fake_sailfish_watch_set_ofono_netreg(struct sailfish_watch *watch,
|
||||
struct ofono_netreg *netreg);
|
||||
|
||||
#endif /* FAKE_SAILFISH_WATCH_H */
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
File diff suppressed because it is too large
Load Diff
128
ofono/unit/test-ril_util.c
Normal file
128
ofono/unit/test-ril_util.c
Normal file
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
* 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 "drivers/ril/ril_util.h"
|
||||
|
||||
#include "ofono.h"
|
||||
#include "common.h"
|
||||
|
||||
void test_parse_tech(void)
|
||||
{
|
||||
int tech = 0;
|
||||
|
||||
g_assert(ril_parse_tech(NULL, NULL) == -1);
|
||||
g_assert(ril_parse_tech(NULL, &tech) == -1);
|
||||
g_assert(tech == -1);
|
||||
g_assert(ril_parse_tech("-1", &tech) == -1);
|
||||
g_assert(tech == -1);
|
||||
g_assert(ril_parse_tech("0", &tech) == -1);
|
||||
g_assert(tech == -1);
|
||||
g_assert(ril_parse_tech("1", &tech) == ACCESS_TECHNOLOGY_GSM);
|
||||
g_assert(tech == RADIO_TECH_GPRS);
|
||||
g_assert(ril_parse_tech("16", &tech) == ACCESS_TECHNOLOGY_GSM);
|
||||
g_assert(tech == RADIO_TECH_GSM);
|
||||
g_assert(ril_parse_tech("2", &tech) == ACCESS_TECHNOLOGY_GSM_EGPRS);
|
||||
g_assert(tech == RADIO_TECH_EDGE);
|
||||
g_assert(ril_parse_tech("3", &tech) == ACCESS_TECHNOLOGY_UTRAN);
|
||||
g_assert(tech == RADIO_TECH_UMTS);
|
||||
g_assert(ril_parse_tech("9", &tech) == ACCESS_TECHNOLOGY_UTRAN_HSDPA);
|
||||
g_assert(tech == RADIO_TECH_HSDPA);
|
||||
g_assert(ril_parse_tech("10", &tech) == ACCESS_TECHNOLOGY_UTRAN_HSUPA);
|
||||
g_assert(tech == RADIO_TECH_HSUPA);
|
||||
g_assert(ril_parse_tech("11", &tech) ==
|
||||
ACCESS_TECHNOLOGY_UTRAN_HSDPA_HSUPA);
|
||||
g_assert(tech == RADIO_TECH_HSPA);
|
||||
g_assert(ril_parse_tech("15", &tech) ==
|
||||
ACCESS_TECHNOLOGY_UTRAN_HSDPA_HSUPA);
|
||||
g_assert(tech == RADIO_TECH_HSPAP);
|
||||
g_assert(ril_parse_tech("14", &tech) == ACCESS_TECHNOLOGY_EUTRAN);
|
||||
g_assert(tech == RADIO_TECH_LTE);
|
||||
}
|
||||
|
||||
void test_parse_mcc_mnc(void)
|
||||
{
|
||||
struct ofono_network_operator op;
|
||||
|
||||
memset(&op, 0, sizeof(op));
|
||||
g_assert(!ril_parse_mcc_mnc(NULL, &op));
|
||||
g_assert(!ril_parse_mcc_mnc("", &op));
|
||||
g_assert(!ril_parse_mcc_mnc("24x", &op));
|
||||
g_assert(!ril_parse_mcc_mnc("244", &op));
|
||||
g_assert(!ril_parse_mcc_mnc("244x", &op));
|
||||
g_assert(ril_parse_mcc_mnc("24412", &op));
|
||||
g_assert(!strcmp(op.mcc, "244"));
|
||||
g_assert(!strcmp(op.mnc, "12"));
|
||||
g_assert(!op.tech);
|
||||
g_assert(ril_parse_mcc_mnc("25001+", &op));
|
||||
g_assert(!strcmp(op.mcc, "250"));
|
||||
g_assert(!strcmp(op.mnc, "01"));
|
||||
g_assert(!op.tech);
|
||||
g_assert(ril_parse_mcc_mnc("25503+14", &op));
|
||||
g_assert(!strcmp(op.mcc, "255"));
|
||||
g_assert(!strcmp(op.mnc, "03"));
|
||||
g_assert(op.tech == ACCESS_TECHNOLOGY_EUTRAN);
|
||||
/* Not sure if this is right but that's now it currently works: */
|
||||
op.tech = 0;
|
||||
g_assert(ril_parse_mcc_mnc("3101500", &op));
|
||||
g_assert(!strcmp(op.mcc, "310"));
|
||||
g_assert(!strcmp(op.mnc, "150"));
|
||||
g_assert(!op.tech);
|
||||
}
|
||||
|
||||
void test_parse_int(void)
|
||||
{
|
||||
int value;
|
||||
|
||||
g_assert(!ril_parse_int(NULL, 0, NULL));
|
||||
g_assert(!ril_parse_int("", 0, NULL));
|
||||
g_assert(!ril_parse_int("garbage", 0, NULL));
|
||||
g_assert(!ril_parse_int("0 trailing garbage", 0, NULL));
|
||||
g_assert(ril_parse_int("0", 0, NULL));
|
||||
g_assert(ril_parse_int("0", 0, &value));
|
||||
g_assert(value == 0);
|
||||
g_assert(!ril_parse_int("0x10000000000000000", 0, &value));
|
||||
g_assert(!ril_parse_int("-2147483649", 0, &value));
|
||||
g_assert(!ril_parse_int("4294967295", 0, &value));
|
||||
g_assert(ril_parse_int(" 0x7fffffff ", 0, &value));
|
||||
g_assert(value == 0x7fffffff);
|
||||
g_assert(ril_parse_int(" 7fffffff ", 16, &value));
|
||||
g_assert(value == 0x7fffffff);
|
||||
g_assert(!ril_parse_int("0xffffffff", 0, &value));
|
||||
}
|
||||
|
||||
#define TEST_(name) "/ril_util/" name
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
g_test_init(&argc, &argv, NULL);
|
||||
|
||||
__ofono_log_init("test-ril_util",
|
||||
g_test_verbose() ? "*" : NULL,
|
||||
FALSE, FALSE);
|
||||
|
||||
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);
|
||||
|
||||
return g_test_run();
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
203
ofono/unit/test-sailfish_cell_info.c
Normal file
203
ofono/unit/test-sailfish_cell_info.c
Normal file
@@ -0,0 +1,203 @@
|
||||
/*
|
||||
* 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 <sailfish_cell_info.h>
|
||||
|
||||
#include <gutil_log.h>
|
||||
|
||||
/* Fake sailfish_cell_info */
|
||||
|
||||
#define FAKE_HANDLER_ID (1)
|
||||
|
||||
static int fake_sailfish_cell_info_ref_count = 0;
|
||||
|
||||
static void fake_sailfish_cell_info_ref(struct sailfish_cell_info *info)
|
||||
{
|
||||
g_assert(fake_sailfish_cell_info_ref_count >= 0);
|
||||
fake_sailfish_cell_info_ref_count++;
|
||||
}
|
||||
|
||||
static void fake_sailfish_cell_info_unref(struct sailfish_cell_info *info)
|
||||
{
|
||||
g_assert(fake_sailfish_cell_info_ref_count > 0);
|
||||
fake_sailfish_cell_info_ref_count--;
|
||||
}
|
||||
|
||||
static gulong fake_sailfish_cell_info_add_cells_changed_handler
|
||||
(struct sailfish_cell_info *info, sailfish_cell_info_cb_t cb, void *arg)
|
||||
{
|
||||
return FAKE_HANDLER_ID;
|
||||
}
|
||||
|
||||
static void fake_sailfish_cell_info_remove_handler
|
||||
(struct sailfish_cell_info *info, gulong id)
|
||||
{
|
||||
g_assert(id == FAKE_HANDLER_ID);
|
||||
}
|
||||
|
||||
static const struct sailfish_cell_info_proc fake_sailfish_cell_info_proc = {
|
||||
fake_sailfish_cell_info_ref,
|
||||
fake_sailfish_cell_info_unref,
|
||||
fake_sailfish_cell_info_add_cells_changed_handler,
|
||||
fake_sailfish_cell_info_remove_handler
|
||||
};
|
||||
|
||||
static struct sailfish_cell_info fake_sailfish_cell_info = {
|
||||
&fake_sailfish_cell_info_proc,
|
||||
NULL
|
||||
};
|
||||
|
||||
/* ==== basic ==== */
|
||||
|
||||
static void test_basic(void)
|
||||
{
|
||||
/* NULL resistance */
|
||||
g_assert(!sailfish_cell_info_ref(NULL));
|
||||
sailfish_cell_info_unref(NULL);
|
||||
g_assert(!sailfish_cell_compare_func(NULL, NULL));
|
||||
g_assert(!sailfish_cell_info_add_cells_changed_handler(NULL, NULL,
|
||||
NULL));
|
||||
sailfish_cell_info_remove_handler(NULL, 0);
|
||||
|
||||
/* Make sure that callbacks are being invoked */
|
||||
g_assert(sailfish_cell_info_ref(&fake_sailfish_cell_info) ==
|
||||
&fake_sailfish_cell_info);
|
||||
g_assert(fake_sailfish_cell_info_ref_count == 1);
|
||||
g_assert(sailfish_cell_info_add_cells_changed_handler(
|
||||
&fake_sailfish_cell_info, NULL, NULL) == FAKE_HANDLER_ID);
|
||||
sailfish_cell_info_remove_handler(&fake_sailfish_cell_info,
|
||||
FAKE_HANDLER_ID);
|
||||
sailfish_cell_info_unref(&fake_sailfish_cell_info);
|
||||
g_assert(!fake_sailfish_cell_info_ref_count);
|
||||
}
|
||||
|
||||
/* ==== compare ==== */
|
||||
|
||||
static void test_compare(void)
|
||||
{
|
||||
struct sailfish_cell c1, c2;
|
||||
|
||||
memset(&c1, 0, sizeof(c1));
|
||||
memset(&c2, 0, sizeof(c2));
|
||||
|
||||
g_assert(!sailfish_cell_compare_location(NULL, NULL));
|
||||
g_assert(sailfish_cell_compare_location(&c1, NULL) > 0);
|
||||
g_assert(sailfish_cell_compare_location(NULL, &c2) < 0);
|
||||
|
||||
c1.type = SAILFISH_CELL_TYPE_GSM;
|
||||
c2.type = SAILFISH_CELL_TYPE_WCDMA;
|
||||
g_assert(sailfish_cell_compare_location(&c1, &c2) < 0);
|
||||
g_assert(sailfish_cell_compare_location(&c2, &c1) > 0);
|
||||
|
||||
/* GSM */
|
||||
c1.type = SAILFISH_CELL_TYPE_GSM;
|
||||
c2 = c1;
|
||||
g_assert(!sailfish_cell_compare_location(&c1, &c2));
|
||||
c2 = c1; c2.info.gsm.mcc++;
|
||||
g_assert(sailfish_cell_compare_location(&c1, &c2) < 0);
|
||||
c2 = c1; c2.info.gsm.mnc++;
|
||||
g_assert(sailfish_cell_compare_location(&c1, &c2) < 0);
|
||||
c2 = c1; c2.info.gsm.lac++;
|
||||
g_assert(sailfish_cell_compare_location(&c1, &c2) < 0);
|
||||
c2 = c1; c2.info.gsm.cid++;
|
||||
g_assert(sailfish_cell_compare_location(&c1, &c2) < 0);
|
||||
/* Other attributes are not being compared */
|
||||
c2 = c1; c2.info.gsm.arfcn++;
|
||||
g_assert(!sailfish_cell_compare_location(&c1, &c2));
|
||||
c2 = c1; c2.info.gsm.bsic++;
|
||||
g_assert(!sailfish_cell_compare_location(&c1, &c2));
|
||||
c2 = c1; c2.info.gsm.signalStrength++;
|
||||
g_assert(!sailfish_cell_compare_location(&c1, &c2));
|
||||
c2 = c1; c2.info.gsm.bitErrorRate++;
|
||||
g_assert(!sailfish_cell_compare_location(&c1, &c2));
|
||||
c2 = c1; c2.info.gsm.bitErrorRate++;
|
||||
g_assert(!sailfish_cell_compare_location(&c1, &c2));
|
||||
|
||||
/* WCDMA */
|
||||
c1.type = SAILFISH_CELL_TYPE_WCDMA;
|
||||
c2 = c1;
|
||||
g_assert(!sailfish_cell_compare_location(&c1, &c2));
|
||||
c2 = c1; c2.info.wcdma.mcc++;
|
||||
g_assert(sailfish_cell_compare_location(&c1, &c2) < 0);
|
||||
c2 = c1; c2.info.wcdma.mnc++;
|
||||
g_assert(sailfish_cell_compare_location(&c1, &c2) < 0);
|
||||
c2 = c1; c2.info.wcdma.lac++;
|
||||
g_assert(sailfish_cell_compare_location(&c1, &c2) < 0);
|
||||
c2 = c1; c2.info.wcdma.cid++;
|
||||
g_assert(sailfish_cell_compare_location(&c1, &c2) < 0);
|
||||
/* Other attributes are not being compared */
|
||||
c2 = c1; c2.info.wcdma.psc++;
|
||||
g_assert(!sailfish_cell_compare_location(&c1, &c2));
|
||||
c2 = c1; c2.info.wcdma.uarfcn++;
|
||||
g_assert(!sailfish_cell_compare_location(&c1, &c2));
|
||||
c2 = c1; c2.info.wcdma.signalStrength++;
|
||||
g_assert(!sailfish_cell_compare_location(&c1, &c2));
|
||||
c2 = c1; c2.info.wcdma.bitErrorRate++;
|
||||
g_assert(!sailfish_cell_compare_location(&c1, &c2));
|
||||
|
||||
/* LTE */
|
||||
c1.type = SAILFISH_CELL_TYPE_LTE;
|
||||
c2 = c1;
|
||||
g_assert(!sailfish_cell_compare_location(&c1, &c2));
|
||||
c2 = c1; c2.info.lte.mcc++;
|
||||
g_assert(sailfish_cell_compare_location(&c1, &c2) < 0);
|
||||
c2 = c1; c2.info.lte.mnc++;
|
||||
g_assert(sailfish_cell_compare_location(&c1, &c2) < 0);
|
||||
c2 = c1; c2.info.lte.ci++;
|
||||
g_assert(sailfish_cell_compare_location(&c1, &c2) < 0);
|
||||
c2 = c1; c2.info.lte.pci++;
|
||||
g_assert(sailfish_cell_compare_location(&c1, &c2) < 0);
|
||||
c2 = c1; c2.info.lte.tac++;
|
||||
g_assert(sailfish_cell_compare_location(&c1, &c2) < 0);
|
||||
/* Other attributes are not being compared */
|
||||
c2 = c1; c2.info.lte.earfcn++;
|
||||
g_assert(!sailfish_cell_compare_location(&c1, &c2));
|
||||
c2 = c1; c2.info.lte.signalStrength++;
|
||||
g_assert(!sailfish_cell_compare_location(&c1, &c2));
|
||||
c2 = c1; c2.info.lte.rsrp++;
|
||||
g_assert(!sailfish_cell_compare_location(&c1, &c2));
|
||||
c2 = c1; c2.info.lte.rsrq++;
|
||||
g_assert(!sailfish_cell_compare_location(&c1, &c2));
|
||||
c2 = c1; c2.info.lte.rssnr++;
|
||||
g_assert(!sailfish_cell_compare_location(&c1, &c2));
|
||||
c2 = c1; c2.info.lte.cqi++;
|
||||
g_assert(!sailfish_cell_compare_location(&c1, &c2));
|
||||
c2 = c1; c2.info.lte.timingAdvance++;
|
||||
g_assert(!sailfish_cell_compare_location(&c1, &c2));
|
||||
}
|
||||
|
||||
#define TEST_(name) "/sailfish_cell_info/" name
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
g_test_init(&argc, &argv, NULL);
|
||||
|
||||
gutil_log_timestamp = FALSE;
|
||||
gutil_log_default.level = g_test_verbose() ?
|
||||
GLOG_LEVEL_VERBOSE : GLOG_LEVEL_NONE;
|
||||
|
||||
g_test_add_func(TEST_("basic"), test_basic);
|
||||
g_test_add_func(TEST_("compare"), test_compare);
|
||||
|
||||
return g_test_run();
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
1507
ofono/unit/test-sailfish_manager.c
Normal file
1507
ofono/unit/test-sailfish_manager.c
Normal file
File diff suppressed because it is too large
Load Diff
442
ofono/unit/test-sailfish_sim_info.c
Normal file
442
ofono/unit/test-sailfish_sim_info.c
Normal file
@@ -0,0 +1,442 @@
|
||||
/*
|
||||
* 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 "sailfish_sim_info.h"
|
||||
#include "fake_sailfish_watch.h"
|
||||
|
||||
#define OFONO_API_SUBJECT_TO_CHANGE
|
||||
#include "ofono.h"
|
||||
#include "common.h"
|
||||
|
||||
#include <gutil_log.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define TEST_PATH "/test"
|
||||
#define TEST_ICCID "1111111111111111111"
|
||||
#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 ICCID_MAP STORAGEDIR "/iccidmap"
|
||||
#define SIM_CACHE STORAGEDIR "/" TEST_IMSI "/cache"
|
||||
|
||||
enum sim_info_signals {
|
||||
SIM_INFO_SIGNAL_ICCID_CHANGED,
|
||||
SIM_INFO_SIGNAL_IMSI_CHANGED,
|
||||
SIM_INFO_SIGNAL_SPN_CHANGED,
|
||||
SIM_INFO_SIGNAL_COUNT
|
||||
};
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
enum network_registration_status status;
|
||||
struct ofono_watchlist *status_watches;
|
||||
};
|
||||
|
||||
int ofono_netreg_get_status(struct ofono_netreg *netreg)
|
||||
{
|
||||
return netreg ? 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;
|
||||
}
|
||||
}
|
||||
|
||||
static void netreg_notify_status_watches(struct ofono_netreg *netreg)
|
||||
{
|
||||
GSList *l;
|
||||
const char *mcc = netreg->mcc;
|
||||
const char *mnc = netreg->mnc;
|
||||
|
||||
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, netreg->location, netreg->cellid,
|
||||
netreg->technology, mcc, mnc, item->notify_data);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Test cases */
|
||||
|
||||
static void test_basic(void)
|
||||
{
|
||||
struct sailfish_sim_info *si;
|
||||
|
||||
/* NULL tolerance */
|
||||
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));
|
||||
sailfish_sim_info_remove_handler(NULL, 0);
|
||||
sailfish_sim_info_remove_handlers(NULL, NULL, 0);
|
||||
|
||||
/* 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));
|
||||
sailfish_sim_info_remove_handler(si, 0);
|
||||
sailfish_sim_info_remove_handlers(si, NULL, 0);
|
||||
sailfish_sim_info_unref(sailfish_sim_info_ref(si));
|
||||
sailfish_sim_info_unref(si);
|
||||
}
|
||||
|
||||
static void test_signal_count_cb(struct sailfish_sim_info *si, void *data)
|
||||
{
|
||||
(*((int*)data))++;
|
||||
}
|
||||
|
||||
static void test_cache(void)
|
||||
{
|
||||
struct sailfish_sim_info *si;
|
||||
struct sailfish_watch *w = sailfish_watch_new(TEST_PATH);
|
||||
struct ofono_sim sim;
|
||||
struct stat st;
|
||||
gulong id[SIM_INFO_SIGNAL_COUNT];
|
||||
int count[SIM_INFO_SIGNAL_COUNT];
|
||||
|
||||
memset(id, 0, sizeof(id));
|
||||
memset(count, 0, sizeof(count));
|
||||
memset(&sim, 0, sizeof(sim));
|
||||
sim.state = OFONO_SIM_STATE_INSERTED;
|
||||
|
||||
rmdir_r(STORAGEDIR);
|
||||
si = sailfish_sim_info_new(TEST_PATH);
|
||||
id[SIM_INFO_SIGNAL_ICCID_CHANGED] =
|
||||
sailfish_sim_info_add_iccid_changed_handler(si,
|
||||
test_signal_count_cb, count +
|
||||
SIM_INFO_SIGNAL_ICCID_CHANGED);
|
||||
id[SIM_INFO_SIGNAL_IMSI_CHANGED] =
|
||||
sailfish_sim_info_add_imsi_changed_handler(si,
|
||||
test_signal_count_cb, count +
|
||||
SIM_INFO_SIGNAL_IMSI_CHANGED);
|
||||
id[SIM_INFO_SIGNAL_SPN_CHANGED] =
|
||||
sailfish_sim_info_add_spn_changed_handler(si,
|
||||
test_signal_count_cb, count +
|
||||
SIM_INFO_SIGNAL_SPN_CHANGED);
|
||||
|
||||
fake_sailfish_watch_set_ofono_sim(w, &sim);
|
||||
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]);
|
||||
|
||||
fake_sailfish_watch_set_ofono_iccid(w, TEST_ICCID);
|
||||
fake_sailfish_watch_emit_queued_signals(w);
|
||||
g_assert(!g_strcmp0(si->iccid, TEST_ICCID));
|
||||
g_assert(count[SIM_INFO_SIGNAL_ICCID_CHANGED] == 1);
|
||||
g_assert(!count[SIM_INFO_SIGNAL_IMSI_CHANGED]);
|
||||
g_assert(!count[SIM_INFO_SIGNAL_SPN_CHANGED]);
|
||||
g_assert(stat(ICCID_MAP, &st) < 0);
|
||||
count[SIM_INFO_SIGNAL_ICCID_CHANGED] = 0;
|
||||
|
||||
fake_sailfish_watch_set_ofono_imsi(w, TEST_IMSI);
|
||||
fake_sailfish_watch_emit_queued_signals(w);
|
||||
g_assert(!g_strcmp0(si->imsi, TEST_IMSI));
|
||||
g_assert(!count[SIM_INFO_SIGNAL_ICCID_CHANGED]);
|
||||
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 */
|
||||
g_assert(stat(ICCID_MAP, &st) == 0);
|
||||
g_assert(S_ISREG(st.st_mode));
|
||||
/* But no cache yet */
|
||||
g_assert(stat(SIM_CACHE, &st) < 0);
|
||||
|
||||
/* This will generate default SPN out of MCC and MNC */
|
||||
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_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;
|
||||
|
||||
/* Replace default SPN with the real one */
|
||||
fake_sailfish_watch_set_ofono_spn(w, TEST_SPN);
|
||||
fake_sailfish_watch_emit_queued_signals(w);
|
||||
g_assert(!g_strcmp0(si->spn, TEST_SPN));
|
||||
g_assert(!count[SIM_INFO_SIGNAL_ICCID_CHANGED]);
|
||||
g_assert(!count[SIM_INFO_SIGNAL_IMSI_CHANGED]);
|
||||
g_assert(count[SIM_INFO_SIGNAL_SPN_CHANGED] == 1);
|
||||
count[SIM_INFO_SIGNAL_SPN_CHANGED] = 0;
|
||||
/* Cache file appears */
|
||||
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;
|
||||
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] == 1);
|
||||
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_SIM_STATE_CHANGED);
|
||||
fake_sailfish_watch_set_ofono_iccid(w, TEST_ICCID);
|
||||
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));
|
||||
|
||||
sailfish_sim_info_remove_handler(si, id[SIM_INFO_SIGNAL_SPN_CHANGED]);
|
||||
id[SIM_INFO_SIGNAL_SPN_CHANGED] = 0;
|
||||
sailfish_sim_info_invalidate(si);
|
||||
g_assert(!si->iccid);
|
||||
g_assert(!si->imsi);
|
||||
g_assert(!si->iccid);
|
||||
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 ^ */
|
||||
memset(count, 0, sizeof(count));
|
||||
|
||||
sailfish_sim_info_remove_handlers(si, id, G_N_ELEMENTS(id));
|
||||
sailfish_sim_info_unref(si);
|
||||
sailfish_watch_unref(w);
|
||||
}
|
||||
|
||||
static void test_netreg(void)
|
||||
{
|
||||
struct sailfish_sim_info *si;
|
||||
struct sailfish_watch *w = sailfish_watch_new(TEST_PATH);
|
||||
struct ofono_sim sim;
|
||||
struct ofono_netreg netreg;
|
||||
struct stat st;
|
||||
gulong id[SIM_INFO_SIGNAL_COUNT];
|
||||
int count[SIM_INFO_SIGNAL_COUNT];
|
||||
|
||||
memset(id, 0, sizeof(id));
|
||||
memset(count, 0, sizeof(count));
|
||||
|
||||
memset(&netreg, 0, sizeof(netreg));
|
||||
netreg.technology = OFONO_RADIO_ACCESS_MODE_GSM;
|
||||
netreg.status = NETWORK_REGISTRATION_STATUS_NOT_REGISTERED;
|
||||
netreg.status_watches = __ofono_watchlist_new(g_free);
|
||||
|
||||
memset(&sim, 0, sizeof(sim));
|
||||
sim.mcc = TEST_MCC;
|
||||
sim.mnc = TEST_MNC;
|
||||
sim.state = OFONO_SIM_STATE_READY;
|
||||
|
||||
rmdir_r(STORAGEDIR);
|
||||
si = sailfish_sim_info_new(TEST_PATH);
|
||||
id[SIM_INFO_SIGNAL_ICCID_CHANGED] =
|
||||
sailfish_sim_info_add_iccid_changed_handler(si,
|
||||
test_signal_count_cb, count +
|
||||
SIM_INFO_SIGNAL_ICCID_CHANGED);
|
||||
id[SIM_INFO_SIGNAL_IMSI_CHANGED] =
|
||||
sailfish_sim_info_add_imsi_changed_handler(si,
|
||||
test_signal_count_cb, count +
|
||||
SIM_INFO_SIGNAL_IMSI_CHANGED);
|
||||
id[SIM_INFO_SIGNAL_SPN_CHANGED] =
|
||||
sailfish_sim_info_add_spn_changed_handler(si,
|
||||
test_signal_count_cb, count +
|
||||
SIM_INFO_SIGNAL_SPN_CHANGED);
|
||||
|
||||
fake_sailfish_watch_set_ofono_sim(w, &sim);
|
||||
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_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));
|
||||
|
||||
g_assert(stat(ICCID_MAP, &st) == 0);
|
||||
g_assert(S_ISREG(st.st_mode));
|
||||
/* Default SPN doesn't get cached */
|
||||
g_assert(stat(SIM_CACHE, &st) < 0);
|
||||
|
||||
fake_sailfish_watch_set_ofono_netreg(w, &netreg);
|
||||
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]);
|
||||
|
||||
/* Simulate home registation */
|
||||
netreg.mcc = TEST_MCC;
|
||||
netreg.mnc = TEST_MNC;
|
||||
netreg.name = TEST_SPN;
|
||||
netreg.status = NETWORK_REGISTRATION_STATUS_REGISTERED;
|
||||
netreg_notify_status_watches(&netreg);
|
||||
g_assert(!g_strcmp0(si->spn, TEST_SPN));
|
||||
g_assert(count[SIM_INFO_SIGNAL_SPN_CHANGED] == 1);
|
||||
/* This one does get cached */
|
||||
g_assert(stat(SIM_CACHE, &st) == 0);
|
||||
g_assert(S_ISREG(st.st_mode));
|
||||
|
||||
fake_sailfish_watch_set_ofono_netreg(w, NULL);
|
||||
fake_sailfish_watch_emit_queued_signals(w);
|
||||
|
||||
__ofono_watchlist_free(netreg.status_watches);
|
||||
sailfish_sim_info_remove_handlers(si, id, G_N_ELEMENTS(id));
|
||||
sailfish_sim_info_unref(si);
|
||||
sailfish_watch_unref(w);
|
||||
}
|
||||
|
||||
#define TEST_(name) "/sailfish_sim_info/" name
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
g_test_init(&argc, &argv, NULL);
|
||||
|
||||
gutil_log_timestamp = FALSE;
|
||||
gutil_log_default.level = g_test_verbose() ?
|
||||
GLOG_LEVEL_VERBOSE : GLOG_LEVEL_NONE;
|
||||
__ofono_log_init("test-sailfish_sim_info",
|
||||
g_test_verbose() ? "*" : NULL,
|
||||
FALSE, FALSE);
|
||||
|
||||
g_test_add_func(TEST_("basic"), test_basic);
|
||||
g_test_add_func(TEST_("cache"), test_cache);
|
||||
g_test_add_func(TEST_("netreg"), test_netreg);
|
||||
|
||||
return g_test_run();
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 8
|
||||
* indent-tabs-mode: t
|
||||
* End:
|
||||
*/
|
||||
@@ -178,12 +178,12 @@ static void test_ber_tlv_builder_efpnn(void)
|
||||
ber_tlv_builder_optimize(&builder, NULL, NULL);
|
||||
|
||||
eons_info = sim_eons_new(1);
|
||||
sim_eons_add_pnn_record(eons_info, 1, efpnn0, sizeof(efpnn0));
|
||||
sim_eons_add_pnn_record(eons_info, 1, efpnn0, 8 + 10);
|
||||
g_assert(!sim_eons_pnn_is_empty(eons_info));
|
||||
sim_eons_free(eons_info);
|
||||
|
||||
eons_info = sim_eons_new(1);
|
||||
sim_eons_add_pnn_record(eons_info, 1, efpnn1, sizeof(efpnn1));
|
||||
sim_eons_add_pnn_record(eons_info, 1, efpnn1, 8 + 6);
|
||||
g_assert(!sim_eons_pnn_is_empty(eons_info));
|
||||
sim_eons_free(eons_info);
|
||||
}
|
||||
|
||||
@@ -1145,6 +1145,8 @@ static void test_assembly(void)
|
||||
|
||||
reencoded = sms_decode_text(l);
|
||||
|
||||
g_slist_free_full(l, g_free);
|
||||
|
||||
if (g_test_verbose())
|
||||
g_printf("ReEncoded:\n%s\n", reencoded);
|
||||
|
||||
@@ -1304,6 +1306,8 @@ static void test_prepare_concat(gconstpointer data)
|
||||
g_assert(decoded_str);
|
||||
g_assert(strcmp(decoded_str, test->str) == 0);
|
||||
g_free(decoded_str);
|
||||
g_slist_free_full(pdus, g_free);
|
||||
g_slist_free_full(r, g_free);
|
||||
sms_assembly_free(assembly);
|
||||
}
|
||||
|
||||
@@ -1334,6 +1338,7 @@ static void test_limit(gunichar uni, int target_size, gboolean use_16bit)
|
||||
g_assert(g_utf8_strlen(decoded, -1) == target_size);
|
||||
|
||||
g_free(decoded);
|
||||
g_slist_free_full(l, g_free);
|
||||
|
||||
memcpy(utf8 + i, utf8_char, stride);
|
||||
utf8[i+stride] = '\0';
|
||||
|
||||
@@ -1,333 +0,0 @@
|
||||
* Fri Feb 27 2015 Tommi Kenakkala <tommi.kenakkala@tieto.com> - 1.16
|
||||
- Update to upstream 1.16
|
||||
- Rilmodem work
|
||||
- Some core changes and API extensions
|
||||
|
||||
* Thu Jan 09 2014 Martti Piirainen <martti.piirainen@oss.tieto.com> - 1.14
|
||||
- Update to upstream 1.14.
|
||||
|
||||
* Wed Jun 12 2013 Juho Hämäläinen <juho.hamalainen@tieto.com> - 1.12
|
||||
- Update to upstream 1.12.
|
||||
- Add phablet patches for ril (version 1.12phablet3).
|
||||
- Additional ril work and fixes.
|
||||
|
||||
* Wed Jan 16 2013 Petri M. Gerdt <petri.gerdt@jollamobile.com> - 1.11
|
||||
- add patch 0001-Experimental-network-time-plugin.patch which adds
|
||||
an API for accessing cellular network time.
|
||||
|
||||
* Mon Dec 10 2012 Lorn Potter <lorn.potter@jollamobile.com> - 1.11
|
||||
- upgrade ofono to 1.11
|
||||
|
||||
* Fri Aug 24 2012 Jarko Poutiainen <jarko.poutiainen@tieto.com> - 1.10
|
||||
- upgrade ofono to 1.10
|
||||
- remove n950 patches
|
||||
- add patch to disable cbs from n900 plugin
|
||||
- add patch to fix answering for N9 modem
|
||||
|
||||
* Thu Aug 23 2012 Carsten Munk <carsten.munk@jollamobile.com> - 1.8
|
||||
- Add isimodem-fix-incoming-calls.patch to fix incoming calls on isimodem
|
||||
|
||||
* Wed Jul 11 2012 Marko Saukko <marko.saukko@jollamobile.com> - 1.8
|
||||
- Fixes MER#285: upgrade ofono to recent version
|
||||
- Fixes MER#422: ofono-test package requires python dbus bindings.
|
||||
- Rename -test packages to -tests
|
||||
|
||||
* Wed Sep 21 2011 Sami Sirkia <sami.sirkia@cybercom.com> - 0.52
|
||||
- Include patches for N950
|
||||
|
||||
* Fri Sep 16 2011 Jouni Peltonen <jouni.peltonen@cybercom.com> - 0.52
|
||||
- Patch BMC22161-isi-call-id.patch added to correct isi modem answering
|
||||
BMC #22161.
|
||||
|
||||
* Tue Jul 19 2011 Yu <yu.a.wang@intel.com> - 0.52
|
||||
- upgrade to 0.52
|
||||
|
||||
* Wed Jul 13 2011 Yu <yu.a.wang@intel.com> - 0.51
|
||||
- upgrade to 0.51
|
||||
|
||||
* Thu Jun 23 2011 Yu <yu.a.wang@intel.com> - 0.50
|
||||
- upgrade to 0.50
|
||||
|
||||
* Thu Jun 23 2011 Yu <yu.a.wang@intel.com> - 0.49
|
||||
- Remove requirement for package usb-modeswitch and use-modeswitch-date due to this is not the right way to fix BMC#19097
|
||||
- Release engineer already added these two packages to package-groups
|
||||
|
||||
* Wed Jun 15 2011 Yu <yu.a.wang@intel.com> - 0.49
|
||||
- Add requirement for package usb-modeswitch and usb-modeswitch-data fix BMC#19097
|
||||
|
||||
* Wed Jun 08 2011 Yu <yu.a.wang@intel.com> - 0.49
|
||||
- upgrade to 0.49
|
||||
|
||||
* Wed May 25 2011 Chris Ferron <chris.e.ferron@linux.intel.com> - 0.48
|
||||
- Updated spec file to change systemctl as a requires to the package systemd
|
||||
- for each scriplet section. Also added a Requires systemd as systemd is configured
|
||||
- as a build option for this package exposing systemd features.
|
||||
|
||||
* Tue May 03 2011 Chris Ferron <chris.e.ferron@linux.intel.com> - 0.48
|
||||
- FEA#16109 - [FEA] Implement SystemD as MeeGo init provide
|
||||
- Updated the ofono package to be usable by systemd as needed
|
||||
to implement systemd as the init provider of MeeGo. For this
|
||||
a systemd ofono.service file was added and installed. This will
|
||||
allow systemd to start stop and track the service.
|
||||
|
||||
* Fri Apr 29 2011 Junfeng Dong <junfeng.dong@intel.com> - 0.48
|
||||
- Fix the error caused by updating libtool.
|
||||
|
||||
* Tue Apr 26 2011 Yu <yu.a.wang@intel.com> - 0.48
|
||||
- upgrade to 0.48 for BMC #14213
|
||||
- Fix issue with crash due to not stopped PPP timers.
|
||||
- Fix issue with offline mode handling and Huawei modem.
|
||||
- Fix issue with missing check for Huawei modem device open.
|
||||
- Fix issue with USSD and use of non-cloned GAtChat object.
|
||||
|
||||
* Sun Apr 17 2011 Yu <yu.a.wang@intel.com> - 0.47
|
||||
- upgrade to 0.47 for BMC #14213
|
||||
- Fix issue with entering offline mode prematurely.
|
||||
- Add support for CPHS CSP network registration handling.
|
||||
|
||||
* Wed Apr 13 2011 Yu <yu.a.wang@intel.com> - 0.46
|
||||
- upgrade to 0.46
|
||||
- Fix issue with operator name reading and older ISI modems.
|
||||
- Fix issue with networking registration and older ISI modems.
|
||||
- Fix issue with missing handling of PIN/SIM states and ISI modems.
|
||||
- Fix issue with voice call state reporting and ISI modems.
|
||||
- Fix issue with STK handling of environment variables.
|
||||
- Fix issue with STK and empty URL for launch browser.
|
||||
- Fix issue with voice call pause character validation.
|
||||
- Fix issue with buffer length and long phone numbers.
|
||||
- Fix issue with SMS sending retries and network timeout.
|
||||
- Fix issue with missing SMS submit canceled history status.
|
||||
- Add support for cancellation of SMS submission.
|
||||
- Add support for handling SIM Toolkit display action commands.
|
||||
- Add support for handling call forwarding and SIM refresh.
|
||||
- Add support for handling EFimg and EFiidf changes.
|
||||
- Add support for handling EFmsisdn and EFsdn changes.
|
||||
- Add support for handling emergency calls without SIM.
|
||||
- Add support for handling emergency calls without PIN.
|
||||
- Add support for handling emergency number updates.
|
||||
- Add support for assisted satellite navigation interface.
|
||||
- Add support for IPv6 contexts and ISI modems.
|
||||
- Add support for dual-stack GPRS contexts.
|
||||
- Add limited support for CDMA connection manager interface.
|
||||
|
||||
* Mon Mar 28 2011 Yu <yu.a.wang@intel.com> - 0.45
|
||||
- upgrade to 0.45
|
||||
- remove three already integrated patches
|
||||
- Fix issue with SIM Toolkit null data object.
|
||||
- Fix issue with SIM filesystem and modem release.
|
||||
- Fix issue with disconnect handling and Huawei modems.
|
||||
- Add support for improved SSN and voicecall handling.
|
||||
- Add support for SIM Toolkit Refresh handled by the modem.
|
||||
- Add support for multiple AT channels and STE modems.
|
||||
- Add support for ISI drivers and wgmodem2.5 handling.
|
||||
- Add support for optimized ringbuffer operations.
|
||||
- Add support for optimized PPP buffer management.
|
||||
|
||||
* Fri Feb 18 2011 Martin Xu <martin.xu@intel.com> - 0.41
|
||||
- Add patches:
|
||||
- 0001_fix_huawei_em770w.patch
|
||||
- 0002_fix_huawei_em770w.patch
|
||||
- 0003_fix_huawei_em770w.patch
|
||||
- to fix BMC #6944 #10018 #9797 #9201
|
||||
|
||||
* Wed Feb 09 2011 Martin Xu <martin.xu@intel.com> - 0.41
|
||||
- upgrade to 0.41 for BMC #12692
|
||||
- Fix issue with SIM callback handling.
|
||||
- Fix issue with XTMS handling and IFX modem.
|
||||
- Add support for alphabets and SMS encoding.
|
||||
- Add support for generic PIN retries handling.
|
||||
- Add support for PIN retries and MBM modem.
|
||||
- Add support for radio settings and MBM modem.
|
||||
- Add support for cell broadcast and STE modem.
|
||||
- Add support for handling ECAV status Released.
|
||||
|
||||
* Thu Jan 27 2011 Jouni Peltonen <jouni.peltonen@cybercom.com> - 0.39
|
||||
- Fixes BMC#12559.
|
||||
- 0001-isimodem-Fix-race-condition-in-SIM-probe.patch upstream commit: 9306837053cd6ce35e0fe02f03c3cd0eba443f6c.
|
||||
- 0002-n900-Fix-online.patch upstream commit: f6f0f4d12116cbf8787928146b3b97df21acb739
|
||||
|
||||
* Fri Jan 21 2011 Martin Xu <martin.xu@intel.com> - 0.39
|
||||
- upgrade to 0.39 for BMC #12692
|
||||
- Fix issue with not handling empty EFecc properly.
|
||||
- Fix issue with string length and DTMF handling.
|
||||
- Fix issue with missing info for terminal busy result.
|
||||
- Fix issue with signal strength handling and IFX modem.
|
||||
- Fix handling of SIM Toolkit enabling and IFX modem.
|
||||
- Add support for packet switched bearer notifications.
|
||||
- Add support for handling called line identification.
|
||||
- Add support for PIN retry counter interface.
|
||||
- Add support for ST-Ericsson modem init daemon.
|
||||
- Add support for Cinterion TC65 modem.
|
||||
- Add support for simple ISI client interface.
|
||||
|
||||
* Fri Jan 07 2011 Martin Xu <martin.xu@intel.com> - 0.38
|
||||
- upgrade to 0.38 for BMC #12501
|
||||
- Change CalledLine* to ConnectedLine* properties.
|
||||
- Fix issue with calling presentation property.
|
||||
- Fix issue with network time and ISI modems.
|
||||
- Fix issue with timezone reporting and HSO modems.
|
||||
- Fix issue with SIM ready status and HSO modems.
|
||||
- Fix issue with hidden caller ID and STE modems.
|
||||
- Fix issue with handling of STK Setup Menu.
|
||||
- Fix issue with missing STK text and icon checks.
|
||||
- Fix issue with missing signal strength query.
|
||||
|
||||
* Wed Dec 08 2010 Martin Xu <martin.xu@intel.com> - 0.36
|
||||
- upgrade to 0.36
|
||||
- Fix issue with CLIR Invocation and Suppression.
|
||||
- Fix issue with power/online transition with ZTE devices.
|
||||
- Fix segmentation fault when removing Nokia Datacard.
|
||||
- Add support for Nokia CS-17 dongles.
|
||||
- Add support for Ericsson F5521gw devices.
|
||||
- Add support for CAIF network interface management.
|
||||
- Add support for COLR in generic AT modem driver.
|
||||
- Add support for SMS Point-to-Point download to UICC.
|
||||
- Add support for checking specific service availability.
|
||||
- Add support for handling null text field for STK.
|
||||
|
||||
* Mon Nov 15 2010 Martin Xu <martin.xu@intel.com> - 0.35
|
||||
- upgrade to 0.35
|
||||
|
||||
* Wed Nov 03 2010 Martin Xu <martin.xu@intel.com> - 0.34
|
||||
- upgrade to 0.34
|
||||
|
||||
* Tue Oct 26 2010 Martin Xu <martin.xu@intel.com> - 0.33
|
||||
- upgrade to 0.33 to fix IFX-MAL bugs
|
||||
|
||||
* Wed Oct 13 2010 Anas Nashif <nashif@linux.intel.com> - 0.31
|
||||
- Remove requirement on ofono-config
|
||||
- Remove unused and obsolete patches
|
||||
|
||||
* Mon Oct 11 2010 Martin Xu <martin.xu@intel.com> - 0.31
|
||||
- upgrade to 0.31
|
||||
- Remove the N900 package patches, waiting for them in upstream
|
||||
|
||||
* Tue Sep 21 2010 Marko Saukko <marko.saukko@cybercom.com> - 0.26
|
||||
- Updated N900 patch
|
||||
- Added modem.conf back as phonet is autodetected with the new patches.
|
||||
- This is the final piece of implementing FEA#4134, FEA#4135, FEA#4136
|
||||
(Dialer - Make call, end call, receive call) on ARM/N900.
|
||||
- Fixes BMC#5662 (Nokia N900 modem does not turn on in Ofono)
|
||||
|
||||
* Fri Sep 3 2010 Carsten Valdemar Munk <carsten@maemo.org> - 0.26
|
||||
- Include N900 patch
|
||||
- Seperate modem.conf out into seperate packages providing ofono-config. Reasoning is because there might be other
|
||||
devices with phonet0, not all n900modem.
|
||||
|
||||
* Thu Aug 26 2010 Martin Xu <martin.xu@intel.com> - 0.26
|
||||
- upgrade to 0.26
|
||||
|
||||
* Mon Jul 19 2010 Martin Xu <martin.xu@intel.com> - 0.25
|
||||
- upgrade to 0.25
|
||||
|
||||
* Wed Jul 14 2010 Martin Xu <martin.xu@intel.com> - 0.24
|
||||
- upgrade to 0.24
|
||||
|
||||
* Tue Jun 22 2010 Martin Xu <martin.xu@intel.com> - 0.23
|
||||
- Upgrade to 0.23
|
||||
|
||||
* Fri May 07 2010 Prajwal Mohan <prajwal.karur.mohan@intel.com> - 0.20
|
||||
- Enabling phonesim for handset images
|
||||
|
||||
* Thu Mar 25 2010 Martin Xu <martin.xu@intel.com> - 0.20
|
||||
- Upgrade to 0.20
|
||||
|
||||
* Tue Feb 23 2010 Martin Xu <martin.xu@intel.com> - 0.18
|
||||
- upgrade to 0.18
|
||||
- remove 0001-add-netmask-to-hso-gprs-context-driver.patch
|
||||
|
||||
* Mon Feb 22 2010 Anas Nashif <anas.nashif@intel.com> - 0.15
|
||||
- Use spectacle
|
||||
- Update Group
|
||||
|
||||
* Tue Jan 05 2010 Martin Xu <martin.xu@intel.com> - 0.15
|
||||
- upgrade to 0.15
|
||||
- add patch 0001-add-netmask-to-hso-gprs-context-driver.patch
|
||||
|
||||
* Mon Dec 14 2009 Martin Xu <martin.xu@intel.com> - 0.14
|
||||
- upgrade to 0.14
|
||||
|
||||
* Thu Dec 7 2009 Martin Xu <martin.xu@intel.com> - 0.13
|
||||
- remove 0001-Allow-builds-to-install-the-test-scripts-for-debuggi.patch
|
||||
- remove use_AT_CFUN_to_query_powered_state.patch
|
||||
- patches has been merged in upstream
|
||||
|
||||
* Thu Dec 7 2009 Martin Xu <martin.xu@intel.com> - 0.13
|
||||
- upgrade to 0.13
|
||||
|
||||
* Thu Dec 3 2009 Martin Xu <martin.xu@intel.com> - 0.12
|
||||
- upgrade to 0.12
|
||||
- clean up spec file
|
||||
- add test subpackage
|
||||
|
||||
* Wed Nov 25 2009 Shane Bryan <shane.bryan@linux.intel.com> - 0.11
|
||||
Update to version 0.11
|
||||
|
||||
* Wed Oct 21 2009 Shane Bryan <shane.bryan@linux.intel.com> - 0.7
|
||||
Additional helper scripts added
|
||||
|
||||
* Mon Oct 19 2009 Shane Bryan <shane.bryan@linux.intel.com> - 0.7
|
||||
Fix install perms on .desktop file
|
||||
|
||||
* Mon Oct 19 2009 Shane Bryan <shane.bryan@linux.intel.com> - 0.7
|
||||
Fixed .ini file and actually added the .desktop file this time
|
||||
|
||||
* Mon Oct 19 2009 Shane Bryan <shane.bryan@linux.intel.com> - 0.7
|
||||
Add .desktop file back in
|
||||
|
||||
* Wed Oct 14 2009 Shane Bryan <shane.bryan@linux.intel.com> - 0.7
|
||||
Fix build
|
||||
|
||||
* Wed Oct 14 2009 Shane Bryan <shane.bryan@linux.intel.com> - 0.7
|
||||
Fix build
|
||||
|
||||
* Wed Oct 14 2009 Shane Bryan <shane.bryan@linux.intel.com> - 0.7
|
||||
Remove service autostart and allow to run as default user
|
||||
|
||||
* Tue Oct 06 2009 Shane Bryan <shane.bryan@linux.intel.com> - 0.7
|
||||
Fix hardcoded modem path in ofono-modem-power script
|
||||
|
||||
* Tue Oct 06 2009 Shane Bryan <shane.bryan@linux.intel.com> - 0.7
|
||||
Update to version 0.7
|
||||
|
||||
* Fri Sep 11 2009 Shane Bryan <shane.bryan@linux.intel.com> - 0.4
|
||||
Obsolete now defunct ofono-extras package
|
||||
|
||||
* Thu Sep 10 2009 Shane Bryan <shane.bryan@linux.intel.com> - 0.4
|
||||
Updated ofono-devel.files with man files and header glob
|
||||
|
||||
* Thu Sep 10 2009 Shane Bryan <shane.bryan@linux.intel.com> - 0.4
|
||||
Fixed bad ref to modem.conf in ofono.files
|
||||
|
||||
* Thu Sep 10 2009 Shane Bryan <shane.bryan@linux.intel.com> - 0.4
|
||||
Created missing bin dir
|
||||
|
||||
* Thu Sep 10 2009 Shane Bryan <shane.bryan@linux.intel.com> - 0.4
|
||||
Created missing autostart and dbus dirs
|
||||
|
||||
* Thu Sep 10 2009 Shane Bryan <shane.bryan@linux.intel.com> - 0.4
|
||||
Fixed bad sysconfdir reference
|
||||
|
||||
* Thu Sep 10 2009 Shane Bryan <shane.bryan@linux.intel.com> - 0.4
|
||||
Update to version 0.4
|
||||
Added moblin specific configurations and patches
|
||||
|
||||
* Fri Jul 31 2009 Shane Bryan <shane.bryan@linux.intel.com> - 0.2
|
||||
- Add new headers to ofono-devel.files list
|
||||
|
||||
* Fri Jul 31 2009 Shane Bryan <shane.bryan@linux.intel.com> - 0.2
|
||||
- Update to tip of tree (0.2+)
|
||||
|
||||
* Wed Jun 24 2009 Shane Bryan <shane.bryan@linux.intel.com> - 0.0
|
||||
- Tip of tree update (127b56baccc8830eb1), plus my patches
|
||||
|
||||
* Tue Jun 23 2009 Shane Bryan <shane.bryan@linux.intel.com> - 0.0
|
||||
- Add new history.h to installed devel file list
|
||||
|
||||
* Tue Jun 23 2009 Shane Bryan <shane.bryan@linux.intel.com> - 0.0
|
||||
- Pulling in latest from tip or tree
|
||||
|
||||
* Thu May 21 2009 Shane Bryan <shane.bryan@linux.intel.com> - 0.0
|
||||
- Initial import into Moblin, based on upstream ofono.org git,
|
||||
commit c427cdfdfacbec9b0221e157797e6c9d33113e91
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
Name: ofono
|
||||
|
||||
Summary: Open Source Telephony
|
||||
Version: 1.18
|
||||
Version: 1.19
|
||||
Release: 1
|
||||
Group: Communications/Connectivity Adaptation
|
||||
License: GPLv2
|
||||
@@ -10,20 +10,21 @@ Source: %{name}-%{version}.tar.bz2
|
||||
Requires: dbus
|
||||
Requires: systemd
|
||||
Requires: ofono-configs
|
||||
Requires: libgrilio >= 1.0.10
|
||||
Requires: libglibutil >= 1.0.10
|
||||
Requires: libgrilio >= 1.0.16
|
||||
Requires: libglibutil >= 1.0.23
|
||||
Requires: mobile-broadband-provider-info
|
||||
Requires(preun): systemd
|
||||
Requires(post): systemd
|
||||
Requires(postun): systemd
|
||||
BuildRequires: pkgconfig(glib-2.0)
|
||||
BuildRequires: pkgconfig(dbus-1)
|
||||
BuildRequires: pkgconfig(glib-2.0)
|
||||
BuildRequires: pkgconfig(libudev) >= 145
|
||||
BuildRequires: pkgconfig(mobile-broadband-provider-info)
|
||||
BuildRequires: pkgconfig(libwspcodec) >= 2.0
|
||||
BuildRequires: pkgconfig(libgrilio) >= 1.0.10
|
||||
BuildRequires: pkgconfig(libglibutil) >= 1.0.10
|
||||
BuildRequires: pkgconfig(libgrilio) >= 1.0.18
|
||||
BuildRequires: pkgconfig(libglibutil) >= 1.0.23
|
||||
BuildRequires: pkgconfig(libdbuslogserver-dbus)
|
||||
BuildRequires: pkgconfig(libmce-glib)
|
||||
BuildRequires: pkgconfig(libmce-glib) >= 1.0.5
|
||||
BuildRequires: pkgconfig(mobile-broadband-provider-info)
|
||||
BuildRequires: libtool
|
||||
BuildRequires: automake
|
||||
BuildRequires: autoconf
|
||||
@@ -69,11 +70,18 @@ autoreconf --force --install
|
||||
|
||||
%configure --disable-static \
|
||||
--enable-test \
|
||||
--enable-debuglog \
|
||||
--enable-jolla-rilmodem \
|
||||
--enable-sailfish-bt \
|
||||
--enable-sailfish-debuglog \
|
||||
--enable-sailfish-manager \
|
||||
--enable-sailfish-provision \
|
||||
--enable-sailfish-pushforwarder \
|
||||
--enable-sailfish-rilmodem \
|
||||
--disable-add-remove-context \
|
||||
--disable-isimodem \
|
||||
--disable-qmimodem \
|
||||
--with-systemdunitdir="/%{_lib}/systemd/system"
|
||||
|
||||
make %{?jobs:-j%jobs}
|
||||
make %{_smp_mflags}
|
||||
|
||||
|
||||
%check
|
||||
|
||||
Reference in New Issue
Block a user