#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 2268 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 4388 of file app_queue.c.
04388 { 04389 QMC_VALID = 0, /* Count valid members */ 04390 QMC_PAUSED, /* Count paused members */ 04391 QMC_ACTIVE, /* Count active members */ 04392 QMC_FREE, /* Count free members */ 04393 QMC_ALL /* Count all queue members */ 04394 };
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 4843 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().
04844 { 04845 struct call_queue *q; 04846 struct queue_ent *qe; 04847 struct member *mem; 04848 int pos, queue_show; 04849 time_t now; 04850 char max_buf[150]; 04851 char *max; 04852 size_t max_left; 04853 float sl = 0; 04854 char *term = manager ? "\r\n" : "\n"; 04855 struct ao2_iterator mem_iter; 04856 04857 time(&now); 04858 if (argc == 2) 04859 queue_show = 0; 04860 else if (argc == 3) 04861 queue_show = 1; 04862 else 04863 return RESULT_SHOWUSAGE; 04864 04865 /* We only want to load realtime queues when a specific queue is asked for. */ 04866 if (queue_show) { 04867 load_realtime_queue(argv[2]); 04868 } else if (ast_check_realtime("queues")) { 04869 struct ast_config *cfg = ast_load_realtime_multientry("queues", "name LIKE", "%", (char *) NULL); 04870 char *queuename; 04871 if (cfg) { 04872 for (queuename = ast_category_browse(cfg, NULL); !ast_strlen_zero(queuename); queuename = ast_category_browse(cfg, queuename)) { 04873 load_realtime_queue(queuename); 04874 } 04875 ast_config_destroy(cfg); 04876 } 04877 } 04878 04879 AST_LIST_LOCK(&queues); 04880 if (AST_LIST_EMPTY(&queues)) { 04881 AST_LIST_UNLOCK(&queues); 04882 if (queue_show) { 04883 if (s) 04884 astman_append(s, "No such queue: %s.%s",argv[2], term); 04885 else 04886 ast_cli(fd, "No such queue: %s.%s",argv[2], term); 04887 } else { 04888 if (s) 04889 astman_append(s, "No queues.%s", term); 04890 else 04891 ast_cli(fd, "No queues.%s", term); 04892 } 04893 return RESULT_SUCCESS; 04894 } 04895 AST_LIST_TRAVERSE(&queues, q, list) { 04896 ao2_lock(q); 04897 if (queue_show) { 04898 if (strcasecmp(q->name, argv[2]) != 0) { 04899 ao2_unlock(q); 04900 if (!AST_LIST_NEXT(q, list)) { 04901 ast_cli(fd, "No such queue: %s.%s",argv[2], term); 04902 break; 04903 } 04904 continue; 04905 } 04906 } 04907 max_buf[0] = '\0'; 04908 max = max_buf; 04909 max_left = sizeof(max_buf); 04910 if (q->maxlen) 04911 ast_build_string(&max, &max_left, "%d", q->maxlen); 04912 else 04913 ast_build_string(&max, &max_left, "unlimited"); 04914 sl = 0; 04915 if (q->callscompleted > 0) 04916 sl = 100 * ((float) q->callscompletedinsl / (float) q->callscompleted); 04917 if (s) 04918 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", 04919 q->name, q->count, max_buf, int2strat(q->strategy), q->holdtime, q->ringlimit, 04920 q->weight, q->callscompleted, q->callsabandoned, sl, q->servicelevel, term); 04921 else 04922 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", 04923 q->name, q->count, max_buf, int2strat(q->strategy), q->holdtime, q->ringlimit, 04924 q->weight, q->callscompleted, q->callsabandoned, sl, q->servicelevel, term); 04925 if (ao2_container_count(q->members)) { 04926 if (s) 04927 astman_append(s, " Members: %s", term); 04928 else 04929 ast_cli(fd, " Members: %s", term); 04930 mem_iter = ao2_iterator_init(q->members, 0); 04931 while ((mem = ao2_iterator_next(&mem_iter))) { 04932 max_buf[0] = '\0'; 04933 max = max_buf; 04934 max_left = sizeof(max_buf); 04935 if (strcasecmp(mem->membername, mem->interface)) { 04936 ast_build_string(&max, &max_left, " (%s)", mem->interface); 04937 } 04938 if (mem->penalty) 04939 ast_build_string(&max, &max_left, " with penalty %d", mem->penalty); 04940 if (mem->dynamic) 04941 ast_build_string(&max, &max_left, " (dynamic)"); 04942 if (mem->realtime) 04943 ast_build_string(&max, &max_left, " (realtime)"); 04944 if (mem->paused) 04945 ast_build_string(&max, &max_left, " (paused)"); 04946 ast_build_string(&max, &max_left, " (%s)", devstate2str(mem->status)); 04947 if (mem->calls) { 04948 ast_build_string(&max, &max_left, " has taken %d calls (last was %ld secs ago)", 04949 mem->calls, (long) (time(NULL) - mem->lastcall)); 04950 } else 04951 ast_build_string(&max, &max_left, " has taken no calls yet"); 04952 if (s) 04953 astman_append(s, " %s%s%s", mem->membername, max_buf, term); 04954 else 04955 ast_cli(fd, " %s%s%s", mem->membername, max_buf, term); 04956 ao2_ref(mem, -1); 04957 } 04958 ao2_iterator_destroy(&mem_iter); 04959 } else if (s) 04960 astman_append(s, " No Members%s", term); 04961 else 04962 ast_cli(fd, " No Members%s", term); 04963 if (q->head) { 04964 pos = 1; 04965 if (s) 04966 astman_append(s, " Callers: %s", term); 04967 else 04968 ast_cli(fd, " Callers: %s", term); 04969 for (qe = q->head; qe; qe = qe->next) { 04970 if (s) 04971 astman_append(s, " %d. %s (wait: %ld:%2.2ld, prio: %d)%s", 04972 pos++, qe->chan->name, (long) (now - qe->start) / 60, 04973 (long) (now - qe->start) % 60, qe->prio, term); 04974 else 04975 ast_cli(fd, " %d. %s (wait: %ld:%2.2ld, prio: %d)%s", pos++, 04976 qe->chan->name, (long) (now - qe->start) / 60, 04977 (long) (now - qe->start) % 60, qe->prio, term); 04978 } 04979 } else if (s) 04980 astman_append(s, " No Callers%s", term); 04981 else 04982 ast_cli(fd, " No Callers%s", term); 04983 if (s) 04984 astman_append(s, "%s", term); 04985 else 04986 ast_cli(fd, "%s", term); 04987 ao2_unlock(q); 04988 if (queue_show) 04989 break; 04990 } 04991 AST_LIST_UNLOCK(&queues); 04992 return RESULT_SUCCESS; 04993 }
static void __reg_module | ( | void | ) | [static] |
Definition at line 5671 of file app_queue.c.
static void __unreg_module | ( | void | ) | [static] |
Definition at line 5671 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 3611 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().
03612 { 03613 struct call_queue *q; 03614 struct member *new_member, *old_member; 03615 int res = RES_NOSUCHQUEUE; 03616 03617 /* \note Ensure the appropriate realtime queue is loaded. Note that this 03618 * short-circuits if the queue is already in memory. */ 03619 if (!(q = load_realtime_queue(queuename))) 03620 return res; 03621 03622 AST_LIST_LOCK(&queues); 03623 03624 ao2_lock(q); 03625 if ((old_member = interface_exists(q, interface)) == NULL) { 03626 if ((new_member = create_queue_member(interface, membername, penalty, paused, state_interface))) { 03627 add_to_interfaces(new_member->state_interface); 03628 new_member->dynamic = 1; 03629 ao2_link(q->members, new_member); 03630 q->membercount++; 03631 manager_event(EVENT_FLAG_AGENT, "QueueMemberAdded", 03632 "Queue: %s\r\n" 03633 "Location: %s\r\n" 03634 "MemberName: %s\r\n" 03635 "Membership: %s\r\n" 03636 "Penalty: %d\r\n" 03637 "CallsTaken: %d\r\n" 03638 "LastCall: %d\r\n" 03639 "Status: %d\r\n" 03640 "Paused: %d\r\n", 03641 q->name, new_member->interface, new_member->membername, 03642 "dynamic", 03643 new_member->penalty, new_member->calls, (int) new_member->lastcall, 03644 new_member->status, new_member->paused); 03645 03646 ao2_ref(new_member, -1); 03647 new_member = NULL; 03648 03649 if (dump) 03650 dump_queue_members(q); 03651 03652 res = RES_OKAY; 03653 } else { 03654 res = RES_OUTOFMEMORY; 03655 } 03656 } else { 03657 ao2_ref(old_member, -1); 03658 res = RES_EXISTS; 03659 } 03660 ao2_unlock(q); 03661 AST_LIST_UNLOCK(&queues); 03662 03663 return res; 03664 }
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 3992 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().
03993 { 03994 int res=-1; 03995 struct ast_module_user *lu; 03996 char *parse, *temppos = NULL; 03997 int priority_jump = 0; 03998 AST_DECLARE_APP_ARGS(args, 03999 AST_APP_ARG(queuename); 04000 AST_APP_ARG(interface); 04001 AST_APP_ARG(penalty); 04002 AST_APP_ARG(options); 04003 AST_APP_ARG(membername); 04004 AST_APP_ARG(state_interface); 04005 ); 04006 int penalty = 0; 04007 04008 if (ast_strlen_zero(data)) { 04009 ast_log(LOG_WARNING, "AddQueueMember requires an argument (queuename[|interface[|penalty[|options[|membername[|state_interface]]]]])\n"); 04010 return -1; 04011 } 04012 04013 parse = ast_strdupa(data); 04014 04015 AST_STANDARD_APP_ARGS(args, parse); 04016 04017 lu = ast_module_user_add(chan); 04018 04019 if (ast_strlen_zero(args.interface)) { 04020 args.interface = ast_strdupa(chan->name); 04021 temppos = strrchr(args.interface, '-'); 04022 if (temppos) 04023 *temppos = '\0'; 04024 } 04025 04026 if (!ast_strlen_zero(args.penalty)) { 04027 if ((sscanf(args.penalty, "%30d", &penalty) != 1) || penalty < 0) { 04028 ast_log(LOG_WARNING, "Penalty '%s' is invalid, must be an integer >= 0\n", args.penalty); 04029 penalty = 0; 04030 } 04031 } 04032 04033 if (args.options) { 04034 if (strchr(args.options, 'j')) 04035 priority_jump = 1; 04036 } 04037 04038 switch (add_to_queue(args.queuename, args.interface, args.membername, penalty, 0, queue_persistent_members, args.state_interface)) { 04039 case RES_OKAY: 04040 ast_queue_log(args.queuename, chan->uniqueid, args.interface, "ADDMEMBER", "%s", ""); 04041 ast_log(LOG_NOTICE, "Added interface '%s' to queue '%s'\n", args.interface, args.queuename); 04042 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "ADDED"); 04043 res = 0; 04044 break; 04045 case RES_EXISTS: 04046 ast_log(LOG_WARNING, "Unable to add interface '%s' to queue '%s': Already there\n", args.interface, args.queuename); 04047 if (priority_jump || ast_opt_priority_jumping) 04048 ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101); 04049 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "MEMBERALREADY"); 04050 res = 0; 04051 break; 04052 case RES_NOSUCHQUEUE: 04053 ast_log(LOG_WARNING, "Unable to add interface to queue '%s': No such queue\n", args.queuename); 04054 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "NOSUCHQUEUE"); 04055 res = 0; 04056 break; 04057 case RES_OUTOFMEMORY: 04058 ast_log(LOG_ERROR, "Out of memory adding member %s to queue %s\n", args.interface, args.queuename); 04059 break; 04060 } 04061 04062 ast_module_user_remove(lu); 04063 04064 return res; 04065 }
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 2819 of file app_queue.c.
References ast_channel_datastore_find(), and queue_transfer_info.
02820 { 02821 return ast_channel_datastore_find(chan, &queue_transfer_info, NULL) ? 0 : 1; 02822 }
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 2696 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().
02697 { 02698 if (qe->max_penalty && (mem->penalty > qe->max_penalty)) 02699 return -1; 02700 02701 switch (q->strategy) { 02702 case QUEUE_STRATEGY_RINGALL: 02703 /* Everyone equal, except for penalty */ 02704 tmp->metric = mem->penalty * 1000000; 02705 break; 02706 case QUEUE_STRATEGY_ROUNDROBIN: 02707 if (!pos) { 02708 if (!q->wrapped) { 02709 /* No more channels, start over */ 02710 q->rrpos = 0; 02711 } else { 02712 /* Prioritize next entry */ 02713 q->rrpos++; 02714 } 02715 q->wrapped = 0; 02716 } 02717 /* Fall through */ 02718 case QUEUE_STRATEGY_RRORDERED: 02719 case QUEUE_STRATEGY_RRMEMORY: 02720 if (pos < q->rrpos) { 02721 tmp->metric = 1000 + pos; 02722 } else { 02723 if (pos > q->rrpos) 02724 /* Indicate there is another priority */ 02725 q->wrapped = 1; 02726 tmp->metric = pos; 02727 } 02728 tmp->metric += mem->penalty * 1000000; 02729 break; 02730 case QUEUE_STRATEGY_RANDOM: 02731 tmp->metric = ast_random() % 1000; 02732 tmp->metric += mem->penalty * 1000000; 02733 break; 02734 case QUEUE_STRATEGY_FEWESTCALLS: 02735 tmp->metric = mem->calls; 02736 tmp->metric += mem->penalty * 1000000; 02737 break; 02738 case QUEUE_STRATEGY_LEASTRECENT: 02739 if (!mem->lastcall) 02740 tmp->metric = 0; 02741 else 02742 tmp->metric = 1000000 - (time(NULL) - mem->lastcall); 02743 tmp->metric += mem->penalty * 1000000; 02744 break; 02745 default: 02746 ast_log(LOG_WARNING, "Can't calculate metric for unknown strategy %d\n", q->strategy); 02747 break; 02748 } 02749 if (q->ringlimit && (mem->ringcount >= q->ringlimit)) { 02750 tmp->metric += (mem->ringcount / q->ringlimit) * 10000000; 02751 } 02752 if (option_debug) 02753 ast_log(LOG_DEBUG, "New metric %d for member %s with %d rings (limit %d)\n", 02754 tmp->metric, mem->interface, mem->ringcount, q->ringlimit); 02755 return 0; 02756 }
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 5498 of file app_queue.c.
References ast_cli(), qmc_handler(), RESULT_FAILURE, RESULT_SHOWUSAGE, and RESULT_SUCCESS.
05499 { 05500 char buffer[256] = ""; 05501 char *queuename; 05502 05503 if (argc != 4) { 05504 return RESULT_SHOWUSAGE; 05505 } 05506 queuename = argv[3]; 05507 05508 if (qmc_handler(queuename, buffer, sizeof(buffer)) == RESULT_SUCCESS) { 05509 ast_cli(fd, 05510 "Member count for queue '%s'\n" 05511 "%s\n", 05512 queuename, buffer); 05513 return RESULT_SUCCESS; 05514 } else { 05515 ast_cli(fd, "No such queue: '%s'\n", queuename); 05516 return RESULT_FAILURE; 05517 } 05518 }
static int compare_weight | ( | struct call_queue * | rq, | |
struct member * | member | |||
) | [static] |
Definition at line 1870 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().
01871 { 01872 struct call_queue *q; 01873 struct member *mem; 01874 int found = 0; 01875 01876 /* &qlock and &rq->lock already set by try_calling() 01877 * to solve deadlock */ 01878 AST_LIST_TRAVERSE(&queues, q, list) { 01879 if (q == rq) /* don't check myself, could deadlock */ 01880 continue; 01881 ao2_lock(q); 01882 if (q->count && q->members) { 01883 if ((mem = ao2_find(q->members, member, OBJ_POINTER))) { 01884 ast_log(LOG_DEBUG, "Found matching member %s in queue '%s'\n", mem->interface, q->name); 01885 if (q->weight > rq->weight && q->count >= num_available_members(q)) { 01886 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); 01887 found = 1; 01888 } 01889 ao2_ref(mem, -1); 01890 } 01891 } 01892 ao2_unlock(q); 01893 if (found) 01894 break; 01895 } 01896 return found; 01897 }
static char* complete_queue | ( | const char * | line, | |
const char * | word, | |||
int | pos, | |||
int | state | |||
) | [static] |
Definition at line 5000 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().
05001 { 05002 struct call_queue *q; 05003 char *ret = NULL; 05004 int which = 0; 05005 int wordlen = strlen(word); 05006 05007 AST_LIST_LOCK(&queues); 05008 AST_LIST_TRAVERSE(&queues, q, list) { 05009 if (!strncasecmp(word, q->name, wordlen) && ++which > state) { 05010 ret = ast_strdup(q->name); 05011 break; 05012 } 05013 } 05014 AST_LIST_UNLOCK(&queues); 05015 05016 return ret; 05017 }
static char* complete_queue_add_member | ( | const char * | line, | |
const char * | word, | |||
int | pos, | |||
int | state | |||
) | [static] |
Definition at line 5303 of file app_queue.c.
References ast_malloc, ast_strdup, and complete_queue().
05304 { 05305 /* 0 - queue; 1 - add; 2 - member; 3 - <interface>; 4 - to; 5 - <queue>; 6 - penalty; 7 - <penalty>; 8 - as; 9 - <membername> */ 05306 switch (pos) { 05307 case 3: /* Don't attempt to complete name of interface (infinite possibilities) */ 05308 return NULL; 05309 case 4: /* only one possible match, "to" */ 05310 return state == 0 ? ast_strdup("to") : NULL; 05311 case 5: /* <queue> */ 05312 return complete_queue(line, word, pos, state); 05313 case 6: /* only one possible match, "penalty" */ 05314 return state == 0 ? ast_strdup("penalty") : NULL; 05315 case 7: 05316 if (state < 100) { /* 0-99 */ 05317 char *num; 05318 if ((num = ast_malloc(3))) { 05319 sprintf(num, "%d", state); 05320 } 05321 return num; 05322 } else { 05323 return NULL; 05324 } 05325 case 8: /* only one possible match, "as" */ 05326 return state == 0 ? ast_strdup("as") : NULL; 05327 case 9: /* Don't attempt to complete name of member (infinite possibilities) */ 05328 return NULL; 05329 case 10: 05330 return state == 0 ? ast_strdup("state_interface") : NULL; 05331 default: 05332 return NULL; 05333 } 05334 }
static char* complete_queue_member_count | ( | const char * | line, | |
const char * | word, | |||
int | pos, | |||
int | state | |||
) | [static] |
Definition at line 5525 of file app_queue.c.
References complete_queue().
05526 { 05527 /* 0 - queue; 1 - member; 2 - count; 3 - <queue> */ 05528 switch (pos) { 05529 case 3: /* <queue> */ 05530 return complete_queue(line, word, pos, state); 05531 default: 05532 return NULL; 05533 } 05534 }
static char* complete_queue_remove_member | ( | const char * | line, | |
const char * | word, | |||
int | pos, | |||
int | state | |||
) | [static] |
Definition at line 5371 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.
05372 { 05373 int which = 0; 05374 struct call_queue *q; 05375 struct member *m; 05376 struct ao2_iterator mem_iter; 05377 05378 /* 0 - queue; 1 - remove; 2 - member; 3 - <member>; 4 - from; 5 - <queue> */ 05379 if (pos > 5 || pos < 3) 05380 return NULL; 05381 if (pos == 4) /* only one possible match, 'from' */ 05382 return state == 0 ? ast_strdup("from") : NULL; 05383 05384 if (pos == 5) /* No need to duplicate code */ 05385 return complete_queue(line, word, pos, state); 05386 05387 /* here is the case for 3, <member> */ 05388 if (!AST_LIST_EMPTY(&queues)) { /* XXX unnecessary ? the traverse does that for us */ 05389 AST_LIST_TRAVERSE(&queues, q, list) { 05390 ao2_lock(q); 05391 mem_iter = ao2_iterator_init(q->members, 0); 05392 while ((m = ao2_iterator_next(&mem_iter))) { 05393 if (++which > state) { 05394 char *tmp; 05395 ao2_iterator_destroy(&mem_iter); 05396 ao2_unlock(q); 05397 tmp = ast_strdup(m->interface); 05398 ao2_ref(m, -1); 05399 return tmp; 05400 } 05401 ao2_ref(m, -1); 05402 } 05403 ao2_iterator_destroy(&mem_iter); 05404 ao2_unlock(q); 05405 } 05406 } 05407 05408 return NULL; 05409 }
static char* complete_queue_show | ( | const char * | line, | |
const char * | word, | |||
int | pos, | |||
int | state | |||
) | [static] |
Definition at line 5019 of file app_queue.c.
References complete_queue().
05020 { 05021 if (pos == 2) 05022 return complete_queue(line, word, pos, state); 05023 return NULL; 05024 }
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 1900 of file app_queue.c.
References ast_hangup(), callattempt::chan, and callattempt::stillgoing.
Referenced by ring_entry().
01901 { 01902 o->stillgoing = 0; 01903 ast_hangup(o->chan); 01904 o->chan = NULL; 01905 }
static void dump_queue_members | ( | struct call_queue * | pm_queue | ) | [static] |
Definition at line 3519 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().
03520 { 03521 struct member *cur_member; 03522 char value[PM_MAX_LEN]; 03523 int value_len = 0; 03524 int res; 03525 struct ao2_iterator mem_iter; 03526 03527 memset(value, 0, sizeof(value)); 03528 03529 if (!pm_queue) 03530 return; 03531 03532 mem_iter = ao2_iterator_init(pm_queue->members, 0); 03533 while ((cur_member = ao2_iterator_next(&mem_iter))) { 03534 if (!cur_member->dynamic) { 03535 ao2_ref(cur_member, -1); 03536 continue; 03537 } 03538 03539 res = snprintf(value + value_len, sizeof(value) - value_len, "%s%s;%d;%d;%s;%s", 03540 value_len ? "|" : "", cur_member->interface, cur_member->penalty, cur_member->paused, cur_member->membername, cur_member->state_interface); 03541 03542 ao2_ref(cur_member, -1); 03543 03544 if (res != strlen(value + value_len)) { 03545 ast_log(LOG_WARNING, "Could not create persistent member string, out of space\n"); 03546 break; 03547 } 03548 value_len += res; 03549 } 03550 ao2_iterator_destroy(&mem_iter); 03551 03552 if (value_len && !cur_member) { 03553 if (ast_db_put(pm_family, pm_queue->name, value)) 03554 ast_log(LOG_WARNING, "failed to create persistent dynamic entry!\n"); 03555 } else 03556 /* Delete the entry if the queue is empty or there is an error */ 03557 ast_db_del(pm_family, pm_queue->name); 03558 }
static struct callattempt* find_best | ( | struct callattempt * | outgoing | ) | [static] |
find the entry with the best metric, or NULL
Definition at line 2107 of file app_queue.c.
References callattempt::metric, and callattempt::q_next.
02108 { 02109 struct callattempt *best = NULL, *cur; 02110 02111 for (cur = outgoing; cur; cur = cur->q_next) { 02112 if (cur->stillgoing && /* Not already done */ 02113 !cur->chan && /* Isn't already going */ 02114 (!best || cur->metric < best->metric)) { /* We haven't found one yet, or it's better */ 02115 best = cur; 02116 } 02117 } 02118 02119 return best; 02120 }
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 5243 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.
05244 { 05245 char *queuename, *interface, *membername = NULL, *state_interface = NULL; 05246 int penalty; 05247 05248 if ((argc != 6) && (argc != 8) && (argc != 10) && (argc != 12)) { 05249 return RESULT_SHOWUSAGE; 05250 } else if (strcmp(argv[4], "to")) { 05251 return RESULT_SHOWUSAGE; 05252 } else if ((argc == 8) && strcmp(argv[6], "penalty")) { 05253 return RESULT_SHOWUSAGE; 05254 } else if ((argc == 10) && strcmp(argv[8], "as")) { 05255 return RESULT_SHOWUSAGE; 05256 } else if ((argc == 12) && strcmp(argv[10], "state_interface")) { 05257 return RESULT_SHOWUSAGE; 05258 } 05259 05260 queuename = argv[5]; 05261 interface = argv[3]; 05262 if (argc >= 8) { 05263 if (sscanf(argv[7], "%30d", &penalty) == 1) { 05264 if (penalty < 0) { 05265 ast_cli(fd, "Penalty must be >= 0\n"); 05266 penalty = 0; 05267 } 05268 } else { 05269 ast_cli(fd, "Penalty must be an integer >= 0\n"); 05270 penalty = 0; 05271 } 05272 } else { 05273 penalty = 0; 05274 } 05275 05276 if (argc >= 10) { 05277 membername = argv[9]; 05278 } 05279 05280 if (argc >= 12) { 05281 state_interface = argv[11]; 05282 } 05283 05284 switch (add_to_queue(queuename, interface, membername, penalty, 0, queue_persistent_members, state_interface)) { 05285 case RES_OKAY: 05286 ast_queue_log(queuename, "CLI", interface, "ADDMEMBER", "%s", ""); 05287 ast_cli(fd, "Added interface '%s' to queue '%s'\n", interface, queuename); 05288 return RESULT_SUCCESS; 05289 case RES_EXISTS: 05290 ast_cli(fd, "Unable to add interface '%s' to queue '%s': Already there\n", interface, queuename); 05291 return RESULT_FAILURE; 05292 case RES_NOSUCHQUEUE: 05293 ast_cli(fd, "Unable to add interface to queue '%s': No such queue\n", queuename); 05294 return RESULT_FAILURE; 05295 case RES_OUTOFMEMORY: 05296 ast_cli(fd, "Out of memory\n"); 05297 return RESULT_FAILURE; 05298 default: 05299 return RESULT_FAILURE; 05300 } 05301 }
static int handle_queue_remove_member | ( | int | fd, | |
int | argc, | |||
char * | argv[] | |||
) | [static] |
Definition at line 5336 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.
05337 { 05338 char *queuename, *interface; 05339 05340 if (argc != 6) { 05341 return RESULT_SHOWUSAGE; 05342 } else if (strcmp(argv[4], "from")) { 05343 return RESULT_SHOWUSAGE; 05344 } 05345 05346 queuename = argv[5]; 05347 interface = argv[3]; 05348 05349 switch (remove_from_queue(queuename, interface)) { 05350 case RES_OKAY: 05351 ast_queue_log(queuename, "CLI", interface, "REMOVEMEMBER", "%s", ""); 05352 ast_cli(fd, "Removed interface '%s' from queue '%s'\n", interface, queuename); 05353 return RESULT_SUCCESS; 05354 case RES_EXISTS: 05355 ast_cli(fd, "Unable to remove interface '%s' from queue '%s': Not there\n", interface, queuename); 05356 return RESULT_FAILURE; 05357 case RES_NOSUCHQUEUE: 05358 ast_cli(fd, "Unable to remove interface from queue '%s': No such queue\n", queuename); 05359 return RESULT_FAILURE; 05360 case RES_OUTOFMEMORY: 05361 ast_cli(fd, "Out of memory\n"); 05362 return RESULT_FAILURE; 05363 case RES_NOT_DYNAMIC: 05364 ast_cli(fd, "Member not dynamic\n"); 05365 return RESULT_FAILURE; 05366 default: 05367 return RESULT_FAILURE; 05368 } 05369 }
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 3492 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().
03493 { 03494 struct member *mem; 03495 struct ao2_iterator mem_iter; 03496 03497 if (!q) 03498 return NULL; 03499 03500 mem_iter = ao2_iterator_init(q->members, 0); 03501 while ((mem = ao2_iterator_next(&mem_iter))) { 03502 if (!strcasecmp(interface, mem->interface)) { 03503 ao2_iterator_destroy(&mem_iter); 03504 return mem; 03505 } 03506 ao2_ref(mem, -1); 03507 } 03508 ao2_iterator_destroy(&mem_iter); 03509 03510 return NULL; 03511 }
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 2553 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().
02554 { 02555 struct queue_ent *ch; 02556 int res; 02557 int avl; 02558 int idx = 0; 02559 /* This needs a lock. How many members are available to be served? */ 02560 ao2_lock(qe->parent); 02561 02562 avl = num_available_members(qe->parent); 02563 02564 ch = qe->parent->head; 02565 02566 if (option_debug) { 02567 ast_log(LOG_DEBUG, "There %s %d available %s.\n", avl != 1 ? "are" : "is", avl, avl != 1 ? "members" : "member"); 02568 } 02569 02570 while ((idx < avl) && (ch) && (ch != qe)) { 02571 if (!ch->pending) 02572 idx++; 02573 ch = ch->next; 02574 } 02575 02576 ao2_unlock(qe->parent); 02577 /* If the queue entry is within avl [the number of available members] calls from the top ... 02578 * Autofill and position check added to support autofill=no (as only calls 02579 * from the front of the queue are valid when autofill is disabled) 02580 */ 02581 if (ch && idx < avl && (qe->parent->autofill || qe->pos == 1)) { 02582 if (option_debug) 02583 ast_log(LOG_DEBUG, "It's our turn (%s).\n", qe->chan->name); 02584 res = 1; 02585 } else { 02586 if (option_debug) 02587 ast_log(LOG_DEBUG, "It's not our turn (%s).\n", qe->chan->name); 02588 res = 0; 02589 } 02590 02591 return res; 02592 }
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 5625 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().
05626 { 05627 int res; 05628 05629 if (!reload_queues()) 05630 return AST_MODULE_LOAD_DECLINE; 05631 05632 if (queue_persistent_members) 05633 reload_queue_members(); 05634 05635 ast_mutex_init(&device_state.lock); 05636 ast_cond_init(&device_state.cond, NULL); 05637 ast_pthread_create(&device_state.thread, NULL, device_state_thread, NULL); 05638 05639 ast_cli_register_multiple(cli_queue, sizeof(cli_queue) / sizeof(struct ast_cli_entry)); 05640 res = ast_register_application(app, queue_exec, synopsis, descrip); 05641 res |= ast_register_application(app_aqm, aqm_exec, app_aqm_synopsis, app_aqm_descrip); 05642 res |= ast_register_application(app_rqm, rqm_exec, app_rqm_synopsis, app_rqm_descrip); 05643 res |= ast_register_application(app_pqm, pqm_exec, app_pqm_synopsis, app_pqm_descrip); 05644 res |= ast_register_application(app_upqm, upqm_exec, app_upqm_synopsis, app_upqm_descrip); 05645 res |= ast_register_application(app_ql, ql_exec, app_ql_synopsis, app_ql_descrip); 05646 res |= ast_manager_register("Queues", 0, manager_queues_show, "Queues"); 05647 res |= ast_manager_register("QueueStatus", 0, manager_queues_status, "Queue Status"); 05648 res |= ast_manager_register("QueueMemberCount", 0, manager_queue_member_count, "Queue Member Count"); 05649 res |= ast_manager_register("QueueAdd", EVENT_FLAG_AGENT, manager_add_queue_member, "Add interface to queue."); 05650 res |= ast_manager_register("QueueRemove", EVENT_FLAG_AGENT, manager_remove_queue_member, "Remove interface from queue."); 05651 res |= ast_manager_register("QueuePause", EVENT_FLAG_AGENT, manager_pause_queue_member, "Makes a queue member temporarily unavailable"); 05652 res |= ast_custom_function_register(&queueagentcount_function); 05653 res |= ast_custom_function_register(&queuemembercount_function); 05654 res |= ast_custom_function_register(&queuememberlist_function); 05655 res |= ast_custom_function_register(&queuewaitingcount_function); 05656 res |= ast_devstate_add(statechange_queue, NULL); 05657 05658 return res; 05659 }
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 5135 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().
05136 { 05137 const char *queuename, *interface, *penalty_s, *paused_s, *membername, *state_interface; 05138 int paused, penalty = 0; 05139 05140 queuename = astman_get_header(m, "Queue"); 05141 interface = astman_get_header(m, "Interface"); 05142 penalty_s = astman_get_header(m, "Penalty"); 05143 paused_s = astman_get_header(m, "Paused"); 05144 membername = astman_get_header(m, "MemberName"); 05145 state_interface = astman_get_header(m, "StateInterface"); 05146 05147 if (ast_strlen_zero(queuename)) { 05148 astman_send_error(s, m, "'Queue' not specified."); 05149 return 0; 05150 } 05151 05152 if (ast_strlen_zero(interface)) { 05153 astman_send_error(s, m, "'Interface' not specified."); 05154 return 0; 05155 } 05156 05157 if (ast_strlen_zero(penalty_s)) 05158 penalty = 0; 05159 else if (sscanf(penalty_s, "%30d", &penalty) != 1 || penalty < 0) 05160 penalty = 0; 05161 05162 if (ast_strlen_zero(paused_s)) 05163 paused = 0; 05164 else 05165 paused = abs(ast_true(paused_s)); 05166 05167 switch (add_to_queue(queuename, interface, membername, penalty, paused, queue_persistent_members, state_interface)) { 05168 case RES_OKAY: 05169 ast_queue_log(queuename, "MANAGER", interface, "ADDMEMBER", "%s", ""); 05170 astman_send_ack(s, m, "Added interface to queue"); 05171 break; 05172 case RES_EXISTS: 05173 astman_send_error(s, m, "Unable to add interface: Already there"); 05174 break; 05175 case RES_NOSUCHQUEUE: 05176 astman_send_error(s, m, "Unable to add interface to queue: No such queue"); 05177 break; 05178 case RES_OUTOFMEMORY: 05179 astman_send_error(s, m, "Out of memory"); 05180 break; 05181 } 05182 05183 return 0; 05184 }
static int manager_pause_queue_member | ( | struct mansession * | s, | |
const struct message * | m | |||
) | [static] |
Definition at line 5220 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().
05221 { 05222 const char *queuename, *interface, *paused_s; 05223 int paused; 05224 05225 interface = astman_get_header(m, "Interface"); 05226 paused_s = astman_get_header(m, "Paused"); 05227 queuename = astman_get_header(m, "Queue"); /* Optional - if not supplied, pause the given Interface in all queues */ 05228 05229 if (ast_strlen_zero(interface) || ast_strlen_zero(paused_s)) { 05230 astman_send_error(s, m, "Need 'Interface' and 'Paused' parameters."); 05231 return 0; 05232 } 05233 05234 paused = abs(ast_true(paused_s)); 05235 05236 if (set_member_paused(queuename, interface, paused)) 05237 astman_send_error(s, m, "Interface not found"); 05238 else 05239 astman_send_ack(s, m, paused ? "Interface paused successfully" : "Interface unpaused successfully"); 05240 return 0; 05241 }
static int manager_queue_member_count | ( | struct mansession * | s, | |
const struct message * | m | |||
) | [static] |
Definition at line 5480 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().
05481 { 05482 char buffer[256] = ""; 05483 const char *queuename = astman_get_header(m,"Queue"); 05484 05485 if (ast_strlen_zero(queuename)) { 05486 astman_send_error(s, m, "'Queue' not specified."); 05487 return 0; 05488 } 05489 if (qmc_handler(queuename, buffer, sizeof(buffer)) == RESULT_SUCCESS) { 05490 astman_send_ack(s, m, buffer); 05491 return RESULT_SUCCESS; 05492 } else { 05493 astman_send_error(s, m, "Queue not found."); 05494 return 0; 05495 } 05496 }
static int manager_queues_show | ( | struct mansession * | s, | |
const struct message * | m | |||
) | [static] |
Definition at line 5029 of file app_queue.c.
References __queues_show(), astman_append(), RESULT_SUCCESS, and s.
Referenced by load_module().
05030 { 05031 char *a[] = { "queue", "show" }; 05032 05033 __queues_show(s, 1, -1, 2, a); 05034 astman_append(s, "\r\n\r\n"); /* Properly terminate Manager output */ 05035 05036 return RESULT_SUCCESS; 05037 }
static int manager_queues_status | ( | struct mansession * | s, | |
const struct message * | m | |||
) | [static] |
Definition at line 5040 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().
05041 { 05042 time_t now; 05043 int pos; 05044 const char *id = astman_get_header(m,"ActionID"); 05045 const char *queuefilter = astman_get_header(m,"Queue"); 05046 const char *memberfilter = astman_get_header(m,"Member"); 05047 char idText[256] = ""; 05048 struct call_queue *q; 05049 struct queue_ent *qe; 05050 float sl = 0; 05051 struct member *mem; 05052 struct ao2_iterator mem_iter; 05053 05054 astman_send_ack(s, m, "Queue status will follow"); 05055 time(&now); 05056 AST_LIST_LOCK(&queues); 05057 if (!ast_strlen_zero(id)) 05058 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id); 05059 05060 AST_LIST_TRAVERSE(&queues, q, list) { 05061 ao2_lock(q); 05062 05063 /* List queue properties */ 05064 if (ast_strlen_zero(queuefilter) || !strcmp(q->name, queuefilter)) { 05065 sl = ((q->callscompleted > 0) ? 100 * ((float)q->callscompletedinsl / (float)q->callscompleted) : 0); 05066 astman_append(s, "Event: QueueParams\r\n" 05067 "Queue: %s\r\n" 05068 "Max: %d\r\n" 05069 "Calls: %d\r\n" 05070 "Holdtime: %d\r\n" 05071 "Completed: %d\r\n" 05072 "Abandoned: %d\r\n" 05073 "ServiceLevel: %d\r\n" 05074 "ServicelevelPerf: %2.1f\r\n" 05075 "RingLimit: %d\r\n" 05076 "Weight: %d\r\n" 05077 "%s" 05078 "\r\n", 05079 q->name, q->maxlen, q->count, q->holdtime, q->callscompleted, 05080 q->callsabandoned, q->servicelevel, sl, q->ringlimit, q->weight, idText); 05081 /* List Queue Members */ 05082 mem_iter = ao2_iterator_init(q->members, 0); 05083 while ((mem = ao2_iterator_next(&mem_iter))) { 05084 if (ast_strlen_zero(memberfilter) || !strcmp(mem->interface, memberfilter)) { 05085 astman_append(s, "Event: QueueMember\r\n" 05086 "Queue: %s\r\n" 05087 "Name: %s\r\n" 05088 "Location: %s\r\n" 05089 "Membership: %s\r\n" 05090 "Penalty: %d\r\n" 05091 "CallsTaken: %d\r\n" 05092 "LastCall: %d\r\n" 05093 "Status: %d\r\n" 05094 "Paused: %d\r\n" 05095 "%s" 05096 "\r\n", 05097 q->name, mem->membername, mem->interface, mem->dynamic ? "dynamic" : "static", 05098 mem->penalty, mem->calls, (int)mem->lastcall, mem->status, mem->paused, idText); 05099 } 05100 ao2_ref(mem, -1); 05101 } 05102 ao2_iterator_destroy(&mem_iter); 05103 /* List Queue Entries */ 05104 pos = 1; 05105 for (qe = q->head; qe; qe = qe->next) { 05106 astman_append(s, "Event: QueueEntry\r\n" 05107 "Queue: %s\r\n" 05108 "Position: %d\r\n" 05109 "Channel: %s\r\n" 05110 "CallerID: %s\r\n" 05111 "CallerIDName: %s\r\n" 05112 "Wait: %ld\r\n" 05113 "%s" 05114 "\r\n", 05115 q->name, pos++, qe->chan->name, 05116 S_OR(qe->chan->cid.cid_num, "unknown"), 05117 S_OR(qe->chan->cid.cid_name, "unknown"), 05118 (long) (now - qe->start), idText); 05119 } 05120 } 05121 ao2_unlock(q); 05122 } 05123 05124 astman_append(s, 05125 "Event: QueueStatusComplete\r\n" 05126 "%s" 05127 "\r\n",idText); 05128 05129 AST_LIST_UNLOCK(&queues); 05130 05131 05132 return RESULT_SUCCESS; 05133 }
static int manager_remove_queue_member | ( | struct mansession * | s, | |
const struct message * | m | |||
) | [static] |
Definition at line 5186 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().
05187 { 05188 const char *queuename, *interface; 05189 05190 queuename = astman_get_header(m, "Queue"); 05191 interface = astman_get_header(m, "Interface"); 05192 05193 if (ast_strlen_zero(queuename) || ast_strlen_zero(interface)) { 05194 astman_send_error(s, m, "Need 'Queue' and 'Interface' parameters."); 05195 return 0; 05196 } 05197 05198 switch (remove_from_queue(queuename, interface)) { 05199 case RES_OKAY: 05200 ast_queue_log(queuename, "MANAGER", interface, "REMOVEMEMBER", "%s", ""); 05201 astman_send_ack(s, m, "Removed interface from queue"); 05202 break; 05203 case RES_EXISTS: 05204 astman_send_error(s, m, "Unable to remove interface: Not there"); 05205 break; 05206 case RES_NOSUCHQUEUE: 05207 astman_send_error(s, m, "Unable to remove interface from queue: No such queue"); 05208 break; 05209 case RES_OUTOFMEMORY: 05210 astman_send_error(s, m, "Out of memory"); 05211 break; 05212 case RES_NOT_DYNAMIC: 05213 astman_send_error(s, m, "Member not dynamic"); 05214 break; 05215 } 05216 05217 return 0; 05218 }
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_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_UNKNOWN: 01842 if (!mem->paused) { 01843 avl++; 01844 } 01845 break; 01846 } 01847 ao2_ref(mem, -1); 01848 01849 /* If autofill is not enabled or if the queue's strategy is ringall, then 01850 * we really don't care about the number of available members so much as we 01851 * do that there is at least one available. 01852 * 01853 * In fact, we purposely will return from this function stating that only 01854 * one member is available if either of those conditions hold. That way, 01855 * functions which determine what action to take based on the number of available 01856 * members will operate properly. The reasoning is that even if multiple 01857 * members are available, only the head caller can actually be serviced. 01858 */ 01859 if ((!q->autofill || q->strategy == QUEUE_STRATEGY_RINGALL) && avl) { 01860 break; 01861 } 01862 } 01863 ao2_iterator_destroy(&mem_iter); 01864 01865 return avl; 01866 }
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 3809 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().
03810 { 03811 struct ast_module_user *lu; 03812 char *parse; 03813 int priority_jump = 0; 03814 int ignore_fail = 0; 03815 AST_DECLARE_APP_ARGS(args, 03816 AST_APP_ARG(queuename); 03817 AST_APP_ARG(interface); 03818 AST_APP_ARG(options); 03819 ); 03820 03821 if (ast_strlen_zero(data)) { 03822 ast_log(LOG_WARNING, "PauseQueueMember requires an argument ([queuename]|interface[|options])\n"); 03823 return -1; 03824 } 03825 03826 parse = ast_strdupa(data); 03827 03828 AST_STANDARD_APP_ARGS(args, parse); 03829 03830 lu = ast_module_user_add(chan); 03831 03832 if (args.options) { 03833 if (strchr(args.options, 'j')) 03834 priority_jump = 1; 03835 if (strchr(args.options, 'i')) 03836 ignore_fail = 1; 03837 } 03838 03839 if (ast_strlen_zero(args.interface)) { 03840 ast_log(LOG_WARNING, "Missing interface argument to PauseQueueMember ([queuename]|interface[|options])\n"); 03841 ast_module_user_remove(lu); 03842 return -1; 03843 } 03844 03845 if (set_member_paused(args.queuename, args.interface, 1)) { 03846 ast_log(LOG_WARNING, "Attempt to pause interface %s, not found\n", args.interface); 03847 pbx_builtin_setvar_helper(chan, "PQMSTATUS", "NOTFOUND"); 03848 if (priority_jump || ast_opt_priority_jumping) { 03849 if (!ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101)) { 03850 ast_module_user_remove(lu); 03851 return 0; 03852 } 03853 } 03854 ast_module_user_remove(lu); 03855 if (ignore_fail) { 03856 return 0; 03857 } else { 03858 return -1; 03859 } 03860 } 03861 03862 ast_module_user_remove(lu); 03863 pbx_builtin_setvar_helper(chan, "PQMSTATUS", "PAUSED"); 03864 return 0; 03865 }
static int ql_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Definition at line 4067 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().
04068 { 04069 struct ast_module_user *u; 04070 char *parse; 04071 04072 AST_DECLARE_APP_ARGS(args, 04073 AST_APP_ARG(queuename); 04074 AST_APP_ARG(uniqueid); 04075 AST_APP_ARG(membername); 04076 AST_APP_ARG(event); 04077 AST_APP_ARG(params); 04078 ); 04079 04080 if (ast_strlen_zero(data)) { 04081 ast_log(LOG_WARNING, "QueueLog requires arguments (queuename|uniqueid|membername|event[|additionalinfo]\n"); 04082 return -1; 04083 } 04084 04085 u = ast_module_user_add(chan); 04086 04087 parse = ast_strdupa(data); 04088 04089 AST_STANDARD_APP_ARGS(args, parse); 04090 04091 if (ast_strlen_zero(args.queuename) || ast_strlen_zero(args.uniqueid) 04092 || ast_strlen_zero(args.membername) || ast_strlen_zero(args.event)) { 04093 ast_log(LOG_WARNING, "QueueLog requires arguments (queuename|uniqueid|membername|event[|additionalinfo])\n"); 04094 ast_module_user_remove(u); 04095 return -1; 04096 } 04097 04098 ast_queue_log(args.queuename, args.uniqueid, args.membername, args.event, 04099 "%s", args.params ? args.params : ""); 04100 04101 ast_module_user_remove(u); 04102 04103 return 0; 04104 }
static int qmc_handler | ( | const char * | queuename, | |
char * | buffer, | |||
int | len | |||
) | [static] |
Definition at line 5465 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().
05466 { 05467 struct member_count qmc; 05468 memset(&qmc, 0, sizeof(qmc)); 05469 if (queue_member_count(queuename, &qmc) != 0) { 05470 return RESULT_FAILURE; 05471 } else { 05472 snprintf(buffer, len, 05473 "valid:%d inuse:%d paused:%d active:%d free:%d all:%d", 05474 qmc.valid, qmc.inuse, qmc.paused, qmc.active, qmc.free, qmc.all); 05475 return RESULT_SUCCESS; 05476 } 05477 }
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 4118 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().
04119 { 04120 int res=-1; 04121 int ringing=0; 04122 struct ast_module_user *lu; 04123 const char *user_priority; 04124 const char *max_penalty_str; 04125 int prio; 04126 int max_penalty; 04127 enum queue_result reason = QUEUE_UNKNOWN; 04128 /* whether to exit Queue application after the timeout hits */ 04129 int tries = 0; 04130 int noption = 0; 04131 char *parse; 04132 AST_DECLARE_APP_ARGS(args, 04133 AST_APP_ARG(queuename); 04134 AST_APP_ARG(options); 04135 AST_APP_ARG(url); 04136 AST_APP_ARG(announceoverride); 04137 AST_APP_ARG(queuetimeoutstr); 04138 AST_APP_ARG(agi); 04139 ); 04140 /* Our queue entry */ 04141 struct queue_ent qe = { 0 }; 04142 04143 if (ast_strlen_zero(data)) { 04144 ast_log(LOG_WARNING, "Queue requires an argument: queuename[|options[|URL[|announceoverride[|timeout[|agi]]]]]\n"); 04145 return -1; 04146 } 04147 04148 parse = ast_strdupa(data); 04149 AST_STANDARD_APP_ARGS(args, parse); 04150 04151 lu = ast_module_user_add(chan); 04152 04153 /* Setup our queue entry */ 04154 qe.start = time(NULL); 04155 04156 /* set the expire time based on the supplied timeout; */ 04157 if (!ast_strlen_zero(args.queuetimeoutstr)) 04158 qe.expire = qe.start + atoi(args.queuetimeoutstr); 04159 else 04160 qe.expire = 0; 04161 04162 /* Get the priority from the variable ${QUEUE_PRIO} */ 04163 user_priority = pbx_builtin_getvar_helper(chan, "QUEUE_PRIO"); 04164 if (user_priority) { 04165 if (sscanf(user_priority, "%30d", &prio) == 1) { 04166 if (option_debug) 04167 ast_log(LOG_DEBUG, "%s: Got priority %d from ${QUEUE_PRIO}.\n", 04168 chan->name, prio); 04169 } else { 04170 ast_log(LOG_WARNING, "${QUEUE_PRIO}: Invalid value (%s), channel %s.\n", 04171 user_priority, chan->name); 04172 prio = 0; 04173 } 04174 } else { 04175 if (option_debug > 2) 04176 ast_log(LOG_DEBUG, "NO QUEUE_PRIO variable found. Using default.\n"); 04177 prio = 0; 04178 } 04179 04180 /* Get the maximum penalty from the variable ${QUEUE_MAX_PENALTY} */ 04181 if ((max_penalty_str = pbx_builtin_getvar_helper(chan, "QUEUE_MAX_PENALTY"))) { 04182 if (sscanf(max_penalty_str, "%30d", &max_penalty) == 1) { 04183 if (option_debug) 04184 ast_log(LOG_DEBUG, "%s: Got max penalty %d from ${QUEUE_MAX_PENALTY}.\n", 04185 chan->name, max_penalty); 04186 } else { 04187 ast_log(LOG_WARNING, "${QUEUE_MAX_PENALTY}: Invalid value (%s), channel %s.\n", 04188 max_penalty_str, chan->name); 04189 max_penalty = 0; 04190 } 04191 } else { 04192 max_penalty = 0; 04193 } 04194 04195 if (args.options && (strchr(args.options, 'r'))) 04196 ringing = 1; 04197 04198 if (ringing != 1 && args.options && (strchr(args.options, 'R'))) { 04199 qe.ring_when_ringing = 1; 04200 } 04201 04202 if (option_debug) 04203 ast_log(LOG_DEBUG, "queue: %s, options: %s, url: %s, announce: %s, expires: %ld, priority: %d\n", 04204 args.queuename, args.options, args.url, args.announceoverride, (long)qe.expire, prio); 04205 04206 qe.chan = chan; 04207 qe.prio = prio; 04208 qe.max_penalty = max_penalty; 04209 qe.last_pos_said = 0; 04210 qe.last_pos = 0; 04211 qe.last_periodic_announce_time = time(NULL); 04212 qe.last_periodic_announce_sound = 0; 04213 qe.valid_digits = 0; 04214 if (!join_queue(args.queuename, &qe, &reason)) { 04215 int makeannouncement = 0; 04216 04217 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "ENTERQUEUE", "%s|%s", S_OR(args.url, ""), 04218 S_OR(chan->cid.cid_num, "")); 04219 check_turns: 04220 if (ringing) { 04221 ast_indicate(chan, AST_CONTROL_RINGING); 04222 } else { 04223 ast_moh_start(chan, qe.moh, NULL); 04224 } 04225 04226 /* This is the wait loop for callers 2 through maxlen */ 04227 res = wait_our_turn(&qe, ringing, &reason); 04228 if (res) 04229 goto stop; 04230 04231 for (;;) { 04232 /* This is the wait loop for the head caller*/ 04233 /* To exit, they may get their call answered; */ 04234 /* they may dial a digit from the queue context; */ 04235 /* or, they may timeout. */ 04236 04237 enum queue_member_status stat; 04238 04239 /* Leave if we have exceeded our queuetimeout */ 04240 if (qe.expire && (time(NULL) >= qe.expire)) { 04241 record_abandoned(&qe); 04242 reason = QUEUE_TIMEOUT; 04243 res = 0; 04244 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHTIMEOUT", "%d", qe.pos); 04245 break; 04246 } 04247 04248 if (makeannouncement) { 04249 /* Make a position announcement, if enabled */ 04250 if (qe.parent->announcefrequency && !ringing) 04251 if ((res = say_position(&qe))) 04252 goto stop; 04253 04254 } 04255 makeannouncement = 1; 04256 04257 /* Leave if we have exceeded our queuetimeout */ 04258 if (qe.expire && (time(NULL) >= qe.expire)) { 04259 record_abandoned(&qe); 04260 reason = QUEUE_TIMEOUT; 04261 res = 0; 04262 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHTIMEOUT", "%d", qe.pos); 04263 break; 04264 } 04265 /* Make a periodic announcement, if enabled */ 04266 if (qe.parent->periodicannouncefrequency && !ringing) 04267 if ((res = say_periodic_announcement(&qe))) 04268 goto stop; 04269 04270 /* Leave if we have exceeded our queuetimeout */ 04271 if (qe.expire && (time(NULL) >= qe.expire)) { 04272 record_abandoned(&qe); 04273 reason = QUEUE_TIMEOUT; 04274 res = 0; 04275 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHTIMEOUT", "%d", qe.pos); 04276 break; 04277 } 04278 /* Try calling all queue members for 'timeout' seconds */ 04279 res = try_calling(&qe, args.options, args.announceoverride, args.url, &tries, &noption, args.agi); 04280 if (res) 04281 goto stop; 04282 04283 stat = get_member_status(qe.parent, qe.max_penalty); 04284 04285 /* exit after 'timeout' cycle if 'n' option enabled */ 04286 if (noption && tries >= qe.parent->membercount) { 04287 if (option_verbose > 2) 04288 ast_verbose(VERBOSE_PREFIX_3 "Exiting on time-out cycle\n"); 04289 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHTIMEOUT", "%d", qe.pos); 04290 record_abandoned(&qe); 04291 reason = QUEUE_TIMEOUT; 04292 res = 0; 04293 break; 04294 } 04295 04296 /* leave the queue if no agents, if enabled */ 04297 if (qe.parent->leavewhenempty && (stat == QUEUE_NO_MEMBERS)) { 04298 record_abandoned(&qe); 04299 reason = QUEUE_LEAVEEMPTY; 04300 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe.pos, qe.opos, (long)(time(NULL) - qe.start)); 04301 res = 0; 04302 break; 04303 } 04304 04305 /* leave the queue if no reachable agents, if enabled */ 04306 if ((qe.parent->leavewhenempty == QUEUE_EMPTY_STRICT) && (stat == QUEUE_NO_REACHABLE_MEMBERS)) { 04307 record_abandoned(&qe); 04308 reason = QUEUE_LEAVEUNAVAIL; 04309 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe.pos, qe.opos, (long)(time(NULL) - qe.start)); 04310 res = 0; 04311 break; 04312 } 04313 04314 /* Leave if we have exceeded our queuetimeout */ 04315 if (qe.expire && (time(NULL) >= qe.expire)) { 04316 record_abandoned(&qe); 04317 reason = QUEUE_TIMEOUT; 04318 res = 0; 04319 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHTIMEOUT", "%d", qe.pos); 04320 break; 04321 } 04322 04323 /* If using dynamic realtime members, we should regenerate the member list for this queue */ 04324 update_realtime_members(qe.parent); 04325 04326 /* OK, we didn't get anybody; wait for 'retry' seconds; may get a digit to exit with */ 04327 res = wait_a_bit(&qe); 04328 if (res) 04329 goto stop; 04330 04331 /* Since this is a priority queue and 04332 * it is not sure that we are still at the head 04333 * of the queue, go and check for our turn again. 04334 */ 04335 if (!is_our_turn(&qe)) { 04336 if (option_debug) 04337 ast_log(LOG_DEBUG, "Darn priorities, going back in queue (%s)!\n", 04338 qe.chan->name); 04339 goto check_turns; 04340 } 04341 } 04342 04343 stop: 04344 if (res) { 04345 if (res < 0) { 04346 if (!qe.handled) { 04347 record_abandoned(&qe); 04348 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "ABANDON", 04349 "%d|%d|%ld", qe.pos, qe.opos, 04350 (long) time(NULL) - qe.start); 04351 } 04352 res = -1; 04353 } else if (qe.valid_digits) { 04354 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHKEY", 04355 "%s|%d", qe.digits, qe.pos); 04356 } 04357 } 04358 04359 /* Don't allow return code > 0 */ 04360 if (res >= 0) { 04361 res = 0; 04362 if (ringing) { 04363 ast_indicate(chan, -1); 04364 } else { 04365 ast_moh_stop(chan); 04366 } 04367 ast_stopstream(chan); 04368 } 04369 leave_queue(&qe); 04370 if (reason != QUEUE_UNKNOWN) 04371 set_queue_result(chan, reason); 04372 } else { 04373 ast_log(LOG_WARNING, "Unable to join queue '%s'\n", args.queuename); 04374 set_queue_result(chan, reason); 04375 res = 0; 04376 } 04377 if (qe.parent) { 04378 /* every queue_ent is given a reference to it's parent call_queue when it joins the queue. 04379 * This ref must be taken away right before the queue_ent is destroyed. In this case 04380 * the queue_ent is about to be returned on the stack */ 04381 ao2_ref(qe.parent, -1); 04382 } 04383 ast_module_user_remove(lu); 04384 04385 return res; 04386 }
static int queue_function_queuemembercount | ( | struct ast_channel * | chan, | |
char * | cmd, | |||
char * | data, | |||
char * | buf, | |||
size_t | len | |||
) | [static] |
Definition at line 4396 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.
04397 { 04398 int count = 0; 04399 struct call_queue *q; 04400 struct ast_module_user *lu; 04401 struct member *m; 04402 struct ao2_iterator mem_iter; 04403 char *name, *item; 04404 enum qmc_status mode = QMC_VALID; 04405 04406 buf[0] = '\0'; 04407 04408 if (ast_strlen_zero(data)) { 04409 ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd); 04410 return -1; 04411 } 04412 04413 name = ast_strdupa(data); 04414 04415 lu = ast_module_user_add(chan); 04416 04417 if ((item = strchr(name, ':'))) { 04418 *item = '\0'; 04419 item++; 04420 } else { 04421 item = ""; 04422 } 04423 04424 if (!strcasecmp(item, "valid")) { 04425 mode = QMC_VALID; 04426 } else if (!strcasecmp(item, "paused")) { 04427 mode = QMC_PAUSED; 04428 } else if (!strcasecmp(item, "active")) { 04429 mode = QMC_ACTIVE; 04430 } else if (!strcasecmp(item, "free")) { 04431 mode = QMC_FREE; 04432 } else if (!strcasecmp(item, "all")) { 04433 mode = QMC_ALL; 04434 } 04435 04436 if ((q = load_realtime_queue(name))) { 04437 ao2_lock(q); 04438 mem_iter = ao2_iterator_init(q->members, 0); 04439 while ((m = ao2_iterator_next(&mem_iter))) { 04440 switch (mode) { 04441 case QMC_VALID: 04442 /* Count the queue members who are logged in and presently answering calls */ 04443 if ((m->status != AST_DEVICE_UNAVAILABLE) && (m->status != AST_DEVICE_INVALID)) { 04444 count++; 04445 } 04446 break; 04447 case QMC_PAUSED: 04448 /* Count paused members */ 04449 if (m->paused) { 04450 count++; 04451 } 04452 break; 04453 case QMC_ACTIVE: 04454 /* Count not paused members who are logged in and presently answering calls */ 04455 if (!m->paused && (m->status != AST_DEVICE_UNAVAILABLE) && (m->status != AST_DEVICE_INVALID)) { 04456 count++; 04457 } 04458 break; 04459 case QMC_FREE: 04460 /* Count free members in the queue */ 04461 if (!m->paused && ((m->status == AST_DEVICE_UNKNOWN) || (m->status == AST_DEVICE_NOT_INUSE))) { 04462 count++; 04463 } 04464 break; 04465 default: 04466 count++; 04467 break; 04468 } 04469 ao2_ref(m, -1); 04470 } 04471 ao2_iterator_destroy(&mem_iter); 04472 ao2_unlock(q); 04473 } else 04474 ast_log(LOG_WARNING, "queue %s was not found\n", name); 04475 04476 snprintf(buf, len, "%d", count); 04477 ast_module_user_remove(lu); 04478 04479 return 0; 04480 }
static int queue_function_queuememberlist | ( | struct ast_channel * | chan, | |
char * | cmd, | |||
char * | data, | |||
char * | buf, | |||
size_t | len | |||
) | [static] |
Definition at line 4525 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.
04526 { 04527 struct ast_module_user *u; 04528 struct call_queue *q; 04529 struct member *m; 04530 04531 /* Ensure an otherwise empty list doesn't return garbage */ 04532 buf[0] = '\0'; 04533 04534 if (ast_strlen_zero(data)) { 04535 ast_log(LOG_ERROR, "QUEUE_MEMBER_LIST requires an argument: queuename\n"); 04536 return -1; 04537 } 04538 04539 u = ast_module_user_add(chan); 04540 04541 AST_LIST_LOCK(&queues); 04542 AST_LIST_TRAVERSE(&queues, q, list) { 04543 if (!strcasecmp(q->name, data)) { 04544 ao2_lock(q); 04545 break; 04546 } 04547 } 04548 AST_LIST_UNLOCK(&queues); 04549 04550 if (q) { 04551 int buflen = 0, count = 0; 04552 struct ao2_iterator mem_iter = ao2_iterator_init(q->members, 0); 04553 04554 while ((m = ao2_iterator_next(&mem_iter))) { 04555 /* strcat() is always faster than printf() */ 04556 if (count++) { 04557 strncat(buf + buflen, ",", len - buflen - 1); 04558 buflen++; 04559 } 04560 strncat(buf + buflen, m->interface, len - buflen - 1); 04561 buflen += strlen(m->interface); 04562 /* Safeguard against overflow (negative length) */ 04563 if (buflen >= len - 2) { 04564 ao2_ref(m, -1); 04565 ast_log(LOG_WARNING, "Truncating list\n"); 04566 break; 04567 } 04568 ao2_ref(m, -1); 04569 } 04570 ao2_iterator_destroy(&mem_iter); 04571 ao2_unlock(q); 04572 } else 04573 ast_log(LOG_WARNING, "queue %s was not found\n", data); 04574 04575 /* We should already be terminated, but let's make sure. */ 04576 buf[len - 1] = '\0'; 04577 ast_module_user_remove(u); 04578 04579 return 0; 04580 }
static int queue_function_queuewaitingcount | ( | struct ast_channel * | chan, | |
char * | cmd, | |||
char * | data, | |||
char * | buf, | |||
size_t | len | |||
) | [static] |
Definition at line 4482 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.
04483 { 04484 int count = 0; 04485 struct call_queue *q; 04486 struct ast_module_user *lu; 04487 struct ast_variable *var = NULL; 04488 04489 buf[0] = '\0'; 04490 04491 if (ast_strlen_zero(data)) { 04492 ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd); 04493 return -1; 04494 } 04495 04496 lu = ast_module_user_add(chan); 04497 04498 AST_LIST_LOCK(&queues); 04499 AST_LIST_TRAVERSE(&queues, q, list) { 04500 if (!strcasecmp(q->name, data)) { 04501 ao2_lock(q); 04502 break; 04503 } 04504 } 04505 AST_LIST_UNLOCK(&queues); 04506 04507 if (q) { 04508 count = q->count; 04509 ao2_unlock(q); 04510 } else if ((var = ast_load_realtime("queues", "name", data, NULL))) { 04511 /* if the queue is realtime but was not found in memory, this 04512 * means that the queue had been deleted from memory since it was 04513 * "dead." This means it has a 0 waiting count 04514 */ 04515 count = 0; 04516 ast_variables_destroy(var); 04517 } else 04518 ast_log(LOG_WARNING, "queue %s was not found\n", data); 04519 04520 snprintf(buf, len, "%d", count); 04521 ast_module_user_remove(lu); 04522 return 0; 04523 }
static int queue_member_count | ( | const char * | qname, | |
struct member_count * | qmc | |||
) | [static] |
Definition at line 5423 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().
05424 { 05425 int res = 0; 05426 struct call_queue *q; 05427 struct member *m; 05428 struct ao2_iterator mem_iter; 05429 05430 if ((q = load_realtime_queue(qname))) { 05431 ao2_lock(q); 05432 mem_iter = ao2_iterator_init(q->members, 0); 05433 while ((m = ao2_iterator_next(&mem_iter))) { 05434 /* Count the queue members in use */ 05435 if (m->status == AST_DEVICE_INUSE) { 05436 qmc->inuse++; 05437 } 05438 /* Count the queue members who are logged in and presently answering calls */ 05439 if ((m->status != AST_DEVICE_UNAVAILABLE) && (m->status != AST_DEVICE_INVALID)) { 05440 qmc->valid++; 05441 } 05442 /* Count paused members */ 05443 if (m->paused) { 05444 qmc->paused++; 05445 } 05446 /* Count not paused members who are logged in and presently answering calls */ 05447 if (!m->paused && (m->status != AST_DEVICE_UNAVAILABLE) && (m->status != AST_DEVICE_INVALID)) { 05448 qmc->active++; 05449 } 05450 /* Count free members in the queue */ 05451 if (!m->paused && ((m->status == AST_DEVICE_UNKNOWN) || (m->status == AST_DEVICE_NOT_INUSE))) { 05452 qmc->free++; 05453 } 05454 qmc->all++; 05455 ao2_ref(m, -1); 05456 } 05457 ao2_unlock(q); 05458 } else { 05459 ast_log(LOG_WARNING, "Queue %s was not found\n", qname); 05460 res = -1; 05461 } 05462 return res; 05463 }
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 4995 of file app_queue.c.
References __queues_show().
Referenced by __queues_show().
04996 { 04997 return __queues_show(NULL, 0, fd, argc, argv); 04998 }
static void queue_transfer_destroy | ( | void * | data | ) | [static] |
Definition at line 2765 of file app_queue.c.
References ast_free.
02766 { 02767 struct queue_transfer_ds *qtds = data; 02768 ast_free(qtds); 02769 }
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 2788 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().
02789 { 02790 struct queue_transfer_ds *qtds = data; 02791 struct queue_ent *qe = qtds->qe; 02792 struct member *member = qtds->member; 02793 time_t callstart = qtds->starttime; 02794 int callcompletedinsl = qtds->callcompletedinsl; 02795 struct ast_datastore *datastore; 02796 02797 ast_queue_log(qe->parent->name, qe->chan->uniqueid, member->membername, "TRANSFER", "%s|%s|%ld|%ld", 02798 new_chan->exten, new_chan->context, (long) (callstart - qe->start), 02799 (long) (time(NULL) - callstart)); 02800 02801 update_queue(qe->parent, member, callcompletedinsl); 02802 02803 /* No need to lock the channels because they are already locked in ast_do_masquerade */ 02804 if ((datastore = ast_channel_datastore_find(old_chan, &queue_transfer_info, NULL))) { 02805 ast_channel_datastore_remove(old_chan, datastore); 02806 } else { 02807 ast_log(LOG_WARNING, "Can't find the queue_transfer datastore.\n"); 02808 } 02809 }
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 2228 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().
02229 { 02230 ao2_lock(qe->parent); 02231 manager_event(EVENT_FLAG_AGENT, "QueueCallerAbandon", 02232 "Queue: %s\r\n" 02233 "Uniqueid: %s\r\n" 02234 "Position: %d\r\n" 02235 "OriginalPosition: %d\r\n" 02236 "HoldTime: %d\r\n", 02237 qe->parent->name, qe->chan->uniqueid, qe->pos, qe->opos, (int)(time(NULL) - qe->start)); 02238 02239 qe->parent->callsabandoned++; 02240 ao2_unlock(qe->parent); 02241 }
static int reload | ( | void | ) | [static] |
Definition at line 5661 of file app_queue.c.
References reload_queues().
05662 { 05663 reload_queues(); 05664 return 0; 05665 }
static void reload_queue_members | ( | void | ) | [static] |
Definition at line 3712 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().
03713 { 03714 char *cur_ptr; 03715 char *queue_name; 03716 char *member; 03717 char *interface; 03718 char *membername = NULL; 03719 char *state_interface; 03720 char *penalty_tok; 03721 int penalty = 0; 03722 char *paused_tok; 03723 int paused = 0; 03724 struct ast_db_entry *db_tree; 03725 struct ast_db_entry *entry; 03726 struct call_queue *cur_queue; 03727 char queue_data[PM_MAX_LEN]; 03728 03729 AST_LIST_LOCK(&queues); 03730 03731 /* Each key in 'pm_family' is the name of a queue */ 03732 db_tree = ast_db_gettree(pm_family, NULL); 03733 for (entry = db_tree; entry; entry = entry->next) { 03734 03735 queue_name = entry->key + strlen(pm_family) + 2; 03736 03737 AST_LIST_TRAVERSE(&queues, cur_queue, list) { 03738 ao2_lock(cur_queue); 03739 if (!strcmp(queue_name, cur_queue->name)) 03740 break; 03741 ao2_unlock(cur_queue); 03742 } 03743 03744 if (!cur_queue) 03745 cur_queue = load_realtime_queue(queue_name); 03746 03747 if (!cur_queue) { 03748 /* If the queue no longer exists, remove it from the 03749 * database */ 03750 ast_log(LOG_WARNING, "Error loading persistent queue: '%s': it does not exist\n", queue_name); 03751 ast_db_del(pm_family, queue_name); 03752 continue; 03753 } else 03754 ao2_unlock(cur_queue); 03755 03756 if (ast_db_get(pm_family, queue_name, queue_data, PM_MAX_LEN)) 03757 continue; 03758 03759 cur_ptr = queue_data; 03760 while ((member = strsep(&cur_ptr, "|"))) { 03761 if (ast_strlen_zero(member)) 03762 continue; 03763 03764 interface = strsep(&member, ";"); 03765 penalty_tok = strsep(&member, ";"); 03766 paused_tok = strsep(&member, ";"); 03767 membername = strsep(&member, ";"); 03768 state_interface = strsep(&member,";"); 03769 03770 if (!penalty_tok) { 03771 ast_log(LOG_WARNING, "Error parsing persistent member string for '%s' (penalty)\n", queue_name); 03772 break; 03773 } 03774 penalty = strtol(penalty_tok, NULL, 10); 03775 if (errno == ERANGE) { 03776 ast_log(LOG_WARNING, "Error converting penalty: %s: Out of range.\n", penalty_tok); 03777 break; 03778 } 03779 03780 if (!paused_tok) { 03781 ast_log(LOG_WARNING, "Error parsing persistent member string for '%s' (paused)\n", queue_name); 03782 break; 03783 } 03784 paused = strtol(paused_tok, NULL, 10); 03785 if ((errno == ERANGE) || paused < 0 || paused > 1) { 03786 ast_log(LOG_WARNING, "Error converting paused: %s: Expected 0 or 1.\n", paused_tok); 03787 break; 03788 } 03789 if (ast_strlen_zero(membername)) 03790 membername = interface; 03791 03792 if (option_debug) 03793 ast_log(LOG_DEBUG, "Reload Members: Queue: %s Member: %s Name: %s Penalty: %d Paused: %d\n", queue_name, interface, membername, penalty, paused); 03794 03795 if (add_to_queue(queue_name, interface, membername, penalty, paused, 0, state_interface) == RES_OUTOFMEMORY) { 03796 ast_log(LOG_ERROR, "Out of Memory when reloading persistent queue member\n"); 03797 break; 03798 } 03799 } 03800 } 03801 03802 AST_LIST_UNLOCK(&queues); 03803 if (db_tree) { 03804 ast_log(LOG_NOTICE, "Queue members successfully reloaded from database.\n"); 03805 ast_db_freetree(db_tree); 03806 } 03807 }
static int reload_queues | ( | void | ) | [static] |
Definition at line 4625 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().
04626 { 04627 struct call_queue *q; 04628 struct ast_config *cfg; 04629 char *cat, *tmp; 04630 struct ast_variable *var; 04631 struct member *cur, *newm; 04632 struct ao2_iterator mem_iter; 04633 int new; 04634 const char *general_val = NULL; 04635 char *parse; 04636 char *interface, *state_interface; 04637 char *membername = NULL; 04638 int penalty; 04639 AST_DECLARE_APP_ARGS(args, 04640 AST_APP_ARG(interface); 04641 AST_APP_ARG(penalty); 04642 AST_APP_ARG(membername); 04643 AST_APP_ARG(state_interface); 04644 ); 04645 04646 if (!(cfg = ast_config_load("queues.conf"))) { 04647 ast_log(LOG_NOTICE, "No call queueing config file (queues.conf), so no call queues\n"); 04648 return 0; 04649 } 04650 AST_LIST_LOCK(&queues); 04651 use_weight=0; 04652 /* Mark all non-realtime queues as dead for the moment */ 04653 AST_LIST_TRAVERSE(&queues, q, list) { 04654 if (!q->realtime) { 04655 q->dead = 1; 04656 q->found = 0; 04657 } 04658 } 04659 04660 /* Chug through config file */ 04661 cat = NULL; 04662 while ((cat = ast_category_browse(cfg, cat)) ) { 04663 if (!strcasecmp(cat, "general")) { 04664 /* Initialize global settings */ 04665 queue_debug = 0; 04666 if ((general_val = ast_variable_retrieve(cfg, "general", "debug"))) 04667 queue_debug = ast_true(general_val); 04668 queue_persistent_members = 0; 04669 if ((general_val = ast_variable_retrieve(cfg, "general", "persistentmembers"))) 04670 queue_persistent_members = ast_true(general_val); 04671 autofill_default = 0; 04672 if ((general_val = ast_variable_retrieve(cfg, "general", "autofill"))) 04673 autofill_default = ast_true(general_val); 04674 montype_default = 0; 04675 if ((general_val = ast_variable_retrieve(cfg, "general", "monitor-type"))) 04676 if (!strcasecmp(general_val, "mixmonitor")) 04677 montype_default = 1; 04678 } else { /* Define queue */ 04679 /* Look for an existing one */ 04680 AST_LIST_TRAVERSE(&queues, q, list) { 04681 if (!strcmp(q->name, cat)) 04682 break; 04683 } 04684 if (!q) { 04685 /* Make one then */ 04686 if (!(q = alloc_queue(cat))) { 04687 /* TODO: Handle memory allocation failure */ 04688 } 04689 new = 1; 04690 } else 04691 new = 0; 04692 if (q) { 04693 const char *tmpvar; 04694 if (!new) 04695 ao2_lock(q); 04696 /* Check if a queue with this name already exists */ 04697 if (q->found) { 04698 ast_log(LOG_WARNING, "Queue '%s' already defined! Skipping!\n", cat); 04699 if (!new) 04700 ao2_unlock(q); 04701 continue; 04702 } 04703 04704 /* Due to the fact that the "rrordered" strategy will have a different allocation 04705 * scheme for queue members, we must devise the queue's strategy before other initializations. 04706 * To be specific, the rrordered strategy needs to function like a linked list, meaning the ao2 04707 * container used will have only a single bucket instead of the typical number. 04708 */ 04709 if ((tmpvar = ast_variable_retrieve(cfg, cat, "strategy"))) { 04710 q->strategy = strat2int(tmpvar); 04711 if (q->strategy < 0) { 04712 ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n", tmpvar, q->name); 04713 q->strategy = QUEUE_STRATEGY_RINGALL; 04714 } 04715 } else { 04716 q->strategy = QUEUE_STRATEGY_RINGALL; 04717 } 04718 04719 /* Re-initialize the queue, and clear statistics */ 04720 init_queue(q); 04721 clear_queue(q); 04722 mem_iter = ao2_iterator_init(q->members, 0); 04723 while ((cur = ao2_iterator_next(&mem_iter))) { 04724 if (!cur->dynamic) { 04725 cur->delme = 1; 04726 } 04727 ao2_ref(cur, -1); 04728 } 04729 ao2_iterator_destroy(&mem_iter); 04730 for (var = ast_variable_browse(cfg, cat); var; var = var->next) { 04731 if (!strcasecmp(var->name, "member")) { 04732 struct member tmpmem; 04733 membername = NULL; 04734 04735 if (ast_strlen_zero(var->value)) { 04736 ast_log(LOG_WARNING, "Empty queue member definition at line %d. Moving on!\n", var->lineno); 04737 continue; 04738 } 04739 04740 /* Add a new member */ 04741 if (!(parse = ast_strdup(var->value))) { 04742 continue; 04743 } 04744 04745 AST_NONSTANDARD_APP_ARGS(args, parse, ','); 04746 04747 interface = args.interface; 04748 if (!ast_strlen_zero(args.penalty)) { 04749 tmp = ast_skip_blanks(args.penalty); 04750 penalty = atoi(tmp); 04751 if (penalty < 0) { 04752 penalty = 0; 04753 } 04754 } else 04755 penalty = 0; 04756 04757 if (!ast_strlen_zero(args.membername)) { 04758 membername = ast_skip_blanks(args.membername); 04759 } 04760 04761 if (!ast_strlen_zero(args.state_interface)) { 04762 state_interface = ast_skip_blanks(args.state_interface); 04763 } else { 04764 state_interface = interface; 04765 } 04766 04767 /* Find the old position in the list */ 04768 ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface)); 04769 cur = ao2_find(q->members, &tmpmem, OBJ_POINTER | OBJ_UNLINK); 04770 04771 /* Only attempt removing from interfaces list if the new state_interface is different than the old one */ 04772 if (cur && strcasecmp(cur->state_interface, state_interface)) { 04773 remove_from_interfaces(cur->state_interface); 04774 } 04775 04776 newm = create_queue_member(interface, membername, penalty, cur ? cur->paused : 0, state_interface); 04777 if (!cur || (cur && strcasecmp(cur->state_interface, state_interface))) { 04778 add_to_interfaces(state_interface); 04779 } 04780 ao2_link(q->members, newm); 04781 ao2_ref(newm, -1); 04782 newm = NULL; 04783 04784 if (cur) 04785 ao2_ref(cur, -1); 04786 else { 04787 q->membercount++; 04788 } 04789 ast_free(parse); 04790 } else { 04791 queue_set_param(q, var->name, var->value, var->lineno, 1); 04792 } 04793 } 04794 04795 /* Free remaining members marked as delme */ 04796 mem_iter = ao2_iterator_init(q->members, 0); 04797 while ((cur = ao2_iterator_next(&mem_iter))) { 04798 if (! cur->delme) { 04799 ao2_ref(cur, -1); 04800 continue; 04801 } 04802 04803 q->membercount--; 04804 ao2_unlink(q->members, cur); 04805 remove_from_interfaces(cur->state_interface); 04806 ao2_ref(cur, -1); 04807 } 04808 ao2_iterator_destroy(&mem_iter); 04809 04810 if (q->strategy == QUEUE_STRATEGY_ROUNDROBIN) 04811 rr_dep_warning(); 04812 04813 if (new) { 04814 AST_LIST_INSERT_HEAD(&queues, q, list); 04815 } else 04816 ao2_unlock(q); 04817 } 04818 } 04819 } 04820 ast_config_destroy(cfg); 04821 AST_LIST_TRAVERSE_SAFE_BEGIN(&queues, q, list) { 04822 if (q->dead) { 04823 AST_LIST_REMOVE_CURRENT(&queues, list); 04824 ao2_ref(q, -1); 04825 } else { 04826 ao2_lock(q); 04827 mem_iter = ao2_iterator_init(q->members, 0); 04828 while ((cur = ao2_iterator_next(&mem_iter))) { 04829 if (cur->dynamic) 04830 q->membercount++; 04831 cur->status = ast_device_state(cur->state_interface); 04832 ao2_ref(cur, -1); 04833 } 04834 ao2_iterator_destroy(&mem_iter); 04835 ao2_unlock(q); 04836 } 04837 } 04838 AST_LIST_TRAVERSE_SAFE_END; 04839 AST_LIST_UNLOCK(&queues); 04840 return 1; 04841 }
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 3560 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().
03561 { 03562 struct call_queue *q; 03563 struct member *mem, tmpmem; 03564 int res = RES_NOSUCHQUEUE; 03565 03566 ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface)); 03567 03568 AST_LIST_LOCK(&queues); 03569 AST_LIST_TRAVERSE(&queues, q, list) { 03570 ao2_lock(q); 03571 if (strcmp(q->name, queuename)) { 03572 ao2_unlock(q); 03573 continue; 03574 } 03575 03576 if ((mem = ao2_find(q->members, &tmpmem, OBJ_POINTER))) { 03577 /* XXX future changes should beware of this assumption!! */ 03578 if (!mem->dynamic) { 03579 res = RES_NOT_DYNAMIC; 03580 ao2_ref(mem, -1); 03581 ao2_unlock(q); 03582 break; 03583 } 03584 q->membercount--; 03585 manager_event(EVENT_FLAG_AGENT, "QueueMemberRemoved", 03586 "Queue: %s\r\n" 03587 "Location: %s\r\n" 03588 "MemberName: %s\r\n", 03589 q->name, mem->interface, mem->membername); 03590 ao2_unlink(q->members, mem); 03591 remove_from_interfaces(mem->state_interface); 03592 ao2_ref(mem, -1); 03593 03594 if (queue_persistent_members) 03595 dump_queue_members(q); 03596 03597 res = RES_OKAY; 03598 } else { 03599 res = RES_EXISTS; 03600 } 03601 ao2_unlock(q); 03602 break; 03603 } 03604 03605 AST_LIST_UNLOCK(&queues); 03606 03607 return res; 03608 }
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 1947 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().
01948 { 01949 int res; 01950 int status; 01951 char tech[256]; 01952 char *location; 01953 const char *macrocontext, *macroexten; 01954 01955 /* on entry here, we know that tmp->chan == NULL */ 01956 if (qe->parent->wrapuptime && (time(NULL) - tmp->lastcall < qe->parent->wrapuptime)) { 01957 if (queue_debug) 01958 ast_log(LOG_NOTICE, "Wrapuptime not yet expired for %s\n", tmp->interface); 01959 if (qe->chan->cdr) 01960 ast_cdr_busy(qe->chan->cdr); 01961 tmp->stillgoing = 0; 01962 (*busies)++; 01963 return 0; 01964 } 01965 01966 if (!qe->parent->ringinuse && (tmp->member->status != AST_DEVICE_NOT_INUSE) && (tmp->member->status != AST_DEVICE_UNKNOWN)) { 01967 if (queue_debug) 01968 ast_log(LOG_NOTICE, "%s in use, can't receive call\n", tmp->interface); 01969 if (qe->chan->cdr) 01970 ast_cdr_busy(qe->chan->cdr); 01971 tmp->stillgoing = 0; 01972 return 0; 01973 } 01974 01975 if (tmp->member->paused) { 01976 if (queue_debug) 01977 ast_log(LOG_NOTICE, "%s paused, can't receive call\n", tmp->interface); 01978 if (qe->chan->cdr) 01979 ast_cdr_busy(qe->chan->cdr); 01980 tmp->stillgoing = 0; 01981 return 0; 01982 } 01983 if (use_weight && compare_weight(qe->parent,tmp->member)) { 01984 if (queue_debug) 01985 ast_log(LOG_NOTICE, "Priority queue delaying call to %s:%s\n", qe->parent->name, tmp->interface); 01986 if (qe->chan->cdr) 01987 ast_cdr_busy(qe->chan->cdr); 01988 tmp->stillgoing = 0; 01989 (*busies)++; 01990 return 0; 01991 } 01992 01993 ast_copy_string(tech, tmp->interface, sizeof(tech)); 01994 if ((location = strchr(tech, '/'))) 01995 *location++ = '\0'; 01996 else 01997 location = ""; 01998 01999 /* Request the peer */ 02000 tmp->chan = ast_request(tech, qe->chan->nativeformats, location, &status); 02001 if (!tmp->chan) { /* If we can't, just go on to the next call */ 02002 if (queue_debug) 02003 ast_log(LOG_NOTICE, "Unable to create channel of type '%s' for Queue\n", tech); 02004 if (qe->chan->cdr) 02005 ast_cdr_busy(qe->chan->cdr); 02006 tmp->stillgoing = 0; 02007 02008 update_status(tmp->member->state_interface, ast_device_state(tmp->member->state_interface)); 02009 02010 ao2_lock(qe->parent); 02011 qe->parent->rrpos++; 02012 ao2_unlock(qe->parent); 02013 02014 (*busies)++; 02015 return 0; 02016 } 02017 02018 /* Increment ring count */ 02019 tmp->member->ringcount++; 02020 tmp->chan->appl = "AppQueue"; 02021 tmp->chan->data = "(Outgoing Line)"; 02022 tmp->chan->whentohangup = 0; 02023 if (tmp->chan->cid.cid_num) 02024 free(tmp->chan->cid.cid_num); 02025 tmp->chan->cid.cid_num = ast_strdup(qe->chan->cid.cid_num); 02026 if (tmp->chan->cid.cid_name) 02027 free(tmp->chan->cid.cid_name); 02028 tmp->chan->cid.cid_name = ast_strdup(qe->chan->cid.cid_name); 02029 if (tmp->chan->cid.cid_ani) 02030 free(tmp->chan->cid.cid_ani); 02031 tmp->chan->cid.cid_ani = ast_strdup(qe->chan->cid.cid_ani); 02032 02033 /* Inherit specially named variables from parent channel */ 02034 ast_channel_inherit_variables(qe->chan, tmp->chan); 02035 ast_channel_datastore_inherit(qe->chan, tmp->chan); 02036 02037 /* Presense of ADSI CPE on outgoing channel follows ours */ 02038 tmp->chan->adsicpe = qe->chan->adsicpe; 02039 02040 /* Inherit context and extension */ 02041 ast_channel_lock(qe->chan); 02042 macrocontext = pbx_builtin_getvar_helper(qe->chan, "MACRO_CONTEXT"); 02043 if (!ast_strlen_zero(macrocontext)) 02044 ast_copy_string(tmp->chan->dialcontext, macrocontext, sizeof(tmp->chan->dialcontext)); 02045 else 02046 ast_copy_string(tmp->chan->dialcontext, qe->chan->context, sizeof(tmp->chan->dialcontext)); 02047 macroexten = pbx_builtin_getvar_helper(qe->chan, "MACRO_EXTEN"); 02048 if (!ast_strlen_zero(macroexten)) 02049 ast_copy_string(tmp->chan->exten, macroexten, sizeof(tmp->chan->exten)); 02050 else 02051 ast_copy_string(tmp->chan->exten, qe->chan->exten, sizeof(tmp->chan->exten)); 02052 if (ast_cdr_isset_unanswered()) { 02053 /* they want to see the unanswered dial attempts! */ 02054 /* set up the CDR fields on all the CDRs to give sensical information */ 02055 ast_cdr_setdestchan(tmp->chan->cdr, tmp->chan->name); 02056 strcpy(tmp->chan->cdr->clid, qe->chan->cdr->clid); 02057 strcpy(tmp->chan->cdr->channel, qe->chan->cdr->channel); 02058 strcpy(tmp->chan->cdr->src, qe->chan->cdr->src); 02059 strcpy(tmp->chan->cdr->dst, qe->chan->exten); 02060 strcpy(tmp->chan->cdr->dcontext, qe->chan->context); 02061 strcpy(tmp->chan->cdr->lastapp, qe->chan->cdr->lastapp); 02062 strcpy(tmp->chan->cdr->lastdata, qe->chan->cdr->lastdata); 02063 tmp->chan->cdr->amaflags = qe->chan->cdr->amaflags; 02064 strcpy(tmp->chan->cdr->accountcode, qe->chan->cdr->accountcode); 02065 strcpy(tmp->chan->cdr->userfield, qe->chan->cdr->userfield); 02066 } 02067 ast_channel_unlock(qe->chan); 02068 02069 /* Place the call, but don't wait on the answer */ 02070 if ((res = ast_call(tmp->chan, location, 0))) { 02071 /* Again, keep going even if there's an error */ 02072 if (option_debug) 02073 ast_log(LOG_DEBUG, "ast call on peer returned %d\n", res); 02074 if (option_verbose > 2) 02075 ast_verbose(VERBOSE_PREFIX_3 "Couldn't call %s\n", tmp->interface); 02076 do_hang(tmp); 02077 (*busies)++; 02078 update_status(tmp->member->state_interface, ast_device_state(tmp->member->state_interface)); 02079 return 0; 02080 } else if (qe->parent->eventwhencalled) { 02081 char vars[2048]; 02082 02083 manager_event(EVENT_FLAG_AGENT, "AgentCalled", 02084 "AgentCalled: %s\r\n" 02085 "AgentName: %s\r\n" 02086 "ChannelCalling: %s\r\n" 02087 "CallerID: %s\r\n" 02088 "CallerIDName: %s\r\n" 02089 "Context: %s\r\n" 02090 "Extension: %s\r\n" 02091 "Priority: %d\r\n" 02092 "%s", 02093 tmp->interface, tmp->member->membername, qe->chan->name, 02094 tmp->chan->cid.cid_num ? tmp->chan->cid.cid_num : "unknown", 02095 tmp->chan->cid.cid_name ? tmp->chan->cid.cid_name : "unknown", 02096 qe->chan->context, qe->chan->exten, qe->chan->priority, 02097 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : ""); 02098 if (option_verbose > 2) 02099 ast_verbose(VERBOSE_PREFIX_3 "Called %s\n", tmp->interface); 02100 } 02101 02102 update_status(tmp->member->state_interface, ast_device_state(tmp->member->state_interface)); 02103 return 1; 02104 }
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 2130 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().
02131 { 02132 int ret = 0; 02133 02134 while (ret == 0) { 02135 struct callattempt *best = find_best(outgoing); 02136 if (!best) { 02137 if (option_debug) 02138 ast_log(LOG_DEBUG, "Nobody left to try ringing in queue\n"); 02139 break; 02140 } 02141 if (qe->parent->strategy == QUEUE_STRATEGY_RINGALL) { 02142 struct callattempt *cur; 02143 /* Ring everyone who shares this best metric (for ringall) */ 02144 for (cur = outgoing; cur; cur = cur->q_next) { 02145 if (cur->stillgoing && !cur->chan && cur->metric <= best->metric) { 02146 if (option_debug) 02147 ast_log(LOG_DEBUG, "(Parallel) Trying '%s' with metric %d\n", cur->interface, cur->metric); 02148 ret |= ring_entry(qe, cur, busies); 02149 } 02150 } 02151 } else { 02152 /* Ring just the best channel */ 02153 if (option_debug) 02154 ast_log(LOG_DEBUG, "Trying '%s' with metric %d\n", best->interface, best->metric); 02155 ret = ring_entry(qe, best, busies); 02156 } 02157 } 02158 02159 return ret; 02160 }
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 2244 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.
02245 { 02246 if (option_verbose > 2) 02247 ast_verbose( VERBOSE_PREFIX_3 "Nobody picked up in %d ms\n", rnatime); 02248 02249 /* Stop ringing, and resume MOH if specified */ 02250 if (qe->ring_when_ringing) { 02251 ast_indicate(qe->chan, -1); 02252 ast_moh_start(qe->chan, qe->moh, NULL); 02253 } 02254 02255 ast_queue_log(qe->parent->name, qe->chan->uniqueid, membername, "RINGNOANSWER", "%d", rnatime); 02256 if (qe->parent->autopause && pause) { 02257 if (!set_member_paused(qe->parent->name, interface, 1)) { 02258 if (option_verbose > 2) 02259 ast_verbose( VERBOSE_PREFIX_3 "Auto-Pausing Queue Member %s in queue %s since they failed to answer.\n", interface, qe->parent->name); 02260 } else { 02261 if (option_verbose > 2) 02262 ast_verbose( VERBOSE_PREFIX_3 "Failed to pause Queue Member %s in queue %s!\n", interface, qe->parent->name); 02263 } 02264 } 02265 return; 02266 }
static int rqm_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Definition at line 3925 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().
03926 { 03927 int res=-1; 03928 struct ast_module_user *lu; 03929 char *parse, *temppos = NULL; 03930 int priority_jump = 0; 03931 AST_DECLARE_APP_ARGS(args, 03932 AST_APP_ARG(queuename); 03933 AST_APP_ARG(interface); 03934 AST_APP_ARG(options); 03935 ); 03936 03937 03938 if (ast_strlen_zero(data)) { 03939 ast_log(LOG_WARNING, "RemoveQueueMember requires an argument (queuename[|interface[|options]])\n"); 03940 return -1; 03941 } 03942 03943 parse = ast_strdupa(data); 03944 03945 AST_STANDARD_APP_ARGS(args, parse); 03946 03947 lu = ast_module_user_add(chan); 03948 03949 if (ast_strlen_zero(args.interface)) { 03950 args.interface = ast_strdupa(chan->name); 03951 temppos = strrchr(args.interface, '-'); 03952 if (temppos) 03953 *temppos = '\0'; 03954 } 03955 03956 if (args.options) { 03957 if (strchr(args.options, 'j')) 03958 priority_jump = 1; 03959 } 03960 03961 switch (remove_from_queue(args.queuename, args.interface)) { 03962 case RES_OKAY: 03963 ast_queue_log(args.queuename, chan->uniqueid, args.interface, "REMOVEMEMBER", "%s", ""); 03964 ast_log(LOG_NOTICE, "Removed interface '%s' from queue '%s'\n", args.interface, args.queuename); 03965 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "REMOVED"); 03966 res = 0; 03967 break; 03968 case RES_EXISTS: 03969 ast_log(LOG_DEBUG, "Unable to remove interface '%s' from queue '%s': Not there\n", args.interface, args.queuename); 03970 if (priority_jump || ast_opt_priority_jumping) 03971 ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101); 03972 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOTINQUEUE"); 03973 res = 0; 03974 break; 03975 case RES_NOSUCHQUEUE: 03976 ast_log(LOG_WARNING, "Unable to remove interface from queue '%s': No such queue\n", args.queuename); 03977 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOSUCHQUEUE"); 03978 res = 0; 03979 break; 03980 case RES_NOT_DYNAMIC: 03981 ast_log(LOG_WARNING, "Unable to remove interface from queue '%s': '%s' is not a dynamic member\n", args.queuename, args.interface); 03982 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOTDYNAMIC"); 03983 res = 0; 03984 break; 03985 } 03986 03987 ast_module_user_remove(lu); 03988 03989 return res; 03990 }
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 2186 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().
02187 { 02188 int res = 0; 02189 time_t now; 02190 02191 /* Get the current time */ 02192 time(&now); 02193 02194 /* Check to see if it is time to announce */ 02195 if ((now - qe->last_periodic_announce_time) < qe->parent->periodicannouncefrequency) 02196 return 0; 02197 02198 /* Stop the music on hold so we can play our own file */ 02199 ast_moh_stop(qe->chan); 02200 02201 if (option_verbose > 2) 02202 ast_verbose(VERBOSE_PREFIX_3 "Playing periodic announcement\n"); 02203 02204 /* Check to make sure we have a sound file. If not, reset to the first sound file */ 02205 if (qe->last_periodic_announce_sound >= MAX_PERIODIC_ANNOUNCEMENTS || !strlen(qe->parent->sound_periodicannounce[qe->last_periodic_announce_sound])) { 02206 qe->last_periodic_announce_sound = 0; 02207 } 02208 02209 /* play the announcement */ 02210 res = play_file(qe->chan, qe->parent->sound_periodicannounce[qe->last_periodic_announce_sound]); 02211 02212 if (res > 0 && !valid_exit(qe, res)) 02213 res = 0; 02214 02215 /* Resume Music on Hold if the caller is going to stay in the queue */ 02216 if (!res) 02217 ast_moh_start(qe->chan, qe->moh, NULL); 02218 02219 /* update last_periodic_announce_time */ 02220 qe->last_periodic_announce_time = now; 02221 02222 /* Update the current periodic announcement to the next announcement */ 02223 qe->last_periodic_announce_sound++; 02224 02225 return res; 02226 }
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 3666 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().
03667 { 03668 int found = 0; 03669 struct call_queue *q; 03670 struct member *mem; 03671 03672 /* Special event for when all queues are paused - individual events still generated */ 03673 /* XXX In all other cases, we use the membername, but since this affects all queues, we cannot */ 03674 if (ast_strlen_zero(queuename)) 03675 ast_queue_log("NONE", "NONE", interface, (paused ? "PAUSEALL" : "UNPAUSEALL"), "%s", ""); 03676 03677 AST_LIST_LOCK(&queues); 03678 AST_LIST_TRAVERSE(&queues, q, list) { 03679 ao2_lock(q); 03680 if (ast_strlen_zero(queuename) || !strcasecmp(q->name, queuename)) { 03681 if ((mem = interface_exists(q, interface))) { 03682 found++; 03683 if (mem->paused == paused) 03684 ast_log(LOG_DEBUG, "%spausing already-%spaused queue member %s:%s\n", (paused ? "" : "un"), (paused ? "" : "un"), q->name, interface); 03685 mem->paused = paused; 03686 03687 if (queue_persistent_members) 03688 dump_queue_members(q); 03689 03690 if (mem->realtime) 03691 update_realtime_member_field(mem, q->name, "paused", paused ? "1" : "0"); 03692 03693 ast_queue_log(q->name, "NONE", mem->membername, (paused ? "PAUSE" : "UNPAUSE"), "%s", ""); 03694 03695 manager_event(EVENT_FLAG_AGENT, "QueueMemberPaused", 03696 "Queue: %s\r\n" 03697 "Location: %s\r\n" 03698 "MemberName: %s\r\n" 03699 "Paused: %d\r\n", 03700 q->name, mem->interface, mem->membername, paused); 03701 ao2_ref(mem, -1); 03702 } 03703 } 03704 ao2_unlock(q); 03705 } 03706 AST_LIST_UNLOCK(&queues); 03707 03708 return found ? RESULT_SUCCESS : RESULT_FAILURE; 03709 }
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 2826 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.
02827 { 02828 struct ast_datastore *ds; 02829 struct queue_transfer_ds *qtds = ast_calloc(1, sizeof(*qtds)); 02830 02831 if (!qtds) { 02832 ast_log(LOG_WARNING, "Memory allocation error!\n"); 02833 return NULL; 02834 } 02835 02836 ast_channel_lock(qe->chan); 02837 if (!(ds = ast_channel_datastore_alloc(&queue_transfer_info, NULL))) { 02838 ast_channel_unlock(qe->chan); 02839 ast_log(LOG_WARNING, "Unable to create transfer datastore. queue_log will not show attended transfer\n"); 02840 return NULL; 02841 } 02842 02843 qtds->qe = qe; 02844 /* This member is refcounted in try_calling, so no need to add it here, too */ 02845 qtds->member = member; 02846 qtds->starttime = starttime; 02847 qtds->callcompletedinsl = callcompletedinsl; 02848 ds->data = qtds; 02849 ast_channel_datastore_add(qe->chan, ds); 02850 ast_channel_unlock(qe->chan); 02851 return ds; 02852 }
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 2162 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().
02163 { 02164 struct callattempt *best = find_best(outgoing); 02165 02166 if (best) { 02167 /* Ring just the best channel */ 02168 if (option_debug) 02169 ast_log(LOG_DEBUG, "Next is '%s' with metric %d\n", best->interface, best->metric); 02170 qe->parent->rrpos = best->metric % 1000; 02171 } else { 02172 /* Just increment rrpos */ 02173 if (qe->parent->wrapped) { 02174 /* No more channels, start over */ 02175 qe->parent->rrpos = 0; 02176 } else { 02177 /* Prioritize next entry */ 02178 qe->parent->rrpos++; 02179 } 02180 } 02181 qe->parent->wrapped = 0; 02182 02183 return 0; 02184 }
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 2879 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().
02880 { 02881 struct member *cur; 02882 struct callattempt *outgoing = NULL; /* the list of calls we are building */ 02883 int to; 02884 char oldexten[AST_MAX_EXTENSION]=""; 02885 char oldcontext[AST_MAX_CONTEXT]=""; 02886 char queuename[256]=""; 02887 struct ast_channel *peer; 02888 struct ast_channel *which; 02889 struct callattempt *lpeer; 02890 struct member *member; 02891 struct ast_app *app; 02892 int res = 0, bridge = 0; 02893 int numbusies = 0; 02894 int x=0; 02895 char *announce = NULL; 02896 char digit = 0; 02897 time_t callstart; 02898 time_t now = time(NULL); 02899 struct ast_bridge_config bridge_config; 02900 char nondataquality = 1; 02901 char *agiexec = NULL; 02902 int ret = 0; 02903 const char *monitorfilename; 02904 const char *monitor_exec; 02905 const char *monitor_options; 02906 char tmpid[256], tmpid2[256]; 02907 char meid[1024], meid2[1024]; 02908 char mixmonargs[1512]; 02909 struct ast_app *mixmonapp = NULL; 02910 char *p; 02911 char vars[2048]; 02912 int forwardsallowed = 1; 02913 int callcompletedinsl; 02914 struct ao2_iterator memi; 02915 struct ast_datastore *datastore, *transfer_ds; 02916 const int need_weight = use_weight; 02917 02918 ast_channel_lock(qe->chan); 02919 datastore = ast_channel_datastore_find(qe->chan, &dialed_interface_info, NULL); 02920 ast_channel_unlock(qe->chan); 02921 02922 memset(&bridge_config, 0, sizeof(bridge_config)); 02923 time(&now); 02924 02925 /* If we've already exceeded our timeout, then just stop 02926 * This should be extremely rare. queue_exec will take care 02927 * of removing the caller and reporting the timeout as the reason. 02928 */ 02929 if (qe->expire && now >= qe->expire) { 02930 res = 0; 02931 goto out; 02932 } 02933 02934 for (; options && *options; options++) 02935 switch (*options) { 02936 case 't': 02937 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_REDIRECT); 02938 break; 02939 case 'T': 02940 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_REDIRECT); 02941 break; 02942 case 'w': 02943 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_AUTOMON); 02944 break; 02945 case 'W': 02946 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_AUTOMON); 02947 break; 02948 case 'd': 02949 nondataquality = 0; 02950 break; 02951 case 'h': 02952 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_DISCONNECT); 02953 break; 02954 case 'H': 02955 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT); 02956 break; 02957 case 'n': 02958 if (qe->parent->strategy == QUEUE_STRATEGY_ROUNDROBIN || qe->parent->strategy == QUEUE_STRATEGY_RRMEMORY || qe->parent->strategy == QUEUE_STRATEGY_RRORDERED) 02959 (*tries)++; 02960 else 02961 *tries = qe->parent->membercount; 02962 *noption = 1; 02963 break; 02964 case 'i': 02965 forwardsallowed = 0; 02966 break; 02967 } 02968 02969 /* Hold the lock while we setup the outgoing calls */ 02970 02971 if (need_weight) 02972 AST_LIST_LOCK(&queues); 02973 ao2_lock(qe->parent); 02974 if (option_debug) 02975 ast_log(LOG_DEBUG, "%s is trying to call a queue member.\n", 02976 qe->chan->name); 02977 ast_copy_string(queuename, qe->parent->name, sizeof(queuename)); 02978 if (!ast_strlen_zero(qe->announce)) 02979 announce = qe->announce; 02980 if (!ast_strlen_zero(announceoverride)) 02981 announce = announceoverride; 02982 02983 memi = ao2_iterator_init(qe->parent->members, 0); 02984 while ((cur = ao2_iterator_next(&memi))) { 02985 struct callattempt *tmp = ast_calloc(1, sizeof(*tmp)); 02986 struct ast_dialed_interface *di; 02987 AST_LIST_HEAD(, ast_dialed_interface) *dialed_interfaces; 02988 if (!tmp) { 02989 ao2_iterator_destroy(&memi); 02990 ao2_ref(cur, -1); 02991 ao2_unlock(qe->parent); 02992 if (need_weight) 02993 AST_LIST_UNLOCK(&queues); 02994 goto out; 02995 } 02996 if (!datastore) { 02997 if (!(datastore = ast_channel_datastore_alloc(&dialed_interface_info, NULL))) { 02998 ao2_iterator_destroy(&memi); 02999 ao2_ref(cur, -1); 03000 ao2_unlock(qe->parent); 03001 if (need_weight) 03002 AST_LIST_UNLOCK(&queues); 03003 free(tmp); 03004 goto out; 03005 } 03006 datastore->inheritance = DATASTORE_INHERIT_FOREVER; 03007 if (!(dialed_interfaces = ast_calloc(1, sizeof(*dialed_interfaces)))) { 03008 ao2_iterator_destroy(&memi); 03009 ao2_ref(cur, -1); 03010 ao2_unlock(qe->parent); 03011 if (need_weight) 03012 AST_LIST_UNLOCK(&queues); 03013 free(tmp); 03014 goto out; 03015 } 03016 datastore->data = dialed_interfaces; 03017 AST_LIST_HEAD_INIT(dialed_interfaces); 03018 03019 ast_channel_lock(qe->chan); 03020 ast_channel_datastore_add(qe->chan, datastore); 03021 ast_channel_unlock(qe->chan); 03022 } else 03023 dialed_interfaces = datastore->data; 03024 03025 AST_LIST_LOCK(dialed_interfaces); 03026 AST_LIST_TRAVERSE(dialed_interfaces, di, list) { 03027 if (!strcasecmp(cur->interface, di->interface)) { 03028 ast_log(LOG_DEBUG, "Skipping dialing interface '%s' since it has already been dialed\n", 03029 di->interface); 03030 break; 03031 } 03032 } 03033 AST_LIST_UNLOCK(dialed_interfaces); 03034 03035 if (di) { 03036 free(tmp); 03037 continue; 03038 } 03039 03040 /* It is always ok to dial a Local interface. We only keep track of 03041 * which "real" interfaces have been dialed. The Local channel will 03042 * inherit this list so that if it ends up dialing a real interface, 03043 * it won't call one that has already been called. */ 03044 if (strncasecmp(cur->interface, "Local/", 6)) { 03045 if (!(di = ast_calloc(1, sizeof(*di) + strlen(cur->interface)))) { 03046 ao2_iterator_destroy(&memi); 03047 ao2_ref(cur, -1); 03048 ao2_unlock(qe->parent); 03049 if (need_weight) 03050 AST_LIST_UNLOCK(&queues); 03051 free(tmp); 03052 goto out; 03053 } 03054 strcpy(di->interface, cur->interface); 03055 03056 AST_LIST_LOCK(dialed_interfaces); 03057 AST_LIST_INSERT_TAIL(dialed_interfaces, di, list); 03058 AST_LIST_UNLOCK(dialed_interfaces); 03059 } 03060 03061 tmp->stillgoing = -1; 03062 tmp->member = cur; 03063 tmp->oldstatus = cur->status; 03064 tmp->lastcall = cur->lastcall; 03065 ast_copy_string(tmp->interface, cur->interface, sizeof(tmp->interface)); 03066 if (qe->tries == 0 && (cur->ringcount >= qe->parent->ringlimit)) { 03067 cur->ringcount = 0; 03068 } 03069 /* Special case: If we ring everyone, go ahead and ring them, otherwise 03070 just calculate their metric for the appropriate strategy */ 03071 if (!calc_metric(qe->parent, cur, x++, qe, tmp)) { 03072 /* Put them in the list of outgoing thingies... We're ready now. 03073 XXX If we're forcibly removed, these outgoing calls won't get 03074 hung up XXX */ 03075 tmp->q_next = outgoing; 03076 outgoing = tmp; 03077 /* If this line is up, don't try anybody else */ 03078 if (outgoing->chan && (outgoing->chan->_state == AST_STATE_UP)) 03079 break; 03080 } else { 03081 ao2_ref(cur, -1); 03082 free(tmp); 03083 } 03084 } 03085 ao2_iterator_destroy(&memi); 03086 if (qe->expire && (!qe->parent->timeout || (qe->expire - now) <= qe->parent->timeout)) 03087 to = (qe->expire - now) * 1000; 03088 else 03089 to = (qe->parent->timeout) ? qe->parent->timeout * 1000 : -1; 03090 ++qe->pending; 03091 ++qe->tries; 03092 if (option_debug) 03093 ast_log(LOG_DEBUG, "%s is trying to ring one member from %s. This is try number %d\n", 03094 qe->chan->name, queuename, qe->tries); 03095 ao2_unlock(qe->parent); 03096 ring_one(qe, outgoing, &numbusies); 03097 if (need_weight) 03098 AST_LIST_UNLOCK(&queues); 03099 lpeer = wait_for_answer(qe, outgoing, &to, &digit, numbusies, ast_test_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT), forwardsallowed); 03100 /* The ast_channel_datastore_remove() function could fail here if the 03101 * datastore was moved to another channel during a masquerade. If this is 03102 * the case, don't free the datastore here because later, when the channel 03103 * to which the datastore was moved hangs up, it will attempt to free this 03104 * datastore again, causing a crash 03105 */ 03106 ast_channel_lock(qe->chan); 03107 if (datastore && !ast_channel_datastore_remove(qe->chan, datastore)) { 03108 ast_channel_datastore_free(datastore); 03109 } 03110 ast_channel_unlock(qe->chan); 03111 ao2_lock(qe->parent); 03112 if (qe->parent->strategy == QUEUE_STRATEGY_RRMEMORY || qe->parent->strategy == QUEUE_STRATEGY_RRORDERED) { 03113 store_next(qe, outgoing); 03114 } 03115 ao2_unlock(qe->parent); 03116 peer = lpeer ? lpeer->chan : NULL; 03117 if (!peer) { 03118 qe->pending = 0; 03119 if (to) { 03120 /* Must gotten hung up */ 03121 res = -1; 03122 } else { 03123 /* User exited by pressing a digit */ 03124 res = digit; 03125 } 03126 if (res == -1) { 03127 /* Post this CDR, and mark call as NOANSWER */ 03128 ast_set_flag(qe->chan->cdr, AST_CDR_FLAG_DONT_TOUCH); 03129 ast_cdr_noanswer(qe->chan->cdr); 03130 if (queue_debug) 03131 ast_log(LOG_NOTICE, "%s: Nobody answered.\n", qe->chan->name); 03132 } 03133 if (qe->parent->eventwhencalled) { 03134 manager_event(EVENT_FLAG_AGENT, "AgentTimeout", 03135 "Queue: %s\r\n" 03136 "ChannelCalling: %s\r\n" 03137 "Uniqueid: %s\r\n" 03138 "Tries: %d\r\n" 03139 "Holdtime: %ld\r\n", 03140 queuename, qe->chan->name, qe->chan->uniqueid, qe->tries, 03141 (long)time(NULL) - qe->start); 03142 } 03143 if (ast_cdr_isset_unanswered()) { 03144 /* channel contains the name of one of the outgoing channels 03145 in its CDR; zero out this CDR to avoid a dual-posting */ 03146 struct callattempt *o; 03147 for (o = outgoing; o; o = o->q_next) { 03148 if (!o->chan) { 03149 continue; 03150 } 03151 if (strcmp(o->chan->cdr->dstchannel, qe->chan->cdr->dstchannel) == 0) { 03152 ast_set_flag(o->chan->cdr, AST_CDR_FLAG_POST_DISABLED); 03153 break; 03154 } 03155 } 03156 } 03157 } else { /* peer is valid */ 03158 /* Ah ha! Someone answered within the desired timeframe. Of course after this 03159 we will always return with -1 so that it is hung up properly after the 03160 conversation. */ 03161 if (!strcmp(qe->chan->tech->type, "Zap")) 03162 ast_channel_setoption(qe->chan, AST_OPTION_TONE_VERIFY, &nondataquality, sizeof(nondataquality), 0); 03163 if (!strcmp(peer->tech->type, "Zap")) 03164 ast_channel_setoption(peer, AST_OPTION_TONE_VERIFY, &nondataquality, sizeof(nondataquality), 0); 03165 /* Update parameters for the queue */ 03166 time(&now); 03167 recalc_holdtime(qe, (now - qe->start)); 03168 ao2_lock(qe->parent); 03169 callcompletedinsl = ((now - qe->start) <= qe->parent->servicelevel); 03170 ao2_unlock(qe->parent); 03171 member = lpeer->member; 03172 /* Increment the refcount for this member, since we're going to be using it for awhile in here. */ 03173 ao2_ref(member, 1); 03174 hangupcalls(outgoing, peer); 03175 outgoing = NULL; 03176 if (announce || qe->parent->reportholdtime || qe->parent->memberdelay) { 03177 int res2; 03178 03179 res2 = ast_autoservice_start(qe->chan); 03180 if (!res2) { 03181 if (qe->parent->memberdelay) { 03182 ast_log(LOG_NOTICE, "Delaying member connect for %d seconds\n", qe->parent->memberdelay); 03183 res2 |= ast_safe_sleep(peer, qe->parent->memberdelay * 1000); 03184 } 03185 if (!res2 && announce) { 03186 play_file(peer, announce); 03187 } 03188 if (!res2 && qe->parent->reportholdtime) { 03189 if (!play_file(peer, qe->parent->sound_reporthold)) { 03190 int holdtime; 03191 03192 time(&now); 03193 holdtime = abs((now - qe->start) / 60); 03194 if (holdtime < 2) { 03195 play_file(peer, qe->parent->sound_lessthan); 03196 ast_say_number(peer, 2, AST_DIGIT_ANY, peer->language, NULL); 03197 } else 03198 ast_say_number(peer, holdtime, AST_DIGIT_ANY, peer->language, NULL); 03199 play_file(peer, qe->parent->sound_minutes); 03200 } 03201 } 03202 } 03203 res2 |= ast_autoservice_stop(qe->chan); 03204 if (peer->_softhangup) { 03205 /* Agent must have hung up */ 03206 ast_log(LOG_WARNING, "Agent on %s hungup on the customer.\n", peer->name); 03207 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "AGENTDUMP", "%s", ""); 03208 if (qe->parent->eventwhencalled) 03209 manager_event(EVENT_FLAG_AGENT, "AgentDump", 03210 "Queue: %s\r\n" 03211 "Uniqueid: %s\r\n" 03212 "Channel: %s\r\n" 03213 "Member: %s\r\n" 03214 "MemberName: %s\r\n" 03215 "%s", 03216 queuename, qe->chan->uniqueid, peer->name, member->interface, member->membername, 03217 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : ""); 03218 ast_hangup(peer); 03219 ao2_ref(member, -1); 03220 goto out; 03221 } else if (res2) { 03222 /* Caller must have hung up just before being connected*/ 03223 ast_log(LOG_NOTICE, "Caller was about to talk to agent on %s but the caller hungup.\n", peer->name); 03224 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "ABANDON", "%d|%d|%ld", qe->pos, qe->opos, (long)time(NULL) - qe->start); 03225 record_abandoned(qe); 03226 ast_hangup(peer); 03227 ao2_ref(member, -1); 03228 return -1; 03229 } 03230 } 03231 /* Stop music on hold */ 03232 ast_moh_stop(qe->chan); 03233 /* If appropriate, log that we have a destination channel */ 03234 if (qe->chan->cdr) 03235 ast_cdr_setdestchan(qe->chan->cdr, peer->name); 03236 /* Make sure channels are compatible */ 03237 res = ast_channel_make_compatible(qe->chan, peer); 03238 if (res < 0) { 03239 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "SYSCOMPAT", "%s", ""); 03240 ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", qe->chan->name, peer->name); 03241 record_abandoned(qe); 03242 ast_cdr_failed(qe->chan->cdr); 03243 ast_hangup(peer); 03244 ao2_ref(member, -1); 03245 return -1; 03246 } 03247 03248 if (qe->parent->setinterfacevar) 03249 pbx_builtin_setvar_helper(qe->chan, "MEMBERINTERFACE", member->interface); 03250 03251 /* Begin Monitoring */ 03252 if (qe->parent->monfmt && *qe->parent->monfmt) { 03253 if (!qe->parent->montype) { 03254 if (option_debug) 03255 ast_log(LOG_DEBUG, "Starting Monitor as requested.\n"); 03256 monitorfilename = pbx_builtin_getvar_helper(qe->chan, "MONITOR_FILENAME"); 03257 if (pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC") || pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC_ARGS")) 03258 which = qe->chan; 03259 else 03260 which = peer; 03261 if (monitorfilename) 03262 ast_monitor_start(which, qe->parent->monfmt, monitorfilename, 1 ); 03263 else if (qe->chan->cdr) 03264 ast_monitor_start(which, qe->parent->monfmt, qe->chan->cdr->uniqueid, 1 ); 03265 else { 03266 /* Last ditch effort -- no CDR, make up something */ 03267 snprintf(tmpid, sizeof(tmpid), "chan-%lx", ast_random()); 03268 ast_monitor_start(which, qe->parent->monfmt, tmpid, 1 ); 03269 } 03270 if (qe->parent->monjoin) 03271 ast_monitor_setjoinfiles(which, 1); 03272 } else { 03273 if (option_debug) 03274 ast_log(LOG_DEBUG, "Starting MixMonitor as requested.\n"); 03275 monitorfilename = pbx_builtin_getvar_helper(qe->chan, "MONITOR_FILENAME"); 03276 if (!monitorfilename) { 03277 if (qe->chan->cdr) 03278 ast_copy_string(tmpid, qe->chan->cdr->uniqueid, sizeof(tmpid)-1); 03279 else 03280 snprintf(tmpid, sizeof(tmpid), "chan-%lx", ast_random()); 03281 } else { 03282 ast_copy_string(tmpid2, monitorfilename, sizeof(tmpid2)-1); 03283 for (p = tmpid2; *p ; p++) { 03284 if (*p == '^' && *(p+1) == '{') { 03285 *p = '$'; 03286 } 03287 } 03288 03289 memset(tmpid, 0, sizeof(tmpid)); 03290 pbx_substitute_variables_helper(qe->chan, tmpid2, tmpid, sizeof(tmpid) - 1); 03291 } 03292 03293 monitor_exec = pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC"); 03294 monitor_options = pbx_builtin_getvar_helper(qe->chan, "MONITOR_OPTIONS"); 03295 03296 if (monitor_exec) { 03297 ast_copy_string(meid2, monitor_exec, sizeof(meid2)-1); 03298 for (p = meid2; *p ; p++) { 03299 if (*p == '^' && *(p+1) == '{') { 03300 *p = '$'; 03301 } 03302 } 03303 03304 memset(meid, 0, sizeof(meid)); 03305 pbx_substitute_variables_helper(qe->chan, meid2, meid, sizeof(meid) - 1); 03306 } 03307 03308 snprintf(tmpid2, sizeof(tmpid2)-1, "%s.%s", tmpid, qe->parent->monfmt); 03309 03310 mixmonapp = pbx_findapp("MixMonitor"); 03311 03312 if (strchr(tmpid2, '|')) { 03313 ast_log(LOG_WARNING, "monitor-format (in queues.conf) and MONITOR_FILENAME cannot contain a '|'! Not recording.\n"); 03314 mixmonapp = NULL; 03315 } 03316 03317 if (!monitor_options) 03318 monitor_options = ""; 03319 03320 if (strchr(monitor_options, '|')) { 03321 ast_log(LOG_WARNING, "MONITOR_OPTIONS cannot contain a '|'! Not recording.\n"); 03322 mixmonapp = NULL; 03323 } 03324 03325 if (mixmonapp) { 03326 if (!ast_strlen_zero(monitor_exec)) 03327 snprintf(mixmonargs, sizeof(mixmonargs)-1, "%s|b%s|%s", tmpid2, monitor_options, monitor_exec); 03328 else 03329 snprintf(mixmonargs, sizeof(mixmonargs)-1, "%s|b%s", tmpid2, monitor_options); 03330 03331 if (option_debug) 03332 ast_log(LOG_DEBUG, "Arguments being passed to MixMonitor: %s\n", mixmonargs); 03333 /* We purposely lock the CDR so that pbx_exec does not update the application data */ 03334 if (qe->chan->cdr) 03335 ast_set_flag(qe->chan->cdr, AST_CDR_FLAG_LOCKED); 03336 ret = pbx_exec(qe->chan, mixmonapp, mixmonargs); 03337 if (qe->chan->cdr) 03338 ast_clear_flag(qe->chan->cdr, AST_CDR_FLAG_LOCKED); 03339 03340 } else 03341 ast_log(LOG_WARNING, "Asked to run MixMonitor on this call, but cannot find the MixMonitor app!\n"); 03342 03343 } 03344 } 03345 /* Drop out of the queue at this point, to prepare for next caller */ 03346 leave_queue(qe); 03347 if (!ast_strlen_zero(url) && ast_channel_supports_html(peer)) { 03348 if (option_debug) 03349 ast_log(LOG_DEBUG, "app_queue: sendurl=%s.\n", url); 03350 ast_channel_sendurl(peer, url); 03351 } 03352 if (!ast_strlen_zero(agi)) { 03353 if (option_debug) 03354 ast_log(LOG_DEBUG, "app_queue: agi=%s.\n", agi); 03355 app = pbx_findapp("agi"); 03356 if (app) { 03357 agiexec = ast_strdupa(agi); 03358 ret = pbx_exec(qe->chan, app, agiexec); 03359 } else 03360 ast_log(LOG_WARNING, "Asked to execute an AGI on this channel, but could not find application (agi)!\n"); 03361 } 03362 qe->handled++; 03363 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "CONNECT", "%ld|%s", (long)time(NULL) - qe->start, peer->uniqueid); 03364 if (qe->parent->eventwhencalled) 03365 manager_event(EVENT_FLAG_AGENT, "AgentConnect", 03366 "Queue: %s\r\n" 03367 "Uniqueid: %s\r\n" 03368 "Channel: %s\r\n" 03369 "Member: %s\r\n" 03370 "MemberName: %s\r\n" 03371 "Holdtime: %ld\r\n" 03372 "BridgedChannel: %s\r\n" 03373 "%s", 03374 queuename, qe->chan->uniqueid, peer->name, member->interface, member->membername, 03375 (long)time(NULL) - qe->start, peer->uniqueid, 03376 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : ""); 03377 ast_copy_string(oldcontext, qe->chan->context, sizeof(oldcontext)); 03378 ast_copy_string(oldexten, qe->chan->exten, sizeof(oldexten)); 03379 time(&callstart); 03380 03381 if (member->status == AST_DEVICE_NOT_INUSE) 03382 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); 03383 03384 transfer_ds = setup_transfer_datastore(qe, member, callstart, callcompletedinsl); 03385 bridge = ast_bridge_call(qe->chan,peer, &bridge_config); 03386 03387 ast_channel_lock(qe->chan); 03388 if (!attended_transfer_occurred(qe->chan)) { 03389 struct ast_datastore *tds; 03390 03391 /* detect a blind transfer */ 03392 if (!(qe->chan->_softhangup | peer->_softhangup) && (strcasecmp(oldcontext, qe->chan->context) || strcasecmp(oldexten, qe->chan->exten))) { 03393 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "TRANSFER", "%s|%s|%ld|%ld", 03394 qe->chan->exten, qe->chan->context, (long) (callstart - qe->start), 03395 (long) (time(NULL) - callstart)); 03396 if (qe->parent->eventwhencalled) 03397 manager_event(EVENT_FLAG_AGENT, "AgentComplete", 03398 "Queue: %s\r\n" 03399 "Uniqueid: %s\r\n" 03400 "Channel: %s\r\n" 03401 "Member: %s\r\n" 03402 "MemberName: %s\r\n" 03403 "HoldTime: %ld\r\n" 03404 "TalkTime: %ld\r\n" 03405 "Reason: transfer\r\n" 03406 "%s", 03407 queuename, qe->chan->uniqueid, peer->name, member->interface, member->membername, 03408 (long)(callstart - qe->start), (long)(time(NULL) - callstart), 03409 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : ""); 03410 } else if (qe->chan->_softhangup) { 03411 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "COMPLETECALLER", "%ld|%ld|%d", 03412 (long) (callstart - qe->start), (long) (time(NULL) - callstart), qe->opos); 03413 if (qe->parent->eventwhencalled) 03414 manager_event(EVENT_FLAG_AGENT, "AgentComplete", 03415 "Queue: %s\r\n" 03416 "Uniqueid: %s\r\n" 03417 "Channel: %s\r\n" 03418 "Member: %s\r\n" 03419 "MemberName: %s\r\n" 03420 "HoldTime: %ld\r\n" 03421 "TalkTime: %ld\r\n" 03422 "Reason: caller\r\n" 03423 "%s", 03424 queuename, qe->chan->uniqueid, peer->name, member->interface, member->membername, 03425 (long)(callstart - qe->start), (long)(time(NULL) - callstart), 03426 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : ""); 03427 } else { 03428 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "COMPLETEAGENT", "%ld|%ld|%d", 03429 (long) (callstart - qe->start), (long) (time(NULL) - callstart), qe->opos); 03430 if (qe->parent->eventwhencalled) 03431 manager_event(EVENT_FLAG_AGENT, "AgentComplete", 03432 "Queue: %s\r\n" 03433 "Uniqueid: %s\r\n" 03434 "Channel: %s\r\n" 03435 "Member: %s\r\n" 03436 "MemberName: %s\r\n" 03437 "HoldTime: %ld\r\n" 03438 "TalkTime: %ld\r\n" 03439 "Reason: agent\r\n" 03440 "%s", 03441 queuename, qe->chan->uniqueid, peer->name, member->interface, member->membername, (long)(callstart - qe->start), 03442 (long)(time(NULL) - callstart), 03443 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : ""); 03444 } 03445 if ((tds = ast_channel_datastore_find(qe->chan, &queue_transfer_info, NULL))) { 03446 ast_channel_datastore_remove(qe->chan, tds); 03447 } 03448 update_queue(qe->parent, member, callcompletedinsl); 03449 } else { 03450 if (qe->parent->eventwhencalled) 03451 manager_event(EVENT_FLAG_AGENT, "AgentComplete", 03452 "Queue: %s\r\n" 03453 "Uniqueid: %s\r\n" 03454 "Channel: %s\r\n" 03455 "Member: %s\r\n" 03456 "MemberName: %s\r\n" 03457 "HoldTime: %ld\r\n" 03458 "TalkTime: %ld\r\n" 03459 "Reason: transfer\r\n" 03460 "%s", 03461 queuename, qe->chan->uniqueid, peer->name, member->interface, member->membername, (long)(callstart - qe->start), 03462 (long)(time(NULL) - callstart), 03463 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : ""); 03464 } 03465 03466 if (transfer_ds) { 03467 ast_channel_datastore_free(transfer_ds); 03468 } 03469 ast_channel_unlock(qe->chan); 03470 ast_hangup(peer); 03471 res = bridge ? bridge : 1; 03472 ao2_ref(member, -1); 03473 } 03474 out: 03475 hangupcalls(outgoing, NULL); 03476 03477 return res; 03478 }
static int unload_module | ( | void | ) | [static] |
Definition at line 5588 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().
05589 { 05590 int res; 05591 05592 if (device_state.thread != AST_PTHREADT_NULL) { 05593 device_state.stop = 1; 05594 ast_mutex_lock(&device_state.lock); 05595 ast_cond_signal(&device_state.cond); 05596 ast_mutex_unlock(&device_state.lock); 05597 pthread_join(device_state.thread, NULL); 05598 } 05599 05600 ast_cli_unregister_multiple(cli_queue, sizeof(cli_queue) / sizeof(struct ast_cli_entry)); 05601 res = ast_manager_unregister("QueueStatus"); 05602 res |= ast_manager_unregister("Queues"); 05603 res |= ast_manager_unregister("QueueAdd"); 05604 res |= ast_manager_unregister("QueueRemove"); 05605 res |= ast_manager_unregister("QueuePause"); 05606 res |= ast_unregister_application(app_aqm); 05607 res |= ast_unregister_application(app_rqm); 05608 res |= ast_unregister_application(app_pqm); 05609 res |= ast_unregister_application(app_upqm); 05610 res |= ast_unregister_application(app_ql); 05611 res |= ast_unregister_application(app); 05612 res |= ast_custom_function_unregister(&queueagentcount_function); 05613 res |= ast_custom_function_unregister(&queuemembercount_function); 05614 res |= ast_custom_function_unregister(&queuememberlist_function); 05615 res |= ast_custom_function_unregister(&queuewaitingcount_function); 05616 ast_devstate_del(statechange_queue, NULL); 05617 05618 ast_module_user_hangup_all(); 05619 05620 clear_and_free_interfaces(); 05621 05622 return res; 05623 }
static int update_queue | ( | struct call_queue * | q, | |
struct member * | member, | |||
int | callcompletedinsl | |||
) | [static] |
Definition at line 2678 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().
02679 { 02680 ao2_lock(q); 02681 time(&member->lastcall); 02682 member->calls++; 02683 q->callscompleted++; 02684 if (callcompletedinsl) 02685 q->callscompletedinsl++; 02686 ao2_unlock(q); 02687 return 0; 02688 }
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 3867 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().
03868 { 03869 struct ast_module_user *lu; 03870 char *parse; 03871 int priority_jump = 0; 03872 int ignore_fail = 0; 03873 AST_DECLARE_APP_ARGS(args, 03874 AST_APP_ARG(queuename); 03875 AST_APP_ARG(interface); 03876 AST_APP_ARG(options); 03877 ); 03878 03879 if (ast_strlen_zero(data)) { 03880 ast_log(LOG_WARNING, "UnpauseQueueMember requires an argument ([queuename]|interface[|options])\n"); 03881 return -1; 03882 } 03883 03884 parse = ast_strdupa(data); 03885 03886 AST_STANDARD_APP_ARGS(args, parse); 03887 03888 lu = ast_module_user_add(chan); 03889 03890 if (args.options) { 03891 if (strchr(args.options, 'j')) 03892 priority_jump = 1; 03893 if (strchr(args.options, 'i')) 03894 ignore_fail = 1; 03895 } 03896 03897 if (ast_strlen_zero(args.interface)) { 03898 ast_log(LOG_WARNING, "Missing interface argument to PauseQueueMember ([queuename]|interface[|options])\n"); 03899 ast_module_user_remove(lu); 03900 return -1; 03901 } 03902 03903 if (set_member_paused(args.queuename, args.interface, 0)) { 03904 ast_log(LOG_WARNING, "Attempt to unpause interface %s, not found\n", args.interface); 03905 pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "NOTFOUND"); 03906 if (priority_jump || ast_opt_priority_jumping) { 03907 if (!ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101)) { 03908 ast_module_user_remove(lu); 03909 return 0; 03910 } 03911 } 03912 ast_module_user_remove(lu); 03913 if (ignore_fail) { 03914 return 0; 03915 } else { 03916 return -1; 03917 } 03918 } 03919 03920 ast_module_user_remove(lu); 03921 pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "UNPAUSED"); 03922 return 0; 03923 }
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 1907 of file app_queue.c.
References ast_copy_string(), and pbx_builtin_serialize_variables().
Referenced by ring_entry().
01908 { 01909 char *tmp = alloca(len); 01910 01911 if (pbx_builtin_serialize_variables(chan, tmp, len)) { 01912 int i, j; 01913 01914 /* convert "\n" to "\nVariable: " */ 01915 strcpy(vars, "Variable: "); 01916 01917 for (i = 0, j = 10; (i < len - 1) && (j < len - 1); i++, j++) { 01918 vars[j] = tmp[i]; 01919 01920 if (tmp[i + 1] == '\0') 01921 break; 01922 if (tmp[i] == '\n') { 01923 vars[j++] = '\r'; 01924 vars[j++] = '\n'; 01925 01926 ast_copy_string(&(vars[j]), "Variable: ", len - j); 01927 j += 9; 01928 } 01929 } 01930 if (j > len - 3) 01931 j = len - 3; 01932 vars[j++] = '\r'; 01933 vars[j++] = '\n'; 01934 vars[j] = '\0'; 01935 } else { 01936 /* there are no channel variables; leave it blank */ 01937 *vars = '\0'; 01938 } 01939 return vars; 01940 }
static int wait_a_bit | ( | struct queue_ent * | qe | ) | [static] |
Definition at line 3480 of file app_queue.c.
References ast_waitfordigit(), queue_ent::chan, queue_ent::parent, call_queue::retry, and valid_exit().
Referenced by queue_exec().
03481 { 03482 /* Don't need to hold the lock while we setup the outgoing calls */ 03483 int retrywait = qe->parent->retry * 1000; 03484 03485 int res = ast_waitfordigit(qe->chan, retrywait); 03486 if (res > 0 && !valid_exit(qe, res)) 03487 res = 0; 03488 03489 return res; 03490 }
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 2279 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.
02280 { 02281 char *queue = qe->parent->name; 02282 struct callattempt *o, *start = NULL, *prev = NULL; 02283 int status; 02284 int numbusies = prebusies; 02285 int numnochan = 0; 02286 int stillgoing = 0; 02287 int orig = *to; 02288 struct ast_frame *f; 02289 struct callattempt *peer = NULL; 02290 struct ast_channel *winner; 02291 struct ast_channel *in = qe->chan; 02292 char on[80] = ""; 02293 char membername[80] = ""; 02294 long starttime = 0; 02295 long endtime = 0; 02296 02297 starttime = (long) time(NULL); 02298 02299 while (*to && !peer) { 02300 int numlines, retry, pos = 1; 02301 struct ast_channel *watchers[AST_MAX_WATCHERS]; 02302 watchers[0] = in; 02303 start = NULL; 02304 02305 for (retry = 0; retry < 2; retry++) { 02306 numlines = 0; 02307 for (o = outgoing; o; o = o->q_next) { /* Keep track of important channels */ 02308 if (o->stillgoing) { /* Keep track of important channels */ 02309 stillgoing = 1; 02310 if (o->chan) { 02311 watchers[pos++] = o->chan; 02312 if (!start) 02313 start = o; 02314 else 02315 prev->call_next = o; 02316 prev = o; 02317 } 02318 } 02319 numlines++; 02320 } 02321 if (pos > 1 /* found */ || !stillgoing /* nobody listening */ || 02322 (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) /* ring would not be delivered */) 02323 break; 02324 /* On "ringall" strategy we only move to the next penalty level 02325 when *all* ringing phones are done in the current penalty level */ 02326 ring_one(qe, outgoing, &numbusies); 02327 /* and retry... */ 02328 } 02329 if (pos == 1 /* not found */) { 02330 if (numlines == (numbusies + numnochan)) { 02331 ast_log(LOG_DEBUG, "Everyone is busy at this time\n"); 02332 } else { 02333 ast_log(LOG_NOTICE, "No one is answering queue '%s' (%d/%d/%d)\n", queue, numlines, numbusies, numnochan); 02334 } 02335 *to = 0; 02336 return NULL; 02337 } 02338 02339 /* Poll for events from both the incoming channel as well as any outgoing channels */ 02340 winner = ast_waitfor_n(watchers, pos, to); 02341 02342 /* Service all of the outgoing channels */ 02343 for (o = start; o; o = o->call_next) { 02344 if (o->stillgoing && (o->chan) && (o->chan->_state == AST_STATE_UP)) { 02345 if (!peer) { 02346 if (option_verbose > 2) 02347 ast_verbose( VERBOSE_PREFIX_3 "%s answered %s\n", o->chan->name, in->name); 02348 peer = o; 02349 } 02350 } else if (o->chan && (o->chan == winner)) { 02351 02352 ast_copy_string(on, o->member->interface, sizeof(on)); 02353 ast_copy_string(membername, o->member->membername, sizeof(membername)); 02354 02355 if (!ast_strlen_zero(o->chan->call_forward) && !forwardsallowed) { 02356 if (option_verbose > 2) 02357 ast_verbose(VERBOSE_PREFIX_3 "Forwarding %s to '%s' prevented.\n", in->name, o->chan->call_forward); 02358 numnochan++; 02359 do_hang(o); 02360 winner = NULL; 02361 continue; 02362 } else if (!ast_strlen_zero(o->chan->call_forward)) { 02363 char tmpchan[256]; 02364 char *stuff; 02365 char *tech; 02366 02367 ast_copy_string(tmpchan, o->chan->call_forward, sizeof(tmpchan)); 02368 if ((stuff = strchr(tmpchan, '/'))) { 02369 *stuff++ = '\0'; 02370 tech = tmpchan; 02371 } else { 02372 snprintf(tmpchan, sizeof(tmpchan), "%s@%s", o->chan->call_forward, o->chan->context); 02373 stuff = tmpchan; 02374 tech = "Local"; 02375 } 02376 /* Before processing channel, go ahead and check for forwarding */ 02377 if (option_verbose > 2) 02378 ast_verbose(VERBOSE_PREFIX_3 "Now forwarding %s to '%s/%s' (thanks to %s)\n", in->name, tech, stuff, o->chan->name); 02379 /* Setup parameters */ 02380 o->chan = ast_request(tech, in->nativeformats, stuff, &status); 02381 if (!o->chan) { 02382 ast_log(LOG_NOTICE, 02383 "Forwarding failed to create channel to dial '%s/%s'\n", 02384 tech, stuff); 02385 o->stillgoing = 0; 02386 numnochan++; 02387 } else { 02388 ast_channel_inherit_variables(in, o->chan); 02389 ast_channel_datastore_inherit(in, o->chan); 02390 if (o->chan->cid.cid_num) 02391 free(o->chan->cid.cid_num); 02392 o->chan->cid.cid_num = ast_strdup(in->cid.cid_num); 02393 02394 if (o->chan->cid.cid_name) 02395 free(o->chan->cid.cid_name); 02396 o->chan->cid.cid_name = ast_strdup(in->cid.cid_name); 02397 02398 ast_string_field_set(o->chan, accountcode, in->accountcode); 02399 o->chan->cdrflags = in->cdrflags; 02400 02401 if (in->cid.cid_ani) { 02402 if (o->chan->cid.cid_ani) 02403 free(o->chan->cid.cid_ani); 02404 o->chan->cid.cid_ani = ast_strdup(in->cid.cid_ani); 02405 } 02406 if (o->chan->cid.cid_rdnis) 02407 free(o->chan->cid.cid_rdnis); 02408 o->chan->cid.cid_rdnis = ast_strdup(S_OR(in->macroexten, in->exten)); 02409 if (ast_call(o->chan, stuff, 0)) { 02410 ast_log(LOG_NOTICE, "Forwarding failed to dial '%s/%s'\n", 02411 tech, stuff); 02412 do_hang(o); 02413 numnochan++; 02414 } 02415 } 02416 /* Hangup the original channel now, in case we needed it */ 02417 ast_hangup(winner); 02418 continue; 02419 } 02420 f = ast_read(winner); 02421 if (f) { 02422 if (f->frametype == AST_FRAME_CONTROL) { 02423 switch (f->subclass) { 02424 case AST_CONTROL_ANSWER: 02425 /* This is our guy if someone answered. */ 02426 if (!peer) { 02427 if (option_verbose > 2) 02428 ast_verbose( VERBOSE_PREFIX_3 "%s answered %s\n", o->chan->name, in->name); 02429 peer = o; 02430 } 02431 break; 02432 case AST_CONTROL_BUSY: 02433 if (option_verbose > 2) 02434 ast_verbose( VERBOSE_PREFIX_3 "%s is busy\n", o->chan->name); 02435 if (in->cdr) 02436 ast_cdr_busy(in->cdr); 02437 do_hang(o); 02438 endtime = (long)time(NULL); 02439 endtime -= starttime; 02440 rna(endtime * 1000, qe, on, membername, 0); 02441 if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) { 02442 if (qe->parent->timeoutrestart) 02443 *to = orig; 02444 /* Have enough time for a queue member to answer? */ 02445 if (*to > 500) { 02446 ring_one(qe, outgoing, &numbusies); 02447 starttime = (long) time(NULL); 02448 } 02449 } 02450 numbusies++; 02451 break; 02452 case AST_CONTROL_CONGESTION: 02453 if (option_verbose > 2) 02454 ast_verbose( VERBOSE_PREFIX_3 "%s is circuit-busy\n", o->chan->name); 02455 if (in->cdr) 02456 ast_cdr_busy(in->cdr); 02457 endtime = (long)time(NULL); 02458 endtime -= starttime; 02459 rna(endtime * 1000, qe, on, membername, 0); 02460 do_hang(o); 02461 if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) { 02462 if (qe->parent->timeoutrestart) 02463 *to = orig; 02464 if (*to > 500) { 02465 ring_one(qe, outgoing, &numbusies); 02466 starttime = (long) time(NULL); 02467 } 02468 } 02469 numbusies++; 02470 break; 02471 case AST_CONTROL_RINGING: 02472 if (option_verbose > 2) 02473 ast_verbose( VERBOSE_PREFIX_3 "%s is ringing\n", o->chan->name); 02474 02475 /* Start ring indication when the channel is ringing, if specified */ 02476 if (qe->ring_when_ringing) { 02477 ast_moh_stop(qe->chan); 02478 ast_indicate(qe->chan, AST_CONTROL_RINGING); 02479 } 02480 break; 02481 case AST_CONTROL_OFFHOOK: 02482 /* Ignore going off hook */ 02483 break; 02484 default: 02485 ast_log(LOG_DEBUG, "Dunno what to do with control type %d\n", f->subclass); 02486 } 02487 } 02488 ast_frfree(f); 02489 } else { /* ast_read() returned NULL */ 02490 endtime = (long) time(NULL) - starttime; 02491 rna(endtime * 1000, qe, on, membername, 1); 02492 do_hang(o); 02493 if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) { 02494 if (qe->parent->timeoutrestart) 02495 *to = orig; 02496 if (*to > 500) { 02497 ring_one(qe, outgoing, &numbusies); 02498 starttime = (long) time(NULL); 02499 } 02500 } 02501 } 02502 } 02503 } 02504 02505 /* If we received an event from the caller, deal with it. */ 02506 if (winner == in) { 02507 f = ast_read(in); 02508 if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP))) { 02509 /* Got hung up */ 02510 *to = -1; 02511 if (f) 02512 ast_frfree(f); 02513 return NULL; 02514 } 02515 /* First check if DTMF digit is a valid exit */ 02516 if ((f->frametype == AST_FRAME_DTMF) && valid_exit(qe, f->subclass)) { 02517 if (option_verbose > 3) 02518 ast_verbose(VERBOSE_PREFIX_3 "User pressed digit: %c\n", f->subclass); 02519 *to = 0; 02520 *digit = f->subclass; 02521 ast_frfree(f); 02522 return NULL; 02523 } 02524 /* Else check if DTMF should be interpreted as caller disconnect */ 02525 if ((f->frametype == AST_FRAME_DTMF) && caller_disconnect && (f->subclass == '*')) { 02526 if (option_verbose > 3) 02527 ast_verbose(VERBOSE_PREFIX_3 "User hit %c to disconnect call.\n", f->subclass); 02528 *to = 0; 02529 ast_frfree(f); 02530 return NULL; 02531 } 02532 ast_frfree(f); 02533 } 02534 if (!*to) { 02535 for (o = start; o; o = o->call_next) 02536 rna(orig, qe, o->interface, o->member->membername, 1); 02537 } 02538 } 02539 02540 return peer; 02541 }
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 2603 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().
02604 { 02605 int res = 0; 02606 02607 /* This is the holding pen for callers 2 through maxlen */ 02608 for (;;) { 02609 enum queue_member_status stat; 02610 02611 if (is_our_turn(qe)) 02612 break; 02613 02614 /* If we have timed out, break out */ 02615 if (qe->expire && (time(NULL) >= qe->expire)) { 02616 *reason = QUEUE_TIMEOUT; 02617 break; 02618 } 02619 02620 stat = get_member_status(qe->parent, qe->max_penalty); 02621 02622 /* leave the queue if no agents, if enabled */ 02623 if (qe->parent->leavewhenempty && (stat == QUEUE_NO_MEMBERS)) { 02624 *reason = QUEUE_LEAVEEMPTY; 02625 ast_queue_log(qe->parent->name, qe->chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe->pos, qe->opos, (long)time(NULL) - qe->start); 02626 leave_queue(qe); 02627 break; 02628 } 02629 02630 /* leave the queue if no reachable agents, if enabled */ 02631 if ((qe->parent->leavewhenempty == QUEUE_EMPTY_STRICT) && (stat == QUEUE_NO_REACHABLE_MEMBERS)) { 02632 *reason = QUEUE_LEAVEUNAVAIL; 02633 ast_queue_log(qe->parent->name, qe->chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe->pos, qe->opos, (long)time(NULL) - qe->start); 02634 leave_queue(qe); 02635 break; 02636 } 02637 02638 /* Make a position announcement, if enabled */ 02639 if (qe->parent->announcefrequency && !ringing && 02640 (res = say_position(qe))) 02641 break; 02642 02643 /* If we have timed out, break out */ 02644 if (qe->expire && (time(NULL) >= qe->expire)) { 02645 *reason = QUEUE_TIMEOUT; 02646 break; 02647 } 02648 02649 /* Make a periodic announcement, if enabled */ 02650 if (qe->parent->periodicannouncefrequency && !ringing && 02651 (res = say_periodic_announcement(qe))) 02652 break; 02653 02654 /* If we have timed out, break out */ 02655 if (qe->expire && (time(NULL) >= qe->expire)) { 02656 *reason = QUEUE_TIMEOUT; 02657 break; 02658 } 02659 02660 /* Wait a second before checking again */ 02661 if ((res = ast_waitfordigit(qe->chan, RECHECK * 1000))) { 02662 if (res > 0 && !valid_exit(qe, res)) 02663 res = 0; 02664 else 02665 break; 02666 } 02667 02668 /* If we have timed out, break out */ 02669 if (qe->expire && (time(NULL) >= qe->expire)) { 02670 *reason = QUEUE_TIMEOUT; 02671 break; 02672 } 02673 } 02674 02675 return res; 02676 }
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 5671 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 5671 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 5554 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 5559 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 5549 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 5543 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 5520 of file app_queue.c.
char qrm_cmd_usage[] [static] |
Initial value:
"Usage: queue remove member <channel> from <queue>\n"
Definition at line 5546 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 5539 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 2773 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] |