Reusable Dial-User Subroutine

Call Handling Asterisk 20+ -- Last reviewed 2026-08-22 call-handling gosub dnd call-forward follow-me astdb architecture Found this useful? Upvote it. ×

Reusable Dial-User Subroutine

Instead of duplicating DND checks, call forward logic, and voicemailAsterisk's built-in voice messaging system (app_voicemail), configured in voicemail.conf with mailboxes per user. fallback in every extensionA dialplan entry that matches a dialed number or pattern within a context and triggers a sequence of prioritized steps. definition, this pattern centralizes all per-user call handling into a single Gosub. Every extension calls the same subroutine, passing just the extension number and display name.

The Snippet

The subroutine itself:

[dial-user]
exten => s,1,NoOp(Dialing ${ARG1} - ${ARG2})
 ; Check DND (stored in AstDB)
 same => n,Set(DND=${DB(DND/${ARG1})})
 same => n,GotoIf($["${DND}" = "yes"]?dnd)
 ;
 ; Check Call Forward
 same => n,Set(CF=${DB(CF/${ARG1})})
 same => n,GotoIf($["${CF}" != ""]?forward)
 ;
 ; Check Follow Me
 same => n,Set(FM=${DB(FM/${ARG1})})
 same => n,GotoIf($["${FM}" = "yes"]?followme)
 ;
 ; Normal dial
 same => n,Dial(PJSIP/${ARG1},30,tTxX)
 same => n,GotoIf($["${DIALSTATUS}" = "BUSY"]?busy)
 same => n,GotoIf($["${DIALSTATUS}" = "NOANSWER"]?noanswer)
 same => n,GotoIf($["${DIALSTATUS}" = "CHANUNAVAIL"]?unavail)
 same => n,Return()
 ;
 same => n(dnd),VoiceMail(${ARG1}@default,u)
 same => n,Return()
 ;
 same => n(forward),NoOp(Call Forward to ${CF})
 ; Internal extension (pattern match) - dial directly
 same => n,GotoIf($["${CF}" : "^[0-9][0-9][0-9][0-9]?$"]?fwd_internal)
 ; Matches 3-4 digit internal extensions; adjust pattern to match your range
 ; External number - route through trunk
 same => n,Dial(PJSIP/1${CF}@${TRUNK},120,tT)
 same => n,VoiceMail(${ARG1}@default,u)
 same => n,Return()
 same => n(fwd_internal),Dial(PJSIP/${CF},30,tT)
 same => n,VoiceMail(${ARG1}@default,u)
 same => n,Return()
 ;
 same => n(followme),FollowMe(${ARG1},ds)
 same => n,GotoIf($["${FMSTATUS}" = "SUCCESS"]?:noanswer)
 same => n,Return()
 ;
 same => n(busy),VoiceMail(${ARG1}@default,b)
 same => n,Return()
 ;
 same => n(noanswer),VoiceMail(${ARG1}@default,u)
 same => n,Return()
 ;
 same => n(unavail),VoiceMail(${ARG1}@default,u)
 same => n,Return()

Calling the subroutine from your extension definitions:

[dial-extension]
exten => 100,1,NoOp(Dial Alice)
 same => n,Gosub(dial-user,s,1(100,Alice))
 same => n,Hangup()

exten => 101,1,NoOp(Dial Bob)
 same => n,Gosub(dial-user,s,1(101,Bob))
 same => n,Hangup()

exten => 102,1,NoOp(Dial Carol)
 same => n,Gosub(dial-user,s,1(102,Carol))
 same => n,Hangup()

; Fallback pattern for any extension in range
exten => _1XX,1,NoOp(Dial extension ${EXTEN})
 same => n,Dial(PJSIP/${EXTEN},30,tT)
 same => n,VoiceMail(${EXTEN}@default,u)
 same => n,Hangup()

How It Works

The subroutine checks features in priority order:

  1. DND: if DB(DND/100) is yes, go straight to voicemail. No ring, no disturbance.
  2. Call Forward: if DB(CF/100) is set to a number, dial that number instead. Handles both internal (direct PJSIPThe modern SIP channel driver in Asterisk (chan_pjsip), replacing the older chan_sip. Configured in pjsip.conf using endpoints, AORs, auths, and transports. dial) and external (route through trunkA connection between Asterisk and another PBX or an ITSP/carrier, used to send and receive external calls.) forwarding.
  3. Follow Me: if DB(FM/100) is yes, use app_followme to try the user's configured follow-me numbers (defined in followme.conf).
  4. Normal Dial: ring the PJSIP endpointIn PJSIP configuration, the SIP entity Asterisk communicates with: a phone, trunk, or other user agent. Defined by an endpoint section in pjsip.conf. for 30 seconds with transfer enabled (tT) and recording enabled (xX).
  5. DIALSTATUS routing: after Dial(), route to appropriate voicemail greeting (busy vs unavailable).

Why This Pattern Matters

Without this subroutine, every extension in your dialplanThe core call-routing configuration of Asterisk, written mostly in extensions.conf as contexts, extensions, and priorities that decide how every call is handled. Full definition → would need its own DND check, CF check, FM check, and DIALSTATUS handling. For a 50-extension system, that's thousands of duplicated lines. With this pattern, adding a new extension is one Gosub call.

The feature state lives in AstDB, which means users can toggle features from their phones using feature codes (*78/*79 for DND, *72/*73 for CF, *21/*22 for Follow Me) without any dialplanThe core call-routing configuration of Asterisk, written mostly in extensions.conf as contexts, extensions, and priorities that decide how every call is handled. Full definition → reload.

Companion Feature Codes

These feature codes set the AstDB values that the subroutine checks:

[features]
; *78/*79 - DND Enable/Disable
exten => *78,1,Set(DB(DND/${CALLERID(num)})=yes)
 same => n,Playback(beep)
 same => n,Hangup()
exten => *79,1,Set(DB_DELETE(DND/${CALLERID(num)})=)
 same => n,Playback(beep)
 same => n,Hangup()

; *72/*73 - Call Forward Enable/Disable
exten => *72,1,Read(FWD_NUM,vm-enter-num-to-call,15)
 same => n,GotoIf($["${FWD_NUM}" = ""]?cancel)
 same => n,Set(DB(CF/${CALLERID(num)})=${FWD_NUM})
 same => n,Playback(beep)
 same => n,SayDigits(${FWD_NUM})
 same => n,Hangup()
 same => n(cancel),Playback(cancelled)
 same => n,Hangup()
exten => *73,1,Set(DB_DELETE(CF/${CALLERID(num)})=)
 same => n,Playback(beep)
 same => n,Hangup()
User Notes

Know a tip or gotcha for this topic? Share it below and help others.

Contribute a note

Share a tip, gotcha, or practical example. Keep it under 2000 characters. No questions (use the Asterisk community forums for support). Wrap code in backticks.

Moderated before publishing. Email never shown.
Related Snippets