Index: apps/app_queue.c =================================================================== RCS file: /usr/cvsroot/asterisk/apps/app_queue.c,v retrieving revision 1.146 diff -u -r1.146 app_queue.c --- apps/app_queue.c 8 Jul 2005 21:14:34 -0000 1.146 +++ apps/app_queue.c 12 Jul 2005 21:37:25 -0000 @@ -234,6 +234,7 @@ char moh[80]; /* Name of musiconhold to be used */ char announce[80]; /* Announcement to play for member when call is answered */ char context[80]; /* Context when user exits queue */ + char digits[80]; /* Digits entered while in queue */ int pos; /* Where we are in the queue */ int prio; /* Our priority */ int last_pos_said; /* Last position we told the user */ @@ -977,15 +978,31 @@ static int valid_exit(struct queue_ent *qe, char digit) { - char tmp[2]; + int digitlen = strlen(qe->digits); + /* Prevent possible buffer overflow */ + if (digitlen < sizeof(qe->digits) - 2) { + qe->digits[digitlen] = digit; + qe->digits[digitlen + 1] = '\0'; + } else { + qe->digits[0] = '\0'; + return 0; + } + + /* If there's no context to goto, short-circuit */ if (ast_strlen_zero(qe->context)) return 0; - tmp[0] = digit; - tmp[1] = '\0'; - if (ast_exists_extension(qe->chan, qe->context, tmp, 1, qe->chan->cid.cid_num)) { + + /* If the extension is bad, then reset the digits to blank */ + if (!ast_canmatch_extension(qe->chan, qe->context, qe->digits, 1, qe->chan->cid.cid_num)) { + qe->digits[0] = '\0'; + return 0; + } + + /* We have an exact match */ + if (ast_exists_extension(qe->chan, qe->context, qe->digits, 1, qe->chan->cid.cid_num)) { ast_copy_string(qe->chan->context, qe->context, sizeof(qe->chan->context)); - ast_copy_string(qe->chan->exten, tmp, sizeof(qe->chan->exten)); + ast_copy_string(qe->chan->exten, qe->digits, sizeof(qe->chan->exten)); qe->chan->priority = 0; return 1; } @@ -1979,11 +1996,7 @@ record_abandoned(qe); res = -1; } else { - if (digit && valid_exit(qe, digit)) - res=digit; - else - /* Nobody answered, next please? */ - res=0; + res = digit; } if (option_debug) ast_log(LOG_DEBUG, "%s: Nobody answered.\n", qe->chan->name); @@ -2762,7 +2775,7 @@ if (!res) break; if (valid_exit(&qe, res)) { - ast_queue_log(queuename, chan->uniqueid, "NONE", "EXITWITHKEY", "%c|%d", res, qe.pos); + ast_queue_log(queuename, chan->uniqueid, "NONE", "EXITWITHKEY", "%s|%d", qe.digits, qe.pos); break; } } @@ -2789,7 +2802,7 @@ if (qe.parent->announcefrequency && !ringing) res = say_position(&qe); if (res && valid_exit(&qe, res)) { - ast_queue_log(queuename, chan->uniqueid, "NONE", "EXITWITHKEY", "%c|%d", res, qe.pos); + ast_queue_log(queuename, chan->uniqueid, "NONE", "EXITWITHKEY", "%s|%d", qe.digits, qe.pos); break; } @@ -2804,7 +2817,7 @@ record_abandoned(&qe); ast_queue_log(queuename, chan->uniqueid, "NONE", "ABANDON", "%d|%d|%ld", qe.pos, qe.opos, (long)time(NULL) - qe.start); } else if (res > 0) - ast_queue_log(queuename, chan->uniqueid, "NONE", "EXITWITHKEY", "%c|%d", res, qe.pos); + ast_queue_log(queuename, chan->uniqueid, "NONE", "EXITWITHKEY", "%s|%d", qe.digits, qe.pos); break; } @@ -2846,7 +2859,7 @@ break; } if (res && valid_exit(&qe, res)) { - ast_queue_log(queuename, chan->uniqueid, "NONE", "EXITWITHKEY", "%c|%d", res, qe.pos); + ast_queue_log(queuename, chan->uniqueid, "NONE", "EXITWITHKEY", "%s|%d", qe.digits, qe.pos); break; } /* exit after 'timeout' cycle if 'n' option enabled */ @@ -2895,6 +2908,54 @@ return res; } +static char *queue_function_qac(struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len) +{ + int count = 0; + struct ast_call_queue *q; + struct localuser *u; + struct member *m; + + if (!data || ast_strlen_zero(data)) { + ast_log(LOG_ERROR, "QUEUEAGENTCOUNT requires an argument: queuename\n"); + return "0"; + } + + LOCAL_USER_ACF_ADD(u); + + ast_mutex_lock(&qlock); + + /* Find the right queue */ + for (q = queues; q; q = q->next) { + if (!strcasecmp(q->name, data)) { + ast_mutex_lock(&q->lock); + break; + } + } + + ast_mutex_unlock(&qlock); + + if (q) { + for (m = q->members; m; m = m->next) { + /* Count the agents who are logged in and presently answering calls */ + if ((m->status != AST_DEVICE_UNAVAILABLE) && (m->status != AST_DEVICE_INVALID)) { + count++; + } + } + ast_mutex_unlock(&q->lock); + } + + snprintf(buf, len, "%d", count); + LOCAL_USER_REMOVE(u); + return buf; +} + +static struct ast_custom_function queueagentcount_function = { + .name = "QUEUEAGENTCOUNT", + .synopsis = "Count number of agents answering a queue", + .syntax = "QUEUEAGENTCOUNT()", + .read = queue_function_qac, +}; + static void reload_queues(void) { struct ast_call_queue *q, *ql, *qn; @@ -3557,6 +3618,7 @@ ast_unregister_application(app_rqm); ast_unregister_application(app_pqm); ast_unregister_application(app_upqm); + ast_custom_function_unregister(&queueagentcount_function); return ast_unregister_application(app); } @@ -3579,6 +3641,7 @@ ast_register_application(app_rqm, rqm_exec, app_rqm_synopsis, app_rqm_descrip) ; ast_register_application(app_pqm, pqm_exec, app_pqm_synopsis, app_pqm_descrip) ; ast_register_application(app_upqm, upqm_exec, app_upqm_synopsis, app_upqm_descrip) ; + ast_custom_function_register(&queueagentcount_function); } reload_queues(); Index: include/asterisk/module.h =================================================================== RCS file: /usr/cvsroot/asterisk/include/asterisk/module.h,v retrieving revision 1.19 diff -u -r1.19 module.h --- include/asterisk/module.h 24 Jun 2005 02:15:04 -0000 1.19 +++ include/asterisk/module.h 12 Jul 2005 21:37:25 -0000 @@ -174,6 +174,21 @@ ast_update_use_count(); \ } +#define LOCAL_USER_ACF_ADD(u) { \ + \ + if (!(u=(struct localuser *)malloc(sizeof(struct localuser)))) { \ + ast_log(LOG_WARNING, "Out of memory\n"); \ + return ""; \ + } \ + ast_mutex_lock(&localuser_lock); \ + u->chan = chan; \ + u->next = localusers; \ + localusers = u; \ + localusecnt++; \ + ast_mutex_unlock(&localuser_lock); \ + ast_update_use_count(); \ +} + #define LOCAL_USER_REMOVE(u) { \ struct localuser *uc, *ul = NULL; \ ast_mutex_lock(&localuser_lock); \