#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 } |
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 } |
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_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_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 (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 { | |
statechange * first | |
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 | queuemembercount_function |
static struct ast_custom_function | queuememberlist_function |
static struct ast_custom_function | queuewaitingcount_function |
static struct strategy | strategies [] |
static char * | synopsis = "Queue a call for a call queue" |
static int | use_weight = 0 |
queues.conf per-queue weight option |
These features added by David C. Troy <dave@toad.net>:
Added servicelevel statistic by Michiel Betel <michiel@betel.nl> Added Priority jumping code for adding and removing queue members by Jonathan Stanton <asterisk@doilooklikeicare.com>
Fixed to work with CVS as of 2004-02-25 and released as 1.07a by Matthew Enger <m.enger@xi.com.au>
Definition in file app_queue.c.
#define ANNOUNCEHOLDTIME_ALWAYS 1 |
#define ANNOUNCEHOLDTIME_ONCE 2 |
#define AST_MAX_WATCHERS 256 |
Definition at line 2215 of file app_queue.c.
#define DEFAULT_RETRY 5 |
#define DEFAULT_TIMEOUT 15 |
#define MAX_PERIODIC_ANNOUNCEMENTS 10 |
Definition at line 140 of file app_queue.c.
Referenced by init_queue(), queue_set_param(), and say_periodic_announcement().
#define PM_MAX_LEN 8192 |
Definition at line 276 of file app_queue.c.
Referenced by dump_queue_members(), and reload_queue_members().
#define QUEUE_EMPTY_NORMAL 1 |
#define QUEUE_EMPTY_STRICT 2 |
Definition at line 389 of file app_queue.c.
Referenced by join_queue(), queue_exec(), queue_set_param(), and wait_our_turn().
#define QUEUE_EVENT_VARIABLES 3 |
#define RECHECK 1 |
#define RES_EXISTS (-1) |
Definition at line 143 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 145 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 146 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 142 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 144 of file app_queue.c.
Referenced by add_to_queue(), aqm_exec(), handle_queue_add_member(), handle_queue_remove_member(), manager_add_queue_member(), manager_remove_queue_member(), and reload_queue_members().
anonymous enum |
QUEUE_STRATEGY_RINGALL | |
QUEUE_STRATEGY_ROUNDROBIN | |
QUEUE_STRATEGY_LEASTRECENT | |
QUEUE_STRATEGY_FEWESTCALLS | |
QUEUE_STRATEGY_RANDOM | |
QUEUE_STRATEGY_RRMEMORY |
Definition at line 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 };
enum qmc_status |
Definition at line 4296 of file app_queue.c.
04296 { 04297 QMC_VALID = 0, /* Count valid members */ 04298 QMC_PAUSED, /* Count paused members */ 04299 QMC_ACTIVE, /* Count active members */ 04300 QMC_FREE, /* Count free members */ 04301 QMC_ALL /* Count all queue members */ 04302 };
enum queue_member_status |
Definition at line 568 of file app_queue.c.
00568 { 00569 QUEUE_NO_MEMBERS, 00570 QUEUE_NO_REACHABLE_MEMBERS, 00571 QUEUE_NORMAL 00572 };
enum queue_result |
QUEUE_UNKNOWN | |
QUEUE_TIMEOUT | |
QUEUE_JOINEMPTY | |
QUEUE_LEAVEEMPTY | |
QUEUE_JOINUNAVAIL | |
QUEUE_LEAVEUNAVAIL | |
QUEUE_FULL |
Definition at line 293 of file app_queue.c.
00293 { 00294 QUEUE_UNKNOWN = 0, 00295 QUEUE_TIMEOUT = 1, 00296 QUEUE_JOINEMPTY = 2, 00297 QUEUE_LEAVEEMPTY = 3, 00298 QUEUE_JOINUNAVAIL = 4, 00299 QUEUE_LEAVEUNAVAIL = 5, 00300 QUEUE_FULL = 6, 00301 };
static int __queues_show | ( | struct mansession * | s, | |
int | manager, | |||
int | fd, | |||
int | argc, | |||
char ** | argv | |||
) | [static] |
Definition at line 4734 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, ast_channel::name, call_queue::name, queue_ent::next, member::paused, member::penalty, queue_ent::prio, queue_show(), member::realtime, RESULT_SHOWUSAGE, RESULT_SUCCESS, call_queue::ringlimit, s, call_queue::servicelevel, queue_ent::start, member::status, call_queue::strategy, and call_queue::weight.
Referenced by manager_queues_show(), and queue_show().
04735 { 04736 struct call_queue *q; 04737 struct queue_ent *qe; 04738 struct member *mem; 04739 int pos, queue_show; 04740 time_t now; 04741 char max_buf[150]; 04742 char *max; 04743 size_t max_left; 04744 float sl = 0; 04745 char *term = manager ? "\r\n" : "\n"; 04746 struct ao2_iterator mem_iter; 04747 04748 time(&now); 04749 if (argc == 2) 04750 queue_show = 0; 04751 else if (argc == 3) 04752 queue_show = 1; 04753 else 04754 return RESULT_SHOWUSAGE; 04755 04756 /* We only want to load realtime queues when a specific queue is asked for. */ 04757 if (queue_show) { 04758 load_realtime_queue(argv[2]); 04759 } else if (ast_check_realtime("queues")) { 04760 struct ast_config *cfg = ast_load_realtime_multientry("queues", "name LIKE", "%", (char *) NULL); 04761 char *queuename; 04762 if (cfg) { 04763 for (queuename = ast_category_browse(cfg, NULL); !ast_strlen_zero(queuename); queuename = ast_category_browse(cfg, queuename)) { 04764 load_realtime_queue(queuename); 04765 } 04766 ast_config_destroy(cfg); 04767 } 04768 } 04769 04770 AST_LIST_LOCK(&queues); 04771 if (AST_LIST_EMPTY(&queues)) { 04772 AST_LIST_UNLOCK(&queues); 04773 if (queue_show) { 04774 if (s) 04775 astman_append(s, "No such queue: %s.%s",argv[2], term); 04776 else 04777 ast_cli(fd, "No such queue: %s.%s",argv[2], term); 04778 } else { 04779 if (s) 04780 astman_append(s, "No queues.%s", term); 04781 else 04782 ast_cli(fd, "No queues.%s", term); 04783 } 04784 return RESULT_SUCCESS; 04785 } 04786 AST_LIST_TRAVERSE(&queues, q, list) { 04787 ao2_lock(q); 04788 if (queue_show) { 04789 if (strcasecmp(q->name, argv[2]) != 0) { 04790 ao2_unlock(q); 04791 if (!AST_LIST_NEXT(q, list)) { 04792 ast_cli(fd, "No such queue: %s.%s",argv[2], term); 04793 break; 04794 } 04795 continue; 04796 } 04797 } 04798 max_buf[0] = '\0'; 04799 max = max_buf; 04800 max_left = sizeof(max_buf); 04801 if (q->maxlen) 04802 ast_build_string(&max, &max_left, "%d", q->maxlen); 04803 else 04804 ast_build_string(&max, &max_left, "unlimited"); 04805 sl = 0; 04806 if (q->callscompleted > 0) 04807 sl = 100 * ((float) q->callscompletedinsl / (float) q->callscompleted); 04808 if (s) 04809 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", 04810 q->name, q->count, max_buf, int2strat(q->strategy), q->holdtime, q->ringlimit, 04811 q->weight, q->callscompleted, q->callsabandoned, sl, q->servicelevel, term); 04812 else 04813 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", 04814 q->name, q->count, max_buf, int2strat(q->strategy), q->holdtime, q->ringlimit, 04815 q->weight, q->callscompleted, q->callsabandoned, sl, q->servicelevel, term); 04816 if (ao2_container_count(q->members)) { 04817 if (s) 04818 astman_append(s, " Members: %s", term); 04819 else 04820 ast_cli(fd, " Members: %s", term); 04821 mem_iter = ao2_iterator_init(q->members, 0); 04822 while ((mem = ao2_iterator_next(&mem_iter))) { 04823 max_buf[0] = '\0'; 04824 max = max_buf; 04825 max_left = sizeof(max_buf); 04826 if (strcasecmp(mem->membername, mem->interface)) { 04827 ast_build_string(&max, &max_left, " (%s)", mem->interface); 04828 } 04829 if (mem->penalty) 04830 ast_build_string(&max, &max_left, " with penalty %d", mem->penalty); 04831 if (mem->dynamic) 04832 ast_build_string(&max, &max_left, " (dynamic)"); 04833 if (mem->realtime) 04834 ast_build_string(&max, &max_left, " (realtime)"); 04835 if (mem->paused) 04836 ast_build_string(&max, &max_left, " (paused)"); 04837 ast_build_string(&max, &max_left, " (%s)", devstate2str(mem->status)); 04838 if (mem->calls) { 04839 ast_build_string(&max, &max_left, " has taken %d calls (last was %ld secs ago)", 04840 mem->calls, (long) (time(NULL) - mem->lastcall)); 04841 } else 04842 ast_build_string(&max, &max_left, " has taken no calls yet"); 04843 if (s) 04844 astman_append(s, " %s%s%s", mem->membername, max_buf, term); 04845 else 04846 ast_cli(fd, " %s%s%s", mem->membername, max_buf, term); 04847 ao2_ref(mem, -1); 04848 } 04849 ao2_iterator_destroy(&mem_iter); 04850 } else if (s) 04851 astman_append(s, " No Members%s", term); 04852 else 04853 ast_cli(fd, " No Members%s", term); 04854 if (q->head) { 04855 pos = 1; 04856 if (s) 04857 astman_append(s, " Callers: %s", term); 04858 else 04859 ast_cli(fd, " Callers: %s", term); 04860 for (qe = q->head; qe; qe = qe->next) { 04861 if (s) 04862 astman_append(s, " %d. %s (wait: %ld:%2.2ld, prio: %d)%s", 04863 pos++, qe->chan->name, (long) (now - qe->start) / 60, 04864 (long) (now - qe->start) % 60, qe->prio, term); 04865 else 04866 ast_cli(fd, " %d. %s (wait: %ld:%2.2ld, prio: %d)%s", pos++, 04867 qe->chan->name, (long) (now - qe->start) / 60, 04868 (long) (now - qe->start) % 60, qe->prio, term); 04869 } 04870 } else if (s) 04871 astman_append(s, " No Callers%s", term); 04872 else 04873 ast_cli(fd, " No Callers%s", term); 04874 if (s) 04875 astman_append(s, "%s", term); 04876 else 04877 ast_cli(fd, "%s", term); 04878 ao2_unlock(q); 04879 if (queue_show) 04880 break; 04881 } 04882 AST_LIST_UNLOCK(&queues); 04883 return RESULT_SUCCESS; 04884 }
static void __reg_module | ( | void | ) | [static] |
Definition at line 5562 of file app_queue.c.
static void __unreg_module | ( | void | ) | [static] |
Definition at line 5562 of file app_queue.c.
static int add_to_interfaces | ( | const char * | interface | ) | [static] |
Definition at line 915 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, member_interface::list, LOG_DEBUG, and option_debug.
Referenced by add_to_queue(), reload_queues(), and rt_handle_member_record().
00916 { 00917 struct member_interface *curint; 00918 00919 AST_LIST_LOCK(&interfaces); 00920 AST_LIST_TRAVERSE(&interfaces, curint, list) { 00921 if (!strcasecmp(curint->interface, interface)) 00922 break; 00923 } 00924 00925 if (curint) { 00926 AST_LIST_UNLOCK(&interfaces); 00927 return 0; 00928 } 00929 00930 if (option_debug) 00931 ast_log(LOG_DEBUG, "Adding %s to the list of interfaces that make up all of our queue members.\n", interface); 00932 00933 if ((curint = ast_calloc(1, sizeof(*curint)))) { 00934 ast_copy_string(curint->interface, interface, sizeof(curint->interface)); 00935 AST_LIST_INSERT_HEAD(&interfaces, curint, list); 00936 } 00937 AST_LIST_UNLOCK(&interfaces); 00938 00939 return 0; 00940 }
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 3515 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().
03516 { 03517 struct call_queue *q; 03518 struct member *new_member, *old_member; 03519 int res = RES_NOSUCHQUEUE; 03520 03521 /* \note Ensure the appropriate realtime queue is loaded. Note that this 03522 * short-circuits if the queue is already in memory. */ 03523 if (!(q = load_realtime_queue(queuename))) 03524 return res; 03525 03526 AST_LIST_LOCK(&queues); 03527 03528 ao2_lock(q); 03529 if ((old_member = interface_exists(q, interface)) == NULL) { 03530 if ((new_member = create_queue_member(interface, membername, penalty, paused, state_interface))) { 03531 add_to_interfaces(new_member->state_interface); 03532 new_member->dynamic = 1; 03533 ao2_link(q->members, new_member); 03534 q->membercount++; 03535 manager_event(EVENT_FLAG_AGENT, "QueueMemberAdded", 03536 "Queue: %s\r\n" 03537 "Location: %s\r\n" 03538 "MemberName: %s\r\n" 03539 "Membership: %s\r\n" 03540 "Penalty: %d\r\n" 03541 "CallsTaken: %d\r\n" 03542 "LastCall: %d\r\n" 03543 "Status: %d\r\n" 03544 "Paused: %d\r\n", 03545 q->name, new_member->interface, new_member->membername, 03546 "dynamic", 03547 new_member->penalty, new_member->calls, (int) new_member->lastcall, 03548 new_member->status, new_member->paused); 03549 03550 ao2_ref(new_member, -1); 03551 new_member = NULL; 03552 03553 if (dump) 03554 dump_queue_members(q); 03555 03556 res = RES_OKAY; 03557 } else { 03558 res = RES_OUTOFMEMORY; 03559 } 03560 } else { 03561 ao2_ref(old_member, -1); 03562 res = RES_EXISTS; 03563 } 03564 ao2_unlock(q); 03565 AST_LIST_UNLOCK(&queues); 03566 03567 return res; 03568 }
static struct call_queue* alloc_queue | ( | const char * | queuename | ) | [static] |
Definition at line 817 of file app_queue.c.
References ao2_alloc(), ast_copy_string(), and destroy_queue().
Referenced by find_queue_by_name_rt(), and reload_queues().
00818 { 00819 struct call_queue *q; 00820 00821 if ((q = ao2_alloc(sizeof(*q), destroy_queue))) { 00822 ast_copy_string(q->name, queuename, sizeof(q->name)); 00823 } 00824 return q; 00825 }
static int aqm_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Definition at line 3896 of file app_queue.c.
References add_to_queue(), AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_goto_if_exists(), ast_log(), ast_module_user_add, ast_module_user_remove, ast_opt_priority_jumping, ast_queue_log(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), ast_module_user::chan, ast_channel::context, LOG_ERROR, LOG_NOTICE, LOG_WARNING, ast_channel::name, parse(), pbx_builtin_setvar_helper(), RES_EXISTS, RES_NOSUCHQUEUE, RES_OKAY, RES_OUTOFMEMORY, and ast_channel::uniqueid.
Referenced by load_module().
03897 { 03898 int res=-1; 03899 struct ast_module_user *lu; 03900 char *parse, *temppos = NULL; 03901 int priority_jump = 0; 03902 AST_DECLARE_APP_ARGS(args, 03903 AST_APP_ARG(queuename); 03904 AST_APP_ARG(interface); 03905 AST_APP_ARG(penalty); 03906 AST_APP_ARG(options); 03907 AST_APP_ARG(membername); 03908 AST_APP_ARG(state_interface); 03909 ); 03910 int penalty = 0; 03911 03912 if (ast_strlen_zero(data)) { 03913 ast_log(LOG_WARNING, "AddQueueMember requires an argument (queuename[|interface[|penalty[|options[|membername[|state_interface]]]]])\n"); 03914 return -1; 03915 } 03916 03917 parse = ast_strdupa(data); 03918 03919 AST_STANDARD_APP_ARGS(args, parse); 03920 03921 lu = ast_module_user_add(chan); 03922 03923 if (ast_strlen_zero(args.interface)) { 03924 args.interface = ast_strdupa(chan->name); 03925 temppos = strrchr(args.interface, '-'); 03926 if (temppos) 03927 *temppos = '\0'; 03928 } 03929 03930 if (!ast_strlen_zero(args.penalty)) { 03931 if ((sscanf(args.penalty, "%30d", &penalty) != 1) || penalty < 0) { 03932 ast_log(LOG_WARNING, "Penalty '%s' is invalid, must be an integer >= 0\n", args.penalty); 03933 penalty = 0; 03934 } 03935 } 03936 03937 if (args.options) { 03938 if (strchr(args.options, 'j')) 03939 priority_jump = 1; 03940 } 03941 03942 switch (add_to_queue(args.queuename, args.interface, args.membername, penalty, 0, queue_persistent_members, args.state_interface)) { 03943 case RES_OKAY: 03944 ast_queue_log(args.queuename, chan->uniqueid, args.interface, "ADDMEMBER", "%s", ""); 03945 ast_log(LOG_NOTICE, "Added interface '%s' to queue '%s'\n", args.interface, args.queuename); 03946 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "ADDED"); 03947 res = 0; 03948 break; 03949 case RES_EXISTS: 03950 ast_log(LOG_WARNING, "Unable to add interface '%s' to queue '%s': Already there\n", args.interface, args.queuename); 03951 if (priority_jump || ast_opt_priority_jumping) 03952 ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101); 03953 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "MEMBERALREADY"); 03954 res = 0; 03955 break; 03956 case RES_NOSUCHQUEUE: 03957 ast_log(LOG_WARNING, "Unable to add interface to queue '%s': No such queue\n", args.queuename); 03958 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "NOSUCHQUEUE"); 03959 res = 0; 03960 break; 03961 case RES_OUTOFMEMORY: 03962 ast_log(LOG_ERROR, "Out of memory adding member %s to queue %s\n", args.interface, args.queuename); 03963 break; 03964 } 03965 03966 ast_module_user_remove(lu); 03967 03968 return res; 03969 }
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 2754 of file app_queue.c.
References ast_channel_datastore_find(), and queue_transfer_info.
02755 { 02756 return ast_channel_datastore_find(chan, &queue_transfer_info, NULL) ? 0 : 1; 02757 }
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 2632 of file app_queue.c.
References ast_log(), ast_random(), member::calls, member::interface, member::lastcall, LOG_DEBUG, LOG_WARNING, queue_ent::max_penalty, callattempt::metric, option_debug, member::penalty, QUEUE_STRATEGY_FEWESTCALLS, QUEUE_STRATEGY_LEASTRECENT, QUEUE_STRATEGY_RANDOM, QUEUE_STRATEGY_RINGALL, QUEUE_STRATEGY_ROUNDROBIN, member::ringcount, call_queue::ringlimit, call_queue::rrpos, call_queue::strategy, and call_queue::wrapped.
Referenced by try_calling().
02633 { 02634 if (qe->max_penalty && (mem->penalty > qe->max_penalty)) 02635 return -1; 02636 02637 switch (q->strategy) { 02638 case QUEUE_STRATEGY_RINGALL: 02639 /* Everyone equal, except for penalty */ 02640 tmp->metric = mem->penalty * 1000000; 02641 break; 02642 case QUEUE_STRATEGY_ROUNDROBIN: 02643 if (!pos) { 02644 if (!q->wrapped) { 02645 /* No more channels, start over */ 02646 q->rrpos = 0; 02647 } else { 02648 /* Prioritize next entry */ 02649 q->rrpos++; 02650 } 02651 q->wrapped = 0; 02652 } 02653 /* Fall through */ 02654 case QUEUE_STRATEGY_RRMEMORY: 02655 if (pos < q->rrpos) { 02656 tmp->metric = 1000 + pos; 02657 } else { 02658 if (pos > q->rrpos) 02659 /* Indicate there is another priority */ 02660 q->wrapped = 1; 02661 tmp->metric = pos; 02662 } 02663 tmp->metric += mem->penalty * 1000000; 02664 break; 02665 case QUEUE_STRATEGY_RANDOM: 02666 tmp->metric = ast_random() % 1000; 02667 tmp->metric += mem->penalty * 1000000; 02668 break; 02669 case QUEUE_STRATEGY_FEWESTCALLS: 02670 tmp->metric = mem->calls; 02671 tmp->metric += mem->penalty * 1000000; 02672 break; 02673 case QUEUE_STRATEGY_LEASTRECENT: 02674 if (!mem->lastcall) 02675 tmp->metric = 0; 02676 else 02677 tmp->metric = 1000000 - (time(NULL) - mem->lastcall); 02678 tmp->metric += mem->penalty * 1000000; 02679 break; 02680 default: 02681 ast_log(LOG_WARNING, "Can't calculate metric for unknown strategy %d\n", q->strategy); 02682 break; 02683 } 02684 if (q->ringlimit && (mem->ringcount >= q->ringlimit)) { 02685 tmp->metric += (mem->ringcount / q->ringlimit) * 10000000; 02686 } 02687 if (option_debug) 02688 ast_log(LOG_DEBUG, "New metric %d for member %s with %d rings (limit %d)\n", 02689 tmp->metric, mem->interface, mem->ringcount, q->ringlimit); 02690 return 0; 02691 }
static void clear_and_free_interfaces | ( | void | ) | [static] |
Definition at line 994 of file app_queue.c.
References AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, free, and member_interface::list.
Referenced by unload_module().
00995 { 00996 struct member_interface *curint; 00997 00998 AST_LIST_LOCK(&interfaces); 00999 while ((curint = AST_LIST_REMOVE_HEAD(&interfaces, list))) 01000 free(curint); 01001 AST_LIST_UNLOCK(&interfaces); 01002 }
static void clear_queue | ( | struct call_queue * | q | ) | [static] |
Definition at line 906 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().
00907 { 00908 q->holdtime = 0; 00909 q->callscompleted = 0; 00910 q->callsabandoned = 0; 00911 q->callscompletedinsl = 0; 00912 q->wrapuptime = 0; 00913 }
static int cli_queue_member_count | ( | int | fd, | |
int | argc, | |||
char ** | argv | |||
) | [static] |
Definition at line 5389 of file app_queue.c.
References ast_cli(), qmc_handler(), RESULT_FAILURE, RESULT_SHOWUSAGE, and RESULT_SUCCESS.
05390 { 05391 char buffer[256] = ""; 05392 char *queuename; 05393 05394 if (argc != 4) { 05395 return RESULT_SHOWUSAGE; 05396 } 05397 queuename = argv[3]; 05398 05399 if (qmc_handler(queuename, buffer, sizeof(buffer)) == RESULT_SUCCESS) { 05400 ast_cli(fd, 05401 "Member count for queue '%s'\n" 05402 "%s\n", 05403 queuename, buffer); 05404 return RESULT_SUCCESS; 05405 } else { 05406 ast_cli(fd, "No such queue: '%s'\n", queuename); 05407 return RESULT_FAILURE; 05408 } 05409 }
static int compare_weight | ( | struct call_queue * | rq, | |
struct member * | member | |||
) | [static] |
Definition at line 1824 of file app_queue.c.
References ao2_find(), ao2_lock(), ao2_ref(), ao2_unlock(), AST_LIST_TRAVERSE, ast_log(), call_queue::count, member::interface, member_interface::list, LOG_DEBUG, call_queue::members, call_queue::name, num_available_members(), and call_queue::weight.
Referenced by ring_entry().
01825 { 01826 struct call_queue *q; 01827 struct member *mem; 01828 int found = 0; 01829 01830 /* &qlock and &rq->lock already set by try_calling() 01831 * to solve deadlock */ 01832 AST_LIST_TRAVERSE(&queues, q, list) { 01833 if (q == rq) /* don't check myself, could deadlock */ 01834 continue; 01835 ao2_lock(q); 01836 if (q->count && q->members) { 01837 if ((mem = ao2_find(q->members, member, OBJ_POINTER))) { 01838 ast_log(LOG_DEBUG, "Found matching member %s in queue '%s'\n", mem->interface, q->name); 01839 if (q->weight > rq->weight && q->count >= num_available_members(q)) { 01840 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); 01841 found = 1; 01842 } 01843 ao2_ref(mem, -1); 01844 } 01845 } 01846 ao2_unlock(q); 01847 if (found) 01848 break; 01849 } 01850 return found; 01851 }
static char* complete_queue | ( | const char * | line, | |
const char * | word, | |||
int | pos, | |||
int | state | |||
) | [static] |
Definition at line 4891 of file app_queue.c.
References AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_strdup, call_queue::list, and call_queue::name.
Referenced by complete_queue_add_member(), complete_queue_member_count(), complete_queue_remove_member(), and complete_queue_show().
04892 { 04893 struct call_queue *q; 04894 char *ret = NULL; 04895 int which = 0; 04896 int wordlen = strlen(word); 04897 04898 AST_LIST_LOCK(&queues); 04899 AST_LIST_TRAVERSE(&queues, q, list) { 04900 if (!strncasecmp(word, q->name, wordlen) && ++which > state) { 04901 ret = ast_strdup(q->name); 04902 break; 04903 } 04904 } 04905 AST_LIST_UNLOCK(&queues); 04906 04907 return ret; 04908 }
static char* complete_queue_add_member | ( | const char * | line, | |
const char * | word, | |||
int | pos, | |||
int | state | |||
) | [static] |
Definition at line 5194 of file app_queue.c.
References ast_malloc, ast_strdup, and complete_queue().
05195 { 05196 /* 0 - queue; 1 - add; 2 - member; 3 - <interface>; 4 - to; 5 - <queue>; 6 - penalty; 7 - <penalty>; 8 - as; 9 - <membername> */ 05197 switch (pos) { 05198 case 3: /* Don't attempt to complete name of interface (infinite possibilities) */ 05199 return NULL; 05200 case 4: /* only one possible match, "to" */ 05201 return state == 0 ? ast_strdup("to") : NULL; 05202 case 5: /* <queue> */ 05203 return complete_queue(line, word, pos, state); 05204 case 6: /* only one possible match, "penalty" */ 05205 return state == 0 ? ast_strdup("penalty") : NULL; 05206 case 7: 05207 if (state < 100) { /* 0-99 */ 05208 char *num; 05209 if ((num = ast_malloc(3))) { 05210 sprintf(num, "%d", state); 05211 } 05212 return num; 05213 } else { 05214 return NULL; 05215 } 05216 case 8: /* only one possible match, "as" */ 05217 return state == 0 ? ast_strdup("as") : NULL; 05218 case 9: /* Don't attempt to complete name of member (infinite possibilities) */ 05219 return NULL; 05220 case 10: 05221 return state == 0 ? ast_strdup("state_interface") : NULL; 05222 default: 05223 return NULL; 05224 } 05225 }
static char* complete_queue_member_count | ( | const char * | line, | |
const char * | word, | |||
int | pos, | |||
int | state | |||
) | [static] |
Definition at line 5416 of file app_queue.c.
References complete_queue().
05417 { 05418 /* 0 - queue; 1 - member; 2 - count; 3 - <queue> */ 05419 switch (pos) { 05420 case 3: /* <queue> */ 05421 return complete_queue(line, word, pos, state); 05422 default: 05423 return NULL; 05424 } 05425 }
static char* complete_queue_remove_member | ( | const char * | line, | |
const char * | word, | |||
int | pos, | |||
int | state | |||
) | [static] |
Definition at line 5262 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.
05263 { 05264 int which = 0; 05265 struct call_queue *q; 05266 struct member *m; 05267 struct ao2_iterator mem_iter; 05268 05269 /* 0 - queue; 1 - remove; 2 - member; 3 - <member>; 4 - from; 5 - <queue> */ 05270 if (pos > 5 || pos < 3) 05271 return NULL; 05272 if (pos == 4) /* only one possible match, 'from' */ 05273 return state == 0 ? ast_strdup("from") : NULL; 05274 05275 if (pos == 5) /* No need to duplicate code */ 05276 return complete_queue(line, word, pos, state); 05277 05278 /* here is the case for 3, <member> */ 05279 if (!AST_LIST_EMPTY(&queues)) { /* XXX unnecessary ? the traverse does that for us */ 05280 AST_LIST_TRAVERSE(&queues, q, list) { 05281 ao2_lock(q); 05282 mem_iter = ao2_iterator_init(q->members, 0); 05283 while ((m = ao2_iterator_next(&mem_iter))) { 05284 if (++which > state) { 05285 char *tmp; 05286 ao2_iterator_destroy(&mem_iter); 05287 ao2_unlock(q); 05288 tmp = ast_strdup(m->interface); 05289 ao2_ref(m, -1); 05290 return tmp; 05291 } 05292 ao2_ref(m, -1); 05293 } 05294 ao2_iterator_destroy(&mem_iter); 05295 ao2_unlock(q); 05296 } 05297 } 05298 05299 return NULL; 05300 }
static char* complete_queue_show | ( | const char * | line, | |
const char * | word, | |||
int | pos, | |||
int | state | |||
) | [static] |
Definition at line 4910 of file app_queue.c.
References complete_queue().
04911 { 04912 if (pos == 2) 04913 return complete_queue(line, word, pos, state); 04914 return NULL; 04915 }
static int compress_char | ( | const char | c | ) | [static] |
static struct member* create_queue_member | ( | const char * | interface, | |
const char * | membername, | |||
int | penalty, | |||
int | paused, | |||
const char * | state_interface | |||
) | [static] |
allocate space for new queue member and set fields based on parameters passed
Definition at line 792 of file app_queue.c.
References ao2_alloc(), ast_copy_string(), ast_device_state(), ast_log(), ast_strlen_zero(), LOG_WARNING, and member::penalty.
Referenced by add_to_queue(), reload_queues(), and rt_handle_member_record().
00793 { 00794 struct member *cur; 00795 00796 if ((cur = ao2_alloc(sizeof(*cur), NULL))) { 00797 cur->penalty = penalty; 00798 cur->paused = paused; 00799 ast_copy_string(cur->interface, interface, sizeof(cur->interface)); 00800 if (!ast_strlen_zero(state_interface)) { 00801 ast_copy_string(cur->state_interface, state_interface, sizeof(cur->state_interface)); 00802 } else { 00803 ast_copy_string(cur->state_interface, interface, sizeof(cur->state_interface)); 00804 } 00805 if (!ast_strlen_zero(membername)) 00806 ast_copy_string(cur->membername, membername, sizeof(cur->membername)); 00807 else 00808 ast_copy_string(cur->membername, interface, sizeof(cur->membername)); 00809 if (!strchr(cur->interface, '/')) 00810 ast_log(LOG_WARNING, "No location at interface '%s'\n", interface); 00811 cur->status = ast_device_state(cur->state_interface); 00812 } 00813 00814 return cur; 00815 }
static void destroy_queue | ( | void * | obj | ) | [static] |
Definition at line 534 of file app_queue.c.
References ao2_ref(), free_members(), and call_queue::members.
Referenced by alloc_queue().
00535 { 00536 struct call_queue *q = obj; 00537 if (q->members) { 00538 free_members(q, 1); 00539 ao2_ref(q->members, -1); 00540 } 00541 }
static void* device_state_thread | ( | void * | data | ) | [static] |
Consumer of the statechange queue.
Definition at line 740 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().
00741 { 00742 struct statechange *sc = NULL; 00743 00744 while (!device_state.stop) { 00745 ast_mutex_lock(&device_state.lock); 00746 if (!(sc = AST_LIST_REMOVE_HEAD(&device_state.state_change_q, entry))) { 00747 ast_cond_wait(&device_state.cond, &device_state.lock); 00748 sc = AST_LIST_REMOVE_HEAD(&device_state.state_change_q, entry); 00749 } 00750 ast_mutex_unlock(&device_state.lock); 00751 00752 /* Check to see if we were woken up to see the request to stop */ 00753 if (device_state.stop) 00754 break; 00755 00756 if (!sc) 00757 continue; 00758 00759 handle_statechange(sc); 00760 00761 free(sc); 00762 sc = NULL; 00763 } 00764 00765 if (sc) 00766 free(sc); 00767 00768 while ((sc = AST_LIST_REMOVE_HEAD(&device_state.state_change_q, entry))) 00769 free(sc); 00770 00771 return NULL; 00772 }
static void do_hang | ( | struct callattempt * | o | ) | [static] |
common hangup actions
Definition at line 1854 of file app_queue.c.
References ast_hangup(), callattempt::chan, and callattempt::stillgoing.
Referenced by ring_entry().
01855 { 01856 o->stillgoing = 0; 01857 ast_hangup(o->chan); 01858 o->chan = NULL; 01859 }
static void dump_queue_members | ( | struct call_queue * | pm_queue | ) | [static] |
Definition at line 3423 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().
03424 { 03425 struct member *cur_member; 03426 char value[PM_MAX_LEN]; 03427 int value_len = 0; 03428 int res; 03429 struct ao2_iterator mem_iter; 03430 03431 memset(value, 0, sizeof(value)); 03432 03433 if (!pm_queue) 03434 return; 03435 03436 mem_iter = ao2_iterator_init(pm_queue->members, 0); 03437 while ((cur_member = ao2_iterator_next(&mem_iter))) { 03438 if (!cur_member->dynamic) { 03439 ao2_ref(cur_member, -1); 03440 continue; 03441 } 03442 03443 res = snprintf(value + value_len, sizeof(value) - value_len, "%s%s;%d;%d;%s;%s", 03444 value_len ? "|" : "", cur_member->interface, cur_member->penalty, cur_member->paused, cur_member->membername, cur_member->state_interface); 03445 03446 ao2_ref(cur_member, -1); 03447 03448 if (res != strlen(value + value_len)) { 03449 ast_log(LOG_WARNING, "Could not create persistent member string, out of space\n"); 03450 break; 03451 } 03452 value_len += res; 03453 } 03454 ao2_iterator_destroy(&mem_iter); 03455 03456 if (value_len && !cur_member) { 03457 if (ast_db_put(pm_family, pm_queue->name, value)) 03458 ast_log(LOG_WARNING, "failed to create persistent dynamic entry!\n"); 03459 } else 03460 /* Delete the entry if the queue is empty or there is an error */ 03461 ast_db_del(pm_family, pm_queue->name); 03462 }
static struct callattempt* find_best | ( | struct callattempt * | outgoing | ) | [static] |
find the entry with the best metric, or NULL
Definition at line 2061 of file app_queue.c.
References callattempt::metric, and callattempt::q_next.
02062 { 02063 struct callattempt *best = NULL, *cur; 02064 02065 for (cur = outgoing; cur; cur = cur->q_next) { 02066 if (cur->stillgoing && /* Not already done */ 02067 !cur->chan && /* Isn't already going */ 02068 (!best || cur->metric < best->metric)) { /* We haven't found one yet, or it's better */ 02069 best = cur; 02070 } 02071 } 02072 02073 return best; 02074 }
static struct call_queue* find_queue_by_name_rt | ( | const char * | queuename, | |
struct ast_variable * | queue_vars, | |||
struct ast_config * | member_config | |||
) | [static] |
Reload a single queue via realtime.
Definition at line 1230 of file app_queue.c.
References alloc_queue(), ao2_lock(), ao2_unlock(), ast_copy_string(), AST_LIST_INSERT_HEAD, AST_LIST_TRAVERSE, ast_log(), ast_strlen_zero(), clear_queue(), init_queue(), member_interface::interface, member_interface::list, LOG_DEBUG, LOG_WARNING, ast_variable::name, call_queue::name, ast_variable::next, queue_set_param(), call_queue::realtime, remove_queue(), and ast_variable::value.
Referenced by load_realtime_queue().
01231 { 01232 struct ast_variable *v; 01233 struct call_queue *q; 01234 struct member *m; 01235 struct ao2_iterator mem_iter; 01236 char *interface = NULL; 01237 char *tmp, *tmp_name; 01238 char tmpbuf[64]; /* Must be longer than the longest queue param name. */ 01239 01240 /* Find the queue in the in-core list (we will create a new one if not found). */ 01241 AST_LIST_TRAVERSE(&queues, q, list) { 01242 if (!strcasecmp(q->name, queuename)) 01243 break; 01244 } 01245 01246 /* Static queues override realtime. */ 01247 if (q) { 01248 ao2_lock(q); 01249 if (!q->realtime) { 01250 if (q->dead) { 01251 ao2_unlock(q); 01252 return NULL; 01253 } else { 01254 ast_log(LOG_WARNING, "Static queue '%s' already exists. Not loading from realtime\n", q->name); 01255 ao2_unlock(q); 01256 return q; 01257 } 01258 } 01259 } else if (!member_config) 01260 /* Not found in the list, and it's not realtime ... */ 01261 return NULL; 01262 01263 /* Check if queue is defined in realtime. */ 01264 if (!queue_vars) { 01265 /* Delete queue from in-core list if it has been deleted in realtime. */ 01266 if (q) { 01267 /*! \note Hmm, can't seem to distinguish a DB failure from a not 01268 found condition... So we might delete an in-core queue 01269 in case of DB failure. */ 01270 ast_log(LOG_DEBUG, "Queue %s not found in realtime.\n", queuename); 01271 01272 q->dead = 1; 01273 /* Delete if unused (else will be deleted when last caller leaves). */ 01274 if (!q->count) { 01275 /* Delete. */ 01276 ao2_unlock(q); 01277 remove_queue(q); 01278 } else 01279 ao2_unlock(q); 01280 } 01281 return NULL; 01282 } 01283 01284 /* Create a new queue if an in-core entry does not exist yet. */ 01285 if (!q) { 01286 if (!(q = alloc_queue(queuename))) 01287 return NULL; 01288 ao2_lock(q); 01289 clear_queue(q); 01290 q->realtime = 1; 01291 AST_LIST_INSERT_HEAD(&queues, q, list); 01292 } 01293 init_queue(q); /* Ensure defaults for all parameters not set explicitly. */ 01294 01295 memset(tmpbuf, 0, sizeof(tmpbuf)); 01296 for (v = queue_vars; v; v = v->next) { 01297 /* Convert to dashes `-' from underscores `_' as the latter are more SQL friendly. */ 01298 if ((tmp = strchr(v->name, '_'))) { 01299 ast_copy_string(tmpbuf, v->name, sizeof(tmpbuf)); 01300 tmp_name = tmpbuf; 01301 tmp = tmp_name; 01302 while ((tmp = strchr(tmp, '_'))) 01303 *tmp++ = '-'; 01304 } else 01305 tmp_name = v->name; 01306 01307 if (!ast_strlen_zero(v->value)) { 01308 /* Don't want to try to set the option if the value is empty */ 01309 queue_set_param(q, tmp_name, v->value, -1, 0); 01310 } 01311 } 01312 01313 if (q->strategy == QUEUE_STRATEGY_ROUNDROBIN) 01314 rr_dep_warning(); 01315 01316 /* Temporarily set realtime members dead so we can detect deleted ones. 01317 * Also set the membercount correctly for realtime*/ 01318 mem_iter = ao2_iterator_init(q->members, 0); 01319 while ((m = ao2_iterator_next(&mem_iter))) { 01320 q->membercount++; 01321 if (m->realtime) 01322 m->dead = 1; 01323 ao2_ref(m, -1); 01324 } 01325 ao2_iterator_destroy(&mem_iter); 01326 01327 while ((interface = ast_category_browse(member_config, interface))) { 01328 rt_handle_member_record(q, interface, 01329 ast_variable_retrieve(member_config, interface, "membername"), 01330 ast_variable_retrieve(member_config, interface, "penalty"), 01331 ast_variable_retrieve(member_config, interface, "paused"), 01332 S_OR(ast_variable_retrieve(member_config, interface, "state_interface"),interface)); 01333 } 01334 01335 /* Delete all realtime members that have been deleted in DB. */ 01336 mem_iter = ao2_iterator_init(q->members, 0); 01337 while ((m = ao2_iterator_next(&mem_iter))) { 01338 if (m->dead) { 01339 ao2_unlink(q->members, m); 01340 ao2_unlock(q); 01341 remove_from_interfaces(m->state_interface); 01342 ao2_lock(q); 01343 q->membercount--; 01344 } 01345 ao2_ref(m, -1); 01346 } 01347 ao2_iterator_destroy(&mem_iter); 01348 01349 ao2_unlock(q); 01350 01351 return q; 01352 }
static void free_members | ( | struct call_queue * | q, | |
int | all | |||
) | [static] |
Definition at line 1210 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().
01211 { 01212 /* Free non-dynamic members */ 01213 struct member *cur; 01214 struct ao2_iterator mem_iter = ao2_iterator_init(q->members, 0); 01215 01216 while ((cur = ao2_iterator_next(&mem_iter))) { 01217 if (all || !cur->dynamic) { 01218 ao2_unlink(q->members, cur); 01219 remove_from_interfaces(cur->state_interface); 01220 q->membercount--; 01221 } 01222 ao2_ref(cur, -1); 01223 } 01224 ao2_iterator_destroy(&mem_iter); 01225 }
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 580 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().
00581 { 00582 struct member *member; 00583 struct ao2_iterator mem_iter; 00584 enum queue_member_status result = QUEUE_NO_MEMBERS; 00585 00586 ao2_lock(q); 00587 mem_iter = ao2_iterator_init(q->members, 0); 00588 while ((member = ao2_iterator_next(&mem_iter))) { 00589 if (max_penalty && (member->penalty > max_penalty)) { 00590 ao2_ref(member, -1); 00591 continue; 00592 } 00593 00594 if (member->paused) { 00595 ao2_ref(member, -1); 00596 continue; 00597 } 00598 00599 switch (member->status) { 00600 case AST_DEVICE_INVALID: 00601 /* nothing to do */ 00602 ao2_ref(member, -1); 00603 break; 00604 case AST_DEVICE_UNAVAILABLE: 00605 result = QUEUE_NO_REACHABLE_MEMBERS; 00606 ao2_ref(member, -1); 00607 break; 00608 default: 00609 ao2_unlock(q); 00610 ao2_ref(member, -1); 00611 return QUEUE_NORMAL; 00612 } 00613 } 00614 ao2_iterator_destroy(&mem_iter); 00615 ao2_unlock(q); 00616 return result; 00617 }
static int handle_queue_add_member | ( | int | fd, | |
int | argc, | |||
char * | argv[] | |||
) | [static] |
Definition at line 5134 of file app_queue.c.
References add_to_queue(), ast_cli(), ast_queue_log(), RES_EXISTS, RES_NOSUCHQUEUE, RES_OKAY, RES_OUTOFMEMORY, RESULT_FAILURE, RESULT_SHOWUSAGE, and RESULT_SUCCESS.
05135 { 05136 char *queuename, *interface, *membername = NULL, *state_interface = NULL; 05137 int penalty; 05138 05139 if ((argc != 6) && (argc != 8) && (argc != 10) && (argc != 12)) { 05140 return RESULT_SHOWUSAGE; 05141 } else if (strcmp(argv[4], "to")) { 05142 return RESULT_SHOWUSAGE; 05143 } else if ((argc == 8) && strcmp(argv[6], "penalty")) { 05144 return RESULT_SHOWUSAGE; 05145 } else if ((argc == 10) && strcmp(argv[8], "as")) { 05146 return RESULT_SHOWUSAGE; 05147 } else if ((argc == 12) && strcmp(argv[10], "state_interface")) { 05148 return RESULT_SHOWUSAGE; 05149 } 05150 05151 queuename = argv[5]; 05152 interface = argv[3]; 05153 if (argc >= 8) { 05154 if (sscanf(argv[7], "%30d", &penalty) == 1) { 05155 if (penalty < 0) { 05156 ast_cli(fd, "Penalty must be >= 0\n"); 05157 penalty = 0; 05158 } 05159 } else { 05160 ast_cli(fd, "Penalty must be an integer >= 0\n"); 05161 penalty = 0; 05162 } 05163 } else { 05164 penalty = 0; 05165 } 05166 05167 if (argc >= 10) { 05168 membername = argv[9]; 05169 } 05170 05171 if (argc >= 12) { 05172 state_interface = argv[11]; 05173 } 05174 05175 switch (add_to_queue(queuename, interface, membername, penalty, 0, queue_persistent_members, state_interface)) { 05176 case RES_OKAY: 05177 ast_queue_log(queuename, "CLI", interface, "ADDMEMBER", "%s", ""); 05178 ast_cli(fd, "Added interface '%s' to queue '%s'\n", interface, queuename); 05179 return RESULT_SUCCESS; 05180 case RES_EXISTS: 05181 ast_cli(fd, "Unable to add interface '%s' to queue '%s': Already there\n", interface, queuename); 05182 return RESULT_FAILURE; 05183 case RES_NOSUCHQUEUE: 05184 ast_cli(fd, "Unable to add interface to queue '%s': No such queue\n", queuename); 05185 return RESULT_FAILURE; 05186 case RES_OUTOFMEMORY: 05187 ast_cli(fd, "Out of memory\n"); 05188 return RESULT_FAILURE; 05189 default: 05190 return RESULT_FAILURE; 05191 } 05192 }
static int handle_queue_remove_member | ( | int | fd, | |
int | argc, | |||
char * | argv[] | |||
) | [static] |
Definition at line 5227 of file app_queue.c.
References ast_cli(), ast_queue_log(), remove_from_queue(), RES_EXISTS, RES_NOSUCHQUEUE, RES_NOT_DYNAMIC, RES_OKAY, RES_OUTOFMEMORY, RESULT_FAILURE, RESULT_SHOWUSAGE, and RESULT_SUCCESS.
05228 { 05229 char *queuename, *interface; 05230 05231 if (argc != 6) { 05232 return RESULT_SHOWUSAGE; 05233 } else if (strcmp(argv[4], "from")) { 05234 return RESULT_SHOWUSAGE; 05235 } 05236 05237 queuename = argv[5]; 05238 interface = argv[3]; 05239 05240 switch (remove_from_queue(queuename, interface)) { 05241 case RES_OKAY: 05242 ast_queue_log(queuename, "CLI", interface, "REMOVEMEMBER", "%s", ""); 05243 ast_cli(fd, "Removed interface '%s' from queue '%s'\n", interface, queuename); 05244 return RESULT_SUCCESS; 05245 case RES_EXISTS: 05246 ast_cli(fd, "Unable to remove interface '%s' from queue '%s': Not there\n", interface, queuename); 05247 return RESULT_FAILURE; 05248 case RES_NOSUCHQUEUE: 05249 ast_cli(fd, "Unable to remove interface from queue '%s': No such queue\n", queuename); 05250 return RESULT_FAILURE; 05251 case RES_OUTOFMEMORY: 05252 ast_cli(fd, "Out of memory\n"); 05253 return RESULT_FAILURE; 05254 case RES_NOT_DYNAMIC: 05255 ast_cli(fd, "Member not dynamic\n"); 05256 return RESULT_FAILURE; 05257 default: 05258 return RESULT_FAILURE; 05259 } 05260 }
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 679 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, member_interface::list, LOG_DEBUG, option_debug, statechange::state, and update_status().
Referenced by device_state_thread().
00680 { 00681 struct member_interface *curint; 00682 char *loc; 00683 char *technology; 00684 char interface[80]; 00685 00686 technology = ast_strdupa(sc->dev); 00687 loc = strchr(technology, '/'); 00688 if (loc) { 00689 *loc++ = '\0'; 00690 } else { 00691 return NULL; 00692 } 00693 00694 AST_LIST_LOCK(&interfaces); 00695 AST_LIST_TRAVERSE(&interfaces, curint, list) { 00696 char *slash_pos; 00697 ast_copy_string(interface, curint->interface, sizeof(interface)); 00698 if ((slash_pos = strchr(interface, '/'))) 00699 if ((slash_pos = strchr(slash_pos + 1, '/'))) 00700 *slash_pos = '\0'; 00701 00702 if (!strcasecmp(interface, sc->dev)) 00703 break; 00704 } 00705 AST_LIST_UNLOCK(&interfaces); 00706 00707 if (!curint) { 00708 if (option_debug > 2) 00709 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)); 00710 return NULL; 00711 } 00712 00713 if (option_debug) 00714 ast_log(LOG_DEBUG, "Device '%s/%s' changed to state '%d' (%s)\n", technology, loc, sc->state, devstate2str(sc->state)); 00715 00716 update_status(sc->dev, sc->state); 00717 00718 return NULL; 00719 }
static void hangupcalls | ( | struct callattempt * | outgoing, | |
struct ast_channel * | exception | |||
) | [static] |
Definition at line 1757 of file app_queue.c.
References ao2_ref(), ast_hangup(), callattempt::chan, free, callattempt::member, and callattempt::q_next.
01758 { 01759 struct callattempt *oo; 01760 01761 while (outgoing) { 01762 /* Hangup any existing lines we have open */ 01763 if (outgoing->chan && (outgoing->chan != exception)) 01764 ast_hangup(outgoing->chan); 01765 oo = outgoing; 01766 outgoing = outgoing->q_next; 01767 if (oo->member) 01768 ao2_ref(oo->member, -1); 01769 free(oo); 01770 } 01771 }
static void init_queue | ( | struct call_queue * | q | ) | [static] |
Definition at line 855 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, 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_lessthan, call_queue::sound_minutes, call_queue::sound_next, call_queue::sound_periodicannounce, call_queue::sound_reporthold, call_queue::sound_seconds, call_queue::sound_thanks, call_queue::sound_thereare, call_queue::timeout, call_queue::timeoutrestart, call_queue::weight, and call_queue::wrapuptime.
Referenced by find_queue_by_name_rt(), and reload_queues().
00856 { 00857 int i; 00858 00859 q->dead = 0; 00860 q->retry = DEFAULT_RETRY; 00861 q->timeout = -1; 00862 q->maxlen = 0; 00863 q->ringlimit = 0; 00864 q->announcefrequency = 0; 00865 q->announceholdtime = 0; 00866 q->roundingseconds = 0; /* Default - don't announce seconds */ 00867 q->servicelevel = 0; 00868 q->ringinuse = 1; 00869 q->setinterfacevar = 0; 00870 q->autofill = autofill_default; 00871 q->montype = montype_default; 00872 q->moh[0] = '\0'; 00873 q->announce[0] = '\0'; 00874 q->context[0] = '\0'; 00875 q->monfmt[0] = '\0'; 00876 q->periodicannouncefrequency = 0; 00877 q->reportholdtime = 0; 00878 q->monjoin = 0; 00879 q->wrapuptime = 0; 00880 q->joinempty = 0; 00881 q->leavewhenempty = 0; 00882 q->memberdelay = 0; 00883 q->maskmemberstatus = 0; 00884 q->eventwhencalled = 0; 00885 q->weight = 0; 00886 q->timeoutrestart = 0; 00887 if (!q->members) 00888 q->members = ao2_container_alloc(37, member_hash_fn, member_cmp_fn); 00889 q->membercount = 0; 00890 q->found = 1; 00891 ast_copy_string(q->sound_next, "queue-youarenext", sizeof(q->sound_next)); 00892 ast_copy_string(q->sound_thereare, "queue-thereare", sizeof(q->sound_thereare)); 00893 ast_copy_string(q->sound_calls, "queue-callswaiting", sizeof(q->sound_calls)); 00894 ast_copy_string(q->sound_holdtime, "queue-holdtime", sizeof(q->sound_holdtime)); 00895 ast_copy_string(q->sound_minutes, "queue-minutes", sizeof(q->sound_minutes)); 00896 ast_copy_string(q->sound_seconds, "queue-seconds", sizeof(q->sound_seconds)); 00897 ast_copy_string(q->sound_thanks, "queue-thankyou", sizeof(q->sound_thanks)); 00898 ast_copy_string(q->sound_lessthan, "queue-less-than", sizeof(q->sound_lessthan)); 00899 ast_copy_string(q->sound_reporthold, "queue-reporthold", sizeof(q->sound_reporthold)); 00900 ast_copy_string(q->sound_periodicannounce[0], "queue-periodic-announce", sizeof(q->sound_periodicannounce[0])); 00901 for (i = 1; i < MAX_PERIODIC_ANNOUNCEMENTS; i++) { 00902 q->sound_periodicannounce[i][0]='\0'; 00903 } 00904 }
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 544 of file app_queue.c.
References ao2_ref(), call_queue::head, and queue_ent::next.
Referenced by join_queue().
00545 { 00546 struct queue_ent *cur; 00547 00548 if (!q || !new) 00549 return; 00550 if (prev) { 00551 cur = prev->next; 00552 prev->next = new; 00553 } else { 00554 cur = q->head; 00555 q->head = new; 00556 } 00557 new->next = cur; 00558 00559 /* every queue_ent must have a reference to it's parent call_queue, this 00560 * reference does not go away until the end of the queue_ent's life, meaning 00561 * that even when the queue_ent leaves the call_queue this ref must remain. */ 00562 ao2_ref(q, +1); 00563 new->parent = q; 00564 new->pos = ++(*pos); 00565 new->opos = *pos; 00566 }
static char* int2strat | ( | int | strategy | ) | [static] |
Definition at line 498 of file app_queue.c.
References name, and strategies.
Referenced by __queues_show().
00499 { 00500 int x; 00501 00502 for (x = 0; x < sizeof(strategies) / sizeof(strategies[0]); x++) { 00503 if (strategy == strategies[x].strategy) 00504 return strategies[x].name; 00505 } 00506 00507 return "<unknown>"; 00508 }
static struct member* interface_exists | ( | struct call_queue * | q, | |
const char * | interface | |||
) | [static] |
Definition at line 3396 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().
03397 { 03398 struct member *mem; 03399 struct ao2_iterator mem_iter; 03400 03401 if (!q) 03402 return NULL; 03403 03404 mem_iter = ao2_iterator_init(q->members, 0); 03405 while ((mem = ao2_iterator_next(&mem_iter))) { 03406 if (!strcasecmp(interface, mem->interface)) { 03407 ao2_iterator_destroy(&mem_iter); 03408 return mem; 03409 } 03410 ao2_ref(mem, -1); 03411 } 03412 ao2_iterator_destroy(&mem_iter); 03413 03414 return NULL; 03415 }
static int interface_exists_global | ( | const char * | interface | ) | [static] |
Definition at line 942 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, member_interface::list, call_queue::members, and member::state_interface.
Referenced by remove_from_interfaces().
00943 { 00944 struct call_queue *q; 00945 struct member *mem; 00946 struct ao2_iterator mem_iter; 00947 int ret = 0; 00948 00949 AST_LIST_LOCK(&queues); 00950 AST_LIST_TRAVERSE(&queues, q, list) { 00951 ao2_lock(q); 00952 mem_iter = ao2_iterator_init(q->members, 0); 00953 while ((mem = ao2_iterator_next(&mem_iter))) { 00954 if (!strcasecmp(mem->state_interface, interface)) { 00955 ao2_ref(mem, -1); 00956 ret = 1; 00957 break; 00958 } 00959 ao2_ref(mem, -1); 00960 } 00961 ao2_iterator_destroy(&mem_iter); 00962 ao2_unlock(q); 00963 if (ret) 00964 break; 00965 } 00966 AST_LIST_UNLOCK(&queues); 00967 00968 return ret; 00969 }
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 2491 of file app_queue.c.
References ao2_lock(), ao2_unlock(), ast_log(), queue_ent::chan, call_queue::head, LOG_DEBUG, ast_channel::name, queue_ent::next, num_available_members(), option_debug, queue_ent::parent, and queue_ent::pending.
Referenced by queue_exec(), and wait_our_turn().
02492 { 02493 struct queue_ent *ch; 02494 int res; 02495 int avl; 02496 int idx = 0; 02497 /* This needs a lock. How many members are available to be served? */ 02498 ao2_lock(qe->parent); 02499 02500 avl = num_available_members(qe->parent); 02501 02502 ch = qe->parent->head; 02503 02504 if (option_debug) { 02505 ast_log(LOG_DEBUG, "There %s %d available %s.\n", avl != 1 ? "are" : "is", avl, avl != 1 ? "members" : "member"); 02506 } 02507 02508 while ((idx < avl) && (ch) && (ch != qe)) { 02509 if (!ch->pending) 02510 idx++; 02511 ch = ch->next; 02512 } 02513 02514 ao2_unlock(qe->parent); 02515 02516 /* If the queue entry is within avl [the number of available members] calls from the top ... */ 02517 if (ch && idx < avl) { 02518 if (option_debug) 02519 ast_log(LOG_DEBUG, "It's our turn (%s).\n", qe->chan->name); 02520 res = 1; 02521 } else { 02522 if (option_debug) 02523 ast_log(LOG_DEBUG, "It's not our turn (%s).\n", qe->chan->name); 02524 res = 0; 02525 } 02526 02527 return res; 02528 }
static int join_queue | ( | char * | queuename, | |
struct queue_ent * | qe, | |||
enum queue_result * | reason | |||
) | [static] |
Definition at line 1475 of file app_queue.c.
References 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, 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, queue_ent::moh, ast_channel::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, S_OR, and ast_channel::uniqueid.
Referenced by queue_exec().
01476 { 01477 struct call_queue *q; 01478 struct queue_ent *cur, *prev = NULL; 01479 int res = -1; 01480 int pos = 0; 01481 int inserted = 0; 01482 enum queue_member_status stat; 01483 01484 if (!(q = load_realtime_queue(queuename))) 01485 return res; 01486 01487 AST_LIST_LOCK(&queues); 01488 ao2_lock(q); 01489 01490 /* This is our one */ 01491 stat = get_member_status(q, qe->max_penalty); 01492 if (!q->joinempty && (stat == QUEUE_NO_MEMBERS)) 01493 *reason = QUEUE_JOINEMPTY; 01494 else if ((q->joinempty == QUEUE_EMPTY_STRICT) && (stat == QUEUE_NO_REACHABLE_MEMBERS || stat == QUEUE_NO_MEMBERS)) 01495 *reason = QUEUE_JOINUNAVAIL; 01496 else if (q->maxlen && (q->count >= q->maxlen)) 01497 *reason = QUEUE_FULL; 01498 else { 01499 /* There's space for us, put us at the right position inside 01500 * the queue. 01501 * Take into account the priority of the calling user */ 01502 inserted = 0; 01503 prev = NULL; 01504 cur = q->head; 01505 while (cur) { 01506 /* We have higher priority than the current user, enter 01507 * before him, after all the other users with priority 01508 * higher or equal to our priority. */ 01509 if ((!inserted) && (qe->prio > cur->prio)) { 01510 insert_entry(q, prev, qe, &pos); 01511 inserted = 1; 01512 } 01513 cur->pos = ++pos; 01514 prev = cur; 01515 cur = cur->next; 01516 } 01517 /* No luck, join at the end of the queue */ 01518 if (!inserted) 01519 insert_entry(q, prev, qe, &pos); 01520 ast_copy_string(qe->moh, q->moh, sizeof(qe->moh)); 01521 ast_copy_string(qe->announce, q->announce, sizeof(qe->announce)); 01522 ast_copy_string(qe->context, q->context, sizeof(qe->context)); 01523 q->count++; 01524 res = 0; 01525 manager_event(EVENT_FLAG_CALL, "Join", 01526 "Channel: %s\r\nCallerID: %s\r\nCallerIDName: %s\r\nQueue: %s\r\nPosition: %d\r\nCount: %d\r\nUniqueid: %s\r\n", 01527 qe->chan->name, 01528 S_OR(qe->chan->cid.cid_num, "unknown"), /* XXX somewhere else it is <unknown> */ 01529 S_OR(qe->chan->cid.cid_name, "unknown"), 01530 q->name, qe->pos, q->count, qe->chan->uniqueid ); 01531 if (option_debug) 01532 ast_log(LOG_DEBUG, "Queue '%s' Join, Channel '%s', Position '%d'\n", q->name, qe->chan->name, qe->pos ); 01533 } 01534 ao2_unlock(q); 01535 AST_LIST_UNLOCK(&queues); 01536 01537 return res; 01538 }
static void leave_queue | ( | struct queue_ent * | qe | ) | [static] |
Definition at line 1716 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, ast_channel::name, queue_ent::next, option_debug, queue_ent::parent, queue_ent::pos, remove_queue(), and ast_channel::uniqueid.
Referenced by queue_exec(), and wait_our_turn().
01717 { 01718 struct call_queue *q; 01719 struct queue_ent *cur, *prev = NULL; 01720 int pos = 0; 01721 01722 if (!(q = qe->parent)) 01723 return; 01724 ao2_lock(q); 01725 01726 prev = NULL; 01727 for (cur = q->head; cur; cur = cur->next) { 01728 if (cur == qe) { 01729 q->count--; 01730 01731 /* Take us out of the queue */ 01732 manager_event(EVENT_FLAG_CALL, "Leave", 01733 "Channel: %s\r\nQueue: %s\r\nCount: %d\r\nUniqueid: %s\r\n", 01734 qe->chan->name, q->name, q->count, qe->chan->uniqueid); 01735 if (option_debug) 01736 ast_log(LOG_DEBUG, "Queue '%s' Leave, Channel '%s'\n", q->name, qe->chan->name ); 01737 /* Take us out of the queue */ 01738 if (prev) 01739 prev->next = cur->next; 01740 else 01741 q->head = cur->next; 01742 } else { 01743 /* Renumber the people after us in the queue based on a new count */ 01744 cur->pos = ++pos; 01745 prev = cur; 01746 } 01747 } 01748 ao2_unlock(q); 01749 01750 if (q->dead && !q->count) { 01751 /* It's dead and nobody is in it, so kill it */ 01752 remove_queue(q); 01753 } 01754 }
static int load_module | ( | void | ) | [static] |
Definition at line 5516 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, queuemembercount_function, queuememberlist_function, queuewaitingcount_function, reload_queue_members(), reload_queues(), rqm_exec(), statechange_queue(), and upqm_exec().
05517 { 05518 int res; 05519 05520 if (!reload_queues()) 05521 return AST_MODULE_LOAD_DECLINE; 05522 05523 if (queue_persistent_members) 05524 reload_queue_members(); 05525 05526 ast_mutex_init(&device_state.lock); 05527 ast_cond_init(&device_state.cond, NULL); 05528 ast_pthread_create(&device_state.thread, NULL, device_state_thread, NULL); 05529 05530 ast_cli_register_multiple(cli_queue, sizeof(cli_queue) / sizeof(struct ast_cli_entry)); 05531 res = ast_register_application(app, queue_exec, synopsis, descrip); 05532 res |= ast_register_application(app_aqm, aqm_exec, app_aqm_synopsis, app_aqm_descrip); 05533 res |= ast_register_application(app_rqm, rqm_exec, app_rqm_synopsis, app_rqm_descrip); 05534 res |= ast_register_application(app_pqm, pqm_exec, app_pqm_synopsis, app_pqm_descrip); 05535 res |= ast_register_application(app_upqm, upqm_exec, app_upqm_synopsis, app_upqm_descrip); 05536 res |= ast_register_application(app_ql, ql_exec, app_ql_synopsis, app_ql_descrip); 05537 res |= ast_manager_register("Queues", 0, manager_queues_show, "Queues"); 05538 res |= ast_manager_register("QueueStatus", 0, manager_queues_status, "Queue Status"); 05539 res |= ast_manager_register("QueueMemberCount", 0, manager_queue_member_count, "Queue Member Count"); 05540 res |= ast_manager_register("QueueAdd", EVENT_FLAG_AGENT, manager_add_queue_member, "Add interface to queue."); 05541 res |= ast_manager_register("QueueRemove", EVENT_FLAG_AGENT, manager_remove_queue_member, "Remove interface from queue."); 05542 res |= ast_manager_register("QueuePause", EVENT_FLAG_AGENT, manager_pause_queue_member, "Makes a queue member temporarily unavailable"); 05543 res |= ast_custom_function_register(&queueagentcount_function); 05544 res |= ast_custom_function_register(&queuemembercount_function); 05545 res |= ast_custom_function_register(&queuememberlist_function); 05546 res |= ast_custom_function_register(&queuewaitingcount_function); 05547 res |= ast_devstate_add(statechange_queue, NULL); 05548 05549 return res; 05550 }
static struct call_queue* load_realtime_queue | ( | const char * | queuename | ) | [static] |
Definition at line 1425 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(), member_interface::list, LOG_ERROR, call_queue::name, call_queue::realtime, and update_realtime_members().
Referenced by __queues_show(), add_to_queue(), join_queue(), queue_function_queuemembercount(), queue_member_count(), and reload_queue_members().
01426 { 01427 struct ast_variable *queue_vars; 01428 struct ast_config *member_config = NULL; 01429 struct call_queue *q; 01430 01431 /* Find the queue in the in-core list first. */ 01432 AST_LIST_LOCK(&queues); 01433 AST_LIST_TRAVERSE(&queues, q, list) { 01434 if (!strcasecmp(q->name, queuename)) { 01435 break; 01436 } 01437 } 01438 AST_LIST_UNLOCK(&queues); 01439 01440 if (!q || q->realtime) { 01441 /*! \note Load from realtime before taking the global qlock, to avoid blocking all 01442 queue operations while waiting for the DB. 01443 01444 This will be two separate database transactions, so we might 01445 see queue parameters as they were before another process 01446 changed the queue and member list as it was after the change. 01447 Thus we might see an empty member list when a queue is 01448 deleted. In practise, this is unlikely to cause a problem. */ 01449 01450 queue_vars = ast_load_realtime("queues", "name", queuename, NULL); 01451 if (queue_vars) { 01452 member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name", queuename, NULL); 01453 if (!member_config) { 01454 ast_log(LOG_ERROR, "no queue_members defined in your config (extconfig.conf).\n"); 01455 ast_variables_destroy(queue_vars); 01456 return NULL; 01457 } 01458 } 01459 01460 AST_LIST_LOCK(&queues); 01461 01462 q = find_queue_by_name_rt(queuename, queue_vars, member_config); 01463 if (member_config) 01464 ast_config_destroy(member_config); 01465 if (queue_vars) 01466 ast_variables_destroy(queue_vars); 01467 01468 AST_LIST_UNLOCK(&queues); 01469 } else { 01470 update_realtime_members(q); 01471 } 01472 return q; 01473 }
static int manager_add_queue_member | ( | struct mansession * | s, | |
const struct message * | m | |||
) | [static] |
Definition at line 5026 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(), RES_EXISTS, RES_NOSUCHQUEUE, RES_OKAY, RES_OUTOFMEMORY, and s.
Referenced by load_module().
05027 { 05028 const char *queuename, *interface, *penalty_s, *paused_s, *membername, *state_interface; 05029 int paused, penalty = 0; 05030 05031 queuename = astman_get_header(m, "Queue"); 05032 interface = astman_get_header(m, "Interface"); 05033 penalty_s = astman_get_header(m, "Penalty"); 05034 paused_s = astman_get_header(m, "Paused"); 05035 membername = astman_get_header(m, "MemberName"); 05036 state_interface = astman_get_header(m, "StateInterface"); 05037 05038 if (ast_strlen_zero(queuename)) { 05039 astman_send_error(s, m, "'Queue' not specified."); 05040 return 0; 05041 } 05042 05043 if (ast_strlen_zero(interface)) { 05044 astman_send_error(s, m, "'Interface' not specified."); 05045 return 0; 05046 } 05047 05048 if (ast_strlen_zero(penalty_s)) 05049 penalty = 0; 05050 else if (sscanf(penalty_s, "%30d", &penalty) != 1 || penalty < 0) 05051 penalty = 0; 05052 05053 if (ast_strlen_zero(paused_s)) 05054 paused = 0; 05055 else 05056 paused = abs(ast_true(paused_s)); 05057 05058 switch (add_to_queue(queuename, interface, membername, penalty, paused, queue_persistent_members, state_interface)) { 05059 case RES_OKAY: 05060 ast_queue_log(queuename, "MANAGER", interface, "ADDMEMBER", "%s", ""); 05061 astman_send_ack(s, m, "Added interface to queue"); 05062 break; 05063 case RES_EXISTS: 05064 astman_send_error(s, m, "Unable to add interface: Already there"); 05065 break; 05066 case RES_NOSUCHQUEUE: 05067 astman_send_error(s, m, "Unable to add interface to queue: No such queue"); 05068 break; 05069 case RES_OUTOFMEMORY: 05070 astman_send_error(s, m, "Out of memory"); 05071 break; 05072 } 05073 05074 return 0; 05075 }
static int manager_pause_queue_member | ( | struct mansession * | s, | |
const struct message * | m | |||
) | [static] |
Definition at line 5111 of file app_queue.c.
References ast_strlen_zero(), ast_true(), astman_get_header(), astman_send_ack(), astman_send_error(), s, and set_member_paused().
Referenced by load_module().
05112 { 05113 const char *queuename, *interface, *paused_s; 05114 int paused; 05115 05116 interface = astman_get_header(m, "Interface"); 05117 paused_s = astman_get_header(m, "Paused"); 05118 queuename = astman_get_header(m, "Queue"); /* Optional - if not supplied, pause the given Interface in all queues */ 05119 05120 if (ast_strlen_zero(interface) || ast_strlen_zero(paused_s)) { 05121 astman_send_error(s, m, "Need 'Interface' and 'Paused' parameters."); 05122 return 0; 05123 } 05124 05125 paused = abs(ast_true(paused_s)); 05126 05127 if (set_member_paused(queuename, interface, paused)) 05128 astman_send_error(s, m, "Interface not found"); 05129 else 05130 astman_send_ack(s, m, paused ? "Interface paused successfully" : "Interface unpaused successfully"); 05131 return 0; 05132 }
static int manager_queue_member_count | ( | struct mansession * | s, | |
const struct message * | m | |||
) | [static] |
Definition at line 5371 of file app_queue.c.
References ast_strlen_zero(), astman_get_header(), astman_send_ack(), astman_send_error(), qmc_handler(), RESULT_SUCCESS, and s.
Referenced by load_module().
05372 { 05373 char buffer[256] = ""; 05374 const char *queuename = astman_get_header(m,"Queue"); 05375 05376 if (ast_strlen_zero(queuename)) { 05377 astman_send_error(s, m, "'Queue' not specified."); 05378 return 0; 05379 } 05380 if (qmc_handler(queuename, buffer, sizeof(buffer)) == RESULT_SUCCESS) { 05381 astman_send_ack(s, m, buffer); 05382 return RESULT_SUCCESS; 05383 } else { 05384 astman_send_error(s, m, "Queue not found."); 05385 return 0; 05386 } 05387 }
static int manager_queues_show | ( | struct mansession * | s, | |
const struct message * | m | |||
) | [static] |
Definition at line 4920 of file app_queue.c.
References __queues_show(), astman_append(), RESULT_SUCCESS, and s.
Referenced by load_module().
04921 { 04922 char *a[] = { "queue", "show" }; 04923 04924 __queues_show(s, 1, -1, 2, a); 04925 astman_append(s, "\r\n\r\n"); /* Properly terminate Manager output */ 04926 04927 return RESULT_SUCCESS; 04928 }
static int manager_queues_status | ( | struct mansession * | s, | |
const struct message * | m | |||
) | [static] |
Definition at line 4931 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, ast_channel::name, call_queue::name, queue_ent::next, member::paused, member::penalty, RESULT_SUCCESS, call_queue::ringlimit, s, S_OR, call_queue::servicelevel, queue_ent::start, member::status, and call_queue::weight.
Referenced by load_module().
04932 { 04933 time_t now; 04934 int pos; 04935 const char *id = astman_get_header(m,"ActionID"); 04936 const char *queuefilter = astman_get_header(m,"Queue"); 04937 const char *memberfilter = astman_get_header(m,"Member"); 04938 char idText[256] = ""; 04939 struct call_queue *q; 04940 struct queue_ent *qe; 04941 float sl = 0; 04942 struct member *mem; 04943 struct ao2_iterator mem_iter; 04944 04945 astman_send_ack(s, m, "Queue status will follow"); 04946 time(&now); 04947 AST_LIST_LOCK(&queues); 04948 if (!ast_strlen_zero(id)) 04949 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id); 04950 04951 AST_LIST_TRAVERSE(&queues, q, list) { 04952 ao2_lock(q); 04953 04954 /* List queue properties */ 04955 if (ast_strlen_zero(queuefilter) || !strcmp(q->name, queuefilter)) { 04956 sl = ((q->callscompleted > 0) ? 100 * ((float)q->callscompletedinsl / (float)q->callscompleted) : 0); 04957 astman_append(s, "Event: QueueParams\r\n" 04958 "Queue: %s\r\n" 04959 "Max: %d\r\n" 04960 "Calls: %d\r\n" 04961 "Holdtime: %d\r\n" 04962 "Completed: %d\r\n" 04963 "Abandoned: %d\r\n" 04964 "ServiceLevel: %d\r\n" 04965 "ServicelevelPerf: %2.1f\r\n" 04966 "RingLimit: %d\r\n" 04967 "Weight: %d\r\n" 04968 "%s" 04969 "\r\n", 04970 q->name, q->maxlen, q->count, q->holdtime, q->callscompleted, 04971 q->callsabandoned, q->servicelevel, sl, q->ringlimit, q->weight, idText); 04972 /* List Queue Members */ 04973 mem_iter = ao2_iterator_init(q->members, 0); 04974 while ((mem = ao2_iterator_next(&mem_iter))) { 04975 if (ast_strlen_zero(memberfilter) || !strcmp(mem->interface, memberfilter)) { 04976 astman_append(s, "Event: QueueMember\r\n" 04977 "Queue: %s\r\n" 04978 "Name: %s\r\n" 04979 "Location: %s\r\n" 04980 "Membership: %s\r\n" 04981 "Penalty: %d\r\n" 04982 "CallsTaken: %d\r\n" 04983 "LastCall: %d\r\n" 04984 "Status: %d\r\n" 04985 "Paused: %d\r\n" 04986 "%s" 04987 "\r\n", 04988 q->name, mem->membername, mem->interface, mem->dynamic ? "dynamic" : "static", 04989 mem->penalty, mem->calls, (int)mem->lastcall, mem->status, mem->paused, idText); 04990 } 04991 ao2_ref(mem, -1); 04992 } 04993 ao2_iterator_destroy(&mem_iter); 04994 /* List Queue Entries */ 04995 pos = 1; 04996 for (qe = q->head; qe; qe = qe->next) { 04997 astman_append(s, "Event: QueueEntry\r\n" 04998 "Queue: %s\r\n" 04999 "Position: %d\r\n" 05000 "Channel: %s\r\n" 05001 "CallerID: %s\r\n" 05002 "CallerIDName: %s\r\n" 05003 "Wait: %ld\r\n" 05004 "%s" 05005 "\r\n", 05006 q->name, pos++, qe->chan->name, 05007 S_OR(qe->chan->cid.cid_num, "unknown"), 05008 S_OR(qe->chan->cid.cid_name, "unknown"), 05009 (long) (now - qe->start), idText); 05010 } 05011 } 05012 ao2_unlock(q); 05013 } 05014 05015 astman_append(s, 05016 "Event: QueueStatusComplete\r\n" 05017 "%s" 05018 "\r\n",idText); 05019 05020 AST_LIST_UNLOCK(&queues); 05021 05022 05023 return RESULT_SUCCESS; 05024 }
static int manager_remove_queue_member | ( | struct mansession * | s, | |
const struct message * | m | |||
) | [static] |
Definition at line 5077 of file app_queue.c.
References ast_queue_log(), ast_strlen_zero(), astman_get_header(), astman_send_ack(), astman_send_error(), remove_from_queue(), RES_EXISTS, RES_NOSUCHQUEUE, RES_NOT_DYNAMIC, RES_OKAY, RES_OUTOFMEMORY, and s.
Referenced by load_module().
05078 { 05079 const char *queuename, *interface; 05080 05081 queuename = astman_get_header(m, "Queue"); 05082 interface = astman_get_header(m, "Interface"); 05083 05084 if (ast_strlen_zero(queuename) || ast_strlen_zero(interface)) { 05085 astman_send_error(s, m, "Need 'Queue' and 'Interface' parameters."); 05086 return 0; 05087 } 05088 05089 switch (remove_from_queue(queuename, interface)) { 05090 case RES_OKAY: 05091 ast_queue_log(queuename, "MANAGER", interface, "REMOVEMEMBER", "%s", ""); 05092 astman_send_ack(s, m, "Removed interface from queue"); 05093 break; 05094 case RES_EXISTS: 05095 astman_send_error(s, m, "Unable to remove interface: Not there"); 05096 break; 05097 case RES_NOSUCHQUEUE: 05098 astman_send_error(s, m, "Unable to remove interface from queue: No such queue"); 05099 break; 05100 case RES_OUTOFMEMORY: 05101 astman_send_error(s, m, "Out of memory"); 05102 break; 05103 case RES_NOT_DYNAMIC: 05104 astman_send_error(s, m, "Member not dynamic"); 05105 break; 05106 } 05107 05108 return 0; 05109 }
static int member_cmp_fn | ( | void * | obj1, | |
void * | obj2, | |||
int | flags | |||
) | [static] |
Definition at line 849 of file app_queue.c.
References member::interface.
Referenced by init_queue().
00850 { 00851 struct member *mem1 = obj1, *mem2 = obj2; 00852 return strcmp(mem1->interface, mem2->interface) ? 0 : CMP_MATCH | CMP_STOP; 00853 }
static int member_hash_fn | ( | const void * | obj, | |
const int | flags | |||
) | [static] |
Definition at line 837 of file app_queue.c.
References compress_char(), and member::interface.
Referenced by init_queue().
00838 { 00839 const struct member *mem = obj; 00840 const char *chname = strchr(mem->interface, '/'); 00841 int ret = 0, i; 00842 if (!chname) 00843 chname = mem->interface; 00844 for (i = 0; i < 5 && chname[i]; i++) 00845 ret += compress_char(chname[i]) << (i * 6); 00846 return ret; 00847 }
static void monjoin_dep_warning | ( | void | ) | [static] |
Definition at line 477 of file app_queue.c.
References ast_log(), and LOG_NOTICE.
Referenced by queue_set_param().
00478 { 00479 static unsigned int warned = 0; 00480 if (!warned) { 00481 ast_log(LOG_NOTICE, "The 'monitor-join' queue option is deprecated. Please use monitor-type=mixmonitor instead.\n"); 00482 warned = 1; 00483 } 00484 }
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 1781 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_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().
01782 { 01783 struct member *mem; 01784 int avl = 0; 01785 struct ao2_iterator mem_iter; 01786 01787 mem_iter = ao2_iterator_init(q->members, 0); 01788 while ((mem = ao2_iterator_next(&mem_iter))) { 01789 switch (mem->status) { 01790 case AST_DEVICE_INUSE: 01791 if (!q->ringinuse) 01792 break; 01793 /* else fall through */ 01794 case AST_DEVICE_NOT_INUSE: 01795 case AST_DEVICE_UNKNOWN: 01796 if (!mem->paused) { 01797 avl++; 01798 } 01799 break; 01800 } 01801 ao2_ref(mem, -1); 01802 01803 /* If autofill is not enabled or if the queue's strategy is ringall, then 01804 * we really don't care about the number of available members so much as we 01805 * do that there is at least one available. 01806 * 01807 * In fact, we purposely will return from this function stating that only 01808 * one member is available if either of those conditions hold. That way, 01809 * functions which determine what action to take based on the number of available 01810 * members will operate properly. The reasoning is that even if multiple 01811 * members are available, only the head caller can actually be serviced. 01812 */ 01813 if ((!q->autofill || q->strategy == QUEUE_STRATEGY_RINGALL) && avl) { 01814 break; 01815 } 01816 } 01817 ao2_iterator_destroy(&mem_iter); 01818 01819 return avl; 01820 }
static int play_file | ( | struct ast_channel * | chan, | |
char * | filename | |||
) | [static] |
Definition at line 1540 of file app_queue.c.
References AST_DIGIT_ANY, ast_stopstream(), ast_streamfile(), ast_strlen_zero(), ast_waitstream(), queue_ent::chan, and ast_channel::language.
Referenced by say_periodic_announcement(), and say_position().
01541 { 01542 int res; 01543 01544 if (ast_strlen_zero(filename)) { 01545 return 0; 01546 } 01547 01548 ast_stopstream(chan); 01549 01550 res = ast_streamfile(chan, filename, chan->language); 01551 if (!res) 01552 res = ast_waitstream(chan, AST_DIGIT_ANY); 01553 01554 ast_stopstream(chan); 01555 01556 return res; 01557 }
static int pqm_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Definition at line 3713 of file app_queue.c.
References AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_goto_if_exists(), ast_log(), ast_module_user_add, ast_module_user_remove, ast_opt_priority_jumping, AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), ast_module_user::chan, ast_channel::context, ast_channel::exten, LOG_WARNING, parse(), pbx_builtin_setvar_helper(), ast_channel::priority, and set_member_paused().
Referenced by load_module().
03714 { 03715 struct ast_module_user *lu; 03716 char *parse; 03717 int priority_jump = 0; 03718 int ignore_fail = 0; 03719 AST_DECLARE_APP_ARGS(args, 03720 AST_APP_ARG(queuename); 03721 AST_APP_ARG(interface); 03722 AST_APP_ARG(options); 03723 ); 03724 03725 if (ast_strlen_zero(data)) { 03726 ast_log(LOG_WARNING, "PauseQueueMember requires an argument ([queuename]|interface[|options])\n"); 03727 return -1; 03728 } 03729 03730 parse = ast_strdupa(data); 03731 03732 AST_STANDARD_APP_ARGS(args, parse); 03733 03734 lu = ast_module_user_add(chan); 03735 03736 if (args.options) { 03737 if (strchr(args.options, 'j')) 03738 priority_jump = 1; 03739 if (strchr(args.options, 'i')) 03740 ignore_fail = 1; 03741 } 03742 03743 if (ast_strlen_zero(args.interface)) { 03744 ast_log(LOG_WARNING, "Missing interface argument to PauseQueueMember ([queuename]|interface[|options])\n"); 03745 ast_module_user_remove(lu); 03746 return -1; 03747 } 03748 03749 if (set_member_paused(args.queuename, args.interface, 1)) { 03750 ast_log(LOG_WARNING, "Attempt to pause interface %s, not found\n", args.interface); 03751 pbx_builtin_setvar_helper(chan, "PQMSTATUS", "NOTFOUND"); 03752 if (priority_jump || ast_opt_priority_jumping) { 03753 if (!ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101)) { 03754 ast_module_user_remove(lu); 03755 return 0; 03756 } 03757 } 03758 ast_module_user_remove(lu); 03759 if (ignore_fail) { 03760 return 0; 03761 } else { 03762 return -1; 03763 } 03764 } 03765 03766 ast_module_user_remove(lu); 03767 pbx_builtin_setvar_helper(chan, "PQMSTATUS", "PAUSED"); 03768 return 0; 03769 }
static int ql_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Definition at line 3971 of file app_queue.c.
References AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_log(), ast_module_user_add, ast_module_user_remove, ast_queue_log(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), ast_module_user::chan, LOG_WARNING, and parse().
Referenced by load_module().
03972 { 03973 struct ast_module_user *u; 03974 char *parse; 03975 03976 AST_DECLARE_APP_ARGS(args, 03977 AST_APP_ARG(queuename); 03978 AST_APP_ARG(uniqueid); 03979 AST_APP_ARG(membername); 03980 AST_APP_ARG(event); 03981 AST_APP_ARG(params); 03982 ); 03983 03984 if (ast_strlen_zero(data)) { 03985 ast_log(LOG_WARNING, "QueueLog requires arguments (queuename|uniqueid|membername|event[|additionalinfo]\n"); 03986 return -1; 03987 } 03988 03989 u = ast_module_user_add(chan); 03990 03991 parse = ast_strdupa(data); 03992 03993 AST_STANDARD_APP_ARGS(args, parse); 03994 03995 if (ast_strlen_zero(args.queuename) || ast_strlen_zero(args.uniqueid) 03996 || ast_strlen_zero(args.membername) || ast_strlen_zero(args.event)) { 03997 ast_log(LOG_WARNING, "QueueLog requires arguments (queuename|uniqueid|membername|event[|additionalinfo])\n"); 03998 ast_module_user_remove(u); 03999 return -1; 04000 } 04001 04002 ast_queue_log(args.queuename, args.uniqueid, args.membername, args.event, 04003 "%s", args.params ? args.params : ""); 04004 04005 ast_module_user_remove(u); 04006 04007 return 0; 04008 }
static int qmc_handler | ( | const char * | queuename, | |
char * | buffer, | |||
int | len | |||
) | [static] |
Definition at line 5356 of file app_queue.c.
References queue_member_count(), RESULT_FAILURE, and RESULT_SUCCESS.
Referenced by cli_queue_member_count(), and manager_queue_member_count().
05357 { 05358 struct member_count qmc; 05359 memset(&qmc, 0, sizeof(qmc)); 05360 if (queue_member_count(queuename, &qmc) != 0) { 05361 return RESULT_FAILURE; 05362 } else { 05363 snprintf(buffer, len, 05364 "valid:%d inuse:%d paused:%d active:%d free:%d all:%d", 05365 qmc.valid, qmc.inuse, qmc.paused, qmc.active, qmc.free, qmc.all); 05366 return RESULT_SUCCESS; 05367 } 05368 }
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 uless some condition (such as an expiration time) causes us to exit the queue.
Definition at line 4022 of file app_queue.c.
References call_queue::announcefrequency, AST_APP_ARG, ast_cdr_noanswer(), AST_CONTROL_RINGING, AST_DECLARE_APP_ARGS, ast_indicate(), ast_log(), ast_module_user_add, ast_moh_start(), ast_moh_stop(), ast_queue_log(), AST_STANDARD_APP_ARGS, ast_stopstream(), ast_strdupa, ast_strlen_zero(), ast_verbose(), ast_channel::cdr, 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, ast_channel::name, queue_ent::opos, option_verbose, queue_ent::parent, parse(), pbx_builtin_getvar_helper(), call_queue::periodicannouncefrequency, queue_ent::pos, queue_ent::prio, QUEUE_EMPTY_STRICT, QUEUE_LEAVEEMPTY, QUEUE_LEAVEUNAVAIL, QUEUE_NO_MEMBERS, QUEUE_NO_REACHABLE_MEMBERS, QUEUE_TIMEOUT, QUEUE_UNKNOWN, record_abandoned(), S_OR, say_periodic_announcement(), say_position(), set_queue_result(), queue_ent::start, stop, try_calling(), ast_channel::uniqueid, update_realtime_members(), queue_ent::valid_digits, VERBOSE_PREFIX_3, wait_a_bit(), and wait_our_turn().
Referenced by load_module().
04023 { 04024 int res=-1; 04025 int ringing=0; 04026 struct ast_module_user *lu; 04027 const char *user_priority; 04028 const char *max_penalty_str; 04029 int prio; 04030 int max_penalty; 04031 enum queue_result reason = QUEUE_UNKNOWN; 04032 /* whether to exit Queue application after the timeout hits */ 04033 int tries = 0; 04034 int noption = 0; 04035 char *parse; 04036 AST_DECLARE_APP_ARGS(args, 04037 AST_APP_ARG(queuename); 04038 AST_APP_ARG(options); 04039 AST_APP_ARG(url); 04040 AST_APP_ARG(announceoverride); 04041 AST_APP_ARG(queuetimeoutstr); 04042 AST_APP_ARG(agi); 04043 ); 04044 /* Our queue entry */ 04045 struct queue_ent qe = { 0 }; 04046 04047 if (ast_strlen_zero(data)) { 04048 ast_log(LOG_WARNING, "Queue requires an argument: queuename[|options[|URL[|announceoverride[|timeout[|agi]]]]]\n"); 04049 return -1; 04050 } 04051 04052 parse = ast_strdupa(data); 04053 AST_STANDARD_APP_ARGS(args, parse); 04054 04055 lu = ast_module_user_add(chan); 04056 04057 /* Setup our queue entry */ 04058 qe.start = time(NULL); 04059 04060 /* set the expire time based on the supplied timeout; */ 04061 if (!ast_strlen_zero(args.queuetimeoutstr)) 04062 qe.expire = qe.start + atoi(args.queuetimeoutstr); 04063 else 04064 qe.expire = 0; 04065 04066 /* Get the priority from the variable ${QUEUE_PRIO} */ 04067 user_priority = pbx_builtin_getvar_helper(chan, "QUEUE_PRIO"); 04068 if (user_priority) { 04069 if (sscanf(user_priority, "%30d", &prio) == 1) { 04070 if (option_debug) 04071 ast_log(LOG_DEBUG, "%s: Got priority %d from ${QUEUE_PRIO}.\n", 04072 chan->name, prio); 04073 } else { 04074 ast_log(LOG_WARNING, "${QUEUE_PRIO}: Invalid value (%s), channel %s.\n", 04075 user_priority, chan->name); 04076 prio = 0; 04077 } 04078 } else { 04079 if (option_debug > 2) 04080 ast_log(LOG_DEBUG, "NO QUEUE_PRIO variable found. Using default.\n"); 04081 prio = 0; 04082 } 04083 04084 /* Get the maximum penalty from the variable ${QUEUE_MAX_PENALTY} */ 04085 if ((max_penalty_str = pbx_builtin_getvar_helper(chan, "QUEUE_MAX_PENALTY"))) { 04086 if (sscanf(max_penalty_str, "%30d", &max_penalty) == 1) { 04087 if (option_debug) 04088 ast_log(LOG_DEBUG, "%s: Got max penalty %d from ${QUEUE_MAX_PENALTY}.\n", 04089 chan->name, max_penalty); 04090 } else { 04091 ast_log(LOG_WARNING, "${QUEUE_MAX_PENALTY}: Invalid value (%s), channel %s.\n", 04092 max_penalty_str, chan->name); 04093 max_penalty = 0; 04094 } 04095 } else { 04096 max_penalty = 0; 04097 } 04098 04099 if (args.options && (strchr(args.options, 'r'))) 04100 ringing = 1; 04101 04102 if (option_debug) 04103 ast_log(LOG_DEBUG, "queue: %s, options: %s, url: %s, announce: %s, expires: %ld, priority: %d\n", 04104 args.queuename, args.options, args.url, args.announceoverride, (long)qe.expire, prio); 04105 04106 qe.chan = chan; 04107 qe.prio = prio; 04108 qe.max_penalty = max_penalty; 04109 qe.last_pos_said = 0; 04110 qe.last_pos = 0; 04111 qe.last_periodic_announce_time = time(NULL); 04112 qe.last_periodic_announce_sound = 0; 04113 qe.valid_digits = 0; 04114 if (!join_queue(args.queuename, &qe, &reason)) { 04115 int makeannouncement = 0; 04116 04117 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "ENTERQUEUE", "%s|%s", S_OR(args.url, ""), 04118 S_OR(chan->cid.cid_num, "")); 04119 check_turns: 04120 if (ringing) { 04121 ast_indicate(chan, AST_CONTROL_RINGING); 04122 } else { 04123 ast_moh_start(chan, qe.moh, NULL); 04124 } 04125 04126 /* This is the wait loop for callers 2 through maxlen */ 04127 res = wait_our_turn(&qe, ringing, &reason); 04128 if (res) 04129 goto stop; 04130 04131 for (;;) { 04132 /* This is the wait loop for the head caller*/ 04133 /* To exit, they may get their call answered; */ 04134 /* they may dial a digit from the queue context; */ 04135 /* or, they may timeout. */ 04136 04137 enum queue_member_status stat; 04138 04139 /* Leave if we have exceeded our queuetimeout */ 04140 if (qe.expire && (time(NULL) >= qe.expire)) { 04141 record_abandoned(&qe); 04142 ast_cdr_noanswer(qe.chan->cdr); 04143 reason = QUEUE_TIMEOUT; 04144 res = 0; 04145 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHTIMEOUT", "%d", qe.pos); 04146 break; 04147 } 04148 04149 if (makeannouncement) { 04150 /* Make a position announcement, if enabled */ 04151 if (qe.parent->announcefrequency && !ringing) 04152 if ((res = say_position(&qe))) 04153 goto stop; 04154 04155 } 04156 makeannouncement = 1; 04157 04158 /* Leave if we have exceeded our queuetimeout */ 04159 if (qe.expire && (time(NULL) >= qe.expire)) { 04160 record_abandoned(&qe); 04161 ast_cdr_noanswer(qe.chan->cdr); 04162 reason = QUEUE_TIMEOUT; 04163 res = 0; 04164 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHTIMEOUT", "%d", qe.pos); 04165 break; 04166 } 04167 /* Make a periodic announcement, if enabled */ 04168 if (qe.parent->periodicannouncefrequency && !ringing) 04169 if ((res = say_periodic_announcement(&qe))) 04170 goto stop; 04171 04172 /* Leave if we have exceeded our queuetimeout */ 04173 if (qe.expire && (time(NULL) >= qe.expire)) { 04174 record_abandoned(&qe); 04175 ast_cdr_noanswer(qe.chan->cdr); 04176 reason = QUEUE_TIMEOUT; 04177 res = 0; 04178 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHTIMEOUT", "%d", qe.pos); 04179 break; 04180 } 04181 /* Try calling all queue members for 'timeout' seconds */ 04182 res = try_calling(&qe, args.options, args.announceoverride, args.url, &tries, &noption, args.agi); 04183 if (res) 04184 goto stop; 04185 04186 stat = get_member_status(qe.parent, qe.max_penalty); 04187 04188 /* exit after 'timeout' cycle if 'n' option enabled */ 04189 if (noption && tries >= qe.parent->membercount) { 04190 if (option_verbose > 2) 04191 ast_verbose(VERBOSE_PREFIX_3 "Exiting on time-out cycle\n"); 04192 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHTIMEOUT", "%d", qe.pos); 04193 record_abandoned(&qe); 04194 ast_cdr_noanswer(qe.chan->cdr); 04195 reason = QUEUE_TIMEOUT; 04196 res = 0; 04197 break; 04198 } 04199 04200 /* leave the queue if no agents, if enabled */ 04201 if (qe.parent->leavewhenempty && (stat == QUEUE_NO_MEMBERS)) { 04202 record_abandoned(&qe); 04203 ast_cdr_noanswer(qe.chan->cdr); 04204 reason = QUEUE_LEAVEEMPTY; 04205 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe.pos, qe.opos, (long)(time(NULL) - qe.start)); 04206 res = 0; 04207 break; 04208 } 04209 04210 /* leave the queue if no reachable agents, if enabled */ 04211 if ((qe.parent->leavewhenempty == QUEUE_EMPTY_STRICT) && (stat == QUEUE_NO_REACHABLE_MEMBERS)) { 04212 record_abandoned(&qe); 04213 ast_cdr_noanswer(qe.chan->cdr); 04214 reason = QUEUE_LEAVEUNAVAIL; 04215 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe.pos, qe.opos, (long)(time(NULL) - qe.start)); 04216 res = 0; 04217 break; 04218 } 04219 04220 /* Leave if we have exceeded our queuetimeout */ 04221 if (qe.expire && (time(NULL) >= qe.expire)) { 04222 record_abandoned(&qe); 04223 ast_cdr_noanswer(qe.chan->cdr); 04224 reason = QUEUE_TIMEOUT; 04225 res = 0; 04226 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHTIMEOUT", "%d", qe.pos); 04227 break; 04228 } 04229 04230 /* If using dynamic realtime members, we should regenerate the member list for this queue */ 04231 update_realtime_members(qe.parent); 04232 04233 /* OK, we didn't get anybody; wait for 'retry' seconds; may get a digit to exit with */ 04234 res = wait_a_bit(&qe); 04235 if (res) 04236 goto stop; 04237 04238 /* Since this is a priority queue and 04239 * it is not sure that we are still at the head 04240 * of the queue, go and check for our turn again. 04241 */ 04242 if (!is_our_turn(&qe)) { 04243 if (option_debug) 04244 ast_log(LOG_DEBUG, "Darn priorities, going back in queue (%s)!\n", 04245 qe.chan->name); 04246 goto check_turns; 04247 } 04248 } 04249 04250 stop: 04251 if (res) { 04252 if (res < 0) { 04253 if (!qe.handled) { 04254 record_abandoned(&qe); 04255 ast_cdr_noanswer(qe.chan->cdr); 04256 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "ABANDON", 04257 "%d|%d|%ld", qe.pos, qe.opos, 04258 (long) time(NULL) - qe.start); 04259 } 04260 res = -1; 04261 } else if (qe.valid_digits) { 04262 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHKEY", 04263 "%s|%d", qe.digits, qe.pos); 04264 } 04265 } 04266 04267 /* Don't allow return code > 0 */ 04268 if (res >= 0) { 04269 res = 0; 04270 if (ringing) { 04271 ast_indicate(chan, -1); 04272 } else { 04273 ast_moh_stop(chan); 04274 } 04275 ast_stopstream(chan); 04276 } 04277 leave_queue(&qe); 04278 if (reason != QUEUE_UNKNOWN) 04279 set_queue_result(chan, reason); 04280 } else { 04281 ast_log(LOG_WARNING, "Unable to join queue '%s'\n", args.queuename); 04282 set_queue_result(chan, reason); 04283 res = 0; 04284 } 04285 if (qe.parent) { 04286 /* every queue_ent is given a reference to it's parent call_queue when it joins the queue. 04287 * This ref must be taken away right before the queue_ent is destroyed. In this case 04288 * the queue_ent is about to be returned on the stack */ 04289 ao2_ref(qe.parent, -1); 04290 } 04291 ast_module_user_remove(lu); 04292 04293 return res; 04294 }
static int queue_function_queuemembercount | ( | struct ast_channel * | chan, | |
char * | cmd, | |||
char * | data, | |||
char * | buf, | |||
size_t | len | |||
) | [static] |
Definition at line 4304 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, name, member::paused, QMC_ACTIVE, QMC_FREE, QMC_PAUSED, QMC_VALID, and member::status.
04305 { 04306 int count = 0; 04307 struct call_queue *q; 04308 struct ast_module_user *lu; 04309 struct member *m; 04310 struct ao2_iterator mem_iter; 04311 char *name, *item; 04312 enum qmc_status mode = QMC_VALID; 04313 04314 buf[0] = '\0'; 04315 04316 if (ast_strlen_zero(data)) { 04317 ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd); 04318 return -1; 04319 } 04320 04321 name = ast_strdupa(data); 04322 04323 lu = ast_module_user_add(chan); 04324 04325 if ((item = strchr(name, ':'))) { 04326 *item = '\0'; 04327 item++; 04328 } else { 04329 item = ""; 04330 } 04331 04332 if (!strcasecmp(item, "valid")) { 04333 mode = QMC_VALID; 04334 } else if (!strcasecmp(item, "paused")) { 04335 mode = QMC_PAUSED; 04336 } else if (!strcasecmp(item, "active")) { 04337 mode = QMC_ACTIVE; 04338 } else if (!strcasecmp(item, "free")) { 04339 mode = QMC_FREE; 04340 } else if (!strcasecmp(item, "all")) { 04341 mode = QMC_ALL; 04342 } 04343 04344 if ((q = load_realtime_queue(name))) { 04345 ao2_lock(q); 04346 mem_iter = ao2_iterator_init(q->members, 0); 04347 while ((m = ao2_iterator_next(&mem_iter))) { 04348 switch (mode) { 04349 case QMC_VALID: 04350 /* Count the queue members who are logged in and presently answering calls */ 04351 if ((m->status != AST_DEVICE_UNAVAILABLE) && (m->status != AST_DEVICE_INVALID)) { 04352 count++; 04353 } 04354 break; 04355 case QMC_PAUSED: 04356 /* Count paused members */ 04357 if (m->paused) { 04358 count++; 04359 } 04360 break; 04361 case QMC_ACTIVE: 04362 /* Count not paused members who are logged in and presently answering calls */ 04363 if (!m->paused && (m->status != AST_DEVICE_UNAVAILABLE) && (m->status != AST_DEVICE_INVALID)) { 04364 count++; 04365 } 04366 break; 04367 case QMC_FREE: 04368 /* Count free members in the queue */ 04369 if (!m->paused && ((m->status == AST_DEVICE_UNKNOWN) || (m->status == AST_DEVICE_NOT_INUSE))) { 04370 count++; 04371 } 04372 break; 04373 default: 04374 count++; 04375 break; 04376 } 04377 ao2_ref(m, -1); 04378 } 04379 ao2_iterator_destroy(&mem_iter); 04380 ao2_unlock(q); 04381 } else 04382 ast_log(LOG_WARNING, "queue %s was not found\n", name); 04383 04384 snprintf(buf, len, "%d", count); 04385 ast_module_user_remove(lu); 04386 04387 return 0; 04388 }
static int queue_function_queuememberlist | ( | struct ast_channel * | chan, | |
char * | cmd, | |||
char * | data, | |||
char * | buf, | |||
size_t | len | |||
) | [static] |
Definition at line 4433 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.
04434 { 04435 struct ast_module_user *u; 04436 struct call_queue *q; 04437 struct member *m; 04438 04439 /* Ensure an otherwise empty list doesn't return garbage */ 04440 buf[0] = '\0'; 04441 04442 if (ast_strlen_zero(data)) { 04443 ast_log(LOG_ERROR, "QUEUE_MEMBER_LIST requires an argument: queuename\n"); 04444 return -1; 04445 } 04446 04447 u = ast_module_user_add(chan); 04448 04449 AST_LIST_LOCK(&queues); 04450 AST_LIST_TRAVERSE(&queues, q, list) { 04451 if (!strcasecmp(q->name, data)) { 04452 ao2_lock(q); 04453 break; 04454 } 04455 } 04456 AST_LIST_UNLOCK(&queues); 04457 04458 if (q) { 04459 int buflen = 0, count = 0; 04460 struct ao2_iterator mem_iter = ao2_iterator_init(q->members, 0); 04461 04462 while ((m = ao2_iterator_next(&mem_iter))) { 04463 /* strcat() is always faster than printf() */ 04464 if (count++) { 04465 strncat(buf + buflen, ",", len - buflen - 1); 04466 buflen++; 04467 } 04468 strncat(buf + buflen, m->interface, len - buflen - 1); 04469 buflen += strlen(m->interface); 04470 /* Safeguard against overflow (negative length) */ 04471 if (buflen >= len - 2) { 04472 ao2_ref(m, -1); 04473 ast_log(LOG_WARNING, "Truncating list\n"); 04474 break; 04475 } 04476 ao2_ref(m, -1); 04477 } 04478 ao2_iterator_destroy(&mem_iter); 04479 ao2_unlock(q); 04480 } else 04481 ast_log(LOG_WARNING, "queue %s was not found\n", data); 04482 04483 /* We should already be terminated, but let's make sure. */ 04484 buf[len - 1] = '\0'; 04485 ast_module_user_remove(u); 04486 04487 return 0; 04488 }
static int queue_function_queuewaitingcount | ( | struct ast_channel * | chan, | |
char * | cmd, | |||
char * | data, | |||
char * | buf, | |||
size_t | len | |||
) | [static] |
Definition at line 4390 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.
04391 { 04392 int count = 0; 04393 struct call_queue *q; 04394 struct ast_module_user *lu; 04395 struct ast_variable *var = NULL; 04396 04397 buf[0] = '\0'; 04398 04399 if (ast_strlen_zero(data)) { 04400 ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd); 04401 return -1; 04402 } 04403 04404 lu = ast_module_user_add(chan); 04405 04406 AST_LIST_LOCK(&queues); 04407 AST_LIST_TRAVERSE(&queues, q, list) { 04408 if (!strcasecmp(q->name, data)) { 04409 ao2_lock(q); 04410 break; 04411 } 04412 } 04413 AST_LIST_UNLOCK(&queues); 04414 04415 if (q) { 04416 count = q->count; 04417 ao2_unlock(q); 04418 } else if ((var = ast_load_realtime("queues", "name", data, NULL))) { 04419 /* if the queue is realtime but was not found in memory, this 04420 * means that the queue had been deleted from memory since it was 04421 * "dead." This means it has a 0 waiting count 04422 */ 04423 count = 0; 04424 ast_variables_destroy(var); 04425 } else 04426 ast_log(LOG_WARNING, "queue %s was not found\n", data); 04427 04428 snprintf(buf, len, "%d", count); 04429 ast_module_user_remove(lu); 04430 return 0; 04431 }
static int queue_member_count | ( | const char * | qname, | |
struct member_count * | qmc | |||
) | [static] |
Definition at line 5314 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, member_count::paused, member::paused, member::status, and member_count::valid.
Referenced by qmc_handler().
05315 { 05316 int res = 0; 05317 struct call_queue *q; 05318 struct member *m; 05319 struct ao2_iterator mem_iter; 05320 05321 if ((q = load_realtime_queue(qname))) { 05322 ao2_lock(q); 05323 mem_iter = ao2_iterator_init(q->members, 0); 05324 while ((m = ao2_iterator_next(&mem_iter))) { 05325 /* Count the queue members in use */ 05326 if (m->status == AST_DEVICE_INUSE) { 05327 qmc->inuse++; 05328 } 05329 /* Count the queue members who are logged in and presently answering calls */ 05330 if ((m->status != AST_DEVICE_UNAVAILABLE) && (m->status != AST_DEVICE_INVALID)) { 05331 qmc->valid++; 05332 } 05333 /* Count paused members */ 05334 if (m->paused) { 05335 qmc->paused++; 05336 } 05337 /* Count not paused members who are logged in and presently answering calls */ 05338 if (!m->paused && (m->status != AST_DEVICE_UNAVAILABLE) && (m->status != AST_DEVICE_INVALID)) { 05339 qmc->active++; 05340 } 05341 /* Count free members in the queue */ 05342 if (!m->paused && ((m->status == AST_DEVICE_UNKNOWN) || (m->status == AST_DEVICE_NOT_INUSE))) { 05343 qmc->free++; 05344 } 05345 qmc->all++; 05346 ao2_ref(m, -1); 05347 } 05348 ao2_unlock(q); 05349 } else { 05350 ast_log(LOG_WARNING, "Queue %s was not found\n", qname); 05351 res = -1; 05352 } 05353 return res; 05354 }
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 1011 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_lessthan, call_queue::sound_minutes, call_queue::sound_next, call_queue::sound_periodicannounce, call_queue::sound_reporthold, call_queue::sound_seconds, call_queue::sound_thanks, call_queue::sound_thereare, strat2int(), call_queue::strategy, call_queue::timeout, call_queue::timeoutrestart, call_queue::weight, and call_queue::wrapuptime.
Referenced by find_queue_by_name_rt(), and reload_queues().
01012 { 01013 if (!strcasecmp(param, "musicclass") || 01014 !strcasecmp(param, "music") || !strcasecmp(param, "musiconhold")) { 01015 ast_copy_string(q->moh, val, sizeof(q->moh)); 01016 } else if (!strcasecmp(param, "announce")) { 01017 ast_copy_string(q->announce, val, sizeof(q->announce)); 01018 } else if (!strcasecmp(param, "context")) { 01019 ast_copy_string(q->context, val, sizeof(q->context)); 01020 } else if (!strcasecmp(param, "timeout")) { 01021 q->timeout = atoi(val); 01022 if (q->timeout < 0) 01023 q->timeout = DEFAULT_TIMEOUT; 01024 } else if (!strcasecmp(param, "ringinuse")) { 01025 q->ringinuse = ast_true(val); 01026 } else if (!strcasecmp(param, "setinterfacevar")) { 01027 q->setinterfacevar = ast_true(val); 01028 } else if (!strcasecmp(param, "monitor-join")) { 01029 monjoin_dep_warning(); 01030 q->monjoin = ast_true(val); 01031 } else if (!strcasecmp(param, "monitor-format")) { 01032 ast_copy_string(q->monfmt, val, sizeof(q->monfmt)); 01033 } else if (!strcasecmp(param, "queue-youarenext")) { 01034 ast_copy_string(q->sound_next, val, sizeof(q->sound_next)); 01035 } else if (!strcasecmp(param, "queue-thereare")) { 01036 ast_copy_string(q->sound_thereare, val, sizeof(q->sound_thereare)); 01037 } else if (!strcasecmp(param, "queue-callswaiting")) { 01038 ast_copy_string(q->sound_calls, val, sizeof(q->sound_calls)); 01039 } else if (!strcasecmp(param, "queue-holdtime")) { 01040 ast_copy_string(q->sound_holdtime, val, sizeof(q->sound_holdtime)); 01041 } else if (!strcasecmp(param, "queue-minutes")) { 01042 ast_copy_string(q->sound_minutes, val, sizeof(q->sound_minutes)); 01043 } else if (!strcasecmp(param, "queue-seconds")) { 01044 ast_copy_string(q->sound_seconds, val, sizeof(q->sound_seconds)); 01045 } else if (!strcasecmp(param, "queue-lessthan")) { 01046 ast_copy_string(q->sound_lessthan, val, sizeof(q->sound_lessthan)); 01047 } else if (!strcasecmp(param, "queue-thankyou")) { 01048 ast_copy_string(q->sound_thanks, val, sizeof(q->sound_thanks)); 01049 } else if (!strcasecmp(param, "queue-reporthold")) { 01050 ast_copy_string(q->sound_reporthold, val, sizeof(q->sound_reporthold)); 01051 } else if (!strcasecmp(param, "announce-frequency")) { 01052 q->announcefrequency = atoi(val); 01053 } else if (!strcasecmp(param, "announce-round-seconds")) { 01054 q->roundingseconds = atoi(val); 01055 if (q->roundingseconds>60 || q->roundingseconds<0) { 01056 if (linenum >= 0) { 01057 ast_log(LOG_WARNING, "'%s' isn't a valid value for %s " 01058 "using 0 instead for queue '%s' at line %d of queues.conf\n", 01059 val, param, q->name, linenum); 01060 } else { 01061 ast_log(LOG_WARNING, "'%s' isn't a valid value for %s " 01062 "using 0 instead for queue '%s'\n", val, param, q->name); 01063 } 01064 q->roundingseconds=0; 01065 } 01066 } else if (!strcasecmp(param, "announce-holdtime")) { 01067 if (!strcasecmp(val, "once")) 01068 q->announceholdtime = ANNOUNCEHOLDTIME_ONCE; 01069 else if (ast_true(val)) 01070 q->announceholdtime = ANNOUNCEHOLDTIME_ALWAYS; 01071 else 01072 q->announceholdtime = 0; 01073 } else if (!strcasecmp(param, "periodic-announce")) { 01074 if (strchr(val, '|')) { 01075 char *s, *buf = ast_strdupa(val); 01076 unsigned int i = 0; 01077 01078 while ((s = strsep(&buf, "|"))) { 01079 ast_copy_string(q->sound_periodicannounce[i], s, sizeof(q->sound_periodicannounce[i])); 01080 i++; 01081 if (i == MAX_PERIODIC_ANNOUNCEMENTS) 01082 break; 01083 } 01084 } else { 01085 ast_copy_string(q->sound_periodicannounce[0], val, sizeof(q->sound_periodicannounce[0])); 01086 } 01087 } else if (!strcasecmp(param, "periodic-announce-frequency")) { 01088 q->periodicannouncefrequency = atoi(val); 01089 } else if (!strcasecmp(param, "retry")) { 01090 q->retry = atoi(val); 01091 if (q->retry <= 0) 01092 q->retry = DEFAULT_RETRY; 01093 } else if (!strcasecmp(param, "wrapuptime")) { 01094 q->wrapuptime = atoi(val); 01095 } else if (!strcasecmp(param, "autofill")) { 01096 q->autofill = ast_true(val); 01097 } else if (!strcasecmp(param, "monitor-type")) { 01098 if (!strcasecmp(val, "mixmonitor")) 01099 q->montype = 1; 01100 } else if (!strcasecmp(param, "autopause")) { 01101 q->autopause = ast_true(val); 01102 } else if (!strcasecmp(param, "maxlen")) { 01103 q->maxlen = atoi(val); 01104 if (q->maxlen < 0) 01105 q->maxlen = 0; 01106 } else if (!strcasecmp(param, "ringlimit")) { 01107 q->ringlimit = atoi(val); 01108 if (q->ringlimit < 0) 01109 q->ringlimit = 0; 01110 } else if (!strcasecmp(param, "servicelevel")) { 01111 q->servicelevel= atoi(val); 01112 } else if (!strcasecmp(param, "strategy")) { 01113 q->strategy = strat2int(val); 01114 if (q->strategy < 0) { 01115 ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n", 01116 val, q->name); 01117 q->strategy = QUEUE_STRATEGY_RINGALL; 01118 } 01119 } else if (!strcasecmp(param, "joinempty")) { 01120 if (!strcasecmp(val, "strict")) 01121 q->joinempty = QUEUE_EMPTY_STRICT; 01122 else if (ast_true(val)) 01123 q->joinempty = QUEUE_EMPTY_NORMAL; 01124 else 01125 q->joinempty = 0; 01126 } else if (!strcasecmp(param, "leavewhenempty")) { 01127 if (!strcasecmp(val, "strict")) 01128 q->leavewhenempty = QUEUE_EMPTY_STRICT; 01129 else if (ast_true(val)) 01130 q->leavewhenempty = QUEUE_EMPTY_NORMAL; 01131 else 01132 q->leavewhenempty = 0; 01133 } else if (!strcasecmp(param, "eventmemberstatus")) { 01134 q->maskmemberstatus = !ast_true(val); 01135 } else if (!strcasecmp(param, "eventwhencalled")) { 01136 if (!strcasecmp(val, "vars")) { 01137 q->eventwhencalled = QUEUE_EVENT_VARIABLES; 01138 } else { 01139 q->eventwhencalled = ast_true(val) ? 1 : 0; 01140 } 01141 } else if (!strcasecmp(param, "reportholdtime")) { 01142 q->reportholdtime = ast_true(val); 01143 } else if (!strcasecmp(param, "memberdelay")) { 01144 q->memberdelay = atoi(val); 01145 } else if (!strcasecmp(param, "weight")) { 01146 q->weight = atoi(val); 01147 if (q->weight) 01148 use_weight++; 01149 /* With Realtime queues, if the last queue using weights is deleted in realtime, 01150 we will not see any effect on use_weight until next reload. */ 01151 } else if (!strcasecmp(param, "timeoutrestart")) { 01152 q->timeoutrestart = ast_true(val); 01153 } else if (failunknown) { 01154 if (linenum >= 0) { 01155 ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s at line %d of queues.conf\n", 01156 q->name, param, linenum); 01157 } else { 01158 ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s\n", q->name, param); 01159 } 01160 } 01161 }
static int queue_show | ( | int | fd, | |
int | argc, | |||
char ** | argv | |||
) | [static] |
Definition at line 4886 of file app_queue.c.
References __queues_show().
Referenced by __queues_show().
04887 { 04888 return __queues_show(NULL, 0, fd, argc, argv); 04889 }
static void queue_transfer_destroy | ( | void * | data | ) | [static] |
Definition at line 2700 of file app_queue.c.
References ast_free.
02701 { 02702 struct queue_transfer_ds *qtds = data; 02703 ast_free(qtds); 02704 }
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 2723 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, ast_channel::uniqueid, and update_queue().
02724 { 02725 struct queue_transfer_ds *qtds = data; 02726 struct queue_ent *qe = qtds->qe; 02727 struct member *member = qtds->member; 02728 time_t callstart = qtds->starttime; 02729 int callcompletedinsl = qtds->callcompletedinsl; 02730 struct ast_datastore *datastore; 02731 02732 ast_queue_log(qe->parent->name, qe->chan->uniqueid, member->membername, "TRANSFER", "%s|%s|%ld|%ld", 02733 new_chan->exten, new_chan->context, (long) (callstart - qe->start), 02734 (long) (time(NULL) - callstart)); 02735 02736 update_queue(qe->parent, member, callcompletedinsl); 02737 02738 /* No need to lock the channels because they are already locked in ast_do_masquerade */ 02739 if ((datastore = ast_channel_datastore_find(old_chan, &queue_transfer_info, NULL))) { 02740 ast_channel_datastore_remove(old_chan, datastore); 02741 } else { 02742 ast_log(LOG_WARNING, "Can't find the queue_transfer datastore.\n"); 02743 } 02744 }
static void recalc_holdtime | ( | struct queue_ent * | qe, | |
int | newholdtime | |||
) | [static] |
Definition at line 1701 of file app_queue.c.
References ao2_lock(), ao2_unlock(), call_queue::holdtime, and queue_ent::parent.
01702 { 01703 int oldvalue; 01704 01705 /* Calculate holdtime using an exponential average */ 01706 /* Thanks to SRT for this contribution */ 01707 /* 2^2 (4) is the filter coefficient; a higher exponent would give old entries more weight */ 01708 01709 ao2_lock(qe->parent); 01710 oldvalue = qe->parent->holdtime; 01711 qe->parent->holdtime = (((oldvalue << 2) - oldvalue) + newholdtime) >> 2; 01712 ao2_unlock(qe->parent); 01713 }
static void record_abandoned | ( | struct queue_ent * | qe | ) | [static] |
Definition at line 2182 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, queue_ent::start, and ast_channel::uniqueid.
Referenced by queue_exec().
02183 { 02184 ao2_lock(qe->parent); 02185 manager_event(EVENT_FLAG_AGENT, "QueueCallerAbandon", 02186 "Queue: %s\r\n" 02187 "Uniqueid: %s\r\n" 02188 "Position: %d\r\n" 02189 "OriginalPosition: %d\r\n" 02190 "HoldTime: %d\r\n", 02191 qe->parent->name, qe->chan->uniqueid, qe->pos, qe->opos, (int)(time(NULL) - qe->start)); 02192 02193 qe->parent->callsabandoned++; 02194 ao2_unlock(qe->parent); 02195 }
static int reload | ( | void | ) | [static] |
Definition at line 5552 of file app_queue.c.
References reload_queues().
05553 { 05554 reload_queues(); 05555 return 0; 05556 }
static void reload_queue_members | ( | void | ) | [static] |
Definition at line 3616 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(), errno, member::interface, ast_db_entry::key, call_queue::list, load_realtime_queue(), LOG_DEBUG, LOG_ERROR, LOG_NOTICE, LOG_WARNING, call_queue::name, ast_db_entry::next, member::paused, member::penalty, PM_MAX_LEN, RES_OUTOFMEMORY, and member::state_interface.
Referenced by load_module().
03617 { 03618 char *cur_ptr; 03619 char *queue_name; 03620 char *member; 03621 char *interface; 03622 char *membername = NULL; 03623 char *state_interface; 03624 char *penalty_tok; 03625 int penalty = 0; 03626 char *paused_tok; 03627 int paused = 0; 03628 struct ast_db_entry *db_tree; 03629 struct ast_db_entry *entry; 03630 struct call_queue *cur_queue; 03631 char queue_data[PM_MAX_LEN]; 03632 03633 AST_LIST_LOCK(&queues); 03634 03635 /* Each key in 'pm_family' is the name of a queue */ 03636 db_tree = ast_db_gettree(pm_family, NULL); 03637 for (entry = db_tree; entry; entry = entry->next) { 03638 03639 queue_name = entry->key + strlen(pm_family) + 2; 03640 03641 AST_LIST_TRAVERSE(&queues, cur_queue, list) { 03642 ao2_lock(cur_queue); 03643 if (!strcmp(queue_name, cur_queue->name)) 03644 break; 03645 ao2_unlock(cur_queue); 03646 } 03647 03648 if (!cur_queue) 03649 cur_queue = load_realtime_queue(queue_name); 03650 03651 if (!cur_queue) { 03652 /* If the queue no longer exists, remove it from the 03653 * database */ 03654 ast_log(LOG_WARNING, "Error loading persistent queue: '%s': it does not exist\n", queue_name); 03655 ast_db_del(pm_family, queue_name); 03656 continue; 03657 } else 03658 ao2_unlock(cur_queue); 03659 03660 if (ast_db_get(pm_family, queue_name, queue_data, PM_MAX_LEN)) 03661 continue; 03662 03663 cur_ptr = queue_data; 03664 while ((member = strsep(&cur_ptr, "|"))) { 03665 if (ast_strlen_zero(member)) 03666 continue; 03667 03668 interface = strsep(&member, ";"); 03669 penalty_tok = strsep(&member, ";"); 03670 paused_tok = strsep(&member, ";"); 03671 membername = strsep(&member, ";"); 03672 state_interface = strsep(&member,";"); 03673 03674 if (!penalty_tok) { 03675 ast_log(LOG_WARNING, "Error parsing persistent member string for '%s' (penalty)\n", queue_name); 03676 break; 03677 } 03678 penalty = strtol(penalty_tok, NULL, 10); 03679 if (errno == ERANGE) { 03680 ast_log(LOG_WARNING, "Error converting penalty: %s: Out of range.\n", penalty_tok); 03681 break; 03682 } 03683 03684 if (!paused_tok) { 03685 ast_log(LOG_WARNING, "Error parsing persistent member string for '%s' (paused)\n", queue_name); 03686 break; 03687 } 03688 paused = strtol(paused_tok, NULL, 10); 03689 if ((errno == ERANGE) || paused < 0 || paused > 1) { 03690 ast_log(LOG_WARNING, "Error converting paused: %s: Expected 0 or 1.\n", paused_tok); 03691 break; 03692 } 03693 if (ast_strlen_zero(membername)) 03694 membername = interface; 03695 03696 if (option_debug) 03697 ast_log(LOG_DEBUG, "Reload Members: Queue: %s Member: %s Name: %s Penalty: %d Paused: %d\n", queue_name, interface, membername, penalty, paused); 03698 03699 if (add_to_queue(queue_name, interface, membername, penalty, paused, 0, state_interface) == RES_OUTOFMEMORY) { 03700 ast_log(LOG_ERROR, "Out of Memory when reloading persistent queue member\n"); 03701 break; 03702 } 03703 } 03704 } 03705 03706 AST_LIST_UNLOCK(&queues); 03707 if (db_tree) { 03708 ast_log(LOG_NOTICE, "Queue members successfully reloaded from database.\n"); 03709 ast_db_freetree(db_tree); 03710 } 03711 }
static int reload_queues | ( | void | ) | [static] |
Definition at line 4533 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_load(), ast_copy_string(), AST_DECLARE_APP_ARGS, ast_free, AST_LIST_INSERT_HEAD, AST_LIST_LOCK, AST_LIST_TRAVERSE, 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(), LOG_NOTICE, LOG_WARNING, call_queue::membercount, call_queue::members, call_queue::name, parse(), member::paused, queue_set_param(), QUEUE_STRATEGY_ROUNDROBIN, call_queue::realtime, remove_from_interfaces(), rr_dep_warning(), member::state_interface, call_queue::strategy, and var.
Referenced by load_module(), and reload().
04534 { 04535 struct call_queue *q; 04536 struct ast_config *cfg; 04537 char *cat, *tmp; 04538 struct ast_variable *var; 04539 struct member *cur, *newm; 04540 struct ao2_iterator mem_iter; 04541 int new; 04542 const char *general_val = NULL; 04543 char *parse; 04544 char *interface, *state_interface; 04545 char *membername = NULL; 04546 int penalty; 04547 AST_DECLARE_APP_ARGS(args, 04548 AST_APP_ARG(interface); 04549 AST_APP_ARG(penalty); 04550 AST_APP_ARG(membername); 04551 AST_APP_ARG(state_interface); 04552 ); 04553 04554 if (!(cfg = ast_config_load("queues.conf"))) { 04555 ast_log(LOG_NOTICE, "No call queueing config file (queues.conf), so no call queues\n"); 04556 return 0; 04557 } 04558 AST_LIST_LOCK(&queues); 04559 use_weight=0; 04560 /* Mark all non-realtime queues as dead for the moment */ 04561 AST_LIST_TRAVERSE(&queues, q, list) { 04562 if (!q->realtime) { 04563 q->dead = 1; 04564 q->found = 0; 04565 } 04566 } 04567 04568 /* Chug through config file */ 04569 cat = NULL; 04570 while ((cat = ast_category_browse(cfg, cat)) ) { 04571 if (!strcasecmp(cat, "general")) { 04572 /* Initialize global settings */ 04573 queue_debug = 0; 04574 if ((general_val = ast_variable_retrieve(cfg, "general", "debug"))) 04575 queue_debug = ast_true(general_val); 04576 queue_persistent_members = 0; 04577 if ((general_val = ast_variable_retrieve(cfg, "general", "persistentmembers"))) 04578 queue_persistent_members = ast_true(general_val); 04579 autofill_default = 0; 04580 if ((general_val = ast_variable_retrieve(cfg, "general", "autofill"))) 04581 autofill_default = ast_true(general_val); 04582 montype_default = 0; 04583 if ((general_val = ast_variable_retrieve(cfg, "general", "monitor-type"))) 04584 if (!strcasecmp(general_val, "mixmonitor")) 04585 montype_default = 1; 04586 } else { /* Define queue */ 04587 /* Look for an existing one */ 04588 AST_LIST_TRAVERSE(&queues, q, list) { 04589 if (!strcmp(q->name, cat)) 04590 break; 04591 } 04592 if (!q) { 04593 /* Make one then */ 04594 if (!(q = alloc_queue(cat))) { 04595 /* TODO: Handle memory allocation failure */ 04596 } 04597 new = 1; 04598 } else 04599 new = 0; 04600 if (q) { 04601 if (!new) 04602 ao2_lock(q); 04603 /* Check if a queue with this name already exists */ 04604 if (q->found) { 04605 ast_log(LOG_WARNING, "Queue '%s' already defined! Skipping!\n", cat); 04606 if (!new) 04607 ao2_unlock(q); 04608 continue; 04609 } 04610 /* Re-initialize the queue, and clear statistics */ 04611 init_queue(q); 04612 clear_queue(q); 04613 mem_iter = ao2_iterator_init(q->members, 0); 04614 while ((cur = ao2_iterator_next(&mem_iter))) { 04615 if (!cur->dynamic) { 04616 cur->delme = 1; 04617 } 04618 ao2_ref(cur, -1); 04619 } 04620 ao2_iterator_destroy(&mem_iter); 04621 for (var = ast_variable_browse(cfg, cat); var; var = var->next) { 04622 if (!strcasecmp(var->name, "member")) { 04623 struct member tmpmem; 04624 membername = NULL; 04625 04626 if (ast_strlen_zero(var->value)) { 04627 ast_log(LOG_WARNING, "Empty queue member definition at line %d. Moving on!\n", var->lineno); 04628 continue; 04629 } 04630 04631 /* Add a new member */ 04632 if (!(parse = ast_strdup(var->value))) { 04633 continue; 04634 } 04635 04636 AST_NONSTANDARD_APP_ARGS(args, parse, ','); 04637 04638 interface = args.interface; 04639 if (!ast_strlen_zero(args.penalty)) { 04640 tmp = ast_skip_blanks(args.penalty); 04641 penalty = atoi(tmp); 04642 if (penalty < 0) { 04643 penalty = 0; 04644 } 04645 } else 04646 penalty = 0; 04647 04648 if (!ast_strlen_zero(args.membername)) { 04649 membername = ast_skip_blanks(args.membername); 04650 } 04651 04652 if (!ast_strlen_zero(args.state_interface)) { 04653 state_interface = ast_skip_blanks(args.state_interface); 04654 } else { 04655 state_interface = interface; 04656 } 04657 04658 /* Find the old position in the list */ 04659 ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface)); 04660 cur = ao2_find(q->members, &tmpmem, OBJ_POINTER | OBJ_UNLINK); 04661 04662 /* Only attempt removing from interfaces list if the new state_interface is different than the old one */ 04663 if (cur && strcasecmp(cur->state_interface, state_interface)) { 04664 remove_from_interfaces(cur->state_interface); 04665 } 04666 04667 newm = create_queue_member(interface, membername, penalty, cur ? cur->paused : 0, state_interface); 04668 if (!cur || (cur && strcasecmp(cur->state_interface, state_interface))) { 04669 add_to_interfaces(state_interface); 04670 } 04671 ao2_link(q->members, newm); 04672 ao2_ref(newm, -1); 04673 newm = NULL; 04674 04675 if (cur) 04676 ao2_ref(cur, -1); 04677 else { 04678 q->membercount++; 04679 } 04680 ast_free(parse); 04681 } else { 04682 queue_set_param(q, var->name, var->value, var->lineno, 1); 04683 } 04684 } 04685 04686 /* Free remaining members marked as delme */ 04687 mem_iter = ao2_iterator_init(q->members, 0); 04688 while ((cur = ao2_iterator_next(&mem_iter))) { 04689 if (! cur->delme) { 04690 ao2_ref(cur, -1); 04691 continue; 04692 } 04693 04694 q->membercount--; 04695 ao2_unlink(q->members, cur); 04696 remove_from_interfaces(cur->state_interface); 04697 ao2_ref(cur, -1); 04698 } 04699 ao2_iterator_destroy(&mem_iter); 04700 04701 if (q->strategy == QUEUE_STRATEGY_ROUNDROBIN) 04702 rr_dep_warning(); 04703 04704 if (new) { 04705 AST_LIST_INSERT_HEAD(&queues, q, list); 04706 } else 04707 ao2_unlock(q); 04708 } 04709 } 04710 } 04711 ast_config_destroy(cfg); 04712 AST_LIST_TRAVERSE_SAFE_BEGIN(&queues, q, list) { 04713 if (q->dead) { 04714 AST_LIST_REMOVE_CURRENT(&queues, list); 04715 ao2_ref(q, -1); 04716 } else { 04717 ao2_lock(q); 04718 mem_iter = ao2_iterator_init(q->members, 0); 04719 while ((cur = ao2_iterator_next(&mem_iter))) { 04720 if (cur->dynamic) 04721 q->membercount++; 04722 cur->status = ast_device_state(cur->state_interface); 04723 ao2_ref(cur, -1); 04724 } 04725 ao2_iterator_destroy(&mem_iter); 04726 ao2_unlock(q); 04727 } 04728 } 04729 AST_LIST_TRAVERSE_SAFE_END; 04730 AST_LIST_UNLOCK(&queues); 04731 return 1; 04732 }
static int remove_from_interfaces | ( | const char * | interface | ) | [static] |
Definition at line 971 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(), member_interface::list, LOG_DEBUG, and option_debug.
Referenced by free_members(), reload_queues(), remove_from_queue(), rt_handle_member_record(), and update_realtime_members().
00972 { 00973 struct member_interface *curint; 00974 00975 if (interface_exists_global(interface)) 00976 return 0; 00977 00978 AST_LIST_LOCK(&interfaces); 00979 AST_LIST_TRAVERSE_SAFE_BEGIN(&interfaces, curint, list) { 00980 if (!strcasecmp(curint->interface, interface)) { 00981 if (option_debug) 00982 ast_log(LOG_DEBUG, "Removing %s from the list of interfaces that make up all of our queue members.\n", interface); 00983 AST_LIST_REMOVE_CURRENT(&interfaces, list); 00984 free(curint); 00985 break; 00986 } 00987 } 00988 AST_LIST_TRAVERSE_SAFE_END; 00989 AST_LIST_UNLOCK(&interfaces); 00990 00991 return 0; 00992 }
static int remove_from_queue | ( | const char * | queuename, | |
const char * | interface | |||
) | [static] |
Definition at line 3464 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 attempt_thread(), handle_queue_remove_member(), manager_remove_queue_member(), rqm_exec(), and scan_service().
03465 { 03466 struct call_queue *q; 03467 struct member *mem, tmpmem; 03468 int res = RES_NOSUCHQUEUE; 03469 03470 ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface)); 03471 03472 AST_LIST_LOCK(&queues); 03473 AST_LIST_TRAVERSE(&queues, q, list) { 03474 ao2_lock(q); 03475 if (strcmp(q->name, queuename)) { 03476 ao2_unlock(q); 03477 continue; 03478 } 03479 03480 if ((mem = ao2_find(q->members, &tmpmem, OBJ_POINTER))) { 03481 /* XXX future changes should beware of this assumption!! */ 03482 if (!mem->dynamic) { 03483 res = RES_NOT_DYNAMIC; 03484 ao2_ref(mem, -1); 03485 ao2_unlock(q); 03486 break; 03487 } 03488 q->membercount--; 03489 manager_event(EVENT_FLAG_AGENT, "QueueMemberRemoved", 03490 "Queue: %s\r\n" 03491 "Location: %s\r\n" 03492 "MemberName: %s\r\n", 03493 q->name, mem->interface, mem->membername); 03494 ao2_unlink(q->members, mem); 03495 remove_from_interfaces(mem->state_interface); 03496 ao2_ref(mem, -1); 03497 03498 if (queue_persistent_members) 03499 dump_queue_members(q); 03500 03501 res = RES_OKAY; 03502 } else { 03503 res = RES_EXISTS; 03504 } 03505 ao2_unlock(q); 03506 break; 03507 } 03508 03509 AST_LIST_UNLOCK(&queues); 03510 03511 return res; 03512 }
static void remove_queue | ( | struct call_queue * | q | ) | [static] |
removes a call_queue from the list of call_queues
Definition at line 525 of file app_queue.c.
References ao2_ref(), AST_LIST_LOCK, AST_LIST_REMOVE, AST_LIST_UNLOCK, and member_interface::list.
Referenced by find_queue_by_name_rt(), and leave_queue().
00526 { 00527 AST_LIST_LOCK(&queues); 00528 if (AST_LIST_REMOVE(&queues, q, list)) { 00529 ao2_ref(q, -1); 00530 } 00531 AST_LIST_UNLOCK(&queues); 00532 }
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 1901 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_state(), 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, LOG_DEBUG, LOG_NOTICE, manager_event(), callattempt::member, member::membername, ast_channel::name, call_queue::name, ast_channel::nativeformats, option_debug, option_verbose, queue_ent::parent, member::paused, pbx_builtin_getvar_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().
01902 { 01903 int res; 01904 int status; 01905 char tech[256]; 01906 char *location; 01907 const char *macrocontext, *macroexten; 01908 01909 /* on entry here, we know that tmp->chan == NULL */ 01910 if (qe->parent->wrapuptime && (time(NULL) - tmp->lastcall < qe->parent->wrapuptime)) { 01911 if (queue_debug) 01912 ast_log(LOG_NOTICE, "Wrapuptime not yet expired for %s\n", tmp->interface); 01913 if (qe->chan->cdr) 01914 ast_cdr_busy(qe->chan->cdr); 01915 tmp->stillgoing = 0; 01916 (*busies)++; 01917 return 0; 01918 } 01919 01920 if (!qe->parent->ringinuse && (tmp->member->status != AST_DEVICE_NOT_INUSE) && (tmp->member->status != AST_DEVICE_UNKNOWN)) { 01921 if (queue_debug) 01922 ast_log(LOG_NOTICE, "%s in use, can't receive call\n", tmp->interface); 01923 if (qe->chan->cdr) 01924 ast_cdr_busy(qe->chan->cdr); 01925 tmp->stillgoing = 0; 01926 return 0; 01927 } 01928 01929 if (tmp->member->paused) { 01930 if (queue_debug) 01931 ast_log(LOG_NOTICE, "%s paused, can't receive call\n", tmp->interface); 01932 if (qe->chan->cdr) 01933 ast_cdr_busy(qe->chan->cdr); 01934 tmp->stillgoing = 0; 01935 return 0; 01936 } 01937 if (use_weight && compare_weight(qe->parent,tmp->member)) { 01938 if (queue_debug) 01939 ast_log(LOG_NOTICE, "Priority queue delaying call to %s:%s\n", qe->parent->name, tmp->interface); 01940 if (qe->chan->cdr) 01941 ast_cdr_busy(qe->chan->cdr); 01942 tmp->stillgoing = 0; 01943 (*busies)++; 01944 return 0; 01945 } 01946 01947 ast_copy_string(tech, tmp->interface, sizeof(tech)); 01948 if ((location = strchr(tech, '/'))) 01949 *location++ = '\0'; 01950 else 01951 location = ""; 01952 01953 /* Request the peer */ 01954 tmp->chan = ast_request(tech, qe->chan->nativeformats, location, &status); 01955 if (!tmp->chan) { /* If we can't, just go on to the next call */ 01956 if (queue_debug) 01957 ast_log(LOG_NOTICE, "Unable to create channel of type '%s' for Queue\n", tech); 01958 if (qe->chan->cdr) 01959 ast_cdr_busy(qe->chan->cdr); 01960 tmp->stillgoing = 0; 01961 01962 update_status(tmp->member->state_interface, ast_device_state(tmp->member->state_interface)); 01963 01964 ao2_lock(qe->parent); 01965 qe->parent->rrpos++; 01966 ao2_unlock(qe->parent); 01967 01968 (*busies)++; 01969 return 0; 01970 } 01971 01972 /* Increment ring count */ 01973 tmp->member->ringcount++; 01974 tmp->chan->appl = "AppQueue"; 01975 tmp->chan->data = "(Outgoing Line)"; 01976 tmp->chan->whentohangup = 0; 01977 if (tmp->chan->cid.cid_num) 01978 free(tmp->chan->cid.cid_num); 01979 tmp->chan->cid.cid_num = ast_strdup(qe->chan->cid.cid_num); 01980 if (tmp->chan->cid.cid_name) 01981 free(tmp->chan->cid.cid_name); 01982 tmp->chan->cid.cid_name = ast_strdup(qe->chan->cid.cid_name); 01983 if (tmp->chan->cid.cid_ani) 01984 free(tmp->chan->cid.cid_ani); 01985 tmp->chan->cid.cid_ani = ast_strdup(qe->chan->cid.cid_ani); 01986 01987 /* Inherit specially named variables from parent channel */ 01988 ast_channel_inherit_variables(qe->chan, tmp->chan); 01989 ast_channel_datastore_inherit(qe->chan, tmp->chan); 01990 01991 /* Presense of ADSI CPE on outgoing channel follows ours */ 01992 tmp->chan->adsicpe = qe->chan->adsicpe; 01993 01994 /* Inherit context and extension */ 01995 ast_channel_lock(qe->chan); 01996 macrocontext = pbx_builtin_getvar_helper(qe->chan, "MACRO_CONTEXT"); 01997 if (!ast_strlen_zero(macrocontext)) 01998 ast_copy_string(tmp->chan->dialcontext, macrocontext, sizeof(tmp->chan->dialcontext)); 01999 else 02000 ast_copy_string(tmp->chan->dialcontext, qe->chan->context, sizeof(tmp->chan->dialcontext)); 02001 macroexten = pbx_builtin_getvar_helper(qe->chan, "MACRO_EXTEN"); 02002 if (!ast_strlen_zero(macroexten)) 02003 ast_copy_string(tmp->chan->exten, macroexten, sizeof(tmp->chan->exten)); 02004 else 02005 ast_copy_string(tmp->chan->exten, qe->chan->exten, sizeof(tmp->chan->exten)); 02006 if (ast_cdr_isset_unanswered()) { 02007 /* they want to see the unanswered dial attempts! */ 02008 /* set up the CDR fields on all the CDRs to give sensical information */ 02009 ast_cdr_setdestchan(tmp->chan->cdr, tmp->chan->name); 02010 strcpy(tmp->chan->cdr->clid, qe->chan->cdr->clid); 02011 strcpy(tmp->chan->cdr->channel, qe->chan->cdr->channel); 02012 strcpy(tmp->chan->cdr->src, qe->chan->cdr->src); 02013 strcpy(tmp->chan->cdr->dst, qe->chan->exten); 02014 strcpy(tmp->chan->cdr->dcontext, qe->chan->context); 02015 strcpy(tmp->chan->cdr->lastapp, qe->chan->cdr->lastapp); 02016 strcpy(tmp->chan->cdr->lastdata, qe->chan->cdr->lastdata); 02017 tmp->chan->cdr->amaflags = qe->chan->cdr->amaflags; 02018 strcpy(tmp->chan->cdr->accountcode, qe->chan->cdr->accountcode); 02019 strcpy(tmp->chan->cdr->userfield, qe->chan->cdr->userfield); 02020 } 02021 ast_channel_unlock(qe->chan); 02022 02023 /* Place the call, but don't wait on the answer */ 02024 if ((res = ast_call(tmp->chan, location, 0))) { 02025 /* Again, keep going even if there's an error */ 02026 if (option_debug) 02027 ast_log(LOG_DEBUG, "ast call on peer returned %d\n", res); 02028 if (option_verbose > 2) 02029 ast_verbose(VERBOSE_PREFIX_3 "Couldn't call %s\n", tmp->interface); 02030 do_hang(tmp); 02031 (*busies)++; 02032 update_status(tmp->member->state_interface, ast_device_state(tmp->member->state_interface)); 02033 return 0; 02034 } else if (qe->parent->eventwhencalled) { 02035 char vars[2048]; 02036 02037 manager_event(EVENT_FLAG_AGENT, "AgentCalled", 02038 "AgentCalled: %s\r\n" 02039 "AgentName: %s\r\n" 02040 "ChannelCalling: %s\r\n" 02041 "CallerID: %s\r\n" 02042 "CallerIDName: %s\r\n" 02043 "Context: %s\r\n" 02044 "Extension: %s\r\n" 02045 "Priority: %d\r\n" 02046 "%s", 02047 tmp->interface, tmp->member->membername, qe->chan->name, 02048 tmp->chan->cid.cid_num ? tmp->chan->cid.cid_num : "unknown", 02049 tmp->chan->cid.cid_name ? tmp->chan->cid.cid_name : "unknown", 02050 qe->chan->context, qe->chan->exten, qe->chan->priority, 02051 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : ""); 02052 if (option_verbose > 2) 02053 ast_verbose(VERBOSE_PREFIX_3 "Called %s\n", tmp->interface); 02054 } 02055 02056 update_status(tmp->member->state_interface, ast_device_state(tmp->member->state_interface)); 02057 return 1; 02058 }
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 2084 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().
02085 { 02086 int ret = 0; 02087 02088 while (ret == 0) { 02089 struct callattempt *best = find_best(outgoing); 02090 if (!best) { 02091 if (option_debug) 02092 ast_log(LOG_DEBUG, "Nobody left to try ringing in queue\n"); 02093 break; 02094 } 02095 if (qe->parent->strategy == QUEUE_STRATEGY_RINGALL) { 02096 struct callattempt *cur; 02097 /* Ring everyone who shares this best metric (for ringall) */ 02098 for (cur = outgoing; cur; cur = cur->q_next) { 02099 if (cur->stillgoing && !cur->chan && cur->metric <= best->metric) { 02100 if (option_debug) 02101 ast_log(LOG_DEBUG, "(Parallel) Trying '%s' with metric %d\n", cur->interface, cur->metric); 02102 ret |= ring_entry(qe, cur, busies); 02103 } 02104 } 02105 } else { 02106 /* Ring just the best channel */ 02107 if (option_debug) 02108 ast_log(LOG_DEBUG, "Trying '%s' with metric %d\n", best->interface, best->metric); 02109 ret = ring_entry(qe, best, busies); 02110 } 02111 } 02112 02113 return ret; 02114 }
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 2198 of file app_queue.c.
References ast_queue_log(), ast_verbose(), call_queue::autopause, queue_ent::chan, call_queue::name, option_verbose, queue_ent::parent, set_member_paused(), ast_channel::uniqueid, and VERBOSE_PREFIX_3.
02199 { 02200 if (option_verbose > 2) 02201 ast_verbose( VERBOSE_PREFIX_3 "Nobody picked up in %d ms\n", rnatime); 02202 ast_queue_log(qe->parent->name, qe->chan->uniqueid, membername, "RINGNOANSWER", "%d", rnatime); 02203 if (qe->parent->autopause && pause) { 02204 if (!set_member_paused(qe->parent->name, interface, 1)) { 02205 if (option_verbose > 2) 02206 ast_verbose( VERBOSE_PREFIX_3 "Auto-Pausing Queue Member %s in queue %s since they failed to answer.\n", interface, qe->parent->name); 02207 } else { 02208 if (option_verbose > 2) 02209 ast_verbose( VERBOSE_PREFIX_3 "Failed to pause Queue Member %s in queue %s!\n", interface, qe->parent->name); 02210 } 02211 } 02212 return; 02213 }
static int rqm_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Definition at line 3829 of file app_queue.c.
References AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_goto_if_exists(), ast_log(), ast_module_user_add, ast_module_user_remove, ast_opt_priority_jumping, ast_queue_log(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), ast_module_user::chan, ast_channel::context, LOG_DEBUG, LOG_NOTICE, LOG_WARNING, ast_channel::name, parse(), pbx_builtin_setvar_helper(), remove_from_queue(), RES_EXISTS, RES_NOSUCHQUEUE, RES_NOT_DYNAMIC, RES_OKAY, and ast_channel::uniqueid.
Referenced by load_module().
03830 { 03831 int res=-1; 03832 struct ast_module_user *lu; 03833 char *parse, *temppos = NULL; 03834 int priority_jump = 0; 03835 AST_DECLARE_APP_ARGS(args, 03836 AST_APP_ARG(queuename); 03837 AST_APP_ARG(interface); 03838 AST_APP_ARG(options); 03839 ); 03840 03841 03842 if (ast_strlen_zero(data)) { 03843 ast_log(LOG_WARNING, "RemoveQueueMember requires an argument (queuename[|interface[|options]])\n"); 03844 return -1; 03845 } 03846 03847 parse = ast_strdupa(data); 03848 03849 AST_STANDARD_APP_ARGS(args, parse); 03850 03851 lu = ast_module_user_add(chan); 03852 03853 if (ast_strlen_zero(args.interface)) { 03854 args.interface = ast_strdupa(chan->name); 03855 temppos = strrchr(args.interface, '-'); 03856 if (temppos) 03857 *temppos = '\0'; 03858 } 03859 03860 if (args.options) { 03861 if (strchr(args.options, 'j')) 03862 priority_jump = 1; 03863 } 03864 03865 switch (remove_from_queue(args.queuename, args.interface)) { 03866 case RES_OKAY: 03867 ast_queue_log(args.queuename, chan->uniqueid, args.interface, "REMOVEMEMBER", "%s", ""); 03868 ast_log(LOG_NOTICE, "Removed interface '%s' from queue '%s'\n", args.interface, args.queuename); 03869 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "REMOVED"); 03870 res = 0; 03871 break; 03872 case RES_EXISTS: 03873 ast_log(LOG_DEBUG, "Unable to remove interface '%s' from queue '%s': Not there\n", args.interface, args.queuename); 03874 if (priority_jump || ast_opt_priority_jumping) 03875 ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101); 03876 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOTINQUEUE"); 03877 res = 0; 03878 break; 03879 case RES_NOSUCHQUEUE: 03880 ast_log(LOG_WARNING, "Unable to remove interface from queue '%s': No such queue\n", args.queuename); 03881 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOSUCHQUEUE"); 03882 res = 0; 03883 break; 03884 case RES_NOT_DYNAMIC: 03885 ast_log(LOG_WARNING, "Unable to remove interface from queue '%s': '%s' is not a dynamic member\n", args.queuename, args.interface); 03886 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOTDYNAMIC"); 03887 res = 0; 03888 break; 03889 } 03890 03891 ast_module_user_remove(lu); 03892 03893 return res; 03894 }
static void rr_dep_warning | ( | void | ) | [static] |
Definition at line 467 of file app_queue.c.
References ast_log(), and LOG_NOTICE.
Referenced by reload_queues().
00468 { 00469 static unsigned int warned = 0; 00470 00471 if (!warned) { 00472 ast_log(LOG_NOTICE, "The 'roundrobin' queue strategy is deprecated. Please use the 'rrmemory' strategy instead.\n"); 00473 warned = 1; 00474 } 00475 }
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 1163 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 update_realtime_members().
01164 { 01165 struct member *m, tmpmem; 01166 int penalty = 0; 01167 int paused = 0; 01168 01169 if (penalty_str) { 01170 penalty = atoi(penalty_str); 01171 if (penalty < 0) 01172 penalty = 0; 01173 } 01174 01175 if (paused_str) { 01176 paused = atoi(paused_str); 01177 if (paused < 0) 01178 paused = 0; 01179 } 01180 01181 /* Find the member, or the place to put a new one. */ 01182 ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface)); 01183 m = ao2_find(q->members, &tmpmem, OBJ_POINTER); 01184 01185 /* Create a new one if not found, else update penalty */ 01186 if (!m) { 01187 if ((m = create_queue_member(interface, membername, penalty, paused, state_interface))) { 01188 m->dead = 0; 01189 m->realtime = 1; 01190 add_to_interfaces(m->state_interface); 01191 ao2_link(q->members, m); 01192 ao2_ref(m, -1); 01193 m = NULL; 01194 q->membercount++; 01195 } 01196 } else { 01197 m->dead = 0; /* Do not delete this one. */ 01198 if (paused_str) 01199 m->paused = paused; 01200 if (strcasecmp(state_interface, m->state_interface)) { 01201 remove_from_interfaces(m->state_interface); 01202 ast_copy_string(m->state_interface, state_interface, sizeof(m->state_interface)); 01203 add_to_interfaces(m->state_interface); 01204 } 01205 m->penalty = penalty; 01206 ao2_ref(m, -1); 01207 } 01208 }
static int say_periodic_announcement | ( | struct queue_ent * | qe | ) | [static] |
Definition at line 2140 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().
02141 { 02142 int res = 0; 02143 time_t now; 02144 02145 /* Get the current time */ 02146 time(&now); 02147 02148 /* Check to see if it is time to announce */ 02149 if ((now - qe->last_periodic_announce_time) < qe->parent->periodicannouncefrequency) 02150 return 0; 02151 02152 /* Stop the music on hold so we can play our own file */ 02153 ast_moh_stop(qe->chan); 02154 02155 if (option_verbose > 2) 02156 ast_verbose(VERBOSE_PREFIX_3 "Playing periodic announcement\n"); 02157 02158 /* Check to make sure we have a sound file. If not, reset to the first sound file */ 02159 if (qe->last_periodic_announce_sound >= MAX_PERIODIC_ANNOUNCEMENTS || !strlen(qe->parent->sound_periodicannounce[qe->last_periodic_announce_sound])) { 02160 qe->last_periodic_announce_sound = 0; 02161 } 02162 02163 /* play the announcement */ 02164 res = play_file(qe->chan, qe->parent->sound_periodicannounce[qe->last_periodic_announce_sound]); 02165 02166 if (res > 0 && !valid_exit(qe, res)) 02167 res = 0; 02168 02169 /* Resume Music on Hold if the caller is going to stay in the queue */ 02170 if (!res) 02171 ast_moh_start(qe->chan, qe->moh, NULL); 02172 02173 /* update last_periodic_announce_time */ 02174 qe->last_periodic_announce_time = now; 02175 02176 /* Update the current periodic announcement to the next announcement */ 02177 qe->last_periodic_announce_sound++; 02178 02179 return res; 02180 }
static int say_position | ( | struct queue_ent * | qe | ) | [static] |
Definition at line 1592 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, ast_channel::language, queue_ent::last_pos, queue_ent::last_pos_said, queue_ent::moh, ast_channel::name, call_queue::name, option_verbose, queue_ent::parent, play_file(), queue_ent::pos, call_queue::roundingseconds, call_queue::sound_calls, call_queue::sound_holdtime, call_queue::sound_lessthan, call_queue::sound_minutes, call_queue::sound_next, call_queue::sound_seconds, call_queue::sound_thanks, call_queue::sound_thereare, queue_ent::start, valid_exit(), and VERBOSE_PREFIX_3.
Referenced by queue_exec(), and wait_our_turn().
01593 { 01594 int res = 0, avgholdmins, avgholdsecs; 01595 time_t now; 01596 01597 /* Check to see if this is ludicrous -- if we just announced position, don't do it again*/ 01598 time(&now); 01599 if ((now - qe->last_pos) < 15) 01600 return 0; 01601 01602 /* If either our position has changed, or we are over the freq timer, say position */ 01603 if ((qe->last_pos_said == qe->pos) && ((now - qe->last_pos) < qe->parent->announcefrequency)) 01604 return 0; 01605 01606 ast_moh_stop(qe->chan); 01607 /* Say we're next, if we are */ 01608 if (qe->pos == 1) { 01609 res = play_file(qe->chan, qe->parent->sound_next); 01610 if (res) 01611 goto playout; 01612 else 01613 goto posout; 01614 } else { 01615 res = play_file(qe->chan, qe->parent->sound_thereare); 01616 if (res) 01617 goto playout; 01618 res = ast_say_number(qe->chan, qe->pos, AST_DIGIT_ANY, qe->chan->language, (char *) NULL); /* Needs gender */ 01619 if (res) 01620 goto playout; 01621 res = play_file(qe->chan, qe->parent->sound_calls); 01622 if (res) 01623 goto playout; 01624 } 01625 /* Round hold time to nearest minute */ 01626 avgholdmins = abs(((qe->parent->holdtime + 30) - (now - qe->start)) / 60); 01627 01628 /* If they have specified a rounding then round the seconds as well */ 01629 if (qe->parent->roundingseconds) { 01630 avgholdsecs = (abs(((qe->parent->holdtime + 30) - (now - qe->start))) - 60 * avgholdmins) / qe->parent->roundingseconds; 01631 avgholdsecs *= qe->parent->roundingseconds; 01632 } else { 01633 avgholdsecs = 0; 01634 } 01635 01636 if (option_verbose > 2) 01637 ast_verbose(VERBOSE_PREFIX_3 "Hold time for %s is %d minutes %d seconds\n", qe->parent->name, avgholdmins, avgholdsecs); 01638 01639 /* If the hold time is >1 min, if it's enabled, and if it's not 01640 supposed to be only once and we have already said it, say it */ 01641 if ((avgholdmins+avgholdsecs) > 0 && qe->parent->announceholdtime && 01642 ((qe->parent->announceholdtime == ANNOUNCEHOLDTIME_ONCE && !qe->last_pos) || 01643 !(qe->parent->announceholdtime == ANNOUNCEHOLDTIME_ONCE))) { 01644 res = play_file(qe->chan, qe->parent->sound_holdtime); 01645 if (res) 01646 goto playout; 01647 01648 if (avgholdmins > 0) { 01649 if (avgholdmins < 2) { 01650 res = play_file(qe->chan, qe->parent->sound_lessthan); 01651 if (res) 01652 goto playout; 01653 01654 res = ast_say_number(qe->chan, 2, AST_DIGIT_ANY, qe->chan->language, NULL); 01655 if (res) 01656 goto playout; 01657 } else { 01658 res = ast_say_number(qe->chan, avgholdmins, AST_DIGIT_ANY, qe->chan->language, NULL); 01659 if (res) 01660 goto playout; 01661 } 01662 01663 res = play_file(qe->chan, qe->parent->sound_minutes); 01664 if (res) 01665 goto playout; 01666 } 01667 if (avgholdsecs>0) { 01668 res = ast_say_number(qe->chan, avgholdsecs, AST_DIGIT_ANY, qe->chan->language, NULL); 01669 if (res) 01670 goto playout; 01671 01672 res = play_file(qe->chan, qe->parent->sound_seconds); 01673 if (res) 01674 goto playout; 01675 } 01676 01677 } 01678 01679 posout: 01680 if (option_verbose > 2) 01681 ast_verbose(VERBOSE_PREFIX_3 "Told %s in %s their queue position (which was %d)\n", 01682 qe->chan->name, qe->parent->name, qe->pos); 01683 res = play_file(qe->chan, qe->parent->sound_thanks); 01684 01685 playout: 01686 01687 if ((res > 0 && !valid_exit(qe, res))) 01688 res = 0; 01689 01690 /* Set our last_pos indicators */ 01691 qe->last_pos = now; 01692 qe->last_pos_said = qe->pos; 01693 01694 /* Don't restart music on hold if we're about to exit the caller from the queue */ 01695 if (!res) 01696 ast_moh_start(qe->chan, qe->moh, NULL); 01697 01698 return res; 01699 }
static int set_member_paused | ( | const char * | queuename, | |
const char * | interface, | |||
int | paused | |||
) | [static] |
Definition at line 3570 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().
03571 { 03572 int found = 0; 03573 struct call_queue *q; 03574 struct member *mem; 03575 03576 /* Special event for when all queues are paused - individual events still generated */ 03577 /* XXX In all other cases, we use the membername, but since this affects all queues, we cannot */ 03578 if (ast_strlen_zero(queuename)) 03579 ast_queue_log("NONE", "NONE", interface, (paused ? "PAUSEALL" : "UNPAUSEALL"), "%s", ""); 03580 03581 AST_LIST_LOCK(&queues); 03582 AST_LIST_TRAVERSE(&queues, q, list) { 03583 ao2_lock(q); 03584 if (ast_strlen_zero(queuename) || !strcasecmp(q->name, queuename)) { 03585 if ((mem = interface_exists(q, interface))) { 03586 found++; 03587 if (mem->paused == paused) 03588 ast_log(LOG_DEBUG, "%spausing already-%spaused queue member %s:%s\n", (paused ? "" : "un"), (paused ? "" : "un"), q->name, interface); 03589 mem->paused = paused; 03590 03591 if (queue_persistent_members) 03592 dump_queue_members(q); 03593 03594 if (mem->realtime) 03595 update_realtime_member_field(mem, q->name, "paused", paused ? "1" : "0"); 03596 03597 ast_queue_log(q->name, "NONE", mem->membername, (paused ? "PAUSE" : "UNPAUSE"), "%s", ""); 03598 03599 manager_event(EVENT_FLAG_AGENT, "QueueMemberPaused", 03600 "Queue: %s\r\n" 03601 "Location: %s\r\n" 03602 "MemberName: %s\r\n" 03603 "Paused: %d\r\n", 03604 q->name, mem->interface, mem->membername, paused); 03605 ao2_ref(mem, -1); 03606 } 03607 } 03608 ao2_unlock(q); 03609 } 03610 AST_LIST_UNLOCK(&queues); 03611 03612 return found ? RESULT_SUCCESS : RESULT_FAILURE; 03613 }
static void set_queue_result | ( | struct ast_channel * | chan, | |
enum queue_result | res | |||
) | [static] |
sets the QUEUESTATUS channel variable
Definition at line 486 of file app_queue.c.
References queue_ent::chan, pbx_builtin_setvar_helper(), queue_results, and text.
Referenced by queue_exec().
00487 { 00488 int i; 00489 00490 for (i = 0; i < sizeof(queue_results) / sizeof(queue_results[0]); i++) { 00491 if (queue_results[i].id == res) { 00492 pbx_builtin_setvar_helper(chan, "QUEUESTATUS", queue_results[i].text); 00493 return; 00494 } 00495 } 00496 }
static struct ast_datastore* setup_transfer_datastore | ( | struct queue_ent * | qe, | |
struct member * | member, | |||
time_t | starttime, | |||
int | callcompletedinsl | |||
) | [static] |
create a datastore for storing relevant info to log attended transfers in the queue_log
Definition at line 2761 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_ent::chan, ast_datastore::data, LOG_WARNING, queue_transfer_ds::member, queue_transfer_ds::qe, and queue_transfer_info.
02762 { 02763 struct ast_datastore *ds; 02764 struct queue_transfer_ds *qtds = ast_calloc(1, sizeof(*qtds)); 02765 02766 if (!qtds) { 02767 ast_log(LOG_WARNING, "Memory allocation error!\n"); 02768 return NULL; 02769 } 02770 02771 ast_channel_lock(qe->chan); 02772 if (!(ds = ast_channel_datastore_alloc(&queue_transfer_info, NULL))) { 02773 ast_channel_unlock(qe->chan); 02774 ast_log(LOG_WARNING, "Unable to create transfer datastore. queue_log will not show attended transfer\n"); 02775 return NULL; 02776 } 02777 02778 qtds->qe = qe; 02779 /* This member is refcounted in try_calling, so no need to add it here, too */ 02780 qtds->member = member; 02781 qtds->starttime = starttime; 02782 qtds->callcompletedinsl = callcompletedinsl; 02783 ds->data = qtds; 02784 ast_channel_datastore_add(qe->chan, ds); 02785 ast_channel_unlock(qe->chan); 02786 return ds; 02787 }
static int statechange_queue | ( | const char * | dev, | |
int | state, | |||
void * | ign | |||
) | [static] |
Producer of the statechange queue.
Definition at line 774 of file app_queue.c.
References ast_calloc, ast_cond_signal(), AST_LIST_INSERT_TAIL, ast_mutex_lock(), ast_mutex_unlock(), device_state, and statechange::entry.
Referenced by load_module(), and unload_module().
00775 { 00776 struct statechange *sc; 00777 00778 if (!(sc = ast_calloc(1, sizeof(*sc) + strlen(dev) + 1))) 00779 return 0; 00780 00781 sc->state = state; 00782 strcpy(sc->dev, dev); 00783 00784 ast_mutex_lock(&device_state.lock); 00785 AST_LIST_INSERT_TAIL(&device_state.state_change_q, sc, entry); 00786 ast_cond_signal(&device_state.cond); 00787 ast_mutex_unlock(&device_state.lock); 00788 00789 return 0; 00790 }
static int store_next | ( | struct queue_ent * | qe, | |
struct callattempt * | outgoing | |||
) | [static] |
Definition at line 2116 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().
02117 { 02118 struct callattempt *best = find_best(outgoing); 02119 02120 if (best) { 02121 /* Ring just the best channel */ 02122 if (option_debug) 02123 ast_log(LOG_DEBUG, "Next is '%s' with metric %d\n", best->interface, best->metric); 02124 qe->parent->rrpos = best->metric % 1000; 02125 } else { 02126 /* Just increment rrpos */ 02127 if (qe->parent->wrapped) { 02128 /* No more channels, start over */ 02129 qe->parent->rrpos = 0; 02130 } else { 02131 /* Prioritize next entry */ 02132 qe->parent->rrpos++; 02133 } 02134 } 02135 qe->parent->wrapped = 0; 02136 02137 return 0; 02138 }
static int strat2int | ( | const char * | strategy | ) | [static] |
Definition at line 510 of file app_queue.c.
References name, and strategies.
Referenced by queue_set_param().
00511 { 00512 int x; 00513 00514 for (x = 0; x < sizeof(strategies) / sizeof(strategies[0]); x++) { 00515 if (!strcasecmp(strategy, strategies[x].name)) 00516 return strategies[x].strategy; 00517 } 00518 00519 return -1; 00520 }
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 2814 of file app_queue.c.
References ast_channel::_state, queue_ent::announce, ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next(), ao2_lock(), ao2_ref(), ao2_unlock(), ast_calloc, AST_CDR_FLAG_DONT_TOUCH, AST_CDR_FLAG_POST_DISABLED, ast_cdr_isset_unanswered(), ast_cdr_noanswer(), 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_unlock, ast_copy_string(), AST_FEATURE_AUTOMON, AST_FEATURE_DISCONNECT, AST_FEATURE_REDIRECT, 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_set_flag, AST_STATE_UP, ast_strlen_zero(), ast_test_flag, calc_metric(), ast_channel::cdr, callattempt::chan, queue_ent::chan, ast_datastore::data, DATASTORE_INHERIT_FOREVER, di, dialed_interface_info, ast_cdr::dstchannel, EVENT_FLAG_AGENT, call_queue::eventwhencalled, queue_ent::expire, free, ast_datastore::inheritance, member::interface, member::lastcall, ast_dialed_interface::list, LOG_DEBUG, LOG_NOTICE, manager_event(), call_queue::membercount, call_queue::members, call_queue::name, ast_channel::name, option_debug, queue_ent::parent, queue_ent::pending, callattempt::q_next, QUEUE_STRATEGY_ROUNDROBIN, ring_one(), member::ringcount, call_queue::ringlimit, queue_ent::start, member::status, store_next(), call_queue::strategy, call_queue::timeout, queue_ent::tries, ast_channel::uniqueid, and wait_for_answer().
Referenced by queue_exec().
02815 { 02816 struct member *cur; 02817 struct callattempt *outgoing = NULL; /* the list of calls we are building */ 02818 int to; 02819 char oldexten[AST_MAX_EXTENSION]=""; 02820 char oldcontext[AST_MAX_CONTEXT]=""; 02821 char queuename[256]=""; 02822 struct ast_channel *peer; 02823 struct ast_channel *which; 02824 struct callattempt *lpeer; 02825 struct member *member; 02826 struct ast_app *app; 02827 int res = 0, bridge = 0; 02828 int numbusies = 0; 02829 int x=0; 02830 char *announce = NULL; 02831 char digit = 0; 02832 time_t callstart; 02833 time_t now = time(NULL); 02834 struct ast_bridge_config bridge_config; 02835 char nondataquality = 1; 02836 char *agiexec = NULL; 02837 int ret = 0; 02838 const char *monitorfilename; 02839 const char *monitor_exec; 02840 const char *monitor_options; 02841 char tmpid[256], tmpid2[256]; 02842 char meid[1024], meid2[1024]; 02843 char mixmonargs[1512]; 02844 struct ast_app *mixmonapp = NULL; 02845 char *p; 02846 char vars[2048]; 02847 int forwardsallowed = 1; 02848 int callcompletedinsl; 02849 struct ao2_iterator memi; 02850 struct ast_datastore *datastore, *transfer_ds; 02851 02852 ast_channel_lock(qe->chan); 02853 datastore = ast_channel_datastore_find(qe->chan, &dialed_interface_info, NULL); 02854 ast_channel_unlock(qe->chan); 02855 02856 memset(&bridge_config, 0, sizeof(bridge_config)); 02857 time(&now); 02858 02859 /* If we've already exceeded our timeout, then just stop 02860 * This should be extremely rare. queue_exec will take care 02861 * of removing the caller and reporting the timeout as the reason. 02862 */ 02863 if (qe->expire && now >= qe->expire) { 02864 res = 0; 02865 goto out; 02866 } 02867 02868 for (; options && *options; options++) 02869 switch (*options) { 02870 case 't': 02871 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_REDIRECT); 02872 break; 02873 case 'T': 02874 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_REDIRECT); 02875 break; 02876 case 'w': 02877 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_AUTOMON); 02878 break; 02879 case 'W': 02880 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_AUTOMON); 02881 break; 02882 case 'd': 02883 nondataquality = 0; 02884 break; 02885 case 'h': 02886 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_DISCONNECT); 02887 break; 02888 case 'H': 02889 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT); 02890 break; 02891 case 'n': 02892 if (qe->parent->strategy == QUEUE_STRATEGY_ROUNDROBIN || qe->parent->strategy == QUEUE_STRATEGY_RRMEMORY) 02893 (*tries)++; 02894 else 02895 *tries = qe->parent->membercount; 02896 *noption = 1; 02897 break; 02898 case 'i': 02899 forwardsallowed = 0; 02900 break; 02901 } 02902 02903 /* Hold the lock while we setup the outgoing calls */ 02904 if (use_weight) 02905 AST_LIST_LOCK(&queues); 02906 ao2_lock(qe->parent); 02907 if (option_debug) 02908 ast_log(LOG_DEBUG, "%s is trying to call a queue member.\n", 02909 qe->chan->name); 02910 ast_copy_string(queuename, qe->parent->name, sizeof(queuename)); 02911 if (!ast_strlen_zero(qe->announce)) 02912 announce = qe->announce; 02913 if (!ast_strlen_zero(announceoverride)) 02914 announce = announceoverride; 02915 02916 memi = ao2_iterator_init(qe->parent->members, 0); 02917 while ((cur = ao2_iterator_next(&memi))) { 02918 struct callattempt *tmp = ast_calloc(1, sizeof(*tmp)); 02919 struct ast_dialed_interface *di; 02920 AST_LIST_HEAD(, ast_dialed_interface) *dialed_interfaces; 02921 if (!tmp) { 02922 ao2_iterator_destroy(&memi); 02923 ao2_ref(cur, -1); 02924 ao2_unlock(qe->parent); 02925 if (use_weight) 02926 AST_LIST_UNLOCK(&queues); 02927 goto out; 02928 } 02929 if (!datastore) { 02930 if (!(datastore = ast_channel_datastore_alloc(&dialed_interface_info, NULL))) { 02931 ao2_iterator_destroy(&memi); 02932 ao2_ref(cur, -1); 02933 ao2_unlock(qe->parent); 02934 if (use_weight) 02935 AST_LIST_UNLOCK(&queues); 02936 free(tmp); 02937 goto out; 02938 } 02939 datastore->inheritance = DATASTORE_INHERIT_FOREVER; 02940 if (!(dialed_interfaces = ast_calloc(1, sizeof(*dialed_interfaces)))) { 02941 ao2_iterator_destroy(&memi); 02942 ao2_ref(cur, -1); 02943 ao2_unlock(qe->parent); 02944 if (use_weight) 02945 AST_LIST_UNLOCK(&queues); 02946 free(tmp); 02947 goto out; 02948 } 02949 datastore->data = dialed_interfaces; 02950 AST_LIST_HEAD_INIT(dialed_interfaces); 02951 02952 ast_channel_lock(qe->chan); 02953 ast_channel_datastore_add(qe->chan, datastore); 02954 ast_channel_unlock(qe->chan); 02955 } else 02956 dialed_interfaces = datastore->data; 02957 02958 AST_LIST_LOCK(dialed_interfaces); 02959 AST_LIST_TRAVERSE(dialed_interfaces, di, list) { 02960 if (!strcasecmp(cur->interface, di->interface)) { 02961 ast_log(LOG_DEBUG, "Skipping dialing interface '%s' since it has already been dialed\n", 02962 di->interface); 02963 break; 02964 } 02965 } 02966 AST_LIST_UNLOCK(dialed_interfaces); 02967 02968 if (di) { 02969 free(tmp); 02970 continue; 02971 } 02972 02973 /* It is always ok to dial a Local interface. We only keep track of 02974 * which "real" interfaces have been dialed. The Local channel will 02975 * inherit this list so that if it ends up dialing a real interface, 02976 * it won't call one that has already been called. */ 02977 if (strncasecmp(cur->interface, "Local/", 6)) { 02978 if (!(di = ast_calloc(1, sizeof(*di) + strlen(cur->interface)))) { 02979 ao2_iterator_destroy(&memi); 02980 ao2_ref(cur, -1); 02981 ao2_unlock(qe->parent); 02982 if (use_weight) 02983 AST_LIST_UNLOCK(&queues); 02984 free(tmp); 02985 goto out; 02986 } 02987 strcpy(di->interface, cur->interface); 02988 02989 AST_LIST_LOCK(dialed_interfaces); 02990 AST_LIST_INSERT_TAIL(dialed_interfaces, di, list); 02991 AST_LIST_UNLOCK(dialed_interfaces); 02992 } 02993 02994 tmp->stillgoing = -1; 02995 tmp->member = cur; 02996 tmp->oldstatus = cur->status; 02997 tmp->lastcall = cur->lastcall; 02998 ast_copy_string(tmp->interface, cur->interface, sizeof(tmp->interface)); 02999 if (qe->tries == 0 && (cur->ringcount >= qe->parent->ringlimit)) { 03000 cur->ringcount = 0; 03001 } 03002 /* Special case: If we ring everyone, go ahead and ring them, otherwise 03003 just calculate their metric for the appropriate strategy */ 03004 if (!calc_metric(qe->parent, cur, x++, qe, tmp)) { 03005 /* Put them in the list of outgoing thingies... We're ready now. 03006 XXX If we're forcibly removed, these outgoing calls won't get 03007 hung up XXX */ 03008 tmp->q_next = outgoing; 03009 outgoing = tmp; 03010 /* If this line is up, don't try anybody else */ 03011 if (outgoing->chan && (outgoing->chan->_state == AST_STATE_UP)) 03012 break; 03013 } else { 03014 ao2_ref(cur, -1); 03015 free(tmp); 03016 } 03017 } 03018 ao2_iterator_destroy(&memi); 03019 if (qe->expire && (!qe->parent->timeout || (qe->expire - now) <= qe->parent->timeout)) 03020 to = (qe->expire - now) * 1000; 03021 else 03022 to = (qe->parent->timeout) ? qe->parent->timeout * 1000 : -1; 03023 ++qe->pending; 03024 ++qe->tries; 03025 if (option_debug) 03026 ast_log(LOG_DEBUG, "%s is trying to ring one member from %s. This is try number %d\n", 03027 qe->chan->name, queuename, qe->tries); 03028 ao2_unlock(qe->parent); 03029 ring_one(qe, outgoing, &numbusies); 03030 if (use_weight) 03031 AST_LIST_UNLOCK(&queues); 03032 lpeer = wait_for_answer(qe, outgoing, &to, &digit, numbusies, ast_test_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT), forwardsallowed); 03033 /* The ast_channel_datastore_remove() function could fail here if the 03034 * datastore was moved to another channel during a masquerade. If this is 03035 * the case, don't free the datastore here because later, when the channel 03036 * to which the datastore was moved hangs up, it will attempt to free this 03037 * datastore again, causing a crash 03038 */ 03039 ast_channel_lock(qe->chan); 03040 if (datastore && !ast_channel_datastore_remove(qe->chan, datastore)) { 03041 ast_channel_datastore_free(datastore); 03042 } 03043 ast_channel_unlock(qe->chan); 03044 ao2_lock(qe->parent); 03045 if (qe->parent->strategy == QUEUE_STRATEGY_RRMEMORY) { 03046 store_next(qe, outgoing); 03047 } 03048 ao2_unlock(qe->parent); 03049 peer = lpeer ? lpeer->chan : NULL; 03050 if (!peer) { 03051 qe->pending = 0; 03052 if (to) { 03053 /* Must gotten hung up */ 03054 res = -1; 03055 } else { 03056 /* User exited by pressing a digit */ 03057 res = digit; 03058 } 03059 if (res == -1) { 03060 /* Post this CDR, and mark call as NOANSWER */ 03061 ast_set_flag(qe->chan->cdr, AST_CDR_FLAG_DONT_TOUCH); 03062 ast_cdr_noanswer(qe->chan->cdr); 03063 if (queue_debug) 03064 ast_log(LOG_NOTICE, "%s: Nobody answered.\n", qe->chan->name); 03065 } 03066 if (qe->parent->eventwhencalled) { 03067 manager_event(EVENT_FLAG_AGENT, "AgentTimeout", 03068 "Queue: %s\r\n" 03069 "ChannelCalling: %s\r\n" 03070 "Uniqueid: %s\r\n" 03071 "Tries: %d\r\n" 03072 "Holdtime: %ld\r\n", 03073 queuename, qe->chan->name, qe->chan->uniqueid, qe->tries, 03074 (long)time(NULL) - qe->start); 03075 } 03076 if (ast_cdr_isset_unanswered()) { 03077 /* channel contains the name of one of the outgoing channels 03078 in its CDR; zero out this CDR to avoid a dual-posting */ 03079 struct callattempt *o; 03080 for (o = outgoing; o; o = o->q_next) { 03081 if (!o->chan) { 03082 continue; 03083 } 03084 if (strcmp(o->chan->cdr->dstchannel, qe->chan->cdr->dstchannel) == 0) { 03085 ast_set_flag(o->chan->cdr, AST_CDR_FLAG_POST_DISABLED); 03086 break; 03087 } 03088 } 03089 } 03090 } else { /* peer is valid */ 03091 /* Ah ha! Someone answered within the desired timeframe. Of course after this 03092 we will always return with -1 so that it is hung up properly after the 03093 conversation. */ 03094 if (!strcmp(qe->chan->tech->type, "Zap")) 03095 ast_channel_setoption(qe->chan, AST_OPTION_TONE_VERIFY, &nondataquality, sizeof(nondataquality), 0); 03096 if (!strcmp(peer->tech->type, "Zap")) 03097 ast_channel_setoption(peer, AST_OPTION_TONE_VERIFY, &nondataquality, sizeof(nondataquality), 0); 03098 /* Update parameters for the queue */ 03099 time(&now); 03100 recalc_holdtime(qe, (now - qe->start)); 03101 ao2_lock(qe->parent); 03102 callcompletedinsl = ((now - qe->start) <= qe->parent->servicelevel); 03103 ao2_unlock(qe->parent); 03104 member = lpeer->member; 03105 /* Increment the refcount for this member, since we're going to be using it for awhile in here. */ 03106 ao2_ref(member, 1); 03107 hangupcalls(outgoing, peer); 03108 outgoing = NULL; 03109 if (announce || qe->parent->reportholdtime || qe->parent->memberdelay) { 03110 int res2; 03111 03112 res2 = ast_autoservice_start(qe->chan); 03113 if (!res2) { 03114 if (qe->parent->memberdelay) { 03115 ast_log(LOG_NOTICE, "Delaying member connect for %d seconds\n", qe->parent->memberdelay); 03116 res2 |= ast_safe_sleep(peer, qe->parent->memberdelay * 1000); 03117 } 03118 if (!res2 && announce) { 03119 play_file(peer, announce); 03120 } 03121 if (!res2 && qe->parent->reportholdtime) { 03122 if (!play_file(peer, qe->parent->sound_reporthold)) { 03123 int holdtime; 03124 03125 time(&now); 03126 holdtime = abs((now - qe->start) / 60); 03127 if (holdtime < 2) { 03128 play_file(peer, qe->parent->sound_lessthan); 03129 ast_say_number(peer, 2, AST_DIGIT_ANY, peer->language, NULL); 03130 } else 03131 ast_say_number(peer, holdtime, AST_DIGIT_ANY, peer->language, NULL); 03132 play_file(peer, qe->parent->sound_minutes); 03133 } 03134 } 03135 } 03136 res2 |= ast_autoservice_stop(qe->chan); 03137 if (peer->_softhangup) { 03138 /* Agent must have hung up */ 03139 ast_log(LOG_WARNING, "Agent on %s hungup on the customer.\n", peer->name); 03140 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "AGENTDUMP", "%s", ""); 03141 if (qe->parent->eventwhencalled) 03142 manager_event(EVENT_FLAG_AGENT, "AgentDump", 03143 "Queue: %s\r\n" 03144 "Uniqueid: %s\r\n" 03145 "Channel: %s\r\n" 03146 "Member: %s\r\n" 03147 "MemberName: %s\r\n" 03148 "%s", 03149 queuename, qe->chan->uniqueid, peer->name, member->interface, member->membername, 03150 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : ""); 03151 ast_hangup(peer); 03152 ao2_ref(member, -1); 03153 goto out; 03154 } else if (res2) { 03155 /* Caller must have hung up just before being connected*/ 03156 ast_log(LOG_NOTICE, "Caller was about to talk to agent on %s but the caller hungup.\n", peer->name); 03157 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "ABANDON", "%d|%d|%ld", qe->pos, qe->opos, (long)time(NULL) - qe->start); 03158 record_abandoned(qe); 03159 ast_cdr_noanswer(qe->chan->cdr); 03160 ast_hangup(peer); 03161 ao2_ref(member, -1); 03162 return -1; 03163 } 03164 } 03165 /* Stop music on hold */ 03166 ast_moh_stop(qe->chan); 03167 /* If appropriate, log that we have a destination channel */ 03168 if (qe->chan->cdr) 03169 ast_cdr_setdestchan(qe->chan->cdr, peer->name); 03170 /* Make sure channels are compatible */ 03171 res = ast_channel_make_compatible(qe->chan, peer); 03172 if (res < 0) { 03173 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "SYSCOMPAT", "%s", ""); 03174 ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", qe->chan->name, peer->name); 03175 record_abandoned(qe); 03176 ast_cdr_failed(qe->chan->cdr); 03177 ast_hangup(peer); 03178 ao2_ref(member, -1); 03179 return -1; 03180 } 03181 03182 if (qe->parent->setinterfacevar) 03183 pbx_builtin_setvar_helper(qe->chan, "MEMBERINTERFACE", member->interface); 03184 03185 /* Begin Monitoring */ 03186 if (qe->parent->monfmt && *qe->parent->monfmt) { 03187 if (!qe->parent->montype) { 03188 if (option_debug) 03189 ast_log(LOG_DEBUG, "Starting Monitor as requested.\n"); 03190 monitorfilename = pbx_builtin_getvar_helper(qe->chan, "MONITOR_FILENAME"); 03191 if (pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC") || pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC_ARGS")) 03192 which = qe->chan; 03193 else 03194 which = peer; 03195 if (monitorfilename) 03196 ast_monitor_start(which, qe->parent->monfmt, monitorfilename, 1 ); 03197 else if (qe->chan->cdr) 03198 ast_monitor_start(which, qe->parent->monfmt, qe->chan->cdr->uniqueid, 1 ); 03199 else { 03200 /* Last ditch effort -- no CDR, make up something */ 03201 snprintf(tmpid, sizeof(tmpid), "chan-%lx", ast_random()); 03202 ast_monitor_start(which, qe->parent->monfmt, tmpid, 1 ); 03203 } 03204 if (qe->parent->monjoin) 03205 ast_monitor_setjoinfiles(which, 1); 03206 } else { 03207 if (option_debug) 03208 ast_log(LOG_DEBUG, "Starting MixMonitor as requested.\n"); 03209 monitorfilename = pbx_builtin_getvar_helper(qe->chan, "MONITOR_FILENAME"); 03210 if (!monitorfilename) { 03211 if (qe->chan->cdr) 03212 ast_copy_string(tmpid, qe->chan->cdr->uniqueid, sizeof(tmpid)-1); 03213 else 03214 snprintf(tmpid, sizeof(tmpid), "chan-%lx", ast_random()); 03215 } else { 03216 ast_copy_string(tmpid2, monitorfilename, sizeof(tmpid2)-1); 03217 for (p = tmpid2; *p ; p++) { 03218 if (*p == '^' && *(p+1) == '{') { 03219 *p = '$'; 03220 } 03221 } 03222 03223 memset(tmpid, 0, sizeof(tmpid)); 03224 pbx_substitute_variables_helper(qe->chan, tmpid2, tmpid, sizeof(tmpid) - 1); 03225 } 03226 03227 monitor_exec = pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC"); 03228 monitor_options = pbx_builtin_getvar_helper(qe->chan, "MONITOR_OPTIONS"); 03229 03230 if (monitor_exec) { 03231 ast_copy_string(meid2, monitor_exec, sizeof(meid2)-1); 03232 for (p = meid2; *p ; p++) { 03233 if (*p == '^' && *(p+1) == '{') { 03234 *p = '$'; 03235 } 03236 } 03237 03238 memset(meid, 0, sizeof(meid)); 03239 pbx_substitute_variables_helper(qe->chan, meid2, meid, sizeof(meid) - 1); 03240 } 03241 03242 snprintf(tmpid2, sizeof(tmpid2)-1, "%s.%s", tmpid, qe->parent->monfmt); 03243 03244 mixmonapp = pbx_findapp("MixMonitor"); 03245 03246 if (strchr(tmpid2, '|')) { 03247 ast_log(LOG_WARNING, "monitor-format (in queues.conf) and MONITOR_FILENAME cannot contain a '|'! Not recording.\n"); 03248 mixmonapp = NULL; 03249 } 03250 03251 if (!monitor_options) 03252 monitor_options = ""; 03253 03254 if (strchr(monitor_options, '|')) { 03255 ast_log(LOG_WARNING, "MONITOR_OPTIONS cannot contain a '|'! Not recording.\n"); 03256 mixmonapp = NULL; 03257 } 03258 03259 if (mixmonapp) { 03260 if (!ast_strlen_zero(monitor_exec)) 03261 snprintf(mixmonargs, sizeof(mixmonargs)-1, "%s|b%s|%s", tmpid2, monitor_options, monitor_exec); 03262 else 03263 snprintf(mixmonargs, sizeof(mixmonargs)-1, "%s|b%s", tmpid2, monitor_options); 03264 03265 if (option_debug) 03266 ast_log(LOG_DEBUG, "Arguments being passed to MixMonitor: %s\n", mixmonargs); 03267 /* We purposely lock the CDR so that pbx_exec does not update the application data */ 03268 if (qe->chan->cdr) 03269 ast_set_flag(qe->chan->cdr, AST_CDR_FLAG_LOCKED); 03270 ret = pbx_exec(qe->chan, mixmonapp, mixmonargs); 03271 if (qe->chan->cdr) 03272 ast_clear_flag(qe->chan->cdr, AST_CDR_FLAG_LOCKED); 03273 03274 } else 03275 ast_log(LOG_WARNING, "Asked to run MixMonitor on this call, but cannot find the MixMonitor app!\n"); 03276 03277 } 03278 } 03279 /* Drop out of the queue at this point, to prepare for next caller */ 03280 leave_queue(qe); 03281 if (!ast_strlen_zero(url) && ast_channel_supports_html(peer)) { 03282 if (option_debug) 03283 ast_log(LOG_DEBUG, "app_queue: sendurl=%s.\n", url); 03284 ast_channel_sendurl(peer, url); 03285 } 03286 if (!ast_strlen_zero(agi)) { 03287 if (option_debug) 03288 ast_log(LOG_DEBUG, "app_queue: agi=%s.\n", agi); 03289 app = pbx_findapp("agi"); 03290 if (app) { 03291 agiexec = ast_strdupa(agi); 03292 ret = pbx_exec(qe->chan, app, agiexec); 03293 } else 03294 ast_log(LOG_WARNING, "Asked to execute an AGI on this channel, but could not find application (agi)!\n"); 03295 } 03296 qe->handled++; 03297 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "CONNECT", "%ld|%s", (long)time(NULL) - qe->start, peer->uniqueid); 03298 if (qe->parent->eventwhencalled) 03299 manager_event(EVENT_FLAG_AGENT, "AgentConnect", 03300 "Queue: %s\r\n" 03301 "Uniqueid: %s\r\n" 03302 "Channel: %s\r\n" 03303 "Member: %s\r\n" 03304 "MemberName: %s\r\n" 03305 "Holdtime: %ld\r\n" 03306 "BridgedChannel: %s\r\n" 03307 "%s", 03308 queuename, qe->chan->uniqueid, peer->name, member->interface, member->membername, 03309 (long)time(NULL) - qe->start, peer->uniqueid, 03310 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : ""); 03311 ast_copy_string(oldcontext, qe->chan->context, sizeof(oldcontext)); 03312 ast_copy_string(oldexten, qe->chan->exten, sizeof(oldexten)); 03313 time(&callstart); 03314 03315 if (member->status == AST_DEVICE_NOT_INUSE) 03316 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); 03317 03318 transfer_ds = setup_transfer_datastore(qe, member, callstart, callcompletedinsl); 03319 bridge = ast_bridge_call(qe->chan,peer, &bridge_config); 03320 03321 ast_channel_lock(qe->chan); 03322 if (!attended_transfer_occurred(qe->chan)) { 03323 struct ast_datastore *tds; 03324 03325 /* detect a blind transfer */ 03326 if (!(qe->chan->_softhangup | peer->_softhangup) && (strcasecmp(oldcontext, qe->chan->context) || strcasecmp(oldexten, qe->chan->exten))) { 03327 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "TRANSFER", "%s|%s|%ld|%ld", 03328 qe->chan->exten, qe->chan->context, (long) (callstart - qe->start), 03329 (long) (time(NULL) - callstart)); 03330 } else if (qe->chan->_softhangup) { 03331 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "COMPLETECALLER", "%ld|%ld|%d", 03332 (long) (callstart - qe->start), (long) (time(NULL) - callstart), qe->opos); 03333 if (qe->parent->eventwhencalled) 03334 manager_event(EVENT_FLAG_AGENT, "AgentComplete", 03335 "Queue: %s\r\n" 03336 "Uniqueid: %s\r\n" 03337 "Channel: %s\r\n" 03338 "Member: %s\r\n" 03339 "MemberName: %s\r\n" 03340 "HoldTime: %ld\r\n" 03341 "TalkTime: %ld\r\n" 03342 "Reason: caller\r\n" 03343 "%s", 03344 queuename, qe->chan->uniqueid, peer->name, member->interface, member->membername, 03345 (long)(callstart - qe->start), (long)(time(NULL) - callstart), 03346 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : ""); 03347 } else { 03348 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "COMPLETEAGENT", "%ld|%ld|%d", 03349 (long) (callstart - qe->start), (long) (time(NULL) - callstart), qe->opos); 03350 if (qe->parent->eventwhencalled) 03351 manager_event(EVENT_FLAG_AGENT, "AgentComplete", 03352 "Queue: %s\r\n" 03353 "Uniqueid: %s\r\n" 03354 "Channel: %s\r\n" 03355 "MemberName: %s\r\n" 03356 "HoldTime: %ld\r\n" 03357 "TalkTime: %ld\r\n" 03358 "Reason: agent\r\n" 03359 "%s", 03360 queuename, qe->chan->uniqueid, peer->name, member->membername, (long)(callstart - qe->start), 03361 (long)(time(NULL) - callstart), 03362 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : ""); 03363 } 03364 if ((tds = ast_channel_datastore_find(qe->chan, &queue_transfer_info, NULL))) { 03365 ast_channel_datastore_remove(qe->chan, tds); 03366 } 03367 update_queue(qe->parent, member, callcompletedinsl); 03368 } 03369 03370 if (transfer_ds) { 03371 ast_channel_datastore_free(transfer_ds); 03372 } 03373 ast_channel_unlock(qe->chan); 03374 ast_hangup(peer); 03375 res = bridge ? bridge : 1; 03376 ao2_ref(member, -1); 03377 } 03378 out: 03379 hangupcalls(outgoing, NULL); 03380 03381 return res; 03382 }
static int unload_module | ( | void | ) | [static] |
Definition at line 5479 of file app_queue.c.
References ast_cli_unregister_multiple(), ast_cond_signal(), ast_custom_function_unregister(), ast_devstate_del(), ast_manager_unregister(), ast_module_user_hangup_all, ast_mutex_lock(), ast_mutex_unlock(), AST_PTHREADT_NULL, ast_unregister_application(), clear_and_free_interfaces(), cli_queue, device_state, queueagentcount_function, queuemembercount_function, queuememberlist_function, queuewaitingcount_function, and statechange_queue().
05480 { 05481 int res; 05482 05483 if (device_state.thread != AST_PTHREADT_NULL) { 05484 device_state.stop = 1; 05485 ast_mutex_lock(&device_state.lock); 05486 ast_cond_signal(&device_state.cond); 05487 ast_mutex_unlock(&device_state.lock); 05488 pthread_join(device_state.thread, NULL); 05489 } 05490 05491 ast_cli_unregister_multiple(cli_queue, sizeof(cli_queue) / sizeof(struct ast_cli_entry)); 05492 res = ast_manager_unregister("QueueStatus"); 05493 res |= ast_manager_unregister("Queues"); 05494 res |= ast_manager_unregister("QueueAdd"); 05495 res |= ast_manager_unregister("QueueRemove"); 05496 res |= ast_manager_unregister("QueuePause"); 05497 res |= ast_unregister_application(app_aqm); 05498 res |= ast_unregister_application(app_rqm); 05499 res |= ast_unregister_application(app_pqm); 05500 res |= ast_unregister_application(app_upqm); 05501 res |= ast_unregister_application(app_ql); 05502 res |= ast_unregister_application(app); 05503 res |= ast_custom_function_unregister(&queueagentcount_function); 05504 res |= ast_custom_function_unregister(&queuemembercount_function); 05505 res |= ast_custom_function_unregister(&queuememberlist_function); 05506 res |= ast_custom_function_unregister(&queuewaitingcount_function); 05507 ast_devstate_del(statechange_queue, NULL); 05508 05509 ast_module_user_hangup_all(); 05510 05511 clear_and_free_interfaces(); 05512 05513 return res; 05514 }
static int update_queue | ( | struct call_queue * | q, | |
struct member * | member, | |||
int | callcompletedinsl | |||
) | [static] |
Definition at line 2614 of file app_queue.c.
References ao2_lock(), ao2_unlock(), member::calls, call_queue::callscompleted, call_queue::callscompletedinsl, and member::lastcall.
Referenced by queue_transfer_fixup().
02615 { 02616 ao2_lock(q); 02617 time(&member->lastcall); 02618 member->calls++; 02619 q->callscompleted++; 02620 if (callcompletedinsl) 02621 q->callscompletedinsl++; 02622 ao2_unlock(q); 02623 return 0; 02624 }
static int update_realtime_member_field | ( | struct member * | mem, | |
const char * | queue_name, | |||
const char * | field, | |||
const char * | value | |||
) | [static] |
Definition at line 1354 of file app_queue.c.
References ast_load_realtime(), ast_strlen_zero(), ast_update_realtime(), ast_variables_destroy(), member::interface, and var.
Referenced by set_member_paused().
01355 { 01356 struct ast_variable *var, *save; 01357 int ret = -1; 01358 01359 if (!(var = ast_load_realtime("queue_members", "interface", mem->interface, "queue_name", queue_name, NULL))) 01360 return ret; 01361 save = var; 01362 while (var) { 01363 if (!strcmp(var->name, "uniqueid")) 01364 break; 01365 var = var->next; 01366 } 01367 if (var && !ast_strlen_zero(var->value)) { 01368 if ((ast_update_realtime("queue_members", "uniqueid", var->value, field, value, NULL)) > -1) 01369 ret = 0; 01370 } 01371 ast_variables_destroy(save); 01372 return ret; 01373 }
static void update_realtime_members | ( | struct call_queue * | q | ) | [static] |
Definition at line 1375 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().
01376 { 01377 struct ast_config *member_config = NULL; 01378 struct member *m; 01379 char *interface = NULL; 01380 struct ao2_iterator mem_iter; 01381 01382 if (!(member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name", q->name , NULL))) { 01383 /*This queue doesn't have realtime members*/ 01384 if (option_debug > 2) 01385 ast_log(LOG_DEBUG, "Queue %s has no realtime members defined. No need for update\n", q->name); 01386 return; 01387 } 01388 01389 ao2_lock(q); 01390 01391 /* Temporarily set realtime members dead so we can detect deleted ones.*/ 01392 mem_iter = ao2_iterator_init(q->members, 0); 01393 while ((m = ao2_iterator_next(&mem_iter))) { 01394 if (m->realtime) 01395 m->dead = 1; 01396 ao2_ref(m, -1); 01397 } 01398 ao2_iterator_destroy(&mem_iter); 01399 01400 while ((interface = ast_category_browse(member_config, interface))) { 01401 rt_handle_member_record(q, interface, 01402 S_OR(ast_variable_retrieve(member_config, interface, "membername"), interface), 01403 ast_variable_retrieve(member_config, interface, "penalty"), 01404 ast_variable_retrieve(member_config, interface, "paused"), 01405 S_OR(ast_variable_retrieve(member_config, interface, "state_interface"), interface)); 01406 } 01407 01408 /* Delete all realtime members that have been deleted in DB. */ 01409 mem_iter = ao2_iterator_init(q->members, 0); 01410 while ((m = ao2_iterator_next(&mem_iter))) { 01411 if (m->dead) { 01412 ao2_unlink(q->members, m); 01413 ao2_unlock(q); 01414 remove_from_interfaces(m->state_interface); 01415 ao2_lock(q); 01416 q->membercount--; 01417 } 01418 ao2_ref(m, -1); 01419 } 01420 ao2_iterator_destroy(&mem_iter); 01421 ao2_unlock(q); 01422 ast_config_destroy(member_config); 01423 }
static int update_status | ( | const char * | interface, | |
const int | status | |||
) | [static] |
Definition at line 625 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, member_interface::list, 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().
00626 { 00627 struct member *cur; 00628 struct ao2_iterator mem_iter; 00629 struct call_queue *q; 00630 char tmp_interface[80]; 00631 00632 AST_LIST_LOCK(&queues); 00633 AST_LIST_TRAVERSE(&queues, q, list) { 00634 ao2_lock(q); 00635 mem_iter = ao2_iterator_init(q->members, 0); 00636 while ((cur = ao2_iterator_next(&mem_iter))) { 00637 char *slash_pos; 00638 ast_copy_string(tmp_interface, cur->state_interface, sizeof(tmp_interface)); 00639 if ((slash_pos = strchr(tmp_interface, '/'))) 00640 if ((slash_pos = strchr(slash_pos + 1, '/'))) 00641 *slash_pos = '\0'; 00642 00643 if (strcasecmp(interface, tmp_interface)) { 00644 ao2_ref(cur, -1); 00645 continue; 00646 } 00647 00648 if (cur->status != status) { 00649 cur->status = status; 00650 if (q->maskmemberstatus) { 00651 ao2_ref(cur, -1); 00652 continue; 00653 } 00654 00655 manager_event(EVENT_FLAG_AGENT, "QueueMemberStatus", 00656 "Queue: %s\r\n" 00657 "Location: %s\r\n" 00658 "MemberName: %s\r\n" 00659 "Membership: %s\r\n" 00660 "Penalty: %d\r\n" 00661 "CallsTaken: %d\r\n" 00662 "LastCall: %d\r\n" 00663 "Status: %d\r\n" 00664 "Paused: %d\r\n", 00665 q->name, cur->interface, cur->membername, cur->dynamic ? "dynamic" : cur->realtime ? "realtime" : "static", 00666 cur->penalty, cur->calls, (int)cur->lastcall, cur->status, cur->paused); 00667 } 00668 ao2_ref(cur, -1); 00669 } 00670 ao2_iterator_destroy(&mem_iter); 00671 ao2_unlock(q); 00672 } 00673 AST_LIST_UNLOCK(&queues); 00674 00675 return 0; 00676 }
static int upqm_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Definition at line 3771 of file app_queue.c.
References AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_goto_if_exists(), ast_log(), ast_module_user_add, ast_module_user_remove, ast_opt_priority_jumping, AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), ast_module_user::chan, ast_channel::context, ast_channel::exten, LOG_WARNING, parse(), pbx_builtin_setvar_helper(), ast_channel::priority, and set_member_paused().
Referenced by load_module().
03772 { 03773 struct ast_module_user *lu; 03774 char *parse; 03775 int priority_jump = 0; 03776 int ignore_fail = 0; 03777 AST_DECLARE_APP_ARGS(args, 03778 AST_APP_ARG(queuename); 03779 AST_APP_ARG(interface); 03780 AST_APP_ARG(options); 03781 ); 03782 03783 if (ast_strlen_zero(data)) { 03784 ast_log(LOG_WARNING, "UnpauseQueueMember requires an argument ([queuename]|interface[|options])\n"); 03785 return -1; 03786 } 03787 03788 parse = ast_strdupa(data); 03789 03790 AST_STANDARD_APP_ARGS(args, parse); 03791 03792 lu = ast_module_user_add(chan); 03793 03794 if (args.options) { 03795 if (strchr(args.options, 'j')) 03796 priority_jump = 1; 03797 if (strchr(args.options, 'i')) 03798 ignore_fail = 1; 03799 } 03800 03801 if (ast_strlen_zero(args.interface)) { 03802 ast_log(LOG_WARNING, "Missing interface argument to PauseQueueMember ([queuename]|interface[|options])\n"); 03803 ast_module_user_remove(lu); 03804 return -1; 03805 } 03806 03807 if (set_member_paused(args.queuename, args.interface, 0)) { 03808 ast_log(LOG_WARNING, "Attempt to unpause interface %s, not found\n", args.interface); 03809 pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "NOTFOUND"); 03810 if (priority_jump || ast_opt_priority_jumping) { 03811 if (!ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101)) { 03812 ast_module_user_remove(lu); 03813 return 0; 03814 } 03815 } 03816 ast_module_user_remove(lu); 03817 if (ignore_fail) { 03818 return 0; 03819 } else { 03820 return -1; 03821 } 03822 } 03823 03824 ast_module_user_remove(lu); 03825 pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "UNPAUSED"); 03826 return 0; 03827 }
static int valid_exit | ( | struct queue_ent * | qe, | |
char | digit | |||
) | [static] |
Definition at line 1559 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(), and wait_our_turn().
01560 { 01561 int digitlen = strlen(qe->digits); 01562 01563 /* Prevent possible buffer overflow */ 01564 if (digitlen < sizeof(qe->digits) - 2) { 01565 qe->digits[digitlen] = digit; 01566 qe->digits[digitlen + 1] = '\0'; 01567 } else { 01568 qe->digits[0] = '\0'; 01569 return 0; 01570 } 01571 01572 /* If there's no context to goto, short-circuit */ 01573 if (ast_strlen_zero(qe->context)) 01574 return 0; 01575 01576 /* If the extension is bad, then reset the digits to blank */ 01577 if (!ast_canmatch_extension(qe->chan, qe->context, qe->digits, 1, qe->chan->cid.cid_num)) { 01578 qe->digits[0] = '\0'; 01579 return 0; 01580 } 01581 01582 /* We have an exact match */ 01583 if (!ast_goto_if_exists(qe->chan, qe->context, qe->digits, 1)) { 01584 qe->valid_digits = 1; 01585 /* Return 1 on a successful goto */ 01586 return 1; 01587 } 01588 01589 return 0; 01590 }
static char* vars2manager | ( | struct ast_channel * | chan, | |
char * | vars, | |||
size_t | len | |||
) | [static] |
Definition at line 1861 of file app_queue.c.
References ast_copy_string(), and pbx_builtin_serialize_variables().
Referenced by ring_entry().
01862 { 01863 char *tmp = alloca(len); 01864 01865 if (pbx_builtin_serialize_variables(chan, tmp, len)) { 01866 int i, j; 01867 01868 /* convert "\n" to "\nVariable: " */ 01869 strcpy(vars, "Variable: "); 01870 01871 for (i = 0, j = 10; (i < len - 1) && (j < len - 1); i++, j++) { 01872 vars[j] = tmp[i]; 01873 01874 if (tmp[i + 1] == '\0') 01875 break; 01876 if (tmp[i] == '\n') { 01877 vars[j++] = '\r'; 01878 vars[j++] = '\n'; 01879 01880 ast_copy_string(&(vars[j]), "Variable: ", len - j); 01881 j += 9; 01882 } 01883 } 01884 if (j > len - 3) 01885 j = len - 3; 01886 vars[j++] = '\r'; 01887 vars[j++] = '\n'; 01888 vars[j] = '\0'; 01889 } else { 01890 /* there are no channel variables; leave it blank */ 01891 *vars = '\0'; 01892 } 01893 return vars; 01894 }
static int wait_a_bit | ( | struct queue_ent * | qe | ) | [static] |
Definition at line 3384 of file app_queue.c.
References ast_waitfordigit(), queue_ent::chan, queue_ent::parent, call_queue::retry, and valid_exit().
Referenced by queue_exec().
03385 { 03386 /* Don't need to hold the lock while we setup the outgoing calls */ 03387 int retrywait = qe->parent->retry * 1000; 03388 03389 int res = ast_waitfordigit(qe->chan, retrywait); 03390 if (res > 0 && !valid_exit(qe, res)) 03391 res = 0; 03392 03393 return res; 03394 }
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] |
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 2226 of file app_queue.c.
References AST_MAX_WATCHERS, callattempt::call_next, callattempt::chan, queue_ent::chan, f, call_queue::name, queue_ent::parent, callattempt::q_next, QUEUE_STRATEGY_RINGALL, ring_one(), starttime, callattempt::stillgoing, and call_queue::strategy.
02227 { 02228 char *queue = qe->parent->name; 02229 struct callattempt *o, *start = NULL, *prev = NULL; 02230 int status; 02231 int numbusies = prebusies; 02232 int numnochan = 0; 02233 int stillgoing = 0; 02234 int orig = *to; 02235 struct ast_frame *f; 02236 struct callattempt *peer = NULL; 02237 struct ast_channel *winner; 02238 struct ast_channel *in = qe->chan; 02239 char on[80] = ""; 02240 char membername[80] = ""; 02241 long starttime = 0; 02242 long endtime = 0; 02243 02244 starttime = (long) time(NULL); 02245 02246 while (*to && !peer) { 02247 int numlines, retry, pos = 1; 02248 struct ast_channel *watchers[AST_MAX_WATCHERS]; 02249 watchers[0] = in; 02250 start = NULL; 02251 02252 for (retry = 0; retry < 2; retry++) { 02253 numlines = 0; 02254 for (o = outgoing; o; o = o->q_next) { /* Keep track of important channels */ 02255 if (o->stillgoing) { /* Keep track of important channels */ 02256 stillgoing = 1; 02257 if (o->chan) { 02258 watchers[pos++] = o->chan; 02259 if (!start) 02260 start = o; 02261 else 02262 prev->call_next = o; 02263 prev = o; 02264 } 02265 } 02266 numlines++; 02267 } 02268 if (pos > 1 /* found */ || !stillgoing /* nobody listening */ || 02269 (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) /* ring would not be delivered */) 02270 break; 02271 /* On "ringall" strategy we only move to the next penalty level 02272 when *all* ringing phones are done in the current penalty level */ 02273 ring_one(qe, outgoing, &numbusies); 02274 /* and retry... */ 02275 } 02276 if (pos == 1 /* not found */) { 02277 if (numlines == (numbusies + numnochan)) { 02278 ast_log(LOG_DEBUG, "Everyone is busy at this time\n"); 02279 } else { 02280 ast_log(LOG_NOTICE, "No one is answering queue '%s' (%d/%d/%d)\n", queue, numlines, numbusies, numnochan); 02281 } 02282 *to = 0; 02283 return NULL; 02284 } 02285 02286 /* Poll for events from both the incoming channel as well as any outgoing channels */ 02287 winner = ast_waitfor_n(watchers, pos, to); 02288 02289 /* Service all of the outgoing channels */ 02290 for (o = start; o; o = o->call_next) { 02291 if (o->stillgoing && (o->chan) && (o->chan->_state == AST_STATE_UP)) { 02292 if (!peer) { 02293 if (option_verbose > 2) 02294 ast_verbose( VERBOSE_PREFIX_3 "%s answered %s\n", o->chan->name, in->name); 02295 peer = o; 02296 } 02297 } else if (o->chan && (o->chan == winner)) { 02298 02299 ast_copy_string(on, o->member->interface, sizeof(on)); 02300 ast_copy_string(membername, o->member->membername, sizeof(membername)); 02301 02302 if (!ast_strlen_zero(o->chan->call_forward) && !forwardsallowed) { 02303 if (option_verbose > 2) 02304 ast_verbose(VERBOSE_PREFIX_3 "Forwarding %s to '%s' prevented.\n", in->name, o->chan->call_forward); 02305 numnochan++; 02306 do_hang(o); 02307 winner = NULL; 02308 continue; 02309 } else if (!ast_strlen_zero(o->chan->call_forward)) { 02310 char tmpchan[256]; 02311 char *stuff; 02312 char *tech; 02313 02314 ast_copy_string(tmpchan, o->chan->call_forward, sizeof(tmpchan)); 02315 if ((stuff = strchr(tmpchan, '/'))) { 02316 *stuff++ = '\0'; 02317 tech = tmpchan; 02318 } else { 02319 snprintf(tmpchan, sizeof(tmpchan), "%s@%s", o->chan->call_forward, o->chan->context); 02320 stuff = tmpchan; 02321 tech = "Local"; 02322 } 02323 /* Before processing channel, go ahead and check for forwarding */ 02324 if (option_verbose > 2) 02325 ast_verbose(VERBOSE_PREFIX_3 "Now forwarding %s to '%s/%s' (thanks to %s)\n", in->name, tech, stuff, o->chan->name); 02326 /* Setup parameters */ 02327 o->chan = ast_request(tech, in->nativeformats, stuff, &status); 02328 if (!o->chan) { 02329 ast_log(LOG_NOTICE, "Unable to create local channel for call forward to '%s/%s'\n", tech, stuff); 02330 o->stillgoing = 0; 02331 numnochan++; 02332 } else { 02333 ast_channel_inherit_variables(in, o->chan); 02334 ast_channel_datastore_inherit(in, o->chan); 02335 if (o->chan->cid.cid_num) 02336 free(o->chan->cid.cid_num); 02337 o->chan->cid.cid_num = ast_strdup(in->cid.cid_num); 02338 02339 if (o->chan->cid.cid_name) 02340 free(o->chan->cid.cid_name); 02341 o->chan->cid.cid_name = ast_strdup(in->cid.cid_name); 02342 02343 ast_string_field_set(o->chan, accountcode, in->accountcode); 02344 o->chan->cdrflags = in->cdrflags; 02345 02346 if (in->cid.cid_ani) { 02347 if (o->chan->cid.cid_ani) 02348 free(o->chan->cid.cid_ani); 02349 o->chan->cid.cid_ani = ast_strdup(in->cid.cid_ani); 02350 } 02351 if (o->chan->cid.cid_rdnis) 02352 free(o->chan->cid.cid_rdnis); 02353 o->chan->cid.cid_rdnis = ast_strdup(S_OR(in->macroexten, in->exten)); 02354 if (ast_call(o->chan, tmpchan, 0)) { 02355 ast_log(LOG_NOTICE, "Failed to dial on local channel for call forward to '%s'\n", tmpchan); 02356 do_hang(o); 02357 numnochan++; 02358 } 02359 } 02360 /* Hangup the original channel now, in case we needed it */ 02361 ast_hangup(winner); 02362 continue; 02363 } 02364 f = ast_read(winner); 02365 if (f) { 02366 if (f->frametype == AST_FRAME_CONTROL) { 02367 switch (f->subclass) { 02368 case AST_CONTROL_ANSWER: 02369 /* This is our guy if someone answered. */ 02370 if (!peer) { 02371 if (option_verbose > 2) 02372 ast_verbose( VERBOSE_PREFIX_3 "%s answered %s\n", o->chan->name, in->name); 02373 peer = o; 02374 } 02375 break; 02376 case AST_CONTROL_BUSY: 02377 if (option_verbose > 2) 02378 ast_verbose( VERBOSE_PREFIX_3 "%s is busy\n", o->chan->name); 02379 if (in->cdr) 02380 ast_cdr_busy(in->cdr); 02381 do_hang(o); 02382 endtime = (long)time(NULL); 02383 endtime -= starttime; 02384 rna(endtime * 1000, qe, on, membername, 0); 02385 if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) { 02386 if (qe->parent->timeoutrestart) 02387 *to = orig; 02388 /* Have enough time for a queue member to answer? */ 02389 if (*to > 500) { 02390 ring_one(qe, outgoing, &numbusies); 02391 starttime = (long) time(NULL); 02392 } 02393 } 02394 numbusies++; 02395 break; 02396 case AST_CONTROL_CONGESTION: 02397 if (option_verbose > 2) 02398 ast_verbose( VERBOSE_PREFIX_3 "%s is circuit-busy\n", o->chan->name); 02399 if (in->cdr) 02400 ast_cdr_busy(in->cdr); 02401 endtime = (long)time(NULL); 02402 endtime -= starttime; 02403 rna(endtime * 1000, qe, on, membername, 0); 02404 do_hang(o); 02405 if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) { 02406 if (qe->parent->timeoutrestart) 02407 *to = orig; 02408 if (*to > 500) { 02409 ring_one(qe, outgoing, &numbusies); 02410 starttime = (long) time(NULL); 02411 } 02412 } 02413 numbusies++; 02414 break; 02415 case AST_CONTROL_RINGING: 02416 if (option_verbose > 2) 02417 ast_verbose( VERBOSE_PREFIX_3 "%s is ringing\n", o->chan->name); 02418 break; 02419 case AST_CONTROL_OFFHOOK: 02420 /* Ignore going off hook */ 02421 break; 02422 default: 02423 ast_log(LOG_DEBUG, "Dunno what to do with control type %d\n", f->subclass); 02424 } 02425 } 02426 ast_frfree(f); 02427 } else { /* ast_read() returned NULL */ 02428 endtime = (long) time(NULL) - starttime; 02429 rna(endtime * 1000, qe, on, membername, 1); 02430 do_hang(o); 02431 if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) { 02432 if (qe->parent->timeoutrestart) 02433 *to = orig; 02434 if (*to > 500) { 02435 ring_one(qe, outgoing, &numbusies); 02436 starttime = (long) time(NULL); 02437 } 02438 } 02439 } 02440 } 02441 } 02442 02443 /* If we received an event from the caller, deal with it. */ 02444 if (winner == in) { 02445 f = ast_read(in); 02446 if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP))) { 02447 /* Got hung up */ 02448 *to = -1; 02449 if (f) 02450 ast_frfree(f); 02451 return NULL; 02452 } 02453 /* First check if DTMF digit is a valid exit */ 02454 if ((f->frametype == AST_FRAME_DTMF) && valid_exit(qe, f->subclass)) { 02455 if (option_verbose > 3) 02456 ast_verbose(VERBOSE_PREFIX_3 "User pressed digit: %c\n", f->subclass); 02457 *to = 0; 02458 *digit = f->subclass; 02459 ast_frfree(f); 02460 return NULL; 02461 } 02462 /* Else check if DTMF should be interpreted as caller disconnect */ 02463 if ((f->frametype == AST_FRAME_DTMF) && caller_disconnect && (f->subclass == '*')) { 02464 if (option_verbose > 3) 02465 ast_verbose(VERBOSE_PREFIX_3 "User hit %c to disconnect call.\n", f->subclass); 02466 *to = 0; 02467 ast_frfree(f); 02468 return NULL; 02469 } 02470 ast_frfree(f); 02471 } 02472 if (!*to) { 02473 for (o = start; o; o = o->call_next) 02474 rna(orig, qe, o->interface, o->member->membername, 1); 02475 } 02476 } 02477 02478 return peer; 02479 }
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 2539 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, ast_channel::uniqueid, and valid_exit().
Referenced by queue_exec().
02540 { 02541 int res = 0; 02542 02543 /* This is the holding pen for callers 2 through maxlen */ 02544 for (;;) { 02545 enum queue_member_status stat; 02546 02547 if (is_our_turn(qe)) 02548 break; 02549 02550 /* If we have timed out, break out */ 02551 if (qe->expire && (time(NULL) >= qe->expire)) { 02552 *reason = QUEUE_TIMEOUT; 02553 break; 02554 } 02555 02556 stat = get_member_status(qe->parent, qe->max_penalty); 02557 02558 /* leave the queue if no agents, if enabled */ 02559 if (qe->parent->leavewhenempty && (stat == QUEUE_NO_MEMBERS)) { 02560 *reason = QUEUE_LEAVEEMPTY; 02561 ast_queue_log(qe->parent->name, qe->chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe->pos, qe->opos, (long)time(NULL) - qe->start); 02562 leave_queue(qe); 02563 break; 02564 } 02565 02566 /* leave the queue if no reachable agents, if enabled */ 02567 if ((qe->parent->leavewhenempty == QUEUE_EMPTY_STRICT) && (stat == QUEUE_NO_REACHABLE_MEMBERS)) { 02568 *reason = QUEUE_LEAVEUNAVAIL; 02569 ast_queue_log(qe->parent->name, qe->chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe->pos, qe->opos, (long)time(NULL) - qe->start); 02570 leave_queue(qe); 02571 break; 02572 } 02573 02574 /* Make a position announcement, if enabled */ 02575 if (qe->parent->announcefrequency && !ringing && 02576 (res = say_position(qe))) 02577 break; 02578 02579 /* If we have timed out, break out */ 02580 if (qe->expire && (time(NULL) >= qe->expire)) { 02581 *reason = QUEUE_TIMEOUT; 02582 break; 02583 } 02584 02585 /* Make a periodic announcement, if enabled */ 02586 if (qe->parent->periodicannouncefrequency && !ringing && 02587 (res = say_periodic_announcement(qe))) 02588 break; 02589 02590 /* If we have timed out, break out */ 02591 if (qe->expire && (time(NULL) >= qe->expire)) { 02592 *reason = QUEUE_TIMEOUT; 02593 break; 02594 } 02595 02596 /* Wait a second before checking again */ 02597 if ((res = ast_waitfordigit(qe->chan, RECHECK * 1000))) { 02598 if (res > 0 && !valid_exit(qe, res)) 02599 res = 0; 02600 else 02601 break; 02602 } 02603 02604 /* If we have timed out, break out */ 02605 if (qe->expire && (time(NULL) >= qe->expire)) { 02606 *reason = QUEUE_TIMEOUT; 02607 break; 02608 } 02609 } 02610 02611 return res; 02612 }
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 5562 of file app_queue.c.
char* app = "Queue" [static] |
Definition at line 148 of file app_queue.c.
char* app_aqm = "AddQueueMember" [static] |
Definition at line 192 of file app_queue.c.
char* app_aqm_descrip [static] |
Definition at line 194 of file app_queue.c.
char* app_aqm_synopsis = "Dynamically adds queue members" [static] |
Definition at line 193 of file app_queue.c.
char* app_pqm = "PauseQueueMember" [static] |
Definition at line 227 of file app_queue.c.
char* app_pqm_descrip [static] |
Definition at line 229 of file app_queue.c.
char* app_pqm_synopsis = "Pauses a queue member" [static] |
Definition at line 228 of file app_queue.c.
char* app_ql = "QueueLog" [static] |
Definition at line 266 of file app_queue.c.
char* app_ql_descrip [static] |
Initial value:
" QueueLog(queuename|uniqueid|agent|event[|additionalinfo]):\n" "Allows you to write your own events into the queue log\n" "Example: QueueLog(101|${UNIQUEID}|${AGENT}|WENTONBREAK|600)\n"
Definition at line 268 of file app_queue.c.
char* app_ql_synopsis = "Writes to the queue_log" [static] |
Definition at line 267 of file app_queue.c.
char* app_rqm = "RemoveQueueMember" [static] |
Definition at line 211 of file app_queue.c.
char* app_rqm_descrip [static] |
Definition at line 213 of file app_queue.c.
char* app_rqm_synopsis = "Dynamically removes queue members" [static] |
Definition at line 212 of file app_queue.c.
char* app_upqm = "UnpauseQueueMember" [static] |
Definition at line 250 of file app_queue.c.
char* app_upqm_descrip [static] |
Definition at line 252 of file app_queue.c.
char* app_upqm_synopsis = "Unpauses a queue member" [static] |
Definition at line 251 of file app_queue.c.
const struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 5562 of file app_queue.c.
int autofill_default = 0 [static] |
struct ast_cli_entry cli_add_queue_member_deprecated [static] |
Initial value:
{ { "add", "queue", "member", NULL }, handle_queue_add_member, NULL, NULL, complete_queue_add_member }
Definition at line 5445 of file app_queue.c.
struct ast_cli_entry cli_queue[] [static] |
struct ast_cli_entry cli_remove_queue_member_deprecated [static] |
Initial value:
{ { "remove", "queue", "member", NULL }, handle_queue_remove_member, NULL, NULL, complete_queue_remove_member }
Definition at line 5450 of file app_queue.c.
struct ast_cli_entry cli_show_queue_deprecated [static] |
Initial value:
{ { "show", "queue", NULL }, queue_show, NULL, NULL, complete_queue_show }
Definition at line 5440 of file app_queue.c.
Condition for the state change queue
Definition at line 732 of file app_queue.c.
char* descrip [static] |
Definition at line 152 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 734 of file app_queue.c.
enum queue_result id |
struct statechange* last |
Definition at line 734 of file app_queue.c.
Lock for the state change queue
Definition at line 730 of file app_queue.c.
int montype_default = 0 [static] |
const char* pm_family = "Queue/PersistentMembers" [static] |
char qam_cmd_usage[] [static] |
Initial value:
"Usage: queue add member <channel> to <queue> [penalty <penalty> [as <membername> [state_interface <state_interface>]]]\n"
Definition at line 5434 of file app_queue.c.
char qmc_cmd_usage[] [static] |
Initial value:
"Usage: queue member count <queue>\n" " Provides member count information on a specified queue.\n"
Definition at line 5411 of file app_queue.c.
char qrm_cmd_usage[] [static] |
Initial value:
"Usage: queue remove member <channel> from <queue>\n"
Definition at line 5437 of file app_queue.c.
int queue_debug = 0 [static] |
int queue_persistent_members = 0 [static] |
struct { ... } queue_results[] |
Referenced by set_queue_result().
char queue_show_usage[] [static] |
Initial value:
"Usage: queue show\n" " Provides summary information on a specified queue.\n"
Definition at line 5430 of file app_queue.c.
struct ast_datastore_info queue_transfer_info [static] |
Initial value:
{ .type = "queue_transfer", .chan_fixup = queue_transfer_fixup, .destroy = queue_transfer_destroy, }
Definition at line 2708 of file app_queue.c.
Referenced by attended_transfer_occurred(), queue_transfer_fixup(), and setup_transfer_datastore().
struct ast_custom_function queueagentcount_function [static] |
struct ast_custom_function queuemembercount_function [static] |
struct ast_custom_function queuememberlist_function [static] |
struct ast_custom_function queuewaitingcount_function [static] |
struct { ... } state_change_q |
Queue of state changes
unsigned int stop |
Set to 1 to stop the thread
Definition at line 726 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 150 of file app_queue.c.
char* text |
Definition at line 305 of file app_queue.c.
Referenced by _sip_show_peer(), build_reply_digest(), check_auth(), handle_response(), method_match(), parse_sip_options(), referstatus2str(), reqprep(), sendtext_exec(), set_queue_result(), sip_alloc(), and sip_show_channel().
pthread_t thread |
The device state monitoring thread
Definition at line 728 of file app_queue.c.
int use_weight = 0 [static] |