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