<p>N A has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.asterisk.org/c/asterisk/+/18001">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">features: Add transfer initiation options.<br><br>Adds additional control options over the transfer<br>feature functionality to give users more control<br>in how the transfer feature sounds and works.<br><br>The "transfer" sound that plays when a transfer is<br>initiated can now be customized in the user in<br>features.conf, just as with the other transfer sounds.<br><br>Secondly, the user can now specify the transfer extension<br>in advance by using the TRANSFER_EXTEN variable. If<br>a valid extension is contained in this variable, the call<br>will automatically be transferred to this destination.<br>Otherwise, it will fall back to collecting the extension<br>from the user as is always done now.<br><br>ASTERISK-29899 #close<br><br>Change-Id: Ibff309caa459a2b958706f2ed0ca393b1ef502e3<br>---<br>M configs/samples/features.conf.sample<br>A doc/CHANGES-staging/transfer.txt<br>M include/asterisk/features_config.h<br>M main/bridge_basic.c<br>M main/features_config.c<br>5 files changed, 75 insertions(+), 15 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://gerrit.asterisk.org:29418/asterisk refs/changes/01/18001/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/configs/samples/features.conf.sample b/configs/samples/features.conf.sample</span><br><span>index afdcf5a..c3bfd19 100644</span><br><span>--- a/configs/samples/features.conf.sample</span><br><span>+++ b/configs/samples/features.conf.sample</span><br><span>@@ -26,6 +26,7 @@</span><br><span>                                 ; By default, this is 2.</span><br><span> ;transferdialattempts = 3       ; Number of times that a transferer may attempt to dial an extension before</span><br><span>                                 ; being kicked back to the original call.</span><br><span style="color: hsl(120, 100%, 40%);">+;transferannouncesound = beep   ; Sound to play to a transferer to indicate transfer process has begun. If empty, no sound will be played.</span><br><span> ;transferretrysound = beep      ; Sound to play when a transferer fails to dial a valid extension.</span><br><span> ;transferinvalidsound = beeperr ; Sound to play when a transferer fails to dial a valid extension and is out of retries.</span><br><span> ;atxferabort = *1               ; cancel the attended transfer</span><br><span>diff --git a/doc/CHANGES-staging/transfer.txt b/doc/CHANGES-staging/transfer.txt</span><br><span>new file mode 100644</span><br><span>index 0000000..6f5247b</span><br><span>--- /dev/null</span><br><span>+++ b/doc/CHANGES-staging/transfer.txt</span><br><span>@@ -0,0 +1,12 @@</span><br><span style="color: hsl(120, 100%, 40%);">+Subject: Transfer feature</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+The following capabilities have been added to the</span><br><span style="color: hsl(120, 100%, 40%);">+transfer feature:</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+- The transfer initiation announcement prompt can</span><br><span style="color: hsl(120, 100%, 40%);">+now be customized in features.conf.</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+- The TRANSFER_EXTEN variable now can be used to</span><br><span style="color: hsl(120, 100%, 40%);">+allow the transfer function to automatically</span><br><span style="color: hsl(120, 100%, 40%);">+attempt to go to the extension contained in this</span><br><span style="color: hsl(120, 100%, 40%);">+variable, if it exists.</span><br><span>diff --git a/include/asterisk/features_config.h b/include/asterisk/features_config.h</span><br><span>index 5253369..336454b 100644</span><br><span>--- a/include/asterisk/features_config.h</span><br><span>+++ b/include/asterisk/features_config.h</span><br><span>@@ -72,6 +72,8 @@</span><br><span>               AST_STRING_FIELD(transferretrysound);</span><br><span>                /*! Sound played when an invalid extension is dialed, and the transferer is being returned to the call. */</span><br><span>           AST_STRING_FIELD(transferinvalidsound);</span><br><span style="color: hsl(120, 100%, 40%);">+               /*! Sound to play to announce the transfer process has started. */</span><br><span style="color: hsl(120, 100%, 40%);">+            AST_STRING_FIELD(transferannouncesound);</span><br><span>     );</span><br><span>   /*! Seconds allowed between digit presses when dialing transfer destination */</span><br><span>       unsigned int transferdigittimeout;</span><br><span>diff --git a/main/bridge_basic.c b/main/bridge_basic.c</span><br><span>index df21195..e2099ba 100644</span><br><span>--- a/main/bridge_basic.c</span><br><span>+++ b/main/bridge_basic.c</span><br><span>@@ -1398,6 +1398,27 @@</span><br><span> }</span><br><span> </span><br><span> /*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \internal</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Determine the transfer extension to use.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param transferer Channel initiating the transfer.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param extension User supplied extension if available.  May be NULL.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \return The extension to use for the transfer.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+static const char *get_transfer_exten(struct ast_channel *transferer, const char *exten)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!ast_strlen_zero(exten)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                return exten;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+     exten = pbx_builtin_getvar_helper(transferer, "TRANSFER_EXTEN");</span><br><span style="color: hsl(120, 100%, 40%);">+    if (!ast_strlen_zero(exten)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                return exten;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+     return ""; /* empty default, to get transfer extension from user now */</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span>  * \brief Allocate and initialize attended transfer properties</span><br><span>  *</span><br><span>  * \param transferer The channel performing the attended transfer</span><br><span>@@ -1452,6 +1473,7 @@</span><br><span>     props->atxfernoanswertimeout = xfer_cfg->atxfernoanswertimeout;</span><br><span>        props->atxferloopdelay = xfer_cfg->atxferloopdelay;</span><br><span>    ast_string_field_set(props, context, get_transfer_context(transferer, context));</span><br><span style="color: hsl(120, 100%, 40%);">+      ast_string_field_set(props, exten, get_transfer_exten(transferer, NULL));</span><br><span>    ast_string_field_set(props, xfersound, xfer_cfg->xfersound);</span><br><span>      ao2_ref(xfer_cfg, -1);</span><br><span> </span><br><span>@@ -3155,16 +3177,26 @@</span><br><span>  * \retval 0 on success</span><br><span>  * \retval -1 on failure</span><br><span>  */</span><br><span style="color: hsl(0, 100%, 40%);">-static int grab_transfer(struct ast_channel *chan, char *exten, size_t exten_len, const char *context)</span><br><span style="color: hsl(120, 100%, 40%);">+static int grab_transfer(struct ast_channel *chan, char *exten, size_t exten_len, const char *context, const char *extenoverride)</span><br><span> {</span><br><span>     int res;</span><br><span>     int digit_timeout;</span><br><span>   int attempts = 0;</span><br><span>    int max_attempts;</span><br><span>    struct ast_features_xfer_config *xfer_cfg;</span><br><span style="color: hsl(0, 100%, 40%);">-      char *retry_sound;</span><br><span style="color: hsl(0, 100%, 40%);">-      char *invalid_sound;</span><br><span style="color: hsl(120, 100%, 40%);">+  char *announce_sound, *retry_sound, *invalid_sound;</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+       if (!ast_strlen_zero(extenoverride)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                int extenres = ast_exists_extension(chan, context, extenoverride, 1,</span><br><span style="color: hsl(120, 100%, 40%);">+                  S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL)) ? 1 : 0;</span><br><span style="color: hsl(120, 100%, 40%);">+               if (extenres) {</span><br><span style="color: hsl(120, 100%, 40%);">+                       ast_copy_string(exten, extenoverride, exten_len);</span><br><span style="color: hsl(120, 100%, 40%);">+                     ast_verb(3, "Transfering call to '%s@%s'", exten, context);</span><br><span style="color: hsl(120, 100%, 40%);">+                 return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+             }</span><br><span style="color: hsl(120, 100%, 40%);">+             ast_log(LOG_WARNING, "Override extension '%s' does not exist in context '%s'\n", extenoverride, context);</span><br><span style="color: hsl(120, 100%, 40%);">+           /* since we didn't get a valid extension from the channel, fall back and grab it from the user as usual now */</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span>    ast_channel_lock(chan);</span><br><span>      xfer_cfg = ast_get_chan_features_xfer_config(chan);</span><br><span>  if (!xfer_cfg) {</span><br><span>@@ -3175,21 +3207,24 @@</span><br><span>   }</span><br><span>    digit_timeout = xfer_cfg->transferdigittimeout * 1000;</span><br><span>    max_attempts = xfer_cfg->transferdialattempts;</span><br><span style="color: hsl(120, 100%, 40%);">+     announce_sound = ast_strdupa(xfer_cfg->transferannouncesound);</span><br><span>    retry_sound = ast_strdupa(xfer_cfg->transferretrysound);</span><br><span>  invalid_sound = ast_strdupa(xfer_cfg->transferinvalidsound);</span><br><span>      ao2_ref(xfer_cfg, -1);</span><br><span>       ast_channel_unlock(chan);</span><br><span> </span><br><span>        /* Play the simple "transfer" prompt out and wait */</span><br><span style="color: hsl(0, 100%, 40%);">-  res = ast_stream_and_wait(chan, "pbx-transfer", AST_DIGIT_ANY);</span><br><span style="color: hsl(0, 100%, 40%);">-       ast_stopstream(chan);</span><br><span style="color: hsl(0, 100%, 40%);">-   if (res < 0) {</span><br><span style="color: hsl(0, 100%, 40%);">-               /* Hangup or error */</span><br><span style="color: hsl(0, 100%, 40%);">-           return -1;</span><br><span style="color: hsl(0, 100%, 40%);">-      }</span><br><span style="color: hsl(0, 100%, 40%);">-       if (res) {</span><br><span style="color: hsl(0, 100%, 40%);">-              /* Store the DTMF digit that interrupted playback of the file. */</span><br><span style="color: hsl(0, 100%, 40%);">-               exten[0] = res;</span><br><span style="color: hsl(120, 100%, 40%);">+       if (!ast_strlen_zero(announce_sound)) {</span><br><span style="color: hsl(120, 100%, 40%);">+               res = ast_stream_and_wait(chan, announce_sound, AST_DIGIT_ANY);</span><br><span style="color: hsl(120, 100%, 40%);">+               ast_stopstream(chan);</span><br><span style="color: hsl(120, 100%, 40%);">+         if (res < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                     /* Hangup or error */</span><br><span style="color: hsl(120, 100%, 40%);">+                 return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+            }</span><br><span style="color: hsl(120, 100%, 40%);">+             if (res) {</span><br><span style="color: hsl(120, 100%, 40%);">+                    /* Store the DTMF digit that interrupted playback of the file. */</span><br><span style="color: hsl(120, 100%, 40%);">+                     exten[0] = res;</span><br><span style="color: hsl(120, 100%, 40%);">+               }</span><br><span>    }</span><br><span> </span><br><span>        /* Drop to dialtone so they can enter the extension they want to transfer to */</span><br><span>@@ -3348,7 +3383,7 @@</span><br><span>      ast_bridge_channel_write_hold(bridge_channel, NULL);</span><br><span> </span><br><span>     /* Grab the extension to transfer to */</span><br><span style="color: hsl(0, 100%, 40%);">- if (grab_transfer(bridge_channel->chan, exten, sizeof(exten), props->context)) {</span><br><span style="color: hsl(120, 100%, 40%);">+        if (grab_transfer(bridge_channel->chan, exten, sizeof(exten), props->context, props->exten)) {</span><br><span>              /*</span><br><span>            * This is a normal exit for when the user fails</span><br><span>              * to specify a valid transfer target.  e.g., The user</span><br><span>@@ -3470,7 +3505,7 @@</span><br><span> {</span><br><span>  char xfer_exten[AST_MAX_EXTENSION] = "";</span><br><span>   struct ast_bridge_features_blind_transfer *blind_transfer = hook_pvt;</span><br><span style="color: hsl(0, 100%, 40%);">-   const char *xfer_context;</span><br><span style="color: hsl(120, 100%, 40%);">+     const char *xfer_context, *xfer_exten_override;</span><br><span>      char *goto_on_blindxfer;</span><br><span> </span><br><span>         ast_verb(3, "Channel %s: Started DTMF blind transfer.\n",</span><br><span>@@ -3481,12 +3516,13 @@</span><br><span>        ast_channel_lock(bridge_channel->chan);</span><br><span>   xfer_context = ast_strdupa(get_transfer_context(bridge_channel->chan,</span><br><span>             blind_transfer ? blind_transfer->context : NULL));</span><br><span style="color: hsl(120, 100%, 40%);">+ xfer_exten_override = ast_strdupa(get_transfer_exten(bridge_channel->chan, NULL));</span><br><span>        goto_on_blindxfer = ast_strdupa(S_OR(pbx_builtin_getvar_helper(bridge_channel->chan,</span><br><span>              "GOTO_ON_BLINDXFR"), ""));</span><br><span>       ast_channel_unlock(bridge_channel->chan);</span><br><span> </span><br><span>     /* Grab the extension to transfer to */</span><br><span style="color: hsl(0, 100%, 40%);">- if (grab_transfer(bridge_channel->chan, xfer_exten, sizeof(xfer_exten), xfer_context)) {</span><br><span style="color: hsl(120, 100%, 40%);">+   if (grab_transfer(bridge_channel->chan, xfer_exten, sizeof(xfer_exten), xfer_context, xfer_exten_override)) {</span><br><span>             ast_bridge_channel_write_unhold(bridge_channel);</span><br><span>             return 0;</span><br><span>    }</span><br><span>diff --git a/main/features_config.c b/main/features_config.c</span><br><span>index 50ca69b..d91d97f 100644</span><br><span>--- a/main/features_config.c</span><br><span>+++ b/main/features_config.c</span><br><span>@@ -143,6 +143,9 @@</span><br><span>                                 <configOption name="transferinvalidsound" default="privacy-incorrect"></span><br><span>                                     <synopsis>Sound that is played when an incorrect extension is dialed and the transferer has no attempts remaining.</synopsis></span><br><span>                            </configOption></span><br><span style="color: hsl(120, 100%, 40%);">+                         <configOption name="transferannouncesound" default="pbx-transfer"></span><br><span style="color: hsl(120, 100%, 40%);">+                                  <synopsis>Sound that is played to the transferer when a transfer is initiated. If empty, no sound will be played.</synopsis></span><br><span style="color: hsl(120, 100%, 40%);">+                              </configOption></span><br><span>                        </configObject></span><br><span>                        <configObject name="featuremap"></span><br><span>                             <synopsis>DTMF options that can be triggered during bridged calls</synopsis></span><br><span>@@ -320,6 +323,7 @@</span><br><span>                                       <enum name="transferdialattempts"><para><xi:include xpointer="xpointer(/docs/configInfo[@name='features']/configFile[@name='features.conf']/configObject[@name='globals']/configOption[@name='transferdialattempts']/synopsis/text())" /></para></enum></span><br><span>                                    <enum name="transferretrysound"><para><xi:include xpointer="xpointer(/docs/configInfo[@name='features']/configFile[@name='features.conf']/configObject[@name='globals']/configOption[@name='transferretrysound']/synopsis/text())" /></para></enum></span><br><span>                                        <enum name="transferinvalidsound"><para><xi:include xpointer="xpointer(/docs/configInfo[@name='features']/configFile[@name='features.conf']/configObject[@name='globals']/configOption[@name='transferinvalidsound']/synopsis/text())" /></para></enum></span><br><span style="color: hsl(120, 100%, 40%);">+                                     <enum name="transferannouncesound"><para><xi:include xpointer="xpointer(/docs/configInfo[@name='features']/configFile[@name='features.conf']/configObject[@name='globals']/configOption[@name='transferannouncesound']/synopsis/text())" /></para></enum></span><br><span>                          </enumlist></span><br><span>                    </parameter></span><br><span>           </syntax></span><br><span>@@ -383,6 +387,7 @@</span><br><span> #define DEFAULT_TRANSFER_DIAL_ATTEMPTS              3</span><br><span> #define DEFAULT_TRANSFER_RETRY_SOUND                "pbx-invalid"</span><br><span> #define DEFAULT_TRANSFER_INVALID_SOUND              "privacy-incorrect"</span><br><span style="color: hsl(120, 100%, 40%);">+#define DEFAULT_TRANSFER_ANNOUNCE_SOUND             "pbx-transfer"</span><br><span> </span><br><span> /*! Default pickup options */</span><br><span> #define DEFAULT_PICKUPEXTEN                         "*8"</span><br><span>@@ -906,6 +911,8 @@</span><br><span>            ast_string_field_set(xfer, transferretrysound, value);</span><br><span>       } else if (!strcasecmp(name, "transferinvalidsound")) {</span><br><span>            ast_string_field_set(xfer, transferinvalidsound, value);</span><br><span style="color: hsl(120, 100%, 40%);">+      } else if (!strcasecmp(name, "transferannouncesound")) {</span><br><span style="color: hsl(120, 100%, 40%);">+            ast_string_field_set(xfer, transferannouncesound, value);</span><br><span>    } else {</span><br><span>             /* Unrecognized option */</span><br><span>            res = -1;</span><br><span>@@ -1797,6 +1804,8 @@</span><br><span>                    DEFAULT_TRANSFER_RETRY_SOUND, xfer_handler, 0);</span><br><span>      aco_option_register_custom(&cfg_info, "transferinvalidsound", ACO_EXACT, global_options,</span><br><span>                       DEFAULT_TRANSFER_INVALID_SOUND, xfer_handler, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+     aco_option_register_custom(&cfg_info, "transferannouncesound", ACO_EXACT, global_options,</span><br><span style="color: hsl(120, 100%, 40%);">+                       DEFAULT_TRANSFER_ANNOUNCE_SOUND, xfer_handler, 0);</span><br><span> </span><br><span>       aco_option_register_custom(&cfg_info, "pickupexten", ACO_EXACT, global_options,</span><br><span>                        DEFAULT_PICKUPEXTEN, pickup_handler, 0);</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.asterisk.org/c/asterisk/+/18001">change 18001</a>. To unsubscribe, or for help writing mail filters, visit <a href="https://gerrit.asterisk.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://gerrit.asterisk.org/c/asterisk/+/18001"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: asterisk </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-Change-Id: Ibff309caa459a2b958706f2ed0ca393b1ef502e3 </div>
<div style="display:none"> Gerrit-Change-Number: 18001 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: N A <mail@interlinked.x10host.com> </div>
<div style="display:none"> Gerrit-MessageType: newchange </div>