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