Index: apps/app_queue.c =================================================================== --- apps/app_queue.c (revision 123867) +++ apps/app_queue.c (working copy) @@ -510,6 +510,8 @@ static struct ao2_container *queues; +static void copy_rules(struct queue_ent *qe, const char *rulename); +static void update_qe_rule(struct queue_ent *qe); static void update_realtime_members(struct call_queue *q); static int set_member_paused(const char *queuename, const char *interface, const char *reason, int paused); @@ -1674,7 +1676,7 @@ ast_config_destroy(member_config); } -static int join_queue(char *queuename, struct queue_ent *qe, enum queue_result *reason) +static int join_queue(char *queuename, struct queue_ent *qe, enum queue_result *reason, const char *overriding_rule) { struct call_queue *q; struct queue_ent *cur, *prev = NULL; @@ -1682,6 +1684,7 @@ int pos = 0; int inserted = 0; enum queue_member_status stat; + int exit = 0; if (!(q = load_realtime_queue(queuename))) return res; @@ -1689,50 +1692,64 @@ ao2_lock(queues); ao2_lock(q); + copy_rules(qe, S_OR(overriding_rule, q->defaultrule)); + qe->pr = AST_LIST_FIRST(&qe->qe_rules); + /* This is our one */ - stat = get_member_status(q, qe->max_penalty, qe->min_penalty); - if (!q->joinempty && (stat == QUEUE_NO_MEMBERS)) - *reason = QUEUE_JOINEMPTY; - else if ((q->joinempty == QUEUE_EMPTY_STRICT) && (stat == QUEUE_NO_REACHABLE_MEMBERS || stat == QUEUE_NO_UNPAUSED_REACHABLE_MEMBERS || stat == QUEUE_NO_MEMBERS)) - *reason = QUEUE_JOINUNAVAIL; - else if ((q->joinempty == QUEUE_EMPTY_LOOSE) && (stat == QUEUE_NO_REACHABLE_MEMBERS || stat == QUEUE_NO_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)) { + while (!exit) { + stat = get_member_status(q, qe->max_penalty, qe->min_penalty); + if (!q->joinempty && (stat == QUEUE_NO_MEMBERS)) + *reason = QUEUE_JOINEMPTY; + else if ((q->joinempty == QUEUE_EMPTY_STRICT) && (stat == QUEUE_NO_REACHABLE_MEMBERS || stat == QUEUE_NO_UNPAUSED_REACHABLE_MEMBERS || stat == QUEUE_NO_MEMBERS)) + *reason = QUEUE_JOINUNAVAIL; + else if ((q->joinempty == QUEUE_EMPTY_LOOSE) && (stat == QUEUE_NO_REACHABLE_MEMBERS || stat == QUEUE_NO_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); - inserted = 1; - } - cur->pos = ++pos; - prev = cur; - cur = cur->next; + 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\nUniqueid: %s\r\n", + qe->chan->name, + S_OR(qe->chan->cid.cid_num, "unknown"), /* XXX somewhere else it is */ + S_OR(qe->chan->cid.cid_name, "unknown"), + q->name, qe->pos, q->count, qe->chan->uniqueid ); + ast_debug(1, "Queue '%s' Join, Channel '%s', Position '%d'\n", q->name, qe->chan->name, qe->pos ); + exit = 1; } - /* 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\nUniqueid: %s\r\n", - qe->chan->name, - S_OR(qe->chan->cid.cid_num, "unknown"), /* XXX somewhere else it is */ - S_OR(qe->chan->cid.cid_name, "unknown"), - q->name, qe->pos, q->count, qe->chan->uniqueid ); - ast_debug(1, "Queue '%s' Join, Channel '%s', Position '%d'\n", q->name, qe->chan->name, qe->pos ); + if (!exit && qe->pr) { + /* We failed to join the queue, but perhaps we can join if we move + * to the next defined penalty rule + */ + update_qe_rule(qe); + } else if (!qe->pr) { + exit = 1; + } } ao2_unlock(q); ao2_unlock(queues); @@ -4316,7 +4333,10 @@ { struct penalty_rule *pr_iter; struct rule_list *rl_iter; - const char *tmp = ast_strlen_zero(rulename) ? qe->parent->defaultrule : rulename; + const char *tmp = rulename; + if (ast_strlen_zero(tmp)) { + return; + } AST_LIST_LOCK(&rule_lists); AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) { if (!strcasecmp(rl_iter->name, tmp)) @@ -4460,15 +4480,13 @@ qe.last_periodic_announce_time = time(NULL); qe.last_periodic_announce_sound = 0; qe.valid_digits = 0; - if (join_queue(args.queuename, &qe, &reason)) { + if (join_queue(args.queuename, &qe, &reason, args.rule)) { ast_log(LOG_WARNING, "Unable to join queue '%s'\n", args.queuename); set_queue_result(chan, reason); return 0; } ast_queue_log(args.queuename, chan->uniqueid, "NONE", "ENTERQUEUE", "%s|%s", S_OR(args.url, ""), S_OR(chan->cid.cid_num, "")); - copy_rules(&qe, args.rule); - qe.pr = AST_LIST_FIRST(&qe.qe_rules); check_turns: if (ringing) { ast_indicate(chan, AST_CONTROL_RINGING);