forked from sailfishos/ofono
		
	Compare commits
	
		
			130 Commits
		
	
	
		
			mer/1.18+g
			...
			mer/1.19+g
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					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 | ||
| 
						 | 
					8cea5b9f96 | ||
| 
						 | 
					5fb35d5fb4 | ||
| 
						 | 
					e8d57bb928 | ||
| 
						 | 
					2bfde2418e | ||
| 
						 | 
					c710ce76c1 | ||
| 
						 | 
					78acd90464 | ||
| 
						 | 
					e51b3ca0c8 | ||
| 
						 | 
					b3c8813bd4 | ||
| 
						 | 
					e2a3acd9d0 | ||
| 
						 | 
					2054ca9570 | ||
| 
						 | 
					48dbb7912a | ||
| 
						 | 
					d7e7ad671d | ||
| 
						 | 
					5b5a86dc80 | ||
| 
						 | 
					c232524e99 | ||
| 
						 | 
					bfd09a5c14 | ||
| 
						 | 
					f8adcd2550 | ||
| 
						 | 
					2a97567147 | ||
| 
						 | 
					04d84b615e | ||
| 
						 | 
					6e34792323 | ||
| 
						 | 
					d6a59f5dc4 | ||
| 
						 | 
					23e299055f | ||
| 
						 | 
					a56ef3ba0f | ||
| 
						 | 
					7294433906 | ||
| 
						 | 
					d7263cd344 | ||
| 
						 | 
					2f3b469fbb | ||
| 
						 | 
					4187e7ee8f | ||
| 
						 | 
					4d3f89bae0 | ||
| 
						 | 
					cbd1c5d524 | ||
| 
						 | 
					7976e44746 | ||
| 
						 | 
					3d6e220686 | ||
| 
						 | 
					919526d392 | ||
| 
						 | 
					b7082146e8 | ||
| 
						 | 
					094a296a14 | ||
| 
						 | 
					5c259e751b | ||
| 
						 | 
					69e5d5b356 | ||
| 
						 | 
					56e7d0e8ea | ||
| 
						 | 
					bb2ae6d1a1 | ||
| 
						 | 
					cf7692db49 | ||
| 
						 | 
					63f3311cd6 | ||
| 
						 | 
					c5aae77d41 | ||
| 
						 | 
					f8e21c8ad4 | ||
| 
						 | 
					8e6dfe433b | ||
| 
						 | 
					ae23bb552b | ||
| 
						 | 
					2becd051d4 | ||
| 
						 | 
					8cfb1d5ca3 | ||
| 
						 | 
					50f35458f6 | ||
| 
						 | 
					51843accf7 | ||
| 
						 | 
					fb856dc7d6 | 
							
								
								
									
										14
									
								
								ofono/.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										14
									
								
								ofono/.gitignore
									
									
									
									
										vendored
									
									
								
							@@ -44,10 +44,24 @@ unit/test-stkutil
 | 
			
		||||
unit/test-cdmasms
 | 
			
		||||
unit/test-rilmodem-cb
 | 
			
		||||
unit/test-rilmodem-cs
 | 
			
		||||
unit/test-rilmodem-gprs
 | 
			
		||||
unit/test-rilmodem-sms
 | 
			
		||||
unit/test-*.log
 | 
			
		||||
unit/test-*.trs
 | 
			
		||||
 | 
			
		||||
unit/test-grilreply
 | 
			
		||||
unit/test-grilrequest
 | 
			
		||||
unit/test-grilunsol
 | 
			
		||||
unit/test-provision
 | 
			
		||||
unit/html
 | 
			
		||||
 | 
			
		||||
drivers/*/*.gcda
 | 
			
		||||
drivers/*/*.gcno
 | 
			
		||||
drivers/*/*.gcov
 | 
			
		||||
*/*.gcda
 | 
			
		||||
*/*.gcno
 | 
			
		||||
*/*.gcov
 | 
			
		||||
 | 
			
		||||
tools/huawei-audio
 | 
			
		||||
tools/auto-enable
 | 
			
		||||
tools/get-location
 | 
			
		||||
 
 | 
			
		||||
@@ -113,3 +113,6 @@ Anirudh Gargi <anirudh.gargi@intel.com>
 | 
			
		||||
Nishanth V <nishanth.v@intel.com>
 | 
			
		||||
Antara Borwankar <antara.borwankar@gmail.com>
 | 
			
		||||
Martin Chaplet <m.chaplet@kerlink.fr>
 | 
			
		||||
Suman Mallela <suman.m@intel.com>
 | 
			
		||||
Rajagopal Aravindan <rajagopalx.aravindan@intel.com>
 | 
			
		||||
Antoine Aubert <a.aubert@overkiz.com>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,3 +1,13 @@
 | 
			
		||||
ver 1.19:
 | 
			
		||||
	Fix issue with DHCP parsing and Huawei modems.
 | 
			
		||||
	Fix issue with detecting Huawei E3372 modem.
 | 
			
		||||
	Fix issue with handling serving cell info.
 | 
			
		||||
	Fix issue with handling SIM SC facility lock.
 | 
			
		||||
	Fix issue with Android RIL PIN retry logic.
 | 
			
		||||
	Fix issue with Android RIL and RAT handling.
 | 
			
		||||
	Add support for Android RIL cell broadcast.
 | 
			
		||||
	Add support for SoFIA 3GR thermal management.
 | 
			
		||||
 | 
			
		||||
ver 1.18:
 | 
			
		||||
	Fix issue with cell broadcast and use-after-fee.
 | 
			
		||||
	Fix issue with repeated held call indicator.
 | 
			
		||||
 
 | 
			
		||||
@@ -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_manager.h \
 | 
			
		||||
			include/sailfish_watch.h
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
local_headers = $(foreach file,$(pkginclude_HEADERS) \
 | 
			
		||||
				$(nodist_pkginclude_HEADERS), \
 | 
			
		||||
					include/ofono/$(notdir $(file)))
 | 
			
		||||
@@ -116,8 +121,17 @@ builtin_modules += udevng
 | 
			
		||||
builtin_sources += plugins/udevng.c
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
if SAILFISH_MANAGER
 | 
			
		||||
builtin_modules += sailfish_manager
 | 
			
		||||
builtin_sources += 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 \
 | 
			
		||||
@@ -134,20 +148,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 \
 | 
			
		||||
@@ -197,6 +208,7 @@ builtin_sources += drivers/rilmodem/rilmodem.h \
 | 
			
		||||
			drivers/rilmodem/call-barring.c \
 | 
			
		||||
			drivers/rilmodem/netmon.c \
 | 
			
		||||
			drivers/rilmodem/stk.c \
 | 
			
		||||
			drivers/rilmodem/cbs.c \
 | 
			
		||||
			drivers/infineonmodem/infineon_constants.h
 | 
			
		||||
endif
 | 
			
		||||
endif
 | 
			
		||||
@@ -574,6 +586,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
 | 
			
		||||
@@ -587,11 +604,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
 | 
			
		||||
@@ -629,16 +660,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
 | 
			
		||||
@@ -650,6 +674,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 \
 | 
			
		||||
@@ -758,6 +783,7 @@ test_scripts = test/backtrace \
 | 
			
		||||
		test/receive-sms \
 | 
			
		||||
		test/remove-contexts \
 | 
			
		||||
		test/send-sms \
 | 
			
		||||
		test/cancel-sms \
 | 
			
		||||
		test/set-mic-volume \
 | 
			
		||||
		test/set-speaker-volume \
 | 
			
		||||
		test/test-stk-menu \
 | 
			
		||||
@@ -828,7 +854,9 @@ test_scripts = test/backtrace \
 | 
			
		||||
		test/set-sms-smsc \
 | 
			
		||||
		test/set-sms-bearer \
 | 
			
		||||
		test/get-serving-cell-info \
 | 
			
		||||
		test/list-allowed-access-points
 | 
			
		||||
		test/list-allowed-access-points \
 | 
			
		||||
		test/enable-throttling \
 | 
			
		||||
		test/disable-throttling
 | 
			
		||||
 | 
			
		||||
if TEST
 | 
			
		||||
testdir = $(pkglibdir)/test
 | 
			
		||||
@@ -840,6 +868,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 =
 | 
			
		||||
 | 
			
		||||
@@ -848,13 +879,39 @@ unit_tests = unit/test-common unit/test-util unit/test-idmap \
 | 
			
		||||
				unit/test-sms unit/test-cdmasms \
 | 
			
		||||
				unit/test-provision
 | 
			
		||||
 | 
			
		||||
if SAILFISH_MANAGER
 | 
			
		||||
 | 
			
		||||
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_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 JOLLA_RILMODEM
 | 
			
		||||
if SAILFISH_RILMODEM
 | 
			
		||||
 | 
			
		||||
unit_tests += unit/test-rilmodem-cs \
 | 
			
		||||
				unit/test-rilmodem-cs \
 | 
			
		||||
				unit/test-rilmodem-sms \
 | 
			
		||||
				unit/test-rilmodem-cb
 | 
			
		||||
				unit/test-rilmodem-cb \
 | 
			
		||||
				unit/test-rilmodem-gprs
 | 
			
		||||
 | 
			
		||||
endif
 | 
			
		||||
endif
 | 
			
		||||
@@ -863,19 +920,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)
 | 
			
		||||
 | 
			
		||||
@@ -883,19 +944,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)
 | 
			
		||||
 | 
			
		||||
@@ -906,24 +971,26 @@ 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)
 | 
			
		||||
 | 
			
		||||
if RILMODEM
 | 
			
		||||
if JOLLA_RILMODEM
 | 
			
		||||
 | 
			
		||||
test_rilmodem_sources = $(gril_sources) src/log.c src/common.c src/util.c \
 | 
			
		||||
				gatchat/ringbuffer.h gatchat/ringbuffer.c \
 | 
			
		||||
				unit/rilmodem-test-server.h \
 | 
			
		||||
				unit/rilmodem-test-server.c \
 | 
			
		||||
				src/simutil.c
 | 
			
		||||
				unit/rilmodem-test-engine.h \
 | 
			
		||||
				unit/rilmodem-test-engine.c \
 | 
			
		||||
				src/simutil.c \
 | 
			
		||||
				drivers/rilmodem/rilutil.c
 | 
			
		||||
 | 
			
		||||
unit_test_rilmodem_cs_SOURCES = $(test_rilmodem_sources) \
 | 
			
		||||
					unit/test-rilmodem-cs.c \
 | 
			
		||||
@@ -946,8 +1013,12 @@ unit_test_rilmodem_cb_LDADD = gdbus/libgdbus-internal.la $(builtin_libadd) \
 | 
			
		||||
					@GLIB_LIBS@ @DBUS_LIBS@ -ldl
 | 
			
		||||
unit_objects += $(unit_test_rilmodem_cb_OBJECTS)
 | 
			
		||||
 | 
			
		||||
endif
 | 
			
		||||
endif
 | 
			
		||||
unit_test_rilmodem_gprs_SOURCES = $(test_rilmodem_sources) \
 | 
			
		||||
					unit/test-rilmodem-gprs.c \
 | 
			
		||||
					drivers/rilmodem/gprs.c
 | 
			
		||||
unit_test_rilmodem_gprs_LDADD = gdbus/libgdbus-internal.la $(builtin_libadd) \
 | 
			
		||||
					@GLIB_LIBS@ @DBUS_LIBS@ -ldl
 | 
			
		||||
unit_objects += $(unit_test_rilmodem_gprs_OBJECTS)
 | 
			
		||||
 | 
			
		||||
TESTS = $(unit_tests)
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,5 @@
 | 
			
		||||
AC_PREREQ(2.60)
 | 
			
		||||
AC_INIT(ofono, 1.18)
 | 
			
		||||
AC_INIT(ofono, 1.19)
 | 
			
		||||
 | 
			
		||||
AM_INIT_AUTOMAKE([foreign subdir-objects color-tests])
 | 
			
		||||
AC_CONFIG_HEADERS(config.h)
 | 
			
		||||
@@ -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.16, dummy=yes,
 | 
			
		||||
				AC_MSG_ERROR(libgrilio >= 1.0.16 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);
 | 
			
		||||
 
 | 
			
		||||
@@ -80,7 +80,7 @@ static gboolean get_next_addr(GAtResultIter *iter, char **addr)
 | 
			
		||||
	if (g_at_result_iter_next_unquoted_string(iter, &str) == FALSE)
 | 
			
		||||
		return FALSE;
 | 
			
		||||
 | 
			
		||||
	val = strtol(str, NULL, 16);
 | 
			
		||||
	val = strtoul(str, NULL, 16);
 | 
			
		||||
 | 
			
		||||
	if (addr)
 | 
			
		||||
		*addr = g_strdup_printf("%u.%u.%u.%u",
 | 
			
		||||
 
 | 
			
		||||
@@ -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;
 | 
			
		||||
 
 | 
			
		||||
@@ -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,60 +16,155 @@
 | 
			
		||||
#include "ril_plugin.h"
 | 
			
		||||
#include "ril_util.h"
 | 
			
		||||
#include "ril_log.h"
 | 
			
		||||
#include "ril_constants.h"
 | 
			
		||||
 | 
			
		||||
#include <gutil_strv.h>
 | 
			
		||||
 | 
			
		||||
struct ril_cbs {
 | 
			
		||||
	struct ofono_cbs *cbs;
 | 
			
		||||
	GRilIoChannel *io;
 | 
			
		||||
	guint timer_id;
 | 
			
		||||
	GRilIoQueue *q;
 | 
			
		||||
	char *log_prefix;
 | 
			
		||||
	gulong event_id;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void ril_set_topics(struct ofono_cbs *cbs, const char *topics,
 | 
			
		||||
				ofono_cbs_set_cb_t cb, void *data)
 | 
			
		||||
struct ril_cbs_cbd {
 | 
			
		||||
	struct ril_cbs *cd;
 | 
			
		||||
	ofono_cbs_set_cb_t cb;
 | 
			
		||||
	gpointer data;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#define RIL_CBS_CHECK_RETRY_MS    1000
 | 
			
		||||
#define RIL_CBS_CHECK_RETRY_COUNT 30
 | 
			
		||||
 | 
			
		||||
#define DBG_(cd,fmt,args...) DBG("%s" fmt, (cd)->log_prefix, ##args)
 | 
			
		||||
 | 
			
		||||
#define ril_cbs_cbd_free g_free
 | 
			
		||||
 | 
			
		||||
static struct ril_cbs_cbd *ril_cbs_cbd_new(struct ril_cbs *cd,
 | 
			
		||||
		ofono_cbs_set_cb_t cb, void *data)
 | 
			
		||||
{
 | 
			
		||||
	struct ofono_error error;
 | 
			
		||||
	cb(ril_error_ok(&error), data);
 | 
			
		||||
	struct ril_cbs_cbd *cbd = g_new(struct ril_cbs_cbd, 1);
 | 
			
		||||
 | 
			
		||||
	cbd->cd = cd;
 | 
			
		||||
	cbd->cb = cb;
 | 
			
		||||
	cbd->data = data;
 | 
			
		||||
	return cbd;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void ril_clear_topics(struct ofono_cbs *cbs,
 | 
			
		||||
static void ril_cbs_request_activation(struct ril_cbs *cd,
 | 
			
		||||
		gboolean activate, GRilIoChannelResponseFunc response,
 | 
			
		||||
		GDestroyNotify destroy, void* user_data)
 | 
			
		||||
{
 | 
			
		||||
	GRilIoRequest* req = grilio_request_sized_new(8);
 | 
			
		||||
 | 
			
		||||
	grilio_request_append_int32(req, 1);
 | 
			
		||||
	grilio_request_append_int32(req, activate ? 0 :1);
 | 
			
		||||
 | 
			
		||||
	DBG_(cd, "%sactivating CB", activate ? "" : "de");
 | 
			
		||||
	grilio_queue_send_request_full(cd->q, req,
 | 
			
		||||
				RIL_REQUEST_GSM_SMS_BROADCAST_ACTIVATION,
 | 
			
		||||
				response, destroy, user_data);
 | 
			
		||||
	grilio_request_unref(req);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void ril_cbs_set_config(struct ril_cbs *cd, const char *topics,
 | 
			
		||||
			GRilIoChannelResponseFunc response,
 | 
			
		||||
			GDestroyNotify destroy, void* user_data)
 | 
			
		||||
{
 | 
			
		||||
	char **list = topics ? g_strsplit(topics, ",", 0) : NULL;
 | 
			
		||||
	int i, n = gutil_strv_length(list);
 | 
			
		||||
	GRilIoRequest* req = grilio_request_new();
 | 
			
		||||
 | 
			
		||||
	grilio_request_append_int32(req, n);
 | 
			
		||||
	for (i = 0; i < n; i++) {
 | 
			
		||||
		const char *entry = list[i];
 | 
			
		||||
		const char *delim = strchr(entry, '-');
 | 
			
		||||
		int from, to;
 | 
			
		||||
		if (delim) {
 | 
			
		||||
			char **range = g_strsplit(topics, "-", 0);
 | 
			
		||||
			from = atoi(range[0]);
 | 
			
		||||
			to = atoi(range[1]);
 | 
			
		||||
			g_strfreev(range);
 | 
			
		||||
		} else {
 | 
			
		||||
			from = to = atoi(entry);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		grilio_request_append_int32(req, from);
 | 
			
		||||
		grilio_request_append_int32(req, to);
 | 
			
		||||
		grilio_request_append_int32(req, 0);
 | 
			
		||||
		grilio_request_append_int32(req, 0xff);
 | 
			
		||||
		grilio_request_append_int32(req, 1);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	DBG_(cd, "configuring CB");
 | 
			
		||||
	grilio_queue_send_request_full(cd->q, req,
 | 
			
		||||
			RIL_REQUEST_GSM_SET_BROADCAST_SMS_CONFIG,
 | 
			
		||||
			response, destroy, user_data);
 | 
			
		||||
	grilio_request_unref(req);
 | 
			
		||||
	g_strfreev(list);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void ril_cbs_cb(GRilIoChannel *io, int ril_status,
 | 
			
		||||
				const void *data, guint len, void *user_data)
 | 
			
		||||
{
 | 
			
		||||
	struct ril_cbs_cbd *cbd = user_data;
 | 
			
		||||
 | 
			
		||||
	if (cbd->cb) {
 | 
			
		||||
		struct ofono_error error;
 | 
			
		||||
 | 
			
		||||
		if (ril_status == RIL_E_SUCCESS) {
 | 
			
		||||
			cbd->cb(ril_error_ok(&error), cbd->data);
 | 
			
		||||
		} else {
 | 
			
		||||
			cbd->cb(ril_error_failure(&error), cbd->data);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void ril_cbs_set_topics(struct ofono_cbs *cbs, const char *topics,
 | 
			
		||||
				ofono_cbs_set_cb_t cb, void *data)
 | 
			
		||||
{
 | 
			
		||||
	struct ofono_error error;
 | 
			
		||||
	cb(ril_error_ok(&error), data);
 | 
			
		||||
	struct ril_cbs *cd = ofono_cbs_get_data(cbs);
 | 
			
		||||
 | 
			
		||||
	DBG_(cd, "%s", topics);
 | 
			
		||||
	ril_cbs_set_config(cd, topics, ril_cbs_cb, ril_cbs_cbd_free,
 | 
			
		||||
					ril_cbs_cbd_new(cd, cb, data));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void ril_cbs_clear_topics(struct ofono_cbs *cbs,
 | 
			
		||||
				ofono_cbs_set_cb_t cb, void *data)
 | 
			
		||||
{
 | 
			
		||||
	struct ril_cbs *cd = ofono_cbs_get_data(cbs);
 | 
			
		||||
 | 
			
		||||
	DBG_(cd, "");
 | 
			
		||||
	ril_cbs_request_activation(cd, FALSE, ril_cbs_cb, ril_cbs_cbd_free,
 | 
			
		||||
					ril_cbs_cbd_new(cd, cb, data));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void ril_cbs_notify(GRilIoChannel *io, guint code,
 | 
			
		||||
				const void *data, guint len, void *user_data)
 | 
			
		||||
{
 | 
			
		||||
	struct ril_cbs *cd = user_data;
 | 
			
		||||
	GRilIoParser rilp;
 | 
			
		||||
	char* pdu;
 | 
			
		||||
 | 
			
		||||
	GASSERT(code == RIL_UNSOL_ON_USSD);
 | 
			
		||||
	grilio_parser_init(&rilp, data, len);
 | 
			
		||||
	pdu = grilio_parser_get_utf8(&rilp);
 | 
			
		||||
	DBG("%s", pdu);
 | 
			
		||||
	if (pdu) {
 | 
			
		||||
		ofono_cbs_notify(cd->cbs, (const guchar *)pdu, strlen(pdu));
 | 
			
		||||
		g_free(pdu);
 | 
			
		||||
	}
 | 
			
		||||
	GASSERT(code == RIL_UNSOL_RESPONSE_NEW_BROADCAST_SMS);
 | 
			
		||||
	DBG_(cd, "%u bytes", len);
 | 
			
		||||
	ofono_cbs_notify(cd->cbs, data, len);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gboolean ril_cbs_register(gpointer user_data)
 | 
			
		||||
static void ril_cbs_probe_done_cb(GRilIoChannel *io, int status,
 | 
			
		||||
				const void *data, guint len, void *user_data)
 | 
			
		||||
{
 | 
			
		||||
	struct ril_cbs *cd = user_data;
 | 
			
		||||
 | 
			
		||||
	DBG("");
 | 
			
		||||
	GASSERT(cd->timer_id);
 | 
			
		||||
	cd->timer_id = 0;
 | 
			
		||||
	ofono_cbs_register(cd->cbs);
 | 
			
		||||
 | 
			
		||||
	cd->event_id = grilio_channel_add_unsol_event_handler(cd->io,
 | 
			
		||||
		ril_cbs_notify, RIL_UNSOL_RESPONSE_NEW_BROADCAST_SMS, cd);
 | 
			
		||||
 | 
			
		||||
	/* Single-shot */
 | 
			
		||||
	return FALSE;
 | 
			
		||||
	if (status == RIL_E_SUCCESS) {
 | 
			
		||||
		DBG_(cd, "registering for CB");
 | 
			
		||||
		cd->event_id = grilio_channel_add_unsol_event_handler(cd->io,
 | 
			
		||||
			ril_cbs_notify, RIL_UNSOL_RESPONSE_NEW_BROADCAST_SMS,
 | 
			
		||||
									cd);
 | 
			
		||||
		ofono_cbs_register(cd->cbs);
 | 
			
		||||
	} else {
 | 
			
		||||
		DBG_(cd, "failed to query CB config");
 | 
			
		||||
		ofono_cbs_remove(cd->cbs);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int ril_cbs_probe(struct ofono_cbs *cbs, unsigned int vendor,
 | 
			
		||||
@@ -77,12 +172,30 @@ static int ril_cbs_probe(struct ofono_cbs *cbs, unsigned int vendor,
 | 
			
		||||
{
 | 
			
		||||
	struct ril_modem *modem = data;
 | 
			
		||||
	struct ril_cbs *cd = g_try_new0(struct ril_cbs, 1);
 | 
			
		||||
	GRilIoRequest* req = grilio_request_new();
 | 
			
		||||
 | 
			
		||||
	DBG("");
 | 
			
		||||
	cd->cbs = cbs;
 | 
			
		||||
	cd->io = grilio_channel_ref(ril_modem_io(modem));
 | 
			
		||||
	cd->timer_id = g_idle_add(ril_cbs_register, cd);
 | 
			
		||||
	ofono_cbs_set_data(cbs, cd);
 | 
			
		||||
	cd->log_prefix = (modem->log_prefix && modem->log_prefix[0]) ?
 | 
			
		||||
		g_strconcat(modem->log_prefix, " ", NULL) : g_strdup("");
 | 
			
		||||
	cd->cbs = cbs;
 | 
			
		||||
 | 
			
		||||
	DBG_(cd, "");
 | 
			
		||||
	cd->io = grilio_channel_ref(ril_modem_io(modem));
 | 
			
		||||
	cd->q = grilio_queue_new(cd->io);
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * 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);
 | 
			
		||||
	grilio_request_unref(req);
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -90,15 +203,13 @@ static void ril_cbs_remove(struct ofono_cbs *cbs)
 | 
			
		||||
{
 | 
			
		||||
	struct ril_cbs *cd = ofono_cbs_get_data(cbs);
 | 
			
		||||
 | 
			
		||||
	DBG("");
 | 
			
		||||
	DBG_(cd, "");
 | 
			
		||||
	ofono_cbs_set_data(cbs, NULL);
 | 
			
		||||
 | 
			
		||||
	if (cd->timer_id > 0) {
 | 
			
		||||
		g_source_remove(cd->timer_id);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	grilio_channel_remove_handler(cd->io, cd->event_id);
 | 
			
		||||
	grilio_channel_unref(cd->io);
 | 
			
		||||
	grilio_queue_cancel_all(cd->q, FALSE);
 | 
			
		||||
	grilio_queue_unref(cd->q);
 | 
			
		||||
	g_free(cd->log_prefix);
 | 
			
		||||
	g_free(cd);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -106,8 +217,8 @@ const struct ofono_cbs_driver ril_cbs_driver = {
 | 
			
		||||
	.name           = RILMODEM_DRIVER,
 | 
			
		||||
	.probe          = ril_cbs_probe,
 | 
			
		||||
	.remove         = ril_cbs_remove,
 | 
			
		||||
	.set_topics     = ril_set_topics,
 | 
			
		||||
	.clear_topics   = ril_clear_topics
 | 
			
		||||
	.set_topics     = ril_cbs_set_topics,
 | 
			
		||||
	.clear_topics   = ril_cbs_clear_topics
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
@@ -28,7 +28,6 @@ struct ril_cell_entry {
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct ril_cell_info_dbus {
 | 
			
		||||
	struct ril_modem *md;
 | 
			
		||||
	struct ril_cell_info *info;
 | 
			
		||||
	DBusConnection *conn;
 | 
			
		||||
	char *path;
 | 
			
		||||
@@ -523,7 +522,6 @@ struct ril_cell_info_dbus *ril_cell_info_dbus_new(struct ril_modem *md,
 | 
			
		||||
	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);
 | 
			
		||||
@@ -553,8 +551,6 @@ void ril_cell_info_dbus_free(struct ril_cell_info_dbus *dbus)
 | 
			
		||||
		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;
 | 
			
		||||
 
 | 
			
		||||
@@ -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,14 @@
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "ril_config.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 +33,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 +135,95 @@ 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) {
 | 
			
		||||
			const char *str = *ptr++;
 | 
			
		||||
			char *end = NULL;
 | 
			
		||||
			long ival = strtol(str, &end, 0);
 | 
			
		||||
 | 
			
		||||
			if (str[0] && !end[0]) {
 | 
			
		||||
				gutil_int_array_append(array, ival);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		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,
 | 
			
		||||
 
 | 
			
		||||
@@ -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,15 +27,14 @@
 | 
			
		||||
#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"
 | 
			
		||||
#define PROTO_IPV4V6_STR "IPV4V6"
 | 
			
		||||
 | 
			
		||||
enum ril_data_priv_flags {
 | 
			
		||||
	RIL_DATA_FLAG_NONE = 0x00,
 | 
			
		||||
	RIL_DATA_FLAG_ALLOWED = 0x01,
 | 
			
		||||
	RIL_DATA_FLAG_MAX_SPEED = 0x02,
 | 
			
		||||
	RIL_DATA_FLAG_ON = 0x04
 | 
			
		||||
@@ -100,6 +99,7 @@ struct ril_data_priv {
 | 
			
		||||
	struct ril_data_request *pending_req;
 | 
			
		||||
 | 
			
		||||
	struct ril_data_options options;
 | 
			
		||||
	guint slot;
 | 
			
		||||
	char *log_prefix;
 | 
			
		||||
	guint query_id;
 | 
			
		||||
	gulong io_event_id;
 | 
			
		||||
@@ -168,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);
 | 
			
		||||
@@ -182,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
 | 
			
		||||
 *==========================================================================*/
 | 
			
		||||
@@ -785,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);
 | 
			
		||||
 | 
			
		||||
@@ -809,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);
 | 
			
		||||
@@ -922,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) {
 | 
			
		||||
@@ -936,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,
 | 
			
		||||
@@ -973,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)
 | 
			
		||||
{
 | 
			
		||||
@@ -991,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);
 | 
			
		||||
@@ -1005,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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -1058,21 +1093,31 @@ static void ril_data_settings_changed(struct ril_sim_settings *settings,
 | 
			
		||||
	ril_data_manager_check_network_mode(RIL_DATA(user_data)->priv->dm);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gint ril_data_compare_cb(gconstpointer a, gconstpointer b)
 | 
			
		||||
{
 | 
			
		||||
	const struct ril_data *d1 = a;
 | 
			
		||||
	const struct ril_data *d2 = b;
 | 
			
		||||
	const struct ril_data_priv *p1 = d1->priv;
 | 
			
		||||
	const struct ril_data_priv *p2 = d2->priv;
 | 
			
		||||
 | 
			
		||||
	return p1->slot < p2->slot ? (-1) : p1->slot > p2->slot ? 1 : 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct ril_data *ril_data_new(struct ril_data_manager *dm, const char *name,
 | 
			
		||||
		struct ril_radio *radio, struct ril_network *network,
 | 
			
		||||
		GRilIoChannel *io, const struct ril_data_options *options)
 | 
			
		||||
		GRilIoChannel *io, const struct ril_data_options *options,
 | 
			
		||||
		const struct ril_slot_config *config)
 | 
			
		||||
{
 | 
			
		||||
	GASSERT(dm);
 | 
			
		||||
	if (G_LIKELY(dm)) {
 | 
			
		||||
		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:
 | 
			
		||||
			/*
 | 
			
		||||
@@ -1080,13 +1125,15 @@ 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;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		priv->log_prefix = (name && name[0]) ?
 | 
			
		||||
			g_strconcat(name, " ", NULL) : g_strdup("");
 | 
			
		||||
 | 
			
		||||
		priv->slot = config->slot;
 | 
			
		||||
		priv->q = grilio_queue_new(io);
 | 
			
		||||
		priv->io = grilio_channel_ref(io);
 | 
			
		||||
		priv->dm = ril_data_manager_ref(dm);
 | 
			
		||||
@@ -1104,20 +1151,36 @@ 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);
 | 
			
		||||
 | 
			
		||||
		dm->data_list = g_slist_append(dm->data_list, self);
 | 
			
		||||
		/* Order data contexts according to slot numbers */
 | 
			
		||||
		dm->data_list = g_slist_insert_sorted(dm->data_list, self,
 | 
			
		||||
							ril_data_compare_cb);
 | 
			
		||||
		ril_data_manager_check_network_mode(dm);
 | 
			
		||||
		return self;
 | 
			
		||||
	}
 | 
			
		||||
	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)) {
 | 
			
		||||
@@ -1195,10 +1258,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.
 | 
			
		||||
@@ -1211,7 +1275,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)
 | 
			
		||||
@@ -1228,12 +1305,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);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
@@ -1287,13 +1359,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);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
@@ -1444,53 +1510,54 @@ static void ril_data_manager_check_network_mode(struct ril_data_manager *self)
 | 
			
		||||
	GSList *l;
 | 
			
		||||
 | 
			
		||||
	if (ril_data_manager_handover(self)) {
 | 
			
		||||
		gboolean need_fast_access = FALSE;
 | 
			
		||||
		struct ril_network *lte_network = NULL;
 | 
			
		||||
		int non_gsm_count = 0;
 | 
			
		||||
 | 
			
		||||
		/*
 | 
			
		||||
		 * Count number of SIMs for which GSM is selected
 | 
			
		||||
		 * Count number of SIMs for which non-GSM mode is selected
 | 
			
		||||
		 */
 | 
			
		||||
		for (l= self->data_list; l; l = l->next) {
 | 
			
		||||
			struct ril_data *data = l->data;
 | 
			
		||||
			struct ril_data_priv *priv = data->priv;
 | 
			
		||||
			struct ril_sim_settings *sim = priv->network->settings;
 | 
			
		||||
			struct ril_network *network = priv->network;
 | 
			
		||||
			struct ril_sim_settings *sim = network->settings;
 | 
			
		||||
 | 
			
		||||
			if (sim->pref_mode != OFONO_RADIO_ACCESS_MODE_GSM &&
 | 
			
		||||
							sim->imsi) {
 | 
			
		||||
			if (sim->pref_mode != OFONO_RADIO_ACCESS_MODE_GSM) {
 | 
			
		||||
				non_gsm_count++;
 | 
			
		||||
				if (priv->flags & RIL_DATA_FLAG_MAX_SPEED) {
 | 
			
		||||
					need_fast_access = TRUE;
 | 
			
		||||
				if ((priv->flags & RIL_DATA_FLAG_MAX_SPEED) &&
 | 
			
		||||
							!lte_network) {
 | 
			
		||||
					lte_network = network;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/*
 | 
			
		||||
		 * If the SIM selected for internet access has non-GSM mode
 | 
			
		||||
		 * enabled and non-GSM mode is enabled for more than one SIM,
 | 
			
		||||
		 * then we need to limit other SIMs to GSM. Otherwise, turn
 | 
			
		||||
		 * all limits off.
 | 
			
		||||
		 * If there's no SIM selected for internet access
 | 
			
		||||
		 * then choose the first slot for LTE.
 | 
			
		||||
		 */
 | 
			
		||||
		if (need_fast_access && non_gsm_count > 1) {
 | 
			
		||||
			for (l= self->data_list; l; l = l->next) {
 | 
			
		||||
				struct ril_data *data = l->data;
 | 
			
		||||
				struct ril_data_priv *priv = data->priv;
 | 
			
		||||
 | 
			
		||||
				ril_network_set_max_pref_mode(priv->network,
 | 
			
		||||
					(priv->flags & RIL_DATA_FLAG_MAX_SPEED) ?
 | 
			
		||||
						OFONO_RADIO_ACCESS_MODE_ANY :
 | 
			
		||||
						OFONO_RADIO_ACCESS_MODE_GSM,
 | 
			
		||||
								FALSE);
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			return;
 | 
			
		||||
		if (!lte_network) {
 | 
			
		||||
			struct ril_data *data = self->data_list->data;
 | 
			
		||||
			lte_network = data->priv->network;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Otherwise there's no reason to limit anything */
 | 
			
		||||
	for (l= self->data_list; l; l = l->next) {
 | 
			
		||||
		struct ril_data *data = l->data;
 | 
			
		||||
		ril_network_set_max_pref_mode(data->priv->network,
 | 
			
		||||
		for (l= self->data_list; l; l = l->next) {
 | 
			
		||||
			struct ril_data *data = l->data;
 | 
			
		||||
			struct ril_network *network = data->priv->network;
 | 
			
		||||
 | 
			
		||||
			ril_network_set_max_pref_mode(network,
 | 
			
		||||
					(network == lte_network) ?
 | 
			
		||||
					OFONO_RADIO_ACCESS_MODE_ANY :
 | 
			
		||||
					OFONO_RADIO_ACCESS_MODE_GSM,
 | 
			
		||||
					FALSE);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	} else {
 | 
			
		||||
		/* Otherwise there's no reason to limit anything */
 | 
			
		||||
		for (l= self->data_list; l; l = l->next) {
 | 
			
		||||
			struct ril_data *data = l->data;
 | 
			
		||||
			ril_network_set_max_pref_mode(data->priv->network,
 | 
			
		||||
					OFONO_RADIO_ACCESS_MODE_ANY, FALSE);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -1521,9 +1588,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));
 | 
			
		||||
@@ -1546,6 +1612,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,
 | 
			
		||||
@@ -94,10 +95,12 @@ typedef void (*ril_data_call_deactivate_cb_t)(struct ril_data *data,
 | 
			
		||||
 | 
			
		||||
struct ril_data *ril_data_new(struct ril_data_manager *dm, const char *name,
 | 
			
		||||
		struct ril_radio *radio, struct ril_network *network,
 | 
			
		||||
		GRilIoChannel *io, const struct ril_data_options *options);
 | 
			
		||||
		GRilIoChannel *io, const struct ril_data_options *options,
 | 
			
		||||
		const struct ril_slot_config *config);
 | 
			
		||||
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);
 | 
			
		||||
@@ -121,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,
 | 
			
		||||
@@ -311,6 +288,7 @@ static void ril_modem_post_sim(struct ofono_modem *modem)
 | 
			
		||||
	ofono_call_forwarding_create(modem, 0, RILMODEM_DRIVER, md);
 | 
			
		||||
	ofono_call_barring_create(modem, 0, RILMODEM_DRIVER, md);
 | 
			
		||||
	ofono_stk_create(modem, 0, RILMODEM_DRIVER, md);
 | 
			
		||||
	ofono_cbs_create(modem, 0, RILMODEM_DRIVER, md);
 | 
			
		||||
	ofono_message_waiting_register(ofono_message_waiting_create(modem));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -335,10 +313,6 @@ static void ril_modem_set_online(struct ofono_modem *modem, ofono_bool_t online,
 | 
			
		||||
	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);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (online) {
 | 
			
		||||
		ril_radio_power_on(md->modem.radio, RADIO_POWER_TAG(md));
 | 
			
		||||
		req = &md->set_online;
 | 
			
		||||
@@ -392,25 +366,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);
 | 
			
		||||
	}
 | 
			
		||||
@@ -432,18 +397,21 @@ static void ril_modem_remove(struct ofono_modem *ofono)
 | 
			
		||||
	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,
 | 
			
		||||
		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 ril_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;
 | 
			
		||||
@@ -454,14 +422,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("");
 | 
			
		||||
 | 
			
		||||
@@ -474,14 +442,10 @@ struct ril_modem *ril_modem_create(GRilIoChannel *io, const char *log_prefix,
 | 
			
		||||
		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) 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 "ril_util.h"
 | 
			
		||||
#include "ril_log.h"
 | 
			
		||||
 | 
			
		||||
#include "sailfish_watch.h"
 | 
			
		||||
 | 
			
		||||
#include <grilio_queue.h>
 | 
			
		||||
#include <grilio_request.h>
 | 
			
		||||
#include <grilio_parser.h>
 | 
			
		||||
@@ -41,18 +43,30 @@ enum ril_network_timer {
 | 
			
		||||
	TIMER_COUNT
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum ril_network_watch_events {
 | 
			
		||||
	WATCH_EVENT_ONLINE,
 | 
			
		||||
	WATCH_EVENT_COUNT
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum ril_network_radio_event {
 | 
			
		||||
	RADIO_EVENT_STATE_CHANGED,
 | 
			
		||||
	RADIO_EVENT_ONLINE_CHANGED,
 | 
			
		||||
	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;
 | 
			
		||||
	struct sailfish_watch *watch;
 | 
			
		||||
	gulong watch_event_id[WATCH_EVENT_COUNT];
 | 
			
		||||
	int rat;
 | 
			
		||||
	char *log_prefix;
 | 
			
		||||
	guint operator_poll_id;
 | 
			
		||||
@@ -61,11 +75,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 +88,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 };
 | 
			
		||||
 | 
			
		||||
@@ -420,13 +437,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 +467,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;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
@@ -467,7 +487,7 @@ static gboolean ril_network_can_set_pref_mode(struct ril_network *self)
 | 
			
		||||
{
 | 
			
		||||
	struct ril_network_priv *priv = self->priv;
 | 
			
		||||
 | 
			
		||||
	return priv->radio->online && ril_sim_card_ready(priv->sim_card);
 | 
			
		||||
	return priv->watch->online && ril_sim_card_ready(priv->sim_card);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gboolean ril_network_set_rat_holdoff_cb(gpointer user_data)
 | 
			
		||||
@@ -486,7 +506,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 +547,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 +577,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 +666,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 +713,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 +732,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 +742,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);
 | 
			
		||||
@@ -715,7 +762,7 @@ static void ril_network_radio_state_cb(struct ril_radio *radio, void *data)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void ril_network_radio_online_cb(struct ril_radio *radio, void *data)
 | 
			
		||||
static void ril_network_online_cb(struct sailfish_watch *watch, void *data)
 | 
			
		||||
{
 | 
			
		||||
	struct ril_network *self = RIL_NETWORK(data);
 | 
			
		||||
 | 
			
		||||
@@ -767,8 +814,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);
 | 
			
		||||
@@ -777,20 +825,26 @@ struct ril_network *ril_network_new(GRilIoChannel *io, const char *log_prefix,
 | 
			
		||||
	self->settings = ril_sim_settings_ref(settings);
 | 
			
		||||
	priv->io = grilio_channel_ref(io);
 | 
			
		||||
	priv->q = grilio_queue_new(priv->io);
 | 
			
		||||
	priv->watch = sailfish_watch_new(path);
 | 
			
		||||
	priv->radio = ril_radio_ref(radio);
 | 
			
		||||
	priv->sim_card = ril_sim_card_ref(sim_card);
 | 
			
		||||
	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);
 | 
			
		||||
	priv->radio_event_id[RADIO_EVENT_ONLINE_CHANGED] =
 | 
			
		||||
		ril_radio_add_online_changed_handler(priv->radio,
 | 
			
		||||
			ril_network_radio_online_cb, self);
 | 
			
		||||
	priv->watch_event_id[WATCH_EVENT_ONLINE] =
 | 
			
		||||
		sailfish_watch_add_modem_changed_handler(priv->watch,
 | 
			
		||||
			ril_network_online_cb, self);
 | 
			
		||||
	priv->settings_event_id =
 | 
			
		||||
		ril_sim_settings_add_pref_mode_changed_handler(settings,
 | 
			
		||||
			ril_network_pref_mode_changed_cb, self);
 | 
			
		||||
@@ -840,57 +894,46 @@ 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);
 | 
			
		||||
	sailfish_watch_remove_all_handlers(priv->watch, priv->watch_event_id);
 | 
			
		||||
	sailfish_watch_unref(priv->watch);
 | 
			
		||||
	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,31 +44,10 @@
 | 
			
		||||
 | 
			
		||||
#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;
 | 
			
		||||
@@ -80,63 +60,27 @@ struct ril_modem {
 | 
			
		||||
	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,
 | 
			
		||||
		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 ril_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 +88,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
 | 
			
		||||
@@ -50,14 +50,12 @@ struct ril_radio_priv {
 | 
			
		||||
 | 
			
		||||
enum ril_radio_signal {
 | 
			
		||||
	SIGNAL_STATE_CHANGED,
 | 
			
		||||
	SIGNAL_ONLINE_CHANGED,
 | 
			
		||||
	SIGNAL_COUNT
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#define POWER_RETRY_SECS (1)
 | 
			
		||||
 | 
			
		||||
#define SIGNAL_STATE_CHANGED_NAME       "ril-radio-state-changed"
 | 
			
		||||
#define SIGNAL_ONLINE_CHANGED_NAME      "ril-radio-online-changed"
 | 
			
		||||
 | 
			
		||||
static guint ril_radio_signals[SIGNAL_COUNT] = { 0 };
 | 
			
		||||
 | 
			
		||||
@@ -77,8 +75,7 @@ static inline gboolean ril_radio_power_should_be_on(struct ril_radio *self)
 | 
			
		||||
{
 | 
			
		||||
	struct ril_radio_priv *priv = self->priv;
 | 
			
		||||
 | 
			
		||||
	return self->online && !priv->power_cycle &&
 | 
			
		||||
				g_hash_table_size(priv->req_table) > 0;
 | 
			
		||||
	return !priv->power_cycle && g_hash_table_size(priv->req_table) > 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline gboolean ril_radio_state_off(enum ril_radio_state radio_state)
 | 
			
		||||
@@ -99,13 +96,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 +124,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 +155,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 +175,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 +193,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);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -274,19 +280,6 @@ void ril_radio_power_off(struct ril_radio *self, gpointer tag)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ril_radio_set_online(struct ril_radio *self, gboolean online)
 | 
			
		||||
{
 | 
			
		||||
	if (G_LIKELY(self) && self->online != online) {
 | 
			
		||||
		gboolean on, was_on = ril_radio_power_should_be_on(self);
 | 
			
		||||
		self->online = online;
 | 
			
		||||
		on = ril_radio_power_should_be_on(self);
 | 
			
		||||
		if (was_on != on) {
 | 
			
		||||
			ril_radio_power_request(self, on, FALSE);
 | 
			
		||||
		}
 | 
			
		||||
		ril_radio_emit_signal(self, SIGNAL_ONLINE_CHANGED);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
gulong ril_radio_add_state_changed_handler(struct ril_radio *self,
 | 
			
		||||
					ril_radio_cb_t cb, void *arg)
 | 
			
		||||
{
 | 
			
		||||
@@ -294,13 +287,6 @@ gulong ril_radio_add_state_changed_handler(struct ril_radio *self,
 | 
			
		||||
		SIGNAL_STATE_CHANGED_NAME, G_CALLBACK(cb), arg) : 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
gulong ril_radio_add_online_changed_handler(struct ril_radio *self,
 | 
			
		||||
					ril_radio_cb_t cb, void *arg)
 | 
			
		||||
{
 | 
			
		||||
	return (G_LIKELY(self) && G_LIKELY(cb)) ? g_signal_connect(self,
 | 
			
		||||
		SIGNAL_ONLINE_CHANGED_NAME, G_CALLBACK(cb), arg) : 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ril_radio_remove_handler(struct ril_radio *self, gulong id)
 | 
			
		||||
{
 | 
			
		||||
	if (G_LIKELY(self) && G_LIKELY(id)) {
 | 
			
		||||
@@ -330,7 +316,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);
 | 
			
		||||
@@ -438,7 +424,6 @@ static void ril_radio_class_init(RilRadioClass *klass)
 | 
			
		||||
	object_class->finalize = ril_radio_finalize;
 | 
			
		||||
	g_type_class_add_private(klass, sizeof(struct ril_radio_priv));
 | 
			
		||||
	NEW_SIGNAL(klass, STATE);
 | 
			
		||||
	NEW_SIGNAL(klass, ONLINE);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 
 | 
			
		||||
@@ -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,7 +22,6 @@ struct ril_radio {
 | 
			
		||||
	GObject object;
 | 
			
		||||
	struct ril_radio_priv *priv;
 | 
			
		||||
	enum ril_radio_state state;
 | 
			
		||||
	gboolean online;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
typedef void (*ril_radio_cb_t)(struct ril_radio *radio, void *arg);
 | 
			
		||||
@@ -35,15 +34,15 @@ void ril_radio_power_on(struct ril_radio *radio, gpointer tag);
 | 
			
		||||
void ril_radio_power_off(struct ril_radio *radio, gpointer tag);
 | 
			
		||||
void ril_radio_power_cycle(struct ril_radio *radio);
 | 
			
		||||
void ril_radio_confirm_power_on(struct ril_radio *radio);
 | 
			
		||||
void ril_radio_set_online(struct ril_radio *radio, gboolean online);
 | 
			
		||||
gulong ril_radio_add_state_changed_handler(struct ril_radio *radio,
 | 
			
		||||
					ril_radio_cb_t cb, void *arg);
 | 
			
		||||
gulong ril_radio_add_online_changed_handler(struct ril_radio *radio,
 | 
			
		||||
					ril_radio_cb_t cb, void *arg);
 | 
			
		||||
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 */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										1407
									
								
								ofono/drivers/ril/ril_radio_caps.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1407
									
								
								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,21 +423,13 @@ static void ril_sim_file_info_cb(GRilIoChannel *io, int status,
 | 
			
		||||
	struct ofono_error error;
 | 
			
		||||
 | 
			
		||||
	DBG_(sd, "");
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * In case sim card has been removed prior to this callback has been
 | 
			
		||||
	 * called we must not call the core call back method as otherwise the
 | 
			
		||||
	 * core will crash.
 | 
			
		||||
	 */
 | 
			
		||||
	if (!sd->inserted) {
 | 
			
		||||
		ofono_error("No SIM card");
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
	ril_sim_card_sim_io_finished(sd->card, cbd->req_id);
 | 
			
		||||
 | 
			
		||||
	ril_error_init_failure(&error);
 | 
			
		||||
	res = ril_sim_parse_io_response(data, len);
 | 
			
		||||
	if (ril_sim_io_response_ok(res) && status == RIL_E_SUCCESS) {
 | 
			
		||||
	if (!sd->inserted) {
 | 
			
		||||
		DBG_(sd, "No SIM card");
 | 
			
		||||
	} else if (ril_sim_io_response_ok(res) && status == RIL_E_SUCCESS) {
 | 
			
		||||
		gboolean ok = FALSE;
 | 
			
		||||
		guchar access[3] = { 0x00, 0x00, 0x00 };
 | 
			
		||||
		guchar file_status = EF_STATUS_VALID;
 | 
			
		||||
@@ -447,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);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -470,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);
 | 
			
		||||
@@ -523,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);
 | 
			
		||||
@@ -583,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;
 | 
			
		||||
@@ -607,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
 | 
			
		||||
@@ -619,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);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -700,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;
 | 
			
		||||
@@ -718,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;
 | 
			
		||||
@@ -727,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;
 | 
			
		||||
 | 
			
		||||
@@ -739,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");
 | 
			
		||||
@@ -773,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;
 | 
			
		||||
@@ -790,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 {
 | 
			
		||||
@@ -854,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)
 | 
			
		||||
@@ -908,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)
 | 
			
		||||
@@ -980,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))) {
 | 
			
		||||
@@ -1023,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;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -1030,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,
 | 
			
		||||
@@ -1109,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,
 | 
			
		||||
@@ -1146,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,
 | 
			
		||||
@@ -1167,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,
 | 
			
		||||
@@ -1191,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;
 | 
			
		||||
@@ -1212,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);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -1238,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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -1289,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"
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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"
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -35,6 +35,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 +78,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 +117,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 +159,20 @@ 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
 | 
			
		||||
 
 | 
			
		||||
@@ -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,20 @@ 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
 | 
			
		||||
@@ -48,7 +48,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 +58,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;
 | 
			
		||||
 
 | 
			
		||||
@@ -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,7 +304,7 @@ 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) {
 | 
			
		||||
				reason = OFONO_DISCONNECT_REASON_REMOTE_HANGUP;
 | 
			
		||||
@@ -250,6 +314,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 +350,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 +362,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 +432,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 +451,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 +549,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 +665,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 +734,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 +760,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 +833,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 +870,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 +884,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 +906,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 +915,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 +929,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,
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										213
									
								
								ofono/drivers/rilmodem/cbs.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										213
									
								
								ofono/drivers/rilmodem/cbs.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,213 @@
 | 
			
		||||
/*
 | 
			
		||||
 *
 | 
			
		||||
 *  oFono - Open Source Telephony
 | 
			
		||||
 *
 | 
			
		||||
 *  Copyright (C) 2008-2016  Intel Corporation. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 *  This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 *  it under the terms of the GNU General Public License version 2 as
 | 
			
		||||
 *  published by the Free Software Foundation.
 | 
			
		||||
 *
 | 
			
		||||
 *  This program is distributed in the hope that it will be useful,
 | 
			
		||||
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 *  GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 *  You should have received a copy of the GNU General Public License
 | 
			
		||||
 *  along with this program; if not, write to the Free Software
 | 
			
		||||
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_CONFIG_H
 | 
			
		||||
#include <config.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#define _GNU_SOURCE
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <ctype.h>
 | 
			
		||||
 | 
			
		||||
#include <glib.h>
 | 
			
		||||
 | 
			
		||||
#include <ofono/log.h>
 | 
			
		||||
#include <ofono/modem.h>
 | 
			
		||||
#include <ofono/cbs.h>
 | 
			
		||||
#include "util.h"
 | 
			
		||||
 | 
			
		||||
#include <gril.h>
 | 
			
		||||
#include <parcel.h>
 | 
			
		||||
 | 
			
		||||
#include "rilmodem.h"
 | 
			
		||||
#include "vendor.h"
 | 
			
		||||
 | 
			
		||||
struct cbs_data {
 | 
			
		||||
	GRil *ril;
 | 
			
		||||
	unsigned int vendor;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void ril_cbs_set_cb(struct ril_msg *message, gpointer user_data)
 | 
			
		||||
{
 | 
			
		||||
	struct cb_data *cbd = user_data;
 | 
			
		||||
	ofono_cbs_set_cb_t cb = cbd->cb;
 | 
			
		||||
	struct cbs_data *cd = cbd->user;
 | 
			
		||||
 | 
			
		||||
	if (message->error == RIL_E_SUCCESS) {
 | 
			
		||||
		CALLBACK_WITH_SUCCESS(cb, cbd->data);
 | 
			
		||||
	} else {
 | 
			
		||||
		ofono_error("%s RILD reply failure: %s",
 | 
			
		||||
			g_ril_request_id_to_string(cd->ril, message->req),
 | 
			
		||||
			ril_error_to_string(message->error));
 | 
			
		||||
		CALLBACK_WITH_FAILURE(cb, cbd->data);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void ril_cbs_set_topics(struct ofono_cbs *cbs, const char *topics,
 | 
			
		||||
					ofono_cbs_set_cb_t cb, void *user_data)
 | 
			
		||||
{
 | 
			
		||||
	struct cbs_data *cd = ofono_cbs_get_data(cbs);
 | 
			
		||||
	struct cb_data *cbd = cb_data_new(cb, user_data, cd);
 | 
			
		||||
	int i = 0, from, to;
 | 
			
		||||
	const char *p, *pto;
 | 
			
		||||
	char **segments;
 | 
			
		||||
	struct parcel rilp;
 | 
			
		||||
 | 
			
		||||
	segments = g_strsplit(topics, ",", 0);
 | 
			
		||||
 | 
			
		||||
	while (segments[i])
 | 
			
		||||
		i++;
 | 
			
		||||
 | 
			
		||||
	parcel_init(&rilp);
 | 
			
		||||
	parcel_w_int32(&rilp, i);
 | 
			
		||||
 | 
			
		||||
	i = 0;
 | 
			
		||||
	while (segments[i]) {
 | 
			
		||||
		p = segments[i++];
 | 
			
		||||
		from = atoi(p);
 | 
			
		||||
		to = from;
 | 
			
		||||
 | 
			
		||||
		pto = strchr(p, '-');
 | 
			
		||||
		if (pto)
 | 
			
		||||
			to = atoi(pto + 1);
 | 
			
		||||
 | 
			
		||||
		parcel_w_int32(&rilp, from);
 | 
			
		||||
		parcel_w_int32(&rilp, to);
 | 
			
		||||
 | 
			
		||||
		parcel_w_int32(&rilp, 0);
 | 
			
		||||
		parcel_w_int32(&rilp, 0xFF);
 | 
			
		||||
 | 
			
		||||
		parcel_w_int32(&rilp, 1);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	g_strfreev(segments);
 | 
			
		||||
 | 
			
		||||
	if (g_ril_send(cd->ril, RIL_REQUEST_GSM_SET_BROADCAST_SMS_CONFIG, &rilp,
 | 
			
		||||
			ril_cbs_set_cb, cbd, g_free) > 0)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	g_free(cbd);
 | 
			
		||||
	CALLBACK_WITH_FAILURE(cb, user_data);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void ril_cbs_clear_topics(struct ofono_cbs *cbs,
 | 
			
		||||
					ofono_cbs_set_cb_t cb, void *user_data)
 | 
			
		||||
{
 | 
			
		||||
	ril_cbs_set_topics(cbs, "", cb, user_data);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void ril_cbs_received(struct ril_msg *message, gpointer user_data)
 | 
			
		||||
{
 | 
			
		||||
	struct ofono_cbs *cbs = user_data;
 | 
			
		||||
	struct cbs_data *cd = ofono_cbs_get_data(cbs);
 | 
			
		||||
	struct parcel rilp;
 | 
			
		||||
	int pdulen;
 | 
			
		||||
	unsigned char *pdu;
 | 
			
		||||
 | 
			
		||||
	g_ril_print_unsol_no_args(cd->ril, message);
 | 
			
		||||
 | 
			
		||||
	DBG("req: %d; data_len: %d", message->req, (int) message->buf_len);
 | 
			
		||||
 | 
			
		||||
	g_ril_init_parcel(message, &rilp);
 | 
			
		||||
	pdu = parcel_r_raw(&rilp, &pdulen);
 | 
			
		||||
 | 
			
		||||
	if (!pdu || pdulen != 88) {
 | 
			
		||||
		ofono_error("%s: it isn't a gsm cell broadcast msg", __func__);
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ofono_cbs_notify(cbs, pdu, pdulen);
 | 
			
		||||
	g_free(pdu);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void ril_cbs_register(const struct ofono_error *error, void *data)
 | 
			
		||||
{
 | 
			
		||||
	struct ofono_cbs *cbs = data;
 | 
			
		||||
	struct cbs_data *cd = ofono_cbs_get_data(cbs);
 | 
			
		||||
 | 
			
		||||
	g_ril_register(cd->ril, RIL_UNSOL_RESPONSE_NEW_BROADCAST_SMS,
 | 
			
		||||
					ril_cbs_received, cbs);
 | 
			
		||||
 | 
			
		||||
	ofono_cbs_register(cbs);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void get_cbs_config_cb(struct ril_msg *message,
 | 
			
		||||
					gpointer user_data)
 | 
			
		||||
{
 | 
			
		||||
	struct ofono_cbs *cbs = user_data;
 | 
			
		||||
 | 
			
		||||
	if (message->error != RIL_E_SUCCESS) {
 | 
			
		||||
		ofono_error("%s: RIL error %s", __func__,
 | 
			
		||||
				ril_error_to_string(message->error));
 | 
			
		||||
		ofono_cbs_remove(cbs);
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ril_cbs_clear_topics(cbs, ril_cbs_register, cbs);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int ril_cbs_probe(struct ofono_cbs *cbs, unsigned int vendor,
 | 
			
		||||
				void *user)
 | 
			
		||||
{
 | 
			
		||||
	GRil *ril = user;
 | 
			
		||||
	struct cbs_data *data;
 | 
			
		||||
 | 
			
		||||
	data = g_new0(struct cbs_data, 1);
 | 
			
		||||
	data->ril = g_ril_clone(ril);
 | 
			
		||||
	data->vendor = vendor;
 | 
			
		||||
 | 
			
		||||
	ofono_cbs_set_data(cbs, data);
 | 
			
		||||
 | 
			
		||||
	if (g_ril_send(ril, RIL_REQUEST_GSM_GET_BROADCAST_SMS_CONFIG, NULL,
 | 
			
		||||
			get_cbs_config_cb, cbs, NULL) == 0)
 | 
			
		||||
		ofono_error("%s: send failed", __func__);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void ril_cbs_remove(struct ofono_cbs *cbs)
 | 
			
		||||
{
 | 
			
		||||
	struct cbs_data *data = ofono_cbs_get_data(cbs);
 | 
			
		||||
 | 
			
		||||
	ofono_cbs_set_data(cbs, NULL);
 | 
			
		||||
 | 
			
		||||
	g_ril_unref(data->ril);
 | 
			
		||||
	g_free(data);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct ofono_cbs_driver driver = {
 | 
			
		||||
	.name = RILMODEM,
 | 
			
		||||
	.probe = ril_cbs_probe,
 | 
			
		||||
	.remove = ril_cbs_remove,
 | 
			
		||||
	.set_topics = ril_cbs_set_topics,
 | 
			
		||||
	.clear_topics = ril_cbs_clear_topics,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
void ril_cbs_init(void)
 | 
			
		||||
{
 | 
			
		||||
	ofono_cbs_driver_register(&driver);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ril_cbs_exit(void)
 | 
			
		||||
{
 | 
			
		||||
	ofono_cbs_driver_unregister(&driver);
 | 
			
		||||
}
 | 
			
		||||
@@ -198,6 +198,7 @@ static void ril_rat_mode_cb(struct ril_msg *message, gpointer user_data)
 | 
			
		||||
	 * capabilities, so it is sort of the default for MTK modems.
 | 
			
		||||
	 */
 | 
			
		||||
	switch (net_type) {
 | 
			
		||||
	case PREF_NET_TYPE_WCDMA:
 | 
			
		||||
	case PREF_NET_TYPE_GSM_WCDMA:
 | 
			
		||||
	case PREF_NET_TYPE_GSM_WCDMA_AUTO:
 | 
			
		||||
		mode = OFONO_RADIO_ACCESS_MODE_UMTS;
 | 
			
		||||
 
 | 
			
		||||
@@ -53,6 +53,7 @@ static int rilmodem_init(void)
 | 
			
		||||
	ril_call_barring_init();
 | 
			
		||||
	ril_netmon_init();
 | 
			
		||||
	ril_stk_init();
 | 
			
		||||
	ril_cbs_init();
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
@@ -76,6 +77,7 @@ static void rilmodem_exit(void)
 | 
			
		||||
	ril_call_barring_exit();
 | 
			
		||||
	ril_netmon_exit();
 | 
			
		||||
	ril_stk_exit();
 | 
			
		||||
	ril_cbs_exit();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
OFONO_PLUGIN_DEFINE(rilmodem, "RIL modem driver", VERSION,
 | 
			
		||||
 
 | 
			
		||||
@@ -75,3 +75,6 @@ extern void ril_netmon_exit(void);
 | 
			
		||||
 | 
			
		||||
extern void ril_stk_init(void);
 | 
			
		||||
extern void ril_stk_exit(void);
 | 
			
		||||
 | 
			
		||||
extern void ril_cbs_init(void);
 | 
			
		||||
extern void ril_cbs_exit(void);
 | 
			
		||||
 
 | 
			
		||||
@@ -79,7 +79,7 @@
 | 
			
		||||
 * The same applies to the app_type.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
static void ril_pin_change_state(struct ofono_sim *sim,
 | 
			
		||||
static void ril_set_facility_lock(struct ofono_sim *sim,
 | 
			
		||||
				enum ofono_sim_password_type passwd_type,
 | 
			
		||||
				int enable, const char *passwd,
 | 
			
		||||
				ofono_sim_lock_unlock_cb_t cb, void *data);
 | 
			
		||||
@@ -1083,7 +1083,7 @@ static void ril_query_passwd_state(struct ofono_sim *sim,
 | 
			
		||||
		CALLBACK_WITH_SUCCESS(cb, sd->passwd_state, data);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void ril_pin_change_state_cb(struct ril_msg *message, gpointer user_data)
 | 
			
		||||
static void ril_enter_sim_pin_cb(struct ril_msg *message, gpointer user_data)
 | 
			
		||||
{
 | 
			
		||||
	struct cb_data *cbd = user_data;
 | 
			
		||||
	ofono_sim_lock_unlock_cb_t cb = cbd->cb;
 | 
			
		||||
@@ -1101,36 +1101,17 @@ static void ril_pin_change_state_cb(struct ril_msg *message, gpointer user_data)
 | 
			
		||||
 | 
			
		||||
	g_ril_init_parcel(message, &rilp);
 | 
			
		||||
 | 
			
		||||
	/* maguro/infineon: no data is returned */
 | 
			
		||||
	if (parcel_data_avail(&rilp) == 0)
 | 
			
		||||
		goto done;
 | 
			
		||||
 | 
			
		||||
	parcel_r_int32(&rilp);
 | 
			
		||||
 | 
			
		||||
	switch (g_ril_vendor(sd->ril)) {
 | 
			
		||||
	case OFONO_RIL_VENDOR_AOSP:
 | 
			
		||||
	case OFONO_RIL_VENDOR_QCOM_MSIM:
 | 
			
		||||
		/*
 | 
			
		||||
		 * The number of retries is valid only when a wrong password has
 | 
			
		||||
		 * been introduced in Nexus 4. TODO: check Nexus 5 behaviour.
 | 
			
		||||
		 */
 | 
			
		||||
		if (message->error == RIL_E_PASSWORD_INCORRECT)
 | 
			
		||||
			sd->retries[sd->passwd_type] = parcel_r_int32(&rilp);
 | 
			
		||||
	if (message->error == RIL_E_SUCCESS)
 | 
			
		||||
		sd->retries[sd->passwd_type] = -1;
 | 
			
		||||
	else
 | 
			
		||||
		sd->retries[sd->passwd_type] = parcel_r_int32(&rilp);
 | 
			
		||||
 | 
			
		||||
		g_ril_append_print_buf(sd->ril, "{%d}",
 | 
			
		||||
					sd->retries[sd->passwd_type]);
 | 
			
		||||
		g_ril_print_response(sd->ril, message);
 | 
			
		||||
	g_ril_append_print_buf(sd->ril, "{%d}",
 | 
			
		||||
				sd->retries[sd->passwd_type]);
 | 
			
		||||
	g_ril_print_response(sd->ril, message);
 | 
			
		||||
 | 
			
		||||
		break;
 | 
			
		||||
	/* Taken care of elsewhere */
 | 
			
		||||
	case OFONO_RIL_VENDOR_INFINEON:
 | 
			
		||||
	case OFONO_RIL_VENDOR_MTK:
 | 
			
		||||
		break;
 | 
			
		||||
	default:
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
done:
 | 
			
		||||
	if (message->error == RIL_E_SUCCESS) {
 | 
			
		||||
		CALLBACK_WITH_SUCCESS(cb, cbd->data);
 | 
			
		||||
		return;
 | 
			
		||||
@@ -1167,30 +1148,13 @@ static void ril_pin_send(struct ofono_sim *sim, const char *passwd,
 | 
			
		||||
	g_ril_append_print_buf(sd->ril, "(%s,aid=%s)", passwd, sd->aid_str);
 | 
			
		||||
 | 
			
		||||
	if (g_ril_send(sd->ril, RIL_REQUEST_ENTER_SIM_PIN, &rilp,
 | 
			
		||||
			ril_pin_change_state_cb, cbd, g_free) > 0)
 | 
			
		||||
			ril_enter_sim_pin_cb, cbd, g_free) > 0)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	g_free(cbd);
 | 
			
		||||
	CALLBACK_WITH_FAILURE(cb, data);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void enter_pin_done(const struct ofono_error *error, void *data)
 | 
			
		||||
{
 | 
			
		||||
	struct change_state_cbd *csd = data;
 | 
			
		||||
	struct sim_data *sd = ofono_sim_get_data(csd->sim);
 | 
			
		||||
 | 
			
		||||
	if (error->type != OFONO_ERROR_TYPE_NO_ERROR) {
 | 
			
		||||
		ofono_error("%s: wrong password", __func__);
 | 
			
		||||
		sd->unlock_pending = FALSE;
 | 
			
		||||
		CALLBACK_WITH_FAILURE(csd->cb, csd->data);
 | 
			
		||||
	} else {
 | 
			
		||||
		ril_pin_change_state(csd->sim, csd->passwd_type, csd->enable,
 | 
			
		||||
					csd->passwd, csd->cb, csd->data);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	g_free(csd);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const char *const clck_cpwd_fac[] = {
 | 
			
		||||
	[OFONO_SIM_PASSWORD_SIM_PIN] = "SC",
 | 
			
		||||
	[OFONO_SIM_PASSWORD_SIM_PIN2] = "P2",
 | 
			
		||||
@@ -1204,7 +1168,45 @@ static const char *const clck_cpwd_fac[] = {
 | 
			
		||||
 | 
			
		||||
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
 | 
			
		||||
 | 
			
		||||
static void ril_pin_change_state(struct ofono_sim *sim,
 | 
			
		||||
static void ril_set_facility_lock_cb(struct ril_msg *message,
 | 
			
		||||
							gpointer user_data)
 | 
			
		||||
{
 | 
			
		||||
	struct cb_data *cbd = user_data;
 | 
			
		||||
	ofono_sim_lock_unlock_cb_t cb = cbd->cb;
 | 
			
		||||
	struct ofono_sim *sim = cbd->user;
 | 
			
		||||
	struct sim_data *sd = ofono_sim_get_data(sim);
 | 
			
		||||
	struct parcel rilp;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * There is no reason to ask SIM status until
 | 
			
		||||
	 * unsolicited sim status change indication
 | 
			
		||||
	 * Looks like state does not change before that.
 | 
			
		||||
	 */
 | 
			
		||||
	DBG("Enter password: type %d, result %d",
 | 
			
		||||
				sd->passwd_type, message->error);
 | 
			
		||||
 | 
			
		||||
	g_ril_init_parcel(message, &rilp);
 | 
			
		||||
 | 
			
		||||
	parcel_r_int32(&rilp);
 | 
			
		||||
 | 
			
		||||
	if (message->error == RIL_E_SUCCESS)
 | 
			
		||||
		sd->retries[sd->passwd_type] = -1;
 | 
			
		||||
	else
 | 
			
		||||
		sd->retries[sd->passwd_type] = parcel_r_int32(&rilp);
 | 
			
		||||
 | 
			
		||||
	g_ril_append_print_buf(sd->ril, "{%d}",
 | 
			
		||||
				sd->retries[sd->passwd_type]);
 | 
			
		||||
	g_ril_print_response(sd->ril, message);
 | 
			
		||||
 | 
			
		||||
	if (message->error == RIL_E_SUCCESS) {
 | 
			
		||||
		CALLBACK_WITH_SUCCESS(cb, cbd->data);
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	CALLBACK_WITH_FAILURE(cb, cbd->data);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void ril_set_facility_lock(struct ofono_sim *sim,
 | 
			
		||||
				enum ofono_sim_password_type passwd_type,
 | 
			
		||||
				int enable, const char *passwd,
 | 
			
		||||
				ofono_sim_lock_unlock_cb_t cb, void *data)
 | 
			
		||||
@@ -1213,29 +1215,8 @@ static void ril_pin_change_state(struct ofono_sim *sim,
 | 
			
		||||
	struct cb_data *cbd;
 | 
			
		||||
	struct parcel rilp;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * If we want to unlock a password that has not been entered yet,
 | 
			
		||||
	 * we enter it before trying to unlock. We need sd->unlock_pending as
 | 
			
		||||
	 * the password still has not yet been refreshed when this function is
 | 
			
		||||
	 * called from enter_pin_done().
 | 
			
		||||
	 */
 | 
			
		||||
	if (ofono_sim_get_password_type(sim) == passwd_type
 | 
			
		||||
			&& enable == FALSE && sd->unlock_pending == FALSE) {
 | 
			
		||||
		struct change_state_cbd *csd = g_malloc0(sizeof(*csd));
 | 
			
		||||
		csd->sim = sim;
 | 
			
		||||
		csd->passwd_type = passwd_type;
 | 
			
		||||
		csd->enable = enable;
 | 
			
		||||
		csd->passwd = passwd;
 | 
			
		||||
		csd->cb = cb;
 | 
			
		||||
		csd->data = data;
 | 
			
		||||
		sd->unlock_pending = TRUE;
 | 
			
		||||
 | 
			
		||||
		ril_pin_send(sim, passwd, enter_pin_done, csd);
 | 
			
		||||
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	sd->unlock_pending = FALSE;
 | 
			
		||||
	sd->passwd_type = passwd_type;
 | 
			
		||||
 | 
			
		||||
	if (passwd_type >= ARRAY_SIZE(clck_cpwd_fac) ||
 | 
			
		||||
			clck_cpwd_fac[passwd_type] == NULL)
 | 
			
		||||
@@ -1257,7 +1238,7 @@ static void ril_pin_change_state(struct ofono_sim *sim,
 | 
			
		||||
				sd->aid_str);
 | 
			
		||||
 | 
			
		||||
	if (g_ril_send(sd->ril, RIL_REQUEST_SET_FACILITY_LOCK, &rilp,
 | 
			
		||||
				ril_pin_change_state_cb, cbd, g_free) > 0)
 | 
			
		||||
				ril_set_facility_lock_cb, cbd, g_free) > 0)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	g_free(cbd);
 | 
			
		||||
@@ -1265,6 +1246,37 @@ error:
 | 
			
		||||
	CALLBACK_WITH_FAILURE(cb, data);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void ril_enter_sim_puk_cb(struct ril_msg *message, gpointer user_data)
 | 
			
		||||
{
 | 
			
		||||
	struct cb_data *cbd = user_data;
 | 
			
		||||
	ofono_sim_lock_unlock_cb_t cb = cbd->cb;
 | 
			
		||||
	struct ofono_sim *sim = cbd->user;
 | 
			
		||||
	struct sim_data *sd = ofono_sim_get_data(sim);
 | 
			
		||||
	struct parcel rilp;
 | 
			
		||||
 | 
			
		||||
	g_ril_init_parcel(message, &rilp);
 | 
			
		||||
 | 
			
		||||
	parcel_r_int32(&rilp);
 | 
			
		||||
 | 
			
		||||
	if (message->error != RIL_E_SUCCESS) {
 | 
			
		||||
		sd->retries[OFONO_SIM_PASSWORD_SIM_PUK] = parcel_r_int32(&rilp);
 | 
			
		||||
	} else {
 | 
			
		||||
		sd->retries[OFONO_SIM_PASSWORD_SIM_PIN] = -1;
 | 
			
		||||
		sd->retries[OFONO_SIM_PASSWORD_SIM_PUK] = -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	g_ril_append_print_buf(sd->ril, "{%d}",
 | 
			
		||||
				sd->retries[OFONO_SIM_PASSWORD_SIM_PUK]);
 | 
			
		||||
	g_ril_print_response(sd->ril, message);
 | 
			
		||||
 | 
			
		||||
	if (message->error == RIL_E_SUCCESS) {
 | 
			
		||||
		CALLBACK_WITH_SUCCESS(cb, cbd->data);
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	CALLBACK_WITH_FAILURE(cb, cbd->data);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void ril_pin_send_puk(struct ofono_sim *sim,
 | 
			
		||||
				const char *puk, const char *passwd,
 | 
			
		||||
				ofono_sim_lock_unlock_cb_t cb, void *data)
 | 
			
		||||
@@ -1286,7 +1298,7 @@ static void ril_pin_send_puk(struct ofono_sim *sim,
 | 
			
		||||
				puk, passwd, sd->aid_str);
 | 
			
		||||
 | 
			
		||||
	if (g_ril_send(sd->ril, RIL_REQUEST_ENTER_SIM_PUK, &rilp,
 | 
			
		||||
			ril_pin_change_state_cb, cbd, g_free) > 0)
 | 
			
		||||
			ril_enter_sim_puk_cb, cbd, g_free) > 0)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	g_free(cbd);
 | 
			
		||||
@@ -1324,7 +1336,7 @@ static void ril_change_passwd(struct ofono_sim *sim,
 | 
			
		||||
	g_ril_append_print_buf(sd->ril, "(old=%s,new=%s,aid=%s)",
 | 
			
		||||
				old_passwd, new_passwd, sd->aid_str);
 | 
			
		||||
 | 
			
		||||
	if (g_ril_send(sd->ril, request, &rilp, ril_pin_change_state_cb,
 | 
			
		||||
	if (g_ril_send(sd->ril, request, &rilp, ril_enter_sim_pin_cb,
 | 
			
		||||
			cbd, g_free) > 0)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
@@ -1413,12 +1425,17 @@ static void ril_query_facility_lock_cb(struct ril_msg *message,
 | 
			
		||||
	struct sim_data *sd = cbd->user;
 | 
			
		||||
	struct parcel rilp;
 | 
			
		||||
	ofono_bool_t status;
 | 
			
		||||
	int numparams;
 | 
			
		||||
 | 
			
		||||
	if (message->error != RIL_E_SUCCESS)
 | 
			
		||||
		goto error;
 | 
			
		||||
 | 
			
		||||
	g_ril_init_parcel(message, &rilp);
 | 
			
		||||
 | 
			
		||||
	numparams = parcel_r_int32(&rilp);
 | 
			
		||||
	if (numparams < 1)
 | 
			
		||||
		goto error;
 | 
			
		||||
 | 
			
		||||
	status = (ofono_bool_t) parcel_r_int32(&rilp);
 | 
			
		||||
 | 
			
		||||
	g_ril_append_print_buf(sd->ril, "{%d}", status);
 | 
			
		||||
@@ -1437,7 +1454,7 @@ static void ril_query_facility_lock(struct ofono_sim *sim,
 | 
			
		||||
					void *data)
 | 
			
		||||
{
 | 
			
		||||
	struct sim_data *sd = ofono_sim_get_data(sim);
 | 
			
		||||
	struct cb_data *cbd = cb_data_new(cb, data, sim);
 | 
			
		||||
	struct cb_data *cbd = cb_data_new(cb, data, sd);
 | 
			
		||||
	struct parcel rilp;
 | 
			
		||||
 | 
			
		||||
	parcel_init(&rilp);
 | 
			
		||||
@@ -1483,7 +1500,7 @@ static struct ofono_sim_driver driver = {
 | 
			
		||||
	.query_pin_retries	= ril_query_pin_retries,
 | 
			
		||||
	.reset_passwd		= ril_pin_send_puk,
 | 
			
		||||
	.change_passwd		= ril_change_passwd,
 | 
			
		||||
	.lock			= ril_pin_change_state,
 | 
			
		||||
	.lock			= ril_set_facility_lock,
 | 
			
		||||
	.query_facility_lock    = ril_query_facility_lock,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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;
 | 
			
		||||
 
 | 
			
		||||
@@ -598,6 +598,13 @@ void g_at_mux_unref(GAtMux *mux)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void read_watcher_destroy_notify(gpointer user_data)
 | 
			
		||||
{
 | 
			
		||||
	GAtMux *mux = user_data;
 | 
			
		||||
 | 
			
		||||
	mux->read_watch = 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
gboolean g_at_mux_start(GAtMux *mux)
 | 
			
		||||
{
 | 
			
		||||
	if (mux->channel == NULL)
 | 
			
		||||
@@ -611,7 +618,8 @@ gboolean g_at_mux_start(GAtMux *mux)
 | 
			
		||||
 | 
			
		||||
	mux->read_watch = g_io_add_watch_full(mux->channel, G_PRIORITY_DEFAULT,
 | 
			
		||||
				G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
 | 
			
		||||
						received_data, mux, NULL);
 | 
			
		||||
						received_data, mux,
 | 
			
		||||
						read_watcher_destroy_notify);
 | 
			
		||||
 | 
			
		||||
	mux->shutdown = FALSE;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -374,6 +374,12 @@ static void handle_response(struct ril_s *p, struct ril_msg *message)
 | 
			
		||||
			if (req->callback)
 | 
			
		||||
				req->callback(message, req->user_data);
 | 
			
		||||
 | 
			
		||||
			/* gril may have been destroyed in the request callback */
 | 
			
		||||
			if (p->destroyed) {
 | 
			
		||||
				ril_request_destroy(req);
 | 
			
		||||
				return;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			len = g_queue_get_length(p->out_queue);
 | 
			
		||||
 | 
			
		||||
			for (i = 0; i < len; i++) {
 | 
			
		||||
 
 | 
			
		||||
@@ -75,7 +75,8 @@ extern char print_buf[];
 | 
			
		||||
#define g_ril_print_request(gril, token, req)				\
 | 
			
		||||
	G_RIL_TRACE(gril, "[%d,%04d]> %s %s",				\
 | 
			
		||||
		g_ril_get_slot(gril), token,				\
 | 
			
		||||
		g_ril_request_id_to_string(gril, req), print_buf)
 | 
			
		||||
		g_ril_request_id_to_string(gril, req), print_buf);	\
 | 
			
		||||
		print_buf[0] = '\0';
 | 
			
		||||
#define g_ril_print_request_no_args(gril, token, req)			\
 | 
			
		||||
	G_RIL_TRACE(gril, "[%d,%04d]> %s",				\
 | 
			
		||||
			g_ril_get_slot(gril), token,			\
 | 
			
		||||
@@ -85,7 +86,8 @@ extern char print_buf[];
 | 
			
		||||
			g_ril_get_slot(gril),				\
 | 
			
		||||
			message->serial_no,				\
 | 
			
		||||
			g_ril_request_id_to_string(gril, message->req), \
 | 
			
		||||
							print_buf)
 | 
			
		||||
							print_buf);	\
 | 
			
		||||
			print_buf[0] = '\0';
 | 
			
		||||
#define g_ril_print_response_no_args(gril, message)			\
 | 
			
		||||
	G_RIL_TRACE(gril, "[%d,%04d]< %s",				\
 | 
			
		||||
		g_ril_get_slot(gril), message->serial_no,		\
 | 
			
		||||
 
 | 
			
		||||
@@ -49,13 +49,14 @@ 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,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct ofono_gprs_primary_context {
 | 
			
		||||
	unsigned int cid;
 | 
			
		||||
	int direction;
 | 
			
		||||
	char apn[OFONO_GPRS_MAX_APN_LENGTH + 1];
 | 
			
		||||
	char username[OFONO_GPRS_MAX_USERNAME_LENGTH + 1];
 | 
			
		||||
	char password[OFONO_GPRS_MAX_PASSWORD_LENGTH + 1];
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										121
									
								
								ofono/include/sailfish_manager.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										121
									
								
								ofono/include/sailfish_manager.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,121 @@
 | 
			
		||||
/*
 | 
			
		||||
 *  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 SAILFISHOS_MANAGER_H
 | 
			
		||||
#define SAILFISHOS_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;
 | 
			
		||||
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);
 | 
			
		||||
 | 
			
		||||
/* 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 /* SAILFISHOS_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);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -53,6 +53,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)
 | 
			
		||||
 | 
			
		||||
@@ -166,6 +169,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,
 | 
			
		||||
@@ -344,7 +351,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 +421,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));
 | 
			
		||||
 
 | 
			
		||||
@@ -239,6 +239,7 @@ void ril_post_online(struct ofono_modem *modem)
 | 
			
		||||
	struct ofono_gprs *gprs;
 | 
			
		||||
	struct ofono_gprs_context *gc;
 | 
			
		||||
 | 
			
		||||
	ofono_cbs_create(modem, rd->vendor, RILMODEM, rd->ril);
 | 
			
		||||
	ofono_netreg_create(modem, rd->vendor, RILMODEM, rd->ril);
 | 
			
		||||
	ofono_ussd_create(modem, rd->vendor, RILMODEM, rd->ril);
 | 
			
		||||
	ofono_call_settings_create(modem, rd->vendor, RILMODEM, rd->ril);
 | 
			
		||||
@@ -409,15 +410,30 @@ int ril_enable(struct ofono_modem *modem)
 | 
			
		||||
	return -EINPROGRESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void power_off_cb(struct ril_msg *message, gpointer user_data)
 | 
			
		||||
{
 | 
			
		||||
	struct cb_data *cbd = user_data;
 | 
			
		||||
	struct ril_data *rd = cbd->user;
 | 
			
		||||
	struct ofono_modem *modem = cbd->data;
 | 
			
		||||
 | 
			
		||||
	if (rd) {
 | 
			
		||||
		g_ril_unref(rd->ril);
 | 
			
		||||
		rd->ril = NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ofono_modem_set_powered(modem, FALSE);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int ril_disable(struct ofono_modem *modem)
 | 
			
		||||
{
 | 
			
		||||
	struct ril_data *rd = ofono_modem_get_data(modem);
 | 
			
		||||
	struct cb_data *cbd = cb_data_new(NULL, modem, rd);
 | 
			
		||||
 | 
			
		||||
	DBG("%p", modem);
 | 
			
		||||
 | 
			
		||||
	ril_send_power(rd, FALSE, NULL, NULL);
 | 
			
		||||
	ril_send_power(rd, FALSE, power_off_cb, cbd);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
	return -EINPROGRESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct ofono_modem_driver ril_driver = {
 | 
			
		||||
 
 | 
			
		||||
@@ -29,6 +29,7 @@
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <stdbool.h>
 | 
			
		||||
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#include <glib.h>
 | 
			
		||||
@@ -52,11 +53,22 @@
 | 
			
		||||
 | 
			
		||||
#include "drivers/rilmodem/rilmodem.h"
 | 
			
		||||
#include "drivers/rilmodem/vendor.h"
 | 
			
		||||
#include "gdbus.h"
 | 
			
		||||
 | 
			
		||||
#include "ofono.h"
 | 
			
		||||
 | 
			
		||||
#define THERMAL_MANAGEMENT_INTERFACE OFONO_SERVICE ".sofia3gr.ThermalManagement"
 | 
			
		||||
 | 
			
		||||
struct ril_data {
 | 
			
		||||
	GRil *ril;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct ril_thermal_management {
 | 
			
		||||
	DBusMessage *pending;
 | 
			
		||||
	struct ofono_modem *modem;
 | 
			
		||||
	dbus_bool_t throttling;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static int ril_send_power(GRil *ril, ofono_bool_t online,
 | 
			
		||||
				GRilResponseFunc func,
 | 
			
		||||
				gpointer user_data,
 | 
			
		||||
@@ -129,7 +141,14 @@ static int ril_probe(struct ofono_modem *modem)
 | 
			
		||||
 | 
			
		||||
static void ril_remove(struct ofono_modem *modem)
 | 
			
		||||
{
 | 
			
		||||
	DBusConnection *conn = ofono_dbus_get_connection();
 | 
			
		||||
	struct ril_data *rd = ofono_modem_get_data(modem);
 | 
			
		||||
	const char *path = ofono_modem_get_path(modem);
 | 
			
		||||
 | 
			
		||||
	if (g_dbus_unregister_interface(conn, path,
 | 
			
		||||
					THERMAL_MANAGEMENT_INTERFACE))
 | 
			
		||||
		ofono_modem_remove_interface(modem,
 | 
			
		||||
						THERMAL_MANAGEMENT_INTERFACE);
 | 
			
		||||
 | 
			
		||||
	ofono_modem_set_data(modem, NULL);
 | 
			
		||||
 | 
			
		||||
@@ -137,6 +156,270 @@ static void ril_remove(struct ofono_modem *modem)
 | 
			
		||||
	g_free(rd);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void set_rf_power_status_cb(struct ril_msg *message, gpointer user_data)
 | 
			
		||||
{
 | 
			
		||||
	DBusConnection *conn = ofono_dbus_get_connection();
 | 
			
		||||
	struct ril_thermal_management *tm = user_data;
 | 
			
		||||
	struct ril_data *rd = ofono_modem_get_data(tm->modem);
 | 
			
		||||
	const char *path = ofono_modem_get_path(tm->modem);
 | 
			
		||||
 | 
			
		||||
	DBG("");
 | 
			
		||||
 | 
			
		||||
	if (message->error != RIL_E_SUCCESS) {
 | 
			
		||||
		ofono_error("%s RILD reply failure: %s",
 | 
			
		||||
			g_ril_request_id_to_string(rd->ril, message->req),
 | 
			
		||||
			ril_error_to_string(message->error));
 | 
			
		||||
 | 
			
		||||
		__ofono_dbus_pending_reply(&tm->pending,
 | 
			
		||||
					__ofono_error_failed(tm->pending));
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Change the throttling state */
 | 
			
		||||
	tm->throttling = tm->throttling ? false : true;
 | 
			
		||||
 | 
			
		||||
	__ofono_dbus_pending_reply(&tm->pending,
 | 
			
		||||
				dbus_message_new_method_return(tm->pending));
 | 
			
		||||
 | 
			
		||||
	ofono_dbus_signal_property_changed(conn, path,
 | 
			
		||||
					THERMAL_MANAGEMENT_INTERFACE,
 | 
			
		||||
					"TransmitPowerThrottling",
 | 
			
		||||
					DBUS_TYPE_BOOLEAN,
 | 
			
		||||
					&tm->throttling);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static DBusMessage *set_rf_power_status(DBusMessage *msg,
 | 
			
		||||
					dbus_bool_t enable,
 | 
			
		||||
					void *data)
 | 
			
		||||
{
 | 
			
		||||
	struct ril_thermal_management *tm = data;
 | 
			
		||||
	struct ril_data *rd = ofono_modem_get_data(tm->modem);
 | 
			
		||||
	struct parcel rilp;
 | 
			
		||||
 | 
			
		||||
	int cmd_id;
 | 
			
		||||
	char buf[4];
 | 
			
		||||
 | 
			
		||||
	DBG("");
 | 
			
		||||
 | 
			
		||||
	if (tm->pending)
 | 
			
		||||
		return __ofono_error_busy(msg);
 | 
			
		||||
 | 
			
		||||
	parcel_init(&rilp);
 | 
			
		||||
	parcel_w_int32(&rilp, 2);
 | 
			
		||||
	/* RIL_OEM_HOOK_STRING_SET_RF_POWER_STATUS = 0x000000AC */
 | 
			
		||||
	cmd_id = 0x000000AC;
 | 
			
		||||
	sprintf(buf, "%d", cmd_id);
 | 
			
		||||
	parcel_w_string(&rilp, buf);
 | 
			
		||||
 | 
			
		||||
	memset(buf, 0, sizeof(buf));
 | 
			
		||||
	sprintf(buf, "%d", enable ? 1 : 0);
 | 
			
		||||
	parcel_w_string(&rilp, buf);
 | 
			
		||||
 | 
			
		||||
	g_ril_append_print_buf(rd->ril, "{cmd_id=0x%02X,arg=%s}", cmd_id, buf);
 | 
			
		||||
 | 
			
		||||
	if (g_ril_send(rd->ril, RIL_REQUEST_OEM_HOOK_STRINGS, &rilp,
 | 
			
		||||
			set_rf_power_status_cb, tm, NULL) == 0)
 | 
			
		||||
		return __ofono_error_failed(msg);
 | 
			
		||||
 | 
			
		||||
	tm->pending = dbus_message_ref(msg);
 | 
			
		||||
 | 
			
		||||
	return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static DBusMessage *thermal_management_set_property(DBusConnection *conn,
 | 
			
		||||
							DBusMessage *msg,
 | 
			
		||||
							void *data)
 | 
			
		||||
{
 | 
			
		||||
	struct ril_thermal_management *tm = data;
 | 
			
		||||
	DBusMessageIter iter;
 | 
			
		||||
	DBusMessageIter var;
 | 
			
		||||
	const char *name;
 | 
			
		||||
	dbus_bool_t throttling;
 | 
			
		||||
 | 
			
		||||
	DBG("");
 | 
			
		||||
 | 
			
		||||
	if (!ofono_modem_get_online(tm->modem))
 | 
			
		||||
		return __ofono_error_not_available(msg);
 | 
			
		||||
 | 
			
		||||
	if (!dbus_message_iter_init(msg, &iter))
 | 
			
		||||
		return __ofono_error_invalid_args(msg);
 | 
			
		||||
 | 
			
		||||
	if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
 | 
			
		||||
		return __ofono_error_invalid_args(msg);
 | 
			
		||||
 | 
			
		||||
	dbus_message_iter_get_basic(&iter, &name);
 | 
			
		||||
 | 
			
		||||
	if (!strcmp(name, "TransmitPowerThrottling")) {
 | 
			
		||||
		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 (dbus_message_iter_get_arg_type(&var) != DBUS_TYPE_BOOLEAN)
 | 
			
		||||
			return __ofono_error_invalid_args(msg);
 | 
			
		||||
 | 
			
		||||
		dbus_message_iter_get_basic(&var, &throttling);
 | 
			
		||||
 | 
			
		||||
		if (tm->throttling == throttling)
 | 
			
		||||
			/* Ignore set request if new state == current state */
 | 
			
		||||
			return dbus_message_new_method_return(msg);
 | 
			
		||||
 | 
			
		||||
		return set_rf_power_status(msg, throttling, tm);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return __ofono_error_invalid_args(msg);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static DBusMessage *thermal_management_get_properties(DBusConnection *conn,
 | 
			
		||||
							DBusMessage *msg,
 | 
			
		||||
							void *data)
 | 
			
		||||
{
 | 
			
		||||
	struct ril_thermal_management *tm = data;
 | 
			
		||||
	DBusMessage *reply;
 | 
			
		||||
	DBusMessageIter iter;
 | 
			
		||||
	DBusMessageIter dict;
 | 
			
		||||
 | 
			
		||||
	DBG("");
 | 
			
		||||
 | 
			
		||||
	reply = dbus_message_new_method_return(msg);
 | 
			
		||||
	if (reply == NULL)
 | 
			
		||||
		return NULL;
 | 
			
		||||
 | 
			
		||||
	dbus_message_iter_init_append(reply, &iter);
 | 
			
		||||
 | 
			
		||||
	dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
 | 
			
		||||
					OFONO_PROPERTIES_ARRAY_SIGNATURE,
 | 
			
		||||
					&dict);
 | 
			
		||||
 | 
			
		||||
	ofono_dbus_dict_append(&dict, "TransmitPowerThrottling",
 | 
			
		||||
				DBUS_TYPE_BOOLEAN,
 | 
			
		||||
				&tm->throttling);
 | 
			
		||||
 | 
			
		||||
	dbus_message_iter_close_container(&iter, &dict);
 | 
			
		||||
 | 
			
		||||
	return reply;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const GDBusMethodTable thermal_management_methods[] = {
 | 
			
		||||
	{ GDBUS_METHOD("GetProperties",
 | 
			
		||||
			NULL, GDBUS_ARGS({ "properties", "a{sv}" }),
 | 
			
		||||
			thermal_management_get_properties) },
 | 
			
		||||
	{ GDBUS_ASYNC_METHOD("SetProperty",
 | 
			
		||||
			GDBUS_ARGS({ "property", "s" }, { "value", "v" }),
 | 
			
		||||
			NULL, thermal_management_set_property) },
 | 
			
		||||
	{}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const GDBusSignalTable thermal_management_signals[] = {
 | 
			
		||||
	{ GDBUS_SIGNAL("PropertyChanged",
 | 
			
		||||
			GDBUS_ARGS({ "name", "s" }, { "value", "v" })) },
 | 
			
		||||
	{ }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void thermal_management_cleanup(void *data)
 | 
			
		||||
{
 | 
			
		||||
	struct ril_thermal_management *tm = data;
 | 
			
		||||
 | 
			
		||||
	if (tm->pending)
 | 
			
		||||
		__ofono_dbus_pending_reply(&tm->pending,
 | 
			
		||||
					__ofono_error_canceled(tm->pending));
 | 
			
		||||
 | 
			
		||||
	g_free(tm);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void get_rf_power_status_cb(struct ril_msg *message, gpointer user_data)
 | 
			
		||||
{
 | 
			
		||||
	struct ofono_modem *modem = user_data;
 | 
			
		||||
	struct ril_data *rd = ofono_modem_get_data(modem);
 | 
			
		||||
	struct ril_thermal_management *tm;
 | 
			
		||||
	DBusConnection *conn = ofono_dbus_get_connection();
 | 
			
		||||
	struct parcel rilp;
 | 
			
		||||
	gint numstr;
 | 
			
		||||
	gchar *power_status;
 | 
			
		||||
	char *endptr;
 | 
			
		||||
	int enabled;
 | 
			
		||||
	const char *path = ofono_modem_get_path(modem);
 | 
			
		||||
 | 
			
		||||
	DBG("");
 | 
			
		||||
 | 
			
		||||
	if (message->error != RIL_E_SUCCESS) {
 | 
			
		||||
		ofono_error("%s RILD reply failure: %s",
 | 
			
		||||
			g_ril_request_id_to_string(rd->ril, message->req),
 | 
			
		||||
			ril_error_to_string(message->error));
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	g_ril_init_parcel(message, &rilp);
 | 
			
		||||
 | 
			
		||||
	numstr = parcel_r_int32(&rilp);
 | 
			
		||||
	if (numstr < 1) {
 | 
			
		||||
		ofono_error("RILD reply empty !");
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	power_status = parcel_r_string(&rilp);
 | 
			
		||||
	if (power_status == NULL || power_status == '\0')
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	enabled = strtol(power_status, &endptr, 10);
 | 
			
		||||
	/*
 | 
			
		||||
	 * power_status == endptr => conversion error
 | 
			
		||||
	 * *endptr != '\0' => partial conversion
 | 
			
		||||
	 */
 | 
			
		||||
	if (power_status == endptr || *endptr != '\0')
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	tm = g_try_new0(struct ril_thermal_management, 1);
 | 
			
		||||
	if (tm == NULL)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	tm->modem = modem;
 | 
			
		||||
	tm->throttling = (enabled > 0) ? true : false;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	if (!g_dbus_register_interface(conn, path, THERMAL_MANAGEMENT_INTERFACE,
 | 
			
		||||
					thermal_management_methods,
 | 
			
		||||
					thermal_management_signals,
 | 
			
		||||
					NULL, tm, thermal_management_cleanup)) {
 | 
			
		||||
		ofono_error("Could not register %s interface under %s",
 | 
			
		||||
					THERMAL_MANAGEMENT_INTERFACE, path);
 | 
			
		||||
		g_free(tm);
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ofono_modem_add_interface(modem, THERMAL_MANAGEMENT_INTERFACE);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int ril_thermal_management_enable(struct ofono_modem *modem)
 | 
			
		||||
{
 | 
			
		||||
	struct ril_data *rd = ofono_modem_get_data(modem);
 | 
			
		||||
	struct parcel rilp;
 | 
			
		||||
 | 
			
		||||
	int cmd_id;
 | 
			
		||||
	char buf[4];
 | 
			
		||||
 | 
			
		||||
	DBG("");
 | 
			
		||||
 | 
			
		||||
	parcel_init(&rilp);
 | 
			
		||||
	parcel_w_int32(&rilp, 1);
 | 
			
		||||
	/* RIL_OEM_HOOK_STRING_GET_RF_POWER_STATUS = 0x000000AB */
 | 
			
		||||
	cmd_id = 0x000000AB;
 | 
			
		||||
	sprintf(buf, "%d", cmd_id);
 | 
			
		||||
	parcel_w_string(&rilp, buf);
 | 
			
		||||
 | 
			
		||||
	g_ril_append_print_buf(rd->ril, "{cmd_id=0x%02X}", cmd_id);
 | 
			
		||||
 | 
			
		||||
	if (g_ril_send(rd->ril, RIL_REQUEST_OEM_HOOK_STRINGS, &rilp,
 | 
			
		||||
			get_rf_power_status_cb, modem, NULL) > 0)
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	/* Error path */
 | 
			
		||||
 | 
			
		||||
	return -EIO;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void ril_pre_sim(struct ofono_modem *modem)
 | 
			
		||||
{
 | 
			
		||||
	struct ril_data *rd = ofono_modem_get_data(modem);
 | 
			
		||||
@@ -145,6 +428,7 @@ static void ril_pre_sim(struct ofono_modem *modem)
 | 
			
		||||
 | 
			
		||||
	ofono_devinfo_create(modem, 0, "rilmodem", rd->ril);
 | 
			
		||||
	ofono_sim_create(modem, 0, "rilmodem", rd->ril);
 | 
			
		||||
	ril_thermal_management_enable(modem);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void ril_post_sim(struct ofono_modem *modem)
 | 
			
		||||
@@ -255,14 +539,45 @@ static int ril_enable(struct ofono_modem *modem)
 | 
			
		||||
	return -EINPROGRESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int ril_disable(struct ofono_modem *modem)
 | 
			
		||||
static void ril_send_power_off_cb(struct ril_msg *message, gpointer user_data)
 | 
			
		||||
{
 | 
			
		||||
	struct ofono_modem *modem = (struct ofono_modem *) user_data;
 | 
			
		||||
	struct ril_data *rd = ofono_modem_get_data(modem);
 | 
			
		||||
 | 
			
		||||
	DBG("%p", modem);
 | 
			
		||||
	ril_send_power(rd->ril, FALSE, NULL, NULL, NULL);
 | 
			
		||||
	g_ril_unref(rd->ril);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
	ofono_modem_set_powered(modem, FALSE);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int ril_disable(struct ofono_modem *modem)
 | 
			
		||||
{
 | 
			
		||||
	DBusConnection *conn = ofono_dbus_get_connection();
 | 
			
		||||
	struct ril_data *rd = ofono_modem_get_data(modem);
 | 
			
		||||
	const char *path = ofono_modem_get_path(modem);
 | 
			
		||||
	struct parcel rilp;
 | 
			
		||||
	int cmd_id;
 | 
			
		||||
	char buf[4];
 | 
			
		||||
 | 
			
		||||
	DBG("%p", modem);
 | 
			
		||||
 | 
			
		||||
	if (g_dbus_unregister_interface(conn, path,
 | 
			
		||||
					THERMAL_MANAGEMENT_INTERFACE))
 | 
			
		||||
		ofono_modem_remove_interface(modem,
 | 
			
		||||
						THERMAL_MANAGEMENT_INTERFACE);
 | 
			
		||||
 | 
			
		||||
	/* RIL_OEM_HOOK_STRING_SET_MODEM_OFF = 0x000000CF */
 | 
			
		||||
	cmd_id = 0x000000CF;
 | 
			
		||||
	sprintf(buf, "%d", cmd_id);
 | 
			
		||||
	parcel_init(&rilp);
 | 
			
		||||
	parcel_w_int32(&rilp, 1);
 | 
			
		||||
	parcel_w_string(&rilp, buf);
 | 
			
		||||
 | 
			
		||||
	g_ril_append_print_buf(rd->ril, "{cmd_id=0x%02X}", cmd_id);
 | 
			
		||||
 | 
			
		||||
	g_ril_send(rd->ril, RIL_REQUEST_OEM_HOOK_STRINGS, &rilp,
 | 
			
		||||
					ril_send_power_off_cb, modem, NULL);
 | 
			
		||||
 | 
			
		||||
	return -EINPROGRESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct ofono_modem_driver ril_driver = {
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										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)
 | 
			
		||||
							
								
								
									
										1300
									
								
								ofono/plugins/sailfish_manager/sailfish_manager.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1300
									
								
								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:
 | 
			
		||||
 */
 | 
			
		||||
@@ -325,11 +325,14 @@ static gboolean setup_huawei(struct modem_info *modem)
 | 
			
		||||
		if (g_strcmp0(info->label, "modem") == 0 ||
 | 
			
		||||
				g_strcmp0(info->interface, "255/1/1") == 0 ||
 | 
			
		||||
				g_strcmp0(info->interface, "255/2/1") == 0 ||
 | 
			
		||||
				g_strcmp0(info->interface, "255/3/1") == 0 ||
 | 
			
		||||
				g_strcmp0(info->interface, "255/1/49") == 0) {
 | 
			
		||||
			mdm = info->devnode;
 | 
			
		||||
		} else if (g_strcmp0(info->label, "pcui") == 0 ||
 | 
			
		||||
				g_strcmp0(info->interface, "255/1/2") == 0 ||
 | 
			
		||||
				g_strcmp0(info->interface, "255/2/2") == 0 ||
 | 
			
		||||
				g_strcmp0(info->interface, "255/2/18") == 0 ||
 | 
			
		||||
				g_strcmp0(info->interface, "255/3/18") == 0 ||
 | 
			
		||||
				g_strcmp0(info->interface, "255/1/50") == 0) {
 | 
			
		||||
			pcui = info->devnode;
 | 
			
		||||
		} else if (g_strcmp0(info->label, "diag") == 0 ||
 | 
			
		||||
 
 | 
			
		||||
@@ -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);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -203,7 +203,7 @@ static gboolean sco_accept(GIOChannel *io, GIOCondition cond,
 | 
			
		||||
	send_new_connection(card->path, nsk, card->selected_codec);
 | 
			
		||||
	close(nsk);
 | 
			
		||||
 | 
			
		||||
	if (card->driver->sco_connected_hint)
 | 
			
		||||
	if (card->driver && card->driver->sco_connected_hint)
 | 
			
		||||
		card->driver->sco_connected_hint(card);
 | 
			
		||||
 | 
			
		||||
	return TRUE;
 | 
			
		||||
 
 | 
			
		||||
@@ -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:
 | 
			
		||||
 */
 | 
			
		||||
@@ -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,21 +13,13 @@
 | 
			
		||||
 *  GNU General Public License for more details.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef RIL_MTU_H
 | 
			
		||||
#define RIL_MTU_H
 | 
			
		||||
#ifndef MTU_WATCH_H
 | 
			
		||||
#define MTU_WATCH_H
 | 
			
		||||
 | 
			
		||||
#include "ril_types.h"
 | 
			
		||||
struct mtu_watch;
 | 
			
		||||
 | 
			
		||||
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 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 /* RIL_MTU_H */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Local Variables:
 | 
			
		||||
 * mode: C
 | 
			
		||||
 * c-basic-offset: 8
 | 
			
		||||
 * indent-tabs-mode: t
 | 
			
		||||
 * End:
 | 
			
		||||
 */
 | 
			
		||||
#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:
 | 
			
		||||
@@ -2511,13 +2514,6 @@ static void sim_spn_close(struct ofono_sim *sim)
 | 
			
		||||
 | 
			
		||||
static void sim_free_main_state(struct ofono_sim *sim)
 | 
			
		||||
{
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < OFONO_SIM_PASSWORD_INVALID; i++)
 | 
			
		||||
		sim->pin_retries[i] = -1;
 | 
			
		||||
 | 
			
		||||
	memset(sim->locked_pins, 0, sizeof(sim->locked_pins));
 | 
			
		||||
 | 
			
		||||
	if (sim->imsi) {
 | 
			
		||||
		g_free(sim->imsi);
 | 
			
		||||
		sim->imsi = NULL;
 | 
			
		||||
@@ -2607,31 +2603,50 @@ static void sim_set_locked_pin(struct ofono_sim *sim,
 | 
			
		||||
	g_strfreev(locked_pins);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void sim_query_fac_imsilock_cb(const struct ofono_error *error,
 | 
			
		||||
static void sim_query_fac_pinlock_cb(const struct ofono_error *error,
 | 
			
		||||
				ofono_bool_t status, void *data)
 | 
			
		||||
{
 | 
			
		||||
	if (error->type != OFONO_ERROR_TYPE_NO_ERROR)
 | 
			
		||||
		return;
 | 
			
		||||
	struct ofono_sim *sim = data;
 | 
			
		||||
 | 
			
		||||
	sim_set_locked_pin(data, OFONO_SIM_PASSWORD_PHSIM_PIN, status);
 | 
			
		||||
	if (error->type != OFONO_ERROR_TYPE_NO_ERROR)
 | 
			
		||||
		goto done;
 | 
			
		||||
 | 
			
		||||
	sim_set_locked_pin(data, OFONO_SIM_PASSWORD_SIM_PIN, status);
 | 
			
		||||
 | 
			
		||||
done:
 | 
			
		||||
	sim_initialize(sim);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void sim_query_fac_networklock_cb(const struct ofono_error *error,
 | 
			
		||||
				ofono_bool_t status, void *data)
 | 
			
		||||
{
 | 
			
		||||
	struct ofono_sim *sim = data;
 | 
			
		||||
 | 
			
		||||
	if (error->type != OFONO_ERROR_TYPE_NO_ERROR)
 | 
			
		||||
		return;
 | 
			
		||||
		goto done;
 | 
			
		||||
 | 
			
		||||
	sim_set_locked_pin(data, OFONO_SIM_PASSWORD_PHNET_PIN, status);
 | 
			
		||||
 | 
			
		||||
done:
 | 
			
		||||
	sim->driver->query_facility_lock(sim,
 | 
			
		||||
					OFONO_SIM_PASSWORD_SIM_PIN,
 | 
			
		||||
					sim_query_fac_pinlock_cb, sim);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void sim_query_fac_pinlock_cb(const struct ofono_error *error,
 | 
			
		||||
static void sim_query_fac_imsilock_cb(const struct ofono_error *error,
 | 
			
		||||
				ofono_bool_t status, void *data)
 | 
			
		||||
{
 | 
			
		||||
	if (error->type != OFONO_ERROR_TYPE_NO_ERROR)
 | 
			
		||||
		return;
 | 
			
		||||
	struct ofono_sim *sim = data;
 | 
			
		||||
 | 
			
		||||
	sim_set_locked_pin(data, OFONO_SIM_PASSWORD_SIM_PIN, status);
 | 
			
		||||
	if (error->type != OFONO_ERROR_TYPE_NO_ERROR)
 | 
			
		||||
		goto done;
 | 
			
		||||
 | 
			
		||||
	sim_set_locked_pin(data, OFONO_SIM_PASSWORD_PHSIM_PIN, status);
 | 
			
		||||
 | 
			
		||||
done:
 | 
			
		||||
	sim->driver->query_facility_lock(sim,
 | 
			
		||||
					OFONO_SIM_PASSWORD_PHNET_PIN,
 | 
			
		||||
					sim_query_fac_networklock_cb, sim);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ofono_sim_inserted_notify(struct ofono_sim *sim, ofono_bool_t inserted)
 | 
			
		||||
@@ -2665,18 +2680,28 @@ void ofono_sim_inserted_notify(struct ofono_sim *sim, ofono_bool_t inserted)
 | 
			
		||||
					OFONO_SIM_PASSWORD_PHSIM_PIN,
 | 
			
		||||
					sim_query_fac_imsilock_cb, sim);
 | 
			
		||||
 | 
			
		||||
			sim->driver->query_facility_lock(sim,
 | 
			
		||||
					OFONO_SIM_PASSWORD_PHNET_PIN,
 | 
			
		||||
					sim_query_fac_networklock_cb, sim);
 | 
			
		||||
 | 
			
		||||
			sim->driver->query_facility_lock(sim,
 | 
			
		||||
					OFONO_SIM_PASSWORD_SIM_PIN,
 | 
			
		||||
					sim_query_fac_pinlock_cb, sim);
 | 
			
		||||
		} else {
 | 
			
		||||
			sim_initialize(sim);
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		switch (sim->pin_type) {
 | 
			
		||||
		case OFONO_SIM_PASSWORD_SIM_PIN:
 | 
			
		||||
		case OFONO_SIM_PASSWORD_SIM_PUK:
 | 
			
		||||
		case OFONO_SIM_PASSWORD_SIM_PIN2:
 | 
			
		||||
		case OFONO_SIM_PASSWORD_SIM_PUK2:
 | 
			
		||||
			sim->pin_type = OFONO_SIM_PASSWORD_NONE;
 | 
			
		||||
			break;
 | 
			
		||||
		default:
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		sim_initialize(sim);
 | 
			
		||||
	} else {
 | 
			
		||||
		sim->pin_type = OFONO_SIM_PASSWORD_NONE;
 | 
			
		||||
		sim->locked_pins[OFONO_SIM_PASSWORD_SIM_PIN] = FALSE;
 | 
			
		||||
		sim->locked_pins[OFONO_SIM_PASSWORD_SIM_PIN2] = FALSE;
 | 
			
		||||
 | 
			
		||||
		sim->pin_retries[OFONO_SIM_PASSWORD_SIM_PIN] = -1;
 | 
			
		||||
		sim->pin_retries[OFONO_SIM_PASSWORD_SIM_PUK] = -1;
 | 
			
		||||
		sim->pin_retries[OFONO_SIM_PASSWORD_SIM_PIN2] = -1;
 | 
			
		||||
		sim->pin_retries[OFONO_SIM_PASSWORD_SIM_PUK2] = -1;
 | 
			
		||||
 | 
			
		||||
		sim_free_state(sim);
 | 
			
		||||
	}
 | 
			
		||||
@@ -3282,8 +3307,6 @@ ofono_bool_t __ofono_is_valid_sim_pin(const char *pin,
 | 
			
		||||
		return is_valid_pin(pin, 8, 8);
 | 
			
		||||
		break;
 | 
			
		||||
	case OFONO_SIM_PASSWORD_NONE:
 | 
			
		||||
		return is_valid_pin(pin, 0, 8);
 | 
			
		||||
		break;
 | 
			
		||||
	case OFONO_SIM_PASSWORD_INVALID:
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
@@ -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;
 | 
			
		||||
 
 | 
			
		||||
@@ -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)
 | 
			
		||||
{
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										15
									
								
								ofono/test/cancel-sms
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										15
									
								
								ofono/test/cancel-sms
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,15 @@
 | 
			
		||||
#!/usr/bin/python3
 | 
			
		||||
 | 
			
		||||
import sys
 | 
			
		||||
import dbus
 | 
			
		||||
 | 
			
		||||
bus = dbus.SystemBus()
 | 
			
		||||
 | 
			
		||||
manager = dbus.Interface(bus.get_object('org.ofono', '/'),
 | 
			
		||||
						'org.ofono.Manager')
 | 
			
		||||
 | 
			
		||||
path = sys.argv[1]
 | 
			
		||||
message = dbus.Interface(bus.get_object('org.ofono', path),
 | 
			
		||||
					'org.ofono.Message')
 | 
			
		||||
 | 
			
		||||
message.Cancel()
 | 
			
		||||
							
								
								
									
										18
									
								
								ofono/test/disable-throttling
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										18
									
								
								ofono/test/disable-throttling
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,18 @@
 | 
			
		||||
#!/usr/bin/python3
 | 
			
		||||
 | 
			
		||||
import dbus, sys
 | 
			
		||||
 | 
			
		||||
bus = dbus.SystemBus()
 | 
			
		||||
 | 
			
		||||
if len(sys.argv) == 2:
 | 
			
		||||
	path = sys.argv[1]
 | 
			
		||||
else:
 | 
			
		||||
	manager = dbus.Interface(bus.get_object('org.ofono', '/'),
 | 
			
		||||
			'org.ofono.Manager')
 | 
			
		||||
	modems = manager.GetModems()
 | 
			
		||||
	path = modems[0][0]
 | 
			
		||||
 | 
			
		||||
print("Disabling transmit power throttling of modem %s ..." % path)
 | 
			
		||||
thermal_management = dbus.Interface(bus.get_object('org.ofono', path),
 | 
			
		||||
		'org.ofono.sofia3gr.ThermalManagement')
 | 
			
		||||
thermal_management.SetProperty("TransmitPowerThrottling", dbus.Boolean(0), timeout = 30)
 | 
			
		||||
							
								
								
									
										18
									
								
								ofono/test/enable-throttling
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										18
									
								
								ofono/test/enable-throttling
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,18 @@
 | 
			
		||||
#!/usr/bin/python3
 | 
			
		||||
 | 
			
		||||
import dbus, sys
 | 
			
		||||
 | 
			
		||||
bus = dbus.SystemBus()
 | 
			
		||||
 | 
			
		||||
if len(sys.argv) == 2:
 | 
			
		||||
	path = sys.argv[1]
 | 
			
		||||
else:
 | 
			
		||||
	manager = dbus.Interface(bus.get_object('org.ofono', '/'),
 | 
			
		||||
			'org.ofono.Manager')
 | 
			
		||||
	modems = manager.GetModems()
 | 
			
		||||
	path = modems[0][0]
 | 
			
		||||
 | 
			
		||||
print("Enabling transmit power throttling of modem %s ..." % path)
 | 
			
		||||
thermal_management = dbus.Interface(bus.get_object('org.ofono', path),
 | 
			
		||||
		'org.ofono.sofia3gr.ThermalManagement')
 | 
			
		||||
thermal_management.SetProperty("TransmitPowerThrottling", dbus.Boolean(1), timeout = 30)
 | 
			
		||||
							
								
								
									
										0
									
								
								ofono/test/get-serving-cell-info
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							
							
						
						
									
										0
									
								
								ofono/test/get-serving-cell-info
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							
							
								
								
									
										58
									
								
								ofono/unit/coverage
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										58
									
								
								ofono/unit/coverage
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,58 @@
 | 
			
		||||
#!/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-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"
 | 
			
		||||
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" "$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/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 "$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:
 | 
			
		||||
 */
 | 
			
		||||
							
								
								
									
										280
									
								
								ofono/unit/rilmodem-test-engine.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										280
									
								
								ofono/unit/rilmodem-test-engine.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,280 @@
 | 
			
		||||
/*
 | 
			
		||||
 *
 | 
			
		||||
 *  oFono - Open Source Telephony
 | 
			
		||||
 *
 | 
			
		||||
 *  Copyright (C) 2016 Canonical 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.
 | 
			
		||||
 *
 | 
			
		||||
 *  You should have received a copy of the GNU General Public License
 | 
			
		||||
 *  along with this program; if not, write to the Free Software
 | 
			
		||||
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_CONFIG_H
 | 
			
		||||
#include <config.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#define _GNU_SOURCE
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <netinet/in.h>
 | 
			
		||||
#include <sys/socket.h>
 | 
			
		||||
#include <sys/un.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
 | 
			
		||||
#include <ofono/types.h>
 | 
			
		||||
 | 
			
		||||
#include <gril.h>
 | 
			
		||||
 | 
			
		||||
#include "rilmodem-test-engine.h"
 | 
			
		||||
 | 
			
		||||
#define MAX_REQUEST_SIZE 4096
 | 
			
		||||
#define RIL_SERVER_SOCK_PATH "/tmp/unittestril"
 | 
			
		||||
 | 
			
		||||
static GMainLoop *mainloop;
 | 
			
		||||
 | 
			
		||||
struct engine_data {
 | 
			
		||||
	int server_sk;
 | 
			
		||||
	int connected_sk;
 | 
			
		||||
	guint connection_watch;
 | 
			
		||||
	rilmodem_test_engine_cb_t connect_func;
 | 
			
		||||
	GIOChannel *server_io;
 | 
			
		||||
	char *sock_name;
 | 
			
		||||
	struct rilmodem_test_data rtd;
 | 
			
		||||
	int step_i;
 | 
			
		||||
	void *user_data;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void send_parcel(struct engine_data *ed)
 | 
			
		||||
{
 | 
			
		||||
	GIOStatus status;
 | 
			
		||||
	gsize wbytes;
 | 
			
		||||
	const struct rilmodem_test_step *step = &ed->rtd.steps[ed->step_i];
 | 
			
		||||
 | 
			
		||||
	status = g_io_channel_write_chars(ed->server_io,
 | 
			
		||||
						step->parcel_data,
 | 
			
		||||
						step->parcel_size,
 | 
			
		||||
						&wbytes, NULL);
 | 
			
		||||
 | 
			
		||||
	g_assert(wbytes == step->parcel_size);
 | 
			
		||||
	g_assert(status == G_IO_STATUS_NORMAL);
 | 
			
		||||
 | 
			
		||||
	status = g_io_channel_flush(ed->server_io, NULL);
 | 
			
		||||
	g_assert(status == G_IO_STATUS_NORMAL);
 | 
			
		||||
 | 
			
		||||
	rilmodem_test_engine_next_step(ed);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gboolean on_rx_data(GIOChannel *chan, GIOCondition cond, gpointer data)
 | 
			
		||||
{
 | 
			
		||||
	struct engine_data *ed = data;
 | 
			
		||||
	GIOStatus status;
 | 
			
		||||
	gsize rbytes;
 | 
			
		||||
	gchar *buf;
 | 
			
		||||
	const struct rilmodem_test_step *step;
 | 
			
		||||
 | 
			
		||||
	/* We have closed the socket */
 | 
			
		||||
	if (cond == G_IO_NVAL)
 | 
			
		||||
		return FALSE;
 | 
			
		||||
 | 
			
		||||
	buf = g_malloc0(MAX_REQUEST_SIZE);
 | 
			
		||||
 | 
			
		||||
	status = g_io_channel_read_chars(ed->server_io, buf, MAX_REQUEST_SIZE,
 | 
			
		||||
								&rbytes, NULL);
 | 
			
		||||
	g_assert(status == G_IO_STATUS_NORMAL);
 | 
			
		||||
 | 
			
		||||
	/* Check this is the expected step */
 | 
			
		||||
	step = &ed->rtd.steps[ed->step_i];
 | 
			
		||||
	g_assert(step->type == TST_EVENT_RECEIVE);
 | 
			
		||||
 | 
			
		||||
	g_assert(rbytes == step->parcel_size);
 | 
			
		||||
 | 
			
		||||
	/* validate received parcel */
 | 
			
		||||
	g_assert(!memcmp(buf, step->parcel_data, rbytes));
 | 
			
		||||
 | 
			
		||||
	rilmodem_test_engine_next_step(ed);
 | 
			
		||||
 | 
			
		||||
	return TRUE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gboolean on_socket_connected(GIOChannel *chan, GIOCondition cond,
 | 
			
		||||
								gpointer data)
 | 
			
		||||
{
 | 
			
		||||
	struct engine_data *ed = data;
 | 
			
		||||
	struct sockaddr saddr;
 | 
			
		||||
	unsigned int len = sizeof(saddr);
 | 
			
		||||
	GIOStatus status;
 | 
			
		||||
 | 
			
		||||
	g_assert(cond == G_IO_IN);
 | 
			
		||||
 | 
			
		||||
	ed->connected_sk = accept(ed->server_sk, &saddr, &len);
 | 
			
		||||
	g_assert(ed->connected_sk != -1);
 | 
			
		||||
 | 
			
		||||
	ed->server_io = g_io_channel_unix_new(ed->connected_sk);
 | 
			
		||||
	g_assert(ed->server_io != NULL);
 | 
			
		||||
 | 
			
		||||
	status = g_io_channel_set_encoding(ed->server_io, NULL, NULL);
 | 
			
		||||
	g_assert(status == G_IO_STATUS_NORMAL);
 | 
			
		||||
 | 
			
		||||
	g_io_channel_set_buffered(ed->server_io, FALSE);
 | 
			
		||||
	g_io_channel_set_close_on_unref(ed->server_io, TRUE);
 | 
			
		||||
 | 
			
		||||
	if (ed->connect_func)
 | 
			
		||||
		ed->connect_func(ed->user_data);
 | 
			
		||||
 | 
			
		||||
	ed->connection_watch =
 | 
			
		||||
		g_io_add_watch_full(ed->server_io, G_PRIORITY_DEFAULT,
 | 
			
		||||
				G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
 | 
			
		||||
				on_rx_data, ed, NULL);
 | 
			
		||||
	g_io_channel_unref(ed->server_io);
 | 
			
		||||
 | 
			
		||||
	return FALSE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void rilmodem_test_engine_remove(struct engine_data *ed)
 | 
			
		||||
{
 | 
			
		||||
	if (ed->connection_watch)
 | 
			
		||||
		g_source_remove(ed->connection_watch);
 | 
			
		||||
 | 
			
		||||
	g_assert(ed->server_sk);
 | 
			
		||||
	close(ed->server_sk);
 | 
			
		||||
	remove(ed->sock_name);
 | 
			
		||||
	g_free(ed->sock_name);
 | 
			
		||||
	g_free(ed);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct engine_data *rilmodem_test_engine_create(
 | 
			
		||||
				rilmodem_test_engine_cb_t connect,
 | 
			
		||||
				const struct rilmodem_test_data *test_data,
 | 
			
		||||
				void *data)
 | 
			
		||||
{
 | 
			
		||||
	GIOChannel *io;
 | 
			
		||||
	struct sockaddr_un addr;
 | 
			
		||||
	int retval;
 | 
			
		||||
	struct engine_data *ed;
 | 
			
		||||
 | 
			
		||||
	ed = g_new0(struct engine_data, 1);
 | 
			
		||||
 | 
			
		||||
	ed->connect_func = connect;
 | 
			
		||||
	ed->user_data = data;
 | 
			
		||||
	ed->rtd = *test_data;
 | 
			
		||||
 | 
			
		||||
	ed->server_sk = socket(AF_UNIX, SOCK_STREAM, 0);
 | 
			
		||||
	g_assert(ed->server_sk);
 | 
			
		||||
 | 
			
		||||
	ed->sock_name =
 | 
			
		||||
		g_strdup_printf(RIL_SERVER_SOCK_PATH"%u", (unsigned) getpid());
 | 
			
		||||
 | 
			
		||||
	memset(&addr, 0, sizeof(addr));
 | 
			
		||||
	addr.sun_family = AF_UNIX;
 | 
			
		||||
	strncpy(addr.sun_path, ed->sock_name, sizeof(addr.sun_path) - 1);
 | 
			
		||||
 | 
			
		||||
	/* Unlink any existing socket for this session */
 | 
			
		||||
	unlink(addr.sun_path);
 | 
			
		||||
 | 
			
		||||
	retval = bind(ed->server_sk, (struct sockaddr *) &addr, sizeof(addr));
 | 
			
		||||
	g_assert(retval >= 0);
 | 
			
		||||
 | 
			
		||||
	retval = listen(ed->server_sk, 0);
 | 
			
		||||
	g_assert(retval >= 0);
 | 
			
		||||
 | 
			
		||||
	io = g_io_channel_unix_new(ed->server_sk);
 | 
			
		||||
	g_assert(io != NULL);
 | 
			
		||||
 | 
			
		||||
	g_io_channel_set_close_on_unref(io, TRUE);
 | 
			
		||||
	g_io_add_watch_full(io,	G_PRIORITY_DEFAULT,
 | 
			
		||||
				G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
 | 
			
		||||
				on_socket_connected, ed, NULL);
 | 
			
		||||
 | 
			
		||||
	g_io_channel_unref(io);
 | 
			
		||||
 | 
			
		||||
	return ed;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void rilmodem_test_engine_write_socket(struct engine_data *ed,
 | 
			
		||||
						const unsigned char *buf,
 | 
			
		||||
						const size_t buf_len)
 | 
			
		||||
{
 | 
			
		||||
	GIOStatus status;
 | 
			
		||||
	gsize wbytes;
 | 
			
		||||
 | 
			
		||||
	status = g_io_channel_write_chars(ed->server_io,
 | 
			
		||||
					(const char *) buf,
 | 
			
		||||
					buf_len,
 | 
			
		||||
					&wbytes, NULL);
 | 
			
		||||
 | 
			
		||||
	g_assert(status == G_IO_STATUS_NORMAL);
 | 
			
		||||
 | 
			
		||||
	status = g_io_channel_flush(ed->server_io, NULL);
 | 
			
		||||
 | 
			
		||||
	g_assert(status == G_IO_STATUS_NORMAL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const char *rilmodem_test_engine_get_socket_name(struct engine_data *ed)
 | 
			
		||||
{
 | 
			
		||||
	return ed->sock_name;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gboolean action_call(gpointer data)
 | 
			
		||||
{
 | 
			
		||||
	struct engine_data *ed = data;
 | 
			
		||||
	const struct rilmodem_test_step *step;
 | 
			
		||||
 | 
			
		||||
	step = &ed->rtd.steps[ed->step_i];
 | 
			
		||||
 | 
			
		||||
	step->call_action(ed->user_data);
 | 
			
		||||
 | 
			
		||||
	return FALSE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void rilmodem_test_engine_next_step(struct engine_data *ed)
 | 
			
		||||
{
 | 
			
		||||
	const struct rilmodem_test_step *step;
 | 
			
		||||
 | 
			
		||||
	ed->step_i++;
 | 
			
		||||
 | 
			
		||||
	if (ed->step_i >= ed->rtd.num_steps) {
 | 
			
		||||
		/* Finish the test */
 | 
			
		||||
		g_main_loop_quit(mainloop);
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	step = &ed->rtd.steps[ed->step_i];
 | 
			
		||||
 | 
			
		||||
	/* If next step is an action, execute it */
 | 
			
		||||
	switch (step->type) {
 | 
			
		||||
	case TST_ACTION_SEND:
 | 
			
		||||
		send_parcel(ed);
 | 
			
		||||
		break;
 | 
			
		||||
	case TST_ACTION_CALL:
 | 
			
		||||
		g_idle_add(action_call, ed);
 | 
			
		||||
		break;
 | 
			
		||||
	case TST_EVENT_RECEIVE:
 | 
			
		||||
	case TST_EVENT_CALL:
 | 
			
		||||
		break;
 | 
			
		||||
	};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const struct rilmodem_test_step *rilmodem_test_engine_get_current_step(
 | 
			
		||||
							struct engine_data *ed)
 | 
			
		||||
{
 | 
			
		||||
	const struct rilmodem_test_step *step = &ed->rtd.steps[ed->step_i];
 | 
			
		||||
 | 
			
		||||
	return step;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void rilmodem_test_engine_start(struct engine_data *ed)
 | 
			
		||||
{
 | 
			
		||||
	mainloop = g_main_loop_new(NULL, FALSE);
 | 
			
		||||
 | 
			
		||||
	g_main_loop_run(mainloop);
 | 
			
		||||
	g_main_loop_unref(mainloop);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										74
									
								
								ofono/unit/rilmodem-test-engine.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										74
									
								
								ofono/unit/rilmodem-test-engine.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,74 @@
 | 
			
		||||
/*
 | 
			
		||||
 *
 | 
			
		||||
 *  oFono - Open Source Telephony
 | 
			
		||||
 *
 | 
			
		||||
 *  Copyright (C) 2016 Canonical 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.
 | 
			
		||||
 *
 | 
			
		||||
 *  You should have received a copy of the GNU General Public License
 | 
			
		||||
 *  along with this program; if not, write to the Free Software
 | 
			
		||||
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
struct engine_data;
 | 
			
		||||
 | 
			
		||||
enum test_step_type {
 | 
			
		||||
	TST_ACTION_SEND,
 | 
			
		||||
	TST_ACTION_CALL,
 | 
			
		||||
	TST_EVENT_RECEIVE,
 | 
			
		||||
	TST_EVENT_CALL,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
typedef void (*rilmodem_test_engine_cb_t)(void *data);
 | 
			
		||||
 | 
			
		||||
struct rilmodem_test_step {
 | 
			
		||||
	enum test_step_type type;
 | 
			
		||||
 | 
			
		||||
	union {
 | 
			
		||||
		/* For TST_ACTION_CALL */
 | 
			
		||||
		rilmodem_test_engine_cb_t call_action;
 | 
			
		||||
		/* For TST_ACTION_SEND or TST_EVENT_RECEIVE */
 | 
			
		||||
		struct {
 | 
			
		||||
			const char *parcel_data;
 | 
			
		||||
			const size_t parcel_size;
 | 
			
		||||
		};
 | 
			
		||||
		/* For TST_EVENT_CALL */
 | 
			
		||||
		struct {
 | 
			
		||||
			void (*call_func)(void);
 | 
			
		||||
			void (*check_func)(void);
 | 
			
		||||
		};
 | 
			
		||||
	};
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct rilmodem_test_data {
 | 
			
		||||
	const struct rilmodem_test_step *steps;
 | 
			
		||||
	int num_steps;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
void rilmodem_test_engine_remove(struct engine_data *ed);
 | 
			
		||||
 | 
			
		||||
struct engine_data *rilmodem_test_engine_create(
 | 
			
		||||
				rilmodem_test_engine_cb_t connect,
 | 
			
		||||
				const struct rilmodem_test_data *test_data,
 | 
			
		||||
				void *data);
 | 
			
		||||
 | 
			
		||||
void rilmodem_test_engine_write_socket(struct engine_data *ed,
 | 
			
		||||
						const unsigned char *buf,
 | 
			
		||||
						const size_t buf_len);
 | 
			
		||||
 | 
			
		||||
const char *rilmodem_test_engine_get_socket_name(struct engine_data *ed);
 | 
			
		||||
 | 
			
		||||
void rilmodem_test_engine_next_step(struct engine_data *ed);
 | 
			
		||||
const struct rilmodem_test_step *rilmodem_test_engine_get_current_step(
 | 
			
		||||
							struct engine_data *ed);
 | 
			
		||||
 | 
			
		||||
void rilmodem_test_engine_start(struct engine_data *ed);
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										750
									
								
								ofono/unit/test-rilmodem-gprs.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										750
									
								
								ofono/unit/test-rilmodem-gprs.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,750 @@
 | 
			
		||||
/*
 | 
			
		||||
 *
 | 
			
		||||
 *  oFono - Open Source Telephony
 | 
			
		||||
 *
 | 
			
		||||
 *  Copyright (C) 2016 Canonical 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.
 | 
			
		||||
 *
 | 
			
		||||
 *  You should have received a copy of the GNU General Public License
 | 
			
		||||
 *  along with this program; if not, write to the Free Software
 | 
			
		||||
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_CONFIG_H
 | 
			
		||||
#include <config.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#define _GNU_SOURCE
 | 
			
		||||
#include <assert.h>
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
#include <glib.h>
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <netinet/in.h>
 | 
			
		||||
#include <sys/socket.h>
 | 
			
		||||
#include <sys/un.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
 | 
			
		||||
#include <ofono/modem.h>
 | 
			
		||||
#include <ofono/types.h>
 | 
			
		||||
#include <ofono/gprs.h>
 | 
			
		||||
#include <gril.h>
 | 
			
		||||
#include <drivers/rilmodem/rilutil.h>
 | 
			
		||||
 | 
			
		||||
#include "common.h"
 | 
			
		||||
#include "ril_constants.h"
 | 
			
		||||
#include "rilmodem-test-engine.h"
 | 
			
		||||
 | 
			
		||||
static const struct ofono_gprs_driver *gprs_drv;
 | 
			
		||||
 | 
			
		||||
/* Declarations && Re-implementations of core functions. */
 | 
			
		||||
void ril_gprs_exit(void);
 | 
			
		||||
void ril_gprs_init(void);
 | 
			
		||||
 | 
			
		||||
struct ofono_modem;
 | 
			
		||||
 | 
			
		||||
struct ofono_gprs {
 | 
			
		||||
	void *driver_data;
 | 
			
		||||
	GRil *ril;
 | 
			
		||||
	struct ofono_modem *modem;
 | 
			
		||||
	struct engine_data *engined;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct ofono_modem {
 | 
			
		||||
	struct ofono_gprs *gprs;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
int ofono_gprs_driver_register(const struct ofono_gprs_driver *d)
 | 
			
		||||
{
 | 
			
		||||
	if (gprs_drv == NULL)
 | 
			
		||||
		gprs_drv = d;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ofono_gprs_driver_unregister(const struct ofono_gprs_driver *d)
 | 
			
		||||
{
 | 
			
		||||
	gprs_drv = NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ofono_gprs_register(struct ofono_gprs *gprs)
 | 
			
		||||
{
 | 
			
		||||
	const struct rilmodem_test_step *step;
 | 
			
		||||
 | 
			
		||||
	step = rilmodem_test_engine_get_current_step(gprs->engined);
 | 
			
		||||
 | 
			
		||||
	g_assert(step->type == TST_EVENT_CALL);
 | 
			
		||||
	g_assert(step->call_func == (void (*)(void)) ofono_gprs_register);
 | 
			
		||||
 | 
			
		||||
	rilmodem_test_engine_next_step(gprs->engined);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ofono_gprs_set_data(struct ofono_gprs *gprs, void *data)
 | 
			
		||||
{
 | 
			
		||||
	gprs->driver_data = data;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void *ofono_gprs_get_data(struct ofono_gprs *gprs)
 | 
			
		||||
{
 | 
			
		||||
	return gprs->driver_data;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ofono_gprs_status_notify(struct ofono_gprs *gprs, int status)
 | 
			
		||||
{
 | 
			
		||||
	const struct rilmodem_test_step *step;
 | 
			
		||||
 | 
			
		||||
	step = rilmodem_test_engine_get_current_step(gprs->engined);
 | 
			
		||||
 | 
			
		||||
	g_assert(step->type == TST_EVENT_CALL);
 | 
			
		||||
	g_assert(step->call_func == (void (*)(void)) ofono_gprs_status_notify);
 | 
			
		||||
 | 
			
		||||
	if (step->check_func != NULL)
 | 
			
		||||
		((void (*)(struct ofono_gprs *, int)) step->check_func)(
 | 
			
		||||
								gprs, status);
 | 
			
		||||
 | 
			
		||||
	rilmodem_test_engine_next_step(gprs->engined);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ofono_gprs_detached_notify(struct ofono_gprs *gprs)
 | 
			
		||||
{
 | 
			
		||||
	const struct rilmodem_test_step *step;
 | 
			
		||||
 | 
			
		||||
	step = rilmodem_test_engine_get_current_step(gprs->engined);
 | 
			
		||||
 | 
			
		||||
	g_assert(step->type == TST_EVENT_CALL);
 | 
			
		||||
	g_assert(step->call_func ==
 | 
			
		||||
				(void (*)(void)) ofono_gprs_detached_notify);
 | 
			
		||||
 | 
			
		||||
	rilmodem_test_engine_next_step(gprs->engined);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ofono_gprs_bearer_notify(struct ofono_gprs *gprs, int bearer)
 | 
			
		||||
{
 | 
			
		||||
	const struct rilmodem_test_step *step;
 | 
			
		||||
 | 
			
		||||
	step = rilmodem_test_engine_get_current_step(gprs->engined);
 | 
			
		||||
 | 
			
		||||
	g_assert(step->type == TST_EVENT_CALL);
 | 
			
		||||
	g_assert(step->call_func == (void (*)(void)) ofono_gprs_bearer_notify);
 | 
			
		||||
 | 
			
		||||
	if (step->check_func != NULL)
 | 
			
		||||
		((void (*)(struct ofono_gprs *, int)) step->check_func)(
 | 
			
		||||
								gprs, bearer);
 | 
			
		||||
 | 
			
		||||
	rilmodem_test_engine_next_step(gprs->engined);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ofono_gprs_set_cid_range(struct ofono_gprs *gprs,
 | 
			
		||||
				unsigned int min, unsigned int max)
 | 
			
		||||
{
 | 
			
		||||
	const struct rilmodem_test_step *step;
 | 
			
		||||
 | 
			
		||||
	step = rilmodem_test_engine_get_current_step(gprs->engined);
 | 
			
		||||
 | 
			
		||||
	g_assert(step->type == TST_EVENT_CALL);
 | 
			
		||||
	g_assert(step->call_func == (void (*)(void)) ofono_gprs_set_cid_range);
 | 
			
		||||
 | 
			
		||||
	if (step->check_func != NULL)
 | 
			
		||||
		((void (*)(struct ofono_gprs *, unsigned int, unsigned int))
 | 
			
		||||
					step->check_func)(gprs, min, max);
 | 
			
		||||
 | 
			
		||||
	rilmodem_test_engine_next_step(gprs->engined);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct ofono_modem *ofono_gprs_get_modem(struct ofono_gprs *gprs)
 | 
			
		||||
{
 | 
			
		||||
	return gprs->modem;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int ofono_modem_set_integer(struct ofono_modem *modem,
 | 
			
		||||
				const char *key, int value)
 | 
			
		||||
{
 | 
			
		||||
	const struct rilmodem_test_step *step;
 | 
			
		||||
 | 
			
		||||
	step = rilmodem_test_engine_get_current_step(modem->gprs->engined);
 | 
			
		||||
 | 
			
		||||
	g_assert(step->type == TST_EVENT_CALL);
 | 
			
		||||
	g_assert(step->call_func == (void (*)(void)) ofono_modem_set_integer);
 | 
			
		||||
 | 
			
		||||
	if (step->check_func != NULL)
 | 
			
		||||
		((void (*)(struct ofono_modem *, const char *, int))
 | 
			
		||||
					step->check_func)(modem, key, value);
 | 
			
		||||
 | 
			
		||||
	rilmodem_test_engine_next_step(modem->gprs->engined);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ofono_gprs_remove(struct ofono_gprs *gprs)
 | 
			
		||||
{
 | 
			
		||||
	const struct rilmodem_test_step *step;
 | 
			
		||||
 | 
			
		||||
	step = rilmodem_test_engine_get_current_step(gprs->engined);
 | 
			
		||||
 | 
			
		||||
	g_assert(step->type == TST_EVENT_CALL);
 | 
			
		||||
	g_assert(step->call_func == (void (*)(void)) ofono_gprs_remove);
 | 
			
		||||
 | 
			
		||||
	rilmodem_test_engine_next_step(gprs->engined);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * As all our architectures are little-endian except for
 | 
			
		||||
 * PowerPC, and the Binder wire-format differs slightly
 | 
			
		||||
 * depending on endian-ness, the following guards against test
 | 
			
		||||
 * failures when run on PowerPC.
 | 
			
		||||
 */
 | 
			
		||||
#if BYTE_ORDER == LITTLE_ENDIAN
 | 
			
		||||
 | 
			
		||||
/* REQUEST_DATA_CALL_LIST, seq 1 */
 | 
			
		||||
static const char parcel_req_data_call_list_1_1[] = {
 | 
			
		||||
	0x00, 0x00, 0x00, 0x08, 0x39, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * --- TEST 1 ---
 | 
			
		||||
 * Step 1: Driver sends REQUEST_DATA_CALL_LIST
 | 
			
		||||
 */
 | 
			
		||||
static const struct rilmodem_test_step steps_test_1[] = {
 | 
			
		||||
	{
 | 
			
		||||
		.type = TST_EVENT_RECEIVE,
 | 
			
		||||
		.parcel_data = parcel_req_data_call_list_1_1,
 | 
			
		||||
		.parcel_size = sizeof(parcel_req_data_call_list_1_1)
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct rilmodem_test_data test_1 = {
 | 
			
		||||
	.steps = steps_test_1,
 | 
			
		||||
	.num_steps = G_N_ELEMENTS(steps_test_1)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* REQUEST_DATA_CALL_LIST, seq 1 */
 | 
			
		||||
static const char parcel_req_data_call_list_2_1[] = {
 | 
			
		||||
	0x00, 0x00, 0x00, 0x08, 0x39, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* Response, no errors */
 | 
			
		||||
static const char parcel_rsp_data_call_list_2_2[] = {
 | 
			
		||||
	0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
 | 
			
		||||
	0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* REQUEST_DATA_REGISTRATION_STATE, seq 2 */
 | 
			
		||||
static const char parcel_req_data_registration_state_2_3[] = {
 | 
			
		||||
	0x00, 0x00, 0x00, 0x08, 0x15, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* Responso, no error, {unregistered,0xb08,0x10e1,GPRS,(null),4} */
 | 
			
		||||
static const char parcel_rsp_data_registration_state_2_4[] = {
 | 
			
		||||
	0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
 | 
			
		||||
	0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
 | 
			
		||||
	0x30, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x30, 0x00, 0x62, 0x00,
 | 
			
		||||
	0x30, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
 | 
			
		||||
	0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x31, 0x00, 0x30, 0x00,
 | 
			
		||||
	0x65, 0x00, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
 | 
			
		||||
	0x31, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00,
 | 
			
		||||
	0x34, 0x00, 0x00, 0x00
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void set_cid_range_check_2_5(struct ofono_gprs *gprs,
 | 
			
		||||
					unsigned int min, unsigned int max)
 | 
			
		||||
{
 | 
			
		||||
	g_assert(min == 1);
 | 
			
		||||
	g_assert(max == 2);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void gprs_cb_2_8(const struct ofono_error *error, void *data)
 | 
			
		||||
{
 | 
			
		||||
	struct ofono_gprs *gprs = data;
 | 
			
		||||
 | 
			
		||||
	g_assert(error->type == OFONO_ERROR_TYPE_NO_ERROR);
 | 
			
		||||
 | 
			
		||||
	rilmodem_test_engine_next_step(gprs->engined);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void call_set_attached_2_7(gpointer data)
 | 
			
		||||
{
 | 
			
		||||
	struct ofono_gprs *gprs = data;
 | 
			
		||||
 | 
			
		||||
	gprs_drv->set_attached(gprs, 0, gprs_cb_2_8, gprs);
 | 
			
		||||
 | 
			
		||||
	rilmodem_test_engine_next_step(gprs->engined);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * --- TEST 2 ---
 | 
			
		||||
 * Step 1: Driver sends REQUEST_DATA_CALL_LIST
 | 
			
		||||
 * Step 2: Harness answers with empty data call list
 | 
			
		||||
 * Step 3: Driver sends REQUEST_DATA_REGISTRATION_STATE
 | 
			
		||||
 * Step 4: Harness answers with status unregistered
 | 
			
		||||
 * Step 5: Driver calls ofono_gprs_set_cid_range
 | 
			
		||||
 * Step 6: Driver calls ofono_gprs_register
 | 
			
		||||
 * Step 7: Harness calls drv->set_attached(false)
 | 
			
		||||
 * Step 8: Driver calls the callback specified in step 7
 | 
			
		||||
 */
 | 
			
		||||
static const struct rilmodem_test_step steps_test_2[] = {
 | 
			
		||||
	{
 | 
			
		||||
		.type = TST_EVENT_RECEIVE,
 | 
			
		||||
		.parcel_data = parcel_req_data_call_list_2_1,
 | 
			
		||||
		.parcel_size = sizeof(parcel_req_data_call_list_2_1)
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		.type = TST_ACTION_SEND,
 | 
			
		||||
		.parcel_data = parcel_rsp_data_call_list_2_2,
 | 
			
		||||
		.parcel_size = sizeof(parcel_rsp_data_call_list_2_2)
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		.type = TST_EVENT_RECEIVE,
 | 
			
		||||
		.parcel_data = parcel_req_data_registration_state_2_3,
 | 
			
		||||
		.parcel_size = sizeof(parcel_req_data_registration_state_2_3)
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		.type = TST_ACTION_SEND,
 | 
			
		||||
		.parcel_data = parcel_rsp_data_registration_state_2_4,
 | 
			
		||||
		.parcel_size = sizeof(parcel_rsp_data_registration_state_2_4)
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		.type = TST_EVENT_CALL,
 | 
			
		||||
		.call_func = (void (*)(void)) ofono_gprs_set_cid_range,
 | 
			
		||||
		.check_func = (void (*)(void)) set_cid_range_check_2_5
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		.type = TST_EVENT_CALL,
 | 
			
		||||
		.call_func = (void (*)(void)) ofono_gprs_register,
 | 
			
		||||
		.check_func = NULL
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		.type = TST_ACTION_CALL,
 | 
			
		||||
		.call_action = call_set_attached_2_7,
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		.type = TST_EVENT_CALL,
 | 
			
		||||
		.call_func = (void (*)(void)) gprs_cb_2_8,
 | 
			
		||||
		.check_func = NULL
 | 
			
		||||
	},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct rilmodem_test_data test_2 = {
 | 
			
		||||
	.steps = steps_test_2,
 | 
			
		||||
	.num_steps = G_N_ELEMENTS(steps_test_2)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void gprs_cb_3_8(const struct ofono_error *error, void *data)
 | 
			
		||||
{
 | 
			
		||||
	struct ofono_gprs *gprs = data;
 | 
			
		||||
 | 
			
		||||
	g_assert(error->type == OFONO_ERROR_TYPE_NO_ERROR);
 | 
			
		||||
 | 
			
		||||
	rilmodem_test_engine_next_step(gprs->engined);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void call_set_attached_3_7(gpointer data)
 | 
			
		||||
{
 | 
			
		||||
	struct ofono_gprs *gprs = data;
 | 
			
		||||
 | 
			
		||||
	gprs_drv->set_attached(gprs, 1, gprs_cb_3_8, gprs);
 | 
			
		||||
 | 
			
		||||
	rilmodem_test_engine_next_step(gprs->engined);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * --- TEST 3 ---
 | 
			
		||||
 * Steps 1-6: Same as in test 2
 | 
			
		||||
 * Step 7: Harness calls drv->set_attached(true)
 | 
			
		||||
 * Step 8: Driver calls the callback specified in step 7
 | 
			
		||||
 */
 | 
			
		||||
static const struct rilmodem_test_step steps_test_3[] = {
 | 
			
		||||
	{
 | 
			
		||||
		.type = TST_EVENT_RECEIVE,
 | 
			
		||||
		.parcel_data = parcel_req_data_call_list_2_1,
 | 
			
		||||
		.parcel_size = sizeof(parcel_req_data_call_list_2_1)
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		.type = TST_ACTION_SEND,
 | 
			
		||||
		.parcel_data = parcel_rsp_data_call_list_2_2,
 | 
			
		||||
		.parcel_size = sizeof(parcel_rsp_data_call_list_2_2)
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		.type = TST_EVENT_RECEIVE,
 | 
			
		||||
		.parcel_data = parcel_req_data_registration_state_2_3,
 | 
			
		||||
		.parcel_size = sizeof(parcel_req_data_registration_state_2_3)
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		.type = TST_ACTION_SEND,
 | 
			
		||||
		.parcel_data = parcel_rsp_data_registration_state_2_4,
 | 
			
		||||
		.parcel_size = sizeof(parcel_rsp_data_registration_state_2_4)
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		.type = TST_EVENT_CALL,
 | 
			
		||||
		.call_func = (void (*)(void)) ofono_gprs_set_cid_range,
 | 
			
		||||
		.check_func = (void (*)(void)) set_cid_range_check_2_5
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		.type = TST_EVENT_CALL,
 | 
			
		||||
		.call_func = (void (*)(void)) ofono_gprs_register,
 | 
			
		||||
		.check_func = NULL
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		.type = TST_ACTION_CALL,
 | 
			
		||||
		.call_action = call_set_attached_3_7,
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		.type = TST_EVENT_CALL,
 | 
			
		||||
		.call_func = (void (*)(void)) gprs_cb_3_8,
 | 
			
		||||
		.check_func = NULL
 | 
			
		||||
	},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct rilmodem_test_data test_3 = {
 | 
			
		||||
	.steps = steps_test_3,
 | 
			
		||||
	.num_steps = G_N_ELEMENTS(steps_test_3)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* REQUEST_DATA_REGISTRATION_STATE, seq 3 */
 | 
			
		||||
static const char parcel_req_registration_state_4_8[] = {
 | 
			
		||||
	0x00, 0x00, 0x00, 0x08, 0x15, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* Response, no error, {registered,0xb08,0x10e1,GPRS,(null),4} */
 | 
			
		||||
static const char parcel_rsp_registration_state_4_9[] = {
 | 
			
		||||
	0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
 | 
			
		||||
	0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
 | 
			
		||||
	0x31, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x30, 0x00, 0x62, 0x00,
 | 
			
		||||
	0x30, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
 | 
			
		||||
	0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x31, 0x00, 0x30, 0x00,
 | 
			
		||||
	0x65, 0x00, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
 | 
			
		||||
	0x31, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00,
 | 
			
		||||
	0x34, 0x00, 0x00, 0x00
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void reg_state_cb_4_12(const struct ofono_error *error,
 | 
			
		||||
							int status, void *data)
 | 
			
		||||
{
 | 
			
		||||
	struct ofono_gprs *gprs = data;
 | 
			
		||||
	const struct rilmodem_test_step *step;
 | 
			
		||||
 | 
			
		||||
	step = rilmodem_test_engine_get_current_step(gprs->engined);
 | 
			
		||||
 | 
			
		||||
	g_assert(step->type == TST_EVENT_CALL);
 | 
			
		||||
	g_assert(step->call_func == (void (*)(void)) reg_state_cb_4_12);
 | 
			
		||||
 | 
			
		||||
	g_assert(error->type == OFONO_ERROR_TYPE_NO_ERROR);
 | 
			
		||||
	/*
 | 
			
		||||
	 * Driver returns unregistered even though network state is attached
 | 
			
		||||
	 * because we did not set attach to true in this test case.
 | 
			
		||||
	 */
 | 
			
		||||
	g_assert(status == NETWORK_REGISTRATION_STATUS_NOT_REGISTERED);
 | 
			
		||||
 | 
			
		||||
	rilmodem_test_engine_next_step(gprs->engined);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void call_registration_status_4_7(gpointer data)
 | 
			
		||||
{
 | 
			
		||||
	struct ofono_gprs *gprs = data;
 | 
			
		||||
 | 
			
		||||
	gprs_drv->attached_status(gprs, reg_state_cb_4_12, gprs);
 | 
			
		||||
 | 
			
		||||
	rilmodem_test_engine_next_step(gprs->engined);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void set_integer_check_4_10(struct ofono_modem *modem,
 | 
			
		||||
						const char *key, int value)
 | 
			
		||||
{
 | 
			
		||||
	g_assert_cmpstr(key, ==, "RilDataRadioTechnology");
 | 
			
		||||
	g_assert(value == RADIO_TECH_GPRS);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void gprs_bearer_check_4_11(struct ofono_gprs *gprs, int bearer)
 | 
			
		||||
{
 | 
			
		||||
	g_assert(bearer == PACKET_BEARER_GPRS);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * --- TEST 4 ---
 | 
			
		||||
 * Steps 1-6: Same as in test 2
 | 
			
		||||
 * Step 7: Harness calls drv->registration_status
 | 
			
		||||
 * Step 8: Driver sends REQUEST_DATA_REGISTRATION_STATE
 | 
			
		||||
 * Step 9: Harness answers saying status is registered
 | 
			
		||||
 * Step 10: Driver calls ofono_modem_set_integer
 | 
			
		||||
 * Step 11: Driver calls ofono_gprs_bearer_notify(PACKET_BEARER_GPRS)
 | 
			
		||||
 * Step 12: Driver calls the callback specified in step 7
 | 
			
		||||
 */
 | 
			
		||||
static const struct rilmodem_test_step steps_test_4[] = {
 | 
			
		||||
	{
 | 
			
		||||
		.type = TST_EVENT_RECEIVE,
 | 
			
		||||
		.parcel_data = parcel_req_data_call_list_2_1,
 | 
			
		||||
		.parcel_size = sizeof(parcel_req_data_call_list_2_1)
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		.type = TST_ACTION_SEND,
 | 
			
		||||
		.parcel_data = parcel_rsp_data_call_list_2_2,
 | 
			
		||||
		.parcel_size = sizeof(parcel_rsp_data_call_list_2_2)
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		.type = TST_EVENT_RECEIVE,
 | 
			
		||||
		.parcel_data = parcel_req_data_registration_state_2_3,
 | 
			
		||||
		.parcel_size = sizeof(parcel_req_data_registration_state_2_3)
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		.type = TST_ACTION_SEND,
 | 
			
		||||
		.parcel_data = parcel_rsp_data_registration_state_2_4,
 | 
			
		||||
		.parcel_size = sizeof(parcel_rsp_data_registration_state_2_4)
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		.type = TST_EVENT_CALL,
 | 
			
		||||
		.call_func = (void (*)(void)) ofono_gprs_set_cid_range,
 | 
			
		||||
		.check_func = (void (*)(void)) set_cid_range_check_2_5
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		.type = TST_EVENT_CALL,
 | 
			
		||||
		.call_func = (void (*)(void)) ofono_gprs_register,
 | 
			
		||||
		.check_func = NULL
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		.type = TST_ACTION_CALL,
 | 
			
		||||
		.call_action = call_registration_status_4_7,
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		.type = TST_EVENT_RECEIVE,
 | 
			
		||||
		.parcel_data = parcel_req_registration_state_4_8,
 | 
			
		||||
		.parcel_size = sizeof(parcel_req_registration_state_4_8)
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		.type = TST_ACTION_SEND,
 | 
			
		||||
		.parcel_data = parcel_rsp_registration_state_4_9,
 | 
			
		||||
		.parcel_size = sizeof(parcel_rsp_registration_state_4_9)
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		.type = TST_EVENT_CALL,
 | 
			
		||||
		.call_func = (void (*)(void)) ofono_modem_set_integer,
 | 
			
		||||
		.check_func = (void (*)(void)) set_integer_check_4_10
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		.type = TST_EVENT_CALL,
 | 
			
		||||
		.call_func = (void (*)(void)) ofono_gprs_bearer_notify,
 | 
			
		||||
		.check_func = (void (*)(void)) gprs_bearer_check_4_11
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		.type = TST_EVENT_CALL,
 | 
			
		||||
		.call_func = (void (*)(void)) reg_state_cb_4_12,
 | 
			
		||||
		.check_func = NULL
 | 
			
		||||
	},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct rilmodem_test_data test_4 = {
 | 
			
		||||
	.steps = steps_test_4,
 | 
			
		||||
	.num_steps = G_N_ELEMENTS(steps_test_4)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED */
 | 
			
		||||
static const char parcel_ev_network_state_changed_5_9[] = {
 | 
			
		||||
	0x00, 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x00, 0xEA, 0x03, 0x00, 0x00
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* REQUEST_DATA_REGISTRATION_STATE, seq 3 */
 | 
			
		||||
static const char parcel_req_registration_state_5_10[] = {
 | 
			
		||||
	0x00, 0x00, 0x00, 0x08, 0x15, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* Response, no error, {registered,0xb08,0x10e1,GPRS,(null),4} */
 | 
			
		||||
static const char parcel_rsp_registration_state_5_11[] = {
 | 
			
		||||
	0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
 | 
			
		||||
	0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
 | 
			
		||||
	0x31, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x30, 0x00, 0x62, 0x00,
 | 
			
		||||
	0x30, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
 | 
			
		||||
	0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x31, 0x00, 0x30, 0x00,
 | 
			
		||||
	0x65, 0x00, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
 | 
			
		||||
	0x31, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00,
 | 
			
		||||
	0x34, 0x00, 0x00, 0x00
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void gprs_status_check_5_12(struct ofono_gprs *gprs, int status)
 | 
			
		||||
{
 | 
			
		||||
	g_assert(status == NETWORK_REGISTRATION_STATUS_REGISTERED);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void set_integer_check_5_13(struct ofono_modem *modem,
 | 
			
		||||
						const char *key, int value)
 | 
			
		||||
{
 | 
			
		||||
	g_assert_cmpstr(key, ==, "RilDataRadioTechnology");
 | 
			
		||||
	g_assert(value == RADIO_TECH_GPRS);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void gprs_bearer_check_5_14(struct ofono_gprs *gprs, int bearer)
 | 
			
		||||
{
 | 
			
		||||
	g_assert(bearer == PACKET_BEARER_GPRS);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * --- TEST 5 ---
 | 
			
		||||
 * Steps 1-8: Same as test 3
 | 
			
		||||
 * Step 9: Harness sends UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED
 | 
			
		||||
 * Step 10: Driver sends REQUEST_DATA_REGISTRATION_STATE
 | 
			
		||||
 * Step 11: Harness answers saying status is registered
 | 
			
		||||
 * Step 12: Driver calls ofono_gprs_status_notify(REGISTERED)
 | 
			
		||||
 * Step 13: Driver calls ofono_modem_set_integer
 | 
			
		||||
 * Step 14: Driver calls ofono_gprs_bearer_notify(PACKET_BEARER_GPRS)
 | 
			
		||||
 */
 | 
			
		||||
static const struct rilmodem_test_step steps_test_5[] = {
 | 
			
		||||
	{
 | 
			
		||||
		.type = TST_EVENT_RECEIVE,
 | 
			
		||||
		.parcel_data = parcel_req_data_call_list_2_1,
 | 
			
		||||
		.parcel_size = sizeof(parcel_req_data_call_list_2_1)
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		.type = TST_ACTION_SEND,
 | 
			
		||||
		.parcel_data = parcel_rsp_data_call_list_2_2,
 | 
			
		||||
		.parcel_size = sizeof(parcel_rsp_data_call_list_2_2)
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		.type = TST_EVENT_RECEIVE,
 | 
			
		||||
		.parcel_data = parcel_req_data_registration_state_2_3,
 | 
			
		||||
		.parcel_size = sizeof(parcel_req_data_registration_state_2_3)
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		.type = TST_ACTION_SEND,
 | 
			
		||||
		.parcel_data = parcel_rsp_data_registration_state_2_4,
 | 
			
		||||
		.parcel_size = sizeof(parcel_rsp_data_registration_state_2_4)
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		.type = TST_EVENT_CALL,
 | 
			
		||||
		.call_func = (void (*)(void)) ofono_gprs_set_cid_range,
 | 
			
		||||
		.check_func = (void (*)(void)) set_cid_range_check_2_5
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		.type = TST_EVENT_CALL,
 | 
			
		||||
		.call_func = (void (*)(void)) ofono_gprs_register,
 | 
			
		||||
		.check_func = NULL
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		.type = TST_ACTION_CALL,
 | 
			
		||||
		.call_action = call_set_attached_3_7,
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		.type = TST_EVENT_CALL,
 | 
			
		||||
		.call_func = (void (*)(void)) gprs_cb_3_8,
 | 
			
		||||
		.check_func = NULL
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		.type = TST_ACTION_SEND,
 | 
			
		||||
		.parcel_data = parcel_ev_network_state_changed_5_9,
 | 
			
		||||
		.parcel_size = sizeof(parcel_ev_network_state_changed_5_9)
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		.type = TST_EVENT_RECEIVE,
 | 
			
		||||
		.parcel_data = parcel_req_registration_state_5_10,
 | 
			
		||||
		.parcel_size = sizeof(parcel_req_registration_state_5_10)
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		.type = TST_ACTION_SEND,
 | 
			
		||||
		.parcel_data = parcel_rsp_registration_state_5_11,
 | 
			
		||||
		.parcel_size = sizeof(parcel_rsp_registration_state_5_11)
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		.type = TST_EVENT_CALL,
 | 
			
		||||
		.call_func = (void (*)(void)) ofono_gprs_status_notify,
 | 
			
		||||
		.check_func = (void (*)(void)) gprs_status_check_5_12
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		.type = TST_EVENT_CALL,
 | 
			
		||||
		.call_func = (void (*)(void)) ofono_modem_set_integer,
 | 
			
		||||
		.check_func = (void (*)(void)) set_integer_check_5_13
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		.type = TST_EVENT_CALL,
 | 
			
		||||
		.call_func = (void (*)(void)) ofono_gprs_bearer_notify,
 | 
			
		||||
		.check_func = (void (*)(void)) gprs_bearer_check_5_14
 | 
			
		||||
	},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct rilmodem_test_data test_5 = {
 | 
			
		||||
	.steps = steps_test_5,
 | 
			
		||||
	.num_steps = G_N_ELEMENTS(steps_test_5)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void server_connect_cb(gpointer data)
 | 
			
		||||
{
 | 
			
		||||
	struct ofono_gprs *gprs = data;
 | 
			
		||||
	int retval;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * This triggers the first event from the gprs atom, which is a request
 | 
			
		||||
	 * to retrieve currently active data calls. Test steps must start from
 | 
			
		||||
	 * there.
 | 
			
		||||
	 */
 | 
			
		||||
	retval = gprs_drv->probe(gprs, OFONO_RIL_VENDOR_AOSP, gprs->ril);
 | 
			
		||||
	g_assert(retval == 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * This unit test:
 | 
			
		||||
 *  - does some test data setup
 | 
			
		||||
 *  - configures a dummy server socket
 | 
			
		||||
 *  - creates a new gril client instance
 | 
			
		||||
 *    - triggers a connect to the dummy
 | 
			
		||||
 *      server socket
 | 
			
		||||
 *  - starts the test engine
 | 
			
		||||
 */
 | 
			
		||||
static void test_function(gconstpointer data)
 | 
			
		||||
{
 | 
			
		||||
	const struct rilmodem_test_data *test_data = data;
 | 
			
		||||
	struct ofono_gprs *gprs;
 | 
			
		||||
	struct ofono_modem *modem;
 | 
			
		||||
 | 
			
		||||
	ril_gprs_init();
 | 
			
		||||
 | 
			
		||||
	gprs = g_malloc0(sizeof(*gprs));
 | 
			
		||||
	modem = g_malloc0(sizeof(*modem));
 | 
			
		||||
 | 
			
		||||
	modem->gprs = gprs;
 | 
			
		||||
	gprs->modem = modem;
 | 
			
		||||
 | 
			
		||||
	gprs->engined = rilmodem_test_engine_create(&server_connect_cb,
 | 
			
		||||
							test_data, gprs);
 | 
			
		||||
 | 
			
		||||
	gprs->ril = g_ril_new(rilmodem_test_engine_get_socket_name(gprs->engined),
 | 
			
		||||
							OFONO_RIL_VENDOR_AOSP);
 | 
			
		||||
	g_assert(gprs->ril != NULL);
 | 
			
		||||
 | 
			
		||||
	/* Perform test */
 | 
			
		||||
	rilmodem_test_engine_start(gprs->engined);
 | 
			
		||||
 | 
			
		||||
	gprs_drv->remove(gprs);
 | 
			
		||||
	g_ril_unref(gprs->ril);
 | 
			
		||||
	g_free(modem);
 | 
			
		||||
	g_free(gprs);
 | 
			
		||||
 | 
			
		||||
	rilmodem_test_engine_remove(gprs->engined);
 | 
			
		||||
 | 
			
		||||
	ril_gprs_exit();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
int main(int argc, char **argv)
 | 
			
		||||
{
 | 
			
		||||
	g_test_init(&argc, &argv, NULL);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * As all our architectures are little-endian except for
 | 
			
		||||
 * PowerPC, and the Binder wire-format differs slightly
 | 
			
		||||
 * depending on endian-ness, the following guards against test
 | 
			
		||||
 * failures when run on PowerPC.
 | 
			
		||||
 */
 | 
			
		||||
#if BYTE_ORDER == LITTLE_ENDIAN
 | 
			
		||||
	g_test_add_data_func("/test-rilmodem-gprs/1", &test_1, test_function);
 | 
			
		||||
	g_test_add_data_func("/test-rilmodem-gprs/2", &test_2, test_function);
 | 
			
		||||
	g_test_add_data_func("/test-rilmodem-gprs/3", &test_3, test_function);
 | 
			
		||||
	g_test_add_data_func("/test-rilmodem-gprs/4", &test_4, test_function);
 | 
			
		||||
	g_test_add_data_func("/test-rilmodem-gprs/5", &test_5, test_function);
 | 
			
		||||
#endif
 | 
			
		||||
	return g_test_run();
 | 
			
		||||
}
 | 
			
		||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user