api,call: new Deflect() method

This method allows deflecting an incoming or waiting call to a
different number.
This commit is contained in:
Aleksander Morgado
2019-07-01 15:21:18 +02:00
parent 81f1483eec
commit 222874299e
8 changed files with 304 additions and 5 deletions

View File

@@ -46,11 +46,12 @@ typedef struct {
static Context *ctx; static Context *ctx;
/* Options */ /* Options */
static gboolean info_flag; /* set when no action found */ static gboolean info_flag; /* set when no action found */
static gboolean start_flag; static gboolean start_flag;
static gboolean accept_flag; static gboolean accept_flag;
static gboolean hangup_flag; static gchar *deflect_str;
static gchar *dtmf_request; static gboolean hangup_flag;
static gchar *dtmf_request;
static GOptionEntry entries[] = { static GOptionEntry entries[] = {
{ "start", 0, 0, G_OPTION_ARG_NONE, &start_flag, { "start", 0, 0, G_OPTION_ARG_NONE, &start_flag,
@@ -61,6 +62,10 @@ static GOptionEntry entries[] = {
"Accept the incoming call", "Accept the incoming call",
NULL, NULL,
}, },
{ "deflect", 0, 0, G_OPTION_ARG_STRING, &deflect_str,
"Deflect the incoming call",
"[NUMBER]",
},
{ "hangup", 0, 0, G_OPTION_ARG_NONE, &hangup_flag, { "hangup", 0, 0, G_OPTION_ARG_NONE, &hangup_flag,
"Hang up the call", "Hang up the call",
NULL, NULL,
@@ -99,6 +104,7 @@ mmcli_call_options_enabled (void)
n_actions = (start_flag + n_actions = (start_flag +
accept_flag + accept_flag +
!!deflect_str +
hangup_flag + hangup_flag +
!!dtmf_request); !!dtmf_request);
@@ -227,6 +233,33 @@ accept_ready (MMCall *call,
mmcli_async_operation_done (); mmcli_async_operation_done ();
} }
static void
deflect_process_reply (gboolean result,
const GError *error)
{
if (!result) {
g_printerr ("error: couldn't deflect the call: '%s'\n",
error ? error->message : "unknown error");
exit (EXIT_FAILURE);
}
g_print ("successfully deflected the call\n");
}
static void
deflect_ready (MMCall *call,
GAsyncResult *result,
gpointer nothing)
{
gboolean operation_result;
GError *error = NULL;
operation_result = mm_call_deflect_finish (call, result, &error);
deflect_process_reply (operation_result, error);
mmcli_async_operation_done ();
}
static void static void
hangup_process_reply (gboolean result, hangup_process_reply (gboolean result,
const GError *error) const GError *error)
@@ -313,6 +346,16 @@ get_call_ready (GObject *source,
return; return;
} }
/* Requesting to deflect the call? */
if (deflect_str) {
mm_call_deflect (ctx->call,
deflect_str,
ctx->cancellable,
(GAsyncReadyCallback)deflect_ready,
NULL);
return;
}
/* Requesting to hangup the call? */ /* Requesting to hangup the call? */
if (hangup_flag) { if (hangup_flag) {
mm_call_hangup (ctx->call, mm_call_hangup (ctx->call,
@@ -398,6 +441,18 @@ mmcli_call_run_synchronous (GDBusConnection *connection)
return; return;
} }
/* Requesting to deflect the call? */
if (deflect_str) {
gboolean operation_result;
operation_result = mm_call_deflect_sync (ctx->call,
deflect_str,
NULL,
&error);
deflect_process_reply (operation_result, error);
return;
}
/* Requesting to hangup the call? */ /* Requesting to hangup the call? */
if (hangup_flag) { if (hangup_flag) {
gboolean operation_result; gboolean operation_result;

View File

@@ -1345,6 +1345,9 @@ mm_call_hangup_sync
mm_call_send_dtmf mm_call_send_dtmf
mm_call_send_dtmf_finish mm_call_send_dtmf_finish
mm_call_send_dtmf_sync mm_call_send_dtmf_sync
mm_call_deflect
mm_call_deflect_finish
mm_call_deflect_sync
<SUBSECTION Standard> <SUBSECTION Standard>
MMCallClass MMCallClass
MMCallPrivate MMCallPrivate
@@ -3256,6 +3259,9 @@ mm_gdbus_call_call_hangup_sync
mm_gdbus_call_call_send_dtmf mm_gdbus_call_call_send_dtmf
mm_gdbus_call_call_send_dtmf_finish mm_gdbus_call_call_send_dtmf_finish
mm_gdbus_call_call_send_dtmf_sync mm_gdbus_call_call_send_dtmf_sync
mm_gdbus_call_call_deflect
mm_gdbus_call_call_deflect_finish
mm_gdbus_call_call_deflect_sync
<SUBSECTION Private> <SUBSECTION Private>
mm_gdbus_call_set_direction mm_gdbus_call_set_direction
mm_gdbus_call_set_number mm_gdbus_call_set_number
@@ -3267,6 +3273,7 @@ mm_gdbus_call_complete_accept
mm_gdbus_call_complete_hangup mm_gdbus_call_complete_hangup
mm_gdbus_call_complete_send_dtmf mm_gdbus_call_complete_send_dtmf
mm_gdbus_call_complete_start mm_gdbus_call_complete_start
mm_gdbus_call_complete_deflect
mm_gdbus_call_interface_info mm_gdbus_call_interface_info
mm_gdbus_call_override_properties mm_gdbus_call_override_properties
mm_gdbus_call_emit_dtmf_received mm_gdbus_call_emit_dtmf_received

View File

@@ -1387,6 +1387,7 @@ typedef enum { /*< underscore_name=mm_call_state >*/
* @MM_CALL_STATE_REASON_ERROR: Wrong number or generic network error. * @MM_CALL_STATE_REASON_ERROR: Wrong number or generic network error.
* @MM_CALL_STATE_REASON_AUDIO_SETUP_FAILED: Error setting up audio channel. * @MM_CALL_STATE_REASON_AUDIO_SETUP_FAILED: Error setting up audio channel.
* @MM_CALL_STATE_REASON_TRANSFERRED: Call has been transferred. Since 1.12. * @MM_CALL_STATE_REASON_TRANSFERRED: Call has been transferred. Since 1.12.
* @MM_CALL_STATE_REASON_DEFLECTED: Call has been deflected to a new number. Since 1.12.
* *
* Reason for the state change in the call. * Reason for the state change in the call.
*/ */
@@ -1400,6 +1401,7 @@ typedef enum { /*< underscore_name=mm_call_state_reason >*/
MM_CALL_STATE_REASON_ERROR = 6, MM_CALL_STATE_REASON_ERROR = 6,
MM_CALL_STATE_REASON_AUDIO_SETUP_FAILED = 7, MM_CALL_STATE_REASON_AUDIO_SETUP_FAILED = 7,
MM_CALL_STATE_REASON_TRANSFERRED = 8, MM_CALL_STATE_REASON_TRANSFERRED = 8,
MM_CALL_STATE_REASON_DEFLECTED = 9,
} MMCallStateReason; } MMCallStateReason;
/** /**

View File

@@ -37,6 +37,21 @@
--> -->
<method name="Accept" /> <method name="Accept" />
<!--
Deflect:
@number: new number where the call will be deflected.
Deflect an incoming or waiting call to a new number. This call will be
considered terminated once the deflection is performed.
Applicable only if state is <link linkend="MM-CALL-STATE-RINGING-IN:CAPS"><constant>MM_CALL_STATE_RINGING_IN</constant></link> or
<link linkend="MM-CALL-STATE-WAITING:CAPS"><constant>MM_CALL_STATE_WAITING</constant></link> and direction is
<link linkend="MM-CALL-DIRECTION-INCOMING:CAPS"><constant>MM_CALL_DIRECTION_INCOMING</constant></link>.
-->
<method name="Deflect">
<arg name="number" type="s" />
</method>
<!-- <!--
Hangup: Hangup:

View File

@@ -491,6 +491,91 @@ mm_call_accept_sync (MMCall *self,
/*****************************************************************************/ /*****************************************************************************/
/**
* mm_call_deflect_finish:
* @self: A #MMCall.
* @res: The #GAsyncResult obtained from the #GAsyncReadyCallback passed to mm_call_deflect().
* @error: Return location for error or %NULL.
*
* Finishes an operation started with mm_call_deflect().
*
* Returns: %TRUE if the operation succeeded, %FALSE if @error is set.
*/
gboolean
mm_call_deflect_finish (MMCall *self,
GAsyncResult *res,
GError **error)
{
g_return_val_if_fail (MM_IS_CALL (self), FALSE);
return mm_gdbus_call_call_deflect_finish (MM_GDBUS_CALL (self), res, error);
}
/**
* mm_call_deflect:
* @self: A #MMCall.
* @number: new number where the call will be deflected.
* @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.
*
* Asynchronously requests to deflect the incoming call.
*
* This call will be considered terminated once the deflection is performed.
*
* When the operation is finished, @callback will be invoked in the <link linkend="g-main-context-push-thread-default">thread-default main loop</link> of the thread you are calling this method from.
* You can then call mm_call_deflect_finish() to get the result of the operation.
*
* See mm_call_deflect_sync() for the synchronous, blocking version of this method.
*/
void
mm_call_deflect (MMCall *self,
const gchar *number,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
g_return_if_fail (MM_IS_CALL (self));
mm_gdbus_call_call_deflect (MM_GDBUS_CALL (self),
number,
cancellable,
callback,
user_data);
}
/**
* mm_call_deflect_sync:
* @self: A #MMCall.
* @number: new number where the call will be deflected.
* @cancellable: (allow-none): A #GCancellable or %NULL.
* @error: Return location for error or %NULL.
*
* Synchronously requests to deflect the incoming call.
*
* This call will be considered terminated once the deflection is performed.
*
* The calling thread is blocked until an incoming call is ready.
* See mm_call_deflect() for the asynchronous version of this method.
*
* Returns: %TRUE if the operation succeeded, %FALSE if @error is set.
*/
gboolean
mm_call_deflect_sync (MMCall *self,
const gchar *number,
GCancellable *cancellable,
GError **error)
{
g_return_val_if_fail (MM_IS_CALL (self), FALSE);
return mm_gdbus_call_call_deflect_sync (MM_GDBUS_CALL (self),
number,
cancellable,
error);
}
/*****************************************************************************/
/** /**
* mm_call_hangup_finish: * mm_call_hangup_finish:
* @self: A #MMCall. * @self: A #MMCall.

View File

@@ -110,6 +110,21 @@ gboolean mm_call_accept_sync (MMCall *self,
GCancellable *cancellable, GCancellable *cancellable,
GError **error); GError **error);
void mm_call_deflect (MMCall *self,
const gchar *number,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
gboolean mm_call_deflect_finish (MMCall *self,
GAsyncResult *res,
GError **error);
gboolean mm_call_deflect_sync (MMCall *self,
const gchar *number,
GCancellable *cancellable,
GError **error);
void mm_call_hangup (MMCall *self, void mm_call_hangup (MMCall *self,
GCancellable *cancellable, GCancellable *cancellable,

View File

@@ -511,7 +511,114 @@ handle_accept (MMBaseCall *self,
} }
/*****************************************************************************/ /*****************************************************************************/
/* Deflect call (DBus call handling) */
typedef struct {
MMBaseCall *self;
MMBaseModem *modem;
GDBusMethodInvocation *invocation;
gchar *number;
} HandleDeflectContext;
static void
handle_deflect_context_free (HandleDeflectContext *ctx)
{
g_free (ctx->number);
g_object_unref (ctx->invocation);
g_object_unref (ctx->modem);
g_object_unref (ctx->self);
g_slice_free (HandleDeflectContext, ctx);
}
static void
handle_deflect_ready (MMBaseCall *self,
GAsyncResult *res,
HandleDeflectContext *ctx)
{
GError *error = NULL;
if (!MM_BASE_CALL_GET_CLASS (self)->deflect_finish (self, res, &error)) {
mm_base_call_change_state (self, MM_CALL_STATE_TERMINATED, MM_CALL_STATE_REASON_ERROR);
g_dbus_method_invocation_take_error (ctx->invocation, error);
handle_deflect_context_free (ctx);
return;
}
mm_info ("call is deflected to '%s'", ctx->number);
mm_base_call_change_state (ctx->self, MM_CALL_STATE_TERMINATED, MM_CALL_STATE_REASON_DEFLECTED);
mm_gdbus_call_complete_deflect (MM_GDBUS_CALL (ctx->self), ctx->invocation);
handle_deflect_context_free (ctx);
}
static void
handle_deflect_auth_ready (MMBaseModem *modem,
GAsyncResult *res,
HandleDeflectContext *ctx)
{
MMCallState state;
GError *error = NULL;
if (!mm_base_modem_authorize_finish (modem, res, &error)) {
g_dbus_method_invocation_take_error (ctx->invocation, error);
handle_deflect_context_free (ctx);
return;
}
state = mm_gdbus_call_get_state (MM_GDBUS_CALL (ctx->self));
/* We can only deflect incoming call in ringing or waiting state */
if (state != MM_CALL_STATE_RINGING_IN && state != MM_CALL_STATE_WAITING) {
g_dbus_method_invocation_return_error (ctx->invocation,
MM_CORE_ERROR,
MM_CORE_ERROR_FAILED,
"This call was not ringing/waiting, cannot deflect");
handle_deflect_context_free (ctx);
return;
}
mm_info ("user request to deflect call");
/* Check if we do support doing it */
if (!MM_BASE_CALL_GET_CLASS (ctx->self)->deflect ||
!MM_BASE_CALL_GET_CLASS (ctx->self)->deflect_finish) {
g_dbus_method_invocation_return_error (ctx->invocation,
MM_CORE_ERROR,
MM_CORE_ERROR_UNSUPPORTED,
"Deflecting call is not supported by this modem");
handle_deflect_context_free (ctx);
return;
}
MM_BASE_CALL_GET_CLASS (ctx->self)->deflect (ctx->self,
ctx->number,
(GAsyncReadyCallback)handle_deflect_ready,
ctx);
}
static gboolean
handle_deflect (MMBaseCall *self,
GDBusMethodInvocation *invocation,
const gchar *number)
{
HandleDeflectContext *ctx;
ctx = g_slice_new0 (HandleDeflectContext);
ctx->self = g_object_ref (self);
ctx->invocation = g_object_ref (invocation);
ctx->number = g_strdup (number);
g_object_get (self,
MM_BASE_CALL_MODEM, &ctx->modem,
NULL);
mm_base_modem_authorize (ctx->modem,
invocation,
MM_AUTHORIZATION_VOICE,
(GAsyncReadyCallback)handle_deflect_auth_ready,
ctx);
return TRUE;
}
/*****************************************************************************/
/* Hangup call (DBus call handling) */ /* Hangup call (DBus call handling) */
typedef struct { typedef struct {
@@ -755,6 +862,10 @@ call_dbus_export (MMBaseCall *self)
"handle-accept", "handle-accept",
G_CALLBACK (handle_accept), G_CALLBACK (handle_accept),
NULL); NULL);
g_signal_connect (self,
"handle-deflect",
G_CALLBACK (handle_deflect),
NULL);
g_signal_connect (self, g_signal_connect (self,
"handle-hangup", "handle-hangup",
G_CALLBACK (handle_hangup), G_CALLBACK (handle_hangup),

View File

@@ -67,6 +67,15 @@ struct _MMBaseCallClass {
GAsyncResult *res, GAsyncResult *res,
GError **error); GError **error);
/* Deflect the call */
void (* deflect) (MMBaseCall *self,
const gchar *number,
GAsyncReadyCallback callback,
gpointer user_data);
gboolean (* deflect_finish) (MMBaseCall *self,
GAsyncResult *res,
GError **error);
/* Hangup the call */ /* Hangup the call */
void (* hangup) (MMBaseCall *self, void (* hangup) (MMBaseCall *self,
GAsyncReadyCallback callback, GAsyncReadyCallback callback,