FollowMe Dialplan Changes

Hello VitalPBX Team,

I recently noticed a small issue in the follow me dialplan, that would cause queue call to extensions that have “Record Caller’s Name” enabled in their follow me settings, to not prompt for call confirmation.
Now, the fix for that issue is quite simple, just move the line that sets the FWM_CONFIRMATION variable to after the start-dialing label so it’s always executed. However, since I was already checking out the follow me dialplan, I decided to try to enhance it a bit and gain the below.

  1. Remove the follow me numbers (destinations) from being hard coded in the conf file, so we can have a feature code to change the follow me numbers, having such feature is really useful so you can have end users set their follow me number on their own, without having to give each user a portal login

  2. Decrease the number of context, currently every single extension has it’s own follow me confirmation context, which results in dialplan relaods taking up to a few seconds on larger systems, as it has to scan ~ 1000 context.

  3. Make the follow me and call confirmation dialplans multi tenant compatible, so it can be moved to the baseplan file (why not)

So I played around and came up with the below.

I created 2 new odbc functions, one to get the follow me settings (including the numbers), and one to get the follow me recordings. See below.

[FOLLOW_ME]
writehandle=vitalpbx
readsql=SELECT REPLACE(followme_numbers,',','-'),(CASE WHEN ringtime = 0 THEN (SELECT value from ombu_settings WHERE name='ringtime') ELSE ringtime END),ring_strategy,recname,enable_callee_prompt,internal_numbers_confirmation,music_group_id FROM ombu_followme WHERE extension_id = (SELECT extension_id FROM ombu_extensions WHERE extension='${SQL_ESC(${ARG1})}' AND tenant_id=(SELECT tenant_id from ombu_tenants WHERE path='${SQL_ESC(${ARG2})}'))

[FOLLOW_ME_RECORDINGS]
writehandle=vitalpbx
readsql=SELECT Md5(call_from_prompt_id),Md5(norecording_prompt_id),Md5(status_prompt_id),Md5(pls_hold_prompt_id),Md5(sorry_prompt_id) FROM ombu_followme WHERE extension_id = (SELECT extension_id FROM ombu_extensions WHERE extension='${SQL_ESC(${ARG1})}' AND tenant_id=(SELECT tenant_id from ombu_tenants WHERE path='${SQL_ESC(${ARG2})}'))

Then I took the existing follow me dialplans and changed it to use those functions instead of hard coded data, see below.

[exten-followme]
exten => s,1,NoOp(Follow Me: ${CALL_DESTINATION})
 same => n,ExecIf($["${LEN(${INBOUND_LANGUAGE})}"!="0"]?Set(CHANNEL(language)=${INBOUND_LANGUAGE}):Set(CHANNEL(language)=${DB(${TENANT}/extensions/${CALL_DESTINATION}/language)}))
 same => n,Set(__RETURN_ON_EXTERNAL=yes)
 same => n,Set(__SKIP_PLAYBACK=${IF($["${QUEUE_CALL}"="TRUE"]?TRUE:${SKIP_PLAYBACK})})
 same => n,Set(ARRAY(followme_numbers,followme_ringtime,ring_strategy,record_name,confirm_call,internal_confirm,moh_class)=${ODBC_FOLLOW_ME(${CALL_DESTINATION},${TENANT})})
 same => n,GotoIf($[!${EXISTS(${followme_numbers})}]?end)
 same => n,Set(__FWM_CONFIRMATION=${IF($["${confirm_call}"="yes"]?TRUE:FALSE)})
 same => n,Set(__FWM_INTERNAL_CONFIRM=${IF($["${internal_confirm}"="yes"]?TRUE:FALSE)})
 same => n,ExecIf($["${moh_class}"="1"]?Set(moh_class=default):Set(moh_class=${IF(${EXISTS(${moh_class})}?moh${moh_class}:ringback)}))
 same => n,Set(ARRAY(call_from_sound,no_recording_sound,status_sound,pls_hold_sound,sorry_sound)=${ODBC_FOLLOW_ME_RECORDINGS(${CALL_DESTINATION},${TENANT})})
 same => n,Set(call_from_sound=${IF($["${call_from_sound}"="${MD5(1)}"]?followme/call-from:/var/lib/vitalpbx/static/${TENANT}/recordings/${call_from_sound})})
 same => n,Set(no_recording_sound=${IF($["${no_recording_sound}"="${MD5(1)}"]?followme/no-recording:/var/lib/vitalpbx/static/${TENANT}/recordings/${no_recording_sound})})
 same => n,ExecIf($["${status_sound}"="${MD5(1)}"]?Set(status_sound=followme/status):Set(status_sound=${IF(${EXISTS(${status_sound})}?/var/lib/vitalpbx/static/${TENANT}/recordings/${status_sound})}))
 same => n,ExecIf($["${pls_hold_sound}"="${MD5(1)}"]?Set(pls_hold_sound=followme/pls-hold-while-try):Set(pls_hold_sound=${IF(${EXISTS(${pls_hold_sound})}?/var/lib/vitalpbx/static/${TENANT}/recordings/${pls_hold_sound})}))
 same => n,ExecIf($["${sorry_sound}"="${MD5(1)}"]?Set(sorry_sound=followme/sorry):Set(sorry_sound=${IF(${EXISTS(${sorry_sound})}?/var/lib/vitalpbx/static/${TENANT}/recordings/${sorry_sound})}))
 same => n,Set(__O_RING_TIME=${followme_ringtime})
 same => n,Set(__SKIP_CONTACT_SERVICES=TRUE)
 same => n,Set(__SRC_APP=${IF($["${LEN(${SRC_APP})}"="0"]?FW${CALL_DESTINATION}:${SRC_APP})})
 same => n,GotoIf($[$["${SKIP_PLAYBACK}"="TRUE"]|$["${record_name}"="no"]]?skip-record)
 same => n,Set(CALLER_RECORDING=${ASTSPOOLDIR}/tmp/followme-${UNIQUEID}.wav)
 same => n,Playback(vm-rec-name)
 same => n,Record(${CALLER_RECORDING},5,20,)
 same => n,Set(FWM_RECORDED_NAME=${RECORDED_FILE})
 same => n(skip-record),NoOp(Start Dialing)
 same => n,ExecIf($[$["${SKIP_PLAYBACK}"!="TRUE"]&$["${status_sound}"!=""]]?Playback(${status_sound}):)
 same => n,ExecIf($[$["${SKIP_PLAYBACK}"!="TRUE"]&$["${pls_hold_sound}"!=""]]?Playback(${pls_hold_sound}):)
 same => n,Gosub(sub-set-moh,s,1(${moh_class},YES))
 same => n,Set(__FWM_SOUND=${IF($["${LEN(${FWM_RECORDED_NAME})}"="0"]?${no_recording_sound}:${call_from_sound}&${FWM_RECORDED_NAME})})
 same => n,Set(counter=1)
 same => n,Set(current_number=${CUT(followme_numbers,,${counter})})
 same => n,While(${EXISTS(${current_number})})
 same => n,Set(current_dial_string=Local/${current_number}@${DESTINATION_COS_NAME}/n)
 same => n,ExecIf($["${ring_strategy}"="one_by_one"]?Dial(${current_dial_string},${followme_ringtime},r):Set(followme_dial=${IF($["${counter}"="1"]?${current_dial_string}:${followme_dial}&${current_dial_string})}))
 same => n,Set(counter=$[${counter} + 1])
 same => n,Set(current_number=${CUT(followme_numbers,,${counter})})
 same => n,EndWhile()
 same => n,ExecIf($["${followme_dial}"!=""]?Dial(${followme_dial},${followme_ringtime},r))
 same => n,System(rm -f ${CALLER_RECORDING})
 same => n,ExecIf($[$["${SKIP_PLAYBACK}"!="TRUE"]&$["${DIALSTATUS}"!="ANSWER"]&$["${sorry_sound}"!=""]]?Playback(${sorry_sound}):)
 same => n,Set(__SKIP_CONTACT_SERVICES=FALSE)
 same => n(end),Return()

[confirm-call]
exten => s,1,NoOp(Confirm Call)
 same => n,ExecIf($["${LEN(${INBOUND_LANGUAGE})}"!="0"]?Set(CHANNEL(language)=${INBOUND_LANGUAGE}):Set(CHANNEL(language)=${DB(${TENANT}/extensions/${ARG1}/language)}))
 same => n,Set(DIALED_NUMBER=${CUT(DIALEDPEERNUMBER,@,1)})
 same => n,GotoIf($[$["${FWM_INTERNAL_CONFIRM}"="FLASE"]&$["${DB_EXISTS(${TENANT}/extensions/${ARG2}/name)}"="1"]]?accept)
 same => n,Set(GOSUB_RESULT=CONTINUE)
 same => n,Read(CONFIRM,${FWM_SOUND}&followme/options,1,,1,5)
 same => n,Set(_GOSUB_RESULT=${IF($["${CONFIRM}" = "1"]?:${GOSUB_RESULT})})
 same => n(accept),Return()

I then removed priority 7 and 8 in the sub-before-bridging-call context, and replaced it with this one line

same => n,GosubIf($["${FWM_CONFIRMATION}"="TRUE"]?confirm-call,s,1(${CALLER},${CALLEE})) 

And it worked… I tested it across multiple tenants and extensions, with all types of follow me configurations, and it all worked perfectly fine.

Thank you.

1 Like

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.