Redirect calls from external to VM part2

Looking for guidance on my first custom dialplan

So let me explain, working for a school district using FreePBX. We do not want outside calls to be able to ring into a classroom extension during “class hours” but inside goes directly to voicemail. We want internal calls to be able to call into a classroom and calls to be able to transfer in. After class hours, the direct dial would ring directly into the classroom as normal.

For example, we have an IVR with direct dial enabled, and from 7am-3pm Monday-Friday any classroom extension will go to voicemail. To be able call into the classroom the caller will need to call the office from the IVR and the office can decide to transfer directly or to VM.

Since there was no built-in solution for this I just disable direct dial and told the school, parents will need to call the office to get transferred in. Not ideal but worked.

Finally, I rolled up my sleeves and try to build my first custom dialplan.

First I created a SQL database called customdb and a table called classroom_phones, with a list of extensions and daytimevm set to 1 to go voicemail.

| extension | daytimevm |
| 1002 | 1 |
| 1003 | 1 |

Then I added the following under /etc/asterisk/extensions.conf

include => daytimevm-custom
include => ext-findmefollow
include => ext-local

exten => _XXXX,1,Answer()
same => n,MYSQL(Connect connid localhost READONLY_USERNAME READONLY_PW customdb)
same => n,MYSQL(Query resultid ${connid} SELECT daytimevm from classroom_phones WHERE extension=’${EXTEN}’ AND daytimevm LIKE ‘1’ LIMIT 1)
same => n,MYSQL(Fetch fetchid ${resultid} classroom)
same => n,MYSQL(Disconnect ${connid})
same => n,NoOp(========== The DAYTIMEVM value is ${classroom} ==========)
same => n,GotoIf($["${classroom}" != “1”]?SkipForwardVM)
same => n,GotoIfTime(15:30-7:00,mon-sun,,?SkipForwardVM)
same => n(ForwardVM),Voicemail(${EXTEN},u)
same => n,Macro(hangupcall,)
same => n(SkipForwardVM),Goto(from-did-direct-continue,${EXTEN},1)

include => ext-findmefollow
include => ext-local

On my test system it seems to be working fine, but before I deploy this into production want to get your guys to opinion on this. Since this is my first I am sure, I am sure it is not efficiently written. The only thing I can not get working is Direct Dial when I have Directory with a spell by name directory enabled. From what I could tell FreePBX consider this an internal transfer that bypasses from-did-direct

Thanks in advance.

Given your
Then I added under extension.conf I added the following
I suggest you consider

head -32 /etc/asterisk/extensions.conf


Typo on my part. That is indeed the file I edited. Thanks for the heads up.

How many classroom extensions are there? Is it feasible to have a separate inbound route for each?

I have over 900 classroom extension spanning 13 campus. General we have most the enough DID for the administration but not enough for each classroom teachers.

The MySQL functions in Asterisk are deprecated and scheduled for removal in Asterisk 19 (source). It will be quite a while before you will be forced to use Asterisk 19, but you may want to investigate using ODBC as a more supportable way of doing the queries. [edit] Just remembered this technique for doing MySQL queries in diaplan that does not rely on either MySQL functions or ODBC.

You could actually use the GUI to flag which extensions get the special classroom treatment, but using @billsimon’s technique described here. Any local extension with the account code set to X will bypass the regular dial plan.

There is nothing wrong with hard coding the classroom hours time in the dialplan, but you might find it more flexible to monitor a Time Condition hint and perform the action based on that. You could then use the temp override for things like holidays/in-service etc.

Are you in the USA? Do you have any means of ensuring that inbound emergency calls from a PSAP don’t go to voicemail.

ODBC is cool and very easy once you get the hang of it, especially when you want to do more than one DB read/write in your dialplan.

(Thinking this may be a good subject/demo for the next OSS Lounge)

1 Like

func_odbc is life-changing.

One thing I have with it is to add SMS logging to the CDR DB, which is straightforward because FreePBX already uses ODBC to interface with the CDR DB.


Thanks, I will need to look into ODBC, but I like the looks of AMPUSER database instead. This would give me the flexibility to allow others that are not familiar with MySQL to edit settings. Are there any other fields besides accountcode that I can use? I am currently using accountcode for storing physical location of the phone.

Yes I am in the USA, and I have an inbound route emergency call back to a ring group. That will be able to direct\transfer them back into the room.

Be careful not to confuse the mysql ampuser table with the astdb.sqlite3 AMPUSER family , (where you could read and set the DND of an extension to accomplish similar behavior dynamically via a cron job or a systemd .timer service )

No. I have periodically considered putting multiple comma separated values in that field and then using REGEX or SHIFT to look thru them, but never did any actual tests to prove to myself that it would work.

Is there anything else that distinguishes classroom phones from admin phones, such as extension range? If so, you may be able to accomplish your goal without doing any kind of lookups at all, but just matching on an existing characteristic.

No sadly not, extensions are sprinkled in on who needs daytime calls, and every other year it changes due to room changes. Extension safe in the Room for example XX01 is room 1, XX02 is room 2 etc.

Regex might work! Thanks this is VERY helpful. I will post a new dialplan once I get something working. I am sure there are other school districts in the same situation.

You could also consider using part of the CallerID name string from the AstDB, i.e. if the first 9 characters $["${DB(AMPUSER/xxx/cidname):9}"= "Classroom"]

. . . or perhaps add an AMPUSER/xxx/Classroom field ?

Oh I think dicko is right, I am confusing the astdb.sqlite3 database with the mysql amuser. This accountcode is not the same as ${DB(AMPUSER/${AMPUSER}/accountcode)} is it?

The GUI/mysql data is for the most part static and only instigated on a ‘reload’, on the other hand manipulating the astdb is dynamic. If you decide to so manipulate the astdb, only use the asterisk database API ‘wrapper functions’, or you will regret it at some point in the future :wink: .

The GUI account code field is in the AstDB, and you can confirm that from the Asterisk console with

database show AMPUSER xxxx/accountcode

sub the ext number for the x’s

so “${DB(AMPUSER/${AMPUSER}/accountcode)}” and “database show AMPUSER xxxx/accountcode” is pointing to the same place?