[Home]

Summary:ASTERISK-18243: VoiceMail application fails to assign some DTMF codes for application exit when using d() option with context
Reporter:Matt Jordan (mjordan)Labels:
Date Opened:2011-08-08 13:20:26Date Closed:2012-05-07 13:43:19
Priority:MinorRegression?
Status:Closed/CompleteComponents:Applications/app_voicemail
Versions:10 1.8.5.0 10.0.0-beta1 Frequency of
Occurrence
Constant
Related
Issues:
causesASTERISK-20455 dialplan fails to run the invalid "i" extension due to an uninitialized variable dat_exten in main/pbx.c
Environment:Fedora 15, running 10.0.-beta1Attachments:
Description:The VoiceMail d() option should allow the operator to exit out of the VoiceMail application by sending any DTMF code.  The context specified in the d() option (when used) should be transferred to, where the DTMF code sent is the extension to be routed to.

For all DTMF codes not equal to '1', the transfer fails to occur when the extension to be routed to only exists in the context specified by the d() option, and not the context that the call to VoiceMail originated in.  This is due to the section of code in app_voicemail that looks up the extension to route to - it assumes that the extension should exist in the channel's current context, as opposed to the context specified.

For example, the following dialplan (using a proposed test in the testsuite, leavel_voicemail_contexts) will fail when the DTMF code sent is '3':

ast1 (voicemail server)

; Accepts a voicemail message and tests that the voicemail application returned successfully.
; Exiting out to any other context is a failure.
;

[voicemail]

exten => 1234,1,NoOp()
same => n,VoiceMail(1234@default,u,d(othercontext))
same => n,GotoIf($[${VMSTATUS} = USEREXIT]?pass:fail)
same => n(fail),UserEvent(TestResult,result: fail, status: VoiceMail failed to exit successfully - returned ${VMSTATUS})
same => n,Hangup()
same => n(pass),NoOp()
same => n,UserEvent(TestResult,result: pass, status: VoiceMail exited successfully with USEREXIT)
same => n,Hangup()

exten => 5678,1,NoOp()
same => n,VoiceMail(5678@default,u,d(othercontext))
same => n,GotoIf($[${VMSTATUS} = USEREXIT]?pass:fail)
same => n(fail),UserEvent(TestResult,result: fail, status: VoiceMail failed to exit successfully - returned ${VMSTATUS})
same => n,Hangup()
same => n(pass),NoOp()
same => n,UserEvent(TestResult,result: pass, status: VoiceMail exited successfully with USEREXIT)
same => n,Hangup()

exten => 9000,1,NoOp()
same => n,VoiceMail(9000@default,u)
same => n,GotoIf($[${VMSTATUS} = USEREXIT]?pass:fail)
same => n(fail),UserEvent(TestResult,result: fail, status: VoiceMail failed to exit successfully - returned ${VMSTATUS})
same => n,Hangup()
same => n(pass),NoOp()
same => n,UserEvent(TestResult,result: pass, status: VoiceMail exited successfully with USEREXIT)
same => n,Hangup()

exten => o,1,UserEvent(TestResult,result: operator,status: exited through operator extension)
same => n,Wait(2)
same => n,Hangup()

exten => i,1,UserEvent(TestResult,result: fail,status: failed to exit successfully)
same => n,Wait(2)
same => n,Hangup()

exten => e,1,UserEvent(TestResult,result: fail,status: failed to exit successfully)
same => n,Wait(2)
same => n,Hangup()

exten => a,1,UserEvent(TestResult,result: asterisk,status: exited through a extension)
same => n,Wait(2)
same => n,Hangup()

exten => t,1,UserEvent(TestResult,result: fail,status: failed to exit successfully)
same => n,Wait(2)
same => n,Hangup()

;
; Test leaving out into another context
;
[othercontext]

exten => 1,1,UserEvent(TestResult,result: othercontext@1,status: exited through 1 extension)
same => n,Wait(2)
same => n,Hangup()

exten => 3,1,UserEvent(TestResult,result: othercontext@3,status: exited through 3 extension)
same => n,Wait(2)
same => n,Hangup()

exten => 1234,1,UserEvent(TestResult,result: othercontext@1234,status: exited through 1234 extension)
same => n,Wait(2)
same => n,Hangup()

exten => 5678,1,UserEvent(TestResult,result: othercontext@5678,status: exited through 5678 extension)
same => n,Wait(2)
same => n,Hangup()

exten => o,1,UserEvent(TestResult,result: othercontext@operator, status: exited through operator extension)
same => n,Wait(2)
same => n,Hangup()

ast2 (caller)

; Tests exiting out of the VoiceMail application through various contexts

[sendvoicemail]
exten => 1234,1,NoOp()
same => n,Wait(3)
same => n,Verbose(1, Sending ${DTMF_TO_SEND} key)
same => n,SendDTMF(${DTMF_TO_SEND})
same => n,UserEvent(TestResult,result: spawn,status: spawn next test)
same => n,Wait(10)
same => n,Hangup()

exten => 5678,1,NoOp()
same => n,Wait(3)
same => n,Verbose(1, Sending ${DTMF_TO_SEND} key)
same => n,SendDTMF(${DTMF_TO_SEND})
same => n,UserEvent(TestResult,result: spawn,status: spawn next test)
same => n,Wait(10)
same => n,Hangup()

exten => 9000,1,NoOp()
same => n,Wait(10)
same => n,Verbose(1, Playing back ${TALK_AUDIO})
same => n,Playback(${TALK_AUDIO})
same => n,Verbose(1, Sending ${DTMF_TO_SEND} key)
same => n,SendDTMF(${DTMF_TO_SEND})
same => n,UserEvent(TestResult,result: spawn,status: spawn next test)
same => n,Wait(10)
same => n,Hangup()

Note that in ast1, if extension 3 is placed under context [voicemail], then the reroute works correctly, and the call is sent to context [othercontext], extension 3.  The offending code occurs in app_voicemail at line 5696:

if (ast_test_flag(options, OPT_DTMFEXIT)) {
for (code = alldtmf; *code; code++) {
char e[2] = "";
e[0] = *code;
if (strchr(ecodes, e[0]) == NULL
&& ast_canmatch_extension(chan, chan->context, e, 1,
S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
strncat(ecodes, e, sizeof(ecodes) - strlen(ecodes) - 1);
}
}
}

We should append the DTMF codes to the exit codes if the extension exists under the option's specified exitcontext, as opposed to the current channel's context.
Comments: