#include "asterisk.h"
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <sys/time.h>
#include <sys/signal.h>
#include <netinet/in.h>
#include "asterisk/lock.h"
#include "asterisk/file.h"
#include "asterisk/logger.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/options.h"
#include "asterisk/app.h"
#include "asterisk/linkedlists.h"
#include "asterisk/module.h"
#include "asterisk/translate.h"
#include "asterisk/say.h"
#include "asterisk/features.h"
#include "asterisk/musiconhold.h"
#include "asterisk/cli.h"
#include "asterisk/manager.h"
#include "asterisk/config.h"
#include "asterisk/monitor.h"
#include "asterisk/utils.h"
#include "asterisk/causes.h"
#include "asterisk/astdb.h"
#include "asterisk/devicestate.h"
#include "asterisk/stringfields.h"
#include "asterisk/astobj2.h"
#include "asterisk/global_datastores.h"
Go to the source code of this file.
Data Structures | |
struct | call_queue |
struct | callattempt |
We define a custom "local user" structure because we use it not only for keeping track of what is in use but also for keeping track of who we're dialing. More... | |
struct | member |
struct | member_interface |
struct | queue_ent |
struct | statechange |
struct | strategy |
Defines | |
#define | ANNOUNCEHOLDTIME_ALWAYS 1 |
#define | ANNOUNCEHOLDTIME_ONCE 2 |
#define | AST_MAX_WATCHERS 256 |
#define | DEFAULT_RETRY 5 |
#define | DEFAULT_TIMEOUT 15 |
#define | MAX_PERIODIC_ANNOUNCEMENTS 10 |
#define | PM_MAX_LEN 8192 |
#define | QUEUE_EMPTY_NORMAL 1 |
#define | QUEUE_EMPTY_STRICT 2 |
#define | QUEUE_EVENT_VARIABLES 3 |
#define | RECHECK 1 |
#define | RES_EXISTS (-1) |
#define | RES_NOSUCHQUEUE (-3) |
#define | RES_NOT_DYNAMIC (-4) |
#define | RES_OKAY 0 |
#define | RES_OUTOFMEMORY (-2) |
Enumerations | |
enum | { QUEUE_STRATEGY_RINGALL = 0, QUEUE_STRATEGY_ROUNDROBIN, QUEUE_STRATEGY_LEASTRECENT, QUEUE_STRATEGY_FEWESTCALLS, QUEUE_STRATEGY_RANDOM, QUEUE_STRATEGY_RRMEMORY } |
enum | qmc_status { QMC_VALID = 0, QMC_PAUSED, QMC_ACTIVE, QMC_FREE, QMC_ALL } |
enum | queue_member_status { QUEUE_NO_MEMBERS, QUEUE_NO_REACHABLE_MEMBERS, QUEUE_NORMAL } |
enum | queue_result { QUEUE_UNKNOWN = 0, QUEUE_TIMEOUT = 1, QUEUE_JOINEMPTY = 2, QUEUE_LEAVEEMPTY = 3, QUEUE_JOINUNAVAIL = 4, QUEUE_LEAVEUNAVAIL = 5, QUEUE_FULL = 6 } |
Functions | |
static int | __queues_show (struct mansession *s, int manager, int fd, int argc, char **argv) |
static int | add_to_interfaces (const char *interface) |
static int | add_to_queue (const char *queuename, const char *interface, const char *membername, int penalty, int paused, int dump) |
static struct call_queue * | alloc_queue (const char *queuename) |
static int | aqm_exec (struct ast_channel *chan, void *data) |
static | AST_LIST_HEAD_STATIC (queues, call_queue) |
static | AST_LIST_HEAD_STATIC (interfaces, member_interface) |
AST_MODULE_INFO (ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT,"True Call Queueing",.load=load_module,.unload=unload_module,.reload=reload,) | |
static int | calc_metric (struct call_queue *q, struct member *mem, int pos, struct queue_ent *qe, struct callattempt *tmp) |
Calculate the metric of each member in the outgoing callattempts. | |
static void | clear_and_free_interfaces (void) |
static void | clear_queue (struct call_queue *q) |
static int | compare_weight (struct call_queue *rq, struct member *member) |
static char * | complete_queue (const char *line, const char *word, int pos, int state) |
static char * | complete_queue_add_member (const char *line, const char *word, int pos, int state) |
static char * | complete_queue_remove_member (const char *line, const char *word, int pos, int state) |
static char * | complete_queue_show (const char *line, const char *word, int pos, int state) |
static int | compress_char (const char c) |
static struct member * | create_queue_member (const char *interface, const char *membername, int penalty, int paused) |
allocate space for new queue member and set fields based on parameters passed | |
static void | destroy_queue (struct call_queue *q) |
static void * | device_state_thread (void *data) |
Consumer of the statechange queue. | |
static void | do_hang (struct callattempt *o) |
common hangup actions | |
static void | dump_queue_members (struct call_queue *pm_queue) |
static struct callattempt * | find_best (struct callattempt *outgoing) |
find the entry with the best metric, or NULL | |
static struct call_queue * | find_queue_by_name_rt (const char *queuename, struct ast_variable *queue_vars, struct ast_config *member_config) |
Reload a single queue via realtime. | |
static void | free_members (struct call_queue *q, int all) |
static enum queue_member_status | get_member_status (struct call_queue *q, int max_penalty) |
Check if members are available. | |
static int | handle_queue_add_member (int fd, int argc, char *argv[]) |
static int | handle_queue_remove_member (int fd, int argc, char *argv[]) |
static void * | handle_statechange (struct statechange *sc) |
set a member's status based on device state of that member's interface | |
static void | hangupcalls (struct callattempt *outgoing, struct ast_channel *exception) |
static void | init_queue (struct call_queue *q) |
static void | insert_entry (struct call_queue *q, struct queue_ent *prev, struct queue_ent *new, int *pos) |
Insert the 'new' entry after the 'prev' entry of queue 'q'. | |
static char * | int2strat (int strategy) |
static struct member * | interface_exists (struct call_queue *q, const char *interface) |
static int | interface_exists_global (const char *interface) |
static int | is_our_turn (struct queue_ent *qe) |
Check if we should start attempting to call queue members. | |
static int | join_queue (char *queuename, struct queue_ent *qe, enum queue_result *reason) |
static void | leave_queue (struct queue_ent *qe) |
static int | load_module (void) |
static struct call_queue * | load_realtime_queue (const char *queuename) |
static int | manager_add_queue_member (struct mansession *s, const struct message *m) |
static int | manager_pause_queue_member (struct mansession *s, const struct message *m) |
static int | manager_queues_show (struct mansession *s, const struct message *m) |
static int | manager_queues_status (struct mansession *s, const struct message *m) |
static int | manager_remove_queue_member (struct mansession *s, const struct message *m) |
static int | member_cmp_fn (void *obj1, void *obj2, int flags) |
static int | member_hash_fn (const void *obj, const int flags) |
static void | monjoin_dep_warning (void) |
static int | play_file (struct ast_channel *chan, char *filename) |
static int | pqm_exec (struct ast_channel *chan, void *data) |
static int | ql_exec (struct ast_channel *chan, void *data) |
static int | queue_exec (struct ast_channel *chan, void *data) |
The starting point for all queue calls. | |
static int | queue_function_queuemembercount (struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len) |
static int | queue_function_queuememberlist (struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len) |
static int | queue_function_queuewaitingcount (struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len) |
static void | queue_set_param (struct call_queue *q, const char *param, const char *val, int linenum, int failunknown) |
Configure a queue parameter. | |
static int | queue_show (int fd, int argc, char **argv) |
static void | recalc_holdtime (struct queue_ent *qe, int newholdtime) |
static void | record_abandoned (struct queue_ent *qe) |
static int | reload (void) |
static void | reload_queue_members (void) |
static int | reload_queues (void) |
static int | remove_from_interfaces (const char *interface) |
static int | remove_from_queue (const char *queuename, const char *interface) |
static int | ring_entry (struct queue_ent *qe, struct callattempt *tmp, int *busies) |
Part 2 of ring_one. | |
static int | ring_one (struct queue_ent *qe, struct callattempt *outgoing, int *busies) |
Place a call to a queue member. | |
static void | rna (int rnatime, struct queue_ent *qe, char *interface, char *membername) |
RNA == Ring No Answer. Common code that is executed when we try a queue member and they don't answer. | |
static int | rqm_exec (struct ast_channel *chan, void *data) |
static void | rr_dep_warning (void) |
static void | rt_handle_member_record (struct call_queue *q, char *interface, const char *membername, const char *penalty_str, const char *paused_str) |
static int | say_periodic_announcement (struct queue_ent *qe) |
static int | say_position (struct queue_ent *qe) |
static int | set_member_paused (const char *queuename, const char *interface, int paused) |
static void | set_queue_result (struct ast_channel *chan, enum queue_result res) |
sets the QUEUESTATUS channel variable | |
static int | statechange_queue (const char *dev, int state, void *ign) |
Producer of the statechange queue. | |
static int | store_next (struct queue_ent *qe, struct callattempt *outgoing) |
static int | strat2int (const char *strategy) |
static int | try_calling (struct queue_ent *qe, const char *options, char *announceoverride, const char *url, int *tries, int *noption, const char *agi) |
A large function which calls members, updates statistics, and bridges the caller and a member. | |
static int | unload_module (void) |
static int | update_queue (struct call_queue *q, struct member *member, int callcompletedinsl) |
static int | update_realtime_member_field (struct member *mem, const char *queue_name, const char *field, const char *value) |
static void | update_realtime_members (struct call_queue *q) |
static int | update_status (const char *interface, const int status) |
static int | upqm_exec (struct ast_channel *chan, void *data) |
static int | valid_exit (struct queue_ent *qe, char digit) |
static char * | vars2manager (struct ast_channel *chan, char *vars, size_t len) |
static int | wait_a_bit (struct queue_ent *qe) |
static struct callattempt * | wait_for_answer (struct queue_ent *qe, struct callattempt *outgoing, int *to, char *digit, int prebusies, int caller_disconnect, int forwardsallowed) |
Wait for a member to answer the call. | |
static int | wait_our_turn (struct queue_ent *qe, int ringing, enum queue_result *reason) |
The waiting areas for callers who are not actively calling members. | |
Variables | |
static char * | app = "Queue" |
static char * | app_aqm = "AddQueueMember" |
static char * | app_aqm_descrip |
static char * | app_aqm_synopsis = "Dynamically adds queue members" |
static char * | app_pqm = "PauseQueueMember" |
static char * | app_pqm_descrip |
static char * | app_pqm_synopsis = "Pauses a queue member" |
static char * | app_ql = "QueueLog" |
static char * | app_ql_descrip |
static char * | app_ql_synopsis = "Writes to the queue_log" |
static char * | app_rqm = "RemoveQueueMember" |
static char * | app_rqm_descrip |
static char * | app_rqm_synopsis = "Dynamically removes queue members" |
static char * | app_upqm = "UnpauseQueueMember" |
static char * | app_upqm_descrip |
static char * | app_upqm_synopsis = "Unpauses a queue member" |
static int | autofill_default = 0 |
queues.conf [general] option | |
static struct ast_cli_entry | cli_add_queue_member_deprecated |
static struct ast_cli_entry | cli_queue [] |
static struct ast_cli_entry | cli_remove_queue_member_deprecated |
static struct ast_cli_entry | cli_show_queue_deprecated |
static char * | descrip |
struct { | |
ast_cond_t cond | |
ast_mutex_t lock | |
unsigned int stop:1 | |
pthread_t thread | |
} | device_state |
Data used by the device state thread. | |
static int | montype_default = 0 |
queues.conf [general] option | |
static const char * | pm_family = "Queue/PersistentMembers" |
Persistent Members astdb family. | |
static char | qam_cmd_usage [] |
static char | qrm_cmd_usage [] |
static int | queue_debug = 0 |
queues.conf [general] extra debug option | |
static int | queue_persistent_members = 0 |
queues.conf [general] option | |
struct { | |
enum queue_result id | |
char * text | |
} | queue_results [] |
static char | queue_show_usage [] |
static struct ast_custom_function | queueagentcount_function |
static struct ast_custom_function | queuemembercount_function |
static struct ast_custom_function | queuememberlist_function |
static struct ast_custom_function | queuewaitingcount_function |
static struct strategy | strategies [] |
static char * | synopsis = "Queue a call for a call queue" |
static int | use_weight = 0 |
queues.conf per-queue weight option |
These features added by David C. Troy <dave@toad.net>:
Added servicelevel statistic by Michiel Betel <michiel@betel.nl> Added Priority jumping code for adding and removing queue members by Jonathan Stanton <asterisk@doilooklikeicare.com>
Fixed to work with CVS as of 2004-02-25 and released as 1.07a by Matthew Enger <m.enger@xi.com.au>
Definition in file app_queue.c.
#define ANNOUNCEHOLDTIME_ALWAYS 1 |
#define ANNOUNCEHOLDTIME_ONCE 2 |
#define AST_MAX_WATCHERS 256 |
Definition at line 2090 of file app_queue.c.
#define DEFAULT_RETRY 5 |
#define DEFAULT_TIMEOUT 15 |
#define MAX_PERIODIC_ANNOUNCEMENTS 10 |
Definition at line 140 of file app_queue.c.
Referenced by init_queue(), queue_set_param(), and say_periodic_announcement().
#define PM_MAX_LEN 8192 |
Definition at line 263 of file app_queue.c.
Referenced by dump_queue_members(), and reload_queue_members().
#define QUEUE_EMPTY_NORMAL 1 |
#define QUEUE_EMPTY_STRICT 2 |
Definition at line 375 of file app_queue.c.
Referenced by join_queue(), queue_exec(), queue_set_param(), and wait_our_turn().
#define QUEUE_EVENT_VARIABLES 3 |
Definition at line 378 of file app_queue.c.
Referenced by queue_set_param(), ring_entry(), and try_calling().
#define RECHECK 1 |
#define RES_EXISTS (-1) |
Definition at line 143 of file app_queue.c.
Referenced by add_to_queue(), aqm_exec(), handle_queue_add_member(), handle_queue_remove_member(), manager_add_queue_member(), manager_remove_queue_member(), remove_from_queue(), and rqm_exec().
#define RES_NOSUCHQUEUE (-3) |
Definition at line 145 of file app_queue.c.
Referenced by add_to_queue(), aqm_exec(), handle_queue_add_member(), handle_queue_remove_member(), manager_add_queue_member(), manager_remove_queue_member(), remove_from_queue(), and rqm_exec().
#define RES_NOT_DYNAMIC (-4) |
Definition at line 146 of file app_queue.c.
Referenced by handle_queue_remove_member(), manager_remove_queue_member(), remove_from_queue(), and rqm_exec().
#define RES_OKAY 0 |
Definition at line 142 of file app_queue.c.
Referenced by add_to_queue(), aqm_exec(), handle_queue_add_member(), handle_queue_remove_member(), manager_add_queue_member(), manager_remove_queue_member(), remove_from_queue(), and rqm_exec().
#define RES_OUTOFMEMORY (-2) |
Definition at line 144 of file app_queue.c.
Referenced by add_to_queue(), aqm_exec(), handle_queue_add_member(), handle_queue_remove_member(), manager_add_queue_member(), manager_remove_queue_member(), and reload_queue_members().
anonymous enum |
QUEUE_STRATEGY_RINGALL | |
QUEUE_STRATEGY_ROUNDROBIN | |
QUEUE_STRATEGY_LEASTRECENT | |
QUEUE_STRATEGY_FEWESTCALLS | |
QUEUE_STRATEGY_RANDOM | |
QUEUE_STRATEGY_RRMEMORY |
Definition at line 116 of file app_queue.c.
00116 { 00117 QUEUE_STRATEGY_RINGALL = 0, 00118 QUEUE_STRATEGY_ROUNDROBIN, 00119 QUEUE_STRATEGY_LEASTRECENT, 00120 QUEUE_STRATEGY_FEWESTCALLS, 00121 QUEUE_STRATEGY_RANDOM, 00122 QUEUE_STRATEGY_RRMEMORY 00123 };
enum qmc_status |
Definition at line 3992 of file app_queue.c.
03992 { 03993 QMC_VALID = 0, /* Count valid members */ 03994 QMC_PAUSED, /* Count paused members */ 03995 QMC_ACTIVE, /* Count active members */ 03996 QMC_FREE, /* Count free members */ 03997 QMC_ALL /* Count all queue members */ 03998 };
enum queue_member_status |
Definition at line 527 of file app_queue.c.
00527 { 00528 QUEUE_NO_MEMBERS, 00529 QUEUE_NO_REACHABLE_MEMBERS, 00530 QUEUE_NORMAL 00531 };
enum queue_result |
QUEUE_UNKNOWN | |
QUEUE_TIMEOUT | |
QUEUE_JOINEMPTY | |
QUEUE_LEAVEEMPTY | |
QUEUE_JOINUNAVAIL | |
QUEUE_LEAVEUNAVAIL | |
QUEUE_FULL |
Definition at line 280 of file app_queue.c.
00280 { 00281 QUEUE_UNKNOWN = 0, 00282 QUEUE_TIMEOUT = 1, 00283 QUEUE_JOINEMPTY = 2, 00284 QUEUE_LEAVEEMPTY = 3, 00285 QUEUE_JOINUNAVAIL = 4, 00286 QUEUE_LEAVEUNAVAIL = 5, 00287 QUEUE_FULL = 6, 00288 };
static int __queues_show | ( | struct mansession * | s, | |
int | manager, | |||
int | fd, | |||
int | argc, | |||
char ** | argv | |||
) | [static] |
Definition at line 4409 of file app_queue.c.
References ao2_container_count(), ao2_iterator_init(), ao2_iterator_next(), ao2_ref(), ast_build_string(), ast_cli(), AST_LIST_EMPTY, AST_LIST_LOCK, AST_LIST_NEXT, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_mutex_lock(), ast_mutex_unlock(), astman_append(), member::calls, call_queue::callsabandoned, call_queue::callscompleted, call_queue::callscompletedinsl, queue_ent::chan, call_queue::count, devstate2str(), member::dynamic, call_queue::head, call_queue::holdtime, int2strat(), member::lastcall, load_realtime_queue(), call_queue::lock, call_queue::maxlen, member::membername, call_queue::members, call_queue::name, queue_ent::next, member::paused, member::penalty, queue_ent::prio, queue_show(), member::realtime, RESULT_SHOWUSAGE, RESULT_SUCCESS, call_queue::ringlimit, s, call_queue::servicelevel, queue_ent::start, member::status, call_queue::strategy, and call_queue::weight.
Referenced by manager_queues_show(), and queue_show().
04410 { 04411 struct call_queue *q; 04412 struct queue_ent *qe; 04413 struct member *mem; 04414 int pos, queue_show; 04415 time_t now; 04416 char max_buf[80]; 04417 char *max; 04418 size_t max_left; 04419 float sl = 0; 04420 char *term = manager ? "\r\n" : "\n"; 04421 struct ao2_iterator mem_iter; 04422 04423 time(&now); 04424 if (argc == 2) 04425 queue_show = 0; 04426 else if (argc == 3) 04427 queue_show = 1; 04428 else 04429 return RESULT_SHOWUSAGE; 04430 04431 /* We only want to load realtime queues when a specific queue is asked for. */ 04432 if (queue_show) 04433 load_realtime_queue(argv[2]); 04434 04435 AST_LIST_LOCK(&queues); 04436 if (AST_LIST_EMPTY(&queues)) { 04437 AST_LIST_UNLOCK(&queues); 04438 if (queue_show) { 04439 if (s) 04440 astman_append(s, "No such queue: %s.%s",argv[2], term); 04441 else 04442 ast_cli(fd, "No such queue: %s.%s",argv[2], term); 04443 } else { 04444 if (s) 04445 astman_append(s, "No queues.%s", term); 04446 else 04447 ast_cli(fd, "No queues.%s", term); 04448 } 04449 return RESULT_SUCCESS; 04450 } 04451 AST_LIST_TRAVERSE(&queues, q, list) { 04452 ast_mutex_lock(&q->lock); 04453 if (queue_show) { 04454 if (strcasecmp(q->name, argv[2]) != 0) { 04455 ast_mutex_unlock(&q->lock); 04456 if (!AST_LIST_NEXT(q, list)) { 04457 ast_cli(fd, "No such queue: %s.%s",argv[2], term); 04458 break; 04459 } 04460 continue; 04461 } 04462 } 04463 max_buf[0] = '\0'; 04464 max = max_buf; 04465 max_left = sizeof(max_buf); 04466 if (q->maxlen) 04467 ast_build_string(&max, &max_left, "%d", q->maxlen); 04468 else 04469 ast_build_string(&max, &max_left, "unlimited"); 04470 sl = 0; 04471 if (q->callscompleted > 0) 04472 sl = 100 * ((float) q->callscompletedinsl / (float) q->callscompleted); 04473 if (s) 04474 astman_append(s, "%-12.12s has %d calls (max %s) in '%s' strategy (%ds holdtime), R:%d, W:%d, C:%d, A:%d, SL:%2.1f%% within %ds%s", 04475 q->name, q->count, max_buf, int2strat(q->strategy), q->holdtime, q->ringlimit, 04476 q->weight, q->callscompleted, q->callsabandoned, sl, q->servicelevel, term); 04477 else 04478 ast_cli(fd, "%-12.12s has %d calls (max %s) in '%s' strategy (%ds holdtime), R:%d, W:%d, C:%d, A:%d, SL:%2.1f%% within %ds%s", 04479 q->name, q->count, max_buf, int2strat(q->strategy), q->holdtime, q->ringlimit, 04480 q->weight, q->callscompleted, q->callsabandoned, sl, q->servicelevel, term); 04481 if (ao2_container_count(q->members)) { 04482 if (s) 04483 astman_append(s, " Members: %s", term); 04484 else 04485 ast_cli(fd, " Members: %s", term); 04486 mem_iter = ao2_iterator_init(q->members, 0); 04487 while ((mem = ao2_iterator_next(&mem_iter))) { 04488 max_buf[0] = '\0'; 04489 max = max_buf; 04490 max_left = sizeof(max_buf); 04491 if (mem->penalty) 04492 ast_build_string(&max, &max_left, " with penalty %d", mem->penalty); 04493 if (mem->dynamic) 04494 ast_build_string(&max, &max_left, " (dynamic)"); 04495 if (mem->realtime) 04496 ast_build_string(&max, &max_left, " (realtime)"); 04497 if (mem->paused) 04498 ast_build_string(&max, &max_left, " (paused)"); 04499 ast_build_string(&max, &max_left, " (%s)", devstate2str(mem->status)); 04500 if (mem->calls) { 04501 ast_build_string(&max, &max_left, " has taken %d calls (last was %ld secs ago)", 04502 mem->calls, (long) (time(NULL) - mem->lastcall)); 04503 } else 04504 ast_build_string(&max, &max_left, " has taken no calls yet"); 04505 if (s) 04506 astman_append(s, " %s%s%s", mem->membername, max_buf, term); 04507 else 04508 ast_cli(fd, " %s%s%s", mem->membername, max_buf, term); 04509 ao2_ref(mem, -1); 04510 } 04511 } else if (s) 04512 astman_append(s, " No Members%s", term); 04513 else 04514 ast_cli(fd, " No Members%s", term); 04515 if (q->head) { 04516 pos = 1; 04517 if (s) 04518 astman_append(s, " Callers: %s", term); 04519 else 04520 ast_cli(fd, " Callers: %s", term); 04521 for (qe = q->head; qe; qe = qe->next) { 04522 if (s) 04523 astman_append(s, " %d. %s (wait: %ld:%2.2ld, prio: %d)%s", 04524 pos++, qe->chan->name, (long) (now - qe->start) / 60, 04525 (long) (now - qe->start) % 60, qe->prio, term); 04526 else 04527 ast_cli(fd, " %d. %s (wait: %ld:%2.2ld, prio: %d)%s", pos++, 04528 qe->chan->name, (long) (now - qe->start) / 60, 04529 (long) (now - qe->start) % 60, qe->prio, term); 04530 } 04531 } else if (s) 04532 astman_append(s, " No Callers%s", term); 04533 else 04534 ast_cli(fd, " No Callers%s", term); 04535 if (s) 04536 astman_append(s, "%s", term); 04537 else 04538 ast_cli(fd, "%s", term); 04539 ast_mutex_unlock(&q->lock); 04540 if (queue_show) 04541 break; 04542 } 04543 AST_LIST_UNLOCK(&queues); 04544 return RESULT_SUCCESS; 04545 }
static int add_to_interfaces | ( | const char * | interface | ) | [static] |
Definition at line 869 of file app_queue.c.
References ast_calloc, AST_LIST_INSERT_HEAD, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), member_interface::interface, LOG_DEBUG, and option_debug.
Referenced by add_to_queue(), reload_queues(), and rt_handle_member_record().
00870 { 00871 struct member_interface *curint; 00872 00873 AST_LIST_LOCK(&interfaces); 00874 AST_LIST_TRAVERSE(&interfaces, curint, list) { 00875 if (!strcasecmp(curint->interface, interface)) 00876 break; 00877 } 00878 00879 if (curint) { 00880 AST_LIST_UNLOCK(&interfaces); 00881 return 0; 00882 } 00883 00884 if (option_debug) 00885 ast_log(LOG_DEBUG, "Adding %s to the list of interfaces that make up all of our queue members.\n", interface); 00886 00887 if ((curint = ast_calloc(1, sizeof(*curint)))) { 00888 ast_copy_string(curint->interface, interface, sizeof(curint->interface)); 00889 AST_LIST_INSERT_HEAD(&interfaces, curint, list); 00890 } 00891 AST_LIST_UNLOCK(&interfaces); 00892 00893 return 0; 00894 }
static int add_to_queue | ( | const char * | queuename, | |
const char * | interface, | |||
const char * | membername, | |||
int | penalty, | |||
int | paused, | |||
int | dump | |||
) | [static] |
Definition at line 3242 of file app_queue.c.
References add_to_interfaces(), ao2_ref(), AST_LIST_LOCK, AST_LIST_UNLOCK, ast_mutex_lock(), ast_mutex_unlock(), member::calls, create_queue_member(), dump_queue_members(), member::dynamic, EVENT_FLAG_AGENT, member::interface, interface_exists(), member::lastcall, load_realtime_queue(), call_queue::lock, manager_event(), call_queue::membercount, member::membername, call_queue::members, call_queue::name, member::paused, member::penalty, RES_EXISTS, RES_NOSUCHQUEUE, RES_OKAY, RES_OUTOFMEMORY, and member::status.
Referenced by aqm_exec(), handle_queue_add_member(), manager_add_queue_member(), and reload_queue_members().
03243 { 03244 struct call_queue *q; 03245 struct member *new_member, *old_member; 03246 int res = RES_NOSUCHQUEUE; 03247 03248 /* \note Ensure the appropriate realtime queue is loaded. Note that this 03249 * short-circuits if the queue is already in memory. */ 03250 if (!(q = load_realtime_queue(queuename))) 03251 return res; 03252 03253 AST_LIST_LOCK(&queues); 03254 03255 ast_mutex_lock(&q->lock); 03256 if ((old_member = interface_exists(q, interface)) == NULL) { 03257 add_to_interfaces(interface); 03258 if ((new_member = create_queue_member(interface, membername, penalty, paused))) { 03259 new_member->dynamic = 1; 03260 ao2_link(q->members, new_member); 03261 q->membercount++; 03262 manager_event(EVENT_FLAG_AGENT, "QueueMemberAdded", 03263 "Queue: %s\r\n" 03264 "Location: %s\r\n" 03265 "MemberName: %s\r\n" 03266 "Membership: %s\r\n" 03267 "Penalty: %d\r\n" 03268 "CallsTaken: %d\r\n" 03269 "LastCall: %d\r\n" 03270 "Status: %d\r\n" 03271 "Paused: %d\r\n", 03272 q->name, new_member->interface, new_member->membername, 03273 "dynamic", 03274 new_member->penalty, new_member->calls, (int) new_member->lastcall, 03275 new_member->status, new_member->paused); 03276 03277 ao2_ref(new_member, -1); 03278 new_member = NULL; 03279 03280 if (dump) 03281 dump_queue_members(q); 03282 03283 res = RES_OKAY; 03284 } else { 03285 res = RES_OUTOFMEMORY; 03286 } 03287 } else { 03288 ao2_ref(old_member, -1); 03289 res = RES_EXISTS; 03290 } 03291 ast_mutex_unlock(&q->lock); 03292 AST_LIST_UNLOCK(&queues); 03293 03294 return res; 03295 }
static struct call_queue* alloc_queue | ( | const char * | queuename | ) | [static] |
Definition at line 770 of file app_queue.c.
References ast_calloc, and ast_mutex_init().
Referenced by find_queue_by_name_rt(), and reload_queues().
00771 { 00772 struct call_queue *q; 00773 00774 if ((q = ast_calloc(1, sizeof(*q)))) { 00775 ast_mutex_init(&q->lock); 00776 ast_copy_string(q->name, queuename, sizeof(q->name)); 00777 } 00778 return q; 00779 }
static int aqm_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Definition at line 3621 of file app_queue.c.
References add_to_queue(), AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_goto_if_exists(), ast_log(), ast_module_user_add, ast_module_user_remove, ast_opt_priority_jumping, ast_queue_log(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), ast_module_user::chan, ast_channel::context, LOG_ERROR, LOG_NOTICE, LOG_WARNING, parse(), pbx_builtin_setvar_helper(), RES_EXISTS, RES_NOSUCHQUEUE, RES_OKAY, and RES_OUTOFMEMORY.
Referenced by load_module().
03622 { 03623 int res=-1; 03624 struct ast_module_user *lu; 03625 char *parse, *temppos = NULL; 03626 int priority_jump = 0; 03627 AST_DECLARE_APP_ARGS(args, 03628 AST_APP_ARG(queuename); 03629 AST_APP_ARG(interface); 03630 AST_APP_ARG(penalty); 03631 AST_APP_ARG(options); 03632 AST_APP_ARG(membername); 03633 ); 03634 int penalty = 0; 03635 03636 if (ast_strlen_zero(data)) { 03637 ast_log(LOG_WARNING, "AddQueueMember requires an argument (queuename[|[interface]|[penalty][|options][|membername]])\n"); 03638 return -1; 03639 } 03640 03641 parse = ast_strdupa(data); 03642 03643 AST_STANDARD_APP_ARGS(args, parse); 03644 03645 lu = ast_module_user_add(chan); 03646 03647 if (ast_strlen_zero(args.interface)) { 03648 args.interface = ast_strdupa(chan->name); 03649 temppos = strrchr(args.interface, '-'); 03650 if (temppos) 03651 *temppos = '\0'; 03652 } 03653 03654 if (!ast_strlen_zero(args.penalty)) { 03655 if ((sscanf(args.penalty, "%d", &penalty) != 1) || penalty < 0) { 03656 ast_log(LOG_WARNING, "Penalty '%s' is invalid, must be an integer >= 0\n", args.penalty); 03657 penalty = 0; 03658 } 03659 } 03660 03661 if (args.options) { 03662 if (strchr(args.options, 'j')) 03663 priority_jump = 1; 03664 } 03665 03666 switch (add_to_queue(args.queuename, args.interface, args.membername, penalty, 0, queue_persistent_members)) { 03667 case RES_OKAY: 03668 ast_queue_log(args.queuename, chan->uniqueid, args.interface, "ADDMEMBER", "%s", ""); 03669 ast_log(LOG_NOTICE, "Added interface '%s' to queue '%s'\n", args.interface, args.queuename); 03670 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "ADDED"); 03671 res = 0; 03672 break; 03673 case RES_EXISTS: 03674 ast_log(LOG_WARNING, "Unable to add interface '%s' to queue '%s': Already there\n", args.interface, args.queuename); 03675 if (priority_jump || ast_opt_priority_jumping) 03676 ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101); 03677 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "MEMBERALREADY"); 03678 res = 0; 03679 break; 03680 case RES_NOSUCHQUEUE: 03681 ast_log(LOG_WARNING, "Unable to add interface to queue '%s': No such queue\n", args.queuename); 03682 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "NOSUCHQUEUE"); 03683 res = 0; 03684 break; 03685 case RES_OUTOFMEMORY: 03686 ast_log(LOG_ERROR, "Out of memory adding member %s to queue %s\n", args.interface, args.queuename); 03687 break; 03688 } 03689 03690 ast_module_user_remove(lu); 03691 03692 return res; 03693 }
static AST_LIST_HEAD_STATIC | ( | queues | , | |
call_queue | ||||
) | [static] |
static AST_LIST_HEAD_STATIC | ( | interfaces | , | |
member_interface | ||||
) | [static] |
AST_MODULE_INFO | ( | ASTERISK_GPL_KEY | , | |
AST_MODFLAG_DEFAULT | , | |||
"True Call Queueing" | , | |||
. | load = load_module , |
|||
. | unload = unload_module , |
|||
. | reload = reload | |||
) |
static int calc_metric | ( | struct call_queue * | q, | |
struct member * | mem, | |||
int | pos, | |||
struct queue_ent * | qe, | |||
struct callattempt * | tmp | |||
) | [static] |
Calculate the metric of each member in the outgoing callattempts.
A numeric metric is given to each member depending on the ring strategy used by the queue. Members with lower metrics will be called before members with higher metrics
Definition at line 2508 of file app_queue.c.
References ast_log(), ast_random(), member::calls, member::interface, member::lastcall, LOG_DEBUG, LOG_WARNING, queue_ent::max_penalty, callattempt::metric, option_debug, member::penalty, QUEUE_STRATEGY_FEWESTCALLS, QUEUE_STRATEGY_LEASTRECENT, QUEUE_STRATEGY_RANDOM, QUEUE_STRATEGY_RINGALL, QUEUE_STRATEGY_ROUNDROBIN, member::ringcount, call_queue::ringlimit, call_queue::rrpos, call_queue::strategy, and call_queue::wrapped.
Referenced by try_calling().
02509 { 02510 if (qe->max_penalty && (mem->penalty > qe->max_penalty)) 02511 return -1; 02512 02513 switch (q->strategy) { 02514 case QUEUE_STRATEGY_RINGALL: 02515 /* Everyone equal, except for penalty */ 02516 tmp->metric = mem->penalty * 1000000; 02517 break; 02518 case QUEUE_STRATEGY_ROUNDROBIN: 02519 if (!pos) { 02520 if (!q->wrapped) { 02521 /* No more channels, start over */ 02522 q->rrpos = 0; 02523 } else { 02524 /* Prioritize next entry */ 02525 q->rrpos++; 02526 } 02527 q->wrapped = 0; 02528 } 02529 /* Fall through */ 02530 case QUEUE_STRATEGY_RRMEMORY: 02531 if (pos < q->rrpos) { 02532 tmp->metric = 1000 + pos; 02533 } else { 02534 if (pos > q->rrpos) 02535 /* Indicate there is another priority */ 02536 q->wrapped = 1; 02537 tmp->metric = pos; 02538 } 02539 tmp->metric += mem->penalty * 1000000; 02540 break; 02541 case QUEUE_STRATEGY_RANDOM: 02542 tmp->metric = ast_random() % 1000; 02543 tmp->metric += mem->penalty * 1000000; 02544 break; 02545 case QUEUE_STRATEGY_FEWESTCALLS: 02546 tmp->metric = mem->calls; 02547 tmp->metric += mem->penalty * 1000000; 02548 break; 02549 case QUEUE_STRATEGY_LEASTRECENT: 02550 if (!mem->lastcall) 02551 tmp->metric = 0; 02552 else 02553 tmp->metric = 1000000 - (time(NULL) - mem->lastcall); 02554 tmp->metric += mem->penalty * 1000000; 02555 break; 02556 default: 02557 ast_log(LOG_WARNING, "Can't calculate metric for unknown strategy %d\n", q->strategy); 02558 break; 02559 } 02560 if (q->ringlimit && (mem->ringcount >= q->ringlimit)) { 02561 tmp->metric += (mem->ringcount / q->ringlimit) * 10000000; 02562 } 02563 if (option_debug) 02564 ast_log(LOG_DEBUG, "New metric %d for member %s with %d rings (limit %d)\n", 02565 tmp->metric, mem->interface, mem->ringcount, q->ringlimit); 02566 return 0; 02567 }
static void clear_and_free_interfaces | ( | void | ) | [static] |
Definition at line 943 of file app_queue.c.
References AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, and free.
Referenced by unload_module().
00944 { 00945 struct member_interface *curint; 00946 00947 AST_LIST_LOCK(&interfaces); 00948 while ((curint = AST_LIST_REMOVE_HEAD(&interfaces, list))) 00949 free(curint); 00950 AST_LIST_UNLOCK(&interfaces); 00951 }
static void clear_queue | ( | struct call_queue * | q | ) | [static] |
Definition at line 860 of file app_queue.c.
References call_queue::callsabandoned, call_queue::callscompleted, call_queue::callscompletedinsl, call_queue::holdtime, and call_queue::wrapuptime.
Referenced by find_queue_by_name_rt(), and reload_queues().
00861 { 00862 q->holdtime = 0; 00863 q->callscompleted = 0; 00864 q->callsabandoned = 0; 00865 q->callscompletedinsl = 0; 00866 q->wrapuptime = 0; 00867 }
static int compare_weight | ( | struct call_queue * | rq, | |
struct member * | member | |||
) | [static] |
Definition at line 1717 of file app_queue.c.
References ao2_find(), ao2_ref(), AST_LIST_TRAVERSE, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), call_queue::count, member::interface, call_queue::lock, LOG_DEBUG, call_queue::members, call_queue::name, and call_queue::weight.
Referenced by ring_entry().
01718 { 01719 struct call_queue *q; 01720 struct member *mem; 01721 int found = 0; 01722 01723 /* &qlock and &rq->lock already set by try_calling() 01724 * to solve deadlock */ 01725 AST_LIST_TRAVERSE(&queues, q, list) { 01726 if (q == rq) /* don't check myself, could deadlock */ 01727 continue; 01728 ast_mutex_lock(&q->lock); 01729 if (q->count && q->members) { 01730 if ((mem = ao2_find(q->members, member, OBJ_POINTER))) { 01731 ast_log(LOG_DEBUG, "Found matching member %s in queue '%s'\n", mem->interface, q->name); 01732 if (q->weight > rq->weight) { 01733 ast_log(LOG_DEBUG, "Queue '%s' (weight %d, calls %d) is preferred over '%s' (weight %d, calls %d)\n", q->name, q->weight, q->count, rq->name, rq->weight, rq->count); 01734 found = 1; 01735 } 01736 ao2_ref(mem, -1); 01737 } 01738 } 01739 ast_mutex_unlock(&q->lock); 01740 if (found) 01741 break; 01742 } 01743 return found; 01744 }
static char* complete_queue | ( | const char * | line, | |
const char * | word, | |||
int | pos, | |||
int | state | |||
) | [static] |
Definition at line 4552 of file app_queue.c.
References AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_strdup, and call_queue::name.
Referenced by complete_queue_add_member(), complete_queue_remove_member(), and complete_queue_show().
04553 { 04554 struct call_queue *q; 04555 char *ret = NULL; 04556 int which = 0; 04557 int wordlen = strlen(word); 04558 04559 AST_LIST_LOCK(&queues); 04560 AST_LIST_TRAVERSE(&queues, q, list) { 04561 if (!strncasecmp(word, q->name, wordlen) && ++which > state) { 04562 ret = ast_strdup(q->name); 04563 break; 04564 } 04565 } 04566 AST_LIST_UNLOCK(&queues); 04567 04568 return ret; 04569 }
static char* complete_queue_add_member | ( | const char * | line, | |
const char * | word, | |||
int | pos, | |||
int | state | |||
) | [static] |
Definition at line 4847 of file app_queue.c.
References ast_malloc, ast_strdup, and complete_queue().
04848 { 04849 /* 0 - queue; 1 - add; 2 - member; 3 - <interface>; 4 - to; 5 - <queue>; 6 - penalty; 7 - <penalty>; 8 - as; 9 - <membername> */ 04850 switch (pos) { 04851 case 3: /* Don't attempt to complete name of interface (infinite possibilities) */ 04852 return NULL; 04853 case 4: /* only one possible match, "to" */ 04854 return state == 0 ? ast_strdup("to") : NULL; 04855 case 5: /* <queue> */ 04856 return complete_queue(line, word, pos, state); 04857 case 6: /* only one possible match, "penalty" */ 04858 return state == 0 ? ast_strdup("penalty") : NULL; 04859 case 7: 04860 if (state < 100) { /* 0-99 */ 04861 char *num; 04862 if ((num = ast_malloc(3))) { 04863 sprintf(num, "%d", state); 04864 } 04865 return num; 04866 } else { 04867 return NULL; 04868 } 04869 case 8: /* only one possible match, "as" */ 04870 return state == 0 ? ast_strdup("as") : NULL; 04871 case 9: /* Don't attempt to complete name of member (infinite possibilities) */ 04872 return NULL; 04873 default: 04874 return NULL; 04875 } 04876 }
static char* complete_queue_remove_member | ( | const char * | line, | |
const char * | word, | |||
int | pos, | |||
int | state | |||
) | [static] |
Definition at line 4913 of file app_queue.c.
References ao2_iterator_init(), ao2_iterator_next(), ao2_ref(), AST_LIST_EMPTY, AST_LIST_TRAVERSE, ast_mutex_lock(), ast_mutex_unlock(), ast_strdup, complete_queue(), member::interface, call_queue::lock, and call_queue::members.
04914 { 04915 int which = 0; 04916 struct call_queue *q; 04917 struct member *m; 04918 struct ao2_iterator mem_iter; 04919 04920 /* 0 - queue; 1 - remove; 2 - member; 3 - <member>; 4 - from; 5 - <queue> */ 04921 if (pos > 5 || pos < 3) 04922 return NULL; 04923 if (pos == 4) /* only one possible match, 'from' */ 04924 return state == 0 ? ast_strdup("from") : NULL; 04925 04926 if (pos == 5) /* No need to duplicate code */ 04927 return complete_queue(line, word, pos, state); 04928 04929 /* here is the case for 3, <member> */ 04930 if (!AST_LIST_EMPTY(&queues)) { /* XXX unnecessary ? the traverse does that for us */ 04931 AST_LIST_TRAVERSE(&queues, q, list) { 04932 ast_mutex_lock(&q->lock); 04933 mem_iter = ao2_iterator_init(q->members, 0); 04934 while ((m = ao2_iterator_next(&mem_iter))) { 04935 if (++which > state) { 04936 char *tmp; 04937 ast_mutex_unlock(&q->lock); 04938 tmp = ast_strdup(m->interface); 04939 ao2_ref(m, -1); 04940 return tmp; 04941 } 04942 ao2_ref(m, -1); 04943 } 04944 ast_mutex_unlock(&q->lock); 04945 } 04946 } 04947 04948 return NULL; 04949 }
static char* complete_queue_show | ( | const char * | line, | |
const char * | word, | |||
int | pos, | |||
int | state | |||
) | [static] |
Definition at line 4571 of file app_queue.c.
References complete_queue().
04572 { 04573 if (pos == 2) 04574 return complete_queue(line, word, pos, state); 04575 return NULL; 04576 }
static int compress_char | ( | const char | c | ) | [static] |
static struct member* create_queue_member | ( | const char * | interface, | |
const char * | membername, | |||
int | penalty, | |||
int | paused | |||
) | [static] |
allocate space for new queue member and set fields based on parameters passed
Definition at line 750 of file app_queue.c.
References ao2_alloc(), ast_device_state(), ast_log(), ast_strlen_zero(), LOG_WARNING, and member::penalty.
Referenced by add_to_queue(), reload_queues(), and rt_handle_member_record().
00751 { 00752 struct member *cur; 00753 00754 if ((cur = ao2_alloc(sizeof(*cur), NULL))) { 00755 cur->penalty = penalty; 00756 cur->paused = paused; 00757 ast_copy_string(cur->interface, interface, sizeof(cur->interface)); 00758 if (!ast_strlen_zero(membername)) 00759 ast_copy_string(cur->membername, membername, sizeof(cur->membername)); 00760 else 00761 ast_copy_string(cur->membername, interface, sizeof(cur->membername)); 00762 if (!strchr(cur->interface, '/')) 00763 ast_log(LOG_WARNING, "No location at interface '%s'\n", interface); 00764 cur->status = ast_device_state(interface); 00765 } 00766 00767 return cur; 00768 }
static void destroy_queue | ( | struct call_queue * | q | ) | [static] |
Definition at line 1170 of file app_queue.c.
References ao2_ref(), ast_mutex_destroy(), free, free_members(), call_queue::lock, and call_queue::members.
Referenced by find_queue_by_name_rt(), and leave_queue().
01171 { 01172 free_members(q, 1); 01173 ast_mutex_destroy(&q->lock); 01174 ao2_ref(q->members, -1); 01175 free(q); 01176 }
static void* device_state_thread | ( | void * | data | ) | [static] |
Consumer of the statechange queue.
Definition at line 698 of file app_queue.c.
References ast_cond_wait(), AST_LIST_REMOVE_HEAD, ast_mutex_lock(), ast_mutex_unlock(), device_state, free, and handle_statechange().
Referenced by load_module().
00699 { 00700 struct statechange *sc = NULL; 00701 00702 while (!device_state.stop) { 00703 ast_mutex_lock(&device_state.lock); 00704 if (!(sc = AST_LIST_REMOVE_HEAD(&device_state.state_change_q, entry))) { 00705 ast_cond_wait(&device_state.cond, &device_state.lock); 00706 sc = AST_LIST_REMOVE_HEAD(&device_state.state_change_q, entry); 00707 } 00708 ast_mutex_unlock(&device_state.lock); 00709 00710 /* Check to see if we were woken up to see the request to stop */ 00711 if (device_state.stop) 00712 break; 00713 00714 if (!sc) 00715 continue; 00716 00717 handle_statechange(sc); 00718 00719 free(sc); 00720 sc = NULL; 00721 } 00722 00723 if (sc) 00724 free(sc); 00725 00726 while ((sc = AST_LIST_REMOVE_HEAD(&device_state.state_change_q, entry))) 00727 free(sc); 00728 00729 return NULL; 00730 }
static void do_hang | ( | struct callattempt * | o | ) | [static] |
common hangup actions
Definition at line 1747 of file app_queue.c.
References ast_hangup(), callattempt::chan, and callattempt::stillgoing.
Referenced by ring_entry().
01748 { 01749 o->stillgoing = 0; 01750 ast_hangup(o->chan); 01751 o->chan = NULL; 01752 }
static void dump_queue_members | ( | struct call_queue * | pm_queue | ) | [static] |
Definition at line 3149 of file app_queue.c.
References ao2_iterator_init(), ao2_iterator_next(), ao2_ref(), ast_db_del(), ast_db_put(), ast_log(), member::dynamic, member::interface, LOG_WARNING, member::membername, call_queue::members, call_queue::name, member::paused, member::penalty, and PM_MAX_LEN.
Referenced by add_to_queue(), remove_from_queue(), and set_member_paused().
03150 { 03151 struct member *cur_member; 03152 char value[PM_MAX_LEN]; 03153 int value_len = 0; 03154 int res; 03155 struct ao2_iterator mem_iter; 03156 03157 memset(value, 0, sizeof(value)); 03158 03159 if (!pm_queue) 03160 return; 03161 03162 mem_iter = ao2_iterator_init(pm_queue->members, 0); 03163 while ((cur_member = ao2_iterator_next(&mem_iter))) { 03164 if (!cur_member->dynamic) { 03165 ao2_ref(cur_member, -1); 03166 continue; 03167 } 03168 03169 res = snprintf(value + value_len, sizeof(value) - value_len, "%s%s;%d;%d;%s", 03170 value_len ? "|" : "", cur_member->interface, cur_member->penalty, cur_member->paused, cur_member->membername); 03171 03172 ao2_ref(cur_member, -1); 03173 03174 if (res != strlen(value + value_len)) { 03175 ast_log(LOG_WARNING, "Could not create persistent member string, out of space\n"); 03176 break; 03177 } 03178 value_len += res; 03179 } 03180 03181 if (value_len && !cur_member) { 03182 if (ast_db_put(pm_family, pm_queue->name, value)) 03183 ast_log(LOG_WARNING, "failed to create persistent dynamic entry!\n"); 03184 } else 03185 /* Delete the entry if the queue is empty or there is an error */ 03186 ast_db_del(pm_family, pm_queue->name); 03187 }
static struct callattempt* find_best | ( | struct callattempt * | outgoing | ) | [static] |
find the entry with the best metric, or NULL
Definition at line 1936 of file app_queue.c.
References callattempt::metric, and callattempt::q_next.
01937 { 01938 struct callattempt *best = NULL, *cur; 01939 01940 for (cur = outgoing; cur; cur = cur->q_next) { 01941 if (cur->stillgoing && /* Not already done */ 01942 !cur->chan && /* Isn't already going */ 01943 (!best || cur->metric < best->metric)) { /* We haven't found one yet, or it's better */ 01944 best = cur; 01945 } 01946 } 01947 01948 return best; 01949 }
static struct call_queue* find_queue_by_name_rt | ( | const char * | queuename, | |
struct ast_variable * | queue_vars, | |||
struct ast_config * | member_config | |||
) | [static] |
Reload a single queue via realtime.
Definition at line 1181 of file app_queue.c.
References alloc_queue(), AST_LIST_INSERT_HEAD, AST_LIST_REMOVE, AST_LIST_TRAVERSE, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_strlen_zero(), clear_queue(), call_queue::dead, destroy_queue(), init_queue(), member_interface::interface, call_queue::lock, LOG_DEBUG, LOG_WARNING, ast_variable::name, call_queue::name, ast_variable::next, queue_set_param(), call_queue::realtime, and ast_variable::value.
Referenced by load_realtime_queue().
01182 { 01183 struct ast_variable *v; 01184 struct call_queue *q; 01185 struct member *m; 01186 struct ao2_iterator mem_iter; 01187 char *interface = NULL; 01188 char *tmp, *tmp_name; 01189 char tmpbuf[64]; /* Must be longer than the longest queue param name. */ 01190 01191 /* Find the queue in the in-core list (we will create a new one if not found). */ 01192 AST_LIST_TRAVERSE(&queues, q, list) { 01193 if (!strcasecmp(q->name, queuename)) 01194 break; 01195 } 01196 01197 /* Static queues override realtime. */ 01198 if (q) { 01199 ast_mutex_lock(&q->lock); 01200 if (!q->realtime) { 01201 if (q->dead) { 01202 ast_mutex_unlock(&q->lock); 01203 return NULL; 01204 } else { 01205 ast_log(LOG_WARNING, "Static queue '%s' already exists. Not loading from realtime\n", q->name); 01206 ast_mutex_unlock(&q->lock); 01207 return q; 01208 } 01209 } 01210 } else if (!member_config) 01211 /* Not found in the list, and it's not realtime ... */ 01212 return NULL; 01213 01214 /* Check if queue is defined in realtime. */ 01215 if (!queue_vars) { 01216 /* Delete queue from in-core list if it has been deleted in realtime. */ 01217 if (q) { 01218 /*! \note Hmm, can't seem to distinguish a DB failure from a not 01219 found condition... So we might delete an in-core queue 01220 in case of DB failure. */ 01221 ast_log(LOG_DEBUG, "Queue %s not found in realtime.\n", queuename); 01222 01223 q->dead = 1; 01224 /* Delete if unused (else will be deleted when last caller leaves). */ 01225 if (!q->count) { 01226 /* Delete. */ 01227 AST_LIST_REMOVE(&queues, q, list); 01228 ast_mutex_unlock(&q->lock); 01229 destroy_queue(q); 01230 } else 01231 ast_mutex_unlock(&q->lock); 01232 } 01233 return NULL; 01234 } 01235 01236 /* Create a new queue if an in-core entry does not exist yet. */ 01237 if (!q) { 01238 if (!(q = alloc_queue(queuename))) 01239 return NULL; 01240 ast_mutex_lock(&q->lock); 01241 clear_queue(q); 01242 q->realtime = 1; 01243 init_queue(q); /* Ensure defaults for all parameters not set explicitly. */ 01244 AST_LIST_INSERT_HEAD(&queues, q, list); 01245 } 01246 01247 memset(tmpbuf, 0, sizeof(tmpbuf)); 01248 for (v = queue_vars; v; v = v->next) { 01249 /* Convert to dashes `-' from underscores `_' as the latter are more SQL friendly. */ 01250 if ((tmp = strchr(v->name, '_'))) { 01251 ast_copy_string(tmpbuf, v->name, sizeof(tmpbuf)); 01252 tmp_name = tmpbuf; 01253 tmp = tmp_name; 01254 while ((tmp = strchr(tmp, '_'))) 01255 *tmp++ = '-'; 01256 } else 01257 tmp_name = v->name; 01258 01259 if (!ast_strlen_zero(v->value)) { 01260 /* Don't want to try to set the option if the value is empty */ 01261 queue_set_param(q, tmp_name, v->value, -1, 0); 01262 } 01263 } 01264 01265 if (q->strategy == QUEUE_STRATEGY_ROUNDROBIN) 01266 rr_dep_warning(); 01267 01268 /* Temporarily set realtime members dead so we can detect deleted ones. 01269 * Also set the membercount correctly for realtime*/ 01270 mem_iter = ao2_iterator_init(q->members, 0); 01271 while ((m = ao2_iterator_next(&mem_iter))) { 01272 q->membercount++; 01273 if (m->realtime) 01274 m->dead = 1; 01275 ao2_ref(m, -1); 01276 } 01277 01278 while ((interface = ast_category_browse(member_config, interface))) { 01279 rt_handle_member_record(q, interface, 01280 ast_variable_retrieve(member_config, interface, "membername"), 01281 ast_variable_retrieve(member_config, interface, "penalty"), 01282 ast_variable_retrieve(member_config, interface, "paused")); 01283 } 01284 01285 /* Delete all realtime members that have been deleted in DB. */ 01286 mem_iter = ao2_iterator_init(q->members, 0); 01287 while ((m = ao2_iterator_next(&mem_iter))) { 01288 if (m->dead) { 01289 ao2_unlink(q->members, m); 01290 ast_mutex_unlock(&q->lock); 01291 remove_from_interfaces(m->interface); 01292 ast_mutex_lock(&q->lock); 01293 q->membercount--; 01294 } 01295 ao2_ref(m, -1); 01296 } 01297 01298 ast_mutex_unlock(&q->lock); 01299 01300 return q; 01301 }
static void free_members | ( | struct call_queue * | q, | |
int | all | |||
) | [static] |
Definition at line 1154 of file app_queue.c.
References ao2_iterator_init(), ao2_iterator_next(), ao2_ref(), ao2_unlink(), member::dynamic, member::interface, call_queue::membercount, call_queue::members, and remove_from_interfaces().
Referenced by destroy_queue().
01155 { 01156 /* Free non-dynamic members */ 01157 struct member *cur; 01158 struct ao2_iterator mem_iter = ao2_iterator_init(q->members, 0); 01159 01160 while ((cur = ao2_iterator_next(&mem_iter))) { 01161 if (all || !cur->dynamic) { 01162 ao2_unlink(q->members, cur); 01163 remove_from_interfaces(cur->interface); 01164 q->membercount--; 01165 } 01166 ao2_ref(cur, -1); 01167 } 01168 }
static enum queue_member_status get_member_status | ( | struct call_queue * | q, | |
int | max_penalty | |||
) | [static] |
Check if members are available.
This function checks to see if members are available to be called. If any member is available, the function immediately returns QUEUE_NORMAL. If no members are available, the appropriate reason why is returned
Definition at line 539 of file app_queue.c.
References ao2_iterator_init(), ao2_iterator_next(), ao2_ref(), AST_DEVICE_INVALID, AST_DEVICE_UNAVAILABLE, ast_mutex_lock(), ast_mutex_unlock(), call_queue::lock, call_queue::members, member::paused, member::penalty, QUEUE_NO_MEMBERS, QUEUE_NO_REACHABLE_MEMBERS, QUEUE_NORMAL, and member::status.
Referenced by join_queue(), queue_exec(), and wait_our_turn().
00540 { 00541 struct member *member; 00542 struct ao2_iterator mem_iter; 00543 enum queue_member_status result = QUEUE_NO_MEMBERS; 00544 00545 ast_mutex_lock(&q->lock); 00546 mem_iter = ao2_iterator_init(q->members, 0); 00547 while ((member = ao2_iterator_next(&mem_iter))) { 00548 if (max_penalty && (member->penalty > max_penalty)) { 00549 ao2_ref(member, -1); 00550 continue; 00551 } 00552 00553 if (member->paused) { 00554 ao2_ref(member, -1); 00555 continue; 00556 } 00557 00558 switch (member->status) { 00559 case AST_DEVICE_INVALID: 00560 /* nothing to do */ 00561 ao2_ref(member, -1); 00562 break; 00563 case AST_DEVICE_UNAVAILABLE: 00564 result = QUEUE_NO_REACHABLE_MEMBERS; 00565 ao2_ref(member, -1); 00566 break; 00567 default: 00568 ast_mutex_unlock(&q->lock); 00569 ao2_ref(member, -1); 00570 return QUEUE_NORMAL; 00571 } 00572 } 00573 00574 ast_mutex_unlock(&q->lock); 00575 return result; 00576 }
static int handle_queue_add_member | ( | int | fd, | |
int | argc, | |||
char * | argv[] | |||
) | [static] |
Definition at line 4793 of file app_queue.c.
References add_to_queue(), ast_cli(), ast_queue_log(), RES_EXISTS, RES_NOSUCHQUEUE, RES_OKAY, RES_OUTOFMEMORY, RESULT_FAILURE, RESULT_SHOWUSAGE, and RESULT_SUCCESS.
04794 { 04795 char *queuename, *interface, *membername = NULL; 04796 int penalty; 04797 04798 if ((argc != 6) && (argc != 8) && (argc != 10)) { 04799 return RESULT_SHOWUSAGE; 04800 } else if (strcmp(argv[4], "to")) { 04801 return RESULT_SHOWUSAGE; 04802 } else if ((argc == 8) && strcmp(argv[6], "penalty")) { 04803 return RESULT_SHOWUSAGE; 04804 } else if ((argc == 10) && strcmp(argv[8], "as")) { 04805 return RESULT_SHOWUSAGE; 04806 } 04807 04808 queuename = argv[5]; 04809 interface = argv[3]; 04810 if (argc >= 8) { 04811 if (sscanf(argv[7], "%d", &penalty) == 1) { 04812 if (penalty < 0) { 04813 ast_cli(fd, "Penalty must be >= 0\n"); 04814 penalty = 0; 04815 } 04816 } else { 04817 ast_cli(fd, "Penalty must be an integer >= 0\n"); 04818 penalty = 0; 04819 } 04820 } else { 04821 penalty = 0; 04822 } 04823 04824 if (argc >= 10) { 04825 membername = argv[9]; 04826 } 04827 04828 switch (add_to_queue(queuename, interface, membername, penalty, 0, queue_persistent_members)) { 04829 case RES_OKAY: 04830 ast_queue_log(queuename, "CLI", interface, "ADDMEMBER", "%s", ""); 04831 ast_cli(fd, "Added interface '%s' to queue '%s'\n", interface, queuename); 04832 return RESULT_SUCCESS; 04833 case RES_EXISTS: 04834 ast_cli(fd, "Unable to add interface '%s' to queue '%s': Already there\n", interface, queuename); 04835 return RESULT_FAILURE; 04836 case RES_NOSUCHQUEUE: 04837 ast_cli(fd, "Unable to add interface to queue '%s': No such queue\n", queuename); 04838 return RESULT_FAILURE; 04839 case RES_OUTOFMEMORY: 04840 ast_cli(fd, "Out of memory\n"); 04841 return RESULT_FAILURE; 04842 default: 04843 return RESULT_FAILURE; 04844 } 04845 }
static int handle_queue_remove_member | ( | int | fd, | |
int | argc, | |||
char * | argv[] | |||
) | [static] |
Definition at line 4878 of file app_queue.c.
References ast_cli(), ast_queue_log(), remove_from_queue(), RES_EXISTS, RES_NOSUCHQUEUE, RES_NOT_DYNAMIC, RES_OKAY, RES_OUTOFMEMORY, RESULT_FAILURE, RESULT_SHOWUSAGE, and RESULT_SUCCESS.
04879 { 04880 char *queuename, *interface; 04881 04882 if (argc != 6) { 04883 return RESULT_SHOWUSAGE; 04884 } else if (strcmp(argv[4], "from")) { 04885 return RESULT_SHOWUSAGE; 04886 } 04887 04888 queuename = argv[5]; 04889 interface = argv[3]; 04890 04891 switch (remove_from_queue(queuename, interface)) { 04892 case RES_OKAY: 04893 ast_queue_log(queuename, "CLI", interface, "REMOVEMEMBER", "%s", ""); 04894 ast_cli(fd, "Removed interface '%s' from queue '%s'\n", interface, queuename); 04895 return RESULT_SUCCESS; 04896 case RES_EXISTS: 04897 ast_cli(fd, "Unable to remove interface '%s' from queue '%s': Not there\n", interface, queuename); 04898 return RESULT_FAILURE; 04899 case RES_NOSUCHQUEUE: 04900 ast_cli(fd, "Unable to remove interface from queue '%s': No such queue\n", queuename); 04901 return RESULT_FAILURE; 04902 case RES_OUTOFMEMORY: 04903 ast_cli(fd, "Out of memory\n"); 04904 return RESULT_FAILURE; 04905 case RES_NOT_DYNAMIC: 04906 ast_cli(fd, "Member not dynamic\n"); 04907 return RESULT_FAILURE; 04908 default: 04909 return RESULT_FAILURE; 04910 } 04911 }
static void* handle_statechange | ( | struct statechange * | sc | ) | [static] |
set a member's status based on device state of that member's interface
Definition at line 637 of file app_queue.c.
References AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_strdupa, devstate2str(), member_interface::interface, LOG_DEBUG, option_debug, and update_status().
Referenced by device_state_thread().
00638 { 00639 struct member_interface *curint; 00640 char *loc; 00641 char *technology; 00642 00643 technology = ast_strdupa(sc->dev); 00644 loc = strchr(technology, '/'); 00645 if (loc) { 00646 *loc++ = '\0'; 00647 } else { 00648 return NULL; 00649 } 00650 00651 AST_LIST_LOCK(&interfaces); 00652 AST_LIST_TRAVERSE(&interfaces, curint, list) { 00653 char *interface; 00654 char *slash_pos; 00655 interface = ast_strdupa(curint->interface); 00656 if ((slash_pos = strchr(interface, '/'))) 00657 if ((slash_pos = strchr(slash_pos + 1, '/'))) 00658 *slash_pos = '\0'; 00659 00660 if (!strcasecmp(interface, sc->dev)) 00661 break; 00662 } 00663 AST_LIST_UNLOCK(&interfaces); 00664 00665 if (!curint) { 00666 if (option_debug > 2) 00667 ast_log(LOG_DEBUG, "Device '%s/%s' changed to state '%d' (%s) but we don't care because they're not a member of any queue.\n", technology, loc, sc->state, devstate2str(sc->state)); 00668 return NULL; 00669 } 00670 00671 if (option_debug) 00672 ast_log(LOG_DEBUG, "Device '%s/%s' changed to state '%d' (%s)\n", technology, loc, sc->state, devstate2str(sc->state)); 00673 00674 update_status(sc->dev, sc->state); 00675 00676 return NULL; 00677 }
static void hangupcalls | ( | struct callattempt * | outgoing, | |
struct ast_channel * | exception | |||
) | [static] |
Definition at line 1698 of file app_queue.c.
References ao2_ref(), ast_hangup(), callattempt::chan, free, callattempt::member, and callattempt::q_next.
Referenced by try_calling().
01699 { 01700 struct callattempt *oo; 01701 01702 while (outgoing) { 01703 /* Hangup any existing lines we have open */ 01704 if (outgoing->chan && (outgoing->chan != exception)) 01705 ast_hangup(outgoing->chan); 01706 oo = outgoing; 01707 outgoing = outgoing->q_next; 01708 if (oo->member) 01709 ao2_ref(oo->member, -1); 01710 free(oo); 01711 } 01712 }
static void init_queue | ( | struct call_queue * | q | ) | [static] |
Definition at line 809 of file app_queue.c.
References call_queue::announce, call_queue::announcefrequency, call_queue::announceholdtime, ao2_container_alloc(), call_queue::autofill, call_queue::context, call_queue::dead, DEFAULT_RETRY, call_queue::eventwhencalled, call_queue::found, call_queue::joinempty, call_queue::leavewhenempty, call_queue::maskmemberstatus, MAX_PERIODIC_ANNOUNCEMENTS, call_queue::maxlen, member_cmp_fn(), member_hash_fn(), call_queue::membercount, call_queue::memberdelay, call_queue::members, call_queue::moh, call_queue::monfmt, call_queue::monjoin, call_queue::montype, call_queue::periodicannouncefrequency, call_queue::reportholdtime, call_queue::retry, call_queue::ringinuse, call_queue::ringlimit, call_queue::roundingseconds, call_queue::servicelevel, call_queue::setinterfacevar, call_queue::sound_calls, call_queue::sound_holdtime, call_queue::sound_lessthan, call_queue::sound_minutes, call_queue::sound_next, call_queue::sound_periodicannounce, call_queue::sound_reporthold, call_queue::sound_seconds, call_queue::sound_thanks, call_queue::sound_thereare, call_queue::timeout, call_queue::timeoutrestart, call_queue::weight, and call_queue::wrapuptime.
Referenced by find_queue_by_name_rt(), and reload_queues().
00810 { 00811 int i; 00812 00813 q->dead = 0; 00814 q->retry = DEFAULT_RETRY; 00815 q->timeout = -1; 00816 q->maxlen = 0; 00817 q->ringlimit = 0; 00818 q->announcefrequency = 0; 00819 q->announceholdtime = 0; 00820 q->roundingseconds = 0; /* Default - don't announce seconds */ 00821 q->servicelevel = 0; 00822 q->ringinuse = 1; 00823 q->setinterfacevar = 0; 00824 q->autofill = autofill_default; 00825 q->montype = montype_default; 00826 q->moh[0] = '\0'; 00827 q->announce[0] = '\0'; 00828 q->context[0] = '\0'; 00829 q->monfmt[0] = '\0'; 00830 q->periodicannouncefrequency = 0; 00831 q->reportholdtime = 0; 00832 q->monjoin = 0; 00833 q->wrapuptime = 0; 00834 q->joinempty = 0; 00835 q->leavewhenempty = 0; 00836 q->memberdelay = 0; 00837 q->maskmemberstatus = 0; 00838 q->eventwhencalled = 0; 00839 q->weight = 0; 00840 q->timeoutrestart = 0; 00841 if (!q->members) 00842 q->members = ao2_container_alloc(37, member_hash_fn, member_cmp_fn); 00843 q->membercount = 0; 00844 q->found = 1; 00845 ast_copy_string(q->sound_next, "queue-youarenext", sizeof(q->sound_next)); 00846 ast_copy_string(q->sound_thereare, "queue-thereare", sizeof(q->sound_thereare)); 00847 ast_copy_string(q->sound_calls, "queue-callswaiting", sizeof(q->sound_calls)); 00848 ast_copy_string(q->sound_holdtime, "queue-holdtime", sizeof(q->sound_holdtime)); 00849 ast_copy_string(q->sound_minutes, "queue-minutes", sizeof(q->sound_minutes)); 00850 ast_copy_string(q->sound_seconds, "queue-seconds", sizeof(q->sound_seconds)); 00851 ast_copy_string(q->sound_thanks, "queue-thankyou", sizeof(q->sound_thanks)); 00852 ast_copy_string(q->sound_lessthan, "queue-less-than", sizeof(q->sound_lessthan)); 00853 ast_copy_string(q->sound_reporthold, "queue-reporthold", sizeof(q->sound_reporthold)); 00854 ast_copy_string(q->sound_periodicannounce[0], "queue-periodic-announce", sizeof(q->sound_periodicannounce[0])); 00855 for (i = 1; i < MAX_PERIODIC_ANNOUNCEMENTS; i++) { 00856 q->sound_periodicannounce[i][0]='\0'; 00857 } 00858 }
static void insert_entry | ( | struct call_queue * | q, | |
struct queue_ent * | prev, | |||
struct queue_ent * | new, | |||
int * | pos | |||
) | [inline, static] |
Insert the 'new' entry after the 'prev' entry of queue 'q'.
Definition at line 508 of file app_queue.c.
References call_queue::head, queue_ent::next, and queue_ent::parent.
Referenced by join_queue().
00509 { 00510 struct queue_ent *cur; 00511 00512 if (!q || !new) 00513 return; 00514 if (prev) { 00515 cur = prev->next; 00516 prev->next = new; 00517 } else { 00518 cur = q->head; 00519 q->head = new; 00520 } 00521 new->next = cur; 00522 new->parent = q; 00523 new->pos = ++(*pos); 00524 new->opos = *pos; 00525 }
static char* int2strat | ( | int | strategy | ) | [static] |
Definition at line 483 of file app_queue.c.
References name, and strategies.
Referenced by __queues_show().
00484 { 00485 int x; 00486 00487 for (x = 0; x < sizeof(strategies) / sizeof(strategies[0]); x++) { 00488 if (strategy == strategies[x].strategy) 00489 return strategies[x].name; 00490 } 00491 00492 return "<unknown>"; 00493 }
static struct member* interface_exists | ( | struct call_queue * | q, | |
const char * | interface | |||
) | [static] |
Definition at line 3125 of file app_queue.c.
References ao2_iterator_init(), ao2_iterator_next(), ao2_ref(), member::interface, and call_queue::members.
Referenced by add_to_queue(), and set_member_paused().
03126 { 03127 struct member *mem; 03128 struct ao2_iterator mem_iter; 03129 03130 if (!q) 03131 return NULL; 03132 03133 mem_iter = ao2_iterator_init(q->members, 0); 03134 while ((mem = ao2_iterator_next(&mem_iter))) { 03135 if (!strcasecmp(interface, mem->interface)) 03136 return mem; 03137 ao2_ref(mem, -1); 03138 } 03139 03140 return NULL; 03141 }
static int interface_exists_global | ( | const char * | interface | ) | [static] |
Definition at line 896 of file app_queue.c.
References ao2_find(), ao2_ref(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_mutex_lock(), ast_mutex_unlock(), member::interface, call_queue::lock, and call_queue::members.
Referenced by remove_from_interfaces().
00897 { 00898 struct call_queue *q; 00899 struct member *mem, tmpmem; 00900 int ret = 0; 00901 00902 ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface)); 00903 00904 AST_LIST_LOCK(&queues); 00905 AST_LIST_TRAVERSE(&queues, q, list) { 00906 ast_mutex_lock(&q->lock); 00907 if ((mem = ao2_find(q->members, &tmpmem, OBJ_POINTER))) { 00908 ao2_ref(mem, -1); 00909 ret = 1; 00910 } 00911 ast_mutex_unlock(&q->lock); 00912 if (ret) 00913 break; 00914 } 00915 AST_LIST_UNLOCK(&queues); 00916 00917 return ret; 00918 }
static int is_our_turn | ( | struct queue_ent * | qe | ) | [static] |
Check if we should start attempting to call queue members.
The behavior of this function is dependent first on whether autofill is enabled and second on whether the ring strategy is ringall. If autofill is not enabled, then return true if we're the head of the queue. If autofill is enabled, then we count the available members and see if the number of available members is enough that given our position in the queue, we would theoretically be able to connect to one of those available members
Definition at line 2348 of file app_queue.c.
References ao2_iterator_init(), ao2_iterator_next(), ao2_ref(), AST_DEVICE_INUSE, AST_DEVICE_NOT_INUSE, AST_DEVICE_UNKNOWN, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), call_queue::autofill, queue_ent::chan, call_queue::head, call_queue::lock, LOG_DEBUG, call_queue::members, queue_ent::next, option_debug, queue_ent::parent, member::paused, queue_ent::pending, QUEUE_STRATEGY_RINGALL, call_queue::ringinuse, member::status, and call_queue::strategy.
Referenced by queue_exec(), and wait_our_turn().
02349 { 02350 struct queue_ent *ch; 02351 struct member *cur; 02352 int avl = 0; 02353 int idx = 0; 02354 int res; 02355 02356 if (!qe->parent->autofill) { 02357 /* Atomically read the parent head -- does not need a lock */ 02358 ch = qe->parent->head; 02359 /* If we are now at the top of the head, break out */ 02360 if (ch == qe) { 02361 if (option_debug) 02362 ast_log(LOG_DEBUG, "It's our turn (%s).\n", qe->chan->name); 02363 res = 1; 02364 } else { 02365 if (option_debug) 02366 ast_log(LOG_DEBUG, "It's not our turn (%s).\n", qe->chan->name); 02367 res = 0; 02368 } 02369 02370 } else { 02371 /* This needs a lock. How many members are available to be served? */ 02372 ast_mutex_lock(&qe->parent->lock); 02373 02374 ch = qe->parent->head; 02375 02376 if (qe->parent->strategy == QUEUE_STRATEGY_RINGALL) { 02377 if (option_debug) 02378 ast_log(LOG_DEBUG, "Even though there may be multiple members available, the strategy is ringall so only the head call is allowed in\n"); 02379 avl = 1; 02380 } else { 02381 struct ao2_iterator mem_iter = ao2_iterator_init(qe->parent->members, 0); 02382 while ((cur = ao2_iterator_next(&mem_iter))) { 02383 switch (cur->status) { 02384 case AST_DEVICE_INUSE: 02385 if (!qe->parent->ringinuse) 02386 break; 02387 /* else fall through */ 02388 case AST_DEVICE_NOT_INUSE: 02389 case AST_DEVICE_UNKNOWN: 02390 if (!cur->paused) 02391 avl++; 02392 break; 02393 } 02394 ao2_ref(cur, -1); 02395 } 02396 } 02397 02398 if (option_debug) 02399 ast_log(LOG_DEBUG, "There are %d available members.\n", avl); 02400 02401 while ((idx < avl) && (ch) && (ch != qe)) { 02402 if (!ch->pending) 02403 idx++; 02404 ch = ch->next; 02405 } 02406 02407 /* If the queue entry is within avl [the number of available members] calls from the top ... */ 02408 if (ch && idx < avl) { 02409 if (option_debug) 02410 ast_log(LOG_DEBUG, "It's our turn (%s).\n", qe->chan->name); 02411 res = 1; 02412 } else { 02413 if (option_debug) 02414 ast_log(LOG_DEBUG, "It's not our turn (%s).\n", qe->chan->name); 02415 res = 0; 02416 } 02417 02418 ast_mutex_unlock(&qe->parent->lock); 02419 } 02420 02421 return res; 02422 }
static int join_queue | ( | char * | queuename, | |
struct queue_ent * | qe, | |||
enum queue_result * | reason | |||
) | [static] |
Definition at line 1419 of file app_queue.c.
References queue_ent::announce, AST_LIST_LOCK, AST_LIST_UNLOCK, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), queue_ent::chan, ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, queue_ent::context, call_queue::count, EVENT_FLAG_CALL, get_member_status(), call_queue::head, insert_entry(), call_queue::joinempty, load_realtime_queue(), call_queue::lock, LOG_DEBUG, manager_event(), queue_ent::max_penalty, call_queue::maxlen, queue_ent::moh, queue_ent::next, option_debug, queue_ent::pos, queue_ent::prio, QUEUE_EMPTY_STRICT, QUEUE_FULL, QUEUE_JOINEMPTY, QUEUE_JOINUNAVAIL, QUEUE_NO_MEMBERS, QUEUE_NO_REACHABLE_MEMBERS, and S_OR.
Referenced by queue_exec().
01420 { 01421 struct call_queue *q; 01422 struct queue_ent *cur, *prev = NULL; 01423 int res = -1; 01424 int pos = 0; 01425 int inserted = 0; 01426 enum queue_member_status stat; 01427 01428 if (!(q = load_realtime_queue(queuename))) 01429 return res; 01430 01431 AST_LIST_LOCK(&queues); 01432 ast_mutex_lock(&q->lock); 01433 01434 /* This is our one */ 01435 stat = get_member_status(q, qe->max_penalty); 01436 if (!q->joinempty && (stat == QUEUE_NO_MEMBERS)) 01437 *reason = QUEUE_JOINEMPTY; 01438 else if ((q->joinempty == QUEUE_EMPTY_STRICT) && (stat == QUEUE_NO_REACHABLE_MEMBERS || stat == QUEUE_NO_MEMBERS)) 01439 *reason = QUEUE_JOINUNAVAIL; 01440 else if (q->maxlen && (q->count >= q->maxlen)) 01441 *reason = QUEUE_FULL; 01442 else { 01443 /* There's space for us, put us at the right position inside 01444 * the queue. 01445 * Take into account the priority of the calling user */ 01446 inserted = 0; 01447 prev = NULL; 01448 cur = q->head; 01449 while (cur) { 01450 /* We have higher priority than the current user, enter 01451 * before him, after all the other users with priority 01452 * higher or equal to our priority. */ 01453 if ((!inserted) && (qe->prio > cur->prio)) { 01454 insert_entry(q, prev, qe, &pos); 01455 inserted = 1; 01456 } 01457 cur->pos = ++pos; 01458 prev = cur; 01459 cur = cur->next; 01460 } 01461 /* No luck, join at the end of the queue */ 01462 if (!inserted) 01463 insert_entry(q, prev, qe, &pos); 01464 ast_copy_string(qe->moh, q->moh, sizeof(qe->moh)); 01465 ast_copy_string(qe->announce, q->announce, sizeof(qe->announce)); 01466 ast_copy_string(qe->context, q->context, sizeof(qe->context)); 01467 q->count++; 01468 res = 0; 01469 manager_event(EVENT_FLAG_CALL, "Join", 01470 "Channel: %s\r\nCallerID: %s\r\nCallerIDName: %s\r\nQueue: %s\r\nPosition: %d\r\nCount: %d\r\nUniqueid: %s\r\n", 01471 qe->chan->name, 01472 S_OR(qe->chan->cid.cid_num, "unknown"), /* XXX somewhere else it is <unknown> */ 01473 S_OR(qe->chan->cid.cid_name, "unknown"), 01474 q->name, qe->pos, q->count, qe->chan->uniqueid ); 01475 if (option_debug) 01476 ast_log(LOG_DEBUG, "Queue '%s' Join, Channel '%s', Position '%d'\n", q->name, qe->chan->name, qe->pos ); 01477 } 01478 ast_mutex_unlock(&q->lock); 01479 AST_LIST_UNLOCK(&queues); 01480 01481 return res; 01482 }
static void leave_queue | ( | struct queue_ent * | qe | ) | [static] |
Definition at line 1654 of file app_queue.c.
References AST_LIST_LOCK, AST_LIST_REMOVE, AST_LIST_UNLOCK, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), queue_ent::chan, call_queue::count, call_queue::dead, destroy_queue(), EVENT_FLAG_CALL, call_queue::head, call_queue::lock, LOG_DEBUG, manager_event(), call_queue::name, queue_ent::next, option_debug, queue_ent::parent, and queue_ent::pos.
Referenced by queue_exec(), try_calling(), and wait_our_turn().
01655 { 01656 struct call_queue *q; 01657 struct queue_ent *cur, *prev = NULL; 01658 int pos = 0; 01659 01660 if (!(q = qe->parent)) 01661 return; 01662 ast_mutex_lock(&q->lock); 01663 01664 prev = NULL; 01665 for (cur = q->head; cur; cur = cur->next) { 01666 if (cur == qe) { 01667 q->count--; 01668 01669 /* Take us out of the queue */ 01670 manager_event(EVENT_FLAG_CALL, "Leave", 01671 "Channel: %s\r\nQueue: %s\r\nCount: %d\r\nUniqueid: %s\r\n", 01672 qe->chan->name, q->name, q->count, qe->chan->uniqueid); 01673 if (option_debug) 01674 ast_log(LOG_DEBUG, "Queue '%s' Leave, Channel '%s'\n", q->name, qe->chan->name ); 01675 /* Take us out of the queue */ 01676 if (prev) 01677 prev->next = cur->next; 01678 else 01679 q->head = cur->next; 01680 } else { 01681 /* Renumber the people after us in the queue based on a new count */ 01682 cur->pos = ++pos; 01683 prev = cur; 01684 } 01685 } 01686 ast_mutex_unlock(&q->lock); 01687 01688 if (q->dead && !q->count) { 01689 /* It's dead and nobody is in it, so kill it */ 01690 AST_LIST_LOCK(&queues); 01691 AST_LIST_REMOVE(&queues, q, list); 01692 AST_LIST_UNLOCK(&queues); 01693 destroy_queue(q); 01694 } 01695 }
static int load_module | ( | void | ) | [static] |
Definition at line 5033 of file app_queue.c.
References aqm_exec(), ast_cli_register_multiple(), ast_cond_init(), ast_custom_function_register(), ast_devstate_add(), ast_manager_register, AST_MODULE_LOAD_DECLINE, ast_mutex_init(), ast_pthread_create, ast_register_application(), cli_queue, device_state, device_state_thread(), EVENT_FLAG_AGENT, manager_add_queue_member(), manager_pause_queue_member(), manager_queues_show(), manager_queues_status(), manager_remove_queue_member(), pqm_exec(), ql_exec(), queue_exec(), queueagentcount_function, queuemembercount_function, queuememberlist_function, queuewaitingcount_function, reload_queue_members(), reload_queues(), rqm_exec(), statechange_queue(), and upqm_exec().
05034 { 05035 int res; 05036 05037 if (!reload_queues()) 05038 return AST_MODULE_LOAD_DECLINE; 05039 05040 if (queue_persistent_members) 05041 reload_queue_members(); 05042 05043 ast_mutex_init(&device_state.lock); 05044 ast_cond_init(&device_state.cond, NULL); 05045 ast_pthread_create(&device_state.thread, NULL, device_state_thread, NULL); 05046 05047 ast_cli_register_multiple(cli_queue, sizeof(cli_queue) / sizeof(struct ast_cli_entry)); 05048 res = ast_register_application(app, queue_exec, synopsis, descrip); 05049 res |= ast_register_application(app_aqm, aqm_exec, app_aqm_synopsis, app_aqm_descrip); 05050 res |= ast_register_application(app_rqm, rqm_exec, app_rqm_synopsis, app_rqm_descrip); 05051 res |= ast_register_application(app_pqm, pqm_exec, app_pqm_synopsis, app_pqm_descrip); 05052 res |= ast_register_application(app_upqm, upqm_exec, app_upqm_synopsis, app_upqm_descrip); 05053 res |= ast_register_application(app_ql, ql_exec, app_ql_synopsis, app_ql_descrip); 05054 res |= ast_manager_register("Queues", 0, manager_queues_show, "Queues"); 05055 res |= ast_manager_register("QueueStatus", 0, manager_queues_status, "Queue Status"); 05056 res |= ast_manager_register("QueueAdd", EVENT_FLAG_AGENT, manager_add_queue_member, "Add interface to queue."); 05057 res |= ast_manager_register("QueueRemove", EVENT_FLAG_AGENT, manager_remove_queue_member, "Remove interface from queue."); 05058 res |= ast_manager_register("QueuePause", EVENT_FLAG_AGENT, manager_pause_queue_member, "Makes a queue member temporarily unavailable"); 05059 res |= ast_custom_function_register(&queueagentcount_function); 05060 res |= ast_custom_function_register(&queuemembercount_function); 05061 res |= ast_custom_function_register(&queuememberlist_function); 05062 res |= ast_custom_function_register(&queuewaitingcount_function); 05063 res |= ast_devstate_add(statechange_queue, NULL); 05064 05065 return res; 05066 }
static struct call_queue* load_realtime_queue | ( | const char * | queuename | ) | [static] |
Definition at line 1369 of file app_queue.c.
References ast_config_destroy(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_load_realtime(), ast_load_realtime_multientry(), ast_log(), ast_variables_destroy(), find_queue_by_name_rt(), LOG_ERROR, call_queue::name, call_queue::realtime, and update_realtime_members().
Referenced by __queues_show(), add_to_queue(), join_queue(), queue_function_queuemembercount(), and reload_queue_members().
01370 { 01371 struct ast_variable *queue_vars; 01372 struct ast_config *member_config = NULL; 01373 struct call_queue *q; 01374 01375 /* Find the queue in the in-core list first. */ 01376 AST_LIST_LOCK(&queues); 01377 AST_LIST_TRAVERSE(&queues, q, list) { 01378 if (!strcasecmp(q->name, queuename)) { 01379 break; 01380 } 01381 } 01382 AST_LIST_UNLOCK(&queues); 01383 01384 if (!q || q->realtime) { 01385 /*! \note Load from realtime before taking the global qlock, to avoid blocking all 01386 queue operations while waiting for the DB. 01387 01388 This will be two separate database transactions, so we might 01389 see queue parameters as they were before another process 01390 changed the queue and member list as it was after the change. 01391 Thus we might see an empty member list when a queue is 01392 deleted. In practise, this is unlikely to cause a problem. */ 01393 01394 queue_vars = ast_load_realtime("queues", "name", queuename, NULL); 01395 if (queue_vars) { 01396 member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name", queuename, NULL); 01397 if (!member_config) { 01398 ast_log(LOG_ERROR, "no queue_members defined in your config (extconfig.conf).\n"); 01399 ast_variables_destroy(queue_vars); 01400 return NULL; 01401 } 01402 } 01403 01404 AST_LIST_LOCK(&queues); 01405 01406 q = find_queue_by_name_rt(queuename, queue_vars, member_config); 01407 if (member_config) 01408 ast_config_destroy(member_config); 01409 if (queue_vars) 01410 ast_variables_destroy(queue_vars); 01411 01412 AST_LIST_UNLOCK(&queues); 01413 } else { 01414 update_realtime_members(q); 01415 } 01416 return q; 01417 }
static int manager_add_queue_member | ( | struct mansession * | s, | |
const struct message * | m | |||
) | [static] |
Definition at line 4686 of file app_queue.c.
References add_to_queue(), ast_queue_log(), ast_strlen_zero(), ast_true(), astman_get_header(), astman_send_ack(), astman_send_error(), RES_EXISTS, RES_NOSUCHQUEUE, RES_OKAY, RES_OUTOFMEMORY, and s.
Referenced by load_module().
04687 { 04688 const char *queuename, *interface, *penalty_s, *paused_s, *membername; 04689 int paused, penalty = 0; 04690 04691 queuename = astman_get_header(m, "Queue"); 04692 interface = astman_get_header(m, "Interface"); 04693 penalty_s = astman_get_header(m, "Penalty"); 04694 paused_s = astman_get_header(m, "Paused"); 04695 membername = astman_get_header(m, "MemberName"); 04696 04697 if (ast_strlen_zero(queuename)) { 04698 astman_send_error(s, m, "'Queue' not specified."); 04699 return 0; 04700 } 04701 04702 if (ast_strlen_zero(interface)) { 04703 astman_send_error(s, m, "'Interface' not specified."); 04704 return 0; 04705 } 04706 04707 if (ast_strlen_zero(penalty_s)) 04708 penalty = 0; 04709 else if (sscanf(penalty_s, "%d", &penalty) != 1 || penalty < 0) 04710 penalty = 0; 04711 04712 if (ast_strlen_zero(paused_s)) 04713 paused = 0; 04714 else 04715 paused = abs(ast_true(paused_s)); 04716 04717 switch (add_to_queue(queuename, interface, membername, penalty, paused, queue_persistent_members)) { 04718 case RES_OKAY: 04719 ast_queue_log(queuename, "MANAGER", interface, "ADDMEMBER", "%s", ""); 04720 astman_send_ack(s, m, "Added interface to queue"); 04721 break; 04722 case RES_EXISTS: 04723 astman_send_error(s, m, "Unable to add interface: Already there"); 04724 break; 04725 case RES_NOSUCHQUEUE: 04726 astman_send_error(s, m, "Unable to add interface to queue: No such queue"); 04727 break; 04728 case RES_OUTOFMEMORY: 04729 astman_send_error(s, m, "Out of memory"); 04730 break; 04731 } 04732 04733 return 0; 04734 }
static int manager_pause_queue_member | ( | struct mansession * | s, | |
const struct message * | m | |||
) | [static] |
Definition at line 4770 of file app_queue.c.
References ast_strlen_zero(), ast_true(), astman_get_header(), astman_send_ack(), astman_send_error(), s, and set_member_paused().
Referenced by load_module().
04771 { 04772 const char *queuename, *interface, *paused_s; 04773 int paused; 04774 04775 interface = astman_get_header(m, "Interface"); 04776 paused_s = astman_get_header(m, "Paused"); 04777 queuename = astman_get_header(m, "Queue"); /* Optional - if not supplied, pause the given Interface in all queues */ 04778 04779 if (ast_strlen_zero(interface) || ast_strlen_zero(paused_s)) { 04780 astman_send_error(s, m, "Need 'Interface' and 'Paused' parameters."); 04781 return 0; 04782 } 04783 04784 paused = abs(ast_true(paused_s)); 04785 04786 if (set_member_paused(queuename, interface, paused)) 04787 astman_send_error(s, m, "Interface not found"); 04788 else 04789 astman_send_ack(s, m, paused ? "Interface paused successfully" : "Interface unpaused successfully"); 04790 return 0; 04791 }
static int manager_queues_show | ( | struct mansession * | s, | |
const struct message * | m | |||
) | [static] |
Definition at line 4581 of file app_queue.c.
References __queues_show(), astman_append(), RESULT_SUCCESS, and s.
Referenced by load_module().
04582 { 04583 char *a[] = { "queue", "show" }; 04584 04585 __queues_show(s, 1, -1, 2, a); 04586 astman_append(s, "\r\n\r\n"); /* Properly terminate Manager output */ 04587 04588 return RESULT_SUCCESS; 04589 }
static int manager_queues_status | ( | struct mansession * | s, | |
const struct message * | m | |||
) | [static] |
Definition at line 4592 of file app_queue.c.
References ao2_iterator_init(), ao2_iterator_next(), ao2_ref(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_mutex_lock(), ast_mutex_unlock(), ast_strlen_zero(), astman_append(), astman_get_header(), astman_send_ack(), member::calls, call_queue::callsabandoned, call_queue::callscompleted, call_queue::callscompletedinsl, queue_ent::chan, ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, call_queue::count, member::dynamic, call_queue::head, call_queue::holdtime, member::interface, member::lastcall, call_queue::lock, call_queue::maxlen, member::membername, call_queue::members, call_queue::name, queue_ent::next, member::paused, member::penalty, RESULT_SUCCESS, call_queue::ringlimit, s, S_OR, call_queue::servicelevel, queue_ent::start, member::status, and call_queue::weight.
Referenced by load_module().
04593 { 04594 time_t now; 04595 int pos; 04596 const char *id = astman_get_header(m,"ActionID"); 04597 const char *queuefilter = astman_get_header(m,"Queue"); 04598 const char *memberfilter = astman_get_header(m,"Member"); 04599 char idText[256] = ""; 04600 struct call_queue *q; 04601 struct queue_ent *qe; 04602 float sl = 0; 04603 struct member *mem; 04604 struct ao2_iterator mem_iter; 04605 04606 astman_send_ack(s, m, "Queue status will follow"); 04607 time(&now); 04608 AST_LIST_LOCK(&queues); 04609 if (!ast_strlen_zero(id)) 04610 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id); 04611 04612 AST_LIST_TRAVERSE(&queues, q, list) { 04613 ast_mutex_lock(&q->lock); 04614 04615 /* List queue properties */ 04616 if (ast_strlen_zero(queuefilter) || !strcmp(q->name, queuefilter)) { 04617 sl = ((q->callscompleted > 0) ? 100 * ((float)q->callscompletedinsl / (float)q->callscompleted) : 0); 04618 astman_append(s, "Event: QueueParams\r\n" 04619 "Queue: %s\r\n" 04620 "Max: %d\r\n" 04621 "Calls: %d\r\n" 04622 "Holdtime: %d\r\n" 04623 "Completed: %d\r\n" 04624 "Abandoned: %d\r\n" 04625 "ServiceLevel: %d\r\n" 04626 "ServicelevelPerf: %2.1f\r\n" 04627 "RingLimit: %d\r\n" 04628 "Weight: %d\r\n" 04629 "%s" 04630 "\r\n", 04631 q->name, q->maxlen, q->count, q->holdtime, q->callscompleted, 04632 q->callsabandoned, q->servicelevel, sl, q->ringlimit, q->weight, idText); 04633 /* List Queue Members */ 04634 mem_iter = ao2_iterator_init(q->members, 0); 04635 while ((mem = ao2_iterator_next(&mem_iter))) { 04636 if (ast_strlen_zero(memberfilter) || !strcmp(mem->interface, memberfilter)) { 04637 astman_append(s, "Event: QueueMember\r\n" 04638 "Queue: %s\r\n" 04639 "Name: %s\r\n" 04640 "Location: %s\r\n" 04641 "Membership: %s\r\n" 04642 "Penalty: %d\r\n" 04643 "CallsTaken: %d\r\n" 04644 "LastCall: %d\r\n" 04645 "Status: %d\r\n" 04646 "Paused: %d\r\n" 04647 "%s" 04648 "\r\n", 04649 q->name, mem->membername, mem->interface, mem->dynamic ? "dynamic" : "static", 04650 mem->penalty, mem->calls, (int)mem->lastcall, mem->status, mem->paused, idText); 04651 } 04652 ao2_ref(mem, -1); 04653 } 04654 /* List Queue Entries */ 04655 pos = 1; 04656 for (qe = q->head; qe; qe = qe->next) { 04657 astman_append(s, "Event: QueueEntry\r\n" 04658 "Queue: %s\r\n" 04659 "Position: %d\r\n" 04660 "Channel: %s\r\n" 04661 "CallerID: %s\r\n" 04662 "CallerIDName: %s\r\n" 04663 "Wait: %ld\r\n" 04664 "%s" 04665 "\r\n", 04666 q->name, pos++, qe->chan->name, 04667 S_OR(qe->chan->cid.cid_num, "unknown"), 04668 S_OR(qe->chan->cid.cid_name, "unknown"), 04669 (long) (now - qe->start), idText); 04670 } 04671 } 04672 ast_mutex_unlock(&q->lock); 04673 } 04674 04675 astman_append(s, 04676 "Event: QueueStatusComplete\r\n" 04677 "%s" 04678 "\r\n",idText); 04679 04680 AST_LIST_UNLOCK(&queues); 04681 04682 04683 return RESULT_SUCCESS; 04684 }
static int manager_remove_queue_member | ( | struct mansession * | s, | |
const struct message * | m | |||
) | [static] |
Definition at line 4736 of file app_queue.c.
References ast_queue_log(), ast_strlen_zero(), astman_get_header(), astman_send_ack(), astman_send_error(), remove_from_queue(), RES_EXISTS, RES_NOSUCHQUEUE, RES_NOT_DYNAMIC, RES_OKAY, RES_OUTOFMEMORY, and s.
Referenced by load_module().
04737 { 04738 const char *queuename, *interface; 04739 04740 queuename = astman_get_header(m, "Queue"); 04741 interface = astman_get_header(m, "Interface"); 04742 04743 if (ast_strlen_zero(queuename) || ast_strlen_zero(interface)) { 04744 astman_send_error(s, m, "Need 'Queue' and 'Interface' parameters."); 04745 return 0; 04746 } 04747 04748 switch (remove_from_queue(queuename, interface)) { 04749 case RES_OKAY: 04750 ast_queue_log(queuename, "MANAGER", interface, "REMOVEMEMBER", "%s", ""); 04751 astman_send_ack(s, m, "Removed interface from queue"); 04752 break; 04753 case RES_EXISTS: 04754 astman_send_error(s, m, "Unable to remove interface: Not there"); 04755 break; 04756 case RES_NOSUCHQUEUE: 04757 astman_send_error(s, m, "Unable to remove interface from queue: No such queue"); 04758 break; 04759 case RES_OUTOFMEMORY: 04760 astman_send_error(s, m, "Out of memory"); 04761 break; 04762 case RES_NOT_DYNAMIC: 04763 astman_send_error(s, m, "Member not dynamic"); 04764 break; 04765 } 04766 04767 return 0; 04768 }
static int member_cmp_fn | ( | void * | obj1, | |
void * | obj2, | |||
int | flags | |||
) | [static] |
Definition at line 803 of file app_queue.c.
References member::interface.
Referenced by init_queue().
00804 { 00805 struct member *mem1 = obj1, *mem2 = obj2; 00806 return strcmp(mem1->interface, mem2->interface) ? 0 : CMP_MATCH; 00807 }
static int member_hash_fn | ( | const void * | obj, | |
const int | flags | |||
) | [static] |
Definition at line 791 of file app_queue.c.
References compress_char(), and member::interface.
Referenced by init_queue().
00792 { 00793 const struct member *mem = obj; 00794 const char *chname = strchr(mem->interface, '/'); 00795 int ret = 0, i; 00796 if (!chname) 00797 chname = mem->interface; 00798 for (i = 0; i < 5 && chname[i]; i++) 00799 ret += compress_char(chname[i]) << (i * 6); 00800 return ret; 00801 }
static void monjoin_dep_warning | ( | void | ) | [static] |
Definition at line 462 of file app_queue.c.
References ast_log(), and LOG_NOTICE.
Referenced by queue_set_param().
00463 { 00464 static unsigned int warned = 0; 00465 if (!warned) { 00466 ast_log(LOG_NOTICE, "The 'monitor-join' queue option is deprecated. Please use monitor-type=mixmonitor instead.\n"); 00467 warned = 1; 00468 } 00469 }
static int play_file | ( | struct ast_channel * | chan, | |
char * | filename | |||
) | [static] |
Definition at line 1484 of file app_queue.c.
References AST_DIGIT_ANY, ast_stopstream(), ast_streamfile(), ast_waitstream(), and queue_ent::chan.
Referenced by say_periodic_announcement(), say_position(), and try_calling().
01485 { 01486 int res; 01487 01488 ast_stopstream(chan); 01489 01490 res = ast_streamfile(chan, filename, chan->language); 01491 if (!res) 01492 res = ast_waitstream(chan, AST_DIGIT_ANY); 01493 01494 ast_stopstream(chan); 01495 01496 return res; 01497 }
static int pqm_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Definition at line 3438 of file app_queue.c.
References AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_goto_if_exists(), ast_log(), ast_module_user_add, ast_module_user_remove, ast_opt_priority_jumping, AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), ast_module_user::chan, ast_channel::context, ast_channel::exten, LOG_WARNING, parse(), pbx_builtin_setvar_helper(), ast_channel::priority, and set_member_paused().
Referenced by load_module().
03439 { 03440 struct ast_module_user *lu; 03441 char *parse; 03442 int priority_jump = 0; 03443 int ignore_fail = 0; 03444 AST_DECLARE_APP_ARGS(args, 03445 AST_APP_ARG(queuename); 03446 AST_APP_ARG(interface); 03447 AST_APP_ARG(options); 03448 ); 03449 03450 if (ast_strlen_zero(data)) { 03451 ast_log(LOG_WARNING, "PauseQueueMember requires an argument ([queuename]|interface[|options])\n"); 03452 return -1; 03453 } 03454 03455 parse = ast_strdupa(data); 03456 03457 AST_STANDARD_APP_ARGS(args, parse); 03458 03459 lu = ast_module_user_add(chan); 03460 03461 if (args.options) { 03462 if (strchr(args.options, 'j')) 03463 priority_jump = 1; 03464 if (strchr(args.options, 'i')) 03465 ignore_fail = 1; 03466 } 03467 03468 if (ast_strlen_zero(args.interface)) { 03469 ast_log(LOG_WARNING, "Missing interface argument to PauseQueueMember ([queuename]|interface[|options])\n"); 03470 ast_module_user_remove(lu); 03471 return -1; 03472 } 03473 03474 if (set_member_paused(args.queuename, args.interface, 1)) { 03475 ast_log(LOG_WARNING, "Attempt to pause interface %s, not found\n", args.interface); 03476 pbx_builtin_setvar_helper(chan, "PQMSTATUS", "NOTFOUND"); 03477 if (priority_jump || ast_opt_priority_jumping) { 03478 if (!ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101)) { 03479 ast_module_user_remove(lu); 03480 return 0; 03481 } 03482 } 03483 ast_module_user_remove(lu); 03484 if (ignore_fail) { 03485 return 0; 03486 } else { 03487 return -1; 03488 } 03489 } 03490 03491 ast_module_user_remove(lu); 03492 pbx_builtin_setvar_helper(chan, "PQMSTATUS", "PAUSED"); 03493 return 0; 03494 }
static int ql_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Definition at line 3695 of file app_queue.c.
References AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_log(), ast_module_user_add, ast_module_user_remove, ast_queue_log(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), ast_module_user::chan, event, LOG_WARNING, and parse().
Referenced by load_module().
03696 { 03697 struct ast_module_user *u; 03698 char *parse; 03699 03700 AST_DECLARE_APP_ARGS(args, 03701 AST_APP_ARG(queuename); 03702 AST_APP_ARG(uniqueid); 03703 AST_APP_ARG(membername); 03704 AST_APP_ARG(event); 03705 AST_APP_ARG(params); 03706 ); 03707 03708 if (ast_strlen_zero(data)) { 03709 ast_log(LOG_WARNING, "QueueLog requires arguments (queuename|uniqueid|membername|event[|additionalinfo]\n"); 03710 return -1; 03711 } 03712 03713 u = ast_module_user_add(chan); 03714 03715 parse = ast_strdupa(data); 03716 03717 AST_STANDARD_APP_ARGS(args, parse); 03718 03719 if (ast_strlen_zero(args.queuename) || ast_strlen_zero(args.uniqueid) 03720 || ast_strlen_zero(args.membername) || ast_strlen_zero(args.event)) { 03721 ast_log(LOG_WARNING, "QueueLog requires arguments (queuename|uniqueid|membername|event[|additionalinfo])\n"); 03722 ast_module_user_remove(u); 03723 return -1; 03724 } 03725 03726 ast_queue_log(args.queuename, args.uniqueid, args.membername, args.event, 03727 "%s", args.params ? args.params : ""); 03728 03729 ast_module_user_remove(u); 03730 03731 return 0; 03732 }
static int queue_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
The starting point for all queue calls.
The process involved here is to 1. Parse the options specified in the call to Queue() 2. Join the queue 3. Wait in a loop until it is our turn to try calling a queue member 4. Attempt to call a queue member 5. If 4. did not result in a bridged call, then check for between call options such as periodic announcements etc. 6. Try 4 again uless some condition (such as an expiration time) causes us to exit the queue.
Definition at line 3746 of file app_queue.c.
References AST_APP_ARG, AST_CONTROL_RINGING, AST_DECLARE_APP_ARGS, ast_indicate(), ast_log(), ast_module_user_add, ast_moh_start(), ast_moh_stop(), AST_PBX_KEEPALIVE, ast_queue_log(), AST_STANDARD_APP_ARGS, ast_stopstream(), ast_strdupa, ast_strlen_zero(), ast_verbose(), queue_ent::chan, ast_channel::cid, ast_callerid::cid_num, get_member_status(), is_our_turn(), join_queue(), leave_queue(), LOG_DEBUG, LOG_WARNING, option_debug, option_verbose, parse(), pbx_builtin_getvar_helper(), QUEUE_EMPTY_STRICT, QUEUE_LEAVEEMPTY, QUEUE_LEAVEUNAVAIL, QUEUE_NO_MEMBERS, QUEUE_NO_REACHABLE_MEMBERS, QUEUE_TIMEOUT, QUEUE_UNKNOWN, record_abandoned(), S_OR, say_periodic_announcement(), say_position(), set_queue_result(), stop, try_calling(), update_realtime_members(), VERBOSE_PREFIX_3, wait_a_bit(), and wait_our_turn().
Referenced by load_module().
03747 { 03748 int res=-1; 03749 int ringing=0; 03750 struct ast_module_user *lu; 03751 const char *user_priority; 03752 const char *max_penalty_str; 03753 int prio; 03754 int max_penalty; 03755 enum queue_result reason = QUEUE_UNKNOWN; 03756 /* whether to exit Queue application after the timeout hits */ 03757 int tries = 0; 03758 int noption = 0; 03759 char *parse; 03760 AST_DECLARE_APP_ARGS(args, 03761 AST_APP_ARG(queuename); 03762 AST_APP_ARG(options); 03763 AST_APP_ARG(url); 03764 AST_APP_ARG(announceoverride); 03765 AST_APP_ARG(queuetimeoutstr); 03766 AST_APP_ARG(agi); 03767 ); 03768 /* Our queue entry */ 03769 struct queue_ent qe; 03770 03771 if (ast_strlen_zero(data)) { 03772 ast_log(LOG_WARNING, "Queue requires an argument: queuename[|options[|URL[|announceoverride[|timeout[|agi]]]]]\n"); 03773 return -1; 03774 } 03775 03776 parse = ast_strdupa(data); 03777 AST_STANDARD_APP_ARGS(args, parse); 03778 03779 lu = ast_module_user_add(chan); 03780 03781 /* Setup our queue entry */ 03782 memset(&qe, 0, sizeof(qe)); 03783 qe.start = time(NULL); 03784 03785 /* set the expire time based on the supplied timeout; */ 03786 if (!ast_strlen_zero(args.queuetimeoutstr)) 03787 qe.expire = qe.start + atoi(args.queuetimeoutstr); 03788 else 03789 qe.expire = 0; 03790 03791 /* Get the priority from the variable ${QUEUE_PRIO} */ 03792 user_priority = pbx_builtin_getvar_helper(chan, "QUEUE_PRIO"); 03793 if (user_priority) { 03794 if (sscanf(user_priority, "%d", &prio) == 1) { 03795 if (option_debug) 03796 ast_log(LOG_DEBUG, "%s: Got priority %d from ${QUEUE_PRIO}.\n", 03797 chan->name, prio); 03798 } else { 03799 ast_log(LOG_WARNING, "${QUEUE_PRIO}: Invalid value (%s), channel %s.\n", 03800 user_priority, chan->name); 03801 prio = 0; 03802 } 03803 } else { 03804 if (option_debug > 2) 03805 ast_log(LOG_DEBUG, "NO QUEUE_PRIO variable found. Using default.\n"); 03806 prio = 0; 03807 } 03808 03809 /* Get the maximum penalty from the variable ${QUEUE_MAX_PENALTY} */ 03810 if ((max_penalty_str = pbx_builtin_getvar_helper(chan, "QUEUE_MAX_PENALTY"))) { 03811 if (sscanf(max_penalty_str, "%d", &max_penalty) == 1) { 03812 if (option_debug) 03813 ast_log(LOG_DEBUG, "%s: Got max penalty %d from ${QUEUE_MAX_PENALTY}.\n", 03814 chan->name, max_penalty); 03815 } else { 03816 ast_log(LOG_WARNING, "${QUEUE_MAX_PENALTY}: Invalid value (%s), channel %s.\n", 03817 max_penalty_str, chan->name); 03818 max_penalty = 0; 03819 } 03820 } else { 03821 max_penalty = 0; 03822 } 03823 03824 if (args.options && (strchr(args.options, 'r'))) 03825 ringing = 1; 03826 03827 if (option_debug) 03828 ast_log(LOG_DEBUG, "queue: %s, options: %s, url: %s, announce: %s, expires: %ld, priority: %d\n", 03829 args.queuename, args.options, args.url, args.announceoverride, (long)qe.expire, prio); 03830 03831 qe.chan = chan; 03832 qe.prio = prio; 03833 qe.max_penalty = max_penalty; 03834 qe.last_pos_said = 0; 03835 qe.last_pos = 0; 03836 qe.last_periodic_announce_time = time(NULL); 03837 qe.last_periodic_announce_sound = 0; 03838 qe.valid_digits = 0; 03839 if (!join_queue(args.queuename, &qe, &reason)) { 03840 int makeannouncement = 0; 03841 03842 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "ENTERQUEUE", "%s|%s", S_OR(args.url, ""), 03843 S_OR(chan->cid.cid_num, "")); 03844 check_turns: 03845 if (ringing) { 03846 ast_indicate(chan, AST_CONTROL_RINGING); 03847 } else { 03848 ast_moh_start(chan, qe.moh, NULL); 03849 } 03850 03851 /* This is the wait loop for callers 2 through maxlen */ 03852 res = wait_our_turn(&qe, ringing, &reason); 03853 if (res) 03854 goto stop; 03855 03856 for (;;) { 03857 /* This is the wait loop for the head caller*/ 03858 /* To exit, they may get their call answered; */ 03859 /* they may dial a digit from the queue context; */ 03860 /* or, they may timeout. */ 03861 03862 enum queue_member_status stat; 03863 03864 /* Leave if we have exceeded our queuetimeout */ 03865 if (qe.expire && (time(NULL) > qe.expire)) { 03866 record_abandoned(&qe); 03867 reason = QUEUE_TIMEOUT; 03868 res = 0; 03869 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHTIMEOUT", "%d", qe.pos); 03870 break; 03871 } 03872 03873 if (makeannouncement) { 03874 /* Make a position announcement, if enabled */ 03875 if (qe.parent->announcefrequency && !ringing) 03876 if ((res = say_position(&qe))) 03877 goto stop; 03878 03879 } 03880 makeannouncement = 1; 03881 03882 /* Make a periodic announcement, if enabled */ 03883 if (qe.parent->periodicannouncefrequency && !ringing) 03884 if ((res = say_periodic_announcement(&qe))) 03885 goto stop; 03886 03887 /* Try calling all queue members for 'timeout' seconds */ 03888 res = try_calling(&qe, args.options, args.announceoverride, args.url, &tries, &noption, args.agi); 03889 if (res) 03890 goto stop; 03891 03892 stat = get_member_status(qe.parent, qe.max_penalty); 03893 03894 /* exit after 'timeout' cycle if 'n' option enabled */ 03895 if (noption && tries >= qe.parent->membercount) { 03896 if (option_verbose > 2) 03897 ast_verbose(VERBOSE_PREFIX_3 "Exiting on time-out cycle\n"); 03898 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHTIMEOUT", "%d", qe.pos); 03899 record_abandoned(&qe); 03900 reason = QUEUE_TIMEOUT; 03901 res = 0; 03902 break; 03903 } 03904 03905 /* leave the queue if no agents, if enabled */ 03906 if (qe.parent->leavewhenempty && (stat == QUEUE_NO_MEMBERS)) { 03907 record_abandoned(&qe); 03908 reason = QUEUE_LEAVEEMPTY; 03909 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe.pos, qe.opos, (long)(time(NULL) - qe.start)); 03910 res = 0; 03911 break; 03912 } 03913 03914 /* leave the queue if no reachable agents, if enabled */ 03915 if ((qe.parent->leavewhenempty == QUEUE_EMPTY_STRICT) && (stat == QUEUE_NO_REACHABLE_MEMBERS)) { 03916 record_abandoned(&qe); 03917 reason = QUEUE_LEAVEUNAVAIL; 03918 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe.pos, qe.opos, (long)(time(NULL) - qe.start)); 03919 res = 0; 03920 break; 03921 } 03922 03923 /* Leave if we have exceeded our queuetimeout */ 03924 if (qe.expire && (time(NULL) > qe.expire)) { 03925 record_abandoned(&qe); 03926 reason = QUEUE_TIMEOUT; 03927 res = 0; 03928 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHTIMEOUT", "%d", qe.pos); 03929 break; 03930 } 03931 03932 /* If using dynamic realtime members, we should regenerate the member list for this queue */ 03933 update_realtime_members(qe.parent); 03934 03935 /* OK, we didn't get anybody; wait for 'retry' seconds; may get a digit to exit with */ 03936 res = wait_a_bit(&qe); 03937 if (res) 03938 goto stop; 03939 03940 03941 /* Since this is a priority queue and 03942 * it is not sure that we are still at the head 03943 * of the queue, go and check for our turn again. 03944 */ 03945 if (!is_our_turn(&qe)) { 03946 if (option_debug) 03947 ast_log(LOG_DEBUG, "Darn priorities, going back in queue (%s)!\n", 03948 qe.chan->name); 03949 goto check_turns; 03950 } 03951 } 03952 03953 stop: 03954 if (res) { 03955 if (res < 0) { 03956 if (!qe.handled) { 03957 record_abandoned(&qe); 03958 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "ABANDON", 03959 "%d|%d|%ld", qe.pos, qe.opos, 03960 (long) time(NULL) - qe.start); 03961 } 03962 res = -1; 03963 } else if (qe.valid_digits) { 03964 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHKEY", 03965 "%s|%d", qe.digits, qe.pos); 03966 } 03967 } 03968 03969 /* Don't allow return code > 0 */ 03970 if (res >= 0 && res != AST_PBX_KEEPALIVE) { 03971 res = 0; 03972 if (ringing) { 03973 ast_indicate(chan, -1); 03974 } else { 03975 ast_moh_stop(chan); 03976 } 03977 ast_stopstream(chan); 03978 } 03979 leave_queue(&qe); 03980 if (reason != QUEUE_UNKNOWN) 03981 set_queue_result(chan, reason); 03982 } else { 03983 ast_log(LOG_WARNING, "Unable to join queue '%s'\n", args.queuename); 03984 set_queue_result(chan, reason); 03985 res = 0; 03986 } 03987 ast_module_user_remove(lu); 03988 03989 return res; 03990 }
static int queue_function_queuemembercount | ( | struct ast_channel * | chan, | |
char * | cmd, | |||
char * | data, | |||
char * | buf, | |||
size_t | len | |||
) | [static] |
Definition at line 4000 of file app_queue.c.
References ao2_iterator_init(), ao2_iterator_next(), ao2_ref(), AST_DEVICE_INVALID, AST_DEVICE_NOT_INUSE, AST_DEVICE_UNAVAILABLE, AST_DEVICE_UNKNOWN, ast_log(), ast_module_user_add, ast_module_user_remove, ast_mutex_lock(), ast_mutex_unlock(), ast_strdupa, ast_strlen_zero(), load_realtime_queue(), call_queue::lock, LOG_ERROR, LOG_WARNING, call_queue::members, name, member::paused, QMC_ACTIVE, QMC_FREE, QMC_PAUSED, QMC_VALID, and member::status.
04001 { 04002 int count = 0; 04003 struct call_queue *q; 04004 struct ast_module_user *lu; 04005 struct member *m; 04006 struct ao2_iterator mem_iter; 04007 char *name, *item; 04008 enum qmc_status mode = QMC_VALID; 04009 04010 buf[0] = '\0'; 04011 04012 if (ast_strlen_zero(data)) { 04013 ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd); 04014 return -1; 04015 } 04016 04017 name = ast_strdupa(data); 04018 04019 lu = ast_module_user_add(chan); 04020 04021 if ((item = strchr(name, ':'))) { 04022 *item = '\0'; 04023 item++; 04024 } else { 04025 item = ""; 04026 } 04027 04028 if (!strcasecmp(item, "valid")) { 04029 mode = QMC_VALID; 04030 } else if (!strcasecmp(item, "paused")) { 04031 mode = QMC_PAUSED; 04032 } else if (!strcasecmp(item, "active")) { 04033 mode = QMC_ACTIVE; 04034 } else if (!strcasecmp(item, "free")) { 04035 mode = QMC_FREE; 04036 } else if (!strcasecmp(item, "all")) { 04037 mode = QMC_ALL; 04038 } 04039 04040 if ((q = load_realtime_queue(name))) { 04041 ast_mutex_lock(&q->lock); 04042 mem_iter = ao2_iterator_init(q->members, 0); 04043 while ((m = ao2_iterator_next(&mem_iter))) { 04044 switch (mode) { 04045 case QMC_VALID: 04046 /* Count the queue members who are logged in and presently answering calls */ 04047 if ((m->status != AST_DEVICE_UNAVAILABLE) && (m->status != AST_DEVICE_INVALID)) { 04048 count++; 04049 } 04050 break; 04051 case QMC_PAUSED: 04052 /* Count paused members */ 04053 if (m->paused) { 04054 count++; 04055 } 04056 break; 04057 case QMC_ACTIVE: 04058 /* Count not paused members who are logged in and presently answering calls */ 04059 if (!m->paused && (m->status != AST_DEVICE_UNAVAILABLE) && (m->status != AST_DEVICE_INVALID)) { 04060 count++; 04061 } 04062 break; 04063 case QMC_FREE: 04064 /* Count free members in the queue */ 04065 if (!m->paused && ((m->status == AST_DEVICE_UNKNOWN) || (m->status == AST_DEVICE_NOT_INUSE))) { 04066 count++; 04067 } 04068 break; 04069 default: 04070 count++; 04071 break; 04072 } 04073 ao2_ref(m, -1); 04074 } 04075 ast_mutex_unlock(&q->lock); 04076 } else 04077 ast_log(LOG_WARNING, "queue %s was not found\n", name); 04078 04079 snprintf(buf, len, "%d", count); 04080 ast_module_user_remove(lu); 04081 04082 return 0; 04083 }
static int queue_function_queuememberlist | ( | struct ast_channel * | chan, | |
char * | cmd, | |||
char * | data, | |||
char * | buf, | |||
size_t | len | |||
) | [static] |
Definition at line 4128 of file app_queue.c.
References ao2_iterator_init(), ao2_iterator_next(), ao2_ref(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_module_user_add, ast_module_user_remove, ast_mutex_lock(), ast_mutex_unlock(), ast_strlen_zero(), call_queue::lock, LOG_ERROR, LOG_WARNING, member::membername, call_queue::members, and call_queue::name.
04129 { 04130 struct ast_module_user *u; 04131 struct call_queue *q; 04132 struct member *m; 04133 04134 /* Ensure an otherwise empty list doesn't return garbage */ 04135 buf[0] = '\0'; 04136 04137 if (ast_strlen_zero(data)) { 04138 ast_log(LOG_ERROR, "QUEUE_MEMBER_LIST requires an argument: queuename\n"); 04139 return -1; 04140 } 04141 04142 u = ast_module_user_add(chan); 04143 04144 AST_LIST_LOCK(&queues); 04145 AST_LIST_TRAVERSE(&queues, q, list) { 04146 if (!strcasecmp(q->name, data)) { 04147 ast_mutex_lock(&q->lock); 04148 break; 04149 } 04150 } 04151 AST_LIST_UNLOCK(&queues); 04152 04153 if (q) { 04154 int buflen = 0, count = 0; 04155 struct ao2_iterator mem_iter = ao2_iterator_init(q->members, 0); 04156 04157 while ((m = ao2_iterator_next(&mem_iter))) { 04158 /* strcat() is always faster than printf() */ 04159 if (count++) { 04160 strncat(buf + buflen, ",", len - buflen - 1); 04161 buflen++; 04162 } 04163 strncat(buf + buflen, m->membername, len - buflen - 1); 04164 buflen += strlen(m->membername); 04165 /* Safeguard against overflow (negative length) */ 04166 if (buflen >= len - 2) { 04167 ao2_ref(m, -1); 04168 ast_log(LOG_WARNING, "Truncating list\n"); 04169 break; 04170 } 04171 ao2_ref(m, -1); 04172 } 04173 ast_mutex_unlock(&q->lock); 04174 } else 04175 ast_log(LOG_WARNING, "queue %s was not found\n", data); 04176 04177 /* We should already be terminated, but let's make sure. */ 04178 buf[len - 1] = '\0'; 04179 ast_module_user_remove(u); 04180 04181 return 0; 04182 }
static int queue_function_queuewaitingcount | ( | struct ast_channel * | chan, | |
char * | cmd, | |||
char * | data, | |||
char * | buf, | |||
size_t | len | |||
) | [static] |
Definition at line 4085 of file app_queue.c.
References AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_load_realtime(), ast_log(), ast_module_user_add, ast_module_user_remove, ast_mutex_lock(), ast_mutex_unlock(), ast_strlen_zero(), ast_variables_destroy(), call_queue::count, call_queue::lock, LOG_ERROR, LOG_WARNING, call_queue::name, and var.
04086 { 04087 int count = 0; 04088 struct call_queue *q; 04089 struct ast_module_user *lu; 04090 struct ast_variable *var = NULL; 04091 04092 buf[0] = '\0'; 04093 04094 if (ast_strlen_zero(data)) { 04095 ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd); 04096 return -1; 04097 } 04098 04099 lu = ast_module_user_add(chan); 04100 04101 AST_LIST_LOCK(&queues); 04102 AST_LIST_TRAVERSE(&queues, q, list) { 04103 if (!strcasecmp(q->name, data)) { 04104 ast_mutex_lock(&q->lock); 04105 break; 04106 } 04107 } 04108 AST_LIST_UNLOCK(&queues); 04109 04110 if (q) { 04111 count = q->count; 04112 ast_mutex_unlock(&q->lock); 04113 } else if ((var = ast_load_realtime("queues", "name", data, NULL))) { 04114 /* if the queue is realtime but was not found in memory, this 04115 * means that the queue had been deleted from memory since it was 04116 * "dead." This means it has a 0 waiting count 04117 */ 04118 count = 0; 04119 ast_variables_destroy(var); 04120 } else 04121 ast_log(LOG_WARNING, "queue %s was not found\n", data); 04122 04123 snprintf(buf, len, "%d", count); 04124 ast_module_user_remove(lu); 04125 return 0; 04126 }
static void queue_set_param | ( | struct call_queue * | q, | |
const char * | param, | |||
const char * | val, | |||
int | linenum, | |||
int | failunknown | |||
) | [static] |
Configure a queue parameter.
Definition at line 960 of file app_queue.c.
References call_queue::announce, call_queue::announcefrequency, call_queue::announceholdtime, ANNOUNCEHOLDTIME_ALWAYS, ANNOUNCEHOLDTIME_ONCE, ast_log(), ast_strdupa, ast_true(), call_queue::autofill, call_queue::autopause, call_queue::context, DEFAULT_RETRY, DEFAULT_TIMEOUT, call_queue::eventwhencalled, call_queue::joinempty, call_queue::leavewhenempty, LOG_WARNING, call_queue::maskmemberstatus, MAX_PERIODIC_ANNOUNCEMENTS, call_queue::maxlen, call_queue::memberdelay, call_queue::moh, call_queue::monfmt, call_queue::monjoin, monjoin_dep_warning(), call_queue::montype, call_queue::name, call_queue::periodicannouncefrequency, QUEUE_EMPTY_NORMAL, QUEUE_EMPTY_STRICT, QUEUE_EVENT_VARIABLES, QUEUE_STRATEGY_RINGALL, call_queue::reportholdtime, call_queue::retry, call_queue::ringinuse, call_queue::ringlimit, call_queue::roundingseconds, s, call_queue::servicelevel, call_queue::setinterfacevar, call_queue::sound_calls, call_queue::sound_holdtime, call_queue::sound_lessthan, call_queue::sound_minutes, call_queue::sound_next, call_queue::sound_periodicannounce, call_queue::sound_reporthold, call_queue::sound_seconds, call_queue::sound_thanks, call_queue::sound_thereare, strat2int(), call_queue::strategy, strsep(), call_queue::timeout, call_queue::timeoutrestart, call_queue::weight, and call_queue::wrapuptime.
Referenced by find_queue_by_name_rt(), and reload_queues().
00961 { 00962 if (!strcasecmp(param, "musicclass") || 00963 !strcasecmp(param, "music") || !strcasecmp(param, "musiconhold")) { 00964 ast_copy_string(q->moh, val, sizeof(q->moh)); 00965 } else if (!strcasecmp(param, "announce")) { 00966 ast_copy_string(q->announce, val, sizeof(q->announce)); 00967 } else if (!strcasecmp(param, "context")) { 00968 ast_copy_string(q->context, val, sizeof(q->context)); 00969 } else if (!strcasecmp(param, "timeout")) { 00970 q->timeout = atoi(val); 00971 if (q->timeout < 0) 00972 q->timeout = DEFAULT_TIMEOUT; 00973 } else if (!strcasecmp(param, "ringinuse")) { 00974 q->ringinuse = ast_true(val); 00975 } else if (!strcasecmp(param, "setinterfacevar")) { 00976 q->setinterfacevar = ast_true(val); 00977 } else if (!strcasecmp(param, "monitor-join")) { 00978 monjoin_dep_warning(); 00979 q->monjoin = ast_true(val); 00980 } else if (!strcasecmp(param, "monitor-format")) { 00981 ast_copy_string(q->monfmt, val, sizeof(q->monfmt)); 00982 } else if (!strcasecmp(param, "queue-youarenext")) { 00983 ast_copy_string(q->sound_next, val, sizeof(q->sound_next)); 00984 } else if (!strcasecmp(param, "queue-thereare")) { 00985 ast_copy_string(q->sound_thereare, val, sizeof(q->sound_thereare)); 00986 } else if (!strcasecmp(param, "queue-callswaiting")) { 00987 ast_copy_string(q->sound_calls, val, sizeof(q->sound_calls)); 00988 } else if (!strcasecmp(param, "queue-holdtime")) { 00989 ast_copy_string(q->sound_holdtime, val, sizeof(q->sound_holdtime)); 00990 } else if (!strcasecmp(param, "queue-minutes")) { 00991 ast_copy_string(q->sound_minutes, val, sizeof(q->sound_minutes)); 00992 } else if (!strcasecmp(param, "queue-seconds")) { 00993 ast_copy_string(q->sound_seconds, val, sizeof(q->sound_seconds)); 00994 } else if (!strcasecmp(param, "queue-lessthan")) { 00995 ast_copy_string(q->sound_lessthan, val, sizeof(q->sound_lessthan)); 00996 } else if (!strcasecmp(param, "queue-thankyou")) { 00997 ast_copy_string(q->sound_thanks, val, sizeof(q->sound_thanks)); 00998 } else if (!strcasecmp(param, "queue-reporthold")) { 00999 ast_copy_string(q->sound_reporthold, val, sizeof(q->sound_reporthold)); 01000 } else if (!strcasecmp(param, "announce-frequency")) { 01001 q->announcefrequency = atoi(val); 01002 } else if (!strcasecmp(param, "announce-round-seconds")) { 01003 q->roundingseconds = atoi(val); 01004 if (q->roundingseconds>60 || q->roundingseconds<0) { 01005 if (linenum >= 0) { 01006 ast_log(LOG_WARNING, "'%s' isn't a valid value for %s " 01007 "using 0 instead for queue '%s' at line %d of queues.conf\n", 01008 val, param, q->name, linenum); 01009 } else { 01010 ast_log(LOG_WARNING, "'%s' isn't a valid value for %s " 01011 "using 0 instead for queue '%s'\n", val, param, q->name); 01012 } 01013 q->roundingseconds=0; 01014 } 01015 } else if (!strcasecmp(param, "announce-holdtime")) { 01016 if (!strcasecmp(val, "once")) 01017 q->announceholdtime = ANNOUNCEHOLDTIME_ONCE; 01018 else if (ast_true(val)) 01019 q->announceholdtime = ANNOUNCEHOLDTIME_ALWAYS; 01020 else 01021 q->announceholdtime = 0; 01022 } else if (!strcasecmp(param, "periodic-announce")) { 01023 if (strchr(val, '|')) { 01024 char *s, *buf = ast_strdupa(val); 01025 unsigned int i = 0; 01026 01027 while ((s = strsep(&buf, "|"))) { 01028 ast_copy_string(q->sound_periodicannounce[i], s, sizeof(q->sound_periodicannounce[i])); 01029 i++; 01030 if (i == MAX_PERIODIC_ANNOUNCEMENTS) 01031 break; 01032 } 01033 } else { 01034 ast_copy_string(q->sound_periodicannounce[0], val, sizeof(q->sound_periodicannounce[0])); 01035 } 01036 } else if (!strcasecmp(param, "periodic-announce-frequency")) { 01037 q->periodicannouncefrequency = atoi(val); 01038 } else if (!strcasecmp(param, "retry")) { 01039 q->retry = atoi(val); 01040 if (q->retry <= 0) 01041 q->retry = DEFAULT_RETRY; 01042 } else if (!strcasecmp(param, "wrapuptime")) { 01043 q->wrapuptime = atoi(val); 01044 } else if (!strcasecmp(param, "autofill")) { 01045 q->autofill = ast_true(val); 01046 } else if (!strcasecmp(param, "monitor-type")) { 01047 if (!strcasecmp(val, "mixmonitor")) 01048 q->montype = 1; 01049 } else if (!strcasecmp(param, "autopause")) { 01050 q->autopause = ast_true(val); 01051 } else if (!strcasecmp(param, "maxlen")) { 01052 q->maxlen = atoi(val); 01053 if (q->maxlen < 0) 01054 q->maxlen = 0; 01055 } else if (!strcasecmp(param, "ringlimit")) { 01056 q->ringlimit = atoi(val); 01057 if (q->ringlimit < 0) 01058 q->ringlimit = 0; 01059 } else if (!strcasecmp(param, "servicelevel")) { 01060 q->servicelevel= atoi(val); 01061 } else if (!strcasecmp(param, "strategy")) { 01062 q->strategy = strat2int(val); 01063 if (q->strategy < 0) { 01064 ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n", 01065 val, q->name); 01066 q->strategy = QUEUE_STRATEGY_RINGALL; 01067 } 01068 } else if (!strcasecmp(param, "joinempty")) { 01069 if (!strcasecmp(val, "strict")) 01070 q->joinempty = QUEUE_EMPTY_STRICT; 01071 else if (ast_true(val)) 01072 q->joinempty = QUEUE_EMPTY_NORMAL; 01073 else 01074 q->joinempty = 0; 01075 } else if (!strcasecmp(param, "leavewhenempty")) { 01076 if (!strcasecmp(val, "strict")) 01077 q->leavewhenempty = QUEUE_EMPTY_STRICT; 01078 else if (ast_true(val)) 01079 q->leavewhenempty = QUEUE_EMPTY_NORMAL; 01080 else 01081 q->leavewhenempty = 0; 01082 } else if (!strcasecmp(param, "eventmemberstatus")) { 01083 q->maskmemberstatus = !ast_true(val); 01084 } else if (!strcasecmp(param, "eventwhencalled")) { 01085 if (!strcasecmp(val, "vars")) { 01086 q->eventwhencalled = QUEUE_EVENT_VARIABLES; 01087 } else { 01088 q->eventwhencalled = ast_true(val) ? 1 : 0; 01089 } 01090 } else if (!strcasecmp(param, "reportholdtime")) { 01091 q->reportholdtime = ast_true(val); 01092 } else if (!strcasecmp(param, "memberdelay")) { 01093 q->memberdelay = atoi(val); 01094 } else if (!strcasecmp(param, "weight")) { 01095 q->weight = atoi(val); 01096 if (q->weight) 01097 use_weight++; 01098 /* With Realtime queues, if the last queue using weights is deleted in realtime, 01099 we will not see any effect on use_weight until next reload. */ 01100 } else if (!strcasecmp(param, "timeoutrestart")) { 01101 q->timeoutrestart = ast_true(val); 01102 } else if (failunknown) { 01103 if (linenum >= 0) { 01104 ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s at line %d of queues.conf\n", 01105 q->name, param, linenum); 01106 } else { 01107 ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s\n", q->name, param); 01108 } 01109 } 01110 }
static int queue_show | ( | int | fd, | |
int | argc, | |||
char ** | argv | |||
) | [static] |
Definition at line 4547 of file app_queue.c.
References __queues_show().
Referenced by __queues_show().
04548 { 04549 return __queues_show(NULL, 0, fd, argc, argv); 04550 }
static void recalc_holdtime | ( | struct queue_ent * | qe, | |
int | newholdtime | |||
) | [static] |
Definition at line 1639 of file app_queue.c.
References ast_mutex_lock(), ast_mutex_unlock(), call_queue::holdtime, call_queue::lock, and queue_ent::parent.
Referenced by try_calling().
01640 { 01641 int oldvalue; 01642 01643 /* Calculate holdtime using a recursive boxcar filter */ 01644 /* Thanks to SRT for this contribution */ 01645 /* 2^2 (4) is the filter coefficient; a higher exponent would give old entries more weight */ 01646 01647 ast_mutex_lock(&qe->parent->lock); 01648 oldvalue = qe->parent->holdtime; 01649 qe->parent->holdtime = (((oldvalue << 2) - oldvalue) + newholdtime) >> 2; 01650 ast_mutex_unlock(&qe->parent->lock); 01651 }
static void record_abandoned | ( | struct queue_ent * | qe | ) | [static] |
Definition at line 2057 of file app_queue.c.
References ast_mutex_lock(), ast_mutex_unlock(), call_queue::callsabandoned, queue_ent::chan, EVENT_FLAG_AGENT, call_queue::lock, manager_event(), call_queue::name, queue_ent::opos, queue_ent::parent, queue_ent::pos, and queue_ent::start.
Referenced by queue_exec(), and try_calling().
02058 { 02059 ast_mutex_lock(&qe->parent->lock); 02060 manager_event(EVENT_FLAG_AGENT, "QueueCallerAbandon", 02061 "Queue: %s\r\n" 02062 "Uniqueid: %s\r\n" 02063 "Position: %d\r\n" 02064 "OriginalPosition: %d\r\n" 02065 "HoldTime: %d\r\n", 02066 qe->parent->name, qe->chan->uniqueid, qe->pos, qe->opos, (int)(time(NULL) - qe->start)); 02067 02068 qe->parent->callsabandoned++; 02069 ast_mutex_unlock(&qe->parent->lock); 02070 }
static int reload | ( | void | ) | [static] |
Definition at line 5068 of file app_queue.c.
References reload_queues().
05069 { 05070 reload_queues(); 05071 return 0; 05072 }
static void reload_queue_members | ( | void | ) | [static] |
Definition at line 3343 of file app_queue.c.
References add_to_queue(), ast_db_del(), ast_db_freetree(), ast_db_get(), ast_db_gettree(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_strlen_zero(), ERANGE, errno, member::interface, ast_db_entry::key, load_realtime_queue(), call_queue::lock, LOG_DEBUG, LOG_ERROR, LOG_NOTICE, LOG_WARNING, call_queue::name, ast_db_entry::next, option_debug, member::paused, member::penalty, PM_MAX_LEN, RES_OUTOFMEMORY, and strsep().
Referenced by load_module().
03344 { 03345 char *cur_ptr; 03346 char *queue_name; 03347 char *member; 03348 char *interface; 03349 char *membername = NULL; 03350 char *penalty_tok; 03351 int penalty = 0; 03352 char *paused_tok; 03353 int paused = 0; 03354 struct ast_db_entry *db_tree; 03355 struct ast_db_entry *entry; 03356 struct call_queue *cur_queue; 03357 char queue_data[PM_MAX_LEN]; 03358 03359 AST_LIST_LOCK(&queues); 03360 03361 /* Each key in 'pm_family' is the name of a queue */ 03362 db_tree = ast_db_gettree(pm_family, NULL); 03363 for (entry = db_tree; entry; entry = entry->next) { 03364 03365 queue_name = entry->key + strlen(pm_family) + 2; 03366 03367 AST_LIST_TRAVERSE(&queues, cur_queue, list) { 03368 ast_mutex_lock(&cur_queue->lock); 03369 if (!strcmp(queue_name, cur_queue->name)) 03370 break; 03371 ast_mutex_unlock(&cur_queue->lock); 03372 } 03373 03374 if (!cur_queue) 03375 cur_queue = load_realtime_queue(queue_name); 03376 03377 if (!cur_queue) { 03378 /* If the queue no longer exists, remove it from the 03379 * database */ 03380 ast_log(LOG_WARNING, "Error loading persistent queue: '%s': it does not exist\n", queue_name); 03381 ast_db_del(pm_family, queue_name); 03382 continue; 03383 } else 03384 ast_mutex_unlock(&cur_queue->lock); 03385 03386 if (ast_db_get(pm_family, queue_name, queue_data, PM_MAX_LEN)) 03387 continue; 03388 03389 cur_ptr = queue_data; 03390 while ((member = strsep(&cur_ptr, "|"))) { 03391 if (ast_strlen_zero(member)) 03392 continue; 03393 03394 interface = strsep(&member, ";"); 03395 penalty_tok = strsep(&member, ";"); 03396 paused_tok = strsep(&member, ";"); 03397 membername = strsep(&member, ";"); 03398 03399 if (!penalty_tok) { 03400 ast_log(LOG_WARNING, "Error parsing persistent member string for '%s' (penalty)\n", queue_name); 03401 break; 03402 } 03403 penalty = strtol(penalty_tok, NULL, 10); 03404 if (errno == ERANGE) { 03405 ast_log(LOG_WARNING, "Error converting penalty: %s: Out of range.\n", penalty_tok); 03406 break; 03407 } 03408 03409 if (!paused_tok) { 03410 ast_log(LOG_WARNING, "Error parsing persistent member string for '%s' (paused)\n", queue_name); 03411 break; 03412 } 03413 paused = strtol(paused_tok, NULL, 10); 03414 if ((errno == ERANGE) || paused < 0 || paused > 1) { 03415 ast_log(LOG_WARNING, "Error converting paused: %s: Expected 0 or 1.\n", paused_tok); 03416 break; 03417 } 03418 if (ast_strlen_zero(membername)) 03419 membername = interface; 03420 03421 if (option_debug) 03422 ast_log(LOG_DEBUG, "Reload Members: Queue: %s Member: %s Name: %s Penalty: %d Paused: %d\n", queue_name, interface, membername, penalty, paused); 03423 03424 if (add_to_queue(queue_name, interface, membername, penalty, paused, 0) == RES_OUTOFMEMORY) { 03425 ast_log(LOG_ERROR, "Out of Memory when reloading persistent queue member\n"); 03426 break; 03427 } 03428 } 03429 } 03430 03431 AST_LIST_UNLOCK(&queues); 03432 if (db_tree) { 03433 ast_log(LOG_NOTICE, "Queue members successfully reloaded from database.\n"); 03434 ast_db_freetree(db_tree); 03435 } 03436 }
static int reload_queues | ( | void | ) | [static] |
Definition at line 4227 of file app_queue.c.
References add_to_interfaces(), alloc_queue(), ao2_find(), ao2_iterator_init(), ao2_iterator_next(), ao2_ref(), ao2_unlink(), AST_APP_ARG, ast_category_browse(), ast_config_load(), AST_DECLARE_APP_ARGS, AST_LIST_INSERT_HEAD, AST_LIST_LOCK, AST_LIST_TRAVERSE, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), AST_NONSTANDARD_APP_ARGS, ast_strlen_zero(), ast_true(), ast_variable_browse(), ast_variable_retrieve(), clear_queue(), create_queue_member(), call_queue::dead, member::delme, member::dynamic, call_queue::found, init_queue(), member::interface, call_queue::lock, LOG_NOTICE, LOG_WARNING, call_queue::membercount, call_queue::members, call_queue::name, parse(), member::paused, queue_set_param(), QUEUE_STRATEGY_ROUNDROBIN, call_queue::realtime, remove_from_interfaces(), rr_dep_warning(), call_queue::strategy, and var.
Referenced by load_module(), and reload().
04228 { 04229 struct call_queue *q; 04230 struct ast_config *cfg; 04231 char *cat, *tmp; 04232 struct ast_variable *var; 04233 struct member *cur, *newm; 04234 struct ao2_iterator mem_iter; 04235 int new; 04236 const char *general_val = NULL; 04237 char parse[80]; 04238 char *interface; 04239 char *membername = NULL; 04240 int penalty; 04241 AST_DECLARE_APP_ARGS(args, 04242 AST_APP_ARG(interface); 04243 AST_APP_ARG(penalty); 04244 AST_APP_ARG(membername); 04245 ); 04246 04247 if (!(cfg = ast_config_load("queues.conf"))) { 04248 ast_log(LOG_NOTICE, "No call queueing config file (queues.conf), so no call queues\n"); 04249 return 0; 04250 } 04251 AST_LIST_LOCK(&queues); 04252 use_weight=0; 04253 /* Mark all non-realtime queues as dead for the moment */ 04254 AST_LIST_TRAVERSE(&queues, q, list) { 04255 if (!q->realtime) { 04256 q->dead = 1; 04257 q->found = 0; 04258 } 04259 } 04260 04261 /* Chug through config file */ 04262 cat = NULL; 04263 while ((cat = ast_category_browse(cfg, cat)) ) { 04264 if (!strcasecmp(cat, "general")) { 04265 /* Initialize global settings */ 04266 queue_debug = 0; 04267 if ((general_val = ast_variable_retrieve(cfg, "general", "debug"))) 04268 queue_debug = ast_true(general_val); 04269 queue_persistent_members = 0; 04270 if ((general_val = ast_variable_retrieve(cfg, "general", "persistentmembers"))) 04271 queue_persistent_members = ast_true(general_val); 04272 autofill_default = 0; 04273 if ((general_val = ast_variable_retrieve(cfg, "general", "autofill"))) 04274 autofill_default = ast_true(general_val); 04275 montype_default = 0; 04276 if ((general_val = ast_variable_retrieve(cfg, "general", "monitor-type"))) 04277 if (!strcasecmp(general_val, "mixmonitor")) 04278 montype_default = 1; 04279 } else { /* Define queue */ 04280 /* Look for an existing one */ 04281 AST_LIST_TRAVERSE(&queues, q, list) { 04282 if (!strcmp(q->name, cat)) 04283 break; 04284 } 04285 if (!q) { 04286 /* Make one then */ 04287 if (!(q = alloc_queue(cat))) { 04288 /* TODO: Handle memory allocation failure */ 04289 } 04290 new = 1; 04291 } else 04292 new = 0; 04293 if (q) { 04294 if (!new) 04295 ast_mutex_lock(&q->lock); 04296 /* Check if a queue with this name already exists */ 04297 if (q->found) { 04298 ast_log(LOG_WARNING, "Queue '%s' already defined! Skipping!\n", cat); 04299 if (!new) 04300 ast_mutex_unlock(&q->lock); 04301 continue; 04302 } 04303 /* Re-initialize the queue, and clear statistics */ 04304 init_queue(q); 04305 clear_queue(q); 04306 mem_iter = ao2_iterator_init(q->members, 0); 04307 while ((cur = ao2_iterator_next(&mem_iter))) { 04308 if (!cur->dynamic) { 04309 cur->delme = 1; 04310 } 04311 ao2_ref(cur, -1); 04312 } 04313 for (var = ast_variable_browse(cfg, cat); var; var = var->next) { 04314 if (!strcasecmp(var->name, "member")) { 04315 struct member tmpmem; 04316 membername = NULL; 04317 04318 /* Add a new member */ 04319 ast_copy_string(parse, var->value, sizeof(parse)); 04320 04321 AST_NONSTANDARD_APP_ARGS(args, parse, ','); 04322 04323 interface = args.interface; 04324 if (!ast_strlen_zero(args.penalty)) { 04325 tmp = args.penalty; 04326 while (*tmp && *tmp < 33) tmp++; 04327 penalty = atoi(tmp); 04328 if (penalty < 0) { 04329 penalty = 0; 04330 } 04331 } else 04332 penalty = 0; 04333 04334 if (!ast_strlen_zero(args.membername)) { 04335 membername = args.membername; 04336 while (*membername && *membername < 33) membername++; 04337 } 04338 04339 /* Find the old position in the list */ 04340 ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface)); 04341 cur = ao2_find(q->members, &tmpmem, OBJ_POINTER | OBJ_UNLINK); 04342 04343 newm = create_queue_member(interface, membername, penalty, cur ? cur->paused : 0); 04344 ao2_link(q->members, newm); 04345 ao2_ref(newm, -1); 04346 newm = NULL; 04347 04348 if (cur) 04349 ao2_ref(cur, -1); 04350 else { 04351 /* Add them to the master int list if necessary */ 04352 add_to_interfaces(interface); 04353 q->membercount++; 04354 } 04355 } else { 04356 queue_set_param(q, var->name, var->value, var->lineno, 1); 04357 } 04358 } 04359 04360 /* Free remaining members marked as delme */ 04361 mem_iter = ao2_iterator_init(q->members, 0); 04362 while ((cur = ao2_iterator_next(&mem_iter))) { 04363 if (! cur->delme) { 04364 ao2_ref(cur, -1); 04365 continue; 04366 } 04367 04368 q->membercount--; 04369 ao2_unlink(q->members, cur); 04370 remove_from_interfaces(cur->interface); 04371 ao2_ref(cur, -1); 04372 } 04373 04374 if (q->strategy == QUEUE_STRATEGY_ROUNDROBIN) 04375 rr_dep_warning(); 04376 04377 if (new) { 04378 AST_LIST_INSERT_HEAD(&queues, q, list); 04379 } else 04380 ast_mutex_unlock(&q->lock); 04381 } 04382 } 04383 } 04384 ast_config_destroy(cfg); 04385 AST_LIST_TRAVERSE_SAFE_BEGIN(&queues, q, list) { 04386 if (q->dead) { 04387 AST_LIST_REMOVE_CURRENT(&queues, list); 04388 if (!q->count) 04389 destroy_queue(q); 04390 else 04391 ast_log(LOG_DEBUG, "XXX Leaking a little memory :( XXX\n"); 04392 } else { 04393 ast_mutex_lock(&q->lock); 04394 mem_iter = ao2_iterator_init(q->members, 0); 04395 while ((cur = ao2_iterator_next(&mem_iter))) { 04396 if (cur->dynamic) 04397 q->membercount++; 04398 cur->status = ast_device_state(cur->interface); 04399 ao2_ref(cur, -1); 04400 } 04401 ast_mutex_unlock(&q->lock); 04402 } 04403 } 04404 AST_LIST_TRAVERSE_SAFE_END; 04405 AST_LIST_UNLOCK(&queues); 04406 return 1; 04407 }
static int remove_from_interfaces | ( | const char * | interface | ) | [static] |
Definition at line 920 of file app_queue.c.
References AST_LIST_LOCK, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, AST_LIST_UNLOCK, ast_log(), free, member_interface::interface, interface_exists_global(), LOG_DEBUG, and option_debug.
Referenced by free_members(), reload_queues(), remove_from_queue(), and update_realtime_members().
00921 { 00922 struct member_interface *curint; 00923 00924 if (interface_exists_global(interface)) 00925 return 0; 00926 00927 AST_LIST_LOCK(&interfaces); 00928 AST_LIST_TRAVERSE_SAFE_BEGIN(&interfaces, curint, list) { 00929 if (!strcasecmp(curint->interface, interface)) { 00930 if (option_debug) 00931 ast_log(LOG_DEBUG, "Removing %s from the list of interfaces that make up all of our queue members.\n", interface); 00932 AST_LIST_REMOVE_CURRENT(&interfaces, list); 00933 free(curint); 00934 break; 00935 } 00936 } 00937 AST_LIST_TRAVERSE_SAFE_END; 00938 AST_LIST_UNLOCK(&interfaces); 00939 00940 return 0; 00941 }
static int remove_from_queue | ( | const char * | queuename, | |
const char * | interface | |||
) | [static] |
Definition at line 3189 of file app_queue.c.
References ao2_find(), ao2_ref(), ao2_unlink(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_mutex_lock(), ast_mutex_unlock(), dump_queue_members(), member::dynamic, EVENT_FLAG_AGENT, member::interface, call_queue::lock, manager_event(), call_queue::membercount, member::membername, call_queue::members, call_queue::name, remove_from_interfaces(), RES_EXISTS, RES_NOSUCHQUEUE, RES_NOT_DYNAMIC, and RES_OKAY.
Referenced by attempt_thread(), handle_queue_remove_member(), manager_remove_queue_member(), rqm_exec(), and scan_service().
03190 { 03191 struct call_queue *q; 03192 struct member *mem, tmpmem; 03193 int res = RES_NOSUCHQUEUE; 03194 03195 ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface)); 03196 03197 AST_LIST_LOCK(&queues); 03198 AST_LIST_TRAVERSE(&queues, q, list) { 03199 ast_mutex_lock(&q->lock); 03200 if (strcmp(q->name, queuename)) { 03201 ast_mutex_unlock(&q->lock); 03202 continue; 03203 } 03204 03205 if ((mem = ao2_find(q->members, &tmpmem, OBJ_POINTER))) { 03206 /* XXX future changes should beware of this assumption!! */ 03207 if (!mem->dynamic) { 03208 res = RES_NOT_DYNAMIC; 03209 ao2_ref(mem, -1); 03210 ast_mutex_unlock(&q->lock); 03211 break; 03212 } 03213 q->membercount--; 03214 manager_event(EVENT_FLAG_AGENT, "QueueMemberRemoved", 03215 "Queue: %s\r\n" 03216 "Location: %s\r\n" 03217 "MemberName: %s\r\n", 03218 q->name, mem->interface, mem->membername); 03219 ao2_unlink(q->members, mem); 03220 ao2_ref(mem, -1); 03221 03222 if (queue_persistent_members) 03223 dump_queue_members(q); 03224 03225 res = RES_OKAY; 03226 } else { 03227 res = RES_EXISTS; 03228 } 03229 ast_mutex_unlock(&q->lock); 03230 break; 03231 } 03232 03233 if (res == RES_OKAY) 03234 remove_from_interfaces(interface); 03235 03236 AST_LIST_UNLOCK(&queues); 03237 03238 return res; 03239 }
static int ring_entry | ( | struct queue_ent * | qe, | |
struct callattempt * | tmp, | |||
int * | busies | |||
) | [static] |
Part 2 of ring_one.
Does error checking before attempting to request a channel and call a member. This function is only called from ring_one
Definition at line 1794 of file app_queue.c.
References ast_channel::adsicpe, ast_channel::appl, ast_call(), ast_cdr_busy(), ast_channel_inherit_variables(), ast_channel_lock, ast_channel_unlock, AST_DEVICE_NOT_INUSE, ast_device_state(), AST_DEVICE_UNKNOWN, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_request(), ast_strdup, ast_strlen_zero(), ast_verbose(), ast_channel::cdr, callattempt::chan, queue_ent::chan, ast_channel::cid, ast_callerid::cid_ani, ast_callerid::cid_name, ast_callerid::cid_num, compare_weight(), ast_channel::context, ast_channel::data, ast_channel::dialcontext, do_hang(), EVENT_FLAG_AGENT, call_queue::eventwhencalled, ast_channel::exten, free, member::interface, callattempt::interface, callattempt::lastcall, call_queue::lock, LOG_DEBUG, LOG_NOTICE, manager_event(), callattempt::member, member::membername, call_queue::name, ast_channel::nativeformats, option_debug, option_verbose, queue_ent::parent, member::paused, pbx_builtin_getvar_helper(), ast_channel::priority, QUEUE_EVENT_VARIABLES, member::ringcount, call_queue::ringinuse, call_queue::rrpos, member::status, callattempt::stillgoing, update_status(), vars2manager(), VERBOSE_PREFIX_3, ast_channel::whentohangup, and call_queue::wrapuptime.
Referenced by ring_one().
01795 { 01796 int res; 01797 int status; 01798 char tech[256]; 01799 char *location; 01800 const char *macrocontext, *macroexten; 01801 01802 /* on entry here, we know that tmp->chan == NULL */ 01803 if (qe->parent->wrapuptime && (time(NULL) - tmp->lastcall < qe->parent->wrapuptime)) { 01804 if (queue_debug) 01805 ast_log(LOG_NOTICE, "Wrapuptime not yet expired for %s\n", tmp->interface); 01806 if (qe->chan->cdr) 01807 ast_cdr_busy(qe->chan->cdr); 01808 tmp->stillgoing = 0; 01809 (*busies)++; 01810 return 0; 01811 } 01812 01813 if (!qe->parent->ringinuse && (tmp->member->status != AST_DEVICE_NOT_INUSE) && (tmp->member->status != AST_DEVICE_UNKNOWN)) { 01814 if (queue_debug) 01815 ast_log(LOG_NOTICE, "%s in use, can't receive call\n", tmp->interface); 01816 if (qe->chan->cdr) 01817 ast_cdr_busy(qe->chan->cdr); 01818 tmp->stillgoing = 0; 01819 return 0; 01820 } 01821 01822 if (tmp->member->paused) { 01823 if (queue_debug) 01824 ast_log(LOG_NOTICE, "%s paused, can't receive call\n", tmp->interface); 01825 if (qe->chan->cdr) 01826 ast_cdr_busy(qe->chan->cdr); 01827 tmp->stillgoing = 0; 01828 return 0; 01829 } 01830 if (use_weight && compare_weight(qe->parent,tmp->member)) { 01831 if (queue_debug) 01832 ast_log(LOG_NOTICE, "Priority queue delaying call to %s:%s\n", qe->parent->name, tmp->interface); 01833 if (qe->chan->cdr) 01834 ast_cdr_busy(qe->chan->cdr); 01835 tmp->stillgoing = 0; 01836 (*busies)++; 01837 return 0; 01838 } 01839 01840 ast_copy_string(tech, tmp->interface, sizeof(tech)); 01841 if ((location = strchr(tech, '/'))) 01842 *location++ = '\0'; 01843 else 01844 location = ""; 01845 01846 /* Request the peer */ 01847 tmp->chan = ast_request(tech, qe->chan->nativeformats, location, &status); 01848 if (!tmp->chan) { /* If we can't, just go on to the next call */ 01849 if (queue_debug) 01850 ast_log(LOG_NOTICE, "Unable to create channel of type '%s' for Queue\n", tech); 01851 if (qe->chan->cdr) 01852 ast_cdr_busy(qe->chan->cdr); 01853 tmp->stillgoing = 0; 01854 01855 update_status(tmp->member->interface, ast_device_state(tmp->member->interface)); 01856 01857 ast_mutex_lock(&qe->parent->lock); 01858 qe->parent->rrpos++; 01859 ast_mutex_unlock(&qe->parent->lock); 01860 01861 (*busies)++; 01862 return 0; 01863 } 01864 01865 /* Increment ring count */ 01866 tmp->member->ringcount++; 01867 tmp->chan->appl = "AppQueue"; 01868 tmp->chan->data = "(Outgoing Line)"; 01869 tmp->chan->whentohangup = 0; 01870 if (tmp->chan->cid.cid_num) 01871 free(tmp->chan->cid.cid_num); 01872 tmp->chan->cid.cid_num = ast_strdup(qe->chan->cid.cid_num); 01873 if (tmp->chan->cid.cid_name) 01874 free(tmp->chan->cid.cid_name); 01875 tmp->chan->cid.cid_name = ast_strdup(qe->chan->cid.cid_name); 01876 if (tmp->chan->cid.cid_ani) 01877 free(tmp->chan->cid.cid_ani); 01878 tmp->chan->cid.cid_ani = ast_strdup(qe->chan->cid.cid_ani); 01879 01880 /* Inherit specially named variables from parent channel */ 01881 ast_channel_inherit_variables(qe->chan, tmp->chan); 01882 01883 /* Presense of ADSI CPE on outgoing channel follows ours */ 01884 tmp->chan->adsicpe = qe->chan->adsicpe; 01885 01886 /* Inherit context and extension */ 01887 ast_channel_lock(qe->chan); 01888 macrocontext = pbx_builtin_getvar_helper(qe->chan, "MACRO_CONTEXT"); 01889 if (!ast_strlen_zero(macrocontext)) 01890 ast_copy_string(tmp->chan->dialcontext, macrocontext, sizeof(tmp->chan->dialcontext)); 01891 else 01892 ast_copy_string(tmp->chan->dialcontext, qe->chan->context, sizeof(tmp->chan->dialcontext)); 01893 macroexten = pbx_builtin_getvar_helper(qe->chan, "MACRO_EXTEN"); 01894 if (!ast_strlen_zero(macroexten)) 01895 ast_copy_string(tmp->chan->exten, macroexten, sizeof(tmp->chan->exten)); 01896 else 01897 ast_copy_string(tmp->chan->exten, qe->chan->exten, sizeof(tmp->chan->exten)); 01898 ast_channel_unlock(qe->chan); 01899 01900 /* Place the call, but don't wait on the answer */ 01901 if ((res = ast_call(tmp->chan, location, 0))) { 01902 /* Again, keep going even if there's an error */ 01903 if (option_debug) 01904 ast_log(LOG_DEBUG, "ast call on peer returned %d\n", res); 01905 if (option_verbose > 2) 01906 ast_verbose(VERBOSE_PREFIX_3 "Couldn't call %s\n", tmp->interface); 01907 do_hang(tmp); 01908 (*busies)++; 01909 return 0; 01910 } else if (qe->parent->eventwhencalled) { 01911 char vars[2048]; 01912 01913 manager_event(EVENT_FLAG_AGENT, "AgentCalled", 01914 "AgentCalled: %s\r\n" 01915 "AgentName: %s\r\n" 01916 "ChannelCalling: %s\r\n" 01917 "CallerID: %s\r\n" 01918 "CallerIDName: %s\r\n" 01919 "Context: %s\r\n" 01920 "Extension: %s\r\n" 01921 "Priority: %d\r\n" 01922 "%s", 01923 tmp->interface, tmp->member->membername, qe->chan->name, 01924 tmp->chan->cid.cid_num ? tmp->chan->cid.cid_num : "unknown", 01925 tmp->chan->cid.cid_name ? tmp->chan->cid.cid_name : "unknown", 01926 qe->chan->context, qe->chan->exten, qe->chan->priority, 01927 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : ""); 01928 if (option_verbose > 2) 01929 ast_verbose(VERBOSE_PREFIX_3 "Called %s\n", tmp->interface); 01930 } 01931 01932 return 1; 01933 }
static int ring_one | ( | struct queue_ent * | qe, | |
struct callattempt * | outgoing, | |||
int * | busies | |||
) | [static] |
Place a call to a queue member.
Once metrics have been calculated for each member, this function is used to place a call to the appropriate member (or members). The low-level channel-handling and error detection is handled in ring_entry
Returns 1 if a member was called successfully, 0 otherwise
Definition at line 1959 of file app_queue.c.
References ast_log(), callattempt::chan, find_best(), callattempt::interface, LOG_DEBUG, callattempt::metric, option_debug, queue_ent::parent, callattempt::q_next, QUEUE_STRATEGY_RINGALL, ring_entry(), callattempt::stillgoing, and call_queue::strategy.
Referenced by try_calling(), and wait_for_answer().
01960 { 01961 int ret = 0; 01962 01963 while (ret == 0) { 01964 struct callattempt *best = find_best(outgoing); 01965 if (!best) { 01966 if (option_debug) 01967 ast_log(LOG_DEBUG, "Nobody left to try ringing in queue\n"); 01968 break; 01969 } 01970 if (qe->parent->strategy == QUEUE_STRATEGY_RINGALL) { 01971 struct callattempt *cur; 01972 /* Ring everyone who shares this best metric (for ringall) */ 01973 for (cur = outgoing; cur; cur = cur->q_next) { 01974 if (cur->stillgoing && !cur->chan && cur->metric <= best->metric) { 01975 if (option_debug) 01976 ast_log(LOG_DEBUG, "(Parallel) Trying '%s' with metric %d\n", cur->interface, cur->metric); 01977 ret |= ring_entry(qe, cur, busies); 01978 } 01979 } 01980 } else { 01981 /* Ring just the best channel */ 01982 if (option_debug) 01983 ast_log(LOG_DEBUG, "Trying '%s' with metric %d\n", best->interface, best->metric); 01984 ret = ring_entry(qe, best, busies); 01985 } 01986 } 01987 01988 return ret; 01989 }
static void rna | ( | int | rnatime, | |
struct queue_ent * | qe, | |||
char * | interface, | |||
char * | membername | |||
) | [static] |
RNA == Ring No Answer. Common code that is executed when we try a queue member and they don't answer.
Definition at line 2073 of file app_queue.c.
References ast_queue_log(), ast_verbose(), call_queue::autopause, queue_ent::chan, call_queue::name, option_verbose, queue_ent::parent, set_member_paused(), and VERBOSE_PREFIX_3.
02074 { 02075 if (option_verbose > 2) 02076 ast_verbose( VERBOSE_PREFIX_3 "Nobody picked up in %d ms\n", rnatime); 02077 ast_queue_log(qe->parent->name, qe->chan->uniqueid, membername, "RINGNOANSWER", "%d", rnatime); 02078 if (qe->parent->autopause) { 02079 if (!set_member_paused(qe->parent->name, interface, 1)) { 02080 if (option_verbose > 2) 02081 ast_verbose( VERBOSE_PREFIX_3 "Auto-Pausing Queue Member %s in queue %s since they failed to answer.\n", interface, qe->parent->name); 02082 } else { 02083 if (option_verbose > 2) 02084 ast_verbose( VERBOSE_PREFIX_3 "Failed to pause Queue Member %s in queue %s!\n", interface, qe->parent->name); 02085 } 02086 } 02087 return; 02088 }
static int rqm_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Definition at line 3554 of file app_queue.c.
References AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_goto_if_exists(), ast_log(), ast_module_user_add, ast_module_user_remove, ast_opt_priority_jumping, ast_queue_log(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), ast_module_user::chan, ast_channel::context, LOG_DEBUG, LOG_NOTICE, LOG_WARNING, parse(), pbx_builtin_setvar_helper(), remove_from_queue(), RES_EXISTS, RES_NOSUCHQUEUE, RES_NOT_DYNAMIC, and RES_OKAY.
Referenced by load_module().
03555 { 03556 int res=-1; 03557 struct ast_module_user *lu; 03558 char *parse, *temppos = NULL; 03559 int priority_jump = 0; 03560 AST_DECLARE_APP_ARGS(args, 03561 AST_APP_ARG(queuename); 03562 AST_APP_ARG(interface); 03563 AST_APP_ARG(options); 03564 ); 03565 03566 03567 if (ast_strlen_zero(data)) { 03568 ast_log(LOG_WARNING, "RemoveQueueMember requires an argument (queuename[|interface[|options]])\n"); 03569 return -1; 03570 } 03571 03572 parse = ast_strdupa(data); 03573 03574 AST_STANDARD_APP_ARGS(args, parse); 03575 03576 lu = ast_module_user_add(chan); 03577 03578 if (ast_strlen_zero(args.interface)) { 03579 args.interface = ast_strdupa(chan->name); 03580 temppos = strrchr(args.interface, '-'); 03581 if (temppos) 03582 *temppos = '\0'; 03583 } 03584 03585 if (args.options) { 03586 if (strchr(args.options, 'j')) 03587 priority_jump = 1; 03588 } 03589 03590 switch (remove_from_queue(args.queuename, args.interface)) { 03591 case RES_OKAY: 03592 ast_queue_log(args.queuename, chan->uniqueid, args.interface, "REMOVEMEMBER", "%s", ""); 03593 ast_log(LOG_NOTICE, "Removed interface '%s' from queue '%s'\n", args.interface, args.queuename); 03594 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "REMOVED"); 03595 res = 0; 03596 break; 03597 case RES_EXISTS: 03598 ast_log(LOG_DEBUG, "Unable to remove interface '%s' from queue '%s': Not there\n", args.interface, args.queuename); 03599 if (priority_jump || ast_opt_priority_jumping) 03600 ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101); 03601 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOTINQUEUE"); 03602 res = 0; 03603 break; 03604 case RES_NOSUCHQUEUE: 03605 ast_log(LOG_WARNING, "Unable to remove interface from queue '%s': No such queue\n", args.queuename); 03606 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOSUCHQUEUE"); 03607 res = 0; 03608 break; 03609 case RES_NOT_DYNAMIC: 03610 ast_log(LOG_WARNING, "Unable to remove interface from queue '%s': '%s' is not a dynamic member\n", args.queuename, args.interface); 03611 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOTDYNAMIC"); 03612 res = 0; 03613 break; 03614 } 03615 03616 ast_module_user_remove(lu); 03617 03618 return res; 03619 }
static void rr_dep_warning | ( | void | ) | [static] |
Definition at line 452 of file app_queue.c.
References ast_log(), and LOG_NOTICE.
Referenced by reload_queues().
00453 { 00454 static unsigned int warned = 0; 00455 00456 if (!warned) { 00457 ast_log(LOG_NOTICE, "The 'roundrobin' queue strategy is deprecated. Please use the 'rrmemory' strategy instead.\n"); 00458 warned = 1; 00459 } 00460 }
static void rt_handle_member_record | ( | struct call_queue * | q, | |
char * | interface, | |||
const char * | membername, | |||
const char * | penalty_str, | |||
const char * | paused_str | |||
) | [static] |
Definition at line 1112 of file app_queue.c.
References add_to_interfaces(), ao2_find(), ao2_ref(), create_queue_member(), member::dead, member::interface, call_queue::membercount, call_queue::members, member::paused, member::penalty, and member::realtime.
Referenced by update_realtime_members().
01113 { 01114 struct member *m, tmpmem; 01115 int penalty = 0; 01116 int paused = 0; 01117 01118 if (penalty_str) { 01119 penalty = atoi(penalty_str); 01120 if (penalty < 0) 01121 penalty = 0; 01122 } 01123 01124 if (paused_str) { 01125 paused = atoi(paused_str); 01126 if (paused < 0) 01127 paused = 0; 01128 } 01129 01130 /* Find the member, or the place to put a new one. */ 01131 ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface)); 01132 m = ao2_find(q->members, &tmpmem, OBJ_POINTER); 01133 01134 /* Create a new one if not found, else update penalty */ 01135 if (!m) { 01136 if ((m = create_queue_member(interface, membername, penalty, paused))) { 01137 m->dead = 0; 01138 m->realtime = 1; 01139 add_to_interfaces(interface); 01140 ao2_link(q->members, m); 01141 ao2_ref(m, -1); 01142 m = NULL; 01143 q->membercount++; 01144 } 01145 } else { 01146 m->dead = 0; /* Do not delete this one. */ 01147 if (paused_str) 01148 m->paused = paused; 01149 m->penalty = penalty; 01150 ao2_ref(m, -1); 01151 } 01152 }
static int say_periodic_announcement | ( | struct queue_ent * | qe | ) | [static] |
Definition at line 2015 of file app_queue.c.
References ast_moh_start(), ast_moh_stop(), ast_verbose(), queue_ent::chan, queue_ent::last_periodic_announce_sound, queue_ent::last_periodic_announce_time, MAX_PERIODIC_ANNOUNCEMENTS, queue_ent::moh, option_verbose, queue_ent::parent, call_queue::periodicannouncefrequency, play_file(), call_queue::sound_periodicannounce, valid_exit(), and VERBOSE_PREFIX_3.
Referenced by queue_exec(), and wait_our_turn().
02016 { 02017 int res = 0; 02018 time_t now; 02019 02020 /* Get the current time */ 02021 time(&now); 02022 02023 /* Check to see if it is time to announce */ 02024 if ((now - qe->last_periodic_announce_time) < qe->parent->periodicannouncefrequency) 02025 return 0; 02026 02027 /* Stop the music on hold so we can play our own file */ 02028 ast_moh_stop(qe->chan); 02029 02030 if (option_verbose > 2) 02031 ast_verbose(VERBOSE_PREFIX_3 "Playing periodic announcement\n"); 02032 02033 /* Check to make sure we have a sound file. If not, reset to the first sound file */ 02034 if (qe->last_periodic_announce_sound >= MAX_PERIODIC_ANNOUNCEMENTS || !strlen(qe->parent->sound_periodicannounce[qe->last_periodic_announce_sound])) { 02035 qe->last_periodic_announce_sound = 0; 02036 } 02037 02038 /* play the announcement */ 02039 res = play_file(qe->chan, qe->parent->sound_periodicannounce[qe->last_periodic_announce_sound]); 02040 02041 if ((res > 0 && !valid_exit(qe, res)) || res < 0) 02042 res = 0; 02043 02044 /* Resume Music on Hold if the caller is going to stay in the queue */ 02045 if (!res) 02046 ast_moh_start(qe->chan, qe->moh, NULL); 02047 02048 /* update last_periodic_announce_time */ 02049 qe->last_periodic_announce_time = now; 02050 02051 /* Update the current periodic announcement to the next announcement */ 02052 qe->last_periodic_announce_sound++; 02053 02054 return res; 02055 }
static int say_position | ( | struct queue_ent * | qe | ) | [static] |
Definition at line 1532 of file app_queue.c.
References call_queue::announcefrequency, call_queue::announceholdtime, ANNOUNCEHOLDTIME_ONCE, AST_DIGIT_ANY, ast_moh_start(), ast_moh_stop(), ast_say_number(), ast_verbose(), queue_ent::chan, call_queue::holdtime, queue_ent::last_pos, queue_ent::last_pos_said, queue_ent::moh, call_queue::name, option_verbose, queue_ent::parent, play_file(), queue_ent::pos, call_queue::roundingseconds, call_queue::sound_calls, call_queue::sound_holdtime, call_queue::sound_lessthan, call_queue::sound_minutes, call_queue::sound_next, call_queue::sound_seconds, call_queue::sound_thanks, call_queue::sound_thereare, queue_ent::start, valid_exit(), and VERBOSE_PREFIX_3.
Referenced by queue_exec(), and wait_our_turn().
01533 { 01534 int res = 0, avgholdmins, avgholdsecs; 01535 time_t now; 01536 01537 /* Check to see if this is ludicrous -- if we just announced position, don't do it again*/ 01538 time(&now); 01539 if ((now - qe->last_pos) < 15) 01540 return 0; 01541 01542 /* If either our position has changed, or we are over the freq timer, say position */ 01543 if ((qe->last_pos_said == qe->pos) && ((now - qe->last_pos) < qe->parent->announcefrequency)) 01544 return 0; 01545 01546 ast_moh_stop(qe->chan); 01547 /* Say we're next, if we are */ 01548 if (qe->pos == 1) { 01549 res = play_file(qe->chan, qe->parent->sound_next); 01550 if (res) 01551 goto playout; 01552 else 01553 goto posout; 01554 } else { 01555 res = play_file(qe->chan, qe->parent->sound_thereare); 01556 if (res) 01557 goto playout; 01558 res = ast_say_number(qe->chan, qe->pos, AST_DIGIT_ANY, qe->chan->language, (char *) NULL); /* Needs gender */ 01559 if (res) 01560 goto playout; 01561 res = play_file(qe->chan, qe->parent->sound_calls); 01562 if (res) 01563 goto playout; 01564 } 01565 /* Round hold time to nearest minute */ 01566 avgholdmins = abs(((qe->parent->holdtime + 30) - (now - qe->start)) / 60); 01567 01568 /* If they have specified a rounding then round the seconds as well */ 01569 if (qe->parent->roundingseconds) { 01570 avgholdsecs = (abs(((qe->parent->holdtime + 30) - (now - qe->start))) - 60 * avgholdmins) / qe->parent->roundingseconds; 01571 avgholdsecs *= qe->parent->roundingseconds; 01572 } else { 01573 avgholdsecs = 0; 01574 } 01575 01576 if (option_verbose > 2) 01577 ast_verbose(VERBOSE_PREFIX_3 "Hold time for %s is %d minutes %d seconds\n", qe->parent->name, avgholdmins, avgholdsecs); 01578 01579 /* If the hold time is >1 min, if it's enabled, and if it's not 01580 supposed to be only once and we have already said it, say it */ 01581 if ((avgholdmins+avgholdsecs) > 0 && (qe->parent->announceholdtime) && 01582 (!(qe->parent->announceholdtime == ANNOUNCEHOLDTIME_ONCE) && qe->last_pos)) { 01583 res = play_file(qe->chan, qe->parent->sound_holdtime); 01584 if (res) 01585 goto playout; 01586 01587 if (avgholdmins > 0) { 01588 if (avgholdmins < 2) { 01589 res = play_file(qe->chan, qe->parent->sound_lessthan); 01590 if (res) 01591 goto playout; 01592 01593 res = ast_say_number(qe->chan, 2, AST_DIGIT_ANY, qe->chan->language, NULL); 01594 if (res) 01595 goto playout; 01596 } else { 01597 res = ast_say_number(qe->chan, avgholdmins, AST_DIGIT_ANY, qe->chan->language, NULL); 01598 if (res) 01599 goto playout; 01600 } 01601 01602 res = play_file(qe->chan, qe->parent->sound_minutes); 01603 if (res) 01604 goto playout; 01605 } 01606 if (avgholdsecs>0) { 01607 res = ast_say_number(qe->chan, avgholdsecs, AST_DIGIT_ANY, qe->chan->language, NULL); 01608 if (res) 01609 goto playout; 01610 01611 res = play_file(qe->chan, qe->parent->sound_seconds); 01612 if (res) 01613 goto playout; 01614 } 01615 01616 } 01617 01618 posout: 01619 if (option_verbose > 2) 01620 ast_verbose(VERBOSE_PREFIX_3 "Told %s in %s their queue position (which was %d)\n", 01621 qe->chan->name, qe->parent->name, qe->pos); 01622 res = play_file(qe->chan, qe->parent->sound_thanks); 01623 01624 playout: 01625 if ((res > 0 && !valid_exit(qe, res)) || res < 0) 01626 res = 0; 01627 01628 /* Set our last_pos indicators */ 01629 qe->last_pos = now; 01630 qe->last_pos_said = qe->pos; 01631 01632 /* Don't restart music on hold if we're about to exit the caller from the queue */ 01633 if (!res) 01634 ast_moh_start(qe->chan, qe->moh, NULL); 01635 01636 return res; 01637 }
static int set_member_paused | ( | const char * | queuename, | |
const char * | interface, | |||
int | paused | |||
) | [static] |
Definition at line 3297 of file app_queue.c.
References ao2_ref(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_queue_log(), ast_strlen_zero(), dump_queue_members(), EVENT_FLAG_AGENT, member::interface, interface_exists(), call_queue::lock, LOG_DEBUG, manager_event(), member::membername, call_queue::name, member::paused, member::realtime, RESULT_FAILURE, RESULT_SUCCESS, and update_realtime_member_field().
Referenced by manager_pause_queue_member(), pqm_exec(), rna(), and upqm_exec().
03298 { 03299 int found = 0; 03300 struct call_queue *q; 03301 struct member *mem; 03302 03303 /* Special event for when all queues are paused - individual events still generated */ 03304 /* XXX In all other cases, we use the membername, but since this affects all queues, we cannot */ 03305 if (ast_strlen_zero(queuename)) 03306 ast_queue_log("NONE", "NONE", interface, (paused ? "PAUSEALL" : "UNPAUSEALL"), "%s", ""); 03307 03308 AST_LIST_LOCK(&queues); 03309 AST_LIST_TRAVERSE(&queues, q, list) { 03310 ast_mutex_lock(&q->lock); 03311 if (ast_strlen_zero(queuename) || !strcasecmp(q->name, queuename)) { 03312 if ((mem = interface_exists(q, interface))) { 03313 found++; 03314 if (mem->paused == paused) 03315 ast_log(LOG_DEBUG, "%spausing already-%spaused queue member %s:%s\n", (paused ? "" : "un"), (paused ? "" : "un"), q->name, interface); 03316 mem->paused = paused; 03317 03318 if (queue_persistent_members) 03319 dump_queue_members(q); 03320 03321 if (mem->realtime) 03322 update_realtime_member_field(mem, q->name, "paused", paused ? "1" : "0"); 03323 03324 ast_queue_log(q->name, "NONE", mem->membername, (paused ? "PAUSE" : "UNPAUSE"), "%s", ""); 03325 03326 manager_event(EVENT_FLAG_AGENT, "QueueMemberPaused", 03327 "Queue: %s\r\n" 03328 "Location: %s\r\n" 03329 "MemberName: %s\r\n" 03330 "Paused: %d\r\n", 03331 q->name, mem->interface, mem->membername, paused); 03332 ao2_ref(mem, -1); 03333 } 03334 } 03335 ast_mutex_unlock(&q->lock); 03336 } 03337 AST_LIST_UNLOCK(&queues); 03338 03339 return found ? RESULT_SUCCESS : RESULT_FAILURE; 03340 }
static void set_queue_result | ( | struct ast_channel * | chan, | |
enum queue_result | res | |||
) | [static] |
sets the QUEUESTATUS channel variable
Definition at line 471 of file app_queue.c.
References queue_ent::chan, pbx_builtin_setvar_helper(), queue_results, and text.
Referenced by queue_exec().
00472 { 00473 int i; 00474 00475 for (i = 0; i < sizeof(queue_results) / sizeof(queue_results[0]); i++) { 00476 if (queue_results[i].id == res) { 00477 pbx_builtin_setvar_helper(chan, "QUEUESTATUS", queue_results[i].text); 00478 return; 00479 } 00480 } 00481 }
static int statechange_queue | ( | const char * | dev, | |
int | state, | |||
void * | ign | |||
) | [static] |
Producer of the statechange queue.
Definition at line 732 of file app_queue.c.
References ast_calloc, ast_cond_signal(), AST_LIST_INSERT_TAIL, ast_mutex_lock(), ast_mutex_unlock(), and device_state.
Referenced by load_module(), and unload_module().
00733 { 00734 struct statechange *sc; 00735 00736 if (!(sc = ast_calloc(1, sizeof(*sc) + strlen(dev) + 1))) 00737 return 0; 00738 00739 sc->state = state; 00740 strcpy(sc->dev, dev); 00741 00742 ast_mutex_lock(&device_state.lock); 00743 AST_LIST_INSERT_TAIL(&device_state.state_change_q, sc, entry); 00744 ast_cond_signal(&device_state.cond); 00745 ast_mutex_unlock(&device_state.lock); 00746 00747 return 0; 00748 }
static int store_next | ( | struct queue_ent * | qe, | |
struct callattempt * | outgoing | |||
) | [static] |
Definition at line 1991 of file app_queue.c.
References ast_log(), find_best(), callattempt::interface, LOG_DEBUG, callattempt::metric, option_debug, queue_ent::parent, call_queue::rrpos, and call_queue::wrapped.
Referenced by try_calling().
01992 { 01993 struct callattempt *best = find_best(outgoing); 01994 01995 if (best) { 01996 /* Ring just the best channel */ 01997 if (option_debug) 01998 ast_log(LOG_DEBUG, "Next is '%s' with metric %d\n", best->interface, best->metric); 01999 qe->parent->rrpos = best->metric % 1000; 02000 } else { 02001 /* Just increment rrpos */ 02002 if (qe->parent->wrapped) { 02003 /* No more channels, start over */ 02004 qe->parent->rrpos = 0; 02005 } else { 02006 /* Prioritize next entry */ 02007 qe->parent->rrpos++; 02008 } 02009 } 02010 qe->parent->wrapped = 0; 02011 02012 return 0; 02013 }
static int strat2int | ( | const char * | strategy | ) | [static] |
Definition at line 495 of file app_queue.c.
References name, and strategies.
Referenced by queue_set_param().
00496 { 00497 int x; 00498 00499 for (x = 0; x < sizeof(strategies) / sizeof(strategies[0]); x++) { 00500 if (!strcasecmp(strategy, strategies[x].name)) 00501 return strategies[x].strategy; 00502 } 00503 00504 return -1; 00505 }
static int try_calling | ( | struct queue_ent * | qe, | |
const char * | options, | |||
char * | announceoverride, | |||
const char * | url, | |||
int * | tries, | |||
int * | noption, | |||
const char * | agi | |||
) | [static] |
A large function which calls members, updates statistics, and bridges the caller and a member.
Here is the process of this function 1. Process any options passed to the Queue() application. Options here mean the third argument to Queue() 2. Iterate trough the members of the queue, creating a callattempt corresponding to each member. During this iteration, we also check the dialed_interfaces datastore to see if we have already attempted calling this member. If we have, we do not create a callattempt. This is in place to prevent call forwarding loops. Also during each iteration, we call calc_metric to determine which members should be rung when. 3. Call ring_one to place a call to the appropriate member(s) 4. Call wait_for_answer to wait for an answer. If no one answers, return. 5. Take care of any holdtime announcements, member delays, or other options which occur after a call has been answered. 6. Start the monitor or mixmonitor if the option is set 7. Remove the caller from the queue to allow other callers to advance 8. Bridge the call. 9. Do any post processing after the call has disconnected.
[in] | qe | the queue_ent structure which corresponds to the caller attempting to reach members |
[in] | options | the options passed as the third parameter to the Queue() application |
[in] | url | the url passed as the fourth parameter to the Queue() application |
[in,out] | tries | the number of times we have tried calling queue members |
[out] | noption | set if the call to Queue() has the 'n' option set. |
[in] | agi | the agi passed as the fifth parameter to the Queue() application |
Definition at line 2592 of file app_queue.c.
References ast_channel::_softhangup, ast_channel::_state, queue_ent::announce, ao2_iterator_init(), ao2_iterator_next(), ao2_ref(), app, ast_autoservice_start(), ast_autoservice_stop(), ast_bridge_call(), ast_calloc, AST_CDR_FLAG_LOCKED, ast_cdr_setdestchan(), ast_channel_datastore_add(), ast_channel_datastore_alloc(), ast_channel_datastore_find(), ast_channel_datastore_free(), ast_channel_datastore_remove(), ast_channel_lock, ast_channel_make_compatible(), ast_channel_sendurl(), ast_channel_setoption(), ast_channel_supports_html(), ast_channel_unlock, ast_clear_flag, AST_DEVICE_NOT_INUSE, AST_DIGIT_ANY, AST_FEATURE_AUTOMON, AST_FEATURE_DISCONNECT, AST_FEATURE_REDIRECT, ast_hangup(), AST_LIST_HEAD, AST_LIST_HEAD_INIT, AST_LIST_INSERT_TAIL, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), AST_MAX_CONTEXT, AST_MAX_EXTENSION, ast_moh_stop(), ast_monitor_setjoinfiles(), ast_monitor_start(), ast_mutex_lock(), ast_mutex_unlock(), AST_OPTION_TONE_VERIFY, AST_PBX_NO_HANGUP_PEER, ast_queue_log(), ast_random(), ast_safe_sleep(), ast_say_number(), ast_set_flag, AST_STATE_UP, ast_strdupa, ast_strlen_zero(), ast_test_flag, calc_metric(), ast_channel::cdr, callattempt::chan, queue_ent::chan, ast_channel::context, ast_datastore::data, DATASTORE_INHERIT_FOREVER, di, dialed_interface_info, EVENT_FLAG_AGENT, call_queue::eventwhencalled, queue_ent::expire, ast_channel::exten, free, queue_ent::handled, hangupcalls(), ast_datastore::inheritance, member::interface, member::lastcall, leave_queue(), call_queue::lock, LOG_DEBUG, LOG_NOTICE, LOG_WARNING, manager_event(), callattempt::member, call_queue::membercount, call_queue::memberdelay, member::membername, call_queue::members, call_queue::monfmt, call_queue::monjoin, call_queue::montype, call_queue::name, queue_ent::opos, option_debug, queue_ent::parent, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), pbx_exec(), pbx_findapp(), pbx_substitute_variables_helper(), queue_ent::pending, play_file(), queue_ent::pos, QUEUE_EVENT_VARIABLES, QUEUE_STRATEGY_ROUNDROBIN, recalc_holdtime(), record_abandoned(), call_queue::reportholdtime, ring_one(), member::ringcount, call_queue::ringlimit, call_queue::servicelevel, call_queue::setinterfacevar, call_queue::sound_lessthan, call_queue::sound_minutes, call_queue::sound_reporthold, queue_ent::start, member::status, store_next(), call_queue::strategy, ast_channel::tech, call_queue::timeout, queue_ent::tries, ast_channel_tech::type, ast_cdr::uniqueid, update_queue(), vars2manager(), and wait_for_answer().
Referenced by queue_exec().
02593 { 02594 struct member *cur; 02595 struct callattempt *outgoing = NULL; /* the list of calls we are building */ 02596 int to; 02597 char oldexten[AST_MAX_EXTENSION]=""; 02598 char oldcontext[AST_MAX_CONTEXT]=""; 02599 char queuename[256]=""; 02600 struct ast_channel *peer; 02601 struct ast_channel *which; 02602 struct callattempt *lpeer; 02603 struct member *member; 02604 struct ast_app *app; 02605 int res = 0, bridge = 0; 02606 int numbusies = 0; 02607 int x=0; 02608 char *announce = NULL; 02609 char digit = 0; 02610 time_t callstart; 02611 time_t now = time(NULL); 02612 struct ast_bridge_config bridge_config; 02613 char nondataquality = 1; 02614 char *agiexec = NULL; 02615 int ret = 0; 02616 const char *monitorfilename; 02617 const char *monitor_exec; 02618 const char *monitor_options; 02619 char tmpid[256], tmpid2[256]; 02620 char meid[1024], meid2[1024]; 02621 char mixmonargs[1512]; 02622 struct ast_app *mixmonapp = NULL; 02623 char *p; 02624 char vars[2048]; 02625 int forwardsallowed = 1; 02626 int callcompletedinsl; 02627 struct ao2_iterator memi; 02628 struct ast_datastore *datastore; 02629 02630 ast_channel_lock(qe->chan); 02631 datastore = ast_channel_datastore_find(qe->chan, &dialed_interface_info, NULL); 02632 ast_channel_unlock(qe->chan); 02633 02634 memset(&bridge_config, 0, sizeof(bridge_config)); 02635 time(&now); 02636 02637 for (; options && *options; options++) 02638 switch (*options) { 02639 case 't': 02640 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_REDIRECT); 02641 break; 02642 case 'T': 02643 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_REDIRECT); 02644 break; 02645 case 'w': 02646 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_AUTOMON); 02647 break; 02648 case 'W': 02649 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_AUTOMON); 02650 break; 02651 case 'd': 02652 nondataquality = 0; 02653 break; 02654 case 'h': 02655 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_DISCONNECT); 02656 break; 02657 case 'H': 02658 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT); 02659 break; 02660 case 'n': 02661 if (qe->parent->strategy == QUEUE_STRATEGY_ROUNDROBIN || qe->parent->strategy == QUEUE_STRATEGY_RRMEMORY) 02662 (*tries)++; 02663 else 02664 *tries = qe->parent->membercount; 02665 *noption = 1; 02666 break; 02667 case 'i': 02668 forwardsallowed = 0; 02669 break; 02670 } 02671 02672 /* Hold the lock while we setup the outgoing calls */ 02673 if (use_weight) 02674 AST_LIST_LOCK(&queues); 02675 ast_mutex_lock(&qe->parent->lock); 02676 if (option_debug) 02677 ast_log(LOG_DEBUG, "%s is trying to call a queue member.\n", 02678 qe->chan->name); 02679 ast_copy_string(queuename, qe->parent->name, sizeof(queuename)); 02680 if (!ast_strlen_zero(qe->announce)) 02681 announce = qe->announce; 02682 if (!ast_strlen_zero(announceoverride)) 02683 announce = announceoverride; 02684 02685 memi = ao2_iterator_init(qe->parent->members, 0); 02686 while ((cur = ao2_iterator_next(&memi))) { 02687 struct callattempt *tmp = ast_calloc(1, sizeof(*tmp)); 02688 struct ast_dialed_interface *di; 02689 AST_LIST_HEAD(, ast_dialed_interface) *dialed_interfaces; 02690 if (!tmp) { 02691 ao2_ref(cur, -1); 02692 ast_mutex_unlock(&qe->parent->lock); 02693 if (use_weight) 02694 AST_LIST_UNLOCK(&queues); 02695 goto out; 02696 } 02697 if (!datastore) { 02698 if (!(datastore = ast_channel_datastore_alloc(&dialed_interface_info, NULL))) { 02699 ao2_ref(cur, -1); 02700 ast_mutex_unlock(&qe->parent->lock); 02701 if (use_weight) 02702 AST_LIST_UNLOCK(&queues); 02703 free(tmp); 02704 goto out; 02705 } 02706 datastore->inheritance = DATASTORE_INHERIT_FOREVER; 02707 if (!(dialed_interfaces = ast_calloc(1, sizeof(*dialed_interfaces)))) { 02708 ao2_ref(cur, -1); 02709 ast_mutex_unlock(&qe->parent->lock); 02710 if (use_weight) 02711 AST_LIST_UNLOCK(&queues); 02712 free(tmp); 02713 goto out; 02714 } 02715 datastore->data = dialed_interfaces; 02716 AST_LIST_HEAD_INIT(dialed_interfaces); 02717 02718 ast_channel_lock(qe->chan); 02719 ast_channel_datastore_add(qe->chan, datastore); 02720 ast_channel_unlock(qe->chan); 02721 } else 02722 dialed_interfaces = datastore->data; 02723 02724 AST_LIST_LOCK(dialed_interfaces); 02725 AST_LIST_TRAVERSE(dialed_interfaces, di, list) { 02726 if (!strcasecmp(cur->interface, di->interface)) { 02727 ast_log(LOG_DEBUG, "Skipping dialing interface '%s' since it has already been dialed\n", 02728 di->interface); 02729 break; 02730 } 02731 } 02732 AST_LIST_UNLOCK(dialed_interfaces); 02733 02734 if (di) { 02735 free(tmp); 02736 continue; 02737 } 02738 02739 /* It is always ok to dial a Local interface. We only keep track of 02740 * which "real" interfaces have been dialed. The Local channel will 02741 * inherit this list so that if it ends up dialing a real interface, 02742 * it won't call one that has already been called. */ 02743 if (strncasecmp(cur->interface, "Local/", 6)) { 02744 if (!(di = ast_calloc(1, sizeof(*di) + strlen(cur->interface)))) { 02745 ao2_ref(cur, -1); 02746 ast_mutex_unlock(&qe->parent->lock); 02747 if (use_weight) 02748 AST_LIST_UNLOCK(&queues); 02749 free(tmp); 02750 goto out; 02751 } 02752 strcpy(di->interface, cur->interface); 02753 02754 AST_LIST_LOCK(dialed_interfaces); 02755 AST_LIST_INSERT_TAIL(dialed_interfaces, di, list); 02756 AST_LIST_UNLOCK(dialed_interfaces); 02757 } 02758 02759 tmp->stillgoing = -1; 02760 tmp->member = cur; 02761 tmp->oldstatus = cur->status; 02762 tmp->lastcall = cur->lastcall; 02763 ast_copy_string(tmp->interface, cur->interface, sizeof(tmp->interface)); 02764 if (qe->tries == 0 && (cur->ringcount >= qe->parent->ringlimit)) { 02765 cur->ringcount = 0; 02766 } 02767 /* Special case: If we ring everyone, go ahead and ring them, otherwise 02768 just calculate their metric for the appropriate strategy */ 02769 if (!calc_metric(qe->parent, cur, x++, qe, tmp)) { 02770 /* Put them in the list of outgoing thingies... We're ready now. 02771 XXX If we're forcibly removed, these outgoing calls won't get 02772 hung up XXX */ 02773 tmp->q_next = outgoing; 02774 outgoing = tmp; 02775 /* If this line is up, don't try anybody else */ 02776 if (outgoing->chan && (outgoing->chan->_state == AST_STATE_UP)) 02777 break; 02778 } else { 02779 ao2_ref(cur, -1); 02780 free(tmp); 02781 } 02782 } 02783 if (qe->expire && (!qe->parent->timeout || (qe->expire - now) <= qe->parent->timeout)) 02784 to = (qe->expire - now) * 1000; 02785 else 02786 to = (qe->parent->timeout) ? qe->parent->timeout * 1000 : -1; 02787 ++qe->pending; 02788 ++qe->tries; 02789 if (option_debug) 02790 ast_log(LOG_DEBUG, "%s is trying to ring one member from %s. This is try number %d\n", 02791 qe->chan->name, queuename, qe->tries); 02792 ast_mutex_unlock(&qe->parent->lock); 02793 ring_one(qe, outgoing, &numbusies); 02794 if (use_weight) 02795 AST_LIST_UNLOCK(&queues); 02796 lpeer = wait_for_answer(qe, outgoing, &to, &digit, numbusies, ast_test_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT), forwardsallowed); 02797 /* The ast_channel_datastore_remove() function could fail here if the 02798 * datastore was moved to another channel during a masquerade. If this is 02799 * the case, don't free the datastore here because later, when the channel 02800 * to which the datastore was moved hangs up, it will attempt to free this 02801 * datastore again, causing a crash 02802 */ 02803 if (datastore && !ast_channel_datastore_remove(qe->chan, datastore)) { 02804 ast_channel_datastore_free(datastore); 02805 } 02806 ast_mutex_lock(&qe->parent->lock); 02807 if (qe->parent->strategy == QUEUE_STRATEGY_RRMEMORY) { 02808 store_next(qe, outgoing); 02809 } 02810 ast_mutex_unlock(&qe->parent->lock); 02811 peer = lpeer ? lpeer->chan : NULL; 02812 if (!peer) { 02813 qe->pending = 0; 02814 if (to) { 02815 /* Must gotten hung up */ 02816 res = -1; 02817 } else { 02818 /* User exited by pressing a digit */ 02819 res = digit; 02820 } 02821 if (queue_debug && res == -1) 02822 ast_log(LOG_NOTICE, "%s: Nobody answered.\n", qe->chan->name); 02823 if (qe->parent->eventwhencalled) { 02824 manager_event(EVENT_FLAG_AGENT, "AgentTimeout", 02825 "Queue: %s\r\n" 02826 "ChannelCalling: %s\r\n" 02827 "Uniqueid: %s\r\n" 02828 "Tries: %d\r\n" 02829 "Holdtime: %ld\r\n", 02830 queuename, qe->chan->name, qe->chan->uniqueid, qe->tries, 02831 (long)time(NULL) - qe->start); 02832 } 02833 } else { /* peer is valid */ 02834 /* Ah ha! Someone answered within the desired timeframe. Of course after this 02835 we will always return with -1 so that it is hung up properly after the 02836 conversation. */ 02837 if (!strcmp(qe->chan->tech->type, "Zap")) 02838 ast_channel_setoption(qe->chan, AST_OPTION_TONE_VERIFY, &nondataquality, sizeof(nondataquality), 0); 02839 if (!strcmp(peer->tech->type, "Zap")) 02840 ast_channel_setoption(peer, AST_OPTION_TONE_VERIFY, &nondataquality, sizeof(nondataquality), 0); 02841 /* Update parameters for the queue */ 02842 time(&now); 02843 recalc_holdtime(qe, (now - qe->start)); 02844 ast_mutex_lock(&qe->parent->lock); 02845 callcompletedinsl = ((now - qe->start) <= qe->parent->servicelevel); 02846 ast_mutex_unlock(&qe->parent->lock); 02847 member = lpeer->member; 02848 /* Increment the refcount for this member, since we're going to be using it for awhile in here. */ 02849 ao2_ref(member, 1); 02850 hangupcalls(outgoing, peer); 02851 outgoing = NULL; 02852 if (announce || qe->parent->reportholdtime || qe->parent->memberdelay) { 02853 int res2; 02854 02855 res2 = ast_autoservice_start(qe->chan); 02856 if (!res2) { 02857 if (qe->parent->memberdelay) { 02858 ast_log(LOG_NOTICE, "Delaying member connect for %d seconds\n", qe->parent->memberdelay); 02859 res2 |= ast_safe_sleep(peer, qe->parent->memberdelay * 1000); 02860 } 02861 if (!res2 && announce) { 02862 play_file(peer, announce); 02863 } 02864 if (!res2 && qe->parent->reportholdtime) { 02865 if (!play_file(peer, qe->parent->sound_reporthold)) { 02866 int holdtime; 02867 02868 time(&now); 02869 holdtime = abs((now - qe->start) / 60); 02870 if (holdtime < 2) { 02871 play_file(peer, qe->parent->sound_lessthan); 02872 ast_say_number(peer, 2, AST_DIGIT_ANY, peer->language, NULL); 02873 } else 02874 ast_say_number(peer, holdtime, AST_DIGIT_ANY, peer->language, NULL); 02875 play_file(peer, qe->parent->sound_minutes); 02876 } 02877 } 02878 } 02879 res2 |= ast_autoservice_stop(qe->chan); 02880 if (peer->_softhangup) { 02881 /* Agent must have hung up */ 02882 ast_log(LOG_WARNING, "Agent on %s hungup on the customer.\n", peer->name); 02883 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "AGENTDUMP", "%s", ""); 02884 if (qe->parent->eventwhencalled) 02885 manager_event(EVENT_FLAG_AGENT, "AgentDump", 02886 "Queue: %s\r\n" 02887 "Uniqueid: %s\r\n" 02888 "Channel: %s\r\n" 02889 "Member: %s\r\n" 02890 "MemberName: %s\r\n" 02891 "%s", 02892 queuename, qe->chan->uniqueid, peer->name, member->interface, member->membername, 02893 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : ""); 02894 ast_hangup(peer); 02895 ao2_ref(member, -1); 02896 goto out; 02897 } else if (res2) { 02898 /* Caller must have hung up just before being connected*/ 02899 ast_log(LOG_NOTICE, "Caller was about to talk to agent on %s but the caller hungup.\n", peer->name); 02900 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "ABANDON", "%d|%d|%ld", qe->pos, qe->opos, (long)time(NULL) - qe->start); 02901 record_abandoned(qe); 02902 ast_hangup(peer); 02903 ao2_ref(member, -1); 02904 return -1; 02905 } 02906 } 02907 /* Stop music on hold */ 02908 ast_moh_stop(qe->chan); 02909 /* If appropriate, log that we have a destination channel */ 02910 if (qe->chan->cdr) 02911 ast_cdr_setdestchan(qe->chan->cdr, peer->name); 02912 /* Make sure channels are compatible */ 02913 res = ast_channel_make_compatible(qe->chan, peer); 02914 if (res < 0) { 02915 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "SYSCOMPAT", "%s", ""); 02916 ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", qe->chan->name, peer->name); 02917 record_abandoned(qe); 02918 ast_hangup(peer); 02919 ao2_ref(member, -1); 02920 return -1; 02921 } 02922 02923 if (qe->parent->setinterfacevar) 02924 pbx_builtin_setvar_helper(qe->chan, "MEMBERINTERFACE", member->interface); 02925 02926 /* Begin Monitoring */ 02927 if (qe->parent->monfmt && *qe->parent->monfmt) { 02928 if (!qe->parent->montype) { 02929 if (option_debug) 02930 ast_log(LOG_DEBUG, "Starting Monitor as requested.\n"); 02931 monitorfilename = pbx_builtin_getvar_helper(qe->chan, "MONITOR_FILENAME"); 02932 if (pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC") || pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC_ARGS")) 02933 which = qe->chan; 02934 else 02935 which = peer; 02936 if (monitorfilename) 02937 ast_monitor_start(which, qe->parent->monfmt, monitorfilename, 1 ); 02938 else if (qe->chan->cdr) 02939 ast_monitor_start(which, qe->parent->monfmt, qe->chan->cdr->uniqueid, 1 ); 02940 else { 02941 /* Last ditch effort -- no CDR, make up something */ 02942 snprintf(tmpid, sizeof(tmpid), "chan-%lx", ast_random()); 02943 ast_monitor_start(which, qe->parent->monfmt, tmpid, 1 ); 02944 } 02945 if (qe->parent->monjoin) 02946 ast_monitor_setjoinfiles(which, 1); 02947 } else { 02948 if (option_debug) 02949 ast_log(LOG_DEBUG, "Starting MixMonitor as requested.\n"); 02950 monitorfilename = pbx_builtin_getvar_helper(qe->chan, "MONITOR_FILENAME"); 02951 if (!monitorfilename) { 02952 if (qe->chan->cdr) 02953 ast_copy_string(tmpid, qe->chan->cdr->uniqueid, sizeof(tmpid)-1); 02954 else 02955 snprintf(tmpid, sizeof(tmpid), "chan-%lx", ast_random()); 02956 } else { 02957 ast_copy_string(tmpid2, monitorfilename, sizeof(tmpid2)-1); 02958 for (p = tmpid2; *p ; p++) { 02959 if (*p == '^' && *(p+1) == '{') { 02960 *p = '$'; 02961 } 02962 } 02963 02964 memset(tmpid, 0, sizeof(tmpid)); 02965 pbx_substitute_variables_helper(qe->chan, tmpid2, tmpid, sizeof(tmpid) - 1); 02966 } 02967 02968 monitor_exec = pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC"); 02969 monitor_options = pbx_builtin_getvar_helper(qe->chan, "MONITOR_OPTIONS"); 02970 02971 if (monitor_exec) { 02972 ast_copy_string(meid2, monitor_exec, sizeof(meid2)-1); 02973 for (p = meid2; *p ; p++) { 02974 if (*p == '^' && *(p+1) == '{') { 02975 *p = '$'; 02976 } 02977 } 02978 02979 memset(meid, 0, sizeof(meid)); 02980 pbx_substitute_variables_helper(qe->chan, meid2, meid, sizeof(meid) - 1); 02981 } 02982 02983 snprintf(tmpid2, sizeof(tmpid2)-1, "%s.%s", tmpid, qe->parent->monfmt); 02984 02985 mixmonapp = pbx_findapp("MixMonitor"); 02986 02987 if (strchr(tmpid2, '|')) { 02988 ast_log(LOG_WARNING, "monitor-format (in queues.conf) and MONITOR_FILENAME cannot contain a '|'! Not recording.\n"); 02989 mixmonapp = NULL; 02990 } 02991 02992 if (!monitor_options) 02993 monitor_options = ""; 02994 02995 if (strchr(monitor_options, '|')) { 02996 ast_log(LOG_WARNING, "MONITOR_OPTIONS cannot contain a '|'! Not recording.\n"); 02997 mixmonapp = NULL; 02998 } 02999 03000 if (mixmonapp) { 03001 if (!ast_strlen_zero(monitor_exec)) 03002 snprintf(mixmonargs, sizeof(mixmonargs)-1, "%s|b%s|%s", tmpid2, monitor_options, monitor_exec); 03003 else 03004 snprintf(mixmonargs, sizeof(mixmonargs)-1, "%s|b%s", tmpid2, monitor_options); 03005 03006 if (option_debug) 03007 ast_log(LOG_DEBUG, "Arguments being passed to MixMonitor: %s\n", mixmonargs); 03008 /* We purposely lock the CDR so that pbx_exec does not update the application data */ 03009 if (qe->chan->cdr) 03010 ast_set_flag(qe->chan->cdr, AST_CDR_FLAG_LOCKED); 03011 ret = pbx_exec(qe->chan, mixmonapp, mixmonargs); 03012 if (qe->chan->cdr) 03013 ast_clear_flag(qe->chan->cdr, AST_CDR_FLAG_LOCKED); 03014 03015 } else 03016 ast_log(LOG_WARNING, "Asked to run MixMonitor on this call, but cannot find the MixMonitor app!\n"); 03017 03018 } 03019 } 03020 /* Drop out of the queue at this point, to prepare for next caller */ 03021 leave_queue(qe); 03022 if (!ast_strlen_zero(url) && ast_channel_supports_html(peer)) { 03023 if (option_debug) 03024 ast_log(LOG_DEBUG, "app_queue: sendurl=%s.\n", url); 03025 ast_channel_sendurl(peer, url); 03026 } 03027 if (!ast_strlen_zero(agi)) { 03028 if (option_debug) 03029 ast_log(LOG_DEBUG, "app_queue: agi=%s.\n", agi); 03030 app = pbx_findapp("agi"); 03031 if (app) { 03032 agiexec = ast_strdupa(agi); 03033 ret = pbx_exec(qe->chan, app, agiexec); 03034 } else 03035 ast_log(LOG_WARNING, "Asked to execute an AGI on this channel, but could not find application (agi)!\n"); 03036 } 03037 qe->handled++; 03038 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "CONNECT", "%ld|%s", (long)time(NULL) - qe->start, peer->uniqueid); 03039 if (qe->parent->eventwhencalled) 03040 manager_event(EVENT_FLAG_AGENT, "AgentConnect", 03041 "Queue: %s\r\n" 03042 "Uniqueid: %s\r\n" 03043 "Channel: %s\r\n" 03044 "Member: %s\r\n" 03045 "MemberName: %s\r\n" 03046 "Holdtime: %ld\r\n" 03047 "BridgedChannel: %s\r\n" 03048 "%s", 03049 queuename, qe->chan->uniqueid, peer->name, member->interface, member->membername, 03050 (long)time(NULL) - qe->start, peer->uniqueid, 03051 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : ""); 03052 ast_copy_string(oldcontext, qe->chan->context, sizeof(oldcontext)); 03053 ast_copy_string(oldexten, qe->chan->exten, sizeof(oldexten)); 03054 time(&callstart); 03055 03056 if (member->status == AST_DEVICE_NOT_INUSE) 03057 ast_log(LOG_WARNING, "The device state of this queue member, %s, is still 'Not in Use' when it probably should not be! Please check UPGRADE.txt for correct configuration settings.\n", member->membername); 03058 03059 03060 bridge = ast_bridge_call(qe->chan,peer, &bridge_config); 03061 03062 if (strcasecmp(oldcontext, qe->chan->context) || strcasecmp(oldexten, qe->chan->exten)) { 03063 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "TRANSFER", "%s|%s|%ld|%ld", 03064 qe->chan->exten, qe->chan->context, (long) (callstart - qe->start), 03065 (long) (time(NULL) - callstart)); 03066 } else if (qe->chan->_softhangup) { 03067 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "COMPLETECALLER", "%ld|%ld|%d", 03068 (long) (callstart - qe->start), (long) (time(NULL) - callstart), qe->opos); 03069 if (qe->parent->eventwhencalled) 03070 manager_event(EVENT_FLAG_AGENT, "AgentComplete", 03071 "Queue: %s\r\n" 03072 "Uniqueid: %s\r\n" 03073 "Channel: %s\r\n" 03074 "Member: %s\r\n" 03075 "MemberName: %s\r\n" 03076 "HoldTime: %ld\r\n" 03077 "TalkTime: %ld\r\n" 03078 "Reason: caller\r\n" 03079 "%s", 03080 queuename, qe->chan->uniqueid, peer->name, member->interface, member->membername, 03081 (long)(callstart - qe->start), (long)(time(NULL) - callstart), 03082 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : ""); 03083 } else { 03084 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "COMPLETEAGENT", "%ld|%ld|%d", 03085 (long) (callstart - qe->start), (long) (time(NULL) - callstart), qe->opos); 03086 if (qe->parent->eventwhencalled) 03087 manager_event(EVENT_FLAG_AGENT, "AgentComplete", 03088 "Queue: %s\r\n" 03089 "Uniqueid: %s\r\n" 03090 "Channel: %s\r\n" 03091 "MemberName: %s\r\n" 03092 "HoldTime: %ld\r\n" 03093 "TalkTime: %ld\r\n" 03094 "Reason: agent\r\n" 03095 "%s", 03096 queuename, qe->chan->uniqueid, peer->name, member->membername, (long)(callstart - qe->start), 03097 (long)(time(NULL) - callstart), 03098 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : ""); 03099 } 03100 03101 if (bridge != AST_PBX_NO_HANGUP_PEER) 03102 ast_hangup(peer); 03103 update_queue(qe->parent, member, callcompletedinsl); 03104 res = bridge ? bridge : 1; 03105 ao2_ref(member, -1); 03106 } 03107 out: 03108 hangupcalls(outgoing, NULL); 03109 03110 return res; 03111 }
static int unload_module | ( | void | ) | [static] |
Definition at line 4995 of file app_queue.c.
References ast_cli_unregister_multiple(), ast_cond_signal(), ast_custom_function_unregister(), ast_devstate_del(), ast_manager_unregister(), ast_module_user_hangup_all, ast_mutex_lock(), ast_mutex_unlock(), AST_PTHREADT_NULL, ast_unregister_application(), clear_and_free_interfaces(), cli_queue, device_state, queueagentcount_function, queuemembercount_function, queuememberlist_function, queuewaitingcount_function, and statechange_queue().
04996 { 04997 int res; 04998 04999 if (device_state.thread != AST_PTHREADT_NULL) { 05000 device_state.stop = 1; 05001 ast_mutex_lock(&device_state.lock); 05002 ast_cond_signal(&device_state.cond); 05003 ast_mutex_unlock(&device_state.lock); 05004 pthread_join(device_state.thread, NULL); 05005 } 05006 05007 ast_cli_unregister_multiple(cli_queue, sizeof(cli_queue) / sizeof(struct ast_cli_entry)); 05008 res = ast_manager_unregister("QueueStatus"); 05009 res |= ast_manager_unregister("Queues"); 05010 res |= ast_manager_unregister("QueueStatus"); 05011 res |= ast_manager_unregister("QueueAdd"); 05012 res |= ast_manager_unregister("QueueRemove"); 05013 res |= ast_manager_unregister("QueuePause"); 05014 res |= ast_unregister_application(app_aqm); 05015 res |= ast_unregister_application(app_rqm); 05016 res |= ast_unregister_application(app_pqm); 05017 res |= ast_unregister_application(app_upqm); 05018 res |= ast_unregister_application(app_ql); 05019 res |= ast_unregister_application(app); 05020 res |= ast_custom_function_unregister(&queueagentcount_function); 05021 res |= ast_custom_function_unregister(&queuemembercount_function); 05022 res |= ast_custom_function_unregister(&queuememberlist_function); 05023 res |= ast_custom_function_unregister(&queuewaitingcount_function); 05024 ast_devstate_del(statechange_queue, NULL); 05025 05026 ast_module_user_hangup_all(); 05027 05028 clear_and_free_interfaces(); 05029 05030 return res; 05031 }
static int update_queue | ( | struct call_queue * | q, | |
struct member * | member, | |||
int | callcompletedinsl | |||
) | [static] |
Definition at line 2490 of file app_queue.c.
References ast_mutex_lock(), ast_mutex_unlock(), member::calls, call_queue::callscompleted, call_queue::callscompletedinsl, member::lastcall, and call_queue::lock.
Referenced by try_calling().
02491 { 02492 ast_mutex_lock(&q->lock); 02493 time(&member->lastcall); 02494 member->calls++; 02495 q->callscompleted++; 02496 if (callcompletedinsl) 02497 q->callscompletedinsl++; 02498 ast_mutex_unlock(&q->lock); 02499 return 0; 02500 }
static int update_realtime_member_field | ( | struct member * | mem, | |
const char * | queue_name, | |||
const char * | field, | |||
const char * | value | |||
) | [static] |
Definition at line 1303 of file app_queue.c.
References ast_load_realtime(), ast_strlen_zero(), ast_update_realtime(), member::interface, and var.
Referenced by set_member_paused().
01304 { 01305 struct ast_variable *var; 01306 int ret = -1; 01307 01308 if (!(var = ast_load_realtime("queue_members", "interface", mem->interface, "queue_name", queue_name, NULL))) 01309 return ret; 01310 while (var) { 01311 if (!strcmp(var->name, "uniqueid")) 01312 break; 01313 var = var->next; 01314 } 01315 if (var && !ast_strlen_zero(var->value)) { 01316 if ((ast_update_realtime("queue_members", "uniqueid", var->value, field, value, NULL)) > -1) 01317 ret = 0; 01318 } 01319 return ret; 01320 }
static void update_realtime_members | ( | struct call_queue * | q | ) | [static] |
Definition at line 1322 of file app_queue.c.
References ao2_iterator_init(), ao2_iterator_next(), ao2_ref(), ao2_unlink(), ast_category_browse(), ast_config_destroy(), ast_load_realtime_multientry(), ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_variable_retrieve(), member::dead, member::interface, member_interface::interface, call_queue::lock, LOG_DEBUG, call_queue::membercount, call_queue::members, call_queue::name, option_debug, member::realtime, remove_from_interfaces(), rt_handle_member_record(), and S_OR.
Referenced by load_realtime_queue(), and queue_exec().
01323 { 01324 struct ast_config *member_config = NULL; 01325 struct member *m; 01326 char *interface = NULL; 01327 struct ao2_iterator mem_iter; 01328 01329 if (!(member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name", q->name , NULL))) { 01330 /*This queue doesn't have realtime members*/ 01331 if (option_debug > 2) 01332 ast_log(LOG_DEBUG, "Queue %s has no realtime members defined. No need for update\n", q->name); 01333 return; 01334 } 01335 01336 ast_mutex_lock(&q->lock); 01337 01338 /* Temporarily set realtime members dead so we can detect deleted ones.*/ 01339 mem_iter = ao2_iterator_init(q->members, 0); 01340 while ((m = ao2_iterator_next(&mem_iter))) { 01341 if (m->realtime) 01342 m->dead = 1; 01343 ao2_ref(m, -1); 01344 } 01345 01346 while ((interface = ast_category_browse(member_config, interface))) { 01347 rt_handle_member_record(q, interface, 01348 S_OR(ast_variable_retrieve(member_config, interface, "membername"), interface), 01349 ast_variable_retrieve(member_config, interface, "penalty"), 01350 ast_variable_retrieve(member_config, interface, "paused")); 01351 } 01352 01353 /* Delete all realtime members that have been deleted in DB. */ 01354 mem_iter = ao2_iterator_init(q->members, 0); 01355 while ((m = ao2_iterator_next(&mem_iter))) { 01356 if (m->dead) { 01357 ao2_unlink(q->members, m); 01358 ast_mutex_unlock(&q->lock); 01359 remove_from_interfaces(m->interface); 01360 ast_mutex_lock(&q->lock); 01361 q->membercount--; 01362 } 01363 ao2_ref(m, -1); 01364 } 01365 ast_mutex_unlock(&q->lock); 01366 ast_config_destroy(member_config); 01367 }
static int update_status | ( | const char * | interface, | |
const int | status | |||
) | [static] |
Definition at line 584 of file app_queue.c.
References ao2_iterator_init(), ao2_iterator_next(), ao2_ref(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_mutex_lock(), ast_mutex_unlock(), ast_strdupa, member::calls, member::dynamic, EVENT_FLAG_AGENT, member::interface, member::lastcall, call_queue::lock, manager_event(), call_queue::maskmemberstatus, member::membername, call_queue::members, call_queue::name, member::paused, member::penalty, member::realtime, and member::status.
Referenced by handle_statechange(), and ring_entry().
00585 { 00586 struct member *cur; 00587 struct ao2_iterator mem_iter; 00588 struct call_queue *q; 00589 00590 AST_LIST_LOCK(&queues); 00591 AST_LIST_TRAVERSE(&queues, q, list) { 00592 ast_mutex_lock(&q->lock); 00593 mem_iter = ao2_iterator_init(q->members, 0); 00594 while ((cur = ao2_iterator_next(&mem_iter))) { 00595 char *tmp_interface; 00596 char *slash_pos; 00597 tmp_interface = ast_strdupa(cur->interface); 00598 if ((slash_pos = strchr(tmp_interface, '/'))) 00599 if ((slash_pos = strchr(slash_pos + 1, '/'))) 00600 *slash_pos = '\0'; 00601 00602 if (strcasecmp(interface, tmp_interface)) { 00603 ao2_ref(cur, -1); 00604 continue; 00605 } 00606 00607 if (cur->status != status) { 00608 cur->status = status; 00609 if (q->maskmemberstatus) { 00610 ao2_ref(cur, -1); 00611 continue; 00612 } 00613 00614 manager_event(EVENT_FLAG_AGENT, "QueueMemberStatus", 00615 "Queue: %s\r\n" 00616 "Location: %s\r\n" 00617 "MemberName: %s\r\n" 00618 "Membership: %s\r\n" 00619 "Penalty: %d\r\n" 00620 "CallsTaken: %d\r\n" 00621 "LastCall: %d\r\n" 00622 "Status: %d\r\n" 00623 "Paused: %d\r\n", 00624 q->name, cur->interface, cur->membername, cur->dynamic ? "dynamic" : cur->realtime ? "realtime" : "static", 00625 cur->penalty, cur->calls, (int)cur->lastcall, cur->status, cur->paused); 00626 } 00627 ao2_ref(cur, -1); 00628 } 00629 ast_mutex_unlock(&q->lock); 00630 } 00631 AST_LIST_UNLOCK(&queues); 00632 00633 return 0; 00634 }
static int upqm_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Definition at line 3496 of file app_queue.c.
References AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_goto_if_exists(), ast_log(), ast_module_user_add, ast_module_user_remove, ast_opt_priority_jumping, AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), ast_module_user::chan, ast_channel::context, ast_channel::exten, LOG_WARNING, parse(), pbx_builtin_setvar_helper(), ast_channel::priority, and set_member_paused().
Referenced by load_module().
03497 { 03498 struct ast_module_user *lu; 03499 char *parse; 03500 int priority_jump = 0; 03501 int ignore_fail = 0; 03502 AST_DECLARE_APP_ARGS(args, 03503 AST_APP_ARG(queuename); 03504 AST_APP_ARG(interface); 03505 AST_APP_ARG(options); 03506 ); 03507 03508 if (ast_strlen_zero(data)) { 03509 ast_log(LOG_WARNING, "UnpauseQueueMember requires an argument ([queuename]|interface[|options])\n"); 03510 return -1; 03511 } 03512 03513 parse = ast_strdupa(data); 03514 03515 AST_STANDARD_APP_ARGS(args, parse); 03516 03517 lu = ast_module_user_add(chan); 03518 03519 if (args.options) { 03520 if (strchr(args.options, 'j')) 03521 priority_jump = 1; 03522 if (strchr(args.options, 'i')) 03523 ignore_fail = 1; 03524 } 03525 03526 if (ast_strlen_zero(args.interface)) { 03527 ast_log(LOG_WARNING, "Missing interface argument to PauseQueueMember ([queuename]|interface[|options])\n"); 03528 ast_module_user_remove(lu); 03529 return -1; 03530 } 03531 03532 if (set_member_paused(args.queuename, args.interface, 0)) { 03533 ast_log(LOG_WARNING, "Attempt to unpause interface %s, not found\n", args.interface); 03534 pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "NOTFOUND"); 03535 if (priority_jump || ast_opt_priority_jumping) { 03536 if (!ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101)) { 03537 ast_module_user_remove(lu); 03538 return 0; 03539 } 03540 } 03541 ast_module_user_remove(lu); 03542 if (ignore_fail) { 03543 return 0; 03544 } else { 03545 return -1; 03546 } 03547 } 03548 03549 ast_module_user_remove(lu); 03550 pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "UNPAUSED"); 03551 return 0; 03552 }
static int valid_exit | ( | struct queue_ent * | qe, | |
char | digit | |||
) | [static] |
Definition at line 1499 of file app_queue.c.
References ast_canmatch_extension(), ast_goto_if_exists(), ast_strlen_zero(), queue_ent::chan, ast_channel::cid, ast_callerid::cid_num, queue_ent::context, queue_ent::digits, and queue_ent::valid_digits.
Referenced by say_periodic_announcement(), say_position(), wait_a_bit(), and wait_our_turn().
01500 { 01501 int digitlen = strlen(qe->digits); 01502 01503 /* Prevent possible buffer overflow */ 01504 if (digitlen < sizeof(qe->digits) - 2) { 01505 qe->digits[digitlen] = digit; 01506 qe->digits[digitlen + 1] = '\0'; 01507 } else { 01508 qe->digits[0] = '\0'; 01509 return 0; 01510 } 01511 01512 /* If there's no context to goto, short-circuit */ 01513 if (ast_strlen_zero(qe->context)) 01514 return 0; 01515 01516 /* If the extension is bad, then reset the digits to blank */ 01517 if (!ast_canmatch_extension(qe->chan, qe->context, qe->digits, 1, qe->chan->cid.cid_num)) { 01518 qe->digits[0] = '\0'; 01519 return 0; 01520 } 01521 01522 /* We have an exact match */ 01523 if (!ast_goto_if_exists(qe->chan, qe->context, qe->digits, 1)) { 01524 qe->valid_digits = 1; 01525 /* Return 1 on a successful goto */ 01526 return 1; 01527 } 01528 01529 return 0; 01530 }
static char* vars2manager | ( | struct ast_channel * | chan, | |
char * | vars, | |||
size_t | len | |||
) | [static] |
Definition at line 1754 of file app_queue.c.
References pbx_builtin_serialize_variables().
Referenced by ring_entry(), and try_calling().
01755 { 01756 char *tmp = alloca(len); 01757 01758 if (pbx_builtin_serialize_variables(chan, tmp, len)) { 01759 int i, j; 01760 01761 /* convert "\n" to "\nVariable: " */ 01762 strcpy(vars, "Variable: "); 01763 01764 for (i = 0, j = 10; (i < len - 1) && (j < len - 1); i++, j++) { 01765 vars[j] = tmp[i]; 01766 01767 if (tmp[i + 1] == '\0') 01768 break; 01769 if (tmp[i] == '\n') { 01770 vars[j++] = '\r'; 01771 vars[j++] = '\n'; 01772 01773 ast_copy_string(&(vars[j]), "Variable: ", len - j); 01774 j += 9; 01775 } 01776 } 01777 if (j > len - 3) 01778 j = len - 3; 01779 vars[j++] = '\r'; 01780 vars[j++] = '\n'; 01781 vars[j] = '\0'; 01782 } else { 01783 /* there are no channel variables; leave it blank */ 01784 *vars = '\0'; 01785 } 01786 return vars; 01787 }
static int wait_a_bit | ( | struct queue_ent * | qe | ) | [static] |
Definition at line 3113 of file app_queue.c.
References ast_waitfordigit(), queue_ent::chan, queue_ent::parent, call_queue::retry, and valid_exit().
Referenced by queue_exec().
03114 { 03115 /* Don't need to hold the lock while we setup the outgoing calls */ 03116 int retrywait = qe->parent->retry * 1000; 03117 03118 int res = ast_waitfordigit(qe->chan, retrywait); 03119 if (res > 0 && !valid_exit(qe, res)) 03120 res = 0; 03121 03122 return res; 03123 }
static struct callattempt* wait_for_answer | ( | struct queue_ent * | qe, | |
struct callattempt * | outgoing, | |||
int * | to, | |||
char * | digit, | |||
int | prebusies, | |||
int | caller_disconnect, | |||
int | forwardsallowed | |||
) | [static] |
Wait for a member to answer the call.
[in] | qe | the queue_ent corresponding to the caller in the queue |
[in] | outgoing | the list of callattempts. Relevant ones will have their chan and stillgoing parameters non-zero |
[in] | to | the amount of time (in milliseconds) to wait for a response |
[out] | digit | if a user presses a digit to exit the queue, this is the digit the caller pressed |
[in] | prebusies | number of busy members calculated prior to calling wait_for_answer |
[in] | caller_disconnect | if the 'H' option is used when calling Queue(), this is used to detect if the caller pressed * to disconnect the call |
[in] | forwardsallowed | used to detect if we should allow call forwarding, based on the 'i' option to Queue() |
Definition at line 2101 of file app_queue.c.
References AST_MAX_WATCHERS, callattempt::call_next, callattempt::chan, queue_ent::chan, f, call_queue::name, queue_ent::parent, callattempt::q_next, QUEUE_STRATEGY_RINGALL, ring_one(), starttime, callattempt::stillgoing, and call_queue::strategy.
02102 { 02103 char *queue = qe->parent->name; 02104 struct callattempt *o, *start = NULL, *prev = NULL; 02105 int status; 02106 int numbusies = prebusies; 02107 int numnochan = 0; 02108 int stillgoing = 0; 02109 int orig = *to; 02110 struct ast_frame *f; 02111 struct callattempt *peer = NULL; 02112 struct ast_channel *winner; 02113 struct ast_channel *in = qe->chan; 02114 char on[80] = ""; 02115 char membername[80] = ""; 02116 long starttime = 0; 02117 long endtime = 0; 02118 02119 starttime = (long) time(NULL); 02120 02121 while (*to && !peer) { 02122 int numlines, retry, pos = 1; 02123 struct ast_channel *watchers[AST_MAX_WATCHERS]; 02124 watchers[0] = in; 02125 start = NULL; 02126 02127 for (retry = 0; retry < 2; retry++) { 02128 numlines = 0; 02129 for (o = outgoing; o; o = o->q_next) { /* Keep track of important channels */ 02130 if (o->stillgoing) { /* Keep track of important channels */ 02131 stillgoing = 1; 02132 if (o->chan) { 02133 watchers[pos++] = o->chan; 02134 if (!start) 02135 start = o; 02136 else 02137 prev->call_next = o; 02138 prev = o; 02139 } 02140 } 02141 numlines++; 02142 } 02143 if (pos > 1 /* found */ || !stillgoing /* nobody listening */ || 02144 (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) /* ring would not be delivered */) 02145 break; 02146 /* On "ringall" strategy we only move to the next penalty level 02147 when *all* ringing phones are done in the current penalty level */ 02148 ring_one(qe, outgoing, &numbusies); 02149 /* and retry... */ 02150 } 02151 if (pos == 1 /* not found */) { 02152 if (numlines == (numbusies + numnochan)) { 02153 ast_log(LOG_DEBUG, "Everyone is busy at this time\n"); 02154 } else { 02155 ast_log(LOG_NOTICE, "No one is answering queue '%s' (%d/%d/%d)\n", queue, numlines, numbusies, numnochan); 02156 } 02157 *to = 0; 02158 return NULL; 02159 } 02160 winner = ast_waitfor_n(watchers, pos, to); 02161 for (o = start; o; o = o->call_next) { 02162 if (o->stillgoing && (o->chan) && (o->chan->_state == AST_STATE_UP)) { 02163 if (!peer) { 02164 if (option_verbose > 2) 02165 ast_verbose( VERBOSE_PREFIX_3 "%s answered %s\n", o->chan->name, in->name); 02166 peer = o; 02167 } 02168 } else if (o->chan && (o->chan == winner)) { 02169 02170 ast_copy_string(on, o->member->interface, sizeof(on)); 02171 ast_copy_string(membername, o->member->membername, sizeof(membername)); 02172 02173 if (!ast_strlen_zero(o->chan->call_forward) && !forwardsallowed) { 02174 if (option_verbose > 2) 02175 ast_verbose(VERBOSE_PREFIX_3 "Forwarding %s to '%s' prevented.\n", in->name, o->chan->call_forward); 02176 numnochan++; 02177 do_hang(o); 02178 winner = NULL; 02179 continue; 02180 } else if (!ast_strlen_zero(o->chan->call_forward)) { 02181 char tmpchan[256]; 02182 char *stuff; 02183 char *tech; 02184 02185 ast_copy_string(tmpchan, o->chan->call_forward, sizeof(tmpchan)); 02186 if ((stuff = strchr(tmpchan, '/'))) { 02187 *stuff++ = '\0'; 02188 tech = tmpchan; 02189 } else { 02190 snprintf(tmpchan, sizeof(tmpchan), "%s@%s", o->chan->call_forward, o->chan->context); 02191 stuff = tmpchan; 02192 tech = "Local"; 02193 } 02194 /* Before processing channel, go ahead and check for forwarding */ 02195 if (option_verbose > 2) 02196 ast_verbose(VERBOSE_PREFIX_3 "Now forwarding %s to '%s/%s' (thanks to %s)\n", in->name, tech, stuff, o->chan->name); 02197 /* Setup parameters */ 02198 o->chan = ast_request(tech, in->nativeformats, stuff, &status); 02199 if (!o->chan) { 02200 ast_log(LOG_NOTICE, "Unable to create local channel for call forward to '%s/%s'\n", tech, stuff); 02201 o->stillgoing = 0; 02202 numnochan++; 02203 } else { 02204 ast_channel_inherit_variables(in, o->chan); 02205 ast_channel_datastore_inherit(in, o->chan); 02206 if (o->chan->cid.cid_num) 02207 free(o->chan->cid.cid_num); 02208 o->chan->cid.cid_num = ast_strdup(in->cid.cid_num); 02209 02210 if (o->chan->cid.cid_name) 02211 free(o->chan->cid.cid_name); 02212 o->chan->cid.cid_name = ast_strdup(in->cid.cid_name); 02213 02214 ast_string_field_set(o->chan, accountcode, in->accountcode); 02215 o->chan->cdrflags = in->cdrflags; 02216 02217 if (in->cid.cid_ani) { 02218 if (o->chan->cid.cid_ani) 02219 free(o->chan->cid.cid_ani); 02220 o->chan->cid.cid_ani = ast_strdup(in->cid.cid_ani); 02221 } 02222 if (o->chan->cid.cid_rdnis) 02223 free(o->chan->cid.cid_rdnis); 02224 o->chan->cid.cid_rdnis = ast_strdup(S_OR(in->macroexten, in->exten)); 02225 if (ast_call(o->chan, tmpchan, 0)) { 02226 ast_log(LOG_NOTICE, "Failed to dial on local channel for call forward to '%s'\n", tmpchan); 02227 do_hang(o); 02228 numnochan++; 02229 } 02230 } 02231 /* Hangup the original channel now, in case we needed it */ 02232 ast_hangup(winner); 02233 continue; 02234 } 02235 f = ast_read(winner); 02236 if (f) { 02237 if (f->frametype == AST_FRAME_CONTROL) { 02238 switch (f->subclass) { 02239 case AST_CONTROL_ANSWER: 02240 /* This is our guy if someone answered. */ 02241 if (!peer) { 02242 if (option_verbose > 2) 02243 ast_verbose( VERBOSE_PREFIX_3 "%s answered %s\n", o->chan->name, in->name); 02244 peer = o; 02245 } 02246 break; 02247 case AST_CONTROL_BUSY: 02248 if (option_verbose > 2) 02249 ast_verbose( VERBOSE_PREFIX_3 "%s is busy\n", o->chan->name); 02250 if (in->cdr) 02251 ast_cdr_busy(in->cdr); 02252 do_hang(o); 02253 endtime = (long)time(NULL); 02254 endtime -= starttime; 02255 rna(endtime*1000, qe, on, membername); 02256 if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) { 02257 if (qe->parent->timeoutrestart) 02258 *to = orig; 02259 ring_one(qe, outgoing, &numbusies); 02260 } 02261 numbusies++; 02262 break; 02263 case AST_CONTROL_CONGESTION: 02264 if (option_verbose > 2) 02265 ast_verbose( VERBOSE_PREFIX_3 "%s is circuit-busy\n", o->chan->name); 02266 if (in->cdr) 02267 ast_cdr_busy(in->cdr); 02268 endtime = (long)time(NULL); 02269 endtime -= starttime; 02270 rna(endtime*1000, qe, on, membername); 02271 do_hang(o); 02272 if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) { 02273 if (qe->parent->timeoutrestart) 02274 *to = orig; 02275 ring_one(qe, outgoing, &numbusies); 02276 } 02277 numbusies++; 02278 break; 02279 case AST_CONTROL_RINGING: 02280 if (option_verbose > 2) 02281 ast_verbose( VERBOSE_PREFIX_3 "%s is ringing\n", o->chan->name); 02282 break; 02283 case AST_CONTROL_OFFHOOK: 02284 /* Ignore going off hook */ 02285 break; 02286 default: 02287 ast_log(LOG_DEBUG, "Dunno what to do with control type %d\n", f->subclass); 02288 } 02289 } 02290 ast_frfree(f); 02291 } else { 02292 endtime = (long) time(NULL) - starttime; 02293 rna(endtime * 1000, qe, on, membername); 02294 do_hang(o); 02295 if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) { 02296 if (qe->parent->timeoutrestart) 02297 *to = orig; 02298 ring_one(qe, outgoing, &numbusies); 02299 } 02300 } 02301 } 02302 } 02303 if (winner == in) { 02304 f = ast_read(in); 02305 if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP))) { 02306 /* Got hung up */ 02307 *to = -1; 02308 if (f) 02309 ast_frfree(f); 02310 return NULL; 02311 } 02312 /* First check if DTMF digit is a valid exit */ 02313 if ((f->frametype == AST_FRAME_DTMF) && valid_exit(qe, f->subclass)) { 02314 if (option_verbose > 3) 02315 ast_verbose(VERBOSE_PREFIX_3 "User pressed digit: %c\n", f->subclass); 02316 *to = 0; 02317 *digit = f->subclass; 02318 ast_frfree(f); 02319 return NULL; 02320 } 02321 /* Else check if DTMF should be interpreted as caller disconnect */ 02322 if ((f->frametype == AST_FRAME_DTMF) && caller_disconnect && (f->subclass == '*')) { 02323 if (option_verbose > 3) 02324 ast_verbose(VERBOSE_PREFIX_3 "User hit %c to disconnect call.\n", f->subclass); 02325 *to = 0; 02326 ast_frfree(f); 02327 return NULL; 02328 } 02329 ast_frfree(f); 02330 } 02331 if (!*to) { 02332 for (o = start; o; o = o->call_next) 02333 rna(orig, qe, o->interface, o->member->membername); 02334 } 02335 } 02336 02337 return peer; 02338 }
static int wait_our_turn | ( | struct queue_ent * | qe, | |
int | ringing, | |||
enum queue_result * | reason | |||
) | [static] |
The waiting areas for callers who are not actively calling members.
This function is one large loop. This function will return if a caller either exits the queue or it becomes that caller's turn to attempt calling queue members. Inside the loop, we service the caller with periodic announcements, holdtime announcements, etc. as configured in queues.conf
0 | if the caller's turn has arrived | |
-1 | if the caller should exit the queue. |
Definition at line 2433 of file app_queue.c.
References call_queue::announcefrequency, ast_queue_log(), ast_waitfordigit(), queue_ent::chan, get_member_status(), is_our_turn(), leave_queue(), call_queue::leavewhenempty, queue_ent::max_penalty, call_queue::name, queue_ent::opos, queue_ent::parent, call_queue::periodicannouncefrequency, queue_ent::pos, QUEUE_EMPTY_STRICT, QUEUE_LEAVEEMPTY, QUEUE_LEAVEUNAVAIL, QUEUE_NO_MEMBERS, QUEUE_NO_REACHABLE_MEMBERS, QUEUE_TIMEOUT, RECHECK, say_periodic_announcement(), say_position(), queue_ent::start, and valid_exit().
Referenced by queue_exec().
02434 { 02435 int res = 0; 02436 02437 /* This is the holding pen for callers 2 through maxlen */ 02438 for (;;) { 02439 enum queue_member_status stat; 02440 02441 if (is_our_turn(qe)) 02442 break; 02443 02444 /* If we have timed out, break out */ 02445 if (qe->expire && (time(NULL) > qe->expire)) { 02446 *reason = QUEUE_TIMEOUT; 02447 break; 02448 } 02449 02450 stat = get_member_status(qe->parent, qe->max_penalty); 02451 02452 /* leave the queue if no agents, if enabled */ 02453 if (qe->parent->leavewhenempty && (stat == QUEUE_NO_MEMBERS)) { 02454 *reason = QUEUE_LEAVEEMPTY; 02455 ast_queue_log(qe->parent->name, qe->chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe->pos, qe->opos, (long)time(NULL) - qe->start); 02456 leave_queue(qe); 02457 break; 02458 } 02459 02460 /* leave the queue if no reachable agents, if enabled */ 02461 if ((qe->parent->leavewhenempty == QUEUE_EMPTY_STRICT) && (stat == QUEUE_NO_REACHABLE_MEMBERS)) { 02462 *reason = QUEUE_LEAVEUNAVAIL; 02463 ast_queue_log(qe->parent->name, qe->chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe->pos, qe->opos, (long)time(NULL) - qe->start); 02464 leave_queue(qe); 02465 break; 02466 } 02467 02468 /* Make a position announcement, if enabled */ 02469 if (qe->parent->announcefrequency && !ringing && 02470 (res = say_position(qe))) 02471 break; 02472 02473 /* Make a periodic announcement, if enabled */ 02474 if (qe->parent->periodicannouncefrequency && !ringing && 02475 (res = say_periodic_announcement(qe))) 02476 break; 02477 02478 /* Wait a second before checking again */ 02479 if ((res = ast_waitfordigit(qe->chan, RECHECK * 1000))) { 02480 if (res > 0 && !valid_exit(qe, res)) 02481 res = 0; 02482 else 02483 break; 02484 } 02485 } 02486 02487 return res; 02488 }
char* app = "Queue" [static] |
Definition at line 148 of file app_queue.c.
char* app_aqm = "AddQueueMember" [static] |
Definition at line 182 of file app_queue.c.
char* app_aqm_descrip [static] |
Definition at line 184 of file app_queue.c.
char* app_aqm_synopsis = "Dynamically adds queue members" [static] |
Definition at line 183 of file app_queue.c.
char* app_pqm = "PauseQueueMember" [static] |
Definition at line 214 of file app_queue.c.
char* app_pqm_descrip [static] |
Definition at line 216 of file app_queue.c.
char* app_pqm_synopsis = "Pauses a queue member" [static] |
Definition at line 215 of file app_queue.c.
char* app_ql = "QueueLog" [static] |
Definition at line 253 of file app_queue.c.
char* app_ql_descrip [static] |
Initial value:
" QueueLog(queuename|uniqueid|agent|event[|additionalinfo]):\n" "Allows you to write your own events into the queue log\n" "Example: QueueLog(101|${UNIQUEID}|${AGENT}|WENTONBREAK|600)\n"
Definition at line 255 of file app_queue.c.
char* app_ql_synopsis = "Writes to the queue_log" [static] |
Definition at line 254 of file app_queue.c.
char* app_rqm = "RemoveQueueMember" [static] |
Definition at line 198 of file app_queue.c.
char* app_rqm_descrip [static] |
Definition at line 200 of file app_queue.c.
char* app_rqm_synopsis = "Dynamically removes queue members" [static] |
Definition at line 199 of file app_queue.c.
char* app_upqm = "UnpauseQueueMember" [static] |
Definition at line 237 of file app_queue.c.
char* app_upqm_descrip [static] |
Definition at line 239 of file app_queue.c.
char* app_upqm_synopsis = "Unpauses a queue member" [static] |
Definition at line 238 of file app_queue.c.
int autofill_default = 0 [static] |
struct ast_cli_entry cli_add_queue_member_deprecated [static] |
Initial value:
{ { "add", "queue", "member", NULL }, handle_queue_add_member, NULL, NULL, complete_queue_add_member }
Definition at line 4966 of file app_queue.c.
struct ast_cli_entry cli_queue[] [static] |
struct ast_cli_entry cli_remove_queue_member_deprecated [static] |
Initial value:
{ { "remove", "queue", "member", NULL }, handle_queue_remove_member, NULL, NULL, complete_queue_remove_member }
Definition at line 4971 of file app_queue.c.
struct ast_cli_entry cli_show_queue_deprecated [static] |
Initial value:
{ { "show", "queue", NULL }, queue_show, NULL, NULL, complete_queue_show }
Definition at line 4961 of file app_queue.c.
Condition for the state change queue
Definition at line 690 of file app_queue.c.
char* descrip [static] |
Definition at line 152 of file app_queue.c.
struct { ... } device_state [static] |
Data used by the device state thread.
Referenced by device_state_thread(), load_module(), statechange_queue(), and unload_module().
enum queue_result id |
Lock for the state change queue
Definition at line 688 of file app_queue.c.
int montype_default = 0 [static] |
const char* pm_family = "Queue/PersistentMembers" [static] |
char qam_cmd_usage[] [static] |
Initial value:
"Usage: queue add member <channel> to <queue> [penalty <penalty>]\n"
Definition at line 4955 of file app_queue.c.
char qrm_cmd_usage[] [static] |
Initial value:
"Usage: queue remove member <channel> from <queue>\n"
Definition at line 4958 of file app_queue.c.
int queue_debug = 0 [static] |
int queue_persistent_members = 0 [static] |
struct { ... } queue_results[] |
Referenced by set_queue_result().
char queue_show_usage[] [static] |
Initial value:
"Usage: queue show\n" " Provides summary information on a specified queue.\n"
Definition at line 4951 of file app_queue.c.
struct ast_custom_function queueagentcount_function [static] |
struct ast_custom_function queuemembercount_function [static] |
struct ast_custom_function queuememberlist_function [static] |
struct ast_custom_function queuewaitingcount_function [static] |
unsigned int stop |
Set to 1 to stop the thread
Definition at line 684 of file app_queue.c.
Referenced by handle_controlstreamfile(), and queue_exec().
struct strategy strategies[] [static] |
Referenced by int2strat(), and strat2int().
char* synopsis = "Queue a call for a call queue" [static] |
Definition at line 150 of file app_queue.c.
char* text |
Definition at line 292 of file app_queue.c.
Referenced by _sip_show_peer(), build_reply_digest(), check_auth(), handle_response(), method_match(), parse_sip_options(), referstatus2str(), reqprep(), sendtext_exec(), set_queue_result(), sip_alloc(), and sip_show_channel().
pthread_t thread |
The device state monitoring thread
Definition at line 686 of file app_queue.c.
int use_weight = 0 [static] |