aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAleksander Morgado <aleksander@aleksander.es>2019-07-15 17:13:21 +0200
committerAleksander Morgado <aleksander@aleksander.es>2019-07-19 17:47:51 +0200
commitf39dbe72e5fceacd9a45f48049b14f734f515ee3 (patch)
tree733e19f0e3c31844686d105608d57436bfe2807c /src
parent9263e79dc341f7b698721d859ed6a4141718e9f6 (diff)
broadband-modem,voice: implement call waiting status setup/query with +CCWA
Diffstat (limited to 'src')
-rw-r--r--src/mm-broadband-modem.c72
-rw-r--r--src/mm-modem-helpers.c79
-rw-r--r--src/mm-modem-helpers.h6
-rw-r--r--src/tests/test-modem-helpers.c58
4 files changed, 215 insertions, 0 deletions
diff --git a/src/mm-broadband-modem.c b/src/mm-broadband-modem.c
index f54ddc56..b0ccd191 100644
--- a/src/mm-broadband-modem.c
+++ b/src/mm-broadband-modem.c
@@ -7957,6 +7957,74 @@ modem_voice_transfer (MMIfaceModemVoice *self,
}
/*****************************************************************************/
+/* Call waiting setup (Voice interface) */
+
+static gboolean
+modem_voice_call_waiting_setup_finish (MMIfaceModemVoice *self,
+ GAsyncResult *res,
+ GError **error)
+{
+ return !!mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, error);
+}
+
+static void
+modem_voice_call_waiting_setup (MMIfaceModemVoice *self,
+ gboolean enable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ gchar *cmd;
+
+ /* Enabling or disabling the call waiting service will only be allowed when
+ * the modem is registered in the network, and so, CCWA URC handling will
+ * always be setup at this point (as it's part of the modem enabling phase).
+ * So, just enable or disable the service (second field) but leaving URCs
+ * (first field) always enabled. */
+ cmd = g_strdup_printf ("+CCWA=1,%u", enable);
+ mm_base_modem_at_command (MM_BASE_MODEM (self),
+ cmd,
+ 60,
+ FALSE,
+ callback,
+ user_data);
+ g_free (cmd);
+}
+
+/*****************************************************************************/
+/* Call waiting query (Voice interface) */
+
+static gboolean
+modem_voice_call_waiting_query_finish (MMIfaceModemVoice *self,
+ GAsyncResult *res,
+ gboolean *status,
+ GError **error)
+{
+ const gchar *response;
+
+ response = mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, error);
+ if (!response)
+ return FALSE;
+
+ return mm_3gpp_parse_ccwa_service_query_response (response, status, error);
+}
+
+static void
+modem_voice_call_waiting_query (MMIfaceModemVoice *self,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ /* This operation will only be allowed while enabled, and so, CCWA URC
+ * handling would always be enabled at this point. So, just perform the
+ * query, but leaving URCs enabled either way. */
+ mm_base_modem_at_command (MM_BASE_MODEM (self),
+ "+CCWA=1,2",
+ 60,
+ FALSE,
+ callback,
+ user_data);
+}
+
+/*****************************************************************************/
/* ESN loading (CDMA interface) */
static gchar *
@@ -12196,6 +12264,10 @@ iface_modem_voice_init (MMIfaceModemVoice *iface)
iface->leave_multiparty_finish = modem_voice_leave_multiparty_finish;
iface->transfer = modem_voice_transfer;
iface->transfer_finish = modem_voice_transfer_finish;
+ iface->call_waiting_setup = modem_voice_call_waiting_setup;
+ iface->call_waiting_setup_finish = modem_voice_call_waiting_setup_finish;
+ iface->call_waiting_query = modem_voice_call_waiting_query;
+ iface->call_waiting_query_finish = modem_voice_call_waiting_query_finish;
}
static void
diff --git a/src/mm-modem-helpers.c b/src/mm-modem-helpers.c
index b9d364d2..c6644c1c 100644
--- a/src/mm-modem-helpers.c
+++ b/src/mm-modem-helpers.c
@@ -2724,6 +2724,85 @@ mm_3gpp_parse_cemode_query_response (const gchar *response,
}
/*************************************************************************/
+/* CCWA service query response parser */
+
+gboolean
+mm_3gpp_parse_ccwa_service_query_response (const gchar *response,
+ gboolean *status,
+ GError **error)
+{
+ GRegex *r;
+ GError *inner_error = NULL;
+ GMatchInfo *match_info = NULL;
+ gint class_1_status = -1;
+
+ /*
+ * AT+CCWA=<n>[,<mode>]
+ * +CCWA: <status>,<class1>
+ * [+CCWA: <status>,<class2>
+ * [...]]
+ * OK
+ *
+ * If <classX> is 255 it applies to ALL classes.
+ *
+ * We're only interested in class 1 (voice)
+ */
+ r = g_regex_new ("\\+CCWA:\\s*(\\d+),\\s*(\\d+)$",
+ G_REGEX_RAW | G_REGEX_MULTILINE | G_REGEX_NEWLINE_CRLF,
+ G_REGEX_MATCH_NEWLINE_CRLF,
+ NULL);
+ g_assert (r != NULL);
+
+ g_regex_match_full (r, response, strlen (response), 0, 0, &match_info, &inner_error);
+ if (inner_error)
+ goto out;
+
+ /* Parse the results */
+ while (g_match_info_matches (match_info)) {
+ guint st;
+ guint class;
+
+ if (!mm_get_uint_from_match_info (match_info, 2, &class))
+ mm_warn ("couldn't parse class from +CCWA line");
+ else if (class == 1 || class == 255) {
+ if (!mm_get_uint_from_match_info (match_info, 1, &st))
+ mm_warn ("couldn't parse status from +CCWA line");
+ else {
+ class_1_status = st;
+ break;
+ }
+ }
+ g_match_info_next (match_info, NULL);
+ }
+
+out:
+ g_clear_pointer (&match_info, g_match_info_free);
+ g_regex_unref (r);
+
+ if (inner_error) {
+ g_propagate_error (error, inner_error);
+ return FALSE;
+ }
+
+ if (class_1_status < 0) {
+ g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_NOT_FOUND,
+ "call waiting status for voice class missing");
+ return FALSE;
+ }
+
+ if (class_1_status != 0 && class_1_status != 1) {
+ g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_UNSUPPORTED,
+ "call waiting status for voice class invalid: %d", class_1_status);
+ return FALSE;
+ }
+
+ if (status)
+ *status = (gboolean) class_1_status;
+
+ return TRUE;
+}
+
+/*************************************************************************/
static MMSmsStorage
storage_from_str (const gchar *str)
diff --git a/src/mm-modem-helpers.h b/src/mm-modem-helpers.h
index cce4bd20..8a73daab 100644
--- a/src/mm-modem-helpers.h
+++ b/src/mm-modem-helpers.h
@@ -397,6 +397,12 @@ gboolean mm_3gpp_parse_cemode_query_response (const gchar *r
MMModem3gppEpsUeModeOperation *out_mode,
GError **error);
+/* CCWA service query response parser */
+gboolean mm_3gpp_parse_ccwa_service_query_response (const gchar *response,
+ gboolean *status,
+ GError **error);
+
+
/* Additional 3GPP-specific helpers */
MMModem3gppFacility mm_3gpp_acronym_to_facility (const gchar *str);
diff --git a/src/tests/test-modem-helpers.c b/src/tests/test-modem-helpers.c
index 8470e3ac..0bca7f09 100644
--- a/src/tests/test-modem-helpers.c
+++ b/src/tests/test-modem-helpers.c
@@ -4019,6 +4019,63 @@ test_ccwa_indication (void)
}
/*****************************************************************************/
+/* +CCWA service query response testing */
+
+static void
+common_test_ccwa_response (const gchar *response,
+ gboolean expected_status,
+ gboolean expected_error)
+{
+ gboolean status = FALSE;
+ GError *error = NULL;
+ gboolean result;
+
+ result = mm_3gpp_parse_ccwa_service_query_response (response, &status, &error);
+
+ if (expected_error) {
+ g_assert (!result);
+ g_assert (error);
+ g_error_free (error);
+ } else {
+ g_assert (result);
+ g_assert_no_error (error);
+ g_assert_cmpuint (status, ==, expected_status);
+ }
+}
+
+typedef struct {
+ const gchar *response;
+ gboolean expected_status;
+ gboolean expected_error;
+} TestCcwa;
+
+static TestCcwa test_ccwa[] = {
+ { "+CCWA: 0,255", FALSE, FALSE }, /* all disabled */
+ { "+CCWA: 1,255", TRUE, FALSE }, /* all enabled */
+ { "+CCWA: 0,1\r\n"
+ "+CCWA: 0,4\r\n", FALSE, FALSE }, /* voice and fax disabled */
+ { "+CCWA: 1,1\r\n"
+ "+CCWA: 1,4\r\n", TRUE, FALSE }, /* voice and fax enabled */
+ { "+CCWA: 0,2\r\n"
+ "+CCWA: 0,4\r\n"
+ "+CCWA: 0,8\r\n", FALSE, TRUE }, /* data, fax, sms disabled, voice not given */
+ { "+CCWA: 1,2\r\n"
+ "+CCWA: 1,4\r\n"
+ "+CCWA: 1,8\r\n", FALSE, TRUE }, /* data, fax, sms enabled, voice not given */
+ { "+CCWA: 2,1\r\n"
+ "+CCWA: 2,4\r\n", FALSE, TRUE }, /* voice and fax enabled but unexpected state */
+};
+
+static void
+test_ccwa_response (void)
+{
+ guint i;
+
+ for (i = 0; i < G_N_ELEMENTS (test_ccwa); i++)
+ common_test_ccwa_response (test_ccwa[i].response, test_ccwa[i].expected_status, test_ccwa[i].expected_error);
+}
+
+/*****************************************************************************/
/* Test +CLCC URCs */
static void
@@ -4435,6 +4492,7 @@ int main (int argc, char **argv)
g_test_suite_add (suite, TESTCASE (test_clip_indication, NULL));
g_test_suite_add (suite, TESTCASE (test_ccwa_indication, NULL));
+ g_test_suite_add (suite, TESTCASE (test_ccwa_response, NULL));
g_test_suite_add (suite, TESTCASE (test_clcc_response_empty, NULL));
g_test_suite_add (suite, TESTCASE (test_clcc_response_single, NULL));