How to instruct dialplan to check if an extension exists before forwarding the call?

Dear all,

Please, help me to solve this problem as I really don’t know how to solve it.

I created two dialplans for two different offices: account (extensions _1XX) and sales (extensions _2XX).

I want that all outgoing calls from both offices ( _X.) be redirected to another context, that is called “outgoing_calls_filter”, which should check if call was placed during working time and if it is an intern of outbound call.

As per bellow configuration is working perfectly. It can successfully detect if call was placed during working time (if not it drops the call) and if it is an inter or outbound call (applying different rules if was dialed a national or international call).

[account]

exten => 101,1,NoOp()
same  => n,Dial(SIP/acc01,60,tT)
same  => n,Playtones(congestion)
same  => n,Hangup()

exten => 102,1,NoOp()
same  => n,Dial(SIP/amm02,60,tT)
same  => n,Playtones(congestion)
same  => n,Hangup()

exten => _X.,1,NoOp()
same  => n,GoTo(outgoing_calls_filter,${EXTEN},1)
same  => n,Hangup()


[sales]

exten => 201,1,NoOp()
same  => n,Dial(SIP/sal01,60,tT)
same  => n,Playtones(congestion)
same  => n,Hangup()

exten => 202,1,NoOp()
same  => n,Dial(SIP/com02,60,tT)
same  => n,Playtones(congestion)
same  => n,Hangup()

exten => _X.,1,NoOp()
same  => n,GoTo(outgoing_calls_filter,${EXTEN},1)
same  => n,Hangup()


[outgoing_calls_filter]


exten => _1XX,1,Set(INTERN_ACCOUNT=1)
same  => n,GoSub(outgoing_time_check,s,1)
same  => n,GoToIf($[${INTERN_ACCOUNT}=1]?account,${EXTEN},1)
same  => n,Hangup()

exten => _2XX,1,Set(INTERN_SALES=1)
same  => n,GoSub(outgoing_time_check,s,1)
same  => n,GoToIf($[${INTERN_SALES}=1]?sales,${EXTEN},1)
same  => n,Hangup()

exten => _0X.,1,Set(NATIONAL=1)
same  => n,GoSub(outgoing_time_check,s,1)
same  => n,GoToIf($[${NATIONAL}=1]?outgoing,${EXTEN},1)
same  => n,Hangup()

exten => _3X.,1,Set(NATIONAL_MOBILE=1)
same  => n,GoSub(outgoing_time_check,s,1)
same  => n,GoToIf($[${NATIONAL_MOBILE}=1]?outgoing,${EXTEN},1)
same  => n,Hangup()

exten => _00X.,1,Set(INTERNATIONAL_00=1)
same  => n,GoSub(outgoing_time_check,s,1)
same  => n,GoSub(outgoing_simultaneous_calls_check,s,1)
same  => n,GoToIf($[${INTERNATIONAL_00}=1]?outgoing,${EXTEN},1)
same  => n,Hangup()

exten => _+X.,1,Set(INTERNATIONAL_+=1)
same  => n,GoSub(outgoing_time_check,s,1)
same  => n,GoSub(outgoing_simultaneous_calls_check,s,1)
same  => n,GoToIf($[${INTERNATIONAL_+}=1]?outgoing,${EXTEN},1)
same  => n,Hangup()


[outgoing_time_check]

exten => s,1,NoOp()
same  => n,GoToIfTime(8:00-17:00,mon-fri,*,*?working_hours,1)
same  => n,GoToIfTime(8:00-12:00,sat-sat,*,*?working_hours,1)
same  => n,Playtones(no_working_hours)
same  => n,Hangup()

exten => working_hours,1,NoOp()
same  => n,Return


[outgoing_simultaneous_calls_check]

exten => s,1,NoOp()
same  => n,Set(GROUP()=INTL_CALL)
same  => n,GoToIf($[{GROUP_COUNT()}<3]?ok,1)
same  => n,Playtones(over_the_limit_retry_later)
same  => n,Hangup()

exten => ok,1,(NoOp()
same  => n,Return


[outgoing]

exten => _X.,1,NoOp()
same  => n,Dial(SIP/${EXTEN}@fritzboxbs)
same  => n,Playtones(congestion)
same  => n,Hangup()

The problem is when I (sal01 extension) dial an invalid extension. For example I dial extension 187 which does not exists (only 101 and 102 exists into the account context). The “outgoing_calls_filter” detects that dialed number 187 matches the _1XX pattern and so call is forwarded to the “account” context. Since there is no 187 extension, _X. catches the call and sends it back to the “outgoing_calls_filter” causing an infinite loop. In this scenario the asterisk CLI is flooded with following log and doesn’t stop since I hangup

 == Using SIP RTP CoS mark 5
    -- Executing [187@sales:1] NoOp("SIP/sal01-00000040", "") in new stack
    -- Executing [187@sales:2] Goto("SIP/sal01-00000040", "outgoing_calls_filter,187,1") in new stack
    -- Goto (outgoing_calls_filter,187,1)
    -- Executing [187@outgoing_calls_filter:1] Set("SIP/sal01-00000040", "INTERN_ACCOUNT=1") in new stack
    -- Executing [187@outgoing_calls_filter:2] Gosub("SIP/sal01-00000040", "outgoing_time_check,s,1") in new stack
    -- Executing [s@outgoing_time_check:1] NoOp("SIP/sal01-00000040", "") in new stack
    -- Executing [s@outgoing_time_check:2] GotoIfTime("SIP/sal01-00000040", "8:00-17:00,mon-fri,*,*?working_hours,1") in new stack
    -- Goto (outgoing_time_check,working_hours,1)
    -- Executing [working_hours@outgoing_time_check:1] NoOp("SIP/sal01-00000040", "orario di lavoro") in new stack
    -- Executing [working_hours@outgoing_time_check:2] Return("SIP/sal01-00000040", "") in new stack
    -- Executing [187@outgoing_calls_filter:3] GotoIf("SIP/sal01-00000040", "1?account,187,1") in new stack
    -- Goto (account,187,1)
    -- Executing [187@account:1] NoOp("SIP/sal01-00000040", "") in new stack
    -- Executing [187@account:2] Goto("SIP/sal01-00000040", "outgoing_calls_filter,187,1") in new stack
    -- Goto (outgoing_calls_filter,187,1)
    -- Executing [187@outgoing_calls_filter:1] Set("SIP/sal01-00000040", "INTERN_ACCOUNT=1") in new stack
    -- Executing [187@outgoing_calls_filter:2] Gosub("SIP/sal01-00000040", "outgoing_time_check,s,1") in new stack
    -- Executing [s@outgoing_time_check:1] NoOp("SIP/sal01-00000040", "") in new stack
    -- Executing [s@outgoing_time_check:2] GotoIfTime("SIP/sal01-00000040", "8:00-17:00,mon-fri,*,*?working_hours,1") in new stack
    -- Goto (outgoing_time_check,working_hours,1)
    -- Executing [working_hours@outgoing_time_check:1] NoOp("SIP/sal01-00000040", "orario di lavoro") in new stack
    -- Executing [working_hours@outgoing_time_check:2] Return("SIP/sal01-00000040", "") in new stack
    -- Executing [187@outgoing_calls_filter:3] GotoIf("SIP/sal01-00000040", "1?account,187,1") in new stack
    -- Goto (account,187,1)
    -- Executing [187@account:1] NoOp("SIP/sal01-00000040", "") in new stack
    -- Executing [187@account:2] Goto("SIP/sal01-00000040", "outgoing_calls_filter,187,1") in new stack
    -- Goto (outgoing_calls_filter,187,1)
    -- Executing [187@outgoing_calls_filter:1] Set("SIP/sal01-00000040", "INTERN_ACCOUNT=1") in new stack
    -- Executing [187@outgoing_calls_filter:2] Gosub("SIP/sal01-00000040", "outgoing_time_check,s,1") in new stack
    -- Executing [s@outgoing_time_check:1] NoOp("SIP/sal01-00000040", "") in new stack
    -- Executing [s@outgoing_time_check:2] GotoIfTime("SIP/sal01-00000040", "8:00-17:00,mon-fri,*,*?working_hours,1") in new stack
    -- Goto (outgoing_time_check,working_hours,1)
    -- Executing [working_hours@outgoing_time_check:1] NoOp("SIP/sal01-00000040", "orario di lavoro") in new stack
    -- Executing [working_hours@outgoing_time_check:2] Return("SIP/sal01-00000040", "") in new stack
    -- Executing [187@outgoing_calls_filter:3] GotoIf("SIP/sal01-00000040", "1?account,187,1") in new stack
    -- Goto (account,187,1)

Now, how can I tell “outgoig_calls_filter” to check if the dialed extension really exists into the “account” context and if it doesn’t exists to just Playback (congestion) and Hangup()?

Thank you!

Your problem is that you have a loop in your dialplan. 187 does exist, because you have log lines showing dialplan being executed for it.

If that hadn’t have been the case, I would have said to use the “i” extension to catch the the failed GoTo.

1 Like

I tried to set it into the [account] context, but loop persists

[account]

exten => 101,1,NoOp()
same  => n,Dial(SIP/acc01,60,tT)
same  => n,Playtones(congestion)
same  => n,Hangup()

exten => 102,1,NoOp()
same  => n,Dial(SIP/acc02,60,tT)
same  => n,Playtones(congestion)
same  => n,Hangup()

exten => i,1,NoOp(Invalid_Extention)
same  => n,Playback(invalid_extention)
same  => n,Hangup()

exten => _X.,1,NoOp()
same  => n,GoTo(outgoing_calls_filter,${EXTEN},1)
same  => n,Hangup()

Maybe is there a function that I could implement into GoToIf application?

[outgoing_calls_filter]


exten => _1XX,1,Set(INTERN_ACCOUNT=1)
same  => n,GoSub(outgoing_time_check,s,1)
same  => n,GoToIf($[${INTERN_ACCOUNT}=1]?account,${EXTEN},1)
same  => n,Hangup()

I havent see you need logs but I’m pretty sure this piece of dial plan is the one causing the loop

Yes, this _X. is causing the loop. I wonder if there is a possibility to tell asterisk - when he is coming back from the outgoing filter context - to dial only extentions I wrote into the [account] context ignoring this _X.

Set a variable on [account] context that will be evaluated on [outgoing_calls_filter]
and if true or false you do that logic,

Mmm… I really don’t know how to do it :frowning:

Where should I put this variable (for example VALID=1 or VALID=0) into [account] context? and how can I tell [outgoing_calls_filter] to look for a specific variable into [account] context?

[account]

exten => 101,1,NoOp(VALID=1)
same  => n,Dial(SIP/acc01,60,tT)
same  => n,Playtones(congestion)
same  => n,Hangup()

exten => 102,1,NoOp(VALID=1)
same  => n,Dial(SIP/acc02,60,tT)
same  => n,Playtones(congestion)
same  => n,Hangup()

exten => _X.,1,NoOp(VALID=0)
same  => n,GoTo(outgoing_calls_filter,${EXTEN},1)
same  => n,Hangup()

[outgoing_calls_filter]

exten => _1XX,1,NoOp()
same  => n,GoSub(outgoing_time_check,s,1)
same  => n,GoToIf($[${VALID}=1]?account,${EXTEN},1)
same  => n,Playback(congestion)
same  => n,Hangup()

Use Set instead of Noop

Ok, so this is now the configuration.

[account]

exten => 101,1,Set(VALID=1)
same  => n,Dial(SIP/acc01,60,tT)
same  => n,Playtones(congestion)
same  => n,Hangup()

exten => 102,1,Set(VALID=1)
same  => n,Dial(SIP/acc02,60,tT)
same  => n,Playtones(congestion)
same  => n,Hangup()

exten => _X.,1,Set(VALID=0)
same  => n,GoTo(outgoing_calls_filter,${EXTEN},1)
same  => n,Hangup()

[outgoing_calls_filter]

exten => _1XX,1,NoOp()
same  => n,GoSub(outgoing_time_check,s,1)
same  => n,GoToIf($[${VALID=1}]?account,${EXTEN},1)
same  => n,Playback(congestion)
same  => n,Hangup()

Unfortunately, even if I call extention 101 I get an error and call drops

 == Using SIP RTP CoS mark 5
    -- Executing [101@sales:1] NoOp("SIP/sal01-00000064", "") in new stack
    -- Executing [101@sales:2] Goto("SIP/sal01-00000064", "outgoing_calls_filter,101,1") in new stack
    -- Goto (outgoing_calls_filter,101,1)
    -- Executing [101@outgoing_calls_filter:1] NoOp("SIP/sal01-00000064", "") in new stack
    -- Executing [101@outgoing_calls_filter:2] GotoIf("SIP/sal01-00000064", "?account,101,1") in new stack
    -- Executing [101@outgoing_calls_filter:3] Hangup("SIP/sal01-00000064", "") in new stack
  == Spawn extension (outgoing_calls_filter, 101, 3) exited non-zero on 'SIP/sal01-00000064'

I dont see where you set the variable on the context sales, as you re using account context instead of sales

[account]

exten => 101,1,Set(VALID=1)
same  => n,Dial(SIP/acc01,60,tT)
same  => n,Playtones(congestion)
same  => n,Hangup()

exten => 102,1,Set(VALID=1)
same  => n,Dial(SIP/acc02,60,tT)
same  => n,Playtones(congestion)
same  => n,Hangup()

exten => _X.,1,Set(VALID=0)
same  => n,GoTo(outgoing_calls_filter,${EXTEN},1)
same  => n,Hangup()

[sales]

exten => 201,1,Set(VALID=1)
same  => n,Dial(SIP/sal01,60,tT)
same  => n,Playtones(congestion)
same  => n,Hangup()

exten => 202,1,Set(VALID=1)
same  => n,Dial(SIP/sal02,60,tT)
same  => n,Playtones(congestion)
same  => n,Hangup()

exten => _X.,1,Set(VALID=0)
same  => n,GoTo(outgoing_calls_filter,${EXTEN},1)
same  => n,Hangup()

[outgoing_calls_filter]

exten => _1XX,1,NoOp()
same  => n,GoSub(outgoing_time_check,s,1)
same  => n,GoToIf($[${VALID=1}]?account,${EXTEN},1)
same  => n,Playback(congestion)
same  => n,Hangup()

exten => _2XX,1,NoOp()
same  => n,GoSub(outgoing_time_check,s,1)
same  => n,GoToIf($[${VALID=1}]?sales,${EXTEN},1)
same  => n,Playback(congestion)
same  => n,Hangup()

This is really, really strange as now I have another error.

I, ext sal01, call number 101 and the call drops even if number 101 in VALID=1

I don’t know why sal01 is marked as VALID=0

== Using SIP RTP CoS mark 5
    -- Executing [101@sales:1] Set("SIP/sal01-00000070", "VALID=0") in new stack
    -- Executing [101@sales:2] Goto("SIP/sal01-00000070", "outgoing_calls_filter,101,1") in new stack
    -- Goto (outgoing_calls_filter,101,1)
    -- Executing [101@outgoing_calls_filter:1] NoOp("SIP/sal01-00000070", "") in new stack
    -- Executing [101@outgoing_calls_filter:2] GotoIf("SIP/sal01-00000070", "?account,101,1") in new stack
[Mar 10 18:57:17] WARNING[20937][C-00000058]: pbx.c:4910 pbx_extension_helper: No application '' for extension (outgoing_calls_filter, 101, 3)
  == Spawn extension (outgoing_calls_filter, 101, 3) exited non-zero on 'SIP/sal01-00000070'

reason why call drops

also add to the noop() the variable VALID on the context outgoing_calls_filter to make sure we are getting the variable with the correct value

Same problem: call drops automatically

[account]

exten => 101,1,Set(VALID=1)
same  => n,Dial(SIP/acc01,60,tT)
same  => n,Playtones(congestion)
same  => n,Hangup()

exten => 102,1,Set(VALID=1)
same  => n,Dial(SIP/acc02,60,tT)
same  => n,Playtones(congestion)
same  => n,Hangup()

exten => _X.,1,Set(VALID=0)
same  => n,GoTo(outgoing_calls_filter,${EXTEN},1)
same  => n,Hangup()

[sales]

exten => 201,1,Set(VALID=1)
same  => n,Dial(SIP/sal01,60,tT)
same  => n,Playtones(congestion)
same  => n,Hangup()

exten => 202,1,Set(VALID=1)
same  => n,Dial(SIP/sal02,60,tT)
same  => n,Playtones(congestion)
same  => n,Hangup()

exten => _X.,1,Set(VALID=0)
same  => n,GoTo(outgoing_calls_filter,${EXTEN},1)
same  => n,Hangup()

[outgoing_calls_filter]

exten => _1XX,1,Set(VALID=1)
same  => n,GoSub(outgoing_time_check,s,1)
same  => n,GoToIf($[${VALID=1}]?account,${EXTEN},1)
same  => n,Playback(congestion)
same  => n,Hangup()

exten => _2XX,1,Set(VALID=1)
same  => n,GoSub(outgoing_time_check,s,1)
same  => n,GoToIf($[${VALID=1}]?sales,${EXTEN},1)
same  => n,Playback(congestion)
same  => n,Hangup()

This is the log

  == Using SIP RTP CoS mark 5
    -- Executing [101@sales:1] Set("SIP/sal01-00000077", "VALID=0") in new stack
    -- Executing [101@sales:2] Goto("SIP/sal01-00000077", "outgoing_calls_filter,101,1") in new stack
    -- Goto (outgoing_calls_filter,101,1)
    -- Executing [101@outgoing_calls_filter:1] Set("SIP/sal01-00000077", "VALID=1") in new stack
    -- Executing [101@outgoing_calls_filter:2] GotoIf("SIP/sal01-00000077", "?account,101,1") in new stack
    -- Executing [101@outgoing_calls_filter:3] Hangup("SIP/sal01-00000077", "") in new stack
  == Spawn extension (outgoing_calls_filter, 101, 3) exited non-zero on 'SIP/sal01-00000077'

sorry?? please explain

You must review how you typed your code.

Wrong:

same => n,GoToIf($[${VALID=1}]?sales,${EXTEN},1)

Right:

same => n,GoToIf($[${VALID}=1]?sales,${EXTEN},1)

How you can troubleshoot your next codes with conditions:

when the response didn’t came with 0 or 1 before question mark:

“?account,101,1”)

Hope that can guide and help you

Shouldn’t

same => n,GoToIf([{VALID}=1]?sales,${EXTEN},1)

be

same => n,GoToIf([${VALID}=1]?sales,${EXTEN},1)

(pesky dollar signs :wink:)

check if device state is invalid

So, I modified the extensions.conf as you adviced

[account]

exten => 101,1,Set(VALID=1)
same  => n,Dial(SIP/acc01,60,tT)
same  => n,Playtones(congestion)
same  => n,Hangup()

exten => _X.,1,Set(VALID=0)
same  => n,GoTo(outgoing_calls_filter,${EXTEN},1)
same  => n,Hangup()

[sales]

exten => 201,1,Set(VALID=1)
same  => n,Dial(SIP/sal01,60,tT)
same  => n,Playtones(congestion)
same  => n,Hangup()

exten => _X.,1,Set(VALID=0)
same  => n,GoTo(outgoing_calls_filter,${EXTEN},1)
same  => n,Hangup()

[outgoing_calls_filter]

exten => _1XX,1,Set(VALID=1)
same  => n,GoToIf($[${VALID}=1]?account,${EXTEN},1)
same  => n,Playback(congestion)
same  => n,Hangup()

exten => _2XX,1,Set(VALID=1)
same  => n,GoToIf($[${VALID}=1]?sales,${EXTEN},1)
same  => n,Playback(congestion)
same  => n,Hangup()


And if I call 101 I can see VALID=1 and call is processed correctly

== Using SIP RTP CoS mark 5
    -- Executing [101@sales:1] Set("SIP/sal01-00000000", "VALID=0") in new stack
    -- Executing [101@sales:2] Goto("SIP/sal01-00000000", "outgoing_calls_filter,101,1") in new stack
    -- Goto (outgoing_calls_filter,101,1)
    -- Executing [101@outgoing_calls_filter:1] Set("SIP/sal01-00000000", "VALID=1") in new stack
    -- Executing [101@outgoing_calls_filter:2] GotoIf("SIP/sal01-00000000", "1?account,101,1") in new stack
    -- Goto (account,101,1)
    -- Executing [101@account:1] Set("SIP/sal01-00000000", "VALID=1") in new stack
    -- Executing [101@account:2] Dial("SIP/sal01-00000000", "SIP/acc01,60,tT") in new stack
  == Using SIP RTP CoS mark 5
    -- Called SIP/acc01
    -- SIP/acc01-00000001 is ringing
       > 0x7f44a400b890 -- Probation passed - setting RTP source address to 192.168.3.4:63944
  == Spawn extension (account, 101, 2) exited non-zero on 'SIP/sal01-00000000'

Now, if I call 187 then asterisk loops again

== Using SIP RTP CoS mark 5
    -- Executing [187@sales:1] Set("SIP/sal01-00000002", "VALID=0") in new stack
    -- Executing [187@sales:2] Goto("SIP/sal01-00000002", "outgoing_calls_filter,187,1") in new stack
    -- Goto (outgoing_calls_filter,187,1)
    -- Executing [187@outgoing_calls_filter:1] Set("SIP/sal01-00000002", "VALID=1") in new stack
    -- Executing [187@outgoing_calls_filter:2] GotoIf("SIP/sal01-00000002", "1?account,187,1") in new stack
    -- Goto (account,187,1)
    -- Executing [187@account:1] Set("SIP/sal01-00000002", "VALID=0") in new stack
    -- Executing [187@account:2] Goto("SIP/sal01-00000002", "outgoing_calls_filter,187,1") in new stack
    -- Goto (outgoing_calls_filter,187,1)
    -- Executing [187@outgoing_calls_filter:1] Set("SIP/sal01-00000002", "VALID=1") in new stack
    -- Executing [187@outgoing_calls_filter:2] GotoIf("SIP/sal01-00000002", "1?account,187,1") in new stack
    -- Goto (account,187,1)

Maybe should I erase the VALID=0 from the _X. extension?

Could be a better idea to use following condition EXTENSION_STATE?

CLI> core show function EXTENSION_STATE 

  -= Info about function 'EXTENSION_STATE' =- 

[Synopsis]
Get an extension's state. 

[Description]
The EXTENSION_STATE function can be used to retrieve the state from any hinted
extension. For example:
NoOp(1234@default has state ${EXTENSION_STATE(1234)})
NoOp(4567@home has state ${EXTENSION_STATE(4567@home)})
The possible values returned by this function are:
UNKNOWN | NOT_INUSE | INUSE | BUSY | INVALID | UNAVAILABLE | RINGING |
RINGINUSE | HOLDINUSE | ONHOLD

[Syntax]
EXTENSION_STATE(extension[@context])

[Arguments]
context
    If it is not specified defaults to 'default'.

[See Also]
Not available