function queues_check_compoundrecordings()
{
    global $db;
    $compound_recordings = array();
    $sql = "SELECT extension, descr, agentannounce_id, ivr_id FROM queues_config WHERE (ivr_id != 'none' AND ivr_id != '') OR agentannounce_id != ''";
    $results = sql($sql, "getAll", DB_FETCHMODE_ASSOC);
    if (function_exists('ivr_get_details')) {
        $ivr_details = ivr_get_details();
        foreach ($ivr_details as $item) {
            $ivr_hash[$item['id']] = $item;
        }
        $check_ivr = true;
    } else {
        $check_ivr = false;
    }
    foreach ($results as $result) {
        $agentannounce = $result['agentannounce_id'] ? recordings_get_file($result['agentannounce_id']) : '';
        if (strpos($agentannounce, "&") !== false) {
            $compound_recordings[] = array('extension' => $result['extension'], 'descr' => $result['descr'], 'error' => _("Agent Announce Msg"));
        }
        if ($result['ivr_id'] != 'none' && $result['ivr_id'] != '' && $check_ivr) {
            $id = $ivr_hash[$result['ivr_id']]['announcement_id'];
            $announce = $id ? recordings_get_file($id) : '';
            if (strpos($announce, "&") !== false) {
                $compound_recordings[] = array('extension' => $result['extension'], 'descr' => $result['descr'], 'error' => sprintf(_("IVR Announce: %s"), $ivr_hash[$result['ivr_id']]['displayname']));
            }
        }
    }
    return $compound_recordings;
}
Esempio n. 2
0
function announcement_get_config($engine)
{
    global $ext;
    switch ($engine) {
        case 'asterisk':
            foreach (announcement_list() as $row) {
                $recording = recordings_get_file($row['recording_id']);
                if (!$row['noanswer']) {
                    $ext->add('app-announcement-' . $row['announcement_id'], 's', '', new ext_gotoif('$["${CDR(disposition)}" = "ANSWERED"]', 'begin'));
                    $ext->add('app-announcement-' . $row['announcement_id'], 's', '', new ext_answer(''));
                    $ext->add('app-announcement-' . $row['announcement_id'], 's', '', new ext_wait('1'));
                } else {
                    $ext->add('app-announcement-' . $row['announcement_id'], 's', '', new ext_progress());
                }
                $ext->add('app-announcement-' . $row['announcement_id'], 's', 'begin', new ext_noop('Playing announcement ' . $row['description']));
                if ($row['allow_skip'] || $row['repeat_msg']) {
                    // allow skip
                    if ($row['repeat_msg']) {
                        $ext->add('app-announcement-' . $row['announcement_id'], 's', '', new ext_responsetimeout(1));
                    }
                    $ext->add('app-announcement-' . $row['announcement_id'], 's', 'play', new ext_background($recording . ',nm'));
                    if ($row['repeat_msg']) {
                        $ext->add('app-announcement-' . $row['announcement_id'], 's', '', new ext_waitexten(''));
                    }
                    if ($row['allow_skip']) {
                        $skip = "_[0-9*#]";
                        $ext->add('app-announcement-' . $row['announcement_id'], $skip, '', new ext_noop('User skipped announcement'));
                        if ($row['return_ivr']) {
                            $ext->add('app-announcement-' . $row['announcement_id'], $skip, '', new ext_gotoif('$["x${IVR_CONTEXT}" = "x"]', $row['post_dest'] . ':${IVR_CONTEXT},return,1'));
                        } else {
                            $ext->add('app-announcement-' . $row['announcement_id'], $skip, '', new ext_goto($row['post_dest']));
                        }
                    }
                    if ($row['repeat_msg']) {
                        $ext->add('app-announcement-' . $row['announcement_id'], $row['repeat_msg'], '', new ext_goto('s,play'));
                    }
                } else {
                    $ext->add('app-announcement-' . $row['announcement_id'], 's', '', new ext_playback($recording . ',noanswer'));
                }
                // if repeat_msg enabled then set exten to t to allow for the key to be pressed, otherwise play message and go
                $exten = $row['repeat_msg'] ? 't' : 's';
                if ($row['return_ivr']) {
                    $ext->add('app-announcement-' . $row['announcement_id'], $exten, '', new ext_gotoif('$["x${IVR_CONTEXT}" = "x"]', $row['post_dest'] . ':${IVR_CONTEXT},return,1'));
                    if ($row['allow_skip'] || $row['repeat_msg']) {
                        $ext->add('app-announcement-' . $row['announcement_id'], 'i', '', new ext_gotoif('$["x${IVR_CONTEXT}" = "x"]', $row['post_dest'] . ':${IVR_CONTEXT},return,1'));
                    }
                } else {
                    $ext->add('app-announcement-' . $row['announcement_id'], $exten, '', new ext_goto($row['post_dest']));
                    if ($row['allow_skip'] || $row['repeat_msg']) {
                        $ext->add('app-announcement-' . $row['announcement_id'], 'i', '', new ext_goto($row['post_dest']));
                    }
                }
            }
            break;
    }
}
Esempio n. 3
0
function ringgroups_get_config($engine)
{
    global $ext;
    // is this the best way to pass this?
    switch ($engine) {
        case "asterisk":
            $ext->addInclude('from-internal-additional', 'ext-group');
            $ext->addInclude('from-internal-additional', 'grps');
            $contextname = 'ext-group';
            $ringlist = ringgroups_list(true);
            if (is_array($ringlist)) {
                foreach ($ringlist as $item) {
                    $grpnum = ltrim($item['0']);
                    $grp = ringgroups_get($grpnum);
                    $strategy = $grp['strategy'];
                    $grptime = $grp['grptime'];
                    $grplist = $grp['grplist'];
                    $postdest = $grp['postdest'];
                    $grppre = isset($grp['grppre']) ? $grp['grppre'] : '';
                    $annmsg_id = isset($grp['annmsg_id']) ? $grp['annmsg_id'] : '';
                    $alertinfo = $grp['alertinfo'];
                    $needsconf = $grp['needsconf'];
                    $cwignore = $grp['cwignore'];
                    $cfignore = $grp['cfignore'];
                    $remotealert_id = $grp['remotealert_id'];
                    $toolate_id = $grp['toolate_id'];
                    $ringing = $grp['ringing'];
                    if ($ringing == 'Ring' || empty($ringing)) {
                        $dialopts = '${DIAL_OPTIONS}';
                    } else {
                        // We need the DIAL_OPTIONS variable
                        $sops = sql("SELECT value from globals where variable='DIAL_OPTIONS'", "getRow");
                        $dialopts = "m({$ringing})" . str_replace('r', '', $sops[0]);
                    }
                    $ext->add($contextname, $grpnum, '', new ext_macro('user-callerid'));
                    // block voicemail until phone is answered at which point a macro should be called on the answering
                    // line to clear this flag so that subsequent transfers can occur, if already set by a the caller
                    // then don't change.
                    //
                    $ext->add($contextname, $grpnum, '', new ext_gotoif('$["foo${BLKVM_OVERRIDE}" = "foo"]', 'skipdb'));
                    $ext->add($contextname, $grpnum, '', new ext_gotoif('$["${DB(${BLKVM_OVERRIDE})}" = "TRUE"]', 'skipov'));
                    $ext->add($contextname, $grpnum, 'skipdb', new ext_setvar('__NODEST', ''));
                    $ext->add($contextname, $grpnum, '', new ext_setvar('__BLKVM_OVERRIDE', 'BLKVM/${EXTEN}/${CHANNEL}'));
                    $ext->add($contextname, $grpnum, '', new ext_setvar('__BLKVM_BASE', '${EXTEN}'));
                    $ext->add($contextname, $grpnum, '', new ext_setvar('DB(${BLKVM_OVERRIDE})', 'TRUE'));
                    // Remember if NODEST was set later, but clear it in case the call is answered so that subsequent
                    // transfers work.
                    //
                    $ext->add($contextname, $grpnum, 'skipov', new ext_setvar('RRNODEST', '${NODEST}'));
                    $ext->add($contextname, $grpnum, 'skipvmblk', new ext_setvar('__NODEST', '${EXTEN}'));
                    $ext->add($contextname, $grpnum, '', new ext_gosubif('$[${DB_EXISTS(RINGGROUP/' . $grpnum . '/changecid)} = 1 & "${DB(RINGGROUP/' . $grpnum . '/changecid)}" != "default" & "${DB(RINGGROUP/' . $grpnum . '/changecid)}" != ""]', 'sub-rgsetcid,s,1'));
                    // deal with group CID prefix
                    // but strip only if you plan on setting a new one
                    if ($grppre != '') {
                        $ext->add($contextname, $grpnum, '', new ext_gotoif('$["foo${RGPREFIX}" = "foo"]', 'REPCID'));
                        $ext->add($contextname, $grpnum, '', new ext_gotoif('$["${RGPREFIX}" != "${CALLERID(name):0:${LEN(${RGPREFIX})}}"]', 'REPCID'));
                        $ext->add($contextname, $grpnum, '', new ext_noop('Current RGPREFIX is ${RGPREFIX}....stripping from Caller ID'));
                        $ext->add($contextname, $grpnum, '', new ext_setvar('CALLERID(name)', '${CALLERID(name):${LEN(${RGPREFIX})}}'));
                        $ext->add($contextname, $grpnum, '', new ext_setvar('_RGPREFIX', ''));
                        $ext->add($contextname, $grpnum, 'REPCID', new ext_noop('CALLERID(name) is ${CALLERID(name)}'));
                        $ext->add($contextname, $grpnum, '', new ext_setvar('_RGPREFIX', $grppre));
                        $ext->add($contextname, $grpnum, '', new ext_setvar('CALLERID(name)', '${RGPREFIX}${CALLERID(name)}'));
                    }
                    // Set Alert_Info
                    if ($alertinfo != '') {
                        $ext->add($contextname, $grpnum, '', new ext_setvar('__ALERT_INFO', str_replace(';', '\\;', $alertinfo)));
                    }
                    if ($cwignore != '') {
                        $ext->add($contextname, $grpnum, '', new ext_setvar('__CWIGNORE', 'TRUE'));
                    }
                    if ($cfignore != '') {
                        $ext->add($contextname, $grpnum, '', new ext_setvar('_CFIGNORE', 'TRUE'));
                        $ext->add($contextname, $grpnum, '', new ext_setvar('_FORWARD_CONTEXT', 'block-cf'));
                    }
                    // recording stuff
                    $ext->add($contextname, $grpnum, '', new ext_setvar('RecordMethod', 'Group'));
                    $ext->add($contextname, $grpnum, '', new ext_macro('record-enable', $grplist . ',${RecordMethod}'));
                    // group dial
                    $ext->add($contextname, $grpnum, '', new ext_setvar('RingGroupMethod', $strategy));
                    if ($annmsg_id) {
                        $annmsg = recordings_get_file($annmsg_id);
                        $ext->add($contextname, $grpnum, '', new ext_gotoif('$["foo${RRNODEST}" != "foo"]', 'DIALGRP'));
                        $ext->add($contextname, $grpnum, '', new ext_answer(''));
                        $ext->add($contextname, $grpnum, '', new ext_wait(1));
                        $ext->add($contextname, $grpnum, '', new ext_playback($annmsg));
                    }
                    if ($needsconf == "CHECKED") {
                        $remotealert = recordings_get_file($remotealert_id);
                        $toolate = recordings_get_file($toolate_id);
                        $len = strlen($grpnum) + 4;
                        $ext->add("grps", "_RG-{$grpnum}-.", '', new ext_macro('dial', $grptime . ",M(confirm^{$remotealert}^{$toolate}^{$grpnum}){$dialopts}" . ',${EXTEN:' . $len . '}'));
                        $ext->add($contextname, $grpnum, 'DIALGRP', new ext_macro('dial-confirm', "{$grptime},{$dialopts},{$grplist},{$grpnum}"));
                    } else {
                        $ext->add($contextname, $grpnum, 'DIALGRP', new ext_macro('dial', $grptime . ",{$dialopts}," . $grplist));
                    }
                    $ext->add($contextname, $grpnum, '', new ext_setvar('RingGroupMethod', ''));
                    // Now if we were told to skip the destination, do so now. Otherwise reset NODEST and proceed to our destination.
                    //
                    $ext->add($contextname, $grpnum, '', new ext_gotoif('$["foo${RRNODEST}" != "foo"]', 'nodest'));
                    if ($cwignore != '') {
                        $ext->add($contextname, $grpnum, '', new ext_setvar('__CWIGNORE', ''));
                    }
                    // TODO: Asterisk uses a blank FORWARD_CONTEXT as a literal at the time of this change. A better solution would be
                    //       if it would ignore blank, since it is possible in a customcontext setup you would not want this set to
                    //       from-internal
                    //
                    if ($cfignore != '') {
                        $ext->add($contextname, $grpnum, '', new ext_setvar('_CFIGNORE', ''));
                        $ext->add($contextname, $grpnum, '', new ext_setvar('_FORWARD_CONTEXT', 'from-internal'));
                    }
                    $ext->add($contextname, $grpnum, '', new ext_setvar('__NODEST', ''));
                    $ext->add($contextname, $grpnum, '', new ext_dbdel('${BLKVM_OVERRIDE}'));
                    // where next?
                    if ((isset($postdest) ? $postdest : '') != '') {
                        $ext->add($contextname, $grpnum, '', new ext_goto($postdest));
                    } else {
                        $ext->add($contextname, $grpnum, '', new ext_hangup(''));
                    }
                    $ext->add($contextname, $grpnum, 'nodest', new ext_noop('SKIPPING DEST, CALL CAME FROM Q/RG: ${RRNODEST}'));
                }
                // We need to have a hangup here, if call is ended by the caller during Playback it will end in the
                // h context and do a proper hangup and clean the BLKVM, see #4671
                $ext->add($contextname, 'h', '', new ext_macro('hangupcall'));
                /*
                  ASTDB Settings:
                  RINGGROUP/nnn/changecid default | did | fixed | extern
                  RINGGROUP/nnn/fixedcid XXXXXXXX
                
                  changecid:
                    default   - works as always, same as if not present
                    fixed     - set to the fixedcid
                    extern    - set to the fixedcid if the call is from the outside only
                    did       - set to the DID that the call came in on or leave alone, treated as foreign
                    forcedid  - set to the DID that the call came in on or leave alone, not treated as foreign
                  
                  NODEST      - has the exten num called, hoaky if that goes away but for now use it
                */
                if (count($ringlist)) {
                    $contextname = 'sub-rgsetcid';
                    $exten = 's';
                    $ext->add($contextname, $exten, '', new ext_goto('1', 's-${DB(RINGGROUP/${NODEST}/changecid)}'));
                    $exten = 's-fixed';
                    $ext->add($contextname, $exten, '', new ext_execif('$["${REGEX("^[\\+]?[0-9]+$" ${DB(RINGGROUP/${NODEST}/fixedcid)})}" = "1"]', 'Set', '__TRUNKCIDOVERRIDE=${DB(RINGGROUP/${NODEST}/fixedcid)}'));
                    $ext->add($contextname, $exten, '', new ext_return(''));
                    $exten = 's-extern';
                    $ext->add($contextname, $exten, '', new ext_execif('$["${REGEX("^[\\+]?[0-9]+$" ${DB(RINGGROUP/${NODEST}/fixedcid)})}" == "1" & "${FROM_DID}" != ""]', 'Set', '__TRUNKCIDOVERRIDE=${DB(RINGGROUP/${NODEST}/fixedcid)}'));
                    $ext->add($contextname, $exten, '', new ext_return(''));
                    $exten = 's-did';
                    $ext->add($contextname, $exten, '', new ext_execif('$["${REGEX("^[\\+]?[0-9]+$" ${FROM_DID})}" = "1"]', 'Set', '__REALCALLERIDNUM=${FROM_DID}'));
                    $ext->add($contextname, $exten, '', new ext_return(''));
                    $exten = 's-forcedid';
                    $ext->add($contextname, $exten, '', new ext_execif('$["${REGEX("^[\\+]?[0-9]+$" ${FROM_DID})}" = "1"]', 'Set', '__TRUNKCIDOVERRIDE=${FROM_DID}'));
                    $ext->add($contextname, $exten, '', new ext_return(''));
                    $exten = '_s-.';
                    $ext->add($contextname, $exten, '', new ext_noop('Unknown value for RINGGROUP/${NODEST}/changecid of ${DB(RINGGROUP/${NODEST}/changecid)} set to "default"'));
                    $ext->add($contextname, $exten, '', new ext_setvar('DB(RINGGROUP/${NODEST}/changecid)', 'default'));
                    $ext->add($contextname, $exten, '', new ext_return(''));
                }
            }
            break;
    }
}
function ringgroups_get_config($engine)
{
    global $ext;
    // is this the best way to pass this?
    global $amp_conf;
    switch ($engine) {
        case "asterisk":
            $ext->addInclude('from-internal-additional', 'ext-group');
            $ext->addInclude('from-internal-additional', 'grps');
            $contextname = 'ext-group';
            $ringlist = ringgroups_list(true);
            if (is_array($ringlist)) {
                foreach ($ringlist as $item) {
                    $grpnum = ltrim($item['0']);
                    $grp = ringgroups_get($grpnum);
                    $strategy = $grp['strategy'];
                    $grptime = $grp['grptime'];
                    $grplist = $grp['grplist'];
                    $postdest = $grp['postdest'];
                    $grppre = isset($grp['grppre']) ? $grp['grppre'] : '';
                    $progress = isset($grp['progress']) ? $grp['progress'] : 'yes';
                    $annmsg_id = isset($grp['annmsg_id']) ? $grp['annmsg_id'] : '';
                    $alertinfo = $grp['alertinfo'];
                    $needsconf = $grp['needsconf'];
                    $cwignore = $grp['cwignore'];
                    $cpickup = $grp['cpickup'];
                    $cfignore = $grp['cfignore'];
                    $remotealert_id = $grp['remotealert_id'];
                    $toolate_id = $grp['toolate_id'];
                    $ringing = $grp['ringing'];
                    $recording = $grp['recording'] == '' ? 'dontcare' : $grp['recording'];
                    // TODO: this looks potentially problematic given the new per-user DIAL_OPTIONS. Need to further
                    //       evaluate/understand if there are implications. The issue may be that we are trying to
                    //       avoid getting a 'polluted' version of the DIAL_OPTIONS in which case we may need to modify
                    //       macro-user-callerid (where it is set) to preserve the version we should be using.
                    //
                    if ($ringing == 'Ring' || empty($ringing)) {
                        $dialopts = '${DIAL_OPTIONS}';
                    } elseif ($ringing == "inherit") {
                        $dialopts = 'm(${CHANNEL(musicclass)})${REPLACE(DIAL_OPTIONS,r)}';
                    } else {
                        $dialopts = 'm(' . $ringing . ')${REPLACE(DIAL_OPTIONS,r)}';
                    }
                    if ($progress == 'yes') {
                        $ext->add($contextname, $grpnum, '', new ext_gotoif('$["${__RINGINGSENT}" = "TRUE"]', 'cid'));
                        if ($ringing == 'Ring' || empty($ringing)) {
                            $ext->add($contextname, $grpnum, '', new ext_playtones("ring"));
                        }
                        $ext->add($contextname, $grpnum, '', new ext_progress());
                    }
                    $ext->add($contextname, $grpnum, 'cid', new ext_macro('user-callerid'));
                    // block voicemail until phone is answered at which point a macro should be called on the answering
                    // line to clear this flag so that subsequent transfers can occur, if already set by a the caller
                    // then don't change.
                    //
                    $ext->add($contextname, $grpnum, '', new ext_macro('blkvm-setifempty'));
                    $ext->add($contextname, $grpnum, '', new ext_gotoif('$["${GOSUB_RETVAL}" = "TRUE"]', 'skipov'));
                    $ext->add($contextname, $grpnum, '', new ext_macro('blkvm-set', 'reset'));
                    $ext->add($contextname, $grpnum, '', new ext_setvar('__NODEST', ''));
                    // Remember if NODEST was set later, but clear it in case the call is answered so that subsequent
                    // transfers work.
                    //
                    $ext->add($contextname, $grpnum, 'skipov', new ext_setvar('RRNODEST', '${NODEST}'));
                    $ext->add($contextname, $grpnum, 'skipvmblk', new ext_setvar('__NODEST', '${EXTEN}'));
                    $ext->add($contextname, $grpnum, '', new ext_gosubif('$[${DB_EXISTS(RINGGROUP/' . $grpnum . '/changecid)} = 1 & "${DB(RINGGROUP/' . $grpnum . '/changecid)}" != "default" & "${DB(RINGGROUP/' . $grpnum . '/changecid)}" != ""]', 'sub-rgsetcid,s,1'));
                    // deal with group CID prefix
                    if ($grppre != '') {
                        $ext->add($contextname, $grpnum, '', new ext_macro('prepend-cid', $grppre));
                    }
                    // Set Alert_Info
                    if ($alertinfo != '') {
                        $ext->add($contextname, $grpnum, '', new ext_setvar('__ALERT_INFO', str_replace(';', '\\;', $alertinfo)));
                    }
                    if ($cwignore != '') {
                        $ext->add($contextname, $grpnum, '', new ext_setvar('__CWIGNORE', 'TRUE'));
                    }
                    if ($cfignore != '') {
                        $ext->add($contextname, $grpnum, '', new ext_setvar('_CFIGNORE', 'TRUE'));
                        $ext->add($contextname, $grpnum, '', new ext_setvar('_FORWARD_CONTEXT', 'block-cf'));
                    }
                    if ($cpickup != '') {
                        $ext->add($contextname, $grpnum, '', new ext_set('__PICKUPMARK', '${EXTEN}'));
                    }
                    // recording stuff
                    //$ext->add($contextname, $grpnum, '', new ext_setvar('RecordMethod','Group'));
                    //$ext->add($contextname, $grpnum, '', new ext_macro('record-enable',$grplist.',${RecordMethod}'));
                    //TODO: hardcoded needs to be configurable in the ringgroup
                    $ext->add($contextname, $grpnum, '', new ext_gosub('1', 's', 'sub-record-check', "rg,{$grpnum},{$recording}"));
                    // group dial
                    $ext->add($contextname, $grpnum, '', new ext_setvar('RingGroupMethod', $strategy));
                    if ($annmsg_id) {
                        $annmsg = recordings_get_file($annmsg_id);
                        $ext->add($contextname, $grpnum, '', new ext_gotoif('$["foo${RRNODEST}" != "foo"]', 'DIALGRP'));
                        $ext->add($contextname, $grpnum, '', new ext_answer(''));
                        $ext->add($contextname, $grpnum, '', new ext_wait(1));
                        $ext->add($contextname, $grpnum, '', new ext_playback($annmsg));
                    }
                    if ($needsconf == "CHECKED") {
                        $remotealert = recordings_get_file($remotealert_id);
                        $toolate = recordings_get_file($toolate_id);
                        $len = strlen($grpnum) + 4;
                        $ext->add("grps", "_RG-{$grpnum}-.", '', new ext_nocdr(''));
                        $ext->add("grps", "_RG-{$grpnum}-.", '', new ext_macro('dial', "{$grptime},{$dialopts}" . "M(confirm^{$remotealert}^{$toolate}^{$grpnum})" . ',${EXTEN:' . $len . '}'));
                        $ext->add($contextname, $grpnum, 'DIALGRP', new ext_macro('dial-confirm', "{$grptime},{$dialopts},{$grplist},{$grpnum}"));
                    } else {
                        $ext->add($contextname, $grpnum, 'DIALGRP', new ext_macro('dial', $grptime . ",{$dialopts}," . $grplist));
                    }
                    $ext->add($contextname, $grpnum, '', new ext_gosub('1', 's', 'sub-record-cancel'));
                    $ext->add($contextname, $grpnum, '', new ext_setvar('RingGroupMethod', ''));
                    // Now if we were told to skip the destination, do so now. Otherwise reset NODEST and proceed to our destination.
                    //
                    $ext->add($contextname, $grpnum, '', new ext_gotoif('$["foo${RRNODEST}" != "foo"]', 'nodest'));
                    if ($cwignore != '') {
                        $ext->add($contextname, $grpnum, '', new ext_setvar('__CWIGNORE', ''));
                    }
                    if ($cpickup != '') {
                        $ext->add($contextname, $grpnum, '', new ext_set('__PICKUPMARK', ''));
                    }
                    // TODO: Asterisk uses a blank FORWARD_CONTEXT as a literal at the time of this change. A better solution would be
                    //       if it would ignore blank, since it is possible in a customcontext setup you would not want this set to
                    //       from-internal
                    //
                    if ($cfignore != '') {
                        $ext->add($contextname, $grpnum, '', new ext_setvar('_CFIGNORE', ''));
                        $ext->add($contextname, $grpnum, '', new ext_setvar('_FORWARD_CONTEXT', 'from-internal'));
                    }
                    $ext->add($contextname, $grpnum, '', new ext_setvar('__NODEST', ''));
                    $ext->add($contextname, $grpnum, '', new ext_macro('blkvm-clr'));
                    // where next?
                    if ((isset($postdest) ? $postdest : '') != '') {
                        $ext->add($contextname, $grpnum, '', new ext_goto($postdest));
                    } else {
                        $ext->add($contextname, $grpnum, '', new ext_hangup(''));
                    }
                    $ext->add($contextname, $grpnum, 'nodest', new ext_noop('SKIPPING DEST, CALL CAME FROM Q/RG: ${RRNODEST}'));
                }
                // We need to have a hangup here, if call is ended by the caller during Playback it will end in the
                // h context and do a proper hangup and clean the blkvm keys if set, see #4671
                $ext->add($contextname, 'h', '', new ext_macro('hangupcall'));
                /*
                  ASTDB Settings:
                  RINGGROUP/nnn/changecid default | did | fixed | extern
                  RINGGROUP/nnn/fixedcid XXXXXXXX
                
                  changecid:
                    default   - works as always, same as if not present
                    fixed     - set to the fixedcid
                    extern    - set to the fixedcid if the call is from the outside only
                    did       - set to the DID that the call came in on or leave alone, treated as foreign
                    forcedid  - set to the DID that the call came in on or leave alone, not treated as foreign
                
                  NODEST      - has the exten num called, hoaky if that goes away but for now use it
                */
                if (count($ringlist)) {
                    $contextname = 'sub-rgsetcid';
                    $exten = 's';
                    $ext->add($contextname, $exten, '', new ext_goto('1', 's-${DB(RINGGROUP/${NODEST}/changecid)}'));
                    $exten = 's-fixed';
                    $ext->add($contextname, $exten, '', new ext_execif('$["${REGEX("^[\\+]?[0-9]+$" ${DB(RINGGROUP/${NODEST}/fixedcid)})}" = "1"]', 'Set', '__TRUNKCIDOVERRIDE=${DB(RINGGROUP/${NODEST}/fixedcid)}'));
                    $ext->add($contextname, $exten, '', new ext_return(''));
                    $exten = 's-extern';
                    $ext->add($contextname, $exten, '', new ext_execif('$["${REGEX("^[\\+]?[0-9]+$" ${DB(RINGGROUP/${NODEST}/fixedcid)})}" == "1" & "${FROM_DID}" != ""]', 'Set', '__TRUNKCIDOVERRIDE=${DB(RINGGROUP/${NODEST}/fixedcid)}'));
                    $ext->add($contextname, $exten, '', new ext_return(''));
                    $exten = 's-did';
                    $ext->add($contextname, $exten, '', new ext_execif('$["${REGEX("^[\\+]?[0-9]+$" ${FROM_DID})}" = "1"]', 'Set', '__REALCALLERIDNUM=${FROM_DID}'));
                    $ext->add($contextname, $exten, '', new ext_return(''));
                    $exten = 's-forcedid';
                    $ext->add($contextname, $exten, '', new ext_execif('$["${REGEX("^[\\+]?[0-9]+$" ${FROM_DID})}" = "1"]', 'Set', '__TRUNKCIDOVERRIDE=${FROM_DID}'));
                    $ext->add($contextname, $exten, '', new ext_return(''));
                    $exten = '_s-.';
                    $ext->add($contextname, $exten, '', new ext_noop('Unknown value for RINGGROUP/${NODEST}/changecid of ${DB(RINGGROUP/${NODEST}/changecid)} set to "default"'));
                    $ext->add($contextname, $exten, '', new ext_setvar('DB(RINGGROUP/${NODEST}/changecid)', 'default'));
                    $ext->add($contextname, $exten, '', new ext_return(''));
                }
            }
            break;
    }
}
Esempio n. 5
0
function conferences_get_config($engine)
{
    global $ext;
    // is this the best way to pass this?
    global $conferences_conf;
    global $version;
    global $amp_conf;
    switch ($engine) {
        case "asterisk":
            $ext->addInclude('from-internal-additional', 'ext-meetme');
            $contextname = 'ext-meetme';
            if (is_array($conflist = conferences_list())) {
                $ast_ge_14 = version_compare($version, "1.4", "ge");
                // Start the conference
                if ($ast_ge_14) {
                    $ext->add($contextname, 'STARTMEETME', '', new ext_execif('$["${MEETME_MUSIC}" != ""]', 'Set', 'CHANNEL(musicclass)=${MEETME_MUSIC}'));
                } else {
                    $ext->add($contextname, 'STARTMEETME', '', new ext_execif('$["${MEETME_MUSIC}" != ""]', 'SetMusicOnHold', '${MEETME_MUSIC}'));
                }
                $ext->add($contextname, 'STARTMEETME', '', new ext_setvar('GROUP(meetme)', '${MEETME_ROOMNUM}'));
                $ext->add($contextname, 'STARTMEETME', '', new ext_gotoif('$[${MAX_PARTICIPANTS} > 0 && ${GROUP_COUNT(${MEETME_ROOMNUM}@meetme)}>${MAX_PARTICIPANTS}]', 'MEETMEFULL,1'));
                $ext->add($contextname, 'STARTMEETME', '', new ext_meetme('${MEETME_ROOMNUM}', '${MEETME_OPTS}', '${PIN}'));
                $ext->add($contextname, 'STARTMEETME', '', new ext_hangup(''));
                //meetme full
                $ext->add($contextname, 'MEETMEFULL', '', new ext_playback('im-sorry&conf-full&goodbye'));
                $ext->add($contextname, 'MEETMEFULL', '', new ext_hangup(''));
                // hangup for whole context
                $ext->add($contextname, 'h', '', new ext_hangup(''));
                foreach ($conflist as $item) {
                    $room = conferences_get(ltrim($item['0']));
                    $roomnum = ltrim($item['0']);
                    $roomoptions = $room['options'];
                    if ($ast_ge_14) {
                        $roomoptions = str_replace('i', 'I', $roomoptions);
                    }
                    if (!$ast_ge_14) {
                        $roomoptions = str_replace('o', '', $roomoptions);
                        $roomoptions = str_replace('T', '', $roomoptions);
                    }
                    $roomuserpin = $room['userpin'];
                    $roomadminpin = $room['adminpin'];
                    $roomusers = $room['users'];
                    if (isset($room['music']) && $room['music'] != '' && $room['music'] != 'inherit') {
                        $music = $room['music'];
                    } else {
                        $music = '${MOHCLASS}';
                        // inherit channel moh class
                    }
                    if (isset($room['joinmsg_id']) && $room['joinmsg_id'] != '') {
                        $roomjoinmsg = recordings_get_file($room['joinmsg_id']);
                    } else {
                        $roomjoinmsg = '';
                    }
                    // Add optional hint
                    if ($amp_conf['USEDEVSTATE']) {
                        $ext->addHint($contextname, $roomnum, "MeetMe:" . $roomnum);
                    }
                    // entry point
                    $ext->add($contextname, $roomnum, '', new ext_macro('user-callerid'));
                    $ext->add($contextname, $roomnum, '', new ext_setvar('MEETME_ROOMNUM', $roomnum));
                    $ext->add($contextname, $roomnum, '', new ext_setvar('MAX_PARTICIPANTS', $roomusers));
                    $ext->add($contextname, $roomnum, '', new ext_setvar('MEETME_MUSIC', $music));
                    if (strstr($room['options'], 'r') !== false) {
                        $ext->add($contextname, $roomnum, '', new ext_setvar('MEETME_RECORDINGFILE', '${ASTSPOOLDIR}/monitor/meetme-conf-rec-${MEETME_ROOMNUM}-${UNIQUEID}'));
                    }
                    $ext->add($contextname, $roomnum, '', new ext_gotoif('$["${DIALSTATUS}" = "ANSWER"]', $roomuserpin == '' && $roomadminpin == '' ? 'USER' : 'READPIN'));
                    $ext->add($contextname, $roomnum, '', new ext_answer(''));
                    $ext->add($contextname, $roomnum, '', new ext_wait(1));
                    // Deal with PINs -- if exist
                    if ($roomuserpin != '' || $roomadminpin != '') {
                        $ext->add($contextname, $roomnum, '', new ext_setvar('PINCOUNT', '0'));
                        $ext->add($contextname, $roomnum, 'READPIN', new ext_read('PIN', 'enter-conf-pin-number'));
                        // userpin -- must do always, otherwise if there is just an adminpin
                        // there would be no way to get to the conference !
                        $ext->add($contextname, $roomnum, '', new ext_gotoif('$[x${PIN} = x' . $roomuserpin . ']', 'USER'));
                        // admin pin -- exists
                        if ($roomadminpin != '') {
                            $ext->add($contextname, $roomnum, '', new ext_gotoif('$[x${PIN} = x' . $roomadminpin . ']', 'ADMIN'));
                        }
                        // pin invalid
                        $ext->add($contextname, $roomnum, '', new ext_setvar('PINCOUNT', '$[${PINCOUNT}+1]'));
                        $ext->add($contextname, $roomnum, '', new ext_gotoif('$[${PINCOUNT}>3]', "h"));
                        $ext->add($contextname, $roomnum, '', new ext_playback('conf-invalidpin'));
                        $ext->add($contextname, $roomnum, '', new ext_goto('READPIN'));
                        // admin mode -- only valid if there is an admin pin
                        if ($roomadminpin != '') {
                            $ext->add($contextname, $roomnum, 'ADMIN', new ext_setvar('MEETME_OPTS', 'aA' . $roomoptions));
                            if ($roomjoinmsg != '') {
                                // play joining message if one defined
                                $ext->add($contextname, $roomnum, '', new ext_playback($roomjoinmsg));
                            }
                            $ext->add($contextname, $roomnum, '', new ext_goto('STARTMEETME,1'));
                        }
                    }
                    // user mode
                    $ext->add($contextname, $roomnum, 'USER', new ext_setvar('MEETME_OPTS', $roomoptions));
                    if ($roomjoinmsg != '') {
                        // play joining message if one defined
                        $ext->add($contextname, $roomnum, '', new ext_playback($roomjoinmsg));
                    }
                    $ext->add($contextname, $roomnum, '', new ext_goto('STARTMEETME,1'));
                    // add meetme config
                    $conferences_conf->addMeetme($room['exten'], $room['userpin'], $room['adminpin']);
                }
            }
            break;
    }
}
function ivr_get_config($engine)
{
    global $ext;
    switch ($engine) {
        case "asterisk":
            $ddial_contexts = array();
            $ivrlist = ivr_get_details();
            if (!is_array($ivrlist)) {
                break;
            }
            if (function_exists('queues_list')) {
                //draw a list of ivrs included by any queues
                $queues = queues_list(true);
                $qivr = array();
                foreach ($queues as $q) {
                    $thisq = queues_get($q[0]);
                    if ($thisq['context'] && strpos($thisq['context'], 'ivr-') === 0) {
                        $qivr[] = str_replace('ivr-', '', $thisq['context']);
                    }
                }
            }
            foreach ($ivrlist as $ivr) {
                $c = 'ivr-' . $ivr['id'];
                $ivr = ivr_get_details($ivr['id']);
                $ext->addSectionComment($c, $ivr['name'] ? $ivr['name'] : 'IVR ' . $ivr['id']);
                if ($ivr['directdial']) {
                    if ($ivr['directdial'] == 'ext-local') {
                        $ext->addInclude($c, 'from-did-direct-ivr');
                        //generated in core module
                    } else {
                        //generated by directory
                        $ext->addInclude($c, 'from-ivr-directory-' . $ivr['directdial']);
                        $directdial_contexts[$ivr['directdial']] = $ivr['directdial'];
                    }
                }
                //set variables for loops when used
                if ($ivr['timeout_loops'] != 'disabled' && $ivr['timeout_loops'] > 0) {
                    $ext->add($c, 's', '', new ext_setvar('TIMEOUT_LOOPCOUNT', 0));
                }
                if ($ivr['invalid_loops'] != 'disabled' && $ivr['invalid_loops'] > 0) {
                    $ext->add($c, 's', '', new ext_setvar('INVALID_LOOPCOUNT', 0));
                }
                $ext->add($c, 's', '', new ext_setvar('_IVR_CONTEXT_${CONTEXT}', '${IVR_CONTEXT}'));
                $ext->add($c, 's', '', new ext_setvar('_IVR_CONTEXT', '${CONTEXT}'));
                if ($ivr['retvm']) {
                    $ext->add($c, 's', '', new ext_setvar('__IVR_RETVM', 'RETURN'));
                } else {
                    //TODO: do we need to set anything at all?
                    $ext->add($c, 's', '', new ext_setvar('__IVR_RETVM', ''));
                }
                if ($ivr['alertinfo'] != '') {
                    $ext->add($c, 's', '', new ext_setvar('__ALERT_INFO', str_replace(';', '\\;', $ivr['alertinfo'])));
                }
                $ext->add($c, 's', '', new ext_gotoif('$["${CHANNEL(state)}" = "Up"]', 'skip'));
                $ext->add($c, 's', '', new ext_answer(''));
                $ext->add($c, 's', '', new ext_wait('1'));
                $ivr_announcement = recordings_get_file($ivr['announcement']);
                $ext->add($c, 's', 'skip', new ext_set('IVR_MSG', $ivr_announcement));
                $ext->add($c, 's', 'start', new ext_digittimeout(3));
                //$ext->add($ivr_id, 's', '', new ext_responsetimeout($ivr['timeout_time']));
                $ext->add($c, 's', '', new ext_execif('$["${IVR_MSG}" != ""]', 'Background', '${IVR_MSG}'));
                $ext->add($c, 's', '', new ext_waitexten($ivr['timeout_time']));
                // Actually add the IVR entires now
                $entries = ivr_get_entries($ivr['id']);
                if ($entries) {
                    foreach ($entries as $e) {
                        //dont set a t or i if there already defined above
                        if ($e['selection'] == 't' && $ivr['timeout_loops'] != 'disabled') {
                            continue;
                        }
                        if ($e['selection'] == 'i' && $ivr['invalid_loops'] != 'disabled') {
                            continue;
                        }
                        //only display these two lines if the ivr is included in any queues
                        if (function_exists('queues_list') && in_array($ivr['id'], $qivr)) {
                            $ext->add($c, $e['selection'], '', new ext_macro('blkvm-clr'));
                            $ext->add($c, $e['selection'], '', new ext_setvar('__NODEST', ''));
                        }
                        if ($e['ivr_ret']) {
                            $ext->add($c, $e['selection'], '', new ext_gotoif('$["x${IVR_CONTEXT_${CONTEXT}}" = "x"]', $e['dest'] . ':${IVR_CONTEXT_${CONTEXT}},return,1'));
                        } else {
                            $ext->add($c, $e['selection'], 'ivrsel-' . $e['selection'], new ext_goto($e['dest']));
                        }
                    }
                }
                // add invalid destination if required
                if ($ivr['invalid_loops'] != 'disabled') {
                    if ($ivr['invalid_loops'] > 0) {
                        $ext->add($c, 'i', '', new ext_set('INVALID_LOOPCOUNT', '$[${INVALID_LOOPCOUNT}+1]'));
                        $ext->add($c, 'i', '', new ext_gotoif('$[${INVALID_LOOPCOUNT} > ' . $ivr['invalid_loops'] . ']', 'final'));
                        switch ($ivr['invalid_retry_recording']) {
                            case 'default':
                                $invalid_annoucement = 'no-valid-responce-pls-try-again';
                                break;
                            case '':
                                $invalid_annoucement = '';
                                break;
                            default:
                                $invalid_annoucement = recordings_get_file($ivr['invalid_retry_recording']);
                                break;
                        }
                        if ($ivr['invalid_append_announce'] || $invalid_annoucement == '') {
                            $invalid_annoucement .= '&' . $ivr_announcement;
                        }
                        $ext->add($c, 'i', '', new ext_set('IVR_MSG', trim($invalid_annoucement, '&')));
                        $ext->add($c, 'i', '', new ext_goto('s,start'));
                    }
                    $label = 'final';
                    switch ($ivr['invalid_recording']) {
                        case 'default':
                            $ext->add($c, 'i', $label, new ext_playback('no-valid-responce-transfering'));
                            $label = '';
                            break;
                        case '':
                            break;
                        default:
                            $ext->add($c, 'i', $label, new ext_playback(recordings_get_file($ivr['invalid_recording'])));
                            $label = '';
                            break;
                    }
                    if (!empty($ivr['invalid_ivr_ret'])) {
                        $ext->add($c, 'i', $label, new ext_gotoif('$["x${IVR_CONTEXT_${CONTEXT}}" = "x"]', $ivr['invalid_destination'] . ':${IVR_CONTEXT_${CONTEXT}},return,1'));
                    } else {
                        $ext->add($c, 'i', $label, new ext_goto($ivr['invalid_destination']));
                    }
                } else {
                    // If no invalid destination provided we need to do something
                    $ext->add($c, 'i', '', new ext_playback('sorry-youre-having-problems'));
                    $ext->add($c, 'i', '', new ext_goto('1', 'hang'));
                }
                // Apply timeout destination if required
                if ($ivr['timeout_loops'] != 'disabled') {
                    if ($ivr['timeout_loops'] > 0) {
                        $ext->add($c, 't', '', new ext_set('TIMEOUT_LOOPCOUNT', '$[${TIMEOUT_LOOPCOUNT}+1]'));
                        $ext->add($c, 't', '', new ext_gotoif('$[${TIMEOUT_LOOPCOUNT} > ' . $ivr['timeout_loops'] . ']', 'final'));
                        switch ($ivr['timeout_retry_recording']) {
                            case 'default':
                                $timeout_annoucement = 'no-valid-responce-pls-try-again';
                                break;
                            case '':
                                $timeout_annoucement = '';
                                break;
                            default:
                                $timeout_annoucement = recordings_get_file($ivr['timeout_retry_recording']);
                                break;
                        }
                        if ($ivr['timeout_append_announce'] || $timeout_annoucement == '') {
                            $timeout_annoucement .= '&' . $ivr_announcement;
                        }
                        $ext->add($c, 't', '', new ext_set('IVR_MSG', trim($timeout_annoucement, '&')));
                        $ext->add($c, 't', '', new ext_goto('s,start'));
                    }
                    $label = 'final';
                    switch ($ivr['timeout_recording']) {
                        case 'default':
                            $ext->add($c, 't', $label, new ext_playback('no-valid-responce-transfering'));
                            $label = '';
                            break;
                        case '':
                            break;
                        default:
                            $ext->add($c, 't', $label, new ext_playback(recordings_get_file($ivr['timeout_recording'])));
                            $label = '';
                            break;
                    }
                    if (!empty($ivr['timeout_ivr_ret'])) {
                        $ext->add($c, 't', $label, new ext_gotoif('$["x${IVR_CONTEXT_${CONTEXT}}" = "x"]', $ivr['timeout_destination'] . ':${IVR_CONTEXT_${CONTEXT}},return,1'));
                    } else {
                        $ext->add($c, 't', $label, new ext_goto($ivr['timeout_destination']));
                    }
                } else {
                    // If no invalid destination provided we need to do something
                    $ext->add($c, 't', '', new ext_playback('sorry-youre-having-problems'));
                    $ext->add($c, 't', '', new ext_goto('1', 'hang'));
                }
                // these need to be reset or inheritance problems makes them go away in some conditions
                //and infinite inheritance creates other problems
                $ext->add($c, 'return', '', new ext_setvar('_IVR_CONTEXT', '${CONTEXT}'));
                $ext->add($c, 'return', '', new ext_setvar('_IVR_CONTEXT_${CONTEXT}', '${IVR_CONTEXT_${CONTEXT}}'));
                $ext->add($c, 'return', '', new ext_set('IVR_MSG', $ivr_announcement));
                $ext->add($c, 'return', '', new ext_goto('s,start'));
                //h extension
                $ext->add($c, 'h', '', new ext_hangup(''));
                $ext->add($c, 'hang', '', new ext_playback('vm-goodbye'));
                $ext->add($c, 'hang', '', new ext_hangup(''));
            }
            //generate from-ivr-directory contexts for direct dialing a directory entire
            if (!empty($directdial_contexts)) {
                foreach ($directdial_contexts as $dir_id) {
                    $c = 'from-ivr-directory-' . $dir_id;
                    $entries = function_exists('directory_get_dir_entries') ? directory_get_dir_entries($dir_id) : array();
                    foreach ($entries as $dstring) {
                        $exten = $dstring['dial'] == '' ? $dstring['foreign_id'] : $dstring['dial'];
                        if ($exten == '' || $exten == 'custom') {
                            continue;
                        }
                        $ext->add($c, $exten, '', new ext_macro('blkvm-clr'));
                        $ext->add($c, $exten, '', new ext_setvar('__NODEST', ''));
                        $ext->add($c, $exten, '', new ext_goto('1', $exten, 'from-internal'));
                    }
                }
            }
            break;
    }
}
function queues_get($account, $queues_conf_only = false)
{
    global $db, $astman, $amp_conf;
    if ($account == "") {
        return array();
    }
    $account = q($account);
    //get all the variables for the queue
    $sql = "SELECT keyword,data FROM queues_details WHERE id = {$account}";
    $results = $db->getAssoc($sql);
    if (empty($results)) {
        return array();
    }
    //okay, but there can be multiple member variables ... do another select for them
    $results['member'] = queues_get_static_members($account);
    //if 'queue-youarenext=queue-youarenext', then assume we want to announce position
    if (!$queues_conf_only) {
        if (isset($results['queue-youarenext']) && $results['queue-youarenext'] == 'queue-youarenext') {
            $results['announce-position'] = 'yes';
        } else {
            $results['announce-position'] = 'no';
        }
    }
    //if 'eventmemberstatusoff=Yes', then assume we want to 'eventmemberstatus=no'
    if (isset($results['eventmemberstatusoff'])) {
        if (strtolower($results['eventmemberstatusoff']) == 'yes') {
            $results['eventmemberstatus'] = 'no';
        } else {
            $results['eventmemberstatus'] = 'yes';
        }
    } elseif (!isset($results['eventmemberstatus'])) {
        $results['eventmemberstatus'] = 'no';
    }
    if ($queues_conf_only) {
        $sql = "SELECT ivr_id, callback_id FROM queues_config WHERE extension = {$account}";
        $config = sql($sql, "getRow", DB_FETCHMODE_ASSOC);
    } else {
        $sql = "SELECT * FROM queues_config WHERE extension = {$account}";
        $config = sql($sql, "getRow", DB_FETCHMODE_ASSOC);
        $results['prefix'] = $config['grppre'];
        $results['alertinfo'] = $config['alertinfo'];
        $results['agentannounce_id'] = $config['agentannounce_id'];
        $results['maxwait'] = $config['maxwait'];
        $results['name'] = $config['descr'];
        $results['joinannounce_id'] = $config['joinannounce_id'];
        $results['password'] = $config['password'];
        $results['goto'] = $config['dest'];
        $results['announcemenu'] = $config['ivr_id'];
        $results['callback'] = $config['callback_id'];
        $results['rtone'] = $config['ringing'];
        $results['cwignore'] = $config['cwignore'];
        $results['qregex'] = $config['qregex'];
        $results['queuewait'] = $config['queuewait'];
        $results['use_queue_context'] = $config['use_queue_context'];
        $results['togglehint'] = $config['togglehint'];
        $results['qnoanswer'] = $config['qnoanswer'];
        $results['callconfirm'] = $config['callconfirm'];
        $results['callconfirm_id'] = $config['callconfirm_id'];
        $results['monitor_type'] = $config['monitor_type'];
        $results['monitor_heard'] = $config['monitor_heard'];
        $results['monitor_spoken'] = $config['monitor_spoken'];
        // TODO: why the str_replace?
        //
        if ($astman) {
            $account = str_replace("'", '', $account);
            //get dynamic members priority from astDB
            $get = $astman->database_show('QPENALTY/' . $account . '/agents');
            if ($get) {
                foreach ($get as $key => $value) {
                    $key1 = explode('/', $key);
                    $mem[$key1[4]] = $value;
                }
                foreach ($mem as $mem => $pnlty) {
                    $dynmem[] = $mem . ',' . $pnlty;
                }
                $results['dynmembers'] = implode("\n", $dynmem);
            } else {
                $results['dynmembers'] = '';
            }
            $results['dynmemberonly'] = $astman->database_get('QPENALTY/' . $account, 'dynmemberonly');
        } else {
            fatal("Cannot connect to Asterisk Manager with " . $amp_conf["AMPMGRUSER"] . "/" . $amp_conf["AMPMGRPASS"]);
        }
    }
    $results['context'] = '';
    $results['periodic-announce'] = '';
    if ($config['ivr_id'] != 'none' && $config['ivr_id'] != '') {
        if (function_exists('ivr_get_details')) {
            $results['context'] = "ivr-" . $config['ivr_id'];
            $arr = ivr_get_details($config['ivr_id']);
            if (isset($arr['announcement']) && $arr['announcement'] != '') {
                $periodic = recordings_get_file($arr['announcement']);
                // We need to strip off all but the first sound file of any compound sound files
                $periodic_arr = explode("&", $periodic);
                $results['periodic-announce'] = $periodic_arr[0];
            }
        }
    } else {
        if ($config['callback_id'] != 'none' && $config['callback_id'] != '') {
            if (function_exists('vqplus_callback_get')) {
                $results['context'] = "queuecallback-" . $config['callback_id'];
                $arr = vqplus_callback_get($config['callback_id']);
                if (isset($arr[0]) && is_array($arr[0])) {
                    /* Vqplus 13 moved to BMO, which made the return value format different. */
                    $arr = $arr[0];
                }
                if (isset($arr['announcement']) && $arr['announcement'] != '') {
                    $periodic = recordings_get_file($arr['announcement']);
                    // We need to strip off all but the first sound file of any compound sound files
                    $periodic_arr = explode("&", $periodic);
                    $results['periodic-announce'] = $periodic_arr[0];
                }
            }
        }
    }
    return $results;
}
Esempio n. 8
0
function ivr_get_config($engine)
{
    global $ext;
    switch ($engine) {
        case "asterisk":
            $ddial_contexts = array();
            $ivrlist = ivr_list();
            if (is_array($ivrlist)) {
                foreach ($ivrlist as $item) {
                    $id = "ivr-" . $item['ivr_id'];
                    $details = ivr_get_details($item['ivr_id']);
                    $announcement_id = isset($details['announcement_id']) ? $details['announcement_id'] : '';
                    $timeout_id = isset($details['timeout_id']) ? $details['timeout_id'] : '';
                    $invalid_id = isset($details['invalid_id']) ? $details['invalid_id'] : '';
                    $loops = isset($details['loops']) ? $details['loops'] : '2';
                    $retvm = isset($details['retvm']) ? $details['retvm'] : '';
                    if (!empty($details['enable_directdial'])) {
                        if ($details['enable_directdial'] == 'CHECKED') {
                            $ext->addInclude($id, 'from-did-direct-ivr');
                            //generated in core module
                        } else {
                            $ext->addInclude($id, 'from-ivr-directory-' . $details['enable_directdial']);
                            $ddial_contexts[$details['enable_directdial']] = true;
                        }
                    }
                    // I'm not sure I like the ability of people to send voicemail from the IVR.
                    // Make it a config option, possibly?
                    // $ext->addInclude($item[0],'app-messagecenter');
                    if (!empty($details['enable_directory'])) {
                        $ext->addInclude($id, 'app-directory');
                        $dir = featurecodes_getFeatureCode('infoservices', 'directory');
                        $ext->add($id, '#', '', new ext_dbdel('${BLKVM_OVERRIDE}'));
                        $ext->add($id, '#', '', new ext_setvar('__NODEST', ''));
                        $ext->add($id, '#', '', new ext_goto("app-directory,{$dir},1"));
                    }
                    $ext->add($id, 'h', '', new ext_hangup(''));
                    if ($announcement_id) {
                        $announcement_msg = recordings_get_file($announcement_id);
                        $ext->add($id, 's', '', new ext_setvar('MSG', "{$announcement_msg}"));
                    } else {
                        $ext->add($id, 's', '', new ext_setvar('MSG', ""));
                    }
                    $ext->add($id, 's', '', new ext_setvar('LOOPCOUNT', 0));
                    $ext->add($id, 's', '', new ext_setvar('__DIR-CONTEXT', $details['dircontext']));
                    $ext->add($id, 's', '', new ext_setvar('_IVR_CONTEXT_${CONTEXT}', '${IVR_CONTEXT}'));
                    $ext->add($id, 's', '', new ext_setvar('_IVR_CONTEXT', '${CONTEXT}'));
                    $ext->add($id, 's', '', new ext_gotoif('$["${CDR(disposition)}" = "ANSWERED"]', 'begin'));
                    $ext->add($id, 's', '', new ext_answer(''));
                    $ext->add($id, 's', '', new ext_wait('1'));
                    $ext->add($id, 's', 'begin', new ext_digittimeout(3));
                    $ext->add($id, 's', '', new ext_responsetimeout($details['timeout']));
                    if ($retvm) {
                        $ext->add($id, 's', '', new ext_setvar('__IVR_RETVM', 'RETURN'));
                    } else {
                        $ext->add($id, 's', '', new ext_setvar('__IVR_RETVM', ''));
                    }
                    $ext->add($id, 's', '', new ext_execif('$["${MSG}" != ""]', 'Background', '${MSG}'));
                    $ext->add($id, 's', '', new ext_waitexten());
                    $ext->add($id, 'hang', '', new ext_playback('vm-goodbye'));
                    $ext->add($id, 'hang', '', new ext_hangup(''));
                    $default_t = true;
                    // Actually add the IVR commands now.
                    $dests = ivr_get_dests($item['ivr_id']);
                    $timeout = false;
                    $invalid = false;
                    $addloop = false;
                    if (!empty($dests)) {
                        foreach ($dests as $dest) {
                            if ($dest['selection'] == 't' && empty($details['alt_timeout'])) {
                                $timeout = true;
                            } elseif ($dest['selection'] == 'i' && empty($details['alt_invalid'])) {
                                $invalid = true;
                            } elseif ($dest['selection'] == 't' && !empty($details['alt_timeout'])) {
                                $timeout = true;
                                if ($timeout_id) {
                                    $timeout_msg = recordings_get_file($timeout_id);
                                    $ext->add($id, $dest['selection'], '', new ext_setvar('MSG', "{$timeout_msg}"));
                                }
                                $ext->add($id, $dest['selection'], '', new ext_setvar('LOOPCOUNT', '$[${LOOPCOUNT} + 1]'));
                                $ext->add($id, $dest['selection'], '', new ext_gotoif('$[${LOOPCOUNT} <= ' . $loops . ']', 's,begin'));
                            } elseif ($dest['selection'] == 'i' && !empty($details['alt_invalid'])) {
                                $invalid = true;
                                $ext->add($id, $dest['selection'], '', new ext_setvar('LOOPCOUNT', '$[${LOOPCOUNT} + 1]'));
                                if ($invalid_id) {
                                    $invalid_msg = recordings_get_file($invalid_id);
                                    $ext->add($id, $dest['selection'], '', new ext_setvar('MSG', "{$invalid_msg}"));
                                } else {
                                    $ext->add($id, $dest['selection'], '', new ext_execif('$[${LOOPCOUNT} <= ' . $loops . ']', 'Playback', 'invalid'));
                                }
                                $ext->add($id, $dest['selection'], '', new ext_gotoif('$[${LOOPCOUNT} <= ' . $loops . ']', 's,begin'));
                            }
                            $ext->add($id, $dest['selection'], '', new ext_dbdel('${BLKVM_OVERRIDE}'));
                            $ext->add($id, $dest['selection'], '', new ext_setvar('__NODEST', ''));
                            // if the goto goes loops back to this ivr, then don't go to the begining or it will break the return to previous ivr info
                            //
                            $dest_context = trim(strtok($dest['dest'], ",|"));
                            if ($dest_context == $id) {
                                $dest['dest'] = $id . ',s,begin';
                            }
                            if ($dest['ivr_ret']) {
                                $ext->add($id, $dest['selection'], '', new ext_gotoif('$["x${IVR_CONTEXT_${CONTEXT}}" = "x"]', $dest['dest'] . ':${IVR_CONTEXT_${CONTEXT}},return,1'));
                            } else {
                                $ext->add($id, $dest['selection'], '', new ext_goto($dest['dest']));
                            }
                        }
                    }
                    // Apply invalid if required
                    if (!$invalid) {
                        if ($invalid_id) {
                            $invalid_msg = recordings_get_file($invalid_id);
                            $ext->add($id, 'i', '', new ext_setvar('MSG', "{$invalid_msg}"));
                        } else {
                            $ext->add($id, 'i', '', new ext_playback('invalid'));
                        }
                        $ext->add($id, 'i', '', new ext_goto('loop,1'));
                        $addloop = true;
                    }
                    if (!$timeout) {
                        if ($timeout_id) {
                            $timeout_msg = recordings_get_file($timeout_id);
                            $ext->add($id, 't', '', new ext_setvar('MSG', "{$timeout_msg}"));
                        }
                        $ext->add($id, 't', '', new ext_goto('loop,1'));
                        $addloop = true;
                    }
                    if ($addloop) {
                        $ext->add($id, 'loop', '', new ext_setvar('LOOPCOUNT', '$[${LOOPCOUNT} + 1]'));
                        $ext->add($id, 'loop', '', new ext_gotoif('$[${LOOPCOUNT} > ' . $loops . ']', 'hang,1'));
                        $ext->add($id, 'loop', '', new ext_goto($id . ',s,begin'));
                        // these need to be reset or inheritance problems makes them go away in some conditions and infinite inheritance creates other problems
                        // reset the message including blanking it if set by a sub-ivr
                        $announcement_msg = $announcement_id ? $announcement_msg : '';
                        $ext->add($id, 'return', '', new ext_setvar('MSG', "{$announcement_msg}"));
                        $ext->add($id, 'return', '', new ext_setvar('_IVR_CONTEXT', '${CONTEXT}'));
                        $ext->add($id, 'return', '', new ext_setvar('_IVR_CONTEXT_${CONTEXT}', '${IVR_CONTEXT_${CONTEXT}}'));
                        $ext->add($id, 'return', '', new ext_goto($id . ',s,begin'));
                    }
                }
                if (!empty($ddial_contexts)) {
                    global $version;
                    $ast_lt_14 = version_compare($version, '1.4', 'lt');
                    foreach (array_keys($ddial_contexts) as $dir_id) {
                        $context = 'from-ivr-directory-' . $dir_id;
                        $entries = function_exists('directory_get_dir_entries') ? directory_get_dir_entries($dir_id) : array();
                        foreach ($entries as $dstring) {
                            $exten = $dstring['dial'] == '' ? $dstring['foreign_id'] : $dstring['dial'];
                            if ($exten == '' || $exten == 'custom') {
                                continue;
                            }
                            if ($ast_lt_14) {
                                $ext->add($context, $exten, '', new ext_execif('$["${BLKVM_OVERRIDE}" != ""]', 'dbDel', '${BLKVM_OVERRIDE}'));
                            } else {
                                $ext->add($context, $exten, '', new ext_execif('$["${BLKVM_OVERRIDE}" != ""]', 'Noop', 'Deleting: ${BLKVM_OVERRIDE}: ${DB_DELETE(${BLKVM_OVERRIDE})}'));
                            }
                            $ext->add($context, $exten, '', new ext_setvar('__NODEST', ''));
                            $ext->add($context, $exten, '', new ext_goto('1', $exten, 'from-internal'));
                        }
                    }
                }
            }
            break;
    }
}
Esempio n. 9
0
function findmefollow_get_config($engine)
{
    global $ext;
    // is this the best way to pass this?
    global $amp_conf;
    switch ($engine) {
        case "asterisk":
            if ($amp_conf['USEDEVSTATE']) {
                $ext->addGlobal('FMDEVSTATE', 'TRUE');
            }
            $fcc = new featurecode('findmefollow', 'fmf_toggle');
            $fmf_code = $fcc->getCodeActive();
            unset($fcc);
            if ($fmf_code != '') {
                findmefollow_fmf_toggle($fmf_code);
            }
            $ext->addInclude('from-internal-additional', 'ext-findmefollow');
            $ext->addInclude('from-internal-additional', 'fmgrps');
            $contextname = 'ext-findmefollow';
            // Before creating all the contexts, let's make a list of hints if needed
            //
            if ($amp_conf['USEDEVSTATE'] && $fmf_code != '') {
                $device_list = core_devices_list("all", 'full', true);
                foreach ($device_list as $device) {
                    if ($device['tech'] == 'sip' || $device['tech'] == 'iax2') {
                        $ext->add($contextname, $fmf_code . $device['id'], '', new ext_goto("1", $fmf_code, "app-fmf-toggle"));
                        $ext->addHint($contextname, $fmf_code . $device['id'], "Custom:FOLLOWME" . $device['id']);
                    }
                }
            }
            $ringlist = findmefollow_full_list();
            if (is_array($ringlist)) {
                foreach ($ringlist as $item) {
                    $grpnum = ltrim($item['0']);
                    $grp = findmefollow_get($grpnum);
                    $strategy = $grp['strategy'];
                    $grptime = $grp['grptime'];
                    $grplist = $grp['grplist'];
                    $postdest = $grp['postdest'];
                    $grppre = isset($grp['grppre']) ? $grp['grppre'] : '';
                    $annmsg_id = $grp['annmsg_id'];
                    $dring = $grp['dring'];
                    $needsconf = $grp['needsconf'];
                    $remotealert_id = $grp['remotealert_id'];
                    $toolate_id = $grp['toolate_id'];
                    $ringing = $grp['ringing'];
                    $pre_ring = $grp['pre_ring'];
                    if ($ringing == 'Ring' || empty($ringing)) {
                        $dialopts = '${DIAL_OPTIONS}';
                    } else {
                        // We need the DIAL_OPTIONS variable
                        $sops = sql("SELECT value from globals where variable='DIAL_OPTIONS'", "getRow");
                        $dialopts = "m({$ringing})" . str_replace('r', '', $sops[0]);
                    }
                    // Direct target to Follow-Me come here bypassing the followme/ddial conditional check
                    //
                    $ext->add($contextname, 'FM' . $grpnum, '', new ext_goto("FM{$grpnum}", "{$grpnum}"));
                    //
                    // If the followme is configured for extension dialing to go to the the extension and not followme then
                    // go there. This is often used in VmX Locater functionality when the user does not want the followme
                    // to automatically be called but only if chosen by the caller as an alternative to going to voicemail
                    //
                    $ext->add($contextname, $grpnum, '', new ext_gotoif('$[ "${DB(AMPUSER/' . $grpnum . '/followme/ddial)}" = "EXTENSION" ]', 'ext-local,' . $grpnum . ',1'));
                    $ext->add($contextname, $grpnum, 'FM' . $grpnum, new ext_macro('user-callerid'));
                    $ext->add($contextname, $grpnum, '', new ext_set('__EXTTOCALL', '${EXTEN}'));
                    // block voicemail until phone is answered at which point a macro should be called on the answering
                    // line to clear this flag so that subsequent transfers can occur, if already set by a the caller
                    // then don't change.
                    //
                    $ext->add($contextname, $grpnum, '', new ext_gotoif('$["foo${BLKVM_OVERRIDE}" = "foo"]', 'skipdb'));
                    $ext->add($contextname, $grpnum, '', new ext_gotoif('$["${DB(${BLKVM_OVERRIDE})}" = "TRUE"]', 'skipov'));
                    $ext->add($contextname, $grpnum, 'skipdb', new ext_setvar('__NODEST', ''));
                    $ext->add($contextname, $grpnum, '', new ext_setvar('__BLKVM_OVERRIDE', 'BLKVM/${EXTEN}/${CHANNEL}'));
                    $ext->add($contextname, $grpnum, '', new ext_setvar('__BLKVM_BASE', '${EXTEN}'));
                    $ext->add($contextname, $grpnum, '', new ext_setvar('DB(${BLKVM_OVERRIDE})', 'TRUE'));
                    // Remember if NODEST was set later, but clear it in case the call is answered so that subsequent
                    // transfers work.
                    //
                    $ext->add($contextname, $grpnum, 'skipov', new ext_setvar('RRNODEST', '${NODEST}'));
                    $ext->add($contextname, $grpnum, 'skipvmblk', new ext_setvar('__NODEST', '${EXTEN}'));
                    $ext->add($contextname, $grpnum, '', new ext_gosubif('$[${DB_EXISTS(AMPUSER/' . $grpnum . '/followme/changecid)} = 1 & "${DB(AMPUSER/' . $grpnum . '/followme/changecid)}" != "default" & "${DB(AMPUSER/' . $grpnum . '/followme/changecid)}" != ""]', 'sub-fmsetcid,s,1'));
                    // deal with group CID prefix
                    // but strip only if you plan on setting a new one
                    if ($grppre != '') {
                        $ext->add($contextname, $grpnum, '', new ext_gotoif('$["foo${RGPREFIX}" = "foo"]', 'REPCID'));
                        $ext->add($contextname, $grpnum, '', new ext_gotoif('$["${RGPREFIX}" != "${CALLERID(name):0:${LEN(${RGPREFIX})}}"]', 'REPCID'));
                        $ext->add($contextname, $grpnum, '', new ext_noop('Current RGPREFIX is ${RGPREFIX}....stripping from Caller ID'));
                        $ext->add($contextname, $grpnum, '', new ext_setvar('CALLERID(name)', '${CALLERID(name):${LEN(${RGPREFIX})}}'));
                        $ext->add($contextname, $grpnum, '', new ext_setvar('_RGPREFIX', ''));
                        $ext->add($contextname, $grpnum, 'REPCID', new ext_noop('CALLERID(name) is ${CALLERID(name)}'));
                        $ext->add($contextname, $grpnum, '', new ext_setvar('_RGPREFIX', $grppre));
                        $ext->add($contextname, $grpnum, '', new ext_setvar('CALLERID(name)', '${RGPREFIX}${CALLERID(name)}'));
                    }
                    // recording stuff
                    $ext->add($contextname, $grpnum, '', new ext_setvar('RecordMethod', 'Group'));
                    // append the followme's extension to the grouplist. This may be redundant but will ensure recording if the extension itself is not part of
                    // the list
                    $ext->add($contextname, $grpnum, '', new ext_macro('record-enable', '${DB(AMPUSER/' . "{$grpnum}/followme/grplist)}-{$grpnum}" . ',${RecordMethod}'));
                    // MODIFIED (PL)
                    // Add Alert Info if set but don't override and already set value (could be from ringgroup, directdid, etc.)
                    //
                    if ((isset($dring) ? $dring : '') != '') {
                        // If ALERTINFO is set, then skip to the next set command. This was modified to two lines because the previous
                        // IF() couldn't handle ':' as part of the string. The jump to PRIORITY+2 allows for now destination label
                        // which is needed in the 2.3 version.
                        $ext->add($contextname, $grpnum, '', new ext_gotoif('$["x${ALERT_INFO}"!="x"]', '$[${PRIORITY}+2])}'));
                        $ext->add($contextname, $grpnum, '', new ext_setvar("__ALERT_INFO", str_replace(';', '\\;', $dring)));
                    }
                    // If pre_ring is set, then ring this number of seconds prior to moving on
                    if ((isset($strategy) ? substr($strategy, 0, strlen('ringallv2')) : '') != 'ringallv2') {
                        $ext->add($contextname, $grpnum, '', new ext_gotoif('$[$[ "${DB(AMPUSER/' . $grpnum . '/followme/prering)}" = "0" ] | $[ "${DB(AMPUSER/' . $grpnum . '/followme/prering)}" = "" ]] ', 'skipsimple'));
                        $ext->add($contextname, $grpnum, '', new ext_macro('simple-dial', $grpnum . ',${DB(AMPUSER/' . "{$grpnum}/followme/prering)}"));
                    }
                    // group dial
                    $ext->add($contextname, $grpnum, 'skipsimple', new ext_setvar('RingGroupMethod', $strategy));
                    $ext->add($contextname, $grpnum, '', new ext_setvar('_FMGRP', $grpnum));
                    if (isset($annmsg_id) ? $annmsg_id : '') {
                        $annmsg = recordings_get_file($annmsg_id);
                        // should always answer before playing anything, shouldn't we ?
                        $ext->add($contextname, $grpnum, '', new ext_gotoif('$[$["${DIALSTATUS}" = "ANSWER"] | $["foo${RRNODEST}" != "foo"]]', 'DIALGRP'));
                        $ext->add($contextname, $grpnum, '', new ext_answer(''));
                        $ext->add($contextname, $grpnum, '', new ext_wait(1));
                        $ext->add($contextname, $grpnum, '', new ext_playback($annmsg));
                    }
                    // Create the confirm target
                    $len = strlen($grpnum) + 4;
                    $remotealert = recordings_get_file($remotealert_id);
                    $toolate = recordings_get_file($toolate_id);
                    $ext->add("fmgrps", "_RG-{$grpnum}-.", '', new ext_macro('dial', '${DB(AMPUSER/' . "{$grpnum}/followme/grptime)}," . "M(confirm^{$remotealert}^{$toolate}^{$grpnum}){$dialopts}" . ',${EXTEN:' . $len . '}'));
                    // If grpconf == ENABLED call with confirmation ELSE call normal
                    $ext->add($contextname, $grpnum, 'DIALGRP', new ext_gotoif('$[ "${DB(AMPUSER/' . $grpnum . '/followme/grpconf)}" = "ENABLED" ]', 'doconfirm'));
                    // Normal call
                    if ((isset($strategy) ? substr($strategy, 0, strlen('ringallv2')) : '') != 'ringallv2') {
                        $ext->add($contextname, $grpnum, '', new ext_macro('dial', '${DB(AMPUSER/' . "{$grpnum}/followme/grptime)},{$dialopts}," . '${DB(AMPUSER/' . "{$grpnum}/followme/grplist)}"));
                    } else {
                        $ext->add($contextname, $grpnum, '', new ext_macro('dial', '$[ ${DB(AMPUSER/' . $grpnum . '/followme/grptime)} + ${DB(AMPUSER/' . $grpnum . '/followme/prering)} ],' . $dialopts . ',${DB(AMPUSER/' . $grpnum . '/followme/grplist)}'));
                    }
                    $ext->add($contextname, $grpnum, '', new ext_goto('nextstep'));
                    // Call Confirm call
                    if ((isset($strategy) ? substr($strategy, 0, strlen('ringallv2')) : '') != 'ringallv2') {
                        $ext->add($contextname, $grpnum, 'doconfirm', new ext_macro('dial-confirm', '${DB(AMPUSER/' . "{$grpnum}/followme/grptime)},{$dialopts}," . '${DB(AMPUSER/' . "{$grpnum}/followme/grplist)}," . $grpnum));
                    } else {
                        $ext->add($contextname, $grpnum, 'doconfirm', new ext_macro('dial-confirm', '$[ ${DB(AMPUSER/' . $grpnum . '/followme/grptime)} + ${DB(AMPUSER/' . $grpnum . '/followme/prering)} ],' . $dialopts . ',${DB(AMPUSER/' . $grpnum . '/followme/grplist)},' . $grpnum));
                    }
                    $ext->add($contextname, $grpnum, 'nextstep', new ext_setvar('RingGroupMethod', ''));
                    // Did the call come from a queue or ringgroup, if so, don't go to the destination, just end and let
                    // the queue or ringgroup decide what to do next
                    //
                    $ext->add($contextname, $grpnum, '', new ext_gotoif('$["foo${RRNODEST}" != "foo"]', 'nodest'));
                    $ext->add($contextname, $grpnum, '', new ext_setvar('__NODEST', ''));
                    $ext->add($contextname, $grpnum, '', new ext_dbdel('${BLKVM_OVERRIDE}'));
                    // where next?
                    if ((isset($postdest) ? $postdest : '') != '') {
                        $ext->add($contextname, $grpnum, '', new ext_goto($postdest));
                    } else {
                        $ext->add($contextname, $grpnum, '', new ext_hangup(''));
                    }
                    $ext->add($contextname, $grpnum, 'nodest', new ext_noop('SKIPPING DEST, CALL CAME FROM Q/RG: ${RRNODEST}'));
                }
                /*
                  ASTDB Settings:
                  AMPUSER/nnn/followme/changecid default | did | fixed | extern
                  AMPUSER/nnn/followme/fixedcid XXXXXXXX
                
                  changecid:
                    default   - works as always, same as if not present
                    fixed     - set to the fixedcid
                    extern    - set to the fixedcid if the call is from the outside only
                    did       - set to the DID that the call came in on or leave alone, treated as foreign
                    forcedid  - set to the DID that the call came in on or leave alone, not treated as foreign
                  
                  EXTTOCALL   - has the exten num called, hoaky if that goes away but for now use it
                */
                if (count($ringlist)) {
                    $contextname = 'sub-fmsetcid';
                    $exten = 's';
                    $ext->add($contextname, $exten, '', new ext_goto('1', 's-${DB(AMPUSER/${EXTTOCALL}/followme/changecid)}'));
                    $exten = 's-fixed';
                    $ext->add($contextname, $exten, '', new ext_execif('$["${REGEX("^[\\+]?[0-9]+$" ${DB(AMPUSER/${EXTTOCALL}/followme/fixedcid)})}" = "1"]', 'Set', '__TRUNKCIDOVERRIDE=${DB(AMPUSER/${EXTTOCALL}/followme/fixedcid)}'));
                    $ext->add($contextname, $exten, '', new ext_return(''));
                    $exten = 's-extern';
                    $ext->add($contextname, $exten, '', new ext_execif('$["${REGEX("^[\\+]?[0-9]+$" ${DB(AMPUSER/${EXTTOCALL}/followme/fixedcid)})}" == "1" & "${FROM_DID}" != ""]', 'Set', '__TRUNKCIDOVERRIDE=${DB(AMPUSER/${EXTTOCALL}/followme/fixedcid)}'));
                    $ext->add($contextname, $exten, '', new ext_return(''));
                    $exten = 's-did';
                    $ext->add($contextname, $exten, '', new ext_execif('$["${REGEX("^[\\+]?[0-9]+$" ${FROM_DID})}" = "1"]', 'Set', '__REALCALLERIDNUM=${FROM_DID}'));
                    $ext->add($contextname, $exten, '', new ext_return(''));
                    $exten = 's-forcedid';
                    $ext->add($contextname, $exten, '', new ext_execif('$["${REGEX("^[\\+]?[0-9]+$" ${FROM_DID})}" = "1"]', 'Set', '__TRUNKCIDOVERRIDE=${FROM_DID}'));
                    $ext->add($contextname, $exten, '', new ext_return(''));
                    $exten = '_s-.';
                    $ext->add($contextname, $exten, '', new ext_noop('Unknown value for AMPUSER/${EXTTOCALL}/followme/changecid of ${DB(AMPUSER/${EXTTOCALL}/followme/changecid)} set to "default"'));
                    $ext->add($contextname, $exten, '', new ext_setvar('DB(AMPUSER/${EXTTOCALL}/followme/changecid)', 'default'));
                    $ext->add($contextname, $exten, '', new ext_return(''));
                }
            }
            break;
    }
}
Esempio n. 10
0
">
			<?php 
        // setting this will set the context= option
        $default = isset($announcemenu) ? $announcemenu : "none";
        echo '<option value=none ' . ($default == "none" ? 'SELECTED' : '') . '>' . _("None") . '</option>';
        //query for exisiting aa_N contexts
        //
        // If a previous bogus IVR was listed, we will leave it in with an error but will no longer show such IVRs as valid options.
        $unique_aas = ivr_list();
        $compound_recordings = false;
        $is_error = false;
        if (isset($unique_aas)) {
            foreach ($unique_aas as $unique_aa) {
                $menu_id = $unique_aa['ivr_id'];
                $menu_name = $unique_aa['displayname'];
                $unique_aa['announcement'] = recordings_get_file($unique_aa['announcement_id']);
                if (strpos($unique_aa['announcement'], "&") === false) {
                    echo '<option value="' . $menu_id . '" ' . ($default == $menu_id ? 'SELECTED' : '') . '>' . ($menu_name ? $menu_name : _("Menu ID ") . $menu_id) . "</option>\n";
                } else {
                    $compound_recordings = true;
                    if ($menu_id == $default) {
                        echo '<option style="color:red" value="' . $menu_id . '" ' . ($default == $menu_id ? 'SELECTED' : '') . '>' . ($menu_name ? $menu_name : _("Menu ID ") . $menu_id) . " (**)</option>\n";
                        $is_error = true;
                    }
                }
            }
        }
        ?>
			</select>
			<?php 
        if ($is_error) {
Esempio n. 11
0
function core_get_config($engine)
{
    global $ext;
    // is this the best way to pass this?
    global $version;
    // this is not the best way to pass this, this should be passetd together with $engine
    global $engineinfo;
    global $amp_conf;
    global $core_conf;
    global $chan_dahdi;
    global $chan_dahdi_loaded;
    global $astman;
    $modulename = "core";
    switch ($engine) {
        case "asterisk":
            $ast_ge_14 = version_compare($version, '1.4', 'ge');
            $ast_lt_16 = version_compare($version, '1.6', 'lt');
            $ast_lt_161 = version_compare($version, '1.6.1', 'lt');
            // Now add to sip_general_addtional.conf
            //
            if (isset($core_conf) && is_a($core_conf, "core_conf")) {
                $core_conf->addSipGeneral('disallow', 'all');
                $core_conf->addSipGeneral('allow', 'ulaw');
                $core_conf->addSipGeneral('allow', 'alaw');
                $core_conf->addSipGeneral('context', 'from-sip-external');
                $core_conf->addSipGeneral('callerid', 'Unknown');
                $core_conf->addSipGeneral('notifyringing', 'yes');
                if ($ast_ge_14) {
                    $core_conf->addSipGeneral('notifyhold', 'yes');
                    $core_conf->addSipGeneral('tos_sip', 'cs3');
                    // Recommended setting from doc/ip-tos.txt
                    $core_conf->addSipGeneral('tos_audio', 'ef');
                    // Recommended setting from doc/ip-tos.txt
                    $core_conf->addSipGeneral('tos_video', 'af41');
                    // Recommended setting from doc/ip-tos.txt
                    $core_conf->addSipGeneral('alwaysauthreject', 'yes');
                    if ($ast_lt_161) {
                        $core_conf->addSipGeneral('limitonpeers', 'yes');
                    }
                } else {
                    $core_conf->addSipGeneral('tos', '0x68');
                    // This really doesn't do anything with astersk not running as root
                }
                $useragent = "FPBX-" . getversion() . "({$version})";
                $core_conf->addSipGeneral('useragent', $useragent);
                $core_conf->addIaxGeneral('disallow', 'all');
                $core_conf->addIaxGeneral('allow', 'ulaw');
                $core_conf->addIaxGeneral('allow', 'alaw');
                $core_conf->addIaxGeneral('allow', 'gsm');
                $core_conf->addIaxGeneral('mailboxdetail', 'yes');
                if ($ast_ge_14) {
                    $core_conf->addIaxGeneral('tos', 'ef');
                    // Recommended setting from doc/ip-tos.txt
                }
                $fcc = new featurecode($modulename, 'blindxfer');
                $code = $fcc->getCodeActive();
                unset($fcc);
                if ($code != '') {
                    $core_conf->addFeatureMap('blindxfer', $code);
                }
                $fcc = new featurecode($modulename, 'atxfer');
                $code = $fcc->getCodeActive();
                unset($fcc);
                if ($code != '') {
                    $core_conf->addFeatureMap('atxfer', $code);
                }
                $fcc = new featurecode($modulename, 'automon');
                $code = $fcc->getCodeActive();
                unset($fcc);
                if ($code != '') {
                    $core_conf->addFeatureMap('automon', $code);
                }
                $fcc = new featurecode($modulename, 'disconnect');
                $code = $fcc->getCodeActive();
                unset($fcc);
                if ($code != '') {
                    $core_conf->addFeatureMap('disconnect', $code);
                }
                $fcc = new featurecode($modulename, 'pickupexten');
                $code = $fcc->getCodeActive();
                unset($fcc);
                if ($code != '') {
                    $core_conf->addFeatureGeneral('pickupexten', $code);
                }
            }
            // FeatureCodes
            $fcc = new featurecode($modulename, 'userlogon');
            $fc_userlogon = $fcc->getCodeActive();
            unset($fcc);
            $fcc = new featurecode($modulename, 'userlogoff');
            $fc_userlogoff = $fcc->getCodeActive();
            unset($fcc);
            $fcc = new featurecode($modulename, 'zapbarge');
            $fc_zapbarge = $fcc->getCodeActive();
            unset($fcc);
            $fcc = new featurecode($modulename, 'chanspy');
            $fc_chanspy = $fcc->getCodeActive();
            unset($fcc);
            $fcc = new featurecode($modulename, 'simu_pstn');
            $fc_simu_pstn = $fcc->getCodeActive();
            unset($fcc);
            $fcc = new featurecode($modulename, 'pickup');
            $fc_pickup = $fcc->getCodeActive();
            unset($fcc);
            // Log on / off -- all in one context
            if ($fc_userlogoff != '' || $fc_userlogon != '') {
                $ext->addInclude('from-internal-additional', 'app-userlogonoff');
                // Add the include from from-internal
                if ($fc_userlogoff != '') {
                    $ext->add('app-userlogonoff', $fc_userlogoff, '', new ext_macro('user-logoff'));
                    $ext->add('app-userlogonoff', $fc_userlogoff, 'hook_off', new ext_hangup(''));
                }
                if ($fc_userlogon != '') {
                    $ext->add('app-userlogonoff', $fc_userlogon, '', new ext_macro('user-logon'));
                    $ext->add('app-userlogonoff', $fc_userlogon, 'hook_on_1', new ext_hangup(''));
                    $clen = strlen($fc_userlogon);
                    $fc_userlogon = "_{$fc_userlogon}.";
                    $ext->add('app-userlogonoff', $fc_userlogon, '', new ext_macro('user-logon,${EXTEN:' . $clen . '}'));
                    $ext->add('app-userlogonoff', $fc_userlogon, 'hook_on_2', new ext_hangup(''));
                }
            }
            // Call pickup using app_pickup - Note that '**xtn' is hard-coded into the GXPs and SNOMs as a number to dial
            // when a user pushes a flashing BLF.
            //
            // We need to add ringgoups to this so that if an extension is part of a ringgroup, we can try to pickup that
            // extension by trying the ringgoup which is what the pickup application is going to respond to.
            //
            // NOTICE: this may be confusing, we check if this is a BRI build of Asterisk and use dpickup instead of pickup
            //         if it is. So we simply assign the varaible $ext_pickup which one it is, and use that variable when
            //         creating all the extnesions below. So those are "$ext_pickup" on purpose!
            //
            if ($fc_pickup != '' && $ast_ge_14) {
                $ext->addInclude('from-internal-additional', 'app-pickup');
                $fclen = strlen($fc_pickup);
                $ext_pickup = strstr($engineinfo['raw'], 'BRI') ? 'ext_dpickup' : 'ext_pickup';
                $fcc = new featurecode('paging', 'intercom-prefix');
                $intercom_code = $fcc->getCodeActive();
                unset($fcc);
                $picklist = '${EXTEN:' . $fclen . '}';
                $picklist .= '&${EXTEN:' . $fclen . '}@ext-local';
                $picklist .= '&${EXTEN:' . $fclen . '}@from-internal';
                $picklist .= '&${EXTEN:' . $fclen . '}@from-internal-xfer';
                $picklist .= '&${EXTEN:' . $fclen . '}@from-did-direct';
                $picklist .= '&LC-${EXTEN:' . $fclen . '}@from-internal';
                $picklist .= '&LC-${EXTEN:' . $fclen . '}@from-internal-xfer';
                $picklist .= '&FMPR-${EXTEN:' . $fclen . '}@from-internal';
                $picklist .= '&FMPR-${EXTEN:' . $fclen . '}@from-internal-xfer';
                $picklist .= '&FMPR-${EXTEN:' . $fclen . '}@from-did-direct';
                $ext->add('app-pickup', "_{$fc_pickup}.", '', new $ext_pickup($picklist));
                $ext->add('app-pickup', "_{$fc_pickup}.", '', new ext_hangup(''));
                if ($intercom_code != '') {
                    $len = strlen($fc_pickup . $intercom_code);
                    $picklist = '${EXTEN:' . $len . '}';
                    $picklist .= '&${EXTEN:' . $len . '}@ext-local';
                    $picklist .= '&${EXTEN:' . $len . '}@from-internal';
                    $picklist .= '&${EXTEN:' . $len . '}@from-internal-xfer';
                    $picklist .= '&${EXTEN:' . $len . '}@from-did-direct';
                    $picklist .= '&LC-${EXTEN:' . $len . '}@from-internal';
                    $picklist .= '&LC-${EXTEN:' . $len . '}@from-internal-xfer';
                    $picklist .= '&FMPR-${EXTEN:' . $len . '}@from-internal';
                    $picklist .= '&FMPR-${EXTEN:' . $len . '}@from-internal-xfer';
                    $picklist .= '&FMPR-${EXTEN:' . $len . '}@from-did-direct';
                    $ext->add('app-pickup', "_{$fc_pickup}{$intercom_code}.", '', new $ext_pickup($picklist));
                    $ext->add('app-pickup', "_{$fc_pickup}{$intercom_code}.", '', new ext_hangup(''));
                }
                // In order to do call pickup in ringgroups, we will need to try the ringgoup number
                // when doing call pickup for that ringgoup so we must see who is a member of what ringgroup
                // and then generate the dialplan
                //
                $rg_members = array();
                if (function_exists('ringgroups_list')) {
                    $rg_list = ringgroups_list(true);
                    foreach ($rg_list as $item) {
                        $thisgrp = ringgroups_get($item['grpnum']);
                        $grpliststr = $thisgrp['grplist'];
                        $grplist = explode("-", $grpliststr);
                        foreach ($grplist as $exten) {
                            if (strpos($exten, "#") === false) {
                                $rg_members[$exten][] = $item['grpnum'];
                            }
                        }
                    }
                }
                // Now we have a hash of extensions and what ringgoups they are members of
                // so we need to generate the callpickup dialplan for these specific extensions
                // to try the ringgoup.
                foreach ($rg_members as $exten => $grps) {
                    $picklist = $exten;
                    $picklist .= '&' . $exten . '@ext-local';
                    $picklist .= '&' . $exten . '@from-internal';
                    $picklist .= '&' . $exten . '@from-internal-xfer';
                    $picklist .= '&' . $exten . '@from-did-direct';
                    $picklist .= '&LC-' . $exten . '@from-internal';
                    $picklist .= '&LC-' . $exten . '@from-internal-xfer';
                    $picklist .= '&FMPR-' . $exten . '@from-internal';
                    $picklist .= '&FMPR-' . $exten . '@from-internal-xfer';
                    $picklist .= '&FMPR-' . $exten . '@from-did-direct';
                    foreach ($grps as $grp) {
                        $picklist .= '&' . $grp . '@from-internal';
                        $picklist .= '&' . $grp . '@from-internal-xfer';
                        $picklist .= '&' . $grp . '@ext-group';
                    }
                    $ext->add('app-pickup', "{$fc_pickup}" . $exten, '', new $ext_pickup($picklist));
                    $ext->add('app-pickup', "{$fc_pickup}" . $exten, '', new ext_hangup(''));
                    if ($intercom_code != '') {
                        $ext->add('app-pickup', "{$fc_pickup}" . $intercom_code . $exten, '', new $ext_pickup($picklist));
                        $ext->add('app-pickup', "{$fc_pickup}" . $intercom_code . $exten, '', new ext_hangup(''));
                    }
                }
            } elseif ($fc_pickup != '') {
                $ext->addInclude('from-internal-additional', 'app-pickup');
                $fclen = strlen($fc_pickup);
                $ext_pickup = strstr($engineinfo['raw'], 'BRI') ? 'ext_dpickup' : 'ext_pickup';
                $fcc = new featurecode('paging', 'intercom-prefix');
                $intercom_code = $fcc->getCodeActive();
                unset($fcc);
                $ext->add('app-pickup', "_{$fc_pickup}.", '', new ext_NoOp('Attempt to Pickup ${EXTEN:' . $fclen . '} by ${CALLERID(num)}'));
                $ext->add('app-pickup', "_{$fc_pickup}.", '', new $ext_pickup('${EXTEN:' . $fclen . '}'));
                $ext->add('app-pickup', "_{$fc_pickup}.", '', new $ext_pickup('${EXTEN:' . $fclen . '}@ext-local'));
                $ext->add('app-pickup', "_{$fc_pickup}.", '', new $ext_pickup('${EXTEN:' . $fclen . '}@from-internal'));
                $ext->add('app-pickup', "_{$fc_pickup}.", '', new $ext_pickup('${EXTEN:' . $fclen . '}@from-internal-xfer'));
                $ext->add('app-pickup', "_{$fc_pickup}.", '', new $ext_pickup('${EXTEN:' . $fclen . '}@from-did-direct'));
                $ext->add('app-pickup', "_{$fc_pickup}.", '', new $ext_pickup('FMPR-${EXTEN:' . $fclen . '}'));
                $ext->add('app-pickup', "_{$fc_pickup}.", '', new $ext_pickup('LC-${EXTEN:' . $fclen . '}@from-internal'));
                $ext->add('app-pickup', "_{$fc_pickup}.", '', new $ext_pickup('LC-${EXTEN:' . $fclen . '}@from-internal-xfer'));
                $ext->add('app-pickup', "_{$fc_pickup}.", '', new $ext_pickup('FMPR-${EXTEN:' . $fclen . '}@from-internal'));
                $ext->add('app-pickup', "_{$fc_pickup}.", '', new $ext_pickup('FMPR-${EXTEN:' . $fclen . '}@from-internal-xfer'));
                $ext->add('app-pickup', "_{$fc_pickup}.", '', new $ext_pickup('FMPR-${EXTEN:' . $fclen . '}@from-did-direct'));
                if ($intercom_code != '') {
                    $ext->add('app-pickup', "_{$fc_pickup}{$intercom_code}.", '', new $ext_pickup('${EXTEN:' . strlen($fc_pickup . $intercom_code) . '}'));
                    $ext->add('app-pickup', "_{$fc_pickup}{$intercom_code}.", '', new $ext_pickup('${EXTEN:' . strlen($fc_pickup . $intercom_code) . '}@from-internal'));
                    $ext->add('app-pickup', "_{$fc_pickup}{$intercom_code}.", '', new $ext_pickup('${EXTEN:' . strlen($fc_pickup . $intercom_code) . '}@from-internal-xfer'));
                    $ext->add('app-pickup', "_{$fc_pickup}{$intercom_code}.", '', new $ext_pickup('${EXTEN:' . strlen($fc_pickup . $intercom_code) . '}@from-did-direct'));
                    $ext->add('app-pickup', "_{$fc_pickup}{$intercom_code}.", '', new $ext_pickup('FMPR-${EXTEN:' . strlen($fc_pickup . $intercom_code) . '}'));
                    $ext->add('app-pickup', "_{$fc_pickup}{$intercom_code}.", '', new $ext_pickup('FMPR-${EXTEN:' . strlen($fc_pickup . $intercom_code) . '}@from-internal'));
                    $ext->add('app-pickup', "_{$fc_pickup}{$intercom_code}.", '', new $ext_pickup('FMPR-${EXTEN:' . strlen($fc_pickup . $intercom_code) . '}@from-internal-xfer'));
                    $ext->add('app-pickup', "_{$fc_pickup}{$intercom_code}.", '', new $ext_pickup('FMPR-${EXTEN:' . strlen($fc_pickup . $intercom_code) . '}@from-did-direct'));
                }
                $ext->add('app-pickup', "_{$fc_pickup}.", '', new ext_hangup(''));
                // In order to do call pickup in ringgroups, we will need to try the ringgoup number
                // when doing call pickup for that ringgoup so we must see who is a member of what ringgroup
                // and then generate the dialplan
                //
                $rg_members = array();
                if (function_exists('ringgroups_list')) {
                    $rg_list = ringgroups_list(true);
                    foreach ($rg_list as $item) {
                        $thisgrp = ringgroups_get($item['grpnum']);
                        $grpliststr = $thisgrp['grplist'];
                        $grplist = explode("-", $grpliststr);
                        foreach ($grplist as $exten) {
                            if (strpos($exten, "#") === false) {
                                $rg_members[$exten][] = $item['grpnum'];
                            }
                        }
                    }
                }
                // Now we have a hash of extensions and what ringgoups they are members of
                // so we need to generate the callpickup dialplan for these specific extensions
                // to try the ringgoup.
                foreach ($rg_members as $exten => $grps) {
                    $ext->add('app-pickup', "{$fc_pickup}" . $exten, '', new $ext_pickup($exten));
                    $ext->add('app-pickup', "{$fc_pickup}" . $exten, '', new $ext_pickup($exten . '@ext-local'));
                    $ext->add('app-pickup', "{$fc_pickup}" . $exten, '', new $ext_pickup($exten . '@from-internal'));
                    $ext->add('app-pickup', "{$fc_pickup}" . $exten, '', new $ext_pickup($exten . '@from-internal-xfer'));
                    $ext->add('app-pickup', "{$fc_pickup}" . $exten, '', new $ext_pickup($exten . '@from-did-direct'));
                    $ext->add('app-pickup', "{$fc_pickup}" . $exten, '', new $ext_pickup('LC-' . $exten . '@from-internal'));
                    $ext->add('app-pickup', "{$fc_pickup}" . $exten, '', new $ext_pickup('LC-' . $exten . '@from-internal-xfer'));
                    $ext->add('app-pickup', "{$fc_pickup}" . $exten, '', new $ext_pickup('FMPR-' . $exten));
                    $ext->add('app-pickup', "{$fc_pickup}" . $exten, '', new $ext_pickup('FMPR-' . $exten . '@from-internal'));
                    $ext->add('app-pickup', "{$fc_pickup}" . $exten, '', new $ext_pickup('FMPR-' . $exten . '@from-internal-xfer'));
                    $ext->add('app-pickup', "{$fc_pickup}" . $exten, '', new $ext_pickup('FMPR-' . $exten . '@from-did-direct'));
                    foreach ($grps as $grp) {
                        $ext->add('app-pickup', "{$fc_pickup}" . $exten, '', new $ext_pickup($grp . '@from-internal'));
                        $ext->add('app-pickup', "{$fc_pickup}" . $exten, '', new $ext_pickup($grp . '@from-internal-xfer'));
                        $ext->add('app-pickup', "{$fc_pickup}" . $exten, '', new $ext_pickup($grp . '@ext-group'));
                    }
                    $ext->add('app-pickup', "{$fc_pickup}" . $exten, '', new ext_hangup(''));
                }
            }
            // zap barge
            if ($fc_zapbarge != '') {
                $ext->addInclude('from-internal-additional', 'app-zapbarge');
                // Add the include from from-internal
                $ext->add('app-zapbarge', $fc_zapbarge, '', new ext_macro('user-callerid'));
                $ext->add('app-zapbarge', $fc_zapbarge, '', new ext_setvar('GROUP()', '${CALLERID(number)}'));
                $ext->add('app-zapbarge', $fc_zapbarge, '', new ext_answer(''));
                $ext->add('app-zapbarge', $fc_zapbarge, '', new ext_wait(1));
                $ext->add('app-zapbarge', $fc_zapbarge, '', new ext_zapbarge(''));
                $ext->add('app-zapbarge', $fc_zapbarge, '', new ext_hangup(''));
            }
            // chan spy
            if ($fc_chanspy != '') {
                $ext->addInclude('from-internal-additional', 'app-chanspy');
                // Add the include from from-internal
                $ext->add('app-chanspy', $fc_chanspy, '', new ext_macro('user-callerid'));
                $ext->add('app-chanspy', $fc_chanspy, '', new ext_answer(''));
                $ext->add('app-chanspy', $fc_chanspy, '', new ext_wait(1));
                $ext->add('app-chanspy', $fc_chanspy, '', new ext_chanspy(''));
                $ext->add('app-chanspy', $fc_chanspy, '', new ext_hangup(''));
            }
            // Simulate options (ext-test)
            if ($fc_simu_pstn != '') {
                $ext->addInclude('from-internal-additional', 'ext-test');
                // Add the include from from-internal
                if ($fc_simu_pstn != '') {
                    if (ctype_digit($fc_simu_pstn)) {
                        $ext->add('ext-test', $fc_simu_pstn, '', new ext_goto('1', '${EXTEN}', 'from-pstn'));
                    } else {
                        $ext->add('ext-test', $fc_simu_pstn, '', new ext_goto('1', 's', 'from-pstn'));
                    }
                }
                $ext->add('ext-test', 'h', '', new ext_macro('hangupcall'));
            }
            $ext->addInclude('ext-did', 'ext-did-0001');
            // Add the include from from-internal
            $ext->addInclude('ext-did', 'ext-did-0002');
            // Add the include from from-internal
            $ext->add('ext-did', 'foo', '', new ext_noop('bar'));
            /* inbound routing extensions */
            $didlist = core_did_list();
            if (is_array($didlist)) {
                $catchall = false;
                $catchall_context = 'ext-did-catchall';
                foreach ($didlist as $item) {
                    if (trim($item['destination']) == '') {
                        continue;
                    }
                    $exten = trim($item['extension']);
                    $cidnum = trim($item['cidnum']);
                    // If the user put in just a cid number for routing, we add _. pattern to catch
                    // all DIDs with that CID number. Asterisk will complain about _. being dangerous
                    // but we don't want to limit this to just numberic as someone may be trying to
                    // route a non-numeric did
                    //
                    $cidroute = false;
                    if ($cidnum != '' && $exten == '') {
                        $exten = '_.';
                        $pricid = $item['pricid'] ? true : false;
                        $cidroute = true;
                    } else {
                        if ($cidnum != '' && $exten != '' || $cidnum == '' && $exten == '') {
                            $pricid = true;
                        } else {
                            $pricid = false;
                        }
                    }
                    $context = $pricid ? "ext-did-0001" : "ext-did-0002";
                    $exten = $exten == "" ? "s" : $exten;
                    $exten = $exten . ($cidnum == "" ? "" : "/" . $cidnum);
                    //if a CID num is defined, add it
                    if ($cidroute) {
                        $ext->add($context, $exten, '', new ext_setvar('__FROM_DID', '${EXTEN}'));
                        $ext->add($context, $exten, '', new ext_goto('1', 's'));
                        $exten = "s/{$cidnum}";
                        $ext->add($context, $exten, '', new ext_execif('$["${FROM_DID}" = ""]', 'Set', '__FROM_DID=${EXTEN}'));
                    } else {
                        $ext->add($context, $exten, '', new ext_setvar('__FROM_DID', '${EXTEN}'));
                    }
                    // always set callerID name
                    $ext->add($context, $exten, '', new ext_execif('$[ "${CALLERID(name)}" = "" ] ', 'Set', 'CALLERID(name)=${CALLERID(num)}'));
                    if (!empty($item['mohclass']) && trim($item['mohclass']) != 'default') {
                        $ext->add($context, $exten, '', new ext_setmusiconhold($item['mohclass']));
                        $ext->add($context, $exten, '', new ext_setvar('__MOHCLASS', $item['mohclass']));
                    }
                    // If we require RINGING, signal it as soon as we enter.
                    if ($item['ringing'] === "CHECKED") {
                        $ext->add($context, $exten, '', new ext_ringing(''));
                    }
                    if ($item['delay_answer']) {
                        $ext->add($context, $exten, '', new ext_wait($item['delay_answer']));
                    }
                    if ($exten == "s") {
                        //if the exten is s, then also make a catchall for undefined DIDs
                        $catchaccount = "_." . (empty($cidnum) ? "" : "/" . $cidnum);
                        if ($catchaccount == "_." && !$catchall) {
                            $catchall = true;
                            $ext->add($catchall_context, $catchaccount, '', new ext_NoOp('Catch-All DID Match - Found ${EXTEN} - You probably want a DID for this.'));
                            $ext->add($catchall_context, $catchaccount, '', new ext_goto('1', 's', 'ext-did'));
                        }
                    }
                    if ($item['privacyman'] == "1") {
                        $ext->add($context, $exten, '', new ext_macro('privacy-mgr', $item['pmmaxretries'] . ',' . $item['pmminlength']));
                    } else {
                        // if privacymanager is used, this is not necessary as it will not let blocked/anonymous calls through
                        // otherwise, we need to save the caller presence to set it properly if we forward the call back out the pbx
                        // note - the indirect table could go away as of 1.4.20 where it is fixed so that SetCallerPres can take
                        // the raw format.
                        //
                        if ($ast_lt_16) {
                            $ext->add($context, $exten, '', new ext_setvar('__CALLINGPRES_SV', '${CALLINGPRES_${CALLINGPRES}}'));
                        } else {
                            $ext->add($context, $exten, '', new ext_setvar('__CALLINGPRES_SV', '${CALLERPRES()}'));
                        }
                        $ext->add($context, $exten, '', new ext_setcallerpres('allowed_not_screened'));
                    }
                    if (!empty($item['alertinfo'])) {
                        $ext->add($context, $exten, '', new ext_setvar("__ALERT_INFO", str_replace(';', '\\;', $item['alertinfo'])));
                    }
                    // Add CID prefix, no need to do checks for existing pre-pends, this is an incoming did so this should
                    // be the first time the CID is manipulated. We set _RGPREFIX which is the same used throughout the different
                    // modules.
                    //
                    // TODO: If/When RGPREFIX is added to trunks, then see code in ringgroups to strip prefix if added here.
                    //
                    // TODO: core FreePBX documentation about this standard. (and probably rename from RGPREFIX to CIDPREFIX)
                    //
                    if (!empty($item['grppre'])) {
                        $ext->add($context, $exten, '', new ext_setvar('_RGPREFIX', $item['grppre']));
                        $ext->add($context, $exten, '', new ext_setvar('CALLERID(name)', '${RGPREFIX}${CALLERID(name)}'));
                    }
                    //the goto destination
                    // destination field in 'incoming' database is backwards from what ext_goto expects
                    $goto_context = strtok($item['destination'], ',');
                    $goto_exten = strtok(',');
                    $goto_pri = strtok(',');
                    $ext->add($context, $exten, 'dest-ext', new ext_goto($goto_pri, $goto_exten, $goto_context));
                }
                // If there's not a catchall, make one with an error message
                if (!$catchall) {
                    $ext->add($catchall_context, 's', '', new ext_noop("No DID or CID Match"));
                    $ext->add($catchall_context, 's', 'a2', new ext_answer(''));
                    $ext->add($catchall_context, 's', '', new ext_wait('2'));
                    $ext->add($catchall_context, 's', '', new ext_playback('ss-noservice'));
                    $ext->add($catchall_context, 's', '', new ext_sayalpha('${FROM_DID}'));
                    $ext->add($catchall_context, 's', '', new ext_hangup(''));
                    $ext->add($catchall_context, '_.', '', new ext_setvar('__FROM_DID', '${EXTEN}'));
                    $ext->add($catchall_context, '_.', '', new ext_noop('Received an unknown call with DID set to ${EXTEN}'));
                    $ext->add($catchall_context, '_.', '', new ext_goto('a2', 's'));
                    $ext->add($catchall_context, 'h', '', new ext_hangup(''));
                }
            }
            // Now create macro-from-zaptel-nnn or macro-from-dahdi-nnn for each defined channel to route it to the DID routing
            // Send it to from-trunk so it is handled as other dids would be handled.
            //
            // to this point we have both zap and dahdi configuration options. At generation though they can't co-exists. If compatibility
            // mode then it's still from-zaptel, otherwise it is which ever is present. We cant use ast_with_dahdi() (chan_dadi) because
            // it is for detection with compatibility mode. We need to actually determine if chan_dahdi is present or not at this point
            //
            if (!isset($chan_dahdi_loaded)) {
                if ($ast_ge_14 && isset($astman) && $astman->connected()) {
                    $response = $astman->send_request('Command', array('Command' => 'module show like chan_dahdi'));
                    $chan_dahdi_loaded = preg_match('/1 modules loaded/', $response['data']) > 0;
                }
            }
            foreach (core_zapchandids_list() as $row) {
                $channel = $row['channel'];
                $did = $row['did'];
                $this_context = "macro-from-dahdi-{$channel}";
                $ext->add($this_context, 's', '', new ext_noop('Entering ' . $this_context . ' with DID = ${DID} and setting to: ' . $did));
                $ext->add($this_context, 's', '', new ext_setvar('__FROM_DID', $did));
                $ext->add($this_context, 's', '', new ext_goto('1', $did, 'from-trunk'));
            }
            /* user extensions */
            $ext->addInclude('from-internal-additional', 'ext-local');
            // If running in Dynamic mode, this will insert the hints through an Asterisk #exec call.
            // which require "execincludes=yes" to be set in the [options] section of asterisk.conf
            //
            $fcc = new featurecode('paging', 'intercom-prefix');
            $intercom_code = $fcc->getCodeActive();
            unset($fcc);
            $intercom_code = $intercom_code == '' ? 'nointercom' : $intercom_code;
            // Pass the code so agi scripts like user_login_logout know to generate hints
            //
            $ext->addGlobal('INTERCOMCODE', $intercom_code);
            if ($amp_conf['DYNAMICHINTS']) {
                if ($amp_conf['USEDEVSTATE'] && function_exists('donotdisturb_get_config')) {
                    $add_dnd = ' dnd';
                } else {
                    $add_dnd = '';
                }
                $ext->addExec('ext-local', $amp_conf['AMPBIN'] . '/generate_hints.php ' . $intercom_code . $add_dnd);
            }
            $userlist = core_users_list();
            if (is_array($userlist)) {
                foreach ($userlist as $item) {
                    $exten = core_users_get($item[0]);
                    $vm = $exten['voicemail'] == "novm" || $exten['voicemail'] == "disabled" || $exten['voicemail'] == "" ? "novm" : $exten['extension'];
                    if (isset($exten['ringtimer']) && $exten['ringtimer'] != 0) {
                        $ext->add('ext-local', $exten['extension'], '', new ext_setvar('__RINGTIMER', $exten['ringtimer']));
                    }
                    $ext->add('ext-local', $exten['extension'], '', new ext_macro('exten-vm', $vm . "," . $exten['extension']));
                    if ($vm != "novm") {
                        $ext->add('ext-local', $exten['extension'], '', new ext_goto('1', 'vmret'));
                        $ext->add('ext-local', '${VM_PREFIX}' . $exten['extension'], '', new ext_macro('vm', $vm . ',DIRECTDIAL,${IVR_RETVM}'));
                        $ext->add('ext-local', '${VM_PREFIX}' . $exten['extension'], '', new ext_goto('1', 'vmret'));
                        $ext->add('ext-local', 'vmb' . $exten['extension'], '', new ext_macro('vm', $vm . ',BUSY,${IVR_RETVM}'));
                        $ext->add('ext-local', 'vmb' . $exten['extension'], '', new ext_goto('1', 'vmret'));
                        $ext->add('ext-local', 'vmu' . $exten['extension'], '', new ext_macro('vm', $vm . ',NOANSWER,${IVR_RETVM}'));
                        $ext->add('ext-local', 'vmu' . $exten['extension'], '', new ext_goto('1', 'vmret'));
                        $ext->add('ext-local', 'vms' . $exten['extension'], '', new ext_macro('vm', $vm . ',NOMESSAGE,${IVR_RETVM}'));
                        $ext->add('ext-local', 'vms' . $exten['extension'], '', new ext_goto('1', 'vmret'));
                    } else {
                        // If we return from teh macro, it means we are suppose to return to the IVR
                        //
                        $ext->add('ext-local', $exten['extension'], '', new ext_goto('1', 'return', '${IVR_CONTEXT}'));
                    }
                    // Create the hints if running in normal mode
                    //
                    if (!$amp_conf['DYNAMICHINTS']) {
                        $hint = core_hint_get($exten['extension']);
                        $dnd_string = $amp_conf['USEDEVSTATE'] && function_exists('donotdisturb_get_config') ? "&Custom:DND" . $exten['extension'] : '';
                        if (!empty($hint)) {
                            $ext->addHint('ext-local', $exten['extension'], $hint . $dnd_string);
                            if ($intercom_code != '') {
                                $ext->addHint('ext-local', $intercom_code . $exten['extension'], $hint . $dnd_string);
                            }
                        } else {
                            if ($dnd_string) {
                                $ext->addHint('ext-local', $exten['extension'], "&Custom:DND" . $exten['extension']);
                                if ($intercom_code != '') {
                                    $ext->addHint('ext-local', $intercom_code . $exten['extension'], "&Custom:DND" . $exten['extension']);
                                }
                            }
                        }
                    }
                    if ($exten['sipname']) {
                        $ext->add('ext-local', $exten['sipname'], '', new ext_goto('1', $item[0], 'from-internal'));
                    }
                    // Now make a special context for the IVR inclusions of local extension dialing so that
                    // when people use the Queues breakout ability, and break out to someone's extensions, voicemail
                    // works.
                    //
                    $ivr_context = 'from-did-direct-ivr';
                    if ($ast_lt_16) {
                        $ext->add($ivr_context, $exten['extension'], '', new ext_execif('$["${BLKVM_OVERRIDE}" != ""]', 'dbDel', '${BLKVM_OVERRIDE}'));
                    } else {
                        $ext->add($ivr_context, $exten['extension'], '', new ext_execif('$["${BLKVM_OVERRIDE}" != ""]', 'Noop', 'Deleting: ${BLKVM_OVERRIDE}: ${DB_DELETE(${BLKVM_OVERRIDE})}'));
                    }
                    $ext->add($ivr_context, $exten['extension'], '', new ext_setvar('__NODEST', ''));
                    $ext->add($ivr_context, $exten['extension'], '', new ext_goto('1', $exten['extension'], 'from-did-direct'));
                    if ($vm != "novm") {
                        if ($ast_lt_16) {
                            $ext->add($ivr_context, '${VM_PREFIX}' . $exten['extension'], '', new ext_execif('$["${BLKVM_OVERRIDE}" != ""]', 'dbDel', '${BLKVM_OVERRIDE}'));
                        } else {
                            $ext->add($ivr_context, '${VM_PREFIX}' . $exten['extension'], '', new ext_execif('$["${BLKVM_OVERRIDE}" != ""]', 'Noop', 'Deleting: ${BLKVM_OVERRIDE}: ${DB_DELETE(${BLKVM_OVERRIDE})}'));
                        }
                        $ext->add($ivr_context, '${VM_PREFIX}' . $exten['extension'], '', new ext_setvar('__NODEST', ''));
                        $ext->add($ivr_context, '${VM_PREFIX}' . $exten['extension'], '', new ext_macro('vm', $vm . ',DIRECTDIAL,${IVR_RETVM}'));
                        $ext->add($ivr_context, '${VM_PREFIX}' . $exten['extension'], '', new ext_gotoif('$["${IVR_RETVM}" = "RETURN" & "${IVR_CONTEXT}" != ""]', 'ext-local,vmret,playret'));
                    }
                }
                $ext->add('ext-local', 'vmret', '', new ext_gotoif('$["${IVR_RETVM}" = "RETURN" & "${IVR_CONTEXT}" != ""]', 'playret'));
                $ext->add('ext-local', 'vmret', '', new ext_hangup(''));
                $ext->add('ext-local', 'vmret', 'playret', new ext_playback('exited-vm-will-be-transfered&silence/1'));
                $ext->add('ext-local', 'vmret', '', new ext_goto('1', 'return', '${IVR_CONTEXT}'));
                $ext->add('ext-local', 'h', '', new ext_macro('hangupcall'));
            }
            /* Create the from-trunk-tech-chanelid context that can be used for inbound group counting
             * Create the DUNDI macros for DUNDI trunks
             * Create the ext-trunk context for direct trunk dialing TODO: should this be its own module?
             */
            $trunklist = core_trunks_listbyid();
            if (is_array($trunklist) && count($trunklist)) {
                $tcontext = 'ext-trunk';
                $texten = 'tdial';
                $tcustom = 'tcustom';
                $generate_texten = false;
                $generate_tcustom = false;
                foreach ($trunklist as $trunkprops) {
                    if (trim($trunkprops['disabled']) == 'on') {
                        continue;
                    }
                    $trunkgroup = 'OUT_' . $trunkprops['trunkid'];
                    switch ($trunkprops['tech']) {
                        case 'dundi':
                            $macro_name = 'macro-dundi-' . $trunkprops['trunkid'];
                            $ext->addSwitch($macro_name, 'DUNDI/' . $trunkprops['channelid']);
                            $ext->add($macro_name, 's', '', new ext_goto('1', '${ARG1}'));
                            $trunkcontext = "from-trunk-" . $trunkprops['tech'] . "-" . $trunkprops['channelid'];
                            $ext->add($trunkcontext, '_.', '', new ext_set('GROUP()', $trunkgroup));
                            $ext->add($trunkcontext, '_.', '', new ext_goto('1', '${EXTEN}', 'from-trunk'));
                            $ext->add($tcontext, $trunkprops['trunkid'], '', new ext_set('OUTBOUND_GROUP', $trunkgroup));
                            $ext->add($tcontext, $trunkprops['trunkid'], '', new ext_gotoif('$["${OUTMAXCHANS_' . $trunkprops['trunkid'] . '}" = ""]', 'nomax'));
                            $ext->add($tcontext, $trunkprops['trunkid'], '', new ext_gotoif('$[${GROUP_COUNT(' . $trunkgroup . ')} >= ${OUTMAXCHANS_${DIAL_TRUNK}}]', 'hangit'));
                            if ($ast_lt_16) {
                                $ext->add($tcontext, $trunkprops['trunkid'], 'nomax', new ext_execif('$["${CALLINGPRES_SV}" != ""]', 'SetCallerPres', '${CALLINGPRES_SV}'));
                            } else {
                                $ext->add($tcontext, $trunkprops['trunkid'], 'nomax', new ext_execif('$["${CALLINGPRES_SV}" != ""]', 'Set', 'CALLERPRES()=${CALLINGPRES_SV}'));
                            }
                            $ext->add($tcontext, $trunkprops['trunkid'], '', new ext_set('DIAL_NUMBER', '${FROM_DID}'));
                            $ext->add($tcontext, $trunkprops['trunkid'], '', new ext_gosubif('$["${PREFIX_TRUNK_' . $trunkprops['trunkid'] . '}" != ""]', 'sub-flp-' . $trunkprops['trunkid'] . ',s,1'));
                            $ext->add($tcontext, $trunkprops['trunkid'], '', new ext_set('OUTNUM', '${OUTPREFIX_${DIAL_TRUNK}}${DIAL_NUMBER}'));
                            // OUTNUM is the final dial number
                            $ext->add($tcontext, $trunkprops['trunkid'], '', new ext_macro('dundi-${DIAL_TRUNK}', '${OUTNUM}'));
                            $ext->add($tcontext, $trunkprops['trunkid'], 'hangit', new ext_hangup());
                            break;
                        case 'iax':
                            $trunkprops['tech'] = 'iax2';
                            // fall-through
                        // fall-through
                        case 'iax2':
                        case 'sip':
                            $trunkcontext = "from-trunk-" . $trunkprops['tech'] . "-" . $trunkprops['channelid'];
                            $ext->add($trunkcontext, '_.', '', new ext_set('GROUP()', $trunkgroup));
                            $ext->add($trunkcontext, '_.', '', new ext_goto('1', '${EXTEN}', 'from-trunk'));
                            // fall-through
                        // fall-through
                        case 'zap':
                        case 'dahdi':
                            $ext->add($tcontext, $trunkprops['trunkid'], '', new ext_set('TDIAL_STRING', strtoupper($trunkprops['tech']) . '/' . $trunkprops['channelid']));
                            $ext->add($tcontext, $trunkprops['trunkid'], '', new ext_set('DIAL_TRUNK', $trunkprops['trunkid']));
                            $ext->add($tcontext, $trunkprops['trunkid'], '', new ext_goto('1', $texten, 'ext-trunk'));
                            $generate_texten = true;
                            break;
                            // TODO we don't have the OUTNUM until later so fix this...
                        // TODO we don't have the OUTNUM until later so fix this...
                        case 'custom':
                            $dial_string = str_replace('$OUTNUM$', '\\\\$\\\\{OUTNUM\\\\}', $trunkprops['channelid']);
                            $ext->add($tcontext, $trunkprops['trunkid'], '', new ext_set('TDIAL_STRING', $dial_string));
                            $ext->add($tcontext, $trunkprops['trunkid'], '', new ext_set('DIAL_TRUNK', $trunkprops['trunkid']));
                            $ext->add($tcontext, $trunkprops['trunkid'], '', new ext_goto('1', $tcustom, 'ext-trunk'));
                            $generate_tcustom = true;
                            break;
                        case 'enum':
                            // Not Supported
                            break;
                        default:
                    }
                }
                if ($generate_tcustom) {
                    $ext->add($tcontext, $tcustom, '', new ext_set('OUTBOUND_GROUP', 'OUT_${DIAL_TRUNK}'));
                    $ext->add($tcontext, $tcustom, '', new ext_gotoif('$["${OUTMAXCHANS_${DIAL_TRUNK}}" = ""]', 'nomax'));
                    $ext->add($tcontext, $tcustom, '', new ext_gotoif('$[${GROUP_COUNT(OUT_${DIAL_TRUNK})} >= ${OUTMAXCHANS_${DIAL_TRUNK}}]', 'hangit'));
                    if ($ast_lt_16) {
                        $ext->add($tcontext, $tcustom, 'nomax', new ext_execif('$["${CALLINGPRES_SV}" != ""]', 'SetCallerPres', '${CALLINGPRES_SV}'));
                    } else {
                        $ext->add($tcontext, $tcustom, 'nomax', new ext_execif('$["${CALLINGPRES_SV}" != ""]', 'Set', 'CALLERPRES()=${CALLINGPRES_SV}'));
                    }
                    $ext->add($tcontext, $tcustom, '', new ext_set('DIAL_NUMBER', '${FROM_DID}'));
                    $ext->add($tcontext, $tcustom, '', new ext_gosubif('$["${PREFIX_TRUNK_${DIAL_TRUNK}}" != ""]', 'sub-flp-${DIAL_TRUNK},s,1'));
                    $ext->add($tcontext, $tcustom, '', new ext_set('OUTNUM', '${OUTPREFIX_${DIAL_TRUNK}}${DIAL_NUMBER}'));
                    // OUTNUM is the final dial number
                    // Address Security Vulnerability in many earlier versions of Asterisk from an external source tranmitting a
                    // malicious CID that can cause overflows in the Asterisk code.
                    //
                    $ext->add($tcontext, $tcustom, '', new ext_set('CALLERID(number)', '${CALLERID(number):0:40}'));
                    $ext->add($tcontext, $tcustom, '', new ext_set('CALLERID(name)', '${CALLERID(name):0:40}'));
                    $ext->add($tcontext, $tcustom, '', new ext_dial('${EVAL(${TDIAL_STRING})}', '300,${DIAL_TRUNK_OPTIONS}'));
                    $ext->add($tcontext, $tcustom, 'hangit', new ext_hangup());
                }
                if ($generate_texten) {
                    $ext->add($tcontext, $texten, '', new ext_set('OUTBOUND_GROUP', 'OUT_${DIAL_TRUNK}'));
                    $ext->add($tcontext, $texten, '', new ext_gotoif('$["${OUTMAXCHANS_${DIAL_TRUNK}}" = ""]', 'nomax'));
                    $ext->add($tcontext, $texten, '', new ext_gotoif('$[${GROUP_COUNT(OUT_${DIAL_TRUNK})} >= ${OUTMAXCHANS_${DIAL_TRUNK}}]', 'hangit'));
                    if ($ast_lt_16) {
                        $ext->add($tcontext, $texten, 'nomax', new ext_execif('$["${CALLINGPRES_SV}" != ""]', 'SetCallerPres', '${CALLINGPRES_SV}'));
                    } else {
                        $ext->add($tcontext, $texten, 'nomax', new ext_execif('$["${CALLINGPRES_SV}" != ""]', 'Set', 'CALLERPRES()=${CALLINGPRES_SV}'));
                    }
                    $ext->add($tcontext, $texten, '', new ext_set('DIAL_NUMBER', '${FROM_DID}'));
                    $ext->add($tcontext, $texten, '', new ext_gosubif('$["${PREFIX_TRUNK_${DIAL_TRUNK}}" != ""]', 'sub-flp-${DIAL_TRUNK},s,1'));
                    $ext->add($tcontext, $texten, '', new ext_set('OUTNUM', '${OUTPREFIX_${DIAL_TRUNK}}${DIAL_NUMBER}'));
                    // OUTNUM is the final dial number
                    $ext->add($tcontext, $texten, '', new ext_dial('${TDIAL_STRING}/${OUTNUM}', '300,${DIAL_TRUNK_OPTIONS}'));
                    // Address Security Vulnerability in many earlier versions of Asterisk from an external source tranmitting a
                    // malicious CID that can cause overflows in the Asterisk code.
                    //
                    $ext->add($tcontext, $texten, '', new ext_set('CALLERID(number)', '${CALLERID(number):0:40}'));
                    $ext->add($tcontext, $texten, '', new ext_set('CALLERID(name)', '${CALLERID(name):0:40}'));
                    $ext->add($tcontext, $texten, 'hangit', new ext_hangup());
                }
            }
            /* dialplan globals */
            // modules should NOT use the globals table to store anything!
            // modules should use $ext->addGlobal("testvar","testval"); in their module_get_config() function instead
            // I'm cheating for core functionality - do as I say, not as I do ;-)
            // Auto add these globals to give access to agi scripts and other needs, unless defined in the global table.
            //
            $amp_conf_globals = array("ASTETCDIR", "ASTMODDIR", "ASTVARLIBDIR", "ASTAGIDIR", "ASTSPOOLDIR", "ASTRUNDIR", "ASTLOGDIR", "CWINUSEBUSY", "AMPMGRUSER", "AMPMGRPASS", "AMPDBENGINE", "AMPDBHOST", "AMPDBNAME", "AMPDBUSER", "AMPDBPASS", "AMPDBFILE");
            $disable_recording = false;
            $sql = "SELECT * FROM globals";
            $globals = sql($sql, "getAll", DB_FETCHMODE_ASSOC);
            foreach ($globals as $global) {
                $value = $global['value'];
                $ext->addGlobal($global['variable'], $value);
                // now if for some reason we have a variable in the global table
                // that is in our $amp_conf_globals list, then remove it so we
                // don't duplicate, the sql table will take precedence
                //
                if (array_key_exists($global['variable'], $amp_conf_globals)) {
                    $rm_keys = array_keys($amp_conf_globals, $global['variable']);
                    foreach ($rm_keys as $index) {
                        unset($amp_conf_globals[$index]);
                    }
                }
                if ($global['variable'] == 'RECORDING_STATE' && strtoupper($global['value']) == 'DISABLED') {
                    $disable_recording = true;
                }
            }
            foreach ($amp_conf_globals as $global) {
                if (isset($amp_conf[$global])) {
                    $value = $amp_conf[$global];
                    if ($value === true || $value === false) {
                        $value = $value ? 'true' : 'false';
                    }
                    $ext->addGlobal($global, $value);
                    out("Added to globals: {$global} = {$value}");
                }
            }
            // Put the asterisk version in a global for agi etc.
            $ext->addGlobal('ASTVERSION', $version);
            // Put the use of chan_dahdi in a global for dialparties
            $ext->addGlobal('ASTCHANDAHDI', $chan_dahdi ? '1' : '0');
            // Create CallingPresTable to deal with difference that ${CALINGPRES} returns vs. what
            // SetCallerPres() accepts. This is a workaround that gets resolved in 1.6 where
            // function CALLINGPRES() is consistent.
            // This should be fixed in 1.4.20 but for now we keep it in until 1.6
            //
            if ($ast_lt_16) {
                $ext->addGlobal('CALLINGPRES_0', 'allowed_not_screened');
                $ext->addGlobal('CALLINGPRES_1', 'allowed_passed_screen');
                $ext->addGlobal('CALLINGPRES_2', 'allowed_failed_screen');
                $ext->addGlobal('CALLINGPRES_3', 'allowed');
                $ext->addGlobal('CALLINGPRES_32', 'prohib_not_screened');
                $ext->addGlobal('CALLINGPRES_33', 'prohib_passed_screen');
                $ext->addGlobal('CALLINGPRES_34', 'prohib_failed_screen');
                $ext->addGlobal('CALLINGPRES_35', 'prohib');
                $ext->addGlobal('CALLINGPRES_67', 'unavailable');
            }
            // This checks if we have func_extstate loaded, if so we set the global which dialparties
            // can use (and any other AGI script) to determine that this function exists and not connect
            // to the manager to get the information
            //
            $has_extension_state = !$ast_lt_16;
            if ($ast_ge_14 && $ast_lt_16) {
                $response = $astman->send_request('Command', array('Command' => 'module show like func_extstate'));
                if (preg_match('/1 modules loaded/', $response['data'])) {
                    $ext->addGlobal('HAS_EXTENSION_STATE', 'TRUE');
                    $has_extension_state = true;
                }
            }
            // Now let's create the required globals for the trunks so outbound routes work. These used to
            // be stored in the globals table but are not generated by retrieve conf and pulled from the
            // trunks table
            //
            $sqlstr = "\n\t\t\t\tSELECT `trunkid`, `tech`, `outcid`, `keepcid`, `maxchans`, `failscript`, `dialoutprefix`, `channelid`, `disabled` \n\t\t\t\tFROM `trunks` ORDER BY `trunkid`\n\t\t\t";
            $trunks = sql($sqlstr, "getAll", DB_FETCHMODE_ASSOC);
            $trunk_hash = core_trunks_list_dialrules();
            // $has_keepcid_cnum is used when macro-outbound-callerid is generated to determine if we need to insert the
            // final execif() statement so it is important to be set before then and here
            //
            $has_keepcid_cnum = false;
            foreach ($trunks as $trunk) {
                $tid = $trunk['trunkid'];
                $tech = strtoupper($trunk['tech']);
                if ($tech == 'IAX') {
                    $tech = 'IAX2';
                } elseif ($tech == 'ZAP' && $chan_dahdi) {
                    $tech = 'DAHDI';
                }
                if ($tech == 'CUSTOM') {
                    $ext->addGlobal('OUT_' . $tid, 'AMP:' . $trunk['channelid']);
                } else {
                    $ext->addGlobal('OUT_' . $tid, $tech . "/" . $trunk['channelid']);
                }
                $ext->addGlobal('OUTCID_' . $tid, $trunk['outcid']);
                $ext->addGlobal('OUTMAXCHANS_' . $tid, $trunk['maxchans']);
                $ext->addGlobal('OUTFAIL_' . $tid, $trunk['failscript']);
                $ext->addGlobal('OUTPREFIX_' . $tid, $trunk['dialoutprefix']);
                $ext->addGlobal('OUTDISABLE_' . $tid, $trunk['disabled']);
                $ext->addGlobal('OUTKEEPCID_' . $tid, $trunk['keepcid']);
                $ext->addGlobal('FORCEDOUTCID_' . $tid, $trunk['keepcid'] == 'all' ? $trunk['outcid'] : "");
                if ($trunk['keepcid'] == 'cnum') {
                    $has_keepcid_cnum = true;
                }
                // Generate PREFIX_TRUNK_$tid even if 0 since globals will persist and cause crashes
                if (isset($trunk_hash[$tid]) && count($trunk_hash)) {
                    $patterns = $trunk_hash[$tid];
                    // First, generate the global referencing how many there are
                    $ext->addGlobal("PREFIX_TRUNK_{$tid}", count($patterns));
                    $context = 'sub-flp-' . $tid;
                    $target = 'TARGET_FLP_' . $tid;
                    $exten = 's';
                    foreach ($patterns as $pattern) {
                        $prepend = $pattern['prepend_digits'];
                        $offset = strlen(preg_replace('/(\\[[^\\]]*\\])/', 'X', $pattern['match_pattern_prefix']));
                        $regex_base = $pattern['match_pattern_prefix'] . $pattern['match_pattern_pass'];
                        // convert asterisk pattern matching into perl regular expression
                        //  - two steps, use $ in place of +
                        //  - next replace $ with +
                        // if you don't do this, the str_replace() walks over itself
                        $regex_intermediate = str_replace(array('X', 'Z', 'N', '.', '*', '+'), array('[0-9]', '[1-9]', '[2-9]', '[0-9#*\\\\$]$', '\\\\*', '\\\\$'), $pattern['match_pattern_prefix'] . $pattern['match_pattern_pass']);
                        $regex = strtr($regex_intermediate, "\$", "+");
                        if ($pattern['prepend_digits'] == '' && $offset == 0) {
                            $ext->add($context, $exten, '', new ext_execif('$[${REGEX("^' . $regex . '$" ${DIAL_NUMBER})} = 1]', 'Return'));
                        } else {
                            $offset = $offset ? ':' . $offset : '';
                            $ext->add($context, $exten, '', new ext_execif('$[${REGEX("^' . $regex . '$" ${DIAL_NUMBER})} = 1]', 'Set', $target . '=' . $pattern['prepend_digits'] . '${DIAL_NUMBER' . $offset . '}'));
                            $ext->add($context, $exten, '', new ext_gotoif('$[${LEN(${' . $target . '})} != 0]', 'match'));
                        }
                    }
                    $ext->add($context, $exten, '', new ext_return(''));
                    $ext->add($context, $exten, 'match', new ext_set('DIAL_NUMBER', '${' . $target . '}'));
                    $ext->add($context, $exten, '', new ext_return(''));
                } else {
                    $ext->addGlobal("PREFIX_TRUNK_{$tid}", '');
                }
            }
            // Generate macro-record-enable, if recording is disabled then we just make it a stub
            // Otherwise we make it right
            //
            $context = 'macro-record-enable';
            $exten = 's';
            if ($disable_recording) {
                $ext->add($context, $exten, '', new ext_macroexit());
            } else {
                $ext->add($context, $exten, '', new ext_gotoif('$["${BLINDTRANSFER}" = ""]', 'check'));
                $ext->add($context, $exten, '', new ext_resetcdr('w'));
                if ($ast_ge_14) {
                    $ext->add($context, $exten, '', new ext_stopmixmonitor());
                } else {
                    $ext->add($context, $exten, '', new ext_stopmonitor());
                }
                $ext->add($context, $exten, 'check', new ext_execif('$["${ARG1}"=""]', 'MacroExit'));
                $ext->add($context, $exten, '', new ext_gotoif('$["${ARG2}"="Group"]', 'Group', 'OUT'));
                $ext->add($context, $exten, 'Group', new ext_set('LOOPCNT', '${FIELDQTY(ARG1,-)}'));
                $ext->add($context, $exten, '', new ext_set('ITER', '1'));
                $ext->add($context, $exten, 'begin', new ext_gotoif('$["${CUT(DB(AMPUSER/${CUT(ARG1,-,${ITER})}/recording),=,3)}" != "Always"]', 'continue'));
                $ext->add($context, $exten, '', new ext_set('TEXTEN', '${CUT(ARG1,-,${ITER})}'));
                $ext->add($context, $exten, '', new ext_noop('Recording enable for ${TEXTEN}'));
                $ext->add($context, $exten, '', new ext_set('CALLFILENAME', 'g${TEXTEN}-${STRFTIME(${EPOCH},,%Y%m%d-%H%M%S)}-${UNIQUEID}'));
                $ext->add($context, $exten, '', new ext_goto('record'));
                $ext->add($context, $exten, 'continue', new ext_set('ITER', '$[${ITER}+1]'));
                $ext->add($context, $exten, '', new ext_gotoif('$[${ITER}<=${LOOPCNT}]', 'begin'));
                $ext->add($context, $exten, 'OUT', new ext_gotoif('$["${ARG2}"="IN"]', 'IN'));
                $ext->add($context, $exten, '', new ext_execif('$["${CUT(DB(AMPUSER/${ARG1}/recording),\\\\\\|,1):4}" != "Always"]', 'MacroExit'));
                $ext->add($context, $exten, '', new ext_noop('Recording enable for ${ARG1}'));
                $ext->add($context, $exten, '', new ext_set('CALLFILENAME', 'OUT${ARG1}-${STRFTIME(${EPOCH},,%Y%m%d-%H%M%S)}-${UNIQUEID}'));
                $ext->add($context, $exten, '', new ext_goto('record'));
                $ext->add($context, $exten, 'IN', new ext_execif('$["${CUT(DB(AMPUSER/${ARG1}/recording),\\\\\\|,2):3}" != "Always"]', 'MacroExit'));
                $ext->add($context, $exten, '', new ext_noop('Recording enable for ${ARG1}'));
                $ext->add($context, $exten, '', new ext_set('CALLFILENAME', '${STRFTIME(${EPOCH},,%Y%m%d-%H%M%S)}-${UNIQUEID}'));
                $ext->add($context, $exten, 'record', new ext_mixmonitor('${MIXMON_DIR}${CALLFILENAME}.${MIXMON_FORMAT}', '', '${MIXMON_POST}'));
                $ext->add($context, $exten, '', new ext_macroexit());
            }
            /* outbound routes */
            $ext->addInclude('from-internal-additional', 'outbound-allroutes');
            //$ext->add('outbound-allroutes', '_!', '', new ext_macro('user-callerid,SKIPTTL'));
            $ext->add('outbound-allroutes', 'foo', '', new ext_noop('bar'));
            $routes = core_routing_list();
            $trunk_table = core_trunks_listbyid();
            $delim = $ast_lt_16 ? '|' : ',';
            foreach ($routes as $route) {
                $add_extra_pri1 = array();
                $context = 'outrt-' . $route['route_id'];
                $comment = $route['name'];
                $ext->addSectionComment($context, $comment);
                if (function_exists('timeconditions_timegroups_get_times') && $route['time_group_id'] !== null) {
                    $times = timeconditions_timegroups_get_times($route['time_group_id'], true);
                    if (is_array($times) && count($times)) {
                        foreach ($times as $time) {
                            $ext->addInclude('outbound-allroutes', $context . $delim . $time[1], $comment);
                        }
                    } else {
                        $ext->addInclude('outbound-allroutes', $context, $comment);
                    }
                } else {
                    $ext->addInclude('outbound-allroutes', $context, $comment);
                }
                $patterns = core_routing_getroutepatternsbyid($route['route_id']);
                $trunks = core_routing_getroutetrunksbyid($route['route_id']);
                foreach ($patterns as $pattern) {
                    // returns:
                    // array('prepend_digits' => $pattern['prepend_digits'], 'dial_pattern' => $exten, 'offset' => $pos);
                    //
                    $fpattern = core_routing_formatpattern($pattern);
                    $exten = $fpattern['dial_pattern'];
                    $offset = $fpattern['offset'] == 0 ? '' : ':' . $fpattern['offset'];
                    // This will not get called, but it fixes some things like custom-context or other possible custom uses of these
                    // generated contexts that don't have an 'outbound-allroutes' wrapper around them, of course in those cases the
                    // CID part of the dialplan will not get executed
                    if (!isset($add_extra_pri1[$fpattern['base_pattern']])) {
                        $ext->add($context, $fpattern['base_pattern'], '', new ext_macro('user-callerid,SKIPTTL'));
                        $add_extra_pri1[$fpattern['base_pattern']] = true;
                    }
                    if ($fpattern['base_pattern'] != $exten) {
                        $ext->add($context, $exten, '', new ext_macro('user-callerid,SKIPTTL'));
                    }
                    $ext->add($context, $exten, '', new ext_noop(sprintf(_('Calling Out Route: %s'), $route['name'])));
                    if ($route['emergency_route'] != '') {
                        $ext->add($context, $exten, '', new ext_set("EMERGENCYROUTE", $route['emergency_route']));
                    }
                    if ($route['intracompany_route'] != '') {
                        $ext->add($context, $exten, '', new ext_set("INTRACOMPANYROUTE", $route['intracompany_route']));
                    }
                    if ($route['mohclass'] != '') {
                        $ext->add($context, $exten, '', new ext_set("MOHCLASS", '${IF($["${MOHCLASS}"=""]?' . $route['mohclass'] . ':${MOHCLASS})}'));
                    }
                    if ($route['outcid'] != '') {
                        if ($route['outcid_mode'] != '') {
                            $ext->add($context, $exten, '', new ext_execif('$["${KEEPCID}"!="TRUE" & ${LEN(${TRUNKCIDOVERRIDE})}=0]', 'Set', 'TRUNKCIDOVERRIDE=' . $route['outcid']));
                        } else {
                            $ext->add($context, $exten, '', new ext_execif('$["${KEEPCID}"!="TRUE" & ${LEN(${DB(AMPUSER/${AMPUSER}/outboundcid)})}=0 & ${LEN(${TRUNKCIDOVERRIDE})}=0]', 'Set', 'TRUNKCIDOVERRIDE=' . $route['outcid']));
                        }
                    }
                    $ext->add($context, $exten, '', new ext_set("_NODEST", ""));
                    $ext->add($context, $exten, '', new ext_macro('record-enable,${AMPUSER},OUT'));
                    $password = $route['password'];
                    foreach ($trunks as $trunk_id) {
                        if (isset($trunk_table[$trunk_id])) {
                            switch (strtolower($trunk_table[$trunk_id]['tech'])) {
                                case 'dundi':
                                    $trunk_macro = 'dialout-dundi';
                                    break;
                                case 'enum':
                                    $trunk_macro = 'dialout-enum';
                                    break;
                                default:
                                    $trunk_macro = 'dialout-trunk';
                                    break;
                            }
                        }
                        $ext->add($context, $exten, '', new ext_macro($trunk_macro, $trunk_id . ',' . $pattern['prepend_digits'] . '${EXTEN' . $offset . '},' . $password));
                        $password = '';
                    }
                    $ext->add($context, $exten, '', new ext_macro("outisbusy"));
                }
                unset($add_extra_pri1);
            }
            general_generate_indications();
            // "blackhole" destinations
            $ext->add('app-blackhole', 'hangup', '', new ext_noop('Blackhole Dest: Hangup'));
            $ext->add('app-blackhole', 'hangup', '', new ext_hangup());
            $ext->add('app-blackhole', 'zapateller', '', new ext_noop('Blackhole Dest: Play SIT Tone'));
            $ext->add('app-blackhole', 'zapateller', '', new ext_answer());
            $ext->add('app-blackhole', 'zapateller', '', new ext_zapateller());
            // Should hangup ?
            // $ext->add('app-blackhole', 'zapateller', '', new ext_hangup());
            $ext->add('app-blackhole', 'musiconhold', '', new ext_noop('Blackhole Dest: Put caller on hold forever'));
            $ext->add('app-blackhole', 'musiconhold', '', new ext_answer());
            $ext->add('app-blackhole', 'musiconhold', '', new ext_musiconhold());
            $ext->add('app-blackhole', 'congestion', '', new ext_noop('Blackhole Dest: Congestion'));
            $ext->add('app-blackhole', 'congestion', '', new ext_answer());
            $ext->add('app-blackhole', 'congestion', '', new ext_playtones('congestion'));
            $ext->add('app-blackhole', 'congestion', '', new ext_congestion());
            $ext->add('app-blackhole', 'congestion', '', new ext_hangup());
            $ext->add('app-blackhole', 'busy', '', new ext_noop('Blackhole Dest: Busy'));
            $ext->add('app-blackhole', 'busy', '', new ext_answer());
            $ext->add('app-blackhole', 'busy', '', new ext_playtones('busy'));
            $ext->add('app-blackhole', 'busy', '', new ext_busy());
            $ext->add('app-blackhole', 'busy', '', new ext_hangup());
            $ext->add('app-blackhole', 'ring', '', new ext_noop('Blackhole Dest: Ring'));
            $ext->add('app-blackhole', 'ring', '', new ext_answer());
            $ext->add('app-blackhole', 'ring', '', new ext_playtones('ring'));
            $ext->add('app-blackhole', 'ring', '', new ext_wait(300));
            $ext->add('app-blackhole', 'ring', '', new ext_hangup());
            if ($amp_conf['AMPBADNUMBER'] !== false) {
                $context = 'bad-number';
                $exten = '_X.';
                $ext->add($context, $exten, '', new extension('ResetCDR()'));
                $ext->add($context, $exten, '', new extension('NoCDR()'));
                $ext->add($context, $exten, '', new ext_progress());
                $ext->add($context, $exten, '', new ext_wait('1'));
                $ext->add($context, $exten, '', new ext_progress());
                $ext->add($context, $exten, '', new ext_playback('silence/1&cannot-complete-as-dialed&check-number-dial-again,noanswer'));
                $ext->add($context, $exten, '', new ext_wait('1'));
                $ext->add($context, $exten, '', new ext_congestion('20'));
                $ext->add($context, $exten, '', new ext_hangup());
            }
            /*
            ;------------------------------------------------------------------------
            ; [macro-confirm]
            ;------------------------------------------------------------------------
            ; CONTEXT:      macro-confirm                                                                                                              
            ; PURPOSE:      added default message if none supplied
            ;
            ; Follom-Me and Ringgroups provide an option to supply a message to be
            ; played as part of the confirmation. These changes have added a default
            ; message if none is supplied.
            ;
            ;------------------------------------------------------------------------
            */
            $context = 'macro-confirm';
            $exten = 's';
            $ext->add($context, $exten, '', new ext_setvar('LOOPCOUNT', '0'));
            $ext->add($context, $exten, '', new ext_setvar('__MACRO_RESULT', 'ABORT'));
            $ext->add($context, $exten, '', new ext_setvar('MSG1', '${IF($["foo${ARG1}" != "foo"]?${ARG1}:"incoming-call-1-accept-2-decline")}'));
            if ($ast_ge_14) {
                $ext->add($context, $exten, 'start', new ext_background('${MSG1},m,${CHANNEL(language)},macro-confirm'));
            } else {
                $ext->add($context, $exten, 'start', new ext_background('${MSG1},m,${LANGUAGE},macro-confirm'));
            }
            $ext->add($context, $exten, '', new ext_read('INPUT', '', 1, '', '', 4));
            $ext->add($context, $exten, '', new ext_gotoif('$[${LEN(${INPUT})} > 0]', '${INPUT},1', 't,1'));
            $exten = '1';
            $ext->add($context, $exten, '', new ext_gotoif('$["${DB_EXISTS(RG/${ARG3}/${UNIQCHAN})}" = "0"]', 'toolate,1'));
            $ext->add($context, $exten, '', new ext_dbdel('RG/${ARG3}/${UNIQCHAN}'));
            $ext->add($context, $exten, '', new ext_dbdel('${BLKVM_OVERRIDE}'));
            $ext->add($context, $exten, '', new ext_setvar('__MACRO_RESULT', ''));
            $ext->add($context, $exten, 'exitopt1', new ext_macroexit());
            $exten = '2';
            $ext->add($context, $exten, '', new ext_goto(1, 'noanswer'));
            $exten = '3';
            $ext->add($context, $exten, '', new ext_saydigits('${CALLCONFIRMCID}'));
            $ext->add($context, $exten, '', new ext_gotoif('$["${DB_EXISTS(RG/${ARG3}/${UNIQCHAN})}" = "0"]', 'toolate,1', 's,start'));
            $exten = 't';
            $ext->add($context, $exten, '', new ext_gotoif('$["${DB_EXISTS(RG/${ARG3}/${UNIQCHAN})}" = "0"]', 'toolate,1'));
            $ext->add($context, $exten, '', new ext_setvar('LOOPCOUNT', '$[ ${LOOPCOUNT} + 1 ]'));
            $ext->add($context, $exten, '', new ext_gotoif('$[ ${LOOPCOUNT} < 5 ]', 's,start', 'noanswer,1'));
            $exten = '_X';
            if ($ast_ge_14) {
                $ext->add($context, $exten, '', new ext_background('invalid,m,${CHANNEL(language)},macro-confirm'));
            } else {
                $ext->add($context, $exten, '', new ext_background('invalid,m,${LANGUAGE},macro-confirm'));
            }
            $ext->add($context, $exten, '', new ext_gotoif('$["${DB_EXISTS(RG/${ARG3}/${UNIQCHAN})}" = "0"]', 'toolate,1'));
            $ext->add($context, $exten, '', new ext_setvar('LOOPCOUNT', '$[ ${LOOPCOUNT} + 1 ]'));
            $ext->add($context, $exten, '', new ext_gotoif('$[ ${LOOPCOUNT} < 5 ]', 's,start', 'noanswer,1'));
            $exten = 'noanswer';
            $ext->add($context, $exten, '', new ext_setvar('__MACRO_RESULT', 'ABORT'));
            $ext->add($context, $exten, 'exitnoanswer', new ext_macroexit());
            $exten = 'toolate';
            $ext->add($context, $exten, '', new ext_setvar('MSG2', '${IF($["foo${ARG2}" != "foo"]?${ARG2}:"incoming-call-no-longer-avail")}'));
            $ext->add($context, $exten, '', new ext_playback('${MSG2}'));
            $ext->add($context, $exten, '', new ext_setvar('__MACRO_RESULT', 'ABORT'));
            $ext->add($context, $exten, 'exittoolate', new ext_macroexit());
            $exten = 'h';
            $ext->add($context, $exten, '', new ext_macro('hangupcall'));
            /*
            ;------------------------------------------------------------------------
            ; [macro-auto-confirm]
            ;------------------------------------------------------------------------
            ; This macro is called from ext-local-confirm to auto-confirm a call so that other extensions
            ; are aware that the call has been answered.
            ;
            ;------------------------------------------------------------------------
            */
            $context = 'macro-auto-confirm';
            $exten = 's';
            $ext->add($context, $exten, '', new ext_setvar('__MACRO_RESULT', ''));
            $ext->add($context, $exten, '', new ext_dbdel('${BLKVM_OVERRIDE}'));
            $ext->add($context, $exten, '', new ext_dbdel('RG/${ARG1}/${UNIQCHAN}'));
            /*
            ;------------------------------------------------------------------------
            ; [macro-auto-blkvm]
            ;------------------------------------------------------------------------
            ; This macro is called for any extension dialed form a queue, ringgroup
            ; or followme, so that the answering extension can clear the voicemail block
            ; override allow subsequent transfers to properly operate.
            ;
            ;------------------------------------------------------------------------
            */
            $context = 'macro-auto-blkvm';
            $exten = 's';
            $ext->add($context, $exten, '', new ext_setvar('__MACRO_RESULT', ''));
            $ext->add($context, $exten, '', new ext_dbdel('${BLKVM_OVERRIDE}'));
            /*
            ;------------------------------------------------------------------------
            ; [sub-pincheck]
            ;------------------------------------------------------------------------
            ; This subroutine checks the pincode and then resets the CDR from that point
            ; if the pincode passes. This way the billsec and duration fields are set
            ; properly for pin dialing.
            ;
            ; ${ARG3} is the pincode if this was called, used by dialout-trunk, dialout-enum
            ; and dialout-dundi
            ;
            ;------------------------------------------------------------------------
            */
            $context = 'sub-pincheck';
            $exten = 's';
            $ext->add($context, $exten, '', new ext_authenticate('${ARG3}'));
            $ext->add($context, $exten, '', new ext_resetcdr(''));
            $ext->add($context, $exten, '', new ext_return(''));
            /*
             * dialout using a trunk, using pattern matching (don't strip any prefix)
             * arg1 = trunk number, arg2 = number, arg3 = route password
             *
             * MODIFIED (PL)
             *
             * Modified both Dial() commands to include the new TRUNK_OPTIONS from the general
             * screen of AMP
             */
            if (function_exists('outroutemsg_get')) {
                $trunkreportmsg_ids = outroutemsg_get();
            } else {
                if (!defined('DEFAULT_MSG')) {
                    define('DEFAULT_MSG', -1);
                }
                if (!defined('CONGESTION_TONE')) {
                    define('CONGESTION_TONE', -2);
                }
                $trunkreportmsg_ids = array('no_answer_msg_id' => -1, 'invalidnmbr_msg_id' => -1, 'unalloc_msg_id' => -1);
            }
            $context = 'macro-dialout-trunk';
            $exten = 's';
            $ext->add($context, $exten, '', new ext_set('DIAL_TRUNK', '${ARG1}'));
            $ext->add($context, $exten, '', new ext_gosubif('$[$["${ARG3}" != ""] & $["${DB(AMPUSER/${AMPUSER}/pinless)}" != "NOPASSWD"]]', 'sub-pincheck,s,1'));
            $ext->add($context, $exten, '', new ext_gotoif('$["x${OUTDISABLE_${DIAL_TRUNK}}" = "xon"]', 'disabletrunk,1'));
            $ext->add($context, $exten, '', new ext_set('DIAL_NUMBER', '${ARG2}'));
            // fixlocalprefix depends on this
            $ext->add($context, $exten, '', new ext_set('DIAL_TRUNK_OPTIONS', '${DIAL_OPTIONS}'));
            // will be reset to TRUNK_OPTIONS if not intra-company
            $ext->add($context, $exten, '', new ext_set('OUTBOUND_GROUP', 'OUT_${DIAL_TRUNK}'));
            $ext->add($context, $exten, '', new ext_gotoif('$["${OUTMAXCHANS_${DIAL_TRUNK}}foo" = "foo"]', 'nomax'));
            $ext->add($context, $exten, '', new ext_gotoif('$[ ${GROUP_COUNT(OUT_${DIAL_TRUNK})} >= ${OUTMAXCHANS_${DIAL_TRUNK}} ]', 'chanfull'));
            $ext->add($context, $exten, 'nomax', new ext_gotoif('$["${INTRACOMPANYROUTE}" = "YES"]', 'skipoutcid'));
            // Set to YES if treated like internal
            $ext->add($context, $exten, '', new ext_set('DIAL_TRUNK_OPTIONS', '${TRUNK_OPTIONS}'));
            $ext->add($context, $exten, '', new ext_macro('outbound-callerid', '${DIAL_TRUNK}'));
            $ext->add($context, $exten, 'skipoutcid', new ext_gosubif('$["${PREFIX_TRUNK_${DIAL_TRUNK}}" != ""]', 'sub-flp-${DIAL_TRUNK},s,1'));
            // this sets DIAL_NUMBER to the proper dial string for this trunk
            $ext->add($context, $exten, '', new ext_set('OUTNUM', '${OUTPREFIX_${DIAL_TRUNK}}${DIAL_NUMBER}'));
            // OUTNUM is the final dial number
            $ext->add($context, $exten, '', new ext_set('custom', '${CUT(OUT_${DIAL_TRUNK},:,1)}'));
            // Custom trunks are prefixed with "AMP:"
            // Back to normal processing, whether intracompany or not.
            // But add the macro-setmusic if we don't want music on this outbound call
            $ext->add($context, $exten, '', new ext_execif('$[$["${MOHCLASS}" != "default"] & $["${MOHCLASS}" != ""]]', 'Set', 'DIAL_TRUNK_OPTIONS=M(setmusic^${MOHCLASS})${DIAL_TRUNK_OPTIONS}'));
            // This macro call will always be blank and is provided as a hook for customization required prior to making a call
            // such as adding SIP header information or other requirements. All the channel variables from above are present
            $ext->add($context, $exten, 'gocall', new ext_macro('dialout-trunk-predial-hook'));
            $ext->add($context, $exten, '', new ext_gotoif('$["${PREDIAL_HOOK_RET}" = "BYPASS"]', 'bypass,1'));
            $ext->add($context, $exten, '', new ext_gotoif('$["${custom}" = "AMP"]', 'customtrunk'));
            $ext->add($context, $exten, '', new ext_dial('${OUT_${DIAL_TRUNK}}/${OUTNUM}', '300,${DIAL_TRUNK_OPTIONS}'));
            // Regular Trunk Dial
            $ext->add($context, $exten, '', new ext_noop('Dial failed for some reason with DIALSTATUS = ${DIALSTATUS} and HANGUPCAUSE = ${HANGUPCAUSE}'));
            $ext->add($context, $exten, '', new ext_goto(1, 's-${DIALSTATUS}'));
            $ext->add($context, $exten, 'customtrunk', new ext_set('pre_num', '${CUT(OUT_${DIAL_TRUNK},$,1)}'));
            $ext->add($context, $exten, '', new ext_set('the_num', '${CUT(OUT_${DIAL_TRUNK},$,2)}'));
            // this is where we expect to find string OUTNUM
            $ext->add($context, $exten, '', new ext_set('post_num', '${CUT(OUT_${DIAL_TRUNK},$,3)}'));
            $ext->add($context, $exten, '', new ext_gotoif('$["${the_num}" = "OUTNUM"]', 'outnum', 'skipoutnum'));
            // if we didn't find "OUTNUM", then skip to Dial
            $ext->add($context, $exten, 'outnum', new ext_set('the_num', '${OUTNUM}'));
            // replace "OUTNUM" with the actual number to dial
            $ext->add($context, $exten, 'skipoutnum', new ext_dial('${pre_num:4}${the_num}${post_num}', '300,${DIAL_TRUNK_OPTIONS}'));
            $ext->add($context, $exten, '', new ext_noop('Dial failed for some reason with DIALSTATUS = ${DIALSTATUS} and HANGUPCAUSE = ${HANGUPCAUSE}'));
            $ext->add($context, $exten, '', new ext_goto(1, 's-${DIALSTATUS}'));
            $ext->add($context, $exten, 'chanfull', new ext_noop('max channels used up'));
            $exten = 's-BUSY';
            /*
             * HANGUPCAUSE 17 = Busy, or SIP 486 Busy everywhere
             */
            $ext->add($context, $exten, '', new ext_noop('Dial failed due to trunk reporting BUSY - giving up'));
            $ext->add($context, $exten, '', new ext_playtones('busy'));
            $ext->add($context, $exten, '', new ext_busy(20));
            /*
             * There are reported bugs in Asterisk Blind Trasfers that result in Dial() returning and continuing
             * execution with a status of ANSWER. So we hangup at this point
             */
            $exten = 's-ANSWER';
            $ext->add($context, $exten, '', new ext_noop('Call successfully answered - Hanging up now'));
            $ext->add($context, $exten, '', new ext_macro('hangupcall'));
            $exten = 's-NOANSWER';
            /*
             * HANGUPCAUSE 18 = No User Responding, or SIP 408 Request Timeout
             * HANGUPCAUSE 19 = No Answer From The User, or SIP 480 Temporarily unavailable, SIP 483 To many hops
             */
            $ext->add($context, $exten, '', new ext_noop('Dial failed due to trunk reporting NOANSWER - giving up'));
            $ext->add($context, $exten, '', new ext_progress());
            switch ($trunkreportmsg_ids['no_answer_msg_id']) {
                case DEFAULT_MSG:
                    $ext->add($context, $exten, '', new ext_playback('number-not-answering,noanswer'));
                    break;
                case CONGESTION_TONE:
                    $ext->add($context, $exten, '', new ext_playtones('congestion'));
                    break;
                default:
                    $message = recordings_get_file($trunkreportmsg_ids['no_answer_msg_id']);
                    $message = $message != "" ? $message : "number-not-answering";
                    $ext->add($context, $exten, '', new ext_playback("{$message}, noanswer"));
            }
            $ext->add($context, $exten, '', new ext_congestion(20));
            $exten = 's-INVALIDNMBR';
            /*
             * HANGUPCAUSE 28 = Address Incomplete, or SIP 484 Address Incomplete
             */
            $ext->add($context, $exten, '', new ext_noop('Dial failed due to trunk reporting Address Incomplete - giving up'));
            $ext->add($context, $exten, '', new ext_progress());
            switch ($trunkreportmsg_ids['invalidnmbr_msg_id']) {
                case DEFAULT_MSG:
                    $ext->add($context, $exten, '', new ext_playback('ss-noservice,noanswer'));
                    break;
                case CONGESTION_TONE:
                    $ext->add($context, $exten, '', new ext_playtones('congestion'));
                    break;
                default:
                    $message = recordings_get_file($trunkreportmsg_ids['invalidnmbr_msg_id']);
                    $message = $message != "" ? $message : "ss-noservice";
                    $ext->add($context, $exten, '', new ext_playback("{$message}, noanswer"));
            }
            $ext->add($context, $exten, '', new ext_busy(20));
            $exten = "s-CHANGED";
            $ext->add($context, $exten, '', new ext_noop('Dial failed due to trunk reporting Number Changed - giving up'));
            $ext->add($context, $exten, '', new ext_playtones('busy'));
            $ext->add($context, $exten, '', new ext_busy(20));
            $exten = '_s-.';
            $ext->add($context, $exten, '', new ext_set('RC', '${IF($[${ISNULL(${HANGUPCAUSE})}]?0:${HANGUPCAUSE})}'));
            $ext->add($context, $exten, '', new ext_goto('1', '${RC}'));
            $ext->add($context, '17', '', new ext_goto('1', 's-BUSY'));
            $ext->add($context, '18', '', new ext_goto('1', 's-NOANSWER'));
            $ext->add($context, '22', '', new ext_goto('1', 's-CHANGED'));
            $ext->add($context, '23', '', new ext_goto('1', 's-CHANGED'));
            $ext->add($context, '28', '', new ext_goto('1', 's-INVALIDNMBR'));
            $ext->add($context, '_X', '', new ext_goto('1', 'continue'));
            $ext->add($context, '_X.', '', new ext_goto('1', 'continue'));
            $exten = 'continue';
            $ext->add($context, $exten, '', new ext_gotoif('$["${OUTFAIL_${ARG1}}" = ""]', 'noreport'));
            $ext->add($context, $exten, '', new ext_agi('${OUTFAIL_${ARG1}}'));
            $ext->add($context, $exten, 'noreport', new ext_noop('TRUNK Dial failed due to ${DIALSTATUS} HANGUPCAUSE: ${HANGUPCAUSE} - failing through to other trunks'));
            $ext->add($context, $exten, '', new ext_set('CALLERID(number)', '${AMPUSER}'));
            $ext->add($context, 'disabletrunk', '', new ext_noop('TRUNK: ${OUT_${DIAL_TRUNK}} DISABLED - falling through to next trunk'));
            $ext->add($context, 'bypass', '', new ext_noop('TRUNK: ${OUT_${DIAL_TRUNK}} BYPASSING because dialout-trunk-predial-hook'));
            $ext->add($context, 'h', '', new ext_macro('hangupcall'));
            $context = 'macro-dialout-dundi';
            $exten = 's';
            /*
             * Dialout Dundi Trunk
             */
            $ext->add($context, $exten, '', new ext_set('DIAL_TRUNK', '${ARG1}'));
            $ext->add($context, $exten, '', new ext_gosubif('$[$["${ARG3}" != ""] & $["${DB(AMPUSER/${AMPUSER}/pinless)}" != "NOPASSWD"]]', 'sub-pincheck,s,1'));
            $ext->add($context, $exten, '', new ext_gotoif('$["x${OUTDISABLE_${DIAL_TRUNK}}" = "xon"]', 'disabletrunk,1'));
            $ext->add($context, $exten, '', new ext_set('DIAL_NUMBER', '${ARG2}'));
            // fixlocalprefix depends on this
            $ext->add($context, $exten, '', new ext_set('DIAL_TRUNK_OPTIONS', '${DIAL_OPTIONS}'));
            // will be reset to TRUNK_OPTIONS if not intra-company
            $ext->add($context, $exten, '', new ext_set('OUTBOUND_GROUP', 'OUT_${DIAL_TRUNK}'));
            $ext->add($context, $exten, '', new ext_gotoif('$["${OUTMAXCHANS_${DIAL_TRUNK}}foo" = "foo"]', 'nomax'));
            $ext->add($context, $exten, '', new ext_gotoif('$[ ${GROUP_COUNT(OUT_${DIAL_TRUNK})} >= ${OUTMAXCHANS_${DIAL_TRUNK}} ]', 'chanfull'));
            $ext->add($context, $exten, 'nomax', new ext_gotoif('$["${INTRACOMPANYROUTE}" = "YES"]', 'skipoutcid'));
            // Set to YES if treated like internal
            $ext->add($context, $exten, '', new ext_set('DIAL_TRUNK_OPTIONS', '${TRUNK_OPTIONS}'));
            $ext->add($context, $exten, '', new ext_macro('outbound-callerid', '${DIAL_TRUNK}'));
            $ext->add($context, $exten, 'skipoutcid', new ext_gosubif('$["${PREFIX_TRUNK_${DIAL_TRUNK}}" != ""]', 'sub-flp-${DIAL_TRUNK},s,1'));
            // manipulate DIAL_NUMBER
            $ext->add($context, $exten, '', new ext_set('OUTNUM', '${OUTPREFIX_${DIAL_TRUNK}}${DIAL_NUMBER}'));
            // OUTNUM is the final dial number
            // Back to normal processing, whether intracompany or not.
            // But add the macro-setmusic if we don't want music on this outbound call
            $ext->add($context, $exten, '', new ext_execif('$[$["${MOHCLASS}" != "default"] & $["${MOHCLASS}" != ""]]', 'Set', 'DIAL_TRUNK_OPTIONS=M(setmusic^${MOHCLASS})${DIAL_TRUNK_OPTIONS}'));
            // This macro call will always be blank and is provided as a hook for customization required prior to making a call
            // such as adding SIP header information or other requirements. All the channel variables from above are present
            $ext->add($context, $exten, 'gocall', new ext_macro('dialout-dundi-predial-hook'));
            $ext->add($context, $exten, '', new ext_gotoif('$["${PREDIAL_HOOK_RET}" = "BYPASS"]', 'bypass,1'));
            $ext->add($context, $exten, '', new ext_macro('dundi-${DIAL_TRUNK}', '${OUTNUM}'));
            $ext->add($context, $exten, '', new ext_goto(1, 's-${DIALSTATUS}'));
            $ext->add($context, $exten, 'chanfull', new ext_noop('max channels used up'));
            $exten = 's-BUSY';
            /*
             * HANGUPCAUSE 17 = Busy, or SIP 486 Busy everywhere
             */
            $ext->add($context, $exten, '', new ext_noop('Dial failed due to trunk reporting BUSY - giving up'));
            $ext->add($context, $exten, '', new ext_playtones('busy'));
            $ext->add($context, $exten, '', new ext_busy(20));
            /*
             * There are reported bugs in Asterisk Blind Trasfers that result in Dial() returning and continuing
             * execution with a status of ANSWER. So we hangup at this point
             */
            $exten = 's-ANSWER';
            $ext->add($context, $exten, '', new ext_noop('Call successfully answered - Hanging up now'));
            $ext->add($context, $exten, '', new ext_macro('hangupcall'));
            $exten = 's-NOANSWER';
            /*
             * HANGUPCAUSE 18 = No User Responding, or SIP 408 Request Timeout
             * HANGUPCAUSE 19 = No Answer From The User, or SIP 480 Temporarily unavailable, SIP 483 To many hops
             */
            $ext->add($context, $exten, '', new ext_noop('Dial failed due to trunk reporting NOANSWER - giving up'));
            $ext->add($context, $exten, '', new ext_progress());
            switch ($trunkreportmsg_ids['no_answer_msg_id']) {
                case DEFAULT_MSG:
                    $ext->add($context, $exten, '', new ext_playback('number-not-answering,noanswer'));
                    break;
                case CONGESTION_TONE:
                    $ext->add($context, $exten, '', new ext_playtones('congestion'));
                    break;
                default:
                    $message = recordings_get_file($trunkreportmsg_ids['no_answer_msg_id']);
                    $message = $message != "" ? $message : "number-not-answering";
                    $ext->add($context, $exten, '', new ext_playback("{$message}, noanswer"));
            }
            $ext->add($context, $exten, '', new ext_congestion(20));
            $exten = 's-INVALIDNMBR';
            /*
             * HANGUPCAUSE 28 = Address Incomplete, or SIP 484 Address Incomplete
             */
            $ext->add($context, $exten, '', new ext_noop('Dial failed due to trunk reporting Address Incomplete - giving up'));
            $ext->add($context, $exten, '', new ext_progress());
            switch ($trunkreportmsg_ids['invalidnmbr_msg_id']) {
                case DEFAULT_MSG:
                    $ext->add($context, $exten, '', new ext_playback('ss-noservice,noanswer'));
                    break;
                case CONGESTION_TONE:
                    $ext->add($context, $exten, '', new ext_playtones('congestion'));
                    break;
                default:
                    $message = recordings_get_file($trunkreportmsg_ids['invalidnmbr_msg_id']);
                    $message = $message != "" ? $message : "ss-noservice";
                    $ext->add($context, $exten, '', new ext_playback("{$message}, noanswer"));
            }
            $ext->add($context, $exten, '', new ext_busy(20));
            $exten = "s-CHANGED";
            $ext->add($context, $exten, '', new ext_noop('Dial failed due to trunk reporting Number Changed - giving up'));
            $ext->add($context, $exten, '', new ext_playtones('busy'));
            $ext->add($context, $exten, '', new ext_busy(20));
            $exten = '_s-.';
            $ext->add($context, $exten, '', new ext_set('RC', '${IF($[${ISNULL(${HANGUPCAUSE})}]?0:${HANGUPCAUSE})}'));
            $ext->add($context, $exten, '', new ext_goto('1', '${RC}'));
            $ext->add($context, '17', '', new ext_goto('1', 's-BUSY'));
            $ext->add($context, '18', '', new ext_goto('1', 's-NOANSWER'));
            $ext->add($context, '22', '', new ext_goto('1', 's-CHANGED'));
            $ext->add($context, '23', '', new ext_goto('1', 's-CHANGED'));
            $ext->add($context, '28', '', new ext_goto('1', 's-INVALIDNMBR'));
            $ext->add($context, '_X', '', new ext_goto('1', 'continue'));
            $ext->add($context, '_X.', '', new ext_goto('1', 'continue'));
            $exten = 'continue';
            $ext->add($context, $exten, '', new ext_gotoif('$["${OUTFAIL_${ARG1}}" = ""]', 'noreport'));
            $ext->add($context, $exten, '', new ext_agi('${OUTFAIL_${ARG1}}'));
            $ext->add($context, $exten, 'noreport', new ext_noop('TRUNK Dial failed due to ${DIALSTATUS} HANGUPCAUSE: ${HANGUPCAUSE} - failing through to other trunks'));
            $ext->add($context, $exten, '', new ext_set('CALLERID(number)', '${AMPUSER}'));
            $ext->add($context, 'disabletrunk', '', new ext_noop('TRUNK: ${OUT_${DIAL_TRUNK}} DISABLED - falling through to next trunk'));
            $ext->add($context, 'bypass', '', new ext_noop('TRUNK: ${OUT_${DIAL_TRUNK}} BYPASSING because dialout-dundi-predial-hook'));
            $ext->add($context, 'h', '', new ext_macro('hangupcall'));
            /*
             * sets the callerid of the device to that of the logged in user
             *
             * ${AMPUSER} is set upon return to the real user despite any aliasing that may
             * have been set as a result of the AMPUSER/<nnn>/cidnum field. This is used by
             * features like DND, CF, etc. to set the proper structure on aliased instructions 
             */
            $context = 'macro-user-callerid';
            $exten = 's';
            //$ext->add($context, $exten, '', new ext_noop('user-callerid: ${CALLERID(name)} ${CALLERID(number)}'));
            // make sure AMPUSER is set if it doesn't get set below
            $ext->add($context, $exten, '', new ext_set('AMPUSER', '${IF($["foo${AMPUSER}" = "foo"]?${CALLERID(number)}:${AMPUSER})}'));
            $ext->add($context, $exten, '', new ext_gotoif('$["${CHANNEL:0:5}" = "Local"]', 'report'));
            $ext->add($context, $exten, '', new ext_execif('$["${REALCALLERIDNUM:1:2}" = ""]', 'Set', 'REALCALLERIDNUM=${CALLERID(number)}'));
            //$ext->add($context, $exten, 'start', new ext_noop('REALCALLERIDNUM is ${REALCALLERIDNUM}'));
            $ext->add($context, $exten, '', new ext_set('AMPUSER', '${DB(DEVICE/${REALCALLERIDNUM}/user)}'));
            $ext->add($context, $exten, '', new ext_set('AMPUSERCIDNAME', '${DB(AMPUSER/${AMPUSER}/cidname)}'));
            $ext->add($context, $exten, '', new ext_gotoif('$["x${AMPUSERCIDNAME:1:2}" = "x"]', 'report'));
            // user may masquerade as a different user internally, so set the internal cid as indicated
            // but keep the REALCALLERID which is used to determine their true identify and lookup info
            // during outbound calls.
            $ext->add($context, $exten, '', new ext_set('AMPUSERCID', '${IF($["${DB_EXISTS(AMPUSER/${AMPUSER}/cidnum)}" = "1"]?${DB_RESULT}:${AMPUSER})}'));
            $ext->add($context, $exten, '', new ext_set('CALLERID(all)', '"${AMPUSERCIDNAME}" <${AMPUSERCID}>'));
            /*
             * This is where to splice in things like setting the language based on a user's astdb setting,
             * or where you might set the CID account code based on a user instead of the device settings.
             */
            $ext->add($context, $exten, 'report', new ext_gotoif('$[ "${ARG1}" = "SKIPTTL" ]', 'continue'));
            $ext->add($context, $exten, 'report2', new ext_set('__TTL', '${IF($["foo${TTL}" = "foo"]?64:$[ ${TTL} - 1 ])}'));
            $ext->add($context, $exten, '', new ext_gotoif('$[ ${TTL} > 0 ]', 'continue'));
            $ext->add($context, $exten, '', new ext_wait('${RINGTIMER}'));
            // wait for a while, to give it a chance to be picked up by voicemail
            $ext->add($context, $exten, '', new ext_answer());
            $ext->add($context, $exten, '', new ext_wait('2'));
            $ext->add($context, $exten, '', new ext_playback('im-sorry&an-error-has-occured&with&call-forwarding'));
            $ext->add($context, $exten, '', new ext_macro('hangupcall'));
            $ext->add($context, $exten, '', new ext_congestion(20));
            // Address Security Vulnerability in many earlier versions of Asterisk from an external source tranmitting a
            // malicious CID that can cause overflows in the Asterisk code.
            //
            $ext->add($context, $exten, 'continue', new ext_set('CALLERID(number)', '${CALLERID(number):0:40}'));
            $ext->add($context, $exten, '', new ext_set('CALLERID(name)', '${CALLERID(name):0:40}'));
            $ext->add($context, $exten, '', new ext_noop('Using CallerID ${CALLERID(all)}'));
            $ext->add($context, 'h', '', new ext_macro('hangupcall'));
            /*
             * arg1 = trunk number, arg2 = number
             * 
             * Re-written to use enumlookup.agi
             */
            // Is this the best place to put it in?
            // Check if we are using Google DNS for ENUM-lookups,
            // enable it as a global variable so we can use it in the agi
            if ($amp_conf['USEGOOGLEDNSFORENUM']) {
                $ext->addGlobal('ENUMUSEGOOGLEDNS', 'TRUE');
            }
            $context = 'macro-dialout-enum';
            $exten = 's';
            $ext->add($context, $exten, '', new ext_gosubif('$[$["${ARG3}" != ""] & $["${DB(AMPUSER/${AMPUSER}/pinless)}" != "NOPASSWD"]]', 'sub-pincheck,s,1'));
            $ext->add($context, $exten, '', new ext_macro('outbound-callerid', '${ARG1}'));
            $ext->add($context, $exten, '', new ext_set('OUTBOUND_GROUP', 'OUT_${ARG1}'));
            $ext->add($context, $exten, '', new ext_gotoif('$["${OUTMAXCHANS_${ARG1}}foo" = "foo"]', 'nomax'));
            $ext->add($context, $exten, '', new ext_gotoif('$[ ${GROUP_COUNT(OUT_${ARG1})} >= ${OUTMAXCHANS_${ARG1}} ]', 'nochans'));
            $ext->add($context, $exten, 'nomax', new ext_set('DIAL_NUMBER', '${ARG2}'));
            $ext->add($context, $exten, '', new ext_set('DIAL_TRUNK', '${ARG1}'));
            $ext->add($context, $exten, '', new ext_gosubif('$["${PREFIX_TRUNK_${DIAL_TRUNK}}" != ""]', 'sub-flp-${DIAL_TRUNK},s,1'));
            // manimpulate DIAL_NUMBER
            //  Replacement for asterisk's ENUMLOOKUP function
            $ext->add($context, $exten, '', new ext_agi('enumlookup.agi'));
            // Now we have the variable DIALARR set to a list of URI's that can be called, in order of priority
            // Loop through them trying them in order.
            $ext->add($context, $exten, 'dialloop', new ext_gotoif('$["foo${DIALARR}"="foo"]', 's-${DIALSTATUS},1'));
            $ext->add($context, $exten, '', new ext_set('TRYDIAL', '${CUT(DIALARR,%,1)}'));
            $ext->add($context, $exten, '', new ext_set('DIALARR', '${CUT(DIALARR,%,2-)}'));
            $ext->add($context, $exten, '', new ext_dial('${TRYDIAL}', ''));
            // Now, if we're still here, that means the Dial failed for some reason.
            // If it's CONGESTION or CHANUNAVAIL we want to try again on a different
            // different channel. If there's no more left, the dialloop tag will exit.
            $ext->add($context, $exten, '', new ext_gotoif('$[ $[ "${DIALSTATUS}" = "CHANUNAVAIL" ] | $[ "${DIALSTATUS}" = "CONGESTION" ] ]', 'dialloop', 's-${DIALSTATUS},1'));
            // Here are the exit points for the macro.
            $ext->add($context, $exten, 'nochans', new ext_noop('max channels used up'));
            $exten = 's-BUSY';
            /*
             * HANGUPCAUSE 17 = Busy, or SIP 486 Busy everywhere
             */
            $ext->add($context, $exten, '', new ext_noop('Dial failed due to trunk reporting BUSY - giving up'));
            $ext->add($context, $exten, '', new ext_playtones('busy'));
            $ext->add($context, $exten, '', new ext_busy(20));
            /*
             * There are reported bugs in Asterisk Blind Trasfers that result in Dial() returning and continuing
             * execution with a status of ANSWER. So we hangup at this point
             */
            $exten = 's-ANSWER';
            $ext->add($context, $exten, '', new ext_noop('Call successfully answered - Hanging up now'));
            $ext->add($context, $exten, '', new ext_macro('hangupcall'));
            $exten = 's-NOANSWER';
            /*
             * HANGUPCAUSE 18 = No User Responding, or SIP 408 Request Timeout
             * HANGUPCAUSE 19 = No Answer From The User, or SIP 480 Temporarily unavailable, SIP 483 To many hops
             */
            $ext->add($context, $exten, '', new ext_noop('Dial failed due to trunk reporting NOANSWER - giving up'));
            $ext->add($context, $exten, '', new ext_progress());
            switch ($trunkreportmsg_ids['no_answer_msg_id']) {
                case DEFAULT_MSG:
                    $ext->add($context, $exten, '', new ext_playback('number-not-answering,noanswer'));
                    break;
                case CONGESTION_TONE:
                    $ext->add($context, $exten, '', new ext_playtones('congestion'));
                    break;
                default:
                    $message = recordings_get_file($trunkreportmsg_ids['no_answer_msg_id']);
                    $message = $message != "" ? $message : "number-not-answering";
                    $ext->add($context, $exten, '', new ext_playback("{$message}, noanswer"));
            }
            $ext->add($context, $exten, '', new ext_congestion(20));
            $exten = 's-INVALIDNMBR';
            /*
             * HANGUPCAUSE 28 = Address Incomplete, or SIP 484 Address Incomplete
             */
            $ext->add($context, $exten, '', new ext_noop('Dial failed due to trunk reporting Address Incomplete - giving up'));
            $ext->add($context, $exten, '', new ext_progress());
            switch ($trunkreportmsg_ids['invalidnmbr_msg_id']) {
                case DEFAULT_MSG:
                    $ext->add($context, $exten, '', new ext_playback('ss-noservice,noanswer'));
                    break;
                case CONGESTION_TONE:
                    $ext->add($context, $exten, '', new ext_playtones('congestion'));
                    break;
                default:
                    $message = recordings_get_file($trunkreportmsg_ids['invalidnmbr_msg_id']);
                    $message = $message != "" ? $message : "ss-noservice";
                    $ext->add($context, $exten, '', new ext_playback("{$message}, noanswer"));
            }
            $ext->add($context, $exten, '', new ext_busy(20));
            $exten = "s-CHANGED";
            $ext->add($context, $exten, '', new ext_noop('Dial failed due to trunk reporting Number Changed - giving up'));
            $ext->add($context, $exten, '', new ext_playtones('busy'));
            $ext->add($context, $exten, '', new ext_busy(20));
            $exten = '_s-.';
            $ext->add($context, $exten, '', new ext_set('RC', '${IF($[${ISNULL(${HANGUPCAUSE})}]?0:${HANGUPCAUSE})}'));
            $ext->add($context, $exten, '', new ext_goto('1', '${RC}'));
            $ext->add($context, '17', '', new ext_goto('1', 's-BUSY'));
            $ext->add($context, '18', '', new ext_goto('1', 's-NOANSWER'));
            $ext->add($context, '22', '', new ext_goto('1', 's-CHANGED'));
            $ext->add($context, '23', '', new ext_goto('1', 's-CHANGED'));
            $ext->add($context, '28', '', new ext_goto('1', 's-INVALIDNMBR'));
            $ext->add($context, '_X', '', new ext_goto('1', 'continue'));
            $ext->add($context, '_X.', '', new ext_goto('1', 'continue'));
            $exten = 'continue';
            $ext->add($context, $exten, '', new ext_gotoif('$["${OUTFAIL_${ARG1}}" = ""]', 'noreport'));
            $ext->add($context, $exten, '', new ext_agi('${OUTFAIL_${ARG1}}'));
            $ext->add($context, $exten, 'noreport', new ext_noop('TRUNK Dial failed due to ${DIALSTATUS} HANGUPCAUSE: ${HANGUPCAUSE} - failing through to other trunks'));
            $ext->add($context, $exten, '', new ext_set('CALLERID(number)', '${AMPUSER}'));
            $ext->add($context, 'disabletrunk', '', new ext_noop('TRUNK: ${OUT_${DIAL_TRUNK}} DISABLED - falling through to next trunk'));
            $ext->add($context, 'bypass', '', new ext_noop('TRUNK: ${OUT_${DIAL_TRUNK}} BYPASSING because dialout-trunk-predial-hook'));
            $ext->add($context, 'h', '', new ext_macro('hangupcall'));
            /*
             * overrides callerid out trunks
             * arg1 is trunk
             * macro-user-callerid should be called _before_ using this macro
             */
            $context = 'macro-outbound-callerid';
            $exten = 's';
            // If we modified the caller presence, set it back. This allows anonymous calls to be internally prepended but keep
            // their status if forwarded back out. Not doing this can result in the trunk CID being displayed vs. 'blocked call'
            //
            if ($ast_lt_16) {
                $ext->add($context, $exten, '', new ext_execif('$["${CALLINGPRES_SV}" != ""]', 'SetCallerPres', '${CALLINGPRES_SV}'));
            } else {
                $ext->add($context, $exten, '', new ext_execif('$["${CALLINGPRES_SV}" != ""]', 'Set', 'CALLERPRES()=${CALLINGPRES_SV}'));
            }
            // Keep the original CallerID number, for failover to the next trunk.
            $ext->add($context, $exten, '', new ext_execif('$["${REALCALLERIDNUM:1:2}" = ""]', 'Set', 'REALCALLERIDNUM=${CALLERID(number)}'));
            // If this came through a ringgroup or CF, then we want to retain original CID unless
            // OUTKEEPCID_${trunknum} is set.
            // Save then CIDNAME while it is still intact in case we end up sending out this same CID
            $ext->add($context, $exten, 'start', new ext_gotoif('$[ $["${REALCALLERIDNUM}" = ""] | $["${KEEPCID}" != "TRUE"] | $["${OUTKEEPCID_${ARG1}}" = "on"] ]', 'normcid'));
            // Set to TRUE if coming from ringgroups, CF, etc.
            $ext->add($context, $exten, '', new ext_set('USEROUTCID', '${REALCALLERIDNUM}'));
            //$ext->add($context, $exten, '', new ext_set('REALCALLERIDNAME', '${CALLERID(name)}'));
            // We now have to make sure the CID is valid. If we find an AMPUSER with the same CID, we assume it is an internal
            // call (would be quite a conincidence if not) and go through the normal processing to get that CID. If a device
            // is set for this CID, then it must be internal
            // If we end up using USEROUTCID at the end, it may still be the REALCALLERIDNUM we saved above. That is determined
            // if the two are equal, AND there is no CALLERID(name) present since it has been removed by the CALLERID(all)=${USEROUTCID}
            // setting. If this is the case, then we put the orignal name back in to send out. Although the CNAME is not honored by most
            // carriers, there are cases where it is so this preserves that information to be used by those carriers who do honor it.
            $ext->add($context, $exten, '', new ext_gotoif('$["foo${DB(AMPUSER/${REALCALLERIDNUM}/device)}" = "foo"]', 'bypass'));
            $ext->add($context, $exten, 'normcid', new ext_set('USEROUTCID', '${DB(AMPUSER/${AMPUSER}/outboundcid)}'));
            $ext->add($context, $exten, 'bypass', new ext_set('EMERGENCYCID', '${DB(DEVICE/${REALCALLERIDNUM}/emergency_cid)}'));
            $ext->add($context, $exten, '', new ext_set('TRUNKOUTCID', '${OUTCID_${ARG1}}'));
            $ext->add($context, $exten, '', new ext_gotoif('$["${EMERGENCYROUTE:1:2}" = "" | "${EMERGENCYCID:1:2}" = ""]', 'trunkcid'));
            // check EMERGENCY ROUTE
            $ext->add($context, $exten, '', new ext_set('CALLERID(all)', '${EMERGENCYCID}'));
            // emergency cid for device
            $ext->add($context, $exten, 'exit', new ext_macroexit());
            $ext->add($context, $exten, 'trunkcid', new ext_execif('$[${LEN(${TRUNKOUTCID})} != 0]', 'Set', 'CALLERID(all)=${TRUNKOUTCID}'));
            $ext->add($context, $exten, 'usercid', new ext_execif('$[${LEN(${USEROUTCID})} != 0]', 'Set', 'CALLERID(all)=${USEROUTCID}'));
            // check CID override for extension
            /* TRUNKCIDOVERRIDE is used by followme and can be used by other functions. It forces the specified CID except for the case of 
             * an Emergency CID on an Emergency Route
             */
            $ext->add($context, $exten, '', new ext_execif('$[${LEN(${TRUNKCIDOVERRIDE})} != 0 | ${LEN(${FORCEDOUTCID_${ARG1}})} != 0]', 'Set', 'CALLERID(all)=${IF($[${LEN(${FORCEDOUTCID_${ARG1}})}=0]?${TRUNKCIDOVERRIDE}:${FORCEDOUTCID_${ARG1}})}'));
            if ($ast_lt_16) {
                $ext->add($context, $exten, 'hidecid', new ext_execif('$["${CALLERID(name)}"="hidden"]', 'SetCallerPres', 'prohib_passed_screen'));
            } else {
                $ext->add($context, $exten, 'hidecid', new ext_execif('$["${CALLERID(name)}"="hidden"]', 'Set', 'CALLERPRES()=prohib_passed_screen'));
            }
            // $has_keepcid_cnum is checked and set when the globals are being generated above
            //
            if ($has_keepcid_cnum) {
                $ext->add($context, $exten, '', new ext_execif('$["${OUTKEEPCID_${ARG1}}" = "cnum"]', 'Set', 'CALLERID(name)='));
            }
            // Combined from-zpatel / from-dahdi and all macros now from-dahdi-channum
            //
            $ext->addInclude('from-zaptel', 'from-dahdi');
            $ext->add('from-zaptel', 'foo', '', new ext_noop('bar'));
            $context = 'from-dahdi';
            $exten = '_X.';
            $ext->add($context, $exten, '', new ext_set('DID', '${EXTEN}'));
            $ext->add($context, $exten, '', new ext_goto(1, 's'));
            $exten = 's';
            $ext->add($context, $exten, '', new ext_noop('Entering from-dahdi with DID == ${DID}'));
            // Some trunks _require_ a RINGING be sent before an Answer.
            $ext->add($context, $exten, '', new ext_ringing());
            // If ($did == "") { $did = "s"; }
            $ext->add($context, $exten, '', new ext_set('DID', '${IF($["${DID}"= ""]?s:${DID})}'));
            $ext->add($context, $exten, '', new ext_noop('DID is now ${DID}'));
            $ext->add($context, $exten, '', new ext_gotoif('$["${CHANNEL:0:5}"="DAHDI"]', 'dahdiok', 'checkzap'));
            $ext->add($context, $exten, 'checkzap', new ext_gotoif('$["${CHANNEL:0:3}"="Zap"]', 'zapok', 'neither'));
            $ext->add($context, $exten, 'neither', new ext_goto('1', '${DID}', 'from-pstn'));
            // If there's no ext-did,s,1, that means there's not a no did/no cid route. Hangup.
            $ext->add($context, $exten, '', new ext_macro('Hangupcall', 'dummy'));
            $ext->add($context, $exten, 'dahdiok', new ext_noop('Is a DAHDI Channel'));
            $ext->add($context, $exten, '', new ext_set('CHAN', '${CHANNEL:6}'));
            $ext->add($context, $exten, '', new ext_set('CHAN', '${CUT(CHAN,-,1)}'));
            $ext->add($context, $exten, '', new ext_macro('from-dahdi-${CHAN}', '${DID},1'));
            // If nothing there, then treat it as a DID
            $ext->add($context, $exten, '', new ext_noop('Returned from Macro from-dahdi-${CHAN}'));
            $ext->add($context, $exten, '', new ext_goto(1, '${DID}', 'from-pstn'));
            $ext->add($context, $exten, 'zapok', new ext_noop('Is a Zaptel Channel'));
            $ext->add($context, $exten, '', new ext_set('CHAN', '${CHANNEL:4}'));
            $ext->add($context, $exten, '', new ext_set('CHAN', '${CUT(CHAN,-,1)}'));
            $ext->add($context, $exten, '', new ext_macro('from-dahdi-${CHAN}', '${DID},1'));
            $ext->add($context, $exten, '', new ext_noop('Returned from Macro from-dahdi-${CHAN}'));
            $ext->add($context, $exten, '', new ext_goto(1, '${DID}', 'from-pstn'));
            /*
             * vm-callme context plays voicemail over telephone for web click-to-call
             * MSG and MBOX are channel variables that must be set when originating the call
             */
            $context = 'vm-callme';
            $ext->add($context, 's', '', new ext_answer());
            $ext->add($context, 's', '', new ext_wait(1));
            $ext->add($context, 's', 'repeat', new ext_background('${MSG}&silence/2&vm-repeat&vm-starmain'));
            $ext->add($context, 's', '', new ext_waitexten(15));
            $ext->add($context, '5', '', new ext_goto('repeat', 's'));
            $ext->add($context, '#', '', new ext_playback('vm-goodbye'));
            $ext->add($context, '#', '', new ext_hangup());
            $ext->add($context, '*', '', new ext_macro('get-vmcontext', '${MBOX}'));
            $ext->add($context, '*', '', new ext_vmmain('${MBOX}@${VMCONTEXT},s'));
            $ext->add($context, 'i', '', new ext_playback('pm-invalid-option'));
            $ext->add($context, 'i', '', new ext_goto('repeat', 's'));
            $ext->add($context, 't', '', new ext_playback('vm-goodbye'));
            $ext->add($context, 't', '', new ext_hangup());
            $ext->add($context, 'h', '', new ext_hangup());
            /* end vm-callme context  */
            /*
             * macro-vm 
             */
            /*
                                    ;------------------------------------------------------------------------
                                    ; [macro-vm]
                                    ;------------------------------------------------------------------------
                                    ; CONTEXT:      macro-vm
                                    ; PURPOSE:      call voicemail system and extend with personal ivr
                                    ;
                                    ; Under normal use, this macro will call the voicemail system with the extension and
                                    ; desired greeting mode of busy, unavailable or as specified with direct voicemail
                                    ; calls (usually unavailable) when entered from destinations.
                                    ;
                                    ; The voicemail system's two greetings have been 'hijacked' as follows to extend the
                                    ; system by giving the option of a private 'ivr' for each voicemail user. The following
                                    ; applies to both the busy and unavailable modes of voicemail and can be applied to one
                                    ; or both, and differently.
                                    ;
                                    ; Global Defaults:
                                    ;
                                    ; The following are default values, used in both busy and unavail modes if no specific
                                    ; values are specified.
                                    ;
                                    ; VMX_REPEAT
                                    ;                                       The number of times to repeat the users message if no option is pressed.
                                    ; VMX_TIMEOUT
                                    ;                                       The timeout to wait after playing message before repeating or giving up.
                                    ; VMX_LOOPS
                                    ;                                       The number of times it should replay the message and check for an option when
                                    ;                                       an invalid option is pressed.
                                    ;
                                    ; VMX_OPTS_DOVM
                                    ;                                       Default voicemail option to use if vm is chosen as an option. No options will
                                    ;                                       cause Allison's generic message, 's' will go straight to beep.
                                    ; VMX_OPTS_TIMEOUT
                                    ;                                       Default voicemail option to use if it times out with no options. No options will
                                    ;                                       cause Allison's generic message, 's' will go straight to beep.
                                    ;                                       IF THE USER PRESSES # - it will look like a timeout as well since no option will
                                    ;                                       be presented. If the user wishes to enable a mode where a caller can press #
                                    ;                                       during their message and it goes straight to voicemail with only a 'beep' then
                                    ;                                       this should be set to 's'.
                                    ; VMX_OPTS_LOOPS
                                    ;                                       Default voicemail option to use if to many wrong options occur. No options will
                                    ;                                       cause Allison's generic message, 's' will go straight to beep.
                                    ;
                                    ; VMX_CONTEXT
                                    ;                                       Default context for user destinations if not supplied in the user's settings
                                    ; VMX_PRI
                                    ;                                       Default priority for user destinations if not supplied in the user's settings
                                    ;
                                    ; VMX_TIMEDEST_CONTEXT
                                    ;                                       Default context for timeout destination if not supplied in the user's settings
                                    ; VMX_TIMEDEST_EXT
                                    ;                                       Default extension for timeout destination if not supplied in the user's settings
                                    ; VMX_TIMEDEST_PRI
                                    ;                                       Default priority for timeout destination if not supplied in the user's settings
                                    ;
                                    ; VMX_LOOPDEST_CONTEXT
                                    ;                                       Default context for loops  destination if not supplied in the user's settings
                                    ; VMX_LOOPDEST_EXT
                                    ;                                       Default extension for loops  destination if not supplied in the user's settings
                                    ; VMX_LOOPDEST_PRI
                                    ;                                       Default priority for loops  destination if not supplied in the user's settings
                                    ;
                                    ;
                                    ; The AMPUSER database variable has been extended with a 'vmx' tree (vm-extension). A
                                    ; duplicate set is included for both unavail and busy. You could choose for to have an
                                    ; ivr when unavail is taken, but not with busy - or a different once with busy.
                                    ; The full list is below, each specific entry is futher described:
                                    ;
                                    ; state:                Whether teh current mode is enabled or disabled. Anything but 'enabled' is
                                    ;                                               treated as disabled.
                                    ; repeat:               This is the number of times that the users message should be played after the
                                    ;                                               timeout if the user has not entered anything. It is just a variable to the
                                    ;                                               Read() function which will do the repeating.
                                    ; timeout:      This is how long to wait after the message has been read for a response from
                                    ;                                               the user. A caller can enter a digit any time during the playback.
                                    ; loops:                This is the number of loops that the system will allow a caller to retry if
                                    ;                                               they enter a bad menu choice, before going to the loop failover destination
                                    ; vmxopts:      This is the vm options to send to the voicemail command used when a specific
                                    ;                                               voicemail destination is chosen (inidcated by 'dovm' in the ext field). This is
                                    ;                                               typically either set to 's' or left blank. When set to 's' there will be no
                                    ;                                               message played when entering the voicemail, just a beep. When blank, you will
                                    ;                                               have Allison's generic message played. It is not typical to play the greetings
                                    ;                                               since they have been 'hijacked' for these IVR's and from a caller's perspecitive
                                    ;                                               this system appears interconnected with the voicemail so instructions can be
                                    ;                                               left there.
                                    ; timedest: The three variables: ext, context and pri are the goto destination if the caller
                                    ;                                               enters no options and it timesout. None have to be set and a system default
                                    ;                                               will be used. If just ext is set, then defaults will be used for context and
                                    ;                                               pri, etc.
                                    ; loopdest:     This is identical to timedest but used if the caller exceeds the maximum invalid
                                    ;                                               menu choices.
                                    ; [0-9*]:               The user can specify up to 11 ivr options, all as single digits from 0-9 or *. The
                                    ;                                               # key can not be used since it is used as a terminator key for the Read command
                                    ;                                               and will never be returned. A minimum of the ext must be specified for each valid
                                    ;                                               option and as above, the context and priority can also be specified if the default
                                    ;                                               is not to be used.
                                    ;                                               Option '0' takes on a special meaning. Since a user is able to break out of the
                                    ;                                               voicemail command once entering it with a 0, if specified, the 0 destination will
                                    ;                                               be used.
                                    ;                                               Option '*' can also be used to breakout. It is undecided at this point whether
                                    ;                                               providing that option will be used as well. (probably should).
                                    ;
                                    ;
                                    ; /AMPUSER/<ext>/vmx/[busy|unavail]/state:                                                              enabled|disabled
                                    ; /AMPUSER/<ext>/vmx/[busy|unavail]/repeat:                                                             n (times to repeat message)
                                    ; /AMPUSER/<ext>/vmx/[busy|unavail]/timeout:                                                    n (timeout to wait for digit)
                                    ; /AMPUSER/<ext>/vmx/[busy|unavail]/loops:                                                              n (loop returies for invalid entries)
                                    ; /AMPUSER/<ext>/vmx/[busy|unavail]/vmxopts/dovm:                                       vmoptions (if ext is dovm)
                                    ; /AMPUSER/<ext>/vmx/[busy|unavail]/vmxopts/timeout:                    vmoptions (if timeout)
                                    ; /AMPUSER/<ext>/vmx/[busy|unavail]/vmxopts/loops:                              vmoptions (if loops)
                                    ; /AMPUSER/<ext>/vmx/[busy|unavail]/timedest/ext:                                       extension (if timeout)
                                    ; /AMPUSER/<ext>/vmx/[busy|unavail]/timedest/context:                   context (if timeout)
                                    ; /AMPUSER/<ext>/vmx/[busy|unavail]/timedest/pri:                                       priority (if timeout)
                                    ; /AMPUSER/<ext>/vmx/[busy|unavail]/loopdest/ext:                                       extension (if too many failures)
                                    ; /AMPUSER/<ext>/vmx/[busy|unavail]/loopdest/context:                   context (if too many failures)
                                    ; /AMPUSER/<ext>/vmx/[busy|unavail]/loopdest/pri:                                       priority (if too many failures)
                                    ; /AMPUSER/<ext>/vmx/[busy|unavail]/[0-9*]/ext:                                         extension (dovm for vm access)
                                    ; /AMPUSER/<ext>/vmx/[busy|unavail]/[0-9*]/context:                             context
                                    ; /AMPUSER/<ext>/vmx/[busy|unavail]/[0-9*]/pri:                                         priority
                                    ;------------------------------------------------------------------------
            */
            // ARG1 - extension
            // ARG2 - DIRECTDIAL/BUSY
            // ARG3 - RETURN makes macro return, otherwise hangup
            //
            $ext->add('macro-vm', 's', '', new ext_macro('user-callerid', 'SKIPTTL'));
            $ext->add('macro-vm', 's', '', new ext_setvar("VMGAIN", '${IF($["foo${VM_GAIN}"!="foo"]?"g(${VM_GAIN})":"")}'));
            // If BLKVM_OVERRIDE is set, then someone told us to block calls from going to
            // voicemail. This variable is reset by the answering channel so subsequent
            // transfers will properly function.
            //
            $ext->add('macro-vm', 's', '', new ext_gotoif('$["foo${DB(${BLKVM_OVERRIDE})}" != "fooTRUE"]', 'vmx,1'));
            // we didn't branch so block this from voicemail
            //
            $ext->add('macro-vm', 's', '', new ext_NoOp('CAME FROM: ${NODEST} - Blocking VM cause of key: ${DB(BLKVM_OVERRIDE)}'));
            $ext->add('macro-vm', 's', '', new ext_hangup(''));
            // If vmx not enabled for the current mode,then jump to normal voicemail behavior
            // also - if not message (no-msg) is requested, straight to voicemail
            //
            $ext->add('macro-vm', 'vmx', '', new ext_setvar("MEXTEN", '${ARG1}'));
            $ext->add('macro-vm', 'vmx', '', new ext_setvar("MMODE", '${ARG2}'));
            $ext->add('macro-vm', 'vmx', '', new ext_setvar("RETVM", '${ARG3}'));
            $ext->add('macro-vm', 'vmx', '', new ext_setvar("MODE", '${IF($["${MMODE}"="BUSY"]?busy:unavail)}'));
            // If this use has individual option set for playing standardized message, then override the global option
            //
            $ext->add('macro-vm', 'vmx', '', new ext_gotoif('$["${DB_EXISTS(AMPUSER/${MEXTEN}/vmx/${MODE}/vmxopts/timeout)}" = "0"]', 'chknomsg'));
            $ext->add('macro-vm', 'vmx', '', new ext_setvar("VM_OPTS", '${DB_RESULT}'));
            $ext->add('macro-vm', 'vmx', 'chknomsg', new ext_gotoif('$["${MMODE}"="NOMESSAGE"]', 's-${MMODE},1'));
            $ext->add('macro-vm', 'vmx', '', new ext_gotoif('$["${MMODE}" != "DIRECTDIAL"]', 'notdirect'));
            $ext->add('macro-vm', 'vmx', '', new ext_setvar("MODE", '${IF($["${REGEX("[b]" ${VM_DDTYPE})}" = "1"]?busy:${MODE})}'));
            $ext->add('macro-vm', 'vmx', 'notdirect', new ext_NoOp('Checking if ext ${MEXTEN} is enabled: ${DB(AMPUSER/${MEXTEN}/vmx/${MODE}/state)}'));
            $ext->add('macro-vm', 'vmx', '', new ext_gotoif('$["${DB(AMPUSER/${MEXTEN}/vmx/${MODE}/state)}" != "enabled"]', 's-${MMODE},1'));
            // If the required voicemail file does not exist, then abort and go to normal voicemail behavior
            //
            // If 1.4 or above, use the STAT function to check for the file. Prior to 1.4, use the AGI script since the System() command tried
            // in the past had errors.
            //
            $ext->add('macro-vm', 'vmx', '', new ext_macro('get-vmcontext', '${MEXTEN}'));
            //$ext->add('macro-vm', 'vmx', '', new ext_trysystem('/bin/ls ${ASTSPOOLDIR}/voicemail/${VMCONTEXT}/${MEXTEN}/${MODE}.[wW][aA][vV]'));
            if ($ast_ge_14) {
                $ext->add('macro-vm', 'vmx', '', new ext_gotoif('$[(${STAT(f,${ASTSPOOLDIR}/voicemail/${VMCONTEXT}/${MEXTEN}/temp.wav)} = 1) || (${STAT(f,${ASTSPOOLDIR}/voicemail/${VMCONTEXT}/${MEXTEN}/temp.WAV)} = 1)]', 'tmpgreet'));
                $ext->add('macro-vm', 'vmx', '', new ext_gotoif('$[(${STAT(f,${ASTSPOOLDIR}/voicemail/${VMCONTEXT}/${MEXTEN}/${MODE}.wav)} = 0) && (${STAT(f,${ASTSPOOLDIR}/voicemail/${VMCONTEXT}/${MEXTEN}/${MODE}.WAV)} = 0)]', 'nofile'));
            } else {
                $ext->add('macro-vm', 'vmx', '', new ext_agi('checksound.agi,${ASTSPOOLDIR}/voicemail/${VMCONTEXT}/${MEXTEN}/temp'));
                $ext->add('macro-vm', 'vmx', '', new ext_gotoif('$["${SYSTEMSTATUS}" = "SUCCESS"]', 'tmpgreet'));
                $ext->add('macro-vm', 'vmx', '', new ext_agi('checksound.agi,${ASTSPOOLDIR}/voicemail/${VMCONTEXT}/${MEXTEN}/${MODE}'));
                $ext->add('macro-vm', 'vmx', '', new ext_gotoif('$["${SYSTEMSTATUS}" != "SUCCESS"]', 'nofile'));
            }
            $ext->add('macro-vm', 'vmx', '', new ext_setvar("LOOPCOUNT", '0'));
            $ext->add('macro-vm', 'vmx', '', new ext_gotoif('$["${DB_EXISTS(AMPUSER/${MEXTEN}/vmx/${MODE}/repeat)}" = "0"]', 'vmxtime'));
            $ext->add('macro-vm', 'vmx', '', new ext_setvar("VMX_REPEAT", '${DB_RESULT}'));
            $ext->add('macro-vm', 'vmx', 'vmxtime', new ext_gotoif('$["${DB_EXISTS(AMPUSER/${MEXTEN}/vmx/${MODE}/timeout)}" = "0"]', 'vmxloops'));
            $ext->add('macro-vm', 'vmx', '', new ext_setvar("VMX_TIMEOUT", '${DB_RESULT}'));
            $ext->add('macro-vm', 'vmx', 'vmxloops', new ext_gotoif('$["${DB_EXISTS(AMPUSER/${MEXTEN}/vmx/${MODE}/loops)}" = "0"]', 'vmxanswer'));
            $ext->add('macro-vm', 'vmx', '', new ext_setvar("VMX_LOOPS", '${DB_RESULT}'));
            $ext->add('macro-vm', 'vmx', 'vmxanswer', new ext_answer(''));
            // Now play the users voicemail recording as the basis for their ivr, the Read command will repeat as needed and if it timesout
            // then we go to the timeout. Otherwise handle invalid options by looping until the limit until a valid option is played.
            //
            $ext->add('macro-vm', 'vmx', 'loopstart', new ext_read('ACTION', '${ASTSPOOLDIR}/voicemail/${VMCONTEXT}/${MEXTEN}/${MODE}', 1, 'skip', '${VMX_REPEAT}', '${VMX_TIMEOUT}'));
            $ext->add('macro-vm', 'vmx', '', new ext_gotoif('$["${EXISTS(${ACTION})}" = "1"]', 'checkopt'));
            // If we are here we timed out, go to the required destination
            //
            $ext->add('macro-vm', 'vmx', 'noopt', new ext_NoOp('Timeout: going to timeout dest'));
            $ext->add('macro-vm', 'vmx', '', new ext_setvar("VMX_OPTS", '${VMX_OPTS_TIMEOUT}'));
            $ext->add('macro-vm', 'vmx', '', new ext_gotoif('$["${DB_EXISTS(AMPUSER/${MEXTEN}/vmx/${MODE}/vmxopts/timeout)}" = "0"]', 'chktime'));
            $ext->add('macro-vm', 'vmx', '', new ext_setvar("VMX_OPTS", '${DB_RESULT}'));
            $ext->add('macro-vm', 'vmx', 'chktime', new ext_gotoif('$["${DB_EXISTS(AMPUSER/${MEXTEN}/vmx/${MODE}/timedest/ext)}" = "0"]', 'dotime'));
            $ext->add('macro-vm', 'vmx', '', new ext_setvar("VMX_TIMEDEST_EXT", '${DB_RESULT}'));
            $ext->add('macro-vm', 'vmx', '', new ext_gotoif('$["${DB_EXISTS(AMPUSER/${MEXTEN}/vmx/${MODE}/timedest/context)}" = "0"]', 'timepri'));
            $ext->add('macro-vm', 'vmx', '', new ext_setvar("VMX_TIMEDEST_CONTEXT", '${DB_RESULT}'));
            $ext->add('macro-vm', 'vmx', 'timepri', new ext_gotoif('$["${DB_EXISTS(AMPUSER/${MEXTEN}/vmx/${MODE}/timedest/pri)}" = "0"]', 'dotime'));
            $ext->add('macro-vm', 'vmx', '', new ext_setvar("VMX_TIMEDEST_PRI", '${DB_RESULT}'));
            $ext->add('macro-vm', 'vmx', 'dotime', new ext_goto('${VMX_TIMEDEST_PRI}', '${VMX_TIMEDEST_EXT}', '${VMX_TIMEDEST_CONTEXT}'));
            // We got an option, check if the option is defined, or one of the system defaults
            //
            $ext->add('macro-vm', 'vmx', 'checkopt', new ext_gotoif('$["${DB_EXISTS(AMPUSER/${MEXTEN}/vmx/${MODE}/${ACTION}/ext)}" = "1"]', 'doopt'));
            $ext->add('macro-vm', 'vmx', '', new ext_gotoif('$["${ACTION}" = "0"]', 'o,1'));
            $ext->add('macro-vm', 'vmx', '', new ext_gotoif('$["${ACTION}" = "*"]', 'adef,1'));
            // Got invalid option loop until the max
            //
            $ext->add('macro-vm', 'vmx', '', new ext_setvar("LOOPCOUNT", '$[${LOOPCOUNT} + 1]'));
            $ext->add('macro-vm', 'vmx', '', new ext_gotoif('$[${LOOPCOUNT} > ${VMX_LOOPS}]', 'toomany'));
            $ext->add('macro-vm', 'vmx', '', new ext_playback('pm-invalid-option&please-try-again'));
            $ext->add('macro-vm', 'vmx', '', new ext_goto('loopstart'));
            // tomany: to many invalid options, go to the specified destination
            //
            $ext->add('macro-vm', 'vmx', 'toomany', new ext_NoOp('Too Many invalid entries, got to invalid dest'));
            $ext->add('macro-vm', 'vmx', '', new ext_setvar("VMX_OPTS", '${VMX_OPTS_LOOPS}'));
            $ext->add('macro-vm', 'vmx', '', new ext_gotoif('$["${DB_EXISTS(AMPUSER/${MEXTEN}/vmx/${MODE}/vmxopts/loops)}" = "0"]', 'chkloop'));
            $ext->add('macro-vm', 'vmx', '', new ext_setvar("VMX_OPTS", '${DB_RESULT}'));
            $ext->add('macro-vm', 'vmx', 'chkloop', new ext_gotoif('$["${DB_EXISTS(AMPUSER/${MEXTEN}/vmx/${MODE}/loopdest/ext)}" = "0"]', 'doloop'));
            $ext->add('macro-vm', 'vmx', '', new ext_setvar("VMX_LOOPDEST_EXT", '${DB_RESULT}'));
            $ext->add('macro-vm', 'vmx', '', new ext_gotoif('$["${DB_EXISTS(AMPUSER/${MEXTEN}/vmx/${MODE}/loopdest/context)}" = "0"]', 'looppri'));
            $ext->add('macro-vm', 'vmx', '', new ext_setvar("VMX_LOOPDEST_CONTEXT", '${DB_RESULT}'));
            $ext->add('macro-vm', 'vmx', 'looppri', new ext_gotoif('$["${DB_EXISTS(AMPUSER/${MEXTEN}/vmx/${MODE}/loopdest/pri)}" = "0"]', 'doloop'));
            $ext->add('macro-vm', 'vmx', '', new ext_setvar("VMX_LOOPDEST_PRI", '${DB_RESULT}'));
            $ext->add('macro-vm', 'vmx', 'doloop', new ext_goto('${VMX_LOOPDEST_PRI}', '${VMX_LOOPDEST_EXT}', '${VMX_LOOPDEST_CONTEXT}'));
            // doopt: execute the valid option that was chosen
            //
            $ext->add('macro-vm', 'vmx', 'doopt', new ext_NoOp('Got a valid option: ${DB_RESULT}'));
            $ext->add('macro-vm', 'vmx', '', new ext_setvar("VMX_EXT", '${DB_RESULT}'));
            // Special case, if this option was to go to voicemail, set options and go
            //
            $ext->add('macro-vm', 'vmx', '', new ext_gotoif('$["${VMX_EXT}" != "dovm"]', 'getdest'));
            $ext->add('macro-vm', 'vmx', 'vmxopts', new ext_setvar("VMX_OPTS", '${VMX_OPTS_DOVM}'));
            $ext->add('macro-vm', 'vmx', '', new ext_gotoif('$["${DB_EXISTS(AMPUSER/${MEXTEN}/vmx/${MODE}/vmxopts/dovm)}" = "0"]', 'vmxdovm'));
            $ext->add('macro-vm', 'vmx', 'vmxopts', new ext_setvar("VMX_OPTS", '${DB_RESULT}'));
            $ext->add('macro-vm', 'vmx', 'vmxdovm', new ext_goto('1', 'dovm'));
            // General case, setup the goto destination and go there (no error checking, its up to the GUI's to assure
            // reasonable values
            //
            $ext->add('macro-vm', 'vmx', 'getdest', new ext_gotoif('$["${DB_EXISTS(AMPUSER/${MEXTEN}/vmx/${MODE}/${ACTION}/context)}" = "0"]', 'vmxpri'));
            $ext->add('macro-vm', 'vmx', '', new ext_setvar("VMX_CONTEXT", '${DB_RESULT}'));
            $ext->add('macro-vm', 'vmx', 'vmxpri', new ext_gotoif('$["${DB_EXISTS(AMPUSER/${MEXTEN}/vmx/${MODE}/${ACTION}/pri)}" = "0"]', 'vmxgoto'));
            $ext->add('macro-vm', 'vmx', '', new ext_setvar("VMX_PRI", '${DB_RESULT}'));
            $ext->add('macro-vm', 'vmx', 'vmxgoto', new ext_goto('${VMX_PRI}', '${VMX_EXT}', '${VMX_CONTEXT}'));
            // If the required voicemail file is not present, then revert to normal voicemail
            // behavior treating as if it was not set
            //
            $ext->add('macro-vm', 'vmx', 'nofile', new ext_NoOp('File for mode: ${MODE} does not exist, SYSTEMSTATUS: ${SYSTEMSTATUS}, going to normal voicemail'));
            $ext->add('macro-vm', 'vmx', '', new ext_goto('1', 's-${MMODE}'));
            $ext->add('macro-vm', 'vmx', 'tmpgreet', new ext_NoOp('Temporary Greeting Detected, going to normal voicemail'));
            $ext->add('macro-vm', 'vmx', '', new ext_goto('1', 's-${MMODE}'));
            // Drop into voicemail either as a direct destination (in which case VMX_OPTS might be set to something) or
            // if the user timed out or broke out of the loop then VMX_OPTS is always cleared such that an Allison
            // message is played and the caller know's what is going on.
            //
            $ext->add('macro-vm', 'dovm', '', new ext_NoOp('VMX Timeout - go to voicemail'));
            $ext->add('macro-vm', 'dovm', '', new ext_vm('${MEXTEN}@${VMCONTEXT},${VMX_OPTS}${VMGAIN}'));
            $ext->add('macro-vm', 'dovm', '', new ext_goto('1', 'exit-${VMSTATUS}'));
            $ext->add('macro-vm', 's-BUSY', '', new ext_NoOp('BUSY voicemail'));
            $ext->add('macro-vm', 's-BUSY', '', new ext_macro('get-vmcontext', '${MEXTEN}'));
            $ext->add('macro-vm', 's-BUSY', '', new ext_vm('${MEXTEN}@${VMCONTEXT},${VM_OPTS}b${VMGAIN}'));
            $ext->add('macro-vm', 's-BUSY', '', new ext_goto('1', 'exit-${VMSTATUS}'));
            $ext->add('macro-vm', 's-NOMESSAGE', '', new ext_NoOp('NOMESSAGE (beeb only) voicemail'));
            $ext->add('macro-vm', 's-NOMESSAGE', '', new ext_macro('get-vmcontext', '${MEXTEN}'));
            $ext->add('macro-vm', 's-NOMESSAGE', '', new ext_vm('${MEXTEN}@${VMCONTEXT},s${VM_OPTS}${VMGAIN}'));
            $ext->add('macro-vm', 's-NOMESSAGE', '', new ext_goto('1', 'exit-${VMSTATUS}'));
            $ext->add('macro-vm', 's-DIRECTDIAL', '', new ext_NoOp('DIRECTDIAL voicemail'));
            $ext->add('macro-vm', 's-DIRECTDIAL', '', new ext_macro('get-vmcontext', '${MEXTEN}'));
            $ext->add('macro-vm', 's-DIRECTDIAL', '', new ext_vm('${MEXTEN}@${VMCONTEXT},${VM_OPTS}${VM_DDTYPE}${VMGAIN}'));
            $ext->add('macro-vm', 's-DIRECTDIAL', '', new ext_goto('1', 'exit-${VMSTATUS}'));
            $ext->add('macro-vm', '_s-.', '', new ext_macro('get-vmcontext', '${MEXTEN}'));
            $ext->add('macro-vm', '_s-.', '', new ext_vm('${MEXTEN}@${VMCONTEXT},${VM_OPTS}u${VMGAIN}'));
            $ext->add('macro-vm', '_s-.', '', new ext_goto('1', 'exit-${VMSTATUS}'));
            // If the user has a 0 option defined, use that for operator zero-out from within voicemail
            // as well to keep it consistant with the menu structure
            //
            $ext->add('macro-vm', 'o', '', new ext_playback('one-moment-please'));
            $ext->add('macro-vm', 'o', '', new ext_gotoif('$["${DB_EXISTS(AMPUSER/${MEXTEN}/vmx/${MODE}/0/ext)}" = "0"]', 'doopdef'));
            $ext->add('macro-vm', 'o', '', new ext_setvar("VMX_OPDEST_EXT", '${DB_RESULT}'));
            $ext->add('macro-vm', 'o', '', new ext_gotoif('$["${DB_EXISTS(AMPUSER/${MEXTEN}/vmx/${MODE}/0/context)}" = "1"]', 'opcontext'));
            $ext->add('macro-vm', 'o', '', new ext_setvar("DB_RESULT", '${VMX_CONTEXT}'));
            $ext->add('macro-vm', 'o', 'opcontext', new ext_setvar("VMX_OPDEST_CONTEXT", '${DB_RESULT}'));
            $ext->add('macro-vm', 'o', '', new ext_gotoif('$["${DB_EXISTS(AMPUSER/${MEXTEN}/vmx/${MODE}/0/pri)}" = "1"]', 'oppri'));
            $ext->add('macro-vm', 'o', '', new ext_setvar("DB_RESULT", '${VMX_PRI}'));
            $ext->add('macro-vm', 'o', 'oppri', new ext_setvar("VMX_OPDEST_PRI", '${DB_RESULT}'));
            $ext->add('macro-vm', 'o', '', new ext_goto('${VMX_OPDEST_PRI}', '${VMX_OPDEST_EXT}', '${VMX_OPDEST_CONTEXT}'));
            $ext->add('macro-vm', 'o', 'doopdef', new ext_gotoif('$["x${OPERATOR_XTN}"="x"]', 'nooper', 'from-internal,${OPERATOR_XTN},1'));
            $ext->add('macro-vm', 'o', 'nooper', new ext_gotoif('$["x${FROM_DID}"="x"]', 'nodid'));
            $ext->add('macro-vm', 'o', '', new ext_dial('Local/${FROM_DID}@from-pstn', ''));
            $ext->add('macro-vm', 'o', '', new ext_macro('hangup'));
            $ext->add('macro-vm', 'o', 'nodid', new ext_dial('Local/s@from-pstn', ''));
            $ext->add('macro-vm', 'o', '', new ext_macro('hangup'));
            // If the user has a * option defined, use that for the * out from within voicemail
            // as well to keep it consistant with the menu structure
            //
            $ext->add('macro-vm', 'a', '', new ext_macro('get-vmcontext', '${MEXTEN}'));
            $ext->add('macro-vm', 'a', '', new ext_gotoif('$["${DB_EXISTS(AMPUSER/${MEXTEN}/vmx/${MODE}/*/ext)}" = "0"]', 'adef,1'));
            $ext->add('macro-vm', 'a', '', new ext_setvar("VMX_ADEST_EXT", '${DB_RESULT}'));
            $ext->add('macro-vm', 'a', '', new ext_gotoif('$["${DB_EXISTS(AMPUSER/${MEXTEN}/vmx/${MODE}/*/context)}" = "1"]', 'acontext'));
            $ext->add('macro-vm', 'a', '', new ext_setvar("DB_RESULT", '${VMX_CONTEXT}'));
            $ext->add('macro-vm', 'a', 'acontext', new ext_setvar("VMX_ADEST_CONTEXT", '${DB_RESULT}'));
            $ext->add('macro-vm', 'a', '', new ext_gotoif('$["${DB_EXISTS(AMPUSER/${MEXTEN}/vmx/${MODE}/*/pri)}" = "1"]', 'apri'));
            $ext->add('macro-vm', 'a', '', new ext_setvar("DB_RESULT", '${VMX_PRI}'));
            $ext->add('macro-vm', 'a', 'apri', new ext_setvar("VMX_ADEST_PRI", '${DB_RESULT}'));
            $ext->add('macro-vm', 'a', '', new ext_goto('${VMX_ADEST_PRI}', '${VMX_ADEST_EXT}', '${VMX_ADEST_CONTEXT}'));
            $ext->add('macro-vm', 'adef', '', new ext_vmmain('${MEXTEN}@${VMCONTEXT}'));
            $ext->add('macro-vm', 'adef', '', new ext_gotoif('$["${RETVM}" = "RETURN"]', 'exit-RETURN,1'));
            $ext->add('macro-vm', 'adef', '', new ext_hangup(''));
            $ext->add('macro-vm', 'exit-FAILED', '', new ext_playback('im-sorry&an-error-has-occured'));
            $ext->add('macro-vm', 'exit-FAILED', '', new ext_gotoif('$["${RETVM}" = "RETURN"]', 'exit-RETURN,1'));
            $ext->add('macro-vm', 'exit-FAILED', '', new ext_hangup(''));
            $ext->add('macro-vm', 'exit-SUCCESS', '', new ext_gotoif('$["${RETVM}" = "RETURN"]', 'exit-RETURN,1'));
            $ext->add('macro-vm', 'exit-SUCCESS', '', new ext_playback('goodbye'));
            $ext->add('macro-vm', 'exit-SUCCESS', '', new ext_hangup(''));
            $ext->add('macro-vm', 'exit-USEREXIT', '', new ext_gotoif('$["${RETVM}" = "RETURN"]', 'exit-RETURN,1'));
            $ext->add('macro-vm', 'exit-USEREXIT', '', new ext_playback('goodbye'));
            $ext->add('macro-vm', 'exit-USEREXIT', '', new ext_hangup(''));
            $ext->add('macro-vm', 'exit-RETURN', '', new ext_noop('Returning From Voicemail because macro'));
            $ext->add('macro-vm', 't', '', new ext_hangup(''));
            /* end macro-vm  */
            $mcontext = 'macro-exten-vm';
            $exten = 's';
            $ext->add($mcontext, $exten, '', new ext_macro('user-callerid'));
            $ext->add($mcontext, $exten, '', new ext_set("RingGroupMethod", 'none'));
            $ext->add($mcontext, $exten, '', new ext_set("VMBOX", '${ARG1}'));
            $ext->add($mcontext, $exten, '', new ext_set("__EXTTOCALL", '${ARG2}'));
            $ext->add($mcontext, $exten, '', new ext_set("CFUEXT", '${DB(CFU/${EXTTOCALL})}'));
            $ext->add($mcontext, $exten, '', new ext_set("CFBEXT", '${DB(CFB/${EXTTOCALL})}'));
            $ext->add($mcontext, $exten, '', new ext_set("RT", '${IF($[$["${VMBOX}"!="novm"] | $["${CFUEXT}"!=""]]?${RINGTIMER}:"")}'));
            $ext->add($mcontext, $exten, 'checkrecord', new ext_macro('record-enable', '${EXTTOCALL},IN'));
            if ($has_extension_state) {
                $ext->add($mcontext, $exten, 'macrodial', new ext_macro('dial-one', '${RT},${DIAL_OPTIONS},${EXTTOCALL}'));
            } else {
                $ext->add($mcontext, $exten, 'macrodial', new ext_macro('dial', '${RT},${DIAL_OPTIONS},${EXTTOCALL}'));
            }
            $ext->add($mcontext, $exten, '', new ext_gotoif('$["${VMBOX}"!="novm" & "${SCREEN}"!="" & "${DIALSTATUS}"="NOANSWER"]', 'exit'));
            $ext->add($mcontext, $exten, '', new ext_set("SV_DIALSTATUS", '${DIALSTATUS}'));
            $ext->add($mcontext, $exten, 'calldocfu', new ext_gosubif('$[("${SV_DIALSTATUS}"="NOANSWER"|"${SV_DIALSTATUS}"="CHANUNAVAIL") & "${CFUEXT}"!="" & "${SCREEN}"=""]', 'docfu,1'));
            $ext->add($mcontext, $exten, 'calldocfb', new ext_gosubif('$["${SV_DIALSTATUS}"="BUSY" & "${CFBEXT}"!=""]', 'docfb,1'));
            $ext->add($mcontext, $exten, '', new ext_set("DIALSTATUS", '${SV_DIALSTATUS}'));
            $ext->add($mcontext, $exten, '', new ext_noop('Voicemail is \'${VMBOX}\''));
            $ext->add($mcontext, $exten, '', new ext_gotoif('$["${VMBOX}"="novm"]', 's-${DIALSTATUS},1'));
            $ext->add($mcontext, $exten, '', new ext_noop('Sending to Voicemail box ${EXTTOCALL}'));
            $ext->add($mcontext, $exten, '', new ext_macro('vm', '${VMBOX},${DIALSTATUS},${IVR_RETVM}'));
            $exten = 'docfu';
            $ext->add($mcontext, $exten, 'docfu', new ext_set("RTCFU", '${IF($["${VMBOX}"!="novm"]?${RINGTIMER}:"")}'));
            $ext->add($mcontext, $exten, '', new ext_dial('Local/${CFUEXT}@from-internal/n', '${RTCFU},${DIAL_OPTIONS}'));
            $ext->add($mcontext, $exten, '', new ext_return(''));
            $exten = 'docfb';
            $ext->add($mcontext, $exten, 'docfb', new ext_set("RTCFB", '${IF($["${VMBOX}"!="novm"]?${RINGTIMER}:"")}'));
            $ext->add($mcontext, $exten, '', new ext_dial('Local/${CFBEXT}@from-internal/n', '${RTCFB},${DIAL_OPTIONS}'));
            $ext->add($mcontext, $exten, '', new ext_return(''));
            $exten = 's-BUSY';
            $ext->add($mcontext, $exten, '', new ext_noop('Extension is reporting BUSY and not passing to Voicemail'));
            $ext->add($mcontext, $exten, '', new ext_gotoif('$["${IVR_RETVM}"="RETURN" & "${IVR_CONTEXT}"!=""]', 'exit,1'));
            $ext->add($mcontext, $exten, '', new ext_playtones('busy'));
            $ext->add($mcontext, $exten, '', new ext_busy(20));
            $exten = '_s-!';
            $ext->add($mcontext, $exten, '', new ext_noop('IVR_RETVM: ${IVR_RETVM} IVR_CONTEXT: ${IVR_CONTEXT}'));
            $ext->add($mcontext, $exten, '', new ext_gotoif('$["${IVR_RETVM}"="RETURN" & "${IVR_CONTEXT}"!=""]', 'exit,1'));
            $ext->add($mcontext, $exten, '', new ext_playtones('congestion'));
            $ext->add($mcontext, $exten, '', new ext_congestion('10'));
            $exten = 'exit';
            $ext->add($mcontext, $exten, '', new ext_playback('beep&line-busy-transfer-menu&silence/1'));
            $ext->add($mcontext, $exten, '', new ext_macroexit());
            /* macro-exten-vm  */
            /*
            ;------------------------------------------------------------------------
            ; [macro-simple-dial]
            ;------------------------------------------------------------------------
            ; This macro was derived from macro-exten-vm, which is what is normally used to
            ; ring an extension. It has been simplified and designed to never go to voicemail
            ; and always return regardless of the DIALSTATUS for any incomplete call.
            ;
            ; It's current primary purpose is to allow findmefollow ring an extension prior
            ; to trying the follow-me ringgroup that is provided.
            ;
            ; Ring an extension, if the extension is busy or there is no answer, return
            ; ARGS: $EXTENSION, $RINGTIME
            ;------------------------------------------------------------------------
            */
            $mcontext = 'macro-simple-dial';
            $exten = 's';
            $ext->add($mcontext, $exten, '', new ext_set("__EXTTOCALL", '${ARG1}'));
            $ext->add($mcontext, $exten, '', new ext_set("RT", '${ARG2}'));
            $ext->add($mcontext, $exten, '', new ext_set("CFUEXT", '${DB(CFU/${EXTTOCALL})}'));
            $ext->add($mcontext, $exten, '', new ext_set("CFBEXT", '${DB(CFB/${EXTTOCALL})}'));
            $ext->add($mcontext, $exten, '', new ext_set("CWI_TMP", '${CWIGNORE}'));
            if ($has_extension_state) {
                $ext->add($mcontext, $exten, 'macrodial', new ext_macro('dial-one', '${RT},${DIAL_OPTIONS},${EXTTOCALL}'));
            } else {
                $ext->add($mcontext, $exten, 'macrodial', new ext_macro('dial', '${RT},${DIAL_OPTIONS},${EXTTOCALL}'));
            }
            $ext->add($mcontext, $exten, '', new ext_set("__CWIGNORE", '${CWI_TMP}'));
            $ext->add($mcontext, $exten, '', new ext_set("PR_DIALSTATUS", '${DIALSTATUS}'));
            $ext->add($mcontext, $exten, 'calldocfu', new ext_gosubif('$["${PR_DIALSTATUS}"="NOANSWER" & "${CFUEXT}"!=""]', 'docfu,1'));
            $ext->add($mcontext, $exten, 'calldocfb', new ext_gosubif('$["${PR_DIALSTATUS}"="BUSY" & "${CFBEXT}"!=""]', 'docfb,1'));
            $ext->add($mcontext, $exten, '', new ext_set("DIALSTATUS", '${PR_DIALSTATUS}'));
            $ext->add($mcontext, $exten, '', new ext_goto('1', 's-${DIALSTATUS}'));
            /*
            ; Try the Call Forward on No Answer / Unavailable number.
            ; We want to try CFU if set, but we want the same ring timer as was set to our call (or do we want the
            ; system ringtimer? - probably not). Then if no answer there (assuming it doesn't drop into their vm or
            ; something we return, which will have the net effect of returning to the followme setup.)
            ;
            ; want to avoid going to other follow-me settings here. So check if the CFUEXT is a user and if it is
            ; then direct it straight to ext-local (to avoid getting intercepted by findmefollow) otherwise send it
            ; to from-internal since it may be an outside line.
            ;
            */
            $exten = 'docfu';
            $ext->add($mcontext, $exten, '', new ext_gotoif('$["${DB(AMPUSER/${CFUEXT}/device)}" = "" ]', 'chlocal'));
            $ext->add($mcontext, $exten, '', new ext_dial('Local/${CFUEXT}@ext-local', '${RT},${DIAL_OPTIONS}'));
            $ext->add($mcontext, $exten, '', new ext_return(''));
            $ext->add($mcontext, $exten, 'chlocal', new ext_dial('Local/${CFUEXT}@from-internal/n', '${RT},${DIAL_OPTIONS}'));
            $ext->add($mcontext, $exten, '', new ext_return(''));
            $exten = 'docfb';
            $ext->add($mcontext, $exten, '', new ext_gotoif('$["${DB(AMPUSER/${CFBEXT}/device)}" = "" ]', 'chlocal'));
            $ext->add($mcontext, $exten, '', new ext_dial('Local/${CFBEXT}@ext-local', '${RT},${DIAL_OPTIONS}'));
            $ext->add($mcontext, $exten, '', new ext_return(''));
            $ext->add($mcontext, $exten, 'chlocal', new ext_dial('Local/${CFBEXT}@from-internal/n', '${RT},${DIAL_OPTIONS}'));
            $ext->add($mcontext, $exten, '', new ext_return(''));
            /*
            ; In all cases of no connection, come here and simply return, since the calling dialplan will
            ; decide what to do next
            */
            $exten = '_s-.';
            $ext->add($mcontext, $exten, '', new ext_noop('Extension is reporting ${EXTEN}'));
            /* macro-simple-dial */
            $mcontext = 'macro-hangupcall';
            $exten = 's';
            /*
            ; Cleanup any remaining RG flag
            */
            $ext->add($mcontext, $exten, 'start', new ext_gotoif('$["${USE_CONFIRMATION}"="" | "${RINGGROUP_INDEX}"="" | "${CHANNEL}"!="${UNIQCHAN}"]', 'skiprg'));
            $ext->add($mcontext, $exten, '', new ext_noop('Cleaning Up Confirmation Flag: RG/${RINGGROUP_INDEX}/${CHANNEL}'));
            $ext->add($mcontext, $exten, 'delrgi', new ext_dbdel('RG/${RINGGROUP_INDEX}/${CHANNEL}'));
            /*
            ; Cleanup any remaining BLKVM flag
            */
            $ext->add($mcontext, $exten, 'skiprg', new ext_gotoif('$["${BLKVM_BASE}"="" | "BLKVM/${BLKVM_BASE}/${CHANNEL}"!="${BLKVM_OVERRIDE}"]', 'skipblkvm'));
            $ext->add($mcontext, $exten, '', new ext_noop('Cleaning Up Block VM Flag: ${BLKVM_OVERRIDE}'));
            $ext->add($mcontext, $exten, 'delblkvm', new ext_dbdel('${BLKVM_OVERRIDE}'));
            /*
            ; Cleanup any remaining FollowMe DND flags
            */
            $ext->add($mcontext, $exten, 'skipblkvm', new ext_gotoif('$["${FMGRP}"="" | "${FMUNIQUE}"="" | "${CHANNEL}"!="${FMUNIQUE}"]', 'theend'));
            $ext->add($mcontext, $exten, 'delfmrgp', new ext_dbdel('FM/DND/${FMGRP}/${CHANNEL}'));
            $ext->add($mcontext, $exten, 'theend', new ext_hangup());
            /* macro-hangupcall */
            /*
            ; macro-dial-one
            ;
            TODO: This is still experimental and has not yet been fully tested. Feedback in using/testing it is welcome and we will be reponsive in
                  fixing it but it should be considered as alpha quality until then and is not used anywhere in the dialplan unless forced with the
                  un-documented USEMACRODIALONE = true flag.
            */
            if ($has_extension_state) {
                $mcontext = 'macro-dial-one';
                $exten = 's';
                $ext->add($mcontext, $exten, '', new ext_set('DEXTEN', '${ARG3}'));
                $ext->add($mcontext, $exten, '', new ext_set('DIALSTATUS_CW', ''));
                $ext->add($mcontext, $exten, '', new ext_gosubif('$["${FROM_DID}"!="" & "${SCREEN}"="" & "${DB(AMPUSER/${DEXTEN}/screen)}"!=""]', 'screen,1'));
                $ext->add($mcontext, $exten, '', new ext_gosubif('$["${DB(CF/${DEXTEN})}"!=""]', 'cf,1'));
                $ext->add($mcontext, $exten, '', new ext_gotoif('$["${DEXTEN:-1}"="#" | "${DB(DND/${DEXTEN})}"=""]', 'skip1'));
                $ext->add($mcontext, $exten, '', new ext_set('DEXTEN', ''));
                $ext->add($mcontext, $exten, '', new ext_set('DIALSTATUS', 'BUSY'));
                $ext->add($mcontext, $exten, 'skip1', new ext_gotoif('$["${DEXTEN}"=""]', 'nodial'));
                $ext->add($mcontext, $exten, '', new ext_gotoif('$["${DEXTEN:-1}"="#"]', 'continue'));
                $ext->add($mcontext, $exten, '', new ext_set('EXTHASCW', '${IF($["${CWIGNORE}"!=""]?"":${DB(CW/${DEXTEN})})}'));
                $ext->add($mcontext, $exten, '', new ext_gotoif('$["${EXTHASCW}"="" | "${DB(CFB/${DEXTEN})}"!="" | "${DB(CFU/${DEXTEN})}"!=""]', 'next1', 'cwinusebusy'));
                $ext->add($mcontext, $exten, 'next1', new ext_gotoif('$["${DB(CFU/${DEXTEN})}"!="" & ("${EXTENSION_STATE(${DEXTEN})}"="UNAVAILABLE" | "${EXTENSION_STATE(${DEXTEN})}"="UNKNOWN")]', 'docfu', 'skip3'));
                $ext->add($mcontext, $exten, 'docfu', new ext_set('DEXTEN', ''));
                $ext->add($mcontext, $exten, '', new ext_set('DIALSTATUS', 'NOANSWER'));
                $ext->add($mcontext, $exten, '', new ext_goto('nodial'));
                $ext->add($mcontext, $exten, 'skip3', new ext_gotoif('$["${EXTHASCW}"="" | "${DB(CFB/${DEXTEN})}"!=""]', 'next2', 'continue'));
                $ext->add($mcontext, $exten, 'next2', new ext_gotoif('$["${EXTENSION_STATE(${DEXTEN})}"="NOT_INUSE" | "${EXTENSION_STATE(${DEXTEN})}"="UNAVAILABLE" | "${EXTENSION_STATE(${DEXTEN})}"="UNKNOWN"]', 'continue'));
                $ext->add($mcontext, $exten, '', new ext_execif('$["${DB(CFB/${DEXTEN})}"!="" & "${CFIGNORE}"=""]', 'Set', 'DIALSTATUS=BUSY'));
                $ext->add($mcontext, $exten, '', new ext_gotoif('$["${EXTHASCW}"!="" | "${DEXTEN:-1}"="#"]', 'cwinusebusy'));
                $ext->add($mcontext, $exten, '', new ext_set('DEXTEN', ''));
                $ext->add($mcontext, $exten, '', new ext_set('DIALSTATUS', 'BUSY'));
                $ext->add($mcontext, $exten, '', new ext_goto('nodial'));
                $ext->add($mcontext, $exten, 'cwinusebusy', new ext_gotoif('$["${EXTHASCW}"!="" & "${CWINUSEBUSY}"!=""]', 'next3', 'continue'));
                $ext->add($mcontext, $exten, 'next3', new ext_execif('$["${EXTENSION_STATE(${DEXTEN})}"!="UNAVAILABLE" & "${EXTENSION_STATE(${DEXTEN})}"!="NOT_INUSE" & "${EXTENSION_STATE(${DEXTEN})}"!="UNKNOWN"]', 'Set', 'DIALSTATUS_CW=BUSY'));
                $ext->add($mcontext, $exten, 'continue', new ext_gotoif('$["${DEXTEN}"=""]', 'nodial'));
                $ext->add($mcontext, $exten, '', new ext_gosubif('$["${DEXTEN:-1}"!="#"]', 'dstring,1', 'dlocal,1'));
                $ext->add($mcontext, $exten, '', new ext_gotoif('$[${LEN(${DSTRING})}=0]', 'nodial'));
                $ext->add($mcontext, $exten, '', new ext_gotoif('$["${DEXTEN:-1}"="#"]', 'skiptrace'));
                $ext->add($mcontext, $exten, '', new ext_gosubif('$[${REGEX("^[\\+]?[0-9]+$" ${CALLERID(number)})} = 1]', 'ctset,1', 'ctclear,1'));
                //TODO: do we need to check for anything beyond auto-blkvm in this call path?
                $ext->add($mcontext, $exten, 'skiptrace', new ext_set('D_OPTIONS', '${IF($["${NODEST}"!="" & ${REGEX("(M[(]auto-blkvm[)])" ${ARG2})} != 1]?${ARG2}M(auto-blkvm):${ARG2})}'));
                $ext->add($mcontext, $exten, '', new ext_execif('$["${ALERT_INFO}"!=""]', 'SIPAddHeader', 'Alert-Info: ${ALERT_INFO}'));
                //TODO: Do I need to  re-propagage anything from ${SIPADDHEADER} ?
                $ext->add($mcontext, $exten, '', new ext_execif('$["${SIPADDHEADER}"!=""]', 'SIPAddHeader', '${SIPADDHEADER}'));
                if ($ast_ge_14) {
                    $ext->add($mcontext, $exten, '', new ext_execif('$["${MOHCLASS}"!=""]', 'Set', 'CHANNEL(musicclass)=${MEETME_MUSIC}'));
                } else {
                    $ext->add($mcontext, $exten, '', new ext_execif('$["${MOHCLASS}"!=""]', 'SetMusicOnHold', '${MOHCLASS}'));
                }
                $ext->add($mcontext, $exten, '', new ext_gosubif('$["${QUEUEWAIT}"!=""]', 'qwait,1'));
                $ext->add($mcontext, $exten, '', new ext_set('__CWIGNORE', '${CWIGNORE}'));
                $ext->add($mcontext, $exten, '', new ext_set('__KEEPCID', 'TRUE'));
                $ext->add($mcontext, $exten, '', new ext_dial('${DSTRING}', '${ARG1},${D_OPTIONS}'));
                $ext->add($mcontext, $exten, '', new ext_execif('$["${DIALSTATUS_CW}"!=""]', 'Set', 'DIALSTATUS=${DIALSTATUS_CW}'));
                $ext->add($mcontext, $exten, '', new ext_gosubif('$["${SCREEN}"!=""|"${DIALSTATUS}"="ANSWER"]', 's-${DIALSTATUS},1'));
                $ext->add($mcontext, $exten, '', new ext_macroexit());
                $ext->add($mcontext, $exten, 'nodial', new ext_execif('$["${DIALSTATUS}" = ""]', 'Set', 'DIALSTATUS=NOANSWER'));
                $ext->add($mcontext, $exten, '', new ext_noop('Returned from dial-one with nothing to call and DIALSTATUS: ${DIALSTATUS}'));
                $ext->add($mcontext, $exten, '', new ext_macroexit());
                $exten = 'h';
                $ext->add($mcontext, $exten, '', new ext_macro('hangupcall'));
                $exten = 'screen';
                $ext->add($mcontext, $exten, '', new ext_gotoif('$["${DB(AMPUSER/${DEXTEN}/screen)}"!="nomemory" | "${CALLERID(number)}"=""]', 'memory'));
                $ext->add($mcontext, $exten, '', new ext_execif('$[${REGEX("^[0-9a-zA-Z ]+$" ${CALLERID(number)})} = 1]', 'System', 'rm -f ${ASTVARLIBDIR}/sounds/priv-callerintros/${CALLERID(number)}.*'));
                $ext->add($mcontext, $exten, 'memory', new ext_set('__SCREEN', '${DB(AMPUSER/${DEXTEN}/screen)}'));
                $ext->add($mcontext, $exten, '', new ext_set('__SCREEN_EXTEN', '${DEXTEN}'));
                $ext->add($mcontext, $exten, '', new ext_set('ARG2', '${ARG2}p'));
                $ext->add($mcontext, $exten, '', new ext_return(''));
                $exten = 'cf';
                $ext->add($mcontext, $exten, '', new ext_set('CFAMPUSER', '${IF($["${AMPUSER}"=""]?${CALLERID(number)}:${AMPUSER})}'));
                $ext->add($mcontext, $exten, '', new ext_execif('$["${DB(CF/${DEXTEN})}"="${CFAMPUSER}" | "${DB(CF/${DEXTEN})}"="${REALCALLERIDNUM}" | "${CUT(CUT(BLINDTRANSFER,-,1),/,1)}" = "${DB(CF/${DEXTEN})}" | "${DEXTEN}"="${DB(CF/${DEXTEN})}"]', 'Return'));
                $ext->add($mcontext, $exten, '', new ext_set('DEXTEN', '${IF($["${CFIGNORE}"=""]?"${DB(CF/${DEXTEN})}#":"")}'));
                $ext->add($mcontext, $exten, '', new ext_execif('$["${DEXTEN}"!=""]', 'Return'));
                $ext->add($mcontext, $exten, '', new ext_set('DIALSTATUS', 'NOANSWER'));
                $ext->add($mcontext, $exten, '', new ext_return(''));
                $exten = 'qwait';
                $ext->add($mcontext, $exten, '', new ext_execif('$["${SAVEDCIDNAME}" = ""]', 'Set', '__SAVEDCIDNAME=${CALLERID(name)}'));
                $ext->add($mcontext, $exten, '', new ext_set('ELAPSED', '${MATH($[${EPOCH}+30-${QUEUEWAIT}]/60,int)}'));
                $ext->add($mcontext, $exten, '', new ext_set('CALLERID(name)', 'M${ELAPSED}:${SAVEDCIDNAME}'));
                $ext->add($mcontext, $exten, '', new ext_return(''));
                $exten = 'ctset';
                $ext->add($mcontext, $exten, '', new ext_set('DB(CALLTRACE/${DEXTEN})', '${CALLERID(number)}'));
                $ext->add($mcontext, $exten, '', new ext_return(''));
                $exten = 'ctclear';
                $ext->add($mcontext, $exten, '', new ext_dbdel('CALLTRACE/${DEXTEN}'));
                $ext->add($mcontext, $exten, '', new ext_return(''));
                $exten = 'dstring';
                $ext->add($mcontext, $exten, '', new ext_set('DSTRING', ''));
                $ext->add($mcontext, $exten, '', new ext_set('DEVICES', '${DB(AMPUSER/${DEXTEN}/device)}'));
                $ext->add($mcontext, $exten, '', new ext_execif('$["${DEVICES}"=""]', 'Return'));
                $ext->add($mcontext, $exten, '', new ext_execif('$["${DEVICES:0:1}"="&"]', 'Set', 'DEVICES=${DEVICES:1}'));
                $ext->add($mcontext, $exten, '', new ext_set('LOOPCNT', '${FIELDQTY(DEVICES,&)}'));
                $ext->add($mcontext, $exten, '', new ext_set('ITER', '1'));
                $ext->add($mcontext, $exten, 'begin', new ext_set('THISDIAL', '${DB(DEVICE/${CUT(DEVICES,&,${ITER})}/dial)}'));
                if ($chan_dahdi) {
                    $ext->add($mcontext, $exten, '', new ext_gosubif('$["${ASTCHANDAHDI}" != ""]', 'zap2dahdi,1'));
                }
                $ext->add($mcontext, $exten, '', new ext_set('DSTRING', '${DSTRING}${THISDIAL}&'));
                $ext->add($mcontext, $exten, '', new ext_set('ITER', '$[${ITER}+1]'));
                $ext->add($mcontext, $exten, '', new ext_gotoif('$[${ITER}<=${LOOPCNT}]', 'begin'));
                $ext->add($mcontext, $exten, '', new ext_set('DSTRING', '${DSTRING:0:$[${LEN(${DSTRING})}-1]}'));
                $ext->add($mcontext, $exten, '', new ext_return(''));
                $exten = 'dlocal';
                $ext->add($mcontext, $exten, '', new ext_set('DSTRING', 'Local/${DEXTEN:0:${MATH(${LEN(${DEXTEN})}-1,int)}}@from-internal/n'));
                $ext->add($mcontext, $exten, '', new ext_return(''));
                if ($chan_dahdi) {
                    $exten = 'zap2dahdi';
                    $ext->add($mcontext, $exten, '', new ext_execif('$["${THISDIAL}" = ""]', 'Return'));
                    $ext->add($mcontext, $exten, '', new ext_set('NEWDIAL', ''));
                    $ext->add($mcontext, $exten, '', new ext_set('LOOPCNT2', '${FIELDQTY(THISDIAL,&)}'));
                    $ext->add($mcontext, $exten, '', new ext_set('ITER2', '1'));
                    $ext->add($mcontext, $exten, 'begin2', new ext_set('THISPART2', '${CUT(THISDIAL,&,${ITER2})}'));
                    $ext->add($mcontext, $exten, '', new ext_execif('$["${THISPART2:0:3}" = "ZAP"]', 'Set', 'THISPART2=DAHDI${THISPART2:3}'));
                    $ext->add($mcontext, $exten, '', new ext_set('NEWDIAL', '${NEWDIAL}${THISPART2}&'));
                    $ext->add($mcontext, $exten, '', new ext_set('ITER2', '$[${ITER2} + 1]'));
                    $ext->add($mcontext, $exten, '', new ext_gotoif('$[${ITER2} <= ${LOOPCNT2}]', 'begin2'));
                    $ext->add($mcontext, $exten, '', new ext_set('THISDIAL', '${NEWDIAL:0:$[${LEN(${NEWDIAL})}-1]}'));
                    $ext->add($mcontext, $exten, '', new ext_return(''));
                }
                $exten = 's-NOANSWER';
                $ext->add($mcontext, $exten, '', new ext_macro('vm', '${SCREEN_EXTEN},BUSY,${IVR_RETVM}'));
                $ext->add($mcontext, $exten, '', new ext_execif('$["${IVR_RETVM}"!="RETURN" | "${IVR_CONTEXT}"=""]', 'Hangup'));
                $ext->add($mcontext, $exten, '', new ext_return(''));
                /*
                 * There are reported bugs in Asterisk Blind Trasfers that result in Dial() returning and continuing
                 * execution with a status of ANSWER. So we hangup at this point
                 */
                $exten = 's-ANSWER';
                $ext->add($context, $exten, '', new ext_noop('Call successfully answered - Hanging up now'));
                $ext->add($context, $exten, '', new ext_macro('hangupcall'));
                $exten = 's-TORTURE';
                $ext->add($mcontext, $exten, '', new ext_goto('1', 'musiconhold', 'app-blackhole'));
                $ext->add($mcontext, $exten, '', new ext_macro('hangupcall'));
                $exten = 's-DONTCALL';
                $ext->add($mcontext, $exten, '', new ext_answer(''));
                $ext->add($mcontext, $exten, '', new ext_wait('1'));
                $ext->add($mcontext, $exten, '', new ext_zapateller(''));
                $ext->add($mcontext, $exten, '', new ext_playback('ss-noservice'));
                $ext->add($mcontext, $exten, '', new ext_macro('hangupcall'));
                /* macro-dial-one */
            }
            break;
    }
}
Esempio n. 12
0
function daynight_toggle()
{
    global $ext;
    global $amp_conf;
    global $version;
    $list = daynight_list();
    $passwords = daynight_passwords();
    $got_code = false;
    $day_recording = daynight_recording('day');
    $night_recording = daynight_recording('night');
    $id = "app-daynight-toggle";
    // The context to be included
    foreach ($list as $item) {
        $index = $item['ext'];
        $fcc = new featurecode('daynight', 'toggle-mode-' . $index);
        $c = $fcc->getCodeActive();
        unset($fcc);
        if (!$c) {
            continue;
        }
        $got_code = true;
        if ($amp_conf['USEDEVSTATE']) {
            $ext->addHint($id, $c, 'Custom:DAYNIGHT' . $index);
        }
        $ext->add($id, $c, '', new ext_macro('user-callerid'));
        $ext->add($id, $c, '', new ext_answer(''));
        $ext->add($id, $c, '', new ext_wait('1'));
        if (isset($passwords[$index]) && trim($passwords[$index]) != "" && ctype_digit(trim($passwords[$index]))) {
            $ext->add($id, $c, '', new ext_authenticate($passwords[$index]));
        }
        $ext->add($id, $c, '', new ext_setvar('INDEXES', $index));
        // Depends on featurecode.sln which is provided in core's sound files
        //
        $day_file = "beep&silence/1&featurecode&digits/{$index}&de-activated";
        $night_file = "beep&silence/1&featurecode&digits/{$index}&activated";
        if (function_exists('recordings_get_file')) {
            if ($day_recording[$index] != 0) {
                $day_file = recordings_get_file($day_recording[$index]);
            }
            if ($night_recording[$index] != 0) {
                $night_file = recordings_get_file($night_recording[$index]);
            }
        }
        $ext->add($id, $c, '', new ext_setvar('DAYREC', $day_file));
        $ext->add($id, $c, '', new ext_setvar('NIGHTREC', $night_file));
        $ext->add($id, $c, '', new ext_goto($id . ',s,1'));
    }
    if ($got_code) {
        $ext->addInclude('from-internal-additional', $id);
        // Add the include from from-internal
        $fcc = new featurecode('daynight', 'toggle-mode-all');
        $c = $fcc->getCodeActive();
        unset($fcc);
        if ($c) {
            $ext->add($id, $c, '', new ext_macro('user-callerid'));
            $ext->add($id, $c, '', new ext_goto($id . ',${EXTEN}*${AMPUSER},1'));
        }
        $c = 's';
        /* If any are on, all will be turned off.
         * Otherwise, all will be turned on.
         */
        $ext->add($id, $c, '', new ext_setvar('LOOPCNT', '${FIELDQTY(INDEXES,&)}'));
        $ext->add($id, $c, '', new ext_setvar('ITER', '1'));
        $ext->add($id, $c, 'begin1', new ext_setvar('INDEX', '${CUT(INDEXES,&,${ITER})}'));
        $ext->add($id, $c, '', new ext_setvar('MODE', '${DB(DAYNIGHT/C${INDEX})}'));
        $ext->add($id, $c, '', new ext_gotoif('$["${MODE}" != "NIGHT"]', 'end1'));
        $ext->add($id, $c, '', new ext_setvar('DAYNIGHTMODE', 'NIGHT'));
        $ext->add($id, $c, 'end1', new ext_setvar('ITER', '$[${ITER} + 1]'));
        $ext->add($id, $c, '', new ext_gotoif('$[${ITER} <= ${LOOPCNT}]', 'begin1'));
        $ext->add($id, $c, '', new ext_setvar('LOOPCNT', '${FIELDQTY(INDEXES,&)}'));
        $ext->add($id, $c, '', new ext_setvar('ITER', '1'));
        $ext->add($id, $c, 'begin2', new ext_setvar('INDEX', '${CUT(INDEXES,&,${ITER})}'));
        $ext->add($id, $c, '', new ext_gotoif('$["${DAYNIGHTMODE}" = "NIGHT"]', 'day', 'night'));
        $ext->add($id, $c, 'day', new ext_setvar('DB(DAYNIGHT/C${INDEX})', 'DAY'));
        if ($amp_conf['USEDEVSTATE']) {
            $ext->add($id, $c, '', new ext_setvar($amp_conf['AST_FUNC_DEVICE_STATE'] . '(Custom:DAYNIGHT${INDEX})', 'NOT_INUSE'));
        }
        $ext->add($id, $c, 'hook_day', new ext_goto('end2'));
        $ext->add($id, $c, 'night', new ext_setvar('DB(DAYNIGHT/C${INDEX})', 'NIGHT'));
        if ($amp_conf['USEDEVSTATE']) {
            $ext->add($id, $c, '', new ext_setvar($amp_conf['AST_FUNC_DEVICE_STATE'] . '(Custom:DAYNIGHT${INDEX})', 'INUSE'));
        }
        $ext->add($id, $c, 'hook_night', new ext_goto('end2'));
        $ext->add($id, $c, 'end2', new ext_setvar('ITER', '$[${ITER} + 1]'));
        $ext->add($id, $c, '', new ext_gotoif('$[${ITER} <= ${LOOPCNT}]', 'begin2'));
        if ($amp_conf['FCBEEPONLY']) {
            $ext->add($id, $c, '', new ext_playback('beep'));
            // $cmd,n,Playback(...)
        } else {
            $ext->add($id, $c, '', new ext_execif('$["${DAYNIGHTMODE}" = "NIGHT"]', 'Playback', '${DAYREC}', 'Playback', '${NIGHTREC}'));
        }
        $ext->add($id, $c, '', new ext_hangup(''));
    }
}
Esempio n. 13
0
function parking_get_config($engine)
{
    global $db;
    global $amp_conf;
    global $ext;
    // is this the best way to pass this?
    global $asterisk_conf;
    global $core_conf;
    global $version;
    switch ($engine) {
        case "asterisk":
            $contextname = 'park-dial';
            $parkinglot_id = 1;
            // only 1 parking lot, but prepare for future
            $results = parking_getconfig($parkinglot_id);
            // Got the array, let's go work out the required variables
            //
            $parkingenabled = isset($results['parkingenabled']) ? $results['parkingenabled'] : '';
            $parkext = isset($results['parkext']) ? $results['parkext'] : 70;
            $numslots = isset($results['numslots']) ? $results['numslots'] : 8;
            $parkingtime = isset($results['parkingtime']) ? $results['parkingtime'] : '';
            $parkingcontext = isset($results['parkingcontext']) ? $results['parkingcontext'] : 'parkedcalls';
            $parkalertinfo = isset($results['parkalertinfo']) ? $results['parkalertinfo'] : '';
            $parkcid = isset($results['parkcid']) ? $results['parkcid'] : '';
            $parkingannmsg_id = isset($results['parkingannmsg_id']) ? $results['parkingannmsg_id'] : '';
            $goto = isset($results['goto']) ? $results['goto'] : 'from-pstn,s,1';
            $parkpos1 = $parkext + 1;
            $parkpos2 = $parkpos1 + $numslots - 1;
            if ($parkingenabled) {
                // TODO: lookup ampportal.conf variables for this, don't hard code
                // first write features_additional.inc include file
                //
                $core_conf->addFeatureGeneral('parkext', $parkext);
                $core_conf->addFeatureGeneral('parkpos', $parkpos1 . "-" . $parkpos2);
                $core_conf->addFeatureGeneral('context', $parkingcontext);
                if ($parkingtime) {
                    $core_conf->addFeatureGeneral('parkingtime', $parkingtime);
                }
                // Now generate dialplan
                $ext->add($contextname, "t", '', new ext_noop('Parked Call Timed Out and Got Orphaned'));
                $ext->add($contextname, "_[0-9a-zA-Z*#].", '', new ext_noop('Parked Call Timed Out and Got Orphaned'));
                // If we have an appropriate Asterisk patch, set paraemters for Asterisk
                //
                if (isset($amp_conf["PARKINGPATCH"]) && strtolower($amp_conf["PARKINGPATCH"]) == 'true') {
                    if ($parkalertinfo) {
                        $core_conf->addFeatureGeneral('parkreturnalertinfo', $parkalertinfo);
                    }
                    if ($parkcid) {
                        $core_conf->addFeatureGeneral('parkreturncidprefix', $parkcid);
                    }
                    // No patch, do the default for orphaned calls
                } else {
                    if ($parkalertinfo) {
                        $ext->add($contextname, "t", '', new ext_setvar('__ALERT_INFO', str_replace(';', '\\;', $parkalertinfo)));
                        $ext->add($contextname, "_[0-9a-zA-Z*#].", '', new ext_setvar('__ALERT_INFO', str_replace(';', '\\;', $parkalertinfo)));
                    }
                    if ($parkcid) {
                        $ext->add($contextname, "t", '', new ext_setvar('CALLERID(name)', $parkcid . '${CALLERID(name)}'));
                        $ext->add($contextname, "_[0-9a-zA-Z*#].", '', new ext_setvar('CALLERID(name)', $parkcid . '${CALLERID(name)}'));
                    }
                }
                if ($parkingannmsg_id != '') {
                    $parkingannmsg = recordings_get_file($parkingannmsg_id);
                    $ext->add($contextname, "t", '', new ext_playback($parkingannmsg));
                    $ext->add($contextname, "_[0-9a-zA-Z*#].", '', new ext_playback($parkingannmsg));
                }
                // goto the destination here
                //
                $ext->add($contextname, "t", '', new ext_goto($goto));
                $ext->add($contextname, "_[0-9a-zA-Z*#].", '', new ext_goto($goto));
                // Asterisk 1.4 requires hints to be generated for parking
                //
                if (version_compare($version, "1.4", "ge")) {
                    $parkhints = 'park-hints';
                    $ext->addInclude('from-internal-additional', $parkhints);
                    // Add the include from from-internal
                    for ($slot = $parkpos1; $slot <= $parkpos2; $slot++) {
                        $ext->addHint($parkhints, $slot, "park:{$slot}@{$parkingcontext}");
                        $ext->add($parkhints, $slot, '', new ext_parkedcall($slot));
                    }
                }
            }
            break;
    }
}
Esempio n. 14
0
function daynight_toggle()
{
    global $ext;
    global $amp_conf;
    global $version;
    global $DEVSTATE;
    $DEVSTATE = version_compare($version, "1.6", "ge") ? "DEVICE_STATE" : "DEVSTATE";
    $list = daynight_list();
    $passwords = daynight_passwords();
    $got_code = false;
    $day_recording = daynight_recording('day');
    $night_recording = daynight_recording('night');
    $id = "app-daynight-toggle";
    // The context to be included
    foreach ($list as $item) {
        $index = $item['ext'];
        $fcc = new featurecode('daynight', 'toggle-mode-' . $index);
        $c = $fcc->getCodeActive();
        unset($fcc);
        if (!$c) {
            continue;
        }
        $got_code = true;
        if ($amp_conf['USEDEVSTATE']) {
            $ext->addHint($id, $c, 'Custom:DAYNIGHT' . $index);
        }
        $ext->add($id, $c, '', new ext_answer(''));
        $ext->add($id, $c, '', new ext_wait('1'));
        if (isset($passwords[$index]) && trim($passwords[$index]) != "" && ctype_digit(trim($passwords[$index]))) {
            $ext->add($id, $c, '', new ext_authenticate($passwords[$index]));
        }
        $ext->add($id, $c, '', new ext_setvar('INDEX', $index));
        $day_file = "beep&silence/1&day&reception&digits/{$index}&activated";
        $night_file = "beep&silence/1&day&reception&digits/{$index}&de-activated";
        if (function_exists('recordings_get_file')) {
            if ($day_recording[$index] != 0) {
                $day_file = recordings_get_file($day_recording[$index]);
            }
            if ($night_recording[$index] != 0) {
                $night_file = recordings_get_file($night_recording[$index]);
            }
        }
        $ext->add($id, $c, '', new ext_setvar('DAYREC', $day_file));
        $ext->add($id, $c, '', new ext_setvar('NIGHTREC', $night_file));
        $ext->add($id, $c, '', new ext_goto($id . ',s,1'));
    }
    if ($got_code) {
        $ext->addInclude('from-internal-additional', $id);
        // Add the include from from-internal
        $c = 's';
        $ext->add($id, $c, '', new ext_setvar('DAYNIGHTMODE', '${DB(DAYNIGHT/C${INDEX})}'));
        $ext->add($id, $c, '', new ext_gotoif('$["${DAYNIGHTMODE}" = "NIGHT"]', 'day', 'night'));
        $ext->add($id, $c, 'day', new ext_setvar('DB(DAYNIGHT/C${INDEX})', 'DAY'));
        if ($amp_conf['USEDEVSTATE']) {
            $ext->add($id, $c, '', new ext_setvar($DEVSTATE . '(Custom:DAYNIGHT${INDEX})', 'NOT_INUSE'));
        }
        if ($amp_conf['FCBEEPONLY']) {
            $ext->add($id, $c, 'hook_day', new ext_playback('beep'));
            // $cmd,n,Playback(...)
        } else {
            $ext->add($id, $c, 'hook_day', new ext_playback('${DAYREC}'));
        }
        $ext->add($id, $c, '', new ext_hangup(''));
        $ext->add($id, $c, 'night', new ext_setvar('DB(DAYNIGHT/C${INDEX})', 'NIGHT'));
        if ($amp_conf['USEDEVSTATE']) {
            $ext->add($id, $c, '', new ext_setvar($DEVSTATE . '(Custom:DAYNIGHT${INDEX})', 'INUSE'));
        }
        if ($amp_conf['FCBEEPONLY']) {
            $ext->add($id, $c, 'hook_night', new ext_playback('beep'));
            // $cmd,n,Playback(...)
        } else {
            $ext->add($id, $c, 'hook_night', new ext_playback('${NIGHTREC}'));
        }
        $ext->add($id, $c, '', new ext_hangup(''));
    }
}
Esempio n. 15
0
function queues_get_config($engine)
{
    global $ext;
    // is this the best way to pass this?
    global $amp_conf;
    global $version;
    $queues_conf = queues_conf::create();
    switch ($engine) {
        case "asterisk":
            global $astman;
            //set our reset cron
            queues_set_backup_cron();
            $ast_ge_14 = version_compare($version, '1.4', 'ge');
            $ast_ge_16 = version_compare($version, '1.6', 'ge');
            $ast_ge_14_25 = version_compare($version, '1.4.25', 'ge');
            $ast_ge_18 = version_compare($version, '1.8', 'ge');
            $ast_ge_11 = version_compare($version, '11', 'ge');
            $ast_ge_12 = version_compare($version, '12', 'ge');
            $has_extension_state = $ast_ge_16;
            if ($ast_ge_14 && !$ast_ge_16) {
                $response = $astman->send_request('Command', array('Command' => 'module show like func_extstate'));
                if (preg_match('/1 modules loaded/', $response['data'])) {
                    $has_extension_state = true;
                }
            }
            if (isset($queues_conf) && is_a($queues_conf, "queues_conf")) {
                $queues_conf->addQueuesGeneral('persistentmembers', $amp_conf['QUEUES_PESISTENTMEMBERS'] ? 'yes' : 'no');
                if ($ast_ge_16) {
                    $queues_conf->addQueuesGeneral('shared_lastcall', $amp_conf['QUEUES_SHARED_LASTCALL'] ? 'yes' : 'no');
                    $queues_conf->addQueuesGeneral('updatecdr', $amp_conf['QUEUES_UPDATECDR'] ? 'yes' : 'no');
                }
                if ($amp_conf['QUEUES_MIX_MONITOR']) {
                    $queues_conf->addQueuesGeneral('monitor-type', 'MixMonitor');
                }
            }
            /* queue extensions */
            $ext->addInclude('from-internal-additional', 'ext-queues');
            /* Trial DEVSTATE */
            $ext->addGlobal('QUEDEVSTATE', 'TRUE');
            $qlist = queues_list(true);
            if (empty($qlist)) {
                return;
                //nothing to do if we dont have any queues
            }
            // $que_code = '*45';
            $fcc = new featurecode('queues', 'que_toggle');
            $que_code = $fcc->getCodeActive();
            unset($fcc);
            if ($que_code != '') {
                queue_app_toggle();
                queue_app_all_toggle();
                queue_agent_del_toggle();
                queue_agent_add_toggle();
                $ext->addGlobal('QUEUETOGGLE', $que_code);
            }
            // $que_pause_code = '*46';
            $fcc = new featurecode('queues', 'que_pause_toggle');
            $que_pause_code = $fcc->getCodeActive();
            unset($fcc);
            if ($que_pause_code != '') {
                app_queue_pause_toggle();
                app_all_queue_pause_toggle();
                $ext->addGlobal('QUEUEPAUSETOGGLE', $que_pause_code);
            }
            // $que_callers_code = '*47';
            $fcc = new featurecode('queues', 'que_callers');
            $que_callers_code = $fcc->getCodeActive();
            unset($fcc);
            $from_queue_exten_only = 'from-queue-exten-only';
            $from_queue_exten_internal = 'from-queue-exten-internal';
            $qmembers = array();
            $hint_hash = array();
            $qlist = is_array($qlist) ? $qlist : array();
            foreach ($qlist as $item) {
                $exten = $item[0];
                $q = queues_get($exten);
                $c = 'ext-queues';
                $grppre = isset($q['prefix']) ? $q['prefix'] : '';
                $alertinfo = isset($q['alertinfo']) ? $q['alertinfo'] : '';
                // Not sure why someone would ever have a ; in the regex, but since Asterisk has problems with them
                // it would need to be escaped
                $qregex = isset($q['qregex']) ? $q['qregex'] : '';
                str_replace(';', '\\;', $qregex);
                $ext->add($c, $exten, '', new ext_macro('user-callerid'));
                if (isset($q['qnoanswer']) && $q['qnoanswer'] == FALSE) {
                    $ext->add($c, $exten, '', new ext_answer(''));
                } else {
                    // TODO: should this only be set if noanswer + (!ringtones || joinannounce)???
                    $ext->add($c, $exten, '', new ext_progress());
                }
                // block voicemail until phone is answered at which point a macro should be called on the answering
                // line to clear this flag so that subsequent transfers can occur.
                if ($q['queuewait']) {
                    $ext->add($c, $exten, '', new ext_execif('$["${QUEUEWAIT}" = ""]', 'Set', '__QUEUEWAIT=${EPOCH}'));
                }
                // If extension_only don't do this and CFIGNORE
                if ($q['use_queue_context'] != '2') {
                    $ext->add($c, $exten, '', new ext_macro('blkvm-set', 'reset'));
                    $ext->add($c, $exten, '', new ext_execif('$["${REGEX("(M[(]auto-blkvm[)])" ${DIAL_OPTIONS})}" != "1"]', 'Set', '_DIAL_OPTIONS=${DIAL_OPTIONS}M(auto-blkvm)'));
                }
                // Inform all the children NOT to send calls to destinations or voicemail
                //
                $ext->add($c, $exten, '', new ext_setvar('__NODEST', '${EXTEN}'));
                /*
                 * Virtual Queue Settings, dialplan designed so these can be changed by other modules and those changes
                 * will override the configured changes here.
                 */
                // deal with group CID prefix
                $ext->add($c, $exten, '', new ext_set('QCIDPP', '${IF($[${LEN(${VQ_CIDPP})}>0]?${VQ_CIDPP}' . ':' . ($grppre == '' ? ' ' : $grppre) . ')}'));
                $ext->add($c, $exten, '', new ext_set('VQ_CIDPP', ''));
                $ext->add($c, $exten, '', new ext_execif('$["${QCIDPP}"!=""]', 'Macro', 'prepend-cid,${QCIDPP}'));
                // Set Alert_Info
                $ainfo = $alertinfo != '' ? str_replace(';', '\\;', $alertinfo) : ' ';
                $ext->add($c, $exten, '', new ext_set('QAINFO', '${IF($[${LEN(${VQ_AINFO})}>0]?${VQ_AINFO}:' . $ainfo . ')}'));
                $ext->add($c, $exten, '', new ext_set('VQ_AINFO', ''));
                $ext->add($c, $exten, '', new ext_execif('$["${QAINFO}"!=""]', 'Set', '__ALERT_INFO=${QAINFO}'));
                $joinannounce_id = isset($q['joinannounce_id']) ? $q['joinannounce_id'] : '';
                $joinannounce = $joinannounce_id ? recordings_get_file($joinannounce_id) : ' ';
                $joinansw = isset($q['qnoanswer']) && $q['qnoanswer'] == TRUE ? 'noanswer' : '';
                $cplay = $q['skip_joinannounce'] ? ' && ${QUEUE_MEMBER(' . $exten . ',' . $q['skip_joinannounce'] . ')}<1' : '';
                $ext->add($c, $exten, '', new ext_set('QJOINMSG', '${IF($[${LEN(${VQ_JOINMSG})}>0]?${IF($["${VQ_JOINMSG}"!="0"]?${VQ_JOINMSG}: )}:' . $joinannounce . ')}'));
                $ext->add($c, $exten, '', new ext_set('VQ_JOINMSG', ''));
                $options = 't';
                if (isset($q['answered_elsewhere']) && $q['answered_elsewhere'] == '1') {
                    $ext->add($c, $exten, '', new ext_set('QCANCELMISSED', 'C'));
                }
                if ($q['rtone'] == 1) {
                    $qringopts = 'r';
                } else {
                    if ($q['rtone'] == 2) {
                        $qringopts = 'R';
                    } else {
                        $qringopts = '';
                    }
                }
                if ($qringopts) {
                    $ext->add($c, $exten, '', new ext_set('QRINGOPTS', $qringopts));
                }
                $qretry = $q['retry'] == 'none' ? 'n' : ' ';
                $ext->add($c, $exten, '', new ext_set('QRETRY', '${IF($[${LEN(${VQ_RETRY})}>0]?${VQ_RETRY}:' . $qretry . ')}'));
                $ext->add($c, $exten, '', new ext_set('VQ_RETRY', ''));
                $ext->add($c, $exten, 'qoptions', new ext_set('QOPTIONS', '${IF($[${LEN(${VQ_OPTIONS})}>0]?${VQ_OPTIONS}:' . ($options != '' ? $options : ' ') . ')}${QCANCELMISSED}${QRINGOPTS}${QRETRY}'));
                $ext->add($c, $exten, '', new ext_set('VQ_OPTIONS', ''));
                // Set these up to be easily spliced into if we want to configure ability in queue modules
                //
                $ext->add($c, $exten, 'qgosub', new ext_set('QGOSUB', '${IF($[${LEN(${VQ_GOSUB})}>0]?${VQ_GOSUB}:${QGOSUB})}'));
                $ext->add($c, $exten, '', new ext_set('VQ_GOSUB', ''));
                $ext->add($c, $exten, 'qagi', new ext_set('QAGI', '${IF($[${LEN(${VQ_AGI})}>0]?${VQ_AGI}:${QAGI})}'));
                $ext->add($c, $exten, '', new ext_set('VQ_AGI', ''));
                $ext->add($c, $exten, 'qrule', new ext_set('QRULE', '${IF($[${LEN(${VQ_RULE})}>0]?${IF($["${VQ_RULE}"!="0"]?${VQ_RULE}: )}:${QRULE})}'));
                $ext->add($c, $exten, '', new ext_set('VQ_RULE', ''));
                $ext->add($c, $exten, 'qposition', new ext_set('QPOSITION', '${IF($[${LEN(${VQ_POSITION})}>0]?${VQ_POSITION}:${QPOSITION})}'));
                $ext->add($c, $exten, '', new ext_set('VQ_POSITION', ''));
                if (!isset($q['recording']) || empty($q['recording'])) {
                    $record_mode = 'dontcare';
                } else {
                    $record_mode = $q['recording'];
                }
                if ($amp_conf['QUEUES_MIX_MONITOR']) {
                    $monitor_options = '';
                    if (isset($q['monitor_type']) && $q['monitor_type'] != '') {
                        $monitor_options .= 'b';
                    }
                    if (isset($q['monitor_spoken']) && $q['monitor_spoken'] != 0) {
                        $monitor_options .= 'V(' . $q['monitor_spoken'] . ')';
                    }
                    if (isset($q['monitor_heard']) && $q['monitor_heard'] != 0) {
                        $monitor_options .= 'v(' . $q['monitor_heard'] . ')';
                    }
                    if ($monitor_options != '') {
                        $ext->add($c, $exten, '', new ext_setvar('MONITOR_OPTIONS', $monitor_options));
                    }
                }
                $ext->add($c, $exten, '', new ext_gosub('1', 's', 'sub-record-check', "q,{$exten},{$record_mode}"));
                // Set CWIGNORE  if enabled so that busy agents don't have another line key ringing and
                // stalling the ACD.
                if ($q['cwignore'] == 1 || $q['cwignore'] == 2) {
                    $ext->add($c, $exten, '', new ext_setvar('__CWIGNORE', 'TRUE'));
                }
                if ($q['use_queue_context']) {
                    $ext->add($c, $exten, '', new ext_setvar('__CFIGNORE', 'TRUE'));
                    $ext->add($c, $exten, '', new ext_setvar('__FORWARD_CONTEXT', 'block-cf'));
                }
                $agentannounce_id = isset($q['agentannounce_id']) ? $q['agentannounce_id'] : '';
                if ($agentannounce_id) {
                    $agentannounce = recordings_get_file($agentannounce_id);
                } else {
                    $agentannounce = ' ';
                }
                if ($q['callconfirm'] == 1) {
                    $ext->add($c, $exten, '', new ext_setvar('__FORCE_CONFIRM', '${CHANNEL}'));
                    if ($amp_conf['AST_FUNC_SHARED']) {
                        $ext->add($c, $exten, '', new ext_setvar('SHARED(ANSWER_STATUS)', 'NOANSWER'));
                    }
                    $ext->add($c, $exten, '', new ext_setvar('__CALLCONFIRMCID', '${CALLERID(number)}'));
                    $callconfirm_id = isset($q['callconfirm_id']) ? $q['callconfirm_id'] : '';
                    if ($callconfirm_id) {
                        $callconfirm = recordings_get_file($callconfirm_id);
                    } else {
                        $callconfirm = ' ';
                    }
                    $ext->add($c, $exten, '', new ext_set('__ALT_CONFIRM_MSG', '${IF($[${LEN(${VQ_CONFIRMMSG})}>0]?${IF($["${VQ_CONFIRMMSG}"!="0"]?${VQ_CONFIRMMSG}: )}:' . $callconfirm . ')}'));
                    $ext->add($c, $exten, '', new ext_set('VQ_CONFIRMMSG', ''));
                }
                $ext->add($c, $exten, '', new ext_execif('$["${QJOINMSG}"!=""' . $cplay . ']', 'Playback', '${QJOINMSG}, ' . $joinansw));
                $ext->add($c, $exten, '', new ext_queuelog($exten, '${UNIQUEID}', 'NONE', 'DID', '${FROM_DID}'));
                $ext->add($c, $exten, '', new ext_set('QAANNOUNCE', '${IF($[${LEN(${VQ_AANNOUNCE})}>0]?${IF($["${VQ_AANNOUNCE}"!="0"]?${VQ_AANNOUNCE}: )}:' . $agentannounce . ')}'));
                $ext->add($c, $exten, '', new ext_set('VQ_AANNOUNCE', ''));
                $agnc = '${QAANNOUNCE}';
                $qmoh = isset($q['music']) && $q['music'] != '' ? $q['music'] : ' ';
                $ext->add($c, $exten, '', new ext_set('QMOH', '${IF($["${VQ_MOH}"!=""]?${VQ_MOH}:' . $qmoh . ')}'));
                $ext->add($c, $exten, '', new ext_set('VQ_MOH', ''));
                $ext->add($c, $exten, '', new ext_execif('$["${QMOH}"!=""]', 'Set', '__MOHCLASS=${QMOH}'));
                $ext->add($c, $exten, '', new ext_execif('$["${MOHCLASS}"!=""]', 'Set', 'CHANNEL(musicclass)=${MOHCLASS}'));
                $ext->add($c, $exten, '', new ext_set('QMAXWAIT', '${IF($[${LEN(${VQ_MAXWAIT})}>0]?${VQ_MAXWAIT}:' . ($q['maxwait'] != '' ? $q['maxwait'] : ' ') . ')}'));
                $ext->add($c, $exten, '', new ext_set('VQ_MAXWAIT', ''));
                $ext->add($c, $exten, '', new ext_set('QUEUENUM', $exten));
                $ext->add($c, $exten, '', new ext_set('QUEUEJOINTIME', '${EPOCH}'));
                $qmaxwait = '${QMAXWAIT}';
                $options = '${QOPTIONS}';
                $qagi = '${QAGI}';
                $qmacro = '';
                $qgosub = '${QGOSUB}';
                $qrule = '${QRULE}';
                $qposition = '${QPOSITION}';
                // Queue(queuename[,options[,URL[,announceoverride[,timeout[,AGI[,macro[,gosub[,rule[,position]]]]]]]]])
                //
                $ext->add($c, $exten, 'qcall', new ext_queue($exten, $options, '', $agnc, $qmaxwait, $qagi, $qmacro, $qgosub, $qrule, $qposition));
                if ($q['use_queue_context'] != '2') {
                    $ext->add($c, $exten, '', new ext_macro('blkvm-clr'));
                }
                // cancel any recording previously requested
                $ext->add($c, $exten, '', new ext_gosub('1', 's', 'sub-record-cancel'));
                // If we are here, disable the NODEST as we want things to resume as normal
                $ext->add($c, $exten, '', new ext_setvar('__NODEST', ''));
                $ext->add($c, $exten, '', new ext_setvar('_QUEUE_PRIO', '0'));
                if ($q['callconfirm'] == 1) {
                    if ($amp_conf['AST_FUNC_SHARED']) {
                        $ext->add($c, $exten, '', new ext_setvar('SHARED(ANSWER_STATUS)', ''));
                    }
                    $ext->add($c, $exten, '', new ext_setvar('__FORCE_CONFIRM', ''));
                    $ext->add($c, $exten, '', new ext_setvar('__ALT_CONFIRM_MSG', ''));
                }
                if ($monitor_options != '') {
                    $ext->add($c, $exten, '', new ext_setvar('MONITOR_OPTIONS', ''));
                }
                if ($q['cwignore'] == 1 || $q['cwignore'] == 2) {
                    $ext->add($c, $exten, '', new ext_setvar('__CWIGNORE', ''));
                }
                if ($q['use_queue_context']) {
                    $ext->add($c, $exten, '', new ext_setvar('__CFIGNORE', ''));
                    $ext->add($c, $exten, '', new ext_setvar('__FORWARD_CONTEXT', 'from-internal'));
                }
                if ($qringopts) {
                    $ext->add($c, $exten, '', new ext_set('QRINGOPTS', ''));
                }
                //VQ_DEST = str_replace(',','^',$vq['goto'])
                $ext->add($c, $exten, '', new ext_set('QDEST', '${VQ_DEST}'));
                $ext->add($c, $exten, '', new ext_set('VQ_DEST', ''));
                $ext->add($c, $exten, 'gotodest', new ext_gotoif('$["${QDEST}"=""]', $q['goto'], '${CUT(QDEST,^,1)},${CUT(QDEST,^,2)},${CUT(QDEST,^,3)}'));
                //dynamic agent login/logout
                if (trim($qregex) != '') {
                    $ext->add($c, $exten . "*", '', new ext_setvar('QREGEX', $qregex));
                }
                if ($amp_conf['GENERATE_LEGACY_QUEUE_CODES']) {
                    if ($q['use_queue_context'] == '2') {
                        $ext->add($c, $exten . "*", '', new ext_macro('agent-add', $exten . "," . $q['password'] . ",EXTEN"));
                    } else {
                        $ext->add($c, $exten . "*", '', new ext_macro('agent-add', $exten . "," . $q['password']));
                    }
                    $ext->add($c, $exten . "**", '', new ext_macro('agent-del', "{$exten}"));
                }
                if ($que_code != '') {
                    $ext->add($c, $que_code . $exten, '', new ext_setvar('QUEUENO', $exten));
                    $ext->add($c, $que_code . $exten, '', new ext_goto('start', 's', 'app-queue-toggle'));
                }
                if ($que_pause_code != '') {
                    $ext->add($c, $que_pause_code . $exten, '', new ext_gosub('1', 's', 'app-queue-pause-toggle', $exten));
                }
                /* Trial Devstate */
                // Create Hints for Devices and Add Astentries for Users
                // Clean up the Members array
                if ($q['togglehint'] && $que_code != '') {
                    if (!isset($device_list)) {
                        $device_list = core_devices_list("all", 'full', true);
                        $device_list = is_array($device_list) ? $device_list : array();
                    }
                    if ($astman) {
                        if (($dynmemberonly = strtolower($astman->database_get('QPENALTY/' . $exten, 'dynmemberonly')) == 'yes') == true) {
                            $get = $astman->database_show('QPENALTY/' . $exten . '/agents');
                            if (is_array($get)) {
                                $mem = array();
                                foreach ($get as $key => $value) {
                                    $key = explode('/', $key);
                                    $mem[$key[4]] = $value;
                                }
                            }
                        }
                    } else {
                        fatal("Cannot connect to Asterisk Manager with " . $amp_conf["AMPMGRUSER"] . "/" . $amp_conf["AMPMGRPASS"]);
                    }
                    $exten_str_len = strlen($exten);
                    $exten_str_tmp = str_repeat('X', $exten_str_len);
                    $que_code_len = strlen($que_code);
                    $device_list = !empty($device_list) ? $device_list : array();
                    foreach ($device_list as $device) {
                        if ((!$dynmemberonly || $device['devicetype'] == 'adhoc' || isset($mem[$device['user']])) && ($device['tech'] == 'sip' || $device['tech'] == 'iax2' || $device['tech'] == 'pjsip')) {
                            $dev_len = strlen($device['id']);
                            $dev_len_tmp = str_repeat('X', $dev_len);
                            $exten_pat = '_' . $que_code . $dev_len_tmp . '*' . $exten_str_tmp;
                            if (!in_array($exten_pat, $hint_hash)) {
                                $hint_hash[] = $exten_pat;
                                $ext->add($c, $exten_pat, '', new ext_setvar('QUEUENO', '${EXTEN:' . ($que_code_len + $dev_len + 1) . ":{$exten_str_len}}"));
                                $ext->add($c, $exten_pat, '', new ext_setvar('QUEUEUSER', '${EXTEN:' . "{$que_code_len}:{$dev_len}" . '}'));
                                $ext->add($c, $exten_pat, '', new ext_goto('start', 's', 'app-queue-toggle'));
                                $ext->addHint($c, $exten_pat, "Custom:QUEUE" . '${EXTEN:' . "{$que_code_len}}");
                                //TODO: dynamic hints
                            }
                        }
                    }
                }
                // Add routing vector to direct which context call should go
                //
                $agent_context = isset($q['use_queue_context']) && $q['use_queue_context'] && isset($queue_context) ? $queue_context : 'from-internal';
                switch ($q['use_queue_context']) {
                    case 1:
                        $agent_context = $from_queue_exten_internal;
                        break;
                    case 2:
                        $agent_context = $from_queue_exten_only;
                        break;
                    case 0:
                    default:
                        $agent_context = 'from-internal';
                        break;
                }
                $ext->add('from-queue', $exten, '', new ext_goto('1', '${QAGENT}', $agent_context));
                $q['member'] = is_array($q['member']) ? $q['member'] : array();
                foreach ($q['member'] as $qm) {
                    if (strtoupper(substr($qm, 0, 1)) == 'L') {
                        $tm = preg_replace("/[^0-9#\\,*]/", "", $qm);
                        $tma = explode(',', $tm);
                        $qmembers[$exten][] = $tma[0];
                    }
                }
            }
            if (!$amp_conf['DYNAMICHINTS'] && ($que_code != '' || $que_pause_code != '' || $que_callers_code != '')) {
                $qpenalty = $astman->database_show('QPENALTY');
                $qc = array();
                foreach (array_keys($qpenalty) as $key) {
                    $key = explode('/', $key);
                    if ($key[3] == 'agents') {
                        $qc[$key[4]][] = $key[2];
                    }
                }
                // Make sure we have all the devices
                //
                if (!isset($device_list)) {
                    $device_list = core_devices_list("all", 'full', true);
                    $device_list = is_array($device_list) ? $device_list : array();
                }
            }
            // Create *45 all queue toggle
            //
            if ($que_code != '') {
                $ext->add($c, $que_code, '', new ext_goto('start', 's', 'app-all-queue-toggle'));
                // create a generic one for any phones that don't get a specific one created since we only
                // create them for phones we know have queues but who knows what is provisioned on the phones
                //
                $ext->add($c, '_' . $que_code . '*X.', '', new ext_goto('start', 's', 'app-all-queue-toggle'));
                // generate with #exec if we are using dynamic hints
                //
                if ($amp_conf['DYNAMICHINTS']) {
                    $ext->addExec($c, $amp_conf['AMPBIN'] . '/generate_queue_hints.php ' . $que_code);
                } else {
                    $que_code_len = strlen($que_code);
                    $hlist = '';
                    foreach ($device_list as $device) {
                        $astman->database_del("AMPUSER/" . $device['id'], "queuehint");
                        //cleanup
                        if ($device['tech'] == 'sip' || $device['tech'] == 'iax2' || $device['tech'] == 'pjsip') {
                            if ($device['user'] != '' && isset($qc[$device['user']])) {
                                $hlist = 'Custom:QUEUE' . $device['id'] . '*' . implode('&Custom:QUEUE' . $device['id'] . '*', $qc[$device['user']]);
                                $astman->database_put("AMPUSER/" . $device['id'], "queuehint", $hlist);
                            }
                        }
                    }
                    $ext->addHint($c, '_' . $que_code . '*' . 'X.', '${DB(AMPUSER/${EXTEN:' . strlen($que_code . '*') . '}/queuehint)}');
                }
            }
            // Add the static members now since so far it only has dynamic members
            foreach ($qmembers as $q => $mems) {
                $mems = is_array($mems) ? $mems : array();
                foreach ($mems as $m) {
                    // If $m is not in qc already then add them, thus avoiding duplicates
                    if (!isset($qc[$m]) || !in_array($q, $qc[$m])) {
                        $qc[$m][] = (string) $q;
                    }
                }
            }
            // Create *46 codes/hints
            //
            if ($que_pause_code != '') {
                $ext->add($c, $que_pause_code, '', new ext_goto('1', 's', 'app-all-queue-pause-toggle'));
                // create a generic one for any phones that don't get a specific one created since we only
                // create them for phones we know have queues but who knows what is provisioned on the phones
                //
                $ext->add($c, '_' . $que_pause_code . '*X.', '', new ext_goto('1', 's', 'app-all-queue-pause-toggle'));
                // TODO: There's a bug here $q_pause_Local isn't initialized and shoudl be something.
                //       Currently this can't be made into a pattern since it's the $device['user'] but the hint has the device
                //
                $q_pause_len = strlen($que_pause_code);
                $device_list = isset($device_list) && is_array($device_list) ? $device_list : array();
                foreach ($device_list as $device) {
                    $astman->database_del("AMPUSER/" . $device['id'], "pausequeuehint");
                    if ($device['user'] != '') {
                        $pause_all_hints = array();
                        if (isset($qc[$device['user']])) {
                            foreach ($qc[$device['user']] as $q) {
                                if (!$amp_conf['DYNAMICHINTS'] && ($device['tech'] == 'pjsip' || $device['tech'] == 'sip' || $device['tech'] == 'iax2')) {
                                    // Do the real hints for below
                                    //
                                    if ($ast_ge_12) {
                                        $hint = "Queue:{$q}_pause_Local/{$device['user']}@from-queue/n";
                                    } else {
                                        $hint = "qpause:{$q}:Local/{$device['user']}@from-queue/n";
                                    }
                                    $pause_all_hints[] = $hint;
                                    $dev_len = strlen($device['id']);
                                    $dev_len_tmp = str_repeat('X', $dev_len);
                                    $exten_pat = "_{$que_pause_code}*{$dev_len_tmp}*{$q}";
                                    if (!in_array($exten_pat, $hint_hash)) {
                                        $hint_hash[] = $exten_pat;
                                        /*
                                        									exten => *46*1999*90000,1,Gosub(app-queue-pause-toggle,s,1(90000,1999))
                                        									exten => *46*1999*90000,hint,Queue:90000_pause_Local/1999@from-queue/n
                                        									${DB(DEVICE/${EXTEN:4:4}/user)}
                                        */
                                        $q_tmp = '${EXTEN:' . ($q_pause_len + $dev_len + 2) . '}';
                                        $d_tmp = '${DB(DEVICE/${EXTEN:' . ($q_pause_len + 1) . ":{$dev_len}}/user)}";
                                        if ($ast_ge_12) {
                                            $hint = "Queue:{$q_tmp}_pause_Local/{$d_tmp}@from-queue/n";
                                        } else {
                                            $hint = "qpause:{$q_tmp}:Local/{$d_tmp}@from-queue/n";
                                        }
                                        $ext->add($c, $exten_pat, '', new ext_gosub('1', 's', 'app-queue-pause-toggle', $q . ',' . $device['id']));
                                        $ext->addHint($c, $exten_pat, $hint);
                                    }
                                } else {
                                    $ext->add($c, $que_pause_code . '*' . $device['id'] . '*' . $q, '', new ext_gosub('1', 's', 'app-queue-pause-toggle', $q . ',' . $device['id']));
                                }
                            }
                        }
                        //$ext->add($c, $que_pause_code . '*' . $device['id'], '', new ext_goto('1','s','app-all-queue-pause-toggle'));
                        if (!empty($pause_all_hints)) {
                            $astman->database_put("AMPUSER/" . $device['id'], "pausequeuehint", implode('&', $pause_all_hints));
                        }
                    }
                }
                $ext->addHint($c, '_' . $que_pause_code . '*X.', '${DB(AMPUSER/${EXTEN:' . strlen($que_pause_code . '*') . '}/pausequeuehint)}');
            }
            // Create *47 codes/hints
            //
            if ($que_callers_code != '') {
                $id = "app-queue-caller-count";
                $ext->addInclude('from-internal-additional', $id);
                // Add the include from from-internal
                $ext->add($id, 's', '', new ext_answer());
                $ext->add($id, 's', '', new ext_wait(1));
                $ext->add($id, 's', '', new ext_setvar('QUEUES', '${ARG1}'));
                $ext->add($id, 's', '', new ext_setvar('COUNT', '0'));
                $ext->add($id, 's', '', new ext_setvar('LOOPCNT', '${FIELDQTY(QUEUES,&)}'));
                $ext->add($id, 's', '', new ext_setvar('ITER', '1'));
                $ext->add($id, 's', 'begin1', new ext_setvar('QUEUE', '${CUT(QUEUES,&,${ITER})}'));
                $ext->add($id, 's', '', new ext_setvar('COUNT', '$[${COUNT} + ${QUEUE_WAITING_COUNT(${QUEUE})}]'));
                $ext->add($id, 's', 'end1', new ext_setvar('ITER', '$[${ITER} + 1]'));
                $ext->add($id, 's', '', new ext_gotoif('$[${ITER} <= ${LOOPCNT}]', 'begin1'));
                $ext->add($id, 's', '', new ext_saynumber('${COUNT}'));
                $ext->add($id, 's', '', new ext_playback('queue-quantity2'));
                $ext->add($id, 's', '', new ext_return());
            }
            // We need to have a hangup here, if call is ended by the caller during Playback it will end in the
            // h context and do a proper hangup and clean the blkvm if set, see #4671
            $ext->add($c, 'h', '', new ext_macro('hangupcall'));
            // NODEST will be the queue that this came from, so we will vector though an entry to determine the context the
            // agent should be delivered to. All queue calls come here, this decides if the should go direct to from-internal
            // or indirectly through from-queue-exten-only to trap extension calls and avoid their follow-me, etc.
            //
            $ext->add('from-queue', '_.', '', new ext_setvar('QAGENT', '${EXTEN}'));
            $ext->add('from-queue', '_.', '', new ext_setvar('__FROMQ', 'true'));
            //see below comments
            $ext->add('from-queue', '_.', '', new ext_goto('1', '${NODEST}'));
            //http://issues.freepbx.org/browse/FREEPBX-11871
            //Because of local channel changes in Asterisk 12+ we end up losing track of our recording file
            //This effectively "gives" back the recording file to the channel that answered the queue
            if ($ast_ge_12) {
                $ext->splice('macro-auto-blkvm', 's', 1, new ext_execif('$["${FROMQ}" = "true" & "${CALLFILENAME}" != "" & "${CDR(recordingfile)}" = ""]', 'Set', 'CDR(recordingfile)=${CALLFILENAME}.${MON_FMT}'));
            }
            $ext->addInclude($from_queue_exten_only . '-x', 'from-internal');
            $ext->add($from_queue_exten_only . '-x', 'foo', '', new ext_noop('bar'));
            $ext->addInclude($from_queue_exten_internal, $from_queue_exten_only);
            $ext->addInclude($from_queue_exten_internal, $from_queue_exten_only . '-x');
            $ext->addInclude($from_queue_exten_internal, 'from-internal');
            $ext->add($from_queue_exten_internal, 'foo', '', new ext_noop('bar'));
            /* create a context, from-queue-exten-only, that can be used for queues that want behavir similar to
             * ringgroup where only the agent's phone will be rung, no follow-me will be pursued.
             */
            $sql = "SELECT LENGTH(extension) as len FROM users GROUP BY len";
            $sth = FreePBX::Database()->prepare($sql);
            $sth->execute();
            $rows = $sth->fetchAll(\PDO::FETCH_ASSOC);
            foreach ($rows as $row) {
                //make sure exten exists
                $ext->add($from_queue_exten_only, '_' . str_repeat('X', $row['len']), '', new ext_gotoif('$[${DB_EXISTS(AMPUSER/${EXTEN}/cidnum)} = 0]', $from_queue_exten_only . '-x,${EXTEN},1'));
                $ext->add($from_queue_exten_only, '_' . str_repeat('X', $row['len']), '', new ext_set('RingGroupMethod', 'none'));
                $ext->add($from_queue_exten_only, '_' . str_repeat('X', $row['len']), '', new ext_set('QDOPTS', '${IF($["${CALLER_DEST}"!=""]?g)}${IF($["${AGENT_DEST}"!=""]?F(${AGENT_DEST}))}'));
                $ext->add($from_queue_exten_only, '_' . str_repeat('X', $row['len']), 'checkrecord', new ext_set('CALLTYPE_OVERRIDE', 'external'));
                // Make sure the call is tagged as external
                // This means:
                // If (!$fromexten) { if (!$nodest) { $fromexten = 'external' } else { $fromexten = $nodest } }
                $ext->add($from_queue_exten_only, '_' . str_repeat('X', $row['len']), '', new ext_execif('$[!${LEN(${FROMEXTEN})}]', 'Set', 'FROMEXTEN=${IF(${LEN(${NODEST})}?${NODEST}:external)}'));
                // Make sure the call is tagged as external
                $ext->add($from_queue_exten_only, '_' . str_repeat('X', $row['len']), '', new ext_gosub('1', 's', 'sub-record-check', 'exten,${EXTEN},'));
                if ($has_extension_state) {
                    $ext->add($from_queue_exten_only, '_' . str_repeat('X', $row['len']), '', new ext_macro('dial-one', ',${DIAL_OPTIONS}${QDOPTS},${EXTEN}'));
                } else {
                    $ext->add($from_queue_exten_only, '_' . str_repeat('X', $row['len']), '', new ext_macro('dial', ',${DIAL_OPTIONS}${QDOPTS},${EXTEN}'));
                }
                $ext->add($from_queue_exten_only, '_' . str_repeat('X', $row['len']), '', new ext_gotoif('$["${CALLER_DEST}"!=""&&"${DIALSTATUS}"="ANSWER"]', '${CUT(CALLER_DEST,^,1)},${CUT(CALLER_DEST,^,2)},${CUT(CALLER_DEST,^,3)}'));
                $ext->add($from_queue_exten_only, '_' . str_repeat('X', $row['len']), '', new ext_hangup());
            }
            if (!empty($rows)) {
                $ext->add($from_queue_exten_only, 'h', '', new ext_macro('hangupcall'));
            }
            /*
             * Adds a dynamic agent/member to a Queue
             * Prompts for call-back number - in not entered, uses CIDNum
             */
            if ($amp_conf['GENERATE_LEGACY_QUEUE_CODES']) {
                $c = 'macro-agent-add';
                // for i18n playback in multiple languages
                $ext->add($c, 'lang-playback', '', new ext_gosubif('$[${DIALPLAN_EXISTS(' . $c . ',${CHANNEL(language)})}]', $c . ',${CHANNEL(language)},${ARG1}', $c . ',en,${ARG1}'));
                $ext->add($c, 'lang-playback', '', new ext_return());
                $exten = 's';
                $ext->add($c, $exten, '', new ext_wait(1));
                $ext->add($c, $exten, '', new ext_set('QUEUENO', '${ARG1}'));
                $ext->add($c, $exten, '', new ext_macro('user-callerid', 'SKIPTTL'));
                $ext->add($c, $exten, 'a3', new ext_read('CALLBACKNUM', 'agent-login'));
                // get callback number from user
                $ext->add($c, $exten, '', new ext_gotoif('$[${LEN(${CALLBACKNUM})}=0]', 'a5', 'a7'));
                // if user just pressed # or timed out, use cidnum
                $ext->add($c, $exten, 'a5', new ext_set('CALLBACKNUM', '${IF($[${LEN(${AMPUSER})}=0]?${CALLERID(number)}:${AMPUSER})}'));
                $ext->add($c, $exten, '', new ext_set('THISDEVICE', '${DB(DEVICE/${REALCALLERIDNUM}/dial)}'));
                $ext->add($c, $exten, '', new ext_gotoif('$["${CALLBACKNUM}" = ""]', 'a3'));
                // if still no number, start over
                $ext->add($c, $exten, 'a7', new ext_gotoif('$["${CALLBACKNUM}" = "${QUEUENO}"]', 'invalid'));
                // Error, they put in the queue number
                // If this is an extension only queue then EXTEN is passed as ARG3 and we make sure this is a valid extension being entered
                $ext->add($c, $exten, '', new ext_gotoif('$["${ARG3}" = "EXTEN" & ${DB_EXISTS(AMPUSER/${CALLBACKNUM}/cidname)} = 0]', 'invalid'));
                // If this is a restricted dynamic agent queue then check to make sure they are allowed
                $ext->add($c, $exten, '', new ext_gotoif('$["${DB(QPENALTY/${QUEUENO}/dynmemberonly)}" = "yes" & ${DB_EXISTS(QPENALTY/${QUEUENO}/agents/${CALLBACKNUM})} != 1]', 'invalid'));
                $ext->add($c, $exten, '', new ext_execif('$["${QREGEX}" != ""]', 'GotoIf', '$["${REGEX("${QREGEX}" ${CALLBACKNUM})}" = "0"]?invalid'));
                $ext->add($c, $exten, '', new ext_execif('$["${ARG2}" != ""]', 'Authenticate', '${ARG2}'));
                $ext->add($c, $exten, '', new ext_set('STATE', 'INUSE'));
                $ext->add($c, $exten, '', new ext_gosub('1', 'sstate', 'app-queue-toggle'));
                $ext->add($c, $exten, '', new ext_execif('$[${DB_EXISTS(AMPUSER/${CALLBACKNUM}/cidname)} = 1 & "${DB(AMPUSER/${CALLBACKNUM}/queues/qnostate)}" != "ignorestate"]', 'AddQueueMember', '${QUEUENO},Local/${CALLBACKNUM}@from-queue/n,${DB(QPENALTY/${QUEUENO}/agents/${CALLBACKNUM})},,${DB(AMPUSER/${CALLBACKNUM}/cidname)},hint:${CALLBACKNUM}@ext-local'));
                $ext->add($c, $exten, '', new ext_execif('$[${DB_EXISTS(AMPUSER/${CALLBACKNUM}/cidname)} = 1 & "${DB(AMPUSER/${CALLBACKNUM}/queues/qnostate)}" = "ignorestate"]', 'AddQueueMember', '${QUEUENO},Local/${CALLBACKNUM}@from-queue/n,${DB(QPENALTY/${QUEUENO}/agents/${CALLBACKNUM})},,${DB(AMPUSER/${CALLBACKNUM}/cidname)}'));
                $ext->add($c, $exten, '', new ext_execif('$[${DB_EXISTS(AMPUSER/${CALLBACKNUM}/cidname)} = 0]', 'AddQueueMember', '${QUEUENO},Local/${CALLBACKNUM}@from-queue/n,${DB(QPENALTY/${QUEUENO}/agents/${CALLBACKNUM})}'));
                $ext->add($c, $exten, '', new ext_userevent('Agentlogin', 'Agent: ${CALLBACKNUM}'));
                $ext->add($c, $exten, '', new ext_wait(1));
                $ext->add($c, $exten, '', new ext_gosub('1', 'lang-playback', $c, 'hook_0'));
                $ext->add($c, $exten, '', new ext_hangup());
                $ext->add($c, $exten, '', new ext_macroexit());
                $ext->add($c, $exten, 'invalid', new ext_playback('pbx-invalid'));
                $ext->add($c, $exten, '', new ext_goto('a3'));
                $lang = 'en';
                // English
                $ext->add($c, $lang, 'hook_0', new ext_playback('agent-loginok&with&extension'));
                $ext->add($c, $lang, '', new ext_saydigits('${CALLBACKNUM}'));
                $ext->add($c, $lang, '', new ext_return());
                $lang = 'ja';
                // Japanese
                $ext->add($c, $lang, 'hook_0', new ext_playback('extension'));
                $ext->add($c, $lang, '', new ext_saydigits('${CALLBACKNUM}'));
                $ext->add($c, $lang, '', new ext_playback('jp-kara&agent-loginok'));
                $ext->add($c, $lang, '', new ext_return());
                /*
                 * Removes a dynamic agent/member from a Queue
                 * Prompts for call-back number - in not entered, uses CIDNum
                 */
                $c = 'macro-agent-del';
                $ext->add($c, $exten, '', new ext_wait(1));
                $ext->add($c, $exten, '', new ext_set('QUEUENO', '${ARG1}'));
                $ext->add($c, $exten, '', new ext_macro('user-callerid', 'SKIPTTL'));
                $ext->add($c, $exten, 'a3', new ext_read('CALLBACKNUM', 'agent-logoff'));
                // get callback number from user
                $ext->add($c, $exten, '', new ext_gotoif('$[${LEN(${CALLBACKNUM})}=0]', 'a5', 'a7'));
                // if user just pressed # or timed out, use cidnum
                $ext->add($c, $exten, 'a5', new ext_set('CALLBACKNUM', '${IF($[${LEN(${AMPUSER})}=0]?${CALLERID(number)}:${AMPUSER})}'));
                $ext->add($c, $exten, '', new ext_gotoif('$["${CALLBACKNUM}" = ""]', 'a3'));
                // if still no number, start over
                $ext->add($c, $exten, '', new ext_set('STATE', 'NOT_INUSE'));
                $ext->add($c, $exten, '', new ext_gosub('1', 'sstate', 'app-queue-toggle'));
                // remove from both contexts in case left over dynamic agents after an upgrade
                $ext->add($c, $exten, 'a7', new ext_removequeuemember('${QUEUENO}', 'Local/${CALLBACKNUM}@from-queue/n'));
                $ext->add($c, $exten, '', new ext_removequeuemember('${QUEUENO}', 'Local/${CALLBACKNUM}@from-internal/n'));
                $ext->add($c, $exten, '', new ext_userevent('RefreshQueue'));
                $ext->add($c, $exten, '', new ext_wait(1));
                $ext->add($c, $exten, '', new ext_playback('agent-loggedoff'));
                $ext->add($c, $exten, '', new ext_hangup());
            }
            // GENERATE_LEGACY_QUEUE_CODES
            break;
    }
}
Esempio n. 16
0
function recordings_delete_file($id, $src)
{
    $files = recordings_get_file($id);
    $tmparr = explode('&', $files);
    $tmp = array();
    $counter = 0;
    foreach ($tmparr as $file) {
        if ($counter != $src) {
            $tmp[] = $file;
        }
        $counter++;
    }
    recordings_set_file($id, implode('&', $tmp));
}
Esempio n. 17
0
function parking_generate_sub_return_routing($lot, $pd)
{
    global $ext;
    $parkpos1 = $lot['parkpos'];
    $parkpos2 = $parkpos1 + $lot['numslots'] - 1;
    $prr = 'park-return-routing';
    $pexten = $lot['parkext'];
    $ext->add($prr, $pexten, '', new ext_set('PLOT', $pexten));
    if ($lot['alertinfo']) {
        $ext->add($prr, $pexten, '', new ext_sipremoveheader('Alert-Info:'));
        $ext->add($prr, $pexten, '', new ext_sipaddheader('Alert-Info', str_replace(';', '\\;', $lot['alertinfo'])));
    }
    // Prepend options are parkingslot they were parked on, or the extension number or user name of the user who parked them
    //
    switch ($lot['autocidpp']) {
        case 'slot':
            $autopp = '${PARKINGSLOT}:';
            break;
        case 'exten':
            $ext->add($prr, $pexten, '', new ext_gosub('1', 's', 'sub-park-user'));
            $autopp = '${UEXTEN}:';
            break;
        case 'name':
            $ext->add($prr, $pexten, '', new ext_gosub('1', 's', 'sub-park-user'));
            $autopp = '${UNAME}:';
            break;
        default:
            $autopp = '';
            break;
    }
    if ($lot['cidpp'] || $autopp != '') {
        $cidpp = $lot['cidpp'] . $autopp;
        $ext->add($prr, $pexten, '', new ext_execif('$[${LEN(${PREPARK_CID})} = 0]', 'Set', 'PREPARK_CID=${CALLERID(name)}'));
        $ext->add($prr, $pexten, '', new ext_set('CALLERID(name)', $cidpp . '${PREPARK_CID}'));
    }
    if ($lot['announcement_id']) {
        $parkingannmsg = recordings_get_file($lot['announcement_id']);
        $ext->add($prr, $pexten, '', new ext_playback($parkingannmsg));
    }
    // If comeback to origin is set then send the call back to the parking target
    // This is our workaround so that we can send Alert-Info and Prepend on a comeback to origin request
    // The default method in Asterisk will not let us send or setup alert-info or prepend anything
    if ($lot['comebacktoorigin'] == 'yes') {
        /*
        //If we detect PARKCALLBACK then we are coming from a transfer and thus we have no PARK_TARGET set
        $ext->add($prr, $pexten, '', new ext_gotoif('$[${LEN(${PARKCALLBACK})} > 0]','transfercallback'));
                //$ext->add($prr, $pexten, '', new ext_goto($pd . ',${PARK_TARGET},1'));
                //The below string is pretty lame and will cause issues with PJSIP (maybe?)
                //But in Asterisk 12 PARK_TARGET (as a goto, see above) is not working right so we are going to
                //just string replace what we want and hope for the best until this is resolved
        $ext->add($prr, $pexten, '', new ext_dial('${REPLACE(PARK_TARGET,_,/)},15'));
        $ext->add($prr, $pexten, '', new ext_goto('next'));
        $ext->add($prr, $pexten, 'transfercallback', new ext_noop('Yes'));
        $ext->add($prr, $pexten, '', new ext_dial('${PARKCALLBACK},15'));
        $ext->add($prr, $pexten, '', new ext_goto('next'));
        */
        $ext->add($prr, $pexten, '', new ext_dial('${PARKCALLBACK},15'));
        $ext->add($prr, $pexten, '', new ext_set('PARKCALLBACK', ''));
        //$ext->add($prr, $pexten, '', new ext_goto('next'));
    }
    // If comback to origin wasn't set or if we have already tried that.
    if (empty($lot['dest'])) {
        $ext->add($prr, $pexten, '', new ext_noop('ERROR: No Alternate Destination Available for Orphaned Call'));
        $ext->add($prr, $pexten, '', new ext_playback('sorry&an-error-has-occured'));
        $ext->add($prr, $pexten, '', new ext_hangup(''));
    } else {
        $ext->add($prr, $pexten, '', new ext_goto($lot['dest']));
    }
    // Route park-return-routing from slot to PARK_TARGET:
    for ($slot = $parkpos1; $slot <= $parkpos2; $slot++) {
        $ext->add($prr, $slot, '', new ext_goto('1', $pexten));
    }
}
Esempio n. 18
0
function core_do_get_config($engine)
{
    global $ext;
    // is this the best way to pass this?
    global $version;
    // this is not the best way to pass this, this should be passetd together with $engine
    global $engineinfo;
    global $amp_conf;
    global $core_conf;
    global $chan_dahdi;
    global $chan_dahdi_loaded;
    global $astman;
    $modulename = "core";
    $callrecording = 'callrecording';
    $callrecording_uid = 'MISSING_CALLRECORDINGS';
    $getCallRecordingModInfo = module_getinfo($callrecording, MODULE_STATUS_ENABLED);
    $nt = notifications::create();
    if (!isset($getCallRecordingModInfo[$callrecording]) || $getCallRecordingModInfo[$callrecording]['status'] !== MODULE_STATUS_ENABLED) {
        if (!$nt->exists($modulename, $callrecording_uid)) {
            $nt->add_notice($modulename, $callrecording_uid, _('Call Recording Module Not Enabled'), _('The Call Recording module is not enabled. Since this feature is required for call recording you may not be able to record calls until the module is installed and enabled.'), '', true, true);
        }
    } else {
        if ($nt->exists($modulename, $callrecording_uid)) {
            $nt->delete($modulename, $callrecording_uid);
        }
    }
    switch ($engine) {
        case "asterisk":
            $ast_ge_14 = version_compare($version, '1.4', 'ge');
            $ast_lt_16 = version_compare($version, '1.6', 'lt');
            $ast_lt_161 = version_compare($version, '1.6.1', 'lt');
            $ast_ge_162 = version_compare($version, '1.6.2', 'ge');
            $ast_ge_10 = version_compare($version, '10', 'ge');
            // Now add to sip_general_addtional.conf
            //
            if (isset($core_conf) && is_a($core_conf, "core_conf")) {
                $useragent = $amp_conf['SIPUSERAGENT'] . '-' . getversion() . "({$version})";
                $core_conf->addIaxGeneral('disallow', 'all');
                $core_conf->addIaxGeneral('allow', 'ulaw');
                $core_conf->addIaxGeneral('allow', 'alaw');
                $core_conf->addIaxGeneral('allow', 'gsm');
                $core_conf->addIaxGeneral('mailboxdetail', 'yes');
                if ($ast_ge_14) {
                    $core_conf->addIaxGeneral('tos', 'ef');
                    // Recommended setting from doc/ip-tos.txt
                }
                $fcc = new featurecode($modulename, 'blindxfer');
                $code = $fcc->getCodeActive();
                unset($fcc);
                $core_conf->addFeatureMap('blindxfer', $code);
                $fcc = new featurecode($modulename, 'atxfer');
                $code = $fcc->getCodeActive();
                unset($fcc);
                $core_conf->addFeatureMap('atxfer', $code);
                $fcc = new featurecode($modulename, 'automon');
                $code = $fcc->getCodeActive();
                unset($fcc);
                if ($code != '') {
                    $core_conf->addFeatureMap('automon', $code);
                    //references app record
                    $core_conf->addApplicationMap('apprecord', $code . ',caller,Macro,one-touch-record', true);
                    /* At this point we are not using hints since we have not found a good way to be always
                     * consistent on both sides of the channel
                     *
                     * $ext->addInclude('from-internal-additional', 'device-hints');
                     * $device_list = core_devices_list("all", 'full', true);
                     * foreach ($device_list as $device) {
                     * 	if ($device['tech'] == 'sip' || $device['tech'] == 'iax2') {
                     *    $ext->add('device-hints', $code.$device['id'], '', new ext_noop("AutoMixMon Hint for: ".$device['id']));
                     *    $ext->addHint('device-hints', $code.$device['id'], "Custom:RECORDING".$device['id']);
                     *   }
                     * }
                     */
                }
                $fcc = new featurecode($modulename, 'disconnect');
                $code = $fcc->getCodeActive();
                unset($fcc);
                $core_conf->addFeatureMap('disconnect', $code);
                $fcc = new featurecode($modulename, 'pickupexten');
                $code = $fcc->getCodeActive();
                unset($fcc);
                $core_conf->addFeatureGeneral('pickupexten', $code);
            }
            // FeatureCodes
            $fcc = new featurecode($modulename, 'userlogon');
            $fc_userlogon = $fcc->getCodeActive();
            unset($fcc);
            $fcc = new featurecode($modulename, 'userlogoff');
            $fc_userlogoff = $fcc->getCodeActive();
            unset($fcc);
            global $version;
            if (version_compare($version, "12.5", "<")) {
                $fcc = new featurecode($modulename, 'zapbarge');
                $fc_zapbarge = $fcc->getCodeActive();
                unset($fcc);
            }
            $fcc = new featurecode($modulename, 'chanspy');
            $fc_chanspy = $fcc->getCodeActive();
            unset($fcc);
            $fcc = new featurecode($modulename, 'simu_pstn');
            $fc_simu_pstn = $fcc->getCodeActive();
            unset($fcc);
            $fcc = new featurecode($modulename, 'pickup');
            $fc_pickup = $fcc->getCodeActive();
            unset($fcc);
            // Log on / off -- all in one context
            if ($fc_userlogoff != '' || $fc_userlogon != '') {
                $ext->addInclude('from-internal-additional', 'app-userlogonoff');
                // Add the include from from-internal
                if ($fc_userlogoff != '') {
                    $ext->add('app-userlogonoff', $fc_userlogoff, '', new ext_macro('user-logoff'));
                    $ext->add('app-userlogonoff', $fc_userlogoff, 'hook_off', new ext_hangup(''));
                }
                if ($fc_userlogon != '') {
                    $ext->add('app-userlogonoff', $fc_userlogon, '', new ext_macro('user-logon'));
                    $ext->add('app-userlogonoff', $fc_userlogon, 'hook_on_1', new ext_hangup(''));
                    $clen = strlen($fc_userlogon);
                    $fc_userlogon = "_{$fc_userlogon}.";
                    $ext->add('app-userlogonoff', $fc_userlogon, '', new ext_macro('user-logon,${EXTEN:' . $clen . '}'));
                    $ext->add('app-userlogonoff', $fc_userlogon, 'hook_on_2', new ext_hangup(''));
                }
            }
            // FREEPBX-7280 - macro-dial
            include 'functions.inc/macro-dial.php';
            /* This needs to be before outbound-routes since they can have a wild-card in them
            		*
            		;------------------------------------------------------------------------
            		; [ext-local-confirm]
            		;------------------------------------------------------------------------
            		; If call confirm is being used in a ringgroup, then calls that do not require confirmation are sent
            		; to this extension instead of straight to the device.
            		;
            		; The sole purpose of sending them here is to make sure we run Macro(auto-confirm) if this
            		; extension answers the line. This takes care of clearing the database key that is used to inform
            		; other potential late comers that the extension has been answered by someone else.
            		;
            		; ALERT_INFO is deprecated in Asterisk 1.4 but still used throughout the FreePBX dialplan and
            		; usually set by dialparties.agi. This allows inheritance. Since no dialparties.agi here, set the
            		; header if it is set.
            		;
            		;------------------------------------------------------------------------
            		*/
            $context = 'ext-local-confirm';
            $ext->addInclude('from-internal-additional', $context);
            // Add the include from from-internal
            $exten = '_LC-.';
            $ext->add($context, $exten, '', new ext_noop_trace('IN ' . $context . ' with - RT: ${RT}, RG_IDX: ${RG_IDX}'));
            //dont allow inbound callers to transfer around inside the system
            $ext->add($context, $exten, '', new ext_execif('$["${DIRECTION}" = "INBOUND"]', 'Set', 'DIAL_OPTIONS=${STRREPLACE(DIAL_OPTIONS,T)}I'));
            $ext->add($context, $exten, '', new ext_set('THISDIAL', '${DB(DEVICE/${EXTEN:3}/dial)}'));
            $ext->add($context, $exten, '', new ext_gotoif('$["${THISDIAL:0:5}"!="PJSIP"]', 'dial'));
            $ext->add($context, $exten, '', new ext_noop('Debug: Found PJSIP Destination ${THISDIAL}, updating with PJSIP_DIAL_CONTACTS'));
            $ext->add($context, $exten, '', new ext_set('THISDIAL', '${PJSIP_DIAL_CONTACTS(${EXTEN:3})}'));
            $ext->add($context, $exten, 'dial', new ext_dial('${THISDIAL}', '${RT},${DIAL_OPTIONS}M(auto-confirm^${RG_IDX})b(func-apply-sipheaders^s^1)'));
            /* This needs to be before outbound-routes since they can have a wild-card in them
            		*
            		;------------------------------------------------------------------------
            		; [findmefollow-ringallv2]
            		;------------------------------------------------------------------------
            		; This context, to be included in from-internal, implements the PreRing part of findmefollow
            		; as well as the GroupRing part. It also communicates between the two so that if DND is set
            		; on the primary extension, and mastermode is enabled, then the other extensions will not ring
            		;
            		;------------------------------------------------------------------------
            		*/
            $context = 'findmefollow-ringallv2';
            $ext->addInclude('from-internal-additional', $context);
            // Add the include from from-internal
            $exten = '_FMPR-.';
            $fm_dnd = $amp_conf['AST_FUNC_SHARED'] ? 'SHARED(FM_DND,${FMUNIQUE})' : 'DB(FM/DND/${FMGRP}/${FMUNIQUE})';
            $ext->add($context, $exten, '', new ext_nocdr(''));
            $ext->add($context, $exten, '', new ext_noop_trace('In FMPR ${FMGRP} with ${EXTEN:5}'));
            $ext->add($context, $exten, '', new ext_set('RingGroupMethod', ''));
            $ext->add($context, $exten, '', new ext_set('USE_CONFIRMATION', ''));
            $ext->add($context, $exten, '', new ext_set('RINGGROUP_INDEX', ''));
            $ext->add($context, $exten, '', new ext_macro('simple-dial', '${EXTEN:5},${FMREALPRERING}'));
            $ext->add($context, $exten, '', new ext_execif('$["${DIALSTATUS}" = "BUSY"]', 'Set', "{$fm_dnd}=DND"));
            $ext->add($context, $exten, '', new ext_noop_trace('Ending FMPR ${FMGRP} with ${EXTEN:5} and dialstatus ${DIALSTATUS}'));
            $ext->add($context, $exten, '', new ext_hangup(''));
            $exten = '_FMGL-.';
            $ext->add($context, $exten, '', new ext_nocdr(''));
            $ext->add($context, $exten, '', new ext_noop_trace('In FMGL ${FMGRP} with ${EXTEN:5}'));
            $ext->add($context, $exten, '', new ext_set('ENDLOOP', '$[${EPOCH} + ${FMPRERING} + 2]'));
            $ext->add($context, $exten, 'start', new ext_gotoif('$["${' . $fm_dnd . '}" = "DND"]', 'dodnd'));
            $ext->add($context, $exten, '', new ext_wait('1'));
            $ext->add($context, $exten, '', new ext_noop_trace('FMGL wait loop: ${EPOCH} / ${ENDLOOP}', 6));
            $ext->add($context, $exten, '', new ext_gotoif('$[${EPOCH} < ${ENDLOOP}]', 'start'));
            if ($amp_conf['AST_FUNC_SHARED']) {
                $ext->add($context, $exten, '', new ext_set($fm_dnd, ''));
            } else {
                $ext->add($context, $exten, '', new ext_dbdel($fm_dnd));
            }
            $ext->add($context, $exten, 'dodial', new ext_macro('dial', '${FMGRPTIME},${DIAL_OPTIONS},${EXTEN:5}'));
            $ext->add($context, $exten, '', new ext_noop_trace('Ending FMGL ${FMGRP} with ${EXTEN:5} and dialstatus ${DIALSTATUS}'));
            $ext->add($context, $exten, '', new ext_hangup(''));
            // n+10(dodnd):
            if ($amp_conf['AST_FUNC_SHARED']) {
                $ext->add($context, $exten, 'dodnd', new ext_set($fm_dnd, ''), 'n', 10);
            } else {
                $ext->add($context, $exten, 'dodnd', new ext_dbdel($fm_dnd), 'n', 10);
            }
            $ext->add($context, $exten, '', new ext_gotoif('$["${FMPRIME}" = "FALSE"]', 'dodial'));
            $ext->add($context, $exten, '', new ext_noop_trace('Got DND in FMGL ${FMGRP} with ${EXTEN:5} in ${RingGroupMethod} mode, aborting'));
            $ext->add($context, $exten, '', new ext_hangup(''));
            // Call pickup using app_pickup - Note that '**xtn' is hard-coded into the GXPs and SNOMs as a number to dial
            // when a user pushes a flashing BLF.
            //
            // We need to add ringgroups to this so that if an extension is part of a ringgroup, we can try to pickup that
            // extension by trying the ringgoup which is what the pickup application is going to respond to.
            //
            // NOTICE: this may be confusing, we check if this is a BRI build of Asterisk and use dpickup instead of pickup
            //         if it is. So we simply assign the variable $ext_pickup which one it is, and use that variable when
            //         creating all the extensions below. So those are "$ext_pickup" on purpose!
            //
            if ($fc_pickup != '' && $ast_ge_14) {
                $ext->addInclude('from-internal-additional', 'app-pickup');
                $fclen = strlen($fc_pickup);
                $ext_pickup = strstr($engineinfo['raw'], 'BRI') ? 'ext_dpickup' : 'ext_pickup';
                $fcc = new featurecode('paging', 'intercom-prefix');
                $intercom_code = $fcc->getCodeActive();
                unset($fcc);
                $picklist = '${EXTEN:' . $fclen . '}';
                $picklist .= '&${EXTEN:' . $fclen . '}@PICKUPMARK';
                $ext->add('app-pickup', "_{$fc_pickup}.", '', new ext_macro('user-callerid'));
                $ext->add('app-pickup', "_{$fc_pickup}.", '', new ext_set('PICKUP_EXTEN', '${AMPUSER}'));
                $ext->add('app-pickup', "_{$fc_pickup}.", '', new $ext_pickup($picklist));
                $ext->add('app-pickup', "_{$fc_pickup}.", '', new ext_hangup(''));
                if ($intercom_code != '') {
                    $len = strlen($fc_pickup . $intercom_code);
                    $picklist = '${EXTEN:' . $len . '}';
                    $picklist .= '&${EXTEN:' . $len . '}@PICKUPMARK';
                    $ext->add('app-pickup', "_{$fc_pickup}{$intercom_code}.", '', new ext_macro('user-callerid'));
                    $ext->add('app-pickup', "_{$fc_pickup}{$intercom_code}.", '', new ext_set('PICKUP_EXTEN', '${AMPUSER}'));
                    $ext->add('app-pickup', "_{$fc_pickup}{$intercom_code}.", '', new $ext_pickup($picklist));
                    $ext->add('app-pickup', "_{$fc_pickup}{$intercom_code}.", '', new ext_hangup(''));
                }
                // In order to do call pickup in ringgroups, we will need to try the ringgoup number
                // when doing call pickup for that ringgoup so we must see who is a member of what ringgroup
                // and then generate the dialplan
                //
                $rg_members = array();
                if (function_exists('ringgroups_list')) {
                    $rg_list = ringgroups_list(true);
                    foreach ($rg_list as $item) {
                        $thisgrp = ringgroups_get($item['grpnum']);
                        $grpliststr = $thisgrp['grplist'];
                        $grplist = explode("-", $grpliststr);
                        foreach ($grplist as $exten) {
                            if (strpos($exten, "#") === false) {
                                $rg_members[$exten][] = $item['grpnum'];
                            }
                        }
                    }
                }
                // Now we have a hash of extensions and what ringgoups they are members of
                // so we need to generate the callpickup dialplan for these specific extensions
                // to try the ringgoup.
                foreach ($rg_members as $exten => $grps) {
                    $picklist = $exten;
                    $picklist .= '&' . $exten . '@PICKUPMARK';
                    foreach ($grps as $grp) {
                        $picklist .= '&' . $grp . '@from-internal';
                        $picklist .= '&' . $grp . '@from-internal-xfer';
                        $picklist .= '&' . $grp . '@ext-group';
                    }
                    $ext->add('app-pickup', "{$fc_pickup}" . $exten, '', new ext_macro('user-callerid'));
                    $ext->add('app-pickup', "{$fc_pickup}" . $exten, '', new ext_set('PICKUP_EXTEN', '${AMPUSER}'));
                    $ext->add('app-pickup', "{$fc_pickup}" . $exten, '', new $ext_pickup($picklist));
                    $ext->add('app-pickup', "{$fc_pickup}" . $exten, '', new ext_hangup(''));
                    if ($intercom_code != '') {
                        $ext->add('app-pickup', "{$fc_pickup}" . $intercom_code . $exten, '', new ext_macro('user-callerid'));
                        $ext->add('app-pickup', "{$fc_pickup}" . $intercom_code . $exten, '', new ext_set('PICKUP_EXTEN', '${AMPUSER}'));
                        $ext->add('app-pickup', "{$fc_pickup}" . $intercom_code . $exten, '', new $ext_pickup($picklist));
                        $ext->add('app-pickup', "{$fc_pickup}" . $intercom_code . $exten, '', new ext_hangup(''));
                    }
                }
            } elseif ($fc_pickup != '') {
                $ext->addInclude('from-internal-additional', 'app-pickup');
                $fclen = strlen($fc_pickup);
                $ext_pickup = strstr($engineinfo['raw'], 'BRI') ? 'ext_dpickup' : 'ext_pickup';
                $fcc = new featurecode('paging', 'intercom-prefix');
                $intercom_code = $fcc->getCodeActive();
                unset($fcc);
                $ext->add('app-pickup', "_{$fc_pickup}.", '', new ext_NoOp('Attempt to Pickup ${EXTEN:' . $fclen . '} by ${CALLERID(num)}'));
                $ext->add('app-pickup', "_{$fc_pickup}.", '', new $ext_pickup('${EXTEN:' . $fclen . '}'));
                $ext->add('app-pickup', "_{$fc_pickup}.", '', new $ext_pickup('${EXTEN:' . $fclen . '}@ext-local'));
                $ext->add('app-pickup', "_{$fc_pickup}.", '', new $ext_pickup('${EXTEN:' . $fclen . '}@from-internal'));
                $ext->add('app-pickup', "_{$fc_pickup}.", '', new $ext_pickup('${EXTEN:' . $fclen . '}@from-internal-xfer'));
                $ext->add('app-pickup', "_{$fc_pickup}.", '', new $ext_pickup('${EXTEN:' . $fclen . '}@from-did-direct'));
                $ext->add('app-pickup', "_{$fc_pickup}.", '', new $ext_pickup('FMPR-${EXTEN:' . $fclen . '}'));
                $ext->add('app-pickup', "_{$fc_pickup}.", '', new $ext_pickup('LC-${EXTEN:' . $fclen . '}@from-internal'));
                $ext->add('app-pickup', "_{$fc_pickup}.", '', new $ext_pickup('LC-${EXTEN:' . $fclen . '}@from-internal-xfer'));
                $ext->add('app-pickup', "_{$fc_pickup}.", '', new $ext_pickup('FMPR-${EXTEN:' . $fclen . '}@from-internal'));
                $ext->add('app-pickup', "_{$fc_pickup}.", '', new $ext_pickup('FMPR-${EXTEN:' . $fclen . '}@from-internal-xfer'));
                $ext->add('app-pickup', "_{$fc_pickup}.", '', new $ext_pickup('FMPR-${EXTEN:' . $fclen . '}@from-did-direct'));
                if ($intercom_code != '') {
                    $ext->add('app-pickup', "_{$fc_pickup}{$intercom_code}.", '', new $ext_pickup('${EXTEN:' . strlen($fc_pickup . $intercom_code) . '}'));
                    $ext->add('app-pickup', "_{$fc_pickup}{$intercom_code}.", '', new $ext_pickup('${EXTEN:' . strlen($fc_pickup . $intercom_code) . '}@from-internal'));
                    $ext->add('app-pickup', "_{$fc_pickup}{$intercom_code}.", '', new $ext_pickup('${EXTEN:' . strlen($fc_pickup . $intercom_code) . '}@from-internal-xfer'));
                    $ext->add('app-pickup', "_{$fc_pickup}{$intercom_code}.", '', new $ext_pickup('${EXTEN:' . strlen($fc_pickup . $intercom_code) . '}@from-did-direct'));
                    $ext->add('app-pickup', "_{$fc_pickup}{$intercom_code}.", '', new $ext_pickup('FMPR-${EXTEN:' . strlen($fc_pickup . $intercom_code) . '}'));
                    $ext->add('app-pickup', "_{$fc_pickup}{$intercom_code}.", '', new $ext_pickup('FMPR-${EXTEN:' . strlen($fc_pickup . $intercom_code) . '}@from-internal'));
                    $ext->add('app-pickup', "_{$fc_pickup}{$intercom_code}.", '', new $ext_pickup('FMPR-${EXTEN:' . strlen($fc_pickup . $intercom_code) . '}@from-internal-xfer'));
                    $ext->add('app-pickup', "_{$fc_pickup}{$intercom_code}.", '', new $ext_pickup('FMPR-${EXTEN:' . strlen($fc_pickup . $intercom_code) . '}@from-did-direct'));
                }
                $ext->add('app-pickup', "_{$fc_pickup}.", '', new ext_hangup(''));
                // In order to do call pickup in ringgroups, we will need to try the ringgoup number
                // when doing call pickup for that ringgoup so we must see who is a member of what ringgroup
                // and then generate the dialplan
                //
                $rg_members = array();
                if (function_exists('ringgroups_list')) {
                    $rg_list = ringgroups_list(true);
                    foreach ($rg_list as $item) {
                        $thisgrp = ringgroups_get($item['grpnum']);
                        $grpliststr = $thisgrp['grplist'];
                        $grplist = explode("-", $grpliststr);
                        foreach ($grplist as $exten) {
                            if (strpos($exten, "#") === false) {
                                $rg_members[$exten][] = $item['grpnum'];
                            }
                        }
                    }
                }
                // Now we have a hash of extensions and what ringgoups they are members of
                // so we need to generate the callpickup dialplan for these specific extensions
                // to try the ringgoup.
                foreach ($rg_members as $exten => $grps) {
                    $ext->add('app-pickup', "{$fc_pickup}" . $exten, '', new $ext_pickup($exten));
                    $ext->add('app-pickup', "{$fc_pickup}" . $exten, '', new $ext_pickup($exten . '@ext-local'));
                    $ext->add('app-pickup', "{$fc_pickup}" . $exten, '', new $ext_pickup($exten . '@from-internal'));
                    $ext->add('app-pickup', "{$fc_pickup}" . $exten, '', new $ext_pickup($exten . '@from-internal-xfer'));
                    $ext->add('app-pickup', "{$fc_pickup}" . $exten, '', new $ext_pickup($exten . '@from-did-direct'));
                    $ext->add('app-pickup', "{$fc_pickup}" . $exten, '', new $ext_pickup('LC-' . $exten . '@from-internal'));
                    $ext->add('app-pickup', "{$fc_pickup}" . $exten, '', new $ext_pickup('LC-' . $exten . '@from-internal-xfer'));
                    $ext->add('app-pickup', "{$fc_pickup}" . $exten, '', new $ext_pickup('FMPR-' . $exten));
                    $ext->add('app-pickup', "{$fc_pickup}" . $exten, '', new $ext_pickup('FMPR-' . $exten . '@from-internal'));
                    $ext->add('app-pickup', "{$fc_pickup}" . $exten, '', new $ext_pickup('FMPR-' . $exten . '@from-internal-xfer'));
                    $ext->add('app-pickup', "{$fc_pickup}" . $exten, '', new $ext_pickup('FMPR-' . $exten . '@from-did-direct'));
                    foreach ($grps as $grp) {
                        $ext->add('app-pickup', "{$fc_pickup}" . $exten, '', new $ext_pickup($grp . '@from-internal'));
                        $ext->add('app-pickup', "{$fc_pickup}" . $exten, '', new $ext_pickup($grp . '@from-internal-xfer'));
                        $ext->add('app-pickup', "{$fc_pickup}" . $exten, '', new $ext_pickup($grp . '@ext-group'));
                    }
                    $ext->add('app-pickup', "{$fc_pickup}" . $exten, '', new ext_hangup(''));
                }
            }
            // zap barge
            global $version;
            if (version_compare($version, "12.5", "<") && $fc_zapbarge != '') {
                $ext->addInclude('from-internal-additional', 'app-zapbarge');
                // Add the include from from-internal
                $ext->add('app-zapbarge', $fc_zapbarge, '', new ext_macro('user-callerid'));
                $ext->add('app-zapbarge', $fc_zapbarge, '', new ext_setvar('GROUP()', '${CALLERID(number)}'));
                $ext->add('app-zapbarge', $fc_zapbarge, '', new ext_answer(''));
                $ext->add('app-zapbarge', $fc_zapbarge, '', new ext_wait(1));
                $ext->add('app-zapbarge', $fc_zapbarge, '', new ext_zapbarge(''));
                $ext->add('app-zapbarge', $fc_zapbarge, '', new ext_hangup(''));
            }
            // chan spy
            if ($fc_chanspy != '') {
                $ext->addInclude('from-internal-additional', 'app-chanspy');
                // Add the include from from-internal
                $ext->add('app-chanspy', $fc_chanspy, '', new ext_macro('user-callerid'));
                $ext->add('app-chanspy', $fc_chanspy, '', new ext_answer(''));
                $ext->add('app-chanspy', $fc_chanspy, '', new ext_wait(1));
                $ext->add('app-chanspy', $fc_chanspy, '', new ext_chanspy(''));
                $ext->add('app-chanspy', $fc_chanspy, '', new ext_hangup(''));
            }
            // Simulate Inbound call
            if ($fc_simu_pstn != '') {
                $ext->addInclude('from-internal-additional', 'ext-test');
                // Add the include from from-internal
                $ext->add('ext-test', $fc_simu_pstn, '', new ext_macro('user-callerid'));
                if (ctype_digit($fc_simu_pstn)) {
                    $ext->add('ext-test', $fc_simu_pstn, '', new ext_goto('1', '${EXTEN}', 'from-pstn'));
                } else {
                    $ext->add('ext-test', $fc_simu_pstn, '', new ext_goto('1', 's', 'from-pstn'));
                }
                $ext->add('ext-test', 'h', '', new ext_macro('hangupcall'));
            }
            $ext->addInclude('ext-did', 'ext-did-0001');
            // Add the include from from-internal
            $ext->addInclude('ext-did', 'ext-did-0002');
            // Add the include from from-internal
            $ext->add('ext-did', 'foo', '', new ext_noop('bar'));
            /* inbound routing extensions */
            $didlist = \FreePBX::Core()->getAllDIDs();
            if (is_array($didlist)) {
                $catchall = false;
                $catchall_context = 'ext-did-catchall';
                foreach ($didlist as $item) {
                    if (trim($item['destination']) == '') {
                        continue;
                    }
                    $exten = trim($item['extension']);
                    $cidnum = trim($item['cidnum']);
                    // If the user put in just a cid number for routing, we add _. pattern to catch
                    // all DIDs with that CID number. Asterisk will complain about _. being dangerous
                    // but we don't want to limit this to just numberic as someone may be trying to
                    // route a non-numeric did
                    //
                    $cidroute = false;
                    if ($cidnum != '' && $exten == '') {
                        $exten = '_.';
                        $pricid = $item['pricid'] ? true : false;
                        $cidroute = true;
                    } else {
                        if ($cidnum != '' && $exten != '' || $cidnum == '' && $exten == '') {
                            $pricid = true;
                        } else {
                            $pricid = false;
                        }
                    }
                    $context = $pricid ? "ext-did-0001" : "ext-did-0002";
                    $exten = $exten == "" ? "s" : $exten;
                    $exten = $exten . ($cidnum == "" ? "" : "/" . $cidnum);
                    //if a CID num is defined, add it
                    $ext->add($context, $exten, '', new ext_setvar('__DIRECTION', $amp_conf['INBOUND_NOTRANS'] ? 'INBOUND' : ''));
                    if ($cidroute) {
                        $ext->add($context, $exten, '', new ext_setvar('__FROM_DID', '${EXTEN}'));
                        $ext->add($context, $exten, '', new ext_goto('1', 's'));
                        $exten = "s/{$cidnum}";
                        $ext->add($context, $exten, '', new ext_execif('$["${FROM_DID}" = ""]', 'Set', '__FROM_DID=${EXTEN}'));
                    } else {
                        if ($exten == 's') {
                            $ext->add($context, $exten, '', new ext_execif('$["${FROM_DID}" = ""]', 'Set', '__FROM_DID=${EXTEN}'));
                        } else {
                            $ext->add($context, $exten, '', new ext_setvar('__FROM_DID', '${EXTEN}'));
                        }
                    }
                    // always set CallerID name
                    $ext->add($context, $exten, '', new ext_set('CDR(did)', '${FROM_DID}'));
                    $ext->add($context, $exten, '', new ext_execif('$[ "${CALLERID(name)}" = "" ] ', 'Set', 'CALLERID(name)=${CALLERID(num)}'));
                    // if VQA present and configured call it
                    if ($amp_conf['AST_APP_VQA'] && $amp_conf['DITECH_VQA_INBOUND']) {
                        $ext->add($context, $exten, '', new ext_vqa($amp_conf['DITECH_VQA_INBOUND']));
                    }
                    // Always set __MOHCLASS and moh.
                    if (empty($item['mohclass'])) {
                        // Should never happen
                        $item['mohclass'] = "default";
                    }
                    if ($item['mohclass'] != "default") {
                        $ext->add($context, $exten, '', new ext_setmusiconhold($item['mohclass']));
                        $ext->add($context, $exten, '', new ext_setvar('__MOHCLASS', $item['mohclass']));
                    } else {
                        $ext->add($context, $exten, '', new ext_setvar('__MOHCLASS', ""));
                    }
                    // If we require RINGING, signal it as soon as we enter.
                    if ($item['ringing'] === "CHECKED") {
                        $ext->add($context, $exten, '', new ext_ringing(''));
                        $ext->add($context, $exten, '', new ext_setvar('__RINGINGSENT', 'TRUE'));
                    }
                    //Block collect Calls
                    if ($item['reversal'] === "CHECKED") {
                        $ext->add($context, $exten, '', new ext_setvar('__REVERSAL_REJECT', 'TRUE'));
                    } else {
                        $ext->add($context, $exten, '', new ext_setvar('__REVERSAL_REJECT', 'FALSE'));
                    }
                    $ext->add($context, $exten, '', new ext_gotoif('$["${REVERSAL_REJECT}"!="TRUE"]', 'post-reverse-charge'));
                    $ext->add($context, $exten, '', new ext_gotoif('$["${CHANNEL(reversecharge)}"="1"]', 'macro-hangupcall'));
                    $ext->add($context, $exten, 'post-reverse-charge', new ext_noop());
                    if ($item['delay_answer']) {
                        $ext->add($context, $exten, '', new ext_wait($item['delay_answer']));
                    }
                    if ($exten == "s") {
                        //if the exten is s, then also make a catchall for undefined DIDs
                        $catchaccount = "_." . (empty($cidnum) ? "" : "/" . $cidnum);
                        if ($catchaccount == "_." && !$catchall) {
                            $catchall = true;
                            $ext->add($catchall_context, $catchaccount, '', new ext_NoOp('Catch-All DID Match - Found ${EXTEN} - You probably want a DID for this.'));
                            $ext->add($catchall_context, $catchaccount, '', new ext_log('WARNING', 'Friendly Scanner from ${CUT(CUT(SIP_HEADER(Via), ,2),:,1)}'));
                            $ext->add($catchall_context, $catchaccount, '', new ext_set('__FROM_DID', '${EXTEN}'));
                            $ext->add($catchall_context, $catchaccount, '', new ext_goto('1', 's', 'ext-did'));
                        }
                    }
                    if ($item['privacyman'] == "1") {
                        $ext->add($context, $exten, '', new ext_macro('privacy-mgr', $item['pmmaxretries'] . ',' . $item['pmminlength']));
                    } else {
                        // if privacymanager is used, this is not necessary as it will not let blocked/anonymous calls through
                        // otherwise, we need to save the caller presence to set it properly if we forward the call back out the pbx
                        // note - the indirect table could go away as of 1.4.20 where it is fixed so that SetCallerPres can take
                        // the raw format.
                        //
                        $ext->add($context, $exten, '', new ext_setvar('__CALLINGNAMEPRES_SV', '${CALLERID(name-pres)}'));
                        $ext->add($context, $exten, '', new ext_setvar('__CALLINGNUMPRES_SV', '${CALLERID(num-pres)}'));
                        $ext->add($context, $exten, '', new ext_setcallernamepres('allowed_not_screened'));
                        $ext->add($context, $exten, '', new ext_setcallernumpres('allowed_not_screened'));
                    }
                    if (!empty($item['alertinfo'])) {
                        $ext->add($context, $exten, '', new ext_setvar("__ALERT_INFO", str_replace(';', '\\;', $item['alertinfo'])));
                    }
                    $ext->add($context, $exten, 'did-cid-hook', new ext_noop('CallerID Entry Point'));
                    if (!empty($item['grppre'])) {
                        $ext->add($context, $exten, '', new ext_macro('prepend-cid', $item['grppre']));
                    }
                    //the goto destination
                    // destination field in 'incoming' database is backwards from what ext_goto expects
                    $goto_context = strtok($item['destination'], ',');
                    $goto_exten = strtok(',');
                    $goto_pri = strtok(',');
                    $ext->add($context, $exten, 'dest-ext', new ext_goto($goto_pri, $goto_exten, $goto_context));
                }
                // If there's not a catchall, make one with an error message
                if (!$catchall) {
                    $ext->add($catchall_context, 's', '', new ext_noop("No DID or CID Match"));
                    $ext->add($catchall_context, 's', 'a2', new ext_answer(''));
                    $ext->add($catchall_context, 's', '', new ext_log('WARNING', 'Friendly Scanner from ${CUT(CUT(SIP_HEADER(Via), ,2),:,1)}'));
                    $ext->add($catchall_context, 's', '', new ext_wait('2'));
                    $ext->add($catchall_context, 's', '', new ext_playback('ss-noservice'));
                    $ext->add($catchall_context, 's', '', new ext_sayalpha('${FROM_DID}'));
                    $ext->add($catchall_context, 's', '', new ext_hangup(''));
                    $ext->add($catchall_context, '_.', '', new ext_setvar('__FROM_DID', '${EXTEN}'));
                    $ext->add($catchall_context, '_.', '', new ext_noop('Received an unknown call with DID set to ${EXTEN}'));
                    $ext->add($catchall_context, '_.', '', new ext_goto('a2', 's'));
                    $ext->add($catchall_context, 'h', '', new ext_hangup(''));
                }
            }
            // Now create macro-from-zaptel-nnn or macro-from-dahdi-nnn for each defined channel to route it to the DID routing
            // Send it to from-trunk so it is handled as other dids would be handled.
            //
            // to this point we have both zap and dahdi configuration options. At generation though they can't co-exists. If compatibility
            // mode then it's still from-zaptel, otherwise it is which ever is present. We cant use ast_with_dahdi() (chan_dadi) because
            // it is for detection with compatibility mode. We need to actually determine if chan_dahdi is present or not at this point
            //
            if (!isset($chan_dahdi_loaded)) {
                if (isset($astman) && $astman->connected()) {
                    $chan_dahdi_loaded = $astman->mod_loaded('chan_dahdi');
                }
            }
            foreach (core_dahdichandids_list() as $row) {
                $channel = $row['channel'];
                $did = $row['did'];
                $this_context = "macro-from-dahdi-{$channel}";
                $ext->add($this_context, 's', '', new ext_noop('Entering ' . $this_context . ' with DID = ${DID} and setting to: ' . $did));
                $ext->add($this_context, 's', '', new ext_setvar('__FROM_DID', $did));
                $ext->add($this_context, 's', '', new ext_goto('1', $did, 'from-trunk'));
            }
            /* user extensions */
            $ext->addInclude('from-internal-additional', 'ext-local');
            // If running in Dynamic mode, this will insert the hints through an Asterisk #exec call.
            // which require "execincludes=yes" to be set in the [options] section of asterisk.conf
            //
            $fcc = new featurecode('paging', 'intercom-prefix');
            $intercom_code = $fcc->getCodeActive();
            unset($fcc);
            $intercom_code = $intercom_code == '' ? 'nointercom' : $intercom_code;
            $fcc = new featurecode('campon', 'toggle');
            $campon_toggle = $fcc->getCodeActive();
            unset($fcc);
            $campon_toggle = $campon_toggle == '' ? 'nocampon' : $campon_toggle;
            // Pass the code so agi scripts like user_login_logout know to generate hints
            //
            $ext->addGlobal('INTERCOMCODE', $intercom_code);
            if ($amp_conf['DYNAMICHINTS']) {
                if ($amp_conf['USEDEVSTATE'] && function_exists('donotdisturb_get_config')) {
                    $add_dnd = 'dnd';
                } else {
                    $add_dnd = '';
                }
                $ext->addExec('ext-local', $amp_conf['AMPBIN'] . '/generate_hints.php ' . $intercom_code . ' ' . $campon_toggle . ' ' . $add_dnd);
            }
            $userlist = core_users_list();
            if (is_array($userlist)) {
                foreach ($userlist as $item) {
                    $exten = \FreePBX::Core()->getUser($item[0]);
                    $vm = $exten['voicemail'] == "novm" || $exten['voicemail'] == "disabled" || $exten['voicemail'] == "" ? "novm" : $exten['extension'];
                    $ext->add('ext-local', $exten['extension'], '', new ext_set('__RINGTIMER', '${IF($["${DB(AMPUSER/' . $exten['extension'] . '/ringtimer)}" > "0"]?${DB(AMPUSER/' . $exten['extension'] . '/ringtimer)}:${RINGTIMER_DEFAULT})}'));
                    $dest_args = ',' . ($exten['noanswer_dest'] == '' ? '0' : '1') . ',' . ($exten['busy_dest'] == '' ? '0' : '1') . ',' . ($exten['chanunavail_dest'] == '' ? '0' : '1');
                    $ext->add('ext-local', $exten['extension'], '', new ext_macro('exten-vm', $vm . "," . $exten['extension'] . $dest_args));
                    $ext->add('ext-local', $exten['extension'], 'dest', new ext_set('__PICKUPMARK', ''));
                    if ($exten['noanswer_dest']) {
                        if ($exten['noanswer_cid'] != '') {
                            $ext->add('ext-local', $exten['extension'], '', new ext_execif('$["${DIALSTATUS}"="NOANSWER"]', 'Set', 'CALLERID(name)=' . $exten['noanswer_cid'] . '${CALLERID(name)}'));
                        }
                        $ext->add('ext-local', $exten['extension'], '', new ext_gotoif('$["${DIALSTATUS}"="NOANSWER"]', $exten['noanswer_dest']));
                    }
                    if ($exten['busy_dest']) {
                        if ($exten['busy_cid'] != '') {
                            $ext->add('ext-local', $exten['extension'], '', new ext_execif('$["${DIALSTATUS}"="BUSY"]', 'Set', 'CALLERID(name)=' . $exten['busy_cid'] . '${CALLERID(name)}'));
                        }
                        $ext->add('ext-local', $exten['extension'], '', new ext_gotoif('$["${DIALSTATUS}"="BUSY"]', $exten['busy_dest']));
                    }
                    if ($exten['chanunavail_dest']) {
                        if ($exten['chanunavail_cid'] != '') {
                            $ext->add('ext-local', $exten['extension'], '', new ext_execif('$["${DIALSTATUS}"="CHANUNAVAIL"]', 'Set', 'CALLERID(name)=' . $exten['chanunavail_cid'] . '${CALLERID(name)}'));
                        }
                        $ext->add('ext-local', $exten['extension'], '', new ext_gotoif('$["${DIALSTATUS}"="CHANUNAVAIL"]', $exten['chanunavail_dest']));
                    }
                    if ($vm != "novm") {
                        // This usually gets called from macro-exten-vm but if follow-me destination need to go this route
                        $ext->add('ext-local', $exten['extension'], '', new ext_macro('vm', $vm . ',${DIALSTATUS},${IVR_RETVM}'));
                        $ext->add('ext-local', $exten['extension'], '', new ext_goto('1', 'vmret'));
                        $ext->add('ext-local', 'vmb' . $exten['extension'], '', new ext_macro('vm', $vm . ',BUSY,${IVR_RETVM}'));
                        $ext->add('ext-local', 'vmb' . $exten['extension'], '', new ext_goto('1', 'vmret'));
                        $ext->add('ext-local', 'vmu' . $exten['extension'], '', new ext_macro('vm', $vm . ',NOANSWER,${IVR_RETVM}'));
                        $ext->add('ext-local', 'vmu' . $exten['extension'], '', new ext_goto('1', 'vmret'));
                        $ext->add('ext-local', 'vms' . $exten['extension'], '', new ext_macro('vm', $vm . ',NOMESSAGE,${IVR_RETVM}'));
                        $ext->add('ext-local', 'vms' . $exten['extension'], '', new ext_goto('1', 'vmret'));
                        $ext->add('ext-local', 'vmi' . $exten['extension'], '', new ext_macro('vm', $vm . ',INSTRUCT,${IVR_RETVM}'));
                        $ext->add('ext-local', 'vmi' . $exten['extension'], '', new ext_goto('1', 'vmret'));
                    } else {
                        // If we return from teh macro, it means we are suppose to return to the IVR
                        //
                        $ext->add('ext-local', $exten['extension'], '', new ext_goto('1', 'return', '${IVR_CONTEXT}'));
                    }
                    // Create the hints if running in normal mode
                    //
                    if (!$amp_conf['DYNAMICHINTS']) {
                        $hint = core_hint_get($exten['extension']);
                        $dnd_string = $amp_conf['USEDEVSTATE'] && function_exists('donotdisturb_get_config') ? "&Custom:DND" . $exten['extension'] : '';
                        $presence_string = $amp_conf['AST_FUNC_PRESENCE_STATE'] ? ",CustomPresence:" . $exten['extension'] : '';
                        $hint_string = (!empty($hint) ? $hint : '') . $dnd_string . $presence_string;
                        $astman->database_put("AMPUSER/" . $exten['extension'], "hint", $hint_string);
                        if ($hint_string) {
                            //TODO: Lots of hints here. Can this be dynamic? No I dont think so
                            $ext->addHint('ext-local', $exten['extension'], $hint_string);
                        }
                    }
                    if ($exten['sipname']) {
                        $ext->add('ext-local', $exten['sipname'], '', new ext_goto('1', $item[0], 'from-internal'));
                    }
                }
                // Now make a special context for the IVR inclusions of local extension dialing so that
                // when people use the Queues breakout ability, and break out to someone's extensions, voicemail
                // works.
                //
                $ivr_context = 'from-did-direct-ivr';
                $sql = "SELECT LENGTH(extension) as len FROM users GROUP BY len";
                $sth = FreePBX::Database()->prepare($sql);
                $sth->execute();
                $rows = $sth->fetchAll(\PDO::FETCH_ASSOC);
                foreach ($rows as $row) {
                    $ext->add($ivr_context, '_' . str_repeat('X', $row['len']), '', new ext_macro('blkvm-clr'));
                    $ext->add($ivr_context, '_' . str_repeat('X', $row['len']), '', new ext_setvar('__NODEST', ''));
                    $ext->add($ivr_context, '_' . str_repeat('X', $row['len']), '', new ext_goto('1', '${EXTEN}', 'from-did-direct'));
                }
                $ext->add('ext-local', 'vmret', '', new ext_gotoif('$["${IVR_RETVM}" = "RETURN" & "${IVR_CONTEXT}" != ""]', 'playret'));
                $ext->add('ext-local', 'vmret', '', new ext_hangup(''));
                $ext->add('ext-local', 'vmret', 'playret', new ext_playback('exited-vm-will-be-transfered&silence/1'));
                $ext->add('ext-local', 'vmret', '', new ext_goto('1', 'return', '${IVR_CONTEXT}'));
                $ext->add('ext-local', 'h', '', new ext_macro('hangupcall'));
            }
            //$ext->addHint('ext-local', "_X.", $hint_string);
            if ($intercom_code != '') {
                $ext->addHint('ext-local', "_" . $intercom_code . "X.", '${DB(AMPUSER/${EXTEN:' . strlen($intercom_code) . '}/hint)}');
            }
            /* Create the from-trunk-tech-chanelid context that can be used for inbound group counting
             * Create the DUNDI macros for DUNDI trunks
             * Create the ext-trunk context for direct trunk dialing TODO: should this be its own module?
             */
            $trunklist = core_trunks_listbyid();
            if (is_array($trunklist) && count($trunklist)) {
                $tcontext = 'ext-trunk';
                $texten = 'tdial';
                $tcustom = 'tcustom';
                $generate_texten = false;
                $generate_tcustom = false;
                foreach ($trunklist as $trunkprops) {
                    if (trim($trunkprops['disabled']) == 'on') {
                        continue;
                    }
                    $trunkgroup = 'OUT_' . $trunkprops['trunkid'];
                    switch ($trunkprops['tech']) {
                        case 'dundi':
                            $macro_name = 'macro-dundi-' . $trunkprops['trunkid'];
                            $ext->addSwitch($macro_name, 'DUNDI/' . $trunkprops['channelid']);
                            $ext->add($macro_name, 's', '', new ext_goto('1', '${ARG1}'));
                            $trunkcontext = "from-trunk-" . $trunkprops['tech'] . "-" . $trunkprops['channelid'];
                            $ext->add($trunkcontext, '_.', '', new ext_set('GROUP()', $trunkgroup));
                            $ext->add($trunkcontext, '_.', '', new ext_goto('1', '${EXTEN}', 'from-trunk'));
                            $ext->add($tcontext, $trunkprops['trunkid'], '', new ext_set('OUTBOUND_GROUP', $trunkgroup));
                            $ext->add($tcontext, $trunkprops['trunkid'], '', new ext_gotoif('$["${OUTMAXCHANS_' . $trunkprops['trunkid'] . '}" = ""]', 'nomax'));
                            $ext->add($tcontext, $trunkprops['trunkid'], '', new ext_gotoif('$[${GROUP_COUNT(' . $trunkgroup . ')} >= ${OUTMAXCHANS_${DIAL_TRUNK}}]', 'hangit'));
                            $ext->add($tcontext, $trunkprops['trunkid'], 'nomax', new ext_execif('$["${CALLINGNAMEPRES_SV}" != ""]', 'Set', 'CALLERPRES(name-pres)=${CALLINGNAMEPRES_SV}'));
                            $ext->add($tcontext, $trunkprops['trunkid'], '', new ext_execif('$["${CALLINGNUMPRES_SV}" != ""]', 'Set', 'CALLERPRES(num-pres)=${CALLINGNUMPRES_SV}'));
                            $ext->add($tcontext, $trunkprops['trunkid'], '', new ext_set('DIAL_NUMBER', '${FROM_DID}'));
                            $ext->add($tcontext, $trunkprops['trunkid'], '', new ext_gosubif('$["${PREFIX_TRUNK_' . $trunkprops['trunkid'] . '}" != ""]', 'sub-flp-' . $trunkprops['trunkid'] . ',s,1'));
                            $ext->add($tcontext, $trunkprops['trunkid'], '', new ext_set('OUTNUM', '${OUTPREFIX_${DIAL_TRUNK}}${DIAL_NUMBER}'));
                            // OUTNUM is the final dial number
                            $ext->add($tcontext, $trunkprops['trunkid'], '', new ext_macro('dundi-${DIAL_TRUNK}', '${OUTNUM}'));
                            $ext->add($tcontext, $trunkprops['trunkid'], 'hangit', new ext_hangup());
                            break;
                        case 'iax':
                            $trunkprops['tech'] = 'iax2';
                            // fall-through
                        // fall-through
                        case 'pjsip':
                        case 'iax2':
                        case 'sip':
                            $trunkcontext = "from-trunk-" . $trunkprops['tech'] . "-" . $trunkprops['channelid'];
                            $ext->add($trunkcontext, '_.', '', new ext_set('GROUP()', $trunkgroup));
                            $ext->add($trunkcontext, '_.', '', new ext_goto('1', '${EXTEN}', 'from-trunk'));
                            // fall-through
                        // fall-through
                        case 'zap':
                        case 'dahdi':
                            // PJSip hack. This needs to be re-written, I think.
                            if ($trunkprops['tech'] == "pjsip") {
                                $ext->add($tcontext, $trunkprops['trunkid'], '', new ext_set('TDIAL_SUFFIX', "@" . $trunkprops['channelid']));
                                $ext->add($tcontext, $trunkprops['trunkid'], '', new ext_set('TDIAL_STRING', strtoupper($trunkprops['tech'])));
                            } else {
                                $ext->add($tcontext, $trunkprops['trunkid'], '', new ext_set('TDIAL_STRING', strtoupper($trunkprops['tech']) . '/' . $trunkprops['channelid']));
                            }
                            $trunkcontext = "from-trunk-" . $trunkprops['tech'] . "-" . $trunkprops['channelid'];
                            $ext->add($tcontext, $trunkprops['trunkid'], '', new ext_set('DIAL_TRUNK', $trunkprops['trunkid']));
                            $ext->add($tcontext, $trunkprops['trunkid'], '', new ext_goto('1', $texten, 'ext-trunk'));
                            $generate_texten = true;
                            break;
                            // TODO we don't have the OUTNUM until later so fix this...
                        // TODO we don't have the OUTNUM until later so fix this...
                        case 'custom':
                            $dial_string = str_replace('$OUTNUM$', '${SS}{OUTNUM}', $trunkprops['channelid']);
                            $ext->add($tcontext, $trunkprops['trunkid'], '', new ext_set('SS', '$'));
                            $ext->add($tcontext, $trunkprops['trunkid'], '', new ext_set('TDIAL_STRING', $dial_string));
                            $ext->add($tcontext, $trunkprops['trunkid'], '', new ext_set('DIAL_TRUNK', $trunkprops['trunkid']));
                            $ext->add($tcontext, $trunkprops['trunkid'], '', new ext_goto('1', $tcustom, 'ext-trunk'));
                            $generate_tcustom = true;
                            break;
                        case 'enum':
                            // Not Supported
                            break;
                        default:
                    }
                }
                if ($generate_tcustom) {
                    $ext->add($tcontext, $tcustom, '', new ext_set('OUTBOUND_GROUP', 'OUT_${DIAL_TRUNK}'));
                    $ext->add($tcontext, $tcustom, '', new ext_gotoif('$["${OUTMAXCHANS_${DIAL_TRUNK}}" = ""]', 'nomax'));
                    $ext->add($tcontext, $tcustom, '', new ext_gotoif('$[${GROUP_COUNT(OUT_${DIAL_TRUNK})} >= ${OUTMAXCHANS_${DIAL_TRUNK}}]', 'hangit'));
                    $ext->add($tcontext, $tcustom, 'nomax', new ext_execif('$["${CALLINGNAMEPRES_SV}" != ""]', 'Set', 'CALLERPRES(name-pres)=${CALLINGNAMEPRES_SV}'));
                    $ext->add($tcontext, $tcustom, '', new ext_execif('$["${CALLINGNUMPRES_SV}" != ""]', 'Set', 'CALLERPRES(num-pres)=${CALLINGNUMPRES_SV}'));
                    $ext->add($tcontext, $tcustom, '', new ext_set('DIAL_NUMBER', '${FROM_DID}'));
                    $ext->add($tcontext, $tcustom, '', new ext_gosubif('$["${PREFIX_TRUNK_${DIAL_TRUNK}}" != ""]', 'sub-flp-${DIAL_TRUNK},s,1'));
                    $ext->add($tcontext, $tcustom, '', new ext_set('OUTNUM', '${OUTPREFIX_${DIAL_TRUNK}}${DIAL_NUMBER}'));
                    // OUTNUM is the final dial number
                    // Address Security Vulnerability in many earlier versions of Asterisk from an external source tranmitting a
                    // malicious CID that can cause overflows in the Asterisk code.
                    //
                    $ext->add($tcontext, $tcustom, '', new ext_set('CALLERID(number)', '${CALLERID(number):0:40}'));
                    $ext->add($tcontext, $tcustom, '', new ext_set('CALLERID(name)', '${CALLERID(name):0:40}'));
                    $ext->add($tcontext, $tcustom, '', new ext_set('DIAL_TRUNK_OPTIONS', '${IF($["${DB_EXISTS(TRUNK/${DIAL_TRUNK}/dialopts)}" = "1"]?${DB_RESULT}:${TRUNK_OPTIONS})}'));
                    $ext->add($tcontext, $tcustom, '', new ext_dial('${EVAL(${TDIAL_STRING})}', '${TRUNK_RING_TIMER},${DIAL_TRUNK_OPTIONS}'));
                    $ext->add($tcontext, $tcustom, 'hangit', new ext_hangup());
                }
                if ($generate_texten) {
                    $ext->add($tcontext, $texten, '', new ext_set('OUTBOUND_GROUP', 'OUT_${DIAL_TRUNK}'));
                    $ext->add($tcontext, $texten, '', new ext_gotoif('$["${OUTMAXCHANS_${DIAL_TRUNK}}" = ""]', 'nomax'));
                    $ext->add($tcontext, $texten, '', new ext_gotoif('$[${GROUP_COUNT(OUT_${DIAL_TRUNK})} >= ${OUTMAXCHANS_${DIAL_TRUNK}}]', 'hangit'));
                    $ext->add($tcontext, $texten, 'nomax', new ext_execif('$["${CALLINGNAMEPRES_SV}" != ""]', 'Set', 'CALLERPRES(name-pres)=${CALLINGNAMEPRES_SV}'));
                    $ext->add($tcontext, $texten, '', new ext_execif('$["${CALLINGNUMPRES_SV}" != ""]', 'Set', 'CALLERPRES(num-pres)=${CALLINGNUMPRES_SV}'));
                    $ext->add($tcontext, $texten, '', new ext_set('DIAL_NUMBER', '${FROM_DID}'));
                    $ext->add($tcontext, $texten, '', new ext_gosubif('$["${PREFIX_TRUNK_${DIAL_TRUNK}}" != ""]', 'sub-flp-${DIAL_TRUNK},s,1'));
                    $ext->add($tcontext, $texten, '', new ext_set('OUTNUM', '${OUTPREFIX_${DIAL_TRUNK}}${DIAL_NUMBER}'));
                    // OUTNUM is the final dial number
                    $ext->add($tcontext, $texten, '', new ext_set('DIAL_TRUNK_OPTIONS', '${IF($["${DB_EXISTS(TRUNK/${DIAL_TRUNK}/dialopts)}" = "1"]?${DB_RESULT}:${TRUNK_OPTIONS})}'));
                    $ext->add($tcontext, $texten, '', new ext_dial('${TDIAL_STRING}/${OUTNUM}${TDIAL_SUFFIX}', '${TRUNK_RING_TIMER},${DIAL_TRUNK_OPTIONS}'));
                    // Address Security Vulnerability in many earlier versions of Asterisk from an external source tranmitting a
                    // malicious CID that can cause overflows in the Asterisk code.
                    //
                    $ext->add($tcontext, $texten, '', new ext_set('CALLERID(number)', '${CALLERID(number):0:40}'));
                    $ext->add($tcontext, $texten, '', new ext_set('CALLERID(name)', '${CALLERID(name):0:40}'));
                    $ext->add($tcontext, $texten, 'hangit', new ext_hangup());
                }
            }
            /* dialplan globals */
            // modules should NOT use the globals table to store anything!
            // modules should use $ext->addGlobal("testvar","testval"); in their module_get_config() function instead
            // I'm cheating for core functionality - do as I say, not as I do ;-)
            // Auto add these globals to give access to agi scripts and other needs, unless defined in the global table.
            //
            $amp_conf_globals = array("ASTETCDIR", "ASTMODDIR", "ASTVARLIBDIR", "ASTAGIDIR", "ASTSPOOLDIR", "ASTRUNDIR", "ASTLOGDIR", "CWINUSEBUSY", "AMPMGRUSER", "AMPMGRPASS", "ASTMANAGERHOST", "AMPDBENGINE", "AMPDBHOST", "AMPDBNAME", "AMPDBUSER", "AMPDBPASS", "AMPDBFILE", "VMX_CONTEXT", "VMX_PRI", "VMX_TIMEDEST_CONTEXT", "VMX_TIMEDEST_EXT", "VMX_TIMEDEST_PRI", "VMX_LOOPDEST_CONTEXT", "VMX_LOOPDEST_EXT", "VMX_LOOPDEST_PRI");
            $sql = "SELECT * FROM globals";
            $globals = sql($sql, "getAll", DB_FETCHMODE_ASSOC);
            foreach ($globals as $global) {
                $value = $global['value'];
                // Ticket # 5477 Create a default value that can't be polluted
                if ($global['variable'] == 'RINGTIMER') {
                    $ext->addGlobal('RINGTIMER_DEFAULT', $value);
                    continue;
                }
                $ext->addGlobal($global['variable'], $value);
                // now if for some reason we have a variable in the global table
                // that is in our $amp_conf_globals list, then remove it so we
                // don't duplicate, the sql table will take precedence
                //
                if (array_key_exists($global['variable'], $amp_conf_globals)) {
                    $rm_keys = array_keys($amp_conf_globals, $global['variable']);
                    foreach ($rm_keys as $index) {
                        unset($amp_conf_globals[$index]);
                    }
                }
            }
            foreach ($amp_conf_globals as $global) {
                if (isset($amp_conf[$global])) {
                    $value = $amp_conf[$global];
                    if ($value === true || $value === false) {
                        $value = $value ? 'true' : 'false';
                    }
                    $ext->addGlobal($global, $value);
                }
            }
            // Put the MIXMON_DIR, it needs a trailing / so is special cased here
            $mixmon_dir = $amp_conf['MIXMON_DIR'] != '' ? $amp_conf['MIXMON_DIR'] . '/' : '';
            $ext->addGlobal('MIXMON_DIR', $mixmon_dir);
            //out("Added to globals: MIXMON_DIR = $mixmon_dir");
            // Add some globals that are used by the dialplan
            //
            $add_globals = array('MIXMON_POST' => 'MIXMON_POST', 'DIAL_OPTIONS' => 'DIAL_OPTIONS', 'TRUNK_OPTIONS' => 'TRUNK_OPTIONS', 'TRUNK_RING_TIMER' => 'TRUNK_RING_TIMER', 'MIXMON_FORMAT' => 'MIXMON_FORMAT', 'REC_POLICY' => 'REC_POLICY', 'RINGTIMER' => 'RINGTIMER_DEFAULT', 'TRANSFER_CONTEXT' => 'TRANSFER_CONTEXT');
            foreach ($add_globals as $g => $v) {
                $ext->addGlobal($v, $amp_conf[$g]);
                //out("Added to globals: $v = ".$amp_conf[$g]);
            }
            unset($add_globals);
            // Put the asterisk version in a global for agi etc.
            $ext->addGlobal('ASTVERSION', $version);
            // Put the use of chan_dahdi in a global for dialparties
            $ext->addGlobal('ASTCHANDAHDI', $chan_dahdi ? '1' : '0');
            // Create constant NULL in globals
            $ext->addGlobal('NULL', '""');
            // Now let's create the required globals for the trunks so outbound routes work. These used to
            // be stored in the globals table but are not generated by retrieve conf and pulled from the
            // trunks table
            //
            $sqlstr = "\n\t\tSELECT `trunkid`, `tech`, `outcid`, `keepcid`, `maxchans`, `failscript`, `dialoutprefix`, `channelid`, `disabled`\n\t\tFROM `trunks` ORDER BY `trunkid`\n\t\t";
            $trunks = sql($sqlstr, "getAll", DB_FETCHMODE_ASSOC);
            $trunk_hash = core_trunks_list_dialrules();
            // $has_keepcid_cnum is used when macro-outbound-callerid is generated to determine if we need to insert the
            // final execif() statement so it is important to be set before then and here
            //
            $has_keepcid_cnum = false;
            foreach ($trunks as $trunk) {
                $tid = $trunk['trunkid'];
                $tech = strtoupper($trunk['tech']);
                if ($tech == 'IAX') {
                    $tech = 'IAX2';
                } elseif ($tech == 'ZAP' && $chan_dahdi) {
                    $tech = 'DAHDI';
                }
                if ($tech == 'CUSTOM') {
                    $ext->addGlobal('OUT_' . $tid, 'AMP:' . trim($trunk['channelid']));
                } elseif ($tech != 'PJSIP') {
                    $ext->addGlobal('OUT_' . $tid, $tech . "/" . $trunk['channelid']);
                } else {
                    $ext->addGlobal('OUT_' . $tid, $tech);
                    $ext->addGlobal('OUT_' . $tid . '_SUFFIX', '@' . $trunk['channelid']);
                }
                $ext->addGlobal('OUTCID_' . $tid, $trunk['outcid']);
                $ext->addGlobal('OUTMAXCHANS_' . $tid, $trunk['maxchans']);
                $ext->addGlobal('OUTFAIL_' . $tid, $trunk['failscript']);
                $ext->addGlobal('OUTPREFIX_' . $tid, $trunk['dialoutprefix']);
                $ext->addGlobal('OUTDISABLE_' . $tid, $trunk['disabled']);
                $ext->addGlobal('OUTKEEPCID_' . $tid, $trunk['keepcid']);
                $ext->addGlobal('FORCEDOUTCID_' . $tid, $trunk['keepcid'] == 'all' ? $trunk['outcid'] : "");
                if ($trunk['keepcid'] == 'cnum') {
                    $has_keepcid_cnum = true;
                }
                // Generate PREFIX_TRUNK_$tid even if 0 since globals will persist and cause crashes
                if (isset($trunk_hash[$tid]) && count($trunk_hash)) {
                    $patterns = $trunk_hash[$tid];
                    // First, generate the global referencing how many there are
                    $ext->addGlobal("PREFIX_TRUNK_{$tid}", count($patterns));
                    $context = 'sub-flp-' . $tid;
                    $target = 'TARGET_FLP_' . $tid;
                    $exten = 's';
                    foreach ($patterns as $pattern) {
                        $prepend = $pattern['prepend_digits'];
                        $offset = strlen(preg_replace('/(\\[[^\\]]*\\])/', 'X', $pattern['match_pattern_prefix']));
                        $regex_base = $pattern['match_pattern_prefix'] . $pattern['match_pattern_pass'];
                        // convert asterisk pattern matching into perl regular expression
                        //  - two steps, use $ in place of +
                        //  - next replace $ with +
                        // if you don't do this, the str_replace() walks over itself
                        $regex_intermediate = str_replace(array('X', 'Z', 'N', '.', '*', '+'), array('[0-9]', '[1-9]', '[2-9]', '[0-9#*\\\\$]$', '\\\\*', '\\\\$'), $pattern['match_pattern_prefix'] . $pattern['match_pattern_pass']);
                        $regex = strtr($regex_intermediate, "\$", "+");
                        if ($pattern['prepend_digits'] == '' && $offset == 0) {
                            $ext->add($context, $exten, '', new ext_execif('$[${REGEX("^' . $regex . '$" ${DIAL_NUMBER})} = 1]', 'Return'));
                        } else {
                            $offset = $offset ? ':' . $offset : '';
                            $ext->add($context, $exten, '', new ext_execif('$[${REGEX("^' . $regex . '$" ${DIAL_NUMBER})} = 1]', 'Set', $target . '=' . $pattern['prepend_digits'] . '${DIAL_NUMBER' . $offset . '}'));
                            $ext->add($context, $exten, '', new ext_gotoif('$[${LEN(${' . $target . '})} != 0]', 'match'));
                        }
                    }
                    $ext->add($context, $exten, '', new ext_return(''));
                    $ext->add($context, $exten, 'match', new ext_set('DIAL_NUMBER', '${' . $target . '}'));
                    $ext->add($context, $exten, '', new ext_return(''));
                } else {
                    $ext->addGlobal("PREFIX_TRUNK_{$tid}", '');
                }
            }
            /* macro-prepend-cid */
            // prepend a cid and if set to replace previous prepends, do so, otherwise stack them
            //
            $mcontext = 'macro-prepend-cid';
            $exten = 's';
            if ($amp_conf['CID_PREPEND_REPLACE']) {
                $ext->add($mcontext, $exten, '', new ext_gotoif('$["${RGPREFIX}" = ""]', 'REPCID'));
                $ext->add($mcontext, $exten, '', new ext_gotoif('$["${RGPREFIX}" != "${CALLERID(name):0:${LEN(${RGPREFIX})}}"]', 'REPCID'));
                $ext->add($mcontext, $exten, '', new ext_noop_trace('Current RGPREFIX is ${RGPREFIX}....stripping from CallerID'));
                $ext->add($mcontext, $exten, '', new ext_set('CALLERID(name)', '${CALLERID(name):${LEN(${RGPREFIX})}}'));
                $ext->add($mcontext, $exten, '', new ext_set('_RGPREFIX', ''));
            }
            $ext->add($mcontext, $exten, 'REPCID', new ext_set('_RGPREFIX', '${ARG1}'));
            $ext->add($mcontext, $exten, '', new ext_set('CALLERID(name)', '${RGPREFIX}${CALLERID(name)}'));
            /* outbound routes */
            $ext->addInclude('from-internal-additional', 'outbound-allroutes');
            //$ext->add('outbound-allroutes', '_!', '', new ext_macro('user-callerid,SKIPTTL'));
            $ext->add('outbound-allroutes', 'foo', '', new ext_noop('bar'));
            $routes = \FreePBX::Core()->getAllRoutes();
            $trunk_table = core_trunks_listbyid();
            $trunk_type_needed = array();
            // track which macros need to be generated
            $delim = $ast_lt_16 ? '|' : ',';
            foreach ($routes as $route) {
                $add_extra_pri1 = array();
                $context = 'outrt-' . $route['route_id'];
                $comment = $route['name'];
                $ext->addSectionComment($context, $comment);
                if (function_exists('timeconditions_timegroups_get_times') && $route['time_group_id'] !== null) {
                    $times = timeconditions_timegroups_get_times($route['time_group_id'], true);
                    if (is_array($times) && count($times)) {
                        foreach ($times as $time) {
                            $ext->addInclude('outbound-allroutes', $context . $delim . $time[1], $comment);
                        }
                    } else {
                        $ext->addInclude('outbound-allroutes', $context, $comment);
                    }
                } else {
                    $ext->addInclude('outbound-allroutes', $context, $comment);
                }
                $patterns = core_routing_getroutepatternsbyid($route['route_id']);
                $trunks = core_routing_getroutetrunksbyid($route['route_id']);
                foreach ($patterns as $pattern) {
                    // returns:
                    // array('prepend_digits' => $pattern['prepend_digits'], 'dial_pattern' => $exten, 'offset' => $pos);
                    //
                    $fpattern = core_routing_formatpattern($pattern);
                    $exten = $fpattern['dial_pattern'];
                    $offset = $fpattern['offset'] == 0 ? '' : ':' . $fpattern['offset'];
                    // This will not get called, but it fixes some things like custom-context or other possible custom uses of these
                    // generated contexts that don't have an 'outbound-allroutes' wrapper around them, of course in those cases the
                    // CID part of the dialplan will not get executed
                    if (!isset($add_extra_pri1[$fpattern['base_pattern']])) {
                        $ext->add($context, $fpattern['base_pattern'], '', new ext_macro('user-callerid,LIMIT,EXTERNAL'));
                        $add_extra_pri1[$fpattern['base_pattern']] = true;
                    }
                    if ($fpattern['base_pattern'] != $exten) {
                        $ext->add($context, $exten, '', new ext_macro('user-callerid,LIMIT,EXTERNAL'));
                    }
                    $ext->add($context, $exten, '', new ext_noop_trace(sprintf(_('Calling Out Route: %s'), '${SET(OUTBOUND_ROUTE_NAME=' . $route['name'] . ')}'), 1));
                    if ($route['dest']) {
                        $ext->add($context, $exten, '', new ext_set("ROUTE_CIDSAVE", '${CALLERID(all)}'));
                    }
                    // Conditionally Add Divesion Header if the call was diverted
                    if ($amp_conf['DIVERSIONHEADER']) {
                        $ext->add($context, $exten, '', new ext_gosubif('$[${LEN(${FROM_DID})}>0 & "${FROM_DID}"!="s"]', 'sub-diversion-header,s,1'));
                    }
                    // if VQA present and configured call it
                    if ($amp_conf['AST_APP_VQA'] && $amp_conf['DITECH_VQA_OUTBOUND']) {
                        $ext->add($context, $exten, '', new ext_vqa($amp_conf['DITECH_VQA_OUTBOUND']));
                    }
                    if ($route['emergency_route'] != '') {
                        $ext->add($context, $exten, '', new ext_set("EMERGENCYROUTE", $route['emergency_route']));
                    }
                    if ($route['intracompany_route'] != '') {
                        $ext->add($context, $exten, '', new ext_set("INTRACOMPANYROUTE", $route['intracompany_route']));
                    }
                    if ($route['mohclass'] != '') {
                        $ext->add($context, $exten, '', new ext_set("MOHCLASS", '${IF($["${MOHCLASS}"=""]?' . $route['mohclass'] . ':${MOHCLASS})}'));
                    }
                    if ($route['outcid'] != '') {
                        if ($route['outcid_mode'] != '') {
                            $ext->add($context, $exten, '', new ext_execif('$["${KEEPCID}"!="TRUE" & ${LEN(${TRUNKCIDOVERRIDE})}=0]', 'Set', 'TRUNKCIDOVERRIDE=' . $route['outcid']));
                        } else {
                            $ext->add($context, $exten, '', new ext_execif('$["${KEEPCID}"!="TRUE" & ${LEN(${DB(AMPUSER/${AMPUSER}/outboundcid)})}=0 & ${LEN(${TRUNKCIDOVERRIDE})}=0]', 'Set', 'TRUNKCIDOVERRIDE=' . $route['outcid']));
                        }
                    }
                    $ext->add($context, $exten, '', new ext_set("_NODEST", ""));
                    $password = $route['password'];
                    foreach ($trunks as $trunk_id) {
                        if (isset($trunk_table[$trunk_id])) {
                            switch (strtolower($trunk_table[$trunk_id]['tech'])) {
                                case 'dundi':
                                    $trunk_macro = 'dialout-dundi';
                                    break;
                                case 'enum':
                                    $trunk_macro = 'dialout-enum';
                                    break;
                                default:
                                    $trunk_macro = 'dialout-trunk';
                                    break;
                            }
                        }
                        $ext->add($context, $exten, '', new ext_macro($trunk_macro, $trunk_id . ',' . $pattern['prepend_digits'] . '${EXTEN' . $offset . '},' . $password . ',' . $trunk_table[$trunk_id]['continue']));
                        $password = '';
                        $trunk_type_needed['macro-' . $trunk_macro] = true;
                    }
                    if ($route['dest']) {
                        // Put back the saved CID since each trunk attempt screws with it and set KEEPCID since this is
                        // a form of forwarding at this point. We could use REALCALLERIDNUM but that doesn't preserve CNAM
                        // which may be wiped out and we may want it.
                        //
                        $ext->add($context, $exten, '', new ext_noop_trace('All trunks failed calling ${EXTEN}, going to destination'));
                        $ext->add($context, $exten, '', new ext_set('CALLERID(all)', '${ROUTE_CIDSAVE}'));
                        $ext->add($context, $exten, '', new ext_set('_KEEPCID', 'TRUE'));
                        $ext->add($context, $exten, '', new ext_goto($route['dest']));
                    } else {
                        $ext->add($context, $exten, '', new ext_noop_trace('All trunks failed calling ${EXTEN}, playing default congestion'));
                        $ext->add($context, $exten, '', new ext_macro("outisbusy"));
                    }
                }
                unset($add_extra_pri1);
            }
            general_generate_indications();
            // "blackhole" destinations
            $ext->add('app-blackhole', 'hangup', '', new ext_noop('Blackhole Dest: Hangup'));
            $ext->add('app-blackhole', 'hangup', '', new ext_hangup());
            $ext->add('app-blackhole', 'zapateller', '', new ext_noop('Blackhole Dest: Play SIT Tone'));
            $ext->add('app-blackhole', 'zapateller', '', new ext_answer());
            $ext->add('app-blackhole', 'zapateller', '', new ext_zapateller());
            // Should hangup ?
            // $ext->add('app-blackhole', 'zapateller', '', new ext_hangup());
            $ext->add('app-blackhole', 'musiconhold', '', new ext_noop('Blackhole Dest: Put caller on hold forever'));
            $ext->add('app-blackhole', 'musiconhold', '', new ext_answer());
            $ext->add('app-blackhole', 'musiconhold', '', new ext_musiconhold());
            $ext->add('app-blackhole', 'congestion', '', new ext_noop('Blackhole Dest: Congestion'));
            $ext->add('app-blackhole', 'congestion', '', new ext_progress());
            $ext->add('app-blackhole', 'congestion', '', new ext_playtones('congestion'));
            $ext->add('app-blackhole', 'congestion', '', new ext_congestion());
            $ext->add('app-blackhole', 'congestion', '', new ext_hangup());
            $ext->add('app-blackhole', 'busy', '', new ext_noop('Blackhole Dest: Busy'));
            $ext->add('app-blackhole', 'busy', '', new ext_progress());
            $ext->add('app-blackhole', 'busy', '', new ext_busy());
            $ext->add('app-blackhole', 'busy', '', new ext_hangup());
            $ext->add('app-blackhole', 'ring', '', new ext_noop('Blackhole Dest: Ring'));
            $ext->add('app-blackhole', 'ring', '', new ext_answer());
            $ext->add('app-blackhole', 'ring', '', new ext_playtones('ring'));
            $ext->add('app-blackhole', 'ring', '', new ext_wait(300));
            $ext->add('app-blackhole', 'ring', '', new ext_hangup());
            $ext->add('app-blackhole', 'no-service', '', new ext_noop('Blackhole Dest: No service'));
            $ext->add('app-blackhole', 'no-service', '', new ext_answer());
            $ext->add('app-blackhole', 'no-service', '', new ext_wait('1'));
            $ext->add('app-blackhole', 'no-service', '', new ext_zapateller());
            $ext->add('app-blackhole', 'no-service', '', new ext_playback('ss-noservice'));
            $ext->add('app-blackhole', 'no-service', '', new ext_hangup());
            if ($amp_conf['AMPBADNUMBER']) {
                $context = 'bad-number';
                $exten = '_X.';
                $ext->add($context, $exten, '', new extension('ResetCDR()'));
                $ext->add($context, $exten, '', new extension('NoCDR()'));
                $ext->add($context, $exten, '', new ext_progress());
                $ext->add($context, $exten, '', new ext_wait('1'));
                $ext->add($context, $exten, '', new ext_playback('silence/1&cannot-complete-as-dialed&check-number-dial-again,noanswer'));
                $ext->add($context, $exten, '', new ext_wait('1'));
                $ext->add($context, $exten, '', new ext_congestion('20'));
                $ext->add($context, $exten, '', new ext_hangup());
            }
            if ($amp_conf['AST_FUNC_PRESENCE_STATE']) {
                $states = array('available' => 'Available', 'chat' => 'Chatty', 'away' => 'Away', 'dnd' => 'DND', 'xa' => 'Extended Away', 'unavailable' => 'Unavailable');
                $context = 'sub-presencestate-display';
                $exten = 's';
                $ext->add($context, $exten, '', new ext_goto(1, 'state-${TOLOWER(${PRESENCE_STATE(CustomPresence:${ARG1},value)})}'));
                foreach ($states as $state => $display) {
                    $exten = 'state-' . $state;
                    $ext->add($context, $exten, '', new ext_setvar('PRESENCESTATE_DISPLAY', '(' . $display . ')'));
                    $ext->add($context, $exten, '', new ext_return(''));
                }
                // Don't display anything if presencestate is unknown (Coding bug)
                $exten = '_state-.';
                $ext->add($context, $exten, '', new ext_setvar('PRESENCESTATE_DISPLAY', ''));
                $ext->add($context, $exten, '', new ext_return(''));
                // Don't display anything if presencestate is empty (not set).
                $exten = 'state-';
                $ext->add($context, $exten, '', new ext_setvar('PRESENCESTATE_DISPLAY', ''));
                $ext->add($context, $exten, '', new ext_return(''));
            }
            /*
            ;------------------------------------------------------------------------
            ; [macro-confirm]
            ;------------------------------------------------------------------------
            ; CONTEXT:      macro-confirm
            ; PURPOSE:      added default message if none supplied
            ;
            ; Follom-Me and Ringgroups provide an option to supply a message to be
            ; played as part of the confirmation. These changes have added a default
            ; message if none is supplied.
            ;
            ;------------------------------------------------------------------------
            */
            $context = 'macro-confirm';
            $exten = 's';
            $ext->add($context, $exten, '', new ext_setvar('LOOPCOUNT', '0'));
            $ext->add($context, $exten, '', new ext_setvar('__MACRO_RESULT', 'ABORT'));
            $ext->add($context, $exten, '', new ext_setvar('MSG1', '${IF($["${ARG1}${ALT_CONFIRM_MSG}"=""]?incoming-call-1-accept-2-decline:${IF($[${LEN(${ALT_CONFIRM_MSG})}>0]?${ALT_CONFIRM_MSG}:${ARG1})})}'));
            if ($ast_ge_14) {
                $ext->add($context, $exten, 'start', new ext_background('${MSG1},m,${CHANNEL(language)},macro-confirm'));
            } else {
                $ext->add($context, $exten, 'start', new ext_background('${MSG1},m,${LANGUAGE},macro-confirm'));
            }
            $ext->add($context, $exten, '', new ext_read('INPUT', '', 1, '', '', 4));
            $ext->add($context, $exten, '', new ext_gotoif('$[${LEN(${INPUT})} > 0]', '${INPUT},1', 't,1'));
            $exten = '1';
            if ($amp_conf['AST_FUNC_SHARED']) {
                $ext->add($context, $exten, '', new ext_gotoif('$["${DB_EXISTS(RG/${ARG3}/${UNIQCHAN})}"="0" & "${SHARED(ANSWER_STATUS,${FORCE_CONFIRM})}"=""]', 'toolate,1'));
            } else {
                $ext->add($context, $exten, '', new ext_gotoif('$["${FORCE_CONFIRM}" != ""]', 'skip'));
                $ext->add($context, $exten, '', new ext_gotoif('$["${DB_EXISTS(RG/${ARG3}/${UNIQCHAN})}"="0"]', 'toolate,1'));
            }
            $ext->add($context, $exten, '', new ext_dbdel('RG/${ARG3}/${UNIQCHAN}'));
            $ext->add($context, $exten, '', new ext_macro('blkvm-clr'));
            if ($amp_conf['AST_FUNC_SHARED']) {
                $ext->add($context, $exten, '', new ext_setvar('SHARED(ANSWER_STATUS,${FORCE_CONFIRM})', ''));
            }
            $ext->add($context, $exten, 'skip', new ext_setvar('__MACRO_RESULT', ''));
            $ext->add($context, $exten, '', new ext_execif('$[("${MOHCLASS}"!="default") & ("${MOHCLASS}"!="")]', 'Set', 'CHANNEL(musicclass)=${MOHCLASS}'));
            $ext->add($context, $exten, 'exitopt1', new ext_macroexit());
            $exten = '2';
            $ext->add($context, $exten, '', new ext_goto(1, 'noanswer'));
            $exten = '3';
            $ext->add($context, $exten, '', new ext_saydigits('${CALLCONFIRMCID}'));
            if ($amp_conf['AST_FUNC_SHARED']) {
                $ext->add($context, $exten, '', new ext_gotoif('$["${DB_EXISTS(RG/${ARG3}/${UNIQCHAN})}"="0" & "${SHARED(ANSWER_STATUS,${FORCE_CONFIRM})}"=""]', 'toolate,1', 's,start'));
            } else {
                $ext->add($context, $exten, '', new ext_gotoif('$["${DB_EXISTS(RG/${ARG3}/${UNIQCHAN})}"="0" & "${FORCE_CONFIRM}"=""]', 'toolate,1', 's,start'));
            }
            $exten = 't';
            if ($amp_conf['AST_FUNC_SHARED']) {
                $ext->add($context, $exten, '', new ext_gotoif('$["${DB_EXISTS(RG/${ARG3}/${UNIQCHAN})}"="0" & "${SHARED(ANSWER_STATUS,${FORCE_CONFIRM})}"=""]', 'toolate,1'));
            } else {
                $ext->add($context, $exten, '', new ext_gotoif('$["${DB_EXISTS(RG/${ARG3}/${UNIQCHAN})}"="0" & "${FORCE_CONFIRM}"=""]', 'toolate,1'));
            }
            $ext->add($context, $exten, '', new ext_setvar('LOOPCOUNT', '$[ ${LOOPCOUNT} + 1 ]'));
            $ext->add($context, $exten, '', new ext_gotoif('$[ ${LOOPCOUNT} < 5 ]', 's,start', 'noanswer,1'));
            $exten = '_X';
            if ($ast_ge_14) {
                $ext->add($context, $exten, '', new ext_background('invalid,m,${CHANNEL(language)},macro-confirm'));
            } else {
                $ext->add($context, $exten, '', new ext_background('invalid,m,${LANGUAGE},macro-confirm'));
            }
            if ($amp_conf['AST_FUNC_SHARED']) {
                $ext->add($context, $exten, '', new ext_gotoif('$["${DB_EXISTS(RG/${ARG3}/${UNIQCHAN})}"="0" | "${SHARED(ANSWER_STATUS,${FORCE_CONFIRM})}"=""]', 'toolate,1'));
            } else {
                $ext->add($context, $exten, '', new ext_gotoif('$["${DB_EXISTS(RG/${ARG3}/${UNIQCHAN})}"="0" & "${FORCE_CONFIRM}"=""]', 'toolate,1'));
            }
            $ext->add($context, $exten, '', new ext_setvar('LOOPCOUNT', '$[ ${LOOPCOUNT} + 1 ]'));
            $ext->add($context, $exten, '', new ext_gotoif('$[ ${LOOPCOUNT} < 5 ]', 's,start', 'noanswer,1'));
            $exten = 'noanswer';
            $ext->add($context, $exten, '', new ext_setvar('__MACRO_RESULT', 'ABORT'));
            $ext->add($context, $exten, 'exitnoanswer', new ext_macroexit());
            $exten = 'toolate';
            $ext->add($context, $exten, '', new ext_setvar('MSG2', '${IF($["foo${ARG2}" != "foo"]?${ARG2}:"incoming-call-no-longer-avail")}'));
            $ext->add($context, $exten, '', new ext_playback('${MSG2}'));
            $ext->add($context, $exten, '', new ext_setvar('__MACRO_RESULT', 'ABORT'));
            $ext->add($context, $exten, 'exittoolate', new ext_macroexit());
            $exten = 'h';
            $ext->add($context, $exten, '', new ext_macro('hangupcall'));
            /*
            ;------------------------------------------------------------------------
            ; [macro-auto-confirm]
            ;------------------------------------------------------------------------
            ; This macro is called from ext-local-confirm to auto-confirm a call so that other extensions
            ; are aware that the call has been answered.
            ;
            ;------------------------------------------------------------------------
            */
            $context = 'macro-auto-confirm';
            $exten = 's';
            $ext->add($context, $exten, '', new ext_setvar('__MACRO_RESULT', ''));
            $ext->add($context, $exten, '', new ext_set('CFIGNORE', ''));
            $ext->add($context, $exten, '', new ext_set('MASTER_CHANNEL(CFIGNORE)', ''));
            $ext->add($context, $exten, '', new ext_set('FORWARD_CONTEXT', 'from-internal'));
            $ext->add($context, $exten, '', new ext_set('MASTER_CHANNEL(FORWARD_CONTEXT)', 'from-internal'));
            $ext->add($context, $exten, '', new ext_macro('blkvm-clr'));
            $ext->add($context, $exten, '', new ext_dbdel('RG/${ARG1}/${UNIQCHAN}'));
            $ext->add($context, $exten, '', new ext_noop_trace('DIALEDPEERNUMBER: ${DIALEDPEERNUMBER} CID: ${CALLERID(all)}'));
            if ($amp_conf['AST_FUNC_MASTER_CHANNEL'] && $amp_conf['AST_FUNC_CONNECTEDLINE']) {
                // Check that it is numeric so we don't pollute it with odd dialplan stuff like FMGL-blah from followme
                $ext->add($context, $exten, '', new ext_execif('$[!${REGEX("[^0-9]" ${DIALEDPEERNUMBER})} && "${DB(AMPUSER/${AMPUSER}/cidname)}" != ""]', 'Set', 'MASTER_CHANNEL(CONNECTEDLINE(num))=${DIALEDPEERNUMBER}'));
                $ext->add($context, $exten, '', new ext_execif('$[!${REGEX("[^0-9]" ${DIALEDPEERNUMBER})} && "${DB(AMPUSER/${AMPUSER}/cidname)}" != ""]', 'Set', 'MASTER_CHANNEL(CONNECTEDLINE(name))=${DB(AMPUSER/${DIALEDPEERNUMBER}/cidname)}'));
            }
            /*
            ;------------------------------------------------------------------------
            ; [macro-auto-blkvm]
            ;------------------------------------------------------------------------
            ; This macro is called for any extension dialed form a queue, ringgroup
            ; or followme, so that the answering extension can clear the voicemail block
            ; override allow subsequent transfers to properly operate.
            ;
            ;------------------------------------------------------------------------
            */
            $context = 'macro-auto-blkvm';
            $exten = 's';
            $ext->add($context, $exten, '', new ext_setvar('__MACRO_RESULT', ''));
            $ext->add($context, $exten, '', new ext_set('CFIGNORE', ''));
            $ext->add($context, $exten, '', new ext_set('MASTER_CHANNEL(CFIGNORE)', ''));
            $ext->add($context, $exten, '', new ext_set('FORWARD_CONTEXT', 'from-internal'));
            $ext->add($context, $exten, '', new ext_set('MASTER_CHANNEL(FORWARD_CONTEXT)', 'from-internal'));
            $ext->add($context, $exten, '', new ext_macro('blkvm-clr'));
            $ext->add($context, $exten, '', new ext_noop_trace('DIALEDPEERNUMBER: ${DIALEDPEERNUMBER} CID: ${CALLERID(all)}'));
            if ($amp_conf['AST_FUNC_MASTER_CHANNEL'] && $amp_conf['AST_FUNC_CONNECTEDLINE']) {
                // Check that it is numeric so we don't pollute it with odd dialplan stuff like FMGL-blah from followme
                $ext->add($context, $exten, '', new ext_execif('$[!${REGEX("[^0-9]" ${DIALEDPEERNUMBER})} && "${DB(AMPUSER/${AMPUSER}/cidname)}" != ""]', 'Set', 'MASTER_CHANNEL(CONNECTEDLINE(num))=${DIALEDPEERNUMBER}'));
                $ext->add($context, $exten, '', new ext_execif('$[!${REGEX("[^0-9]" ${DIALEDPEERNUMBER})} && "${DB(AMPUSER/${AMPUSER}/cidname)}" != ""]', 'Set', 'MASTER_CHANNEL(CONNECTEDLINE(name))=${DB(AMPUSER/${DIALEDPEERNUMBER}/cidname)}'));
            }
            /*
            ;------------------------------------------------------------------------
            ; [sub-pincheck]
            ;------------------------------------------------------------------------
            ; This subroutine checks the pincode and then resets the CDR from that point
            ; if the pincode passes. This way the billsec and duration fields are set
            ; properly for pin dialing.
            ;
            ; ${ARG3} is the pincode if this was called, used by dialout-trunk, dialout-enum
            ; and dialout-dundi
            ;
            ;------------------------------------------------------------------------
            */
            $context = 'sub-pincheck';
            $exten = 's';
            $ext->add($context, $exten, '', new ext_authenticate('${ARG3}'));
            $ext->add($context, $exten, '', new ext_resetcdr(''));
            $ext->add($context, $exten, '', new ext_return(''));
            // Subroutine to add diversion header with reason code "no-answer" unless provided differently elsewhere in the dialplan to indicate
            // the reason for the diversion (e.g. CFB could set it to busy)
            //
            if ($amp_conf['DIVERSIONHEADER']) {
                $context = 'sub-diversion-header';
                $exten = 's';
                $ext->add($context, $exten, '', new ext_set('DIVERSION_REASON', '${IF($[${LEN(${DIVERSION_REASON})}=0]?no-answer:${DIVERSION_REASON})}'));
                $ext->add($context, $exten, '', new ext_sipaddheader('Diversion', '<tel:${FROM_DID}>\\;reason=${DIVERSION_REASON}\\;screen=no\\;privacy=off'));
                $ext->add($context, $exten, '', new ext_return(''));
            }
            /*
             * dialout using a trunk, using pattern matching (don't strip any prefix)
             * arg1 = trunk number, arg2 = number, arg3 = route password
             *
             * MODIFIED (PL)
             *
             * Modified both Dial() commands to include the new TRUNK_OPTIONS from the general
             * screen of AMP
             */
            if (function_exists('outroutemsg_get')) {
                $trunkreportmsg_ids = outroutemsg_get();
            } else {
                if (!defined('DEFAULT_MSG')) {
                    define('DEFAULT_MSG', -1);
                }
                if (!defined('CONGESTION_TONE')) {
                    define('CONGESTION_TONE', -2);
                }
                $trunkreportmsg_ids = array('no_answer_msg_id' => -1, 'invalidnmbr_msg_id' => -1);
            }
            // Since rarely used only generate this dialplan if are using this feature
            //
            $generate_trunk_monitor_failure = false;
            foreach ($trunk_table as $tid => $tdetails) {
                // assign and if true no need to continue
                if ($generate_trunk_monitor_failure = $generate_trunk_monitor_failure || $tdetails['failscript']) {
                    break;
                }
            }
            $context = 'macro-dialout-trunk';
            if (!empty($trunk_type_needed[$context])) {
                $exten = 's';
                $ext->add($context, $exten, '', new ext_set('DIAL_TRUNK', '${ARG1}'));
                $ext->add($context, $exten, '', new ext_gosubif('$[$["${ARG3}" != ""] & $["${DB(AMPUSER/${AMPUSER}/pinless)}" != "NOPASSWD"]]', 'sub-pincheck,s,1'));
                $ext->add($context, $exten, '', new ext_gotoif('$["x${OUTDISABLE_${DIAL_TRUNK}}" = "xon"]', 'disabletrunk,1'));
                $ext->add($context, $exten, '', new ext_set('DIAL_NUMBER', '${ARG2}'));
                // fixlocalprefix depends on this
                $ext->add($context, $exten, '', new ext_set('DIAL_TRUNK_OPTIONS', '${DIAL_OPTIONS}'));
                // will be reset to TRUNK_OPTIONS if not intra-company
                $ext->add($context, $exten, '', new ext_set('OUTBOUND_GROUP', 'OUT_${DIAL_TRUNK}'));
                $ext->add($context, $exten, '', new ext_gotoif('$["${OUTMAXCHANS_${DIAL_TRUNK}}foo" = "foo"]', 'nomax'));
                $ext->add($context, $exten, '', new ext_gotoif('$[ ${GROUP_COUNT(OUT_${DIAL_TRUNK})} >= ${OUTMAXCHANS_${DIAL_TRUNK}} ]', 'chanfull'));
                $ext->add($context, $exten, 'nomax', new ext_gotoif('$["${INTRACOMPANYROUTE}" = "YES"]', 'skipoutcid'));
                // Set to YES if treated like internal
                $ext->add($context, $exten, '', new ext_set('DIAL_TRUNK_OPTIONS', '${IF($["${DB_EXISTS(TRUNK/${DIAL_TRUNK}/dialopts)}" = "1"]?${DB_RESULT}:${TRUNK_OPTIONS})}'));
                $ext->add($context, $exten, '', new ext_macro('outbound-callerid', '${DIAL_TRUNK}'));
                $ext->add($context, $exten, 'skipoutcid', new ext_gosubif('$["${PREFIX_TRUNK_${DIAL_TRUNK}}" != ""]', 'sub-flp-${DIAL_TRUNK},s,1'));
                // this sets DIAL_NUMBER to the proper dial string for this trunk
                $ext->add($context, $exten, '', new ext_set('OUTNUM', '${OUTPREFIX_${DIAL_TRUNK}}${DIAL_NUMBER}'));
                // OUTNUM is the final dial number
                $ext->add($context, $exten, '', new ext_set('custom', '${CUT(OUT_${DIAL_TRUNK},:,1)}'));
                // Custom trunks are prefixed with "AMP:"
                // Back to normal processing, whether intracompany or not.
                // But add the macro-setmusic if we don't want music on this outbound call
                // if FORCE_CONFIRM then that macro will set any necessary MOHCLASS, and we will also call the confirm macro
                $ext->add($context, $exten, '', new ext_execif('$["${MOHCLASS}"!="default" & "${MOHCLASS}"!="" & "${FORCE_CONFIRM}"="" ]', 'Set', 'DIAL_TRUNK_OPTIONS=M(setmusic^${MOHCLASS})${DIAL_TRUNK_OPTIONS}'));
                $ext->add($context, $exten, '', new ext_execif('$["${FORCE_CONFIRM}"!="" ]', 'Set', 'DIAL_TRUNK_OPTIONS=${DIAL_TRUNK_OPTIONS}M(confirm)'));
                // This macro call will always be blank and is provided as a hook for customization required prior to making a call
                // such as adding SIP header information or other requirements. All the channel variables from above are present
                $ext->add($context, $exten, 'gocall', new ext_macro('dialout-trunk-predial-hook'));
                $ext->add($context, $exten, '', new ext_gotoif('$["${PREDIAL_HOOK_RET}" = "BYPASS"]', 'bypass,1'));
                if ($amp_conf['AST_FUNC_CONNECTEDLINE'] && $amp_conf['OUTBOUND_DIAL_UPDATE']) {
                    $ext->add($context, $exten, '', new ext_execif('$["${DB(AMPUSER/${AMPUSER}/cidname)}" != ""]', 'Set', 'CONNECTEDLINE(num,i)=${DIAL_NUMBER}'));
                }
                if ($amp_conf['AST_FUNC_CONNECTEDLINE'] && $amp_conf['OUTBOUND_CID_UPDATE']) {
                    $ext->add($context, $exten, '', new ext_execif('$[$["${DB(AMPUSER/${AMPUSER}/cidname)}" != ""] & $["${CALLERID(name)}"!="hidden"]]', 'Set', 'CONNECTEDLINE(name,i)=CID:${CALLERID(number)}'));
                    $ext->add($context, $exten, '', new ext_execif('$[$["${DB(AMPUSER/${AMPUSER}/cidname)}" != ""] & $["${CALLERID(name)}"="hidden"]]', 'Set', 'CONNECTEDLINE(name,i)=CID:(Hidden)${CALLERID(number)}'));
                }
                $ext->add($context, $exten, '', new ext_gotoif('$["${custom}" = "AMP"]', 'customtrunk'));
                $ext->add($context, $exten, '', new ext_dial('${OUT_${DIAL_TRUNK}}/${OUTNUM}${OUT_${DIAL_TRUNK}_SUFFIX}', '${TRUNK_RING_TIMER},${DIAL_TRUNK_OPTIONS}'));
                // Regular Trunk Dial
                $ext->add($context, $exten, '', new ext_noop('Dial failed for some reason with DIALSTATUS = ${DIALSTATUS} and HANGUPCAUSE = ${HANGUPCAUSE}'));
                $ext->add($context, $exten, '', new ext_gotoif('$["${ARG4}" = "on"]', 'continue,1', 's-${DIALSTATUS},1'));
                $ext->add($context, $exten, 'customtrunk', new ext_set('pre_num', '${CUT(OUT_${DIAL_TRUNK},$,1)}'));
                $ext->add($context, $exten, '', new ext_set('the_num', '${CUT(OUT_${DIAL_TRUNK},$,2)}'));
                // this is where we expect to find string OUTNUM
                $ext->add($context, $exten, '', new ext_set('post_num', '${CUT(OUT_${DIAL_TRUNK},$,3)}'));
                $ext->add($context, $exten, '', new ext_gotoif('$["${the_num}" = "OUTNUM"]', 'outnum', 'skipoutnum'));
                // if we didn't find "OUTNUM", then skip to Dial
                $ext->add($context, $exten, 'outnum', new ext_set('the_num', '${OUTNUM}'));
                // replace "OUTNUM" with the actual number to dial
                $ext->add($context, $exten, 'skipoutnum', new ext_dial('${pre_num:4}${the_num}${post_num}', '${TRUNK_RING_TIMER},${DIAL_TRUNK_OPTIONS}'));
                $ext->add($context, $exten, '', new ext_noop('Dial failed for some reason with DIALSTATUS = ${DIALSTATUS} and HANGUPCAUSE = ${HANGUPCAUSE}'));
                $ext->add($context, $exten, '', new ext_gotoif('$["${ARG4}" = "on"]', 'continue,1', 's-${DIALSTATUS},1'));
                $ext->add($context, $exten, 'chanfull', new ext_noop('max channels used up'));
                $exten = 's-BUSY';
                /*
                 * HANGUPCAUSE 17 = Busy, or SIP 486 Busy everywhere
                 */
                $ext->add($context, $exten, '', new ext_noop('Dial failed due to trunk reporting BUSY - giving up'));
                $ext->add($context, $exten, '', new ext_playtones('busy'));
                $ext->add($context, $exten, '', new ext_busy(20));
                /*
                 * There are reported bugs in Asterisk Blind Trasfers that result in Dial() returning and continuing
                 * execution with a status of ANSWER. So we hangup at this point
                 */
                $exten = 's-ANSWER';
                $ext->add($context, $exten, '', new ext_noop('Call successfully answered - Hanging up now'));
                $ext->add($context, $exten, '', new ext_macro('hangupcall'));
                $exten = 's-NOANSWER';
                /*
                 * HANGUPCAUSE 18 = No User Responding, or SIP 408 Request Timeout
                 * HANGUPCAUSE 19 = No Answer From The User, or SIP 480 Temporarily unavailable, SIP 483 To many hops
                 */
                $ext->add($context, $exten, '', new ext_noop('Dial failed due to trunk reporting NOANSWER - giving up'));
                $ext->add($context, $exten, '', new ext_progress());
                switch ($trunkreportmsg_ids['no_answer_msg_id']) {
                    case DEFAULT_MSG:
                        $ext->add($context, $exten, '', new ext_playback('number-not-answering,noanswer'));
                        break;
                    case CONGESTION_TONE:
                        $ext->add($context, $exten, '', new ext_playtones('congestion'));
                        break;
                    default:
                        $message = recordings_get_file($trunkreportmsg_ids['no_answer_msg_id']);
                        $message = $message != "" ? $message : "number-not-answering";
                        $ext->add($context, $exten, '', new ext_playback("{$message}, noanswer"));
                }
                $ext->add($context, $exten, '', new ext_congestion(20));
                $exten = 's-INVALIDNMBR';
                /*
                 * HANGUPCAUSE 28 = Address Incomplete, or SIP 484 Address Incomplete
                 */
                $ext->add($context, $exten, '', new ext_noop('Dial failed due to trunk reporting Address Incomplete - giving up'));
                $ext->add($context, $exten, '', new ext_progress());
                switch ($trunkreportmsg_ids['invalidnmbr_msg_id']) {
                    case DEFAULT_MSG:
                        $ext->add($context, $exten, '', new ext_playback('ss-noservice,noanswer'));
                        break;
                    case CONGESTION_TONE:
                        $ext->add($context, $exten, '', new ext_playtones('congestion'));
                        break;
                    default:
                        $message = recordings_get_file($trunkreportmsg_ids['invalidnmbr_msg_id']);
                        $message = $message != "" ? $message : "ss-noservice";
                        $ext->add($context, $exten, '', new ext_playback("{$message}, noanswer"));
                }
                $ext->add($context, $exten, '', new ext_busy(20));
                $exten = "s-CHANGED";
                $ext->add($context, $exten, '', new ext_noop('Dial failed due to trunk reporting Number Changed - giving up'));
                $ext->add($context, $exten, '', new ext_playtones('busy'));
                $ext->add($context, $exten, '', new ext_busy(20));
                $exten = '_s-.';
                $ext->add($context, $exten, '', new ext_set('RC', '${IF($[${ISNULL(${HANGUPCAUSE})}]?0:${HANGUPCAUSE})}'));
                $ext->add($context, $exten, '', new ext_goto('1', '${RC}'));
                $ext->add($context, '17', '', new ext_goto('1', 's-BUSY'));
                $ext->add($context, '18', '', new ext_goto('1', 's-NOANSWER'));
                $ext->add($context, '22', '', new ext_goto('1', 's-CHANGED'));
                $ext->add($context, '23', '', new ext_goto('1', 's-CHANGED'));
                $ext->add($context, '1', '', new ext_goto('1', 's-INVALIDNMBR'));
                $ext->add($context, '28', '', new ext_goto('1', 's-INVALIDNMBR'));
                $ext->add($context, '_X', '', new ext_goto('1', 'continue'));
                $ext->add($context, '_X.', '', new ext_goto('1', 'continue'));
                $exten = 'continue';
                if ($generate_trunk_monitor_failure) {
                    $ext->add($context, $exten, '', new ext_gotoif('$["${OUTFAIL_${ARG1}}" = ""]', 'noreport'));
                    $ext->add($context, $exten, '', new ext_agi('${OUTFAIL_${ARG1}}'));
                }
                $ext->add($context, $exten, 'noreport', new ext_noop('TRUNK Dial failed due to ${DIALSTATUS} HANGUPCAUSE: ${HANGUPCAUSE} - failing through to other trunks'));
                $ext->add($context, $exten, '', new ext_execif('$["${AMPUSER}"!="" ]', 'Set', 'CALLERID(number)=${AMPUSER}'));
                $ext->add($context, 'disabletrunk', '', new ext_noop('TRUNK: ${OUT_${DIAL_TRUNK}} DISABLED - falling through to next trunk'));
                $ext->add($context, 'bypass', '', new ext_noop('TRUNK: ${OUT_${DIAL_TRUNK}} BYPASSING because dialout-trunk-predial-hook'));
                $ext->add($context, 'h', '', new ext_macro('hangupcall'));
            }
            // if trunk_type_needed
            $context = 'macro-dialout-dundi';
            if (!empty($trunk_type_needed[$context])) {
                $exten = 's';
                /*
                 * Dialout Dundi Trunk
                 */
                $ext->add($context, $exten, '', new ext_set('DIAL_TRUNK', '${ARG1}'));
                $ext->add($context, $exten, '', new ext_gosubif('$[$["${ARG3}" != ""] & $["${DB(AMPUSER/${AMPUSER}/pinless)}" != "NOPASSWD"]]', 'sub-pincheck,s,1'));
                $ext->add($context, $exten, '', new ext_gotoif('$["x${OUTDISABLE_${DIAL_TRUNK}}" = "xon"]', 'disabletrunk,1'));
                $ext->add($context, $exten, '', new ext_set('DIAL_NUMBER', '${ARG2}'));
                // fixlocalprefix depends on this
                $ext->add($context, $exten, '', new ext_set('DIAL_TRUNK_OPTIONS', '${DIAL_OPTIONS}'));
                // will be reset to TRUNK_OPTIONS if not intra-company
                $ext->add($context, $exten, '', new ext_set('OUTBOUND_GROUP', 'OUT_${DIAL_TRUNK}'));
                $ext->add($context, $exten, '', new ext_gotoif('$["${OUTMAXCHANS_${DIAL_TRUNK}}foo" = "foo"]', 'nomax'));
                $ext->add($context, $exten, '', new ext_gotoif('$[ ${GROUP_COUNT(OUT_${DIAL_TRUNK})} >= ${OUTMAXCHANS_${DIAL_TRUNK}} ]', 'chanfull'));
                $ext->add($context, $exten, 'nomax', new ext_gotoif('$["${INTRACOMPANYROUTE}" = "YES"]', 'skipoutcid'));
                // Set to YES if treated like internal
                $ext->add($context, $exten, '', new ext_set('DIAL_TRUNK_OPTIONS', '${IF($["${DB_EXISTS(TRUNK/${DIAL_TRUNK}/dialopts)}" = "1"]?${DB_RESULT}:${TRUNK_OPTIONS})}'));
                $ext->add($context, $exten, '', new ext_macro('outbound-callerid', '${DIAL_TRUNK}'));
                $ext->add($context, $exten, 'skipoutcid', new ext_gosubif('$["${PREFIX_TRUNK_${DIAL_TRUNK}}" != ""]', 'sub-flp-${DIAL_TRUNK},s,1'));
                // manipulate DIAL_NUMBER
                $ext->add($context, $exten, '', new ext_set('OUTNUM', '${OUTPREFIX_${DIAL_TRUNK}}${DIAL_NUMBER}'));
                // OUTNUM is the final dial number
                // Back to normal processing, whether intracompany or not.
                // But add the macro-setmusic if we don't want music on this outbound call
                $ext->add($context, $exten, '', new ext_execif('$["${MOHCLASS}"!="default" & "${MOHCLASS}"!="" & "${FORCE_CONFIRM}"="" ]', 'Set', 'DIAL_TRUNK_OPTIONS=M(setmusic^${MOHCLASS})${DIAL_TRUNK_OPTIONS}'));
                $ext->add($context, $exten, '', new ext_execif('$["${FORCE_CONFIRM}"!="" ]', 'Set', 'DIAL_TRUNK_OPTIONS=${DIAL_TRUNK_OPTIONS}M(confirm)'));
                // This macro call will always be blank and is provided as a hook for customization required prior to making a call
                // such as adding SIP header information or other requirements. All the channel variables from above are present
                $ext->add($context, $exten, 'gocall', new ext_macro('dialout-dundi-predial-hook'));
                $ext->add($context, $exten, '', new ext_gotoif('$["${PREDIAL_HOOK_RET}" = "BYPASS"]', 'bypass,1'));
                if ($amp_conf['AST_FUNC_CONNECTEDLINE'] && $amp_conf['OUTBOUND_DIAL_UPDATE']) {
                    $ext->add($context, $exten, '', new ext_execif('$["${DB(AMPUSER/${AMPUSER}/cidname)}" != ""]', 'Set', 'CONNECTEDLINE(num,i)=${DIAL_NUMBER}'));
                }
                if ($amp_conf['AST_FUNC_CONNECTEDLINE'] && $amp_conf['OUTBOUND_CID_UPDATE']) {
                    $ext->add($context, $exten, '', new ext_execif('$["${DB(AMPUSER/${AMPUSER}/cidname)}" != ""]', 'Set', 'CONNECTEDLINE(name,i)=CID:${CALLERID(number)}'));
                }
                $ext->add($context, $exten, '', new ext_macro('dundi-${DIAL_TRUNK}', '${OUTNUM}'));
                $ext->add($context, $exten, '', new ext_gotoif('$["${ARG4}" = "on"]', 'continue,1', 's-${DIALSTATUS},1'));
                $ext->add($context, $exten, 'chanfull', new ext_noop('max channels used up'));
                $exten = 's-BUSY';
                /*
                 * HANGUPCAUSE 17 = Busy, or SIP 486 Busy everywhere
                 */
                $ext->add($context, $exten, '', new ext_noop('Dial failed due to trunk reporting BUSY - giving up'));
                $ext->add($context, $exten, '', new ext_playtones('busy'));
                $ext->add($context, $exten, '', new ext_busy(20));
                /*
                 * There are reported bugs in Asterisk Blind Trasfers that result in Dial() returning and continuing
                 * execution with a status of ANSWER. So we hangup at this point
                 */
                $exten = 's-ANSWER';
                $ext->add($context, $exten, '', new ext_noop('Call successfully answered - Hanging up now'));
                $ext->add($context, $exten, '', new ext_macro('hangupcall'));
                $exten = 's-NOANSWER';
                /*
                 * HANGUPCAUSE 18 = No User Responding, or SIP 408 Request Timeout
                 * HANGUPCAUSE 19 = No Answer From The User, or SIP 480 Temporarily unavailable, SIP 483 To many hops
                 */
                $ext->add($context, $exten, '', new ext_noop('Dial failed due to trunk reporting NOANSWER - giving up'));
                $ext->add($context, $exten, '', new ext_progress());
                switch ($trunkreportmsg_ids['no_answer_msg_id']) {
                    case DEFAULT_MSG:
                        $ext->add($context, $exten, '', new ext_playback('number-not-answering,noanswer'));
                        break;
                    case CONGESTION_TONE:
                        $ext->add($context, $exten, '', new ext_playtones('congestion'));
                        break;
                    default:
                        $message = recordings_get_file($trunkreportmsg_ids['no_answer_msg_id']);
                        $message = $message != "" ? $message : "number-not-answering";
                        $ext->add($context, $exten, '', new ext_playback("{$message}, noanswer"));
                }
                $ext->add($context, $exten, '', new ext_congestion(20));
                $exten = 's-INVALIDNMBR';
                /*
                 * HANGUPCAUSE 28 = Address Incomplete, or SIP 484 Address Incomplete
                 * HANGUPCAUSE 1 = Unallocated (unassigned) number
                 */
                $ext->add($context, $exten, '', new ext_noop('Dial failed due to trunk reporting Address Incomplete - giving up'));
                $ext->add($context, $exten, '', new ext_progress());
                switch ($trunkreportmsg_ids['invalidnmbr_msg_id']) {
                    case DEFAULT_MSG:
                        $ext->add($context, $exten, '', new ext_playback('ss-noservice,noanswer'));
                        break;
                    case CONGESTION_TONE:
                        $ext->add($context, $exten, '', new ext_playtones('congestion'));
                        break;
                    default:
                        $message = recordings_get_file($trunkreportmsg_ids['invalidnmbr_msg_id']);
                        $message = $message != "" ? $message : "ss-noservice";
                        $ext->add($context, $exten, '', new ext_playback("{$message}, noanswer"));
                }
                $ext->add($context, $exten, '', new ext_busy(20));
                $exten = "s-CHANGED";
                $ext->add($context, $exten, '', new ext_noop('Dial failed due to trunk reporting Number Changed - giving up'));
                $ext->add($context, $exten, '', new ext_playtones('busy'));
                $ext->add($context, $exten, '', new ext_busy(20));
                $exten = '_s-.';
                $ext->add($context, $exten, '', new ext_set('RC', '${IF($[${ISNULL(${HANGUPCAUSE})}]?0:${HANGUPCAUSE})}'));
                $ext->add($context, $exten, '', new ext_goto('1', '${RC}'));
                $ext->add($context, '17', '', new ext_goto('1', 's-BUSY'));
                $ext->add($context, '18', '', new ext_goto('1', 's-NOANSWER'));
                $ext->add($context, '22', '', new ext_goto('1', 's-CHANGED'));
                $ext->add($context, '23', '', new ext_goto('1', 's-CHANGED'));
                $ext->add($context, '28', '', new ext_goto('1', 's-INVALIDNMBR'));
                $ext->add($context, '_X', '', new ext_goto('1', 'continue'));
                $ext->add($context, '_X.', '', new ext_goto('1', 'continue'));
                $exten = 'continue';
                if ($generate_trunk_monitor_failure) {
                    $ext->add($context, $exten, '', new ext_gotoif('$["${OUTFAIL_${ARG1}}" = ""]', 'noreport'));
                    $ext->add($context, $exten, '', new ext_agi('${OUTFAIL_${ARG1}}'));
                }
                $ext->add($context, $exten, 'noreport', new ext_noop('TRUNK Dial failed due to ${DIALSTATUS} HANGUPCAUSE: ${HANGUPCAUSE} - failing through to other trunks'));
                $ext->add($context, $exten, '', new ext_execif('$["${AMPUSER}"!="" ]', 'Set', 'CALLERID(number)=${AMPUSER}'));
                $ext->add($context, 'disabletrunk', '', new ext_noop('TRUNK: ${OUT_${DIAL_TRUNK}} DISABLED - falling through to next trunk'));
                $ext->add($context, 'bypass', '', new ext_noop('TRUNK: ${OUT_${DIAL_TRUNK}} BYPASSING because dialout-dundi-predial-hook'));
                $ext->add($context, 'h', '', new ext_macro('hangupcall'));
            }
            // if trunk_type_needed
            /*
            ;-------------------------------------------------------------------------------
            ; macro-privacy-mgr:
            ;
            ; Privacy Manager Macro makes sure that any calls that don't pass the privacy manager are presented
            ; with congestion since there have been observed cases of the call continuing if not stopped with a
            ; congestion, and this provides a slightly more friendly 'sorry' message in case the user is
            ; legitimately trying to be cooperative.
            ;
            ; Note: the following options are configurable in privacy.conf:
            ;
            ;	maxretries = 3 ; default value, number of retries before failing
            ;	minlength = 10 ; default value, number of digits to be accepted as valid CID
            ;
            ;-------------------------------------------------------------------------------
            */
            $context = 'macro-privacy-mgr';
            $exten = 's';
            $ext->add($context, $exten, '', new ext_set('KEEPCID', '${CALLERID(num)}'));
            $ext->add($context, $exten, '', new ext_set('TESTCID', '${IF($["${CALLERID(num):0:1}"="+"]?${MATH(1+${CALLERID(num):1})}:${MATH(1+${CALLERID(num)})})}'));
            $ext->add($context, $exten, '', new ext_execif('$[${LEN(${TESTCID})}=0]', 'Set', 'CALLERID(num)='));
            $ext->add($context, $exten, '', new ext_privacymanager('${ARG1},${ARG2}'));
            $ext->add($context, $exten, '', new ext_gotoif('$["${PRIVACYMGRSTATUS}"="FAILED"]', 'fail'));
            $ext->add($context, $exten, '', new ext_gosubif('$["${CALLED_BLACKLIST}"="1"]', 'app-blacklist-check,s,1'));
            $ext->add($context, $exten, '', new ext_set('CALLERID(num-pres)', 'allowed_passed_screen'));
            $ext->add($context, $exten, '', new ext_macroexit());
            $ext->add($context, $exten, 'fail', new ext_noop('STATUS: ${PRIVACYMGRSTATUS} CID: ${CALLERID(num)} ${CALLERID(name)} CALLPRES: ${CALLLINGPRES}'));
            $ext->add($context, $exten, '', new ext_playback('sorry-youre-having-problems&goodbye'));
            $ext->add($context, $exten, '', new ext_playtones('congestion'));
            $ext->add($context, $exten, '', new ext_congestion(20));
            $ext->add($context, 'h', '', new ext_hangup());
            /*
             * sets the CallerID of the device to that of the logged in user
             *
             * ${AMPUSER} is set upon return to the real user despite any aliasing that may
             * have been set as a result of the AMPUSER/<nnn>/cidnum field. This is used by
             * features like DND, CF, etc. to set the proper structure on aliased instructions
             */
            $context = 'macro-user-callerid';
            $exten = 's';
            //$ext->add($context, $exten, '', new ext_noop('user-callerid: ${CALLERID(name)} ${CALLERID(number)}'));
            // for i18n playback in multiple languages
            $ext->add($context, 'lang-playback', '', new ext_gosubif('$[${DIALPLAN_EXISTS(' . $context . ',${CHANNEL(language)})}]', $context . ',${CHANNEL(language)},${ARG1}', $context . ',en,${ARG1}'));
            $ext->add($context, 'lang-playback', '', new ext_return());
            $ext->add($context, $exten, '', new ext_set('TOUCH_MONITOR', '${UNIQUEID}'));
            // make sure AMPUSER is set if it doesn't get set below
            $ext->add($context, $exten, '', new ext_set('AMPUSER', '${IF($["${AMPUSER}" = ""]?${CALLERID(number)}:${AMPUSER})}'));
            $ext->add($context, $exten, '', new ext_gotoif('$["${CUT(CHANNEL,@,2):5:5}"="queue" | ${LEN(${AMPUSERCIDNAME})}]', 'report'));
            $ext->add($context, $exten, '', new ext_execif('$["${REALCALLERIDNUM:1:2}" = ""]', 'Set', 'REALCALLERIDNUM=${CALLERID(number)}'));
            $ext->add($context, $exten, '', new ext_set('AMPUSER', '${DB(DEVICE/${REALCALLERIDNUM}/user)}'));
            // Device & User: If they're not signed in, then they can't do anything.
            $ext->add($context, $exten, '', new ext_gotoif('$["${AMPUSER}" = "none"]', 'limit'));
            $ext->add($context, $exten, '', new ext_set('AMPUSERCIDNAME', '${DB(AMPUSER/${AMPUSER}/cidname)}'));
            $ext->add($context, $exten, '', new ext_gotoif('$["${AMPUSERCIDNAME:1:2}" = ""]', 'report'));
            // user may masquerade as a different user internally, so set the internal cid as indicated
            // but keep the REALCALLERID which is used to determine their true identify and lookup info
            // during outbound calls.
            $ext->add($context, $exten, '', new ext_set('AMPUSERCID', '${IF($["${ARG2}" != "EXTERNAL" & "${DB_EXISTS(AMPUSER/${AMPUSER}/cidnum)}" = "1"]?${DB_RESULT}:${AMPUSER})}'));
            // If there is a defined dialopts then use it, otherwise use the global default
            //
            $ext->add($context, $exten, '', new ext_set('__DIAL_OPTIONS', '${IF($["${DB_EXISTS(AMPUSER/${AMPUSER}/dialopts)}" = "1"]?${DB_RESULT}:${DIAL_OPTIONS})}'));
            $ext->add($context, $exten, '', new ext_set('CALLERID(all)', '"${AMPUSERCIDNAME}" <${AMPUSERCID}>'));
            $ext->add($context, $exten, '', new ext_noop_trace('Current Concurrency Count for ${AMPUSER}: ${GROUP_COUNT(${AMPUSER}@concurrency_limit)}, User Limit: ${DB(AMPUSER/${AMPUSER}/concurrency_limit)}'));
            $ext->add($context, $exten, '', new ext_gotoif('$["${ARG1}"="LIMIT" & ${LEN(${AMPUSER})} & ${DB_EXISTS(AMPUSER/${AMPUSER}/concurrency_limit)} & ${DB(AMPUSER/${AMPUSER}/concurrency_limit)}>0 & ${GROUP_COUNT(${AMPUSER}@concurrency_limit)}>=${DB(AMPUSER/${AMPUSER}/concurrency_limit)}]', 'limit'));
            $ext->add($context, $exten, '', new ext_execif('$["${ARG1}"="LIMIT" & ${LEN(${AMPUSER})}]', 'Set', 'GROUP(concurrency_limit)=${AMPUSER}'));
            /*
             * This is where to splice in things like setting the language based on a user's astdb setting,
             * or where you might set the CID account code based on a user instead of the device settings.
             */
            $ext->add($context, $exten, 'report', new ext_gotoif('$[ "${ARG1}" = "SKIPTTL" | "${ARG1}" = "LIMIT" ]', 'continue'));
            $ext->add($context, $exten, 'report2', new ext_set('__TTL', '${IF($["foo${TTL}" = "foo"]?64:$[ ${TTL} - 1 ])}'));
            $ext->add($context, $exten, '', new ext_gotoif('$[ ${TTL} > 0 ]', 'continue'));
            $ext->add($context, $exten, '', new ext_wait('${RINGTIMER}'));
            // wait for a while, to give it a chance to be picked up by voicemail
            $ext->add($context, $exten, '', new ext_answer());
            $ext->add($context, $exten, '', new ext_wait('1'));
            $ext->add($context, $exten, '', new ext_gosub('1', 'lang-playback', $context, 'hook_0'));
            $ext->add($context, $exten, '', new ext_macro('hangupcall'));
            $ext->add($context, $exten, 'limit', new ext_answer());
            $ext->add($context, $exten, '', new ext_wait('1'));
            $ext->add($context, $exten, '', new ext_gosub('1', 'lang-playback', $context, 'hook_1'));
            $ext->add($context, $exten, '', new ext_macro('hangupcall'));
            $ext->add($context, $exten, '', new ext_congestion(20));
            // Address Security Vulnerability in many earlier versions of Asterisk from an external source tranmitting a
            // malicious CID that can cause overflows in the Asterisk code.
            //
            $ext->add($context, $exten, 'continue', new ext_set('CALLERID(number)', '${CALLERID(number):0:40}'));
            $ext->add($context, $exten, '', new ext_set('CALLERID(name)', '${CALLERID(name):0:40}'));
            $ext->add($context, $exten, '', new ext_set('CDR(cnum)', '${CALLERID(num)}'));
            $ext->add($context, $exten, '', new ext_set('CDR(cnam)', '${CALLERID(name)}'));
            // CHANNEL(language) does not get inherited (which seems like an Asterisk bug as musicclass does)
            // so if whe have MASTER_CHANNEL() available to us let's rectify that
            //
            if ($amp_conf['AST_FUNC_MASTER_CHANNEL']) {
                $ext->add($context, $exten, '', new ext_set('CHANNEL(language)', '${MASTER_CHANNEL(CHANNEL(language))}'));
            }
            $ext->add($context, $exten, '', new ext_noop_trace('Using CallerID ${CALLERID(all)}'));
            $ext->add($context, 'h', '', new ext_macro('hangupcall'));
            $lang = 'en';
            //English
            $ext->add($context, $lang, 'hook_0', new ext_playback('im-sorry&an-error-has-occurred&with&call-forwarding'));
            $ext->add($context, $lang, '', new ext_return());
            $ext->add($context, $lang, 'hook_1', new ext_playback('beep&im-sorry&your&simul-call-limit-reached&goodbye'));
            $ext->add($context, $lang, '', new ext_return());
            $lang = 'ja';
            //Japanese
            $ext->add($context, $lang, 'hook_0', new ext_playback('im-sorry&call-forwarding&jp-no&an-error-has-occured'));
            $ext->add($context, $lang, '', new ext_return());
            $ext->add($context, $lang, 'hook_1', new ext_playback('beep&im-sorry&simul-call-limit-reached'));
            $ext->add($context, $lang, '', new ext_return());
            /*
             * arg1 = trunk number, arg2 = number
             *
             * Re-written to use enumlookup.agi
             */
            // Is this the best place to put it in?
            // Check if we are using Google DNS for ENUM-lookups,
            // enable it as a global variable so we can use it in the agi
            if ($amp_conf['USEGOOGLEDNSFORENUM']) {
                $ext->addGlobal('ENUMUSEGOOGLEDNS', 'TRUE');
            }
            $context = 'macro-dialout-enum';
            if (!empty($trunk_type_needed[$context])) {
                $exten = 's';
                $ext->add($context, $exten, '', new ext_gosubif('$[$["${ARG3}" != ""] & $["${DB(AMPUSER/${AMPUSER}/pinless)}" != "NOPASSWD"]]', 'sub-pincheck,s,1'));
                $ext->add($context, $exten, '', new ext_gotoif('$["x${OUTDISABLE_${DIAL_TRUNK}}" = "xon"]', 'disabletrunk,1'));
                $ext->add($context, $exten, '', new ext_set('DIAL_TRUNK_OPTIONS', '${IF($["${DB_EXISTS(TRUNK/${DIAL_TRUNK}/dialopts)}" = "1"]?${DB_RESULT}:${TRUNK_OPTIONS})}'));
                $ext->add($context, $exten, '', new ext_set('OUTBOUND_GROUP', 'OUT_${ARG1}'));
                $ext->add($context, $exten, '', new ext_gotoif('$["${OUTMAXCHANS_${ARG1}}foo" = "foo"]', 'nomax'));
                $ext->add($context, $exten, '', new ext_gotoif('$[ ${GROUP_COUNT(OUT_${ARG1})} >= ${OUTMAXCHANS_${ARG1}} ]', 'nochans'));
                $ext->add($context, $exten, 'nomax', new ext_set('DIAL_NUMBER', '${ARG2}'));
                $ext->add($context, $exten, '', new ext_set('DIAL_TRUNK', '${ARG1}'));
                $ext->add($context, $exten, '', new ext_gotoif('$["${INTRACOMPANYROUTE}" = "YES"]', 'skipoutcid'));
                // Set to YES if treated like internal
                $ext->add($context, $exten, '', new ext_set('DIAL_TRUNK_OPTIONS', '${DIAL_OPTIONS}'));
                // will be reset to TRUNK_OPTIONS if not intra-company
                $ext->add($context, $exten, '', new ext_macro('outbound-callerid', '${DIAL_TRUNK}'));
                $ext->add($context, $exten, 'skipoutcid', new ext_gosubif('$["${PREFIX_TRUNK_${DIAL_TRUNK}}" != ""]', 'sub-flp-${DIAL_TRUNK},s,1'));
                // manimpulate DIAL_NUMBER
                //  Replacement for asterisk's ENUMLOOKUP function
                $ext->add($context, $exten, '', new ext_agi('enumlookup.agi'));
                if ($amp_conf['AST_FUNC_CONNECTEDLINE'] && $amp_conf['OUTBOUND_DIAL_UPDATE']) {
                    $ext->add($context, $exten, '', new ext_execif('$["${DB(AMPUSER/${AMPUSER}/cidname)}" != ""]', 'Set', 'CONNECTEDLINE(num,i)=${DIAL_NUMBER}'));
                }
                if ($amp_conf['AST_FUNC_CONNECTEDLINE'] && $amp_conf['OUTBOUND_CID_UPDATE']) {
                    $ext->add($context, $exten, '', new ext_execif('$["${DB(AMPUSER/${AMPUSER}/cidname)}" != ""]', 'Set', 'CONNECTEDLINE(name,i)=CID:${CALLERID(number)}'));
                }
                // Now we have the variable DIALARR set to a list of URI's that can be called, in order of priority
                // Loop through them trying them in order.
                $ext->add($context, $exten, 'dialloop', new ext_gotoif('$["foo${DIALARR}"="foo"]', 's-${DIALSTATUS},1'));
                $ext->add($context, $exten, '', new ext_execif('$["${MOHCLASS}"!="default" & "${MOHCLASS}"!="" & "${FORCE_CONFIRM}"="" ]', 'Set', 'DIAL_TRUNK_OPTIONS=M(setmusic^${MOHCLASS})${DIAL_TRUNK_OPTIONS}'));
                $ext->add($context, $exten, '', new ext_execif('$["${FORCE_CONFIRM}"!="" ]', 'Set', 'DIAL_TRUNK_OPTIONS=M(confirm)${DIAL_TRUNK_OPTIONS}'));
                $ext->add($context, $exten, '', new ext_set('TRYDIAL', '${CUT(DIALARR,%,1)}'));
                $ext->add($context, $exten, '', new ext_set('DIALARR', '${CUT(DIALARR,%,2-)}'));
                $ext->add($context, $exten, '', new ext_dial('${TRYDIAL}', '${TRUNK_RING_TIMER},${DIAL_TRUNK_OPTIONS}'));
                // Now, if we're still here, that means the Dial failed for some reason.
                // If it's CONGESTION or CHANUNAVAIL we want to try again on a different
                // different channel. If there's no more left, the dialloop tag will exit.
                $ext->add($context, $exten, '', new ext_gotoif('$[ $[ "${DIALSTATUS}" = "CHANUNAVAIL" ] | $[ "${DIALSTATUS}" = "CONGESTION" ] ]', 'dialloop'));
                $ext->add($context, $exten, '', new ext_gotoif('$["${ARG4}" = "on"]', 'continue,1', 's-${DIALSTATUS},1'));
                // Here are the exit points for the macro.
                $ext->add($context, $exten, 'nochans', new ext_noop('max channels used up'));
                $exten = 's-BUSY';
                /*
                 * HANGUPCAUSE 17 = Busy, or SIP 486 Busy everywhere
                 */
                $ext->add($context, $exten, '', new ext_noop('Dial failed due to trunk reporting BUSY - giving up'));
                $ext->add($context, $exten, '', new ext_playtones('busy'));
                $ext->add($context, $exten, '', new ext_busy(20));
                /*
                 * There are reported bugs in Asterisk Blind Trasfers that result in Dial() returning and continuing
                 * execution with a status of ANSWER. So we hangup at this point
                 */
                $exten = 's-ANSWER';
                $ext->add($context, $exten, '', new ext_noop('Call successfully answered - Hanging up now'));
                $ext->add($context, $exten, '', new ext_macro('hangupcall'));
                $exten = 's-NOANSWER';
                /*
                 * HANGUPCAUSE 18 = No User Responding, or SIP 408 Request Timeout
                 * HANGUPCAUSE 19 = No Answer From The User, or SIP 480 Temporarily unavailable, SIP 483 To many hops
                 */
                $ext->add($context, $exten, '', new ext_noop('Dial failed due to trunk reporting NOANSWER - giving up'));
                $ext->add($context, $exten, '', new ext_progress());
                switch ($trunkreportmsg_ids['no_answer_msg_id']) {
                    case DEFAULT_MSG:
                        $ext->add($context, $exten, '', new ext_playback('number-not-answering,noanswer'));
                        break;
                    case CONGESTION_TONE:
                        $ext->add($context, $exten, '', new ext_playtones('congestion'));
                        break;
                    default:
                        $message = recordings_get_file($trunkreportmsg_ids['no_answer_msg_id']);
                        $message = $message != "" ? $message : "number-not-answering";
                        $ext->add($context, $exten, '', new ext_playback("{$message}, noanswer"));
                }
                $ext->add($context, $exten, '', new ext_congestion(20));
                $exten = 's-INVALIDNMBR';
                /*
                 * HANGUPCAUSE 28 = Address Incomplete, or SIP 484 Address Incomplete
                 */
                $ext->add($context, $exten, '', new ext_noop('Dial failed due to trunk reporting Address Incomplete - giving up'));
                $ext->add($context, $exten, '', new ext_progress());
                switch ($trunkreportmsg_ids['invalidnmbr_msg_id']) {
                    case DEFAULT_MSG:
                        $ext->add($context, $exten, '', new ext_playback('ss-noservice,noanswer'));
                        break;
                    case CONGESTION_TONE:
                        $ext->add($context, $exten, '', new ext_playtones('congestion'));
                        break;
                    default:
                        $message = recordings_get_file($trunkreportmsg_ids['invalidnmbr_msg_id']);
                        $message = $message != "" ? $message : "ss-noservice";
                        $ext->add($context, $exten, '', new ext_playback("{$message}, noanswer"));
                }
                $ext->add($context, $exten, '', new ext_busy(20));
                $exten = "s-CHANGED";
                $ext->add($context, $exten, '', new ext_noop('Dial failed due to trunk reporting Number Changed - giving up'));
                $ext->add($context, $exten, '', new ext_playtones('busy'));
                $ext->add($context, $exten, '', new ext_busy(20));
                $exten = '_s-.';
                $ext->add($context, $exten, '', new ext_set('RC', '${IF($[${ISNULL(${HANGUPCAUSE})}]?0:${HANGUPCAUSE})}'));
                $ext->add($context, $exten, '', new ext_goto('1', '${RC}'));
                $ext->add($context, '17', '', new ext_goto('1', 's-BUSY'));
                $ext->add($context, '18', '', new ext_goto('1', 's-NOANSWER'));
                $ext->add($context, '22', '', new ext_goto('1', 's-CHANGED'));
                $ext->add($context, '23', '', new ext_goto('1', 's-CHANGED'));
                $ext->add($context, '28', '', new ext_goto('1', 's-INVALIDNMBR'));
                $ext->add($context, '_X', '', new ext_goto('1', 'continue'));
                $ext->add($context, '_X.', '', new ext_goto('1', 'continue'));
                $exten = 'continue';
                if ($generate_trunk_monitor_failure) {
                    $ext->add($context, $exten, '', new ext_gotoif('$["${OUTFAIL_${ARG1}}" = ""]', 'noreport'));
                    $ext->add($context, $exten, '', new ext_agi('${OUTFAIL_${ARG1}}'));
                }
                $ext->add($context, $exten, 'noreport', new ext_noop('TRUNK Dial failed due to ${DIALSTATUS} HANGUPCAUSE: ${HANGUPCAUSE} - failing through to other trunks'));
                $ext->add($context, $exten, '', new ext_execif('$["${AMPUSER}"!="" ]', 'Set', 'CALLERID(number)=${AMPUSER}'));
                $ext->add($context, 'disabletrunk', '', new ext_noop('TRUNK: ${OUT_${DIAL_TRUNK}} DISABLED - falling through to next trunk'));
                $ext->add($context, 'bypass', '', new ext_noop('TRUNK: ${OUT_${DIAL_TRUNK}} BYPASSING because dialout-trunk-predial-hook'));
                $ext->add($context, 'h', '', new ext_macro('hangupcall'));
            }
            // if trunk_type_needed
            /*
             * overrides CallerID out trunks
             * arg1 is trunk
             * macro-user-callerid should be called _before_ using this macro
             */
            $context = 'macro-outbound-callerid';
            $exten = 's';
            // If we modified the caller presence, set it back. This allows anonymous calls to be internally prepended but keep
            // their status if forwarded back out. Not doing this can result in the trunk CID being displayed vs. 'blocked call'
            //
            $ext->add($context, $exten, '', new ext_execif('$["${CALLINGNAMEPRES_SV}" != ""]', 'Set', 'CALLERPRES(name-pres)=${CALLINGNAMEPRES_SV}'));
            $ext->add($context, $exten, '', new ext_execif('$["${CALLINGNUMPRES_SV}" != ""]', 'Set', 'CALLERPRES(num-pres)=${CALLINGNUMPRES_SV}'));
            // Keep the original CallerID number, for failover to the next trunk.
            $ext->add($context, $exten, '', new ext_execif('$["${REALCALLERIDNUM:1:2}" = ""]', 'Set', 'REALCALLERIDNUM=${CALLERID(number)}'));
            // If this came through a ringgroup or CF, then we want to retain original CID unless
            // OUTKEEPCID_${trunknum} is set.
            // Save then CIDNAME while it is still intact in case we end up sending out this same CID
            $ext->add($context, $exten, 'start', new ext_gotoif('$[ $["${REALCALLERIDNUM}" = ""] | $["${KEEPCID}" != "TRUE"] | $["${OUTKEEPCID_${ARG1}}" = "on"] ]', 'normcid'));
            // Set to TRUE if coming from ringgroups, CF, etc.
            $ext->add($context, $exten, '', new ext_set('USEROUTCID', '${REALCALLERIDNUM}'));
            //$ext->add($context, $exten, '', new ext_set('REALCALLERIDNAME', '${CALLERID(name)}'));
            // We now have to make sure the CID is valid. If we find an AMPUSER with the same CID, we assume it is an internal
            // call (would be quite a conincidence if not) and go through the normal processing to get that CID. If a device
            // is set for this CID, then it must be internal
            // If we end up using USEROUTCID at the end, it may still be the REALCALLERIDNUM we saved above. That is determined
            // if the two are equal, AND there is no CALLERID(name) present since it has been removed by the CALLERID(all)=${USEROUTCID}
            // setting. If this is the case, then we put the orignal name back in to send out. Although the CNAME is not honored by most
            // carriers, there are cases where it is so this preserves that information to be used by those carriers who do honor it.
            $ext->add($context, $exten, '', new ext_gotoif('$["foo${DB(AMPUSER/${REALCALLERIDNUM}/device)}" = "foo"]', 'bypass'));
            $ext->add($context, $exten, 'normcid', new ext_set('USEROUTCID', '${DB(AMPUSER/${AMPUSER}/outboundcid)}'));
            $ext->add($context, $exten, 'bypass', new ext_set('EMERGENCYCID', '${DB(DEVICE/${REALCALLERIDNUM}/emergency_cid)}'));
            $ext->add($context, $exten, '', new ext_set('TRUNKOUTCID', '${OUTCID_${ARG1}}'));
            $ext->add($context, $exten, '', new ext_gotoif('$["${EMERGENCYROUTE:1:2}" = "" | "${EMERGENCYCID:1:2}" = ""]', 'trunkcid'));
            // check EMERGENCY ROUTE
            $ext->add($context, $exten, '', new ext_set('CALLERID(all)', '${EMERGENCYCID}'));
            // emergency cid for device
            $ext->add($context, $exten, '', new ext_set('CDR(outbound_cnum)', '${CALLERID(num)}'));
            $ext->add($context, $exten, '', new ext_set('CDR(outbound_cnam)', '${CALLERID(name)}'));
            $ext->add($context, $exten, 'exit', new ext_macroexit());
            $ext->add($context, $exten, 'trunkcid', new ext_execif('$[${LEN(${TRUNKOUTCID})} != 0]', 'Set', 'CALLERID(all)=${TRUNKOUTCID}'));
            $ext->add($context, $exten, 'usercid', new ext_execif('$[${LEN(${USEROUTCID})} != 0]', 'Set', 'CALLERID(all)=${USEROUTCID}'));
            // check CID override for extension
            /* TRUNKCIDOVERRIDE is used by followme and can be used by other functions. It forces the specified CID except for the case of
             * an Emergency CID on an Emergency Route
             */
            $ext->add($context, $exten, '', new ext_execif('$[${LEN(${TRUNKCIDOVERRIDE})} != 0 | ${LEN(${FORCEDOUTCID_${ARG1}})} != 0]', 'Set', 'CALLERID(all)=${IF($[${LEN(${FORCEDOUTCID_${ARG1}})}=0]?${TRUNKCIDOVERRIDE}:${FORCEDOUTCID_${ARG1}})}'));
            $ext->add($context, $exten, 'hidecid', new ext_execif('$["${CALLERID(name)}"="hidden"]', 'Set', 'CALLERPRES(name-pres)=prohib_passed_screen'));
            //We are checking to see if the CallerID name is <hidden> (from freepbx) so we hide both the name and the number. I believe this is correct.
            $ext->add($context, $exten, '', new ext_execif('$["${CALLERID(name)}"="hidden"]', 'Set', 'CALLERPRES(num-pres)=prohib_passed_screen'));
            // $has_keepcid_cnum is checked and set when the globals are being generated above
            //
            if ($has_keepcid_cnum || $amp_conf['BLOCK_OUTBOUND_TRUNK_CNAM']) {
                if ($amp_conf['BLOCK_OUTBOUND_TRUNK_CNAM']) {
                    $ext->add($context, $exten, '', new ext_set('CALLERID(name)', ''));
                } else {
                    $ext->add($context, $exten, '', new ext_execif('$["${OUTKEEPCID_${ARG1}}" = "cnum"]', 'Set', 'CALLERID(name)='));
                }
            }
            $ext->add($context, $exten, '', new ext_set('CDR(outbound_cnum)', '${CALLERID(num)}'));
            $ext->add($context, $exten, '', new ext_set('CDR(outbound_cnam)', '${CALLERID(name)}'));
            // Combined from-zpatel / from-dahdi and all macros now from-dahdi-channum
            //
            $ext->addInclude('from-zaptel', 'from-dahdi');
            $ext->add('from-zaptel', 'foo', '', new ext_noop('bar'));
            $context = 'from-dahdi';
            $exten = '_X.';
            $ext->add($context, $exten, '', new ext_set('DID', '${EXTEN}'));
            $ext->add($context, $exten, '', new ext_goto(1, 's'));
            $exten = 's';
            $ext->add($context, $exten, '', new ext_noop('Entering from-dahdi with DID == ${DID}'));
            // Some trunks _require_ a RINGING be sent before an Answer.
            $ext->add($context, $exten, '', new ext_ringing());
            // If ($did == "") { $did = "s"; }
            $ext->add($context, $exten, '', new ext_set('DID', '${IF($["${DID}"= ""]?s:${DID})}'));
            $ext->add($context, $exten, '', new ext_noop('DID is now ${DID}'));
            $ext->add($context, $exten, '', new ext_gotoif('$["${CHANNEL:0:5}"="DAHDI"]', 'dahdiok', 'checkzap'));
            $ext->add($context, $exten, 'checkzap', new ext_gotoif('$["${CHANNEL:0:3}"="Zap"]', 'zapok', 'neither'));
            $ext->add($context, $exten, 'neither', new ext_goto('1', '${DID}', 'from-pstn'));
            // If there's no ext-did,s,1, that means there's not a no did/no cid route. Hangup.
            $ext->add($context, $exten, '', new ext_macro('Hangupcall', 'dummy'));
            $ext->add($context, $exten, 'dahdiok', new ext_noop('Is a DAHDi Channel'));
            $ext->add($context, $exten, '', new ext_set('CHAN', '${CHANNEL:6}'));
            $ext->add($context, $exten, '', new ext_set('CHAN', '${CUT(CHAN,-,1)}'));
            $ext->add($context, $exten, '', new ext_macro('from-dahdi-${CHAN}', '${DID},1'));
            // If nothing there, then treat it as a DID
            $ext->add($context, $exten, '', new ext_noop('Returned from Macro from-dahdi-${CHAN}'));
            $ext->add($context, $exten, '', new ext_goto(1, '${DID}', 'from-pstn'));
            $ext->add($context, $exten, 'zapok', new ext_noop('Is a Zaptel Channel'));
            $ext->add($context, $exten, '', new ext_set('CHAN', '${CHANNEL:4}'));
            $ext->add($context, $exten, '', new ext_set('CHAN', '${CUT(CHAN,-,1)}'));
            $ext->add($context, $exten, '', new ext_macro('from-dahdi-${CHAN}', '${DID},1'));
            $ext->add($context, $exten, '', new ext_noop('Returned from Macro from-dahdi-${CHAN}'));
            $ext->add($context, $exten, '', new ext_goto(1, '${DID}', 'from-pstn'));
            /*
            ;------------------------------------------------------------------------
            ; [macro-dial-confirm]
            ;------------------------------------------------------------------------
            ; This has now been incorporated into dialparties. It still only works with ringall
            ; and ringall-prim strategies. Have not investigated why it doesn't work with
            ; hunt and memory hunt.
            ;
            ;------------------------------------------------------------------------
            [macro-dial-confirm]
            ; This was written to make it easy to use macro-dial-confirm instead of macro-dial in generated dialplans.
            ; This takes the same parameters, with an additional parameter of the ring group Number
            ; ARG1 is the timeout
            ; ARG2 is the DIAL_OPTIONS
            ; ARG3 is a list of xtns to call - 203-222-240-123123123#-211
            ; ARG4 is the ring group number
            */
            $mcontext = 'macro-dial-confirm';
            $exten = 's';
            // set to ringing so confirm macro can keep from passing the channel during confirmation if
            // someone beat them to it.
            //
            $ext->add($mcontext, $exten, '', new ext_set('DB(RG/${ARG4}/${CHANNEL})', 'RINGING'));
            $ext->add($mcontext, $exten, '', new ext_set('__UNIQCHAN', '${CHANNEL}'));
            // Tell dialparites to place the call through the [grps] context
            //
            $ext->add($mcontext, $exten, '', new ext_set('USE_CONFIRMATION', 'TRUE'));
            $ext->add($mcontext, $exten, '', new ext_set('RINGGROUP_INDEX', '${ARG4}'));
            $ext->add($mcontext, $exten, '', new ext_set('FORCE_CONFIRM', ''));
            $ext->add($mcontext, $exten, '', new ext_set('ARG4', ''));
            $ext->add($mcontext, $exten, '', new ext_macro('dial', '${ARG1},${ARG2},${ARG3}'));
            $ext->add($mcontext, $exten, '', new ext_dbdel('RG/${RINGGROUP_INDEX}/${CHANNEL}'));
            $ext->add($mcontext, $exten, '', new ext_set('USE_CONFIRMATION', ''));
            $ext->add($mcontext, $exten, '', new ext_set('RINGGROUP_INDEX', ''));
            /*
            ;------------------------------------------------------------------------
            ; [macro-setmusic]
            ;------------------------------------------------------------------------
            ; CONTEXT:      macro-setmusic
            ; PURPOSE:      to turn off moh on routes where it is not desired
            ;
            ;------------------------------------------------------------------------
            [macro-setmusic]
            exten => s,1,NoOp(Setting Outbound Route MoH To: ${ARG1})
            exten => s,2,Set(CHANNEL(musicclass)=${ARG1}) ; this won't work in 1.2 anymore, could fix in auto-generate if we wanted...
            ;------------------------------------------------------------------------
            */
            $mcontext = 'macro-setmusic';
            $exten = 's';
            $ext->add($mcontext, $exten, '', new ext_noop_trace('Setting Outbound Route MoH To: ${ARG1}'));
            $ext->add($mcontext, $exten, '', new ext_setmusiconhold('${ARG1}'));
            /*
            ;------------------------------------------------------------------------
            ; [block-cf]
            ;------------------------------------------------------------------------
            ; This context is set as a target with FORWARD_CONTEXT when Call Forwarding is set to be
            ; ignored in a ringgroup or other features that may take advantage of this. Server side
            ; CF is done in dialparties.agi but if a client device forwards a call, it will be caught
            ; and blocked here.
            ;------------------------------------------------------------------------
            [block-cf]
            exten => _X.,1,Noop(Blocking callforward to ${EXTEN} because CF is blocked)
            exten => _X.,n,Hangup()
            
            ;------------------------------------------------------------------------
            */
            $context = 'macro-block-cf';
            $exten = '_X.';
            $ext->add($context, $exten, '', new ext_noop_trace('Blocking callforward to ${EXTEN} because CF is blocked'));
            $ext->add($context, $exten, '', new ext_hangup(''));
            /*
             * macro-vm
             */
            /*
            	;------------------------------------------------------------------------
            	; [macro-vm]
            	;------------------------------------------------------------------------
            	; CONTEXT:      macro-vm
            	; PURPOSE:      call voicemail system and extend with personal ivr
            	;
            	; Under normal use, this macro will call the voicemail system with the extension and
            	; desired greeting mode of busy, unavailable or as specified with direct voicemail
            	; calls (usually unavailable) when entered from destinations.
            	;
            	; The voicemail system's two greetings have been 'hijacked' as follows to extend the
            	; system by giving the option of a private 'ivr' for each voicemail user. The following
            	; applies to both the busy and unavailable modes of voicemail and can be applied to one
            	; or both, and differently.
            	;
            	; Global Defaults:
            	;
            	; The following are default values, used in both busy and unavail modes if no specific
            	; values are specified.
            	;
            	; VMX_REPEAT
            	;                                       The number of times to repeat the users message if no option is pressed.
            	; VMX_TIMEOUT
            	;                                       The timeout to wait after playing message before repeating or giving up.
            	; VMX_LOOPS
            	;                                       The number of times it should replay the message and check for an option when
            	;                                       an invalid option is pressed.
            	;
            	; VMX_OPTS_DOVM
            	;                                       Default voicemail option to use if vm is chosen as an option. No options will
            	;                                       cause Allison's generic message, 's' will go straight to beep.
            	; VMX_OPTS_TIMEOUT
            	;                                       Default voicemail option to use if it times out with no options. No options will
            	;                                       cause Allison's generic message, 's' will go straight to beep.
            	;                                       IF THE USER PRESSES # - it will look like a timeout as well since no option will
            	;                                       be presented. If the user wishes to enable a mode where a caller can press #
            	;                                       during their message and it goes straight to voicemail with only a 'beep' then
            	;                                       this should be set to 's'.
            	; VMX_OPTS_LOOP
            	;                                       Default voicemail option to use if to many wrong options occur. No options will
            	;                                       cause Allison's generic message, 's' will go straight to beep.
            	;
            	; VMX_CONTEXT
            	;                                       Default context for user destinations if not supplied in the user's settings
            	; VMX_PRI
            	;                                       Default priority for user destinations if not supplied in the user's settings
            	;
            	; VMX_TIMEDEST_CONTEXT
            	;                                       Default context for timeout destination if not supplied in the user's settings
            	; VMX_TIMEDEST_EXT
            	;                                       Default extension for timeout destination if not supplied in the user's settings
            	; VMX_TIMEDEST_PRI
            	;                                       Default priority for timeout destination if not supplied in the user's settings
            	;
            	; VMX_LOOPDEST_CONTEXT
            	;                                       Default context for loops  destination if not supplied in the user's settings
            	; VMX_LOOPDEST_EXT
            	;                                       Default extension for loops  destination if not supplied in the user's settings
            	; VMX_LOOPDEST_PRI
            	;                                       Default priority for loops  destination if not supplied in the user's settings
            	;
            	;
            	; The AMPUSER database variable has been extended with a 'vmx' tree (vm-extension). A
            	; duplicate set is included for both unavail and busy. You could choose for to have an
            	; ivr when unavail is taken, but not with busy - or a different once with busy.
            	; The full list is below, each specific entry is futher described:
            	;
            	; state:                Whether teh current mode is enabled or disabled. Anything but 'enabled' is
            	;                                               treated as disabled.
            	; repeat:               This is the number of times that the users message should be played after the
            	;                                               timeout if the user has not entered anything. It is just a variable to the
            	;                                               Read() function which will do the repeating.
            	; timeout:      This is how long to wait after the message has been read for a response from
            	;                                               the user. A caller can enter a digit any time during the playback.
            	; loops:                This is the number of loops that the system will allow a caller to retry if
            	;                                               they enter a bad menu choice, before going to the loop failover destination
            	; vmxopts:      This is the vm options to send to the voicemail command used when a specific
            	;                                               voicemail destination is chosen (inidcated by 'dovm' in the ext field). This is
            	;                                               typically either set to 's' or left blank. When set to 's' there will be no
            	;                                               message played when entering the voicemail, just a beep. When blank, you will
            	;                                               have Allison's generic message played. It is not typical to play the greetings
            	;                                               since they have been 'hijacked' for these IVR's and from a caller's perspecitive
            	;                                               this system appears interconnected with the voicemail so instructions can be
            	;                                               left there.
            	; timedest: The three variables: ext, context and pri are the goto destination if the caller
            	;                                               enters no options and it timesout. None have to be set and a system default
            	;                                               will be used. If just ext is set, then defaults will be used for context and
            	;                                               pri, etc.
            	; loopdest:     This is identical to timedest but used if the caller exceeds the maximum invalid
            	;                                               menu choices.
            	; [0-9*]:               The user can specify up to 11 ivr options, all as single digits from 0-9 or *. The
            	;                                               # key can not be used since it is used as a terminator key for the Read command
            	;                                               and will never be returned. A minimum of the ext must be specified for each valid
            	;                                               option and as above, the context and priority can also be specified if the default
            	;                                               is not to be used.
            	;                                               Option '0' takes on a special meaning. Since a user is able to break out of the
            	;                                               voicemail command once entering it with a 0, if specified, the 0 destination will
            	;                                               be used.
            	;                                               Option '*' can also be used to breakout. It is undecided at this point whether
            	;                                               providing that option will be used as well. (probably should).
            	;
            	;
            	; /AMPUSER/<ext>/vmx/[busy|unavail]/state:                                                              enabled|disabled
            	; /AMPUSER/<ext>/vmx/[busy|unavail]/repeat:                                                             n (times to repeat message)
            	; /AMPUSER/<ext>/vmx/[busy|unavail]/timeout:                                                    n (timeout to wait for digit)
            	; /AMPUSER/<ext>/vmx/[busy|unavail]/loops:                                                              n (loop returies for invalid entries)
            	; /AMPUSER/<ext>/vmx/[busy|unavail]/vmxopts/dovm:                                       vmoptions (if ext is dovm)
            	; /AMPUSER/<ext>/vmx/[busy|unavail]/vmxopts/timeout:                    vmoptions (if timeout)
            	; /AMPUSER/<ext>/vmx/[busy|unavail]/vmxopts/loops:                              vmoptions (if loops)
            	; /AMPUSER/<ext>/vmx/[busy|unavail]/timedest/ext:                                       extension (if timeout)
            	; /AMPUSER/<ext>/vmx/[busy|unavail]/timedest/context:                   context (if timeout)
            	; /AMPUSER/<ext>/vmx/[busy|unavail]/timedest/pri:                                       priority (if timeout)
            	; /AMPUSER/<ext>/vmx/[busy|unavail]/loopdest/ext:                                       extension (if too many failures)
            	; /AMPUSER/<ext>/vmx/[busy|unavail]/loopdest/context:                   context (if too many failures)
            	; /AMPUSER/<ext>/vmx/[busy|unavail]/loopdest/pri:                                       priority (if too many failures)
            	; /AMPUSER/<ext>/vmx/[busy|unavail]/[0-9*]/ext:                                         extension (dovm for vm access)
            	; /AMPUSER/<ext>/vmx/[busy|unavail]/[0-9*]/context:                             context
            	; /AMPUSER/<ext>/vmx/[busy|unavail]/[0-9*]/pri:                                         priority
            	;------------------------------------------------------------------------
            */
            // ARG1 - extension
            // ARG2 - DIRECTDIAL/BUSY
            // ARG3 - RETURN makes macro return, otherwise hangup
            //
            $ext->add('macro-vm', 's', '', new ext_macro('user-callerid', 'SKIPTTL'));
            $ext->add('macro-vm', 's', '', new ext_setvar("VMGAIN", '${IF($["foo${VM_GAIN}"!="foo"]?"g(${VM_GAIN})": )}'));
            // If blkvm-check is set TRUE, then someone told us to block calls from going to
            // voicemail. This variable is reset by the answering channel so subsequent
            // transfers will properly function.
            //
            $ext->add('macro-vm', 's', '', new ext_macro('blkvm-check'));
            $ext->add('macro-vm', 's', '', new ext_gotoif('$["${GOSUB_RETVAL}" != "TRUE"]', 'vmx,1'));
            // we didn't branch so block this from voicemail
            //
            $ext->add('macro-vm', 's', '', new ext_noop_trace('CAME FROM: ${NODEST} - Blocking VM macro-blkvm-check returned TRUE'));
            $ext->add('macro-vm', 's', '', new ext_hangup(''));
            // If vmx not enabled for the current mode,then jump to normal voicemail behavior
            // also - if not message (no-msg) is requested, straight to voicemail
            //
            $ext->add('macro-vm', 'vmx', '', new ext_setvar("MEXTEN", '${ARG1}'));
            $ext->add('macro-vm', 'vmx', '', new ext_setvar("MMODE", '${ARG2}'));
            $ext->add('macro-vm', 'vmx', '', new ext_setvar("RETVM", '${ARG3}'));
            $ext->add('macro-vm', 'vmx', '', new ext_setvar("MODE", '${IF($["${MMODE}"="BUSY"]?busy:unavail)}'));
            $ext->add('macro-vm', 'vmx', '', new ext_macro('get-vmcontext', '${MEXTEN}'));
            $ext->add('macro-vm', 'vmx', '', new ext_setvar("MODE", '${IF($[(${STAT(f,${ASTSPOOLDIR}/voicemail/${VMCONTEXT}/${MEXTEN}/temp.wav)} = 1) || (${STAT(f,${ASTSPOOLDIR}/voicemail/${VMCONTEXT}/${MEXTEN}/temp.WAV)} = 1)]?temp:${MODE})}'));
            $ext->add('macro-vm', 'vmx', '', new ext_noop('MODE IS: ${MODE}'));
            // If this use has individual option set for playing standardized message, then override the global option
            // but only if the vmx state is 'enabled'
            //
            $ext->add('macro-vm', 'vmx', '', new ext_gotoif('$["${DB(AMPUSER/${MEXTEN}/vmx/${MODE}/state)}" != "enabled"]', 'chknomsg'));
            /* Replaced
            	$ext->add('macro-vm','vmx', '', new ext_gotoif('$["${DB_EXISTS(AMPUSER/${MEXTEN}/vmx/${MODE}/vmxopts/timeout)}" = "0"]','chknomsg'));
            	$ext->add('macro-vm','vmx', '', new ext_setvar("VM_OPTS", '${DB_RESULT}'));
            	*/
            $ext->add('macro-vm', 'vmx', '', new ext_set('VM_OPTS', '${IF($["${DB_EXISTS(AMPUSER/${MEXTEN}/vmx/${MODE}/vmxopts/timeout)}" = "1"]?${DB_RESULT}:${VM_OPTS})}'));
            $ext->add('macro-vm', 'vmx', 'chknomsg', new ext_gotoif('$["${MMODE}"="NOMESSAGE"]', 's-${MMODE},1'));
            $ext->add('macro-vm', 'vmx', '', new ext_gotoif('$["${MMODE}" != "DIRECTDIAL"]', 'notdirect'));
            $ext->add('macro-vm', 'vmx', '', new ext_setvar("MODE", '${IF($["${REGEX("[b]" ${VM_DDTYPE})}" = "1"]?busy:${MODE})}'));
            $ext->add('macro-vm', 'vmx', 'notdirect', new ext_NoOp('Checking if ext ${MEXTEN} is enabled: ${DB(AMPUSER/${MEXTEN}/vmx/${MODE}/state)}'));
            $ext->add('macro-vm', 'vmx', '', new ext_gotoif('$["${DB(AMPUSER/${MEXTEN}/vmx/${MODE}/state)}" != "enabled"]', 's-${MMODE},1'));
            // If the required voicemail file does not exist, then abort and go to normal voicemail behavior
            //
            // If 1.4 or above, use the STAT function to check for the file. Prior to 1.4, use the AGI script since the System() command tried
            // in the past had errors.
            //
            //$ext->add('macro-vm', 'vmx', '', new ext_trysystem('/bin/ls ${ASTSPOOLDIR}/voicemail/${VMCONTEXT}/${MEXTEN}/${MODE}.[wW][aA][vV]'));
            if ($ast_ge_14) {
                $ext->add('macro-vm', 'vmx', '', new ext_gotoif('$[(${STAT(f,${ASTSPOOLDIR}/voicemail/${VMCONTEXT}/${MEXTEN}/temp.wav)} = 1) || (${STAT(f,${ASTSPOOLDIR}/voicemail/${VMCONTEXT}/${MEXTEN}/temp.WAV)} = 1)]', 'tmpgreet'));
                $ext->add('macro-vm', 'vmx', '', new ext_gotoif('$[(${STAT(f,${ASTSPOOLDIR}/voicemail/${VMCONTEXT}/${MEXTEN}/${MODE}.wav)} = 0) && (${STAT(f,${ASTSPOOLDIR}/voicemail/${VMCONTEXT}/${MEXTEN}/${MODE}.WAV)} = 0)]', 'nofile'));
            } else {
                $ext->add('macro-vm', 'vmx', '', new ext_agi('checksound.agi,${ASTSPOOLDIR}/voicemail/${VMCONTEXT}/${MEXTEN}/temp'));
                $ext->add('macro-vm', 'vmx', '', new ext_gotoif('$["${SYSTEMSTATUS}" = "SUCCESS"]', 'tmpgreet'));
                $ext->add('macro-vm', 'vmx', '', new ext_agi('checksound.agi,${ASTSPOOLDIR}/voicemail/${VMCONTEXT}/${MEXTEN}/${MODE}'));
                $ext->add('macro-vm', 'vmx', '', new ext_gotoif('$["${SYSTEMSTATUS}" != "SUCCESS"]', 'nofile'));
            }
            $repeat = sql("SELECT `value` FROM `voicemail_admin` WHERE `variable` = 'VMX_REPEAT'", "getOne");
            $to = sql("SELECT `value` FROM `voicemail_admin` WHERE `variable` = 'VMX_TIMEOUT'", "getOne");
            $loops = sql("SELECT `value` FROM `voicemail_admin` WHERE `variable` = 'VMX_LOOPS'", "getOne");
            $ext->add('macro-vm', 'vmx', '', new ext_set("VMX_TIMEOUT", isset($to) ? $to : 2));
            $ext->add('macro-vm', 'vmx', '', new ext_set("VMX_REPEAT", isset($repeat) ? $repeat : 1));
            $ext->add('macro-vm', 'vmx', '', new ext_set("VMX_LOOPS", isset($loops) ? $loops : 1));
            $ext->add('macro-vm', 'vmx', '', new ext_setvar("LOOPCOUNT", '0'));
            /* Replaced
            	$ext->add('macro-vm','vmx', '', new ext_gotoif('$["${DB_EXISTS(AMPUSER/${MEXTEN}/vmx/${MODE}/repeat)}" = "0"]','vmxtime'));
            	$ext->add('macro-vm','vmx', '', new ext_setvar("VMX_REPEAT", '${DB_RESULT}'));
            	*/
            $ext->add('macro-vm', 'vmx', '', new ext_set('VMX_REPEAT', '${IF($["${DB_EXISTS(AMPUSER/${MEXTEN}/vmx/${MODE}/repeat)}" = "1"]?${DB_RESULT}:${VMX_REPEAT})}'));
            /* Replaced
            	$ext->add('macro-vm','vmx', 'vmxtime', new ext_gotoif('$["${DB_EXISTS(AMPUSER/${MEXTEN}/vmx/${MODE}/timeout)}" = "0"]','vmxloops'));
            	$ext->add('macro-vm','vmx', '', new ext_setvar("VMX_TIMEOUT", '${DB_RESULT}'));
            	*/
            $ext->add('macro-vm', 'vmx', 'vmxtime', new ext_set('VMX_TIMEOUT', '${IF($["${DB_EXISTS(AMPUSER/${MEXTEN}/vmx/${MODE}/timeout)}" = "1"]?${DB_RESULT}:${VMX_TIMEOUT})}'));
            /* Replaced
            	$ext->add('macro-vm','vmx', 'vmxloops', new ext_gotoif('$["${DB_EXISTS(AMPUSER/${MEXTEN}/vmx/${MODE}/loops)}" = "0"]','vmxanswer'));
            	$ext->add('macro-vm','vmx', '', new ext_setvar("VMX_LOOPS", '${DB_RESULT}'));
            	*/
            $ext->add('macro-vm', 'vmx', 'vmxloops', new ext_set('VMX_LOOPS', '${IF($["${DB_EXISTS(AMPUSER/${MEXTEN}/vmx/${MODE}/loops)}" = "1"]?${DB_RESULT}:${VMX_LOOPS})}'));
            $ext->add('macro-vm', 'vmx', 'vmxanswer', new ext_answer(''));
            // Now play the users voicemail recording as the basis for their ivr, the Read command will repeat as needed and if it timesout
            // then we go to the timeout. Otherwise handle invalid options by looping until the limit until a valid option is played.
            //
            $ext->add('macro-vm', 'vmx', 'loopstart', new ext_read('ACTION', '${ASTSPOOLDIR}/voicemail/${VMCONTEXT}/${MEXTEN}/${MODE}', 1, 'skip', '${VMX_REPEAT}', '${VMX_TIMEOUT}'));
            $ext->add('macro-vm', 'vmx', '', new ext_gotoif('$["${EXISTS(${ACTION})}" = "1"]', 'checkopt'));
            // If we are here we timed out, go to the required destination
            //
            $ext->add('macro-vm', 'vmx', 'noopt', new ext_NoOp('Timeout: going to timeout dest'));
            // this is always set, if not it will default to no options
            $ext->add('macro-vm', 'vmx', '', new ext_set('VMX_OPTS', '${DB(AMPUSER/${MEXTEN}/vmx/${MODE}/vmxopts/timeout)}'));
            // TODO should we just go do the other sets and skip the complexity, will have to if we remove the globals since they will be gonein dotime
            $ext->add('macro-vm', 'vmx', 'chktime', new ext_gotoif('$["${DB_EXISTS(AMPUSER/${MEXTEN}/vmx/${MODE}/timedest/ext)}" = "0"]', 'dotime'));
            $ext->add('macro-vm', 'vmx', '', new ext_setvar("VMX_TIMEDEST_EXT", '${DB_RESULT}'));
            /* this is the alternative if re the above TODO
            	$ext->add('macro-vm','vmx', 'chktime', new ext_set('VMX_TIMEDEST_EXT', '${IF($["${DB_EXISTS(AMPUSER/${MEXTEN}/vmx/${MODE}/timedest/ext)}" = "1"]?${DB_RESULT}:${VMX_TIMEDEST_EXT})}'));
            	*/
            /* Replaced
            	$ext->add('macro-vm','vmx', '', new ext_gotoif('$["${DB_EXISTS(AMPUSER/${MEXTEN}/vmx/${MODE}/timedest/context)}" = "0"]','timepri'));
            	$ext->add('macro-vm','vmx', '', new ext_setvar("VMX_TIMEDEST_CONTEXT",'${DB_RESULT}'));
            	*/
            $ext->add('macro-vm', 'vmx', '', new ext_set('VMX_TIMEDEST_CONTEXT', '${IF($["${DB_EXISTS(AMPUSER/${MEXTEN}/vmx/${MODE}/timedest/context)}" = "1"]?${DB_RESULT}:${VMX_TIMEDEST_CONTEXT})}'));
            /* Replaced
            	$ext->add('macro-vm','vmx', 'timepri', new ext_gotoif('$["${DB_EXISTS(AMPUSER/${MEXTEN}/vmx/${MODE}/timedest/pri)}" = "0"]','dotime'));
            	$ext->add('macro-vm','vmx', '', new ext_setvar("VMX_TIMEDEST_PRI",'${DB_RESULT}'));
            	*/
            $ext->add('macro-vm', 'vmx', 'timepri', new ext_set('VMX_TIMEDEST_PRI', '${IF($["${DB_EXISTS(AMPUSER/${MEXTEN}/vmx/${MODE}/timedest/pri)}" = "1"]?${DB_RESULT}:${VMX_TIMEDEST_PRI})}'));
            $ext->add('macro-vm', 'vmx', 'dotime', new ext_goto('${VMX_TIMEDEST_PRI}', '${VMX_TIMEDEST_EXT}', '${VMX_TIMEDEST_CONTEXT}'));
            // We got an option, check if the option is defined, or one of the system defaults
            //
            $ext->add('macro-vm', 'vmx', 'checkopt', new ext_gotoif('$["${DB_EXISTS(AMPUSER/${MEXTEN}/vmx/${MODE}/${ACTION}/ext)}" = "1"]', 'doopt'));
            $ext->add('macro-vm', 'vmx', '', new ext_gotoif('$["${ACTION}" = "0"]', 'o,1'));
            $ext->add('macro-vm', 'vmx', '', new ext_gotoif('$["${ACTION}" = "*"]', 'adef,1'));
            // Got invalid option loop until the max
            //
            $ext->add('macro-vm', 'vmx', '', new ext_setvar("LOOPCOUNT", '$[${LOOPCOUNT} + 1]'));
            $ext->add('macro-vm', 'vmx', '', new ext_gotoif('$["${LOOPCOUNT}" > "${VMX_LOOPS}"]', 'toomany'));
            $ext->add('macro-vm', 'vmx', '', new ext_playback('pm-invalid-option&please-try-again'));
            $ext->add('macro-vm', 'vmx', '', new ext_goto('loopstart'));
            // tomany: to many invalid options, go to the specified destination
            //
            $ext->add('macro-vm', 'vmx', 'toomany', new ext_NoOp('Too Many invalid entries, got to invalid dest'));
            $ext->add('macro-vm', 'vmx', '', new ext_setvar("VMX_OPTS", '${VMX_OPTS_LOOP}'));
            /* Replaced
            	$ext->add('macro-vm','vmx', '', new ext_gotoif('$["${DB_EXISTS(AMPUSER/${MEXTEN}/vmx/${MODE}/vmxopts/loops)}" = "0"]','chkloop'));
            	$ext->add('macro-vm','vmx', '', new ext_setvar("VMX_OPTS",'${DB_RESULT}'));
            	*/
            $ext->add('macro-vm', 'vmx', '', new ext_set('VMX_OPTS', '${IF($["${DB_EXISTS(AMPUSER/${MEXTEN}/vmx/${MODE}/vmxopts/loops)}" = "1"]?${DB_RESULT}:${VMX_OPTS})}'));
            // TODO: same as above, if we just set them then we don't depend on the globals at doloop
            $ext->add('macro-vm', 'vmx', 'chkloop', new ext_gotoif('$["${DB_EXISTS(AMPUSER/${MEXTEN}/vmx/${MODE}/loopdest/ext)}" = "0"]', 'doloop'));
            $ext->add('macro-vm', 'vmx', '', new ext_setvar("VMX_LOOPDEST_EXT", '${DB_RESULT}'));
            /* this would go with the above TODO
            	$ext->add('macro-vm','vmx', 'chkloop', new ext_set('VMX_LOOPDEST_EXT', '${IF($["${DB_EXISTS(AMPUSER/${MEXTEN}/vmx/${MODE}/loopdest/ext)}" = "1"]?${DB_RESULT}:${VMX_LOOPDEST_EXT})}'));
            	*/
            /* Replaced
            	$ext->add('macro-vm','vmx', '', new ext_gotoif('$["${DB_EXISTS(AMPUSER/${MEXTEN}/vmx/${MODE}/loopdest/context)}" = "0"]','looppri'));
            	$ext->add('macro-vm','vmx', '', new ext_setvar("VMX_LOOPDEST_CONTEXT",'${DB_RESULT}'));
            	*/
            $ext->add('macro-vm', 'vmx', '', new ext_set('VMX_LOOPDEST_CONTEXT', '${IF($["${DB_EXISTS(AMPUSER/${MEXTEN}/vmx/${MODE}/loopdest/context)}" = "1"]?${DB_RESULT}:${VMX_LOOPDEST_CONTEXT})}'));
            /* Replaced
            	$ext->add('macro-vm','vmx', 'looppri', new ext_gotoif('$["${DB_EXISTS(AMPUSER/${MEXTEN}/vmx/${MODE}/loopdest/pri)}" = "0"]','doloop'));
            	$ext->add('macro-vm','vmx', '', new ext_setvar("VMX_LOOPDEST_PRI",'${DB_RESULT}'));
            	*/
            $ext->add('macro-vm', 'vmx', 'looppri', new ext_set('VMX_LOOPDEST_PRI', '${IF($["${DB_EXISTS(AMPUSER/${MEXTEN}/vmx/${MODE}/loopdest/pri)}" = "1"]?${DB_RESULT}:${VMX_LOOPDEST_PRI})}'));
            $ext->add('macro-vm', 'vmx', 'doloop', new ext_goto('${VMX_LOOPDEST_PRI}', '${VMX_LOOPDEST_EXT}', '${VMX_LOOPDEST_CONTEXT}'));
            // doopt: execute the valid option that was chosen
            //
            $ext->add('macro-vm', 'vmx', 'doopt', new ext_NoOp('Got a valid option: ${DB_RESULT}'));
            $ext->add('macro-vm', 'vmx', '', new ext_setvar("VMX_EXT", '${DB_RESULT}'));
            // Special case, if this option was to go to voicemail, set options and go
            //
            $ext->add('macro-vm', 'vmx', '', new ext_gotoif('$["${VMX_EXT}" != "dovm"]', 'getdest'));
            /* Replaced
            	$ext->add('macro-vm','vmx', 'vmxopts', new ext_setvar("VMX_OPTS",'${VMX_OPTS_DOVM}'));
            	$ext->add('macro-vm','vmx', '', new ext_gotoif('$["${DB_EXISTS(AMPUSER/${MEXTEN}/vmx/${MODE}/vmxopts/dovm)}" = "0"]','vmxdovm'));
            	$ext->add('macro-vm','vmx', '', new ext_setvar("VMX_OPTS",'${DB_RESULT}'));
            	*/
            $ext->add('macro-vm', 'vmx', 'vmxopts', new ext_set('VMX_OPTS', '${IF($["${DB_EXISTS(AMPUSER/${MEXTEN}/vmx/${MODE}/vmxopts/dovm)}" = "1"]?${DB_RESULT}:${VMX_OPTS_DOVM})}'));
            $ext->add('macro-vm', 'vmx', 'vmxdovm', new ext_goto('1', 'dovm'));
            // General case, setup the goto destination and go there (no error checking, its up to the GUI's to assure
            // reasonable values
            //
            /* Replaced
            	$ext->add('macro-vm','vmx', 'getdest', new ext_gotoif('$["${DB_EXISTS(AMPUSER/${MEXTEN}/vmx/${MODE}/${ACTION}/context)}" = "0"]','vmxpri'));
            	$ext->add('macro-vm','vmx', '', new ext_setvar("VMX_CONTEXT",'${DB_RESULT}'));
            	*/
            $ext->add('macro-vm', 'vmx', 'getdest', new ext_set('VMX_CONTEXT', '${IF($["${DB_EXISTS(AMPUSER/${MEXTEN}/vmx/${MODE}/${ACTION}/context)}" = "1"]?${DB_RESULT}:${VMX_CONTEXT})}'));
            /* Replaced
            	$ext->add('macro-vm','vmx', 'vmxpri', new ext_gotoif('$["${DB_EXISTS(AMPUSER/${MEXTEN}/vmx/${MODE}/${ACTION}/pri)}" = "0"]','vmxgoto'));
            	$ext->add('macro-vm','vmx', '', new ext_setvar("VMX_PRI",'${DB_RESULT}'));
            	*/
            $ext->add('macro-vm', 'vmx', 'vmxpri', new ext_set('VMX_PRI', '${IF($["${DB_EXISTS(AMPUSER/${MEXTEN}/vmx/${MODE}/${ACTION}/pri)}" = "1"]?${DB_RESULT}:${VMX_PRI})}'));
            $ext->add('macro-vm', 'vmx', 'vmxgoto', new ext_goto('${VMX_PRI}', '${VMX_EXT}', '${VMX_CONTEXT}'));
            // If the required voicemail file is not present, then revert to normal voicemail
            // behavior treating as if it was not set
            //
            $ext->add('macro-vm', 'vmx', 'nofile', new ext_NoOp('File for mode: ${MODE} does not exist, SYSTEMSTATUS: ${SYSTEMSTATUS}, going to normal voicemail'));
            $ext->add('macro-vm', 'vmx', '', new ext_goto('1', 's-${MMODE}'));
            $ext->add('macro-vm', 'vmx', 'tmpgreet', new ext_NoOp('Temporary Greeting Detected, going to normal voicemail'));
            $ext->add('macro-vm', 'vmx', '', new ext_goto('1', 's-${MMODE}'));
            // Drop into voicemail either as a direct destination (in which case VMX_OPTS might be set to something) or
            // if the user timed out or broke out of the loop then VMX_OPTS is always cleared such that an Allison
            // message is played and the caller know's what is going on.
            //
            $ext->add('macro-vm', 'dovm', '', new ext_NoOp('VMX Timeout - go to voicemail'));
            $ext->add('macro-vm', 'dovm', '', new ext_vm('${MEXTEN}@${VMCONTEXT},${VMX_OPTS}${VMGAIN}'));
            $ext->add('macro-vm', 'dovm', '', new ext_goto('1', 'exit-${VMSTATUS}'));
            $ext->add('macro-vm', 's-BUSY', '', new ext_NoOp('BUSY voicemail'));
            $ext->add('macro-vm', 's-BUSY', '', new ext_macro('get-vmcontext', '${MEXTEN}'));
            $ext->add('macro-vm', 's-BUSY', '', new ext_vm('${MEXTEN}@${VMCONTEXT},${VM_OPTS}b${VMGAIN}'));
            $ext->add('macro-vm', 's-BUSY', '', new ext_goto('1', 'exit-${VMSTATUS}'));
            $ext->add('macro-vm', 's-NOMESSAGE', '', new ext_NoOp('NOMESSAGE (beep only) voicemail'));
            $ext->add('macro-vm', 's-NOMESSAGE', '', new ext_macro('get-vmcontext', '${MEXTEN}'));
            $ext->add('macro-vm', 's-NOMESSAGE', '', new ext_vm('${MEXTEN}@${VMCONTEXT},s${VM_OPTS}${VMGAIN}'));
            $ext->add('macro-vm', 's-NOMESSAGE', '', new ext_goto('1', 'exit-${VMSTATUS}'));
            $ext->add('macro-vm', 's-INSTRUCT', '', new ext_NoOp('NOMESSAGE (beeb only) voicemail'));
            $ext->add('macro-vm', 's-INSTRUCT', '', new ext_macro('get-vmcontext', '${MEXTEN}'));
            $ext->add('macro-vm', 's-INSTRUCT', '', new ext_vm('${MEXTEN}@${VMCONTEXT},${VM_OPTS}${VMGAIN}'));
            $ext->add('macro-vm', 's-INSTRUCT', '', new ext_goto('1', 'exit-${VMSTATUS}'));
            $ext->add('macro-vm', 's-DIRECTDIAL', '', new ext_NoOp('DIRECTDIAL voicemail'));
            $ext->add('macro-vm', 's-DIRECTDIAL', '', new ext_macro('get-vmcontext', '${MEXTEN}'));
            $ext->add('macro-vm', 's-DIRECTDIAL', '', new ext_vm('${MEXTEN}@${VMCONTEXT},${VM_OPTS}${VM_DDTYPE}${VMGAIN}'));
            $ext->add('macro-vm', 's-DIRECTDIAL', '', new ext_goto('1', 'exit-${VMSTATUS}'));
            $ext->add('macro-vm', '_s-.', '', new ext_macro('get-vmcontext', '${MEXTEN}'));
            $ext->add('macro-vm', '_s-.', '', new ext_vm('${MEXTEN}@${VMCONTEXT},${VM_OPTS}u${VMGAIN}'));
            $ext->add('macro-vm', '_s-.', '', new ext_goto('1', 'exit-${VMSTATUS}'));
            // If the user has a 0 option defined, use that for operator zero-out from within voicemail
            // as well to keep it consistant with the menu structure
            //
            $ext->add('macro-vm', 'o', '', new ext_playback('one-moment-please'));
            $ext->add('macro-vm', 'o', '', new ext_gotoif('$["${DB_EXISTS(AMPUSER/${MEXTEN}/vmx/${MODE}/0/ext)}" = "0"]', 'doopdef'));
            $ext->add('macro-vm', 'o', '', new ext_setvar("VMX_OPDEST_EXT", '${DB_RESULT}'));
            /* Replaced
            	$ext->add('macro-vm','o','',new ext_gotoif('$["${DB_EXISTS(AMPUSER/${MEXTEN}/vmx/${MODE}/0/context)}" = "1"]','opcontext'));
            	$ext->add('macro-vm','o','',new ext_setvar("DB_RESULT",'${VMX_CONTEXT}'));
            	$ext->add('macro-vm','o','opcontext',new ext_setvar("VMX_OPDEST_CONTEXT",'${DB_RESULT}'));
            	*/
            $ext->add('macro-vm', 'o', 'opcontext', new ext_set('VMX_OPDEST_CONTEXT', '${IF($["${DB_EXISTS(AMPUSER/${MEXTEN}/vmx/${MODE}/0/context)}" = "1"]?${DB_RESULT}:${VMX_CONTEXT})}'));
            /* Replaced
            	$ext->add('macro-vm','o','',new ext_gotoif('$["${DB_EXISTS(AMPUSER/${MEXTEN}/vmx/${MODE}/0/pri)}" = "1"]','oppri'));
            	$ext->add('macro-vm','o','',new ext_setvar("DB_RESULT",'${VMX_PRI}'));
            	$ext->add('macro-vm','o','oppri',new ext_setvar("VMX_OPDEST_PRI",'${DB_RESULT}'));
            	*/
            $ext->add('macro-vm', 'o', 'oppri', new ext_set('VMX_OPDEST_PRI', '${IF($["${DB_EXISTS(AMPUSER/${MEXTEN}/vmx/${MODE}/0/pri)}" = "1"]?${DB_RESULT}:${VMX_PRI})}'));
            $ext->add('macro-vm', 'o', '', new ext_goto('${VMX_OPDEST_PRI}', '${VMX_OPDEST_EXT}', '${VMX_OPDEST_CONTEXT}'));
            $ext->add('macro-vm', 'o', 'doopdef', new ext_gotoif('$["x${OPERATOR_XTN}"="x"]', 'nooper', 'from-internal,${OPERATOR_XTN},1'));
            $ext->add('macro-vm', 'o', 'nooper', new ext_gotoif('$["x${FROM_DID}"="x"]', 'nodid'));
            $ext->add('macro-vm', 'o', '', new ext_dial('Local/${FROM_DID}@from-pstn', ''));
            $ext->add('macro-vm', 'o', '', new ext_macro('hangup'));
            $ext->add('macro-vm', 'o', 'nodid', new ext_dial('Local/s@from-pstn', ''));
            $ext->add('macro-vm', 'o', '', new ext_macro('hangup'));
            // If the user has a * option defined, use that for the * out from within voicemail
            // as well to keep it consistant with the menu structure
            //
            $ext->add('macro-vm', 'a', '', new ext_macro('get-vmcontext', '${MEXTEN}'));
            //Dont allow (*) to be dialed to hack voicemail
            //http://issues.freepbx.org/browse/FREEPBX-7757
            $ext->add('macro-vm', 'a', '', new ext_gotoif('$["${DB_EXISTS(AMPUSER/${MEXTEN}/novmstar)}" = "1"]', 's,1'));
            $ext->add('macro-vm', 'a', '', new ext_gotoif('$["${DB_EXISTS(AMPUSER/${MEXTEN}/vmx/${MODE}/*/ext)}" = "0"]', 'adef,1'));
            $ext->add('macro-vm', 'a', '', new ext_setvar("VMX_ADEST_EXT", '${DB_RESULT}'));
            // Replaced
            //$ext->add('macro-vm','a','',new ext_gotoif('$["${DB_EXISTS(AMPUSER/${MEXTEN}/vmx/${MODE}/*/context)}" = "1"]','acontext'));
            //$ext->add('macro-vm','a','',new ext_setvar("DB_RESULT",'${VMX_CONTEXT}'));
            //$ext->add('macro-vm','a','acontext',new ext_setvar("VMX_ADEST_CONTEXT",'${DB_RESULT}'));
            $ext->add('macro-vm', 'a', 'acontext', new ext_set('VMX_ADEST_CONTEXT', '${IF($["${DB_EXISTS(AMPUSER/${MEXTEN}/vmx/${MODE}/*/context)}" = "1"]?${DB_RESULT}:${VMX_CONTEXT})}'));
            // Replaced
            //$ext->add('macro-vm','a','',new ext_gotoif('$["${DB_EXISTS(AMPUSER/${MEXTEN}/vmx/${MODE}/*/pri)}" = "1"]','apri'));
            //$ext->add('macro-vm','a','',new ext_setvar("DB_RESULT",'${VMX_PRI}'));
            //$ext->add('macro-vm','a','apri',new ext_setvar("VMX_ADEST_PRI",'${DB_RESULT}'));
            $ext->add('macro-vm', 'a', 'apri', new ext_set('VMX_ADEST_PRI', '${IF($["${DB_EXISTS(AMPUSER/${MEXTEN}/vmx/${MODE}/*/pri)}" = "1"]?${DB_RESULT}:${VMX_PRI})}'));
            $ext->add('macro-vm', 'a', '', new ext_goto('${VMX_ADEST_PRI}', '${VMX_ADEST_EXT}', '${VMX_ADEST_CONTEXT}'));
            $ext->add('macro-vm', 'adef', '', new ext_vmmain('${MEXTEN}@${VMCONTEXT}'));
            $ext->add('macro-vm', 'adef', '', new ext_gotoif('$["${RETVM}" = "RETURN"]', 'exit-RETURN,1'));
            $ext->add('macro-vm', 'adef', '', new ext_hangup(''));
            $ext->add('macro-vm', 'exit-FAILED', '', new ext_playback('im-sorry&an-error-has-occurred'));
            $ext->add('macro-vm', 'exit-FAILED', '', new ext_gotoif('$["${RETVM}" = "RETURN"]', 'exit-RETURN,1'));
            $ext->add('macro-vm', 'exit-FAILED', '', new ext_hangup(''));
            $ext->add('macro-vm', 'exit-SUCCESS', '', new ext_gotoif('$["${RETVM}" = "RETURN"]', 'exit-RETURN,1'));
            $ext->add('macro-vm', 'exit-SUCCESS', '', new ext_playback('goodbye'));
            $ext->add('macro-vm', 'exit-SUCCESS', '', new ext_hangup(''));
            $ext->add('macro-vm', 'exit-USEREXIT', '', new ext_gotoif('$["${RETVM}" = "RETURN"]', 'exit-RETURN,1'));
            $ext->add('macro-vm', 'exit-USEREXIT', '', new ext_playback('goodbye'));
            $ext->add('macro-vm', 'exit-USEREXIT', '', new ext_hangup(''));
            $ext->add('macro-vm', 'exit-RETURN', '', new ext_noop('Returning From Voicemail because macro'));
            $ext->add('macro-vm', 't', '', new ext_hangup(''));
            /* end macro-vm  */
            /*
             * ARG1: VMBOX
             * ARG2: EXTTOCALL
             * ARG3: If NOANSWER dest exists 1, otherwise 0
             * ARG4: If BUSY dest exists 1, otherwise 0
             * ARG5: If CHANUNAVAIL dest exists 1, otherwise 0
             */
            $mcontext = 'macro-exten-vm';
            $exten = 's';
            $ext->add($mcontext, $exten, '', new ext_macro('user-callerid'));
            $ext->add($mcontext, $exten, '', new ext_set("RingGroupMethod", 'none'));
            $ext->add($mcontext, $exten, '', new ext_set("__EXTTOCALL", '${ARG2}'));
            $ext->add($mcontext, $exten, '', new ext_set("__PICKUPMARK", '${ARG2}'));
            $ext->add($mcontext, $exten, '', new ext_set("RT", '${IF($["${ARG1}"!="novm" | "${DB(CFU/${EXTTOCALL})}"!="" | "${DB(CFB/${EXTTOCALL})}"!="" | "${ARG3}"="1" | "${ARG4}"="1" | "${ARG5}"="1"]?${RINGTIMER}:)}'));
            $ext->add($mcontext, $exten, 'checkrecord', new ext_gosub('1', 's', 'sub-record-check', 'exten,${EXTTOCALL},dontcare'));
            // If paging module is not present, then what happens?
            // TODO: test with no paging module
            $fcc = new featurecode('paging', 'intercom-prefix');
            $intercom_code = $fcc->getCodeActive();
            unset($fcc);
            // I think it is adequate that if AMPUSER is blank, it's not internal (don't think FROM_DID has to be checked though I don't think it hurts)
            $macrodial = 'macrodial';
            if ($intercom_code != '') {
                if ($amp_conf['AST_FUNC_EXTENSION_STATE']) {
                    $ext->add($mcontext, $exten, '', new ext_noop_trace('AMPUSER: ${AMPUSER}, FROM_DID: ${FROM_DID}, FROM_QUEUE: $["${CUT(CHANNEL,@,2):5:5}"="queue"], answermode: ${DB(AMPUSER/${EXTTOCALL}/answermode)}, BLINDTXF: ${BLINDTRANSFER}, ATTTXF: ${ATTENDEDTRANSFER}, EXT_STATE: ${EXTENSION_STATE(${EXTTOCALL})}, CC_RECALL: ${CC_RECALL}'));
                    if ($amp_conf['FORCE_INTERNAL_AUTO_ANSWER_ALL']) {
                        $ext->add($mcontext, $exten, '', new ext_gotoif('$["${CUT(CHANNEL,@,2):5:5}"="queue"|"${AMPUSER}"=""|${LEN(${FROM_DID})}|${LEN(${BLINDTRANSFER})}|"${EXTENSION_STATE(${EXTTOCALL})}"!="NOT_INUSE"|"${CC_RECALL}"!=""]', 'macrodial'));
                    } else {
                        $ext->add($mcontext, $exten, '', new ext_gotoif('$["${CUT(CHANNEL,@,2):5:5}"="queue"|"${AMPUSER}"=""|${LEN(${FROM_DID})}|"${DB(AMPUSER/${EXTTOCALL}/answermode)}"!="intercom"|${LEN(${BLINDTRANSFER})}|"${EXTENSION_STATE(${EXTTOCALL})}"!="NOT_INUSE"|"${CC_RECALL}"!=""]', 'macrodial'));
                    }
                } else {
                    $ext->add($mcontext, $exten, '', new ext_noop_trace('AMPUSER: ${AMPUSER}, FROM_DID: ${FROM_DID}, FROM_QUEUE: $["${CUT(CHANNEL,@,2):5:5}"="queue"], answermode: ${DB(AMPUSER/${EXTTOCALL}/answermode)}, BLINDTXF: ${BLINDTRANSFER}, , ATTTXF: ${ATTENDEDTRANSFER}, CC_RECALL: ${CC_RECALL}'));
                    if ($amp_conf['FORCE_INTERNAL_AUTO_ANSWER_ALL']) {
                        $ext->add($mcontext, $exten, '', new ext_gotoif('$["${CUT(CHANNEL,@,2):5:5}"="queue"|"${AMPUSER}"=""|${LEN(${FROM_DID})}|${LEN(${BLINDTRANSFER})}]', 'macrodial'));
                    } else {
                        $ext->add($mcontext, $exten, '', new ext_gotoif('$["${CUT(CHANNEL,@,2):5:5}"="queue"|"${AMPUSER}"=""|${LEN(${FROM_DID})}|"${DB(AMPUSER/${EXTTOCALL}/answermode)}"!="intercom"|${LEN(${BLINDTRANSFER})}]', 'macrodial'));
                    }
                }
                $ext->add($mcontext, $exten, '', new ext_set("INTERCOM_EXT_DOPTIONS", '${DIAL_OPTIONS}'));
                $ext->add($mcontext, $exten, '', new ext_set("INTERCOM_RETURN", 'TRUE'));
                $ext->add($mcontext, $exten, '', new ext_gosub('1', $intercom_code . '${EXTTOCALL}', 'ext-intercom'));
                $ext->add($mcontext, $exten, '', new ext_set("INTERCOM_RETURN", ''));
                $ext->add($mcontext, $exten, '', new ext_set("INTERCOM_EXT_DOPTIONS", ''));
                // If it was a blind transfer and there was a previous auto-answer, then we cleanup all the auto-answer headers left in the channel
                // It won't be from this call because we don't ever intercom in a blind transfer scenario (hmm unless it was blind transfered to a
                // specific intercom code but in that case, they won't have been able to subsequently transfered the call
                //
                $ext->add($mcontext, $exten, $macrodial, new ext_gosubif('$["${INTERCOM_CALL}"="TRUE" & ${LEN(${BLINDTRANSFER})}]', 'clrheader,1'));
                $macrodial = '';
            }
            if ($amp_conf['AST_FUNC_EXTENSION_STATE']) {
                $ext->add($mcontext, $exten, $macrodial, new ext_macro('dial-one', '${RT},${DIAL_OPTIONS},${EXTTOCALL}'));
            } else {
                $ext->add($mcontext, $exten, $macrodial, new ext_macro('dial', '${RT},${DIAL_OPTIONS},${EXTTOCALL}'));
            }
            $ext->add($mcontext, $exten, '', new ext_set("SV_DIALSTATUS", '${DIALSTATUS}'));
            $ext->add($mcontext, $exten, 'calldocfu', new ext_gosubif('$[("${SV_DIALSTATUS}"="NOANSWER"|"${SV_DIALSTATUS}"="CHANUNAVAIL") & "${DB(CFU/${EXTTOCALL})}"!="" & "${SCREEN}"=""]', 'docfu,1'));
            $ext->add($mcontext, $exten, 'calldocfb', new ext_gosubif('$["${SV_DIALSTATUS}"="BUSY" & "${DB(CFB/${EXTTOCALL})}"!="" & "${SCREEN}"=""]', 'docfb,1'));
            $ext->add($mcontext, $exten, '', new ext_set("DIALSTATUS", '${SV_DIALSTATUS}'));
            $ext->add($mcontext, $exten, '', new ext_execif('$[("${DIALSTATUS}"="NOANSWER"&"${ARG3}"="1")|("${DIALSTATUS}"="BUSY"&"${ARG4}"="1")|("${DIALSTATUS}"="CHANUNAVAIL"&"${ARG5}"="1")]', 'MacroExit'));
            $ext->add($mcontext, $exten, '', new ext_noop_trace('Voicemail is \'${ARG1}\'', 1));
            $ext->add($mcontext, $exten, '', new ext_gotoif('$["${ARG1}"="novm"]', 's-${DIALSTATUS},1'));
            $ext->add($mcontext, $exten, '', new ext_noop_trace('Sending to Voicemail box ${EXTTOCALL}', 1));
            $ext->add($mcontext, $exten, '', new ext_macro('vm', '${ARG1},${DIALSTATUS},${IVR_RETVM}'));
            $exten = 'docfu';
            if ($amp_conf['DIVERSIONHEADER']) {
                $ext->add($mcontext, $exten, '', new ext_set('__DIVERSION_REASON', 'unavailable'));
            }
            $ext->add($mcontext, $exten, 'docfu', new ext_execif('$["${DB(AMPUSER/${EXTTOCALL}/cfringtimer)}"="-1"|("${ARG1}"="novm"&"${ARG3}"="1")]', 'StackPop'));
            $ext->add($mcontext, $exten, '', new ext_gotoif('$["${DB(AMPUSER/${EXTTOCALL}/cfringtimer)}"="-1"|("${ARG1}"="novm"&"${ARG3}"="1")]', 'from-internal,${DB(CFU/${EXTTOCALL})},1'));
            $ext->add($mcontext, $exten, '', new ext_set("RTCF", '${IF($["${DB(AMPUSER/${EXTTOCALL}/cfringtimer)}"="0"]?${RT}:${DB(AMPUSER/${EXTTOCALL}/cfringtimer)})}'));
            $ext->add($mcontext, $exten, '', new ext_execif('$["${DIRECTION}" = "INBOUND"]', 'Set', 'DIAL_OPTIONS=${STRREPLACE(DIAL_OPTIONS,T)}I'));
            $ext->add($mcontext, $exten, '', new ext_dial('Local/${DB(CFU/${EXTTOCALL})}@from-internal/n', '${RTCF},${DIAL_OPTIONS}'));
            if ($amp_conf['DIVERSIONHEADER']) {
                $ext->add($mcontext, $exten, '', new ext_set('__DIVERSION_REASON', ''));
            }
            $ext->add($mcontext, $exten, '', new ext_return(''));
            $exten = 'docfb';
            if ($amp_conf['DIVERSIONHEADER']) {
                $ext->add($mcontext, $exten, '', new ext_set('__DIVERSION_REASON', 'user-busy'));
            }
            $ext->add($mcontext, $exten, 'docfu', new ext_execif('$["${DB(AMPUSER/${EXTTOCALL}/cfringtimer)}"="-1"|("${ARG1}"="novm"&"${ARG4}"="1")]', 'StackPop'));
            $ext->add($mcontext, $exten, '', new ext_gotoif('$["${DB(AMPUSER/${EXTTOCALL}/cfringtimer)}"="-1"|("${ARG1}"="novm"&"${ARG4}"="1")]', 'from-internal,${DB(CFB/${EXTTOCALL})},1'));
            $ext->add($mcontext, $exten, '', new ext_set("RTCF", '${IF($["${DB(AMPUSER/${EXTTOCALL}/cfringtimer)}"="0"]?${RT}:${DB(AMPUSER/${EXTTOCALL}/cfringtimer)})}'));
            $ext->add($mcontext, $exten, '', new ext_execif('$["${DIRECTION}" = "INBOUND"]', 'Set', 'DIAL_OPTIONS=${STRREPLACE(DIAL_OPTIONS,T)}I'));
            $ext->add($mcontext, $exten, '', new ext_dial('Local/${DB(CFB/${EXTTOCALL})}@from-internal/n', '${RTCF},${DIAL_OPTIONS}'));
            if ($amp_conf['DIVERSIONHEADER']) {
                $ext->add($mcontext, $exten, '', new ext_set('__DIVERSION_REASON', ''));
            }
            $ext->add($mcontext, $exten, '', new ext_return(''));
            // If we are here it was determined that there had been intercom sip headers left over in the channel. If 1.6.2+ then we can use
            // the SIPRemoveHeader() option to remove the specific headers. We are trying to be careful not to remove similar headers that
            // may be used for 'distinctive ring' type reasons from elsewhere in the dialplan. Thus only if we detected the intercom situation
            // do we do it here.
            //
            // If we are pre 1.6.2 then some experimentation on 1.4.X has shown that we are able to clear the SIPADDHEADERnn channel variables
            // that result from setting the headers so we start from 1 (the first) and iterate up until we find one. In some weird situations
            // if a header had been removed, we could miss out since it is not possible to detect the existence of a blank channel variable
            //
            if ($intercom_code != '') {
                $exten = 'clrheader';
                $ext->add($mcontext, $exten, '', new ext_execif('$[${LEN(${SIPURI})}&"${SIPURI}"="${SIP_URI_OPTIONS}"]', 'Set', 'SIP_URI_OPTIONS='));
                if ($ast_ge_162) {
                    $ext->add($mcontext, $exten, '', new ext_execif('$[${LEN(${ALERTINFO})}]', 'SIPRemoveHeader', '${ALERTINFO}'));
                    $ext->add($mcontext, $exten, '', new ext_execif('$[${LEN(${CALLINFO})}]', 'SIPRemoveHeader', '${CALLINFO}'));
                } else {
                    $ext->add($mcontext, $exten, '', new ext_set('SP', '0'));
                    $ext->add($mcontext, $exten, '', new ext_set('ITER', '1'));
                    $ext->add($mcontext, $exten, 'begin', new ext_execif('$[${ITER} > 9]', 'Set', 'SP='));
                    $ext->add($mcontext, $exten, '', new ext_execif('$[${LEN(${SIPADDHEADER${SP}${ITER}})}=0]', 'Return'));
                    $ext->add($mcontext, $exten, '', new ext_execif('$["${SIPADDHEADER${SP}${ITER}}"="${ALERTINFO}"|"${SIPADDHEADER${SP}${ITER}}"="${CALLINFO}"]', 'Set', 'SIPADDHEADER${SP}${ITER}='));
                    $ext->add($mcontext, $exten, '', new ext_setvar('ITER', '$[${ITER} + 1]'));
                    $ext->add($mcontext, $exten, '', new ext_gotoif('$[${ITER} < 100]', 'begin'));
                }
                $ext->add($mcontext, $exten, '', new ext_return(''));
            }
            $exten = 's-BUSY';
            $ext->add($mcontext, $exten, '', new ext_noop_trace('Extension is reporting BUSY and not passing to Voicemail', 1));
            $ext->add($mcontext, $exten, '', new ext_gotoif('$["${IVR_RETVM}"="RETURN" & "${IVR_CONTEXT}"!=""]', 'exit,1'));
            $ext->add($mcontext, $exten, '', new ext_playtones('busy'));
            $ext->add($mcontext, $exten, '', new ext_busy(20));
            $exten = '_s-!';
            $ext->add($mcontext, $exten, '', new ext_noop_trace('IVR_RETVM: ${IVR_RETVM} IVR_CONTEXT: ${IVR_CONTEXT}', 1));
            $ext->add($mcontext, $exten, '', new ext_gotoif('$["${IVR_RETVM}"="RETURN" & "${IVR_CONTEXT}"!=""]', 'exit,1'));
            $ext->add($mcontext, $exten, '', new ext_playtones('congestion'));
            $ext->add($mcontext, $exten, '', new ext_congestion('10'));
            $exten = 'exit';
            $ext->add($mcontext, $exten, '', new ext_playback('beep&line-busy-transfer-menu&silence/1'));
            $ext->add($mcontext, $exten, '', new ext_macroexit());
            /* macro-exten-vm  */
            /*
            ;------------------------------------------------------------------------
            ; [macro-simple-dial]
            ;------------------------------------------------------------------------
            ; This macro was derived from macro-exten-vm, which is what is normally used to
            ; ring an extension. It has been simplified and designed to never go to voicemail
            ; and always return regardless of the DIALSTATUS for any incomplete call.
            ;
            ; It's current primary purpose is to allow findmefollow ring an extension prior
            ; to trying the follow-me ringgroup that is provided.
            ;
            ; Ring an extension, if the extension is busy or there is no answer, return
            ; ARGS: $EXTENSION, $RINGTIME
            ;------------------------------------------------------------------------
            */
            $mcontext = 'macro-simple-dial';
            $exten = 's';
            $ext->add($mcontext, $exten, '', new ext_set("__EXTTOCALL", '${ARG1}'));
            $ext->add($mcontext, $exten, '', new ext_set("RT", '${ARG2}'));
            $ext->add($mcontext, $exten, '', new ext_set("CFUEXT", '${DB(CFU/${EXTTOCALL})}'));
            $ext->add($mcontext, $exten, '', new ext_set("CFBEXT", '${DB(CFB/${EXTTOCALL})}'));
            $ext->add($mcontext, $exten, '', new ext_set("CWI_TMP", '${CWIGNORE}'));
            if ($amp_conf['AST_FUNC_EXTENSION_STATE']) {
                $ext->add($mcontext, $exten, 'macrodial', new ext_macro('dial-one', '${RT},${DIAL_OPTIONS},${EXTTOCALL}'));
            } else {
                $ext->add($mcontext, $exten, 'macrodial', new ext_macro('dial', '${RT},${DIAL_OPTIONS},${EXTTOCALL}'));
            }
            $ext->add($mcontext, $exten, '', new ext_set("__CWIGNORE", '${CWI_TMP}'));
            $ext->add($mcontext, $exten, '', new ext_set("PR_DIALSTATUS", '${DIALSTATUS}'));
            $ext->add($mcontext, $exten, 'calldocfu', new ext_gosubif('$["${PR_DIALSTATUS}"="NOANSWER" & "${CFUEXT}"!=""]', 'docfu,1'));
            $ext->add($mcontext, $exten, 'calldocfb', new ext_gosubif('$["${PR_DIALSTATUS}"="BUSY" & "${CFBEXT}"!=""]', 'docfb,1'));
            $ext->add($mcontext, $exten, '', new ext_set("DIALSTATUS", '${PR_DIALSTATUS}'));
            $ext->add($mcontext, $exten, '', new ext_goto('1', 's-${DIALSTATUS}'));
            /*
            ; Try the Call Forward on No Answer / Unavailable number.
            ; We want to try CFU if set, but we want the same ring timer as was set to our call (or do we want the
            ; system ringtimer? - probably not). Then if no answer there (assuming it doesn't drop into their vm or
            ; something we return, which will have the net effect of returning to the followme setup.)
            ;
            ; want to avoid going to other follow-me settings here. So check if the CFUEXT is a user and if it is
            ; then direct it straight to ext-local (to avoid getting intercepted by findmefollow) otherwise send it
            ; to from-internal since it may be an outside line.
            ;
            */
            $exten = 'docfu';
            $ext->add($mcontext, $exten, '', new ext_gotoif('$["${DB(AMPUSER/${CFUEXT}/device)}" = "" ]', 'chlocal'));
            $ext->add($mcontext, $exten, '', new ext_dial('Local/${CFUEXT}@ext-local', '${RT},${DIAL_OPTIONS}'));
            $ext->add($mcontext, $exten, '', new ext_return(''));
            $ext->add($mcontext, $exten, 'chlocal', new ext_execif('$["${DIRECTION}" = "INBOUND"]', 'Set', 'DIAL_OPTIONS=${STRREPLACE(DIAL_OPTIONS,T)}I'));
            $ext->add($mcontext, $exten, '', new ext_dial('Local/${CFUEXT}@from-internal/n', '${RT},${DIAL_OPTIONS}'));
            $ext->add($mcontext, $exten, '', new ext_return(''));
            $exten = 'docfb';
            $ext->add($mcontext, $exten, '', new ext_gotoif('$["${DB(AMPUSER/${CFBEXT}/device)}" = "" ]', 'chlocal'));
            $ext->add($mcontext, $exten, '', new ext_dial('Local/${CFBEXT}@ext-local', '${RT},${DIAL_OPTIONS}'));
            $ext->add($mcontext, $exten, '', new ext_return(''));
            $ext->add($mcontext, $exten, 'chlocal', new ext_execif('$["${DIRECTION}" = "INBOUND"]', 'Set', 'DIAL_OPTIONS=${STRREPLACE(DIAL_OPTIONS,T)}I'));
            $ext->add($mcontext, $exten, '', new ext_dial('Local/${CFBEXT}@from-internal/n', '${RT},${DIAL_OPTIONS}'));
            $ext->add($mcontext, $exten, '', new ext_return(''));
            /*
            ; In all cases of no connection, come here and simply return, since the calling dialplan will
            ; decide what to do next
            */
            $exten = '_s-.';
            $ext->add($mcontext, $exten, '', new ext_noop('Extension is reporting ${EXTEN}'));
            /*
            		Originate a call but skip voicemail if the device does not answer
            */
            $mcontext = 'originate-skipvm';
            $ext->add($mcontext, '_.X', '', new ext_macro('blkvm-set'));
            $ext->add($mcontext, '_.X', '', new ext_goto('1', '${EXTEN}', 'from-internal'));
            /* macro-simple-dial */
            /* macro-blkvm-setifempty
             * macro-blkvm-set
             * macro-blkvm-clr
             * macro-blkvm-check
             *
             * These macros are used to tell the voicemail system if it should answer a call or kill the call.
             * They are also used by modules like findmefollow and ringgroups to determine if a destination
             * if noanswer should be pursued, or if they should just end because they were called by a higher
             * level module who's destination should be honored. (Thus if vm should be blocked, so should
             * such destinations.
             *
             * In the past, it was necessary to create and track unique AstDB variables to track this since
             * it is necessary for a call that is answered, for example a queue memeber who answers a queue
             * call, to clr the block so that subsequent transfers to voicemail or user extensions which might
             * hit voicemail could succeed and the nature of Asterisk inheritable variable did not allow
             * this. This also meant that these needed to be cleaned up when the master channel who 'started
             * it all' ended, which is attempted in macro-hangupcall. There are still cases where cleanup
             * does not happen which can result in an accumulation of these.
             *
             * With the advent of the SHARED() channel variable starting in 1.6, we can achieve the same
             * thing with such a SHARED() channel variable which should be more efficient since it does not
             * hit the DB, but more importantly, there is no cleanup because the variable will die with the
             * owner channel.
             *
             * We check if the SHARED function is available and if so, we use that in our macro. If not, we
             * fall back to the shared DB variable and keep our cleanup code in hangupcall.
             *
             * Note that we have chosen to use a Macro() in place of a GoSub() because in the legacy DB
             * mode we must have the owning ${EXTEN} to create our unique key. Since GoSub() does not support
             * passing arguments until 1.6 this would not be possible in 1.4 which is still mainstream.
             * We have chosen to use the GOSUB_RETVAL in anticipation of a future point where we move to
             * a GoSub() call which would be slightly more efficient.
             */
            $exten = 's';
            if ($amp_conf['AST_FUNC_SHARED']) {
                // If it BLKVM_CHANNEL exists, return it's value. If not, then set it and return TRUE
                //
                $mcontext = 'macro-blkvm-setifempty';
                $ext->add($mcontext, $exten, '', new ext_gotoif('$[!${EXISTS(${BLKVM_CHANNEL})}]', 'init'));
                $ext->add($mcontext, $exten, '', new ext_set('GOSUB_RETVAL', '${SHARED(BLKVM,${BLKVM_CHANNEL})}'));
                $ext->add($mcontext, $exten, '', new ext_macroexit(''));
                $ext->add($mcontext, $exten, 'init', new ext_set('__BLKVM_CHANNEL', '${CHANNEL}'));
                $ext->add($mcontext, $exten, '', new ext_set('SHARED(BLKVM,${BLKVM_CHANNEL})', 'TRUE'));
                $ext->add($mcontext, $exten, '', new ext_set('GOSUB_RETVAL', 'TRUE'));
                $ext->add($mcontext, $exten, '', new ext_macroexit(''));
                // If BLKVM_CHANNEL not set or 'reset' is passed, then initialize it to this channel then set and retrun TRUE
                //
                $mcontext = 'macro-blkvm-set';
                $ext->add($mcontext, $exten, '', new ext_execif('$[!${EXISTS(${BLKVM_CHANNEL})} | "{ARG1}" = "reset"]', 'Set', '__BLKVM_CHANNEL=${CHANNEL}'));
                $ext->add($mcontext, $exten, '', new ext_set('SHARED(BLKVM,${BLKVM_CHANNEL})', 'TRUE'));
                $ext->add($mcontext, $exten, '', new ext_set('GOSUB_RETVAL', 'TRUE'));
                $ext->add($mcontext, $exten, '', new ext_macroexit(''));
                // if clearing, BLKVM_CHANNEL should already exist (if not, we clear our channel's copy)
                //
                $mcontext = 'macro-blkvm-clr';
                $ext->add($mcontext, $exten, '', new ext_set('SHARED(BLKVM,${BLKVM_CHANNEL})', ''));
                $ext->add($mcontext, $exten, '', new ext_set('GOSUB_RETVAL', ''));
                $ext->add($mcontext, $exten, '', new ext_macroexit(''));
                // if checking, BLKVM_CHANNEL should already exist (if not, we check our channel's copy)
                // CC_RECALL was originally used for CallCompletion but is used elsewhere as well for recall automated
                // calls that should therefore not go to voicemail, for example a wakeup call
                //
                $mcontext = 'macro-blkvm-check';
                $ext->add($mcontext, $exten, '', new ext_set('GOSUB_RETVAL', '${SHARED(BLKVM,${BLKVM_CHANNEL})}'));
                $ext->add($mcontext, $exten, '', new ext_execif('$["${GOSUB_RETVAL}"="" & "${CC_RECALL}"="1"]', 'Set', 'GOSUB_RETVAL=TRUE'));
                $ext->add($mcontext, $exten, '', new ext_macroexit(''));
            } else {
                // NO SHARED()
                // If it BLKVM_OVERRIDE exists, return it's value. If not, then set it and return TRUE
                //
                $mcontext = 'macro-blkvm-setifempty';
                $ext->add($mcontext, $exten, '', new ext_gotoif('$[!${EXISTS(${BLKVM_OVERRIDE})}]', 'init'));
                $ext->add($mcontext, $exten, '', new ext_set('GOSUB_RETVAL', '${DB(${BLKVM_OVERRIDE})}'));
                $ext->add($mcontext, $exten, '', new ext_macroexit(''));
                $ext->add($mcontext, $exten, 'init', new ext_set('__BLKVM_OVERRIDE', 'BLKVM/${MACRO_EXTEN}/${CHANNEL}'));
                $ext->add($mcontext, $exten, '', new ext_set('__BLKVM_BASE', '${MACRO_EXTEN}'));
                $ext->add($mcontext, $exten, '', new ext_set('DB(${BLKVM_OVERRIDE})', 'TRUE'));
                $ext->add($mcontext, $exten, '', new ext_set('GOSUB_RETVAL', 'TRUE'));
                $ext->add($mcontext, $exten, '', new ext_macroexit(''));
                // If BLKVM_OVERRIDE not set or 'reset' is passed, then initialize it to this channel then set and retrun TRUE
                //
                $mcontext = 'macro-blkvm-set';
                $ext->add($mcontext, $exten, '', new ext_execif('$[!${EXISTS(${BLKVM_OVERRIDE})} | "{ARG1}" = "reset"]', 'Set', '__BLKVM_BASE=${MACRO_EXTEN}'));
                $ext->add($mcontext, $exten, '', new ext_execif('$[!${EXISTS(${BLKVM_OVERRIDE})} | "{ARG1}" = "reset"]', 'Set', '__BLKVM_OVERRIDE=BLKVM/${MACRO_EXTEN}/${CHANNEL}'));
                $ext->add($mcontext, $exten, '', new ext_set('DB(${BLKVM_OVERRIDE})', 'TRUE'));
                $ext->add($mcontext, $exten, '', new ext_set('GOSUB_RETVAL', 'TRUE'));
                $ext->add($mcontext, $exten, '', new ext_macroexit(''));
                // if clearing, BLKVM_OVERRIDE should already exist (if not, it's already cleared anyhow)
                //
                $mcontext = 'macro-blkvm-clr';
                $ext->add($mcontext, $exten, '', new ext_gotoif('$[!${EXISTS(${BLKVM_OVERRIDE})}]', 'ret'));
                $ext->add($mcontext, $exten, '', new ext_dbdel('${BLKVM_OVERRIDE}'));
                $ext->add($mcontext, $exten, 'ret', new ext_set('GOSUB_RETVAL', ''));
                $ext->add($mcontext, $exten, '', new ext_macroexit(''));
                // if checking, BLKVM_OVERRIDE should already exist (if not, '' will be returned)
                //
                $mcontext = 'macro-blkvm-check';
                $ext->add($mcontext, $exten, '', new ext_set('GOSUB_RETVAL', '${DB(${BLKVM_OVERRIDE})}'));
                $ext->add($mcontext, $exten, '', new ext_macroexit(''));
            }
            $mcontext = 'macro-hangupcall';
            $exten = 's';
            /*
            ; Cleanup any remaining RG flag
            */
            $skip_label = $amp_conf['AST_FUNC_SHARED'] ? 'theend' : 'skiprg';
            $ext->add($mcontext, $exten, 'start', new ext_gotoif('$["${USE_CONFIRMATION}"="" | "${RINGGROUP_INDEX}"="" | "${CHANNEL}"!="${UNIQCHAN}"]', $skip_label));
            $ext->add($mcontext, $exten, '', new ext_noop_trace('Cleaning Up Confirmation Flag: RG/${RINGGROUP_INDEX}/${CHANNEL}'));
            $ext->add($mcontext, $exten, 'delrgi', new ext_dbdel('RG/${RINGGROUP_INDEX}/${CHANNEL}'));
            if (!$amp_conf['AST_FUNC_SHARED']) {
                // only clr it if we were the originating channel
                //
                $ext->add($mcontext, $exten, 'skiprg', new ext_gotoif('$["${BLKVM_BASE}"="" | "BLKVM/${BLKVM_BASE}/${CHANNEL}"!="${BLKVM_OVERRIDE}"]', 'skipblkvm'));
                $ext->add($mcontext, $exten, '', new ext_noop_trace('Cleaning Up Block VM Flag: ${BLKVM_OVERRIDE}'));
                $ext->add($mcontext, $exten, '', new ext_macro('blkvm-clr'));
                /*
                ; Cleanup any remaining FollowMe DND flags
                */
                $ext->add($mcontext, $exten, 'skipblkvm', new ext_gotoif('$["${FMGRP}"="" | "${FMUNIQUE}"="" | "${CHANNEL}"!="${FMUNIQUE}"]', 'theend'));
                $ext->add($mcontext, $exten, 'delfmrgp', new ext_dbdel('FM/DND/${FMGRP}/${CHANNEL}'));
                $skip_label = $next_label;
            }
            // Work around Asterisk issue: https://issues.asterisk.org/jira/browse/ASTERISK-19853
            $ext->add($mcontext, $exten, 'theend', new ext_execif('$["${ONETOUCH_RECFILE}"!="" & "${CDR(recordingfile)}"=""]', 'Set', 'CDR(recordingfile)=${ONETOUCH_RECFILE}'));
            $ext->add($mcontext, $exten, '', new ext_hangup());
            // TODO: once Asterisk issue fixed label as theend
            $ext->add($mcontext, $exten, '', new ext_macroexit(''));
            /*
            $ext->add($mcontext, $exten, 'theend', new ext_gosubif('$["${ONETOUCH_REC}"="RECORDING"]', 'macro-one-touch-record,s,sstate', false, '${FROMEXTEN},NOT_INUSE'));
            $ext->add($mcontext, $exten, '', new ext_gosubif('$["${ONETOUCH_REC}"="RECORDING"&"${MASTER_CHANNEL(CLEAN_DIALEDPEERNUMBER)}"="${CUT(CALLFILENAME,-,2)}"]', 'macro-one-touch-record,s,sstate', false, '${IF($["${EXTTOCALL}"!=""]?${EXTTOCALL}:${CUT(CALLFILENAME,-,2)})},NOT_INUSE'));
            $ext->add($mcontext, $exten, '', new ext_gosubif('$["${ONETOUCH_REC}"="RECORDING"&"${MASTER_CHANNEL(CLEAN_DIALEDPEERNUMBER)}"!="${CUT(CALLFILENAME,-,2)}"]','macro-one-touch-record,s,sstate',false,'${MASTER_CHANNEL(CLEAN_DIALEDPEERNUMBER)},NOT_INUSE'));
            $ext->add($mcontext,$exten,'', new ext_noop_trace('ONETOUCH_REC: ${ONETOUCH_REC}',5));
            */
            /* Now generate a clean DIALEDPEERNUMBER if ugly followme/ringgroup extensions dialplans were engaged
            	* doesn't seem like this is need with some of the NoCDRs() but leave for now and keep an eye on it
            	*
            	$ext->add($mcontext, $exten, '', new ext_execif('$["${CLEAN_DIALEDPEERNUMBER}"=""]','Set','CLEAN_DIALEDPEERNUMBER=${IF($[${FIELDQTY(DIALEDPEERNUMBER,-)}=1]?${DIALEDPEERNUMBER}:${CUT(CUT(DIALEDPEERNUMBER,-,2),@,1)})}'));
            	$ext->add($mcontext, $exten, '', new ext_set('CDR(clean_dst)','${CLEAN_DIALEDPEERNUMBER}'));
            	*/
            /* macro-hangupcall */
            include 'functions.inc/macro-dial-one.php';
            include 'functions.inc/func-sipheaders.php';
            break;
    }
}
Esempio n. 19
0
function outroutemsg_get_config($engine)
{
    global $db;
    global $ext;
    global $version;
    switch ($engine) {
        case "asterisk":
            /* here we add macro-outisbusy with the following actions:
             * if ( EMERGENCYROUTE=YES ):
             * 	choose Emergency Message over everything else, ANSWER CALL
             * if ( INTRACOMPANYROUTE=YES ):
             * 	choose Intracompany Message over default
             * Use default
             */
            $contextname = 'macro-outisbusy';
            $outroutemsg_ids = outroutemsg_get();
            $exten = 's';
            $ext->add($contextname, $exten, '', new ext_progress());
            $ext->add($contextname, $exten, '', new ext_gotoif('$["${EMERGENCYROUTE}" = "YES"]', 'emergency,1'));
            $ext->add($contextname, $exten, '', new ext_gotoif('$["${INTRACOMPANYROUTE}" = "YES"]', 'intracompany,1'));
            switch ($outroutemsg_ids['default_msg_id']) {
                case DEFAULT_MSG:
                    $ext->add($contextname, $exten, '', new ext_playback("all-circuits-busy-now&pls-try-call-later, noanswer"));
                    break;
                case CONGESTION_TONE:
                    $ext->add($contextname, $exten, '', new ext_playtones("congestion"));
                    break;
                default:
                    $message = recordings_get_file($outroutemsg_ids['default_msg_id']);
                    $message = $message != "" ? $message : "all-circuits-busy-now&pls-try-call-later";
                    $ext->add($contextname, $exten, '', new ext_playback("{$message}, noanswer"));
            }
            $ext->add($contextname, $exten, '', new ext_congestion());
            $ext->add($contextname, $exten, '', new ext_hangup());
            $exten = 'intracompany';
            switch ($outroutemsg_ids['intracompany_msg_id']) {
                case DEFAULT_MSG:
                    $ext->add($contextname, $exten, '', new ext_playback("all-circuits-busy-now&pls-try-call-later, noanswer"));
                    break;
                case CONGESTION_TONE:
                    $ext->add($contextname, $exten, '', new ext_playtones("congestion"));
                    break;
                default:
                    $message = recordings_get_file($outroutemsg_ids['intracompany_msg_id']);
                    $message = $message != "" ? $message : "all-circuits-busy-now&pls-try-call-later";
                    $ext->add($contextname, $exten, '', new ext_playback("{$message}, noanswer"));
            }
            $ext->add($contextname, $exten, '', new ext_congestion());
            $ext->add($contextname, $exten, '', new ext_hangup());
            $exten = 'emergency';
            switch ($outroutemsg_ids['emergency_msg_id']) {
                case DEFAULT_MSG:
                    $ext->add($contextname, $exten, '', new ext_playback("all-circuits-busy-now&pls-try-call-later"));
                    break;
                case CONGESTION_TONE:
                    $ext->add($contextname, $exten, '', new ext_playtones("congestion"));
                    break;
                default:
                    $message = recordings_get_file($outroutemsg_ids['emergency_msg_id']);
                    $message = $message != "" ? $message : "all-circuits-busy-now&pls-try-call-later";
                    $ext->add($contextname, $exten, '', new ext_playback("{$message}"));
            }
            $ext->add($contextname, $exten, '', new ext_congestion());
            $ext->add($contextname, $exten, '', new ext_hangup());
    }
}
Esempio n. 20
0
function paging_get_config($engine)
{
    global $db, $ext, $chan_dahdi, $version, $amp_conf, $conferences_conf;
    switch ($engine) {
        case "asterisk":
            // setup for intercom
            $fcc = new featurecode('paging', 'intercom-prefix');
            $intercom_code = $fcc->getCodeActive();
            unset($fcc);
            // Since these are going down channel local, set ALERT_INFO and SIPADDHEADER which will be set in dialparties.agi
            // no point in even setting the headers here they will get lost in channel local
            //
            /* Set these up once here and in intercom so that autoanswer macro does not have
             * to go through this for every single extension which causes a lot of extra overhead
             * with big page groups
             */
            $has_answermacro = false;
            $alertinfo = 'Ring Answer';
            $callinfo = '<uri>\\;answer-after=0';
            $sipuri = 'intercom=true';
            $doptions = 'A(beep)b(autoanswer^s^1(${ALERTINFO},${CALLINFO}))';
            $vxml_url = '';
            $dtime = '5';
            $custom_vars = array();
            $autoanswer_arr = paging_get_autoanswer_defaults();
            foreach ($autoanswer_arr as $autosetting) {
                switch (trim($autosetting['var'])) {
                    case 'ALERTINFO':
                        $alertinfo = trim($autosetting['setting']);
                        break;
                    case 'CALLINFO':
                        $callinfo = trim($autosetting['setting']);
                        break;
                    case 'SIPURI':
                        $sipuri = trim($autosetting['setting']);
                        break;
                    case 'VXML_URL':
                        $vxml_url = trim($autosetting['setting']);
                        break;
                    case 'DOPTIONS':
                        $doptions = trim($autosetting['setting']);
                        break;
                    case 'DTIME':
                        $dtime = trim($autosetting['setting']);
                        break;
                    default:
                        $key = trim($autosetting['var']);
                        $custom_vars[$key] = trim($autosetting['setting']);
                        if (ltrim($custom_vars[$key], '_') == "ANSWERMACRO") {
                            $has_answermacro = true;
                        }
                        break;
                }
            }
            $apppaging = 'app-paging';
            if (!empty($intercom_code)) {
                $code = '_' . $intercom_code . '.';
                $context = 'ext-intercom';
                // Add for languages
                $ext->add($context, 'lang-playback', '', new ext_gosubif('$[${DIALPLAN_EXISTS(' . $context . ',${CHANNEL(language)})}]', $context . ',${CHANNEL(language)},${ARG1}', $context . ',en,${ARG1}'));
                $ext->add($context, 'lang-playback', '', new ext_return());
                $ext->add($context, $code, '', new ext_macro('user-callerid'));
                $ext->add($context, $code, '', new ext_setvar('dialnumber', '${EXTEN:' . strlen($intercom_code) . '}'));
                $ext->add($context, $code, '', new ext_setvar('INTERCOM_CALL', 'TRUE'));
                $ext->add($context, $code, '', new ext_gosub('1', 's', 'sub-record-check', 'exten,${dialnumber}'));
                $ext->add($context, $code, '', new ext_gotoif('$["${DB(AMPUSER/${AMPUSER}/intercom/block)}" = "blocked"]', 'end'));
                $ext->add($context, $code, '', new ext_gotoif('$["${DB(DND/${dialnumber})}" = "YES"]', 'end'));
                $ext->add($context, $code, '', new ext_gotoif('$["${DB(AMPUSER/${dialnumber}/intercom/${AMPUSER})}" = "allow" ]', 'allow'));
                $ext->add($context, $code, '', new ext_gotoif('$["${DB(AMPUSER/${dialnumber}/intercom/${AMPUSER})}" = "deny" ]', 'nointercom'));
                $ext->add($context, $code, '', new ext_gotoif('$["${DB(AMPUSER/${dialnumber}/intercom)}" = "disabled" ]', 'nointercom'));
                $ext->add($context, $code, 'allow', new ext_dbget('DEVICES', 'AMPUSER/${dialnumber}/device'));
                $ext->add($context, $code, '', new ext_gotoif('$["${DEVICES}" = "" ]', 'end'));
                $ext->add($context, $code, '', new ext_dbget('OVERRIDE', 'AMPUSER/${dialnumber}/intercom/override'));
                $ext->add($context, $code, '', new ext_setvar('LOOPCNT', '${FIELDQTY(DEVICES,&)}'));
                /* Set these up so that macro-autoanswer doesn't have to
                 */
                $ext->add($context, $code, '', new ext_setvar('_SIPURI', ''));
                if (trim($alertinfo) != "") {
                    $ext->add($context, $code, '', new ext_setvar('_ALERTINFO', $alertinfo));
                }
                if (trim($callinfo) != "") {
                    $ext->add($context, $code, '', new ext_setvar('_CALLINFO', $callinfo));
                }
                if (trim($sipuri) != "") {
                    $ext->add($context, $code, '', new ext_setvar('_SIPURI', $sipuri));
                }
                if (trim($vxml_url) != "") {
                    $ext->add($context, $code, '', new ext_setvar('_VXML_URL', $vxml_url));
                }
                foreach ($custom_vars as $key => $value) {
                    $ext->add($context, $code, '', new ext_setvar('_' . ltrim($key, '_'), $value));
                }
                $ext->add($context, $code, '', new ext_setvar('_DTIME', $dtime));
                $ext->add($context, $code, '', new ext_setvar('_ANSWERMACRO', ''));
                $ext->add($context, $code, '', new ext_gotoif('$[${LOOPCNT} > 1 ]', 'pagemode'));
                $ext->add($context, $code, '', new ext_macro('autoanswer', '${DEVICES}'));
                $ext->add($context, $code, '', new ext_setvar('_DOPTIONS', $doptions));
                $ext->add($context, $code, 'check', new ext_chanisavail('${DEVICE}', 's'));
                // If it's ringing for an inbound call, we should page.
                $ext->add($context, $code, '', new ext_execif('$["${AVAILSTATUS}" = "6"]', 'Set', 'AVAILORIGCHAN=${DEVICE}'));
                // Did we have a device we can page? If so, go to continue. If not, check for
                // paging override functions.
                $ext->add($context, $code, '', new ext_gotoif('$["${AVAILORIGCHAN}" != ""]', 'continue'));
                // Check the intercom override.
                $ext->add($context, $code, '', new ext_execif('$["${OVERRIDE}" = ""]', 'Set', 'OVERRIDE=reject'));
                $ext->add($context, $code, '', new ext_gotoif('$["${OVERRIDE}" = "reject"]', 'end'));
                // We don't know what the phones are going to do. Let's be generous.
                $ext->add($context, $code, '', new ext_set('DTIME', '30'));
                // If it's ring, treat it as a normal call.
                $ext->add($context, $code, '', new ext_execif('$["${OVERRIDE}" = "ring"]', 'Set', 'DOPTIONS=A(beep)'));
                // It's something else. Assume it's force, and just smash the device.
                $ext->add($context, $code, 'continue', new ext_noop('Continuing with page', 5));
                $len = strlen($code) - 2;
                $dopt = 'I';
                // Don't sent connectedline updates.
                $ext->add($context, $code, '', new ext_gotoif('$["${DB(AMPUSER/${EXTEN:' . $len . '}/cidname)}" = ""]', 'godial'));
                $ext->add($context, $code, '', new ext_set('CONNECTEDLINE(name,i)', '${DB(AMPUSER/${EXTEN:' . $len . '}/cidname)}'));
                $ext->add($context, $code, '', new ext_set('CONNECTEDLINE(num)', '${EXTEN:' . $len . '}'));
                $ext->add($context, $code, 'godial', new ext_dial('${DIAL}', '${DTIME},' . $dopt . '${DOPTIONS}${INTERCOM_EXT_DOPTIONS}'));
                $ext->add($context, $code, 'end', new ext_execif('$[${INTERCOM_RETURN}]', 'Return'));
                $ext->add($context, $code, '', new ext_busy());
                $ext->add($context, $code, '', new ext_macro('hangupcall'));
                $ext->add($context, $code, 'pagemode', new ext_setvar('ITER', '1'));
                $ext->add($context, $code, '', new ext_setvar('DIALSTR', ''));
                $ds = $amp_conf['ASTCONFAPP'] == 'app_confbridge' ? '${DIALSTR}-${CUT(DEVICES,&,${ITER})}' : '${DIALSTR}&LOCAL/PAGE${CUT(DEVICES,&,${ITER})}@' . $apppaging;
                $ext->add($context, $code, 'begin', new ext_chanisavail('${DB(DEVICE/${CUT(DEVICES,&,${ITER})}/dial)}', 's'));
                $ext->add($context, $code, '', new ext_gotoif('$["${AVAILORIGCHAN}" = ""]', 'skip'));
                $ext->add($context, $code, '', new ext_setvar('DIALSTR', $ds));
                $ext->add($context, $code, 'skip', new ext_setvar('ITER', '$[${ITER} + 1]'));
                $ext->add($context, $code, '', new ext_gotoif('$[${ITER} <= ${LOOPCNT}]', 'begin'));
                $ext->add($context, $code, '', new ext_setvar('DIALSTR', '${DIALSTR:1}'));
                $ext->add($context, $code, '', new ext_gotoif('$["${DIALSTR}" = ""]', 'end2'));
                $ext->add($context, $code, '', new ext_setvar('_AMPUSER', '${AMPUSER}'));
                if ($amp_conf['ASTCONFAPP'] == 'app_confbridge') {
                    $ext->add($context, $code, '', new ext_gosub('1', 'page', false, '${DIALSTR}'));
                } else {
                    $ext->add($context, $code, '', new ext_page('${DIALSTR},d'));
                }
                $ext->add($context, $code, 'end2', new ext_execif('$[${INTERCOM_RETURN}]', 'Return'));
                $ext->add($context, $code, '', new ext_busy());
                $ext->add($context, $code, '', new ext_macro('hangupcall'));
                $ext->add($context, $code, 'nointercom', new ext_noop('Intercom disallowed by ${dialnumber}'));
                $ext->add($context, $code, '', new ext_execif('$[${INTERCOM_RETURN}]', 'Return'));
                $ext->add($context, $code, '', new ext_gosub('1', 'lang-playback', $context, 'hook_0'));
                $ext->add($context, $code, '', new ext_congestion());
                if ($amp_conf['ASTCONFAPP'] == 'app_confbridge') {
                    $sub = 'page';
                    $ext->add($context, $sub, '', new ext_set('PAGE_CONF', '${EPOCH}${RAND(100,999)}'));
                    $ext->add($context, $sub, '', new ext_set('PAGEMODE', 'PAGE'));
                    $ext->add($context, $sub, '', new ext_set('PAGE_MEMBERS', '${ARG1}'));
                    $ext->add($context, $sub, '', new ext_set('PAGE_CONF_OPTS', 'duplex'));
                    $ext->add($context, $sub, '', new ext_agi('page.agi'));
                    $ext->add($context, $sub, '', new ext_set('CONFBRIDGE(user,template)', 'page_user_duplex'));
                    $ext->add($context, $sub, '', new ext_set('CONFBRIDGE(user,admin)', 'yes'));
                    $ext->add($context, $sub, '', new ext_set('CONFBRIDGE(user,marked)', 'yes'));
                    $ext->add($context, $sub, '', new ext_meetme('${PAGE_CONF}', ',', 'admin_menu'));
                    $ext->add($context, $sub, '', new ext_hangup());
                }
                $lang = 'en';
                // English
                $ext->add($context, $lang, 'hook_0', new ext_playback('intercom&for&extension'));
                $ext->add($context, $lang, '', new ext_saydigits('${dialnumber}'));
                $ext->add($context, $lang, '', new ext_playback('is&disabled'));
                $ext->add($context, $lang, '', new ext_return());
                $lang = 'ja';
                // Japanese
                $ext->add($context, $lang, 'hook_0', new ext_playback('extension'));
                $ext->add($context, $lang, '', new ext_saydigits('${dialnumber}'));
                $ext->add($context, $lang, '', new ext_playback('jp-no&intercom&jp-wa&disabled-2'));
                $ext->add($context, $lang, '', new ext_return());
                $extintercomusers = 'ext-intercom-users';
                $sql = "SELECT LENGTH(id) as len FROM devices GROUP BY len";
                $sth = FreePBX::Database()->prepare($sql);
                $sth->execute();
                $rows = $sth->fetchAll(\PDO::FETCH_ASSOC);
                foreach ($rows as $row) {
                    $ext->add($extintercomusers, '_' . $intercom_code . str_repeat('X', $row['len']), '', new ext_goto($context . ',${EXTEN},1'));
                }
                $context = $extintercomusers;
                // for language handling which is done on a per context basis
                $ext->add($context, 'lang-playback', '', new ext_gosubif('$[${DIALPLAN_EXISTS(' . $context . ',${CHANNEL(language)})}]', $context . ',${CHANNEL(language)},${ARG1}', $context . ',en,${ARG1}'));
                $ext->add($context, 'lang-playback', '', new ext_return());
                $ext->addInclude('from-internal-additional', $context);
            }
            $fcc = new featurecode('paging', 'intercom-on');
            $oncode = $fcc->getCodeActive();
            unset($fcc);
            if ($oncode) {
                $ext->add($context, $oncode, '', new ext_macro('user-callerid'));
                $ext->add($context, $oncode, '', new ext_set('CONNECTEDLINE(name-charset,i)', 'utf8'));
                $ext->add($context, $oncode, '', new ext_set('CONNECTEDLINE(name,i)', _("Intercom: Enabled")));
                $ext->add($context, $oncode, '', new ext_set('CONNECTEDLINE(num,i)', '${AMPUSER}'));
                $ext->add($context, $oncode, '', new ext_answer(''));
                $ext->add($context, $oncode, '', new ext_wait('1'));
                $ext->add($context, $oncode, '', new ext_setvar('DB(AMPUSER/${AMPUSER}/intercom)', 'enabled'));
                $ext->add($context, $oncode, '', new ext_playback('intercom&enabled'));
                $ext->add($context, $oncode, '', new ext_macro('hangupcall'));
                $target = '${EXTEN:' . strlen($oncode) . '}';
                $oncode = "_" . $oncode . ".";
                $ext->add($context, $oncode, '', new ext_macro('user-callerid'));
                $ext->add($context, $oncode, '', new ext_set('CONNECTEDLINE(name-charset,i)', 'utf8'));
                $ext->add($context, $oncode, '', new ext_set('CONNECTEDLINE(name,i)', sprintf(_("Intercom from %s: Enabled"), $target)));
                $ext->add($context, $oncode, '', new ext_set('CONNECTEDLINE(num,i)', '${AMPUSER}'));
                $ext->add($context, $oncode, '', new ext_setvar('dialnumber', '${EVAL(${EXTEN:' . strlen(substr($oncode, 1, -1)) . '})}'));
                // Asterisk variable for saydigits languages
                $ext->add($context, $oncode, '', new ext_answer(''));
                $ext->add($context, $oncode, '', new ext_wait('1'));
                $ext->add($context, $oncode, '', new ext_gotoif('$["${DB(AMPUSER/${AMPUSER}/intercom/' . $target . ')}" = "allow" ]}', 'unset'));
                $ext->add($context, $oncode, '', new ext_gotoif('$[${DB_EXISTS(AMPUSER/' . $target . '/device)} != 1]', 'invaliduser'));
                $ext->add($context, $oncode, '', new ext_dbput('AMPUSER/${AMPUSER}/intercom/' . $target, 'allow'));
                $ext->add($context, $oncode, '', new ext_gosub('1', 'lang-playback', $context, 'hook_1'));
                $ext->add($context, $oncode, '', new ext_macro('hangupcall'));
                $ext->add($context, $oncode, 'unset', new ext_dbdeltree('AMPUSER/${AMPUSER}/intercom/' . $target));
                $ext->add($context, $oncode, '', new ext_gosub('1', 'lang-playback', $context, 'hook_2'));
                $ext->add($context, $oncode, '', new ext_macro('hangupcall'));
                $ext->add($context, $oncode, 'invaliduser', new ext_gosub('1', 'lang-playback', $context, 'hook_3'));
                $ext->add($context, $oncode, '', new ext_macro('hangupcall'));
                $lang = 'en';
                // English
                $ext->add($context, $lang, 'hook_1', new ext_playback('intercom&from&extension&number'));
                $ext->add($context, $lang, '', new ext_saydigits('${dialnumber}'));
                $ext->add($context, $lang, '', new ext_playback('enabled'));
                $ext->add($context, $lang, '', new ext_return());
                $ext->add($context, $lang, 'hook_2', new ext_playback('intercom&enabled&cancelled&for&extension&number'));
                $ext->add($context, $lang, '', new ext_saydigits('${dialnumber}'));
                $ext->add($context, $lang, '', new ext_return());
                $ext->add($context, $lang, 'hook_3', new ext_playback('extension&number'));
                $ext->add($context, $lang, '', new ext_saydigits('${dialnumber}'));
                $ext->add($context, $lang, '', new ext_playback('invalid'));
                $ext->add($context, $lang, '', new ext_return());
                $lang = 'ja';
                // Japanese
                $ext->add($context, $lang, 'hook_1', new ext_playback('extension'));
                $ext->add($context, $lang, '', new ext_saydigits('${dialnumber}'));
                $ext->add($context, $lang, '', new ext_playback('jp-kara&jp-no&intercom&jp-wo&allow'));
                $ext->add($context, $lang, '', new ext_return());
                $ext->add($context, $lang, 'hook_2', new ext_playback('extension'));
                $ext->add($context, $lang, '', new ext_saydigits('${dialnumber}'));
                $ext->add($context, $lang, '', new ext_playback('jp-kara&jp-no&intercom&setting&jp-wo&cancelled'));
                $ext->add($context, $lang, '', new ext_return());
                $ext->add($context, $lang, 'hook_3', new ext_playback('extension'));
                $ext->add($context, $lang, '', new ext_saydigits('${dialnumber}'));
                $ext->add($context, $lang, '', new ext_playback('invalid'));
                $ext->add($context, $lang, '', new ext_return());
            }
            $fcc = new featurecode('paging', 'intercom-off');
            $offcode = $fcc->getCodeActive();
            unset($fcc);
            if ($offcode) {
                $ext->add($context, $offcode, '', new ext_macro('user-callerid'));
                $ext->add($context, $offcode, '', new ext_set('CONNECTEDLINE(name-charset,i)', 'utf8'));
                $ext->add($context, $offcode, '', new ext_set('CONNECTEDLINE(name,i)', _("Intercom: Disabled")));
                $ext->add($context, $offcode, '', new ext_set('CONNECTEDLINE(num,i)', '${AMPUSER}'));
                $ext->add($context, $offcode, '', new ext_answer(''));
                $ext->add($context, $offcode, '', new ext_wait('1'));
                $ext->add($context, $offcode, '', new ext_setvar('DB(AMPUSER/${AMPUSER}/intercom)', 'disabled'));
                $ext->add($context, $offcode, '', new ext_playback('intercom&disabled'));
                $ext->add($context, $offcode, '', new ext_macro('hangupcall'));
                $target = '${EXTEN:' . strlen($offcode) . '}';
                $offcode = "_" . $offcode . ".";
                $ext->add($context, $offcode, '', new ext_macro('user-callerid'));
                $ext->add($context, $offcode, '', new ext_set('CONNECTEDLINE(name-charset,i)', 'utf8'));
                $ext->add($context, $offcode, '', new ext_set('CONNECTEDLINE(name,i)', sprintf(_("Intercom from %s: Disabled"), $target)));
                $ext->add($context, $offcode, '', new ext_set('CONNECTEDLINE(num,i)', '${AMPUSER}'));
                $ext->add($context, $offcode, '', new ext_setvar('dialnumber', '${EVAL(${EXTEN:' . strlen(substr($offcode, 1, -1)) . '})}'));
                // Asterisk variable for saydigits languages
                $ext->add($context, $offcode, '', new ext_answer(''));
                $ext->add($context, $offcode, '', new ext_wait('1'));
                $ext->add($context, $offcode, '', new ext_gotoif('$["${DB(AMPUSER/${AMPUSER}/intercom/' . $target . ')}" = "deny" ]}', 'unset2'));
                $ext->add($context, $offcode, '', new ext_gotoif('$[${DB_EXISTS(AMPUSER/' . $target . '/device)} != 1]', 'invaliduser2'));
                $ext->add($context, $offcode, '', new ext_dbput('AMPUSER/${AMPUSER}/intercom/' . $target, 'deny'));
                $ext->add($context, $offcode, '', new ext_gosub('1', 'lang-playback', $context, 'hook_4'));
                $ext->add($context, $offcode, '', new ext_macro('hangupcall'));
                $ext->add($context, $offcode, 'unset2', new ext_dbdeltree('AMPUSER/${AMPUSER}/intercom/' . $target));
                $ext->add($context, $offcode, '', new ext_gosub('1', 'lang-playback', $context, 'hook_5'));
                $ext->add($context, $offcode, '', new ext_macro('hangupcall'));
                $ext->add($context, $offcode, 'invaliduser2', new ext_gosub('1', 'lang-playback', $context, 'hook_6'));
                $ext->add($context, $offcode, '', new ext_macro('hangupcall'));
                $lang = 'en';
                $ext->add($context, $lang, 'hook_4', new ext_playback('intercom&from&extension&number'));
                $ext->add($context, $lang, '', new ext_saydigits('${dialnumber}'));
                $ext->add($context, $lang, '', new ext_playback('disabled'));
                $ext->add($context, $lang, '', new ext_return());
                $ext->add($context, $lang, 'hook_5', new ext_playback('intercom&disabled&cancelled&for&extension&number'));
                $ext->add($context, $lang, '', new ext_saydigits('${dialnumber}'));
                $ext->add($context, $lang, '', new ext_return());
                $ext->add($context, $lang, 'hook_6', new ext_playback('extension&number'));
                $ext->add($context, $lang, '', new ext_saydigits('${dialnumber}'));
                $ext->add($context, $lang, '', new ext_playback('invalid'));
                $ext->add($context, $lang, '', new ext_return());
                $lang = 'ja';
                $ext->add($context, $lang, 'hook_4', new ext_playback('extension'));
                $ext->add($context, $lang, '', new ext_saydigits('${dialnumber}'));
                $ext->add($context, $lang, '', new ext_playback('jp-kara&jp-no&intercom&jp-wo&deny'));
                $ext->add($context, $lang, '', new ext_return());
                $ext->add($context, $lang, 'hook_5', new ext_playback('extension'));
                $ext->add($context, $lang, '', new ext_saydigits('${dialnumber}'));
                $ext->add($context, $lang, '', new ext_playback('jp-kara&jp-no&intercom&setting&jp-wo&cancelled'));
                $ext->add($context, $lang, '', new ext_return());
                $ext->add($context, $lang, 'hook_6', new ext_playback('extension'));
                $ext->add($context, $lang, '', new ext_saydigits('${dialnumber}'));
                $ext->add($context, $lang, '', new ext_playback('invalid'));
                $ext->add($context, $lang, '', new ext_return());
            }
            /* Create macro-autoanswer that will try to intelligently set the
            			required parameters to handle paging. Eventually it will use
            				known device information.
            
            				This macro does the following:
            
            				Input:  FreePBX Device number to be called requiring autoanswer
            				Output: ${DIAL} Channel Variable with the dial string to be called
            						Appropriate SIP headers added
            								Other special requirements that may be custom for this device
            
            				1. Set ${DIAL} to the device's dial string
            				2. If there is a device specific macro defined in the DEVICE's object
            				   (DEVICE/<devicenum>/autoanswer/macro) then execute that macro and end
            				3. Try to identify endpoints by their useragents that may need known
            				   changes and make those changes. These are generated from the
            					 paging_autoanswer table so users can extend them, if any are present
            				5. Set the variables and end unless a useragent specific ANSWERMACRO is
            				   defined in which case call it and end.
            
            				This macro is called for intercoming and paging to try and enable the
            				target device to auto-answer. Devices with special needs can be handled
            				with the device specific macro. For example, if you have a device that
            				can not auto-answer except by specifically configuring a line key on
            				the device that always answers, you could use a device specific macro
            				to change the dialstring. If you had a set of such devices, you could
            				standardize on the device numbers (e.g. nnnn for normal calls and 2nnnn
            				for auto-answer calls). You could then create a general purpose macro
            				to modify the dial string accordingly. Provisioning tools will be able
            				to take advantage of setting and creating such an ability.
            				If you have a set of devices that can be identified with a SIP useragent
            				then you can use a general macro without setting info in each device.
            			 */
            $autoanswer_arr = paging_get_autoanswer_useragents();
            $macro = 'macro-autoanswer';
            // Do we already know what the correct string is? This may have been handed to us
            // by page.agi.
            $ext->add($macro, "s", '', new ext_gotoif('$["${KNOWNDIAL}" != ""]', 'knowndial'));
            // Do we have a PJSIP Endpoint?
            $ext->add($macro, "s", '', new ext_setvar('DEVICE', '${DB(DEVICE/${ARG1}/dial)}'));
            $ext->add($macro, "s", '', new ext_gotoif('$["${DEVICE:0:5}" == "PJSIP" ]', 'dopjsip'));
            // We're not pjsip, so our dial is going to be our device
            $ext->add($macro, "s", '', new ext_setvar('KNOWNDIAL', '${DEVICE}'));
            $ext->add($macro, "s", '', new ext_goto('knowndial'));
            // Handle PJSIP stuff.
            $ext->add($macro, "s", 'dopjsip', new ext_setvar('KNOWNDIAL', '${PJSIP_DIAL_CONTACTS(${ARG1})}'));
            // If there's an ampersand, there's more than one device registered to this endpoint, and we
            // need to page, rather than intercom.
            $ext->add($macro, "s", '', new ext_gotoif('$[${REGEX("&" ${KNOWNDIAL})} == 0]', 'knowndial'));
            // Bugger. However, we can hard-code some settings here that'll make our life a bit easier.
            $ext->add($macro, "s", '', new ext_gosub('1', 'ssetup', 'app-paging'));
            $ext->add($macro, "s", '', new ext_setvar('PAGEMODE', 'PAGE'));
            $ext->add($macro, "s", '', new ext_setvar('PAGE_CONF_OPTS', 'duplex'));
            $ext->add($macro, "s", '', new ext_setvar('STREAM', 'NONE'));
            $ext->add($macro, "s", '', new ext_setvar('PAGE_MEMBERS', '${ARG1}'));
            // Start the AGI to get the clients into the conf
            $ext->add($macro, "s", '', new ext_agi('page.agi'));
            // Now I need to join the conf as admin.
            $ext->add($macro, "s", '', new ext_set('CONFBRIDGE(user,template)', 'page_user_duplex'));
            $ext->add($macro, "s", '', new ext_set('CONFBRIDGE(user,admin)', 'yes'));
            $ext->add($macro, "s", '', new ext_set('CONFBRIDGE(user,marked)', 'yes'));
            $ext->add($macro, "s", '', new ext_meetme('${PAGE_CONF}', ',', 'admin_menu'));
            // ext_confbridge, actually.
            $ext->add($macro, "s", '', new ext_hangup());
            // Don't even try to continue after this.
            // Right. Bypassing all that, it's a single device, and, we know what our dial string is.
            $ext->add($macro, "s", 'knowndial', new ext_setvar('DIAL', '${KNOWNDIAL}'));
            // If we are in DAHDI compat mode, then we need to substitute DAHDI for ZAP
            if ($chan_dahdi) {
                $ext->add($macro, "s", '', new ext_execif('$["${DIAL:0:3}" = "ZAP"]', 'Set', 'DIAL=DAHDI${DIAL:3}'));
            }
            $ext->add($macro, "s", '', new ext_gotoif('$["${DB(DEVICE/${ARG1}/autoanswer/macro)}" != "" ]', 'macro'));
            // If there are no phone specific auto-answer vars, then we don't care what the phone is below
            //
            if (!empty($autoanswer_arr)) {
                global $version;
                $ext->add($macro, "s", '', new ext_gotoif('$["${DIAL:0:5}" = "PJSIP"]', 'pjsipua'));
                //http://issues.freepbx.org/browse/FREEPBX-7715
                if (version_compare($version, "12", "<")) {
                    $ext->add($macro, "s", '', new ext_setvar('USERAGENT', '${SIPPEER(${CUT(DIAL,/,2)}:useragent)}'));
                } else {
                    $ext->add($macro, "s", '', new ext_setvar('USERAGENT', '${SIPPEER(${CUT(DIAL,/,2)},useragent)}'));
                }
                $ext->add($macro, "s", '', new ext_goto('uafin'));
                $ext->add($macro, "s", 'pjsipua', new ext_setvar('AOR', '${CUT(DIAL,/,2)}'));
                $ext->add($macro, "s", '', new ext_setvar('CONTACT', '${PJSIP_AOR(${AOR},contact)}'));
                $ext->add($macro, "s", '', new ext_setvar('USERAGENT', '${PJSIP_CONTACT(${CONTACT},user_agent)}'));
                $ext->add($macro, "s", 'uafin', new ext_execif('$["${KNOWNAGENT}" != ""]', 'Set', 'USERAGENT=${KNOWNAGENT}'));
            }
            // We used to set all the variables here (ALERTINFO, CALLINFO, etc. That has been moved to each
            // paging group and the intercom main macro, since it was redundant for every phone causing a lot
            // of overhead with large page groups.
            //
            // Defaults are setup, now make specific adjustments for detected phones
            // These come from the SQL table as well where installations can make customizations
            //
            foreach ($autoanswer_arr as $autosetting) {
                $useragent = trim($autosetting['useragent']);
                $autovar = trim($autosetting['var']);
                $data = trim($autosetting['setting']);
                switch (ltrim($autovar, '_')) {
                    case 'ANSWERMACRO':
                        $has_answermacro = true;
                        // fall through - no break on purpose
                    // fall through - no break on purpose
                    case 'ALERTINFO':
                    case 'CALLINFO':
                    case 'SIPURI':
                    case 'VXML_URL':
                    case 'DOPTIONS':
                    case 'DTIME':
                    default:
                        if (trim($data) != "") {
                            $ext->add($macro, "s", '', new ext_execif('$["${USERAGENT:0:' . strlen($useragent) . '}" = "' . $useragent . '"]', 'Set', $autovar . '=' . $data));
                        }
                        break;
                }
            }
            // Now any adjustments have been made, set the headers and done
            //
            if ($has_answermacro) {
                $ext->add($macro, "s", '', new ext_gotoif('$["${ANSWERMACRO}" != ""]', 'macro2'));
            }
            $ext->add($macro, "s", '', new ext_execif('$["${SIPURI}" != ""]', 'Set', '__SIP_URI_OPTIONS=${SIPURI}'));
            $ext->add($macro, "s", 'macro', new ext_macro('${DB(DEVICE/${ARG1}/autoanswer/macro)}', '${ARG1}'), 'n', 2);
            if ($has_answermacro) {
                $ext->add($macro, "s", 'macro2', new ext_macro('${ANSWERMACRO}', '${ARG1}'), 'n', 2);
            }
            //auto answer stuff
            //set autoanswer variables
            if (!empty($custom_vars)) {
                foreach ($custom_vars as $key => $value) {
                    $ext->add($apppaging, '_AUTOASWER.', '', new ext_setvar('_' . ltrim($key, '_'), $value));
                }
                $ext->add($apppaging, '_AUTOASWER.', '', new ext_macro('autoanswer', '${EXTEN:9}'));
                $ext->add($apppaging, '_AUTOASWER.', '', new ext_return());
            }
            // Macro to apply SIP Headers to channel.
            //   function ext_gosubif($condition, $true_priority, $false_priority = false, $true_args = '', $false_args = '') {
            //
            $ext->add("autoanswer", "s", '', new ext_gosubif('$["${ARG1}" != ""]', 'func-set-sipheader,s,1', false, 'Alert-Info,${ARG1}'));
            $ext->add("autoanswer", "s", '', new ext_gosubif('$["${ARG2}" != ""]', 'func-set-sipheader,s,1', false, 'Call-Info,${ARG2}'));
            $ext->add("autoanswer", "s", '', new ext_gosub('func-apply-sipheaders,s,1'));
            $ext->add("autoanswer", "s", '', new ext_return());
            // Setup Variables before AGI script
            //
            $ext->add($apppaging, 'ssetup', '', new ext_set('_SIPURI', ''));
            if (isset($alertinfo) && trim($alertinfo) != "") {
                $ext->add($apppaging, 'ssetup', '', new ext_set('_ALERTINFO', $alertinfo));
            }
            if (isset($callinfo) && trim($callinfo) != "") {
                $ext->add($apppaging, 'ssetup', '', new ext_set('_CALLINFO', $callinfo));
            }
            if (isset($sipuri) && trim($sipuri) != "") {
                $ext->add($apppaging, 'ssetup', '', new ext_set('_SIPURI', $sipuri));
            }
            if (isset($vxml_url) && trim($vxml_url) != "") {
                $ext->add($apppaging, 'ssetup', '', new ext_set('_VXML_URL', $vxml_url));
            }
            $ext->add($apppaging, 'ssetup', '', new ext_set('_DTIME', $dtime));
            $ext->add($apppaging, 'ssetup', '', new ext_set('_ANSWERMACRO', ''));
            $page_opts = $amp_conf['ASTCONFAPP'] == 'app_confbridge' ? '1qs' : '1dqsx';
            $ext->add($apppaging, 'ssetup', '', new ext_set('PAGE_CONF', '${EPOCH}${RAND(100,999)}'));
            $ext->add($apppaging, 'ssetup', '', new ext_return());
            // Normal page version (now used for Force also)
            // If we had any custom_vars then call the AUTOASWER subroutine first, otherwise go
            // straight to macro-autoanswer
            if (!empty($custom_vars)) {
                $ext->add($apppaging, "_PAGE.", 'SKIPCHECK', new ext_gosub('AUTOASWER${EXTEN:4},1'));
            } else {
                $ext->add($apppaging, "_PAGE.", 'SKIPCHECK', new ext_macro('autoanswer', '${EXTEN:4}'));
            }
            $ext->add($apppaging, "_PAGE.", '', new ext_noop('${EXTRINGTIME}'));
            $ext->add($apppaging, "_PAGE.", '', new ext_gotoif('$["${EXTRINGTIME}" != "true"]', 'doptions'));
            $ext->add($apppaging, "_PAGE.", '', new ext_set('_DTIME', '${RINGTIMER_DEFAULT}'));
            $ext->add($apppaging, "_PAGE.", '', new ext_execif('$["${DB(AMPUSER/${EXTEN:4}/ringtimer)}" != "" & ${DB(AMPUSER/${EXTEN:4}/ringtimer)} > 0]', 'Set', '_DTIME=${DB(AMPUSER/${EXTEN:4}/ringtimer)}'));
            //strip the global Announcement out of doptions (We use our announcement variable lower --V)
            $doptions2 = preg_replace("/A\\([^\\)]*\\)/", "", $doptions);
            $ext->add($apppaging, "_PAGE.", 'doptions', new ext_execif('$["${DOPTIONS}" = ""]', 'Set', '_DOPTIONS=' . $doptions2));
            $ext->add($apppaging, "_PAGE.", '', new ext_dial('${DIAL}', '${DTIME},A(${ANNOUNCEMENT})${DOPTIONS}'));
            $ext->add($apppaging, "_PAGE.", 'skipself', new ext_hangup());
            // Try ChanSpy Version
            $ext->add($apppaging, "_SPAGE.", 'chanspy', new ext_chanspy('${SP_DEVICE}-', 'qW'));
            $ext->add($apppaging, "_SPAGE.", '', new ext_hangup());
            // If Asterisk 10 and app_confbridge:
            //
            // Common to admin:
            //  d: dynamically addd conf
            //  o: talker optimization (don't mix non-talkers)
            //  q: quiet mode no enter/leave sounds
            //  x: close conf when last marked user exits
            //
            // Not in Admin:
            //  1: ???
            //  s: present menu
            //See http://issues.freepbx.org/browse/FREEPBX-8796
            //before you even think about removing this to after checking for a page group!
            if ($amp_conf['ASTCONFAPP'] == 'app_confbridge' && isset($conferences_conf) && is_a($conferences_conf, "conferences_conf")) {
                $pu = 'page_user';
                $pud = 'page_user_duplex';
                foreach (array($pu, $pud) as $u) {
                    $conferences_conf->addConfUser($u, 'quiet', 'yes');
                    $conferences_conf->addConfUser($u, 'announce_user_count', 'no');
                    $conferences_conf->addConfUser($u, 'wait_marked', 'yes');
                    $conferences_conf->addConfUser($u, 'end_marked', 'yes');
                    $dds = \FreePBX::Paging()->getDropSilence() ? 'yes' : 'no';
                    $conferences_conf->addConfUser($u, 'dsp_drop_silence', $dds);
                    $conferences_conf->addConfUser($u, 'announce_join_leave', 'no');
                    $conferences_conf->addConfUser($u, 'admin', 'no');
                    $conferences_conf->addConfUser($u, 'marked', 'no');
                }
                $conferences_conf->addConfUser($pu, 'startmuted', 'yes');
            }
            //page playback
            $c = 'app-page-stream';
            $ext->add($c, 's', '', new ext_wait(1));
            $ext->add($c, 's', '', new ext_answer());
            // TODO: PAGE_CONF_OPTS reset in agi script so just use proper context if 10+confbridge no mute
            // x: close conf when last marked user exits
            // q: quiet mode no enter/leave sounds
            //
            // TODO: Ideally what we want is to mark the stream and wait for that, if no stream then no wait for makred user. However
            //       it seems like to end a conference you have to have the kick after last marked user since there doesn't have to be
            //       an admin as far as I can tell.
            //
            //
            if ($amp_conf['ASTCONFAPP'] == 'app_confbridge') {
                $ext->add($c, 's', '', new ext_set('CONFBRIDGE(user,template)', $pud));
                $ext->add($c, 's', '', new ext_set('CONFBRIDGE(user,marked)', 'yes'));
                $ext->add($c, 's', '', new ext_meetme('${PAGE_CONF}', '', ''));
            } else {
                $ext->add($c, 's', '', new ext_meetme('${PAGE_CONF}', '${PAGE_CONF_OPTS}'));
            }
            $ext->add($c, 's', '', new ext_hangup());
            $apppagegroups = 'app-pagegroups';
            // Now get a list of all the paging groups...
            $sql = "SELECT page_group, force_page, duplex, announcement FROM paging_config";
            $paging_groups = $db->getAll($sql, DB_FETCHMODE_ASSOC);
            if (!$paging_groups) {
                break;
                //no need to continue if we dont have any pagegroups
            }
            $extpaging = 'ext-paging';
            if (!empty($paging_groups)) {
                $ext->addInclude('from-internal-noxfer-additional', $extpaging);
            }
            foreach ($paging_groups as $thisgroup) {
                $grp = trim($thisgroup['page_group']);
                switch ($thisgroup['force_page']) {
                    case 1:
                        $pagemode = 'FPAGE';
                        break;
                    case 2:
                        $pagemode = 'SPAGE';
                        break;
                    case 0:
                    default:
                        $pagemode = 'PAGE';
                        break;
                }
                $sql = "SELECT ext FROM paging_groups WHERE page_number='{$grp}'";
                $all_exts = $db->getCol($sql);
                // Create the paging context that is used in the paging application for each phone to auto-answer
                //add ext-paging with goto's to our app-paging context and a hint for the page
                $ext->add($extpaging, $grp, '', new ext_goto($apppagegroups . ',' . $grp . ',1'));
                $ext->addHint($extpaging, $grp, 'Custom:PAGE' . $grp);
                //app-page dialplan
                $ext->add($apppagegroups, $grp, '', new ext_macro('user-callerid'));
                $ext->add($apppagegroups, $grp, '', new ext_set('_PAGEGROUP', $grp));
                //if page group it in use, goto to busy
                $ext->add($apppagegroups, $grp, 'busy-check', new ext_gotoif('$[${TRYLOCK(apppagegroups' . $grp . ')}]', '', 'busy'));
                //set blf to in use
                $ext->add($apppagegroups, $grp, 'devstate', new ext_setvar('DEVICE_STATE(Custom:PAGE' . $grp . ')', 'INUSE'));
                $ext->add($apppagegroups, $grp, '', new ext_gosub('1', 'ssetup', $apppaging));
                $ext->add($apppagegroups, $grp, '', new ext_set('PAGEMODE', $pagemode));
                $ext->add($apppagegroups, $grp, '', new ext_set('PAGE_MEMBERS', implode('-', $all_exts)));
                if ($amp_conf['ASTCONFAPP'] == 'app_confbridge') {
                    $ext->add($apppagegroups, $grp, '', new ext_set('PAGE_CONF_OPTS', $thisgroup['duplex'] ? 'duplex' : ''));
                } else {
                    $ext->add($apppagegroups, $grp, '', new ext_set('PAGE_CONF_OPTS', $page_opts . (!$thisgroup['duplex'] ? 'm' : '')));
                }
                //Default announcement is a beep
                $announcement = "beep";
                //extract our "global default announcement" from the doptions and set it to announcement
                if (preg_match("/A\\(([^\\)]*)\\)/", $doptions, $matches)) {
                    $announcement = isset($matches[1]) ? $matches[1] : "";
                }
                //get our individual page group announcement if set
                if (!empty($thisgroup['announcement'])) {
                    switch ($thisgroup['announcement']) {
                        case "beep":
                            $announcement = "beep";
                            break;
                        case "none":
                            $announcement = "";
                            break;
                        case "default":
                            //do nothing
                            break;
                        default:
                            if (function_exists('recordings_get_file')) {
                                $announcement = recordings_get_file($thisgroup['announcement']);
                            } else {
                                $announcement = "";
                            }
                            break;
                    }
                }
                $ext->add($apppagegroups, $grp, '', new ext_set('ANNOUNCEMENT', $announcement));
                $ext->add($apppagegroups, $grp, 'agi', new ext_agi('page.agi'));
                //we cant use originate from the dialplan as the dialplan command is not asynchronous
                //we would like to though...
                //this code here as a sign of hope -MB
                /*foreach ($page_members as $member) {
                				$ext->add($apppagegroups, $grp, 'page', new ext_originate($member,'app','meetme', '${PAGE_CONF}\,${PAGE_CONF_OPTS}'));
                		}*/
                // TODO this is the master so set appropriate
                //      This is what everyone else has: 1doqsx
                //      Common:
                //        d: dynamically addd conf
                //        o: talker optimization (don't mix non-talkers)
                //        q: quiet mode no enter/leave sounds
                //        x: close conf when last marked user exits
                //      Added:
                //      	w: W() wait until marked user enters conf
                //      	A: Set marked mode
                //      	G: G() Play an intro announcemend in conference
                //      Removed:
                //        1: ???
                //        s: present menu
                //
                //
                if ($amp_conf['ASTCONFAPP'] == 'app_confbridge') {
                    $ext->add($apppagegroups, $grp, '', new ext_set('CONFBRIDGE(user,template)', $pud));
                    $ext->add($apppagegroups, $grp, '', new ext_set('CONFBRIDGE(user,admin)', 'yes'));
                    $ext->add($apppagegroups, $grp, '', new ext_set('CONFBRIDGE(user,marked)', 'yes'));
                    // TODO: should I have no menu?
                    $ext->add($apppagegroups, $grp, '', new ext_answer(''));
                    $ext->add($apppagegroups, $grp, 'page', new ext_meetme('${PAGE_CONF}', ',', 'admin_menu'));
                } else {
                    $ext->add($apppagegroups, $grp, '', new ext_answer(''));
                    $ext->add($apppagegroups, $grp, 'page', new ext_meetme('${PAGE_CONF}', 'dqwxAG'));
                }
                $ext->add($apppagegroups, $grp, '', new ext_hangup());
                $ext->add($apppagegroups, $grp, 'busy', new ext_set('PAGE${PAGEGROUP}BUSY', 'TRUE'));
                $ext->add($apppagegroups, $grp, 'play-busy', new ext_busy(3));
                $ext->add($apppagegroups, $grp, 'busy-hang', new ext_goto('app-pagegroups,h,1'));
            }
            //h
            $ext->add($apppagegroups, 'h', '', new ext_execif('$[${ISNULL(${PAGE${PAGEGROUP}BUSY})}]', 'Set', 'DEVICE_STATE(Custom:PAGE${PAGEGROUP})=NOT_INUSE'));
            break;
    }
}
Esempio n. 21
0
function findmefollow_get_config($engine)
{
    global $ext;
    // is this the best way to pass this?
    global $amp_conf;
    global $astman;
    switch ($engine) {
        case "asterisk":
            if ($amp_conf['USEDEVSTATE']) {
                $ext->addGlobal('FMDEVSTATE', 'TRUE');
            }
            $fcc = new featurecode('findmefollow', 'fmf_toggle');
            $fmf_code = $fcc->getCodeActive();
            unset($fcc);
            if ($fmf_code != '') {
                findmefollow_fmf_toggle($fmf_code);
            }
            $ext->addInclude('from-internal-additional', 'ext-findmefollow');
            $ext->addInclude('from-internal-additional', 'fmgrps');
            $contextname = 'ext-findmefollow';
            $grpcontextname = 'fmgrps';
            // Before creating all the contexts, let's make a list of hints if needed
            //
            if ($amp_conf['USEDEVSTATE'] && $fmf_code != '') {
                $ext->add($contextname, "_" . $fmf_code . 'X.', '', new ext_goto("1", $fmf_code, "app-fmf-toggle"));
                $ext->addHint($contextname, "_" . $fmf_code . 'X.', "Custom:FOLLOWME" . '${EXTEN:' . strlen($fmf_code) . '}');
            }
            $groups = FreePBX::Findmefollow()->getAllFollowmes();
            $dial_options = FreePBX::Config()->get("DIAL_OPTIONS");
            foreach ($groups as $grp) {
                $grpnum = $grp['grpnum'];
                $strategy = $grp['strategy'];
                $grptime = $grp['grptime'];
                $grplist = $grp['grplist'];
                $postdest = $grp['postdest'];
                $grppre = isset($grp['grppre']) ? $grp['grppre'] : '';
                $annmsg_id = $grp['annmsg_id'];
                $dring = $grp['dring'];
                $needsconf = $grp['needsconf'];
                $remotealert_id = $grp['remotealert_id'];
                $toolate_id = $grp['toolate_id'];
                $ringing = $grp['ringing'];
                $pre_ring = $grp['pre_ring'];
                $astman->database_put("AMPUSER", $grpnum . "/followme/grppre", isset($grppre) ? $grppre : '');
                $astman->database_put("AMPUSER", $grpnum . "/followme/dring", isset($dring) ? $dring : '');
                $astman->database_put("AMPUSER", $grpnum . "/followme/strategy", isset($strategy) ? $strategy : '');
                $astman->database_put("AMPUSER", $grpnum . "/followme/annmsg", !empty($annmsg_id) ? recordings_get_file($annmsg_id) : '');
                $astman->database_put("AMPUSER", $grpnum . "/followme/remotealertmsg", !empty($remotealert_id) ? recordings_get_file($remotealert_id) : '');
                $astman->database_put("AMPUSER", $grpnum . "/followme/toolatemsg", !empty($toolate_id) ? recordings_get_file($toolate_id) : '');
                $astman->database_put("AMPUSER", $grpnum . "/followme/postdest", $postdest);
                $astman->database_put("AMPUSER", $grpnum . "/followme/ringing", $ringing);
                // Create the confirm target
                $len = strlen($grpnum) + 4;
                $remotealert = empty($remotealert_id) ? '' : recordings_get_file($remotealert_id);
                $toolate = empty($toolate_id) ? '' : recordings_get_file($toolate_id);
                if ($ringing == 'Ring' || empty($ringing)) {
                    $dialopts = '${DIAL_OPTIONS}';
                } else {
                    // We need the DIAL_OPTIONS variable
                    $dialopts = "m({$ringing})" . str_replace('r', '', $dial_options);
                }
                //These two have to be here because of how they function in the dialplan.
                //Dont try to make them dynamic, we really can't do that
                $len = strlen($grpnum) + 4;
                $ext->add($grpcontextname, "_RG-" . $grpnum . ".", '', new ext_macro('dial', '${DB(AMPUSER/' . $grpnum . '/followme/grptime)},' . $dialopts . 'M(confirm^${remotealert}^${toolate}^${grpnum}),${EXTEN:' . $len . '}'), 1, 1);
                $ext->add($contextname, $grpnum, '', new ext_gotoif('$[${DB_EXISTS(AMPUSER/${EXTEN}/followme/ddial)} != 1 | "${DB(AMPUSER/${EXTEN}/followme/ddial)}" = "EXTENSION" ]', 'ext-local,${EXTEN},1', 'followme-check,${EXTEN},1'));
            }
            $ext->add($grpcontextname, "_RG-X.", '', new ext_nocdr(''));
            // Direct target to Follow-Me come here bypassing the followme/ddial conditional check
            //
            $ext->add($contextname, '_FMX.', '', new ext_goto('FMCID', '${EXTEN:2}', 'followme-check'));
            $contextname = 'followme-check';
            $ext->add($contextname, '_X.', 'FMCID', new ext_gosub('1', '${EXTEN}', 'followme-sub'));
            $ext->add($contextname, '_X.', '', new ext_noop('Should never get here'));
            $ext->add($contextname, '_X.', '', new ext_hangup());
            $contextname = 'followme-sub';
            $ext->add($contextname, '_X.', '', new ext_macro('user-callerid'));
            $ext->add($contextname, '_X.', '', new ext_set('DIAL_OPTIONS', '${DIAL_OPTIONS}I'));
            $ext->add($contextname, '_X.', '', new ext_set('CONNECTEDLINE(num,i)', '${EXTEN}'));
            $cidnameval = '${DB(AMPUSER/${EXTEN}/cidname)}';
            if ($amp_conf['AST_FUNC_PRESENCE_STATE'] && $amp_conf['CONNECTEDLINE_PRESENCESTATE']) {
                $ext->add($contextname, '_X.', '', new ext_gosub('1', 's', 'sub-presencestate-display', '${EXTEN}'));
                $cidnameval .= '${PRESENCESTATE_DISPLAY}';
            }
            $ext->add($contextname, '_X.', '', new ext_set('CONNECTEDLINE(name)', $cidnameval));
            $ext->add($contextname, '_X.', '', new ext_set('FM_DIALSTATUS', '${EXTENSION_STATE(${EXTEN}@ext-local)}'));
            $ext->add($contextname, '_X.', '', new ext_set('__EXTTOCALL', '${EXTEN}'));
            $ext->add($contextname, '_X.', '', new ext_set('__PICKUPMARK', '${EXTEN}'));
            // block voicemail until phone is answered at which point a macro should be called on the answering
            // line to clear this flag so that subsequent transfers can occur, if already set by a the caller
            // then don't change.
            //
            $ext->add($contextname, '_X.', '', new ext_macro('blkvm-setifempty'));
            $ext->add($contextname, '_X.', '', new ext_gotoif('$["${GOSUB_RETVAL}" = "TRUE"]', 'skipov'));
            $ext->add($contextname, '_X.', '', new ext_macro('blkvm-set', 'reset'));
            $ext->add($contextname, '_X.', '', new ext_setvar('__NODEST', ''));
            // Remember if NODEST was set later, but clear it in case the call is answered so that subsequent
            // transfers work.
            //
            $ext->add($contextname, '_X.', 'skipov', new ext_setvar('RRNODEST', '${NODEST}'));
            $ext->add($contextname, '_X.', 'skipvmblk', new ext_setvar('__NODEST', '${EXTEN}'));
            $ext->add($contextname, '_X.', '', new ext_gosubif('$[${DB_EXISTS(AMPUSER/${EXTEN}/followme/changecid)} = 1 & "${DB(AMPUSER/${EXTEN}/followme/changecid)}" != "default" & "${DB(AMPUSER/${EXTEN}/followme/changecid)}" != ""]', 'sub-fmsetcid,s,1'));
            // deal with group CID prefix
            $ext->add($contextname, '_X.', '', new ext_gotoif('$[ "${DB(AMPUSER/${EXTEN}/followme/grppre)}" = "" ]', 'skipprepend'));
            $ext->add($contextname, '_X.', '', new ext_macro('prepend-cid', '${DB(AMPUSER/${EXTEN}/followme/grppre)}'));
            // recording stuff
            $ext->add($contextname, '_X.', 'skipprepend', new ext_setvar('RecordMethod', 'Group'));
            // Note there is no cancel later as the special case of follow-me, if they say record, it should stick
            $ext->add($contextname, '_X.', 'checkrecord', new ext_gosub('1', 's', 'sub-record-check', 'exten,${EXTEN},'));
            // MODIFIED (PL)
            // Add Alert Info if set but don't override and already set value (could be from ringgroup, directdid, etc.)
            //
            $ext->add($contextname, '_X.', '', new ext_gotoif('$[ $["${DB(AMPUSER/${EXTEN}/followme/dring)}" = ""] | $["${ALERT_INFO}"!=""] ]', 'skipdring'));
            $ext->add($contextname, '_X.', '', new ext_setvar('DRING', '${DB(AMPUSER/${EXTEN}/followme/dring)}'));
            $ext->add($contextname, '_X.', '', new ext_setvar("__ALERT_INFO", '${STRREPLACE(DRING,\\;,\\\\;)}'));
            // If pre_ring is set, then ring this number of seconds prior to moving on
            $ext->add($contextname, '_X.', 'skipdring', new ext_setvar('STRATEGY', '${DB(AMPUSER/${EXTEN}/followme/strategy)}'));
            $ext->add($contextname, '_X.', '', new ext_gotoif('$["${CUT(STRATEGY,-,1)}"="ringallv2"]', 'skipsimple'));
            $ext->add($contextname, '_X.', '', new ext_gotoif('$[$[ "${DB(AMPUSER/${EXTEN}/followme/prering)}" = "0" ] | $[ "${DB(AMPUSER/${EXTEN}/followme/prering)}" = "" ]] ', 'skipsimple'));
            $ext->add($contextname, '_X.', '', new ext_macro('simple-dial', '${EXTEN},${DB(AMPUSER/${EXTEN}/followme/prering)}'));
            // group dial
            $ext->add($contextname, '_X.', 'skipsimple', new ext_setvar('RingGroupMethod', '${STRATEGY}'));
            $ext->add($contextname, '_X.', '', new ext_setvar('_FMGRP', '${EXTEN}'));
            // should always answer before playing anything, shouldn't we ?
            $ext->add($contextname, '_X.', '', new ext_gotoif('$[$["${DB(AMPUSER/${EXTEN}/followme/annmsg)}" = ""] | $["${DIALSTATUS}" = "ANSWER"] | $["foo${RRNODEST}" != "foo"]]', 'DIALGRP'));
            $ext->add($contextname, '_X.', '', new ext_answer(''));
            $ext->add($contextname, '_X.', '', new ext_wait(1));
            $ext->add($contextname, '_X.', '', new ext_playback('${DB(AMPUSER/${EXTEN}/followme/annmsg)}'));
            // If grpconf == ENABLED call with confirmation ELSE call normal
            $ext->add($contextname, '_X.', 'DIALGRP', new ext_execif('$[$["${DB(AMPUSER/${EXTEN}/followme/ringing)}"="Ring"] | $["${DB(AMPUSER/${EXTEN}/followme/ringing)}"=""]]', 'Set', 'DOPTS=${DIAL_OPTIONS}', 'Set', 'DOPTS=m(${DB(AMPUSER/${EXTEN}/followme/ringing)})${STRREPLACE(DIAL_OPTIONS,r)}'));
            $ext->add($contextname, '_X.', '', new ext_gotoif('$[("${DB(AMPUSER/${EXTEN}/followme/grpconf)}"="ENABLED") | ("${FORCE_CONFIRM}"!="") ]', 'doconfirm'));
            // Normal call
            $ext->add($contextname, '_X.', '', new ext_gotoif('$["${CUT(STRATEGY,-,1)}"="ringallv2"]', 'ringallv21'));
            $ext->add($contextname, '_X.', '', new ext_macro('dial', '${DB(AMPUSER/${EXTEN}/followme/grptime)},${DOPTS},' . '${DB(AMPUSER/${EXTEN}/followme/grplist)}'));
            $ext->add($contextname, '_X.', 'ringallv21', new ext_macro('dial', '$[ ${DB(AMPUSER/${EXTEN}/followme/grptime)} + ${DB(AMPUSER/${EXTEN}/followme/prering)} ],${DOPTS},${DB(AMPUSER/${EXTEN}/followme/grplist)}'));
            $ext->add($contextname, '_X.', '', new ext_goto('nextstep'));
            // Call Confirm call
            $ext->add($contextname, '_X.', 'doconfirm', new ext_gotoif('$["${CUT(STRATEGY,-,1)}"="ringallv2"]', 'ringallv22'));
            $ext->add($contextname, '_X.', '', new ext_macro('dial-confirm', '${DB(AMPUSER/${EXTEN}/followme/grptime)},${DOPTS},' . '${DB(AMPUSER/${EXTEN}/followme/grplist)},${EXTEN}'));
            $ext->add($contextname, '_X.', 'ringallv22', new ext_macro('dial-confirm', '$[ ${DB(AMPUSER/${EXTEN}/followme/grptime)} + ${DB(AMPUSER/${EXTEN}/followme/prering)} ],${DOPTS},${DB(AMPUSER/${EXTEN}/followme/grplist)},${EXTEN}'));
            $ext->add($contextname, '_X.', 'nextstep', new ext_setvar('RingGroupMethod', ''));
            // Did the call come from a queue or ringgroup, if so, don't go to the destination, just end and let
            // the queue or ringgroup decide what to do next
            //
            $ext->add($contextname, '_X.', '', new ext_gotoif('$["foo${RRNODEST}" != "foo"]', 'nodest'));
            $ext->add($contextname, '_X.', '', new ext_setvar('__NODEST', ''));
            $ext->add($contextname, '_X.', '', new ext_set('__PICKUPMARK', ''));
            $ext->add($contextname, '_X.', '', new ext_macro('blkvm-clr'));
            /* NOANSWER:    NOT_INUSE
             * CHANUNAVAIL: UNAVAILABLE, UNKNOWN, INVALID (or DIALSTATUS=CHANUNAVAIL)
             * BUSY:        BUSY, INUSE, RINGING, RINGINUSE, HOLDINUSE, ONHOLD
             */
            $ext->add($contextname, '_X.', '', new ext_noop_trace('FM_DIALSTATUS: ${FM_DIALSTATUS} DIALSTATUS: ${DIALSTATUS}'));
            $ext->add($contextname, '_X.', '', new ext_set('DIALSTATUS', '${IF($["${FM_DIALSTATUS}"="NOT_INUSE"&"${DIALSTATUS}"!="CHANUNAVAIL"]?NOANSWER:' . '${IF($["${DIALSTATUS}"="CHANUNAVAIL"|"${FM_DIALSTATUS}"="UNAVAILABLE"|"${FM_DIALSTATUS}"="UNKNOWN"|"${FM_DIALSTATUS}"="INVALID"]?' . 'CHANUNAVAIL:BUSY)})}'));
            // where next?
            $ext->add($contextname, '_X.', '', new ext_gotoif('$["${DB(AMPUSER/${EXTEN}/followme/postdest)}"=""]', 'dohangup'));
            $ext->add($contextname, '_X.', '', new ext_goto('${DB(AMPUSER/${EXTEN}/followme/postdest)}'));
            $ext->add($contextname, '_X.', 'dohangup', new ext_hangup(''));
            $ext->add($contextname, '_X.', 'nodest', new ext_noop('SKIPPING DEST, CALL CAME FROM Q/RG: ${RRNODEST}'));
            $ext->add($contextname, '_X.', '', new ext_return());
            /*
            	ASTDB Settings:
            	AMPUSER/nnn/followme/changecid default | did | fixed | extern
            	AMPUSER/nnn/followme/fixedcid XXXXXXXX
            
            	changecid:
            		default   - works as always, same as if not present
            		fixed     - set to the fixedcid
            		extern    - set to the fixedcid if the call is from the outside only
            		did       - set to the DID that the call came in on or leave alone, treated as foreign
            		forcedid  - set to the DID that the call came in on or leave alone, not treated as foreign
            
            	EXTTOCALL   - has the exten num called, hoaky if that goes away but for now use it
            */
            $contextname = 'sub-fmsetcid';
            $exten = 's';
            $ext->add($contextname, $exten, '', new ext_goto('1', 's-${DB(AMPUSER/${EXTTOCALL}/followme/changecid)}'));
            $exten = 's-fixed';
            $ext->add($contextname, $exten, '', new ext_execif('$["${REGEX("^[\\+]?[0-9]+$" ${DB(AMPUSER/${EXTTOCALL}/followme/fixedcid)})}" = "1"]', 'Set', '__TRUNKCIDOVERRIDE=${DB(AMPUSER/${EXTTOCALL}/followme/fixedcid)}'));
            $ext->add($contextname, $exten, '', new ext_return(''));
            $exten = 's-extern';
            $ext->add($contextname, $exten, '', new ext_execif('$["${REGEX("^[\\+]?[0-9]+$" ${DB(AMPUSER/${EXTTOCALL}/followme/fixedcid)})}" == "1" & "${FROM_DID}" != ""]', 'Set', '__TRUNKCIDOVERRIDE=${DB(AMPUSER/${EXTTOCALL}/followme/fixedcid)}'));
            $ext->add($contextname, $exten, '', new ext_return(''));
            $exten = 's-did';
            $ext->add($contextname, $exten, '', new ext_execif('$["${REGEX("^[\\+]?[0-9]+$" ${FROM_DID})}" = "1"]', 'Set', '__REALCALLERIDNUM=${FROM_DID}'));
            $ext->add($contextname, $exten, '', new ext_return(''));
            $exten = 's-forcedid';
            $ext->add($contextname, $exten, '', new ext_execif('$["${REGEX("^[\\+]?[0-9]+$" ${FROM_DID})}" = "1"]', 'Set', '__TRUNKCIDOVERRIDE=${FROM_DID}'));
            $ext->add($contextname, $exten, '', new ext_return(''));
            $exten = '_s-.';
            $ext->add($contextname, $exten, '', new ext_noop('Unknown value for AMPUSER/${EXTTOCALL}/followme/changecid of ${DB(AMPUSER/${EXTTOCALL}/followme/changecid)} set to "default"'));
            $ext->add($contextname, $exten, '', new ext_setvar('DB(AMPUSER/${EXTTOCALL}/followme/changecid)', 'default'));
            $ext->add($contextname, $exten, '', new ext_return(''));
            break;
    }
}