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