예제 #1
6
function getContent(&$smarty, $module_name, $withList)
{
    require_once "libs/misc.lib.php";
    $lang = get_language();
    $base_dir = dirname($_SERVER['SCRIPT_FILENAME']);
    $lang_file = "modules/{$module_name}/lang/{$lang}.lang";
    include_once "modules/{$module_name}/lang/en.lang";
    if (file_exists("{$base_dir}/{$lang_file}")) {
        $arrLangEn = $arrLangModule;
        include_once $lang_file;
        $arrLangModule = array_merge($arrLangEn, $arrLangModule);
    }
    $skip_astman = NULL;
    // En el FreePBX original, siempre se define display y setup en GET
    if (!isset($_REQUEST['display'])) {
        $_REQUEST['display'] = 'extensions';
        $_REQUEST['type'] = 'setup';
        $_GET['display'] = 'extensions';
        $_GET['type'] = 'setup';
    }
    /*interprete language to freepbx, todavia no funciona de todo bien :)
    	  en_US - English
    	  bg_BG - Bulgarian
    	  de_DE - Deutsch
    	  es_ES - Español
    	  fr_FR - Francais
    	  he_IL - Hebrew
    	  hu_HU - Hungarian
    	  it_IT - Italiano
    	  pt_PT - Portuguese
    	  ru_RU - Russki
    	  sv_SE - Svenska
    	*/
    $arrLangFreePBX = array("en" => "en_US", "bg" => "bg_BG", "de" => "de_DE", "es" => "es_ES", "fr" => "fr_FR", "he" => "he_IL", "hu" => "hu_HU", "it" => "it_IT", "pt" => "pt_PT", "ru" => "ru_RU", "sv" => "sv_SE");
    $langFreePBX = isset($arrLangFreePBX[$lang]) ? $arrLangFreePBX[$lang] : "en_US";
    if (!isset($_COOKIE['lang'])) {
        $_COOKIE['lang'] = $langFreePBX;
    }
    //global variables
    global $arrConf;
    global $arrLang;
    global $arrLangModule;
    $arrLang = array_merge($arrLang, $arrLangModule);
    // Scripts adicionales que pueden ser necesarios
    $sScripts = '';
    foreach (array('admin/common/jquery.toggleval.3.0.js') as $sRuta) {
        if (file_exists($sRuta)) {
            $sScripts .= "<script type='text/javascript' src='/{$sRuta}'></script>";
        }
    }
    $salida = "";
    $fromElastixAdminPBX = 1;
    $headerFreePBX = "\n\t<link href='/modules/pbxadmin/themes/default/mainstyle.css' rel='stylesheet' type='text/css'>\n\t<!--[if IE]>\n\t<link href='/modules/pbxadmin/themes/default/ie.css' rel='stylesheet' type='text/css'>\n\t<![endif]-->    \n\t<script type='text/javascript' src='/modules/pbxadmin/js/script.js.php'></script>\n\t<script type='text/javascript' src='/modules/pbxadmin/js/script.legacy.js'></script>\n\t<script type='text/javascript' src='/modules/pbxadmin/js/libfreepbx.javascripts.js'></script>\n    {$sScripts}\n\t<!--[if IE]>\n\t<style type='text/css'>div.inyourface a{position:absolute;}</style>\n\t<![endif]-->";
    $dir_base = "/var/www/html/modules/{$module_name}/themes";
    $local_templates_dir = file_exists("{$dir_base}/" . $arrConf['theme']) ? "{$dir_base}/" . $arrConf['theme'] : "{$dir_base}/default";
    // Obtengo el {$HEADER} anterior y le agrego lo nuevo
    $headerNuevo = @$smarty->fetch("HEADER");
    $headerNuevo .= $headerFreePBX;
    $smarty->assign("HEADER", $headerNuevo);
    // Obtengo el {$BODYPARAMS} anterior y le agrego lo nuevo
    $bodyParams = @$smarty->fetch("BODYPARAMS");
    $bodyParams .= "onload='body_loaded();'";
    $smarty->assign("BODYPARAMS", $bodyParams);
    $_SESSION["AMP_user"] = NULL;
    /* benchmark */
    function microtime_float()
    {
        list($usec, $sec) = explode(' ', microtime());
        return (double) $usec + (double) $sec;
    }
    $benchmark_starttime = microtime_float();
    /*************/
    $type = isset($_REQUEST['type']) ? $_REQUEST['type'] : 'setup';
    // Ojo, modifique ligeramente la sgte. linea para que la opcion por omision sea extensions
    if (isset($_REQUEST['display'])) {
        $display = $_REQUEST['display'];
    } else {
        $display = 'extensions';
        $_REQUEST['display'] = 'extensions';
    }
    $extdisplay = isset($_REQUEST['extdisplay']) ? $_REQUEST['extdisplay'] : null;
    $skip = isset($_REQUEST['skip']) ? $_REQUEST['skip'] : 0;
    $action = isset($_REQUEST['action']) ? $_REQUEST['action'] : null;
    $quietmode = isset($_REQUEST['quietmode']) ? $_REQUEST['quietmode'] : '';
    // determine module type to show, default to 'setup'
    $type_names = array('tool' => 'Tools', 'setup' => 'Setup', 'cdrcost' => 'Call Cost');
    /*************************************************************/
    /* Este bloque pertenece en su mayoria al archivo header.php */
    /* ya que no estaban registrando ciertas variables globales; */
    /* asi que lo repito aqui y evito parchar dicho archivo y    */
    /* otros mas.                                                */
    /*************************************************************/
    // include base functions
    global $amp_conf_defaults;
    require_once '/var/www/html/admin/functions.inc.php';
    require_once '/var/www/html/admin/common/php-asmanager.php';
    // Hack to avoid patching admin/functions.inc.php
    $GLOBALS['amp_conf_defaults'] = $amp_conf_defaults;
    // get settings
    $amp_conf = parse_amportal_conf("/etc/amportal.conf");
    $asterisk_conf = parse_asterisk_conf($amp_conf["ASTETCDIR"] . "/asterisk.conf");
    $astman = new AGI_AsteriskManager();
    // attempt to connect to asterisk manager proxy
    if (!isset($amp_conf["ASTMANAGERPROXYPORT"]) || !($res = $astman->connect("127.0.0.1:" . $amp_conf["ASTMANAGERPROXYPORT"], $amp_conf["AMPMGRUSER"], $amp_conf["AMPMGRPASS"]))) {
        // attempt to connect directly to asterisk, if no proxy or if proxy failed
        if (!($res = $astman->connect("127.0.0.1:" . $amp_conf["ASTMANAGERPORT"], $amp_conf["AMPMGRUSER"], $amp_conf["AMPMGRPASS"]))) {
            // couldn't connect at all
            unset($astman);
        }
    }
    if (!isset($astman) || is_null($astman)) {
        return _tr('Failed to connect to Asterisk Manager Interface') . ' - ' . "127.0.0.1:" . $amp_conf["ASTMANAGERPORT"];
    }
    $GLOBALS['amp_conf'] = $amp_conf;
    $GLOBALS['asterisk_conf'] = $asterisk_conf;
    $GLOBALS['astman'] = $astman;
    // Hack to avoid patching common/db_connect.php
    // I suppose the used database is mysql
    require_once 'DB.php';
    //PEAR must be installed
    $db_user = $amp_conf["AMPDBUSER"];
    $db_pass = $amp_conf["AMPDBPASS"];
    $db_host = $amp_conf["AMPDBHOST"];
    $db_name = $amp_conf["AMPDBNAME"];
    $datasource = 'mysql://' . $db_user . ':' . $db_pass . '@' . $db_host . '/' . $db_name;
    $db = DB::connect($datasource);
    // attempt connection
    $GLOBALS['db'] = $db;
    if (!isset($_SESSION['AMP_user'])) {
        $_SESSION['AMP_user'] = new ampuser($amp_conf['AMPDBUSER']);
        $_SESSION['AMP_user']->setAdmin();
    }
    // Requiring header.php
    include '/var/www/html/admin/header.php';
    // The next block is to fix a music on hold issue
    $category = strtr(isset($_REQUEST['category']) ? $_REQUEST['category'] : '', " ./\"\\'\\`", "------");
    if ($category == null) {
        $category = 'default';
    }
    if ($category == "default") {
        $path_to_dir = $asterisk_conf['astvarlibdir'] . "/" . $amp_conf["MOHDIR"] . "/";
    } else {
        $path_to_dir = $asterisk_conf['astvarlibdir'] . "/" . $amp_conf["MOHDIR"] . "/{$category}";
    }
    //path to directory u want to read.
    $GLOBALS['path_to_dir'] = $path_to_dir;
    $path_to_moh_dir = $amp_conf['ASTVARLIBDIR'] . '/' . $amp_conf['MOHDIR'];
    $GLOBALS['path_to_moh_dir'] = $path_to_moh_dir;
    /*************************************************************/
    /* Fin del bloque                                            */
    /*************************************************************/
    $GLOBALS['title'] = isset($title) ? $title : '';
    $GLOBALS['type'] = isset($type) ? $type : '';
    $GLOBALS['display'] = isset($display) ? $display : '';
    $GLOBALS['extdisplay'] = isset($extdisplay) ? $extdisplay : '';
    $GLOBALS['skip'] = isset($skip) ? $skip : '';
    $GLOBALS['action'] = isset($action) ? $action : '';
    $GLOBALS['quietmode'] = isset($quietmode) ? $quietmode : '';
    $GLOBALS['message'] = isset($message) ? $message : '';
    $GLOBALS['fpbx_menu'] = isset($fpbx_menu) ? $fpbx_menu : '';
    $GLOBALS['recordings_save_path'] = "/tmp/";
    //This _guielement_tabindex and _guielement_formfields fixed bug in extensions freePBX embedded
    $GLOBALS['_guielement_tabindex'] = 1;
    $GLOBALS['_guielement_formfields'] = 0;
    //This $fc_save var fixed bug in System Recording en freePBX embedeed
    global $fc_save;
    global $fc_check;
    global $recordings_save_path;
    global $itemid;
    // handle special requests
    if (isset($_REQUEST['handler'])) {
        switch ($_REQUEST['handler']) {
            case 'reload':
                /** AJAX handler for reload event
                 */
                include_once '/var/www/html/admin/common/json.inc.php';
                $response = do_reload();
                $json = new Services_JSON();
                //echo $json->encode($response);
                break;
            case 'file':
                /** Handler to pass-through file requests 
                 * Looks for "module" and "file" variables, strips .. and only allows normal filename characters.
                 * Accepts only files of the type listed in $allowed_exts below, and sends the corresponding mime-type, 
                 * and always interprets files through the PHP interpreter. (Most of?) the freepbx environment is available,
                 * including $db and $astman, and the user is authenticated.
                 */
                if (!isset($_REQUEST['module']) || !isset($_REQUEST['file'])) {
                    die_freepbx("unknown");
                }
                //TODO: this could probably be more efficient
                $module = str_replace('..', '.', preg_replace('/[^a-zA-Z0-9-\\_\\.]/', '', $_REQUEST['module']));
                $file = str_replace('..', '.', preg_replace('/[^a-zA-Z0-9-\\_\\.]/', '', $_REQUEST['file']));
                $allowed_exts = array('.js' => 'text/javascript', '.js.php' => 'text/javascript', '.css' => 'text/css', '.css.php' => 'text/css', '.html.php' => 'text/html', '.jpg.php' => 'image/jpeg', '.jpeg.php' => 'image/jpeg', '.png.php' => 'image/png', '.gif.php' => 'image/gif');
                foreach ($allowed_exts as $ext => $mimetype) {
                    if (substr($file, -1 * strlen($ext)) == $ext) {
                        $fullpath = 'modules/' . $module . '/' . $file;
                        if (file_exists($fullpath)) {
                            // file exists, and is allowed extension
                            // image, css, js types - set Expires to an hour in advance so the client does
                            // not keep checking for them. Replace from header.php
                            if (!$amp_conf['DEVEL']) {
                                @header('Expires: ' . gmdate('D, d M Y H:i:s', time() + 3600) . ' GMT', true);
                                @header('Cache-Control: ', true);
                                @header('Pragma: ', true);
                            }
                            @header("Content-type: " . $mimetype);
                            include $fullpath;
                            exit;
                        }
                        break;
                    }
                }
                die_freepbx("not allowed");
                break;
        }
        //exit();
    }
    module_run_notification_checks();
    $framework_asterisk_running = checkAstMan();
    // get all enabled modules
    // active_modules array used below and in drawselects function and genConf function
    // $active_modules = module_getinfo(false, MODULE_STATUS_ENABLED);
    $active_modules = module_getinfo(false, MODULE_STATUS_ENABLED);
    $GLOBALS['active_modules'] = $active_modules;
    // Esto lo he puesto aqui porque el modulo blacklist lo requiere
    // en caso de que o exista la clase extension
    require_once "/var/www/html/admin/extensions.class.php";
    $fpbx_menu = array();
    // pointer to current item in $fpbx_menu, if applicable
    $cur_menuitem = null;
    // add module sections to $fpbx_menu
    // Aqui lleno el arreglo fpbx_menu que es quien contiene los elementos del menu
    // Tambien cargo unas funciones y se hacen otras cositas mas como setear la variable
    // que contiene el item actual
    $types = array();
    if (is_array($active_modules)) {
        foreach ($active_modules as $key => $module) {
            //include module functions
            if (is_file("/var/www/html/admin/modules/{$key}/functions.inc.php")) {
                require_once "/var/www/html/admin/modules/{$key}/functions.inc.php";
            }
            //create an array of module sections to display
            // stored as [items][$type][$category][$name] = $displayvalue
            if (isset($module['items']) && is_array($module['items'])) {
                // loop through the types
                foreach ($module['items'] as $itemKey => $item) {
                    // check access, unless module.xml defines all have access
                    if (!isset($item['access']) || strtolower($item['access']) != 'all') {
                        if (!$_SESSION["AMP_user"]->checkSection($itemKey)) {
                            // no access, skip to the next
                            continue;
                        }
                    }
                    if (!$framework_asterisk_running && (isset($item['needsenginedb']) && strtolower($item['needsenginedb'] == 'yes') || isset($item['needsenginerunning']) && strtolower($item['needsenginerunning'] == 'yes'))) {
                        $item['disabled'] = true;
                    } else {
                        $item['disabled'] = false;
                    }
                    if (!in_array($item['type'], $types)) {
                        $types[] = $item['type'];
                    }
                    if (!isset($item['display'])) {
                        $item['display'] = $itemKey;
                    }
                    // reference to the actual module
                    $item['module'] =& $active_modules[$key];
                    // item is an assoc array, with at least array(module=> name=>, category=>, type=>, display=>)
                    $fpbx_menu[$itemKey] = $item;
                    // allow a module to replace our main index page
                    if ($item['display'] == 'index' && $display == '') {
                        $display = 'index';
                    }
                    // check current item
                    if ($display == $item['display']) {
                        // found current menuitem, make a reference to it
                        $cur_menuitem =& $fpbx_menu[$itemKey];
                    }
                }
            }
        }
    }
    sort($types);
    // new gui hooks
    // Este bloque al parecer almacena en el arreglo configpageinits el nombre de ciertas funciones
    // estandar que se deben cargar si es que se encuentran.
    // Al parecer no todo modulo las trae, es opcional. Por eso se buscan en todos los modulos...
    if (is_array($active_modules)) {
        foreach ($active_modules as $key => $module) {
            if (isset($module['items']) && is_array($module['items'])) {
                foreach ($module['items'] as $itemKey => $itemName) {
                    //list of potential _configpageinit functions
                    $initfuncname = $key . '_' . $itemKey . '_configpageinit';
                    if (function_exists($initfuncname)) {
                        $configpageinits[] = $initfuncname;
                    }
                }
            }
            //check for module level (rather than item as above) _configpageinit function
            $initfuncname = $key . '_configpageinit';
            if (function_exists($initfuncname)) {
                $configpageinits[] = $initfuncname;
            }
        }
    }
    // extensions vs device/users ... this is a bad design, but hey, it works
    // Este bloque distingue entre si mostrar el menu de extensiones o en su lugar
    // mostrar los menus de devices y users. Esto es porque existe la posibilidad de
    // disasociar dispositivos de usuarios.
    if (isset($amp_conf["AMPEXTENSIONS"]) && $amp_conf["AMPEXTENSIONS"] == "deviceanduser") {
        unset($fpbx_menu["extensions"]);
    } else {
        unset($fpbx_menu["devices"]);
        unset($fpbx_menu["users"]);
    }
    // check access
    if (!is_array($cur_menuitem) && $display != "") {
        showview("noaccess");
        return '(internal) No active FreePBX modules found. Please enable Unembedded FreePBX for troubleshooting.';
    }
    // load the component from the loaded modules
    if ($display != '' && isset($configpageinits) && is_array($configpageinits)) {
        $currentcomponent = new component($display, $type);
        $GLOBALS['currentcomponent'] = $currentcomponent;
        // call every modules _configpageinit function which should just
        // register the gui and process functions for each module, if relevent
        // for this $display
        foreach ($configpageinits as $func) {
            $func($display);
        }
        // now run each 'process' function and 'gui' function
        $currentcomponent->processconfigpage();
        $currentcomponent->buildconfigpage();
    }
    //  note: we buffer all the output from the 'page' being loaded..
    // This may change in the future, with proper returns, but for now, it's a simple
    // way to support the old page.item.php include module format.
    ob_start();
    $module_name = "";
    $module_page = "";
    $module_file = "";
    // hack to have our default display handler show the "welcome" view
    // Note: this probably isn't REALLY needed if there is no menu item for "Welcome"..
    // but it doesn't really hurt, and it provides a handler in case some page links
    // to "?display=index"
    if ($display == 'index' && $cur_menuitem['module']['rawname'] == 'builtin') {
        $display = '';
    }
    // show the appropriate page
    switch ($display) {
        default:
            //display the appropriate module page
            $module_name = $cur_menuitem['module']['rawname'];
            $module_page = $cur_menuitem['display'];
            $module_file = '/var/www/html/admin/modules/' . $module_name . '/page.' . $module_page . '.php';
            //TODO Determine which item is this module displaying. Currently this is over the place, we should standarize on a "itemid" request var for now, we'll just cover all possibilities :-(
            $possibilites = array('userdisplay', 'extdisplay', 'id', 'itemid', 'category', 'selection');
            $itemid = '';
            foreach ($possibilites as $possibility) {
                if (isset($_REQUEST[$possibility]) && $_REQUEST[$possibility] != '') {
                    $itemid = $_REQUEST[$possibility];
                }
            }
            // create a module_hook object for this module's page
            $module_hook = new moduleHook();
            // populate object variables
            $module_hook->install_hooks($module_page, $module_name, $itemid);
            // let hooking modules process the $_REQUEST
            $module_hook->process_hooks($itemid, $module_name, $module_page, $_REQUEST);
            // include the module page
            if (isset($cur_menuitem['disabled']) && $cur_menuitem['disabled']) {
                showview("menuitem_disabled", $cur_menuitem);
                break;
                // we break here to avoid the generateconfigpage() below
            } else {
                if (file_exists($module_file)) {
                    // load language info if available
                    if (extension_loaded('gettext')) {
                        if (is_dir("/var/www/html/admin/modules/{$module_name}/i18n")) {
                            bindtextdomain($module_name, "/var/www/html/admin/modules/{$module_name}/i18n");
                            bind_textdomain_codeset($module_name, 'utf8');
                            textdomain($module_name);
                        }
                    }
                    // Aqui es donde se dibuja el GUI
                    include $module_file;
                } else {
                    // TODO: make this a showview()
                    echo "404 Not found";
                }
            }
            // global component
            if (isset($currentcomponent)) {
                echo $currentcomponent->generateconfigpage();
            }
            break;
        case 'modules':
            // set these to avoide undefined variable warnings later
            //
            $module_name = 'modules';
            $module_page = $cur_menuitem['display'];
            include '/var/www/html/admin/page.modules.php';
            break;
        case '':
            if ($astman) {
                showview('welcome', array('AMP_CONF' => &$amp_conf));
            } else {
                // no manager, no connection to asterisk
                showview('welcome_nomanager', array('mgruser' => $amp_conf["AMPMGRUSER"]));
            }
            break;
    }
    //$salida .= @ob_get_flush();
    $htmlFPBX = @ob_get_contents();
    ob_end_clean();
    // Aqui reviso si hay modulos deshabilitados
    $modulos_desabilitados = 0;
    foreach ($active_modules as $modulo) {
        if ($modulo['status'] == '3') {
            $modulos_desabilitados = 1;
        }
    }
    if ($modulos_desabilitados == 1) {
        $salida .= "<table border=0 cellpadding=2 cellspacing=0 align='center' width='100%'><tr bgcolor='#cccccc'><td align='center'>There is at least one freePBX module that has been automatically disabled because it needs an update. Please go to the unembedded freePBX option and update this module(s). Otherwise unexpected things could happen with your PBX configuration.</td></tr></table>";
    }
    if (check_reload_needed()) {
        // Reviso si el REQUEST_URI tiene ya variables tipo get. Solo busco por un signo de ?
        $pos = strpos($_SERVER['REQUEST_URI'], '?');
        if ($pos > 0) {
            $URL_RELOAD = $_SERVER['REQUEST_URI'] . "&handler=reload";
        } else {
            $URL_RELOAD = $_SERVER['REQUEST_URI'] . "?handler=reload";
        }
        $salida .= "<table border=0 cellpadding=2 cellspacing=0 align='center' width='100%'><tr bgcolor='#f6bbbb'><td align='center'><a href='{$URL_RELOAD}'>Apply Configuration Changes Here</a></td></tr></table>";
    }
    if ($withList) {
        $smarty->assign("Option", _tr('Option'));
        $smarty->assign("Unembedded_freePBX", _tr('Unembedded freePBX'));
        $smarty->assign("Basic", _tr('Basic'));
        $smarty->assign("Extensions", _tr('Extensions'));
        $smarty->assign("Feature_Codes", _tr('Feature Codes'));
        $smarty->assign("General_Settings", _tr('General Settings'));
        $smarty->assign("Outbound_Routes", _tr('Outbound Routes'));
        $smarty->assign("Trunks", _tr('Trunks'));
        $smarty->assign("Inbound_Call_Control", _tr('Inbound Call Control'));
        $smarty->assign("Inbound_Routes", _tr('Inbound Routes'));
        $smarty->assign("Announcements", _tr('Announcements'));
        $smarty->assign("Follow_Me", _tr('Follow Me'));
        $smarty->assign("IVR", _tr('IVR'));
        $smarty->assign("Misc_Destinations", _tr('Misc Destinations'));
        $smarty->assign("Queues", _tr('Queues'));
        $smarty->assign("Ring_Groups", _tr('Ring Groups'));
        $smarty->assign("Time_Conditions", _tr('Time Conditions'));
        $smarty->assign("Internal_Options_Configuration", _tr('Internal Options & Configuration'));
        $smarty->assign("Conferences", _tr('Conferences'));
        $smarty->assign("Misc_Applications", _tr('Misc Applications'));
        $smarty->assign("Music_on_Hold", _tr('Music on Hold'));
        $smarty->assign("PIN_Sets", _tr('PIN Sets'));
        $smarty->assign("Paging_Intercom", _tr('Paging and Intercom'));
        $smarty->assign("Parking_Lot", _tr('Parking Lot'));
        $smarty->assign("System_Recordings", _tr('System Recordings'));
        $smarty->assign("Remote_Access", _tr('Remote Access'));
        $smarty->assign("Callback", _tr('Callback'));
        $smarty->assign("DISA", _tr('DISA'));
        $smarty->assign("Zap_Channel_DIDs", _tr('Zap Channel DIDs'));
        $smarty->assign("Blacklist", _tr('Blacklist'));
        $smarty->assign("CallerID_Lookup_Sources", _tr('CallerID Lookup Sources'));
        $smarty->assign("Day_Night_Control", _tr('Day/Night Control'));
        $smarty->assign("Queue_Priorities", _tr('Queue Priorities'));
        $smarty->assign("Time_Groups", _tr('Time Groups'));
        $smarty->assign("Languages", _tr('Languages'));
        $smarty->assign("VoiceMail_Blasting", _tr('VoiceMail Blasting'));
        $smarty->assign("INFO", _tr("Warning: Updating FreePBX through its web interface will cause it to install versions that may have not yet been properly integrated with Elastix. To avoid conflicts, it is always recommended to search/install updates only through the linux command \"yum update freePBX\"."));
    }
    $smarty->assign("htmlFPBX", $htmlFPBX);
    $salida .= $smarty->fetch("{$local_templates_dir}/main.tpl");
    return $salida;
}
예제 #2
0
function customcontexts_getmodulevalue($id)
{
    static $moduledisplayname = null;
    static $moduleversion = null;
    global $db;
    switch ($id) {
        case 'moduledisplayname':
            if ($moduledisplayname === null) {
                $module_info = module_getinfo('customcontexts');
                $moduledisplayname = $module_info['customcontexts']['name'];
            }
            return $moduledisplayname;
            break;
        case 'moduleversion':
            if ($moduleversion === null) {
                $moduleversion = modules_getversion('customcontexts');
            }
            return $moduleversion;
            break;
        default:
            $sql = "select value from customcontexts_module where id = '{$id}'";
            $results = $db->getAll($sql);
            if (DB::IsError($results)) {
                $results = null;
            }
            return isset($results) ? $results[0][0] : null;
    }
}
예제 #3
0
function featurecodes_getAllFeaturesDetailed($sort_module = true)
{
    global $amp_conf;
    $fd = $amp_conf['ASTETCDIR'] . '/freepbx_featurecodes.conf';
    $overridecodes = array();
    if (file_exists($fd)) {
        $overridecodes = parse_ini_file($fd, true);
    }
    $s = "SELECT featurecodes.modulename, featurecodes.featurename, featurecodes.description AS featuredescription, featurecodes.helptext AS featurehelptext, featurecodes.enabled AS featureenabled, featurecodes.defaultcode, featurecodes.customcode, ";
    $s .= "modules.enabled AS moduleenabled, featurecodes.providedest ";
    $s .= "FROM featurecodes ";
    $s .= "INNER JOIN modules ON modules.modulename = featurecodes.modulename ";
    $s .= $sort_module ? "ORDER BY featurecodes.modulename, featurecodes.description " : "ORDER BY featurecodes.description ";
    $results = sql($s, "getAll", DB_FETCHMODE_ASSOC);
    if (is_array($results)) {
        $modules = module_getinfo(false, MODULE_STATUS_ENABLED);
        foreach ($results as $key => $item) {
            // get the module display name
            $results[$key]['moduledescription'] = !empty($modules[$item['modulename']]['name']) ? $modules[$item['modulename']]['name'] : ucfirst($item['modulename']);
            if (isset($overridecodes[$item['modulename']][$item['featurename']]) && trim($overridecodes[$item['modulename']][$item['featurename']]) != '') {
                $results[$key]['defaultcode'] = $overridecodes[$item['modulename']][$item['featurename']];
            }
        }
        return $results;
    } else {
        return null;
    }
}
예제 #4
0
function freepbx_get_contexts()
{
    $modules = module_getinfo(false, array(MODULE_STATUS_ENABLED, MODULE_STATUS_DISABLED, MODULE_STATUS_NEEDUPGRADE));
    $contexts = array();
    foreach ($modules as $modname => $mod) {
        $funct = strtolower($modname . '_contexts');
        if (function_exists($funct)) {
            // call the  modulename_contexts() function
            $contextArray = $funct();
            if (is_array($contextArray)) {
                foreach ($contextArray as $con) {
                    if (isset($con['context'])) {
                        if (!isset($con['description'])) {
                            $con['description'] = $con['context'];
                        }
                        if (!isset($con['module'])) {
                            $con['module'] = $mod['displayName'];
                        }
                        if (!isset($con['priority'])) {
                            $con['priority'] = 0;
                        }
                        if (!isset($con['parent'])) {
                            $con['parent'] = '';
                        }
                        if (!isset($con['extension'])) {
                            $con['extension'] = null;
                        }
                        if (!isset($con['dept'])) {
                            $con['dept'] = null;
                        }
                        if ($mod['status'] == MODULE_STATUS_ENABLED) {
                            if (!isset($con['enabled'])) {
                                $con['enabled'] = true;
                            }
                        } else {
                            $con['enabled'] = false;
                        }
                        $contexts[$con['context']] = $con;
                    }
                }
            }
        }
    }
    return $contexts;
}
예제 #5
0
#!/usr/bin/env php
<?php 
$restrict_mods = array('backup' => true, 'core' => true, 'sysadmin' => true);
$bootstrap_settings['cdrdb'] = true;
$bootstrap_settings['freepbx_auth'] = false;
if (!@(include_once getenv('FREEPBX_CONF') ? getenv('FREEPBX_CONF') : '/etc/freepbx.conf')) {
    include_once '/etc/asterisk/freepbx.conf';
}
//ensure the backup modules is avalible before continuing
$mod_info = module_getinfo('backup', MODULE_STATUS_ENABLED);
if (!isset($mod_info['backup'])) {
    echo _('Backup module not found or is disabled. Aborting!' . PHP_EOL);
    exit(1);
}
/**
 * OPTIONS
 * opts - if we have opts, run the backup from it, passing the file back when finisehed
 * id - if we have an id. If we do, just run a "regular" backup, using the id for options
 *    and pulling all other data from the database
 * astdb - tools for handeling the astdb
 */
$getopt = (function_exists('_getopt') ? '_' : '') . 'getopt';
$vars = $getopt($short = '', $long = array('opts::', 'id::', 'astdb::', 'data::'));
//if the id option was passed
if (isset($vars['id']) && $vars['id']) {
    //bu = backup settings
    //s= servers
    //b= backup object
    if ($bu = backup_get_backup($vars['id'])) {
        //dont run if no storage servers were found
        if (!isset($bu['storage_servers']) || count($bu['storage_servers']) < 1) {
예제 #6
0
    require $dirname . '/libraries/gui_auth.php';
    frameworkPasswordCheck();
}
if (!isset($no_auth) && !defined('FREEPBX_IS_AUTH')) {
    die('No direct script access allowed');
}
//we should never need this, just another line of defence
bootstrap_include_hooks('pre_module_load', 'all_mods');
$bootstrap_settings['function_modules_included'] = false;
$restrict_mods_local = $restrict_mods;
//I'm pretty sure if this is == true then there is no need to even pull all
//the module info as we are going down a path such as an ajax path that this
//is just overhead. (We'll know soon enough if this is too restrcitive).
if ($restrict_mods_local !== true) {
    $isauth = !isset($no_auth);
    $active_modules = module_getinfo(false, MODULE_STATUS_ENABLED);
    $modpath = $amp_conf['AMPWEBROOT'] . '/admin/modules/';
    if (is_array($active_modules)) {
        $force_autoload = false;
        foreach ($active_modules as $key => $module) {
            //check if this module was was excluded
            $is_selected = is_array($restrict_mods_local) && isset($restrict_mods_local[$key]);
            //get file path
            $file = $modpath . $key . '/functions.inc.php';
            $file_exists = is_file($file);
            //check authentication, skip this module if we dont have auth
            $needs_auth = isset($module['requires_auth']) && $module['requires_auth'] == 'false' ? false : true;
            if (!$isauth && $needs_auth) {
                continue;
            }
            // Zend appears to break class auto-loading. Therefore, if we
예제 #7
0
파일: functions.inc.php 프로젝트: lidl/core
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;
    }
}
예제 #8
0
$first_install = db_e($db->getAll('SELECT * FROM xmpp_options'), '');
//prosody creates this on startup but just to be safe we should as well
$sql[] = "CREATE TABLE IF NOT EXISTS `prosody` (\n  `host` text,\n  `user` text,\n  `store` text,\n  `key` text,\n  `type` text,\n  `value` mediumtext,\n  KEY `prosody_index` (`host`(20),`user`(20),`store`(20),`key`(20))\n)";
$sql[] = "CREATE TABLE IF NOT EXISTS `xmpp_users` (\n  `user` varchar(50) NOT NULL default '',\n  `username` varchar(50) default NULL,\n  `password` varchar(50) default NULL,\n  PRIMARY KEY  (`user`)\n)";
$sql[] = "CREATE TABLE IF NOT EXISTS `xmpp_options` (\n  `keyword` varchar(75) NOT NULL default '',\n  `value` text,\n  PRIMARY KEY  (`keyword`)\n)";
if ($first_install) {
    $sql[] = 'INSERT INTO xmpp_options (keyword, value) VALUES
			("dirty", "true"),
			("domain", "localhost")
	';
}
$sql[] = 'REPLACE INTO xmpp_options (keyword, value) VALUES ("dirty", "true")';
foreach ($sql as $q) {
    db_e($e = $db->query($q), 'die_freepbx', 4, _("Cannot create xmpp tables"));
}
$mod_info = module_getinfo('xmpp');
if (!empty($mod_info['xmpp']['dbversion']) && version_compare($mod_info['xmpp']['dbversion'], '2.11.1.3', '<')) {
    out(_('Migrating Token Users to User Manager'));
    $sql = "SELECT * FROM xmpp_users";
    $users = sql($sql, 'getAll', DB_FETCHMODE_ASSOC);
    if (!empty($users)) {
        $usermapping = array();
        $userman = FreePBX::create()->Userman;
        $umusers = array();
        $umusersn = array();
        foreach ($userman->getAllUsers() as $user) {
            $umusersn[] = $user['username'];
            if ($user['default_extension'] == 'none') {
                continue;
            }
            $umusers[$user['default_extension']] = $user['id'];
예제 #9
0
        $sql = "select * from users where voicemail='disabled' or voicemail='';";
        $users = sql($sql, "getAll", DB_FETCHMODE_ASSOC);
        foreach ($users as $user) {
            $astman->database_put("AMPUSER", $user['extension'] . "/voicemail", "\"novm\"");
        }
    } else {
        echo _("Cannot connect to Asterisk Manager with ") . $amp_conf["AMPMGRUSER"] . "/" . $amp_conf["AMPMGRPASS"];
        return false;
    }
    sql("update users set voicemail='novm' where voicemail='disabled' or voicemail='';");
}
// vmailadmin module functionality has been fully incporporated into this module
// so if it is installed we remove and delete it from the repository.
//
outn(_("checking if Voicemail Admin (vmailadmin) is installed.."));
$modules = module_getinfo('vmailadmin');
if (!isset($modules['vmailadmin'])) {
    out(_("not installed, ok"));
} else {
    out(_("installed."));
    out(_("Voicemail Admin being removed and merged with Voicemail"));
    outn(_("Attempting to delete.."));
    $result = module_delete('vmailadmin');
    if ($result === true) {
        out(_("ok"));
    } else {
        out($result);
    }
}
$freepbx_conf =& freepbx_conf::create();
// VM_SHOW_IMAP
#!/usr/bin/env php
<?php 
$restrict_mods = array('queues' => true, 'core' => true);
$bootstrap_settings['cdrdb'] = true;
$bootstrap_settings['freepbx_auth'] = false;
if (!@(include_once getenv('FREEPBX_CONF') ? getenv('FREEPBX_CONF') : '/etc/freepbx.conf')) {
    include_once '/etc/asterisk/freepbx.conf';
}
//ensure the queues module is avalible before continuing
$mod_info = module_getinfo('queues', MODULE_STATUS_ENABLED);
if (!isset($mod_info['queues'])) {
    echo _('Queues module not found or is disabled. Aborting!' . PHP_EOL);
    exit(1);
}
/**
 * OPTIONS
 * id - if we have an id, it's the queue id, so go ahead and reset the queue stats
 */
$getopt = (function_exists('_getopt') ? '_' : '') . 'getopt';
$vars = $getopt($short = '', $long = array('opts::', 'id::'));
if (isset($vars['id']) && $vars['id'] && is_numeric($vars['id'])) {
    if ($amp_conf['AMPENGINE'] == 'asterisk' && isset($astman) && $astman->connected()) {
        $cmd = 'queue reset stats ' . $vars['id'];
        $response = $astman->send_request('Command', array('Command' => $cmd));
        //TODO: freepbx dashboard notification?
    }
} else {
    show_opts();
}
exit;
function show_opts()
예제 #11
0
out("Endpoint Manager Installer");
//define("PHONE_MODULES_PATH", $amp_conf['AMPWEBROOT'] . '/admin/modules/_ep_phone_modules/');
//define("LOCAL_PATH", $amp_conf['AMPWEBROOT'] . '/admin/modules/endpointman/');
if (!file_exists(PHONE_MODULES_PATH)) {
    mkdir(PHONE_MODULES_PATH, 0764);
    out("Creating Phone Modules Directory");
}
if (!file_exists(PHONE_MODULES_PATH . "setup.php")) {
    copy(LOCAL_PATH . "install/setup.php", PHONE_MODULES_PATH . "setup.php");
    out("Moving Auto Provisioner Class");
}
if (!file_exists(PHONE_MODULES_PATH . "temp/")) {
    mkdir(PHONE_MODULES_PATH . "temp/", 0764);
    out("Creating temp folder");
}
$modinfo = module_getinfo('endpointman');
$epmxmlversion = $modinfo['endpointman']['version'];
$epmdbversion = !empty($modinfo['endpointman']['dbversion']) ? $modinfo['endpointman']['dbversion'] : null;
if (!empty($epmdbversion)) {
    if (version_compare_freepbx($epmdbversion, '1.9', '<')) {
        out("Please Wait While we upgrade your old setup");
        //Expand the value option
        $sql = 'ALTER TABLE `endpointman_global_vars` CHANGE `value` `value` VARCHAR(100) CHARACTER SET latin1 COLLATE latin1_swedish_ci NOT NULL COMMENT \'Data\'';
        $db->query($sql);
        out("Locating NMAP + ARP + ASTERISK Executables");
        $nmap = find_exec("nmap");
        $arp = find_exec("arp");
        $asterisk = find_exec("asterisk");
        out("Updating Global Variables table");
        //Add new Vars into database
        $sql_update_vars = "INSERT INTO `endpointman_global_vars` (`idnum`, `var_name`, `value`) VALUES\n\t\t(5, 'config_location', '/tftpboot/'),\n\t\t(6, 'update_server', 'http://mirror.freepbx.org/provisioner/'),\n\t\t(7, 'version', '2.0.0'),\n\t\t(8, 'enable_ari', '0'),\n\t\t(9, 'debug', '0'),\n\t\t(10, 'arp_location', '" . $arp . "'),\n\t\t(11, 'nmap_location', '" . $nmap . "'),\n\t\t(12, 'asterisk_location', '" . $asterisk . "'),\n                (13, 'language', ''),\n                (14, 'check_updates', '1'),\n                (15, 'disable_htaccess', ''),\n                (16, 'endpoint_vers', '0'),\n                (17, 'disable_help', '0')";
예제 #12
0
function module_run_notification_checks()
{
    global $db;
    $modules_needup = module_getinfo(false, MODULE_STATUS_NEEDUPGRADE);
    $modules_broken = module_getinfo(false, MODULE_STATUS_BROKEN);
    $notifications =& notifications::create($db);
    if ($cnt = count($modules_needup)) {
        $text = $cnt > 1 ? sprintf(_('You have %s disabled modules'), $cnt) : _('You have a disabled module');
        $desc = _('The following modules are disabled because they need to be upgraded:') . "\n" . implode(", ", array_keys($modules_needup));
        $desc .= "\n\n" . _('You should go to the module admin page to fix these.');
        $notifications->add_error('freepbx', 'modules_disabled', $text, $desc, '?type=tool&display=modules');
    } else {
        $notifications->delete('freepbx', 'modules_disabled');
    }
    if ($cnt = count($modules_broken)) {
        $text = $cnt > 1 ? sprintf(_('You have %s broken modules'), $cnt) : _('You have a broken module');
        $desc = _('The following modules are disabled because they are broken:') . "\n" . implode(", ", array_keys($modules_broken));
        $desc .= "\n\n" . _('You should go to the module admin page to fix these.');
        $notifications->add_critical('freepbx', 'modules_broken', $text, $desc, '?type=tool&display=modules', false);
    } else {
        $notifications->delete('freepbx', 'modules_broken');
    }
}
예제 #13
0
    public function install()
    {
        global $db;
        global $amp_conf;
        $sql[] = 'CREATE TABLE IF NOT EXISTS `restapi_general` (
		  `keyword` varchar(50),
		  `value` varchar(150) default NULL,
		  UNIQUE KEY `keyword` (`keyword`)
		);';
        $sql[] = 'CREATE TABLE IF NOT EXISTS `restapi_log_event_details` (
		  `id` int(11) default NULL AUTO_INCREMENT,
		  `e_id` int(11) default NULL,
		  `time` int(11) default NULL,
		  `event` varchar(150) default NULL,
		  `data` text,
		  `trigger` text,
		   UNIQUE KEY `id` (`id`),
		   KEY `e_id` (`e_id`)
		);';
        $sql[] = 'CREATE TABLE IF NOT EXISTS `restapi_log_events` (
		  `id` int(11) default NULL AUTO_INCREMENT,
		  `time` int(11) default NULL,
		  `token` varchar(75) default NULL,
		  `signature` varchar(150) default NULL,
		  `ip` varchar(20) default NULL,
		  `server` varchar(75) default NULL,
		   UNIQUE KEY `id` (`id`),
		   KEY `time` (`time`),
		   KEY `token` (`token`)
		);';
        $sql[] = 'CREATE TABLE IF NOT EXISTS `restapi_token_details` (
		  `token_id` int(11) default NULL,
		  `key` varchar(50) default NULL,
		  `value` text default NULL
		);';
        $sql[] = 'CREATE TABLE IF NOT EXISTS `restapi_tokens` (
		  `id` int(11) default NULL AUTO_INCREMENT,
		  `name` varchar(150) default NULL,
		  `desc` varchar(250) default NULL,
		  UNIQUE KEY `id` (`id`)
		);';
        $sql[] = 'CREATE TABLE IF NOT EXISTS `restapi_token_user_mapping` (
		  `user` varchar(25) default NULL,
		  `token_id` int(11) default NULL
		);';
        $firstinstall = false;
        $q = $db->query('SELECT * FROM restapi_general;');
        if (\DB::isError($q)) {
            $firstinstall = true;
            $sql[] = 'INSERT IGNORE INTO `restapi_general` VALUES
			  ("status", "normal"),
			  ("token", "' . restapi_tokens_generate() . '"),
			  ("tokenkey", "' . restapi_tokens_generate() . '");';
        }
        foreach ($sql as $statement) {
            $check = $db->query($statement);
            if (\DB::IsError($check)) {
                die_freepbx("Can not execute {$statement} : " . $check->getMessage() . "\n");
            }
        }
        $sql = "SHOW KEYS FROM restapi_log_event_details WHERE Key_name='e_id'";
        $check = $db->getOne($sql);
        if (empty($check)) {
            $sql = "ALTER TABLE restapi_log_event_details ADD KEY `e_id` (`e_id`)";
            $result = $db->query($sql);
            if (\DB::IsError($result)) {
                out(_("Unable to add index to e_id field in restapi_log_event_details table"));
                freepbx_log(FPBX_LOG_ERROR, "Failed to add index to e_id field in the restapi_log_event_details table");
            } else {
                out(_("Adding index to e_id field in the restapi_log_event_details table"));
            }
        }
        $sql = "SHOW KEYS FROM restapi_log_events WHERE Key_name='time'";
        $check = $db->getOne($sql);
        if (empty($check)) {
            $sql = "ALTER TABLE restapi_log_events ADD KEY `time` (`time`), ADD KEY `token` (`token`)";
            $result = $db->query($sql);
            if (\DB::IsError($result)) {
                out(_("Unable to add index to time field in restapi_log_events table"));
                freepbx_log(FPBX_LOG_ERROR, "Failed to add index to time field in the restapi_log_events table");
            } else {
                out(_("Adding index to time field in the restapi_log_events table"));
            }
        }
        $sql = "SELECT data_type FROM information_schema.columns WHERE table_name = 'restapi_token_details' AND column_name = 'value' AND data_type = 'varchar'";
        $check = $db->getOne($sql);
        if (!empty($check)) {
            $sql = "ALTER TABLE restapi_token_details MODIFY `value` TEXT";
            $result = $db->query($sql);
            if (\DB::IsError($result)) {
                out(_("Unable to modify data type of value field in restapi_token_details table"));
            } else {
                out(_("Modifying data type of value field in the restapi_token_details table"));
            }
        }
        if (!file_exists($amp_conf['AMPWEBROOT'] . '/restapi')) {
            @mkdir($amp_conf['AMPWEBROOT'] . '/restapi');
        }
        if (!file_exists($amp_conf['AMPWEBROOT'] . '/restapi/rest.php')) {
            @symlink(dirname(__FILE__) . '/rest.php', $amp_conf['AMPWEBROOT'] . '/restapi/rest.php');
        }
        $mod_info = module_getinfo('restapi');
        if (!empty($mod_info['restapi']) && version_compare($mod_info['restapi']['dbversion'], '2.11.1.2', '<')) {
            out('Migrating Token Users to User Manager');
            $sql = 'SELECT * FROM restapi_token_user_mapping';
            $users = sql($sql, 'getAll', DB_FETCHMODE_ASSOC);
            if (!empty($users)) {
                $usermapping = array();
                $userman = $this->freepbx->Userman;
                $umusers = array();
                $umusersn = array();
                foreach ($userman->getAllUsers() as $user) {
                    $umusersn[] = $user['username'];
                    if ($user['default_extension'] == 'none') {
                        continue;
                    }
                    $umusers[$user['default_extension']] = $user['id'];
                }
                foreach ($users as $user) {
                    $sql = "SELECT * FROM restapi_tokens WHERE `id` = " . $user['token_id'];
                    $tokenDetails = sql($sql, 'getAll', DB_FETCHMODE_ASSOC);
                    $ucpuser = $user['user'];
                    out('Found Token ' . $tokenDetails[0]['name']);
                    if (empty($usermapping[$user['user']]['id'])) {
                        if (isset($umusers[$user['user']])) {
                            $id = $umusers[$user['user']];
                            $uInfo = $userman->getUserByID($id);
                            try {
                                $userman->updateUser($id, $uInfo['username'], $uInfo['username'], $uInfo['default_extension'], $tokenDetails[0]['desc']);
                            } catch (\Exception $e) {
                                continue;
                            }
                        } else {
                            out('Creating a User Manager User called ' . $ucpuser . ' for token ' . $tokenDetails[0]['name']);
                            try {
                                $output = $userman->addUser($ucpuser, bin2hex(openssl_random_pseudo_bytes(6)), $user['user'], $tokenDetails[0]['desc']);
                            } catch (\Exception $e) {
                                $output['status'] = false;
                            }
                            if (!$output['status']) {
                                out('User confliction detected, attempting to autogenerate a username for token ' . $tokenDetails[0]['name']);
                                try {
                                    $output = $userman->addUser(bin2hex(openssl_random_pseudo_bytes(6)), bin2hex(openssl_random_pseudo_bytes(6)), $user['user'], $tokenDetails[0]['desc']);
                                } catch (\Exception $e) {
                                    $output['status'] = false;
                                }
                                if (!$output['status']) {
                                    out('Username auto generation failed, skipping token ' . $tokenDetails[0]['name']);
                                    continue;
                                }
                            }
                            $id = $output['id'];
                        }
                    } else {
                        out('Adding token ' . $tokenDetails[0]['name'] . ' to  User ' . $ucpuser);
                        $id = $usermapping[$user['user']]['id'];
                    }
                    $sql = "UPDATE restapi_token_user_mapping SET user = '******' WHERE user = '******'user'] . "'";
                    sql($sql);
                    $sql = "SELECT value FROM restapi_token_details WHERE `key` = 'users' AND token_id = " . $user['token_id'];
                    $uljson = sql($sql, 'getOne');
                    $ul = json_decode($uljson, true);
                    if ($ul[0] == "*") {
                        $ul = array();
                        foreach (core_users_list() as $list) {
                            $ul[] = $list[0];
                        }
                    }
                    $devices = $userman->getAssignedDevices($id);
                    $devices = !empty($devices) ? $devices : array();
                    foreach ($ul as $d) {
                        if (!in_array($d, $devices)) {
                            $devices[] = $d;
                        }
                    }
                    out('Attaching devices ' . implode(',', $ul) . ' from token ' . $tokenDetails[0]['name'] . ' to user ' . $ucpuser);
                    $userman->setAssignedDevices($id, $devices);
                    $usermapping[$user['user']]['id'] = $id;
                }
            }
        }
        //migrate to valid settings
        //this needs more work.
        if (function_exists('restapi_user_get_user_tokens') && function_exists('restapi_tokens_put')) {
            $users = $this->userman->getAllUsers();
            foreach ($users as $user) {
                $tokens = \restapi_user_get_user_tokens($user['id']);
                foreach ($tokens as $id => $token) {
                    $data = \restapi_tokens_get($token);
                    if (!empty($data['users']) && in_array("*", $data['users'])) {
                        $data['users'] = array($user['default_extension']);
                        \restapi_tokens_put($data);
                    }
                }
            }
        }
    }
예제 #14
0
	}
	</script>
	<?php 
    echo "<h2>" . _("Module Administration") . "</h2>";
    if ($module_repo == "extended") {
        echo "<h4 align='center'>" . _("NOTICE") . "<br />" . _("You have accessed the extended repository which includes un-supported and third party modules") . "</h4>";
    }
} else {
    // $quietmode==true
    ?>
	<html><head>
		<link href="common/mainstyle.css" rel="stylesheet" type="text/css" />
	</head><body>
	<?php 
}
$modules_local = module_getinfo(false, false, true);
if ($online) {
    $modules_online = module_getonlinexml(false, $repo);
    // $module_getonlinexml_error is a global set by module_getonlinexml()
    if ($module_getonlinexml_error) {
        echo "<div class=\"warning\"><p>" . sprintf(_("Warning: Cannot connect to online repository (%s). Online modules are not available."), "mirror.freepbx.org") . "</p></div><br />";
        $online = 0;
        unset($modules_online);
    } else {
        if (!is_array($modules_online)) {
            echo "<div class=\"warning\"><p>" . sprintf(_("Warning: Error retrieving updates from online repository (%s). Online modules are not available."), "mirror.freepbx.org") . "</p></div><br />";
            $online = 0;
            unset($modules_online);
        } else {
            // combine online and local modules
            $modules = $modules_online;
예제 #15
0
/**
 * Helper function to laod hooks for bootstrap_include_hooks()
 */
function _bootstrap_parse_hooks()
{
    $hooks = array();
    $modules = module_getinfo(false, MODULE_STATUS_ENABLED);
    foreach ($modules as $mymod => $mod) {
        if (isset($mod['bootstrap_hooks'])) {
            foreach ($mod['bootstrap_hooks'] as $type => $type_mods) {
                switch ($type) {
                    case 'pre_module_load':
                    case 'post_module_load':
                        //first get all_mods
                        if (isset($type_mods['all_mods'])) {
                            $hooks[$type]['all_mods'] = isset($hooks[$type]['all_mods']) ? array_merge($hooks[$type]['all_mods'], (array) $type_mods['all_mods']) : (array) $type_mods['all_mods'];
                            unset($type_mods['all_mods']);
                        }
                        if (!isset($type_mods)) {
                            break;
                            //break if there are no more hooks to include
                        }
                        //now load all remaining modules
                        foreach ($type_mods as $type_mod) {
                            $hooks[$type][$mymod] = isset($hooks[$type][$mymod]) ? array_merge($hooks[$type][$mymod], (array) $type_mod) : (array) $type_mod;
                        }
                        break;
                    default:
                        break;
                }
            }
        }
    }
    return $hooks;
}
예제 #16
0
파일: noaccess.php 프로젝트: lidl/framework
<?php

if (empty($display) || $display == 'noaccess') {
    $title = _("Module Not Found");
    $summary = _("We are unable to find any information on the module you are looking for.");
    $links = '';
} else {
    $dis = isset($_REQUEST['display']) ? $_REQUEST['display'] : false;
    $modinfo = \module_getinfo($dis);
    $status = isset($modinfo[$dis]['status']) ? $modinfo[$dis]['status'] : '';
    switch ($status) {
        case MODULE_STATUS_NOTINSTALLED:
            $title = _('Module Not Installed');
            $summary = _("The module appears to be valid but is not currently installed");
            $links = '<li class="list-group-item"><a href="?display=modules">' . _("Go to Module Admin to install this module") . '</a></li>';
            break;
        case MODULE_STATUS_NEEDUPGRADE:
            $title = _('Module Disabled - Needs Upgrade');
            $summary = _("The module you are trying to access has been disabled pending a version change.");
            $links = '<li class="list-group-item"><a href="?display=modules">' . _("Go to Module Admin to re-enable this module") . '</a></li>';
            break;
        case MODULE_STATUS_DISABLED:
            $title = _('Module Disabled');
            $summary = _("The module you are trying to access has been disabled by an admin.");
            $links = '<li class="list-group-item"><a href="?display=modules">' . _("Go to Module Admin to enable this module") . '</a></li>';
            break;
        case MODULE_STATUS_BROKEN:
            $title = _('Module Broken');
            $summary = _("This module appears to be broken");
            $links = '<li class="list-group-item"><a href="#">' . _("This is generally a permissions issue. From a console run 'fwconsole chown'") . '</a></li>';
            $links .= '<li class="list-group-item"><a href="#">' . _("You may wish to redownload this module if the data is corrupted.") . '</a></li>';
예제 #17
0
<?php

$display = isset($_REQUEST['display']) ? $_REQUEST['display'] : false;
$modinfo = \module_getinfo($display);
$status = isset($modinfo[$display]['status']) ? $modinfo[$display]['status'] : '';
switch ($status) {
    case MODULE_STATUS_NOTINSTALLED:
        $title = _('Module Not Installed');
        $summary = _("The module appears to be valid but is not currently installed");
        $links = '<li class="list-group-item"><a href="?display=modules">' . _("Go to Module Admin to install this module") . '</a></li>';
        break;
    case MODULE_STATUS_NEEDUPGRADE:
        $title = _('Module Disabled - Needs Upgrade');
        $summary = _("The module you are trying to access has been disabled pending a version change.");
        $links = '<li class="list-group-item"><a href="?display=modules">' . _("Go to Module Admin to re-enable this module") . '</a></li>';
        break;
    case MODULE_STATUS_DISABLED:
        $title = _('Module Disabled');
        $summary = _("The module you are trying to access has been disabled by an admin.");
        $links = '<li class="list-group-item"><a href="?display=modules">' . _("Go to Module Admin to enable this module") . '</a></li>';
        break;
    case MODULE_STATUS_BROKEN:
        $title = _('Module Broken');
        $summary = _("This module appears to be broken");
        $links = '<li class="list-group-item"><a href="#">' . _("This is generally a permissions issue. From a console run 'fwconsole chown'") . '</a></li>';
        $links .= '<li class="list-group-item"><a href="#">' . _("You may wish to redownload this module if the data is corrupted.") . '</a></li>';
        break;
    case MODULE_STATUS_ENABLED:
        $title = _("Module Access Denied");
        $summary = _("This module appears to be installed and enabled but your user does not seem to have permission to access it.");
        $links = '<li class="list-group-item"><a href="?display=ampusers">' . _("Make sure you have access to this item.") . '</a></li>';