From 30973879c1dd49e16d73390a9bc045188f5763ef Mon Sep 17 00:00:00 2001 From: "Kevin P. Fleming" Date: Thu, 2 Jun 2005 21:42:49 +0000 Subject: add realtime support to app_queue for static members/agents (bug #4037) git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@5821 65c4cc65-6c06-0410-ace0-fbb531ad65f3 --- apps/app_queue.c | 673 ++++++++++++++++++++++++++++-------------- configs/extconfig.conf.sample | 2 + 2 files changed, 454 insertions(+), 221 deletions(-) diff --git a/apps/app_queue.c b/apps/app_queue.c index 11bd229dc..9add78a4d 100755 --- a/apps/app_queue.c +++ b/apps/app_queue.c @@ -250,6 +250,7 @@ struct member { int status; /* Status of queue member */ int paused; /* Are we paused (not accepting calls)? */ time_t lastcall; /* When last successful call was hungup */ + int dead; /* Used to detect members deleted in realtime */ struct member *next; /* Next member */ }; @@ -276,6 +277,7 @@ struct ast_call_queue { unsigned int announceholdtime:2; unsigned int strategy:3; unsigned int maskmemberstatus:1; + unsigned int realtime:1; int announcefrequency; /* How often to announce their position */ int roundingseconds; /* How many seconds do we round to? */ int holdtime; /* Current avg holdtime, based on recursive boxcar filter */ @@ -336,7 +338,7 @@ static char *int2strat(int strategy) return ""; } -static int strat2int(char *strategy) +static int strat2int(const char *strategy) { int x; for (x=0;xpenalty = penalty; + cur->paused = paused; + ast_copy_string(cur->interface, interface, sizeof(cur->interface)); + if (!strchr(cur->interface, '/')) + ast_log(LOG_WARNING, "No location at interface '%s'\n", interface); + cur->status = ast_device_state(interface); + } + + return cur; +} + +static struct ast_call_queue *alloc_queue(const char *queuename) +{ + struct ast_call_queue *q; + + q = malloc(sizeof(*q)); + if (q) { + memset(q, 0, sizeof(*q)); + ast_mutex_init(&q->lock); + ast_copy_string(q->name, queuename, sizeof(q->name)); + } + return q; +} + +static void init_queue(struct ast_call_queue *q) +{ + q->dead = 0; + q->retry = DEFAULT_RETRY; + q->timeout = -1; + q->maxlen = 0; + q->announcefrequency = 0; + q->announceholdtime = 0; + q->roundingseconds = 0; /* Default - don't announce seconds */ + q->servicelevel = 0; + q->moh[0] = '\0'; + q->announce[0] = '\0'; + q->context[0] = '\0'; + q->monfmt[0] = '\0'; + ast_copy_string(q->sound_next, "queue-youarenext", sizeof(q->sound_next)); + ast_copy_string(q->sound_thereare, "queue-thereare", sizeof(q->sound_thereare)); + ast_copy_string(q->sound_calls, "queue-callswaiting", sizeof(q->sound_calls)); + ast_copy_string(q->sound_holdtime, "queue-holdtime", sizeof(q->sound_holdtime)); + ast_copy_string(q->sound_minutes, "queue-minutes", sizeof(q->sound_minutes)); + ast_copy_string(q->sound_seconds, "queue-seconds", sizeof(q->sound_seconds)); + ast_copy_string(q->sound_thanks, "queue-thankyou", sizeof(q->sound_thanks)); + ast_copy_string(q->sound_lessthan, "queue-less-than", sizeof(q->sound_lessthan)); + ast_copy_string(q->sound_reporthold, "queue-reporthold", sizeof(q->sound_reporthold)); +} + +static void clear_queue(struct ast_call_queue *q) +{ + q->holdtime = 0; + q->callscompleted = 0; + q->callsabandoned = 0; + q->callscompletedinsl = 0; + q->wrapuptime = 0; +} + +/* Configure a queue parameter. + For error reporting, line number is passed for .conf static configuration. + For Realtime queues, linenum is -1. + The failunknown flag is set for config files (and static realtime) to show + errors for unknown parameters. It is cleared for dynamic realtime to allow + extra fields in the tables. */ +static void queue_set_param(struct ast_call_queue *q, const char *param, const char *val, int linenum, int failunknown) +{ + if (!strcasecmp(param, "music") || !strcasecmp(param, "musiconhold")) { + ast_copy_string(q->moh, val, sizeof(q->moh)); + } else if (!strcasecmp(param, "announce")) { + ast_copy_string(q->announce, val, sizeof(q->announce)); + } else if (!strcasecmp(param, "context")) { + ast_copy_string(q->context, val, sizeof(q->context)); + } else if (!strcasecmp(param, "timeout")) { + q->timeout = atoi(val); + if (q->timeout < 0) + q->timeout = DEFAULT_TIMEOUT; + } else if (!strcasecmp(param, "monitor-join")) { + q->monjoin = ast_true(val); + } else if (!strcasecmp(param, "monitor-format")) { + ast_copy_string(q->monfmt, val, sizeof(q->monfmt)); + } else if (!strcasecmp(param, "queue-youarenext")) { + ast_copy_string(q->sound_next, val, sizeof(q->sound_next)); + } else if (!strcasecmp(param, "queue-thereare")) { + ast_copy_string(q->sound_thereare, val, sizeof(q->sound_thereare)); + } else if (!strcasecmp(param, "queue-callswaiting")) { + ast_copy_string(q->sound_calls, val, sizeof(q->sound_calls)); + } else if (!strcasecmp(param, "queue-holdtime")) { + ast_copy_string(q->sound_holdtime, val, sizeof(q->sound_holdtime)); + } else if (!strcasecmp(param, "queue-minutes")) { + ast_copy_string(q->sound_minutes, val, sizeof(q->sound_minutes)); + } else if (!strcasecmp(param, "queue-seconds")) { + ast_copy_string(q->sound_seconds, val, sizeof(q->sound_seconds)); + } else if (!strcasecmp(param, "queue-lessthan")) { + ast_copy_string(q->sound_lessthan, val, sizeof(q->sound_lessthan)); + } else if (!strcasecmp(param, "queue-thankyou")) { + ast_copy_string(q->sound_thanks, val, sizeof(q->sound_thanks)); + } else if (!strcasecmp(param, "queue-reporthold")) { + ast_copy_string(q->sound_reporthold, val, sizeof(q->sound_reporthold)); + } else if (!strcasecmp(param, "announce-frequency")) { + q->announcefrequency = atoi(val); + } else if (!strcasecmp(param, "announce-round-seconds")) { + q->roundingseconds = atoi(val); + if (q->roundingseconds>60 || q->roundingseconds<0) { + if (linenum >= 0) { + ast_log(LOG_WARNING, "'%s' isn't a valid value for %s " + "using 0 instead for queue '%s' at line %d of queues.conf\n", + val, param, q->name, linenum); + } else { + ast_log(LOG_WARNING, "'%s' isn't a valid value for %s " + "using 0 instead for queue '%s'\n", val, param, q->name); + } + q->roundingseconds=0; + } + } else if (!strcasecmp(param, "announce-holdtime")) { + if (!strcasecmp(val, "once")) + q->announceholdtime = ANNOUNCEHOLDTIME_ONCE; + else if (ast_true(val)) + q->announceholdtime = ANNOUNCEHOLDTIME_ALWAYS; + else + q->announceholdtime = 0; + } else if (!strcasecmp(param, "retry")) { + q->retry = atoi(val); + if (q->retry < 0) + q->retry = DEFAULT_RETRY; + } else if (!strcasecmp(param, "wrapuptime")) { + q->wrapuptime = atoi(val); + } else if (!strcasecmp(param, "maxlen")) { + q->maxlen = atoi(val); + if (q->maxlen < 0) + q->maxlen = 0; + } else if (!strcasecmp(param, "servicelevel")) { + q->servicelevel= atoi(val); + } else if (!strcasecmp(param, "strategy")) { + q->strategy = strat2int(val); + if (q->strategy < 0) { + ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n", + val, q->name); + q->strategy = 0; + } + } else if (!strcasecmp(param, "joinempty")) { + if (!strcasecmp(val, "strict")) + q->joinempty = QUEUE_EMPTY_STRICT; + else if (ast_true(val)) + q->joinempty = QUEUE_EMPTY_NORMAL; + else + q->joinempty = 0; + } else if (!strcasecmp(param, "leavewhenempty")) { + if (!strcasecmp(val, "strict")) + q->leavewhenempty = QUEUE_EMPTY_STRICT; + else if (ast_true(val)) + q->leavewhenempty = QUEUE_EMPTY_NORMAL; + else + q->leavewhenempty = 0; + } else if (!strcasecmp(param, "eventmemberstatus")) { + q->maskmemberstatus = !ast_true(val); + } else if (!strcasecmp(param, "eventwhencalled")) { + q->eventwhencalled = ast_true(val); + } else if (!strcasecmp(param, "reportholdtime")) { + q->reportholdtime = ast_true(val); + } else if (!strcasecmp(param, "memberdelay")) { + q->memberdelay = atoi(val); + } else if (!strcasecmp(param, "weight")) { + q->weight = atoi(val); + if (q->weight) + use_weight++; + /* With Realtime queues, if the last queue using weights is deleted in realtime, + we will not see any effect on use_weight until next reload. */ + } else if (!strcasecmp(param, "timeoutrestart")) { + q->timeoutrestart = ast_true(val); + } else if(failunknown) { + if (linenum >= 0) { + ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s at line %d of queues.conf\n", + q->name, param, linenum); + } else { + ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s\n", q->name, param); + } + } +} + +static void rt_handle_member_record(struct ast_call_queue *q, char *interface, const char *penalty_str) +{ + struct member *m, *prev_m; + int penalty = 0; + + if(penalty_str) { + penalty = atoi(penalty_str); + if(penalty < 0) + penalty = 0; + } + + /* Find the member, or the place to put a new one. */ + prev_m = NULL; + m = q->members; + while (m && strcmp(m->interface, interface)) { + prev_m = m; + m = m->next; + } + + /* Create a new one if not found, else update penalty */ + if (!m) { + m = create_queue_member(interface, penalty, 0); + if (m) { + m->dead = 0; + if (prev_m) { + prev_m->next = m; + } else { + q->members = m; + } + } + } else { + m->dead = 0; /* Do not delete this one. */ + m->penalty = penalty; + } +} + + +/* Reload a single queue via realtime. Return the queue, or NULL if it doesn't exist. + Should be called with the global qlock locked. + When found, the queue is returned with q->lock locked. */ +static struct ast_call_queue *reload_queue_rt(const char *queuename, struct ast_variable *queue_vars, struct ast_config *member_config) +{ + struct ast_variable *v; + struct ast_call_queue *q, *prev_q; + struct member *m, *prev_m, *next_m; + char *interface; + char *tmp, *tmp_name; + char tmpbuf[64]; /* Must be longer than the longest queue param name. */ + + /* Find the queue in the in-core list (we will create a new one if not found). */ + q = queues; + prev_q = NULL; + while (q) { + if (!strcasecmp(q->name, queuename)) { + break; + } + q = q->next; + prev_q = q; + } + + /* Static queues override realtime. */ + if (q) { + ast_mutex_lock(&q->lock); + if (!q->realtime) { + if (q->dead) { + ast_mutex_unlock(&q->lock); + return NULL; + } else { + return q; + } + } + } + + /* Check if queue is defined in realtime. */ + if (!queue_vars) { + /* Delete queue from in-core list if it has been deleted in realtime. */ + if (q) { + /* Hmm, can't seem to distinguish a DB failure from a not + found condition... So we might delete an in-core queue + in case of DB failure. */ + ast_log(LOG_DEBUG, "Queue %s not found in realtime.\n", queuename); + + q->dead = 1; + /* Delete if unused (else will be deleted when last caller leaves). */ + if (!q->count) { + /* Delete. */ + if (!prev_q) { + queues = q->next; + } else { + prev_q->next = q->next; + } + ast_mutex_unlock(&q->lock); + free(q); + } else + ast_mutex_unlock(&q->lock); + } + return NULL; + } + + /* Create a new queue if an in-core entry does not exist yet. */ + if (!q) { + q = alloc_queue(queuename); + if (!q) + return NULL; + ast_mutex_lock(&q->lock); + clear_queue(q); + q->realtime = 1; + q->next = queues; + queues = q; + } + init_queue(q); /* Ensure defaults for all parameters not set explicitly. */ + + v = queue_vars; + memset(tmpbuf, 0, sizeof(tmpbuf)); + while(v) { + /* Convert to dashes `-' from underscores `_' as the latter are more SQL friendly. */ + if((tmp = strchr(v->name, '_')) != NULL) { + ast_copy_string(tmpbuf, v->name, sizeof(tmpbuf)); + tmp_name = tmpbuf; + tmp = tmp_name; + while((tmp = strchr(tmp, '_')) != NULL) + *tmp++ = '-'; + } else + tmp_name = v->name; + queue_set_param(q, tmp_name, v->value, -1, 0); + v = v->next; + } + + /* Temporarily set members dead so we can detect deleted ones. */ + m = q->members; + while (m) { + m->dead = 1; + m = m->next; + } + + interface = ast_category_browse(member_config, NULL); + while (interface) { + rt_handle_member_record(q, interface, ast_variable_retrieve(member_config, interface, "penalty")); + interface = ast_category_browse(member_config, interface); + } + + /* Delete all realtime members that have been deleted in DB. */ + m = q->members; + prev_m = NULL; + while (m) { + next_m = m->next; + if (m->dead) { + if (prev_m) { + prev_m->next = next_m; + } else { + q->members = next_m; + } + free(m); + } else { + prev_m = m; + } + m = next_m; + } + + return q; +} + static int join_queue(char *queuename, struct queue_ent *qe, enum queue_result *reason) { + struct ast_variable *queue_vars = NULL; + struct ast_config *member_config = NULL; struct ast_call_queue *q; struct queue_ent *cur, *prev = NULL; int res = -1; int pos = 0; int inserted = 0; + enum queue_member_status stat; + + /* Load from realtime before taking the global qlock, to avoid blocking all + queue operations while waiting for the DB. + + This will be two separate database transactions, so we might + see queue parameters as they were before another process + changed the queue and member list as it was after the change. + Thus we might see an empty member list when a queue is + deleted. In practise, this is unlikely to cause a problem. */ + queue_vars = ast_load_realtime("queues", "name", queuename, NULL); + if(queue_vars) + member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name", queuename, NULL); ast_mutex_lock(&qlock); - for (q = queues; q; q = q->next) { - if (!strcasecmp(q->name, queuename)) { - enum queue_member_status stat; - /* This is our one */ - ast_mutex_lock(&q->lock); - stat = get_member_status(q); - if (!q->joinempty && (stat == QUEUE_NO_MEMBERS)) - *reason = QUEUE_JOINEMPTY; - else if ((q->joinempty == QUEUE_EMPTY_STRICT) && (stat == QUEUE_NO_REACHABLE_MEMBERS)) - *reason = QUEUE_JOINUNAVAIL; - else if (q->maxlen && (q->count >= q->maxlen)) - *reason = QUEUE_FULL; - else { - /* There's space for us, put us at the right position inside - * the queue. - * Take into account the priority of the calling user */ - inserted = 0; - prev = NULL; - cur = q->head; - while(cur) { - /* We have higher priority than the current user, enter - * before him, after all the other users with priority - * higher or equal to our priority. */ - if ((!inserted) && (qe->prio > cur->prio)) { - insert_entry(q, prev, qe, &pos); - inserted = 1; - } - cur->pos = ++pos; - prev = cur; - cur = cur->next; - } - /* No luck, join at the end of the queue */ - if (!inserted) - insert_entry(q, prev, qe, &pos); - ast_copy_string(qe->moh, q->moh, sizeof(qe->moh)); - ast_copy_string(qe->announce, q->announce, sizeof(qe->announce)); - ast_copy_string(qe->context, q->context, sizeof(qe->context)); - q->count++; - res = 0; - manager_event(EVENT_FLAG_CALL, "Join", - "Channel: %s\r\nCallerID: %s\r\nCallerIDName: %s\r\nQueue: %s\r\nPosition: %d\r\nCount: %d\r\n", - qe->chan->name, - qe->chan->cid.cid_num ? qe->chan->cid.cid_num : "unknown", - qe->chan->cid.cid_name ? qe->chan->cid.cid_name : "unknown", - q->name, qe->pos, q->count ); + q = reload_queue_rt(queuename, queue_vars, member_config); + /* Note: If found, reload_queue_rt() returns with q->lock locked. */ + if(member_config) + ast_config_destroy(member_config); + if(queue_vars) + ast_variables_destroy(queue_vars); + + if (!q) { + ast_mutex_unlock(&qlock); + return res; + } + + /* This is our one */ + stat = get_member_status(q); + if (!q->joinempty && (stat == QUEUE_NO_MEMBERS)) + *reason = QUEUE_JOINEMPTY; + else if ((q->joinempty == QUEUE_EMPTY_STRICT) && (stat == QUEUE_NO_REACHABLE_MEMBERS)) + *reason = QUEUE_JOINUNAVAIL; + else if (q->maxlen && (q->count >= q->maxlen)) + *reason = QUEUE_FULL; + else { + /* There's space for us, put us at the right position inside + * the queue. + * Take into account the priority of the calling user */ + inserted = 0; + prev = NULL; + cur = q->head; + while(cur) { + /* We have higher priority than the current user, enter + * before him, after all the other users with priority + * higher or equal to our priority. */ + if ((!inserted) && (qe->prio > cur->prio)) { + insert_entry(q, prev, qe, &pos); + inserted = 1; + } + cur->pos = ++pos; + prev = cur; + cur = cur->next; + } + /* No luck, join at the end of the queue */ + if (!inserted) + insert_entry(q, prev, qe, &pos); + ast_copy_string(qe->moh, q->moh, sizeof(qe->moh)); + ast_copy_string(qe->announce, q->announce, sizeof(qe->announce)); + ast_copy_string(qe->context, q->context, sizeof(qe->context)); + q->count++; + res = 0; + manager_event(EVENT_FLAG_CALL, "Join", + "Channel: %s\r\nCallerID: %s\r\nCallerIDName: %s\r\nQueue: %s\r\nPosition: %d\r\nCount: %d\r\n", + qe->chan->name, + qe->chan->cid.cid_num ? qe->chan->cid.cid_num : "unknown", + qe->chan->cid.cid_name ? qe->chan->cid.cid_name : "unknown", + q->name, qe->pos, q->count ); #if 0 ast_log(LOG_NOTICE, "Queue '%s' Join, Channel '%s', Position '%d'\n", q->name, qe->chan->name, qe->pos ); #endif - } - ast_mutex_unlock(&q->lock); - break; - } } + ast_mutex_unlock(&q->lock); ast_mutex_unlock(&qlock); return res; } @@ -1793,27 +2166,6 @@ static struct member * interface_exists(struct ast_call_queue *q, char *interfac } -static struct member *create_queue_node(char *interface, int penalty, int paused) -{ - struct member *cur; - - /* Add a new member */ - - cur = malloc(sizeof(struct member)); - - if (cur) { - memset(cur, 0, sizeof(struct member)); - cur->penalty = penalty; - cur->paused = paused; - ast_copy_string(cur->interface, interface, sizeof(cur->interface)); - if (!strchr(cur->interface, '/')) - ast_log(LOG_WARNING, "No location at interface '%s'\n", interface); - cur->status = ast_device_state(interface); - } - - return cur; -} - /* Dump all members in a specific queue to the databse * * / = ;;[|...] @@ -1909,7 +2261,7 @@ static int add_to_queue(char *queuename, char *interface, int penalty, int pause ast_mutex_lock(&q->lock); if (!strcmp(q->name, queuename)) { if (interface_exists(q, interface) == NULL) { - new_member = create_queue_node(interface, penalty, paused); + new_member = create_queue_member(interface, penalty, paused); if (new_member != NULL) { new_member->dynamic = 1; @@ -2540,12 +2892,15 @@ static void reload_queues(void) struct member *prev, *cur; int new; char *general_val = NULL; + char interface[80]; + int penalty; cfg = ast_config_load("queues.conf"); if (!cfg) { ast_log(LOG_NOTICE, "No call queueing config file (queues.conf), so no call queues\n"); return; } + memset(interface, 0, sizeof(interface)); ast_mutex_lock(&qlock); use_weight=0; /* Mark all queues as dead for the moment */ @@ -2557,7 +2912,12 @@ static void reload_queues(void) /* Chug through config file */ cat = ast_category_browse(cfg, NULL); while(cat) { - if (strcasecmp(cat, "general")) { /* Define queue */ + if (!strcasecmp(cat, "general")) { + /* Initialize global settings */ + queue_persistent_members = 0; + if ((general_val = ast_variable_retrieve(cfg, "general", "persistentmembers"))) + queue_persistent_members = ast_true(general_val); + } else { /* Define queue */ /* Look for an existing one */ q = queues; while(q) { @@ -2567,47 +2927,17 @@ static void reload_queues(void) } if (!q) { /* Make one then */ - q = malloc(sizeof(struct ast_call_queue)); - if (q) { - /* Initialize it */ - memset(q, 0, sizeof(struct ast_call_queue)); - ast_mutex_init(&q->lock); - ast_copy_string(q->name, cat, sizeof(q->name)); - new = 1; - } else new = 0; + q = alloc_queue(cat); + new = 1; } else - new = 0; + new = 0; if (q) { - if (!new) + if (!new) ast_mutex_lock(&q->lock); - /* Re-initialize the queue */ - q->dead = 0; - q->retry = DEFAULT_RETRY; - q->timeout = -1; - q->maxlen = 0; - q->announcefrequency = 0; - q->announceholdtime = 0; - q->roundingseconds = 0; /* Default - don't announce seconds */ - q->holdtime = 0; - q->callscompleted = 0; - q->callsabandoned = 0; - q->callscompletedinsl = 0; - q->servicelevel = 0; - q->wrapuptime = 0; + /* Re-initialize the queue, and clear statistics */ + init_queue(q); + clear_queue(q); free_members(q, 0); - q->moh[0] = '\0'; - q->announce[0] = '\0'; - q->context[0] = '\0'; - q->monfmt[0] = '\0'; - ast_copy_string(q->sound_next, "queue-youarenext", sizeof(q->sound_next)); - ast_copy_string(q->sound_thereare, "queue-thereare", sizeof(q->sound_thereare)); - ast_copy_string(q->sound_calls, "queue-callswaiting", sizeof(q->sound_calls)); - ast_copy_string(q->sound_holdtime, "queue-holdtime", sizeof(q->sound_holdtime)); - ast_copy_string(q->sound_minutes, "queue-minutes", sizeof(q->sound_minutes)); - ast_copy_string(q->sound_seconds, "queue-seconds", sizeof(q->sound_seconds)); - ast_copy_string(q->sound_thanks, "queue-thankyou", sizeof(q->sound_thanks)); - ast_copy_string(q->sound_lessthan, "queue-less-than", sizeof(q->sound_lessthan)); - ast_copy_string(q->sound_reporthold, "queue-reporthold", sizeof(q->sound_reporthold)); prev = q->members; if (prev) { /* find the end of any dynamic members */ @@ -2618,123 +2948,29 @@ static void reload_queues(void) while(var) { if (!strcasecmp(var->name, "member")) { /* Add a new member */ - cur = malloc(sizeof(struct member)); - if (cur) { - memset(cur, 0, sizeof(struct member)); - ast_copy_string(cur->interface, var->value, sizeof(cur->interface)); - if ((tmp = strchr(cur->interface, ','))) { - *tmp = '\0'; - tmp++; - cur->penalty = atoi(tmp); - if (cur->penalty < 0) - cur->penalty = 0; + ast_copy_string(interface, var->value, sizeof(interface)); + if ((tmp = strchr(interface, ','))) { + *tmp = '\0'; + tmp++; + penalty = atoi(tmp); + if (penalty < 0) { + penalty = 0; } - if (!strchr(cur->interface, '/')) - ast_log(LOG_WARNING, "No location at line %d of queue.conf\n", var->lineno); + } else + penalty = 0; + cur = create_queue_member(interface, penalty, 0); + if (cur) { if (prev) prev->next = cur; else q->members = cur; prev = cur; } - } else if (!strcasecmp(var->name, "music") || !strcasecmp(var->name, "musiconhold")) { - ast_copy_string(q->moh, var->value, sizeof(q->moh)); - } else if (!strcasecmp(var->name, "announce")) { - ast_copy_string(q->announce, var->value, sizeof(q->announce)); - } else if (!strcasecmp(var->name, "context")) { - ast_copy_string(q->context, var->value, sizeof(q->context)); - } else if (!strcasecmp(var->name, "timeout")) { - q->timeout = atoi(var->value); - } else if (!strcasecmp(var->name, "monitor-join")) { - q->monjoin = ast_true(var->value); - } else if (!strcasecmp(var->name, "monitor-format")) { - ast_copy_string(q->monfmt, var->value, sizeof(q->monfmt)); - } else if (!strcasecmp(var->name, "queue-youarenext")) { - ast_copy_string(q->sound_next, var->value, sizeof(q->sound_next)); - } else if (!strcasecmp(var->name, "queue-thereare")) { - ast_copy_string(q->sound_thereare, var->value, sizeof(q->sound_thereare)); - } else if (!strcasecmp(var->name, "queue-callswaiting")) { - ast_copy_string(q->sound_calls, var->value, sizeof(q->sound_calls)); - } else if (!strcasecmp(var->name, "queue-holdtime")) { - ast_copy_string(q->sound_holdtime, var->value, sizeof(q->sound_holdtime)); - } else if (!strcasecmp(var->name, "queue-minutes")) { - ast_copy_string(q->sound_minutes, var->value, sizeof(q->sound_minutes)); - } else if (!strcasecmp(var->name, "queue-seconds")) { - ast_copy_string(q->sound_seconds, var->value, sizeof(q->sound_seconds)); - } else if (!strcasecmp(var->name, "queue-lessthan")) { - ast_copy_string(q->sound_lessthan, var->value, sizeof(q->sound_lessthan)); - } else if (!strcasecmp(var->name, "queue-thankyou")) { - ast_copy_string(q->sound_thanks, var->value, sizeof(q->sound_thanks)); - } else if (!strcasecmp(var->name, "queue-reporthold")) { - ast_copy_string(q->sound_reporthold, var->value, sizeof(q->sound_reporthold)); - } else if (!strcasecmp(var->name, "announce-frequency")) { - q->announcefrequency = atoi(var->value); - } else if (!strcasecmp(var->name, "announce-round-seconds")) { - q->roundingseconds = atoi(var->value); - if(q->roundingseconds>60 || q->roundingseconds<0) { - ast_log(LOG_WARNING, "'%s' isn't a valid value for queue-rounding-seconds using 0 instead at line %d of queue.conf\n", var->value, var->lineno); - q->roundingseconds=0; - } - } else if (!strcasecmp(var->name, "announce-holdtime")) { - if (!strcasecmp(var->value, "once")) - q->announceholdtime = ANNOUNCEHOLDTIME_ONCE; - else if (ast_true(var->value)) - q->announceholdtime = ANNOUNCEHOLDTIME_ALWAYS; - else - q->announceholdtime = 0; - } else if (!strcasecmp(var->name, "retry")) { - q->retry = atoi(var->value); - } else if (!strcasecmp(var->name, "wrapuptime")) { - q->wrapuptime = atoi(var->value); - } else if (!strcasecmp(var->name, "maxlen")) { - q->maxlen = atoi(var->value); - } else if (!strcasecmp(var->name, "servicelevel")) { - q->servicelevel= atoi(var->value); - } else if (!strcasecmp(var->name, "strategy")) { - q->strategy = strat2int(var->value); - if (q->strategy < 0) { - ast_log(LOG_WARNING, "'%s' isn't a valid strategy, using ringall instead\n", var->value); - q->strategy = 0; - } - } else if (!strcasecmp(var->name, "joinempty")) { - if (!strcasecmp(var->value, "strict")) - q->joinempty = QUEUE_EMPTY_STRICT; - else if (ast_true(var->value)) - q->joinempty = QUEUE_EMPTY_NORMAL; - else - q->joinempty = 0; - } else if (!strcasecmp(var->name, "leavewhenempty")) { - if (!strcasecmp(var->value, "strict")) - q->leavewhenempty = QUEUE_EMPTY_STRICT; - else if (ast_true(var->value)) - q->leavewhenempty = QUEUE_EMPTY_NORMAL; - else - q->leavewhenempty = 0; - } else if (!strcasecmp(var->name, "eventmemberstatus")) { - q->maskmemberstatus = !ast_true(var->value); - } else if (!strcasecmp(var->name, "eventwhencalled")) { - q->eventwhencalled = ast_true(var->value); - } else if (!strcasecmp(var->name, "reportholdtime")) { - q->reportholdtime = ast_true(var->value); - } else if (!strcasecmp(var->name, "memberdelay")) { - q->memberdelay = atoi(var->value); - } else if (!strcasecmp(var->name, "weight")) { - q->weight = atoi(var->value); - if (q->weight) - use_weight++; - } else if (!strcasecmp(var->name, "timeoutrestart")) { - q->timeoutrestart = ast_true(var->value); } else { - ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s at line %d of queue.conf\n", cat, var->name, var->lineno); + queue_set_param(q, var->name, var->value, var->lineno, 1); } var = var->next; } - if (q->retry < 0) - q->retry = DEFAULT_RETRY; - if (q->timeout < 0) - q->timeout = DEFAULT_TIMEOUT; - if (q->maxlen < 0) - q->maxlen = 0; if (!new) ast_mutex_unlock(&q->lock); if (new) { @@ -2742,11 +2978,6 @@ static void reload_queues(void) queues = q; } } - } else { - /* Initialize global settings */ - queue_persistent_members = 0; - if ((general_val = ast_variable_retrieve(cfg, "general", "persistentmembers"))) - queue_persistent_members = ast_true(general_val); } cat = ast_category_browse(cfg, cat); } diff --git a/configs/extconfig.conf.sample b/configs/extconfig.conf.sample index c4b058adf..56ca2d117 100755 --- a/configs/extconfig.conf.sample +++ b/configs/extconfig.conf.sample @@ -34,4 +34,6 @@ ;sippeers => odbc,asterisk ;voicemail => odbc,asterisk ;extensions => odbc,asterisk +;queues => odbc,asterisk +;queue_members => odbc,asterisk -- cgit v1.2.3