True call queues with optional send URL on answer. More...
#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 | interfaces |
struct | member |
struct | member_count |
struct | member_interface |
struct | queue_ent |
struct | queue_transfer_ds |
struct | queues |
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, QUEUE_STRATEGY_LINEAR, QUEUE_STRATEGY_RRORDERED } |
enum | qmc_status { QMC_VALID = 0, QMC_PAUSED, QMC_ACTIVE, QMC_FREE, QMC_ALL } |
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, QUEUE_CONTINUE = 7 } |
Functions | |
static int | __queues_show (struct mansession *s, int manager, int fd, int argc, char **argv) |
static void | __reg_module (void) |
static void | __unreg_module (void) |
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, const char *state_interface) |
static struct call_queue * | alloc_queue (const char *queuename) |
static int | aqm_exec (struct ast_channel *chan, void *data) |
static int | attended_transfer_occurred (struct ast_channel *chan) |
mechanism to tell if a queue caller was atxferred by a queue member. | |
static int | calc_metric (struct call_queue *q, struct member *mem, int pos, struct queue_ent *qe, struct callattempt *tmp) |
Calculate the metric of each member in the outgoing callattempts. | |
static void | clear_and_free_interfaces (void) |
static void | clear_queue (struct call_queue *q) |
static int | cli_queue_member_count (int fd, int argc, char **argv) |
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_member_count (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, const char *state_interface) |
allocate space for new queue member and set fields based on parameters passed | |
static void | destroy_queue (void *obj) |
static void * | device_state_thread (void *data) |
Consumer of the statechange queue. | |
static void | do_hang (struct callattempt *o) |
common hangup actions | |
static void | dump_queue_members (struct call_queue *pm_queue) |
static struct callattempt * | find_best (struct callattempt *outgoing) |
find the entry with the best metric, or NULL | |
static struct call_queue * | find_queue_by_name_rt (const char *queuename, struct ast_variable *queue_vars, struct ast_config *member_config) |
Reload a single queue via realtime. | |
static void | free_members (struct call_queue *q, int all) |
static enum queue_member_status | get_member_status (struct call_queue *q, int max_penalty) |
Check if members are available. | |
static int | handle_queue_add_member (int fd, int argc, char *argv[]) |
static int | handle_queue_remove_member (int fd, int argc, char *argv[]) |
static void * | handle_statechange (struct statechange *sc) |
set a member's status based on device state of that member's interface | |
static void | hangupcalls (struct callattempt *outgoing, struct ast_channel *exception) |
static void | init_queue (struct call_queue *q) |
static void | insert_entry (struct call_queue *q, struct queue_ent *prev, struct queue_ent *new, int *pos) |
Insert the 'new' entry after the 'prev' entry of queue 'q'. | |
static char * | int2strat (int strategy) |
static struct member * | interface_exists (struct call_queue *q, const char *interface) |
static int | interface_exists_global (const char *interface) |
static int | is_our_turn (struct queue_ent *qe) |
Check if we should start attempting to call queue members. | |
static int | join_queue (char *queuename, struct queue_ent *qe, enum queue_result *reason) |
static void | leave_queue (struct queue_ent *qe) |
static int | load_module (void) |
static struct call_queue * | load_realtime_queue (const char *queuename) |
static int | manager_add_queue_member (struct mansession *s, const struct message *m) |
static int | manager_pause_queue_member (struct mansession *s, const struct message *m) |
static int | manager_queue_member_count (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 | num_available_members (struct call_queue *q) |
Get the number of members available to accept a call. | |
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 | qmc_handler (const char *queuename, char *buffer, int len) |
static int | queue_exec (struct ast_channel *chan, void *data) |
The starting point for all queue calls. | |
static int | queue_function_exists (struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len) |
static int | queue_function_queuemembercount (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_queuememberpaused (struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len) |
static int | queue_function_queuememberstatus (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 int | queue_member_count (const char *qname, struct member_count *qmc) |
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 | queue_transfer_destroy (void *data) |
static void | queue_transfer_fixup (void *data, struct ast_channel *old_chan, struct ast_channel *new_chan) |
Log an attended transfer when a queue caller channel is masqueraded. | |
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 void | remove_queue (struct call_queue *q) |
removes a call_queue from the list of call_queues | |
static int | ring_entry (struct queue_ent *qe, struct callattempt *tmp, int *busies) |
Part 2 of ring_one. | |
static int | ring_one (struct queue_ent *qe, struct callattempt *outgoing, int *busies) |
Place a call to a queue member. | |
static void | rna (int rnatime, struct queue_ent *qe, char *interface, char *membername, int pause) |
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, const char *state_interface) |
static int | say_periodic_announcement (struct queue_ent *qe) |
static int | say_position (struct queue_ent *qe) |
static int | set_member_paused (const char *queuename, const char *interface, int paused) |
static void | set_queue_result (struct ast_channel *chan, enum queue_result res) |
sets the QUEUESTATUS channel variable | |
static struct ast_datastore * | setup_transfer_datastore (struct queue_ent *qe, struct member *member, time_t starttime, int callcompletedinsl) |
create a datastore for storing relevant info to log attended transfers in the queue_log | |
static int | statechange_queue (const char *dev, int state, void *ign) |
Producer of the statechange queue. | |
static int | store_next_lin (struct queue_ent *qe, struct callattempt *outgoing) |
static int | store_next_rr (struct queue_ent *qe, struct callattempt *outgoing) |
static int | strat2int (const char *strategy) |
static int | try_calling (struct queue_ent *qe, const char *options, char *announceoverride, const char *url, int *tries, int *noption, const char *agi) |
A large function which calls members, updates statistics, and bridges the caller and a member. | |
static int | unload_module (void) |
static int | update_queue (struct call_queue *q, struct member *member, int callcompletedinsl) |
static int | update_realtime_member_field (struct member *mem, const char *queue_name, const char *field, const char *value) |
static void | update_realtime_members (struct call_queue *q) |
static int | update_status (const char *interface, const int status) |
static int | upqm_exec (struct ast_channel *chan, void *data) |
static int | valid_exit (struct queue_ent *qe, char digit) |
static char * | vars2manager (struct ast_channel *chan, char *vars, size_t len) |
static int | wait_a_bit (struct queue_ent *qe) |
static struct callattempt * | wait_for_answer (struct queue_ent *qe, struct callattempt *outgoing, int *to, char *digit, int prebusies, int caller_disconnect, int forwardsallowed) |
Wait for a member to answer the call. | |
static int | wait_our_turn (struct queue_ent *qe, int ringing, enum queue_result *reason) |
The waiting areas for callers who are not actively calling members. | |
Variables | |
static struct ast_module_info | __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT | AST_MODFLAG_BUILDSUM, .description = "True Call Queueing" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "361d7bb937402d51e4658efb5b4d76e4" , .load = load_module, .unload = unload_module, .reload = reload, } |
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 const struct ast_module_info * | ast_module_info = &__mod_info |
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 | |
struct { | |
struct statechange * first | |
struct statechange * last | |
} state_change_q | |
unsigned int stop:1 | |
pthread_t thread | |
} | device_state |
Data used by the device state thread. | |
static int | montype_default = 0 |
queues.conf [general] option | |
static const char * | pm_family = "Queue/PersistentMembers" |
Persistent Members astdb family. | |
static char | qam_cmd_usage [] |
static char | qmc_cmd_usage [] |
static char | qrm_cmd_usage [] |
static int | queue_debug = 0 |
queues.conf [general] extra debug option | |
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_datastore_info | queue_transfer_info |
a datastore used to help correctly log attended transfers of queue callers | |
static struct ast_custom_function | queueagentcount_function |
static struct ast_custom_function | queueexists_function |
static struct ast_custom_function | queuemembercount_function |
static struct ast_custom_function | queuememberlist_function |
static struct ast_custom_function | queuememberpaused_function |
static struct ast_custom_function | queuememberstatus_function |
static struct ast_custom_function | queuewaitingcount_function |
static int | shared_lastcall = 0 |
queues.conf [general] option | |
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 |
True call queues with optional send URL on answer.
Each dynamic agent in each queue is now stored in the astdb. When asterisk is restarted, each agent will be automatically readded into their recorded queues. This feature can be configured with the 'persistent_members=<1|0>' setting in the '[general]' category in queues.conf. The default is on.
Patch Version 1.07 2003-12-24 01
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 |
Definition at line 406 of file app_queue.c.
Referenced by queue_set_param().
#define ANNOUNCEHOLDTIME_ONCE 2 |
Definition at line 407 of file app_queue.c.
Referenced by queue_set_param(), and say_position().
#define AST_MAX_WATCHERS 256 |
Definition at line 2318 of file app_queue.c.
#define DEFAULT_RETRY 5 |
Definition at line 141 of file app_queue.c.
Referenced by init_queue(), and queue_set_param().
#define DEFAULT_TIMEOUT 15 |
Definition at line 142 of file app_queue.c.
Referenced by queue_set_param().
#define MAX_PERIODIC_ANNOUNCEMENTS 10 |
Definition at line 144 of file app_queue.c.
Referenced by init_queue(), queue_set_param(), and say_periodic_announcement().
#define PM_MAX_LEN 8192 |
Definition at line 282 of file app_queue.c.
Referenced by dump_queue_members(), and reload_queue_members().
#define QUEUE_EMPTY_NORMAL 1 |
Definition at line 404 of file app_queue.c.
Referenced by queue_set_param().
#define QUEUE_EMPTY_STRICT 2 |
Definition at line 405 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 408 of file app_queue.c.
Referenced by queue_set_param(), ring_entry(), and try_calling().
#define RECHECK 1 |
Definition at line 143 of file app_queue.c.
Referenced by wait_our_turn().
#define RES_EXISTS (-1) |
Definition at line 147 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 149 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 150 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 146 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 148 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 | |
QUEUE_STRATEGY_LINEAR | |
QUEUE_STRATEGY_RRORDERED |
Definition at line 116 of file app_queue.c.
00116 { 00117 QUEUE_STRATEGY_RINGALL = 0, 00118 QUEUE_STRATEGY_ROUNDROBIN, 00119 QUEUE_STRATEGY_LEASTRECENT, 00120 QUEUE_STRATEGY_FEWESTCALLS, 00121 QUEUE_STRATEGY_RANDOM, 00122 QUEUE_STRATEGY_RRMEMORY, 00123 QUEUE_STRATEGY_LINEAR, 00124 QUEUE_STRATEGY_RRORDERED, 00125 };
enum qmc_status |
Definition at line 4514 of file app_queue.c.
04514 { 04515 QMC_VALID = 0, /* Count valid members */ 04516 QMC_PAUSED, /* Count paused members */ 04517 QMC_ACTIVE, /* Count active members */ 04518 QMC_FREE, /* Count free members */ 04519 QMC_ALL /* Count all queue members */ 04520 };
enum queue_member_status |
Definition at line 584 of file app_queue.c.
00584 { 00585 QUEUE_NO_MEMBERS, 00586 QUEUE_NO_REACHABLE_MEMBERS, 00587 QUEUE_NORMAL 00588 };
enum queue_result |
QUEUE_UNKNOWN | |
QUEUE_TIMEOUT | |
QUEUE_JOINEMPTY | |
QUEUE_LEAVEEMPTY | |
QUEUE_JOINUNAVAIL | |
QUEUE_LEAVEUNAVAIL | |
QUEUE_FULL | |
QUEUE_CONTINUE |
Definition at line 302 of file app_queue.c.
00302 { 00303 QUEUE_UNKNOWN = 0, 00304 QUEUE_TIMEOUT = 1, 00305 QUEUE_JOINEMPTY = 2, 00306 QUEUE_LEAVEEMPTY = 3, 00307 QUEUE_JOINUNAVAIL = 4, 00308 QUEUE_LEAVEUNAVAIL = 5, 00309 QUEUE_FULL = 6, 00310 QUEUE_CONTINUE = 7, 00311 };
static int __queues_show | ( | struct mansession * | s, | |
int | manager, | |||
int | fd, | |||
int | argc, | |||
char ** | argv | |||
) | [static] |
Definition at line 5126 of file app_queue.c.
References ao2_container_count(), ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next(), ao2_lock(), ao2_ref(), ao2_unlock(), ast_build_string(), ast_category_browse(), ast_check_realtime(), ast_cli(), ast_config_destroy(), AST_LIST_EMPTY, AST_LIST_LOCK, AST_LIST_NEXT, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_load_realtime_multientry(), ast_strlen_zero(), astman_append(), member::calls, call_queue::callsabandoned, call_queue::callscompleted, call_queue::callscompletedinsl, queue_ent::chan, call_queue::count, devstate2str(), member::dynamic, call_queue::head, call_queue::holdtime, int2strat(), member::interface, member::lastcall, load_realtime_queue(), call_queue::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::ringlimit, call_queue::servicelevel, queue_ent::start, member::status, call_queue::strategy, and call_queue::weight.
Referenced by manager_queues_show(), and queue_show().
05127 { 05128 struct call_queue *q; 05129 struct queue_ent *qe; 05130 struct member *mem; 05131 int pos, queue_show; 05132 time_t now; 05133 char max_buf[150]; 05134 char *max; 05135 size_t max_left; 05136 float sl = 0; 05137 char *term = manager ? "\r\n" : "\n"; 05138 struct ao2_iterator mem_iter; 05139 05140 time(&now); 05141 if (argc == 2) 05142 queue_show = 0; 05143 else if (argc == 3) 05144 queue_show = 1; 05145 else 05146 return RESULT_SHOWUSAGE; 05147 05148 /* We only want to load realtime queues when a specific queue is asked for. */ 05149 if (queue_show) { 05150 load_realtime_queue(argv[2]); 05151 } else if (ast_check_realtime("queues")) { 05152 struct ast_config *cfg = ast_load_realtime_multientry("queues", "name LIKE", "%", (char *) NULL); 05153 char *queuename; 05154 if (cfg) { 05155 for (queuename = ast_category_browse(cfg, NULL); !ast_strlen_zero(queuename); queuename = ast_category_browse(cfg, queuename)) { 05156 load_realtime_queue(queuename); 05157 } 05158 ast_config_destroy(cfg); 05159 } 05160 } 05161 05162 AST_LIST_LOCK(&queues); 05163 if (AST_LIST_EMPTY(&queues)) { 05164 AST_LIST_UNLOCK(&queues); 05165 if (queue_show) { 05166 if (s) 05167 astman_append(s, "No such queue: %s.%s",argv[2], term); 05168 else 05169 ast_cli(fd, "No such queue: %s.%s",argv[2], term); 05170 } else { 05171 if (s) 05172 astman_append(s, "No queues.%s", term); 05173 else 05174 ast_cli(fd, "No queues.%s", term); 05175 } 05176 return RESULT_SUCCESS; 05177 } 05178 AST_LIST_TRAVERSE(&queues, q, list) { 05179 ao2_lock(q); 05180 if (queue_show) { 05181 if (strcasecmp(q->name, argv[2]) != 0) { 05182 ao2_unlock(q); 05183 if (!AST_LIST_NEXT(q, list)) { 05184 ast_cli(fd, "No such queue: %s.%s",argv[2], term); 05185 break; 05186 } 05187 continue; 05188 } 05189 } 05190 max_buf[0] = '\0'; 05191 max = max_buf; 05192 max_left = sizeof(max_buf); 05193 if (q->maxlen) 05194 ast_build_string(&max, &max_left, "%d", q->maxlen); 05195 else 05196 ast_build_string(&max, &max_left, "unlimited"); 05197 sl = 0; 05198 if (q->callscompleted > 0) 05199 sl = 100 * ((float) q->callscompletedinsl / (float) q->callscompleted); 05200 if (s) 05201 astman_append(s, "%-12.12s has %d calls (max %s) in '%s' strategy (%ds holdtime), R:%d, W:%d, C:%d, A:%d, SL:%2.1f%% within %ds%s", 05202 q->name, q->count, max_buf, int2strat(q->strategy), q->holdtime, q->ringlimit, 05203 q->weight, q->callscompleted, q->callsabandoned, sl, q->servicelevel, term); 05204 else 05205 ast_cli(fd, "%-12.12s has %d calls (max %s) in '%s' strategy (%ds holdtime), R:%d, W:%d, C:%d, A:%d, SL:%2.1f%% within %ds%s", 05206 q->name, q->count, max_buf, int2strat(q->strategy), q->holdtime, q->ringlimit, 05207 q->weight, q->callscompleted, q->callsabandoned, sl, q->servicelevel, term); 05208 if (ao2_container_count(q->members)) { 05209 if (s) 05210 astman_append(s, " Members: %s", term); 05211 else 05212 ast_cli(fd, " Members: %s", term); 05213 mem_iter = ao2_iterator_init(q->members, 0); 05214 while ((mem = ao2_iterator_next(&mem_iter))) { 05215 max_buf[0] = '\0'; 05216 max = max_buf; 05217 max_left = sizeof(max_buf); 05218 if (strcasecmp(mem->membername, mem->interface)) { 05219 ast_build_string(&max, &max_left, " (%s)", mem->interface); 05220 } 05221 if (mem->penalty) 05222 ast_build_string(&max, &max_left, " with penalty %d", mem->penalty); 05223 if (mem->dynamic) 05224 ast_build_string(&max, &max_left, " (dynamic)"); 05225 if (mem->realtime) 05226 ast_build_string(&max, &max_left, " (realtime)"); 05227 if (mem->paused) 05228 ast_build_string(&max, &max_left, " (paused)"); 05229 ast_build_string(&max, &max_left, " (%s)", devstate2str(mem->status)); 05230 if (mem->calls) { 05231 ast_build_string(&max, &max_left, " has taken %d calls (last was %ld secs ago)", 05232 mem->calls, (long) (time(NULL) - mem->lastcall)); 05233 } else 05234 ast_build_string(&max, &max_left, " has taken no calls yet"); 05235 if (s) 05236 astman_append(s, " %s%s%s", mem->membername, max_buf, term); 05237 else 05238 ast_cli(fd, " %s%s%s", mem->membername, max_buf, term); 05239 ao2_ref(mem, -1); 05240 } 05241 ao2_iterator_destroy(&mem_iter); 05242 } else if (s) 05243 astman_append(s, " No Members%s", term); 05244 else 05245 ast_cli(fd, " No Members%s", term); 05246 if (q->head) { 05247 pos = 1; 05248 if (s) 05249 astman_append(s, " Callers: %s", term); 05250 else 05251 ast_cli(fd, " Callers: %s", term); 05252 for (qe = q->head; qe; qe = qe->next) { 05253 if (s) 05254 astman_append(s, " %d. %s (wait: %ld:%2.2ld, prio: %d)%s", 05255 pos++, qe->chan->name, (long) (now - qe->start) / 60, 05256 (long) (now - qe->start) % 60, qe->prio, term); 05257 else 05258 ast_cli(fd, " %d. %s (wait: %ld:%2.2ld, prio: %d)%s", pos++, 05259 qe->chan->name, (long) (now - qe->start) / 60, 05260 (long) (now - qe->start) % 60, qe->prio, term); 05261 } 05262 } else if (s) 05263 astman_append(s, " No Callers%s", term); 05264 else 05265 ast_cli(fd, " No Callers%s", term); 05266 if (s) 05267 astman_append(s, "%s", term); 05268 else 05269 ast_cli(fd, "%s", term); 05270 ao2_unlock(q); 05271 if (queue_show) 05272 break; 05273 } 05274 AST_LIST_UNLOCK(&queues); 05275 return RESULT_SUCCESS; 05276 }
static void __reg_module | ( | void | ) | [static] |
Definition at line 5960 of file app_queue.c.
static void __unreg_module | ( | void | ) | [static] |
Definition at line 5960 of file app_queue.c.
static int add_to_interfaces | ( | const char * | interface | ) | [static] |
Definition at line 945 of file app_queue.c.
References ast_calloc, ast_copy_string(), 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().
00946 { 00947 struct member_interface *curint; 00948 00949 AST_LIST_LOCK(&interfaces); 00950 AST_LIST_TRAVERSE(&interfaces, curint, list) { 00951 if (!strcasecmp(curint->interface, interface)) 00952 break; 00953 } 00954 00955 if (curint) { 00956 AST_LIST_UNLOCK(&interfaces); 00957 return 0; 00958 } 00959 00960 if (option_debug) 00961 ast_log(LOG_DEBUG, "Adding %s to the list of interfaces that make up all of our queue members.\n", interface); 00962 00963 if ((curint = ast_calloc(1, sizeof(*curint)))) { 00964 ast_copy_string(curint->interface, interface, sizeof(curint->interface)); 00965 AST_LIST_INSERT_HEAD(&interfaces, curint, list); 00966 } 00967 AST_LIST_UNLOCK(&interfaces); 00968 00969 return 0; 00970 }
static int add_to_queue | ( | const char * | queuename, | |
const char * | interface, | |||
const char * | membername, | |||
int | penalty, | |||
int | paused, | |||
int | dump, | |||
const char * | state_interface | |||
) | [static] |
Definition at line 3730 of file app_queue.c.
References add_to_interfaces(), ao2_lock(), ao2_ref(), ao2_unlock(), AST_LIST_LOCK, AST_LIST_UNLOCK, member::calls, create_queue_member(), dump_queue_members(), member::dynamic, EVENT_FLAG_AGENT, member::interface, interface_exists(), member::lastcall, load_realtime_queue(), 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, member::state_interface, and member::status.
Referenced by aqm_exec(), handle_queue_add_member(), manager_add_queue_member(), and reload_queue_members().
03731 { 03732 struct call_queue *q; 03733 struct member *new_member, *old_member; 03734 int res = RES_NOSUCHQUEUE; 03735 03736 /* \note Ensure the appropriate realtime queue is loaded. Note that this 03737 * short-circuits if the queue is already in memory. */ 03738 if (!(q = load_realtime_queue(queuename))) 03739 return res; 03740 03741 AST_LIST_LOCK(&queues); 03742 03743 ao2_lock(q); 03744 if ((old_member = interface_exists(q, interface)) == NULL) { 03745 if ((new_member = create_queue_member(interface, membername, penalty, paused, state_interface))) { 03746 add_to_interfaces(new_member->state_interface); 03747 new_member->dynamic = 1; 03748 ao2_link(q->members, new_member); 03749 q->membercount++; 03750 manager_event(EVENT_FLAG_AGENT, "QueueMemberAdded", 03751 "Queue: %s\r\n" 03752 "Location: %s\r\n" 03753 "MemberName: %s\r\n" 03754 "Membership: %s\r\n" 03755 "Penalty: %d\r\n" 03756 "CallsTaken: %d\r\n" 03757 "LastCall: %d\r\n" 03758 "Status: %d\r\n" 03759 "Paused: %d\r\n", 03760 q->name, new_member->interface, new_member->membername, 03761 "dynamic", 03762 new_member->penalty, new_member->calls, (int) new_member->lastcall, 03763 new_member->status, new_member->paused); 03764 03765 ao2_ref(new_member, -1); 03766 new_member = NULL; 03767 03768 if (dump) 03769 dump_queue_members(q); 03770 03771 res = RES_OKAY; 03772 } else { 03773 res = RES_OUTOFMEMORY; 03774 } 03775 } else { 03776 ao2_ref(old_member, -1); 03777 res = RES_EXISTS; 03778 } 03779 ao2_unlock(q); 03780 AST_LIST_UNLOCK(&queues); 03781 03782 return res; 03783 }
static struct call_queue* alloc_queue | ( | const char * | queuename | ) | [static, read] |
Definition at line 842 of file app_queue.c.
References ao2_alloc(), ast_copy_string(), destroy_queue(), and call_queue::name.
Referenced by find_queue_by_name_rt(), and reload_queues().
00843 { 00844 struct call_queue *q; 00845 00846 if ((q = ao2_alloc(sizeof(*q), destroy_queue))) { 00847 ast_copy_string(q->name, queuename, sizeof(q->name)); 00848 } 00849 return q; 00850 }
static int aqm_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Definition at line 4111 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().
04112 { 04113 int res=-1; 04114 struct ast_module_user *lu; 04115 char *parse, *temppos = NULL; 04116 int priority_jump = 0; 04117 AST_DECLARE_APP_ARGS(args, 04118 AST_APP_ARG(queuename); 04119 AST_APP_ARG(interface); 04120 AST_APP_ARG(penalty); 04121 AST_APP_ARG(options); 04122 AST_APP_ARG(membername); 04123 AST_APP_ARG(state_interface); 04124 ); 04125 int penalty = 0; 04126 04127 if (ast_strlen_zero(data)) { 04128 ast_log(LOG_WARNING, "AddQueueMember requires an argument (queuename[|interface[|penalty[|options[|membername[|state_interface]]]]])\n"); 04129 return -1; 04130 } 04131 04132 parse = ast_strdupa(data); 04133 04134 AST_STANDARD_APP_ARGS(args, parse); 04135 04136 lu = ast_module_user_add(chan); 04137 04138 if (ast_strlen_zero(args.interface)) { 04139 args.interface = ast_strdupa(chan->name); 04140 temppos = strrchr(args.interface, '-'); 04141 if (temppos) 04142 *temppos = '\0'; 04143 } 04144 04145 if (!ast_strlen_zero(args.penalty)) { 04146 if ((sscanf(args.penalty, "%30d", &penalty) != 1) || penalty < 0) { 04147 ast_log(LOG_WARNING, "Penalty '%s' is invalid, must be an integer >= 0\n", args.penalty); 04148 penalty = 0; 04149 } 04150 } 04151 04152 if (args.options) { 04153 if (strchr(args.options, 'j')) 04154 priority_jump = 1; 04155 } 04156 04157 switch (add_to_queue(args.queuename, args.interface, args.membername, penalty, 0, queue_persistent_members, args.state_interface)) { 04158 case RES_OKAY: 04159 ast_queue_log(args.queuename, chan->uniqueid, args.interface, "ADDMEMBER", "%s", ""); 04160 ast_log(LOG_NOTICE, "Added interface '%s' to queue '%s'\n", args.interface, args.queuename); 04161 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "ADDED"); 04162 res = 0; 04163 break; 04164 case RES_EXISTS: 04165 ast_log(LOG_WARNING, "Unable to add interface '%s' to queue '%s': Already there\n", args.interface, args.queuename); 04166 if (priority_jump || ast_opt_priority_jumping) 04167 ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101); 04168 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "MEMBERALREADY"); 04169 res = 0; 04170 break; 04171 case RES_NOSUCHQUEUE: 04172 ast_log(LOG_WARNING, "Unable to add interface to queue '%s': No such queue\n", args.queuename); 04173 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "NOSUCHQUEUE"); 04174 res = 0; 04175 break; 04176 case RES_OUTOFMEMORY: 04177 ast_log(LOG_ERROR, "Out of memory adding member %s to queue %s\n", args.interface, args.queuename); 04178 break; 04179 } 04180 04181 ast_module_user_remove(lu); 04182 04183 return res; 04184 }
static int attended_transfer_occurred | ( | struct ast_channel * | chan | ) | [static] |
mechanism to tell if a queue caller was atxferred by a queue member.
When a caller is atxferred, then the queue_transfer_info datastore is removed from the channel. If it's still there after the bridge is broken, then the caller was not atxferred.
Definition at line 2920 of file app_queue.c.
References ast_channel_datastore_find(), and queue_transfer_info.
Referenced by try_calling().
02921 { 02922 return ast_channel_datastore_find(chan, &queue_transfer_info, NULL) ? 0 : 1; 02923 }
static int calc_metric | ( | struct call_queue * | q, | |
struct member * | mem, | |||
int | pos, | |||
struct queue_ent * | qe, | |||
struct callattempt * | tmp | |||
) | [static] |
Calculate the metric of each member in the outgoing callattempts.
A numeric metric is given to each member depending on the ring strategy used by the queue. Members with lower metrics will be called before members with higher metrics
Definition at line 2786 of file app_queue.c.
References ast_log(), ast_random(), member::calls, member::interface, member::lastcall, queue_ent::linpos, queue_ent::linwrapped, LOG_DEBUG, LOG_WARNING, queue_ent::max_penalty, callattempt::metric, option_debug, member::penalty, QUEUE_STRATEGY_FEWESTCALLS, QUEUE_STRATEGY_LEASTRECENT, QUEUE_STRATEGY_LINEAR, QUEUE_STRATEGY_RANDOM, QUEUE_STRATEGY_RINGALL, QUEUE_STRATEGY_ROUNDROBIN, QUEUE_STRATEGY_RRMEMORY, QUEUE_STRATEGY_RRORDERED, member::ringcount, call_queue::ringlimit, call_queue::rrpos, call_queue::strategy, and call_queue::wrapped.
Referenced by try_calling().
02787 { 02788 if (qe->max_penalty && (mem->penalty > qe->max_penalty)) 02789 return -1; 02790 02791 switch (q->strategy) { 02792 case QUEUE_STRATEGY_RINGALL: 02793 /* Everyone equal, except for penalty */ 02794 tmp->metric = mem->penalty * 1000000; 02795 break; 02796 case QUEUE_STRATEGY_ROUNDROBIN: 02797 if (!pos) { 02798 if (!q->wrapped) { 02799 /* No more channels, start over */ 02800 q->rrpos = 0; 02801 } else { 02802 /* Prioritize next entry */ 02803 q->rrpos++; 02804 } 02805 q->wrapped = 0; 02806 } 02807 /* Fall through */ 02808 case QUEUE_STRATEGY_RRORDERED: 02809 case QUEUE_STRATEGY_RRMEMORY: 02810 if (pos < q->rrpos) { 02811 tmp->metric = 1000 + pos; 02812 } else { 02813 if (pos > q->rrpos) 02814 /* Indicate there is another priority */ 02815 q->wrapped = 1; 02816 tmp->metric = pos; 02817 } 02818 tmp->metric += mem->penalty * 1000000; 02819 break; 02820 case QUEUE_STRATEGY_LINEAR: 02821 if (pos < qe->linpos) { 02822 tmp->metric = 1000 + pos; 02823 } else { 02824 if (pos > qe->linpos) 02825 /* Indicate there is another priority */ 02826 qe->linwrapped = 1; 02827 tmp->metric = pos; 02828 } 02829 tmp->metric += mem->penalty * 1000000; 02830 break; 02831 case QUEUE_STRATEGY_RANDOM: 02832 tmp->metric = ast_random() % 1000; 02833 tmp->metric += mem->penalty * 1000000; 02834 break; 02835 case QUEUE_STRATEGY_FEWESTCALLS: 02836 tmp->metric = mem->calls; 02837 tmp->metric += mem->penalty * 1000000; 02838 break; 02839 case QUEUE_STRATEGY_LEASTRECENT: 02840 if (!mem->lastcall) 02841 tmp->metric = 0; 02842 else 02843 tmp->metric = 1000000 - (time(NULL) - mem->lastcall); 02844 tmp->metric += mem->penalty * 1000000; 02845 break; 02846 default: 02847 ast_log(LOG_WARNING, "Can't calculate metric for unknown strategy %d\n", q->strategy); 02848 break; 02849 } 02850 if (q->ringlimit && (mem->ringcount >= q->ringlimit)) { 02851 tmp->metric += (mem->ringcount / q->ringlimit) * 10000000; 02852 } 02853 if (option_debug) 02854 ast_log(LOG_DEBUG, "New metric %d for member %s with %d rings (limit %d)\n", 02855 tmp->metric, mem->interface, mem->ringcount, q->ringlimit); 02856 return 0; 02857 }
static void clear_and_free_interfaces | ( | void | ) | [static] |
Definition at line 1024 of file app_queue.c.
References AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, and free.
Referenced by unload_module().
01025 { 01026 struct member_interface *curint; 01027 01028 AST_LIST_LOCK(&interfaces); 01029 while ((curint = AST_LIST_REMOVE_HEAD(&interfaces, list))) 01030 free(curint); 01031 AST_LIST_UNLOCK(&interfaces); 01032 }
static void clear_queue | ( | struct call_queue * | q | ) | [static] |
Definition at line 936 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().
00937 { 00938 q->holdtime = 0; 00939 q->callscompleted = 0; 00940 q->callsabandoned = 0; 00941 q->callscompletedinsl = 0; 00942 q->wrapuptime = 0; 00943 }
static int cli_queue_member_count | ( | int | fd, | |
int | argc, | |||
char ** | argv | |||
) | [static] |
Definition at line 5781 of file app_queue.c.
References ast_cli(), qmc_handler(), RESULT_FAILURE, RESULT_SHOWUSAGE, and RESULT_SUCCESS.
05782 { 05783 char buffer[256] = ""; 05784 char *queuename; 05785 05786 if (argc != 4) { 05787 return RESULT_SHOWUSAGE; 05788 } 05789 queuename = argv[3]; 05790 05791 if (qmc_handler(queuename, buffer, sizeof(buffer)) == RESULT_SUCCESS) { 05792 ast_cli(fd, 05793 "Member count for queue '%s'\n" 05794 "%s\n", 05795 queuename, buffer); 05796 return RESULT_SUCCESS; 05797 } else { 05798 ast_cli(fd, "No such queue: '%s'\n", queuename); 05799 return RESULT_FAILURE; 05800 } 05801 }
static int compare_weight | ( | struct call_queue * | rq, | |
struct member * | member | |||
) | [static] |
Definition at line 1882 of file app_queue.c.
References ao2_find(), ao2_lock(), ao2_ref(), ao2_unlock(), AST_LIST_TRAVERSE, ast_log(), call_queue::count, member::interface, LOG_DEBUG, call_queue::members, call_queue::name, num_available_members(), and call_queue::weight.
Referenced by ring_entry().
01883 { 01884 struct call_queue *q; 01885 struct member *mem; 01886 int found = 0; 01887 01888 /* &qlock and &rq->lock already set by try_calling() 01889 * to solve deadlock */ 01890 AST_LIST_TRAVERSE(&queues, q, list) { 01891 if (q == rq) /* don't check myself, could deadlock */ 01892 continue; 01893 ao2_lock(q); 01894 if (q->count && q->members) { 01895 if ((mem = ao2_find(q->members, member, OBJ_POINTER))) { 01896 ast_log(LOG_DEBUG, "Found matching member %s in queue '%s'\n", mem->interface, q->name); 01897 if (q->weight > rq->weight && q->count >= num_available_members(q)) { 01898 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); 01899 found = 1; 01900 } 01901 ao2_ref(mem, -1); 01902 } 01903 } 01904 ao2_unlock(q); 01905 if (found) 01906 break; 01907 } 01908 return found; 01909 }
static char* complete_queue | ( | const char * | line, | |
const char * | word, | |||
int | pos, | |||
int | state | |||
) | [static] |
Definition at line 5283 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_member_count(), complete_queue_remove_member(), and complete_queue_show().
05284 { 05285 struct call_queue *q; 05286 char *ret = NULL; 05287 int which = 0; 05288 int wordlen = strlen(word); 05289 05290 AST_LIST_LOCK(&queues); 05291 AST_LIST_TRAVERSE(&queues, q, list) { 05292 if (!strncasecmp(word, q->name, wordlen) && ++which > state) { 05293 ret = ast_strdup(q->name); 05294 break; 05295 } 05296 } 05297 AST_LIST_UNLOCK(&queues); 05298 05299 return ret; 05300 }
static char* complete_queue_add_member | ( | const char * | line, | |
const char * | word, | |||
int | pos, | |||
int | state | |||
) | [static] |
Definition at line 5586 of file app_queue.c.
References ast_malloc, ast_strdup, and complete_queue().
05587 { 05588 /* 0 - queue; 1 - add; 2 - member; 3 - <interface>; 4 - to; 5 - <queue>; 6 - penalty; 7 - <penalty>; 8 - as; 9 - <membername> */ 05589 switch (pos) { 05590 case 3: /* Don't attempt to complete name of interface (infinite possibilities) */ 05591 return NULL; 05592 case 4: /* only one possible match, "to" */ 05593 return state == 0 ? ast_strdup("to") : NULL; 05594 case 5: /* <queue> */ 05595 return complete_queue(line, word, pos, state); 05596 case 6: /* only one possible match, "penalty" */ 05597 return state == 0 ? ast_strdup("penalty") : NULL; 05598 case 7: 05599 if (state < 100) { /* 0-99 */ 05600 char *num; 05601 if ((num = ast_malloc(3))) { 05602 sprintf(num, "%d", state); 05603 } 05604 return num; 05605 } else { 05606 return NULL; 05607 } 05608 case 8: /* only one possible match, "as" */ 05609 return state == 0 ? ast_strdup("as") : NULL; 05610 case 9: /* Don't attempt to complete name of member (infinite possibilities) */ 05611 return NULL; 05612 case 10: 05613 return state == 0 ? ast_strdup("state_interface") : NULL; 05614 default: 05615 return NULL; 05616 } 05617 }
static char* complete_queue_member_count | ( | const char * | line, | |
const char * | word, | |||
int | pos, | |||
int | state | |||
) | [static] |
Definition at line 5808 of file app_queue.c.
References complete_queue().
05809 { 05810 /* 0 - queue; 1 - member; 2 - count; 3 - <queue> */ 05811 switch (pos) { 05812 case 3: /* <queue> */ 05813 return complete_queue(line, word, pos, state); 05814 default: 05815 return NULL; 05816 } 05817 }
static char* complete_queue_remove_member | ( | const char * | line, | |
const char * | word, | |||
int | pos, | |||
int | state | |||
) | [static] |
Definition at line 5654 of file app_queue.c.
References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next(), ao2_lock(), ao2_ref(), ao2_unlock(), AST_LIST_EMPTY, AST_LIST_TRAVERSE, ast_strdup, complete_queue(), member::interface, and call_queue::members.
05655 { 05656 int which = 0; 05657 struct call_queue *q; 05658 struct member *m; 05659 struct ao2_iterator mem_iter; 05660 05661 /* 0 - queue; 1 - remove; 2 - member; 3 - <member>; 4 - from; 5 - <queue> */ 05662 if (pos > 5 || pos < 3) 05663 return NULL; 05664 if (pos == 4) /* only one possible match, 'from' */ 05665 return state == 0 ? ast_strdup("from") : NULL; 05666 05667 if (pos == 5) /* No need to duplicate code */ 05668 return complete_queue(line, word, pos, state); 05669 05670 /* here is the case for 3, <member> */ 05671 if (!AST_LIST_EMPTY(&queues)) { /* XXX unnecessary ? the traverse does that for us */ 05672 AST_LIST_TRAVERSE(&queues, q, list) { 05673 ao2_lock(q); 05674 mem_iter = ao2_iterator_init(q->members, 0); 05675 while ((m = ao2_iterator_next(&mem_iter))) { 05676 if (++which > state) { 05677 char *tmp; 05678 ao2_iterator_destroy(&mem_iter); 05679 ao2_unlock(q); 05680 tmp = ast_strdup(m->interface); 05681 ao2_ref(m, -1); 05682 return tmp; 05683 } 05684 ao2_ref(m, -1); 05685 } 05686 ao2_iterator_destroy(&mem_iter); 05687 ao2_unlock(q); 05688 } 05689 } 05690 05691 return NULL; 05692 }
static char* complete_queue_show | ( | const char * | line, | |
const char * | word, | |||
int | pos, | |||
int | state | |||
) | [static] |
Definition at line 5302 of file app_queue.c.
References complete_queue().
05303 { 05304 if (pos == 2) 05305 return complete_queue(line, word, pos, state); 05306 return NULL; 05307 }
static int compress_char | ( | const char | c | ) | [static] |
Definition at line 852 of file app_queue.c.
Referenced by member_hash_fn().
static struct member* create_queue_member | ( | const char * | interface, | |
const char * | membername, | |||
int | penalty, | |||
int | paused, | |||
const char * | state_interface | |||
) | [static, read] |
allocate space for new queue member and set fields based on parameters passed
Definition at line 817 of file app_queue.c.
References ao2_alloc(), ast_copy_string(), ast_log(), ast_strlen_zero(), member::interface, LOG_WARNING, member::membername, member::paused, member::penalty, member::state_interface, and member::status.
Referenced by add_to_queue(), reload_queues(), and rt_handle_member_record().
00818 { 00819 struct member *cur; 00820 00821 if ((cur = ao2_alloc(sizeof(*cur), NULL))) { 00822 cur->penalty = penalty; 00823 cur->paused = paused; 00824 ast_copy_string(cur->interface, interface, sizeof(cur->interface)); 00825 if (!ast_strlen_zero(state_interface)) { 00826 ast_copy_string(cur->state_interface, state_interface, sizeof(cur->state_interface)); 00827 } else { 00828 ast_copy_string(cur->state_interface, interface, sizeof(cur->state_interface)); 00829 } 00830 if (!ast_strlen_zero(membername)) 00831 ast_copy_string(cur->membername, membername, sizeof(cur->membername)); 00832 else 00833 ast_copy_string(cur->membername, interface, sizeof(cur->membername)); 00834 if (!strchr(cur->interface, '/')) 00835 ast_log(LOG_WARNING, "No location at interface '%s'\n", interface); 00836 cur->status = ast_device_state(cur->state_interface); 00837 } 00838 00839 return cur; 00840 }
static void destroy_queue | ( | void * | obj | ) | [static] |
Definition at line 550 of file app_queue.c.
References ao2_ref(), free_members(), and call_queue::members.
Referenced by alloc_queue().
00551 { 00552 struct call_queue *q = obj; 00553 if (q->members) { 00554 free_members(q, 1); 00555 ao2_ref(q->members, -1); 00556 } 00557 }
static void* device_state_thread | ( | void * | data | ) | [static] |
Consumer of the statechange queue.
Definition at line 765 of file app_queue.c.
References ast_cond_wait(), AST_LIST_REMOVE_HEAD, ast_mutex_lock(), ast_mutex_unlock(), device_state, statechange::entry, free, and handle_statechange().
Referenced by load_module().
00766 { 00767 struct statechange *sc = NULL; 00768 00769 while (!device_state.stop) { 00770 ast_mutex_lock(&device_state.lock); 00771 if (!(sc = AST_LIST_REMOVE_HEAD(&device_state.state_change_q, entry))) { 00772 ast_cond_wait(&device_state.cond, &device_state.lock); 00773 sc = AST_LIST_REMOVE_HEAD(&device_state.state_change_q, entry); 00774 } 00775 ast_mutex_unlock(&device_state.lock); 00776 00777 /* Check to see if we were woken up to see the request to stop */ 00778 if (device_state.stop) 00779 break; 00780 00781 if (!sc) 00782 continue; 00783 00784 handle_statechange(sc); 00785 00786 free(sc); 00787 sc = NULL; 00788 } 00789 00790 if (sc) 00791 free(sc); 00792 00793 while ((sc = AST_LIST_REMOVE_HEAD(&device_state.state_change_q, entry))) 00794 free(sc); 00795 00796 return NULL; 00797 }
static void do_hang | ( | struct callattempt * | o | ) | [static] |
common hangup actions
Definition at line 1912 of file app_queue.c.
References ast_hangup(), callattempt::chan, and callattempt::stillgoing.
Referenced by ring_entry(), and wait_for_answer().
01913 { 01914 o->stillgoing = 0; 01915 ast_hangup(o->chan); 01916 o->chan = NULL; 01917 }
static void dump_queue_members | ( | struct call_queue * | pm_queue | ) | [static] |
Definition at line 3638 of file app_queue.c.
References ao2_iterator_destroy(), 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, PM_MAX_LEN, and member::state_interface.
Referenced by add_to_queue(), remove_from_queue(), and set_member_paused().
03639 { 03640 struct member *cur_member; 03641 char value[PM_MAX_LEN]; 03642 int value_len = 0; 03643 int res; 03644 struct ao2_iterator mem_iter; 03645 03646 memset(value, 0, sizeof(value)); 03647 03648 if (!pm_queue) 03649 return; 03650 03651 mem_iter = ao2_iterator_init(pm_queue->members, 0); 03652 while ((cur_member = ao2_iterator_next(&mem_iter))) { 03653 if (!cur_member->dynamic) { 03654 ao2_ref(cur_member, -1); 03655 continue; 03656 } 03657 03658 res = snprintf(value + value_len, sizeof(value) - value_len, "%s%s;%d;%d;%s;%s", 03659 value_len ? "|" : "", cur_member->interface, cur_member->penalty, cur_member->paused, cur_member->membername, cur_member->state_interface); 03660 03661 ao2_ref(cur_member, -1); 03662 03663 if (res != strlen(value + value_len)) { 03664 ast_log(LOG_WARNING, "Could not create persistent member string, out of space\n"); 03665 break; 03666 } 03667 value_len += res; 03668 } 03669 ao2_iterator_destroy(&mem_iter); 03670 03671 if (value_len && !cur_member) { 03672 if (ast_db_put(pm_family, pm_queue->name, value)) 03673 ast_log(LOG_WARNING, "failed to create persistent dynamic entry!\n"); 03674 } else 03675 /* Delete the entry if the queue is empty or there is an error */ 03676 ast_db_del(pm_family, pm_queue->name); 03677 }
static struct callattempt* find_best | ( | struct callattempt * | outgoing | ) | [static, read] |
find the entry with the best metric, or NULL
Definition at line 2133 of file app_queue.c.
References callattempt::metric, and callattempt::q_next.
Referenced by ring_one(), store_next_lin(), and store_next_rr().
02134 { 02135 struct callattempt *best = NULL, *cur; 02136 02137 for (cur = outgoing; cur; cur = cur->q_next) { 02138 if (cur->stillgoing && /* Not already done */ 02139 !cur->chan && /* Isn't already going */ 02140 (!best || cur->metric < best->metric)) { /* We haven't found one yet, or it's better */ 02141 best = cur; 02142 } 02143 } 02144 02145 return best; 02146 }
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 1262 of file app_queue.c.
References alloc_queue(), ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next(), ao2_lock(), ao2_ref(), ao2_unlink(), ao2_unlock(), ast_category_browse(), ast_copy_string(), AST_LIST_INSERT_HEAD, AST_LIST_TRAVERSE, ast_log(), ast_variable_retrieve(), clear_queue(), call_queue::count, member::dead, call_queue::dead, init_queue(), member_interface::interface, LOG_DEBUG, LOG_WARNING, call_queue::membercount, call_queue::members, ast_variable::name, call_queue::name, ast_variable::next, queue_set_param(), QUEUE_STRATEGY_RINGALL, QUEUE_STRATEGY_ROUNDROBIN, member::realtime, call_queue::realtime, remove_from_interfaces(), remove_queue(), rr_dep_warning(), rt_handle_member_record(), S_OR, member::state_interface, strat2int(), call_queue::strategy, and ast_variable::value.
Referenced by load_realtime_queue().
01263 { 01264 struct ast_variable *v; 01265 struct call_queue *q; 01266 struct member *m; 01267 struct ao2_iterator mem_iter; 01268 char *interface = NULL; 01269 char *tmp, *tmp_name; 01270 char tmpbuf[64]; /* Must be longer than the longest queue param name. */ 01271 01272 /* Find the queue in the in-core list (we will create a new one if not found). */ 01273 AST_LIST_TRAVERSE(&queues, q, list) { 01274 if (!strcasecmp(q->name, queuename)) 01275 break; 01276 } 01277 01278 /* Static queues override realtime. */ 01279 if (q) { 01280 ao2_lock(q); 01281 if (!q->realtime) { 01282 if (q->dead) { 01283 ao2_unlock(q); 01284 return NULL; 01285 } else { 01286 ast_log(LOG_WARNING, "Static queue '%s' already exists. Not loading from realtime\n", q->name); 01287 ao2_unlock(q); 01288 return q; 01289 } 01290 } 01291 } else if (!member_config) 01292 /* Not found in the list, and it's not realtime ... */ 01293 return NULL; 01294 01295 /* Check if queue is defined in realtime. */ 01296 if (!queue_vars) { 01297 /* Delete queue from in-core list if it has been deleted in realtime. */ 01298 if (q) { 01299 /*! \note Hmm, can't seem to distinguish a DB failure from a not 01300 found condition... So we might delete an in-core queue 01301 in case of DB failure. */ 01302 ast_log(LOG_DEBUG, "Queue %s not found in realtime.\n", queuename); 01303 01304 q->dead = 1; 01305 /* Delete if unused (else will be deleted when last caller leaves). */ 01306 if (!q->count) { 01307 /* Delete. */ 01308 ao2_unlock(q); 01309 remove_queue(q); 01310 } else 01311 ao2_unlock(q); 01312 } 01313 return NULL; 01314 } 01315 01316 /* Create a new queue if an in-core entry does not exist yet. */ 01317 if (!q) { 01318 struct ast_variable *tmpvar; 01319 if (!(q = alloc_queue(queuename))) 01320 return NULL; 01321 ao2_lock(q); 01322 clear_queue(q); 01323 q->realtime = 1; 01324 AST_LIST_INSERT_HEAD(&queues, q, list); 01325 01326 /* Due to the fact that the "rrordered" strategy will have a different allocation 01327 * scheme for queue members, we must devise the queue's strategy before other initializations. 01328 * To be specific, the rrordered strategy needs to function like a linked list, meaning the ao2 01329 * container used will have only a single bucket instead of the typical number. 01330 */ 01331 for (tmpvar = queue_vars; tmpvar; tmpvar = tmpvar->next) { 01332 if (!strcasecmp(tmpvar->name, "strategy")) { 01333 q->strategy = strat2int(tmpvar->value); 01334 if (q->strategy < 0) { 01335 ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n", 01336 tmpvar->value, q->name); 01337 q->strategy = QUEUE_STRATEGY_RINGALL; 01338 } 01339 break; 01340 } 01341 } 01342 /* We traversed all variables and didn't find a strategy */ 01343 if (!tmpvar) { 01344 q->strategy = QUEUE_STRATEGY_RINGALL; 01345 } 01346 } 01347 init_queue(q); /* Ensure defaults for all parameters not set explicitly. */ 01348 01349 memset(tmpbuf, 0, sizeof(tmpbuf)); 01350 for (v = queue_vars; v; v = v->next) { 01351 /* Convert to dashes `-' from underscores `_' as the latter are more SQL friendly. */ 01352 if ((tmp = strchr(v->name, '_'))) { 01353 ast_copy_string(tmpbuf, v->name, sizeof(tmpbuf)); 01354 tmp_name = tmpbuf; 01355 tmp = tmp_name; 01356 while ((tmp = strchr(tmp, '_'))) 01357 *tmp++ = '-'; 01358 } else 01359 tmp_name = v->name; 01360 01361 /* NULL values don't get returned from realtime; blank values should 01362 * still get set. If someone doesn't want a value to be set, they 01363 * should set the realtime column to NULL, not blank. */ 01364 queue_set_param(q, tmp_name, v->value, -1, 0); 01365 } 01366 01367 if (q->strategy == QUEUE_STRATEGY_ROUNDROBIN) 01368 rr_dep_warning(); 01369 01370 /* Temporarily set realtime members dead so we can detect deleted ones. 01371 * Also set the membercount correctly for realtime*/ 01372 mem_iter = ao2_iterator_init(q->members, 0); 01373 while ((m = ao2_iterator_next(&mem_iter))) { 01374 q->membercount++; 01375 if (m->realtime) 01376 m->dead = 1; 01377 ao2_ref(m, -1); 01378 } 01379 ao2_iterator_destroy(&mem_iter); 01380 01381 while ((interface = ast_category_browse(member_config, interface))) { 01382 rt_handle_member_record(q, interface, 01383 ast_variable_retrieve(member_config, interface, "membername"), 01384 ast_variable_retrieve(member_config, interface, "penalty"), 01385 ast_variable_retrieve(member_config, interface, "paused"), 01386 S_OR(ast_variable_retrieve(member_config, interface, "state_interface"),interface)); 01387 } 01388 01389 /* Delete all realtime members that have been deleted in DB. */ 01390 mem_iter = ao2_iterator_init(q->members, 0); 01391 while ((m = ao2_iterator_next(&mem_iter))) { 01392 if (m->dead) { 01393 ao2_unlink(q->members, m); 01394 ao2_unlock(q); 01395 remove_from_interfaces(m->state_interface); 01396 ao2_lock(q); 01397 q->membercount--; 01398 } 01399 ao2_ref(m, -1); 01400 } 01401 ao2_iterator_destroy(&mem_iter); 01402 01403 ao2_unlock(q); 01404 01405 return q; 01406 }
static void free_members | ( | struct call_queue * | q, | |
int | all | |||
) | [static] |
Definition at line 1242 of file app_queue.c.
References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next(), ao2_ref(), ao2_unlink(), member::dynamic, call_queue::membercount, call_queue::members, remove_from_interfaces(), and member::state_interface.
Referenced by destroy_queue().
01243 { 01244 /* Free non-dynamic members */ 01245 struct member *cur; 01246 struct ao2_iterator mem_iter = ao2_iterator_init(q->members, 0); 01247 01248 while ((cur = ao2_iterator_next(&mem_iter))) { 01249 if (all || !cur->dynamic) { 01250 ao2_unlink(q->members, cur); 01251 remove_from_interfaces(cur->state_interface); 01252 q->membercount--; 01253 } 01254 ao2_ref(cur, -1); 01255 } 01256 ao2_iterator_destroy(&mem_iter); 01257 }
static enum queue_member_status get_member_status | ( | struct call_queue * | q, | |
int | max_penalty | |||
) | [static] |
Check if members are available.
This function checks to see if members are available to be called. If any member is available, the function immediately returns QUEUE_NORMAL. If no members are available, the appropriate reason why is returned
Definition at line 596 of file app_queue.c.
References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next(), ao2_lock(), ao2_ref(), ao2_unlock(), AST_DEVICE_INVALID, AST_DEVICE_UNAVAILABLE, 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().
00597 { 00598 struct member *member; 00599 struct ao2_iterator mem_iter; 00600 enum queue_member_status result = QUEUE_NO_MEMBERS; 00601 int allpaused = 1, empty = 1; 00602 00603 ao2_lock(q); 00604 mem_iter = ao2_iterator_init(q->members, 0); 00605 while ((member = ao2_iterator_next(&mem_iter))) { 00606 empty = 0; 00607 00608 if (max_penalty && (member->penalty > max_penalty)) { 00609 ao2_ref(member, -1); 00610 continue; 00611 } 00612 00613 if (member->paused) { 00614 ao2_ref(member, -1); 00615 continue; 00616 } else { 00617 allpaused = 0; 00618 } 00619 00620 switch (member->status) { 00621 case AST_DEVICE_INVALID: 00622 /* nothing to do */ 00623 ao2_ref(member, -1); 00624 break; 00625 case AST_DEVICE_UNAVAILABLE: 00626 result = QUEUE_NO_REACHABLE_MEMBERS; 00627 ao2_ref(member, -1); 00628 break; 00629 default: 00630 ao2_unlock(q); 00631 ao2_ref(member, -1); 00632 return QUEUE_NORMAL; 00633 } 00634 } 00635 ao2_iterator_destroy(&mem_iter); 00636 ao2_unlock(q); 00637 00638 if (!empty && allpaused) { 00639 result = QUEUE_NO_REACHABLE_MEMBERS; 00640 } 00641 return result; 00642 }
static int handle_queue_add_member | ( | int | fd, | |
int | argc, | |||
char * | argv[] | |||
) | [static] |
Definition at line 5526 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.
05527 { 05528 char *queuename, *interface, *membername = NULL, *state_interface = NULL; 05529 int penalty; 05530 05531 if ((argc != 6) && (argc != 8) && (argc != 10) && (argc != 12)) { 05532 return RESULT_SHOWUSAGE; 05533 } else if (strcmp(argv[4], "to")) { 05534 return RESULT_SHOWUSAGE; 05535 } else if ((argc == 8) && strcmp(argv[6], "penalty")) { 05536 return RESULT_SHOWUSAGE; 05537 } else if ((argc == 10) && strcmp(argv[8], "as")) { 05538 return RESULT_SHOWUSAGE; 05539 } else if ((argc == 12) && strcmp(argv[10], "state_interface")) { 05540 return RESULT_SHOWUSAGE; 05541 } 05542 05543 queuename = argv[5]; 05544 interface = argv[3]; 05545 if (argc >= 8) { 05546 if (sscanf(argv[7], "%30d", &penalty) == 1) { 05547 if (penalty < 0) { 05548 ast_cli(fd, "Penalty must be >= 0\n"); 05549 penalty = 0; 05550 } 05551 } else { 05552 ast_cli(fd, "Penalty must be an integer >= 0\n"); 05553 penalty = 0; 05554 } 05555 } else { 05556 penalty = 0; 05557 } 05558 05559 if (argc >= 10) { 05560 membername = argv[9]; 05561 } 05562 05563 if (argc >= 12) { 05564 state_interface = argv[11]; 05565 } 05566 05567 switch (add_to_queue(queuename, interface, membername, penalty, 0, queue_persistent_members, state_interface)) { 05568 case RES_OKAY: 05569 ast_queue_log(queuename, "CLI", interface, "ADDMEMBER", "%s", ""); 05570 ast_cli(fd, "Added interface '%s' to queue '%s'\n", interface, queuename); 05571 return RESULT_SUCCESS; 05572 case RES_EXISTS: 05573 ast_cli(fd, "Unable to add interface '%s' to queue '%s': Already there\n", interface, queuename); 05574 return RESULT_FAILURE; 05575 case RES_NOSUCHQUEUE: 05576 ast_cli(fd, "Unable to add interface to queue '%s': No such queue\n", queuename); 05577 return RESULT_FAILURE; 05578 case RES_OUTOFMEMORY: 05579 ast_cli(fd, "Out of memory\n"); 05580 return RESULT_FAILURE; 05581 default: 05582 return RESULT_FAILURE; 05583 } 05584 }
static int handle_queue_remove_member | ( | int | fd, | |
int | argc, | |||
char * | argv[] | |||
) | [static] |
Definition at line 5619 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.
05620 { 05621 char *queuename, *interface; 05622 05623 if (argc != 6) { 05624 return RESULT_SHOWUSAGE; 05625 } else if (strcmp(argv[4], "from")) { 05626 return RESULT_SHOWUSAGE; 05627 } 05628 05629 queuename = argv[5]; 05630 interface = argv[3]; 05631 05632 switch (remove_from_queue(queuename, interface)) { 05633 case RES_OKAY: 05634 ast_queue_log(queuename, "CLI", interface, "REMOVEMEMBER", "%s", ""); 05635 ast_cli(fd, "Removed interface '%s' from queue '%s'\n", interface, queuename); 05636 return RESULT_SUCCESS; 05637 case RES_EXISTS: 05638 ast_cli(fd, "Unable to remove interface '%s' from queue '%s': Not there\n", interface, queuename); 05639 return RESULT_FAILURE; 05640 case RES_NOSUCHQUEUE: 05641 ast_cli(fd, "Unable to remove interface from queue '%s': No such queue\n", queuename); 05642 return RESULT_FAILURE; 05643 case RES_OUTOFMEMORY: 05644 ast_cli(fd, "Out of memory\n"); 05645 return RESULT_FAILURE; 05646 case RES_NOT_DYNAMIC: 05647 ast_cli(fd, "Member not dynamic\n"); 05648 return RESULT_FAILURE; 05649 default: 05650 return RESULT_FAILURE; 05651 } 05652 }
static void* handle_statechange | ( | struct statechange * | sc | ) | [static] |
set a member's status based on device state of that member's interface
Definition at line 704 of file app_queue.c.
References ast_copy_string(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_strdupa, statechange::dev, devstate2str(), member_interface::interface, LOG_DEBUG, option_debug, statechange::state, and update_status().
Referenced by device_state_thread().
00705 { 00706 struct member_interface *curint; 00707 char *loc; 00708 char *technology; 00709 char interface[80]; 00710 00711 technology = ast_strdupa(sc->dev); 00712 loc = strchr(technology, '/'); 00713 if (loc) { 00714 *loc++ = '\0'; 00715 } else { 00716 return NULL; 00717 } 00718 00719 AST_LIST_LOCK(&interfaces); 00720 AST_LIST_TRAVERSE(&interfaces, curint, list) { 00721 char *slash_pos; 00722 ast_copy_string(interface, curint->interface, sizeof(interface)); 00723 if ((slash_pos = strchr(interface, '/'))) 00724 if ((slash_pos = strchr(slash_pos + 1, '/'))) 00725 *slash_pos = '\0'; 00726 00727 if (!strcasecmp(interface, sc->dev)) 00728 break; 00729 } 00730 AST_LIST_UNLOCK(&interfaces); 00731 00732 if (!curint) { 00733 if (option_debug > 2) 00734 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)); 00735 return NULL; 00736 } 00737 00738 if (option_debug) 00739 ast_log(LOG_DEBUG, "Device '%s/%s' changed to state '%d' (%s)\n", technology, loc, sc->state, devstate2str(sc->state)); 00740 00741 update_status(sc->dev, sc->state); 00742 00743 return NULL; 00744 }
static void hangupcalls | ( | struct callattempt * | outgoing, | |
struct ast_channel * | exception | |||
) | [static] |
Definition at line 1812 of file app_queue.c.
References ao2_ref(), ast_hangup(), callattempt::chan, free, callattempt::member, and callattempt::q_next.
Referenced by try_calling().
01813 { 01814 struct callattempt *oo; 01815 01816 while (outgoing) { 01817 /* Hangup any existing lines we have open */ 01818 if (outgoing->chan && (outgoing->chan != exception)) 01819 ast_hangup(outgoing->chan); 01820 oo = outgoing; 01821 outgoing = outgoing->q_next; 01822 if (oo->member) 01823 ao2_ref(oo->member, -1); 01824 free(oo); 01825 } 01826 }
static void init_queue | ( | struct call_queue * | q | ) | [static] |
Definition at line 880 of file app_queue.c.
References call_queue::announce, call_queue::announcefrequency, call_queue::announceholdtime, ao2_container_alloc(), ast_copy_string(), call_queue::autofill, call_queue::context, call_queue::dead, DEFAULT_RETRY, call_queue::eventwhencalled, call_queue::found, call_queue::joinempty, call_queue::leavewhenempty, call_queue::maskmemberstatus, MAX_PERIODIC_ANNOUNCEMENTS, call_queue::maxlen, member_cmp_fn(), member_hash_fn(), call_queue::membercount, call_queue::memberdelay, call_queue::members, call_queue::moh, call_queue::monfmt, call_queue::monjoin, call_queue::montype, call_queue::periodicannouncefrequency, QUEUE_STRATEGY_LINEAR, QUEUE_STRATEGY_RRORDERED, call_queue::reportholdtime, call_queue::retry, call_queue::ringinuse, call_queue::ringlimit, call_queue::roundingseconds, call_queue::servicelevel, call_queue::setinterfacevar, call_queue::sound_calls, call_queue::sound_holdtime, call_queue::sound_minute, call_queue::sound_minutes, call_queue::sound_next, call_queue::sound_periodicannounce, call_queue::sound_reporthold, call_queue::sound_seconds, call_queue::sound_thanks, call_queue::sound_thereare, call_queue::strategy, call_queue::timeout, call_queue::timeoutrestart, call_queue::weight, and call_queue::wrapuptime.
Referenced by find_queue_by_name_rt(), and reload_queues().
00881 { 00882 int i; 00883 00884 q->dead = 0; 00885 q->retry = DEFAULT_RETRY; 00886 q->timeout = -1; 00887 q->maxlen = 0; 00888 q->ringlimit = 0; 00889 q->announcefrequency = 0; 00890 q->announceholdtime = 0; 00891 q->roundingseconds = 0; /* Default - don't announce seconds */ 00892 q->servicelevel = 0; 00893 q->ringinuse = 1; 00894 q->setinterfacevar = 0; 00895 q->autofill = autofill_default; 00896 q->montype = montype_default; 00897 q->moh[0] = '\0'; 00898 q->announce[0] = '\0'; 00899 q->context[0] = '\0'; 00900 q->monfmt[0] = '\0'; 00901 q->periodicannouncefrequency = 0; 00902 q->reportholdtime = 0; 00903 q->monjoin = 0; 00904 q->wrapuptime = 0; 00905 q->joinempty = 0; 00906 q->leavewhenempty = 0; 00907 q->memberdelay = 0; 00908 q->maskmemberstatus = 0; 00909 q->eventwhencalled = 0; 00910 q->weight = 0; 00911 q->timeoutrestart = 0; 00912 if (!q->members) { 00913 if (q->strategy == QUEUE_STRATEGY_LINEAR || q->strategy == QUEUE_STRATEGY_RRORDERED) 00914 /* linear strategy depends on order, so we have to place all members in a single bucket */ 00915 q->members = ao2_container_alloc(1, member_hash_fn, member_cmp_fn); 00916 else 00917 q->members = ao2_container_alloc(37, member_hash_fn, member_cmp_fn); 00918 } 00919 q->membercount = 0; 00920 q->found = 1; 00921 ast_copy_string(q->sound_next, "queue-youarenext", sizeof(q->sound_next)); 00922 ast_copy_string(q->sound_thereare, "queue-thereare", sizeof(q->sound_thereare)); 00923 ast_copy_string(q->sound_calls, "queue-callswaiting", sizeof(q->sound_calls)); 00924 ast_copy_string(q->sound_holdtime, "queue-holdtime", sizeof(q->sound_holdtime)); 00925 ast_copy_string(q->sound_minutes, "queue-minutes", sizeof(q->sound_minutes)); 00926 ast_copy_string(q->sound_minute, "queue-minute", sizeof(q->sound_minute)); 00927 ast_copy_string(q->sound_seconds, "queue-seconds", sizeof(q->sound_seconds)); 00928 ast_copy_string(q->sound_thanks, "queue-thankyou", sizeof(q->sound_thanks)); 00929 ast_copy_string(q->sound_reporthold, "queue-reporthold", sizeof(q->sound_reporthold)); 00930 ast_copy_string(q->sound_periodicannounce[0], "queue-periodic-announce", sizeof(q->sound_periodicannounce[0])); 00931 for (i = 1; i < MAX_PERIODIC_ANNOUNCEMENTS; i++) { 00932 q->sound_periodicannounce[i][0]='\0'; 00933 } 00934 }
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 560 of file app_queue.c.
References ao2_ref(), call_queue::head, and queue_ent::next.
Referenced by join_queue().
00561 { 00562 struct queue_ent *cur; 00563 00564 if (!q || !new) 00565 return; 00566 if (prev) { 00567 cur = prev->next; 00568 prev->next = new; 00569 } else { 00570 cur = q->head; 00571 q->head = new; 00572 } 00573 new->next = cur; 00574 00575 /* every queue_ent must have a reference to it's parent call_queue, this 00576 * reference does not go away until the end of the queue_ent's life, meaning 00577 * that even when the queue_ent leaves the call_queue this ref must remain. */ 00578 ao2_ref(q, +1); 00579 new->parent = q; 00580 new->pos = ++(*pos); 00581 new->opos = *pos; 00582 }
static char* int2strat | ( | int | strategy | ) | [static] |
Definition at line 514 of file app_queue.c.
References strategy::name, and strategies.
Referenced by __queues_show().
00515 { 00516 int x; 00517 00518 for (x = 0; x < sizeof(strategies) / sizeof(strategies[0]); x++) { 00519 if (strategy == strategies[x].strategy) 00520 return strategies[x].name; 00521 } 00522 00523 return "<unknown>"; 00524 }
static struct member* interface_exists | ( | struct call_queue * | q, | |
const char * | interface | |||
) | [static, read] |
Definition at line 3611 of file app_queue.c.
References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next(), ao2_ref(), member::interface, and call_queue::members.
Referenced by add_to_queue(), and set_member_paused().
03612 { 03613 struct member *mem; 03614 struct ao2_iterator mem_iter; 03615 03616 if (!q) 03617 return NULL; 03618 03619 mem_iter = ao2_iterator_init(q->members, 0); 03620 while ((mem = ao2_iterator_next(&mem_iter))) { 03621 if (!strcasecmp(interface, mem->interface)) { 03622 ao2_iterator_destroy(&mem_iter); 03623 return mem; 03624 } 03625 ao2_ref(mem, -1); 03626 } 03627 ao2_iterator_destroy(&mem_iter); 03628 03629 return NULL; 03630 }
static int interface_exists_global | ( | const char * | interface | ) | [static] |
Definition at line 972 of file app_queue.c.
References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next(), ao2_lock(), ao2_ref(), ao2_unlock(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, call_queue::members, and member::state_interface.
Referenced by remove_from_interfaces().
00973 { 00974 struct call_queue *q; 00975 struct member *mem; 00976 struct ao2_iterator mem_iter; 00977 int ret = 0; 00978 00979 AST_LIST_LOCK(&queues); 00980 AST_LIST_TRAVERSE(&queues, q, list) { 00981 ao2_lock(q); 00982 mem_iter = ao2_iterator_init(q->members, 0); 00983 while ((mem = ao2_iterator_next(&mem_iter))) { 00984 if (!strcasecmp(mem->state_interface, interface)) { 00985 ao2_ref(mem, -1); 00986 ret = 1; 00987 break; 00988 } 00989 ao2_ref(mem, -1); 00990 } 00991 ao2_iterator_destroy(&mem_iter); 00992 ao2_unlock(q); 00993 if (ret) 00994 break; 00995 } 00996 AST_LIST_UNLOCK(&queues); 00997 00998 return ret; 00999 }
static int is_our_turn | ( | struct queue_ent * | qe | ) | [static] |
Check if we should start attempting to call queue members.
A simple process, really. Count the number of members who are available to take our call and then see if we are in a position in the queue at which a member could accept our call.
[in] | qe | The caller who wants to know if it is his turn |
0 | It is not our turn | |
1 | It is our turn |
Definition at line 2621 of file app_queue.c.
References ao2_lock(), ao2_unlock(), ast_log(), call_queue::autofill, queue_ent::chan, call_queue::head, LOG_DEBUG, queue_ent::next, num_available_members(), option_debug, queue_ent::parent, queue_ent::pending, and queue_ent::pos.
Referenced by queue_exec(), and wait_our_turn().
02622 { 02623 struct queue_ent *ch; 02624 int res; 02625 int avl; 02626 int idx = 0; 02627 /* This needs a lock. How many members are available to be served? */ 02628 ao2_lock(qe->parent); 02629 02630 avl = num_available_members(qe->parent); 02631 02632 ch = qe->parent->head; 02633 02634 if (option_debug) { 02635 ast_log(LOG_DEBUG, "There %s %d available %s.\n", avl != 1 ? "are" : "is", avl, avl != 1 ? "members" : "member"); 02636 } 02637 02638 while ((idx < avl) && (ch) && (ch != qe)) { 02639 if (!ch->pending) 02640 idx++; 02641 ch = ch->next; 02642 } 02643 02644 ao2_unlock(qe->parent); 02645 /* If the queue entry is within avl [the number of available members] calls from the top ... 02646 * Autofill and position check added to support autofill=no (as only calls 02647 * from the front of the queue are valid when autofill is disabled) 02648 */ 02649 if (ch && idx < avl && (qe->parent->autofill || qe->pos == 1)) { 02650 if (option_debug) 02651 ast_log(LOG_DEBUG, "It's our turn (%s).\n", qe->chan->name); 02652 res = 1; 02653 } else { 02654 if (option_debug) 02655 ast_log(LOG_DEBUG, "It's not our turn (%s).\n", qe->chan->name); 02656 res = 0; 02657 } 02658 02659 return res; 02660 }
static int join_queue | ( | char * | queuename, | |
struct queue_ent * | qe, | |||
enum queue_result * | reason | |||
) | [static] |
Definition at line 1529 of file app_queue.c.
References call_queue::announce, queue_ent::announce, ao2_lock(), ao2_unlock(), ast_copy_string(), AST_LIST_LOCK, AST_LIST_UNLOCK, ast_log(), 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(), 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().
01530 { 01531 struct call_queue *q; 01532 struct queue_ent *cur, *prev = NULL; 01533 int res = -1; 01534 int pos = 0; 01535 int inserted = 0; 01536 enum queue_member_status stat; 01537 01538 if (!(q = load_realtime_queue(queuename))) 01539 return res; 01540 01541 AST_LIST_LOCK(&queues); 01542 ao2_lock(q); 01543 01544 /* This is our one */ 01545 stat = get_member_status(q, qe->max_penalty); 01546 if (!q->joinempty && (stat == QUEUE_NO_MEMBERS)) 01547 *reason = QUEUE_JOINEMPTY; 01548 else if ((q->joinempty == QUEUE_EMPTY_STRICT) && (stat == QUEUE_NO_REACHABLE_MEMBERS || stat == QUEUE_NO_MEMBERS)) 01549 *reason = QUEUE_JOINUNAVAIL; 01550 else if (q->maxlen && (q->count >= q->maxlen)) 01551 *reason = QUEUE_FULL; 01552 else { 01553 /* There's space for us, put us at the right position inside 01554 * the queue. 01555 * Take into account the priority of the calling user */ 01556 inserted = 0; 01557 prev = NULL; 01558 cur = q->head; 01559 while (cur) { 01560 /* We have higher priority than the current user, enter 01561 * before him, after all the other users with priority 01562 * higher or equal to our priority. */ 01563 if ((!inserted) && (qe->prio > cur->prio)) { 01564 insert_entry(q, prev, qe, &pos); 01565 inserted = 1; 01566 } 01567 cur->pos = ++pos; 01568 prev = cur; 01569 cur = cur->next; 01570 } 01571 /* No luck, join at the end of the queue */ 01572 if (!inserted) 01573 insert_entry(q, prev, qe, &pos); 01574 ast_copy_string(qe->moh, q->moh, sizeof(qe->moh)); 01575 ast_copy_string(qe->announce, q->announce, sizeof(qe->announce)); 01576 ast_copy_string(qe->context, q->context, sizeof(qe->context)); 01577 q->count++; 01578 res = 0; 01579 manager_event(EVENT_FLAG_CALL, "Join", 01580 "Channel: %s\r\nCallerID: %s\r\nCallerIDName: %s\r\nQueue: %s\r\nPosition: %d\r\nCount: %d\r\nUniqueid: %s\r\n", 01581 qe->chan->name, 01582 S_OR(qe->chan->cid.cid_num, "unknown"), /* XXX somewhere else it is <unknown> */ 01583 S_OR(qe->chan->cid.cid_name, "unknown"), 01584 q->name, qe->pos, q->count, qe->chan->uniqueid ); 01585 if (option_debug) 01586 ast_log(LOG_DEBUG, "Queue '%s' Join, Channel '%s', Position '%d'\n", q->name, qe->chan->name, qe->pos ); 01587 } 01588 ao2_unlock(q); 01589 AST_LIST_UNLOCK(&queues); 01590 01591 return res; 01592 }
static void leave_queue | ( | struct queue_ent * | qe | ) | [static] |
Definition at line 1771 of file app_queue.c.
References ao2_lock(), ao2_unlock(), ast_log(), queue_ent::chan, call_queue::count, call_queue::dead, EVENT_FLAG_CALL, call_queue::head, LOG_DEBUG, manager_event(), call_queue::name, queue_ent::next, option_debug, queue_ent::parent, queue_ent::pos, and remove_queue().
Referenced by queue_exec(), try_calling(), and wait_our_turn().
01772 { 01773 struct call_queue *q; 01774 struct queue_ent *cur, *prev = NULL; 01775 int pos = 0; 01776 01777 if (!(q = qe->parent)) 01778 return; 01779 ao2_lock(q); 01780 01781 prev = NULL; 01782 for (cur = q->head; cur; cur = cur->next) { 01783 if (cur == qe) { 01784 q->count--; 01785 01786 /* Take us out of the queue */ 01787 manager_event(EVENT_FLAG_CALL, "Leave", 01788 "Channel: %s\r\nQueue: %s\r\nCount: %d\r\nUniqueid: %s\r\n", 01789 qe->chan->name, q->name, q->count, qe->chan->uniqueid); 01790 if (option_debug) 01791 ast_log(LOG_DEBUG, "Queue '%s' Leave, Channel '%s'\n", q->name, qe->chan->name ); 01792 /* Take us out of the queue */ 01793 if (prev) 01794 prev->next = cur->next; 01795 else 01796 q->head = cur->next; 01797 } else { 01798 /* Renumber the people after us in the queue based on a new count */ 01799 cur->pos = ++pos; 01800 prev = cur; 01801 } 01802 } 01803 ao2_unlock(q); 01804 01805 if (q->dead && !q->count) { 01806 /* It's dead and nobody is in it, so kill it */ 01807 remove_queue(q); 01808 } 01809 }
static int load_module | ( | void | ) | [static] |
Definition at line 5911 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_queue_member_count(), manager_queues_show(), manager_queues_status(), manager_remove_queue_member(), pqm_exec(), ql_exec(), queue_exec(), queueagentcount_function, queueexists_function, queuemembercount_function, queuememberlist_function, queuememberpaused_function, queuememberstatus_function, queuewaitingcount_function, reload_queue_members(), reload_queues(), rqm_exec(), statechange_queue(), and upqm_exec().
05912 { 05913 int res; 05914 05915 if (!reload_queues()) 05916 return AST_MODULE_LOAD_DECLINE; 05917 05918 if (queue_persistent_members) 05919 reload_queue_members(); 05920 05921 ast_mutex_init(&device_state.lock); 05922 ast_cond_init(&device_state.cond, NULL); 05923 ast_pthread_create(&device_state.thread, NULL, device_state_thread, NULL); 05924 05925 ast_cli_register_multiple(cli_queue, sizeof(cli_queue) / sizeof(struct ast_cli_entry)); 05926 res = ast_register_application(app, queue_exec, synopsis, descrip); 05927 res |= ast_register_application(app_aqm, aqm_exec, app_aqm_synopsis, app_aqm_descrip); 05928 res |= ast_register_application(app_rqm, rqm_exec, app_rqm_synopsis, app_rqm_descrip); 05929 res |= ast_register_application(app_pqm, pqm_exec, app_pqm_synopsis, app_pqm_descrip); 05930 res |= ast_register_application(app_upqm, upqm_exec, app_upqm_synopsis, app_upqm_descrip); 05931 res |= ast_register_application(app_ql, ql_exec, app_ql_synopsis, app_ql_descrip); 05932 res |= ast_manager_register("Queues", 0, manager_queues_show, "Queues"); 05933 res |= ast_manager_register("QueueStatus", 0, manager_queues_status, "Queue Status"); 05934 res |= ast_manager_register("QueueMemberCount", 0, manager_queue_member_count, "Queue Member Count"); 05935 res |= ast_manager_register("QueueAdd", EVENT_FLAG_AGENT, manager_add_queue_member, "Add interface to queue."); 05936 res |= ast_manager_register("QueueRemove", EVENT_FLAG_AGENT, manager_remove_queue_member, "Remove interface from queue."); 05937 res |= ast_manager_register("QueuePause", EVENT_FLAG_AGENT, manager_pause_queue_member, "Makes a queue member temporarily unavailable"); 05938 res |= ast_custom_function_register(&queueexists_function); 05939 res |= ast_custom_function_register(&queueagentcount_function); 05940 res |= ast_custom_function_register(&queuemembercount_function); 05941 res |= ast_custom_function_register(&queuememberlist_function); 05942 res |= ast_custom_function_register(&queuememberstatus_function); 05943 res |= ast_custom_function_register(&queuememberpaused_function); 05944 res |= ast_custom_function_register(&queuewaitingcount_function); 05945 res |= ast_devstate_add(statechange_queue, NULL); 05946 05947 return res; 05948 }
static struct call_queue* load_realtime_queue | ( | const char * | queuename | ) | [static, read] |
This will be two separate database transactions, so we might see queue parameters as they were before another process changed the queue and member list as it was after the change. Thus we might see an empty member list when a queue is deleted. In practise, this is unlikely to cause a problem.
Definition at line 1479 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_exists(), queue_function_queuemembercount(), queue_member_count(), and reload_queue_members().
01480 { 01481 struct ast_variable *queue_vars; 01482 struct ast_config *member_config = NULL; 01483 struct call_queue *q; 01484 01485 /* Find the queue in the in-core list first. */ 01486 AST_LIST_LOCK(&queues); 01487 AST_LIST_TRAVERSE(&queues, q, list) { 01488 if (!strcasecmp(q->name, queuename)) { 01489 break; 01490 } 01491 } 01492 AST_LIST_UNLOCK(&queues); 01493 01494 if (!q || q->realtime) { 01495 /*! \note Load from realtime before taking the global qlock, to avoid blocking all 01496 queue operations while waiting for the DB. 01497 01498 This will be two separate database transactions, so we might 01499 see queue parameters as they were before another process 01500 changed the queue and member list as it was after the change. 01501 Thus we might see an empty member list when a queue is 01502 deleted. In practise, this is unlikely to cause a problem. */ 01503 01504 queue_vars = ast_load_realtime("queues", "name", queuename, NULL); 01505 if (queue_vars) { 01506 member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name", queuename, NULL); 01507 if (!member_config) { 01508 ast_log(LOG_ERROR, "no queue_members defined in your config (extconfig.conf).\n"); 01509 ast_variables_destroy(queue_vars); 01510 return NULL; 01511 } 01512 } 01513 01514 AST_LIST_LOCK(&queues); 01515 01516 q = find_queue_by_name_rt(queuename, queue_vars, member_config); 01517 if (member_config) 01518 ast_config_destroy(member_config); 01519 if (queue_vars) 01520 ast_variables_destroy(queue_vars); 01521 01522 AST_LIST_UNLOCK(&queues); 01523 } else { 01524 update_realtime_members(q); 01525 } 01526 return q; 01527 }
static int manager_add_queue_member | ( | struct mansession * | s, | |
const struct message * | m | |||
) | [static] |
Definition at line 5418 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().
05419 { 05420 const char *queuename, *interface, *penalty_s, *paused_s, *membername, *state_interface; 05421 int paused, penalty = 0; 05422 05423 queuename = astman_get_header(m, "Queue"); 05424 interface = astman_get_header(m, "Interface"); 05425 penalty_s = astman_get_header(m, "Penalty"); 05426 paused_s = astman_get_header(m, "Paused"); 05427 membername = astman_get_header(m, "MemberName"); 05428 state_interface = astman_get_header(m, "StateInterface"); 05429 05430 if (ast_strlen_zero(queuename)) { 05431 astman_send_error(s, m, "'Queue' not specified."); 05432 return 0; 05433 } 05434 05435 if (ast_strlen_zero(interface)) { 05436 astman_send_error(s, m, "'Interface' not specified."); 05437 return 0; 05438 } 05439 05440 if (ast_strlen_zero(penalty_s)) 05441 penalty = 0; 05442 else if (sscanf(penalty_s, "%30d", &penalty) != 1 || penalty < 0) 05443 penalty = 0; 05444 05445 if (ast_strlen_zero(paused_s)) 05446 paused = 0; 05447 else 05448 paused = abs(ast_true(paused_s)); 05449 05450 switch (add_to_queue(queuename, interface, membername, penalty, paused, queue_persistent_members, state_interface)) { 05451 case RES_OKAY: 05452 ast_queue_log(queuename, "MANAGER", interface, "ADDMEMBER", "%s", ""); 05453 astman_send_ack(s, m, "Added interface to queue"); 05454 break; 05455 case RES_EXISTS: 05456 astman_send_error(s, m, "Unable to add interface: Already there"); 05457 break; 05458 case RES_NOSUCHQUEUE: 05459 astman_send_error(s, m, "Unable to add interface to queue: No such queue"); 05460 break; 05461 case RES_OUTOFMEMORY: 05462 astman_send_error(s, m, "Out of memory"); 05463 break; 05464 } 05465 05466 return 0; 05467 }
static int manager_pause_queue_member | ( | struct mansession * | s, | |
const struct message * | m | |||
) | [static] |
Definition at line 5503 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().
05504 { 05505 const char *queuename, *interface, *paused_s; 05506 int paused; 05507 05508 interface = astman_get_header(m, "Interface"); 05509 paused_s = astman_get_header(m, "Paused"); 05510 queuename = astman_get_header(m, "Queue"); /* Optional - if not supplied, pause the given Interface in all queues */ 05511 05512 if (ast_strlen_zero(interface) || ast_strlen_zero(paused_s)) { 05513 astman_send_error(s, m, "Need 'Interface' and 'Paused' parameters."); 05514 return 0; 05515 } 05516 05517 paused = abs(ast_true(paused_s)); 05518 05519 if (set_member_paused(queuename, interface, paused)) 05520 astman_send_error(s, m, "Interface not found"); 05521 else 05522 astman_send_ack(s, m, paused ? "Interface paused successfully" : "Interface unpaused successfully"); 05523 return 0; 05524 }
static int manager_queue_member_count | ( | struct mansession * | s, | |
const struct message * | m | |||
) | [static] |
Definition at line 5763 of file app_queue.c.
References ast_strlen_zero(), astman_get_header(), astman_send_ack(), astman_send_error(), qmc_handler(), and RESULT_SUCCESS.
Referenced by load_module().
05764 { 05765 char buffer[256] = ""; 05766 const char *queuename = astman_get_header(m,"Queue"); 05767 05768 if (ast_strlen_zero(queuename)) { 05769 astman_send_error(s, m, "'Queue' not specified."); 05770 return 0; 05771 } 05772 if (qmc_handler(queuename, buffer, sizeof(buffer)) == RESULT_SUCCESS) { 05773 astman_send_ack(s, m, buffer); 05774 return RESULT_SUCCESS; 05775 } else { 05776 astman_send_error(s, m, "Queue not found."); 05777 return 0; 05778 } 05779 }
static int manager_queues_show | ( | struct mansession * | s, | |
const struct message * | m | |||
) | [static] |
Definition at line 5312 of file app_queue.c.
References __queues_show(), astman_append(), and RESULT_SUCCESS.
Referenced by load_module().
05313 { 05314 char *a[] = { "queue", "show" }; 05315 05316 __queues_show(s, 1, -1, 2, a); 05317 astman_append(s, "\r\n\r\n"); /* Properly terminate Manager output */ 05318 05319 return RESULT_SUCCESS; 05320 }
static int manager_queues_status | ( | struct mansession * | s, | |
const struct message * | m | |||
) | [static] |
Definition at line 5323 of file app_queue.c.
References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next(), ao2_lock(), ao2_ref(), ao2_unlock(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_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::maxlen, member::membername, call_queue::members, call_queue::name, queue_ent::next, member::paused, member::penalty, RESULT_SUCCESS, call_queue::ringlimit, S_OR, call_queue::servicelevel, queue_ent::start, member::status, and call_queue::weight.
Referenced by load_module().
05324 { 05325 time_t now; 05326 int pos; 05327 const char *id = astman_get_header(m,"ActionID"); 05328 const char *queuefilter = astman_get_header(m,"Queue"); 05329 const char *memberfilter = astman_get_header(m,"Member"); 05330 char idText[256] = ""; 05331 struct call_queue *q; 05332 struct queue_ent *qe; 05333 float sl = 0; 05334 struct member *mem; 05335 struct ao2_iterator mem_iter; 05336 05337 astman_send_ack(s, m, "Queue status will follow"); 05338 time(&now); 05339 AST_LIST_LOCK(&queues); 05340 if (!ast_strlen_zero(id)) 05341 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id); 05342 05343 AST_LIST_TRAVERSE(&queues, q, list) { 05344 ao2_lock(q); 05345 05346 /* List queue properties */ 05347 if (ast_strlen_zero(queuefilter) || !strcmp(q->name, queuefilter)) { 05348 sl = ((q->callscompleted > 0) ? 100 * ((float)q->callscompletedinsl / (float)q->callscompleted) : 0); 05349 astman_append(s, "Event: QueueParams\r\n" 05350 "Queue: %s\r\n" 05351 "Max: %d\r\n" 05352 "Calls: %d\r\n" 05353 "Holdtime: %d\r\n" 05354 "Completed: %d\r\n" 05355 "Abandoned: %d\r\n" 05356 "ServiceLevel: %d\r\n" 05357 "ServicelevelPerf: %2.1f\r\n" 05358 "RingLimit: %d\r\n" 05359 "Weight: %d\r\n" 05360 "%s" 05361 "\r\n", 05362 q->name, q->maxlen, q->count, q->holdtime, q->callscompleted, 05363 q->callsabandoned, q->servicelevel, sl, q->ringlimit, q->weight, idText); 05364 /* List Queue Members */ 05365 mem_iter = ao2_iterator_init(q->members, 0); 05366 while ((mem = ao2_iterator_next(&mem_iter))) { 05367 if (ast_strlen_zero(memberfilter) || !strcmp(mem->interface, memberfilter)) { 05368 astman_append(s, "Event: QueueMember\r\n" 05369 "Queue: %s\r\n" 05370 "Name: %s\r\n" 05371 "Location: %s\r\n" 05372 "Membership: %s\r\n" 05373 "Penalty: %d\r\n" 05374 "CallsTaken: %d\r\n" 05375 "LastCall: %d\r\n" 05376 "Status: %d\r\n" 05377 "Paused: %d\r\n" 05378 "%s" 05379 "\r\n", 05380 q->name, mem->membername, mem->interface, mem->dynamic ? "dynamic" : "static", 05381 mem->penalty, mem->calls, (int)mem->lastcall, mem->status, mem->paused, idText); 05382 } 05383 ao2_ref(mem, -1); 05384 } 05385 ao2_iterator_destroy(&mem_iter); 05386 /* List Queue Entries */ 05387 pos = 1; 05388 for (qe = q->head; qe; qe = qe->next) { 05389 astman_append(s, "Event: QueueEntry\r\n" 05390 "Queue: %s\r\n" 05391 "Position: %d\r\n" 05392 "Channel: %s\r\n" 05393 "CallerID: %s\r\n" 05394 "CallerIDName: %s\r\n" 05395 "Wait: %ld\r\n" 05396 "%s" 05397 "\r\n", 05398 q->name, pos++, qe->chan->name, 05399 S_OR(qe->chan->cid.cid_num, "unknown"), 05400 S_OR(qe->chan->cid.cid_name, "unknown"), 05401 (long) (now - qe->start), idText); 05402 } 05403 } 05404 ao2_unlock(q); 05405 } 05406 05407 astman_append(s, 05408 "Event: QueueStatusComplete\r\n" 05409 "%s" 05410 "\r\n",idText); 05411 05412 AST_LIST_UNLOCK(&queues); 05413 05414 05415 return RESULT_SUCCESS; 05416 }
static int manager_remove_queue_member | ( | struct mansession * | s, | |
const struct message * | m | |||
) | [static] |
Definition at line 5469 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().
05470 { 05471 const char *queuename, *interface; 05472 05473 queuename = astman_get_header(m, "Queue"); 05474 interface = astman_get_header(m, "Interface"); 05475 05476 if (ast_strlen_zero(queuename) || ast_strlen_zero(interface)) { 05477 astman_send_error(s, m, "Need 'Queue' and 'Interface' parameters."); 05478 return 0; 05479 } 05480 05481 switch (remove_from_queue(queuename, interface)) { 05482 case RES_OKAY: 05483 ast_queue_log(queuename, "MANAGER", interface, "REMOVEMEMBER", "%s", ""); 05484 astman_send_ack(s, m, "Removed interface from queue"); 05485 break; 05486 case RES_EXISTS: 05487 astman_send_error(s, m, "Unable to remove interface: Not there"); 05488 break; 05489 case RES_NOSUCHQUEUE: 05490 astman_send_error(s, m, "Unable to remove interface from queue: No such queue"); 05491 break; 05492 case RES_OUTOFMEMORY: 05493 astman_send_error(s, m, "Out of memory"); 05494 break; 05495 case RES_NOT_DYNAMIC: 05496 astman_send_error(s, m, "Member not dynamic"); 05497 break; 05498 } 05499 05500 return 0; 05501 }
static int member_cmp_fn | ( | void * | obj1, | |
void * | obj2, | |||
int | flags | |||
) | [static] |
Definition at line 874 of file app_queue.c.
References member::interface.
Referenced by init_queue().
static int member_hash_fn | ( | const void * | obj, | |
const int | flags | |||
) | [static] |
Definition at line 862 of file app_queue.c.
References compress_char(), and member::interface.
Referenced by init_queue().
00863 { 00864 const struct member *mem = obj; 00865 const char *chname = strchr(mem->interface, '/'); 00866 int ret = 0, i; 00867 if (!chname) 00868 chname = mem->interface; 00869 for (i = 0; i < 5 && chname[i]; i++) 00870 ret += compress_char(chname[i]) << (i * 6); 00871 return ret; 00872 }
static void monjoin_dep_warning | ( | void | ) | [static] |
Definition at line 493 of file app_queue.c.
References ast_log(), and LOG_NOTICE.
Referenced by queue_set_param().
00494 { 00495 static unsigned int warned = 0; 00496 if (!warned) { 00497 ast_log(LOG_NOTICE, "The 'monitor-join' queue option is deprecated. Please use monitor-type=mixmonitor instead.\n"); 00498 warned = 1; 00499 } 00500 }
static int num_available_members | ( | struct call_queue * | q | ) | [static] |
Get the number of members available to accept a call.
[in] | q | The queue for which we are couting the number of available members |
Definition at line 1836 of file app_queue.c.
References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next(), ao2_ref(), AST_DEVICE_INUSE, AST_DEVICE_NOT_INUSE, AST_DEVICE_ONHOLD, AST_DEVICE_RINGING, AST_DEVICE_RINGINUSE, AST_DEVICE_UNKNOWN, call_queue::autofill, call_queue::members, member::paused, QUEUE_STRATEGY_RINGALL, call_queue::ringinuse, member::status, and call_queue::strategy.
Referenced by compare_weight(), and is_our_turn().
01837 { 01838 struct member *mem; 01839 int avl = 0; 01840 struct ao2_iterator mem_iter; 01841 01842 mem_iter = ao2_iterator_init(q->members, 0); 01843 while ((mem = ao2_iterator_next(&mem_iter))) { 01844 switch (mem->status) { 01845 case AST_DEVICE_INUSE: 01846 if (!q->ringinuse) 01847 break; 01848 /* else fall through */ 01849 case AST_DEVICE_NOT_INUSE: 01850 case AST_DEVICE_ONHOLD: 01851 case AST_DEVICE_RINGINUSE: 01852 case AST_DEVICE_RINGING: 01853 case AST_DEVICE_UNKNOWN: 01854 if (!mem->paused) { 01855 avl++; 01856 } 01857 break; 01858 } 01859 ao2_ref(mem, -1); 01860 01861 /* If autofill is not enabled or if the queue's strategy is ringall, then 01862 * we really don't care about the number of available members so much as we 01863 * do that there is at least one available. 01864 * 01865 * In fact, we purposely will return from this function stating that only 01866 * one member is available if either of those conditions hold. That way, 01867 * functions which determine what action to take based on the number of available 01868 * members will operate properly. The reasoning is that even if multiple 01869 * members are available, only the head caller can actually be serviced. 01870 */ 01871 if ((!q->autofill || q->strategy == QUEUE_STRATEGY_RINGALL) && avl) { 01872 break; 01873 } 01874 } 01875 ao2_iterator_destroy(&mem_iter); 01876 01877 return avl; 01878 }
static int play_file | ( | struct ast_channel * | chan, | |
char * | filename | |||
) | [static] |
Definition at line 1594 of file app_queue.c.
References AST_DIGIT_ANY, ast_fileexists(), ast_stopstream(), ast_streamfile(), ast_strlen_zero(), and ast_waitstream().
Referenced by say_periodic_announcement(), say_position(), and try_calling().
01595 { 01596 int res; 01597 01598 if (ast_strlen_zero(filename)) { 01599 return 0; 01600 } 01601 01602 if (!ast_fileexists(filename, NULL, chan->language)) { 01603 return 0; 01604 } 01605 01606 ast_stopstream(chan); 01607 01608 res = ast_streamfile(chan, filename, chan->language); 01609 if (!res) 01610 res = ast_waitstream(chan, AST_DIGIT_ANY); 01611 01612 ast_stopstream(chan); 01613 01614 return res; 01615 }
static int pqm_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Definition at line 3928 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().
03929 { 03930 struct ast_module_user *lu; 03931 char *parse; 03932 int priority_jump = 0; 03933 int ignore_fail = 0; 03934 AST_DECLARE_APP_ARGS(args, 03935 AST_APP_ARG(queuename); 03936 AST_APP_ARG(interface); 03937 AST_APP_ARG(options); 03938 ); 03939 03940 if (ast_strlen_zero(data)) { 03941 ast_log(LOG_WARNING, "PauseQueueMember requires an argument ([queuename]|interface[|options])\n"); 03942 return -1; 03943 } 03944 03945 parse = ast_strdupa(data); 03946 03947 AST_STANDARD_APP_ARGS(args, parse); 03948 03949 lu = ast_module_user_add(chan); 03950 03951 if (args.options) { 03952 if (strchr(args.options, 'j')) 03953 priority_jump = 1; 03954 if (strchr(args.options, 'i')) 03955 ignore_fail = 1; 03956 } 03957 03958 if (ast_strlen_zero(args.interface)) { 03959 ast_log(LOG_WARNING, "Missing interface argument to PauseQueueMember ([queuename]|interface[|options])\n"); 03960 ast_module_user_remove(lu); 03961 return -1; 03962 } 03963 03964 if (set_member_paused(args.queuename, args.interface, 1)) { 03965 ast_log(LOG_WARNING, "Attempt to pause interface %s, not found\n", args.interface); 03966 pbx_builtin_setvar_helper(chan, "PQMSTATUS", "NOTFOUND"); 03967 if (priority_jump || ast_opt_priority_jumping) { 03968 if (!ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101)) { 03969 ast_module_user_remove(lu); 03970 return 0; 03971 } 03972 } 03973 ast_module_user_remove(lu); 03974 if (ignore_fail) { 03975 return 0; 03976 } else { 03977 return -1; 03978 } 03979 } 03980 03981 ast_module_user_remove(lu); 03982 pbx_builtin_setvar_helper(chan, "PQMSTATUS", "PAUSED"); 03983 return 0; 03984 }
static int ql_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Definition at line 4186 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(), LOG_WARNING, and parse().
Referenced by load_module().
04187 { 04188 struct ast_module_user *u; 04189 char *parse; 04190 04191 AST_DECLARE_APP_ARGS(args, 04192 AST_APP_ARG(queuename); 04193 AST_APP_ARG(uniqueid); 04194 AST_APP_ARG(membername); 04195 AST_APP_ARG(event); 04196 AST_APP_ARG(params); 04197 ); 04198 04199 if (ast_strlen_zero(data)) { 04200 ast_log(LOG_WARNING, "QueueLog requires arguments (queuename|uniqueid|membername|event[|additionalinfo]\n"); 04201 return -1; 04202 } 04203 04204 u = ast_module_user_add(chan); 04205 04206 parse = ast_strdupa(data); 04207 04208 AST_STANDARD_APP_ARGS(args, parse); 04209 04210 if (ast_strlen_zero(args.queuename) || ast_strlen_zero(args.uniqueid) 04211 || ast_strlen_zero(args.membername) || ast_strlen_zero(args.event)) { 04212 ast_log(LOG_WARNING, "QueueLog requires arguments (queuename|uniqueid|membername|event[|additionalinfo])\n"); 04213 ast_module_user_remove(u); 04214 return -1; 04215 } 04216 04217 ast_queue_log(args.queuename, args.uniqueid, args.membername, args.event, 04218 "%s", args.params ? args.params : ""); 04219 04220 ast_module_user_remove(u); 04221 04222 return 0; 04223 }
static int qmc_handler | ( | const char * | queuename, | |
char * | buffer, | |||
int | len | |||
) | [static] |
Definition at line 5748 of file app_queue.c.
References member_count::active, member_count::all, member_count::free, member_count::inuse, member_count::paused, queue_member_count(), RESULT_FAILURE, RESULT_SUCCESS, and member_count::valid.
Referenced by cli_queue_member_count(), and manager_queue_member_count().
05749 { 05750 struct member_count qmc; 05751 memset(&qmc, 0, sizeof(qmc)); 05752 if (queue_member_count(queuename, &qmc) != 0) { 05753 return RESULT_FAILURE; 05754 } else { 05755 snprintf(buffer, len, 05756 "valid:%d inuse:%d paused:%d active:%d free:%d all:%d", 05757 qmc.valid, qmc.inuse, qmc.paused, qmc.active, qmc.free, qmc.all); 05758 return RESULT_SUCCESS; 05759 } 05760 }
static int queue_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
The starting point for all queue calls.
The process involved here is to 1. Parse the options specified in the call to Queue() 2. Join the queue 3. Wait in a loop until it is our turn to try calling a queue member 4. Attempt to call a queue member 5. If 4. did not result in a bridged call, then check for between call options such as periodic announcements etc. 6. Try 4 again unless some condition (such as an expiration time) causes us to exit the queue.
Definition at line 4237 of file app_queue.c.
References call_queue::announcefrequency, ao2_ref(), 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_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_CONTINUE, QUEUE_EMPTY_STRICT, QUEUE_LEAVEEMPTY, QUEUE_LEAVEUNAVAIL, QUEUE_NO_MEMBERS, QUEUE_NO_REACHABLE_MEMBERS, QUEUE_TIMEOUT, QUEUE_UNKNOWN, record_abandoned(), queue_ent::ring_when_ringing, 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().
04238 { 04239 int res=-1; 04240 int ringing=0; 04241 struct ast_module_user *lu; 04242 const char *user_priority; 04243 const char *max_penalty_str; 04244 int prio; 04245 int qcontinue = 0; 04246 int max_penalty; 04247 enum queue_result reason = QUEUE_UNKNOWN; 04248 /* whether to exit Queue application after the timeout hits */ 04249 int tries = 0; 04250 int noption = 0; 04251 char *parse; 04252 AST_DECLARE_APP_ARGS(args, 04253 AST_APP_ARG(queuename); 04254 AST_APP_ARG(options); 04255 AST_APP_ARG(url); 04256 AST_APP_ARG(announceoverride); 04257 AST_APP_ARG(queuetimeoutstr); 04258 AST_APP_ARG(agi); 04259 ); 04260 /* Our queue entry */ 04261 struct queue_ent qe = { 0 }; 04262 04263 if (ast_strlen_zero(data)) { 04264 ast_log(LOG_WARNING, "Queue requires an argument: queuename[|options[|URL[|announceoverride[|timeout[|agi]]]]]\n"); 04265 return -1; 04266 } 04267 04268 parse = ast_strdupa(data); 04269 AST_STANDARD_APP_ARGS(args, parse); 04270 04271 lu = ast_module_user_add(chan); 04272 04273 /* Setup our queue entry */ 04274 qe.start = time(NULL); 04275 04276 /* set the expire time based on the supplied timeout; */ 04277 if (!ast_strlen_zero(args.queuetimeoutstr)) 04278 qe.expire = qe.start + atoi(args.queuetimeoutstr); 04279 else 04280 qe.expire = 0; 04281 04282 /* Get the priority from the variable ${QUEUE_PRIO} */ 04283 user_priority = pbx_builtin_getvar_helper(chan, "QUEUE_PRIO"); 04284 if (user_priority) { 04285 if (sscanf(user_priority, "%30d", &prio) == 1) { 04286 if (option_debug) 04287 ast_log(LOG_DEBUG, "%s: Got priority %d from ${QUEUE_PRIO}.\n", 04288 chan->name, prio); 04289 } else { 04290 ast_log(LOG_WARNING, "${QUEUE_PRIO}: Invalid value (%s), channel %s.\n", 04291 user_priority, chan->name); 04292 prio = 0; 04293 } 04294 } else { 04295 if (option_debug > 2) 04296 ast_log(LOG_DEBUG, "NO QUEUE_PRIO variable found. Using default.\n"); 04297 prio = 0; 04298 } 04299 04300 /* Get the maximum penalty from the variable ${QUEUE_MAX_PENALTY} */ 04301 if ((max_penalty_str = pbx_builtin_getvar_helper(chan, "QUEUE_MAX_PENALTY"))) { 04302 if (sscanf(max_penalty_str, "%30d", &max_penalty) == 1) { 04303 if (option_debug) 04304 ast_log(LOG_DEBUG, "%s: Got max penalty %d from ${QUEUE_MAX_PENALTY}.\n", 04305 chan->name, max_penalty); 04306 } else { 04307 ast_log(LOG_WARNING, "${QUEUE_MAX_PENALTY}: Invalid value (%s), channel %s.\n", 04308 max_penalty_str, chan->name); 04309 max_penalty = 0; 04310 } 04311 } else { 04312 max_penalty = 0; 04313 } 04314 04315 if (args.options && (strchr(args.options, 'r'))) 04316 ringing = 1; 04317 04318 if (ringing != 1 && args.options && (strchr(args.options, 'R'))) { 04319 qe.ring_when_ringing = 1; 04320 } 04321 04322 if (args.options && (strchr(args.options, 'c'))) 04323 qcontinue = 1; 04324 04325 if (option_debug) 04326 ast_log(LOG_DEBUG, "queue: %s, options: %s, url: %s, announce: %s, expires: %ld, priority: %d\n", 04327 args.queuename, args.options, args.url, args.announceoverride, (long)qe.expire, prio); 04328 04329 qe.chan = chan; 04330 qe.prio = prio; 04331 qe.max_penalty = max_penalty; 04332 qe.last_pos_said = 0; 04333 qe.last_pos = 0; 04334 qe.last_periodic_announce_time = time(NULL); 04335 qe.last_periodic_announce_sound = 0; 04336 qe.valid_digits = 0; 04337 if (!join_queue(args.queuename, &qe, &reason)) { 04338 int makeannouncement = 0; 04339 04340 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "ENTERQUEUE", "%s|%s", S_OR(args.url, ""), 04341 S_OR(chan->cid.cid_num, "")); 04342 check_turns: 04343 if (ringing) { 04344 ast_indicate(chan, AST_CONTROL_RINGING); 04345 } else { 04346 ast_moh_start(chan, qe.moh, NULL); 04347 } 04348 04349 /* This is the wait loop for callers 2 through maxlen */ 04350 res = wait_our_turn(&qe, ringing, &reason); 04351 if (res) 04352 goto stop; 04353 04354 for (;;) { 04355 /* This is the wait loop for the head caller*/ 04356 /* To exit, they may get their call answered; */ 04357 /* they may dial a digit from the queue context; */ 04358 /* or, they may timeout. */ 04359 04360 enum queue_member_status stat; 04361 04362 /* Leave if we have exceeded our queuetimeout */ 04363 if (qe.expire && (time(NULL) >= qe.expire)) { 04364 record_abandoned(&qe); 04365 reason = QUEUE_TIMEOUT; 04366 res = 0; 04367 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHTIMEOUT", "%d", qe.pos); 04368 break; 04369 } 04370 04371 if (makeannouncement) { 04372 /* Make a position announcement, if enabled */ 04373 if (qe.parent->announcefrequency && !ringing) 04374 if ((res = say_position(&qe))) 04375 goto stop; 04376 04377 } 04378 makeannouncement = 1; 04379 04380 /* Leave if we have exceeded our queuetimeout */ 04381 if (qe.expire && (time(NULL) >= qe.expire)) { 04382 record_abandoned(&qe); 04383 reason = QUEUE_TIMEOUT; 04384 res = 0; 04385 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHTIMEOUT", "%d", qe.pos); 04386 break; 04387 } 04388 /* Make a periodic announcement, if enabled */ 04389 if (qe.parent->periodicannouncefrequency && !ringing) 04390 if ((res = say_periodic_announcement(&qe))) 04391 goto stop; 04392 04393 /* Leave if we have exceeded our queuetimeout */ 04394 if (qe.expire && (time(NULL) >= qe.expire)) { 04395 record_abandoned(&qe); 04396 reason = QUEUE_TIMEOUT; 04397 res = 0; 04398 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHTIMEOUT", "%d", qe.pos); 04399 break; 04400 } 04401 /* Try calling all queue members for 'timeout' seconds */ 04402 res = try_calling(&qe, args.options, args.announceoverride, args.url, &tries, &noption, args.agi); 04403 if (res) 04404 goto stop; 04405 04406 stat = get_member_status(qe.parent, qe.max_penalty); 04407 04408 /* exit after 'timeout' cycle if 'n' option enabled */ 04409 if (noption && tries >= qe.parent->membercount) { 04410 if (option_verbose > 2) 04411 ast_verbose(VERBOSE_PREFIX_3 "Exiting on time-out cycle\n"); 04412 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHTIMEOUT", "%d", qe.pos); 04413 record_abandoned(&qe); 04414 reason = QUEUE_TIMEOUT; 04415 res = 0; 04416 break; 04417 } 04418 04419 /* leave the queue if no agents, if enabled */ 04420 if (qe.parent->leavewhenempty && (stat == QUEUE_NO_MEMBERS)) { 04421 record_abandoned(&qe); 04422 reason = QUEUE_LEAVEEMPTY; 04423 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe.pos, qe.opos, (long)(time(NULL) - qe.start)); 04424 res = 0; 04425 break; 04426 } 04427 04428 /* leave the queue if no reachable agents, if enabled */ 04429 if ((qe.parent->leavewhenempty == QUEUE_EMPTY_STRICT) && (stat == QUEUE_NO_REACHABLE_MEMBERS)) { 04430 record_abandoned(&qe); 04431 reason = QUEUE_LEAVEUNAVAIL; 04432 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe.pos, qe.opos, (long)(time(NULL) - qe.start)); 04433 res = 0; 04434 break; 04435 } 04436 04437 /* Leave if we have exceeded our queuetimeout */ 04438 if (qe.expire && (time(NULL) >= qe.expire)) { 04439 record_abandoned(&qe); 04440 reason = QUEUE_TIMEOUT; 04441 res = 0; 04442 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHTIMEOUT", "%d", qe.pos); 04443 break; 04444 } 04445 04446 /* If using dynamic realtime members, we should regenerate the member list for this queue */ 04447 update_realtime_members(qe.parent); 04448 04449 /* OK, we didn't get anybody; wait for 'retry' seconds; may get a digit to exit with */ 04450 res = wait_a_bit(&qe); 04451 if (res) 04452 goto stop; 04453 04454 /* Since this is a priority queue and 04455 * it is not sure that we are still at the head 04456 * of the queue, go and check for our turn again. 04457 */ 04458 if (!is_our_turn(&qe)) { 04459 if (option_debug) 04460 ast_log(LOG_DEBUG, "Darn priorities, going back in queue (%s)!\n", 04461 qe.chan->name); 04462 goto check_turns; 04463 } 04464 } 04465 04466 stop: 04467 if (res) { 04468 if (res < 0) { 04469 res = -1; 04470 if (!qe.handled) { 04471 record_abandoned(&qe); 04472 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "ABANDON", 04473 "%d|%d|%ld", qe.pos, qe.opos, 04474 (long) time(NULL) - qe.start); 04475 } else if (qcontinue) { 04476 reason = QUEUE_CONTINUE; 04477 res = 0; 04478 } 04479 } else if (qe.valid_digits) { 04480 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHKEY", 04481 "%s|%d", qe.digits, qe.pos); 04482 } 04483 } 04484 04485 /* Don't allow return code > 0 */ 04486 if (res >= 0) { 04487 res = 0; 04488 if (ringing) { 04489 ast_indicate(chan, -1); 04490 } else { 04491 ast_moh_stop(chan); 04492 } 04493 ast_stopstream(chan); 04494 } 04495 leave_queue(&qe); 04496 if (reason != QUEUE_UNKNOWN) 04497 set_queue_result(chan, reason); 04498 } else { 04499 ast_log(LOG_WARNING, "Unable to join queue '%s'\n", args.queuename); 04500 set_queue_result(chan, reason); 04501 res = 0; 04502 } 04503 if (qe.parent) { 04504 /* every queue_ent is given a reference to it's parent call_queue when it joins the queue. 04505 * This ref must be taken away right before the queue_ent is destroyed. In this case 04506 * the queue_ent is about to be returned on the stack */ 04507 ao2_ref(qe.parent, -1); 04508 } 04509 ast_module_user_remove(lu); 04510 04511 return res; 04512 }
static int queue_function_exists | ( | struct ast_channel * | chan, | |
char * | cmd, | |||
char * | data, | |||
char * | buf, | |||
size_t | len | |||
) | [static] |
Definition at line 4820 of file app_queue.c.
References ast_log(), ast_module_user_add, ast_module_user_remove, ast_strlen_zero(), load_realtime_queue(), and LOG_ERROR.
04821 { 04822 struct ast_module_user *lu; 04823 buf[0] = '\0'; 04824 04825 if (ast_strlen_zero(data)) { 04826 ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd); 04827 return -1; 04828 } 04829 lu = ast_module_user_add(chan); 04830 snprintf(buf, len, "%d", load_realtime_queue(data) != NULL? 1 : 0); 04831 ast_module_user_remove(lu); 04832 04833 return 0; 04834 }
static int queue_function_queuemembercount | ( | struct ast_channel * | chan, | |
char * | cmd, | |||
char * | data, | |||
char * | buf, | |||
size_t | len | |||
) | [static] |
Definition at line 4522 of file app_queue.c.
References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next(), ao2_lock(), ao2_ref(), ao2_unlock(), AST_DEVICE_INVALID, AST_DEVICE_NOT_INUSE, AST_DEVICE_UNAVAILABLE, AST_DEVICE_UNKNOWN, ast_log(), ast_module_user_add, ast_module_user_remove, ast_strdupa, ast_strlen_zero(), load_realtime_queue(), LOG_ERROR, LOG_WARNING, call_queue::members, name, member::paused, QMC_ACTIVE, QMC_ALL, QMC_FREE, QMC_PAUSED, QMC_VALID, and member::status.
04523 { 04524 int count = 0; 04525 struct call_queue *q; 04526 struct ast_module_user *lu; 04527 struct member *m; 04528 struct ao2_iterator mem_iter; 04529 char *name, *item; 04530 enum qmc_status mode = QMC_VALID; 04531 04532 buf[0] = '\0'; 04533 04534 if (ast_strlen_zero(data)) { 04535 ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd); 04536 return -1; 04537 } 04538 04539 name = ast_strdupa(data); 04540 04541 lu = ast_module_user_add(chan); 04542 04543 if ((item = strchr(name, ':'))) { 04544 *item = '\0'; 04545 item++; 04546 } else { 04547 item = ""; 04548 } 04549 04550 if (!strcasecmp(item, "valid")) { 04551 mode = QMC_VALID; 04552 } else if (!strcasecmp(item, "paused")) { 04553 mode = QMC_PAUSED; 04554 } else if (!strcasecmp(item, "active")) { 04555 mode = QMC_ACTIVE; 04556 } else if (!strcasecmp(item, "free")) { 04557 mode = QMC_FREE; 04558 } else if (!strcasecmp(item, "all")) { 04559 mode = QMC_ALL; 04560 } 04561 04562 if ((q = load_realtime_queue(name))) { 04563 ao2_lock(q); 04564 mem_iter = ao2_iterator_init(q->members, 0); 04565 while ((m = ao2_iterator_next(&mem_iter))) { 04566 switch (mode) { 04567 case QMC_VALID: 04568 /* Count the queue members who are logged in and presently answering calls */ 04569 if ((m->status != AST_DEVICE_UNAVAILABLE) && (m->status != AST_DEVICE_INVALID)) { 04570 count++; 04571 } 04572 break; 04573 case QMC_PAUSED: 04574 /* Count paused members */ 04575 if (m->paused) { 04576 count++; 04577 } 04578 break; 04579 case QMC_ACTIVE: 04580 /* Count not paused members who are logged in and presently answering calls */ 04581 if (!m->paused && (m->status != AST_DEVICE_UNAVAILABLE) && (m->status != AST_DEVICE_INVALID)) { 04582 count++; 04583 } 04584 break; 04585 case QMC_FREE: 04586 /* Count free members in the queue */ 04587 if (!m->paused && ((m->status == AST_DEVICE_UNKNOWN) || (m->status == AST_DEVICE_NOT_INUSE))) { 04588 count++; 04589 } 04590 break; 04591 default: 04592 count++; 04593 break; 04594 } 04595 ao2_ref(m, -1); 04596 } 04597 ao2_iterator_destroy(&mem_iter); 04598 ao2_unlock(q); 04599 } else 04600 ast_log(LOG_WARNING, "queue %s was not found\n", name); 04601 04602 snprintf(buf, len, "%d", count); 04603 ast_module_user_remove(lu); 04604 04605 return 0; 04606 }
static int queue_function_queuememberlist | ( | struct ast_channel * | chan, | |
char * | cmd, | |||
char * | data, | |||
char * | buf, | |||
size_t | len | |||
) | [static] |
Definition at line 4651 of file app_queue.c.
References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next(), ao2_lock(), ao2_ref(), ao2_unlock(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_module_user_add, ast_module_user_remove, ast_strlen_zero(), member::interface, LOG_ERROR, LOG_WARNING, call_queue::members, and call_queue::name.
04652 { 04653 struct ast_module_user *u; 04654 struct call_queue *q; 04655 struct member *m; 04656 04657 /* Ensure an otherwise empty list doesn't return garbage */ 04658 buf[0] = '\0'; 04659 04660 if (ast_strlen_zero(data)) { 04661 ast_log(LOG_ERROR, "QUEUE_MEMBER_LIST requires an argument: queuename\n"); 04662 return -1; 04663 } 04664 04665 u = ast_module_user_add(chan); 04666 04667 AST_LIST_LOCK(&queues); 04668 AST_LIST_TRAVERSE(&queues, q, list) { 04669 if (!strcasecmp(q->name, data)) { 04670 ao2_lock(q); 04671 break; 04672 } 04673 } 04674 AST_LIST_UNLOCK(&queues); 04675 04676 if (q) { 04677 int buflen = 0, count = 0; 04678 struct ao2_iterator mem_iter = ao2_iterator_init(q->members, 0); 04679 04680 while ((m = ao2_iterator_next(&mem_iter))) { 04681 /* strcat() is always faster than printf() */ 04682 if (count++) { 04683 strncat(buf + buflen, ",", len - buflen - 1); 04684 buflen++; 04685 } 04686 strncat(buf + buflen, m->interface, len - buflen - 1); 04687 buflen += strlen(m->interface); 04688 /* Safeguard against overflow (negative length) */ 04689 if (buflen >= len - 2) { 04690 ao2_ref(m, -1); 04691 ast_log(LOG_WARNING, "Truncating list\n"); 04692 break; 04693 } 04694 ao2_ref(m, -1); 04695 } 04696 ao2_iterator_destroy(&mem_iter); 04697 ao2_unlock(q); 04698 } else 04699 ast_log(LOG_WARNING, "queue %s was not found\n", data); 04700 04701 /* We should already be terminated, but let's make sure. */ 04702 buf[len - 1] = '\0'; 04703 ast_module_user_remove(u); 04704 04705 return 0; 04706 }
static int queue_function_queuememberpaused | ( | struct ast_channel * | chan, | |
char * | cmd, | |||
char * | data, | |||
char * | buf, | |||
size_t | len | |||
) | [static] |
Definition at line 4764 of file app_queue.c.
References ao2_iterator_init(), ao2_iterator_next(), ao2_lock(), ao2_ref(), ao2_unlock(), AST_APP_ARG, ast_copy_string(), AST_DECLARE_APP_ARGS, ast_free, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_malloc, ast_module_user_add, ast_module_user_remove, AST_STANDARD_APP_ARGS, ast_strlen_zero(), member_interface::interface, LOG_WARNING, member::membername, call_queue::members, call_queue::name, and member::paused.
04765 { 04766 struct ast_module_user *lu; 04767 struct call_queue *q; 04768 struct member *cur; 04769 struct ao2_iterator mem_iter; 04770 char tmp[128] = ""; 04771 char *buffer; 04772 04773 AST_DECLARE_APP_ARGS(args, 04774 AST_APP_ARG(queue); 04775 AST_APP_ARG(interface); 04776 ); 04777 04778 AST_STANDARD_APP_ARGS(args, data); 04779 if (ast_strlen_zero(args.interface)) { 04780 ast_log(LOG_WARNING, "This function requires an interface name.\n"); 04781 return -1; 04782 } 04783 lu = ast_module_user_add(chan); 04784 04785 buffer = ast_malloc(len); 04786 buffer[0]='\0'; 04787 04788 AST_LIST_LOCK(&queues); 04789 AST_LIST_TRAVERSE(&queues, q, list) { 04790 ao2_lock(q); 04791 if (ast_strlen_zero(args.queue) || 04792 (!ast_strlen_zero(args.queue) && !strncmp(args.queue, q->name, strlen(args.queue))) 04793 ) { 04794 /* Iterate over queue members */ 04795 mem_iter = ao2_iterator_init(q->members, 0); 04796 while ((cur = ao2_iterator_next(&mem_iter))) { 04797 if (!strncasecmp(args.interface, cur->membername, strlen(args.interface))) { 04798 if (!ast_strlen_zero(args.queue)) { 04799 ast_copy_string(buffer, cur->paused?"1":"0", len); 04800 } else { 04801 snprintf(tmp, sizeof(tmp), "%s%s:%s", ast_strlen_zero(tmp)?"":",", q->name, cur->paused?"1":"0"); 04802 strncat(buffer, tmp, sizeof(tmp)); 04803 } 04804 ao2_ref(cur, -1); 04805 break; 04806 } 04807 ao2_ref(cur, -1); 04808 } 04809 } 04810 ao2_unlock(q); 04811 } 04812 AST_LIST_UNLOCK(&queues); 04813 ast_copy_string(buf, buffer, len); 04814 ast_free(buffer); 04815 04816 ast_module_user_remove(lu); 04817 return 0; 04818 }
static int queue_function_queuememberstatus | ( | struct ast_channel * | chan, | |
char * | cmd, | |||
char * | data, | |||
char * | buf, | |||
size_t | len | |||
) | [static] |
Definition at line 4708 of file app_queue.c.
References ao2_iterator_init(), ao2_iterator_next(), ao2_lock(), ao2_ref(), ao2_unlock(), AST_APP_ARG, ast_copy_string(), AST_DECLARE_APP_ARGS, ast_free, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_malloc, ast_module_user_add, ast_module_user_remove, AST_STANDARD_APP_ARGS, ast_strlen_zero(), devstate2str(), member_interface::interface, LOG_WARNING, member::membername, call_queue::members, call_queue::name, and member::status.
04709 { 04710 struct ast_module_user *lu; 04711 struct call_queue *q; 04712 struct member *cur; 04713 struct ao2_iterator mem_iter; 04714 char tmp[128] = ""; 04715 char *buffer; 04716 04717 AST_DECLARE_APP_ARGS(args, 04718 AST_APP_ARG(queue); 04719 AST_APP_ARG(interface); 04720 ); 04721 04722 AST_STANDARD_APP_ARGS(args, data); 04723 if (ast_strlen_zero(args.interface)) { 04724 ast_log(LOG_WARNING, "This function requires an interface name.\n"); 04725 return -1; 04726 } 04727 lu = ast_module_user_add(chan); 04728 04729 buffer = ast_malloc(len); 04730 buffer[0]='\0'; 04731 04732 AST_LIST_LOCK(&queues); 04733 AST_LIST_TRAVERSE(&queues, q, list) { 04734 ao2_lock(q); 04735 if (ast_strlen_zero(args.queue) || 04736 (!ast_strlen_zero(args.queue) && !strncmp(args.queue, q->name, strlen(args.queue))) 04737 ) { 04738 /* Iterate over queue members */ 04739 mem_iter = ao2_iterator_init(q->members, 0); 04740 while ((cur = ao2_iterator_next(&mem_iter))) { 04741 if (!strncasecmp(args.interface, cur->membername, strlen(args.interface))) { 04742 if (!ast_strlen_zero(args.queue)) { 04743 ast_copy_string(buffer, devstate2str(cur->status), len); 04744 } else { 04745 snprintf(tmp, sizeof(tmp), "%s%s:%s", ast_strlen_zero(tmp)?"":",", q->name, devstate2str(cur->status)); 04746 strncat(buffer, tmp, sizeof(tmp)); 04747 } 04748 ao2_ref(cur, -1); 04749 continue; 04750 } 04751 ao2_ref(cur, -1); 04752 } 04753 } 04754 ao2_unlock(q); 04755 } 04756 AST_LIST_UNLOCK(&queues); 04757 ast_copy_string(buf, buffer, len); 04758 ast_free(buffer); 04759 04760 ast_module_user_remove(lu); 04761 return 0; 04762 }
static int queue_function_queuewaitingcount | ( | struct ast_channel * | chan, | |
char * | cmd, | |||
char * | data, | |||
char * | buf, | |||
size_t | len | |||
) | [static] |
Definition at line 4608 of file app_queue.c.
References ao2_lock(), ao2_unlock(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_load_realtime(), ast_log(), ast_module_user_add, ast_module_user_remove, ast_strlen_zero(), ast_variables_destroy(), call_queue::count, LOG_ERROR, LOG_WARNING, call_queue::name, and var.
04609 { 04610 int count = 0; 04611 struct call_queue *q; 04612 struct ast_module_user *lu; 04613 struct ast_variable *var = NULL; 04614 04615 buf[0] = '\0'; 04616 04617 if (ast_strlen_zero(data)) { 04618 ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd); 04619 return -1; 04620 } 04621 04622 lu = ast_module_user_add(chan); 04623 04624 AST_LIST_LOCK(&queues); 04625 AST_LIST_TRAVERSE(&queues, q, list) { 04626 if (!strcasecmp(q->name, data)) { 04627 ao2_lock(q); 04628 break; 04629 } 04630 } 04631 AST_LIST_UNLOCK(&queues); 04632 04633 if (q) { 04634 count = q->count; 04635 ao2_unlock(q); 04636 } else if ((var = ast_load_realtime("queues", "name", data, NULL))) { 04637 /* if the queue is realtime but was not found in memory, this 04638 * means that the queue had been deleted from memory since it was 04639 * "dead." This means it has a 0 waiting count 04640 */ 04641 count = 0; 04642 ast_variables_destroy(var); 04643 } else 04644 ast_log(LOG_WARNING, "queue %s was not found\n", data); 04645 04646 snprintf(buf, len, "%d", count); 04647 ast_module_user_remove(lu); 04648 return 0; 04649 }
static int queue_member_count | ( | const char * | qname, | |
struct member_count * | qmc | |||
) | [static] |
Definition at line 5706 of file app_queue.c.
References member_count::active, member_count::all, ao2_iterator_init(), ao2_iterator_next(), ao2_lock(), ao2_ref(), ao2_unlock(), AST_DEVICE_INUSE, AST_DEVICE_INVALID, AST_DEVICE_NOT_INUSE, AST_DEVICE_UNAVAILABLE, AST_DEVICE_UNKNOWN, ast_log(), member_count::free, member_count::inuse, load_realtime_queue(), LOG_WARNING, call_queue::members, member_count::paused, member::paused, member::status, and member_count::valid.
Referenced by qmc_handler().
05707 { 05708 int res = 0; 05709 struct call_queue *q; 05710 struct member *m; 05711 struct ao2_iterator mem_iter; 05712 05713 if ((q = load_realtime_queue(qname))) { 05714 ao2_lock(q); 05715 mem_iter = ao2_iterator_init(q->members, 0); 05716 while ((m = ao2_iterator_next(&mem_iter))) { 05717 /* Count the queue members in use */ 05718 if (m->status == AST_DEVICE_INUSE) { 05719 qmc->inuse++; 05720 } 05721 /* Count the queue members who are logged in and presently answering calls */ 05722 if ((m->status != AST_DEVICE_UNAVAILABLE) && (m->status != AST_DEVICE_INVALID)) { 05723 qmc->valid++; 05724 } 05725 /* Count paused members */ 05726 if (m->paused) { 05727 qmc->paused++; 05728 } 05729 /* Count not paused members who are logged in and presently answering calls */ 05730 if (!m->paused && (m->status != AST_DEVICE_UNAVAILABLE) && (m->status != AST_DEVICE_INVALID)) { 05731 qmc->active++; 05732 } 05733 /* Count free members in the queue */ 05734 if (!m->paused && ((m->status == AST_DEVICE_UNKNOWN) || (m->status == AST_DEVICE_NOT_INUSE))) { 05735 qmc->free++; 05736 } 05737 qmc->all++; 05738 ao2_ref(m, -1); 05739 } 05740 ao2_unlock(q); 05741 } else { 05742 ast_log(LOG_WARNING, "Queue %s was not found\n", qname); 05743 res = -1; 05744 } 05745 return res; 05746 }
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 1041 of file app_queue.c.
References call_queue::announce, call_queue::announcefrequency, call_queue::announceholdtime, ANNOUNCEHOLDTIME_ALWAYS, ANNOUNCEHOLDTIME_ONCE, ast_copy_string(), 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::ringlimit, call_queue::roundingseconds, s, call_queue::servicelevel, call_queue::setinterfacevar, call_queue::sound_calls, call_queue::sound_holdtime, call_queue::sound_minute, 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().
01042 { 01043 if (!strcasecmp(param, "musicclass") || 01044 !strcasecmp(param, "music") || !strcasecmp(param, "musiconhold")) { 01045 ast_copy_string(q->moh, val, sizeof(q->moh)); 01046 } else if (!strcasecmp(param, "announce")) { 01047 ast_copy_string(q->announce, val, sizeof(q->announce)); 01048 } else if (!strcasecmp(param, "context")) { 01049 ast_copy_string(q->context, val, sizeof(q->context)); 01050 } else if (!strcasecmp(param, "timeout")) { 01051 q->timeout = atoi(val); 01052 if (q->timeout < 0) 01053 q->timeout = DEFAULT_TIMEOUT; 01054 } else if (!strcasecmp(param, "ringinuse")) { 01055 q->ringinuse = ast_true(val); 01056 } else if (!strcasecmp(param, "setinterfacevar")) { 01057 q->setinterfacevar = ast_true(val); 01058 } else if (!strcasecmp(param, "monitor-join")) { 01059 monjoin_dep_warning(); 01060 q->monjoin = ast_true(val); 01061 } else if (!strcasecmp(param, "monitor-format")) { 01062 ast_copy_string(q->monfmt, val, sizeof(q->monfmt)); 01063 } else if (!strcasecmp(param, "queue-youarenext")) { 01064 ast_copy_string(q->sound_next, val, sizeof(q->sound_next)); 01065 } else if (!strcasecmp(param, "queue-thereare")) { 01066 ast_copy_string(q->sound_thereare, val, sizeof(q->sound_thereare)); 01067 } else if (!strcasecmp(param, "queue-callswaiting")) { 01068 ast_copy_string(q->sound_calls, val, sizeof(q->sound_calls)); 01069 } else if (!strcasecmp(param, "queue-holdtime")) { 01070 ast_copy_string(q->sound_holdtime, val, sizeof(q->sound_holdtime)); 01071 } else if (!strcasecmp(param, "queue-minutes")) { 01072 ast_copy_string(q->sound_minutes, val, sizeof(q->sound_minutes)); 01073 } else if (!strcasecmp(param, "queue-minute")) { 01074 ast_copy_string(q->sound_minute, val, sizeof(q->sound_minute)); 01075 } else if (!strcasecmp(param, "queue-seconds")) { 01076 ast_copy_string(q->sound_seconds, val, sizeof(q->sound_seconds)); 01077 } else if (!strcasecmp(param, "queue-thankyou")) { 01078 ast_copy_string(q->sound_thanks, val, sizeof(q->sound_thanks)); 01079 } else if (!strcasecmp(param, "queue-reporthold")) { 01080 ast_copy_string(q->sound_reporthold, val, sizeof(q->sound_reporthold)); 01081 } else if (!strcasecmp(param, "announce-frequency")) { 01082 q->announcefrequency = atoi(val); 01083 } else if (!strcasecmp(param, "announce-round-seconds")) { 01084 q->roundingseconds = atoi(val); 01085 /* Rounding to any other values just doesn't make sense... */ 01086 if (!(q->roundingseconds == 0 || q->roundingseconds == 5 || q->roundingseconds == 10 01087 || q->roundingseconds == 15 || q->roundingseconds == 20 || q->roundingseconds == 30)) { 01088 if (linenum >= 0) { 01089 ast_log(LOG_WARNING, "'%s' isn't a valid value for %s " 01090 "using 0 instead for queue '%s' at line %d of queues.conf\n", 01091 val, param, q->name, linenum); 01092 } else { 01093 ast_log(LOG_WARNING, "'%s' isn't a valid value for %s " 01094 "using 0 instead for queue '%s'\n", val, param, q->name); 01095 } 01096 q->roundingseconds=0; 01097 } 01098 } else if (!strcasecmp(param, "announce-holdtime")) { 01099 if (!strcasecmp(val, "once")) 01100 q->announceholdtime = ANNOUNCEHOLDTIME_ONCE; 01101 else if (ast_true(val)) 01102 q->announceholdtime = ANNOUNCEHOLDTIME_ALWAYS; 01103 else 01104 q->announceholdtime = 0; 01105 } else if (!strcasecmp(param, "periodic-announce")) { 01106 if (strchr(val, '|')) { 01107 char *s, *buf = ast_strdupa(val); 01108 unsigned int i = 0; 01109 01110 while ((s = strsep(&buf, "|"))) { 01111 ast_copy_string(q->sound_periodicannounce[i], s, sizeof(q->sound_periodicannounce[i])); 01112 i++; 01113 if (i == MAX_PERIODIC_ANNOUNCEMENTS) 01114 break; 01115 } 01116 } else { 01117 ast_copy_string(q->sound_periodicannounce[0], val, sizeof(q->sound_periodicannounce[0])); 01118 } 01119 } else if (!strcasecmp(param, "periodic-announce-frequency")) { 01120 q->periodicannouncefrequency = atoi(val); 01121 } else if (!strcasecmp(param, "retry")) { 01122 q->retry = atoi(val); 01123 if (q->retry <= 0) 01124 q->retry = DEFAULT_RETRY; 01125 } else if (!strcasecmp(param, "wrapuptime")) { 01126 q->wrapuptime = atoi(val); 01127 } else if (!strcasecmp(param, "autofill")) { 01128 q->autofill = ast_true(val); 01129 } else if (!strcasecmp(param, "monitor-type")) { 01130 if (!strcasecmp(val, "mixmonitor")) 01131 q->montype = 1; 01132 } else if (!strcasecmp(param, "autopause")) { 01133 q->autopause = ast_true(val); 01134 } else if (!strcasecmp(param, "maxlen")) { 01135 q->maxlen = atoi(val); 01136 if (q->maxlen < 0) 01137 q->maxlen = 0; 01138 } else if (!strcasecmp(param, "ringlimit")) { 01139 q->ringlimit = atoi(val); 01140 if (q->ringlimit < 0) 01141 q->ringlimit = 0; 01142 } else if (!strcasecmp(param, "servicelevel")) { 01143 q->servicelevel= atoi(val); 01144 } else if (!strcasecmp(param, "strategy")) { 01145 q->strategy = strat2int(val); 01146 if (q->strategy < 0) { 01147 ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n", 01148 val, q->name); 01149 q->strategy = QUEUE_STRATEGY_RINGALL; 01150 } 01151 } else if (!strcasecmp(param, "joinempty")) { 01152 if (!strcasecmp(val, "strict")) 01153 q->joinempty = QUEUE_EMPTY_STRICT; 01154 else if (ast_true(val)) 01155 q->joinempty = QUEUE_EMPTY_NORMAL; 01156 else 01157 q->joinempty = 0; 01158 } else if (!strcasecmp(param, "leavewhenempty")) { 01159 if (!strcasecmp(val, "strict")) 01160 q->leavewhenempty = QUEUE_EMPTY_STRICT; 01161 else if (ast_true(val)) 01162 q->leavewhenempty = QUEUE_EMPTY_NORMAL; 01163 else 01164 q->leavewhenempty = 0; 01165 } else if (!strcasecmp(param, "eventmemberstatus")) { 01166 q->maskmemberstatus = !ast_true(val); 01167 } else if (!strcasecmp(param, "eventwhencalled")) { 01168 if (!strcasecmp(val, "vars")) { 01169 q->eventwhencalled = QUEUE_EVENT_VARIABLES; 01170 } else { 01171 q->eventwhencalled = ast_true(val) ? 1 : 0; 01172 } 01173 } else if (!strcasecmp(param, "reportholdtime")) { 01174 q->reportholdtime = ast_true(val); 01175 } else if (!strcasecmp(param, "memberdelay")) { 01176 q->memberdelay = atoi(val); 01177 } else if (!strcasecmp(param, "weight")) { 01178 q->weight = atoi(val); 01179 if (q->weight) 01180 use_weight++; 01181 /* With Realtime queues, if the last queue using weights is deleted in realtime, 01182 we will not see any effect on use_weight until next reload. */ 01183 } else if (!strcasecmp(param, "timeoutrestart")) { 01184 q->timeoutrestart = ast_true(val); 01185 } else if (failunknown) { 01186 if (linenum >= 0) { 01187 ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s at line %d of queues.conf\n", 01188 q->name, param, linenum); 01189 } else { 01190 ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s\n", q->name, param); 01191 } 01192 } 01193 }
static int queue_show | ( | int | fd, | |
int | argc, | |||
char ** | argv | |||
) | [static] |
Definition at line 5278 of file app_queue.c.
References __queues_show().
Referenced by __queues_show().
05279 { 05280 return __queues_show(NULL, 0, fd, argc, argv); 05281 }
static void queue_transfer_destroy | ( | void * | data | ) | [static] |
Definition at line 2866 of file app_queue.c.
References ast_free.
02867 { 02868 struct queue_transfer_ds *qtds = data; 02869 ast_free(qtds); 02870 }
static void queue_transfer_fixup | ( | void * | data, | |
struct ast_channel * | old_chan, | |||
struct ast_channel * | new_chan | |||
) | [static] |
Log an attended transfer when a queue caller channel is masqueraded.
When a caller is masqueraded, we want to log a transfer. Fixup time is the closest we can come to when the actual transfer occurs. This happens during the masquerade after datastores are moved from old_chan to new_chan. This is why new_chan is referenced for exten, context, and datastore information.
At the end of this, we want to remove the datastore so that this fixup function is not called on any future masquerades of the caller during the current call.
Definition at line 2889 of file app_queue.c.
References ast_channel_datastore_find(), ast_channel_datastore_remove(), ast_log(), ast_queue_log(), queue_transfer_ds::callcompletedinsl, queue_ent::chan, ast_channel::context, ast_channel::exten, LOG_WARNING, queue_transfer_ds::member, member::membername, call_queue::name, queue_ent::parent, queue_transfer_ds::qe, queue_transfer_info, queue_ent::start, queue_transfer_ds::starttime, and update_queue().
02890 { 02891 struct queue_transfer_ds *qtds = data; 02892 struct queue_ent *qe = qtds->qe; 02893 struct member *member = qtds->member; 02894 time_t callstart = qtds->starttime; 02895 int callcompletedinsl = qtds->callcompletedinsl; 02896 struct ast_datastore *datastore; 02897 02898 ast_queue_log(qe->parent->name, qe->chan->uniqueid, member->membername, "TRANSFER", "%s|%s|%ld|%ld", 02899 new_chan->exten, new_chan->context, (long) (callstart - qe->start), 02900 (long) (time(NULL) - callstart)); 02901 02902 update_queue(qe->parent, member, callcompletedinsl); 02903 02904 /* No need to lock the channels because they are already locked in ast_do_masquerade */ 02905 if ((datastore = ast_channel_datastore_find(old_chan, &queue_transfer_info, NULL))) { 02906 ast_channel_datastore_remove(old_chan, datastore); 02907 } else { 02908 ast_log(LOG_WARNING, "Can't find the queue_transfer datastore.\n"); 02909 } 02910 }
static void recalc_holdtime | ( | struct queue_ent * | qe, | |
int | newholdtime | |||
) | [static] |
Definition at line 1756 of file app_queue.c.
References ao2_lock(), ao2_unlock(), call_queue::holdtime, and queue_ent::parent.
Referenced by try_calling().
01757 { 01758 int oldvalue; 01759 01760 /* Calculate holdtime using an exponential average */ 01761 /* Thanks to SRT for this contribution */ 01762 /* 2^2 (4) is the filter coefficient; a higher exponent would give old entries more weight */ 01763 01764 ao2_lock(qe->parent); 01765 oldvalue = qe->parent->holdtime; 01766 qe->parent->holdtime = (((oldvalue << 2) - oldvalue) + newholdtime) >> 2; 01767 ao2_unlock(qe->parent); 01768 }
static void record_abandoned | ( | struct queue_ent * | qe | ) | [static] |
Definition at line 2278 of file app_queue.c.
References ao2_lock(), ao2_unlock(), call_queue::callsabandoned, queue_ent::chan, EVENT_FLAG_AGENT, 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().
02279 { 02280 ao2_lock(qe->parent); 02281 manager_event(EVENT_FLAG_AGENT, "QueueCallerAbandon", 02282 "Queue: %s\r\n" 02283 "Uniqueid: %s\r\n" 02284 "Position: %d\r\n" 02285 "OriginalPosition: %d\r\n" 02286 "HoldTime: %d\r\n", 02287 qe->parent->name, qe->chan->uniqueid, qe->pos, qe->opos, (int)(time(NULL) - qe->start)); 02288 02289 qe->parent->callsabandoned++; 02290 ao2_unlock(qe->parent); 02291 }
static int reload | ( | void | ) | [static] |
Definition at line 5950 of file app_queue.c.
References reload_queues().
05951 { 05952 reload_queues(); 05953 return 0; 05954 }
static void reload_queue_members | ( | void | ) | [static] |
Definition at line 3831 of file app_queue.c.
References add_to_queue(), ao2_lock(), ao2_unlock(), ast_db_del(), ast_db_freetree(), ast_db_get(), ast_db_gettree(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_strlen_zero(), ERANGE, errno, member_interface::interface, ast_db_entry::key, load_realtime_queue(), 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, member::state_interface, and strsep().
Referenced by load_module().
03832 { 03833 char *cur_ptr; 03834 char *queue_name; 03835 char *member; 03836 char *interface; 03837 char *membername = NULL; 03838 char *state_interface; 03839 char *penalty_tok; 03840 int penalty = 0; 03841 char *paused_tok; 03842 int paused = 0; 03843 struct ast_db_entry *db_tree; 03844 struct ast_db_entry *entry; 03845 struct call_queue *cur_queue; 03846 char queue_data[PM_MAX_LEN]; 03847 03848 AST_LIST_LOCK(&queues); 03849 03850 /* Each key in 'pm_family' is the name of a queue */ 03851 db_tree = ast_db_gettree(pm_family, NULL); 03852 for (entry = db_tree; entry; entry = entry->next) { 03853 03854 queue_name = entry->key + strlen(pm_family) + 2; 03855 03856 AST_LIST_TRAVERSE(&queues, cur_queue, list) { 03857 ao2_lock(cur_queue); 03858 if (!strcmp(queue_name, cur_queue->name)) 03859 break; 03860 ao2_unlock(cur_queue); 03861 } 03862 03863 if (!cur_queue) 03864 cur_queue = load_realtime_queue(queue_name); 03865 03866 if (!cur_queue) { 03867 /* If the queue no longer exists, remove it from the 03868 * database */ 03869 ast_log(LOG_WARNING, "Error loading persistent queue: '%s': it does not exist\n", queue_name); 03870 ast_db_del(pm_family, queue_name); 03871 continue; 03872 } else 03873 ao2_unlock(cur_queue); 03874 03875 if (ast_db_get(pm_family, queue_name, queue_data, PM_MAX_LEN)) 03876 continue; 03877 03878 cur_ptr = queue_data; 03879 while ((member = strsep(&cur_ptr, "|"))) { 03880 if (ast_strlen_zero(member)) 03881 continue; 03882 03883 interface = strsep(&member, ";"); 03884 penalty_tok = strsep(&member, ";"); 03885 paused_tok = strsep(&member, ";"); 03886 membername = strsep(&member, ";"); 03887 state_interface = strsep(&member,";"); 03888 03889 if (!penalty_tok) { 03890 ast_log(LOG_WARNING, "Error parsing persistent member string for '%s' (penalty)\n", queue_name); 03891 break; 03892 } 03893 penalty = strtol(penalty_tok, NULL, 10); 03894 if (errno == ERANGE) { 03895 ast_log(LOG_WARNING, "Error converting penalty: %s: Out of range.\n", penalty_tok); 03896 break; 03897 } 03898 03899 if (!paused_tok) { 03900 ast_log(LOG_WARNING, "Error parsing persistent member string for '%s' (paused)\n", queue_name); 03901 break; 03902 } 03903 paused = strtol(paused_tok, NULL, 10); 03904 if ((errno == ERANGE) || paused < 0 || paused > 1) { 03905 ast_log(LOG_WARNING, "Error converting paused: %s: Expected 0 or 1.\n", paused_tok); 03906 break; 03907 } 03908 if (ast_strlen_zero(membername)) 03909 membername = interface; 03910 03911 if (option_debug) 03912 ast_log(LOG_DEBUG, "Reload Members: Queue: %s Member: %s Name: %s Penalty: %d Paused: %d\n", queue_name, interface, membername, penalty, paused); 03913 03914 if (add_to_queue(queue_name, interface, membername, penalty, paused, 0, state_interface) == RES_OUTOFMEMORY) { 03915 ast_log(LOG_ERROR, "Out of Memory when reloading persistent queue member\n"); 03916 break; 03917 } 03918 } 03919 } 03920 03921 AST_LIST_UNLOCK(&queues); 03922 if (db_tree) { 03923 ast_log(LOG_NOTICE, "Queue members successfully reloaded from database.\n"); 03924 ast_db_freetree(db_tree); 03925 } 03926 }
static int reload_queues | ( | void | ) | [static] |
Definition at line 4905 of file app_queue.c.
References add_to_interfaces(), alloc_queue(), ao2_find(), ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next(), ao2_lock(), ao2_ref(), ao2_unlink(), ao2_unlock(), AST_APP_ARG, ast_category_browse(), ast_config_destroy(), ast_config_load(), ast_copy_string(), AST_DECLARE_APP_ARGS, ast_free, 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_NONSTANDARD_APP_ARGS, ast_skip_blanks(), ast_strdup, ast_strlen_zero(), ast_true(), ast_variable_browse(), ast_variable_retrieve(), clear_queue(), create_queue_member(), call_queue::dead, member::delme, member::dynamic, call_queue::found, init_queue(), member::interface, member_interface::interface, ast_variable::lineno, 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_RINGALL, QUEUE_STRATEGY_ROUNDROBIN, call_queue::realtime, remove_from_interfaces(), rr_dep_warning(), member::state_interface, member::status, strat2int(), call_queue::strategy, ast_variable::value, and var.
Referenced by load_module(), and reload().
04906 { 04907 struct call_queue *q; 04908 struct ast_config *cfg; 04909 char *cat, *tmp; 04910 struct ast_variable *var; 04911 struct member *cur, *newm; 04912 struct ao2_iterator mem_iter; 04913 int new; 04914 const char *general_val = NULL; 04915 char *parse; 04916 char *interface, *state_interface; 04917 char *membername = NULL; 04918 int penalty; 04919 AST_DECLARE_APP_ARGS(args, 04920 AST_APP_ARG(interface); 04921 AST_APP_ARG(penalty); 04922 AST_APP_ARG(membername); 04923 AST_APP_ARG(state_interface); 04924 ); 04925 04926 if (!(cfg = ast_config_load("queues.conf"))) { 04927 ast_log(LOG_NOTICE, "No call queueing config file (queues.conf), so no call queues\n"); 04928 return 0; 04929 } 04930 AST_LIST_LOCK(&queues); 04931 use_weight=0; 04932 /* Mark all non-realtime queues as dead for the moment */ 04933 AST_LIST_TRAVERSE(&queues, q, list) { 04934 if (!q->realtime) { 04935 q->dead = 1; 04936 q->found = 0; 04937 } 04938 } 04939 04940 /* Chug through config file */ 04941 cat = NULL; 04942 while ((cat = ast_category_browse(cfg, cat)) ) { 04943 if (!strcasecmp(cat, "general")) { 04944 /* Initialize global settings */ 04945 queue_debug = 0; 04946 if ((general_val = ast_variable_retrieve(cfg, "general", "debug"))) 04947 queue_debug = ast_true(general_val); 04948 queue_persistent_members = 0; 04949 if ((general_val = ast_variable_retrieve(cfg, "general", "persistentmembers"))) 04950 queue_persistent_members = ast_true(general_val); 04951 autofill_default = 0; 04952 if ((general_val = ast_variable_retrieve(cfg, "general", "autofill"))) 04953 autofill_default = ast_true(general_val); 04954 montype_default = 0; 04955 if ((general_val = ast_variable_retrieve(cfg, "general", "monitor-type"))) 04956 if (!strcasecmp(general_val, "mixmonitor")) 04957 montype_default = 1; 04958 shared_lastcall = 0; 04959 if ((general_val = ast_variable_retrieve(cfg, "general", "shared_lastcall"))) 04960 shared_lastcall = ast_true(general_val); 04961 } else { /* Define queue */ 04962 /* Look for an existing one */ 04963 AST_LIST_TRAVERSE(&queues, q, list) { 04964 if (!strcmp(q->name, cat)) 04965 break; 04966 } 04967 if (!q) { 04968 /* Make one then */ 04969 if (!(q = alloc_queue(cat))) { 04970 /* TODO: Handle memory allocation failure */ 04971 } 04972 new = 1; 04973 } else 04974 new = 0; 04975 if (q) { 04976 const char *tmpvar; 04977 if (!new) 04978 ao2_lock(q); 04979 /* Check if a queue with this name already exists */ 04980 if (q->found) { 04981 ast_log(LOG_WARNING, "Queue '%s' already defined! Skipping!\n", cat); 04982 if (!new) 04983 ao2_unlock(q); 04984 continue; 04985 } 04986 04987 /* Due to the fact that the "rrordered" strategy will have a different allocation 04988 * scheme for queue members, we must devise the queue's strategy before other initializations. 04989 * To be specific, the rrordered strategy needs to function like a linked list, meaning the ao2 04990 * container used will have only a single bucket instead of the typical number. 04991 */ 04992 if ((tmpvar = ast_variable_retrieve(cfg, cat, "strategy"))) { 04993 q->strategy = strat2int(tmpvar); 04994 if (q->strategy < 0) { 04995 ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n", tmpvar, q->name); 04996 q->strategy = QUEUE_STRATEGY_RINGALL; 04997 } 04998 } else { 04999 q->strategy = QUEUE_STRATEGY_RINGALL; 05000 } 05001 05002 /* Re-initialize the queue, and clear statistics */ 05003 init_queue(q); 05004 clear_queue(q); 05005 mem_iter = ao2_iterator_init(q->members, 0); 05006 while ((cur = ao2_iterator_next(&mem_iter))) { 05007 if (!cur->dynamic) { 05008 cur->delme = 1; 05009 } 05010 ao2_ref(cur, -1); 05011 } 05012 ao2_iterator_destroy(&mem_iter); 05013 for (var = ast_variable_browse(cfg, cat); var; var = var->next) { 05014 if (!strcasecmp(var->name, "member")) { 05015 struct member tmpmem; 05016 membername = NULL; 05017 05018 if (ast_strlen_zero(var->value)) { 05019 ast_log(LOG_WARNING, "Empty queue member definition at line %d. Moving on!\n", var->lineno); 05020 continue; 05021 } 05022 05023 /* Add a new member */ 05024 if (!(parse = ast_strdup(var->value))) { 05025 continue; 05026 } 05027 05028 AST_NONSTANDARD_APP_ARGS(args, parse, ','); 05029 05030 interface = args.interface; 05031 if (!ast_strlen_zero(args.penalty)) { 05032 tmp = ast_skip_blanks(args.penalty); 05033 penalty = atoi(tmp); 05034 if (penalty < 0) { 05035 penalty = 0; 05036 } 05037 } else 05038 penalty = 0; 05039 05040 if (!ast_strlen_zero(args.membername)) { 05041 membername = ast_skip_blanks(args.membername); 05042 } 05043 05044 if (!ast_strlen_zero(args.state_interface)) { 05045 state_interface = ast_skip_blanks(args.state_interface); 05046 } else { 05047 state_interface = interface; 05048 } 05049 05050 /* Find the old position in the list */ 05051 ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface)); 05052 cur = ao2_find(q->members, &tmpmem, OBJ_POINTER | OBJ_UNLINK); 05053 05054 /* Only attempt removing from interfaces list if the new state_interface is different than the old one */ 05055 if (cur && strcasecmp(cur->state_interface, state_interface)) { 05056 remove_from_interfaces(cur->state_interface); 05057 } 05058 05059 newm = create_queue_member(interface, membername, penalty, cur ? cur->paused : 0, state_interface); 05060 if (!cur || (cur && strcasecmp(cur->state_interface, state_interface))) { 05061 add_to_interfaces(state_interface); 05062 } 05063 ao2_link(q->members, newm); 05064 ao2_ref(newm, -1); 05065 newm = NULL; 05066 05067 if (cur) 05068 ao2_ref(cur, -1); 05069 else { 05070 q->membercount++; 05071 } 05072 ast_free(parse); 05073 } else { 05074 queue_set_param(q, var->name, var->value, var->lineno, 1); 05075 } 05076 } 05077 05078 /* Free remaining members marked as delme */ 05079 mem_iter = ao2_iterator_init(q->members, 0); 05080 while ((cur = ao2_iterator_next(&mem_iter))) { 05081 if (! cur->delme) { 05082 ao2_ref(cur, -1); 05083 continue; 05084 } 05085 05086 q->membercount--; 05087 ao2_unlink(q->members, cur); 05088 remove_from_interfaces(cur->state_interface); 05089 ao2_ref(cur, -1); 05090 } 05091 ao2_iterator_destroy(&mem_iter); 05092 05093 if (q->strategy == QUEUE_STRATEGY_ROUNDROBIN) 05094 rr_dep_warning(); 05095 05096 if (new) { 05097 AST_LIST_INSERT_HEAD(&queues, q, list); 05098 } else 05099 ao2_unlock(q); 05100 } 05101 } 05102 } 05103 ast_config_destroy(cfg); 05104 AST_LIST_TRAVERSE_SAFE_BEGIN(&queues, q, list) { 05105 if (q->dead) { 05106 AST_LIST_REMOVE_CURRENT(&queues, list); 05107 ao2_ref(q, -1); 05108 } else { 05109 ao2_lock(q); 05110 mem_iter = ao2_iterator_init(q->members, 0); 05111 while ((cur = ao2_iterator_next(&mem_iter))) { 05112 if (cur->dynamic) 05113 q->membercount++; 05114 cur->status = ast_device_state(cur->state_interface); 05115 ao2_ref(cur, -1); 05116 } 05117 ao2_iterator_destroy(&mem_iter); 05118 ao2_unlock(q); 05119 } 05120 } 05121 AST_LIST_TRAVERSE_SAFE_END; 05122 AST_LIST_UNLOCK(&queues); 05123 return 1; 05124 }
static int remove_from_interfaces | ( | const char * | interface | ) | [static] |
Definition at line 1001 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(), rt_handle_member_record(), and update_realtime_members().
01002 { 01003 struct member_interface *curint; 01004 01005 if (interface_exists_global(interface)) 01006 return 0; 01007 01008 AST_LIST_LOCK(&interfaces); 01009 AST_LIST_TRAVERSE_SAFE_BEGIN(&interfaces, curint, list) { 01010 if (!strcasecmp(curint->interface, interface)) { 01011 if (option_debug) 01012 ast_log(LOG_DEBUG, "Removing %s from the list of interfaces that make up all of our queue members.\n", interface); 01013 AST_LIST_REMOVE_CURRENT(&interfaces, list); 01014 free(curint); 01015 break; 01016 } 01017 } 01018 AST_LIST_TRAVERSE_SAFE_END; 01019 AST_LIST_UNLOCK(&interfaces); 01020 01021 return 0; 01022 }
static int remove_from_queue | ( | const char * | queuename, | |
const char * | interface | |||
) | [static] |
Definition at line 3679 of file app_queue.c.
References ao2_find(), ao2_lock(), ao2_ref(), ao2_unlink(), ao2_unlock(), ast_copy_string(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, dump_queue_members(), member::dynamic, EVENT_FLAG_AGENT, member::interface, manager_event(), call_queue::membercount, member::membername, call_queue::members, call_queue::name, remove_from_interfaces(), RES_EXISTS, RES_NOSUCHQUEUE, RES_NOT_DYNAMIC, RES_OKAY, and member::state_interface.
Referenced by handle_queue_remove_member(), manager_remove_queue_member(), and rqm_exec().
03680 { 03681 struct call_queue *q; 03682 struct member *mem, tmpmem; 03683 int res = RES_NOSUCHQUEUE; 03684 03685 ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface)); 03686 03687 AST_LIST_LOCK(&queues); 03688 AST_LIST_TRAVERSE(&queues, q, list) { 03689 ao2_lock(q); 03690 if (strcmp(q->name, queuename)) { 03691 ao2_unlock(q); 03692 continue; 03693 } 03694 03695 if ((mem = ao2_find(q->members, &tmpmem, OBJ_POINTER))) { 03696 /* XXX future changes should beware of this assumption!! */ 03697 if (!mem->dynamic) { 03698 res = RES_NOT_DYNAMIC; 03699 ao2_ref(mem, -1); 03700 ao2_unlock(q); 03701 break; 03702 } 03703 q->membercount--; 03704 manager_event(EVENT_FLAG_AGENT, "QueueMemberRemoved", 03705 "Queue: %s\r\n" 03706 "Location: %s\r\n" 03707 "MemberName: %s\r\n", 03708 q->name, mem->interface, mem->membername); 03709 ao2_unlink(q->members, mem); 03710 remove_from_interfaces(mem->state_interface); 03711 ao2_ref(mem, -1); 03712 03713 if (queue_persistent_members) 03714 dump_queue_members(q); 03715 03716 res = RES_OKAY; 03717 } else { 03718 res = RES_EXISTS; 03719 } 03720 ao2_unlock(q); 03721 break; 03722 } 03723 03724 AST_LIST_UNLOCK(&queues); 03725 03726 return res; 03727 }
static void remove_queue | ( | struct call_queue * | q | ) | [static] |
removes a call_queue from the list of call_queues
Definition at line 541 of file app_queue.c.
References ao2_ref(), AST_LIST_LOCK, AST_LIST_REMOVE, and AST_LIST_UNLOCK.
Referenced by find_queue_by_name_rt(), and leave_queue().
00542 { 00543 AST_LIST_LOCK(&queues); 00544 if (AST_LIST_REMOVE(&queues, q, list)) { 00545 ao2_ref(q, -1); 00546 } 00547 AST_LIST_UNLOCK(&queues); 00548 }
static int ring_entry | ( | struct queue_ent * | qe, | |
struct callattempt * | tmp, | |||
int * | busies | |||
) | [static] |
Part 2 of ring_one.
Does error checking before attempting to request a channel and call a member. This function is only called from ring_one
Definition at line 1959 of file app_queue.c.
References ast_cdr::accountcode, ast_channel::adsicpe, ast_cdr::amaflags, ao2_lock(), ao2_unlock(), ast_channel::appl, ast_call(), ast_cdr_busy(), ast_cdr_isset_unanswered(), ast_cdr_setdestchan(), ast_channel_datastore_inherit(), ast_channel_inherit_variables(), ast_channel_lock, ast_channel_unlock, ast_copy_string(), AST_DEVICE_NOT_INUSE, AST_DEVICE_UNKNOWN, ast_log(), ast_request(), ast_strdup, ast_strlen_zero(), ast_verbose(), ast_channel::cdr, callattempt::chan, queue_ent::chan, ast_cdr::channel, ast_channel::cid, ast_callerid::cid_ani, ast_callerid::cid_name, ast_callerid::cid_num, ast_cdr::clid, compare_weight(), ast_channel::context, ast_channel::data, ast_cdr::dcontext, ast_channel::dialcontext, do_hang(), ast_cdr::dst, EVENT_FLAG_AGENT, call_queue::eventwhencalled, ast_channel::exten, free, callattempt::interface, ast_cdr::lastapp, callattempt::lastcall, ast_cdr::lastdata, callattempt::lastqueue, queue_ent::linpos, LOG_DEBUG, LOG_NOTICE, manager_event(), callattempt::member, member::membername, call_queue::name, ast_channel::nativeformats, option_debug, option_verbose, queue_ent::parent, member::paused, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), ast_channel::priority, QUEUE_EVENT_VARIABLES, member::ringcount, call_queue::ringinuse, call_queue::rrpos, ast_cdr::src, member::state_interface, member::status, callattempt::stillgoing, update_status(), ast_cdr::userfield, vars2manager(), VERBOSE_PREFIX_3, ast_channel::whentohangup, and call_queue::wrapuptime.
Referenced by ring_one().
01960 { 01961 int res; 01962 int status; 01963 char tech[256]; 01964 char *location, *location2; 01965 const char *macrocontext, *macroexten; 01966 char pickupmark[256], chan[128]; 01967 01968 /* on entry here, we know that tmp->chan == NULL */ 01969 if ((tmp->lastqueue && tmp->lastqueue->wrapuptime && (time(NULL) - tmp->lastcall < tmp->lastqueue->wrapuptime)) || 01970 (!tmp->lastqueue && qe->parent->wrapuptime && (time(NULL) - tmp->lastcall < qe->parent->wrapuptime))) { 01971 if (queue_debug) 01972 ast_log(LOG_NOTICE, "Wrapuptime not yet expired on queue %s for %s\n", 01973 (tmp->lastqueue ? tmp->lastqueue->name : qe->parent->name), tmp->interface); 01974 tmp->stillgoing = 0; 01975 (*busies)++; 01976 return 0; 01977 } 01978 01979 if (!qe->parent->ringinuse && (tmp->member->status != AST_DEVICE_NOT_INUSE) && (tmp->member->status != AST_DEVICE_UNKNOWN)) { 01980 if (queue_debug) 01981 ast_log(LOG_NOTICE, "%s in use, can't receive call\n", tmp->interface); 01982 tmp->stillgoing = 0; 01983 (*busies)++; 01984 return 0; 01985 } 01986 01987 if (tmp->member->paused) { 01988 if (queue_debug) 01989 ast_log(LOG_NOTICE, "%s paused, can't receive call\n", tmp->interface); 01990 tmp->stillgoing = 0; 01991 (*busies)++; 01992 return 0; 01993 } 01994 if (use_weight && compare_weight(qe->parent,tmp->member)) { 01995 if (queue_debug) 01996 ast_log(LOG_NOTICE, "Priority queue delaying call to %s:%s\n", qe->parent->name, tmp->interface); 01997 if (qe->chan->cdr) 01998 ast_cdr_busy(qe->chan->cdr); 01999 tmp->stillgoing = 0; 02000 (*busies)++; 02001 return 0; 02002 } 02003 02004 ast_copy_string(tech, tmp->interface, sizeof(tech)); 02005 if ((location = strchr(tech, '/'))) 02006 *location++ = '\0'; 02007 else 02008 location = ""; 02009 02010 /* Request the peer */ 02011 tmp->chan = ast_request(tech, qe->chan->nativeformats, location, &status); 02012 if (!tmp->chan) { /* If we can't, just go on to the next call */ 02013 if (queue_debug) 02014 ast_log(LOG_NOTICE, "Unable to create channel of type '%s' for Queue\n", tech); 02015 if (qe->chan->cdr) 02016 ast_cdr_busy(qe->chan->cdr); 02017 tmp->stillgoing = 0; 02018 02019 update_status(tmp->member->state_interface, ast_device_state(tmp->member->state_interface)); 02020 02021 ao2_lock(qe->parent); 02022 qe->parent->rrpos++; 02023 qe->linpos++; 02024 ao2_unlock(qe->parent); 02025 02026 (*busies)++; 02027 return 0; 02028 } 02029 02030 /* Increment ring count */ 02031 tmp->member->ringcount++; 02032 tmp->chan->appl = "AppQueue"; 02033 tmp->chan->data = "(Outgoing Line)"; 02034 tmp->chan->whentohangup = 0; 02035 if (tmp->chan->cid.cid_num) 02036 free(tmp->chan->cid.cid_num); 02037 tmp->chan->cid.cid_num = ast_strdup(qe->chan->cid.cid_num); 02038 if (tmp->chan->cid.cid_name) 02039 free(tmp->chan->cid.cid_name); 02040 tmp->chan->cid.cid_name = ast_strdup(qe->chan->cid.cid_name); 02041 if (tmp->chan->cid.cid_ani) 02042 free(tmp->chan->cid.cid_ani); 02043 tmp->chan->cid.cid_ani = ast_strdup(qe->chan->cid.cid_ani); 02044 02045 /* Inherit specially named variables from parent channel */ 02046 ast_channel_inherit_variables(qe->chan, tmp->chan); 02047 ast_channel_datastore_inherit(qe->chan, tmp->chan); 02048 02049 /* Presense of ADSI CPE on outgoing channel follows ours */ 02050 tmp->chan->adsicpe = qe->chan->adsicpe; 02051 02052 /* Inherit context and extension */ 02053 ast_channel_lock(qe->chan); 02054 macrocontext = pbx_builtin_getvar_helper(qe->chan, "MACRO_CONTEXT"); 02055 if (!ast_strlen_zero(macrocontext)) 02056 ast_copy_string(tmp->chan->dialcontext, macrocontext, sizeof(tmp->chan->dialcontext)); 02057 else 02058 ast_copy_string(tmp->chan->dialcontext, qe->chan->context, sizeof(tmp->chan->dialcontext)); 02059 macroexten = pbx_builtin_getvar_helper(qe->chan, "MACRO_EXTEN"); 02060 if (!ast_strlen_zero(macroexten)) 02061 ast_copy_string(tmp->chan->exten, macroexten, sizeof(tmp->chan->exten)); 02062 else 02063 ast_copy_string(tmp->chan->exten, qe->chan->exten, sizeof(tmp->chan->exten)); 02064 if (ast_cdr_isset_unanswered()) { 02065 /* they want to see the unanswered dial attempts! */ 02066 /* set up the CDR fields on all the CDRs to give sensical information */ 02067 ast_cdr_setdestchan(tmp->chan->cdr, tmp->chan->name); 02068 strcpy(tmp->chan->cdr->clid, qe->chan->cdr->clid); 02069 strcpy(tmp->chan->cdr->channel, qe->chan->cdr->channel); 02070 strcpy(tmp->chan->cdr->src, qe->chan->cdr->src); 02071 strcpy(tmp->chan->cdr->dst, qe->chan->exten); 02072 strcpy(tmp->chan->cdr->dcontext, qe->chan->context); 02073 strcpy(tmp->chan->cdr->lastapp, qe->chan->cdr->lastapp); 02074 strcpy(tmp->chan->cdr->lastdata, qe->chan->cdr->lastdata); 02075 tmp->chan->cdr->amaflags = qe->chan->cdr->amaflags; 02076 strcpy(tmp->chan->cdr->accountcode, qe->chan->cdr->accountcode); 02077 strcpy(tmp->chan->cdr->userfield, qe->chan->cdr->userfield); 02078 } 02079 ast_channel_unlock(qe->chan); 02080 02081 /* Add a PICKUPMARK variable to ringing interface */ 02082 if (option_debug > 2) 02083 ast_log(LOG_DEBUG, "chan %s, tech: %s, part %s\n", tmp->chan->name, tech, location); 02084 /* Delete DAHDI ring pattern in tech like DAHDI/1r2 */ 02085 ast_copy_string(chan, location, sizeof(chan)); 02086 if (!strncasecmp(tech, "dahdi", 5)) { 02087 if((chan[0] > '0') && (chan[0] <= '9')) { 02088 if ((location2 = strchr(chan, 'r'))) 02089 *location2++ = '\0'; 02090 } 02091 } 02092 snprintf(pickupmark, sizeof(pickupmark), "%s/%s", tech, chan); 02093 pbx_builtin_setvar_helper(tmp->chan, "PICKUPMARK", pickupmark); 02094 02095 /* Place the call, but don't wait on the answer */ 02096 if ((res = ast_call(tmp->chan, location, 0))) { 02097 /* Again, keep going even if there's an error */ 02098 if (option_debug) 02099 ast_log(LOG_DEBUG, "ast call on peer returned %d\n", res); 02100 if (option_verbose > 2) 02101 ast_verbose(VERBOSE_PREFIX_3 "Couldn't call %s\n", tmp->interface); 02102 do_hang(tmp); 02103 (*busies)++; 02104 update_status(tmp->member->state_interface, ast_device_state(tmp->member->state_interface)); 02105 return 0; 02106 } else if (qe->parent->eventwhencalled) { 02107 char vars[2048]; 02108 02109 manager_event(EVENT_FLAG_AGENT, "AgentCalled", 02110 "AgentCalled: %s\r\n" 02111 "AgentName: %s\r\n" 02112 "ChannelCalling: %s\r\n" 02113 "CallerID: %s\r\n" 02114 "CallerIDName: %s\r\n" 02115 "Context: %s\r\n" 02116 "Extension: %s\r\n" 02117 "Priority: %d\r\n" 02118 "%s", 02119 tmp->interface, tmp->member->membername, qe->chan->name, 02120 tmp->chan->cid.cid_num ? tmp->chan->cid.cid_num : "unknown", 02121 tmp->chan->cid.cid_name ? tmp->chan->cid.cid_name : "unknown", 02122 qe->chan->context, qe->chan->exten, qe->chan->priority, 02123 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : ""); 02124 if (option_verbose > 2) 02125 ast_verbose(VERBOSE_PREFIX_3 "Called %s\n", tmp->interface); 02126 } 02127 02128 update_status(tmp->member->state_interface, ast_device_state(tmp->member->state_interface)); 02129 return 1; 02130 }
static int ring_one | ( | struct queue_ent * | qe, | |
struct callattempt * | outgoing, | |||
int * | busies | |||
) | [static] |
Place a call to a queue member.
Once metrics have been calculated for each member, this function is used to place a call to the appropriate member (or members). The low-level channel-handling and error detection is handled in ring_entry
Returns 1 if a member was called successfully, 0 otherwise
Definition at line 2156 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().
02157 { 02158 int ret = 0; 02159 02160 while (ret == 0) { 02161 struct callattempt *best = find_best(outgoing); 02162 if (!best) { 02163 if (option_debug) 02164 ast_log(LOG_DEBUG, "Nobody left to try ringing in queue\n"); 02165 break; 02166 } 02167 if (qe->parent->strategy == QUEUE_STRATEGY_RINGALL) { 02168 struct callattempt *cur; 02169 /* Ring everyone who shares this best metric (for ringall) */ 02170 for (cur = outgoing; cur; cur = cur->q_next) { 02171 if (cur->stillgoing && !cur->chan && cur->metric <= best->metric) { 02172 if (option_debug) 02173 ast_log(LOG_DEBUG, "(Parallel) Trying '%s' with metric %d\n", cur->interface, cur->metric); 02174 ret |= ring_entry(qe, cur, busies); 02175 } 02176 } 02177 } else { 02178 /* Ring just the best channel */ 02179 if (option_debug) 02180 ast_log(LOG_DEBUG, "Trying '%s' with metric %d\n", best->interface, best->metric); 02181 ret = ring_entry(qe, best, busies); 02182 } 02183 } 02184 02185 return ret; 02186 }
static void rna | ( | int | rnatime, | |
struct queue_ent * | qe, | |||
char * | interface, | |||
char * | membername, | |||
int | pause | |||
) | [static] |
RNA == Ring No Answer. Common code that is executed when we try a queue member and they don't answer.
Definition at line 2294 of file app_queue.c.
References ast_indicate(), ast_moh_start(), ast_queue_log(), ast_verbose(), call_queue::autopause, queue_ent::chan, queue_ent::moh, call_queue::name, option_verbose, queue_ent::parent, queue_ent::ring_when_ringing, set_member_paused(), and VERBOSE_PREFIX_3.
Referenced by wait_for_answer().
02295 { 02296 if (option_verbose > 2) 02297 ast_verbose( VERBOSE_PREFIX_3 "Nobody picked up in %d ms\n", rnatime); 02298 02299 /* Stop ringing, and resume MOH if specified */ 02300 if (qe->ring_when_ringing) { 02301 ast_indicate(qe->chan, -1); 02302 ast_moh_start(qe->chan, qe->moh, NULL); 02303 } 02304 02305 ast_queue_log(qe->parent->name, qe->chan->uniqueid, membername, "RINGNOANSWER", "%d", rnatime); 02306 if (qe->parent->autopause && pause) { 02307 if (!set_member_paused(qe->parent->name, interface, 1)) { 02308 if (option_verbose > 2) 02309 ast_verbose( VERBOSE_PREFIX_3 "Auto-Pausing Queue Member %s in queue %s since they failed to answer.\n", interface, qe->parent->name); 02310 } else { 02311 if (option_verbose > 2) 02312 ast_verbose( VERBOSE_PREFIX_3 "Failed to pause Queue Member %s in queue %s!\n", interface, qe->parent->name); 02313 } 02314 } 02315 return; 02316 }
static int rqm_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Definition at line 4044 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().
04045 { 04046 int res=-1; 04047 struct ast_module_user *lu; 04048 char *parse, *temppos = NULL; 04049 int priority_jump = 0; 04050 AST_DECLARE_APP_ARGS(args, 04051 AST_APP_ARG(queuename); 04052 AST_APP_ARG(interface); 04053 AST_APP_ARG(options); 04054 ); 04055 04056 04057 if (ast_strlen_zero(data)) { 04058 ast_log(LOG_WARNING, "RemoveQueueMember requires an argument (queuename[|interface[|options]])\n"); 04059 return -1; 04060 } 04061 04062 parse = ast_strdupa(data); 04063 04064 AST_STANDARD_APP_ARGS(args, parse); 04065 04066 lu = ast_module_user_add(chan); 04067 04068 if (ast_strlen_zero(args.interface)) { 04069 args.interface = ast_strdupa(chan->name); 04070 temppos = strrchr(args.interface, '-'); 04071 if (temppos) 04072 *temppos = '\0'; 04073 } 04074 04075 if (args.options) { 04076 if (strchr(args.options, 'j')) 04077 priority_jump = 1; 04078 } 04079 04080 switch (remove_from_queue(args.queuename, args.interface)) { 04081 case RES_OKAY: 04082 ast_queue_log(args.queuename, chan->uniqueid, args.interface, "REMOVEMEMBER", "%s", ""); 04083 ast_log(LOG_NOTICE, "Removed interface '%s' from queue '%s'\n", args.interface, args.queuename); 04084 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "REMOVED"); 04085 res = 0; 04086 break; 04087 case RES_EXISTS: 04088 ast_log(LOG_DEBUG, "Unable to remove interface '%s' from queue '%s': Not there\n", args.interface, args.queuename); 04089 if (priority_jump || ast_opt_priority_jumping) 04090 ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101); 04091 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOTINQUEUE"); 04092 res = 0; 04093 break; 04094 case RES_NOSUCHQUEUE: 04095 ast_log(LOG_WARNING, "Unable to remove interface from queue '%s': No such queue\n", args.queuename); 04096 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOSUCHQUEUE"); 04097 res = 0; 04098 break; 04099 case RES_NOT_DYNAMIC: 04100 ast_log(LOG_WARNING, "Unable to remove interface from queue '%s': '%s' is not a dynamic member\n", args.queuename, args.interface); 04101 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOTDYNAMIC"); 04102 res = 0; 04103 break; 04104 } 04105 04106 ast_module_user_remove(lu); 04107 04108 return res; 04109 }
static void rr_dep_warning | ( | void | ) | [static] |
Definition at line 483 of file app_queue.c.
References ast_log(), and LOG_NOTICE.
Referenced by find_queue_by_name_rt(), and reload_queues().
00484 { 00485 static unsigned int warned = 0; 00486 00487 if (!warned) { 00488 ast_log(LOG_NOTICE, "The 'roundrobin' queue strategy is deprecated. Please use the 'rrmemory' strategy instead.\n"); 00489 warned = 1; 00490 } 00491 }
static void rt_handle_member_record | ( | struct call_queue * | q, | |
char * | interface, | |||
const char * | membername, | |||
const char * | penalty_str, | |||
const char * | paused_str, | |||
const char * | state_interface | |||
) | [static] |
Definition at line 1195 of file app_queue.c.
References add_to_interfaces(), ao2_find(), ao2_ref(), ast_copy_string(), create_queue_member(), member::dead, member::interface, call_queue::membercount, call_queue::members, member::paused, member::penalty, member::realtime, remove_from_interfaces(), and member::state_interface.
Referenced by find_queue_by_name_rt(), and update_realtime_members().
01196 { 01197 struct member *m, tmpmem; 01198 int penalty = 0; 01199 int paused = 0; 01200 01201 if (penalty_str) { 01202 penalty = atoi(penalty_str); 01203 if (penalty < 0) 01204 penalty = 0; 01205 } 01206 01207 if (paused_str) { 01208 paused = atoi(paused_str); 01209 if (paused < 0) 01210 paused = 0; 01211 } 01212 01213 /* Find the member, or the place to put a new one. */ 01214 ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface)); 01215 m = ao2_find(q->members, &tmpmem, OBJ_POINTER); 01216 01217 /* Create a new one if not found, else update penalty */ 01218 if (!m) { 01219 if ((m = create_queue_member(interface, membername, penalty, paused, state_interface))) { 01220 m->dead = 0; 01221 m->realtime = 1; 01222 add_to_interfaces(m->state_interface); 01223 ao2_link(q->members, m); 01224 ao2_ref(m, -1); 01225 m = NULL; 01226 q->membercount++; 01227 } 01228 } else { 01229 m->dead = 0; /* Do not delete this one. */ 01230 if (paused_str) 01231 m->paused = paused; 01232 if (strcasecmp(state_interface, m->state_interface)) { 01233 remove_from_interfaces(m->state_interface); 01234 ast_copy_string(m->state_interface, state_interface, sizeof(m->state_interface)); 01235 add_to_interfaces(m->state_interface); 01236 } 01237 m->penalty = penalty; 01238 ao2_ref(m, -1); 01239 } 01240 }
static int say_periodic_announcement | ( | struct queue_ent * | qe | ) | [static] |
Definition at line 2236 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().
02237 { 02238 int res = 0; 02239 time_t now; 02240 02241 /* Get the current time */ 02242 time(&now); 02243 02244 /* Check to see if it is time to announce */ 02245 if ((now - qe->last_periodic_announce_time) < qe->parent->periodicannouncefrequency) 02246 return 0; 02247 02248 /* Stop the music on hold so we can play our own file */ 02249 ast_moh_stop(qe->chan); 02250 02251 if (option_verbose > 2) 02252 ast_verbose(VERBOSE_PREFIX_3 "Playing periodic announcement\n"); 02253 02254 /* Check to make sure we have a sound file. If not, reset to the first sound file */ 02255 if (qe->last_periodic_announce_sound >= MAX_PERIODIC_ANNOUNCEMENTS || !strlen(qe->parent->sound_periodicannounce[qe->last_periodic_announce_sound])) { 02256 qe->last_periodic_announce_sound = 0; 02257 } 02258 02259 /* play the announcement */ 02260 res = play_file(qe->chan, qe->parent->sound_periodicannounce[qe->last_periodic_announce_sound]); 02261 02262 if (res > 0 && !valid_exit(qe, res)) 02263 res = 0; 02264 02265 /* Resume Music on Hold if the caller is going to stay in the queue */ 02266 if (!res) 02267 ast_moh_start(qe->chan, qe->moh, NULL); 02268 02269 /* update last_periodic_announce_time */ 02270 qe->last_periodic_announce_time = now; 02271 02272 /* Update the current periodic announcement to the next announcement */ 02273 qe->last_periodic_announce_sound++; 02274 02275 return res; 02276 }
static int say_position | ( | struct queue_ent * | qe | ) | [static] |
Definition at line 1650 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_minute, 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().
01651 { 01652 int res = 0, avgholdmins, avgholdsecs; 01653 time_t now; 01654 01655 /* Check to see if this is ludicrous -- if we just announced position, don't do it again*/ 01656 time(&now); 01657 if ((now - qe->last_pos) < 15) 01658 return 0; 01659 01660 /* If either our position has changed, or we are over the freq timer, say position */ 01661 if ((qe->last_pos_said == qe->pos) && ((now - qe->last_pos) < qe->parent->announcefrequency)) 01662 return 0; 01663 01664 ast_moh_stop(qe->chan); 01665 /* Say we're next, if we are */ 01666 if (qe->pos == 1) { 01667 res = play_file(qe->chan, qe->parent->sound_next); 01668 if (res) 01669 goto playout; 01670 else 01671 goto posout; 01672 } else { 01673 res = play_file(qe->chan, qe->parent->sound_thereare); 01674 if (res) 01675 goto playout; 01676 res = ast_say_number(qe->chan, qe->pos, AST_DIGIT_ANY, qe->chan->language, (char *) NULL); /* Needs gender */ 01677 if (res) 01678 goto playout; 01679 res = play_file(qe->chan, qe->parent->sound_calls); 01680 if (res) 01681 goto playout; 01682 } 01683 /* Round hold time to nearest minute */ 01684 avgholdmins = abs(((qe->parent->holdtime + 30) - (now - qe->start)) / 60); 01685 01686 /* If they have specified a rounding then round the seconds as well */ 01687 if (qe->parent->roundingseconds) { 01688 avgholdsecs = (abs(((qe->parent->holdtime + 30) - (now - qe->start))) - 60 * avgholdmins) / qe->parent->roundingseconds; 01689 avgholdsecs *= qe->parent->roundingseconds; 01690 } else { 01691 avgholdsecs = 0; 01692 } 01693 01694 if (option_verbose > 2) 01695 ast_verbose(VERBOSE_PREFIX_3 "Hold time for %s is %d minute(s) %d seconds\n", qe->parent->name, avgholdmins, avgholdsecs); 01696 01697 /* If the hold time is >1 min, if it's enabled, and if it's not 01698 supposed to be only once and we have already said it, say it */ 01699 if ((avgholdmins+avgholdsecs) > 0 && qe->parent->announceholdtime && 01700 ((qe->parent->announceholdtime == ANNOUNCEHOLDTIME_ONCE && !qe->last_pos) || 01701 !(qe->parent->announceholdtime == ANNOUNCEHOLDTIME_ONCE))) { 01702 res = play_file(qe->chan, qe->parent->sound_holdtime); 01703 if (res) 01704 goto playout; 01705 01706 if (avgholdmins >= 1) { 01707 res = ast_say_number(qe->chan, avgholdmins, AST_DIGIT_ANY, qe->chan->language, NULL); 01708 if (res) 01709 goto playout; 01710 01711 if (avgholdmins == 1) { 01712 res = play_file(qe->chan, qe->parent->sound_minute); 01713 if (res) 01714 goto playout; 01715 } else { 01716 res = play_file(qe->chan, qe->parent->sound_minutes); 01717 if (res) 01718 goto playout; 01719 } 01720 01721 } 01722 if (avgholdsecs >= 1) { 01723 res = ast_say_number(qe->chan, avgholdsecs, AST_DIGIT_ANY, qe->chan->language, NULL); 01724 if (res) 01725 goto playout; 01726 01727 res = play_file(qe->chan, qe->parent->sound_seconds); 01728 if (res) 01729 goto playout; 01730 } 01731 01732 } 01733 01734 posout: 01735 if (option_verbose > 2) 01736 ast_verbose(VERBOSE_PREFIX_3 "Told %s in %s their queue position (which was %d)\n", 01737 qe->chan->name, qe->parent->name, qe->pos); 01738 res = play_file(qe->chan, qe->parent->sound_thanks); 01739 01740 playout: 01741 01742 if ((res > 0 && !valid_exit(qe, res))) 01743 res = 0; 01744 01745 /* Set our last_pos indicators */ 01746 qe->last_pos = now; 01747 qe->last_pos_said = qe->pos; 01748 01749 /* Don't restart music on hold if we're about to exit the caller from the queue */ 01750 if (!res) 01751 ast_moh_start(qe->chan, qe->moh, NULL); 01752 01753 return res; 01754 }
static int set_member_paused | ( | const char * | queuename, | |
const char * | interface, | |||
int | paused | |||
) | [static] |
Definition at line 3785 of file app_queue.c.
References ao2_lock(), ao2_ref(), ao2_unlock(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_queue_log(), ast_strlen_zero(), dump_queue_members(), EVENT_FLAG_AGENT, member::interface, interface_exists(), 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().
03786 { 03787 int found = 0; 03788 struct call_queue *q; 03789 struct member *mem; 03790 03791 /* Special event for when all queues are paused - individual events still generated */ 03792 /* XXX In all other cases, we use the membername, but since this affects all queues, we cannot */ 03793 if (ast_strlen_zero(queuename)) 03794 ast_queue_log("NONE", "NONE", interface, (paused ? "PAUSEALL" : "UNPAUSEALL"), "%s", ""); 03795 03796 AST_LIST_LOCK(&queues); 03797 AST_LIST_TRAVERSE(&queues, q, list) { 03798 ao2_lock(q); 03799 if (ast_strlen_zero(queuename) || !strcasecmp(q->name, queuename)) { 03800 if ((mem = interface_exists(q, interface))) { 03801 found++; 03802 if (mem->paused == paused) 03803 ast_log(LOG_DEBUG, "%spausing already-%spaused queue member %s:%s\n", (paused ? "" : "un"), (paused ? "" : "un"), q->name, interface); 03804 mem->paused = paused; 03805 03806 if (queue_persistent_members) 03807 dump_queue_members(q); 03808 03809 if (mem->realtime) 03810 update_realtime_member_field(mem, q->name, "paused", paused ? "1" : "0"); 03811 03812 ast_queue_log(q->name, "NONE", mem->membername, (paused ? "PAUSE" : "UNPAUSE"), "%s", ""); 03813 03814 manager_event(EVENT_FLAG_AGENT, "QueueMemberPaused", 03815 "Queue: %s\r\n" 03816 "Location: %s\r\n" 03817 "MemberName: %s\r\n" 03818 "Paused: %d\r\n", 03819 q->name, mem->interface, mem->membername, paused); 03820 ao2_ref(mem, -1); 03821 } 03822 } 03823 ao2_unlock(q); 03824 } 03825 AST_LIST_UNLOCK(&queues); 03826 03827 return found ? RESULT_SUCCESS : RESULT_FAILURE; 03828 }
static void set_queue_result | ( | struct ast_channel * | chan, | |
enum queue_result | res | |||
) | [static] |
sets the QUEUESTATUS channel variable
Definition at line 502 of file app_queue.c.
References pbx_builtin_setvar_helper(), queue_results, and text.
Referenced by queue_exec().
00503 { 00504 int i; 00505 00506 for (i = 0; i < sizeof(queue_results) / sizeof(queue_results[0]); i++) { 00507 if (queue_results[i].id == res) { 00508 pbx_builtin_setvar_helper(chan, "QUEUESTATUS", queue_results[i].text); 00509 return; 00510 } 00511 } 00512 }
static struct ast_datastore* setup_transfer_datastore | ( | struct queue_ent * | qe, | |
struct member * | member, | |||
time_t | starttime, | |||
int | callcompletedinsl | |||
) | [static, read] |
create a datastore for storing relevant info to log attended transfers in the queue_log
Definition at line 2927 of file app_queue.c.
References ast_calloc, ast_channel_datastore_add(), ast_channel_datastore_alloc(), ast_channel_lock, ast_channel_unlock, ast_log(), queue_transfer_ds::callcompletedinsl, queue_ent::chan, ast_datastore::data, LOG_WARNING, queue_transfer_ds::member, queue_transfer_ds::qe, queue_transfer_info, and queue_transfer_ds::starttime.
Referenced by try_calling().
02928 { 02929 struct ast_datastore *ds; 02930 struct queue_transfer_ds *qtds = ast_calloc(1, sizeof(*qtds)); 02931 02932 if (!qtds) { 02933 ast_log(LOG_WARNING, "Memory allocation error!\n"); 02934 return NULL; 02935 } 02936 02937 ast_channel_lock(qe->chan); 02938 if (!(ds = ast_channel_datastore_alloc(&queue_transfer_info, NULL))) { 02939 ast_channel_unlock(qe->chan); 02940 ast_log(LOG_WARNING, "Unable to create transfer datastore. queue_log will not show attended transfer\n"); 02941 return NULL; 02942 } 02943 02944 qtds->qe = qe; 02945 /* This member is refcounted in try_calling, so no need to add it here, too */ 02946 qtds->member = member; 02947 qtds->starttime = starttime; 02948 qtds->callcompletedinsl = callcompletedinsl; 02949 ds->data = qtds; 02950 ast_channel_datastore_add(qe->chan, ds); 02951 ast_channel_unlock(qe->chan); 02952 return ds; 02953 }
static int statechange_queue | ( | const char * | dev, | |
int | state, | |||
void * | ign | |||
) | [static] |
Producer of the statechange queue.
Definition at line 799 of file app_queue.c.
References ast_calloc, ast_cond_signal(), AST_LIST_INSERT_TAIL, ast_mutex_lock(), ast_mutex_unlock(), statechange::dev, device_state, statechange::entry, and statechange::state.
Referenced by load_module(), and unload_module().
00800 { 00801 struct statechange *sc; 00802 00803 if (!(sc = ast_calloc(1, sizeof(*sc) + strlen(dev) + 1))) 00804 return 0; 00805 00806 sc->state = state; 00807 strcpy(sc->dev, dev); 00808 00809 ast_mutex_lock(&device_state.lock); 00810 AST_LIST_INSERT_TAIL(&device_state.state_change_q, sc, entry); 00811 ast_cond_signal(&device_state.cond); 00812 ast_mutex_unlock(&device_state.lock); 00813 00814 return 0; 00815 }
static int store_next_lin | ( | struct queue_ent * | qe, | |
struct callattempt * | outgoing | |||
) | [static] |
Definition at line 2212 of file app_queue.c.
References ast_log(), find_best(), callattempt::interface, queue_ent::linpos, queue_ent::linwrapped, LOG_DEBUG, callattempt::metric, and option_debug.
Referenced by try_calling().
02213 { 02214 struct callattempt *best = find_best(outgoing); 02215 02216 if (best) { 02217 /* Ring just the best channel */ 02218 if (option_debug) 02219 ast_log(LOG_DEBUG, "Next is '%s' with metric %d\n", best->interface, best->metric); 02220 qe->linpos = best->metric % 1000; 02221 } else { 02222 /* Just increment rrpos */ 02223 if (qe->linwrapped) { 02224 /* No more channels, start over */ 02225 qe->linpos = 0; 02226 } else { 02227 /* Prioritize next entry */ 02228 qe->linpos++; 02229 } 02230 } 02231 qe->linwrapped = 0; 02232 02233 return 0; 02234 }
static int store_next_rr | ( | struct queue_ent * | qe, | |
struct callattempt * | outgoing | |||
) | [static] |
Definition at line 2188 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().
02189 { 02190 struct callattempt *best = find_best(outgoing); 02191 02192 if (best) { 02193 /* Ring just the best channel */ 02194 if (option_debug) 02195 ast_log(LOG_DEBUG, "Next is '%s' with metric %d\n", best->interface, best->metric); 02196 qe->parent->rrpos = best->metric % 1000; 02197 } else { 02198 /* Just increment rrpos */ 02199 if (qe->parent->wrapped) { 02200 /* No more channels, start over */ 02201 qe->parent->rrpos = 0; 02202 } else { 02203 /* Prioritize next entry */ 02204 qe->parent->rrpos++; 02205 } 02206 } 02207 qe->parent->wrapped = 0; 02208 02209 return 0; 02210 }
static int strat2int | ( | const char * | strategy | ) | [static] |
Definition at line 526 of file app_queue.c.
References name, and strategies.
Referenced by find_queue_by_name_rt(), queue_set_param(), and reload_queues().
00527 { 00528 int x; 00529 00530 for (x = 0; x < sizeof(strategies) / sizeof(strategies[0]); x++) { 00531 if (!strcasecmp(strategy, strategies[x].name)) 00532 return strategies[x].strategy; 00533 } 00534 00535 return -1; 00536 }
static int try_calling | ( | struct queue_ent * | qe, | |
const char * | options, | |||
char * | announceoverride, | |||
const char * | url, | |||
int * | tries, | |||
int * | noption, | |||
const char * | agi | |||
) | [static] |
A large function which calls members, updates statistics, and bridges the caller and a member.
Here is the process of this function 1. Process any options passed to the Queue() application. Options here mean the third argument to Queue() 2. Iterate trough the members of the queue, creating a callattempt corresponding to each member. During this iteration, we also check the dialed_interfaces datastore to see if we have already attempted calling this member. If we have, we do not create a callattempt. This is in place to prevent call forwarding loops. Also during each iteration, we call calc_metric to determine which members should be rung when. 3. Call ring_one to place a call to the appropriate member(s) 4. Call wait_for_answer to wait for an answer. If no one answers, return. 5. Take care of any holdtime announcements, member delays, or other options which occur after a call has been answered. 6. Start the monitor or mixmonitor if the option is set 7. Remove the caller from the queue to allow other callers to advance 8. Bridge the call. 9. Do any post processing after the call has disconnected.
[in] | qe | the queue_ent structure which corresponds to the caller attempting to reach members |
[in] | options | the options passed as the third parameter to the Queue() application |
[in] | url | the url passed as the fourth parameter to the Queue() application |
[in,out] | tries | the number of times we have tried calling queue members |
[out] | noption | set if the call to Queue() has the 'n' option set. |
[in] | agi | the agi passed as the fifth parameter to the Queue() application |
Definition at line 2980 of file app_queue.c.
References ast_channel::_softhangup, ast_channel::_state, queue_ent::announce, ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next(), ao2_lock(), ao2_ref(), ao2_unlock(), ast_autoservice_start(), ast_autoservice_stop(), ast_bridge_call(), ast_calloc, ast_cdr_failed(), AST_CDR_FLAG_DONT_TOUCH, AST_CDR_FLAG_LOCKED, AST_CDR_FLAG_POST_DISABLED, ast_cdr_isset_unanswered(), ast_cdr_noanswer(), 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_copy_string(), 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_OPTION_TONE_VERIFY, 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, attended_transfer_occurred(), calc_metric(), ast_channel::cdr, callattempt::chan, queue_ent::chan, ast_channel::context, ast_datastore::data, DATASTORE_INHERIT_FOREVER, di, dialed_interface_info, ast_cdr::dstchannel, 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, member::lastqueue, callattempt::lastqueue, leave_queue(), LOG_DEBUG, LOG_ERROR, 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_LINEAR, QUEUE_STRATEGY_ROUNDROBIN, QUEUE_STRATEGY_RRMEMORY, QUEUE_STRATEGY_RRORDERED, queue_transfer_info, recalc_holdtime(), record_abandoned(), call_queue::reportholdtime, ring_one(), member::ringcount, call_queue::ringlimit, call_queue::servicelevel, call_queue::setinterfacevar, setup_transfer_datastore(), call_queue::sound_minute, call_queue::sound_minutes, call_queue::sound_reporthold, call_queue::sound_seconds, queue_ent::start, member::status, callattempt::stillgoing, store_next_lin(), store_next_rr(), call_queue::strategy, tds, ast_channel::tech, call_queue::timeout, queue_ent::tries, ast_channel_tech::type, ast_cdr::uniqueid, update_queue(), vars2manager(), and wait_for_answer().
Referenced by queue_exec().
02981 { 02982 struct member *cur; 02983 struct callattempt *outgoing = NULL; /* the list of calls we are building */ 02984 int to; 02985 char oldexten[AST_MAX_EXTENSION]=""; 02986 char oldcontext[AST_MAX_CONTEXT]=""; 02987 char queuename[256]=""; 02988 struct ast_channel *peer; 02989 struct ast_channel *which; 02990 struct callattempt *lpeer; 02991 struct member *member; 02992 struct ast_app *app; 02993 int res = 0, bridge = 0; 02994 int numbusies = 0; 02995 int x=0; 02996 char *announce = NULL; 02997 char digit = 0; 02998 time_t callstart; 02999 time_t now = time(NULL); 03000 struct ast_bridge_config bridge_config; 03001 char nondataquality = 1; 03002 char *agiexec = NULL; 03003 int ret = 0; 03004 const char *monitorfilename; 03005 const char *monitor_exec; 03006 const char *monitor_options; 03007 char tmpid[256], tmpid2[256]; 03008 char meid[1024], meid2[1024]; 03009 char mixmonargs[1512]; 03010 struct ast_app *mixmonapp = NULL; 03011 char *p; 03012 char vars[2048]; 03013 int forwardsallowed = 1; 03014 int callcompletedinsl; 03015 struct ao2_iterator memi; 03016 struct ast_datastore *datastore, *transfer_ds; 03017 const int need_weight = use_weight; 03018 03019 ast_channel_lock(qe->chan); 03020 datastore = ast_channel_datastore_find(qe->chan, &dialed_interface_info, NULL); 03021 ast_channel_unlock(qe->chan); 03022 03023 memset(&bridge_config, 0, sizeof(bridge_config)); 03024 time(&now); 03025 03026 /* If we've already exceeded our timeout, then just stop 03027 * This should be extremely rare. queue_exec will take care 03028 * of removing the caller and reporting the timeout as the reason. 03029 */ 03030 if (qe->expire && now >= qe->expire) { 03031 res = 0; 03032 goto out; 03033 } 03034 03035 for (; options && *options; options++) 03036 switch (*options) { 03037 case 't': 03038 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_REDIRECT); 03039 break; 03040 case 'T': 03041 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_REDIRECT); 03042 break; 03043 case 'w': 03044 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_AUTOMON); 03045 break; 03046 case 'W': 03047 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_AUTOMON); 03048 break; 03049 case 'd': 03050 nondataquality = 0; 03051 break; 03052 case 'h': 03053 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_DISCONNECT); 03054 break; 03055 case 'H': 03056 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT); 03057 break; 03058 case 'n': 03059 if (qe->parent->strategy == QUEUE_STRATEGY_ROUNDROBIN || qe->parent->strategy == QUEUE_STRATEGY_RRMEMORY || qe->parent->strategy == QUEUE_STRATEGY_RRORDERED || qe->parent->strategy == QUEUE_STRATEGY_LINEAR) 03060 (*tries)++; 03061 else 03062 *tries = qe->parent->membercount; 03063 *noption = 1; 03064 break; 03065 case 'i': 03066 forwardsallowed = 0; 03067 break; 03068 } 03069 03070 /* Hold the lock while we setup the outgoing calls */ 03071 03072 if (need_weight) 03073 AST_LIST_LOCK(&queues); 03074 ao2_lock(qe->parent); 03075 if (option_debug) 03076 ast_log(LOG_DEBUG, "%s is trying to call a queue member.\n", 03077 qe->chan->name); 03078 ast_copy_string(queuename, qe->parent->name, sizeof(queuename)); 03079 if (!ast_strlen_zero(qe->announce)) 03080 announce = qe->announce; 03081 if (!ast_strlen_zero(announceoverride)) 03082 announce = announceoverride; 03083 03084 memi = ao2_iterator_init(qe->parent->members, 0); 03085 while ((cur = ao2_iterator_next(&memi))) { 03086 struct callattempt *tmp = ast_calloc(1, sizeof(*tmp)); 03087 struct ast_dialed_interface *di; 03088 AST_LIST_HEAD(, ast_dialed_interface) *dialed_interfaces; 03089 if (!tmp) { 03090 ao2_iterator_destroy(&memi); 03091 ao2_ref(cur, -1); 03092 ao2_unlock(qe->parent); 03093 if (need_weight) 03094 AST_LIST_UNLOCK(&queues); 03095 goto out; 03096 } 03097 if (!datastore) { 03098 if (!(datastore = ast_channel_datastore_alloc(&dialed_interface_info, NULL))) { 03099 ao2_iterator_destroy(&memi); 03100 ao2_ref(cur, -1); 03101 ao2_unlock(qe->parent); 03102 if (need_weight) 03103 AST_LIST_UNLOCK(&queues); 03104 free(tmp); 03105 goto out; 03106 } 03107 datastore->inheritance = DATASTORE_INHERIT_FOREVER; 03108 if (!(dialed_interfaces = ast_calloc(1, sizeof(*dialed_interfaces)))) { 03109 ao2_iterator_destroy(&memi); 03110 ao2_ref(cur, -1); 03111 ao2_unlock(qe->parent); 03112 if (need_weight) 03113 AST_LIST_UNLOCK(&queues); 03114 free(tmp); 03115 goto out; 03116 } 03117 datastore->data = dialed_interfaces; 03118 AST_LIST_HEAD_INIT(dialed_interfaces); 03119 03120 ast_channel_lock(qe->chan); 03121 ast_channel_datastore_add(qe->chan, datastore); 03122 ast_channel_unlock(qe->chan); 03123 } else 03124 dialed_interfaces = datastore->data; 03125 03126 AST_LIST_LOCK(dialed_interfaces); 03127 AST_LIST_TRAVERSE(dialed_interfaces, di, list) { 03128 if (!strcasecmp(cur->interface, di->interface)) { 03129 ast_log(LOG_DEBUG, "Skipping dialing interface '%s' since it has already been dialed\n", 03130 di->interface); 03131 break; 03132 } 03133 } 03134 AST_LIST_UNLOCK(dialed_interfaces); 03135 03136 if (di) { 03137 free(tmp); 03138 continue; 03139 } 03140 03141 /* It is always ok to dial a Local interface. We only keep track of 03142 * which "real" interfaces have been dialed. The Local channel will 03143 * inherit this list so that if it ends up dialing a real interface, 03144 * it won't call one that has already been called. */ 03145 if (strncasecmp(cur->interface, "Local/", 6)) { 03146 if (!(di = ast_calloc(1, sizeof(*di) + strlen(cur->interface)))) { 03147 ao2_iterator_destroy(&memi); 03148 ao2_ref(cur, -1); 03149 ao2_unlock(qe->parent); 03150 if (need_weight) 03151 AST_LIST_UNLOCK(&queues); 03152 free(tmp); 03153 goto out; 03154 } 03155 strcpy(di->interface, cur->interface); 03156 03157 AST_LIST_LOCK(dialed_interfaces); 03158 AST_LIST_INSERT_TAIL(dialed_interfaces, di, list); 03159 AST_LIST_UNLOCK(dialed_interfaces); 03160 } 03161 03162 tmp->stillgoing = -1; 03163 tmp->member = cur; 03164 tmp->oldstatus = cur->status; 03165 tmp->lastcall = cur->lastcall; 03166 tmp->lastqueue = cur->lastqueue; 03167 ast_copy_string(tmp->interface, cur->interface, sizeof(tmp->interface)); 03168 if (qe->tries == 0 && (cur->ringcount >= qe->parent->ringlimit)) { 03169 cur->ringcount = 0; 03170 } 03171 /* Special case: If we ring everyone, go ahead and ring them, otherwise 03172 just calculate their metric for the appropriate strategy */ 03173 if (!calc_metric(qe->parent, cur, x++, qe, tmp)) { 03174 /* Put them in the list of outgoing thingies... We're ready now. 03175 XXX If we're forcibly removed, these outgoing calls won't get 03176 hung up XXX */ 03177 tmp->q_next = outgoing; 03178 outgoing = tmp; 03179 /* If this line is up, don't try anybody else */ 03180 if (outgoing->chan && (outgoing->chan->_state == AST_STATE_UP)) 03181 break; 03182 } else { 03183 ao2_ref(cur, -1); 03184 free(tmp); 03185 } 03186 } 03187 ao2_iterator_destroy(&memi); 03188 if (qe->expire && (!qe->parent->timeout || (qe->expire - now) <= qe->parent->timeout)) 03189 to = (qe->expire - now) * 1000; 03190 else 03191 to = (qe->parent->timeout) ? qe->parent->timeout * 1000 : -1; 03192 ++qe->pending; 03193 ++qe->tries; 03194 if (option_debug) 03195 ast_log(LOG_DEBUG, "%s is trying to ring one member from %s. This is try number %d\n", 03196 qe->chan->name, queuename, qe->tries); 03197 ao2_unlock(qe->parent); 03198 ring_one(qe, outgoing, &numbusies); 03199 if (need_weight) 03200 AST_LIST_UNLOCK(&queues); 03201 lpeer = wait_for_answer(qe, outgoing, &to, &digit, numbusies, ast_test_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT), forwardsallowed); 03202 /* The ast_channel_datastore_remove() function could fail here if the 03203 * datastore was moved to another channel during a masquerade. If this is 03204 * the case, don't free the datastore here because later, when the channel 03205 * to which the datastore was moved hangs up, it will attempt to free this 03206 * datastore again, causing a crash 03207 */ 03208 ast_channel_lock(qe->chan); 03209 if (datastore && !ast_channel_datastore_remove(qe->chan, datastore)) { 03210 ast_channel_datastore_free(datastore); 03211 } 03212 ast_channel_unlock(qe->chan); 03213 ao2_lock(qe->parent); 03214 if (qe->parent->strategy == QUEUE_STRATEGY_RRMEMORY || qe->parent->strategy == QUEUE_STRATEGY_RRORDERED) { 03215 store_next_rr(qe, outgoing); 03216 } 03217 if (qe->parent->strategy == QUEUE_STRATEGY_LINEAR) { 03218 store_next_lin(qe, outgoing); 03219 } 03220 ao2_unlock(qe->parent); 03221 peer = lpeer ? lpeer->chan : NULL; 03222 if (!peer) { 03223 qe->pending = 0; 03224 if (to) { 03225 /* Must gotten hung up */ 03226 res = -1; 03227 } else { 03228 /* User exited by pressing a digit */ 03229 res = digit; 03230 } 03231 if (res == -1) { 03232 /* Post this CDR, and mark call as NOANSWER */ 03233 ast_set_flag(qe->chan->cdr, AST_CDR_FLAG_DONT_TOUCH); 03234 ast_cdr_noanswer(qe->chan->cdr); 03235 if (queue_debug) 03236 ast_log(LOG_NOTICE, "%s: Nobody answered.\n", qe->chan->name); 03237 } 03238 if (qe->parent->eventwhencalled) { 03239 manager_event(EVENT_FLAG_AGENT, "AgentTimeout", 03240 "Queue: %s\r\n" 03241 "ChannelCalling: %s\r\n" 03242 "Uniqueid: %s\r\n" 03243 "Tries: %d\r\n" 03244 "Holdtime: %ld\r\n", 03245 queuename, qe->chan->name, qe->chan->uniqueid, qe->tries, 03246 (long)time(NULL) - qe->start); 03247 } 03248 if (ast_cdr_isset_unanswered()) { 03249 /* channel contains the name of one of the outgoing channels 03250 in its CDR; zero out this CDR to avoid a dual-posting */ 03251 struct callattempt *o; 03252 for (o = outgoing; o; o = o->q_next) { 03253 if (!o->chan) { 03254 continue; 03255 } 03256 if (strcmp(o->chan->cdr->dstchannel, qe->chan->cdr->dstchannel) == 0) { 03257 ast_set_flag(o->chan->cdr, AST_CDR_FLAG_POST_DISABLED); 03258 break; 03259 } 03260 } 03261 } 03262 } else { /* peer is valid */ 03263 /* Ah ha! Someone answered within the desired timeframe. Of course after this 03264 we will always return with -1 so that it is hung up properly after the 03265 conversation. */ 03266 if (!strcmp(qe->chan->tech->type, "Zap")) 03267 ast_channel_setoption(qe->chan, AST_OPTION_TONE_VERIFY, &nondataquality, sizeof(nondataquality), 0); 03268 if (!strcmp(peer->tech->type, "Zap")) 03269 ast_channel_setoption(peer, AST_OPTION_TONE_VERIFY, &nondataquality, sizeof(nondataquality), 0); 03270 /* Update parameters for the queue */ 03271 time(&now); 03272 recalc_holdtime(qe, (now - qe->start)); 03273 ao2_lock(qe->parent); 03274 callcompletedinsl = ((now - qe->start) <= qe->parent->servicelevel); 03275 ao2_unlock(qe->parent); 03276 member = lpeer->member; 03277 /* Increment the refcount for this member, since we're going to be using it for awhile in here. */ 03278 ao2_ref(member, 1); 03279 hangupcalls(outgoing, peer); 03280 outgoing = NULL; 03281 if (announce || qe->parent->reportholdtime || qe->parent->memberdelay) { 03282 int res2; 03283 03284 res2 = ast_autoservice_start(qe->chan); 03285 if (!res2) { 03286 if (qe->parent->memberdelay) { 03287 ast_log(LOG_NOTICE, "Delaying member connect for %d seconds\n", qe->parent->memberdelay); 03288 res2 |= ast_safe_sleep(peer, qe->parent->memberdelay * 1000); 03289 } 03290 if (!res2 && announce) { 03291 if (play_file(peer, announce) < 0) { 03292 ast_log(LOG_ERROR, "play_file failed for '%s' on %s\n", announce, peer->name); 03293 } 03294 } 03295 if (!res2 && qe->parent->reportholdtime) { 03296 if (!play_file(peer, qe->parent->sound_reporthold)) { 03297 int holdtime, holdtimesecs; 03298 03299 time(&now); 03300 holdtime = abs((now - qe->start) / 60); 03301 holdtimesecs = abs((now - qe->start) % 60); 03302 if (holdtime == 1) { 03303 ast_say_number(peer, holdtime, AST_DIGIT_ANY, peer->language, NULL); 03304 if (play_file(peer, qe->parent->sound_minute) < 0) { 03305 ast_log(LOG_ERROR, "play_file failed for '%s' on %s\n", qe->parent->sound_minute, peer->name); 03306 } 03307 } else { 03308 ast_say_number(peer, holdtime, AST_DIGIT_ANY, peer->language, NULL); 03309 if (play_file(peer, qe->parent->sound_minutes) < 0) { 03310 ast_log(LOG_ERROR, "play_file failed for '%s' on %s\n", qe->parent->sound_minutes, peer->name); 03311 } 03312 } 03313 if (holdtimesecs > 1) { 03314 ast_say_number(peer, holdtimesecs, AST_DIGIT_ANY, peer->language, NULL); 03315 if (play_file(peer, qe->parent->sound_seconds) < 0) { 03316 ast_log(LOG_ERROR, "play_file failed for '%s' on %s\n", qe->parent->sound_seconds, peer->name); 03317 } 03318 } 03319 } 03320 } 03321 } 03322 res2 |= ast_autoservice_stop(qe->chan); 03323 if (peer->_softhangup) { 03324 /* Agent must have hung up */ 03325 ast_log(LOG_WARNING, "Agent on %s hungup on the customer.\n", peer->name); 03326 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "AGENTDUMP", "%s", ""); 03327 if (qe->parent->eventwhencalled) 03328 manager_event(EVENT_FLAG_AGENT, "AgentDump", 03329 "Queue: %s\r\n" 03330 "Uniqueid: %s\r\n" 03331 "Channel: %s\r\n" 03332 "Member: %s\r\n" 03333 "MemberName: %s\r\n" 03334 "%s", 03335 queuename, qe->chan->uniqueid, peer->name, member->interface, member->membername, 03336 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : ""); 03337 ast_hangup(peer); 03338 ao2_ref(member, -1); 03339 goto out; 03340 } else if (res2) { 03341 /* Caller must have hung up just before being connected*/ 03342 ast_log(LOG_NOTICE, "Caller was about to talk to agent on %s but the caller hungup.\n", peer->name); 03343 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "ABANDON", "%d|%d|%ld", qe->pos, qe->opos, (long)time(NULL) - qe->start); 03344 record_abandoned(qe); 03345 ast_hangup(peer); 03346 ao2_ref(member, -1); 03347 return -1; 03348 } 03349 } 03350 /* Stop music on hold */ 03351 ast_moh_stop(qe->chan); 03352 /* If appropriate, log that we have a destination channel */ 03353 if (qe->chan->cdr) 03354 ast_cdr_setdestchan(qe->chan->cdr, peer->name); 03355 /* Make sure channels are compatible */ 03356 res = ast_channel_make_compatible(qe->chan, peer); 03357 if (res < 0) { 03358 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "SYSCOMPAT", "%s", ""); 03359 ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", qe->chan->name, peer->name); 03360 record_abandoned(qe); 03361 ast_cdr_failed(qe->chan->cdr); 03362 ast_hangup(peer); 03363 ao2_ref(member, -1); 03364 return -1; 03365 } 03366 03367 if (qe->parent->setinterfacevar) 03368 pbx_builtin_setvar_helper(qe->chan, "MEMBERINTERFACE", member->interface); 03369 03370 /* Begin Monitoring */ 03371 if (qe->parent->monfmt && *qe->parent->monfmt) { 03372 if (!qe->parent->montype) { 03373 if (option_debug) 03374 ast_log(LOG_DEBUG, "Starting Monitor as requested.\n"); 03375 monitorfilename = pbx_builtin_getvar_helper(qe->chan, "MONITOR_FILENAME"); 03376 if (pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC") || pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC_ARGS")) 03377 which = qe->chan; 03378 else 03379 which = peer; 03380 if (monitorfilename) 03381 ast_monitor_start(which, qe->parent->monfmt, monitorfilename, 1 ); 03382 else if (qe->chan->cdr) 03383 ast_monitor_start(which, qe->parent->monfmt, qe->chan->cdr->uniqueid, 1 ); 03384 else { 03385 /* Last ditch effort -- no CDR, make up something */ 03386 snprintf(tmpid, sizeof(tmpid), "chan-%lx", ast_random()); 03387 ast_monitor_start(which, qe->parent->monfmt, tmpid, 1 ); 03388 } 03389 if (qe->parent->monjoin) 03390 ast_monitor_setjoinfiles(which, 1); 03391 } else { 03392 if (option_debug) 03393 ast_log(LOG_DEBUG, "Starting MixMonitor as requested.\n"); 03394 monitorfilename = pbx_builtin_getvar_helper(qe->chan, "MONITOR_FILENAME"); 03395 if (!monitorfilename) { 03396 if (qe->chan->cdr) 03397 ast_copy_string(tmpid, qe->chan->cdr->uniqueid, sizeof(tmpid)-1); 03398 else 03399 snprintf(tmpid, sizeof(tmpid), "chan-%lx", ast_random()); 03400 } else { 03401 ast_copy_string(tmpid2, monitorfilename, sizeof(tmpid2)-1); 03402 for (p = tmpid2; *p ; p++) { 03403 if (*p == '^' && *(p+1) == '{') { 03404 *p = '$'; 03405 } 03406 } 03407 03408 memset(tmpid, 0, sizeof(tmpid)); 03409 pbx_substitute_variables_helper(qe->chan, tmpid2, tmpid, sizeof(tmpid) - 1); 03410 } 03411 03412 monitor_exec = pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC"); 03413 monitor_options = pbx_builtin_getvar_helper(qe->chan, "MONITOR_OPTIONS"); 03414 03415 if (monitor_exec) { 03416 ast_copy_string(meid2, monitor_exec, sizeof(meid2)-1); 03417 for (p = meid2; *p ; p++) { 03418 if (*p == '^' && *(p+1) == '{') { 03419 *p = '$'; 03420 } 03421 } 03422 03423 memset(meid, 0, sizeof(meid)); 03424 pbx_substitute_variables_helper(qe->chan, meid2, meid, sizeof(meid) - 1); 03425 } 03426 03427 snprintf(tmpid2, sizeof(tmpid2)-1, "%s.%s", tmpid, qe->parent->monfmt); 03428 03429 mixmonapp = pbx_findapp("MixMonitor"); 03430 03431 if (strchr(tmpid2, '|')) { 03432 ast_log(LOG_WARNING, "monitor-format (in queues.conf) and MONITOR_FILENAME cannot contain a '|'! Not recording.\n"); 03433 mixmonapp = NULL; 03434 } 03435 03436 if (!monitor_options) 03437 monitor_options = ""; 03438 03439 if (strchr(monitor_options, '|')) { 03440 ast_log(LOG_WARNING, "MONITOR_OPTIONS cannot contain a '|'! Not recording.\n"); 03441 mixmonapp = NULL; 03442 } 03443 03444 if (mixmonapp) { 03445 if (!ast_strlen_zero(monitor_exec)) 03446 snprintf(mixmonargs, sizeof(mixmonargs)-1, "%s|b%s|%s", tmpid2, monitor_options, monitor_exec); 03447 else 03448 snprintf(mixmonargs, sizeof(mixmonargs)-1, "%s|b%s", tmpid2, monitor_options); 03449 03450 if (option_debug) 03451 ast_log(LOG_DEBUG, "Arguments being passed to MixMonitor: %s\n", mixmonargs); 03452 /* We purposely lock the CDR so that pbx_exec does not update the application data */ 03453 if (qe->chan->cdr) 03454 ast_set_flag(qe->chan->cdr, AST_CDR_FLAG_LOCKED); 03455 ret = pbx_exec(qe->chan, mixmonapp, mixmonargs); 03456 if (qe->chan->cdr) 03457 ast_clear_flag(qe->chan->cdr, AST_CDR_FLAG_LOCKED); 03458 03459 } else 03460 ast_log(LOG_WARNING, "Asked to run MixMonitor on this call, but cannot find the MixMonitor app!\n"); 03461 03462 } 03463 } 03464 /* Drop out of the queue at this point, to prepare for next caller */ 03465 leave_queue(qe); 03466 if (!ast_strlen_zero(url) && ast_channel_supports_html(peer)) { 03467 if (option_debug) 03468 ast_log(LOG_DEBUG, "app_queue: sendurl=%s.\n", url); 03469 ast_channel_sendurl(peer, url); 03470 } 03471 if (!ast_strlen_zero(agi)) { 03472 if (option_debug) 03473 ast_log(LOG_DEBUG, "app_queue: agi=%s.\n", agi); 03474 app = pbx_findapp("agi"); 03475 if (app) { 03476 agiexec = ast_strdupa(agi); 03477 ret = pbx_exec(qe->chan, app, agiexec); 03478 } else 03479 ast_log(LOG_WARNING, "Asked to execute an AGI on this channel, but could not find application (agi)!\n"); 03480 } 03481 qe->handled++; 03482 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "CONNECT", "%ld|%s", (long)time(NULL) - qe->start, peer->uniqueid); 03483 if (qe->parent->eventwhencalled) 03484 manager_event(EVENT_FLAG_AGENT, "AgentConnect", 03485 "Queue: %s\r\n" 03486 "Uniqueid: %s\r\n" 03487 "Channel: %s\r\n" 03488 "Member: %s\r\n" 03489 "MemberName: %s\r\n" 03490 "Holdtime: %ld\r\n" 03491 "BridgedChannel: %s\r\n" 03492 "%s", 03493 queuename, qe->chan->uniqueid, peer->name, member->interface, member->membername, 03494 (long)time(NULL) - qe->start, peer->uniqueid, 03495 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : ""); 03496 ast_copy_string(oldcontext, qe->chan->context, sizeof(oldcontext)); 03497 ast_copy_string(oldexten, qe->chan->exten, sizeof(oldexten)); 03498 time(&callstart); 03499 03500 if (member->status == AST_DEVICE_NOT_INUSE) 03501 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); 03502 03503 transfer_ds = setup_transfer_datastore(qe, member, callstart, callcompletedinsl); 03504 bridge = ast_bridge_call(qe->chan,peer, &bridge_config); 03505 03506 ast_channel_lock(qe->chan); 03507 if (!attended_transfer_occurred(qe->chan)) { 03508 struct ast_datastore *tds; 03509 03510 /* detect a blind transfer */ 03511 if (!(qe->chan->_softhangup | peer->_softhangup) && (strcasecmp(oldcontext, qe->chan->context) || strcasecmp(oldexten, qe->chan->exten))) { 03512 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "TRANSFER", "%s|%s|%ld|%ld", 03513 qe->chan->exten, qe->chan->context, (long) (callstart - qe->start), 03514 (long) (time(NULL) - callstart)); 03515 if (qe->parent->eventwhencalled) 03516 manager_event(EVENT_FLAG_AGENT, "AgentComplete", 03517 "Queue: %s\r\n" 03518 "Uniqueid: %s\r\n" 03519 "Channel: %s\r\n" 03520 "Member: %s\r\n" 03521 "MemberName: %s\r\n" 03522 "HoldTime: %ld\r\n" 03523 "TalkTime: %ld\r\n" 03524 "Reason: transfer\r\n" 03525 "%s", 03526 queuename, qe->chan->uniqueid, peer->name, member->interface, member->membername, 03527 (long)(callstart - qe->start), (long)(time(NULL) - callstart), 03528 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : ""); 03529 } else if (qe->chan->_softhangup) { 03530 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "COMPLETECALLER", "%ld|%ld|%d", 03531 (long) (callstart - qe->start), (long) (time(NULL) - callstart), qe->opos); 03532 if (qe->parent->eventwhencalled) 03533 manager_event(EVENT_FLAG_AGENT, "AgentComplete", 03534 "Queue: %s\r\n" 03535 "Uniqueid: %s\r\n" 03536 "Channel: %s\r\n" 03537 "Member: %s\r\n" 03538 "MemberName: %s\r\n" 03539 "HoldTime: %ld\r\n" 03540 "TalkTime: %ld\r\n" 03541 "Reason: caller\r\n" 03542 "%s", 03543 queuename, qe->chan->uniqueid, peer->name, member->interface, member->membername, 03544 (long)(callstart - qe->start), (long)(time(NULL) - callstart), 03545 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : ""); 03546 } else { 03547 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "COMPLETEAGENT", "%ld|%ld|%d", 03548 (long) (callstart - qe->start), (long) (time(NULL) - callstart), qe->opos); 03549 if (qe->parent->eventwhencalled) 03550 manager_event(EVENT_FLAG_AGENT, "AgentComplete", 03551 "Queue: %s\r\n" 03552 "Uniqueid: %s\r\n" 03553 "Channel: %s\r\n" 03554 "Member: %s\r\n" 03555 "MemberName: %s\r\n" 03556 "HoldTime: %ld\r\n" 03557 "TalkTime: %ld\r\n" 03558 "Reason: agent\r\n" 03559 "%s", 03560 queuename, qe->chan->uniqueid, peer->name, member->interface, member->membername, (long)(callstart - qe->start), 03561 (long)(time(NULL) - callstart), 03562 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : ""); 03563 } 03564 if ((tds = ast_channel_datastore_find(qe->chan, &queue_transfer_info, NULL))) { 03565 ast_channel_datastore_remove(qe->chan, tds); 03566 } 03567 update_queue(qe->parent, member, callcompletedinsl); 03568 } else { 03569 if (qe->parent->eventwhencalled) 03570 manager_event(EVENT_FLAG_AGENT, "AgentComplete", 03571 "Queue: %s\r\n" 03572 "Uniqueid: %s\r\n" 03573 "Channel: %s\r\n" 03574 "Member: %s\r\n" 03575 "MemberName: %s\r\n" 03576 "HoldTime: %ld\r\n" 03577 "TalkTime: %ld\r\n" 03578 "Reason: transfer\r\n" 03579 "%s", 03580 queuename, qe->chan->uniqueid, peer->name, member->interface, member->membername, (long)(callstart - qe->start), 03581 (long)(time(NULL) - callstart), 03582 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : ""); 03583 } 03584 03585 if (transfer_ds) { 03586 ast_channel_datastore_free(transfer_ds); 03587 } 03588 ast_channel_unlock(qe->chan); 03589 ast_hangup(peer); 03590 res = bridge ? bridge : 1; 03591 ao2_ref(member, -1); 03592 } 03593 out: 03594 hangupcalls(outgoing, NULL); 03595 03596 return res; 03597 }
static int unload_module | ( | void | ) | [static] |
Definition at line 5871 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, queueexists_function, queuemembercount_function, queuememberlist_function, queuememberpaused_function, queuememberstatus_function, queuewaitingcount_function, and statechange_queue().
05872 { 05873 int res; 05874 05875 if (device_state.thread != AST_PTHREADT_NULL) { 05876 device_state.stop = 1; 05877 ast_mutex_lock(&device_state.lock); 05878 ast_cond_signal(&device_state.cond); 05879 ast_mutex_unlock(&device_state.lock); 05880 pthread_join(device_state.thread, NULL); 05881 } 05882 05883 ast_cli_unregister_multiple(cli_queue, sizeof(cli_queue) / sizeof(struct ast_cli_entry)); 05884 res = ast_manager_unregister("QueueStatus"); 05885 res |= ast_manager_unregister("Queues"); 05886 res |= ast_manager_unregister("QueueAdd"); 05887 res |= ast_manager_unregister("QueueRemove"); 05888 res |= ast_manager_unregister("QueuePause"); 05889 res |= ast_unregister_application(app_aqm); 05890 res |= ast_unregister_application(app_rqm); 05891 res |= ast_unregister_application(app_pqm); 05892 res |= ast_unregister_application(app_upqm); 05893 res |= ast_unregister_application(app_ql); 05894 res |= ast_unregister_application(app); 05895 res |= ast_custom_function_unregister(&queueexists_function); 05896 res |= ast_custom_function_unregister(&queueagentcount_function); 05897 res |= ast_custom_function_unregister(&queuemembercount_function); 05898 res |= ast_custom_function_unregister(&queuememberlist_function); 05899 res |= ast_custom_function_unregister(&queuememberstatus_function); 05900 res |= ast_custom_function_unregister(&queuememberpaused_function); 05901 res |= ast_custom_function_unregister(&queuewaitingcount_function); 05902 ast_devstate_del(statechange_queue, NULL); 05903 05904 ast_module_user_hangup_all(); 05905 05906 clear_and_free_interfaces(); 05907 05908 return res; 05909 }
static int update_queue | ( | struct call_queue * | q, | |
struct member * | member, | |||
int | callcompletedinsl | |||
) | [static] |
Definition at line 2746 of file app_queue.c.
References ao2_find(), ao2_lock(), ao2_ref(), ao2_unlock(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, member::calls, call_queue::callscompleted, call_queue::callscompletedinsl, member::lastcall, member::lastqueue, and call_queue::members.
Referenced by queue_transfer_fixup(), and try_calling().
02747 { 02748 struct member *mem; 02749 struct call_queue *qtmp; 02750 02751 if (shared_lastcall) { 02752 AST_LIST_LOCK(&queues); 02753 AST_LIST_TRAVERSE(&queues, qtmp, list) { 02754 ao2_lock(qtmp); 02755 if ((mem = ao2_find(qtmp->members, member, OBJ_POINTER))) { 02756 time(&mem->lastcall); 02757 mem->calls++; 02758 mem->lastqueue = q; 02759 ao2_ref(mem, -1); 02760 } 02761 ao2_unlock(qtmp); 02762 } 02763 AST_LIST_UNLOCK(&queues); 02764 } else { 02765 ao2_lock(q); 02766 time(&member->lastcall); 02767 member->calls++; 02768 member->lastqueue = q; 02769 ao2_unlock(q); 02770 } 02771 ao2_lock(q); 02772 q->callscompleted++; 02773 if (callcompletedinsl) 02774 q->callscompletedinsl++; 02775 ao2_unlock(q); 02776 02777 return 0; 02778 }
static int update_realtime_member_field | ( | struct member * | mem, | |
const char * | queue_name, | |||
const char * | field, | |||
const char * | value | |||
) | [static] |
Definition at line 1408 of file app_queue.c.
References ast_load_realtime(), ast_strlen_zero(), ast_update_realtime(), ast_variables_destroy(), member::interface, ast_variable::name, ast_variable::next, ast_variable::value, and var.
Referenced by set_member_paused().
01409 { 01410 struct ast_variable *var, *save; 01411 int ret = -1; 01412 01413 if (!(var = ast_load_realtime("queue_members", "interface", mem->interface, "queue_name", queue_name, NULL))) 01414 return ret; 01415 save = var; 01416 while (var) { 01417 if (!strcmp(var->name, "uniqueid")) 01418 break; 01419 var = var->next; 01420 } 01421 if (var && !ast_strlen_zero(var->value)) { 01422 if ((ast_update_realtime("queue_members", "uniqueid", var->value, field, value, NULL)) > -1) 01423 ret = 0; 01424 } 01425 ast_variables_destroy(save); 01426 return ret; 01427 }
static void update_realtime_members | ( | struct call_queue * | q | ) | [static] |
Definition at line 1429 of file app_queue.c.
References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next(), ao2_lock(), ao2_ref(), ao2_unlink(), ao2_unlock(), ast_category_browse(), ast_config_destroy(), ast_load_realtime_multientry(), ast_log(), ast_variable_retrieve(), member::dead, member_interface::interface, LOG_DEBUG, call_queue::membercount, call_queue::members, call_queue::name, option_debug, member::realtime, remove_from_interfaces(), rt_handle_member_record(), S_OR, and member::state_interface.
Referenced by load_realtime_queue(), and queue_exec().
01430 { 01431 struct ast_config *member_config = NULL; 01432 struct member *m; 01433 char *interface = NULL; 01434 struct ao2_iterator mem_iter; 01435 01436 if (!(member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name", q->name , NULL))) { 01437 /*This queue doesn't have realtime members*/ 01438 if (option_debug > 2) 01439 ast_log(LOG_DEBUG, "Queue %s has no realtime members defined. No need for update\n", q->name); 01440 return; 01441 } 01442 01443 ao2_lock(q); 01444 01445 /* Temporarily set realtime members dead so we can detect deleted ones.*/ 01446 mem_iter = ao2_iterator_init(q->members, 0); 01447 while ((m = ao2_iterator_next(&mem_iter))) { 01448 if (m->realtime) 01449 m->dead = 1; 01450 ao2_ref(m, -1); 01451 } 01452 ao2_iterator_destroy(&mem_iter); 01453 01454 while ((interface = ast_category_browse(member_config, interface))) { 01455 rt_handle_member_record(q, interface, 01456 S_OR(ast_variable_retrieve(member_config, interface, "membername"), interface), 01457 ast_variable_retrieve(member_config, interface, "penalty"), 01458 ast_variable_retrieve(member_config, interface, "paused"), 01459 S_OR(ast_variable_retrieve(member_config, interface, "state_interface"), interface)); 01460 } 01461 01462 /* Delete all realtime members that have been deleted in DB. */ 01463 mem_iter = ao2_iterator_init(q->members, 0); 01464 while ((m = ao2_iterator_next(&mem_iter))) { 01465 if (m->dead) { 01466 ao2_unlink(q->members, m); 01467 ao2_unlock(q); 01468 remove_from_interfaces(m->state_interface); 01469 ao2_lock(q); 01470 q->membercount--; 01471 } 01472 ao2_ref(m, -1); 01473 } 01474 ao2_iterator_destroy(&mem_iter); 01475 ao2_unlock(q); 01476 ast_config_destroy(member_config); 01477 }
static int update_status | ( | const char * | interface, | |
const int | status | |||
) | [static] |
Definition at line 650 of file app_queue.c.
References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next(), ao2_lock(), ao2_ref(), ao2_unlock(), ast_copy_string(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, member::calls, member::dynamic, EVENT_FLAG_AGENT, member::interface, member::lastcall, manager_event(), call_queue::maskmemberstatus, member::membername, call_queue::members, call_queue::name, member::paused, member::penalty, member::realtime, member::state_interface, and member::status.
Referenced by handle_statechange(), and ring_entry().
00651 { 00652 struct member *cur; 00653 struct ao2_iterator mem_iter; 00654 struct call_queue *q; 00655 char tmp_interface[80]; 00656 00657 AST_LIST_LOCK(&queues); 00658 AST_LIST_TRAVERSE(&queues, q, list) { 00659 ao2_lock(q); 00660 mem_iter = ao2_iterator_init(q->members, 0); 00661 while ((cur = ao2_iterator_next(&mem_iter))) { 00662 char *slash_pos; 00663 ast_copy_string(tmp_interface, cur->state_interface, sizeof(tmp_interface)); 00664 if ((slash_pos = strchr(tmp_interface, '/'))) 00665 if ((slash_pos = strchr(slash_pos + 1, '/'))) 00666 *slash_pos = '\0'; 00667 00668 if (strcasecmp(interface, tmp_interface)) { 00669 ao2_ref(cur, -1); 00670 continue; 00671 } 00672 00673 if (cur->status != status) { 00674 cur->status = status; 00675 if (q->maskmemberstatus) { 00676 ao2_ref(cur, -1); 00677 continue; 00678 } 00679 00680 manager_event(EVENT_FLAG_AGENT, "QueueMemberStatus", 00681 "Queue: %s\r\n" 00682 "Location: %s\r\n" 00683 "MemberName: %s\r\n" 00684 "Membership: %s\r\n" 00685 "Penalty: %d\r\n" 00686 "CallsTaken: %d\r\n" 00687 "LastCall: %d\r\n" 00688 "Status: %d\r\n" 00689 "Paused: %d\r\n", 00690 q->name, cur->interface, cur->membername, cur->dynamic ? "dynamic" : cur->realtime ? "realtime" : "static", 00691 cur->penalty, cur->calls, (int)cur->lastcall, cur->status, cur->paused); 00692 } 00693 ao2_ref(cur, -1); 00694 } 00695 ao2_iterator_destroy(&mem_iter); 00696 ao2_unlock(q); 00697 } 00698 AST_LIST_UNLOCK(&queues); 00699 00700 return 0; 00701 }
static int upqm_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Definition at line 3986 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().
03987 { 03988 struct ast_module_user *lu; 03989 char *parse; 03990 int priority_jump = 0; 03991 int ignore_fail = 0; 03992 AST_DECLARE_APP_ARGS(args, 03993 AST_APP_ARG(queuename); 03994 AST_APP_ARG(interface); 03995 AST_APP_ARG(options); 03996 ); 03997 03998 if (ast_strlen_zero(data)) { 03999 ast_log(LOG_WARNING, "UnpauseQueueMember requires an argument ([queuename]|interface[|options])\n"); 04000 return -1; 04001 } 04002 04003 parse = ast_strdupa(data); 04004 04005 AST_STANDARD_APP_ARGS(args, parse); 04006 04007 lu = ast_module_user_add(chan); 04008 04009 if (args.options) { 04010 if (strchr(args.options, 'j')) 04011 priority_jump = 1; 04012 if (strchr(args.options, 'i')) 04013 ignore_fail = 1; 04014 } 04015 04016 if (ast_strlen_zero(args.interface)) { 04017 ast_log(LOG_WARNING, "Missing interface argument to PauseQueueMember ([queuename]|interface[|options])\n"); 04018 ast_module_user_remove(lu); 04019 return -1; 04020 } 04021 04022 if (set_member_paused(args.queuename, args.interface, 0)) { 04023 ast_log(LOG_WARNING, "Attempt to unpause interface %s, not found\n", args.interface); 04024 pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "NOTFOUND"); 04025 if (priority_jump || ast_opt_priority_jumping) { 04026 if (!ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101)) { 04027 ast_module_user_remove(lu); 04028 return 0; 04029 } 04030 } 04031 ast_module_user_remove(lu); 04032 if (ignore_fail) { 04033 return 0; 04034 } else { 04035 return -1; 04036 } 04037 } 04038 04039 ast_module_user_remove(lu); 04040 pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "UNPAUSED"); 04041 return 0; 04042 }
static int valid_exit | ( | struct queue_ent * | qe, | |
char | digit | |||
) | [static] |
Definition at line 1617 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().
01618 { 01619 int digitlen = strlen(qe->digits); 01620 01621 /* Prevent possible buffer overflow */ 01622 if (digitlen < sizeof(qe->digits) - 2) { 01623 qe->digits[digitlen] = digit; 01624 qe->digits[digitlen + 1] = '\0'; 01625 } else { 01626 qe->digits[0] = '\0'; 01627 return 0; 01628 } 01629 01630 /* If there's no context to goto, short-circuit */ 01631 if (ast_strlen_zero(qe->context)) 01632 return 0; 01633 01634 /* If the extension is bad, then reset the digits to blank */ 01635 if (!ast_canmatch_extension(qe->chan, qe->context, qe->digits, 1, qe->chan->cid.cid_num)) { 01636 qe->digits[0] = '\0'; 01637 return 0; 01638 } 01639 01640 /* We have an exact match */ 01641 if (!ast_goto_if_exists(qe->chan, qe->context, qe->digits, 1)) { 01642 qe->valid_digits = 1; 01643 /* Return 1 on a successful goto */ 01644 return 1; 01645 } 01646 01647 return 0; 01648 }
static char* vars2manager | ( | struct ast_channel * | chan, | |
char * | vars, | |||
size_t | len | |||
) | [static] |
Definition at line 1919 of file app_queue.c.
References ast_copy_string(), and pbx_builtin_serialize_variables().
Referenced by ring_entry(), and try_calling().
01920 { 01921 char *tmp = alloca(len); 01922 01923 if (pbx_builtin_serialize_variables(chan, tmp, len)) { 01924 int i, j; 01925 01926 /* convert "\n" to "\nVariable: " */ 01927 strcpy(vars, "Variable: "); 01928 01929 for (i = 0, j = 10; (i < len - 1) && (j < len - 1); i++, j++) { 01930 vars[j] = tmp[i]; 01931 01932 if (tmp[i + 1] == '\0') 01933 break; 01934 if (tmp[i] == '\n') { 01935 vars[j++] = '\r'; 01936 vars[j++] = '\n'; 01937 01938 ast_copy_string(&(vars[j]), "Variable: ", len - j); 01939 j += 9; 01940 } 01941 } 01942 if (j > len - 3) 01943 j = len - 3; 01944 vars[j++] = '\r'; 01945 vars[j++] = '\n'; 01946 vars[j] = '\0'; 01947 } else { 01948 /* there are no channel variables; leave it blank */ 01949 *vars = '\0'; 01950 } 01951 return vars; 01952 }
static int wait_a_bit | ( | struct queue_ent * | qe | ) | [static] |
Definition at line 3599 of file app_queue.c.
References ast_waitfordigit(), queue_ent::chan, queue_ent::parent, call_queue::retry, and valid_exit().
Referenced by queue_exec().
03600 { 03601 /* Don't need to hold the lock while we setup the outgoing calls */ 03602 int retrywait = qe->parent->retry * 1000; 03603 03604 int res = ast_waitfordigit(qe->chan, retrywait); 03605 if (res > 0 && !valid_exit(qe, res)) 03606 res = 0; 03607 03608 return res; 03609 }
static struct callattempt* wait_for_answer | ( | struct queue_ent * | qe, | |
struct callattempt * | outgoing, | |||
int * | to, | |||
char * | digit, | |||
int | prebusies, | |||
int | caller_disconnect, | |||
int | forwardsallowed | |||
) | [static, read] |
Wait for a member to answer the call.
[in] | qe | the queue_ent corresponding to the caller in the queue |
[in] | outgoing | the list of callattempts. Relevant ones will have their chan and stillgoing parameters non-zero |
[in] | to | the amount of time (in milliseconds) to wait for a response |
[out] | digit | if a user presses a digit to exit the queue, this is the digit the caller pressed |
[in] | prebusies | number of busy members calculated prior to calling wait_for_answer |
[in] | caller_disconnect | if the 'H' option is used when calling Queue(), this is used to detect if the caller pressed * to disconnect the call |
[in] | forwardsallowed | used to detect if we should allow call forwarding, based on the 'i' option to Queue() |
Definition at line 2329 of file app_queue.c.
References ast_channel::_state, accountcode, ast_call(), ast_cdr_busy(), ast_cdr_failed(), ast_cdr_noanswer(), ast_channel_datastore_inherit(), ast_channel_inherit_variables(), ast_check_hangup(), AST_CONTROL_ANSWER, AST_CONTROL_BUSY, AST_CONTROL_CONGESTION, AST_CONTROL_HANGUP, AST_CONTROL_OFFHOOK, AST_CONTROL_RINGING, ast_copy_string(), AST_FRAME_CONTROL, AST_FRAME_DTMF, ast_frfree, ast_hangup(), ast_indicate(), ast_log(), AST_MAX_WATCHERS, ast_moh_stop(), ast_read(), ast_request(), AST_STATE_UP, ast_strdup, ast_string_field_set, ast_strlen_zero(), ast_verbose(), ast_waitfor_n(), callattempt::call_next, ast_channel::cdr, ast_channel::cdrflags, callattempt::chan, queue_ent::chan, ast_channel::cid, ast_callerid::cid_ani, ast_callerid::cid_name, ast_callerid::cid_num, ast_callerid::cid_rdnis, ast_channel::context, do_hang(), ast_channel::exten, f, ast_frame::frametype, free, callattempt::interface, member::interface, LOG_DEBUG, LOG_NOTICE, ast_channel::macroexten, callattempt::member, member::membername, call_queue::name, ast_channel::nativeformats, option_verbose, queue_ent::parent, callattempt::q_next, QUEUE_STRATEGY_RINGALL, ring_one(), queue_ent::ring_when_ringing, rna(), S_OR, starttime, callattempt::stillgoing, call_queue::strategy, ast_frame::subclass, ast_channel::tech, call_queue::timeoutrestart, valid_exit(), and VERBOSE_PREFIX_3.
Referenced by try_calling().
02330 { 02331 char *queue = qe->parent->name; 02332 struct callattempt *o, *start = NULL, *prev = NULL; 02333 int status; 02334 int numbusies = prebusies; 02335 int numnochan = 0; 02336 int stillgoing = 0; 02337 int orig = *to; 02338 struct ast_frame *f; 02339 struct callattempt *peer = NULL; 02340 struct ast_channel *winner; 02341 struct ast_channel *in = qe->chan; 02342 char on[80] = ""; 02343 char membername[80] = ""; 02344 long starttime = 0; 02345 long endtime = 0; 02346 02347 starttime = (long) time(NULL); 02348 02349 while (*to && !peer) { 02350 int numlines, retry, pos = 1; 02351 struct ast_channel *watchers[AST_MAX_WATCHERS]; 02352 watchers[0] = in; 02353 start = NULL; 02354 02355 for (retry = 0; retry < 2; retry++) { 02356 numlines = 0; 02357 for (o = outgoing; o; o = o->q_next) { /* Keep track of important channels */ 02358 if (o->stillgoing) { /* Keep track of important channels */ 02359 stillgoing = 1; 02360 if (o->chan) { 02361 watchers[pos++] = o->chan; 02362 if (!start) 02363 start = o; 02364 else 02365 prev->call_next = o; 02366 prev = o; 02367 } 02368 } 02369 numlines++; 02370 } 02371 if (pos > 1 /* found */ || !stillgoing /* nobody listening */ || 02372 (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) /* ring would not be delivered */) 02373 break; 02374 /* On "ringall" strategy we only move to the next penalty level 02375 when *all* ringing phones are done in the current penalty level */ 02376 ring_one(qe, outgoing, &numbusies); 02377 /* and retry... */ 02378 } 02379 if (pos == 1 /* not found */) { 02380 if (numlines == (numbusies + numnochan)) { 02381 ast_log(LOG_DEBUG, "Everyone is busy at this time\n"); 02382 if (in->cdr && (in->_state != AST_STATE_UP)) { 02383 ast_cdr_busy(in->cdr); 02384 } 02385 } else { 02386 ast_log(LOG_NOTICE, "No one is answering queue '%s' (%d/%d/%d)\n", queue, numlines, numbusies, numnochan); 02387 if (in->cdr && (in->_state != AST_STATE_UP)) { 02388 ast_cdr_failed(in->cdr); 02389 } 02390 } 02391 *to = 0; 02392 return NULL; 02393 } 02394 02395 /* Poll for events from both the incoming channel as well as any outgoing channels */ 02396 winner = ast_waitfor_n(watchers, pos, to); 02397 02398 /* Service all of the outgoing channels */ 02399 for (o = start; o; o = o->call_next) { 02400 if (o->stillgoing && (o->chan) && (o->chan->_state == AST_STATE_UP)) { 02401 if (!peer) { 02402 if (option_verbose > 2) 02403 ast_verbose( VERBOSE_PREFIX_3 "%s answered %s\n", o->chan->name, in->name); 02404 peer = o; 02405 } 02406 } else if (o->chan && (o->chan == winner)) { 02407 02408 ast_copy_string(on, o->member->interface, sizeof(on)); 02409 ast_copy_string(membername, o->member->membername, sizeof(membername)); 02410 02411 if (!ast_strlen_zero(o->chan->call_forward) && !forwardsallowed) { 02412 if (option_verbose > 2) 02413 ast_verbose(VERBOSE_PREFIX_3 "Forwarding %s to '%s' prevented.\n", in->name, o->chan->call_forward); 02414 numnochan++; 02415 do_hang(o); 02416 winner = NULL; 02417 continue; 02418 } else if (!ast_strlen_zero(o->chan->call_forward)) { 02419 char tmpchan[256]; 02420 char *stuff; 02421 char *tech; 02422 02423 ast_copy_string(tmpchan, o->chan->call_forward, sizeof(tmpchan)); 02424 if ((stuff = strchr(tmpchan, '/'))) { 02425 *stuff++ = '\0'; 02426 tech = tmpchan; 02427 } else { 02428 snprintf(tmpchan, sizeof(tmpchan), "%s@%s", o->chan->call_forward, o->chan->context); 02429 stuff = tmpchan; 02430 tech = "Local"; 02431 } 02432 /* Before processing channel, go ahead and check for forwarding */ 02433 if (option_verbose > 2) 02434 ast_verbose(VERBOSE_PREFIX_3 "Now forwarding %s to '%s/%s' (thanks to %s)\n", in->name, tech, stuff, o->chan->name); 02435 /* Setup parameters */ 02436 o->chan = ast_request(tech, in->nativeformats, stuff, &status); 02437 if (!o->chan) { 02438 ast_log(LOG_NOTICE, 02439 "Forwarding failed to create channel to dial '%s/%s'\n", 02440 tech, stuff); 02441 o->stillgoing = 0; 02442 numnochan++; 02443 } else { 02444 ast_channel_inherit_variables(in, o->chan); 02445 ast_channel_datastore_inherit(in, o->chan); 02446 if (o->chan->cid.cid_num) 02447 free(o->chan->cid.cid_num); 02448 o->chan->cid.cid_num = ast_strdup(in->cid.cid_num); 02449 02450 if (o->chan->cid.cid_name) 02451 free(o->chan->cid.cid_name); 02452 o->chan->cid.cid_name = ast_strdup(in->cid.cid_name); 02453 02454 ast_string_field_set(o->chan, accountcode, in->accountcode); 02455 o->chan->cdrflags = in->cdrflags; 02456 02457 if (in->cid.cid_ani) { 02458 if (o->chan->cid.cid_ani) 02459 free(o->chan->cid.cid_ani); 02460 o->chan->cid.cid_ani = ast_strdup(in->cid.cid_ani); 02461 } 02462 if (o->chan->cid.cid_rdnis) 02463 free(o->chan->cid.cid_rdnis); 02464 o->chan->cid.cid_rdnis = ast_strdup(S_OR(in->macroexten, in->exten)); 02465 if (ast_call(o->chan, stuff, 0)) { 02466 ast_log(LOG_NOTICE, "Forwarding failed to dial '%s/%s'\n", 02467 tech, stuff); 02468 do_hang(o); 02469 numnochan++; 02470 } 02471 } 02472 /* Hangup the original channel now, in case we needed it */ 02473 ast_hangup(winner); 02474 continue; 02475 } 02476 f = ast_read(winner); 02477 if (f) { 02478 if (f->frametype == AST_FRAME_CONTROL) { 02479 switch (f->subclass) { 02480 case AST_CONTROL_ANSWER: 02481 /* This is our guy if someone answered. */ 02482 if (!peer) { 02483 if (option_verbose > 2) 02484 ast_verbose( VERBOSE_PREFIX_3 "%s answered %s\n", o->chan->name, in->name); 02485 peer = o; 02486 } 02487 break; 02488 case AST_CONTROL_BUSY: 02489 if (option_verbose > 2) 02490 ast_verbose( VERBOSE_PREFIX_3 "%s is busy\n", o->chan->name); 02491 if (in->cdr) 02492 ast_cdr_busy(in->cdr); 02493 do_hang(o); 02494 endtime = (long)time(NULL); 02495 endtime -= starttime; 02496 rna(endtime * 1000, qe, on, membername, 0); 02497 if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) { 02498 if (qe->parent->timeoutrestart) 02499 *to = orig; 02500 /* Have enough time for a queue member to answer? */ 02501 if (*to > 500) { 02502 ring_one(qe, outgoing, &numbusies); 02503 starttime = (long) time(NULL); 02504 } 02505 } 02506 numbusies++; 02507 break; 02508 case AST_CONTROL_CONGESTION: 02509 if (option_verbose > 2) 02510 ast_verbose( VERBOSE_PREFIX_3 "%s is circuit-busy\n", o->chan->name); 02511 if (in->cdr) 02512 ast_cdr_failed(in->cdr); 02513 endtime = (long)time(NULL); 02514 endtime -= starttime; 02515 rna(endtime * 1000, qe, on, membername, 0); 02516 do_hang(o); 02517 if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) { 02518 if (qe->parent->timeoutrestart) 02519 *to = orig; 02520 if (*to > 500) { 02521 ring_one(qe, outgoing, &numbusies); 02522 starttime = (long) time(NULL); 02523 } 02524 } 02525 numbusies++; 02526 break; 02527 case AST_CONTROL_RINGING: 02528 if (option_verbose > 2) 02529 ast_verbose( VERBOSE_PREFIX_3 "%s is ringing\n", o->chan->name); 02530 02531 /* Start ring indication when the channel is ringing, if specified */ 02532 if (qe->ring_when_ringing) { 02533 ast_moh_stop(qe->chan); 02534 ast_indicate(qe->chan, AST_CONTROL_RINGING); 02535 } 02536 break; 02537 case AST_CONTROL_OFFHOOK: 02538 /* Ignore going off hook */ 02539 break; 02540 default: 02541 ast_log(LOG_DEBUG, "Dunno what to do with control type %d\n", f->subclass); 02542 } 02543 } 02544 ast_frfree(f); 02545 } else { /* ast_read() returned NULL */ 02546 endtime = (long) time(NULL) - starttime; 02547 rna(endtime * 1000, qe, on, membername, 1); 02548 do_hang(o); 02549 if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) { 02550 if (qe->parent->timeoutrestart) 02551 *to = orig; 02552 if (*to > 500) { 02553 ring_one(qe, outgoing, &numbusies); 02554 starttime = (long) time(NULL); 02555 } 02556 } 02557 } 02558 } 02559 } 02560 02561 /* If we received an event from the caller, deal with it. */ 02562 if (winner == in) { 02563 f = ast_read(in); 02564 if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP))) { 02565 /* Got hung up */ 02566 *to = -1; 02567 if (f) 02568 ast_frfree(f); 02569 return NULL; 02570 } 02571 /* First check if DTMF digit is a valid exit */ 02572 if ((f->frametype == AST_FRAME_DTMF) && valid_exit(qe, f->subclass)) { 02573 if (option_verbose > 3) 02574 ast_verbose(VERBOSE_PREFIX_3 "User pressed digit: %c\n", f->subclass); 02575 *to = 0; 02576 *digit = f->subclass; 02577 ast_frfree(f); 02578 if (in->cdr && (in->_state != AST_STATE_UP)) { 02579 ast_cdr_noanswer(in->cdr); 02580 } 02581 return NULL; 02582 } 02583 /* Else check if DTMF should be interpreted as caller disconnect */ 02584 if ((f->frametype == AST_FRAME_DTMF) && caller_disconnect && (f->subclass == '*')) { 02585 if (option_verbose > 3) 02586 ast_verbose(VERBOSE_PREFIX_3 "User hit %c to disconnect call.\n", f->subclass); 02587 *to = 0; 02588 ast_frfree(f); 02589 if (in->cdr && (in->_state != AST_STATE_UP)) { 02590 ast_cdr_noanswer(in->cdr); 02591 } 02592 return NULL; 02593 } 02594 ast_frfree(f); 02595 } 02596 if (!*to) { 02597 for (o = start; o; o = o->call_next) 02598 rna(orig, qe, o->interface, o->member->membername, 1); 02599 } 02600 } 02601 02602 if (in->cdr 02603 && in->_state != AST_STATE_UP 02604 && (!*to || ast_check_hangup(in))) { 02605 ast_cdr_noanswer(in->cdr); 02606 } 02607 02608 return peer; 02609 }
static int wait_our_turn | ( | struct queue_ent * | qe, | |
int | ringing, | |||
enum queue_result * | reason | |||
) | [static] |
The waiting areas for callers who are not actively calling members.
This function is one large loop. This function will return if a caller either exits the queue or it becomes that caller's turn to attempt calling queue members. Inside the loop, we service the caller with periodic announcements, holdtime announcements, etc. as configured in queues.conf
0 | if the caller's turn has arrived | |
-1 | if the caller should exit the queue. |
Definition at line 2671 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().
02672 { 02673 int res = 0; 02674 02675 /* This is the holding pen for callers 2 through maxlen */ 02676 for (;;) { 02677 enum queue_member_status stat; 02678 02679 if (is_our_turn(qe)) 02680 break; 02681 02682 /* If we have timed out, break out */ 02683 if (qe->expire && (time(NULL) >= qe->expire)) { 02684 *reason = QUEUE_TIMEOUT; 02685 break; 02686 } 02687 02688 stat = get_member_status(qe->parent, qe->max_penalty); 02689 02690 /* leave the queue if no agents, if enabled */ 02691 if (qe->parent->leavewhenempty && (stat == QUEUE_NO_MEMBERS)) { 02692 *reason = QUEUE_LEAVEEMPTY; 02693 ast_queue_log(qe->parent->name, qe->chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe->pos, qe->opos, (long)time(NULL) - qe->start); 02694 leave_queue(qe); 02695 break; 02696 } 02697 02698 /* leave the queue if no reachable agents, if enabled */ 02699 if ((qe->parent->leavewhenempty == QUEUE_EMPTY_STRICT) && (stat == QUEUE_NO_REACHABLE_MEMBERS)) { 02700 *reason = QUEUE_LEAVEUNAVAIL; 02701 ast_queue_log(qe->parent->name, qe->chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe->pos, qe->opos, (long)time(NULL) - qe->start); 02702 leave_queue(qe); 02703 break; 02704 } 02705 02706 /* Make a position announcement, if enabled */ 02707 if (qe->parent->announcefrequency && !ringing && 02708 (res = say_position(qe))) 02709 break; 02710 02711 /* If we have timed out, break out */ 02712 if (qe->expire && (time(NULL) >= qe->expire)) { 02713 *reason = QUEUE_TIMEOUT; 02714 break; 02715 } 02716 02717 /* Make a periodic announcement, if enabled */ 02718 if (qe->parent->periodicannouncefrequency && !ringing && 02719 (res = say_periodic_announcement(qe))) 02720 break; 02721 02722 /* If we have timed out, break out */ 02723 if (qe->expire && (time(NULL) >= qe->expire)) { 02724 *reason = QUEUE_TIMEOUT; 02725 break; 02726 } 02727 02728 /* Wait a second before checking again */ 02729 if ((res = ast_waitfordigit(qe->chan, RECHECK * 1000))) { 02730 if (res > 0 && !valid_exit(qe, res)) 02731 res = 0; 02732 else 02733 break; 02734 } 02735 02736 /* If we have timed out, break out */ 02737 if (qe->expire && (time(NULL) >= qe->expire)) { 02738 *reason = QUEUE_TIMEOUT; 02739 break; 02740 } 02741 } 02742 02743 return res; 02744 }
struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT | AST_MODFLAG_BUILDSUM, .description = "True Call Queueing" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "361d7bb937402d51e4658efb5b4d76e4" , .load = load_module, .unload = unload_module, .reload = reload, } [static] |
Definition at line 5960 of file app_queue.c.
char* app = "Queue" [static] |
Definition at line 152 of file app_queue.c.
char* app_aqm = "AddQueueMember" [static] |
Definition at line 198 of file app_queue.c.
char* app_aqm_descrip [static] |
Definition at line 200 of file app_queue.c.
char* app_aqm_synopsis = "Dynamically adds queue members" [static] |
Definition at line 199 of file app_queue.c.
char* app_pqm = "PauseQueueMember" [static] |
Definition at line 233 of file app_queue.c.
char* app_pqm_descrip [static] |
Definition at line 235 of file app_queue.c.
char* app_pqm_synopsis = "Pauses a queue member" [static] |
Definition at line 234 of file app_queue.c.
char* app_ql = "QueueLog" [static] |
Definition at line 272 of file app_queue.c.
char* app_ql_descrip [static] |
" 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 274 of file app_queue.c.
char* app_ql_synopsis = "Writes to the queue_log" [static] |
Definition at line 273 of file app_queue.c.
char* app_rqm = "RemoveQueueMember" [static] |
Definition at line 217 of file app_queue.c.
char* app_rqm_descrip [static] |
Definition at line 219 of file app_queue.c.
char* app_rqm_synopsis = "Dynamically removes queue members" [static] |
Definition at line 218 of file app_queue.c.
char* app_upqm = "UnpauseQueueMember" [static] |
Definition at line 256 of file app_queue.c.
char* app_upqm_descrip [static] |
Definition at line 258 of file app_queue.c.
char* app_upqm_synopsis = "Unpauses a queue member" [static] |
Definition at line 257 of file app_queue.c.
const struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 5960 of file app_queue.c.
int autofill_default = 0 [static] |
queues.conf [general] option
Definition at line 294 of file app_queue.c.
struct ast_cli_entry cli_add_queue_member_deprecated [static] |
{ { "add", "queue", "member", NULL }, handle_queue_add_member, NULL, NULL, complete_queue_add_member }
Definition at line 5837 of file app_queue.c.
struct ast_cli_entry cli_queue[] [static] |
Definition at line 5847 of file app_queue.c.
Referenced by load_module(), and unload_module().
struct ast_cli_entry cli_remove_queue_member_deprecated [static] |
{ { "remove", "queue", "member", NULL }, handle_queue_remove_member, NULL, NULL, complete_queue_remove_member }
Definition at line 5842 of file app_queue.c.
struct ast_cli_entry cli_show_queue_deprecated [static] |
{ { "show", "queue", NULL }, queue_show, NULL, NULL, complete_queue_show }
Definition at line 5832 of file app_queue.c.
Condition for the state change queue
Definition at line 757 of file app_queue.c.
char* descrip [static] |
Definition at line 156 of file app_queue.c.
struct { ... } device_state [static] |
Data used by the device state thread.
Referenced by device_state_thread(), load_module(), statechange_queue(), and unload_module().
struct statechange* first |
Definition at line 759 of file app_queue.c.
enum queue_result id |
Definition at line 314 of file app_queue.c.
Referenced by _sip_show_peers().
struct statechange* last |
Definition at line 759 of file app_queue.c.
Lock for the state change queue
Definition at line 755 of file app_queue.c.
int montype_default = 0 [static] |
queues.conf [general] option
Definition at line 297 of file app_queue.c.
const char* pm_family = "Queue/PersistentMembers" [static] |
Persistent Members astdb family.
Definition at line 280 of file app_queue.c.
char qam_cmd_usage[] [static] |
"Usage: queue add member <channel> to <queue> [penalty <penalty> [as <membername> [state_interface <state_interface>]]]\n"
Definition at line 5826 of file app_queue.c.
char qmc_cmd_usage[] [static] |
"Usage: queue member count <queue>\n" " Provides member count information on a specified queue.\n"
Definition at line 5803 of file app_queue.c.
char qrm_cmd_usage[] [static] |
"Usage: queue remove member <channel> from <queue>\n"
Definition at line 5829 of file app_queue.c.
int queue_debug = 0 [static] |
queues.conf [general] extra debug option
Definition at line 285 of file app_queue.c.
int queue_persistent_members = 0 [static] |
queues.conf [general] option
Definition at line 288 of file app_queue.c.
struct { ... } queue_results[] |
Referenced by set_queue_result().
char queue_show_usage[] [static] |
"Usage: queue show\n" " Provides summary information on a specified queue.\n"
Definition at line 5822 of file app_queue.c.
struct ast_datastore_info queue_transfer_info [static] |
{ .type = "queue_transfer", .chan_fixup = queue_transfer_fixup, .destroy = queue_transfer_destroy, }
a datastore used to help correctly log attended transfers of queue callers
Definition at line 2874 of file app_queue.c.
Referenced by attended_transfer_occurred(), queue_transfer_fixup(), setup_transfer_datastore(), and try_calling().
struct ast_custom_function queueagentcount_function [static] |
Definition at line 4844 of file app_queue.c.
Referenced by load_module(), and unload_module().
struct ast_custom_function queueexists_function [static] |
Definition at line 4836 of file app_queue.c.
Referenced by load_module(), and unload_module().
struct ast_custom_function queuemembercount_function [static] |
Definition at line 4854 of file app_queue.c.
Referenced by load_module(), and unload_module().
struct ast_custom_function queuememberlist_function [static] |
Definition at line 4878 of file app_queue.c.
Referenced by load_module(), and unload_module().
struct ast_custom_function queuememberpaused_function [static] |
Definition at line 4896 of file app_queue.c.
Referenced by load_module(), and unload_module().
struct ast_custom_function queuememberstatus_function [static] |
Definition at line 4887 of file app_queue.c.
Referenced by load_module(), and unload_module().
struct ast_custom_function queuewaitingcount_function [static] |
Definition at line 4869 of file app_queue.c.
Referenced by load_module(), and unload_module().
int shared_lastcall = 0 [static] |
queues.conf [general] option
Definition at line 300 of file app_queue.c.
struct { ... } state_change_q |
Queue of state changes
unsigned int stop |
Set to 1 to stop the thread
Definition at line 751 of file app_queue.c.
struct strategy strategies[] [static] |
Referenced by int2strat(), and strat2int().
char* synopsis = "Queue a call for a call queue" [static] |
Definition at line 154 of file app_queue.c.
char* text |
Definition at line 315 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 753 of file app_queue.c.
int use_weight = 0 [static] |
queues.conf per-queue weight option
Definition at line 291 of file app_queue.c.