#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 dependency graph for app_queue.c:
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_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) |
static void * | changethread (void *data) |
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 struct member * | create_queue_member (const char *interface, const char *membername, int penalty, int paused) |
static void | destroy_queue (struct call_queue *q) |
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) |
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 | 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) |
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 | 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) |
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) |
static int | ring_one (struct queue_ent *qe, struct callattempt *outgoing, int *busies) |
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) |
static int | statechange_queue (const char *dev, int state, void *ign) |
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) |
static int | unload_module (void) |
static int | update_dial_status (struct call_queue *q, struct member *member, int status) |
static int | update_queue (struct call_queue *q, struct member *member, int callcompletedinsl) |
static void | update_realtime_members (struct call_queue *q) |
static int | update_status (struct call_queue *q, struct member *member, 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) |
static int | wait_our_turn (struct queue_ent *qe, int ringing, enum queue_result *reason) |
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 |
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 1906 of file app_queue.c.
#define DEFAULT_RETRY 5 |
#define DEFAULT_TIMEOUT 15 |
#define MAX_PERIODIC_ANNOUNCEMENTS 10 |
Definition at line 120 of file app_queue.c.
Referenced by init_queue(), queue_set_param(), and say_periodic_announcement().
#define PM_MAX_LEN 8192 |
Definition at line 240 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 338 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 341 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 123 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 125 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_OKAY 0 |
Definition at line 122 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 124 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 96 of file app_queue.c.
00096 { 00097 QUEUE_STRATEGY_RINGALL = 0, 00098 QUEUE_STRATEGY_ROUNDROBIN, 00099 QUEUE_STRATEGY_LEASTRECENT, 00100 QUEUE_STRATEGY_FEWESTCALLS, 00101 QUEUE_STRATEGY_RANDOM, 00102 QUEUE_STRATEGY_RRMEMORY 00103 };
enum queue_member_status |
Definition at line 474 of file app_queue.c.
00474 { 00475 QUEUE_NO_MEMBERS, 00476 QUEUE_NO_REACHABLE_MEMBERS, 00477 QUEUE_NORMAL 00478 };
enum queue_result |
QUEUE_UNKNOWN | |
QUEUE_TIMEOUT | |
QUEUE_JOINEMPTY | |
QUEUE_LEAVEEMPTY | |
QUEUE_JOINUNAVAIL | |
QUEUE_LEAVEUNAVAIL | |
QUEUE_FULL |
Definition at line 254 of file app_queue.c.
00254 { 00255 QUEUE_UNKNOWN = 0, 00256 QUEUE_TIMEOUT = 1, 00257 QUEUE_JOINEMPTY = 2, 00258 QUEUE_LEAVEEMPTY = 3, 00259 QUEUE_JOINUNAVAIL = 4, 00260 QUEUE_LEAVEUNAVAIL = 5, 00261 QUEUE_FULL = 6, 00262 };
static int __queues_show | ( | struct mansession * | s, | |
int | manager, | |||
int | fd, | |||
int | argc, | |||
char ** | argv | |||
) | [static] |
Definition at line 3938 of file app_queue.c.
References 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::interface, member::lastcall, load_realtime_queue(), call_queue::lock, call_queue::maxlen, call_queue::members, call_queue::name, queue_ent::next, member::next, member::paused, member::penalty, queue_ent::prio, queue_show(), RESULT_SHOWUSAGE, RESULT_SUCCESS, s, call_queue::servicelevel, queue_ent::start, member::status, call_queue::strategy, and call_queue::weight.
Referenced by manager_queues_show(), and queue_show().
03939 { 03940 struct call_queue *q; 03941 struct queue_ent *qe; 03942 struct member *mem; 03943 int pos, queue_show; 03944 time_t now; 03945 char max_buf[80]; 03946 char *max; 03947 size_t max_left; 03948 float sl = 0; 03949 char *term = manager ? "\r\n" : "\n"; 03950 03951 time(&now); 03952 if (argc == 2) 03953 queue_show = 0; 03954 else if (argc == 3) 03955 queue_show = 1; 03956 else 03957 return RESULT_SHOWUSAGE; 03958 03959 /* We only want to load realtime queues when a specific queue is asked for. */ 03960 if (queue_show) 03961 load_realtime_queue(argv[2]); 03962 03963 AST_LIST_LOCK(&queues); 03964 if (AST_LIST_EMPTY(&queues)) { 03965 AST_LIST_UNLOCK(&queues); 03966 if (queue_show) { 03967 if (s) 03968 astman_append(s, "No such queue: %s.%s",argv[2], term); 03969 else 03970 ast_cli(fd, "No such queue: %s.%s",argv[2], term); 03971 } else { 03972 if (s) 03973 astman_append(s, "No queues.%s", term); 03974 else 03975 ast_cli(fd, "No queues.%s", term); 03976 } 03977 return RESULT_SUCCESS; 03978 } 03979 AST_LIST_TRAVERSE(&queues, q, list) { 03980 ast_mutex_lock(&q->lock); 03981 if (queue_show) { 03982 if (strcasecmp(q->name, argv[2]) != 0) { 03983 ast_mutex_unlock(&q->lock); 03984 if (!AST_LIST_NEXT(q, list)) { 03985 ast_cli(fd, "No such queue: %s.%s",argv[2], term); 03986 break; 03987 } 03988 continue; 03989 } 03990 } 03991 max_buf[0] = '\0'; 03992 max = max_buf; 03993 max_left = sizeof(max_buf); 03994 if (q->maxlen) 03995 ast_build_string(&max, &max_left, "%d", q->maxlen); 03996 else 03997 ast_build_string(&max, &max_left, "unlimited"); 03998 sl = 0; 03999 if (q->callscompleted > 0) 04000 sl = 100 * ((float) q->callscompletedinsl / (float) q->callscompleted); 04001 if (s) 04002 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", 04003 q->name, q->count, max_buf, int2strat(q->strategy), q->holdtime, q->weight, 04004 q->callscompleted, q->callsabandoned,sl,q->servicelevel, term); 04005 else 04006 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", 04007 q->name, q->count, max_buf, int2strat(q->strategy), q->holdtime, q->weight, q->callscompleted, q->callsabandoned,sl,q->servicelevel, term); 04008 if (q->members) { 04009 if (s) 04010 astman_append(s, " Members: %s", term); 04011 else 04012 ast_cli(fd, " Members: %s", term); 04013 for (mem = q->members; mem; mem = mem->next) { 04014 max_buf[0] = '\0'; 04015 max = max_buf; 04016 max_left = sizeof(max_buf); 04017 if (mem->penalty) 04018 ast_build_string(&max, &max_left, " with penalty %d", mem->penalty); 04019 if (mem->dynamic) 04020 ast_build_string(&max, &max_left, " (dynamic)"); 04021 if (mem->paused) 04022 ast_build_string(&max, &max_left, " (paused)"); 04023 ast_build_string(&max, &max_left, " (%s)", devstate2str(mem->status)); 04024 if (mem->calls) { 04025 ast_build_string(&max, &max_left, " has taken %d calls (last was %ld secs ago)", 04026 mem->calls, (long) (time(NULL) - mem->lastcall)); 04027 } else 04028 ast_build_string(&max, &max_left, " has taken no calls yet"); 04029 if (s) 04030 astman_append(s, " %s%s%s", mem->interface, max_buf, term); 04031 else 04032 ast_cli(fd, " %s%s%s", mem->interface, max_buf, term); 04033 } 04034 } else if (s) 04035 astman_append(s, " No Members%s", term); 04036 else 04037 ast_cli(fd, " No Members%s", term); 04038 if (q->head) { 04039 pos = 1; 04040 if (s) 04041 astman_append(s, " Callers: %s", term); 04042 else 04043 ast_cli(fd, " Callers: %s", term); 04044 for (qe = q->head; qe; qe = qe->next) { 04045 if (s) 04046 astman_append(s, " %d. %s (wait: %ld:%2.2ld, prio: %d)%s", 04047 pos++, qe->chan->name, (long) (now - qe->start) / 60, 04048 (long) (now - qe->start) % 60, qe->prio, term); 04049 else 04050 ast_cli(fd, " %d. %s (wait: %ld:%2.2ld, prio: %d)%s", pos++, 04051 qe->chan->name, (long) (now - qe->start) / 60, 04052 (long) (now - qe->start) % 60, qe->prio, term); 04053 } 04054 } else if (s) 04055 astman_append(s, " No Callers%s", term); 04056 else 04057 ast_cli(fd, " No Callers%s", term); 04058 if (s) 04059 astman_append(s, "%s", term); 04060 else 04061 ast_cli(fd, "%s", term); 04062 ast_mutex_unlock(&q->lock); 04063 if (queue_show) 04064 break; 04065 } 04066 AST_LIST_UNLOCK(&queues); 04067 return RESULT_SUCCESS; 04068 }
static int add_to_interfaces | ( | const char * | interface | ) | [static] |
Definition at line 695 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().
00696 { 00697 struct member_interface *curint; 00698 00699 AST_LIST_LOCK(&interfaces); 00700 AST_LIST_TRAVERSE(&interfaces, curint, list) { 00701 if (!strcasecmp(curint->interface, interface)) 00702 break; 00703 } 00704 00705 if (curint) { 00706 AST_LIST_UNLOCK(&interfaces); 00707 return 0; 00708 } 00709 00710 if (option_debug) 00711 ast_log(LOG_DEBUG, "Adding %s to the list of interfaces that make up all of our queue members.\n", interface); 00712 00713 if ((curint = ast_calloc(1, sizeof(*curint)))) { 00714 ast_copy_string(curint->interface, interface, sizeof(curint->interface)); 00715 AST_LIST_INSERT_HEAD(&interfaces, curint, list); 00716 } 00717 AST_LIST_UNLOCK(&interfaces); 00718 00719 return 0; 00720 }
static int add_to_queue | ( | const char * | queuename, | |
const char * | interface, | |||
const char * | membername, | |||
int | penalty, | |||
int | paused, | |||
int | dump | |||
) | [static] |
Definition at line 2883 of file app_queue.c.
References add_to_interfaces(), 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::next, 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().
02884 { 02885 struct call_queue *q; 02886 struct member *new_member; 02887 int res = RES_NOSUCHQUEUE; 02888 02889 /* \note Ensure the appropriate realtime queue is loaded. Note that this 02890 * short-circuits if the queue is already in memory. */ 02891 if (!(q = load_realtime_queue(queuename))) 02892 return res; 02893 02894 AST_LIST_LOCK(&queues); 02895 02896 ast_mutex_lock(&q->lock); 02897 if (interface_exists(q, interface) == NULL) { 02898 add_to_interfaces(interface); 02899 if ((new_member = create_queue_member(interface, membername, penalty, paused))) { 02900 new_member->dynamic = 1; 02901 new_member->next = q->members; 02902 q->members = new_member; 02903 q->membercount++; 02904 manager_event(EVENT_FLAG_AGENT, "QueueMemberAdded", 02905 "Queue: %s\r\n" 02906 "Location: %s\r\n" 02907 "MemberName: %s\r\n" 02908 "Membership: %s\r\n" 02909 "Penalty: %d\r\n" 02910 "CallsTaken: %d\r\n" 02911 "LastCall: %d\r\n" 02912 "Status: %d\r\n" 02913 "Paused: %d\r\n", 02914 q->name, new_member->interface, new_member->membername, 02915 "dynamic", 02916 new_member->penalty, new_member->calls, (int) new_member->lastcall, 02917 new_member->status, new_member->paused); 02918 02919 if (dump) 02920 dump_queue_members(q); 02921 02922 res = RES_OKAY; 02923 } else { 02924 res = RES_OUTOFMEMORY; 02925 } 02926 } else { 02927 res = RES_EXISTS; 02928 } 02929 ast_mutex_unlock(&q->lock); 02930 AST_LIST_UNLOCK(&queues); 02931 02932 return res; 02933 }
static struct call_queue* alloc_queue | ( | const char * | queuename | ) | [static] |
Definition at line 638 of file app_queue.c.
References ast_calloc, and ast_mutex_init().
Referenced by find_queue_by_name_rt(), and reload_queues().
00639 { 00640 struct call_queue *q; 00641 00642 if ((q = ast_calloc(1, sizeof(*q)))) { 00643 ast_mutex_init(&q->lock); 00644 ast_copy_string(q->name, queuename, sizeof(q->name)); 00645 } 00646 return q; 00647 }
static int aqm_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Definition at line 3240 of file app_queue.c.
References add_to_queue(), AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_goto_if_exists(), ast_log(), ast_module_user_add, ast_module_user_remove, ast_opt_priority_jumping, ast_queue_log(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), ast_module_user::chan, ast_channel::context, LOG_ERROR, LOG_NOTICE, LOG_WARNING, parse(), pbx_builtin_setvar_helper(), RES_EXISTS, RES_NOSUCHQUEUE, RES_OKAY, and RES_OUTOFMEMORY.
Referenced by load_module().
03241 { 03242 int res=-1; 03243 struct ast_module_user *lu; 03244 char *parse, *temppos = NULL; 03245 int priority_jump = 0; 03246 AST_DECLARE_APP_ARGS(args, 03247 AST_APP_ARG(queuename); 03248 AST_APP_ARG(interface); 03249 AST_APP_ARG(penalty); 03250 AST_APP_ARG(options); 03251 AST_APP_ARG(membername); 03252 ); 03253 int penalty = 0; 03254 03255 if (ast_strlen_zero(data)) { 03256 ast_log(LOG_WARNING, "AddQueueMember requires an argument (queuename[|[interface]|[penalty][|options][|membername]])\n"); 03257 return -1; 03258 } 03259 03260 parse = ast_strdupa(data); 03261 03262 AST_STANDARD_APP_ARGS(args, parse); 03263 03264 lu = ast_module_user_add(chan); 03265 03266 if (ast_strlen_zero(args.interface)) { 03267 args.interface = ast_strdupa(chan->name); 03268 temppos = strrchr(args.interface, '-'); 03269 if (temppos) 03270 *temppos = '\0'; 03271 } 03272 03273 if (!ast_strlen_zero(args.penalty)) { 03274 if ((sscanf(args.penalty, "%d", &penalty) != 1) || penalty < 0) { 03275 ast_log(LOG_WARNING, "Penalty '%s' is invalid, must be an integer >= 0\n", args.penalty); 03276 penalty = 0; 03277 } 03278 } 03279 03280 if (args.options) { 03281 if (strchr(args.options, 'j')) 03282 priority_jump = 1; 03283 } 03284 03285 if (ast_strlen_zero(args.membername)) 03286 args.membername = args.interface; 03287 03288 03289 switch (add_to_queue(args.queuename, args.interface, args.membername, penalty, 0, queue_persistent_members)) { 03290 case RES_OKAY: 03291 ast_queue_log(args.queuename, chan->uniqueid, args.interface, "ADDMEMBER", "%s", ""); 03292 ast_log(LOG_NOTICE, "Added interface '%s' to queue '%s'\n", args.interface, args.queuename); 03293 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "ADDED"); 03294 res = 0; 03295 break; 03296 case RES_EXISTS: 03297 ast_log(LOG_WARNING, "Unable to add interface '%s' to queue '%s': Already there\n", args.interface, args.queuename); 03298 if (priority_jump || ast_opt_priority_jumping) 03299 ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101); 03300 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "MEMBERALREADY"); 03301 res = 0; 03302 break; 03303 case RES_NOSUCHQUEUE: 03304 ast_log(LOG_WARNING, "Unable to add interface to queue '%s': No such queue\n", args.queuename); 03305 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "NOSUCHQUEUE"); 03306 res = 0; 03307 break; 03308 case RES_OUTOFMEMORY: 03309 ast_log(LOG_ERROR, "Out of memory adding member %s to queue %s\n", args.interface, args.queuename); 03310 break; 03311 } 03312 03313 ast_module_user_remove(lu); 03314 03315 return res; 03316 }
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] |
Definition at line 2292 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, call_queue::rrpos, call_queue::strategy, and call_queue::wrapped.
Referenced by try_calling().
02293 { 02294 if (qe->max_penalty && (mem->penalty > qe->max_penalty)) 02295 return -1; 02296 02297 switch (q->strategy) { 02298 case QUEUE_STRATEGY_RINGALL: 02299 /* Everyone equal, except for penalty */ 02300 tmp->metric = mem->penalty * 1000000; 02301 break; 02302 case QUEUE_STRATEGY_ROUNDROBIN: 02303 if (!pos) { 02304 if (!q->wrapped) { 02305 /* No more channels, start over */ 02306 q->rrpos = 0; 02307 } else { 02308 /* Prioritize next entry */ 02309 q->rrpos++; 02310 } 02311 q->wrapped = 0; 02312 } 02313 /* Fall through */ 02314 case QUEUE_STRATEGY_RRMEMORY: 02315 if (pos < q->rrpos) { 02316 tmp->metric = 1000 + pos; 02317 } else { 02318 if (pos > q->rrpos) 02319 /* Indicate there is another priority */ 02320 q->wrapped = 1; 02321 tmp->metric = pos; 02322 } 02323 tmp->metric += mem->penalty * 1000000; 02324 break; 02325 case QUEUE_STRATEGY_RANDOM: 02326 tmp->metric = ast_random() % 1000; 02327 tmp->metric += mem->penalty * 1000000; 02328 break; 02329 case QUEUE_STRATEGY_FEWESTCALLS: 02330 tmp->metric = mem->calls; 02331 tmp->metric += mem->penalty * 1000000; 02332 break; 02333 case QUEUE_STRATEGY_LEASTRECENT: 02334 if (!mem->lastcall) 02335 tmp->metric = 0; 02336 else 02337 tmp->metric = 1000000 - (time(NULL) - mem->lastcall); 02338 tmp->metric += mem->penalty * 1000000; 02339 break; 02340 default: 02341 ast_log(LOG_WARNING, "Can't calculate metric for unknown strategy %d\n", q->strategy); 02342 break; 02343 } 02344 return 0; 02345 }
static void* changethread | ( | void * | data | ) | [static] |
Definition at line 514 of file app_queue.c.
References AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_strdupa, member::calls, statechange::dev, devstate2str(), member::dynamic, EVENT_FLAG_AGENT, free, member::interface, member_interface::interface, member::lastcall, call_queue::lock, LOG_DEBUG, manager_event(), call_queue::maskmemberstatus, member::membername, call_queue::members, call_queue::name, member::next, option_debug, member::paused, member::penalty, statechange::state, and member::status.
Referenced by statechange_queue().
00515 { 00516 struct call_queue *q; 00517 struct statechange *sc = data; 00518 struct member *cur; 00519 struct member_interface *curint; 00520 char *loc; 00521 char *technology; 00522 00523 technology = ast_strdupa(sc->dev); 00524 loc = strchr(technology, '/'); 00525 if (loc) { 00526 *loc++ = '\0'; 00527 } else { 00528 free(sc); 00529 return NULL; 00530 } 00531 00532 AST_LIST_LOCK(&interfaces); 00533 AST_LIST_TRAVERSE(&interfaces, curint, list) { 00534 char *interface; 00535 char *slash_pos; 00536 interface = ast_strdupa(curint->interface); 00537 if ((slash_pos = strchr(interface, '/'))) 00538 if ((slash_pos = strchr(slash_pos + 1, '/'))) 00539 *slash_pos = '\0'; 00540 00541 if (!strcasecmp(interface, sc->dev)) 00542 break; 00543 } 00544 AST_LIST_UNLOCK(&interfaces); 00545 00546 if (!curint) { 00547 if (option_debug > 2) 00548 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)); 00549 free(sc); 00550 return NULL; 00551 } 00552 00553 if (option_debug) 00554 ast_log(LOG_DEBUG, "Device '%s/%s' changed to state '%d' (%s)\n", technology, loc, sc->state, devstate2str(sc->state)); 00555 AST_LIST_LOCK(&queues); 00556 AST_LIST_TRAVERSE(&queues, q, list) { 00557 ast_mutex_lock(&q->lock); 00558 for (cur = q->members; cur; cur = cur->next) { 00559 char *interface; 00560 char *slash_pos; 00561 interface = ast_strdupa(cur->interface); 00562 if ((slash_pos = strchr(interface, '/'))) 00563 if ((slash_pos = strchr(slash_pos + 1, '/'))) 00564 *slash_pos = '\0'; 00565 00566 if (strcasecmp(sc->dev, interface)) 00567 continue; 00568 00569 if (cur->status != sc->state) { 00570 cur->status = sc->state; 00571 if (q->maskmemberstatus) 00572 continue; 00573 00574 manager_event(EVENT_FLAG_AGENT, "QueueMemberStatus", 00575 "Queue: %s\r\n" 00576 "Location: %s\r\n" 00577 "MemberName: %s\r\n" 00578 "Membership: %s\r\n" 00579 "Penalty: %d\r\n" 00580 "CallsTaken: %d\r\n" 00581 "LastCall: %d\r\n" 00582 "Status: %d\r\n" 00583 "Paused: %d\r\n", 00584 q->name, cur->interface, cur->membername, cur->dynamic ? "dynamic" : "static", 00585 cur->penalty, cur->calls, (int)cur->lastcall, cur->status, cur->paused); 00586 } 00587 } 00588 ast_mutex_unlock(&q->lock); 00589 } 00590 AST_LIST_UNLOCK(&queues); 00591 00592 free(sc); 00593 00594 return NULL; 00595 }
static void clear_and_free_interfaces | ( | void | ) | [static] |
Definition at line 766 of file app_queue.c.
References AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, and free.
Referenced by unload_module().
00767 { 00768 struct member_interface *curint; 00769 00770 AST_LIST_LOCK(&interfaces); 00771 while ((curint = AST_LIST_REMOVE_HEAD(&interfaces, list))) 00772 free(curint); 00773 AST_LIST_UNLOCK(&interfaces); 00774 }
static void clear_queue | ( | struct call_queue * | q | ) | [static] |
Definition at line 686 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().
00687 { 00688 q->holdtime = 0; 00689 q->callscompleted = 0; 00690 q->callsabandoned = 0; 00691 q->callscompletedinsl = 0; 00692 q->wrapuptime = 0; 00693 }
static int compare_weight | ( | struct call_queue * | rq, | |
struct member * | member | |||
) | [static] |
Definition at line 1562 of file app_queue.c.
References 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, member::next, and call_queue::weight.
Referenced by ring_entry().
01563 { 01564 struct call_queue *q; 01565 struct member *mem; 01566 int found = 0; 01567 01568 /* &qlock and &rq->lock already set by try_calling() 01569 * to solve deadlock */ 01570 AST_LIST_TRAVERSE(&queues, q, list) { 01571 if (q == rq) /* don't check myself, could deadlock */ 01572 continue; 01573 ast_mutex_lock(&q->lock); 01574 if (q->count && q->members) { 01575 for (mem = q->members; mem; mem = mem->next) { 01576 if (strcmp(mem->interface, member->interface)) 01577 continue; 01578 01579 ast_log(LOG_DEBUG, "Found matching member %s in queue '%s'\n", mem->interface, q->name); 01580 if (q->weight > rq->weight) { 01581 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); 01582 found = 1; 01583 break; 01584 } 01585 } 01586 } 01587 ast_mutex_unlock(&q->lock); 01588 if (found) 01589 break; 01590 } 01591 return found; 01592 }
static char* complete_queue | ( | const char * | line, | |
const char * | word, | |||
int | pos, | |||
int | state | |||
) | [static] |
Definition at line 4075 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().
04076 { 04077 struct call_queue *q; 04078 char *ret = NULL; 04079 int which = 0; 04080 int wordlen = strlen(word); 04081 04082 AST_LIST_LOCK(&queues); 04083 AST_LIST_TRAVERSE(&queues, q, list) { 04084 if (!strncasecmp(word, q->name, wordlen) && ++which > state) { 04085 ret = ast_strdup(q->name); 04086 break; 04087 } 04088 } 04089 AST_LIST_UNLOCK(&queues); 04090 04091 return ret; 04092 }
static char* complete_queue_add_member | ( | const char * | line, | |
const char * | word, | |||
int | pos, | |||
int | state | |||
) | [static] |
Definition at line 4367 of file app_queue.c.
References ast_malloc, ast_strdup, and complete_queue().
04368 { 04369 /* 0 - queue; 1 - add; 2 - member; 3 - <interface>; 4 - to; 5 - <queue>; 6 - penalty; 7 - <penalty>; 8 - as; 9 - <membername> */ 04370 switch (pos) { 04371 case 3: /* Don't attempt to complete name of interface (infinite possibilities) */ 04372 return NULL; 04373 case 4: /* only one possible match, "to" */ 04374 return state == 0 ? ast_strdup("to") : NULL; 04375 case 5: /* <queue> */ 04376 return complete_queue(line, word, pos, state); 04377 case 6: /* only one possible match, "penalty" */ 04378 return state == 0 ? ast_strdup("penalty") : NULL; 04379 case 7: 04380 if (state < 100) { /* 0-99 */ 04381 char *num; 04382 if ((num = ast_malloc(3))) { 04383 sprintf(num, "%d", state); 04384 } 04385 return num; 04386 } else { 04387 return NULL; 04388 } 04389 case 8: /* only one possible match, "as" */ 04390 return state == 0 ? ast_strdup("as") : NULL; 04391 case 9: /* Don't attempt to complete name of member (infinite possibilities) */ 04392 return NULL; 04393 default: 04394 return NULL; 04395 } 04396 }
static char* complete_queue_remove_member | ( | const char * | line, | |
const char * | word, | |||
int | pos, | |||
int | state | |||
) | [static] |
Definition at line 4430 of file app_queue.c.
References AST_LIST_EMPTY, AST_LIST_TRAVERSE, ast_mutex_lock(), ast_mutex_unlock(), ast_strdup, complete_queue(), member::interface, call_queue::lock, call_queue::members, and member::next.
04431 { 04432 int which = 0; 04433 struct call_queue *q; 04434 struct member *m; 04435 04436 /* 0 - queue; 1 - remove; 2 - member; 3 - <member>; 4 - from; 5 - <queue> */ 04437 if (pos > 5 || pos < 3) 04438 return NULL; 04439 if (pos == 4) /* only one possible match, 'from' */ 04440 return state == 0 ? ast_strdup("from") : NULL; 04441 04442 if (pos == 5) /* No need to duplicate code */ 04443 return complete_queue(line, word, pos, state); 04444 04445 /* here is the case for 3, <member> */ 04446 if (!AST_LIST_EMPTY(&queues)) { /* XXX unnecessary ? the traverse does that for us */ 04447 AST_LIST_TRAVERSE(&queues, q, list) { 04448 ast_mutex_lock(&q->lock); 04449 for (m = q->members ; m ; m = m->next) { 04450 if (++which > state) { 04451 ast_mutex_unlock(&q->lock); 04452 return ast_strdup(m->interface); 04453 } 04454 } 04455 ast_mutex_unlock(&q->lock); 04456 } 04457 } 04458 04459 return NULL; 04460 }
static char* complete_queue_show | ( | const char * | line, | |
const char * | word, | |||
int | pos, | |||
int | state | |||
) | [static] |
Definition at line 4094 of file app_queue.c.
References complete_queue().
04095 { 04096 if (pos == 2) 04097 return complete_queue(line, word, pos, state); 04098 return NULL; 04099 }
static struct member* create_queue_member | ( | const char * | interface, | |
const char * | membername, | |||
int | penalty, | |||
int | paused | |||
) | [static] |
Definition at line 621 of file app_queue.c.
References ast_calloc, ast_device_state(), ast_log(), LOG_WARNING, and member::penalty.
Referenced by add_to_queue(), reload_queues(), and rt_handle_member_record().
00622 { 00623 struct member *cur; 00624 00625 if ((cur = ast_calloc(1, sizeof(*cur)))) { 00626 cur->penalty = penalty; 00627 cur->paused = paused; 00628 ast_copy_string(cur->interface, interface, sizeof(cur->interface)); 00629 ast_copy_string(cur->membername, membername, sizeof(cur->membername)); 00630 if (!strchr(cur->interface, '/')) 00631 ast_log(LOG_WARNING, "No location at interface '%s'\n", interface); 00632 cur->status = ast_device_state(interface); 00633 } 00634 00635 return cur; 00636 }
static void destroy_queue | ( | struct call_queue * | q | ) | [static] |
Definition at line 993 of file app_queue.c.
References ast_mutex_destroy(), free, free_members(), and call_queue::lock.
Referenced by find_queue_by_name_rt(), and leave_queue().
00994 { 00995 free_members(q, 1); 00996 ast_mutex_destroy(&q->lock); 00997 free(q); 00998 }
static void do_hang | ( | struct callattempt * | o | ) | [static] |
common hangup actions
Definition at line 1595 of file app_queue.c.
References ast_hangup(), callattempt::chan, and callattempt::stillgoing.
Referenced by ring_entry(), and wait_for_answer().
01596 { 01597 o->stillgoing = 0; 01598 ast_hangup(o->chan); 01599 o->chan = NULL; 01600 }
static void dump_queue_members | ( | struct call_queue * | pm_queue | ) | [static] |
Definition at line 2793 of file app_queue.c.
References ast_db_del(), ast_db_put(), ast_log(), member::dynamic, member::interface, LOG_WARNING, member::membername, call_queue::members, call_queue::name, member::next, member::paused, member::penalty, and PM_MAX_LEN.
Referenced by add_to_queue(), remove_from_queue(), and set_member_paused().
02794 { 02795 struct member *cur_member; 02796 char value[PM_MAX_LEN]; 02797 int value_len = 0; 02798 int res; 02799 02800 memset(value, 0, sizeof(value)); 02801 02802 if (!pm_queue) 02803 return; 02804 02805 for (cur_member = pm_queue->members; cur_member; cur_member = cur_member->next) { 02806 if (!cur_member->dynamic) 02807 continue; 02808 02809 res = snprintf(value + value_len, sizeof(value) - value_len, "%s;%d;%d;%s%s", 02810 cur_member->interface, cur_member->penalty, cur_member->paused, cur_member->membername, 02811 cur_member->next ? "|" : ""); 02812 if (res != strlen(value + value_len)) { 02813 ast_log(LOG_WARNING, "Could not create persistent member string, out of space\n"); 02814 break; 02815 } 02816 value_len += res; 02817 } 02818 02819 if (value_len && !cur_member) { 02820 if (ast_db_put(pm_family, pm_queue->name, value)) 02821 ast_log(LOG_WARNING, "failed to create persistent dynamic entry!\n"); 02822 } else 02823 /* Delete the entry if the queue is empty or there is an error */ 02824 ast_db_del(pm_family, pm_queue->name); 02825 }
static struct callattempt* find_best | ( | struct callattempt * | outgoing | ) | [static] |
find the entry with the best metric, or NULL
Definition at line 1758 of file app_queue.c.
References callattempt::metric, and callattempt::q_next.
01759 { 01760 struct callattempt *best = NULL, *cur; 01761 01762 for (cur = outgoing; cur; cur = cur->q_next) { 01763 if (cur->stillgoing && /* Not already done */ 01764 !cur->chan && /* Isn't already going */ 01765 (!best || cur->metric < best->metric)) { /* We haven't found one yet, or it's better */ 01766 best = cur; 01767 } 01768 } 01769 01770 return best; 01771 }
static struct call_queue* find_queue_by_name_rt | ( | const char * | queuename, | |
struct ast_variable * | queue_vars, | |||
struct ast_config * | member_config | |||
) | [static] |
Reload a single queue via realtime.
Definition at line 1003 of file app_queue.c.
References alloc_queue(), AST_LIST_INSERT_HEAD, AST_LIST_REMOVE, AST_LIST_TRAVERSE, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), clear_queue(), call_queue::dead, destroy_queue(), init_queue(), member_interface::interface, call_queue::lock, LOG_DEBUG, ast_variable::name, call_queue::name, ast_variable::next, queue_set_param(), call_queue::realtime, and ast_variable::value.
Referenced by load_realtime_queue().
01004 { 01005 struct ast_variable *v; 01006 struct call_queue *q; 01007 struct member *m, *prev_m, *next_m; 01008 char *interface = NULL; 01009 char *tmp, *tmp_name; 01010 char tmpbuf[64]; /* Must be longer than the longest queue param name. */ 01011 01012 /* Find the queue in the in-core list (we will create a new one if not found). */ 01013 AST_LIST_TRAVERSE(&queues, q, list) { 01014 if (!strcasecmp(q->name, queuename)) 01015 break; 01016 } 01017 01018 /* Static queues override realtime. */ 01019 if (q) { 01020 ast_mutex_lock(&q->lock); 01021 if (!q->realtime) { 01022 if (q->dead) { 01023 ast_mutex_unlock(&q->lock); 01024 return NULL; 01025 } else { 01026 ast_mutex_unlock(&q->lock); 01027 return q; 01028 } 01029 } 01030 } else if (!member_config) 01031 /* Not found in the list, and it's not realtime ... */ 01032 return NULL; 01033 01034 /* Check if queue is defined in realtime. */ 01035 if (!queue_vars) { 01036 /* Delete queue from in-core list if it has been deleted in realtime. */ 01037 if (q) { 01038 /*! \note Hmm, can't seem to distinguish a DB failure from a not 01039 found condition... So we might delete an in-core queue 01040 in case of DB failure. */ 01041 ast_log(LOG_DEBUG, "Queue %s not found in realtime.\n", queuename); 01042 01043 q->dead = 1; 01044 /* Delete if unused (else will be deleted when last caller leaves). */ 01045 if (!q->count) { 01046 /* Delete. */ 01047 AST_LIST_REMOVE(&queues, q, list); 01048 ast_mutex_unlock(&q->lock); 01049 destroy_queue(q); 01050 } else 01051 ast_mutex_unlock(&q->lock); 01052 } 01053 return NULL; 01054 } 01055 01056 /* Create a new queue if an in-core entry does not exist yet. */ 01057 if (!q) { 01058 if (!(q = alloc_queue(queuename))) 01059 return NULL; 01060 ast_mutex_lock(&q->lock); 01061 clear_queue(q); 01062 q->realtime = 1; 01063 AST_LIST_INSERT_HEAD(&queues, q, list); 01064 } 01065 init_queue(q); /* Ensure defaults for all parameters not set explicitly. */ 01066 01067 memset(tmpbuf, 0, sizeof(tmpbuf)); 01068 for (v = queue_vars; v; v = v->next) { 01069 /* Convert to dashes `-' from underscores `_' as the latter are more SQL friendly. */ 01070 if ((tmp = strchr(v->name, '_'))) { 01071 ast_copy_string(tmpbuf, v->name, sizeof(tmpbuf)); 01072 tmp_name = tmpbuf; 01073 tmp = tmp_name; 01074 while ((tmp = strchr(tmp, '_'))) 01075 *tmp++ = '-'; 01076 } else 01077 tmp_name = v->name; 01078 queue_set_param(q, tmp_name, v->value, -1, 0); 01079 } 01080 01081 if (q->strategy == QUEUE_STRATEGY_ROUNDROBIN) 01082 rr_dep_warning(); 01083 01084 /* Temporarily set non-dynamic members dead so we can detect deleted ones. 01085 * Also set the membercount correctly for realtime*/ 01086 for (m = q->members; m; m = m->next, q->membercount++) { 01087 if (!m->dynamic) 01088 m->dead = 1; 01089 } 01090 01091 while ((interface = ast_category_browse(member_config, interface))) { 01092 rt_handle_member_record(q, interface, 01093 S_OR(ast_variable_retrieve(member_config, interface, "membername"), interface), 01094 ast_variable_retrieve(member_config, interface, "penalty"), 01095 ast_variable_retrieve(member_config, interface, "paused")); 01096 } 01097 01098 /* Delete all realtime members that have been deleted in DB. */ 01099 m = q->members; 01100 prev_m = NULL; 01101 while (m) { 01102 next_m = m->next; 01103 if (m->dead) { 01104 if (prev_m) { 01105 prev_m->next = next_m; 01106 } else { 01107 q->members = next_m; 01108 } 01109 remove_from_interfaces(m->interface); 01110 q->membercount--; 01111 free(m); 01112 } else { 01113 prev_m = m; 01114 } 01115 m = next_m; 01116 } 01117 01118 ast_mutex_unlock(&q->lock); 01119 01120 return q; 01121 }
static void free_members | ( | struct call_queue * | q, | |
int | all | |||
) | [static] |
Definition at line 973 of file app_queue.c.
References member::dynamic, free, member::interface, call_queue::membercount, call_queue::members, member::next, and remove_from_interfaces().
Referenced by destroy_queue().
00974 { 00975 /* Free non-dynamic members */ 00976 struct member *curm, *next, *prev = NULL; 00977 00978 for (curm = q->members; curm; curm = next) { 00979 next = curm->next; 00980 if (all || !curm->dynamic) { 00981 if (prev) 00982 prev->next = next; 00983 else 00984 q->members = next; 00985 remove_from_interfaces(curm->interface); 00986 q->membercount--; 00987 free(curm); 00988 } else 00989 prev = curm; 00990 } 00991 }
static enum queue_member_status get_member_status | ( | struct call_queue * | q, | |
int | max_penalty | |||
) | [static] |
Definition at line 480 of file app_queue.c.
References AST_DEVICE_INVALID, AST_DEVICE_UNAVAILABLE, ast_mutex_lock(), ast_mutex_unlock(), call_queue::lock, call_queue::members, member::next, member::paused, member::penalty, QUEUE_NO_MEMBERS, QUEUE_NO_REACHABLE_MEMBERS, QUEUE_NORMAL, result, and member::status.
Referenced by join_queue(), queue_exec(), and wait_our_turn().
00481 { 00482 struct member *member; 00483 enum queue_member_status result = QUEUE_NO_MEMBERS; 00484 00485 ast_mutex_lock(&q->lock); 00486 for (member = q->members; member; member = member->next) { 00487 if (max_penalty && (member->penalty > max_penalty)) 00488 continue; 00489 00490 if (member->paused) continue; 00491 00492 switch (member->status) { 00493 case AST_DEVICE_INVALID: 00494 /* nothing to do */ 00495 break; 00496 case AST_DEVICE_UNAVAILABLE: 00497 result = QUEUE_NO_REACHABLE_MEMBERS; 00498 break; 00499 default: 00500 ast_mutex_unlock(&q->lock); 00501 return QUEUE_NORMAL; 00502 } 00503 } 00504 00505 ast_mutex_unlock(&q->lock); 00506 return result; 00507 }
static int handle_queue_add_member | ( | int | fd, | |
int | argc, | |||
char * | argv[] | |||
) | [static] |
Definition at line 4311 of file app_queue.c.
References add_to_queue(), ast_cli(), ast_queue_log(), member::interface, member::membername, member::penalty, RES_EXISTS, RES_NOSUCHQUEUE, RES_OKAY, RES_OUTOFMEMORY, RESULT_FAILURE, RESULT_SHOWUSAGE, and RESULT_SUCCESS.
04312 { 04313 char *queuename, *interface, *membername; 04314 int penalty; 04315 04316 if ((argc != 6) && (argc != 8) && (argc != 10)) { 04317 return RESULT_SHOWUSAGE; 04318 } else if (strcmp(argv[4], "to")) { 04319 return RESULT_SHOWUSAGE; 04320 } else if ((argc == 8) && strcmp(argv[6], "penalty")) { 04321 return RESULT_SHOWUSAGE; 04322 } else if ((argc == 10) && strcmp(argv[8], "as")) { 04323 return RESULT_SHOWUSAGE; 04324 } 04325 04326 queuename = argv[5]; 04327 interface = argv[3]; 04328 if (argc >= 8) { 04329 if (sscanf(argv[7], "%d", &penalty) == 1) { 04330 if (penalty < 0) { 04331 ast_cli(fd, "Penalty must be >= 0\n"); 04332 penalty = 0; 04333 } 04334 } else { 04335 ast_cli(fd, "Penalty must be an integer >= 0\n"); 04336 penalty = 0; 04337 } 04338 } else { 04339 penalty = 0; 04340 } 04341 04342 if (argc >= 10) { 04343 membername = argv[9]; 04344 } else { 04345 membername = interface; 04346 } 04347 04348 switch (add_to_queue(queuename, interface, membername, penalty, 0, queue_persistent_members)) { 04349 case RES_OKAY: 04350 ast_queue_log(queuename, "CLI", interface, "ADDMEMBER", "%s", ""); 04351 ast_cli(fd, "Added interface '%s' to queue '%s'\n", interface, queuename); 04352 return RESULT_SUCCESS; 04353 case RES_EXISTS: 04354 ast_cli(fd, "Unable to add interface '%s' to queue '%s': Already there\n", interface, queuename); 04355 return RESULT_FAILURE; 04356 case RES_NOSUCHQUEUE: 04357 ast_cli(fd, "Unable to add interface to queue '%s': No such queue\n", queuename); 04358 return RESULT_FAILURE; 04359 case RES_OUTOFMEMORY: 04360 ast_cli(fd, "Out of memory\n"); 04361 return RESULT_FAILURE; 04362 default: 04363 return RESULT_FAILURE; 04364 } 04365 }
static int handle_queue_remove_member | ( | int | fd, | |
int | argc, | |||
char * | argv[] | |||
) | [static] |
Definition at line 4398 of file app_queue.c.
References ast_cli(), ast_queue_log(), member::interface, remove_from_queue(), RES_EXISTS, RES_NOSUCHQUEUE, RES_OKAY, RES_OUTOFMEMORY, RESULT_FAILURE, RESULT_SHOWUSAGE, and RESULT_SUCCESS.
04399 { 04400 char *queuename, *interface; 04401 04402 if (argc != 6) { 04403 return RESULT_SHOWUSAGE; 04404 } else if (strcmp(argv[4], "from")) { 04405 return RESULT_SHOWUSAGE; 04406 } 04407 04408 queuename = argv[5]; 04409 interface = argv[3]; 04410 04411 switch (remove_from_queue(queuename, interface)) { 04412 case RES_OKAY: 04413 ast_queue_log(queuename, "CLI", interface, "REMOVEMEMBER", "%s", ""); 04414 ast_cli(fd, "Removed interface '%s' from queue '%s'\n", interface, queuename); 04415 return RESULT_SUCCESS; 04416 case RES_EXISTS: 04417 ast_cli(fd, "Unable to remove interface '%s' from queue '%s': Not there\n", interface, queuename); 04418 return RESULT_FAILURE; 04419 case RES_NOSUCHQUEUE: 04420 ast_cli(fd, "Unable to remove interface from queue '%s': No such queue\n", queuename); 04421 return RESULT_FAILURE; 04422 case RES_OUTOFMEMORY: 04423 ast_cli(fd, "Out of memory\n"); 04424 return RESULT_FAILURE; 04425 default: 04426 return RESULT_FAILURE; 04427 } 04428 }
static void hangupcalls | ( | struct callattempt * | outgoing, | |
struct ast_channel * | exception | |||
) | [static] |
Definition at line 1502 of file app_queue.c.
References ast_hangup(), callattempt::chan, free, and callattempt::q_next.
Referenced by try_calling().
01503 { 01504 struct callattempt *oo; 01505 01506 while (outgoing) { 01507 /* Hangup any existing lines we have open */ 01508 if (outgoing->chan && (outgoing->chan != exception)) 01509 ast_hangup(outgoing->chan); 01510 oo = outgoing; 01511 outgoing = outgoing->q_next; 01512 free(oo); 01513 } 01514 }
static void init_queue | ( | struct call_queue * | q | ) | [static] |
Definition at line 649 of file app_queue.c.
References call_queue::announce, call_queue::announcefrequency, call_queue::announceholdtime, call_queue::autofill, call_queue::context, call_queue::dead, DEFAULT_RETRY, MAX_PERIODIC_ANNOUNCEMENTS, call_queue::maxlen, call_queue::membercount, call_queue::moh, call_queue::monfmt, call_queue::montype, call_queue::periodicannouncefrequency, 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, and call_queue::timeout.
Referenced by find_queue_by_name_rt(), and reload_queues().
00650 { 00651 int i; 00652 00653 q->dead = 0; 00654 q->retry = DEFAULT_RETRY; 00655 q->timeout = -1; 00656 q->maxlen = 0; 00657 q->announcefrequency = 0; 00658 q->announceholdtime = 0; 00659 q->roundingseconds = 0; /* Default - don't announce seconds */ 00660 q->servicelevel = 0; 00661 q->ringinuse = 1; 00662 q->setinterfacevar = 0; 00663 q->autofill = autofill_default; 00664 q->montype = montype_default; 00665 q->moh[0] = '\0'; 00666 q->announce[0] = '\0'; 00667 q->context[0] = '\0'; 00668 q->monfmt[0] = '\0'; 00669 q->periodicannouncefrequency = 0; 00670 q->membercount = 0; 00671 ast_copy_string(q->sound_next, "queue-youarenext", sizeof(q->sound_next)); 00672 ast_copy_string(q->sound_thereare, "queue-thereare", sizeof(q->sound_thereare)); 00673 ast_copy_string(q->sound_calls, "queue-callswaiting", sizeof(q->sound_calls)); 00674 ast_copy_string(q->sound_holdtime, "queue-holdtime", sizeof(q->sound_holdtime)); 00675 ast_copy_string(q->sound_minutes, "queue-minutes", sizeof(q->sound_minutes)); 00676 ast_copy_string(q->sound_seconds, "queue-seconds", sizeof(q->sound_seconds)); 00677 ast_copy_string(q->sound_thanks, "queue-thankyou", sizeof(q->sound_thanks)); 00678 ast_copy_string(q->sound_lessthan, "queue-less-than", sizeof(q->sound_lessthan)); 00679 ast_copy_string(q->sound_reporthold, "queue-reporthold", sizeof(q->sound_reporthold)); 00680 ast_copy_string(q->sound_periodicannounce[0], "queue-periodic-announce", sizeof(q->sound_periodicannounce[0])); 00681 for (i = 1; i < MAX_PERIODIC_ANNOUNCEMENTS; i++) { 00682 q->sound_periodicannounce[i][0]='\0'; 00683 } 00684 }
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 455 of file app_queue.c.
References call_queue::head, queue_ent::next, and queue_ent::parent.
Referenced by join_queue().
00456 { 00457 struct queue_ent *cur; 00458 00459 if (!q || !new) 00460 return; 00461 if (prev) { 00462 cur = prev->next; 00463 prev->next = new; 00464 } else { 00465 cur = q->head; 00466 q->head = new; 00467 } 00468 new->next = cur; 00469 new->parent = q; 00470 new->pos = ++(*pos); 00471 new->opos = *pos; 00472 }
static char* int2strat | ( | int | strategy | ) | [static] |
Definition at line 430 of file app_queue.c.
References name, and strategies.
Referenced by __queues_show().
00431 { 00432 int x; 00433 00434 for (x = 0; x < sizeof(strategies) / sizeof(strategies[0]); x++) { 00435 if (strategy == strategies[x].strategy) 00436 return strategies[x].name; 00437 } 00438 00439 return "<unknown>"; 00440 }
static struct member* interface_exists | ( | struct call_queue * | q, | |
const char * | interface | |||
) | [static] |
Definition at line 2772 of file app_queue.c.
References member::interface, call_queue::members, and member::next.
Referenced by add_to_queue(), remove_from_queue(), and set_member_paused().
02773 { 02774 struct member *mem; 02775 02776 if (!q) 02777 return NULL; 02778 02779 for (mem = q->members; mem; mem = mem->next) { 02780 if (!strcasecmp(interface, mem->interface)) 02781 return mem; 02782 } 02783 02784 return NULL; 02785 }
static int interface_exists_global | ( | const char * | interface | ) | [static] |
Definition at line 722 of file app_queue.c.
References AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_mutex_lock(), ast_mutex_unlock(), member::interface, call_queue::lock, call_queue::members, and member::next.
Referenced by remove_from_interfaces().
00723 { 00724 struct call_queue *q; 00725 struct member *mem; 00726 int ret = 0; 00727 00728 AST_LIST_LOCK(&queues); 00729 AST_LIST_TRAVERSE(&queues, q, list) { 00730 ast_mutex_lock(&q->lock); 00731 for (mem = q->members; mem && !ret; mem = mem->next) { 00732 if (!strcasecmp(interface, mem->interface)) 00733 ret = 1; 00734 } 00735 ast_mutex_unlock(&q->lock); 00736 if (ret) 00737 break; 00738 } 00739 AST_LIST_UNLOCK(&queues); 00740 00741 return ret; 00742 }
static int is_our_turn | ( | struct queue_ent * | qe | ) | [static] |
Definition at line 2144 of file app_queue.c.
References 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, member::next, option_debug, queue_ent::parent, QUEUE_STRATEGY_RINGALL, member::status, and call_queue::strategy.
Referenced by queue_exec(), and wait_our_turn().
02145 { 02146 struct queue_ent *ch; 02147 struct member *cur; 02148 int avl = 0; 02149 int idx = 0; 02150 int res; 02151 02152 if (!qe->parent->autofill) { 02153 /* Atomically read the parent head -- does not need a lock */ 02154 ch = qe->parent->head; 02155 /* If we are now at the top of the head, break out */ 02156 if (ch == qe) { 02157 if (option_debug) 02158 ast_log(LOG_DEBUG, "It's our turn (%s).\n", qe->chan->name); 02159 res = 1; 02160 } else { 02161 if (option_debug) 02162 ast_log(LOG_DEBUG, "It's not our turn (%s).\n", qe->chan->name); 02163 res = 0; 02164 } 02165 02166 } else { 02167 /* This needs a lock. How many members are available to be served? */ 02168 ast_mutex_lock(&qe->parent->lock); 02169 02170 ch = qe->parent->head; 02171 02172 if (qe->parent->strategy == QUEUE_STRATEGY_RINGALL) { 02173 if (option_debug) 02174 ast_log(LOG_DEBUG, "Even though there are %d available members, the strategy is ringall so only the head call is allowed in\n", avl); 02175 avl = 1; 02176 } else { 02177 for (cur = qe->parent->members; cur; cur = cur->next) { 02178 switch (cur->status) { 02179 case AST_DEVICE_NOT_INUSE: 02180 case AST_DEVICE_UNKNOWN: 02181 avl++; 02182 break; 02183 } 02184 } 02185 } 02186 02187 if (option_debug) 02188 ast_log(LOG_DEBUG, "There are %d available members.\n", avl); 02189 02190 while ((idx < avl) && (ch) && (ch != qe)) { 02191 idx++; 02192 ch = ch->next; 02193 } 02194 02195 /* If the queue entry is within avl [the number of available members] calls from the top ... */ 02196 if (ch && idx < avl) { 02197 if (option_debug) 02198 ast_log(LOG_DEBUG, "It's our turn (%s).\n", qe->chan->name); 02199 res = 1; 02200 } else { 02201 if (option_debug) 02202 ast_log(LOG_DEBUG, "It's not our turn (%s).\n", qe->chan->name); 02203 res = 0; 02204 } 02205 02206 ast_mutex_unlock(&qe->parent->lock); 02207 } 02208 02209 return res; 02210 }
static int join_queue | ( | char * | queuename, | |
struct queue_ent * | qe, | |||
enum queue_result * | reason | |||
) | [static] |
Definition at line 1223 of file app_queue.c.
References queue_ent::announce, AST_LIST_LOCK, AST_LIST_UNLOCK, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), queue_ent::chan, ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, queue_ent::context, call_queue::count, EVENT_FLAG_CALL, get_member_status(), call_queue::head, insert_entry(), call_queue::joinempty, load_realtime_queue(), call_queue::lock, LOG_DEBUG, manager_event(), queue_ent::max_penalty, call_queue::maxlen, queue_ent::moh, queue_ent::next, option_debug, queue_ent::pos, queue_ent::prio, QUEUE_EMPTY_STRICT, QUEUE_FULL, QUEUE_JOINEMPTY, QUEUE_JOINUNAVAIL, QUEUE_NO_MEMBERS, QUEUE_NO_REACHABLE_MEMBERS, and S_OR.
Referenced by queue_exec().
01224 { 01225 struct call_queue *q; 01226 struct queue_ent *cur, *prev = NULL; 01227 int res = -1; 01228 int pos = 0; 01229 int inserted = 0; 01230 enum queue_member_status stat; 01231 01232 if (!(q = load_realtime_queue(queuename))) 01233 return res; 01234 01235 AST_LIST_LOCK(&queues); 01236 ast_mutex_lock(&q->lock); 01237 01238 /* This is our one */ 01239 stat = get_member_status(q, qe->max_penalty); 01240 if (!q->joinempty && (stat == QUEUE_NO_MEMBERS)) 01241 *reason = QUEUE_JOINEMPTY; 01242 else if ((q->joinempty == QUEUE_EMPTY_STRICT) && (stat == QUEUE_NO_REACHABLE_MEMBERS)) 01243 *reason = QUEUE_JOINUNAVAIL; 01244 else if (q->maxlen && (q->count >= q->maxlen)) 01245 *reason = QUEUE_FULL; 01246 else { 01247 /* There's space for us, put us at the right position inside 01248 * the queue. 01249 * Take into account the priority of the calling user */ 01250 inserted = 0; 01251 prev = NULL; 01252 cur = q->head; 01253 while (cur) { 01254 /* We have higher priority than the current user, enter 01255 * before him, after all the other users with priority 01256 * higher or equal to our priority. */ 01257 if ((!inserted) && (qe->prio > cur->prio)) { 01258 insert_entry(q, prev, qe, &pos); 01259 inserted = 1; 01260 } 01261 cur->pos = ++pos; 01262 prev = cur; 01263 cur = cur->next; 01264 } 01265 /* No luck, join at the end of the queue */ 01266 if (!inserted) 01267 insert_entry(q, prev, qe, &pos); 01268 ast_copy_string(qe->moh, q->moh, sizeof(qe->moh)); 01269 ast_copy_string(qe->announce, q->announce, sizeof(qe->announce)); 01270 ast_copy_string(qe->context, q->context, sizeof(qe->context)); 01271 q->count++; 01272 res = 0; 01273 manager_event(EVENT_FLAG_CALL, "Join", 01274 "Channel: %s\r\nCallerID: %s\r\nCallerIDName: %s\r\nQueue: %s\r\nPosition: %d\r\nCount: %d\r\nUniqueid: %s\r\n", 01275 qe->chan->name, 01276 S_OR(qe->chan->cid.cid_num, "unknown"), /* XXX somewhere else it is <unknown> */ 01277 S_OR(qe->chan->cid.cid_name, "unknown"), 01278 q->name, qe->pos, q->count, qe->chan->uniqueid ); 01279 if (option_debug) 01280 ast_log(LOG_DEBUG, "Queue '%s' Join, Channel '%s', Position '%d'\n", q->name, qe->chan->name, qe->pos ); 01281 } 01282 ast_mutex_unlock(&q->lock); 01283 AST_LIST_UNLOCK(&queues); 01284 01285 return res; 01286 }
static void leave_queue | ( | struct queue_ent * | qe | ) | [static] |
Definition at line 1458 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().
01459 { 01460 struct call_queue *q; 01461 struct queue_ent *cur, *prev = NULL; 01462 int pos = 0; 01463 01464 if (!(q = qe->parent)) 01465 return; 01466 ast_mutex_lock(&q->lock); 01467 01468 prev = NULL; 01469 for (cur = q->head; cur; cur = cur->next) { 01470 if (cur == qe) { 01471 q->count--; 01472 01473 /* Take us out of the queue */ 01474 manager_event(EVENT_FLAG_CALL, "Leave", 01475 "Channel: %s\r\nQueue: %s\r\nCount: %d\r\nUniqueid: %s\r\n", 01476 qe->chan->name, q->name, q->count, qe->chan->uniqueid); 01477 if (option_debug) 01478 ast_log(LOG_DEBUG, "Queue '%s' Leave, Channel '%s'\n", q->name, qe->chan->name ); 01479 /* Take us out of the queue */ 01480 if (prev) 01481 prev->next = cur->next; 01482 else 01483 q->head = cur->next; 01484 } else { 01485 /* Renumber the people after us in the queue based on a new count */ 01486 cur->pos = ++pos; 01487 prev = cur; 01488 } 01489 } 01490 ast_mutex_unlock(&q->lock); 01491 01492 if (q->dead && !q->count) { 01493 /* It's dead and nobody is in it, so kill it */ 01494 AST_LIST_LOCK(&queues); 01495 AST_LIST_REMOVE(&queues, q, list); 01496 AST_LIST_UNLOCK(&queues); 01497 destroy_queue(q); 01498 } 01499 }
static int load_module | ( | void | ) | [static] |
Definition at line 4536 of file app_queue.c.
References aqm_exec(), ast_cli_register_multiple(), ast_custom_function_register(), ast_devstate_add(), ast_manager_register, AST_MODULE_LOAD_DECLINE, ast_register_application(), cli_queue, 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().
04537 { 04538 int res; 04539 if(!reload_queues()) 04540 return AST_MODULE_LOAD_DECLINE; 04541 if (queue_persistent_members) 04542 reload_queue_members(); 04543 ast_cli_register_multiple(cli_queue, sizeof(cli_queue) / sizeof(struct ast_cli_entry)); 04544 res = ast_register_application(app, queue_exec, synopsis, descrip); 04545 res |= ast_register_application(app_aqm, aqm_exec, app_aqm_synopsis, app_aqm_descrip); 04546 res |= ast_register_application(app_rqm, rqm_exec, app_rqm_synopsis, app_rqm_descrip); 04547 res |= ast_register_application(app_pqm, pqm_exec, app_pqm_synopsis, app_pqm_descrip); 04548 res |= ast_register_application(app_upqm, upqm_exec, app_upqm_synopsis, app_upqm_descrip); 04549 res |= ast_register_application(app_ql, ql_exec, app_ql_synopsis, app_ql_descrip); 04550 res |= ast_manager_register("Queues", 0, manager_queues_show, "Queues"); 04551 res |= ast_manager_register("QueueStatus", 0, manager_queues_status, "Queue Status"); 04552 res |= ast_manager_register("QueueAdd", EVENT_FLAG_AGENT, manager_add_queue_member, "Add interface to queue."); 04553 res |= ast_manager_register("QueueRemove", EVENT_FLAG_AGENT, manager_remove_queue_member, "Remove interface from queue."); 04554 res |= ast_manager_register("QueuePause", EVENT_FLAG_AGENT, manager_pause_queue_member, "Makes a queue member temporarily unavailable"); 04555 res |= ast_custom_function_register(&queueagentcount_function); 04556 res |= ast_custom_function_register(&queuemembercount_function); 04557 res |= ast_custom_function_register(&queuememberlist_function); 04558 res |= ast_custom_function_register(&queuewaitingcount_function); 04559 res |= ast_devstate_add(statechange_queue, NULL); 04560 04561 return res; 04562 }
static struct call_queue* load_realtime_queue | ( | const char * | queuename | ) | [static] |
Definition at line 1174 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(), and reload_queue_members().
01175 { 01176 struct ast_variable *queue_vars; 01177 struct ast_config *member_config = NULL; 01178 struct call_queue *q; 01179 01180 /* Find the queue in the in-core list first. */ 01181 AST_LIST_LOCK(&queues); 01182 AST_LIST_TRAVERSE(&queues, q, list) { 01183 if (!strcasecmp(q->name, queuename)) { 01184 break; 01185 } 01186 } 01187 AST_LIST_UNLOCK(&queues); 01188 01189 if (!q || q->realtime) { 01190 /*! \note Load from realtime before taking the global qlock, to avoid blocking all 01191 queue operations while waiting for the DB. 01192 01193 This will be two separate database transactions, so we might 01194 see queue parameters as they were before another process 01195 changed the queue and member list as it was after the change. 01196 Thus we might see an empty member list when a queue is 01197 deleted. In practise, this is unlikely to cause a problem. */ 01198 01199 queue_vars = ast_load_realtime("queues", "name", queuename, NULL); 01200 if (queue_vars) { 01201 member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name", queuename, NULL); 01202 if (!member_config) { 01203 ast_log(LOG_ERROR, "no queue_members defined in your config (extconfig.conf).\n"); 01204 return NULL; 01205 } 01206 } 01207 01208 AST_LIST_LOCK(&queues); 01209 01210 q = find_queue_by_name_rt(queuename, queue_vars, member_config); 01211 if (member_config) 01212 ast_config_destroy(member_config); 01213 if (queue_vars) 01214 ast_variables_destroy(queue_vars); 01215 01216 AST_LIST_UNLOCK(&queues); 01217 } else { 01218 update_realtime_members(q); 01219 } 01220 return q; 01221 }
static int manager_add_queue_member | ( | struct mansession * | s, | |
const struct message * | m | |||
) | [static] |
Definition at line 4204 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, member::membername, member::paused, member::penalty, RES_EXISTS, RES_NOSUCHQUEUE, RES_OKAY, RES_OUTOFMEMORY, and s.
Referenced by load_module().
04205 { 04206 const char *queuename, *interface, *penalty_s, *paused_s, *membername; 04207 int paused, penalty = 0; 04208 04209 queuename = astman_get_header(m, "Queue"); 04210 interface = astman_get_header(m, "Interface"); 04211 penalty_s = astman_get_header(m, "Penalty"); 04212 paused_s = astman_get_header(m, "Paused"); 04213 membername = astman_get_header(m, "MemberName"); 04214 04215 if (ast_strlen_zero(queuename)) { 04216 astman_send_error(s, m, "'Queue' not specified."); 04217 return 0; 04218 } 04219 04220 if (ast_strlen_zero(interface)) { 04221 astman_send_error(s, m, "'Interface' not specified."); 04222 return 0; 04223 } 04224 04225 if (ast_strlen_zero(penalty_s)) 04226 penalty = 0; 04227 else if (sscanf(penalty_s, "%d", &penalty) != 1) 04228 penalty = 0; 04229 04230 if (ast_strlen_zero(paused_s)) 04231 paused = 0; 04232 else 04233 paused = abs(ast_true(paused_s)); 04234 04235 if (ast_strlen_zero(membername)) 04236 membername = interface; 04237 04238 switch (add_to_queue(queuename, interface, membername, penalty, paused, queue_persistent_members)) { 04239 case RES_OKAY: 04240 ast_queue_log(queuename, "MANAGER", interface, "ADDMEMBER", "%s", ""); 04241 astman_send_ack(s, m, "Added interface to queue"); 04242 break; 04243 case RES_EXISTS: 04244 astman_send_error(s, m, "Unable to add interface: Already there"); 04245 break; 04246 case RES_NOSUCHQUEUE: 04247 astman_send_error(s, m, "Unable to add interface to queue: No such queue"); 04248 break; 04249 case RES_OUTOFMEMORY: 04250 astman_send_error(s, m, "Out of memory"); 04251 break; 04252 } 04253 04254 return 0; 04255 }
static int manager_pause_queue_member | ( | struct mansession * | s, | |
const struct message * | m | |||
) | [static] |
Definition at line 4288 of file app_queue.c.
References ast_strlen_zero(), ast_true(), astman_get_header(), astman_send_ack(), astman_send_error(), member::interface, member::paused, s, and set_member_paused().
Referenced by load_module().
04289 { 04290 const char *queuename, *interface, *paused_s; 04291 int paused; 04292 04293 interface = astman_get_header(m, "Interface"); 04294 paused_s = astman_get_header(m, "Paused"); 04295 queuename = astman_get_header(m, "Queue"); /* Optional - if not supplied, pause the given Interface in all queues */ 04296 04297 if (ast_strlen_zero(interface) || ast_strlen_zero(paused_s)) { 04298 astman_send_error(s, m, "Need 'Interface' and 'Paused' parameters."); 04299 return 0; 04300 } 04301 04302 paused = abs(ast_true(paused_s)); 04303 04304 if (set_member_paused(queuename, interface, paused)) 04305 astman_send_error(s, m, "Interface not found"); 04306 else 04307 astman_send_ack(s, m, paused ? "Interface paused successfully" : "Interface unpaused successfully"); 04308 return 0; 04309 }
static int manager_queues_show | ( | struct mansession * | s, | |
const struct message * | m | |||
) | [static] |
Definition at line 4104 of file app_queue.c.
References __queues_show(), astman_append(), RESULT_SUCCESS, and s.
Referenced by load_module().
04105 { 04106 char *a[] = { "queue", "show" }; 04107 04108 __queues_show(s, 1, -1, 2, a); 04109 astman_append(s, "\r\n\r\n"); /* Properly terminate Manager output */ 04110 04111 return RESULT_SUCCESS; 04112 }
static int manager_queues_status | ( | struct mansession * | s, | |
const struct message * | m | |||
) | [static] |
Definition at line 4115 of file app_queue.c.
References 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, call_queue::members, call_queue::name, queue_ent::next, member::next, member::paused, member::penalty, RESULT_SUCCESS, s, S_OR, call_queue::servicelevel, queue_ent::start, member::status, and call_queue::weight.
Referenced by load_module().
04116 { 04117 time_t now; 04118 int pos; 04119 const char *id = astman_get_header(m,"ActionID"); 04120 const char *queuefilter = astman_get_header(m,"Queue"); 04121 const char *memberfilter = astman_get_header(m,"Member"); 04122 char idText[256] = ""; 04123 struct call_queue *q; 04124 struct queue_ent *qe; 04125 float sl = 0; 04126 struct member *mem; 04127 04128 astman_send_ack(s, m, "Queue status will follow"); 04129 time(&now); 04130 AST_LIST_LOCK(&queues); 04131 if (!ast_strlen_zero(id)) 04132 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id); 04133 04134 AST_LIST_TRAVERSE(&queues, q, list) { 04135 ast_mutex_lock(&q->lock); 04136 04137 /* List queue properties */ 04138 if (ast_strlen_zero(queuefilter) || !strcmp(q->name, queuefilter)) { 04139 sl = ((q->callscompleted > 0) ? 100 * ((float)q->callscompletedinsl / (float)q->callscompleted) : 0); 04140 astman_append(s, "Event: QueueParams\r\n" 04141 "Queue: %s\r\n" 04142 "Max: %d\r\n" 04143 "Calls: %d\r\n" 04144 "Holdtime: %d\r\n" 04145 "Completed: %d\r\n" 04146 "Abandoned: %d\r\n" 04147 "ServiceLevel: %d\r\n" 04148 "ServicelevelPerf: %2.1f\r\n" 04149 "Weight: %d\r\n" 04150 "%s" 04151 "\r\n", 04152 q->name, q->maxlen, q->count, q->holdtime, q->callscompleted, 04153 q->callsabandoned, q->servicelevel, sl, q->weight, idText); 04154 /* List Queue Members */ 04155 for (mem = q->members; mem; mem = mem->next) { 04156 if (ast_strlen_zero(memberfilter) || !strcmp(mem->interface, memberfilter)) { 04157 astman_append(s, "Event: QueueMember\r\n" 04158 "Queue: %s\r\n" 04159 "Location: %s\r\n" 04160 "Membership: %s\r\n" 04161 "Penalty: %d\r\n" 04162 "CallsTaken: %d\r\n" 04163 "LastCall: %d\r\n" 04164 "Status: %d\r\n" 04165 "Paused: %d\r\n" 04166 "%s" 04167 "\r\n", 04168 q->name, mem->interface, mem->dynamic ? "dynamic" : "static", 04169 mem->penalty, mem->calls, (int)mem->lastcall, mem->status, mem->paused, idText); 04170 } 04171 } 04172 /* List Queue Entries */ 04173 pos = 1; 04174 for (qe = q->head; qe; qe = qe->next) { 04175 astman_append(s, "Event: QueueEntry\r\n" 04176 "Queue: %s\r\n" 04177 "Position: %d\r\n" 04178 "Channel: %s\r\n" 04179 "CallerID: %s\r\n" 04180 "CallerIDName: %s\r\n" 04181 "Wait: %ld\r\n" 04182 "%s" 04183 "\r\n", 04184 q->name, pos++, qe->chan->name, 04185 S_OR(qe->chan->cid.cid_num, "unknown"), 04186 S_OR(qe->chan->cid.cid_name, "unknown"), 04187 (long) (now - qe->start), idText); 04188 } 04189 } 04190 ast_mutex_unlock(&q->lock); 04191 } 04192 04193 astman_append(s, 04194 "Event: QueueStatusComplete\r\n" 04195 "%s" 04196 "\r\n",idText); 04197 04198 AST_LIST_UNLOCK(&queues); 04199 04200 04201 return RESULT_SUCCESS; 04202 }
static int manager_remove_queue_member | ( | struct mansession * | s, | |
const struct message * | m | |||
) | [static] |
Definition at line 4257 of file app_queue.c.
References ast_queue_log(), ast_strlen_zero(), astman_get_header(), astman_send_ack(), astman_send_error(), member::interface, remove_from_queue(), RES_EXISTS, RES_NOSUCHQUEUE, RES_OKAY, RES_OUTOFMEMORY, and s.
Referenced by load_module().
04258 { 04259 const char *queuename, *interface; 04260 04261 queuename = astman_get_header(m, "Queue"); 04262 interface = astman_get_header(m, "Interface"); 04263 04264 if (ast_strlen_zero(queuename) || ast_strlen_zero(interface)) { 04265 astman_send_error(s, m, "Need 'Queue' and 'Interface' parameters."); 04266 return 0; 04267 } 04268 04269 switch (remove_from_queue(queuename, interface)) { 04270 case RES_OKAY: 04271 ast_queue_log(queuename, "MANAGER", interface, "REMOVEMEMBER", "%s", ""); 04272 astman_send_ack(s, m, "Removed interface from queue"); 04273 break; 04274 case RES_EXISTS: 04275 astman_send_error(s, m, "Unable to remove interface: Not there"); 04276 break; 04277 case RES_NOSUCHQUEUE: 04278 astman_send_error(s, m, "Unable to remove interface from queue: No such queue"); 04279 break; 04280 case RES_OUTOFMEMORY: 04281 astman_send_error(s, m, "Out of memory"); 04282 break; 04283 } 04284 04285 return 0; 04286 }
static int play_file | ( | struct ast_channel * | chan, | |
char * | filename | |||
) | [static] |
Definition at line 1288 of file app_queue.c.
References AST_DIGIT_ANY, ast_stopstream(), ast_streamfile(), ast_waitstream(), and queue_ent::chan.
Referenced by say_periodic_announcement(), say_position(), and try_calling().
01289 { 01290 int res; 01291 01292 ast_stopstream(chan); 01293 01294 res = ast_streamfile(chan, filename, chan->language); 01295 if (!res) 01296 res = ast_waitstream(chan, AST_DIGIT_ANY); 01297 01298 ast_stopstream(chan); 01299 01300 return res; 01301 }
static int pqm_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Definition at line 3072 of file app_queue.c.
References AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_goto_if_exists(), ast_log(), ast_module_user_add, ast_module_user_remove, ast_opt_priority_jumping, AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), ast_module_user::chan, ast_channel::context, LOG_WARNING, parse(), pbx_builtin_setvar_helper(), and set_member_paused().
Referenced by load_module().
03073 { 03074 struct ast_module_user *lu; 03075 char *parse; 03076 int priority_jump = 0; 03077 AST_DECLARE_APP_ARGS(args, 03078 AST_APP_ARG(queuename); 03079 AST_APP_ARG(interface); 03080 AST_APP_ARG(options); 03081 ); 03082 03083 if (ast_strlen_zero(data)) { 03084 ast_log(LOG_WARNING, "PauseQueueMember requires an argument ([queuename]|interface[|options])\n"); 03085 return -1; 03086 } 03087 03088 parse = ast_strdupa(data); 03089 03090 AST_STANDARD_APP_ARGS(args, parse); 03091 03092 lu = ast_module_user_add(chan); 03093 03094 if (args.options) { 03095 if (strchr(args.options, 'j')) 03096 priority_jump = 1; 03097 } 03098 03099 if (ast_strlen_zero(args.interface)) { 03100 ast_log(LOG_WARNING, "Missing interface argument to PauseQueueMember ([queuename]|interface[|options])\n"); 03101 ast_module_user_remove(lu); 03102 return -1; 03103 } 03104 03105 if (set_member_paused(args.queuename, args.interface, 1)) { 03106 ast_log(LOG_WARNING, "Attempt to pause interface %s, not found\n", args.interface); 03107 if (priority_jump || ast_opt_priority_jumping) { 03108 if (ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101)) { 03109 pbx_builtin_setvar_helper(chan, "PQMSTATUS", "NOTFOUND"); 03110 ast_module_user_remove(lu); 03111 return 0; 03112 } 03113 } 03114 ast_module_user_remove(lu); 03115 pbx_builtin_setvar_helper(chan, "PQMSTATUS", "NOTFOUND"); 03116 return -1; 03117 } 03118 03119 ast_module_user_remove(lu); 03120 pbx_builtin_setvar_helper(chan, "PQMSTATUS", "PAUSED"); 03121 03122 return 0; 03123 }
static int ql_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Definition at line 3318 of file app_queue.c.
References AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_log(), ast_module_user_add, ast_module_user_remove, ast_queue_log(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), ast_module_user::chan, event, LOG_WARNING, and parse().
Referenced by load_module().
03319 { 03320 struct ast_module_user *u; 03321 char *parse; 03322 03323 AST_DECLARE_APP_ARGS(args, 03324 AST_APP_ARG(queuename); 03325 AST_APP_ARG(uniqueid); 03326 AST_APP_ARG(membername); 03327 AST_APP_ARG(event); 03328 AST_APP_ARG(params); 03329 ); 03330 03331 if (ast_strlen_zero(data)) { 03332 ast_log(LOG_WARNING, "QueueLog requires arguments (queuename|uniqueid|membername|event[|additionalinfo]\n"); 03333 return -1; 03334 } 03335 03336 u = ast_module_user_add(chan); 03337 03338 parse = ast_strdupa(data); 03339 03340 AST_STANDARD_APP_ARGS(args, parse); 03341 03342 if (ast_strlen_zero(args.queuename) || ast_strlen_zero(args.uniqueid) 03343 || ast_strlen_zero(args.membername) || ast_strlen_zero(args.event)) { 03344 ast_log(LOG_WARNING, "QueueLog requires arguments (queuename|uniqueid|membername|event[|additionalinfo])\n"); 03345 ast_module_user_remove(u); 03346 return -1; 03347 } 03348 03349 ast_queue_log(args.queuename, args.uniqueid, args.membername, args.event, 03350 "%s", args.params ? args.params : ""); 03351 03352 ast_module_user_remove(u); 03353 03354 return 0; 03355 }
static int queue_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Definition at line 3357 of file app_queue.c.
References AST_APP_ARG, AST_CONTROL_RINGING, AST_DECLARE_APP_ARGS, ast_indicate(), ast_log(), ast_module_user_add, ast_moh_start(), ast_moh_stop(), AST_PBX_KEEPALIVE, ast_queue_log(), AST_STANDARD_APP_ARGS, ast_stopstream(), ast_strdupa, ast_strlen_zero(), ast_verbose(), queue_ent::chan, ast_channel::cid, ast_callerid::cid_num, get_member_status(), is_our_turn(), join_queue(), leave_queue(), LOG_DEBUG, LOG_WARNING, option_debug, option_verbose, parse(), pbx_builtin_getvar_helper(), QUEUE_EMPTY_STRICT, QUEUE_LEAVEEMPTY, QUEUE_LEAVEUNAVAIL, QUEUE_NO_MEMBERS, QUEUE_NO_REACHABLE_MEMBERS, QUEUE_TIMEOUT, QUEUE_UNKNOWN, record_abandoned(), S_OR, say_periodic_announcement(), say_position(), set_queue_result(), try_calling(), update_realtime_members(), VERBOSE_PREFIX_3, wait_a_bit(), and wait_our_turn().
Referenced by load_module().
03358 { 03359 int res=-1; 03360 int ringing=0; 03361 struct ast_module_user *lu; 03362 const char *user_priority; 03363 const char *max_penalty_str; 03364 int prio; 03365 int max_penalty; 03366 enum queue_result reason = QUEUE_UNKNOWN; 03367 /* whether to exit Queue application after the timeout hits */ 03368 int tries = 0; 03369 int noption = 0; 03370 char *parse; 03371 AST_DECLARE_APP_ARGS(args, 03372 AST_APP_ARG(queuename); 03373 AST_APP_ARG(options); 03374 AST_APP_ARG(url); 03375 AST_APP_ARG(announceoverride); 03376 AST_APP_ARG(queuetimeoutstr); 03377 AST_APP_ARG(agi); 03378 ); 03379 /* Our queue entry */ 03380 struct queue_ent qe; 03381 03382 if (ast_strlen_zero(data)) { 03383 ast_log(LOG_WARNING, "Queue requires an argument: queuename[|options[|URL[|announceoverride[|timeout[|agi]]]]]\n"); 03384 return -1; 03385 } 03386 03387 parse = ast_strdupa(data); 03388 AST_STANDARD_APP_ARGS(args, parse); 03389 03390 lu = ast_module_user_add(chan); 03391 03392 /* Setup our queue entry */ 03393 memset(&qe, 0, sizeof(qe)); 03394 qe.start = time(NULL); 03395 03396 /* set the expire time based on the supplied timeout; */ 03397 if (args.queuetimeoutstr) 03398 qe.expire = qe.start + atoi(args.queuetimeoutstr); 03399 else 03400 qe.expire = 0; 03401 03402 /* Get the priority from the variable ${QUEUE_PRIO} */ 03403 user_priority = pbx_builtin_getvar_helper(chan, "QUEUE_PRIO"); 03404 if (user_priority) { 03405 if (sscanf(user_priority, "%d", &prio) == 1) { 03406 if (option_debug) 03407 ast_log(LOG_DEBUG, "%s: Got priority %d from ${QUEUE_PRIO}.\n", 03408 chan->name, prio); 03409 } else { 03410 ast_log(LOG_WARNING, "${QUEUE_PRIO}: Invalid value (%s), channel %s.\n", 03411 user_priority, chan->name); 03412 prio = 0; 03413 } 03414 } else { 03415 if (option_debug > 2) 03416 ast_log(LOG_DEBUG, "NO QUEUE_PRIO variable found. Using default.\n"); 03417 prio = 0; 03418 } 03419 03420 /* Get the maximum penalty from the variable ${QUEUE_MAX_PENALTY} */ 03421 if ((max_penalty_str = pbx_builtin_getvar_helper(chan, "QUEUE_MAX_PENALTY"))) { 03422 if (sscanf(max_penalty_str, "%d", &max_penalty) == 1) { 03423 if (option_debug) 03424 ast_log(LOG_DEBUG, "%s: Got max penalty %d from ${QUEUE_MAX_PENALTY}.\n", 03425 chan->name, max_penalty); 03426 } else { 03427 ast_log(LOG_WARNING, "${QUEUE_MAX_PENALTY}: Invalid value (%s), channel %s.\n", 03428 max_penalty_str, chan->name); 03429 max_penalty = 0; 03430 } 03431 } else { 03432 max_penalty = 0; 03433 } 03434 03435 if (args.options && (strchr(args.options, 'r'))) 03436 ringing = 1; 03437 03438 if (option_debug) 03439 ast_log(LOG_DEBUG, "queue: %s, options: %s, url: %s, announce: %s, expires: %ld, priority: %d\n", 03440 args.queuename, args.options, args.url, args.announceoverride, (long)qe.expire, prio); 03441 03442 qe.chan = chan; 03443 qe.prio = prio; 03444 qe.max_penalty = max_penalty; 03445 qe.last_pos_said = 0; 03446 qe.last_pos = 0; 03447 qe.last_periodic_announce_time = time(NULL); 03448 qe.last_periodic_announce_sound = 0; 03449 qe.valid_digits = 0; 03450 if (!join_queue(args.queuename, &qe, &reason)) { 03451 int makeannouncement = 0; 03452 03453 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "ENTERQUEUE", "%s|%s", S_OR(args.url, ""), 03454 S_OR(chan->cid.cid_num, "")); 03455 check_turns: 03456 if (ringing) { 03457 ast_indicate(chan, AST_CONTROL_RINGING); 03458 } else { 03459 ast_moh_start(chan, qe.moh, NULL); 03460 } 03461 03462 /* This is the wait loop for callers 2 through maxlen */ 03463 res = wait_our_turn(&qe, ringing, &reason); 03464 if (res) 03465 goto stop; 03466 03467 for (;;) { 03468 /* This is the wait loop for the head caller*/ 03469 /* To exit, they may get their call answered; */ 03470 /* they may dial a digit from the queue context; */ 03471 /* or, they may timeout. */ 03472 03473 enum queue_member_status stat; 03474 03475 /* Leave if we have exceeded our queuetimeout */ 03476 if (qe.expire && (time(NULL) > qe.expire)) { 03477 record_abandoned(&qe); 03478 reason = QUEUE_TIMEOUT; 03479 res = 0; 03480 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHTIMEOUT", "%d", qe.pos); 03481 break; 03482 } 03483 03484 if (makeannouncement) { 03485 /* Make a position announcement, if enabled */ 03486 if (qe.parent->announcefrequency && !ringing) 03487 if ((res = say_position(&qe))) 03488 goto stop; 03489 03490 } 03491 makeannouncement = 1; 03492 03493 /* Make a periodic announcement, if enabled */ 03494 if (qe.parent->periodicannouncefrequency && !ringing) 03495 if ((res = say_periodic_announcement(&qe))) 03496 goto stop; 03497 03498 /* Try calling all queue members for 'timeout' seconds */ 03499 res = try_calling(&qe, args.options, args.announceoverride, args.url, &tries, &noption, args.agi); 03500 if (res) 03501 goto stop; 03502 03503 stat = get_member_status(qe.parent, qe.max_penalty); 03504 03505 /* exit after 'timeout' cycle if 'n' option enabled */ 03506 if (noption && tries >= qe.parent->membercount) { 03507 if (option_verbose > 2) 03508 ast_verbose(VERBOSE_PREFIX_3 "Exiting on time-out cycle\n"); 03509 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHTIMEOUT", "%d", qe.pos); 03510 record_abandoned(&qe); 03511 reason = QUEUE_TIMEOUT; 03512 res = 0; 03513 break; 03514 } 03515 03516 /* leave the queue if no agents, if enabled */ 03517 if (qe.parent->leavewhenempty && (stat == QUEUE_NO_MEMBERS)) { 03518 record_abandoned(&qe); 03519 reason = QUEUE_LEAVEEMPTY; 03520 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe.pos, qe.opos, (long)(time(NULL) - qe.start)); 03521 res = 0; 03522 break; 03523 } 03524 03525 /* leave the queue if no reachable agents, if enabled */ 03526 if ((qe.parent->leavewhenempty == QUEUE_EMPTY_STRICT) && (stat == QUEUE_NO_REACHABLE_MEMBERS)) { 03527 record_abandoned(&qe); 03528 reason = QUEUE_LEAVEUNAVAIL; 03529 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe.pos, qe.opos, (long)(time(NULL) - qe.start)); 03530 res = 0; 03531 break; 03532 } 03533 03534 /* Leave if we have exceeded our queuetimeout */ 03535 if (qe.expire && (time(NULL) > qe.expire)) { 03536 record_abandoned(&qe); 03537 reason = QUEUE_TIMEOUT; 03538 res = 0; 03539 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHTIMEOUT", "%d", qe.pos); 03540 break; 03541 } 03542 03543 /* If using dynamic realtime members, we should regenerate the member list for this queue */ 03544 update_realtime_members(qe.parent); 03545 03546 /* OK, we didn't get anybody; wait for 'retry' seconds; may get a digit to exit with */ 03547 res = wait_a_bit(&qe); 03548 if (res) 03549 goto stop; 03550 03551 03552 /* Since this is a priority queue and 03553 * it is not sure that we are still at the head 03554 * of the queue, go and check for our turn again. 03555 */ 03556 if (!is_our_turn(&qe)) { 03557 if (option_debug) 03558 ast_log(LOG_DEBUG, "Darn priorities, going back in queue (%s)!\n", 03559 qe.chan->name); 03560 goto check_turns; 03561 } 03562 } 03563 03564 stop: 03565 if (res) { 03566 if (res < 0) { 03567 if (!qe.handled) { 03568 record_abandoned(&qe); 03569 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "ABANDON", 03570 "%d|%d|%ld", qe.pos, qe.opos, 03571 (long) time(NULL) - qe.start); 03572 } 03573 res = -1; 03574 } else if (qe.valid_digits) { 03575 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHKEY", 03576 "%s|%d", qe.digits, qe.pos); 03577 } 03578 } 03579 03580 /* Don't allow return code > 0 */ 03581 if (res >= 0 && res != AST_PBX_KEEPALIVE) { 03582 res = 0; 03583 if (ringing) { 03584 ast_indicate(chan, -1); 03585 } else { 03586 ast_moh_stop(chan); 03587 } 03588 ast_stopstream(chan); 03589 } 03590 leave_queue(&qe); 03591 if (reason != QUEUE_UNKNOWN) 03592 set_queue_result(chan, reason); 03593 } else { 03594 ast_log(LOG_WARNING, "Unable to join queue '%s'\n", args.queuename); 03595 set_queue_result(chan, reason); 03596 res = 0; 03597 } 03598 ast_module_user_remove(lu); 03599 03600 return res; 03601 }
static int queue_function_qac | ( | struct ast_channel * | chan, | |
char * | cmd, | |||
char * | data, | |||
char * | buf, | |||
size_t | len | |||
) | [static] |
Definition at line 3603 of file app_queue.c.
References 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(), ast_module_user::chan, call_queue::lock, LOG_ERROR, LOG_WARNING, call_queue::membercount, and call_queue::name.
03604 { 03605 int count = 0; 03606 struct call_queue *q; 03607 struct ast_module_user *lu; 03608 03609 buf[0] = '\0'; 03610 03611 if (ast_strlen_zero(data)) { 03612 ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd); 03613 return -1; 03614 } 03615 03616 lu = ast_module_user_add(chan); 03617 03618 AST_LIST_LOCK(&queues); 03619 AST_LIST_TRAVERSE(&queues, q, list) { 03620 if (!strcasecmp(q->name, data)) { 03621 ast_mutex_lock(&q->lock); 03622 break; 03623 } 03624 } 03625 AST_LIST_UNLOCK(&queues); 03626 03627 if (q) { 03628 count = q->membercount; 03629 ast_mutex_unlock(&q->lock); 03630 } else 03631 ast_log(LOG_WARNING, "queue %s was not found\n", data); 03632 03633 snprintf(buf, len, "%d", count); 03634 ast_module_user_remove(lu); 03635 03636 return 0; 03637 }
static int queue_function_queuememberlist | ( | struct ast_channel * | chan, | |
char * | cmd, | |||
char * | data, | |||
char * | buf, | |||
size_t | len | |||
) | [static] |
Definition at line 3674 of file app_queue.c.
References 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(), member::interface, call_queue::lock, LOG_ERROR, LOG_WARNING, call_queue::members, call_queue::name, and member::next.
03675 { 03676 struct ast_module_user *u; 03677 struct call_queue *q; 03678 struct member *m; 03679 03680 /* Ensure an otherwise empty list doesn't return garbage */ 03681 buf[0] = '\0'; 03682 03683 if (ast_strlen_zero(data)) { 03684 ast_log(LOG_ERROR, "QUEUE_MEMBER_LIST requires an argument: queuename\n"); 03685 return -1; 03686 } 03687 03688 u = ast_module_user_add(chan); 03689 03690 AST_LIST_LOCK(&queues); 03691 AST_LIST_TRAVERSE(&queues, q, list) { 03692 if (!strcasecmp(q->name, data)) { 03693 ast_mutex_lock(&q->lock); 03694 break; 03695 } 03696 } 03697 AST_LIST_UNLOCK(&queues); 03698 03699 if (q) { 03700 int buflen = 0, count = 0; 03701 03702 for (m = q->members; m; m = m->next) { 03703 /* strcat() is always faster than printf() */ 03704 if (count++) { 03705 strncat(buf + buflen, ",", len - buflen - 1); 03706 buflen++; 03707 } 03708 strncat(buf + buflen, m->interface, len - buflen - 1); 03709 buflen += strlen(m->interface); 03710 /* Safeguard against overflow (negative length) */ 03711 if (buflen >= len - 2) { 03712 ast_log(LOG_WARNING, "Truncating list\n"); 03713 break; 03714 } 03715 } 03716 ast_mutex_unlock(&q->lock); 03717 } else 03718 ast_log(LOG_WARNING, "queue %s was not found\n", data); 03719 03720 /* We should already be terminated, but let's make sure. */ 03721 buf[len - 1] = '\0'; 03722 ast_module_user_remove(u); 03723 03724 return 0; 03725 }
static int queue_function_queuewaitingcount | ( | struct ast_channel * | chan, | |
char * | cmd, | |||
char * | data, | |||
char * | buf, | |||
size_t | len | |||
) | [static] |
Definition at line 3639 of file app_queue.c.
References 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(), ast_module_user::chan, call_queue::count, call_queue::lock, LOG_ERROR, LOG_WARNING, and call_queue::name.
03640 { 03641 int count = 0; 03642 struct call_queue *q; 03643 struct ast_module_user *lu; 03644 03645 buf[0] = '\0'; 03646 03647 if (ast_strlen_zero(data)) { 03648 ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd); 03649 return -1; 03650 } 03651 03652 lu = ast_module_user_add(chan); 03653 03654 AST_LIST_LOCK(&queues); 03655 AST_LIST_TRAVERSE(&queues, q, list) { 03656 if (!strcasecmp(q->name, data)) { 03657 ast_mutex_lock(&q->lock); 03658 break; 03659 } 03660 } 03661 AST_LIST_UNLOCK(&queues); 03662 03663 if (q) { 03664 count = q->count; 03665 ast_mutex_unlock(&q->lock); 03666 } else 03667 ast_log(LOG_WARNING, "queue %s was not found\n", data); 03668 03669 snprintf(buf, len, "%d", count); 03670 ast_module_user_remove(lu); 03671 return 0; 03672 }
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 783 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, 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().
00784 { 00785 if (!strcasecmp(param, "musicclass") || 00786 !strcasecmp(param, "music") || !strcasecmp(param, "musiconhold")) { 00787 ast_copy_string(q->moh, val, sizeof(q->moh)); 00788 } else if (!strcasecmp(param, "announce")) { 00789 ast_copy_string(q->announce, val, sizeof(q->announce)); 00790 } else if (!strcasecmp(param, "context")) { 00791 ast_copy_string(q->context, val, sizeof(q->context)); 00792 } else if (!strcasecmp(param, "timeout")) { 00793 q->timeout = atoi(val); 00794 if (q->timeout < 0) 00795 q->timeout = DEFAULT_TIMEOUT; 00796 } else if (!strcasecmp(param, "ringinuse")) { 00797 q->ringinuse = ast_true(val); 00798 } else if (!strcasecmp(param, "setinterfacevar")) { 00799 q->setinterfacevar = ast_true(val); 00800 } else if (!strcasecmp(param, "monitor-join")) { 00801 q->monjoin = ast_true(val); 00802 } else if (!strcasecmp(param, "monitor-format")) { 00803 ast_copy_string(q->monfmt, val, sizeof(q->monfmt)); 00804 } else if (!strcasecmp(param, "queue-youarenext")) { 00805 ast_copy_string(q->sound_next, val, sizeof(q->sound_next)); 00806 } else if (!strcasecmp(param, "queue-thereare")) { 00807 ast_copy_string(q->sound_thereare, val, sizeof(q->sound_thereare)); 00808 } else if (!strcasecmp(param, "queue-callswaiting")) { 00809 ast_copy_string(q->sound_calls, val, sizeof(q->sound_calls)); 00810 } else if (!strcasecmp(param, "queue-holdtime")) { 00811 ast_copy_string(q->sound_holdtime, val, sizeof(q->sound_holdtime)); 00812 } else if (!strcasecmp(param, "queue-minutes")) { 00813 ast_copy_string(q->sound_minutes, val, sizeof(q->sound_minutes)); 00814 } else if (!strcasecmp(param, "queue-seconds")) { 00815 ast_copy_string(q->sound_seconds, val, sizeof(q->sound_seconds)); 00816 } else if (!strcasecmp(param, "queue-lessthan")) { 00817 ast_copy_string(q->sound_lessthan, val, sizeof(q->sound_lessthan)); 00818 } else if (!strcasecmp(param, "queue-thankyou")) { 00819 ast_copy_string(q->sound_thanks, val, sizeof(q->sound_thanks)); 00820 } else if (!strcasecmp(param, "queue-reporthold")) { 00821 ast_copy_string(q->sound_reporthold, val, sizeof(q->sound_reporthold)); 00822 } else if (!strcasecmp(param, "announce-frequency")) { 00823 q->announcefrequency = atoi(val); 00824 } else if (!strcasecmp(param, "announce-round-seconds")) { 00825 q->roundingseconds = atoi(val); 00826 if (q->roundingseconds>60 || q->roundingseconds<0) { 00827 if (linenum >= 0) { 00828 ast_log(LOG_WARNING, "'%s' isn't a valid value for %s " 00829 "using 0 instead for queue '%s' at line %d of queues.conf\n", 00830 val, param, q->name, linenum); 00831 } else { 00832 ast_log(LOG_WARNING, "'%s' isn't a valid value for %s " 00833 "using 0 instead for queue '%s'\n", val, param, q->name); 00834 } 00835 q->roundingseconds=0; 00836 } 00837 } else if (!strcasecmp(param, "announce-holdtime")) { 00838 if (!strcasecmp(val, "once")) 00839 q->announceholdtime = ANNOUNCEHOLDTIME_ONCE; 00840 else if (ast_true(val)) 00841 q->announceholdtime = ANNOUNCEHOLDTIME_ALWAYS; 00842 else 00843 q->announceholdtime = 0; 00844 } else if (!strcasecmp(param, "periodic-announce")) { 00845 if (strchr(val, '|')) { 00846 char *s, *buf = ast_strdupa(val); 00847 unsigned int i = 0; 00848 00849 while ((s = strsep(&buf, "|"))) { 00850 ast_copy_string(q->sound_periodicannounce[i], s, sizeof(q->sound_periodicannounce[i])); 00851 i++; 00852 if (i == MAX_PERIODIC_ANNOUNCEMENTS) 00853 break; 00854 } 00855 } else { 00856 ast_copy_string(q->sound_periodicannounce[0], val, sizeof(q->sound_periodicannounce[0])); 00857 } 00858 } else if (!strcasecmp(param, "periodic-announce-frequency")) { 00859 q->periodicannouncefrequency = atoi(val); 00860 } else if (!strcasecmp(param, "retry")) { 00861 q->retry = atoi(val); 00862 if (q->retry <= 0) 00863 q->retry = DEFAULT_RETRY; 00864 } else if (!strcasecmp(param, "wrapuptime")) { 00865 q->wrapuptime = atoi(val); 00866 } else if (!strcasecmp(param, "autofill")) { 00867 q->autofill = ast_true(val); 00868 } else if (!strcasecmp(param, "monitor-type")) { 00869 if (!strcasecmp(val, "mixmonitor")) 00870 q->montype = 1; 00871 } else if (!strcasecmp(param, "autopause")) { 00872 q->autopause = ast_true(val); 00873 } else if (!strcasecmp(param, "maxlen")) { 00874 q->maxlen = atoi(val); 00875 if (q->maxlen < 0) 00876 q->maxlen = 0; 00877 } else if (!strcasecmp(param, "servicelevel")) { 00878 q->servicelevel= atoi(val); 00879 } else if (!strcasecmp(param, "strategy")) { 00880 q->strategy = strat2int(val); 00881 if (q->strategy < 0) { 00882 ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n", 00883 val, q->name); 00884 q->strategy = QUEUE_STRATEGY_RINGALL; 00885 } 00886 } else if (!strcasecmp(param, "joinempty")) { 00887 if (!strcasecmp(val, "strict")) 00888 q->joinempty = QUEUE_EMPTY_STRICT; 00889 else if (ast_true(val)) 00890 q->joinempty = QUEUE_EMPTY_NORMAL; 00891 else 00892 q->joinempty = 0; 00893 } else if (!strcasecmp(param, "leavewhenempty")) { 00894 if (!strcasecmp(val, "strict")) 00895 q->leavewhenempty = QUEUE_EMPTY_STRICT; 00896 else if (ast_true(val)) 00897 q->leavewhenempty = QUEUE_EMPTY_NORMAL; 00898 else 00899 q->leavewhenempty = 0; 00900 } else if (!strcasecmp(param, "eventmemberstatus")) { 00901 q->maskmemberstatus = !ast_true(val); 00902 } else if (!strcasecmp(param, "eventwhencalled")) { 00903 if (!strcasecmp(val, "vars")) { 00904 q->eventwhencalled = QUEUE_EVENT_VARIABLES; 00905 } else { 00906 q->eventwhencalled = ast_true(val); 00907 } 00908 } else if (!strcasecmp(param, "reportholdtime")) { 00909 q->reportholdtime = ast_true(val); 00910 } else if (!strcasecmp(param, "memberdelay")) { 00911 q->memberdelay = atoi(val); 00912 } else if (!strcasecmp(param, "weight")) { 00913 q->weight = atoi(val); 00914 if (q->weight) 00915 use_weight++; 00916 /* With Realtime queues, if the last queue using weights is deleted in realtime, 00917 we will not see any effect on use_weight until next reload. */ 00918 } else if (!strcasecmp(param, "timeoutrestart")) { 00919 q->timeoutrestart = ast_true(val); 00920 } else if (failunknown) { 00921 if (linenum >= 0) { 00922 ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s at line %d of queues.conf\n", 00923 q->name, param, linenum); 00924 } else { 00925 ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s\n", q->name, param); 00926 } 00927 } 00928 }
static int queue_show | ( | int | fd, | |
int | argc, | |||
char ** | argv | |||
) | [static] |
Definition at line 4070 of file app_queue.c.
References __queues_show().
Referenced by __queues_show().
04071 { 04072 return __queues_show(NULL, 0, fd, argc, argv); 04073 }
static void recalc_holdtime | ( | struct queue_ent * | qe, | |
int | newholdtime | |||
) | [static] |
Definition at line 1443 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().
01444 { 01445 int oldvalue; 01446 01447 /* Calculate holdtime using a recursive boxcar filter */ 01448 /* Thanks to SRT for this contribution */ 01449 /* 2^2 (4) is the filter coefficient; a higher exponent would give old entries more weight */ 01450 01451 ast_mutex_lock(&qe->parent->lock); 01452 oldvalue = qe->parent->holdtime; 01453 qe->parent->holdtime = (((oldvalue << 2) - oldvalue) + newholdtime) >> 2; 01454 ast_mutex_unlock(&qe->parent->lock); 01455 }
static void record_abandoned | ( | struct queue_ent * | qe | ) | [static] |
Definition at line 1873 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().
01874 { 01875 ast_mutex_lock(&qe->parent->lock); 01876 manager_event(EVENT_FLAG_AGENT, "QueueCallerAbandon", 01877 "Queue: %s\r\n" 01878 "Uniqueid: %s\r\n" 01879 "Position: %d\r\n" 01880 "OriginalPosition: %d\r\n" 01881 "HoldTime: %d\r\n", 01882 qe->parent->name, qe->chan->uniqueid, qe->pos, qe->opos, (int)(time(NULL) - qe->start)); 01883 01884 qe->parent->callsabandoned++; 01885 ast_mutex_unlock(&qe->parent->lock); 01886 }
static int reload | ( | void | ) | [static] |
Definition at line 4564 of file app_queue.c.
References reload_queues().
04565 { 04566 reload_queues(); 04567 return 0; 04568 }
static void reload_queue_members | ( | void | ) | [static] |
Definition at line 2977 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, member::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().
02978 { 02979 char *cur_ptr; 02980 char *queue_name; 02981 char *member; 02982 char *interface; 02983 char *membername; 02984 char *penalty_tok; 02985 int penalty = 0; 02986 char *paused_tok; 02987 int paused = 0; 02988 struct ast_db_entry *db_tree; 02989 struct ast_db_entry *entry; 02990 struct call_queue *cur_queue; 02991 char queue_data[PM_MAX_LEN]; 02992 02993 AST_LIST_LOCK(&queues); 02994 02995 /* Each key in 'pm_family' is the name of a queue */ 02996 db_tree = ast_db_gettree(pm_family, NULL); 02997 for (entry = db_tree; entry; entry = entry->next) { 02998 02999 queue_name = entry->key + strlen(pm_family) + 2; 03000 03001 AST_LIST_TRAVERSE(&queues, cur_queue, list) { 03002 ast_mutex_lock(&cur_queue->lock); 03003 if (!strcmp(queue_name, cur_queue->name)) 03004 break; 03005 ast_mutex_unlock(&cur_queue->lock); 03006 } 03007 03008 if (!cur_queue) 03009 cur_queue = load_realtime_queue(queue_name); 03010 03011 if (!cur_queue) { 03012 /* If the queue no longer exists, remove it from the 03013 * database */ 03014 ast_log(LOG_WARNING, "Error loading persistent queue: '%s': it does not exist\n", queue_name); 03015 ast_db_del(pm_family, queue_name); 03016 continue; 03017 } else 03018 ast_mutex_unlock(&cur_queue->lock); 03019 03020 if (ast_db_get(pm_family, queue_name, queue_data, PM_MAX_LEN)) 03021 continue; 03022 03023 cur_ptr = queue_data; 03024 while ((member = strsep(&cur_ptr, "|"))) { 03025 if (ast_strlen_zero(member)) 03026 continue; 03027 03028 interface = strsep(&member, ";"); 03029 penalty_tok = strsep(&member, ";"); 03030 paused_tok = strsep(&member, ";"); 03031 membername = strsep(&member, ";"); 03032 03033 if (!penalty_tok) { 03034 ast_log(LOG_WARNING, "Error parsing persistent member string for '%s' (penalty)\n", queue_name); 03035 break; 03036 } 03037 penalty = strtol(penalty_tok, NULL, 10); 03038 if (errno == ERANGE) { 03039 ast_log(LOG_WARNING, "Error converting penalty: %s: Out of range.\n", penalty_tok); 03040 break; 03041 } 03042 03043 if (!paused_tok) { 03044 ast_log(LOG_WARNING, "Error parsing persistent member string for '%s' (paused)\n", queue_name); 03045 break; 03046 } 03047 paused = strtol(paused_tok, NULL, 10); 03048 if ((errno == ERANGE) || paused < 0 || paused > 1) { 03049 ast_log(LOG_WARNING, "Error converting paused: %s: Expected 0 or 1.\n", paused_tok); 03050 break; 03051 } 03052 if (ast_strlen_zero(membername)) 03053 membername = interface; 03054 03055 if (option_debug) 03056 ast_log(LOG_DEBUG, "Reload Members: Queue: %s Member: %s Name: %s Penalty: %d Paused: %d\n", queue_name, interface, membername, penalty, paused); 03057 03058 if (add_to_queue(queue_name, interface, membername, penalty, paused, 0) == RES_OUTOFMEMORY) { 03059 ast_log(LOG_ERROR, "Out of Memory when reloading persistent queue member\n"); 03060 break; 03061 } 03062 } 03063 } 03064 03065 AST_LIST_UNLOCK(&queues); 03066 if (db_tree) { 03067 ast_log(LOG_NOTICE, "Queue members successfully reloaded from database.\n"); 03068 ast_db_freetree(db_tree); 03069 } 03070 }
static int reload_queues | ( | void | ) | [static] |
Definition at line 3764 of file app_queue.c.
References add_to_interfaces(), alloc_queue(), AST_APP_ARG, ast_category_browse(), ast_config_load(), AST_DECLARE_APP_ARGS, AST_LIST_INSERT_HEAD, AST_LIST_LOCK, AST_LIST_TRAVERSE, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), AST_NONSTANDARD_APP_ARGS, ast_strlen_zero(), ast_true(), ast_variable_browse(), ast_variable_retrieve(), clear_queue(), create_queue_member(), call_queue::dead, member::delme, member::dynamic, free, init_queue(), member::interface, call_queue::lock, LOG_NOTICE, call_queue::membercount, member::membername, call_queue::members, call_queue::name, member::next, parse(), member::paused, member::penalty, queue_set_param(), QUEUE_STRATEGY_ROUNDROBIN, remove_from_interfaces(), rr_dep_warning(), call_queue::strategy, and var.
Referenced by load_module(), and reload().
03765 { 03766 struct call_queue *q; 03767 struct ast_config *cfg; 03768 char *cat, *tmp; 03769 struct ast_variable *var; 03770 struct member *prev, *cur, *newm, *next; 03771 int new; 03772 const char *general_val = NULL; 03773 char parse[80]; 03774 char *interface; 03775 char *membername; 03776 int penalty; 03777 AST_DECLARE_APP_ARGS(args, 03778 AST_APP_ARG(interface); 03779 AST_APP_ARG(penalty); 03780 AST_APP_ARG(membername); 03781 ); 03782 03783 if (!(cfg = ast_config_load("queues.conf"))) { 03784 ast_log(LOG_NOTICE, "No call queueing config file (queues.conf), so no call queues\n"); 03785 return 0; 03786 } 03787 AST_LIST_LOCK(&queues); 03788 use_weight=0; 03789 /* Mark all queues as dead for the moment */ 03790 AST_LIST_TRAVERSE(&queues, q, list) 03791 q->dead = 1; 03792 03793 /* Chug through config file */ 03794 cat = NULL; 03795 while ((cat = ast_category_browse(cfg, cat)) ) { 03796 if (!strcasecmp(cat, "general")) { 03797 /* Initialize global settings */ 03798 queue_persistent_members = 0; 03799 if ((general_val = ast_variable_retrieve(cfg, "general", "persistentmembers"))) 03800 queue_persistent_members = ast_true(general_val); 03801 autofill_default = 0; 03802 if ((general_val = ast_variable_retrieve(cfg, "general", "autofill"))) 03803 autofill_default = ast_true(general_val); 03804 montype_default = 0; 03805 if ((general_val = ast_variable_retrieve(cfg, "general", "monitor-type"))) 03806 if (!strcasecmp(general_val, "mixmonitor")) 03807 montype_default = 1; 03808 } else { /* Define queue */ 03809 /* Look for an existing one */ 03810 AST_LIST_TRAVERSE(&queues, q, list) { 03811 if (!strcmp(q->name, cat)) 03812 break; 03813 } 03814 if (!q) { 03815 /* Make one then */ 03816 if (!(q = alloc_queue(cat))) { 03817 /* TODO: Handle memory allocation failure */ 03818 } 03819 new = 1; 03820 } else 03821 new = 0; 03822 if (q) { 03823 if (!new) 03824 ast_mutex_lock(&q->lock); 03825 /* Re-initialize the queue, and clear statistics */ 03826 init_queue(q); 03827 clear_queue(q); 03828 for (cur = q->members; cur; cur = cur->next) { 03829 if (!cur->dynamic) { 03830 cur->delme = 1; 03831 } 03832 } 03833 for (var = ast_variable_browse(cfg, cat); var; var = var->next) { 03834 if (!strcasecmp(var->name, "member")) { 03835 /* Add a new member */ 03836 ast_copy_string(parse, var->value, sizeof(parse)); 03837 03838 AST_NONSTANDARD_APP_ARGS(args, parse, ','); 03839 03840 interface = args.interface; 03841 if(!ast_strlen_zero(args.penalty)) { 03842 tmp = args.penalty; 03843 while (*tmp && *tmp < 33) tmp++; 03844 penalty = atoi(tmp); 03845 if (penalty < 0) { 03846 penalty = 0; 03847 } 03848 } else 03849 penalty = 0; 03850 03851 if (!ast_strlen_zero(args.membername)) { 03852 membername = args.membername; 03853 while (*membername && *membername < 33) membername++; 03854 } else 03855 membername = interface; 03856 03857 /* Find the old position in the list */ 03858 for (prev = NULL, cur = q->members; cur; prev = cur, cur = cur->next) { 03859 if (!strcmp(cur->interface, interface)) { 03860 break; 03861 } 03862 } 03863 03864 newm = create_queue_member(interface, membername, penalty, cur ? cur->paused : 0); 03865 03866 if (cur) { 03867 /* Delete it now */ 03868 newm->next = cur->next; 03869 if (prev) { 03870 prev->next = newm; 03871 } else { 03872 q->members = newm; 03873 } 03874 free(cur); 03875 } else { 03876 /* Add them to the master int list if necessary */ 03877 add_to_interfaces(interface); 03878 newm->next = q->members; 03879 q->members = newm; 03880 } 03881 q->membercount++; 03882 } else { 03883 queue_set_param(q, var->name, var->value, var->lineno, 1); 03884 } 03885 } 03886 03887 /* Free remaining members marked as delme */ 03888 for (prev = NULL, cur = q->members; 03889 cur; 03890 cur = next) { 03891 next = cur->next; 03892 03893 if (!cur->delme) { 03894 prev = cur; 03895 continue; 03896 } 03897 03898 if (prev) 03899 prev->next = next; 03900 else 03901 q->members = next; 03902 03903 remove_from_interfaces(cur->interface); 03904 q->membercount--; 03905 free(cur); 03906 } 03907 03908 if (q->strategy == QUEUE_STRATEGY_ROUNDROBIN) 03909 rr_dep_warning(); 03910 03911 if (new) { 03912 AST_LIST_INSERT_HEAD(&queues, q, list); 03913 } else 03914 ast_mutex_unlock(&q->lock); 03915 } 03916 } 03917 } 03918 ast_config_destroy(cfg); 03919 AST_LIST_TRAVERSE_SAFE_BEGIN(&queues, q, list) { 03920 if (q->dead) { 03921 AST_LIST_REMOVE_CURRENT(&queues, list); 03922 if (!q->count) 03923 destroy_queue(q); 03924 else 03925 ast_log(LOG_DEBUG, "XXX Leaking a little memory :( XXX\n"); 03926 } else { 03927 ast_mutex_lock(&q->lock); 03928 for (cur = q->members; cur; cur = cur->next) 03929 cur->status = ast_device_state(cur->interface); 03930 ast_mutex_unlock(&q->lock); 03931 } 03932 } 03933 AST_LIST_TRAVERSE_SAFE_END; 03934 AST_LIST_UNLOCK(&queues); 03935 return 1; 03936 }
static int remove_from_interfaces | ( | const char * | interface | ) | [static] |
Definition at line 744 of file app_queue.c.
References AST_LIST_LOCK, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, AST_LIST_UNLOCK, ast_log(), free, member_interface::interface, interface_exists_global(), LOG_DEBUG, and option_debug.
Referenced by free_members(), reload_queues(), remove_from_queue(), and update_realtime_members().
00745 { 00746 struct member_interface *curint; 00747 00748 AST_LIST_LOCK(&interfaces); 00749 AST_LIST_TRAVERSE_SAFE_BEGIN(&interfaces, curint, list) { 00750 if (!strcasecmp(curint->interface, interface)) { 00751 if (!interface_exists_global(interface)) { 00752 if (option_debug) 00753 ast_log(LOG_DEBUG, "Removing %s from the list of interfaces that make up all of our queue members.\n", interface); 00754 AST_LIST_REMOVE_CURRENT(&interfaces, list); 00755 free(curint); 00756 } 00757 break; 00758 } 00759 } 00760 AST_LIST_TRAVERSE_SAFE_END; 00761 AST_LIST_UNLOCK(&interfaces); 00762 00763 return 0; 00764 }
static int remove_from_queue | ( | const char * | queuename, | |
const char * | interface | |||
) | [static] |
Definition at line 2827 of file app_queue.c.
References AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_mutex_lock(), ast_mutex_unlock(), dump_queue_members(), EVENT_FLAG_AGENT, free, member::interface, interface_exists(), call_queue::lock, manager_event(), call_queue::membercount, member::membername, call_queue::members, call_queue::name, member::next, remove_from_interfaces(), RES_EXISTS, RES_NOSUCHQUEUE, and RES_OKAY.
Referenced by attempt_thread(), handle_queue_remove_member(), manager_remove_queue_member(), rqm_exec(), and scan_service().
02828 { 02829 struct call_queue *q; 02830 struct member *last_member, *look; 02831 int res = RES_NOSUCHQUEUE; 02832 02833 AST_LIST_LOCK(&queues); 02834 AST_LIST_TRAVERSE(&queues, q, list) { 02835 ast_mutex_lock(&q->lock); 02836 if (strcmp(q->name, queuename)) { 02837 ast_mutex_unlock(&q->lock); 02838 continue; 02839 } 02840 02841 if ((last_member = interface_exists(q, interface))) { 02842 if ((look = q->members) == last_member) { 02843 q->members = last_member->next; 02844 q->membercount--; 02845 } else { 02846 while (look != NULL) { 02847 if (look->next == last_member) { 02848 look->next = last_member->next; 02849 q->membercount--; 02850 break; 02851 } else { 02852 look = look->next; 02853 } 02854 } 02855 } 02856 manager_event(EVENT_FLAG_AGENT, "QueueMemberRemoved", 02857 "Queue: %s\r\n" 02858 "Location: %s\r\n" 02859 "MemberName: %s\r\n", 02860 q->name, last_member->interface, last_member->membername); 02861 free(last_member); 02862 02863 if (queue_persistent_members) 02864 dump_queue_members(q); 02865 02866 res = RES_OKAY; 02867 } else { 02868 res = RES_EXISTS; 02869 } 02870 ast_mutex_unlock(&q->lock); 02871 break; 02872 } 02873 02874 if (res == RES_OKAY) 02875 remove_from_interfaces(interface); 02876 02877 AST_LIST_UNLOCK(&queues); 02878 02879 return res; 02880 }
static int ring_entry | ( | struct queue_ent * | qe, | |
struct callattempt * | tmp, | |||
int * | busies | |||
) | [static] |
Definition at line 1637 of file app_queue.c.
References ast_channel::adsicpe, ast_channel::appl, ast_call(), ast_cdr_busy(), ast_channel_inherit_variables(), AST_DEVICE_NOT_INUSE, AST_DEVICE_UNKNOWN, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_request(), ast_strdup, 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, do_hang(), EVENT_FLAG_AGENT, call_queue::eventwhencalled, ast_channel::exten, free, callattempt::interface, callattempt::lastcall, call_queue::lock, LOG_DEBUG, manager_event(), callattempt::member, call_queue::name, ast_channel::nativeformats, callattempt::oldstatus, option_debug, option_verbose, queue_ent::parent, member::paused, ast_channel::priority, QUEUE_EVENT_VARIABLES, call_queue::ringinuse, call_queue::rrpos, member::status, callattempt::stillgoing, update_dial_status(), vars2manager(), VERBOSE_PREFIX_3, ast_channel::whentohangup, and call_queue::wrapuptime.
Referenced by ring_one().
01638 { 01639 int res; 01640 int status; 01641 char tech[256]; 01642 char *location; 01643 01644 /* on entry here, we know that tmp->chan == NULL */ 01645 if (qe->parent->wrapuptime && (time(NULL) - tmp->lastcall < qe->parent->wrapuptime)) { 01646 if (option_debug) 01647 ast_log(LOG_DEBUG, "Wrapuptime not yet expired for %s\n", tmp->interface); 01648 if (qe->chan->cdr) 01649 ast_cdr_busy(qe->chan->cdr); 01650 tmp->stillgoing = 0; 01651 (*busies)++; 01652 return 0; 01653 } 01654 01655 if (!qe->parent->ringinuse && (tmp->member->status != AST_DEVICE_NOT_INUSE) && (tmp->member->status != AST_DEVICE_UNKNOWN)) { 01656 if (option_debug) 01657 ast_log(LOG_DEBUG, "%s in use, can't receive call\n", tmp->interface); 01658 if (qe->chan->cdr) 01659 ast_cdr_busy(qe->chan->cdr); 01660 tmp->stillgoing = 0; 01661 return 0; 01662 } 01663 01664 if (tmp->member->paused) { 01665 if (option_debug) 01666 ast_log(LOG_DEBUG, "%s paused, can't receive call\n", tmp->interface); 01667 if (qe->chan->cdr) 01668 ast_cdr_busy(qe->chan->cdr); 01669 tmp->stillgoing = 0; 01670 return 0; 01671 } 01672 if (use_weight && compare_weight(qe->parent,tmp->member)) { 01673 ast_log(LOG_DEBUG, "Priority queue delaying call to %s:%s\n", qe->parent->name, tmp->interface); 01674 if (qe->chan->cdr) 01675 ast_cdr_busy(qe->chan->cdr); 01676 tmp->stillgoing = 0; 01677 (*busies)++; 01678 return 0; 01679 } 01680 01681 ast_copy_string(tech, tmp->interface, sizeof(tech)); 01682 if ((location = strchr(tech, '/'))) 01683 *location++ = '\0'; 01684 else 01685 location = ""; 01686 01687 /* Request the peer */ 01688 tmp->chan = ast_request(tech, qe->chan->nativeformats, location, &status); 01689 if (!tmp->chan) { /* If we can't, just go on to the next call */ 01690 if (qe->chan->cdr) 01691 ast_cdr_busy(qe->chan->cdr); 01692 tmp->stillgoing = 0; 01693 update_dial_status(qe->parent, tmp->member, status); 01694 01695 ast_mutex_lock(&qe->parent->lock); 01696 qe->parent->rrpos++; 01697 ast_mutex_unlock(&qe->parent->lock); 01698 01699 (*busies)++; 01700 return 0; 01701 } else if (status != tmp->oldstatus) 01702 update_dial_status(qe->parent, tmp->member, status); 01703 01704 tmp->chan->appl = "AppQueue"; 01705 tmp->chan->data = "(Outgoing Line)"; 01706 tmp->chan->whentohangup = 0; 01707 if (tmp->chan->cid.cid_num) 01708 free(tmp->chan->cid.cid_num); 01709 tmp->chan->cid.cid_num = ast_strdup(qe->chan->cid.cid_num); 01710 if (tmp->chan->cid.cid_name) 01711 free(tmp->chan->cid.cid_name); 01712 tmp->chan->cid.cid_name = ast_strdup(qe->chan->cid.cid_name); 01713 if (tmp->chan->cid.cid_ani) 01714 free(tmp->chan->cid.cid_ani); 01715 tmp->chan->cid.cid_ani = ast_strdup(qe->chan->cid.cid_ani); 01716 01717 /* Inherit specially named variables from parent channel */ 01718 ast_channel_inherit_variables(qe->chan, tmp->chan); 01719 01720 /* Presense of ADSI CPE on outgoing channel follows ours */ 01721 tmp->chan->adsicpe = qe->chan->adsicpe; 01722 01723 /* Place the call, but don't wait on the answer */ 01724 if ((res = ast_call(tmp->chan, location, 0))) { 01725 /* Again, keep going even if there's an error */ 01726 if (option_debug) 01727 ast_log(LOG_DEBUG, "ast call on peer returned %d\n", res); 01728 if (option_verbose > 2) 01729 ast_verbose(VERBOSE_PREFIX_3 "Couldn't call %s\n", tmp->interface); 01730 do_hang(tmp); 01731 (*busies)++; 01732 return 0; 01733 } else if (qe->parent->eventwhencalled) { 01734 char vars[2048]; 01735 01736 manager_event(EVENT_FLAG_AGENT, "AgentCalled", 01737 "AgentCalled: %s\r\n" 01738 "ChannelCalling: %s\r\n" 01739 "CallerID: %s\r\n" 01740 "CallerIDName: %s\r\n" 01741 "Context: %s\r\n" 01742 "Extension: %s\r\n" 01743 "Priority: %d\r\n" 01744 "%s", 01745 tmp->interface, qe->chan->name, 01746 tmp->chan->cid.cid_num ? tmp->chan->cid.cid_num : "unknown", 01747 tmp->chan->cid.cid_name ? tmp->chan->cid.cid_name : "unknown", 01748 qe->chan->context, qe->chan->exten, qe->chan->priority, 01749 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : ""); 01750 if (option_verbose > 2) 01751 ast_verbose(VERBOSE_PREFIX_3 "Called %s\n", tmp->interface); 01752 } 01753 01754 return 1; 01755 }
static int ring_one | ( | struct queue_ent * | qe, | |
struct callattempt * | outgoing, | |||
int * | busies | |||
) | [static] |
Definition at line 1773 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().
01774 { 01775 int ret = 0; 01776 01777 while (ret == 0) { 01778 struct callattempt *best = find_best(outgoing); 01779 if (!best) { 01780 if (option_debug) 01781 ast_log(LOG_DEBUG, "Nobody left to try ringing in queue\n"); 01782 break; 01783 } 01784 if (qe->parent->strategy == QUEUE_STRATEGY_RINGALL) { 01785 struct callattempt *cur; 01786 /* Ring everyone who shares this best metric (for ringall) */ 01787 for (cur = outgoing; cur; cur = cur->q_next) { 01788 if (cur->stillgoing && !cur->chan && cur->metric <= best->metric) { 01789 if (option_debug) 01790 ast_log(LOG_DEBUG, "(Parallel) Trying '%s' with metric %d\n", cur->interface, cur->metric); 01791 ring_entry(qe, cur, busies); 01792 } 01793 } 01794 } else { 01795 /* Ring just the best channel */ 01796 if (option_debug) 01797 ast_log(LOG_DEBUG, "Trying '%s' with metric %d\n", best->interface, best->metric); 01798 ring_entry(qe, best, busies); 01799 } 01800 if (best->chan) /* break out with result = 1 */ 01801 ret = 1; 01802 } 01803 01804 return ret; 01805 }
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 1889 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.
01890 { 01891 if (option_verbose > 2) 01892 ast_verbose( VERBOSE_PREFIX_3 "Nobody picked up in %d ms\n", rnatime); 01893 ast_queue_log(qe->parent->name, qe->chan->uniqueid, membername, "RINGNOANSWER", "%d", rnatime); 01894 if (qe->parent->autopause) { 01895 if (!set_member_paused(qe->parent->name, interface, 1)) { 01896 if (option_verbose > 2) 01897 ast_verbose( VERBOSE_PREFIX_3 "Auto-Pausing Queue Member %s in queue %s since they failed to answer.\n", interface, qe->parent->name); 01898 } else { 01899 if (option_verbose > 2) 01900 ast_verbose( VERBOSE_PREFIX_3 "Failed to pause Queue Member %s in queue %s!\n", interface, qe->parent->name); 01901 } 01902 } 01903 return; 01904 }
static int rqm_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Definition at line 3178 of file app_queue.c.
References AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_goto_if_exists(), ast_log(), ast_module_user_add, ast_module_user_remove, ast_opt_priority_jumping, ast_queue_log(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), ast_module_user::chan, ast_channel::context, LOG_DEBUG, LOG_NOTICE, LOG_WARNING, parse(), pbx_builtin_setvar_helper(), remove_from_queue(), RES_EXISTS, RES_NOSUCHQUEUE, and RES_OKAY.
Referenced by load_module().
03179 { 03180 int res=-1; 03181 struct ast_module_user *lu; 03182 char *parse, *temppos = NULL; 03183 int priority_jump = 0; 03184 AST_DECLARE_APP_ARGS(args, 03185 AST_APP_ARG(queuename); 03186 AST_APP_ARG(interface); 03187 AST_APP_ARG(options); 03188 ); 03189 03190 03191 if (ast_strlen_zero(data)) { 03192 ast_log(LOG_WARNING, "RemoveQueueMember requires an argument (queuename[|interface[|options]])\n"); 03193 return -1; 03194 } 03195 03196 parse = ast_strdupa(data); 03197 03198 AST_STANDARD_APP_ARGS(args, parse); 03199 03200 lu = ast_module_user_add(chan); 03201 03202 if (ast_strlen_zero(args.interface)) { 03203 args.interface = ast_strdupa(chan->name); 03204 temppos = strrchr(args.interface, '-'); 03205 if (temppos) 03206 *temppos = '\0'; 03207 } 03208 03209 if (args.options) { 03210 if (strchr(args.options, 'j')) 03211 priority_jump = 1; 03212 } 03213 03214 switch (remove_from_queue(args.queuename, args.interface)) { 03215 case RES_OKAY: 03216 ast_queue_log(args.queuename, chan->uniqueid, args.interface, "REMOVEMEMBER", "%s", ""); 03217 ast_log(LOG_NOTICE, "Removed interface '%s' from queue '%s'\n", args.interface, args.queuename); 03218 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "REMOVED"); 03219 res = 0; 03220 break; 03221 case RES_EXISTS: 03222 ast_log(LOG_DEBUG, "Unable to remove interface '%s' from queue '%s': Not there\n", args.interface, args.queuename); 03223 if (priority_jump || ast_opt_priority_jumping) 03224 ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101); 03225 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOTINQUEUE"); 03226 res = 0; 03227 break; 03228 case RES_NOSUCHQUEUE: 03229 ast_log(LOG_WARNING, "Unable to remove interface from queue '%s': No such queue\n", args.queuename); 03230 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOSUCHQUEUE"); 03231 res = 0; 03232 break; 03233 } 03234 03235 ast_module_user_remove(lu); 03236 03237 return res; 03238 }
static void rr_dep_warning | ( | void | ) | [static] |
Definition at line 408 of file app_queue.c.
References ast_log(), and LOG_NOTICE.
Referenced by reload_queues().
00409 { 00410 static unsigned int warned = 0; 00411 00412 if (!warned) { 00413 ast_log(LOG_NOTICE, "The 'roundrobin' queue strategy is deprecated. Please use the 'rrmemory' strategy instead.\n"); 00414 warned = 1; 00415 } 00416 }
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 930 of file app_queue.c.
References add_to_interfaces(), create_queue_member(), member::dead, member::interface, call_queue::membercount, call_queue::members, member::next, member::paused, and member::penalty.
Referenced by update_realtime_members().
00931 { 00932 struct member *m, *prev_m; 00933 int penalty = 0; 00934 int paused = 0; 00935 00936 if (penalty_str) { 00937 penalty = atoi(penalty_str); 00938 if (penalty < 0) 00939 penalty = 0; 00940 } 00941 00942 if (paused_str) { 00943 paused = atoi(paused_str); 00944 if (paused < 0) 00945 paused = 0; 00946 } 00947 00948 /* Find the member, or the place to put a new one. */ 00949 for (m = q->members, prev_m = NULL; 00950 m && strcmp(m->interface, interface); 00951 prev_m = m, m = m->next); 00952 00953 /* Create a new one if not found, else update penalty */ 00954 if (!m) { 00955 if ((m = create_queue_member(interface, membername, penalty, paused))) { 00956 m->dead = 0; 00957 add_to_interfaces(interface); 00958 if (prev_m) { 00959 prev_m->next = m; 00960 } else { 00961 q->members = m; 00962 } 00963 q->membercount++; 00964 } 00965 } else { 00966 m->dead = 0; /* Do not delete this one. */ 00967 if (paused_str) 00968 m->paused = paused; 00969 m->penalty = penalty; 00970 } 00971 }
static int say_periodic_announcement | ( | struct queue_ent * | qe | ) | [static] |
Definition at line 1831 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().
01832 { 01833 int res = 0; 01834 time_t now; 01835 01836 /* Get the current time */ 01837 time(&now); 01838 01839 /* Check to see if it is time to announce */ 01840 if ((now - qe->last_periodic_announce_time) < qe->parent->periodicannouncefrequency) 01841 return 0; 01842 01843 /* Stop the music on hold so we can play our own file */ 01844 ast_moh_stop(qe->chan); 01845 01846 if (option_verbose > 2) 01847 ast_verbose(VERBOSE_PREFIX_3 "Playing periodic announcement\n"); 01848 01849 /* Check to make sure we have a sound file. If not, reset to the first sound file */ 01850 if (qe->last_periodic_announce_sound >= MAX_PERIODIC_ANNOUNCEMENTS || !strlen(qe->parent->sound_periodicannounce[qe->last_periodic_announce_sound])) { 01851 qe->last_periodic_announce_sound = 0; 01852 } 01853 01854 /* play the announcement */ 01855 res = play_file(qe->chan, qe->parent->sound_periodicannounce[qe->last_periodic_announce_sound]); 01856 01857 if (res > 0 && !valid_exit(qe, res)) 01858 res = 0; 01859 01860 /* Resume Music on Hold if the caller is going to stay in the queue */ 01861 if (!res) 01862 ast_moh_start(qe->chan, qe->moh, NULL); 01863 01864 /* update last_periodic_announce_time */ 01865 qe->last_periodic_announce_time = now; 01866 01867 /* Update the current periodic announcement to the next announcement */ 01868 qe->last_periodic_announce_sound++; 01869 01870 return res; 01871 }
static int say_position | ( | struct queue_ent * | qe | ) | [static] |
Definition at line 1336 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().
01337 { 01338 int res = 0, avgholdmins, avgholdsecs; 01339 time_t now; 01340 01341 /* Check to see if this is ludicrous -- if we just announced position, don't do it again*/ 01342 time(&now); 01343 if ((now - qe->last_pos) < 15) 01344 return 0; 01345 01346 /* If either our position has changed, or we are over the freq timer, say position */ 01347 if ((qe->last_pos_said == qe->pos) && ((now - qe->last_pos) < qe->parent->announcefrequency)) 01348 return 0; 01349 01350 ast_moh_stop(qe->chan); 01351 /* Say we're next, if we are */ 01352 if (qe->pos == 1) { 01353 res = play_file(qe->chan, qe->parent->sound_next); 01354 if (res) 01355 goto playout; 01356 else 01357 goto posout; 01358 } else { 01359 res = play_file(qe->chan, qe->parent->sound_thereare); 01360 if (res) 01361 goto playout; 01362 res = ast_say_number(qe->chan, qe->pos, AST_DIGIT_ANY, qe->chan->language, (char *) NULL); /* Needs gender */ 01363 if (res) 01364 goto playout; 01365 res = play_file(qe->chan, qe->parent->sound_calls); 01366 if (res) 01367 goto playout; 01368 } 01369 /* Round hold time to nearest minute */ 01370 avgholdmins = abs(((qe->parent->holdtime + 30) - (now - qe->start)) / 60); 01371 01372 /* If they have specified a rounding then round the seconds as well */ 01373 if (qe->parent->roundingseconds) { 01374 avgholdsecs = (abs(((qe->parent->holdtime + 30) - (now - qe->start))) - 60 * avgholdmins) / qe->parent->roundingseconds; 01375 avgholdsecs *= qe->parent->roundingseconds; 01376 } else { 01377 avgholdsecs = 0; 01378 } 01379 01380 if (option_verbose > 2) 01381 ast_verbose(VERBOSE_PREFIX_3 "Hold time for %s is %d minutes %d seconds\n", qe->parent->name, avgholdmins, avgholdsecs); 01382 01383 /* If the hold time is >1 min, if it's enabled, and if it's not 01384 supposed to be only once and we have already said it, say it */ 01385 if ((avgholdmins+avgholdsecs) > 0 && (qe->parent->announceholdtime) && 01386 (!(qe->parent->announceholdtime == ANNOUNCEHOLDTIME_ONCE) && qe->last_pos)) { 01387 res = play_file(qe->chan, qe->parent->sound_holdtime); 01388 if (res) 01389 goto playout; 01390 01391 if (avgholdmins > 0) { 01392 if (avgholdmins < 2) { 01393 res = play_file(qe->chan, qe->parent->sound_lessthan); 01394 if (res) 01395 goto playout; 01396 01397 res = ast_say_number(qe->chan, 2, AST_DIGIT_ANY, qe->chan->language, NULL); 01398 if (res) 01399 goto playout; 01400 } else { 01401 res = ast_say_number(qe->chan, avgholdmins, AST_DIGIT_ANY, qe->chan->language, NULL); 01402 if (res) 01403 goto playout; 01404 } 01405 01406 res = play_file(qe->chan, qe->parent->sound_minutes); 01407 if (res) 01408 goto playout; 01409 } 01410 if (avgholdsecs>0) { 01411 res = ast_say_number(qe->chan, avgholdsecs, AST_DIGIT_ANY, qe->chan->language, NULL); 01412 if (res) 01413 goto playout; 01414 01415 res = play_file(qe->chan, qe->parent->sound_seconds); 01416 if (res) 01417 goto playout; 01418 } 01419 01420 } 01421 01422 posout: 01423 if (option_verbose > 2) 01424 ast_verbose(VERBOSE_PREFIX_3 "Told %s in %s their queue position (which was %d)\n", 01425 qe->chan->name, qe->parent->name, qe->pos); 01426 res = play_file(qe->chan, qe->parent->sound_thanks); 01427 01428 playout: 01429 if (res > 0 && !valid_exit(qe, res)) 01430 res = 0; 01431 01432 /* Set our last_pos indicators */ 01433 qe->last_pos = now; 01434 qe->last_pos_said = qe->pos; 01435 01436 /* Don't restart music on hold if we're about to exit the caller from the queue */ 01437 if (!res) 01438 ast_moh_start(qe->chan, qe->moh, NULL); 01439 01440 return res; 01441 }
static int set_member_paused | ( | const char * | queuename, | |
const char * | interface, | |||
int | paused | |||
) | [static] |
Definition at line 2935 of file app_queue.c.
References 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, RESULT_FAILURE, and RESULT_SUCCESS.
Referenced by manager_pause_queue_member(), pqm_exec(), rna(), and upqm_exec().
02936 { 02937 int found = 0; 02938 struct call_queue *q; 02939 struct member *mem; 02940 02941 /* Special event for when all queues are paused - individual events still generated */ 02942 /* XXX In all other cases, we use the membername, but since this affects all queues, we cannot */ 02943 if (ast_strlen_zero(queuename)) 02944 ast_queue_log("NONE", "NONE", interface, (paused ? "PAUSEALL" : "UNPAUSEALL"), "%s", ""); 02945 02946 AST_LIST_LOCK(&queues); 02947 AST_LIST_TRAVERSE(&queues, q, list) { 02948 ast_mutex_lock(&q->lock); 02949 if (ast_strlen_zero(queuename) || !strcasecmp(q->name, queuename)) { 02950 if ((mem = interface_exists(q, interface))) { 02951 found++; 02952 if (mem->paused == paused) 02953 ast_log(LOG_DEBUG, "%spausing already-%spaused queue member %s:%s\n", (paused ? "" : "un"), (paused ? "" : "un"), q->name, interface); 02954 mem->paused = paused; 02955 02956 if (queue_persistent_members) 02957 dump_queue_members(q); 02958 02959 ast_queue_log(q->name, "NONE", mem->membername, (paused ? "PAUSE" : "UNPAUSE"), "%s", ""); 02960 02961 manager_event(EVENT_FLAG_AGENT, "QueueMemberPaused", 02962 "Queue: %s\r\n" 02963 "Location: %s\r\n" 02964 "MemberName: %s\r\n" 02965 "Paused: %d\r\n", 02966 q->name, mem->interface, mem->membername, paused); 02967 } 02968 } 02969 ast_mutex_unlock(&q->lock); 02970 } 02971 AST_LIST_UNLOCK(&queues); 02972 02973 return found ? RESULT_SUCCESS : RESULT_FAILURE; 02974 }
static void set_queue_result | ( | struct ast_channel * | chan, | |
enum queue_result | res | |||
) | [static] |
Definition at line 418 of file app_queue.c.
References queue_ent::chan, pbx_builtin_setvar_helper(), queue_results, and text.
Referenced by queue_exec().
00419 { 00420 int i; 00421 00422 for (i = 0; i < sizeof(queue_results) / sizeof(queue_results[0]); i++) { 00423 if (queue_results[i].id == res) { 00424 pbx_builtin_setvar_helper(chan, "QUEUESTATUS", queue_results[i].text); 00425 return; 00426 } 00427 } 00428 }
static int statechange_queue | ( | const char * | dev, | |
int | state, | |||
void * | ign | |||
) | [static] |
Definition at line 597 of file app_queue.c.
References ast_calloc, ast_log(), ast_pthread_create_background, changethread(), free, LOG_WARNING, and t.
Referenced by load_module(), and unload_module().
00598 { 00599 /* Avoid potential for deadlocks by spawning a new thread to handle 00600 the event */ 00601 struct statechange *sc; 00602 pthread_t t; 00603 pthread_attr_t attr; 00604 00605 if (!(sc = ast_calloc(1, sizeof(*sc) + strlen(dev) + 1))) 00606 return 0; 00607 00608 sc->state = state; 00609 strcpy(sc->dev, dev); 00610 pthread_attr_init(&attr); 00611 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); 00612 if (ast_pthread_create_background(&t, &attr, changethread, sc)) { 00613 ast_log(LOG_WARNING, "Failed to create update thread!\n"); 00614 free(sc); 00615 } 00616 pthread_attr_destroy(&attr); 00617 00618 return 0; 00619 }
static int store_next | ( | struct queue_ent * | qe, | |
struct callattempt * | outgoing | |||
) | [static] |
Definition at line 1807 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().
01808 { 01809 struct callattempt *best = find_best(outgoing); 01810 01811 if (best) { 01812 /* Ring just the best channel */ 01813 if (option_debug) 01814 ast_log(LOG_DEBUG, "Next is '%s' with metric %d\n", best->interface, best->metric); 01815 qe->parent->rrpos = best->metric % 1000; 01816 } else { 01817 /* Just increment rrpos */ 01818 if (qe->parent->wrapped) { 01819 /* No more channels, start over */ 01820 qe->parent->rrpos = 0; 01821 } else { 01822 /* Prioritize next entry */ 01823 qe->parent->rrpos++; 01824 } 01825 } 01826 qe->parent->wrapped = 0; 01827 01828 return 0; 01829 }
static int strat2int | ( | const char * | strategy | ) | [static] |
Definition at line 442 of file app_queue.c.
References name, and strategies.
Referenced by queue_set_param().
00443 { 00444 int x; 00445 00446 for (x = 0; x < sizeof(strategies) / sizeof(strategies[0]); x++) { 00447 if (!strcasecmp(strategy, strategies[x].name)) 00448 return strategies[x].strategy; 00449 } 00450 00451 return -1; 00452 }
static int try_calling | ( | struct queue_ent * | qe, | |
const char * | options, | |||
char * | announceoverride, | |||
const char * | url, | |||
int * | tries, | |||
int * | noption, | |||
const char * | agi | |||
) | [static] |
Definition at line 2347 of file app_queue.c.
References ast_channel::_softhangup, ast_channel::_state, queue_ent::announce, app, ast_autoservice_start(), ast_autoservice_stop(), ast_bridge_call(), ast_calloc, ast_cdr_setdestchan(), ast_channel_make_compatible(), ast_channel_sendurl(), ast_channel_setoption(), ast_channel_supports_html(), AST_DEVICE_NOT_INUSE, AST_DIGIT_ANY, AST_FEATURE_AUTOMON, AST_FEATURE_DISCONNECT, AST_FEATURE_REDIRECT, ast_hangup(), AST_LIST_LOCK, 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, EVENT_FLAG_AGENT, call_queue::eventwhencalled, queue_ent::expire, ast_channel::exten, free, queue_ent::handled, hangupcalls(), member::interface, member::lastcall, leave_queue(), call_queue::lock, LOG_DEBUG, LOG_NOTICE, LOG_WARNING, manager_event(), callattempt::member, call_queue::membercount, call_queue::memberdelay, member::membername, call_queue::members, call_queue::monfmt, call_queue::monjoin, call_queue::montype, call_queue::name, member::next, queue_ent::opos, option_debug, queue_ent::parent, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), pbx_exec(), pbx_findapp(), pbx_substitute_variables_helper(), play_file(), queue_ent::pos, QUEUE_EVENT_VARIABLES, QUEUE_STRATEGY_ROUNDROBIN, 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, store_next(), call_queue::strategy, ast_channel::tech, call_queue::timeout, ast_channel_tech::type, ast_cdr::uniqueid, update_queue(), valid_exit(), vars2manager(), and wait_for_answer().
Referenced by queue_exec().
02348 { 02349 struct member *cur; 02350 struct callattempt *outgoing = NULL; /* the list of calls we are building */ 02351 int to; 02352 char oldexten[AST_MAX_EXTENSION]=""; 02353 char oldcontext[AST_MAX_CONTEXT]=""; 02354 char queuename[256]=""; 02355 struct ast_channel *peer; 02356 struct ast_channel *which; 02357 struct callattempt *lpeer; 02358 struct member *member; 02359 struct ast_app *app; 02360 int res = 0, bridge = 0; 02361 int numbusies = 0; 02362 int x=0; 02363 char *announce = NULL; 02364 char digit = 0; 02365 time_t callstart; 02366 time_t now = time(NULL); 02367 struct ast_bridge_config bridge_config; 02368 char nondataquality = 1; 02369 char *agiexec = NULL; 02370 int ret = 0; 02371 const char *monitorfilename; 02372 const char *monitor_exec; 02373 const char *monitor_options; 02374 char tmpid[256], tmpid2[256]; 02375 char meid[1024], meid2[1024]; 02376 char mixmonargs[1512]; 02377 struct ast_app *mixmonapp = NULL; 02378 char *p; 02379 char vars[2048]; 02380 int forwardsallowed = 1; 02381 int callcompletedinsl; 02382 02383 memset(&bridge_config, 0, sizeof(bridge_config)); 02384 time(&now); 02385 02386 for (; options && *options; options++) 02387 switch (*options) { 02388 case 't': 02389 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_REDIRECT); 02390 break; 02391 case 'T': 02392 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_REDIRECT); 02393 break; 02394 case 'w': 02395 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_AUTOMON); 02396 break; 02397 case 'W': 02398 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_AUTOMON); 02399 break; 02400 case 'd': 02401 nondataquality = 0; 02402 break; 02403 case 'h': 02404 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_DISCONNECT); 02405 break; 02406 case 'H': 02407 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT); 02408 break; 02409 case 'n': 02410 if (qe->parent->strategy == QUEUE_STRATEGY_ROUNDROBIN || qe->parent->strategy == QUEUE_STRATEGY_RRMEMORY) 02411 (*tries)++; 02412 else 02413 *tries = qe->parent->membercount; 02414 *noption = 1; 02415 break; 02416 case 'i': 02417 forwardsallowed = 0; 02418 break; 02419 } 02420 02421 /* Hold the lock while we setup the outgoing calls */ 02422 if (use_weight) 02423 AST_LIST_LOCK(&queues); 02424 ast_mutex_lock(&qe->parent->lock); 02425 if (option_debug) 02426 ast_log(LOG_DEBUG, "%s is trying to call a queue member.\n", 02427 qe->chan->name); 02428 ast_copy_string(queuename, qe->parent->name, sizeof(queuename)); 02429 cur = qe->parent->members; 02430 if (!ast_strlen_zero(qe->announce)) 02431 announce = qe->announce; 02432 if (!ast_strlen_zero(announceoverride)) 02433 announce = announceoverride; 02434 02435 for (; cur; cur = cur->next) { 02436 struct callattempt *tmp = ast_calloc(1, sizeof(*tmp)); 02437 02438 if (!tmp) { 02439 ast_mutex_unlock(&qe->parent->lock); 02440 if (use_weight) 02441 AST_LIST_UNLOCK(&queues); 02442 goto out; 02443 } 02444 tmp->stillgoing = -1; 02445 tmp->member = cur; /* Never directly dereference! Could change on reload */ 02446 tmp->oldstatus = cur->status; 02447 tmp->lastcall = cur->lastcall; 02448 ast_copy_string(tmp->interface, cur->interface, sizeof(tmp->interface)); 02449 /* Special case: If we ring everyone, go ahead and ring them, otherwise 02450 just calculate their metric for the appropriate strategy */ 02451 if (!calc_metric(qe->parent, cur, x++, qe, tmp)) { 02452 /* Put them in the list of outgoing thingies... We're ready now. 02453 XXX If we're forcibly removed, these outgoing calls won't get 02454 hung up XXX */ 02455 tmp->q_next = outgoing; 02456 outgoing = tmp; 02457 /* If this line is up, don't try anybody else */ 02458 if (outgoing->chan && (outgoing->chan->_state == AST_STATE_UP)) 02459 break; 02460 } else { 02461 free(tmp); 02462 } 02463 } 02464 if (qe->expire && (!qe->parent->timeout || (qe->expire - now) <= qe->parent->timeout)) 02465 to = (qe->expire - now) * 1000; 02466 else 02467 to = (qe->parent->timeout) ? qe->parent->timeout * 1000 : -1; 02468 ring_one(qe, outgoing, &numbusies); 02469 ast_mutex_unlock(&qe->parent->lock); 02470 if (use_weight) 02471 AST_LIST_UNLOCK(&queues); 02472 lpeer = wait_for_answer(qe, outgoing, &to, &digit, numbusies, ast_test_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT), forwardsallowed); 02473 ast_mutex_lock(&qe->parent->lock); 02474 if (qe->parent->strategy == QUEUE_STRATEGY_RRMEMORY) { 02475 store_next(qe, outgoing); 02476 } 02477 ast_mutex_unlock(&qe->parent->lock); 02478 peer = lpeer ? lpeer->chan : NULL; 02479 if (!peer) { 02480 if (to) { 02481 /* Must gotten hung up */ 02482 res = -1; 02483 } else { 02484 res = digit; 02485 if (res > 0 && !valid_exit(qe, res)) 02486 res = 0; 02487 } 02488 if (option_debug) 02489 ast_log(LOG_DEBUG, "%s: Nobody answered.\n", qe->chan->name); 02490 } else { /* peer is valid */ 02491 /* Ah ha! Someone answered within the desired timeframe. Of course after this 02492 we will always return with -1 so that it is hung up properly after the 02493 conversation. */ 02494 qe->handled++; 02495 if (!strcmp(qe->chan->tech->type, "Zap")) 02496 ast_channel_setoption(qe->chan, AST_OPTION_TONE_VERIFY, &nondataquality, sizeof(nondataquality), 0); 02497 if (!strcmp(peer->tech->type, "Zap")) 02498 ast_channel_setoption(peer, AST_OPTION_TONE_VERIFY, &nondataquality, sizeof(nondataquality), 0); 02499 /* Update parameters for the queue */ 02500 time(&now); 02501 recalc_holdtime(qe, (now - qe->start)); 02502 ast_mutex_lock(&qe->parent->lock); 02503 callcompletedinsl = ((now - qe->start) <= qe->parent->servicelevel); 02504 ast_mutex_unlock(&qe->parent->lock); 02505 member = lpeer->member; 02506 hangupcalls(outgoing, peer); 02507 outgoing = NULL; 02508 if (announce || qe->parent->reportholdtime || qe->parent->memberdelay) { 02509 int res2; 02510 02511 res2 = ast_autoservice_start(qe->chan); 02512 if (!res2) { 02513 if (qe->parent->memberdelay) { 02514 ast_log(LOG_NOTICE, "Delaying member connect for %d seconds\n", qe->parent->memberdelay); 02515 res2 |= ast_safe_sleep(peer, qe->parent->memberdelay * 1000); 02516 } 02517 if (!res2 && announce) { 02518 if (play_file(peer, announce)) 02519 ast_log(LOG_WARNING, "Announcement file '%s' is unavailable, continuing anyway...\n", announce); 02520 } 02521 if (!res2 && qe->parent->reportholdtime) { 02522 if (!play_file(peer, qe->parent->sound_reporthold)) { 02523 int holdtime; 02524 02525 time(&now); 02526 holdtime = abs((now - qe->start) / 60); 02527 if (holdtime < 2) { 02528 play_file(peer, qe->parent->sound_lessthan); 02529 ast_say_number(peer, 2, AST_DIGIT_ANY, peer->language, NULL); 02530 } else 02531 ast_say_number(peer, holdtime, AST_DIGIT_ANY, peer->language, NULL); 02532 play_file(peer, qe->parent->sound_minutes); 02533 } 02534 } 02535 } 02536 res2 |= ast_autoservice_stop(qe->chan); 02537 if (peer->_softhangup) { 02538 /* Agent must have hung up */ 02539 ast_log(LOG_WARNING, "Agent on %s hungup on the customer.\n", peer->name); 02540 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "AGENTDUMP", "%s", ""); 02541 record_abandoned(qe); 02542 if (qe->parent->eventwhencalled) 02543 manager_event(EVENT_FLAG_AGENT, "AgentDump", 02544 "Queue: %s\r\n" 02545 "Uniqueid: %s\r\n" 02546 "Channel: %s\r\n" 02547 "Member: %s\r\n" 02548 "MemberName: %s\r\n" 02549 "%s", 02550 queuename, qe->chan->uniqueid, peer->name, member->interface, member->membername, 02551 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : ""); 02552 ast_hangup(peer); 02553 goto out; 02554 } else if (res2) { 02555 /* Caller must have hung up just before being connected*/ 02556 ast_log(LOG_NOTICE, "Caller was about to talk to agent on %s but the caller hungup.\n", peer->name); 02557 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "ABANDON", "%d|%d|%ld", qe->pos, qe->opos, (long)time(NULL) - qe->start); 02558 record_abandoned(qe); 02559 ast_hangup(peer); 02560 return -1; 02561 } 02562 } 02563 /* Stop music on hold */ 02564 ast_moh_stop(qe->chan); 02565 /* If appropriate, log that we have a destination channel */ 02566 if (qe->chan->cdr) 02567 ast_cdr_setdestchan(qe->chan->cdr, peer->name); 02568 /* Make sure channels are compatible */ 02569 res = ast_channel_make_compatible(qe->chan, peer); 02570 if (res < 0) { 02571 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "SYSCOMPAT", "%s", ""); 02572 ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", qe->chan->name, peer->name); 02573 record_abandoned(qe); 02574 ast_hangup(peer); 02575 return -1; 02576 } 02577 /* Begin Monitoring */ 02578 if (qe->parent->monfmt && *qe->parent->monfmt) { 02579 if (!qe->parent->montype) { 02580 if (option_debug) 02581 ast_log(LOG_DEBUG, "Starting Monitor as requested.\n"); 02582 monitorfilename = pbx_builtin_getvar_helper(qe->chan, "MONITOR_FILENAME"); 02583 if (pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC") || pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC_ARGS")) 02584 which = qe->chan; 02585 else 02586 which = peer; 02587 if (monitorfilename) 02588 ast_monitor_start(which, qe->parent->monfmt, monitorfilename, 1 ); 02589 else if (qe->chan->cdr) 02590 ast_monitor_start(which, qe->parent->monfmt, qe->chan->cdr->uniqueid, 1 ); 02591 else { 02592 /* Last ditch effort -- no CDR, make up something */ 02593 snprintf(tmpid, sizeof(tmpid), "chan-%lx", ast_random()); 02594 ast_monitor_start(which, qe->parent->monfmt, tmpid, 1 ); 02595 } 02596 if (qe->parent->monjoin) 02597 ast_monitor_setjoinfiles(which, 1); 02598 } else { 02599 if (option_debug) 02600 ast_log(LOG_DEBUG, "Starting MixMonitor as requested.\n"); 02601 monitorfilename = pbx_builtin_getvar_helper(qe->chan, "MONITOR_FILENAME"); 02602 if (!monitorfilename) { 02603 if (qe->chan->cdr) 02604 ast_copy_string(tmpid, qe->chan->cdr->uniqueid, sizeof(tmpid)-1); 02605 else 02606 snprintf(tmpid, sizeof(tmpid), "chan-%lx", ast_random()); 02607 } else { 02608 ast_copy_string(tmpid2, monitorfilename, sizeof(tmpid2)-1); 02609 for (p = tmpid2; *p ; p++) { 02610 if (*p == '^' && *(p+1) == '{') { 02611 *p = '$'; 02612 } 02613 } 02614 02615 memset(tmpid, 0, sizeof(tmpid)); 02616 pbx_substitute_variables_helper(qe->chan, tmpid2, tmpid, sizeof(tmpid) - 1); 02617 } 02618 02619 monitor_exec = pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC"); 02620 monitor_options = pbx_builtin_getvar_helper(qe->chan, "MONITOR_OPTIONS"); 02621 02622 if (monitor_exec) { 02623 ast_copy_string(meid2, monitor_exec, sizeof(meid2)-1); 02624 for (p = meid2; *p ; p++) { 02625 if (*p == '^' && *(p+1) == '{') { 02626 *p = '$'; 02627 } 02628 } 02629 02630 memset(meid, 0, sizeof(meid)); 02631 pbx_substitute_variables_helper(qe->chan, meid2, meid, sizeof(meid) - 1); 02632 } 02633 02634 snprintf(tmpid2, sizeof(tmpid2)-1, "%s.%s", tmpid, qe->parent->monfmt); 02635 02636 mixmonapp = pbx_findapp("MixMonitor"); 02637 02638 if (strchr(tmpid2, '|')) { 02639 ast_log(LOG_WARNING, "monitor-format (in queues.conf) and MONITOR_FILENAME cannot contain a '|'! Not recording.\n"); 02640 mixmonapp = NULL; 02641 } 02642 02643 if (!monitor_options) 02644 monitor_options = ""; 02645 02646 if (strchr(monitor_options, '|')) { 02647 ast_log(LOG_WARNING, "MONITOR_OPTIONS cannot contain a '|'! Not recording.\n"); 02648 mixmonapp = NULL; 02649 } 02650 02651 if (mixmonapp) { 02652 if (!ast_strlen_zero(monitor_exec)) 02653 snprintf(mixmonargs, sizeof(mixmonargs)-1, "%s|b%s|%s", tmpid2, monitor_options, monitor_exec); 02654 else 02655 snprintf(mixmonargs, sizeof(mixmonargs)-1, "%s|b%s", tmpid2, monitor_options); 02656 02657 if (option_debug) 02658 ast_log(LOG_DEBUG, "Arguments being passed to MixMonitor: %s\n", mixmonargs); 02659 02660 ret = pbx_exec(qe->chan, mixmonapp, mixmonargs); 02661 02662 } else 02663 ast_log(LOG_WARNING, "Asked to run MixMonitor on this call, but cannot find the MixMonitor app!\n"); 02664 02665 } 02666 } 02667 /* Drop out of the queue at this point, to prepare for next caller */ 02668 leave_queue(qe); 02669 if (!ast_strlen_zero(url) && ast_channel_supports_html(peer)) { 02670 if (option_debug) 02671 ast_log(LOG_DEBUG, "app_queue: sendurl=%s.\n", url); 02672 ast_channel_sendurl(peer, url); 02673 } 02674 if (qe->parent->setinterfacevar) 02675 pbx_builtin_setvar_helper(qe->chan, "MEMBERINTERFACE", member->interface); 02676 if (!ast_strlen_zero(agi)) { 02677 if (option_debug) 02678 ast_log(LOG_DEBUG, "app_queue: agi=%s.\n", agi); 02679 app = pbx_findapp("agi"); 02680 if (app) { 02681 agiexec = ast_strdupa(agi); 02682 ret = pbx_exec(qe->chan, app, agiexec); 02683 } else 02684 ast_log(LOG_WARNING, "Asked to execute an AGI on this channel, but could not find application (agi)!\n"); 02685 } 02686 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "CONNECT", "%ld|%s", (long)time(NULL) - qe->start, peer->uniqueid); 02687 if (qe->parent->eventwhencalled) 02688 manager_event(EVENT_FLAG_AGENT, "AgentConnect", 02689 "Queue: %s\r\n" 02690 "Uniqueid: %s\r\n" 02691 "Channel: %s\r\n" 02692 "Member: %s\r\n" 02693 "MemberName: %s\r\n" 02694 "Holdtime: %ld\r\n" 02695 "BridgedChannel: %s\r\n" 02696 "%s", 02697 queuename, qe->chan->uniqueid, peer->name, member->interface, member->membername, 02698 (long)time(NULL) - qe->start, peer->uniqueid, 02699 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : ""); 02700 ast_copy_string(oldcontext, qe->chan->context, sizeof(oldcontext)); 02701 ast_copy_string(oldexten, qe->chan->exten, sizeof(oldexten)); 02702 time(&callstart); 02703 02704 if (member->status == AST_DEVICE_NOT_INUSE) 02705 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); 02706 02707 02708 bridge = ast_bridge_call(qe->chan,peer, &bridge_config); 02709 02710 if (strcasecmp(oldcontext, qe->chan->context) || strcasecmp(oldexten, qe->chan->exten)) { 02711 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "TRANSFER", "%s|%s|%ld|%ld", 02712 qe->chan->exten, qe->chan->context, (long) (callstart - qe->start), 02713 (long) (time(NULL) - callstart)); 02714 } else if (qe->chan->_softhangup) { 02715 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "COMPLETECALLER", "%ld|%ld|%d", 02716 (long) (callstart - qe->start), (long) (time(NULL) - callstart), qe->opos); 02717 if (qe->parent->eventwhencalled) 02718 manager_event(EVENT_FLAG_AGENT, "AgentComplete", 02719 "Queue: %s\r\n" 02720 "Uniqueid: %s\r\n" 02721 "Channel: %s\r\n" 02722 "Member: %s\r\n" 02723 "MemberName: %s\r\n" 02724 "HoldTime: %ld\r\n" 02725 "TalkTime: %ld\r\n" 02726 "Reason: caller\r\n" 02727 "%s", 02728 queuename, qe->chan->uniqueid, peer->name, member->interface, member->membername, 02729 (long)(callstart - qe->start), (long)(time(NULL) - callstart), 02730 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : ""); 02731 } else { 02732 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "COMPLETEAGENT", "%ld|%ld|%d", 02733 (long) (callstart - qe->start), (long) (time(NULL) - callstart), qe->opos); 02734 if (qe->parent->eventwhencalled) 02735 manager_event(EVENT_FLAG_AGENT, "AgentComplete", 02736 "Queue: %s\r\n" 02737 "Uniqueid: %s\r\n" 02738 "Channel: %s\r\n" 02739 "MemberName: %s\r\n" 02740 "HoldTime: %ld\r\n" 02741 "TalkTime: %ld\r\n" 02742 "Reason: agent\r\n" 02743 "%s", 02744 queuename, qe->chan->uniqueid, peer->name, member->membername, (long)(callstart - qe->start), 02745 (long)(time(NULL) - callstart), 02746 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : ""); 02747 } 02748 02749 if (bridge != AST_PBX_NO_HANGUP_PEER) 02750 ast_hangup(peer); 02751 update_queue(qe->parent, member, callcompletedinsl); 02752 res = bridge ? bridge : 1; 02753 } 02754 out: 02755 hangupcalls(outgoing, NULL); 02756 02757 return res; 02758 }
static int unload_module | ( | void | ) | [static] |
Definition at line 4506 of file app_queue.c.
References ast_cli_unregister_multiple(), ast_custom_function_unregister(), ast_devstate_del(), ast_manager_unregister(), ast_module_user_hangup_all, ast_unregister_application(), clear_and_free_interfaces(), cli_queue, queueagentcount_function, queuemembercount_function, queuememberlist_function, queuewaitingcount_function, and statechange_queue().
04507 { 04508 int res; 04509 04510 ast_cli_unregister_multiple(cli_queue, sizeof(cli_queue) / sizeof(struct ast_cli_entry)); 04511 res = ast_manager_unregister("QueueStatus"); 04512 res |= ast_manager_unregister("Queues"); 04513 res |= ast_manager_unregister("QueueStatus"); 04514 res |= ast_manager_unregister("QueueAdd"); 04515 res |= ast_manager_unregister("QueueRemove"); 04516 res |= ast_manager_unregister("QueuePause"); 04517 res |= ast_unregister_application(app_aqm); 04518 res |= ast_unregister_application(app_rqm); 04519 res |= ast_unregister_application(app_pqm); 04520 res |= ast_unregister_application(app_upqm); 04521 res |= ast_unregister_application(app_ql); 04522 res |= ast_unregister_application(app); 04523 res |= ast_custom_function_unregister(&queueagentcount_function); 04524 res |= ast_custom_function_unregister(&queuemembercount_function); 04525 res |= ast_custom_function_unregister(&queuememberlist_function); 04526 res |= ast_custom_function_unregister(&queuewaitingcount_function); 04527 ast_devstate_del(statechange_queue, NULL); 04528 04529 ast_module_user_hangup_all(); 04530 04531 clear_and_free_interfaces(); 04532 04533 return res; 04534 }
static int update_dial_status | ( | struct call_queue * | q, | |
struct member * | member, | |||
int | status | |||
) | [static] |
Definition at line 1547 of file app_queue.c.
References AST_CAUSE_BUSY, AST_CAUSE_NOSUCHDRIVER, AST_CAUSE_UNREGISTERED, AST_DEVICE_BUSY, AST_DEVICE_INVALID, AST_DEVICE_UNAVAILABLE, AST_DEVICE_UNKNOWN, and update_status().
Referenced by ring_entry().
01548 { 01549 if (status == AST_CAUSE_BUSY) 01550 status = AST_DEVICE_BUSY; 01551 else if (status == AST_CAUSE_UNREGISTERED) 01552 status = AST_DEVICE_UNAVAILABLE; 01553 else if (status == AST_CAUSE_NOSUCHDRIVER) 01554 status = AST_DEVICE_INVALID; 01555 else 01556 status = AST_DEVICE_UNKNOWN; 01557 return update_status(q, member, status); 01558 }
static int update_queue | ( | struct call_queue * | q, | |
struct member * | member, | |||
int | callcompletedinsl | |||
) | [static] |
Definition at line 2269 of file app_queue.c.
References ast_mutex_lock(), ast_mutex_unlock(), member::calls, call_queue::callscompleted, call_queue::callscompletedinsl, member::lastcall, call_queue::lock, call_queue::members, and member::next.
Referenced by try_calling().
02270 { 02271 struct member *cur; 02272 02273 /* Since a reload could have taken place, we have to traverse the list to 02274 be sure it's still valid */ 02275 ast_mutex_lock(&q->lock); 02276 cur = q->members; 02277 while (cur) { 02278 if (member == cur) { 02279 time(&cur->lastcall); 02280 cur->calls++; 02281 break; 02282 } 02283 cur = cur->next; 02284 } 02285 q->callscompleted++; 02286 if (callcompletedinsl) 02287 q->callscompletedinsl++; 02288 ast_mutex_unlock(&q->lock); 02289 return 0; 02290 }
static void update_realtime_members | ( | struct call_queue * | q | ) | [static] |
Definition at line 1123 of file app_queue.c.
References ast_category_browse(), ast_load_realtime_multientry(), ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_variable_retrieve(), member::dead, member::dynamic, free, member::interface, member_interface::interface, call_queue::lock, LOG_DEBUG, call_queue::membercount, call_queue::members, call_queue::name, member::next, option_debug, remove_from_interfaces(), rt_handle_member_record(), and S_OR.
Referenced by load_realtime_queue(), and queue_exec().
01124 { 01125 struct ast_config *member_config = NULL; 01126 struct member *m, *prev_m, *next_m; 01127 char *interface = NULL; 01128 01129 member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name", q->name , NULL); 01130 if (!member_config) { 01131 /*This queue doesn't have realtime members*/ 01132 if (option_debug > 2) 01133 ast_log(LOG_DEBUG, "Queue %s has no realtime members defined. No need for update\n", q->name); 01134 return; 01135 } 01136 01137 ast_mutex_lock(&q->lock); 01138 01139 /* Temporarily set non-dynamic members dead so we can detect deleted ones.*/ 01140 for (m = q->members; m; m = m->next) { 01141 if (!m->dynamic) 01142 m->dead = 1; 01143 } 01144 01145 while ((interface = ast_category_browse(member_config, interface))) { 01146 rt_handle_member_record(q, interface, 01147 S_OR(ast_variable_retrieve(member_config, interface, "membername"), interface), 01148 ast_variable_retrieve(member_config, interface, "penalty"), 01149 ast_variable_retrieve(member_config, interface, "paused")); 01150 } 01151 01152 /* Delete all realtime members that have been deleted in DB. */ 01153 m = q->members; 01154 prev_m = NULL; 01155 while (m) { 01156 next_m = m->next; 01157 if (m->dead) { 01158 if (prev_m) { 01159 prev_m->next = next_m; 01160 } else { 01161 q->members = next_m; 01162 } 01163 remove_from_interfaces(m->interface); 01164 q->membercount--; 01165 free(m); 01166 } else { 01167 prev_m = m; 01168 } 01169 m = next_m; 01170 } 01171 ast_mutex_unlock(&q->lock); 01172 }
static int update_status | ( | struct call_queue * | q, | |
struct member * | member, | |||
int | status | |||
) | [static] |
Definition at line 1516 of file app_queue.c.
References ast_mutex_lock(), ast_mutex_unlock(), 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::next, member::paused, member::penalty, and member::status.
Referenced by update_dial_status().
01517 { 01518 struct member *cur; 01519 01520 /* Since a reload could have taken place, we have to traverse the list to 01521 be sure it's still valid */ 01522 ast_mutex_lock(&q->lock); 01523 for (cur = q->members; cur; cur = cur->next) { 01524 if (member != cur) 01525 continue; 01526 01527 cur->status = status; 01528 if (!q->maskmemberstatus) { 01529 manager_event(EVENT_FLAG_AGENT, "QueueMemberStatus", 01530 "Queue: %s\r\n" 01531 "Location: %s\r\n" 01532 "MemberName: %s\r\n" 01533 "Membership: %s\r\n" 01534 "Penalty: %d\r\n" 01535 "CallsTaken: %d\r\n" 01536 "LastCall: %d\r\n" 01537 "Status: %d\r\n" 01538 "Paused: %d\r\n", 01539 q->name, cur->interface, cur->membername, cur->dynamic ? "dynamic" : "static", 01540 cur->penalty, cur->calls, (int)cur->lastcall, cur->status, cur->paused); 01541 } 01542 } 01543 ast_mutex_unlock(&q->lock); 01544 return 0; 01545 }
static int upqm_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Definition at line 3125 of file app_queue.c.
References AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_goto_if_exists(), ast_log(), ast_module_user_add, ast_module_user_remove, ast_opt_priority_jumping, AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), ast_module_user::chan, ast_channel::context, LOG_WARNING, parse(), pbx_builtin_setvar_helper(), and set_member_paused().
Referenced by load_module().
03126 { 03127 struct ast_module_user *lu; 03128 char *parse; 03129 int priority_jump = 0; 03130 AST_DECLARE_APP_ARGS(args, 03131 AST_APP_ARG(queuename); 03132 AST_APP_ARG(interface); 03133 AST_APP_ARG(options); 03134 ); 03135 03136 if (ast_strlen_zero(data)) { 03137 ast_log(LOG_WARNING, "UnpauseQueueMember requires an argument ([queuename]|interface[|options])\n"); 03138 return -1; 03139 } 03140 03141 parse = ast_strdupa(data); 03142 03143 AST_STANDARD_APP_ARGS(args, parse); 03144 03145 lu = ast_module_user_add(chan); 03146 03147 if (args.options) { 03148 if (strchr(args.options, 'j')) 03149 priority_jump = 1; 03150 } 03151 03152 if (ast_strlen_zero(args.interface)) { 03153 ast_log(LOG_WARNING, "Missing interface argument to PauseQueueMember ([queuename]|interface[|options])\n"); 03154 ast_module_user_remove(lu); 03155 return -1; 03156 } 03157 03158 if (set_member_paused(args.queuename, args.interface, 0)) { 03159 ast_log(LOG_WARNING, "Attempt to unpause interface %s, not found\n", args.interface); 03160 if (priority_jump || ast_opt_priority_jumping) { 03161 if (ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101)) { 03162 pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "NOTFOUND"); 03163 ast_module_user_remove(lu); 03164 return 0; 03165 } 03166 } 03167 ast_module_user_remove(lu); 03168 pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "NOTFOUND"); 03169 return -1; 03170 } 03171 03172 ast_module_user_remove(lu); 03173 pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "UNPAUSED"); 03174 03175 return 0; 03176 }
static int valid_exit | ( | struct queue_ent * | qe, | |
char | digit | |||
) | [static] |
Definition at line 1303 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(), try_calling(), wait_a_bit(), and wait_our_turn().
01304 { 01305 int digitlen = strlen(qe->digits); 01306 01307 /* Prevent possible buffer overflow */ 01308 if (digitlen < sizeof(qe->digits) - 2) { 01309 qe->digits[digitlen] = digit; 01310 qe->digits[digitlen + 1] = '\0'; 01311 } else { 01312 qe->digits[0] = '\0'; 01313 return 0; 01314 } 01315 01316 /* If there's no context to goto, short-circuit */ 01317 if (ast_strlen_zero(qe->context)) 01318 return 0; 01319 01320 /* If the extension is bad, then reset the digits to blank */ 01321 if (!ast_canmatch_extension(qe->chan, qe->context, qe->digits, 1, qe->chan->cid.cid_num)) { 01322 qe->digits[0] = '\0'; 01323 return 0; 01324 } 01325 01326 /* We have an exact match */ 01327 if (!ast_goto_if_exists(qe->chan, qe->context, qe->digits, 1)) { 01328 qe->valid_digits = 1; 01329 /* Return 1 on a successful goto */ 01330 return 1; 01331 } 01332 01333 return 0; 01334 }
static char* vars2manager | ( | struct ast_channel * | chan, | |
char * | vars, | |||
size_t | len | |||
) | [static] |
Definition at line 1602 of file app_queue.c.
References pbx_builtin_serialize_variables().
Referenced by ring_entry(), and try_calling().
01603 { 01604 char *tmp = alloca(len); 01605 01606 if (pbx_builtin_serialize_variables(chan, tmp, len)) { 01607 int i, j; 01608 01609 /* convert "\n" to "\nVariable: " */ 01610 strcpy(vars, "Variable: "); 01611 01612 for (i = 0, j = 10; (i < len - 1) && (j < len - 1); i++, j++) { 01613 vars[j] = tmp[i]; 01614 01615 if (tmp[i + 1] == '\0') 01616 break; 01617 if (tmp[i] == '\n') { 01618 vars[j] = '\r'; 01619 vars[++j] = '\n'; 01620 01621 ast_copy_string(&(vars[j]), "Variable: ", len - j); 01622 j += 9; 01623 } 01624 } 01625 if (j > len - 1) 01626 j = len - 1; 01627 vars[j - 2] = '\r'; 01628 vars[j - 1] = '\n'; 01629 vars[j] = '\0'; 01630 } else { 01631 /* there are no channel variables; leave it blank */ 01632 *vars = '\0'; 01633 } 01634 return vars; 01635 }
static int wait_a_bit | ( | struct queue_ent * | qe | ) | [static] |
Definition at line 2760 of file app_queue.c.
References ast_waitfordigit(), queue_ent::chan, queue_ent::parent, call_queue::retry, and valid_exit().
Referenced by queue_exec().
02761 { 02762 /* Don't need to hold the lock while we setup the outgoing calls */ 02763 int retrywait = qe->parent->retry * 1000; 02764 02765 int res = ast_waitfordigit(qe->chan, retrywait); 02766 if (res > 0 && !valid_exit(qe, res)) 02767 res = 0; 02768 02769 return res; 02770 }
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] |
Definition at line 1908 of file app_queue.c.
References ast_channel::_state, ast_log(), AST_MAX_WATCHERS, AST_STATE_UP, ast_strlen_zero(), ast_verbose(), ast_waitfor_n(), callattempt::chan, queue_ent::chan, do_hang(), f, member::interface, LOG_DEBUG, LOG_NOTICE, callattempt::member, member::membername, call_queue::name, option_verbose, queue_ent::parent, callattempt::q_next, QUEUE_STRATEGY_RINGALL, ring_one(), starttime, callattempt::stillgoing, call_queue::strategy, and VERBOSE_PREFIX_3.
01909 { 01910 char *queue = qe->parent->name; 01911 struct callattempt *o; 01912 int status; 01913 int sentringing = 0; 01914 int numbusies = prebusies; 01915 int numnochan = 0; 01916 int stillgoing = 0; 01917 int orig = *to; 01918 struct ast_frame *f; 01919 struct callattempt *peer = NULL; 01920 struct ast_channel *winner; 01921 struct ast_channel *in = qe->chan; 01922 char on[80] = ""; 01923 char membername[80] = ""; 01924 long starttime = 0; 01925 long endtime = 0; 01926 01927 starttime = (long) time(NULL); 01928 01929 while (*to && !peer) { 01930 int numlines, retry, pos = 1; 01931 struct ast_channel *watchers[AST_MAX_WATCHERS]; 01932 watchers[0] = in; 01933 01934 for (retry = 0; retry < 2; retry++) { 01935 numlines = 0; 01936 for (o = outgoing; o; o = o->q_next) { /* Keep track of important channels */ 01937 if (o->stillgoing) { /* Keep track of important channels */ 01938 stillgoing = 1; 01939 if (o->chan) 01940 watchers[pos++] = o->chan; 01941 } 01942 numlines++; 01943 } 01944 if (pos > 1 /* found */ || !stillgoing /* nobody listening */ || 01945 (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) /* ring would not be delivered */) 01946 break; 01947 /* On "ringall" strategy we only move to the next penalty level 01948 when *all* ringing phones are done in the current penalty level */ 01949 ring_one(qe, outgoing, &numbusies); 01950 /* and retry... */ 01951 } 01952 if (pos == 1 /* not found */) { 01953 if (numlines == (numbusies + numnochan)) { 01954 ast_log(LOG_DEBUG, "Everyone is busy at this time\n"); 01955 } else { 01956 ast_log(LOG_NOTICE, "No one is answering queue '%s' (%d/%d/%d)\n", queue, numlines, numbusies, numnochan); 01957 } 01958 *to = 0; 01959 return NULL; 01960 } 01961 winner = ast_waitfor_n(watchers, pos, to); 01962 for (o = outgoing; o; o = o->q_next) { 01963 if (o->stillgoing && (o->chan) && (o->chan->_state == AST_STATE_UP)) { 01964 if (!peer) { 01965 if (option_verbose > 2) 01966 ast_verbose( VERBOSE_PREFIX_3 "%s answered %s\n", o->chan->name, in->name); 01967 peer = o; 01968 } 01969 } else if (o->chan && (o->chan == winner)) { 01970 01971 ast_copy_string(on, o->member->interface, sizeof(on)); 01972 ast_copy_string(membername, o->member->membername, sizeof(membername)); 01973 01974 if (!ast_strlen_zero(o->chan->call_forward) && !forwardsallowed) { 01975 if (option_verbose > 2) 01976 ast_verbose(VERBOSE_PREFIX_3 "Forwarding %s to '%s' prevented.\n", in->name, o->chan->call_forward); 01977 numnochan++; 01978 do_hang(o); 01979 winner = NULL; 01980 continue; 01981 } else if (!ast_strlen_zero(o->chan->call_forward)) { 01982 char tmpchan[256]; 01983 char *stuff; 01984 char *tech; 01985 01986 ast_copy_string(tmpchan, o->chan->call_forward, sizeof(tmpchan)); 01987 if ((stuff = strchr(tmpchan, '/'))) { 01988 *stuff++ = '\0'; 01989 tech = tmpchan; 01990 } else { 01991 snprintf(tmpchan, sizeof(tmpchan), "%s@%s", o->chan->call_forward, o->chan->context); 01992 stuff = tmpchan; 01993 tech = "Local"; 01994 } 01995 /* Before processing channel, go ahead and check for forwarding */ 01996 if (option_verbose > 2) 01997 ast_verbose(VERBOSE_PREFIX_3 "Now forwarding %s to '%s/%s' (thanks to %s)\n", in->name, tech, stuff, o->chan->name); 01998 /* Setup parameters */ 01999 o->chan = ast_request(tech, in->nativeformats, stuff, &status); 02000 if (status != o->oldstatus) 02001 update_dial_status(qe->parent, o->member, status); 02002 if (!o->chan) { 02003 ast_log(LOG_NOTICE, "Unable to create local channel for call forward to '%s/%s'\n", tech, stuff); 02004 o->stillgoing = 0; 02005 numnochan++; 02006 } else { 02007 ast_channel_inherit_variables(in, o->chan); 02008 if (o->chan->cid.cid_num) 02009 free(o->chan->cid.cid_num); 02010 o->chan->cid.cid_num = ast_strdup(in->cid.cid_num); 02011 02012 if (o->chan->cid.cid_name) 02013 free(o->chan->cid.cid_name); 02014 o->chan->cid.cid_name = ast_strdup(in->cid.cid_name); 02015 02016 ast_string_field_set(o->chan, accountcode, in->accountcode); 02017 o->chan->cdrflags = in->cdrflags; 02018 02019 if (in->cid.cid_ani) { 02020 if (o->chan->cid.cid_ani) 02021 free(o->chan->cid.cid_ani); 02022 o->chan->cid.cid_ani = ast_strdup(in->cid.cid_ani); 02023 } 02024 if (o->chan->cid.cid_rdnis) 02025 free(o->chan->cid.cid_rdnis); 02026 o->chan->cid.cid_rdnis = ast_strdup(S_OR(in->macroexten, in->exten)); 02027 if (ast_call(o->chan, tmpchan, 0)) { 02028 ast_log(LOG_NOTICE, "Failed to dial on local channel for call forward to '%s'\n", tmpchan); 02029 do_hang(o); 02030 numnochan++; 02031 } 02032 } 02033 /* Hangup the original channel now, in case we needed it */ 02034 ast_hangup(winner); 02035 continue; 02036 } 02037 f = ast_read(winner); 02038 if (f) { 02039 if (f->frametype == AST_FRAME_CONTROL) { 02040 switch (f->subclass) { 02041 case AST_CONTROL_ANSWER: 02042 /* This is our guy if someone answered. */ 02043 if (!peer) { 02044 if (option_verbose > 2) 02045 ast_verbose( VERBOSE_PREFIX_3 "%s answered %s\n", o->chan->name, in->name); 02046 peer = o; 02047 } 02048 break; 02049 case AST_CONTROL_BUSY: 02050 if (option_verbose > 2) 02051 ast_verbose( VERBOSE_PREFIX_3 "%s is busy\n", o->chan->name); 02052 if (in->cdr) 02053 ast_cdr_busy(in->cdr); 02054 do_hang(o); 02055 endtime = (long)time(NULL); 02056 endtime -= starttime; 02057 rna(endtime*1000, qe, on, membername); 02058 if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) { 02059 if (qe->parent->timeoutrestart) 02060 *to = orig; 02061 ring_one(qe, outgoing, &numbusies); 02062 } 02063 numbusies++; 02064 break; 02065 case AST_CONTROL_CONGESTION: 02066 if (option_verbose > 2) 02067 ast_verbose( VERBOSE_PREFIX_3 "%s is circuit-busy\n", o->chan->name); 02068 if (in->cdr) 02069 ast_cdr_busy(in->cdr); 02070 endtime = (long)time(NULL); 02071 endtime -= starttime; 02072 rna(endtime*1000, qe, on, membername); 02073 do_hang(o); 02074 if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) { 02075 if (qe->parent->timeoutrestart) 02076 *to = orig; 02077 ring_one(qe, outgoing, &numbusies); 02078 } 02079 numbusies++; 02080 break; 02081 case AST_CONTROL_RINGING: 02082 if (option_verbose > 2) 02083 ast_verbose( VERBOSE_PREFIX_3 "%s is ringing\n", o->chan->name); 02084 if (!sentringing) { 02085 #if 0 02086 ast_indicate(in, AST_CONTROL_RINGING); 02087 #endif 02088 sentringing++; 02089 } 02090 break; 02091 case AST_CONTROL_OFFHOOK: 02092 /* Ignore going off hook */ 02093 break; 02094 default: 02095 ast_log(LOG_DEBUG, "Dunno what to do with control type %d\n", f->subclass); 02096 } 02097 } 02098 ast_frfree(f); 02099 } else { 02100 endtime = (long) time(NULL) - starttime; 02101 rna(endtime * 1000, qe, on, membername); 02102 do_hang(o); 02103 if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) { 02104 if (qe->parent->timeoutrestart) 02105 *to = orig; 02106 ring_one(qe, outgoing, &numbusies); 02107 } 02108 } 02109 } 02110 } 02111 if (winner == in) { 02112 f = ast_read(in); 02113 if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP))) { 02114 /* Got hung up */ 02115 *to = -1; 02116 if (f) 02117 ast_frfree(f); 02118 return NULL; 02119 } 02120 if ((f->frametype == AST_FRAME_DTMF) && caller_disconnect && (f->subclass == '*')) { 02121 if (option_verbose > 3) 02122 ast_verbose(VERBOSE_PREFIX_3 "User hit %c to disconnect call.\n", f->subclass); 02123 *to = 0; 02124 ast_frfree(f); 02125 return NULL; 02126 } 02127 if ((f->frametype == AST_FRAME_DTMF) && valid_exit(qe, f->subclass)) { 02128 if (option_verbose > 3) 02129 ast_verbose(VERBOSE_PREFIX_3 "User pressed digit: %c\n", f->subclass); 02130 *to = 0; 02131 *digit = f->subclass; 02132 ast_frfree(f); 02133 return NULL; 02134 } 02135 ast_frfree(f); 02136 } 02137 if (!*to) 02138 rna(orig, qe, on, membername); 02139 } 02140 02141 return peer; 02142 }
static int wait_our_turn | ( | struct queue_ent * | qe, | |
int | ringing, | |||
enum queue_result * | reason | |||
) | [static] |
Definition at line 2212 of file app_queue.c.
References call_queue::announcefrequency, ast_queue_log(), ast_waitfordigit(), queue_ent::chan, get_member_status(), is_our_turn(), leave_queue(), call_queue::leavewhenempty, queue_ent::max_penalty, call_queue::name, queue_ent::opos, queue_ent::parent, call_queue::periodicannouncefrequency, queue_ent::pos, QUEUE_EMPTY_STRICT, QUEUE_LEAVEEMPTY, QUEUE_LEAVEUNAVAIL, QUEUE_NO_MEMBERS, QUEUE_NO_REACHABLE_MEMBERS, QUEUE_TIMEOUT, RECHECK, say_periodic_announcement(), say_position(), queue_ent::start, and valid_exit().
Referenced by queue_exec().
02213 { 02214 int res = 0; 02215 02216 /* This is the holding pen for callers 2 through maxlen */ 02217 for (;;) { 02218 enum queue_member_status stat; 02219 02220 if (is_our_turn(qe)) 02221 break; 02222 02223 /* If we have timed out, break out */ 02224 if (qe->expire && (time(NULL) > qe->expire)) { 02225 *reason = QUEUE_TIMEOUT; 02226 break; 02227 } 02228 02229 stat = get_member_status(qe->parent, qe->max_penalty); 02230 02231 /* leave the queue if no agents, if enabled */ 02232 if (qe->parent->leavewhenempty && (stat == QUEUE_NO_MEMBERS)) { 02233 *reason = QUEUE_LEAVEEMPTY; 02234 ast_queue_log(qe->parent->name, qe->chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe->pos, qe->opos, (long)time(NULL) - qe->start); 02235 leave_queue(qe); 02236 break; 02237 } 02238 02239 /* leave the queue if no reachable agents, if enabled */ 02240 if ((qe->parent->leavewhenempty == QUEUE_EMPTY_STRICT) && (stat == QUEUE_NO_REACHABLE_MEMBERS)) { 02241 *reason = QUEUE_LEAVEUNAVAIL; 02242 ast_queue_log(qe->parent->name, qe->chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe->pos, qe->opos, (long)time(NULL) - qe->start); 02243 leave_queue(qe); 02244 break; 02245 } 02246 02247 /* Make a position announcement, if enabled */ 02248 if (qe->parent->announcefrequency && !ringing && 02249 (res = say_position(qe))) 02250 break; 02251 02252 /* Make a periodic announcement, if enabled */ 02253 if (qe->parent->periodicannouncefrequency && !ringing && 02254 (res = say_periodic_announcement(qe))) 02255 break; 02256 02257 /* Wait a second before checking again */ 02258 if ((res = ast_waitfordigit(qe->chan, RECHECK * 1000))) { 02259 if (res > 0 && !valid_exit(qe, res)) 02260 res = 0; 02261 else 02262 break; 02263 } 02264 } 02265 02266 return res; 02267 }
char* app = "Queue" [static] |
Definition at line 127 of file app_queue.c.
char* app_aqm = "AddQueueMember" [static] |
Definition at line 161 of file app_queue.c.
char* app_aqm_descrip [static] |
Definition at line 163 of file app_queue.c.
char* app_aqm_synopsis = "Dynamically adds queue members" [static] |
Definition at line 162 of file app_queue.c.
char* app_pqm = "PauseQueueMember" [static] |
Definition at line 193 of file app_queue.c.
char* app_pqm_descrip [static] |
Definition at line 195 of file app_queue.c.
char* app_pqm_synopsis = "Pauses a queue member" [static] |
Definition at line 194 of file app_queue.c.
char* app_ql = "QueueLog" [static] |
Definition at line 230 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 232 of file app_queue.c.
char* app_ql_synopsis = "Writes to the queue_log" [static] |
Definition at line 231 of file app_queue.c.
char* app_rqm = "RemoveQueueMember" [static] |
Definition at line 177 of file app_queue.c.
char* app_rqm_descrip [static] |
Definition at line 179 of file app_queue.c.
char* app_rqm_synopsis = "Dynamically removes queue members" [static] |
Definition at line 178 of file app_queue.c.
char* app_upqm = "UnpauseQueueMember" [static] |
Definition at line 215 of file app_queue.c.
char* app_upqm_descrip [static] |
Definition at line 217 of file app_queue.c.
char* app_upqm_synopsis = "Unpauses a queue member" [static] |
Definition at line 216 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 4477 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 4482 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 4472 of file app_queue.c.
char* descrip [static] |
Definition at line 131 of file app_queue.c.
enum queue_result id |
Definition at line 265 of file app_queue.c.
Referenced by _sip_show_peers(), aMYSQL_clear(), and aMYSQL_disconnect().
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 4466 of file app_queue.c.
char qrm_cmd_usage[] [static] |
Initial value:
"Usage: queue remove member <channel> from <queue>\n"
Definition at line 4469 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 4462 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] |
struct strategy strategies[] [static] |
Referenced by int2strat(), and strat2int().
char* synopsis = "Queue a call for a call queue" [static] |
Definition at line 129 of file app_queue.c.
char* text |
Definition at line 266 of file app_queue.c.
Referenced by _sip_show_peer(), build_reply_digest(), check_auth(), handle_response(), method_match(), parse_sip_options(), referstatus2str(), reqprep(), sendtext_exec(), set_queue_result(), sip_alloc(), and sip_show_channel().
int use_weight = 0 [static] |