diff --git a/apps/app_attended_transfer.c b/apps/app_attended_transfer.c new file mode 100644 index 0000000000000000000000000000000000000000..df8d83cd9b59eb4292f623cca83248c5c67e07e4 --- /dev/null +++ b/apps/app_attended_transfer.c @@ -0,0 +1,143 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2019, Alexei Gradinari + * + * Alexei Gradinari <alex2grad@gmail.com> + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ + +/*! \file + * + * \brief Attended transfer by caller channel + * + * \author Alexei Gradinari <alex2grad@gmail.com> + * + * \ingroup applications + */ + +/*** MODULEINFO + <support_level>extended</support_level> + ***/ + +#include "asterisk.h" + +#include "asterisk/pbx.h" +#include "asterisk/module.h" +#include "asterisk/app.h" +#include "asterisk/channel.h" +#include "asterisk/bridge.h" +#include "asterisk/features_config.h" + +/*** DOCUMENTATION + <application name="AttendedTransfer" language="en_US"> + <synopsis> + Attended transfer to the extension provided and TRANSFER_CONTEXT + </synopsis> + <syntax> + <parameter name="exten" required="true"> + <para>Specify extension.</para> + </parameter> + </syntax> + <description> + <para>Queue up attended transfer to the specified extension in the <literal>TRANSFER_CONTEXT</literal>.</para> + <para>Note that the attended transfer only work when two channels have answered and are bridged together.</para> + <para>Make sure to set Attended Transfer DTMF feature <literal>atxfer</literal> + and attended transfer is permitted.</para> + <para>The result of the application will be reported in the <variable>ATTENDEDTRANSFERSTATUS</variable> + channel variable:</para> + <variablelist> + <variable name="ATTENDEDTRANSFERSTATUS"> + <value name="SUCCESS"> + Transfer successfully queued. + </value> + <value name="FAILURE"> + Transfer failed. + </value> + <value name="NOTPERMITTED"> + Transfer not permitted. + </value> + </variable> + </variablelist> + </description> + </application> + ***/ + +static const char * const app = "AttendedTransfer"; + +static int attended_transfer_exec(struct ast_channel *chan, const char *data) +{ + char *exten = NULL; + const char *context = NULL; + char *parse; + AST_DECLARE_APP_ARGS(args, + AST_APP_ARG(exten); + ); + char feature_code[AST_FEATURE_MAX_LEN]; + const char *digit; + struct ast_frame f = { .frametype = AST_FRAME_DTMF }; + + if (ast_strlen_zero((char *)data)) { + ast_log(LOG_WARNING, "%s requires an argument (exten)\n", app); + pbx_builtin_setvar_helper(chan, "ATTENDEDTRANSFERSTATUS", "FAILURE"); + return 0; + } + + context = pbx_builtin_getvar_helper(chan, "TRANSFER_CONTEXT"); + if (ast_strlen_zero(context)) { + pbx_builtin_setvar_helper(chan, "ATTENDEDTRANSFERSTATUS", "NOTPERMITTED"); + return 0; + } + + ast_channel_lock(chan); + if (ast_get_builtin_feature(chan, "atxfer", feature_code, sizeof(feature_code)) || + ast_strlen_zero(feature_code)) { + pbx_builtin_setvar_helper(chan, "ATTENDEDTRANSFERSTATUS", "NOTPERMITTED"); + ast_channel_unlock(chan); + return 0; + } + ast_channel_unlock(chan); + + parse = ast_strdupa(data); + AST_STANDARD_APP_ARGS(args, parse); + + exten = args.exten; + + for (digit = feature_code; *digit; ++digit) { + f.subclass.integer = *digit; + ast_queue_frame(chan, &f); + } + + for (digit = exten; *digit; ++digit) { + f.subclass.integer = *digit; + ast_queue_frame(chan, &f); + } + + f.subclass.integer = '#'; + ast_queue_frame(chan, &f); + + pbx_builtin_setvar_helper(chan, "ATTENDEDTRANSFERSTATUS", "SUCCESS"); + + return 0; +} + +static int unload_module(void) +{ + return ast_unregister_application(app); +} + +static int load_module(void) +{ + return ast_register_application_xml(app, attended_transfer_exec); +} + +AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Attended transfer to the given extension"); diff --git a/doc/CHANGES-staging/app_attended_transfer.txt b/doc/CHANGES-staging/app_attended_transfer.txt new file mode 100644 index 0000000000000000000000000000000000000000..97929e4b08d0778870595807a493c51ce1238ae4 --- /dev/null +++ b/doc/CHANGES-staging/app_attended_transfer.txt @@ -0,0 +1,3 @@ +Subject: AttendedTransfer + +A new application, this will queue up attended transfer to the given extension. diff --git a/menuselect/example_menuselect-tree b/menuselect/example_menuselect-tree index be07fda30f46b6530fd2a5648af727d6136eb97b..83441b1ce9586d39947d87efa3d7ae659c3d2050 100644 --- a/menuselect/example_menuselect-tree +++ b/menuselect/example_menuselect-tree @@ -8,6 +8,8 @@ </member> <member name="app_amd" displayname="Answering Machine Detection Application" remove_on_change="apps/app_amd.o apps/app_amd.so"> </member> + <member name="app_attended_transfer" displayname="Attended transfer to the given extension" remove_on_change="apps/app_attended_transfer.o apps/app_attended_transfer.so"> + </member> <member name="app_authenticate" displayname="Authentication Application" remove_on_change="apps/app_authenticate.o apps/app_authenticate.so"> </member> <member name="app_blind_transfer" displayname="Blind transfer by caller channel" remove_on_change="apps/app_blind_transfer.o apps/app_blind_transfer.so"> diff --git a/menuselect/test/menuselect-tree b/menuselect/test/menuselect-tree index ac69e90f1450f9c9212cb14bb031fe250e0acecb..4c541b50617721fb33f0f4ca22f15286cee384cd 100644 --- a/menuselect/test/menuselect-tree +++ b/menuselect/test/menuselect-tree @@ -9,6 +9,8 @@ </member> <member name="app_amd" displayname="Answering Machine Detection Application" remove_on_change="apps/app_amd.o apps/app_amd.so"> </member> +<member name="app_attended_transfer" displayname="Attended transfer to the given extension" remove_on_change="apps/app_attended_transfer.o apps/app_attended_transfer.so"> +</member> <member name="app_authenticate" displayname="Authentication Application" remove_on_change="apps/app_authenticate.o apps/app_authenticate.so"> </member> <member name="app_blind_transfer" displayname="Blind transfer by caller channel" remove_on_change="apps/app_blind_transfer.o apps/app_blind_transfer.so">