aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorkpfleming <kpfleming@f38db490-d61c-443f-a65b-d21fe96a405b>2005-07-12 22:28:51 +0000
committerkpfleming <kpfleming@f38db490-d61c-443f-a65b-d21fe96a405b>2005-07-12 22:28:51 +0000
commit7b08b9a445588227e3ee819a66834bb3c89eab88 (patch)
tree83512413becc47a21b94b80cb38918d7ba83836e
parent20933df5384da8f82a38bd52502452220f3834d2 (diff)
add support for multiple-digit extensions in queue exit contexts (bug #4690)
add QUEUEAGENTCOUNT dialplan function (bug #4690) git-svn-id: http://svn.digium.com/svn/asterisk/trunk@6114 f38db490-d61c-443f-a65b-d21fe96a405b
-rwxr-xr-xUPGRADE.txt6
-rwxr-xr-xapps/app_queue.c91
-rwxr-xr-xinclude/asterisk/module.h15
3 files changed, 98 insertions, 14 deletions
diff --git a/UPGRADE.txt b/UPGRADE.txt
index f613c39a4..835b987b0 100755
--- a/UPGRADE.txt
+++ b/UPGRADE.txt
@@ -106,6 +106,12 @@ Queues:
restore the original behavior, use "leavewhenempty=strict" or
"joinwhenempty=strict" instead of "=yes" for those options.
+* It is now possible to use multi-digit extensions in the exit context
+ for a queue (although you should not have overlapping extensions,
+ as there is no digit timeout). This means that the EXITWITHKEY event
+ in queue_log can now contain a key field with more than a single
+ character in it.
+
Extensions:
* By default, there is a new option called "autofallthrough" in
diff --git a/apps/app_queue.c b/apps/app_queue.c
index 2d992735f..c0dea9426 100755
--- a/apps/app_queue.c
+++ b/apps/app_queue.c
@@ -234,6 +234,7 @@ struct queue_ent {
char moh[80]; /* Name of musiconhold to be used */
char announce[80]; /* Announcement to play for member when call is answered */
char context[AST_MAX_CONTEXT]; /* Context when user exits queue */
+ char digits[AST_MAX_EXTENSION]; /* 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 play_file(struct ast_channel *chan, char *filename)
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 @@ static int try_calling(struct queue_ent *qe, const char *options, char *announce
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 @@ check_turns:
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 @@ check_turns:
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 @@ check_turns:
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 @@ check_turns:
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 @@ check_turns:
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(<queuename>)",
+ .read = queue_function_qac,
+};
+
static void reload_queues(void)
{
struct ast_call_queue *q, *ql, *qn;
@@ -3557,6 +3618,7 @@ int unload_module(void)
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 @@ int load_module(void)
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();
diff --git a/include/asterisk/module.h b/include/asterisk/module.h
index b6a17982c..19e31ee9d 100755
--- a/include/asterisk/module.h
+++ b/include/asterisk/module.h
@@ -174,6 +174,21 @@ void ast_unregister_atexit(void (*func)(void));
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); \