#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"
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 *go_on, 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 1904 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 3939 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, call_queue::servicelevel, queue_ent::start, member::status, call_queue::strategy, and call_queue::weight.
Referenced by manager_queues_show(), and queue_show().
03940 { 03941 struct call_queue *q; 03942 struct queue_ent *qe; 03943 struct member *mem; 03944 int pos, queue_show; 03945 time_t now; 03946 char max_buf[80]; 03947 char *max; 03948 size_t max_left; 03949 float sl = 0; 03950 char *term = manager ? "\r\n" : "\n"; 03951 03952 time(&now); 03953 if (argc == 2) 03954 queue_show = 0; 03955 else if (argc == 3) 03956 queue_show = 1; 03957 else 03958 return RESULT_SHOWUSAGE; 03959 03960 /* We only want to load realtime queues when a specific queue is asked for. */ 03961 if (queue_show) 03962 load_realtime_queue(argv[2]); 03963 03964 AST_LIST_LOCK(&queues); 03965 if (AST_LIST_EMPTY(&queues)) { 03966 AST_LIST_UNLOCK(&queues); 03967 if (queue_show) { 03968 if (s) 03969 astman_append(s, "No such queue: %s.%s",argv[2], term); 03970 else 03971 ast_cli(fd, "No such queue: %s.%s",argv[2], term); 03972 } else { 03973 if (s) 03974 astman_append(s, "No queues.%s", term); 03975 else 03976 ast_cli(fd, "No queues.%s", term); 03977 } 03978 return RESULT_SUCCESS; 03979 } 03980 AST_LIST_TRAVERSE(&queues, q, list) { 03981 ast_mutex_lock(&q->lock); 03982 if (queue_show) { 03983 if (strcasecmp(q->name, argv[2]) != 0) { 03984 ast_mutex_unlock(&q->lock); 03985 if (!AST_LIST_NEXT(q, list)) { 03986 ast_cli(fd, "No such queue: %s.%s",argv[2], term); 03987 break; 03988 } 03989 continue; 03990 } 03991 } 03992 max_buf[0] = '\0'; 03993 max = max_buf; 03994 max_left = sizeof(max_buf); 03995 if (q->maxlen) 03996 ast_build_string(&max, &max_left, "%d", q->maxlen); 03997 else 03998 ast_build_string(&max, &max_left, "unlimited"); 03999 sl = 0; 04000 if (q->callscompleted > 0) 04001 sl = 100 * ((float) q->callscompletedinsl / (float) q->callscompleted); 04002 if (s) 04003 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", 04004 q->name, q->count, max_buf, int2strat(q->strategy), q->holdtime, q->weight, 04005 q->callscompleted, q->callsabandoned,sl,q->servicelevel, term); 04006 else 04007 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", 04008 q->name, q->count, max_buf, int2strat(q->strategy), q->holdtime, q->weight, q->callscompleted, q->callsabandoned,sl,q->servicelevel, term); 04009 if (q->members) { 04010 if (s) 04011 astman_append(s, " Members: %s", term); 04012 else 04013 ast_cli(fd, " Members: %s", term); 04014 for (mem = q->members; mem; mem = mem->next) { 04015 max_buf[0] = '\0'; 04016 max = max_buf; 04017 max_left = sizeof(max_buf); 04018 if (mem->penalty) 04019 ast_build_string(&max, &max_left, " with penalty %d", mem->penalty); 04020 if (mem->dynamic) 04021 ast_build_string(&max, &max_left, " (dynamic)"); 04022 if (mem->paused) 04023 ast_build_string(&max, &max_left, " (paused)"); 04024 ast_build_string(&max, &max_left, " (%s)", devstate2str(mem->status)); 04025 if (mem->calls) { 04026 ast_build_string(&max, &max_left, " has taken %d calls (last was %ld secs ago)", 04027 mem->calls, (long) (time(NULL) - mem->lastcall)); 04028 } else 04029 ast_build_string(&max, &max_left, " has taken no calls yet"); 04030 if (s) 04031 astman_append(s, " %s%s%s", mem->interface, max_buf, term); 04032 else 04033 ast_cli(fd, " %s%s%s", mem->interface, max_buf, term); 04034 } 04035 } else if (s) 04036 astman_append(s, " No Members%s", term); 04037 else 04038 ast_cli(fd, " No Members%s", term); 04039 if (q->head) { 04040 pos = 1; 04041 if (s) 04042 astman_append(s, " Callers: %s", term); 04043 else 04044 ast_cli(fd, " Callers: %s", term); 04045 for (qe = q->head; qe; qe = qe->next) { 04046 if (s) 04047 astman_append(s, " %d. %s (wait: %ld:%2.2ld, prio: %d)%s", 04048 pos++, qe->chan->name, (long) (now - qe->start) / 60, 04049 (long) (now - qe->start) % 60, qe->prio, term); 04050 else 04051 ast_cli(fd, " %d. %s (wait: %ld:%2.2ld, prio: %d)%s", pos++, 04052 qe->chan->name, (long) (now - qe->start) / 60, 04053 (long) (now - qe->start) % 60, qe->prio, term); 04054 } 04055 } else if (s) 04056 astman_append(s, " No Callers%s", term); 04057 else 04058 ast_cli(fd, " No Callers%s", term); 04059 if (s) 04060 astman_append(s, "%s", term); 04061 else 04062 ast_cli(fd, "%s", term); 04063 ast_mutex_unlock(&q->lock); 04064 if (queue_show) 04065 break; 04066 } 04067 AST_LIST_UNLOCK(&queues); 04068 return RESULT_SUCCESS; 04069 }
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 2885 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().
02886 { 02887 struct call_queue *q; 02888 struct member *new_member; 02889 int res = RES_NOSUCHQUEUE; 02890 02891 /* \note Ensure the appropriate realtime queue is loaded. Note that this 02892 * short-circuits if the queue is already in memory. */ 02893 if (!(q = load_realtime_queue(queuename))) 02894 return res; 02895 02896 AST_LIST_LOCK(&queues); 02897 02898 ast_mutex_lock(&q->lock); 02899 if (interface_exists(q, interface) == NULL) { 02900 add_to_interfaces(interface); 02901 if ((new_member = create_queue_member(interface, membername, penalty, paused))) { 02902 new_member->dynamic = 1; 02903 new_member->next = q->members; 02904 q->members = new_member; 02905 q->membercount++; 02906 manager_event(EVENT_FLAG_AGENT, "QueueMemberAdded", 02907 "Queue: %s\r\n" 02908 "Location: %s\r\n" 02909 "MemberName: %s\r\n" 02910 "Membership: %s\r\n" 02911 "Penalty: %d\r\n" 02912 "CallsTaken: %d\r\n" 02913 "LastCall: %d\r\n" 02914 "Status: %d\r\n" 02915 "Paused: %d\r\n", 02916 q->name, new_member->interface, new_member->membername, 02917 new_member->dynamic ? "dynamic" : "static", 02918 new_member->penalty, new_member->calls, (int) new_member->lastcall, 02919 new_member->status, new_member->paused); 02920 02921 if (dump) 02922 dump_queue_members(q); 02923 02924 res = RES_OKAY; 02925 } else { 02926 res = RES_OUTOFMEMORY; 02927 } 02928 } else { 02929 res = RES_EXISTS; 02930 } 02931 ast_mutex_unlock(&q->lock); 02932 AST_LIST_UNLOCK(&queues); 02933 02934 return res; 02935 }
static struct call_queue* alloc_queue | ( | const char * | queuename | ) | [static, read] |
Definition at line 638 of file app_queue.c.
References ast_calloc, ast_mutex_init(), call_queue::lock, and call_queue::name.
Referenced by find_queue_by_name_rt(), and reload_queues().
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 3242 of file app_queue.c.
References add_to_queue(), AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_goto_if_exists(), ast_log(), ast_module_user_add, ast_module_user_remove, ast_opt_priority_jumping, ast_queue_log(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), ast_channel::context, ast_channel::exten, member_interface::interface, LOG_ERROR, LOG_NOTICE, LOG_WARNING, parse(), pbx_builtin_setvar_helper(), ast_channel::priority, RES_EXISTS, RES_NOSUCHQUEUE, RES_OKAY, and RES_OUTOFMEMORY.
Referenced by load_module().
03243 { 03244 int res=-1; 03245 struct ast_module_user *lu; 03246 char *parse, *temppos = NULL; 03247 int priority_jump = 0; 03248 AST_DECLARE_APP_ARGS(args, 03249 AST_APP_ARG(queuename); 03250 AST_APP_ARG(interface); 03251 AST_APP_ARG(penalty); 03252 AST_APP_ARG(options); 03253 AST_APP_ARG(membername); 03254 ); 03255 int penalty = 0; 03256 03257 if (ast_strlen_zero(data)) { 03258 ast_log(LOG_WARNING, "AddQueueMember requires an argument (queuename[|[interface]|[penalty][|options][|membername]])\n"); 03259 return -1; 03260 } 03261 03262 parse = ast_strdupa(data); 03263 03264 AST_STANDARD_APP_ARGS(args, parse); 03265 03266 lu = ast_module_user_add(chan); 03267 03268 if (ast_strlen_zero(args.interface)) { 03269 args.interface = ast_strdupa(chan->name); 03270 temppos = strrchr(args.interface, '-'); 03271 if (temppos) 03272 *temppos = '\0'; 03273 } 03274 03275 if (!ast_strlen_zero(args.penalty)) { 03276 if ((sscanf(args.penalty, "%d", &penalty) != 1) || penalty < 0) { 03277 ast_log(LOG_WARNING, "Penalty '%s' is invalid, must be an integer >= 0\n", args.penalty); 03278 penalty = 0; 03279 } 03280 } 03281 03282 if (args.options) { 03283 if (strchr(args.options, 'j')) 03284 priority_jump = 1; 03285 } 03286 03287 if (ast_strlen_zero(args.membername)) 03288 args.membername = args.interface; 03289 03290 03291 switch (add_to_queue(args.queuename, args.interface, args.membername, penalty, 0, queue_persistent_members)) { 03292 case RES_OKAY: 03293 ast_queue_log(args.queuename, chan->uniqueid, args.interface, "ADDMEMBER", "%s", ""); 03294 ast_log(LOG_NOTICE, "Added interface '%s' to queue '%s'\n", args.interface, args.queuename); 03295 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "ADDED"); 03296 res = 0; 03297 break; 03298 case RES_EXISTS: 03299 ast_log(LOG_WARNING, "Unable to add interface '%s' to queue '%s': Already there\n", args.interface, args.queuename); 03300 if (priority_jump || ast_opt_priority_jumping) 03301 ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101); 03302 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "MEMBERALREADY"); 03303 res = 0; 03304 break; 03305 case RES_NOSUCHQUEUE: 03306 ast_log(LOG_WARNING, "Unable to add interface to queue '%s': No such queue\n", args.queuename); 03307 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "NOSUCHQUEUE"); 03308 res = 0; 03309 break; 03310 case RES_OUTOFMEMORY: 03311 ast_log(LOG_ERROR, "Out of memory adding member %s to queue %s\n", args.interface, args.queuename); 03312 break; 03313 } 03314 03315 ast_module_user_remove(lu); 03316 03317 return res; 03318 }
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 2290 of file app_queue.c.
References ast_log(), ast_random(), member::calls, member::lastcall, LOG_WARNING, queue_ent::max_penalty, callattempt::metric, member::penalty, QUEUE_STRATEGY_FEWESTCALLS, QUEUE_STRATEGY_LEASTRECENT, QUEUE_STRATEGY_RANDOM, QUEUE_STRATEGY_RINGALL, QUEUE_STRATEGY_ROUNDROBIN, QUEUE_STRATEGY_RRMEMORY, call_queue::rrpos, call_queue::strategy, and call_queue::wrapped.
Referenced by try_calling().
02291 { 02292 if (qe->max_penalty && (mem->penalty > qe->max_penalty)) 02293 return -1; 02294 02295 switch (q->strategy) { 02296 case QUEUE_STRATEGY_RINGALL: 02297 /* Everyone equal, except for penalty */ 02298 tmp->metric = mem->penalty * 1000000; 02299 break; 02300 case QUEUE_STRATEGY_ROUNDROBIN: 02301 if (!pos) { 02302 if (!q->wrapped) { 02303 /* No more channels, start over */ 02304 q->rrpos = 0; 02305 } else { 02306 /* Prioritize next entry */ 02307 q->rrpos++; 02308 } 02309 q->wrapped = 0; 02310 } 02311 /* Fall through */ 02312 case QUEUE_STRATEGY_RRMEMORY: 02313 if (pos < q->rrpos) { 02314 tmp->metric = 1000 + pos; 02315 } else { 02316 if (pos > q->rrpos) 02317 /* Indicate there is another priority */ 02318 q->wrapped = 1; 02319 tmp->metric = pos; 02320 } 02321 tmp->metric += mem->penalty * 1000000; 02322 break; 02323 case QUEUE_STRATEGY_RANDOM: 02324 tmp->metric = ast_random() % 1000; 02325 tmp->metric += mem->penalty * 1000000; 02326 break; 02327 case QUEUE_STRATEGY_FEWESTCALLS: 02328 tmp->metric = mem->calls; 02329 tmp->metric += mem->penalty * 1000000; 02330 break; 02331 case QUEUE_STRATEGY_LEASTRECENT: 02332 if (!mem->lastcall) 02333 tmp->metric = 0; 02334 else 02335 tmp->metric = 1000000 - (time(NULL) - mem->lastcall); 02336 tmp->metric += mem->penalty * 1000000; 02337 break; 02338 default: 02339 ast_log(LOG_WARNING, "Can't calculate metric for unknown strategy %d\n", q->strategy); 02340 break; 02341 } 02342 return 0; 02343 }
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 1560 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().
01561 { 01562 struct call_queue *q; 01563 struct member *mem; 01564 int found = 0; 01565 01566 /* &qlock and &rq->lock already set by try_calling() 01567 * to solve deadlock */ 01568 AST_LIST_TRAVERSE(&queues, q, list) { 01569 if (q == rq) /* don't check myself, could deadlock */ 01570 continue; 01571 ast_mutex_lock(&q->lock); 01572 if (q->count && q->members) { 01573 for (mem = q->members; mem; mem = mem->next) { 01574 if (strcmp(mem->interface, member->interface)) 01575 continue; 01576 01577 ast_log(LOG_DEBUG, "Found matching member %s in queue '%s'\n", mem->interface, q->name); 01578 if (q->weight > rq->weight) { 01579 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); 01580 found = 1; 01581 break; 01582 } 01583 } 01584 } 01585 ast_mutex_unlock(&q->lock); 01586 if (found) 01587 break; 01588 } 01589 return found; 01590 }
static char* complete_queue | ( | const char * | line, | |
const char * | word, | |||
int | pos, | |||
int | state | |||
) | [static] |
Definition at line 4076 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().
04077 { 04078 struct call_queue *q; 04079 char *ret = NULL; 04080 int which = 0; 04081 int wordlen = strlen(word); 04082 04083 AST_LIST_LOCK(&queues); 04084 AST_LIST_TRAVERSE(&queues, q, list) { 04085 if (!strncasecmp(word, q->name, wordlen) && ++which > state) { 04086 ret = ast_strdup(q->name); 04087 break; 04088 } 04089 } 04090 AST_LIST_UNLOCK(&queues); 04091 04092 return ret; 04093 }
static char* complete_queue_add_member | ( | const char * | line, | |
const char * | word, | |||
int | pos, | |||
int | state | |||
) | [static] |
Definition at line 4368 of file app_queue.c.
References ast_malloc, ast_strdup, and complete_queue().
04369 { 04370 /* 0 - queue; 1 - add; 2 - member; 3 - <interface>; 4 - to; 5 - <queue>; 6 - penalty; 7 - <penalty>; 8 - as; 9 - <membername> */ 04371 switch (pos) { 04372 case 3: /* Don't attempt to complete name of interface (infinite possibilities) */ 04373 return NULL; 04374 case 4: /* only one possible match, "to" */ 04375 return state == 0 ? ast_strdup("to") : NULL; 04376 case 5: /* <queue> */ 04377 return complete_queue(line, word, pos, state); 04378 case 6: /* only one possible match, "penalty" */ 04379 return state == 0 ? ast_strdup("penalty") : NULL; 04380 case 7: 04381 if (state < 100) { /* 0-99 */ 04382 char *num; 04383 if ((num = ast_malloc(3))) { 04384 sprintf(num, "%d", state); 04385 } 04386 return num; 04387 } else { 04388 return NULL; 04389 } 04390 case 8: /* only one possible match, "as" */ 04391 return state == 0 ? ast_strdup("as") : NULL; 04392 case 9: /* Don't attempt to complete name of member (infinite possibilities) */ 04393 return NULL; 04394 default: 04395 return NULL; 04396 } 04397 }
static char* complete_queue_remove_member | ( | const char * | line, | |
const char * | word, | |||
int | pos, | |||
int | state | |||
) | [static] |
Definition at line 4431 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.
04432 { 04433 int which = 0; 04434 struct call_queue *q; 04435 struct member *m; 04436 04437 /* 0 - queue; 1 - remove; 2 - member; 3 - <member>; 4 - from; 5 - <queue> */ 04438 if (pos > 5 || pos < 3) 04439 return NULL; 04440 if (pos == 4) /* only one possible match, 'from' */ 04441 return state == 0 ? ast_strdup("from") : NULL; 04442 04443 if (pos == 5) /* No need to duplicate code */ 04444 return complete_queue(line, word, pos, state); 04445 04446 /* here is the case for 3, <member> */ 04447 if (!AST_LIST_EMPTY(&queues)) { /* XXX unnecessary ? the traverse does that for us */ 04448 AST_LIST_TRAVERSE(&queues, q, list) { 04449 ast_mutex_lock(&q->lock); 04450 for (m = q->members ; m ; m = m->next) { 04451 if (++which > state) { 04452 ast_mutex_unlock(&q->lock); 04453 return ast_strdup(m->interface); 04454 } 04455 } 04456 ast_mutex_unlock(&q->lock); 04457 } 04458 } 04459 04460 return NULL; 04461 }
static char* complete_queue_show | ( | const char * | line, | |
const char * | word, | |||
int | pos, | |||
int | state | |||
) | [static] |
Definition at line 4095 of file app_queue.c.
References complete_queue().
04096 { 04097 if (pos == 2) 04098 return complete_queue(line, word, pos, state); 04099 return NULL; 04100 }
static struct member* create_queue_member | ( | const char * | interface, | |
const char * | membername, | |||
int | penalty, | |||
int | paused | |||
) | [static, read] |
Definition at line 621 of file app_queue.c.
References ast_calloc, ast_device_state(), ast_log(), member::interface, LOG_WARNING, member::membername, member::paused, member::penalty, and member::status.
Referenced by add_to_queue(), reload_queues(), and rt_handle_member_record().
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(), leave_queue(), and reload_queues().
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 1593 of file app_queue.c.
References ast_hangup(), callattempt::chan, and callattempt::stillgoing.
Referenced by ring_entry(), and wait_for_answer().
01594 { 01595 o->stillgoing = 0; 01596 ast_hangup(o->chan); 01597 o->chan = NULL; 01598 }
static void dump_queue_members | ( | struct call_queue * | pm_queue | ) | [static] |
Definition at line 2795 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().
02796 { 02797 struct member *cur_member; 02798 char value[PM_MAX_LEN]; 02799 int value_len = 0; 02800 int res; 02801 02802 memset(value, 0, sizeof(value)); 02803 02804 if (!pm_queue) 02805 return; 02806 02807 for (cur_member = pm_queue->members; cur_member; cur_member = cur_member->next) { 02808 if (!cur_member->dynamic) 02809 continue; 02810 02811 res = snprintf(value + value_len, sizeof(value) - value_len, "%s;%d;%d;%s%s", 02812 cur_member->interface, cur_member->penalty, cur_member->paused, cur_member->membername, 02813 cur_member->next ? "|" : ""); 02814 if (res != strlen(value + value_len)) { 02815 ast_log(LOG_WARNING, "Could not create persistent member string, out of space\n"); 02816 break; 02817 } 02818 value_len += res; 02819 } 02820 02821 if (value_len && !cur_member) { 02822 if (ast_db_put(pm_family, pm_queue->name, value)) 02823 ast_log(LOG_WARNING, "failed to create persistent dynamic entry!\n"); 02824 } else 02825 /* Delete the entry if the queue is empty or there is an error */ 02826 ast_db_del(pm_family, pm_queue->name); 02827 }
static struct callattempt* find_best | ( | struct callattempt * | outgoing | ) | [static, read] |
find the entry with the best metric, or NULL
Definition at line 1756 of file app_queue.c.
References callattempt::metric, and callattempt::q_next.
01757 { 01758 struct callattempt *best = NULL, *cur; 01759 01760 for (cur = outgoing; cur; cur = cur->q_next) { 01761 if (cur->stillgoing && /* Not already done */ 01762 !cur->chan && /* Isn't already going */ 01763 (!best || cur->metric < best->metric)) { /* We haven't found one yet, or it's better */ 01764 best = cur; 01765 } 01766 } 01767 01768 return best; 01769 }
static struct call_queue* find_queue_by_name_rt | ( | const char * | queuename, | |
struct ast_variable * | queue_vars, | |||
struct ast_config * | member_config | |||
) | [static, read] |
Reload a single queue via realtime.
Definition at line 1003 of file app_queue.c.
References alloc_queue(), ast_category_browse(), AST_LIST_INSERT_HEAD, AST_LIST_REMOVE, AST_LIST_TRAVERSE, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_variable_retrieve(), clear_queue(), call_queue::count, member::dead, call_queue::dead, destroy_queue(), member::dynamic, free, init_queue(), member::interface, member_interface::interface, call_queue::lock, LOG_DEBUG, call_queue::membercount, call_queue::members, ast_variable::name, call_queue::name, member::next, ast_variable::next, queue_set_param(), QUEUE_STRATEGY_ROUNDROBIN, call_queue::realtime, remove_from_interfaces(), rr_dep_warning(), rt_handle_member_record(), S_OR, call_queue::strategy, 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, 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 4312 of file app_queue.c.
References add_to_queue(), ast_cli(), ast_queue_log(), member_interface::interface, member::membername, member::penalty, RES_EXISTS, RES_NOSUCHQUEUE, RES_OKAY, RES_OUTOFMEMORY, RESULT_FAILURE, RESULT_SHOWUSAGE, and RESULT_SUCCESS.
04313 { 04314 char *queuename, *interface, *membername; 04315 int penalty; 04316 04317 if ((argc != 6) && (argc != 8) && (argc != 10)) { 04318 return RESULT_SHOWUSAGE; 04319 } else if (strcmp(argv[4], "to")) { 04320 return RESULT_SHOWUSAGE; 04321 } else if ((argc == 8) && strcmp(argv[6], "penalty")) { 04322 return RESULT_SHOWUSAGE; 04323 } else if ((argc == 10) && strcmp(argv[8], "as")) { 04324 return RESULT_SHOWUSAGE; 04325 } 04326 04327 queuename = argv[5]; 04328 interface = argv[3]; 04329 if (argc >= 8) { 04330 if (sscanf(argv[7], "%d", &penalty) == 1) { 04331 if (penalty < 0) { 04332 ast_cli(fd, "Penalty must be >= 0\n"); 04333 penalty = 0; 04334 } 04335 } else { 04336 ast_cli(fd, "Penalty must be an integer >= 0\n"); 04337 penalty = 0; 04338 } 04339 } else { 04340 penalty = 0; 04341 } 04342 04343 if (argc >= 10) { 04344 membername = argv[9]; 04345 } else { 04346 membername = interface; 04347 } 04348 04349 switch (add_to_queue(queuename, interface, membername, penalty, 0, queue_persistent_members)) { 04350 case RES_OKAY: 04351 ast_queue_log(queuename, "CLI", interface, "ADDMEMBER", "%s", ""); 04352 ast_cli(fd, "Added interface '%s' to queue '%s'\n", interface, queuename); 04353 return RESULT_SUCCESS; 04354 case RES_EXISTS: 04355 ast_cli(fd, "Unable to add interface '%s' to queue '%s': Already there\n", interface, queuename); 04356 return RESULT_FAILURE; 04357 case RES_NOSUCHQUEUE: 04358 ast_cli(fd, "Unable to add interface to queue '%s': No such queue\n", queuename); 04359 return RESULT_FAILURE; 04360 case RES_OUTOFMEMORY: 04361 ast_cli(fd, "Out of memory\n"); 04362 return RESULT_FAILURE; 04363 default: 04364 return RESULT_FAILURE; 04365 } 04366 }
static int handle_queue_remove_member | ( | int | fd, | |
int | argc, | |||
char * | argv[] | |||
) | [static] |
Definition at line 4399 of file app_queue.c.
References ast_cli(), ast_queue_log(), member_interface::interface, remove_from_queue(), RES_EXISTS, RES_NOSUCHQUEUE, RES_OKAY, RES_OUTOFMEMORY, RESULT_FAILURE, RESULT_SHOWUSAGE, and RESULT_SUCCESS.
04400 { 04401 char *queuename, *interface; 04402 04403 if (argc != 6) { 04404 return RESULT_SHOWUSAGE; 04405 } else if (strcmp(argv[4], "from")) { 04406 return RESULT_SHOWUSAGE; 04407 } 04408 04409 queuename = argv[5]; 04410 interface = argv[3]; 04411 04412 switch (remove_from_queue(queuename, interface)) { 04413 case RES_OKAY: 04414 ast_queue_log(queuename, "CLI", interface, "REMOVEMEMBER", "%s", ""); 04415 ast_cli(fd, "Removed interface '%s' from queue '%s'\n", interface, queuename); 04416 return RESULT_SUCCESS; 04417 case RES_EXISTS: 04418 ast_cli(fd, "Unable to remove interface '%s' from queue '%s': Not there\n", interface, queuename); 04419 return RESULT_FAILURE; 04420 case RES_NOSUCHQUEUE: 04421 ast_cli(fd, "Unable to remove interface from queue '%s': No such queue\n", queuename); 04422 return RESULT_FAILURE; 04423 case RES_OUTOFMEMORY: 04424 ast_cli(fd, "Out of memory\n"); 04425 return RESULT_FAILURE; 04426 default: 04427 return RESULT_FAILURE; 04428 } 04429 }
static void hangupcalls | ( | struct callattempt * | outgoing, | |
struct ast_channel * | exception | |||
) | [static] |
Definition at line 1500 of file app_queue.c.
References ast_hangup(), callattempt::chan, free, and callattempt::q_next.
Referenced by try_calling().
01501 { 01502 struct callattempt *oo; 01503 01504 while (outgoing) { 01505 /* Hangup any existing lines we have open */ 01506 if (outgoing->chan && (outgoing->chan != exception)) 01507 ast_hangup(outgoing->chan); 01508 oo = outgoing; 01509 outgoing = outgoing->q_next; 01510 free(oo); 01511 } 01512 }
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 strategy::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, read] |
Definition at line 2774 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().
02775 { 02776 struct member *mem; 02777 02778 if (!q) 02779 return NULL; 02780 02781 for (mem = q->members; mem; mem = mem->next) { 02782 if (!strcasecmp(interface, mem->interface)) 02783 return mem; 02784 } 02785 02786 return NULL; 02787 }
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 2142 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().
02143 { 02144 struct queue_ent *ch; 02145 struct member *cur; 02146 int avl = 0; 02147 int idx = 0; 02148 int res; 02149 02150 if (!qe->parent->autofill) { 02151 /* Atomically read the parent head -- does not need a lock */ 02152 ch = qe->parent->head; 02153 /* If we are now at the top of the head, break out */ 02154 if (ch == qe) { 02155 if (option_debug) 02156 ast_log(LOG_DEBUG, "It's our turn (%s).\n", qe->chan->name); 02157 res = 1; 02158 } else { 02159 if (option_debug) 02160 ast_log(LOG_DEBUG, "It's not our turn (%s).\n", qe->chan->name); 02161 res = 0; 02162 } 02163 02164 } else { 02165 /* This needs a lock. How many members are available to be served? */ 02166 ast_mutex_lock(&qe->parent->lock); 02167 02168 ch = qe->parent->head; 02169 02170 if (qe->parent->strategy == QUEUE_STRATEGY_RINGALL) { 02171 if (option_debug) 02172 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); 02173 avl = 1; 02174 } else { 02175 for (cur = qe->parent->members; cur; cur = cur->next) { 02176 switch (cur->status) { 02177 case AST_DEVICE_NOT_INUSE: 02178 case AST_DEVICE_UNKNOWN: 02179 avl++; 02180 break; 02181 } 02182 } 02183 } 02184 02185 if (option_debug) 02186 ast_log(LOG_DEBUG, "There are %d available members.\n", avl); 02187 02188 while ((idx < avl) && (ch) && (ch != qe)) { 02189 idx++; 02190 ch = ch->next; 02191 } 02192 02193 /* If the queue entry is within avl [the number of available members] calls from the top ... */ 02194 if (ch && idx < avl) { 02195 if (option_debug) 02196 ast_log(LOG_DEBUG, "It's our turn (%s).\n", qe->chan->name); 02197 res = 1; 02198 } else { 02199 if (option_debug) 02200 ast_log(LOG_DEBUG, "It's not our turn (%s).\n", qe->chan->name); 02201 res = 0; 02202 } 02203 02204 ast_mutex_unlock(&qe->parent->lock); 02205 } 02206 02207 return res; 02208 }
static int join_queue | ( | char * | queuename, | |
struct queue_ent * | qe, | |||
enum queue_result * | reason | |||
) | [static] |
Definition at line 1221 of file app_queue.c.
References call_queue::announce, queue_ent::announce, AST_LIST_LOCK, AST_LIST_UNLOCK, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), queue_ent::chan, ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, call_queue::context, queue_ent::context, call_queue::count, EVENT_FLAG_CALL, get_member_status(), call_queue::head, insert_entry(), call_queue::joinempty, load_realtime_queue(), call_queue::lock, LOG_DEBUG, manager_event(), queue_ent::max_penalty, call_queue::maxlen, call_queue::moh, queue_ent::moh, call_queue::name, queue_ent::next, option_debug, queue_ent::pos, queue_ent::prio, QUEUE_EMPTY_STRICT, QUEUE_FULL, QUEUE_JOINEMPTY, QUEUE_JOINUNAVAIL, QUEUE_NO_MEMBERS, QUEUE_NO_REACHABLE_MEMBERS, and S_OR.
Referenced by queue_exec().
01222 { 01223 struct call_queue *q; 01224 struct queue_ent *cur, *prev = NULL; 01225 int res = -1; 01226 int pos = 0; 01227 int inserted = 0; 01228 enum queue_member_status stat; 01229 01230 if (!(q = load_realtime_queue(queuename))) 01231 return res; 01232 01233 AST_LIST_LOCK(&queues); 01234 ast_mutex_lock(&q->lock); 01235 01236 /* This is our one */ 01237 stat = get_member_status(q, qe->max_penalty); 01238 if (!q->joinempty && (stat == QUEUE_NO_MEMBERS)) 01239 *reason = QUEUE_JOINEMPTY; 01240 else if ((q->joinempty == QUEUE_EMPTY_STRICT) && (stat == QUEUE_NO_REACHABLE_MEMBERS)) 01241 *reason = QUEUE_JOINUNAVAIL; 01242 else if (q->maxlen && (q->count >= q->maxlen)) 01243 *reason = QUEUE_FULL; 01244 else { 01245 /* There's space for us, put us at the right position inside 01246 * the queue. 01247 * Take into account the priority of the calling user */ 01248 inserted = 0; 01249 prev = NULL; 01250 cur = q->head; 01251 while (cur) { 01252 /* We have higher priority than the current user, enter 01253 * before him, after all the other users with priority 01254 * higher or equal to our priority. */ 01255 if ((!inserted) && (qe->prio > cur->prio)) { 01256 insert_entry(q, prev, qe, &pos); 01257 inserted = 1; 01258 } 01259 cur->pos = ++pos; 01260 prev = cur; 01261 cur = cur->next; 01262 } 01263 /* No luck, join at the end of the queue */ 01264 if (!inserted) 01265 insert_entry(q, prev, qe, &pos); 01266 ast_copy_string(qe->moh, q->moh, sizeof(qe->moh)); 01267 ast_copy_string(qe->announce, q->announce, sizeof(qe->announce)); 01268 ast_copy_string(qe->context, q->context, sizeof(qe->context)); 01269 q->count++; 01270 res = 0; 01271 manager_event(EVENT_FLAG_CALL, "Join", 01272 "Channel: %s\r\nCallerID: %s\r\nCallerIDName: %s\r\nQueue: %s\r\nPosition: %d\r\nCount: %d\r\nUniqueid: %s\r\n", 01273 qe->chan->name, 01274 S_OR(qe->chan->cid.cid_num, "unknown"), /* XXX somewhere else it is <unknown> */ 01275 S_OR(qe->chan->cid.cid_name, "unknown"), 01276 q->name, qe->pos, q->count, qe->chan->uniqueid ); 01277 if (option_debug) 01278 ast_log(LOG_DEBUG, "Queue '%s' Join, Channel '%s', Position '%d'\n", q->name, qe->chan->name, qe->pos ); 01279 } 01280 ast_mutex_unlock(&q->lock); 01281 AST_LIST_UNLOCK(&queues); 01282 01283 return res; 01284 }
static void leave_queue | ( | struct queue_ent * | qe | ) | [static] |
Definition at line 1456 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().
01457 { 01458 struct call_queue *q; 01459 struct queue_ent *cur, *prev = NULL; 01460 int pos = 0; 01461 01462 if (!(q = qe->parent)) 01463 return; 01464 ast_mutex_lock(&q->lock); 01465 01466 prev = NULL; 01467 for (cur = q->head; cur; cur = cur->next) { 01468 if (cur == qe) { 01469 q->count--; 01470 01471 /* Take us out of the queue */ 01472 manager_event(EVENT_FLAG_CALL, "Leave", 01473 "Channel: %s\r\nQueue: %s\r\nCount: %d\r\nUniqueid: %s\r\n", 01474 qe->chan->name, q->name, q->count, qe->chan->uniqueid); 01475 if (option_debug) 01476 ast_log(LOG_DEBUG, "Queue '%s' Leave, Channel '%s'\n", q->name, qe->chan->name ); 01477 /* Take us out of the queue */ 01478 if (prev) 01479 prev->next = cur->next; 01480 else 01481 q->head = cur->next; 01482 } else { 01483 /* Renumber the people after us in the queue based on a new count */ 01484 cur->pos = ++pos; 01485 prev = cur; 01486 } 01487 } 01488 ast_mutex_unlock(&q->lock); 01489 01490 if (q->dead && !q->count) { 01491 /* It's dead and nobody is in it, so kill it */ 01492 AST_LIST_LOCK(&queues); 01493 AST_LIST_REMOVE(&queues, q, list); 01494 AST_LIST_UNLOCK(&queues); 01495 destroy_queue(q); 01496 } 01497 }
static int load_module | ( | void | ) | [static] |
Definition at line 4537 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().
04538 { 04539 int res; 04540 if(!reload_queues()) 04541 return AST_MODULE_LOAD_DECLINE; 04542 if (queue_persistent_members) 04543 reload_queue_members(); 04544 ast_cli_register_multiple(cli_queue, sizeof(cli_queue) / sizeof(struct ast_cli_entry)); 04545 res = ast_register_application(app, queue_exec, synopsis, descrip); 04546 res |= ast_register_application(app_aqm, aqm_exec, app_aqm_synopsis, app_aqm_descrip); 04547 res |= ast_register_application(app_rqm, rqm_exec, app_rqm_synopsis, app_rqm_descrip); 04548 res |= ast_register_application(app_pqm, pqm_exec, app_pqm_synopsis, app_pqm_descrip); 04549 res |= ast_register_application(app_upqm, upqm_exec, app_upqm_synopsis, app_upqm_descrip); 04550 res |= ast_register_application(app_ql, ql_exec, app_ql_synopsis, app_ql_descrip); 04551 res |= ast_manager_register("Queues", 0, manager_queues_show, "Queues"); 04552 res |= ast_manager_register("QueueStatus", 0, manager_queues_status, "Queue Status"); 04553 res |= ast_manager_register("QueueAdd", EVENT_FLAG_AGENT, manager_add_queue_member, "Add interface to queue."); 04554 res |= ast_manager_register("QueueRemove", EVENT_FLAG_AGENT, manager_remove_queue_member, "Remove interface from queue."); 04555 res |= ast_manager_register("QueuePause", EVENT_FLAG_AGENT, manager_pause_queue_member, "Makes a queue member temporarily unavailable"); 04556 res |= ast_custom_function_register(&queueagentcount_function); 04557 res |= ast_custom_function_register(&queuemembercount_function); 04558 res |= ast_custom_function_register(&queuememberlist_function); 04559 res |= ast_custom_function_register(&queuewaitingcount_function); 04560 res |= ast_devstate_add(statechange_queue, NULL); 04561 04562 return res; 04563 }
static struct call_queue* load_realtime_queue | ( | const char * | queuename | ) | [static, read] |
Definition at line 1123 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, and call_queue::realtime.
Referenced by __queues_show(), add_to_queue(), join_queue(), and reload_queue_members().
01124 { 01125 struct ast_variable *queue_vars; 01126 struct ast_config *member_config = NULL; 01127 struct call_queue *q; 01128 01129 /* Find the queue in the in-core list first. */ 01130 AST_LIST_LOCK(&queues); 01131 AST_LIST_TRAVERSE(&queues, q, list) { 01132 if (!strcasecmp(q->name, queuename)) { 01133 break; 01134 } 01135 } 01136 AST_LIST_UNLOCK(&queues); 01137 01138 if (!q || q->realtime) { 01139 /*! \note Load from realtime before taking the global qlock, to avoid blocking all 01140 queue operations while waiting for the DB. 01141 01142 This will be two separate database transactions, so we might 01143 see queue parameters as they were before another process 01144 changed the queue and member list as it was after the change. 01145 Thus we might see an empty member list when a queue is 01146 deleted. In practise, this is unlikely to cause a problem. */ 01147 01148 queue_vars = ast_load_realtime("queues", "name", queuename, NULL); 01149 if (queue_vars) { 01150 member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name", queuename, NULL); 01151 if (!member_config) { 01152 ast_log(LOG_ERROR, "no queue_members defined in your config (extconfig.conf).\n"); 01153 return NULL; 01154 } 01155 } 01156 01157 AST_LIST_LOCK(&queues); 01158 01159 q = find_queue_by_name_rt(queuename, queue_vars, member_config); 01160 if (member_config) 01161 ast_config_destroy(member_config); 01162 if (queue_vars) 01163 ast_variables_destroy(queue_vars); 01164 01165 AST_LIST_UNLOCK(&queues); 01166 } 01167 return q; 01168 }
static int manager_add_queue_member | ( | struct mansession * | s, | |
const struct message * | m | |||
) | [static] |
Definition at line 4205 of file app_queue.c.
References add_to_queue(), ast_queue_log(), ast_strlen_zero(), ast_true(), astman_get_header(), astman_send_ack(), astman_send_error(), member_interface::interface, member::membername, member::paused, member::penalty, RES_EXISTS, RES_NOSUCHQUEUE, RES_OKAY, and RES_OUTOFMEMORY.
Referenced by load_module().
04206 { 04207 const char *queuename, *interface, *penalty_s, *paused_s, *membername; 04208 int paused, penalty = 0; 04209 04210 queuename = astman_get_header(m, "Queue"); 04211 interface = astman_get_header(m, "Interface"); 04212 penalty_s = astman_get_header(m, "Penalty"); 04213 paused_s = astman_get_header(m, "Paused"); 04214 membername = astman_get_header(m, "MemberName"); 04215 04216 if (ast_strlen_zero(queuename)) { 04217 astman_send_error(s, m, "'Queue' not specified."); 04218 return 0; 04219 } 04220 04221 if (ast_strlen_zero(interface)) { 04222 astman_send_error(s, m, "'Interface' not specified."); 04223 return 0; 04224 } 04225 04226 if (ast_strlen_zero(penalty_s)) 04227 penalty = 0; 04228 else if (sscanf(penalty_s, "%d", &penalty) != 1) 04229 penalty = 0; 04230 04231 if (ast_strlen_zero(paused_s)) 04232 paused = 0; 04233 else 04234 paused = abs(ast_true(paused_s)); 04235 04236 if (ast_strlen_zero(membername)) 04237 membername = interface; 04238 04239 switch (add_to_queue(queuename, interface, membername, penalty, paused, queue_persistent_members)) { 04240 case RES_OKAY: 04241 ast_queue_log(queuename, "MANAGER", interface, "ADDMEMBER", "%s", ""); 04242 astman_send_ack(s, m, "Added interface to queue"); 04243 break; 04244 case RES_EXISTS: 04245 astman_send_error(s, m, "Unable to add interface: Already there"); 04246 break; 04247 case RES_NOSUCHQUEUE: 04248 astman_send_error(s, m, "Unable to add interface to queue: No such queue"); 04249 break; 04250 case RES_OUTOFMEMORY: 04251 astman_send_error(s, m, "Out of memory"); 04252 break; 04253 } 04254 04255 return 0; 04256 }
static int manager_pause_queue_member | ( | struct mansession * | s, | |
const struct message * | m | |||
) | [static] |
Definition at line 4289 of file app_queue.c.
References ast_strlen_zero(), ast_true(), astman_get_header(), astman_send_ack(), astman_send_error(), member_interface::interface, member::paused, and set_member_paused().
Referenced by load_module().
04290 { 04291 const char *queuename, *interface, *paused_s; 04292 int paused; 04293 04294 interface = astman_get_header(m, "Interface"); 04295 paused_s = astman_get_header(m, "Paused"); 04296 queuename = astman_get_header(m, "Queue"); /* Optional - if not supplied, pause the given Interface in all queues */ 04297 04298 if (ast_strlen_zero(interface) || ast_strlen_zero(paused_s)) { 04299 astman_send_error(s, m, "Need 'Interface' and 'Paused' parameters."); 04300 return 0; 04301 } 04302 04303 paused = abs(ast_true(paused_s)); 04304 04305 if (set_member_paused(queuename, interface, paused)) 04306 astman_send_error(s, m, "Interface not found"); 04307 else 04308 astman_send_ack(s, m, paused ? "Interface paused successfully" : "Interface unpaused successfully"); 04309 return 0; 04310 }
static int manager_queues_show | ( | struct mansession * | s, | |
const struct message * | m | |||
) | [static] |
Definition at line 4105 of file app_queue.c.
References __queues_show(), astman_append(), and RESULT_SUCCESS.
Referenced by load_module().
04106 { 04107 char *a[] = { "queue", "show" }; 04108 04109 __queues_show(s, 1, -1, 2, a); 04110 astman_append(s, "\r\n\r\n"); /* Properly terminate Manager output */ 04111 04112 return RESULT_SUCCESS; 04113 }
static int manager_queues_status | ( | struct mansession * | s, | |
const struct message * | m | |||
) | [static] |
Definition at line 4116 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_OR, call_queue::servicelevel, queue_ent::start, member::status, and call_queue::weight.
Referenced by load_module().
04117 { 04118 time_t now; 04119 int pos; 04120 const char *id = astman_get_header(m,"ActionID"); 04121 const char *queuefilter = astman_get_header(m,"Queue"); 04122 const char *memberfilter = astman_get_header(m,"Member"); 04123 char idText[256] = ""; 04124 struct call_queue *q; 04125 struct queue_ent *qe; 04126 float sl = 0; 04127 struct member *mem; 04128 04129 astman_send_ack(s, m, "Queue status will follow"); 04130 time(&now); 04131 AST_LIST_LOCK(&queues); 04132 if (!ast_strlen_zero(id)) 04133 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id); 04134 04135 AST_LIST_TRAVERSE(&queues, q, list) { 04136 ast_mutex_lock(&q->lock); 04137 04138 /* List queue properties */ 04139 if (ast_strlen_zero(queuefilter) || !strcmp(q->name, queuefilter)) { 04140 sl = ((q->callscompleted > 0) ? 100 * ((float)q->callscompletedinsl / (float)q->callscompleted) : 0); 04141 astman_append(s, "Event: QueueParams\r\n" 04142 "Queue: %s\r\n" 04143 "Max: %d\r\n" 04144 "Calls: %d\r\n" 04145 "Holdtime: %d\r\n" 04146 "Completed: %d\r\n" 04147 "Abandoned: %d\r\n" 04148 "ServiceLevel: %d\r\n" 04149 "ServicelevelPerf: %2.1f\r\n" 04150 "Weight: %d\r\n" 04151 "%s" 04152 "\r\n", 04153 q->name, q->maxlen, q->count, q->holdtime, q->callscompleted, 04154 q->callsabandoned, q->servicelevel, sl, q->weight, idText); 04155 /* List Queue Members */ 04156 for (mem = q->members; mem; mem = mem->next) { 04157 if (ast_strlen_zero(memberfilter) || !strcmp(mem->interface, memberfilter)) { 04158 astman_append(s, "Event: QueueMember\r\n" 04159 "Queue: %s\r\n" 04160 "Location: %s\r\n" 04161 "Membership: %s\r\n" 04162 "Penalty: %d\r\n" 04163 "CallsTaken: %d\r\n" 04164 "LastCall: %d\r\n" 04165 "Status: %d\r\n" 04166 "Paused: %d\r\n" 04167 "%s" 04168 "\r\n", 04169 q->name, mem->interface, mem->dynamic ? "dynamic" : "static", 04170 mem->penalty, mem->calls, (int)mem->lastcall, mem->status, mem->paused, idText); 04171 } 04172 } 04173 /* List Queue Entries */ 04174 pos = 1; 04175 for (qe = q->head; qe; qe = qe->next) { 04176 astman_append(s, "Event: QueueEntry\r\n" 04177 "Queue: %s\r\n" 04178 "Position: %d\r\n" 04179 "Channel: %s\r\n" 04180 "CallerID: %s\r\n" 04181 "CallerIDName: %s\r\n" 04182 "Wait: %ld\r\n" 04183 "%s" 04184 "\r\n", 04185 q->name, pos++, qe->chan->name, 04186 S_OR(qe->chan->cid.cid_num, "unknown"), 04187 S_OR(qe->chan->cid.cid_name, "unknown"), 04188 (long) (now - qe->start), idText); 04189 } 04190 } 04191 ast_mutex_unlock(&q->lock); 04192 } 04193 04194 astman_append(s, 04195 "Event: QueueStatusComplete\r\n" 04196 "%s" 04197 "\r\n",idText); 04198 04199 AST_LIST_UNLOCK(&queues); 04200 04201 04202 return RESULT_SUCCESS; 04203 }
static int manager_remove_queue_member | ( | struct mansession * | s, | |
const struct message * | m | |||
) | [static] |
Definition at line 4258 of file app_queue.c.
References ast_queue_log(), ast_strlen_zero(), astman_get_header(), astman_send_ack(), astman_send_error(), member_interface::interface, remove_from_queue(), RES_EXISTS, RES_NOSUCHQUEUE, RES_OKAY, and RES_OUTOFMEMORY.
Referenced by load_module().
04259 { 04260 const char *queuename, *interface; 04261 04262 queuename = astman_get_header(m, "Queue"); 04263 interface = astman_get_header(m, "Interface"); 04264 04265 if (ast_strlen_zero(queuename) || ast_strlen_zero(interface)) { 04266 astman_send_error(s, m, "Need 'Queue' and 'Interface' parameters."); 04267 return 0; 04268 } 04269 04270 switch (remove_from_queue(queuename, interface)) { 04271 case RES_OKAY: 04272 ast_queue_log(queuename, "MANAGER", interface, "REMOVEMEMBER", "%s", ""); 04273 astman_send_ack(s, m, "Removed interface from queue"); 04274 break; 04275 case RES_EXISTS: 04276 astman_send_error(s, m, "Unable to remove interface: Not there"); 04277 break; 04278 case RES_NOSUCHQUEUE: 04279 astman_send_error(s, m, "Unable to remove interface from queue: No such queue"); 04280 break; 04281 case RES_OUTOFMEMORY: 04282 astman_send_error(s, m, "Out of memory"); 04283 break; 04284 } 04285 04286 return 0; 04287 }
static int play_file | ( | struct ast_channel * | chan, | |
char * | filename | |||
) | [static] |
Definition at line 1286 of file app_queue.c.
References AST_DIGIT_ANY, ast_stopstream(), ast_streamfile(), and ast_waitstream().
Referenced by say_periodic_announcement(), say_position(), and try_calling().
01287 { 01288 int res; 01289 01290 ast_stopstream(chan); 01291 01292 res = ast_streamfile(chan, filename, chan->language); 01293 if (!res) 01294 res = ast_waitstream(chan, AST_DIGIT_ANY); 01295 01296 ast_stopstream(chan); 01297 01298 return res; 01299 }
static int pqm_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Definition at line 3074 of file app_queue.c.
References AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_goto_if_exists(), ast_log(), ast_module_user_add, ast_module_user_remove, ast_opt_priority_jumping, AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), ast_channel::context, ast_channel::exten, member_interface::interface, LOG_WARNING, parse(), pbx_builtin_setvar_helper(), ast_channel::priority, and set_member_paused().
Referenced by load_module().
03075 { 03076 struct ast_module_user *lu; 03077 char *parse; 03078 int priority_jump = 0; 03079 AST_DECLARE_APP_ARGS(args, 03080 AST_APP_ARG(queuename); 03081 AST_APP_ARG(interface); 03082 AST_APP_ARG(options); 03083 ); 03084 03085 if (ast_strlen_zero(data)) { 03086 ast_log(LOG_WARNING, "PauseQueueMember requires an argument ([queuename]|interface[|options])\n"); 03087 return -1; 03088 } 03089 03090 parse = ast_strdupa(data); 03091 03092 AST_STANDARD_APP_ARGS(args, parse); 03093 03094 lu = ast_module_user_add(chan); 03095 03096 if (args.options) { 03097 if (strchr(args.options, 'j')) 03098 priority_jump = 1; 03099 } 03100 03101 if (ast_strlen_zero(args.interface)) { 03102 ast_log(LOG_WARNING, "Missing interface argument to PauseQueueMember ([queuename]|interface[|options])\n"); 03103 ast_module_user_remove(lu); 03104 return -1; 03105 } 03106 03107 if (set_member_paused(args.queuename, args.interface, 1)) { 03108 ast_log(LOG_WARNING, "Attempt to pause interface %s, not found\n", args.interface); 03109 if (priority_jump || ast_opt_priority_jumping) { 03110 if (ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101)) { 03111 pbx_builtin_setvar_helper(chan, "PQMSTATUS", "NOTFOUND"); 03112 ast_module_user_remove(lu); 03113 return 0; 03114 } 03115 } 03116 ast_module_user_remove(lu); 03117 pbx_builtin_setvar_helper(chan, "PQMSTATUS", "NOTFOUND"); 03118 return -1; 03119 } 03120 03121 ast_module_user_remove(lu); 03122 pbx_builtin_setvar_helper(chan, "PQMSTATUS", "PAUSED"); 03123 03124 return 0; 03125 }
static int ql_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Definition at line 3320 of file app_queue.c.
References AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_log(), ast_module_user_add, ast_module_user_remove, ast_queue_log(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), event, LOG_WARNING, and parse().
Referenced by load_module().
03321 { 03322 struct ast_module_user *u; 03323 char *parse; 03324 03325 AST_DECLARE_APP_ARGS(args, 03326 AST_APP_ARG(queuename); 03327 AST_APP_ARG(uniqueid); 03328 AST_APP_ARG(membername); 03329 AST_APP_ARG(event); 03330 AST_APP_ARG(params); 03331 ); 03332 03333 if (ast_strlen_zero(data)) { 03334 ast_log(LOG_WARNING, "QueueLog requires arguments (queuename|uniqueid|membername|event[|additionalinfo]\n"); 03335 return -1; 03336 } 03337 03338 u = ast_module_user_add(chan); 03339 03340 parse = ast_strdupa(data); 03341 03342 AST_STANDARD_APP_ARGS(args, parse); 03343 03344 if (ast_strlen_zero(args.queuename) || ast_strlen_zero(args.uniqueid) 03345 || ast_strlen_zero(args.membername) || ast_strlen_zero(args.event)) { 03346 ast_log(LOG_WARNING, "QueueLog requires arguments (queuename|uniqueid|membername|event[|additionalinfo])\n"); 03347 ast_module_user_remove(u); 03348 return -1; 03349 } 03350 03351 ast_queue_log(args.queuename, args.uniqueid, args.membername, args.event, 03352 "%s", args.params ? args.params : ""); 03353 03354 ast_module_user_remove(u); 03355 03356 return 0; 03357 }
static int queue_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Definition at line 3359 of file app_queue.c.
References call_queue::announcefrequency, AST_APP_ARG, AST_CONTROL_RINGING, AST_DECLARE_APP_ARGS, ast_indicate(), ast_log(), ast_module_user_add, ast_module_user_remove, ast_moh_start(), ast_moh_stop(), AST_PBX_KEEPALIVE, ast_queue_log(), AST_STANDARD_APP_ARGS, ast_stopstream(), ast_strdupa, ast_strlen_zero(), ast_verbose(), queue_ent::chan, ast_channel::cid, ast_callerid::cid_num, queue_ent::digits, queue_ent::expire, get_member_status(), queue_ent::handled, is_our_turn(), join_queue(), queue_ent::last_periodic_announce_sound, queue_ent::last_periodic_announce_time, queue_ent::last_pos, queue_ent::last_pos_said, leave_queue(), call_queue::leavewhenempty, LOG_DEBUG, LOG_WARNING, queue_ent::max_penalty, call_queue::membercount, queue_ent::moh, queue_ent::opos, option_debug, option_verbose, queue_ent::parent, parse(), pbx_builtin_getvar_helper(), call_queue::periodicannouncefrequency, queue_ent::pos, queue_ent::prio, QUEUE_EMPTY_STRICT, QUEUE_LEAVEEMPTY, QUEUE_LEAVEUNAVAIL, QUEUE_NO_MEMBERS, QUEUE_NO_REACHABLE_MEMBERS, QUEUE_TIMEOUT, QUEUE_UNKNOWN, record_abandoned(), S_OR, say_periodic_announcement(), say_position(), set_queue_result(), queue_ent::start, try_calling(), update_realtime_members(), queue_ent::valid_digits, VERBOSE_PREFIX_3, wait_a_bit(), and wait_our_turn().
Referenced by load_module().
03360 { 03361 int res=-1; 03362 int ringing=0; 03363 struct ast_module_user *lu; 03364 const char *user_priority; 03365 const char *max_penalty_str; 03366 int prio; 03367 int max_penalty; 03368 enum queue_result reason = QUEUE_UNKNOWN; 03369 /* whether to exit Queue application after the timeout hits */ 03370 int go_on = 0; 03371 char *parse; 03372 AST_DECLARE_APP_ARGS(args, 03373 AST_APP_ARG(queuename); 03374 AST_APP_ARG(options); 03375 AST_APP_ARG(url); 03376 AST_APP_ARG(announceoverride); 03377 AST_APP_ARG(queuetimeoutstr); 03378 AST_APP_ARG(agi); 03379 ); 03380 /* Our queue entry */ 03381 struct queue_ent qe; 03382 03383 if (ast_strlen_zero(data)) { 03384 ast_log(LOG_WARNING, "Queue requires an argument: queuename[|options[|URL[|announceoverride[|timeout[|agi]]]]]\n"); 03385 return -1; 03386 } 03387 03388 parse = ast_strdupa(data); 03389 AST_STANDARD_APP_ARGS(args, parse); 03390 03391 lu = ast_module_user_add(chan); 03392 03393 /* Setup our queue entry */ 03394 memset(&qe, 0, sizeof(qe)); 03395 qe.start = time(NULL); 03396 03397 /* set the expire time based on the supplied timeout; */ 03398 if (args.queuetimeoutstr) 03399 qe.expire = qe.start + atoi(args.queuetimeoutstr); 03400 else 03401 qe.expire = 0; 03402 03403 /* Get the priority from the variable ${QUEUE_PRIO} */ 03404 user_priority = pbx_builtin_getvar_helper(chan, "QUEUE_PRIO"); 03405 if (user_priority) { 03406 if (sscanf(user_priority, "%d", &prio) == 1) { 03407 if (option_debug) 03408 ast_log(LOG_DEBUG, "%s: Got priority %d from ${QUEUE_PRIO}.\n", 03409 chan->name, prio); 03410 } else { 03411 ast_log(LOG_WARNING, "${QUEUE_PRIO}: Invalid value (%s), channel %s.\n", 03412 user_priority, chan->name); 03413 prio = 0; 03414 } 03415 } else { 03416 if (option_debug > 2) 03417 ast_log(LOG_DEBUG, "NO QUEUE_PRIO variable found. Using default.\n"); 03418 prio = 0; 03419 } 03420 03421 /* Get the maximum penalty from the variable ${QUEUE_MAX_PENALTY} */ 03422 if ((max_penalty_str = pbx_builtin_getvar_helper(chan, "QUEUE_MAX_PENALTY"))) { 03423 if (sscanf(max_penalty_str, "%d", &max_penalty) == 1) { 03424 if (option_debug) 03425 ast_log(LOG_DEBUG, "%s: Got max penalty %d from ${QUEUE_MAX_PENALTY}.\n", 03426 chan->name, max_penalty); 03427 } else { 03428 ast_log(LOG_WARNING, "${QUEUE_MAX_PENALTY}: Invalid value (%s), channel %s.\n", 03429 max_penalty_str, chan->name); 03430 max_penalty = 0; 03431 } 03432 } else { 03433 max_penalty = 0; 03434 } 03435 03436 if (args.options && (strchr(args.options, 'r'))) 03437 ringing = 1; 03438 03439 if (option_debug) 03440 ast_log(LOG_DEBUG, "queue: %s, options: %s, url: %s, announce: %s, expires: %ld, priority: %d\n", 03441 args.queuename, args.options, args.url, args.announceoverride, (long)qe.expire, prio); 03442 03443 qe.chan = chan; 03444 qe.prio = prio; 03445 qe.max_penalty = max_penalty; 03446 qe.last_pos_said = 0; 03447 qe.last_pos = 0; 03448 qe.last_periodic_announce_time = time(NULL); 03449 qe.last_periodic_announce_sound = 0; 03450 qe.valid_digits = 0; 03451 if (!join_queue(args.queuename, &qe, &reason)) { 03452 int makeannouncement = 0; 03453 03454 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "ENTERQUEUE", "%s|%s", S_OR(args.url, ""), 03455 S_OR(chan->cid.cid_num, "")); 03456 check_turns: 03457 if (ringing) { 03458 ast_indicate(chan, AST_CONTROL_RINGING); 03459 } else { 03460 ast_moh_start(chan, qe.moh, NULL); 03461 } 03462 03463 /* This is the wait loop for callers 2 through maxlen */ 03464 res = wait_our_turn(&qe, ringing, &reason); 03465 if (res) 03466 goto stop; 03467 03468 for (;;) { 03469 /* This is the wait loop for the head caller*/ 03470 /* To exit, they may get their call answered; */ 03471 /* they may dial a digit from the queue context; */ 03472 /* or, they may timeout. */ 03473 03474 enum queue_member_status stat; 03475 03476 /* Leave if we have exceeded our queuetimeout */ 03477 if (qe.expire && (time(NULL) > qe.expire)) { 03478 record_abandoned(&qe); 03479 reason = QUEUE_TIMEOUT; 03480 res = 0; 03481 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHTIMEOUT", "%d", qe.pos); 03482 break; 03483 } 03484 03485 if (makeannouncement) { 03486 /* Make a position announcement, if enabled */ 03487 if (qe.parent->announcefrequency && !ringing) 03488 if ((res = say_position(&qe))) 03489 goto stop; 03490 03491 } 03492 makeannouncement = 1; 03493 03494 /* Make a periodic announcement, if enabled */ 03495 if (qe.parent->periodicannouncefrequency && !ringing) 03496 if ((res = say_periodic_announcement(&qe))) 03497 goto stop; 03498 03499 /* Try calling all queue members for 'timeout' seconds */ 03500 res = try_calling(&qe, args.options, args.announceoverride, args.url, &go_on, args.agi); 03501 if (res) 03502 goto stop; 03503 03504 stat = get_member_status(qe.parent, qe.max_penalty); 03505 03506 /* exit after 'timeout' cycle if 'n' option enabled */ 03507 if (go_on >= qe.parent->membercount) { 03508 if (option_verbose > 2) 03509 ast_verbose(VERBOSE_PREFIX_3 "Exiting on time-out cycle\n"); 03510 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHTIMEOUT", "%d", qe.pos); 03511 record_abandoned(&qe); 03512 reason = QUEUE_TIMEOUT; 03513 res = 0; 03514 break; 03515 } 03516 03517 /* leave the queue if no agents, if enabled */ 03518 if (qe.parent->leavewhenempty && (stat == QUEUE_NO_MEMBERS)) { 03519 record_abandoned(&qe); 03520 reason = QUEUE_LEAVEEMPTY; 03521 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe.pos, qe.opos, (long)(time(NULL) - qe.start)); 03522 res = 0; 03523 break; 03524 } 03525 03526 /* leave the queue if no reachable agents, if enabled */ 03527 if ((qe.parent->leavewhenempty == QUEUE_EMPTY_STRICT) && (stat == QUEUE_NO_REACHABLE_MEMBERS)) { 03528 record_abandoned(&qe); 03529 reason = QUEUE_LEAVEUNAVAIL; 03530 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe.pos, qe.opos, (long)(time(NULL) - qe.start)); 03531 res = 0; 03532 break; 03533 } 03534 03535 /* Leave if we have exceeded our queuetimeout */ 03536 if (qe.expire && (time(NULL) > qe.expire)) { 03537 record_abandoned(&qe); 03538 reason = QUEUE_TIMEOUT; 03539 res = 0; 03540 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHTIMEOUT", "%d", qe.pos); 03541 break; 03542 } 03543 03544 /* If using dynamic realtime members, we should regenerate the member list for this queue */ 03545 update_realtime_members(qe.parent); 03546 03547 /* OK, we didn't get anybody; wait for 'retry' seconds; may get a digit to exit with */ 03548 res = wait_a_bit(&qe); 03549 if (res) 03550 goto stop; 03551 03552 03553 /* Since this is a priority queue and 03554 * it is not sure that we are still at the head 03555 * of the queue, go and check for our turn again. 03556 */ 03557 if (!is_our_turn(&qe)) { 03558 if (option_debug) 03559 ast_log(LOG_DEBUG, "Darn priorities, going back in queue (%s)!\n", 03560 qe.chan->name); 03561 goto check_turns; 03562 } 03563 } 03564 03565 stop: 03566 if (res) { 03567 if (res < 0) { 03568 if (!qe.handled) { 03569 record_abandoned(&qe); 03570 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "ABANDON", 03571 "%d|%d|%ld", qe.pos, qe.opos, 03572 (long) time(NULL) - qe.start); 03573 } 03574 res = -1; 03575 } else if (qe.valid_digits) { 03576 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHKEY", 03577 "%s|%d", qe.digits, qe.pos); 03578 } 03579 } 03580 03581 /* Don't allow return code > 0 */ 03582 if (res >= 0 && res != AST_PBX_KEEPALIVE) { 03583 res = 0; 03584 if (ringing) { 03585 ast_indicate(chan, -1); 03586 } else { 03587 ast_moh_stop(chan); 03588 } 03589 ast_stopstream(chan); 03590 } 03591 leave_queue(&qe); 03592 if (reason != QUEUE_UNKNOWN) 03593 set_queue_result(chan, reason); 03594 } else { 03595 ast_log(LOG_WARNING, "Unable to join queue '%s'\n", args.queuename); 03596 set_queue_result(chan, reason); 03597 res = 0; 03598 } 03599 ast_module_user_remove(lu); 03600 03601 return res; 03602 }
static int queue_function_qac | ( | struct ast_channel * | chan, | |
char * | cmd, | |||
char * | data, | |||
char * | buf, | |||
size_t | len | |||
) | [static] |
Definition at line 3604 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(), call_queue::lock, LOG_ERROR, LOG_WARNING, call_queue::membercount, and call_queue::name.
03605 { 03606 int count = 0; 03607 struct call_queue *q; 03608 struct ast_module_user *lu; 03609 03610 buf[0] = '\0'; 03611 03612 if (ast_strlen_zero(data)) { 03613 ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd); 03614 return -1; 03615 } 03616 03617 lu = ast_module_user_add(chan); 03618 03619 AST_LIST_LOCK(&queues); 03620 AST_LIST_TRAVERSE(&queues, q, list) { 03621 if (!strcasecmp(q->name, data)) { 03622 ast_mutex_lock(&q->lock); 03623 break; 03624 } 03625 } 03626 AST_LIST_UNLOCK(&queues); 03627 03628 if (q) { 03629 count = q->membercount; 03630 ast_mutex_unlock(&q->lock); 03631 } else 03632 ast_log(LOG_WARNING, "queue %s was not found\n", data); 03633 03634 snprintf(buf, len, "%d", count); 03635 ast_module_user_remove(lu); 03636 03637 return 0; 03638 }
static int queue_function_queuememberlist | ( | struct ast_channel * | chan, | |
char * | cmd, | |||
char * | data, | |||
char * | buf, | |||
size_t | len | |||
) | [static] |
Definition at line 3675 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.
03676 { 03677 struct ast_module_user *u; 03678 struct call_queue *q; 03679 struct member *m; 03680 03681 /* Ensure an otherwise empty list doesn't return garbage */ 03682 buf[0] = '\0'; 03683 03684 if (ast_strlen_zero(data)) { 03685 ast_log(LOG_ERROR, "QUEUE_MEMBER_LIST requires an argument: queuename\n"); 03686 return -1; 03687 } 03688 03689 u = ast_module_user_add(chan); 03690 03691 AST_LIST_LOCK(&queues); 03692 AST_LIST_TRAVERSE(&queues, q, list) { 03693 if (!strcasecmp(q->name, data)) { 03694 ast_mutex_lock(&q->lock); 03695 break; 03696 } 03697 } 03698 AST_LIST_UNLOCK(&queues); 03699 03700 if (q) { 03701 int buflen = 0, count = 0; 03702 03703 for (m = q->members; m; m = m->next) { 03704 /* strcat() is always faster than printf() */ 03705 if (count++) { 03706 strncat(buf + buflen, ",", len - buflen - 1); 03707 buflen++; 03708 } 03709 strncat(buf + buflen, m->interface, len - buflen - 1); 03710 buflen += strlen(m->interface); 03711 /* Safeguard against overflow (negative length) */ 03712 if (buflen >= len - 2) { 03713 ast_log(LOG_WARNING, "Truncating list\n"); 03714 break; 03715 } 03716 } 03717 ast_mutex_unlock(&q->lock); 03718 } else 03719 ast_log(LOG_WARNING, "queue %s was not found\n", data); 03720 03721 /* We should already be terminated, but let's make sure. */ 03722 buf[len - 1] = '\0'; 03723 ast_module_user_remove(u); 03724 03725 return 0; 03726 }
static int queue_function_queuewaitingcount | ( | struct ast_channel * | chan, | |
char * | cmd, | |||
char * | data, | |||
char * | buf, | |||
size_t | len | |||
) | [static] |
Definition at line 3640 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(), call_queue::count, call_queue::lock, LOG_ERROR, LOG_WARNING, and call_queue::name.
03641 { 03642 int count = 0; 03643 struct call_queue *q; 03644 struct ast_module_user *lu; 03645 03646 buf[0] = '\0'; 03647 03648 if (ast_strlen_zero(data)) { 03649 ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd); 03650 return -1; 03651 } 03652 03653 lu = ast_module_user_add(chan); 03654 03655 AST_LIST_LOCK(&queues); 03656 AST_LIST_TRAVERSE(&queues, q, list) { 03657 if (!strcasecmp(q->name, data)) { 03658 ast_mutex_lock(&q->lock); 03659 break; 03660 } 03661 } 03662 AST_LIST_UNLOCK(&queues); 03663 03664 if (q) { 03665 count = q->count; 03666 ast_mutex_unlock(&q->lock); 03667 } else 03668 ast_log(LOG_WARNING, "queue %s was not found\n", data); 03669 03670 snprintf(buf, len, "%d", count); 03671 ast_module_user_remove(lu); 03672 return 0; 03673 }
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 4071 of file app_queue.c.
References __queues_show().
Referenced by __queues_show().
04072 { 04073 return __queues_show(NULL, 0, fd, argc, argv); 04074 }
static void recalc_holdtime | ( | struct queue_ent * | qe, | |
int | newholdtime | |||
) | [static] |
Definition at line 1441 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().
01442 { 01443 int oldvalue; 01444 01445 /* Calculate holdtime using a recursive boxcar filter */ 01446 /* Thanks to SRT for this contribution */ 01447 /* 2^2 (4) is the filter coefficient; a higher exponent would give old entries more weight */ 01448 01449 ast_mutex_lock(&qe->parent->lock); 01450 oldvalue = qe->parent->holdtime; 01451 qe->parent->holdtime = (((oldvalue << 2) - oldvalue) + newholdtime) >> 2; 01452 ast_mutex_unlock(&qe->parent->lock); 01453 }
static void record_abandoned | ( | struct queue_ent * | qe | ) | [static] |
Definition at line 1871 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().
01872 { 01873 ast_mutex_lock(&qe->parent->lock); 01874 manager_event(EVENT_FLAG_AGENT, "QueueCallerAbandon", 01875 "Queue: %s\r\n" 01876 "Uniqueid: %s\r\n" 01877 "Position: %d\r\n" 01878 "OriginalPosition: %d\r\n" 01879 "HoldTime: %d\r\n", 01880 qe->parent->name, qe->chan->uniqueid, qe->pos, qe->opos, (int)(time(NULL) - qe->start)); 01881 01882 qe->parent->callsabandoned++; 01883 ast_mutex_unlock(&qe->parent->lock); 01884 }
static int reload | ( | void | ) | [static] |
Definition at line 4565 of file app_queue.c.
References reload_queues().
04566 { 04567 reload_queues(); 04568 return 0; 04569 }
static void reload_queue_members | ( | void | ) | [static] |
Definition at line 2979 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::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().
02980 { 02981 char *cur_ptr; 02982 char *queue_name; 02983 char *member; 02984 char *interface; 02985 char *membername; 02986 char *penalty_tok; 02987 int penalty = 0; 02988 char *paused_tok; 02989 int paused = 0; 02990 struct ast_db_entry *db_tree; 02991 struct ast_db_entry *entry; 02992 struct call_queue *cur_queue; 02993 char queue_data[PM_MAX_LEN]; 02994 02995 AST_LIST_LOCK(&queues); 02996 02997 /* Each key in 'pm_family' is the name of a queue */ 02998 db_tree = ast_db_gettree(pm_family, NULL); 02999 for (entry = db_tree; entry; entry = entry->next) { 03000 03001 queue_name = entry->key + strlen(pm_family) + 2; 03002 03003 AST_LIST_TRAVERSE(&queues, cur_queue, list) { 03004 ast_mutex_lock(&cur_queue->lock); 03005 if (!strcmp(queue_name, cur_queue->name)) 03006 break; 03007 ast_mutex_unlock(&cur_queue->lock); 03008 } 03009 03010 if (!cur_queue) 03011 cur_queue = load_realtime_queue(queue_name); 03012 03013 if (!cur_queue) { 03014 /* If the queue no longer exists, remove it from the 03015 * database */ 03016 ast_log(LOG_WARNING, "Error loading persistent queue: '%s': it does not exist\n", queue_name); 03017 ast_db_del(pm_family, queue_name); 03018 continue; 03019 } else 03020 ast_mutex_unlock(&cur_queue->lock); 03021 03022 if (ast_db_get(pm_family, queue_name, queue_data, PM_MAX_LEN)) 03023 continue; 03024 03025 cur_ptr = queue_data; 03026 while ((member = strsep(&cur_ptr, "|"))) { 03027 if (ast_strlen_zero(member)) 03028 continue; 03029 03030 interface = strsep(&member, ";"); 03031 penalty_tok = strsep(&member, ";"); 03032 paused_tok = strsep(&member, ";"); 03033 membername = strsep(&member, ";"); 03034 03035 if (!penalty_tok) { 03036 ast_log(LOG_WARNING, "Error parsing persistent member string for '%s' (penalty)\n", queue_name); 03037 break; 03038 } 03039 penalty = strtol(penalty_tok, NULL, 10); 03040 if (errno == ERANGE) { 03041 ast_log(LOG_WARNING, "Error converting penalty: %s: Out of range.\n", penalty_tok); 03042 break; 03043 } 03044 03045 if (!paused_tok) { 03046 ast_log(LOG_WARNING, "Error parsing persistent member string for '%s' (paused)\n", queue_name); 03047 break; 03048 } 03049 paused = strtol(paused_tok, NULL, 10); 03050 if ((errno == ERANGE) || paused < 0 || paused > 1) { 03051 ast_log(LOG_WARNING, "Error converting paused: %s: Expected 0 or 1.\n", paused_tok); 03052 break; 03053 } 03054 if (ast_strlen_zero(membername)) 03055 membername = interface; 03056 03057 if (option_debug) 03058 ast_log(LOG_DEBUG, "Reload Members: Queue: %s Member: %s Name: %s Penalty: %d Paused: %d\n", queue_name, interface, membername, penalty, paused); 03059 03060 if (add_to_queue(queue_name, interface, membername, penalty, paused, 0) == RES_OUTOFMEMORY) { 03061 ast_log(LOG_ERROR, "Out of Memory when reloading persistent queue member\n"); 03062 break; 03063 } 03064 } 03065 } 03066 03067 AST_LIST_UNLOCK(&queues); 03068 if (db_tree) { 03069 ast_log(LOG_NOTICE, "Queue members successfully reloaded from database.\n"); 03070 ast_db_freetree(db_tree); 03071 } 03072 }
static int reload_queues | ( | void | ) | [static] |
Definition at line 3765 of file app_queue.c.
References add_to_interfaces(), alloc_queue(), AST_APP_ARG, ast_category_browse(), ast_config_destroy(), ast_config_load(), AST_DECLARE_APP_ARGS, ast_device_state(), AST_LIST_INSERT_HEAD, AST_LIST_LOCK, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, AST_LIST_UNLOCK, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), AST_NONSTANDARD_APP_ARGS, ast_strlen_zero(), ast_true(), ast_variable_browse(), ast_variable_retrieve(), clear_queue(), call_queue::count, create_queue_member(), call_queue::dead, member::delme, destroy_queue(), member::dynamic, free, init_queue(), member::interface, member_interface::interface, ast_variable::lineno, call_queue::lock, LOG_DEBUG, LOG_NOTICE, call_queue::membercount, member::membername, call_queue::members, ast_variable::name, call_queue::name, ast_variable::next, member::next, parse(), member::paused, member::penalty, queue_set_param(), QUEUE_STRATEGY_ROUNDROBIN, remove_from_interfaces(), rr_dep_warning(), member::status, call_queue::strategy, ast_variable::value, and var.
Referenced by load_module(), and reload().
03766 { 03767 struct call_queue *q; 03768 struct ast_config *cfg; 03769 char *cat, *tmp; 03770 struct ast_variable *var; 03771 struct member *prev, *cur, *newm, *next; 03772 int new; 03773 const char *general_val = NULL; 03774 char parse[80]; 03775 char *interface; 03776 char *membername; 03777 int penalty; 03778 AST_DECLARE_APP_ARGS(args, 03779 AST_APP_ARG(interface); 03780 AST_APP_ARG(penalty); 03781 AST_APP_ARG(membername); 03782 ); 03783 03784 if (!(cfg = ast_config_load("queues.conf"))) { 03785 ast_log(LOG_NOTICE, "No call queueing config file (queues.conf), so no call queues\n"); 03786 return 0; 03787 } 03788 AST_LIST_LOCK(&queues); 03789 use_weight=0; 03790 /* Mark all queues as dead for the moment */ 03791 AST_LIST_TRAVERSE(&queues, q, list) 03792 q->dead = 1; 03793 03794 /* Chug through config file */ 03795 cat = NULL; 03796 while ((cat = ast_category_browse(cfg, cat)) ) { 03797 if (!strcasecmp(cat, "general")) { 03798 /* Initialize global settings */ 03799 queue_persistent_members = 0; 03800 if ((general_val = ast_variable_retrieve(cfg, "general", "persistentmembers"))) 03801 queue_persistent_members = ast_true(general_val); 03802 autofill_default = 0; 03803 if ((general_val = ast_variable_retrieve(cfg, "general", "autofill"))) 03804 autofill_default = ast_true(general_val); 03805 montype_default = 0; 03806 if ((general_val = ast_variable_retrieve(cfg, "general", "monitor-type"))) 03807 if (!strcasecmp(general_val, "mixmonitor")) 03808 montype_default = 1; 03809 } else { /* Define queue */ 03810 /* Look for an existing one */ 03811 AST_LIST_TRAVERSE(&queues, q, list) { 03812 if (!strcmp(q->name, cat)) 03813 break; 03814 } 03815 if (!q) { 03816 /* Make one then */ 03817 if (!(q = alloc_queue(cat))) { 03818 /* TODO: Handle memory allocation failure */ 03819 } 03820 new = 1; 03821 } else 03822 new = 0; 03823 if (q) { 03824 if (!new) 03825 ast_mutex_lock(&q->lock); 03826 /* Re-initialize the queue, and clear statistics */ 03827 init_queue(q); 03828 clear_queue(q); 03829 for (cur = q->members; cur; cur = cur->next) { 03830 if (!cur->dynamic) { 03831 cur->delme = 1; 03832 } 03833 } 03834 for (var = ast_variable_browse(cfg, cat); var; var = var->next) { 03835 if (!strcasecmp(var->name, "member")) { 03836 /* Add a new member */ 03837 ast_copy_string(parse, var->value, sizeof(parse)); 03838 03839 AST_NONSTANDARD_APP_ARGS(args, parse, ','); 03840 03841 interface = args.interface; 03842 if(!ast_strlen_zero(args.penalty)) { 03843 tmp = args.penalty; 03844 while (*tmp && *tmp < 33) tmp++; 03845 penalty = atoi(tmp); 03846 if (penalty < 0) { 03847 penalty = 0; 03848 } 03849 } else 03850 penalty = 0; 03851 03852 if (!ast_strlen_zero(args.membername)) { 03853 membername = args.membername; 03854 while (*membername && *membername < 33) membername++; 03855 } else 03856 membername = interface; 03857 03858 /* Find the old position in the list */ 03859 for (prev = NULL, cur = q->members; cur; prev = cur, cur = cur->next) { 03860 if (!strcmp(cur->interface, interface)) { 03861 break; 03862 } 03863 } 03864 03865 newm = create_queue_member(interface, membername, penalty, cur ? cur->paused : 0); 03866 03867 if (cur) { 03868 /* Delete it now */ 03869 newm->next = cur->next; 03870 if (prev) { 03871 prev->next = newm; 03872 } else { 03873 q->members = newm; 03874 } 03875 free(cur); 03876 } else { 03877 /* Add them to the master int list if necessary */ 03878 add_to_interfaces(interface); 03879 newm->next = q->members; 03880 q->members = newm; 03881 } 03882 q->membercount++; 03883 } else { 03884 queue_set_param(q, var->name, var->value, var->lineno, 1); 03885 } 03886 } 03887 03888 /* Free remaining members marked as delme */ 03889 for (prev = NULL, cur = q->members; 03890 cur; 03891 cur = next) { 03892 next = cur->next; 03893 03894 if (!cur->delme) { 03895 prev = cur; 03896 continue; 03897 } 03898 03899 if (prev) 03900 prev->next = next; 03901 else 03902 q->members = next; 03903 03904 remove_from_interfaces(cur->interface); 03905 q->membercount--; 03906 free(cur); 03907 } 03908 03909 if (q->strategy == QUEUE_STRATEGY_ROUNDROBIN) 03910 rr_dep_warning(); 03911 03912 if (new) { 03913 AST_LIST_INSERT_HEAD(&queues, q, list); 03914 } else 03915 ast_mutex_unlock(&q->lock); 03916 } 03917 } 03918 } 03919 ast_config_destroy(cfg); 03920 AST_LIST_TRAVERSE_SAFE_BEGIN(&queues, q, list) { 03921 if (q->dead) { 03922 AST_LIST_REMOVE_CURRENT(&queues, list); 03923 if (!q->count) 03924 destroy_queue(q); 03925 else 03926 ast_log(LOG_DEBUG, "XXX Leaking a little memory :( XXX\n"); 03927 } else { 03928 ast_mutex_lock(&q->lock); 03929 for (cur = q->members; cur; cur = cur->next) 03930 cur->status = ast_device_state(cur->interface); 03931 ast_mutex_unlock(&q->lock); 03932 } 03933 } 03934 AST_LIST_TRAVERSE_SAFE_END; 03935 AST_LIST_UNLOCK(&queues); 03936 return 1; 03937 }
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 find_queue_by_name_rt(), 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 2829 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().
02830 { 02831 struct call_queue *q; 02832 struct member *last_member, *look; 02833 int res = RES_NOSUCHQUEUE; 02834 02835 AST_LIST_LOCK(&queues); 02836 AST_LIST_TRAVERSE(&queues, q, list) { 02837 ast_mutex_lock(&q->lock); 02838 if (strcmp(q->name, queuename)) { 02839 ast_mutex_unlock(&q->lock); 02840 continue; 02841 } 02842 02843 if ((last_member = interface_exists(q, interface))) { 02844 if ((look = q->members) == last_member) { 02845 q->members = last_member->next; 02846 q->membercount--; 02847 } else { 02848 while (look != NULL) { 02849 if (look->next == last_member) { 02850 look->next = last_member->next; 02851 q->membercount--; 02852 break; 02853 } else { 02854 look = look->next; 02855 } 02856 } 02857 } 02858 manager_event(EVENT_FLAG_AGENT, "QueueMemberRemoved", 02859 "Queue: %s\r\n" 02860 "Location: %s\r\n" 02861 "MemberName: %s\r\n", 02862 q->name, last_member->interface, last_member->membername); 02863 free(last_member); 02864 02865 if (queue_persistent_members) 02866 dump_queue_members(q); 02867 02868 res = RES_OKAY; 02869 } else { 02870 res = RES_EXISTS; 02871 } 02872 ast_mutex_unlock(&q->lock); 02873 break; 02874 } 02875 02876 if (res == RES_OKAY) 02877 remove_from_interfaces(interface); 02878 02879 AST_LIST_UNLOCK(&queues); 02880 02881 return res; 02882 }
static int ring_entry | ( | struct queue_ent * | qe, | |
struct callattempt * | tmp, | |||
int * | busies | |||
) | [static] |
Definition at line 1635 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().
01636 { 01637 int res; 01638 int status; 01639 char tech[256]; 01640 char *location; 01641 01642 /* on entry here, we know that tmp->chan == NULL */ 01643 if (qe->parent->wrapuptime && (time(NULL) - tmp->lastcall < qe->parent->wrapuptime)) { 01644 if (option_debug) 01645 ast_log(LOG_DEBUG, "Wrapuptime not yet expired for %s\n", tmp->interface); 01646 if (qe->chan->cdr) 01647 ast_cdr_busy(qe->chan->cdr); 01648 tmp->stillgoing = 0; 01649 (*busies)++; 01650 return 0; 01651 } 01652 01653 if (!qe->parent->ringinuse && (tmp->member->status != AST_DEVICE_NOT_INUSE) && (tmp->member->status != AST_DEVICE_UNKNOWN)) { 01654 if (option_debug) 01655 ast_log(LOG_DEBUG, "%s in use, can't receive call\n", tmp->interface); 01656 if (qe->chan->cdr) 01657 ast_cdr_busy(qe->chan->cdr); 01658 tmp->stillgoing = 0; 01659 return 0; 01660 } 01661 01662 if (tmp->member->paused) { 01663 if (option_debug) 01664 ast_log(LOG_DEBUG, "%s paused, can't receive call\n", tmp->interface); 01665 if (qe->chan->cdr) 01666 ast_cdr_busy(qe->chan->cdr); 01667 tmp->stillgoing = 0; 01668 return 0; 01669 } 01670 if (use_weight && compare_weight(qe->parent,tmp->member)) { 01671 ast_log(LOG_DEBUG, "Priority queue delaying call to %s:%s\n", qe->parent->name, tmp->interface); 01672 if (qe->chan->cdr) 01673 ast_cdr_busy(qe->chan->cdr); 01674 tmp->stillgoing = 0; 01675 (*busies)++; 01676 return 0; 01677 } 01678 01679 ast_copy_string(tech, tmp->interface, sizeof(tech)); 01680 if ((location = strchr(tech, '/'))) 01681 *location++ = '\0'; 01682 else 01683 location = ""; 01684 01685 /* Request the peer */ 01686 tmp->chan = ast_request(tech, qe->chan->nativeformats, location, &status); 01687 if (!tmp->chan) { /* If we can't, just go on to the next call */ 01688 if (qe->chan->cdr) 01689 ast_cdr_busy(qe->chan->cdr); 01690 tmp->stillgoing = 0; 01691 update_dial_status(qe->parent, tmp->member, status); 01692 01693 ast_mutex_lock(&qe->parent->lock); 01694 qe->parent->rrpos++; 01695 ast_mutex_unlock(&qe->parent->lock); 01696 01697 (*busies)++; 01698 return 0; 01699 } else if (status != tmp->oldstatus) 01700 update_dial_status(qe->parent, tmp->member, status); 01701 01702 tmp->chan->appl = "AppQueue"; 01703 tmp->chan->data = "(Outgoing Line)"; 01704 tmp->chan->whentohangup = 0; 01705 if (tmp->chan->cid.cid_num) 01706 free(tmp->chan->cid.cid_num); 01707 tmp->chan->cid.cid_num = ast_strdup(qe->chan->cid.cid_num); 01708 if (tmp->chan->cid.cid_name) 01709 free(tmp->chan->cid.cid_name); 01710 tmp->chan->cid.cid_name = ast_strdup(qe->chan->cid.cid_name); 01711 if (tmp->chan->cid.cid_ani) 01712 free(tmp->chan->cid.cid_ani); 01713 tmp->chan->cid.cid_ani = ast_strdup(qe->chan->cid.cid_ani); 01714 01715 /* Inherit specially named variables from parent channel */ 01716 ast_channel_inherit_variables(qe->chan, tmp->chan); 01717 01718 /* Presense of ADSI CPE on outgoing channel follows ours */ 01719 tmp->chan->adsicpe = qe->chan->adsicpe; 01720 01721 /* Place the call, but don't wait on the answer */ 01722 if ((res = ast_call(tmp->chan, location, 0))) { 01723 /* Again, keep going even if there's an error */ 01724 if (option_debug) 01725 ast_log(LOG_DEBUG, "ast call on peer returned %d\n", res); 01726 if (option_verbose > 2) 01727 ast_verbose(VERBOSE_PREFIX_3 "Couldn't call %s\n", tmp->interface); 01728 do_hang(tmp); 01729 (*busies)++; 01730 return 0; 01731 } else if (qe->parent->eventwhencalled) { 01732 char vars[2048]; 01733 01734 manager_event(EVENT_FLAG_AGENT, "AgentCalled", 01735 "AgentCalled: %s\r\n" 01736 "ChannelCalling: %s\r\n" 01737 "CallerID: %s\r\n" 01738 "CallerIDName: %s\r\n" 01739 "Context: %s\r\n" 01740 "Extension: %s\r\n" 01741 "Priority: %d\r\n" 01742 "%s", 01743 tmp->interface, qe->chan->name, 01744 tmp->chan->cid.cid_num ? tmp->chan->cid.cid_num : "unknown", 01745 tmp->chan->cid.cid_name ? tmp->chan->cid.cid_name : "unknown", 01746 qe->chan->context, qe->chan->exten, qe->chan->priority, 01747 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : ""); 01748 if (option_verbose > 2) 01749 ast_verbose(VERBOSE_PREFIX_3 "Called %s\n", tmp->interface); 01750 } 01751 01752 return 1; 01753 }
static int ring_one | ( | struct queue_ent * | qe, | |
struct callattempt * | outgoing, | |||
int * | busies | |||
) | [static] |
Definition at line 1771 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().
01772 { 01773 int ret = 0; 01774 01775 while (ret == 0) { 01776 struct callattempt *best = find_best(outgoing); 01777 if (!best) { 01778 if (option_debug) 01779 ast_log(LOG_DEBUG, "Nobody left to try ringing in queue\n"); 01780 break; 01781 } 01782 if (qe->parent->strategy == QUEUE_STRATEGY_RINGALL) { 01783 struct callattempt *cur; 01784 /* Ring everyone who shares this best metric (for ringall) */ 01785 for (cur = outgoing; cur; cur = cur->q_next) { 01786 if (cur->stillgoing && !cur->chan && cur->metric <= best->metric) { 01787 if (option_debug) 01788 ast_log(LOG_DEBUG, "(Parallel) Trying '%s' with metric %d\n", cur->interface, cur->metric); 01789 ring_entry(qe, cur, busies); 01790 } 01791 } 01792 } else { 01793 /* Ring just the best channel */ 01794 if (option_debug) 01795 ast_log(LOG_DEBUG, "Trying '%s' with metric %d\n", best->interface, best->metric); 01796 ring_entry(qe, best, busies); 01797 } 01798 if (best->chan) /* break out with result = 1 */ 01799 ret = 1; 01800 } 01801 01802 return ret; 01803 }
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 1887 of file app_queue.c.
References ast_queue_log(), ast_verbose(), call_queue::autopause, queue_ent::chan, call_queue::name, option_verbose, queue_ent::parent, set_member_paused(), and VERBOSE_PREFIX_3.
Referenced by wait_for_answer().
01888 { 01889 if (option_verbose > 2) 01890 ast_verbose( VERBOSE_PREFIX_3 "Nobody picked up in %d ms\n", rnatime); 01891 ast_queue_log(qe->parent->name, qe->chan->uniqueid, membername, "RINGNOANSWER", "%d", rnatime); 01892 if (qe->parent->autopause) { 01893 if (!set_member_paused(qe->parent->name, interface, 1)) { 01894 if (option_verbose > 2) 01895 ast_verbose( VERBOSE_PREFIX_3 "Auto-Pausing Queue Member %s in queue %s since they failed to answer.\n", interface, qe->parent->name); 01896 } else { 01897 if (option_verbose > 2) 01898 ast_verbose( VERBOSE_PREFIX_3 "Failed to pause Queue Member %s in queue %s!\n", interface, qe->parent->name); 01899 } 01900 } 01901 return; 01902 }
static int rqm_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Definition at line 3180 of file app_queue.c.
References AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_goto_if_exists(), ast_log(), ast_module_user_add, ast_module_user_remove, ast_opt_priority_jumping, ast_queue_log(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), ast_channel::context, ast_channel::exten, member_interface::interface, LOG_DEBUG, LOG_NOTICE, LOG_WARNING, parse(), pbx_builtin_setvar_helper(), ast_channel::priority, remove_from_queue(), RES_EXISTS, RES_NOSUCHQUEUE, and RES_OKAY.
Referenced by load_module().
03181 { 03182 int res=-1; 03183 struct ast_module_user *lu; 03184 char *parse, *temppos = NULL; 03185 int priority_jump = 0; 03186 AST_DECLARE_APP_ARGS(args, 03187 AST_APP_ARG(queuename); 03188 AST_APP_ARG(interface); 03189 AST_APP_ARG(options); 03190 ); 03191 03192 03193 if (ast_strlen_zero(data)) { 03194 ast_log(LOG_WARNING, "RemoveQueueMember requires an argument (queuename[|interface[|options]])\n"); 03195 return -1; 03196 } 03197 03198 parse = ast_strdupa(data); 03199 03200 AST_STANDARD_APP_ARGS(args, parse); 03201 03202 lu = ast_module_user_add(chan); 03203 03204 if (ast_strlen_zero(args.interface)) { 03205 args.interface = ast_strdupa(chan->name); 03206 temppos = strrchr(args.interface, '-'); 03207 if (temppos) 03208 *temppos = '\0'; 03209 } 03210 03211 if (args.options) { 03212 if (strchr(args.options, 'j')) 03213 priority_jump = 1; 03214 } 03215 03216 switch (remove_from_queue(args.queuename, args.interface)) { 03217 case RES_OKAY: 03218 ast_queue_log(args.queuename, chan->uniqueid, args.interface, "REMOVEMEMBER", "%s", ""); 03219 ast_log(LOG_NOTICE, "Removed interface '%s' from queue '%s'\n", args.interface, args.queuename); 03220 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "REMOVED"); 03221 res = 0; 03222 break; 03223 case RES_EXISTS: 03224 ast_log(LOG_DEBUG, "Unable to remove interface '%s' from queue '%s': Not there\n", args.interface, args.queuename); 03225 if (priority_jump || ast_opt_priority_jumping) 03226 ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101); 03227 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOTINQUEUE"); 03228 res = 0; 03229 break; 03230 case RES_NOSUCHQUEUE: 03231 ast_log(LOG_WARNING, "Unable to remove interface from queue '%s': No such queue\n", args.queuename); 03232 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOSUCHQUEUE"); 03233 res = 0; 03234 break; 03235 } 03236 03237 ast_module_user_remove(lu); 03238 03239 return res; 03240 }
static void rr_dep_warning | ( | void | ) | [static] |
Definition at line 408 of file app_queue.c.
References ast_log(), and LOG_NOTICE.
Referenced by find_queue_by_name_rt(), and 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 find_queue_by_name_rt(), and 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 1829 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().
01830 { 01831 int res = 0; 01832 time_t now; 01833 01834 /* Get the current time */ 01835 time(&now); 01836 01837 /* Check to see if it is time to announce */ 01838 if ((now - qe->last_periodic_announce_time) < qe->parent->periodicannouncefrequency) 01839 return 0; 01840 01841 /* Stop the music on hold so we can play our own file */ 01842 ast_moh_stop(qe->chan); 01843 01844 if (option_verbose > 2) 01845 ast_verbose(VERBOSE_PREFIX_3 "Playing periodic announcement\n"); 01846 01847 /* Check to make sure we have a sound file. If not, reset to the first sound file */ 01848 if (qe->last_periodic_announce_sound >= MAX_PERIODIC_ANNOUNCEMENTS || !strlen(qe->parent->sound_periodicannounce[qe->last_periodic_announce_sound])) { 01849 qe->last_periodic_announce_sound = 0; 01850 } 01851 01852 /* play the announcement */ 01853 res = play_file(qe->chan, qe->parent->sound_periodicannounce[qe->last_periodic_announce_sound]); 01854 01855 if (res > 0 && !valid_exit(qe, res)) 01856 res = 0; 01857 01858 /* Resume Music on Hold if the caller is going to stay in the queue */ 01859 if (!res) 01860 ast_moh_start(qe->chan, qe->moh, NULL); 01861 01862 /* update last_periodic_announce_time */ 01863 qe->last_periodic_announce_time = now; 01864 01865 /* Update the current periodic announcement to the next announcement */ 01866 qe->last_periodic_announce_sound++; 01867 01868 return res; 01869 }
static int say_position | ( | struct queue_ent * | qe | ) | [static] |
Definition at line 1334 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().
01335 { 01336 int res = 0, avgholdmins, avgholdsecs; 01337 time_t now; 01338 01339 /* Check to see if this is ludicrous -- if we just announced position, don't do it again*/ 01340 time(&now); 01341 if ((now - qe->last_pos) < 15) 01342 return 0; 01343 01344 /* If either our position has changed, or we are over the freq timer, say position */ 01345 if ((qe->last_pos_said == qe->pos) && ((now - qe->last_pos) < qe->parent->announcefrequency)) 01346 return 0; 01347 01348 ast_moh_stop(qe->chan); 01349 /* Say we're next, if we are */ 01350 if (qe->pos == 1) { 01351 res = play_file(qe->chan, qe->parent->sound_next); 01352 if (res) 01353 goto playout; 01354 else 01355 goto posout; 01356 } else { 01357 res = play_file(qe->chan, qe->parent->sound_thereare); 01358 if (res) 01359 goto playout; 01360 res = ast_say_number(qe->chan, qe->pos, AST_DIGIT_ANY, qe->chan->language, (char *) NULL); /* Needs gender */ 01361 if (res) 01362 goto playout; 01363 res = play_file(qe->chan, qe->parent->sound_calls); 01364 if (res) 01365 goto playout; 01366 } 01367 /* Round hold time to nearest minute */ 01368 avgholdmins = abs(((qe->parent->holdtime + 30) - (now - qe->start)) / 60); 01369 01370 /* If they have specified a rounding then round the seconds as well */ 01371 if (qe->parent->roundingseconds) { 01372 avgholdsecs = (abs(((qe->parent->holdtime + 30) - (now - qe->start))) - 60 * avgholdmins) / qe->parent->roundingseconds; 01373 avgholdsecs *= qe->parent->roundingseconds; 01374 } else { 01375 avgholdsecs = 0; 01376 } 01377 01378 if (option_verbose > 2) 01379 ast_verbose(VERBOSE_PREFIX_3 "Hold time for %s is %d minutes %d seconds\n", qe->parent->name, avgholdmins, avgholdsecs); 01380 01381 /* If the hold time is >1 min, if it's enabled, and if it's not 01382 supposed to be only once and we have already said it, say it */ 01383 if ((avgholdmins+avgholdsecs) > 0 && (qe->parent->announceholdtime) && 01384 (!(qe->parent->announceholdtime == ANNOUNCEHOLDTIME_ONCE) && qe->last_pos)) { 01385 res = play_file(qe->chan, qe->parent->sound_holdtime); 01386 if (res) 01387 goto playout; 01388 01389 if (avgholdmins > 0) { 01390 if (avgholdmins < 2) { 01391 res = play_file(qe->chan, qe->parent->sound_lessthan); 01392 if (res) 01393 goto playout; 01394 01395 res = ast_say_number(qe->chan, 2, AST_DIGIT_ANY, qe->chan->language, NULL); 01396 if (res) 01397 goto playout; 01398 } else { 01399 res = ast_say_number(qe->chan, avgholdmins, AST_DIGIT_ANY, qe->chan->language, NULL); 01400 if (res) 01401 goto playout; 01402 } 01403 01404 res = play_file(qe->chan, qe->parent->sound_minutes); 01405 if (res) 01406 goto playout; 01407 } 01408 if (avgholdsecs>0) { 01409 res = ast_say_number(qe->chan, avgholdsecs, AST_DIGIT_ANY, qe->chan->language, NULL); 01410 if (res) 01411 goto playout; 01412 01413 res = play_file(qe->chan, qe->parent->sound_seconds); 01414 if (res) 01415 goto playout; 01416 } 01417 01418 } 01419 01420 posout: 01421 if (option_verbose > 2) 01422 ast_verbose(VERBOSE_PREFIX_3 "Told %s in %s their queue position (which was %d)\n", 01423 qe->chan->name, qe->parent->name, qe->pos); 01424 res = play_file(qe->chan, qe->parent->sound_thanks); 01425 01426 playout: 01427 if (res > 0 && !valid_exit(qe, res)) 01428 res = 0; 01429 01430 /* Set our last_pos indicators */ 01431 qe->last_pos = now; 01432 qe->last_pos_said = qe->pos; 01433 01434 /* Don't restart music on hold if we're about to exit the caller from the queue */ 01435 if (!res) 01436 ast_moh_start(qe->chan, qe->moh, NULL); 01437 01438 return res; 01439 }
static int set_member_paused | ( | const char * | queuename, | |
const char * | interface, | |||
int | paused | |||
) | [static] |
Definition at line 2937 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().
02938 { 02939 int found = 0; 02940 struct call_queue *q; 02941 struct member *mem; 02942 02943 /* Special event for when all queues are paused - individual events still generated */ 02944 /* XXX In all other cases, we use the membername, but since this affects all queues, we cannot */ 02945 if (ast_strlen_zero(queuename)) 02946 ast_queue_log("NONE", "NONE", interface, (paused ? "PAUSEALL" : "UNPAUSEALL"), "%s", ""); 02947 02948 AST_LIST_LOCK(&queues); 02949 AST_LIST_TRAVERSE(&queues, q, list) { 02950 ast_mutex_lock(&q->lock); 02951 if (ast_strlen_zero(queuename) || !strcasecmp(q->name, queuename)) { 02952 if ((mem = interface_exists(q, interface))) { 02953 found++; 02954 if (mem->paused == paused) 02955 ast_log(LOG_DEBUG, "%spausing already-%spaused queue member %s:%s\n", (paused ? "" : "un"), (paused ? "" : "un"), q->name, interface); 02956 mem->paused = paused; 02957 02958 if (queue_persistent_members) 02959 dump_queue_members(q); 02960 02961 ast_queue_log(q->name, "NONE", mem->membername, (paused ? "PAUSE" : "UNPAUSE"), "%s", ""); 02962 02963 manager_event(EVENT_FLAG_AGENT, "QueueMemberPaused", 02964 "Queue: %s\r\n" 02965 "Location: %s\r\n" 02966 "MemberName: %s\r\n" 02967 "Paused: %d\r\n", 02968 q->name, mem->interface, mem->membername, paused); 02969 } 02970 } 02971 ast_mutex_unlock(&q->lock); 02972 } 02973 AST_LIST_UNLOCK(&queues); 02974 02975 return found ? RESULT_SUCCESS : RESULT_FAILURE; 02976 }
static void set_queue_result | ( | struct ast_channel * | chan, | |
enum queue_result | res | |||
) | [static] |
Definition at line 418 of file app_queue.c.
References 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(), statechange::dev, free, LOG_WARNING, statechange::state, 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 1805 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().
01806 { 01807 struct callattempt *best = find_best(outgoing); 01808 01809 if (best) { 01810 /* Ring just the best channel */ 01811 if (option_debug) 01812 ast_log(LOG_DEBUG, "Next is '%s' with metric %d\n", best->interface, best->metric); 01813 qe->parent->rrpos = best->metric % 1000; 01814 } else { 01815 /* Just increment rrpos */ 01816 if (qe->parent->wrapped) { 01817 /* No more channels, start over */ 01818 qe->parent->rrpos = 0; 01819 } else { 01820 /* Prioritize next entry */ 01821 qe->parent->rrpos++; 01822 } 01823 } 01824 qe->parent->wrapped = 0; 01825 01826 return 0; 01827 }
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 * | go_on, | |||
const char * | agi | |||
) | [static] |
Definition at line 2345 of file app_queue.c.
References ast_channel::_softhangup, ast_channel::_state, queue_ent::announce, 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, ast_bridge_config::features_callee, ast_bridge_config::features_caller, free, queue_ent::handled, hangupcalls(), member::interface, callattempt::interface, member::lastcall, callattempt::lastcall, leave_queue(), call_queue::lock, LOG_DEBUG, LOG_NOTICE, LOG_WARNING, manager_event(), callattempt::member, call_queue::membercount, call_queue::memberdelay, member::membername, call_queue::members, call_queue::monfmt, call_queue::monjoin, call_queue::montype, call_queue::name, member::next, callattempt::oldstatus, queue_ent::opos, option_debug, queue_ent::parent, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), pbx_exec(), pbx_findapp(), pbx_substitute_variables_helper(), play_file(), queue_ent::pos, callattempt::q_next, QUEUE_EVENT_VARIABLES, QUEUE_STRATEGY_ROUNDROBIN, QUEUE_STRATEGY_RRMEMORY, recalc_holdtime(), record_abandoned(), call_queue::reportholdtime, ring_one(), call_queue::servicelevel, call_queue::setinterfacevar, call_queue::sound_lessthan, call_queue::sound_minutes, call_queue::sound_reporthold, queue_ent::start, member::status, callattempt::stillgoing, store_next(), call_queue::strategy, ast_channel::tech, call_queue::timeout, ast_channel_tech::type, ast_cdr::uniqueid, update_queue(), valid_exit(), vars2manager(), and wait_for_answer().
Referenced by queue_exec().
02346 { 02347 struct member *cur; 02348 struct callattempt *outgoing = NULL; /* the list of calls we are building */ 02349 int to; 02350 char oldexten[AST_MAX_EXTENSION]=""; 02351 char oldcontext[AST_MAX_CONTEXT]=""; 02352 char queuename[256]=""; 02353 struct ast_channel *peer; 02354 struct ast_channel *which; 02355 struct callattempt *lpeer; 02356 struct member *member; 02357 struct ast_app *app; 02358 int res = 0, bridge = 0; 02359 int numbusies = 0; 02360 int x=0; 02361 char *announce = NULL; 02362 char digit = 0; 02363 time_t callstart; 02364 time_t now = time(NULL); 02365 struct ast_bridge_config bridge_config; 02366 char nondataquality = 1; 02367 char *agiexec = NULL; 02368 int ret = 0; 02369 const char *monitorfilename; 02370 const char *monitor_exec; 02371 const char *monitor_options; 02372 char tmpid[256], tmpid2[256]; 02373 char meid[1024], meid2[1024]; 02374 char mixmonargs[1512]; 02375 struct ast_app *mixmonapp = NULL; 02376 char *p; 02377 char vars[2048]; 02378 int forwardsallowed = 1; 02379 int callcompletedinsl; 02380 int noption = 0; 02381 02382 memset(&bridge_config, 0, sizeof(bridge_config)); 02383 time(&now); 02384 02385 for (; options && *options; options++) 02386 switch (*options) { 02387 case 't': 02388 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_REDIRECT); 02389 break; 02390 case 'T': 02391 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_REDIRECT); 02392 break; 02393 case 'w': 02394 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_AUTOMON); 02395 break; 02396 case 'W': 02397 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_AUTOMON); 02398 break; 02399 case 'd': 02400 nondataquality = 0; 02401 break; 02402 case 'h': 02403 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_DISCONNECT); 02404 break; 02405 case 'H': 02406 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT); 02407 break; 02408 case 'n': 02409 if (qe->parent->strategy == QUEUE_STRATEGY_ROUNDROBIN || qe->parent->strategy == QUEUE_STRATEGY_RRMEMORY) 02410 (*go_on)++; 02411 else 02412 *go_on = qe->parent->membercount; 02413 noption = 1; 02414 break; 02415 case 'i': 02416 forwardsallowed = 0; 02417 break; 02418 } 02419 02420 if(!noption) 02421 *go_on = -1; 02422 02423 /* Hold the lock while we setup the outgoing calls */ 02424 if (use_weight) 02425 AST_LIST_LOCK(&queues); 02426 ast_mutex_lock(&qe->parent->lock); 02427 if (option_debug) 02428 ast_log(LOG_DEBUG, "%s is trying to call a queue member.\n", 02429 qe->chan->name); 02430 ast_copy_string(queuename, qe->parent->name, sizeof(queuename)); 02431 cur = qe->parent->members; 02432 if (!ast_strlen_zero(qe->announce)) 02433 announce = qe->announce; 02434 if (!ast_strlen_zero(announceoverride)) 02435 announce = announceoverride; 02436 02437 for (; cur; cur = cur->next) { 02438 struct callattempt *tmp = ast_calloc(1, sizeof(*tmp)); 02439 02440 if (!tmp) { 02441 ast_mutex_unlock(&qe->parent->lock); 02442 if (use_weight) 02443 AST_LIST_UNLOCK(&queues); 02444 goto out; 02445 } 02446 tmp->stillgoing = -1; 02447 tmp->member = cur; /* Never directly dereference! Could change on reload */ 02448 tmp->oldstatus = cur->status; 02449 tmp->lastcall = cur->lastcall; 02450 ast_copy_string(tmp->interface, cur->interface, sizeof(tmp->interface)); 02451 /* Special case: If we ring everyone, go ahead and ring them, otherwise 02452 just calculate their metric for the appropriate strategy */ 02453 if (!calc_metric(qe->parent, cur, x++, qe, tmp)) { 02454 /* Put them in the list of outgoing thingies... We're ready now. 02455 XXX If we're forcibly removed, these outgoing calls won't get 02456 hung up XXX */ 02457 tmp->q_next = outgoing; 02458 outgoing = tmp; 02459 /* If this line is up, don't try anybody else */ 02460 if (outgoing->chan && (outgoing->chan->_state == AST_STATE_UP)) 02461 break; 02462 } else { 02463 free(tmp); 02464 } 02465 } 02466 if (qe->expire && (!qe->parent->timeout || (qe->expire - now) <= qe->parent->timeout)) 02467 to = (qe->expire - now) * 1000; 02468 else 02469 to = (qe->parent->timeout) ? qe->parent->timeout * 1000 : -1; 02470 ring_one(qe, outgoing, &numbusies); 02471 ast_mutex_unlock(&qe->parent->lock); 02472 if (use_weight) 02473 AST_LIST_UNLOCK(&queues); 02474 lpeer = wait_for_answer(qe, outgoing, &to, &digit, numbusies, ast_test_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT), forwardsallowed); 02475 ast_mutex_lock(&qe->parent->lock); 02476 if (qe->parent->strategy == QUEUE_STRATEGY_RRMEMORY) { 02477 store_next(qe, outgoing); 02478 } 02479 ast_mutex_unlock(&qe->parent->lock); 02480 peer = lpeer ? lpeer->chan : NULL; 02481 if (!peer) { 02482 if (to) { 02483 /* Must gotten hung up */ 02484 res = -1; 02485 } else { 02486 res = digit; 02487 if (res > 0 && !valid_exit(qe, res)) 02488 res = 0; 02489 } 02490 if (option_debug) 02491 ast_log(LOG_DEBUG, "%s: Nobody answered.\n", qe->chan->name); 02492 } else { /* peer is valid */ 02493 /* Ah ha! Someone answered within the desired timeframe. Of course after this 02494 we will always return with -1 so that it is hung up properly after the 02495 conversation. */ 02496 qe->handled++; 02497 if (!strcmp(qe->chan->tech->type, "Zap")) 02498 ast_channel_setoption(qe->chan, AST_OPTION_TONE_VERIFY, &nondataquality, sizeof(nondataquality), 0); 02499 if (!strcmp(peer->tech->type, "Zap")) 02500 ast_channel_setoption(peer, AST_OPTION_TONE_VERIFY, &nondataquality, sizeof(nondataquality), 0); 02501 /* Update parameters for the queue */ 02502 time(&now); 02503 recalc_holdtime(qe, (now - qe->start)); 02504 ast_mutex_lock(&qe->parent->lock); 02505 callcompletedinsl = ((now - qe->start) <= qe->parent->servicelevel); 02506 ast_mutex_unlock(&qe->parent->lock); 02507 member = lpeer->member; 02508 hangupcalls(outgoing, peer); 02509 outgoing = NULL; 02510 if (announce || qe->parent->reportholdtime || qe->parent->memberdelay) { 02511 int res2; 02512 02513 res2 = ast_autoservice_start(qe->chan); 02514 if (!res2) { 02515 if (qe->parent->memberdelay) { 02516 ast_log(LOG_NOTICE, "Delaying member connect for %d seconds\n", qe->parent->memberdelay); 02517 res2 |= ast_safe_sleep(peer, qe->parent->memberdelay * 1000); 02518 } 02519 if (!res2 && announce) { 02520 if (play_file(peer, announce)) 02521 ast_log(LOG_WARNING, "Announcement file '%s' is unavailable, continuing anyway...\n", announce); 02522 } 02523 if (!res2 && qe->parent->reportholdtime) { 02524 if (!play_file(peer, qe->parent->sound_reporthold)) { 02525 int holdtime; 02526 02527 time(&now); 02528 holdtime = abs((now - qe->start) / 60); 02529 if (holdtime < 2) { 02530 play_file(peer, qe->parent->sound_lessthan); 02531 ast_say_number(peer, 2, AST_DIGIT_ANY, peer->language, NULL); 02532 } else 02533 ast_say_number(peer, holdtime, AST_DIGIT_ANY, peer->language, NULL); 02534 play_file(peer, qe->parent->sound_minutes); 02535 } 02536 } 02537 } 02538 res2 |= ast_autoservice_stop(qe->chan); 02539 if (peer->_softhangup) { 02540 /* Agent must have hung up */ 02541 ast_log(LOG_WARNING, "Agent on %s hungup on the customer.\n", peer->name); 02542 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "AGENTDUMP", "%s", ""); 02543 record_abandoned(qe); 02544 if (qe->parent->eventwhencalled) 02545 manager_event(EVENT_FLAG_AGENT, "AgentDump", 02546 "Queue: %s\r\n" 02547 "Uniqueid: %s\r\n" 02548 "Channel: %s\r\n" 02549 "Member: %s\r\n" 02550 "MemberName: %s\r\n" 02551 "%s", 02552 queuename, qe->chan->uniqueid, peer->name, member->interface, member->membername, 02553 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : ""); 02554 ast_hangup(peer); 02555 goto out; 02556 } else if (res2) { 02557 /* Caller must have hung up just before being connected*/ 02558 ast_log(LOG_NOTICE, "Caller was about to talk to agent on %s but the caller hungup.\n", peer->name); 02559 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "ABANDON", "%d|%d|%ld", qe->pos, qe->opos, (long)time(NULL) - qe->start); 02560 record_abandoned(qe); 02561 ast_hangup(peer); 02562 return -1; 02563 } 02564 } 02565 /* Stop music on hold */ 02566 ast_moh_stop(qe->chan); 02567 /* If appropriate, log that we have a destination channel */ 02568 if (qe->chan->cdr) 02569 ast_cdr_setdestchan(qe->chan->cdr, peer->name); 02570 /* Make sure channels are compatible */ 02571 res = ast_channel_make_compatible(qe->chan, peer); 02572 if (res < 0) { 02573 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "SYSCOMPAT", "%s", ""); 02574 ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", qe->chan->name, peer->name); 02575 record_abandoned(qe); 02576 ast_hangup(peer); 02577 return -1; 02578 } 02579 /* Begin Monitoring */ 02580 if (qe->parent->monfmt && *qe->parent->monfmt) { 02581 if (!qe->parent->montype) { 02582 if (option_debug) 02583 ast_log(LOG_DEBUG, "Starting Monitor as requested.\n"); 02584 monitorfilename = pbx_builtin_getvar_helper(qe->chan, "MONITOR_FILENAME"); 02585 if (pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC") || pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC_ARGS")) 02586 which = qe->chan; 02587 else 02588 which = peer; 02589 if (monitorfilename) 02590 ast_monitor_start(which, qe->parent->monfmt, monitorfilename, 1 ); 02591 else if (qe->chan->cdr) 02592 ast_monitor_start(which, qe->parent->monfmt, qe->chan->cdr->uniqueid, 1 ); 02593 else { 02594 /* Last ditch effort -- no CDR, make up something */ 02595 snprintf(tmpid, sizeof(tmpid), "chan-%lx", ast_random()); 02596 ast_monitor_start(which, qe->parent->monfmt, tmpid, 1 ); 02597 } 02598 if (qe->parent->monjoin) 02599 ast_monitor_setjoinfiles(which, 1); 02600 } else { 02601 if (option_debug) 02602 ast_log(LOG_DEBUG, "Starting MixMonitor as requested.\n"); 02603 monitorfilename = pbx_builtin_getvar_helper(qe->chan, "MONITOR_FILENAME"); 02604 if (!monitorfilename) { 02605 if (qe->chan->cdr) 02606 ast_copy_string(tmpid, qe->chan->cdr->uniqueid, sizeof(tmpid)-1); 02607 else 02608 snprintf(tmpid, sizeof(tmpid), "chan-%lx", ast_random()); 02609 } else { 02610 ast_copy_string(tmpid2, monitorfilename, sizeof(tmpid2)-1); 02611 for (p = tmpid2; *p ; p++) { 02612 if (*p == '^' && *(p+1) == '{') { 02613 *p = '$'; 02614 } 02615 } 02616 02617 memset(tmpid, 0, sizeof(tmpid)); 02618 pbx_substitute_variables_helper(qe->chan, tmpid2, tmpid, sizeof(tmpid) - 1); 02619 } 02620 02621 monitor_exec = pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC"); 02622 monitor_options = pbx_builtin_getvar_helper(qe->chan, "MONITOR_OPTIONS"); 02623 02624 if (monitor_exec) { 02625 ast_copy_string(meid2, monitor_exec, sizeof(meid2)-1); 02626 for (p = meid2; *p ; p++) { 02627 if (*p == '^' && *(p+1) == '{') { 02628 *p = '$'; 02629 } 02630 } 02631 02632 memset(meid, 0, sizeof(meid)); 02633 pbx_substitute_variables_helper(qe->chan, meid2, meid, sizeof(meid) - 1); 02634 } 02635 02636 snprintf(tmpid2, sizeof(tmpid2)-1, "%s.%s", tmpid, qe->parent->monfmt); 02637 02638 mixmonapp = pbx_findapp("MixMonitor"); 02639 02640 if (strchr(tmpid2, '|')) { 02641 ast_log(LOG_WARNING, "monitor-format (in queues.conf) and MONITOR_FILENAME cannot contain a '|'! Not recording.\n"); 02642 mixmonapp = NULL; 02643 } 02644 02645 if (!monitor_options) 02646 monitor_options = ""; 02647 02648 if (strchr(monitor_options, '|')) { 02649 ast_log(LOG_WARNING, "MONITOR_OPTIONS cannot contain a '|'! Not recording.\n"); 02650 mixmonapp = NULL; 02651 } 02652 02653 if (mixmonapp) { 02654 if (!ast_strlen_zero(monitor_exec)) 02655 snprintf(mixmonargs, sizeof(mixmonargs)-1, "%s|b%s|%s", tmpid2, monitor_options, monitor_exec); 02656 else 02657 snprintf(mixmonargs, sizeof(mixmonargs)-1, "%s|b%s", tmpid2, monitor_options); 02658 02659 if (option_debug) 02660 ast_log(LOG_DEBUG, "Arguments being passed to MixMonitor: %s\n", mixmonargs); 02661 02662 ret = pbx_exec(qe->chan, mixmonapp, mixmonargs); 02663 02664 } else 02665 ast_log(LOG_WARNING, "Asked to run MixMonitor on this call, but cannot find the MixMonitor app!\n"); 02666 02667 } 02668 } 02669 /* Drop out of the queue at this point, to prepare for next caller */ 02670 leave_queue(qe); 02671 if (!ast_strlen_zero(url) && ast_channel_supports_html(peer)) { 02672 if (option_debug) 02673 ast_log(LOG_DEBUG, "app_queue: sendurl=%s.\n", url); 02674 ast_channel_sendurl(peer, url); 02675 } 02676 if (qe->parent->setinterfacevar) 02677 pbx_builtin_setvar_helper(qe->chan, "MEMBERINTERFACE", member->interface); 02678 if (!ast_strlen_zero(agi)) { 02679 if (option_debug) 02680 ast_log(LOG_DEBUG, "app_queue: agi=%s.\n", agi); 02681 app = pbx_findapp("agi"); 02682 if (app) { 02683 agiexec = ast_strdupa(agi); 02684 ret = pbx_exec(qe->chan, app, agiexec); 02685 } else 02686 ast_log(LOG_WARNING, "Asked to execute an AGI on this channel, but could not find application (agi)!\n"); 02687 } 02688 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "CONNECT", "%ld|%s", (long)time(NULL) - qe->start, peer->uniqueid); 02689 if (qe->parent->eventwhencalled) 02690 manager_event(EVENT_FLAG_AGENT, "AgentConnect", 02691 "Queue: %s\r\n" 02692 "Uniqueid: %s\r\n" 02693 "Channel: %s\r\n" 02694 "Member: %s\r\n" 02695 "MemberName: %s\r\n" 02696 "Holdtime: %ld\r\n" 02697 "BridgedChannel: %s\r\n" 02698 "%s", 02699 queuename, qe->chan->uniqueid, peer->name, member->interface, member->membername, 02700 (long)time(NULL) - qe->start, peer->uniqueid, 02701 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : ""); 02702 ast_copy_string(oldcontext, qe->chan->context, sizeof(oldcontext)); 02703 ast_copy_string(oldexten, qe->chan->exten, sizeof(oldexten)); 02704 time(&callstart); 02705 02706 if (member->status == AST_DEVICE_NOT_INUSE) 02707 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); 02708 02709 02710 bridge = ast_bridge_call(qe->chan,peer, &bridge_config); 02711 02712 if (strcasecmp(oldcontext, qe->chan->context) || strcasecmp(oldexten, qe->chan->exten)) { 02713 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "TRANSFER", "%s|%s|%ld|%ld", 02714 qe->chan->exten, qe->chan->context, (long) (callstart - qe->start), 02715 (long) (time(NULL) - callstart)); 02716 } else if (qe->chan->_softhangup) { 02717 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "COMPLETECALLER", "%ld|%ld|%d", 02718 (long) (callstart - qe->start), (long) (time(NULL) - callstart), qe->opos); 02719 if (qe->parent->eventwhencalled) 02720 manager_event(EVENT_FLAG_AGENT, "AgentComplete", 02721 "Queue: %s\r\n" 02722 "Uniqueid: %s\r\n" 02723 "Channel: %s\r\n" 02724 "Member: %s\r\n" 02725 "MemberName: %s\r\n" 02726 "HoldTime: %ld\r\n" 02727 "TalkTime: %ld\r\n" 02728 "Reason: caller\r\n" 02729 "%s", 02730 queuename, qe->chan->uniqueid, peer->name, member->interface, member->membername, 02731 (long)(callstart - qe->start), (long)(time(NULL) - callstart), 02732 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : ""); 02733 } else { 02734 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "COMPLETEAGENT", "%ld|%ld|%d", 02735 (long) (callstart - qe->start), (long) (time(NULL) - callstart), qe->opos); 02736 if (qe->parent->eventwhencalled) 02737 manager_event(EVENT_FLAG_AGENT, "AgentComplete", 02738 "Queue: %s\r\n" 02739 "Uniqueid: %s\r\n" 02740 "Channel: %s\r\n" 02741 "MemberName: %s\r\n" 02742 "HoldTime: %ld\r\n" 02743 "TalkTime: %ld\r\n" 02744 "Reason: agent\r\n" 02745 "%s", 02746 queuename, qe->chan->uniqueid, peer->name, member->membername, (long)(callstart - qe->start), 02747 (long)(time(NULL) - callstart), 02748 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : ""); 02749 } 02750 02751 if (bridge != AST_PBX_NO_HANGUP_PEER) 02752 ast_hangup(peer); 02753 update_queue(qe->parent, member, callcompletedinsl); 02754 res = bridge ? bridge : 1; 02755 } 02756 out: 02757 hangupcalls(outgoing, NULL); 02758 02759 return res; 02760 }
static int unload_module | ( | void | ) | [static] |
Definition at line 4507 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().
04508 { 04509 int res; 04510 04511 ast_cli_unregister_multiple(cli_queue, sizeof(cli_queue) / sizeof(struct ast_cli_entry)); 04512 res = ast_manager_unregister("QueueStatus"); 04513 res |= ast_manager_unregister("Queues"); 04514 res |= ast_manager_unregister("QueueStatus"); 04515 res |= ast_manager_unregister("QueueAdd"); 04516 res |= ast_manager_unregister("QueueRemove"); 04517 res |= ast_manager_unregister("QueuePause"); 04518 res |= ast_unregister_application(app_aqm); 04519 res |= ast_unregister_application(app_rqm); 04520 res |= ast_unregister_application(app_pqm); 04521 res |= ast_unregister_application(app_upqm); 04522 res |= ast_unregister_application(app_ql); 04523 res |= ast_unregister_application(app); 04524 res |= ast_custom_function_unregister(&queueagentcount_function); 04525 res |= ast_custom_function_unregister(&queuemembercount_function); 04526 res |= ast_custom_function_unregister(&queuememberlist_function); 04527 res |= ast_custom_function_unregister(&queuewaitingcount_function); 04528 ast_devstate_del(statechange_queue, NULL); 04529 04530 ast_module_user_hangup_all(); 04531 04532 clear_and_free_interfaces(); 04533 04534 return res; 04535 }
static int update_dial_status | ( | struct call_queue * | q, | |
struct member * | member, | |||
int | status | |||
) | [static] |
Definition at line 1545 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(), and wait_for_answer().
01546 { 01547 if (status == AST_CAUSE_BUSY) 01548 status = AST_DEVICE_BUSY; 01549 else if (status == AST_CAUSE_UNREGISTERED) 01550 status = AST_DEVICE_UNAVAILABLE; 01551 else if (status == AST_CAUSE_NOSUCHDRIVER) 01552 status = AST_DEVICE_INVALID; 01553 else 01554 status = AST_DEVICE_UNKNOWN; 01555 return update_status(q, member, status); 01556 }
static int update_queue | ( | struct call_queue * | q, | |
struct member * | member, | |||
int | callcompletedinsl | |||
) | [static] |
Definition at line 2267 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().
02268 { 02269 struct member *cur; 02270 02271 /* Since a reload could have taken place, we have to traverse the list to 02272 be sure it's still valid */ 02273 ast_mutex_lock(&q->lock); 02274 cur = q->members; 02275 while (cur) { 02276 if (member == cur) { 02277 time(&cur->lastcall); 02278 cur->calls++; 02279 break; 02280 } 02281 cur = cur->next; 02282 } 02283 q->callscompleted++; 02284 if (callcompletedinsl) 02285 q->callscompletedinsl++; 02286 ast_mutex_unlock(&q->lock); 02287 return 0; 02288 }
static void update_realtime_members | ( | struct call_queue * | q | ) | [static] |
Definition at line 1170 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 queue_exec().
01171 { 01172 struct ast_config *member_config = NULL; 01173 struct member *m, *prev_m, *next_m; 01174 char *interface = NULL; 01175 01176 member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name", q->name , NULL); 01177 if (!member_config) { 01178 /*This queue doesn't have realtime members*/ 01179 if (option_debug > 2) 01180 ast_log(LOG_DEBUG, "Queue %s has no realtime members defined. No need for update\n", q->name); 01181 return; 01182 } 01183 01184 ast_mutex_lock(&q->lock); 01185 01186 /* Temporarily set non-dynamic members dead so we can detect deleted ones.*/ 01187 for (m = q->members; m; m = m->next) { 01188 if (!m->dynamic) 01189 m->dead = 1; 01190 } 01191 01192 while ((interface = ast_category_browse(member_config, interface))) { 01193 rt_handle_member_record(q, interface, 01194 S_OR(ast_variable_retrieve(member_config, interface, "membername"), interface), 01195 ast_variable_retrieve(member_config, interface, "penalty"), 01196 ast_variable_retrieve(member_config, interface, "paused")); 01197 } 01198 01199 /* Delete all realtime members that have been deleted in DB. */ 01200 m = q->members; 01201 prev_m = NULL; 01202 while (m) { 01203 next_m = m->next; 01204 if (m->dead) { 01205 if (prev_m) { 01206 prev_m->next = next_m; 01207 } else { 01208 q->members = next_m; 01209 } 01210 remove_from_interfaces(m->interface); 01211 q->membercount--; 01212 free(m); 01213 } else { 01214 prev_m = m; 01215 } 01216 m = next_m; 01217 } 01218 ast_mutex_unlock(&q->lock); 01219 }
static int update_status | ( | struct call_queue * | q, | |
struct member * | member, | |||
int | status | |||
) | [static] |
Definition at line 1514 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().
01515 { 01516 struct member *cur; 01517 01518 /* Since a reload could have taken place, we have to traverse the list to 01519 be sure it's still valid */ 01520 ast_mutex_lock(&q->lock); 01521 for (cur = q->members; cur; cur = cur->next) { 01522 if (member != cur) 01523 continue; 01524 01525 cur->status = status; 01526 if (!q->maskmemberstatus) { 01527 manager_event(EVENT_FLAG_AGENT, "QueueMemberStatus", 01528 "Queue: %s\r\n" 01529 "Location: %s\r\n" 01530 "MemberName: %s\r\n" 01531 "Membership: %s\r\n" 01532 "Penalty: %d\r\n" 01533 "CallsTaken: %d\r\n" 01534 "LastCall: %d\r\n" 01535 "Status: %d\r\n" 01536 "Paused: %d\r\n", 01537 q->name, cur->interface, cur->membername, cur->dynamic ? "dynamic" : "static", 01538 cur->penalty, cur->calls, (int)cur->lastcall, cur->status, cur->paused); 01539 } 01540 } 01541 ast_mutex_unlock(&q->lock); 01542 return 0; 01543 }
static int upqm_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Definition at line 3127 of file app_queue.c.
References AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_goto_if_exists(), ast_log(), ast_module_user_add, ast_module_user_remove, ast_opt_priority_jumping, AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), ast_channel::context, ast_channel::exten, member_interface::interface, LOG_WARNING, parse(), pbx_builtin_setvar_helper(), ast_channel::priority, and set_member_paused().
Referenced by load_module().
03128 { 03129 struct ast_module_user *lu; 03130 char *parse; 03131 int priority_jump = 0; 03132 AST_DECLARE_APP_ARGS(args, 03133 AST_APP_ARG(queuename); 03134 AST_APP_ARG(interface); 03135 AST_APP_ARG(options); 03136 ); 03137 03138 if (ast_strlen_zero(data)) { 03139 ast_log(LOG_WARNING, "UnpauseQueueMember requires an argument ([queuename]|interface[|options])\n"); 03140 return -1; 03141 } 03142 03143 parse = ast_strdupa(data); 03144 03145 AST_STANDARD_APP_ARGS(args, parse); 03146 03147 lu = ast_module_user_add(chan); 03148 03149 if (args.options) { 03150 if (strchr(args.options, 'j')) 03151 priority_jump = 1; 03152 } 03153 03154 if (ast_strlen_zero(args.interface)) { 03155 ast_log(LOG_WARNING, "Missing interface argument to PauseQueueMember ([queuename]|interface[|options])\n"); 03156 ast_module_user_remove(lu); 03157 return -1; 03158 } 03159 03160 if (set_member_paused(args.queuename, args.interface, 0)) { 03161 ast_log(LOG_WARNING, "Attempt to unpause interface %s, not found\n", args.interface); 03162 if (priority_jump || ast_opt_priority_jumping) { 03163 if (ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101)) { 03164 pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "NOTFOUND"); 03165 ast_module_user_remove(lu); 03166 return 0; 03167 } 03168 } 03169 ast_module_user_remove(lu); 03170 pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "NOTFOUND"); 03171 return -1; 03172 } 03173 03174 ast_module_user_remove(lu); 03175 pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "UNPAUSED"); 03176 03177 return 0; 03178 }
static int valid_exit | ( | struct queue_ent * | qe, | |
char | digit | |||
) | [static] |
Definition at line 1301 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(), wait_for_answer(), and wait_our_turn().
01302 { 01303 int digitlen = strlen(qe->digits); 01304 01305 /* Prevent possible buffer overflow */ 01306 if (digitlen < sizeof(qe->digits) - 2) { 01307 qe->digits[digitlen] = digit; 01308 qe->digits[digitlen + 1] = '\0'; 01309 } else { 01310 qe->digits[0] = '\0'; 01311 return 0; 01312 } 01313 01314 /* If there's no context to goto, short-circuit */ 01315 if (ast_strlen_zero(qe->context)) 01316 return 0; 01317 01318 /* If the extension is bad, then reset the digits to blank */ 01319 if (!ast_canmatch_extension(qe->chan, qe->context, qe->digits, 1, qe->chan->cid.cid_num)) { 01320 qe->digits[0] = '\0'; 01321 return 0; 01322 } 01323 01324 /* We have an exact match */ 01325 if (!ast_goto_if_exists(qe->chan, qe->context, qe->digits, 1)) { 01326 qe->valid_digits = 1; 01327 /* Return 1 on a successful goto */ 01328 return 1; 01329 } 01330 01331 return 0; 01332 }
static char* vars2manager | ( | struct ast_channel * | chan, | |
char * | vars, | |||
size_t | len | |||
) | [static] |
Definition at line 1600 of file app_queue.c.
References pbx_builtin_serialize_variables().
Referenced by ring_entry(), and try_calling().
01601 { 01602 char *tmp = alloca(len); 01603 01604 if (pbx_builtin_serialize_variables(chan, tmp, len)) { 01605 int i, j; 01606 01607 /* convert "\n" to "\nVariable: " */ 01608 strcpy(vars, "Variable: "); 01609 01610 for (i = 0, j = 10; (i < len - 1) && (j < len - 1); i++, j++) { 01611 vars[j] = tmp[i]; 01612 01613 if (tmp[i + 1] == '\0') 01614 break; 01615 if (tmp[i] == '\n') { 01616 vars[j] = '\r'; 01617 vars[++j] = '\n'; 01618 01619 ast_copy_string(&(vars[j]), "Variable: ", len - j); 01620 j += 9; 01621 } 01622 } 01623 if (j > len - 1) 01624 j = len - 1; 01625 vars[j - 2] = '\r'; 01626 vars[j - 1] = '\n'; 01627 vars[j] = '\0'; 01628 } else { 01629 /* there are no channel variables; leave it blank */ 01630 *vars = '\0'; 01631 } 01632 return vars; 01633 }
static int wait_a_bit | ( | struct queue_ent * | qe | ) | [static] |
Definition at line 2762 of file app_queue.c.
References ast_waitfordigit(), queue_ent::chan, queue_ent::parent, call_queue::retry, and valid_exit().
Referenced by queue_exec().
02763 { 02764 /* Don't need to hold the lock while we setup the outgoing calls */ 02765 int retrywait = qe->parent->retry * 1000; 02766 02767 int res = ast_waitfordigit(qe->chan, retrywait); 02768 if (res > 0 && !valid_exit(qe, res)) 02769 res = 0; 02770 02771 return res; 02772 }
static struct callattempt* wait_for_answer | ( | struct queue_ent * | qe, | |
struct callattempt * | outgoing, | |||
int * | to, | |||
char * | digit, | |||
int | prebusies, | |||
int | caller_disconnect, | |||
int | forwardsallowed | |||
) | [static, read] |
Definition at line 1906 of file app_queue.c.
References ast_channel::_state, accountcode, ast_call(), ast_cdr_busy(), ast_channel_inherit_variables(), AST_CONTROL_ANSWER, AST_CONTROL_BUSY, AST_CONTROL_CONGESTION, AST_CONTROL_HANGUP, AST_CONTROL_OFFHOOK, AST_CONTROL_RINGING, AST_FRAME_CONTROL, AST_FRAME_DTMF, ast_frfree(), ast_hangup(), ast_indicate(), ast_log(), AST_MAX_WATCHERS, ast_read(), ast_request(), AST_STATE_UP, ast_strdup, ast_string_field_set, ast_strlen_zero(), ast_verbose(), ast_waitfor_n(), ast_channel::cdr, ast_channel::cdrflags, callattempt::chan, queue_ent::chan, ast_channel::cid, ast_callerid::cid_ani, ast_callerid::cid_name, ast_callerid::cid_num, ast_callerid::cid_rdnis, ast_channel::context, do_hang(), ast_channel::exten, f, ast_frame::frametype, free, member::interface, LOG_DEBUG, LOG_NOTICE, ast_channel::macroexten, callattempt::member, member::membername, call_queue::name, ast_channel::nativeformats, callattempt::oldstatus, option_verbose, queue_ent::parent, callattempt::q_next, QUEUE_STRATEGY_RINGALL, ring_one(), rna(), S_OR, starttime, callattempt::stillgoing, call_queue::strategy, ast_frame::subclass, ast_channel::tech, call_queue::timeoutrestart, update_dial_status(), valid_exit(), and VERBOSE_PREFIX_3.
01907 { 01908 char *queue = qe->parent->name; 01909 struct callattempt *o; 01910 int status; 01911 int sentringing = 0; 01912 int numbusies = prebusies; 01913 int numnochan = 0; 01914 int stillgoing = 0; 01915 int orig = *to; 01916 struct ast_frame *f; 01917 struct callattempt *peer = NULL; 01918 struct ast_channel *winner; 01919 struct ast_channel *in = qe->chan; 01920 char on[80] = ""; 01921 char membername[80] = ""; 01922 long starttime = 0; 01923 long endtime = 0; 01924 01925 starttime = (long) time(NULL); 01926 01927 while (*to && !peer) { 01928 int numlines, retry, pos = 1; 01929 struct ast_channel *watchers[AST_MAX_WATCHERS]; 01930 watchers[0] = in; 01931 01932 for (retry = 0; retry < 2; retry++) { 01933 numlines = 0; 01934 for (o = outgoing; o; o = o->q_next) { /* Keep track of important channels */ 01935 if (o->stillgoing) { /* Keep track of important channels */ 01936 stillgoing = 1; 01937 if (o->chan) 01938 watchers[pos++] = o->chan; 01939 } 01940 numlines++; 01941 } 01942 if (pos > 1 /* found */ || !stillgoing /* nobody listening */ || 01943 (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) /* ring would not be delivered */) 01944 break; 01945 /* On "ringall" strategy we only move to the next penalty level 01946 when *all* ringing phones are done in the current penalty level */ 01947 ring_one(qe, outgoing, &numbusies); 01948 /* and retry... */ 01949 } 01950 if (pos == 1 /* not found */) { 01951 if (numlines == (numbusies + numnochan)) { 01952 ast_log(LOG_DEBUG, "Everyone is busy at this time\n"); 01953 } else { 01954 ast_log(LOG_NOTICE, "No one is answering queue '%s' (%d/%d/%d)\n", queue, numlines, numbusies, numnochan); 01955 } 01956 *to = 0; 01957 return NULL; 01958 } 01959 winner = ast_waitfor_n(watchers, pos, to); 01960 for (o = outgoing; o; o = o->q_next) { 01961 if (o->stillgoing && (o->chan) && (o->chan->_state == AST_STATE_UP)) { 01962 if (!peer) { 01963 if (option_verbose > 2) 01964 ast_verbose( VERBOSE_PREFIX_3 "%s answered %s\n", o->chan->name, in->name); 01965 peer = o; 01966 } 01967 } else if (o->chan && (o->chan == winner)) { 01968 01969 ast_copy_string(on, o->member->interface, sizeof(on)); 01970 ast_copy_string(membername, o->member->membername, sizeof(membername)); 01971 01972 if (!ast_strlen_zero(o->chan->call_forward) && !forwardsallowed) { 01973 if (option_verbose > 2) 01974 ast_verbose(VERBOSE_PREFIX_3 "Forwarding %s to '%s' prevented.\n", in->name, o->chan->call_forward); 01975 numnochan++; 01976 do_hang(o); 01977 winner = NULL; 01978 continue; 01979 } else if (!ast_strlen_zero(o->chan->call_forward)) { 01980 char tmpchan[256]; 01981 char *stuff; 01982 char *tech; 01983 01984 ast_copy_string(tmpchan, o->chan->call_forward, sizeof(tmpchan)); 01985 if ((stuff = strchr(tmpchan, '/'))) { 01986 *stuff++ = '\0'; 01987 tech = tmpchan; 01988 } else { 01989 snprintf(tmpchan, sizeof(tmpchan), "%s@%s", o->chan->call_forward, o->chan->context); 01990 stuff = tmpchan; 01991 tech = "Local"; 01992 } 01993 /* Before processing channel, go ahead and check for forwarding */ 01994 if (option_verbose > 2) 01995 ast_verbose(VERBOSE_PREFIX_3 "Now forwarding %s to '%s/%s' (thanks to %s)\n", in->name, tech, stuff, o->chan->name); 01996 /* Setup parameters */ 01997 o->chan = ast_request(tech, in->nativeformats, stuff, &status); 01998 if (status != o->oldstatus) 01999 update_dial_status(qe->parent, o->member, status); 02000 if (!o->chan) { 02001 ast_log(LOG_NOTICE, "Unable to create local channel for call forward to '%s/%s'\n", tech, stuff); 02002 o->stillgoing = 0; 02003 numnochan++; 02004 } else { 02005 ast_channel_inherit_variables(in, o->chan); 02006 if (o->chan->cid.cid_num) 02007 free(o->chan->cid.cid_num); 02008 o->chan->cid.cid_num = ast_strdup(in->cid.cid_num); 02009 02010 if (o->chan->cid.cid_name) 02011 free(o->chan->cid.cid_name); 02012 o->chan->cid.cid_name = ast_strdup(in->cid.cid_name); 02013 02014 ast_string_field_set(o->chan, accountcode, in->accountcode); 02015 o->chan->cdrflags = in->cdrflags; 02016 02017 if (in->cid.cid_ani) { 02018 if (o->chan->cid.cid_ani) 02019 free(o->chan->cid.cid_ani); 02020 o->chan->cid.cid_ani = ast_strdup(in->cid.cid_ani); 02021 } 02022 if (o->chan->cid.cid_rdnis) 02023 free(o->chan->cid.cid_rdnis); 02024 o->chan->cid.cid_rdnis = ast_strdup(S_OR(in->macroexten, in->exten)); 02025 if (ast_call(o->chan, tmpchan, 0)) { 02026 ast_log(LOG_NOTICE, "Failed to dial on local channel for call forward to '%s'\n", tmpchan); 02027 do_hang(o); 02028 numnochan++; 02029 } 02030 } 02031 /* Hangup the original channel now, in case we needed it */ 02032 ast_hangup(winner); 02033 continue; 02034 } 02035 f = ast_read(winner); 02036 if (f) { 02037 if (f->frametype == AST_FRAME_CONTROL) { 02038 switch (f->subclass) { 02039 case AST_CONTROL_ANSWER: 02040 /* This is our guy if someone answered. */ 02041 if (!peer) { 02042 if (option_verbose > 2) 02043 ast_verbose( VERBOSE_PREFIX_3 "%s answered %s\n", o->chan->name, in->name); 02044 peer = o; 02045 } 02046 break; 02047 case AST_CONTROL_BUSY: 02048 if (option_verbose > 2) 02049 ast_verbose( VERBOSE_PREFIX_3 "%s is busy\n", o->chan->name); 02050 if (in->cdr) 02051 ast_cdr_busy(in->cdr); 02052 do_hang(o); 02053 endtime = (long)time(NULL); 02054 endtime -= starttime; 02055 rna(endtime*1000, qe, on, membername); 02056 if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) { 02057 if (qe->parent->timeoutrestart) 02058 *to = orig; 02059 ring_one(qe, outgoing, &numbusies); 02060 } 02061 numbusies++; 02062 break; 02063 case AST_CONTROL_CONGESTION: 02064 if (option_verbose > 2) 02065 ast_verbose( VERBOSE_PREFIX_3 "%s is circuit-busy\n", o->chan->name); 02066 if (in->cdr) 02067 ast_cdr_busy(in->cdr); 02068 endtime = (long)time(NULL); 02069 endtime -= starttime; 02070 rna(endtime*1000, qe, on, membername); 02071 do_hang(o); 02072 if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) { 02073 if (qe->parent->timeoutrestart) 02074 *to = orig; 02075 ring_one(qe, outgoing, &numbusies); 02076 } 02077 numbusies++; 02078 break; 02079 case AST_CONTROL_RINGING: 02080 if (option_verbose > 2) 02081 ast_verbose( VERBOSE_PREFIX_3 "%s is ringing\n", o->chan->name); 02082 if (!sentringing) { 02083 #if 0 02084 ast_indicate(in, AST_CONTROL_RINGING); 02085 #endif 02086 sentringing++; 02087 } 02088 break; 02089 case AST_CONTROL_OFFHOOK: 02090 /* Ignore going off hook */ 02091 break; 02092 default: 02093 ast_log(LOG_DEBUG, "Dunno what to do with control type %d\n", f->subclass); 02094 } 02095 } 02096 ast_frfree(f); 02097 } else { 02098 endtime = (long) time(NULL) - starttime; 02099 rna(endtime * 1000, qe, on, membername); 02100 do_hang(o); 02101 if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) { 02102 if (qe->parent->timeoutrestart) 02103 *to = orig; 02104 ring_one(qe, outgoing, &numbusies); 02105 } 02106 } 02107 } 02108 } 02109 if (winner == in) { 02110 f = ast_read(in); 02111 if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP))) { 02112 /* Got hung up */ 02113 *to = -1; 02114 if (f) 02115 ast_frfree(f); 02116 return NULL; 02117 } 02118 if ((f->frametype == AST_FRAME_DTMF) && caller_disconnect && (f->subclass == '*')) { 02119 if (option_verbose > 3) 02120 ast_verbose(VERBOSE_PREFIX_3 "User hit %c to disconnect call.\n", f->subclass); 02121 *to = 0; 02122 ast_frfree(f); 02123 return NULL; 02124 } 02125 if ((f->frametype == AST_FRAME_DTMF) && valid_exit(qe, f->subclass)) { 02126 if (option_verbose > 3) 02127 ast_verbose(VERBOSE_PREFIX_3 "User pressed digit: %c\n", f->subclass); 02128 *to = 0; 02129 *digit = f->subclass; 02130 ast_frfree(f); 02131 return NULL; 02132 } 02133 ast_frfree(f); 02134 } 02135 if (!*to) 02136 rna(orig, qe, on, membername); 02137 } 02138 02139 return peer; 02140 }
static int wait_our_turn | ( | struct queue_ent * | qe, | |
int | ringing, | |||
enum queue_result * | reason | |||
) | [static] |
Definition at line 2210 of file app_queue.c.
References call_queue::announcefrequency, ast_queue_log(), ast_waitfordigit(), queue_ent::chan, queue_ent::expire, get_member_status(), is_our_turn(), leave_queue(), call_queue::leavewhenempty, queue_ent::max_penalty, call_queue::name, queue_ent::opos, queue_ent::parent, call_queue::periodicannouncefrequency, queue_ent::pos, QUEUE_EMPTY_STRICT, QUEUE_LEAVEEMPTY, QUEUE_LEAVEUNAVAIL, QUEUE_NO_MEMBERS, QUEUE_NO_REACHABLE_MEMBERS, QUEUE_TIMEOUT, RECHECK, say_periodic_announcement(), say_position(), queue_ent::start, and valid_exit().
Referenced by queue_exec().
02211 { 02212 int res = 0; 02213 02214 /* This is the holding pen for callers 2 through maxlen */ 02215 for (;;) { 02216 enum queue_member_status stat; 02217 02218 if (is_our_turn(qe)) 02219 break; 02220 02221 /* If we have timed out, break out */ 02222 if (qe->expire && (time(NULL) > qe->expire)) { 02223 *reason = QUEUE_TIMEOUT; 02224 break; 02225 } 02226 02227 stat = get_member_status(qe->parent, qe->max_penalty); 02228 02229 /* leave the queue if no agents, if enabled */ 02230 if (qe->parent->leavewhenempty && (stat == QUEUE_NO_MEMBERS)) { 02231 *reason = QUEUE_LEAVEEMPTY; 02232 ast_queue_log(qe->parent->name, qe->chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe->pos, qe->opos, (long)time(NULL) - qe->start); 02233 leave_queue(qe); 02234 break; 02235 } 02236 02237 /* leave the queue if no reachable agents, if enabled */ 02238 if ((qe->parent->leavewhenempty == QUEUE_EMPTY_STRICT) && (stat == QUEUE_NO_REACHABLE_MEMBERS)) { 02239 *reason = QUEUE_LEAVEUNAVAIL; 02240 ast_queue_log(qe->parent->name, qe->chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe->pos, qe->opos, (long)time(NULL) - qe->start); 02241 leave_queue(qe); 02242 break; 02243 } 02244 02245 /* Make a position announcement, if enabled */ 02246 if (qe->parent->announcefrequency && !ringing && 02247 (res = say_position(qe))) 02248 break; 02249 02250 /* Make a periodic announcement, if enabled */ 02251 if (qe->parent->periodicannouncefrequency && !ringing && 02252 (res = say_periodic_announcement(qe))) 02253 break; 02254 02255 /* Wait a second before checking again */ 02256 if ((res = ast_waitfordigit(qe->chan, RECHECK * 1000))) { 02257 if (res > 0 && !valid_exit(qe, res)) 02258 res = 0; 02259 else 02260 break; 02261 } 02262 } 02263 02264 return res; 02265 }
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 4478 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 4483 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 4473 of file app_queue.c.
char* descrip [static] |
Definition at line 131 of file app_queue.c.
enum queue_result id |
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 4467 of file app_queue.c.
char qrm_cmd_usage[] [static] |
Initial value:
"Usage: queue remove member <channel> from <queue>\n"
Definition at line 4470 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 4463 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(), reqprep(), sendtext_exec(), set_queue_result(), sip_alloc(), and sip_show_channel().
int use_weight = 0 [static] |