Newer
Older
o->chan->cid.cid_rdnis = strdup(in->exten);
if (ast_call(o->chan, tmpchan, 0)) {
ast_log(LOG_NOTICE, "Failed to dial on local channel for call forward to '%s'\n", tmpchan);
o->stillgoing = 0;
ast_hangup(o->chan);
o->chan = NULL;
numnochan++;
}
}
/* Hangup the original channel now, in case we needed it */
ast_hangup(winner);
continue;
}
f = ast_read(winner);
if (f) {
if (f->frametype == AST_FRAME_CONTROL) {
switch(f->subclass) {
case AST_CONTROL_ANSWER:
/* This is our guy if someone answered. */
if (!peer) {
if (option_verbose > 2)
ast_verbose( VERBOSE_PREFIX_3 "%s answered %s\n", o->chan->name, in->name);
peer = o;
*allowredir_in = o->allowredirect_in;
*allowredir_out = o->allowredirect_out;
*allowdisconnect_in = o->allowdisconnect_out;
*allowdisconnect_out = o->allowdisconnect_out;
}
break;
case AST_CONTROL_BUSY:
if (option_verbose > 2)
ast_verbose( VERBOSE_PREFIX_3 "%s is busy\n", o->chan->name);
o->stillgoing = 0;
if (in->cdr)
ast_cdr_busy(in->cdr);
ast_hangup(o->chan);
o->chan = NULL;
if (qe->parent->strategy)
ring_one(qe, outgoing);
numbusies++;
break;
case AST_CONTROL_CONGESTION:
if (option_verbose > 2)
ast_verbose( VERBOSE_PREFIX_3 "%s is circuit-busy\n", o->chan->name);
o->stillgoing = 0;
if (in->cdr)
ast_cdr_busy(in->cdr);
ast_hangup(o->chan);
o->chan = NULL;
if (qe->parent->strategy)
ring_one(qe, outgoing);
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
numbusies++;
break;
case AST_CONTROL_RINGING:
if (option_verbose > 2)
ast_verbose( VERBOSE_PREFIX_3 "%s is ringing\n", o->chan->name);
if (!sentringing) {
#if 0
ast_indicate(in, AST_CONTROL_RINGING);
#endif
sentringing++;
}
break;
case AST_CONTROL_OFFHOOK:
/* Ignore going off hook */
break;
default:
ast_log(LOG_DEBUG, "Dunno what to do with control type %d\n", f->subclass);
}
}
ast_frfree(f);
} else {
o->stillgoing = 0;
ast_hangup(o->chan);
o->chan = NULL;
if (qe->parent->strategy)
ring_one(qe, outgoing);
}
}
o = o->next;
}
if (winner == in) {
f = ast_read(in);
#if 0
if (f && (f->frametype != AST_FRAME_VOICE))
printf("Frame type: %d, %d\n", f->frametype, f->subclass);
else if (!f || (f->frametype != AST_FRAME_VOICE))
printf("Hangup received on %s\n", in->name);
#endif
if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP))) {
/* Got hung up */
*to=-1;
return NULL;
}
if (f && (f->frametype == AST_FRAME_DTMF) && allowdisconnect_out && (f->subclass == '*')) {
ast_verbose(VERBOSE_PREFIX_3 "User hit %c to disconnect call.\n", f->subclass);
if (f && (f->frametype == AST_FRAME_DTMF) && (f->subclass != '*') && valid_exit(qe, f->subclass)) {
if (option_verbose > 3)
ast_verbose(VERBOSE_PREFIX_3 "User pressed digit: %c", f->subclass);
*to=0;
*digit=f->subclass;
return NULL;
}
}
if (!*to && (option_verbose > 2))
ast_verbose( VERBOSE_PREFIX_3 "Nobody picked up in %d ms\n", orig);
}
return peer;
}
static int is_our_turn(struct queue_ent *qe)
{
struct queue_ent *ch;
int res;
/* Atomically read the parent head -- does not need a lock */
ch = qe->parent->head;
/* If we are now at the top of the head, break out */
if (ch == qe) {
if (option_debug)
ast_log(LOG_DEBUG, "It's our turn (%s).\n", qe->chan->name);
res = 1;
} else {
if (option_debug)
ast_log(LOG_DEBUG, "It's not our turn (%s).\n", qe->chan->name);
res = 0;
}
return res;
}
static int wait_our_turn(struct queue_ent *qe, int ringing)
time_t now;
/* This is the holding pen for callers 2 through maxlen */
/* Atomically read the parent head -- does not need a lock */
/* If we are now at the top of the head, break out */
if (ch == qe) {
if (option_debug)
ast_log(LOG_DEBUG, "It's our turn (%s).\n", qe->chan->name);
/* If we have timed out, break out */
if ( qe->queuetimeout ) {
time(&now);
if ( (now - qe->start) >= qe->queuetimeout )
/* leave the queue if no agents, if enabled */
Mark Spencer
committed
if (has_no_members(qe->parent) && qe->parent->leavewhenempty) {
leave_queue(qe);
break;
}
/* Make a position announcement, if enabled */
if (qe->parent->announcefrequency && !ringing)
/* Wait a second before checking again */
res = ast_waitfordigit(qe->chan, RECHECK * 1000);
if (res)
break;
}
return res;
}
static int update_queue(struct ast_call_queue *q, struct member *member)
{
struct member *cur;
/* Since a reload could have taken place, we have to traverse the list to
be sure it's still valid */
ast_mutex_lock(&q->lock);
cur = q->members;
while(cur) {
time(&cur->lastcall);
cur->calls++;
break;
}
cur = cur->next;
}
ast_mutex_unlock(&q->lock);
return 0;
}
static int calc_metric(struct ast_call_queue *q, struct member *mem, int pos, struct queue_ent *qe, struct localuser *tmp)
{
switch (q->strategy) {
case QUEUE_STRATEGY_RINGALL:
/* Everyone equal, except for penalty */
tmp->metric = mem->penalty * 1000000;
case QUEUE_STRATEGY_ROUNDROBIN:
if (!pos) {
if (!q->wrapped) {
/* No more channels, start over */
q->rrpos = 0;
} else {
/* Prioritize next entry */
q->rrpos++;
q->wrapped = 0;
}
/* Fall through */
case QUEUE_STRATEGY_RRMEMORY:
if (pos < q->rrpos) {
tmp->metric = 1000 + pos;
} else {
if (pos > q->rrpos) {
/* Indicate there is another priority */
q->wrapped = 1;
tmp->metric = pos;
}
tmp->metric += mem->penalty * 1000000;
break;
case QUEUE_STRATEGY_RANDOM:
tmp->metric = rand() % 1000;
tmp->metric += mem->penalty * 1000000;
break;
case QUEUE_STRATEGY_FEWESTCALLS:
tmp->metric = mem->calls;
tmp->metric += mem->penalty * 1000000;
break;
case QUEUE_STRATEGY_LEASTRECENT:
if (!mem->lastcall)
tmp->metric = 0;
else
tmp->metric = 1000000 - (time(NULL) - mem->lastcall);
tmp->metric += mem->penalty * 1000000;
break;
default:
ast_log(LOG_WARNING, "Can't calculate metric for unknown strategy %d\n", q->strategy);
break;
static int try_calling(struct queue_ent *qe, char *options, char *announceoverride, char *url, int *go_on)
{
struct member *cur;
struct localuser *outgoing=NULL, *tmp = NULL;
int to;
int allowredir_in=0;
int allowredir_out=0;
int allowdisconnect_in=0;
int allowdisconnect_out=0;
char oldexten[AST_MAX_EXTENSION]="";
char oldcontext[AST_MAX_EXTENSION]="";
char queuename[256]="";
struct localuser *lpeer;
struct member *member;
int x=0;
char digit = 0;
struct ast_bridge_config config;
/* Hold the lock while we setup the outgoing calls */
ast_mutex_lock(&qe->parent->lock);
if (option_debug)
ast_log(LOG_DEBUG, "%s is trying to call a queue member.\n",
qe->chan->name);
strncpy(queuename, qe->parent->name, sizeof(queuename) - 1);
if (announceoverride && !ast_strlen_zero(announceoverride))
while(cur) {
/* Get a technology/[device:]number pair */
tmp = malloc(sizeof(struct localuser));
if (!tmp) {
ast_mutex_unlock(&qe->parent->lock);
ast_log(LOG_WARNING, "Out of memory\n");
goto out;
}
memset(tmp, 0, sizeof(struct localuser));
tmp->allowredirect_in = 1;
if (strchr(options, 'T'))
tmp->allowredirect_out = 1;
if (strchr(options, 'r'))
tmp->ringbackonly = 1;
if (strchr(options, 'm'))
tmp->musiconhold = 1;
if (strchr(options, 'd'))
tmp->dataquality = 1;
if (strchr(options, 'h'))
tmp->allowdisconnect_in = 1;
tmp->allowdisconnect_out = 1;
if ((strchr(options, 'n')) && (now - qe->start >= qe->parent->timeout))
if (option_debug) {
if (url)
ast_log(LOG_DEBUG, "Queue with URL=%s_\n", url);
else
ast_log(LOG_DEBUG, "Simple queue (no URL)\n");
}
tmp->member = cur; /* Never directly dereference! Could change on reload */
strncpy(tmp->tech, cur->tech, sizeof(tmp->tech)-1);
strncpy(tmp->numsubst, cur->loc, sizeof(tmp->numsubst)-1);
Mark Spencer
committed
tmp->oldstatus = cur->status;
tmp->lastcall = cur->lastcall;
/* If we're dialing by extension, look at the extension to know what to dial */
if ((newnum = strstr(tmp->numsubst, "BYEXTENSION"))) {
strncpy(restofit, newnum + strlen("BYEXTENSION"), sizeof(restofit)-1);
snprintf(newnum, sizeof(tmp->numsubst) - (newnum - tmp->numsubst), "%s%s", qe->chan->exten,restofit);
ast_log(LOG_DEBUG, "Dialing by extension %s\n", tmp->numsubst);
/* Special case: If we ring everyone, go ahead and ring them, otherwise
just calculate their metric for the appropriate strategy */
calc_metric(qe->parent, cur, x++, qe, tmp);
/* Put them in the list of outgoing thingies... We're ready now.
XXX If we're forcibly removed, these outgoing calls won't get
hung up XXX */
tmp->next = outgoing;
outgoing = tmp;
/* If this line is up, don't try anybody else */
if (outgoing->chan && (outgoing->chan->_state == AST_STATE_UP))
break;
cur = cur->next;
}
if (qe->parent->timeout)
to = qe->parent->timeout * 1000;
else
to = -1;
ring_one(qe, outgoing);
ast_mutex_unlock(&qe->parent->lock);
lpeer = wait_for_answer(qe, outgoing, &to, &allowredir_in, &allowredir_out, &allowdisconnect_in, &allowdisconnect_out, &digit);
ast_mutex_lock(&qe->parent->lock);
if (qe->parent->strategy == QUEUE_STRATEGY_RRMEMORY) {
store_next(qe, outgoing);
}
ast_mutex_unlock(&qe->parent->lock);
if (lpeer)
peer = lpeer->chan;
else
peer = NULL;
if (to) {
} else {
if (digit && valid_exit(qe, digit))
res=digit;
else
/* Nobody answered, next please? */
res=0;
}
if (option_debug)
ast_log(LOG_DEBUG, "%s: Nobody answered.\n", qe->chan->name);
goto out;
}
if (peer) {
/* Ah ha! Someone answered within the desired timeframe. Of course after this
we will always return with -1 so that it is hung up properly after the
conversation. */
if (!strcmp(qe->chan->type,"Zap")) {
if (tmp->dataquality) zapx = 0;
ast_channel_setoption(qe->chan,AST_OPTION_TONE_VERIFY,&zapx,sizeof(char),0);
}
if (!strcmp(peer->type,"Zap")) {
if (tmp->dataquality) zapx = 0;
ast_channel_setoption(peer,AST_OPTION_TONE_VERIFY,&zapx,sizeof(char),0);
}
/* Update parameters for the queue */
member = lpeer->member;
hanguptree(outgoing, peer);
outgoing = NULL;
if (announce || qe->parent->reportholdtime || qe->parent->memberdelay) {
res2 = ast_autoservice_start(qe->chan);
if (!res2) {
if (qe->parent->memberdelay) {
ast_log(LOG_NOTICE, "Delaying member connect for %d seconds\n", qe->parent->memberdelay);
res2 |= ast_safe_sleep(peer, qe->parent->memberdelay * 1000);
}
if (!res2 && announce) {
if (play_file(peer, announce))
ast_log(LOG_WARNING, "Announcement file '%s' is unavailable, continuing anyway...\n", announce);
}
if (!res2 && qe->parent->reportholdtime) {
if (!play_file(peer, qe->parent->sound_reporthold)) {
int holdtime;
time_t now;
time(&now);
holdtime = abs((now - qe->start) / 60);
if (holdtime < 2) {
play_file(peer, qe->parent->sound_lessthan);
ast_say_number(peer, 2, AST_DIGIT_ANY, peer->language, NULL);
} else
ast_say_number(peer, holdtime, AST_DIGIT_ANY, peer->language, NULL);
play_file(peer, qe->parent->sound_minutes);
}
}
}
res2 |= ast_autoservice_stop(qe->chan);
if (res2) {
/* Agent must have hung up */
ast_log(LOG_WARNING, "Agent on %s hungup on the customer. They're going to be pissed.\n", peer->name);
ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "AGENTDUMP", "%s", "");
/* Stop music on hold */
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, peer->name, "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);
ast_hangup(peer);
return -1;
}
/* Begin Monitoring */
if (qe->parent->monfmt && *qe->parent->monfmt) {
monitorfilename = pbx_builtin_getvar_helper( qe->chan, "MONITOR_FILENAME");
if(monitorfilename) {
ast_monitor_start( peer, qe->parent->monfmt, monitorfilename, 1 );
} else {
ast_monitor_start( peer, qe->parent->monfmt, qe->chan->cdr->uniqueid, 1 );
}
if(qe->parent->monjoin) {
ast_monitor_setjoinfiles( peer, 1);
}
/* Drop out of the queue at this point, to prepare for next caller */
leave_queue(qe);
if( url && !ast_strlen_zero(url) && ast_channel_supports_html(peer) ) {
if (option_debug)
ast_log(LOG_DEBUG, "app_queue: sendurl=%s.\n", url);
ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "CONNECT", "%ld", (long)time(NULL) - qe->start);
strncpy(oldcontext, qe->chan->context, sizeof(oldcontext) - 1);
strncpy(oldexten, qe->chan->exten, sizeof(oldexten) - 1);
time(&callstart);
memset(&config,0,sizeof(struct ast_bridge_config));
config.allowredirect_in = allowredir_in;
config.allowredirect_out = allowredir_out;
config.allowdisconnect_in = allowdisconnect_in;
config.allowdisconnect_out = allowdisconnect_out;
bridge = ast_bridge_call(qe->chan,peer,&config);
if (strcasecmp(oldcontext, qe->chan->context) || strcasecmp(oldexten, qe->chan->exten)) {
ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "TRANSFER", "%s|%s", qe->chan->exten, qe->chan->context);
} else if (qe->chan->_softhangup) {
ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "COMPLETECALLER", "%ld|%ld", (long)(callstart - qe->start), (long)(time(NULL) - callstart));
} else {
ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "COMPLETEAGENT", "%ld|%ld", (long)(callstart - qe->start), (long)(time(NULL) - callstart));
}
if(bridge != AST_PBX_NO_HANGUP_PEER)
ast_hangup(peer);
update_queue(qe->parent, member);
if( bridge == 0 ) res=1; /* JDG: bridge successfull, leave app_queue */
else res = bridge; /* bridge error, stay in the queue */
}
out:
hanguptree(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;
return ast_waitfordigit(qe->chan, retrywait);
}
static struct member * interface_exists( struct ast_call_queue * q, char * interface )
{
struct member * ret = NULL ;
struct member *mem;
char buf[500] ;
if( q != NULL )
{
mem = q->members ;
while( mem != NULL ) {
snprintf( buf, sizeof(buf), "%s/%s", mem->tech, mem->loc);
if( strcmp( buf, interface ) == 0 ) {
ret = mem ;
break ;
}
else
mem = mem->next ;
}
}
return( ret ) ;
}
static struct member * create_queue_node( char * interface, int penalty )
{
struct member * cur ;
char * tmp ;
/* Add a new member */
cur = malloc(sizeof(struct member));
if (cur) {
memset(cur, 0, sizeof(struct member));
strncpy(cur->tech, interface, sizeof(cur->tech) - 1);
if ((tmp = strchr(cur->tech, '/')))
*tmp = '\0';
if ((tmp = strchr(interface, '/'))) {
tmp++;
strncpy(cur->loc, tmp, sizeof(cur->loc) - 1);
} else
ast_log(LOG_WARNING, "No location at interface '%s'\n", interface);
cur->status = ast_device_state(interface);
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
/* Dump all members in a specific queue to the databse
*
* <pm_family>/<queuename> = <interface>;<penalty>;...
*
*/
static void dump_queue_members(struct ast_call_queue *pm_queue)
{
struct member *cur_member = NULL;
char value[PM_MAX_LEN];
int value_len = 0;
int res;
memset(value, 0, sizeof(value));
if (pm_queue) {
cur_member = pm_queue->members;
while (cur_member) {
if (cur_member->dynamic) {
value_len = strlen(value);
res = snprintf(value+value_len, sizeof(value)-value_len, "%s/%s;%d;", cur_member->tech, cur_member->loc, cur_member->penalty);
if (res != strlen(value + value_len)) {
ast_log(LOG_WARNING, "Could not create persistent member string, out of space\n");
break;
}
}
cur_member = cur_member->next;
}
if (!ast_strlen_zero(value) && !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);
}
}
}
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
static int remove_from_queue(char *queuename, char *interface)
{
struct ast_call_queue *q;
struct member *last_member, *look;
int res = RES_NOSUCHQUEUE;
ast_mutex_lock(&qlock);
for (q = queues ; q ; q = q->next) {
ast_mutex_lock(&q->lock);
if (!strcmp(q->name, queuename)) {
if ((last_member = interface_exists(q, interface))) {
if ((look = q->members) == last_member) {
q->members = last_member->next;
} else {
while (look != NULL) {
if (look->next == last_member) {
look->next = last_member->next;
break;
} else {
look = look->next;
}
}
}
manager_event(EVENT_FLAG_AGENT, "QueueMemberRemoved",
"Queue: %s\r\n"
"Location: %s/%s\r\n",
q->name, last_member->tech, last_member->loc);
free(last_member);
if (queue_persistent_members)
dump_queue_members(q);
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
res = RES_OKAY;
} else {
res = RES_EXISTS;
}
ast_mutex_unlock(&q->lock);
break;
}
ast_mutex_unlock(&q->lock);
}
ast_mutex_unlock(&qlock);
return res;
}
static int add_to_queue(char *queuename, char *interface, int penalty)
{
struct ast_call_queue *q;
struct member *new_member;
int res = RES_NOSUCHQUEUE;
ast_mutex_lock(&qlock);
for (q = queues ; q ; q = q->next) {
ast_mutex_lock(&q->lock);
if (!strcmp(q->name, queuename)) {
if (interface_exists(q, interface) == NULL) {
new_member = create_queue_node(interface, penalty);
if (new_member != NULL) {
new_member->dynamic = 1;
new_member->next = q->members;
q->members = new_member;
manager_event(EVENT_FLAG_AGENT, "QueueMemberAdded",
"Queue: %s\r\n"
"Location: %s/%s\r\n"
"Membership: %s\r\n"
"Penalty: %d\r\n"
"CallsTaken: %d\r\n"
"LastCall: %ld\r\n"
"Status: %d\r\n",
q->name, new_member->tech, new_member->loc, new_member->dynamic ? "dynamic" : "static",
new_member->penalty, new_member->calls, new_member->lastcall, new_member->status);
if (queue_persistent_members)
dump_queue_members(q);
res = RES_OKAY;
} else {
res = RES_OUTOFMEMORY;
}
} else {
res = RES_EXISTS;
}
ast_mutex_unlock(&q->lock);
break;
}
ast_mutex_unlock(&q->lock);
}
ast_mutex_unlock(&qlock);
return res;
}
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
/* Add members saved in the queue members DB file saves
* created by dump_queue_members(), back into the queues */
static void reload_queue_members(void)
{
char *cur_pm_ptr;
char *pm_queue_name;
char *pm_interface;
char *pm_penalty_tok;
int pm_penalty = 0;
struct ast_db_entry *pm_db_tree = NULL;
int pm_family_len = 0;
struct ast_call_queue *cur_queue = NULL;
char queue_data[PM_MAX_LEN];
pm_db_tree = ast_db_gettree(pm_family, NULL);
pm_family_len = strlen(pm_family);
ast_mutex_lock(&qlock);
/* Each key in 'pm_family' is the name of a specific queue in which
* we will reload members into. */
while (pm_db_tree) {
pm_queue_name = pm_db_tree->key+pm_family_len+2;
cur_queue = queues;
while (cur_queue) {
ast_mutex_lock(&cur_queue->lock);
if (strcmp(pm_queue_name, cur_queue->name) == 0)
break;
ast_mutex_unlock(&cur_queue->lock);
cur_queue = cur_queue->next;
}
if (!cur_queue) {
/* If the queue no longer exists, remove it from the
* database */
ast_db_del(pm_family, pm_queue_name);
pm_db_tree = pm_db_tree->next;
continue;
} else
ast_mutex_unlock(&cur_queue->lock);
if (!ast_db_get(pm_family, pm_queue_name, queue_data, PM_MAX_LEN)) {
/* Parse each <interface>;<penalty>; from the value of the
* queuename key and add it to the respective queue */
cur_pm_ptr = queue_data;
while ((pm_interface = strsep(&cur_pm_ptr, ";"))) {
if (!(pm_penalty_tok = strsep(&cur_pm_ptr, ";"))) {
ast_log(LOG_WARNING, "Error parsing corrupted Queue DB string for '%s'\n", pm_queue_name);
break;
}
pm_penalty = strtol(pm_penalty_tok, NULL, 10);
if (errno == ERANGE) {
ast_log(LOG_WARNING, "Error converting penalty: %s: Out of range.\n", pm_penalty_tok);
break;
}
if (option_debug)
ast_log(LOG_DEBUG, "Reload Members: Queue: %s Member: %s Penalty: %d\n", pm_queue_name, pm_interface, pm_penalty);
if (add_to_queue(pm_queue_name, pm_interface, pm_penalty) == RES_OUTOFMEMORY) {
ast_log(LOG_ERROR, "Out of Memory\n");
break;
}
}
}
pm_db_tree = pm_db_tree->next;
}
ast_log(LOG_NOTICE, "Queue members sucessfully reloaded from database.\n");
ast_mutex_unlock(&qlock);
if (pm_db_tree) {
ast_db_freetree(pm_db_tree);
pm_db_tree = NULL;
}
}
static int rqm_exec(struct ast_channel *chan, void *data)
{
int res=-1;
struct localuser *u;
char *info, *queuename;
char *interface = NULL;
ast_log(LOG_WARNING, "RemoveQueueMember requires an argument (queuename[|interface])\n");
info = ast_strdupa((char *)data);
if (!info) {
ast_log(LOG_ERROR, "Out of memory\n");
return -1;
}
LOCAL_USER_ADD(u);
queuename = info;
if (queuename) {
interface = strchr(queuename, '|');
if (interface) {
*interface = '\0';
interface++;
}
else {
strncpy(tmpchan, chan->name, sizeof(tmpchan) - 1);
interface = strrchr(tmpchan, '-');
if (interface)
*interface = '\0';
interface = tmpchan;
}
switch (remove_from_queue(queuename, interface)) {
case RES_OKAY:
ast_log(LOG_NOTICE, "Removed interface '%s' from queue '%s'\n", interface, queuename);
res = 0;
break;
case RES_EXISTS:
ast_log(LOG_WARNING, "Unable to remove interface '%s' from queue '%s': Not there\n", interface, queuename);
if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 101, chan->cid.cid_num)) {
chan->priority += 100;
res = 0;
break;
case RES_NOSUCHQUEUE:
ast_log(LOG_WARNING, "Unable to remove interface from queue '%s': No such queue\n", queuename);
res = 0;
break;
case RES_OUTOFMEMORY:
ast_log(LOG_ERROR, "Out of memory\n");
break;
}
LOCAL_USER_REMOVE(u);
return res;
}
static int aqm_exec(struct ast_channel *chan, void *data)
{
int res=-1;
struct localuser *u;
char *queuename;
char *info;
char *penaltys=NULL;
int penalty = 0;
ast_log(LOG_WARNING, "AddQueueMember requires an argument (queuename[|[interface][|penalty]])\n");
info = ast_strdupa((char *)data);
if (!info) {
ast_log(LOG_ERROR, "Out of memory\n");
return -1;
}
LOCAL_USER_ADD(u);
queuename = info;
if (queuename) {
interface = strchr(queuename, '|');
if (interface) {
*interface = '\0';
interface++;
}
if (interface) {
penaltys = strchr(interface, '|');
if (penaltys) {
*penaltys = '\0';
if (!interface || ast_strlen_zero(interface)) {
strncpy(tmpchan, chan->name, sizeof(tmpchan) - 1);
interface = strrchr(tmpchan, '-');
if (interface)
*interface = '\0';
interface = tmpchan;
}
if (penaltys && strlen(penaltys)) {
if ((sscanf(penaltys, "%d", &penalty) != 1) || penalty < 0) {
ast_log(LOG_WARNING, "Penalty '%s' is invalid, must be an integer >= 0\n", penaltys);
penalty = 0;
}
}
switch (add_to_queue(queuename, interface, penalty)) {
case RES_OKAY:
ast_log(LOG_NOTICE, "Added interface '%s' to queue '%s'\n", interface, queuename);
res = 0;
break;
case RES_EXISTS:
ast_log(LOG_WARNING, "Unable to add interface '%s' to queue '%s': Already there\n", interface, queuename);
if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 101, chan->cid.cid_num)) {
chan->priority += 100;
res = 0;
break;
case RES_NOSUCHQUEUE:
ast_log(LOG_WARNING, "Unable to add interface to queue '%s': No such queue\n", queuename);
res = 0;
break;
case RES_OUTOFMEMORY:
ast_log(LOG_ERROR, "Out of memory\n");
break;
}
LOCAL_USER_REMOVE(u);
return res;
}
static int queue_exec(struct ast_channel *chan, void *data)
{
int res=-1;
struct localuser *u;
char *queuename;
char info[512];
char *options = NULL;
char *url = NULL;
char *announceoverride = NULL;
char *user_priority;
int prio;
/* whether to exit Queue application after the timeout hits */
int go_on = 0;
/* Our queue entry */
struct queue_ent qe;
if (!data) {
ast_log(LOG_WARNING, "Queue requires an argument (queuename[|[timeout][|URL]])\n");
/* Setup our queue entry */
memset(&qe, 0, sizeof(qe));
/* Parse our arguments XXX Check for failure XXX */
strncpy(info, (char *)data, strlen((char *)data) + AST_MAX_EXTENSION-1);
queuename = info;
if (queuename) {
options = strchr(queuename, '|');
if (options) {
*options = '\0';
options++;
url = strchr(options, '|');
if (url) {
*url = '\0';
url++;
announceoverride = strchr(url, '|');
if (announceoverride) {
*announceoverride = '\0';
announceoverride++;
queuetimeoutstr = strchr(announceoverride, '|');
if (queuetimeoutstr) {
*queuetimeoutstr = '\0';
queuetimeoutstr++;
qe.queuetimeout = atoi(queuetimeoutstr);
} else {
qe.queuetimeout = 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) {
if (option_debug)
ast_log(LOG_DEBUG, "%s: Got priority %d from ${QUEUE_PRIO}.\n",
chan->name, prio);
} else {
ast_log(LOG_WARNING, "${QUEUE_PRIO}: Invalid value (%s), channel %s.\n",
user_priority, chan->name);
prio = 0;
}
} else {
if (option_debug)
ast_log(LOG_DEBUG, "NO QUEUE_PRIO variable found. Using default.\n");
prio = 0;
if (options) {
if (strchr(options, 'r')) {
ringing = 1;
ast_log(LOG_DEBUG, "queue: %s, options: %s, url: %s, announce: %s, timeout: %d, priority: %d\n",
queuename, options, url, announceoverride, qe.queuetimeout, (int)prio);