Newer
Older
goto out;
} else if (res2) {
/* Caller must have hung up just before being connected*/
ast_log(LOG_NOTICE, "Caller was about to talk to agent on %s but the caller hungup.\n", peer->name);
Russell Bryant
committed
ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "ABANDON", "%d|%d|%ld", qe->pos, qe->opos, (long) time(NULL) - qe->start);
record_abandoned(qe);
ast_hangup(peer);
Steve Murphy
committed
if (ringing)
ast_indicate(qe->chan,-1);
else
ast_moh_stop(qe->chan);
/* If appropriate, log that we have a destination channel */
if (qe->chan->cdr)
ast_cdr_setdestchan(qe->chan->cdr, peer->name);
/* Make sure channels are compatible */
res = ast_channel_make_compatible(qe->chan, peer);
if (res < 0) {
ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "SYSCOMPAT", "%s", "");
ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", qe->chan->name, peer->name);
/* Play announcement to the caller telling it's his turn if defined */
if (!ast_strlen_zero(qe->parent->sound_callerannounce)) {
if (play_file(qe->chan, qe->parent->sound_callerannounce))
ast_log(LOG_WARNING, "Announcement file '%s' is unavailable, continuing anyway...\n", qe->parent->sound_callerannounce);
}
Mark Michelson
committed
ao2_lock(qe->parent);
/* if setinterfacevar is defined, make member variables available to the channel */
/* use pbx_builtin_setvar to set a load of variables with one call */
if (qe->parent->setinterfacevar) {
snprintf(interfacevar,sizeof(interfacevar), "MEMBERINTERFACE=%s|MEMBERNAME=%s|MEMBERCALLS=%d|MEMBERLASTCALL=%ld|MEMBERPENALTY=%d|MEMBERDYNAMIC=%d|MEMBERREALTIME=%d",
member->interface, member->membername, member->calls, (long)member->lastcall, member->penalty, member->dynamic, member->realtime);
pbx_builtin_setvar(qe->chan, interfacevar);
}
/* if setqueueentryvar is defined, make queue entry (i.e. the caller) variables available to the channel */
/* use pbx_builtin_setvar to set a load of variables with one call */
if (qe->parent->setqueueentryvar) {
snprintf(interfacevar,sizeof(interfacevar), "QEHOLDTIME=%ld|QEORIGINALPOS=%d",
(long) time(NULL) - qe->start, qe->opos);
pbx_builtin_setvar(qe->chan, interfacevar);
}
/* try to set queue variables if configured to do so*/
set_queue_variables(qe);
Mark Michelson
committed
ao2_unlock(qe->parent);
/* Begin Monitoring */
if (qe->parent->monfmt && *qe->parent->monfmt) {
if (!qe->parent->montype) {
ast_debug(1, "Starting Monitor as requested.\n");
monitorfilename = pbx_builtin_getvar_helper(qe->chan, "MONITOR_FILENAME");
if (pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC") || pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC_ARGS"))
which = qe->chan;
else
which = peer;
if (monitorfilename)
Jason Parker
committed
ast_monitor_start(which, qe->parent->monfmt, monitorfilename, 1, X_REC_IN | X_REC_OUT);
Jason Parker
committed
ast_monitor_start(which, qe->parent->monfmt, qe->chan->cdr->uniqueid, 1, X_REC_IN | X_REC_OUT);
else {
/* Last ditch effort -- no CDR, make up something */
snprintf(tmpid, sizeof(tmpid), "chan-%lx", ast_random());
Jason Parker
committed
ast_monitor_start(which, qe->parent->monfmt, tmpid, 1, X_REC_IN | X_REC_OUT);
}
} else {
ast_debug(1, "Starting MixMonitor as requested.\n");
monitorfilename = pbx_builtin_getvar_helper(qe->chan, "MONITOR_FILENAME");
if (!monitorfilename) {
if (qe->chan->cdr)
Tilghman Lesher
committed
ast_copy_string(tmpid, qe->chan->cdr->uniqueid, sizeof(tmpid));
snprintf(tmpid, sizeof(tmpid), "chan-%lx", ast_random());
} else {
Tilghman Lesher
committed
const char *m = monitorfilename;
for (p = tmpid2; p < tmpid2 + sizeof(tmpid2) - 1; p++, m++) {
switch (*m) {
case '^':
if (*(m + 1) == '{')
*p = '$';
break;
case ',':
*p++ = '\\';
/* Fall through */
default:
*p = *m;
}
Tilghman Lesher
committed
if (*m == '\0')
break;
}
Tilghman Lesher
committed
if (p == tmpid2 + sizeof(tmpid2))
tmpid2[sizeof(tmpid2) - 1] = '\0';
pbx_substitute_variables_helper(qe->chan, tmpid2, tmpid, sizeof(tmpid) - 1);
}
monitor_exec = pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC");
monitor_options = pbx_builtin_getvar_helper(qe->chan, "MONITOR_OPTIONS");
if (monitor_exec) {
Tilghman Lesher
committed
const char *m = monitor_exec;
for (p = meid2; p < meid2 + sizeof(meid2) - 1; p++, m++) {
switch (*m) {
case '^':
if (*(m + 1) == '{')
*p = '$';
break;
case ',':
*p++ = '\\';
/* Fall through */
default:
*p = *m;
}
Tilghman Lesher
committed
if (*m == '\0')
break;
}
Tilghman Lesher
committed
if (p == meid2 + sizeof(meid2))
meid2[sizeof(meid2) - 1] = '\0';
pbx_substitute_variables_helper(qe->chan, meid2, meid, sizeof(meid) - 1);
Tilghman Lesher
committed
snprintf(tmpid2, sizeof(tmpid2), "%s.%s", tmpid, qe->parent->monfmt);
mixmonapp = pbx_findapp("MixMonitor");
BJ Weschke
committed
if (!monitor_options)
if (mixmonapp) {
if (!ast_strlen_zero(monitor_exec))
Tilghman Lesher
committed
snprintf(mixmonargs, sizeof(mixmonargs), "%s,b%s,%s", tmpid2, monitor_options, monitor_exec);
Tilghman Lesher
committed
snprintf(mixmonargs, sizeof(mixmonargs), "%s,b%s", tmpid2, monitor_options);
ast_debug(1, "Arguments being passed to MixMonitor: %s\n", mixmonargs);
/* We purposely lock the CDR so that pbx_exec does not update the application data */
if (qe->chan->cdr)
ast_set_flag(qe->chan->cdr, AST_CDR_FLAG_LOCKED);
ret = pbx_exec(qe->chan, mixmonapp, mixmonargs);
if (qe->chan->cdr)
ast_clear_flag(qe->chan->cdr, AST_CDR_FLAG_LOCKED);
} else
ast_log(LOG_WARNING, "Asked to run MixMonitor on this call, but cannot find the MixMonitor app!\n");
Mark Spencer
committed
}
/* Drop out of the queue at this point, to prepare for next caller */
leave_queue(qe);
if (!ast_strlen_zero(url) && ast_channel_supports_html(peer)) {
ast_debug(1, "app_queue: sendurl=%s.\n", url);
/* run a macro for this connection if defined. The macro simply returns, no action is taken on the result */
/* use macro from dialplan if passed as a option, otherwise use the default queue macro */
if (!ast_strlen_zero(macro)) {
macroexec = ast_strdupa(macro);
} else {
if (qe->parent->membermacro)
macroexec = ast_strdupa(qe->parent->membermacro);
}
if (!ast_strlen_zero(macroexec)) {
ast_debug(1, "app_queue: macro=%s.\n", macroexec);
res = ast_autoservice_start(qe->chan);
if (res) {
ast_log(LOG_ERROR, "Unable to start autoservice on calling channel\n");
res = -1;
}
app = pbx_findapp("Macro");
Tilghman Lesher
committed
if (app) {
res = pbx_exec(qe->chan, app, macroexec);
ast_debug(1, "Macro exited with status %d\n", res);
res = 0;
} else {
ast_log(LOG_ERROR, "Could not find application Macro\n");
res = -1;
}
Tilghman Lesher
committed
if (ast_autoservice_stop(qe->chan) < 0) {
ast_log(LOG_ERROR, "Could not stop autoservice on calling channel\n");
res = -1;
}
}
Steve Murphy
committed
3203
3204
3205
3206
3207
3208
3209
3210
3211
3212
3213
3214
3215
3216
3217
3218
3219
3220
3221
3222
3223
3224
/* run a gosub for this connection if defined. The gosub simply returns, no action is taken on the result */
/* use gosub from dialplan if passed as a option, otherwise use the default queue gosub */
if (!ast_strlen_zero(gosub)) {
gosubexec = ast_strdupa(gosub);
} else {
if (qe->parent->membergosub)
gosubexec = ast_strdupa(qe->parent->membergosub);
}
if (!ast_strlen_zero(gosubexec)) {
if (option_debug)
ast_log(LOG_DEBUG, "app_queue: gosub=%s.\n", gosubexec);
res = ast_autoservice_start(qe->chan);
if (res) {
ast_log(LOG_ERROR, "Unable to start autoservice on calling channel\n");
res = -1;
}
app = pbx_findapp("Gosub");
if (app) {
char *gosub_args, *gosub_argstart;
/* Set where we came from */
ast_copy_string(qe->chan->context, "app_dial_gosub_virtual_context", sizeof(qe->chan->context));
ast_copy_string(qe->chan->exten, "s", sizeof(qe->chan->exten));
qe->chan->priority = 0;
Tilghman Lesher
committed
gosub_argstart = strchr(gosubexec, ',');
if (gosub_argstart) {
*gosub_argstart = 0;
Tilghman Lesher
committed
asprintf(&gosub_args, "%s,s,1(%s)", gosubexec, gosub_argstart + 1);
*gosub_argstart = '|';
} else {
Tilghman Lesher
committed
asprintf(&gosub_args, "%s,s,1", gosubexec);
}
if (gosub_args) {
res = pbx_exec(qe->chan, app, gosub_args);
ast_pbx_run(qe->chan);
free(gosub_args);
if (option_debug)
ast_log(LOG_DEBUG, "Gosub exited with status %d\n", res);
} else
ast_log(LOG_ERROR, "Could not Allocate string for Gosub arguments -- Gosub Call Aborted!\n");
Steve Murphy
committed
res = 0;
} else {
ast_log(LOG_ERROR, "Could not find application Gosub\n");
res = -1;
}
if (ast_autoservice_stop(qe->chan) < 0) {
ast_log(LOG_ERROR, "Could not stop autoservice on calling channel\n");
res = -1;
}
}
if (!ast_strlen_zero(agi)) {
ast_debug(1, "app_queue: agi=%s.\n", agi);
app = pbx_findapp("agi");
if (app) {
agiexec = ast_strdupa(agi);
ret = pbx_exec(qe->chan, app, agiexec);
ast_log(LOG_WARNING, "Asked to execute an AGI on this channel, but could not find application (agi)!\n");
}
Jason Parker
committed
ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "CONNECT", "%ld|%s|%ld", (long) time(NULL) - qe->start, peer->uniqueid,
(long)(orig - to > 0 ? (orig - to) / 1000 : 0));
if (update_cdr && qe->chan->cdr)
ast_copy_string(qe->chan->cdr->dstchannel, member->membername, sizeof(qe->chan->cdr->dstchannel));
Mark Spencer
committed
if (qe->parent->eventwhencalled)
manager_event(EVENT_FLAG_AGENT, "AgentConnect",
"Queue: %s\r\n"
"Uniqueid: %s\r\n"
"Channel: %s\r\n"
"Member: %s\r\n"
"Holdtime: %ld\r\n"
"BridgedChannel: %s\r\n"
Jason Parker
committed
"Ringtime: %ld\r\n"
queuename, qe->chan->uniqueid, peer->name, member->interface, member->membername,
Jason Parker
committed
(long) time(NULL) - qe->start, peer->uniqueid, (long)(orig - to > 0 ? (orig - to) / 1000 : 0),
qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : "");
Kevin P. Fleming
committed
ast_copy_string(oldcontext, qe->chan->context, sizeof(oldcontext));
ast_copy_string(oldexten, qe->chan->exten, sizeof(oldexten));
Mark Spencer
committed
bridge = ast_bridge_call(qe->chan,peer, &bridge_config);
if (strcasecmp(oldcontext, qe->chan->context) || strcasecmp(oldexten, qe->chan->exten)) {
ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "TRANSFER", "%s|%s|%ld|%ld",
qe->chan->exten, qe->chan->context, (long) (callstart - qe->start),
(long) (time(NULL) - callstart));
send_agent_complete(qe, queuename, peer, member, callstart, vars, sizeof(vars), TRANSFER);
Russell Bryant
committed
} else if (ast_check_hangup(qe->chan)) {
ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "COMPLETECALLER", "%ld|%ld|%d",
(long) (callstart - qe->start), (long) (time(NULL) - callstart), qe->opos);
send_agent_complete(qe, queuename, peer, member, callstart, vars, sizeof(vars), CALLER);
ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "COMPLETEAGENT", "%ld|%ld|%d",
(long) (callstart - qe->start), (long) (time(NULL) - callstart), qe->opos);
send_agent_complete(qe, queuename, peer, member, callstart, vars, sizeof(vars), AGENT);
if (bridge != AST_PBX_NO_HANGUP_PEER)
update_queue(qe->parent, member, callcompletedinsl);
Mark Spencer
committed
hangupcalls(outgoing, NULL);
return res;
}
static int wait_a_bit(struct queue_ent *qe)
{
/* Don't need to hold the lock while we setup the outgoing calls */
int retrywait = qe->parent->retry * 1000;
Mark Spencer
committed
int res = ast_waitfordigit(qe->chan, retrywait);
if (res > 0 && !valid_exit(qe, res))
res = 0;
return res;
static struct member *interface_exists(struct call_queue *q, const char *interface)
struct ao2_iterator mem_iter;
if (!q)
return NULL;
mem_iter = ao2_iterator_init(q->members, 0);
while ((mem = ao2_iterator_next(&mem_iter))) {
if (!strcasecmp(interface, mem->interface))
return mem;
/* Dump all members in a specific queue to the database
* <pm_family>/<queuename> = <interface>;<penalty>;<paused>[|...]
static void dump_queue_members(struct call_queue *pm_queue)
char value[PM_MAX_LEN];
int value_len = 0;
int res;
struct ao2_iterator mem_iter;
memset(value, 0, sizeof(value));
mem_iter = ao2_iterator_init(pm_queue->members, 0);
while ((cur_member = ao2_iterator_next(&mem_iter))) {
if (!cur_member->dynamic) {
ao2_ref(cur_member, -1);
}
res = snprintf(value + value_len, sizeof(value) - value_len, "%s%s;%d;%d;%s",
value_len ? "|" : "", cur_member->interface, cur_member->penalty, cur_member->paused, cur_member->membername);
ao2_ref(cur_member, -1);
if (res != strlen(value + value_len)) {
ast_log(LOG_WARNING, "Could not create persistent member string, out of space\n");
break;
}
value_len += res;
if (value_len && !cur_member) {
if (ast_db_put(pm_family, pm_queue->name, value))
ast_log(LOG_WARNING, "failed to create persistent dynamic entry!\n");
} else
/* Delete the entry if the queue is empty or there is an error */
ast_db_del(pm_family, pm_queue->name);
static int remove_from_queue(const char *queuename, const char *interface)
struct call_queue *q, tmpq = {
.name = queuename,
};
int res = RES_NOSUCHQUEUE;
ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface));
if ((q = ao2_find(queues, &tmpq, OBJ_POINTER))) {
Mark Michelson
committed
ao2_lock(q);
if ((mem = ao2_find(q->members, &tmpmem, OBJ_POINTER))) {
/* XXX future changes should beware of this assumption!! */
if(!mem->dynamic) {
ao2_ref(mem, -1);
manager_event(EVENT_FLAG_AGENT, "QueueMemberRemoved",
"Location: %s\r\n"
"MemberName: %s\r\n",
q->name, mem->interface, mem->membername);
if (queue_persistent_members)
dump_queue_members(q);
res = RES_OKAY;
} else {
res = RES_EXISTS;
Mark Michelson
committed
ao2_unlock(q);
queue_unref(q);
if (res == RES_OKAY)
BJ Weschke
committed
remove_from_interfaces(interface);
return res;
}
BJ Weschke
committed
static int add_to_queue(const char *queuename, const char *interface, const char *membername, int penalty, int paused, int dump)
struct member *new_member, *old_member;
int res = RES_NOSUCHQUEUE;
Tilghman Lesher
committed
/* \note Ensure the appropriate realtime queue is loaded. Note that this
* short-circuits if the queue is already in memory. */
if (!(q = load_realtime_queue(queuename)))
return res;
Tilghman Lesher
committed
Mark Michelson
committed
ao2_lock(queues);
Tilghman Lesher
committed
Mark Michelson
committed
ao2_lock(q);
if ((old_member = interface_exists(q, interface)) == NULL) {
add_to_interfaces(interface);
if ((new_member = create_queue_member(interface, membername, penalty, paused))) {
new_member->dynamic = 1;
ao2_link(q->members, new_member);
manager_event(EVENT_FLAG_AGENT, "QueueMemberAdded",
"Membership: %s\r\n"
"Penalty: %d\r\n"
"CallsTaken: %d\r\n"
"LastCall: %d\r\n"
"Status: %d\r\n"
"Paused: %d\r\n",
q->name, new_member->interface, new_member->membername,
new_member->penalty, new_member->calls, (int) new_member->lastcall,
new_member->status, new_member->paused);
ao2_ref(new_member, -1);
new_member = NULL;
if (dump)
dump_queue_members(q);
res = RES_OKAY;
Tilghman Lesher
committed
} else {
Mark Michelson
committed
ao2_unlock(q);
ao2_unlock(queues);
return res;
}
static int set_member_paused(const char *queuename, const char *interface, const char *reason, int paused)
Mark Michelson
committed
struct ao2_iterator queue_iter;
/* Special event for when all queues are paused - individual events still generated */
/* XXX In all other cases, we use the membername, but since this affects all queues, we cannot */
if (ast_strlen_zero(queuename))
ast_queue_log("NONE", "NONE", interface, (paused ? "PAUSEALL" : "UNPAUSEALL"), "%s", "");
Mark Michelson
committed
queue_iter = ao2_iterator_init(queues, 0);
while((q = ao2_iterator_next(&queue_iter))) {
ao2_lock(q);
if (ast_strlen_zero(queuename) || !strcasecmp(q->name, queuename)) {
if ((mem = interface_exists(q, interface))) {
found++;
if (mem->paused == paused) {
ast_debug(1, "%spausing already-%spaused queue member %s:%s\n", (paused ? "" : "un"), (paused ? "" : "un"), q->name, interface);
mem->paused = paused;
if (queue_persistent_members)
update_realtime_member_field(mem, q->name, "paused", paused ? "1" : "0");
ast_queue_log(q->name, "NONE", mem->membername, (paused ? "PAUSE" : "UNPAUSE"), "%s", S_OR(reason, ""));
if (!ast_strlen_zero(reason)) {
manager_event(EVENT_FLAG_AGENT, "QueueMemberPaused",
"Queue: %s\r\n"
"Location: %s\r\n"
"MemberName: %s\r\n"
"Paused: %d\r\n"
"Reason: %s\r\n",
q->name, mem->interface, mem->membername, paused, reason);
} else {
manager_event(EVENT_FLAG_AGENT, "QueueMemberPaused",
"Queue: %s\r\n"
"Location: %s\r\n"
"MemberName: %s\r\n"
"Paused: %d\r\n",
q->name, mem->interface, mem->membername, paused);
}
Mark Michelson
committed
ao2_unlock(q);
queue_unref(q);
return found ? RESULT_SUCCESS : RESULT_FAILURE;
3554
3555
3556
3557
3558
3559
3560
3561
3562
3563
3564
3565
3566
3567
3568
3569
3570
3571
3572
3573
3574
3575
3576
3577
3578
3579
3580
3581
3582
3583
3584
3585
3586
3587
3588
3589
3590
3591
3592
3593
3594
3595
3596
3597
3598
3599
3600
/* \brief Sets members penalty, if queuename=NULL we set member penalty in all the queues. */
static int set_member_penalty(char *queuename, char *interface, int penalty)
{
int foundinterface = 0, foundqueue = 0;
struct call_queue *q;
struct member *mem;
struct ao2_iterator queue_iter;
queue_iter = ao2_iterator_init(queues, 0);
while ((q = ao2_iterator_next(&queue_iter))) {
ao2_lock(q);
if (ast_strlen_zero(queuename) || !strcasecmp(q->name, queuename)) {
foundqueue++;
if ((mem = interface_exists(q, interface))) {
foundinterface++;
mem->penalty = penalty;
ast_queue_log(q->name, "NONE", interface, "PENALTY", "%d", penalty);
manager_event(EVENT_FLAG_AGENT, "QueueMemberPenalty",
"Queue: %s\r\n"
"Location: %s\r\n"
"Penalty: %d\r\n",
q->name, mem->interface, penalty);
}
}
ao2_unlock(q);
queue_unref(q);
}
if (foundinterface) {
return RESULT_SUCCESS;
} else if (foundqueue) {
ast_log (LOG_ERROR, "Invalid queuename\n");
} else {
ast_log (LOG_ERROR, "Invalid interface\n");
}
return RESULT_FAILURE;
}
/* \brief Gets members penalty.
*
* \return Return the members penalty or RESULT_FAILURE on error. */
static int get_member_penalty(char *queuename, char *interface)
{
int foundqueue = 0, penalty;
struct call_queue *q, tmpq = {
.name = queuename,
};
struct member *mem;
if ((q = ao2_find(queues, &tmpq, OBJ_POINTER))) {
3607
3608
3609
3610
3611
3612
3613
3614
3615
3616
3617
3618
3619
3620
3621
3622
3623
3624
3625
3626
3627
foundqueue = 1;
ao2_lock(q);
if ((mem = interface_exists(q, interface))) {
penalty = mem->penalty;
ao2_unlock(q);
queue_unref(q);
return penalty;
}
ao2_unlock(q);
queue_unref(q);
}
/* some useful debuging */
if (foundqueue)
ast_log (LOG_ERROR, "Invalid queuename\n");
else
ast_log (LOG_ERROR, "Invalid interface\n");
return RESULT_FAILURE;
}
/* Reload dynamic queue members persisted into the astdb */
static void reload_queue_members(void)
{
const char *queue_name;
char *member;
char *interface;
char *penalty_tok;
int penalty = 0;
char *paused_tok;
int paused = 0;
struct ast_db_entry *db_tree;
struct ast_db_entry *entry;
struct call_queue *cur_queue;
char queue_data[PM_MAX_LEN];
Mark Michelson
committed
ao2_lock(queues);
/* Each key in 'pm_family' is the name of a queue */
db_tree = ast_db_gettree(pm_family, NULL);
for (entry = db_tree; entry; entry = entry->next) {
queue_name = entry->key + strlen(pm_family) + 2;
{
struct call_queue tmpq = {
.name = queue_name,
};
cur_queue = ao2_find(queues, &tmpq, OBJ_POINTER);
}
if (!cur_queue)
cur_queue = load_realtime_queue(queue_name);
if (!cur_queue) {
/* If the queue no longer exists, remove it from the
* database */
ast_log(LOG_WARNING, "Error loading persistent queue: '%s': it does not exist\n", queue_name);
ast_db_del(pm_family, queue_name);
Mark Michelson
committed
}
Mark Michelson
committed
if (ast_db_get(pm_family, queue_name, queue_data, PM_MAX_LEN)) {
queue_unref(cur_queue);
Mark Michelson
committed
}
Tilghman Lesher
committed
while ((member = strsep(&cur_ptr, ",|"))) {
if (ast_strlen_zero(member))
continue;
interface = strsep(&member, ";");
penalty_tok = strsep(&member, ";");
paused_tok = strsep(&member, ";");
membername = strsep(&member, ";");
ast_log(LOG_WARNING, "Error parsing persistent member string for '%s' (penalty)\n", queue_name);
break;
}
penalty = strtol(penalty_tok, NULL, 10);
if (errno == ERANGE) {
ast_log(LOG_WARNING, "Error converting penalty: %s: Out of range.\n", penalty_tok);
break;
}
if (!paused_tok) {
ast_log(LOG_WARNING, "Error parsing persistent member string for '%s' (paused)\n", queue_name);
break;
}
paused = strtol(paused_tok, NULL, 10);
if ((errno == ERANGE) || paused < 0 || paused > 1) {
ast_log(LOG_WARNING, "Error converting paused: %s: Expected 0 or 1.\n", paused_tok);
break;
}
if (ast_strlen_zero(membername))
membername = interface;
ast_debug(1, "Reload Members: Queue: %s Member: %s Name: %s Penalty: %d Paused: %d\n", queue_name, interface, membername, penalty, paused);
if (add_to_queue(queue_name, interface, membername, penalty, paused, 0) == RES_OUTOFMEMORY) {
ast_log(LOG_ERROR, "Out of Memory when reloading persistent queue member\n");
break;
Mark Michelson
committed
queue_unref(cur_queue);
Mark Michelson
committed
ao2_unlock(queues);
ast_log(LOG_NOTICE, "Queue members successfully reloaded from database.\n");
static int pqm_exec(struct ast_channel *chan, void *data)
{
char *parse;
AST_DECLARE_APP_ARGS(args,
AST_APP_ARG(queuename);
AST_APP_ARG(interface);
AST_APP_ARG(options);
AST_APP_ARG(reason);
if (ast_strlen_zero(data)) {
ast_log(LOG_WARNING, "PauseQueueMember requires an argument ([queuename]|interface[|options][|reason])\n");
Russell Bryant
committed
parse = ast_strdupa(data);
AST_STANDARD_APP_ARGS(args, parse);
if (ast_strlen_zero(args.interface)) {
ast_log(LOG_WARNING, "Missing interface argument to PauseQueueMember ([queuename]|interface[|options[|reason]])\n");
if (set_member_paused(args.queuename, args.interface, args.reason, 1)) {
ast_log(LOG_WARNING, "Attempt to pause interface %s, not found\n", args.interface);
pbx_builtin_setvar_helper(chan, "PQMSTATUS", "NOTFOUND");
pbx_builtin_setvar_helper(chan, "PQMSTATUS", "PAUSED");
return 0;
}
static int upqm_exec(struct ast_channel *chan, void *data)
{
char *parse;
AST_DECLARE_APP_ARGS(args,
AST_APP_ARG(queuename);
AST_APP_ARG(interface);
AST_APP_ARG(options);
AST_APP_ARG(reason);
if (ast_strlen_zero(data)) {
ast_log(LOG_WARNING, "UnpauseQueueMember requires an argument ([queuename]|interface[|options[|reason]])\n");
Russell Bryant
committed
parse = ast_strdupa(data);
AST_STANDARD_APP_ARGS(args, parse);
if (ast_strlen_zero(args.interface)) {
ast_log(LOG_WARNING, "Missing interface argument to PauseQueueMember ([queuename]|interface[|options[|reason]])\n");
if (set_member_paused(args.queuename, args.interface, args.reason, 0)) {
ast_log(LOG_WARNING, "Attempt to unpause interface %s, not found\n", args.interface);
pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "NOTFOUND");
pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "UNPAUSED");
static int rqm_exec(struct ast_channel *chan, void *data)
{
int res=-1;
char *parse, *temppos = NULL;
AST_DECLARE_APP_ARGS(args,
AST_APP_ARG(queuename);
AST_APP_ARG(interface);
AST_APP_ARG(options);
);
if (ast_strlen_zero(data)) {
ast_log(LOG_WARNING, "RemoveQueueMember requires an argument (queuename[|interface[|options]])\n");
Russell Bryant
committed
parse = ast_strdupa(data);
AST_STANDARD_APP_ARGS(args, parse);
if (ast_strlen_zero(args.interface)) {
temppos = strrchr(args.interface, '-');
if (temppos)
*temppos = '\0';
switch (remove_from_queue(args.queuename, args.interface)) {
case RES_OKAY:
ast_queue_log(args.queuename, chan->uniqueid, args.interface, "REMOVEMEMBER", "%s", "");
ast_log(LOG_NOTICE, "Removed interface '%s' from queue '%s'\n", args.interface, args.queuename);
pbx_builtin_setvar_helper(chan, "RQMSTATUS", "REMOVED");
res = 0;
break;
case RES_EXISTS:
ast_debug(1, "Unable to remove interface '%s' from queue '%s': Not there\n", args.interface, args.queuename);
pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOTINQUEUE");
res = 0;
break;
case RES_NOSUCHQUEUE:
ast_log(LOG_WARNING, "Unable to remove interface from queue '%s': No such queue\n", args.queuename);
pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOSUCHQUEUE");
res = 0;
break;
case RES_NOT_DYNAMIC:
ast_log(LOG_WARNING, "Unable to remove interface from queue '%s': '%s' is not a dynamic member\n", args.queuename, args.interface);
pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOTDYNAMIC");
res = 0;
break;
return res;
}
static int aqm_exec(struct ast_channel *chan, void *data)
{
int res=-1;
char *parse, *temppos = NULL;
AST_DECLARE_APP_ARGS(args,
AST_APP_ARG(queuename);
AST_APP_ARG(interface);
AST_APP_ARG(penalty);
AST_APP_ARG(options);
if (ast_strlen_zero(data)) {
ast_log(LOG_WARNING, "AddQueueMember requires an argument (queuename[|[interface]|[penalty][|options][|membername]])\n");
Russell Bryant
committed
parse = ast_strdupa(data);
AST_STANDARD_APP_ARGS(args, parse);
if (ast_strlen_zero(args.interface)) {
temppos = strrchr(args.interface, '-');
if (temppos)
*temppos = '\0';
}
if (!ast_strlen_zero(args.penalty)) {
if ((sscanf(args.penalty, "%d", &penalty) != 1) || penalty < 0) {
ast_log(LOG_WARNING, "Penalty '%s' is invalid, must be an integer >= 0\n", args.penalty);
penalty = 0;
switch (add_to_queue(args.queuename, args.interface, args.membername, penalty, 0, queue_persistent_members)) {
case RES_OKAY:
ast_queue_log(args.queuename, chan->uniqueid, args.interface, "ADDMEMBER", "%s", "");
ast_log(LOG_NOTICE, "Added interface '%s' to queue '%s'\n", args.interface, args.queuename);
pbx_builtin_setvar_helper(chan, "AQMSTATUS", "ADDED");
res = 0;
break;
case RES_EXISTS:
ast_log(LOG_WARNING, "Unable to add interface '%s' to queue '%s': Already there\n", args.interface, args.queuename);
pbx_builtin_setvar_helper(chan, "AQMSTATUS", "MEMBERALREADY");
res = 0;
break;
case RES_NOSUCHQUEUE:
ast_log(LOG_WARNING, "Unable to add interface to queue '%s': No such queue\n", args.queuename);
pbx_builtin_setvar_helper(chan, "AQMSTATUS", "NOSUCHQUEUE");
res = 0;
break;
case RES_OUTOFMEMORY:
ast_log(LOG_ERROR, "Out of memory adding member %s to queue %s\n", args.interface, args.queuename);
break;
}
static int ql_exec(struct ast_channel *chan, void *data)
{
char *parse;
AST_DECLARE_APP_ARGS(args,
AST_APP_ARG(queuename);
AST_APP_ARG(uniqueid);
AST_APP_ARG(event);
AST_APP_ARG(params);
);
if (ast_strlen_zero(data)) {
ast_log(LOG_WARNING, "QueueLog requires arguments (queuename|uniqueid|membername|event[|additionalinfo]\n");
return -1;
}
parse = ast_strdupa(data);
AST_STANDARD_APP_ARGS(args, parse);
if (ast_strlen_zero(args.queuename) || ast_strlen_zero(args.uniqueid)
|| ast_strlen_zero(args.membername) || ast_strlen_zero(args.event)) {
ast_log(LOG_WARNING, "QueueLog requires arguments (queuename|uniqueid|membername|event[|additionalinfo])\n");
return -1;
}
ast_queue_log(args.queuename, args.uniqueid, args.membername, args.event,
"%s", args.params ? args.params : "");
return 0;
}
static int queue_exec(struct ast_channel *chan, void *data)
{
int res=-1;
const char *user_priority;
Kevin P. Fleming
committed
const char *max_penalty_str;
Jason Parker
committed
int qcontinue = 0;
Kevin P. Fleming
committed
int max_penalty;
Mark Spencer
committed
enum queue_result reason = QUEUE_UNKNOWN;
/* whether to exit Queue application after the timeout hits */
int tries = 0;
int noption = 0;
Steve Murphy
committed
int makeannouncement = 0;
AST_DECLARE_APP_ARGS(args,
AST_APP_ARG(queuename);
AST_APP_ARG(options);
AST_APP_ARG(url);
AST_APP_ARG(announceoverride);
AST_APP_ARG(queuetimeoutstr);
AST_APP_ARG(agi);
AST_APP_ARG(macro);
Steve Murphy
committed
AST_APP_ARG(gosub);
/* Our queue entry */
struct queue_ent qe;
if (ast_strlen_zero(data)) {
ast_log(LOG_WARNING, "Queue requires an argument: queuename[|options[|URL[|announceoverride[|timeout[|agi]]]]]\n");
parse = ast_strdupa(data);
AST_STANDARD_APP_ARGS(args, parse);
Russell Bryant
committed
/* Setup our queue entry */
memset(&qe, 0, sizeof(qe));
qe.start = time(NULL);
/* set the expire time based on the supplied timeout; */
if (args.queuetimeoutstr)
qe.expire = qe.start + atoi(args.queuetimeoutstr);
else
qe.expire = 0;
/* Get the priority from the variable ${QUEUE_PRIO} */
user_priority = pbx_builtin_getvar_helper(chan, "QUEUE_PRIO");
if (user_priority) {
if (sscanf(user_priority, "%d", &prio) == 1) {
ast_debug(1, "%s: Got priority %d from ${QUEUE_PRIO}.\n", chan->name, prio);
} else {
ast_log(LOG_WARNING, "${QUEUE_PRIO}: Invalid value (%s), channel %s.\n",
Mark Spencer
committed
user_priority, chan->name);
prio = 0;
}
} else {
ast_debug(3, "NO QUEUE_PRIO variable found. Using default.\n");