Exemple #1
0
 /**
  * @verb GET
  * @returns - the queue list
  * @uri /queues
  */
 function get_queues($params)
 {
     $queues = queues_list();
     foreach ($queues as $queue) {
         $entry = new stdClass();
         $entry->extension = $queue[0];
         $entry->name = $queue[1];
         $list[$queue[0]] = $entry;
     }
     return $list ? $list : false;
 }
function queues_destinations()
{
    //get the list of all exisiting
    $results = queues_list(true);
    //return an associative array with destination and description
    if (isset($results)) {
        foreach ($results as $result) {
            $extens[] = array('destination' => 'ext-queues,' . $result['0'] . ',1', 'description' => $result['0'] . ' ' . $result['1']);
        }
    }
    if (isset($extens)) {
        return $extens;
    } else {
        return null;
    }
}
Exemple #3
0
function queues_set_backup_cron()
{
    global $amp_conf;
    //remove all stale backup's
    edit_crontab($amp_conf['AMPBIN'] . '/queue_reset_stats.php');
    //get our list of queues
    $queues_list = queues_list(true);
    $queues = array();
    foreach ($queues_list as $key => $value) {
        //get queue details
        $queues[$value[0]] = queues_get($value[0], false);
    }
    foreach ($queues as $qid => $q) {
        $cron_vars = array('cron_minute', 'cron_hour', 'cron_dow', 'cron_month', 'cron_dom');
        foreach ($cron_vars as $value) {
            if (isset($q[$value])) {
                $q[$value] = array($q[$value]);
            }
        }
        if (!isset($q['cron_schedule'])) {
            $q['cron_schedule'] = 'never';
        }
        $cron = '';
        $cron['command'] = $amp_conf['AMPBIN'] . '/queue_reset_stats.php --id=' . $qid;
        if (!isset($q['cron_random']) || $q['cron_random'] != 'true') {
            switch ($q['cron_schedule']) {
                case 'never':
                    $cron = '';
                    break;
                case 'hourly':
                case 'daily':
                case 'weekly':
                case 'monthly':
                case 'annually':
                case 'reboot':
                    $cron['event'] = $q['cron_schedule'];
                    break;
                case 'custom':
                    $cron['minute'] = isset($q['cron_minute']) ? implode(',', $q['cron_minute']) : '*';
                    $cron['dom'] = isset($q['cron_dom']) ? implode(',', $q['cron_dom']) : '*';
                    $cron['dow'] = isset($q['cron_dow']) ? implode(',', $q['cron_dow']) : '*';
                    $cron['hour'] = isset($q['cron_hour']) ? implode(',', $q['cron_hour']) : '*';
                    $cron['month'] = isset($q['cron_month']) ? implode(',', $q['cron_month']) : '*';
                    break;
                default:
                    $cron = '';
                    break;
            }
        } else {
            switch ($q['cron_schedule']) {
                case 'annually':
                    $cron['month'] = rand(1, 12);
                case 'monthly':
                    $cron['dom'] = rand(1, 31);
                case 'weekly':
                    if (!in_array($q['cron_schedule'], array('annually', 'monthly'))) {
                        $cron['dow'] = rand(0, 6);
                    }
                case 'daily':
                    $hour = rand(0, 7) + 21;
                    $cron['hour'] = $hour > 23 ? $hour - 23 : $hour;
                case 'hourly':
                    $cron['minute'] = rand(0, 59);
                    break;
                default:
                    $cron = '';
                    break;
            }
        }
        if ($cron) {
            //dbug('calling cron with ', $cron);
            edit_crontab('', $cron);
        }
    }
}
<?php

/* $Id$ */
if (!defined('FREEPBX_IS_AUTH')) {
    die('No direct script access allowed');
}
$request = $_REQUEST;
//used for switch on config.php
$dispnum = 'queues';
$heading = _("Queues");
//get unique queues
$queues = queues_list();
$view = isset($request['view']) ? $request["view"] : '';
switch ($view) {
    case "form":
        if ($request['extdisplay']) {
            $heading .= _(" Edit: ");
            $heading .= $request['extdisplay'];
        } else {
            $heading .= _(" Add Queue");
        }
        $content = load_view(__DIR__ . '/views/form.php', array('request' => $request, 'amp_conf' => $amp_conf));
        break;
    default:
        $content = load_view(__DIR__ . '/views/qgrid.php');
        break;
}
?>
<div class="container-fluid">
	<h1><?php 
echo $heading;
Exemple #5
0
<?php

$queuelist = queues_list();
$qrows = '';
foreach ($queuelist as $q) {
    $qrows .= '<tr><td>' . $q[0] . '</td><td>' . $q[1] . '</td><td><a href="/admin/config.php?display=queues&view=form&extdisplay=' . urlencode($q[0]) . '"><i class="fa fa-edit"></i></a>&nbsp;<a href="/admin/config.php?display=queues&action=delete&account=' . urlencode($q[0]) . '"><i class="fa fa-trash"></i></a></td></tr>';
}
?>
<div id="toolbar-all">
	<a href="config.php?display=queues&amp;view=form" class="btn btn-primary"><i class="fa fa-plus"></i> <?php 
echo _("Add Queue");
?>
</a>
</div>
<table id="qgrid" data-toolbar="#toolbar-all" data-maintain-selected="true" data-show-columns="true" data-show-toggle="true" data-toggle="table" data-pagination="true" data-search="true"class="table table-striped">
<thead>
	<tr>
		<th data-sortable="true"><?php 
echo _("Queue");
?>
</th>
		<th><?php 
echo _("Description");
?>
</th>
		<th><?php 
echo _("Actions");
?>
</th>
	</tr>
</thead>
function ivr_get_config($engine)
{
    global $ext;
    switch ($engine) {
        case "asterisk":
            $ddial_contexts = array();
            $ivrlist = ivr_get_details();
            if (!is_array($ivrlist)) {
                break;
            }
            if (function_exists('queues_list')) {
                //draw a list of ivrs included by any queues
                $queues = queues_list(true);
                $qivr = array();
                foreach ($queues as $q) {
                    $thisq = queues_get($q[0]);
                    if ($thisq['context'] && strpos($thisq['context'], 'ivr-') === 0) {
                        $qivr[] = str_replace('ivr-', '', $thisq['context']);
                    }
                }
            }
            foreach ($ivrlist as $ivr) {
                $c = 'ivr-' . $ivr['id'];
                $ivr = ivr_get_details($ivr['id']);
                $ext->addSectionComment($c, $ivr['name'] ? $ivr['name'] : 'IVR ' . $ivr['id']);
                if ($ivr['directdial']) {
                    if ($ivr['directdial'] == 'ext-local') {
                        $ext->addInclude($c, 'from-did-direct-ivr');
                        //generated in core module
                    } else {
                        //generated by directory
                        $ext->addInclude($c, 'from-ivr-directory-' . $ivr['directdial']);
                        $directdial_contexts[$ivr['directdial']] = $ivr['directdial'];
                    }
                }
                //set variables for loops when used
                if ($ivr['timeout_loops'] != 'disabled' && $ivr['timeout_loops'] > 0) {
                    $ext->add($c, 's', '', new ext_setvar('TIMEOUT_LOOPCOUNT', 0));
                }
                if ($ivr['invalid_loops'] != 'disabled' && $ivr['invalid_loops'] > 0) {
                    $ext->add($c, 's', '', new ext_setvar('INVALID_LOOPCOUNT', 0));
                }
                $ext->add($c, 's', '', new ext_setvar('_IVR_CONTEXT_${CONTEXT}', '${IVR_CONTEXT}'));
                $ext->add($c, 's', '', new ext_setvar('_IVR_CONTEXT', '${CONTEXT}'));
                if ($ivr['retvm']) {
                    $ext->add($c, 's', '', new ext_setvar('__IVR_RETVM', 'RETURN'));
                } else {
                    //TODO: do we need to set anything at all?
                    $ext->add($c, 's', '', new ext_setvar('__IVR_RETVM', ''));
                }
                if ($ivr['alertinfo'] != '') {
                    $ext->add($c, 's', '', new ext_setvar('__ALERT_INFO', str_replace(';', '\\;', $ivr['alertinfo'])));
                }
                $ext->add($c, 's', '', new ext_gotoif('$["${CHANNEL(state)}" = "Up"]', 'skip'));
                $ext->add($c, 's', '', new ext_answer(''));
                $ext->add($c, 's', '', new ext_wait('1'));
                $ivr_announcement = recordings_get_file($ivr['announcement']);
                $ext->add($c, 's', 'skip', new ext_set('IVR_MSG', $ivr_announcement));
                $ext->add($c, 's', 'start', new ext_digittimeout(3));
                //$ext->add($ivr_id, 's', '', new ext_responsetimeout($ivr['timeout_time']));
                $ext->add($c, 's', '', new ext_execif('$["${IVR_MSG}" != ""]', 'Background', '${IVR_MSG}'));
                $ext->add($c, 's', '', new ext_waitexten($ivr['timeout_time']));
                // Actually add the IVR entires now
                $entries = ivr_get_entries($ivr['id']);
                if ($entries) {
                    foreach ($entries as $e) {
                        //dont set a t or i if there already defined above
                        if ($e['selection'] == 't' && $ivr['timeout_loops'] != 'disabled') {
                            continue;
                        }
                        if ($e['selection'] == 'i' && $ivr['invalid_loops'] != 'disabled') {
                            continue;
                        }
                        //only display these two lines if the ivr is included in any queues
                        if (function_exists('queues_list') && in_array($ivr['id'], $qivr)) {
                            $ext->add($c, $e['selection'], '', new ext_macro('blkvm-clr'));
                            $ext->add($c, $e['selection'], '', new ext_setvar('__NODEST', ''));
                        }
                        if ($e['ivr_ret']) {
                            $ext->add($c, $e['selection'], '', new ext_gotoif('$["x${IVR_CONTEXT_${CONTEXT}}" = "x"]', $e['dest'] . ':${IVR_CONTEXT_${CONTEXT}},return,1'));
                        } else {
                            $ext->add($c, $e['selection'], 'ivrsel-' . $e['selection'], new ext_goto($e['dest']));
                        }
                    }
                }
                // add invalid destination if required
                if ($ivr['invalid_loops'] != 'disabled') {
                    if ($ivr['invalid_loops'] > 0) {
                        $ext->add($c, 'i', '', new ext_set('INVALID_LOOPCOUNT', '$[${INVALID_LOOPCOUNT}+1]'));
                        $ext->add($c, 'i', '', new ext_gotoif('$[${INVALID_LOOPCOUNT} > ' . $ivr['invalid_loops'] . ']', 'final'));
                        switch ($ivr['invalid_retry_recording']) {
                            case 'default':
                                $invalid_annoucement = 'no-valid-responce-pls-try-again';
                                break;
                            case '':
                                $invalid_annoucement = '';
                                break;
                            default:
                                $invalid_annoucement = recordings_get_file($ivr['invalid_retry_recording']);
                                break;
                        }
                        if ($ivr['invalid_append_announce'] || $invalid_annoucement == '') {
                            $invalid_annoucement .= '&' . $ivr_announcement;
                        }
                        $ext->add($c, 'i', '', new ext_set('IVR_MSG', trim($invalid_annoucement, '&')));
                        $ext->add($c, 'i', '', new ext_goto('s,start'));
                    }
                    $label = 'final';
                    switch ($ivr['invalid_recording']) {
                        case 'default':
                            $ext->add($c, 'i', $label, new ext_playback('no-valid-responce-transfering'));
                            $label = '';
                            break;
                        case '':
                            break;
                        default:
                            $ext->add($c, 'i', $label, new ext_playback(recordings_get_file($ivr['invalid_recording'])));
                            $label = '';
                            break;
                    }
                    if (!empty($ivr['invalid_ivr_ret'])) {
                        $ext->add($c, 'i', $label, new ext_gotoif('$["x${IVR_CONTEXT_${CONTEXT}}" = "x"]', $ivr['invalid_destination'] . ':${IVR_CONTEXT_${CONTEXT}},return,1'));
                    } else {
                        $ext->add($c, 'i', $label, new ext_goto($ivr['invalid_destination']));
                    }
                } else {
                    // If no invalid destination provided we need to do something
                    $ext->add($c, 'i', '', new ext_playback('sorry-youre-having-problems'));
                    $ext->add($c, 'i', '', new ext_goto('1', 'hang'));
                }
                // Apply timeout destination if required
                if ($ivr['timeout_loops'] != 'disabled') {
                    if ($ivr['timeout_loops'] > 0) {
                        $ext->add($c, 't', '', new ext_set('TIMEOUT_LOOPCOUNT', '$[${TIMEOUT_LOOPCOUNT}+1]'));
                        $ext->add($c, 't', '', new ext_gotoif('$[${TIMEOUT_LOOPCOUNT} > ' . $ivr['timeout_loops'] . ']', 'final'));
                        switch ($ivr['timeout_retry_recording']) {
                            case 'default':
                                $timeout_annoucement = 'no-valid-responce-pls-try-again';
                                break;
                            case '':
                                $timeout_annoucement = '';
                                break;
                            default:
                                $timeout_annoucement = recordings_get_file($ivr['timeout_retry_recording']);
                                break;
                        }
                        if ($ivr['timeout_append_announce'] || $timeout_annoucement == '') {
                            $timeout_annoucement .= '&' . $ivr_announcement;
                        }
                        $ext->add($c, 't', '', new ext_set('IVR_MSG', trim($timeout_annoucement, '&')));
                        $ext->add($c, 't', '', new ext_goto('s,start'));
                    }
                    $label = 'final';
                    switch ($ivr['timeout_recording']) {
                        case 'default':
                            $ext->add($c, 't', $label, new ext_playback('no-valid-responce-transfering'));
                            $label = '';
                            break;
                        case '':
                            break;
                        default:
                            $ext->add($c, 't', $label, new ext_playback(recordings_get_file($ivr['timeout_recording'])));
                            $label = '';
                            break;
                    }
                    if (!empty($ivr['timeout_ivr_ret'])) {
                        $ext->add($c, 't', $label, new ext_gotoif('$["x${IVR_CONTEXT_${CONTEXT}}" = "x"]', $ivr['timeout_destination'] . ':${IVR_CONTEXT_${CONTEXT}},return,1'));
                    } else {
                        $ext->add($c, 't', $label, new ext_goto($ivr['timeout_destination']));
                    }
                } else {
                    // If no invalid destination provided we need to do something
                    $ext->add($c, 't', '', new ext_playback('sorry-youre-having-problems'));
                    $ext->add($c, 't', '', new ext_goto('1', 'hang'));
                }
                // these need to be reset or inheritance problems makes them go away in some conditions
                //and infinite inheritance creates other problems
                $ext->add($c, 'return', '', new ext_setvar('_IVR_CONTEXT', '${CONTEXT}'));
                $ext->add($c, 'return', '', new ext_setvar('_IVR_CONTEXT_${CONTEXT}', '${IVR_CONTEXT_${CONTEXT}}'));
                $ext->add($c, 'return', '', new ext_set('IVR_MSG', $ivr_announcement));
                $ext->add($c, 'return', '', new ext_goto('s,start'));
                //h extension
                $ext->add($c, 'h', '', new ext_hangup(''));
                $ext->add($c, 'hang', '', new ext_playback('vm-goodbye'));
                $ext->add($c, 'hang', '', new ext_hangup(''));
            }
            //generate from-ivr-directory contexts for direct dialing a directory entire
            if (!empty($directdial_contexts)) {
                foreach ($directdial_contexts as $dir_id) {
                    $c = 'from-ivr-directory-' . $dir_id;
                    $entries = function_exists('directory_get_dir_entries') ? directory_get_dir_entries($dir_id) : array();
                    foreach ($entries as $dstring) {
                        $exten = $dstring['dial'] == '' ? $dstring['foreign_id'] : $dstring['dial'];
                        if ($exten == '' || $exten == 'custom') {
                            continue;
                        }
                        $ext->add($c, $exten, '', new ext_macro('blkvm-clr'));
                        $ext->add($c, $exten, '', new ext_setvar('__NODEST', ''));
                        $ext->add($c, $exten, '', new ext_goto('1', $exten, 'from-internal'));
                    }
                }
            }
            break;
    }
}
 function generate_queues_additional($ast_version)
 {
     global $db;
     global $amp_conf;
     $additional = "";
     $output = "";
     // Asterisk 1.4 does not like blank assignments so just don't put them there
     //
     $ver12 = version_compare($ast_version, '1.4', 'lt');
     $ver16 = version_compare($ast_version, '1.6', 'ge');
     $ast_ge_14_25 = version_compare($ast_version, '1.4.25', 'ge');
     $ast_ge_18 = version_compare($ast_version, '1.8', 'ge');
     $ast_ge_120 = version_compare($ast_version, '12', 'ge');
     // legacy but in case someone was using this we will leave it
     //TODO: abstract getters/setters from business logic
     $sql = "SELECT keyword,data FROM queues_details WHERE id='-1' AND keyword <> 'account'";
     $results = $db->getAll($sql, DB_FETCHMODE_ASSOC);
     if ($db->IsError($results)) {
         die($results->getMessage());
     }
     foreach ($results as $result) {
         if (!$ver12 && trim($result['data']) == '') {
             continue;
         }
         $additional .= $result['keyword'] . "=" . $result['data'] . "\n";
     }
     if ($ast_ge_14_25) {
         $devices = array();
         $device_results = core_devices_list('all', 'full', true);
         if (is_array($device_results)) {
             foreach ($device_results as $device) {
                 if (!isset($devices[$device['user']]) && $device['devicetype'] == 'fixed') {
                     $devices[$device['user']] = $device['dial'];
                 }
             }
             unset($device_results);
         }
     }
     if ($amp_conf['USEQUEUESTATE'] || $ast_ge_14_25) {
         $users = array();
         $user_results = core_users_list();
         if (is_array($user_results)) {
             foreach ($user_results as $user) {
                 $users[$user[0]] = $user[1];
             }
             unset($user_results);
         }
     }
     $results = queues_list(true);
     foreach ($results as $result) {
         $output .= "[" . $result[0] . "]\n";
         // passing 2nd param 'true' tells queues_get to send back only queue_conf required params
         // and nothing else
         //
         $results2 = queues_get($result[0], true);
         if (empty($results2['context'])) {
             $results2['context'] = "";
         }
         // memebers is an array of members so we set it asside and remove it
         // and then generate each later
         //
         $members = $results2['member'];
         unset($results2['member']);
         // Queues cannot control their own recordings, it must now be
         // done through sub-record-check
         unset($results2['monitor-format']);
         unset($results2['recording']);
         //Unset Old commands Resolves FREEPBX-8610.
         unset($results2['monitor-join']);
         unset($results2['answered_elsewhere']);
         unset($results2['skip_joinannounce']);
         //These items still exist for backwards compatibility but are useless in 12+
         if ($ast_ge_120) {
             unset($results2['eventwhencalled']);
             unset($results2['eventmemberstatus']);
         }
         foreach ($results2 as $keyword => $data) {
             if (trim($data) == '' && $keyword != "context" || substr($keyword, 0, 4) == "cron") {
                 // Skip anything that's empty or not required
                 continue;
             }
             // Some old commands have been removed. Make sure we
             // don't add them.
             switch ($keyword) {
                 case 'monitor-join':
                 case 'answered_elsewhere':
                 case 'skip_joinannounce':
                     continue;
                     break;
                 case 'music':
                     $keyword = 'musicclass';
                     break;
             }
             if ($keyword == "retry" && $data == "none") {
                 $data = 0;
             }
             $output .= $keyword . "=" . $data . "\n";
         }
         // Now pull out all the memebers, one line for each
         //
         if ($ast_ge_18 || $amp_conf['USEQUEUESTATE']) {
             foreach ($members as $member) {
                 preg_match("/^Local\\/([\\d]+)\\@*/", $member, $matches);
                 if (isset($matches[1]) && isset($users[$matches[1]])) {
                     $name = sprintf('"%s"', $users[$matches[1]]);
                     //str_replace(',','\,',$name);
                     $qnostate = queues_get_qnostate($matches[1]);
                     if ($qnostate == 'ignorestate') {
                         freepbx_log(FPBX_LOG_NOTICE, "Ignoring State information for Queue Member: " . $matches[1]);
                         $output .= "member={$member},{$name}\n";
                     } else {
                         $output .= "member={$member},{$name},hint:" . $matches[1] . "@ext-local\n";
                     }
                 } else {
                     $output .= "member=" . $member . "\n";
                 }
             }
         } else {
             if ($ast_ge_14_25) {
                 foreach ($members as $member) {
                     preg_match("/^Local\\/([\\d]+)\\@*/", $member, $matches);
                     if (isset($matches[1]) && isset($devices[$matches[1]])) {
                         $name = sprintf('"%s"', $users[$matches[1]]);
                         //str_replace(',','\,',$name);
                         $qnostate = queues_get_qnostate($matches[1]);
                         if ($qnostate == 'ignorestate') {
                             freepbx_log(FPBX_LOG_NOTICE, "Ignoring State information for Queue Member: " . $matches[1]);
                             $output .= "member={$member},{$name}\n";
                         } else {
                             $output .= "member={$member},{$name}," . $devices[$matches[1]] . "\n";
                         }
                     } else {
                         $output .= "member=" . $member . "\n";
                     }
                 }
             } else {
                 foreach ($members as $member) {
                     $output .= "member=" . $member . "\n";
                 }
             }
         }
         if (isset($this->_queues_additional[$result[0]])) {
             foreach ($this->_queues_additional[$result[0]] as $qsetting) {
                 $output .= $qsetting['key'] . "=" . $qsetting['value'] . "\n";
             }
         }
         $output .= $additional . "\n";
     }
     // Before returning the results, do an integrity check to see
     // if there are any truncated compound recrodings and if so
     // crate a noticication.
     //
     $nt = notifications::create($db);
     $compound_recordings = queues_check_compoundrecordings();
     if (empty($compound_recordings)) {
         $nt->delete('queues', 'COMPOUNDREC');
     } else {
         $str = _('Warning, there are compound recordings configured in ' . 'one or more Queue configurations. Queues can not play these ' . 'so they have been truncated to the first sound file. You ' . 'should correct this problem.<br />Details:<br /><br />');
         foreach ($compound_recordings as $item) {
             $str .= sprintf(_("Queue - %s (%s): %s<br />"), $item['extension'], $item['descr'], $item['error']);
         }
         $nt->add_error('queues', 'COMPOUNDREC', _("Compound Recordings in Queues Detected"), $str);
     }
     return $output;
 }
Exemple #8
0
 function generate_queues_additional($ast_version)
 {
     global $db;
     global $amp_conf;
     $additional = "";
     $output = "";
     // Asterisk 1.4 does not like blank assignments so just don't put them there
     //
     $ver12 = version_compare($ast_version, '1.4', 'lt');
     $ver16 = version_compare($ast_version, '1.6', 'ge');
     $ast_ge_14_25 = version_compare($ast_version, '1.4.25', 'ge');
     // legacy but in case someone was using this we will leave it
     //
     $sql = "SELECT keyword,data FROM queues_details WHERE id='-1' AND keyword <> 'account'";
     $results = $db->getAll($sql, DB_FETCHMODE_ASSOC);
     if (DB::IsError($results)) {
         die($results->getMessage());
     }
     foreach ($results as $result) {
         if (!$ver12 && trim($result['data']) == '') {
             continue;
         }
         $additional .= $result['keyword'] . "=" . $result['data'] . "\n";
     }
     if ($ast_ge_14_25) {
         $devices = array();
         $device_results = core_devices_list('all', 'full', true);
         if (is_array($device_results)) {
             foreach ($device_results as $device) {
                 if (!isset($devices[$device['user']]) && $device['devicetype'] == 'fixed') {
                     $devices[$device['user']] = $device['dial'];
                 }
             }
             unset($device_results);
         }
     }
     if ($amp_conf['USEQUEUESTATE'] || $ast_ge_14_25) {
         $users = array();
         $user_results = core_users_list();
         if (is_array($user_results)) {
             foreach ($user_results as $user) {
                 $users[$user[0]] = $user[1];
             }
             unset($user_results);
         }
     }
     $results = queues_list(true);
     foreach ($results as $result) {
         $output .= "[" . $result[0] . "]\n";
         // passing 2nd param 'true' tells queues_get to send back only queue_conf required params
         // and nothing else
         //
         $results2 = queues_get($result[0], true);
         // memebers is an array of members so we set it asside and remove it
         // and then generate each later
         //
         $members = $results2['member'];
         unset($results2['member']);
         foreach ($results2 as $keyword => $data) {
             if ($ver12) {
                 switch ($keyword) {
                     case 'ringinuse':
                     case 'autofill':
                         break;
                     case 'retry':
                         if ($data == 'none') {
                             $data = 0;
                         }
                         // no break, fallthrough to default
                     // no break, fallthrough to default
                     default:
                         $output .= $keyword . "=" . $data . "\n";
                         break;
                 }
             } else {
                 switch ($keyword) {
                     case trim($data) == '':
                     case 'monitor-join':
                         break;
                     case 'monitor-format':
                         if (strtolower($data) != 'no') {
                             $output .= "monitor-type=mixmonitor\n";
                             $output .= $keyword . "=" . $data . "\n";
                         }
                         break;
                     case 'announce-position':
                         if ($ver16) {
                             $output .= $keyword . "=" . $data . "\n";
                         }
                         break;
                     case 'retry':
                         if ($data == 'none') {
                             $data = 0;
                         }
                         // no break, fallthrough to default
                     // no break, fallthrough to default
                     default:
                         $output .= $keyword . "=" . $data . "\n";
                         break;
                 }
             }
         }
         // Now pull out all the memebers, one line for each
         //
         if ($amp_conf['USEQUEUESTATE']) {
             foreach ($members as $member) {
                 preg_match("/^Local\\/([\\d]+)\\@*/", $member, $matches);
                 if (isset($matches[1]) && isset($users[$matches[1]])) {
                     $name = $users[$matches[1]];
                     str_replace(',', '\\,', $name);
                     $output .= "member={$member},{$name},hint:" . $matches[1] . "@ext-local\n";
                 } else {
                     $output .= "member=" . $member . "\n";
                 }
             }
         } else {
             if ($ast_ge_14_25) {
                 foreach ($members as $member) {
                     preg_match("/^Local\\/([\\d]+)\\@*/", $member, $matches);
                     if (isset($matches[1]) && isset($devices[$matches[1]])) {
                         $name = $users[$matches[1]];
                         str_replace(',', '\\,', $name);
                         $output .= "member={$member},{$name}," . $devices[$matches[1]] . "\n";
                     } else {
                         $output .= "member=" . $member . "\n";
                     }
                 }
             } else {
                 foreach ($members as $member) {
                     $output .= "member=" . $member . "\n";
                 }
             }
         }
         $output .= $additional . "\n";
     }
     // Before returning the results, do an integrity check to see
     // if there are any truncated compound recrodings and if so
     // crate a noticication.
     //
     $nt = notifications::create($db);
     $compound_recordings = queues_check_compoundrecordings();
     if (empty($compound_recordings)) {
         $nt->delete('queues', 'COMPOUNDREC');
     } else {
         $str = _("Warning, there are compound recordings configured in one or more Queue configurations. Queues can not play these so they have been truncated to the first sound file. You should correct this problem.<br />Details:<br /><br />");
         foreach ($compound_recordings as $item) {
             $str .= sprintf(_("Queue - %s (%s): %s<br />"), $item['extension'], $item['descr'], $item['error']);
         }
         $nt->add_error('queues', 'COMPOUNDREC', _("Compound Recordings in Queues Detected"), $str);
     }
     return $output;
 }
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;
    }
}