[general]
;transferdigittimeout => 3 ; Number of seconds to wait between digits when transferring a call
- ; (default is 3 seconds)
+ ; (default is 3 seconds). If the TRANSFER_EXTEN dialplan variable has been set
+ ; on the channel of the user that is invoking the transfer feature, then
+ ; this option is not used as the user is transferred directly to the extension
+ ; specified by TRANSFER_EXTEN (the transfer context remains the context specified
+ ; by TRANSFER_CONTEXT, if set, and otherwise the default context).
;xfersound = beep ; to indicate an attended transfer is complete
;xferfailsound = beeperr ; to indicate a failed transfer
;pickupexten = *8 ; Configure the pickup extension. (default is *8)
; By default, this is 2.
;transferdialattempts = 3 ; Number of times that a transferer may attempt to dial an extension before
; being kicked back to the original call.
+;transferannouncesound = beep ; Sound to play to a transferer to indicate transfer process has begun. If empty, no sound will be played.
;transferretrysound = beep ; Sound to play when a transferer fails to dial a valid extension.
;transferinvalidsound = beeperr ; Sound to play when a transferer fails to dial a valid extension and is out of retries.
;atxferabort = *1 ; cancel the attended transfer
;atxfercomplete = *2 ; complete the attended transfer, dropping out of the call
;atxferthreeway = *3 ; complete the attended transfer, but stay in the call. This will turn the call into a multi-party bridge
-;atxferswap = *4 ; swap to the other party. Once an attended transfer has begun, this options may be used multiple times
+;atxferswap = *4 ; swap to the other party. Once an attended transfer has begun, this option may be used multiple times
; Note that the DTMF features listed below only work when two channels have answered and are bridged together.
; They can not be used while the remote party is ringing or in progress. If you require this feature you can use
--- /dev/null
+Subject: Transfer feature
+
+The following capabilities have been added to the
+transfer feature:
+
+- The transfer initiation announcement prompt can
+now be customized in features.conf.
+
+- The TRANSFER_EXTEN variable now can be set on the
+transferer's channel in order to allow the transfer
+function to automatically attempt to go to the extension
+contained in this variable, if it exists. The transfer
+context behavior is not changed (TRANSFER_CONTEXT is used
+if it exists; otherwise the default context is used).
AST_STRING_FIELD(transferretrysound);
/*! Sound played when an invalid extension is dialed, and the transferer is being returned to the call. */
AST_STRING_FIELD(transferinvalidsound);
+ /*! Sound to play to announce the transfer process has started. */
+ AST_STRING_FIELD_EXTENDED(transferannouncesound);
);
/*! Seconds allowed between digit presses when dialing transfer destination */
unsigned int transferdigittimeout;
return "default";
}
+/*!
+ * \internal
+ * \brief Determine the transfer extension to use.
+ *
+ * \param transferer Channel initiating the transfer.
+ * \param extension User supplied extension if available. May be NULL.
+ *
+ * \return The extension to use for the transfer.
+ */
+static const char *get_transfer_exten(struct ast_channel *transferer, const char *exten)
+{
+ if (!ast_strlen_zero(exten)) {
+ return exten;
+ }
+ exten = pbx_builtin_getvar_helper(transferer, "TRANSFER_EXTEN");
+ if (!ast_strlen_zero(exten)) {
+ return exten;
+ }
+ return ""; /* empty default, to get transfer extension from user now */
+}
+
/*!
* \brief Allocate and initialize attended transfer properties
*
int attempts = 0;
int max_attempts;
struct ast_features_xfer_config *xfer_cfg;
- char *retry_sound;
- char *invalid_sound;
+ char *announce_sound, *retry_sound, *invalid_sound;
+ const char *extenoverride;
ast_channel_lock(chan);
+ extenoverride = get_transfer_exten(chan, NULL);
+
+ if (!ast_strlen_zero(extenoverride)) {
+ int extenres = ast_exists_extension(chan, context, extenoverride, 1,
+ S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL)) ? 1 : 0;
+ if (extenres) {
+ ast_copy_string(exten, extenoverride, exten_len);
+ ast_channel_unlock(chan);
+ ast_verb(3, "Transfering call to '%s@%s'", exten, context);
+ return 0;
+ }
+ ast_log(LOG_WARNING, "Override extension '%s' does not exist in context '%s'\n", extenoverride, context);
+ /* since we didn't get a valid extension from the channel, fall back and grab it from the user as usual now */
+ }
+
xfer_cfg = ast_get_chan_features_xfer_config(chan);
if (!xfer_cfg) {
ast_log(LOG_ERROR, "Channel %s: Unable to get transfer configuration\n",
}
digit_timeout = xfer_cfg->transferdigittimeout * 1000;
max_attempts = xfer_cfg->transferdialattempts;
+ announce_sound = ast_strdupa(xfer_cfg->transferannouncesound);
retry_sound = ast_strdupa(xfer_cfg->transferretrysound);
invalid_sound = ast_strdupa(xfer_cfg->transferinvalidsound);
ao2_ref(xfer_cfg, -1);
ast_channel_unlock(chan);
/* Play the simple "transfer" prompt out and wait */
- res = ast_stream_and_wait(chan, "pbx-transfer", AST_DIGIT_ANY);
- ast_stopstream(chan);
- if (res < 0) {
- /* Hangup or error */
- return -1;
- }
- if (res) {
- /* Store the DTMF digit that interrupted playback of the file. */
- exten[0] = res;
+ if (!ast_strlen_zero(announce_sound)) {
+ res = ast_stream_and_wait(chan, announce_sound, AST_DIGIT_ANY);
+ ast_stopstream(chan);
+ if (res < 0) {
+ /* Hangup or error */
+ return -1;
+ }
+ if (res) {
+ /* Store the DTMF digit that interrupted playback of the file. */
+ exten[0] = res;
+ }
}
/* Drop to dialtone so they can enter the extension they want to transfer to */
<configOption name="transferinvalidsound" default="privacy-incorrect">
<synopsis>Sound that is played when an incorrect extension is dialed and the transferer has no attempts remaining.</synopsis>
</configOption>
+ <configOption name="transferannouncesound" default="pbx-transfer">
+ <synopsis>Sound that is played to the transferer when a transfer is initiated. If empty, no sound will be played.</synopsis>
+ </configOption>
</configObject>
<configObject name="featuremap">
<synopsis>DTMF options that can be triggered during bridged calls</synopsis>
<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>
<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>
<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>
+ <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>
</enumlist>
</parameter>
</syntax>
#define DEFAULT_TRANSFER_DIAL_ATTEMPTS 3
#define DEFAULT_TRANSFER_RETRY_SOUND "pbx-invalid"
#define DEFAULT_TRANSFER_INVALID_SOUND "privacy-incorrect"
+#define DEFAULT_TRANSFER_ANNOUNCE_SOUND "pbx-transfer"
/*! Default pickup options */
#define DEFAULT_PICKUPEXTEN "*8"
ast_string_field_set(xfer, transferretrysound, value);
} else if (!strcasecmp(name, "transferinvalidsound")) {
ast_string_field_set(xfer, transferinvalidsound, value);
+ } else if (!strcasecmp(name, "transferannouncesound")) {
+ ast_string_field_set(xfer, transferannouncesound, value);
} else {
/* Unrecognized option */
res = -1;
DEFAULT_TRANSFER_RETRY_SOUND, xfer_handler, 0);
aco_option_register_custom(&cfg_info, "transferinvalidsound", ACO_EXACT, global_options,
DEFAULT_TRANSFER_INVALID_SOUND, xfer_handler, 0);
+ aco_option_register_custom(&cfg_info, "transferannouncesound", ACO_EXACT, global_options,
+ DEFAULT_TRANSFER_ANNOUNCE_SOUND, xfer_handler, 0);
aco_option_register_custom(&cfg_info, "pickupexten", ACO_EXACT, global_options,
DEFAULT_PICKUPEXTEN, pickup_handler, 0);