Convert Asterisk dial plan for use in FreePBX



  • So continuing on from here..

    https://mangolassi.it/topic/18756/need-to-parse-large-conf-files

    This allowed us to quickly locate things that needed to be looked at.

    Now it is time to parse this into something that we can use to recreate in FreePBX.

    Let's look at one context only as Asterisk understands it.

    [email protected]:~# asterisk -x "dialplan show ivrCLIENTNAME"
    [ Context 'ivrCLIENTNAME' created by 'pbx_config' ]
      '*' =>            1. Goto(346690,end_call)                      [pbx_config]
      '0' =>            1. NoOp()                                     [pbx_config]
                        2. GotoIf($["${AH}"="1"]?346690,lbl_clientname_menu:from-sra,0,1) [pbx_config]
      '346690' =>       1. NoOp()                                     [pbx_config]
                        2. Answer()                                   [pbx_config]
                        3. Wait(1)                                    [pbx_config]
         [lbl_CLIENTNAME_menu] 4. Set(TIMEOUT(response)=10)                  [pbx_config]
                        5. Set(TIMEOUT(digit)=3)                      [pbx_config]
                        6. GotoIfTime(10:30-19:30,mon-fri,*,*?bizhours:afterhours) [pbx_config]
         [bizhours]     7. NoOp()                                     [pbx_config]
                        8. GotoIfTime(*,*,1,jan?holiday)              [pbx_config]
                        9. GotoIfTime(*,*,21,jan?holiday)             [pbx_config]
                        10. GotoIfTime(*,*,27,may?holiday)            [pbx_config]
                        11. GotoIfTime(*,*,4,jul?holiday)             [pbx_config]
                        12. GotoIfTime(*,*,2,sep?holiday)             [pbx_config]
                        13. GotoIfTime(*,*,28,nov?holiday)            [pbx_config]
                        14. GotoIfTime(*,*,29,nov?holiday)            [pbx_config]
                        15. GotoIfTime(*,*,25,dec?holiday)            [pbx_config]
                        16. Background(/var/lib/asterisk/sounds/en/chi/clientname_main) [pbx_config]
                        17. WaitExten(3)                              [pbx_config]
                        18. SipAddHeader(Diversion:<tel:${EXTEN}>;reason=no-answer;screen=no;privacy=off) [pbx_config]
                        19. Dial(SIP/ExchUM1/6040)                    [pbx_config]
                        20. Dial(SIP/ExchUM2/6040)                    [pbx_config]
         [end_call]     21. Hangup()                                  [pbx_config]
         [afterhours]   22. NoOp()                                    [pbx_config]
                        23. Set(AH=1)                                 [pbx_config]
                        24. Background(/var/lib/asterisk/sounds/en/chi/clientname_closed) [pbx_config]
                        25. WaitExten(3)                              [pbx_config]
                        26. SipAddHeader(Diversion:<tel:${EXTEN}>;reason=no-answer;screen=no;privacy=off) [pbx_config]
                        27. Dial(SIP/ExchUM1/6040)                    [pbx_config]
                        28. Dial(SIP/ExchUM2/6040)                    [pbx_config]
                        29. Hangup()                                  [pbx_config]
         [holiday]      30. NoOp()                                    [pbx_config]
                        31. Set(AH=1)                                 [pbx_config]
                        32. Background(/var/lib/asterisk/sounds/en/chi/clientname_holiday) [pbx_config]
                        33. WaitExten(3)                              [pbx_config]
                        34. SipAddHeader(Diversion:<tel:${EXTEN}>;reason=no-answer;screen=no;privacy=off) [pbx_config]
                        35. Dial(SIP/ExchUM1/6040)                    [pbx_config]
                        36. Dial(SIP/ExchUM2/6040)                    [pbx_config]
                        37. Hangup()                                  [pbx_config]
      '9' =>            1. NoOp()                                     [pbx_config]
                        2. Dial(SIP/[email protected])                   [pbx_config]
                        3. Dial(SIP/[email protected])                   [pbx_config]
                        4. Hangup()                                   [pbx_config]
      'i' =>            1. Playback(invalid)                          [pbx_config]
                        2. Goto(346690,lbl_CLIENTNAME_menu)           [pbx_config]
      't' =>            1. Playback(timeout)                          [pbx_config]
                        2. Goto(346690,lbl_CLIENTNAME_menu)           [pbx_config]
      '_3466XX' =>      1. NoOp()                                     [pbx_config]
                        2. Goto(main,${EXTEN},1)                      [pbx_config]
                        3. Hangup()                                   [pbx_config]
      '_66XX' =>        1. NoOp()                                     [pbx_config]
                        2. Goto(main,34${EXTEN},1)                    [pbx_config]
                        3. Hangup()                                   [pbx_config]
    

    Everything with => is an event that is triggered.
    The 346690 is the extension for this IVR, this is not used by FreePBX.
    The *, 0, and 9 are the Press 9 for X.
    The _3466XX and _66XX are allowing extension dialing.
    The i and t are the invalid entry and timeout actions.
    The stuff in the square brackets are simply labels for the various goto statements

    This one is an IVR. IVR cannot be imported into FreePBX natively, but you can insert them into the MySQL database directly, if you know what you are doing.

    I will do it manually right after I post this, and then will post the output of that so we can work towards a script to do the work.



  • Here is the GUI look for setting up the IVR.
    cdd1204c-eeab-4d64-acca-30a430e09a7e-image.png
    66fca24a-3b4f-41e5-8b65-2a242e15b96d-image.png
    177f23de-cb66-43c4-9710-a595341b8cd2-image.png



  • Here is what gets put into MySQL

    SELECT * FROM `ivr_details` WHERE `id` = 4
    
    Column Name Value
    id 4
    name Client_Day
    description Client Day
    announcement 4
    directdial ext-local
    invalid_loops 3
    invalid_retry_recording default
    invalid_destination app-blackhole,hangup,1
    timeout_enabled NULL
    invalid_recording default
    retvm
    timeout_time 10
    timeout_recording default
    timeout_retry_recording default
    timeout_destination app-blackhole,hangup,1
    timeout_loops 3
    timeout_append_announce 1
    invalid_append_announce 1
    timeout_ivr_ret 0
    invalid_ivr_ret 0
    alertinfo
    rvolume 0
    strict_dial_timeout 0
    SELECT * FROM `ivr_entries` WHERE `ivr_id` = 4 ORDER BY `selection`
    
    ivr_id selection dest ivr_ret
    4 * app-blackhole,hangup,1 0
    4 0 ivr-4,s,1 0
    4 9 um-vm,s,1 0


  • Now that we have all of the pieces, let's put together what we can do.

    • Hours and holiday are done outside of the IVR. So that will be a separate work up.
    • The announcement links to a sound recording by id number. So that means the recordings need to be added first and a subquery put into the SQL statement to look it up.
      • This should be straightforward assuming that names are matched up.
      • Sounds can be uploaded with SCP and potentially inserted into MySQL.
    • The id field is an auto-increment.
      • This leans me to overriding that during the mass import. Opinions appreciated.
    • name and description should match except that name has no spaces allowed.
    • When extension dialing is allowed directdial has the value ext-local else it has Disabled
    • The rest of the fields should be set as shown above.

    The ivr_entries is going to be more complicated. The exmaple above was simple. * is hangup call. 0 is play again, and 9 was the dial by name directory in Exchange UM.

    But other another IVR has calls forwarded out to external numbers.
    Those are setup under Misc. Destinations.
    f82a878a-14d5-42cd-8187-3d4d5650a6ef-image.png



  • @JaredBusch said in Convert Asterisk dial plan for use in FreePBX:

    • The id field is an auto-increment.
      • This leans me to overriding that during the mass import. Opinions appreciated.

    Just omit the id field completely when you insert rows and it will handle itself.



  • @Pete-S said in Convert Asterisk dial plan for use in FreePBX:

    @JaredBusch said in Convert Asterisk dial plan for use in FreePBX:

    • The id field is an auto-increment.
      • This leans me to overriding that during the mass import. Opinions appreciated.

    Just omit the id field completely when you insert rows and it will handle itself.

    Except I have to know it to use it in the ivr_entries. Yes it could be requeried, but why? I can simply specify it as I parse down the dialplan.
    Turning of identity insert is a trivial and common task when importing/migrating like this.



  • @JaredBusch said in Convert Asterisk dial plan for use in FreePBX:

    @Pete-S said in Convert Asterisk dial plan for use in FreePBX:

    @JaredBusch said in Convert Asterisk dial plan for use in FreePBX:

    • The id field is an auto-increment.
      • This leans me to overriding that during the mass import. Opinions appreciated.

    Just omit the id field completely when you insert rows and it will handle itself.

    Except I have to know it to use it in the ivr_entries. Yes it could be requeried, but why? I can simply specify it as I parse down the dialplan.
    Turning of identity insert is a trivial and common task when importing/migrating like this.

    The purpose of turning it off is only when you want to make sure you have the same id. Maybe the id is referring to a filename or something like that and you are importing into empty tables. Otherwise it is bad practice.

    Good practice is to use SELECT LAST_INSERT_ID(); after insert (if you need the number) and let mysql handle the autoincrement. Then you can be certain you are not trying to insert the same id as has already been used.



  • @Pete-S said in Convert Asterisk dial plan for use in FreePBX:

    @JaredBusch said in Convert Asterisk dial plan for use in FreePBX:

    @Pete-S said in Convert Asterisk dial plan for use in FreePBX:

    @JaredBusch said in Convert Asterisk dial plan for use in FreePBX:

    • The id field is an auto-increment.
      • This leans me to overriding that during the mass import. Opinions appreciated.

    Just omit the id field completely when you insert rows and it will handle itself.

    Except I have to know it to use it in the ivr_entries. Yes it could be requeried, but why? I can simply specify it as I parse down the dialplan.
    Turning of identity insert is a trivial and common task when importing/migrating like this.

    The purpose of turning it off is only when you want to make sure you have the same id. Maybe the id is referring to a filename or something like that and you are importing into empty tables. Otherwise it is bad practice.

    Good practice is to use SELECT LAST_INSERT_ID(); after insert and let mysql handle the autoincrement. Then you can be certain you are not trying to insert the same id as has already been used.

    It is certainly not a "good" or a "bad" practice. It is a tool to be used appropriately with understanding of how the tool works.

    select last insert just adds overhead and slows things down when doing large scale migrations. I use it all the time when creating stored procs and other small one at a time tasks. But it is just silly to design a large script like this (eventually inserting ~100 IVR) around it.



  • For reference, here is the same IVR dialplan as output by FreePBX

    asterisk -x "dialplan show ivr-4"
    [ Context 'ivr-4' created by 'pbx_config' ]
      '*' =>            1. Set(__ivrreturn=0)                         [extensions_additional.conf:4167]
         [ivrsel-*]     2. Goto(app-blackhole,hangup,1)               [extensions_additional.conf:4168]
      '0' =>            1. Set(__ivrreturn=0)                         [extensions_additional.conf:4164]
         [ivrsel-0]     2. Goto(ivr-4,s,1)                            [extensions_additional.conf:4165]
      '9' =>            1. Set(__ivrreturn=0)                         [extensions_additional.conf:4170]
         [ivrsel-9]     2. Goto(um-vm,s,1)                            [extensions_additional.conf:4171]
      'fax' =>          1. Goto(${CUT(FAX_DEST,^,1)},${CUT(FAX_DEST,^,2)},${CUT(FAX_DEST,^,3)}) [extensions_additional.conf:4149]
      'h' =>            1. Hangup()                                   [extensions_additional.conf:4192]
      'hang' =>         1. Playback(vm-goodbye)                       [extensions_additional.conf:4194]
                        2. Hangup()                                   [extensions_additional.conf:4195]
      'i' =>            1. Set(INVALID_LOOPCOUNT=$[${INVALID_LOOPCOUNT}+1]) [extensions_additional.conf:4173]
                        2. GotoIf($[${INVALID_LOOPCOUNT} > 3]?final)  [extensions_additional.conf:4174]
                        3. Set(IVR_MSG=no-valid-responce-pls-try-again&custom/client_main)     [extensions_additional.conf:4175]
                        4. Goto(s,start)                              [extensions_additional.conf:4176]
         [final]        5. Playback(no-valid-responce-transfering)    [extensions_additional.conf:4177]
                        6. Goto(app-blackhole,hangup,1)               [extensions_additional.conf:4178]
      'return' =>       1. Set(_IVR_CONTEXT=${CONTEXT})               [extensions_additional.conf:4187]
                        2. Set(_IVR_CONTEXT_${CONTEXT}=${IVR_CONTEXT_${CONTEXT}}) [extensions_additional.conf:4188]
                        3. Set(IVR_MSG=custom/client_main)            [extensions_additional.conf:4189]
                        4. Goto(s,start)                              [extensions_additional.conf:4190]
      's' =>            1. Set(TIMEOUT_LOOPCOUNT=0)                   [extensions_additional.conf:4151]
                        2. Set(INVALID_LOOPCOUNT=0)                   [extensions_additional.conf:4152]
                        3. Set(_IVR_CONTEXT_${CONTEXT}=${IVR_CONTEXT}) [extensions_additional.conf:4153]
                        4. Set(_IVR_CONTEXT=${CONTEXT})               [extensions_additional.conf:4154]
                        5. Set(__IVR_RETVM=)                          [extensions_additional.conf:4155]
                        6. GotoIf($["${CHANNEL(state)}" = "Up"]?skip) [extensions_additional.conf:4156]
                        7. Answer()                                   [extensions_additional.conf:4157]
                        8. Wait(1)                                    [extensions_additional.conf:4158]
         [skip]         9. Set(IVR_MSG=custom/client_main)            [extensions_additional.conf:4159]
         [start]        10. Set(TIMEOUT(digit)=3)                     [extensions_additional.conf:4160]
                        11. ExecIf($["${IVR_MSG}" != ""]?Background(${IVR_MSG})) [extensions_additional.conf:4161]
                        12. WaitExten(10,)                            [extensions_additional.conf:4162]
      't' =>            1. Set(TIMEOUT_LOOPCOUNT=$[${TIMEOUT_LOOPCOUNT}+1]) [extensions_additional.conf:4180]
                        2. GotoIf($[${TIMEOUT_LOOPCOUNT} > 3]?final)  [extensions_additional.conf:4181]
                        3. Set(IVR_MSG=no-valid-responce-pls-try-again&custom/client_main)     [extensions_additional.conf:4182]
                        4. Goto(s,start)                              [extensions_additional.conf:4183]
         [final]        5. Playback(no-valid-responce-transfering)    [extensions_additional.conf:4184]
                        6. Goto(app-blackhole,hangup,1)               [extensions_additional.conf:4185]
      Include =>        'ivr-4-custom'                                [pbx_config]
      Include =>        'from-did-direct-ivr'                         [pbx_config]