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