#include "asterisk.h"
#include <sys/time.h>
#include <sys/signal.h>
#include <netinet/in.h>
#include <ctype.h>
#include "asterisk/lock.h"
#include "asterisk/file.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.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/event.h"
#include "asterisk/astobj2.h"
#include "asterisk/strings.h"
#include "asterisk/global_datastores.h"
#include "asterisk/taskprocessor.h"
#include "asterisk/aoc.h"
#include "asterisk/callerid.h"
#include "asterisk/cel.h"
#include "asterisk/data.h"
Go to the source code of this file.
Data Structures | |
struct | autopause |
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 | member |
struct | penalty_rule |
struct | queue_end_bridge |
struct | queue_ent |
struct | queue_transfer_ds |
struct | rule_list |
struct | rule_lists |
struct | statechange |
struct | strategy |
Defines | |
#define | ANNOUNCEHOLDTIME_ALWAYS 1 |
#define | ANNOUNCEHOLDTIME_ONCE 2 |
#define | ANNOUNCEPOSITION_LIMIT 4 |
#define | ANNOUNCEPOSITION_MORE_THAN 3 |
#define | ANNOUNCEPOSITION_NO 2 |
#define | ANNOUNCEPOSITION_YES 1 |
#define | AST_MAX_WATCHERS 256 |
#define | DATA_EXPORT_CALL_QUEUE(MEMBER) |
#define | DATA_EXPORT_MEMBER(MEMBER) |
#define | DATA_EXPORT_QUEUE_ENT(MEMBER) |
#define | DEFAULT_MIN_ANNOUNCE_FREQUENCY 15 |
#define | DEFAULT_RETRY 5 |
#define | DEFAULT_TIMEOUT 15 |
#define | MAX_PERIODIC_ANNOUNCEMENTS 10 |
#define | MAX_QUEUE_BUCKETS 53 |
#define | PM_MAX_LEN 8192 |
#define | QUEUE_EVENT_VARIABLES 3 |
#define | queue_t_ref(a, b) queue_ref(a) |
#define | queue_t_unref(a, b) queue_unref(a) |
#define | queues_t_link(c, q, tag) ao2_t_link(c,q,tag) |
#define | queues_t_unlink(c, q, tag) ao2_t_unlink(c,q,tag) |
#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_LEASTRECENT, QUEUE_STRATEGY_FEWESTCALLS, QUEUE_STRATEGY_RANDOM, QUEUE_STRATEGY_RRMEMORY, QUEUE_STRATEGY_LINEAR, QUEUE_STRATEGY_WRANDOM, QUEUE_STRATEGY_RRORDERED } |
enum | { QUEUE_AUTOPAUSE_OFF = 0, QUEUE_AUTOPAUSE_ON, QUEUE_AUTOPAUSE_ALL } |
enum | agent_complete_reason { CALLER, AGENT, TRANSFER } |
enum | empty_conditions { QUEUE_EMPTY_PENALTY = (1 << 0), QUEUE_EMPTY_PAUSED = (1 << 1), QUEUE_EMPTY_INUSE = (1 << 2), QUEUE_EMPTY_RINGING = (1 << 3), QUEUE_EMPTY_UNAVAILABLE = (1 << 4), QUEUE_EMPTY_INVALID = (1 << 5), QUEUE_EMPTY_UNKNOWN = (1 << 6), QUEUE_EMPTY_WRAPUP = (1 << 7) } |
enum | queue_reload_mask { QUEUE_RELOAD_PARAMETERS = (1 << 0), QUEUE_RELOAD_MEMBER = (1 << 1), QUEUE_RELOAD_RULES = (1 << 2), QUEUE_RESET_STATS = (1 << 3) } |
enum | queue_result { QUEUE_UNKNOWN = 0, QUEUE_TIMEOUT = 1, QUEUE_JOINEMPTY = 2, QUEUE_LEAVEEMPTY = 3, QUEUE_JOINUNAVAIL = 4, QUEUE_LEAVEUNAVAIL = 5, QUEUE_FULL = 6, QUEUE_CONTINUE = 7 } |
enum | queue_timeout_priority { TIMEOUT_PRIORITY_APP, TIMEOUT_PRIORITY_CONF } |
Functions | |
static char * | __queues_show (struct mansession *s, int fd, int argc, const char *const *argv) |
Show queue(s) status and statistics. | |
static void | __reg_module (void) |
static void | __unreg_module (void) |
static int | add_to_queue (const char *queuename, const char *interface, const char *membername, int penalty, int paused, int dump, const char *state_interface) |
Add member to queue. | |
static struct call_queue * | alloc_queue (const char *queuename) |
static int | aqm_exec (struct ast_channel *chan, const char *data) |
AddQueueMember application. | |
AST_DATA_STRUCTURE (queue_ent, DATA_EXPORT_QUEUE_ENT) | |
AST_DATA_STRUCTURE (member, DATA_EXPORT_MEMBER) | |
AST_DATA_STRUCTURE (call_queue, DATA_EXPORT_CALL_QUEUE) | |
static int | attended_transfer_occurred (struct ast_channel *chan) |
mechanism to tell if a queue caller was atxferred by a queue member. | |
static int | autopause2int (const char *autopause) |
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 | callattempt_free (struct callattempt *doomed) |
static void | clear_queue (struct call_queue *q) |
static int | clear_stats (const char *queuename) |
Facilitates resetting statistics for a queue. | |
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_pause_member (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_rule_show (const char *line, const char *word, int pos, int state) |
static char * | complete_queue_set_member_penalty (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 void | copy_rules (struct queue_ent *qe, const char *rulename) |
Copy rule from global list into specified queue. | |
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) |
Free queue's member list then its string fields. | |
static void | device_state_cb (const struct ast_event *event, void *unused) |
static void | do_hang (struct callattempt *o) |
common hangup actions | |
static void | do_print (struct mansession *s, int fd, const char *str) |
direct ouput to manager or cli with proper terminator | |
static void | dump_queue_members (struct call_queue *pm_queue) |
Dump all members in a specific queue to the database. | |
static void | end_bridge_callback (void *data) |
static void | end_bridge_callback_data_fixup (struct ast_bridge_config *bconfig, struct ast_channel *originator, struct ast_channel *terminator) |
static int | extension_state_cb (char *context, char *exten, enum ast_extension_states state, void *data) |
static int | extensionstate2devicestate (int state) |
Helper function which converts from extension state to device state values. | |
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) |
Iterate through queue's member list and delete them. | |
static int | get_member_penalty (char *queuename, char *interface) |
static int | get_member_status (struct call_queue *q, int max_penalty, int min_penalty, enum empty_conditions conditions) |
Check if members are available. | |
static int | get_queue_member_status (struct member *cur) |
Return the current state of a member. | |
static char * | handle_queue_add_member (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
static char * | handle_queue_pause_member (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
static char * | handle_queue_reload (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
static char * | handle_queue_remove_member (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
static char * | handle_queue_reset (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
static char * | handle_queue_rule_show (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
static char * | handle_queue_set_member_penalty (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
static int | handle_statechange (void *datap) |
set a member's status based on device state of that member's interface | |
static void | hangupcalls (struct callattempt *outgoing, struct ast_channel *exception, int cancel_answered_elsewhere) |
Hang up a list of outgoing calls. | |
static void | init_queue (struct call_queue *q) |
Initialize Queue default values. | |
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 int | insert_penaltychange (const char *list_name, const char *content, const int linenum) |
Change queue penalty by adding rule. | |
static const char * | int2strat (int strategy) |
static struct member * | interface_exists (struct call_queue *q, 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, int position) |
static int | kill_dead_members (void *obj, void *arg, int flags) |
static int | kill_dead_queues (void *obj, void *arg, int flags) |
static void | leave_queue (struct queue_ent *qe) |
Caller leaving queue. | |
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_log_custom (struct mansession *s, const struct message *m) |
static int | manager_queue_member_penalty (struct mansession *s, const struct message *m) |
static int | manager_queue_reload (struct mansession *s, const struct message *m) |
static int | manager_queue_reset (struct mansession *s, const struct message *m) |
static int | manager_queue_rule_show (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) |
Queue status info via AMI. | |
static int | manager_queues_summary (struct mansession *s, const struct message *m) |
Summary of queue info via the AMI. | |
static int | manager_remove_queue_member (struct mansession *s, const struct message *m) |
static int | mark_dead_and_unfound (void *obj, void *arg, int flags) |
static int | mark_member_dead (void *obj, void *arg, int flags) |
static int | member_cmp_fn (void *obj1, void *obj2, int flags) |
static int | member_hash_fn (const void *obj, const int flags) |
static int | num_available_members (struct call_queue *q) |
Get the number of members available to accept a call. | |
static void | parse_empty_options (const char *value, enum empty_conditions *empty, int joinempty) |
static int | play_file (struct ast_channel *chan, const char *filename) |
static int | pqm_exec (struct ast_channel *chan, const char *data) |
PauseQueueMember application. | |
static int | ql_exec (struct ast_channel *chan, const char *data) |
QueueLog application. | |
static int | queue_cmp_cb (void *obj, void *arg, int flags) |
static int | queue_exec (struct ast_channel *chan, const char *data) |
The starting point for all queue calls. | |
static int | queue_function_exists (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len) |
Check if a given queue exists. | |
static int | queue_function_memberpenalty_read (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len) |
Dialplan function QUEUE_MEMBER_PENALTY() Gets the members penalty. | |
static int | queue_function_memberpenalty_write (struct ast_channel *chan, const char *cmd, char *data, const char *value) |
Dialplan function QUEUE_MEMBER_PENALTY() Sets the members penalty. | |
static int | queue_function_qac (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len) |
Get number either busy / free / ready or total members of a specific queue. | |
static int | queue_function_qac_dep (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len) |
Get the total number of members in a specific queue (Deprecated). | |
static int | queue_function_queuememberlist (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len) |
Dialplan function QUEUE_MEMBER_LIST() Get list of members in a specific queue. | |
static int | queue_function_queuewaitingcount (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len) |
Dialplan function QUEUE_WAITING_COUNT() Get number callers waiting in a specific queue. | |
static int | queue_function_var (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len) |
create interface var with all queue details. | |
static int | queue_hash_cb (const void *obj, const int flags) |
static struct call_queue * | queue_ref (struct call_queue *q) |
static void | queue_set_global_params (struct ast_config *cfg) |
static void | queue_set_param (struct call_queue *q, const char *param, const char *val, int linenum, int failunknown) |
Configure a queue parameter. | |
static char * | queue_show (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
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 struct call_queue * | queue_unref (struct call_queue *q) |
static int | queues_data_provider_get (const struct ast_data_search *search, struct ast_data *data_root) |
static void | queues_data_provider_get_helper (const struct ast_data_search *search, struct ast_data *data_root, struct call_queue *queue) |
static void | recalc_holdtime (struct queue_ent *qe, int newholdtime) |
static void | record_abandoned (struct queue_ent *qe) |
Record that a caller gave up on waiting in queue. | |
static int | reload (void) |
static int | reload_handler (int reload, struct ast_flags *mask, const char *queuename) |
The command center for all reload operations. | |
static void | reload_queue_members (void) |
Reload dynamic queue members persisted into the astdb. | |
static int | reload_queue_rules (int reload) |
Reload the rules defined in queuerules.conf. | |
static int | reload_queues (int reload, struct ast_flags *mask, const char *queuename) |
reload the queues.conf file | |
static void | reload_single_member (const char *memberdata, struct call_queue *q) |
reload information pertaining to a single member | |
static void | reload_single_queue (struct ast_config *cfg, struct ast_flags *mask, const char *queuename) |
Reload information pertaining to a particular queue. | |
static int | remove_from_queue (const char *queuename, const char *interface) |
Remove member from queue. | |
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, const char *data) |
RemoveQueueMember application. | |
static void | rt_handle_member_record (struct call_queue *q, char *interface, const char *rt_uniqueid, const char *membername, const char *penalty_str, const char *paused_str, const char *state_interface) |
Find rt member record to update otherwise create one. | |
static int | say_periodic_announcement (struct queue_ent *qe, int ringing) |
Playback announcement to queued members if peroid has elapsed. | |
static int | say_position (struct queue_ent *qe, int ringing) |
static void | send_agent_complete (const struct queue_ent *qe, const char *queuename, const struct ast_channel *peer, const struct member *member, time_t callstart, char *vars, size_t vars_len, enum agent_complete_reason rsn) |
Send out AMI message with member call completion status information. | |
static int | set_member_paused (const char *queuename, const char *interface, const char *reason, int paused) |
static int | set_member_penalty (const char *queuename, const char *interface, int penalty) |
static void | set_queue_result (struct ast_channel *chan, enum queue_result res) |
sets the QUEUESTATUS channel variable | |
static void | set_queue_variables (struct call_queue *q, struct ast_channel *chan) |
Set variables of queue. | |
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 | store_next_lin (struct queue_ent *qe, struct callattempt *outgoing) |
Search for best metric and add to Linear queue. | |
static int | store_next_rr (struct queue_ent *qe, struct callattempt *outgoing) |
Search for best metric and add to Round Robbin queue. | |
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, const char *macro, const char *gosub, int ringing) |
A large function which calls members, updates statistics, and bridges the caller and a member. | |
static int | unload_module (void) |
static void | update_qe_rule (struct queue_ent *qe) |
update rules for queues | |
static int | update_queue (struct call_queue *q, struct member *member, int callcompletedinsl, int newtalktime) |
update the queue status | |
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 (struct call_queue *q, struct member *m, const int status) |
set a member's status based on device state of that member's state_interface. | |
static int | upqm_exec (struct ast_channel *chan, const char *data) |
UnPauseQueueMember application. | |
static int | valid_exit (struct queue_ent *qe, char digit) |
Check for valid exit from queue via goto. | |
static char * | vars2manager (struct ast_channel *chan, char *vars, size_t len) |
convert "\n" to "\nVariable: " ready for manager to use | |
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, int update_connectedline) |
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_LOAD_ORDER , .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 = "8586c2a7d357cb591cc3a6607a8f62d1" , .load = load_module, .unload = unload_module, .reload = reload, .load_pri = AST_MODPRI_DEVSTATE_CONSUMER, .nonoptreq = "res_monitor", } |
static char * | app = "Queue" |
static char * | app_aqm = "AddQueueMember" |
static char * | app_pqm = "PauseQueueMember" |
static char * | app_ql = "QueueLog" |
static char * | app_rqm = "RemoveQueueMember" |
static char * | app_upqm = "UnpauseQueueMember" |
static struct ast_module_info * | ast_module_info = &__mod_info |
static int | autofill_default = 1 |
queues.conf [general] option | |
static struct autopause | autopausesmodes [] |
static struct ast_cli_entry | cli_queue [] |
static struct ast_event_sub * | device_state_sub |
Subscription to device state change events. | |
static struct ast_taskprocessor * | devicestate_tps |
static int | montype_default = 0 |
queues.conf [general] option | |
static const char *const | pm_family = "Queue/PersistentMembers" |
Persistent Members astdb family. | |
static const char | qpm_cmd_usage [] |
static const char | qsmp_cmd_usage [] |
static struct ast_data_entry | queue_data_providers [] |
static int | queue_persistent_members = 0 |
queues.conf [general] option | |
struct { | |
enum queue_result id | |
char * text | |
} | queue_results [] |
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 | queueexists_function |
static struct ast_custom_function | queuemembercount_dep |
static struct ast_custom_function | queuemembercount_function |
static struct ast_custom_function | queuememberlist_function |
static struct ast_custom_function | queuememberpenalty_function |
static struct ao2_container * | queues |
static struct ast_data_handler | queues_data_provider |
static struct ast_custom_function | queuevar_function |
static struct ast_custom_function | queuewaitingcount_function |
static const char | qum_cmd_usage [] |
static int | shared_lastcall = 1 |
queues.conf [general] option | |
static struct strategy | strategies [] |
static int | update_cdr = 0 |
queues.conf [general] option | |
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 ANNOUNCEPOSITION_LIMIT 4 |
We not announce position more than <limit>
Definition at line 1076 of file app_queue.c.
Referenced by queue_set_param(), queues_data_provider_get_helper(), and say_position().
#define ANNOUNCEPOSITION_MORE_THAN 3 |
We say "Currently there are more than <limit>"
Definition at line 1075 of file app_queue.c.
Referenced by queue_set_param(), queues_data_provider_get_helper(), and say_position().
#define ANNOUNCEPOSITION_NO 2 |
We don't announce position
Definition at line 1074 of file app_queue.c.
Referenced by queue_set_param(), and queues_data_provider_get_helper().
#define ANNOUNCEPOSITION_YES 1 |
We announce position
Definition at line 1073 of file app_queue.c.
Referenced by init_queue(), queue_set_param(), queues_data_provider_get_helper(), and say_position().
#define AST_MAX_WATCHERS 256 |
Definition at line 3410 of file app_queue.c.
#define DATA_EXPORT_CALL_QUEUE | ( | MEMBER | ) |
Definition at line 7978 of file app_queue.c.
#define DATA_EXPORT_MEMBER | ( | MEMBER | ) |
Definition at line 8043 of file app_queue.c.
#define DATA_EXPORT_QUEUE_ENT | ( | MEMBER | ) |
Definition at line 8057 of file app_queue.c.
#define DEFAULT_MIN_ANNOUNCE_FREQUENCY 15 |
The minimum number of seconds between position announcements \ The default value of 15 provides backwards compatibility
Definition at line 889 of file app_queue.c.
Referenced by init_queue().
#define DEFAULT_RETRY 5 |
#define DEFAULT_TIMEOUT 15 |
#define MAX_PERIODIC_ANNOUNCEMENTS 10 |
The maximum periodic announcements we can have
Definition at line 888 of file app_queue.c.
Referenced by destroy_queue(), init_queue(), and queue_set_param().
#define MAX_QUEUE_BUCKETS 53 |
#define PM_MAX_LEN 8192 |
Definition at line 914 of file app_queue.c.
Referenced by dump_queue_members(), and reload_queue_members().
#define QUEUE_EVENT_VARIABLES 3 |
Definition at line 1062 of file app_queue.c.
Referenced by queue_set_param(), ring_entry(), rna(), and send_agent_complete().
#define queue_t_ref | ( | a, | |||
b | ) | queue_ref(a) |
#define queue_t_unref | ( | a, | |||
b | ) | queue_unref(a) |
Definition at line 1275 of file app_queue.c.
Referenced by __queues_show(), add_to_queue(), alloc_queue(), clear_stats(), compare_weight(), complete_queue(), complete_queue_remove_member(), end_bridge_callback(), extension_state_cb(), find_queue_by_name_rt(), get_member_penalty(), handle_statechange(), leave_queue(), manager_queues_status(), manager_queues_summary(), queue_function_exists(), queue_function_qac(), queue_function_qac_dep(), queue_function_queuememberlist(), queue_function_queuewaitingcount(), queue_function_var(), reload_queue_members(), reload_single_queue(), remove_from_queue(), set_member_paused(), set_member_penalty(), unload_module(), and update_queue().
#define queues_t_link | ( | c, | |||
q, | |||||
tag | ) | ao2_t_link(c,q,tag) |
Definition at line 1276 of file app_queue.c.
#define queues_t_unlink | ( | c, | |||
q, | |||||
tag | ) | ao2_t_unlink(c,q,tag) |
Definition at line 1277 of file app_queue.c.
Referenced by find_queue_by_name_rt(), leave_queue(), and unload_module().
#define RECHECK 1 |
Recheck every second to see we we're at the top yet
Definition at line 887 of file app_queue.c.
#define RES_EXISTS (-1) |
Entry already exists
Definition at line 894 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) |
No such queue
Definition at line 896 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) |
Member is not dynamic
Definition at line 897 of file app_queue.c.
Referenced by handle_queue_add_member(), handle_queue_remove_member(), manager_remove_queue_member(), remove_from_queue(), and rqm_exec().
#define RES_OKAY 0 |
Action completed
Definition at line 893 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) |
Out of memory
Definition at line 895 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_LEASTRECENT | |
QUEUE_STRATEGY_FEWESTCALLS | |
QUEUE_STRATEGY_RANDOM | |
QUEUE_STRATEGY_RRMEMORY | |
QUEUE_STRATEGY_LINEAR | |
QUEUE_STRATEGY_WRANDOM | |
QUEUE_STRATEGY_RRORDERED |
Definition at line 834 of file app_queue.c.
00834 { 00835 QUEUE_STRATEGY_RINGALL = 0, 00836 QUEUE_STRATEGY_LEASTRECENT, 00837 QUEUE_STRATEGY_FEWESTCALLS, 00838 QUEUE_STRATEGY_RANDOM, 00839 QUEUE_STRATEGY_RRMEMORY, 00840 QUEUE_STRATEGY_LINEAR, 00841 QUEUE_STRATEGY_WRANDOM, 00842 QUEUE_STRATEGY_RRORDERED, 00843 };
anonymous enum |
Definition at line 845 of file app_queue.c.
00845 { 00846 QUEUE_AUTOPAUSE_OFF = 0, 00847 QUEUE_AUTOPAUSE_ON, 00848 QUEUE_AUTOPAUSE_ALL 00849 };
enum empty_conditions |
QUEUE_EMPTY_PENALTY | |
QUEUE_EMPTY_PAUSED | |
QUEUE_EMPTY_INUSE | |
QUEUE_EMPTY_RINGING | |
QUEUE_EMPTY_UNAVAILABLE | |
QUEUE_EMPTY_INVALID | |
QUEUE_EMPTY_UNKNOWN | |
QUEUE_EMPTY_WRAPUP |
Definition at line 1048 of file app_queue.c.
01048 { 01049 QUEUE_EMPTY_PENALTY = (1 << 0), 01050 QUEUE_EMPTY_PAUSED = (1 << 1), 01051 QUEUE_EMPTY_INUSE = (1 << 2), 01052 QUEUE_EMPTY_RINGING = (1 << 3), 01053 QUEUE_EMPTY_UNAVAILABLE = (1 << 4), 01054 QUEUE_EMPTY_INVALID = (1 << 5), 01055 QUEUE_EMPTY_UNKNOWN = (1 << 6), 01056 QUEUE_EMPTY_WRAPUP = (1 << 7), 01057 };
enum queue_reload_mask |
Definition at line 851 of file app_queue.c.
00851 { 00852 QUEUE_RELOAD_PARAMETERS = (1 << 0), 00853 QUEUE_RELOAD_MEMBER = (1 << 1), 00854 QUEUE_RELOAD_RULES = (1 << 2), 00855 QUEUE_RESET_STATS = (1 << 3), 00856 };
enum queue_result |
QUEUE_UNKNOWN | |
QUEUE_TIMEOUT | |
QUEUE_JOINEMPTY | |
QUEUE_LEAVEEMPTY | |
QUEUE_JOINUNAVAIL | |
QUEUE_LEAVEUNAVAIL | |
QUEUE_FULL | |
QUEUE_CONTINUE |
Definition at line 937 of file app_queue.c.
00937 { 00938 QUEUE_UNKNOWN = 0, 00939 QUEUE_TIMEOUT = 1, 00940 QUEUE_JOINEMPTY = 2, 00941 QUEUE_LEAVEEMPTY = 3, 00942 QUEUE_JOINUNAVAIL = 4, 00943 QUEUE_LEAVEUNAVAIL = 5, 00944 QUEUE_FULL = 6, 00945 QUEUE_CONTINUE = 7, 00946 };
Definition at line 962 of file app_queue.c.
00962 { 00963 TIMEOUT_PRIORITY_APP, 00964 TIMEOUT_PRIORITY_CONF, 00965 };
static char* __queues_show | ( | struct mansession * | s, | |
int | fd, | |||
int | argc, | |||
const char *const * | argv | |||
) | [static] |
Show queue(s) status and statistics.
List the queues strategy, calls processed, members logged in, other queue statistics such as avg hold time.
Definition at line 6890 of file app_queue.c.
References ao2_container_count(), ao2_iterator_destroy(), AO2_ITERATOR_DONTLOCK, ao2_iterator_init(), ao2_iterator_next, ao2_lock, ao2_ref, ao2_t_iterator_next, ao2_unlock, ast_category_browse(), ast_check_realtime(), ast_config_destroy(), ast_devstate2str(), ast_load_realtime_multientry(), ast_str_alloca, ast_str_append(), ast_str_buffer(), ast_str_set(), ast_strlen_zero(), member::calls, call_queue::callsabandoned, call_queue::callscompleted, call_queue::callscompletedinsl, queue_ent::chan, CLI_SHOWUSAGE, CLI_SUCCESS, call_queue::count, do_print(), 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::pos, queue_ent::prio, queue_t_unref, member::realtime, call_queue::realtime, SENTINEL, call_queue::servicelevel, queue_ent::start, member::status, call_queue::strategy, call_queue::talktime, and call_queue::weight.
Referenced by manager_queues_show(), and queue_show().
06891 { 06892 struct call_queue *q; 06893 struct ast_str *out = ast_str_alloca(240); 06894 int found = 0; 06895 time_t now = time(NULL); 06896 struct ao2_iterator queue_iter; 06897 struct ao2_iterator mem_iter; 06898 06899 if (argc != 2 && argc != 3) 06900 return CLI_SHOWUSAGE; 06901 06902 if (argc == 3) { /* specific queue */ 06903 if ((q = load_realtime_queue(argv[2]))) { 06904 queue_t_unref(q, "Done with temporary pointer"); 06905 } 06906 } else if (ast_check_realtime("queues")) { 06907 /* This block is to find any queues which are defined in realtime but 06908 * which have not yet been added to the in-core container 06909 */ 06910 struct ast_config *cfg = ast_load_realtime_multientry("queues", "name LIKE", "%", SENTINEL); 06911 char *queuename; 06912 if (cfg) { 06913 for (queuename = ast_category_browse(cfg, NULL); !ast_strlen_zero(queuename); queuename = ast_category_browse(cfg, queuename)) { 06914 if ((q = load_realtime_queue(queuename))) { 06915 queue_t_unref(q, "Done with temporary pointer"); 06916 } 06917 } 06918 ast_config_destroy(cfg); 06919 } 06920 } 06921 06922 queue_iter = ao2_iterator_init(queues, AO2_ITERATOR_DONTLOCK); 06923 ao2_lock(queues); 06924 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) { 06925 float sl; 06926 struct call_queue *realtime_queue = NULL; 06927 06928 ao2_lock(q); 06929 /* This check is to make sure we don't print information for realtime 06930 * queues which have been deleted from realtime but which have not yet 06931 * been deleted from the in-core container 06932 */ 06933 if (q->realtime && !(realtime_queue = load_realtime_queue(q->name))) { 06934 ao2_unlock(q); 06935 queue_t_unref(q, "Done with iterator"); 06936 continue; 06937 } else if (q->realtime) { 06938 queue_t_unref(realtime_queue, "Queue is already in memory"); 06939 } 06940 if (argc == 3 && strcasecmp(q->name, argv[2])) { 06941 ao2_unlock(q); 06942 queue_t_unref(q, "Done with iterator"); 06943 continue; 06944 } 06945 found = 1; 06946 06947 ast_str_set(&out, 0, "%s has %d calls (max ", q->name, q->count); 06948 if (q->maxlen) 06949 ast_str_append(&out, 0, "%d", q->maxlen); 06950 else 06951 ast_str_append(&out, 0, "unlimited"); 06952 sl = 0; 06953 if (q->callscompleted > 0) 06954 sl = 100 * ((float) q->callscompletedinsl / (float) q->callscompleted); 06955 ast_str_append(&out, 0, ") in '%s' strategy (%ds holdtime, %ds talktime), W:%d, C:%d, A:%d, SL:%2.1f%% within %ds", 06956 int2strat(q->strategy), q->holdtime, q->talktime, q->weight, 06957 q->callscompleted, q->callsabandoned,sl,q->servicelevel); 06958 do_print(s, fd, ast_str_buffer(out)); 06959 if (!ao2_container_count(q->members)) 06960 do_print(s, fd, " No Members"); 06961 else { 06962 struct member *mem; 06963 06964 do_print(s, fd, " Members: "); 06965 mem_iter = ao2_iterator_init(q->members, 0); 06966 while ((mem = ao2_iterator_next(&mem_iter))) { 06967 ast_str_set(&out, 0, " %s", mem->membername); 06968 if (strcasecmp(mem->membername, mem->interface)) { 06969 ast_str_append(&out, 0, " (%s)", mem->interface); 06970 } 06971 if (mem->penalty) 06972 ast_str_append(&out, 0, " with penalty %d", mem->penalty); 06973 ast_str_append(&out, 0, "%s%s%s (%s)", 06974 mem->dynamic ? " (dynamic)" : "", 06975 mem->realtime ? " (realtime)" : "", 06976 mem->paused ? " (paused)" : "", 06977 ast_devstate2str(mem->status)); 06978 if (mem->calls) 06979 ast_str_append(&out, 0, " has taken %d calls (last was %ld secs ago)", 06980 mem->calls, (long) (time(NULL) - mem->lastcall)); 06981 else 06982 ast_str_append(&out, 0, " has taken no calls yet"); 06983 do_print(s, fd, ast_str_buffer(out)); 06984 ao2_ref(mem, -1); 06985 } 06986 ao2_iterator_destroy(&mem_iter); 06987 } 06988 if (!q->head) 06989 do_print(s, fd, " No Callers"); 06990 else { 06991 struct queue_ent *qe; 06992 int pos = 1; 06993 06994 do_print(s, fd, " Callers: "); 06995 for (qe = q->head; qe; qe = qe->next) { 06996 ast_str_set(&out, 0, " %d. %s (wait: %ld:%2.2ld, prio: %d)", 06997 pos++, qe->chan->name, (long) (now - qe->start) / 60, 06998 (long) (now - qe->start) % 60, qe->prio); 06999 do_print(s, fd, ast_str_buffer(out)); 07000 } 07001 } 07002 do_print(s, fd, ""); /* blank line between entries */ 07003 ao2_unlock(q); 07004 queue_t_unref(q, "Done with iterator"); /* Unref the iterator's reference */ 07005 } 07006 ao2_iterator_destroy(&queue_iter); 07007 ao2_unlock(queues); 07008 if (!found) { 07009 if (argc == 3) 07010 ast_str_set(&out, 0, "No such queue: %s.", argv[2]); 07011 else 07012 ast_str_set(&out, 0, "No queues."); 07013 do_print(s, fd, ast_str_buffer(out)); 07014 } 07015 return CLI_SUCCESS; 07016 }
static void __reg_module | ( | void | ) | [static] |
Definition at line 8378 of file app_queue.c.
static void __unreg_module | ( | void | ) | [static] |
Definition at line 8378 of file app_queue.c.
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] |
Add member to queue.
RES_NOT_DYNAMIC | when they aren't a RT member | |
RES_NOSUCHQUEUE | queue does not exist | |
RES_OKAY | added member from queue | |
RES_EXISTS | queue exists but no members | |
RES_OUT_OF_MEMORY | queue exists but not enough memory to create member |
Definition at line 5210 of file app_queue.c.
References ao2_link, ao2_lock, ao2_ref, ao2_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, queue_t_unref, RES_EXISTS, RES_NOSUCHQUEUE, RES_OKAY, RES_OUTOFMEMORY, and member::status.
Referenced by aqm_exec(), handle_queue_add_member(), manager_add_queue_member(), and reload_queue_members().
05211 { 05212 struct call_queue *q; 05213 struct member *new_member, *old_member; 05214 int res = RES_NOSUCHQUEUE; 05215 05216 /*! \note Ensure the appropriate realtime queue is loaded. Note that this 05217 * short-circuits if the queue is already in memory. */ 05218 if (!(q = load_realtime_queue(queuename))) 05219 return res; 05220 05221 ao2_lock(queues); 05222 05223 ao2_lock(q); 05224 if ((old_member = interface_exists(q, interface)) == NULL) { 05225 if ((new_member = create_queue_member(interface, membername, penalty, paused, state_interface))) { 05226 new_member->dynamic = 1; 05227 ao2_link(q->members, new_member); 05228 q->membercount++; 05229 manager_event(EVENT_FLAG_AGENT, "QueueMemberAdded", 05230 "Queue: %s\r\n" 05231 "Location: %s\r\n" 05232 "MemberName: %s\r\n" 05233 "Membership: %s\r\n" 05234 "Penalty: %d\r\n" 05235 "CallsTaken: %d\r\n" 05236 "LastCall: %d\r\n" 05237 "Status: %d\r\n" 05238 "Paused: %d\r\n", 05239 q->name, new_member->interface, new_member->membername, 05240 "dynamic", 05241 new_member->penalty, new_member->calls, (int) new_member->lastcall, 05242 new_member->status, new_member->paused); 05243 05244 ao2_ref(new_member, -1); 05245 new_member = NULL; 05246 05247 if (dump) 05248 dump_queue_members(q); 05249 05250 res = RES_OKAY; 05251 } else { 05252 res = RES_OUTOFMEMORY; 05253 } 05254 } else { 05255 ao2_ref(old_member, -1); 05256 res = RES_EXISTS; 05257 } 05258 ao2_unlock(q); 05259 ao2_unlock(queues); 05260 queue_t_unref(q, "Expiring temporary reference"); 05261 05262 return res; 05263 }
static struct call_queue* alloc_queue | ( | const char * | queuename | ) | [static] |
Definition at line 2169 of file app_queue.c.
References ao2_t_alloc, ast_string_field_init, ast_string_field_set, destroy_queue(), and queue_t_unref.
Referenced by find_queue_by_name_rt(), and reload_single_queue().
02170 { 02171 struct call_queue *q; 02172 02173 if ((q = ao2_t_alloc(sizeof(*q), destroy_queue, "Allocate queue"))) { 02174 if (ast_string_field_init(q, 64)) { 02175 queue_t_unref(q, "String field allocation failed"); 02176 return NULL; 02177 } 02178 ast_string_field_set(q, name, queuename); 02179 } 02180 return q; 02181 }
static int aqm_exec | ( | struct ast_channel * | chan, | |
const char * | data | |||
) | [static] |
AddQueueMember application.
Definition at line 5649 of file app_queue.c.
References add_to_queue(), args, AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_log(), ast_queue_log(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), 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().
05650 { 05651 int res=-1; 05652 char *parse, *temppos = NULL; 05653 AST_DECLARE_APP_ARGS(args, 05654 AST_APP_ARG(queuename); 05655 AST_APP_ARG(interface); 05656 AST_APP_ARG(penalty); 05657 AST_APP_ARG(options); 05658 AST_APP_ARG(membername); 05659 AST_APP_ARG(state_interface); 05660 ); 05661 int penalty = 0; 05662 05663 if (ast_strlen_zero(data)) { 05664 ast_log(LOG_WARNING, "AddQueueMember requires an argument (queuename[,interface[,penalty[,options[,membername[,stateinterface]]]]])\n"); 05665 return -1; 05666 } 05667 05668 parse = ast_strdupa(data); 05669 05670 AST_STANDARD_APP_ARGS(args, parse); 05671 05672 if (ast_strlen_zero(args.interface)) { 05673 args.interface = ast_strdupa(chan->name); 05674 temppos = strrchr(args.interface, '-'); 05675 if (temppos) 05676 *temppos = '\0'; 05677 } 05678 05679 if (!ast_strlen_zero(args.penalty)) { 05680 if ((sscanf(args.penalty, "%30d", &penalty) != 1) || penalty < 0) { 05681 ast_log(LOG_WARNING, "Penalty '%s' is invalid, must be an integer >= 0\n", args.penalty); 05682 penalty = 0; 05683 } 05684 } 05685 05686 switch (add_to_queue(args.queuename, args.interface, args.membername, penalty, 0, queue_persistent_members, args.state_interface)) { 05687 case RES_OKAY: 05688 ast_queue_log(args.queuename, chan->uniqueid, args.interface, "ADDMEMBER", "%s", ""); 05689 ast_log(LOG_NOTICE, "Added interface '%s' to queue '%s'\n", args.interface, args.queuename); 05690 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "ADDED"); 05691 res = 0; 05692 break; 05693 case RES_EXISTS: 05694 ast_log(LOG_WARNING, "Unable to add interface '%s' to queue '%s': Already there\n", args.interface, args.queuename); 05695 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "MEMBERALREADY"); 05696 res = 0; 05697 break; 05698 case RES_NOSUCHQUEUE: 05699 ast_log(LOG_WARNING, "Unable to add interface to queue '%s': No such queue\n", args.queuename); 05700 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "NOSUCHQUEUE"); 05701 res = 0; 05702 break; 05703 case RES_OUTOFMEMORY: 05704 ast_log(LOG_ERROR, "Out of memory adding member %s to queue %s\n", args.interface, args.queuename); 05705 break; 05706 } 05707 05708 return res; 05709 }
AST_DATA_STRUCTURE | ( | queue_ent | , | |
DATA_EXPORT_QUEUE_ENT | ||||
) |
AST_DATA_STRUCTURE | ( | member | , | |
DATA_EXPORT_MEMBER | ||||
) |
AST_DATA_STRUCTURE | ( | call_queue | , | |
DATA_EXPORT_CALL_QUEUE | ||||
) |
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 4213 of file app_queue.c.
References ast_channel_datastore_find(), and queue_transfer_info.
04214 { 04215 return ast_channel_datastore_find(chan, &queue_transfer_info, NULL) ? 0 : 1; 04216 }
static int autopause2int | ( | const char * | autopause | ) | [static] |
Definition at line 1233 of file app_queue.c.
References ARRAY_LEN, ast_strlen_zero(), ast_true(), autopause::autopause, autopausesmodes, QUEUE_AUTOPAUSE_OFF, and QUEUE_AUTOPAUSE_ON.
Referenced by queue_set_param().
01234 { 01235 int x; 01236 /*This 'double check' that default value is OFF */ 01237 if (ast_strlen_zero(autopause)) 01238 return QUEUE_AUTOPAUSE_OFF; 01239 01240 /*This 'double check' is to ensure old values works */ 01241 if(ast_true(autopause)) 01242 return QUEUE_AUTOPAUSE_ON; 01243 01244 for (x = 0; x < ARRAY_LEN(autopausesmodes); x++) { 01245 if (!strcasecmp(autopause, autopausesmodes[x].name)) 01246 return autopausesmodes[x].autopause; 01247 } 01248 01249 /*This 'double check' that default value is OFF */ 01250 return QUEUE_AUTOPAUSE_OFF; 01251 }
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
-1 | if penalties are exceeded | |
0 | otherwise |
Definition at line 4041 of file app_queue.c.
References ast_debug, ast_log(), ast_random(), member::calls, member::lastcall, queue_ent::linpos, queue_ent::linwrapped, LOG_WARNING, queue_ent::max_penalty, call_queue::membercount, callattempt::metric, queue_ent::min_penalty, member::penalty, call_queue::penaltymemberslimit, QUEUE_STRATEGY_FEWESTCALLS, QUEUE_STRATEGY_LEASTRECENT, QUEUE_STRATEGY_LINEAR, QUEUE_STRATEGY_RANDOM, QUEUE_STRATEGY_RINGALL, QUEUE_STRATEGY_RRMEMORY, QUEUE_STRATEGY_RRORDERED, QUEUE_STRATEGY_WRANDOM, call_queue::rrpos, call_queue::strategy, and call_queue::wrapped.
04042 { 04043 /* disregarding penalty on too few members? */ 04044 unsigned char usepenalty = (q->membercount <= q->penaltymemberslimit) ? 0 : 1; 04045 04046 if (usepenalty) { 04047 if ((qe->max_penalty && (mem->penalty > qe->max_penalty)) || 04048 (qe->min_penalty && (mem->penalty < qe->min_penalty))) { 04049 return -1; 04050 } 04051 } else { 04052 ast_debug(1, "Disregarding penalty, %d members and %d in penaltymemberslimit.\n", 04053 q->membercount, q->penaltymemberslimit); 04054 } 04055 04056 switch (q->strategy) { 04057 case QUEUE_STRATEGY_RINGALL: 04058 /* Everyone equal, except for penalty */ 04059 tmp->metric = mem->penalty * 1000000 * usepenalty; 04060 break; 04061 case QUEUE_STRATEGY_LINEAR: 04062 if (pos < qe->linpos) { 04063 tmp->metric = 1000 + pos; 04064 } else { 04065 if (pos > qe->linpos) 04066 /* Indicate there is another priority */ 04067 qe->linwrapped = 1; 04068 tmp->metric = pos; 04069 } 04070 tmp->metric += mem->penalty * 1000000 * usepenalty; 04071 break; 04072 case QUEUE_STRATEGY_RRORDERED: 04073 case QUEUE_STRATEGY_RRMEMORY: 04074 if (pos < q->rrpos) { 04075 tmp->metric = 1000 + pos; 04076 } else { 04077 if (pos > q->rrpos) 04078 /* Indicate there is another priority */ 04079 q->wrapped = 1; 04080 tmp->metric = pos; 04081 } 04082 tmp->metric += mem->penalty * 1000000 * usepenalty; 04083 break; 04084 case QUEUE_STRATEGY_RANDOM: 04085 tmp->metric = ast_random() % 1000; 04086 tmp->metric += mem->penalty * 1000000 * usepenalty; 04087 break; 04088 case QUEUE_STRATEGY_WRANDOM: 04089 tmp->metric = ast_random() % ((1 + mem->penalty) * 1000); 04090 break; 04091 case QUEUE_STRATEGY_FEWESTCALLS: 04092 tmp->metric = mem->calls; 04093 tmp->metric += mem->penalty * 1000000 * usepenalty; 04094 break; 04095 case QUEUE_STRATEGY_LEASTRECENT: 04096 if (!mem->lastcall) 04097 tmp->metric = 0; 04098 else 04099 tmp->metric = 1000000 - (time(NULL) - mem->lastcall); 04100 tmp->metric += mem->penalty * 1000000 * usepenalty; 04101 break; 04102 default: 04103 ast_log(LOG_WARNING, "Can't calculate metric for unknown strategy %d\n", q->strategy); 04104 break; 04105 } 04106 return 0; 04107 }
static void callattempt_free | ( | struct callattempt * | doomed | ) | [static] |
Definition at line 2824 of file app_queue.c.
References ao2_ref, ast_free, ast_party_connected_line_free(), callattempt::connected, and callattempt::member.
Referenced by hangupcalls().
02825 { 02826 if (doomed->member) { 02827 ao2_ref(doomed->member, -1); 02828 } 02829 ast_party_connected_line_free(&doomed->connected); 02830 ast_free(doomed); 02831 }
static void clear_queue | ( | struct call_queue * | q | ) | [static] |
Definition at line 1734 of file app_queue.c.
References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_ref, member::calls, call_queue::callsabandoned, call_queue::callscompleted, call_queue::callscompletedinsl, call_queue::holdtime, member::lastcall, call_queue::members, and call_queue::talktime.
Referenced by clear_stats(), and find_queue_by_name_rt().
01735 { 01736 q->holdtime = 0; 01737 q->callscompleted = 0; 01738 q->callsabandoned = 0; 01739 q->callscompletedinsl = 0; 01740 q->talktime = 0; 01741 01742 if (q->members) { 01743 struct member *mem; 01744 struct ao2_iterator mem_iter = ao2_iterator_init(q->members, 0); 01745 while ((mem = ao2_iterator_next(&mem_iter))) { 01746 mem->calls = 0; 01747 mem->lastcall = 0; 01748 ao2_ref(mem, -1); 01749 } 01750 ao2_iterator_destroy(&mem_iter); 01751 } 01752 }
static int clear_stats | ( | const char * | queuename | ) | [static] |
Facilitates resetting statistics for a queue.
This function actually does not reset any statistics, but rather finds a call_queue struct which corresponds to the passed-in queue name and passes that structure to the clear_queue function. If no queuename is passed in, then all queues will have their statistics reset.
queuename | The name of the queue to reset the statistics for. If this is NULL or zero-length, then this means to reset the statistics for all queues |
void |
Definition at line 6831 of file app_queue.c.
References ao2_iterator_destroy(), ao2_iterator_init(), ao2_lock, ao2_t_iterator_next, ao2_unlock, ast_strlen_zero(), clear_queue(), call_queue::name, and queue_t_unref.
Referenced by reload_handler().
06832 { 06833 struct call_queue *q; 06834 struct ao2_iterator queue_iter = ao2_iterator_init(queues, 0); 06835 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) { 06836 ao2_lock(q); 06837 if (ast_strlen_zero(queuename) || !strcasecmp(q->name, queuename)) 06838 clear_queue(q); 06839 ao2_unlock(q); 06840 queue_t_unref(q, "Done with iterator"); 06841 } 06842 ao2_iterator_destroy(&queue_iter); 06843 return 0; 06844 }
static int compare_weight | ( | struct call_queue * | rq, | |
struct member * | member | |||
) | [static] |
Definition at line 2904 of file app_queue.c.
References ao2_find, ao2_iterator_destroy(), ao2_iterator_init(), ao2_lock, ao2_ref, ao2_t_iterator_next, ao2_unlock, ast_debug, call_queue::count, member::interface, call_queue::members, call_queue::name, num_available_members(), OBJ_POINTER, queue_t_unref, queues, and call_queue::weight.
Referenced by ring_entry().
02905 { 02906 struct call_queue *q; 02907 struct member *mem; 02908 int found = 0; 02909 struct ao2_iterator queue_iter; 02910 02911 /* q's lock and rq's lock already set by try_calling() 02912 * to solve deadlock */ 02913 queue_iter = ao2_iterator_init(queues, 0); 02914 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) { 02915 if (q == rq) { /* don't check myself, could deadlock */ 02916 queue_t_unref(q, "Done with iterator"); 02917 continue; 02918 } 02919 ao2_lock(q); 02920 if (q->count && q->members) { 02921 if ((mem = ao2_find(q->members, member, OBJ_POINTER))) { 02922 ast_debug(1, "Found matching member %s in queue '%s'\n", mem->interface, q->name); 02923 if (q->weight > rq->weight && q->count >= num_available_members(q)) { 02924 ast_debug(1, "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); 02925 found = 1; 02926 } 02927 ao2_ref(mem, -1); 02928 } 02929 } 02930 ao2_unlock(q); 02931 queue_t_unref(q, "Done with iterator"); 02932 if (found) { 02933 break; 02934 } 02935 } 02936 ao2_iterator_destroy(&queue_iter); 02937 return found; 02938 }
static char* complete_queue | ( | const char * | line, | |
const char * | word, | |||
int | pos, | |||
int | state | |||
) | [static] |
Definition at line 7018 of file app_queue.c.
References ao2_iterator_destroy(), ao2_iterator_init(), ao2_t_iterator_next, ast_strdup, call_queue::name, and queue_t_unref.
Referenced by complete_queue_add_member(), complete_queue_pause_member(), complete_queue_remove_member(), complete_queue_set_member_penalty(), complete_queue_show(), handle_queue_reload(), and handle_queue_reset().
07019 { 07020 struct call_queue *q; 07021 char *ret = NULL; 07022 int which = 0; 07023 int wordlen = strlen(word); 07024 struct ao2_iterator queue_iter; 07025 07026 queue_iter = ao2_iterator_init(queues, 0); 07027 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) { 07028 if (!strncasecmp(word, q->name, wordlen) && ++which > state) { 07029 ret = ast_strdup(q->name); 07030 queue_t_unref(q, "Done with iterator"); 07031 break; 07032 } 07033 queue_t_unref(q, "Done with iterator"); 07034 } 07035 ao2_iterator_destroy(&queue_iter); 07036 07037 return ret; 07038 }
static char* complete_queue_add_member | ( | const char * | line, | |
const char * | word, | |||
int | pos, | |||
int | state | |||
) | [static] |
Definition at line 7450 of file app_queue.c.
References ast_malloc, ast_strdup, and complete_queue().
Referenced by handle_queue_add_member().
07451 { 07452 /* 0 - queue; 1 - add; 2 - member; 3 - <interface>; 4 - to; 5 - <queue>; 6 - penalty; 7 - <penalty>; 8 - as; 9 - <membername> */ 07453 switch (pos) { 07454 case 3: /* Don't attempt to complete name of interface (infinite possibilities) */ 07455 return NULL; 07456 case 4: /* only one possible match, "to" */ 07457 return state == 0 ? ast_strdup("to") : NULL; 07458 case 5: /* <queue> */ 07459 return complete_queue(line, word, pos, state); 07460 case 6: /* only one possible match, "penalty" */ 07461 return state == 0 ? ast_strdup("penalty") : NULL; 07462 case 7: 07463 if (state < 100) { /* 0-99 */ 07464 char *num; 07465 if ((num = ast_malloc(3))) { 07466 sprintf(num, "%d", state); 07467 } 07468 return num; 07469 } else { 07470 return NULL; 07471 } 07472 case 8: /* only one possible match, "as" */ 07473 return state == 0 ? ast_strdup("as") : NULL; 07474 case 9: /* Don't attempt to complete name of member (infinite possibilities) */ 07475 return NULL; 07476 default: 07477 return NULL; 07478 } 07479 }
static char* complete_queue_pause_member | ( | const char * | line, | |
const char * | word, | |||
int | pos, | |||
int | state | |||
) | [static] |
Definition at line 7671 of file app_queue.c.
References ast_strdup, and complete_queue().
Referenced by handle_queue_pause_member().
07672 { 07673 /* 0 - queue; 1 - pause; 2 - member; 3 - <interface>; 4 - queue; 5 - <queue>; 6 - reason; 7 - <reason> */ 07674 switch (pos) { 07675 case 3: /* Don't attempt to complete name of interface (infinite possibilities) */ 07676 return NULL; 07677 case 4: /* only one possible match, "queue" */ 07678 return state == 0 ? ast_strdup("queue") : NULL; 07679 case 5: /* <queue> */ 07680 return complete_queue(line, word, pos, state); 07681 case 6: /* "reason" */ 07682 return state == 0 ? ast_strdup("reason") : NULL; 07683 case 7: /* Can't autocomplete a reason, since it's 100% customizeable */ 07684 return NULL; 07685 default: 07686 return NULL; 07687 } 07688 }
static char* complete_queue_remove_member | ( | const char * | line, | |
const char * | word, | |||
int | pos, | |||
int | state | |||
) | [static] |
Definition at line 7580 of file app_queue.c.
References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_lock, ao2_ref, ao2_t_iterator_next, ao2_unlock, ast_strdup, complete_queue(), member::interface, member::membername, call_queue::members, and queue_t_unref.
Referenced by handle_queue_remove_member().
07581 { 07582 int which = 0; 07583 struct call_queue *q; 07584 struct member *m; 07585 struct ao2_iterator queue_iter; 07586 struct ao2_iterator mem_iter; 07587 int wordlen = strlen(word); 07588 07589 /* 0 - queue; 1 - remove; 2 - member; 3 - <member>; 4 - from; 5 - <queue> */ 07590 if (pos > 5 || pos < 3) 07591 return NULL; 07592 if (pos == 4) /* only one possible match, 'from' */ 07593 return (state == 0 ? ast_strdup("from") : NULL); 07594 07595 if (pos == 5) /* No need to duplicate code */ 07596 return complete_queue(line, word, pos, state); 07597 07598 /* here is the case for 3, <member> */ 07599 queue_iter = ao2_iterator_init(queues, 0); 07600 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) { 07601 ao2_lock(q); 07602 mem_iter = ao2_iterator_init(q->members, 0); 07603 while ((m = ao2_iterator_next(&mem_iter))) { 07604 if (!strncasecmp(word, m->membername, wordlen) && ++which > state) { 07605 char *tmp; 07606 ao2_unlock(q); 07607 tmp = ast_strdup(m->interface); 07608 ao2_ref(m, -1); 07609 queue_t_unref(q, "Done with iterator, returning interface name"); 07610 ao2_iterator_destroy(&mem_iter); 07611 ao2_iterator_destroy(&queue_iter); 07612 return tmp; 07613 } 07614 ao2_ref(m, -1); 07615 } 07616 ao2_iterator_destroy(&mem_iter); 07617 ao2_unlock(q); 07618 queue_t_unref(q, "Done with iterator"); 07619 } 07620 ao2_iterator_destroy(&queue_iter); 07621 07622 return NULL; 07623 }
static char* complete_queue_rule_show | ( | const char * | line, | |
const char * | word, | |||
int | pos, | |||
int | state | |||
) | [static] |
Definition at line 7804 of file app_queue.c.
References AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_strdup, rule_list::list, and rule_list::name.
Referenced by handle_queue_rule_show().
07805 { 07806 int which = 0; 07807 struct rule_list *rl_iter; 07808 int wordlen = strlen(word); 07809 char *ret = NULL; 07810 if (pos != 3) /* Wha? */ { 07811 return NULL; 07812 } 07813 07814 AST_LIST_LOCK(&rule_lists); 07815 AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) { 07816 if (!strncasecmp(word, rl_iter->name, wordlen) && ++which > state) { 07817 ret = ast_strdup(rl_iter->name); 07818 break; 07819 } 07820 } 07821 AST_LIST_UNLOCK(&rule_lists); 07822 07823 return ret; 07824 }
static char* complete_queue_set_member_penalty | ( | const char * | line, | |
const char * | word, | |||
int | pos, | |||
int | state | |||
) | [static] |
Definition at line 7741 of file app_queue.c.
References ast_strdup, and complete_queue().
Referenced by handle_queue_set_member_penalty().
07742 { 07743 /* 0 - queue; 1 - set; 2 - penalty; 3 - <penalty>; 4 - on; 5 - <member>; 6 - in; 7 - <queue>;*/ 07744 switch (pos) { 07745 case 4: 07746 if (state == 0) { 07747 return ast_strdup("on"); 07748 } else { 07749 return NULL; 07750 } 07751 case 6: 07752 if (state == 0) { 07753 return ast_strdup("in"); 07754 } else { 07755 return NULL; 07756 } 07757 case 7: 07758 return complete_queue(line, word, pos, state); 07759 default: 07760 return NULL; 07761 } 07762 }
static char* complete_queue_show | ( | const char * | line, | |
const char * | word, | |||
int | pos, | |||
int | state | |||
) | [static] |
Definition at line 7040 of file app_queue.c.
References complete_queue().
Referenced by queue_show().
07041 { 07042 if (pos == 2) 07043 return complete_queue(line, word, pos, state); 07044 return NULL; 07045 }
static int compress_char | ( | const char | c | ) | [static] |
Definition at line 1631 of file app_queue.c.
Referenced by member_hash_fn().
01632 { 01633 if (c < 32) 01634 return 0; 01635 else if (c > 96) 01636 return c - 64; 01637 else 01638 return c - 32; 01639 }
static void copy_rules | ( | struct queue_ent * | qe, | |
const char * | rulename | |||
) | [static] |
Copy rule from global list into specified queue.
Definition at line 5746 of file app_queue.c.
References ast_calloc, AST_LIST_INSERT_TAIL, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_strlen_zero(), call_queue::defaultrule, penalty_rule::list, rule_list::list, LOG_ERROR, penalty_rule::max_relative, penalty_rule::max_value, penalty_rule::min_relative, penalty_rule::min_value, rule_list::name, queue_ent::parent, queue_ent::qe_rules, rule_list::rules, and penalty_rule::time.
Referenced by queue_exec().
05747 { 05748 struct penalty_rule *pr_iter; 05749 struct rule_list *rl_iter; 05750 const char *tmp = ast_strlen_zero(rulename) ? qe->parent->defaultrule : rulename; 05751 AST_LIST_LOCK(&rule_lists); 05752 AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) { 05753 if (!strcasecmp(rl_iter->name, tmp)) 05754 break; 05755 } 05756 if (rl_iter) { 05757 AST_LIST_TRAVERSE(&rl_iter->rules, pr_iter, list) { 05758 struct penalty_rule *new_pr = ast_calloc(1, sizeof(*new_pr)); 05759 if (!new_pr) { 05760 ast_log(LOG_ERROR, "Memory allocation error when copying penalty rules! Aborting!\n"); 05761 AST_LIST_UNLOCK(&rule_lists); 05762 break; 05763 } 05764 new_pr->time = pr_iter->time; 05765 new_pr->max_value = pr_iter->max_value; 05766 new_pr->min_value = pr_iter->min_value; 05767 new_pr->max_relative = pr_iter->max_relative; 05768 new_pr->min_relative = pr_iter->min_relative; 05769 AST_LIST_INSERT_TAIL(&qe->qe_rules, new_pr, list); 05770 } 05771 } 05772 AST_LIST_UNLOCK(&rule_lists); 05773 }
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 1599 of file app_queue.c.
References ao2_alloc, ast_copy_string(), ast_log(), ast_strdupa, ast_strlen_zero(), queue_ent::context, exten, get_queue_member_status(), LOG_WARNING, member::penalty, S_OR, and strsep().
Referenced by add_to_queue(), reload_single_member(), and rt_handle_member_record().
01600 { 01601 struct member *cur; 01602 01603 if ((cur = ao2_alloc(sizeof(*cur), NULL))) { 01604 cur->penalty = penalty; 01605 cur->paused = paused; 01606 ast_copy_string(cur->interface, interface, sizeof(cur->interface)); 01607 if (!ast_strlen_zero(state_interface)) 01608 ast_copy_string(cur->state_interface, state_interface, sizeof(cur->state_interface)); 01609 else 01610 ast_copy_string(cur->state_interface, interface, sizeof(cur->state_interface)); 01611 if (!ast_strlen_zero(membername)) 01612 ast_copy_string(cur->membername, membername, sizeof(cur->membername)); 01613 else 01614 ast_copy_string(cur->membername, interface, sizeof(cur->membername)); 01615 if (!strchr(cur->interface, '/')) 01616 ast_log(LOG_WARNING, "No location at interface '%s'\n", interface); 01617 if (!strncmp(cur->state_interface, "hint:", 5)) { 01618 char *tmp = ast_strdupa(cur->state_interface), *context = tmp; 01619 char *exten = strsep(&context, "@") + 5; 01620 01621 ast_copy_string(cur->state_exten, exten, sizeof(cur->state_exten)); 01622 ast_copy_string(cur->state_context, S_OR(context, "default"), sizeof(cur->state_context)); 01623 } 01624 cur->status = get_queue_member_status(cur); 01625 } 01626 01627 return cur; 01628 }
static void destroy_queue | ( | void * | obj | ) | [static] |
Free queue's member list then its string fields.
Definition at line 2155 of file app_queue.c.
References ao2_ref, ast_string_field_free_memory, free, free_members(), MAX_PERIODIC_ANNOUNCEMENTS, call_queue::members, and call_queue::sound_periodicannounce.
Referenced by alloc_queue().
02156 { 02157 struct call_queue *q = obj; 02158 int i; 02159 02160 free_members(q, 1); 02161 ast_string_field_free_memory(q); 02162 for (i = 0; i < MAX_PERIODIC_ANNOUNCEMENTS; i++) { 02163 if (q->sound_periodicannounce[i]) 02164 free(q->sound_periodicannounce[i]); 02165 } 02166 ao2_ref(q->members, -1); 02167 }
static void device_state_cb | ( | const struct ast_event * | event, | |
void * | unused | |||
) | [static] |
Definition at line 1497 of file app_queue.c.
References ast_calloc, ast_device_state(), ast_event_get_ie_str(), ast_event_get_ie_uint(), AST_EVENT_IE_DEVICE, AST_EVENT_IE_STATE, ast_free, ast_log(), ast_strlen_zero(), ast_taskprocessor_push(), statechange::dev, devicestate_tps, handle_statechange(), LOG_ERROR, and statechange::state.
Referenced by load_module(), and load_pbx().
01498 { 01499 enum ast_device_state state; 01500 const char *device; 01501 struct statechange *sc; 01502 size_t datapsize; 01503 01504 state = ast_event_get_ie_uint(event, AST_EVENT_IE_STATE); 01505 device = ast_event_get_ie_str(event, AST_EVENT_IE_DEVICE); 01506 01507 if (ast_strlen_zero(device)) { 01508 ast_log(LOG_ERROR, "Received invalid event that had no device IE\n"); 01509 return; 01510 } 01511 datapsize = sizeof(*sc) + strlen(device) + 1; 01512 if (!(sc = ast_calloc(1, datapsize))) { 01513 ast_log(LOG_ERROR, "failed to calloc a state change struct\n"); 01514 return; 01515 } 01516 sc->state = state; 01517 strcpy(sc->dev, device); 01518 if (ast_taskprocessor_push(devicestate_tps, handle_statechange, sc) < 0) { 01519 ast_free(sc); 01520 } 01521 }
static void do_hang | ( | struct callattempt * | o | ) | [static] |
common hangup actions
Definition at line 2941 of file app_queue.c.
References ast_hangup(), callattempt::chan, and callattempt::stillgoing.
Referenced by ring_entry().
02942 { 02943 o->stillgoing = 0; 02944 ast_hangup(o->chan); 02945 o->chan = NULL; 02946 }
static void do_print | ( | struct mansession * | s, | |
int | fd, | |||
const char * | str | |||
) | [static] |
direct ouput to manager or cli with proper terminator
Definition at line 6876 of file app_queue.c.
References ast_cli(), and astman_append().
Referenced by __queues_show().
06877 { 06878 if (s) 06879 astman_append(s, "%s\r\n", str); 06880 else 06881 ast_cli(fd, "%s\n", str); 06882 }
static void dump_queue_members | ( | struct call_queue * | pm_queue | ) | [static] |
Dump all members in a specific queue to the database.
<pm_family>/<queuename> = <interface>;<penalty>;<paused>;<state_interface>[|...]
Definition at line 5111 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, member::state_interface, and value.
Referenced by add_to_queue(), remove_from_queue(), and set_member_paused().
05112 { 05113 struct member *cur_member; 05114 char value[PM_MAX_LEN]; 05115 int value_len = 0; 05116 int res; 05117 struct ao2_iterator mem_iter; 05118 05119 memset(value, 0, sizeof(value)); 05120 05121 if (!pm_queue) 05122 return; 05123 05124 mem_iter = ao2_iterator_init(pm_queue->members, 0); 05125 while ((cur_member = ao2_iterator_next(&mem_iter))) { 05126 if (!cur_member->dynamic) { 05127 ao2_ref(cur_member, -1); 05128 continue; 05129 } 05130 05131 res = snprintf(value + value_len, sizeof(value) - value_len, "%s%s;%d;%d;%s;%s", 05132 value_len ? "|" : "", cur_member->interface, cur_member->penalty, cur_member->paused, cur_member->membername, cur_member->state_interface); 05133 05134 ao2_ref(cur_member, -1); 05135 05136 if (res != strlen(value + value_len)) { 05137 ast_log(LOG_WARNING, "Could not create persistent member string, out of space\n"); 05138 break; 05139 } 05140 value_len += res; 05141 } 05142 ao2_iterator_destroy(&mem_iter); 05143 05144 if (value_len && !cur_member) { 05145 if (ast_db_put(pm_family, pm_queue->name, value)) 05146 ast_log(LOG_WARNING, "failed to create persistent dynamic entry!\n"); 05147 } else 05148 /* Delete the entry if the queue is empty or there is an error */ 05149 ast_db_del(pm_family, pm_queue->name); 05150 }
static void end_bridge_callback | ( | void * | data | ) | [static] |
Definition at line 4260 of file app_queue.c.
References ao2_ref, queue_end_bridge::chan, queue_end_bridge::q, queue_t_unref, and set_queue_variables().
04261 { 04262 struct queue_end_bridge *qeb = data; 04263 struct call_queue *q = qeb->q; 04264 struct ast_channel *chan = qeb->chan; 04265 04266 if (ao2_ref(qeb, -1) == 1) { 04267 set_queue_variables(q, chan); 04268 /* This unrefs the reference we made in try_calling when we allocated qeb */ 04269 queue_t_unref(q, "Expire bridge_config reference"); 04270 } 04271 }
static void end_bridge_callback_data_fixup | ( | struct ast_bridge_config * | bconfig, | |
struct ast_channel * | originator, | |||
struct ast_channel * | terminator | |||
) | [static] |
Definition at line 4253 of file app_queue.c.
References ao2_ref, queue_end_bridge::chan, and ast_bridge_config::end_bridge_callback_data.
04254 { 04255 struct queue_end_bridge *qeb = bconfig->end_bridge_callback_data; 04256 ao2_ref(qeb, +1); 04257 qeb->chan = originator; 04258 }
static int extension_state_cb | ( | char * | context, | |
char * | exten, | |||
enum ast_extension_states | state, | |||
void * | data | |||
) | [static] |
Definition at line 1555 of file app_queue.c.
References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_lock, ao2_ref, ao2_t_iterator_next, ao2_unlock, ast_debug, ast_devstate2str(), extensionstate2devicestate(), call_queue::found, call_queue::members, queue_t_unref, queues, member::state_context, member::state_exten, and update_status().
Referenced by load_module(), and unload_module().
01556 { 01557 struct ao2_iterator miter, qiter; 01558 struct member *m; 01559 struct call_queue *q; 01560 int found = 0, device_state = extensionstate2devicestate(state); 01561 01562 qiter = ao2_iterator_init(queues, 0); 01563 while ((q = ao2_t_iterator_next(&qiter, "Iterate through queues"))) { 01564 ao2_lock(q); 01565 01566 miter = ao2_iterator_init(q->members, 0); 01567 for (; (m = ao2_iterator_next(&miter)); ao2_ref(m, -1)) { 01568 if (!strcmp(m->state_context, context) && !strcmp(m->state_exten, exten)) { 01569 update_status(q, m, device_state); 01570 ao2_ref(m, -1); 01571 found = 1; 01572 break; 01573 } 01574 } 01575 ao2_iterator_destroy(&miter); 01576 01577 ao2_unlock(q); 01578 queue_t_unref(q, "Done with iterator"); 01579 } 01580 ao2_iterator_destroy(&qiter); 01581 01582 if (found) { 01583 ast_debug(1, "Extension '%s@%s' changed to state '%d' (%s)\n", exten, context, device_state, ast_devstate2str(device_state)); 01584 } else { 01585 ast_debug(3, "Extension '%s@%s' changed to state '%d' (%s) but we don't care because they're not a member of any queue.\n", 01586 exten, context, device_state, ast_devstate2str(device_state)); 01587 } 01588 01589 return 0; 01590 }
static int extensionstate2devicestate | ( | int | state | ) | [static] |
Helper function which converts from extension state to device state values.
Definition at line 1524 of file app_queue.c.
References AST_DEVICE_BUSY, AST_DEVICE_INUSE, AST_DEVICE_INVALID, AST_DEVICE_NOT_INUSE, AST_DEVICE_ONHOLD, AST_DEVICE_RINGING, AST_DEVICE_UNAVAILABLE, AST_EXTENSION_BUSY, AST_EXTENSION_DEACTIVATED, AST_EXTENSION_INUSE, AST_EXTENSION_NOT_INUSE, AST_EXTENSION_ONHOLD, AST_EXTENSION_REMOVED, AST_EXTENSION_RINGING, and AST_EXTENSION_UNAVAILABLE.
Referenced by extension_state_cb(), and get_queue_member_status().
01525 { 01526 switch (state) { 01527 case AST_EXTENSION_NOT_INUSE: 01528 state = AST_DEVICE_NOT_INUSE; 01529 break; 01530 case AST_EXTENSION_INUSE: 01531 state = AST_DEVICE_INUSE; 01532 break; 01533 case AST_EXTENSION_BUSY: 01534 state = AST_DEVICE_BUSY; 01535 break; 01536 case AST_EXTENSION_RINGING: 01537 state = AST_DEVICE_RINGING; 01538 break; 01539 case AST_EXTENSION_ONHOLD: 01540 state = AST_DEVICE_ONHOLD; 01541 break; 01542 case AST_EXTENSION_UNAVAILABLE: 01543 state = AST_DEVICE_UNAVAILABLE; 01544 break; 01545 case AST_EXTENSION_REMOVED: 01546 case AST_EXTENSION_DEACTIVATED: 01547 default: 01548 state = AST_DEVICE_INVALID; 01549 break; 01550 } 01551 01552 return state; 01553 }
static struct callattempt* find_best | ( | struct callattempt * | outgoing | ) | [static] |
find the entry with the best metric, or NULL
Definition at line 3175 of file app_queue.c.
References callattempt::metric, and callattempt::q_next.
Referenced by ast_cli_command_full(), ring_one(), store_next_lin(), and store_next_rr().
03176 { 03177 struct callattempt *best = NULL, *cur; 03178 03179 for (cur = outgoing; cur; cur = cur->q_next) { 03180 if (cur->stillgoing && /* Not already done */ 03181 !cur->chan && /* Isn't already going */ 03182 (!best || cur->metric < best->metric)) { /* We haven't found one yet, or it's better */ 03183 best = cur; 03184 } 03185 } 03186 03187 return best; 03188 }
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.
Check for statically defined queue first, check if deleted RT queue, check for new RT queue, if queue vars are not defined init them with defaults. reload RT queue vars, set RT queue members dead and reload them, return finished queue.
the | queue, | |
NULL | if it doesn't exist. |
Definition at line 2193 of file app_queue.c.
References alloc_queue(), ao2_lock, ao2_t_find, ao2_unlock, ast_debug, ast_log(), clear_queue(), call_queue::dead, LOG_WARNING, call_queue::membercount, ast_variable::name, call_queue::name, ast_variable::next, OBJ_POINTER, QUEUE_STRATEGY_RINGALL, queue_t_unref, queues, queues_t_unlink, call_queue::realtime, strat2int(), call_queue::strategy, and ast_variable::value.
Referenced by load_realtime_queue().
02194 { 02195 struct ast_variable *v; 02196 struct call_queue *q, tmpq = { 02197 .name = queuename, 02198 }; 02199 struct member *m; 02200 struct ao2_iterator mem_iter; 02201 char *interface = NULL; 02202 const char *tmp_name; 02203 char *tmp; 02204 char tmpbuf[64]; /* Must be longer than the longest queue param name. */ 02205 02206 /* Static queues override realtime. */ 02207 if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Check if static queue exists"))) { 02208 ao2_lock(q); 02209 if (!q->realtime) { 02210 if (q->dead) { 02211 ao2_unlock(q); 02212 queue_t_unref(q, "Queue is dead; can't return it"); 02213 return NULL; 02214 } else { 02215 ast_log(LOG_WARNING, "Static queue '%s' already exists. Not loading from realtime\n", q->name); 02216 ao2_unlock(q); 02217 return q; 02218 } 02219 } 02220 } else if (!member_config) 02221 /* Not found in the list, and it's not realtime ... */ 02222 return NULL; 02223 02224 /* Check if queue is defined in realtime. */ 02225 if (!queue_vars) { 02226 /* Delete queue from in-core list if it has been deleted in realtime. */ 02227 if (q) { 02228 /*! \note Hmm, can't seem to distinguish a DB failure from a not 02229 found condition... So we might delete an in-core queue 02230 in case of DB failure. */ 02231 ast_debug(1, "Queue %s not found in realtime.\n", queuename); 02232 02233 q->dead = 1; 02234 /* Delete if unused (else will be deleted when last caller leaves). */ 02235 queues_t_unlink(queues, q, "Unused; removing from container"); 02236 ao2_unlock(q); 02237 queue_t_unref(q, "Queue is dead; can't return it"); 02238 } 02239 return NULL; 02240 } 02241 02242 /* Create a new queue if an in-core entry does not exist yet. */ 02243 if (!q) { 02244 struct ast_variable *tmpvar = NULL; 02245 if (!(q = alloc_queue(queuename))) 02246 return NULL; 02247 ao2_lock(q); 02248 clear_queue(q); 02249 q->realtime = 1; 02250 q->membercount = 0; 02251 /*Before we initialize the queue, we need to set the strategy, so that linear strategy 02252 * will allocate the members properly 02253 */ 02254 for (tmpvar = queue_vars; tmpvar; tmpvar = tmpvar->next) { 02255 if (!strcasecmp(tmpvar->name, "strategy")) { 02256 q->strategy = strat2int(tmpvar->value); 02257 if (q->strategy < 0) { 02258 ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n", 02259 tmpvar->value, q->name); 02260 q->strategy = QUEUE_STRATEGY_RINGALL; 02261 } 02262 break; 02263 } 02264 } 02265 /* We traversed all variables and didn't find a strategy */ 02266 if (!tmpvar) 02267 q->strategy = QUEUE_STRATEGY_RINGALL; 02268 queues_t_link(queues, q, "Add queue to container"); 02269 } 02270 init_queue(q); /* Ensure defaults for all parameters not set explicitly. */ 02271 02272 memset(tmpbuf, 0, sizeof(tmpbuf)); 02273 for (v = queue_vars; v; v = v->next) { 02274 /* Convert to dashes `-' from underscores `_' as the latter are more SQL friendly. */ 02275 if ((tmp = strchr(v->name, '_'))) { 02276 ast_copy_string(tmpbuf, v->name, sizeof(tmpbuf)); 02277 tmp_name = tmpbuf; 02278 tmp = tmpbuf; 02279 while ((tmp = strchr(tmp, '_'))) 02280 *tmp++ = '-'; 02281 } else 02282 tmp_name = v->name; 02283 02284 /* NULL values don't get returned from realtime; blank values should 02285 * still get set. If someone doesn't want a value to be set, they 02286 * should set the realtime column to NULL, not blank. */ 02287 queue_set_param(q, tmp_name, v->value, -1, 0); 02288 } 02289 02290 /* Temporarily set realtime members dead so we can detect deleted ones. 02291 * Also set the membercount correctly for realtime*/ 02292 mem_iter = ao2_iterator_init(q->members, 0); 02293 while ((m = ao2_iterator_next(&mem_iter))) { 02294 q->membercount++; 02295 if (m->realtime) 02296 m->dead = 1; 02297 ao2_ref(m, -1); 02298 } 02299 ao2_iterator_destroy(&mem_iter); 02300 02301 while ((interface = ast_category_browse(member_config, interface))) { 02302 rt_handle_member_record(q, interface, 02303 ast_variable_retrieve(member_config, interface, "uniqueid"), 02304 S_OR(ast_variable_retrieve(member_config, interface, "membername"),interface), 02305 ast_variable_retrieve(member_config, interface, "penalty"), 02306 ast_variable_retrieve(member_config, interface, "paused"), 02307 S_OR(ast_variable_retrieve(member_config, interface, "state_interface"),interface)); 02308 } 02309 02310 /* Delete all realtime members that have been deleted in DB. */ 02311 mem_iter = ao2_iterator_init(q->members, 0); 02312 while ((m = ao2_iterator_next(&mem_iter))) { 02313 if (m->dead) { 02314 ast_queue_log(q->name, "REALTIME", m->interface, "REMOVEMEMBER", "%s", ""); 02315 ao2_unlink(q->members, m); 02316 q->membercount--; 02317 } 02318 ao2_ref(m, -1); 02319 } 02320 ao2_iterator_destroy(&mem_iter); 02321 02322 ao2_unlock(q); 02323 02324 return q; 02325 }
static void free_members | ( | struct call_queue * | q, | |
int | all | |||
) | [static] |
Iterate through queue's member list and delete them.
Definition at line 2138 of file app_queue.c.
References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_ref, ao2_unlink, member::dynamic, call_queue::membercount, and call_queue::members.
Referenced by destroy_queue().
02139 { 02140 /* Free non-dynamic members */ 02141 struct member *cur; 02142 struct ao2_iterator mem_iter = ao2_iterator_init(q->members, 0); 02143 02144 while ((cur = ao2_iterator_next(&mem_iter))) { 02145 if (all || !cur->dynamic) { 02146 ao2_unlink(q->members, cur); 02147 q->membercount--; 02148 } 02149 ao2_ref(cur, -1); 02150 } 02151 ao2_iterator_destroy(&mem_iter); 02152 }
static int get_member_penalty | ( | char * | queuename, | |
char * | interface | |||
) | [static] |
Definition at line 5391 of file app_queue.c.
References ao2_lock, ao2_ref, ao2_t_find, ao2_unlock, ast_log(), interface_exists(), LOG_ERROR, OBJ_POINTER, member::penalty, queue_t_unref, and RESULT_FAILURE.
Referenced by queue_function_memberpenalty_read().
05392 { 05393 int foundqueue = 0, penalty; 05394 struct call_queue *q, tmpq = { 05395 .name = queuename, 05396 }; 05397 struct member *mem; 05398 05399 if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Search for queue"))) { 05400 foundqueue = 1; 05401 ao2_lock(q); 05402 if ((mem = interface_exists(q, interface))) { 05403 penalty = mem->penalty; 05404 ao2_ref(mem, -1); 05405 ao2_unlock(q); 05406 queue_t_unref(q, "Search complete"); 05407 return penalty; 05408 } 05409 ao2_unlock(q); 05410 queue_t_unref(q, "Search complete"); 05411 } 05412 05413 /* some useful debuging */ 05414 if (foundqueue) 05415 ast_log (LOG_ERROR, "Invalid queuename\n"); 05416 else 05417 ast_log (LOG_ERROR, "Invalid interface\n"); 05418 05419 return RESULT_FAILURE; 05420 }
static int get_member_status | ( | struct call_queue * | q, | |
int | max_penalty, | |||
int | min_penalty, | |||
enum empty_conditions | conditions | |||
) | [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 0. If no members are available, then -1 is returned.
Definition at line 1347 of file app_queue.c.
References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_lock, ao2_ref, ao2_unlock, ast_debug, AST_DEVICE_INUSE, AST_DEVICE_INVALID, AST_DEVICE_RINGING, AST_DEVICE_UNAVAILABLE, AST_DEVICE_UNKNOWN, member::lastcall, member::membername, call_queue::members, member::paused, member::penalty, QUEUE_EMPTY_INUSE, QUEUE_EMPTY_INVALID, QUEUE_EMPTY_PAUSED, QUEUE_EMPTY_PENALTY, QUEUE_EMPTY_RINGING, QUEUE_EMPTY_UNAVAILABLE, QUEUE_EMPTY_UNKNOWN, QUEUE_EMPTY_WRAPUP, member::status, and call_queue::wrapuptime.
Referenced by join_queue(), queue_exec(), and wait_our_turn().
01348 { 01349 struct member *member; 01350 struct ao2_iterator mem_iter; 01351 01352 ao2_lock(q); 01353 mem_iter = ao2_iterator_init(q->members, 0); 01354 for (; (member = ao2_iterator_next(&mem_iter)); ao2_ref(member, -1)) { 01355 if ((max_penalty && (member->penalty > max_penalty)) || (min_penalty && (member->penalty < min_penalty))) { 01356 if (conditions & QUEUE_EMPTY_PENALTY) { 01357 ast_debug(4, "%s is unavailable because his penalty is not between %d and %d\n", member->membername, min_penalty, max_penalty); 01358 continue; 01359 } 01360 } 01361 01362 switch (member->status) { 01363 case AST_DEVICE_INVALID: 01364 if (conditions & QUEUE_EMPTY_INVALID) { 01365 ast_debug(4, "%s is unavailable because his device state is 'invalid'\n", member->membername); 01366 break; 01367 } 01368 goto default_case; 01369 case AST_DEVICE_UNAVAILABLE: 01370 if (conditions & QUEUE_EMPTY_UNAVAILABLE) { 01371 ast_debug(4, "%s is unavailable because his device state is 'unavailable'\n", member->membername); 01372 break; 01373 } 01374 goto default_case; 01375 case AST_DEVICE_INUSE: 01376 if (conditions & QUEUE_EMPTY_INUSE) { 01377 ast_debug(4, "%s is unavailable because his device state is 'inuse'\n", member->membername); 01378 break; 01379 } 01380 goto default_case; 01381 case AST_DEVICE_RINGING: 01382 if (conditions & QUEUE_EMPTY_RINGING) { 01383 ast_debug(4, "%s is unavailable because his device state is 'ringing'\n", member->membername); 01384 break; 01385 } 01386 goto default_case; 01387 case AST_DEVICE_UNKNOWN: 01388 if (conditions & QUEUE_EMPTY_UNKNOWN) { 01389 ast_debug(4, "%s is unavailable because his device state is 'unknown'\n", member->membername); 01390 break; 01391 } 01392 /* Fall-through */ 01393 default: 01394 default_case: 01395 if (member->paused && (conditions & QUEUE_EMPTY_PAUSED)) { 01396 ast_debug(4, "%s is unavailable because he is paused'\n", member->membername); 01397 break; 01398 } else if ((conditions & QUEUE_EMPTY_WRAPUP) && member->lastcall && q->wrapuptime && (time(NULL) - q->wrapuptime < member->lastcall)) { 01399 ast_debug(4, "%s is unavailable because it has only been %d seconds since his last call (wrapup time is %d)\n", member->membername, (int) (time(NULL) - member->lastcall), q->wrapuptime); 01400 break; 01401 } else { 01402 ao2_unlock(q); 01403 ao2_ref(member, -1); 01404 ao2_iterator_destroy(&mem_iter); 01405 ast_debug(4, "%s is available.\n", member->membername); 01406 return 0; 01407 } 01408 break; 01409 } 01410 } 01411 ao2_iterator_destroy(&mem_iter); 01412 01413 ao2_unlock(q); 01414 return -1; 01415 }
static int get_queue_member_status | ( | struct member * | cur | ) | [static] |
Return the current state of a member.
Definition at line 1593 of file app_queue.c.
References ast_device_state(), ast_extension_state(), ast_strlen_zero(), extensionstate2devicestate(), member::state_context, member::state_exten, and member::state_interface.
Referenced by create_queue_member(), kill_dead_members(), and ring_entry().
01594 { 01595 return ast_strlen_zero(cur->state_exten) ? ast_device_state(cur->state_interface) : extensionstate2devicestate(ast_extension_state(NULL, cur->state_context, cur->state_exten)); 01596 }
static char* handle_queue_add_member | ( | struct ast_cli_entry * | e, | |
int | cmd, | |||
struct ast_cli_args * | a | |||
) | [static] |
Definition at line 7506 of file app_queue.c.
References add_to_queue(), ast_cli_args::argc, ast_cli_args::argv, ast_cli(), ast_queue_log(), CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, complete_queue_add_member(), ast_cli_args::fd, ast_cli_args::line, ast_cli_args::n, ast_cli_args::pos, RES_EXISTS, RES_NOSUCHQUEUE, RES_NOT_DYNAMIC, RES_OKAY, RES_OUTOFMEMORY, ast_cli_entry::usage, and ast_cli_args::word.
07507 { 07508 const char *queuename, *interface, *membername = NULL, *state_interface = NULL; 07509 int penalty; 07510 07511 switch ( cmd ) { 07512 case CLI_INIT: 07513 e->command = "queue add member"; 07514 e->usage = 07515 "Usage: queue add member <channel> to <queue> [[[penalty <penalty>] as <membername>] state_interface <interface>]\n" 07516 " Add a channel to a queue with optionally: a penalty, membername and a state_interface\n"; 07517 return NULL; 07518 case CLI_GENERATE: 07519 return complete_queue_add_member(a->line, a->word, a->pos, a->n); 07520 } 07521 07522 if ((a->argc != 6) && (a->argc != 8) && (a->argc != 10) && (a->argc != 12)) { 07523 return CLI_SHOWUSAGE; 07524 } else if (strcmp(a->argv[4], "to")) { 07525 return CLI_SHOWUSAGE; 07526 } else if ((a->argc >= 8) && strcmp(a->argv[6], "penalty")) { 07527 return CLI_SHOWUSAGE; 07528 } else if ((a->argc >= 10) && strcmp(a->argv[8], "as")) { 07529 return CLI_SHOWUSAGE; 07530 } else if ((a->argc == 12) && strcmp(a->argv[10], "state_interface")) { 07531 return CLI_SHOWUSAGE; 07532 } 07533 07534 queuename = a->argv[5]; 07535 interface = a->argv[3]; 07536 if (a->argc >= 8) { 07537 if (sscanf(a->argv[7], "%30d", &penalty) == 1) { 07538 if (penalty < 0) { 07539 ast_cli(a->fd, "Penalty must be >= 0\n"); 07540 penalty = 0; 07541 } 07542 } else { 07543 ast_cli(a->fd, "Penalty must be an integer >= 0\n"); 07544 penalty = 0; 07545 } 07546 } else { 07547 penalty = 0; 07548 } 07549 07550 if (a->argc >= 10) { 07551 membername = a->argv[9]; 07552 } 07553 07554 if (a->argc >= 12) { 07555 state_interface = a->argv[11]; 07556 } 07557 07558 switch (add_to_queue(queuename, interface, membername, penalty, 0, queue_persistent_members, state_interface)) { 07559 case RES_OKAY: 07560 ast_queue_log(queuename, "CLI", interface, "ADDMEMBER", "%s", ""); 07561 ast_cli(a->fd, "Added interface '%s' to queue '%s'\n", interface, queuename); 07562 return CLI_SUCCESS; 07563 case RES_EXISTS: 07564 ast_cli(a->fd, "Unable to add interface '%s' to queue '%s': Already there\n", interface, queuename); 07565 return CLI_FAILURE; 07566 case RES_NOSUCHQUEUE: 07567 ast_cli(a->fd, "Unable to add interface to queue '%s': No such queue\n", queuename); 07568 return CLI_FAILURE; 07569 case RES_OUTOFMEMORY: 07570 ast_cli(a->fd, "Out of memory\n"); 07571 return CLI_FAILURE; 07572 case RES_NOT_DYNAMIC: 07573 ast_cli(a->fd, "Member not dynamic\n"); 07574 return CLI_FAILURE; 07575 default: 07576 return CLI_FAILURE; 07577 } 07578 }
static char* handle_queue_pause_member | ( | struct ast_cli_entry * | e, | |
int | cmd, | |||
struct ast_cli_args * | a | |||
) | [static] |
Definition at line 7690 of file app_queue.c.
References ast_cli_args::argc, ast_cli_args::argv, ast_cli(), ast_strlen_zero(), CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, complete_queue_pause_member(), ast_cli_args::fd, ast_cli_args::line, ast_cli_args::n, ast_cli_args::pos, RESULT_SUCCESS, set_member_paused(), ast_cli_entry::usage, and word.
07691 { 07692 const char *queuename, *interface, *reason; 07693 int paused; 07694 07695 switch (cmd) { 07696 case CLI_INIT: 07697 e->command = "queue {pause|unpause} member"; 07698 e->usage = 07699 "Usage: queue {pause|unpause} member <member> [queue <queue> [reason <reason>]]\n" 07700 " Pause or unpause a queue member. Not specifying a particular queue\n" 07701 " will pause or unpause a member across all queues to which the member\n" 07702 " belongs.\n"; 07703 return NULL; 07704 case CLI_GENERATE: 07705 return complete_queue_pause_member(a->line, a-> word, a->pos, a->n); 07706 } 07707 07708 if (a->argc < 4 || a->argc == 5 || a->argc == 7 || a->argc > 8) { 07709 return CLI_SHOWUSAGE; 07710 } else if (a->argc >= 5 && strcmp(a->argv[4], "queue")) { 07711 return CLI_SHOWUSAGE; 07712 } else if (a->argc == 8 && strcmp(a->argv[6], "reason")) { 07713 return CLI_SHOWUSAGE; 07714 } 07715 07716 07717 interface = a->argv[3]; 07718 queuename = a->argc >= 6 ? a->argv[5] : NULL; 07719 reason = a->argc == 8 ? a->argv[7] : NULL; 07720 paused = !strcasecmp(a->argv[1], "pause"); 07721 07722 if (set_member_paused(queuename, interface, reason, paused) == RESULT_SUCCESS) { 07723 ast_cli(a->fd, "%spaused interface '%s'", paused ? "" : "un", interface); 07724 if (!ast_strlen_zero(queuename)) 07725 ast_cli(a->fd, " in queue '%s'", queuename); 07726 if (!ast_strlen_zero(reason)) 07727 ast_cli(a->fd, " for reason '%s'", reason); 07728 ast_cli(a->fd, "\n"); 07729 return CLI_SUCCESS; 07730 } else { 07731 ast_cli(a->fd, "Unable to %spause interface '%s'", paused ? "" : "un", interface); 07732 if (!ast_strlen_zero(queuename)) 07733 ast_cli(a->fd, " in queue '%s'", queuename); 07734 if (!ast_strlen_zero(reason)) 07735 ast_cli(a->fd, " for reason '%s'", reason); 07736 ast_cli(a->fd, "\n"); 07737 return CLI_FAILURE; 07738 } 07739 }
static char* handle_queue_reload | ( | struct ast_cli_entry * | e, | |
int | cmd, | |||
struct ast_cli_args * | a | |||
) | [static] |
Definition at line 7899 of file app_queue.c.
References ast_cli_args::argc, ast_cli_args::argv, AST_FLAGS_ALL, ast_set_flag, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, complete_queue(), ast_cli_args::line, ast_cli_args::n, ast_cli_args::pos, QUEUE_RELOAD_MEMBER, QUEUE_RELOAD_PARAMETERS, QUEUE_RELOAD_RULES, reload_handler(), ast_cli_entry::usage, and ast_cli_args::word.
07900 { 07901 struct ast_flags mask = {0,}; 07902 int i; 07903 07904 switch (cmd) { 07905 case CLI_INIT: 07906 e->command = "queue reload {parameters|members|rules|all}"; 07907 e->usage = 07908 "Usage: queue reload {parameters|members|rules|all} [<queuenames>]\n" 07909 "Reload queues. If <queuenames> are specified, only reload information pertaining\n" 07910 "to <queuenames>. One of 'parameters,' 'members,' 'rules,' or 'all' must be\n" 07911 "specified in order to know what information to reload. Below is an explanation\n" 07912 "of each of these qualifiers.\n" 07913 "\n" 07914 "\t'members' - reload queue members from queues.conf\n" 07915 "\t'parameters' - reload all queue options except for queue members\n" 07916 "\t'rules' - reload the queuerules.conf file\n" 07917 "\t'all' - reload queue rules, parameters, and members\n" 07918 "\n" 07919 "Note: the 'rules' qualifier here cannot actually be applied to a specific queue.\n" 07920 "Use of the 'rules' qualifier causes queuerules.conf to be reloaded. Even if only\n" 07921 "one queue is specified when using this command, reloading queue rules may cause\n" 07922 "other queues to be affected\n"; 07923 return NULL; 07924 case CLI_GENERATE: 07925 if (a->pos >= 3) { 07926 return complete_queue(a->line, a->word, a->pos, a->n); 07927 } else { 07928 return NULL; 07929 } 07930 } 07931 07932 if (a->argc < 3) 07933 return CLI_SHOWUSAGE; 07934 07935 if (!strcasecmp(a->argv[2], "rules")) { 07936 ast_set_flag(&mask, QUEUE_RELOAD_RULES); 07937 } else if (!strcasecmp(a->argv[2], "members")) { 07938 ast_set_flag(&mask, QUEUE_RELOAD_MEMBER); 07939 } else if (!strcasecmp(a->argv[2], "parameters")) { 07940 ast_set_flag(&mask, QUEUE_RELOAD_PARAMETERS); 07941 } else if (!strcasecmp(a->argv[2], "all")) { 07942 ast_set_flag(&mask, AST_FLAGS_ALL); 07943 } 07944 07945 if (a->argc == 3) { 07946 reload_handler(1, &mask, NULL); 07947 return CLI_SUCCESS; 07948 } 07949 07950 for (i = 3; i < a->argc; ++i) { 07951 reload_handler(1, &mask, a->argv[i]); 07952 } 07953 07954 return CLI_SUCCESS; 07955 }
static char* handle_queue_remove_member | ( | struct ast_cli_entry * | e, | |
int | cmd, | |||
struct ast_cli_args * | a | |||
) | [static] |
Definition at line 7625 of file app_queue.c.
References ast_cli_args::argc, ast_cli_args::argv, ast_cli(), ast_queue_log(), CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, complete_queue_remove_member(), ast_cli_args::fd, ast_cli_args::line, ast_cli_args::n, ast_cli_args::pos, remove_from_queue(), RES_EXISTS, RES_NOSUCHQUEUE, RES_NOT_DYNAMIC, RES_OKAY, RES_OUTOFMEMORY, ast_cli_entry::usage, and ast_cli_args::word.
07626 { 07627 const char *queuename, *interface; 07628 07629 switch (cmd) { 07630 case CLI_INIT: 07631 e->command = "queue remove member"; 07632 e->usage = 07633 "Usage: queue remove member <channel> from <queue>\n" 07634 " Remove a specific channel from a queue.\n"; 07635 return NULL; 07636 case CLI_GENERATE: 07637 return complete_queue_remove_member(a->line, a->word, a->pos, a->n); 07638 } 07639 07640 if (a->argc != 6) { 07641 return CLI_SHOWUSAGE; 07642 } else if (strcmp(a->argv[4], "from")) { 07643 return CLI_SHOWUSAGE; 07644 } 07645 07646 queuename = a->argv[5]; 07647 interface = a->argv[3]; 07648 07649 switch (remove_from_queue(queuename, interface)) { 07650 case RES_OKAY: 07651 ast_queue_log(queuename, "CLI", interface, "REMOVEMEMBER", "%s", ""); 07652 ast_cli(a->fd, "Removed interface '%s' from queue '%s'\n", interface, queuename); 07653 return CLI_SUCCESS; 07654 case RES_EXISTS: 07655 ast_cli(a->fd, "Unable to remove interface '%s' from queue '%s': Not there\n", interface, queuename); 07656 return CLI_FAILURE; 07657 case RES_NOSUCHQUEUE: 07658 ast_cli(a->fd, "Unable to remove interface from queue '%s': No such queue\n", queuename); 07659 return CLI_FAILURE; 07660 case RES_OUTOFMEMORY: 07661 ast_cli(a->fd, "Out of memory\n"); 07662 return CLI_FAILURE; 07663 case RES_NOT_DYNAMIC: 07664 ast_cli(a->fd, "Unable to remove interface '%s' from queue '%s': Member is not dynamic\n", interface, queuename); 07665 return CLI_FAILURE; 07666 default: 07667 return CLI_FAILURE; 07668 } 07669 }
static char* handle_queue_reset | ( | struct ast_cli_entry * | e, | |
int | cmd, | |||
struct ast_cli_args * | a | |||
) | [static] |
Definition at line 7860 of file app_queue.c.
References ast_cli_args::argc, ast_cli_args::argv, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, complete_queue(), ast_cli_args::line, ast_cli_args::n, ast_cli_args::pos, QUEUE_RESET_STATS, reload_handler(), ast_cli_entry::usage, and ast_cli_args::word.
07861 { 07862 struct ast_flags mask = {QUEUE_RESET_STATS,}; 07863 int i; 07864 07865 switch (cmd) { 07866 case CLI_INIT: 07867 e->command = "queue reset stats"; 07868 e->usage = 07869 "Usage: queue reset stats [<queuenames>]\n" 07870 "\n" 07871 "Issuing this command will reset statistics for\n" 07872 "<queuenames>, or for all queues if no queue is\n" 07873 "specified.\n"; 07874 return NULL; 07875 case CLI_GENERATE: 07876 if (a->pos >= 3) { 07877 return complete_queue(a->line, a->word, a->pos, a->n); 07878 } else { 07879 return NULL; 07880 } 07881 } 07882 07883 if (a->argc < 3) { 07884 return CLI_SHOWUSAGE; 07885 } 07886 07887 if (a->argc == 3) { 07888 reload_handler(1, &mask, NULL); 07889 return CLI_SUCCESS; 07890 } 07891 07892 for (i = 3; i < a->argc; ++i) { 07893 reload_handler(1, &mask, a->argv[i]); 07894 } 07895 07896 return CLI_SUCCESS; 07897 }
static char* handle_queue_rule_show | ( | struct ast_cli_entry * | e, | |
int | cmd, | |||
struct ast_cli_args * | a | |||
) | [static] |
Definition at line 7826 of file app_queue.c.
References ast_cli_args::argc, ast_cli_args::argv, ast_cli(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_strlen_zero(), CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, complete_queue_rule_show(), ast_cli_args::fd, ast_cli_args::line, penalty_rule::list, penalty_rule::max_relative, penalty_rule::max_value, penalty_rule::min_relative, penalty_rule::min_value, ast_cli_args::n, rule_list::name, ast_cli_args::pos, rule_list::rules, penalty_rule::time, ast_cli_entry::usage, and ast_cli_args::word.
07827 { 07828 const char *rule; 07829 struct rule_list *rl_iter; 07830 struct penalty_rule *pr_iter; 07831 switch (cmd) { 07832 case CLI_INIT: 07833 e->command = "queue show rules"; 07834 e->usage = 07835 "Usage: queue show rules [rulename]\n" 07836 " Show the list of rules associated with rulename. If no\n" 07837 " rulename is specified, list all rules defined in queuerules.conf\n"; 07838 return NULL; 07839 case CLI_GENERATE: 07840 return complete_queue_rule_show(a->line, a->word, a->pos, a->n); 07841 } 07842 07843 if (a->argc != 3 && a->argc != 4) 07844 return CLI_SHOWUSAGE; 07845 07846 rule = a->argc == 4 ? a->argv[3] : ""; 07847 AST_LIST_LOCK(&rule_lists); 07848 AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) { 07849 if (ast_strlen_zero(rule) || !strcasecmp(rl_iter->name, rule)) { 07850 ast_cli(a->fd, "Rule: %s\n", rl_iter->name); 07851 AST_LIST_TRAVERSE(&rl_iter->rules, pr_iter, list) { 07852 ast_cli(a->fd, "\tAfter %d seconds, adjust QUEUE_MAX_PENALTY %s %d and adjust QUEUE_MIN_PENALTY %s %d\n", pr_iter->time, pr_iter->max_relative ? "by" : "to", pr_iter->max_value, pr_iter->min_relative ? "by" : "to", pr_iter->min_value); 07853 } 07854 } 07855 } 07856 AST_LIST_UNLOCK(&rule_lists); 07857 return CLI_SUCCESS; 07858 }
static char* handle_queue_set_member_penalty | ( | struct ast_cli_entry * | e, | |
int | cmd, | |||
struct ast_cli_args * | a | |||
) | [static] |
Definition at line 7764 of file app_queue.c.
References ast_cli_args::argc, ast_cli_args::argv, ast_cli(), CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, complete_queue_set_member_penalty(), ast_cli_args::fd, ast_cli_args::line, ast_cli_args::n, ast_cli_args::pos, RESULT_FAILURE, RESULT_SUCCESS, set_member_penalty(), ast_cli_entry::usage, and ast_cli_args::word.
07765 { 07766 const char *queuename = NULL, *interface; 07767 int penalty = 0; 07768 07769 switch (cmd) { 07770 case CLI_INIT: 07771 e->command = "queue set penalty"; 07772 e->usage = 07773 "Usage: queue set penalty <penalty> on <interface> [in <queue>]\n" 07774 " Set a member's penalty in the queue specified. If no queue is specified\n" 07775 " then that interface's penalty is set in all queues to which that interface is a member\n"; 07776 return NULL; 07777 case CLI_GENERATE: 07778 return complete_queue_set_member_penalty(a->line, a->word, a->pos, a->n); 07779 } 07780 07781 if (a->argc != 6 && a->argc != 8) { 07782 return CLI_SHOWUSAGE; 07783 } else if (strcmp(a->argv[4], "on") || (a->argc > 6 && strcmp(a->argv[6], "in"))) { 07784 return CLI_SHOWUSAGE; 07785 } 07786 07787 if (a->argc == 8) 07788 queuename = a->argv[7]; 07789 interface = a->argv[5]; 07790 penalty = atoi(a->argv[3]); 07791 07792 switch (set_member_penalty(queuename, interface, penalty)) { 07793 case RESULT_SUCCESS: 07794 ast_cli(a->fd, "Set penalty on interface '%s' from queue '%s'\n", interface, queuename); 07795 return CLI_SUCCESS; 07796 case RESULT_FAILURE: 07797 ast_cli(a->fd, "Failed to set penalty on interface '%s' from queue '%s'\n", interface, queuename); 07798 return CLI_FAILURE; 07799 default: 07800 return CLI_FAILURE; 07801 } 07802 }
static int handle_statechange | ( | void * | datap | ) | [static] |
set a member's status based on device state of that member's interface
Definition at line 1453 of file app_queue.c.
References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_lock, ao2_ref, ao2_t_iterator_next, ao2_unlock, ast_copy_string(), ast_debug, ast_devstate2str(), ast_free, statechange::dev, call_queue::found, call_queue::members, queue_t_unref, queues, statechange::state, member::state_interface, and update_status().
Referenced by device_state_cb().
01454 { 01455 struct statechange *sc = datap; 01456 struct ao2_iterator miter, qiter; 01457 struct member *m; 01458 struct call_queue *q; 01459 char interface[80], *slash_pos; 01460 int found = 0; 01461 01462 qiter = ao2_iterator_init(queues, 0); 01463 while ((q = ao2_t_iterator_next(&qiter, "Iterate over queues"))) { 01464 ao2_lock(q); 01465 01466 miter = ao2_iterator_init(q->members, 0); 01467 for (; (m = ao2_iterator_next(&miter)); ao2_ref(m, -1)) { 01468 ast_copy_string(interface, m->state_interface, sizeof(interface)); 01469 01470 if ((slash_pos = strchr(interface, '/'))) 01471 if (!strncasecmp(interface, "Local/", 6) && (slash_pos = strchr(slash_pos + 1, '/'))) 01472 *slash_pos = '\0'; 01473 01474 if (!strcasecmp(interface, sc->dev)) { 01475 found = 1; 01476 update_status(q, m, sc->state); 01477 ao2_ref(m, -1); 01478 break; 01479 } 01480 } 01481 ao2_iterator_destroy(&miter); 01482 01483 ao2_unlock(q); 01484 queue_t_unref(q, "Done with iterator"); 01485 } 01486 ao2_iterator_destroy(&qiter); 01487 01488 if (found) 01489 ast_debug(1, "Device '%s' changed to state '%d' (%s)\n", sc->dev, sc->state, ast_devstate2str(sc->state)); 01490 else 01491 ast_debug(3, "Device '%s' changed to state '%d' (%s) but we don't care because they're not a member of any queue.\n", sc->dev, sc->state, ast_devstate2str(sc->state)); 01492 01493 ast_free(sc); 01494 return 0; 01495 }
static void hangupcalls | ( | struct callattempt * | outgoing, | |
struct ast_channel * | exception, | |||
int | cancel_answered_elsewhere | |||
) | [static] |
Hang up a list of outgoing calls.
Definition at line 2834 of file app_queue.c.
References callattempt::aoc_s_rate_list, ast_aoc_destroy_decoded(), AST_FLAG_ANSWERED_ELSEWHERE, ast_hangup(), ast_set_flag, callattempt_free(), callattempt::chan, and callattempt::q_next.
02835 { 02836 struct callattempt *oo; 02837 02838 while (outgoing) { 02839 /* If someone else answered the call we should indicate this in the CANCEL */ 02840 /* Hangup any existing lines we have open */ 02841 if (outgoing->chan && (outgoing->chan != exception)) { 02842 if (exception || cancel_answered_elsewhere) 02843 ast_set_flag(outgoing->chan, AST_FLAG_ANSWERED_ELSEWHERE); 02844 ast_hangup(outgoing->chan); 02845 } 02846 oo = outgoing; 02847 outgoing = outgoing->q_next; 02848 ast_aoc_destroy_decoded(oo->aoc_s_rate_list); 02849 callattempt_free(oo); 02850 } 02851 }
static void init_queue | ( | struct call_queue * | q | ) | [static] |
Initialize Queue default values.
Definition at line 1663 of file app_queue.c.
References call_queue::announcefrequency, call_queue::announceholdtime, call_queue::announceposition, ANNOUNCEPOSITION_YES, call_queue::announcepositionlimit, ao2_container_alloc, ast_free, AST_LIST_REMOVE_HEAD, ast_str_create(), ast_str_set(), ast_string_field_set, call_queue::autofill, call_queue::autopause, call_queue::dead, DEFAULT_MIN_ANNOUNCE_FREQUENCY, DEFAULT_RETRY, DEFAULT_TIMEOUT, call_queue::eventwhencalled, call_queue::found, call_queue::joinempty, call_queue::leavewhenempty, penalty_rule::list, call_queue::maskmemberstatus, MAX_PERIODIC_ANNOUNCEMENTS, call_queue::maxlen, member_cmp_fn(), member_hash_fn(), call_queue::memberdelay, call_queue::members, call_queue::minannouncefrequency, call_queue::monfmt, call_queue::montype, call_queue::numperiodicannounce, call_queue::penaltymemberslimit, call_queue::periodicannouncefrequency, QUEUE_AUTOPAUSE_OFF, QUEUE_STRATEGY_LINEAR, QUEUE_STRATEGY_RRORDERED, call_queue::randomperiodicannounce, call_queue::reportholdtime, call_queue::retry, call_queue::ringinuse, call_queue::roundingseconds, call_queue::rules, call_queue::servicelevel, call_queue::setinterfacevar, call_queue::setqueueentryvar, call_queue::setqueuevar, call_queue::sound_periodicannounce, call_queue::strategy, call_queue::timeout, TIMEOUT_PRIORITY_APP, call_queue::timeoutpriority, call_queue::timeoutrestart, call_queue::weight, and call_queue::wrapuptime.
Referenced by reload_single_queue().
01664 { 01665 int i; 01666 struct penalty_rule *pr_iter; 01667 01668 q->dead = 0; 01669 q->retry = DEFAULT_RETRY; 01670 q->timeout = DEFAULT_TIMEOUT; 01671 q->maxlen = 0; 01672 q->announcefrequency = 0; 01673 q->minannouncefrequency = DEFAULT_MIN_ANNOUNCE_FREQUENCY; 01674 q->announceholdtime = 1; 01675 q->announcepositionlimit = 10; /* Default 10 positions */ 01676 q->announceposition = ANNOUNCEPOSITION_YES; /* Default yes */ 01677 q->roundingseconds = 0; /* Default - don't announce seconds */ 01678 q->servicelevel = 0; 01679 q->ringinuse = 1; 01680 q->setinterfacevar = 0; 01681 q->setqueuevar = 0; 01682 q->setqueueentryvar = 0; 01683 q->autofill = autofill_default; 01684 q->montype = montype_default; 01685 q->monfmt[0] = '\0'; 01686 q->reportholdtime = 0; 01687 q->wrapuptime = 0; 01688 q->penaltymemberslimit = 0; 01689 q->joinempty = 0; 01690 q->leavewhenempty = 0; 01691 q->memberdelay = 0; 01692 q->maskmemberstatus = 0; 01693 q->eventwhencalled = 0; 01694 q->weight = 0; 01695 q->timeoutrestart = 0; 01696 q->periodicannouncefrequency = 0; 01697 q->randomperiodicannounce = 0; 01698 q->numperiodicannounce = 0; 01699 q->autopause = QUEUE_AUTOPAUSE_OFF; 01700 q->timeoutpriority = TIMEOUT_PRIORITY_APP; 01701 if (!q->members) { 01702 if (q->strategy == QUEUE_STRATEGY_LINEAR || q->strategy == QUEUE_STRATEGY_RRORDERED) 01703 /* linear strategy depends on order, so we have to place all members in a single bucket */ 01704 q->members = ao2_container_alloc(1, member_hash_fn, member_cmp_fn); 01705 else 01706 q->members = ao2_container_alloc(37, member_hash_fn, member_cmp_fn); 01707 } 01708 q->found = 1; 01709 01710 ast_string_field_set(q, sound_next, "queue-youarenext"); 01711 ast_string_field_set(q, sound_thereare, "queue-thereare"); 01712 ast_string_field_set(q, sound_calls, "queue-callswaiting"); 01713 ast_string_field_set(q, queue_quantity1, "queue-quantity1"); 01714 ast_string_field_set(q, queue_quantity2, "queue-quantity2"); 01715 ast_string_field_set(q, sound_holdtime, "queue-holdtime"); 01716 ast_string_field_set(q, sound_minutes, "queue-minutes"); 01717 ast_string_field_set(q, sound_minute, "queue-minute"); 01718 ast_string_field_set(q, sound_seconds, "queue-seconds"); 01719 ast_string_field_set(q, sound_thanks, "queue-thankyou"); 01720 ast_string_field_set(q, sound_reporthold, "queue-reporthold"); 01721 01722 if ((q->sound_periodicannounce[0] = ast_str_create(32))) 01723 ast_str_set(&q->sound_periodicannounce[0], 0, "queue-periodic-announce"); 01724 01725 for (i = 1; i < MAX_PERIODIC_ANNOUNCEMENTS; i++) { 01726 if (q->sound_periodicannounce[i]) 01727 ast_str_set(&q->sound_periodicannounce[i], 0, "%s", ""); 01728 } 01729 01730 while ((pr_iter = AST_LIST_REMOVE_HEAD(&q->rules,list))) 01731 ast_free(pr_iter); 01732 }
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 1317 of file app_queue.c.
References call_queue::head, queue_ent::next, and queue_ref().
Referenced by join_queue().
01318 { 01319 struct queue_ent *cur; 01320 01321 if (!q || !new) 01322 return; 01323 if (prev) { 01324 cur = prev->next; 01325 prev->next = new; 01326 } else { 01327 cur = q->head; 01328 q->head = new; 01329 } 01330 new->next = cur; 01331 01332 /* every queue_ent must have a reference to it's parent call_queue, this 01333 * reference does not go away until the end of the queue_ent's life, meaning 01334 * that even when the queue_ent leaves the call_queue this ref must remain. */ 01335 queue_ref(q); 01336 new->parent = q; 01337 new->pos = ++(*pos); 01338 new->opos = *pos; 01339 }
static int insert_penaltychange | ( | const char * | list_name, | |
const char * | content, | |||
const int | linenum | |||
) | [static] |
Change queue penalty by adding rule.
Check rule for errors with time or fomatting, see if rule is relative to rest of queue, iterate list of rules to find correct insertion point, insert and return.
-1 | on failure | |
0 | on success |
Definition at line 1763 of file app_queue.c.
References ast_calloc, ast_free, AST_LIST_INSERT_BEFORE_CURRENT, AST_LIST_INSERT_TAIL, AST_LIST_TRAVERSE, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, ast_log(), ast_strdupa, ast_strlen_zero(), rule_list::list, LOG_WARNING, rule_list::name, and rule_list::rules.
Referenced by reload_queue_rules().
01764 { 01765 char *timestr, *maxstr, *minstr, *contentdup; 01766 struct penalty_rule *rule = NULL, *rule_iter; 01767 struct rule_list *rl_iter; 01768 int penaltychangetime, inserted = 0; 01769 01770 if (!(rule = ast_calloc(1, sizeof(*rule)))) { 01771 return -1; 01772 } 01773 01774 contentdup = ast_strdupa(content); 01775 01776 if (!(maxstr = strchr(contentdup, ','))) { 01777 ast_log(LOG_WARNING, "Improperly formatted penaltychange rule at line %d. Ignoring.\n", linenum); 01778 ast_free(rule); 01779 return -1; 01780 } 01781 01782 *maxstr++ = '\0'; 01783 timestr = contentdup; 01784 01785 if ((penaltychangetime = atoi(timestr)) < 0) { 01786 ast_log(LOG_WARNING, "Improper time parameter specified for penaltychange rule at line %d. Ignoring.\n", linenum); 01787 ast_free(rule); 01788 return -1; 01789 } 01790 01791 rule->time = penaltychangetime; 01792 01793 if ((minstr = strchr(maxstr,','))) 01794 *minstr++ = '\0'; 01795 01796 /* The last check will evaluate true if either no penalty change is indicated for a given rule 01797 * OR if a min penalty change is indicated but no max penalty change is */ 01798 if (*maxstr == '+' || *maxstr == '-' || *maxstr == '\0') { 01799 rule->max_relative = 1; 01800 } 01801 01802 rule->max_value = atoi(maxstr); 01803 01804 if (!ast_strlen_zero(minstr)) { 01805 if (*minstr == '+' || *minstr == '-') 01806 rule->min_relative = 1; 01807 rule->min_value = atoi(minstr); 01808 } else /*there was no minimum specified, so assume this means no change*/ 01809 rule->min_relative = 1; 01810 01811 /*We have the rule made, now we need to insert it where it belongs*/ 01812 AST_LIST_TRAVERSE(&rule_lists, rl_iter, list){ 01813 if (strcasecmp(rl_iter->name, list_name)) 01814 continue; 01815 01816 AST_LIST_TRAVERSE_SAFE_BEGIN(&rl_iter->rules, rule_iter, list) { 01817 if (rule->time < rule_iter->time) { 01818 AST_LIST_INSERT_BEFORE_CURRENT(rule, list); 01819 inserted = 1; 01820 break; 01821 } 01822 } 01823 AST_LIST_TRAVERSE_SAFE_END; 01824 01825 if (!inserted) { 01826 AST_LIST_INSERT_TAIL(&rl_iter->rules, rule, list); 01827 } 01828 } 01829 01830 return 0; 01831 }
static const char* int2strat | ( | int | strategy | ) | [static] |
Definition at line 1209 of file app_queue.c.
References ARRAY_LEN, strategy::name, and strategies.
Referenced by __queues_show(), manager_queues_status(), queue_function_var(), queues_data_provider_get_helper(), and set_queue_variables().
01210 { 01211 int x; 01212 01213 for (x = 0; x < ARRAY_LEN(strategies); x++) { 01214 if (strategy == strategies[x].strategy) 01215 return strategies[x].name; 01216 } 01217 01218 return "<unknown>"; 01219 }
static struct member* interface_exists | ( | struct call_queue * | q, | |
const char * | interface | |||
) | [static] |
Definition at line 5085 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(), get_member_penalty(), set_member_paused(), and set_member_penalty().
05086 { 05087 struct member *mem; 05088 struct ao2_iterator mem_iter; 05089 05090 if (!q) 05091 return NULL; 05092 05093 mem_iter = ao2_iterator_init(q->members, 0); 05094 while ((mem = ao2_iterator_next(&mem_iter))) { 05095 if (!strcasecmp(interface, mem->interface)) { 05096 ao2_iterator_destroy(&mem_iter); 05097 return mem; 05098 } 05099 ao2_ref(mem, -1); 05100 } 05101 ao2_iterator_destroy(&mem_iter); 05102 05103 return NULL; 05104 }
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 3842 of file app_queue.c.
References ao2_lock, ao2_unlock, ast_debug, call_queue::autofill, queue_ent::chan, call_queue::head, ast_channel::name, queue_ent::next, num_available_members(), queue_ent::parent, queue_ent::pending, and queue_ent::pos.
Referenced by queue_exec(), and wait_our_turn().
03843 { 03844 struct queue_ent *ch; 03845 int res; 03846 int avl; 03847 int idx = 0; 03848 /* This needs a lock. How many members are available to be served? */ 03849 ao2_lock(qe->parent); 03850 03851 avl = num_available_members(qe->parent); 03852 03853 ch = qe->parent->head; 03854 03855 ast_debug(1, "There %s %d available %s.\n", avl != 1 ? "are" : "is", avl, avl != 1 ? "members" : "member"); 03856 03857 while ((idx < avl) && (ch) && (ch != qe)) { 03858 if (!ch->pending) 03859 idx++; 03860 ch = ch->next; 03861 } 03862 03863 ao2_unlock(qe->parent); 03864 /* If the queue entry is within avl [the number of available members] calls from the top ... 03865 * Autofill and position check added to support autofill=no (as only calls 03866 * from the front of the queue are valid when autofill is disabled) 03867 */ 03868 if (ch && idx < avl && (qe->parent->autofill || qe->pos == 1)) { 03869 ast_debug(1, "It's our turn (%s).\n", qe->chan->name); 03870 res = 1; 03871 } else { 03872 ast_debug(1, "It's not our turn (%s).\n", qe->chan->name); 03873 res = 0; 03874 } 03875 03876 return res; 03877 }
static int join_queue | ( | char * | queuename, | |
struct queue_ent * | qe, | |||
enum queue_result * | reason, | |||
int | position | |||
) | [static] |
Definition at line 2453 of file app_queue.c.
References queue_ent::announce, ao2_lock, ao2_unlock, ast_copy_string(), ast_debug, ast_log(), ast_manager_event, ast_channel::caller, queue_ent::chan, queue_ent::context, call_queue::count, EVENT_FLAG_CALL, get_member_status(), call_queue::head, ast_party_caller::id, insert_entry(), call_queue::joinempty, load_realtime_queue(), LOG_NOTICE, queue_ent::max_penalty, call_queue::maxlen, queue_ent::min_penalty, queue_ent::moh, ast_party_id::name, ast_channel::name, queue_ent::next, ast_party_id::number, queue_ent::pos, queue_ent::prio, QUEUE_FULL, QUEUE_JOINEMPTY, QUEUE_UNKNOWN, queues, S_COR, status, ast_party_name::str, ast_party_number::str, ast_channel::uniqueid, ast_party_name::valid, and ast_party_number::valid.
Referenced by queue_exec().
02454 { 02455 struct call_queue *q; 02456 struct queue_ent *cur, *prev = NULL; 02457 int res = -1; 02458 int pos = 0; 02459 int inserted = 0; 02460 02461 if (!(q = load_realtime_queue(queuename))) 02462 return res; 02463 02464 ao2_lock(queues); 02465 ao2_lock(q); 02466 02467 /* This is our one */ 02468 if (q->joinempty) { 02469 int status = 0; 02470 if ((status = get_member_status(q, qe->max_penalty, qe->min_penalty, q->joinempty))) { 02471 *reason = QUEUE_JOINEMPTY; 02472 ao2_unlock(q); 02473 ao2_unlock(queues); 02474 return res; 02475 } 02476 } 02477 if (*reason == QUEUE_UNKNOWN && q->maxlen && (q->count >= q->maxlen)) 02478 *reason = QUEUE_FULL; 02479 else if (*reason == QUEUE_UNKNOWN) { 02480 /* There's space for us, put us at the right position inside 02481 * the queue. 02482 * Take into account the priority of the calling user */ 02483 inserted = 0; 02484 prev = NULL; 02485 cur = q->head; 02486 while (cur) { 02487 /* We have higher priority than the current user, enter 02488 * before him, after all the other users with priority 02489 * higher or equal to our priority. */ 02490 if ((!inserted) && (qe->prio > cur->prio)) { 02491 insert_entry(q, prev, qe, &pos); 02492 inserted = 1; 02493 } 02494 /* <= is necessary for the position comparison because it may not be possible to enter 02495 * at our desired position since higher-priority callers may have taken the position we want 02496 */ 02497 if (!inserted && (qe->prio >= cur->prio) && position && (position <= pos + 1)) { 02498 insert_entry(q, prev, qe, &pos); 02499 /*pos is incremented inside insert_entry, so don't need to add 1 here*/ 02500 if (position < pos) { 02501 ast_log(LOG_NOTICE, "Asked to be inserted at position %d but forced into position %d due to higher priority callers\n", position, pos); 02502 } 02503 inserted = 1; 02504 } 02505 cur->pos = ++pos; 02506 prev = cur; 02507 cur = cur->next; 02508 } 02509 /* No luck, join at the end of the queue */ 02510 if (!inserted) 02511 insert_entry(q, prev, qe, &pos); 02512 ast_copy_string(qe->moh, q->moh, sizeof(qe->moh)); 02513 ast_copy_string(qe->announce, q->announce, sizeof(qe->announce)); 02514 ast_copy_string(qe->context, q->context, sizeof(qe->context)); 02515 q->count++; 02516 res = 0; 02517 ast_manager_event(qe->chan, EVENT_FLAG_CALL, "Join", 02518 "Channel: %s\r\nCallerIDNum: %s\r\nCallerIDName: %s\r\nQueue: %s\r\nPosition: %d\r\nCount: %d\r\nUniqueid: %s\r\n", 02519 qe->chan->name, 02520 S_COR(qe->chan->caller.id.number.valid, qe->chan->caller.id.number.str, "unknown"),/* XXX somewhere else it is <unknown> */ 02521 S_COR(qe->chan->caller.id.name.valid, qe->chan->caller.id.name.str, "unknown"), 02522 q->name, qe->pos, q->count, qe->chan->uniqueid ); 02523 ast_debug(1, "Queue '%s' Join, Channel '%s', Position '%d'\n", q->name, qe->chan->name, qe->pos ); 02524 } 02525 ao2_unlock(q); 02526 ao2_unlock(queues); 02527 02528 return res; 02529 }
static int kill_dead_members | ( | void * | obj, | |
void * | arg, | |||
int | flags | |||
) | [static] |
Definition at line 6610 of file app_queue.c.
References CMP_MATCH, member::delme, member::dynamic, get_queue_member_status(), call_queue::membercount, and member::status.
06611 { 06612 struct member *member = obj; 06613 struct call_queue *q = arg; 06614 06615 if (!member->delme) { 06616 if (member->dynamic) { 06617 /* dynamic members were not counted toward the member count 06618 * when reloading members from queues.conf, so we do that here 06619 */ 06620 q->membercount++; 06621 } 06622 member->status = get_queue_member_status(member); 06623 return 0; 06624 } else { 06625 q->membercount--; 06626 return CMP_MATCH; 06627 } 06628 }
static int kill_dead_queues | ( | void * | obj, | |
void * | arg, | |||
int | flags | |||
) | [static] |
Definition at line 6748 of file app_queue.c.
References ast_strlen_zero(), CMP_MATCH, call_queue::dead, and call_queue::name.
Referenced by reload_queues().
06749 { 06750 struct call_queue *q = obj; 06751 char *queuename = arg; 06752 if ((ast_strlen_zero(queuename) || !strcasecmp(queuename, q->name)) && q->dead) { 06753 return CMP_MATCH; 06754 } else { 06755 return 0; 06756 } 06757 }
static void leave_queue | ( | struct queue_ent * | qe | ) | [static] |
Caller leaving queue.
Search the queue to find the leaving client, if found remove from queue create manager event, move others up the queue.
Definition at line 2756 of file app_queue.c.
References ao2_lock, ao2_unlock, ast_debug, ast_free, AST_LIST_REMOVE_HEAD, ast_load_realtime(), ast_manager_event, ast_variables_destroy(), queue_ent::chan, call_queue::count, call_queue::dead, EVENT_FLAG_CALL, call_queue::head, penalty_rule::list, call_queue::name, ast_channel::name, queue_ent::next, queue_ent::parent, pbx_builtin_setvar_helper(), queue_ent::pos, queue_ent::qe_rules, queue_t_ref, queue_t_unref, queues, queues_t_unlink, call_queue::realtime, SENTINEL, ast_channel::uniqueid, and var.
Referenced by wait_our_turn().
02757 { 02758 struct call_queue *q; 02759 struct queue_ent *current, *prev = NULL; 02760 struct penalty_rule *pr_iter; 02761 int pos = 0; 02762 02763 if (!(q = qe->parent)) 02764 return; 02765 queue_t_ref(q, "Copy queue pointer from queue entry"); 02766 ao2_lock(q); 02767 02768 prev = NULL; 02769 for (current = q->head; current; current = current->next) { 02770 if (current == qe) { 02771 char posstr[20]; 02772 q->count--; 02773 02774 /* Take us out of the queue */ 02775 ast_manager_event(qe->chan, EVENT_FLAG_CALL, "Leave", 02776 "Channel: %s\r\nQueue: %s\r\nCount: %d\r\nPosition: %d\r\nUniqueid: %s\r\n", 02777 qe->chan->name, q->name, q->count, qe->pos, qe->chan->uniqueid); 02778 ast_debug(1, "Queue '%s' Leave, Channel '%s'\n", q->name, qe->chan->name ); 02779 /* Take us out of the queue */ 02780 if (prev) 02781 prev->next = current->next; 02782 else 02783 q->head = current->next; 02784 /* Free penalty rules */ 02785 while ((pr_iter = AST_LIST_REMOVE_HEAD(&qe->qe_rules, list))) 02786 ast_free(pr_iter); 02787 snprintf(posstr, sizeof(posstr), "%d", qe->pos); 02788 pbx_builtin_setvar_helper(qe->chan, "QUEUEPOSITION", posstr); 02789 } else { 02790 /* Renumber the people after us in the queue based on a new count */ 02791 current->pos = ++pos; 02792 prev = current; 02793 } 02794 } 02795 ao2_unlock(q); 02796 02797 /*If the queue is a realtime queue, check to see if it's still defined in real time*/ 02798 if (q->realtime) { 02799 struct ast_variable *var; 02800 if (!(var = ast_load_realtime("queues", "name", q->name, SENTINEL))) { 02801 q->dead = 1; 02802 } else { 02803 ast_variables_destroy(var); 02804 } 02805 } 02806 02807 if (q->dead) { 02808 /* It's dead and nobody is in it, so kill it */ 02809 queues_t_unlink(queues, q, "Queue is now dead; remove it from the container"); 02810 } 02811 /* unref the explicit ref earlier in the function */ 02812 queue_t_unref(q, "Expire copied reference"); 02813 }
static int load_module | ( | void | ) | [static] |
Definition at line 8298 of file app_queue.c.
References ao2_container_alloc, aqm_exec(), ARRAY_LEN, ast_add_extension2(), ast_cli_register_multiple(), ast_context_find_or_create(), ast_custom_function_register, ast_data_register_multiple, AST_EVENT_DEVICE_STATE, AST_EVENT_IE_END, ast_event_subscribe(), ast_extension_state_add(), AST_FLAGS_ALL, ast_free_ptr, ast_log(), ast_manager_register_xml, AST_MODULE_LOAD_DECLINE, ast_realtime_require_field(), ast_register_application_xml, ast_strdup, ast_taskprocessor_get(), cli_queue, device_state_cb(), device_state_sub, devicestate_tps, EVENT_FLAG_AGENT, extension_state_cb(), LOG_ERROR, LOG_WARNING, manager_add_queue_member(), manager_pause_queue_member(), manager_queue_log_custom(), manager_queue_member_penalty(), manager_queue_reload(), manager_queue_reset(), manager_queue_rule_show(), manager_queues_show(), manager_queues_status(), manager_queues_summary(), manager_remove_queue_member(), MAX_QUEUE_BUCKETS, pqm_exec(), ql_exec(), queue_cmp_cb(), queue_data_providers, queue_exec(), queue_hash_cb(), queueexists_function, queuemembercount_dep, queuemembercount_function, queuememberlist_function, queuememberpenalty_function, queuevar_function, queuewaitingcount_function, reload_handler(), reload_queue_members(), RQ_INTEGER1, RQ_UINTEGER2, rqm_exec(), SENTINEL, and upqm_exec().
08299 { 08300 int res; 08301 struct ast_context *con; 08302 struct ast_flags mask = {AST_FLAGS_ALL, }; 08303 08304 queues = ao2_container_alloc(MAX_QUEUE_BUCKETS, queue_hash_cb, queue_cmp_cb); 08305 08306 use_weight = 0; 08307 08308 if (reload_handler(0, &mask, NULL)) 08309 return AST_MODULE_LOAD_DECLINE; 08310 08311 con = ast_context_find_or_create(NULL, NULL, "app_queue_gosub_virtual_context", "app_queue"); 08312 if (!con) 08313 ast_log(LOG_ERROR, "Queue virtual context 'app_queue_gosub_virtual_context' does not exist and unable to create\n"); 08314 else 08315 ast_add_extension2(con, 1, "s", 1, NULL, NULL, "NoOp", ast_strdup(""), ast_free_ptr, "app_queue"); 08316 08317 if (queue_persistent_members) 08318 reload_queue_members(); 08319 08320 ast_data_register_multiple(queue_data_providers, ARRAY_LEN(queue_data_providers)); 08321 08322 ast_cli_register_multiple(cli_queue, ARRAY_LEN(cli_queue)); 08323 res = ast_register_application_xml(app, queue_exec); 08324 res |= ast_register_application_xml(app_aqm, aqm_exec); 08325 res |= ast_register_application_xml(app_rqm, rqm_exec); 08326 res |= ast_register_application_xml(app_pqm, pqm_exec); 08327 res |= ast_register_application_xml(app_upqm, upqm_exec); 08328 res |= ast_register_application_xml(app_ql, ql_exec); 08329 res |= ast_manager_register_xml("Queues", 0, manager_queues_show); 08330 res |= ast_manager_register_xml("QueueStatus", 0, manager_queues_status); 08331 res |= ast_manager_register_xml("QueueSummary", 0, manager_queues_summary); 08332 res |= ast_manager_register_xml("QueueAdd", EVENT_FLAG_AGENT, manager_add_queue_member); 08333 res |= ast_manager_register_xml("QueueRemove", EVENT_FLAG_AGENT, manager_remove_queue_member); 08334 res |= ast_manager_register_xml("QueuePause", EVENT_FLAG_AGENT, manager_pause_queue_member); 08335 res |= ast_manager_register_xml("QueueLog", EVENT_FLAG_AGENT, manager_queue_log_custom); 08336 res |= ast_manager_register_xml("QueuePenalty", EVENT_FLAG_AGENT, manager_queue_member_penalty); 08337 res |= ast_manager_register_xml("QueueRule", 0, manager_queue_rule_show); 08338 res |= ast_manager_register_xml("QueueReload", 0, manager_queue_reload); 08339 res |= ast_manager_register_xml("QueueReset", 0, manager_queue_reset); 08340 res |= ast_custom_function_register(&queuevar_function); 08341 res |= ast_custom_function_register(&queueexists_function); 08342 res |= ast_custom_function_register(&queuemembercount_function); 08343 res |= ast_custom_function_register(&queuemembercount_dep); 08344 res |= ast_custom_function_register(&queuememberlist_function); 08345 res |= ast_custom_function_register(&queuewaitingcount_function); 08346 res |= ast_custom_function_register(&queuememberpenalty_function); 08347 08348 if (!(devicestate_tps = ast_taskprocessor_get("app_queue", 0))) { 08349 ast_log(LOG_WARNING, "devicestate taskprocessor reference failed - devicestate notifications will not occur\n"); 08350 } 08351 08352 /* in the following subscribe call, do I use DEVICE_STATE, or DEVICE_STATE_CHANGE? */ 08353 if (!(device_state_sub = ast_event_subscribe(AST_EVENT_DEVICE_STATE, device_state_cb, "AppQueue Device state", NULL, AST_EVENT_IE_END))) { 08354 res = -1; 08355 } 08356 08357 ast_extension_state_add(NULL, NULL, extension_state_cb, NULL); 08358 08359 ast_realtime_require_field("queue_members", "paused", RQ_INTEGER1, 1, "uniqueid", RQ_UINTEGER2, 5, SENTINEL); 08360 08361 return res ? AST_MODULE_LOAD_DECLINE : 0; 08362 }
static struct call_queue* load_realtime_queue | ( | const char * | queuename | ) | [static] |
Definition at line 2327 of file app_queue.c.
References ao2_lock, ao2_t_find, ao2_unlock, ast_atomic_fetchadd_int(), ast_config_destroy(), ast_load_realtime(), ast_load_realtime_multientry(), ast_log(), ast_variables_destroy(), find_queue_by_name_rt(), LOG_ERROR, call_queue::name, OBJ_POINTER, queues, call_queue::realtime, SENTINEL, update_realtime_members(), and call_queue::weight.
Referenced by __queues_show(), add_to_queue(), join_queue(), queue_function_exists(), queue_function_qac(), queue_function_qac_dep(), queues_data_provider_get(), and reload_queue_members().
02328 { 02329 struct ast_variable *queue_vars; 02330 struct ast_config *member_config = NULL; 02331 struct call_queue *q = NULL, tmpq = { 02332 .name = queuename, 02333 }; 02334 int prev_weight = 0; 02335 02336 /* Find the queue in the in-core list first. */ 02337 q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Look for queue in memory first"); 02338 02339 if (!q || q->realtime) { 02340 /*! \note Load from realtime before taking the "queues" container lock, to avoid blocking all 02341 queue operations while waiting for the DB. 02342 02343 This will be two separate database transactions, so we might 02344 see queue parameters as they were before another process 02345 changed the queue and member list as it was after the change. 02346 Thus we might see an empty member list when a queue is 02347 deleted. In practise, this is unlikely to cause a problem. */ 02348 02349 queue_vars = ast_load_realtime("queues", "name", queuename, SENTINEL); 02350 if (queue_vars) { 02351 member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name", queuename, SENTINEL); 02352 if (!member_config) { 02353 ast_log(LOG_ERROR, "no queue_members defined in your config (extconfig.conf).\n"); 02354 ast_variables_destroy(queue_vars); 02355 return NULL; 02356 } 02357 } 02358 if (q) { 02359 prev_weight = q->weight ? 1 : 0; 02360 } 02361 02362 ao2_lock(queues); 02363 02364 q = find_queue_by_name_rt(queuename, queue_vars, member_config); 02365 if (member_config) { 02366 ast_config_destroy(member_config); 02367 } 02368 if (queue_vars) { 02369 ast_variables_destroy(queue_vars); 02370 } 02371 /* update the use_weight value if the queue's has gained or lost a weight */ 02372 if (q) { 02373 if (!q->weight && prev_weight) { 02374 ast_atomic_fetchadd_int(&use_weight, -1); 02375 } 02376 if (q->weight && !prev_weight) { 02377 ast_atomic_fetchadd_int(&use_weight, +1); 02378 } 02379 } 02380 /* Other cases will end up with the proper value for use_weight */ 02381 ao2_unlock(queues); 02382 02383 } else { 02384 update_realtime_members(q); 02385 } 02386 return q; 02387 }
static int manager_add_queue_member | ( | struct mansession * | s, | |
const struct message * | m | |||
) | [static] |
Definition at line 7273 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, and RES_OUTOFMEMORY.
Referenced by load_module().
07274 { 07275 const char *queuename, *interface, *penalty_s, *paused_s, *membername, *state_interface; 07276 int paused, penalty = 0; 07277 07278 queuename = astman_get_header(m, "Queue"); 07279 interface = astman_get_header(m, "Interface"); 07280 penalty_s = astman_get_header(m, "Penalty"); 07281 paused_s = astman_get_header(m, "Paused"); 07282 membername = astman_get_header(m, "MemberName"); 07283 state_interface = astman_get_header(m, "StateInterface"); 07284 07285 if (ast_strlen_zero(queuename)) { 07286 astman_send_error(s, m, "'Queue' not specified."); 07287 return 0; 07288 } 07289 07290 if (ast_strlen_zero(interface)) { 07291 astman_send_error(s, m, "'Interface' not specified."); 07292 return 0; 07293 } 07294 07295 if (ast_strlen_zero(penalty_s)) 07296 penalty = 0; 07297 else if (sscanf(penalty_s, "%30d", &penalty) != 1 || penalty < 0) 07298 penalty = 0; 07299 07300 if (ast_strlen_zero(paused_s)) 07301 paused = 0; 07302 else 07303 paused = abs(ast_true(paused_s)); 07304 07305 switch (add_to_queue(queuename, interface, membername, penalty, paused, queue_persistent_members, state_interface)) { 07306 case RES_OKAY: 07307 ast_queue_log(queuename, "MANAGER", interface, "ADDMEMBER", "%s", ""); 07308 astman_send_ack(s, m, "Added interface to queue"); 07309 break; 07310 case RES_EXISTS: 07311 astman_send_error(s, m, "Unable to add interface: Already there"); 07312 break; 07313 case RES_NOSUCHQUEUE: 07314 astman_send_error(s, m, "Unable to add interface to queue: No such queue"); 07315 break; 07316 case RES_OUTOFMEMORY: 07317 astman_send_error(s, m, "Out of memory"); 07318 break; 07319 } 07320 07321 return 0; 07322 }
static int manager_pause_queue_member | ( | struct mansession * | s, | |
const struct message * | m | |||
) | [static] |
Definition at line 7358 of file app_queue.c.
References ast_strlen_zero(), ast_true(), astman_get_header(), astman_send_ack(), astman_send_error(), and set_member_paused().
Referenced by load_module().
07359 { 07360 const char *queuename, *interface, *paused_s, *reason; 07361 int paused; 07362 07363 interface = astman_get_header(m, "Interface"); 07364 paused_s = astman_get_header(m, "Paused"); 07365 queuename = astman_get_header(m, "Queue"); /* Optional - if not supplied, pause the given Interface in all queues */ 07366 reason = astman_get_header(m, "Reason"); /* Optional - Only used for logging purposes */ 07367 07368 if (ast_strlen_zero(interface) || ast_strlen_zero(paused_s)) { 07369 astman_send_error(s, m, "Need 'Interface' and 'Paused' parameters."); 07370 return 0; 07371 } 07372 07373 paused = abs(ast_true(paused_s)); 07374 07375 if (set_member_paused(queuename, interface, reason, paused)) 07376 astman_send_error(s, m, "Interface not found"); 07377 else 07378 astman_send_ack(s, m, paused ? "Interface paused successfully" : "Interface unpaused successfully"); 07379 return 0; 07380 }
static int manager_queue_log_custom | ( | struct mansession * | s, | |
const struct message * | m | |||
) | [static] |
Definition at line 7382 of file app_queue.c.
References ast_queue_log(), ast_strlen_zero(), astman_get_header(), astman_send_ack(), astman_send_error(), and S_OR.
Referenced by load_module().
07383 { 07384 const char *queuename, *event, *message, *interface, *uniqueid; 07385 07386 queuename = astman_get_header(m, "Queue"); 07387 uniqueid = astman_get_header(m, "UniqueId"); 07388 interface = astman_get_header(m, "Interface"); 07389 event = astman_get_header(m, "Event"); 07390 message = astman_get_header(m, "Message"); 07391 07392 if (ast_strlen_zero(queuename) || ast_strlen_zero(event)) { 07393 astman_send_error(s, m, "Need 'Queue' and 'Event' parameters."); 07394 return 0; 07395 } 07396 07397 ast_queue_log(queuename, S_OR(uniqueid, "NONE"), interface, event, "%s", message); 07398 astman_send_ack(s, m, "Event added successfully"); 07399 07400 return 0; 07401 }
static int manager_queue_member_penalty | ( | struct mansession * | s, | |
const struct message * | m | |||
) | [static] |
Definition at line 7481 of file app_queue.c.
References ast_strlen_zero(), astman_get_header(), astman_send_ack(), astman_send_error(), and set_member_penalty().
Referenced by load_module().
07482 { 07483 const char *queuename, *interface, *penalty_s; 07484 int penalty; 07485 07486 interface = astman_get_header(m, "Interface"); 07487 penalty_s = astman_get_header(m, "Penalty"); 07488 /* Optional - if not supplied, set the penalty value for the given Interface in all queues */ 07489 queuename = astman_get_header(m, "Queue"); 07490 07491 if (ast_strlen_zero(interface) || ast_strlen_zero(penalty_s)) { 07492 astman_send_error(s, m, "Need 'Interface' and 'Penalty' parameters."); 07493 return 0; 07494 } 07495 07496 penalty = atoi(penalty_s); 07497 07498 if (set_member_penalty((char *)queuename, (char *)interface, penalty)) 07499 astman_send_error(s, m, "Invalid interface, queuename or penalty"); 07500 else 07501 astman_send_ack(s, m, "Interface penalty set successfully"); 07502 07503 return 0; 07504 }
static int manager_queue_reload | ( | struct mansession * | s, | |
const struct message * | m | |||
) | [static] |
Definition at line 7403 of file app_queue.c.
References AST_FLAGS_ALL, ast_set_flag, astman_get_header(), astman_send_ack(), astman_send_error(), QUEUE_RELOAD_MEMBER, QUEUE_RELOAD_PARAMETERS, QUEUE_RELOAD_RULES, reload_handler(), and S_OR.
Referenced by load_module().
07404 { 07405 struct ast_flags mask = {0,}; 07406 const char *queuename = NULL; 07407 int header_found = 0; 07408 07409 queuename = astman_get_header(m, "Queue"); 07410 if (!strcasecmp(S_OR(astman_get_header(m, "Members"), ""), "yes")) { 07411 ast_set_flag(&mask, QUEUE_RELOAD_MEMBER); 07412 header_found = 1; 07413 } 07414 if (!strcasecmp(S_OR(astman_get_header(m, "Rules"), ""), "yes")) { 07415 ast_set_flag(&mask, QUEUE_RELOAD_RULES); 07416 header_found = 1; 07417 } 07418 if (!strcasecmp(S_OR(astman_get_header(m, "Parameters"), ""), "yes")) { 07419 ast_set_flag(&mask, QUEUE_RELOAD_PARAMETERS); 07420 header_found = 1; 07421 } 07422 07423 if (!header_found) { 07424 ast_set_flag(&mask, AST_FLAGS_ALL); 07425 } 07426 07427 if (!reload_handler(1, &mask, queuename)) { 07428 astman_send_ack(s, m, "Queue reloaded successfully"); 07429 } else { 07430 astman_send_error(s, m, "Error encountered while reloading queue"); 07431 } 07432 return 0; 07433 }
static int manager_queue_reset | ( | struct mansession * | s, | |
const struct message * | m | |||
) | [static] |
Definition at line 7435 of file app_queue.c.
References astman_get_header(), astman_send_ack(), astman_send_error(), QUEUE_RESET_STATS, and reload_handler().
Referenced by load_module().
07436 { 07437 const char *queuename = NULL; 07438 struct ast_flags mask = {QUEUE_RESET_STATS,}; 07439 07440 queuename = astman_get_header(m, "Queue"); 07441 07442 if (!reload_handler(1, &mask, queuename)) { 07443 astman_send_ack(s, m, "Queue stats reset successfully"); 07444 } else { 07445 astman_send_error(s, m, "Error encountered while resetting queue stats"); 07446 } 07447 return 0; 07448 }
static int manager_queue_rule_show | ( | struct mansession * | s, | |
const struct message * | m | |||
) | [static] |
Definition at line 7076 of file app_queue.c.
References AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_strlen_zero(), astman_append(), astman_get_header(), penalty_rule::list, penalty_rule::max_relative, penalty_rule::max_value, penalty_rule::min_relative, penalty_rule::min_value, rule_list::name, RESULT_SUCCESS, rule_list::rules, and penalty_rule::time.
Referenced by load_module().
07077 { 07078 const char *rule = astman_get_header(m, "Rule"); 07079 struct rule_list *rl_iter; 07080 struct penalty_rule *pr_iter; 07081 07082 AST_LIST_LOCK(&rule_lists); 07083 AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) { 07084 if (ast_strlen_zero(rule) || !strcasecmp(rule, rl_iter->name)) { 07085 astman_append(s, "RuleList: %s\r\n", rl_iter->name); 07086 AST_LIST_TRAVERSE(&rl_iter->rules, pr_iter, list) { 07087 astman_append(s, "Rule: %d,%s%d,%s%d\r\n", pr_iter->time, pr_iter->max_relative && pr_iter->max_value >= 0 ? "+" : "", pr_iter->max_value, pr_iter->min_relative && pr_iter->min_value >= 0 ? "+" : "", pr_iter->min_value ); 07088 } 07089 if (!ast_strlen_zero(rule)) 07090 break; 07091 } 07092 } 07093 AST_LIST_UNLOCK(&rule_lists); 07094 07095 astman_append(s, "\r\n\r\n"); 07096 07097 return RESULT_SUCCESS; 07098 }
static int manager_queues_show | ( | struct mansession * | s, | |
const struct message * | m | |||
) | [static] |
Definition at line 7066 of file app_queue.c.
References __queues_show(), astman_append(), and RESULT_SUCCESS.
Referenced by load_module().
07067 { 07068 static const char * const a[] = { "queue", "show" }; 07069 07070 __queues_show(s, -1, 2, a); 07071 astman_append(s, "\r\n\r\n"); /* Properly terminate Manager output */ 07072 07073 return RESULT_SUCCESS; 07074 }
static int manager_queues_status | ( | struct mansession * | s, | |
const struct message * | m | |||
) | [static] |
Queue status info via AMI.
Definition at line 7176 of file app_queue.c.
References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_lock, ao2_ref, ao2_t_iterator_next, ao2_unlock, ast_strlen_zero(), astman_append(), astman_get_header(), astman_send_ack(), ast_channel::caller, member::calls, call_queue::callsabandoned, call_queue::callscompleted, call_queue::callscompletedinsl, queue_ent::chan, call_queue::count, member::dynamic, call_queue::head, call_queue::holdtime, ast_party_caller::id, int2strat(), member::interface, member::lastcall, call_queue::maxlen, member::membername, call_queue::members, ast_party_id::name, ast_channel::name, call_queue::name, queue_ent::next, ast_party_id::number, member::paused, member::penalty, queue_t_unref, RESULT_SUCCESS, S_COR, call_queue::servicelevel, queue_ent::start, member::status, ast_party_name::str, ast_party_number::str, call_queue::strategy, call_queue::talktime, ast_channel::uniqueid, ast_party_name::valid, ast_party_number::valid, and call_queue::weight.
Referenced by load_module().
07177 { 07178 time_t now; 07179 int pos; 07180 const char *id = astman_get_header(m,"ActionID"); 07181 const char *queuefilter = astman_get_header(m,"Queue"); 07182 const char *memberfilter = astman_get_header(m,"Member"); 07183 char idText[256] = ""; 07184 struct call_queue *q; 07185 struct queue_ent *qe; 07186 float sl = 0; 07187 struct member *mem; 07188 struct ao2_iterator queue_iter; 07189 struct ao2_iterator mem_iter; 07190 07191 astman_send_ack(s, m, "Queue status will follow"); 07192 time(&now); 07193 if (!ast_strlen_zero(id)) 07194 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id); 07195 07196 queue_iter = ao2_iterator_init(queues, 0); 07197 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) { 07198 ao2_lock(q); 07199 07200 /* List queue properties */ 07201 if (ast_strlen_zero(queuefilter) || !strcmp(q->name, queuefilter)) { 07202 sl = ((q->callscompleted > 0) ? 100 * ((float)q->callscompletedinsl / (float)q->callscompleted) : 0); 07203 astman_append(s, "Event: QueueParams\r\n" 07204 "Queue: %s\r\n" 07205 "Max: %d\r\n" 07206 "Strategy: %s\r\n" 07207 "Calls: %d\r\n" 07208 "Holdtime: %d\r\n" 07209 "TalkTime: %d\r\n" 07210 "Completed: %d\r\n" 07211 "Abandoned: %d\r\n" 07212 "ServiceLevel: %d\r\n" 07213 "ServicelevelPerf: %2.1f\r\n" 07214 "Weight: %d\r\n" 07215 "%s" 07216 "\r\n", 07217 q->name, q->maxlen, int2strat(q->strategy), q->count, q->holdtime, q->talktime, q->callscompleted, 07218 q->callsabandoned, q->servicelevel, sl, q->weight, idText); 07219 /* List Queue Members */ 07220 mem_iter = ao2_iterator_init(q->members, 0); 07221 while ((mem = ao2_iterator_next(&mem_iter))) { 07222 if (ast_strlen_zero(memberfilter) || !strcmp(mem->interface, memberfilter) || !strcmp(mem->membername, memberfilter)) { 07223 astman_append(s, "Event: QueueMember\r\n" 07224 "Queue: %s\r\n" 07225 "Name: %s\r\n" 07226 "Location: %s\r\n" 07227 "Membership: %s\r\n" 07228 "Penalty: %d\r\n" 07229 "CallsTaken: %d\r\n" 07230 "LastCall: %d\r\n" 07231 "Status: %d\r\n" 07232 "Paused: %d\r\n" 07233 "%s" 07234 "\r\n", 07235 q->name, mem->membername, mem->interface, mem->dynamic ? "dynamic" : "static", 07236 mem->penalty, mem->calls, (int)mem->lastcall, mem->status, mem->paused, idText); 07237 } 07238 ao2_ref(mem, -1); 07239 } 07240 ao2_iterator_destroy(&mem_iter); 07241 /* List Queue Entries */ 07242 pos = 1; 07243 for (qe = q->head; qe; qe = qe->next) { 07244 astman_append(s, "Event: QueueEntry\r\n" 07245 "Queue: %s\r\n" 07246 "Position: %d\r\n" 07247 "Channel: %s\r\n" 07248 "Uniqueid: %s\r\n" 07249 "CallerIDNum: %s\r\n" 07250 "CallerIDName: %s\r\n" 07251 "Wait: %ld\r\n" 07252 "%s" 07253 "\r\n", 07254 q->name, pos++, qe->chan->name, qe->chan->uniqueid, 07255 S_COR(qe->chan->caller.id.number.valid, qe->chan->caller.id.number.str, "unknown"), 07256 S_COR(qe->chan->caller.id.name.valid, qe->chan->caller.id.name.str, "unknown"), 07257 (long) (now - qe->start), idText); 07258 } 07259 } 07260 ao2_unlock(q); 07261 queue_t_unref(q, "Done with iterator"); 07262 } 07263 ao2_iterator_destroy(&queue_iter); 07264 07265 astman_append(s, 07266 "Event: QueueStatusComplete\r\n" 07267 "%s" 07268 "\r\n",idText); 07269 07270 return RESULT_SUCCESS; 07271 }
static int manager_queues_summary | ( | struct mansession * | s, | |
const struct message * | m | |||
) | [static] |
Summary of queue info via the AMI.
Definition at line 7101 of file app_queue.c.
References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_lock, ao2_ref, ao2_t_iterator_next, ao2_unlock, AST_DEVICE_INVALID, AST_DEVICE_NOT_INUSE, AST_DEVICE_UNAVAILABLE, AST_DEVICE_UNKNOWN, ast_strlen_zero(), astman_append(), astman_get_header(), astman_send_ack(), call_queue::head, call_queue::holdtime, call_queue::members, call_queue::name, queue_ent::next, member::paused, queue_t_unref, RESULT_SUCCESS, queue_ent::start, member::status, and call_queue::talktime.
Referenced by load_module().
07102 { 07103 time_t now; 07104 int qmemcount = 0; 07105 int qmemavail = 0; 07106 int qchancount = 0; 07107 int qlongestholdtime = 0; 07108 const char *id = astman_get_header(m, "ActionID"); 07109 const char *queuefilter = astman_get_header(m, "Queue"); 07110 char idText[256] = ""; 07111 struct call_queue *q; 07112 struct queue_ent *qe; 07113 struct member *mem; 07114 struct ao2_iterator queue_iter; 07115 struct ao2_iterator mem_iter; 07116 07117 astman_send_ack(s, m, "Queue summary will follow"); 07118 time(&now); 07119 if (!ast_strlen_zero(id)) 07120 snprintf(idText, 256, "ActionID: %s\r\n", id); 07121 queue_iter = ao2_iterator_init(queues, 0); 07122 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) { 07123 ao2_lock(q); 07124 07125 /* List queue properties */ 07126 if (ast_strlen_zero(queuefilter) || !strcmp(q->name, queuefilter)) { 07127 /* Reset the necessary local variables if no queuefilter is set*/ 07128 qmemcount = 0; 07129 qmemavail = 0; 07130 qchancount = 0; 07131 qlongestholdtime = 0; 07132 07133 /* List Queue Members */ 07134 mem_iter = ao2_iterator_init(q->members, 0); 07135 while ((mem = ao2_iterator_next(&mem_iter))) { 07136 if ((mem->status != AST_DEVICE_UNAVAILABLE) && (mem->status != AST_DEVICE_INVALID)) { 07137 ++qmemcount; 07138 if (((mem->status == AST_DEVICE_NOT_INUSE) || (mem->status == AST_DEVICE_UNKNOWN)) && !(mem->paused)) { 07139 ++qmemavail; 07140 } 07141 } 07142 ao2_ref(mem, -1); 07143 } 07144 ao2_iterator_destroy(&mem_iter); 07145 for (qe = q->head; qe; qe = qe->next) { 07146 if ((now - qe->start) > qlongestholdtime) { 07147 qlongestholdtime = now - qe->start; 07148 } 07149 ++qchancount; 07150 } 07151 astman_append(s, "Event: QueueSummary\r\n" 07152 "Queue: %s\r\n" 07153 "LoggedIn: %d\r\n" 07154 "Available: %d\r\n" 07155 "Callers: %d\r\n" 07156 "HoldTime: %d\r\n" 07157 "TalkTime: %d\r\n" 07158 "LongestHoldTime: %d\r\n" 07159 "%s" 07160 "\r\n", 07161 q->name, qmemcount, qmemavail, qchancount, q->holdtime, q->talktime, qlongestholdtime, idText); 07162 } 07163 ao2_unlock(q); 07164 queue_t_unref(q, "Done with iterator"); 07165 } 07166 ao2_iterator_destroy(&queue_iter); 07167 astman_append(s, 07168 "Event: QueueSummaryComplete\r\n" 07169 "%s" 07170 "\r\n", idText); 07171 07172 return RESULT_SUCCESS; 07173 }
static int manager_remove_queue_member | ( | struct mansession * | s, | |
const struct message * | m | |||
) | [static] |
Definition at line 7324 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, and RES_OUTOFMEMORY.
Referenced by load_module().
07325 { 07326 const char *queuename, *interface; 07327 07328 queuename = astman_get_header(m, "Queue"); 07329 interface = astman_get_header(m, "Interface"); 07330 07331 if (ast_strlen_zero(queuename) || ast_strlen_zero(interface)) { 07332 astman_send_error(s, m, "Need 'Queue' and 'Interface' parameters."); 07333 return 0; 07334 } 07335 07336 switch (remove_from_queue(queuename, interface)) { 07337 case RES_OKAY: 07338 ast_queue_log(queuename, "MANAGER", interface, "REMOVEMEMBER", "%s", ""); 07339 astman_send_ack(s, m, "Removed interface from queue"); 07340 break; 07341 case RES_EXISTS: 07342 astman_send_error(s, m, "Unable to remove interface: Not there"); 07343 break; 07344 case RES_NOSUCHQUEUE: 07345 astman_send_error(s, m, "Unable to remove interface from queue: No such queue"); 07346 break; 07347 case RES_OUTOFMEMORY: 07348 astman_send_error(s, m, "Out of memory"); 07349 break; 07350 case RES_NOT_DYNAMIC: 07351 astman_send_error(s, m, "Member not dynamic"); 07352 break; 07353 } 07354 07355 return 0; 07356 }
static int mark_dead_and_unfound | ( | void * | obj, | |
void * | arg, | |||
int | flags | |||
) | [static] |
Definition at line 6737 of file app_queue.c.
References ast_strlen_zero(), call_queue::dead, call_queue::found, call_queue::name, and call_queue::realtime.
Referenced by reload_queues().
06738 { 06739 struct call_queue *q = obj; 06740 char *queuename = arg; 06741 if (!q->realtime && (ast_strlen_zero(queuename) || !strcasecmp(queuename, q->name))) { 06742 q->dead = 1; 06743 q->found = 0; 06744 } 06745 return 0; 06746 }
static int mark_member_dead | ( | void * | obj, | |
void * | arg, | |||
int | flags | |||
) | [static] |
Definition at line 6601 of file app_queue.c.
References member::delme, and member::dynamic.
Referenced by reload_single_queue().
06602 { 06603 struct member *member = obj; 06604 if (!member->dynamic) { 06605 member->delme = 1; 06606 } 06607 return 0; 06608 }
static int member_cmp_fn | ( | void * | obj1, | |
void * | obj2, | |||
int | flags | |||
) | [static] |
Definition at line 1653 of file app_queue.c.
References CMP_MATCH, CMP_STOP, and member::interface.
Referenced by init_queue().
01654 { 01655 struct member *mem1 = obj1, *mem2 = obj2; 01656 return strcasecmp(mem1->interface, mem2->interface) ? 0 : CMP_MATCH | CMP_STOP; 01657 }
static int member_hash_fn | ( | const void * | obj, | |
const int | flags | |||
) | [static] |
Definition at line 1641 of file app_queue.c.
References compress_char(), and member::interface.
Referenced by init_queue().
01642 { 01643 const struct member *mem = obj; 01644 const char *chname = strchr(mem->interface, '/'); 01645 int ret = 0, i; 01646 if (!chname) 01647 chname = mem->interface; 01648 for (i = 0; i < 5 && chname[i]; i++) 01649 ret += compress_char(chname[i]) << (i * 6); 01650 return ret; 01651 }
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 2861 of file app_queue.c.
References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_ref, AST_DEVICE_INUSE, AST_DEVICE_NOT_INUSE, AST_DEVICE_UNKNOWN, call_queue::autofill, call_queue::members, member::paused, QUEUE_STRATEGY_RINGALL, call_queue::ringinuse, member::status, and call_queue::strategy.
Referenced by compare_weight(), and is_our_turn().
02862 { 02863 struct member *mem; 02864 int avl = 0; 02865 struct ao2_iterator mem_iter; 02866 02867 mem_iter = ao2_iterator_init(q->members, 0); 02868 while ((mem = ao2_iterator_next(&mem_iter))) { 02869 switch (mem->status) { 02870 case AST_DEVICE_INUSE: 02871 if (!q->ringinuse) 02872 break; 02873 /* else fall through */ 02874 case AST_DEVICE_NOT_INUSE: 02875 case AST_DEVICE_UNKNOWN: 02876 if (!mem->paused) { 02877 avl++; 02878 } 02879 break; 02880 } 02881 ao2_ref(mem, -1); 02882 02883 /* If autofill is not enabled or if the queue's strategy is ringall, then 02884 * we really don't care about the number of available members so much as we 02885 * do that there is at least one available. 02886 * 02887 * In fact, we purposely will return from this function stating that only 02888 * one member is available if either of those conditions hold. That way, 02889 * functions which determine what action to take based on the number of available 02890 * members will operate properly. The reasoning is that even if multiple 02891 * members are available, only the head caller can actually be serviced. 02892 */ 02893 if ((!q->autofill || q->strategy == QUEUE_STRATEGY_RINGALL) && avl) { 02894 break; 02895 } 02896 } 02897 ao2_iterator_destroy(&mem_iter); 02898 02899 return avl; 02900 }
static void parse_empty_options | ( | const char * | value, | |
enum empty_conditions * | empty, | |||
int | joinempty | |||
) | [static] |
Definition at line 1833 of file app_queue.c.
References ast_false(), ast_log(), ast_strdupa, ast_true(), LOG_WARNING, QUEUE_EMPTY_INUSE, QUEUE_EMPTY_INVALID, QUEUE_EMPTY_PAUSED, QUEUE_EMPTY_PENALTY, QUEUE_EMPTY_RINGING, QUEUE_EMPTY_UNAVAILABLE, QUEUE_EMPTY_UNKNOWN, QUEUE_EMPTY_WRAPUP, and strsep().
Referenced by queue_set_param().
01834 { 01835 char *value_copy = ast_strdupa(value); 01836 char *option = NULL; 01837 while ((option = strsep(&value_copy, ","))) { 01838 if (!strcasecmp(option, "paused")) { 01839 *empty |= QUEUE_EMPTY_PAUSED; 01840 } else if (!strcasecmp(option, "penalty")) { 01841 *empty |= QUEUE_EMPTY_PENALTY; 01842 } else if (!strcasecmp(option, "inuse")) { 01843 *empty |= QUEUE_EMPTY_INUSE; 01844 } else if (!strcasecmp(option, "ringing")) { 01845 *empty |= QUEUE_EMPTY_RINGING; 01846 } else if (!strcasecmp(option, "invalid")) { 01847 *empty |= QUEUE_EMPTY_INVALID; 01848 } else if (!strcasecmp(option, "wrapup")) { 01849 *empty |= QUEUE_EMPTY_WRAPUP; 01850 } else if (!strcasecmp(option, "unavailable")) { 01851 *empty |= QUEUE_EMPTY_UNAVAILABLE; 01852 } else if (!strcasecmp(option, "unknown")) { 01853 *empty |= QUEUE_EMPTY_UNKNOWN; 01854 } else if (!strcasecmp(option, "loose")) { 01855 *empty = (QUEUE_EMPTY_PENALTY | QUEUE_EMPTY_INVALID); 01856 } else if (!strcasecmp(option, "strict")) { 01857 *empty = (QUEUE_EMPTY_PENALTY | QUEUE_EMPTY_INVALID | QUEUE_EMPTY_PAUSED | QUEUE_EMPTY_UNAVAILABLE); 01858 } else if ((ast_false(option) && joinempty) || (ast_true(option) && !joinempty)) { 01859 *empty = (QUEUE_EMPTY_PENALTY | QUEUE_EMPTY_INVALID | QUEUE_EMPTY_PAUSED); 01860 } else if ((ast_false(option) && !joinempty) || (ast_true(option) && joinempty)) { 01861 *empty = 0; 01862 } else { 01863 ast_log(LOG_WARNING, "Unknown option %s for '%s'\n", option, joinempty ? "joinempty" : "leavewhenempty"); 01864 } 01865 } 01866 }
static int play_file | ( | struct ast_channel * | chan, | |
const char * | filename | |||
) | [static] |
Definition at line 2531 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().
02532 { 02533 int res; 02534 02535 if (ast_strlen_zero(filename)) { 02536 return 0; 02537 } 02538 02539 if (!ast_fileexists(filename, NULL, chan->language)) { 02540 return 0; 02541 } 02542 02543 ast_stopstream(chan); 02544 02545 res = ast_streamfile(chan, filename, chan->language); 02546 if (!res) 02547 res = ast_waitstream(chan, AST_DIGIT_ANY); 02548 02549 ast_stopstream(chan); 02550 02551 return res; 02552 }
static int pqm_exec | ( | struct ast_channel * | chan, | |
const char * | data | |||
) | [static] |
PauseQueueMember application.
Definition at line 5520 of file app_queue.c.
References args, AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_log(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), LOG_WARNING, parse(), pbx_builtin_setvar_helper(), and set_member_paused().
Referenced by load_module().
05521 { 05522 char *parse; 05523 AST_DECLARE_APP_ARGS(args, 05524 AST_APP_ARG(queuename); 05525 AST_APP_ARG(interface); 05526 AST_APP_ARG(options); 05527 AST_APP_ARG(reason); 05528 ); 05529 05530 if (ast_strlen_zero(data)) { 05531 ast_log(LOG_WARNING, "PauseQueueMember requires an argument ([queuename],interface[,options][,reason])\n"); 05532 return -1; 05533 } 05534 05535 parse = ast_strdupa(data); 05536 05537 AST_STANDARD_APP_ARGS(args, parse); 05538 05539 if (ast_strlen_zero(args.interface)) { 05540 ast_log(LOG_WARNING, "Missing interface argument to PauseQueueMember ([queuename],interface[,options[,reason]])\n"); 05541 return -1; 05542 } 05543 05544 if (set_member_paused(args.queuename, args.interface, args.reason, 1)) { 05545 ast_log(LOG_WARNING, "Attempt to pause interface %s, not found\n", args.interface); 05546 pbx_builtin_setvar_helper(chan, "PQMSTATUS", "NOTFOUND"); 05547 return 0; 05548 } 05549 05550 pbx_builtin_setvar_helper(chan, "PQMSTATUS", "PAUSED"); 05551 05552 return 0; 05553 }
static int ql_exec | ( | struct ast_channel * | chan, | |
const char * | data | |||
) | [static] |
QueueLog application.
Definition at line 5712 of file app_queue.c.
References args, AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_log(), ast_queue_log(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), LOG_WARNING, and parse().
Referenced by load_module().
05713 { 05714 char *parse; 05715 05716 AST_DECLARE_APP_ARGS(args, 05717 AST_APP_ARG(queuename); 05718 AST_APP_ARG(uniqueid); 05719 AST_APP_ARG(membername); 05720 AST_APP_ARG(event); 05721 AST_APP_ARG(params); 05722 ); 05723 05724 if (ast_strlen_zero(data)) { 05725 ast_log(LOG_WARNING, "QueueLog requires arguments (queuename,uniqueid,membername,event[,additionalinfo]\n"); 05726 return -1; 05727 } 05728 05729 parse = ast_strdupa(data); 05730 05731 AST_STANDARD_APP_ARGS(args, parse); 05732 05733 if (ast_strlen_zero(args.queuename) || ast_strlen_zero(args.uniqueid) 05734 || ast_strlen_zero(args.membername) || ast_strlen_zero(args.event)) { 05735 ast_log(LOG_WARNING, "QueueLog requires arguments (queuename,uniqueid,membername,event[,additionalinfo])\n"); 05736 return -1; 05737 } 05738 05739 ast_queue_log(args.queuename, args.uniqueid, args.membername, args.event, 05740 "%s", args.params ? args.params : ""); 05741 05742 return 0; 05743 }
static int queue_cmp_cb | ( | void * | obj, | |
void * | arg, | |||
int | flags | |||
) | [static] |
Definition at line 1260 of file app_queue.c.
References CMP_MATCH, CMP_STOP, and call_queue::name.
Referenced by load_module().
01261 { 01262 struct call_queue *q = obj, *q2 = arg; 01263 return !strcasecmp(q->name, q2->name) ? CMP_MATCH | CMP_STOP : 0; 01264 }
static int queue_exec | ( | struct ast_channel * | chan, | |
const char * | 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 unless some condition (such as an expiration time) causes us to exit the queue.
Definition at line 5787 of file app_queue.c.
References call_queue::announcefrequency, args, AST_APP_ARG, ast_channel_lock, ast_channel_unlock, AST_CONTROL_RINGING, ast_debug, AST_DECLARE_APP_ARGS, ast_indicate(), AST_LIST_FIRST, ast_log(), ast_moh_start(), ast_queue_log(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), ast_verb, ast_channel::caller, queue_ent::chan, copy_rules(), queue_ent::expire, get_member_status(), ast_party_caller::id, 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, call_queue::leavewhenempty, LOG_WARNING, queue_ent::max_penalty, call_queue::membercount, queue_ent::min_penalty, queue_ent::moh, call_queue::name, ast_channel::name, ast_party_id::number, queue_ent::opos, queue_ent::parent, parse(), pbx_builtin_getvar_helper(), call_queue::periodicannouncefrequency, queue_ent::pos, queue_ent::pr, queue_ent::prio, queue_ent::qe_rules, QUEUE_LEAVEEMPTY, QUEUE_TIMEOUT, QUEUE_UNKNOWN, record_abandoned(), queue_ent::ring_when_ringing, S_COR, S_OR, say_periodic_announcement(), say_position(), set_queue_result(), queue_ent::start, status, stop, ast_party_number::str, penalty_rule::time, try_calling(), ast_channel::uniqueid, update_qe_rule(), update_realtime_members(), url, ast_party_number::valid, queue_ent::valid_digits, wait_a_bit(), and wait_our_turn().
Referenced by load_module().
05788 { 05789 int res=-1; 05790 int ringing=0; 05791 const char *user_priority; 05792 const char *max_penalty_str; 05793 const char *min_penalty_str; 05794 int prio; 05795 int qcontinue = 0; 05796 int max_penalty, min_penalty; 05797 enum queue_result reason = QUEUE_UNKNOWN; 05798 /* whether to exit Queue application after the timeout hits */ 05799 int tries = 0; 05800 int noption = 0; 05801 char *parse; 05802 int makeannouncement = 0; 05803 int position = 0; 05804 AST_DECLARE_APP_ARGS(args, 05805 AST_APP_ARG(queuename); 05806 AST_APP_ARG(options); 05807 AST_APP_ARG(url); 05808 AST_APP_ARG(announceoverride); 05809 AST_APP_ARG(queuetimeoutstr); 05810 AST_APP_ARG(agi); 05811 AST_APP_ARG(macro); 05812 AST_APP_ARG(gosub); 05813 AST_APP_ARG(rule); 05814 AST_APP_ARG(position); 05815 ); 05816 /* Our queue entry */ 05817 struct queue_ent qe = { 0 }; 05818 05819 if (ast_strlen_zero(data)) { 05820 ast_log(LOG_WARNING, "Queue requires an argument: queuename[,options[,URL[,announceoverride[,timeout[,agi[,macro[,gosub[,rule[,position]]]]]]]]]\n"); 05821 return -1; 05822 } 05823 05824 parse = ast_strdupa(data); 05825 AST_STANDARD_APP_ARGS(args, parse); 05826 05827 /* Setup our queue entry */ 05828 qe.start = time(NULL); 05829 05830 /* set the expire time based on the supplied timeout; */ 05831 if (!ast_strlen_zero(args.queuetimeoutstr)) 05832 qe.expire = qe.start + atoi(args.queuetimeoutstr); 05833 else 05834 qe.expire = 0; 05835 05836 /* Get the priority from the variable ${QUEUE_PRIO} */ 05837 ast_channel_lock(chan); 05838 user_priority = pbx_builtin_getvar_helper(chan, "QUEUE_PRIO"); 05839 if (user_priority) { 05840 if (sscanf(user_priority, "%30d", &prio) == 1) { 05841 ast_debug(1, "%s: Got priority %d from ${QUEUE_PRIO}.\n", chan->name, prio); 05842 } else { 05843 ast_log(LOG_WARNING, "${QUEUE_PRIO}: Invalid value (%s), channel %s.\n", 05844 user_priority, chan->name); 05845 prio = 0; 05846 } 05847 } else { 05848 ast_debug(3, "NO QUEUE_PRIO variable found. Using default.\n"); 05849 prio = 0; 05850 } 05851 05852 /* Get the maximum penalty from the variable ${QUEUE_MAX_PENALTY} */ 05853 05854 if ((max_penalty_str = pbx_builtin_getvar_helper(chan, "QUEUE_MAX_PENALTY"))) { 05855 if (sscanf(max_penalty_str, "%30d", &max_penalty) == 1) { 05856 ast_debug(1, "%s: Got max penalty %d from ${QUEUE_MAX_PENALTY}.\n", chan->name, max_penalty); 05857 } else { 05858 ast_log(LOG_WARNING, "${QUEUE_MAX_PENALTY}: Invalid value (%s), channel %s.\n", 05859 max_penalty_str, chan->name); 05860 max_penalty = 0; 05861 } 05862 } else { 05863 max_penalty = 0; 05864 } 05865 05866 if ((min_penalty_str = pbx_builtin_getvar_helper(chan, "QUEUE_MIN_PENALTY"))) { 05867 if (sscanf(min_penalty_str, "%30d", &min_penalty) == 1) { 05868 ast_debug(1, "%s: Got min penalty %d from ${QUEUE_MIN_PENALTY}.\n", chan->name, min_penalty); 05869 } else { 05870 ast_log(LOG_WARNING, "${QUEUE_MIN_PENALTY}: Invalid value (%s), channel %s.\n", 05871 min_penalty_str, chan->name); 05872 min_penalty = 0; 05873 } 05874 } else { 05875 min_penalty = 0; 05876 } 05877 ast_channel_unlock(chan); 05878 05879 if (args.options && (strchr(args.options, 'r'))) 05880 ringing = 1; 05881 05882 if (ringing != 1 && args.options && (strchr(args.options, 'R'))) { 05883 qe.ring_when_ringing = 1; 05884 } 05885 05886 if (args.options && (strchr(args.options, 'c'))) 05887 qcontinue = 1; 05888 05889 if (args.position) { 05890 position = atoi(args.position); 05891 if (position < 0) { 05892 ast_log(LOG_WARNING, "Invalid position '%s' given for call to queue '%s'. Assuming no preference for position\n", args.position, args.queuename); 05893 position = 0; 05894 } 05895 } 05896 05897 ast_debug(1, "queue: %s, options: %s, url: %s, announce: %s, expires: %ld, priority: %d\n", 05898 args.queuename, args.options, args.url, args.announceoverride, (long)qe.expire, prio); 05899 05900 qe.chan = chan; 05901 qe.prio = prio; 05902 qe.max_penalty = max_penalty; 05903 qe.min_penalty = min_penalty; 05904 qe.last_pos_said = 0; 05905 qe.last_pos = 0; 05906 qe.last_periodic_announce_time = time(NULL); 05907 qe.last_periodic_announce_sound = 0; 05908 qe.valid_digits = 0; 05909 if (join_queue(args.queuename, &qe, &reason, position)) { 05910 ast_log(LOG_WARNING, "Unable to join queue '%s'\n", args.queuename); 05911 set_queue_result(chan, reason); 05912 return 0; 05913 } 05914 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "ENTERQUEUE", "%s|%s|%d", 05915 S_OR(args.url, ""), 05916 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, ""), 05917 qe.opos); 05918 copy_rules(&qe, args.rule); 05919 qe.pr = AST_LIST_FIRST(&qe.qe_rules); 05920 check_turns: 05921 if (ringing) { 05922 ast_indicate(chan, AST_CONTROL_RINGING); 05923 } else { 05924 ast_moh_start(chan, qe.moh, NULL); 05925 } 05926 05927 /* This is the wait loop for callers 2 through maxlen */ 05928 res = wait_our_turn(&qe, ringing, &reason); 05929 if (res) { 05930 goto stop; 05931 } 05932 05933 makeannouncement = 0; 05934 05935 for (;;) { 05936 /* This is the wait loop for the head caller*/ 05937 /* To exit, they may get their call answered; */ 05938 /* they may dial a digit from the queue context; */ 05939 /* or, they may timeout. */ 05940 05941 /* Leave if we have exceeded our queuetimeout */ 05942 if (qe.expire && (time(NULL) >= qe.expire)) { 05943 record_abandoned(&qe); 05944 reason = QUEUE_TIMEOUT; 05945 res = 0; 05946 ast_queue_log(args.queuename, chan->uniqueid,"NONE", "EXITWITHTIMEOUT", "%d|%d|%ld", 05947 qe.pos, qe.opos, (long) time(NULL) - qe.start); 05948 break; 05949 } 05950 05951 if (makeannouncement) { 05952 /* Make a position announcement, if enabled */ 05953 if (qe.parent->announcefrequency) 05954 if ((res = say_position(&qe,ringing))) 05955 goto stop; 05956 } 05957 makeannouncement = 1; 05958 05959 /* Make a periodic announcement, if enabled */ 05960 if (qe.parent->periodicannouncefrequency) 05961 if ((res = say_periodic_announcement(&qe,ringing))) 05962 goto stop; 05963 05964 /* Leave if we have exceeded our queuetimeout */ 05965 if (qe.expire && (time(NULL) >= qe.expire)) { 05966 record_abandoned(&qe); 05967 reason = QUEUE_TIMEOUT; 05968 res = 0; 05969 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHTIMEOUT", "%d", qe.pos); 05970 break; 05971 } 05972 05973 /* see if we need to move to the next penalty level for this queue */ 05974 while (qe.pr && ((time(NULL) - qe.start) > qe.pr->time)) { 05975 update_qe_rule(&qe); 05976 } 05977 05978 /* Try calling all queue members for 'timeout' seconds */ 05979 res = try_calling(&qe, args.options, args.announceoverride, args.url, &tries, &noption, args.agi, args.macro, args.gosub, ringing); 05980 if (res) { 05981 goto stop; 05982 } 05983 05984 if (qe.parent->leavewhenempty) { 05985 int status = 0; 05986 if ((status = get_member_status(qe.parent, qe.max_penalty, qe.min_penalty, qe.parent->leavewhenempty))) { 05987 record_abandoned(&qe); 05988 reason = QUEUE_LEAVEEMPTY; 05989 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe.pos, qe.opos, (long)(time(NULL) - qe.start)); 05990 res = 0; 05991 break; 05992 } 05993 } 05994 05995 /* exit after 'timeout' cycle if 'n' option enabled */ 05996 if (noption && tries >= qe.parent->membercount) { 05997 ast_verb(3, "Exiting on time-out cycle\n"); 05998 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHTIMEOUT", "%d", qe.pos); 05999 record_abandoned(&qe); 06000 reason = QUEUE_TIMEOUT; 06001 res = 0; 06002 break; 06003 } 06004 06005 06006 /* Leave if we have exceeded our queuetimeout */ 06007 if (qe.expire && (time(NULL) >= qe.expire)) { 06008 record_abandoned(&qe); 06009 reason = QUEUE_TIMEOUT; 06010 res = 0; 06011 ast_queue_log(qe.parent->name, qe.chan->uniqueid,"NONE", "EXITWITHTIMEOUT", "%d|%d|%ld", qe.pos, qe.opos, (long) time(NULL) - qe.start); 06012 break; 06013 } 06014 06015 /* If using dynamic realtime members, we should regenerate the member list for this queue */ 06016 update_realtime_members(qe.parent); 06017 /* OK, we didn't get anybody; wait for 'retry' seconds; may get a digit to exit with */ 06018 res = wait_a_bit(&qe); 06019 if (res) 06020 goto stop; 06021 06022 /* Since this is a priority queue and 06023 * it is not sure that we are still at the head 06024 * of the queue, go and check for our turn again. 06025 */ 06026 if (!is_our_turn(&qe)) { 06027 ast_debug(1, "Darn priorities, going back in queue (%s)!\n", qe.chan->name); 06028 goto check_turns; 06029 } 06030 } 06031 06032 stop: 06033 if (res) { 06034 if (res < 0) { 06035 if (!qe.handled) { 06036 record_abandoned(&qe); 06037 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "ABANDON", 06038 "%d|%d|%ld", qe.pos, qe.opos, 06039 (long) time(NULL) - qe.start); 06040 res = -1; 06041 } else if (qcontinue) { 06042 reason = QUEUE_CONTINUE; 06043 res = 0; 06044 } 06045 } else if (qe.valid_digits) { 06046 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHKEY", 06047 "%s|%d", qe.digits, qe.pos); 06048 } 06049 } 06050 06051 /* Don't allow return code > 0 */ 06052 if (res >= 0) { 06053 res = 0; 06054 if (ringing) { 06055 ast_indicate(chan, -1); 06056 } else { 06057 ast_moh_stop(chan); 06058 } 06059 ast_stopstream(chan); 06060 } 06061 06062 set_queue_variables(qe.parent, qe.chan); 06063 06064 leave_queue(&qe); 06065 if (reason != QUEUE_UNKNOWN) 06066 set_queue_result(chan, reason); 06067 06068 if (qe.parent) { 06069 /* every queue_ent is given a reference to it's parent call_queue when it joins the queue. 06070 * This ref must be taken away right before the queue_ent is destroyed. In this case 06071 * the queue_ent is about to be returned on the stack */ 06072 qe.parent = queue_unref(qe.parent); 06073 } 06074 06075 return res; 06076 }
static int queue_function_exists | ( | struct ast_channel * | chan, | |
const char * | cmd, | |||
char * | data, | |||
char * | buf, | |||
size_t | len | |||
) | [static] |
Check if a given queue exists.
Definition at line 6130 of file app_queue.c.
References ast_log(), ast_strlen_zero(), load_realtime_queue(), LOG_ERROR, and queue_t_unref.
06131 { 06132 struct call_queue *q; 06133 06134 buf[0] = '\0'; 06135 06136 if (ast_strlen_zero(data)) { 06137 ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd); 06138 return -1; 06139 } 06140 q = load_realtime_queue(data); 06141 snprintf(buf, len, "%d", q != NULL? 1 : 0); 06142 if (q) { 06143 queue_t_unref(q, "Done with temporary reference in QUEUE_EXISTS()"); 06144 } 06145 06146 return 0; 06147 }
static int queue_function_memberpenalty_read | ( | struct ast_channel * | chan, | |
const char * | cmd, | |||
char * | data, | |||
char * | buf, | |||
size_t | len | |||
) | [static] |
Dialplan function QUEUE_MEMBER_PENALTY() Gets the members penalty.
Definition at line 6348 of file app_queue.c.
References args, AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_log(), AST_STANDARD_APP_ARGS, ast_strlen_zero(), get_member_penalty(), and LOG_ERROR.
06349 { 06350 int penalty; 06351 AST_DECLARE_APP_ARGS(args, 06352 AST_APP_ARG(queuename); 06353 AST_APP_ARG(interface); 06354 ); 06355 /* Make sure the returned value on error is NULL. */ 06356 buf[0] = '\0'; 06357 06358 if (ast_strlen_zero(data)) { 06359 ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n"); 06360 return -1; 06361 } 06362 06363 AST_STANDARD_APP_ARGS(args, data); 06364 06365 if (args.argc < 2) { 06366 ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n"); 06367 return -1; 06368 } 06369 06370 penalty = get_member_penalty (args.queuename, args.interface); 06371 06372 if (penalty >= 0) /* remember that buf is already '\0' */ 06373 snprintf (buf, len, "%d", penalty); 06374 06375 return 0; 06376 }
static int queue_function_memberpenalty_write | ( | struct ast_channel * | chan, | |
const char * | cmd, | |||
char * | data, | |||
const char * | value | |||
) | [static] |
Dialplan function QUEUE_MEMBER_PENALTY() Sets the members penalty.
Definition at line 6379 of file app_queue.c.
References args, AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_log(), AST_STANDARD_APP_ARGS, ast_strlen_zero(), LOG_ERROR, and set_member_penalty().
06380 { 06381 int penalty; 06382 AST_DECLARE_APP_ARGS(args, 06383 AST_APP_ARG(queuename); 06384 AST_APP_ARG(interface); 06385 ); 06386 06387 if (ast_strlen_zero(data)) { 06388 ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n"); 06389 return -1; 06390 } 06391 06392 AST_STANDARD_APP_ARGS(args, data); 06393 06394 if (args.argc < 2) { 06395 ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n"); 06396 return -1; 06397 } 06398 06399 penalty = atoi(value); 06400 06401 if (ast_strlen_zero(args.interface)) { 06402 ast_log (LOG_ERROR, "<interface> parameter can't be null\n"); 06403 return -1; 06404 } 06405 06406 /* if queuename = NULL then penalty will be set for interface in all the queues. */ 06407 if (set_member_penalty(args.queuename, args.interface, penalty)) { 06408 ast_log(LOG_ERROR, "Invalid interface, queue or penalty\n"); 06409 return -1; 06410 } 06411 06412 return 0; 06413 }
static int queue_function_qac | ( | struct ast_channel * | chan, | |
const char * | cmd, | |||
char * | data, | |||
char * | buf, | |||
size_t | len | |||
) | [static] |
Get number either busy / free / ready or total members of a specific queue.
number | of members (busy / free / ready / total) | |
-1 | on error |
Definition at line 6154 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_log(), ast_strlen_zero(), call_queue::count, member::lastcall, load_realtime_queue(), LOG_ERROR, LOG_WARNING, member::paused, queue_t_unref, and member::status.
06155 { 06156 int count = 0; 06157 struct member *m; 06158 struct ao2_iterator mem_iter; 06159 struct call_queue *q; 06160 char *option; 06161 06162 if (ast_strlen_zero(data)) { 06163 ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd); 06164 return -1; 06165 } 06166 06167 if ((option = strchr(data, ','))) 06168 *option++ = '\0'; 06169 else 06170 option = "logged"; 06171 if ((q = load_realtime_queue(data))) { 06172 ao2_lock(q); 06173 if (!strcasecmp(option, "logged")) { 06174 mem_iter = ao2_iterator_init(q->members, 0); 06175 while ((m = ao2_iterator_next(&mem_iter))) { 06176 /* Count the agents who are logged in and presently answering calls */ 06177 if ((m->status != AST_DEVICE_UNAVAILABLE) && (m->status != AST_DEVICE_INVALID)) { 06178 count++; 06179 } 06180 ao2_ref(m, -1); 06181 } 06182 ao2_iterator_destroy(&mem_iter); 06183 } else if (!strcasecmp(option, "free")) { 06184 mem_iter = ao2_iterator_init(q->members, 0); 06185 while ((m = ao2_iterator_next(&mem_iter))) { 06186 /* Count the agents who are logged in and presently answering calls */ 06187 if ((m->status == AST_DEVICE_NOT_INUSE) && (!m->paused)) { 06188 count++; 06189 } 06190 ao2_ref(m, -1); 06191 } 06192 ao2_iterator_destroy(&mem_iter); 06193 } else if (!strcasecmp(option, "ready")) { 06194 time_t now; 06195 time(&now); 06196 mem_iter = ao2_iterator_init(q->members, 0); 06197 while ((m = ao2_iterator_next(&mem_iter))) { 06198 /* Count the agents who are logged in, not paused and not wrapping up */ 06199 if ((m->status == AST_DEVICE_NOT_INUSE) && (!m->paused) && 06200 !(m->lastcall && q->wrapuptime && ((now - q->wrapuptime) < m->lastcall))) { 06201 count++; 06202 } 06203 ao2_ref(m, -1); 06204 } 06205 ao2_iterator_destroy(&mem_iter); 06206 } else /* must be "count" */ 06207 count = q->membercount; 06208 ao2_unlock(q); 06209 queue_t_unref(q, "Done with temporary reference in QUEUE_MEMBER()"); 06210 } else 06211 ast_log(LOG_WARNING, "queue %s was not found\n", data); 06212 06213 snprintf(buf, len, "%d", count); 06214 06215 return 0; 06216 }
static int queue_function_qac_dep | ( | struct ast_channel * | chan, | |
const char * | cmd, | |||
char * | data, | |||
char * | buf, | |||
size_t | len | |||
) | [static] |
Get the total number of members in a specific queue (Deprecated).
number | of members | |
-1 | on error |
Definition at line 6223 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, ast_log(), ast_strlen_zero(), call_queue::count, load_realtime_queue(), LOG_ERROR, LOG_NOTICE, LOG_WARNING, queue_t_unref, and member::status.
06224 { 06225 int count = 0; 06226 struct member *m; 06227 struct call_queue *q; 06228 struct ao2_iterator mem_iter; 06229 static int depflag = 1; 06230 06231 if (depflag) { 06232 depflag = 0; 06233 ast_log(LOG_NOTICE, "The function QUEUE_MEMBER_COUNT has been deprecated in favor of the QUEUE_MEMBER function and will not be in further releases.\n"); 06234 } 06235 06236 if (ast_strlen_zero(data)) { 06237 ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd); 06238 return -1; 06239 } 06240 06241 if ((q = load_realtime_queue(data))) { 06242 ao2_lock(q); 06243 mem_iter = ao2_iterator_init(q->members, 0); 06244 while ((m = ao2_iterator_next(&mem_iter))) { 06245 /* Count the agents who are logged in and presently answering calls */ 06246 if ((m->status != AST_DEVICE_UNAVAILABLE) && (m->status != AST_DEVICE_INVALID)) { 06247 count++; 06248 } 06249 ao2_ref(m, -1); 06250 } 06251 ao2_iterator_destroy(&mem_iter); 06252 ao2_unlock(q); 06253 queue_t_unref(q, "Done with temporary reference in QUEUE_MEMBER_COUNT"); 06254 } else 06255 ast_log(LOG_WARNING, "queue %s was not found\n", data); 06256 06257 snprintf(buf, len, "%d", count); 06258 06259 return 0; 06260 }
static int queue_function_queuememberlist | ( | struct ast_channel * | chan, | |
const char * | cmd, | |||
char * | data, | |||
char * | buf, | |||
size_t | len | |||
) | [static] |
Dialplan function QUEUE_MEMBER_LIST() Get list of members in a specific queue.
Definition at line 6299 of file app_queue.c.
References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_lock, ao2_ref, ao2_t_find, ao2_unlock, ast_log(), ast_strlen_zero(), member::interface, LOG_ERROR, LOG_WARNING, call_queue::members, OBJ_POINTER, and queue_t_unref.
06300 { 06301 struct call_queue *q, tmpq = { 06302 .name = data, 06303 }; 06304 struct member *m; 06305 06306 /* Ensure an otherwise empty list doesn't return garbage */ 06307 buf[0] = '\0'; 06308 06309 if (ast_strlen_zero(data)) { 06310 ast_log(LOG_ERROR, "QUEUE_MEMBER_LIST requires an argument: queuename\n"); 06311 return -1; 06312 } 06313 06314 if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Find for QUEUE_MEMBER_LIST()"))) { 06315 int buflen = 0, count = 0; 06316 struct ao2_iterator mem_iter = ao2_iterator_init(q->members, 0); 06317 06318 ao2_lock(q); 06319 while ((m = ao2_iterator_next(&mem_iter))) { 06320 /* strcat() is always faster than printf() */ 06321 if (count++) { 06322 strncat(buf + buflen, ",", len - buflen - 1); 06323 buflen++; 06324 } 06325 strncat(buf + buflen, m->interface, len - buflen - 1); 06326 buflen += strlen(m->interface); 06327 /* Safeguard against overflow (negative length) */ 06328 if (buflen >= len - 2) { 06329 ao2_ref(m, -1); 06330 ast_log(LOG_WARNING, "Truncating list\n"); 06331 break; 06332 } 06333 ao2_ref(m, -1); 06334 } 06335 ao2_iterator_destroy(&mem_iter); 06336 ao2_unlock(q); 06337 queue_t_unref(q, "Done with QUEUE_MEMBER_LIST()"); 06338 } else 06339 ast_log(LOG_WARNING, "queue %s was not found\n", data); 06340 06341 /* We should already be terminated, but let's make sure. */ 06342 buf[len - 1] = '\0'; 06343 06344 return 0; 06345 }
static int queue_function_queuewaitingcount | ( | struct ast_channel * | chan, | |
const char * | cmd, | |||
char * | data, | |||
char * | buf, | |||
size_t | len | |||
) | [static] |
Dialplan function QUEUE_WAITING_COUNT() Get number callers waiting in a specific queue.
Definition at line 6263 of file app_queue.c.
References ao2_lock, ao2_t_find, ao2_unlock, ast_load_realtime(), ast_log(), ast_strlen_zero(), ast_variables_destroy(), call_queue::count, LOG_ERROR, LOG_WARNING, OBJ_POINTER, queue_t_unref, SENTINEL, and var.
06264 { 06265 int count = 0; 06266 struct call_queue *q, tmpq = { 06267 .name = data, 06268 }; 06269 struct ast_variable *var = NULL; 06270 06271 buf[0] = '\0'; 06272 06273 if (ast_strlen_zero(data)) { 06274 ast_log(LOG_ERROR, "QUEUE_WAITING_COUNT requires an argument: queuename\n"); 06275 return -1; 06276 } 06277 06278 if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Find for QUEUE_WAITING_COUNT()"))) { 06279 ao2_lock(q); 06280 count = q->count; 06281 ao2_unlock(q); 06282 queue_t_unref(q, "Done with reference in QUEUE_WAITING_COUNT()"); 06283 } else if ((var = ast_load_realtime("queues", "name", data, SENTINEL))) { 06284 /* if the queue is realtime but was not found in memory, this 06285 * means that the queue had been deleted from memory since it was 06286 * "dead." This means it has a 0 waiting count 06287 */ 06288 count = 0; 06289 ast_variables_destroy(var); 06290 } else 06291 ast_log(LOG_WARNING, "queue %s was not found\n", data); 06292 06293 snprintf(buf, len, "%d", count); 06294 06295 return 0; 06296 }
static int queue_function_var | ( | struct ast_channel * | chan, | |
const char * | cmd, | |||
char * | data, | |||
char * | buf, | |||
size_t | len | |||
) | [static] |
create interface var with all queue details.
0 | on success | |
-1 | on error |
Definition at line 6083 of file app_queue.c.
References ao2_lock, ao2_t_find, ao2_unlock, ast_log(), ast_strlen_zero(), call_queue::callsabandoned, call_queue::callscompleted, call_queue::callscompletedinsl, call_queue::count, call_queue::holdtime, int2strat(), LOG_ERROR, LOG_WARNING, call_queue::maxlen, OBJ_POINTER, pbx_builtin_setvar_multiple(), queue_t_unref, call_queue::servicelevel, call_queue::setqueuevar, call_queue::strategy, and call_queue::talktime.
06084 { 06085 int res = -1; 06086 struct call_queue *q, tmpq = { 06087 .name = data, 06088 }; 06089 06090 char interfacevar[256] = ""; 06091 float sl = 0; 06092 06093 if (ast_strlen_zero(data)) { 06094 ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd); 06095 return -1; 06096 } 06097 06098 if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Find for QUEUE() function"))) { 06099 ao2_lock(q); 06100 if (q->setqueuevar) { 06101 sl = 0; 06102 res = 0; 06103 06104 if (q->callscompleted > 0) { 06105 sl = 100 * ((float) q->callscompletedinsl / (float) q->callscompleted); 06106 } 06107 06108 snprintf(interfacevar, sizeof(interfacevar), 06109 "QUEUEMAX=%d,QUEUESTRATEGY=%s,QUEUECALLS=%d,QUEUEHOLDTIME=%d,QUEUETALKTIME=%d,QUEUECOMPLETED=%d,QUEUEABANDONED=%d,QUEUESRVLEVEL=%d,QUEUESRVLEVELPERF=%2.1f", 06110 q->maxlen, int2strat(q->strategy), q->count, q->holdtime, q->talktime, q->callscompleted, q->callsabandoned, q->servicelevel, sl); 06111 06112 pbx_builtin_setvar_multiple(chan, interfacevar); 06113 } 06114 06115 ao2_unlock(q); 06116 queue_t_unref(q, "Done with QUEUE() function"); 06117 } else { 06118 ast_log(LOG_WARNING, "queue %s was not found\n", data); 06119 } 06120 06121 snprintf(buf, len, "%d", res); 06122 06123 return 0; 06124 }
static int queue_hash_cb | ( | const void * | obj, | |
const int | flags | |||
) | [static] |
Definition at line 1253 of file app_queue.c.
References ast_str_case_hash(), and call_queue::name.
Referenced by load_module().
01254 { 01255 const struct call_queue *q = obj; 01256 01257 return ast_str_case_hash(q->name); 01258 }
static struct call_queue* queue_ref | ( | struct call_queue * | q | ) | [inline, static] |
Definition at line 1278 of file app_queue.c.
References ao2_ref.
Referenced by insert_entry().
01279 { 01280 ao2_ref(q, 1); 01281 return q; 01282 }
static void queue_set_global_params | ( | struct ast_config * | cfg | ) | [static] |
Set the global queue parameters as defined in the "general" section of queues.conf
Definition at line 6505 of file app_queue.c.
References ast_true(), and ast_variable_retrieve().
Referenced by reload_queues().
06506 { 06507 const char *general_val = NULL; 06508 queue_persistent_members = 0; 06509 if ((general_val = ast_variable_retrieve(cfg, "general", "persistentmembers"))) 06510 queue_persistent_members = ast_true(general_val); 06511 autofill_default = 0; 06512 if ((general_val = ast_variable_retrieve(cfg, "general", "autofill"))) 06513 autofill_default = ast_true(general_val); 06514 montype_default = 0; 06515 if ((general_val = ast_variable_retrieve(cfg, "general", "monitor-type"))) { 06516 if (!strcasecmp(general_val, "mixmonitor")) 06517 montype_default = 1; 06518 } 06519 update_cdr = 0; 06520 if ((general_val = ast_variable_retrieve(cfg, "general", "updatecdr"))) 06521 update_cdr = ast_true(general_val); 06522 shared_lastcall = 0; 06523 if ((general_val = ast_variable_retrieve(cfg, "general", "shared_lastcall"))) 06524 shared_lastcall = ast_true(general_val); 06525 }
static void queue_set_param | ( | struct call_queue * | q, | |
const char * | param, | |||
const char * | val, | |||
int | linenum, | |||
int | failunknown | |||
) | [static] |
Configure a queue parameter.
The failunknown flag is set for config files (and static realtime) to show errors for unknown parameters. It is cleared for dynamic realtime to allow extra fields in the tables.
Definition at line 1876 of file app_queue.c.
References queue_ent::announce, call_queue::announcefrequency, call_queue::announceholdtime, ANNOUNCEHOLDTIME_ALWAYS, ANNOUNCEHOLDTIME_ONCE, call_queue::announceposition, ANNOUNCEPOSITION_LIMIT, ANNOUNCEPOSITION_MORE_THAN, ANNOUNCEPOSITION_NO, ANNOUNCEPOSITION_YES, call_queue::announcepositionlimit, ast_copy_string(), ast_debug, ast_log(), ast_str_create(), ast_str_set(), ast_strdupa, ast_string_field_set, ast_true(), call_queue::autofill, call_queue::autopause, autopause2int(), queue_ent::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::minannouncefrequency, call_queue::monfmt, call_queue::montype, call_queue::name, call_queue::numperiodicannounce, parse_empty_options(), call_queue::penaltymemberslimit, call_queue::periodicannouncefrequency, QUEUE_EVENT_VARIABLES, QUEUE_STRATEGY_LINEAR, QUEUE_STRATEGY_RINGALL, call_queue::randomperiodicannounce, call_queue::relativeperiodicannounce, call_queue::reportholdtime, call_queue::retry, call_queue::ringinuse, call_queue::roundingseconds, call_queue::servicelevel, call_queue::setinterfacevar, call_queue::setqueueentryvar, call_queue::setqueuevar, call_queue::sound_periodicannounce, strat2int(), call_queue::strategy, strsep(), call_queue::timeout, TIMEOUT_PRIORITY_APP, TIMEOUT_PRIORITY_CONF, call_queue::timeoutpriority, call_queue::timeoutrestart, call_queue::weight, and call_queue::wrapuptime.
Referenced by reload_single_queue().
01877 { 01878 if (!strcasecmp(param, "musicclass") || 01879 !strcasecmp(param, "music") || !strcasecmp(param, "musiconhold")) { 01880 ast_string_field_set(q, moh, val); 01881 } else if (!strcasecmp(param, "announce")) { 01882 ast_string_field_set(q, announce, val); 01883 } else if (!strcasecmp(param, "context")) { 01884 ast_string_field_set(q, context, val); 01885 } else if (!strcasecmp(param, "timeout")) { 01886 q->timeout = atoi(val); 01887 if (q->timeout < 0) 01888 q->timeout = DEFAULT_TIMEOUT; 01889 } else if (!strcasecmp(param, "ringinuse")) { 01890 q->ringinuse = ast_true(val); 01891 } else if (!strcasecmp(param, "setinterfacevar")) { 01892 q->setinterfacevar = ast_true(val); 01893 } else if (!strcasecmp(param, "setqueuevar")) { 01894 q->setqueuevar = ast_true(val); 01895 } else if (!strcasecmp(param, "setqueueentryvar")) { 01896 q->setqueueentryvar = ast_true(val); 01897 } else if (!strcasecmp(param, "monitor-format")) { 01898 ast_copy_string(q->monfmt, val, sizeof(q->monfmt)); 01899 } else if (!strcasecmp(param, "membermacro")) { 01900 ast_string_field_set(q, membermacro, val); 01901 } else if (!strcasecmp(param, "membergosub")) { 01902 ast_string_field_set(q, membergosub, val); 01903 } else if (!strcasecmp(param, "queue-youarenext")) { 01904 ast_string_field_set(q, sound_next, val); 01905 } else if (!strcasecmp(param, "queue-thereare")) { 01906 ast_string_field_set(q, sound_thereare, val); 01907 } else if (!strcasecmp(param, "queue-callswaiting")) { 01908 ast_string_field_set(q, sound_calls, val); 01909 } else if (!strcasecmp(param, "queue-quantity1")) { 01910 ast_string_field_set(q, queue_quantity1, val); 01911 } else if (!strcasecmp(param, "queue-quantity2")) { 01912 ast_string_field_set(q, queue_quantity2, val); 01913 } else if (!strcasecmp(param, "queue-holdtime")) { 01914 ast_string_field_set(q, sound_holdtime, val); 01915 } else if (!strcasecmp(param, "queue-minutes")) { 01916 ast_string_field_set(q, sound_minutes, val); 01917 } else if (!strcasecmp(param, "queue-minute")) { 01918 ast_string_field_set(q, sound_minute, val); 01919 } else if (!strcasecmp(param, "queue-seconds")) { 01920 ast_string_field_set(q, sound_seconds, val); 01921 } else if (!strcasecmp(param, "queue-thankyou")) { 01922 ast_string_field_set(q, sound_thanks, val); 01923 } else if (!strcasecmp(param, "queue-callerannounce")) { 01924 ast_string_field_set(q, sound_callerannounce, val); 01925 } else if (!strcasecmp(param, "queue-reporthold")) { 01926 ast_string_field_set(q, sound_reporthold, val); 01927 } else if (!strcasecmp(param, "announce-frequency")) { 01928 q->announcefrequency = atoi(val); 01929 } else if (!strcasecmp(param, "min-announce-frequency")) { 01930 q->minannouncefrequency = atoi(val); 01931 ast_debug(1, "%s=%s for queue '%s'\n", param, val, q->name); 01932 } else if (!strcasecmp(param, "announce-round-seconds")) { 01933 q->roundingseconds = atoi(val); 01934 /* Rounding to any other values just doesn't make sense... */ 01935 if (!(q->roundingseconds == 0 || q->roundingseconds == 5 || q->roundingseconds == 10 01936 || q->roundingseconds == 15 || q->roundingseconds == 20 || q->roundingseconds == 30)) { 01937 if (linenum >= 0) { 01938 ast_log(LOG_WARNING, "'%s' isn't a valid value for %s " 01939 "using 0 instead for queue '%s' at line %d of queues.conf\n", 01940 val, param, q->name, linenum); 01941 } else { 01942 ast_log(LOG_WARNING, "'%s' isn't a valid value for %s " 01943 "using 0 instead for queue '%s'\n", val, param, q->name); 01944 } 01945 q->roundingseconds=0; 01946 } 01947 } else if (!strcasecmp(param, "announce-holdtime")) { 01948 if (!strcasecmp(val, "once")) 01949 q->announceholdtime = ANNOUNCEHOLDTIME_ONCE; 01950 else if (ast_true(val)) 01951 q->announceholdtime = ANNOUNCEHOLDTIME_ALWAYS; 01952 else 01953 q->announceholdtime = 0; 01954 } else if (!strcasecmp(param, "announce-position")) { 01955 if (!strcasecmp(val, "limit")) 01956 q->announceposition = ANNOUNCEPOSITION_LIMIT; 01957 else if (!strcasecmp(val, "more")) 01958 q->announceposition = ANNOUNCEPOSITION_MORE_THAN; 01959 else if (ast_true(val)) 01960 q->announceposition = ANNOUNCEPOSITION_YES; 01961 else 01962 q->announceposition = ANNOUNCEPOSITION_NO; 01963 } else if (!strcasecmp(param, "announce-position-limit")) { 01964 q->announcepositionlimit = atoi(val); 01965 } else if (!strcasecmp(param, "periodic-announce")) { 01966 if (strchr(val, ',')) { 01967 char *s, *buf = ast_strdupa(val); 01968 unsigned int i = 0; 01969 01970 while ((s = strsep(&buf, ",|"))) { 01971 if (!q->sound_periodicannounce[i]) 01972 q->sound_periodicannounce[i] = ast_str_create(16); 01973 ast_str_set(&q->sound_periodicannounce[i], 0, "%s", s); 01974 i++; 01975 if (i == MAX_PERIODIC_ANNOUNCEMENTS) 01976 break; 01977 } 01978 q->numperiodicannounce = i; 01979 } else { 01980 ast_str_set(&q->sound_periodicannounce[0], 0, "%s", val); 01981 q->numperiodicannounce = 1; 01982 } 01983 } else if (!strcasecmp(param, "periodic-announce-frequency")) { 01984 q->periodicannouncefrequency = atoi(val); 01985 } else if (!strcasecmp(param, "relative-periodic-announce")) { 01986 q->relativeperiodicannounce = ast_true(val); 01987 } else if (!strcasecmp(param, "random-periodic-announce")) { 01988 q->randomperiodicannounce = ast_true(val); 01989 } else if (!strcasecmp(param, "retry")) { 01990 q->retry = atoi(val); 01991 if (q->retry <= 0) 01992 q->retry = DEFAULT_RETRY; 01993 } else if (!strcasecmp(param, "wrapuptime")) { 01994 q->wrapuptime = atoi(val); 01995 } else if (!strcasecmp(param, "penaltymemberslimit")) { 01996 if ((sscanf(val, "%10d", &q->penaltymemberslimit) != 1)) { 01997 q->penaltymemberslimit = 0; 01998 } 01999 } else if (!strcasecmp(param, "autofill")) { 02000 q->autofill = ast_true(val); 02001 } else if (!strcasecmp(param, "monitor-type")) { 02002 if (!strcasecmp(val, "mixmonitor")) 02003 q->montype = 1; 02004 } else if (!strcasecmp(param, "autopause")) { 02005 q->autopause = autopause2int(val); 02006 } else if (!strcasecmp(param, "maxlen")) { 02007 q->maxlen = atoi(val); 02008 if (q->maxlen < 0) 02009 q->maxlen = 0; 02010 } else if (!strcasecmp(param, "servicelevel")) { 02011 q->servicelevel= atoi(val); 02012 } else if (!strcasecmp(param, "strategy")) { 02013 int strategy; 02014 02015 /* We are a static queue and already have set this, no need to do it again */ 02016 if (failunknown) { 02017 return; 02018 } 02019 strategy = strat2int(val); 02020 if (strategy < 0) { 02021 ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n", 02022 val, q->name); 02023 q->strategy = QUEUE_STRATEGY_RINGALL; 02024 } 02025 if (strategy == q->strategy) { 02026 return; 02027 } 02028 if (strategy == QUEUE_STRATEGY_LINEAR) { 02029 ast_log(LOG_WARNING, "Changing to the linear strategy currently requires asterisk to be restarted.\n"); 02030 return; 02031 } 02032 q->strategy = strategy; 02033 } else if (!strcasecmp(param, "joinempty")) { 02034 parse_empty_options(val, &q->joinempty, 1); 02035 } else if (!strcasecmp(param, "leavewhenempty")) { 02036 parse_empty_options(val, &q->leavewhenempty, 0); 02037 } else if (!strcasecmp(param, "eventmemberstatus")) { 02038 q->maskmemberstatus = !ast_true(val); 02039 } else if (!strcasecmp(param, "eventwhencalled")) { 02040 if (!strcasecmp(val, "vars")) { 02041 q->eventwhencalled = QUEUE_EVENT_VARIABLES; 02042 } else { 02043 q->eventwhencalled = ast_true(val) ? 1 : 0; 02044 } 02045 } else if (!strcasecmp(param, "reportholdtime")) { 02046 q->reportholdtime = ast_true(val); 02047 } else if (!strcasecmp(param, "memberdelay")) { 02048 q->memberdelay = atoi(val); 02049 } else if (!strcasecmp(param, "weight")) { 02050 q->weight = atoi(val); 02051 } else if (!strcasecmp(param, "timeoutrestart")) { 02052 q->timeoutrestart = ast_true(val); 02053 } else if (!strcasecmp(param, "defaultrule")) { 02054 ast_string_field_set(q, defaultrule, val); 02055 } else if (!strcasecmp(param, "timeoutpriority")) { 02056 if (!strcasecmp(val, "conf")) { 02057 q->timeoutpriority = TIMEOUT_PRIORITY_CONF; 02058 } else { 02059 q->timeoutpriority = TIMEOUT_PRIORITY_APP; 02060 } 02061 } else if (failunknown) { 02062 if (linenum >= 0) { 02063 ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s at line %d of queues.conf\n", 02064 q->name, param, linenum); 02065 } else { 02066 ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s\n", q->name, param); 02067 } 02068 } 02069 }
static char* queue_show | ( | struct ast_cli_entry * | e, | |
int | cmd, | |||
struct ast_cli_args * | a | |||
) | [static] |
Definition at line 7047 of file app_queue.c.
References __queues_show(), ast_cli_args::argc, ast_cli_args::argv, CLI_GENERATE, CLI_INIT, ast_cli_entry::command, complete_queue_show(), ast_cli_args::fd, ast_cli_args::line, ast_cli_args::n, ast_cli_args::pos, ast_cli_entry::usage, and ast_cli_args::word.
07048 { 07049 switch ( cmd ) { 07050 case CLI_INIT: 07051 e->command = "queue show"; 07052 e->usage = 07053 "Usage: queue show\n" 07054 " Provides summary information on a specified queue.\n"; 07055 return NULL; 07056 case CLI_GENERATE: 07057 return complete_queue_show(a->line, a->word, a->pos, a->n); 07058 } 07059 07060 return __queues_show(NULL, a->fd, a->argc, a->argv); 07061 }
static void queue_transfer_destroy | ( | void * | data | ) | [static] |
Definition at line 4159 of file app_queue.c.
References ast_free.
04160 { 04161 struct queue_transfer_ds *qtds = data; 04162 ast_free(qtds); 04163 }
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 4182 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::opos, queue_ent::parent, queue_transfer_ds::qe, queue_transfer_info, queue_ent::start, queue_transfer_ds::starttime, ast_channel::uniqueid, and update_queue().
04183 { 04184 struct queue_transfer_ds *qtds = data; 04185 struct queue_ent *qe = qtds->qe; 04186 struct member *member = qtds->member; 04187 time_t callstart = qtds->starttime; 04188 int callcompletedinsl = qtds->callcompletedinsl; 04189 struct ast_datastore *datastore; 04190 04191 ast_queue_log(qe->parent->name, qe->chan->uniqueid, member->membername, "TRANSFER", "%s|%s|%ld|%ld|%d", 04192 new_chan->exten, new_chan->context, (long) (callstart - qe->start), 04193 (long) (time(NULL) - callstart), qe->opos); 04194 04195 update_queue(qe->parent, member, callcompletedinsl, (time(NULL) - callstart)); 04196 04197 /* No need to lock the channels because they are already locked in ast_do_masquerade */ 04198 if ((datastore = ast_channel_datastore_find(old_chan, &queue_transfer_info, NULL))) { 04199 ast_channel_datastore_remove(old_chan, datastore); 04200 } else { 04201 ast_log(LOG_WARNING, "Can't find the queue_transfer datastore.\n"); 04202 } 04203 }
static struct call_queue* queue_unref | ( | struct call_queue * | q | ) | [inline, static] |
Definition at line 1284 of file app_queue.c.
References ao2_ref.
Referenced by queues_data_provider_get().
01285 { 01286 ao2_ref(q, -1); 01287 return q; 01288 }
static int queues_data_provider_get | ( | const struct ast_data_search * | search, | |
struct ast_data * | data_root | |||
) | [static] |
Definition at line 8193 of file app_queue.c.
References ao2_iterator_init(), ao2_iterator_next, ao2_lock, ao2_unlock, ast_category_browse(), ast_config_destroy(), ast_load_realtime_multientry(), ast_strlen_zero(), load_realtime_queue(), queue_unref(), queues_data_provider_get_helper(), and SENTINEL.
08195 { 08196 struct ao2_iterator i; 08197 struct call_queue *queue, *queue_realtime = NULL; 08198 struct ast_config *cfg; 08199 char *queuename; 08200 08201 /* load realtime queues. */ 08202 cfg = ast_load_realtime_multientry("queues", "name LIKE", "%", SENTINEL); 08203 if (cfg) { 08204 for (queuename = ast_category_browse(cfg, NULL); 08205 !ast_strlen_zero(queuename); 08206 queuename = ast_category_browse(cfg, queuename)) { 08207 if ((queue = load_realtime_queue(queuename))) { 08208 queue_unref(queue); 08209 } 08210 } 08211 ast_config_destroy(cfg); 08212 } 08213 08214 /* static queues. */ 08215 i = ao2_iterator_init(queues, 0); 08216 while ((queue = ao2_iterator_next(&i))) { 08217 ao2_lock(queue); 08218 if (queue->realtime && !(queue_realtime = load_realtime_queue(queue->name))) { 08219 ao2_unlock(queue); 08220 queue_unref(queue); 08221 continue; 08222 } else if (queue->realtime) { 08223 queue_unref(queue_realtime); 08224 } 08225 08226 queues_data_provider_get_helper(search, data_root, queue); 08227 ao2_unlock(queue); 08228 queue_unref(queue); 08229 } 08230 08231 return 0; 08232 }
static void queues_data_provider_get_helper | ( | const struct ast_data_search * | search, | |
struct ast_data * | data_root, | |||
struct call_queue * | queue | |||
) | [static] |
Definition at line 8089 of file app_queue.c.
References call_queue::announceposition, ANNOUNCEPOSITION_LIMIT, ANNOUNCEPOSITION_MORE_THAN, ANNOUNCEPOSITION_NO, ANNOUNCEPOSITION_YES, ao2_iterator_init(), ao2_iterator_next, ao2_ref, ast_channel_data_add_structure(), ast_data_add_int(), ast_data_add_node(), ast_data_add_str(), ast_data_add_structure, ast_data_remove_node(), ast_data_search_match(), queue_ent::chan, call_queue::head, int2strat(), call_queue::members, queue_ent::next, and call_queue::strategy.
Referenced by queues_data_provider_get().
08091 { 08092 struct ao2_iterator im; 08093 struct member *member; 08094 struct queue_ent *qe; 08095 struct ast_data *data_queue, *data_members = NULL, *enum_node; 08096 struct ast_data *data_member, *data_callers = NULL, *data_caller, *data_caller_channel; 08097 08098 data_queue = ast_data_add_node(data_root, "queue"); 08099 if (!data_queue) { 08100 return; 08101 } 08102 08103 ast_data_add_structure(call_queue, data_queue, queue); 08104 08105 ast_data_add_str(data_queue, "strategy", int2strat(queue->strategy)); 08106 08107 /* announce position */ 08108 enum_node = ast_data_add_node(data_queue, "announceposition"); 08109 if (!enum_node) { 08110 return; 08111 } 08112 switch (queue->announceposition) { 08113 case ANNOUNCEPOSITION_LIMIT: 08114 ast_data_add_str(enum_node, "text", "limit"); 08115 break; 08116 case ANNOUNCEPOSITION_MORE_THAN: 08117 ast_data_add_str(enum_node, "text", "more"); 08118 break; 08119 case ANNOUNCEPOSITION_YES: 08120 ast_data_add_str(enum_node, "text", "yes"); 08121 break; 08122 case ANNOUNCEPOSITION_NO: 08123 ast_data_add_str(enum_node, "text", "no"); 08124 break; 08125 default: 08126 ast_data_add_str(enum_node, "text", "unknown"); 08127 break; 08128 } 08129 ast_data_add_int(enum_node, "value", queue->announceposition); 08130 08131 /* add queue members */ 08132 im = ao2_iterator_init(queue->members, 0); 08133 while ((member = ao2_iterator_next(&im))) { 08134 if (!data_members) { 08135 data_members = ast_data_add_node(data_queue, "members"); 08136 if (!data_members) { 08137 ao2_ref(member, -1); 08138 continue; 08139 } 08140 } 08141 08142 data_member = ast_data_add_node(data_members, "member"); 08143 if (!data_member) { 08144 ao2_ref(member, -1); 08145 continue; 08146 } 08147 08148 ast_data_add_structure(member, data_member, member); 08149 08150 ao2_ref(member, -1); 08151 } 08152 08153 /* include the callers inside the result. */ 08154 if (queue->head) { 08155 for (qe = queue->head; qe; qe = qe->next) { 08156 if (!data_callers) { 08157 data_callers = ast_data_add_node(data_queue, "callers"); 08158 if (!data_callers) { 08159 continue; 08160 } 08161 } 08162 08163 data_caller = ast_data_add_node(data_callers, "caller"); 08164 if (!data_caller) { 08165 continue; 08166 } 08167 08168 ast_data_add_structure(queue_ent, data_caller, qe); 08169 08170 /* add the caller channel. */ 08171 data_caller_channel = ast_data_add_node(data_caller, "channel"); 08172 if (!data_caller_channel) { 08173 continue; 08174 } 08175 08176 ast_channel_data_add_structure(data_caller_channel, qe->chan, 1); 08177 } 08178 } 08179 08180 /* if this queue doesn't match remove the added queue. */ 08181 if (!ast_data_search_match(search, data_queue)) { 08182 ast_data_remove_node(data_root, data_queue); 08183 } 08184 }
static void recalc_holdtime | ( | struct queue_ent * | qe, | |
int | newholdtime | |||
) | [static] |
Definition at line 2737 of file app_queue.c.
References ao2_lock, ao2_unlock, call_queue::holdtime, and queue_ent::parent.
02738 { 02739 int oldvalue; 02740 02741 /* Calculate holdtime using an exponential average */ 02742 /* Thanks to SRT for this contribution */ 02743 /* 2^2 (4) is the filter coefficient; a higher exponent would give old entries more weight */ 02744 02745 ao2_lock(qe->parent); 02746 oldvalue = qe->parent->holdtime; 02747 qe->parent->holdtime = (((oldvalue << 2) - oldvalue) + newholdtime) >> 2; 02748 ao2_unlock(qe->parent); 02749 }
static void record_abandoned | ( | struct queue_ent * | qe | ) | [static] |
Record that a caller gave up on waiting in queue.
Definition at line 3341 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, set_queue_variables(), queue_ent::start, and ast_channel::uniqueid.
Referenced by queue_exec().
03342 { 03343 set_queue_variables(qe->parent, qe->chan); 03344 ao2_lock(qe->parent); 03345 manager_event(EVENT_FLAG_AGENT, "QueueCallerAbandon", 03346 "Queue: %s\r\n" 03347 "Uniqueid: %s\r\n" 03348 "Position: %d\r\n" 03349 "OriginalPosition: %d\r\n" 03350 "HoldTime: %d\r\n", 03351 qe->parent->name, qe->chan->uniqueid, qe->pos, qe->opos, (int)(time(NULL) - qe->start)); 03352 03353 qe->parent->callsabandoned++; 03354 ao2_unlock(qe->parent); 03355 }
static int reload | ( | void | ) | [static] |
Definition at line 8364 of file app_queue.c.
References AST_FLAGS_ALL, ast_unload_realtime(), QUEUE_RESET_STATS, and reload_handler().
08365 { 08366 struct ast_flags mask = {AST_FLAGS_ALL & ~QUEUE_RESET_STATS,}; 08367 ast_unload_realtime("queue_members"); 08368 reload_handler(1, &mask, NULL); 08369 return 0; 08370 }
static int reload_handler | ( | int | reload, | |
struct ast_flags * | mask, | |||
const char * | queuename | |||
) | [static] |
The command center for all reload operations.
Whenever any piece of queue information is to be reloaded, this function is called. It interprets the flags set in the mask parameter and acts based on how they are set.
reload | True if we are reloading information, false if we are loading information for the first time. | |
mask | A bitmask which tells the handler what actions to take | |
queuename | The name of the queue on which we wish to take action |
0 | All reloads were successful | |
non-zero | There was a failure |
Definition at line 6859 of file app_queue.c.
References ast_test_flag, clear_stats(), QUEUE_RELOAD_MEMBER, QUEUE_RELOAD_PARAMETERS, QUEUE_RELOAD_RULES, QUEUE_RESET_STATS, reload_queue_rules(), and reload_queues().
Referenced by handle_queue_reload(), handle_queue_reset(), load_module(), manager_queue_reload(), manager_queue_reset(), and reload().
06860 { 06861 int res = 0; 06862 06863 if (ast_test_flag(mask, QUEUE_RELOAD_RULES)) { 06864 res |= reload_queue_rules(reload); 06865 } 06866 if (ast_test_flag(mask, QUEUE_RESET_STATS)) { 06867 res |= clear_stats(queuename); 06868 } 06869 if (ast_test_flag(mask, (QUEUE_RELOAD_PARAMETERS | QUEUE_RELOAD_MEMBER))) { 06870 res |= reload_queues(reload, mask, queuename); 06871 } 06872 return res; 06873 }
static void reload_queue_members | ( | void | ) | [static] |
Reload dynamic queue members persisted into the astdb.
Definition at line 5423 of file app_queue.c.
References add_to_queue(), ao2_lock, ao2_t_find, ao2_unlock, ast_db_del(), ast_db_freetree(), ast_db_get(), ast_db_gettree(), ast_debug, ast_log(), ast_strlen_zero(), errno, member::interface, ast_db_entry::key, load_realtime_queue(), LOG_ERROR, LOG_NOTICE, LOG_WARNING, member::membername, call_queue::name, ast_db_entry::next, OBJ_POINTER, member::paused, member::penalty, PM_MAX_LEN, queue_t_unref, RES_OUTOFMEMORY, member::state_interface, and strsep().
Referenced by load_module().
05424 { 05425 char *cur_ptr; 05426 const char *queue_name; 05427 char *member; 05428 char *interface; 05429 char *membername = NULL; 05430 char *state_interface; 05431 char *penalty_tok; 05432 int penalty = 0; 05433 char *paused_tok; 05434 int paused = 0; 05435 struct ast_db_entry *db_tree; 05436 struct ast_db_entry *entry; 05437 struct call_queue *cur_queue; 05438 char queue_data[PM_MAX_LEN]; 05439 05440 ao2_lock(queues); 05441 05442 /* Each key in 'pm_family' is the name of a queue */ 05443 db_tree = ast_db_gettree(pm_family, NULL); 05444 for (entry = db_tree; entry; entry = entry->next) { 05445 05446 queue_name = entry->key + strlen(pm_family) + 2; 05447 05448 { 05449 struct call_queue tmpq = { 05450 .name = queue_name, 05451 }; 05452 cur_queue = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Reload queue members"); 05453 } 05454 05455 if (!cur_queue) 05456 cur_queue = load_realtime_queue(queue_name); 05457 05458 if (!cur_queue) { 05459 /* If the queue no longer exists, remove it from the 05460 * database */ 05461 ast_log(LOG_WARNING, "Error loading persistent queue: '%s': it does not exist\n", queue_name); 05462 ast_db_del(pm_family, queue_name); 05463 continue; 05464 } 05465 05466 if (ast_db_get(pm_family, queue_name, queue_data, PM_MAX_LEN)) { 05467 queue_t_unref(cur_queue, "Expire reload reference"); 05468 continue; 05469 } 05470 05471 cur_ptr = queue_data; 05472 while ((member = strsep(&cur_ptr, ",|"))) { 05473 if (ast_strlen_zero(member)) 05474 continue; 05475 05476 interface = strsep(&member, ";"); 05477 penalty_tok = strsep(&member, ";"); 05478 paused_tok = strsep(&member, ";"); 05479 membername = strsep(&member, ";"); 05480 state_interface = strsep(&member, ";"); 05481 05482 if (!penalty_tok) { 05483 ast_log(LOG_WARNING, "Error parsing persistent member string for '%s' (penalty)\n", queue_name); 05484 break; 05485 } 05486 penalty = strtol(penalty_tok, NULL, 10); 05487 if (errno == ERANGE) { 05488 ast_log(LOG_WARNING, "Error converting penalty: %s: Out of range.\n", penalty_tok); 05489 break; 05490 } 05491 05492 if (!paused_tok) { 05493 ast_log(LOG_WARNING, "Error parsing persistent member string for '%s' (paused)\n", queue_name); 05494 break; 05495 } 05496 paused = strtol(paused_tok, NULL, 10); 05497 if ((errno == ERANGE) || paused < 0 || paused > 1) { 05498 ast_log(LOG_WARNING, "Error converting paused: %s: Expected 0 or 1.\n", paused_tok); 05499 break; 05500 } 05501 05502 ast_debug(1, "Reload Members: Queue: %s Member: %s Name: %s Penalty: %d Paused: %d\n", queue_name, interface, membername, penalty, paused); 05503 05504 if (add_to_queue(queue_name, interface, membername, penalty, paused, 0, state_interface) == RES_OUTOFMEMORY) { 05505 ast_log(LOG_ERROR, "Out of Memory when reloading persistent queue member\n"); 05506 break; 05507 } 05508 } 05509 queue_t_unref(cur_queue, "Expire reload reference"); 05510 } 05511 05512 ao2_unlock(queues); 05513 if (db_tree) { 05514 ast_log(LOG_NOTICE, "Queue members successfully reloaded from database.\n"); 05515 ast_db_freetree(db_tree); 05516 } 05517 }
static int reload_queue_rules | ( | int | reload | ) | [static] |
Reload the rules defined in queuerules.conf.
reload | If 1, then only process queuerules.conf if the file has changed since the last time we inspected it. |
Definition at line 6457 of file app_queue.c.
References ast_calloc, ast_category_browse(), ast_config_destroy(), ast_config_load, ast_copy_string(), ast_free, AST_LIST_INSERT_TAIL, AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, ast_log(), AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_SUCCESS, ast_variable_browse(), CONFIG_FLAG_FILEUNCHANGED, config_flags, CONFIG_STATUS_FILEINVALID, CONFIG_STATUS_FILEUNCHANGED, insert_penaltychange(), ast_variable::lineno, LOG_ERROR, LOG_NOTICE, LOG_WARNING, ast_variable::name, ast_variable::next, rule_list::rules, and ast_variable::value.
Referenced by reload_handler().
06458 { 06459 struct ast_config *cfg; 06460 struct rule_list *rl_iter, *new_rl; 06461 struct penalty_rule *pr_iter; 06462 char *rulecat = NULL; 06463 struct ast_variable *rulevar = NULL; 06464 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 }; 06465 06466 if (!(cfg = ast_config_load("queuerules.conf", config_flags))) { 06467 ast_log(LOG_NOTICE, "No queuerules.conf file found, queues will not follow penalty rules\n"); 06468 return AST_MODULE_LOAD_SUCCESS; 06469 } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) { 06470 ast_log(LOG_NOTICE, "queuerules.conf has not changed since it was last loaded. Not taking any action.\n"); 06471 return AST_MODULE_LOAD_SUCCESS; 06472 } else if (cfg == CONFIG_STATUS_FILEINVALID) { 06473 ast_log(LOG_ERROR, "Config file queuerules.conf is in an invalid format. Aborting.\n"); 06474 return AST_MODULE_LOAD_SUCCESS; 06475 } 06476 06477 AST_LIST_LOCK(&rule_lists); 06478 while ((rl_iter = AST_LIST_REMOVE_HEAD(&rule_lists, list))) { 06479 while ((pr_iter = AST_LIST_REMOVE_HEAD(&rl_iter->rules, list))) 06480 ast_free(pr_iter); 06481 ast_free(rl_iter); 06482 } 06483 while ((rulecat = ast_category_browse(cfg, rulecat))) { 06484 if (!(new_rl = ast_calloc(1, sizeof(*new_rl)))) { 06485 AST_LIST_UNLOCK(&rule_lists); 06486 return AST_MODULE_LOAD_FAILURE; 06487 } else { 06488 ast_copy_string(new_rl->name, rulecat, sizeof(new_rl->name)); 06489 AST_LIST_INSERT_TAIL(&rule_lists, new_rl, list); 06490 for (rulevar = ast_variable_browse(cfg, rulecat); rulevar; rulevar = rulevar->next) 06491 if(!strcasecmp(rulevar->name, "penaltychange")) 06492 insert_penaltychange(new_rl->name, rulevar->value, rulevar->lineno); 06493 else 06494 ast_log(LOG_WARNING, "Don't know how to handle rule type '%s' on line %d\n", rulevar->name, rulevar->lineno); 06495 } 06496 } 06497 AST_LIST_UNLOCK(&rule_lists); 06498 06499 ast_config_destroy(cfg); 06500 06501 return AST_MODULE_LOAD_SUCCESS; 06502 }
static int reload_queues | ( | int | reload, | |
struct ast_flags * | mask, | |||
const char * | queuename | |||
) | [static] |
reload the queues.conf file
This function reloads the information in the general section of the queues.conf file and potentially more, depending on the value of mask.
reload | 0 if we are calling this the first time, 1 every other time | |
mask | Gives flags telling us what information to actually reload | |
queuename | If set to a non-zero string, then only reload information from that particular queue. Otherwise inspect all queues |
-1 | Failure occurred | |
0 | All clear! |
Definition at line 6771 of file app_queue.c.
References ao2_callback, ao2_lock, ao2_unlock, ast_category_browse(), ast_config_destroy(), ast_config_load, ast_log(), ast_strlen_zero(), ast_test_flag, CONFIG_FLAG_FILEUNCHANGED, config_flags, CONFIG_STATUS_FILEINVALID, CONFIG_STATUS_FILEUNCHANGED, kill_dead_queues(), LOG_ERROR, LOG_NOTICE, mark_dead_and_unfound(), OBJ_MULTIPLE, OBJ_NODATA, OBJ_UNLINK, QUEUE_RELOAD_PARAMETERS, queue_set_global_params(), and reload_single_queue().
Referenced by reload_handler().
06772 { 06773 struct ast_config *cfg; 06774 char *cat; 06775 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 }; 06776 const int queue_reload = ast_test_flag(mask, QUEUE_RELOAD_PARAMETERS); 06777 06778 if (!(cfg = ast_config_load("queues.conf", config_flags))) { 06779 ast_log(LOG_NOTICE, "No call queueing config file (queues.conf), so no call queues\n"); 06780 return -1; 06781 } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) { 06782 return 0; 06783 } else if (cfg == CONFIG_STATUS_FILEINVALID) { 06784 ast_log(LOG_ERROR, "Config file queues.conf is in an invalid format. Aborting.\n"); 06785 return -1; 06786 } 06787 06788 /* We've made it here, so it looks like we're doing operations on all queues. */ 06789 ao2_lock(queues); 06790 06791 /* Mark all queues as dead for the moment if we're reloading queues. 06792 * For clarity, we could just be reloading members, in which case we don't want to mess 06793 * with the other queue parameters at all*/ 06794 if (queue_reload) { 06795 ao2_callback(queues, OBJ_NODATA, mark_dead_and_unfound, (char *) queuename); 06796 } 06797 06798 /* Chug through config file */ 06799 cat = NULL; 06800 while ((cat = ast_category_browse(cfg, cat)) ) { 06801 if (!strcasecmp(cat, "general") && queue_reload) { 06802 queue_set_global_params(cfg); 06803 continue; 06804 } 06805 if (ast_strlen_zero(queuename) || !strcasecmp(cat, queuename)) 06806 reload_single_queue(cfg, mask, cat); 06807 } 06808 06809 ast_config_destroy(cfg); 06810 /* Unref all the dead queues if we were reloading queues */ 06811 if (queue_reload) { 06812 ao2_callback(queues, OBJ_NODATA | OBJ_MULTIPLE | OBJ_UNLINK, kill_dead_queues, (char *) queuename); 06813 } 06814 ao2_unlock(queues); 06815 return 0; 06816 }
static void reload_single_member | ( | const char * | memberdata, | |
struct call_queue * | q | |||
) | [static] |
reload information pertaining to a single member
This function is called when a member = line is encountered in queues.conf.
memberdata | The part after member = in the config file | |
q | The queue to which this member belongs |
Definition at line 6535 of file app_queue.c.
References ao2_find, ao2_link, ao2_ref, args, AST_APP_ARG, ast_copy_string(), AST_DECLARE_APP_ARGS, ast_log(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strip(), ast_strlen_zero(), create_queue_member(), member::interface, LOG_WARNING, call_queue::membercount, call_queue::members, OBJ_POINTER, OBJ_UNLINK, parse(), member::paused, and member::penalty.
Referenced by reload_single_queue().
06536 { 06537 char *membername, *interface, *state_interface, *tmp; 06538 char *parse; 06539 struct member *cur, *newm; 06540 struct member tmpmem; 06541 int penalty; 06542 AST_DECLARE_APP_ARGS(args, 06543 AST_APP_ARG(interface); 06544 AST_APP_ARG(penalty); 06545 AST_APP_ARG(membername); 06546 AST_APP_ARG(state_interface); 06547 ); 06548 06549 if (ast_strlen_zero(memberdata)) { 06550 ast_log(LOG_WARNING, "Empty queue member definition. Moving on!\n"); 06551 return; 06552 } 06553 06554 /* Add a new member */ 06555 parse = ast_strdupa(memberdata); 06556 06557 AST_STANDARD_APP_ARGS(args, parse); 06558 06559 interface = args.interface; 06560 if (!ast_strlen_zero(args.penalty)) { 06561 tmp = args.penalty; 06562 ast_strip(tmp); 06563 penalty = atoi(tmp); 06564 if (penalty < 0) { 06565 penalty = 0; 06566 } 06567 } else { 06568 penalty = 0; 06569 } 06570 06571 if (!ast_strlen_zero(args.membername)) { 06572 membername = args.membername; 06573 ast_strip(membername); 06574 } else { 06575 membername = interface; 06576 } 06577 06578 if (!ast_strlen_zero(args.state_interface)) { 06579 state_interface = args.state_interface; 06580 ast_strip(state_interface); 06581 } else { 06582 state_interface = interface; 06583 } 06584 06585 /* Find the old position in the list */ 06586 ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface)); 06587 cur = ao2_find(q->members, &tmpmem, OBJ_POINTER | OBJ_UNLINK); 06588 if ((newm = create_queue_member(interface, membername, penalty, cur ? cur->paused : 0, state_interface))) { 06589 ao2_link(q->members, newm); 06590 ao2_ref(newm, -1); 06591 } 06592 newm = NULL; 06593 06594 if (cur) { 06595 ao2_ref(cur, -1); 06596 } else { 06597 q->membercount++; 06598 } 06599 }
static void reload_single_queue | ( | struct ast_config * | cfg, | |
struct ast_flags * | mask, | |||
const char * | queuename | |||
) | [static] |
Reload information pertaining to a particular queue.
Once we have isolated a queue within reload_queues, we call this. This will either reload information for the queue or if we're just reloading member information, we'll just reload that without touching other settings within the queue
cfg | The configuration which we are reading | |
mask | Tells us what information we need to reload | |
queuename | The name of the queue we are reloading information from |
void |
Definition at line 6641 of file app_queue.c.
References alloc_queue(), ao2_callback, ao2_lock, ao2_t_find, ao2_unlock, ast_log(), ast_test_flag, ast_variable_browse(), ast_variable_retrieve(), call_queue::found, init_queue(), LOG_WARNING, mark_member_dead(), call_queue::membercount, call_queue::members, call_queue::name, OBJ_NODATA, OBJ_POINTER, QUEUE_RELOAD_MEMBER, QUEUE_RELOAD_PARAMETERS, queue_set_param(), QUEUE_STRATEGY_RINGALL, queue_t_unref, reload_single_member(), strat2int(), call_queue::strategy, and var.
Referenced by reload_queues().
06642 { 06643 int new; 06644 struct call_queue *q = NULL; 06645 /*We're defining a queue*/ 06646 struct call_queue tmpq = { 06647 .name = queuename, 06648 }; 06649 const char *tmpvar; 06650 const int queue_reload = ast_test_flag(mask, QUEUE_RELOAD_PARAMETERS); 06651 const int member_reload = ast_test_flag(mask, QUEUE_RELOAD_MEMBER); 06652 int prev_weight = 0; 06653 struct ast_variable *var; 06654 if (!(q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Find queue for reload"))) { 06655 if (queue_reload) { 06656 /* Make one then */ 06657 if (!(q = alloc_queue(queuename))) { 06658 return; 06659 } 06660 } else { 06661 /* Since we're not reloading queues, this means that we found a queue 06662 * in the configuration file which we don't know about yet. Just return. 06663 */ 06664 return; 06665 } 06666 new = 1; 06667 } else { 06668 new = 0; 06669 } 06670 06671 if (!new) { 06672 ao2_lock(q); 06673 prev_weight = q->weight ? 1 : 0; 06674 } 06675 /* Check if we already found a queue with this name in the config file */ 06676 if (q->found) { 06677 ast_log(LOG_WARNING, "Queue '%s' already defined! Skipping!\n", queuename); 06678 if (!new) { 06679 /* It should be impossible to *not* hit this case*/ 06680 ao2_unlock(q); 06681 } 06682 queue_t_unref(q, "We exist! Expiring temporary pointer"); 06683 return; 06684 } 06685 /* Due to the fact that the "linear" strategy will have a different allocation 06686 * scheme for queue members, we must devise the queue's strategy before other initializations. 06687 * To be specific, the linear strategy needs to function like a linked list, meaning the ao2 06688 * container used will have only a single bucket instead of the typical number. 06689 */ 06690 if (queue_reload) { 06691 if ((tmpvar = ast_variable_retrieve(cfg, queuename, "strategy"))) { 06692 q->strategy = strat2int(tmpvar); 06693 if (q->strategy < 0) { 06694 ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n", 06695 tmpvar, q->name); 06696 q->strategy = QUEUE_STRATEGY_RINGALL; 06697 } 06698 } else { 06699 q->strategy = QUEUE_STRATEGY_RINGALL; 06700 } 06701 init_queue(q); 06702 } 06703 if (member_reload) { 06704 q->membercount = 0; 06705 ao2_callback(q->members, OBJ_NODATA, mark_member_dead, NULL); 06706 } 06707 for (var = ast_variable_browse(cfg, queuename); var; var = var->next) { 06708 if (member_reload && !strcasecmp(var->name, "member")) { 06709 reload_single_member(var->value, q); 06710 } else if (queue_reload) { 06711 queue_set_param(q, var->name, var->value, var->lineno, 1); 06712 } 06713 } 06714 /* At this point, we've determined if the queue has a weight, so update use_weight 06715 * as appropriate 06716 */ 06717 if (!q->weight && prev_weight) { 06718 ast_atomic_fetchadd_int(&use_weight, -1); 06719 } 06720 else if (q->weight && !prev_weight) { 06721 ast_atomic_fetchadd_int(&use_weight, +1); 06722 } 06723 06724 /* Free remaining members marked as delme */ 06725 if (member_reload) { 06726 ao2_callback(q->members, OBJ_NODATA | OBJ_MULTIPLE | OBJ_UNLINK, kill_dead_members, q); 06727 } 06728 06729 if (new) { 06730 queues_t_link(queues, q, "Add queue to container"); 06731 } else { 06732 ao2_unlock(q); 06733 } 06734 queue_t_unref(q, "Expiring creation reference"); 06735 }
static int remove_from_queue | ( | const char * | queuename, | |
const char * | interface | |||
) | [static] |
Remove member from queue.
RES_NOT_DYNAMIC | when they aren't a RT member | |
RES_NOSUCHQUEUE | queue does not exist | |
RES_OKAY | removed member from queue | |
RES_EXISTS | queue exists but no members |
Definition at line 5158 of file app_queue.c.
References ao2_find, ao2_lock, ao2_ref, ao2_t_find, ao2_unlink, ao2_unlock, ast_copy_string(), dump_queue_members(), member::dynamic, EVENT_FLAG_AGENT, member::interface, manager_event, call_queue::membercount, member::membername, call_queue::members, call_queue::name, OBJ_POINTER, queue_t_unref, RES_EXISTS, RES_NOSUCHQUEUE, RES_NOT_DYNAMIC, and RES_OKAY.
Referenced by attempt_thread(), handle_queue_remove_member(), manager_remove_queue_member(), rqm_exec(), and scan_service().
05159 { 05160 struct call_queue *q, tmpq = { 05161 .name = queuename, 05162 }; 05163 struct member *mem, tmpmem; 05164 int res = RES_NOSUCHQUEUE; 05165 05166 ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface)); 05167 if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Temporary reference for interface removal"))) { 05168 ao2_lock(queues); 05169 ao2_lock(q); 05170 if ((mem = ao2_find(q->members, &tmpmem, OBJ_POINTER))) { 05171 /* XXX future changes should beware of this assumption!! */ 05172 if (!mem->dynamic) { 05173 ao2_ref(mem, -1); 05174 ao2_unlock(q); 05175 queue_t_unref(q, "Interface wasn't dynamic, expiring temporary reference"); 05176 ao2_unlock(queues); 05177 return RES_NOT_DYNAMIC; 05178 } 05179 q->membercount--; 05180 manager_event(EVENT_FLAG_AGENT, "QueueMemberRemoved", 05181 "Queue: %s\r\n" 05182 "Location: %s\r\n" 05183 "MemberName: %s\r\n", 05184 q->name, mem->interface, mem->membername); 05185 ao2_unlink(q->members, mem); 05186 ao2_ref(mem, -1); 05187 05188 if (queue_persistent_members) 05189 dump_queue_members(q); 05190 05191 res = RES_OKAY; 05192 } else { 05193 res = RES_EXISTS; 05194 } 05195 ao2_unlock(q); 05196 ao2_unlock(queues); 05197 queue_t_unref(q, "Expiring temporary reference"); 05198 } 05199 05200 return res; 05201 }
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(). Failure can occur if:
1 | on success to reach a free agent | |
0 | on failure to get agent. |
Definition at line 3000 of file app_queue.c.
References ast_cdr::accountcode, ast_channel::adsicpe, ast_cdr::amaflags, ast_party_connected_line::ani, ast_party_caller::ani, 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_set_caller_event(), ast_channel_trylock, ast_channel_unlock, ast_connected_line_copy_from_caller(), ast_copy_string(), ast_debug, AST_DEVICE_NOT_INUSE, AST_DEVICE_UNKNOWN, AST_FLAG_ANSWERED_ELSEWHERE, ast_party_caller_set_init(), ast_party_redirecting_copy(), ast_request(), ast_set_callerid(), ast_set_flag, ast_string_field_set, ast_strlen_zero(), ast_verb, ast_channel::caller, queue_ent::cancel_answered_elsewhere, ast_channel::cdr, callattempt::chan, queue_ent::chan, ast_cdr::channel, CHANNEL_DEADLOCK_AVOIDANCE, ast_cdr::clid, compare_weight(), ast_channel::connected, ast_channel::context, ast_channel::data, ast_cdr::dcontext, callattempt::dial_callerid_absent, dialcontext, ast_channel::dialed, do_hang(), ast_cdr::dst, EVENT_FLAG_AGENT, call_queue::eventwhencalled, ast_channel::exten, get_queue_member_status(), ast_party_connected_line::id, ast_party_caller::id, callattempt::interface, ast_cdr::lastapp, callattempt::lastcall, ast_cdr::lastdata, callattempt::lastqueue, queue_ent::linpos, ast_channel::macroexten, manager_event, callattempt::member, member::membername, ast_party_id::name, ast_channel::name, call_queue::name, ast_channel::nativeformats, ast_party_dialed::number, ast_party_id::number, queue_ent::parent, member::paused, pbx_builtin_getvar_helper(), ast_channel::priority, QUEUE_EVENT_VARIABLES, ast_channel::redirecting, call_queue::ringinuse, call_queue::rrpos, S_COR, S_OR, ast_cdr::src, member::status, status, callattempt::stillgoing, ast_party_name::str, ast_party_number::str, ast_party_dialed::str, ast_party_dialed::transit_network_select, ast_channel::uniqueid, update_status(), ast_cdr::userfield, ast_party_name::valid, ast_party_number::valid, vars2manager(), ast_channel::whentohangup, and call_queue::wrapuptime.
Referenced by ring_one().
03001 { 03002 int res; 03003 int status; 03004 char tech[256]; 03005 char *location; 03006 const char *macrocontext, *macroexten; 03007 03008 /* on entry here, we know that tmp->chan == NULL */ 03009 if ((tmp->lastqueue && tmp->lastqueue->wrapuptime && (time(NULL) - tmp->lastcall < tmp->lastqueue->wrapuptime)) || 03010 (!tmp->lastqueue && qe->parent->wrapuptime && (time(NULL) - tmp->lastcall < qe->parent->wrapuptime))) { 03011 ast_debug(1, "Wrapuptime not yet expired on queue %s for %s\n", 03012 (tmp->lastqueue ? tmp->lastqueue->name : qe->parent->name), tmp->interface); 03013 if (qe->chan->cdr) 03014 ast_cdr_busy(qe->chan->cdr); 03015 tmp->stillgoing = 0; 03016 (*busies)++; 03017 return 0; 03018 } 03019 03020 if (!qe->parent->ringinuse && (tmp->member->status != AST_DEVICE_NOT_INUSE) && (tmp->member->status != AST_DEVICE_UNKNOWN)) { 03021 ast_debug(1, "%s in use, can't receive call\n", tmp->interface); 03022 if (qe->chan->cdr) 03023 ast_cdr_busy(qe->chan->cdr); 03024 tmp->stillgoing = 0; 03025 return 0; 03026 } 03027 03028 if (tmp->member->paused) { 03029 ast_debug(1, "%s paused, can't receive call\n", tmp->interface); 03030 if (qe->chan->cdr) 03031 ast_cdr_busy(qe->chan->cdr); 03032 tmp->stillgoing = 0; 03033 return 0; 03034 } 03035 if (use_weight && compare_weight(qe->parent,tmp->member)) { 03036 ast_debug(1, "Priority queue delaying call to %s:%s\n", qe->parent->name, tmp->interface); 03037 if (qe->chan->cdr) 03038 ast_cdr_busy(qe->chan->cdr); 03039 tmp->stillgoing = 0; 03040 (*busies)++; 03041 return 0; 03042 } 03043 03044 ast_copy_string(tech, tmp->interface, sizeof(tech)); 03045 if ((location = strchr(tech, '/'))) 03046 *location++ = '\0'; 03047 else 03048 location = ""; 03049 03050 /* Request the peer */ 03051 tmp->chan = ast_request(tech, qe->chan->nativeformats, qe->chan, location, &status); 03052 if (!tmp->chan) { /* If we can't, just go on to the next call */ 03053 if (qe->chan->cdr) 03054 ast_cdr_busy(qe->chan->cdr); 03055 tmp->stillgoing = 0; 03056 03057 ao2_lock(qe->parent); 03058 update_status(qe->parent, tmp->member, get_queue_member_status(tmp->member)); 03059 qe->parent->rrpos++; 03060 qe->linpos++; 03061 ao2_unlock(qe->parent); 03062 03063 (*busies)++; 03064 return 0; 03065 } 03066 03067 ast_channel_lock(tmp->chan); 03068 while (ast_channel_trylock(qe->chan)) { 03069 CHANNEL_DEADLOCK_AVOIDANCE(tmp->chan); 03070 } 03071 03072 if (qe->cancel_answered_elsewhere) { 03073 ast_set_flag(tmp->chan, AST_FLAG_ANSWERED_ELSEWHERE); 03074 } 03075 tmp->chan->appl = "AppQueue"; 03076 tmp->chan->data = "(Outgoing Line)"; 03077 memset(&tmp->chan->whentohangup, 0, sizeof(tmp->chan->whentohangup)); 03078 03079 /* If the new channel has no callerid, try to guess what it should be */ 03080 if (!tmp->chan->caller.id.number.valid) { 03081 if (qe->chan->connected.id.number.valid) { 03082 struct ast_party_caller caller; 03083 03084 ast_party_caller_set_init(&caller, &tmp->chan->caller); 03085 caller.id = qe->chan->connected.id; 03086 caller.ani = qe->chan->connected.ani; 03087 ast_channel_set_caller_event(tmp->chan, &caller, NULL); 03088 } else if (!ast_strlen_zero(qe->chan->dialed.number.str)) { 03089 ast_set_callerid(tmp->chan, qe->chan->dialed.number.str, NULL, NULL); 03090 } else if (!ast_strlen_zero(S_OR(qe->chan->macroexten, qe->chan->exten))) { 03091 ast_set_callerid(tmp->chan, S_OR(qe->chan->macroexten, qe->chan->exten), NULL, NULL); 03092 } 03093 tmp->dial_callerid_absent = 1; 03094 } 03095 03096 ast_party_redirecting_copy(&tmp->chan->redirecting, &qe->chan->redirecting); 03097 03098 tmp->chan->dialed.transit_network_select = qe->chan->dialed.transit_network_select; 03099 03100 ast_connected_line_copy_from_caller(&tmp->chan->connected, &qe->chan->caller); 03101 03102 /* Inherit specially named variables from parent channel */ 03103 ast_channel_inherit_variables(qe->chan, tmp->chan); 03104 ast_channel_datastore_inherit(qe->chan, tmp->chan); 03105 03106 /* Presense of ADSI CPE on outgoing channel follows ours */ 03107 tmp->chan->adsicpe = qe->chan->adsicpe; 03108 03109 /* Inherit context and extension */ 03110 macrocontext = pbx_builtin_getvar_helper(qe->chan, "MACRO_CONTEXT"); 03111 ast_string_field_set(tmp->chan, dialcontext, ast_strlen_zero(macrocontext) ? qe->chan->context : macrocontext); 03112 macroexten = pbx_builtin_getvar_helper(qe->chan, "MACRO_EXTEN"); 03113 if (!ast_strlen_zero(macroexten)) 03114 ast_copy_string(tmp->chan->exten, macroexten, sizeof(tmp->chan->exten)); 03115 else 03116 ast_copy_string(tmp->chan->exten, qe->chan->exten, sizeof(tmp->chan->exten)); 03117 if (ast_cdr_isset_unanswered()) { 03118 /* they want to see the unanswered dial attempts! */ 03119 /* set up the CDR fields on all the CDRs to give sensical information */ 03120 ast_cdr_setdestchan(tmp->chan->cdr, tmp->chan->name); 03121 strcpy(tmp->chan->cdr->clid, qe->chan->cdr->clid); 03122 strcpy(tmp->chan->cdr->channel, qe->chan->cdr->channel); 03123 strcpy(tmp->chan->cdr->src, qe->chan->cdr->src); 03124 strcpy(tmp->chan->cdr->dst, qe->chan->exten); 03125 strcpy(tmp->chan->cdr->dcontext, qe->chan->context); 03126 strcpy(tmp->chan->cdr->lastapp, qe->chan->cdr->lastapp); 03127 strcpy(tmp->chan->cdr->lastdata, qe->chan->cdr->lastdata); 03128 tmp->chan->cdr->amaflags = qe->chan->cdr->amaflags; 03129 strcpy(tmp->chan->cdr->accountcode, qe->chan->cdr->accountcode); 03130 strcpy(tmp->chan->cdr->userfield, qe->chan->cdr->userfield); 03131 } 03132 03133 /* Place the call, but don't wait on the answer */ 03134 if ((res = ast_call(tmp->chan, location, 0))) { 03135 /* Again, keep going even if there's an error */ 03136 ast_debug(1, "ast call on peer returned %d\n", res); 03137 ast_verb(3, "Couldn't call %s\n", tmp->interface); 03138 ast_channel_unlock(tmp->chan); 03139 ast_channel_unlock(qe->chan); 03140 do_hang(tmp); 03141 (*busies)++; 03142 update_status(qe->parent, tmp->member, get_queue_member_status(tmp->member)); 03143 return 0; 03144 } else if (qe->parent->eventwhencalled) { 03145 char vars[2048]; 03146 03147 manager_event(EVENT_FLAG_AGENT, "AgentCalled", 03148 "Queue: %s\r\n" 03149 "AgentCalled: %s\r\n" 03150 "AgentName: %s\r\n" 03151 "ChannelCalling: %s\r\n" 03152 "DestinationChannel: %s\r\n" 03153 "CallerIDNum: %s\r\n" 03154 "CallerIDName: %s\r\n" 03155 "Context: %s\r\n" 03156 "Extension: %s\r\n" 03157 "Priority: %d\r\n" 03158 "Uniqueid: %s\r\n" 03159 "%s", 03160 qe->parent->name, tmp->interface, tmp->member->membername, qe->chan->name, tmp->chan->name, 03161 S_COR(tmp->chan->caller.id.number.valid, tmp->chan->caller.id.number.str, "unknown"), 03162 S_COR(tmp->chan->caller.id.name.valid, tmp->chan->caller.id.name.str, "unknown"), 03163 qe->chan->context, qe->chan->exten, qe->chan->priority, qe->chan->uniqueid, 03164 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : ""); 03165 ast_verb(3, "Called %s\n", tmp->interface); 03166 } 03167 ast_channel_unlock(tmp->chan); 03168 ast_channel_unlock(qe->chan); 03169 03170 update_status(qe->parent, tmp->member, get_queue_member_status(tmp->member)); 03171 return 1; 03172 }
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
1 | if a member was called successfully | |
0 | otherwise |
Definition at line 3200 of file app_queue.c.
References ast_debug, callattempt::chan, queue_ent::expire, find_best(), callattempt::interface, callattempt::metric, queue_ent::parent, callattempt::q_next, QUEUE_STRATEGY_RINGALL, ring_entry(), callattempt::stillgoing, and call_queue::strategy.
Referenced by wait_for_answer().
03201 { 03202 int ret = 0; 03203 03204 while (ret == 0) { 03205 struct callattempt *best = find_best(outgoing); 03206 if (!best) { 03207 ast_debug(1, "Nobody left to try ringing in queue\n"); 03208 break; 03209 } 03210 if (qe->parent->strategy == QUEUE_STRATEGY_RINGALL) { 03211 struct callattempt *cur; 03212 /* Ring everyone who shares this best metric (for ringall) */ 03213 for (cur = outgoing; cur; cur = cur->q_next) { 03214 if (cur->stillgoing && !cur->chan && cur->metric <= best->metric) { 03215 ast_debug(1, "(Parallel) Trying '%s' with metric %d\n", cur->interface, cur->metric); 03216 ret |= ring_entry(qe, cur, busies); 03217 } 03218 } 03219 } else { 03220 /* Ring just the best channel */ 03221 ast_debug(1, "Trying '%s' with metric %d\n", best->interface, best->metric); 03222 ret = ring_entry(qe, best, busies); 03223 } 03224 03225 /* If we have timed out, break out */ 03226 if (qe->expire && (time(NULL) >= qe->expire)) { 03227 ast_debug(1, "Queue timed out while ringing members.\n"); 03228 ret = 0; 03229 break; 03230 } 03231 } 03232 03233 return ret; 03234 }
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 3358 of file app_queue.c.
References ast_indicate(), ast_moh_start(), ast_queue_log(), ast_verb, call_queue::autopause, queue_ent::chan, EVENT_FLAG_AGENT, call_queue::eventwhencalled, manager_event, queue_ent::moh, ast_channel::name, call_queue::name, queue_ent::parent, QUEUE_AUTOPAUSE_OFF, QUEUE_AUTOPAUSE_ON, QUEUE_EVENT_VARIABLES, queue_ent::ring_when_ringing, set_member_paused(), ast_channel::uniqueid, and vars2manager().
03359 { 03360 ast_verb(3, "Nobody picked up in %d ms\n", rnatime); 03361 03362 /* Stop ringing, and resume MOH if specified */ 03363 if (qe->ring_when_ringing) { 03364 ast_indicate(qe->chan, -1); 03365 ast_moh_start(qe->chan, qe->moh, NULL); 03366 } 03367 03368 if (qe->parent->eventwhencalled) { 03369 char vars[2048]; 03370 03371 manager_event(EVENT_FLAG_AGENT, "AgentRingNoAnswer", 03372 "Queue: %s\r\n" 03373 "Uniqueid: %s\r\n" 03374 "Channel: %s\r\n" 03375 "Member: %s\r\n" 03376 "MemberName: %s\r\n" 03377 "Ringtime: %d\r\n" 03378 "%s", 03379 qe->parent->name, 03380 qe->chan->uniqueid, 03381 qe->chan->name, 03382 interface, 03383 membername, 03384 rnatime, 03385 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : ""); 03386 } 03387 ast_queue_log(qe->parent->name, qe->chan->uniqueid, membername, "RINGNOANSWER", "%d", rnatime); 03388 if (qe->parent->autopause != QUEUE_AUTOPAUSE_OFF && pause) { 03389 if (qe->parent->autopause == QUEUE_AUTOPAUSE_ON) { 03390 if (!set_member_paused(qe->parent->name, interface, "Auto-Pause", 1)) { 03391 ast_verb(3, "Auto-Pausing Queue Member %s in queue %s since they failed to answer.\n", 03392 interface, qe->parent->name); 03393 } else { 03394 ast_verb(3, "Failed to pause Queue Member %s in queue %s!\n", interface, qe->parent->name); 03395 } 03396 } else { 03397 /* If queue autopause is mode all, just don't send any queue to stop. 03398 * the function will stop in all queues */ 03399 if (!set_member_paused("", interface, "Auto-Pause", 1)) { 03400 ast_verb(3, "Auto-Pausing Queue Member %s in all queues since they failed to answer on queue %s.\n", 03401 interface, qe->parent->name); 03402 } else { 03403 ast_verb(3, "Failed to pause Queue Member %s in all queues!\n", interface); 03404 } 03405 } 03406 } 03407 return; 03408 }
static int rqm_exec | ( | struct ast_channel * | chan, | |
const char * | data | |||
) | [static] |
RemoveQueueMember application.
Definition at line 5592 of file app_queue.c.
References args, AST_APP_ARG, ast_debug, AST_DECLARE_APP_ARGS, ast_log(), ast_queue_log(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), 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().
05593 { 05594 int res=-1; 05595 char *parse, *temppos = NULL; 05596 AST_DECLARE_APP_ARGS(args, 05597 AST_APP_ARG(queuename); 05598 AST_APP_ARG(interface); 05599 AST_APP_ARG(options); 05600 ); 05601 05602 05603 if (ast_strlen_zero(data)) { 05604 ast_log(LOG_WARNING, "RemoveQueueMember requires an argument (queuename[,interface[,options]])\n"); 05605 return -1; 05606 } 05607 05608 parse = ast_strdupa(data); 05609 05610 AST_STANDARD_APP_ARGS(args, parse); 05611 05612 if (ast_strlen_zero(args.interface)) { 05613 args.interface = ast_strdupa(chan->name); 05614 temppos = strrchr(args.interface, '-'); 05615 if (temppos) 05616 *temppos = '\0'; 05617 } 05618 05619 ast_debug(1, "queue: %s, member: %s\n", args.queuename, args.interface); 05620 05621 switch (remove_from_queue(args.queuename, args.interface)) { 05622 case RES_OKAY: 05623 ast_queue_log(args.queuename, chan->uniqueid, args.interface, "REMOVEMEMBER", "%s", ""); 05624 ast_log(LOG_NOTICE, "Removed interface '%s' from queue '%s'\n", args.interface, args.queuename); 05625 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "REMOVED"); 05626 res = 0; 05627 break; 05628 case RES_EXISTS: 05629 ast_debug(1, "Unable to remove interface '%s' from queue '%s': Not there\n", args.interface, args.queuename); 05630 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOTINQUEUE"); 05631 res = 0; 05632 break; 05633 case RES_NOSUCHQUEUE: 05634 ast_log(LOG_WARNING, "Unable to remove interface from queue '%s': No such queue\n", args.queuename); 05635 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOSUCHQUEUE"); 05636 res = 0; 05637 break; 05638 case RES_NOT_DYNAMIC: 05639 ast_log(LOG_WARNING, "Unable to remove interface from queue '%s': '%s' is not a dynamic member\n", args.queuename, args.interface); 05640 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOTDYNAMIC"); 05641 res = 0; 05642 break; 05643 } 05644 05645 return res; 05646 }
static void rt_handle_member_record | ( | struct call_queue * | q, | |
char * | interface, | |||
const char * | rt_uniqueid, | |||
const char * | membername, | |||
const char * | penalty_str, | |||
const char * | paused_str, | |||
const char * | state_interface | |||
) | [static] |
Find rt member record to update otherwise create one.
Search for member in queue, if found update penalty/paused state, if no member exists create one flag it as a RT member and add to queue member list.
Definition at line 2077 of file app_queue.c.
References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_link, ao2_ref, ast_copy_string(), ast_log(), ast_queue_log(), ast_strlen_zero(), create_queue_member(), member::dead, member::interface, LOG_WARNING, call_queue::membercount, call_queue::members, call_queue::name, member::paused, member::penalty, member::realtime, member::rt_uniqueid, S_OR, and member::state_interface.
Referenced by update_realtime_members().
02078 { 02079 struct member *m; 02080 struct ao2_iterator mem_iter; 02081 int penalty = 0; 02082 int paused = 0; 02083 int found = 0; 02084 02085 if (ast_strlen_zero(rt_uniqueid)) { 02086 ast_log(LOG_WARNING, "Realtime field uniqueid is empty for member %s\n", S_OR(membername, "NULL")); 02087 return; 02088 } 02089 02090 if (penalty_str) { 02091 penalty = atoi(penalty_str); 02092 if (penalty < 0) 02093 penalty = 0; 02094 } 02095 02096 if (paused_str) { 02097 paused = atoi(paused_str); 02098 if (paused < 0) 02099 paused = 0; 02100 } 02101 02102 /* Find member by realtime uniqueid and update */ 02103 mem_iter = ao2_iterator_init(q->members, 0); 02104 while ((m = ao2_iterator_next(&mem_iter))) { 02105 if (!strcasecmp(m->rt_uniqueid, rt_uniqueid)) { 02106 m->dead = 0; /* Do not delete this one. */ 02107 ast_copy_string(m->rt_uniqueid, rt_uniqueid, sizeof(m->rt_uniqueid)); 02108 if (paused_str) 02109 m->paused = paused; 02110 if (strcasecmp(state_interface, m->state_interface)) { 02111 ast_copy_string(m->state_interface, state_interface, sizeof(m->state_interface)); 02112 } 02113 m->penalty = penalty; 02114 found = 1; 02115 ao2_ref(m, -1); 02116 break; 02117 } 02118 ao2_ref(m, -1); 02119 } 02120 ao2_iterator_destroy(&mem_iter); 02121 02122 /* Create a new member */ 02123 if (!found) { 02124 if ((m = create_queue_member(interface, membername, penalty, paused, state_interface))) { 02125 m->dead = 0; 02126 m->realtime = 1; 02127 ast_copy_string(m->rt_uniqueid, rt_uniqueid, sizeof(m->rt_uniqueid)); 02128 ast_queue_log(q->name, "REALTIME", m->interface, "ADDMEMBER", "%s", ""); 02129 ao2_link(q->members, m); 02130 ao2_ref(m, -1); 02131 m = NULL; 02132 q->membercount++; 02133 } 02134 } 02135 }
static int say_periodic_announcement | ( | struct queue_ent * | qe, | |
int | ringing | |||
) | [static] |
Playback announcement to queued members if peroid has elapsed.
Definition at line 3285 of file app_queue.c.
References AST_CONTROL_RINGING, ast_indicate(), ast_moh_start(), ast_moh_stop(), ast_random(), ast_str_buffer(), ast_str_strlen(), ast_verb, queue_ent::chan, queue_ent::last_periodic_announce_sound, queue_ent::last_periodic_announce_time, queue_ent::moh, call_queue::numperiodicannounce, queue_ent::parent, call_queue::periodicannouncefrequency, play_file(), call_queue::randomperiodicannounce, call_queue::relativeperiodicannounce, call_queue::sound_periodicannounce, and valid_exit().
Referenced by queue_exec().
03286 { 03287 int res = 0; 03288 time_t now; 03289 03290 /* Get the current time */ 03291 time(&now); 03292 03293 /* Check to see if it is time to announce */ 03294 if ((now - qe->last_periodic_announce_time) < qe->parent->periodicannouncefrequency) 03295 return 0; 03296 03297 /* Stop the music on hold so we can play our own file */ 03298 if (ringing) 03299 ast_indicate(qe->chan,-1); 03300 else 03301 ast_moh_stop(qe->chan); 03302 03303 ast_verb(3, "Playing periodic announcement\n"); 03304 03305 if (qe->parent->randomperiodicannounce && qe->parent->numperiodicannounce) { 03306 qe->last_periodic_announce_sound = ((unsigned long) ast_random()) % qe->parent->numperiodicannounce; 03307 } else if (qe->last_periodic_announce_sound >= qe->parent->numperiodicannounce || 03308 ast_str_strlen(qe->parent->sound_periodicannounce[qe->last_periodic_announce_sound]) == 0) { 03309 qe->last_periodic_announce_sound = 0; 03310 } 03311 03312 /* play the announcement */ 03313 res = play_file(qe->chan, ast_str_buffer(qe->parent->sound_periodicannounce[qe->last_periodic_announce_sound])); 03314 03315 if (res > 0 && !valid_exit(qe, res)) 03316 res = 0; 03317 03318 /* Resume Music on Hold if the caller is going to stay in the queue */ 03319 if (!res) { 03320 if (ringing) 03321 ast_indicate(qe->chan, AST_CONTROL_RINGING); 03322 else 03323 ast_moh_start(qe->chan, qe->moh, NULL); 03324 } 03325 03326 /* update last_periodic_announce_time */ 03327 if (qe->parent->relativeperiodicannounce) 03328 time(&qe->last_periodic_announce_time); 03329 else 03330 qe->last_periodic_announce_time = now; 03331 03332 /* Update the current periodic announcement to the next announcement */ 03333 if (!qe->parent->randomperiodicannounce) { 03334 qe->last_periodic_announce_sound++; 03335 } 03336 03337 return res; 03338 }
static int say_position | ( | struct queue_ent * | qe, | |
int | ringing | |||
) | [static] |
Definition at line 2593 of file app_queue.c.
References call_queue::announcefrequency, call_queue::announceholdtime, ANNOUNCEHOLDTIME_ONCE, call_queue::announceposition, ANNOUNCEPOSITION_LIMIT, ANNOUNCEPOSITION_MORE_THAN, ANNOUNCEPOSITION_YES, call_queue::announcepositionlimit, AST_CONTROL_RINGING, AST_DIGIT_ANY, ast_indicate(), ast_moh_start(), ast_moh_stop(), ast_say_number(), ast_verb, queue_ent::chan, call_queue::holdtime, ast_channel::language, queue_ent::last_pos, queue_ent::last_pos_said, call_queue::minannouncefrequency, queue_ent::moh, ast_channel::name, call_queue::name, queue_ent::parent, play_file(), queue_ent::pos, call_queue::queue_quantity1, call_queue::queue_quantity2, call_queue::roundingseconds, call_queue::sound_calls, call_queue::sound_holdtime, call_queue::sound_minute, call_queue::sound_minutes, call_queue::sound_next, call_queue::sound_seconds, call_queue::sound_thanks, call_queue::sound_thereare, queue_ent::start, and valid_exit().
Referenced by queue_exec().
02594 { 02595 int res = 0, avgholdmins, avgholdsecs, announceposition = 0; 02596 int say_thanks = 1; 02597 time_t now; 02598 02599 /* Let minannouncefrequency seconds pass between the start of each position announcement */ 02600 time(&now); 02601 if ((now - qe->last_pos) < qe->parent->minannouncefrequency) 02602 return 0; 02603 02604 /* If either our position has changed, or we are over the freq timer, say position */ 02605 if ((qe->last_pos_said == qe->pos) && ((now - qe->last_pos) < qe->parent->announcefrequency)) 02606 return 0; 02607 02608 if (ringing) { 02609 ast_indicate(qe->chan,-1); 02610 } else { 02611 ast_moh_stop(qe->chan); 02612 } 02613 02614 if (qe->parent->announceposition == ANNOUNCEPOSITION_YES || 02615 qe->parent->announceposition == ANNOUNCEPOSITION_MORE_THAN || 02616 (qe->parent->announceposition == ANNOUNCEPOSITION_LIMIT && 02617 qe->pos <= qe->parent->announcepositionlimit)) 02618 announceposition = 1; 02619 02620 02621 if (announceposition == 1) { 02622 /* Say we're next, if we are */ 02623 if (qe->pos == 1) { 02624 res = play_file(qe->chan, qe->parent->sound_next); 02625 if (res) 02626 goto playout; 02627 else 02628 goto posout; 02629 } else { 02630 if (qe->parent->announceposition == ANNOUNCEPOSITION_MORE_THAN && qe->pos > qe->parent->announcepositionlimit){ 02631 /* More than Case*/ 02632 res = play_file(qe->chan, qe->parent->queue_quantity1); 02633 if (res) 02634 goto playout; 02635 res = ast_say_number(qe->chan, qe->parent->announcepositionlimit, AST_DIGIT_ANY, qe->chan->language, NULL); /* Needs gender */ 02636 if (res) 02637 goto playout; 02638 } else { 02639 /* Normal Case */ 02640 res = play_file(qe->chan, qe->parent->sound_thereare); 02641 if (res) 02642 goto playout; 02643 res = ast_say_number(qe->chan, qe->pos, AST_DIGIT_ANY, qe->chan->language, NULL); /* Needs gender */ 02644 if (res) 02645 goto playout; 02646 } 02647 if (qe->parent->announceposition == ANNOUNCEPOSITION_MORE_THAN && qe->pos > qe->parent->announcepositionlimit){ 02648 /* More than Case*/ 02649 res = play_file(qe->chan, qe->parent->queue_quantity2); 02650 if (res) 02651 goto playout; 02652 } else { 02653 res = play_file(qe->chan, qe->parent->sound_calls); 02654 if (res) 02655 goto playout; 02656 } 02657 } 02658 } 02659 /* Round hold time to nearest minute */ 02660 avgholdmins = abs(((qe->parent->holdtime + 30) - (now - qe->start)) / 60); 02661 02662 /* If they have specified a rounding then round the seconds as well */ 02663 if (qe->parent->roundingseconds) { 02664 avgholdsecs = (abs(((qe->parent->holdtime + 30) - (now - qe->start))) - 60 * avgholdmins) / qe->parent->roundingseconds; 02665 avgholdsecs *= qe->parent->roundingseconds; 02666 } else { 02667 avgholdsecs = 0; 02668 } 02669 02670 ast_verb(3, "Hold time for %s is %d minute(s) %d seconds\n", qe->parent->name, avgholdmins, avgholdsecs); 02671 02672 /* If the hold time is >1 min, if it's enabled, and if it's not 02673 supposed to be only once and we have already said it, say it */ 02674 if ((avgholdmins+avgholdsecs) > 0 && qe->parent->announceholdtime && 02675 ((qe->parent->announceholdtime == ANNOUNCEHOLDTIME_ONCE && !qe->last_pos) || 02676 !(qe->parent->announceholdtime == ANNOUNCEHOLDTIME_ONCE))) { 02677 res = play_file(qe->chan, qe->parent->sound_holdtime); 02678 if (res) 02679 goto playout; 02680 02681 if (avgholdmins >= 1) { 02682 res = ast_say_number(qe->chan, avgholdmins, AST_DIGIT_ANY, qe->chan->language, NULL); 02683 if (res) 02684 goto playout; 02685 02686 if (avgholdmins == 1) { 02687 res = play_file(qe->chan, qe->parent->sound_minute); 02688 if (res) 02689 goto playout; 02690 } else { 02691 res = play_file(qe->chan, qe->parent->sound_minutes); 02692 if (res) 02693 goto playout; 02694 } 02695 } 02696 if (avgholdsecs >= 1) { 02697 res = ast_say_number(qe->chan, avgholdsecs, AST_DIGIT_ANY, qe->chan->language, NULL); 02698 if (res) 02699 goto playout; 02700 02701 res = play_file(qe->chan, qe->parent->sound_seconds); 02702 if (res) 02703 goto playout; 02704 } 02705 } else if (qe->parent->announceholdtime && !qe->parent->announceposition) { 02706 say_thanks = 0; 02707 } 02708 02709 posout: 02710 if (qe->parent->announceposition) { 02711 ast_verb(3, "Told %s in %s their queue position (which was %d)\n", 02712 qe->chan->name, qe->parent->name, qe->pos); 02713 } 02714 if (say_thanks) { 02715 res = play_file(qe->chan, qe->parent->sound_thanks); 02716 } 02717 playout: 02718 02719 if ((res > 0 && !valid_exit(qe, res))) 02720 res = 0; 02721 02722 /* Set our last_pos indicators */ 02723 qe->last_pos = now; 02724 qe->last_pos_said = qe->pos; 02725 02726 /* Don't restart music on hold if we're about to exit the caller from the queue */ 02727 if (!res) { 02728 if (ringing) { 02729 ast_indicate(qe->chan, AST_CONTROL_RINGING); 02730 } else { 02731 ast_moh_start(qe->chan, qe->moh, NULL); 02732 } 02733 } 02734 return res; 02735 }
static void send_agent_complete | ( | const struct queue_ent * | qe, | |
const char * | queuename, | |||
const struct ast_channel * | peer, | |||
const struct member * | member, | |||
time_t | callstart, | |||
char * | vars, | |||
size_t | vars_len, | |||
enum agent_complete_reason | rsn | |||
) | [static] |
Send out AMI message with member call completion status information.
Definition at line 4116 of file app_queue.c.
References AGENT, CALLER, queue_ent::chan, EVENT_FLAG_AGENT, call_queue::eventwhencalled, member::interface, manager_event, member::membername, ast_channel::name, queue_ent::parent, QUEUE_EVENT_VARIABLES, queue_ent::start, ast_channel::uniqueid, and vars2manager().
04119 { 04120 const char *reason = NULL; /* silence dumb compilers */ 04121 04122 if (!qe->parent->eventwhencalled) 04123 return; 04124 04125 switch (rsn) { 04126 case CALLER: 04127 reason = "caller"; 04128 break; 04129 case AGENT: 04130 reason = "agent"; 04131 break; 04132 case TRANSFER: 04133 reason = "transfer"; 04134 break; 04135 } 04136 04137 manager_event(EVENT_FLAG_AGENT, "AgentComplete", 04138 "Queue: %s\r\n" 04139 "Uniqueid: %s\r\n" 04140 "Channel: %s\r\n" 04141 "Member: %s\r\n" 04142 "MemberName: %s\r\n" 04143 "HoldTime: %ld\r\n" 04144 "TalkTime: %ld\r\n" 04145 "Reason: %s\r\n" 04146 "%s", 04147 queuename, qe->chan->uniqueid, peer->name, member->interface, member->membername, 04148 (long)(callstart - qe->start), (long)(time(NULL) - callstart), reason, 04149 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, vars_len) : ""); 04150 }
static int set_member_paused | ( | const char * | queuename, | |
const char * | interface, | |||
const char * | reason, | |||
int | paused | |||
) | [static] |
Definition at line 5265 of file app_queue.c.
References ao2_iterator_destroy(), ao2_iterator_init(), ao2_lock, ao2_ref, ao2_t_iterator_next, ao2_unlock, ast_debug, ast_log(), ast_queue_log(), ast_strlen_zero(), dump_queue_members(), EVENT_FLAG_AGENT, member::interface, interface_exists(), LOG_WARNING, manager_event, member::membername, call_queue::name, member::paused, queue_t_unref, member::realtime, RESULT_FAILURE, RESULT_SUCCESS, S_OR, and update_realtime_member_field().
Referenced by handle_queue_pause_member(), manager_pause_queue_member(), pqm_exec(), rna(), and upqm_exec().
05266 { 05267 int found = 0; 05268 struct call_queue *q; 05269 struct member *mem; 05270 struct ao2_iterator queue_iter; 05271 int failed; 05272 05273 /* Special event for when all queues are paused - individual events still generated */ 05274 /* XXX In all other cases, we use the membername, but since this affects all queues, we cannot */ 05275 if (ast_strlen_zero(queuename)) 05276 ast_queue_log("NONE", "NONE", interface, (paused ? "PAUSEALL" : "UNPAUSEALL"), "%s", ""); 05277 05278 queue_iter = ao2_iterator_init(queues, 0); 05279 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate over queues"))) { 05280 ao2_lock(q); 05281 if (ast_strlen_zero(queuename) || !strcasecmp(q->name, queuename)) { 05282 if ((mem = interface_exists(q, interface))) { 05283 if (mem->paused == paused) { 05284 ast_debug(1, "%spausing already-%spaused queue member %s:%s\n", (paused ? "" : "un"), (paused ? "" : "un"), q->name, interface); 05285 } 05286 05287 failed = 0; 05288 if (mem->realtime) { 05289 failed = update_realtime_member_field(mem, q->name, "paused", paused ? "1" : "0"); 05290 } 05291 05292 if (failed) { 05293 ast_log(LOG_WARNING, "Failed %spausing realtime queue member %s:%s\n", (paused ? "" : "un"), q->name, interface); 05294 ao2_ref(mem, -1); 05295 ao2_unlock(q); 05296 queue_t_unref(q, "Done with iterator"); 05297 continue; 05298 } 05299 found++; 05300 mem->paused = paused; 05301 05302 if (queue_persistent_members) 05303 dump_queue_members(q); 05304 05305 ast_queue_log(q->name, "NONE", mem->membername, (paused ? "PAUSE" : "UNPAUSE"), "%s", S_OR(reason, "")); 05306 05307 if (!ast_strlen_zero(reason)) { 05308 manager_event(EVENT_FLAG_AGENT, "QueueMemberPaused", 05309 "Queue: %s\r\n" 05310 "Location: %s\r\n" 05311 "MemberName: %s\r\n" 05312 "Paused: %d\r\n" 05313 "Reason: %s\r\n", 05314 q->name, mem->interface, mem->membername, paused, reason); 05315 } else { 05316 manager_event(EVENT_FLAG_AGENT, "QueueMemberPaused", 05317 "Queue: %s\r\n" 05318 "Location: %s\r\n" 05319 "MemberName: %s\r\n" 05320 "Paused: %d\r\n", 05321 q->name, mem->interface, mem->membername, paused); 05322 } 05323 ao2_ref(mem, -1); 05324 } 05325 } 05326 05327 if (!ast_strlen_zero(queuename) && !strcasecmp(queuename, q->name)) { 05328 ao2_unlock(q); 05329 queue_t_unref(q, "Done with iterator"); 05330 break; 05331 } 05332 05333 ao2_unlock(q); 05334 queue_t_unref(q, "Done with iterator"); 05335 } 05336 ao2_iterator_destroy(&queue_iter); 05337 05338 return found ? RESULT_SUCCESS : RESULT_FAILURE; 05339 }
static int set_member_penalty | ( | const char * | queuename, | |
const char * | interface, | |||
int | penalty | |||
) | [static] |
Definition at line 5342 of file app_queue.c.
References ao2_iterator_destroy(), ao2_iterator_init(), ao2_lock, ao2_ref, ao2_t_iterator_next, ao2_unlock, ast_log(), ast_queue_log(), ast_strlen_zero(), EVENT_FLAG_AGENT, member::interface, interface_exists(), LOG_ERROR, manager_event, call_queue::name, member::penalty, queue_t_unref, RESULT_FAILURE, and RESULT_SUCCESS.
Referenced by handle_queue_set_member_penalty(), manager_queue_member_penalty(), and queue_function_memberpenalty_write().
05343 { 05344 int foundinterface = 0, foundqueue = 0; 05345 struct call_queue *q; 05346 struct member *mem; 05347 struct ao2_iterator queue_iter; 05348 05349 if (penalty < 0) { 05350 ast_log(LOG_ERROR, "Invalid penalty (%d)\n", penalty); 05351 return RESULT_FAILURE; 05352 } 05353 05354 queue_iter = ao2_iterator_init(queues, 0); 05355 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) { 05356 ao2_lock(q); 05357 if (ast_strlen_zero(queuename) || !strcasecmp(q->name, queuename)) { 05358 foundqueue++; 05359 if ((mem = interface_exists(q, interface))) { 05360 foundinterface++; 05361 mem->penalty = penalty; 05362 05363 ast_queue_log(q->name, "NONE", interface, "PENALTY", "%d", penalty); 05364 manager_event(EVENT_FLAG_AGENT, "QueueMemberPenalty", 05365 "Queue: %s\r\n" 05366 "Location: %s\r\n" 05367 "Penalty: %d\r\n", 05368 q->name, mem->interface, penalty); 05369 ao2_ref(mem, -1); 05370 } 05371 } 05372 ao2_unlock(q); 05373 queue_t_unref(q, "Done with iterator"); 05374 } 05375 ao2_iterator_destroy(&queue_iter); 05376 05377 if (foundinterface) { 05378 return RESULT_SUCCESS; 05379 } else if (!foundqueue) { 05380 ast_log (LOG_ERROR, "Invalid queuename\n"); 05381 } else { 05382 ast_log (LOG_ERROR, "Invalid interface\n"); 05383 } 05384 05385 return RESULT_FAILURE; 05386 }
static void set_queue_result | ( | struct ast_channel * | chan, | |
enum queue_result | res | |||
) | [static] |
sets the QUEUESTATUS channel variable
Definition at line 1197 of file app_queue.c.
References ARRAY_LEN, pbx_builtin_setvar_helper(), queue_results, and text.
Referenced by queue_exec().
01198 { 01199 int i; 01200 01201 for (i = 0; i < ARRAY_LEN(queue_results); i++) { 01202 if (queue_results[i].id == res) { 01203 pbx_builtin_setvar_helper(chan, "QUEUESTATUS", queue_results[i].text); 01204 return; 01205 } 01206 } 01207 }
static void set_queue_variables | ( | struct call_queue * | q, | |
struct ast_channel * | chan | |||
) | [static] |
Set variables of queue.
Definition at line 1292 of file app_queue.c.
References ao2_lock, ao2_unlock, call_queue::callsabandoned, call_queue::callscompleted, call_queue::callscompletedinsl, queue_ent::chan, call_queue::count, call_queue::holdtime, int2strat(), call_queue::maxlen, call_queue::name, pbx_builtin_setvar_multiple(), call_queue::servicelevel, call_queue::setqueuevar, call_queue::strategy, and call_queue::talktime.
Referenced by end_bridge_callback(), and record_abandoned().
01293 { 01294 char interfacevar[256]=""; 01295 float sl = 0; 01296 01297 ao2_lock(q); 01298 01299 if (q->setqueuevar) { 01300 sl = 0; 01301 if (q->callscompleted > 0) 01302 sl = 100 * ((float) q->callscompletedinsl / (float) q->callscompleted); 01303 01304 snprintf(interfacevar, sizeof(interfacevar), 01305 "QUEUENAME=%s,QUEUEMAX=%d,QUEUESTRATEGY=%s,QUEUECALLS=%d,QUEUEHOLDTIME=%d,QUEUETALKTIME=%d,QUEUECOMPLETED=%d,QUEUEABANDONED=%d,QUEUESRVLEVEL=%d,QUEUESRVLEVELPERF=%2.1f", 01306 q->name, q->maxlen, int2strat(q->strategy), q->count, q->holdtime, q->talktime, q->callscompleted, q->callsabandoned, q->servicelevel, sl); 01307 01308 ao2_unlock(q); 01309 01310 pbx_builtin_setvar_multiple(chan, interfacevar); 01311 } else { 01312 ao2_unlock(q); 01313 } 01314 }
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 4220 of file app_queue.c.
References ast_calloc, ast_channel_datastore_add(), ast_channel_lock, ast_channel_unlock, ast_datastore_alloc, ast_log(), queue_ent::chan, ast_datastore::data, LOG_WARNING, queue_transfer_ds::member, queue_transfer_ds::qe, and queue_transfer_info.
04221 { 04222 struct ast_datastore *ds; 04223 struct queue_transfer_ds *qtds = ast_calloc(1, sizeof(*qtds)); 04224 04225 if (!qtds) { 04226 ast_log(LOG_WARNING, "Memory allocation error!\n"); 04227 return NULL; 04228 } 04229 04230 ast_channel_lock(qe->chan); 04231 if (!(ds = ast_datastore_alloc(&queue_transfer_info, NULL))) { 04232 ast_channel_unlock(qe->chan); 04233 ast_log(LOG_WARNING, "Unable to create transfer datastore. queue_log will not show attended transfer\n"); 04234 return NULL; 04235 } 04236 04237 qtds->qe = qe; 04238 /* This member is refcounted in try_calling, so no need to add it here, too */ 04239 qtds->member = member; 04240 qtds->starttime = starttime; 04241 qtds->callcompletedinsl = callcompletedinsl; 04242 ds->data = qtds; 04243 ast_channel_datastore_add(qe->chan, ds); 04244 ast_channel_unlock(qe->chan); 04245 return ds; 04246 }
static int store_next_lin | ( | struct queue_ent * | qe, | |
struct callattempt * | outgoing | |||
) | [static] |
Search for best metric and add to Linear queue.
Definition at line 3261 of file app_queue.c.
References ast_debug, find_best(), callattempt::interface, queue_ent::linpos, queue_ent::linwrapped, and callattempt::metric.
03262 { 03263 struct callattempt *best = find_best(outgoing); 03264 03265 if (best) { 03266 /* Ring just the best channel */ 03267 ast_debug(1, "Next is '%s' with metric %d\n", best->interface, best->metric); 03268 qe->linpos = best->metric % 1000; 03269 } else { 03270 /* Just increment rrpos */ 03271 if (qe->linwrapped) { 03272 /* No more channels, start over */ 03273 qe->linpos = 0; 03274 } else { 03275 /* Prioritize next entry */ 03276 qe->linpos++; 03277 } 03278 } 03279 qe->linwrapped = 0; 03280 03281 return 0; 03282 }
static int store_next_rr | ( | struct queue_ent * | qe, | |
struct callattempt * | outgoing | |||
) | [static] |
Search for best metric and add to Round Robbin queue.
Definition at line 3237 of file app_queue.c.
References ast_debug, find_best(), callattempt::interface, callattempt::metric, queue_ent::parent, call_queue::rrpos, and call_queue::wrapped.
03238 { 03239 struct callattempt *best = find_best(outgoing); 03240 03241 if (best) { 03242 /* Ring just the best channel */ 03243 ast_debug(1, "Next is '%s' with metric %d\n", best->interface, best->metric); 03244 qe->parent->rrpos = best->metric % 1000; 03245 } else { 03246 /* Just increment rrpos */ 03247 if (qe->parent->wrapped) { 03248 /* No more channels, start over */ 03249 qe->parent->rrpos = 0; 03250 } else { 03251 /* Prioritize next entry */ 03252 qe->parent->rrpos++; 03253 } 03254 } 03255 qe->parent->wrapped = 0; 03256 03257 return 0; 03258 }
static int strat2int | ( | const char * | strategy | ) | [static] |
Definition at line 1221 of file app_queue.c.
References ARRAY_LEN, strategies, and strategy::strategy.
Referenced by find_queue_by_name_rt(), queue_set_param(), and reload_single_queue().
01222 { 01223 int x; 01224 01225 for (x = 0; x < ARRAY_LEN(strategies); x++) { 01226 if (!strcasecmp(strategy, strategies[x].name)) 01227 return strategies[x].strategy; 01228 } 01229 01230 return -1; 01231 }
static int try_calling | ( | struct queue_ent * | qe, | |
const char * | options, | |||
char * | announceoverride, | |||
const char * | url, | |||
int * | tries, | |||
int * | noption, | |||
const char * | agi, | |||
const char * | macro, | |||
const char * | gosub, | |||
int | ringing | |||
) | [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] | announceoverride | filename to play to user when waiting |
[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 |
[in] | macro | the macro passed as the sixth parameter to the Queue() application |
[in] | gosub | the gosub passed as the seventh parameter to the Queue() application |
[in] | ringing | 1 if the 'r' option is set, otherwise 0 |
Definition at line 4300 of file app_queue.c.
References ast_channel_datastore_find(), ast_channel_lock, ast_channel_unlock, AST_FEATURE_AUTOMIXMON, AST_FEATURE_AUTOMON, AST_FEATURE_DISCONNECT, AST_FEATURE_NO_H_EXTEN, AST_FEATURE_PARKCALL, AST_FEATURE_REDIRECT, AST_FLAG_ANSWERED_ELSEWHERE, AST_MAX_CONTEXT, AST_MAX_EXTENSION, ast_set_flag, ast_test_flag, queue_ent::cancel_answered_elsewhere, queue_ent::chan, dialed_interface_info, queue_ent::expire, call_queue::membercount, queue_ent::parent, QUEUE_STRATEGY_LINEAR, QUEUE_STRATEGY_RRMEMORY, QUEUE_STRATEGY_RRORDERED, and call_queue::strategy.
Referenced by queue_exec().
04301 { 04302 struct member *cur; 04303 struct callattempt *outgoing = NULL; /* the list of calls we are building */ 04304 int to, orig; 04305 char oldexten[AST_MAX_EXTENSION]=""; 04306 char oldcontext[AST_MAX_CONTEXT]=""; 04307 char queuename[256]=""; 04308 char interfacevar[256]=""; 04309 struct ast_channel *peer; 04310 struct ast_channel *which; 04311 struct callattempt *lpeer; 04312 struct member *member; 04313 struct ast_app *application; 04314 int res = 0, bridge = 0; 04315 int numbusies = 0; 04316 int x=0; 04317 char *announce = NULL; 04318 char digit = 0; 04319 time_t callstart; 04320 time_t now = time(NULL); 04321 struct ast_bridge_config bridge_config; 04322 char nondataquality = 1; 04323 char *agiexec = NULL; 04324 char *macroexec = NULL; 04325 char *gosubexec = NULL; 04326 int ret = 0; 04327 const char *monitorfilename; 04328 const char *monitor_exec; 04329 const char *monitor_options; 04330 char tmpid[256], tmpid2[256]; 04331 char meid[1024], meid2[1024]; 04332 char mixmonargs[1512]; 04333 struct ast_app *mixmonapp = NULL; 04334 char *p; 04335 char vars[2048]; 04336 int forwardsallowed = 1; 04337 int update_connectedline = 1; 04338 int callcompletedinsl; 04339 struct ao2_iterator memi; 04340 struct ast_datastore *datastore, *transfer_ds; 04341 struct queue_end_bridge *queue_end_bridge = NULL; 04342 const int need_weight = use_weight; 04343 04344 ast_channel_lock(qe->chan); 04345 datastore = ast_channel_datastore_find(qe->chan, &dialed_interface_info, NULL); 04346 ast_channel_unlock(qe->chan); 04347 04348 memset(&bridge_config, 0, sizeof(bridge_config)); 04349 tmpid[0] = 0; 04350 meid[0] = 0; 04351 time(&now); 04352 04353 /* If we've already exceeded our timeout, then just stop 04354 * This should be extremely rare. queue_exec will take care 04355 * of removing the caller and reporting the timeout as the reason. 04356 */ 04357 if (qe->expire && now >= qe->expire) { 04358 res = 0; 04359 goto out; 04360 } 04361 04362 for (; options && *options; options++) 04363 switch (*options) { 04364 case 't': 04365 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_REDIRECT); 04366 break; 04367 case 'T': 04368 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_REDIRECT); 04369 break; 04370 case 'w': 04371 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_AUTOMON); 04372 break; 04373 case 'W': 04374 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_AUTOMON); 04375 break; 04376 case 'c': 04377 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_NO_H_EXTEN); 04378 break; 04379 case 'd': 04380 nondataquality = 0; 04381 break; 04382 case 'h': 04383 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_DISCONNECT); 04384 break; 04385 case 'H': 04386 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT); 04387 break; 04388 case 'k': 04389 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_PARKCALL); 04390 break; 04391 case 'K': 04392 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_PARKCALL); 04393 break; 04394 case 'n': 04395 if (qe->parent->strategy == QUEUE_STRATEGY_RRMEMORY || qe->parent->strategy == QUEUE_STRATEGY_LINEAR || qe->parent->strategy == QUEUE_STRATEGY_RRORDERED) 04396 (*tries)++; 04397 else 04398 *tries = qe->parent->membercount; 04399 *noption = 1; 04400 break; 04401 case 'i': 04402 forwardsallowed = 0; 04403 break; 04404 case 'I': 04405 update_connectedline = 0; 04406 break; 04407 case 'x': 04408 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_AUTOMIXMON); 04409 break; 04410 case 'X': 04411 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_AUTOMIXMON); 04412 break; 04413 case 'C': 04414 qe->cancel_answered_elsewhere = 1; 04415 break; 04416 } 04417 04418 /* if the calling channel has the ANSWERED_ELSEWHERE flag set, make sure this is inherited. 04419 (this is mainly to support chan_local) 04420 */ 04421 if (ast_test_flag(qe->chan, AST_FLAG_ANSWERED_ELSEWHERE)) { 04422 qe->cancel_answered_elsewhere = 1; 04423 } 04424 04425 /* Hold the lock while we setup the outgoing calls */ 04426 if (need_weight) 04427 ao2_lock(queues); 04428 ao2_lock(qe->parent); 04429 ast_debug(1, "%s is trying to call a queue member.\n", 04430 qe->chan->name); 04431 ast_copy_string(queuename, qe->parent->name, sizeof(queuename)); 04432 if (!ast_strlen_zero(qe->announce)) 04433 announce = qe->announce; 04434 if (!ast_strlen_zero(announceoverride)) 04435 announce = announceoverride; 04436 04437 memi = ao2_iterator_init(qe->parent->members, 0); 04438 while ((cur = ao2_iterator_next(&memi))) { 04439 struct callattempt *tmp = ast_calloc(1, sizeof(*tmp)); 04440 struct ast_dialed_interface *di; 04441 AST_LIST_HEAD(, ast_dialed_interface) *dialed_interfaces; 04442 if (!tmp) { 04443 ao2_ref(cur, -1); 04444 ao2_unlock(qe->parent); 04445 ao2_iterator_destroy(&memi); 04446 if (need_weight) 04447 ao2_unlock(queues); 04448 goto out; 04449 } 04450 if (!datastore) { 04451 if (!(datastore = ast_datastore_alloc(&dialed_interface_info, NULL))) { 04452 ao2_ref(cur, -1); 04453 ao2_unlock(qe->parent); 04454 ao2_iterator_destroy(&memi); 04455 if (need_weight) 04456 ao2_unlock(queues); 04457 callattempt_free(tmp); 04458 goto out; 04459 } 04460 datastore->inheritance = DATASTORE_INHERIT_FOREVER; 04461 if (!(dialed_interfaces = ast_calloc(1, sizeof(*dialed_interfaces)))) { 04462 ao2_ref(cur, -1); 04463 ao2_unlock(&qe->parent); 04464 ao2_iterator_destroy(&memi); 04465 if (need_weight) 04466 ao2_unlock(queues); 04467 callattempt_free(tmp); 04468 goto out; 04469 } 04470 datastore->data = dialed_interfaces; 04471 AST_LIST_HEAD_INIT(dialed_interfaces); 04472 04473 ast_channel_lock(qe->chan); 04474 ast_channel_datastore_add(qe->chan, datastore); 04475 ast_channel_unlock(qe->chan); 04476 } else 04477 dialed_interfaces = datastore->data; 04478 04479 AST_LIST_LOCK(dialed_interfaces); 04480 AST_LIST_TRAVERSE(dialed_interfaces, di, list) { 04481 if (!strcasecmp(cur->interface, di->interface)) { 04482 ast_debug(1, "Skipping dialing interface '%s' since it has already been dialed\n", 04483 di->interface); 04484 break; 04485 } 04486 } 04487 AST_LIST_UNLOCK(dialed_interfaces); 04488 04489 if (di) { 04490 callattempt_free(tmp); 04491 continue; 04492 } 04493 04494 /* It is always ok to dial a Local interface. We only keep track of 04495 * which "real" interfaces have been dialed. The Local channel will 04496 * inherit this list so that if it ends up dialing a real interface, 04497 * it won't call one that has already been called. */ 04498 if (strncasecmp(cur->interface, "Local/", 6)) { 04499 if (!(di = ast_calloc(1, sizeof(*di) + strlen(cur->interface)))) { 04500 ao2_ref(cur, -1); 04501 ao2_unlock(qe->parent); 04502 ao2_iterator_destroy(&memi); 04503 if (need_weight) 04504 ao2_unlock(queues); 04505 callattempt_free(tmp); 04506 goto out; 04507 } 04508 strcpy(di->interface, cur->interface); 04509 04510 AST_LIST_LOCK(dialed_interfaces); 04511 AST_LIST_INSERT_TAIL(dialed_interfaces, di, list); 04512 AST_LIST_UNLOCK(dialed_interfaces); 04513 } 04514 04515 ast_channel_lock(qe->chan); 04516 /* 04517 * Seed the callattempt's connected line information with previously 04518 * acquired connected line info from the queued channel. The 04519 * previously acquired connected line info could have been set 04520 * through the CONNECTED_LINE dialplan function. 04521 */ 04522 ast_party_connected_line_copy(&tmp->connected, &qe->chan->connected); 04523 ast_channel_unlock(qe->chan); 04524 04525 tmp->stillgoing = -1; 04526 tmp->member = cur;/* Place the reference for cur into callattempt. */ 04527 tmp->lastcall = cur->lastcall; 04528 tmp->lastqueue = cur->lastqueue; 04529 ast_copy_string(tmp->interface, cur->interface, sizeof(tmp->interface)); 04530 /* Special case: If we ring everyone, go ahead and ring them, otherwise 04531 just calculate their metric for the appropriate strategy */ 04532 if (!calc_metric(qe->parent, cur, x++, qe, tmp)) { 04533 /* Put them in the list of outgoing thingies... We're ready now. 04534 XXX If we're forcibly removed, these outgoing calls won't get 04535 hung up XXX */ 04536 tmp->q_next = outgoing; 04537 outgoing = tmp; 04538 /* If this line is up, don't try anybody else */ 04539 if (outgoing->chan && (outgoing->chan->_state == AST_STATE_UP)) 04540 break; 04541 } else { 04542 callattempt_free(tmp); 04543 } 04544 } 04545 ao2_iterator_destroy(&memi); 04546 04547 if (qe->parent->timeoutpriority == TIMEOUT_PRIORITY_APP) { 04548 /* Application arguments have higher timeout priority (behaviour for <=1.6) */ 04549 if (qe->expire && (!qe->parent->timeout || (qe->expire - now) <= qe->parent->timeout)) 04550 to = (qe->expire - now) * 1000; 04551 else 04552 to = (qe->parent->timeout) ? qe->parent->timeout * 1000 : -1; 04553 } else { 04554 /* Config timeout is higher priority thatn application timeout */ 04555 if (qe->expire && qe->expire<=now) { 04556 to = 0; 04557 } else if (qe->parent->timeout) { 04558 to = qe->parent->timeout * 1000; 04559 } else { 04560 to = -1; 04561 } 04562 } 04563 orig = to; 04564 ++qe->pending; 04565 ao2_unlock(qe->parent); 04566 ring_one(qe, outgoing, &numbusies); 04567 if (need_weight) 04568 ao2_unlock(queues); 04569 lpeer = wait_for_answer(qe, outgoing, &to, &digit, numbusies, ast_test_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT), forwardsallowed, update_connectedline); 04570 /* The ast_channel_datastore_remove() function could fail here if the 04571 * datastore was moved to another channel during a masquerade. If this is 04572 * the case, don't free the datastore here because later, when the channel 04573 * to which the datastore was moved hangs up, it will attempt to free this 04574 * datastore again, causing a crash 04575 */ 04576 ast_channel_lock(qe->chan); 04577 if (datastore && !ast_channel_datastore_remove(qe->chan, datastore)) { 04578 ast_datastore_free(datastore); 04579 } 04580 ast_channel_unlock(qe->chan); 04581 ao2_lock(qe->parent); 04582 if (qe->parent->strategy == QUEUE_STRATEGY_RRMEMORY || qe->parent->strategy == QUEUE_STRATEGY_RRORDERED) { 04583 store_next_rr(qe, outgoing); 04584 04585 } 04586 if (qe->parent->strategy == QUEUE_STRATEGY_LINEAR) { 04587 store_next_lin(qe, outgoing); 04588 } 04589 ao2_unlock(qe->parent); 04590 peer = lpeer ? lpeer->chan : NULL; 04591 if (!peer) { 04592 qe->pending = 0; 04593 if (to) { 04594 /* Must gotten hung up */ 04595 res = -1; 04596 } else { 04597 /* User exited by pressing a digit */ 04598 res = digit; 04599 } 04600 if (res == -1) 04601 ast_debug(1, "%s: Nobody answered.\n", qe->chan->name); 04602 if (ast_cdr_isset_unanswered()) { 04603 /* channel contains the name of one of the outgoing channels 04604 in its CDR; zero out this CDR to avoid a dual-posting */ 04605 struct callattempt *o; 04606 for (o = outgoing; o; o = o->q_next) { 04607 if (!o->chan) { 04608 continue; 04609 } 04610 if (strcmp(o->chan->cdr->dstchannel, qe->chan->cdr->dstchannel) == 0) { 04611 ast_set_flag(o->chan->cdr, AST_CDR_FLAG_POST_DISABLED); 04612 break; 04613 } 04614 } 04615 } 04616 } else { /* peer is valid */ 04617 /* Ah ha! Someone answered within the desired timeframe. Of course after this 04618 we will always return with -1 so that it is hung up properly after the 04619 conversation. */ 04620 if (!strcmp(qe->chan->tech->type, "DAHDI")) 04621 ast_channel_setoption(qe->chan, AST_OPTION_TONE_VERIFY, &nondataquality, sizeof(nondataquality), 0); 04622 if (!strcmp(peer->tech->type, "DAHDI")) 04623 ast_channel_setoption(peer, AST_OPTION_TONE_VERIFY, &nondataquality, sizeof(nondataquality), 0); 04624 /* Update parameters for the queue */ 04625 time(&now); 04626 recalc_holdtime(qe, (now - qe->start)); 04627 ao2_lock(qe->parent); 04628 callcompletedinsl = ((now - qe->start) <= qe->parent->servicelevel); 04629 ao2_unlock(qe->parent); 04630 member = lpeer->member; 04631 /* Increment the refcount for this member, since we're going to be using it for awhile in here. */ 04632 ao2_ref(member, 1); 04633 hangupcalls(outgoing, peer, qe->cancel_answered_elsewhere); 04634 outgoing = NULL; 04635 if (announce || qe->parent->reportholdtime || qe->parent->memberdelay) { 04636 int res2; 04637 04638 res2 = ast_autoservice_start(qe->chan); 04639 if (!res2) { 04640 if (qe->parent->memberdelay) { 04641 ast_log(LOG_NOTICE, "Delaying member connect for %d seconds\n", qe->parent->memberdelay); 04642 res2 |= ast_safe_sleep(peer, qe->parent->memberdelay * 1000); 04643 } 04644 if (!res2 && announce) { 04645 play_file(peer, announce); 04646 } 04647 if (!res2 && qe->parent->reportholdtime) { 04648 if (!play_file(peer, qe->parent->sound_reporthold)) { 04649 int holdtime, holdtimesecs; 04650 04651 time(&now); 04652 holdtime = abs((now - qe->start) / 60); 04653 holdtimesecs = abs((now - qe->start) % 60); 04654 if (holdtime > 0) { 04655 ast_say_number(peer, holdtime, AST_DIGIT_ANY, peer->language, NULL); 04656 play_file(peer, qe->parent->sound_minutes); 04657 } 04658 if (holdtimesecs > 1) { 04659 ast_say_number(peer, holdtimesecs, AST_DIGIT_ANY, peer->language, NULL); 04660 play_file(peer, qe->parent->sound_seconds); 04661 } 04662 } 04663 } 04664 } 04665 res2 |= ast_autoservice_stop(qe->chan); 04666 if (ast_check_hangup(peer)) { 04667 /* Agent must have hung up */ 04668 ast_log(LOG_WARNING, "Agent on %s hungup on the customer.\n", peer->name); 04669 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "AGENTDUMP", "%s", ""); 04670 if (qe->parent->eventwhencalled) 04671 manager_event(EVENT_FLAG_AGENT, "AgentDump", 04672 "Queue: %s\r\n" 04673 "Uniqueid: %s\r\n" 04674 "Channel: %s\r\n" 04675 "Member: %s\r\n" 04676 "MemberName: %s\r\n" 04677 "%s", 04678 queuename, qe->chan->uniqueid, peer->name, member->interface, member->membername, 04679 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : ""); 04680 ast_hangup(peer); 04681 ao2_ref(member, -1); 04682 goto out; 04683 } else if (res2) { 04684 /* Caller must have hung up just before being connected*/ 04685 ast_log(LOG_NOTICE, "Caller was about to talk to agent on %s but the caller hungup.\n", peer->name); 04686 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "ABANDON", "%d|%d|%ld", qe->pos, qe->opos, (long) time(NULL) - qe->start); 04687 record_abandoned(qe); 04688 ast_hangup(peer); 04689 ao2_ref(member, -1); 04690 return -1; 04691 } 04692 } 04693 /* Stop music on hold */ 04694 if (ringing) 04695 ast_indicate(qe->chan,-1); 04696 else 04697 ast_moh_stop(qe->chan); 04698 /* If appropriate, log that we have a destination channel */ 04699 if (qe->chan->cdr) 04700 ast_cdr_setdestchan(qe->chan->cdr, peer->name); 04701 /* Make sure channels are compatible */ 04702 res = ast_channel_make_compatible(qe->chan, peer); 04703 if (res < 0) { 04704 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "SYSCOMPAT", "%s", ""); 04705 ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", qe->chan->name, peer->name); 04706 record_abandoned(qe); 04707 ast_cdr_failed(qe->chan->cdr); 04708 ast_hangup(peer); 04709 ao2_ref(member, -1); 04710 return -1; 04711 } 04712 04713 /* Play announcement to the caller telling it's his turn if defined */ 04714 if (!ast_strlen_zero(qe->parent->sound_callerannounce)) { 04715 if (play_file(qe->chan, qe->parent->sound_callerannounce)) 04716 ast_log(LOG_WARNING, "Announcement file '%s' is unavailable, continuing anyway...\n", qe->parent->sound_callerannounce); 04717 } 04718 04719 ao2_lock(qe->parent); 04720 /* if setinterfacevar is defined, make member variables available to the channel */ 04721 /* use pbx_builtin_setvar to set a load of variables with one call */ 04722 if (qe->parent->setinterfacevar) { 04723 snprintf(interfacevar, sizeof(interfacevar), "MEMBERINTERFACE=%s,MEMBERNAME=%s,MEMBERCALLS=%d,MEMBERLASTCALL=%ld,MEMBERPENALTY=%d,MEMBERDYNAMIC=%d,MEMBERREALTIME=%d", 04724 member->interface, member->membername, member->calls, (long)member->lastcall, member->penalty, member->dynamic, member->realtime); 04725 pbx_builtin_setvar_multiple(qe->chan, interfacevar); 04726 pbx_builtin_setvar_multiple(peer, interfacevar); 04727 } 04728 04729 /* if setqueueentryvar is defined, make queue entry (i.e. the caller) variables available to the channel */ 04730 /* use pbx_builtin_setvar to set a load of variables with one call */ 04731 if (qe->parent->setqueueentryvar) { 04732 snprintf(interfacevar, sizeof(interfacevar), "QEHOLDTIME=%ld,QEORIGINALPOS=%d", 04733 (long) time(NULL) - qe->start, qe->opos); 04734 pbx_builtin_setvar_multiple(qe->chan, interfacevar); 04735 pbx_builtin_setvar_multiple(peer, interfacevar); 04736 } 04737 04738 ao2_unlock(qe->parent); 04739 04740 /* try to set queue variables if configured to do so*/ 04741 set_queue_variables(qe->parent, qe->chan); 04742 set_queue_variables(qe->parent, peer); 04743 04744 ast_channel_lock(qe->chan); 04745 if ((monitorfilename = pbx_builtin_getvar_helper(qe->chan, "MONITOR_FILENAME"))) { 04746 monitorfilename = ast_strdupa(monitorfilename); 04747 } 04748 ast_channel_unlock(qe->chan); 04749 /* Begin Monitoring */ 04750 if (qe->parent->monfmt && *qe->parent->monfmt) { 04751 if (!qe->parent->montype) { 04752 const char *monexec, *monargs; 04753 ast_debug(1, "Starting Monitor as requested.\n"); 04754 ast_channel_lock(qe->chan); 04755 if ((monexec = pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC")) || (monargs = pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC_ARGS"))) { 04756 which = qe->chan; 04757 monexec = monexec ? ast_strdupa(monexec) : NULL; 04758 } 04759 else 04760 which = peer; 04761 ast_channel_unlock(qe->chan); 04762 if (monitorfilename) { 04763 ast_monitor_start(which, qe->parent->monfmt, monitorfilename, 1, X_REC_IN | X_REC_OUT); 04764 } else if (qe->chan->cdr) { 04765 ast_monitor_start(which, qe->parent->monfmt, qe->chan->cdr->uniqueid, 1, X_REC_IN | X_REC_OUT); 04766 } else { 04767 /* Last ditch effort -- no CDR, make up something */ 04768 snprintf(tmpid, sizeof(tmpid), "chan-%lx", ast_random()); 04769 ast_monitor_start(which, qe->parent->monfmt, tmpid, 1, X_REC_IN | X_REC_OUT); 04770 } 04771 if (!ast_strlen_zero(monexec)) { 04772 ast_monitor_setjoinfiles(which, 1); 04773 } 04774 } else { 04775 mixmonapp = pbx_findapp("MixMonitor"); 04776 04777 if (mixmonapp) { 04778 ast_debug(1, "Starting MixMonitor as requested.\n"); 04779 if (!monitorfilename) { 04780 if (qe->chan->cdr) 04781 ast_copy_string(tmpid, qe->chan->cdr->uniqueid, sizeof(tmpid)); 04782 else 04783 snprintf(tmpid, sizeof(tmpid), "chan-%lx", ast_random()); 04784 } else { 04785 const char *m = monitorfilename; 04786 for (p = tmpid2; p < tmpid2 + sizeof(tmpid2) - 1; p++, m++) { 04787 switch (*m) { 04788 case '^': 04789 if (*(m + 1) == '{') 04790 *p = '$'; 04791 break; 04792 case ',': 04793 *p++ = '\\'; 04794 /* Fall through */ 04795 default: 04796 *p = *m; 04797 } 04798 if (*m == '\0') 04799 break; 04800 } 04801 if (p == tmpid2 + sizeof(tmpid2)) 04802 tmpid2[sizeof(tmpid2) - 1] = '\0'; 04803 04804 pbx_substitute_variables_helper(qe->chan, tmpid2, tmpid, sizeof(tmpid) - 1); 04805 } 04806 04807 ast_channel_lock(qe->chan); 04808 if ((monitor_exec = pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC"))) { 04809 monitor_exec = ast_strdupa(monitor_exec); 04810 } 04811 if ((monitor_options = pbx_builtin_getvar_helper(qe->chan, "MONITOR_OPTIONS"))) { 04812 monitor_options = ast_strdupa(monitor_options); 04813 } else { 04814 monitor_options = ""; 04815 } 04816 ast_channel_unlock(qe->chan); 04817 04818 if (monitor_exec) { 04819 const char *m = monitor_exec; 04820 for (p = meid2; p < meid2 + sizeof(meid2) - 1; p++, m++) { 04821 switch (*m) { 04822 case '^': 04823 if (*(m + 1) == '{') 04824 *p = '$'; 04825 break; 04826 case ',': 04827 *p++ = '\\'; 04828 /* Fall through */ 04829 default: 04830 *p = *m; 04831 } 04832 if (*m == '\0') 04833 break; 04834 } 04835 if (p == meid2 + sizeof(meid2)) 04836 meid2[sizeof(meid2) - 1] = '\0'; 04837 04838 pbx_substitute_variables_helper(qe->chan, meid2, meid, sizeof(meid) - 1); 04839 } 04840 04841 snprintf(tmpid2, sizeof(tmpid2), "%s.%s", tmpid, qe->parent->monfmt); 04842 04843 if (!ast_strlen_zero(monitor_exec)) 04844 snprintf(mixmonargs, sizeof(mixmonargs), "%s,b%s,%s", tmpid2, monitor_options, monitor_exec); 04845 else 04846 snprintf(mixmonargs, sizeof(mixmonargs), "%s,b%s", tmpid2, monitor_options); 04847 04848 ast_debug(1, "Arguments being passed to MixMonitor: %s\n", mixmonargs); 04849 /* We purposely lock the CDR so that pbx_exec does not update the application data */ 04850 if (qe->chan->cdr) 04851 ast_set_flag(qe->chan->cdr, AST_CDR_FLAG_LOCKED); 04852 ret = pbx_exec(qe->chan, mixmonapp, mixmonargs); 04853 if (qe->chan->cdr) 04854 ast_clear_flag(qe->chan->cdr, AST_CDR_FLAG_LOCKED); 04855 04856 } else { 04857 ast_log(LOG_WARNING, "Asked to run MixMonitor on this call, but cannot find the MixMonitor app!\n"); 04858 } 04859 } 04860 } 04861 /* Drop out of the queue at this point, to prepare for next caller */ 04862 leave_queue(qe); 04863 if (!ast_strlen_zero(url) && ast_channel_supports_html(peer)) { 04864 ast_debug(1, "app_queue: sendurl=%s.\n", url); 04865 ast_channel_sendurl(peer, url); 04866 } 04867 04868 /* run a macro for this connection if defined. The macro simply returns, no action is taken on the result */ 04869 /* use macro from dialplan if passed as a option, otherwise use the default queue macro */ 04870 if (!ast_strlen_zero(macro)) { 04871 macroexec = ast_strdupa(macro); 04872 } else { 04873 if (qe->parent->membermacro) 04874 macroexec = ast_strdupa(qe->parent->membermacro); 04875 } 04876 04877 if (!ast_strlen_zero(macroexec)) { 04878 ast_debug(1, "app_queue: macro=%s.\n", macroexec); 04879 04880 res = ast_autoservice_start(qe->chan); 04881 if (res) { 04882 ast_log(LOG_ERROR, "Unable to start autoservice on calling channel\n"); 04883 res = -1; 04884 } 04885 04886 application = pbx_findapp("Macro"); 04887 04888 if (application) { 04889 res = pbx_exec(peer, application, macroexec); 04890 ast_debug(1, "Macro exited with status %d\n", res); 04891 res = 0; 04892 } else { 04893 ast_log(LOG_ERROR, "Could not find application Macro\n"); 04894 res = -1; 04895 } 04896 04897 if (ast_autoservice_stop(qe->chan) < 0) { 04898 ast_log(LOG_ERROR, "Could not stop autoservice on calling channel\n"); 04899 res = -1; 04900 } 04901 } 04902 04903 /* run a gosub for this connection if defined. The gosub simply returns, no action is taken on the result */ 04904 /* use gosub from dialplan if passed as a option, otherwise use the default queue gosub */ 04905 if (!ast_strlen_zero(gosub)) { 04906 gosubexec = ast_strdupa(gosub); 04907 } else { 04908 if (qe->parent->membergosub) 04909 gosubexec = ast_strdupa(qe->parent->membergosub); 04910 } 04911 04912 if (!ast_strlen_zero(gosubexec)) { 04913 ast_debug(1, "app_queue: gosub=%s.\n", gosubexec); 04914 04915 res = ast_autoservice_start(qe->chan); 04916 if (res) { 04917 ast_log(LOG_ERROR, "Unable to start autoservice on calling channel\n"); 04918 res = -1; 04919 } 04920 04921 application = pbx_findapp("Gosub"); 04922 04923 if (application) { 04924 char *gosub_args, *gosub_argstart; 04925 04926 /* Set where we came from */ 04927 ast_copy_string(peer->context, "app_queue_gosub_virtual_context", sizeof(peer->context)); 04928 ast_copy_string(peer->exten, "s", sizeof(peer->exten)); 04929 peer->priority = 0; 04930 04931 gosub_argstart = strchr(gosubexec, ','); 04932 if (gosub_argstart) { 04933 const char *what_is_s = "s"; 04934 *gosub_argstart = 0; 04935 if (!ast_exists_extension(peer, gosubexec, "s", 1, S_COR(peer->caller.id.number.valid, peer->caller.id.number.str, NULL)) && 04936 ast_exists_extension(peer, gosubexec, "~~s~~", 1, S_COR(peer->caller.id.number.valid, peer->caller.id.number.str, NULL))) { 04937 what_is_s = "~~s~~"; 04938 } 04939 if (asprintf(&gosub_args, "%s,%s,1(%s)", gosubexec, what_is_s, gosub_argstart + 1) < 0) { 04940 ast_log(LOG_WARNING, "asprintf() failed: %s\n", strerror(errno)); 04941 gosub_args = NULL; 04942 } 04943 *gosub_argstart = ','; 04944 } else { 04945 const char *what_is_s = "s"; 04946 if (!ast_exists_extension(peer, gosubexec, "s", 1, S_COR(peer->caller.id.number.valid, peer->caller.id.number.str, NULL)) && 04947 ast_exists_extension(peer, gosubexec, "~~s~~", 1, S_COR(peer->caller.id.number.valid, peer->caller.id.number.str, NULL))) { 04948 what_is_s = "~~s~~"; 04949 } 04950 if (asprintf(&gosub_args, "%s,%s,1", gosubexec, what_is_s) < 0) { 04951 ast_log(LOG_WARNING, "asprintf() failed: %s\n", strerror(errno)); 04952 gosub_args = NULL; 04953 } 04954 } 04955 if (gosub_args) { 04956 res = pbx_exec(peer, application, gosub_args); 04957 if (!res) { 04958 struct ast_pbx_args args; 04959 memset(&args, 0, sizeof(args)); 04960 args.no_hangup_chan = 1; 04961 ast_pbx_run_args(peer, &args); 04962 } 04963 ast_free(gosub_args); 04964 ast_debug(1, "Gosub exited with status %d\n", res); 04965 } else { 04966 ast_log(LOG_ERROR, "Could not Allocate string for Gosub arguments -- Gosub Call Aborted!\n"); 04967 } 04968 } else { 04969 ast_log(LOG_ERROR, "Could not find application Gosub\n"); 04970 res = -1; 04971 } 04972 04973 if (ast_autoservice_stop(qe->chan) < 0) { 04974 ast_log(LOG_ERROR, "Could not stop autoservice on calling channel\n"); 04975 res = -1; 04976 } 04977 } 04978 04979 if (!ast_strlen_zero(agi)) { 04980 ast_debug(1, "app_queue: agi=%s.\n", agi); 04981 application = pbx_findapp("agi"); 04982 if (application) { 04983 agiexec = ast_strdupa(agi); 04984 ret = pbx_exec(qe->chan, application, agiexec); 04985 } else 04986 ast_log(LOG_WARNING, "Asked to execute an AGI on this channel, but could not find application (agi)!\n"); 04987 } 04988 qe->handled++; 04989 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "CONNECT", "%ld|%s|%ld", (long) time(NULL) - qe->start, peer->uniqueid, 04990 (long)(orig - to > 0 ? (orig - to) / 1000 : 0)); 04991 if (update_cdr && qe->chan->cdr) 04992 ast_copy_string(qe->chan->cdr->dstchannel, member->membername, sizeof(qe->chan->cdr->dstchannel)); 04993 if (qe->parent->eventwhencalled) 04994 manager_event(EVENT_FLAG_AGENT, "AgentConnect", 04995 "Queue: %s\r\n" 04996 "Uniqueid: %s\r\n" 04997 "Channel: %s\r\n" 04998 "Member: %s\r\n" 04999 "MemberName: %s\r\n" 05000 "Holdtime: %ld\r\n" 05001 "BridgedChannel: %s\r\n" 05002 "Ringtime: %ld\r\n" 05003 "%s", 05004 queuename, qe->chan->uniqueid, peer->name, member->interface, member->membername, 05005 (long) time(NULL) - qe->start, peer->uniqueid, (long)(orig - to > 0 ? (orig - to) / 1000 : 0), 05006 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : ""); 05007 ast_copy_string(oldcontext, qe->chan->context, sizeof(oldcontext)); 05008 ast_copy_string(oldexten, qe->chan->exten, sizeof(oldexten)); 05009 05010 if ((queue_end_bridge = ao2_alloc(sizeof(*queue_end_bridge), NULL))) { 05011 queue_end_bridge->q = qe->parent; 05012 queue_end_bridge->chan = qe->chan; 05013 bridge_config.end_bridge_callback = end_bridge_callback; 05014 bridge_config.end_bridge_callback_data = queue_end_bridge; 05015 bridge_config.end_bridge_callback_data_fixup = end_bridge_callback_data_fixup; 05016 /* Since queue_end_bridge can survive beyond the life of this call to Queue, we need 05017 * to make sure to increase the refcount of this queue so it cannot be freed until we 05018 * are done with it. We remove this reference in end_bridge_callback. 05019 */ 05020 queue_t_ref(qe->parent, "For bridge_config reference"); 05021 } 05022 05023 time(&callstart); 05024 transfer_ds = setup_transfer_datastore(qe, member, callstart, callcompletedinsl); 05025 bridge = ast_bridge_call(qe->chan,peer, &bridge_config); 05026 05027 /* If the queue member did an attended transfer, then the TRANSFER already was logged in the queue_log 05028 * when the masquerade occurred. These other "ending" queue_log messages are unnecessary, except for 05029 * the AgentComplete manager event 05030 */ 05031 ast_channel_lock(qe->chan); 05032 if (!attended_transfer_occurred(qe->chan)) { 05033 struct ast_datastore *tds; 05034 05035 /* detect a blind transfer */ 05036 if (!(qe->chan->_softhangup | peer->_softhangup) && (strcasecmp(oldcontext, qe->chan->context) || strcasecmp(oldexten, qe->chan->exten))) { 05037 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "TRANSFER", "%s|%s|%ld|%ld|%d", 05038 qe->chan->exten, qe->chan->context, (long) (callstart - qe->start), 05039 (long) (time(NULL) - callstart), qe->opos); 05040 send_agent_complete(qe, queuename, peer, member, callstart, vars, sizeof(vars), TRANSFER); 05041 } else if (ast_check_hangup(qe->chan)) { 05042 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "COMPLETECALLER", "%ld|%ld|%d", 05043 (long) (callstart - qe->start), (long) (time(NULL) - callstart), qe->opos); 05044 send_agent_complete(qe, queuename, peer, member, callstart, vars, sizeof(vars), CALLER); 05045 } else { 05046 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "COMPLETEAGENT", "%ld|%ld|%d", 05047 (long) (callstart - qe->start), (long) (time(NULL) - callstart), qe->opos); 05048 send_agent_complete(qe, queuename, peer, member, callstart, vars, sizeof(vars), AGENT); 05049 } 05050 if ((tds = ast_channel_datastore_find(qe->chan, &queue_transfer_info, NULL))) { 05051 ast_channel_datastore_remove(qe->chan, tds); 05052 } 05053 update_queue(qe->parent, member, callcompletedinsl, (time(NULL) - callstart)); 05054 } else { 05055 /* We already logged the TRANSFER on the queue_log, but we still need to send the AgentComplete event */ 05056 send_agent_complete(qe, queuename, peer, member, callstart, vars, sizeof(vars), TRANSFER); 05057 } 05058 05059 if (transfer_ds) { 05060 ast_datastore_free(transfer_ds); 05061 } 05062 ast_channel_unlock(qe->chan); 05063 ast_hangup(peer); 05064 res = bridge ? bridge : 1; 05065 ao2_ref(member, -1); 05066 } 05067 out: 05068 hangupcalls(outgoing, NULL, qe->cancel_answered_elsewhere); 05069 05070 return res; 05071 }
static int unload_module | ( | void | ) | [static] |
Definition at line 8243 of file app_queue.c.
References ao2_iterator_destroy(), ao2_iterator_init(), ao2_ref, ao2_t_iterator_next, ARRAY_LEN, ast_cli_unregister_multiple(), ast_context_destroy(), ast_context_find(), ast_context_remove_extension2(), ast_custom_function_unregister(), ast_data_unregister, ast_event_unsubscribe(), ast_extension_state_del(), ast_manager_unregister(), ast_taskprocessor_unreference(), ast_unload_realtime(), ast_unregister_application(), cli_queue, device_state_sub, devicestate_tps, extension_state_cb(), queue_t_unref, queueexists_function, queuemembercount_dep, queuemembercount_function, queuememberlist_function, queuememberpenalty_function, queues_t_unlink, queuevar_function, and queuewaitingcount_function.
08244 { 08245 int res; 08246 struct ast_context *con; 08247 struct ao2_iterator q_iter; 08248 struct call_queue *q = NULL; 08249 08250 ast_cli_unregister_multiple(cli_queue, ARRAY_LEN(cli_queue)); 08251 res = ast_manager_unregister("QueueStatus"); 08252 res |= ast_manager_unregister("Queues"); 08253 res |= ast_manager_unregister("QueueRule"); 08254 res |= ast_manager_unregister("QueueSummary"); 08255 res |= ast_manager_unregister("QueueAdd"); 08256 res |= ast_manager_unregister("QueueRemove"); 08257 res |= ast_manager_unregister("QueuePause"); 08258 res |= ast_manager_unregister("QueueLog"); 08259 res |= ast_manager_unregister("QueuePenalty"); 08260 res |= ast_unregister_application(app_aqm); 08261 res |= ast_unregister_application(app_rqm); 08262 res |= ast_unregister_application(app_pqm); 08263 res |= ast_unregister_application(app_upqm); 08264 res |= ast_unregister_application(app_ql); 08265 res |= ast_unregister_application(app); 08266 res |= ast_custom_function_unregister(&queueexists_function); 08267 res |= ast_custom_function_unregister(&queuevar_function); 08268 res |= ast_custom_function_unregister(&queuemembercount_function); 08269 res |= ast_custom_function_unregister(&queuemembercount_dep); 08270 res |= ast_custom_function_unregister(&queuememberlist_function); 08271 res |= ast_custom_function_unregister(&queuewaitingcount_function); 08272 res |= ast_custom_function_unregister(&queuememberpenalty_function); 08273 08274 res |= ast_data_unregister(NULL); 08275 08276 if (device_state_sub) 08277 ast_event_unsubscribe(device_state_sub); 08278 08279 ast_extension_state_del(0, extension_state_cb); 08280 08281 if ((con = ast_context_find("app_queue_gosub_virtual_context"))) { 08282 ast_context_remove_extension2(con, "s", 1, NULL, 0); 08283 ast_context_destroy(con, "app_queue"); /* leave no trace */ 08284 } 08285 08286 q_iter = ao2_iterator_init(queues, 0); 08287 while ((q = ao2_t_iterator_next(&q_iter, "Iterate through queues"))) { 08288 queues_t_unlink(queues, q, "Remove queue from container due to unload"); 08289 queue_t_unref(q, "Done with iterator"); 08290 } 08291 ao2_iterator_destroy(&q_iter); 08292 ao2_ref(queues, -1); 08293 devicestate_tps = ast_taskprocessor_unreference(devicestate_tps); 08294 ast_unload_realtime("queue_members"); 08295 return res; 08296 }
static void update_qe_rule | ( | struct queue_ent * | qe | ) | [static] |
update rules for queues
Calculate min/max penalties making sure if relative they stay within bounds. Update queues penalty and set dialplan vars, goto next list entry.
Definition at line 3885 of file app_queue.c.
References ast_debug, AST_LIST_NEXT, queue_ent::chan, queue_ent::max_penalty, penalty_rule::max_relative, penalty_rule::max_value, queue_ent::min_penalty, penalty_rule::min_relative, penalty_rule::min_value, ast_channel::name, pbx_builtin_setvar_helper(), queue_ent::pr, and penalty_rule::time.
Referenced by queue_exec().
03886 { 03887 int max_penalty = qe->pr->max_relative ? qe->max_penalty + qe->pr->max_value : qe->pr->max_value; 03888 int min_penalty = qe->pr->min_relative ? qe->min_penalty + qe->pr->min_value : qe->pr->min_value; 03889 char max_penalty_str[20], min_penalty_str[20]; 03890 /* a relative change to the penalty could put it below 0 */ 03891 if (max_penalty < 0) 03892 max_penalty = 0; 03893 if (min_penalty < 0) 03894 min_penalty = 0; 03895 if (min_penalty > max_penalty) 03896 min_penalty = max_penalty; 03897 snprintf(max_penalty_str, sizeof(max_penalty_str), "%d", max_penalty); 03898 snprintf(min_penalty_str, sizeof(min_penalty_str), "%d", min_penalty); 03899 pbx_builtin_setvar_helper(qe->chan, "QUEUE_MAX_PENALTY", max_penalty_str); 03900 pbx_builtin_setvar_helper(qe->chan, "QUEUE_MIN_PENALTY", min_penalty_str); 03901 qe->max_penalty = max_penalty; 03902 qe->min_penalty = min_penalty; 03903 ast_debug(3, "Setting max penalty to %d and min penalty to %d for caller %s since %d seconds have elapsed\n", qe->max_penalty, qe->min_penalty, qe->chan->name, qe->pr->time); 03904 qe->pr = AST_LIST_NEXT(qe->pr, list); 03905 }
static int update_queue | ( | struct call_queue * | q, | |
struct member * | member, | |||
int | callcompletedinsl, | |||
int | newtalktime | |||
) | [static] |
update the queue status
Always | 0 |
Definition at line 3993 of file app_queue.c.
References ao2_find, ao2_iterator_destroy(), ao2_iterator_init(), ao2_lock, ao2_ref, ao2_t_iterator_next, ao2_unlock, member::calls, call_queue::callscompleted, call_queue::callscompletedinsl, member::lastcall, member::lastqueue, call_queue::members, OBJ_POINTER, queue_t_unref, queues, and call_queue::talktime.
Referenced by queue_transfer_fixup().
03994 { 03995 int oldtalktime; 03996 03997 struct member *mem; 03998 struct call_queue *qtmp; 03999 struct ao2_iterator queue_iter; 04000 04001 if (shared_lastcall) { 04002 queue_iter = ao2_iterator_init(queues, 0); 04003 while ((qtmp = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) { 04004 ao2_lock(qtmp); 04005 if ((mem = ao2_find(qtmp->members, member, OBJ_POINTER))) { 04006 time(&mem->lastcall); 04007 mem->calls++; 04008 mem->lastqueue = q; 04009 ao2_ref(mem, -1); 04010 } 04011 ao2_unlock(qtmp); 04012 queue_t_unref(qtmp, "Done with iterator"); 04013 } 04014 ao2_iterator_destroy(&queue_iter); 04015 } else { 04016 ao2_lock(q); 04017 time(&member->lastcall); 04018 member->calls++; 04019 member->lastqueue = q; 04020 ao2_unlock(q); 04021 } 04022 ao2_lock(q); 04023 q->callscompleted++; 04024 if (callcompletedinsl) 04025 q->callscompletedinsl++; 04026 /* Calculate talktime using the same exponential average as holdtime code*/ 04027 oldtalktime = q->talktime; 04028 q->talktime = (((oldtalktime << 2) - oldtalktime) + newtalktime) >> 2; 04029 ao2_unlock(q); 04030 return 0; 04031 }
static int update_realtime_member_field | ( | struct member * | mem, | |
const char * | queue_name, | |||
const char * | field, | |||
const char * | value | |||
) | [static] |
Definition at line 2389 of file app_queue.c.
References ast_strlen_zero(), ast_update_realtime(), member::rt_uniqueid, and SENTINEL.
Referenced by set_member_paused().
02390 { 02391 int ret = -1; 02392 02393 if (ast_strlen_zero(mem->rt_uniqueid)) 02394 return ret; 02395 02396 if ((ast_update_realtime("queue_members", "uniqueid", mem->rt_uniqueid, field, value, SENTINEL)) > 0) 02397 ret = 0; 02398 02399 return ret; 02400 }
static void update_realtime_members | ( | struct call_queue * | q | ) | [static] |
Definition at line 2403 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_debug, ast_load_realtime_multientry(), ast_queue_log(), ast_variable_retrieve(), member::dead, member::interface, call_queue::membercount, call_queue::members, call_queue::name, queues, member::realtime, rt_handle_member_record(), S_OR, and SENTINEL.
Referenced by load_realtime_queue(), and queue_exec().
02404 { 02405 struct ast_config *member_config = NULL; 02406 struct member *m; 02407 char *interface = NULL; 02408 struct ao2_iterator mem_iter; 02409 02410 if (!(member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name", q->name , SENTINEL))) { 02411 /*This queue doesn't have realtime members*/ 02412 ast_debug(3, "Queue %s has no realtime members defined. No need for update\n", q->name); 02413 return; 02414 } 02415 02416 ao2_lock(queues); 02417 ao2_lock(q); 02418 02419 /* Temporarily set realtime members dead so we can detect deleted ones.*/ 02420 mem_iter = ao2_iterator_init(q->members, 0); 02421 while ((m = ao2_iterator_next(&mem_iter))) { 02422 if (m->realtime) 02423 m->dead = 1; 02424 ao2_ref(m, -1); 02425 } 02426 ao2_iterator_destroy(&mem_iter); 02427 02428 while ((interface = ast_category_browse(member_config, interface))) { 02429 rt_handle_member_record(q, interface, 02430 ast_variable_retrieve(member_config, interface, "uniqueid"), 02431 S_OR(ast_variable_retrieve(member_config, interface, "membername"), interface), 02432 ast_variable_retrieve(member_config, interface, "penalty"), 02433 ast_variable_retrieve(member_config, interface, "paused"), 02434 S_OR(ast_variable_retrieve(member_config, interface, "state_interface"), interface)); 02435 } 02436 02437 /* Delete all realtime members that have been deleted in DB. */ 02438 mem_iter = ao2_iterator_init(q->members, 0); 02439 while ((m = ao2_iterator_next(&mem_iter))) { 02440 if (m->dead) { 02441 ast_queue_log(q->name, "REALTIME", m->interface, "REMOVEMEMBER", "%s", ""); 02442 ao2_unlink(q->members, m); 02443 q->membercount--; 02444 } 02445 ao2_ref(m, -1); 02446 } 02447 ao2_iterator_destroy(&mem_iter); 02448 ao2_unlock(q); 02449 ao2_unlock(queues); 02450 ast_config_destroy(member_config); 02451 }
static int update_status | ( | struct call_queue * | q, | |
struct member * | m, | |||
const int | status | |||
) | [static] |
set a member's status based on device state of that member's state_interface.
Lock interface list find sc, iterate through each queues queue_member list for member to update state inside queues
Definition at line 1428 of file app_queue.c.
References EVENT_FLAG_AGENT, and manager_event.
Referenced by extension_state_cb(), handle_statechange(), and ring_entry().
01429 { 01430 m->status = status; 01431 01432 if (q->maskmemberstatus) 01433 return 0; 01434 01435 manager_event(EVENT_FLAG_AGENT, "QueueMemberStatus", 01436 "Queue: %s\r\n" 01437 "Location: %s\r\n" 01438 "MemberName: %s\r\n" 01439 "Membership: %s\r\n" 01440 "Penalty: %d\r\n" 01441 "CallsTaken: %d\r\n" 01442 "LastCall: %d\r\n" 01443 "Status: %d\r\n" 01444 "Paused: %d\r\n", 01445 q->name, m->interface, m->membername, m->dynamic ? "dynamic" : m->realtime ? "realtime" : "static", 01446 m->penalty, m->calls, (int)m->lastcall, m->status, m->paused 01447 ); 01448 01449 return 0; 01450 }
static int upqm_exec | ( | struct ast_channel * | chan, | |
const char * | data | |||
) | [static] |
UnPauseQueueMember application.
Definition at line 5556 of file app_queue.c.
References args, AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_log(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), LOG_WARNING, parse(), pbx_builtin_setvar_helper(), and set_member_paused().
Referenced by load_module().
05557 { 05558 char *parse; 05559 AST_DECLARE_APP_ARGS(args, 05560 AST_APP_ARG(queuename); 05561 AST_APP_ARG(interface); 05562 AST_APP_ARG(options); 05563 AST_APP_ARG(reason); 05564 ); 05565 05566 if (ast_strlen_zero(data)) { 05567 ast_log(LOG_WARNING, "UnpauseQueueMember requires an argument ([queuename],interface[,options[,reason]])\n"); 05568 return -1; 05569 } 05570 05571 parse = ast_strdupa(data); 05572 05573 AST_STANDARD_APP_ARGS(args, parse); 05574 05575 if (ast_strlen_zero(args.interface)) { 05576 ast_log(LOG_WARNING, "Missing interface argument to PauseQueueMember ([queuename],interface[,options[,reason]])\n"); 05577 return -1; 05578 } 05579 05580 if (set_member_paused(args.queuename, args.interface, args.reason, 0)) { 05581 ast_log(LOG_WARNING, "Attempt to unpause interface %s, not found\n", args.interface); 05582 pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "NOTFOUND"); 05583 return 0; 05584 } 05585 05586 pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "UNPAUSED"); 05587 05588 return 0; 05589 }
static int valid_exit | ( | struct queue_ent * | qe, | |
char | digit | |||
) | [static] |
Check for valid exit from queue via goto.
0 | if failure | |
1 | if successful |
Definition at line 2559 of file app_queue.c.
References ast_canmatch_extension(), ast_goto_if_exists(), ast_strlen_zero(), ast_channel::caller, queue_ent::chan, queue_ent::context, queue_ent::digits, ast_party_caller::id, ast_party_id::number, S_COR, ast_party_number::str, ast_party_number::valid, and queue_ent::valid_digits.
Referenced by say_periodic_announcement(), say_position(), and wait_a_bit().
02560 { 02561 int digitlen = strlen(qe->digits); 02562 02563 /* Prevent possible buffer overflow */ 02564 if (digitlen < sizeof(qe->digits) - 2) { 02565 qe->digits[digitlen] = digit; 02566 qe->digits[digitlen + 1] = '\0'; 02567 } else { 02568 qe->digits[0] = '\0'; 02569 return 0; 02570 } 02571 02572 /* If there's no context to goto, short-circuit */ 02573 if (ast_strlen_zero(qe->context)) 02574 return 0; 02575 02576 /* If the extension is bad, then reset the digits to blank */ 02577 if (!ast_canmatch_extension(qe->chan, qe->context, qe->digits, 1, 02578 S_COR(qe->chan->caller.id.number.valid, qe->chan->caller.id.number.str, NULL))) { 02579 qe->digits[0] = '\0'; 02580 return 0; 02581 } 02582 02583 /* We have an exact match */ 02584 if (!ast_goto_if_exists(qe->chan, qe->context, qe->digits, 1)) { 02585 qe->valid_digits = 1; 02586 /* Return 1 on a successful goto */ 02587 return 1; 02588 } 02589 02590 return 0; 02591 }
static char* vars2manager | ( | struct ast_channel * | chan, | |
char * | vars, | |||
size_t | len | |||
) | [static] |
convert "\n" to "\nVariable: " ready for manager to use
Definition at line 2949 of file app_queue.c.
References ast_copy_string(), ast_str_buffer(), ast_str_thread_get(), queue_ent::chan, and pbx_builtin_serialize_variables().
Referenced by ring_entry(), rna(), and send_agent_complete().
02950 { 02951 struct ast_str *buf = ast_str_thread_get(&ast_str_thread_global_buf, len + 1); 02952 const char *tmp; 02953 02954 if (pbx_builtin_serialize_variables(chan, &buf)) { 02955 int i, j; 02956 02957 /* convert "\n" to "\nVariable: " */ 02958 strcpy(vars, "Variable: "); 02959 tmp = ast_str_buffer(buf); 02960 02961 for (i = 0, j = 10; (i < len - 1) && (j < len - 1); i++, j++) { 02962 vars[j] = tmp[i]; 02963 02964 if (tmp[i + 1] == '\0') 02965 break; 02966 if (tmp[i] == '\n') { 02967 vars[j++] = '\r'; 02968 vars[j++] = '\n'; 02969 02970 ast_copy_string(&(vars[j]), "Variable: ", len - j); 02971 j += 9; 02972 } 02973 } 02974 if (j > len - 3) 02975 j = len - 3; 02976 vars[j++] = '\r'; 02977 vars[j++] = '\n'; 02978 vars[j] = '\0'; 02979 } else { 02980 /* there are no channel variables; leave it blank */ 02981 *vars = '\0'; 02982 } 02983 return vars; 02984 }
static int wait_a_bit | ( | struct queue_ent * | qe | ) | [static] |
Definition at line 5073 of file app_queue.c.
References ast_waitfordigit(), queue_ent::chan, queue_ent::parent, call_queue::retry, and valid_exit().
Referenced by queue_exec().
05074 { 05075 /* Don't need to hold the lock while we setup the outgoing calls */ 05076 int retrywait = qe->parent->retry * 1000; 05077 05078 int res = ast_waitfordigit(qe->chan, retrywait); 05079 if (res > 0 && !valid_exit(qe, res)) 05080 res = 0; 05081 05082 return res; 05083 }
static struct callattempt* wait_for_answer | ( | struct queue_ent * | qe, | |
struct callattempt * | outgoing, | |||
int * | to, | |||
char * | digit, | |||
int | prebusies, | |||
int | caller_disconnect, | |||
int | forwardsallowed, | |||
int | update_connectedline | |||
) | [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() |
[in] | update_connectedline | Allow connected line and redirecting updates to pass through. |
Definition at line 3425 of file app_queue.c.
References ast_channel_lock, ast_channel_unlock, AST_MAX_WATCHERS, ast_party_connected_line_init(), ast_poll_channel_add(), ast_strdupa, callattempt::call_next, callattempt::chan, queue_ent::chan, f, ast_channel::name, call_queue::name, queue_ent::parent, callattempt::q_next, QUEUE_STRATEGY_RINGALL, ring_one(), starttime, status, callattempt::stillgoing, and call_queue::strategy.
03426 { 03427 const char *queue = qe->parent->name; 03428 struct callattempt *o, *start = NULL, *prev = NULL; 03429 int res; 03430 int status; 03431 int numbusies = prebusies; 03432 int numnochan = 0; 03433 int stillgoing = 0; 03434 int orig = *to; 03435 struct ast_frame *f; 03436 struct callattempt *peer = NULL; 03437 struct ast_channel *winner; 03438 struct ast_channel *in = qe->chan; 03439 char on[80] = ""; 03440 char membername[80] = ""; 03441 long starttime = 0; 03442 long endtime = 0; 03443 #ifdef HAVE_EPOLL 03444 struct callattempt *epollo; 03445 #endif 03446 struct ast_party_connected_line connected_caller; 03447 char *inchan_name; 03448 03449 ast_party_connected_line_init(&connected_caller); 03450 03451 ast_channel_lock(qe->chan); 03452 inchan_name = ast_strdupa(qe->chan->name); 03453 ast_channel_unlock(qe->chan); 03454 03455 starttime = (long) time(NULL); 03456 #ifdef HAVE_EPOLL 03457 for (epollo = outgoing; epollo; epollo = epollo->q_next) { 03458 if (epollo->chan) 03459 ast_poll_channel_add(in, epollo->chan); 03460 } 03461 #endif 03462 03463 while (*to && !peer) { 03464 int numlines, retry, pos = 1; 03465 struct ast_channel *watchers[AST_MAX_WATCHERS]; 03466 watchers[0] = in; 03467 start = NULL; 03468 03469 for (retry = 0; retry < 2; retry++) { 03470 numlines = 0; 03471 for (o = outgoing; o; o = o->q_next) { /* Keep track of important channels */ 03472 if (o->stillgoing) { /* Keep track of important channels */ 03473 stillgoing = 1; 03474 if (o->chan) { 03475 watchers[pos++] = o->chan; 03476 if (!start) 03477 start = o; 03478 else 03479 prev->call_next = o; 03480 prev = o; 03481 } 03482 } 03483 numlines++; 03484 } 03485 if (pos > 1 /* found */ || !stillgoing /* nobody listening */ || 03486 (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) /* ring would not be delivered */) 03487 break; 03488 /* On "ringall" strategy we only move to the next penalty level 03489 when *all* ringing phones are done in the current penalty level */ 03490 ring_one(qe, outgoing, &numbusies); 03491 /* and retry... */ 03492 } 03493 if (pos == 1 /* not found */) { 03494 if (numlines == (numbusies + numnochan)) { 03495 ast_debug(1, "Everyone is busy at this time\n"); 03496 } else { 03497 ast_debug(3, "No one is answering queue '%s' (%d numlines / %d busies / %d failed channels)\n", queue, numlines, numbusies, numnochan); 03498 } 03499 *to = 0; 03500 return NULL; 03501 } 03502 03503 /* Poll for events from both the incoming channel as well as any outgoing channels */ 03504 winner = ast_waitfor_n(watchers, pos, to); 03505 03506 /* Service all of the outgoing channels */ 03507 for (o = start; o; o = o->call_next) { 03508 /* We go with a static buffer here instead of using ast_strdupa. Using 03509 * ast_strdupa in a loop like this one can cause a stack overflow 03510 */ 03511 char ochan_name[AST_CHANNEL_NAME]; 03512 if (o->chan) { 03513 ast_channel_lock(o->chan); 03514 ast_copy_string(ochan_name, o->chan->name, sizeof(ochan_name)); 03515 ast_channel_unlock(o->chan); 03516 } 03517 if (o->stillgoing && (o->chan) && (o->chan->_state == AST_STATE_UP)) { 03518 if (!peer) { 03519 ast_verb(3, "%s answered %s\n", ochan_name, inchan_name); 03520 if (update_connectedline) { 03521 if (o->pending_connected_update) { 03522 if (ast_channel_connected_line_macro(o->chan, in, &o->connected, 1, 0)) { 03523 ast_channel_update_connected_line(in, &o->connected, NULL); 03524 } 03525 } else if (!o->dial_callerid_absent) { 03526 ast_channel_lock(o->chan); 03527 ast_connected_line_copy_from_caller(&connected_caller, &o->chan->caller); 03528 ast_channel_unlock(o->chan); 03529 connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER; 03530 ast_channel_update_connected_line(in, &connected_caller, NULL); 03531 ast_party_connected_line_free(&connected_caller); 03532 } 03533 } 03534 if (o->aoc_s_rate_list) { 03535 size_t encoded_size; 03536 struct ast_aoc_encoded *encoded; 03537 if ((encoded = ast_aoc_encode(o->aoc_s_rate_list, &encoded_size, o->chan))) { 03538 ast_indicate_data(in, AST_CONTROL_AOC, encoded, encoded_size); 03539 ast_aoc_destroy_encoded(encoded); 03540 } 03541 } 03542 peer = o; 03543 } 03544 } else if (o->chan && (o->chan == winner)) { 03545 03546 ast_copy_string(on, o->member->interface, sizeof(on)); 03547 ast_copy_string(membername, o->member->membername, sizeof(membername)); 03548 03549 if (!ast_strlen_zero(o->chan->call_forward) && !forwardsallowed) { 03550 ast_verb(3, "Forwarding %s to '%s' prevented.\n", inchan_name, o->chan->call_forward); 03551 numnochan++; 03552 do_hang(o); 03553 winner = NULL; 03554 continue; 03555 } else if (!ast_strlen_zero(o->chan->call_forward)) { 03556 struct ast_channel *original = o->chan; 03557 char tmpchan[256]; 03558 char *stuff; 03559 char *tech; 03560 03561 ast_copy_string(tmpchan, o->chan->call_forward, sizeof(tmpchan)); 03562 if ((stuff = strchr(tmpchan, '/'))) { 03563 *stuff++ = '\0'; 03564 tech = tmpchan; 03565 } else { 03566 snprintf(tmpchan, sizeof(tmpchan), "%s@%s", o->chan->call_forward, o->chan->context); 03567 stuff = tmpchan; 03568 tech = "Local"; 03569 } 03570 03571 ast_cel_report_event(in, AST_CEL_FORWARD, NULL, o->chan->call_forward, NULL); 03572 03573 /* Before processing channel, go ahead and check for forwarding */ 03574 ast_verb(3, "Now forwarding %s to '%s/%s' (thanks to %s)\n", inchan_name, tech, stuff, ochan_name); 03575 /* Setup parameters */ 03576 o->chan = ast_request(tech, in->nativeformats, in, stuff, &status); 03577 if (!o->chan) { 03578 ast_log(LOG_NOTICE, 03579 "Forwarding failed to create channel to dial '%s/%s'\n", 03580 tech, stuff); 03581 o->stillgoing = 0; 03582 numnochan++; 03583 } else { 03584 struct ast_party_redirecting redirecting; 03585 03586 ast_channel_lock(o->chan); 03587 while (ast_channel_trylock(in)) { 03588 CHANNEL_DEADLOCK_AVOIDANCE(o->chan); 03589 } 03590 ast_channel_inherit_variables(in, o->chan); 03591 ast_channel_datastore_inherit(in, o->chan); 03592 03593 ast_string_field_set(o->chan, accountcode, in->accountcode); 03594 03595 ast_channel_set_redirecting(o->chan, &original->redirecting, NULL); 03596 if (!o->chan->redirecting.from.number.valid 03597 || ast_strlen_zero(o->chan->redirecting.from.number.str)) { 03598 /* 03599 * The call was not previously redirected so it is 03600 * now redirected from this number. 03601 */ 03602 ast_party_number_free(&o->chan->redirecting.from.number); 03603 ast_party_number_init(&o->chan->redirecting.from.number); 03604 o->chan->redirecting.from.number.valid = 1; 03605 o->chan->redirecting.from.number.str = 03606 ast_strdup(S_OR(in->macroexten, in->exten)); 03607 } 03608 03609 o->chan->dialed.transit_network_select = in->dialed.transit_network_select; 03610 03611 ast_party_caller_copy(&o->chan->caller, &in->caller); 03612 ast_party_connected_line_copy(&o->chan->connected, &original->connected); 03613 03614 /* 03615 * We must unlock o->chan before calling 03616 * ast_channel_redirecting_macro, because we put o->chan into 03617 * autoservice there. That is pretty much a guaranteed 03618 * deadlock. This is why the handling of o->chan's lock may 03619 * seem a bit unusual here. 03620 */ 03621 ast_party_redirecting_init(&redirecting); 03622 ast_party_redirecting_copy(&redirecting, &o->chan->redirecting); 03623 ast_channel_unlock(o->chan); 03624 res = ast_channel_redirecting_macro(o->chan, in, &redirecting, 1, 0); 03625 if (res) { 03626 ast_channel_update_redirecting(in, &redirecting, NULL); 03627 } 03628 ast_party_redirecting_free(&redirecting); 03629 ast_channel_unlock(in); 03630 03631 update_connectedline = 1; 03632 03633 if (ast_call(o->chan, stuff, 0)) { 03634 ast_log(LOG_NOTICE, "Forwarding failed to dial '%s/%s'\n", 03635 tech, stuff); 03636 do_hang(o); 03637 numnochan++; 03638 } 03639 } 03640 /* Hangup the original channel now, in case we needed it */ 03641 ast_hangup(winner); 03642 continue; 03643 } 03644 f = ast_read(winner); 03645 if (f) { 03646 if (f->frametype == AST_FRAME_CONTROL) { 03647 switch (f->subclass.integer) { 03648 case AST_CONTROL_ANSWER: 03649 /* This is our guy if someone answered. */ 03650 if (!peer) { 03651 ast_verb(3, "%s answered %s\n", ochan_name, inchan_name); 03652 if (update_connectedline) { 03653 if (o->pending_connected_update) { 03654 if (ast_channel_connected_line_macro(o->chan, in, &o->connected, 1, 0)) { 03655 ast_channel_update_connected_line(in, &o->connected, NULL); 03656 } 03657 } else if (!o->dial_callerid_absent) { 03658 ast_channel_lock(o->chan); 03659 ast_connected_line_copy_from_caller(&connected_caller, &o->chan->caller); 03660 ast_channel_unlock(o->chan); 03661 connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER; 03662 ast_channel_update_connected_line(in, &connected_caller, NULL); 03663 ast_party_connected_line_free(&connected_caller); 03664 } 03665 } 03666 if (o->aoc_s_rate_list) { 03667 size_t encoded_size; 03668 struct ast_aoc_encoded *encoded; 03669 if ((encoded = ast_aoc_encode(o->aoc_s_rate_list, &encoded_size, o->chan))) { 03670 ast_indicate_data(in, AST_CONTROL_AOC, encoded, encoded_size); 03671 ast_aoc_destroy_encoded(encoded); 03672 } 03673 } 03674 peer = o; 03675 } 03676 break; 03677 case AST_CONTROL_BUSY: 03678 ast_verb(3, "%s is busy\n", ochan_name); 03679 if (in->cdr) 03680 ast_cdr_busy(in->cdr); 03681 do_hang(o); 03682 endtime = (long) time(NULL); 03683 endtime -= starttime; 03684 rna(endtime * 1000, qe, on, membername, 0); 03685 if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) { 03686 if (qe->parent->timeoutrestart) 03687 *to = orig; 03688 /* Have enough time for a queue member to answer? */ 03689 if (*to > 500) { 03690 ring_one(qe, outgoing, &numbusies); 03691 starttime = (long) time(NULL); 03692 } 03693 } 03694 numbusies++; 03695 break; 03696 case AST_CONTROL_CONGESTION: 03697 ast_verb(3, "%s is circuit-busy\n", ochan_name); 03698 if (in->cdr) 03699 ast_cdr_busy(in->cdr); 03700 endtime = (long) time(NULL); 03701 endtime -= starttime; 03702 rna(endtime * 1000, qe, on, membername, 0); 03703 do_hang(o); 03704 if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) { 03705 if (qe->parent->timeoutrestart) 03706 *to = orig; 03707 if (*to > 500) { 03708 ring_one(qe, outgoing, &numbusies); 03709 starttime = (long) time(NULL); 03710 } 03711 } 03712 numbusies++; 03713 break; 03714 case AST_CONTROL_RINGING: 03715 ast_verb(3, "%s is ringing\n", ochan_name); 03716 03717 /* Start ring indication when the channel is ringing, if specified */ 03718 if (qe->ring_when_ringing) { 03719 ast_moh_stop(qe->chan); 03720 ast_indicate(qe->chan, AST_CONTROL_RINGING); 03721 } 03722 break; 03723 case AST_CONTROL_OFFHOOK: 03724 /* Ignore going off hook */ 03725 break; 03726 case AST_CONTROL_CONNECTED_LINE: 03727 if (!update_connectedline) { 03728 ast_verb(3, "Connected line update to %s prevented.\n", inchan_name); 03729 } else if (qe->parent->strategy == QUEUE_STRATEGY_RINGALL) { 03730 struct ast_party_connected_line connected; 03731 ast_verb(3, "%s connected line has changed. Saving it until answer for %s\n", ochan_name, inchan_name); 03732 ast_party_connected_line_set_init(&connected, &o->connected); 03733 ast_connected_line_parse_data(f->data.ptr, f->datalen, &connected); 03734 ast_party_connected_line_set(&o->connected, &connected, NULL); 03735 ast_party_connected_line_free(&connected); 03736 o->pending_connected_update = 1; 03737 } else { 03738 if (ast_channel_connected_line_macro(o->chan, in, f, 1, 1)) { 03739 ast_indicate_data(in, AST_CONTROL_CONNECTED_LINE, f->data.ptr, f->datalen); 03740 } 03741 } 03742 break; 03743 case AST_CONTROL_AOC: 03744 { 03745 struct ast_aoc_decoded *decoded = ast_aoc_decode(f->data.ptr, f->datalen, o->chan); 03746 if (decoded && (ast_aoc_get_msg_type(decoded) == AST_AOC_S)) { 03747 ast_aoc_destroy_decoded(o->aoc_s_rate_list); 03748 o->aoc_s_rate_list = decoded; 03749 } else { 03750 ast_aoc_destroy_decoded(decoded); 03751 } 03752 } 03753 break; 03754 case AST_CONTROL_REDIRECTING: 03755 if (!update_connectedline) { 03756 ast_verb(3, "Redirecting update to %s prevented\n", inchan_name); 03757 } else if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) { 03758 ast_verb(3, "%s redirecting info has changed, passing it to %s\n", ochan_name, inchan_name); 03759 if (ast_channel_redirecting_macro(o->chan, in, f, 1, 1)) { 03760 ast_indicate_data(in, AST_CONTROL_REDIRECTING, f->data.ptr, f->datalen); 03761 } 03762 } 03763 break; 03764 default: 03765 ast_debug(1, "Dunno what to do with control type %d\n", f->subclass.integer); 03766 break; 03767 } 03768 } 03769 ast_frfree(f); 03770 } else { /* ast_read() returned NULL */ 03771 endtime = (long) time(NULL) - starttime; 03772 rna(endtime * 1000, qe, on, membername, 1); 03773 do_hang(o); 03774 if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) { 03775 if (qe->parent->timeoutrestart) 03776 *to = orig; 03777 if (*to > 500) { 03778 ring_one(qe, outgoing, &numbusies); 03779 starttime = (long) time(NULL); 03780 } 03781 } 03782 } 03783 } 03784 } 03785 03786 /* If we received an event from the caller, deal with it. */ 03787 if (winner == in) { 03788 f = ast_read(in); 03789 if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass.integer == AST_CONTROL_HANGUP))) { 03790 /* Got hung up */ 03791 *to = -1; 03792 if (f) { 03793 if (f->data.uint32) { 03794 in->hangupcause = f->data.uint32; 03795 } 03796 ast_frfree(f); 03797 } 03798 return NULL; 03799 } 03800 if ((f->frametype == AST_FRAME_DTMF) && caller_disconnect && (f->subclass.integer == '*')) { 03801 ast_verb(3, "User hit %c to disconnect call.\n", f->subclass.integer); 03802 *to = 0; 03803 ast_frfree(f); 03804 return NULL; 03805 } 03806 if ((f->frametype == AST_FRAME_DTMF) && valid_exit(qe, f->subclass.integer)) { 03807 ast_verb(3, "User pressed digit: %c\n", f->subclass.integer); 03808 *to = 0; 03809 *digit = f->subclass.integer; 03810 ast_frfree(f); 03811 return NULL; 03812 } 03813 ast_frfree(f); 03814 } 03815 if (!*to) { 03816 for (o = start; o; o = o->call_next) 03817 rna(orig, qe, o->interface, o->member->membername, 1); 03818 } 03819 } 03820 03821 #ifdef HAVE_EPOLL 03822 for (epollo = outgoing; epollo; epollo = epollo->q_next) { 03823 if (epollo->chan) 03824 ast_poll_channel_del(in, epollo->chan); 03825 } 03826 #endif 03827 03828 return peer; 03829 }
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 3917 of file app_queue.c.
References ast_queue_log(), queue_ent::chan, get_member_status(), is_our_turn(), leave_queue(), call_queue::leavewhenempty, queue_ent::max_penalty, queue_ent::min_penalty, call_queue::name, queue_ent::opos, queue_ent::parent, queue_ent::pos, QUEUE_LEAVEEMPTY, QUEUE_TIMEOUT, queue_ent::start, status, and ast_channel::uniqueid.
Referenced by queue_exec().
03918 { 03919 int res = 0; 03920 03921 /* This is the holding pen for callers 2 through maxlen */ 03922 for (;;) { 03923 03924 if (is_our_turn(qe)) 03925 break; 03926 03927 /* If we have timed out, break out */ 03928 if (qe->expire && (time(NULL) >= qe->expire)) { 03929 *reason = QUEUE_TIMEOUT; 03930 break; 03931 } 03932 03933 if (qe->parent->leavewhenempty) { 03934 int status = 0; 03935 03936 if ((status = get_member_status(qe->parent, qe->max_penalty, qe->min_penalty, qe->parent->leavewhenempty))) { 03937 *reason = QUEUE_LEAVEEMPTY; 03938 ast_queue_log(qe->parent->name, qe->chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe->pos, qe->opos, (long) time(NULL) - qe->start); 03939 leave_queue(qe); 03940 break; 03941 } 03942 } 03943 03944 /* Make a position announcement, if enabled */ 03945 if (qe->parent->announcefrequency && 03946 (res = say_position(qe,ringing))) 03947 break; 03948 03949 /* If we have timed out, break out */ 03950 if (qe->expire && (time(NULL) >= qe->expire)) { 03951 *reason = QUEUE_TIMEOUT; 03952 break; 03953 } 03954 03955 /* Make a periodic announcement, if enabled */ 03956 if (qe->parent->periodicannouncefrequency && 03957 (res = say_periodic_announcement(qe,ringing))) 03958 break; 03959 03960 /* see if we need to move to the next penalty level for this queue */ 03961 while (qe->pr && ((time(NULL) - qe->start) >= qe->pr->time)) { 03962 update_qe_rule(qe); 03963 } 03964 03965 /* If we have timed out, break out */ 03966 if (qe->expire && (time(NULL) >= qe->expire)) { 03967 *reason = QUEUE_TIMEOUT; 03968 break; 03969 } 03970 03971 /* Wait a second before checking again */ 03972 if ((res = ast_waitfordigit(qe->chan, RECHECK * 1000))) { 03973 if (res > 0 && !valid_exit(qe, res)) 03974 res = 0; 03975 else 03976 break; 03977 } 03978 03979 /* If we have timed out, break out */ 03980 if (qe->expire && (time(NULL) >= qe->expire)) { 03981 *reason = QUEUE_TIMEOUT; 03982 break; 03983 } 03984 } 03985 03986 return res; 03987 }
struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .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 = "8586c2a7d357cb591cc3a6607a8f62d1" , .load = load_module, .unload = unload_module, .reload = reload, .load_pri = AST_MODPRI_DEVSTATE_CONSUMER, .nonoptreq = "res_monitor", } [static] |
Definition at line 8378 of file app_queue.c.
char* app = "Queue" [static] |
Definition at line 899 of file app_queue.c.
char* app_aqm = "AddQueueMember" [static] |
Definition at line 901 of file app_queue.c.
char* app_pqm = "PauseQueueMember" [static] |
Definition at line 905 of file app_queue.c.
char* app_ql = "QueueLog" [static] |
Definition at line 909 of file app_queue.c.
char* app_rqm = "RemoveQueueMember" [static] |
Definition at line 903 of file app_queue.c.
char* app_upqm = "UnpauseQueueMember" [static] |
Definition at line 907 of file app_queue.c.
struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 8378 of file app_queue.c.
int autofill_default = 1 [static] |
struct autopause autopausesmodes[] [static] |
Referenced by autopause2int().
struct ast_cli_entry cli_queue[] [static] |
struct ast_event_sub* device_state_sub [static] |
Subscription to device state change events.
Definition at line 932 of file app_queue.c.
Referenced by aji_init_event_distribution(), load_module(), load_pbx(), and unload_module().
struct ast_taskprocessor* devicestate_tps [static] |
Definition at line 883 of file app_queue.c.
Referenced by device_state_cb(), load_module(), and unload_module().
enum queue_result id |
Definition at line 949 of file app_queue.c.
Referenced by _sip_show_peers(), _skinny_show_devices(), _skinny_show_lines(), amixer_max(), ast_cc_extension_monitor_add_dialstring(), ast_party_id_presentation(), frame_trace_helper(), idemodulator(), misdn_queue_connected_line_update(), misdn_update_caller_id(), party_id_build_data(), party_id_read(), party_id_write(), pidf_validate_tuple(), and setamixer().
int montype_default = 0 [static] |
const char* const pm_family = "Queue/PersistentMembers" [static] |
const char qpm_cmd_usage[] [static] |
Initial value:
"Usage: queue pause member <channel> in <queue> reason <reason>\n"
Definition at line 7957 of file app_queue.c.
const char qsmp_cmd_usage[] [static] |
Initial value:
"Usage: queue set member penalty <channel> from <queue> <penalty>\n"
Definition at line 7963 of file app_queue.c.
struct ast_data_entry queue_data_providers[] [static] |
Initial value:
{ AST_DATA_ENTRY("asterisk/application/queue/list", &queues_data_provider), }
Definition at line 8239 of file app_queue.c.
Referenced by load_module().
int queue_persistent_members = 0 [static] |
struct { ... } queue_results[] [static] |
Referenced by set_queue_result().
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 4167 of file app_queue.c.
Referenced by attended_transfer_occurred(), queue_transfer_fixup(), and setup_transfer_datastore().
struct ast_custom_function queueexists_function [static] |
Initial value:
{ .name = "QUEUE_EXISTS", .read = queue_function_exists, }
Definition at line 6415 of file app_queue.c.
Referenced by load_module(), and unload_module().
struct ast_custom_function queuemembercount_dep [static] |
Initial value:
{ .name = "QUEUE_MEMBER_COUNT", .read = queue_function_qac_dep, }
Definition at line 6430 of file app_queue.c.
Referenced by load_module(), and unload_module().
struct ast_custom_function queuemembercount_function [static] |
Initial value:
{ .name = "QUEUE_MEMBER", .read = queue_function_qac, }
Definition at line 6425 of file app_queue.c.
Referenced by load_module(), and unload_module().
struct ast_custom_function queuememberlist_function [static] |
Initial value:
{ .name = "QUEUE_MEMBER_LIST", .read = queue_function_queuememberlist, }
Definition at line 6440 of file app_queue.c.
Referenced by load_module(), and unload_module().
struct ast_custom_function queuememberpenalty_function [static] |
Initial value:
{ .name = "QUEUE_MEMBER_PENALTY", .read = queue_function_memberpenalty_read, .write = queue_function_memberpenalty_write, }
Definition at line 6445 of file app_queue.c.
Referenced by load_module(), and unload_module().
struct ao2_container* queues [static] |
Definition at line 1190 of file app_queue.c.
Referenced by compare_weight(), extension_state_cb(), find_queue_by_name_rt(), handle_statechange(), join_queue(), leave_queue(), load_realtime_queue(), update_queue(), and update_realtime_members().
struct ast_data_handler queues_data_provider [static] |
Initial value:
{ .version = AST_DATA_HANDLER_VERSION, .get = queues_data_provider_get }
Definition at line 8234 of file app_queue.c.
struct ast_custom_function queuevar_function [static] |
Initial value:
{ .name = "QUEUE_VARIABLES", .read = queue_function_var, }
Definition at line 6420 of file app_queue.c.
Referenced by load_module(), and unload_module().
struct ast_custom_function queuewaitingcount_function [static] |
Initial value:
{ .name = "QUEUE_WAITING_COUNT", .read = queue_function_queuewaitingcount, }
Definition at line 6435 of file app_queue.c.
Referenced by load_module(), and unload_module().
const char qum_cmd_usage[] [static] |
Initial value:
"Usage: queue unpause member <channel> in <queue> reason <reason>\n"
Definition at line 7960 of file app_queue.c.
int shared_lastcall = 1 [static] |
struct strategy strategies[] [static] |
Referenced by int2strat(), and strat2int().
char* text |
Definition at line 950 of file app_queue.c.
Referenced by festival_exec(), iconv_read(), method_match(), process_sdp(), reqprep(), set_queue_result(), and sip_new().
int update_cdr = 0 [static] |
queues.conf [general] option
Definition at line 935 of file app_queue.c.
Referenced by login_exec().
int use_weight = 0 [static] |