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