Example #1
0
function queues_get_config($engine)
{
    global $ext;
    // is this the best way to pass this?
    global $queues_conf;
    global $amp_conf;
    global $version;
    switch ($engine) {
        case "asterisk":
            global $astman;
            $ast_ge_14 = version_compare($version, '1.4', 'ge');
            $ast_ge_16 = version_compare($version, '1.6', 'ge');
            $ast_ge_14_25 = version_compare($version, '1.4.25', 'ge');
            $has_extension_state = $ast_ge_16;
            if ($ast_ge_14 && !$ast_ge_16) {
                $response = $astman->send_request('Command', array('Command' => 'module show like func_extstate'));
                if (preg_match('/1 modules loaded/', $response['data'])) {
                    $has_extension_state = true;
                }
            }
            if (isset($queues_conf) && is_a($queues_conf, "queues_conf")) {
                $queues_conf->addQueuesGeneral('persistentmembers', 'yes');
            }
            /* queue extensions */
            $ext->addInclude('from-internal-additional', 'ext-queues');
            /* Trial DEVSTATE */
            if ($amp_conf['USEDEVSTATE']) {
                $ext->addGlobal('QUEDEVSTATE', 'TRUE');
            }
            // $que_code = '*45';
            $fcc = new featurecode('queues', 'que_toggle');
            $que_code = $fcc->getCodeActive();
            unset($fcc);
            if ($que_code != '') {
                queue_app_toggle($que_code);
                queue_agent_del_toggle();
                queue_agent_add_toggle();
            }
            $qlist = queues_list(true);
            $from_queue_exten_only = 'from-queue-exten-only';
            $from_queue_exten_internal = 'from-queue-exten-internal';
            if (is_array($qlist)) {
                foreach ($qlist as $item) {
                    $exten = $item[0];
                    $q = queues_get($exten);
                    $grppre = isset($q['prefix']) ? $q['prefix'] : '';
                    $alertinfo = isset($q['alertinfo']) ? $q['alertinfo'] : '';
                    // Not sure why someone would ever have a ; in the regex, but since Asterisk has problems with them
                    // it would need to be escaped
                    //
                    $qregex = isset($q['qregex']) ? $q['qregex'] : '';
                    str_replace(';', '\\;', $qregex);
                    $ext->add('ext-queues', $exten, '', new ext_macro('user-callerid'));
                    $ext->add('ext-queues', $exten, '', new ext_answer(''));
                    // block voicemail until phone is answered at which point a macro should be called on the answering
                    // line to clear this flag so that subsequent transfers can occur.
                    //
                    if ($q['queuewait']) {
                        $ext->add('ext-queues', $exten, '', new ext_execif('$["${QUEUEWAIT}" = ""]', 'Set', '__QUEUEWAIT=${EPOCH}'));
                    }
                    // If extension_only don't do this and CFIGNORE
                    if ($q['use_queue_context'] != '2') {
                        $ext->add('ext-queues', $exten, '', new ext_setvar('__BLKVM_OVERRIDE', 'BLKVM/${EXTEN}/${CHANNEL}'));
                        $ext->add('ext-queues', $exten, '', new ext_setvar('__BLKVM_BASE', '${EXTEN}'));
                        $ext->add('ext-queues', $exten, '', new ext_setvar('DB(${BLKVM_OVERRIDE})', 'TRUE'));
                        $ext->add('ext-queues', $exten, '', new ext_execif('$["${REGEX("(M[(]auto-blkvm[)])" ${DIAL_OPTIONS})}" != "1"]', 'Set', '_DIAL_OPTIONS=${DIAL_OPTIONS}M(auto-blkvm)'));
                    }
                    // Inform all the children NOT to send calls to destinations or voicemail
                    //
                    $ext->add('ext-queues', $exten, '', new ext_setvar('__NODEST', '${EXTEN}'));
                    // deal with group CID prefix
                    // Use the same variable as ringgroups/followme so that we can manage chaines of calls
                    // but strip only if you plan on setting a new one
                    //
                    if ($grppre != '') {
                        $ext->add('ext-queues', $exten, '', new ext_gotoif('$["foo${RGPREFIX}" = "foo"]', 'REPCID'));
                        $ext->add('ext-queues', $exten, '', new ext_gotoif('$["${RGPREFIX}" != "${CALLERID(name):0:${LEN(${RGPREFIX})}}"]', 'REPCID'));
                        $ext->add('ext-queues', $exten, '', new ext_noop('Current RGPREFIX is ${RGPREFIX}....stripping from Caller ID'));
                        $ext->add('ext-queues', $exten, '', new ext_setvar('CALLERID(name)', '${CALLERID(name):${LEN(${RGPREFIX})}}'));
                        $ext->add('ext-queues', $exten, '', new ext_setvar('_RGPREFIX', ''));
                        $ext->add('ext-queues', $exten, 'REPCID', new ext_noop('CALLERID(name) is ${CALLERID(name)}'));
                        $ext->add('ext-queues', $exten, '', new ext_setvar('_RGPREFIX', $grppre));
                        $ext->add('ext-queues', $exten, '', new ext_setvar('CALLERID(name)', '${RGPREFIX}${CALLERID(name)}'));
                    }
                    // Set Alert_Info
                    if ($alertinfo != '') {
                        $ext->add('ext-queues', $exten, '', new ext_setvar('__ALERT_INFO', str_replace(';', '\\;', $alertinfo)));
                    }
                    $ext->add('ext-queues', $exten, '', new ext_setvar('MONITOR_FILENAME', '/var/spool/asterisk/monitor/q${EXTEN}-${STRFTIME(${EPOCH},,%Y%m%d-%H%M%S)}-${UNIQUEID}'));
                    $joinannounce_id = isset($q['joinannounce_id']) ? $q['joinannounce_id'] : '';
                    if ($joinannounce_id) {
                        $joinannounce = recordings_get_file($joinannounce_id);
                        $ext->add('ext-queues', $exten, '', new ext_playback($joinannounce));
                    }
                    $options = 't';
                    if ($q['rtone'] == 1) {
                        $options .= 'r';
                    }
                    if ($q['retry'] == 'none') {
                        $options .= 'n';
                    }
                    if (isset($q['music'])) {
                        $ext->add('ext-queues', $exten, '', new ext_setvar('__MOHCLASS', $q['music']));
                    }
                    // Set CWIGNORE  if enabled so that busy agents don't have another line key ringing and
                    // stalling the ACD.
                    if ($q['cwignore'] == 1 || $q['cwignore'] == 2) {
                        $ext->add('ext-queues', $exten, '', new ext_setvar('__CWIGNORE', 'TRUE'));
                    }
                    if ($q['use_queue_context']) {
                        $ext->add('ext-queues', $exten, '', new ext_setvar('__CFIGNORE', 'TRUE'));
                        $ext->add('ext-queues', $exten, '', new ext_setvar('__FORWARD_CONTEXT', 'block-cf'));
                    }
                    $agentannounce_id = isset($q['agentannounce_id']) ? $q['agentannounce_id'] : '';
                    if ($agentannounce_id) {
                        $agentannounce = recordings_get_file($agentannounce_id);
                    } else {
                        $agentannounce = '';
                    }
                    $ext->add('ext-queues', $exten, '', new ext_queue($exten, $options, '', $agentannounce, $q['maxwait']));
                    if ($q['use_queue_context'] != '2') {
                        $ext->add('ext-queues', $exten, '', new ext_dbdel('${BLKVM_OVERRIDE}'));
                    }
                    // If we are here, disable the NODEST as we want things to resume as normal
                    //
                    $ext->add('ext-queues', $exten, '', new ext_setvar('__NODEST', ''));
                    if ($q['cwignore'] == 1 || $q['cwignore'] == 2) {
                        $ext->add('ext-queues', $exten, '', new ext_setvar('__CWIGNORE', ''));
                    }
                    if ($q['use_queue_context']) {
                        $ext->add('ext-queues', $exten, '', new ext_setvar('__CFIGNORE', ''));
                        $ext->add('ext-queues', $exten, '', new ext_setvar('__FORWARD_CONTEXT', 'from-internal'));
                    }
                    // destination field in 'incoming' database is backwards from what ext_goto expects
                    $goto_context = strtok($q['goto'], ',');
                    $goto_exten = strtok(',');
                    $goto_pri = strtok(',');
                    $ext->add('ext-queues', $exten, '', new ext_goto($goto_pri, $goto_exten, $goto_context));
                    //dynamic agent login/logout
                    if (trim($qregex) != '') {
                        $ext->add('ext-queues', $exten . "*", '', new ext_setvar('QREGEX', $qregex));
                    }
                    if ($q['use_queue_context'] == '2') {
                        $ext->add('ext-queues', $exten . "*", '', new ext_macro('agent-add', $exten . "," . $q['password'] . ",EXTEN"));
                    } else {
                        $ext->add('ext-queues', $exten . "*", '', new ext_macro('agent-add', $exten . "," . $q['password']));
                    }
                    $ext->add('ext-queues', $exten . "**", '', new ext_macro('agent-del', "{$exten}"));
                    if ($que_code != '') {
                        $ext->add('ext-queues', $que_code . $exten, '', new ext_setvar('QUEUENO', $exten));
                        $ext->add('ext-queues', $que_code . $exten, '', new ext_goto('start', 's', 'app-queue-toggle'));
                    }
                    /* Trial Devstate */
                    // Create Hints for Devices and Add Astentries for Users
                    // Clean up the Members array
                    if ($q['togglehint'] && $amp_conf['USEDEVSTATE'] && $que_code != '') {
                        if (!isset($device_list)) {
                            $device_list = core_devices_list("all", 'full', true);
                        }
                        if ($astman) {
                            if (($dynmemberonly = strtolower($astman->database_get('QPENALTY/' . $exten, 'dynmemberonly')) == 'yes') == true) {
                                $get = $astman->database_show('QPENALTY/' . $exten . '/agents');
                                if ($get) {
                                    $mem = array();
                                    foreach ($get as $key => $value) {
                                        $key = explode('/', $key);
                                        $mem[$key[4]] = $value;
                                    }
                                }
                            }
                        } else {
                            fatal("Cannot connect to Asterisk Manager with " . $amp_conf["AMPMGRUSER"] . "/" . $amp_conf["AMPMGRPASS"]);
                        }
                        foreach ($device_list as $device) {
                            if ((!$dynmemberonly || $device['devicetype'] == 'adhoc' || isset($mem[$device['user']])) && ($device['tech'] == 'sip' || $device['tech'] == 'iax2')) {
                                $ext->add('ext-queues', $que_code . $device['id'] . '*' . $exten, '', new ext_setvar('QUEUENO', $exten));
                                $ext->add('ext-queues', $que_code . $device['id'] . '*' . $exten, '', new ext_goto('start', 's', 'app-queue-toggle'));
                                $ext->addHint('ext-queues', $que_code . $device['id'] . '*' . $exten, "Custom:QUEUE" . $device['id'] . '*' . $exten);
                            }
                        }
                    }
                    // Add routing vector to direct which context call should go
                    //
                    $agent_context = $q['use_queue_context'] ? $queue_context : 'from-internal';
                    switch ($q['use_queue_context']) {
                        case 1:
                            $agent_context = $from_queue_exten_internal;
                            break;
                        case 2:
                            $agent_context = $from_queue_exten_only;
                            break;
                        case 0:
                        default:
                            $agent_context = 'from-internal';
                            break;
                    }
                    $ext->add('from-queue', $exten, '', new ext_goto('1', '${QAGENT}', $agent_context));
                }
            }
            // We need to have a hangup here, if call is ended by the caller during Playback it will end in the
            // h context and do a proper hangup and clean the BLKVM, see #4671
            $ext->add('ext-queues', 'h', '', new ext_macro('hangupcall'));
            // NODEST will be the queue that this came from, so we will vector though an entry to determine the context the
            // agent should be delivered to. All queue calls come here, this decides if the should go direct to from-internal
            // or indirectly through from-queue-exten-only to trap extension calls and avoid their follow-me, etc.
            //
            $ext->add('from-queue', '_.', '', new ext_setvar('QAGENT', '${EXTEN}'));
            $ext->add('from-queue', '_.', '', new ext_goto('1', '${NODEST}'));
            $ext->addInclude($from_queue_exten_internal, $from_queue_exten_only);
            $ext->addInclude($from_queue_exten_internal, 'from-internal');
            $ext->add($from_queue_exten_internal, 'foo', '', new ext_noop('bar'));
            /* create a context, from-queue-exten-only, that can be used for queues that want behavir similar to
             * ringgroup where only the agent's phone will be rung, no follow-me will be pursued.
             */
            $userlist = core_users_list();
            if (is_array($userlist)) {
                foreach ($userlist as $item) {
                    $ext->add($from_queue_exten_only, $item[0], '', new ext_setvar('RingGroupMethod', 'none'));
                    $ext->add($from_queue_exten_only, $item[0], '', new ext_macro('record-enable', $item[0] . ",IN"));
                    if ($has_extension_state) {
                        $ext->add($from_queue_exten_only, $item[0], '', new ext_macro('dial-one', ',${DIAL_OPTIONS},' . $item[0]));
                    } else {
                        $ext->add($from_queue_exten_only, $item[0], '', new ext_macro('dial', ',${DIAL_OPTIONS},' . $item[0]));
                    }
                    $ext->add($from_queue_exten_only, $item[0], '', new ext_hangup());
                }
                $ext->add($from_queue_exten_only, 'h', '', new ext_macro('hangupcall'));
            }
            /*
             * Adds a dynamic agent/member to a Queue
             * Prompts for call-back number - in not entered, uses CIDNum
             */
            $context = 'macro-agent-add';
            $exten = 's';
            $ext->add($context, $exten, '', new ext_wait(1));
            $ext->add($context, $exten, '', new ext_macro('user-callerid', 'SKIPTTL'));
            $ext->add($context, $exten, 'a3', new ext_read('CALLBACKNUM', 'agent-login'));
            // get callback number from user
            $ext->add($context, $exten, '', new ext_gotoif('$[${LEN(${CALLBACKNUM})}=0]', 'a5', 'a7'));
            // if user just pressed # or timed out, use cidnum
            $ext->add($context, $exten, 'a5', new ext_set('CALLBACKNUM', '${IF($[${LEN(${AMPUSER})}=0]?${CALLERID(number)}:${AMPUSER})}'));
            if ($ast_ge_14_25) {
                $ext->add($context, $exten, '', new ext_set('THISDEVICE', '${DB(DEVICE/${REALCALLERIDNUM}/dial)}'));
            }
            $ext->add($context, $exten, '', new ext_gotoif('$["${CALLBACKNUM}" = ""]', 'a3'));
            // if still no number, start over
            $ext->add($context, $exten, 'a7', new ext_gotoif('$["${CALLBACKNUM}" = "${ARG1}"]', 'invalid'));
            // Error, they put in the queue number
            // If this is an extension only queue then EXTEN is passed as ARG3 and we make sure this is a valid extension being entered
            //
            $ext->add($context, $exten, '', new ext_gotoif('$["${ARG3}" = "EXTEN" & ${DB_EXISTS(AMPUSER/${CALLBACKNUM}/cidname)} = 0]', 'invalid'));
            // If this is a restricted dynamic agent queue then check to make sure they are allowed
            //
            $ext->add($context, $exten, '', new ext_gotoif('$["${DB(QPENALTY/${ARG1}/dynmemberonly)}" = "yes" & ${DB_EXISTS(QPENALTY/${ARG1}/agents/${CALLBACKNUM})} != 1]', 'invalid'));
            $ext->add($context, $exten, '', new ext_execif('$["${QREGEX}" != ""]', 'GotoIf', '$["${REGEX("${QREGEX}" ${CALLBACKNUM})}" = "0"]?invalid'));
            $ext->add($context, $exten, '', new ext_execif('$["${ARG2}" != ""]', 'Authenticate', '${ARG2}'));
            if ($amp_conf['USEQUEUESTATE']) {
                $ext->add($context, $exten, '', new ext_execif('$[${DB_EXISTS(AMPUSER/${CALLBACKNUM}/cidname)} = 1]', 'AddQueueMember', '${ARG1},Local/${CALLBACKNUM}@from-queue/n,${DB(QPENALTY/${ARG1}/agents/${CALLBACKNUM})},,${DB(AMPUSER/${CALLBACKNUM}/cidname)},hint:${CALLBACKNUM}@ext-local'));
                $ext->add($context, $exten, '', new ext_execif('$[${DB_EXISTS(AMPUSER/${CALLBACKNUM}/cidname)} = 0]', 'AddQueueMember', '${ARG1},Local/${CALLBACKNUM}@from-queue/n,${DB(QPENALTY/${ARG1}/agents/${CALLBACKNUM})}'));
            } else {
                if ($ast_ge_14_25) {
                    $ext->add($context, $exten, '', new ext_set('THISDEVICE', '${IF($[${LEN(${THISDEVICE})}=0]?${DB(DEVICE/${CUT(DB(AMPUSER/${CALLBACKNUM}/device),&,1)}/dial)}:${THISDEVICE})}'));
                    $ext->add($context, $exten, '', new ext_execif('$[${LEN(${THISDEVICE})}!=0]', 'AddQueueMember', '${ARG1},Local/${CALLBACKNUM}@from-queue/n,${DB(QPENALTY/${ARG1}/agents/${CALLBACKNUM})},,${DB(AMPUSER/${CALLBACKNUM}/cidname)},${THISDEVICE}'));
                    $ext->add($context, $exten, '', new ext_execif('$[${LEN(${THISDEVICE})}=0]', 'AddQueueMember', '${ARG1},Local/${CALLBACKNUM}@from-queue/n,${DB(QPENALTY/${ARG1}/agents/${CALLBACKNUM})}'));
                } else {
                    $ext->add($context, $exten, 'a9', new ext_addqueuemember('${ARG1}', 'Local/${CALLBACKNUM}@from-queue/n,${DB(QPENALTY/${ARG1}/agents/${CALLBACKNUM})}'));
                }
            }
            $ext->add($context, $exten, '', new ext_userevent('Agentlogin', 'Agent: ${CALLBACKNUM}'));
            $ext->add($context, $exten, '', new ext_wait(1));
            $ext->add($context, $exten, '', new ext_playback('agent-loginok&with&extension'));
            $ext->add($context, $exten, '', new ext_saydigits('${CALLBACKNUM}'));
            $ext->add($context, $exten, '', new ext_hangup());
            $ext->add($context, $exten, '', new ext_macroexit());
            $ext->add($context, $exten, 'invalid', new ext_playback('pbx-invalid'));
            $ext->add($context, $exten, '', new ext_goto('a3'));
            /*
             * Removes a dynamic agent/member from a Queue
             * Prompts for call-back number - in not entered, uses CIDNum 
             */
            $context = 'macro-agent-del';
            $ext->add($context, $exten, '', new ext_wait(1));
            $ext->add($context, $exten, '', new ext_macro('user-callerid', 'SKIPTTL'));
            $ext->add($context, $exten, 'a3', new ext_read('CALLBACKNUM', 'agent-logoff'));
            // get callback number from user
            $ext->add($context, $exten, '', new ext_gotoif('$[${LEN(${CALLBACKNUM})}=0]', 'a5', 'a7'));
            // if user just pressed # or timed out, use cidnum
            $ext->add($context, $exten, 'a5', new ext_set('CALLBACKNUM', '${IF($[${LEN(${AMPUSER})}=0]?${CALLERID(number)}:${AMPUSER})}'));
            $ext->add($context, $exten, '', new ext_gotoif('$["${CALLBACKNUM}" = ""]', 'a3'));
            // if still no number, start over
            // remove from both contexts in case left over dynamic agents after an upgrade
            $ext->add($context, $exten, 'a7', new ext_removequeuemember('${ARG1}', 'Local/${CALLBACKNUM}@from-queue/n'));
            $ext->add($context, $exten, '', new ext_removequeuemember('${ARG1}', 'Local/${CALLBACKNUM}@from-internal/n'));
            $ext->add($context, $exten, '', new ext_userevent('RefreshQueue'));
            $ext->add($context, $exten, '', new ext_wait(1));
            $ext->add($context, $exten, '', new ext_playback('agent-loggedoff'));
            $ext->add($context, $exten, '', new ext_hangup());
            break;
    }
}
Example #2
0
function queues_get_config($engine)
{
    global $ext;
    // is this the best way to pass this?
    global $amp_conf;
    global $version;
    $queues_conf = queues_conf::create();
    switch ($engine) {
        case "asterisk":
            global $astman;
            //set our reset cron
            queues_set_backup_cron();
            $ast_ge_14 = version_compare($version, '1.4', 'ge');
            $ast_ge_16 = version_compare($version, '1.6', 'ge');
            $ast_ge_14_25 = version_compare($version, '1.4.25', 'ge');
            $ast_ge_18 = version_compare($version, '1.8', 'ge');
            $ast_ge_11 = version_compare($version, '11', 'ge');
            $ast_ge_12 = version_compare($version, '12', 'ge');
            $has_extension_state = $ast_ge_16;
            if ($ast_ge_14 && !$ast_ge_16) {
                $response = $astman->send_request('Command', array('Command' => 'module show like func_extstate'));
                if (preg_match('/1 modules loaded/', $response['data'])) {
                    $has_extension_state = true;
                }
            }
            if (isset($queues_conf) && is_a($queues_conf, "queues_conf")) {
                $queues_conf->addQueuesGeneral('persistentmembers', $amp_conf['QUEUES_PESISTENTMEMBERS'] ? 'yes' : 'no');
                if ($ast_ge_16) {
                    $queues_conf->addQueuesGeneral('shared_lastcall', $amp_conf['QUEUES_SHARED_LASTCALL'] ? 'yes' : 'no');
                    $queues_conf->addQueuesGeneral('updatecdr', $amp_conf['QUEUES_UPDATECDR'] ? 'yes' : 'no');
                }
                if ($amp_conf['QUEUES_MIX_MONITOR']) {
                    $queues_conf->addQueuesGeneral('monitor-type', 'MixMonitor');
                }
            }
            /* queue extensions */
            $ext->addInclude('from-internal-additional', 'ext-queues');
            /* Trial DEVSTATE */
            $ext->addGlobal('QUEDEVSTATE', 'TRUE');
            $qlist = queues_list(true);
            if (empty($qlist)) {
                return;
                //nothing to do if we dont have any queues
            }
            // $que_code = '*45';
            $fcc = new featurecode('queues', 'que_toggle');
            $que_code = $fcc->getCodeActive();
            unset($fcc);
            if ($que_code != '') {
                queue_app_toggle();
                queue_app_all_toggle();
                queue_agent_del_toggle();
                queue_agent_add_toggle();
                $ext->addGlobal('QUEUETOGGLE', $que_code);
            }
            // $que_pause_code = '*46';
            $fcc = new featurecode('queues', 'que_pause_toggle');
            $que_pause_code = $fcc->getCodeActive();
            unset($fcc);
            if ($que_pause_code != '') {
                app_queue_pause_toggle();
                app_all_queue_pause_toggle();
                $ext->addGlobal('QUEUEPAUSETOGGLE', $que_pause_code);
            }
            // $que_callers_code = '*47';
            $fcc = new featurecode('queues', 'que_callers');
            $que_callers_code = $fcc->getCodeActive();
            unset($fcc);
            $from_queue_exten_only = 'from-queue-exten-only';
            $from_queue_exten_internal = 'from-queue-exten-internal';
            $qmembers = array();
            $hint_hash = array();
            $qlist = is_array($qlist) ? $qlist : array();
            foreach ($qlist as $item) {
                $exten = $item[0];
                $q = queues_get($exten);
                $c = 'ext-queues';
                $grppre = isset($q['prefix']) ? $q['prefix'] : '';
                $alertinfo = isset($q['alertinfo']) ? $q['alertinfo'] : '';
                // Not sure why someone would ever have a ; in the regex, but since Asterisk has problems with them
                // it would need to be escaped
                $qregex = isset($q['qregex']) ? $q['qregex'] : '';
                str_replace(';', '\\;', $qregex);
                $ext->add($c, $exten, '', new ext_macro('user-callerid'));
                if (isset($q['qnoanswer']) && $q['qnoanswer'] == FALSE) {
                    $ext->add($c, $exten, '', new ext_answer(''));
                } else {
                    // TODO: should this only be set if noanswer + (!ringtones || joinannounce)???
                    $ext->add($c, $exten, '', new ext_progress());
                }
                // block voicemail until phone is answered at which point a macro should be called on the answering
                // line to clear this flag so that subsequent transfers can occur.
                if ($q['queuewait']) {
                    $ext->add($c, $exten, '', new ext_execif('$["${QUEUEWAIT}" = ""]', 'Set', '__QUEUEWAIT=${EPOCH}'));
                }
                // If extension_only don't do this and CFIGNORE
                if ($q['use_queue_context'] != '2') {
                    $ext->add($c, $exten, '', new ext_macro('blkvm-set', 'reset'));
                    $ext->add($c, $exten, '', new ext_execif('$["${REGEX("(M[(]auto-blkvm[)])" ${DIAL_OPTIONS})}" != "1"]', 'Set', '_DIAL_OPTIONS=${DIAL_OPTIONS}M(auto-blkvm)'));
                }
                // Inform all the children NOT to send calls to destinations or voicemail
                //
                $ext->add($c, $exten, '', new ext_setvar('__NODEST', '${EXTEN}'));
                /*
                 * Virtual Queue Settings, dialplan designed so these can be changed by other modules and those changes
                 * will override the configured changes here.
                 */
                // deal with group CID prefix
                $ext->add($c, $exten, '', new ext_set('QCIDPP', '${IF($[${LEN(${VQ_CIDPP})}>0]?${VQ_CIDPP}' . ':' . ($grppre == '' ? ' ' : $grppre) . ')}'));
                $ext->add($c, $exten, '', new ext_set('VQ_CIDPP', ''));
                $ext->add($c, $exten, '', new ext_execif('$["${QCIDPP}"!=""]', 'Macro', 'prepend-cid,${QCIDPP}'));
                // Set Alert_Info
                $ainfo = $alertinfo != '' ? str_replace(';', '\\;', $alertinfo) : ' ';
                $ext->add($c, $exten, '', new ext_set('QAINFO', '${IF($[${LEN(${VQ_AINFO})}>0]?${VQ_AINFO}:' . $ainfo . ')}'));
                $ext->add($c, $exten, '', new ext_set('VQ_AINFO', ''));
                $ext->add($c, $exten, '', new ext_execif('$["${QAINFO}"!=""]', 'Set', '__ALERT_INFO=${QAINFO}'));
                $joinannounce_id = isset($q['joinannounce_id']) ? $q['joinannounce_id'] : '';
                $joinannounce = $joinannounce_id ? recordings_get_file($joinannounce_id) : ' ';
                $joinansw = isset($q['qnoanswer']) && $q['qnoanswer'] == TRUE ? 'noanswer' : '';
                $cplay = $q['skip_joinannounce'] ? ' && ${QUEUE_MEMBER(' . $exten . ',' . $q['skip_joinannounce'] . ')}<1' : '';
                $ext->add($c, $exten, '', new ext_set('QJOINMSG', '${IF($[${LEN(${VQ_JOINMSG})}>0]?${IF($["${VQ_JOINMSG}"!="0"]?${VQ_JOINMSG}: )}:' . $joinannounce . ')}'));
                $ext->add($c, $exten, '', new ext_set('VQ_JOINMSG', ''));
                $options = 't';
                if (isset($q['answered_elsewhere']) && $q['answered_elsewhere'] == '1') {
                    $ext->add($c, $exten, '', new ext_set('QCANCELMISSED', 'C'));
                }
                if ($q['rtone'] == 1) {
                    $qringopts = 'r';
                } else {
                    if ($q['rtone'] == 2) {
                        $qringopts = 'R';
                    } else {
                        $qringopts = '';
                    }
                }
                if ($qringopts) {
                    $ext->add($c, $exten, '', new ext_set('QRINGOPTS', $qringopts));
                }
                $qretry = $q['retry'] == 'none' ? 'n' : ' ';
                $ext->add($c, $exten, '', new ext_set('QRETRY', '${IF($[${LEN(${VQ_RETRY})}>0]?${VQ_RETRY}:' . $qretry . ')}'));
                $ext->add($c, $exten, '', new ext_set('VQ_RETRY', ''));
                $ext->add($c, $exten, 'qoptions', new ext_set('QOPTIONS', '${IF($[${LEN(${VQ_OPTIONS})}>0]?${VQ_OPTIONS}:' . ($options != '' ? $options : ' ') . ')}${QCANCELMISSED}${QRINGOPTS}${QRETRY}'));
                $ext->add($c, $exten, '', new ext_set('VQ_OPTIONS', ''));
                // Set these up to be easily spliced into if we want to configure ability in queue modules
                //
                $ext->add($c, $exten, 'qgosub', new ext_set('QGOSUB', '${IF($[${LEN(${VQ_GOSUB})}>0]?${VQ_GOSUB}:${QGOSUB})}'));
                $ext->add($c, $exten, '', new ext_set('VQ_GOSUB', ''));
                $ext->add($c, $exten, 'qagi', new ext_set('QAGI', '${IF($[${LEN(${VQ_AGI})}>0]?${VQ_AGI}:${QAGI})}'));
                $ext->add($c, $exten, '', new ext_set('VQ_AGI', ''));
                $ext->add($c, $exten, 'qrule', new ext_set('QRULE', '${IF($[${LEN(${VQ_RULE})}>0]?${IF($["${VQ_RULE}"!="0"]?${VQ_RULE}: )}:${QRULE})}'));
                $ext->add($c, $exten, '', new ext_set('VQ_RULE', ''));
                $ext->add($c, $exten, 'qposition', new ext_set('QPOSITION', '${IF($[${LEN(${VQ_POSITION})}>0]?${VQ_POSITION}:${QPOSITION})}'));
                $ext->add($c, $exten, '', new ext_set('VQ_POSITION', ''));
                if (!isset($q['recording']) || empty($q['recording'])) {
                    $record_mode = 'dontcare';
                } else {
                    $record_mode = $q['recording'];
                }
                if ($amp_conf['QUEUES_MIX_MONITOR']) {
                    $monitor_options = '';
                    if (isset($q['monitor_type']) && $q['monitor_type'] != '') {
                        $monitor_options .= 'b';
                    }
                    if (isset($q['monitor_spoken']) && $q['monitor_spoken'] != 0) {
                        $monitor_options .= 'V(' . $q['monitor_spoken'] . ')';
                    }
                    if (isset($q['monitor_heard']) && $q['monitor_heard'] != 0) {
                        $monitor_options .= 'v(' . $q['monitor_heard'] . ')';
                    }
                    if ($monitor_options != '') {
                        $ext->add($c, $exten, '', new ext_setvar('MONITOR_OPTIONS', $monitor_options));
                    }
                }
                $ext->add($c, $exten, '', new ext_gosub('1', 's', 'sub-record-check', "q,{$exten},{$record_mode}"));
                // Set CWIGNORE  if enabled so that busy agents don't have another line key ringing and
                // stalling the ACD.
                if ($q['cwignore'] == 1 || $q['cwignore'] == 2) {
                    $ext->add($c, $exten, '', new ext_setvar('__CWIGNORE', 'TRUE'));
                }
                if ($q['use_queue_context']) {
                    $ext->add($c, $exten, '', new ext_setvar('__CFIGNORE', 'TRUE'));
                    $ext->add($c, $exten, '', new ext_setvar('__FORWARD_CONTEXT', 'block-cf'));
                }
                $agentannounce_id = isset($q['agentannounce_id']) ? $q['agentannounce_id'] : '';
                if ($agentannounce_id) {
                    $agentannounce = recordings_get_file($agentannounce_id);
                } else {
                    $agentannounce = ' ';
                }
                if ($q['callconfirm'] == 1) {
                    $ext->add($c, $exten, '', new ext_setvar('__FORCE_CONFIRM', '${CHANNEL}'));
                    if ($amp_conf['AST_FUNC_SHARED']) {
                        $ext->add($c, $exten, '', new ext_setvar('SHARED(ANSWER_STATUS)', 'NOANSWER'));
                    }
                    $ext->add($c, $exten, '', new ext_setvar('__CALLCONFIRMCID', '${CALLERID(number)}'));
                    $callconfirm_id = isset($q['callconfirm_id']) ? $q['callconfirm_id'] : '';
                    if ($callconfirm_id) {
                        $callconfirm = recordings_get_file($callconfirm_id);
                    } else {
                        $callconfirm = ' ';
                    }
                    $ext->add($c, $exten, '', new ext_set('__ALT_CONFIRM_MSG', '${IF($[${LEN(${VQ_CONFIRMMSG})}>0]?${IF($["${VQ_CONFIRMMSG}"!="0"]?${VQ_CONFIRMMSG}: )}:' . $callconfirm . ')}'));
                    $ext->add($c, $exten, '', new ext_set('VQ_CONFIRMMSG', ''));
                }
                $ext->add($c, $exten, '', new ext_execif('$["${QJOINMSG}"!=""' . $cplay . ']', 'Playback', '${QJOINMSG}, ' . $joinansw));
                $ext->add($c, $exten, '', new ext_queuelog($exten, '${UNIQUEID}', 'NONE', 'DID', '${FROM_DID}'));
                $ext->add($c, $exten, '', new ext_set('QAANNOUNCE', '${IF($[${LEN(${VQ_AANNOUNCE})}>0]?${IF($["${VQ_AANNOUNCE}"!="0"]?${VQ_AANNOUNCE}: )}:' . $agentannounce . ')}'));
                $ext->add($c, $exten, '', new ext_set('VQ_AANNOUNCE', ''));
                $agnc = '${QAANNOUNCE}';
                $qmoh = isset($q['music']) && $q['music'] != '' ? $q['music'] : ' ';
                $ext->add($c, $exten, '', new ext_set('QMOH', '${IF($["${VQ_MOH}"!=""]?${VQ_MOH}:' . $qmoh . ')}'));
                $ext->add($c, $exten, '', new ext_set('VQ_MOH', ''));
                $ext->add($c, $exten, '', new ext_execif('$["${QMOH}"!=""]', 'Set', '__MOHCLASS=${QMOH}'));
                $ext->add($c, $exten, '', new ext_execif('$["${MOHCLASS}"!=""]', 'Set', 'CHANNEL(musicclass)=${MOHCLASS}'));
                $ext->add($c, $exten, '', new ext_set('QMAXWAIT', '${IF($[${LEN(${VQ_MAXWAIT})}>0]?${VQ_MAXWAIT}:' . ($q['maxwait'] != '' ? $q['maxwait'] : ' ') . ')}'));
                $ext->add($c, $exten, '', new ext_set('VQ_MAXWAIT', ''));
                $ext->add($c, $exten, '', new ext_set('QUEUENUM', $exten));
                $ext->add($c, $exten, '', new ext_set('QUEUEJOINTIME', '${EPOCH}'));
                $qmaxwait = '${QMAXWAIT}';
                $options = '${QOPTIONS}';
                $qagi = '${QAGI}';
                $qmacro = '';
                $qgosub = '${QGOSUB}';
                $qrule = '${QRULE}';
                $qposition = '${QPOSITION}';
                // Queue(queuename[,options[,URL[,announceoverride[,timeout[,AGI[,macro[,gosub[,rule[,position]]]]]]]]])
                //
                $ext->add($c, $exten, 'qcall', new ext_queue($exten, $options, '', $agnc, $qmaxwait, $qagi, $qmacro, $qgosub, $qrule, $qposition));
                if ($q['use_queue_context'] != '2') {
                    $ext->add($c, $exten, '', new ext_macro('blkvm-clr'));
                }
                // cancel any recording previously requested
                $ext->add($c, $exten, '', new ext_gosub('1', 's', 'sub-record-cancel'));
                // If we are here, disable the NODEST as we want things to resume as normal
                $ext->add($c, $exten, '', new ext_setvar('__NODEST', ''));
                $ext->add($c, $exten, '', new ext_setvar('_QUEUE_PRIO', '0'));
                if ($q['callconfirm'] == 1) {
                    if ($amp_conf['AST_FUNC_SHARED']) {
                        $ext->add($c, $exten, '', new ext_setvar('SHARED(ANSWER_STATUS)', ''));
                    }
                    $ext->add($c, $exten, '', new ext_setvar('__FORCE_CONFIRM', ''));
                    $ext->add($c, $exten, '', new ext_setvar('__ALT_CONFIRM_MSG', ''));
                }
                if ($monitor_options != '') {
                    $ext->add($c, $exten, '', new ext_setvar('MONITOR_OPTIONS', ''));
                }
                if ($q['cwignore'] == 1 || $q['cwignore'] == 2) {
                    $ext->add($c, $exten, '', new ext_setvar('__CWIGNORE', ''));
                }
                if ($q['use_queue_context']) {
                    $ext->add($c, $exten, '', new ext_setvar('__CFIGNORE', ''));
                    $ext->add($c, $exten, '', new ext_setvar('__FORWARD_CONTEXT', 'from-internal'));
                }
                if ($qringopts) {
                    $ext->add($c, $exten, '', new ext_set('QRINGOPTS', ''));
                }
                //VQ_DEST = str_replace(',','^',$vq['goto'])
                $ext->add($c, $exten, '', new ext_set('QDEST', '${VQ_DEST}'));
                $ext->add($c, $exten, '', new ext_set('VQ_DEST', ''));
                $ext->add($c, $exten, 'gotodest', new ext_gotoif('$["${QDEST}"=""]', $q['goto'], '${CUT(QDEST,^,1)},${CUT(QDEST,^,2)},${CUT(QDEST,^,3)}'));
                //dynamic agent login/logout
                if (trim($qregex) != '') {
                    $ext->add($c, $exten . "*", '', new ext_setvar('QREGEX', $qregex));
                }
                if ($amp_conf['GENERATE_LEGACY_QUEUE_CODES']) {
                    if ($q['use_queue_context'] == '2') {
                        $ext->add($c, $exten . "*", '', new ext_macro('agent-add', $exten . "," . $q['password'] . ",EXTEN"));
                    } else {
                        $ext->add($c, $exten . "*", '', new ext_macro('agent-add', $exten . "," . $q['password']));
                    }
                    $ext->add($c, $exten . "**", '', new ext_macro('agent-del', "{$exten}"));
                }
                if ($que_code != '') {
                    $ext->add($c, $que_code . $exten, '', new ext_setvar('QUEUENO', $exten));
                    $ext->add($c, $que_code . $exten, '', new ext_goto('start', 's', 'app-queue-toggle'));
                }
                if ($que_pause_code != '') {
                    $ext->add($c, $que_pause_code . $exten, '', new ext_gosub('1', 's', 'app-queue-pause-toggle', $exten));
                }
                /* Trial Devstate */
                // Create Hints for Devices and Add Astentries for Users
                // Clean up the Members array
                if ($q['togglehint'] && $que_code != '') {
                    if (!isset($device_list)) {
                        $device_list = core_devices_list("all", 'full', true);
                        $device_list = is_array($device_list) ? $device_list : array();
                    }
                    if ($astman) {
                        if (($dynmemberonly = strtolower($astman->database_get('QPENALTY/' . $exten, 'dynmemberonly')) == 'yes') == true) {
                            $get = $astman->database_show('QPENALTY/' . $exten . '/agents');
                            if (is_array($get)) {
                                $mem = array();
                                foreach ($get as $key => $value) {
                                    $key = explode('/', $key);
                                    $mem[$key[4]] = $value;
                                }
                            }
                        }
                    } else {
                        fatal("Cannot connect to Asterisk Manager with " . $amp_conf["AMPMGRUSER"] . "/" . $amp_conf["AMPMGRPASS"]);
                    }
                    $exten_str_len = strlen($exten);
                    $exten_str_tmp = str_repeat('X', $exten_str_len);
                    $que_code_len = strlen($que_code);
                    $device_list = !empty($device_list) ? $device_list : array();
                    foreach ($device_list as $device) {
                        if ((!$dynmemberonly || $device['devicetype'] == 'adhoc' || isset($mem[$device['user']])) && ($device['tech'] == 'sip' || $device['tech'] == 'iax2' || $device['tech'] == 'pjsip')) {
                            $dev_len = strlen($device['id']);
                            $dev_len_tmp = str_repeat('X', $dev_len);
                            $exten_pat = '_' . $que_code . $dev_len_tmp . '*' . $exten_str_tmp;
                            if (!in_array($exten_pat, $hint_hash)) {
                                $hint_hash[] = $exten_pat;
                                $ext->add($c, $exten_pat, '', new ext_setvar('QUEUENO', '${EXTEN:' . ($que_code_len + $dev_len + 1) . ":{$exten_str_len}}"));
                                $ext->add($c, $exten_pat, '', new ext_setvar('QUEUEUSER', '${EXTEN:' . "{$que_code_len}:{$dev_len}" . '}'));
                                $ext->add($c, $exten_pat, '', new ext_goto('start', 's', 'app-queue-toggle'));
                                $ext->addHint($c, $exten_pat, "Custom:QUEUE" . '${EXTEN:' . "{$que_code_len}}");
                                //TODO: dynamic hints
                            }
                        }
                    }
                }
                // Add routing vector to direct which context call should go
                //
                $agent_context = isset($q['use_queue_context']) && $q['use_queue_context'] && isset($queue_context) ? $queue_context : 'from-internal';
                switch ($q['use_queue_context']) {
                    case 1:
                        $agent_context = $from_queue_exten_internal;
                        break;
                    case 2:
                        $agent_context = $from_queue_exten_only;
                        break;
                    case 0:
                    default:
                        $agent_context = 'from-internal';
                        break;
                }
                $ext->add('from-queue', $exten, '', new ext_goto('1', '${QAGENT}', $agent_context));
                $q['member'] = is_array($q['member']) ? $q['member'] : array();
                foreach ($q['member'] as $qm) {
                    if (strtoupper(substr($qm, 0, 1)) == 'L') {
                        $tm = preg_replace("/[^0-9#\\,*]/", "", $qm);
                        $tma = explode(',', $tm);
                        $qmembers[$exten][] = $tma[0];
                    }
                }
            }
            if (!$amp_conf['DYNAMICHINTS'] && ($que_code != '' || $que_pause_code != '' || $que_callers_code != '')) {
                $qpenalty = $astman->database_show('QPENALTY');
                $qc = array();
                foreach (array_keys($qpenalty) as $key) {
                    $key = explode('/', $key);
                    if ($key[3] == 'agents') {
                        $qc[$key[4]][] = $key[2];
                    }
                }
                // Make sure we have all the devices
                //
                if (!isset($device_list)) {
                    $device_list = core_devices_list("all", 'full', true);
                    $device_list = is_array($device_list) ? $device_list : array();
                }
            }
            // Create *45 all queue toggle
            //
            if ($que_code != '') {
                $ext->add($c, $que_code, '', new ext_goto('start', 's', 'app-all-queue-toggle'));
                // create a generic one for any phones that don't get a specific one created since we only
                // create them for phones we know have queues but who knows what is provisioned on the phones
                //
                $ext->add($c, '_' . $que_code . '*X.', '', new ext_goto('start', 's', 'app-all-queue-toggle'));
                // generate with #exec if we are using dynamic hints
                //
                if ($amp_conf['DYNAMICHINTS']) {
                    $ext->addExec($c, $amp_conf['AMPBIN'] . '/generate_queue_hints.php ' . $que_code);
                } else {
                    $que_code_len = strlen($que_code);
                    $hlist = '';
                    foreach ($device_list as $device) {
                        $astman->database_del("AMPUSER/" . $device['id'], "queuehint");
                        //cleanup
                        if ($device['tech'] == 'sip' || $device['tech'] == 'iax2' || $device['tech'] == 'pjsip') {
                            if ($device['user'] != '' && isset($qc[$device['user']])) {
                                $hlist = 'Custom:QUEUE' . $device['id'] . '*' . implode('&Custom:QUEUE' . $device['id'] . '*', $qc[$device['user']]);
                                $astman->database_put("AMPUSER/" . $device['id'], "queuehint", $hlist);
                            }
                        }
                    }
                    $ext->addHint($c, '_' . $que_code . '*' . 'X.', '${DB(AMPUSER/${EXTEN:' . strlen($que_code . '*') . '}/queuehint)}');
                }
            }
            // Add the static members now since so far it only has dynamic members
            foreach ($qmembers as $q => $mems) {
                $mems = is_array($mems) ? $mems : array();
                foreach ($mems as $m) {
                    // If $m is not in qc already then add them, thus avoiding duplicates
                    if (!isset($qc[$m]) || !in_array($q, $qc[$m])) {
                        $qc[$m][] = (string) $q;
                    }
                }
            }
            // Create *46 codes/hints
            //
            if ($que_pause_code != '') {
                $ext->add($c, $que_pause_code, '', new ext_goto('1', 's', 'app-all-queue-pause-toggle'));
                // create a generic one for any phones that don't get a specific one created since we only
                // create them for phones we know have queues but who knows what is provisioned on the phones
                //
                $ext->add($c, '_' . $que_pause_code . '*X.', '', new ext_goto('1', 's', 'app-all-queue-pause-toggle'));
                // TODO: There's a bug here $q_pause_Local isn't initialized and shoudl be something.
                //       Currently this can't be made into a pattern since it's the $device['user'] but the hint has the device
                //
                $q_pause_len = strlen($que_pause_code);
                $device_list = isset($device_list) && is_array($device_list) ? $device_list : array();
                foreach ($device_list as $device) {
                    $astman->database_del("AMPUSER/" . $device['id'], "pausequeuehint");
                    if ($device['user'] != '') {
                        $pause_all_hints = array();
                        if (isset($qc[$device['user']])) {
                            foreach ($qc[$device['user']] as $q) {
                                if (!$amp_conf['DYNAMICHINTS'] && ($device['tech'] == 'pjsip' || $device['tech'] == 'sip' || $device['tech'] == 'iax2')) {
                                    // Do the real hints for below
                                    //
                                    if ($ast_ge_12) {
                                        $hint = "Queue:{$q}_pause_Local/{$device['user']}@from-queue/n";
                                    } else {
                                        $hint = "qpause:{$q}:Local/{$device['user']}@from-queue/n";
                                    }
                                    $pause_all_hints[] = $hint;
                                    $dev_len = strlen($device['id']);
                                    $dev_len_tmp = str_repeat('X', $dev_len);
                                    $exten_pat = "_{$que_pause_code}*{$dev_len_tmp}*{$q}";
                                    if (!in_array($exten_pat, $hint_hash)) {
                                        $hint_hash[] = $exten_pat;
                                        /*
                                        									exten => *46*1999*90000,1,Gosub(app-queue-pause-toggle,s,1(90000,1999))
                                        									exten => *46*1999*90000,hint,Queue:90000_pause_Local/1999@from-queue/n
                                        									${DB(DEVICE/${EXTEN:4:4}/user)}
                                        */
                                        $q_tmp = '${EXTEN:' . ($q_pause_len + $dev_len + 2) . '}';
                                        $d_tmp = '${DB(DEVICE/${EXTEN:' . ($q_pause_len + 1) . ":{$dev_len}}/user)}";
                                        if ($ast_ge_12) {
                                            $hint = "Queue:{$q_tmp}_pause_Local/{$d_tmp}@from-queue/n";
                                        } else {
                                            $hint = "qpause:{$q_tmp}:Local/{$d_tmp}@from-queue/n";
                                        }
                                        $ext->add($c, $exten_pat, '', new ext_gosub('1', 's', 'app-queue-pause-toggle', $q . ',' . $device['id']));
                                        $ext->addHint($c, $exten_pat, $hint);
                                    }
                                } else {
                                    $ext->add($c, $que_pause_code . '*' . $device['id'] . '*' . $q, '', new ext_gosub('1', 's', 'app-queue-pause-toggle', $q . ',' . $device['id']));
                                }
                            }
                        }
                        //$ext->add($c, $que_pause_code . '*' . $device['id'], '', new ext_goto('1','s','app-all-queue-pause-toggle'));
                        if (!empty($pause_all_hints)) {
                            $astman->database_put("AMPUSER/" . $device['id'], "pausequeuehint", implode('&', $pause_all_hints));
                        }
                    }
                }
                $ext->addHint($c, '_' . $que_pause_code . '*X.', '${DB(AMPUSER/${EXTEN:' . strlen($que_pause_code . '*') . '}/pausequeuehint)}');
            }
            // Create *47 codes/hints
            //
            if ($que_callers_code != '') {
                $id = "app-queue-caller-count";
                $ext->addInclude('from-internal-additional', $id);
                // Add the include from from-internal
                $ext->add($id, 's', '', new ext_answer());
                $ext->add($id, 's', '', new ext_wait(1));
                $ext->add($id, 's', '', new ext_setvar('QUEUES', '${ARG1}'));
                $ext->add($id, 's', '', new ext_setvar('COUNT', '0'));
                $ext->add($id, 's', '', new ext_setvar('LOOPCNT', '${FIELDQTY(QUEUES,&)}'));
                $ext->add($id, 's', '', new ext_setvar('ITER', '1'));
                $ext->add($id, 's', 'begin1', new ext_setvar('QUEUE', '${CUT(QUEUES,&,${ITER})}'));
                $ext->add($id, 's', '', new ext_setvar('COUNT', '$[${COUNT} + ${QUEUE_WAITING_COUNT(${QUEUE})}]'));
                $ext->add($id, 's', 'end1', new ext_setvar('ITER', '$[${ITER} + 1]'));
                $ext->add($id, 's', '', new ext_gotoif('$[${ITER} <= ${LOOPCNT}]', 'begin1'));
                $ext->add($id, 's', '', new ext_saynumber('${COUNT}'));
                $ext->add($id, 's', '', new ext_playback('queue-quantity2'));
                $ext->add($id, 's', '', new ext_return());
            }
            // We need to have a hangup here, if call is ended by the caller during Playback it will end in the
            // h context and do a proper hangup and clean the blkvm if set, see #4671
            $ext->add($c, 'h', '', new ext_macro('hangupcall'));
            // NODEST will be the queue that this came from, so we will vector though an entry to determine the context the
            // agent should be delivered to. All queue calls come here, this decides if the should go direct to from-internal
            // or indirectly through from-queue-exten-only to trap extension calls and avoid their follow-me, etc.
            //
            $ext->add('from-queue', '_.', '', new ext_setvar('QAGENT', '${EXTEN}'));
            $ext->add('from-queue', '_.', '', new ext_setvar('__FROMQ', 'true'));
            //see below comments
            $ext->add('from-queue', '_.', '', new ext_goto('1', '${NODEST}'));
            //http://issues.freepbx.org/browse/FREEPBX-11871
            //Because of local channel changes in Asterisk 12+ we end up losing track of our recording file
            //This effectively "gives" back the recording file to the channel that answered the queue
            if ($ast_ge_12) {
                $ext->splice('macro-auto-blkvm', 's', 1, new ext_execif('$["${FROMQ}" = "true" & "${CALLFILENAME}" != "" & "${CDR(recordingfile)}" = ""]', 'Set', 'CDR(recordingfile)=${CALLFILENAME}.${MON_FMT}'));
            }
            $ext->addInclude($from_queue_exten_only . '-x', 'from-internal');
            $ext->add($from_queue_exten_only . '-x', 'foo', '', new ext_noop('bar'));
            $ext->addInclude($from_queue_exten_internal, $from_queue_exten_only);
            $ext->addInclude($from_queue_exten_internal, $from_queue_exten_only . '-x');
            $ext->addInclude($from_queue_exten_internal, 'from-internal');
            $ext->add($from_queue_exten_internal, 'foo', '', new ext_noop('bar'));
            /* create a context, from-queue-exten-only, that can be used for queues that want behavir similar to
             * ringgroup where only the agent's phone will be rung, no follow-me will be pursued.
             */
            $sql = "SELECT LENGTH(extension) as len FROM users GROUP BY len";
            $sth = FreePBX::Database()->prepare($sql);
            $sth->execute();
            $rows = $sth->fetchAll(\PDO::FETCH_ASSOC);
            foreach ($rows as $row) {
                //make sure exten exists
                $ext->add($from_queue_exten_only, '_' . str_repeat('X', $row['len']), '', new ext_gotoif('$[${DB_EXISTS(AMPUSER/${EXTEN}/cidnum)} = 0]', $from_queue_exten_only . '-x,${EXTEN},1'));
                $ext->add($from_queue_exten_only, '_' . str_repeat('X', $row['len']), '', new ext_set('RingGroupMethod', 'none'));
                $ext->add($from_queue_exten_only, '_' . str_repeat('X', $row['len']), '', new ext_set('QDOPTS', '${IF($["${CALLER_DEST}"!=""]?g)}${IF($["${AGENT_DEST}"!=""]?F(${AGENT_DEST}))}'));
                $ext->add($from_queue_exten_only, '_' . str_repeat('X', $row['len']), 'checkrecord', new ext_set('CALLTYPE_OVERRIDE', 'external'));
                // Make sure the call is tagged as external
                // This means:
                // If (!$fromexten) { if (!$nodest) { $fromexten = 'external' } else { $fromexten = $nodest } }
                $ext->add($from_queue_exten_only, '_' . str_repeat('X', $row['len']), '', new ext_execif('$[!${LEN(${FROMEXTEN})}]', 'Set', 'FROMEXTEN=${IF(${LEN(${NODEST})}?${NODEST}:external)}'));
                // Make sure the call is tagged as external
                $ext->add($from_queue_exten_only, '_' . str_repeat('X', $row['len']), '', new ext_gosub('1', 's', 'sub-record-check', 'exten,${EXTEN},'));
                if ($has_extension_state) {
                    $ext->add($from_queue_exten_only, '_' . str_repeat('X', $row['len']), '', new ext_macro('dial-one', ',${DIAL_OPTIONS}${QDOPTS},${EXTEN}'));
                } else {
                    $ext->add($from_queue_exten_only, '_' . str_repeat('X', $row['len']), '', new ext_macro('dial', ',${DIAL_OPTIONS}${QDOPTS},${EXTEN}'));
                }
                $ext->add($from_queue_exten_only, '_' . str_repeat('X', $row['len']), '', new ext_gotoif('$["${CALLER_DEST}"!=""&&"${DIALSTATUS}"="ANSWER"]', '${CUT(CALLER_DEST,^,1)},${CUT(CALLER_DEST,^,2)},${CUT(CALLER_DEST,^,3)}'));
                $ext->add($from_queue_exten_only, '_' . str_repeat('X', $row['len']), '', new ext_hangup());
            }
            if (!empty($rows)) {
                $ext->add($from_queue_exten_only, 'h', '', new ext_macro('hangupcall'));
            }
            /*
             * Adds a dynamic agent/member to a Queue
             * Prompts for call-back number - in not entered, uses CIDNum
             */
            if ($amp_conf['GENERATE_LEGACY_QUEUE_CODES']) {
                $c = 'macro-agent-add';
                // for i18n playback in multiple languages
                $ext->add($c, 'lang-playback', '', new ext_gosubif('$[${DIALPLAN_EXISTS(' . $c . ',${CHANNEL(language)})}]', $c . ',${CHANNEL(language)},${ARG1}', $c . ',en,${ARG1}'));
                $ext->add($c, 'lang-playback', '', new ext_return());
                $exten = 's';
                $ext->add($c, $exten, '', new ext_wait(1));
                $ext->add($c, $exten, '', new ext_set('QUEUENO', '${ARG1}'));
                $ext->add($c, $exten, '', new ext_macro('user-callerid', 'SKIPTTL'));
                $ext->add($c, $exten, 'a3', new ext_read('CALLBACKNUM', 'agent-login'));
                // get callback number from user
                $ext->add($c, $exten, '', new ext_gotoif('$[${LEN(${CALLBACKNUM})}=0]', 'a5', 'a7'));
                // if user just pressed # or timed out, use cidnum
                $ext->add($c, $exten, 'a5', new ext_set('CALLBACKNUM', '${IF($[${LEN(${AMPUSER})}=0]?${CALLERID(number)}:${AMPUSER})}'));
                $ext->add($c, $exten, '', new ext_set('THISDEVICE', '${DB(DEVICE/${REALCALLERIDNUM}/dial)}'));
                $ext->add($c, $exten, '', new ext_gotoif('$["${CALLBACKNUM}" = ""]', 'a3'));
                // if still no number, start over
                $ext->add($c, $exten, 'a7', new ext_gotoif('$["${CALLBACKNUM}" = "${QUEUENO}"]', 'invalid'));
                // Error, they put in the queue number
                // If this is an extension only queue then EXTEN is passed as ARG3 and we make sure this is a valid extension being entered
                $ext->add($c, $exten, '', new ext_gotoif('$["${ARG3}" = "EXTEN" & ${DB_EXISTS(AMPUSER/${CALLBACKNUM}/cidname)} = 0]', 'invalid'));
                // If this is a restricted dynamic agent queue then check to make sure they are allowed
                $ext->add($c, $exten, '', new ext_gotoif('$["${DB(QPENALTY/${QUEUENO}/dynmemberonly)}" = "yes" & ${DB_EXISTS(QPENALTY/${QUEUENO}/agents/${CALLBACKNUM})} != 1]', 'invalid'));
                $ext->add($c, $exten, '', new ext_execif('$["${QREGEX}" != ""]', 'GotoIf', '$["${REGEX("${QREGEX}" ${CALLBACKNUM})}" = "0"]?invalid'));
                $ext->add($c, $exten, '', new ext_execif('$["${ARG2}" != ""]', 'Authenticate', '${ARG2}'));
                $ext->add($c, $exten, '', new ext_set('STATE', 'INUSE'));
                $ext->add($c, $exten, '', new ext_gosub('1', 'sstate', 'app-queue-toggle'));
                $ext->add($c, $exten, '', new ext_execif('$[${DB_EXISTS(AMPUSER/${CALLBACKNUM}/cidname)} = 1 & "${DB(AMPUSER/${CALLBACKNUM}/queues/qnostate)}" != "ignorestate"]', 'AddQueueMember', '${QUEUENO},Local/${CALLBACKNUM}@from-queue/n,${DB(QPENALTY/${QUEUENO}/agents/${CALLBACKNUM})},,${DB(AMPUSER/${CALLBACKNUM}/cidname)},hint:${CALLBACKNUM}@ext-local'));
                $ext->add($c, $exten, '', new ext_execif('$[${DB_EXISTS(AMPUSER/${CALLBACKNUM}/cidname)} = 1 & "${DB(AMPUSER/${CALLBACKNUM}/queues/qnostate)}" = "ignorestate"]', 'AddQueueMember', '${QUEUENO},Local/${CALLBACKNUM}@from-queue/n,${DB(QPENALTY/${QUEUENO}/agents/${CALLBACKNUM})},,${DB(AMPUSER/${CALLBACKNUM}/cidname)}'));
                $ext->add($c, $exten, '', new ext_execif('$[${DB_EXISTS(AMPUSER/${CALLBACKNUM}/cidname)} = 0]', 'AddQueueMember', '${QUEUENO},Local/${CALLBACKNUM}@from-queue/n,${DB(QPENALTY/${QUEUENO}/agents/${CALLBACKNUM})}'));
                $ext->add($c, $exten, '', new ext_userevent('Agentlogin', 'Agent: ${CALLBACKNUM}'));
                $ext->add($c, $exten, '', new ext_wait(1));
                $ext->add($c, $exten, '', new ext_gosub('1', 'lang-playback', $c, 'hook_0'));
                $ext->add($c, $exten, '', new ext_hangup());
                $ext->add($c, $exten, '', new ext_macroexit());
                $ext->add($c, $exten, 'invalid', new ext_playback('pbx-invalid'));
                $ext->add($c, $exten, '', new ext_goto('a3'));
                $lang = 'en';
                // English
                $ext->add($c, $lang, 'hook_0', new ext_playback('agent-loginok&with&extension'));
                $ext->add($c, $lang, '', new ext_saydigits('${CALLBACKNUM}'));
                $ext->add($c, $lang, '', new ext_return());
                $lang = 'ja';
                // Japanese
                $ext->add($c, $lang, 'hook_0', new ext_playback('extension'));
                $ext->add($c, $lang, '', new ext_saydigits('${CALLBACKNUM}'));
                $ext->add($c, $lang, '', new ext_playback('jp-kara&agent-loginok'));
                $ext->add($c, $lang, '', new ext_return());
                /*
                 * Removes a dynamic agent/member from a Queue
                 * Prompts for call-back number - in not entered, uses CIDNum
                 */
                $c = 'macro-agent-del';
                $ext->add($c, $exten, '', new ext_wait(1));
                $ext->add($c, $exten, '', new ext_set('QUEUENO', '${ARG1}'));
                $ext->add($c, $exten, '', new ext_macro('user-callerid', 'SKIPTTL'));
                $ext->add($c, $exten, 'a3', new ext_read('CALLBACKNUM', 'agent-logoff'));
                // get callback number from user
                $ext->add($c, $exten, '', new ext_gotoif('$[${LEN(${CALLBACKNUM})}=0]', 'a5', 'a7'));
                // if user just pressed # or timed out, use cidnum
                $ext->add($c, $exten, 'a5', new ext_set('CALLBACKNUM', '${IF($[${LEN(${AMPUSER})}=0]?${CALLERID(number)}:${AMPUSER})}'));
                $ext->add($c, $exten, '', new ext_gotoif('$["${CALLBACKNUM}" = ""]', 'a3'));
                // if still no number, start over
                $ext->add($c, $exten, '', new ext_set('STATE', 'NOT_INUSE'));
                $ext->add($c, $exten, '', new ext_gosub('1', 'sstate', 'app-queue-toggle'));
                // remove from both contexts in case left over dynamic agents after an upgrade
                $ext->add($c, $exten, 'a7', new ext_removequeuemember('${QUEUENO}', 'Local/${CALLBACKNUM}@from-queue/n'));
                $ext->add($c, $exten, '', new ext_removequeuemember('${QUEUENO}', 'Local/${CALLBACKNUM}@from-internal/n'));
                $ext->add($c, $exten, '', new ext_userevent('RefreshQueue'));
                $ext->add($c, $exten, '', new ext_wait(1));
                $ext->add($c, $exten, '', new ext_playback('agent-loggedoff'));
                $ext->add($c, $exten, '', new ext_hangup());
            }
            // GENERATE_LEGACY_QUEUE_CODES
            break;
    }
}