<p>George Joseph <strong>submitted</strong> this change.</p><p><a href="https://gerrit.asterisk.org/c/asterisk/+/18357">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span></span><br></pre><div style="white-space:pre-wrap">Approvals:
  Joshua Colp: Looks good to me, but someone else must approve
  George Joseph: Looks good to me, approved; Approved for Submit

</div><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>First, the "transfer" sound that plays when a transfer is<br>initiated can now be customized by 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, 108 insertions(+), 13 deletions(-)<br><br></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..05b514e 100644</span><br><span>--- a/configs/samples/features.conf.sample</span><br><span>+++ b/configs/samples/features.conf.sample</span><br><span>@@ -6,7 +6,11 @@</span><br><span> </span><br><span> [general]</span><br><span> ;transferdigittimeout => 3      ; Number of seconds to wait between digits when transferring a call</span><br><span style="color: hsl(0, 100%, 40%);">-                                ; (default is 3 seconds)</span><br><span style="color: hsl(120, 100%, 40%);">+                                ; (default is 3 seconds). If the TRANSFER_EXTEN dialplan variable has been set</span><br><span style="color: hsl(120, 100%, 40%);">+                                ; on the channel of the user that is invoking the transfer feature, then</span><br><span style="color: hsl(120, 100%, 40%);">+                                ; this option is not used as the user is transferred directly to the extension</span><br><span style="color: hsl(120, 100%, 40%);">+                                ; specified by TRANSFER_EXTEN (the transfer context remains the context specified</span><br><span style="color: hsl(120, 100%, 40%);">+                                ; by TRANSFER_CONTEXT, if set, and otherwise the default context).</span><br><span> ;xfersound = beep               ; to indicate an attended transfer is complete</span><br><span> ;xferfailsound = beeperr        ; to indicate a failed transfer</span><br><span> ;pickupexten = *8               ; Configure the pickup extension. (default is *8)</span><br><span>@@ -26,12 +30,13 @@</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> ;atxfercomplete = *2            ; complete the attended transfer, dropping out of the call</span><br><span> ;atxferthreeway = *3            ; complete the attended transfer, but stay in the call. This will turn the call into a multi-party bridge</span><br><span style="color: hsl(0, 100%, 40%);">-;atxferswap = *4                ; swap to the other party. Once an attended transfer has begun, this options may be used multiple times</span><br><span style="color: hsl(120, 100%, 40%);">+;atxferswap = *4                ; swap to the other party. Once an attended transfer has begun, this option may be used multiple times</span><br><span> </span><br><span> ; Note that the DTMF features listed below only work when two channels have answered and are bridged together.</span><br><span> ; They can not be used while the remote party is ringing or in progress. If you require this feature you can use</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..962272f</span><br><span>--- /dev/null</span><br><span>+++ b/doc/CHANGES-staging/transfer.txt</span><br><span>@@ -0,0 +1,14 @@</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 set on the</span><br><span style="color: hsl(120, 100%, 40%);">+transferer's channel in order to allow the transfer</span><br><span style="color: hsl(120, 100%, 40%);">+function to automatically attempt to go to the extension</span><br><span style="color: hsl(120, 100%, 40%);">+contained in this variable, if it exists. The transfer</span><br><span style="color: hsl(120, 100%, 40%);">+context behavior is not changed (TRANSFER_CONTEXT is used</span><br><span style="color: hsl(120, 100%, 40%);">+if it exists; otherwise the default context is used).</span><br><span>diff --git a/include/asterisk/features_config.h b/include/asterisk/features_config.h</span><br><span>index 5253369..9d626ee 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_EXTENDED(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..c291fb2 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>@@ -3162,10 +3183,25 @@</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 style="color: hsl(120, 100%, 40%);">+   const char *extenoverride;</span><br><span> </span><br><span>       ast_channel_lock(chan);</span><br><span style="color: hsl(120, 100%, 40%);">+       extenoverride = get_transfer_exten(chan, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+</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_channel_unlock(chan);</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 style="color: hsl(120, 100%, 40%);">+</span><br><span>  xfer_cfg = ast_get_chan_features_xfer_config(chan);</span><br><span>  if (!xfer_cfg) {</span><br><span>             ast_log(LOG_ERROR, "Channel %s: Unable to get transfer configuration\n",</span><br><span>@@ -3175,21 +3211,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>diff --git a/main/features_config.c b/main/features_config.c</span><br><span>index ac0135a..ba2f905 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>@@ -324,6 +327,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>@@ -387,6 +391,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>@@ -910,6 +915,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>@@ -1801,6 +1808,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/+/18357">change 18357</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/+/18357"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: asterisk </div>
<div style="display:none"> Gerrit-Branch: 18 </div>
<div style="display:none"> Gerrit-Change-Id: Ibff309caa459a2b958706f2ed0ca393b1ef502e3 </div>
<div style="display:none"> Gerrit-Change-Number: 18357 </div>
<div style="display:none"> Gerrit-PatchSet: 4 </div>
<div style="display:none"> Gerrit-Owner: N A <mail@interlinked.x10host.com> </div>
<div style="display:none"> Gerrit-Reviewer: Friendly Automation </div>
<div style="display:none"> Gerrit-Reviewer: George Joseph <gjoseph@digium.com> </div>
<div style="display:none"> Gerrit-Reviewer: Joshua Colp <jcolp@sangoma.com> </div>
<div style="display:none"> Gerrit-Reviewer: Kevin Harwell <default.enum@gmail.com> </div>
<div style="display:none"> Gerrit-MessageType: merged </div>