<?php

$ringlist = ringgroups_list();
$ctr = 0;
if (is_array($ringlist)) {
    outn("   Creating 'ringgroups' table if needed... ");
    // Create the new table first
    $sql = "CREATE TABLE IF NOT EXISTS `ringgroups` ( ";
    $sql .= "`grpnum` INT NOT NULL , ";
    $sql .= "`strategy` VARCHAR( 50 ) NOT NULL , ";
    $sql .= "`grptime` SMALLINT NOT NULL , ";
    $sql .= "`grppre` VARCHAR( 100 ) NULL , ";
    $sql .= "`grplist` VARCHAR( 255 ) NOT NULL , ";
    $sql .= "`annmsg` VARCHAR( 255 ) NULL , ";
    $sql .= "`postdest` VARCHAR( 255 ) NULL , ";
    $sql .= "PRIMARY KEY  (`grpnum`) ";
    $sql .= ") TYPE = MYISAM ";
    $result = $db->query($sql);
    if (DB::IsError($result)) {
        die($result->getDebugInfo());
    }
    out("OK");
    out("   Upgrading old Ring Group(s)");
    // upgrade each group
    foreach ($ringlist as $item) {
        $ctr += 1;
        $grpnum = ltrim($item['0']);
        outn("     upgrading GRP-" . $grpnum . "... ");
        $exten = ringgroups_get($grpnum, $strategy, $grptime, $grppre, $grplist);
        $goto = upgrade_legacy_args_get($grpnum, 2, 'ext-group');
        // write new record
Beispiel #2
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;
    }
}
function ringgroups_hookProcess_core($viewing_itemid, $request)
{
    if (!isset($request['action'])) {
        return;
    }
    switch ($request['action']) {
        case 'del':
            // Get all ringgroups
            $grouplist = ringgroups_list();
            if (isset($grouplist)) {
                foreach ($grouplist as $list => $group) {
                    // Get the extension list for the ringgroup
                    $extensionlist = ringgroups_get_extensions($group['grpnum']);
                    $extensions = explode('-', $extensionlist['grplist']);
                    $key = array_search($viewing_itemid, $extensions);
                    if ($key !== FALSE) {
                        unset($extensions[$key]);
                        $new_grplist = implode('-', $extensions);
                        ringgroups_update_extensions($group['grpnum'], $new_grplist);
                    }
                }
            }
            break;
    }
}
Beispiel #4
0
function ringgroups_add($grpnum, $strategy, $grptime, $grplist, $postdest, $desc, $grppre = '', $annmsg_id = '', $alertinfo, $needsconf, $remotealert_id, $toolate_id, $ringing, $cwignore, $cfignore, $changecid = 'default', $fixedcid = '')
{
    global $db;
    global $astman;
    $extens = ringgroups_list();
    if (is_array($extens)) {
        foreach ($extens as $exten) {
            if ($exten[0] === $grpnum) {
                echo "<script>javascript:alert('" . _("This ringgroup") . " ({$grpnum}) " . _("is already in use") . "');</script>";
                return false;
            }
        }
    }
    print_r($extens);
    $sql = "INSERT INTO ringgroups (grpnum, strategy, grptime, grppre, grplist, annmsg_id, postdest, description, alertinfo, needsconf, remotealert_id, toolate_id, ringing, cwignore, cfignore) VALUES ('" . $db->escapeSimple($grpnum) . "', '" . $db->escapeSimple($strategy) . "', " . $db->escapeSimple($grptime) . ", '" . $db->escapeSimple($grppre) . "', '" . $db->escapeSimple($grplist) . "', '" . $annmsg_id . "', '" . $db->escapeSimple($postdest) . "', '" . $db->escapeSimple($desc) . "', '" . $db->escapeSimple($alertinfo) . "', '{$needsconf}', '{$remotealert_id}', '{$toolate_id}', '{$ringing}', '{$cwignore}', '{$cfignore}')";
    $results = sql($sql);
    // from followme, put these in astdb, should migrate more settings to astdb from sql so that user portal control can be
    // added. So consider this a start.
    if ($astman) {
        $astman->database_put("RINGGROUP", $grpnum . "/changecid", $changecid);
        $fixedcid = preg_replace("/[^0-9\\+]/", "", trim($fixedcid));
        $astman->database_put("RINGGROUP", $grpnum . "/fixedcid", $fixedcid);
    } else {
        die_freepbx("Cannot connect to Asterisk Manager with " . $amp_conf["AMPMGRUSER"] . "/" . $amp_conf["AMPMGRPASS"]);
    }
    return true;
}
Beispiel #5
0
</div>

<div class="rnav"><ul>
    <li><a class="<?php 
echo $extdisplay == '' ? 'current' : '';
?>
" href="config.php?display=<?php 
echo urlencode($dispnum);
?>
"><?php 
echo _("Add Ring Group");
?>
</a></li>
<?php 
//get unique ring groups
$gresults = ringgroups_list();
if (isset($gresults)) {
    foreach ($gresults as $gresult) {
        echo "<li><a class=\"" . ($extdisplay == 'GRP-' . $gresult[0] ? 'current' : '') . "\" href=\"config.php?display=" . urlencode($dispnum) . "&extdisplay=" . urlencode("GRP-" . $gresult[0]) . "\">" . $gresult[1] . " ({$gresult[0]})</a></li>";
    }
}
?>
</ul></div>

<div class="content">
<?php 
if ($action == 'delGRP') {
    echo '<br><h3>' . _("Ring Group") . ' ' . $account . ' ' . _("deleted") . '!</h3><br><br><br><br><br><br><br><br>';
} else {
    if ($extdisplay) {
        // We need to populate grplist with the existing extension list.
Beispiel #6
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;
    }
}