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