Merge remote-tracking branch 'cros/upstream' into 'cros/master'
Contains the following patches:
4a0de586 base-call: if start() fails, always terminated (Aleksander Morgado)
2c0281aa call: disallow non-emergency calls when in emergency-only state (Aleksander Morgado)
d6f9d5e9 sim: load emergency numbers from EF_ECC (Aleksander Morgado)
1f6c0069 api,sim: new 'Emergency Numbers' property (Aleksander Morgado)
45cf1ba2 cinterion: don't cache voice support check AT commands (Aleksander Morgado)
57e78413 iface-modem-voice: always completely reinitialize the interface (Aleksander Morgado)
98066d24 broadband-modem: don't cache voice support check AT commands (Aleksander Morgado)
5fef1417 broadband-modem: ignore SIM-related errors in voice support check (Aleksander Morgado)
6347a7d7 base-call: catch terminated errors before ATD replies (Aleksander Morgado)
eaf66547 broadband-modem: keep ports context open while in-call (Aleksander Morgado)
c99f767f broadband-modem: reorder generic port context logic in sources (Aleksander Morgado)
ba1f3af3 broadband-modem: new generic ports_context_open() (Aleksander Morgado)
7c8d0d17 broadband-modem: skip redundant ATE0/AT+CMEE=1 settings (Aleksander Morgado)
657833a4 voice,api: new 'EmergencyOnly' boolean flag (Aleksander Morgado)
79718443 iface-modem-voice: all methods available even if not enabled (Aleksander Morgado)
ed3a1264 iface-modem-voice: call list setup during initialization (Aleksander Morgado)
00a39cd0 broadband-modem: voice interface available in failed/locked state (Aleksander Morgado)
27405a44 broadband-modem: new initialization step when failed/locked (Aleksander Morgado)
d555c4c4 iface-modem-simple: allow single ongoing Connect() attempt (Aleksander Morgado)
f228d0dd base-bearer,iface-modem-simple: log user requests to connect/disconnect (Aleksander Morgado)
667d1613 x22x: add support for the Alcatel X602D (Aleksander Morgado)
407cfa0c x22x: ignore unhandled URCs in the Alcatel X602D (Aleksander Morgado)
f30d3d46 ci: ignore errors on apt update (Aleksander Morgado)
5316e9e4 simtech: handle 'MISSED_CALL' URCs (Aleksander Morgado)
eb66e8ae simtech: setup USB audio channel when in-call (Aleksander Morgado)
e3a1364d core: allow flagging ports as 'audio' (Aleksander Morgado)
d61cb4a2 simtech: handle '+RXDTMF' URCs reporting DTMF tones (Aleksander Morgado)
345922ca simtech: handle non-standard '+CRING' URCs (Aleksander Morgado)
395b2217 simtech: handle 'VOICE CALL' URCs (Aleksander Morgado)
1a17996c iface-modem-voice: ignore unknown calls reported as terminated (Aleksander Morgado)
089faef8 modem-helpers: support reporting 'terminated' call state in +CLCC (Aleksander Morgado)
89c9566e simtech: implement +CLCC URC based call list management (Aleksander Morgado)
b99597b5 tests,helpers: minor alignment fix (Aleksander Morgado)
d5d0ed0b tests: print MM logs only on verbose test mode (Aleksander Morgado)
03223fe7 tests,sms: print PDUs only on verbose test mode (Aleksander Morgado)
3b18d21b tests: avoid g_print() and use g_debug() instead (Aleksander Morgado)
cc4e7f6c shared-qmi: fix NAS SSP support check during supported caps loading (Aleksander Morgado)
c8d715e5 api: set enum values not part of the API as private (Aleksander Morgado)
33140e1f mm-broadband-modem-mbim: fix incorrect log message (Eric Caruso)
6cbeb96a simtech: +CNSMOD value may have multiple digits (Aleksander Morgado)
e1d18afe simtech: add support for reporting LTE (Aleksander Morgado)
61f3c3c8 simtech: rework access tech value mapping (Aleksander Morgado)
7fcefc7a simtech: rework enabling/disabling unsolicited events (Aleksander Morgado)
1277ebb4 iface-modem: allow plugins to disable access technology polling (Aleksander Morgado)
45a238bc iface-modem: allow disabling signal quality polling during runtime (Aleksander Morgado)
c820e02f simtech: enable +CSQ URC support (Aleksander Morgado)
765f26a4 iface-modem: don't log error if it's in progress (Aleksander Morgado)
1f6f9eec simtech: keep access tech URC regex in private struct (Aleksander Morgado)
c98a1a9d simtech: disable CMER/CIND support explicitly (Aleksander Morgado)
feb6c826 broadband-modem: allow disabling +CIND URC setup (Aleksander Morgado)
81795f30 simtech: implement GPS support with AT+CGPS (Aleksander Morgado)
583d53a7 simtech: port type hints for the SIM7000/SIM7600 family (Aleksander Morgado)
eeb1f739 simtech: remove unused ID_MM_SIMTECH_TAGGED tag (Aleksander Morgado)
55c3f7d3 systemd: always start MM after polkit service if enabling policy (Aleksander Morgado)
803c7705 broadband-modem-qmi: fix when >1 PRI images for the same modem image (Aleksander Morgado)
227c2907 mmcli,firmware: don't use tabs when printing human-friendly list (Aleksander Morgado)
6977b41a broadband-modem-qmi: prefer ASCII unique IDs (Aleksander Morgado)
a55543d1 broadband-modem-qmi: fix listing images when 'Get Stored Image Info' is unsupported (Aleksander Morgado)
1b29f752 broadband-modem-qmi: move pri/modem pair list building to separate method (Aleksander Morgado)
7986b273 broadband-modem-qmi: move pri/modem list index lookup to separate method (Aleksander Morgado)
5b8da2e1 broadband-modem-qmi: add note about index_of_running_image known issue (Aleksander Morgado)
66192288 broadband-modem-qmi: fix minor typo in comment (Aleksander Morgado)
3f15293a daemon: register G_IO_ERROR_CANCELLED as "Cancelled" in DBus (Aleksander Morgado)
cf0d3f36 iface-modem: avoid using MM_CORE_ERROR_CANCELLED (Aleksander Morgado)
651bfd62 port-serial: avoid using MM_CORE_ERROR_CANCELLED (Aleksander Morgado)
fa453a17 iface-modem-voice: avoid using MM_CORE_ERROR_CANCELLED (Aleksander Morgado)
cff3be23 broadband-modem: avoid using MM_CORE_ERROR_CANCELLED (Aleksander Morgado)
7974933d broadband-modem-mbim: avoid using MM_CORE_ERROR_CANCELLED (Aleksander Morgado)
c0e1bde0 base-modem-at: avoid using MM_CORE_ERROR_CANCELLED (Aleksander Morgado)
def5c76c huawei,bearer: avoid using MM_CORE_ERROR_CANCELLED (Aleksander Morgado)
6de9c8cb base-bearer: avoid using MM_CORE_ERROR_CANCELLED (Aleksander Morgado)
15b81560 iface-modem-simple: fix Simple.Disconnect() when bearer path given (Aleksander Morgado)
3a9c5531 libmm-glib,oma: avoid plural in type (Aleksander Morgado)
19652e10 libmm-glib,call: fix typo in documentation (Aleksander Morgado)
a64223ca po: update Polish translation (Piotr Drąg)
0a85254d cli: fix typo when looking for a specific call fails (Aleksander Morgado)
4352c273 po: updated after new Time policy setup (Aleksander Morgado)
8a652179 policy: USSD policy requires user authentication in strict mode (Aleksander Morgado)
958c2434 polkit,conf: trivial comment update regarding Signal.Setup() (Aleksander Morgado)
1cd24a31 iface-modem-firmware: use the explicit Firmware policy (Aleksander Morgado)
110f6fd0 polkit,conf: add missing firmware management methods (Aleksander Morgado)
2e5af74d polkit,conf: add missing OMA methods (Aleksander Morgado)
7a7b3aa5 polkit,time: protect GetNetworkTime() with a new 'Time' policy rule (Aleksander Morgado)
be2500b0 polkit,conf: add missing supplementary voice service methods (Aleksander Morgado)
01acd9a0 polkit,conf: add missing InjectAssistanceData (Aleksander Morgado)
9e24d1c1 polkit,conf: add missing SetInitialEpsBearerSettings (Aleksander Morgado)
614c7fbc polkit,conf: add missing SetEpsUeModeOperation (Aleksander Morgado)
f2182a73 polkit,conf: add missing SetCurrentCapabilities (Aleksander Morgado)
3696a009 polkit,conf: add missing SetPowerState (Aleksander Morgado)
d3e75eec policy,conf: use SetCurrentBands instead of SetBands (Aleksander Morgado)
e21e7ddf policy: Use SetCurrentModes instead of SetAllowedModes (Mohammed Sadiq)
79a39656 broadband-modem: shutdown firmware interface on dispose() (Aleksander Morgado)
dcf50efd ublox: fix calling setup_unsolicited_events_finish() (Aleksander Morgado)
a1148f87 cinterion: fix calling setup_unsolicited_events_finish() (Aleksander Morgado)
c8af22ab cli,messaging: trivial fix in comment (Aleksander Morgado)
6c9027b2 docs,libmm-glib: add missing references to call waiting query/setup (Aleksander Morgado)
16145c29 sms-part-3gpp: SMS timestamp in ISO8601 format (amol.lad)
Change-Id: I81f3c5805b6bd8adab694e3440a526b9e4e435a4
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index fe7068b..6727160 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -4,7 +4,7 @@
- build
before_script:
- - apt update
+ - apt update || true
- apt -y install autoconf automake libtool libglib2.0-dev libgudev-1.0-dev libgettextpo-dev autopoint xsltproc dbus
build-no-qmi:
diff --git a/cli/mmcli-common.c b/cli/mmcli-common.c
index c149927..1c63d84 100644
--- a/cli/mmcli-common.c
+++ b/cli/mmcli-common.c
@@ -1485,7 +1485,7 @@
manager = mmcli_get_manager_sync (connection);
modems = g_dbus_object_manager_get_objects (G_DBUS_OBJECT_MANAGER (manager));
if (!modems) {
- g_printerr ("error: couldn't find sms at '%s': 'no modems found'\n",
+ g_printerr ("error: couldn't find call at '%s': 'no modems found'\n",
call_path);
exit (EXIT_FAILURE);
}
diff --git a/cli/mmcli-modem-messaging.c b/cli/mmcli-modem-messaging.c
index 0f38e97..e56d9bc 100644
--- a/cli/mmcli-modem-messaging.c
+++ b/cli/mmcli-modem-messaging.c
@@ -437,7 +437,7 @@
ensure_modem_messaging ();
- /* Request to get location status? */
+ /* Request to get messaging status? */
if (status_flag) {
g_debug ("Printing messaging status...");
print_messaging_status ();
diff --git a/cli/mmcli-modem-voice.c b/cli/mmcli-modem-voice.c
index 87c27be..878984b 100644
--- a/cli/mmcli-modem-voice.c
+++ b/cli/mmcli-modem-voice.c
@@ -47,6 +47,7 @@
static Context *ctx;
/* Options */
+static gboolean status_flag;
static gboolean list_flag;
static gchar *create_str;
static gchar *delete_str;
@@ -59,6 +60,10 @@
static gboolean call_waiting_query_flag;
static GOptionEntry entries[] = {
+ { "voice-status", 0, 0, G_OPTION_ARG_NONE, &status_flag,
+ "Show status of voice support.",
+ NULL
+ },
{ "voice-list-calls", 0, 0, G_OPTION_ARG_NONE, &list_flag,
"List calls available in a given modem",
NULL
@@ -126,7 +131,8 @@
if (checked)
return !!n_actions;
- n_actions = (list_flag +
+ n_actions = (status_flag +
+ list_flag +
!!create_str +
!!delete_str +
hold_and_accept_flag +
@@ -142,6 +148,9 @@
exit (EXIT_FAILURE);
}
+ if (status_flag)
+ mmcli_force_sync_operation ();
+
checked = TRUE;
return !!n_actions;
}
@@ -168,11 +177,6 @@
static void
ensure_modem_voice (void)
{
- if (mm_modem_get_state (mm_object_peek_modem (ctx->object)) < MM_MODEM_STATE_ENABLED) {
- g_printerr ("error: modem not enabled yet\n");
- exit (EXIT_FAILURE);
- }
-
if (!ctx->modem_voice) {
g_printerr ("error: modem has no voice capabilities\n");
exit (EXIT_FAILURE);
@@ -203,6 +207,13 @@
}
static void
+print_voice_status (void)
+{
+ mmcli_output_string (MMC_F_VOICE_EMERGENCY_ONLY, mm_modem_voice_get_emergency_only (ctx->modem_voice) ? "yes" : "no");
+ mmcli_output_dump ();
+}
+
+static void
output_call_info (MMCall *call)
{
gchar *extra;
@@ -493,6 +504,9 @@
ensure_modem_voice ();
+ if (status_flag)
+ g_assert_not_reached ();
+
/* Request to list call? */
if (list_flag) {
g_debug ("Asynchronously listing calls in modem...");
@@ -639,6 +653,13 @@
ensure_modem_voice ();
+ /* Request to get voice status? */
+ if (status_flag) {
+ g_debug ("Printing voice status...");
+ print_voice_status ();
+ return;
+ }
+
/* Request to list the call? */
if (list_flag) {
GList *result;
diff --git a/cli/mmcli-output.c b/cli/mmcli-output.c
index 4fd9db3..338e658 100644
--- a/cli/mmcli-output.c
+++ b/cli/mmcli-output.c
@@ -66,6 +66,7 @@
[MMC_S_MODEM_LOCATION_CDMABS] = { "CDMA BS" },
[MMC_S_MODEM_FIRMWARE] = { "Firmware" },
[MMC_S_MODEM_FIRMWARE_FASTBOOT] = { "Fastboot settings" },
+ [MMC_S_MODEM_VOICE] = { "Voice" },
[MMC_S_BEARER_GENERAL] = { "General" },
[MMC_S_BEARER_STATUS] = { "Status" },
[MMC_S_BEARER_PROPERTIES] = { "Properties" },
@@ -196,6 +197,7 @@
[MMC_F_FIRMWARE_DEVICE_IDS] = { "modem.firmware.device-ids", "device ids", MMC_S_MODEM_FIRMWARE, },
[MMC_F_FIRMWARE_VERSION] = { "modem.firmware.version", "version", MMC_S_MODEM_FIRMWARE, },
[MMC_F_FIRMWARE_FASTBOOT_AT] = { "modem.firmware.fastboot.at", "at command", MMC_S_MODEM_FIRMWARE_FASTBOOT, },
+ [MMC_F_VOICE_EMERGENCY_ONLY] = { "modem.voice.emergency-only", "emergency only", MMC_S_MODEM_VOICE, },
[MMC_F_BEARER_GENERAL_DBUS_PATH] = { "bearer.dbus-path", "dbus path", MMC_S_BEARER_GENERAL, },
[MMC_F_BEARER_GENERAL_TYPE] = { "bearer.type", "type", MMC_S_BEARER_GENERAL, },
[MMC_F_BEARER_STATUS_CONNECTED] = { "bearer.status.connected", "connected", MMC_S_BEARER_STATUS, },
@@ -256,6 +258,7 @@
[MMC_F_SIM_PROPERTIES_ICCID] = { "sim.properties.iccid", "iccid", MMC_S_SIM_PROPERTIES, },
[MMC_F_SIM_PROPERTIES_OPERATOR_ID] = { "sim.properties.operator-code", "operator id", MMC_S_SIM_PROPERTIES, },
[MMC_F_SIM_PROPERTIES_OPERATOR_NAME] = { "sim.properties.operator-name", "operator name", MMC_S_SIM_PROPERTIES, },
+ [MMC_F_SIM_PROPERTIES_EMERGENCY_NUMBERS] = { "sim.properties.emergency-numbers", "emergency numbers", MMC_S_SIM_PROPERTIES, },
[MMC_F_MODEM_LIST_DBUS_PATH] = { "modem-list", "modems", MMC_S_UNKNOWN, },
[MMC_F_SMS_LIST_DBUS_PATH] = { "modem.messaging.sms", "sms messages", MMC_S_UNKNOWN, },
[MMC_F_CALL_LIST_DBUS_PATH] = { "modem.voice.call", "calls", MMC_S_UNKNOWN, },
@@ -622,21 +625,21 @@
gboolean selected)
{
g_ptr_array_add (array, g_strdup (mm_firmware_properties_get_unique_id (props)));
- g_ptr_array_add (array, g_strdup_printf ("\tcurrent: %s", selected ? "yes" : "no"));
+ g_ptr_array_add (array, g_strdup_printf (" current: %s", selected ? "yes" : "no"));
if (mm_firmware_properties_get_image_type (props) == MM_FIRMWARE_IMAGE_TYPE_GOBI) {
const gchar *aux;
if ((aux = mm_firmware_properties_get_gobi_pri_version (props)) != NULL)
- g_ptr_array_add (array, g_strdup_printf ("\tgobi pri version: %s", aux));
+ g_ptr_array_add (array, g_strdup_printf (" gobi pri version: %s", aux));
if ((aux = mm_firmware_properties_get_gobi_pri_info (props)) != NULL)
- g_ptr_array_add (array, g_strdup_printf ("\tgobi pri info: %s", aux));
+ g_ptr_array_add (array, g_strdup_printf (" gobi pri info: %s", aux));
if ((aux = mm_firmware_properties_get_gobi_boot_version (props)) != NULL)
- g_ptr_array_add (array, g_strdup_printf ("\tgobi boot version: %s", aux));
+ g_ptr_array_add (array, g_strdup_printf (" gobi boot version: %s", aux));
if ((aux = mm_firmware_properties_get_gobi_pri_unique_id (props)) != NULL)
- g_ptr_array_add (array, g_strdup_printf ("\tgobi pri unique id: %s", aux));
+ g_ptr_array_add (array, g_strdup_printf (" gobi pri unique id: %s", aux));
if ((aux = mm_firmware_properties_get_gobi_modem_unique_id (props)) != NULL)
- g_ptr_array_add (array, g_strdup_printf ("\tgobi modem unique id: %s", aux));
+ g_ptr_array_add (array, g_strdup_printf (" gobi modem unique id: %s", aux));
}
}
diff --git a/cli/mmcli-output.h b/cli/mmcli-output.h
index 135d429..bd7b317 100644
--- a/cli/mmcli-output.h
+++ b/cli/mmcli-output.h
@@ -63,6 +63,7 @@
MMC_S_MODEM_LOCATION_CDMABS,
MMC_S_MODEM_FIRMWARE,
MMC_S_MODEM_FIRMWARE_FASTBOOT,
+ MMC_S_MODEM_VOICE,
MMC_S_BEARER_GENERAL,
MMC_S_BEARER_STATUS,
MMC_S_BEARER_PROPERTIES,
@@ -209,6 +210,8 @@
MMC_F_FIRMWARE_DEVICE_IDS,
MMC_F_FIRMWARE_VERSION,
MMC_F_FIRMWARE_FASTBOOT_AT,
+ /* Voice section */
+ MMC_F_VOICE_EMERGENCY_ONLY,
/* Bearer general section */
MMC_F_BEARER_GENERAL_DBUS_PATH,
MMC_F_BEARER_GENERAL_TYPE,
@@ -272,6 +275,7 @@
MMC_F_SIM_PROPERTIES_ICCID,
MMC_F_SIM_PROPERTIES_OPERATOR_ID,
MMC_F_SIM_PROPERTIES_OPERATOR_NAME,
+ MMC_F_SIM_PROPERTIES_EMERGENCY_NUMBERS,
/* Lists */
MMC_F_MODEM_LIST_DBUS_PATH,
MMC_F_SMS_LIST_DBUS_PATH,
diff --git a/cli/mmcli-sim.c b/cli/mmcli-sim.c
index d31f07c..e7f885e 100644
--- a/cli/mmcli-sim.c
+++ b/cli/mmcli-sim.c
@@ -158,11 +158,12 @@
static void
print_sim_info (MMSim *sim)
{
- mmcli_output_string (MMC_F_SIM_GENERAL_DBUS_PATH, mm_sim_get_path (sim));
- mmcli_output_string (MMC_F_SIM_PROPERTIES_IMSI, mm_sim_get_imsi (sim));
- mmcli_output_string (MMC_F_SIM_PROPERTIES_ICCID, mm_sim_get_identifier (sim));
- mmcli_output_string (MMC_F_SIM_PROPERTIES_OPERATOR_ID, mm_sim_get_operator_identifier (sim));
- mmcli_output_string (MMC_F_SIM_PROPERTIES_OPERATOR_NAME, mm_sim_get_operator_name (sim));
+ mmcli_output_string (MMC_F_SIM_GENERAL_DBUS_PATH, mm_sim_get_path (sim));
+ mmcli_output_string (MMC_F_SIM_PROPERTIES_IMSI, mm_sim_get_imsi (sim));
+ mmcli_output_string (MMC_F_SIM_PROPERTIES_ICCID, mm_sim_get_identifier (sim));
+ mmcli_output_string (MMC_F_SIM_PROPERTIES_OPERATOR_ID, mm_sim_get_operator_identifier (sim));
+ mmcli_output_string (MMC_F_SIM_PROPERTIES_OPERATOR_NAME, mm_sim_get_operator_name (sim));
+ mmcli_output_string_array (MMC_F_SIM_PROPERTIES_EMERGENCY_NUMBERS, (const gchar **) mm_sim_get_emergency_numbers (sim), FALSE);
mmcli_output_dump ();
}
diff --git a/configure.ac b/configure.ac
index d3c9beb..667fb9d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -288,6 +288,7 @@
with_polkit=strict
fi
+MM_POLKIT_SERVICE=""
if test "x$with_polkit" != "xno"; then
if test "x$have_polkit" = "xno"; then
AC_MSG_ERROR(PolicyKit development headers are required)
@@ -296,9 +297,11 @@
case "x$with_polkit" in
"xpermissive")
MM_DEFAULT_USER_POLICY="yes"
+ MM_POLKIT_SERVICE="polkit.service"
;;
"xstrict")
MM_DEFAULT_USER_POLICY="auth_self_keep"
+ MM_POLKIT_SERVICE="polkit.service"
;;
*)
AC_MSG_ERROR([Wrong value for --with-polkit: $with_polkit])
@@ -311,6 +314,7 @@
AC_SUBST(MM_DEFAULT_USER_POLICY)
fi
+AC_SUBST(MM_POLKIT_SERVICE)
AM_CONDITIONAL(WITH_POLKIT, [test "x$with_polkit" != "xno"])
dnl-----------------------------------------------------------------------------
diff --git a/data/Makefile.am b/data/Makefile.am
index ee05bdf..447cb3d 100644
--- a/data/Makefile.am
+++ b/data/Makefile.am
@@ -5,7 +5,8 @@
-e 's|@sbindir[@]|$(sbindir)|g' \
-e 's|@sysconfdir[@]|$(sysconfdir)|g' \
-e 's|@localstatedir[@]|$(localstatedir)|g' \
- -e 's|@libexecdir[@]|$(libexecdir)|g'
+ -e 's|@libexecdir[@]|$(libexecdir)|g' \
+ -e 's|@MM_POLKIT_SERVICE[@]|$(MM_POLKIT_SERVICE)|g'
# DBus Service file
diff --git a/data/ModemManager.service.in b/data/ModemManager.service.in
index 420d22b..23bf809 100644
--- a/data/ModemManager.service.in
+++ b/data/ModemManager.service.in
@@ -1,5 +1,7 @@
[Unit]
Description=Modem Manager
+After=@MM_POLKIT_SERVICE@
+Requires=@MM_POLKIT_SERVICE@
[Service]
Type=dbus
diff --git a/data/org.freedesktop.ModemManager1.conf.polkit b/data/org.freedesktop.ModemManager1.conf.polkit
index 14240ea..8087da6 100644
--- a/data/org.freedesktop.ModemManager1.conf.polkit
+++ b/data/org.freedesktop.ModemManager1.conf.polkit
@@ -53,6 +53,10 @@
<allow send_destination="org.freedesktop.ModemManager1"
send_interface="org.freedesktop.ModemManager1.Modem"
+ send_member="SetPowerState"/>
+
+ <allow send_destination="org.freedesktop.ModemManager1"
+ send_interface="org.freedesktop.ModemManager1.Modem"
send_member="Reset"/>
<allow send_destination="org.freedesktop.ModemManager1"
@@ -61,16 +65,30 @@
<allow send_destination="org.freedesktop.ModemManager1"
send_interface="org.freedesktop.ModemManager1.Modem"
- send_member="SetAllowedModes"/>
+ send_member="SetCurrentCapabilities"/>
<allow send_destination="org.freedesktop.ModemManager1"
send_interface="org.freedesktop.ModemManager1.Modem"
- send_member="SetBands"/>
+ send_member="SetCurrentModes"/>
+
+ <allow send_destination="org.freedesktop.ModemManager1"
+ send_interface="org.freedesktop.ModemManager1.Modem"
+ send_member="SetCurrentBands"/>
<allow send_destination="org.freedesktop.ModemManager1"
send_interface="org.freedesktop.ModemManager1.Modem"
send_member="Command"/>
+ <!-- org.freedesktop.ModemManager1.Modem.Firmware.xml -->
+
+ <!-- Protected by the Device.Control policy rule -->
+ <allow send_destination="org.freedesktop.ModemManager1"
+ send_interface="org.freedesktop.ModemManager1.Modem.Firmware"
+ send_member="List"/>
+ <allow send_destination="org.freedesktop.ModemManager1"
+ send_interface="org.freedesktop.ModemManager1.Modem.Firmware"
+ send_member="Select"/>
+
<!-- org.freedesktop.ModemManager1.Modem.Simple.xml -->
<!-- Allowed for everyone -->
@@ -98,6 +116,14 @@
send_interface="org.freedesktop.ModemManager1.Modem.Modem3gpp"
send_member="Scan"/>
+ <allow send_destination="org.freedesktop.ModemManager1"
+ send_interface="org.freedesktop.ModemManager1.Modem.Modem3gpp"
+ send_member="SetEpsUeModeOperation"/>
+
+ <allow send_destination="org.freedesktop.ModemManager1"
+ send_interface="org.freedesktop.ModemManager1.Modem.Modem3gpp"
+ send_member="SetInitialEpsBearerSettings"/>
+
<!-- org.freedesktop.ModemManager1.Modem.ModemCdma.xml -->
<!-- Protected by the Device.Control policy rule -->
@@ -109,6 +135,25 @@
send_interface="org.freedesktop.ModemManager1.Modem.ModemCdma"
send_member="ActivateManual"/>
+ <!-- org.freedesktop.ModemManager1.Modem.Oma.xml -->
+
+ <!-- Protected by the Device.Control policy rule -->
+ <allow send_destination="org.freedesktop.ModemManager1"
+ send_interface="org.freedesktop.ModemManager1.Modem.Oma"
+ send_member="Setup"/>
+
+ <allow send_destination="org.freedesktop.ModemManager1"
+ send_interface="org.freedesktop.ModemManager1.Modem.Oma"
+ send_member="StartClientInitiatedSession"/>
+
+ <allow send_destination="org.freedesktop.ModemManager1"
+ send_interface="org.freedesktop.ModemManager1.Modem.Oma"
+ send_member="AcceptNetworkInitiatedSession"/>
+
+ <allow send_destination="org.freedesktop.ModemManager1"
+ send_interface="org.freedesktop.ModemManager1.Modem.Oma"
+ send_member="CancelSession"/>
+
<!-- org.freedesktop.ModemManager1.Sim.xml -->
<!-- Protected by the Device.Control policy rule -->
@@ -167,6 +212,10 @@
<allow send_destination="org.freedesktop.ModemManager1"
send_interface="org.freedesktop.ModemManager1.Modem.Location"
+ send_member="InjectAssistanceData"/>
+
+ <allow send_destination="org.freedesktop.ModemManager1"
+ send_interface="org.freedesktop.ModemManager1.Modem.Location"
send_member="SetGpsRefreshRate"/>
<!-- Protected by the Location policy rule -->
@@ -217,6 +266,30 @@
send_interface="org.freedesktop.ModemManager1.Modem.Voice"
send_member="DeleteCall"/>
+ <allow send_destination="org.freedesktop.ModemManager1"
+ send_interface="org.freedesktop.ModemManager1.Modem.Voice"
+ send_member="HoldAndAccept"/>
+
+ <allow send_destination="org.freedesktop.ModemManager1"
+ send_interface="org.freedesktop.ModemManager1.Modem.Voice"
+ send_member="HangupAndAccept"/>
+
+ <allow send_destination="org.freedesktop.ModemManager1"
+ send_interface="org.freedesktop.ModemManager1.Modem.Voice"
+ send_member="HangupAll"/>
+
+ <allow send_destination="org.freedesktop.ModemManager1"
+ send_interface="org.freedesktop.ModemManager1.Modem.Voice"
+ send_member="Transfer"/>
+
+ <allow send_destination="org.freedesktop.ModemManager1"
+ send_interface="org.freedesktop.ModemManager1.Modem.Voice"
+ send_member="CallWaitingSetup"/>
+
+ <allow send_destination="org.freedesktop.ModemManager1"
+ send_interface="org.freedesktop.ModemManager1.Modem.Voice"
+ send_member="CallWaitingQuery"/>
+
<!-- org.freedesktop.ModemManager1.Call.xml -->
<!-- Protected by the Voice policy rule -->
@@ -230,6 +303,18 @@
<allow send_destination="org.freedesktop.ModemManager1"
send_interface="org.freedesktop.ModemManager1.Call"
+ send_member="Deflect"/>
+
+ <allow send_destination="org.freedesktop.ModemManager1"
+ send_interface="org.freedesktop.ModemManager1.Call"
+ send_member="JoinMultiparty"/>
+
+ <allow send_destination="org.freedesktop.ModemManager1"
+ send_interface="org.freedesktop.ModemManager1.Call"
+ send_member="LeaveMultiparty"/>
+
+ <allow send_destination="org.freedesktop.ModemManager1"
+ send_interface="org.freedesktop.ModemManager1.Call"
send_member="Hangup"/>
<allow send_destination="org.freedesktop.ModemManager1"
@@ -238,11 +323,18 @@
<!-- org.freedesktop.ModemManager1.Modem.Signal.xml -->
- <!-- Allowed for everyone -->
+ <!-- Protected by the Device.Control policy rule -->
<allow send_destination="org.freedesktop.ModemManager1"
send_interface="org.freedesktop.ModemManager1.Modem.Signal"
send_member="Setup"/>
+ <!-- org.freedesktop.ModemManager1.Modem.Time.xml -->
+
+ <!-- Protected by the Time policy rule -->
+ <allow send_destination="org.freedesktop.ModemManager1"
+ send_interface="org.freedesktop.ModemManager1.Modem.Time"
+ send_member="GetNetworkTime"/>
+
</policy>
<policy user="root">
diff --git a/data/org.freedesktop.ModemManager1.policy.in.in b/data/org.freedesktop.ModemManager1.policy.in.in
index 7edb20c..301b6e9 100644
--- a/data/org.freedesktop.ModemManager1.policy.in.in
+++ b/data/org.freedesktop.ModemManager1.policy.in.in
@@ -54,6 +54,15 @@
</defaults>
</action>
+ <action id="org.freedesktop.ModemManager1.Time">
+ <description>Query network time and timezone information</description>
+ <message>System policy prevents querying network time information.</message>
+ <defaults>
+ <allow_inactive>no</allow_inactive>
+ <allow_active>@MM_DEFAULT_USER_POLICY@</allow_active>
+ </defaults>
+ </action>
+
<action id="org.freedesktop.ModemManager1.Location">
<description>Enable and view geographic location and positioning information</description>
<message>System policy prevents enabling or viewing geographic location information.</message>
@@ -68,7 +77,7 @@
<message>System policy prevents querying or utilizing network information and services.</message>
<defaults>
<allow_inactive>no</allow_inactive>
- <allow_active>yes</allow_active>
+ <allow_active>@MM_DEFAULT_USER_POLICY@</allow_active>
</defaults>
</action>
diff --git a/docs/reference/libmm-glib/libmm-glib-sections.txt b/docs/reference/libmm-glib/libmm-glib-sections.txt
index 690db8b..bc3eeb9 100644
--- a/docs/reference/libmm-glib/libmm-glib-sections.txt
+++ b/docs/reference/libmm-glib/libmm-glib-sections.txt
@@ -1001,6 +1001,7 @@
<SUBSECTION Getters>
mm_modem_voice_get_path
mm_modem_voice_dup_path
+mm_modem_voice_get_emergency_only
<SUBSECTION Methods>
mm_modem_voice_create_call
@@ -1024,6 +1025,12 @@
mm_modem_voice_transfer
mm_modem_voice_transfer_finish
mm_modem_voice_transfer_sync
+mm_modem_voice_call_waiting_query
+mm_modem_voice_call_waiting_query_finish
+mm_modem_voice_call_waiting_query_sync
+mm_modem_voice_call_waiting_setup
+mm_modem_voice_call_waiting_setup_finish
+mm_modem_voice_call_waiting_setup_sync
<SUBSECTION Standard>
MMModemVoiceClass
MMModemVoicePrivate
@@ -2847,6 +2854,7 @@
<SUBSECTION Getters>
mm_gdbus_modem_voice_get_calls
mm_gdbus_modem_voice_dup_calls
+mm_gdbus_modem_voice_get_emergency_only
<SUBSECTION Methods>
mm_gdbus_modem_voice_call_create_call
mm_gdbus_modem_voice_call_create_call_finish
@@ -2869,8 +2877,15 @@
mm_gdbus_modem_voice_call_transfer
mm_gdbus_modem_voice_call_transfer_finish
mm_gdbus_modem_voice_call_transfer_sync
+mm_gdbus_modem_voice_call_call_waiting_query
+mm_gdbus_modem_voice_call_call_waiting_query_finish
+mm_gdbus_modem_voice_call_call_waiting_query_sync
+mm_gdbus_modem_voice_call_call_waiting_setup
+mm_gdbus_modem_voice_call_call_waiting_setup_finish
+mm_gdbus_modem_voice_call_call_waiting_setup_sync
<SUBSECTION Private>
mm_gdbus_modem_voice_set_calls
+mm_gdbus_modem_voice_set_emergency_only
mm_gdbus_modem_voice_emit_call_added
mm_gdbus_modem_voice_emit_call_deleted
mm_gdbus_modem_voice_complete_create_call
@@ -2880,6 +2895,8 @@
mm_gdbus_modem_voice_complete_hold_and_accept
mm_gdbus_modem_voice_complete_hangup_all
mm_gdbus_modem_voice_complete_transfer
+mm_gdbus_modem_voice_complete_call_waiting_query
+mm_gdbus_modem_voice_complete_call_waiting_setup
mm_gdbus_modem_voice_interface_info
mm_gdbus_modem_voice_override_properties
<SUBSECTION Standard>
diff --git a/include/ModemManager-enums.h b/include/ModemManager-enums.h
index f84eafc..c26e169 100644
--- a/include/ModemManager-enums.h
+++ b/include/ModemManager-enums.h
@@ -514,6 +514,7 @@
* @MM_MODEM_PORT_TYPE_GPS: GPS port.
* @MM_MODEM_PORT_TYPE_QMI: QMI port.
* @MM_MODEM_PORT_TYPE_MBIM: MBIM port.
+ * @MM_MODEM_PORT_TYPE_AUDIO: Audio port.
*
* Type of modem port.
*/
@@ -524,7 +525,8 @@
MM_MODEM_PORT_TYPE_QCDM = 4,
MM_MODEM_PORT_TYPE_GPS = 5,
MM_MODEM_PORT_TYPE_QMI = 6,
- MM_MODEM_PORT_TYPE_MBIM = 7
+ MM_MODEM_PORT_TYPE_MBIM = 7,
+ MM_MODEM_PORT_TYPE_AUDIO = 8,
} MMModemPortType;
/**
@@ -942,8 +944,7 @@
MM_MODEM_LOCATION_SOURCE_GPS_UNMANAGED = 1 << 4,
MM_MODEM_LOCATION_SOURCE_AGPS_MSA = 1 << 5,
MM_MODEM_LOCATION_SOURCE_AGPS_MSB = 1 << 6,
-#if defined (MM_COMPILATION)
- /* MM internal methods, not part of the API */
+#if defined (MM_COMPILATION) /*< private >*/
MM_MODEM_LOCATION_SOURCE_FIRST = MM_MODEM_LOCATION_SOURCE_3GPP_LAC_CI, /*< skip >*/
MM_MODEM_LOCATION_SOURCE_LAST = MM_MODEM_LOCATION_SOURCE_AGPS_MSB, /*< skip >*/
#endif
diff --git a/include/ModemManager-tags.h b/include/ModemManager-tags.h
index ed65af5..8c7a76d 100644
--- a/include/ModemManager-tags.h
+++ b/include/ModemManager-tags.h
@@ -178,6 +178,16 @@
#define ID_MM_PORT_TYPE_GPS "ID_MM_PORT_TYPE_GPS"
/**
+ * ID_MM_PORT_TYPE_AUDIO:
+ *
+ * This is a port-specific tag applied to TTYs that we know in advance
+ * are audio ports.
+ *
+ * This tag also prevents AT and QCDM probing in the port.
+ */
+#define ID_MM_PORT_TYPE_AUDIO "ID_MM_PORT_TYPE_AUDIO"
+
+/**
* ID_MM_TTY_BAUDRATE:
*
* This is a port-specific tag applied to TTYs that require a specific
diff --git a/introspection/org.freedesktop.ModemManager1.Modem.Voice.xml b/introspection/org.freedesktop.ModemManager1.Modem.Voice.xml
index 59f11e9..698b8e3 100644
--- a/introspection/org.freedesktop.ModemManager1.Modem.Voice.xml
+++ b/introspection/org.freedesktop.ModemManager1.Modem.Voice.xml
@@ -176,5 +176,15 @@
-->
<property name="Calls" type="ao" access="read" />
+ <!--
+ EmergencyOnly:
+
+ A flag indicating whether emergency calls are the only allowed ones.
+
+ If this flag is set, users should only attempt voice calls to
+ emergency numbers, as standard voice calls will likely fail.
+ -->
+ <property name="EmergencyOnly" type="b" access="read" />
+
</interface>
</node>
diff --git a/introspection/org.freedesktop.ModemManager1.Sim.xml b/introspection/org.freedesktop.ModemManager1.Sim.xml
index ca28334..1db9b66 100644
--- a/introspection/org.freedesktop.ModemManager1.Sim.xml
+++ b/introspection/org.freedesktop.ModemManager1.Sim.xml
@@ -97,5 +97,15 @@
-->
<property name="OperatorName" type="s" access="read" />
+ <!--
+ EmergencyNumbers:
+
+ List of emergency numbers programmed in the SIM card.
+
+ These numbers should be treated as numbers for emergency calls in
+ addition to 112 and 911.
+ -->
+ <property name="EmergencyNumbers" type="as" access="read" />
+
</interface>
</node>
diff --git a/libmm-glib/mm-call.c b/libmm-glib/mm-call.c
index 91439f5..7d6b2b3 100644
--- a/libmm-glib/mm-call.c
+++ b/libmm-glib/mm-call.c
@@ -644,7 +644,7 @@
/**
* mm_call_join_multiparty_sync:
- * @self: A #MMCall.g
+ * @self: A #MMCall.
* @cancellable: (allow-none): A #GCancellable or %NULL.
* @error: Return location for error or %NULL.
*
diff --git a/libmm-glib/mm-modem-oma.c b/libmm-glib/mm-modem-oma.c
index 77c682d..3002c8a 100644
--- a/libmm-glib/mm-modem-oma.c
+++ b/libmm-glib/mm-modem-oma.c
@@ -113,7 +113,7 @@
/**
* mm_modem_oma_setup:
* @self: A #MMModemOma.
- * @features: Mask of #MMOmaFeatures to enable.
+ * @features: Mask of #MMOmaFeature values to enable.
* @cancellable: (allow-none): A #GCancellable or %NULL.
* @callback: A #GAsyncReadyCallback to call when the request is satisfied or %NULL.
* @user_data: User data to pass to @callback.
@@ -140,7 +140,7 @@
/**
* mm_modem_oma_setup_sync:
* @self: A #MMModemOma.
- * @features: Mask of #MMOmaFeatures to enable.
+ * @features: Mask of #MMOmaFeature values to enable.
* @cancellable: (allow-none): A #GCancellable or %NULL.
* @error: Return location for error or %NULL.
*
diff --git a/libmm-glib/mm-modem-voice.c b/libmm-glib/mm-modem-voice.c
index e23a730..ce22e0b 100644
--- a/libmm-glib/mm-modem-voice.c
+++ b/libmm-glib/mm-modem-voice.c
@@ -81,6 +81,20 @@
RETURN_NON_EMPTY_STRING (value);
}
+/**
+ * mm_modem_voice_get_emergency_only:
+ * @self: A #MMModemVoice.
+ *
+ * Checks whether emergency calls only are allowed.
+ *
+ * Returns: %TRUE if only emergency calls are allowed, %FALSE otherwise..
+ */
+gboolean
+mm_modem_voice_get_emergency_only (MMModemVoice *self)
+{
+ return mm_gdbus_modem_voice_get_emergency_only (MM_GDBUS_MODEM_VOICE (self));
+}
+
/*****************************************************************************/
typedef struct {
diff --git a/libmm-glib/mm-modem-voice.h b/libmm-glib/mm-modem-voice.h
index f43a60a..d3a8fc9 100644
--- a/libmm-glib/mm-modem-voice.h
+++ b/libmm-glib/mm-modem-voice.h
@@ -70,8 +70,9 @@
G_DEFINE_AUTOPTR_CLEANUP_FUNC (MMModemVoice, g_object_unref)
#endif
-const gchar *mm_modem_voice_get_path (MMModemVoice *self);
-gchar *mm_modem_voice_dup_path (MMModemVoice *self);
+const gchar *mm_modem_voice_get_path (MMModemVoice *self);
+gchar *mm_modem_voice_dup_path (MMModemVoice *self);
+gboolean mm_modem_voice_get_emergency_only (MMModemVoice *self);
void mm_modem_voice_create_call (MMModemVoice *self,
MMCallProperties *properties,
diff --git a/libmm-glib/mm-sim.c b/libmm-glib/mm-sim.c
index 052f7e5..b79a362 100644
--- a/libmm-glib/mm-sim.c
+++ b/libmm-glib/mm-sim.c
@@ -246,6 +246,45 @@
/*****************************************************************************/
/**
+ * mm_sim_get_emergency_numbers:
+ * @self: A #MMSim.
+ *
+ * Gets the list of emergency call numbers programmed in the SIM card.
+ *
+ * <warning>The returned value is only valid until the property changes so
+ * it is only safe to use this function on the thread where
+ * @self was constructed. Use mm_sim_dup_emergency_numbers() if on another
+ * thread.</warning>
+ *
+ * Returns: (transfer none): The emergency numbers, or %NULL if none available. Do not free the returned value, it belongs to @self.
+ */
+const gchar * const *
+mm_sim_get_emergency_numbers (MMSim *self)
+{
+ g_return_val_if_fail (MM_IS_SIM (self), NULL);
+
+ return mm_gdbus_sim_get_emergency_numbers (MM_GDBUS_SIM (self));
+}
+
+/**
+ * mm_sim_dup_emergency_numbers:
+ * @self: A #MMSim.
+ *
+ * Gets a copy of the list of emergency call numbers programmed in the SIM card.
+ *
+ * Returns: (transfer full): The emergency numbers, or %NULL if none available. The returned value should be freed with g_strfreev().
+ */
+gchar **
+mm_sim_dup_emergency_numbers (MMSim *self)
+{
+ g_return_val_if_fail (MM_IS_SIM (self), NULL);
+
+ return mm_gdbus_sim_dup_emergency_numbers (MM_GDBUS_SIM (self));
+}
+
+/*****************************************************************************/
+
+/**
* mm_sim_send_pin_finish:
* @self: A #MMSim.
* @res: The #GAsyncResult obtained from the #GAsyncReadyCallback passed to mm_sim_send_pin().
diff --git a/libmm-glib/mm-sim.h b/libmm-glib/mm-sim.h
index 0f162ef..90b49b5 100644
--- a/libmm-glib/mm-sim.h
+++ b/libmm-glib/mm-sim.h
@@ -82,6 +82,9 @@
const gchar *mm_sim_get_operator_name (MMSim *self);
gchar *mm_sim_dup_operator_name (MMSim *self);
+const gchar * const *mm_sim_get_emergency_numbers (MMSim *self);
+gchar **mm_sim_dup_emergency_numbers (MMSim *self);
+
void mm_sim_send_pin (MMSim *self,
const gchar *pin,
GCancellable *cancellable,
diff --git a/plugins/Makefile.am b/plugins/Makefile.am
index dd66d2f..ffc0c0e 100644
--- a/plugins/Makefile.am
+++ b/plugins/Makefile.am
@@ -590,15 +590,43 @@
# plugin: simtech
################################################################################
+noinst_LTLIBRARIES += libhelpers-simtech.la
+libhelpers_simtech_la_SOURCES = \
+ simtech/mm-modem-helpers-simtech.c \
+ simtech/mm-modem-helpers-simtech.h \
+ $(NULL)
+
+noinst_PROGRAMS += test-modem-helpers-simtech
+test_modem_helpers_simtech_SOURCES = \
+ simtech/tests/test-modem-helpers-simtech.c \
+ $(NULL)
+test_modem_helpers_simtech_CPPFLAGS = \
+ -I$(top_srcdir)/plugins/simtech \
+ $(NULL)
+test_modem_helpers_simtech_LDADD = \
+ $(builddir)/libhelpers-simtech.la \
+ $(top_builddir)/src/libhelpers.la \
+ $(top_builddir)/libmm-glib/libmm-glib.la \
+ $(NULL)
+
pkglib_LTLIBRARIES += libmm-plugin-simtech.la
libmm_plugin_simtech_la_SOURCES = \
simtech/mm-plugin-simtech.c \
simtech/mm-plugin-simtech.h \
+ simtech/mm-shared-simtech.c \
+ simtech/mm-shared-simtech.h \
simtech/mm-broadband-modem-simtech.h \
simtech/mm-broadband-modem-simtech.c \
$(NULL)
+if WITH_QMI
+libmm_plugin_simtech_la_SOURCES += \
+ simtech/mm-broadband-modem-qmi-simtech.c \
+ simtech/mm-broadband-modem-qmi-simtech.h \
+ $(NULL)
+endif
libmm_plugin_simtech_la_CPPFLAGS = $(PLUGIN_COMMON_COMPILER_FLAGS)
libmm_plugin_simtech_la_LDFLAGS = $(PLUGIN_COMMON_LINKER_FLAGS)
+libmm_plugin_simtech_la_LIBADD = $(builddir)/libhelpers-simtech.la
dist_udevrules_DATA += simtech/77-mm-simtech-port-types.rules
diff --git a/plugins/cinterion/mm-shared-cinterion.c b/plugins/cinterion/mm-shared-cinterion.c
index 5cb35a8..23f3fe1 100644
--- a/plugins/cinterion/mm-shared-cinterion.c
+++ b/plugins/cinterion/mm-shared-cinterion.c
@@ -1228,8 +1228,8 @@
priv = get_private (MM_SHARED_CINTERION (self));
- if (!priv->iface_modem_voice_parent->cleanup_unsolicited_events_finish (self, res, &error)) {
- mm_warn ("Couldn't cleanup parent voice unsolicited events: %s", error->message);
+ if (!priv->iface_modem_voice_parent->setup_unsolicited_events_finish (self, res, &error)) {
+ mm_warn ("Couldn't setup parent voice unsolicited events: %s", error->message);
g_error_free (error);
}
@@ -1315,7 +1315,10 @@
mm_base_modem_at_command (MM_BASE_MODEM (self),
"^SLCC=?",
3,
- TRUE,
+ /* Do NOT cache as the reply may be different if PIN locked
+ * or unlocked. E.g. we may not support ^SLCC for emergency
+ * voice calls. */
+ FALSE,
(GAsyncReadyCallback) slcc_format_check_ready,
task);
}
diff --git a/plugins/cinterion/tests/test-modem-helpers-cinterion.c b/plugins/cinterion/tests/test-modem-helpers-cinterion.c
index eef0a70..875cf74 100644
--- a/plugins/cinterion/tests/test-modem-helpers-cinterion.c
+++ b/plugins/cinterion/tests/test-modem-helpers-cinterion.c
@@ -699,7 +699,7 @@
g_assert_no_error (error);
g_assert (result);
- g_print ("found %u calls\n", g_list_length (call_info_list));
+ g_debug ("found %u calls", g_list_length (call_info_list));
if (expected_call_info_list) {
g_assert (call_info_list);
@@ -712,7 +712,7 @@
gboolean found = FALSE;
guint i;
- g_print ("call at index %u: direction %s, state %s, number %s\n",
+ g_debug ("call at index %u: direction %s, state %s, number %s",
call_info->index,
mm_call_direction_get_string (call_info->direction),
mm_call_state_get_string (call_info->state),
@@ -865,17 +865,17 @@
const char *fmt,
...)
{
-#if defined ENABLE_TEST_MESSAGE_TRACES
- /* Dummy log function */
va_list args;
gchar *msg;
+ if (!g_test_verbose ())
+ return;
+
va_start (args, fmt);
msg = g_strdup_vprintf (fmt, args);
va_end (args);
g_print ("%s\n", msg);
g_free (msg);
-#endif
}
int main (int argc, char **argv)
diff --git a/plugins/huawei/mm-broadband-bearer-huawei.c b/plugins/huawei/mm-broadband-bearer-huawei.c
index c2830e1..01a46c6 100644
--- a/plugins/huawei/mm-broadband-bearer-huawei.c
+++ b/plugins/huawei/mm-broadband-bearer-huawei.c
@@ -333,9 +333,7 @@
NULL, /* Do not care the AT response */
NULL);
- g_task_return_new_error (task,
- MM_CORE_ERROR,
- MM_CORE_ERROR_CANCELLED,
+ g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_CANCELLED,
"Huawei connection operation has been cancelled");
g_object_unref (task);
return;
diff --git a/plugins/huawei/tests/test-modem-helpers-huawei.c b/plugins/huawei/tests/test-modem-helpers-huawei.c
index 70c40db..97b11a8 100644
--- a/plugins/huawei/tests/test-modem-helpers-huawei.c
+++ b/plugins/huawei/tests/test-modem-helpers-huawei.c
@@ -391,7 +391,6 @@
g_assert (combinations != NULL);
g_assert_cmpuint (combinations->len, ==, n_expected_combinations);
-#if defined ENABLE_TEST_MESSAGE_TRACES
for (j = 0; j < combinations->len; j++) {
MMHuaweiPrefmodeCombination *single;
gchar *allowed_str;
@@ -409,7 +408,6 @@
g_free (allowed_str);
g_free (preferred_str);
}
-#endif
for (j = 0; j < combinations->len; j++) {
MMHuaweiPrefmodeCombination *single;
@@ -629,7 +627,6 @@
g_assert (combinations != NULL);
g_assert_cmpuint (combinations->len, ==, n_expected_combinations);
-#if defined ENABLE_TEST_MESSAGE_TRACES
for (j = 0; j < combinations->len; j++) {
MMHuaweiSyscfgCombination *single;
gchar *allowed_str;
@@ -648,7 +645,6 @@
g_free (allowed_str);
g_free (preferred_str);
}
-#endif
for (j = 0; j < combinations->len; j++) {
MMHuaweiSyscfgCombination *single;
@@ -898,7 +894,6 @@
g_assert (combinations != NULL);
g_assert_cmpuint (combinations->len, ==, n_expected_combinations);
-#if defined ENABLE_TEST_MESSAGE_TRACES
for (j = 0; j < combinations->len; j++) {
MMHuaweiSyscfgexCombination *single;
gchar *allowed_str;
@@ -916,7 +911,6 @@
g_free (allowed_str);
g_free (preferred_str);
}
-#endif
for (j = 0; j < combinations->len; j++) {
MMHuaweiSyscfgexCombination *single;
@@ -1280,17 +1274,17 @@
const char *fmt,
...)
{
-#if defined ENABLE_TEST_MESSAGE_TRACES
- /* Dummy log function */
va_list args;
gchar *msg;
+ if (!g_test_verbose ())
+ return;
+
va_start (args, fmt);
msg = g_strdup_vprintf (fmt, args);
va_end (args);
g_print ("%s\n", msg);
g_free (msg);
-#endif
}
int main (int argc, char **argv)
diff --git a/plugins/icera/tests/test-modem-helpers-icera.c b/plugins/icera/tests/test-modem-helpers-icera.c
index 3761b02..592b8b2 100644
--- a/plugins/icera/tests/test-modem-helpers-icera.c
+++ b/plugins/icera/tests/test-modem-helpers-icera.c
@@ -182,17 +182,17 @@
const char *fmt,
...)
{
-#if defined ENABLE_TEST_MESSAGE_TRACES
- /* Dummy log function */
va_list args;
gchar *msg;
+ if (!g_test_verbose ())
+ return;
+
va_start (args, fmt);
msg = g_strdup_vprintf (fmt, args);
va_end (args);
g_print ("%s\n", msg);
g_free (msg);
-#endif
}
int main (int argc, char **argv)
diff --git a/plugins/linktop/tests/test-modem-helpers-linktop.c b/plugins/linktop/tests/test-modem-helpers-linktop.c
index 27119bb..827d044 100644
--- a/plugins/linktop/tests/test-modem-helpers-linktop.c
+++ b/plugins/linktop/tests/test-modem-helpers-linktop.c
@@ -25,8 +25,6 @@
#include "mm-modem-helpers.h"
#include "mm-modem-helpers-linktop.h"
-/* #define ENABLE_TEST_MESSAGE_TRACES */
-
/*****************************************************************************/
typedef struct {
@@ -68,17 +66,17 @@
const char *fmt,
...)
{
-#if defined ENABLE_TEST_MESSAGE_TRACES
- /* Dummy log function */
va_list args;
gchar *msg;
+ if (!g_test_verbose ())
+ return;
+
va_start (args, fmt);
msg = g_strdup_vprintf (fmt, args);
va_end (args);
g_print ("%s\n", msg);
g_free (msg);
-#endif
}
int main (int argc, char **argv)
diff --git a/plugins/mbm/tests/test-modem-helpers-mbm.c b/plugins/mbm/tests/test-modem-helpers-mbm.c
index 8c573af..cca121b 100644
--- a/plugins/mbm/tests/test-modem-helpers-mbm.c
+++ b/plugins/mbm/tests/test-modem-helpers-mbm.c
@@ -28,8 +28,6 @@
#include "mm-modem-helpers.h"
#include "mm-modem-helpers-mbm.h"
-#define ENABLE_TEST_MESSAGE_TRACES
-
/*****************************************************************************/
/* Test *E2IPCFG responses */
@@ -262,17 +260,17 @@
const char *fmt,
...)
{
-#if defined ENABLE_TEST_MESSAGE_TRACES
- /* Dummy log function */
va_list args;
gchar *msg;
+ if (!g_test_verbose ())
+ return;
+
va_start (args, fmt);
msg = g_strdup_vprintf (fmt, args);
va_end (args);
g_print ("%s\n", msg);
g_free (msg);
-#endif
}
int main (int argc, char **argv)
diff --git a/plugins/sierra/tests/test-modem-helpers-sierra.c b/plugins/sierra/tests/test-modem-helpers-sierra.c
index a53f27e..629572e 100644
--- a/plugins/sierra/tests/test-modem-helpers-sierra.c
+++ b/plugins/sierra/tests/test-modem-helpers-sierra.c
@@ -122,17 +122,17 @@
const char *fmt,
...)
{
-#if defined ENABLE_TEST_MESSAGE_TRACES
- /* Dummy log function */
va_list args;
gchar *msg;
+ if (!g_test_verbose ())
+ return;
+
va_start (args, fmt);
msg = g_strdup_vprintf (fmt, args);
va_end (args);
g_print ("%s\n", msg);
g_free (msg);
-#endif
}
int main (int argc, char **argv)
diff --git a/plugins/simtech/77-mm-simtech-port-types.rules b/plugins/simtech/77-mm-simtech-port-types.rules
index 715eb00..c138ed9 100644
--- a/plugins/simtech/77-mm-simtech-port-types.rules
+++ b/plugins/simtech/77-mm-simtech-port-types.rules
@@ -21,16 +21,20 @@
ATTRS{idVendor}=="1e0e", ATTRS{idProduct}=="cefe", ENV{.MM_USBIFNUM}=="02", ENV{ID_MM_PORT_TYPE_AT_PRIMARY}="1"
ATTRS{idVendor}=="1e0e", ATTRS{idProduct}=="cefe", ENV{.MM_USBIFNUM}=="00", ENV{ID_MM_PORT_TYPE_AT_SECONDARY}="1"
ATTRS{idVendor}=="1e0e", ATTRS{idProduct}=="cefe", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_PORT_TYPE_AT_SECONDARY}="1"
-ATTRS{idVendor}=="1e0e", ATTRS{idProduct}=="cefe", ENV{ID_MM_SIMTECH_TAGGED}="1"
# Prolink PH-300
ATTRS{idVendor}=="1e0e", ATTRS{idProduct}=="9100", ENV{.MM_USBIFNUM}=="03", ENV{ID_MM_PORT_TYPE_AT_PRIMARY}="1"
ATTRS{idVendor}=="1e0e", ATTRS{idProduct}=="9100", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_PORT_TYPE_AT_SECONDARY}="1"
-ATTRS{idVendor}=="1e0e", ATTRS{idProduct}=="9100", ENV{ID_MM_SIMTECH_TAGGED}="1"
# SCT UM300
ATTRS{idVendor}=="1e0e", ATTRS{idProduct}=="9200", ENV{.MM_USBIFNUM}=="03", ENV{ID_MM_PORT_TYPE_AT_PRIMARY}="1"
ATTRS{idVendor}=="1e0e", ATTRS{idProduct}=="9200", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_PORT_TYPE_AT_SECONDARY}="1"
-ATTRS{idVendor}=="1e0e", ATTRS{idProduct}=="9200", ENV{ID_MM_SIMTECH_TAGGED}="1"
+
+# SIM7000, SIM7100, SIM7600...
+ATTRS{idVendor}=="1e0e", ATTRS{idProduct}=="9001", ENV{.MM_USBIFNUM}=="00", ENV{ID_MM_PORT_TYPE_QCDM}="1"
+ATTRS{idVendor}=="1e0e", ATTRS{idProduct}=="9001", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_PORT_TYPE_GPS}="1"
+ATTRS{idVendor}=="1e0e", ATTRS{idProduct}=="9001", ENV{.MM_USBIFNUM}=="02", ENV{ID_MM_PORT_TYPE_AT_PRIMARY}="1"
+ATTRS{idVendor}=="1e0e", ATTRS{idProduct}=="9001", ENV{.MM_USBIFNUM}=="03", ENV{ID_MM_PORT_TYPE_AT_SECONDARY}="1"
+ATTRS{idVendor}=="1e0e", ATTRS{idProduct}=="9001", ENV{.MM_USBIFNUM}=="04", ENV{ID_MM_PORT_TYPE_AUDIO}="1"
LABEL="mm_simtech_port_types_end"
diff --git a/plugins/simtech/mm-broadband-modem-qmi-simtech.c b/plugins/simtech/mm-broadband-modem-qmi-simtech.c
new file mode 100644
index 0000000..392f562
--- /dev/null
+++ b/plugins/simtech/mm-broadband-modem-qmi-simtech.c
@@ -0,0 +1,124 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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:
+ *
+ * Copyright (C) 2019 Aleksander Morgado <aleksander@aleksander.es>
+ */
+
+#include <config.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <ctype.h>
+
+#include "ModemManager.h"
+#include "mm-log.h"
+#include "mm-errors-types.h"
+#include "mm-iface-modem-location.h"
+#include "mm-iface-modem-voice.h"
+#include "mm-broadband-modem-qmi-simtech.h"
+#include "mm-shared-simtech.h"
+
+static void iface_modem_location_init (MMIfaceModemLocation *iface);
+static void iface_modem_voice_init (MMIfaceModemVoice *iface);
+static void shared_simtech_init (MMSharedSimtech *iface);
+
+static MMIfaceModemLocation *iface_modem_location_parent;
+static MMIfaceModemVoice *iface_modem_voice_parent;
+
+G_DEFINE_TYPE_EXTENDED (MMBroadbandModemQmiSimtech, mm_broadband_modem_qmi_simtech, MM_TYPE_BROADBAND_MODEM_QMI, 0,
+ G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_LOCATION, iface_modem_location_init)
+ G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_VOICE, iface_modem_voice_init)
+ G_IMPLEMENT_INTERFACE (MM_TYPE_SHARED_SIMTECH, shared_simtech_init))
+
+/*****************************************************************************/
+
+MMBroadbandModemQmiSimtech *
+mm_broadband_modem_qmi_simtech_new (const gchar *device,
+ const gchar **drivers,
+ const gchar *plugin,
+ guint16 vendor_id,
+ guint16 product_id)
+{
+ return g_object_new (MM_TYPE_BROADBAND_MODEM_QMI_SIMTECH,
+ MM_BASE_MODEM_DEVICE, device,
+ MM_BASE_MODEM_DRIVERS, drivers,
+ MM_BASE_MODEM_PLUGIN, plugin,
+ MM_BASE_MODEM_VENDOR_ID, vendor_id,
+ MM_BASE_MODEM_PRODUCT_ID, product_id,
+ MM_BROADBAND_MODEM_INDICATORS_DISABLED, TRUE,
+ NULL);
+}
+
+static void
+mm_broadband_modem_qmi_simtech_init (MMBroadbandModemQmiSimtech *self)
+{
+}
+
+static void
+iface_modem_location_init (MMIfaceModemLocation *iface)
+{
+ iface_modem_location_parent = g_type_interface_peek_parent (iface);
+
+ iface->load_capabilities = mm_shared_simtech_location_load_capabilities;
+ iface->load_capabilities_finish = mm_shared_simtech_location_load_capabilities_finish;
+ iface->enable_location_gathering = mm_shared_simtech_enable_location_gathering;
+ iface->enable_location_gathering_finish = mm_shared_simtech_enable_location_gathering_finish;
+ iface->disable_location_gathering = mm_shared_simtech_disable_location_gathering;
+ iface->disable_location_gathering_finish = mm_shared_simtech_disable_location_gathering_finish;
+}
+
+static MMIfaceModemLocation *
+peek_parent_location_interface (MMSharedSimtech *self)
+{
+ return iface_modem_location_parent;
+}
+
+static void
+iface_modem_voice_init (MMIfaceModemVoice *iface)
+{
+ iface_modem_voice_parent = g_type_interface_peek_parent (iface);
+
+ iface->check_support = mm_shared_simtech_voice_check_support;
+ iface->check_support_finish = mm_shared_simtech_voice_check_support_finish;
+ iface->enable_unsolicited_events = mm_shared_simtech_voice_enable_unsolicited_events;
+ iface->enable_unsolicited_events_finish = mm_shared_simtech_voice_enable_unsolicited_events_finish;
+ iface->disable_unsolicited_events = mm_shared_simtech_voice_disable_unsolicited_events;
+ iface->disable_unsolicited_events_finish = mm_shared_simtech_voice_disable_unsolicited_events_finish;
+ iface->setup_unsolicited_events = mm_shared_simtech_voice_setup_unsolicited_events;
+ iface->setup_unsolicited_events_finish = mm_shared_simtech_voice_setup_unsolicited_events_finish;
+ iface->cleanup_unsolicited_events = mm_shared_simtech_voice_cleanup_unsolicited_events;
+ iface->cleanup_unsolicited_events_finish = mm_shared_simtech_voice_cleanup_unsolicited_events_finish;
+ iface->setup_in_call_audio_channel = mm_shared_simtech_voice_setup_in_call_audio_channel;
+ iface->setup_in_call_audio_channel_finish = mm_shared_simtech_voice_setup_in_call_audio_channel_finish;
+ iface->cleanup_in_call_audio_channel = mm_shared_simtech_voice_cleanup_in_call_audio_channel;
+ iface->cleanup_in_call_audio_channel_finish = mm_shared_simtech_voice_cleanup_in_call_audio_channel_finish;
+}
+
+static MMIfaceModemVoice *
+peek_parent_voice_interface (MMSharedSimtech *self)
+{
+ return iface_modem_voice_parent;
+}
+
+static void
+shared_simtech_init (MMSharedSimtech *iface)
+{
+ iface->peek_parent_location_interface = peek_parent_location_interface;
+ iface->peek_parent_voice_interface = peek_parent_voice_interface;
+}
+
+static void
+mm_broadband_modem_qmi_simtech_class_init (MMBroadbandModemQmiSimtechClass *klass)
+{
+}
diff --git a/plugins/simtech/mm-broadband-modem-qmi-simtech.h b/plugins/simtech/mm-broadband-modem-qmi-simtech.h
new file mode 100644
index 0000000..2f5b819
--- /dev/null
+++ b/plugins/simtech/mm-broadband-modem-qmi-simtech.h
@@ -0,0 +1,47 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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:
+ *
+ * Copyright (C) 2019 Aleksander Morgado <aleksander@aleksander.es>
+ */
+
+#ifndef MM_BROADBAND_MODEM_QMI_SIMTECH_QMI_H
+#define MM_BROADBAND_MODEM_QMI_SIMTECH_QMI_H
+
+#include "mm-broadband-modem-qmi.h"
+
+#define MM_TYPE_BROADBAND_MODEM_QMI_SIMTECH (mm_broadband_modem_qmi_simtech_get_type ())
+#define MM_BROADBAND_MODEM_QMI_SIMTECH(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_BROADBAND_MODEM_QMI_SIMTECH, MMBroadbandModemQmiSimtech))
+#define MM_BROADBAND_MODEM_QMI_SIMTECH_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_BROADBAND_MODEM_QMI_SIMTECH, MMBroadbandModemQmiSimtechClass))
+#define MM_IS_BROADBAND_MODEM_QMI_SIMTECH(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_BROADBAND_MODEM_QMI_SIMTECH))
+#define MM_IS_BROADBAND_MODEM_QMI_SIMTECH_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_BROADBAND_MODEM_QMI_SIMTECH))
+#define MM_BROADBAND_MODEM_QMI_SIMTECH_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_BROADBAND_MODEM_QMI_SIMTECH, MMBroadbandModemQmiSimtechClass))
+
+typedef struct _MMBroadbandModemQmiSimtech MMBroadbandModemQmiSimtech;
+typedef struct _MMBroadbandModemQmiSimtechClass MMBroadbandModemQmiSimtechClass;
+
+struct _MMBroadbandModemQmiSimtech {
+ MMBroadbandModemQmi parent;
+};
+
+struct _MMBroadbandModemQmiSimtechClass{
+ MMBroadbandModemQmiClass parent;
+};
+
+GType mm_broadband_modem_qmi_simtech_get_type (void);
+
+MMBroadbandModemQmiSimtech *mm_broadband_modem_qmi_simtech_new (const gchar *device,
+ const gchar **drivers,
+ const gchar *plugin,
+ guint16 vendor_id,
+ guint16 product_id);
+
+#endif /* MM_BROADBAND_MODEM_QMI_SIMTECH_H */
diff --git a/plugins/simtech/mm-broadband-modem-simtech.c b/plugins/simtech/mm-broadband-modem-simtech.c
index b200114..21781dc 100644
--- a/plugins/simtech/mm-broadband-modem-simtech.c
+++ b/plugins/simtech/mm-broadband-modem-simtech.c
@@ -32,17 +32,41 @@
#include "mm-base-modem-at.h"
#include "mm-iface-modem.h"
#include "mm-iface-modem-3gpp.h"
+#include "mm-iface-modem-location.h"
+#include "mm-iface-modem-voice.h"
+#include "mm-shared-simtech.h"
#include "mm-broadband-modem-simtech.h"
-static void iface_modem_init (MMIfaceModem *iface);
-static void iface_modem_3gpp_init (MMIfaceModem3gpp *iface);
+static void iface_modem_init (MMIfaceModem *iface);
+static void iface_modem_3gpp_init (MMIfaceModem3gpp *iface);
+static void iface_modem_location_init (MMIfaceModemLocation *iface);
+static void iface_modem_voice_init (MMIfaceModemVoice *iface);
+static void shared_simtech_init (MMSharedSimtech *iface);
-static MMIfaceModem *iface_modem_parent;
-static MMIfaceModem3gpp *iface_modem_3gpp_parent;
+static MMIfaceModem *iface_modem_parent;
+static MMIfaceModem3gpp *iface_modem_3gpp_parent;
+static MMIfaceModemLocation *iface_modem_location_parent;
+static MMIfaceModemVoice *iface_modem_voice_parent;
G_DEFINE_TYPE_EXTENDED (MMBroadbandModemSimtech, mm_broadband_modem_simtech, MM_TYPE_BROADBAND_MODEM, 0,
G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM, iface_modem_init)
- G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_3GPP, iface_modem_3gpp_init))
+ G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_3GPP, iface_modem_3gpp_init)
+ G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_LOCATION, iface_modem_location_init)
+ G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_VOICE, iface_modem_voice_init)
+ G_IMPLEMENT_INTERFACE (MM_TYPE_SHARED_SIMTECH, shared_simtech_init))
+
+typedef enum {
+ FEATURE_SUPPORT_UNKNOWN,
+ FEATURE_NOT_SUPPORTED,
+ FEATURE_SUPPORTED
+} FeatureSupport;
+
+struct _MMBroadbandModemSimtechPrivate {
+ FeatureSupport cnsmod_support;
+ FeatureSupport autocsq_support;
+ GRegex *cnsmod_regex;
+ GRegex *csq_regex;
+};
/*****************************************************************************/
/* Setup/Cleanup unsolicited events (3GPP interface) */
@@ -50,22 +74,19 @@
static MMModemAccessTechnology
simtech_act_to_mm_act (int nsmod)
{
- if (nsmod == 1)
- return MM_MODEM_ACCESS_TECHNOLOGY_GSM;
- else if (nsmod == 2)
- return MM_MODEM_ACCESS_TECHNOLOGY_GPRS;
- else if (nsmod == 3)
- return MM_MODEM_ACCESS_TECHNOLOGY_EDGE;
- else if (nsmod == 4)
- return MM_MODEM_ACCESS_TECHNOLOGY_UMTS;
- else if (nsmod == 5)
- return MM_MODEM_ACCESS_TECHNOLOGY_HSDPA;
- else if (nsmod == 6)
- return MM_MODEM_ACCESS_TECHNOLOGY_HSUPA;
- else if (nsmod == 7)
- return MM_MODEM_ACCESS_TECHNOLOGY_HSPA;
+ static const MMModemAccessTechnology simtech_act_to_mm_act_map[] = {
+ [0] = MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN,
+ [1] = MM_MODEM_ACCESS_TECHNOLOGY_GSM,
+ [2] = MM_MODEM_ACCESS_TECHNOLOGY_GPRS,
+ [3] = MM_MODEM_ACCESS_TECHNOLOGY_EDGE,
+ [4] = MM_MODEM_ACCESS_TECHNOLOGY_UMTS,
+ [5] = MM_MODEM_ACCESS_TECHNOLOGY_HSDPA,
+ [6] = MM_MODEM_ACCESS_TECHNOLOGY_HSUPA,
+ [7] = MM_MODEM_ACCESS_TECHNOLOGY_HSPA,
+ [8] = MM_MODEM_ACCESS_TECHNOLOGY_LTE,
+ };
- return MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN;
+ return (nsmod < G_N_ELEMENTS (simtech_act_to_mm_act_map) ? simtech_act_to_mm_act_map[nsmod] : MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN);
}
static void
@@ -85,19 +106,33 @@
}
static void
+simtech_signal_changed (MMPortSerialAt *port,
+ GMatchInfo *match_info,
+ MMBroadbandModemSimtech *self)
+{
+ guint quality = 0;
+
+ if (!mm_get_uint_from_match_info (match_info, 1, &quality))
+ return;
+
+ if (quality != 99)
+ quality = CLAMP (quality, 0, 31) * 100 / 31;
+ else
+ quality = 0;
+
+ mm_iface_modem_update_signal_quality (MM_IFACE_MODEM (self), quality);
+}
+
+static void
set_unsolicited_events_handlers (MMBroadbandModemSimtech *self,
gboolean enable)
{
MMPortSerialAt *ports[2];
guint i;
- GRegex *regex;
ports[0] = mm_base_modem_peek_port_primary (MM_BASE_MODEM (self));
ports[1] = mm_base_modem_peek_port_secondary (MM_BASE_MODEM (self));
- regex = g_regex_new ("\\r\\n\\+CNSMOD:\\s*(\\d)\\r\\n",
- G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
-
/* Enable unsolicited events in given port */
for (i = 0; i < G_N_ELEMENTS (ports); i++) {
if (!ports[i])
@@ -106,13 +141,19 @@
/* Access technology related */
mm_port_serial_at_add_unsolicited_msg_handler (
ports[i],
- regex,
+ self->priv->cnsmod_regex,
enable ? (MMPortSerialAtUnsolicitedMsgFn)simtech_tech_changed : NULL,
enable ? self : NULL,
NULL);
- }
- g_regex_unref (regex);
+ /* Signal quality related */
+ mm_port_serial_at_add_unsolicited_msg_handler (
+ ports[i],
+ self->priv->csq_regex,
+ enable ? (MMPortSerialAtUnsolicitedMsgFn)simtech_signal_changed : NULL,
+ enable ? self : NULL,
+ NULL);
+ }
}
static gboolean
@@ -182,7 +223,21 @@
}
/*****************************************************************************/
-/* Enabling unsolicited events (3GPP interface) */
+/* Enable unsolicited events (3GPP interface) */
+
+typedef enum {
+ ENABLE_UNSOLICITED_EVENTS_STEP_FIRST,
+ ENABLE_UNSOLICITED_EVENTS_STEP_PARENT,
+ ENABLE_UNSOLICITED_EVENTS_STEP_CHECK_SUPPORT_CNSMOD,
+ ENABLE_UNSOLICITED_EVENTS_STEP_ENABLE_CNSMOD,
+ ENABLE_UNSOLICITED_EVENTS_STEP_CHECK_SUPPORT_AUTOCSQ,
+ ENABLE_UNSOLICITED_EVENTS_STEP_ENABLE_AUTOCSQ,
+ ENABLE_UNSOLICITED_EVENTS_STEP_LAST,
+} EnableUnsolicitedEventsStep;
+
+typedef struct {
+ EnableUnsolicitedEventsStep step;
+} EnableUnsolicitedEventsContext;
static gboolean
modem_3gpp_enable_unsolicited_events_finish (MMIfaceModem3gpp *self,
@@ -192,35 +247,113 @@
return g_task_propagate_boolean (G_TASK (res), error);
}
-static void
-own_enable_unsolicited_events_ready (MMBaseModem *self,
- GAsyncResult *res,
- GTask *task)
-{
- GError *error = NULL;
+static void enable_unsolicited_events_context_step (GTask *task);
- mm_base_modem_at_sequence_full_finish (self, res, NULL, &error);
- if (error)
- g_task_return_error (task, error);
- else
- g_task_return_boolean (task, TRUE);
- g_object_unref (task);
+static void
+autocsq_set_enabled_ready (MMBaseModem *self,
+ GAsyncResult *res,
+ GTask *task)
+{
+ EnableUnsolicitedEventsContext *ctx;
+ GError *error = NULL;
+ gboolean csq_urcs_enabled = FALSE;
+
+ ctx = g_task_get_task_data (task);
+
+ if (!mm_base_modem_at_command_finish (self, res, &error)) {
+ mm_dbg ("Couldn't enable automatic signal quality reporting: %s", error->message);
+ g_error_free (error);
+ } else
+ csq_urcs_enabled = TRUE;
+
+ /* Disable access technology polling if we can use the +CSQ URCs */
+ g_object_set (self,
+ MM_IFACE_MODEM_PERIODIC_SIGNAL_CHECK_DISABLED, csq_urcs_enabled,
+ NULL);
+
+ /* go to next step */
+ ctx->step++;
+ enable_unsolicited_events_context_step (task);
}
-static const MMBaseModemAtCommand unsolicited_enable_sequence[] = {
- /* Autoreport access technology changes */
- { "+CNSMOD=1", 20, FALSE, NULL },
- /* Autoreport CSQ (first arg), and only report when it changes (second arg) */
- { "+AUTOCSQ=1,1", 5, FALSE, NULL },
- { NULL }
-};
+static void
+autocsq_test_ready (MMBaseModem *_self,
+ GAsyncResult *res,
+ GTask *task)
+{
+ MMBroadbandModemSimtech *self;
+ EnableUnsolicitedEventsContext *ctx;
+
+ self = MM_BROADBAND_MODEM_SIMTECH (_self);
+ ctx = g_task_get_task_data (task);
+
+ if (!mm_base_modem_at_command_finish (_self, res, NULL))
+ self->priv->autocsq_support = FEATURE_NOT_SUPPORTED;
+ else
+ self->priv->autocsq_support = FEATURE_SUPPORTED;
+
+ /* go to next step */
+ ctx->step++;
+ enable_unsolicited_events_context_step (task);
+}
+
+static void
+cnsmod_set_enabled_ready (MMBaseModem *self,
+ GAsyncResult *res,
+ GTask *task)
+{
+ EnableUnsolicitedEventsContext *ctx;
+ GError *error = NULL;
+ gboolean cnsmod_urcs_enabled = FALSE;
+
+ ctx = g_task_get_task_data (task);
+
+ if (!mm_base_modem_at_command_finish (self, res, &error)) {
+ mm_dbg ("Couldn't enable automatic access technology reporting: %s", error->message);
+ g_error_free (error);
+ } else
+ cnsmod_urcs_enabled = TRUE;
+
+ /* Disable access technology polling if we can use the +CNSMOD URCs */
+ g_object_set (self,
+ MM_IFACE_MODEM_PERIODIC_ACCESS_TECH_CHECK_DISABLED, cnsmod_urcs_enabled,
+ NULL);
+
+ /* go to next step */
+ ctx->step++;
+ enable_unsolicited_events_context_step (task);
+}
+
+static void
+cnsmod_test_ready (MMBaseModem *_self,
+ GAsyncResult *res,
+ GTask *task)
+{
+ MMBroadbandModemSimtech *self;
+ EnableUnsolicitedEventsContext *ctx;
+
+ self = MM_BROADBAND_MODEM_SIMTECH (_self);
+ ctx = g_task_get_task_data (task);
+
+ if (!mm_base_modem_at_command_finish (_self, res, NULL))
+ self->priv->cnsmod_support = FEATURE_NOT_SUPPORTED;
+ else
+ self->priv->cnsmod_support = FEATURE_SUPPORTED;
+
+ /* go to next step */
+ ctx->step++;
+ enable_unsolicited_events_context_step (task);
+}
static void
parent_enable_unsolicited_events_ready (MMIfaceModem3gpp *self,
GAsyncResult *res,
GTask *task)
{
- GError *error = NULL;
+ EnableUnsolicitedEventsContext *ctx;
+ GError *error = NULL;
+
+ ctx = g_task_get_task_data (task);
if (!iface_modem_3gpp_parent->enable_unsolicited_events_finish (self, res, &error)) {
g_task_return_error (task, error);
@@ -228,16 +361,91 @@
return;
}
- /* Our own enable now */
- mm_base_modem_at_sequence_full (
- MM_BASE_MODEM (self),
- mm_base_modem_peek_port_primary (MM_BASE_MODEM (self)),
- unsolicited_enable_sequence,
- NULL, /* response_processor_context */
- NULL, /* response_processor_context_free */
- NULL, /* cancellable */
- (GAsyncReadyCallback)own_enable_unsolicited_events_ready,
- task);
+ /* go to next step */
+ ctx->step++;
+ enable_unsolicited_events_context_step (task);
+}
+
+static void
+enable_unsolicited_events_context_step (GTask *task)
+{
+ MMBroadbandModemSimtech *self;
+ EnableUnsolicitedEventsContext *ctx;
+
+ self = g_task_get_source_object (task);
+ ctx = g_task_get_task_data (task);
+
+ switch (ctx->step) {
+ case ENABLE_UNSOLICITED_EVENTS_STEP_FIRST:
+ /* fall down to next step */
+ ctx->step++;
+
+ case ENABLE_UNSOLICITED_EVENTS_STEP_PARENT:
+ iface_modem_3gpp_parent->enable_unsolicited_events (
+ MM_IFACE_MODEM_3GPP (self),
+ (GAsyncReadyCallback)parent_enable_unsolicited_events_ready,
+ task);
+ return;
+
+ case ENABLE_UNSOLICITED_EVENTS_STEP_CHECK_SUPPORT_CNSMOD:
+ if (self->priv->cnsmod_support == FEATURE_SUPPORT_UNKNOWN) {
+ mm_base_modem_at_command (MM_BASE_MODEM (self),
+ "+CNSMOD=?",
+ 3,
+ TRUE,
+ (GAsyncReadyCallback)cnsmod_test_ready,
+ task);
+ return;
+ }
+ /* fall down to next step */
+ ctx->step++;
+
+ case ENABLE_UNSOLICITED_EVENTS_STEP_ENABLE_CNSMOD:
+ if (self->priv->cnsmod_support == FEATURE_SUPPORTED) {
+ mm_base_modem_at_command (MM_BASE_MODEM (self),
+ /* Autoreport +CNSMOD when it changes */
+ "+CNSMOD=1",
+ 20,
+ FALSE,
+ (GAsyncReadyCallback)cnsmod_set_enabled_ready,
+ task);
+ return;
+ }
+ /* fall down to next step */
+ ctx->step++;
+
+ case ENABLE_UNSOLICITED_EVENTS_STEP_CHECK_SUPPORT_AUTOCSQ:
+ if (self->priv->autocsq_support == FEATURE_SUPPORT_UNKNOWN) {
+ mm_base_modem_at_command (MM_BASE_MODEM (self),
+ "+AUTOCSQ=?",
+ 3,
+ TRUE,
+ (GAsyncReadyCallback)autocsq_test_ready,
+ task);
+ return;
+ }
+ /* fall down to next step */
+ ctx->step++;
+
+ case ENABLE_UNSOLICITED_EVENTS_STEP_ENABLE_AUTOCSQ:
+ if (self->priv->autocsq_support == FEATURE_SUPPORTED) {
+ mm_base_modem_at_command (MM_BASE_MODEM (self),
+ /* Autoreport+ CSQ (first arg), and only report when it changes (second arg) */
+ "+AUTOCSQ=1,1",
+ 20,
+ FALSE,
+ (GAsyncReadyCallback)autocsq_set_enabled_ready,
+ task);
+ return;
+ }
+ /* fall down to next step */
+ ctx->step++;
+
+ case ENABLE_UNSOLICITED_EVENTS_STEP_LAST:
+ g_task_return_boolean (task, TRUE);
+ g_object_unref (task);
+ return;
+ }
}
static void
@@ -245,80 +453,173 @@
GAsyncReadyCallback callback,
gpointer user_data)
{
- /* Chain up parent's enable */
- iface_modem_3gpp_parent->enable_unsolicited_events (
- self,
- (GAsyncReadyCallback)parent_enable_unsolicited_events_ready,
- g_task_new (self, NULL, callback, user_data));
+ EnableUnsolicitedEventsContext *ctx;
+ GTask *task;
+
+ task = g_task_new (self, NULL, callback, user_data);
+
+ ctx = g_new (EnableUnsolicitedEventsContext, 1);
+ ctx->step = ENABLE_UNSOLICITED_EVENTS_STEP_FIRST;
+ g_task_set_task_data (task, ctx, g_free);
+
+ enable_unsolicited_events_context_step (task);
}
/*****************************************************************************/
-/* Disabling unsolicited events (3GPP interface) */
+/* Disable unsolicited events (3GPP interface) */
+
+typedef enum {
+ DISABLE_UNSOLICITED_EVENTS_STEP_FIRST,
+ DISABLE_UNSOLICITED_EVENTS_STEP_DISABLE_AUTOCSQ,
+ DISABLE_UNSOLICITED_EVENTS_STEP_DISABLE_CNSMOD,
+ DISABLE_UNSOLICITED_EVENTS_STEP_PARENT,
+ DISABLE_UNSOLICITED_EVENTS_STEP_LAST,
+} DisableUnsolicitedEventsStep;
+
+typedef struct {
+ DisableUnsolicitedEventsStep step;
+} DisableUnsolicitedEventsContext;
static gboolean
-modem_3gpp_disable_unsolicited_events_finish (MMIfaceModem3gpp *self,
- GAsyncResult *res,
- GError **error)
+modem_3gpp_disable_unsolicited_events_finish (MMIfaceModem3gpp *self,
+ GAsyncResult *res,
+ GError **error)
{
return g_task_propagate_boolean (G_TASK (res), error);
}
-static const MMBaseModemAtCommand unsolicited_disable_sequence[] = {
- { "+CNSMOD=0", 3, FALSE, NULL },
- { "+AUTOCSQ=0", 3, FALSE, NULL },
- { NULL }
-};
+static void disable_unsolicited_events_context_step (GTask *task);
static void
parent_disable_unsolicited_events_ready (MMIfaceModem3gpp *self,
GAsyncResult *res,
GTask *task)
{
- GError *error = NULL;
+ DisableUnsolicitedEventsContext *ctx;
+ GError *error = NULL;
- if (!iface_modem_3gpp_parent->disable_unsolicited_events_finish (self, res, &error))
- g_task_return_error (task, error);
- else
- g_task_return_boolean (task, TRUE);
- g_object_unref (task);
-}
+ ctx = g_task_get_task_data (task);
-static void
-own_disable_unsolicited_events_ready (MMBaseModem *self,
- GAsyncResult *res,
- GTask *task)
-{
- GError *error = NULL;
-
- mm_base_modem_at_sequence_full_finish (self, res, NULL, &error);
- if (error) {
+ if (!iface_modem_3gpp_parent->disable_unsolicited_events_finish (self, res, &error)) {
g_task_return_error (task, error);
g_object_unref (task);
return;
}
- /* Next, chain up parent's disable */
- iface_modem_3gpp_parent->disable_unsolicited_events (
- MM_IFACE_MODEM_3GPP (self),
- (GAsyncReadyCallback)parent_disable_unsolicited_events_ready,
- task);
+ /* go to next step */
+ ctx->step++;
+ disable_unsolicited_events_context_step (task);
}
static void
-modem_3gpp_disable_unsolicited_events (MMIfaceModem3gpp *self,
- GAsyncReadyCallback callback,
- gpointer user_data)
+cnsmod_set_disabled_ready (MMBaseModem *self,
+ GAsyncResult *res,
+ GTask *task)
{
- /* Our own disable first */
- mm_base_modem_at_sequence_full (
- MM_BASE_MODEM (self),
- mm_base_modem_peek_port_primary (MM_BASE_MODEM (self)),
- unsolicited_disable_sequence,
- NULL, /* response_processor_context */
- NULL, /* response_processor_context_free */
- NULL, /* cancellable */
- (GAsyncReadyCallback)own_disable_unsolicited_events_ready,
- g_task_new (self, NULL, callback, user_data));
+ DisableUnsolicitedEventsContext *ctx;
+ GError *error = NULL;
+
+ ctx = g_task_get_task_data (task);
+
+ if (!mm_base_modem_at_command_finish (self, res, &error)) {
+ mm_dbg ("Couldn't disable automatic access technology reporting: %s", error->message);
+ g_error_free (error);
+ }
+
+ /* go to next step */
+ ctx->step++;
+ disable_unsolicited_events_context_step (task);
+}
+
+static void
+autocsq_set_disabled_ready (MMBaseModem *self,
+ GAsyncResult *res,
+ GTask *task)
+{
+ DisableUnsolicitedEventsContext *ctx;
+ GError *error = NULL;
+
+ ctx = g_task_get_task_data (task);
+
+ if (!mm_base_modem_at_command_finish (self, res, &error)) {
+ mm_dbg ("Couldn't disable automatic signal quality reporting: %s", error->message);
+ g_error_free (error);
+ }
+
+ /* go to next step */
+ ctx->step++;
+ disable_unsolicited_events_context_step (task);
+}
+
+static void
+disable_unsolicited_events_context_step (GTask *task)
+{
+ MMBroadbandModemSimtech *self;
+ DisableUnsolicitedEventsContext *ctx;
+
+ self = g_task_get_source_object (task);
+ ctx = g_task_get_task_data (task);
+
+ switch (ctx->step) {
+ case DISABLE_UNSOLICITED_EVENTS_STEP_FIRST:
+ /* fall down to next step */
+ ctx->step++;
+
+ case DISABLE_UNSOLICITED_EVENTS_STEP_DISABLE_AUTOCSQ:
+ if (self->priv->autocsq_support == FEATURE_SUPPORTED) {
+ mm_base_modem_at_command (MM_BASE_MODEM (self),
+ "+AUTOCSQ=0",
+ 20,
+ FALSE,
+ (GAsyncReadyCallback)autocsq_set_disabled_ready,
+ task);
+ return;
+ }
+ /* fall down to next step */
+ ctx->step++;
+
+ case DISABLE_UNSOLICITED_EVENTS_STEP_DISABLE_CNSMOD:
+ if (self->priv->cnsmod_support == FEATURE_SUPPORTED) {
+ mm_base_modem_at_command (MM_BASE_MODEM (self),
+ "+CNSMOD=0",
+ 20,
+ FALSE,
+ (GAsyncReadyCallback)cnsmod_set_disabled_ready,
+ task);
+ return;
+ }
+ /* fall down to next step */
+ ctx->step++;
+
+ case DISABLE_UNSOLICITED_EVENTS_STEP_PARENT:
+ iface_modem_3gpp_parent->disable_unsolicited_events (
+ MM_IFACE_MODEM_3GPP (self),
+ (GAsyncReadyCallback)parent_disable_unsolicited_events_ready,
+ task);
+ return;
+
+ case DISABLE_UNSOLICITED_EVENTS_STEP_LAST:
+ g_task_return_boolean (task, TRUE);
+ g_object_unref (task);
+ return;
+ }
+}
+
+static void
+modem_3gpp_disable_unsolicited_events (MMIfaceModem3gpp *self,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ DisableUnsolicitedEventsContext *ctx;
+ GTask *task;
+
+ task = g_task_new (self, NULL, callback, user_data);
+
+ ctx = g_new (DisableUnsolicitedEventsContext, 1);
+ ctx->step = DISABLE_UNSOLICITED_EVENTS_STEP_FIRST;
+ g_task_set_task_data (task, ctx, g_free);
+
+ disable_unsolicited_events_context_step (task);
}
/*****************************************************************************/
@@ -377,21 +678,31 @@
}
static void
-load_access_technologies (MMIfaceModem *self,
+load_access_technologies (MMIfaceModem *_self,
GAsyncReadyCallback callback,
gpointer user_data)
{
- GTask *task;
+ MMBroadbandModemSimtech *self;
+ GTask *task;
+ self = MM_BROADBAND_MODEM_SIMTECH (_self);
task = g_task_new (self, NULL, callback, user_data);
/* Launch query only for 3GPP modems */
- if (!mm_iface_modem_is_3gpp (self)) {
+ if (!mm_iface_modem_is_3gpp (_self)) {
g_task_return_int (task, MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN);
g_object_unref (task);
return;
}
+ g_assert (self->priv->cnsmod_support != FEATURE_SUPPORT_UNKNOWN);
+ if (self->priv->cnsmod_support == FEATURE_NOT_SUPPORTED) {
+ g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_UNSUPPORTED,
+ "Loading access technologies with +CNSMOD is not supported");
+ g_object_unref (task);
+ return;
+ }
+
mm_base_modem_at_command (
MM_BASE_MODEM (self),
"AT+CNSMOD?",
@@ -402,6 +713,85 @@
}
/*****************************************************************************/
+/* Load signal quality (Modem interface) */
+
+static guint
+load_signal_quality_finish (MMIfaceModem *self,
+ GAsyncResult *res,
+ GError **error)
+{
+ gssize value;
+
+ value = g_task_propagate_int (G_TASK (res), error);
+ return value < 0 ? 0 : value;
+}
+
+static void
+csq_query_ready (MMBaseModem *self,
+ GAsyncResult *res,
+ GTask *task)
+{
+ const gchar *response, *p;
+ GError *error = NULL;
+ gint quality;
+ gint ber;
+
+ response = mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, &error);
+ if (!response) {
+ g_task_return_error (task, error);
+ g_object_unref (task);
+ return;
+ }
+
+ /* Given that we may have enabled AUTOCSQ support, it is totally possible
+ * to get an empty string at this point, because the +CSQ reply may have
+ * been processed as an URC already. If we ever see this, we should not return
+ * an error, because that would reset the reported signal quality to 0 :/
+ * So, in this case, return the last cached signal quality value. */
+ if (!response[0]) {
+ g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_IN_PROGRESS,
+ "already refreshed via URCs");
+ g_object_unref (task);
+ return;
+ }
+
+ p = mm_strip_tag (response, "+CSQ:");
+ if (sscanf (p, "%d, %d", &quality, &ber)) {
+ if (quality != 99)
+ quality = CLAMP (quality, 0, 31) * 100 / 31;
+ else
+ quality = 0;
+ g_task_return_int (task, quality);
+ g_object_unref (task);
+ return;
+ }
+
+ g_task_return_new_error (task,
+ MM_CORE_ERROR,
+ MM_CORE_ERROR_FAILED,
+ "Could not parse signal quality results");
+ g_object_unref (task);
+}
+
+static void
+load_signal_quality (MMIfaceModem *self,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GTask *task;
+
+ task = g_task_new (self, NULL, callback, user_data);
+
+ mm_base_modem_at_command (
+ MM_BASE_MODEM (self),
+ "+CSQ",
+ 3,
+ FALSE,
+ (GAsyncReadyCallback)csq_query_ready,
+ task);
+}
+
+/*****************************************************************************/
/* Load supported modes (Modem interface) */
static GArray *
@@ -819,12 +1209,53 @@
MM_BASE_MODEM_PLUGIN, plugin,
MM_BASE_MODEM_VENDOR_ID, vendor_id,
MM_BASE_MODEM_PRODUCT_ID, product_id,
+ MM_BROADBAND_MODEM_INDICATORS_DISABLED, TRUE,
NULL);
}
static void
mm_broadband_modem_simtech_init (MMBroadbandModemSimtech *self)
{
+ /* Initialize private data */
+ self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
+ MM_TYPE_BROADBAND_MODEM_SIMTECH,
+ MMBroadbandModemSimtechPrivate);
+
+ self->priv->cnsmod_support = FEATURE_SUPPORT_UNKNOWN;
+ self->priv->autocsq_support = FEATURE_SUPPORT_UNKNOWN;
+
+ self->priv->cnsmod_regex = g_regex_new ("\\r\\n\\+CNSMOD:\\s*(\\d+)\\r\\n",
+ G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
+ self->priv->csq_regex = g_regex_new ("\\r\\n\\+CSQ:\\s*(\\d+),(\\d+)\\r\\n",
+ G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
+}
+
+static void
+finalize (GObject *object)
+{
+ MMBroadbandModemSimtech *self = MM_BROADBAND_MODEM_SIMTECH (object);
+
+ g_regex_unref (self->priv->cnsmod_regex);
+ g_regex_unref (self->priv->csq_regex);
+
+ G_OBJECT_CLASS (mm_broadband_modem_simtech_parent_class)->finalize (object);
+}
+
+static void
+iface_modem_init (MMIfaceModem *iface)
+{
+ iface_modem_parent = g_type_interface_peek_parent (iface);
+
+ iface->load_signal_quality = load_signal_quality;
+ iface->load_signal_quality_finish = load_signal_quality_finish;
+ iface->load_access_technologies = load_access_technologies;
+ iface->load_access_technologies_finish = load_access_technologies_finish;
+ iface->load_supported_modes = load_supported_modes;
+ iface->load_supported_modes_finish = load_supported_modes_finish;
+ iface->load_current_modes = load_current_modes;
+ iface->load_current_modes_finish = load_current_modes_finish;
+ iface->set_current_modes = set_current_modes;
+ iface->set_current_modes_finish = set_current_modes_finish;
}
static void
@@ -844,24 +1275,68 @@
}
static void
-iface_modem_init (MMIfaceModem *iface)
+iface_modem_location_init (MMIfaceModemLocation *iface)
{
- iface_modem_parent = g_type_interface_peek_parent (iface);
+ iface_modem_location_parent = g_type_interface_peek_parent (iface);
- iface->load_access_technologies = load_access_technologies;
- iface->load_access_technologies_finish = load_access_technologies_finish;
- iface->load_supported_modes = load_supported_modes;
- iface->load_supported_modes_finish = load_supported_modes_finish;
- iface->load_current_modes = load_current_modes;
- iface->load_current_modes_finish = load_current_modes_finish;
- iface->set_current_modes = set_current_modes;
- iface->set_current_modes_finish = set_current_modes_finish;
+ iface->load_capabilities = mm_shared_simtech_location_load_capabilities;
+ iface->load_capabilities_finish = mm_shared_simtech_location_load_capabilities_finish;
+ iface->enable_location_gathering = mm_shared_simtech_enable_location_gathering;
+ iface->enable_location_gathering_finish = mm_shared_simtech_enable_location_gathering_finish;
+ iface->disable_location_gathering = mm_shared_simtech_disable_location_gathering;
+ iface->disable_location_gathering_finish = mm_shared_simtech_disable_location_gathering_finish;
+}
+
+static MMIfaceModemLocation *
+peek_parent_location_interface (MMSharedSimtech *self)
+{
+ return iface_modem_location_parent;
+}
+
+static void
+iface_modem_voice_init (MMIfaceModemVoice *iface)
+{
+ iface_modem_voice_parent = g_type_interface_peek_parent (iface);
+
+ iface->check_support = mm_shared_simtech_voice_check_support;
+ iface->check_support_finish = mm_shared_simtech_voice_check_support_finish;
+ iface->enable_unsolicited_events = mm_shared_simtech_voice_enable_unsolicited_events;
+ iface->enable_unsolicited_events_finish = mm_shared_simtech_voice_enable_unsolicited_events_finish;
+ iface->disable_unsolicited_events = mm_shared_simtech_voice_disable_unsolicited_events;
+ iface->disable_unsolicited_events_finish = mm_shared_simtech_voice_disable_unsolicited_events_finish;
+ iface->setup_unsolicited_events = mm_shared_simtech_voice_setup_unsolicited_events;
+ iface->setup_unsolicited_events_finish = mm_shared_simtech_voice_setup_unsolicited_events_finish;
+ iface->cleanup_unsolicited_events = mm_shared_simtech_voice_cleanup_unsolicited_events;
+ iface->cleanup_unsolicited_events_finish = mm_shared_simtech_voice_cleanup_unsolicited_events_finish;
+ iface->setup_in_call_audio_channel = mm_shared_simtech_voice_setup_in_call_audio_channel;
+ iface->setup_in_call_audio_channel_finish = mm_shared_simtech_voice_setup_in_call_audio_channel_finish;
+ iface->cleanup_in_call_audio_channel = mm_shared_simtech_voice_cleanup_in_call_audio_channel;
+ iface->cleanup_in_call_audio_channel_finish = mm_shared_simtech_voice_cleanup_in_call_audio_channel_finish;
+
+}
+
+static MMIfaceModemVoice *
+peek_parent_voice_interface (MMSharedSimtech *self)
+{
+ return iface_modem_voice_parent;
+}
+
+static void
+shared_simtech_init (MMSharedSimtech *iface)
+{
+ iface->peek_parent_location_interface = peek_parent_location_interface;
+ iface->peek_parent_voice_interface = peek_parent_voice_interface;
}
static void
mm_broadband_modem_simtech_class_init (MMBroadbandModemSimtechClass *klass)
{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
MMBroadbandModemClass *broadband_modem_class = MM_BROADBAND_MODEM_CLASS (klass);
+ g_type_class_add_private (object_class, sizeof (MMBroadbandModemSimtechPrivate));
+
+ object_class->finalize = finalize;
+
broadband_modem_class->setup_ports = setup_ports;
}
diff --git a/plugins/simtech/mm-broadband-modem-simtech.h b/plugins/simtech/mm-broadband-modem-simtech.h
index 6ee32b1..a2b57fe 100644
--- a/plugins/simtech/mm-broadband-modem-simtech.h
+++ b/plugins/simtech/mm-broadband-modem-simtech.h
@@ -29,9 +29,11 @@
typedef struct _MMBroadbandModemSimtech MMBroadbandModemSimtech;
typedef struct _MMBroadbandModemSimtechClass MMBroadbandModemSimtechClass;
+typedef struct _MMBroadbandModemSimtechPrivate MMBroadbandModemSimtechPrivate;
struct _MMBroadbandModemSimtech {
MMBroadbandModem parent;
+ MMBroadbandModemSimtechPrivate *priv;
};
struct _MMBroadbandModemSimtechClass{
diff --git a/plugins/simtech/mm-modem-helpers-simtech.c b/plugins/simtech/mm-modem-helpers-simtech.c
new file mode 100644
index 0000000..d452e0b
--- /dev/null
+++ b/plugins/simtech/mm-modem-helpers-simtech.c
@@ -0,0 +1,209 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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:
+ *
+ * Copyright (C) 2019 Aleksander Morgado <aleksander@aleksander.es>
+ */
+
+#include <config.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "ModemManager.h"
+#define _LIBMM_INSIDE_MM
+#include <libmm-glib.h>
+#include "mm-log.h"
+#include "mm-errors-types.h"
+#include "mm-modem-helpers-simtech.h"
+#include "mm-modem-helpers.h"
+
+
+/*****************************************************************************/
+/* +CLCC test parser
+ *
+ * Example (SIM7600E):
+ * AT+CLCC=?
+ * +CLCC: (0-1)
+ */
+
+gboolean
+mm_simtech_parse_clcc_test (const gchar *response,
+ gboolean *clcc_urcs_supported,
+ GError **error)
+{
+ g_assert (response);
+
+ response = mm_strip_tag (response, "+CLCC:");
+
+ /* 3GPP specifies that the output of AT+CLCC=? should be just OK, so support
+ * that */
+ if (!response[0]) {
+ *clcc_urcs_supported = FALSE;
+ return TRUE;
+ }
+
+ /* As per 3GPP TS 27.007, the AT+CLCC command doesn't expect any argument,
+ * as it only is designed to report the current call list, nothing else.
+ * In the case of the Simtech plugin, though, we are going to support +CLCC
+ * URCs that can be enabled/disabled via AT+CLCC=1/0. We therefore need to
+ * detect whether this URC management is possible or not, for now with a
+ * simple check looking for the specific "(0-1)" string.
+ */
+ if (!strncmp (response, "(0-1)", 5)) {
+ *clcc_urcs_supported = TRUE;
+ return TRUE;
+ }
+
+ g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
+ "unexpected +CLCC test response: '%s'", response);
+ return FALSE;
+}
+
+/*****************************************************************************/
+
+GRegex *
+mm_simtech_get_clcc_urc_regex (void)
+{
+ return g_regex_new ("\\r\\n(\\+CLCC: .*\\r\\n)+",
+ G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
+}
+
+gboolean
+mm_simtech_parse_clcc_list (const gchar *str,
+ GList **out_list,
+ GError **error)
+{
+ /* Parse the URC contents as a plain +CLCC response, but make sure to skip first
+ * EOL in the string because the plain +CLCC response would never have that.
+ */
+ return mm_3gpp_parse_clcc_response (mm_strip_tag (str, "\r\n"), out_list, error);
+}
+
+void
+mm_simtech_call_info_list_free (GList *call_info_list)
+{
+ mm_3gpp_call_info_list_free (call_info_list);
+}
+
+/*****************************************************************************/
+
+/*
+ * <CR><LF>VOICE CALL: BEGIN<CR><LF>
+ * <CR><LF>VOICE CALL: END: 000041<CR><LF>
+ */
+GRegex *
+mm_simtech_get_voice_call_urc_regex (void)
+{
+ return g_regex_new ("\\r\\nVOICE CALL:\\s*([A-Z]+)(?::\\s*(\\d+))?\\r\\n",
+ G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
+}
+
+gboolean
+mm_simtech_parse_voice_call_urc (GMatchInfo *match_info,
+ gboolean *start_or_stop,
+ guint *duration,
+ GError **error)
+{
+ GError *inner_error = NULL;
+ gchar *str;
+
+ str = mm_get_string_unquoted_from_match_info (match_info, 1);
+ if (!str) {
+ inner_error = g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
+ "Couldn't read voice call URC action");
+ goto out;
+ }
+
+ if (g_strcmp0 (str, "BEGIN") == 0) {
+ *start_or_stop = TRUE;
+ *duration = 0;
+ goto out;
+ }
+
+ if (g_strcmp0 (str, "END") == 0) {
+ *start_or_stop = FALSE;
+ if (!mm_get_uint_from_match_info (match_info, 2, duration))
+ *duration = 0;
+ goto out;
+ }
+
+ inner_error = g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
+ "Unknown voice call URC action: %s", str);
+
+out:
+ g_free (str);
+ if (inner_error) {
+ g_propagate_error (error, inner_error);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/*****************************************************************************/
+
+/*
+ * <CR><LF>MISSED_CALL: 11:01AM 07712345678<CR><LF>
+ */
+GRegex *
+mm_simtech_get_missed_call_urc_regex (void)
+{
+ return g_regex_new ("\\r\\nMISSED_CALL:\\s*(.+)\\r\\n",
+ G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
+}
+
+gboolean
+mm_simtech_parse_missed_call_urc (GMatchInfo *match_info,
+ gchar **details,
+ GError **error)
+{
+ gchar *str;
+
+ str = mm_get_string_unquoted_from_match_info (match_info, 1);
+ if (!str) {
+ g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
+ "Couldn't read missed call URC details");
+ return FALSE;
+ }
+
+ *details = str;
+ return TRUE;
+}
+
+/*****************************************************************************/
+
+/*
+ * Using TWO <CR> instead of one...
+ * <CR><CR><LF>+CRING: VOICE<CR><CR><LF>
+ */
+GRegex *
+mm_simtech_get_cring_urc_regex (void)
+{
+ return g_regex_new ("(?:\\r)+\\n\\+CRING:\\s*(\\S+)(?:\\r)+\\n",
+ G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
+}
+
+/*****************************************************************************/
+
+/*
+ * <CR><CR><LF>+RXDTMF: 8<CR><CR><LF>
+ * <CR><CR><LF>+RXDTMF: *<CR><CR><LF>
+ * <CR><CR><LF>+RXDTMF: 7<CR><CR><LF>
+ *
+ * Note! using TWO <CR> instead of one...
+ */
+GRegex *
+mm_simtech_get_rxdtmf_urc_regex (void)
+{
+ return g_regex_new ("(?:\\r)+\\n\\+RXDTMF:\\s*([0-9A-D\\*\\#])(?:\\r)+\\n",
+ G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
+}
diff --git a/plugins/simtech/mm-modem-helpers-simtech.h b/plugins/simtech/mm-modem-helpers-simtech.h
new file mode 100644
index 0000000..efcc23f
--- /dev/null
+++ b/plugins/simtech/mm-modem-helpers-simtech.h
@@ -0,0 +1,66 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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:
+ *
+ * Copyright (C) 2019 Aleksander Morgado <aleksander@aleksander.es>
+ */
+
+#ifndef MM_MODEM_HELPERS_SIMTECH_H
+#define MM_MODEM_HELPERS_SIMTECH_H
+
+#include <glib.h>
+
+#include <ModemManager.h>
+#include <mm-base-bearer.h>
+#define _LIBMM_INSIDE_MM
+#include <libmm-glib.h>
+
+/*****************************************************************************/
+/* +CLCC URC helpers */
+
+gboolean mm_simtech_parse_clcc_test (const gchar *response,
+ gboolean *clcc_urcs_supported,
+ GError **error);
+
+GRegex *mm_simtech_get_clcc_urc_regex (void);
+gboolean mm_simtech_parse_clcc_list (const gchar *str,
+ GList **out_list,
+ GError **error);
+void mm_simtech_call_info_list_free (GList *call_info_list);
+
+/*****************************************************************************/
+/* VOICE CALL URC helpers */
+
+GRegex *mm_simtech_get_voice_call_urc_regex (void);
+gboolean mm_simtech_parse_voice_call_urc (GMatchInfo *match_info,
+ gboolean *start_or_stop,
+ guint *duration,
+ GError **error);
+
+/*****************************************************************************/
+/* MISSED_CALL URC helpers */
+
+GRegex *mm_simtech_get_missed_call_urc_regex (void);
+gboolean mm_simtech_parse_missed_call_urc (GMatchInfo *match_info,
+ gchar **details,
+ GError **error);
+
+/*****************************************************************************/
+/* Non-standard CRING URC helpers */
+
+GRegex *mm_simtech_get_cring_urc_regex (void);
+
+/*****************************************************************************/
+/* +RXDTMF URC helpers */
+
+GRegex *mm_simtech_get_rxdtmf_urc_regex (void);
+
+#endif /* MM_MODEM_HELPERS_SIMTECH_H */
diff --git a/plugins/simtech/mm-plugin-simtech.c b/plugins/simtech/mm-plugin-simtech.c
index fb3a795..79afeb5 100644
--- a/plugins/simtech/mm-plugin-simtech.c
+++ b/plugins/simtech/mm-plugin-simtech.c
@@ -26,7 +26,7 @@
#include "mm-broadband-modem-simtech.h"
#if defined WITH_QMI
-#include "mm-broadband-modem-qmi.h"
+#include "mm-broadband-modem-qmi-simtech.h"
#endif
G_DEFINE_TYPE (MMPluginSimtech, mm_plugin_simtech, MM_TYPE_PLUGIN)
@@ -48,11 +48,11 @@
#if defined WITH_QMI
if (mm_port_probe_list_has_qmi_port (probes)) {
mm_dbg ("QMI-powered SimTech modem found...");
- return MM_BASE_MODEM (mm_broadband_modem_qmi_new (uid,
- drivers,
- mm_plugin_get_name (self),
- vendor,
- product));
+ return MM_BASE_MODEM (mm_broadband_modem_qmi_simtech_new (uid,
+ drivers,
+ mm_plugin_get_name (self),
+ vendor,
+ product));
}
#endif
diff --git a/plugins/simtech/mm-shared-simtech.c b/plugins/simtech/mm-shared-simtech.c
new file mode 100644
index 0000000..b7f98ac
--- /dev/null
+++ b/plugins/simtech/mm-shared-simtech.c
@@ -0,0 +1,1284 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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:
+ *
+ * Copyright (C) 2019 Aleksander Morgado <aleksander@aleksander.es>
+ */
+
+#include <config.h>
+
+#include <glib-object.h>
+#include <gio/gio.h>
+
+#define _LIBMM_INSIDE_MM
+#include <libmm-glib.h>
+
+#include "mm-log.h"
+#include "mm-iface-modem.h"
+#include "mm-iface-modem-voice.h"
+#include "mm-iface-modem-location.h"
+#include "mm-base-modem.h"
+#include "mm-base-modem-at.h"
+#include "mm-shared-simtech.h"
+#include "mm-modem-helpers-simtech.h"
+
+/*****************************************************************************/
+/* Private data context */
+
+#define PRIVATE_TAG "shared-simtech-private-tag"
+static GQuark private_quark;
+
+typedef enum {
+ FEATURE_SUPPORT_UNKNOWN,
+ FEATURE_NOT_SUPPORTED,
+ FEATURE_SUPPORTED,
+} FeatureSupport;
+
+typedef struct {
+ /* location */
+ MMIfaceModemLocation *iface_modem_location_parent;
+ MMModemLocationSource supported_sources;
+ MMModemLocationSource enabled_sources;
+ FeatureSupport cgps_support;
+ /* voice */
+ MMIfaceModemVoice *iface_modem_voice_parent;
+ FeatureSupport cpcmreg_support;
+ FeatureSupport clcc_urc_support;
+ GRegex *clcc_urc_regex;
+ GRegex *voice_call_regex;
+ GRegex *missed_call_regex;
+ GRegex *cring_regex;
+ GRegex *rxdtmf_regex;
+} Private;
+
+static void
+private_free (Private *ctx)
+{
+ g_regex_unref (ctx->rxdtmf_regex);
+ g_regex_unref (ctx->cring_regex);
+ g_regex_unref (ctx->missed_call_regex);
+ g_regex_unref (ctx->voice_call_regex);
+ g_regex_unref (ctx->clcc_urc_regex);
+ g_slice_free (Private, ctx);
+}
+
+static Private *
+get_private (MMSharedSimtech *self)
+{
+ Private *priv;
+
+ if (G_UNLIKELY (!private_quark))
+ private_quark = (g_quark_from_static_string (PRIVATE_TAG));
+
+ priv = g_object_get_qdata (G_OBJECT (self), private_quark);
+ if (!priv) {
+ priv = g_slice_new0 (Private);
+ priv->supported_sources = MM_MODEM_LOCATION_SOURCE_NONE;
+ priv->enabled_sources = MM_MODEM_LOCATION_SOURCE_NONE;
+ priv->cgps_support = FEATURE_SUPPORT_UNKNOWN;
+ priv->cpcmreg_support = FEATURE_SUPPORT_UNKNOWN;
+ priv->clcc_urc_support = FEATURE_SUPPORT_UNKNOWN;
+ priv->clcc_urc_regex = mm_simtech_get_clcc_urc_regex ();
+ priv->voice_call_regex = mm_simtech_get_voice_call_urc_regex ();
+ priv->missed_call_regex = mm_simtech_get_missed_call_urc_regex ();
+ priv->cring_regex = mm_simtech_get_cring_urc_regex ();
+ priv->rxdtmf_regex = mm_simtech_get_rxdtmf_urc_regex ();
+
+ /* Setup parent class' MMIfaceModemLocation and MMIfaceModemVoice */
+
+ g_assert (MM_SHARED_SIMTECH_GET_INTERFACE (self)->peek_parent_location_interface);
+ priv->iface_modem_location_parent = MM_SHARED_SIMTECH_GET_INTERFACE (self)->peek_parent_location_interface (self);
+
+ g_assert (MM_SHARED_SIMTECH_GET_INTERFACE (self)->peek_parent_voice_interface);
+ priv->iface_modem_voice_parent = MM_SHARED_SIMTECH_GET_INTERFACE (self)->peek_parent_voice_interface (self);
+
+ g_object_set_qdata_full (G_OBJECT (self), private_quark, priv, (GDestroyNotify)private_free);
+ }
+
+ return priv;
+}
+
+/*****************************************************************************/
+/* GPS trace received */
+
+static void
+trace_received (MMPortSerialGps *port,
+ const gchar *trace,
+ MMIfaceModemLocation *self)
+{
+ /* Helper to debug GPS location related issues. Don't depend on a real GPS
+ * fix for debugging, just use some random values to update */
+#if 0
+ if (g_str_has_prefix (trace, "$GPGGA")) {
+ GString *str;
+ GDateTime *now;
+
+ now = g_date_time_new_now_utc ();
+ str = g_string_new ("");
+ g_string_append_printf (str,
+ "$GPGGA,%02u%02u%02u,4807.038,N,01131.000,E,1,08,0.9,545.4,M,46.9,M,,*47",
+ g_date_time_get_hour (now),
+ g_date_time_get_minute (now),
+ g_date_time_get_second (now));
+ mm_iface_modem_location_gps_update (self, str->str);
+ g_string_free (str, TRUE);
+ g_date_time_unref (now);
+ return;
+ }
+#endif
+
+ mm_iface_modem_location_gps_update (self, trace);
+}
+
+/*****************************************************************************/
+/* Location capabilities loading (Location interface) */
+
+MMModemLocationSource
+mm_shared_simtech_location_load_capabilities_finish (MMIfaceModemLocation *self,
+ GAsyncResult *res,
+ GError **error)
+{
+ GError *inner_error = NULL;
+ gssize aux;
+
+ aux = g_task_propagate_int (G_TASK (res), &inner_error);
+ if (inner_error) {
+ g_propagate_error (error, inner_error);
+ return MM_MODEM_LOCATION_SOURCE_NONE;
+ }
+ return (MMModemLocationSource) aux;
+}
+
+static void probe_gps_features (GTask *task);
+
+static void
+cgps_test_ready (MMBaseModem *self,
+ GAsyncResult *res,
+ GTask *task)
+{
+ Private *priv;
+
+ priv = get_private (MM_SHARED_SIMTECH (self));
+
+ if (!mm_base_modem_at_command_finish (self, res, NULL))
+ priv->cgps_support = FEATURE_NOT_SUPPORTED;
+ else
+ priv->cgps_support = FEATURE_SUPPORTED;
+
+ probe_gps_features (task);
+}
+
+static void
+probe_gps_features (GTask *task)
+{
+ MMSharedSimtech *self;
+ MMModemLocationSource sources;
+ Private *priv;
+
+ self = MM_SHARED_SIMTECH (g_task_get_source_object (task));
+ priv = get_private (self);
+
+ /* Need to check if CGPS supported... */
+ if (priv->cgps_support == FEATURE_SUPPORT_UNKNOWN) {
+ mm_base_modem_at_command (MM_BASE_MODEM (self), "+CGPS=?", 3, TRUE, (GAsyncReadyCallback) cgps_test_ready, task);
+ return;
+ }
+
+ /* All GPS features probed */
+
+ /* Recover parent sources */
+ sources = GPOINTER_TO_UINT (g_task_get_task_data (task));
+
+ if (priv->cgps_support == FEATURE_SUPPORTED) {
+ mm_dbg ("GPS commands supported: GPS capabilities enabled");
+
+ /* We only flag as supported by this implementation those sources not already
+ * supported by the parent implementation */
+ if (!(sources & MM_MODEM_LOCATION_SOURCE_GPS_NMEA))
+ priv->supported_sources |= MM_MODEM_LOCATION_SOURCE_GPS_NMEA;
+ if (!(sources & MM_MODEM_LOCATION_SOURCE_GPS_RAW))
+ priv->supported_sources |= MM_MODEM_LOCATION_SOURCE_GPS_RAW;
+ if (!(sources & MM_MODEM_LOCATION_SOURCE_GPS_UNMANAGED))
+ priv->supported_sources |= MM_MODEM_LOCATION_SOURCE_GPS_UNMANAGED;
+
+ sources |= priv->supported_sources;
+
+ /* Add handler for the NMEA traces in the GPS data port */
+ mm_port_serial_gps_add_trace_handler (mm_base_modem_peek_port_gps (MM_BASE_MODEM (self)),
+ (MMPortSerialGpsTraceFn)trace_received,
+ self,
+ NULL);
+ } else
+ mm_dbg ("No GPS command supported: no GPS capabilities");
+
+ g_task_return_int (task, (gssize) sources);
+ g_object_unref (task);
+}
+
+static void
+parent_load_capabilities_ready (MMIfaceModemLocation *self,
+ GAsyncResult *res,
+ GTask *task)
+{
+ MMModemLocationSource sources;
+ GError *error = NULL;
+ Private *priv;
+
+ priv = get_private (MM_SHARED_SIMTECH (self));
+
+ sources = priv->iface_modem_location_parent->load_capabilities_finish (self, res, &error);
+ if (error) {
+ g_task_return_error (task, error);
+ g_object_unref (task);
+ return;
+ }
+
+ /* Now our own check. If we don't have any GPS port, we're done */
+ if (!mm_base_modem_peek_port_gps (MM_BASE_MODEM (self))) {
+ mm_dbg ("No GPS data port found: no GPS capabilities");
+ g_task_return_int (task, sources);
+ g_object_unref (task);
+ return;
+ }
+
+ /* Cache sources supported by the parent */
+ g_task_set_task_data (task, GUINT_TO_POINTER (sources), NULL);
+
+ /* Probe all GPS features */
+ probe_gps_features (task);
+}
+
+void
+mm_shared_simtech_location_load_capabilities (MMIfaceModemLocation *self,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ Private *priv;
+ GTask *task;
+
+ priv = get_private (MM_SHARED_SIMTECH (self));
+ task = g_task_new (self, NULL, callback, user_data);
+
+ g_assert (priv->iface_modem_location_parent);
+ g_assert (priv->iface_modem_location_parent->load_capabilities);
+ g_assert (priv->iface_modem_location_parent->load_capabilities_finish);
+
+ priv->iface_modem_location_parent->load_capabilities (self,
+ (GAsyncReadyCallback)parent_load_capabilities_ready,
+ task);
+}
+
+/*****************************************************************************/
+/* Disable location gathering (Location interface) */
+
+gboolean
+mm_shared_simtech_disable_location_gathering_finish (MMIfaceModemLocation *self,
+ GAsyncResult *res,
+ GError **error)
+{
+ return g_task_propagate_boolean (G_TASK (res), error);
+}
+
+static void
+disable_cgps_ready (MMBaseModem *self,
+ GAsyncResult *res,
+ GTask *task)
+{
+ MMModemLocationSource source;
+ Private *priv;
+ GError *error = NULL;
+
+ priv = get_private (MM_SHARED_SIMTECH (self));
+
+ mm_base_modem_at_command_finish (self, res, &error);
+
+ /* Only use the GPS port in NMEA/RAW setups */
+ source = (MMModemLocationSource) GPOINTER_TO_UINT (g_task_get_task_data (task));
+ if (source & (MM_MODEM_LOCATION_SOURCE_GPS_NMEA | MM_MODEM_LOCATION_SOURCE_GPS_RAW)) {
+ MMPortSerialGps *gps_port;
+
+ /* Even if we get an error here, we try to close the GPS port */
+ gps_port = mm_base_modem_peek_port_gps (MM_BASE_MODEM (self));
+ if (gps_port)
+ mm_port_serial_close (MM_PORT_SERIAL (gps_port));
+ }
+
+ if (error)
+ g_task_return_error (task, error);
+ else {
+ priv->enabled_sources &= source;
+ g_task_return_boolean (task, TRUE);
+ }
+ g_object_unref (task);
+}
+
+static void
+parent_disable_location_gathering_ready (MMIfaceModemLocation *self,
+ GAsyncResult *res,
+ GTask *task)
+{
+ GError *error;
+ Private *priv;
+
+ priv = get_private (MM_SHARED_SIMTECH (self));
+
+ g_assert (priv->iface_modem_location_parent);
+ if (!priv->iface_modem_location_parent->disable_location_gathering_finish (self, res, &error))
+ g_task_return_error (task, error);
+ else
+ g_task_return_boolean (task, TRUE);
+ g_object_unref (task);
+}
+
+void
+mm_shared_simtech_disable_location_gathering (MMIfaceModemLocation *self,
+ MMModemLocationSource source,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ MMModemLocationSource enabled_sources;
+ Private *priv;
+ GTask *task;
+
+ task = g_task_new (self, NULL, callback, user_data);
+ g_task_set_task_data (task, GUINT_TO_POINTER (source), NULL);
+
+ priv = get_private (MM_SHARED_SIMTECH (self));
+ g_assert (priv->iface_modem_location_parent);
+
+ /* Only consider request if it applies to one of the sources we are
+ * supporting, otherwise run parent disable */
+ if (!(priv->supported_sources & source)) {
+ /* If disabling implemented by the parent, run it. */
+ if (priv->iface_modem_location_parent->disable_location_gathering &&
+ priv->iface_modem_location_parent->disable_location_gathering_finish) {
+ priv->iface_modem_location_parent->disable_location_gathering (self,
+ source,
+ (GAsyncReadyCallback)parent_disable_location_gathering_ready,
+ task);
+ return;
+ }
+ /* Otherwise, we're done */
+ g_task_return_boolean (task, TRUE);
+ g_object_unref (task);
+ return;
+ }
+
+ /* We only expect GPS sources here */
+ g_assert (source & (MM_MODEM_LOCATION_SOURCE_GPS_NMEA |
+ MM_MODEM_LOCATION_SOURCE_GPS_RAW |
+ MM_MODEM_LOCATION_SOURCE_GPS_UNMANAGED));
+
+ /* Flag as disabled to see how many others we would have left enabled */
+ enabled_sources = priv->enabled_sources;
+ enabled_sources &= ~source;
+
+ /* If there are still GPS-related sources enabled, do nothing else */
+ if (enabled_sources & (MM_MODEM_LOCATION_SOURCE_GPS_NMEA |
+ MM_MODEM_LOCATION_SOURCE_GPS_RAW |
+ MM_MODEM_LOCATION_SOURCE_GPS_UNMANAGED)) {
+ priv->enabled_sources &= ~source;
+ g_task_return_boolean (task, TRUE);
+ g_object_unref (task);
+ return;
+ }
+
+ /* Stop GPS engine if all GPS-related sources are disabled */
+ g_assert (priv->cgps_support == FEATURE_SUPPORTED);
+ mm_base_modem_at_command (MM_BASE_MODEM (self),
+ "+CGPS=0",
+ 10,
+ FALSE,
+ (GAsyncReadyCallback) disable_cgps_ready,
+ task);
+}
+
+/*****************************************************************************/
+/* Enable location gathering (Location interface) */
+
+gboolean
+mm_shared_simtech_enable_location_gathering_finish (MMIfaceModemLocation *self,
+ GAsyncResult *res,
+ GError **error)
+{
+ return g_task_propagate_boolean (G_TASK (res), error);
+}
+
+static void
+enable_cgps_ready (MMBaseModem *self,
+ GAsyncResult *res,
+ GTask *task)
+{
+ MMModemLocationSource source;
+ GError *error = NULL;
+ Private *priv;
+
+ priv = get_private (MM_SHARED_SIMTECH (self));
+
+ if (!mm_base_modem_at_command_finish (self, res, &error)) {
+ g_task_return_error (task, error);
+ g_object_unref (task);
+ return;
+ }
+
+ /* Only use the GPS port in NMEA/RAW setups */
+ source = (MMModemLocationSource) GPOINTER_TO_UINT (g_task_get_task_data (task));
+ if (source & (MM_MODEM_LOCATION_SOURCE_GPS_NMEA |
+ MM_MODEM_LOCATION_SOURCE_GPS_RAW)) {
+ MMPortSerialGps *gps_port;
+
+ gps_port = mm_base_modem_peek_port_gps (MM_BASE_MODEM (self));
+ if (!gps_port || !mm_port_serial_open (MM_PORT_SERIAL (gps_port), &error)) {
+ if (error)
+ g_task_return_error (task, error);
+ else
+ g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
+ "Couldn't open raw GPS serial port");
+ g_object_unref (task);
+ return;
+ }
+ }
+
+ priv->enabled_sources |= source;
+ g_task_return_boolean (task, TRUE);
+ g_object_unref (task);
+}
+
+static void
+parent_enable_location_gathering_ready (MMIfaceModemLocation *self,
+ GAsyncResult *res,
+ GTask *task)
+{
+ GError *error;
+ Private *priv;
+
+ priv = get_private (MM_SHARED_SIMTECH (self));
+
+ g_assert (priv->iface_modem_location_parent);
+ if (!priv->iface_modem_location_parent->enable_location_gathering_finish (self, res, &error))
+ g_task_return_error (task, error);
+ else
+ g_task_return_boolean (task, TRUE);
+ g_object_unref (task);
+}
+
+void
+mm_shared_simtech_enable_location_gathering (MMIfaceModemLocation *self,
+ MMModemLocationSource source,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ Private *priv;
+ GTask *task;
+
+ task = g_task_new (self, NULL, callback, user_data);
+ g_task_set_task_data (task, GUINT_TO_POINTER (source), NULL);
+
+ priv = get_private (MM_SHARED_SIMTECH (self));
+ g_assert (priv->iface_modem_location_parent);
+ g_assert (priv->iface_modem_location_parent->enable_location_gathering);
+ g_assert (priv->iface_modem_location_parent->enable_location_gathering_finish);
+
+ /* Only consider request if it applies to one of the sources we are
+ * supporting, otherwise run parent enable */
+ if (!(priv->supported_sources & source)) {
+ priv->iface_modem_location_parent->enable_location_gathering (self,
+ source,
+ (GAsyncReadyCallback)parent_enable_location_gathering_ready,
+ task);
+ return;
+ }
+
+ /* We only expect GPS sources here */
+ g_assert (source & (MM_MODEM_LOCATION_SOURCE_GPS_NMEA |
+ MM_MODEM_LOCATION_SOURCE_GPS_RAW |
+ MM_MODEM_LOCATION_SOURCE_GPS_UNMANAGED));
+
+ /* If GPS already started, store new flag and we're done */
+ if (priv->enabled_sources & (MM_MODEM_LOCATION_SOURCE_GPS_NMEA |
+ MM_MODEM_LOCATION_SOURCE_GPS_RAW |
+ MM_MODEM_LOCATION_SOURCE_GPS_UNMANAGED)) {
+ priv->enabled_sources |= source;
+ g_task_return_boolean (task, TRUE);
+ g_object_unref (task);
+ return;
+ }
+
+ g_assert (priv->cgps_support == FEATURE_SUPPORTED);
+ mm_base_modem_at_command (MM_BASE_MODEM (self),
+ "+CGPS=1,1",
+ 10,
+ FALSE,
+ (GAsyncReadyCallback) enable_cgps_ready,
+ task);
+}
+
+/*****************************************************************************/
+/* Common enable/disable voice unsolicited events */
+
+typedef struct {
+ gboolean enable;
+ MMPortSerialAt *primary;
+ MMPortSerialAt *secondary;
+ gchar *clcc_command;
+ gboolean clcc_primary_done;
+ gboolean clcc_secondary_done;
+} VoiceUnsolicitedEventsContext;
+
+static void
+voice_unsolicited_events_context_free (VoiceUnsolicitedEventsContext *ctx)
+{
+ g_clear_object (&ctx->secondary);
+ g_clear_object (&ctx->primary);
+ g_free (ctx->clcc_command);
+ g_slice_free (VoiceUnsolicitedEventsContext, ctx);
+}
+
+static gboolean
+common_voice_enable_disable_unsolicited_events_finish (MMSharedSimtech *self,
+ GAsyncResult *res,
+ GError **error)
+{
+ return g_task_propagate_boolean (G_TASK (res), error);
+}
+
+static void run_voice_enable_disable_unsolicited_events (GTask *task);
+
+static void
+clcc_command_ready (MMBaseModem *self,
+ GAsyncResult *res,
+ GTask *task)
+{
+ VoiceUnsolicitedEventsContext *ctx;
+ GError *error = NULL;
+
+ ctx = g_task_get_task_data (task);
+
+ if (!mm_base_modem_at_command_finish (self, res, &error)) {
+ mm_dbg ("Couldn't %s +CLCC reporting: '%s'",
+ ctx->enable ? "enable" : "disable",
+ error->message);
+ g_error_free (error);
+ }
+
+ /* Continue on next port */
+ run_voice_enable_disable_unsolicited_events (task);
+}
+
+static void
+run_voice_enable_disable_unsolicited_events (GTask *task)
+{
+ MMSharedSimtech *self;
+ Private *priv;
+ VoiceUnsolicitedEventsContext *ctx;
+ MMPortSerialAt *port = NULL;
+
+ self = MM_SHARED_SIMTECH (g_task_get_source_object (task));
+ priv = get_private (self);
+ ctx = g_task_get_task_data (task);
+
+ /* If +CLCC URCs not supported, we're done */
+ if (priv->clcc_urc_support == FEATURE_NOT_SUPPORTED) {
+ g_task_return_boolean (task, TRUE);
+ g_object_unref (task);
+ return;
+ }
+
+ if (!ctx->clcc_primary_done && ctx->primary) {
+ mm_dbg ("%s +CLCC extended list of current calls reporting in primary port...",
+ ctx->enable ? "Enabling" : "Disabling");
+ ctx->clcc_primary_done = TRUE;
+ port = ctx->primary;
+ } else if (!ctx->clcc_secondary_done && ctx->secondary) {
+ mm_dbg ("%s +CLCC extended list of current calls reporting in secondary port...",
+ ctx->enable ? "Enabling" : "Disabling");
+ ctx->clcc_secondary_done = TRUE;
+ port = ctx->secondary;
+ }
+
+ if (port) {
+ mm_base_modem_at_command_full (MM_BASE_MODEM (self),
+ port,
+ ctx->clcc_command,
+ 3,
+ FALSE,
+ FALSE,
+ NULL,
+ (GAsyncReadyCallback)clcc_command_ready,
+ task);
+ return;
+ }
+
+ /* Fully done now */
+ g_task_return_boolean (task, TRUE);
+ g_object_unref (task);
+}
+
+static void
+common_voice_enable_disable_unsolicited_events (MMSharedSimtech *self,
+ gboolean enable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ VoiceUnsolicitedEventsContext *ctx;
+ GTask *task;
+
+ task = g_task_new (self, NULL, callback, user_data);
+
+ ctx = g_slice_new0 (VoiceUnsolicitedEventsContext);
+ ctx->enable = enable;
+ if (enable)
+ ctx->clcc_command = g_strdup ("+CLCC=1");
+ else
+ ctx->clcc_command = g_strdup ("+CLCC=0");
+ ctx->primary = mm_base_modem_get_port_primary (MM_BASE_MODEM (self));
+ ctx->secondary = mm_base_modem_get_port_secondary (MM_BASE_MODEM (self));
+ g_task_set_task_data (task, ctx, (GDestroyNotify) voice_unsolicited_events_context_free);
+
+ run_voice_enable_disable_unsolicited_events (task);
+}
+
+/*****************************************************************************/
+/* Disable unsolicited events (Voice interface) */
+
+gboolean
+mm_shared_simtech_voice_disable_unsolicited_events_finish (MMIfaceModemVoice *self,
+ GAsyncResult *res,
+ GError **error)
+{
+ return g_task_propagate_boolean (G_TASK (res), error);
+}
+
+static void
+parent_voice_disable_unsolicited_events_ready (MMIfaceModemVoice *self,
+ GAsyncResult *res,
+ GTask *task)
+{
+ GError *error = NULL;
+ Private *priv;
+
+ priv = get_private (MM_SHARED_SIMTECH (self));
+
+ if (!priv->iface_modem_voice_parent->disable_unsolicited_events_finish (self, res, &error)) {
+ mm_warn ("Couldn't disable parent voice unsolicited events: %s", error->message);
+ g_error_free (error);
+ }
+
+ g_task_return_boolean (task, TRUE);
+ g_object_unref (task);
+}
+
+static void
+voice_disable_unsolicited_events_ready (MMSharedSimtech *self,
+ GAsyncResult *res,
+ GTask *task)
+{
+ Private *priv;
+ GError *error = NULL;
+
+ if (!common_voice_enable_disable_unsolicited_events_finish (self, res, &error)) {
+ mm_warn ("Couldn't disable Simtech-specific voice unsolicited events: %s", error->message);
+ g_error_free (error);
+ }
+
+ priv = get_private (MM_SHARED_SIMTECH (self));
+ g_assert (priv->iface_modem_voice_parent);
+ g_assert (priv->iface_modem_voice_parent->disable_unsolicited_events);
+ g_assert (priv->iface_modem_voice_parent->disable_unsolicited_events_finish);
+
+ /* Chain up parent's disable */
+ priv->iface_modem_voice_parent->disable_unsolicited_events (
+ MM_IFACE_MODEM_VOICE (self),
+ (GAsyncReadyCallback)parent_voice_disable_unsolicited_events_ready,
+ task);
+}
+
+void
+mm_shared_simtech_voice_disable_unsolicited_events (MMIfaceModemVoice *self,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GTask *task;
+
+ task = g_task_new (self, NULL, callback, user_data);
+
+ /* our own disabling first */
+ common_voice_enable_disable_unsolicited_events (MM_SHARED_SIMTECH (self),
+ FALSE,
+ (GAsyncReadyCallback) voice_disable_unsolicited_events_ready,
+ task);
+}
+
+/*****************************************************************************/
+/* Enable unsolicited events (Voice interface) */
+
+gboolean
+mm_shared_simtech_voice_enable_unsolicited_events_finish (MMIfaceModemVoice *self,
+ GAsyncResult *res,
+ GError **error)
+{
+ return g_task_propagate_boolean (G_TASK (res), error);
+}
+
+static void
+voice_enable_unsolicited_events_ready (MMSharedSimtech *self,
+ GAsyncResult *res,
+ GTask *task)
+{
+ GError *error = NULL;
+
+ if (!common_voice_enable_disable_unsolicited_events_finish (self, res, &error)) {
+ mm_warn ("Couldn't enable Simtech-specific voice unsolicited events: %s", error->message);
+ g_error_free (error);
+ }
+
+ g_task_return_boolean (task, TRUE);
+ g_object_unref (task);
+}
+
+static void
+parent_voice_enable_unsolicited_events_ready (MMIfaceModemVoice *self,
+ GAsyncResult *res,
+ GTask *task)
+{
+ GError *error = NULL;
+ Private *priv;
+
+ priv = get_private (MM_SHARED_SIMTECH (self));
+
+ if (!priv->iface_modem_voice_parent->enable_unsolicited_events_finish (self, res, &error)) {
+ mm_warn ("Couldn't enable parent voice unsolicited events: %s", error->message);
+ g_error_free (error);
+ }
+
+ /* our own enabling next */
+ common_voice_enable_disable_unsolicited_events (MM_SHARED_SIMTECH (self),
+ TRUE,
+ (GAsyncReadyCallback) voice_enable_unsolicited_events_ready,
+ task);
+}
+
+void
+mm_shared_simtech_voice_enable_unsolicited_events (MMIfaceModemVoice *self,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ Private *priv;
+ GTask *task;
+
+ task = g_task_new (self, NULL, callback, user_data);
+
+ priv = get_private (MM_SHARED_SIMTECH (self));
+ g_assert (priv->iface_modem_voice_parent);
+ g_assert (priv->iface_modem_voice_parent->enable_unsolicited_events);
+ g_assert (priv->iface_modem_voice_parent->enable_unsolicited_events_finish);
+
+ /* chain up parent's enable first */
+ priv->iface_modem_voice_parent->enable_unsolicited_events (
+ self,
+ (GAsyncReadyCallback)parent_voice_enable_unsolicited_events_ready,
+ task);
+}
+
+/*****************************************************************************/
+/* Common setup/cleanup voice unsolicited events */
+
+static void
+clcc_urc_received (MMPortSerialAt *port,
+ GMatchInfo *match_info,
+ MMSharedSimtech *self)
+{
+ gchar *full;
+ GError *error = NULL;
+ GList *call_info_list = NULL;
+
+ full = g_match_info_fetch (match_info, 0);
+
+ if (!mm_simtech_parse_clcc_list (full, &call_info_list, &error)) {
+ mm_warn ("couldn't parse +CLCC list in URC: %s", error->message);
+ g_error_free (error);
+ } else
+ mm_iface_modem_voice_report_all_calls (MM_IFACE_MODEM_VOICE (self), call_info_list);
+
+ mm_simtech_call_info_list_free (call_info_list);
+ g_free (full);
+}
+
+static void
+missed_call_urc_received (MMPortSerialAt *port,
+ GMatchInfo *match_info,
+ MMSharedSimtech *self)
+{
+ GError *error = NULL;
+ gchar *details = NULL;
+
+ if (!mm_simtech_parse_missed_call_urc (match_info, &details, &error)) {
+ mm_warn ("couldn't parse missed call URC: %s", error->message);
+ g_error_free (error);
+ return;
+ }
+
+ mm_dbg ("missed call reported: %s", details);
+ g_free (details);
+}
+
+static void
+voice_call_urc_received (MMPortSerialAt *port,
+ GMatchInfo *match_info,
+ MMSharedSimtech *self)
+{
+ GError *error = NULL;
+ gboolean start_or_stop = FALSE; /* start = TRUE, stop = FALSE */
+ guint duration = 0;
+
+ if (!mm_simtech_parse_voice_call_urc (match_info, &start_or_stop, &duration, &error)) {
+ mm_warn ("couldn't parse VOICE CALL URC: %s", error->message);
+ g_error_free (error);
+ return;
+ }
+
+ if (start_or_stop) {
+ mm_dbg ("voice call started");
+ return;
+ }
+
+ if (duration) {
+ mm_dbg ("voice call finished (duration: %us)", duration);
+ return;
+ }
+
+ mm_dbg ("voice call finished");
+}
+
+static void
+cring_urc_received (MMPortSerialAt *port,
+ GMatchInfo *info,
+ MMSharedSimtech *self)
+{
+ MMCallInfo call_info;
+ gchar *str;
+
+ /* We could have "VOICE" or "DATA". Now consider only "VOICE" */
+ str = mm_get_string_unquoted_from_match_info (info, 1);
+ mm_dbg ("Ringing (%s)", str);
+ g_free (str);
+
+ call_info.index = 0;
+ call_info.direction = MM_CALL_DIRECTION_INCOMING;
+ call_info.state = MM_CALL_STATE_RINGING_IN;
+ call_info.number = NULL;
+
+ mm_iface_modem_voice_report_call (MM_IFACE_MODEM_VOICE (self), &call_info);
+}
+
+static void
+rxdtmf_urc_received (MMPortSerialAt *port,
+ GMatchInfo *match_info,
+ MMSharedSimtech *self)
+{
+ gchar *dtmf;
+
+ dtmf = g_match_info_fetch (match_info, 1);
+ mm_dbg ("Received DTMF: %s", dtmf);
+ /* call index unknown */
+ mm_iface_modem_voice_received_dtmf (MM_IFACE_MODEM_VOICE (self), 0, dtmf);
+ g_free (dtmf);
+}
+
+static void
+common_voice_setup_cleanup_unsolicited_events (MMSharedSimtech *self,
+ gboolean enable)
+{
+ Private *priv;
+ MMPortSerialAt *ports[2];
+ guint i;
+
+ priv = get_private (MM_SHARED_SIMTECH (self));
+
+ ports[0] = mm_base_modem_peek_port_primary (MM_BASE_MODEM (self));
+ ports[1] = mm_base_modem_peek_port_secondary (MM_BASE_MODEM (self));
+
+ for (i = 0; i < G_N_ELEMENTS (ports); i++) {
+ if (!ports[i])
+ continue;
+
+ if (priv->clcc_urc_support == FEATURE_SUPPORTED)
+ mm_port_serial_at_add_unsolicited_msg_handler (ports[i],
+ priv->clcc_urc_regex,
+ enable ? (MMPortSerialAtUnsolicitedMsgFn)clcc_urc_received : NULL,
+ enable ? self : NULL,
+ NULL);
+
+ mm_port_serial_at_add_unsolicited_msg_handler (ports[i],
+ priv->voice_call_regex,
+ enable ? (MMPortSerialAtUnsolicitedMsgFn)voice_call_urc_received : NULL,
+ enable ? self : NULL,
+ NULL);
+
+ mm_port_serial_at_add_unsolicited_msg_handler (ports[i],
+ priv->missed_call_regex,
+ enable ? (MMPortSerialAtUnsolicitedMsgFn)missed_call_urc_received : NULL,
+ enable ? self : NULL,
+ NULL);
+
+ mm_port_serial_at_add_unsolicited_msg_handler (ports[i],
+ priv->cring_regex,
+ enable ? (MMPortSerialAtUnsolicitedMsgFn)cring_urc_received : NULL,
+ enable ? self : NULL,
+ NULL);
+
+ mm_port_serial_at_add_unsolicited_msg_handler (ports[i],
+ priv->rxdtmf_regex,
+ enable ? (MMPortSerialAtUnsolicitedMsgFn)rxdtmf_urc_received : NULL,
+ enable ? self : NULL,
+ NULL);
+ }
+}
+
+/*****************************************************************************/
+/* Cleanup unsolicited events (Voice interface) */
+
+gboolean
+mm_shared_simtech_voice_cleanup_unsolicited_events_finish (MMIfaceModemVoice *self,
+ GAsyncResult *res,
+ GError **error)
+{
+ return g_task_propagate_boolean (G_TASK (res), error);
+}
+
+static void
+parent_voice_cleanup_unsolicited_events_ready (MMIfaceModemVoice *self,
+ GAsyncResult *res,
+ GTask *task)
+{
+ GError *error = NULL;
+ Private *priv;
+
+ priv = get_private (MM_SHARED_SIMTECH (self));
+
+ if (!priv->iface_modem_voice_parent->cleanup_unsolicited_events_finish (self, res, &error)) {
+ mm_warn ("Couldn't cleanup parent voice unsolicited events: %s", error->message);
+ g_error_free (error);
+ }
+
+ g_task_return_boolean (task, TRUE);
+ g_object_unref (task);
+}
+
+void
+mm_shared_simtech_voice_cleanup_unsolicited_events (MMIfaceModemVoice *self,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ Private *priv;
+ GTask *task;
+
+ task = g_task_new (self, NULL, callback, user_data);
+
+ priv = get_private (MM_SHARED_SIMTECH (self));
+ g_assert (priv->iface_modem_voice_parent);
+ g_assert (priv->iface_modem_voice_parent->cleanup_unsolicited_events);
+ g_assert (priv->iface_modem_voice_parent->cleanup_unsolicited_events_finish);
+
+ /* our own cleanup first */
+ common_voice_setup_cleanup_unsolicited_events (MM_SHARED_SIMTECH (self), FALSE);
+
+ /* Chain up parent's cleanup */
+ priv->iface_modem_voice_parent->cleanup_unsolicited_events (
+ self,
+ (GAsyncReadyCallback)parent_voice_cleanup_unsolicited_events_ready,
+ task);
+}
+
+/*****************************************************************************/
+/* Setup unsolicited events (Voice interface) */
+
+gboolean
+mm_shared_simtech_voice_setup_unsolicited_events_finish (MMIfaceModemVoice *self,
+ GAsyncResult *res,
+ GError **error)
+{
+ return g_task_propagate_boolean (G_TASK (res), error);
+}
+
+static void
+parent_voice_setup_unsolicited_events_ready (MMIfaceModemVoice *self,
+ GAsyncResult *res,
+ GTask *task)
+{
+ GError *error = NULL;
+ Private *priv;
+
+ priv = get_private (MM_SHARED_SIMTECH (self));
+
+ if (!priv->iface_modem_voice_parent->setup_unsolicited_events_finish (self, res, &error)) {
+ mm_warn ("Couldn't setup parent voice unsolicited events: %s", error->message);
+ g_error_free (error);
+ }
+
+ /* our own setup next */
+ common_voice_setup_cleanup_unsolicited_events (MM_SHARED_SIMTECH (self), TRUE);
+
+ g_task_return_boolean (task, TRUE);
+ g_object_unref (task);
+}
+
+void
+mm_shared_simtech_voice_setup_unsolicited_events (MMIfaceModemVoice *self,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ Private *priv;
+ GTask *task;
+
+ task = g_task_new (self, NULL, callback, user_data);
+
+ priv = get_private (MM_SHARED_SIMTECH (self));
+ g_assert (priv->iface_modem_voice_parent);
+ g_assert (priv->iface_modem_voice_parent->setup_unsolicited_events);
+ g_assert (priv->iface_modem_voice_parent->setup_unsolicited_events_finish);
+
+ /* chain up parent's setup first */
+ priv->iface_modem_voice_parent->setup_unsolicited_events (
+ self,
+ (GAsyncReadyCallback)parent_voice_setup_unsolicited_events_ready,
+ task);
+}
+
+/*****************************************************************************/
+/* In-call audio channel setup/cleanup */
+
+gboolean
+mm_shared_simtech_voice_setup_in_call_audio_channel_finish (MMIfaceModemVoice *self,
+ GAsyncResult *res,
+ MMPort **audio_port, /* optional */
+ MMCallAudioFormat **audio_format, /* optional */
+ GError **error)
+{
+ Private *priv;
+
+ priv = get_private (MM_SHARED_SIMTECH (self));
+
+ if (!g_task_propagate_boolean (G_TASK (res), error))
+ return FALSE;
+
+ if (audio_format)
+ *audio_format = NULL;
+
+ if (audio_port) {
+ if (priv->cpcmreg_support == FEATURE_SUPPORTED)
+ *audio_port = MM_PORT (mm_base_modem_get_port_audio (MM_BASE_MODEM (self)));
+ else
+ *audio_port = NULL;
+ }
+
+ return TRUE;
+}
+
+gboolean
+mm_shared_simtech_voice_cleanup_in_call_audio_channel_finish (MMIfaceModemVoice *self,
+ GAsyncResult *res,
+ GError **error)
+{
+ return g_task_propagate_boolean (G_TASK (res), error);
+}
+
+static void
+cpcmreg_set_ready (MMBaseModem *self,
+ GAsyncResult *res,
+ GTask *task)
+{
+ GError *error = NULL;
+
+ if (!mm_base_modem_at_command_finish (self, res, &error))
+ g_task_return_error (task, error);
+ else
+ g_task_return_boolean (task, TRUE);
+ g_object_unref (task);
+}
+
+static void
+common_setup_cleanup_in_call_audio_channel (MMSharedSimtech *self,
+ gboolean setup,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GTask *task;
+ Private *priv;
+
+ priv = get_private (MM_SHARED_SIMTECH (self));
+
+ task = g_task_new (self, NULL, callback, user_data);
+
+ /* Do nothing if CPCMREG isn't supported */
+ if (priv->cpcmreg_support != FEATURE_SUPPORTED) {
+ g_task_return_boolean (task, TRUE);
+ g_object_unref (task);
+ return;
+ }
+
+ mm_base_modem_at_command (MM_BASE_MODEM (self),
+ setup ? "+CPCMREG=1" : "+CPCMREG=0",
+ 3,
+ FALSE,
+ (GAsyncReadyCallback) cpcmreg_set_ready,
+ task);
+}
+
+void
+mm_shared_simtech_voice_setup_in_call_audio_channel (MMIfaceModemVoice *self,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ common_setup_cleanup_in_call_audio_channel (MM_SHARED_SIMTECH (self), TRUE, callback, user_data);
+}
+
+void
+mm_shared_simtech_voice_cleanup_in_call_audio_channel (MMIfaceModemVoice *self,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ common_setup_cleanup_in_call_audio_channel (MM_SHARED_SIMTECH (self), FALSE, callback, user_data);
+}
+
+/*****************************************************************************/
+/* Check if Voice supported (Voice interface) */
+
+gboolean
+mm_shared_simtech_voice_check_support_finish (MMIfaceModemVoice *self,
+ GAsyncResult *res,
+ GError **error)
+{
+ return g_task_propagate_boolean (G_TASK (res), error);
+}
+
+static void
+cpcmreg_format_check_ready (MMBroadbandModem *self,
+ GAsyncResult *res,
+ GTask *task)
+{
+ Private *priv;
+
+ priv = get_private (MM_SHARED_SIMTECH (self));
+
+ priv->cpcmreg_support = (mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, NULL) ?
+ FEATURE_SUPPORTED : FEATURE_NOT_SUPPORTED);
+ mm_dbg ("modem %s USB audio control", (priv->cpcmreg_support == FEATURE_SUPPORTED) ? "supports" : "doesn't support");
+
+ g_task_return_boolean (task, TRUE);
+ g_object_unref (task);
+}
+
+static void
+clcc_format_check_ready (MMBroadbandModem *self,
+ GAsyncResult *res,
+ GTask *task)
+{
+ Private *priv;
+ GError *error = NULL;
+ const gchar *response;
+ gboolean clcc_urc_supported = FALSE;
+
+ priv = get_private (MM_SHARED_SIMTECH (self));
+
+ response = mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, NULL);
+ if (response && !mm_simtech_parse_clcc_test (response, &clcc_urc_supported, &error)) {
+ mm_dbg ("failed checking CLCC URC support: %s", error->message);
+ g_clear_error (&error);
+ }
+
+ priv->clcc_urc_support = (clcc_urc_supported ? FEATURE_SUPPORTED : FEATURE_NOT_SUPPORTED);
+ mm_dbg ("modem %s +CLCC URCs", (priv->clcc_urc_support == FEATURE_SUPPORTED) ? "supports" : "doesn't support");
+
+ /* If +CLCC URC supported we won't need polling in the parent */
+ g_object_set (self,
+ MM_IFACE_MODEM_VOICE_PERIODIC_CALL_LIST_CHECK_DISABLED, (priv->clcc_urc_support == FEATURE_SUPPORTED),
+ NULL);
+
+ mm_base_modem_at_command (MM_BASE_MODEM (self),
+ "+CPCMREG=?",
+ 3,
+ TRUE,
+ (GAsyncReadyCallback) cpcmreg_format_check_ready,
+ task);
+}
+
+static void
+parent_voice_check_support_ready (MMIfaceModemVoice *self,
+ GAsyncResult *res,
+ GTask *task)
+{
+ Private *priv;
+ GError *error = NULL;
+
+ priv = get_private (MM_SHARED_SIMTECH (self));
+ if (!priv->iface_modem_voice_parent->check_support_finish (self, res, &error)) {
+ g_task_return_error (task, error);
+ g_object_unref (task);
+ return;
+ }
+
+ /* voice is supported, check if +CLCC URCs are available */
+ mm_base_modem_at_command (MM_BASE_MODEM (self),
+ "+CLCC=?",
+ 3,
+ TRUE,
+ (GAsyncReadyCallback) clcc_format_check_ready,
+ task);
+}
+
+void
+mm_shared_simtech_voice_check_support (MMIfaceModemVoice *self,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ Private *priv;
+ GTask *task;
+
+ task = g_task_new (self, NULL, callback, user_data);
+
+ priv = get_private (MM_SHARED_SIMTECH (self));
+ g_assert (priv->iface_modem_voice_parent);
+ g_assert (priv->iface_modem_voice_parent->check_support);
+ g_assert (priv->iface_modem_voice_parent->check_support_finish);
+
+ /* chain up parent's setup first */
+ priv->iface_modem_voice_parent->check_support (
+ self,
+ (GAsyncReadyCallback)parent_voice_check_support_ready,
+ task);
+}
+
+/*****************************************************************************/
+
+static void
+shared_simtech_init (gpointer g_iface)
+{
+}
+
+GType
+mm_shared_simtech_get_type (void)
+{
+ static GType shared_simtech_type = 0;
+
+ if (!G_UNLIKELY (shared_simtech_type)) {
+ static const GTypeInfo info = {
+ sizeof (MMSharedSimtech), /* class_size */
+ shared_simtech_init, /* base_init */
+ NULL, /* base_finalize */
+ };
+
+ shared_simtech_type = g_type_register_static (G_TYPE_INTERFACE, "MMSharedSimtech", &info, 0);
+ g_type_interface_add_prerequisite (shared_simtech_type, MM_TYPE_IFACE_MODEM_LOCATION);
+ }
+
+ return shared_simtech_type;
+}
diff --git a/plugins/simtech/mm-shared-simtech.h b/plugins/simtech/mm-shared-simtech.h
new file mode 100644
index 0000000..37a221c
--- /dev/null
+++ b/plugins/simtech/mm-shared-simtech.h
@@ -0,0 +1,129 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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:
+ *
+ * Copyright (C) 2019 Aleksander Morgado <aleksander@aleksander.es>
+ */
+
+#ifndef MM_SHARED_SIMTECH_H
+#define MM_SHARED_SIMTECH_H
+
+#include <glib-object.h>
+#include <gio/gio.h>
+
+#define _LIBMM_INSIDE_MM
+#include <libmm-glib.h>
+
+#include "mm-broadband-modem.h"
+#include "mm-iface-modem.h"
+#include "mm-iface-modem-location.h"
+#include "mm-iface-modem-voice.h"
+
+#define MM_TYPE_SHARED_SIMTECH (mm_shared_simtech_get_type ())
+#define MM_SHARED_SIMTECH(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_SHARED_SIMTECH, MMSharedSimtech))
+#define MM_IS_SHARED_SIMTECH(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_SHARED_SIMTECH))
+#define MM_SHARED_SIMTECH_GET_INTERFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), MM_TYPE_SHARED_SIMTECH, MMSharedSimtech))
+
+typedef struct _MMSharedSimtech MMSharedSimtech;
+
+struct _MMSharedSimtech {
+ GTypeInterface g_iface;
+
+ /* Peek location interface of the parent class of the object */
+ MMIfaceModemLocation * (* peek_parent_location_interface) (MMSharedSimtech *self);
+
+ /* Peek voice interface of the parent class of the object */
+ MMIfaceModemVoice * (* peek_parent_voice_interface) (MMSharedSimtech *self);
+};
+
+GType mm_shared_simtech_get_type (void);
+
+/*****************************************************************************/
+/* Location interface */
+
+void mm_shared_simtech_location_load_capabilities (MMIfaceModemLocation *self,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+MMModemLocationSource mm_shared_simtech_location_load_capabilities_finish (MMIfaceModemLocation *self,
+ GAsyncResult *res,
+ GError **error);
+
+void mm_shared_simtech_enable_location_gathering (MMIfaceModemLocation *self,
+ MMModemLocationSource source,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+gboolean mm_shared_simtech_enable_location_gathering_finish (MMIfaceModemLocation *self,
+ GAsyncResult *res,
+ GError **error);
+
+void mm_shared_simtech_disable_location_gathering (MMIfaceModemLocation *self,
+ MMModemLocationSource source,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+gboolean mm_shared_simtech_disable_location_gathering_finish (MMIfaceModemLocation *self,
+ GAsyncResult *res,
+ GError **error);
+
+
+/*****************************************************************************/
+/* Voice interface */
+
+void mm_shared_simtech_voice_check_support (MMIfaceModemVoice *self,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+gboolean mm_shared_simtech_voice_check_support_finish (MMIfaceModemVoice *self,
+ GAsyncResult *res,
+ GError **error);
+
+void mm_shared_simtech_voice_setup_unsolicited_events (MMIfaceModemVoice *self,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+gboolean mm_shared_simtech_voice_setup_unsolicited_events_finish (MMIfaceModemVoice *self,
+ GAsyncResult *res,
+ GError **error);
+
+void mm_shared_simtech_voice_cleanup_unsolicited_events (MMIfaceModemVoice *self,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+gboolean mm_shared_simtech_voice_cleanup_unsolicited_events_finish (MMIfaceModemVoice *self,
+ GAsyncResult *res,
+ GError **error);
+
+void mm_shared_simtech_voice_enable_unsolicited_events (MMIfaceModemVoice *self,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+gboolean mm_shared_simtech_voice_enable_unsolicited_events_finish (MMIfaceModemVoice *self,
+ GAsyncResult *res,
+ GError **error);
+
+void mm_shared_simtech_voice_disable_unsolicited_events (MMIfaceModemVoice *self,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+gboolean mm_shared_simtech_voice_disable_unsolicited_events_finish (MMIfaceModemVoice *self,
+ GAsyncResult *res,
+ GError **error);
+
+void mm_shared_simtech_voice_setup_in_call_audio_channel (MMIfaceModemVoice *self,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+gboolean mm_shared_simtech_voice_setup_in_call_audio_channel_finish (MMIfaceModemVoice *self,
+ GAsyncResult *res,
+ MMPort **audio_port, /* optional */
+ MMCallAudioFormat **audio_format, /* optional */
+ GError **error);
+void mm_shared_simtech_voice_cleanup_in_call_audio_channel (MMIfaceModemVoice *self,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+gboolean mm_shared_simtech_voice_cleanup_in_call_audio_channel_finish (MMIfaceModemVoice *self,
+ GAsyncResult *res,
+ GError **error);
+
+#endif /* MM_SHARED_SIMTECH_H */
diff --git a/plugins/simtech/tests/test-modem-helpers-simtech.c b/plugins/simtech/tests/test-modem-helpers-simtech.c
new file mode 100644
index 0000000..2e93d89
--- /dev/null
+++ b/plugins/simtech/tests/test-modem-helpers-simtech.c
@@ -0,0 +1,363 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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:
+ *
+ * Copyright (C) 2019 Aleksander Morgado <aleksander@aleksander.es>
+ */
+
+#include <glib.h>
+#include <glib-object.h>
+#include <locale.h>
+
+#include <ModemManager.h>
+#define _LIBMM_INSIDE_MM
+#include <libmm-glib.h>
+
+#include "mm-log.h"
+#include "mm-modem-helpers.h"
+#include "mm-modem-helpers-simtech.h"
+
+/*****************************************************************************/
+/* Test +CLCC URCs */
+
+static void
+common_test_clcc_urc (const gchar *urc,
+ const MMCallInfo *expected_call_info_list,
+ guint expected_call_info_list_size)
+{
+ GError *error = NULL;
+ GRegex *clcc_regex = NULL;
+ gboolean result;
+ GMatchInfo *match_info = NULL;
+ gchar *str;
+ GList *call_info_list = NULL;
+ GList *l;
+
+ clcc_regex = mm_simtech_get_clcc_urc_regex ();
+
+ /* Same matching logic as done in MMSerialPortAt when processing URCs! */
+ result = g_regex_match_full (clcc_regex, urc, -1, 0, 0, &match_info, &error);
+ g_assert_no_error (error);
+ g_assert (result);
+
+ /* read full matched content */
+ str = g_match_info_fetch (match_info, 0);
+ g_assert (str);
+
+ result = mm_simtech_parse_clcc_list (str, &call_info_list, &error);
+ g_assert_no_error (error);
+ g_assert (result);
+
+ g_debug ("found %u calls", g_list_length (call_info_list));
+
+ if (expected_call_info_list) {
+ g_assert (call_info_list);
+ g_assert_cmpuint (g_list_length (call_info_list), ==, expected_call_info_list_size);
+ } else
+ g_assert (!call_info_list);
+
+ for (l = call_info_list; l; l = g_list_next (l)) {
+ const MMCallInfo *call_info = (const MMCallInfo *)(l->data);
+ gboolean found = FALSE;
+ guint i;
+
+ g_debug ("call at index %u: direction %s, state %s, number %s",
+ call_info->index,
+ mm_call_direction_get_string (call_info->direction),
+ mm_call_state_get_string (call_info->state),
+ call_info->number ? call_info->number : "n/a");
+
+ for (i = 0; !found && i < expected_call_info_list_size; i++)
+ found = ((call_info->index == expected_call_info_list[i].index) &&
+ (call_info->direction == expected_call_info_list[i].direction) &&
+ (call_info->state == expected_call_info_list[i].state) &&
+ (g_strcmp0 (call_info->number, expected_call_info_list[i].number) == 0));
+
+ g_assert (found);
+ }
+
+ g_match_info_free (match_info);
+ g_regex_unref (clcc_regex);
+ g_free (str);
+
+ mm_simtech_call_info_list_free (call_info_list);
+}
+
+static void
+test_clcc_urc_single (void)
+{
+ static const MMCallInfo expected_call_info_list[] = {
+ { 1, MM_CALL_DIRECTION_INCOMING, MM_CALL_STATE_ACTIVE, "123456789" }
+ };
+
+ const gchar *urc =
+ "\r\n+CLCC: 1,1,0,0,0,\"123456789\",161"
+ "\r\n";
+
+ common_test_clcc_urc (urc, expected_call_info_list, G_N_ELEMENTS (expected_call_info_list));
+}
+
+static void
+test_clcc_urc_multiple (void)
+{
+ static const MMCallInfo expected_call_info_list[] = {
+ { 1, MM_CALL_DIRECTION_INCOMING, MM_CALL_STATE_ACTIVE, NULL },
+ { 2, MM_CALL_DIRECTION_INCOMING, MM_CALL_STATE_ACTIVE, "123456789" },
+ { 3, MM_CALL_DIRECTION_INCOMING, MM_CALL_STATE_ACTIVE, "987654321" },
+ };
+
+ const gchar *urc =
+ "\r\n+CLCC: 1,1,0,0,0" /* number unknown */
+ "\r\n+CLCC: 2,1,0,0,0,\"123456789\",161"
+ "\r\n+CLCC: 3,1,0,0,0,\"987654321\",161,\"Alice\""
+ "\r\n";
+
+ common_test_clcc_urc (urc, expected_call_info_list, G_N_ELEMENTS (expected_call_info_list));
+}
+
+static void
+test_clcc_urc_complex (void)
+{
+ static const MMCallInfo expected_call_info_list[] = {
+ { 1, MM_CALL_DIRECTION_INCOMING, MM_CALL_STATE_ACTIVE, "123456789" },
+ { 2, MM_CALL_DIRECTION_INCOMING, MM_CALL_STATE_WAITING, "987654321" },
+ };
+
+ const gchar *urc =
+ "\r\n^CIEV: 1,0" /* some different URC before our match */
+ "\r\n+CLCC: 1,1,0,0,0,\"123456789\",161"
+ "\r\n+CLCC: 2,1,5,0,0,\"987654321\",161"
+ "\r\n^CIEV: 1,0" /* some different URC after our match */
+ "\r\n";
+
+ common_test_clcc_urc (urc, expected_call_info_list, G_N_ELEMENTS (expected_call_info_list));
+}
+
+/*****************************************************************************/
+
+static void
+common_test_voice_call_urc (const gchar *urc,
+ gboolean expected_start_or_stop,
+ guint expected_duration)
+{
+ GError *error = NULL;
+ gboolean start_or_stop = FALSE; /* start = TRUE, stop = FALSE */
+ guint duration = 0;
+ GRegex *voice_call_regex = NULL;
+ gboolean result;
+ GMatchInfo *match_info = NULL;
+
+ voice_call_regex = mm_simtech_get_voice_call_urc_regex ();
+
+ /* Same matching logic as done in MMSerialPortAt when processing URCs! */
+ result = g_regex_match_full (voice_call_regex, urc, -1, 0, 0, &match_info, &error);
+ g_assert_no_error (error);
+ g_assert (result);
+
+ result = mm_simtech_parse_voice_call_urc (match_info, &start_or_stop, &duration, &error);
+ g_assert_no_error (error);
+ g_assert (result);
+
+ g_assert_cmpuint (expected_start_or_stop, ==, start_or_stop);
+ g_assert_cmpuint (expected_duration, ==, duration);
+
+ g_match_info_free (match_info);
+ g_regex_unref (voice_call_regex);
+}
+
+static void
+test_voice_call_begin_urc (void)
+{
+ common_test_voice_call_urc ("\r\nVOICE CALL: BEGIN\r\n", TRUE, 0);
+}
+
+static void
+test_voice_call_end_urc (void)
+{
+ common_test_voice_call_urc ("\r\nVOICE CALL: END\r\n", FALSE, 0);
+}
+
+static void
+test_voice_call_end_duration_urc (void)
+{
+ common_test_voice_call_urc ("\r\nVOICE CALL: END: 000041\r\n", FALSE, 41);
+}
+
+/*****************************************************************************/
+
+static void
+common_test_missed_call_urc (const gchar *urc,
+ const gchar *expected_details)
+{
+ GError *error = NULL;
+ gchar *details = NULL;
+ GRegex *missed_call_regex = NULL;
+ gboolean result;
+ GMatchInfo *match_info = NULL;
+
+ missed_call_regex = mm_simtech_get_missed_call_urc_regex ();
+
+ /* Same matching logic as done in MMSerialPortAt when processing URCs! */
+ result = g_regex_match_full (missed_call_regex, urc, -1, 0, 0, &match_info, &error);
+ g_assert_no_error (error);
+ g_assert (result);
+
+ result = mm_simtech_parse_missed_call_urc (match_info, &details, &error);
+ g_assert_no_error (error);
+ g_assert (result);
+
+ g_assert_cmpstr (expected_details, ==, details);
+ g_free (details);
+
+ g_match_info_free (match_info);
+ g_regex_unref (missed_call_regex);
+}
+
+static void
+test_missed_call_urc (void)
+{
+ common_test_missed_call_urc ("\r\nMISSED_CALL: 11:01AM 07712345678\r\n", "11:01AM 07712345678");
+}
+
+/*****************************************************************************/
+
+static void
+common_test_cring_urc (const gchar *urc,
+ const gchar *expected_type)
+{
+ GError *error = NULL;
+ GRegex *cring_regex = NULL;
+ GMatchInfo *match_info = NULL;
+ gchar *type;
+ gboolean result;
+
+ cring_regex = mm_simtech_get_cring_urc_regex ();
+
+ /* Same matching logic as done in MMSerialPortAt when processing URCs! */
+ result = g_regex_match_full (cring_regex, urc, -1, 0, 0, &match_info, &error);
+ g_assert_no_error (error);
+ g_assert (result);
+
+ type = g_match_info_fetch (match_info, 1);
+ g_assert (type);
+
+ g_assert_cmpstr (type, ==, expected_type);
+
+ g_match_info_free (match_info);
+ g_regex_unref (cring_regex);
+ g_free (type);
+}
+
+static void
+test_cring_urc_two_crs (void)
+{
+ common_test_cring_urc ("\r\r\n+CRING: VOICE\r\r\n", "VOICE");
+}
+
+static void
+test_cring_urc_one_cr (void)
+{
+ common_test_cring_urc ("\r\n+CRING: VOICE\r\n", "VOICE");
+}
+
+/*****************************************************************************/
+
+static void
+common_test_rxdtmf_urc (const gchar *urc,
+ const gchar *expected_str)
+{
+ GError *error = NULL;
+ GRegex *rxdtmf_regex = NULL;
+ GMatchInfo *match_info = NULL;
+ gchar *type;
+ gboolean result;
+
+ rxdtmf_regex = mm_simtech_get_rxdtmf_urc_regex ();
+
+ /* Same matching logic as done in MMSerialPortAt when processing URCs! */
+ result = g_regex_match_full (rxdtmf_regex, urc, -1, 0, 0, &match_info, &error);
+ g_assert_no_error (error);
+ g_assert (result);
+
+ type = g_match_info_fetch (match_info, 1);
+ g_assert (type);
+
+ g_assert_cmpstr (type, ==, expected_str);
+
+ g_match_info_free (match_info);
+ g_regex_unref (rxdtmf_regex);
+ g_free (type);
+}
+
+static void
+test_rxdtmf_urc_two_crs (void)
+{
+ common_test_rxdtmf_urc ("\r\r\n+RXDTMF: 8\r\r\n", "8");
+ common_test_rxdtmf_urc ("\r\r\n+RXDTMF: *\r\r\n", "*");
+ common_test_rxdtmf_urc ("\r\r\n+RXDTMF: #\r\r\n", "#");
+ common_test_rxdtmf_urc ("\r\r\n+RXDTMF: A\r\r\n", "A");
+}
+
+static void
+test_rxdtmf_urc_one_cr (void)
+{
+ common_test_rxdtmf_urc ("\r\n+RXDTMF: 8\r\n", "8");
+ common_test_rxdtmf_urc ("\r\n+RXDTMF: *\r\n", "*");
+ common_test_rxdtmf_urc ("\r\n+RXDTMF: #\r\n", "#");
+ common_test_rxdtmf_urc ("\r\n+RXDTMF: A\r\n", "A");
+}
+
+/*****************************************************************************/
+
+void
+_mm_log (const char *loc,
+ const char *func,
+ guint32 level,
+ const char *fmt,
+ ...)
+{
+ va_list args;
+ gchar *msg;
+
+ if (!g_test_verbose ())
+ return;
+
+ va_start (args, fmt);
+ msg = g_strdup_vprintf (fmt, args);
+ va_end (args);
+ g_print ("%s\n", msg);
+ g_free (msg);
+}
+
+int main (int argc, char **argv)
+{
+ setlocale (LC_ALL, "");
+
+ g_test_init (&argc, &argv, NULL);
+
+ g_test_add_func ("/MM/simtech/clcc/urc/single", test_clcc_urc_single);
+ g_test_add_func ("/MM/simtech/clcc/urc/multiple", test_clcc_urc_multiple);
+ g_test_add_func ("/MM/simtech/clcc/urc/complex", test_clcc_urc_complex);
+
+ g_test_add_func ("/MM/simtech/voicecall/urc/begin", test_voice_call_begin_urc);
+ g_test_add_func ("/MM/simtech/voicecall/urc/end", test_voice_call_end_urc);
+ g_test_add_func ("/MM/simtech/voicecall/urc/end-duration", test_voice_call_end_duration_urc);
+
+ g_test_add_func ("/MM/simtech/missedcall/urc", test_missed_call_urc);
+
+ g_test_add_func ("/MM/simtech/cring/urc/two-crs", test_cring_urc_two_crs);
+ g_test_add_func ("/MM/simtech/cring/urc/one-cr", test_cring_urc_one_cr);
+
+ g_test_add_func ("/MM/simtech/rxdtmf/urc/two-crs", test_rxdtmf_urc_two_crs);
+ g_test_add_func ("/MM/simtech/rxdtmf/urc/one-cr", test_rxdtmf_urc_one_cr);
+
+ return g_test_run ();
+}
diff --git a/plugins/telit/tests/test-mm-modem-helpers-telit.c b/plugins/telit/tests/test-mm-modem-helpers-telit.c
index f95a97d..c9c30e5 100644
--- a/plugins/telit/tests/test-mm-modem-helpers-telit.c
+++ b/plugins/telit/tests/test-mm-modem-helpers-telit.c
@@ -553,17 +553,17 @@
const char *fmt,
...)
{
-#if defined ENABLE_TEST_MESSAGE_TRACES
- /* Dummy log function */
va_list args;
gchar *msg;
+ if (!g_test_verbose ())
+ return;
+
va_start (args, fmt);
msg = g_strdup_vprintf (fmt, args);
va_end (args);
g_print ("%s\n", msg);
g_free (msg);
-#endif
}
int main (int argc, char **argv)
diff --git a/plugins/tests/test-helpers.c b/plugins/tests/test-helpers.c
index 5620c04..1fe2cdc 100644
--- a/plugins/tests/test-helpers.c
+++ b/plugins/tests/test-helpers.c
@@ -24,8 +24,8 @@
void
mm_test_helpers_compare_bands (GArray *bands,
- const MMModemBand *expected_bands,
- guint n_expected_bands)
+ const MMModemBand *expected_bands,
+ guint n_expected_bands)
{
gchar *bands_str;
GArray *expected_bands_array;
diff --git a/plugins/tests/test-keyfiles.c b/plugins/tests/test-keyfiles.c
index 9604643..c1c740c 100644
--- a/plugins/tests/test-keyfiles.c
+++ b/plugins/tests/test-keyfiles.c
@@ -57,17 +57,17 @@
const char *fmt,
...)
{
-#if defined ENABLE_TEST_MESSAGE_TRACES
- /* Dummy log function */
va_list args;
gchar *msg;
+ if (!g_test_verbose ())
+ return;
+
va_start (args, fmt);
msg = g_strdup_vprintf (fmt, args);
va_end (args);
g_print ("%s\n", msg);
g_free (msg);
-#endif
}
int main (int argc, char **argv)
diff --git a/plugins/tests/test-udev-rules.c b/plugins/tests/test-udev-rules.c
index 581adca..f6dc6f4 100644
--- a/plugins/tests/test-udev-rules.c
+++ b/plugins/tests/test-udev-rules.c
@@ -22,9 +22,6 @@
#define _LIBMM_INSIDE_MM
#include <libmm-glib.h>
-/* Define symbol to enable test message traces */
-#undef ENABLE_TEST_MESSAGE_TRACES
-
#include "mm-kernel-device-generic-rules.h"
#include "mm-log.h"
@@ -133,17 +130,17 @@
const char *fmt,
...)
{
-#if defined ENABLE_TEST_MESSAGE_TRACES
- /* Dummy log function */
va_list args;
gchar *msg;
+ if (!g_test_verbose ())
+ return;
+
va_start (args, fmt);
msg = g_strdup_vprintf (fmt, args);
va_end (args);
g_print ("%s\n", msg);
g_free (msg);
-#endif
}
int main (int argc, char **argv)
diff --git a/plugins/thuraya/tests/test-mm-modem-helpers-thuraya.c b/plugins/thuraya/tests/test-mm-modem-helpers-thuraya.c
index bc05b7c..dcd4ab2 100644
--- a/plugins/thuraya/tests/test-mm-modem-helpers-thuraya.c
+++ b/plugins/thuraya/tests/test-mm-modem-helpers-thuraya.c
@@ -26,12 +26,6 @@
#include "mm-modem-helpers-thuraya.h"
#include "mm-log.h"
-#if defined ENABLE_TEST_MESSAGE_TRACES
-#define trace(message, ...) g_print (message, ##__VA_ARGS__)
-#else
-#define trace(...)
-#endif
-
/*****************************************************************************/
/* Test CPMS response */
@@ -62,7 +56,7 @@
GArray *mem2 = NULL;
GArray *mem3 = NULL;
- trace ("\nTesting thuraya +CPMS=? response...\n");
+ g_debug ("Testing thuraya +CPMS=? response...");
g_assert (mm_thuraya_3gpp_parse_cpms_test_response (reply, &mem1, &mem2, &mem3));
g_assert_cmpuint (mem1->len, ==, 5);
@@ -98,17 +92,17 @@
const char *fmt,
...)
{
-#if defined ENABLE_TEST_MESSAGE_TRACES
- /* Dummy log function */
va_list args;
gchar *msg;
+ if (!g_test_verbose ())
+ return;
+
va_start (args, fmt);
msg = g_strdup_vprintf (fmt, args);
va_end (args);
g_print ("%s\n", msg);
g_free (msg);
-#endif
}
#define TESTCASE(t, d) g_test_create_case (#t, 0, d, NULL, (GTestFixtureFunc) t, NULL)
diff --git a/plugins/ublox/mm-broadband-modem-ublox.c b/plugins/ublox/mm-broadband-modem-ublox.c
index 509c4c6..d27599b 100644
--- a/plugins/ublox/mm-broadband-modem-ublox.c
+++ b/plugins/ublox/mm-broadband-modem-ublox.c
@@ -1208,8 +1208,8 @@
{
GError *error = NULL;
- if (!iface_modem_voice_parent->cleanup_unsolicited_events_finish (self, res, &error)) {
- mm_warn ("Couldn't cleanup parent voice unsolicited events: %s", error->message);
+ if (!iface_modem_voice_parent->setup_unsolicited_events_finish (self, res, &error)) {
+ mm_warn ("Couldn't setup parent voice unsolicited events: %s", error->message);
g_error_free (error);
}
diff --git a/plugins/ublox/tests/test-modem-helpers-ublox.c b/plugins/ublox/tests/test-modem-helpers-ublox.c
index 5fad8a7..17a4641 100644
--- a/plugins/ublox/tests/test-modem-helpers-ublox.c
+++ b/plugins/ublox/tests/test-modem-helpers-ublox.c
@@ -986,17 +986,17 @@
const char *fmt,
...)
{
-#if defined ENABLE_TEST_MESSAGE_TRACES
- /* Dummy log function */
va_list args;
gchar *msg;
+ if (!g_test_verbose ())
+ return;
+
va_start (args, fmt);
msg = g_strdup_vprintf (fmt, args);
va_end (args);
g_print ("%s\n", msg);
g_free (msg);
-#endif
}
int main (int argc, char **argv)
diff --git a/plugins/x22x/77-mm-x22x-port-types.rules b/plugins/x22x/77-mm-x22x-port-types.rules
index 9ba0ae4..9d58796 100644
--- a/plugins/x22x/77-mm-x22x-port-types.rules
+++ b/plugins/x22x/77-mm-x22x-port-types.rules
@@ -40,6 +40,13 @@
ATTRS{idVendor}=="1bbb", ATTRS{idProduct}=="00B7", ENV{.MM_USBIFNUM}=="03", ENV{ID_MM_PORT_TYPE_AT_SECONDARY}="1"
ATTRS{idVendor}=="1bbb", ATTRS{idProduct}=="00B7", ENV{ID_MM_X22X_TAGGED}="1"
+# Alcaltel X602D
+ATTRS{idVendor}=="1bbb", ATTRS{idProduct}=="022c", ENV{.MM_USBIFNUM}=="00", ENV{ID_MM_PORT_IGNORE}="1"
+ATTRS{idVendor}=="1bbb", ATTRS{idProduct}=="022c", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_PORT_TYPE_AT_PRIMARY}="1"
+ATTRS{idVendor}=="1bbb", ATTRS{idProduct}=="022c", ENV{.MM_USBIFNUM}=="02", ENV{ID_MM_PORT_TYPE_AT_SECONDARY}="1"
+ATTRS{idVendor}=="1bbb", ATTRS{idProduct}=="022c", ENV{.MM_USBIFNUM}=="03", ENV{ID_MM_PORT_IGNORE}="1"
+ATTRS{idVendor}=="1bbb", ATTRS{idProduct}=="022c", ENV{ID_MM_X22X_TAGGED}="1"
+
GOTO="mm_x22x_port_types_end"
# Olivetti devices ---------------------------
diff --git a/plugins/x22x/mm-broadband-modem-x22x.c b/plugins/x22x/mm-broadband-modem-x22x.c
index ed9aec5..0d7794a 100644
--- a/plugins/x22x/mm-broadband-modem-x22x.c
+++ b/plugins/x22x/mm-broadband-modem-x22x.c
@@ -38,6 +38,13 @@
G_DEFINE_TYPE_EXTENDED (MMBroadbandModemX22x, mm_broadband_modem_x22x, MM_TYPE_BROADBAND_MODEM, 0,
G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM, iface_modem_init))
+struct _MMBroadbandModemX22xPrivate {
+ GRegex *mode_regex;
+ GRegex *sysinfo_regex;
+ GRegex *specc_regex;
+ GRegex *sperror_regex;
+};
+
/*****************************************************************************/
/* Load supported modes (Modem interface) */
@@ -303,6 +310,52 @@
}
/*****************************************************************************/
+/* Setup ports (Broadband modem class) */
+
+static void
+set_ignored_unsolicited_events_handlers (MMBroadbandModemX22x *self)
+{
+ MMPortSerialAt *ports[2];
+ guint i;
+
+ ports[0] = mm_base_modem_peek_port_primary (MM_BASE_MODEM (self));
+ ports[1] = mm_base_modem_peek_port_secondary (MM_BASE_MODEM (self));
+
+ /* Enable/disable unsolicited events in given port */
+ for (i = 0; i < G_N_ELEMENTS (ports); i++) {
+ if (!ports[i])
+ continue;
+
+ mm_port_serial_at_add_unsolicited_msg_handler (
+ ports[i],
+ self->priv->mode_regex,
+ NULL, NULL, NULL);
+ mm_port_serial_at_add_unsolicited_msg_handler (
+ ports[i],
+ self->priv->sysinfo_regex,
+ NULL, NULL, NULL);
+ mm_port_serial_at_add_unsolicited_msg_handler (
+ ports[i],
+ self->priv->specc_regex,
+ NULL, NULL, NULL);
+ mm_port_serial_at_add_unsolicited_msg_handler (
+ ports[i],
+ self->priv->sperror_regex,
+ NULL, NULL, NULL);
+ }
+}
+
+static void
+setup_ports (MMBroadbandModem *self)
+{
+ /* Call parent's setup ports first always */
+ MM_BROADBAND_MODEM_CLASS (mm_broadband_modem_x22x_parent_class)->setup_ports (self);
+
+ /* Unsolicited messages to always ignore */
+ set_ignored_unsolicited_events_handlers (MM_BROADBAND_MODEM_X22X (self));
+}
+
+/*****************************************************************************/
MMBroadbandModemX22x *
mm_broadband_modem_x22x_new (const gchar *device,
@@ -323,6 +376,30 @@
static void
mm_broadband_modem_x22x_init (MMBroadbandModemX22x *self)
{
+ self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
+ MM_TYPE_BROADBAND_MODEM_X22X,
+ MMBroadbandModemX22xPrivate);
+
+ self->priv->mode_regex = g_regex_new ("\\r\\n\\^MODE:.+\\r\\n",
+ G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
+ self->priv->sysinfo_regex = g_regex_new ("\\r\\n\\^SYSINFO:.+\\r\\n",
+ G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
+ self->priv->specc_regex = g_regex_new ("\\r\\n\\+SPECC\\r\\n",
+ G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
+ self->priv->sperror_regex = g_regex_new ("\\r\\n\\+SPERROR:.+\\r\\n",
+ G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
+}
+
+static void
+finalize (GObject *object)
+{
+ MMBroadbandModemX22x *self = MM_BROADBAND_MODEM_X22X (object);
+
+ g_regex_unref (self->priv->mode_regex);
+ g_regex_unref (self->priv->sysinfo_regex);
+ g_regex_unref (self->priv->specc_regex);
+ g_regex_unref (self->priv->sperror_regex);
+ G_OBJECT_CLASS (mm_broadband_modem_x22x_parent_class)->finalize (object);
}
static void
@@ -343,4 +420,12 @@
static void
mm_broadband_modem_x22x_class_init (MMBroadbandModemX22xClass *klass)
{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ MMBroadbandModemClass *broadband_modem_class = MM_BROADBAND_MODEM_CLASS (klass);
+
+ g_type_class_add_private (object_class, sizeof (MMBroadbandModemX22xPrivate));
+
+ object_class->finalize = finalize;
+
+ broadband_modem_class->setup_ports = setup_ports;
}
diff --git a/plugins/x22x/mm-broadband-modem-x22x.h b/plugins/x22x/mm-broadband-modem-x22x.h
index f61e301..74c2b48 100644
--- a/plugins/x22x/mm-broadband-modem-x22x.h
+++ b/plugins/x22x/mm-broadband-modem-x22x.h
@@ -29,9 +29,11 @@
typedef struct _MMBroadbandModemX22x MMBroadbandModemX22x;
typedef struct _MMBroadbandModemX22xClass MMBroadbandModemX22xClass;
+typedef struct _MMBroadbandModemX22xPrivate MMBroadbandModemX22xPrivate;
struct _MMBroadbandModemX22x {
MMBroadbandModem parent;
+ MMBroadbandModemX22xPrivate *priv;
};
struct _MMBroadbandModemX22xClass{
diff --git a/plugins/xmm/tests/test-modem-helpers-xmm.c b/plugins/xmm/tests/test-modem-helpers-xmm.c
index 28aea93..b4a8b2b 100644
--- a/plugins/xmm/tests/test-modem-helpers-xmm.c
+++ b/plugins/xmm/tests/test-modem-helpers-xmm.c
@@ -760,17 +760,17 @@
const char *fmt,
...)
{
-#if defined ENABLE_TEST_MESSAGE_TRACES
- /* Dummy log function */
va_list args;
gchar *msg;
+ if (!g_test_verbose ())
+ return;
+
va_start (args, fmt);
msg = g_strdup_vprintf (fmt, args);
va_end (args);
g_print ("%s\n", msg);
g_free (msg);
-#endif
}
int main (int argc, char **argv)
diff --git a/po/cs.po b/po/cs.po
index 7427623..568e43f 100644
--- a/po/cs.po
+++ b/po/cs.po
@@ -8,7 +8,7 @@
msgstr ""
"Project-Id-Version: ModemManager master\n"
"Report-Msgid-Bugs-To: modemmanager-devel@lists.freedesktop.org\n"
-"POT-Creation-Date: 2017-10-22 11:32+0200\n"
+"POT-Creation-Date: 2019-09-25 12:48+0200\n"
"PO-Revision-Date: 2017-10-21 15:32+0200\n"
"Last-Translator: Marek Černocký <marek@manet.cz>\n"
"Language-Team: čeština <gnome-cs-list@gnome.org>\n"
@@ -69,22 +69,33 @@
msgstr "Systémová zásada brání v hlasových hovorech."
#: data/org.freedesktop.ModemManager1.policy.in.in:58
+msgid "Query network time and timezone information"
+msgstr ""
+
+#: data/org.freedesktop.ModemManager1.policy.in.in:59
+#, fuzzy
+msgid "System policy prevents querying network time information."
+msgstr ""
+"Systémová zásada brání v dotazování na informace o síti a na služby, nebo "
+"brání v jejich využívání."
+
+#: data/org.freedesktop.ModemManager1.policy.in.in:67
msgid "Enable and view geographic location and positioning information"
msgstr ""
"Povolovat sdělování a zobrazování geografické polohy a informací o pozici"
-#: data/org.freedesktop.ModemManager1.policy.in.in:59
+#: data/org.freedesktop.ModemManager1.policy.in.in:68
msgid ""
"System policy prevents enabling or viewing geographic location information."
msgstr ""
"Systémová zásada brání v povolení sdělování a v zobrazení informací o "
"geografické poloze."
-#: data/org.freedesktop.ModemManager1.policy.in.in:67
+#: data/org.freedesktop.ModemManager1.policy.in.in:76
msgid "Query and utilize network information and services"
msgstr "Dotazovat se na informace o síti a na služby a využívat je"
-#: data/org.freedesktop.ModemManager1.policy.in.in:68
+#: data/org.freedesktop.ModemManager1.policy.in.in:77
msgid ""
"System policy prevents querying or utilizing network information and "
"services."
@@ -92,12 +103,12 @@
"Systémová zásada brání v dotazování na informace o síti a na služby, nebo "
"brání v jejich využívání."
-#: data/org.freedesktop.ModemManager1.policy.in.in:76
+#: data/org.freedesktop.ModemManager1.policy.in.in:85
msgid "Query and manage firmware on a mobile broadband device"
msgstr ""
"Dotazovat se na firmware a spravovat jej na mobilním širokopásmovém zařízení"
-#: data/org.freedesktop.ModemManager1.policy.in.in:77
+#: data/org.freedesktop.ModemManager1.policy.in.in:86
msgid "System policy prevents querying or managing this device's firmware."
msgstr ""
"Systémová zásada brání v dotázání na firmware nebo brání v jeho správě na "
diff --git a/po/da.po b/po/da.po
index 30c76d0..9473d0a 100644
--- a/po/da.po
+++ b/po/da.po
@@ -6,7 +6,7 @@
msgstr ""
"Project-Id-Version: ModemManager master\n"
"Report-Msgid-Bugs-To: modemmanager-devel@lists.freedesktop.org\n"
-"POT-Creation-Date: 2019-02-11 17:22+0100\n"
+"POT-Creation-Date: 2019-09-25 12:48+0200\n"
"PO-Revision-Date: 2019-02-10 16:46+0200\n"
"Last-Translator: scootergrisen\n"
"Language-Team: Danish\n"
@@ -65,21 +65,32 @@
msgstr "Systempolitikken forhindrer stemmeopkald."
#: data/org.freedesktop.ModemManager1.policy.in.in:58
+msgid "Query network time and timezone information"
+msgstr ""
+
+#: data/org.freedesktop.ModemManager1.policy.in.in:59
+#, fuzzy
+msgid "System policy prevents querying network time information."
+msgstr ""
+"Systempolitikken forhindrer forespørgsel eller anvendelse af "
+"netværksinformation og -tjenester."
+
+#: data/org.freedesktop.ModemManager1.policy.in.in:67
msgid "Enable and view geographic location and positioning information"
msgstr "Aktivér og vis information om geografisk placering og positition"
-#: data/org.freedesktop.ModemManager1.policy.in.in:59
+#: data/org.freedesktop.ModemManager1.policy.in.in:68
msgid ""
"System policy prevents enabling or viewing geographic location information."
msgstr ""
"Systempolitikken forhindrer aktivering og visning af information geografisk "
"placering."
-#: data/org.freedesktop.ModemManager1.policy.in.in:67
+#: data/org.freedesktop.ModemManager1.policy.in.in:76
msgid "Query and utilize network information and services"
msgstr "Forespørg og anvend netværksinformation og -tjenester"
-#: data/org.freedesktop.ModemManager1.policy.in.in:68
+#: data/org.freedesktop.ModemManager1.policy.in.in:77
msgid ""
"System policy prevents querying or utilizing network information and "
"services."
@@ -87,11 +98,11 @@
"Systempolitikken forhindrer forespørgsel eller anvendelse af "
"netværksinformation og -tjenester."
-#: data/org.freedesktop.ModemManager1.policy.in.in:76
+#: data/org.freedesktop.ModemManager1.policy.in.in:85
msgid "Query and manage firmware on a mobile broadband device"
msgstr "Forespørg og håndter firmware på en mobilt bredbånd-enhed"
-#: data/org.freedesktop.ModemManager1.policy.in.in:77
+#: data/org.freedesktop.ModemManager1.policy.in.in:86
msgid "System policy prevents querying or managing this device's firmware."
msgstr ""
"Systempolitikken forhindrer forespørgsel og håndtering af enhedens firmware."
diff --git a/po/de.po b/po/de.po
index 7fc9dc4..7e0281f 100644
--- a/po/de.po
+++ b/po/de.po
@@ -8,7 +8,7 @@
msgstr ""
"Project-Id-Version: ModemManager\n"
"Report-Msgid-Bugs-To: modemmanager-devel@lists.freedesktop.org\n"
-"POT-Creation-Date: 2017-08-29 09:24+0200\n"
+"POT-Creation-Date: 2019-09-25 12:48+0200\n"
"PO-Revision-Date: 2014-01-06 21:23+0100\n"
"Last-Translator: Mario Blättermann <mario.blaettermann@gmail.com>\n"
"Language-Team: German <debian-l10n-german@lists.debian.org>\n"
@@ -70,23 +70,34 @@
msgstr "Die Systemrichtlinien verhindern die Steuerung von ModemManager."
#: data/org.freedesktop.ModemManager1.policy.in.in:58
+msgid "Query network time and timezone information"
+msgstr ""
+
+#: data/org.freedesktop.ModemManager1.policy.in.in:59
+#, fuzzy
+msgid "System policy prevents querying network time information."
+msgstr ""
+"Die Systemrichtlinien verhindern die Abfrage der Netzwerkinformationen und -"
+"dienste."
+
+#: data/org.freedesktop.ModemManager1.policy.in.in:67
msgid "Enable and view geographic location and positioning information"
msgstr ""
"Informationen zum geografischen Standort und Positionierung aktivieren und "
"anzeigen"
-#: data/org.freedesktop.ModemManager1.policy.in.in:59
+#: data/org.freedesktop.ModemManager1.policy.in.in:68
msgid ""
"System policy prevents enabling or viewing geographic location information."
msgstr ""
"Die Systemrichtlinien verhindern das Aktivieren oder Ändern der "
"Informationen zum geografischen Standort."
-#: data/org.freedesktop.ModemManager1.policy.in.in:67
+#: data/org.freedesktop.ModemManager1.policy.in.in:76
msgid "Query and utilize network information and services"
msgstr "Netzwerkinformationen und -dienste abfragen und nutzen"
-#: data/org.freedesktop.ModemManager1.policy.in.in:68
+#: data/org.freedesktop.ModemManager1.policy.in.in:77
msgid ""
"System policy prevents querying or utilizing network information and "
"services."
@@ -94,11 +105,11 @@
"Die Systemrichtlinien verhindern die Abfrage der Netzwerkinformationen und -"
"dienste."
-#: data/org.freedesktop.ModemManager1.policy.in.in:76
+#: data/org.freedesktop.ModemManager1.policy.in.in:85
msgid "Query and manage firmware on a mobile broadband device"
msgstr "Firmware auf mobilen Breitbandgeräten abfragen und verwalten"
-#: data/org.freedesktop.ModemManager1.policy.in.in:77
+#: data/org.freedesktop.ModemManager1.policy.in.in:86
msgid "System policy prevents querying or managing this device's firmware."
msgstr ""
"Die Systemrichtlinien verhindern die Abfrage oder Verwaltung der Firmware "
diff --git a/po/fr.po b/po/fr.po
index 8408271..c86ecd1 100644
--- a/po/fr.po
+++ b/po/fr.po
@@ -8,7 +8,7 @@
msgstr ""
"Project-Id-Version: ModemManager master\n"
"Report-Msgid-Bugs-To: modemmanager-devel@lists.freedesktop.org\n"
-"POT-Creation-Date: 2018-09-13 09:33+0200\n"
+"POT-Creation-Date: 2019-09-25 12:48+0200\n"
"PO-Revision-Date: 2018-08-18 16:17+0200\n"
"Last-Translator: Claude Paroz <claude@2xlibre.net>\n"
"Language-Team: French <gnomefr@traduc.org>\n"
@@ -68,21 +68,32 @@
msgstr "La politique système empêche les appels vocaux."
#: data/org.freedesktop.ModemManager1.policy.in.in:58
+msgid "Query network time and timezone information"
+msgstr ""
+
+#: data/org.freedesktop.ModemManager1.policy.in.in:59
+#, fuzzy
+msgid "System policy prevents querying network time information."
+msgstr ""
+"La politique système empêche l’interrogation et l’utilisation des "
+"informations et des services du réseau."
+
+#: data/org.freedesktop.ModemManager1.policy.in.in:67
msgid "Enable and view geographic location and positioning information"
msgstr "Activer et voir les informations de position géographique"
-#: data/org.freedesktop.ModemManager1.policy.in.in:59
+#: data/org.freedesktop.ModemManager1.policy.in.in:68
msgid ""
"System policy prevents enabling or viewing geographic location information."
msgstr ""
"La politique système empêche d’activer ou de voir les informations de "
"position géographique."
-#: data/org.freedesktop.ModemManager1.policy.in.in:67
+#: data/org.freedesktop.ModemManager1.policy.in.in:76
msgid "Query and utilize network information and services"
msgstr "Interroger et utiliser les informations et services du réseau"
-#: data/org.freedesktop.ModemManager1.policy.in.in:68
+#: data/org.freedesktop.ModemManager1.policy.in.in:77
msgid ""
"System policy prevents querying or utilizing network information and "
"services."
@@ -90,11 +101,11 @@
"La politique système empêche l’interrogation et l’utilisation des "
"informations et des services du réseau."
-#: data/org.freedesktop.ModemManager1.policy.in.in:76
+#: data/org.freedesktop.ModemManager1.policy.in.in:85
msgid "Query and manage firmware on a mobile broadband device"
msgstr "Interroger et gérer le matériel d’un périphérique mobile à large bande"
-#: data/org.freedesktop.ModemManager1.policy.in.in:77
+#: data/org.freedesktop.ModemManager1.policy.in.in:86
msgid "System policy prevents querying or managing this device's firmware."
msgstr ""
"La politique système empêche l’interrogation et la gestion du matériel de ce "
diff --git a/po/fur.po b/po/fur.po
index 67e4961..536e482 100644
--- a/po/fur.po
+++ b/po/fur.po
@@ -7,7 +7,7 @@
msgstr ""
"Project-Id-Version: ModemManager master\n"
"Report-Msgid-Bugs-To: modemmanager-devel@lists.freedesktop.org\n"
-"POT-Creation-Date: 2018-06-19 17:58+0200\n"
+"POT-Creation-Date: 2019-09-25 12:48+0200\n"
"PO-Revision-Date: 2018-03-25 17:20+0200\n"
"Last-Translator: Fabio Tomat <f.t.public@gmail.com>\n"
"Language-Team: Friulian <f.t.public@gmail.com>\n"
@@ -69,22 +69,33 @@
msgstr "La politiche dal sisteme e impedìs lis clamadis vocâls."
#: data/org.freedesktop.ModemManager1.policy.in.in:58
+msgid "Query network time and timezone information"
+msgstr ""
+
+#: data/org.freedesktop.ModemManager1.policy.in.in:59
+#, fuzzy
+msgid "System policy prevents querying network time information."
+msgstr ""
+"La politiche dal sisteme e impedìs la interogazion e la utilizazion di "
+"informazions di rêt e servizis."
+
+#: data/org.freedesktop.ModemManager1.policy.in.in:67
msgid "Enable and view geographic location and positioning information"
msgstr ""
"Abilite e viôt la posizion gjeografiche e lis informazions su la posizion"
-#: data/org.freedesktop.ModemManager1.policy.in.in:59
+#: data/org.freedesktop.ModemManager1.policy.in.in:68
msgid ""
"System policy prevents enabling or viewing geographic location information."
msgstr ""
"La politiche dal sisteme e impedìs di abilitâ o viodi lis informazions su la "
"posizion gjeografiche."
-#: data/org.freedesktop.ModemManager1.policy.in.in:67
+#: data/org.freedesktop.ModemManager1.policy.in.in:76
msgid "Query and utilize network information and services"
msgstr "Interoghe e dopre lis informazions di rêt e i servizis"
-#: data/org.freedesktop.ModemManager1.policy.in.in:68
+#: data/org.freedesktop.ModemManager1.policy.in.in:77
msgid ""
"System policy prevents querying or utilizing network information and "
"services."
@@ -92,12 +103,12 @@
"La politiche dal sisteme e impedìs la interogazion e la utilizazion di "
"informazions di rêt e servizis."
-#: data/org.freedesktop.ModemManager1.policy.in.in:76
+#: data/org.freedesktop.ModemManager1.policy.in.in:85
msgid "Query and manage firmware on a mobile broadband device"
msgstr ""
"Interoghe e gjestìs il firmware suntun dispositîf a bande largje mobile"
-#: data/org.freedesktop.ModemManager1.policy.in.in:77
+#: data/org.freedesktop.ModemManager1.policy.in.in:86
msgid "System policy prevents querying or managing this device's firmware."
msgstr ""
"La politiche dal sisteme e impedìs di interogâ o gjestî il firmware di chest "
diff --git a/po/hu.po b/po/hu.po
index 53b9e9d..6b204c2 100644
--- a/po/hu.po
+++ b/po/hu.po
@@ -7,7 +7,7 @@
msgstr ""
"Project-Id-Version: modemmanager master\n"
"Report-Msgid-Bugs-To: modemmanager-devel@lists.freedesktop.org\n"
-"POT-Creation-Date: 2017-09-27 21:46+0200\n"
+"POT-Creation-Date: 2019-09-25 12:48+0200\n"
"PO-Revision-Date: 2017-09-26 22:02+0000\n"
"Last-Translator: Gabor Kelemen <kelemeng@openscope.org>\n"
"Language-Team: Hungarian <hu@li.org>\n"
@@ -66,22 +66,33 @@
msgstr "A rendszer házirendje nem teszi lehetővé a hívásokat."
#: data/org.freedesktop.ModemManager1.policy.in.in:58
+msgid "Query network time and timezone information"
+msgstr ""
+
+#: data/org.freedesktop.ModemManager1.policy.in.in:59
+#, fuzzy
+msgid "System policy prevents querying network time information."
+msgstr ""
+"A rendszer házirendje nem teszi lehetővé a hálózati információk és "
+"szolgáltatások lekérdezését és használatát."
+
+#: data/org.freedesktop.ModemManager1.policy.in.in:67
msgid "Enable and view geographic location and positioning information"
msgstr ""
"Földrajzi helyzetmeghatározás bekapcsolása és az információk megtekintése"
-#: data/org.freedesktop.ModemManager1.policy.in.in:59
+#: data/org.freedesktop.ModemManager1.policy.in.in:68
msgid ""
"System policy prevents enabling or viewing geographic location information."
msgstr ""
"A rendszer házirendje nem teszi lehetővé a földrajzi helyzetmeghatározás "
"bekapcsolását vagy az információk megtekintését."
-#: data/org.freedesktop.ModemManager1.policy.in.in:67
+#: data/org.freedesktop.ModemManager1.policy.in.in:76
msgid "Query and utilize network information and services"
msgstr "Hálózati információk és szolgáltatások lekérdezése és használata"
-#: data/org.freedesktop.ModemManager1.policy.in.in:68
+#: data/org.freedesktop.ModemManager1.policy.in.in:77
msgid ""
"System policy prevents querying or utilizing network information and "
"services."
@@ -89,11 +100,11 @@
"A rendszer házirendje nem teszi lehetővé a hálózati információk és "
"szolgáltatások lekérdezését és használatát."
-#: data/org.freedesktop.ModemManager1.policy.in.in:76
+#: data/org.freedesktop.ModemManager1.policy.in.in:85
msgid "Query and manage firmware on a mobile broadband device"
msgstr "Firmware lekérdezése és kezelése a mobil széles sávú eszközön"
-#: data/org.freedesktop.ModemManager1.policy.in.in:77
+#: data/org.freedesktop.ModemManager1.policy.in.in:86
msgid "System policy prevents querying or managing this device's firmware."
msgstr ""
"A rendszer lekérdezése és használata lehetővé a firmware lekérdezését és "
diff --git a/po/id.po b/po/id.po
index 9efd0cc..a6142a5 100644
--- a/po/id.po
+++ b/po/id.po
@@ -7,7 +7,7 @@
msgstr ""
"Project-Id-Version: ModemManager master\n"
"Report-Msgid-Bugs-To: modemmanager-devel@lists.freedesktop.org\n"
-"POT-Creation-Date: 2018-03-04 16:56+0100\n"
+"POT-Creation-Date: 2019-09-25 12:48+0200\n"
"PO-Revision-Date: 2018-03-04 20:31+0700\n"
"Last-Translator: Andika Triwidada <andika@gmail.com>\n"
"Language-Team: Indonesian <gnome-l10n-id@googlegroups.com>\n"
@@ -67,21 +67,32 @@
msgstr "Kebijakan sistem mencegah panggilan suara."
#: data/org.freedesktop.ModemManager1.policy.in.in:58
+msgid "Query network time and timezone information"
+msgstr ""
+
+#: data/org.freedesktop.ModemManager1.policy.in.in:59
+#, fuzzy
+msgid "System policy prevents querying network time information."
+msgstr ""
+"Kebijakan sistem mencegah kueri atau pemanfaatan layanan dan informasi "
+"jaringan."
+
+#: data/org.freedesktop.ModemManager1.policy.in.in:67
msgid "Enable and view geographic location and positioning information"
msgstr "Fungsikan dan tilik lokasi geografis dan informasi posisi"
-#: data/org.freedesktop.ModemManager1.policy.in.in:59
+#: data/org.freedesktop.ModemManager1.policy.in.in:68
msgid ""
"System policy prevents enabling or viewing geographic location information."
msgstr ""
"Kebijakan sistem mencegah memfungsikan atau menilik informasi lokasi "
"geografis."
-#: data/org.freedesktop.ModemManager1.policy.in.in:67
+#: data/org.freedesktop.ModemManager1.policy.in.in:76
msgid "Query and utilize network information and services"
msgstr "Kueri dan manfaatkan layanan dan informasi jaringan"
-#: data/org.freedesktop.ModemManager1.policy.in.in:68
+#: data/org.freedesktop.ModemManager1.policy.in.in:77
msgid ""
"System policy prevents querying or utilizing network information and "
"services."
@@ -89,11 +100,11 @@
"Kebijakan sistem mencegah kueri atau pemanfaatan layanan dan informasi "
"jaringan."
-#: data/org.freedesktop.ModemManager1.policy.in.in:76
+#: data/org.freedesktop.ModemManager1.policy.in.in:85
msgid "Query and manage firmware on a mobile broadband device"
msgstr "Kueri dan kelola firmware pada suatu peranti data seluler"
-#: data/org.freedesktop.ModemManager1.policy.in.in:77
+#: data/org.freedesktop.ModemManager1.policy.in.in:86
msgid "System policy prevents querying or managing this device's firmware."
msgstr "Kebijakan sistem mencegah kueri atau pengelolaan firmware peranti ini."
diff --git a/po/it.po b/po/it.po
index b32735c..a15f503 100644
--- a/po/it.po
+++ b/po/it.po
@@ -7,7 +7,7 @@
msgstr ""
"Project-Id-Version: ModemManager master\n"
"Report-Msgid-Bugs-To: modemmanager-devel@lists.freedesktop.org\n"
-"POT-Creation-Date: 2018-09-13 09:33+0200\n"
+"POT-Creation-Date: 2019-09-25 12:48+0200\n"
"PO-Revision-Date: 2018-09-11 11:25+0200\n"
"Last-Translator: Milo Casagrande <milo@milo.name>\n"
"Language-Team: Italian <gnome-it-list@gnome.org>\n"
@@ -68,22 +68,33 @@
msgstr "La politica di sistema impedisce di effettuare chiamate vocali."
#: data/org.freedesktop.ModemManager1.policy.in.in:58
+msgid "Query network time and timezone information"
+msgstr ""
+
+#: data/org.freedesktop.ModemManager1.policy.in.in:59
+#, fuzzy
+msgid "System policy prevents querying network time information."
+msgstr ""
+"La politica di sistema impedisce di interrogare o di utilizzare le "
+"informazioni e i servizi della rete."
+
+#: data/org.freedesktop.ModemManager1.policy.in.in:67
msgid "Enable and view geographic location and positioning information"
msgstr ""
"Abilita e visualizza informazioni di geolocalizzazione e posizionamento"
-#: data/org.freedesktop.ModemManager1.policy.in.in:59
+#: data/org.freedesktop.ModemManager1.policy.in.in:68
msgid ""
"System policy prevents enabling or viewing geographic location information."
msgstr ""
"La politica di sistema impedisce di abilitare o visualizzare informazioni di "
"geolocalizzazione."
-#: data/org.freedesktop.ModemManager1.policy.in.in:67
+#: data/org.freedesktop.ModemManager1.policy.in.in:76
msgid "Query and utilize network information and services"
msgstr "Interroga e utilizza informazioni e servizi della rete"
-#: data/org.freedesktop.ModemManager1.policy.in.in:68
+#: data/org.freedesktop.ModemManager1.policy.in.in:77
msgid ""
"System policy prevents querying or utilizing network information and "
"services."
@@ -91,12 +102,12 @@
"La politica di sistema impedisce di interrogare o di utilizzare le "
"informazioni e i servizi della rete."
-#: data/org.freedesktop.ModemManager1.policy.in.in:76
+#: data/org.freedesktop.ModemManager1.policy.in.in:85
msgid "Query and manage firmware on a mobile broadband device"
msgstr ""
"Interroga e gestisce il firmware su un dispositivo mobile a banda larga"
-#: data/org.freedesktop.ModemManager1.policy.in.in:77
+#: data/org.freedesktop.ModemManager1.policy.in.in:86
msgid "System policy prevents querying or managing this device's firmware."
msgstr ""
"La politica di sistema impedisce di interrogare o gestire il firmware di "
diff --git a/po/lt.po b/po/lt.po
index ded731e..d238b02 100644
--- a/po/lt.po
+++ b/po/lt.po
@@ -7,7 +7,7 @@
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: modemmanager-devel@lists.freedesktop.org\n"
-"POT-Creation-Date: 2019-04-25 10:07+0200\n"
+"POT-Creation-Date: 2019-09-25 12:48+0200\n"
"PO-Revision-Date: 2019-04-13 22:08+0300\n"
"Last-Translator: \n"
"Language-Team: \n"
@@ -72,20 +72,31 @@
msgstr "Sistemos politika neleidžia balso skambučių."
#: data/org.freedesktop.ModemManager1.policy.in.in:58
+msgid "Query network time and timezone information"
+msgstr ""
+
+#: data/org.freedesktop.ModemManager1.policy.in.in:59
+#, fuzzy
+msgid "System policy prevents querying network time information."
+msgstr ""
+"Sistemos politika neleidžia užklausti ar panaudoti tinklo informacija ir "
+"paslaugas."
+
+#: data/org.freedesktop.ModemManager1.policy.in.in:67
msgid "Enable and view geographic location and positioning information"
msgstr "Įjungti ir rodyti geografinės vietos bei pozicionavimo informaciją"
-#: data/org.freedesktop.ModemManager1.policy.in.in:59
+#: data/org.freedesktop.ModemManager1.policy.in.in:68
msgid ""
"System policy prevents enabling or viewing geographic location information."
msgstr ""
"Sistemos politika neleidžia įjungti ar rodyti geografinės vietos informaciją."
-#: data/org.freedesktop.ModemManager1.policy.in.in:67
+#: data/org.freedesktop.ModemManager1.policy.in.in:76
msgid "Query and utilize network information and services"
msgstr "Užklausti ir panaudoti tinklo informacija bei paslaugas"
-#: data/org.freedesktop.ModemManager1.policy.in.in:68
+#: data/org.freedesktop.ModemManager1.policy.in.in:77
msgid ""
"System policy prevents querying or utilizing network information and "
"services."
@@ -93,13 +104,13 @@
"Sistemos politika neleidžia užklausti ar panaudoti tinklo informacija ir "
"paslaugas."
-#: data/org.freedesktop.ModemManager1.policy.in.in:76
+#: data/org.freedesktop.ModemManager1.policy.in.in:85
msgid "Query and manage firmware on a mobile broadband device"
msgstr ""
"Užklausti ir tvarkyti programinę aparatinę įrangą mobiliojo plačiajuosčio "
"ryšio įrenginyje"
-#: data/org.freedesktop.ModemManager1.policy.in.in:77
+#: data/org.freedesktop.ModemManager1.policy.in.in:86
msgid "System policy prevents querying or managing this device's firmware."
msgstr ""
"Sistemos politika neleidžia užklausti ar tvarkyti šio įrenginio programinę "
diff --git a/po/pl.po b/po/pl.po
index f3c1803..928c378 100644
--- a/po/pl.po
+++ b/po/pl.po
@@ -1,15 +1,15 @@
# Polish translation for ModemManager.
-# Copyright © 2017 the ModemManager authors.
+# Copyright © 2017-2019 the ModemManager authors.
# This file is distributed under the same license as the ModemManager package.
-# Piotr Drąg <piotrdrag@gmail.com>, 2017.
-# Aviary.pl <community-poland@mozilla.org>, 2017.
+# Piotr Drąg <piotrdrag@gmail.com>, 2017-2019.
+# Aviary.pl <community-poland@mozilla.org>, 2017-2019.
#
msgid ""
msgstr ""
"Project-Id-Version: ModemManager\n"
"Report-Msgid-Bugs-To: modemmanager-devel@lists.freedesktop.org\n"
-"POT-Creation-Date: 2017-09-07 13:12+0200\n"
-"PO-Revision-Date: 2017-09-06 19:15+0200\n"
+"POT-Creation-Date: 2019-09-26 03:26+0000\n"
+"PO-Revision-Date: 2019-09-28 15:02+0200\n"
"Last-Translator: Piotr Drąg <piotrdrag@gmail.com>\n"
"Language-Team: Polish <community-poland@mozilla.org>\n"
"Language: pl\n"
@@ -69,23 +69,32 @@
msgstr "Ustawienia systemu uniemożliwiają dzwonienie."
#: data/org.freedesktop.ModemManager1.policy.in.in:58
+msgid "Query network time and timezone information"
+msgstr "Odpytywanie informacji o czasie sieciowym i strefie czasowej"
+
+#: data/org.freedesktop.ModemManager1.policy.in.in:59
+msgid "System policy prevents querying network time information."
+msgstr ""
+"Ustawienia systemu uniemożliwiają odpytywanie informacji o czasie sieciowym."
+
+#: data/org.freedesktop.ModemManager1.policy.in.in:67
msgid "Enable and view geographic location and positioning information"
msgstr ""
"Włączanie i wyświetlanie informacji o położeniu geograficznym "
"i pozycjonowaniu"
-#: data/org.freedesktop.ModemManager1.policy.in.in:59
+#: data/org.freedesktop.ModemManager1.policy.in.in:68
msgid ""
"System policy prevents enabling or viewing geographic location information."
msgstr ""
"Ustawienia systemu uniemożliwiają włączanie lub wyświetlanie informacji "
"o położeniu geograficznym."
-#: data/org.freedesktop.ModemManager1.policy.in.in:67
+#: data/org.freedesktop.ModemManager1.policy.in.in:76
msgid "Query and utilize network information and services"
msgstr "Odpytywanie i używanie informacji i usług sieciowych"
-#: data/org.freedesktop.ModemManager1.policy.in.in:68
+#: data/org.freedesktop.ModemManager1.policy.in.in:77
msgid ""
"System policy prevents querying or utilizing network information and "
"services."
@@ -93,12 +102,12 @@
"Ustawienia systemu uniemożliwiają odpytywanie lub używanie informacji "
"i usług sieciowych."
-#: data/org.freedesktop.ModemManager1.policy.in.in:76
+#: data/org.freedesktop.ModemManager1.policy.in.in:85
msgid "Query and manage firmware on a mobile broadband device"
msgstr ""
"Odpytywanie i zarządzanie oprogramowaniem sprzętowym urządzenia komórkowego"
-#: data/org.freedesktop.ModemManager1.policy.in.in:77
+#: data/org.freedesktop.ModemManager1.policy.in.in:86
msgid "System policy prevents querying or managing this device's firmware."
msgstr ""
"Ustawienia systemu uniemożliwiają odpytywanie lub zarządzanie "
diff --git a/po/pt_BR.po b/po/pt_BR.po
index a9d7446..d2860ac 100644
--- a/po/pt_BR.po
+++ b/po/pt_BR.po
@@ -6,7 +6,7 @@
msgstr ""
"Project-Id-Version: ModemManager master\n"
"Report-Msgid-Bugs-To: modemmanager-devel@lists.freedesktop.org\n"
-"POT-Creation-Date: 2017-09-07 13:35+0200\n"
+"POT-Creation-Date: 2019-09-25 12:48+0200\n"
"PO-Revision-Date: 2017-09-05 21:49-0200\n"
"Last-Translator: Rafael Fontenelle <rafaelff@gnome.org>\n"
"Language-Team: Brazilian Portuguese <gnome-pt_br-list@gnome.org>\n"
@@ -67,21 +67,32 @@
msgstr "A política de sistema impede chamadas de voz."
#: data/org.freedesktop.ModemManager1.policy.in.in:58
+msgid "Query network time and timezone information"
+msgstr ""
+
+#: data/org.freedesktop.ModemManager1.policy.in.in:59
+#, fuzzy
+msgid "System policy prevents querying network time information."
+msgstr ""
+"A política de sistema impede de consultar ou utilizar serviços e informações "
+"de rede."
+
+#: data/org.freedesktop.ModemManager1.policy.in.in:67
msgid "Enable and view geographic location and positioning information"
msgstr "Habilitar e ver informações de posicionamento e localização geográfica"
-#: data/org.freedesktop.ModemManager1.policy.in.in:59
+#: data/org.freedesktop.ModemManager1.policy.in.in:68
msgid ""
"System policy prevents enabling or viewing geographic location information."
msgstr ""
"A política de sistema impede de habilitar ou ver informações de localização "
"geográfica."
-#: data/org.freedesktop.ModemManager1.policy.in.in:67
+#: data/org.freedesktop.ModemManager1.policy.in.in:76
msgid "Query and utilize network information and services"
msgstr "Consultar ou utilizar serviços e informações de rede."
-#: data/org.freedesktop.ModemManager1.policy.in.in:68
+#: data/org.freedesktop.ModemManager1.policy.in.in:77
msgid ""
"System policy prevents querying or utilizing network information and "
"services."
@@ -89,11 +100,11 @@
"A política de sistema impede de consultar ou utilizar serviços e informações "
"de rede."
-#: data/org.freedesktop.ModemManager1.policy.in.in:76
+#: data/org.freedesktop.ModemManager1.policy.in.in:85
msgid "Query and manage firmware on a mobile broadband device"
msgstr "Consultar e gerenciar firmware em um dispositivo de banda larga móvel"
-#: data/org.freedesktop.ModemManager1.policy.in.in:77
+#: data/org.freedesktop.ModemManager1.policy.in.in:86
msgid "System policy prevents querying or managing this device's firmware."
msgstr ""
"A política de sistema impede de consultar ou gerenciar o firmware do "
diff --git a/po/sk.po b/po/sk.po
index 46c858a..a8e342f 100644
--- a/po/sk.po
+++ b/po/sk.po
@@ -7,7 +7,7 @@
msgstr ""
"Project-Id-Version: ModemManager master\n"
"Report-Msgid-Bugs-To: modemmanager-devel@lists.freedesktop.org\n"
-"POT-Creation-Date: 2017-09-16 10:32-0700\n"
+"POT-Creation-Date: 2019-09-25 12:48+0200\n"
"PO-Revision-Date: 2017-09-16 08:51+0200\n"
"Last-Translator: Dušan Kazik <prescott66@gmail.com>\n"
"Language-Team: Slovak <gnome-sk-list@gnome.org>\n"
@@ -71,21 +71,32 @@
msgstr "Politika systému zabraňuje hlasovým hovorom."
#: data/org.freedesktop.ModemManager1.policy.in.in:58
+msgid "Query network time and timezone information"
+msgstr ""
+
+#: data/org.freedesktop.ModemManager1.policy.in.in:59
+#, fuzzy
+msgid "System policy prevents querying network time information."
+msgstr ""
+"Politika systému zabraňuje požadovaniu, alebo spracovaniu sieťových "
+"informácií a službám."
+
+#: data/org.freedesktop.ModemManager1.policy.in.in:67
msgid "Enable and view geographic location and positioning information"
msgstr "Povolenie a zobrazenie geografickej polohy a informácií o pozícii"
-#: data/org.freedesktop.ModemManager1.policy.in.in:59
+#: data/org.freedesktop.ModemManager1.policy.in.in:68
msgid ""
"System policy prevents enabling or viewing geographic location information."
msgstr ""
"Politika systému zabraňuje povoleniu, alebo zobrazeniu informácií o "
"geografickej polohe."
-#: data/org.freedesktop.ModemManager1.policy.in.in:67
+#: data/org.freedesktop.ModemManager1.policy.in.in:76
msgid "Query and utilize network information and services"
msgstr "Požadovanie a spracovanie sieťových informácií a služieb"
-#: data/org.freedesktop.ModemManager1.policy.in.in:68
+#: data/org.freedesktop.ModemManager1.policy.in.in:77
msgid ""
"System policy prevents querying or utilizing network information and "
"services."
@@ -93,11 +104,11 @@
"Politika systému zabraňuje požadovaniu, alebo spracovaniu sieťových "
"informácií a službám."
-#: data/org.freedesktop.ModemManager1.policy.in.in:76
+#: data/org.freedesktop.ModemManager1.policy.in.in:85
msgid "Query and manage firmware on a mobile broadband device"
msgstr "Požadovanie a správa firmvéru mobilného širokopásmového zariadenia"
-#: data/org.freedesktop.ModemManager1.policy.in.in:77
+#: data/org.freedesktop.ModemManager1.policy.in.in:86
msgid "System policy prevents querying or managing this device's firmware."
msgstr ""
"Politika systému zabraňuje požadovaniu, alebo správe firmvéru tohto "
diff --git a/po/sv.po b/po/sv.po
index bff9c79..c6f0fcf 100644
--- a/po/sv.po
+++ b/po/sv.po
@@ -7,7 +7,7 @@
msgstr ""
"Project-Id-Version: ModemManager master\n"
"Report-Msgid-Bugs-To: modemmanager-devel@lists.freedesktop.org\n"
-"POT-Creation-Date: 2017-12-05 10:49+0100\n"
+"POT-Creation-Date: 2019-09-25 12:48+0200\n"
"PO-Revision-Date: 2017-12-04 20:28+0100\n"
"Last-Translator: Josef Andersson <l10nl18nsweja@gmail.com>\n"
"Language-Team: Swedish <tp-sv@listor.tp-sv.se>\n"
@@ -68,21 +68,32 @@
msgstr "En systempolicy förhindrar röstsamtal."
#: data/org.freedesktop.ModemManager1.policy.in.in:58
+msgid "Query network time and timezone information"
+msgstr ""
+
+#: data/org.freedesktop.ModemManager1.policy.in.in:59
+#, fuzzy
+msgid "System policy prevents querying network time information."
+msgstr ""
+"En systempolicy förhindrar frågande och nyttjande av nätverksinformation och "
+"tjänster."
+
+#: data/org.freedesktop.ModemManager1.policy.in.in:67
msgid "Enable and view geographic location and positioning information"
msgstr "Aktivera och visa geografisk plats samt positioneringsinformation"
-#: data/org.freedesktop.ModemManager1.policy.in.in:59
+#: data/org.freedesktop.ModemManager1.policy.in.in:68
msgid ""
"System policy prevents enabling or viewing geographic location information."
msgstr ""
"En systempolicy förhindrar aktivering eller visning av geografisk "
"platsinformation."
-#: data/org.freedesktop.ModemManager1.policy.in.in:67
+#: data/org.freedesktop.ModemManager1.policy.in.in:76
msgid "Query and utilize network information and services"
msgstr "Fråga och nyttja nätverksinformation och tjänster"
-#: data/org.freedesktop.ModemManager1.policy.in.in:68
+#: data/org.freedesktop.ModemManager1.policy.in.in:77
msgid ""
"System policy prevents querying or utilizing network information and "
"services."
@@ -90,11 +101,11 @@
"En systempolicy förhindrar frågande och nyttjande av nätverksinformation och "
"tjänster."
-#: data/org.freedesktop.ModemManager1.policy.in.in:76
+#: data/org.freedesktop.ModemManager1.policy.in.in:85
msgid "Query and manage firmware on a mobile broadband device"
msgstr "Fråga och hantera fast programvara för en mobil bredbandsenhet"
-#: data/org.freedesktop.ModemManager1.policy.in.in:77
+#: data/org.freedesktop.ModemManager1.policy.in.in:86
msgid "System policy prevents querying or managing this device's firmware."
msgstr ""
"En systempolicy förhindrar att fråga och hantera denna enhets fasta "
diff --git a/po/tr.po b/po/tr.po
index 2f9ca15..85ce8ef 100644
--- a/po/tr.po
+++ b/po/tr.po
@@ -7,7 +7,7 @@
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: modemmanager-devel@lists.freedesktop.org\n"
-"POT-Creation-Date: 2018-08-14 11:06+0200\n"
+"POT-Creation-Date: 2019-09-25 12:48+0200\n"
"PO-Revision-Date: 2018-06-23 18:53+0300\n"
"Last-Translator: Emin Tufan Çetin <etcetin@gmail.com>\n"
"Language-Team: Türkçe <gnome-turk@gnome.org>\n"
@@ -68,21 +68,32 @@
msgstr "Sistem ilkesi sesli çağrıları engelliyor."
#: data/org.freedesktop.ModemManager1.policy.in.in:58
+msgid "Query network time and timezone information"
+msgstr ""
+
+#: data/org.freedesktop.ModemManager1.policy.in.in:59
+#, fuzzy
+msgid "System policy prevents querying network time information."
+msgstr ""
+"Sistem ilkesi ağ bilgisini ve hizmetleri sorgulamayı veya yararlanmayı "
+"engelliyor."
+
+#: data/org.freedesktop.ModemManager1.policy.in.in:67
msgid "Enable and view geographic location and positioning information"
msgstr "Coğrafi konum ve konumlandırma bilgisini etkinleştir ve gör"
-#: data/org.freedesktop.ModemManager1.policy.in.in:59
+#: data/org.freedesktop.ModemManager1.policy.in.in:68
msgid ""
"System policy prevents enabling or viewing geographic location information."
msgstr ""
"Sistem ilkesi coğrafi konum bilgisini etkinleştirmeyi ve göstermeyi "
"engelliyor."
-#: data/org.freedesktop.ModemManager1.policy.in.in:67
+#: data/org.freedesktop.ModemManager1.policy.in.in:76
msgid "Query and utilize network information and services"
msgstr "Ağ bilgisi ve hizmetleri sorgula ve yararlan"
-#: data/org.freedesktop.ModemManager1.policy.in.in:68
+#: data/org.freedesktop.ModemManager1.policy.in.in:77
msgid ""
"System policy prevents querying or utilizing network information and "
"services."
@@ -90,11 +101,11 @@
"Sistem ilkesi ağ bilgisini ve hizmetleri sorgulamayı veya yararlanmayı "
"engelliyor."
-#: data/org.freedesktop.ModemManager1.policy.in.in:76
+#: data/org.freedesktop.ModemManager1.policy.in.in:85
msgid "Query and manage firmware on a mobile broadband device"
msgstr "Mobil geniş bant aygıtındaki donanım yazılımını sorgula ve yönet"
-#: data/org.freedesktop.ModemManager1.policy.in.in:77
+#: data/org.freedesktop.ModemManager1.policy.in.in:86
msgid "System policy prevents querying or managing this device's firmware."
msgstr ""
"Sistem ilkesi bu aygıtın donanım yazılımını sorgulamayı veya yönetmeyi "
diff --git a/po/uk.po b/po/uk.po
index 7fa3e58..f1412e0 100644
--- a/po/uk.po
+++ b/po/uk.po
@@ -7,7 +7,7 @@
msgstr ""
"Project-Id-Version: Modem Manager\n"
"Report-Msgid-Bugs-To: modemmanager-devel@lists.freedesktop.org\n"
-"POT-Creation-Date: 2017-11-12 13:40+0100\n"
+"POT-Creation-Date: 2019-09-25 12:48+0200\n"
"PO-Revision-Date: 2017-11-11 18:33+0200\n"
"Last-Translator: Yuri Chornoivan <yurchor@ukr.net>\n"
"Language-Team: Ukrainian <kde-i18n-uk@kde.org>\n"
@@ -72,21 +72,32 @@
msgstr "Правила системи перешкоджають голосовим викликам."
#: data/org.freedesktop.ModemManager1.policy.in.in:58
+msgid "Query network time and timezone information"
+msgstr ""
+
+#: data/org.freedesktop.ModemManager1.policy.in.in:59
+#, fuzzy
+msgid "System policy prevents querying network time information."
+msgstr ""
+"Правила системи забороняють надсилання запитів і використання даних щодо "
+"мережі і служб."
+
+#: data/org.freedesktop.ModemManager1.policy.in.in:67
msgid "Enable and view geographic location and positioning information"
msgstr ""
"Увімкнути або переглянути дані щодо географічного розташування і позиціювання"
-#: data/org.freedesktop.ModemManager1.policy.in.in:59
+#: data/org.freedesktop.ModemManager1.policy.in.in:68
msgid ""
"System policy prevents enabling or viewing geographic location information."
msgstr ""
"Правила системи забороняють вмикання або перегляд даних щодо розташування."
-#: data/org.freedesktop.ModemManager1.policy.in.in:67
+#: data/org.freedesktop.ModemManager1.policy.in.in:76
msgid "Query and utilize network information and services"
msgstr "Надіслати запит і використати дані щодо мережі і служби"
-#: data/org.freedesktop.ModemManager1.policy.in.in:68
+#: data/org.freedesktop.ModemManager1.policy.in.in:77
msgid ""
"System policy prevents querying or utilizing network information and "
"services."
@@ -94,13 +105,13 @@
"Правила системи забороняють надсилання запитів і використання даних щодо "
"мережі і служб."
-#: data/org.freedesktop.ModemManager1.policy.in.in:76
+#: data/org.freedesktop.ModemManager1.policy.in.in:85
msgid "Query and manage firmware on a mobile broadband device"
msgstr ""
"Опитування та керування мікропрограмою на пристрої мобільної широкосмугової "
"мережі"
-#: data/org.freedesktop.ModemManager1.policy.in.in:77
+#: data/org.freedesktop.ModemManager1.policy.in.in:86
msgid "System policy prevents querying or managing this device's firmware."
msgstr ""
"Правила системи перешкоджають опитуванню або керування мікропрограмою цього "
diff --git a/po/zh_CN.po b/po/zh_CN.po
index 4a998d2..1b576a2 100644
--- a/po/zh_CN.po
+++ b/po/zh_CN.po
@@ -8,7 +8,7 @@
msgstr ""
"Project-Id-Version: ModemManager master\n"
"Report-Msgid-Bugs-To: modemmanager-devel@lists.freedesktop.org\n"
-"POT-Creation-Date: 2019-07-02 09:46+0200\n"
+"POT-Creation-Date: 2019-09-25 12:48+0200\n"
"PO-Revision-Date: 2019-05-03 00:10+0800\n"
"Last-Translator: 王滋涵 <i@wi24rd.ml>\n"
"Language-Team: Chinese (China) <i18n-zh@googlegroups.com>\n"
@@ -62,29 +62,38 @@
msgstr "系统策略禁止语音呼叫。"
#: data/org.freedesktop.ModemManager1.policy.in.in:58
+msgid "Query network time and timezone information"
+msgstr ""
+
+#: data/org.freedesktop.ModemManager1.policy.in.in:59
+#, fuzzy
+msgid "System policy prevents querying network time information."
+msgstr "系统策略禁止查询和利用网络信息和服务。"
+
+#: data/org.freedesktop.ModemManager1.policy.in.in:67
msgid "Enable and view geographic location and positioning information"
msgstr "启用和查看地理位置和定位信息"
-#: data/org.freedesktop.ModemManager1.policy.in.in:59
+#: data/org.freedesktop.ModemManager1.policy.in.in:68
msgid ""
"System policy prevents enabling or viewing geographic location information."
msgstr "系统策略禁止启用和查看地理位置和定位信息。"
-#: data/org.freedesktop.ModemManager1.policy.in.in:67
+#: data/org.freedesktop.ModemManager1.policy.in.in:76
msgid "Query and utilize network information and services"
msgstr "查询和利用网络信息和服务"
-#: data/org.freedesktop.ModemManager1.policy.in.in:68
+#: data/org.freedesktop.ModemManager1.policy.in.in:77
msgid ""
"System policy prevents querying or utilizing network information and "
"services."
msgstr "系统策略禁止查询和利用网络信息和服务。"
-#: data/org.freedesktop.ModemManager1.policy.in.in:76
+#: data/org.freedesktop.ModemManager1.policy.in.in:85
msgid "Query and manage firmware on a mobile broadband device"
msgstr "在移动宽带设备上查询和管理固件"
-#: data/org.freedesktop.ModemManager1.policy.in.in:77
+#: data/org.freedesktop.ModemManager1.policy.in.in:86
msgid "System policy prevents querying or managing this device's firmware."
msgstr "系统策略禁止在移动宽带设备上查询和管理固件。"
diff --git a/src/main.c b/src/main.c
index 96190b8..7a6b4b1 100644
--- a/src/main.c
+++ b/src/main.c
@@ -130,6 +130,28 @@
g_main_loop_quit (loop);
}
+static void
+register_dbus_errors (void)
+{
+ static volatile guint32 aux = 0;
+
+ if (aux)
+ return;
+
+ /* Register all known own errors */
+ aux |= MM_CORE_ERROR;
+ aux |= MM_MOBILE_EQUIPMENT_ERROR;
+ aux |= MM_CONNECTION_ERROR;
+ aux |= MM_SERIAL_ERROR;
+ aux |= MM_MESSAGE_ERROR;
+ aux |= MM_CDMA_ACTIVATION_ERROR;
+
+ /* We no longer use MM_CORE_ERROR_CANCELLED in the daemon, we rely on
+ * G_IO_ERROR_CANCELLED internally */
+ g_dbus_error_unregister_error (MM_CORE_ERROR, MM_CORE_ERROR_CANCELLED, MM_CORE_ERROR_DBUS_PREFIX ".Cancelled");
+ g_dbus_error_register_error (G_IO_ERROR, G_IO_ERROR_CANCELLED, MM_CORE_ERROR_DBUS_PREFIX ".Cancelled");
+}
+
int
main (int argc, char *argv[])
{
@@ -154,6 +176,9 @@
g_unix_signal_add (SIGTERM, quit_cb, NULL);
g_unix_signal_add (SIGINT, quit_cb, NULL);
+ /* Early register all known errors */
+ register_dbus_errors ();
+
mm_info ("ModemManager (version " MM_DIST_VERSION ") starting in %s bus...",
mm_context_get_test_session () ? "session" : "system");
diff --git a/src/mm-auth-provider.h b/src/mm-auth-provider.h
index e9c2cba..0f1270c 100644
--- a/src/mm-auth-provider.h
+++ b/src/mm-auth-provider.h
@@ -34,6 +34,7 @@
#define MM_AUTHORIZATION_VOICE "org.freedesktop.ModemManager1.Voice"
#define MM_AUTHORIZATION_USSD "org.freedesktop.ModemManager1.USSD"
#define MM_AUTHORIZATION_LOCATION "org.freedesktop.ModemManager1.Location"
+#define MM_AUTHORIZATION_TIME "org.freedesktop.ModemManager1.Time"
#define MM_AUTHORIZATION_FIRMWARE "org.freedesktop.ModemManager1.Firmware"
typedef struct _MMAuthProvider MMAuthProvider;
diff --git a/src/mm-base-bearer.c b/src/mm-base-bearer.c
index 9808eb4..222e123 100644
--- a/src/mm-base-bearer.c
+++ b/src/mm-base-bearer.c
@@ -724,8 +724,7 @@
mm_dbg ("Couldn't connect bearer '%s': '%s'",
self->priv->path,
error->message);
- if ( g_error_matches (error, MM_CORE_ERROR, MM_CORE_ERROR_CANCELLED)
- || g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
+ if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
/* Will launch disconnection */
launch_disconnect = TRUE;
} else
@@ -735,10 +734,8 @@
else if (g_cancellable_is_cancelled (self->priv->connect_cancellable)) {
mm_dbg ("Connected bearer '%s', but need to disconnect", self->priv->path);
mm_bearer_connect_result_unref (result);
- error = g_error_new (
- MM_CORE_ERROR,
- MM_CORE_ERROR_CANCELLED,
- "Bearer got connected, but had to disconnect after cancellation request");
+ error = g_error_new (G_IO_ERROR, G_IO_ERROR_CANCELLED,
+ "Bearer got connected, but had to disconnect after cancellation request");
launch_disconnect = TRUE;
}
else {
@@ -930,6 +927,8 @@
MM_BASE_BEARER_MODEM, &ctx->modem,
NULL);
+ mm_dbg ("User request to connect bearer '%s'", self->priv->path);
+
mm_base_modem_authorize (ctx->modem,
invocation,
MM_AUTHORIZATION_DEVICE_CONTROL,
@@ -1121,6 +1120,8 @@
MM_BASE_BEARER_MODEM, &ctx->modem,
NULL);
+ mm_dbg ("User request to disconnect bearer '%s'", self->priv->path);
+
mm_base_modem_authorize (ctx->modem,
invocation,
MM_AUTHORIZATION_DEVICE_CONTROL,
diff --git a/src/mm-base-call.c b/src/mm-base-call.c
index 0d09a09..c01ef46 100644
--- a/src/mm-base-call.c
+++ b/src/mm-base-call.c
@@ -34,6 +34,7 @@
#include "mm-base-modem.h"
#include "mm-log.h"
#include "mm-modem-helpers.h"
+#include "mm-error-helpers.h"
G_DEFINE_TYPE (MMBaseCall, mm_base_call, MM_GDBUS_TYPE_CALL_SKELETON)
@@ -69,6 +70,11 @@
/* Ongoing call index */
guint index;
+
+ /* Start cancellable, used when the call state transition to
+ * 'terminated' is coming asynchronously (e.g. via in-call state
+ * update notifications) */
+ GCancellable *start_cancellable;
};
/*****************************************************************************/
@@ -148,8 +154,19 @@
{
GError *error = NULL;
+ g_clear_object (&ctx->self->priv->start_cancellable);
+
if (!MM_BASE_CALL_GET_CLASS (self)->start_finish (self, res, &error)) {
mm_warn ("Couldn't start call : '%s'", error->message);
+
+ /* When cancelled via the start cancellable, it's because we got an early in-call error
+ * before the call attempt was reported as started. */
+ if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED) ||
+ g_error_matches (error, MM_CORE_ERROR, MM_CORE_ERROR_CANCELLED)) {
+ g_clear_error (&error);
+ error = mm_connection_error_for_code (MM_CONNECTION_ERROR_NO_DIALTONE);
+ }
+
/* Convert errors into call state updates */
if (g_error_matches (error, MM_CONNECTION_ERROR, MM_CONNECTION_ERROR_NO_DIALTONE))
mm_base_call_change_state (self, MM_CALL_STATE_TERMINATED, MM_CALL_STATE_REASON_ERROR);
@@ -159,6 +176,7 @@
mm_base_call_change_state (self, MM_CALL_STATE_TERMINATED, MM_CALL_STATE_REASON_REFUSED_OR_BUSY);
else
mm_base_call_change_state (self, MM_CALL_STATE_TERMINATED, MM_CALL_STATE_REASON_UNKNOWN);
+
g_dbus_method_invocation_take_error (ctx->invocation, error);
handle_start_context_free (ctx);
return;
@@ -188,6 +206,7 @@
GError *error = NULL;
if (!mm_base_modem_authorize_finish (modem, res, &error)) {
+ mm_base_call_change_state (ctx->self, MM_CALL_STATE_TERMINATED, MM_CALL_STATE_REASON_UNKNOWN);
g_dbus_method_invocation_take_error (ctx->invocation, error);
handle_start_context_free (ctx);
return;
@@ -207,9 +226,18 @@
mm_info ("user request to start call");
+ /* Disallow non-emergency calls when in emergency-only state */
+ if (!mm_iface_modem_voice_authorize_outgoing_call (MM_IFACE_MODEM_VOICE (modem), ctx->self, &error)) {
+ mm_base_call_change_state (ctx->self, MM_CALL_STATE_TERMINATED, MM_CALL_STATE_REASON_UNKNOWN);
+ g_dbus_method_invocation_take_error (ctx->invocation, error);
+ handle_start_context_free (ctx);
+ return;
+ }
+
/* Check if we do support doing it */
if (!MM_BASE_CALL_GET_CLASS (ctx->self)->start ||
!MM_BASE_CALL_GET_CLASS (ctx->self)->start_finish) {
+ mm_base_call_change_state (ctx->self, MM_CALL_STATE_TERMINATED, MM_CALL_STATE_REASON_UNKNOWN);
g_dbus_method_invocation_return_error (ctx->invocation,
MM_CORE_ERROR,
MM_CORE_ERROR_UNSUPPORTED,
@@ -220,7 +248,12 @@
mm_base_call_change_state (ctx->self, MM_CALL_STATE_DIALING, MM_CALL_STATE_REASON_OUTGOING_STARTED);
+ /* Setup start cancellable to get notified of termination asynchronously */
+ g_assert (!ctx->self->priv->start_cancellable);
+ ctx->self->priv->start_cancellable = g_cancellable_new ();
+
MM_BASE_CALL_GET_CLASS (ctx->self)->start (ctx->self,
+ ctx->self->priv->start_cancellable,
(GAsyncReadyCallback)handle_start_ready,
ctx);
}
@@ -970,6 +1003,8 @@
g_source_remove (self->priv->incoming_timeout);
self->priv->incoming_timeout = 0;
}
+ /* cancel start if ongoing */
+ g_cancellable_cancel (self->priv->start_cancellable);
}
mm_gdbus_call_set_state (MM_GDBUS_CALL (self), new_state);
@@ -1021,6 +1056,7 @@
static void
call_start (MMBaseCall *self,
+ GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
@@ -1030,12 +1066,15 @@
task = g_task_new (self, NULL, callback, user_data);
cmd = g_strdup_printf ("ATD%s;", mm_gdbus_call_get_number (MM_GDBUS_CALL (self)));
- mm_base_modem_at_command (self->priv->modem,
- cmd,
- 90,
- FALSE,
- (GAsyncReadyCallback)call_start_ready,
- task);
+ mm_base_modem_at_command_full (self->priv->modem,
+ mm_base_modem_peek_port_primary (self->priv->modem),
+ cmd,
+ 90,
+ FALSE, /* no cached */
+ FALSE, /* no raw */
+ cancellable,
+ (GAsyncReadyCallback)call_start_ready,
+ task);
g_free (cmd);
}
@@ -1400,6 +1439,7 @@
{
MMBaseCall *self = MM_BASE_CALL (object);
+ g_assert (!self->priv->start_cancellable);
g_free (self->priv->path);
G_OBJECT_CLASS (mm_base_call_parent_class)->finalize (object);
diff --git a/src/mm-base-call.h b/src/mm-base-call.h
index 973bcaf..8d6944f 100644
--- a/src/mm-base-call.h
+++ b/src/mm-base-call.h
@@ -54,6 +54,7 @@
/* Start the call */
void (* start) (MMBaseCall *self,
+ GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
gboolean (* start_finish) (MMBaseCall *self,
diff --git a/src/mm-base-modem-at.c b/src/mm-base-modem-at.c
index b4e0660..e1537af 100644
--- a/src/mm-base-modem-at.c
+++ b/src/mm-base-modem-at.c
@@ -168,9 +168,7 @@
/* Cancelled? */
if (g_cancellable_is_cancelled (ctx->cancellable)) {
- g_simple_async_result_set_error (ctx->simple,
- MM_CORE_ERROR,
- MM_CORE_ERROR_CANCELLED,
+ g_simple_async_result_set_error (ctx->simple, G_IO_ERROR, G_IO_ERROR_CANCELLED,
"AT sequence was cancelled");
if (error)
g_error_free (error);
@@ -483,9 +481,7 @@
/* Cancelled? */
if (g_cancellable_is_cancelled (ctx->cancellable)) {
- g_simple_async_result_set_error (ctx->result,
- MM_CORE_ERROR,
- MM_CORE_ERROR_CANCELLED,
+ g_simple_async_result_set_error (ctx->result, G_IO_ERROR, G_IO_ERROR_CANCELLED,
"AT command was cancelled");
if (error)
g_error_free (error);
diff --git a/src/mm-base-modem.c b/src/mm-base-modem.c
index 3b9dc7d..2b96f1a 100644
--- a/src/mm-base-modem.c
+++ b/src/mm-base-modem.c
@@ -95,6 +95,9 @@
MMPortSerialAt *gps_control;
MMPortSerialGps *gps;
+ /* Some audio-capable devices will have a port for audio specifically */
+ MMPortSerial *audio;
+
/* Support for parallel enable/disable operations */
GList *enable_tasks;
GList *disable_tasks;
@@ -232,6 +235,9 @@
} else if (ptype == MM_PORT_TYPE_GPS) {
/* Raw GPS port */
port = MM_PORT (mm_port_serial_gps_new (name));
+ } else if (ptype == MM_PORT_TYPE_AUDIO) {
+ /* Generic audio port */
+ port = MM_PORT (mm_port_serial_new (name, ptype));
} else {
g_set_error (error,
MM_CORE_ERROR,
@@ -646,6 +652,22 @@
return self->priv->gps;
}
+MMPortSerial *
+mm_base_modem_get_port_audio (MMBaseModem *self)
+{
+ g_return_val_if_fail (MM_IS_BASE_MODEM (self), NULL);
+
+ return (self->priv->audio ? g_object_ref (self->priv->audio) : NULL);
+}
+
+MMPortSerial *
+mm_base_modem_peek_port_audio (MMBaseModem *self)
+{
+ g_return_val_if_fail (MM_IS_BASE_MODEM (self), NULL);
+
+ return self->priv->audio;
+}
+
#if defined WITH_QMI
MMPortQmi *
@@ -929,6 +951,9 @@
case MM_PORT_TYPE_GPS:
port_infos[i].type = MM_MODEM_PORT_TYPE_GPS;
break;
+ case MM_PORT_TYPE_AUDIO:
+ port_infos[i].type = MM_MODEM_PORT_TYPE_AUDIO;
+ break;
case MM_PORT_TYPE_QMI:
port_infos[i].type = MM_MODEM_PORT_TYPE_QMI;
break;
@@ -1039,6 +1064,7 @@
MMPortSerialQcdm *qcdm = NULL;
MMPortSerialAt *gps_control = NULL;
MMPortSerialGps *gps = NULL;
+ MMPortSerial *audio = NULL;
MMPort *data_primary = NULL;
GList *data = NULL;
#if defined WITH_QMI
@@ -1129,6 +1155,12 @@
gps = MM_PORT_SERIAL_GPS (candidate);
break;
+ case MM_PORT_TYPE_AUDIO:
+ g_assert (MM_IS_PORT_SERIAL (candidate));
+ if (!audio)
+ audio = MM_PORT_SERIAL (candidate);
+ break;
+
#if defined WITH_QMI
case MM_PORT_TYPE_QMI:
if (!qmi_primary)
@@ -1246,6 +1278,7 @@
log_port (self, MM_PORT (qcdm), "qcdm");
log_port (self, MM_PORT (gps_control), "gps (control)");
log_port (self, MM_PORT (gps), "gps (nmea)");
+ log_port (self, MM_PORT (audio), "audio");
#if defined WITH_QMI
log_port (self, MM_PORT (qmi_primary), "qmi (primary)");
for (l = qmi; l; l = g_list_next (l))
@@ -1576,6 +1609,7 @@
g_clear_object (&self->priv->qcdm);
g_clear_object (&self->priv->gps_control);
g_clear_object (&self->priv->gps);
+ g_clear_object (&self->priv->audio);
#if defined WITH_QMI
/* We need to close the QMI port cleanly when disposing the modem object,
* otherwise the allocated CIDs will be kept allocated, and if we end up
diff --git a/src/mm-base-modem.h b/src/mm-base-modem.h
index db3d54d..45a9ecc 100644
--- a/src/mm-base-modem.h
+++ b/src/mm-base-modem.h
@@ -121,6 +121,7 @@
MMPortSerialQcdm *mm_base_modem_peek_port_qcdm (MMBaseModem *self);
MMPortSerialAt *mm_base_modem_peek_port_gps_control (MMBaseModem *self);
MMPortSerialGps *mm_base_modem_peek_port_gps (MMBaseModem *self);
+MMPortSerial *mm_base_modem_peek_port_audio (MMBaseModem *self);
#if defined WITH_QMI
MMPortQmi *mm_base_modem_peek_port_qmi (MMBaseModem *self);
MMPortQmi *mm_base_modem_peek_port_qmi_for_data (MMBaseModem *self, MMPort *data, GError **error);
@@ -138,6 +139,7 @@
MMPortSerialQcdm *mm_base_modem_get_port_qcdm (MMBaseModem *self);
MMPortSerialAt *mm_base_modem_get_port_gps_control (MMBaseModem *self);
MMPortSerialGps *mm_base_modem_get_port_gps (MMBaseModem *self);
+MMPortSerial *mm_base_modem_get_port_audio (MMBaseModem *self);
#if defined WITH_QMI
MMPortQmi *mm_base_modem_get_port_qmi (MMBaseModem *self);
MMPortQmi *mm_base_modem_get_port_qmi_for_data (MMBaseModem *self, MMPort *data, GError **error);
diff --git a/src/mm-base-sim.c b/src/mm-base-sim.c
index 1cb2459..73ed088 100644
--- a/src/mm-base-sim.c
+++ b/src/mm-base-sim.c
@@ -953,6 +953,28 @@
/*****************************************************************************/
+gboolean
+mm_base_sim_is_emergency_number (MMBaseSim *self,
+ const gchar *number)
+{
+ const gchar *const *emergency_numbers;
+ guint i;
+
+ emergency_numbers = mm_gdbus_sim_get_emergency_numbers (MM_GDBUS_SIM (self));
+
+ if (!emergency_numbers)
+ return FALSE;
+
+ for (i = 0; emergency_numbers[i]; i++) {
+ if (g_strcmp0 (number, emergency_numbers[i]) == 0)
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/*****************************************************************************/
+
#undef STR_REPLY_READY_FN
#define STR_REPLY_READY_FN(NAME) \
static void \
@@ -973,7 +995,84 @@
}
/*****************************************************************************/
-/* SIM IDENTIFIER */
+/* Emergency numbers */
+
+static GStrv
+parse_emergency_numbers (const gchar *response,
+ GError **error)
+{
+ guint sw1 = 0;
+ guint sw2 = 0;
+ gchar *hex = 0;
+ GStrv ret;
+
+ if (!mm_3gpp_parse_crsm_response (response, &sw1, &sw2, &hex, error))
+ return NULL;
+
+ if ((sw1 == 0x90 && sw2 == 0x00) ||
+ (sw1 == 0x91) ||
+ (sw1 == 0x92) ||
+ (sw1 == 0x9f)) {
+ ret = mm_3gpp_parse_emergency_numbers (hex, error);
+ g_free (hex);
+ return ret;
+ }
+
+ g_free (hex);
+ g_set_error (error,
+ MM_CORE_ERROR,
+ MM_CORE_ERROR_FAILED,
+ "SIM failed to handle CRSM request (sw1 %d sw2 %d)",
+ sw1, sw2);
+ return NULL;
+}
+
+static GStrv
+load_emergency_numbers_finish (MMBaseSim *self,
+ GAsyncResult *res,
+ GError **error)
+{
+ gchar *result;
+ GStrv emergency_numbers;
+ guint i;
+
+ result = g_task_propagate_pointer (G_TASK (res), error);
+ if (!result)
+ return NULL;
+
+ emergency_numbers = parse_emergency_numbers (result, error);
+ g_free (result);
+
+ if (!emergency_numbers)
+ return NULL;
+
+ for (i = 0; emergency_numbers[i]; i++)
+ mm_dbg ("loaded emergency number: %s", emergency_numbers[i]);
+
+ return emergency_numbers;
+}
+
+STR_REPLY_READY_FN (load_emergency_numbers)
+
+static void
+load_emergency_numbers (MMBaseSim *self,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ mm_dbg ("loading emergency numbers...");
+
+ /* READ BINARY of EF_ECC (Emergency Call Codes) ETSI TS 51.011 section 10.3.27 */
+ mm_base_modem_at_command (
+ self->priv->modem,
+ "+CRSM=176,28599,0,0,15",
+ 20,
+ FALSE,
+ (GAsyncReadyCallback)load_emergency_numbers_command_ready,
+ g_task_new (self, NULL, callback, user_data));
+}
+
+/*****************************************************************************/
+/* ICCID */
static gchar *
parse_iccid (const gchar *response,
@@ -1341,6 +1440,7 @@
INITIALIZATION_STEP_IMSI,
INITIALIZATION_STEP_OPERATOR_ID,
INITIALIZATION_STEP_OPERATOR_NAME,
+ INITIALIZATION_STEP_EMERGENCY_NUMBERS,
INITIALIZATION_STEP_LAST
} InitializationStep;
@@ -1414,6 +1514,32 @@
interface_initialization_step (task);
}
+static void
+init_load_emergency_numbers_ready (MMBaseSim *self,
+ GAsyncResult *res,
+ GTask *task)
+{
+ InitAsyncContext *ctx;
+ GError *error = NULL;
+ GStrv str_list;
+
+ str_list = MM_BASE_SIM_GET_CLASS (self)->load_emergency_numbers_finish (self, res, &error);
+ if (error) {
+ mm_warn ("couldn't load list of Emergency Numbers: '%s'", error->message);
+ g_error_free (error);
+ }
+
+ if (str_list) {
+ mm_gdbus_sim_set_emergency_numbers (MM_GDBUS_SIM (self), (const gchar *const *) str_list);
+ g_strfreev (str_list);
+ }
+
+ /* Go on to next step */
+ ctx = g_task_get_task_data (task);
+ ctx->step++;
+ interface_initialization_step (task);
+}
+
#undef STR_REPLY_READY_FN
#define STR_REPLY_READY_FN(NAME,DISPLAY) \
static void \
@@ -1527,6 +1653,22 @@
/* Fall down to next step */
ctx->step++;
+ case INITIALIZATION_STEP_EMERGENCY_NUMBERS:
+ /* Emergency Numbers are meant to be loaded only once during the whole
+ * lifetime of the modem. Therefore, if we already have them loaded,
+ * don't try to load them again. */
+ if (mm_gdbus_sim_get_emergency_numbers (MM_GDBUS_SIM (self)) == NULL &&
+ MM_BASE_SIM_GET_CLASS (self)->load_emergency_numbers &&
+ MM_BASE_SIM_GET_CLASS (self)->load_emergency_numbers_finish) {
+ MM_BASE_SIM_GET_CLASS (self)->load_emergency_numbers (
+ self,
+ (GAsyncReadyCallback)init_load_emergency_numbers_ready,
+ task);
+ return;
+ }
+ /* Fall down to next step */
+ ctx->step++;
+
case INITIALIZATION_STEP_LAST:
/* We are done without errors! */
g_task_return_boolean (task, TRUE);
@@ -1741,6 +1883,8 @@
klass->load_operator_identifier_finish = load_operator_identifier_finish;
klass->load_operator_name = load_operator_name;
klass->load_operator_name_finish = load_operator_name_finish;
+ klass->load_emergency_numbers = load_emergency_numbers;
+ klass->load_emergency_numbers_finish = load_emergency_numbers_finish;
klass->send_pin = send_pin;
klass->send_pin_finish = common_send_pin_puk_finish;
klass->send_puk = send_puk;
diff --git a/src/mm-base-sim.h b/src/mm-base-sim.h
index 5e141f3..afafa37 100644
--- a/src/mm-base-sim.h
+++ b/src/mm-base-sim.h
@@ -83,6 +83,14 @@
GAsyncResult *res,
GError **error);
+ /* Load emergency numbers (async) */
+ void (* load_emergency_numbers) (MMBaseSim *self,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+ GStrv (* load_emergency_numbers_finish) (MMBaseSim *self,
+ GAsyncResult *res,
+ GError **error);
+
/* Change PIN (async) */
void (* change_pin) (MMBaseSim *self,
const gchar *old_pin,
@@ -172,4 +180,7 @@
GAsyncResult *res,
GError **error);
+gboolean mm_base_sim_is_emergency_number (MMBaseSim *self,
+ const gchar *number);
+
#endif /* MM_BASE_SIM_H */
diff --git a/src/mm-broadband-modem-mbim.c b/src/mm-broadband-modem-mbim.c
index 10d831a..7e5f665 100644
--- a/src/mm-broadband-modem-mbim.c
+++ b/src/mm-broadband-modem-mbim.c
@@ -3309,7 +3309,7 @@
self->priv->setup_flags & PROCESS_NOTIFICATION_FLAG_PACKET_SERVICE ? "yes" : "no",
self->priv->setup_flags & PROCESS_NOTIFICATION_FLAG_PCO ? "yes" : "no",
self->priv->setup_flags & PROCESS_NOTIFICATION_FLAG_USSD ? "yes" : "no",
- self->priv->setup_flags & MBIM_CID_MS_BASIC_CONNECT_EXTENSIONS_LTE_ATTACH_STATUS ? "yes" : "no");
+ self->priv->setup_flags & PROCESS_NOTIFICATION_FLAG_LTE_ATTACH_STATUS ? "yes" : "no");
if (setup) {
/* Don't re-enable it if already there */
@@ -4521,23 +4521,23 @@
break;
case MBIM_USSD_RESPONSE_TERMINATED_BY_NETWORK:
- error = g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_CANCELLED, "USSD terminated by network");
+ error = g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_ABORTED, "USSD terminated by network");
break;
case MBIM_USSD_RESPONSE_OTHER_LOCAL_CLIENT:
- error = g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_CANCELLED, "Another ongoing USSD operation is in progress");
+ error = g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_RETRY, "Another ongoing USSD operation is in progress");
break;
case MBIM_USSD_RESPONSE_OPERATION_NOT_SUPPORTED:
- error = g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_CANCELLED, "Operation not supported");
+ error = g_error_new (MM_MOBILE_EQUIPMENT_ERROR, MM_MOBILE_EQUIPMENT_ERROR_NOT_SUPPORTED, "Operation not supported");
break;
case MBIM_USSD_RESPONSE_NETWORK_TIMEOUT:
- error = g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_CANCELLED, "Network timeout");
+ error = g_error_new (MM_MOBILE_EQUIPMENT_ERROR, MM_MOBILE_EQUIPMENT_ERROR_NETWORK_TIMEOUT, "Network timeout");
break;
default:
- error = g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_CANCELLED, "Unknown USSD response (%u)", ussd_response);
+ error = g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Unknown USSD response (%u)", ussd_response);
break;
}
@@ -4851,7 +4851,7 @@
task = self->priv->pending_ussd_action;
self->priv->pending_ussd_action = NULL;
- g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_CANCELLED,
+ g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_ABORTED,
"USSD session was cancelled");
g_object_unref (task);
}
diff --git a/src/mm-broadband-modem-qmi.c b/src/mm-broadband-modem-qmi.c
index 6329c21..30f3da8 100644
--- a/src/mm-broadband-modem-qmi.c
+++ b/src/mm-broadband-modem-qmi.c
@@ -7053,14 +7053,18 @@
}
typedef struct {
- QmiClientDms *client;
- GList *pairs;
- GList *l;
+ QmiClientDms *client;
+ GList *pairs;
+ FirmwarePair *current_pair;
+ MMFirmwareProperties *current_firmware;
+ gboolean skip_image_info;
} FirmwareListPreloadContext;
static void
firmware_list_preload_context_free (FirmwareListPreloadContext *ctx)
{
+ g_clear_object (&ctx->current_firmware);
+ g_clear_pointer (&ctx->current_pair, (GDestroyNotify)firmware_pair_free);
g_list_free_full (ctx->pairs, (GDestroyNotify)firmware_pair_free);
g_object_unref (ctx->client);
g_slice_free (FirmwareListPreloadContext, ctx);
@@ -7074,150 +7078,201 @@
return g_task_propagate_boolean (G_TASK (res), error);
}
+static void
+store_preloaded_firmware_image_info (MMBroadbandModemQmi *self,
+ MMFirmwareProperties *firmware,
+ gboolean running)
+{
+ self->priv->firmware_list = g_list_append (self->priv->firmware_list, g_object_ref (firmware));
+
+ /* If this is is also the running image, keep an extra reference to it */
+ if (running) {
+ if (self->priv->current_firmware)
+ mm_warn ("A running firmware is already set (%s), not setting '%s'",
+ mm_firmware_properties_get_unique_id (self->priv->current_firmware),
+ mm_firmware_properties_get_unique_id (firmware));
+ else
+ self->priv->current_firmware = g_object_ref (firmware);
+ }
+}
+
static void get_next_image_info (GTask *task);
static void
get_pri_image_info_ready (QmiClientDms *client,
GAsyncResult *res,
- GTask *task)
+ GTask *task)
{
- MMBroadbandModemQmi *self;
- FirmwareListPreloadContext *ctx;
+ MMBroadbandModemQmi *self;
+ FirmwareListPreloadContext *ctx;
QmiMessageDmsGetStoredImageInfoOutput *output;
- GError *error = NULL;
- FirmwarePair *current;
+ GError *error = NULL;
self = g_task_get_source_object (task);
- ctx = g_task_get_task_data (task);
- current = (FirmwarePair *)ctx->l->data;
+ ctx = g_task_get_task_data (task);
+
+ g_assert (ctx->current_pair);
+ g_assert (ctx->current_firmware);
output = qmi_client_dms_get_stored_image_info_finish (client, res, &error);
- if (!output ||
- !qmi_message_dms_get_stored_image_info_output_get_result (output, &error)) {
- mm_warn ("Couldn't get detailed info for PRI image with build ID '%s': %s",
- current->build_id,
- error->message);
+ if (!output || !qmi_message_dms_get_stored_image_info_output_get_result (output, &error)) {
+ if (g_error_matches (error, QMI_PROTOCOL_ERROR, QMI_PROTOCOL_ERROR_INVALID_QMI_COMMAND))
+ ctx->skip_image_info = TRUE;
+ else
+ mm_dbg ("couldn't get detailed info for PRI image with build ID '%s': %s",
+ ctx->current_pair->build_id, error->message);
g_error_free (error);
- } else {
- gchar *unique_id_str;
- MMFirmwareProperties *firmware;
+ goto out;
+ }
- firmware = mm_firmware_properties_new (MM_FIRMWARE_IMAGE_TYPE_GOBI,
- current->build_id);
+ /* Boot version (optional) */
+ {
+ guint16 boot_major_version;
+ guint16 boot_minor_version;
- unique_id_str = mm_utils_bin2hexstr ((const guint8 *)current->pri_unique_id->data,
- current->pri_unique_id->len);
- mm_firmware_properties_set_gobi_pri_unique_id (firmware, unique_id_str);
- g_free (unique_id_str);
+ if (qmi_message_dms_get_stored_image_info_output_get_boot_version (
+ output,
+ &boot_major_version,
+ &boot_minor_version,
+ NULL)) {
+ gchar *aux;
- unique_id_str = mm_utils_bin2hexstr ((const guint8 *)current->modem_unique_id->data,
- current->modem_unique_id->len);
- mm_firmware_properties_set_gobi_modem_unique_id (firmware, unique_id_str);
- g_free (unique_id_str);
-
- /* Boot version (optional) */
- {
- guint16 boot_major_version;
- guint16 boot_minor_version;
-
- if (qmi_message_dms_get_stored_image_info_output_get_boot_version (
- output,
- &boot_major_version,
- &boot_minor_version,
- NULL)) {
- gchar *aux;
-
- aux = g_strdup_printf ("%u.%u", boot_major_version, boot_minor_version);
- mm_firmware_properties_set_gobi_boot_version (firmware, aux);
- g_free (aux);
- }
- }
-
- /* PRI version (optional) */
- {
- guint32 pri_version;
- const gchar *pri_info;
-
- if (qmi_message_dms_get_stored_image_info_output_get_pri_version (
- output,
- &pri_version,
- &pri_info,
- NULL)) {
- gchar *aux;
-
- aux = g_strdup_printf ("%u", pri_version);
- mm_firmware_properties_set_gobi_pri_version (firmware, aux);
- g_free (aux);
-
- mm_firmware_properties_set_gobi_pri_info (firmware, pri_info);
- }
- }
-
- /* Add firmware image to our internal list */
- self->priv->firmware_list = g_list_append (self->priv->firmware_list,
- firmware);
-
- /* If this is is also the current image running, keep it */
- if (current->current) {
- if (self->priv->current_firmware)
- mm_warn ("A current firmware is already set (%s), not setting '%s' as current",
- mm_firmware_properties_get_unique_id (self->priv->current_firmware),
- current->build_id);
- else
- self->priv->current_firmware = g_object_ref (firmware);
-
+ aux = g_strdup_printf ("%u.%u", boot_major_version, boot_minor_version);
+ mm_firmware_properties_set_gobi_boot_version (ctx->current_firmware, aux);
+ g_free (aux);
}
}
- if (output)
- qmi_message_dms_get_stored_image_info_output_unref (output);
+ /* PRI version (optional) */
+ {
+ guint32 pri_version;
+ const gchar *pri_info;
+
+ if (qmi_message_dms_get_stored_image_info_output_get_pri_version (
+ output,
+ &pri_version,
+ &pri_info,
+ NULL)) {
+ gchar *aux;
+
+ aux = g_strdup_printf ("%u", pri_version);
+ mm_firmware_properties_set_gobi_pri_version (ctx->current_firmware, aux);
+ g_free (aux);
+
+ mm_firmware_properties_set_gobi_pri_info (ctx->current_firmware, pri_info);
+ }
+ }
+
+out:
+
+ /* We're done with this image */
+ store_preloaded_firmware_image_info (self, ctx->current_firmware, ctx->current_pair->current);
+ g_clear_object (&ctx->current_firmware);
+ g_clear_pointer (&ctx->current_pair, (GDestroyNotify)firmware_pair_free);
/* Go on to the next one */
- ctx->l = g_list_next (ctx->l);
get_next_image_info (task);
+
+ if (output)
+ qmi_message_dms_get_stored_image_info_output_unref (output);
+}
+
+static MMFirmwareProperties *
+create_firmware_properties_from_pair (FirmwarePair *pair,
+ GError **error)
+{
+ gchar *pri_unique_id_str = NULL;
+ gchar *modem_unique_id_str = NULL;
+ gchar *firmware_unique_id_str = NULL;
+ MMFirmwareProperties *firmware = NULL;
+
+ /* If the string is ASCII, use it without converting to HEX */
+
+ pri_unique_id_str = mm_qmi_unique_id_to_firmware_unique_id (pair->pri_unique_id, error);
+ if (!pri_unique_id_str)
+ goto out;
+
+ modem_unique_id_str = mm_qmi_unique_id_to_firmware_unique_id (pair->modem_unique_id, error);
+ if (!modem_unique_id_str)
+ goto out;
+
+ /* We will always append the PRI unique ID to the build id to form the unique id
+ * used by the API, because it may happen that a device holds multiple PRI images
+ * for the same build ID.
+ *
+ * E.g. we could have a single modem image (e.g. 02.14.03.00) and then two or more
+ * different PRI images with the same build ID (e.g. 02.14.03.00_VODAFONE) but
+ * different unique IDs (e.g. 000.008_000 and 000.016_000).
+ */
+ firmware_unique_id_str = g_strdup_printf ("%s_%s", pair->build_id, pri_unique_id_str);
+
+ firmware = mm_firmware_properties_new (MM_FIRMWARE_IMAGE_TYPE_GOBI, firmware_unique_id_str);
+ mm_firmware_properties_set_gobi_pri_unique_id (firmware, pri_unique_id_str);
+ mm_firmware_properties_set_gobi_modem_unique_id (firmware, modem_unique_id_str);
+
+out:
+ g_free (firmware_unique_id_str);
+ g_free (pri_unique_id_str);
+ g_free (modem_unique_id_str);
+
+ return firmware;
}
static void
get_next_image_info (GTask *task)
{
- MMBroadbandModemQmi *self;
+ MMBroadbandModemQmi *self;
FirmwareListPreloadContext *ctx;
- QmiMessageDmsGetStoredImageInfoInputImage image_id;
- QmiMessageDmsGetStoredImageInfoInput *input;
- FirmwarePair *current;
+ GError *error = NULL;
self = g_task_get_source_object (task);
ctx = g_task_get_task_data (task);
- if (!ctx->l) {
- /* We're done */
-
- if (!self->priv->firmware_list) {
- mm_warn ("No valid firmware images listed. "
- "Assuming firmware unsupported.");
- g_task_return_boolean (task, FALSE);
- } else
- g_task_return_boolean (task, TRUE);
-
+ if (!ctx->pairs) {
+ g_task_return_boolean (task, TRUE);
g_object_unref (task);
return;
}
- current = (FirmwarePair *)ctx->l->data;
+ /* Take next pair to process from list head */
+ ctx->current_pair = (FirmwarePair *)ctx->pairs->data;
+ ctx->pairs = g_list_delete_link (ctx->pairs, ctx->pairs);
- /* Query PRI image info */
- image_id.type = QMI_DMS_FIRMWARE_IMAGE_TYPE_PRI;
- image_id.unique_id = current->pri_unique_id;
- image_id.build_id = current->build_id;
- input = qmi_message_dms_get_stored_image_info_input_new ();
- qmi_message_dms_get_stored_image_info_input_set_image (input, &image_id, NULL);
- qmi_client_dms_get_stored_image_info (ctx->client,
- input,
- 10,
- NULL,
- (GAsyncReadyCallback)get_pri_image_info_ready,
- task);
- qmi_message_dms_get_stored_image_info_input_unref (input);
+ /* Build firmware properties */
+ ctx->current_firmware = create_firmware_properties_from_pair (ctx->current_pair, &error);
+ if (!ctx->current_firmware) {
+ g_task_return_error (task, error);
+ g_object_unref (task);
+ return;
+ }
+
+ /* Now, load additional optional information for the PRI image */
+ if (!ctx->skip_image_info) {
+ QmiMessageDmsGetStoredImageInfoInputImage image_id;
+ QmiMessageDmsGetStoredImageInfoInput *input;
+
+ image_id.type = QMI_DMS_FIRMWARE_IMAGE_TYPE_PRI;
+ image_id.unique_id = ctx->current_pair->pri_unique_id;
+ image_id.build_id = ctx->current_pair->build_id;
+ input = qmi_message_dms_get_stored_image_info_input_new ();
+ qmi_message_dms_get_stored_image_info_input_set_image (input, &image_id, NULL);
+ qmi_client_dms_get_stored_image_info (ctx->client,
+ input,
+ 10,
+ NULL,
+ (GAsyncReadyCallback)get_pri_image_info_ready,
+ task);
+ qmi_message_dms_get_stored_image_info_input_unref (input);
+ return;
+ }
+
+ /* If we shouldn't be loading additional image info, we're done with this image */
+ store_preloaded_firmware_image_info (self, ctx->current_firmware, ctx->current_pair->current);
+ g_clear_object (&ctx->current_firmware);
+ g_clear_pointer (&ctx->current_pair, (GDestroyNotify)firmware_pair_free);
+
+ /* Go on to the next one */
+ get_next_image_info (task);
}
static gboolean
@@ -7242,85 +7297,15 @@
return strncmp (pri_id, modem_id, modem_id_len - 1) == 0;
}
-static void
-list_stored_images_ready (QmiClientDms *client,
- GAsyncResult *res,
- GTask *task)
+static GList *
+find_image_pairs (QmiMessageDmsListStoredImagesOutputListImage *image_pri,
+ QmiMessageDmsListStoredImagesOutputListImage *image_modem,
+ GError **error)
{
- FirmwareListPreloadContext *ctx;
- GArray *array;
- gint pri_id;
- gint modem_id;
- guint i;
- guint j;
- QmiMessageDmsListStoredImagesOutputListImage *image_pri;
- QmiMessageDmsListStoredImagesOutputListImage *image_modem;
- QmiMessageDmsListStoredImagesOutput *output;
+ guint i, j;
+ GList *pairs = NULL;
- output = qmi_client_dms_list_stored_images_finish (client, res, NULL);
- if (!output ||
- !qmi_message_dms_list_stored_images_output_get_result (output, NULL)) {
- /* Assume firmware unsupported */
- g_task_return_boolean (task, FALSE);
- g_object_unref (task);
- if (output)
- qmi_message_dms_list_stored_images_output_unref (output);
- return;
- }
-
- qmi_message_dms_list_stored_images_output_get_list (
- output,
- &array,
- NULL);
-
- /* Find which index corresponds to each image type */
- pri_id = -1;
- modem_id = -1;
- for (i = 0; i < array->len; i++) {
- QmiMessageDmsListStoredImagesOutputListImage *image;
-
- image = &g_array_index (array,
- QmiMessageDmsListStoredImagesOutputListImage,
- i);
-
- switch (image->type) {
- case QMI_DMS_FIRMWARE_IMAGE_TYPE_PRI:
- if (pri_id != -1)
- mm_warn ("Multiple array elements found with PRI type");
- else
- pri_id = (gint)i;
- break;
- case QMI_DMS_FIRMWARE_IMAGE_TYPE_MODEM:
- if (modem_id != -1)
- mm_warn ("Multiple array elements found with MODEM type");
- else
- modem_id = (gint)i;
- break;
- default:
- break;
- }
- }
-
- if (pri_id < 0 || modem_id < 0) {
- mm_dbg ("We need both PRI (%s) and MODEM (%s) images",
- pri_id < 0 ? "not found" : "found",
- modem_id < 0 ? "not found" : "found");
- g_task_return_boolean (task, FALSE);
- g_object_unref (task);
- qmi_message_dms_list_stored_images_output_unref (output);
- return;
- }
-
- ctx = g_task_get_task_data (task);
-
- /* Loop PRI images and try to find a pairing MODEM image with same boot ID */
- image_pri = &g_array_index (array,
- QmiMessageDmsListStoredImagesOutputListImage,
- pri_id);
- image_modem = &g_array_index (array,
- QmiMessageDmsListStoredImagesOutputListImage,
- modem_id);
-
+ /* Loop PRI images and try to find a pairing MODEM image with same build ID */
for (i = 0; i < image_pri->sublist->len; i++) {
QmiMessageDmsListStoredImagesOutputListImageSublistSublistElement *subimage_pri;
@@ -7342,8 +7327,15 @@
pair->build_id = g_strdup (subimage_pri->build_id);
pair->modem_unique_id = g_array_ref (subimage_modem->unique_id);
pair->pri_unique_id = g_array_ref (subimage_pri->unique_id);
+
+ /* We're using the PRI 'index_of_running_image' only as source to select
+ * which is the current running firmware. This avoids issues with the wrong
+ * 'index_of_running_image' reported for the MODEM images, see:
+ * https://forum.sierrawireless.com/t/mc74xx-wrong-running-image-in-qmi-get-stored-images/8998
+ */
pair->current = (image_pri->index_of_running_image == i ? TRUE : FALSE);
- ctx->pairs = g_list_append (ctx->pairs, pair);
+
+ pairs = g_list_append (pairs, pair);
break;
}
}
@@ -7352,19 +7344,110 @@
mm_dbg ("Pairing for PRI image with build ID '%s' not found", subimage_pri->build_id);
}
- if (!ctx->pairs) {
- mm_dbg ("No valid PRI+MODEM pairs found");
- g_task_return_boolean (task, FALSE);
- g_object_unref (task);
- qmi_message_dms_list_stored_images_output_unref (output);
- return;
+ if (!pairs)
+ g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_NOT_FOUND, "No valid PRI+MODEM pairs found");
+
+ return pairs;
+}
+
+static gboolean
+find_image_type_indices (GArray *array,
+ QmiMessageDmsListStoredImagesOutputListImage **image_pri,
+ QmiMessageDmsListStoredImagesOutputListImage **image_modem,
+ GError **error)
+{
+ guint i;
+
+ g_assert (array);
+ g_assert (image_pri);
+ g_assert (image_modem);
+
+ *image_pri = NULL;
+ *image_modem = NULL;
+
+ /* The MODEM image list is usually given before the PRI image list, but
+ * let's not assume that. Try to find both lists and report at which index
+ * we can find each. */
+
+ for (i = 0; i < array->len; i++) {
+ QmiMessageDmsListStoredImagesOutputListImage *image;
+
+ image = &g_array_index (array, QmiMessageDmsListStoredImagesOutputListImage, i);
+ switch (image->type) {
+ case QMI_DMS_FIRMWARE_IMAGE_TYPE_PRI:
+ if (*image_pri != NULL)
+ mm_dbg ("Multiple array elements found with PRI type: ignoring additional list at index %u", i);
+ else
+ *image_pri = image;
+ break;
+ case QMI_DMS_FIRMWARE_IMAGE_TYPE_MODEM:
+ if (*image_modem != NULL)
+ mm_dbg ("Multiple array elements found with MODEM type: ignoring additional list at index %u", i);
+ else
+ *image_modem = image;
+ break;
+ default:
+ break;
+ }
}
- /* Firmware is supported; now keep on loading info for each image and cache it */
- qmi_message_dms_list_stored_images_output_unref (output);
+ if (!(*image_pri) || !(*image_modem)) {
+ g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_NOT_FOUND,
+ "Missing image list: pri list %s, modem list %s",
+ !(*image_pri) ? "not found" : "found",
+ !(*image_modem) ? "not found" : "found");
+ return FALSE;
+ }
- ctx->l = ctx->pairs;
+ return TRUE;
+}
+
+static void
+list_stored_images_ready (QmiClientDms *client,
+ GAsyncResult *res,
+ GTask *task)
+{
+ FirmwareListPreloadContext *ctx;
+ GArray *array;
+ QmiMessageDmsListStoredImagesOutputListImage *image_pri;
+ QmiMessageDmsListStoredImagesOutputListImage *image_modem;
+ QmiMessageDmsListStoredImagesOutput *output;
+ GError *error = NULL;
+
+ ctx = g_task_get_task_data (task);
+
+ /* Read array from output */
+ output = qmi_client_dms_list_stored_images_finish (client, res, &error);
+ if (!output ||
+ !qmi_message_dms_list_stored_images_output_get_result (output, &error) ||
+ !qmi_message_dms_list_stored_images_output_get_list (output, &array, &error)) {
+ g_task_return_error (task, error);
+ g_object_unref (task);
+ goto out;
+ }
+
+ /* Find which index corresponds to each image type */
+ if (!find_image_type_indices (array, &image_pri, &image_modem, &error)) {
+ g_task_return_error (task, error);
+ g_object_unref (task);
+ goto out;
+ }
+
+ /* Build firmware PRI+MODEM pair list */
+ ctx->pairs = find_image_pairs (image_pri, image_modem, &error);
+ if (!ctx->pairs) {
+ g_task_return_error (task, error);
+ g_object_unref (task);
+ goto out;
+ }
+
+ /* Now keep on loading info for each image and cache it */
get_next_image_info (task);
+
+out:
+
+ if (output)
+ qmi_message_dms_list_stored_images_output_unref (output);
}
static void
@@ -7612,21 +7695,21 @@
static void
firmware_change_current (MMIfaceModemFirmware *_self,
- const gchar *unique_id,
- GAsyncReadyCallback callback,
- gpointer user_data)
+ const gchar *unique_id,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
{
- MMBroadbandModemQmi *self = MM_BROADBAND_MODEM_QMI (_self);
- QmiMessageDmsSetFirmwarePreferenceInput *input;
- FirmwareChangeCurrentContext *ctx;
- GTask *task;
- QmiClient *client = NULL;
- GArray *array;
- QmiMessageDmsSetFirmwarePreferenceInputListImage modem_image_id;
- QmiMessageDmsSetFirmwarePreferenceInputListImage pri_image_id;
- guint8 *tmp;
- gsize tmp_len;
+ MMBroadbandModemQmi *self;
+ GTask *task;
+ FirmwareChangeCurrentContext *ctx;
+ GError *error = NULL;
+ QmiClient *client = NULL;
+ GArray *array;
+ QmiMessageDmsSetFirmwarePreferenceInput *input = NULL;
+ QmiMessageDmsSetFirmwarePreferenceInputListImage modem_image_id = { 0 };
+ QmiMessageDmsSetFirmwarePreferenceInputListImage pri_image_id = { 0 };
+ self = MM_BROADBAND_MODEM_QMI (_self);
if (!mm_shared_qmi_ensure_client (MM_SHARED_QMI (self),
QMI_SERVICE_DMS, &client,
callback, user_data))
@@ -7679,22 +7762,26 @@
}
/* Modem image ID */
- tmp_len = 0;
- tmp = (guint8 *)mm_utils_hexstr2bin (mm_firmware_properties_get_gobi_modem_unique_id (ctx->firmware), &tmp_len);
modem_image_id.type = QMI_DMS_FIRMWARE_IMAGE_TYPE_MODEM;
modem_image_id.build_id = (gchar *)mm_firmware_properties_get_unique_id (ctx->firmware);
- modem_image_id.unique_id = g_array_sized_new (FALSE, FALSE, sizeof (guint8), tmp_len);
- g_array_insert_vals (modem_image_id.unique_id, 0, tmp, tmp_len);
- g_free (tmp);
+ modem_image_id.unique_id = mm_firmware_unique_id_to_qmi_unique_id (mm_firmware_properties_get_gobi_modem_unique_id (ctx->firmware), &error);
+ if (!modem_image_id.unique_id) {
+ g_prefix_error (&error, "Couldn't build modem image unique id: ");
+ g_task_return_error (task, error);
+ g_object_unref (task);
+ goto out;
+ }
/* PRI image ID */
- tmp_len = 0;
- tmp = (guint8 *)mm_utils_hexstr2bin (mm_firmware_properties_get_gobi_pri_unique_id (ctx->firmware), &tmp_len);
pri_image_id.type = QMI_DMS_FIRMWARE_IMAGE_TYPE_PRI;
pri_image_id.build_id = (gchar *)mm_firmware_properties_get_unique_id (ctx->firmware);
- pri_image_id.unique_id = g_array_sized_new (FALSE, FALSE, sizeof (guint8), tmp_len);
- g_array_insert_vals (pri_image_id.unique_id, 0, tmp, tmp_len);
- g_free (tmp);
+ pri_image_id.unique_id = mm_firmware_unique_id_to_qmi_unique_id (mm_firmware_properties_get_gobi_pri_unique_id (ctx->firmware), &error);
+ if (!pri_image_id.unique_id) {
+ g_prefix_error (&error, "Couldn't build PRI image unique id: ");
+ g_task_return_error (task, error);
+ g_object_unref (task);
+ goto out;
+ }
mm_dbg ("Changing Gobi firmware to MODEM '%s' and PRI '%s' with Build ID '%s'...",
mm_firmware_properties_get_gobi_modem_unique_id (ctx->firmware),
@@ -7715,9 +7802,14 @@
NULL,
(GAsyncReadyCallback)firmware_select_stored_image_ready,
task);
- g_array_unref (modem_image_id.unique_id);
- g_array_unref (pri_image_id.unique_id);
- qmi_message_dms_set_firmware_preference_input_unref (input);
+
+out:
+ if (modem_image_id.unique_id)
+ g_array_unref (modem_image_id.unique_id);
+ if (pri_image_id.unique_id)
+ g_array_unref (pri_image_id.unique_id);
+ if (input)
+ qmi_message_dms_set_firmware_preference_input_unref (input);
}
/*****************************************************************************/
diff --git a/src/mm-broadband-modem.c b/src/mm-broadband-modem.c
index 3cbf513..9df2ee1 100644
--- a/src/mm-broadband-modem.c
+++ b/src/mm-broadband-modem.c
@@ -121,9 +121,11 @@
PROP_MODEM_SIM_HOT_SWAP_SUPPORTED,
PROP_MODEM_SIM_HOT_SWAP_CONFIGURED,
PROP_MODEM_PERIODIC_SIGNAL_CHECK_DISABLED,
+ PROP_MODEM_PERIODIC_ACCESS_TECH_CHECK_DISABLED,
PROP_MODEM_PERIODIC_CALL_LIST_CHECK_DISABLED,
PROP_MODEM_CARRIER_CONFIG_MAPPING,
PROP_FLOW_CONTROL,
+ PROP_INDICATORS_DISABLED,
PROP_LAST
};
@@ -139,10 +141,12 @@
/* Broadband modem specific implementation */
PortsContext *enabled_ports_ctx;
PortsContext *sim_hot_swap_ports_ctx;
+ PortsContext *in_call_ports_ctx;
gboolean modem_init_run;
gboolean sim_hot_swap_supported;
gboolean sim_hot_swap_configured;
gboolean periodic_signal_check_disabled;
+ gboolean periodic_access_tech_check_disabled;
/*<--- Modem interface --->*/
/* Properties */
@@ -153,6 +157,7 @@
gchar *carrier_config_mapping;
/* Implementation helpers */
MMModemCharset modem_current_charset;
+ gboolean modem_cind_disabled;
gboolean modem_cind_support_checked;
gboolean modem_cind_supported;
guint modem_cind_indicator_signal_quality;
@@ -248,6 +253,119 @@
};
/*****************************************************************************/
+/* Generic ports open/close context */
+
+struct _PortsContext {
+ volatile gint ref_count;
+ MMPortSerialAt *primary;
+ gboolean primary_open;
+ MMPortSerialAt *secondary;
+ gboolean secondary_open;
+ MMPortSerialQcdm *qcdm;
+ gboolean qcdm_open;
+};
+
+static PortsContext *
+ports_context_ref (PortsContext *ctx)
+{
+ g_atomic_int_inc (&ctx->ref_count);
+ return ctx;
+}
+
+static void
+ports_context_unref (PortsContext *ctx)
+{
+ if (g_atomic_int_dec_and_test (&ctx->ref_count)) {
+ if (ctx->primary) {
+ if (ctx->primary_open)
+ mm_port_serial_close (MM_PORT_SERIAL (ctx->primary));
+ g_object_unref (ctx->primary);
+ }
+ if (ctx->secondary) {
+ if (ctx->secondary_open)
+ mm_port_serial_close (MM_PORT_SERIAL (ctx->secondary));
+ g_object_unref (ctx->secondary);
+ }
+ if (ctx->qcdm) {
+ if (ctx->qcdm_open)
+ mm_port_serial_close (MM_PORT_SERIAL (ctx->qcdm));
+ g_object_unref (ctx->qcdm);
+ }
+ g_free (ctx);
+ }
+}
+
+static gboolean
+ports_context_open (MMBroadbandModem *self,
+ PortsContext *ctx,
+ gboolean disable_at_init_sequence,
+ gboolean with_at_secondary,
+ gboolean with_qcdm,
+ GError **error)
+{
+ /* Open primary */
+ ctx->primary = mm_base_modem_get_port_primary (MM_BASE_MODEM (self));
+ if (!ctx->primary) {
+ g_set_error (error,
+ MM_CORE_ERROR,
+ MM_CORE_ERROR_FAILED,
+ "Couldn't get primary port");
+ return FALSE;
+ }
+ /* If we'll need to run modem initialization, disable port init sequence */
+ if (disable_at_init_sequence)
+ g_object_set (ctx->primary,
+ MM_PORT_SERIAL_AT_INIT_SEQUENCE_ENABLED, FALSE,
+ NULL);
+ if (!mm_port_serial_open (MM_PORT_SERIAL (ctx->primary), error)) {
+ g_prefix_error (error, "Couldn't open primary port: ");
+ return FALSE;
+ }
+ ctx->primary_open = TRUE;
+
+ /* Open secondary (optional) */
+ if (with_at_secondary) {
+ ctx->secondary = mm_base_modem_get_port_secondary (MM_BASE_MODEM (self));
+ if (ctx->secondary) {
+ /* If we'll need to run modem initialization, disable port init sequence */
+ if (disable_at_init_sequence)
+ g_object_set (ctx->secondary,
+ MM_PORT_SERIAL_AT_INIT_SEQUENCE_ENABLED, FALSE,
+ NULL);
+ if (!mm_port_serial_open (MM_PORT_SERIAL (ctx->secondary), error)) {
+ g_prefix_error (error, "Couldn't open secondary port: ");
+ return FALSE;
+ }
+ ctx->secondary_open = TRUE;
+ }
+ }
+
+ /* Open qcdm (optional) */
+ if (with_qcdm) {
+ ctx->qcdm = mm_base_modem_get_port_qcdm (MM_BASE_MODEM (self));
+ if (ctx->qcdm) {
+ if (!mm_port_serial_open (MM_PORT_SERIAL (ctx->qcdm), error)) {
+ g_prefix_error (error, "Couldn't open QCDM port: ");
+ return FALSE;
+ }
+ ctx->qcdm_open = TRUE;
+ }
+ }
+
+ return TRUE;
+}
+
+static PortsContext *
+ports_context_new (void)
+{
+ PortsContext *ctx;
+
+ ctx = g_new0 (PortsContext, 1);
+ ctx->ref_count = 1;
+ return ctx;
+}
+
+/*****************************************************************************/
static gboolean
response_processor_string_ignore_at_errors (MMBaseModem *self,
@@ -2205,7 +2323,8 @@
/* Check whether we can get a non-connected AT port */
ctx->at_port = (MMPortSerial *)mm_base_modem_get_best_at_port (MM_BASE_MODEM (self), &error);
if (ctx->at_port) {
- if (self->priv->modem_cind_supported &&
+ if (!self->priv->modem_cind_disabled &&
+ self->priv->modem_cind_supported &&
CIND_INDICATOR_IS_VALID (self->priv->modem_cind_indicator_signal_quality))
signal_quality_cind (task);
else
@@ -3187,7 +3306,7 @@
self = g_task_get_source_object (task);
/* Check support for +CIEV indications, managed with +CIND/+CMER */
- if (!self->priv->modem_cind_support_checked) {
+ if (!self->priv->modem_cind_disabled && !self->priv->modem_cind_support_checked) {
mm_dbg ("Checking indicator support...");
self->priv->modem_cind_support_checked = TRUE;
mm_base_modem_at_command (MM_BASE_MODEM (self),
@@ -3236,7 +3355,7 @@
task = g_task_new (self, NULL, callback, user_data);
- if (self->priv->modem_cind_support_checked && self->priv->modem_cind_supported)
+ if (!self->priv->modem_cind_disabled && self->priv->modem_cind_support_checked && self->priv->modem_cind_supported)
set_ciev_unsolicited_events_handlers (self, FALSE);
if (self->priv->modem_cgerep_supported)
@@ -3316,14 +3435,14 @@
ctx = g_task_get_task_data (task);
/* CMER on primary port */
- if (!ctx->cmer_primary_done && ctx->cmer_command && ctx->primary) {
+ if (!ctx->cmer_primary_done && ctx->cmer_command && ctx->primary && !self->priv->modem_cind_disabled) {
mm_dbg ("%s +CIND event reporting in primary port...", ctx->enable ? "Enabling" : "Disabling");
ctx->cmer_primary_done = TRUE;
command = ctx->cmer_command;
port = ctx->primary;
}
/* CMER on secondary port */
- else if (!ctx->cmer_secondary_done && ctx->cmer_command && ctx->secondary) {
+ else if (!ctx->cmer_secondary_done && ctx->cmer_command && ctx->secondary && !self->priv->modem_cind_disabled) {
mm_dbg ("%s +CIND event reporting in secondary port...", ctx->enable ? "Enabling" : "Disabling");
ctx->cmer_secondary_done = TRUE;
command = ctx->cmer_command;
@@ -5294,7 +5413,7 @@
task = self->priv->pending_ussd_action;
self->priv->pending_ussd_action = NULL;
- g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_CANCELLED,
+ g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_ABORTED,
"USSD session was cancelled");
g_object_unref (task);
}
@@ -5701,13 +5820,13 @@
case 2:
/* Response to the user's request? */
if (task)
- error = g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_CANCELLED, "USSD terminated by network");
+ error = g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_ABORTED, "USSD terminated by network");
break;
case 4:
/* Response to the user's request? */
if (task)
- error = g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_CANCELLED, "Operation not supported");
+ error = g_error_new (MM_MOBILE_EQUIPMENT_ERROR, MM_MOBILE_EQUIPMENT_ERROR_NOT_SUPPORTED, "Operation not supported");
break;
default:
@@ -7205,6 +7324,20 @@
}
static void
+ignore_sim_related_errors (GError **error)
+{
+ g_assert (error && *error);
+ if (g_error_matches (*error, MM_MOBILE_EQUIPMENT_ERROR, MM_MOBILE_EQUIPMENT_ERROR_SIM_NOT_INSERTED) ||
+ g_error_matches (*error, MM_MOBILE_EQUIPMENT_ERROR, MM_MOBILE_EQUIPMENT_ERROR_SIM_PIN) ||
+ g_error_matches (*error, MM_MOBILE_EQUIPMENT_ERROR, MM_MOBILE_EQUIPMENT_ERROR_SIM_PUK) ||
+ g_error_matches (*error, MM_MOBILE_EQUIPMENT_ERROR, MM_MOBILE_EQUIPMENT_ERROR_SIM_FAILURE) ||
+ g_error_matches (*error, MM_MOBILE_EQUIPMENT_ERROR, MM_MOBILE_EQUIPMENT_ERROR_SIM_BUSY) ||
+ g_error_matches (*error, MM_MOBILE_EQUIPMENT_ERROR, MM_MOBILE_EQUIPMENT_ERROR_SIM_WRONG)) {
+ g_clear_error (error);
+ }
+}
+
+static void
clcc_format_check_ready (MMBroadbandModem *self,
GAsyncResult *res,
GTask *task)
@@ -7231,16 +7364,25 @@
mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, &error);
if (error) {
- g_task_return_error (task, error);
- g_object_unref (task);
- return;
+ /* Ignore some errors that the module may return when there is no SIM inserted or
+ * if the SIM is PIN-locked. We do need the voice interface exposed even in those
+ * cases, in order to support emergency calls */
+ ignore_sim_related_errors (&error);
+ if (error) {
+ g_task_return_error (task, error);
+ g_object_unref (task);
+ return;
+ }
}
/* Also check if +CLCC is supported */
mm_base_modem_at_command (MM_BASE_MODEM (self),
"+CLCC=?",
3,
- TRUE,
+ /* Do NOT cache as the reply may be different if PIN locked
+ * or unlocked. E.g. we may not support +CLCC for emergency
+ * voice calls. */
+ FALSE,
(GAsyncReadyCallback)clcc_format_check_ready,
task);
}
@@ -7260,7 +7402,7 @@
mm_base_modem_at_command (MM_BASE_MODEM (self),
"H",
3,
- TRUE,
+ FALSE,
(GAsyncReadyCallback)ath_format_check_ready,
task);
}
@@ -7353,21 +7495,19 @@
}
static void
-set_voice_in_call_unsolicited_events_handlers (MMIfaceModemVoice *self,
- gboolean enable,
- GAsyncReadyCallback callback,
- gpointer user_data)
+set_voice_in_call_unsolicited_events_handlers (MMBroadbandModem *self,
+ PortsContext *ports_ctx,
+ gboolean enable)
{
MMPortSerialAt *ports[2];
GRegex *in_call_event_regex;
guint i;
- GTask *task;
in_call_event_regex = g_regex_new ("\\r\\n(NO CARRIER|BUSY|NO ANSWER|NO DIALTONE)\\r\\n$",
- G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
+ G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
- ports[0] = mm_base_modem_peek_port_primary (MM_BASE_MODEM (self));
- ports[1] = mm_base_modem_peek_port_secondary (MM_BASE_MODEM (self));
+ ports[0] = MM_PORT_SERIAL_AT (ports_ctx->primary);
+ ports[1] = MM_PORT_SERIAL_AT (ports_ctx->secondary);
/* Enable unsolicited events in given port */
for (i = 0; i < 2; i++) {
@@ -7386,26 +7526,60 @@
}
g_regex_unref (in_call_event_regex);
+}
+
+static void
+modem_voice_setup_in_call_unsolicited_events (MMIfaceModemVoice *_self,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ MMBroadbandModem *self;
+ GTask *task;
+ GError *error = NULL;
+
+ self = MM_BROADBAND_MODEM (_self);
+ if (!self->priv->in_call_ports_ctx) {
+ PortsContext *ctx;
+
+ mm_dbg ("Setting up in-call ports context");
+ ctx = ports_context_new ();
+ if (!ports_context_open (self, ctx, FALSE, FALSE, FALSE, &error)) {
+ ports_context_unref (ctx);
+ g_prefix_error (&error, "Couldn't open ports in-call: ");
+ } else {
+ set_voice_in_call_unsolicited_events_handlers (self, ctx, TRUE);
+ self->priv->in_call_ports_ctx = ctx;
+ }
+ } else
+ mm_dbg ("In-call ports context already set up");
task = g_task_new (self, NULL, callback, user_data);
- g_task_return_boolean (task, TRUE);
+ if (error)
+ g_task_return_error (task, error);
+ else
+ g_task_return_boolean (task, TRUE);
g_object_unref (task);
}
static void
-modem_voice_setup_in_call_unsolicited_events (MMIfaceModemVoice *self,
- GAsyncReadyCallback callback,
- gpointer user_data)
-{
- set_voice_in_call_unsolicited_events_handlers (self, TRUE, callback, user_data);
-}
-
-static void
-modem_voice_cleanup_in_call_unsolicited_events (MMIfaceModemVoice *self,
+modem_voice_cleanup_in_call_unsolicited_events (MMIfaceModemVoice *_self,
GAsyncReadyCallback callback,
gpointer user_data)
{
- set_voice_in_call_unsolicited_events_handlers (self, FALSE, callback, user_data);
+ MMBroadbandModem *self;
+ GTask *task;
+
+ self = MM_BROADBAND_MODEM (_self);
+ if (self->priv->in_call_ports_ctx) {
+ mm_dbg ("Cleaning up in-call ports context");
+ set_voice_in_call_unsolicited_events_handlers (self, self->priv->in_call_ports_ctx, FALSE);
+ g_clear_pointer (&self->priv->in_call_ports_ctx, (GDestroyNotify) ports_context_unref);
+ } else
+ mm_dbg ("In-call ports context already cleaned up");
+
+ task = g_task_new (self, NULL, callback, user_data);
+ g_task_return_boolean (task, TRUE);
+ g_object_unref (task);
}
/*****************************************************************************/
@@ -9773,50 +9947,6 @@
}
/*****************************************************************************/
-/* Generic ports open/close context */
-
-struct _PortsContext {
- volatile gint ref_count;
-
- MMPortSerialAt *primary;
- gboolean primary_open;
- MMPortSerialAt *secondary;
- gboolean secondary_open;
- MMPortSerialQcdm *qcdm;
- gboolean qcdm_open;
-};
-
-static PortsContext *
-ports_context_ref (PortsContext *ctx)
-{
- g_atomic_int_inc (&ctx->ref_count);
- return ctx;
-}
-
-static void
-ports_context_unref (PortsContext *ctx)
-{
- if (g_atomic_int_dec_and_test (&ctx->ref_count)) {
- if (ctx->primary) {
- if (ctx->primary_open)
- mm_port_serial_close (MM_PORT_SERIAL (ctx->primary));
- g_object_unref (ctx->primary);
- }
- if (ctx->secondary) {
- if (ctx->secondary_open)
- mm_port_serial_close (MM_PORT_SERIAL (ctx->secondary));
- g_object_unref (ctx->secondary);
- }
- if (ctx->qcdm) {
- if (ctx->qcdm_open)
- mm_port_serial_close (MM_PORT_SERIAL (ctx->qcdm));
- g_object_unref (ctx->qcdm);
- }
- g_free (ctx);
- }
-}
-
-/*****************************************************************************/
/* Initialization started/stopped */
static gboolean
@@ -9864,17 +9994,6 @@
ctx->primary_open = TRUE;
- /* Try to disable echo */
- mm_base_modem_at_command_full (MM_BASE_MODEM (self),
- ctx->primary,
- "E0", 3,
- FALSE, FALSE, NULL, NULL, NULL);
- /* Try to get extended errors */
- mm_base_modem_at_command_full (MM_BASE_MODEM (self),
- ctx->primary,
- "+CMEE=1", 3,
- FALSE, FALSE, NULL, NULL, NULL);
-
return TRUE;
}
@@ -9889,10 +10008,9 @@
task = g_task_new (self, NULL, callback, user_data);
- ctx = g_new0 (PortsContext, 1);
- ctx->ref_count = 1;
-
- if (!open_ports_initialization (self, ctx, &error)) {
+ /* Open ports for initialization, just the primary AT port */
+ ctx = ports_context_new ();
+ if (!ports_context_open (self, ctx, FALSE, FALSE, FALSE, &error)) {
ports_context_unref (ctx);
g_prefix_error (&error, "Couldn't open ports during modem initialization: ");
g_task_return_error (task, error);
@@ -9981,6 +10099,7 @@
ctx = g_task_get_task_data (task);
/* Reset init sequence enabled flags and run them explicitly */
+ g_assert (ctx->modem_init_required);
g_object_set (ctx->ports->primary,
MM_PORT_SERIAL_AT_INIT_SEQUENCE_ENABLED, TRUE,
NULL);
@@ -10053,64 +10172,6 @@
g_object_unref (task);
}
-static gboolean
-open_ports_enabling (MMBroadbandModem *self,
- PortsContext *ctx,
- gboolean modem_init_required,
- GError **error)
-{
- /* Open primary */
- ctx->primary = mm_base_modem_get_port_primary (MM_BASE_MODEM (self));
- if (!ctx->primary) {
- g_set_error (error,
- MM_CORE_ERROR,
- MM_CORE_ERROR_FAILED,
- "Couldn't get primary port");
- return FALSE;
- }
-
- /* If we'll need to run modem initialization, disable port init sequence */
- if (modem_init_required)
- g_object_set (ctx->primary,
- MM_PORT_SERIAL_AT_INIT_SEQUENCE_ENABLED, FALSE,
- NULL);
-
-
- if (!mm_port_serial_open (MM_PORT_SERIAL (ctx->primary), error)) {
- g_prefix_error (error, "Couldn't open primary port: ");
- return FALSE;
- }
-
- ctx->primary_open = TRUE;
-
- /* Open secondary (optional) */
- ctx->secondary = mm_base_modem_get_port_secondary (MM_BASE_MODEM (self));
- if (ctx->secondary) {
- /* If we'll need to run modem initialization, disable port init sequence */
- if (modem_init_required)
- g_object_set (ctx->secondary,
- MM_PORT_SERIAL_AT_INIT_SEQUENCE_ENABLED, FALSE,
- NULL);
- if (!mm_port_serial_open (MM_PORT_SERIAL (ctx->secondary), error)) {
- g_prefix_error (error, "Couldn't open secondary port: ");
- return FALSE;
- }
- ctx->secondary_open = TRUE;
- }
-
- /* Open qcdm (optional) */
- ctx->qcdm = mm_base_modem_get_port_qcdm (MM_BASE_MODEM (self));
- if (ctx->qcdm) {
- if (!mm_port_serial_open (MM_PORT_SERIAL (ctx->qcdm), error)) {
- g_prefix_error (error, "Couldn't open QCDM port: ");
- return FALSE;
- }
- ctx->qcdm_open = TRUE;
- }
-
- return TRUE;
-}
-
static void
enabling_started (MMBroadbandModem *self,
GAsyncReadyCallback callback,
@@ -10121,8 +10182,7 @@
GTask *task;
ctx = g_slice_new0 (EnablingStartedContext);
- ctx->ports = g_new0 (PortsContext, 1);
- ctx->ports->ref_count = 1;
+ ctx->ports = ports_context_new ();
/* Skip modem initialization if the device was hotplugged OR if we already
* did it (i.e. don't reinitialize if the modem got disabled and enabled
@@ -10141,8 +10201,8 @@
task = g_task_new (self, NULL, callback, user_data);
g_task_set_task_data (task, ctx, (GDestroyNotify)enabling_started_context_free);
- /* Enabling */
- if (!open_ports_enabling (self, ctx->ports, ctx->modem_init_required, &error)) {
+ /* Open ports for enabling, including secondary AT port and QCDM if available */
+ if (!ports_context_open (self, ctx->ports, ctx->modem_init_required, TRUE, TRUE, &error)) {
g_prefix_error (&error, "Couldn't open ports during modem enabling: ");
g_task_return_error (task, error);
g_object_unref (task);
@@ -10219,11 +10279,11 @@
DISABLING_STEP_DISCONNECT_BEARERS,
DISABLING_STEP_IFACE_SIMPLE,
DISABLING_STEP_IFACE_FIRMWARE,
+ DISABLING_STEP_IFACE_VOICE,
DISABLING_STEP_IFACE_SIGNAL,
DISABLING_STEP_IFACE_OMA,
DISABLING_STEP_IFACE_TIME,
DISABLING_STEP_IFACE_MESSAGING,
- DISABLING_STEP_IFACE_VOICE,
DISABLING_STEP_IFACE_LOCATION,
DISABLING_STEP_IFACE_CDMA,
DISABLING_STEP_IFACE_3GPP_USSD,
@@ -10423,6 +10483,18 @@
/* Fall down to next step */
ctx->step++;
+ case DISABLING_STEP_IFACE_VOICE:
+ if (ctx->self->priv->modem_voice_dbus_skeleton) {
+ mm_dbg ("Modem has voice capabilities, disabling the Voice interface...");
+ /* Disabling the Modem Voice interface */
+ mm_iface_modem_voice_disable (MM_IFACE_MODEM_VOICE (ctx->self),
+ (GAsyncReadyCallback)iface_modem_voice_disable_ready,
+ task);
+ return;
+ }
+ /* Fall down to next step */
+ ctx->step++;
+
case DISABLING_STEP_IFACE_SIGNAL:
if (ctx->self->priv->modem_signal_dbus_skeleton) {
mm_dbg ("Modem has extended signal reporting capabilities, disabling the Signal interface...");
@@ -10471,18 +10543,6 @@
/* Fall down to next step */
ctx->step++;
- case DISABLING_STEP_IFACE_VOICE:
- if (ctx->self->priv->modem_voice_dbus_skeleton) {
- mm_dbg ("Modem has voice capabilities, disabling the Voice interface...");
- /* Disabling the Modem Voice interface */
- mm_iface_modem_voice_disable (MM_IFACE_MODEM_VOICE (ctx->self),
- (GAsyncReadyCallback)iface_modem_voice_disable_ready,
- task);
- return;
- }
- /* Fall down to next step */
- ctx->step++;
-
case DISABLING_STEP_IFACE_LOCATION:
if (ctx->self->priv->modem_location_dbus_skeleton) {
mm_dbg ("Modem has location capabilities, disabling the Location interface...");
@@ -10586,10 +10646,10 @@
ENABLING_STEP_IFACE_CDMA,
ENABLING_STEP_IFACE_LOCATION,
ENABLING_STEP_IFACE_MESSAGING,
- ENABLING_STEP_IFACE_VOICE,
ENABLING_STEP_IFACE_TIME,
ENABLING_STEP_IFACE_SIGNAL,
ENABLING_STEP_IFACE_OMA,
+ ENABLING_STEP_IFACE_VOICE,
ENABLING_STEP_IFACE_FIRMWARE,
ENABLING_STEP_IFACE_SIMPLE,
ENABLING_STEP_LAST,
@@ -10833,19 +10893,6 @@
/* Fall down to next step */
ctx->step++;
- case ENABLING_STEP_IFACE_VOICE:
- if (ctx->self->priv->modem_voice_dbus_skeleton) {
- mm_dbg ("Modem has voice capabilities, enabling the Voice interface...");
- /* Enabling the Modem Voice interface */
- mm_iface_modem_voice_enable (MM_IFACE_MODEM_VOICE (ctx->self),
- g_task_get_cancellable (task),
- (GAsyncReadyCallback)iface_modem_voice_enable_ready,
- task);
- return;
- }
- /* Fall down to next step */
- ctx->step++;
-
case ENABLING_STEP_IFACE_TIME:
if (ctx->self->priv->modem_time_dbus_skeleton) {
mm_dbg ("Modem has time capabilities, enabling the Time interface...");
@@ -10885,6 +10932,19 @@
/* Fall down to next step */
ctx->step++;
+ case ENABLING_STEP_IFACE_VOICE:
+ if (ctx->self->priv->modem_voice_dbus_skeleton) {
+ mm_dbg ("Modem has voice capabilities, enabling the Voice interface...");
+ /* Enabling the Modem Voice interface */
+ mm_iface_modem_voice_enable (MM_IFACE_MODEM_VOICE (ctx->self),
+ g_task_get_cancellable (task),
+ (GAsyncReadyCallback)iface_modem_voice_enable_ready,
+ task);
+ return;
+ }
+ /* Fall down to next step */
+ ctx->step++;
+
case ENABLING_STEP_IFACE_FIRMWARE:
/* Fall down to next step */
ctx->step++;
@@ -10991,10 +11051,11 @@
INITIALIZE_STEP_IFACE_CDMA,
INITIALIZE_STEP_IFACE_LOCATION,
INITIALIZE_STEP_IFACE_MESSAGING,
- INITIALIZE_STEP_IFACE_VOICE,
INITIALIZE_STEP_IFACE_TIME,
INITIALIZE_STEP_IFACE_SIGNAL,
INITIALIZE_STEP_IFACE_OMA,
+ INITIALIZE_STEP_FALLBACK_LIMITED,
+ INITIALIZE_STEP_IFACE_VOICE,
INITIALIZE_STEP_IFACE_FIRMWARE,
INITIALIZE_STEP_SIM_HOT_SWAP,
INITIALIZE_STEP_IFACE_SIMPLE,
@@ -11101,9 +11162,9 @@
mm_iface_modem_update_failed_state (MM_IFACE_MODEM (self), failed_reason);
- /* Jump to the firmware step. We allow firmware switching even in failed
- * state */
- ctx->step = INITIALIZE_STEP_IFACE_FIRMWARE;
+ /* Jump to the fallback step when on failure, we will allow some additional
+ * interfaces even in failed state. */
+ ctx->step = INITIALIZE_STEP_FALLBACK_LIMITED;
initialize_step (task);
return;
}
@@ -11116,9 +11177,9 @@
* the initialization sequence. Instead, we will re-initialize once
* we are unlocked. */
if (ctx->self->priv->modem_state == MM_MODEM_STATE_LOCKED) {
- /* Jump to the Firmware interface. We do allow modems to export
- * both the Firmware and Simple interfaces when locked. */
- ctx->step = INITIALIZE_STEP_IFACE_FIRMWARE;
+ /* Jump to the fallback step when locked, we will allow some additional
+ * interfaces even in locked state. */
+ ctx->step = INITIALIZE_STEP_FALLBACK_LIMITED;
initialize_step (task);
return;
}
@@ -11286,14 +11347,6 @@
task);
return;
- case INITIALIZE_STEP_IFACE_VOICE:
- /* Initialize the Voice interface */
- mm_iface_modem_voice_initialize (MM_IFACE_MODEM_VOICE (ctx->self),
- g_task_get_cancellable (task),
- (GAsyncReadyCallback)iface_modem_voice_initialize_ready,
- task);
- return;
-
case INITIALIZE_STEP_IFACE_TIME:
/* Initialize the Time interface */
mm_iface_modem_time_initialize (MM_IFACE_MODEM_TIME (ctx->self),
@@ -11318,6 +11371,20 @@
task);
return;
+ case INITIALIZE_STEP_FALLBACK_LIMITED:
+ /* All the initialization steps after this one will be run both on
+ * successful and locked/failed initializations.
+ * Fall down to next step */
+ ctx->step++;
+
+ case INITIALIZE_STEP_IFACE_VOICE:
+ /* Initialize the Voice interface */
+ mm_iface_modem_voice_initialize (MM_IFACE_MODEM_VOICE (ctx->self),
+ g_task_get_cancellable (task),
+ (GAsyncReadyCallback)iface_modem_voice_initialize_ready,
+ task);
+ return;
+
case INITIALIZE_STEP_IFACE_FIRMWARE:
/* Initialize the Firmware interface */
mm_iface_modem_firmware_initialize (MM_IFACE_MODEM_FIRMWARE (ctx->self),
@@ -11347,11 +11414,8 @@
GError *error = NULL;
mm_dbg ("Creating ports context for SIM hot swap");
-
- ports = g_new0 (PortsContext, 1);
- ports->ref_count = 1;
-
- if (!open_ports_enabling (ctx->self, ports, FALSE, &error)) {
+ ports = ports_context_new ();
+ if (!ports_context_open (ctx->self, ports, FALSE, FALSE, FALSE, &error)) {
mm_warn ("Couldn't open ports during Modem SIM hot swap enabling: %s", error? error->message : "unknown reason");
g_error_free (error);
} else {
@@ -11420,9 +11484,11 @@
"Modem is unusable, "
"cannot fully initialize");
sim_hot_swap_enabled:
- /* Ensure we only leave the Modem, OMA, and Firmware interfaces
+ /* Ensure we only leave the Modem and Firmware interfaces
* around. A failure could be caused by firmware issues, which
- * a firmware update, switch, or provisioning could fix.
+ * a firmware update, switch, or provisioning could fix. We also
+ * leave the Voice interface around so that we can attempt
+ * emergency voice calls.
*/
mm_iface_modem_3gpp_shutdown (MM_IFACE_MODEM_3GPP (ctx->self));
mm_iface_modem_3gpp_ussd_shutdown (MM_IFACE_MODEM_3GPP_USSD (ctx->self));
@@ -11430,7 +11496,6 @@
mm_iface_modem_location_shutdown (MM_IFACE_MODEM_LOCATION (ctx->self));
mm_iface_modem_signal_shutdown (MM_IFACE_MODEM_SIGNAL (ctx->self));
mm_iface_modem_messaging_shutdown (MM_IFACE_MODEM_MESSAGING (ctx->self));
- mm_iface_modem_voice_shutdown (MM_IFACE_MODEM_VOICE (ctx->self));
mm_iface_modem_time_shutdown (MM_IFACE_MODEM_TIME (ctx->self));
mm_iface_modem_simple_shutdown (MM_IFACE_MODEM_SIMPLE (ctx->self));
}
@@ -11760,6 +11825,9 @@
case PROP_MODEM_PERIODIC_SIGNAL_CHECK_DISABLED:
self->priv->periodic_signal_check_disabled = g_value_get_boolean (value);
break;
+ case PROP_MODEM_PERIODIC_ACCESS_TECH_CHECK_DISABLED:
+ self->priv->periodic_access_tech_check_disabled = g_value_get_boolean (value);
+ break;
case PROP_MODEM_PERIODIC_CALL_LIST_CHECK_DISABLED:
self->priv->periodic_call_list_check_disabled = g_value_get_boolean (value);
break;
@@ -11769,6 +11837,9 @@
case PROP_FLOW_CONTROL:
self->priv->flow_control = g_value_get_flags (value);
break;
+ case PROP_INDICATORS_DISABLED:
+ self->priv->modem_cind_disabled = g_value_get_boolean (value);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -11886,6 +11957,9 @@
case PROP_MODEM_PERIODIC_SIGNAL_CHECK_DISABLED:
g_value_set_boolean (value, self->priv->periodic_signal_check_disabled);
break;
+ case PROP_MODEM_PERIODIC_ACCESS_TECH_CHECK_DISABLED:
+ g_value_set_boolean (value, self->priv->periodic_access_tech_check_disabled);
+ break;
case PROP_MODEM_PERIODIC_CALL_LIST_CHECK_DISABLED:
g_value_set_boolean (value, self->priv->periodic_call_list_check_disabled);
break;
@@ -11895,6 +11969,9 @@
case PROP_FLOW_CONTROL:
g_value_set_flags (value, self->priv->flow_control);
break;
+ case PROP_INDICATORS_DISABLED:
+ g_value_set_boolean (value, self->priv->modem_cind_disabled);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -11925,6 +12002,7 @@
self->priv->current_sms_mem2_storage = MM_SMS_STORAGE_UNKNOWN;
self->priv->sim_hot_swap_supported = FALSE;
self->priv->periodic_signal_check_disabled = FALSE;
+ self->priv->periodic_access_tech_check_disabled = FALSE;
self->priv->periodic_call_list_check_disabled = FALSE;
self->priv->modem_cmer_enable_mode = MM_3GPP_CMER_MODE_NONE;
self->priv->modem_cmer_disable_mode = MM_3GPP_CMER_MODE_NONE;
@@ -11943,6 +12021,9 @@
if (self->priv->sim_hot_swap_ports_ctx)
ports_context_unref (self->priv->sim_hot_swap_ports_ctx);
+ if (self->priv->in_call_ports_ctx)
+ ports_context_unref (self->priv->in_call_ports_ctx);
+
if (self->priv->modem_3gpp_registration_regex)
mm_3gpp_creg_regex_destroy (self->priv->modem_3gpp_registration_regex);
@@ -12006,6 +12087,11 @@
g_clear_object (&self->priv->modem_simple_dbus_skeleton);
}
+ if (self->priv->modem_firmware_dbus_skeleton) {
+ mm_iface_modem_firmware_shutdown (MM_IFACE_MODEM_FIRMWARE (object));
+ g_clear_object (&self->priv->modem_firmware_dbus_skeleton);
+ }
+
g_clear_object (&self->priv->modem_3gpp_initial_eps_bearer);
g_clear_object (&self->priv->modem_sim);
g_clear_object (&self->priv->modem_bearer_list);
@@ -12454,6 +12540,10 @@
MM_IFACE_MODEM_PERIODIC_SIGNAL_CHECK_DISABLED);
g_object_class_override_property (object_class,
+ PROP_MODEM_PERIODIC_ACCESS_TECH_CHECK_DISABLED,
+ MM_IFACE_MODEM_PERIODIC_ACCESS_TECH_CHECK_DISABLED);
+
+ g_object_class_override_property (object_class,
PROP_MODEM_PERIODIC_CALL_LIST_CHECK_DISABLED,
MM_IFACE_MODEM_VOICE_PERIODIC_CALL_LIST_CHECK_DISABLED);
@@ -12469,4 +12559,12 @@
MM_FLOW_CONTROL_NONE,
G_PARAM_READWRITE);
g_object_class_install_property (object_class, PROP_FLOW_CONTROL, properties[PROP_FLOW_CONTROL]);
+
+ properties[PROP_INDICATORS_DISABLED] =
+ g_param_spec_boolean (MM_BROADBAND_MODEM_INDICATORS_DISABLED,
+ "Disable indicators",
+ "Avoid explicitly setting up +CIND URCs",
+ FALSE,
+ G_PARAM_READWRITE);
+ g_object_class_install_property (object_class, PROP_INDICATORS_DISABLED, properties[PROP_INDICATORS_DISABLED]);
}
diff --git a/src/mm-broadband-modem.h b/src/mm-broadband-modem.h
index 4625b22..8042f50 100644
--- a/src/mm-broadband-modem.h
+++ b/src/mm-broadband-modem.h
@@ -39,7 +39,8 @@
typedef struct _MMBroadbandModemClass MMBroadbandModemClass;
typedef struct _MMBroadbandModemPrivate MMBroadbandModemPrivate;
-#define MM_BROADBAND_MODEM_FLOW_CONTROL "broadband-modem-flow-control"
+#define MM_BROADBAND_MODEM_FLOW_CONTROL "broadband-modem-flow-control"
+#define MM_BROADBAND_MODEM_INDICATORS_DISABLED "broadband-modem-indicators-disabled"
struct _MMBroadbandModem {
MMBaseModem parent;
diff --git a/src/mm-iface-modem-firmware.c b/src/mm-iface-modem-firmware.c
index a3e68c5..f65b775 100644
--- a/src/mm-iface-modem-firmware.c
+++ b/src/mm-iface-modem-firmware.c
@@ -157,7 +157,7 @@
mm_base_modem_authorize (MM_BASE_MODEM (self),
invocation,
- MM_AUTHORIZATION_DEVICE_CONTROL,
+ MM_AUTHORIZATION_FIRMWARE,
(GAsyncReadyCallback)list_auth_ready,
ctx);
@@ -244,7 +244,7 @@
mm_base_modem_authorize (MM_BASE_MODEM (self),
invocation,
- MM_AUTHORIZATION_DEVICE_CONTROL,
+ MM_AUTHORIZATION_FIRMWARE,
(GAsyncReadyCallback)select_auth_ready,
ctx);
diff --git a/src/mm-iface-modem-simple.c b/src/mm-iface-modem-simple.c
index ecf0b68..893c470 100644
--- a/src/mm-iface-modem-simple.c
+++ b/src/mm-iface-modem-simple.c
@@ -29,6 +29,40 @@
#include "mm-log.h"
/*****************************************************************************/
+/* Private data context */
+
+#define PRIVATE_TAG "iface-modem-simple-private-tag"
+static GQuark private_quark;
+
+typedef struct {
+ GCancellable *ongoing_connect;
+} Private;
+
+static void
+private_free (Private *priv)
+{
+ g_assert (!priv->ongoing_connect);
+ g_slice_free (Private, priv);
+}
+
+static Private *
+get_private (MMIfaceModemSimple *self)
+{
+ Private *priv;
+
+ if (G_UNLIKELY (!private_quark))
+ private_quark = g_quark_from_static_string (PRIVATE_TAG);
+
+ priv = g_object_get_qdata (G_OBJECT (self), private_quark);
+ if (!priv) {
+ priv = g_slice_new0 (Private);
+ g_object_set_qdata_full (G_OBJECT (self), private_quark, priv, (GDestroyNotify)private_free);
+ }
+
+ return priv;
+}
+
+/*****************************************************************************/
/* Register in either a CDMA or a 3GPP network (or both) */
typedef struct {
@@ -198,16 +232,18 @@
/* Results to set */
MMBaseBearer *bearer;
+
+ /* Cancellation */
+ GCancellable *cancellable;
} ConnectionContext;
static void
connection_context_free (ConnectionContext *ctx)
{
+ g_clear_object (&ctx->cancellable);
+ g_clear_object (&ctx->properties);
+ g_clear_object (&ctx->bearer);
g_variant_unref (ctx->dictionary);
- if (ctx->properties)
- g_object_unref (ctx->properties);
- if (ctx->bearer)
- g_object_unref (ctx->bearer);
g_object_unref (ctx->skeleton);
g_object_unref (ctx->invocation);
g_object_unref (ctx->self);
@@ -436,9 +472,58 @@
ctx->found = g_object_ref (bearer);
}
+static gboolean
+completed_if_cancelled (ConnectionContext *ctx)
+{
+ /* Do nothing if not cancelled */
+ if (!g_cancellable_is_cancelled (ctx->cancellable))
+ return FALSE;
+
+ /* Otherwise cancellable is valid and it's cancelled */
+ g_dbus_method_invocation_return_error (
+ ctx->invocation, G_IO_ERROR, G_IO_ERROR_CANCELLED,
+ "Connection attempt cancelled");
+ connection_context_free (ctx);
+ return TRUE;
+}
+
+static void
+cleanup_cancellation (ConnectionContext *ctx)
+{
+ Private *priv;
+
+ priv = get_private (ctx->self);
+ g_clear_object (&priv->ongoing_connect);
+ g_clear_object (&ctx->cancellable);
+}
+
+static gboolean
+setup_cancellation (ConnectionContext *ctx,
+ GError **error)
+{
+ Private *priv;
+
+ /* Only one connection attempt by Simple.Connect() may be handled at a time */
+ priv = get_private (ctx->self);
+ if (priv->ongoing_connect) {
+ g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_IN_PROGRESS,
+ "Connection request forbidden: operation already in progress");
+ return FALSE;
+ }
+
+ g_assert (!ctx->cancellable);
+ ctx->cancellable = g_cancellable_new ();
+ priv->ongoing_connect = g_object_ref (ctx->cancellable);
+ return TRUE;
+}
+
static void
connection_step (ConnectionContext *ctx)
{
+ /* Early abort if operation is cancelled */
+ if (completed_if_cancelled (ctx))
+ return;
+
switch (ctx->step) {
case CONNECTION_STEP_FIRST:
/* Fall down to next step */
@@ -588,6 +673,10 @@
mm_info ("Simple connect state (%d/%d): Connect",
ctx->step, CONNECTION_STEP_LAST);
+ /* At this point, we can cleanup the cancellation point in the Simple interface,
+ * because the bearer connection has its own cancellation setup. */
+ cleanup_cancellation (ctx);
+
/* Wait... if we're already using an existing bearer, we need to check if it is
* already connected; and if so, just don't do anything else */
if (mm_base_bearer_get_status (ctx->bearer) != MM_BEARER_STATUS_CONNECTED) {
@@ -639,6 +728,12 @@
return;
}
+ if (!setup_cancellation (ctx, &error)) {
+ g_dbus_method_invocation_take_error (ctx->invocation, error);
+ connection_context_free (ctx);
+ return;
+ }
+
/* We may be able to skip some steps, so check that before doing anything */
g_object_get (self,
MM_IFACE_MODEM_STATE, ¤t,
@@ -736,6 +831,8 @@
ctx->self = g_object_ref (self);
ctx->dictionary = g_variant_ref (dictionary);
+ mm_dbg ("User request to connect modem");
+
mm_base_modem_authorize (MM_BASE_MODEM (self),
invocation,
MM_AUTHORIZATION_DEVICE_CONTROL,
@@ -824,6 +921,7 @@
{
GError *error = NULL;
MMBearerList *list = NULL;
+ Private *priv;
if (!mm_base_modem_authorize_finish (self, res, &error)) {
g_dbus_method_invocation_take_error (ctx->invocation, error);
@@ -831,6 +929,14 @@
return;
}
+ /* If not disconnecting a specific bearer, also cancel any ongoing
+ * connection attempt. */
+ priv = get_private (MM_IFACE_MODEM_SIMPLE (self));
+ if (!ctx->bearer_path && priv->ongoing_connect) {
+ g_cancellable_cancel (priv->ongoing_connect);
+ g_clear_object (&priv->ongoing_connect);
+ }
+
g_object_get (self,
MM_IFACE_MODEM_BEARER_LIST, &list,
NULL);
@@ -878,11 +984,18 @@
ctx->self = g_object_ref (self);
ctx->invocation = g_object_ref (invocation);
- if (bearer_path &&
- bearer_path[0] == '/' &&
- bearer_path[1]) {
- ctx->bearer_path = g_strdup (ctx->bearer_path);
- }
+ /* The Disconnect() method expects a valid object path given in bearer path,
+ * it cannot be NULL, so we assume we get '/' when we're asked to disconnect
+ * all connected bearers, as that is what mm_modem_simple_disconnect() does
+ * when a NULL bearer path is given to that method.
+ *
+ * We will detect the '/' string and set the bearer path as NULL in the
+ * context if so, and otherwise use the given input string as path */
+ if (g_strcmp0 (bearer_path, "/") != 0) {
+ mm_dbg ("User request to disconnect modem (bearer '%s')", bearer_path);
+ ctx->bearer_path = g_strdup (bearer_path);
+ } else
+ mm_dbg ("User request to disconnect modem (all bearers)");
mm_base_modem_authorize (MM_BASE_MODEM (self),
invocation,
diff --git a/src/mm-iface-modem-time.c b/src/mm-iface-modem-time.c
index b8d35bf..1ed4b90 100644
--- a/src/mm-iface-modem-time.c
+++ b/src/mm-iface-modem-time.c
@@ -55,42 +55,34 @@
}
static void
-load_network_time_ready (MMIfaceModemTime *self,
- GAsyncResult *res,
+load_network_time_ready (MMIfaceModemTime *self,
+ GAsyncResult *res,
HandleGetNetworkTimeContext *ctx)
{
gchar *time_str;
GError *error = NULL;
- time_str = MM_IFACE_MODEM_TIME_GET_INTERFACE (self)->load_network_time_finish (self,
- res,
- &error);
+ time_str = MM_IFACE_MODEM_TIME_GET_INTERFACE (self)->load_network_time_finish (self, res, &error);
if (error)
g_dbus_method_invocation_take_error (ctx->invocation, error);
else
- mm_gdbus_modem_time_complete_get_network_time (ctx->skeleton,
- ctx->invocation,
- time_str);
+ mm_gdbus_modem_time_complete_get_network_time (ctx->skeleton, ctx->invocation, time_str);
g_free (time_str);
handle_get_network_time_context_free (ctx);
}
-static gboolean
-handle_get_network_time (MmGdbusModemTime *skeleton,
- GDBusMethodInvocation *invocation,
- MMIfaceModemTime *self)
+static void
+handle_get_network_time_auth_ready (MMBaseModem *self,
+ GAsyncResult *res,
+ HandleGetNetworkTimeContext *ctx)
{
- HandleGetNetworkTimeContext *ctx;
- MMModemState state;
+ MMModemState state;
+ GError *error = NULL;
- if (!MM_IFACE_MODEM_TIME_GET_INTERFACE (self)->load_network_time ||
- !MM_IFACE_MODEM_TIME_GET_INTERFACE (self)->load_network_time_finish) {
- g_dbus_method_invocation_return_error (invocation,
- MM_CORE_ERROR,
- MM_CORE_ERROR_UNSUPPORTED,
- "Cannot load network time: "
- "operation not supported");
- return TRUE;
+ if (!mm_base_modem_authorize_finish (self, res, &error)) {
+ g_dbus_method_invocation_take_error (ctx->invocation, error);
+ handle_get_network_time_context_free (ctx);
+ return;
}
state = MM_MODEM_STATE_UNKNOWN;
@@ -99,23 +91,49 @@
NULL);
/* If we're not yet registered, we cannot get the network time */
if (state < MM_MODEM_STATE_REGISTERED) {
- g_dbus_method_invocation_return_error (invocation,
+ g_dbus_method_invocation_return_error (ctx->invocation,
MM_CORE_ERROR,
MM_CORE_ERROR_WRONG_STATE,
"Cannot load network time: "
"not registered yet");
- return TRUE;
+ handle_get_network_time_context_free (ctx);
+ return;
}
+ if (!MM_IFACE_MODEM_TIME_GET_INTERFACE (self)->load_network_time ||
+ !MM_IFACE_MODEM_TIME_GET_INTERFACE (self)->load_network_time_finish) {
+ g_dbus_method_invocation_return_error (ctx->invocation,
+ MM_CORE_ERROR,
+ MM_CORE_ERROR_UNSUPPORTED,
+ "Cannot load network time: "
+ "operation not supported");
+ handle_get_network_time_context_free (ctx);
+ return;
+ }
+
+ MM_IFACE_MODEM_TIME_GET_INTERFACE (self)->load_network_time (
+ ctx->self,
+ (GAsyncReadyCallback)load_network_time_ready,
+ ctx);
+}
+
+static gboolean
+handle_get_network_time (MmGdbusModemTime *skeleton,
+ GDBusMethodInvocation *invocation,
+ MMIfaceModemTime *self)
+{
+ HandleGetNetworkTimeContext *ctx;
+
ctx = g_new (HandleGetNetworkTimeContext, 1);
ctx->invocation = g_object_ref (invocation);
ctx->skeleton = g_object_ref (skeleton);
ctx->self = g_object_ref (self);
- MM_IFACE_MODEM_TIME_GET_INTERFACE (self)->load_network_time (
- self,
- (GAsyncReadyCallback)load_network_time_ready,
- ctx);
+ mm_base_modem_authorize (MM_BASE_MODEM (self),
+ invocation,
+ MM_AUTHORIZATION_TIME,
+ (GAsyncReadyCallback)handle_get_network_time_auth_ready,
+ ctx);
return TRUE;
}
diff --git a/src/mm-iface-modem-voice.c b/src/mm-iface-modem-voice.c
index 1c7af9c..ff685aa 100644
--- a/src/mm-iface-modem-voice.c
+++ b/src/mm-iface-modem-voice.c
@@ -23,13 +23,9 @@
#include "mm-call-list.h"
#include "mm-log.h"
-#define SUPPORT_CHECKED_TAG "voice-support-checked-tag"
-#define SUPPORTED_TAG "voice-supported-tag"
#define CALL_LIST_POLLING_CONTEXT_TAG "voice-call-list-polling-context-tag"
#define IN_CALL_EVENT_CONTEXT_TAG "voice-in-call-event-context-tag"
-static GQuark support_checked_quark;
-static GQuark supported_quark;
static GQuark call_list_polling_context_quark;
static GQuark in_call_event_context_quark;
@@ -43,6 +39,109 @@
/*****************************************************************************/
+gboolean
+mm_iface_modem_voice_authorize_outgoing_call (MMIfaceModemVoice *self,
+ MMBaseCall *call,
+ GError **error)
+{
+ MmGdbusModemVoice *skeleton = NULL;
+ MMBaseSim *sim = NULL;
+ gboolean emergency_only = FALSE;
+ gboolean call_allowed = FALSE;
+ GError *inner_error = NULL;
+ guint i;
+ const gchar *number;
+
+ static const gchar *always_valid_emergency_numbers[] = { "112", "911" };
+ static const gchar *no_sim_valid_emergency_numbers[] = { "000", "08", "110", "999", "118", "119" };
+
+ g_assert (mm_base_call_get_direction (call) == MM_CALL_DIRECTION_OUTGOING);
+ number = mm_base_call_get_number (call);
+ g_assert (number);
+
+ g_object_get (self,
+ MM_IFACE_MODEM_VOICE_DBUS_SKELETON, &skeleton,
+ NULL);
+
+ if (!skeleton) {
+ g_set_error (&inner_error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
+ "voice operations unsupported");
+ goto out;
+ }
+
+ g_object_get (skeleton,
+ "emergency-only", &emergency_only,
+ NULL);
+
+ /* Identification of emergency numbers. 3GPP TS 22.101
+ *
+ * a) 112 and 911 shall always be available.
+ * b) Any emergency call number stored on a SIM/USIM when the SIM/USIM is
+ * present.
+ * c) 000, 08, 110, 999, 118 and 119 when a SIM/USIM is not present.
+ * d) Additional emergency call numbers that may have been downloaded by
+ * the serving network when the SIM/USIM is present.
+ *
+ * In ModemManager we're not flagging any call as being "emergency" or
+ * "normal", but we can right away limit non-emergency calls if we're in
+ * "emergency-only" mode.
+ */
+
+ /* If we're not in emergency mode, the call (emergency or normal) is always allowed */
+ if (!emergency_only) {
+ mm_dbg ("voice call to %s allowed", number);
+ call_allowed = TRUE;
+ goto out;
+ }
+
+ for (i = 0; i < G_N_ELEMENTS (always_valid_emergency_numbers); i++) {
+ if (g_strcmp0 (number, always_valid_emergency_numbers[i]) == 0) {
+ mm_dbg ("voice call to %s allowed: emergency call number always valid", number);
+ call_allowed = TRUE;
+ goto out;
+ }
+ }
+
+ /* Check if we have a SIM */
+ g_object_get (self,
+ MM_IFACE_MODEM_SIM, &sim,
+ NULL);
+ if (!sim) {
+ /* If no SIM available, some additional numbers may be valid emergency numbers */
+ for (i = 0; i < G_N_ELEMENTS (no_sim_valid_emergency_numbers); i++) {
+ if (g_strcmp0 (number, no_sim_valid_emergency_numbers[i]) == 0) {
+ mm_dbg ("voice call to %s allowed: emergency call number valid when no SIM", number);
+ call_allowed = TRUE;
+ goto out;
+ }
+ }
+
+ mm_dbg ("voice call to %s NOT allowed: not a valid emergency call number when no SIM", number);
+ goto out;
+ }
+
+ /* Check if the number is programmed in EF_ECC */
+ if (mm_base_sim_is_emergency_number (sim, number)) {
+ mm_dbg ("voice call to %s allowed: emergency call number programmed in the SIM", number);
+ call_allowed = TRUE;
+ } else
+ mm_dbg ("voice call to %s NOT allowed: not a valid emergency call number programmed in the SIM", number);
+
+ out:
+
+ if (inner_error)
+ g_propagate_error (error, inner_error);
+ else if (!call_allowed)
+ g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_UNAUTHORIZED,
+ "only emergency calls allowed");
+
+ g_clear_object (&skeleton);
+ g_clear_object (&sim);
+ return call_allowed;
+}
+
+/*****************************************************************************/
+
/* new calls will inherit audio settings if the modem is already in-call state */
static void update_audio_settings_in_call (MMIfaceModemVoice *self,
MMBaseCall *call);
@@ -355,6 +454,11 @@
for (l = ctx.call_info_list; l; l = g_list_next (l)) {
MMCallInfo *call_info = (MMCallInfo *)(l->data);
+ /* Ignore unknown terminated calls, because these be due to an already
+ * processed event. */
+ if (call_info->state == MM_CALL_STATE_TERMINATED)
+ continue;
+
if (call_info->direction == MM_CALL_DIRECTION_OUTGOING) {
mm_warn ("unexpected outgoing call to number '%s' reported in call list: state %s",
call_info->number ? call_info->number : "n/a",
@@ -464,7 +568,6 @@
GAsyncResult *res,
HandleDeleteContext *ctx)
{
- MMModemState modem_state = MM_MODEM_STATE_UNKNOWN;
MMCallList *list = NULL;
GError *error = NULL;
@@ -475,19 +578,6 @@
}
g_object_get (self,
- MM_IFACE_MODEM_STATE, &modem_state,
- NULL);
-
- if (modem_state < MM_MODEM_STATE_ENABLED) {
- g_dbus_method_invocation_return_error (ctx->invocation,
- MM_CORE_ERROR,
- MM_CORE_ERROR_WRONG_STATE,
- "Cannot delete call: device not yet enabled");
- handle_delete_context_free (ctx);
- return;
- }
-
- g_object_get (self,
MM_IFACE_MODEM_VOICE_CALL_LIST, &list,
NULL);
if (!list) {
@@ -554,7 +644,6 @@
GAsyncResult *res,
HandleCreateContext *ctx)
{
- MMModemState modem_state = MM_MODEM_STATE_UNKNOWN;
MMCallList *list = NULL;
GError *error = NULL;
MMCallProperties *properties;
@@ -566,19 +655,6 @@
return;
}
- g_object_get (self,
- MM_IFACE_MODEM_STATE, &modem_state,
- NULL);
-
- if (modem_state < MM_MODEM_STATE_ENABLED) {
- g_dbus_method_invocation_return_error (ctx->invocation,
- MM_CORE_ERROR,
- MM_CORE_ERROR_WRONG_STATE,
- "Cannot create CALL: device not yet enabled");
- handle_create_context_free (ctx);
- return;
- }
-
/* Parse input properties */
properties = mm_call_properties_new_from_dictionary (ctx->dictionary, &error);
if (!properties) {
@@ -656,21 +732,6 @@
{
GStrv paths;
MMCallList *list = NULL;
- MMModemState modem_state;
-
- modem_state = MM_MODEM_STATE_UNKNOWN;
- g_object_get (self,
- MM_IFACE_MODEM_STATE, &modem_state,
- NULL);
-
- if (modem_state < MM_MODEM_STATE_ENABLED) {
- g_dbus_method_invocation_return_error (invocation,
- MM_CORE_ERROR,
- MM_CORE_ERROR_WRONG_STATE,
- "Cannot list CALL messages: "
- "device not yet enabled");
- return TRUE;
- }
g_object_get (self,
MM_IFACE_MODEM_VOICE_CALL_LIST, &list,
@@ -762,9 +823,8 @@
GAsyncResult *res,
HandleHoldAndAcceptContext *ctx)
{
- MMModemState modem_state = MM_MODEM_STATE_UNKNOWN;
- GError *error = NULL;
- MMCallList *list = NULL;
+ GError *error = NULL;
+ MMCallList *list = NULL;
if (!mm_base_modem_authorize_finish (self, res, &error)) {
g_dbus_method_invocation_take_error (ctx->invocation, error);
@@ -772,19 +832,6 @@
return;
}
- g_object_get (self,
- MM_IFACE_MODEM_STATE, &modem_state,
- NULL);
-
- if (modem_state < MM_MODEM_STATE_ENABLED) {
- g_dbus_method_invocation_return_error (ctx->invocation,
- MM_CORE_ERROR,
- MM_CORE_ERROR_WRONG_STATE,
- "Cannot hold and accept: device not yet enabled");
- handle_hold_and_accept_context_free (ctx);
- return;
- }
-
if (!MM_IFACE_MODEM_VOICE_GET_INTERFACE (self)->hold_and_accept ||
!MM_IFACE_MODEM_VOICE_GET_INTERFACE (self)->hold_and_accept_finish) {
g_dbus_method_invocation_return_error (ctx->invocation,
@@ -904,9 +951,8 @@
GAsyncResult *res,
HandleHangupAndAcceptContext *ctx)
{
- MMModemState modem_state = MM_MODEM_STATE_UNKNOWN;
- GError *error = NULL;
- MMCallList *list = NULL;
+ GError *error = NULL;
+ MMCallList *list = NULL;
if (!mm_base_modem_authorize_finish (self, res, &error)) {
g_dbus_method_invocation_take_error (ctx->invocation, error);
@@ -914,19 +960,6 @@
return;
}
- g_object_get (self,
- MM_IFACE_MODEM_STATE, &modem_state,
- NULL);
-
- if (modem_state < MM_MODEM_STATE_ENABLED) {
- g_dbus_method_invocation_return_error (ctx->invocation,
- MM_CORE_ERROR,
- MM_CORE_ERROR_WRONG_STATE,
- "Cannot hangup and accept: device not yet enabled");
- handle_hangup_and_accept_context_free (ctx);
- return;
- }
-
if (!MM_IFACE_MODEM_VOICE_GET_INTERFACE (self)->hangup_and_accept ||
!MM_IFACE_MODEM_VOICE_GET_INTERFACE (self)->hangup_and_accept_finish) {
g_dbus_method_invocation_return_error (ctx->invocation,
@@ -1059,9 +1092,8 @@
GAsyncResult *res,
HandleHangupAllContext *ctx)
{
- MMModemState modem_state = MM_MODEM_STATE_UNKNOWN;
- GError *error = NULL;
- MMCallList *list = NULL;
+ GError *error = NULL;
+ MMCallList *list = NULL;
if (!mm_base_modem_authorize_finish (self, res, &error)) {
g_dbus_method_invocation_take_error (ctx->invocation, error);
@@ -1069,19 +1101,6 @@
return;
}
- g_object_get (self,
- MM_IFACE_MODEM_STATE, &modem_state,
- NULL);
-
- if (modem_state < MM_MODEM_STATE_ENABLED) {
- g_dbus_method_invocation_return_error (ctx->invocation,
- MM_CORE_ERROR,
- MM_CORE_ERROR_WRONG_STATE,
- "Cannot hangup all: device not yet enabled");
- handle_hangup_all_context_free (ctx);
- return;
- }
-
if (!MM_IFACE_MODEM_VOICE_GET_INTERFACE (self)->hangup_all ||
!MM_IFACE_MODEM_VOICE_GET_INTERFACE (self)->hangup_all_finish) {
g_dbus_method_invocation_return_error (ctx->invocation,
@@ -1190,9 +1209,8 @@
GAsyncResult *res,
HandleTransferContext *ctx)
{
- MMModemState modem_state = MM_MODEM_STATE_UNKNOWN;
- GError *error = NULL;
- MMCallList *list = NULL;
+ GError *error = NULL;
+ MMCallList *list = NULL;
if (!mm_base_modem_authorize_finish (self, res, &error)) {
g_dbus_method_invocation_take_error (ctx->invocation, error);
@@ -1200,19 +1218,6 @@
return;
}
- g_object_get (self,
- MM_IFACE_MODEM_STATE, &modem_state,
- NULL);
-
- if (modem_state < MM_MODEM_STATE_ENABLED) {
- g_dbus_method_invocation_return_error (ctx->invocation,
- MM_CORE_ERROR,
- MM_CORE_ERROR_WRONG_STATE,
- "Cannot transfer: device not yet enabled");
- handle_transfer_context_free (ctx);
- return;
- }
-
if (!MM_IFACE_MODEM_VOICE_GET_INTERFACE (self)->transfer ||
!MM_IFACE_MODEM_VOICE_GET_INTERFACE (self)->transfer_finish) {
g_dbus_method_invocation_return_error (ctx->invocation,
@@ -1302,8 +1307,7 @@
GAsyncResult *res,
HandleCallWaitingSetupContext *ctx)
{
- MMModemState modem_state = MM_MODEM_STATE_UNKNOWN;
- GError *error = NULL;
+ GError *error = NULL;
if (!mm_base_modem_authorize_finish (self, res, &error)) {
g_dbus_method_invocation_take_error (ctx->invocation, error);
@@ -1311,19 +1315,6 @@
return;
}
- g_object_get (self,
- MM_IFACE_MODEM_STATE, &modem_state,
- NULL);
-
- if (modem_state < MM_MODEM_STATE_ENABLED) {
- g_dbus_method_invocation_return_error (ctx->invocation,
- MM_CORE_ERROR,
- MM_CORE_ERROR_WRONG_STATE,
- "Cannot setup call waiting: device not yet enabled");
- handle_call_waiting_setup_context_free (ctx);
- return;
- }
-
if (!MM_IFACE_MODEM_VOICE_GET_INTERFACE (self)->call_waiting_setup ||
!MM_IFACE_MODEM_VOICE_GET_INTERFACE (self)->call_waiting_setup_finish) {
g_dbus_method_invocation_return_error (ctx->invocation,
@@ -1403,8 +1394,7 @@
GAsyncResult *res,
HandleCallWaitingQueryContext *ctx)
{
- MMModemState modem_state = MM_MODEM_STATE_UNKNOWN;
- GError *error = NULL;
+ GError *error = NULL;
if (!mm_base_modem_authorize_finish (self, res, &error)) {
g_dbus_method_invocation_take_error (ctx->invocation, error);
@@ -1412,19 +1402,6 @@
return;
}
- g_object_get (self,
- MM_IFACE_MODEM_STATE, &modem_state,
- NULL);
-
- if (modem_state < MM_MODEM_STATE_ENABLED) {
- g_dbus_method_invocation_return_error (ctx->invocation,
- MM_CORE_ERROR,
- MM_CORE_ERROR_WRONG_STATE,
- "Cannot query call waiting: device not yet enabled");
- handle_call_waiting_query_context_free (ctx);
- return;
- }
-
if (!MM_IFACE_MODEM_VOICE_GET_INTERFACE (self)->call_waiting_query ||
!MM_IFACE_MODEM_VOICE_GET_INTERFACE (self)->call_waiting_query_finish) {
g_dbus_method_invocation_return_error (ctx->invocation,
@@ -2165,7 +2142,7 @@
if (!in_call_cleanup_finish (self, res, &error)) {
/* ignore cancelled operations */
- if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED) && !g_error_matches (error, MM_CORE_ERROR, MM_CORE_ERROR_CANCELLED))
+ if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
mm_warn ("Cannot cleanup in-call modem state: %s", error->message);
g_clear_error (&error);
} else {
@@ -2189,7 +2166,7 @@
if (!in_call_setup_finish (self, res, &ctx->audio_port, &ctx->audio_format, &error)) {
/* ignore cancelled operations */
- if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED) && !g_error_matches (error, MM_CORE_ERROR, MM_CORE_ERROR_CANCELLED))
+ if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
mm_warn ("Cannot setup in-call modem state: %s", error->message);
g_clear_error (&error);
} else {
@@ -2600,11 +2577,6 @@
ctx->step++;
case DISABLING_STEP_LAST:
- /* Clear CALL list */
- g_object_set (self,
- MM_IFACE_MODEM_VOICE_CALL_LIST, NULL,
- NULL);
-
/* We are done without errors! */
g_task_return_boolean (task, TRUE);
g_object_unref (task);
@@ -2734,55 +2706,12 @@
ctx = g_task_get_task_data (task);
switch (ctx->step) {
- case ENABLING_STEP_FIRST: {
- MMCallList *list;
-
- list = mm_call_list_new (MM_BASE_MODEM (self));
- g_object_set (self,
- MM_IFACE_MODEM_VOICE_CALL_LIST, list,
- NULL);
-
- /* Connect to list's signals */
- g_signal_connect (list,
- MM_CALL_ADDED,
- G_CALLBACK (call_added),
- ctx->skeleton);
- g_signal_connect (list,
- MM_CALL_DELETED,
- G_CALLBACK (call_deleted),
- ctx->skeleton);
-
- /* Setup monitoring for in-call event handling */
- g_signal_connect (list,
- MM_CALL_ADDED,
- G_CALLBACK (setup_in_call_event_handling),
- self);
-
- /* Unless we're told not to, setup call list polling logic */
- if (MM_IFACE_MODEM_VOICE_GET_INTERFACE (self)->load_call_list &&
- MM_IFACE_MODEM_VOICE_GET_INTERFACE (self)->load_call_list_finish) {
- gboolean periodic_call_list_check_disabled = FALSE;
-
- g_object_get (self,
- MM_IFACE_MODEM_VOICE_PERIODIC_CALL_LIST_CHECK_DISABLED, &periodic_call_list_check_disabled,
- NULL);
- if (!periodic_call_list_check_disabled) {
- mm_dbg ("periodic call list polling will be used if supported");
- g_signal_connect (list,
- MM_CALL_ADDED,
- G_CALLBACK (setup_call_list_polling),
- self);
- }
- }
-
- g_object_unref (list);
-
+ case ENABLING_STEP_FIRST:
/* Fall down to next step */
ctx->step++;
- }
case ENABLING_STEP_SETUP_UNSOLICITED_EVENTS:
- /* Allow setting up unsolicited events */
+ /* Allow setting up unsolicited events to get notified of incoming calls */
if (MM_IFACE_MODEM_VOICE_GET_INTERFACE (self)->setup_unsolicited_events &&
MM_IFACE_MODEM_VOICE_GET_INTERFACE (self)->setup_unsolicited_events_finish) {
MM_IFACE_MODEM_VOICE_GET_INTERFACE (self)->setup_unsolicited_events (
@@ -2795,7 +2724,7 @@
ctx->step++;
case ENABLING_STEP_ENABLE_UNSOLICITED_EVENTS:
- /* Allow setting up unsolicited events */
+ /* Allow setting up unsolicited events to get notified of incoming calls */
if (MM_IFACE_MODEM_VOICE_GET_INTERFACE (self)->enable_unsolicited_events &&
MM_IFACE_MODEM_VOICE_GET_INTERFACE (self)->enable_unsolicited_events_finish) {
MM_IFACE_MODEM_VOICE_GET_INTERFACE (self)->enable_unsolicited_events (
@@ -2855,7 +2784,7 @@
typedef enum {
INITIALIZATION_STEP_FIRST,
INITIALIZATION_STEP_CHECK_SUPPORT,
- INITIALIZATION_STEP_FAIL_IF_UNSUPPORTED,
+ INITIALIZATION_STEP_SETUP_CALL_LIST,
INITIALIZATION_STEP_LAST
} InitializationStep;
@@ -2879,19 +2808,12 @@
InitializationContext *ctx;
GError *error = NULL;
- if (!MM_IFACE_MODEM_VOICE_GET_INTERFACE (self)->check_support_finish (self,
- res,
- &error)) {
- if (error) {
- /* This error shouldn't be treated as critical */
- mm_dbg ("Voice support check failed: '%s'", error->message);
- g_error_free (error);
- }
- } else {
- /* Voice is supported! */
- g_object_set_qdata (G_OBJECT (self),
- supported_quark,
- GUINT_TO_POINTER (TRUE));
+ if (!MM_IFACE_MODEM_VOICE_GET_INTERFACE (self)->check_support_finish (self, res, &error)) {
+ mm_dbg ("Voice support check failed: '%s'", error->message);
+ g_error_free (error);
+ g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_UNSUPPORTED, "Voice not supported");
+ g_object_unref (task);
+ return;
}
/* Go on to next step */
@@ -2917,56 +2839,83 @@
switch (ctx->step) {
case INITIALIZATION_STEP_FIRST:
- /* Setup quarks if we didn't do it before */
- if (G_UNLIKELY (!support_checked_quark))
- support_checked_quark = (g_quark_from_static_string (
- SUPPORT_CHECKED_TAG));
- if (G_UNLIKELY (!supported_quark))
- supported_quark = (g_quark_from_static_string (
- SUPPORTED_TAG));
-
/* Fall down to next step */
ctx->step++;
case INITIALIZATION_STEP_CHECK_SUPPORT:
- if (!GPOINTER_TO_UINT (g_object_get_qdata (G_OBJECT (self),
- support_checked_quark))) {
- /* Set the checked flag so that we don't run it again */
- g_object_set_qdata (G_OBJECT (self),
- support_checked_quark,
- GUINT_TO_POINTER (TRUE));
- /* Initially, assume we don't support it */
- g_object_set_qdata (G_OBJECT (self),
- supported_quark,
- GUINT_TO_POINTER (FALSE));
-
- if (MM_IFACE_MODEM_VOICE_GET_INTERFACE (self)->check_support &&
- MM_IFACE_MODEM_VOICE_GET_INTERFACE (self)->check_support_finish) {
- MM_IFACE_MODEM_VOICE_GET_INTERFACE (self)->check_support (
- self,
- (GAsyncReadyCallback)check_support_ready,
- task);
- return;
- }
-
- /* If there is no implementation to check support, assume we DON'T
- * support it. */
- }
- /* Fall down to next step */
- ctx->step++;
-
- case INITIALIZATION_STEP_FAIL_IF_UNSUPPORTED:
- if (!GPOINTER_TO_UINT (g_object_get_qdata (G_OBJECT (self),
- supported_quark))) {
- g_task_return_new_error (task,
- MM_CORE_ERROR,
- MM_CORE_ERROR_UNSUPPORTED,
- "Voice not supported");
- g_object_unref (task);
+ /* Always check voice support when we run initialization, because
+ * the support may be different before and after SIM-PIN unlock. */
+ if (MM_IFACE_MODEM_VOICE_GET_INTERFACE (self)->check_support &&
+ MM_IFACE_MODEM_VOICE_GET_INTERFACE (self)->check_support_finish) {
+ MM_IFACE_MODEM_VOICE_GET_INTERFACE (self)->check_support (
+ self,
+ (GAsyncReadyCallback)check_support_ready,
+ task);
return;
}
+
+ g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_UNSUPPORTED, "Voice not supported");
+ g_object_unref (task);
+ return;
+
+ case INITIALIZATION_STEP_SETUP_CALL_LIST: {
+ MMCallList *list = NULL;
+
+ g_object_get (self,
+ MM_IFACE_MODEM_VOICE_CALL_LIST, &list,
+ NULL);
+
+ /* Create a new call list if not already available (this initialization
+ * may be called multiple times) */
+ if (!list) {
+ list = mm_call_list_new (MM_BASE_MODEM (self));
+ g_object_set (self,
+ MM_IFACE_MODEM_VOICE_CALL_LIST, list,
+ NULL);
+
+ /* Connect to list's signals */
+ g_signal_connect (list,
+ MM_CALL_ADDED,
+ G_CALLBACK (call_added),
+ ctx->skeleton);
+ g_signal_connect (list,
+ MM_CALL_DELETED,
+ G_CALLBACK (call_deleted),
+ ctx->skeleton);
+
+ /* Setup monitoring for in-call event handling */
+ g_signal_connect (list,
+ MM_CALL_ADDED,
+ G_CALLBACK (setup_in_call_event_handling),
+ self);
+ }
+
+ /* Unless we're told not to, setup call list polling logic */
+ if (MM_IFACE_MODEM_VOICE_GET_INTERFACE (self)->load_call_list &&
+ MM_IFACE_MODEM_VOICE_GET_INTERFACE (self)->load_call_list_finish) {
+ gboolean periodic_call_list_check_disabled = FALSE;
+
+ /* Cleanup any previously configured handler, before checking if we need to
+ * add a new one, because the PERIODIC_CALL_LIST_CHECK_DISABLED flag may
+ * change before and after SIM-PIN unlock */
+ g_signal_handlers_disconnect_by_func (list, G_CALLBACK (setup_call_list_polling), self);
+
+ g_object_get (self,
+ MM_IFACE_MODEM_VOICE_PERIODIC_CALL_LIST_CHECK_DISABLED, &periodic_call_list_check_disabled,
+ NULL);
+ if (!periodic_call_list_check_disabled) {
+ mm_dbg ("periodic call list polling will be used if supported");
+ g_signal_connect (list,
+ MM_CALL_ADDED,
+ G_CALLBACK (setup_call_list_polling),
+ self);
+ }
+ }
+ g_object_unref (list);
+
/* Fall down to next step */
ctx->step++;
+ }
case INITIALIZATION_STEP_LAST:
/* Setup all method handlers */
@@ -3002,6 +2951,20 @@
return g_task_propagate_boolean (G_TASK (res), error);
}
+static gboolean
+modem_state_to_emergency_only (GBinding *binding,
+ const GValue *from_value,
+ GValue *to_value)
+{
+ MMModemState state;
+
+ /* If the modem is REGISTERED, we allow any kind of call, otherwise
+ * only emergency calls */
+ state = g_value_get_enum (from_value);
+ g_value_set_boolean (to_value, (state < MM_MODEM_STATE_REGISTERED));
+ return TRUE;
+}
+
void
mm_iface_modem_voice_initialize (MMIfaceModemVoice *self,
GCancellable *cancellable,
@@ -3022,6 +2985,12 @@
g_object_set (self,
MM_IFACE_MODEM_VOICE_DBUS_SKELETON, skeleton,
NULL);
+
+ g_object_bind_property_full (self, MM_IFACE_MODEM_STATE,
+ skeleton, "emergency-only",
+ G_BINDING_DEFAULT | G_BINDING_SYNC_CREATE,
+ (GBindingTransformFunc) modem_state_to_emergency_only,
+ NULL, NULL, NULL);
}
/* Perform async initialization here */
diff --git a/src/mm-iface-modem-voice.h b/src/mm-iface-modem-voice.h
index 7f793dc..2a9e52e 100644
--- a/src/mm-iface-modem-voice.h
+++ b/src/mm-iface-modem-voice.h
@@ -243,6 +243,11 @@
guint index,
const gchar *dtmf);
+/* Authorize outgoing call based on modem status and ECC list */
+gboolean mm_iface_modem_voice_authorize_outgoing_call (MMIfaceModemVoice *self,
+ MMBaseCall *call,
+ GError **error);
+
/* Join/Leave multiparty calls
*
* These actions are provided in the Call API, but implemented in the
diff --git a/src/mm-iface-modem.c b/src/mm-iface-modem.c
index c284524..4247a7e 100644
--- a/src/mm-iface-modem.c
+++ b/src/mm-iface-modem.c
@@ -315,8 +315,8 @@
/* For several kinds of errors, just return them directly */
if (error->domain == MM_SERIAL_ERROR ||
g_error_matches (error,
- MM_CORE_ERROR,
- MM_CORE_ERROR_CANCELLED) ||
+ G_IO_ERROR,
+ G_IO_ERROR_CANCELLED) ||
g_error_matches (error,
MM_MOBILE_EQUIPMENT_ERROR,
MM_MOBILE_EQUIPMENT_ERROR_SIM_NOT_INSERTED) ||
@@ -1142,18 +1142,24 @@
typedef struct {
gboolean enabled;
- guint interval;
- guint initial_retries;
guint timeout_source;
+ /* We first attempt an initial loading, and once it's done we
+ * setup polling */
+ guint initial_retries;
+ gboolean initial_check_done;
+
/* Values polled in this iteration */
guint signal_quality;
MMModemAccessTechnology access_technologies;
guint access_technologies_mask;
- /* If both these are unset we'll automatically stop polling */
+ /* If both signal and access tech polling are either unsupported
+ * or disabled, we'll automatically stop polling */
gboolean signal_quality_polling_supported;
+ gboolean signal_quality_polling_disabled;
gboolean access_technology_polling_supported;
+ gboolean access_technology_polling_disabled;
/* Steps triggered when polling active */
SignalCheckStep running_step;
@@ -1194,6 +1200,12 @@
ctx->signal_quality_polling_supported = (MM_IFACE_MODEM_GET_INTERFACE (self)->load_signal_quality &&
MM_IFACE_MODEM_GET_INTERFACE (self)->load_signal_quality_finish);
+ /* Get plugin-specific setup for the polling logic */
+ g_object_get (self,
+ MM_IFACE_MODEM_PERIODIC_SIGNAL_CHECK_DISABLED, &ctx->signal_quality_polling_disabled,
+ MM_IFACE_MODEM_PERIODIC_ACCESS_TECH_CHECK_DISABLED, &ctx->access_technology_polling_disabled,
+ NULL);
+
g_object_set_qdata_full (G_OBJECT (self), signal_check_context_quark,
ctx, (GDestroyNotify) signal_check_context_free);
}
@@ -1226,7 +1238,9 @@
if (g_error_matches (error, MM_CORE_ERROR, MM_CORE_ERROR_UNSUPPORTED)) {
mm_dbg ("Polling to refresh access technologies is unsupported");
ctx->access_technology_polling_supported = FALSE;
- } else
+ }
+ /* Ignore logging any message if the error is in 'in-progress' */
+ else if (!g_error_matches (error, MM_CORE_ERROR, MM_CORE_ERROR_IN_PROGRESS))
mm_dbg ("Couldn't refresh access technologies: '%s'", error->message);
g_error_free (error);
}
@@ -1254,7 +1268,9 @@
if (g_error_matches (error, MM_CORE_ERROR, MM_CORE_ERROR_UNSUPPORTED)) {
mm_dbg ("Polling to refresh signal quality is unsupported");
ctx->signal_quality_polling_supported = FALSE;
- } else
+ }
+ /* Ignore logging any message if the error is in 'in-progress' */
+ else if (!g_error_matches (error, MM_CORE_ERROR, MM_CORE_ERROR_IN_PROGRESS))
mm_dbg ("Couldn't refresh signal quality: '%s'", error->message);
g_error_free (error);
}
@@ -1270,7 +1286,6 @@
static void
peridic_signal_check_step (MMIfaceModem *self)
{
- gboolean periodic_signal_check_disabled = FALSE;
SignalCheckContext *ctx;
ctx = get_signal_check_context (self);
@@ -1284,7 +1299,8 @@
ctx->running_step++;
case SIGNAL_CHECK_STEP_SIGNAL_QUALITY:
- if (ctx->enabled && ctx->signal_quality_polling_supported) {
+ if (ctx->enabled && ctx->signal_quality_polling_supported &&
+ (!ctx->initial_check_done || !ctx->signal_quality_polling_disabled)) {
MM_IFACE_MODEM_GET_INTERFACE (self)->load_signal_quality (
self, (GAsyncReadyCallback)signal_quality_check_ready, NULL);
return;
@@ -1293,7 +1309,8 @@
ctx->running_step++;
case SIGNAL_CHECK_STEP_ACCESS_TECHNOLOGIES:
- if (ctx->enabled && ctx->access_technology_polling_supported) {
+ if (ctx->enabled && ctx->access_technology_polling_supported &&
+ (!ctx->initial_check_done || !ctx->access_technology_polling_disabled)) {
MM_IFACE_MODEM_GET_INTERFACE (self)->load_access_technologies (
self, (GAsyncReadyCallback)access_technologies_check_ready, NULL);
return;
@@ -1308,7 +1325,7 @@
/* If we have been disabled while we were running the steps, we don't
* do anything else. */
if (!ctx->enabled) {
- mm_dbg ("Periodic signal checks not rescheduled: disabled");
+ mm_dbg ("Periodic signal quality and access technology checks not rescheduled: disabled");
return;
}
@@ -1317,45 +1334,38 @@
* quality and access technology values. As soon as we get them, OR if
* we made too many retries at a high frequency, we fallback to the
* slower polling. */
- if (ctx->interval == SIGNAL_CHECK_INITIAL_TIMEOUT_SEC) {
+ if (!ctx->initial_check_done) {
gboolean signal_quality_ready;
gboolean access_technology_ready;
- gboolean initial_check_done;
/* Signal quality is ready if unsupported or if we got a valid
* value reported */
signal_quality_ready = (!ctx->signal_quality_polling_supported || (ctx->signal_quality != 0));
+
/* Access technology is ready if unsupported or if we got a valid
* value reported */
access_technology_ready = (!ctx->access_technology_polling_supported ||
((ctx->access_technologies & ctx->access_technologies_mask) != MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN));
- initial_check_done = ((signal_quality_ready && access_technology_ready) ||
- (--ctx->initial_retries == 0));
- if (initial_check_done) {
- /* After the initial check is done, check if periodic signal
- * check is disabled. */
- g_object_get (self,
- MM_IFACE_MODEM_PERIODIC_SIGNAL_CHECK_DISABLED,
- &periodic_signal_check_disabled,
- NULL);
- ctx->interval = SIGNAL_CHECK_TIMEOUT_SEC;
- }
+ ctx->initial_check_done = ((signal_quality_ready && access_technology_ready) || (--ctx->initial_retries == 0));
}
- /* If both tasks are unsupported, implicitly disable. Do NOT clear the
- * values, because if we're told they are unsupported it may be that
- * they're really updated via unsolicited messages. */
- if (!ctx->access_technology_polling_supported &&
- (!ctx->signal_quality_polling_supported || periodic_signal_check_disabled)) {
- mm_dbg ("Periodic signal and access technologies checks not supported");
+ /* After running the initial check, if both signal quality and access tech
+ * loading are either disabled or unsupported, we'll stop polling completely,
+ * because they may be loaded asynchronously by unsolicited messages */
+ if (ctx->initial_check_done &&
+ (!ctx->signal_quality_polling_supported || ctx->signal_quality_polling_disabled) &&
+ (!ctx->access_technology_polling_supported || ctx->access_technology_polling_disabled)) {
+ mm_dbg ("Periodic signal quality and access technology checks not rescheduled: unneeded or unsupported");
periodic_signal_check_disable (self, FALSE);
return;
}
- mm_dbg ("Periodic signal quality checks scheduled in %ds", ctx->interval);
+ mm_dbg ("Periodic signal quality and access technology checks scheduled");
g_assert (!ctx->timeout_source);
- ctx->timeout_source = g_timeout_add_seconds (ctx->interval, (GSourceFunc) periodic_signal_check_cb, self);
+ ctx->timeout_source = g_timeout_add_seconds (ctx->initial_check_done ? SIGNAL_CHECK_TIMEOUT_SEC : SIGNAL_CHECK_INITIAL_TIMEOUT_SEC,
+ (GSourceFunc) periodic_signal_check_cb,
+ self);
return;
}
}
@@ -1410,8 +1420,8 @@
/* Reset refresh rate and initial retries when we're asked to refresh signal
* so that we poll at a higher frequency */
- ctx->interval = SIGNAL_CHECK_INITIAL_TIMEOUT_SEC;
- ctx->initial_retries = SIGNAL_CHECK_INITIAL_RETRIES;
+ ctx->initial_retries = SIGNAL_CHECK_INITIAL_RETRIES;
+ ctx->initial_check_done = FALSE;
/* Start sequence */
periodic_signal_check_cb (self);
@@ -1465,7 +1475,7 @@
ctx->enabled = TRUE;
}
- /* And refresh, which will trigger the first check at high frequency*/
+ /* And refresh, which will trigger the first check at high frequency */
mm_iface_modem_refresh_signal (self);
}
@@ -3316,8 +3326,8 @@
* state. */
if (error->domain == MM_SERIAL_ERROR ||
g_error_matches (error,
- MM_CORE_ERROR,
- MM_CORE_ERROR_CANCELLED)) {
+ G_IO_ERROR,
+ G_IO_ERROR_CANCELLED)) {
ctx->saved_error = error;
ctx->step = UPDATE_LOCK_INFO_CONTEXT_STEP_LAST;
update_lock_info_context_step (task);
@@ -5691,10 +5701,18 @@
g_object_interface_install_property
(g_iface,
g_param_spec_boolean (MM_IFACE_MODEM_PERIODIC_SIGNAL_CHECK_DISABLED,
- "Periodic signal check disabled",
- "Whether periodic signal check is disabled.",
+ "Periodic signal quality check disabled",
+ "Whether periodic signal quality check is disabled.",
FALSE,
- G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+ G_PARAM_READWRITE));
+
+ g_object_interface_install_property
+ (g_iface,
+ g_param_spec_boolean (MM_IFACE_MODEM_PERIODIC_ACCESS_TECH_CHECK_DISABLED,
+ "Periodic access technology check disabled",
+ "Whether periodic access technology check is disabled.",
+ FALSE,
+ G_PARAM_READWRITE));
g_object_interface_install_property
(g_iface,
diff --git a/src/mm-iface-modem.h b/src/mm-iface-modem.h
index 9df3903..c4aba7a 100644
--- a/src/mm-iface-modem.h
+++ b/src/mm-iface-modem.h
@@ -38,8 +38,9 @@
#define MM_IFACE_MODEM_BEARER_LIST "iface-modem-bearer-list"
#define MM_IFACE_MODEM_SIM_HOT_SWAP_SUPPORTED "iface-modem-sim-hot-swap-supported"
#define MM_IFACE_MODEM_SIM_HOT_SWAP_CONFIGURED "iface-modem-sim-hot-swap-configured"
-#define MM_IFACE_MODEM_PERIODIC_SIGNAL_CHECK_DISABLED "iface-modem-periodic-signal-check-disabled"
#define MM_IFACE_MODEM_CARRIER_CONFIG_MAPPING "iface-modem-carrier-config-mapping"
+#define MM_IFACE_MODEM_PERIODIC_SIGNAL_CHECK_DISABLED "iface-modem-periodic-signal-check-disabled"
+#define MM_IFACE_MODEM_PERIODIC_ACCESS_TECH_CHECK_DISABLED "iface-modem-periodic-access-tech-check-disabled"
typedef struct _MMIfaceModem MMIfaceModem;
diff --git a/src/mm-modem-helpers-qmi.c b/src/mm-modem-helpers-qmi.c
index ef6e048..c8f5e0b 100644
--- a/src/mm-modem-helpers-qmi.c
+++ b/src/mm-modem-helpers-qmi.c
@@ -20,6 +20,7 @@
#include <mm-errors-types.h>
#include "mm-modem-helpers-qmi.h"
+#include "mm-modem-helpers.h"
#include "mm-enums-types.h"
#include "mm-log.h"
@@ -1588,6 +1589,8 @@
}
}
+/*****************************************************************************/
+
gboolean
mm_error_from_qmi_loc_indication_status (QmiLocIndicationStatus status,
GError **error)
@@ -1618,3 +1621,121 @@
return FALSE;
}
}
+
+/*****************************************************************************/
+/* Convert between firmware unique ID (string) and QMI unique ID (16 bytes)
+ *
+ * The unique ID coming in the QMI message is a fixed-size 16 byte array, and its
+ * format really depends on the manufacturer. But, if the manufacturer is nice enough
+ * to use ASCII for this field, just use it ourselves as well, no need to obfuscate
+ * the information we expose in our interfaces.
+ *
+ * We also need to do the conversion in the other way around, because when
+ * selecting a new image to run we need to provide the QMI unique ID.
+ */
+
+#define EXPECTED_QMI_UNIQUE_ID_LENGTH 16
+
+gchar *
+mm_qmi_unique_id_to_firmware_unique_id (GArray *qmi_unique_id,
+ GError **error)
+{
+ gint i;
+ gboolean expect_nul_byte = FALSE;
+
+ if (qmi_unique_id->len != EXPECTED_QMI_UNIQUE_ID_LENGTH) {
+ g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
+ "unexpected QMI unique ID length: %u (expected: %u)",
+ qmi_unique_id->len, EXPECTED_QMI_UNIQUE_ID_LENGTH);
+ return NULL;
+ }
+
+ for (i = 0; i < qmi_unique_id->len; i++) {
+ guint8 val;
+
+ val = g_array_index (qmi_unique_id, guint8, i);
+
+ /* Check for ASCII chars */
+ if (g_ascii_isprint ((gchar) val)) {
+ /* Halt iteration if we found an ASCII char after a NUL byte */
+ if (expect_nul_byte)
+ break;
+
+ /* good char */
+ continue;
+ }
+
+ /* Allow NUL bytes at the end of the array */
+ if (val == '\0' && i > 0) {
+ if (!expect_nul_byte)
+ expect_nul_byte = TRUE;
+ continue;
+ }
+
+ /* Halt iteration, not something we can build as ASCII */
+ break;
+ }
+
+ if (i != qmi_unique_id->len)
+ return mm_utils_bin2hexstr ((const guint8 *)qmi_unique_id->data, qmi_unique_id->len);
+
+ return g_strndup ((const gchar *)qmi_unique_id->data, qmi_unique_id->len);
+}
+
+GArray *
+mm_firmware_unique_id_to_qmi_unique_id (const gchar *unique_id,
+ GError **error)
+{
+ guint len;
+ GArray *qmi_unique_id;
+
+ len = strlen (unique_id);
+
+ /* The length will be exactly EXPECTED_QMI_UNIQUE_ID_LENGTH*2 if given in HEX */
+ if (len == (2 * EXPECTED_QMI_UNIQUE_ID_LENGTH)) {
+ guint8 *tmp;
+ gsize tmp_len;
+ guint i;
+
+ for (i = 0; i < len; i++) {
+ if (!g_ascii_isxdigit (unique_id[i])) {
+ g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
+ "Unexpected character found in unique id (not HEX): %c", unique_id[i]);
+ return NULL;
+ }
+ }
+
+ tmp_len = 0;
+ tmp = (guint8 *) mm_utils_hexstr2bin (unique_id, &tmp_len);
+ g_assert (tmp_len == EXPECTED_QMI_UNIQUE_ID_LENGTH);
+
+ qmi_unique_id = g_array_sized_new (FALSE, FALSE, sizeof (guint8), tmp_len);
+ g_array_insert_vals (qmi_unique_id, 0, tmp, tmp_len);
+ g_free (tmp);
+ return qmi_unique_id;
+ }
+
+ /* The length will be EXPECTED_QMI_UNIQUE_ID_LENGTH or less if given in ASCII */
+ if (len > 0 && len <= EXPECTED_QMI_UNIQUE_ID_LENGTH) {
+ guint i;
+
+ for (i = 0; i < len; i++) {
+ if (!g_ascii_isprint (unique_id[i])) {
+ g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
+ "Unexpected character found in unique id (not ASCII): %c", unique_id[i]);
+ return NULL;
+ }
+ }
+
+ qmi_unique_id = g_array_sized_new (FALSE, FALSE, sizeof (guint8), EXPECTED_QMI_UNIQUE_ID_LENGTH);
+ g_array_set_size (qmi_unique_id, EXPECTED_QMI_UNIQUE_ID_LENGTH);
+ memcpy (&qmi_unique_id->data[0], unique_id, len);
+ if (len < EXPECTED_QMI_UNIQUE_ID_LENGTH)
+ memset (&qmi_unique_id->data[len], 0, EXPECTED_QMI_UNIQUE_ID_LENGTH - len);
+ return qmi_unique_id;
+ }
+
+ g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
+ "Unexpected unique id length: %u", len);
+ return NULL;
+}
diff --git a/src/mm-modem-helpers-qmi.h b/src/mm-modem-helpers-qmi.h
index a51c4f6..5c0200e 100644
--- a/src/mm-modem-helpers-qmi.h
+++ b/src/mm-modem-helpers-qmi.h
@@ -138,4 +138,12 @@
MMModemCapability mm_modem_capability_from_qmi_capabilities_context (MMQmiCapabilitiesContext *ctx);
+/*****************************************************************************/
+/* QMI unique id manipulation */
+
+gchar *mm_qmi_unique_id_to_firmware_unique_id (GArray *qmi_unique_id,
+ GError **error);
+GArray *mm_firmware_unique_id_to_qmi_unique_id (const gchar *unique_id,
+ GError **error);
+
#endif /* MM_MODEM_HELPERS_QMI_H */
diff --git a/src/mm-modem-helpers.c b/src/mm-modem-helpers.c
index f7115cb..ec07aad 100644
--- a/src/mm-modem-helpers.c
+++ b/src/mm-modem-helpers.c
@@ -606,6 +606,15 @@
[3] = MM_CALL_STATE_RINGING_OUT, /* Alerting (MOC) */
[4] = MM_CALL_STATE_RINGING_IN, /* Incoming (MTC) */
[5] = MM_CALL_STATE_WAITING, /* Waiting (MTC) */
+
+ /* This next call state number isn't defined by 3GPP, because it
+ * doesn't make sense to have it when reporting a full list of calls
+ * via +CLCC (i.e. the absence of the call would mean it's terminated).
+ * But, this value may be used by other implementations (e.g. SimTech
+ * plugin) to report that a call is terminated even when the full
+ * call list isn't being reported. So, let's support it in the generic,
+ * parser, even if not strictly standard. */
+ [6] = MM_CALL_STATE_TERMINATED,
};
g_assert (out_list);
@@ -4344,6 +4353,70 @@
}
/*************************************************************************/
+/* Emergency numbers (+CRSM output) */
+
+GStrv
+mm_3gpp_parse_emergency_numbers (const char *raw, GError **error)
+{
+ gsize rawlen;
+ guint8 *bin;
+ gsize binlen;
+ gsize max_items;
+ GPtrArray *out;
+ guint i;
+
+ /* The emergency call code is of a variable length with a maximum length of
+ * 6 digits. Each emergency call code is coded on three bytes, with each
+ * digit within the code being coded on four bits. If a code of less that 6
+ * digits is chosen, then the unused nibbles shall be set to 'F'. */
+
+ rawlen = strlen (raw);
+ if (!rawlen) {
+ g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_INVALID_ARGS,
+ "empty emergency numbers list");
+ return NULL;
+ }
+
+ if (rawlen % 6 != 0) {
+ g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_INVALID_ARGS,
+ "invalid raw emergency numbers list length: %" G_GSIZE_FORMAT, rawlen);
+ return NULL;
+ }
+
+ bin = (guint8 *) mm_utils_hexstr2bin (raw, &binlen);
+ if (!bin) {
+ g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_INVALID_ARGS,
+ "invalid raw emergency numbers list contents: %s", raw);
+ return NULL;
+ }
+
+ max_items = binlen / 3;
+ out = g_ptr_array_sized_new (max_items + 1);
+
+ for (i = 0; i < max_items; i++) {
+ gchar *number;
+
+ number = mm_bcd_to_string (&bin[i*3], 3);
+ if (number && number[0])
+ g_ptr_array_add (out, number);
+ else
+ g_free (number);
+ }
+
+ g_free (bin);
+
+ if (!out->len) {
+ g_ptr_array_unref (out);
+ g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_UNSUPPORTED,
+ "uninitialized emergency numbers list");
+ return NULL;
+ }
+
+ g_ptr_array_add (out, NULL);
+ return (GStrv) g_ptr_array_free (out, FALSE);
+}
+
+/*************************************************************************/
gboolean
mm_cdma_parse_spservice_read_response (const gchar *reply,
diff --git a/src/mm-modem-helpers.h b/src/mm-modem-helpers.h
index 73a13dd..28a6999 100644
--- a/src/mm-modem-helpers.h
+++ b/src/mm-modem-helpers.h
@@ -445,6 +445,8 @@
gboolean mm_3gpp_rssnr_level_to_rssnr (gint rssnr_level,
gdouble *out_rssnr);
+GStrv mm_3gpp_parse_emergency_numbers (const char *raw, GError **error);
+
/*****************************************************************************/
/* CDMA specific helpers and utilities */
/*****************************************************************************/
diff --git a/src/mm-port-probe.c b/src/mm-port-probe.c
index c02f0b2..c0b5b45 100644
--- a/src/mm-port-probe.c
+++ b/src/mm-port-probe.c
@@ -93,6 +93,7 @@
/* From udev tags */
gboolean is_ignored;
gboolean is_gps;
+ gboolean is_audio;
gboolean maybe_at_primary;
gboolean maybe_at_secondary;
gboolean maybe_at_ppp;
@@ -1477,6 +1478,15 @@
mm_port_probe_set_result_qcdm (self, FALSE);
}
+ /* If this is a port flagged as an audio port, don't do any AT or QCDM probing */
+ if (self->priv->is_audio) {
+ mm_dbg ("(%s/%s) audio port detected",
+ mm_kernel_device_get_subsystem (self->priv->port),
+ mm_kernel_device_get_name (self->priv->port));
+ mm_port_probe_set_result_at (self, FALSE);
+ mm_port_probe_set_result_qcdm (self, FALSE);
+ }
+
/* If this is a port flagged as being an AT port, don't do any QCDM probing */
if (self->priv->maybe_at_primary || self->priv->maybe_at_secondary || self->priv->maybe_at_ppp) {
mm_dbg ("(%s/%s) no QCDM probing in possible AT port",
@@ -1711,6 +1721,9 @@
if (self->priv->is_gps)
return MM_PORT_TYPE_GPS;
+ if (self->priv->is_audio)
+ return MM_PORT_TYPE_AUDIO;
+
return MM_PORT_TYPE_UNKNOWN;
}
@@ -1900,6 +1913,7 @@
self->priv->port = g_value_dup_object (value);
self->priv->is_ignored = mm_kernel_device_get_property_as_boolean (self->priv->port, ID_MM_PORT_IGNORE);
self->priv->is_gps = mm_kernel_device_get_property_as_boolean (self->priv->port, ID_MM_PORT_TYPE_GPS);
+ self->priv->is_audio = mm_kernel_device_get_property_as_boolean (self->priv->port, ID_MM_PORT_TYPE_AUDIO);
self->priv->maybe_at_primary = mm_kernel_device_get_property_as_boolean (self->priv->port, ID_MM_PORT_TYPE_AT_PRIMARY);
self->priv->maybe_at_secondary = mm_kernel_device_get_property_as_boolean (self->priv->port, ID_MM_PORT_TYPE_AT_SECONDARY);
self->priv->maybe_at_ppp = mm_kernel_device_get_property_as_boolean (self->priv->port, ID_MM_PORT_TYPE_AT_PPP);
diff --git a/src/mm-port-serial.c b/src/mm-port-serial.c
index 052d0dd..3101ce6 100644
--- a/src/mm-port-serial.c
+++ b/src/mm-port-serial.c
@@ -815,8 +815,7 @@
/* FIXME: This is not completely correct - if the response finally arrives and there's
* some other command waiting for response right now, the other command will
* get the output of the cancelled command. Not sure what to do here. */
- error = g_error_new_literal (MM_CORE_ERROR,
- MM_CORE_ERROR_CANCELLED,
+ error = g_error_new_literal (G_IO_ERROR, G_IO_ERROR_CANCELLED,
"Waiting for the reply cancelled");
/* Note: may complete last operation and unref the MMPortSerial */
port_serial_got_response (self, NULL, error);
@@ -1566,10 +1565,7 @@
task = self->priv->reopen_task;
self->priv->reopen_task = NULL;
- g_task_return_new_error (task,
- MM_CORE_ERROR,
- MM_CORE_ERROR_CANCELLED,
- "Reopen cancelled");
+ g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_CANCELLED, "Reopen cancelled");
g_object_unref (task);
}
@@ -1740,7 +1736,7 @@
static gboolean
flash_cancel_cb (GTask *task)
{
- g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_CANCELLED, "Flash cancelled");
+ g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_CANCELLED, "Flash cancelled");
g_object_unref (task);
return G_SOURCE_REMOVE;
}
diff --git a/src/mm-port.h b/src/mm-port.h
index 8046329..33b07d9 100644
--- a/src/mm-port.h
+++ b/src/mm-port.h
@@ -41,7 +41,8 @@
MM_PORT_TYPE_GPS,
MM_PORT_TYPE_QMI,
MM_PORT_TYPE_MBIM,
- MM_PORT_TYPE_LAST = MM_PORT_TYPE_MBIM /*< skip >*/
+ MM_PORT_TYPE_AUDIO,
+ MM_PORT_TYPE_LAST = MM_PORT_TYPE_AUDIO /*< skip >*/
} MMPortType;
#define MM_TYPE_PORT (mm_port_get_type ())
diff --git a/src/mm-shared-qmi.c b/src/mm-shared-qmi.c
index 9629fab..d1a78d4 100644
--- a/src/mm-shared-qmi.c
+++ b/src/mm-shared-qmi.c
@@ -1000,7 +1000,7 @@
* switching only when switching GSM/UMTS+CDMA/EVDO multimode devices, and only if
* we have support for the commands doing it.
*/
- if (priv->feature_nas_technology_preference == FEATURE_SUPPORTED || priv->feature_nas_system_selection_preference == FEATURE_UNKNOWN) {
+ if (priv->feature_nas_technology_preference == FEATURE_SUPPORTED || priv->feature_nas_system_selection_preference == FEATURE_SUPPORTED) {
if (mask == (MM_MODEM_CAPABILITY_GSM_UMTS | MM_MODEM_CAPABILITY_CDMA_EVDO)) {
/* Multimode GSM/UMTS+CDMA/EVDO device switched to GSM/UMTS only */
single = MM_MODEM_CAPABILITY_GSM_UMTS;
diff --git a/src/mm-sms-part-3gpp.c b/src/mm-sms-part-3gpp.c
index 7e3f537..d977989 100644
--- a/src/mm-sms-part-3gpp.c
+++ b/src/mm-sms-part-3gpp.c
@@ -156,25 +156,26 @@
return utf8;
}
-static char *
+static gchar *
sms_decode_timestamp (const guint8 *timestamp)
{
- /* YYMMDDHHMMSS+ZZ */
- char *timestr;
- int quarters, hours;
+ /* ISO8601 format: YYYY-MM-DDTHH:MM:SS+HHMM */
+ guint year, month, day, hour, minute, second;
+ gint quarters, offset_minutes;
- timestr = g_malloc0 (16);
- sms_semi_octets_to_bcd_string (timestr, timestamp, 6);
+ year = 2000 + ((timestamp[0] & 0xf) * 10) + ((timestamp[0] >> 4) & 0xf);
+ month = ((timestamp[1] & 0xf) * 10) + ((timestamp[1] >> 4) & 0xf);
+ day = ((timestamp[2] & 0xf) * 10) + ((timestamp[2] >> 4) & 0xf);
+ hour = ((timestamp[3] & 0xf) * 10) + ((timestamp[3] >> 4) & 0xf);
+ minute = ((timestamp[4] & 0xf) * 10) + ((timestamp[4] >> 4) & 0xf);
+ second = ((timestamp[5] & 0xf) * 10) + ((timestamp[5] >> 4) & 0xf);
quarters = ((timestamp[6] & 0x7) * 10) + ((timestamp[6] >> 4) & 0xf);
- hours = quarters / 4;
+ offset_minutes = quarters * 15;
if (timestamp[6] & 0x08)
- timestr[12] = '-';
- else
- timestr[12] = '+';
- timestr[13] = (hours / 10) + '0';
- timestr[14] = (hours % 10) + '0';
- /* TODO(njw): Change timestamp rep to something that includes quarter-hours */
- return timestr;
+ offset_minutes = -1 * offset_minutes;
+
+ return mm_new_iso8601_time (year, month, day, hour,
+ minute, second, TRUE, offset_minutes);
}
static MMSmsEncoding
diff --git a/src/tests/test-at-serial-port.c b/src/tests/test-at-serial-port.c
index 2173f20..5aacba2 100644
--- a/src/tests/test-at-serial-port.c
+++ b/src/tests/test-at-serial-port.c
@@ -71,17 +71,17 @@
const char *fmt,
...)
{
-#if defined ENABLE_TEST_MESSAGE_TRACES
- /* Dummy log function */
va_list args;
gchar *msg;
+ if (!g_test_verbose ())
+ return;
+
va_start (args, fmt);
msg = g_strdup_vprintf (fmt, args);
va_end (args);
g_print ("%s\n", msg);
g_free (msg);
-#endif
}
int main (int argc, char **argv)
diff --git a/src/tests/test-charsets.c b/src/tests/test-charsets.c
index e7b47da..8c34af5 100644
--- a/src/tests/test-charsets.c
+++ b/src/tests/test-charsets.c
@@ -20,12 +20,6 @@
#include "mm-modem-helpers.h"
#include "mm-log.h"
-#if defined ENABLE_TEST_MESSAGE_TRACES
-#define trace(message, ...) g_print (message, ##__VA_ARGS__)
-#else
-#define trace(...)
-#endif
-
static void
test_gsm7_default_chars (void)
{
@@ -400,7 +394,7 @@
guint i;
for (i = 0; i < G_N_ELEMENTS (charset_can_convert_to_test); i++) {
- trace ("testing charset conversion: '%s'\n", charset_can_convert_to_test[i].utf8);
+ g_debug ("testing charset conversion: '%s'", charset_can_convert_to_test[i].utf8);
g_assert (mm_charset_can_convert_to (charset_can_convert_to_test[i].utf8, MM_MODEM_CHARSET_GSM) == charset_can_convert_to_test[i].to_gsm);
g_assert (mm_charset_can_convert_to (charset_can_convert_to_test[i].utf8, MM_MODEM_CHARSET_IRA) == charset_can_convert_to_test[i].to_ira);
g_assert (mm_charset_can_convert_to (charset_can_convert_to_test[i].utf8, MM_MODEM_CHARSET_8859_1) == charset_can_convert_to_test[i].to_8859_1);
@@ -417,17 +411,17 @@
const char *fmt,
...)
{
-#if defined ENABLE_TEST_MESSAGE_TRACES
- /* Dummy log function */
va_list args;
gchar *msg;
+ if (!g_test_verbose ())
+ return;
+
va_start (args, fmt);
msg = g_strdup_vprintf (fmt, args);
va_end (args);
g_print ("%s\n", msg);
g_free (msg);
-#endif
}
int main (int argc, char **argv)
diff --git a/src/tests/test-modem-helpers-qmi.c b/src/tests/test-modem-helpers-qmi.c
index f85430c..d6b491c 100644
--- a/src/tests/test-modem-helpers-qmi.c
+++ b/src/tests/test-modem-helpers-qmi.c
@@ -316,17 +316,17 @@
const char *fmt,
...)
{
-#if defined ENABLE_TEST_MESSAGE_TRACES
- /* Dummy log function */
va_list args;
gchar *msg;
+ if (!g_test_verbose ())
+ return;
+
va_start (args, fmt);
msg = g_strdup_vprintf (fmt, args);
va_end (args);
g_print ("%s\n", msg);
g_free (msg);
-#endif
}
int main (int argc, char **argv)
diff --git a/src/tests/test-modem-helpers.c b/src/tests/test-modem-helpers.c
index 18c7fdb..0e63e41 100644
--- a/src/tests/test-modem-helpers.c
+++ b/src/tests/test-modem-helpers.c
@@ -24,12 +24,6 @@
#include "mm-modem-helpers.h"
#include "mm-log.h"
-#if defined ENABLE_TEST_MESSAGE_TRACES
-#define trace(message, ...) g_print (message, ##__VA_ARGS__)
-#else
-#define trace(...)
-#endif
-
#define g_assert_cmpfloat_tolerance(val1, val2, tolerance) \
g_assert_cmpfloat (fabs (val1 - val2), <, tolerance)
@@ -489,7 +483,7 @@
GError *error = NULL;
GList *results;
- trace ("\nTesting %s +COPS response...\n", desc);
+ g_debug ("Testing %s +COPS response...", desc);
results = mm_3gpp_parse_cops_test_response (reply, &error);
g_assert (results);
@@ -1091,17 +1085,17 @@
g_assert (data);
g_assert (result);
- trace ("\nTesting '%s' +C%sREG %s response...\n",
- test,
- result->cgreg ? "G" : "",
- solicited ? "solicited" : "unsolicited");
+ g_debug ("Testing '%s' +C%sREG %s response...",
+ test,
+ result->cgreg ? "G" : "",
+ solicited ? "solicited" : "unsolicited");
array = solicited ? data->solicited_creg : data->unsolicited_creg;
for (i = 0; i < array->len; i++) {
GRegex *r = g_ptr_array_index (array, i);
if (g_regex_match (r, reply, 0, &info)) {
- trace (" matched with %d\n", i);
+ g_debug (" matched with %d", i);
regex_num = i + 1;
break;
}
@@ -1109,9 +1103,9 @@
info = NULL;
}
- trace (" regex_num (%u) == result->regex_num (%u)\n",
- regex_num,
- result->regex_num);
+ g_debug (" regex_num (%u) == result->regex_num (%u)",
+ regex_num,
+ result->regex_num);
g_assert (info != NULL);
g_assert_cmpuint (regex_num, ==, result->regex_num);
@@ -1124,8 +1118,8 @@
g_assert (lac == result->lac);
g_assert (ci == result->ci);
- trace (" access_tech (%d) == result->act (%d)\n",
- access_tech, result->act);
+ g_debug (" access_tech (%d) == result->act (%d)",
+ access_tech, result->act);
g_assert_cmpuint (access_tech, ==, result->act);
g_assert_cmpuint (cgreg, ==, result->cgreg);
g_assert_cmpuint (cereg, ==, result->cereg);
@@ -1881,7 +1875,7 @@
DevidItem *item = (DevidItem *) d;
char *devid;
- trace ("%s... ", item->desc);
+ g_debug ("%s... ", item->desc);
devid = mm_create_device_identifier (item->vid,
item->pid,
item->ati,
@@ -1990,7 +1984,7 @@
GError *error = NULL;
GHashTable *results;
- trace ("\nTesting %s +CIND response...\n", desc);
+ g_debug ("Testing %s +CIND response...", desc);
results = mm_3gpp_parse_cind_test_response (reply, &error);
g_assert (results);
@@ -2133,7 +2127,7 @@
type = mm_3gpp_parse_cgev_indication_action (test->str);
g_assert_cmpuint (type, ==, test->expected_type);
- g_print ("[%u] type: %u\n", i, type);
+ g_debug ("[%u] type: %u", i, type);
switch (type) {
case MM_3GPP_CGEV_NW_DETACH:
@@ -2145,7 +2139,7 @@
case MM_3GPP_CGEV_ME_DEACT_PRIMARY: {
guint cid;
- g_print ("[%u] parsing as primary\n", i);
+ g_debug ("[%u] parsing as primary", i);
ret = mm_3gpp_parse_cgev_indication_primary (test->str, type, &cid, &error);
g_assert_no_error (error);
g_assert (ret);
@@ -2160,7 +2154,7 @@
guint cid;
guint event_type;
- g_print ("[%u] parsing as secondary\n", i);
+ g_debug ("[%u] parsing as secondary", i);
ret = mm_3gpp_parse_cgev_indication_secondary (test->str, type, &p_cid, &cid, &event_type, &error);
g_assert_no_error (error);
g_assert (ret);
@@ -2177,7 +2171,7 @@
gchar *pdp_addr;
guint cid;
- g_print ("[%u] parsing as pdp\n", i);
+ g_debug ("[%u] parsing as pdp", i);
ret = mm_3gpp_parse_cgev_indication_pdp (test->str, type, &pdp_type, &pdp_addr, &cid, &error);
g_assert_no_error (error);
g_assert (ret);
@@ -2409,7 +2403,7 @@
GError *error = NULL;
GList *results;
- trace ("\nTesting %s +CGDCONT test response...\n", desc);
+ g_debug ("Testing %s +CGDCONT test response...", desc);
results = mm_3gpp_parse_cgdcont_test_response (reply, &error);
g_assert (results);
@@ -2537,7 +2531,7 @@
GError *error = NULL;
GList *results;
- trace ("\nTesting %s +CGDCONT response...\n", desc);
+ g_debug ("Testing %s +CGDCONT response...", desc);
results = mm_3gpp_parse_cgdcont_read_response (reply, &error);
g_assert (results);
@@ -2607,7 +2601,7 @@
GError *error = NULL;
GList *results;
- trace ("\nTesting %s +CGACT response...\n", desc);
+ g_debug ("Testing %s +CGACT response...", desc);
results = mm_3gpp_parse_cgact_read_response (reply, &error);
g_assert_no_error (error);
@@ -2872,7 +2866,7 @@
GArray *mem2 = NULL;
GArray *mem3 = NULL;
- trace ("\nTesting Cinterion +CPMS=? response...\n");
+ g_debug ("Testing Cinterion +CPMS=? response...");
g_assert (mm_3gpp_parse_cpms_test_response (reply, &mem1, &mem2, &mem3));
g_assert_cmpuint (mem1->len, ==, 2);
@@ -2900,7 +2894,7 @@
GArray *mem2 = NULL;
GArray *mem3 = NULL;
- trace ("\nTesting Huawei MU609 +CPMS=? response...\n");
+ g_debug ("Testing Huawei MU609 +CPMS=? response...");
g_assert (mm_3gpp_parse_cpms_test_response (reply, &mem1, &mem2, &mem3));
g_assert_cmpuint (mem1->len, ==, 1);
@@ -2924,7 +2918,7 @@
GArray *mem2 = NULL;
GArray *mem3 = NULL;
- trace ("\nTesting Nokia C6 response...\n");
+ g_debug ("Testing Nokia C6 response...");
g_assert (mm_3gpp_parse_cpms_test_response (reply, &mem1, &mem2, &mem3));
g_assert_cmpuint (mem1->len, ==, 0);
@@ -2949,7 +2943,7 @@
GArray *mem2 = NULL;
GArray *mem3 = NULL;
- trace ("\nTesting mixed +CPMS=? response...\n");
+ g_debug ("Testing mixed +CPMS=? response...");
g_assert (mm_3gpp_parse_cpms_test_response (reply, &mem1, &mem2, &mem3));
g_assert_cmpuint (mem1->len, ==, 2);
@@ -2974,7 +2968,7 @@
GArray *mem2 = NULL;
GArray *mem3 = NULL;
- trace ("\nTesting mixed +CPMS=? response with spaces...\n");
+ g_debug ("Testing mixed +CPMS=? response with spaces...");
g_assert (mm_3gpp_parse_cpms_test_response (reply, &mem1, &mem2, &mem3));
g_assert_cmpuint (mem1->len, ==, 2);
@@ -3003,7 +2997,7 @@
GArray *mem2 = NULL;
GArray *mem3 = NULL;
- trace ("\nTesting mixed +CPMS=? response...\n");
+ g_debug ("Testing mixed +CPMS=? response...");
g_assert (mm_3gpp_parse_cpms_test_response (reply, &mem1, &mem2, &mem3));
g_assert_cmpuint (mem1->len, ==, 0);
@@ -3060,7 +3054,7 @@
GStrv results;
guint i;
- trace ("\nTesting +CNUM response (%s)...\n", desc);
+ g_debug ("Testing +CNUM response (%s)...", desc);
results = mm_3gpp_parse_cnum_exec_response (reply);
g_assert (results);
@@ -3161,19 +3155,19 @@
GError *error = NULL;
if (expected_mcc) {
- trace ("\nParsing Operator ID '%s' "
- "(%" G_GUINT16_FORMAT ", %" G_GUINT16_FORMAT ")...\n",
- operator_id, expected_mcc, expected_mnc);
+ g_debug ("Parsing Operator ID '%s' "
+ "(%" G_GUINT16_FORMAT ", %" G_GUINT16_FORMAT ")...",
+ operator_id, expected_mcc, expected_mnc);
result = mm_3gpp_parse_operator_id (operator_id, &mcc, &mnc, &error);
} else {
- trace ("\nValidating Operator ID '%s'...\n", operator_id);
+ g_debug ("Validating Operator ID '%s'...", operator_id);
result = mm_3gpp_parse_operator_id (operator_id, NULL, NULL, &error);
}
if (error)
- trace ("\tGot %s error: %s...\n",
- expected_success ? "unexpected" : "expected",
- error->message);
+ g_debug ("Got %s error: %s...",
+ expected_success ? "unexpected" : "expected",
+ error->message);
g_assert (result == expected_success);
@@ -3193,7 +3187,6 @@
static void
test_parse_operator_id (void *f, gpointer d)
{
- trace ("\n");
/* Valid MCC+MNC(2) */
common_parse_operator_id ("41201", TRUE, 412, 1);
common_parse_operator_id ("41201", TRUE, 0, 0);
@@ -4257,7 +4250,7 @@
g_assert_no_error (error);
g_assert (result);
- g_print ("found %u calls\n", g_list_length (call_info_list));
+ g_debug ("found %u calls", g_list_length (call_info_list));
if (expected_call_info_list) {
g_assert (call_info_list);
@@ -4270,7 +4263,7 @@
gboolean found = FALSE;
guint i;
- g_print ("call at index %u: direction %s, state %s, number %s\n",
+ g_debug ("call at index %u: direction %s, state %s, number %s",
call_info->index,
mm_call_direction_get_string (call_info->direction),
mm_call_state_get_string (call_info->state),
@@ -4345,6 +4338,55 @@
}
/*****************************************************************************/
+/* Test +CRSM EF_ECC read data parsing */
+
+#define MAX_EMERGENCY_NUMBERS 5
+typedef struct {
+ const gchar *raw;
+ guint n_numbers;
+ gchar *numbers[MAX_EMERGENCY_NUMBERS];
+} EmergencyNumbersTest;
+
+static const EmergencyNumbersTest emergency_numbers_tests[] = {
+ { "", 0 },
+ { "FFF", 0 },
+ { "FFFFFF" "FFFFFF" "FFFFFF" "FFFFFF" "FFFFFF", 0 },
+ { "00F0FF" "11F2FF" "88F8FF", 3, { "000", "112", "888" } },
+ { "00F0FF" "11F2FF" "88F8FF" "FFFFFF" "FFFFFF", 3, { "000", "112", "888" } },
+ { "00F0FF" "11F2FF" "88F8FF" "214365" "08FFFF", 5, { "000", "112", "888", "123456", "80" } },
+};
+
+static void
+test_emergency_numbers (void)
+{
+ guint i;
+
+ for (i = 0; i < G_N_ELEMENTS (emergency_numbers_tests); i++) {
+ GStrv numbers;
+ GError *error = NULL;
+ guint j;
+
+ g_debug (" testing %s...", emergency_numbers_tests[i].raw);
+
+ numbers = mm_3gpp_parse_emergency_numbers (emergency_numbers_tests[i].raw, &error);
+ if (!emergency_numbers_tests[i].n_numbers) {
+ g_assert (error);
+ g_assert (!numbers);
+ continue;
+ }
+
+ g_assert_no_error (error);
+ g_assert (numbers);
+
+ g_assert_cmpuint (emergency_numbers_tests[i].n_numbers, ==, g_strv_length (numbers));
+ for (j = 0; j < emergency_numbers_tests[i].n_numbers; j++)
+ g_assert_cmpstr (emergency_numbers_tests[i].numbers[j], ==, numbers[j]);
+
+ g_strfreev (numbers);
+ }
+}
+
+/*****************************************************************************/
typedef struct {
gchar *str;
@@ -4432,17 +4474,17 @@
const char *fmt,
...)
{
-#if defined ENABLE_TEST_MESSAGE_TRACES
- /* Dummy log function */
va_list args;
gchar *msg;
+ if (!g_test_verbose ())
+ return;
+
va_start (args, fmt);
msg = g_strdup_vprintf (fmt, args);
va_end (args);
g_print ("%s\n", msg);
g_free (msg);
-#endif
}
#define TESTCASE(t, d) g_test_create_case (#t, 0, d, NULL, (GTestFixtureFunc) t, NULL)
@@ -4666,6 +4708,8 @@
g_test_suite_add (suite, TESTCASE (test_clcc_response_single_long, NULL));
g_test_suite_add (suite, TESTCASE (test_clcc_response_multiple, NULL));
+ g_test_suite_add (suite, TESTCASE (test_emergency_numbers, NULL));
+
g_test_suite_add (suite, TESTCASE (test_parse_uint_list, NULL));
g_test_suite_add (suite, TESTCASE (test_bcd_to_string, NULL));
diff --git a/src/tests/test-qcdm-serial-port.c b/src/tests/test-qcdm-serial-port.c
index ac73a5b..e689905 100644
--- a/src/tests/test-qcdm-serial-port.c
+++ b/src/tests/test-qcdm-serial-port.c
@@ -444,17 +444,17 @@
const char *fmt,
...)
{
-#if defined ENABLE_TEST_MESSAGE_TRACES
- /* Dummy log function */
va_list args;
gchar *msg;
+ if (!g_test_verbose ())
+ return;
+
va_start (args, fmt);
msg = g_strdup_vprintf (fmt, args);
va_end (args);
g_print ("%s\n", msg);
g_free (msg);
-#endif
}
typedef void (*TCFunc) (TestData *, gconstpointer);
diff --git a/src/tests/test-sms-part-3gpp.c b/src/tests/test-sms-part-3gpp.c
index dcf4cc8..d915240 100644
--- a/src/tests/test-sms-part-3gpp.c
+++ b/src/tests/test-sms-part-3gpp.c
@@ -26,23 +26,6 @@
#include "mm-sms-part-3gpp.h"
#include "mm-log.h"
-/* If defined will print debugging traces */
-#ifdef TEST_SMS_PART_ENABLE_TRACE
-#define trace_pdu(pdu, pdu_len) do { \
- guint i; \
- \
- g_print ("\n "); \
- for (i = 0; i < len; i++) { \
- g_print (" 0x%02X", pdu[i]); \
- if (((i + 1) % 12) == 0) \
- g_print ("\n "); \
- } \
- g_print ("\n"); \
- } while (0)
-#else
-#define trace_pdu(...)
-#endif
-
/********************* PDU PARSER TESTS *********************/
static void
@@ -136,7 +119,7 @@
pdu, sizeof (pdu),
"+12404492164", /* smsc */
"+16175927198", /* number */
- "110228115050-05", /* timestamp */
+ "2011-02-28T11:50:50-05:00", /* timestamp */
FALSE,
"Here's a longer message [{with some extended characters}] "
"thrown in, such as £ and ΩΠΨ and §¿ as well.", /* text */
@@ -157,7 +140,7 @@
pdu, sizeof (pdu),
"+79037011111", /* smsc */
"InternetSMS", /* number */
- "110329192004+04", /* timestamp */
+ "2011-03-29T19:20:04+04:00", /* timestamp */
FALSE,
"тест", /* text */
NULL, 0);
@@ -177,7 +160,7 @@
pdu, sizeof (pdu),
"+12345678901", /* smsc */
"+18005551212", /* number */
- "110101123456+00", /* timestamp */
+ "2011-01-01T12:34:56+00:00", /* timestamp */
FALSE,
"hellohello", /* text */
NULL, 0);
@@ -198,7 +181,7 @@
pdu, sizeof (pdu),
"+12345678901", /* smsc */
"+18005551212", /* number */
- "110101123456+00", /* timestamp */
+ "2011-01-01T12:34:56+00:00", /* timestamp */
FALSE,
"hellohello", /* text */
NULL, 0);
@@ -219,7 +202,7 @@
pdu, sizeof (pdu),
"+12345678901", /* smsc */
"+18005551212", /* number */
- "110101123456+00", /* timestamp */
+ "2011-01-01T12:34:56+00:00", /* timestamp */
FALSE,
"hellohello", /* text */
NULL, 0);
@@ -240,7 +223,7 @@
pdu, sizeof (pdu),
"+12345678901", /* smsc */
"18005551212", /* number, no plus */
- "110101123456+00", /* timestamp */
+ "2011-01-01T12:34:56+00:00", /* timestamp */
FALSE,
"hellohello", /* text */
NULL, 0);
@@ -262,7 +245,7 @@
pdu, sizeof (pdu),
"+12345678901", /* smsc */
"+18005551212", /* number */
- "110101123456+00", /* timestamp */
+ "2011-01-01T12:34:56+00:00", /* timestamp */
FALSE,
NULL, /* text */
expected_data, /* data */
@@ -310,7 +293,7 @@
pdu, sizeof (pdu),
"+33609001390", /* smsc */
"1800", /* number */
- "110624130815+02", /* timestamp */
+ "2011-06-24T13:08:15+02:00", /* timestamp */
FALSE,
"Info SFR - Confidentiel, à ne jamais transmettre -\r\n"
"Voici votre nouveau mot de passe : sw2ced pour gérer "
@@ -334,7 +317,7 @@
pdu, sizeof (pdu),
"+12345678901", /* smsc */
"+18005551212", /* number */
- "110101123456+00", /* timestamp */
+ "2011-01-01T12:34:56+00:00", /* timestamp */
FALSE,
NULL, /* text */
expected_data, /* data */
@@ -380,7 +363,7 @@
hexpdu,
"+31653131316", /* smsc */
"1002", /* number */
- "110629233219+02", /* timestamp */
+ "2011-06-29T23:32:19+02:00", /* timestamp */
TRUE,
"Welkom, bel om uw Voicemail te beluisteren naar +31612001233"
" (PrePay: *100*1233#). Voicemail ontvangen is altijd gratis."
@@ -405,7 +388,7 @@
hexpdu1,
"+12063130025", /* smsc */
"+16175046925", /* number */
- "120425195650-04", /* timestamp */
+ "2012-04-25T19:56:50-04:00", /* timestamp */
TRUE, /* multipart! */
"This is a very long test designed to exercise multi part capability. It should "
"show up as one message, not as two, as the underlying encoding represents ", /* text */
@@ -415,7 +398,7 @@
hexpdu2,
"+12063130026", /* smsc */
"+16175046925", /* number */
- "120425195651-04", /* timestamp */
+ "2012-04-25T19:56:51-04:00", /* timestamp */
TRUE, /* multipart! */
"that the parts are related to one another. ", /* text */
NULL, 0);
@@ -448,7 +431,7 @@
hexpdu1,
"+34656000311", /* smsc */
"639337937", /* number */
- "120911074036+02", /* timestamp */
+ "2012-09-11T07:40:36+02:00", /* timestamp */
FALSE, /* multipart! */
NULL, /* text */
NULL, 0);
@@ -509,6 +492,21 @@
/********************* PDU CREATOR TESTS *********************/
static void
+trace_pdu (const guint8 *pdu,
+ guint len)
+{
+ guint i;
+
+ g_print ("n ");
+ for (i = 0; i < len; i++) {
+ g_print (" 0x%02X", pdu[i]);
+ if (((i + 1) % 12) == 0)
+ g_print ("n ");
+ }
+ g_print ("n");
+}
+
+static void
common_test_create_pdu (const gchar *smsc,
const gchar *number,
const gchar *text,
@@ -549,7 +547,8 @@
&error);
mm_sms_part_free (part);
- trace_pdu (pdu, len);
+ if (g_test_verbose ())
+ trace_pdu (pdu, len);
g_assert_no_error (error);
g_assert (pdu != NULL);
@@ -848,17 +847,17 @@
const char *fmt,
...)
{
-#if defined ENABLE_TEST_MESSAGE_TRACES
- /* Dummy log function */
va_list args;
gchar *msg;
+ if (!g_test_verbose ())
+ return;
+
va_start (args, fmt);
msg = g_strdup_vprintf (fmt, args);
va_end (args);
g_print ("%s\n", msg);
g_free (msg);
-#endif
}
int main (int argc, char **argv)
diff --git a/src/tests/test-sms-part-cdma.c b/src/tests/test-sms-part-cdma.c
index 91b7c3c..e155926 100644
--- a/src/tests/test-sms-part-cdma.c
+++ b/src/tests/test-sms-part-cdma.c
@@ -25,23 +25,6 @@
#include "mm-sms-part-cdma.h"
#include "mm-log.h"
-/* If defined will print debugging traces */
-#ifdef TEST_SMS_PART_ENABLE_TRACE
-#define trace_pdu(pdu, pdu_len) do { \
- guint i; \
- \
- g_print ("\n "); \
- for (i = 0; i < len; i++) { \
- g_print (" 0x%02X", pdu[i]); \
- if (((i + 1) % 12) == 0) \
- g_print ("\n "); \
- } \
- g_print ("\n"); \
- } while (0)
-#else
-#define trace_pdu(...)
-#endif
-
/********************* PDU PARSER TESTS *********************/
static void
@@ -370,6 +353,21 @@
/********************* PDU CREATOR TESTS *********************/
static void
+trace_pdu (const guint8 *pdu,
+ guint len)
+{
+ guint i;
+
+ g_print ("n ");
+ for (i = 0; i < len; i++) {
+ g_print (" 0x%02X", pdu[i]);
+ if (((i + 1) % 12) == 0)
+ g_print ("n ");
+ }
+ g_print ("n");
+}
+
+static void
common_test_create_pdu (MMSmsCdmaTeleserviceId teleservice_id,
const gchar *number,
const gchar *text,
@@ -401,7 +399,8 @@
pdu = mm_sms_part_cdma_get_submit_pdu (part, &len, &error);
mm_sms_part_free (part);
- trace_pdu (pdu, len);
+ if (g_test_verbose ())
+ trace_pdu (pdu, len);
g_assert_no_error (error);
g_assert (pdu != NULL);
@@ -512,17 +511,17 @@
const char *fmt,
...)
{
-#if defined ENABLE_TEST_MESSAGE_TRACES
- /* Dummy log function */
va_list args;
gchar *msg;
+ if (!g_test_verbose ())
+ return;
+
va_start (args, fmt);
msg = g_strdup_vprintf (fmt, args);
va_end (args);
g_print ("%s\n", msg);
g_free (msg);
-#endif
}
int main (int argc, char **argv)
diff --git a/src/tests/test-udev-rules.c b/src/tests/test-udev-rules.c
index 07e9b8d..3398e41 100644
--- a/src/tests/test-udev-rules.c
+++ b/src/tests/test-udev-rules.c
@@ -22,9 +22,6 @@
#define _LIBMM_INSIDE_MM
#include <libmm-glib.h>
-/* Define symbol to enable test message traces */
-#undef ENABLE_TEST_MESSAGE_TRACES
-
#include "mm-kernel-device-generic-rules.h"
#include "mm-log.h"
@@ -53,17 +50,17 @@
const char *fmt,
...)
{
-#if defined ENABLE_TEST_MESSAGE_TRACES
- /* Dummy log function */
va_list args;
gchar *msg;
+ if (!g_test_verbose ())
+ return;
+
va_start (args, fmt);
msg = g_strdup_vprintf (fmt, args);
va_end (args);
g_print ("%s\n", msg);
g_free (msg);
-#endif
}
int main (int argc, char **argv)