Asterisk - The Open Source Telephony Project GIT-master-f36a736
Data Structures | Macros | Enumerations | Functions | Variables
app_queue.c File Reference

True call queues with optional send URL on answer. More...

#include "asterisk.h"
#include <sys/time.h>
#include <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/utils.h"
#include "asterisk/causes.h"
#include "asterisk/astdb.h"
#include "asterisk/devicestate.h"
#include "asterisk/stringfields.h"
#include "asterisk/astobj2.h"
#include "asterisk/strings.h"
#include "asterisk/taskprocessor.h"
#include "asterisk/aoc.h"
#include "asterisk/callerid.h"
#include "asterisk/term.h"
#include "asterisk/dial.h"
#include "asterisk/stasis_channels.h"
#include "asterisk/stasis_message_router.h"
#include "asterisk/bridge_after.h"
#include "asterisk/stasis_bridges.h"
#include "asterisk/core_local.h"
#include "asterisk/mixmonitor.h"
#include "asterisk/bridge_basic.h"
#include "asterisk/max_forwards.h"
Include dependency graph for app_queue.c:

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  local_optimization
 Structure representing relevant data during a local channel optimization. More...
 
struct  member
 
struct  penalty_rule
 
struct  queue_end_bridge
 
struct  queue_ent
 
struct  queue_stasis_data
 User data for stasis subscriptions used for queue calls. More...
 
struct  rule_list
 
struct  rule_lists
 
struct  strategy
 

Macros

#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 DEFAULT_MIN_ANNOUNCE_FREQUENCY   15
 The minimum number of seconds between position announcements. More...
 
#define DEFAULT_RETRY   5
 
#define DEFAULT_TIMEOUT   15
 
#define MAX_CALL_ATTEMPT_BUCKETS   353
 
#define MAX_PERIODIC_ANNOUNCEMENTS   10
 
#define MAX_QUEUE_BUCKETS   53
 
#define QUEUE_EVENT_VARIABLES   3
 
#define QUEUE_PAUSED_DEVSTATE   AST_DEVICE_INUSE
 
#define queue_ref(q)   ao2_bump(q)
 
#define queue_t_ref(q, tag)   ao2_t_bump(q, tag)
 
#define queue_t_unref(q, tag)   ({ ao2_t_cleanup(q, tag); NULL; })
 
#define QUEUE_UNKNOWN_PAUSED_DEVSTATE   AST_DEVICE_NOT_INUSE
 
#define QUEUE_UNPAUSED_DEVSTATE   AST_DEVICE_NOT_INUSE
 
#define queue_unref(q)   ({ ao2_cleanup(q); NULL; })
 
#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_CALLER   (-5)
 
#define RES_NOT_DYNAMIC   (-4)
 
#define RES_OKAY   0
 
#define RES_OUTOFMEMORY   (-2)
 

Enumerations

enum  {
  OPT_MARK_AS_ANSWERED = (1 << 0) , OPT_GO_ON = (1 << 1) , OPT_DATA_QUALITY = (1 << 2) , OPT_CALLEE_GO_ON = (1 << 3) ,
  OPT_CALLEE_HANGUP = (1 << 4) , OPT_CALLER_HANGUP = (1 << 5) , OPT_IGNORE_CALL_FW = (1 << 6) , OPT_IGNORE_CONNECTEDLINE = (1 << 7) ,
  OPT_CALLEE_PARK = (1 << 8) , OPT_CALLER_PARK = (1 << 9) , OPT_NO_RETRY = (1 << 10) , OPT_RINGING = (1 << 11) ,
  OPT_RING_WHEN_RINGING = (1 << 12) , OPT_CALLEE_TRANSFER = (1 << 13) , OPT_CALLER_TRANSFER = (1 << 14) , OPT_CALLEE_AUTOMIXMON = (1 << 15) ,
  OPT_CALLER_AUTOMIXMON = (1 << 16) , OPT_CALLEE_AUTOMON = (1 << 17) , OPT_CALLER_AUTOMON = (1 << 18) , OPT_PREDIAL_CALLEE = (1 << 19) ,
  OPT_PREDIAL_CALLER = (1 << 20) , OPT_MUSICONHOLD_CLASS = (1 << 21)
}
 
enum  {
  OPT_ARG_CALLEE_GO_ON = 0 , OPT_ARG_PREDIAL_CALLEE , OPT_ARG_PREDIAL_CALLER , OPT_ARG_MUSICONHOLD_CLASS ,
  OPT_ARG_ARRAY_SIZE
}
 
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  aqm_args { AQM_OPT_ARG_PAUSE_REASON = 0 , AQM_OPT_ARG_ARRAY_SIZE }
 
enum  aqm_flags { AQMFLAG_PAUSED = (1 << 1) , AQMFLAG_REASON = (1 << 2) }
 
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  member_properties { MEMBER_PENALTY = 0 , MEMBER_RINGINUSE = 1 }
 
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 ,
  QUEUE_WITHDRAW = 8
}
 
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. More...
 
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, const char *reason_paused, int wrapuptime)
 Add member to queue. More...
 
static struct call_queuealloc_queue (const char *queuename)
 
 AO2_STRING_FIELD_SORT_FN (call_queue, name)
 
static int aqm_exec (struct ast_channel *chan, const char *data)
 AddQueueMember application. More...
 
struct ast_moduleAST_MODULE_SELF_SYM (void)
 
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. More...
 
static void callattempt_free (struct callattempt *doomed)
 
static int can_ring_entry (struct queue_ent *qe, struct callattempt *call)
 
static int change_priority_caller_on_queue (const char *queuename, const char *caller, int priority, int immediate)
 Change priority caller into a queue. More...
 
static void clear_queue (struct call_queue *q)
 
static int clear_stats (const char *queuename)
 Facilitates resetting statistics for a queue. More...
 
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, ptrdiff_t word_list_offset)
 Check if a given word is in a space-delimited list. More...
 
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_value (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 int context_included (const char *parent, const char *child)
 Returns if one context includes another context. More...
 
static void copy_rules (struct queue_ent *qe, const char *rulename)
 Copy rule from global list into specified queue. More...
 
static struct membercreate_queue_member (const char *interface, const char *membername, int penalty, int paused, const char *state_interface, int ringinuse, int wrapuptime)
 allocate space for new queue member and set fields based on parameters passed More...
 
static void destroy_queue (void *obj)
 Free queue's member list then its string fields. More...
 
static void destroy_queue_member_cb (void *obj)
 
static void device_state_cb (void *unused, struct stasis_subscription *sub, struct stasis_message *msg)
 set a member's status based on device state of that member's interface More...
 
static void do_hang (struct callattempt *o)
 common hangup actions More...
 
static void do_print (struct mansession *s, int fd, const char *str)
 direct output to manager or cli with proper terminator More...
 
static void dump_queue_members (struct call_queue *pm_queue)
 Dump all members in a specific queue to the database. More...
 
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 void escape_and_substitute (struct ast_channel *chan, const char *input, char *output, size_t size)
 
static int extension_state_cb (const char *context, const char *exten, struct ast_state_cb_info *info, void *data)
 
static int extensionstate2devicestate (int state)
 Helper function which converts from extension state to device state values. More...
 
static struct callattemptfind_best (struct callattempt *outgoing)
 find the entry with the best metric, or NULL More...
 
static struct call_queuefind_load_queue_rt_friendly (const char *queuename)
 
static struct memberfind_member_by_queuename_and_interface (const char *queuename, const char *interface)
 Find a member by looking up queuename and interface. More...
 
static struct call_queuefind_queue_by_name_rt (const char *queuename, struct ast_variable *queue_vars, struct ast_config *member_config)
 Reload a single queue via realtime. More...
 
static void free_members (struct call_queue *q, int all)
 Iterate through queue's member list and delete them. More...
 
static struct memberget_interface_helper (struct call_queue *q, const char *interface)
 
static int get_member_penalty (char *queuename, char *interface)
 Gets members penalty. More...
 
static int get_member_status (struct call_queue *q, int max_penalty, int min_penalty, int raise_penalty, enum empty_conditions conditions, int devstate)
 Check if members are available. More...
 
static int get_queue_member_status (struct member *cur)
 Return the current state of a member. More...
 
static int get_wrapuptime (struct call_queue *q, struct member *member)
 Return wrapuptime. More...
 
static void handle_attended_transfer (void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
 Handle an attended transfer event. More...
 
static void handle_blind_transfer (void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
 Handle a blind transfer event. More...
 
static void handle_bridge_enter (void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
 
static void handle_hangup (void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
 
static void handle_local_optimization_begin (void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
 
static void handle_local_optimization_end (void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
 
static void handle_masquerade (void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
 
static char * handle_queue_add_member (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 
static char * handle_queue_change_priority_caller (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 char * handle_queue_set_member_ringinuse (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 
static void hangupcalls (struct queue_ent *qe, struct callattempt *outgoing, struct ast_channel *exception, int cancel_answered_elsewhere)
 Hang up a list of outgoing calls. More...
 
static void init_queue (struct call_queue *q)
 Initialize Queue default values. More...
 
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'. More...
 
static int insert_penaltychange (const char *list_name, const char *content, const int linenum)
 Change queue penalty by adding rule. More...
 
static const char * int2strat (int strategy)
 
static struct memberinterface_exists (struct call_queue *q, const char *interface)
 
static int is_longest_waiting_caller (struct queue_ent *caller, struct member *member)
 
static int is_member_available (struct call_queue *q, struct member *mem)
 
static int is_our_turn (struct queue_ent *qe)
 Check if we should start attempting to call queue members. More...
 
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_if_unfound (void *obj, void *arg, int flags)
 
static void leave_queue (struct queue_ent *qe)
 Caller leaving queue. More...
 
static int load_module (void)
 Load the module. More...
 
static void load_realtime_queues (const char *queuename)
 
static int load_realtime_rules (void)
 Load queue rules from realtime. More...
 
static void log_attended_transfer (struct queue_stasis_data *queue_data, struct ast_attended_transfer_message *atxfer_msg)
 
static int manager_add_queue_member (struct mansession *s, const struct message *m)
 
static int manager_change_priority_caller_on_queue (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_member_ringinuse (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_status (struct mansession *s, const struct message *m)
 Queue status info via AMI. More...
 
static int manager_queues_summary (struct mansession *s, const struct message *m)
 Summary of queue info via the AMI. More...
 
static int manager_remove_queue_member (struct mansession *s, const struct message *m)
 
static int manager_request_withdraw_caller_from_queue (struct mansession *s, const struct message *m)
 
static int mark_member_dead (void *obj, void *arg, int flags)
 
static int mark_unfound (void *obj, void *arg, int flags)
 
static void member_add_to_queue (struct call_queue *queue, struct member *mem)
 
static int member_cmp_fn (void *obj1, void *obj2, int flags)
 
static int member_hash_fn (const void *obj, const int flags)
 
static void member_remove_from_queue (struct call_queue *queue, struct member *mem)
 
static int member_status_available (int status)
 
static int num_available_members (struct call_queue *q)
 Get the number of members available to accept a call. More...
 
static void parse_empty_options (const char *value, enum empty_conditions *empty, int joinempty)
 
static int pending_members_cmp (void *obj, void *arg, int flags)
 
static int pending_members_hash (const void *obj, const int flags)
 
static void pending_members_remove (struct member *mem)
 
static int play_file (struct ast_channel *chan, const char *filename)
 
static int pqm_exec (struct ast_channel *chan, const char *data)
 PauseQueueMember application. More...
 
static void print_queue (struct mansession *s, int fd, struct call_queue *q)
 Print a single queue to AMI or the CLI. More...
 
static void publish_dial_end_event (struct ast_channel *in, struct callattempt *outgoing, struct ast_channel *exception, const char *status)
 
static int publish_queue_member_pause (struct call_queue *q, struct member *member)
 
static int ql_exec (struct ast_channel *chan, const char *data)
 QueueLog application. More...
 
static struct ast_manager_event_blobqueue_agent_called_to_ami (struct stasis_message *message)
 
static void queue_agent_cb (void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
 
static struct ast_manager_event_blobqueue_agent_complete_to_ami (struct stasis_message *message)
 
static struct ast_manager_event_blobqueue_agent_connect_to_ami (struct stasis_message *message)
 
static struct ast_manager_event_blobqueue_agent_dump_to_ami (struct stasis_message *message)
 
static struct ast_manager_event_blobqueue_agent_ringnoanswer_to_ami (struct stasis_message *message)
 
static void queue_bridge_cb (void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
 
static struct ast_manager_event_blobqueue_caller_abandon_to_ami (struct stasis_message *message)
 
static struct ast_manager_event_blobqueue_caller_join_to_ami (struct stasis_message *message)
 
static struct ast_manager_event_blobqueue_caller_leave_to_ami (struct stasis_message *message)
 
static void queue_channel_cb (void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
 
static struct ast_manager_event_blobqueue_channel_to_ami (const char *type, struct stasis_message *message)
 
static int queue_cmp_cb (void *obj, void *arg, int flags)
 
static int queue_delme_members_decrement_followers (void *obj, void *arg, int flag)
 
static int queue_exec (struct ast_channel *chan, const char *data)
 The starting point for all queue calls. More...
 
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. More...
 
static int queue_function_mem_read (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. More...
 
static int queue_function_mem_write (struct ast_channel *chan, const char *cmd, char *data, const char *value)
 Dialplan function QUEUE_MEMBER() Sets the members penalty / paused / ringinuse. More...
 
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. More...
 
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. More...
 
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) More...
 
static int queue_function_queuegetchannel (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
 Dialplan function QUEUE_GET_CHANNEL() Get caller channel waiting at specified position in the queue. More...
 
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. More...
 
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. More...
 
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. More...
 
static int queue_hash_cb (const void *obj, const int flags)
 
static struct ast_manager_event_blobqueue_member_added_to_ami (struct stasis_message *message)
 
static struct ast_jsonqueue_member_blob_create (struct call_queue *q, struct member *mem)
 
static int queue_member_decrement_followers (void *obj, void *arg, int flag)
 
static void queue_member_follower_removal (struct call_queue *queue, struct member *mem)
 
static struct ast_manager_event_blobqueue_member_pause_to_ami (struct stasis_message *message)
 
static struct ast_manager_event_blobqueue_member_penalty_to_ami (struct stasis_message *message)
 
static struct ast_manager_event_blobqueue_member_removed_to_ami (struct stasis_message *message)
 
static struct ast_manager_event_blobqueue_member_ringinuse_to_ami (struct stasis_message *message)
 
static struct ast_manager_event_blobqueue_member_status_to_ami (struct stasis_message *message)
 
static struct ast_manager_event_blobqueue_member_to_ami (const char *type, struct stasis_message *message)
 
static struct ast_manager_event_blobqueue_multi_channel_to_ami (const char *type, struct stasis_message *message)
 
static void queue_publish_member_blob (struct stasis_message_type *type, struct ast_json *blob)
 
static void queue_publish_multi_channel_blob (struct ast_channel *caller, struct ast_channel *agent, struct stasis_message_type *type, struct ast_json *blob)
 
static void queue_publish_multi_channel_snapshot_blob (struct stasis_topic *topic, struct ast_channel_snapshot *caller_snapshot, struct ast_channel_snapshot *agent_snapshot, struct stasis_message_type *type, struct ast_json *blob)
 
static void queue_reset_global_params (void)
 
static void queue_rules_reset_global_params (void)
 
static void queue_rules_set_global_params (struct ast_config *cfg)
 
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. More...
 
static char * queue_show (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 
static struct queue_stasis_dataqueue_stasis_data_alloc (struct queue_ent *qe, struct ast_channel *peer, struct member *mem, time_t holdstart, time_t starttime, int callcompletedinsl)
 
static void queue_stasis_data_destructor (void *obj)
 
static int qupd_exec (struct ast_channel *chan, const char *data)
 Update Queue with data of an outgoing call. More...
 
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. More...
 
static int reload (void)
 
static int reload_handler (int reload, struct ast_flags *mask, const char *queuename)
 The command center for all reload operations. More...
 
static void reload_queue_members (void)
 Reload dynamic queue members persisted into the astdb. More...
 
static int reload_queue_rules (int reload)
 Reload the rules defined in queuerules.conf. More...
 
static int reload_queues (int reload, struct ast_flags *mask, const char *queuename)
 reload the queues.conf file More...
 
static void reload_single_member (const char *memberdata, struct call_queue *q)
 reload information pertaining to a single member More...
 
static void reload_single_queue (struct ast_config *cfg, struct ast_flags *mask, const char *queuename)
 Reload information pertaining to a particular queue. More...
 
static int remove_from_queue (const char *queuename, const char *interface)
 Remove member from queue. More...
 
static void remove_stasis_subscriptions (struct queue_stasis_data *queue_data)
 
static int request_withdraw_caller_from_queue (const char *queuename, const char *caller, const char *withdraw_info)
 Request to withdraw a caller from a queue. More...
 
static int ring_entry (struct queue_ent *qe, struct callattempt *tmp, int *busies)
 Part 2 of ring_one. More...
 
static int ring_one (struct queue_ent *qe, struct callattempt *outgoing, int *busies)
 Place a call to a queue member. More...
 
static void rna (int rnatime, struct queue_ent *qe, struct ast_channel *peer, char *interface, char *membername, int autopause)
 RNA == Ring No Answer. Common code that is executed when we try a queue member and they don't answer. More...
 
static int rqm_exec (struct ast_channel *chan, const char *data)
 RemoveQueueMember application. More...
 
static void rt_handle_member_record (struct call_queue *q, char *category, struct ast_config *member_config)
 Find rt member record to update otherwise create one. More...
 
static int say_periodic_announcement (struct queue_ent *qe, int ringing)
 Playback announcement to queued members if period has elapsed. More...
 
static int say_position (struct queue_ent *qe, int ringing)
 
static void send_agent_complete (const char *queuename, struct ast_channel_snapshot *caller, struct ast_channel_snapshot *peer, const struct member *member, time_t holdstart, time_t callstart, enum agent_complete_reason rsn)
 Send out AMI message with member call completion status information. More...
 
static int set_member_paused (const char *queuename, const char *interface, const char *reason, int paused)
 
static int set_member_penalty_help_members (struct call_queue *q, const char *interface, int penalty)
 
static int set_member_ringinuse_help_members (struct call_queue *q, const char *interface, int ringinuse)
 
static int set_member_value (const char *queuename, const char *interface, int property, int value)
 
static int set_member_value_help_members (struct call_queue *q, const char *interface, int property, int value)
 
static void set_queue_member_pause (struct call_queue *q, struct member *mem, const char *reason, int paused)
 
static void set_queue_member_ringinuse (struct call_queue *q, struct member *mem, int ringinuse)
 
static void set_queue_result (struct ast_channel *chan, enum queue_result res)
 sets the QUEUESTATUS channel variable More...
 
static void set_queue_variables (struct call_queue *q, struct ast_channel *chan)
 Set variables of queue. More...
 
static void setup_mixmonitor (struct queue_ent *qe, const char *filename)
 
static void setup_peer_after_bridge_goto (struct ast_channel *chan, struct ast_channel *peer, struct ast_flags *opts, char *opt_args[])
 
static int setup_stasis_subs (struct queue_ent *qe, struct ast_channel *peer, struct member *mem, time_t holdstart, time_t starttime, int callcompletedinsl)
 
 STASIS_MESSAGE_TYPE_DEFN_LOCAL (queue_agent_called_type,.to_ami=queue_agent_called_to_ami,)
 
 STASIS_MESSAGE_TYPE_DEFN_LOCAL (queue_agent_complete_type,.to_ami=queue_agent_complete_to_ami,)
 
 STASIS_MESSAGE_TYPE_DEFN_LOCAL (queue_agent_connect_type,.to_ami=queue_agent_connect_to_ami,)
 
 STASIS_MESSAGE_TYPE_DEFN_LOCAL (queue_agent_dump_type,.to_ami=queue_agent_dump_to_ami,)
 
 STASIS_MESSAGE_TYPE_DEFN_LOCAL (queue_agent_ringnoanswer_type,.to_ami=queue_agent_ringnoanswer_to_ami,)
 
 STASIS_MESSAGE_TYPE_DEFN_LOCAL (queue_caller_abandon_type,.to_ami=queue_caller_abandon_to_ami,)
 
 STASIS_MESSAGE_TYPE_DEFN_LOCAL (queue_caller_join_type,.to_ami=queue_caller_join_to_ami,)
 
 STASIS_MESSAGE_TYPE_DEFN_LOCAL (queue_caller_leave_type,.to_ami=queue_caller_leave_to_ami,)
 
 STASIS_MESSAGE_TYPE_DEFN_LOCAL (queue_member_added_type,.to_ami=queue_member_added_to_ami,)
 
 STASIS_MESSAGE_TYPE_DEFN_LOCAL (queue_member_pause_type,.to_ami=queue_member_pause_to_ami,)
 
 STASIS_MESSAGE_TYPE_DEFN_LOCAL (queue_member_penalty_type,.to_ami=queue_member_penalty_to_ami,)
 
 STASIS_MESSAGE_TYPE_DEFN_LOCAL (queue_member_removed_type,.to_ami=queue_member_removed_to_ami,)
 
 STASIS_MESSAGE_TYPE_DEFN_LOCAL (queue_member_ringinuse_type,.to_ami=queue_member_ringinuse_to_ami,)
 
 STASIS_MESSAGE_TYPE_DEFN_LOCAL (queue_member_status_type,.to_ami=queue_member_status_to_ami,)
 
static int store_next_lin (struct queue_ent *qe, struct callattempt *outgoing)
 Search for best metric and add to Linear queue. More...
 
static int store_next_rr (struct queue_ent *qe, struct callattempt *outgoing)
 Search for best metric and add to Round Robbin queue. More...
 
static int strat2int (const char *strategy)
 
static int try_calling (struct queue_ent *qe, struct ast_flags opts, char **opt_args, char *announceoverride, const char *url, int *tries, int *noption, const char *agi, const char *gosub, int ringing)
 
static int unload_module (void)
 
static void update_connected_line_from_peer (struct ast_channel *chan, struct ast_channel *peer, int is_caller)
 
static void update_qe_rule (struct queue_ent *qe)
 update rules for queues More...
 
static int update_queue (struct call_queue *q, struct member *member, int callcompletedinsl, time_t starttime)
 update the queue status More...
 
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 void 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. More...
 
static int upqm_exec (struct ast_channel *chan, const char *data)
 UnpauseQueueMember application. More...
 
static int valid_exit (struct queue_ent *qe, char digit)
 Check for valid exit from queue via goto. More...
 
static int wait_a_bit (struct queue_ent *qe)
 
static struct callattemptwait_for_answer (struct queue_ent *qe, struct callattempt *outgoing, int *to, char *digit, int prebusies, int caller_disconnect, int forwardsallowed)
 Wait for a member to answer the call. More...
 
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. More...
 
static int word_in_list (const char *list, const char *word)
 Check if a given word is in a space-delimited list. More...
 

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 = AST_BUILDOPT_SUM, .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, .reload = reload, .load_pri = AST_MODPRI_DEVSTATE_CONSUMER, }
 
static struct stasis_message_routeragent_router
 
static char * app = "Queue"
 
static char * app_aqm = "AddQueueMember"
 
static char * app_pqm = "PauseQueueMember"
 
static char * app_ql = "QueueLog"
 
static char * app_qupd = "QueueUpdate"
 
static char * app_rqm = "RemoveQueueMember"
 
static char * app_upqm = "UnpauseQueueMember"
 
static const struct ast_app_option aqm_opts [128] = { [ 'p' ] = { .flag = AQMFLAG_PAUSED }, [ 'r' ] = { .flag = AQMFLAG_REASON , .arg_index = AQM_OPT_ARG_PAUSE_REASON + 1 }, }
 
static const struct ast_module_infoast_module_info = &__mod_info
 
static int autofill_default
 queues.conf [general] option More...
 
static const struct autopause autopausesmodes []
 
static struct ast_cli_entry cli_queue []
 
static struct stasis_subscriptiondevice_state_sub
 Subscription to device state change messages. More...
 
static int force_longest_waiting_caller
 queues.conf [general] option More...
 
static int log_membername_as_agent
 queues.conf [general] option More...
 
static int montype_default
 queues.conf [general] option More...
 
static int negative_penalty_invalid
 queues.conf [general] option More...
 
static struct ao2_containerpending_members
 
static const char *const pm_family = "Queue/PersistentMembers"
 Persistent Members astdb family. More...
 
static const struct ast_app_option queue_exec_options [128] = { [ 'b' ] = { .flag = OPT_PREDIAL_CALLEE , .arg_index = OPT_ARG_PREDIAL_CALLEE + 1 }, [ 'B' ] = { .flag = OPT_PREDIAL_CALLER , .arg_index = OPT_ARG_PREDIAL_CALLER + 1 }, [ 'C' ] = { .flag = OPT_MARK_AS_ANSWERED }, [ 'c' ] = { .flag = OPT_GO_ON }, [ 'd' ] = { .flag = OPT_DATA_QUALITY }, [ 'F' ] = { .flag = OPT_CALLEE_GO_ON , .arg_index = OPT_ARG_CALLEE_GO_ON + 1 }, [ 'h' ] = { .flag = OPT_CALLEE_HANGUP }, [ 'H' ] = { .flag = OPT_CALLER_HANGUP }, [ 'i' ] = { .flag = OPT_IGNORE_CALL_FW }, [ 'I' ] = { .flag = OPT_IGNORE_CONNECTEDLINE }, [ 'k' ] = { .flag = OPT_CALLEE_PARK }, [ 'K' ] = { .flag = OPT_CALLER_PARK }, [ 'm' ] = { .flag = OPT_MUSICONHOLD_CLASS , .arg_index = OPT_ARG_MUSICONHOLD_CLASS + 1 }, [ 'n' ] = { .flag = OPT_NO_RETRY }, [ 'r' ] = { .flag = OPT_RINGING }, [ 'R' ] = { .flag = OPT_RING_WHEN_RINGING }, [ 't' ] = { .flag = OPT_CALLEE_TRANSFER }, [ 'T' ] = { .flag = OPT_CALLER_TRANSFER }, [ 'x' ] = { .flag = OPT_CALLEE_AUTOMIXMON }, [ 'X' ] = { .flag = OPT_CALLER_AUTOMIXMON }, [ 'w' ] = { .flag = OPT_CALLEE_AUTOMON }, [ 'W' ] = { .flag = OPT_CALLER_AUTOMON }, }
 
static int queue_persistent_members
 queues.conf [general] option More...
 
struct {
   enum queue_result   id
 
   char *   text
 
queue_results []
 
static struct ast_custom_function queueexists_function
 
static struct ast_custom_function queuegetchannel_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_containerqueues
 
static struct ast_custom_function queuevar_function
 
static struct ast_custom_function queuewaitingcount_function
 
static int realtime_reason_paused
 does realtime backend support reason_paused More...
 
static char * realtime_ringinuse_field
 name of the ringinuse field in the realtime database More...
 
static int realtime_rules
 queuerules.conf [general] option More...
 
static struct rule_lists rule_lists = { .first = NULL, .last = NULL, .lock = { PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP , NULL, {1, 0} } , }
 
static int shared_lastcall
 queues.conf [general] option More...
 
static const struct strategy strategies []
 
static struct stasis_forwardtopic_forwarder
 
static int use_weight
 Records that one or more queues use weight. More...
 

Detailed Description

True call queues with optional send URL on answer.

Author
Mark Spencer marks.nosp@m.ter@.nosp@m.digiu.nosp@m.m.co.nosp@m.m
Development notes
Note
2004-11-25: Persistent Dynamic Members added by: NetNation Communications (www.netnation.com) Kevin Lindsay kevin.nosp@m.l@ne.nosp@m.tnati.nosp@m.on.c.nosp@m.om

Each dynamic agent in each queue is now stored in the astdb. When asterisk is restarted, each agent will be automatically readded into their recorded queues. This feature can be configured with the 'persistent_members=<1|0>' setting in the '[general]' category in queues.conf. The default is on.

Note
2004-06-04: Priorities in queues added by inAccess Networks (work funded by Hellas On Line (HOL) www.hol.gr).
These features added by David C. Troy dave@.nosp@m.toad.nosp@m..net:
  • Per-queue holdtime calculation
  • Estimated holdtime announcement
  • Position announcement
  • Abandoned/completed call counters
  • Failout timer passed as optional app parameter

Patch Version 1.07 2003-12-24 01

Added servicelevel statistic by Michiel Betel michi.nosp@m.el@b.nosp@m.etel..nosp@m.nl Added Priority jumping code for adding and removing queue members by Jonathan Stanton aster.nosp@m.isk@.nosp@m.doilo.nosp@m.okli.nosp@m.keica.nosp@m.re.c.nosp@m.om

Fixed to work with CVS as of 2004-02-25 and released as 1.07a by Matthew Enger m.eng.nosp@m.er@x.nosp@m.i.com.nosp@m..au

Definition in file app_queue.c.

Macro Definition Documentation

◆ ANNOUNCEHOLDTIME_ALWAYS

#define ANNOUNCEHOLDTIME_ALWAYS   1

Definition at line 1800 of file app_queue.c.

◆ ANNOUNCEHOLDTIME_ONCE

#define ANNOUNCEHOLDTIME_ONCE   2

Definition at line 1801 of file app_queue.c.

◆ ANNOUNCEPOSITION_LIMIT

#define ANNOUNCEPOSITION_LIMIT   4

We not announce position more than <limit>

Definition at line 1818 of file app_queue.c.

◆ ANNOUNCEPOSITION_MORE_THAN

#define ANNOUNCEPOSITION_MORE_THAN   3

We say "Currently there are more than <limit>"

Definition at line 1817 of file app_queue.c.

◆ ANNOUNCEPOSITION_NO

#define ANNOUNCEPOSITION_NO   2

We don't announce position

Definition at line 1816 of file app_queue.c.

◆ ANNOUNCEPOSITION_YES

#define ANNOUNCEPOSITION_YES   1

We announce position

Definition at line 1815 of file app_queue.c.

◆ AST_MAX_WATCHERS

#define AST_MAX_WATCHERS   256

Definition at line 5220 of file app_queue.c.

◆ DEFAULT_MIN_ANNOUNCE_FREQUENCY

#define DEFAULT_MIN_ANNOUNCE_FREQUENCY   15

The minimum number of seconds between position announcements.

Note
The default value of 15 provides backwards compatibility.

Definition at line 1590 of file app_queue.c.

◆ DEFAULT_RETRY

#define DEFAULT_RETRY   5

Definition at line 1582 of file app_queue.c.

◆ DEFAULT_TIMEOUT

#define DEFAULT_TIMEOUT   15

Definition at line 1583 of file app_queue.c.

◆ MAX_CALL_ATTEMPT_BUCKETS

#define MAX_CALL_ATTEMPT_BUCKETS   353

Definition at line 2543 of file app_queue.c.

◆ MAX_PERIODIC_ANNOUNCEMENTS

#define MAX_PERIODIC_ANNOUNCEMENTS   10

The maximum periodic announcements we can have

Definition at line 1585 of file app_queue.c.

◆ MAX_QUEUE_BUCKETS

#define MAX_QUEUE_BUCKETS   53

Definition at line 1592 of file app_queue.c.

◆ QUEUE_EVENT_VARIABLES

#define QUEUE_EVENT_VARIABLES   3

Definition at line 1802 of file app_queue.c.

◆ QUEUE_PAUSED_DEVSTATE

#define QUEUE_PAUSED_DEVSTATE   AST_DEVICE_INUSE

Definition at line 3565 of file app_queue.c.

◆ queue_ref

#define queue_ref (   q)    ao2_bump(q)

Definition at line 2084 of file app_queue.c.

◆ queue_t_ref

#define queue_t_ref (   q,
  tag 
)    ao2_t_bump(q, tag)

Definition at line 2086 of file app_queue.c.

◆ queue_t_unref

#define queue_t_unref (   q,
  tag 
)    ({ ao2_t_cleanup(q, tag); NULL; })

Definition at line 2087 of file app_queue.c.

◆ QUEUE_UNKNOWN_PAUSED_DEVSTATE

#define QUEUE_UNKNOWN_PAUSED_DEVSTATE   AST_DEVICE_NOT_INUSE

Definition at line 3567 of file app_queue.c.

◆ QUEUE_UNPAUSED_DEVSTATE

#define QUEUE_UNPAUSED_DEVSTATE   AST_DEVICE_NOT_INUSE

Definition at line 3566 of file app_queue.c.

◆ queue_unref

#define queue_unref (   q)    ({ ao2_cleanup(q); NULL; })

Definition at line 2085 of file app_queue.c.

◆ queues_t_link

#define queues_t_link (   c,
  q,
  tag 
)    ao2_t_link(c, q, tag)

Definition at line 2088 of file app_queue.c.

◆ queues_t_unlink

#define queues_t_unlink (   c,
  q,
  tag 
)    ao2_t_unlink(c, q, tag)

Definition at line 2089 of file app_queue.c.

◆ RECHECK

#define RECHECK   1

Recheck every second to see we we're at the top yet

Definition at line 1584 of file app_queue.c.

◆ RES_EXISTS

#define RES_EXISTS   (-1)

Entry already exists

Definition at line 1595 of file app_queue.c.

◆ RES_NOSUCHQUEUE

#define RES_NOSUCHQUEUE   (-3)

No such queue

Definition at line 1597 of file app_queue.c.

◆ RES_NOT_CALLER

#define RES_NOT_CALLER   (-5)

Caller not found

Definition at line 1599 of file app_queue.c.

◆ RES_NOT_DYNAMIC

#define RES_NOT_DYNAMIC   (-4)

Member is not dynamic

Definition at line 1598 of file app_queue.c.

◆ RES_OKAY

#define RES_OKAY   0

Action completed

Definition at line 1594 of file app_queue.c.

◆ RES_OUTOFMEMORY

#define RES_OUTOFMEMORY   (-2)

Out of memory

Definition at line 1596 of file app_queue.c.

Enumeration Type Documentation

◆ anonymous enum

anonymous enum
Please read before modifying this file.
There are three locks which are regularly used throughout this file, the queue list lock, the lock for each individual queue, and the interface list lock. Please be extra careful to always lock in the following order 1) queue list lock 2) individual queue lock 3) interface list lock This order has sort of "evolved" over the lifetime of this application, but it is now in place this way, so please adhere to this order!
Enumerator
OPT_MARK_AS_ANSWERED 
OPT_GO_ON 
OPT_DATA_QUALITY 
OPT_CALLEE_GO_ON 
OPT_CALLEE_HANGUP 
OPT_CALLER_HANGUP 
OPT_IGNORE_CALL_FW 
OPT_IGNORE_CONNECTEDLINE 
OPT_CALLEE_PARK 
OPT_CALLER_PARK 
OPT_NO_RETRY 
OPT_RINGING 
OPT_RING_WHEN_RINGING 
OPT_CALLEE_TRANSFER 
OPT_CALLER_TRANSFER 
OPT_CALLEE_AUTOMIXMON 
OPT_CALLER_AUTOMIXMON 
OPT_CALLEE_AUTOMON 
OPT_CALLER_AUTOMON 
OPT_PREDIAL_CALLEE 
OPT_PREDIAL_CALLER 
OPT_MUSICONHOLD_CLASS 

Definition at line 1459 of file app_queue.c.

1459 {
1460 OPT_MARK_AS_ANSWERED = (1 << 0),
1461 OPT_GO_ON = (1 << 1),
1462 OPT_DATA_QUALITY = (1 << 2),
1463 OPT_CALLEE_GO_ON = (1 << 3),
1464 OPT_CALLEE_HANGUP = (1 << 4),
1465 OPT_CALLER_HANGUP = (1 << 5),
1466 OPT_IGNORE_CALL_FW = (1 << 6),
1467 OPT_IGNORE_CONNECTEDLINE = (1 << 7),
1468 OPT_CALLEE_PARK = (1 << 8),
1469 OPT_CALLER_PARK = (1 << 9),
1470 OPT_NO_RETRY = (1 << 10),
1471 OPT_RINGING = (1 << 11),
1472 OPT_RING_WHEN_RINGING = (1 << 12),
1473 OPT_CALLEE_TRANSFER = (1 << 13),
1474 OPT_CALLER_TRANSFER = (1 << 14),
1475 OPT_CALLEE_AUTOMIXMON = (1 << 15),
1476 OPT_CALLER_AUTOMIXMON = (1 << 16),
1477 OPT_CALLEE_AUTOMON = (1 << 17),
1478 OPT_CALLER_AUTOMON = (1 << 18),
1479 OPT_PREDIAL_CALLEE = (1 << 19),
1480 OPT_PREDIAL_CALLER = (1 << 20),
1481 OPT_MUSICONHOLD_CLASS = (1 << 21),
1482};
@ OPT_CALLER_AUTOMON
Definition: app_queue.c:1478
@ OPT_CALLEE_PARK
Definition: app_queue.c:1468
@ OPT_PREDIAL_CALLER
Definition: app_queue.c:1480
@ OPT_GO_ON
Definition: app_queue.c:1461
@ OPT_IGNORE_CONNECTEDLINE
Definition: app_queue.c:1467
@ OPT_CALLEE_AUTOMON
Definition: app_queue.c:1477
@ OPT_CALLEE_TRANSFER
Definition: app_queue.c:1473
@ OPT_CALLEE_GO_ON
Definition: app_queue.c:1463
@ OPT_MARK_AS_ANSWERED
Definition: app_queue.c:1460
@ OPT_IGNORE_CALL_FW
Definition: app_queue.c:1466
@ OPT_CALLER_PARK
Definition: app_queue.c:1469
@ OPT_NO_RETRY
Definition: app_queue.c:1470
@ OPT_DATA_QUALITY
Definition: app_queue.c:1462
@ OPT_CALLER_HANGUP
Definition: app_queue.c:1465
@ OPT_MUSICONHOLD_CLASS
Definition: app_queue.c:1481
@ OPT_CALLEE_AUTOMIXMON
Definition: app_queue.c:1475
@ OPT_CALLEE_HANGUP
Definition: app_queue.c:1464
@ OPT_CALLER_AUTOMIXMON
Definition: app_queue.c:1476
@ OPT_RINGING
Definition: app_queue.c:1471
@ OPT_CALLER_TRANSFER
Definition: app_queue.c:1474
@ OPT_PREDIAL_CALLEE
Definition: app_queue.c:1479
@ OPT_RING_WHEN_RINGING
Definition: app_queue.c:1472

◆ anonymous enum

anonymous enum
Enumerator
OPT_ARG_CALLEE_GO_ON 
OPT_ARG_PREDIAL_CALLEE 
OPT_ARG_PREDIAL_CALLER 
OPT_ARG_MUSICONHOLD_CLASS 
OPT_ARG_ARRAY_SIZE 

Definition at line 1484 of file app_queue.c.

1484 {
1489 /* note: this entry _MUST_ be the last one in the enum */
1491};
@ OPT_ARG_CALLEE_GO_ON
Definition: app_queue.c:1485
@ OPT_ARG_PREDIAL_CALLEE
Definition: app_queue.c:1486
@ OPT_ARG_MUSICONHOLD_CLASS
Definition: app_queue.c:1488
@ OPT_ARG_PREDIAL_CALLER
Definition: app_queue.c:1487
@ OPT_ARG_ARRAY_SIZE
Definition: app_queue.c:1490

◆ anonymous enum

anonymous enum
Enumerator
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 1534 of file app_queue.c.

1534 {
1543};
@ QUEUE_STRATEGY_RINGALL
Definition: app_queue.c:1535
@ QUEUE_STRATEGY_RRMEMORY
Definition: app_queue.c:1539
@ QUEUE_STRATEGY_LINEAR
Definition: app_queue.c:1540
@ QUEUE_STRATEGY_LEASTRECENT
Definition: app_queue.c:1536
@ QUEUE_STRATEGY_RANDOM
Definition: app_queue.c:1538
@ QUEUE_STRATEGY_FEWESTCALLS
Definition: app_queue.c:1537
@ QUEUE_STRATEGY_RRORDERED
Definition: app_queue.c:1542
@ QUEUE_STRATEGY_WRANDOM
Definition: app_queue.c:1541

◆ anonymous enum

anonymous enum
Enumerator
QUEUE_AUTOPAUSE_OFF 
QUEUE_AUTOPAUSE_ON 
QUEUE_AUTOPAUSE_ALL 

Definition at line 1545 of file app_queue.c.

1545 {
1549};
@ QUEUE_AUTOPAUSE_ON
Definition: app_queue.c:1547
@ QUEUE_AUTOPAUSE_OFF
Definition: app_queue.c:1546
@ QUEUE_AUTOPAUSE_ALL
Definition: app_queue.c:1548

◆ agent_complete_reason

Enumerator
CALLER 
AGENT 
TRANSFER 

Definition at line 6151 of file app_queue.c.

6151 {
6152 CALLER,
6153 AGENT,
6154 TRANSFER
6155};
@ AGENT
Definition: app_queue.c:6153
@ CALLER
Definition: app_queue.c:6152
@ TRANSFER
Definition: app_queue.c:6154

◆ aqm_args

enum aqm_args
Enumerator
AQM_OPT_ARG_PAUSE_REASON 
AQM_OPT_ARG_ARRAY_SIZE 

Definition at line 1524 of file app_queue.c.

1524 {
1526 AQM_OPT_ARG_ARRAY_SIZE, /* Always last element of the enum */
1527};
@ AQM_OPT_ARG_ARRAY_SIZE
Definition: app_queue.c:1526
@ AQM_OPT_ARG_PAUSE_REASON
Definition: app_queue.c:1525

◆ aqm_flags

enum aqm_flags
Enumerator
AQMFLAG_PAUSED 
AQMFLAG_REASON 

Definition at line 1519 of file app_queue.c.

1519 {
1520 AQMFLAG_PAUSED = (1 << 1),
1521 AQMFLAG_REASON = (1 << 2),
1522};
@ AQMFLAG_REASON
Definition: app_queue.c:1521
@ AQMFLAG_PAUSED
Definition: app_queue.c:1520

◆ empty_conditions

Enumerator
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 1783 of file app_queue.c.

1783 {
1784 QUEUE_EMPTY_PENALTY = (1 << 0),
1785 QUEUE_EMPTY_PAUSED = (1 << 1),
1786 QUEUE_EMPTY_INUSE = (1 << 2),
1787 QUEUE_EMPTY_RINGING = (1 << 3),
1788 QUEUE_EMPTY_UNAVAILABLE = (1 << 4),
1789 QUEUE_EMPTY_INVALID = (1 << 5),
1790 QUEUE_EMPTY_UNKNOWN = (1 << 6),
1791 QUEUE_EMPTY_WRAPUP = (1 << 7),
1792};
@ QUEUE_EMPTY_INVALID
Definition: app_queue.c:1789
@ QUEUE_EMPTY_UNKNOWN
Definition: app_queue.c:1790
@ QUEUE_EMPTY_PENALTY
Definition: app_queue.c:1784
@ QUEUE_EMPTY_RINGING
Definition: app_queue.c:1787
@ QUEUE_EMPTY_INUSE
Definition: app_queue.c:1786
@ QUEUE_EMPTY_UNAVAILABLE
Definition: app_queue.c:1788
@ QUEUE_EMPTY_WRAPUP
Definition: app_queue.c:1791
@ QUEUE_EMPTY_PAUSED
Definition: app_queue.c:1785

◆ member_properties

Enumerator
MEMBER_PENALTY 
MEMBER_RINGINUSE 

Definition at line 1794 of file app_queue.c.

1794 {
1795 MEMBER_PENALTY = 0,
1796 MEMBER_RINGINUSE = 1,
1797};
@ MEMBER_RINGINUSE
Definition: app_queue.c:1796
@ MEMBER_PENALTY
Definition: app_queue.c:1795

◆ queue_reload_mask

Enumerator
QUEUE_RELOAD_PARAMETERS 
QUEUE_RELOAD_MEMBER 
QUEUE_RELOAD_RULES 
QUEUE_RESET_STATS 

Definition at line 1551 of file app_queue.c.

1551 {
1552 QUEUE_RELOAD_PARAMETERS = (1 << 0),
1553 QUEUE_RELOAD_MEMBER = (1 << 1),
1554 QUEUE_RELOAD_RULES = (1 << 2),
1555 QUEUE_RESET_STATS = (1 << 3),
1556};
@ QUEUE_RELOAD_RULES
Definition: app_queue.c:1554
@ QUEUE_RELOAD_MEMBER
Definition: app_queue.c:1553
@ QUEUE_RESET_STATS
Definition: app_queue.c:1555
@ QUEUE_RELOAD_PARAMETERS
Definition: app_queue.c:1552

◆ queue_result

Enumerator
QUEUE_UNKNOWN 
QUEUE_TIMEOUT 
QUEUE_JOINEMPTY 
QUEUE_LEAVEEMPTY 
QUEUE_JOINUNAVAIL 
QUEUE_LEAVEUNAVAIL 
QUEUE_FULL 
QUEUE_CONTINUE 
QUEUE_WITHDRAW 

Definition at line 1654 of file app_queue.c.

1654 {
1655 QUEUE_UNKNOWN = 0,
1656 QUEUE_TIMEOUT = 1,
1657 QUEUE_JOINEMPTY = 2,
1658 QUEUE_LEAVEEMPTY = 3,
1661 QUEUE_FULL = 6,
1662 QUEUE_CONTINUE = 7,
1663 QUEUE_WITHDRAW = 8,
1664};
@ QUEUE_FULL
Definition: app_queue.c:1661
@ QUEUE_UNKNOWN
Definition: app_queue.c:1655
@ QUEUE_WITHDRAW
Definition: app_queue.c:1663
@ QUEUE_CONTINUE
Definition: app_queue.c:1662
@ QUEUE_LEAVEEMPTY
Definition: app_queue.c:1658
@ QUEUE_LEAVEUNAVAIL
Definition: app_queue.c:1660
@ QUEUE_JOINUNAVAIL
Definition: app_queue.c:1659
@ QUEUE_JOINEMPTY
Definition: app_queue.c:1657
@ QUEUE_TIMEOUT
Definition: app_queue.c:1656

◆ queue_timeout_priority

Enumerator
TIMEOUT_PRIORITY_APP 
TIMEOUT_PRIORITY_CONF 

Definition at line 1681 of file app_queue.c.

1681 {
1684};
@ TIMEOUT_PRIORITY_CONF
Definition: app_queue.c:1683
@ TIMEOUT_PRIORITY_APP
Definition: app_queue.c:1682

Function Documentation

◆ __queues_show()

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 10201 of file app_queue.c.

10202{
10203 struct call_queue *q;
10204 struct ast_str *out = ast_str_alloca(512);
10205 struct ao2_container *sorted_queues;
10206
10207 struct ao2_iterator queue_iter;
10208 int found = 0;
10209
10210 if (argc != 2 && argc != 3) {
10211 return CLI_SHOWUSAGE;
10212 }
10213
10214 if (argc == 3) { /* specific queue */
10215 if ((q = find_load_queue_rt_friendly(argv[2]))) {
10216 ao2_lock(q);
10217 print_queue(s, fd, q);
10218 ao2_unlock(q);
10219 queue_unref(q);
10220 } else {
10221 ast_str_set(&out, 0, "No such queue: %s.", argv[2]);
10222 do_print(s, fd, ast_str_buffer(out));
10223 }
10224 return CLI_SUCCESS;
10225 }
10226
10227 if (ast_check_realtime("queues")) {
10228 /* This block is to find any queues which are defined in realtime but
10229 * which have not yet been added to the in-core container
10230 */
10231 struct ast_config *cfg = ast_load_realtime_multientry("queues", "name LIKE", "%", SENTINEL);
10232 if (cfg) {
10233 char *category = NULL;
10234 while ((category = ast_category_browse(cfg, category))) {
10235 const char *queuename = ast_variable_retrieve(cfg, category, "name");
10236 if (ast_strlen_zero(queuename)) {
10237 ast_log(LOG_WARNING, "Ignoring realtime queue with a NULL or empty 'name.'\n");
10238 continue;
10239 }
10240 if ((q = find_load_queue_rt_friendly(queuename))) {
10241 queue_t_unref(q, "Done with temporary pointer");
10242 }
10243 }
10244 ast_config_destroy(cfg);
10245 }
10246 }
10247
10248 /*
10249 * Snapping a copy of the container prevents having to lock both the queues container
10250 * and the queue itself at the same time. It also allows us to sort the entries.
10251 */
10252 sorted_queues = ao2_container_alloc_rbtree(AO2_ALLOC_OPT_LOCK_NOLOCK, 0, call_queue_sort_fn, NULL);
10253 if (!sorted_queues) {
10254 return CLI_SUCCESS;
10255 }
10256 if (ao2_container_dup(sorted_queues, queues, 0)) {
10257 ao2_ref(sorted_queues, -1);
10258 return CLI_SUCCESS;
10259 }
10260
10261 /*
10262 * No need to lock the container since it's temporary and static.
10263 * We also unlink the entries as we use them so the container is
10264 * empty when the iterator finishes. We can then just unref the container.
10265 */
10266 queue_iter = ao2_iterator_init(sorted_queues, AO2_ITERATOR_DONTLOCK | AO2_ITERATOR_UNLINK);
10267 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
10268 struct call_queue *realtime_queue = NULL;
10269 ao2_lock(q);
10270 /* This check is to make sure we don't print information for realtime
10271 * queues which have been deleted from realtime but which have not yet
10272 * been deleted from the in-core container. Only do this if we're not
10273 * looking for a specific queue.
10274 */
10275 if (q->realtime) {
10276 realtime_queue = find_load_queue_rt_friendly(q->name);
10277 if (!realtime_queue) {
10278 ao2_unlock(q);
10279 queue_t_unref(q, "Done with iterator");
10280 continue;
10281 }
10282 queue_t_unref(realtime_queue, "Queue is already in memory");
10283 }
10284
10285 found = 1;
10286 print_queue(s, fd, q);
10287
10288 ao2_unlock(q);
10289 queue_t_unref(q, "Done with iterator"); /* Unref the iterator's reference */
10290 }
10291 ao2_iterator_destroy(&queue_iter);
10292 ao2_ref(sorted_queues, -1);
10293 if (!found) {
10294 ast_str_set(&out, 0, "No queues.");
10295 do_print(s, fd, ast_str_buffer(out));
10296 }
10297 return CLI_SUCCESS;
10298}
static void print_queue(struct mansession *s, int fd, struct call_queue *q)
Print a single queue to AMI or the CLI.
Definition: app_queue.c:10093
static struct ao2_container * queues
Definition: app_queue.c:1930
#define queue_t_unref(q, tag)
Definition: app_queue.c:2087
#define queue_unref(q)
Definition: app_queue.c:2085
static void do_print(struct mansession *s, int fd, const char *str)
direct output to manager or cli with proper terminator
Definition: app_queue.c:10083
static struct call_queue * find_load_queue_rt_friendly(const char *queuename)
Definition: app_queue.c:3924
#define ast_log
Definition: astobj2.c:42
int ao2_container_dup(struct ao2_container *dest, struct ao2_container *src, enum search_flags flags)
Copy all object references in the src container into the dest container.
@ AO2_ALLOC_OPT_LOCK_NOLOCK
Definition: astobj2.h:367
#define ao2_t_iterator_next(iter, tag)
Definition: astobj2.h:1909
@ AO2_ITERATOR_UNLINK
Definition: astobj2.h:1863
@ AO2_ITERATOR_DONTLOCK
Assume that the ao2_container is already locked.
Definition: astobj2.h:1852
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
#define ao2_container_alloc_rbtree(ao2_options, container_options, sort_fn, cmp_fn)
Allocate and initialize a red-black tree container.
Definition: astobj2.h:1349
#define ao2_unlock(a)
Definition: astobj2.h:729
#define ao2_lock(a)
Definition: astobj2.h:717
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
#define CLI_SHOWUSAGE
Definition: cli.h:45
#define CLI_SUCCESS
Definition: cli.h:44
#define SENTINEL
Definition: compiler.h:87
char * ast_category_browse(struct ast_config *config, const char *prev_name)
Browse categories.
Definition: extconf.c:3326
struct ast_config * ast_load_realtime_multientry(const char *family,...) attribute_sentinel
Retrieve realtime configuration.
Definition: main/config.c:3637
int ast_check_realtime(const char *family)
Check if realtime engine is configured for family.
Definition: main/config.c:3545
void ast_config_destroy(struct ast_config *cfg)
Destroys a config.
Definition: extconf.c:1289
const char * ast_variable_retrieve(struct ast_config *config, const char *category, const char *variable)
Definition: main/config.c:784
#define LOG_WARNING
#define NULL
Definition: resample.c:96
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:761
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:65
#define ast_str_alloca(init_len)
Definition: strings.h:848
int ast_str_set(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Set a dynamic string using variable arguments.
Definition: strings.h:1113
Generic container type.
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1821
Support for dynamic strings.
Definition: strings.h:623
unsigned int realtime
Definition: app_queue.c:1874
unsigned int found
Definition: app_queue.c:1875
const ast_string_field name
Definition: app_queue.c:1858
FILE * out
Definition: utils/frame.c:33

References AO2_ALLOC_OPT_LOCK_NOLOCK, ao2_container_alloc_rbtree, ao2_container_dup(), ao2_iterator_destroy(), AO2_ITERATOR_DONTLOCK, ao2_iterator_init(), AO2_ITERATOR_UNLINK, ao2_lock, ao2_ref, ao2_t_iterator_next, ao2_unlock, ast_category_browse(), ast_check_realtime(), ast_config_destroy(), ast_load_realtime_multientry(), ast_log, ast_str_alloca, ast_str_buffer(), ast_str_set(), ast_strlen_zero(), ast_variable_retrieve(), CLI_SHOWUSAGE, CLI_SUCCESS, do_print(), find_load_queue_rt_friendly(), call_queue::found, LOG_WARNING, call_queue::name, NULL, out, print_queue(), queue_t_unref, queue_unref, queues, call_queue::realtime, and SENTINEL.

Referenced by queue_show().

◆ __reg_module()

static void __reg_module ( void  )
static

Definition at line 12018 of file app_queue.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

Definition at line 12018 of file app_queue.c.

◆ add_to_queue()

static int add_to_queue ( const char *  queuename,
const char *  interface,
const char *  membername,
int  penalty,
int  paused,
int  dump,
const char *  state_interface,
const char *  reason_paused,
int  wrapuptime 
)
static

Add member to queue.

Return values
RES_NOT_DYNAMICwhen they aren't a RT member
RES_NOSUCHQUEUEqueue does not exist
RES_OKAYadded member from queue
RES_EXISTSqueue exists but no members
RES_OUT_OF_MEMORYqueue exists but not enough memory to create member
Note
Ensure the appropriate realtime queue is loaded. Note that this short-circuits if the queue is already in memory.

Definition at line 7622 of file app_queue.c.

7623{
7624 struct call_queue *q;
7625 struct member *new_member, *old_member;
7626 int res = RES_NOSUCHQUEUE;
7627
7628 /*! \note Ensure the appropriate realtime queue is loaded. Note that this
7629 * short-circuits if the queue is already in memory. */
7630 if (!(q = find_load_queue_rt_friendly(queuename))) {
7631 return res;
7632 }
7633
7634 ao2_lock(q);
7635 if ((old_member = interface_exists(q, interface)) == NULL) {
7637 new_member->dynamic = 1;
7638 if (reason_paused) {
7639 ast_copy_string(new_member->reason_paused, reason_paused, sizeof(new_member->reason_paused));
7640 }
7641 member_add_to_queue(q, new_member);
7642 queue_publish_member_blob(queue_member_added_type(), queue_member_blob_create(q, new_member));
7643
7644 if (is_member_available(q, new_member)) {
7646 }
7647
7648 ao2_ref(new_member, -1);
7649 new_member = NULL;
7650
7651 if (dump) {
7653 }
7654
7655 res = RES_OKAY;
7656 } else {
7657 res = RES_OUTOFMEMORY;
7658 }
7659 } else {
7660 ao2_ref(old_member, -1);
7661 res = RES_EXISTS;
7662 }
7663 ao2_unlock(q);
7664 queue_t_unref(q, "Expiring temporary reference");
7665
7666 return res;
7667}
static struct member * create_queue_member(const char *interface, const char *membername, int penalty, int paused, const char *state_interface, int ringinuse, int wrapuptime)
allocate space for new queue member and set fields based on parameters passed
Definition: app_queue.c:2894
static struct member * interface_exists(struct call_queue *q, const char *interface)
Definition: app_queue.c:7487
static void dump_queue_members(struct call_queue *pm_queue)
Dump all members in a specific queue to the database.
Definition: app_queue.c:7514
static int is_member_available(struct call_queue *q, struct member *mem)
Definition: app_queue.c:2635
#define RES_OUTOFMEMORY
Definition: app_queue.c:1596
#define RES_NOSUCHQUEUE
Definition: app_queue.c:1597
#define RES_OKAY
Definition: app_queue.c:1594
static void member_add_to_queue(struct call_queue *queue, struct member *mem)
Definition: app_queue.c:3575
static struct ast_json * queue_member_blob_create(struct call_queue *q, struct member *mem)
Definition: app_queue.c:2424
#define RES_EXISTS
Definition: app_queue.c:1595
static void queue_publish_member_blob(struct stasis_message_type *type, struct ast_json *blob)
Definition: app_queue.c:2400
@ AST_DEVSTATE_CACHABLE
Definition: devicestate.h:70
int ast_devstate_changed(enum ast_device_state state, enum ast_devstate_cache cachable, const char *fmt,...)
Tells Asterisk the State for Device is changed.
Definition: devicestate.c:510
@ AST_DEVICE_NOT_INUSE
Definition: devicestate.h:54
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:425
unsigned int ringinuse
Definition: app_queue.c:1862
char interface[AST_CHANNEL_NAME]
Definition: app_queue.c:1756
int dynamic
Definition: app_queue.c:1764
char membername[80]
Definition: app_queue.c:1761
int penalty
Definition: app_queue.c:1762
int paused
Definition: app_queue.c:1767
int wrapuptime
Definition: app_queue.c:1771
char reason_paused[80]
Definition: app_queue.c:1768
char state_interface[AST_CHANNEL_NAME]
Definition: app_queue.c:1759

References ao2_lock, ao2_ref, ao2_unlock, ast_copy_string(), AST_DEVICE_NOT_INUSE, AST_DEVSTATE_CACHABLE, ast_devstate_changed(), create_queue_member(), dump_queue_members(), member::dynamic, find_load_queue_rt_friendly(), member::interface, interface_exists(), is_member_available(), member_add_to_queue(), member::membername, call_queue::name, NULL, member::paused, member::penalty, queue_member_blob_create(), queue_publish_member_blob(), queue_t_unref, member::reason_paused, RES_EXISTS, RES_NOSUCHQUEUE, RES_OKAY, RES_OUTOFMEMORY, call_queue::ringinuse, member::state_interface, and member::wrapuptime.

Referenced by aqm_exec(), handle_queue_add_member(), manager_add_queue_member(), and reload_queue_members().

◆ alloc_queue()

static struct call_queue * alloc_queue ( const char *  queuename)
static

Definition at line 3756 of file app_queue.c.

3757{
3758 struct call_queue *q;
3759
3760 if ((q = ao2_t_alloc(sizeof(*q), destroy_queue, "Allocate queue"))) {
3761 if (ast_string_field_init(q, 64)) {
3762 queue_t_unref(q, "String field allocation failed");
3763 return NULL;
3764 }
3765 ast_string_field_set(q, name, queuename);
3766 }
3767 return q;
3768}
static void destroy_queue(void *obj)
Free queue's member list then its string fields.
Definition: app_queue.c:3741
#define ao2_t_alloc(data_size, destructor_fn, debug_msg)
Definition: astobj2.h:407
static const char name[]
Definition: format_mp3.c:68
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
Definition: stringfields.h:521
#define ast_string_field_init(x, size)
Initialize a field pool and fields.
Definition: stringfields.h:359

References ao2_t_alloc, ast_string_field_init, ast_string_field_set, destroy_queue(), name, NULL, and queue_t_unref.

Referenced by find_queue_by_name_rt(), and reload_single_queue().

◆ AO2_STRING_FIELD_SORT_FN()

AO2_STRING_FIELD_SORT_FN ( call_queue  ,
name   
)

◆ aqm_exec()

static int aqm_exec ( struct ast_channel chan,
const char *  data 
)
static

AddQueueMember application.

Definition at line 8383 of file app_queue.c.

8384{
8385 int res=-1;
8386 char *parse, *tmp, *temppos = NULL, *reason = NULL;
8388 AST_APP_ARG(queuename);
8389 AST_APP_ARG(interface);
8390 AST_APP_ARG(penalty);
8392 AST_APP_ARG(membername);
8393 AST_APP_ARG(state_interface);
8394 AST_APP_ARG(wrapuptime);
8395 );
8396 int penalty = 0;
8397 int paused = 0;
8398 int wrapuptime;
8399 struct ast_flags flags = { 0 };
8400
8401 if (ast_strlen_zero(data)) {
8402 ast_log(LOG_WARNING, "AddQueueMember requires an argument (queuename[,interface[,penalty[,options[,membername[,stateinterface][,wrapuptime]]]]])\n");
8403 return -1;
8404 }
8405
8406 parse = ast_strdupa(data);
8407
8409
8410 if (args.options) {
8411 char *opts[AQM_OPT_ARG_ARRAY_SIZE] = { NULL, };
8412 ast_app_parse_options(aqm_opts, &flags, opts, args.options);
8414 paused = 1;
8416 reason = ast_strdupa(opts[AQM_OPT_ARG_PAUSE_REASON]);
8417 }
8418 }
8419 }
8420
8421 if (ast_strlen_zero(args.interface)) {
8422 args.interface = ast_strdupa(ast_channel_name(chan));
8423 temppos = strrchr(args.interface, '-');
8424 if (temppos) {
8425 *temppos = '\0';
8426 }
8427 }
8428
8429 if (!ast_strlen_zero(args.penalty)) {
8430 if ((sscanf(args.penalty, "%30d", &penalty) != 1) || penalty < 0) {
8431 ast_log(LOG_WARNING, "Penalty '%s' is invalid, must be an integer >= 0\n", args.penalty);
8432 penalty = 0;
8433 }
8434 }
8435
8436 if (!ast_strlen_zero(args.wrapuptime)) {
8437 tmp = args.wrapuptime;
8438 ast_strip(tmp);
8439 wrapuptime = atoi(tmp);
8440 if (wrapuptime < 0) {
8441 wrapuptime = 0;
8442 }
8443 } else {
8444 wrapuptime = 0;
8445 }
8446
8447 switch (add_to_queue(args.queuename, args.interface, args.membername, penalty, paused, queue_persistent_members, args.state_interface, reason, wrapuptime)) {
8448 case RES_OKAY:
8449 if (ast_strlen_zero(args.membername) || !log_membername_as_agent) {
8450 ast_queue_log(args.queuename, ast_channel_uniqueid(chan), args.interface, "ADDMEMBER", "%s", paused ? "PAUSED" : "");
8451 } else {
8452 ast_queue_log(args.queuename, ast_channel_uniqueid(chan), args.membername, "ADDMEMBER", "%s", paused ? "PAUSED" : "");
8453 }
8454 ast_log(LOG_NOTICE, "Added interface '%s' to queue '%s'\n", args.interface, args.queuename);
8455 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "ADDED");
8456 res = 0;
8457 break;
8458 case RES_EXISTS:
8459 ast_log(LOG_WARNING, "Unable to add interface '%s' to queue '%s': Already there\n", args.interface, args.queuename);
8460 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "MEMBERALREADY");
8461 res = 0;
8462 break;
8463 case RES_NOSUCHQUEUE:
8464 ast_log(LOG_WARNING, "Unable to add interface to queue '%s': No such queue\n", args.queuename);
8465 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "NOSUCHQUEUE");
8466 res = 0;
8467 break;
8468 case RES_OUTOFMEMORY:
8469 ast_log(LOG_ERROR, "Out of memory adding interface %s to queue %s\n", args.interface, args.queuename);
8470 break;
8471 }
8472
8473 return res;
8474}
static int queue_persistent_members
queues.conf [general] option
Definition: app_queue.c:1619
static int log_membername_as_agent
queues.conf [general] option
Definition: app_queue.c:1643
static const struct ast_app_option aqm_opts[128]
Definition: app_queue.c:1532
static int add_to_queue(const char *queuename, const char *interface, const char *membername, int penalty, int paused, int dump, const char *state_interface, const char *reason_paused, int wrapuptime)
Add member to queue.
Definition: app_queue.c:7622
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:298
static int tmp()
Definition: bt_open.c:389
const char * ast_channel_name(const struct ast_channel *chan)
const char * ast_channel_uniqueid(const struct ast_channel *chan)
#define AST_APP_ARG(name)
Define an application argument.
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application's arguments.
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the 'standard' argument separation process for an application.
int ast_app_parse_options(const struct ast_app_option *options, struct ast_flags *flags, char **args, char *optstr)
Parses a string containing application options and sets flags/arguments.
Definition: main/app.c:3066
void ast_queue_log(const char *queuename, const char *callid, const char *agent, const char *event, const char *fmt,...)
Definition: logger.c:965
#define LOG_ERROR
#define LOG_NOTICE
int pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value)
Add a variable to the channel variable stack, removing the most recently set value for the same name.
char * ast_strip(char *s)
Strip leading/trailing whitespace from a string.
Definition: strings.h:223
Structure used to handle boolean flags.
Definition: utils.h:199
unsigned int flags
Definition: utils.h:200
const char * args
static struct test_options options
#define ast_test_flag(p, flag)
Definition: utils.h:63

References add_to_queue(), AQM_OPT_ARG_ARRAY_SIZE, AQM_OPT_ARG_PAUSE_REASON, aqm_opts, AQMFLAG_PAUSED, AQMFLAG_REASON, args, AST_APP_ARG, ast_app_parse_options(), ast_channel_name(), ast_channel_uniqueid(), AST_DECLARE_APP_ARGS, ast_log, ast_queue_log(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strip(), ast_strlen_zero(), ast_test_flag, ast_flags::flags, member::interface, LOG_ERROR, log_membername_as_agent, LOG_NOTICE, LOG_WARNING, member::membername, NULL, options, member::paused, pbx_builtin_setvar_helper(), member::penalty, queue_persistent_members, RES_EXISTS, RES_NOSUCHQUEUE, RES_OKAY, RES_OUTOFMEMORY, member::state_interface, tmp(), and member::wrapuptime.

Referenced by load_module().

◆ AST_MODULE_SELF_SYM()

struct ast_module * AST_MODULE_SELF_SYM ( void  )

Definition at line 12018 of file app_queue.c.

◆ autopause2int()

static int autopause2int ( const char *  autopause)
static

Definition at line 1977 of file app_queue.c.

1978{
1979 int x;
1980 /*This 'double check' that default value is OFF */
1982 return QUEUE_AUTOPAUSE_OFF;
1983 }
1984
1985 /*This 'double check' is to ensure old values works */
1986 if(ast_true(autopause)) {
1987 return QUEUE_AUTOPAUSE_ON;
1988 }
1989
1990 for (x = 0; x < ARRAY_LEN(autopausesmodes); x++) {
1991 if (!strcasecmp(autopause, autopausesmodes[x].name)) {
1992 return autopausesmodes[x].autopause;
1993 }
1994 }
1995
1996 /*This 'double check' that default value is OFF */
1997 return QUEUE_AUTOPAUSE_OFF;
1998}
static const struct autopause autopausesmodes[]
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is "true"....
Definition: utils.c:2199
int autopause
Definition: app_queue.c:1574
#define ARRAY_LEN(a)
Definition: utils.h:666

References ARRAY_LEN, ast_strlen_zero(), ast_true(), autopause::autopause, autopausesmodes, name, QUEUE_AUTOPAUSE_OFF, and QUEUE_AUTOPAUSE_ON.

Referenced by queue_set_param().

◆ calc_metric()

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

Return values
-1if penalties are exceeded
0otherwise

Definition at line 6073 of file app_queue.c.

6074{
6075 /* disregarding penalty on too few members? */
6076 int membercount = ao2_container_count(q->members);
6077 unsigned char usepenalty = (membercount <= q->penaltymemberslimit) ? 0 : 1;
6078 int penalty = mem->penalty;
6079
6080 if (usepenalty) {
6081 if (qe->raise_penalty != INT_MAX && penalty < qe->raise_penalty) {
6082 /* Low penalty is raised up to the current minimum */
6083 penalty = qe->raise_penalty;
6084 }
6085 if ((qe->max_penalty != INT_MAX && penalty > qe->max_penalty) ||
6086 (qe->min_penalty != INT_MAX && penalty < qe->min_penalty)) {
6087 return -1;
6088 }
6089 } else {
6090 ast_debug(1, "Disregarding penalty, %d members and %d in penaltymemberslimit.\n",
6091 membercount, q->penaltymemberslimit);
6092 }
6093
6094 switch (q->strategy) {
6096 /* Everyone equal, except for penalty */
6097 tmp->metric = penalty * 1000000 * usepenalty;
6098 break;
6100 if (pos < qe->linpos) {
6101 tmp->metric = 1000 + pos;
6102 } else {
6103 if (pos > qe->linpos) {
6104 /* Indicate there is another priority */
6105 qe->linwrapped = 1;
6106 }
6107 tmp->metric = pos;
6108 }
6109 tmp->metric += penalty * 1000000 * usepenalty;
6110 break;
6113 pos = mem->queuepos;
6114 if (pos < q->rrpos) {
6115 tmp->metric = 1000 + pos;
6116 } else {
6117 if (pos > q->rrpos) {
6118 /* Indicate there is another priority */
6119 q->wrapped = 1;
6120 }
6121 tmp->metric = pos;
6122 }
6123 tmp->metric += penalty * 1000000 * usepenalty;
6124 break;
6126 tmp->metric = ast_random() % 1000;
6127 tmp->metric += penalty * 1000000 * usepenalty;
6128 break;
6130 tmp->metric = ast_random() % ((1 + penalty) * 1000);
6131 break;
6133 tmp->metric = mem->calls;
6134 tmp->metric += penalty * 1000000 * usepenalty;
6135 break;
6137 if (!mem->lastcall) {
6138 tmp->metric = 0;
6139 } else {
6140 tmp->metric = 1000000 - (time(NULL) - mem->lastcall);
6141 }
6142 tmp->metric += penalty * 1000000 * usepenalty;
6143 break;
6144 default:
6145 ast_log(LOG_WARNING, "Can't calculate metric for unknown strategy %d\n", q->strategy);
6146 break;
6147 }
6148 return 0;
6149}
int ao2_container_count(struct ao2_container *c)
Returns the number of elements in a container.
#define ast_debug(level,...)
Log a DEBUG message.
struct ao2_container * members
Definition: app_queue.c:1916
int penaltymemberslimit
Definition: app_queue.c:1900
unsigned int wrapped
Definition: app_queue.c:1868
int strategy
Definition: app_queue.c:1873
int queuepos
Definition: app_queue.c:1769
time_t lastcall
Definition: app_queue.c:1773
int calls
Definition: app_queue.c:1763
int linpos
Definition: app_queue.c:1742
int max_penalty
Definition: app_queue.c:1739
int raise_penalty
Definition: app_queue.c:1741
int min_penalty
Definition: app_queue.c:1740
int linwrapped
Definition: app_queue.c:1743
long int ast_random(void)
Definition: utils.c:2312

References ao2_container_count(), ast_debug, ast_log, ast_random(), member::calls, member::lastcall, queue_ent::linpos, queue_ent::linwrapped, LOG_WARNING, queue_ent::max_penalty, call_queue::members, queue_ent::min_penalty, NULL, 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, member::queuepos, queue_ent::raise_penalty, call_queue::rrpos, call_queue::strategy, tmp(), and call_queue::wrapped.

Referenced by try_calling().

◆ callattempt_free()

static void callattempt_free ( struct callattempt doomed)
static

Definition at line 4476 of file app_queue.c.

4477{
4478 if (doomed->member) {
4479 ao2_ref(doomed->member, -1);
4480 }
4482 ast_free(doomed->orig_chan_name);
4483 ast_free(doomed);
4484}
#define ast_free(a)
Definition: astmm.h:180
void ast_party_connected_line_free(struct ast_party_connected_line *doomed)
Destroy the connected line information contents.
Definition: channel.c:2091
struct ast_party_connected_line connected
Definition: app_queue.c:1706
char * orig_chan_name
Definition: app_queue.c:1717
struct member * member
Definition: app_queue.c:1704

References ao2_ref, ast_free, ast_party_connected_line_free(), callattempt::connected, callattempt::member, and callattempt::orig_chan_name.

Referenced by hangupcalls(), and try_calling().

◆ can_ring_entry()

static int can_ring_entry ( struct queue_ent qe,
struct callattempt call 
)
static

Definition at line 4686 of file app_queue.c.

4687{
4688 struct member *memberp = call->member;
4689 int wrapuptime;
4690
4691 if (memberp->paused) {
4692 ast_debug(1, "%s paused, can't receive call\n", call->interface);
4693 return 0;
4694 }
4695
4696 if (!memberp->ringinuse && !member_status_available(memberp->status)) {
4697 ast_debug(1, "%s not available, can't receive call\n", call->interface);
4698 return 0;
4699 }
4700
4701 if (memberp->lastqueue) {
4702 wrapuptime = get_wrapuptime(memberp->lastqueue, memberp);
4703 } else {
4704 wrapuptime = get_wrapuptime(qe->parent, memberp);
4705 }
4706 if (wrapuptime && (time(NULL) - memberp->lastcall) < wrapuptime) {
4707 ast_debug(1, "Wrapuptime not yet expired on queue %s for %s\n",
4708 (memberp->lastqueue ? memberp->lastqueue->name : qe->parent->name),
4709 call->interface);
4710 return 0;
4711 }
4712
4713 if (use_weight && compare_weight(qe->parent, memberp)) {
4714 ast_debug(1, "Priority queue delaying call to %s:%s\n",
4715 qe->parent->name, call->interface);
4716 return 0;
4717 }
4718
4720 ast_debug(1, "Another caller was waiting longer; delaying call to %s:%s\n",
4721 qe->parent->name, call->interface);
4722 return 0;
4723 }
4724
4725 if (!memberp->ringinuse) {
4726 struct member *mem;
4727
4729
4730 mem = ao2_find(pending_members, memberp,
4732 if (mem) {
4733 /*
4734 * If found that means this member is currently being attempted
4735 * from another calling thread, so stop trying from this thread
4736 */
4737 ast_debug(1, "%s has another call trying, can't receive call\n",
4738 call->interface);
4739 ao2_ref(mem, -1);
4741 return 0;
4742 }
4743
4744 /*
4745 * If not found add it to the container so another queue
4746 * won't attempt to call this member at the same time.
4747 */
4748 ast_debug(3, "Add %s to pending_members\n", memberp->membername);
4749 ao2_link(pending_members, memberp);
4751
4752 /*
4753 * The queue member is available. Get current status to be sure
4754 * because the device state and extension state callbacks may
4755 * not have updated the status yet.
4756 */
4758 ast_debug(1, "%s actually not available, can't receive call\n",
4759 call->interface);
4760 pending_members_remove(memberp);
4761 return 0;
4762 }
4763 }
4764
4765 return 1;
4766}
static int is_longest_waiting_caller(struct queue_ent *caller, struct member *member)
Definition: app_queue.c:4605
static int get_wrapuptime(struct call_queue *q, struct member *member)
Return wrapuptime.
Definition: app_queue.c:2020
static int compare_weight(struct call_queue *rq, struct member *member)
Definition: app_queue.c:4571
static struct ao2_container * pending_members
Definition: app_queue.c:2542
static int force_longest_waiting_caller
queues.conf [general] option
Definition: app_queue.c:1646
static void pending_members_remove(struct member *mem)
Definition: app_queue.c:2593
static int get_queue_member_status(struct member *cur)
Return the current state of a member.
Definition: app_queue.c:2879
static int use_weight
Records that one or more queues use weight.
Definition: app_queue.c:1622
static int member_status_available(int status)
Definition: app_queue.c:4672
#define ao2_link(container, obj)
Add an object to a container.
Definition: astobj2.h:1532
#define ao2_find(container, arg, flags)
Definition: astobj2.h:1736
@ OBJ_SEARCH_OBJECT
The arg parameter is an object of the same type.
Definition: astobj2.h:1087
@ OBJ_NOLOCK
Assume that the ao2_container is already locked.
Definition: astobj2.h:1063
static int call(void *data)
Definition: chan_pjsip.c:2394
int status
Definition: app_queue.c:1766
unsigned int ringinuse
Definition: app_queue.c:1780
struct call_queue * lastqueue
Definition: app_queue.c:1776
struct call_queue * parent
Definition: app_queue.c:1722

References ao2_find, ao2_link, ao2_lock, ao2_ref, ao2_unlock, ast_debug, call(), compare_weight(), force_longest_waiting_caller, get_queue_member_status(), get_wrapuptime(), is_longest_waiting_caller(), member::lastcall, member::lastqueue, member_status_available(), member::membername, call_queue::name, NULL, OBJ_NOLOCK, OBJ_SEARCH_OBJECT, queue_ent::parent, member::paused, pending_members, pending_members_remove(), member::ringinuse, member::status, use_weight, and member::wrapuptime.

Referenced by ring_entry().

◆ change_priority_caller_on_queue()

static int change_priority_caller_on_queue ( const char *  queuename,
const char *  caller,
int  priority,
int  immediate 
)
static

Change priority caller into a queue.

Return values
RES_NOSUCHQUEUEqueue does not exist
RES_OKAYchange priority
RES_NOT_CALLERqueue exists but no caller
Note
Ensure the appropriate realtime queue is loaded. Note that this short-circuits if the queue is already in memory.

Definition at line 7675 of file app_queue.c.

7676{
7677 struct call_queue *q;
7678 struct queue_ent *current, *prev = NULL, *caller_qe = NULL;
7679 int res = RES_NOSUCHQUEUE;
7680
7681 /*! \note Ensure the appropriate realtime queue is loaded. Note that this
7682 * short-circuits if the queue is already in memory. */
7683 if (!(q = find_load_queue_rt_friendly(queuename))) {
7684 return res;
7685 }
7686
7687 ao2_lock(q);
7688 res = RES_NOT_CALLER;
7689 for (current = q->head; current; current = current->next) {
7690 if (strcmp(ast_channel_name(current->chan), caller) == 0) {
7691 ast_debug(1, "%s Caller new priority %d in queue %s\n",
7692 caller, priority, queuename);
7693 current->prio = priority;
7694 if (immediate) {
7695 /* This caller is being immediately moved in the queue so remove them */
7696 if (prev) {
7697 prev->next = current->next;
7698 } else {
7699 q->head = current->next;
7700 }
7701 caller_qe = current;
7702 /* The position for all callers is not recalculated in here as it will
7703 * be updated when the moved caller is inserted back into the queue
7704 */
7705 }
7706 res = RES_OKAY;
7707 break;
7708 } else if (immediate) {
7709 prev = current;
7710 }
7711 }
7712
7713 if (caller_qe) {
7714 int inserted = 0, pos = 0;
7715
7716 /* If a caller queue entry exists, we are applying their priority immediately
7717 * and have to reinsert them at the correct position.
7718 */
7719 prev = NULL;
7720 current = q->head;
7721 while (current) {
7722 if (!inserted && (caller_qe->prio > current->prio)) {
7723 insert_entry(q, prev, caller_qe, &pos);
7724 inserted = 1;
7725 }
7726
7727 /* We always update the position as it may have changed */
7728 current->pos = ++pos;
7729
7730 /* Move to the next caller in the queue */
7731 prev = current;
7732 current = current->next;
7733 }
7734
7735 if (!inserted) {
7736 insert_entry(q, prev, caller_qe, &pos);
7737 }
7738 }
7739
7740 ao2_unlock(q);
7741 return res;
7742}
#define RES_NOT_CALLER
Definition: app_queue.c:1599
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'.
Definition: app_queue.c:2118
static int priority
size_t current
Definition: main/cli.c:113
struct queue_ent * head
Definition: app_queue.c:1917
struct queue_ent * next
Definition: app_queue.c:1752

References ao2_lock, ao2_unlock, ast_channel_name(), ast_debug, current, find_load_queue_rt_friendly(), call_queue::head, insert_entry(), queue_ent::next, NULL, queue_ent::pos, priority, RES_NOSUCHQUEUE, RES_NOT_CALLER, and RES_OKAY.

Referenced by handle_queue_change_priority_caller(), and manager_change_priority_caller_on_queue().

◆ clear_queue()

static void clear_queue ( struct call_queue q)
static

Definition at line 3080 of file app_queue.c.

3081{
3082 q->holdtime = 0;
3083 q->callscompleted = 0;
3084 q->callsabandoned = 0;
3085 q->callscompletedinsl = 0;
3086 q->callsabandonedinsl = 0;
3087 q->talktime = 0;
3088
3089 if (q->members) {
3090 struct member *mem;
3091 struct ao2_iterator mem_iter = ao2_iterator_init(q->members, 0);
3092 while ((mem = ao2_iterator_next(&mem_iter))) {
3093 mem->calls = 0;
3094 mem->callcompletedinsl = 0;
3095 mem->lastcall = 0;
3096 mem->starttime = 0;
3097 ao2_ref(mem, -1);
3098 }
3099 ao2_iterator_destroy(&mem_iter);
3100 }
3101}
#define ao2_iterator_next(iter)
Definition: astobj2.h:1911
int talktime
Definition: app_queue.c:1890
int callsabandoned
Definition: app_queue.c:1892
int callscompleted
Definition: app_queue.c:1891
int callsabandonedinsl
Definition: app_queue.c:1893
int callscompletedinsl
Definition: app_queue.c:1895
int holdtime
Definition: app_queue.c:1889
time_t starttime
Definition: app_queue.c:1772
int callcompletedinsl
Definition: app_queue.c:1770

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_ref, member::callcompletedinsl, member::calls, call_queue::callsabandoned, call_queue::callsabandonedinsl, call_queue::callscompleted, call_queue::callscompletedinsl, call_queue::holdtime, member::lastcall, call_queue::members, member::starttime, and call_queue::talktime.

Referenced by clear_stats(), and find_queue_by_name_rt().

◆ clear_stats()

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.

Parameters
queuenameThe 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
Return values
0always

Definition at line 10036 of file app_queue.c.

10037{
10038 struct call_queue *q;
10039 struct ao2_iterator queue_iter;
10040
10041 queue_iter = ao2_iterator_init(queues, 0);
10042 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
10043 ao2_lock(q);
10044 if (ast_strlen_zero(queuename) || !strcasecmp(q->name, queuename))
10045 clear_queue(q);
10046 ao2_unlock(q);
10047 queue_t_unref(q, "Done with iterator");
10048 }
10049 ao2_iterator_destroy(&queue_iter);
10050 return 0;
10051}
static void clear_queue(struct call_queue *q)
Definition: app_queue.c:3080

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_lock, ao2_t_iterator_next, ao2_unlock, ast_strlen_zero(), clear_queue(), call_queue::name, queue_t_unref, and queues.

Referenced by reload_handler().

◆ compare_weight()

static int compare_weight ( struct call_queue rq,
struct member member 
)
static

Definition at line 4571 of file app_queue.c.

4572{
4573 struct call_queue *q;
4574 struct member *mem;
4575 int found = 0;
4576 struct ao2_iterator queue_iter;
4577
4578 queue_iter = ao2_iterator_init(queues, 0);
4579 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
4580 if (q == rq) { /* don't check myself, could deadlock */
4581 queue_t_unref(q, "Done with iterator");
4582 continue;
4583 }
4584 ao2_lock(q);
4585 if (q->count && q->members) {
4586 if ((mem = ao2_find(q->members, member, OBJ_POINTER))) {
4587 ast_debug(1, "Found matching member %s in queue '%s'\n", mem->interface, q->name);
4588 if (q->weight > rq->weight && q->count >= num_available_members(q)) {
4589 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);
4590 found = 1;
4591 }
4592 ao2_ref(mem, -1);
4593 }
4594 }
4595 ao2_unlock(q);
4596 queue_t_unref(q, "Done with iterator");
4597 if (found) {
4598 break;
4599 }
4600 }
4601 ao2_iterator_destroy(&queue_iter);
4602 return found;
4603}
static int num_available_members(struct call_queue *q)
Get the number of members available to accept a call.
Definition: app_queue.c:4538
#define OBJ_POINTER
Definition: astobj2.h:1150

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 can_ring_entry().

◆ complete_queue()

static char * complete_queue ( const char *  line,
const char *  word,
int  pos,
int  state,
ptrdiff_t  word_list_offset 
)
static

Check if a given word is in a space-delimited list.

Parameters
lineThe line as typed not including the current word being completed
wordThe word currently being completed
posThe number of completed words in line
stateThe nth desired completion option
word_list_offsetOffset into the line where the list of queues begins. If non-zero, queues in the list will not be offered for further completion.
Returns
Returns the queue tab-completion for the given word and state

Definition at line 10372 of file app_queue.c.

10373{
10374 struct call_queue *q;
10375 char *ret = NULL;
10376 int which = 0;
10377 int wordlen = strlen(word);
10378 struct ao2_iterator queue_iter;
10379 const char *word_list = NULL;
10380
10381 /* for certain commands, already completed items should be left out of
10382 * the list */
10383 if (word_list_offset && strlen(line) >= word_list_offset) {
10384 word_list = line + word_list_offset;
10385 }
10386
10387 queue_iter = ao2_iterator_init(queues, 0);
10388 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
10389 if (!strncasecmp(word, q->name, wordlen) && ++which > state
10390 && (!word_list_offset || !word_in_list(word_list, q->name))) {
10391 ret = ast_strdup(q->name);
10392 queue_t_unref(q, "Done with iterator");
10393 break;
10394 }
10395 queue_t_unref(q, "Done with iterator");
10396 }
10397 ao2_iterator_destroy(&queue_iter);
10398
10399 /* Pretend "rules" is at the end of the queues list in certain
10400 * circumstances since it is an alternate command that should be
10401 * tab-completable for "queue show" */
10402 if (!ret && which == state && !wordlen && !strncmp("queue show", line, 10)) {
10403 ret = ast_strdup("rules");
10404 }
10405
10406 return ret;
10407}
static int word_in_list(const char *list, const char *word)
Check if a given word is in a space-delimited list.
Definition: app_queue.c:10313
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:241
short word

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_t_iterator_next, ast_strdup, call_queue::name, NULL, queue_t_unref, queues, and word_in_list().

Referenced by complete_queue_add_member(), complete_queue_pause_member(), complete_queue_remove_member(), complete_queue_set_member_value(), complete_queue_show(), handle_queue_reload(), and handle_queue_reset().

◆ complete_queue_add_member()

static char * complete_queue_add_member ( const char *  line,
const char *  word,
int  pos,
int  state 
)
static

Definition at line 10879 of file app_queue.c.

10880{
10881 /* 0 - queue; 1 - add; 2 - member; 3 - <interface>; 4 - to; 5 - <queue>; 6 - penalty; 7 - <penalty>; 8 - as; 9 - <membername> */
10882 switch (pos) {
10883 case 3: /* Don't attempt to complete name of interface (infinite possibilities) */
10884 return NULL;
10885 case 4: /* only one possible match, "to" */
10886 return state == 0 ? ast_strdup("to") : NULL;
10887 case 5: /* <queue> */
10888 return complete_queue(line, word, pos, state, 0);
10889 case 6: /* only one possible match, "penalty" */
10890 return state == 0 ? ast_strdup("penalty") : NULL;
10891 case 7:
10892 if (0 <= state && state < 100) { /* 0-99 */
10893 char *num;
10894 if ((num = ast_malloc(3))) {
10895 sprintf(num, "%d", state);
10896 }
10897 return num;
10898 } else {
10899 return NULL;
10900 }
10901 case 8: /* only one possible match, "as" */
10902 return state == 0 ? ast_strdup("as") : NULL;
10903 case 9: /* Don't attempt to complete name of member (infinite possibilities) */
10904 return NULL;
10905 default:
10906 return NULL;
10907 }
10908}
static char * complete_queue(const char *line, const char *word, int pos, int state, ptrdiff_t word_list_offset)
Check if a given word is in a space-delimited list.
Definition: app_queue.c:10372
#define ast_malloc(len)
A wrapper for malloc()
Definition: astmm.h:191

References ast_malloc, ast_strdup, complete_queue(), and NULL.

Referenced by handle_queue_add_member().

◆ complete_queue_pause_member()

static char * complete_queue_pause_member ( const char *  line,
const char *  word,
int  pos,
int  state 
)
static

Definition at line 11304 of file app_queue.c.

11305{
11306 /* 0 - queue; 1 - pause; 2 - member; 3 - <interface>; 4 - queue; 5 - <queue>; 6 - reason; 7 - <reason> */
11307 switch (pos) {
11308 case 3: /* Don't attempt to complete name of interface (infinite possibilities) */
11309 return NULL;
11310 case 4: /* only one possible match, "queue" */
11311 return state == 0 ? ast_strdup("queue") : NULL;
11312 case 5: /* <queue> */
11313 return complete_queue(line, word, pos, state, 0);
11314 case 6: /* "reason" */
11315 return state == 0 ? ast_strdup("reason") : NULL;
11316 case 7: /* Can't autocomplete a reason, since it's 100% customizeable */
11317 return NULL;
11318 default:
11319 return NULL;
11320 }
11321}

References ast_strdup, complete_queue(), and NULL.

Referenced by handle_queue_pause_member().

◆ complete_queue_remove_member()

static char * complete_queue_remove_member ( const char *  line,
const char *  word,
int  pos,
int  state 
)
static

Definition at line 11139 of file app_queue.c.

11140{
11141 int which = 0;
11142 struct call_queue *q;
11143 struct member *m;
11144 struct ao2_iterator queue_iter;
11145 struct ao2_iterator mem_iter;
11146 int wordlen = strlen(word);
11147
11148 /* 0 - queue; 1 - remove; 2 - member; 3 - <member>; 4 - from; 5 - <queue> */
11149 if (pos > 5 || pos < 3) {
11150 return NULL;
11151 }
11152 if (pos == 4) { /* only one possible match, 'from' */
11153 return (state == 0 ? ast_strdup("from") : NULL);
11154 }
11155
11156 if (pos == 5) { /* No need to duplicate code */
11157 return complete_queue(line, word, pos, state, 0);
11158 }
11159
11160 /* here is the case for 3, <member> */
11161 queue_iter = ao2_iterator_init(queues, 0);
11162 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
11163 ao2_lock(q);
11164 mem_iter = ao2_iterator_init(q->members, 0);
11165 while ((m = ao2_iterator_next(&mem_iter))) {
11166 if (!strncasecmp(word, m->membername, wordlen) && ++which > state) {
11167 char *tmp;
11168 tmp = ast_strdup(m->interface);
11169 ao2_ref(m, -1);
11170 ao2_iterator_destroy(&mem_iter);
11171 ao2_unlock(q);
11172 queue_t_unref(q, "Done with iterator, returning interface name");
11173 ao2_iterator_destroy(&queue_iter);
11174 return tmp;
11175 }
11176 ao2_ref(m, -1);
11177 }
11178 ao2_iterator_destroy(&mem_iter);
11179 ao2_unlock(q);
11180 queue_t_unref(q, "Done with iterator");
11181 }
11182 ao2_iterator_destroy(&queue_iter);
11183
11184 return NULL;
11185}

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, NULL, queue_t_unref, queues, and tmp().

Referenced by handle_queue_remove_member().

◆ complete_queue_rule_show()

static char * complete_queue_rule_show ( const char *  line,
const char *  word,
int  pos,
int  state 
)
static

Definition at line 11499 of file app_queue.c.

11500{
11501 int which = 0;
11502 struct rule_list *rl_iter;
11503 int wordlen = strlen(word);
11504 char *ret = NULL;
11505 if (pos != 3) /* Wha? */ {
11506 return NULL;
11507 }
11508
11510 AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) {
11511 if (!strncasecmp(word, rl_iter->name, wordlen) && ++which > state) {
11512 ret = ast_strdup(rl_iter->name);
11513 break;
11514 }
11515 }
11517
11518 return ret;
11519}
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:491
#define AST_LIST_LOCK(head)
Locks a list.
Definition: linkedlists.h:40
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
Definition: linkedlists.h:140
char name[80]
Definition: app_queue.c:1923
struct rule_list::@56 list

References AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_strdup, rule_list::list, rule_list::name, and NULL.

Referenced by handle_queue_rule_show().

◆ complete_queue_set_member_value()

static char * complete_queue_set_member_value ( const char *  line,
const char *  word,
int  pos,
int  state 
)
static

Definition at line 11378 of file app_queue.c.

11379{
11380 /* 0 - queue; 1 - set; 2 - penalty/ringinuse; 3 - <value>; 4 - on; 5 - <member>; 6 - in; 7 - <queue>;*/
11381 switch (pos) {
11382 case 4:
11383 if (state == 0) {
11384 return ast_strdup("on");
11385 } else {
11386 return NULL;
11387 }
11388 case 6:
11389 if (state == 0) {
11390 return ast_strdup("in");
11391 } else {
11392 return NULL;
11393 }
11394 case 7:
11395 return complete_queue(line, word, pos, state, 0);
11396 default:
11397 return NULL;
11398 }
11399}

References ast_strdup, complete_queue(), and NULL.

Referenced by handle_queue_set_member_penalty(), and handle_queue_set_member_ringinuse().

◆ complete_queue_show()

static char * complete_queue_show ( const char *  line,
const char *  word,
int  pos,
int  state 
)
static

Definition at line 10409 of file app_queue.c.

10410{
10411 if (pos == 2) {
10412 return complete_queue(line, word, pos, state, 0);
10413 }
10414 return NULL;
10415}

References complete_queue(), and NULL.

Referenced by queue_show().

◆ compress_char()

static int compress_char ( const char  c)
static

Definition at line 2939 of file app_queue.c.

2940{
2941 if (c < 32) {
2942 return 0;
2943 } else if (c > 96) {
2944 return c - 64;
2945 }
2946 return c - 32;
2947}
static struct test_val c

References c.

Referenced by member_hash_fn().

◆ context_included()

static int context_included ( const char *  parent,
const char *  child 
)
static

Returns if one context includes another context.

Parameters
parentParent context to search for child
childContext to check for inclusion in parent

This function recursively checks if the context child is included in the context parent.

Return values
1if child is included in parent
0if not

Definition at line 2806 of file app_queue.c.

2807{
2808 struct ast_context *c = NULL;
2809
2810 c = ast_context_find(parent);
2811 if (!c) {
2812 /* well, if parent doesn't exist, how can the child be included in it? */
2813 return 0;
2814 }
2815 if (!strcmp(ast_get_context_name(c), parent)) {
2816 /* found the context of the hint app_queue is using. Now, see
2817 if that context includes the one that just changed state */
2818 struct ast_include *inc = NULL;
2819
2820 while ((inc = (struct ast_include*) ast_walk_context_includes(c, inc))) {
2821 const char *includename = ast_get_include_name(inc);
2822 if (!strcasecmp(child, includename)) {
2823 return 1;
2824 }
2825 /* recurse on this context, for nested includes. The
2826 PBX extension parser will prevent infinite recursion. */
2827 if (context_included(includename, child)) {
2828 return 1;
2829 }
2830 }
2831 }
2832 return 0;
2833}
static int context_included(const char *parent, const char *child)
Returns if one context includes another context.
Definition: app_queue.c:2806
const struct ast_include * ast_walk_context_includes(const struct ast_context *con, const struct ast_include *inc)
Definition: pbx.c:8650
struct ast_context * ast_context_find(const char *name)
Find a context.
Definition: extconf.c:4172
const char * ast_get_include_name(const struct ast_include *include)
Definition: pbx_include.c:50
const char * ast_get_context_name(struct ast_context *con)
Definition: ael_main.c:421
ast_context: An extension context
Definition: pbx.c:284
ast_include: include= support in extensions.conf
Definition: pbx_include.c:37

References ast_context_find(), ast_get_context_name(), ast_get_include_name(), ast_walk_context_includes(), c, context_included(), and NULL.

Referenced by context_included(), and extension_state_cb().

◆ copy_rules()

static void copy_rules ( struct queue_ent qe,
const char *  rulename 
)
static

Copy rule from global list into specified queue.

Definition at line 8511 of file app_queue.c.

8512{
8513 struct penalty_rule *pr_iter;
8514 struct rule_list *rl_iter;
8515 const char *tmp = ast_strlen_zero(rulename) ? qe->parent->defaultrule : rulename;
8517 AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) {
8518 if (!strcasecmp(rl_iter->name, tmp)) {
8519 break;
8520 }
8521 }
8522 if (rl_iter) {
8523 AST_LIST_TRAVERSE(&rl_iter->rules, pr_iter, list) {
8524 struct penalty_rule *new_pr = ast_calloc(1, sizeof(*new_pr));
8525 if (!new_pr) {
8526 ast_log(LOG_ERROR, "Memory allocation error when copying penalty rules! Aborting!\n");
8527 break;
8528 }
8529 new_pr->time = pr_iter->time;
8530 new_pr->max_value = pr_iter->max_value;
8531 new_pr->min_value = pr_iter->min_value;
8532 new_pr->raise_value = pr_iter->raise_value;
8533 new_pr->max_relative = pr_iter->max_relative;
8534 new_pr->min_relative = pr_iter->min_relative;
8535 new_pr->raise_relative = pr_iter->raise_relative;
8536 AST_LIST_INSERT_TAIL(&qe->qe_rules, new_pr, list);
8537 }
8538 }
8540}
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:202
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Definition: linkedlists.h:731
const ast_string_field defaultrule
Definition: app_queue.c:1858
int raise_relative
Definition: app_queue.c:1811
struct penalty_rule::@52 list
int min_relative
Definition: app_queue.c:1810
int max_relative
Definition: app_queue.c:1809
struct queue_ent::@51 qe_rules
struct rule_list::@55 rules

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, penalty_rule::raise_relative, penalty_rule::raise_value, rule_list::rules, penalty_rule::time, and tmp().

Referenced by queue_exec().

◆ create_queue_member()

static struct member * create_queue_member ( const char *  interface,
const char *  membername,
int  penalty,
int  paused,
const char *  state_interface,
int  ringinuse,
int  wrapuptime 
)
static

allocate space for new queue member and set fields based on parameters passed

Definition at line 2894 of file app_queue.c.

2895{
2896 struct member *cur;
2897
2898 if ((cur = ao2_alloc(sizeof(*cur), destroy_queue_member_cb))) {
2899 cur->ringinuse = ringinuse;
2900 cur->penalty = penalty;
2901 cur->paused = paused;
2902 cur->wrapuptime = wrapuptime;
2903 if (paused) {
2904 time(&cur->lastpause); /* Update time of last pause */
2905 }
2906 time(&cur->logintime);
2907 ast_copy_string(cur->interface, interface, sizeof(cur->interface));
2910 } else {
2912 }
2914 ast_copy_string(cur->membername, membername, sizeof(cur->membername));
2915 } else {
2916 ast_copy_string(cur->membername, interface, sizeof(cur->membername));
2917 }
2918 if (!strchr(cur->interface, '/')) {
2919 ast_log(LOG_WARNING, "No location at interface '%s'\n", interface);
2920 }
2921 if (!strncmp(cur->state_interface, "hint:", 5)) {
2922 char *tmp = ast_strdupa(cur->state_interface), *context = tmp;
2923 char *exten = strsep(&context, "@") + 5;
2924
2925 ast_copy_string(cur->state_exten, exten, sizeof(cur->state_exten));
2926 ast_copy_string(cur->state_context, S_OR(context, "default"), sizeof(cur->state_context));
2927
2929 } else {
2930 cur->state_id = -1;
2931 }
2932 cur->status = get_queue_member_status(cur);
2933 }
2934
2935 return cur;
2936}
static int extension_state_cb(const char *context, const char *exten, struct ast_state_cb_info *info, void *data)
Definition: app_queue.c:2835
static void destroy_queue_member_cb(void *obj)
Definition: app_queue.c:2884
#define ao2_alloc(data_size, destructor_fn)
Definition: astobj2.h:409
char * strsep(char **str, const char *delims)
int ast_extension_state_add(const char *context, const char *exten, ast_state_cb_type change_cb, void *data)
Add watcher for extension states.
Definition: pbx.c:3823
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one.
Definition: strings.h:80
time_t logintime
Definition: app_queue.c:1775
char state_exten[AST_MAX_EXTENSION]
Definition: app_queue.c:1757
char state_context[AST_MAX_CONTEXT]
Definition: app_queue.c:1758
int state_id
Definition: app_queue.c:1760
time_t lastpause
Definition: app_queue.c:1774

References ao2_alloc, ast_copy_string(), ast_extension_state_add(), ast_log, ast_strdupa, ast_strlen_zero(), voicemailpwcheck::context, destroy_queue_member_cb(), extension_state_cb(), get_queue_member_status(), member::interface, member::lastpause, LOG_WARNING, member::logintime, member::membername, NULL, member::paused, member::penalty, member::ringinuse, S_OR, member::state_context, member::state_exten, member::state_id, member::state_interface, member::status, strsep(), tmp(), and member::wrapuptime.

Referenced by add_to_queue(), reload_single_member(), and rt_handle_member_record().

◆ destroy_queue()

static void destroy_queue ( void *  obj)
static

Free queue's member list then its string fields.

Definition at line 3741 of file app_queue.c.

3742{
3743 struct call_queue *q = obj;
3744 int i;
3745
3746 free_members(q, 1);
3748 for (i = 0; i < MAX_PERIODIC_ANNOUNCEMENTS; i++) {
3749 if (q->sound_periodicannounce[i]) {
3751 }
3752 }
3753 ao2_ref(q->members, -1);
3754}
#define MAX_PERIODIC_ANNOUNCEMENTS
Definition: app_queue.c:1585
static void free_members(struct call_queue *q, int all)
Iterate through queue's member list and delete them.
Definition: app_queue.c:3725
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
Definition: stringfields.h:374
struct ast_str * sound_periodicannounce[MAX_PERIODIC_ANNOUNCEMENTS]
Definition: app_queue.c:1860

References ao2_ref, ast_free, ast_string_field_free_memory, free_members(), MAX_PERIODIC_ANNOUNCEMENTS, call_queue::members, and call_queue::sound_periodicannounce.

Referenced by alloc_queue().

◆ destroy_queue_member_cb()

static void destroy_queue_member_cb ( void *  obj)
static

Definition at line 2884 of file app_queue.c.

2885{
2886 struct member *mem = obj;
2887
2888 if (mem->state_id != -1) {
2890 }
2891}
int ast_extension_state_del(int id, ast_state_cb_type change_cb)
Deletes a state change watcher by ID.
Definition: pbx.c:3856

References ast_extension_state_del(), extension_state_cb(), and member::state_id.

Referenced by create_queue_member().

◆ device_state_cb()

static void device_state_cb ( void *  unused,
struct stasis_subscription sub,
struct stasis_message msg 
)
static

set a member's status based on device state of that member's interface

Definition at line 2670 of file app_queue.c.

2671{
2672 struct ao2_iterator miter, qiter;
2673 struct ast_device_state_message *dev_state;
2674 struct member *m;
2675 struct call_queue *q;
2676 char interface[80], *slash_pos;
2677 int found = 0; /* Found this member in any queue */
2678 int found_member; /* Found this member in this queue */
2679 int avail = 0; /* Found an available member in this queue */
2680
2682 return;
2683 }
2684
2685 dev_state = stasis_message_data(msg);
2686 if (dev_state->eid) {
2687 /* ignore non-aggregate states */
2688 return;
2689 }
2690
2691 qiter = ao2_iterator_init(queues, 0);
2692 while ((q = ao2_t_iterator_next(&qiter, "Iterate over queues"))) {
2693 ao2_lock(q);
2694
2695 avail = 0;
2696 found_member = 0;
2697 miter = ao2_iterator_init(q->members, 0);
2698 for (; (m = ao2_iterator_next(&miter)); ao2_ref(m, -1)) {
2699 if (!found_member) {
2700 ast_copy_string(interface, m->state_interface, sizeof(interface));
2701
2702 if ((slash_pos = strchr(interface, '/'))) {
2703 if (!strncasecmp(interface, "Local/", 6) && (slash_pos = strchr(slash_pos + 1, '/'))) {
2704 *slash_pos = '\0';
2705 }
2706 }
2707
2708 if (!strcasecmp(interface, dev_state->device)) {
2709 found_member = 1;
2710 update_status(q, m, dev_state->state);
2711 }
2712 }
2713
2714 /* check every member until we find one NOT_INUSE */
2715 if (!avail) {
2716 avail = is_member_available(q, m);
2717 }
2718 if (avail && found_member) {
2719 /* early exit as we've found an available member and the member of interest */
2720 ao2_ref(m, -1);
2721 break;
2722 }
2723 }
2724
2725 if (found_member) {
2726 found = 1;
2727 if (avail) {
2729 } else {
2731 }
2732 }
2733
2734 ao2_iterator_destroy(&miter);
2735
2736 ao2_unlock(q);
2737 queue_t_unref(q, "Done with iterator");
2738 }
2739 ao2_iterator_destroy(&qiter);
2740
2741 if (found) {
2742 ast_debug(1, "Device '%s' changed to state '%u' (%s)\n",
2743 dev_state->device,
2744 dev_state->state,
2745 ast_devstate2str(dev_state->state));
2746 } else {
2747 ast_debug(3, "Device '%s' changed to state '%u' (%s) but we don't care because they're not a member of any queue.\n",
2748 dev_state->device,
2749 dev_state->state,
2750 ast_devstate2str(dev_state->state));
2751 }
2752
2753 return;
2754}
static void 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.
Definition: app_queue.c:2604
struct stasis_message_type * ast_device_state_message_type(void)
Get the Stasis message type for device state messages.
const char * ast_devstate2str(enum ast_device_state devstate) attribute_pure
Convert device state to text string for output.
Definition: devicestate.c:237
@ AST_DEVICE_INUSE
Definition: devicestate.h:55
struct stasis_message_type * stasis_message_type(const struct stasis_message *msg)
Get the message type for a stasis_message.
void * stasis_message_data(const struct stasis_message *msg)
Get the data contained in a message.
The structure that contains device state.
Definition: devicestate.h:238
enum ast_device_state state
Definition: devicestate.h:248
const struct ast_eid * eid
The EID of the server where this message originated.
Definition: devicestate.h:246

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_DEVICE_INUSE, AST_DEVICE_NOT_INUSE, ast_device_state_message_type(), ast_devstate2str(), AST_DEVSTATE_CACHABLE, ast_devstate_changed(), ast_device_state_message::device, ast_device_state_message::eid, call_queue::found, is_member_available(), call_queue::members, call_queue::name, queue_t_unref, queues, stasis_message_data(), stasis_message_type(), ast_device_state_message::state, member::state_interface, and update_status().

Referenced by load_module().

◆ do_hang()

static void do_hang ( struct callattempt o)
static

common hangup actions

Definition at line 4656 of file app_queue.c.

4657{
4658 o->stillgoing = 0;
4659 ast_hangup(o->chan);
4661 o->chan = NULL;
4662}
void ast_hangup(struct ast_channel *chan)
Hang up a channel.
Definition: channel.c:2560
struct ast_channel * chan
Definition: app_queue.c:1701
unsigned int stillgoing
Definition: app_queue.c:1714

References ast_hangup(), callattempt::chan, callattempt::member, NULL, pending_members_remove(), and callattempt::stillgoing.

Referenced by ring_entry(), and wait_for_answer().

◆ do_print()

static void do_print ( struct mansession s,
int  fd,
const char *  str 
)
static

direct output to manager or cli with proper terminator

Definition at line 10083 of file app_queue.c.

10084{
10085 if (s) {
10086 astman_append(s, "%s\r\n", str);
10087 } else {
10088 ast_cli(fd, "%s\n", str);
10089 }
10090}
const char * str
Definition: app_jack.c:147
void ast_cli(int fd, const char *fmt,...)
Definition: clicompat.c:6
void astman_append(struct mansession *s, const char *fmt,...)
Definition: manager.c:1890

References ast_cli(), astman_append(), and str.

Referenced by __queues_show(), and print_queue().

◆ dump_queue_members()

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>[|...]
static const char *const pm_family
Persistent Members astdb family.
Definition: app_queue.c:1616

Definition at line 7514 of file app_queue.c.

7515{
7516 struct member *cur_member;
7517 struct ast_str *value;
7518 struct ao2_iterator mem_iter;
7519
7520 if (!pm_queue) {
7521 return;
7522 }
7523
7524 /* 4K is a reasonable default for most applications, but we grow to
7525 * accommodate more if necessary. */
7526 if (!(value = ast_str_create(4096))) {
7527 return;
7528 }
7529
7530 mem_iter = ao2_iterator_init(pm_queue->members, 0);
7531 while ((cur_member = ao2_iterator_next(&mem_iter))) {
7532 if (!cur_member->dynamic) {
7533 ao2_ref(cur_member, -1);
7534 continue;
7535 }
7536
7537 ast_str_append(&value, 0, "%s%s;%d;%d;%s;%s;%s;%d",
7538 ast_str_strlen(value) ? "|" : "",
7539 cur_member->interface,
7540 cur_member->penalty,
7541 cur_member->paused,
7542 cur_member->membername,
7543 cur_member->state_interface,
7544 cur_member->reason_paused,
7545 cur_member->wrapuptime);
7546
7547 ao2_ref(cur_member, -1);
7548 }
7549 ao2_iterator_destroy(&mem_iter);
7550
7551 if (ast_str_strlen(value) && !cur_member) {
7552 if (ast_db_put(pm_family, pm_queue->name, ast_str_buffer(value))) {
7553 ast_log(LOG_WARNING, "failed to create persistent dynamic entry!\n");
7554 }
7555 } else {
7556 /* Delete the entry if the queue is empty or there is an error */
7557 ast_db_del(pm_family, pm_queue->name);
7558 }
7559
7560 ast_free(value);
7561}
int ast_db_put(const char *family, const char *key, const char *value)
Store value addressed by family/key.
Definition: main/db.c:341
int ast_db_del(const char *family, const char *key)
Delete entry in astdb.
Definition: main/db.c:478
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
Definition: strings.h:1139
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
Definition: strings.h:659
size_t ast_str_strlen(const struct ast_str *buf)
Returns the current length of the string stored within buf.
Definition: strings.h:730
int value
Definition: syslog.c:37

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_ref, ast_db_del(), ast_db_put(), ast_free, ast_log, ast_str_append(), ast_str_buffer(), ast_str_create, ast_str_strlen(), member::dynamic, member::interface, LOG_WARNING, member::membername, call_queue::members, call_queue::name, member::paused, member::penalty, pm_family, member::reason_paused, member::state_interface, value, and member::wrapuptime.

Referenced by add_to_queue(), remove_from_queue(), and set_queue_member_pause().

◆ end_bridge_callback()

static void end_bridge_callback ( void *  data)
static

Definition at line 6863 of file app_queue.c.

6864{
6865 struct queue_end_bridge *qeb = data;
6866 struct call_queue *q = qeb->q;
6867 struct ast_channel *chan = qeb->chan;
6868
6869 if (ao2_ref(qeb, -1) == 1) {
6870 set_queue_variables(q, chan);
6871 /* This unrefs the reference we made in try_calling when we allocated qeb */
6872 queue_t_unref(q, "Expire bridge_config reference");
6873 }
6874}
static void set_queue_variables(struct call_queue *q, struct ast_channel *chan)
Set variables of queue.
Definition: app_queue.c:2092
Main Channel structure associated with a channel.
struct call_queue * q
Definition: app_queue.c:6852
struct ast_channel * chan
Definition: app_queue.c:6853

References ao2_ref, queue_end_bridge::chan, queue_end_bridge::q, queue_t_unref, and set_queue_variables().

Referenced by try_calling().

◆ end_bridge_callback_data_fixup()

static void end_bridge_callback_data_fixup ( struct ast_bridge_config bconfig,
struct ast_channel originator,
struct ast_channel terminator 
)
static

Definition at line 6856 of file app_queue.c.

6857{
6858 struct queue_end_bridge *qeb = bconfig->end_bridge_callback_data;
6859 ao2_ref(qeb, +1);
6860 qeb->chan = originator;
6861}
void * end_bridge_callback_data
Definition: channel.h:1111

References ao2_ref, queue_end_bridge::chan, and ast_bridge_config::end_bridge_callback_data.

Referenced by try_calling().

◆ escape_and_substitute()

static void escape_and_substitute ( struct ast_channel chan,
const char *  input,
char *  output,
size_t  size 
)
static

Definition at line 6903 of file app_queue.c.

6905{
6906 const char *m = input;
6907 char escaped[size];
6908 char *p;
6909
6910 for (p = escaped; p < escaped + size - 1; p++, m++) {
6911 switch (*m) {
6912 case '^':
6913 if (*(m + 1) == '{') {
6914 *p = '$';
6915 }
6916 break;
6917 case ',':
6918 *p++ = '\\';
6919 /* Fall through */
6920 default:
6921 *p = *m;
6922 }
6923 if (*m == '\0')
6924 break;
6925 }
6926
6927 if (p == escaped + size) {
6928 escaped[size - 1] = '\0';
6929 }
6930
6931 pbx_substitute_variables_helper(chan, escaped, output, size - 1);
6932}
static int input(yyscan_t yyscanner)
Definition: ast_expr2f.c:1570
void pbx_substitute_variables_helper(struct ast_channel *c, const char *cp1, char *cp2, int count)
Definition: ael_main.c:211

References input(), and pbx_substitute_variables_helper().

Referenced by setup_mixmonitor().

◆ extension_state_cb()

static int extension_state_cb ( const char *  context,
const char *  exten,
struct ast_state_cb_info info,
void *  data 
)
static

Definition at line 2835 of file app_queue.c.

2836{
2837 struct ao2_iterator miter, qiter;
2838 struct member *m;
2839 struct call_queue *q;
2840 int state = info->exten_state;
2841 int found = 0, device_state = extensionstate2devicestate(state);
2842
2843 /* only interested in extension state updates involving device states */
2844 if (info->reason != AST_HINT_UPDATE_DEVICE) {
2845 return 0;
2846 }
2847
2848 qiter = ao2_iterator_init(queues, 0);
2849 while ((q = ao2_t_iterator_next(&qiter, "Iterate through queues"))) {
2850 ao2_lock(q);
2851
2852 miter = ao2_iterator_init(q->members, 0);
2853 for (; (m = ao2_iterator_next(&miter)); ao2_ref(m, -1)) {
2854 if (!strcmp(m->state_exten, exten) &&
2856 /* context could be included in m->state_context. We need to check. */
2857 found = 1;
2858 update_status(q, m, device_state);
2859 }
2860 }
2861 ao2_iterator_destroy(&miter);
2862
2863 ao2_unlock(q);
2864 queue_t_unref(q, "Done with iterator");
2865 }
2866 ao2_iterator_destroy(&qiter);
2867
2868 if (found) {
2869 ast_debug(1, "Extension '%s@%s' changed to state '%d' (%s)\n", exten, context, device_state, ast_devstate2str(device_state));
2870 } else {
2871 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",
2872 exten, context, device_state, ast_devstate2str(device_state));
2873 }
2874
2875 return 0;
2876}
static int extensionstate2devicestate(int state)
Helper function which converts from extension state to device state values.
Definition: app_queue.c:2757
def info(msg)
@ AST_HINT_UPDATE_DEVICE
Definition: pbx.h:91

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_lock, ao2_ref, ao2_t_iterator_next, ao2_unlock, ast_debug, ast_devstate2str(), AST_HINT_UPDATE_DEVICE, voicemailpwcheck::context, context_included(), extensionstate2devicestate(), call_queue::found, sip_to_pjsip::info(), call_queue::members, queue_t_unref, queues, member::state_context, member::state_exten, and update_status().

Referenced by create_queue_member(), and destroy_queue_member_cb().

◆ extensionstate2devicestate()

static int extensionstate2devicestate ( int  state)
static

Helper function which converts from extension state to device state values.

Definition at line 2757 of file app_queue.c.

2758{
2759 switch (state) {
2762 break;
2765 break;
2766 case AST_EXTENSION_BUSY:
2768 break;
2771 break;
2774 break;
2777 break;
2780 break;
2783 break;
2786 default:
2788 break;
2789 }
2790
2791 return state;
2792}
enum cc_state state
Definition: ccss.c:393
@ AST_DEVICE_RINGINUSE
Definition: devicestate.h:60
@ AST_DEVICE_ONHOLD
Definition: devicestate.h:61
@ AST_DEVICE_RINGING
Definition: devicestate.h:59
@ AST_DEVICE_INVALID
Definition: devicestate.h:57
@ AST_DEVICE_BUSY
Definition: devicestate.h:56
@ AST_DEVICE_UNAVAILABLE
Definition: devicestate.h:58
@ AST_EXTENSION_REMOVED
Definition: pbx.h:62
@ AST_EXTENSION_RINGING
Definition: pbx.h:68
@ AST_EXTENSION_NOT_INUSE
Definition: pbx.h:64
@ AST_EXTENSION_INUSE
Definition: pbx.h:65
@ AST_EXTENSION_UNAVAILABLE
Definition: pbx.h:67
@ AST_EXTENSION_ONHOLD
Definition: pbx.h:69
@ AST_EXTENSION_BUSY
Definition: pbx.h:66
@ AST_EXTENSION_DEACTIVATED
Definition: pbx.h:63

References AST_DEVICE_BUSY, AST_DEVICE_INUSE, AST_DEVICE_INVALID, AST_DEVICE_NOT_INUSE, AST_DEVICE_ONHOLD, AST_DEVICE_RINGING, AST_DEVICE_RINGINUSE, 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, AST_EXTENSION_UNAVAILABLE, and state.

Referenced by extension_state_cb(), and get_queue_member_status().

◆ find_best()

static struct callattempt * find_best ( struct callattempt outgoing)
static

find the entry with the best metric, or NULL

Definition at line 4914 of file app_queue.c.

4915{
4916 struct callattempt *best = NULL, *cur;
4917
4918 for (cur = outgoing; cur; cur = cur->q_next) {
4919 if (cur->stillgoing && /* Not already done */
4920 !cur->chan && /* Isn't already going */
4921 (!best || cur->metric < best->metric)) { /* We haven't found one yet, or it's better */
4922 best = cur;
4923 }
4924 }
4925
4926 return best;
4927}
We define a custom "local user" structure because we use it not only for keeping track of what is in ...
Definition: app_queue.c:1698

References callattempt::metric, and NULL.

Referenced by ring_one(), store_next_lin(), and store_next_rr().

◆ find_load_queue_rt_friendly()

static struct call_queue * find_load_queue_rt_friendly ( const char *  queuename)
static

note

Note
Load from realtime before taking the "queues" container lock, to avoid blocking all queue operations while waiting for the DB.

This will be two separate database transactions, so we might see queue parameters as they were before another process changed the queue and member list as it was after the change. Thus we might see an empty member list when a queue is deleted. In practise, this is unlikely to cause a problem.

Definition at line 3924 of file app_queue.c.

3925{
3926 struct ast_variable *queue_vars;
3927 struct ast_config *member_config = NULL;
3928 struct call_queue *q = NULL, tmpq = {
3929 .name = queuename,
3930 };
3931 int prev_weight = 0;
3932
3933 /* Find the queue in the in-core list first. */
3934 q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Look for queue in memory first");
3935
3936 if (!q || q->realtime) {
3937 /*! \note Load from realtime before taking the "queues" container lock, to avoid blocking all
3938 queue operations while waiting for the DB.
3939
3940 This will be two separate database transactions, so we might
3941 see queue parameters as they were before another process
3942 changed the queue and member list as it was after the change.
3943 Thus we might see an empty member list when a queue is
3944 deleted. In practise, this is unlikely to cause a problem. */
3945
3946 queue_vars = ast_load_realtime("queues", "name", queuename, SENTINEL);
3947 if (queue_vars) {
3948 member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name", queuename, SENTINEL);
3949 if (!member_config) {
3950 ast_debug(1, "No queue_members defined in config extconfig.conf\n");
3951 member_config = ast_config_new();
3952 }
3953 }
3954 if (q) {
3955 prev_weight = q->weight ? 1 : 0;
3956 queue_t_unref(q, "Need to find realtime queue");
3957 }
3958
3959 q = find_queue_by_name_rt(queuename, queue_vars, member_config);
3960 ast_config_destroy(member_config);
3961 ast_variables_destroy(queue_vars);
3962
3963 /* update the use_weight value if the queue's has gained or lost a weight */
3964 if (q) {
3965 if (!q->weight && prev_weight) {
3967 }
3968 if (q->weight && !prev_weight) {
3970 }
3971 }
3972 /* Other cases will end up with the proper value for use_weight */
3973 } else {
3975 }
3976 return q;
3977}
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.
Definition: app_queue.c:3780
static void update_realtime_members(struct call_queue *q)
Definition: app_queue.c:4029
#define ao2_t_find(container, arg, flags, tag)
Definition: astobj2.h:1734
struct ast_config * ast_config_new(void)
Create a new base configuration structure.
Definition: extconf.c:3274
struct ast_variable * ast_load_realtime(const char *family,...) attribute_sentinel
Definition: main/config.c:3521
void ast_variables_destroy(struct ast_variable *var)
Free variable list.
Definition: extconf.c:1262
int ast_atomic_fetchadd_int(volatile int *p, int v)
Atomically add v to *p and return the previous value of *p.
Definition: lock.h:757
Structure for variables, used for configurations and for channel variables.

References ao2_t_find, ast_atomic_fetchadd_int(), ast_config_destroy(), ast_config_new(), ast_debug, ast_load_realtime(), ast_load_realtime_multientry(), ast_variables_destroy(), find_queue_by_name_rt(), NULL, OBJ_POINTER, queue_t_unref, queues, call_queue::realtime, SENTINEL, update_realtime_members(), use_weight, and call_queue::weight.

Referenced by __queues_show(), add_to_queue(), change_priority_caller_on_queue(), find_member_by_queuename_and_interface(), get_member_penalty(), join_queue(), load_realtime_queues(), queue_function_exists(), queue_function_mem_read(), queue_function_qac_dep(), queue_function_queuememberlist(), queue_function_var(), qupd_exec(), reload_queue_members(), request_withdraw_caller_from_queue(), and set_member_value().

◆ find_member_by_queuename_and_interface()

static struct member * find_member_by_queuename_and_interface ( const char *  queuename,
const char *  interface 
)
static

Find a member by looking up queuename and interface.

Returns
member or NULL if member not found.

Definition at line 11998 of file app_queue.c.

11999{
12000 struct member *mem = NULL;
12001 struct call_queue *q;
12002
12003 if ((q = find_load_queue_rt_friendly(queuename))) {
12004 ao2_lock(q);
12005 mem = ao2_find(q->members, interface, OBJ_KEY);
12006 ao2_unlock(q);
12007 queue_t_unref(q, "Expiring temporary reference.");
12008 }
12009 return mem;
12010}
#define OBJ_KEY
Definition: astobj2.h:1151

References ao2_find, ao2_lock, ao2_unlock, find_load_queue_rt_friendly(), call_queue::members, NULL, OBJ_KEY, and queue_t_unref.

Referenced by handle_queue_remove_member(), manager_remove_queue_member(), and rqm_exec().

◆ find_queue_by_name_rt()

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.

Return values
thequeue,
NULLif it doesn't exist.
Note
Should be called with the "queues" container locked.
Note
Hmm, can't seem to distinguish a DB failure from a not found condition... So we might delete an in-core queue in case of DB failure.

Definition at line 3780 of file app_queue.c.

3781{
3782 struct ast_variable *v;
3783 struct call_queue *q, tmpq = {
3784 .name = queuename,
3785 };
3786 struct member *m;
3787 struct ao2_iterator mem_iter;
3788 char *category = NULL;
3789 const char *tmp_name;
3790 char *tmp;
3791 char tmpbuf[64]; /* Must be longer than the longest queue param name. */
3792
3793 /* Static queues override realtime. */
3794 if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Check if static queue exists"))) {
3795 ao2_lock(q);
3796 if (!q->realtime) {
3797 if (q->dead) {
3798 ao2_unlock(q);
3799 queue_t_unref(q, "Queue is dead; can't return it");
3800 return NULL;
3801 }
3802 ast_log(LOG_WARNING, "Static queue '%s' already exists. Not loading from realtime\n", q->name);
3803 ao2_unlock(q);
3804 return q;
3805 }
3806 } else if (!member_config) {
3807 /* Not found in the list, and it's not realtime ... */
3808 return NULL;
3809 }
3810 /* Check if queue is defined in realtime. */
3811 if (!queue_vars) {
3812 /* Delete queue from in-core list if it has been deleted in realtime. */
3813 if (q) {
3814 /*! \note Hmm, can't seem to distinguish a DB failure from a not
3815 found condition... So we might delete an in-core queue
3816 in case of DB failure. */
3817 ast_debug(1, "Queue %s not found in realtime.\n", queuename);
3818
3819 q->dead = 1;
3820 /* Delete if unused (else will be deleted when last caller leaves). */
3821 queues_t_unlink(queues, q, "Unused; removing from container");
3822 ao2_unlock(q);
3823 queue_t_unref(q, "Queue is dead; can't return it");
3824 }
3825 return NULL;
3826 }
3827
3828 /* Create a new queue if an in-core entry does not exist yet. */
3829 if (!q) {
3830 struct ast_variable *tmpvar = NULL;
3831 if (!(q = alloc_queue(queuename))) {
3832 return NULL;
3833 }
3834 ao2_lock(q);
3835 clear_queue(q);
3836 q->realtime = 1;
3837 /*Before we initialize the queue, we need to set the strategy, so that linear strategy
3838 * will allocate the members properly
3839 */
3840 for (tmpvar = queue_vars; tmpvar; tmpvar = tmpvar->next) {
3841 if (!strcasecmp(tmpvar->name, "strategy")) {
3842 q->strategy = strat2int(tmpvar->value);
3843 if (q->strategy < 0) {
3844 ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n",
3845 tmpvar->value, q->name);
3847 }
3848 break;
3849 }
3850 }
3851 /* We traversed all variables and didn't find a strategy */
3852 if (!tmpvar) {
3854 }
3855 queues_t_link(queues, q, "Add queue to container");
3856 }
3857 init_queue(q); /* Ensure defaults for all parameters not set explicitly. */
3858
3859 memset(tmpbuf, 0, sizeof(tmpbuf));
3860 for (v = queue_vars; v; v = v->next) {
3861 /* Convert to dashes `-' from underscores `_' as the latter are more SQL friendly. */
3862 if (strchr(v->name, '_')) {
3863 ast_copy_string(tmpbuf, v->name, sizeof(tmpbuf));
3864 tmp_name = tmpbuf;
3865 tmp = tmpbuf;
3866 while ((tmp = strchr(tmp, '_'))) {
3867 *tmp++ = '-';
3868 }
3869 } else {
3870 tmp_name = v->name;
3871 }
3872
3873 /* NULL values don't get returned from realtime; blank values should
3874 * still get set. If someone doesn't want a value to be set, they
3875 * should set the realtime column to NULL, not blank. */
3876 queue_set_param(q, tmp_name, v->value, -1, 0);
3877 }
3878
3879 /* Temporarily set realtime members dead so we can detect deleted ones. */
3880 mem_iter = ao2_iterator_init(q->members, 0);
3881 while ((m = ao2_iterator_next(&mem_iter))) {
3882 if (m->realtime) {
3883 m->dead = 1;
3884 }
3885 ao2_ref(m, -1);
3886 }
3887 ao2_iterator_destroy(&mem_iter);
3888
3889 while ((category = ast_category_browse(member_config, category))) {
3890 rt_handle_member_record(q, category, member_config);
3891 }
3892
3893 /* Delete all realtime members that have been deleted in DB. */
3894 mem_iter = ao2_iterator_init(q->members, 0);
3895 while ((m = ao2_iterator_next(&mem_iter))) {
3896 if (m->dead) {
3898 ast_queue_log(q->name, "REALTIME", m->interface, "REMOVEMEMBER", "%s", "");
3899 } else {
3900 ast_queue_log(q->name, "REALTIME", m->membername, "REMOVEMEMBER", "%s", "");
3901 }
3903 }
3904 ao2_ref(m, -1);
3905 }
3906 ao2_iterator_destroy(&mem_iter);
3907
3908 ao2_unlock(q);
3909
3910 return q;
3911}
static void member_remove_from_queue(struct call_queue *queue, struct member *mem)
Definition: app_queue.c:3591
static void rt_handle_member_record(struct call_queue *q, char *category, struct ast_config *member_config)
Find rt member record to update otherwise create one.
Definition: app_queue.c:3607
#define queues_t_unlink(c, q, tag)
Definition: app_queue.c:2089
#define queues_t_link(c, q, tag)
Definition: app_queue.c:2088
static void queue_set_param(struct call_queue *q, const char *param, const char *val, int linenum, int failunknown)
Configure a queue parameter.
Definition: app_queue.c:3361
static void init_queue(struct call_queue *q)
Initialize Queue default values.
Definition: app_queue.c:2978
static struct call_queue * alloc_queue(const char *queuename)
Definition: app_queue.c:3756
static int strat2int(const char *strategy)
Definition: app_queue.c:1964
struct ast_variable * next
unsigned int dead
Definition: app_queue.c:1861
unsigned int dead
Definition: app_queue.c:1777
int realtime
Definition: app_queue.c:1765

References alloc_queue(), ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_lock, ao2_ref, ao2_t_find, ao2_unlock, ast_category_browse(), ast_copy_string(), ast_debug, ast_log, ast_queue_log(), ast_strlen_zero(), clear_queue(), member::dead, call_queue::dead, init_queue(), member::interface, log_membername_as_agent, LOG_WARNING, member_remove_from_queue(), member::membername, call_queue::members, call_queue::name, ast_variable::name, ast_variable::next, NULL, OBJ_POINTER, queue_set_param(), QUEUE_STRATEGY_RINGALL, queue_t_unref, queues, queues_t_link, queues_t_unlink, member::realtime, call_queue::realtime, rt_handle_member_record(), strat2int(), call_queue::strategy, tmp(), and ast_variable::value.

Referenced by find_load_queue_rt_friendly().

◆ free_members()

static void free_members ( struct call_queue q,
int  all 
)
static

Iterate through queue's member list and delete them.

Definition at line 3725 of file app_queue.c.

3726{
3727 /* Free non-dynamic members */
3728 struct member *cur;
3729 struct ao2_iterator mem_iter = ao2_iterator_init(q->members, 0);
3730
3731 while ((cur = ao2_iterator_next(&mem_iter))) {
3732 if (all || !cur->dynamic) {
3734 }
3735 ao2_ref(cur, -1);
3736 }
3737 ao2_iterator_destroy(&mem_iter);
3738}

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_ref, member::dynamic, member_remove_from_queue(), and call_queue::members.

Referenced by destroy_queue().

◆ get_interface_helper()

static struct member * get_interface_helper ( struct call_queue q,
const char *  interface 
)
static

Definition at line 9029 of file app_queue.c.

9030{
9031 struct member *m;
9032
9034 ast_log(LOG_ERROR, "QUEUE_MEMBER: Missing required interface argument.\n");
9035 return NULL;
9036 }
9037
9039 if (!m) {
9040 ast_log(LOG_ERROR, "Queue member interface '%s' not in queue '%s'.\n",
9041 interface, q->name);
9042 }
9043 return m;
9044}

References ast_log, ast_strlen_zero(), member::interface, interface_exists(), LOG_ERROR, call_queue::name, and NULL.

Referenced by queue_function_mem_read().

◆ get_member_penalty()

static int get_member_penalty ( char *  queuename,
char *  interface 
)
static

Gets members penalty.

Returns
Return the members penalty or RESULT_FAILURE on error.

Definition at line 8098 of file app_queue.c.

8099{
8100 int foundqueue = 0, penalty;
8101 struct call_queue *q;
8102 struct member *mem;
8103
8104 if ((q = find_load_queue_rt_friendly(queuename))) {
8105 foundqueue = 1;
8106 ao2_lock(q);
8107 if ((mem = interface_exists(q, interface))) {
8108 penalty = mem->penalty;
8109 ao2_ref(mem, -1);
8110 ao2_unlock(q);
8111 queue_t_unref(q, "Search complete");
8112 return penalty;
8113 }
8114 ao2_unlock(q);
8115 queue_t_unref(q, "Search complete");
8116 }
8117
8118 /* some useful debugging */
8119 if (foundqueue) {
8120 ast_log (LOG_ERROR, "Invalid queuename\n");
8121 } else {
8122 ast_log (LOG_ERROR, "Invalid interface\n");
8123 }
8124
8125 return RESULT_FAILURE;
8126}
#define RESULT_FAILURE
Definition: cli.h:42

References ao2_lock, ao2_ref, ao2_unlock, ast_log, find_load_queue_rt_friendly(), member::interface, interface_exists(), LOG_ERROR, member::penalty, queue_t_unref, and RESULT_FAILURE.

Referenced by queue_function_memberpenalty_read().

◆ get_member_status()

static int get_member_status ( struct call_queue q,
int  max_penalty,
int  min_penalty,
int  raise_penalty,
enum empty_conditions  conditions,
int  devstate 
)
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 2451 of file app_queue.c.

2452{
2453 struct member *member;
2454 struct ao2_iterator mem_iter;
2455
2456 ao2_lock(q);
2457 mem_iter = ao2_iterator_init(q->members, 0);
2458 for (; (member = ao2_iterator_next(&mem_iter)); ao2_ref(member, -1)) {
2459 int penalty = member->penalty;
2460 if (raise_penalty != INT_MAX && penalty < raise_penalty) {
2461 ast_debug(4, "%s is having his penalty raised up from %d to %d\n", member->membername, penalty, raise_penalty);
2462 penalty = raise_penalty;
2463 }
2464 if ((max_penalty != INT_MAX && penalty > max_penalty) || (min_penalty != INT_MAX && penalty < min_penalty)) {
2465 if (conditions & QUEUE_EMPTY_PENALTY) {
2466 ast_debug(4, "%s is unavailable because his penalty is not between %d and %d\n", member->membername, min_penalty, max_penalty);
2467 continue;
2468 }
2469 }
2470
2471 switch (devstate ? ast_device_state(member->state_interface) : member->status) {
2472 case AST_DEVICE_INVALID:
2473 if (conditions & QUEUE_EMPTY_INVALID) {
2474 ast_debug(4, "%s is unavailable because his device state is 'invalid'\n", member->membername);
2475 break;
2476 }
2477 goto default_case;
2479 if (conditions & QUEUE_EMPTY_UNAVAILABLE) {
2480 ast_debug(4, "%s is unavailable because his device state is 'unavailable'\n", member->membername);
2481 break;
2482 }
2483 goto default_case;
2484 case AST_DEVICE_INUSE:
2485 if (conditions & QUEUE_EMPTY_INUSE) {
2486 ast_debug(4, "%s is unavailable because his device state is 'inuse'\n", member->membername);
2487 break;
2488 }
2489 goto default_case;
2490 case AST_DEVICE_RINGING:
2491 if (conditions & QUEUE_EMPTY_RINGING) {
2492 ast_debug(4, "%s is unavailable because his device state is 'ringing'\n", member->membername);
2493 break;
2494 }
2495 goto default_case;
2496 case AST_DEVICE_UNKNOWN:
2497 if (conditions & QUEUE_EMPTY_UNKNOWN) {
2498 ast_debug(4, "%s is unavailable because his device state is 'unknown'\n", member->membername);
2499 break;
2500 }
2501 /* Fall-through */
2502 default:
2503 default_case:
2504 if (member->paused && (conditions & QUEUE_EMPTY_PAUSED)) {
2505 ast_debug(4, "%s is unavailable because he is paused'\n", member->membername);
2506 break;
2507 } else if ((conditions & QUEUE_EMPTY_WRAPUP)
2508 && member->lastcall
2509 && get_wrapuptime(q, member)
2510 && (time(NULL) - get_wrapuptime(q, member) < member->lastcall)) {
2511 ast_debug(4, "%s is unavailable because it has only been %d seconds since his last call (wrapup time is %d)\n",
2512 member->membername, (int) (time(NULL) - member->lastcall), get_wrapuptime(q, member));
2513 break;
2514 } else {
2515 ao2_ref(member, -1);
2516 ao2_iterator_destroy(&mem_iter);
2517 ao2_unlock(q);
2518 ast_debug(4, "%s is available.\n", member->membername);
2519 return 0;
2520 }
2521 break;
2522 }
2523 }
2524 ao2_iterator_destroy(&mem_iter);
2525 ao2_unlock(q);
2526
2527 if (!devstate && (conditions & QUEUE_EMPTY_RINGING)) {
2528 /* member state still may be RINGING due to lag in event message - check again with device state */
2529 return get_member_status(q, max_penalty, min_penalty, raise_penalty, conditions, 1);
2530 }
2531 return -1;
2532}
static int get_member_status(struct call_queue *q, int max_penalty, int min_penalty, int raise_penalty, enum empty_conditions conditions, int devstate)
Check if members are available.
Definition: app_queue.c:2451
ast_device_state
Device States.
Definition: devicestate.h:52
@ AST_DEVICE_UNKNOWN
Definition: devicestate.h:53

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, get_member_status(), get_wrapuptime(), member::lastcall, member::membername, call_queue::members, NULL, 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::state_interface, and member::status.

Referenced by get_member_status(), join_queue(), queue_exec(), and wait_our_turn().

◆ get_queue_member_status()

static int get_queue_member_status ( struct member cur)
static

Return the current state of a member.

Definition at line 2879 of file app_queue.c.

2880{
2881 return ast_strlen_zero(cur->state_exten) ? ast_device_state(cur->state_interface) : extensionstate2devicestate(ast_extension_state(NULL, cur->state_context, cur->state_exten));
2882}
int ast_extension_state(struct ast_channel *c, const char *context, const char *exten)
Uses hint and devicestate callback to get the state of an extension.
Definition: pbx.c:3170

References ast_extension_state(), ast_strlen_zero(), extensionstate2devicestate(), NULL, member::state_context, member::state_exten, and member::state_interface.

Referenced by can_ring_entry(), create_queue_member(), and kill_dead_members().

◆ get_wrapuptime()

static int get_wrapuptime ( struct call_queue q,
struct member member 
)
static

Return wrapuptime.

This function checks if wrapuptime in member is set and return this value. Otherwise return value the wrapuptime in the queue configuration

Returns
integer value

Definition at line 2020 of file app_queue.c.

2021{
2022 if (member->wrapuptime) {
2023 return member->wrapuptime;
2024 }
2025 return q->wrapuptime;
2026}
int wrapuptime
Definition: app_queue.c:1899

References member::wrapuptime, and call_queue::wrapuptime.

Referenced by can_ring_entry(), get_member_status(), is_member_available(), and queue_function_mem_read().

◆ handle_attended_transfer()

static void handle_attended_transfer ( void *  userdata,
struct stasis_subscription sub,
struct stasis_message msg 
)
static

Handle an attended transfer event.

This event is important in order to be able to log the end of the call to the queue log and to stasis.

Parameters
userdataData pertaining to the particular call in the queue.
subThe stasis subscription on which the message occurred.
msgThe stasis message for the attended transfer event.

Definition at line 6497 of file app_queue.c.

6499{
6500 struct queue_stasis_data *queue_data = userdata;
6501 struct ast_attended_transfer_message *atxfer_msg = stasis_message_data(msg);
6502 RAII_VAR(struct ast_channel_snapshot *, caller_snapshot, NULL, ao2_cleanup);
6503 RAII_VAR(struct ast_channel_snapshot *, member_snapshot, NULL, ao2_cleanup);
6504
6505 if (atxfer_msg->result != AST_BRIDGE_TRANSFER_SUCCESS ||
6507 return;
6508 }
6509
6510 ao2_lock(queue_data);
6511
6512 if (queue_data->dying) {
6513 ao2_unlock(queue_data);
6514 return;
6515 }
6516
6517 if (ast_strlen_zero(queue_data->bridge_uniqueid)) {
6518 ao2_unlock(queue_data);
6519 return;
6520 }
6521
6522 if ((!atxfer_msg->to_transferee.bridge_snapshot || strcmp(queue_data->bridge_uniqueid,
6523 atxfer_msg->to_transferee.bridge_snapshot->uniqueid)) &&
6524 (!atxfer_msg->to_transfer_target.bridge_snapshot || strcmp(queue_data->bridge_uniqueid,
6526 ao2_unlock(queue_data);
6527 return;
6528 }
6529
6530 caller_snapshot = ast_channel_snapshot_get_latest(queue_data->caller_uniqueid);
6531 member_snapshot = ast_channel_snapshot_get_latest(queue_data->member_uniqueid);
6532
6533 ao2_unlock(queue_data);
6534
6535 ast_debug(3, "Detected attended transfer in queue %s\n", queue_data->queue->name);
6536 log_attended_transfer(queue_data, atxfer_msg);
6537
6538 send_agent_complete(queue_data->queue->name, caller_snapshot, member_snapshot, queue_data->member,
6539 queue_data->holdstart, queue_data->starttime, TRANSFER);
6540 update_queue(queue_data->queue, queue_data->member, queue_data->callcompletedinsl,
6541 queue_data->starttime);
6542 remove_stasis_subscriptions(queue_data);
6543}
static void send_agent_complete(const char *queuename, struct ast_channel_snapshot *caller, struct ast_channel_snapshot *peer, const struct member *member, time_t holdstart, time_t callstart, enum agent_complete_reason rsn)
Send out AMI message with member call completion status information.
Definition: app_queue.c:6158
static int update_queue(struct call_queue *q, struct member *member, int callcompletedinsl, time_t starttime)
update the queue status
Definition: app_queue.c:6001
static void remove_stasis_subscriptions(struct queue_stasis_data *queue_data)
Definition: app_queue.c:6305
static void log_attended_transfer(struct queue_stasis_data *queue_data, struct ast_attended_transfer_message *atxfer_msg)
Definition: app_queue.c:6359
#define ao2_cleanup(obj)
Definition: astobj2.h:1934
@ AST_BRIDGE_TRANSFER_SUCCESS
Definition: bridge.h:1100
struct ast_channel_snapshot * ast_channel_snapshot_get_latest(const char *uniqueid)
Obtain the latest ast_channel_snapshot from the Stasis Message Bus API cache. This is an ao2 object,...
@ AST_ATTENDED_TRANSFER_DEST_THREEWAY
Message representing attended transfer.
enum ast_attended_transfer_dest_type dest_type
struct ast_bridge_channel_snapshot_pair to_transfer_target
enum ast_transfer_result result
struct ast_bridge_channel_snapshot_pair to_transferee
struct ast_bridge_snapshot * bridge_snapshot
const ast_string_field uniqueid
Definition: bridge.h:328
Structure representing a snapshot of channel state.
User data for stasis subscriptions used for queue calls.
Definition: app_queue.c:6251
const ast_string_field caller_uniqueid
Definition: app_queue.c:6259
const ast_string_field member_uniqueid
Definition: app_queue.c:6259
struct call_queue * queue
Definition: app_queue.c:6261
const ast_string_field bridge_uniqueid
Definition: app_queue.c:6259
struct member * member
Definition: app_queue.c:6263
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:941

References ao2_cleanup, ao2_lock, ao2_unlock, AST_ATTENDED_TRANSFER_DEST_THREEWAY, AST_BRIDGE_TRANSFER_SUCCESS, ast_channel_snapshot_get_latest(), ast_debug, ast_strlen_zero(), ast_bridge_channel_snapshot_pair::bridge_snapshot, queue_stasis_data::bridge_uniqueid, queue_stasis_data::callcompletedinsl, queue_stasis_data::caller_uniqueid, ast_attended_transfer_message::dest_type, queue_stasis_data::dying, queue_stasis_data::holdstart, log_attended_transfer(), queue_stasis_data::member, queue_stasis_data::member_uniqueid, call_queue::name, NULL, queue_stasis_data::queue, RAII_VAR, remove_stasis_subscriptions(), ast_attended_transfer_message::result, send_agent_complete(), queue_stasis_data::starttime, stasis_message_data(), ast_attended_transfer_message::to_transfer_target, ast_attended_transfer_message::to_transferee, TRANSFER, ast_bridge_snapshot::uniqueid, and update_queue().

Referenced by setup_stasis_subs().

◆ handle_blind_transfer()

static void handle_blind_transfer ( void *  userdata,
struct stasis_subscription sub,
struct stasis_message msg 
)
static

Handle a blind transfer event.

This event is important in order to be able to log the end of the call to the queue log and to stasis.

Parameters
userdataData pertaining to the particular call in the queue.
subThe stasis subscription on which the message occurred.
msgThe stasis message for the blind transfer event

Definition at line 6438 of file app_queue.c.

6440{
6441 struct queue_stasis_data *queue_data = userdata;
6442 struct ast_blind_transfer_message *transfer_msg = stasis_message_data(msg);
6443 const char *exten;
6444 const char *context;
6445 RAII_VAR(struct ast_channel_snapshot *, caller_snapshot, NULL, ao2_cleanup);
6446 RAII_VAR(struct ast_channel_snapshot *, member_snapshot, NULL, ao2_cleanup);
6447
6448 if (transfer_msg->result != AST_BRIDGE_TRANSFER_SUCCESS) {
6449 return;
6450 }
6451
6452 ao2_lock(queue_data);
6453
6454 if (queue_data->dying) {
6455 ao2_unlock(queue_data);
6456 return;
6457 }
6458
6459 if (ast_strlen_zero(queue_data->bridge_uniqueid) ||
6460 strcmp(queue_data->bridge_uniqueid, transfer_msg->bridge->uniqueid)) {
6461 ao2_unlock(queue_data);
6462 return;
6463 }
6464
6465 caller_snapshot = ast_channel_snapshot_get_latest(queue_data->caller_uniqueid);
6466 member_snapshot = ast_channel_snapshot_get_latest(queue_data->member_uniqueid);
6467
6468 ao2_unlock(queue_data);
6469
6470 exten = transfer_msg->exten;
6471 context = transfer_msg->context;
6472
6473 ast_debug(3, "Detected blind transfer in queue %s\n", queue_data->queue->name);
6474 ast_queue_log(queue_data->queue->name, queue_data->caller_uniqueid, queue_data->member->membername,
6475 "BLINDTRANSFER", "%s|%s|%ld|%ld|%d",
6476 exten, context,
6477 (long) (queue_data->starttime - queue_data->holdstart),
6478 (long) (time(NULL) - queue_data->starttime), queue_data->caller_pos);
6479
6480 send_agent_complete(queue_data->queue->name, caller_snapshot, member_snapshot, queue_data->member,
6481 queue_data->holdstart, queue_data->starttime, TRANSFER);
6482 update_queue(queue_data->queue, queue_data->member, queue_data->callcompletedinsl,
6483 queue_data->starttime);
6484 remove_stasis_subscriptions(queue_data);
6485}
Message published during a blind transfer.
char exten[AST_MAX_EXTENSION]
struct ast_bridge_snapshot * bridge
enum ast_transfer_result result
char context[AST_MAX_CONTEXT]

References ao2_cleanup, ao2_lock, ao2_unlock, AST_BRIDGE_TRANSFER_SUCCESS, ast_channel_snapshot_get_latest(), ast_debug, ast_queue_log(), ast_strlen_zero(), ast_blind_transfer_message::bridge, queue_stasis_data::bridge_uniqueid, queue_stasis_data::callcompletedinsl, queue_stasis_data::caller_pos, queue_stasis_data::caller_uniqueid, voicemailpwcheck::context, ast_blind_transfer_message::context, queue_stasis_data::dying, ast_blind_transfer_message::exten, queue_stasis_data::holdstart, queue_stasis_data::member, queue_stasis_data::member_uniqueid, member::membername, call_queue::name, NULL, queue_stasis_data::queue, RAII_VAR, remove_stasis_subscriptions(), ast_blind_transfer_message::result, send_agent_complete(), queue_stasis_data::starttime, stasis_message_data(), TRANSFER, ast_bridge_snapshot::uniqueid, and update_queue().

Referenced by setup_stasis_subs().

◆ handle_bridge_enter()

static void handle_bridge_enter ( void *  userdata,
struct stasis_subscription sub,
struct stasis_message msg 
)
static

Definition at line 6405 of file app_queue.c.

6407{
6408 struct queue_stasis_data *queue_data = userdata;
6409 struct ast_bridge_blob *enter_blob = stasis_message_data(msg);
6410 SCOPED_AO2LOCK(lock, queue_data);
6411
6412 if (queue_data->dying) {
6413 return;
6414 }
6415
6416 if (!ast_strlen_zero(queue_data->bridge_uniqueid)) {
6417 return;
6418 }
6419
6420 if (!strcmp(enter_blob->channel->base->uniqueid, queue_data->caller_uniqueid)) {
6421 ast_string_field_set(queue_data, bridge_uniqueid,
6422 enter_blob->bridge->uniqueid);
6423 ast_debug(3, "Detected entry of caller channel %s into bridge %s\n",
6424 enter_blob->channel->base->name, queue_data->bridge_uniqueid);
6425 }
6426}
ast_mutex_t lock
Definition: app_sla.c:331
#define SCOPED_AO2LOCK(varname, obj)
scoped lock specialization for ao2 mutexes.
Definition: lock.h:604
Blob of data associated with a bridge.
struct ast_bridge_snapshot * bridge
struct ast_channel_snapshot * channel
const ast_string_field uniqueid
const ast_string_field name
struct ast_channel_snapshot_base * base

References ast_debug, ast_string_field_set, ast_strlen_zero(), ast_channel_snapshot::base, ast_bridge_blob::bridge, queue_stasis_data::bridge_uniqueid, queue_stasis_data::caller_uniqueid, ast_bridge_blob::channel, queue_stasis_data::dying, lock, ast_channel_snapshot_base::name, SCOPED_AO2LOCK, stasis_message_data(), ast_bridge_snapshot::uniqueid, and ast_channel_snapshot_base::uniqueid.

Referenced by setup_stasis_subs().

◆ handle_hangup()

static void handle_hangup ( void *  userdata,
struct stasis_subscription sub,
struct stasis_message msg 
)
static

Definition at line 6686 of file app_queue.c.

6688{
6689 struct queue_stasis_data *queue_data = userdata;
6690 struct ast_channel_blob *channel_blob = stasis_message_data(msg);
6691 RAII_VAR(struct ast_channel_snapshot *, caller_snapshot, NULL, ao2_cleanup);
6692 RAII_VAR(struct ast_channel_snapshot *, member_snapshot, NULL, ao2_cleanup);
6693 RAII_VAR(struct ast_channel *, chan, NULL, ao2_cleanup);
6694 enum agent_complete_reason reason;
6695
6696 ao2_lock(queue_data);
6697
6698 if (queue_data->dying) {
6699 ao2_unlock(queue_data);
6700 return;
6701 }
6702
6703 if (!strcmp(channel_blob->snapshot->base->uniqueid, queue_data->caller_uniqueid)) {
6704 reason = CALLER;
6705 } else if (!strcmp(channel_blob->snapshot->base->uniqueid, queue_data->member_uniqueid)) {
6706 reason = AGENT;
6707 } else {
6708 ao2_unlock(queue_data);
6709 return;
6710 }
6711
6712 chan = ast_channel_get_by_name(channel_blob->snapshot->base->name);
6713 if (chan && (ast_channel_has_role(chan, AST_TRANSFERER_ROLE_NAME) ||
6714 !ast_strlen_zero(pbx_builtin_getvar_helper(chan, "ATTENDEDTRANSFER")) ||
6715 !ast_strlen_zero(pbx_builtin_getvar_helper(chan, "BLINDTRANSFER")))) {
6716 /* Channel that is hanging up is doing it as part of a transfer.
6717 * We'll get a transfer event later
6718 */
6719 ao2_unlock(queue_data);
6720 return;
6721 }
6722
6723 caller_snapshot = ast_channel_snapshot_get_latest(queue_data->caller_uniqueid);
6724 member_snapshot = ast_channel_snapshot_get_latest(queue_data->member_uniqueid);
6725
6726 ao2_unlock(queue_data);
6727
6728 ast_debug(3, "Detected hangup of queue %s channel %s\n", reason == CALLER ? "caller" : "member",
6729 channel_blob->snapshot->base->name);
6730
6731 ast_queue_log(queue_data->queue->name, queue_data->caller_uniqueid, queue_data->member->membername,
6732 reason == CALLER ? "COMPLETECALLER" : "COMPLETEAGENT", "%ld|%ld|%d",
6733 (long) (queue_data->starttime - queue_data->holdstart),
6734 (long) (time(NULL) - queue_data->starttime), queue_data->caller_pos);
6735
6736 send_agent_complete(queue_data->queue->name, caller_snapshot, member_snapshot, queue_data->member,
6737 queue_data->holdstart, queue_data->starttime, reason);
6738 update_queue(queue_data->queue, queue_data->member, queue_data->callcompletedinsl,
6739 queue_data->starttime);
6740 remove_stasis_subscriptions(queue_data);
6741}
agent_complete_reason
Definition: app_queue.c:6151
#define AST_TRANSFERER_ROLE_NAME
Definition: bridge_basic.h:36
int ast_channel_has_role(struct ast_channel *channel, const char *role_name)
Check if a role exists on a channel.
Definition: bridge_roles.c:394
struct ast_channel * ast_channel_get_by_name(const char *name)
Find a channel by name.
Definition: channel.c:1473
const char * pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name)
Return a pointer to the value of the corresponding channel variable.
Blob of data associated with a channel.
struct ast_channel_snapshot * snapshot

References AGENT, ao2_cleanup, ao2_lock, ao2_unlock, ast_channel_get_by_name(), ast_channel_has_role(), ast_channel_snapshot_get_latest(), ast_debug, ast_queue_log(), ast_strlen_zero(), AST_TRANSFERER_ROLE_NAME, ast_channel_snapshot::base, queue_stasis_data::callcompletedinsl, CALLER, queue_stasis_data::caller_pos, queue_stasis_data::caller_uniqueid, queue_stasis_data::dying, queue_stasis_data::holdstart, queue_stasis_data::member, queue_stasis_data::member_uniqueid, member::membername, call_queue::name, ast_channel_snapshot_base::name, NULL, pbx_builtin_getvar_helper(), queue_stasis_data::queue, RAII_VAR, remove_stasis_subscriptions(), send_agent_complete(), ast_channel_blob::snapshot, queue_stasis_data::starttime, stasis_message_data(), ast_channel_snapshot_base::uniqueid, and update_queue().

Referenced by setup_stasis_subs().

◆ handle_local_optimization_begin()

static void handle_local_optimization_begin ( void *  userdata,
struct stasis_subscription sub,
struct stasis_message msg 
)
static

Definition at line 6571 of file app_queue.c.

6573{
6574 struct queue_stasis_data *queue_data = userdata;
6575 struct ast_multi_channel_blob *optimization_blob = stasis_message_data(msg);
6576 struct ast_channel_snapshot *local_one = ast_multi_channel_blob_get_channel(optimization_blob, "1");
6577 struct ast_channel_snapshot *local_two = ast_multi_channel_blob_get_channel(optimization_blob, "2");
6578 struct ast_channel_snapshot *source = ast_multi_channel_blob_get_channel(optimization_blob, "source");
6579 struct local_optimization *optimization;
6580 unsigned int id;
6581 SCOPED_AO2LOCK(lock, queue_data);
6582
6583 if (queue_data->dying) {
6584 return;
6585 }
6586
6587 if (!strcmp(local_one->base->uniqueid, queue_data->member_uniqueid)) {
6588 optimization = &queue_data->member_optimize;
6589 } else if (!strcmp(local_two->base->uniqueid, queue_data->caller_uniqueid)) {
6590 optimization = &queue_data->caller_optimize;
6591 } else {
6592 return;
6593 }
6594
6595 /* We only allow move-swap optimizations, so there had BETTER be a source */
6596 ast_assert(source != NULL);
6597
6598 optimization->source_chan_uniqueid = ast_strdup(source->base->uniqueid);
6599 if (!optimization->source_chan_uniqueid) {
6600 ast_log(LOG_ERROR, "Unable to track local channel optimization for channel %s. Expect further errors\n", local_one->base->name);
6601 return;
6602 }
6604
6605 optimization->id = id;
6606 optimization->in_progress = 1;
6607}
enum queue_result id
Definition: app_queue.c:1667
struct ast_channel_snapshot * ast_multi_channel_blob_get_channel(struct ast_multi_channel_blob *obj, const char *role)
Retrieve a channel snapshot associated with a specific role from a ast_multi_channel_blob.
struct ast_json * ast_multi_channel_blob_get_json(struct ast_multi_channel_blob *obj)
Retrieve the JSON blob from a ast_multi_channel_blob. Returned ast_json is still owned by obj.
struct ast_json * ast_json_object_get(struct ast_json *object, const char *key)
Get a field from a JSON object.
Definition: json.c:407
intmax_t ast_json_integer_get(const struct ast_json *integer)
Get the value from a JSON integer.
Definition: json.c:332
A multi channel blob data structure for multi_channel_blob stasis messages.
Structure representing relevant data during a local channel optimization.
Definition: app_queue.c:6227
const char * source_chan_uniqueid
Definition: app_queue.c:6229
unsigned int id
Definition: app_queue.c:6233
struct local_optimization member_optimize
Definition: app_queue.c:6281
struct local_optimization caller_optimize
Definition: app_queue.c:6279
#define ast_assert(a)
Definition: utils.h:739

References ast_assert, ast_json_integer_get(), ast_json_object_get(), ast_log, ast_multi_channel_blob_get_channel(), ast_multi_channel_blob_get_json(), ast_strdup, ast_channel_snapshot::base, queue_stasis_data::caller_optimize, queue_stasis_data::caller_uniqueid, queue_stasis_data::dying, id, local_optimization::id, local_optimization::in_progress, lock, LOG_ERROR, queue_stasis_data::member_optimize, queue_stasis_data::member_uniqueid, ast_channel_snapshot_base::name, NULL, SCOPED_AO2LOCK, local_optimization::source_chan_uniqueid, stasis_message_data(), and ast_channel_snapshot_base::uniqueid.

Referenced by setup_stasis_subs().

◆ handle_local_optimization_end()

static void handle_local_optimization_end ( void *  userdata,
struct stasis_subscription sub,
struct stasis_message msg 
)
static

Definition at line 6622 of file app_queue.c.

6624{
6625 struct queue_stasis_data *queue_data = userdata;
6626 struct ast_multi_channel_blob *optimization_blob = stasis_message_data(msg);
6627 struct ast_channel_snapshot *local_one = ast_multi_channel_blob_get_channel(optimization_blob, "1");
6628 struct ast_channel_snapshot *local_two = ast_multi_channel_blob_get_channel(optimization_blob, "2");
6629 struct local_optimization *optimization;
6630 int is_caller;
6631 unsigned int id;
6632 SCOPED_AO2LOCK(lock, queue_data);
6633
6634 if (queue_data->dying) {
6635 return;
6636 }
6637
6638 if (!strcmp(local_one->base->uniqueid, queue_data->member_uniqueid)) {
6639 optimization = &queue_data->member_optimize;
6640 is_caller = 0;
6641 } else if (!strcmp(local_two->base->uniqueid, queue_data->caller_uniqueid)) {
6642 optimization = &queue_data->caller_optimize;
6643 is_caller = 1;
6644 } else {
6645 return;
6646 }
6647
6649
6650 if (!optimization->in_progress) {
6651 ast_log(LOG_WARNING, "Told of a local optimization end when we had no previous begin\n");
6652 return;
6653 }
6654
6655 if (id != optimization->id) {
6656 ast_log(LOG_WARNING, "Local optimization end event ID does not match begin (%u != %u)\n",
6657 id, optimization->id);
6658 return;
6659 }
6660
6661 if (is_caller) {
6662 ast_debug(3, "Local optimization: Changing queue caller uniqueid from %s to %s\n",
6663 queue_data->caller_uniqueid, optimization->source_chan_uniqueid);
6664 ast_string_field_set(queue_data, caller_uniqueid, optimization->source_chan_uniqueid);
6665 } else {
6666 ast_debug(3, "Local optimization: Changing queue member uniqueid from %s to %s\n",
6667 queue_data->member_uniqueid, optimization->source_chan_uniqueid);
6668 ast_string_field_set(queue_data, member_uniqueid, optimization->source_chan_uniqueid);
6669 }
6670
6671 optimization->in_progress = 0;
6672}

References ast_debug, ast_json_integer_get(), ast_json_object_get(), ast_log, ast_multi_channel_blob_get_channel(), ast_multi_channel_blob_get_json(), ast_string_field_set, ast_channel_snapshot::base, queue_stasis_data::caller_optimize, queue_stasis_data::caller_uniqueid, queue_stasis_data::dying, id, local_optimization::id, local_optimization::in_progress, lock, LOG_WARNING, queue_stasis_data::member_optimize, queue_stasis_data::member_uniqueid, SCOPED_AO2LOCK, local_optimization::source_chan_uniqueid, stasis_message_data(), and ast_channel_snapshot_base::uniqueid.

Referenced by setup_stasis_subs().

◆ handle_masquerade()

static void handle_masquerade ( void *  userdata,
struct stasis_subscription sub,
struct stasis_message msg 
)
static

Definition at line 6743 of file app_queue.c.

6745{
6746 struct queue_stasis_data *queue_data = userdata;
6747 struct ast_channel_blob *channel_blob = stasis_message_data(msg);
6748 const char *new_channel_id;
6749
6750 new_channel_id = ast_json_string_get(ast_json_object_get(channel_blob->blob, "newchanneluniqueid"));
6751
6752 ao2_lock(queue_data);
6753
6754 if (queue_data->dying) {
6755 ao2_unlock(queue_data);
6756 return;
6757 }
6758
6759 if (!strcmp(channel_blob->snapshot->base->uniqueid, queue_data->caller_uniqueid)) {
6760 ast_debug(1, "Replacing caller channel %s with %s due to masquerade\n", queue_data->caller_uniqueid, new_channel_id);
6761 ast_string_field_set(queue_data, caller_uniqueid, new_channel_id);
6762 } else if (!strcmp(channel_blob->snapshot->base->uniqueid, queue_data->member_uniqueid)) {
6763 ast_debug(1, "Replacing member channel %s with %s due to masquerade\n", queue_data->member_uniqueid, new_channel_id);
6764 ast_string_field_set(queue_data, member_uniqueid, new_channel_id);
6765 }
6766
6767 ao2_unlock(queue_data);
6768}
const char * ast_json_string_get(const struct ast_json *string)
Get the value of a JSON string.
Definition: json.c:283
struct ast_json * blob

References ao2_lock, ao2_unlock, ast_debug, ast_json_object_get(), ast_json_string_get(), ast_string_field_set, ast_channel_snapshot::base, ast_channel_blob::blob, queue_stasis_data::caller_uniqueid, queue_stasis_data::dying, queue_stasis_data::member_uniqueid, ast_channel_blob::snapshot, stasis_message_data(), and ast_channel_snapshot_base::uniqueid.

Referenced by setup_stasis_subs().

◆ handle_queue_add_member()

static char * handle_queue_add_member ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
)
static

Definition at line 11054 of file app_queue.c.

11055{
11056 const char *queuename, *interface, *membername = NULL, *state_interface = NULL, *reason = NULL;
11057 int penalty, paused = 0;
11058
11059 switch ( cmd ) {
11060 case CLI_INIT:
11061 e->command = "queue add member";
11062 e->usage =
11063 "Usage: queue add member <dial string> to <queue> [penalty <penalty> [as <membername> [state_interface <interface> [paused <reason>]]]]\n"
11064 " Add a dial string (Such as a channel,e.g. SIP/6001) to a queue with optionally: a penalty, membername and a state_interface\n";
11065 return NULL;
11066 case CLI_GENERATE:
11067 return complete_queue_add_member(a->line, a->word, a->pos, a->n);
11068 }
11069
11070 if ((a->argc != 6) && (a->argc != 8) && (a->argc != 10) && (a->argc != 12) && (a->argc != 14)) {
11071 return CLI_SHOWUSAGE;
11072 } else if (strcmp(a->argv[4], "to")) {
11073 return CLI_SHOWUSAGE;
11074 } else if ((a->argc >= 8) && strcmp(a->argv[6], "penalty")) {
11075 return CLI_SHOWUSAGE;
11076 } else if ((a->argc >= 10) && strcmp(a->argv[8], "as")) {
11077 return CLI_SHOWUSAGE;
11078 } else if ((a->argc == 12) && strcmp(a->argv[10], "state_interface")) {
11079 return CLI_SHOWUSAGE;
11080 } else if ((a->argc == 14) && strcmp(a->argv[12], "paused")) {
11081 return CLI_SHOWUSAGE;
11082 }
11083
11084 queuename = a->argv[5];
11085 interface = a->argv[3];
11086 if (a->argc >= 8) {
11087 if (sscanf(a->argv[7], "%30d", &penalty) == 1) {
11088 if (penalty < 0) {
11089 ast_cli(a->fd, "Penalty must be >= 0\n");
11090 penalty = 0;
11091 }
11092 } else {
11093 ast_cli(a->fd, "Penalty must be an integer >= 0\n");
11094 penalty = 0;
11095 }
11096 } else {
11097 penalty = 0;
11098 }
11099
11100 if (a->argc >= 10) {
11101 membername = a->argv[9];
11102 }
11103
11104 if (a->argc >= 12) {
11105 state_interface = a->argv[11];
11106 }
11107
11108 if (a->argc >= 14) {
11109 paused = 1;
11110 reason = a->argv[13];
11111 }
11112
11113 switch (add_to_queue(queuename, interface, membername, penalty, paused, queue_persistent_members, state_interface, reason, 0)) {
11114 case RES_OKAY:
11115 if (ast_strlen_zero(membername) || !log_membername_as_agent) {
11116 ast_queue_log(queuename, "CLI", interface, "ADDMEMBER", "%s", paused ? "PAUSED" : "");
11117 } else {
11118 ast_queue_log(queuename, "CLI", membername, "ADDMEMBER", "%s", paused ? "PAUSED" : "");
11119 }
11120 ast_cli(a->fd, "Added interface '%s' to queue '%s'\n", interface, queuename);
11121 return CLI_SUCCESS;
11122 case RES_EXISTS:
11123 ast_cli(a->fd, "Unable to add interface '%s' to queue '%s': Already there\n", interface, queuename);
11124 return CLI_FAILURE;
11125 case RES_NOSUCHQUEUE:
11126 ast_cli(a->fd, "Unable to add interface to queue '%s': No such queue\n", queuename);
11127 return CLI_FAILURE;
11128 case RES_OUTOFMEMORY:
11129 ast_cli(a->fd, "Out of memory\n");
11130 return CLI_FAILURE;
11131 case RES_NOT_DYNAMIC:
11132 ast_cli(a->fd, "Member not dynamic\n");
11133 return CLI_FAILURE;
11134 default:
11135 return CLI_FAILURE;
11136 }
11137}
#define RES_NOT_DYNAMIC
Definition: app_queue.c:1598
static char * complete_queue_add_member(const char *line, const char *word, int pos, int state)
Definition: app_queue.c:10879
@ CLI_INIT
Definition: cli.h:152
@ CLI_GENERATE
Definition: cli.h:153
#define CLI_FAILURE
Definition: cli.h:46
char * command
Definition: cli.h:186
const char * usage
Definition: cli.h:177
static struct test_val a

References a, add_to_queue(), ast_cli(), ast_queue_log(), ast_strlen_zero(), CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, complete_queue_add_member(), log_membername_as_agent, NULL, queue_persistent_members, RES_EXISTS, RES_NOSUCHQUEUE, RES_NOT_DYNAMIC, RES_OKAY, RES_OUTOFMEMORY, and ast_cli_entry::usage.

◆ handle_queue_change_priority_caller()

static char * handle_queue_change_priority_caller ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
)
static

Definition at line 11250 of file app_queue.c.

11251{
11252 const char *queuename, *caller;
11253 int priority, immediate = 0;
11254 char *res = CLI_FAILURE;
11255
11256 switch (cmd) {
11257 case CLI_INIT:
11258 e->command = "queue priority caller";
11259 e->usage =
11260 "Usage: queue priority caller <channel> on <queue> to <priority> [immediate]\n"
11261 " Change the priority of a channel on a queue, optionally applying the change in relation to existing callers.\n";
11262 return NULL;
11263 case CLI_GENERATE:
11264 return NULL;
11265 }
11266
11267 if (a->argc < 8) {
11268 return CLI_SHOWUSAGE;
11269 } else if (strcmp(a->argv[4], "on")) {
11270 return CLI_SHOWUSAGE;
11271 } else if (strcmp(a->argv[6], "to")) {
11272 return CLI_SHOWUSAGE;
11273 } else if (sscanf(a->argv[7], "%30d", &priority) != 1) {
11274 ast_log (LOG_ERROR, "<priority> parameter must be an integer.\n");
11275 return CLI_SHOWUSAGE;
11276 } else if (a->argc == 9) {
11277 if (strcmp(a->argv[8], "immediate")) {
11278 return CLI_SHOWUSAGE;
11279 }
11280 immediate = 1;
11281 }
11282
11283 caller = a->argv[3];
11284 queuename = a->argv[5];
11285
11286 switch (change_priority_caller_on_queue(queuename, caller, priority, immediate)) {
11287 case RES_OKAY:
11288 res = CLI_SUCCESS;
11289 break;
11290 case RES_NOSUCHQUEUE:
11291 ast_cli(a->fd, "Unable change priority caller %s on queue '%s': No such queue\n", caller, queuename);
11292 break;
11293 case RES_NOT_CALLER:
11294 ast_cli(a->fd, "Unable to change priority caller '%s' on queue '%s': Not there\n", caller, queuename);
11295
11296 break;
11297 }
11298
11299 return res;
11300}
static int change_priority_caller_on_queue(const char *queuename, const char *caller, int priority, int immediate)
Change priority caller into a queue.
Definition: app_queue.c:7675

References a, ast_cli(), ast_log, change_priority_caller_on_queue(), CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, LOG_ERROR, NULL, priority, RES_NOSUCHQUEUE, RES_NOT_CALLER, RES_OKAY, and ast_cli_entry::usage.

◆ handle_queue_pause_member()

static char * handle_queue_pause_member ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
)
static

Definition at line 11323 of file app_queue.c.

11324{
11325 const char *queuename, *interface, *reason;
11326 int paused;
11327
11328 switch (cmd) {
11329 case CLI_INIT:
11330 e->command = "queue {pause|unpause} member";
11331 e->usage =
11332 "Usage: queue {pause|unpause} member <member> [queue <queue> [reason <reason>]]\n"
11333 " Pause or unpause a queue member. Not specifying a particular queue\n"
11334 " will pause or unpause a member across all queues to which the member\n"
11335 " belongs.\n";
11336 return NULL;
11337 case CLI_GENERATE:
11338 return complete_queue_pause_member(a->line, a-> word, a->pos, a->n);
11339 }
11340
11341 if (a->argc < 4 || a->argc == 5 || a->argc == 7 || a->argc > 8) {
11342 return CLI_SHOWUSAGE;
11343 } else if (a->argc >= 5 && strcmp(a->argv[4], "queue")) {
11344 return CLI_SHOWUSAGE;
11345 } else if (a->argc == 8 && strcmp(a->argv[6], "reason")) {
11346 return CLI_SHOWUSAGE;
11347 }
11348
11349
11350 interface = a->argv[3];
11351 queuename = a->argc >= 6 ? a->argv[5] : NULL;
11352 reason = a->argc == 8 ? a->argv[7] : NULL;
11353 paused = !strcasecmp(a->argv[1], "pause");
11354
11355 if (set_member_paused(queuename, interface, reason, paused) == RESULT_SUCCESS) {
11356 ast_cli(a->fd, "%spaused interface '%s'", paused ? "" : "un", interface);
11357 if (!ast_strlen_zero(queuename)) {
11358 ast_cli(a->fd, " in queue '%s'", queuename);
11359 }
11360 if (!ast_strlen_zero(reason)) {
11361 ast_cli(a->fd, " for reason '%s'", reason);
11362 }
11363 ast_cli(a->fd, "\n");
11364 return CLI_SUCCESS;
11365 } else {
11366 ast_cli(a->fd, "Unable to %spause interface '%s'", paused ? "" : "un", interface);
11367 if (!ast_strlen_zero(queuename)) {
11368 ast_cli(a->fd, " in queue '%s'", queuename);
11369 }
11370 if (!ast_strlen_zero(reason)) {
11371 ast_cli(a->fd, " for reason '%s'", reason);
11372 }
11373 ast_cli(a->fd, "\n");
11374 return CLI_FAILURE;
11375 }
11376}
static char * complete_queue_pause_member(const char *line, const char *word, int pos, int state)
Definition: app_queue.c:11304
static int set_member_paused(const char *queuename, const char *interface, const char *reason, int paused)
Definition: app_queue.c:7881
#define RESULT_SUCCESS
Definition: cli.h:40

References a, ast_cli(), ast_strlen_zero(), CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, complete_queue_pause_member(), NULL, RESULT_SUCCESS, set_member_paused(), and ast_cli_entry::usage.

◆ handle_queue_reload()

static char * handle_queue_reload ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
)
static

Definition at line 11595 of file app_queue.c.

11596{
11597 struct ast_flags mask = {0,};
11598 int i;
11599
11600 switch (cmd) {
11601 case CLI_INIT:
11602 e->command = "queue reload {parameters|members|rules|all}";
11603 e->usage =
11604 "Usage: queue reload {parameters|members|rules|all} [<queuenames>]\n"
11605 "Reload queues. If <queuenames> are specified, only reload information pertaining\n"
11606 "to <queuenames>. One of 'parameters,' 'members,' 'rules,' or 'all' must be\n"
11607 "specified in order to know what information to reload. Below is an explanation\n"
11608 "of each of these qualifiers.\n"
11609 "\n"
11610 "\t'members' - reload queue members from queues.conf\n"
11611 "\t'parameters' - reload all queue options except for queue members\n"
11612 "\t'rules' - reload the queuerules.conf file\n"
11613 "\t'all' - reload queue rules, parameters, and members\n"
11614 "\n"
11615 "Note: the 'rules' qualifier here cannot actually be applied to a specific queue.\n"
11616 "Use of the 'rules' qualifier causes queuerules.conf to be reloaded. Even if only\n"
11617 "one queue is specified when using this command, reloading queue rules may cause\n"
11618 "other queues to be affected\n";
11619 return NULL;
11620 case CLI_GENERATE:
11621 if (a->pos >= 3) {
11622 /* find the point at which the list of queue names starts */
11623 const char *command_end = a->line + strlen("queue reload ");
11624 command_end = strchr(command_end, ' ');
11625 if (!command_end) {
11626 command_end = a->line + strlen(a->line);
11627 }
11628 return complete_queue(a->line, a->word, a->pos, a->n, command_end - a->line);
11629 } else {
11630 return NULL;
11631 }
11632 }
11633
11634 if (a->argc < 3)
11635 return CLI_SHOWUSAGE;
11636
11637 if (!strcasecmp(a->argv[2], "rules")) {
11639 } else if (!strcasecmp(a->argv[2], "members")) {
11641 } else if (!strcasecmp(a->argv[2], "parameters")) {
11643 } else if (!strcasecmp(a->argv[2], "all")) {
11645 }
11646
11647 if (a->argc == 3) {
11648 reload_handler(1, &mask, NULL);
11649 return CLI_SUCCESS;
11650 }
11651
11652 for (i = 3; i < a->argc; ++i) {
11653 reload_handler(1, &mask, a->argv[i]);
11654 }
11655
11656 return CLI_SUCCESS;
11657}
static int reload_handler(int reload, struct ast_flags *mask, const char *queuename)
The command center for all reload operations.
Definition: app_queue.c:10066
#define ast_set_flag(p, flag)
Definition: utils.h:70
#define AST_FLAGS_ALL
Definition: utils.h:196

References a, AST_FLAGS_ALL, ast_set_flag, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, complete_queue(), NULL, QUEUE_RELOAD_MEMBER, QUEUE_RELOAD_PARAMETERS, QUEUE_RELOAD_RULES, QUEUE_RESET_STATS, reload_handler(), and ast_cli_entry::usage.

◆ handle_queue_remove_member()

static char * handle_queue_remove_member ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
)
static

Definition at line 11187 of file app_queue.c.

11188{
11189 const char *queuename, *interface;
11190 struct member *mem = NULL;
11191 char *res = CLI_FAILURE;
11192
11193 switch (cmd) {
11194 case CLI_INIT:
11195 e->command = "queue remove member";
11196 e->usage =
11197 "Usage: queue remove member <channel> from <queue>\n"
11198 " Remove a specific channel from a queue.\n";
11199 return NULL;
11200 case CLI_GENERATE:
11201 return complete_queue_remove_member(a->line, a->word, a->pos, a->n);
11202 }
11203
11204 if (a->argc != 6) {
11205 return CLI_SHOWUSAGE;
11206 } else if (strcmp(a->argv[4], "from")) {
11207 return CLI_SHOWUSAGE;
11208 }
11209
11210 queuename = a->argv[5];
11211 interface = a->argv[3];
11212
11214 mem = find_member_by_queuename_and_interface(queuename, interface);
11215 }
11216
11217 switch (remove_from_queue(queuename, interface)) {
11218 case RES_OKAY:
11219 if (!mem || ast_strlen_zero(mem->membername)) {
11220 ast_queue_log(queuename, "CLI", interface, "REMOVEMEMBER", "%s", "");
11221 } else {
11222 ast_queue_log(queuename, "CLI", mem->membername, "REMOVEMEMBER", "%s", "");
11223 }
11224 ast_cli(a->fd, "Removed interface %s from queue '%s'\n", interface, queuename);
11225 res = CLI_SUCCESS;
11226 break;
11227 case RES_EXISTS:
11228 ast_cli(a->fd, "Unable to remove interface '%s' from queue '%s': Not there\n", interface, queuename);
11229 break;
11230 case RES_NOSUCHQUEUE:
11231 ast_cli(a->fd, "Unable to remove interface from queue '%s': No such queue\n", queuename);
11232 break;
11233 case RES_OUTOFMEMORY:
11234 ast_cli(a->fd, "Out of memory\n");
11235 break;
11236 case RES_NOT_DYNAMIC:
11237 ast_cli(a->fd, "Unable to remove interface '%s' from queue '%s': Member is not dynamic\n", interface, queuename);
11238 break;
11239 }
11240
11241 if (mem) {
11242 ao2_ref(mem, -1);
11243 }
11244
11245 return res;
11246}
static int remove_from_queue(const char *queuename, const char *interface)
Remove member from queue.
Definition: app_queue.c:7569
static struct member * find_member_by_queuename_and_interface(const char *queuename, const char *interface)
Find a member by looking up queuename and interface.
Definition: app_queue.c:11998
static char * complete_queue_remove_member(const char *line, const char *word, int pos, int state)
Definition: app_queue.c:11139

References a, ao2_ref, ast_cli(), ast_queue_log(), ast_strlen_zero(), CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, complete_queue_remove_member(), find_member_by_queuename_and_interface(), log_membername_as_agent, member::membername, NULL, remove_from_queue(), RES_EXISTS, RES_NOSUCHQUEUE, RES_NOT_DYNAMIC, RES_OKAY, RES_OUTOFMEMORY, and ast_cli_entry::usage.

◆ handle_queue_reset()

static char * handle_queue_reset ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
)
static

Definition at line 11556 of file app_queue.c.

11557{
11558 struct ast_flags mask = {QUEUE_RESET_STATS,};
11559 int i;
11560
11561 switch (cmd) {
11562 case CLI_INIT:
11563 e->command = "queue reset stats";
11564 e->usage =
11565 "Usage: queue reset stats [<queuenames>]\n"
11566 "\n"
11567 "Issuing this command will reset statistics for\n"
11568 "<queuenames>, or for all queues if no queue is\n"
11569 "specified.\n";
11570 return NULL;
11571 case CLI_GENERATE:
11572 if (a->pos >= 3) {
11573 return complete_queue(a->line, a->word, a->pos, a->n, 17);
11574 } else {
11575 return NULL;
11576 }
11577 }
11578
11579 if (a->argc < 3) {
11580 return CLI_SHOWUSAGE;
11581 }
11582
11583 if (a->argc == 3) {
11584 reload_handler(1, &mask, NULL);
11585 return CLI_SUCCESS;
11586 }
11587
11588 for (i = 3; i < a->argc; ++i) {
11589 reload_handler(1, &mask, a->argv[i]);
11590 }
11591
11592 return CLI_SUCCESS;
11593}

References a, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, complete_queue(), NULL, QUEUE_RESET_STATS, reload_handler(), and ast_cli_entry::usage.

◆ handle_queue_rule_show()

static char * handle_queue_rule_show ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
)
static

Definition at line 11521 of file app_queue.c.

11522{
11523 const char *rule;
11524 struct rule_list *rl_iter;
11525 struct penalty_rule *pr_iter;
11526 switch (cmd) {
11527 case CLI_INIT:
11528 e->command = "queue show rules";
11529 e->usage =
11530 "Usage: queue show rules [rulename]\n"
11531 " Show the list of rules associated with rulename. If no\n"
11532 " rulename is specified, list all rules defined in queuerules.conf\n";
11533 return NULL;
11534 case CLI_GENERATE:
11535 return complete_queue_rule_show(a->line, a->word, a->pos, a->n);
11536 }
11537
11538 if (a->argc != 3 && a->argc != 4) {
11539 return CLI_SHOWUSAGE;
11540 }
11541
11542 rule = a->argc == 4 ? a->argv[3] : "";
11544 AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) {
11545 if (ast_strlen_zero(rule) || !strcasecmp(rl_iter->name, rule)) {
11546 ast_cli(a->fd, "Rule: %s\n", rl_iter->name);
11547 AST_LIST_TRAVERSE(&rl_iter->rules, pr_iter, list) {
11548 ast_cli(a->fd, "\tAfter %d seconds, adjust QUEUE_MAX_PENALTY %s %d, adjust QUEUE_MIN_PENALTY %s %d and adjust QUEUE_RAISE_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, pr_iter->raise_relative ? "by" : "to", pr_iter->raise_value);
11549 }
11550 }
11551 }
11553 return CLI_SUCCESS;
11554}
static char * complete_queue_rule_show(const char *line, const char *word, int pos, int state)
Definition: app_queue.c:11499

References a, 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(), penalty_rule::list, penalty_rule::max_relative, penalty_rule::max_value, penalty_rule::min_relative, penalty_rule::min_value, rule_list::name, NULL, penalty_rule::raise_relative, penalty_rule::raise_value, rule_list::rules, penalty_rule::time, and ast_cli_entry::usage.

◆ handle_queue_set_member_penalty()

static char * handle_queue_set_member_penalty ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
)
static

Definition at line 11458 of file app_queue.c.

11459{
11460 const char *queuename = NULL, *interface;
11461 int penalty = 0;
11462
11463 switch (cmd) {
11464 case CLI_INIT:
11465 e->command = "queue set penalty";
11466 e->usage =
11467 "Usage: queue set penalty <penalty> on <interface> [in <queue>]\n"
11468 " Set a member's penalty in the queue specified. If no queue is specified\n"
11469 " then that interface's penalty is set in all queues to which that interface is a member\n";
11470 return NULL;
11471 case CLI_GENERATE:
11472 return complete_queue_set_member_value(a->line, a->word, a->pos, a->n);
11473 }
11474
11475 if (a->argc != 6 && a->argc != 8) {
11476 return CLI_SHOWUSAGE;
11477 } else if (strcmp(a->argv[4], "on") || (a->argc > 6 && strcmp(a->argv[6], "in"))) {
11478 return CLI_SHOWUSAGE;
11479 }
11480
11481 if (a->argc == 8) {
11482 queuename = a->argv[7];
11483 }
11484 interface = a->argv[5];
11485 penalty = atoi(a->argv[3]);
11486
11487 switch (set_member_value(queuename, interface, MEMBER_PENALTY, penalty)) {
11488 case RESULT_SUCCESS:
11489 ast_cli(a->fd, "Set penalty on interface '%s' from queue '%s'\n", interface, queuename);
11490 return CLI_SUCCESS;
11491 case RESULT_FAILURE:
11492 ast_cli(a->fd, "Failed to set penalty on interface '%s' from queue '%s'\n", interface, queuename);
11493 return CLI_FAILURE;
11494 default:
11495 return CLI_FAILURE;
11496 }
11497}
static int set_member_value(const char *queuename, const char *interface, int property, int value)
Definition: app_queue.c:8029
static char * complete_queue_set_member_value(const char *line, const char *word, int pos, int state)
Definition: app_queue.c:11378

References a, ast_cli(), CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, complete_queue_set_member_value(), MEMBER_PENALTY, NULL, RESULT_FAILURE, RESULT_SUCCESS, set_member_value(), and ast_cli_entry::usage.

◆ handle_queue_set_member_ringinuse()

static char * handle_queue_set_member_ringinuse ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
)
static

Definition at line 11401 of file app_queue.c.

11402{
11403 const char *queuename = NULL, *interface;
11404 int ringinuse;
11405
11406 switch (cmd) {
11407 case CLI_INIT:
11408 e->command = "queue set ringinuse";
11409 e->usage =
11410 "Usage: queue set ringinuse <yes/no> on <interface> [in <queue>]\n"
11411 " Set a member's ringinuse in the queue specified. If no queue is specified\n"
11412 " then that interface's penalty is set in all queues to which that interface is a member.\n";
11413 break;
11414 return NULL;
11415 case CLI_GENERATE:
11416 return complete_queue_set_member_value(a->line, a->word, a->pos, a->n);
11417 }
11418
11419 /* Sensible argument counts */
11420 if (a->argc != 6 && a->argc != 8) {
11421 return CLI_SHOWUSAGE;
11422 }
11423
11424 /* Uses proper indicational words */
11425 if (strcmp(a->argv[4], "on") || (a->argc > 6 && strcmp(a->argv[6], "in"))) {
11426 return CLI_SHOWUSAGE;
11427 }
11428
11429 /* Set the queue name if applicable */
11430 if (a->argc == 8) {
11431 queuename = a->argv[7];
11432 }
11433
11434 /* Interface being set */
11435 interface = a->argv[5];
11436
11437 /* Check and set the ringinuse value */
11438 if (ast_true(a->argv[3])) {
11439 ringinuse = 1;
11440 } else if (ast_false(a->argv[3])) {
11441 ringinuse = 0;
11442 } else {
11443 return CLI_SHOWUSAGE;
11444 }
11445
11446 switch (set_member_value(queuename, interface, MEMBER_RINGINUSE, ringinuse)) {
11447 case RESULT_SUCCESS:
11448 ast_cli(a->fd, "Set ringinuse on interface '%s' from queue '%s'\n", interface, queuename);
11449 return CLI_SUCCESS;
11450 case RESULT_FAILURE:
11451 ast_cli(a->fd, "Failed to set ringinuse on interface '%s' from queue '%s'\n", interface, queuename);
11452 return CLI_FAILURE;
11453 default:
11454 return CLI_FAILURE;
11455 }
11456}
int attribute_pure ast_false(const char *val)
Make sure something is false. Determine if a string containing a boolean value is "false"....
Definition: utils.c:2216

References a, ast_cli(), ast_false(), ast_true(), CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, complete_queue_set_member_value(), MEMBER_RINGINUSE, NULL, RESULT_FAILURE, RESULT_SUCCESS, set_member_value(), and ast_cli_entry::usage.

◆ hangupcalls()

static void hangupcalls ( struct queue_ent qe,
struct callattempt outgoing,
struct ast_channel exception,
int  cancel_answered_elsewhere 
)
static

Hang up a list of outgoing calls.

Definition at line 4498 of file app_queue.c.

4499{
4500 struct callattempt *oo;
4501
4502 while (outgoing) {
4503 /* If someone else answered the call we should indicate this in the CANCEL */
4504 /* Hangup any existing lines we have open */
4505 if (outgoing->chan && (outgoing->chan != exception)) {
4506 if (exception || cancel_answered_elsewhere) {
4508 }
4509 ast_channel_publish_dial(qe->chan, outgoing->chan, outgoing->interface, "CANCEL");
4510
4511 /* When dialing channels it is possible that they may not ever
4512 * leave the not in use state (Local channels in particular) by
4513 * the time we cancel them. If this occurs but we know they were
4514 * dialed we explicitly remove them from the pending members
4515 * container so that subsequent call attempts occur.
4516 */
4517 if (outgoing->member->status == AST_DEVICE_NOT_INUSE) {
4519 }
4520
4521 ast_hangup(outgoing->chan);
4522 }
4523 oo = outgoing;
4524 outgoing = outgoing->q_next;
4526 callattempt_free(oo);
4527 }
4528}
void * ast_aoc_destroy_decoded(struct ast_aoc_decoded *decoded)
free an ast_aoc_decoded object
Definition: aoc.c:307
static void callattempt_free(struct callattempt *doomed)
Definition: app_queue.c:4476
#define AST_CAUSE_ANSWERED_ELSEWHERE
Definition: causes.h:114
void ast_channel_hangupcause_set(struct ast_channel *chan, int value)
void ast_channel_publish_dial(struct ast_channel *caller, struct ast_channel *peer, const char *dialstring, const char *dialstatus)
Publish in the ast_channel_topic or ast_channel_topic_all topics a stasis message for the channels in...
struct ast_aoc_decoded * aoc_s_rate_list
Definition: app_queue.c:1715
struct ast_channel * chan
Definition: app_queue.c:1749

References callattempt::aoc_s_rate_list, ast_aoc_destroy_decoded(), AST_CAUSE_ANSWERED_ELSEWHERE, ast_channel_hangupcause_set(), ast_channel_publish_dial(), AST_DEVICE_NOT_INUSE, ast_hangup(), callattempt_free(), queue_ent::chan, and pending_members_remove().

Referenced by try_calling().

◆ init_queue()

static void init_queue ( struct call_queue q)
static

Initialize Queue default values.

Note
the queue's lock must be held before executing this function

Definition at line 2978 of file app_queue.c.

2979{
2980 int i;
2981 struct penalty_rule *pr_iter;
2982
2983 q->dead = 0;
2984 q->retry = DEFAULT_RETRY;
2986 q->maxlen = 0;
2987
2988 ast_string_field_set(q, announce, "");
2990 ast_string_field_set(q, membergosub, "");
2991 ast_string_field_set(q, defaultrule, "");
2992
2993 q->announcefrequency = 0;
2995 q->announceholdtime = 1;
2997 q->announcepositionlimit = 10; /* Default 10 positions */
2998 q->announceposition = ANNOUNCEPOSITION_YES; /* Default yes */
2999 q->roundingseconds = 0; /* Default - don't announce seconds */
3000 q->servicelevel = 0;
3001 q->ringinuse = 1;
3003 q->setinterfacevar = 0;
3004 q->setqueuevar = 0;
3005 q->setqueueentryvar = 0;
3007 q->monfmt[0] = '\0';
3008 q->reportholdtime = 0;
3009 q->wrapuptime = 0;
3010 q->penaltymemberslimit = 0;
3011 q->joinempty = 0;
3012 q->leavewhenempty = 0;
3013 q->memberdelay = 0;
3014 q->weight = 0;
3015 q->timeoutrestart = 0;
3019 q->numperiodicannounce = 0;
3022 q->autopausebusy = 0;
3023 q->autopauseunavail = 0;
3025 q->autopausedelay = 0;
3027 if (!q->members) {
3029 /* linear strategy depends on order, so we have to place all members in a list */
3031 } else {
3034 }
3035 }
3036 q->found = 1;
3037
3038 ast_string_field_set(q, moh, "");
3039 ast_string_field_set(q, sound_next, "queue-youarenext");
3040 ast_string_field_set(q, sound_thereare, "queue-thereare");
3041 ast_string_field_set(q, sound_calls, "queue-callswaiting");
3042 ast_string_field_set(q, queue_quantity1, "queue-quantity1");
3043 ast_string_field_set(q, queue_quantity2, "queue-quantity2");
3044 ast_string_field_set(q, sound_holdtime, "queue-holdtime");
3045 ast_string_field_set(q, sound_minutes, "queue-minutes");
3046 ast_string_field_set(q, sound_minute, "queue-minute");
3047 ast_string_field_set(q, sound_seconds, "queue-seconds");
3048 ast_string_field_set(q, sound_thanks, "queue-thankyou");
3049 ast_string_field_set(q, sound_callerannounce, "");
3050 ast_string_field_set(q, sound_reporthold, "queue-reporthold");
3051
3052 if (!q->sound_periodicannounce[0]) {
3054 }
3055
3056 if (q->sound_periodicannounce[0]) {
3057 ast_str_set(&q->sound_periodicannounce[0], 0, "queue-periodic-announce");
3058 }
3059
3060 for (i = 1; i < MAX_PERIODIC_ANNOUNCEMENTS; i++) {
3061 if (q->sound_periodicannounce[i]) {
3062 ast_str_set(&q->sound_periodicannounce[i], 0, "%s", "");
3063 }
3064 }
3065
3066 while ((pr_iter = AST_LIST_REMOVE_HEAD(&q->rules,list))) {
3067 ast_free(pr_iter);
3068 }
3069
3070 /* On restart assume no members are available.
3071 * The queue_avail hint is a boolean state to indicate whether a member is available or not.
3072 *
3073 * This seems counter intuitive, but is required to light a BLF
3074 * AST_DEVICE_INUSE indicates no members are available.
3075 * AST_DEVICE_NOT_INUSE indicates a member is available.
3076 */
3078}
#define DEFAULT_RETRY
Definition: app_queue.c:1582
static int member_hash_fn(const void *obj, const int flags)
Definition: app_queue.c:2949
static int member_cmp_fn(void *obj1, void *obj2, int flags)
Definition: app_queue.c:2965
#define DEFAULT_MIN_ANNOUNCE_FREQUENCY
The minimum number of seconds between position announcements.
Definition: app_queue.c:1590
#define DEFAULT_TIMEOUT
Definition: app_queue.c:1583
static int autofill_default
queues.conf [general] option
Definition: app_queue.c:1625
#define ANNOUNCEPOSITION_YES
Definition: app_queue.c:1815
@ AO2_ALLOC_OPT_LOCK_MUTEX
Definition: astobj2.h:363
#define ao2_container_alloc_list(ao2_options, container_options, sort_fn, cmp_fn)
Allocate and initialize a list container.
Definition: astobj2.h:1327
#define ao2_container_alloc_hash(ao2_options, container_options, n_buckets, hash_fn, sort_fn, cmp_fn)
Allocate and initialize a hash container with the desired number of buckets.
Definition: astobj2.h:1303
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:833
unsigned int autopauseunavail
Definition: app_queue.c:1878
unsigned int setinterfacevar
Definition: app_queue.c:1864
int announcefrequency
Definition: app_queue.c:1882
unsigned int announceholdtime
Definition: app_queue.c:1870
unsigned int reportholdtime
Definition: app_queue.c:1867
unsigned int setqueueentryvar
Definition: app_queue.c:1866
unsigned int timeoutrestart
Definition: app_queue.c:1869
int periodicannouncefrequency
Definition: app_queue.c:1885
unsigned int announceposition_only_up
Definition: app_queue.c:1872
unsigned int setqueuevar
Definition: app_queue.c:1865
int announcepositionlimit
Definition: app_queue.c:1881
unsigned int announce_to_first_user
Definition: app_queue.c:1863
int randomperiodicannounce
Definition: app_queue.c:1887
int autopause
Definition: app_queue.c:1905
int periodicannouncestartdelay
Definition: app_queue.c:1884
int log_restricted_caller_id
Definition: app_queue.c:1914
struct call_queue::@54 rules
int servicelevel
Definition: app_queue.c:1894
int autofill
Definition: app_queue.c:1912
int minannouncefrequency
Definition: app_queue.c:1883
enum empty_conditions leavewhenempty
Definition: app_queue.c:1880
int roundingseconds
Definition: app_queue.c:1888
int numperiodicannounce
Definition: app_queue.c:1886
unsigned int announceposition
Definition: app_queue.c:1871
char monfmt[8]
Definition: app_queue.c:1896
enum empty_conditions joinempty
Definition: app_queue.c:1879
int memberdelay
Definition: app_queue.c:1911
unsigned int autopausebusy
Definition: app_queue.c:1877
int autopausedelay
Definition: app_queue.c:1906
int timeoutpriority
Definition: app_queue.c:1907
unsigned int relativeperiodicannounce
Definition: app_queue.c:1876

References call_queue::announce_to_first_user, call_queue::announcefrequency, call_queue::announceholdtime, call_queue::announceposition, call_queue::announceposition_only_up, ANNOUNCEPOSITION_YES, call_queue::announcepositionlimit, AO2_ALLOC_OPT_LOCK_MUTEX, ao2_container_alloc_hash, ao2_container_alloc_list, AST_DEVICE_INUSE, AST_DEVSTATE_CACHABLE, ast_devstate_changed(), ast_free, AST_LIST_REMOVE_HEAD, ast_str_create, ast_str_set(), ast_string_field_set, call_queue::autofill, autofill_default, call_queue::autopause, call_queue::autopausebusy, call_queue::autopausedelay, call_queue::autopauseunavail, voicemailpwcheck::context, call_queue::dead, DEFAULT_MIN_ANNOUNCE_FREQUENCY, DEFAULT_RETRY, DEFAULT_TIMEOUT, call_queue::found, call_queue::joinempty, call_queue::leavewhenempty, penalty_rule::list, call_queue::log_restricted_caller_id, 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::name, NULL, call_queue::numperiodicannounce, call_queue::penaltymemberslimit, call_queue::periodicannouncefrequency, call_queue::periodicannouncestartdelay, QUEUE_AUTOPAUSE_OFF, QUEUE_STRATEGY_LINEAR, QUEUE_STRATEGY_RRORDERED, call_queue::randomperiodicannounce, call_queue::relativeperiodicannounce, 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 find_queue_by_name_rt(), and reload_single_queue().

◆ insert_entry()

static void insert_entry ( struct call_queue q,
struct queue_ent prev,
struct queue_ent new,
int *  pos 
)
inlinestatic

Insert the 'new' entry after the 'prev' entry of queue 'q'.

Definition at line 2118 of file app_queue.c.

2119{
2120 struct queue_ent *cur;
2121
2122 if (!q || !new)
2123 return;
2124 if (prev) {
2125 cur = prev->next;
2126 prev->next = new;
2127 } else {
2128 cur = q->head;
2129 q->head = new;
2130 }
2131 new->next = cur;
2132
2133 /* every queue_ent must have a reference to it's parent call_queue, this
2134 * reference does not go away until the end of the queue_ent's life, meaning
2135 * that even when the queue_ent leaves the call_queue this ref must remain. */
2136 if (!new->parent) {
2137 queue_ref(q);
2138 new->parent = q;
2139 }
2140 new->pos = ++(*pos);
2141 new->opos = *pos;
2142}
#define queue_ref(q)
Definition: app_queue.c:2084

References call_queue::head, queue_ent::next, queue_ent::pos, and queue_ref.

Referenced by change_priority_caller_on_queue(), and join_queue().

◆ insert_penaltychange()

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 formatting, see if rule is relative to rest of queue, iterate list of rules to find correct insertion point, insert and return.

Return values
-1on failure
0on success
Note
Call this with the rule_lists locked

Definition at line 3112 of file app_queue.c.

3113{
3114 char *timestr, *maxstr, *minstr, *raisestr, *contentdup;
3115 struct penalty_rule *rule = NULL, *rule_iter;
3116 struct rule_list *rl_iter;
3117 int penaltychangetime, inserted = 0;
3118
3119 if (!(rule = ast_calloc(1, sizeof(*rule)))) {
3120 return -1;
3121 }
3122
3123 contentdup = ast_strdupa(content);
3124
3125 if (!(maxstr = strchr(contentdup, ','))) {
3126 ast_log(LOG_WARNING, "Improperly formatted penaltychange rule at line %d. Ignoring.\n", linenum);
3127 ast_free(rule);
3128 return -1;
3129 }
3130
3131 *maxstr++ = '\0';
3132 if ((minstr = strchr(maxstr,','))) {
3133 *minstr++ = '\0';
3134 if ((raisestr = strchr(minstr,','))) {
3135 *raisestr++ = '\0';
3136 }
3137 } else {
3138 raisestr = NULL;
3139 }
3140
3141 timestr = contentdup;
3142 if ((penaltychangetime = atoi(timestr)) < 0) {
3143 ast_log(LOG_WARNING, "Improper time parameter specified for penaltychange rule at line %d. Ignoring.\n", linenum);
3144 ast_free(rule);
3145 return -1;
3146 }
3147
3148 rule->time = penaltychangetime;
3149
3150 /* The last check will evaluate true if either no penalty change is indicated for a given rule
3151 * OR if a min penalty change is indicated but no max penalty change is */
3152 if (*maxstr == '+' || *maxstr == '-' || *maxstr == '\0') {
3153 rule->max_relative = 1;
3154 }
3155
3156 rule->max_value = atoi(maxstr);
3157
3158 if (!ast_strlen_zero(minstr)) {
3159 if (*minstr == '+' || *minstr == '-') {
3160 rule->min_relative = 1;
3161 }
3162 rule->min_value = atoi(minstr);
3163 } else { /*there was no minimum specified, so assume this means no change*/
3164 rule->min_relative = 1;
3165 }
3166
3167 if (!ast_strlen_zero(raisestr)) {
3168 if (*raisestr == '+' || *raisestr == '-') {
3169 rule->raise_relative = 1;
3170 }
3171 rule->raise_value = atoi(raisestr);
3172 } else { /*there was no raise specified, so assume this means no change*/
3173 rule->raise_relative = 1;
3174 }
3175
3176 /*We have the rule made, now we need to insert it where it belongs*/
3177 AST_LIST_TRAVERSE(&rule_lists, rl_iter, list){
3178 if (strcasecmp(rl_iter->name, list_name)) {
3179 continue;
3180 }
3181
3182 AST_LIST_TRAVERSE_SAFE_BEGIN(&rl_iter->rules, rule_iter, list) {
3183 if (rule->time < rule_iter->time) {
3185 inserted = 1;
3186 break;
3187 }
3188 }
3190
3191 if (!inserted) {
3192 AST_LIST_INSERT_TAIL(&rl_iter->rules, rule, list);
3193 inserted = 1;
3194 }
3195
3196 break;
3197 }
3198
3199 if (!inserted) {
3200 ast_log(LOG_WARNING, "Unknown rule list name %s; ignoring.\n", list_name);
3201 ast_free(rule);
3202 return -1;
3203 }
3204 return 0;
3205}
#define AST_LIST_TRAVERSE_SAFE_END
Closes a safe loop traversal block.
Definition: linkedlists.h:615
#define AST_LIST_INSERT_BEFORE_CURRENT(elm, field)
Inserts a list entry before the current entry during a traversal.
Definition: linkedlists.h:599
#define AST_LIST_TRAVERSE_SAFE_BEGIN(head, var, field)
Loops safely over (traverses) the entries in a list.
Definition: linkedlists.h:529

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, NULL, and rule_list::rules.

Referenced by reload_queue_rules().

◆ int2strat()

static const char * int2strat ( int  strategy)
static

Definition at line 1951 of file app_queue.c.

1952{
1953 int x;
1954
1955 for (x = 0; x < ARRAY_LEN(strategies); x++) {
1956 if (strategy == strategies[x].strategy) {
1957 return strategies[x].name;
1958 }
1959 }
1960
1961 return "<unknown>";
1962}
static const struct strategy strategies[]
const char * name
Definition: app_queue.c:1560

References ARRAY_LEN, strategy::name, and strategies.

Referenced by manager_queues_status(), print_queue(), queue_function_var(), and set_queue_variables().

◆ interface_exists()

static struct member * interface_exists ( struct call_queue q,
const char *  interface 
)
static

Definition at line 7487 of file app_queue.c.

7488{
7489 struct member *mem;
7490 struct ao2_iterator mem_iter;
7491
7492 if (!q) {
7493 return NULL;
7494 }
7495 mem_iter = ao2_iterator_init(q->members, 0);
7496 while ((mem = ao2_iterator_next(&mem_iter))) {
7497 if (!strcasecmp(interface, mem->interface)) {
7498 ao2_iterator_destroy(&mem_iter);
7499 return mem;
7500 }
7501 ao2_ref(mem, -1);
7502 }
7503 ao2_iterator_destroy(&mem_iter);
7504
7505 return NULL;
7506}

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_ref, member::interface, call_queue::members, and NULL.

Referenced by add_to_queue(), get_interface_helper(), get_member_penalty(), rna(), set_member_paused(), set_member_penalty_help_members(), and set_member_ringinuse_help_members().

◆ is_longest_waiting_caller()

static int is_longest_waiting_caller ( struct queue_ent caller,
struct member member 
)
static

Definition at line 4605 of file app_queue.c.

4606{
4607 struct call_queue *q;
4608 struct member *mem;
4609 int is_longest_waiting = 1;
4610 struct ao2_iterator queue_iter;
4611 struct queue_ent *ch;
4612
4613 queue_iter = ao2_iterator_init(queues, 0);
4614 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
4615 if (q == caller->parent) { /* don't check myself, could deadlock */
4616 queue_t_unref(q, "Done with iterator");
4617 continue;
4618 }
4619 ao2_lock(q);
4620 /*
4621 * If the other queue has equal weight, see if we should let that handle
4622 * their call first. If weights are not equal, compare_weights will step in.
4623 */
4624 if (q->weight == caller->parent->weight && q->count && q->members) {
4625 if ((mem = ao2_find(q->members, member, OBJ_POINTER))) {
4626 ast_debug(2, "Found matching member %s in queue '%s'\n", mem->interface, q->name);
4627
4628 /* Does this queue have a caller that's been waiting longer? */
4629 ch = q->head;
4630 while (ch) {
4631 /* If ch->pending, the other call (which may be waiting for a longer period of time),
4632 * is already ringing at another agent. Ignore such callers; otherwise, all agents
4633 * will be unused until the first caller is picked up.
4634 */
4635 if (ch->start < caller->start && !ch->pending) {
4636 ast_debug(1, "Queue %s has a call at position %i that's been waiting longer (%li vs %li)\n",
4637 q->name, ch->pos, ch->start, caller->start);
4638 is_longest_waiting = 0;
4639 break;
4640 }
4641 ch = ch->next;
4642 }
4643 }
4644 }
4645 ao2_unlock(q);
4646 queue_t_unref(q, "Done with iterator");
4647 if (!is_longest_waiting) {
4648 break;
4649 }
4650 }
4651 ao2_iterator_destroy(&queue_iter);
4652 return is_longest_waiting;
4653}
int pending
Definition: app_queue.c:1738
time_t start
Definition: app_queue.c:1744

References ao2_find, ao2_iterator_destroy(), ao2_iterator_init(), ao2_lock, ao2_t_iterator_next, ao2_unlock, ast_debug, call_queue::count, call_queue::head, member::interface, call_queue::members, call_queue::name, queue_ent::next, OBJ_POINTER, queue_ent::parent, queue_ent::pending, queue_ent::pos, queue_t_unref, queues, queue_ent::start, and call_queue::weight.

Referenced by can_ring_entry().

◆ is_member_available()

static int is_member_available ( struct call_queue q,
struct member mem 
)
static

Definition at line 2635 of file app_queue.c.

2636{
2637 int available = 0;
2638 int wrapuptime;
2639
2640 switch (mem->status) {
2641 case AST_DEVICE_INVALID:
2643 break;
2644 case AST_DEVICE_INUSE:
2645 case AST_DEVICE_BUSY:
2646 case AST_DEVICE_RINGING:
2648 case AST_DEVICE_ONHOLD:
2649 if (!mem->ringinuse) {
2650 break;
2651 }
2652 /* else fall through */
2654 case AST_DEVICE_UNKNOWN:
2655 if (!mem->paused) {
2656 available = 1;
2657 }
2658 break;
2659 }
2660
2661 /* Let wrapuptimes override device state availability */
2662 wrapuptime = get_wrapuptime(q, mem);
2663 if (mem->lastcall && wrapuptime && (time(NULL) - wrapuptime < mem->lastcall)) {
2664 available = 0;
2665 }
2666 return available;
2667}
static int available(struct dahdi_pvt **pvt, int is_specific_channel)
Definition: chan_dahdi.c:13477

References AST_DEVICE_BUSY, AST_DEVICE_INUSE, AST_DEVICE_INVALID, AST_DEVICE_NOT_INUSE, AST_DEVICE_ONHOLD, AST_DEVICE_RINGING, AST_DEVICE_RINGINUSE, AST_DEVICE_UNAVAILABLE, AST_DEVICE_UNKNOWN, available(), get_wrapuptime(), member::lastcall, NULL, member::paused, member::ringinuse, member::status, and member::wrapuptime.

Referenced by add_to_queue(), device_state_cb(), num_available_members(), and set_queue_member_pause().

◆ is_our_turn()

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.

Parameters
[in]qeThe caller who wants to know if it is his turn
Return values
0It is not our turn
1It is our turn

Definition at line 5774 of file app_queue.c.

5775{
5776 struct queue_ent *ch;
5777 int res;
5778 int avl;
5779 int idx = 0;
5780 /* This needs a lock. How many members are available to be served? */
5781 ao2_lock(qe->parent);
5782
5783 avl = num_available_members(qe->parent);
5784
5785 ch = qe->parent->head;
5786
5787 ast_debug(1, "There %s %d available %s.\n", avl != 1 ? "are" : "is", avl, avl != 1 ? "members" : "member");
5788
5789 while ((idx < avl) && (ch) && (ch != qe)) {
5790 if (!ch->pending) {
5791 idx++;
5792 }
5793 ch = ch->next;
5794 }
5795
5796 ao2_unlock(qe->parent);
5797 /* If the queue entry is within avl [the number of available members] calls from the top ...
5798 * Autofill and position check added to support autofill=no (as only calls
5799 * from the front of the queue are valid when autofill is disabled)
5800 */
5801 if (ch && idx < avl && (qe->parent->autofill || qe->pos == 1)) {
5802 ast_debug(1, "It's our turn (%s).\n", ast_channel_name(qe->chan));
5803 res = 1;
5804 } else {
5805 ast_debug(1, "It's not our turn (%s).\n", ast_channel_name(qe->chan));
5806 res = 0;
5807 }
5808
5809 /* Update realtime members if this is the first call and number of avalable members is 0 */
5810 if (avl == 0 && qe->pos == 1) {
5812 }
5813
5814 return res;
5815}

References ao2_lock, ao2_unlock, ast_channel_name(), ast_debug, call_queue::autofill, queue_ent::chan, call_queue::head, queue_ent::next, num_available_members(), queue_ent::parent, queue_ent::pending, queue_ent::pos, and update_realtime_members().

Referenced by queue_exec(), and wait_our_turn().

◆ join_queue()

static int join_queue ( char *  queuename,
struct queue_ent qe,
enum queue_result reason,
int  position 
)
static

Definition at line 4088 of file app_queue.c.

4089{
4090 struct call_queue *q;
4091 struct queue_ent *cur, *prev = NULL;
4092 int res = -1;
4093 int pos = 0;
4094 int inserted = 0;
4095
4096 if (!(q = find_load_queue_rt_friendly(queuename))) {
4097 return res;
4098 }
4099 ao2_lock(q);
4100
4101 /* This is our one */
4102 if (q->joinempty) {
4103 int status = 0;
4104 if ((status = get_member_status(q, qe->max_penalty, qe->min_penalty, qe->raise_penalty, q->joinempty, 0))) {
4105 *reason = QUEUE_JOINEMPTY;
4106 ao2_unlock(q);
4107 queue_t_unref(q, "Done with realtime queue");
4108 return res;
4109 }
4110 }
4111 if (*reason == QUEUE_UNKNOWN && q->maxlen && (q->count >= q->maxlen)) {
4112 *reason = QUEUE_FULL;
4113 } else if (*reason == QUEUE_UNKNOWN) {
4114 RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
4115
4116 /* There's space for us, put us at the right position inside
4117 * the queue.
4118 * Take into account the priority of the calling user */
4119 inserted = 0;
4120 prev = NULL;
4121 cur = q->head;
4122 while (cur) {
4123 /* We have higher priority than the current user, enter
4124 * before him, after all the other users with priority
4125 * higher or equal to our priority. */
4126 if ((!inserted) && (qe->prio > cur->prio)) {
4127 insert_entry(q, prev, qe, &pos);
4128 inserted = 1;
4129 }
4130 /* <= is necessary for the position comparison because it may not be possible to enter
4131 * at our desired position since higher-priority callers may have taken the position we want
4132 */
4133 if (!inserted && (qe->prio >= cur->prio) && position && (position <= pos + 1)) {
4134 insert_entry(q, prev, qe, &pos);
4135 inserted = 1;
4136 /*pos is incremented inside insert_entry, so don't need to add 1 here*/
4137 if (position < pos) {
4138 ast_log(LOG_NOTICE, "Asked to be inserted at position %d but forced into position %d due to higher priority callers\n", position, pos);
4139 }
4140 }
4141 cur->pos = ++pos;
4142 prev = cur;
4143 cur = cur->next;
4144 }
4145 /* No luck, join at the end of the queue */
4146 if (!inserted) {
4147 insert_entry(q, prev, qe, &pos);
4148 }
4149 ast_copy_string(qe->moh, q->moh, sizeof(qe->moh));
4150 ast_copy_string(qe->announce, q->announce, sizeof(qe->announce));
4151 ast_copy_string(qe->context, q->context, sizeof(qe->context));
4152 q->count++;
4153 if (q->count == 1) {
4155 }
4156
4157 res = 0;
4158
4159 blob = ast_json_pack("{s: s, s: i, s: i}",
4160 "Queue", q->name,
4161 "Position", qe->pos,
4162 "Count", q->count);
4163 ast_channel_publish_cached_blob(qe->chan, queue_caller_join_type(), blob);
4164 ast_debug(1, "Queue '%s' Join, Channel '%s', Position '%d'\n", q->name, ast_channel_name(qe->chan), qe->pos );
4165 }
4166 ao2_unlock(q);
4167 queue_t_unref(q, "Done with realtime queue");
4168
4169 return res;
4170}
jack_status_t status
Definition: app_jack.c:146
void ast_channel_publish_cached_blob(struct ast_channel *chan, struct stasis_message_type *type, struct ast_json *blob)
Publish a channel blob message using the latest snapshot from the cache.
void ast_json_unref(struct ast_json *value)
Decrease refcount on value. If refcount reaches zero, value is freed.
Definition: json.c:73
struct ast_json * ast_json_pack(char const *format,...)
Helper for creating complex JSON values.
Definition: json.c:612
Abstract JSON element (object, array, string, int, ...).
const ast_string_field moh
Definition: app_queue.c:1858
const ast_string_field context
Definition: app_queue.c:1858
const ast_string_field announce
Definition: app_queue.c:1858
char announce[PATH_MAX]
Definition: app_queue.c:1724
char moh[MAX_MUSICCLASS]
Definition: app_queue.c:1723
char context[AST_MAX_CONTEXT]
Definition: app_queue.c:1725

References queue_ent::announce, call_queue::announce, ao2_lock, ao2_unlock, ast_channel_name(), ast_channel_publish_cached_blob(), ast_copy_string(), ast_debug, AST_DEVICE_RINGING, AST_DEVSTATE_CACHABLE, ast_devstate_changed(), ast_json_pack(), ast_json_unref(), ast_log, queue_ent::chan, queue_ent::context, call_queue::context, call_queue::count, find_load_queue_rt_friendly(), get_member_status(), call_queue::head, insert_entry(), call_queue::joinempty, LOG_NOTICE, queue_ent::max_penalty, call_queue::maxlen, queue_ent::min_penalty, queue_ent::moh, call_queue::moh, call_queue::name, queue_ent::next, NULL, queue_ent::pos, queue_ent::prio, QUEUE_FULL, QUEUE_JOINEMPTY, queue_t_unref, QUEUE_UNKNOWN, RAII_VAR, queue_ent::raise_penalty, and status.

Referenced by queue_exec().

◆ kill_dead_members()

static int kill_dead_members ( void *  obj,
void *  arg,
int  flags 
)
static

Definition at line 9800 of file app_queue.c.

9801{
9802 struct member *member = obj;
9803
9804 if (!member->delme) {
9806 return 0;
9807 } else {
9808 return CMP_MATCH;
9809 }
9810}
@ CMP_MATCH
Definition: astobj2.h:1027
unsigned int delme
Definition: app_queue.c:1778

References CMP_MATCH, member::delme, get_queue_member_status(), and member::status.

Referenced by reload_single_queue().

◆ kill_if_unfound()

static int kill_if_unfound ( void *  obj,
void *  arg,
int  flags 
)
static

Definition at line 9955 of file app_queue.c.

9956{
9957 struct call_queue *q = obj;
9958 char *queuename = arg;
9959 if (!q->realtime && !q->found && (ast_strlen_zero(queuename) || !strcasecmp(queuename, q->name))) {
9960 q->dead = 1;
9961 return CMP_MATCH;
9962 } else {
9963 return 0;
9964 }
9965}

References ast_strlen_zero(), CMP_MATCH, call_queue::dead, call_queue::found, call_queue::name, and call_queue::realtime.

Referenced by reload_queues().

◆ leave_queue()

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 4401 of file app_queue.c.

4402{
4403 struct call_queue *q;
4404 struct queue_ent *current, *prev = NULL;
4405 struct penalty_rule *pr_iter;
4406 int pos = 0;
4407
4408 if (!(q = qe->parent)) {
4409 return;
4410 }
4411 queue_t_ref(q, "Copy queue pointer from queue entry");
4412 ao2_lock(q);
4413
4414 prev = NULL;
4415 for (current = q->head; current; current = current->next) {
4416 if (current == qe) {
4417 RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
4418 char posstr[20];
4419 q->count--;
4420 if (!q->count) {
4422 }
4423
4424 blob = ast_json_pack("{s: s, s: i, s: i}",
4425 "Queue", q->name,
4426 "Position", qe->pos,
4427 "Count", q->count);
4428 ast_channel_publish_cached_blob(qe->chan, queue_caller_leave_type(), blob);
4429 ast_debug(1, "Queue '%s' Leave, Channel '%s'\n", q->name, ast_channel_name(qe->chan));
4430 /* Take us out of the queue */
4431 if (prev) {
4432 prev->next = current->next;
4433 } else {
4434 q->head = current->next;
4435 }
4436 /* Free penalty rules */
4437 while ((pr_iter = AST_LIST_REMOVE_HEAD(&qe->qe_rules, list))) {
4438 ast_free(pr_iter);
4439 }
4440 qe->pr = NULL;
4441 snprintf(posstr, sizeof(posstr), "%d", qe->pos);
4442 pbx_builtin_setvar_helper(qe->chan, "QUEUEPOSITION", posstr);
4443 } else {
4444 /* Renumber the people after us in the queue based on a new count */
4445 current->pos = ++pos;
4446 prev = current;
4447 }
4448 }
4449 ao2_unlock(q);
4450
4451 /*If the queue is a realtime queue, check to see if it's still defined in real time*/
4452 if (q->realtime) {
4453 struct ast_variable *var;
4454 if (!(var = ast_load_realtime("queues", "name", q->name, SENTINEL))) {
4455 q->dead = 1;
4456 } else {
4458 }
4459 }
4460
4461 if (q->dead) {
4462 /* It's dead and nobody is in it, so kill it */
4463 queues_t_unlink(queues, q, "Queue is now dead; remove it from the container");
4464 }
4465 /* unref the explicit ref earlier in the function */
4466 queue_t_unref(q, "Expire copied reference");
4467}
#define queue_t_ref(q, tag)
Definition: app_queue.c:2086
#define var
Definition: ast_expr2f.c:605
struct penalty_rule * pr
Definition: app_queue.c:1751

References ao2_lock, ao2_unlock, ast_channel_name(), ast_channel_publish_cached_blob(), ast_debug, AST_DEVICE_NOT_INUSE, AST_DEVSTATE_CACHABLE, ast_devstate_changed(), ast_free, ast_json_pack(), ast_json_unref(), AST_LIST_REMOVE_HEAD, ast_load_realtime(), ast_variables_destroy(), queue_ent::chan, call_queue::count, current, call_queue::dead, call_queue::head, penalty_rule::list, call_queue::name, queue_ent::next, NULL, queue_ent::parent, pbx_builtin_setvar_helper(), queue_ent::pos, queue_ent::pr, queue_ent::qe_rules, queue_t_ref, queue_t_unref, queues, queues_t_unlink, RAII_VAR, call_queue::realtime, SENTINEL, and var.

Referenced by queue_exec(), and try_calling().

◆ load_module()

static int load_module ( void  )
static

Load the module.

Module loading including tests for configuration or dependencies. This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE, or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails tests return AST_MODULE_LOAD_FAILURE. If the module can not load the configuration file or other non-critical problem return AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS.

Definition at line 11830 of file app_queue.c.

11831{
11832 int err = 0;
11833 struct ast_flags mask = {AST_FLAGS_ALL, };
11834 struct ast_config *member_config;
11835 struct stasis_topic *queue_topic;
11837
11840 if (!queues) {
11842 }
11843
11846 if (!pending_members) {
11847 unload_module();
11849 }
11850
11851 use_weight = 0;
11852
11853 if (reload_handler(0, &mask, NULL)) {
11854 unload_module();
11856 }
11857
11858 ast_realtime_require_field("queue_members", "paused", RQ_INTEGER1, 1, "uniqueid", RQ_UINTEGER2, 5, "reason_paused", RQ_CHAR, 80, SENTINEL);
11859
11860 /*
11861 * This section is used to determine which name for 'ringinuse' to use in realtime members
11862 * Necessary for supporting older setups.
11863 *
11864 * It also checks if 'reason_paused' exists in the realtime backend
11865 */
11866 member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name LIKE", "%", SENTINEL);
11867 if (!member_config) {
11868 realtime_ringinuse_field = "ringinuse";
11869 } else {
11870 const char *config_val;
11871
11872 if ((config_val = ast_variable_retrieve(member_config, NULL, "ringinuse"))) {
11873 ast_log(LOG_NOTICE, "ringinuse field entries found in queue_members table. Using 'ringinuse'\n");
11874 realtime_ringinuse_field = "ringinuse";
11875 } else if ((config_val = ast_variable_retrieve(member_config, NULL, "ignorebusy"))) {
11876 ast_log(LOG_NOTICE, "ignorebusy field found in queue_members table with no ringinuse field. Using 'ignorebusy'\n");
11877 realtime_ringinuse_field = "ignorebusy";
11878 } else {
11879 ast_log(LOG_NOTICE, "No entries were found for ringinuse/ignorebusy in queue_members table. Using 'ringinuse'\n");
11880 realtime_ringinuse_field = "ringinuse";
11881 }
11882
11883 if (ast_variable_retrieve(member_config, NULL, "reason_paused")) {
11885 }
11886 }
11887 ast_config_destroy(member_config);
11888
11891 }
11892
11901 err |= ast_manager_register_xml("QueueStatus", 0, manager_queues_status);
11902 err |= ast_manager_register_xml("QueueSummary", 0, manager_queues_summary);
11909 err |= ast_manager_register_xml("QueueRule", 0, manager_queue_rule_show);
11910 err |= ast_manager_register_xml("QueueReload", 0, manager_queue_reload);
11911 err |= ast_manager_register_xml("QueueReset", 0, manager_queue_reset);
11912 err |= ast_manager_register_xml("QueueChangePriorityCaller", 0, manager_change_priority_caller_on_queue);
11922
11923 /* in the following subscribe call, do I use DEVICE_STATE, or DEVICE_STATE_CHANGE? */
11925 if (!device_state_sub) {
11926 err = -1;
11927 }
11930
11932 queue_topic = ast_queue_topic_all();
11933 if (!manager_topic || !queue_topic) {
11934 unload_module();
11936 }
11938 if (!topic_forwarder) {
11939 unload_module();
11941 }
11942
11945 unload_module();
11947 }
11949 if (!agent_router) {
11950 unload_module();
11952 }
11956 NULL);
11960 NULL);
11961
11962 err |= STASIS_MESSAGE_TYPE_INIT(queue_caller_join_type);
11963 err |= STASIS_MESSAGE_TYPE_INIT(queue_caller_leave_type);
11964 err |= STASIS_MESSAGE_TYPE_INIT(queue_caller_abandon_type);
11965
11966 err |= STASIS_MESSAGE_TYPE_INIT(queue_member_status_type);
11967 err |= STASIS_MESSAGE_TYPE_INIT(queue_member_added_type);
11968 err |= STASIS_MESSAGE_TYPE_INIT(queue_member_removed_type);
11969 err |= STASIS_MESSAGE_TYPE_INIT(queue_member_pause_type);
11970 err |= STASIS_MESSAGE_TYPE_INIT(queue_member_penalty_type);
11971 err |= STASIS_MESSAGE_TYPE_INIT(queue_member_ringinuse_type);
11972
11973 err |= STASIS_MESSAGE_TYPE_INIT(queue_agent_called_type);
11974 err |= STASIS_MESSAGE_TYPE_INIT(queue_agent_connect_type);
11975 err |= STASIS_MESSAGE_TYPE_INIT(queue_agent_complete_type);
11976 err |= STASIS_MESSAGE_TYPE_INIT(queue_agent_dump_type);
11977 err |= STASIS_MESSAGE_TYPE_INIT(queue_agent_ringnoanswer_type);
11978
11979 if (err) {
11980 unload_module();
11982 }
11984}
static struct ast_custom_function queuevar_function
Definition: app_queue.c:9495
static int manager_queue_reset(struct mansession *s, const struct message *m)
Definition: app_queue.c:10864
static int pending_members_cmp(void *obj, void *arg, int flags)
Definition: app_queue.c:2565
static struct ast_custom_function queuemembercount_function
Definition: app_queue.c:9500
static struct ast_custom_function queuewaitingcount_function
Definition: app_queue.c:9516
static char * app_pqm
Definition: app_queue.c:1607
static struct ast_custom_function queuememberlist_function
Definition: app_queue.c:9521
static char * realtime_ringinuse_field
name of the ringinuse field in the realtime database
Definition: app_queue.c:1649
static int manager_add_queue_member(struct mansession *s, const struct message *m)
Definition: app_queue.c:10674
static int aqm_exec(struct ast_channel *chan, const char *data)
AddQueueMember application.
Definition: app_queue.c:8383
#define MAX_QUEUE_BUCKETS
Definition: app_queue.c:1592
static int upqm_exec(struct ast_channel *chan, const char *data)
UnpauseQueueMember application.
Definition: app_queue.c:8276
static void queue_agent_cb(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Definition: app_queue.c:6189
static char * app_ql
Definition: app_queue.c:1611
static void reload_queue_members(void)
Reload dynamic queue members persisted into the astdb.
Definition: app_queue.c:8129
static int rqm_exec(struct ast_channel *chan, const char *data)
RemoveQueueMember application.
Definition: app_queue.c:8312
#define MAX_CALL_ATTEMPT_BUCKETS
Definition: app_queue.c:2543
static char * app_rqm
Definition: app_queue.c:1605
static int manager_queue_rule_show(struct mansession *s, const struct message *m)
Definition: app_queue.c:10433
static int manager_queue_reload(struct mansession *s, const struct message *m)
Definition: app_queue.c:10832
static int pqm_exec(struct ast_channel *chan, const char *data)
PauseQueueMember application.
Definition: app_queue.c:8240
static int qupd_exec(struct ast_channel *chan, const char *data)
Update Queue with data of an outgoing call.
Definition: app_queue.c:11662
static int manager_queue_member_ringinuse(struct mansession *s, const struct message *m)
Definition: app_queue.c:10910
static char * app_qupd
Definition: app_queue.c:1613
static int manager_queue_member_penalty(struct mansession *s, const struct message *m)
Definition: app_queue.c:10944
static char * app_upqm
Definition: app_queue.c:1609
static struct ast_custom_function queuememberpenalty_function
Definition: app_queue.c:9526
static int queue_cmp_cb(void *obj, void *arg, int flags)
Definition: app_queue.c:2007
static int manager_request_withdraw_caller_from_queue(struct mansession *s, const struct message *m)
Definition: app_queue.c:11017
static char * app
Definition: app_queue.c:1601
static int queue_hash_cb(const void *obj, const int flags)
Definition: app_queue.c:2000
static int queue_exec(struct ast_channel *chan, const char *data)
The starting point for all queue calls.
Definition: app_queue.c:8554
static int pending_members_hash(const void *obj, const int flags)
Definition: app_queue.c:2545
static int manager_pause_queue_member(struct mansession *s, const struct message *m)
Definition: app_queue.c:10786
static int ql_exec(struct ast_channel *chan, const char *data)
QueueLog application.
Definition: app_queue.c:8477
static int manager_remove_queue_member(struct mansession *s, const struct message *m)
Definition: app_queue.c:10739
static struct stasis_message_router * agent_router
Definition: app_queue.c:11752
static void device_state_cb(void *unused, struct stasis_subscription *sub, struct stasis_message *msg)
set a member's status based on device state of that member's interface
Definition: app_queue.c:2670
static struct stasis_subscription * device_state_sub
Subscription to device state change messages.
Definition: app_queue.c:1637
static int manager_queues_summary(struct mansession *s, const struct message *m)
Summary of queue info via the AMI.
Definition: app_queue.c:10469
static int unload_module(void)
Definition: app_queue.c:11755
static int manager_queues_status(struct mansession *s, const struct message *m)
Queue status info via AMI.
Definition: app_queue.c:10551
static int realtime_reason_paused
does realtime backend support reason_paused
Definition: app_queue.c:1652
static struct ast_custom_function queuemembercount_dep
Definition: app_queue.c:9506
static char * app_aqm
Definition: app_queue.c:1603
static struct ast_cli_entry cli_queue[]
Definition: app_queue.c:11739
static struct ast_custom_function queuegetchannel_function
Definition: app_queue.c:9511
static struct stasis_forward * topic_forwarder
Definition: app_queue.c:11753
static struct ast_custom_function queueexists_function
Definition: app_queue.c:9490
static int manager_change_priority_caller_on_queue(struct mansession *s, const struct message *m)
Definition: app_queue.c:10970
static int manager_queue_log_custom(struct mansession *s, const struct message *m)
Definition: app_queue.c:10811
#define ast_cli_register_multiple(e, len)
Register multiple commands.
Definition: cli.h:265
struct stasis_topic * ast_device_state_topic_all(void)
Get the Stasis topic for device state messages.
Definition: devicestate.c:668
struct stasis_topic * ast_manager_get_topic(void)
Get the Stasis Message Bus API topic for AMI.
Definition: manager.c:453
static struct stasis_topic * manager_topic
A stasis_topic that all topics AMI cares about will be forwarded to.
Definition: manager.c:185
struct stasis_topic * ast_channel_topic_all(void)
A topic which publishes the events for all channels.
struct stasis_message_type * ast_channel_agent_logoff_type(void)
Message type for agent logoff on a channel.
struct stasis_message_type * ast_channel_agent_login_type(void)
Message type for agent login on a channel.
struct stasis_topic * ast_queue_topic_all(void)
Get the Stasis Message Bus API topic for queue messages.
Definition: main/app.c:3344
int ast_realtime_require_field(const char *family,...) attribute_sentinel
Inform realtime what fields that may be stored.
Definition: main/config.c:3564
#define ast_manager_register_xml(action, authority, func)
Register a manager callback using XML documentation to describe the manager.
Definition: manager.h:191
#define EVENT_FLAG_AGENT
Definition: manager.h:80
@ AST_MODULE_LOAD_SUCCESS
Definition: module.h:70
@ AST_MODULE_LOAD_DECLINE
Module has failed to load, may be in an inconsistent state.
Definition: module.h:78
#define ast_register_application_xml(app, execute)
Register an application using XML documentation.
Definition: module.h:640
#define ast_custom_function_register(acf)
Register a custom function.
Definition: pbx.h:1558
@ STASIS_SUBSCRIPTION_FILTER_SELECTIVE
Definition: stasis.h:297
int stasis_subscription_accept_message_type(struct stasis_subscription *subscription, const struct stasis_message_type *type)
Indicate to a subscription that we are interested in a message type.
Definition: stasis.c:1024
int stasis_subscription_set_filter(struct stasis_subscription *subscription, enum stasis_subscription_message_filter filter)
Set the message type filtering level on a subscription.
Definition: stasis.c:1078
#define STASIS_MESSAGE_TYPE_INIT(name)
Boiler-plate messaging macro for initializing message types.
Definition: stasis.h:1493
struct stasis_forward * stasis_forward_all(struct stasis_topic *from_topic, struct stasis_topic *to_topic)
Create a subscription which forwards all messages from one topic to another.
Definition: stasis.c:1579
#define stasis_subscribe(topic, callback, data)
Definition: stasis.h:649
#define stasis_message_router_create(topic)
Create a new message router object.
int stasis_message_router_add(struct stasis_message_router *router, struct stasis_message_type *message_type, stasis_subscription_cb callback, void *data)
Add a route to a message router.

References agent_router, AO2_ALLOC_OPT_LOCK_MUTEX, ao2_container_alloc_hash, app, app_aqm, app_pqm, app_ql, app_qupd, app_rqm, app_upqm, aqm_exec(), ARRAY_LEN, ast_channel_agent_login_type(), ast_channel_agent_logoff_type(), ast_channel_topic_all(), ast_cli_register_multiple, ast_config_destroy(), ast_custom_function_register, ast_device_state_message_type(), ast_device_state_topic_all(), AST_FLAGS_ALL, ast_load_realtime_multientry(), ast_log, ast_manager_get_topic(), ast_manager_register_xml, AST_MODULE_LOAD_DECLINE, AST_MODULE_LOAD_SUCCESS, ast_queue_topic_all(), ast_realtime_require_field(), ast_register_application_xml, ast_variable_retrieve(), cli_queue, device_state_cb(), device_state_sub, EVENT_FLAG_AGENT, LOG_NOTICE, manager_add_queue_member(), manager_change_priority_caller_on_queue(), manager_pause_queue_member(), manager_queue_log_custom(), manager_queue_member_penalty(), manager_queue_member_ringinuse(), manager_queue_reload(), manager_queue_reset(), manager_queue_rule_show(), manager_queues_status(), manager_queues_summary(), manager_remove_queue_member(), manager_request_withdraw_caller_from_queue(), manager_topic, MAX_CALL_ATTEMPT_BUCKETS, MAX_QUEUE_BUCKETS, NULL, pending_members, pending_members_cmp(), pending_members_hash(), pqm_exec(), ql_exec(), queue_agent_cb(), queue_cmp_cb(), queue_exec(), queue_hash_cb(), queue_persistent_members, queueexists_function, queuegetchannel_function, queuemembercount_dep, queuemembercount_function, queuememberlist_function, queuememberpenalty_function, queues, queuevar_function, queuewaitingcount_function, qupd_exec(), realtime_reason_paused, realtime_ringinuse_field, reload_handler(), reload_queue_members(), RQ_CHAR, RQ_INTEGER1, RQ_UINTEGER2, rqm_exec(), SENTINEL, stasis_forward_all(), stasis_message_router_add(), stasis_message_router_create, STASIS_MESSAGE_TYPE_INIT, stasis_subscribe, stasis_subscription_accept_message_type(), STASIS_SUBSCRIPTION_FILTER_SELECTIVE, stasis_subscription_set_filter(), topic_forwarder, unload_module(), upqm_exec(), and use_weight.

◆ load_realtime_queues()

static void load_realtime_queues ( const char *  queuename)
static

Definition at line 3985 of file app_queue.c.

3986{
3987 struct ast_config *cfg = NULL;
3988 char *category = NULL;
3989 const char *name = NULL;
3990 struct call_queue *q = NULL;
3991
3992 if (!ast_check_realtime("queues")) {
3993 return;
3994 }
3995
3996 if (ast_strlen_zero(queuename)) {
3997 if ((cfg = ast_load_realtime_multientry("queues", "name LIKE", "%", SENTINEL))) {
3998 while ((category = ast_category_browse(cfg, category))) {
3999 name = ast_variable_retrieve(cfg, category, "name");
4001 queue_unref(q);
4002 }
4003 }
4004 ast_config_destroy(cfg);
4005 }
4006 } else {
4007 if ((q = find_load_queue_rt_friendly(queuename))) {
4008 queue_unref(q);
4009 }
4010 }
4011}

References ast_category_browse(), ast_check_realtime(), ast_config_destroy(), ast_load_realtime_multientry(), ast_strlen_zero(), ast_variable_retrieve(), find_load_queue_rt_friendly(), name, NULL, queue_unref, and SENTINEL.

Referenced by manager_queues_status(), manager_queues_summary(), and set_member_paused().

◆ load_realtime_rules()

static int load_realtime_rules ( void  )
static

Load queue rules from realtime.

Check rule for errors with time or formatting, see if rule is relative to rest of queue, iterate list of rules to find correct insertion point, insert and return.

Return values
-1on failure
0on success
Note
Call this with the rule_lists locked

Definition at line 3216 of file app_queue.c.

3217{
3218 struct ast_config *cfg;
3219 struct rule_list *rl_iter, *new_rl;
3220 struct penalty_rule *pr_iter;
3221 char *rulecat = NULL;
3222
3223 if (!ast_check_realtime("queue_rules")) {
3224 ast_log(LOG_WARNING, "Missing \"queue_rules\" in extconfig.conf\n");
3225 return 0;
3226 }
3227 if (!(cfg = ast_load_realtime_multientry("queue_rules", "rule_name LIKE", "%", SENTINEL))) {
3228 ast_log(LOG_WARNING, "Failed to load queue rules from realtime\n");
3229 return 0;
3230 }
3231 while ((rulecat = ast_category_browse(cfg, rulecat))) {
3232 const char *timestr, *maxstr, *minstr, *raisestr, *rule_name;
3233 int penaltychangetime, rule_exists = 0, inserted = 0;
3234 int max_penalty = 0, min_penalty = 0, raise_penalty = 0;
3235 int min_relative = 0, max_relative = 0, raise_relative = 0;
3236 struct penalty_rule *new_penalty_rule = NULL;
3237
3238 rule_name = ast_variable_retrieve(cfg, rulecat, "rule_name");
3239 if (ast_strlen_zero(rule_name)) {
3240 continue;
3241 }
3242
3243 AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) {
3244 if (!(strcasecmp(rl_iter->name, rule_name))) {
3245 rule_exists = 1;
3246 new_rl = rl_iter;
3247 break;
3248 }
3249 }
3250 if (!rule_exists) {
3251 if (!(new_rl = ast_calloc(1, sizeof(*new_rl)))) {
3252 ast_config_destroy(cfg);
3253 return -1;
3254 }
3255 ast_copy_string(new_rl->name, rule_name, sizeof(new_rl->name));
3257 }
3258 timestr = ast_variable_retrieve(cfg, rulecat, "time");
3259 if (!(timestr) || sscanf(timestr, "%30d", &penaltychangetime) != 1) {
3260 ast_log(LOG_NOTICE, "Failed to parse time (%s) for one of the %s rules, skipping it\n",
3261 (ast_strlen_zero(timestr) ? "invalid value" : timestr), rule_name);
3262 continue;
3263 }
3264 if (!(new_penalty_rule = ast_calloc(1, sizeof(*new_penalty_rule)))) {
3265 ast_config_destroy(cfg);
3266 return -1;
3267 }
3268 if (!(maxstr = ast_variable_retrieve(cfg, rulecat, "max_penalty")) ||
3269 ast_strlen_zero(maxstr) || sscanf(maxstr, "%30d", &max_penalty) != 1) {
3270 max_penalty = 0;
3271 max_relative = 1;
3272 } else {
3273 if (*maxstr == '+' || *maxstr == '-') {
3274 max_relative = 1;
3275 }
3276 }
3277 if (!(minstr = ast_variable_retrieve(cfg, rulecat, "min_penalty")) ||
3278 ast_strlen_zero(minstr) || sscanf(minstr, "%30d", &min_penalty) != 1) {
3279 min_penalty = 0;
3280 min_relative = 1;
3281 } else {
3282 if (*minstr == '+' || *minstr == '-') {
3283 min_relative = 1;
3284 }
3285 }
3286 if (!(raisestr = ast_variable_retrieve(cfg, rulecat, "raise_penalty")) ||
3287 ast_strlen_zero(raisestr) || sscanf(raisestr, "%30d", &raise_penalty) != 1) {
3288 raise_penalty = 0;
3289 raise_relative = 1;
3290 } else {
3291 if (*raisestr == '+' || *raisestr == '-') {
3292 raise_relative = 1;
3293 }
3294 }
3295 new_penalty_rule->time = penaltychangetime;
3296 new_penalty_rule->max_relative = max_relative;
3297 new_penalty_rule->max_value = max_penalty;
3298 new_penalty_rule->min_relative = min_relative;
3299 new_penalty_rule->min_value = min_penalty;
3300 new_penalty_rule->raise_relative = raise_relative;
3301 new_penalty_rule->raise_value = raise_penalty;
3302 AST_LIST_TRAVERSE_SAFE_BEGIN(&new_rl->rules, pr_iter, list) {
3303 if (new_penalty_rule->time < pr_iter->time) {
3304 AST_LIST_INSERT_BEFORE_CURRENT(new_penalty_rule, list);
3305 inserted = 1;
3306 }
3307 }
3309 if (!inserted) {
3310 AST_LIST_INSERT_TAIL(&new_rl->rules, new_penalty_rule, list);
3311 }
3312 }
3313
3314 ast_config_destroy(cfg);
3315 return 0;
3316}

References ast_calloc, ast_category_browse(), ast_check_realtime(), ast_config_destroy(), ast_copy_string(), AST_LIST_INSERT_BEFORE_CURRENT, AST_LIST_INSERT_TAIL, AST_LIST_TRAVERSE, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, ast_load_realtime_multientry(), ast_log, ast_strlen_zero(), ast_variable_retrieve(), penalty_rule::list, LOG_NOTICE, LOG_WARNING, penalty_rule::max_relative, penalty_rule::max_value, penalty_rule::min_relative, penalty_rule::min_value, rule_list::name, NULL, penalty_rule::raise_relative, penalty_rule::raise_value, rule_list::rules, SENTINEL, and penalty_rule::time.

Referenced by reload_queue_rules().

◆ log_attended_transfer()

static void log_attended_transfer ( struct queue_stasis_data queue_data,
struct ast_attended_transfer_message atxfer_msg 
)
static

Definition at line 6359 of file app_queue.c.

6361{
6362 RAII_VAR(struct ast_str *, transfer_str, ast_str_create(32), ast_free);
6363
6364 if (!transfer_str) {
6365 ast_log(LOG_WARNING, "Unable to log attended transfer to queue log\n");
6366 return;
6367 }
6368
6369 switch (atxfer_msg->dest_type) {
6371 ast_str_set(&transfer_str, 0, "BRIDGE|%s", atxfer_msg->dest.bridge);
6372 break;
6375 ast_str_set(&transfer_str, 0, "APP|%s", atxfer_msg->dest.app);
6376 break;
6378 ast_str_set(&transfer_str, 0, "LINK|%s|%s", atxfer_msg->dest.links[0]->base->name,
6379 atxfer_msg->dest.links[1]->base->name);
6380 break;
6383 /* Threeways are headed off and should not be logged here */
6384 ast_assert(0);
6385 return;
6386 }
6387
6388 ast_queue_log(queue_data->queue->name, queue_data->caller_uniqueid, queue_data->member->membername, "ATTENDEDTRANSFER", "%s|%ld|%ld|%d",
6389 ast_str_buffer(transfer_str),
6390 (long) (queue_data->starttime - queue_data->holdstart),
6391 (long) (time(NULL) - queue_data->starttime), queue_data->caller_pos);
6392}
@ AST_ATTENDED_TRANSFER_DEST_FAIL
@ AST_ATTENDED_TRANSFER_DEST_BRIDGE_MERGE
@ AST_ATTENDED_TRANSFER_DEST_LOCAL_APP
@ AST_ATTENDED_TRANSFER_DEST_LINK
@ AST_ATTENDED_TRANSFER_DEST_APP
union ast_attended_transfer_message::@284 dest
struct ast_channel_snapshot * links[2]
char bridge[AST_UUID_STR_LEN]

References ast_attended_transfer_message::app, ast_assert, AST_ATTENDED_TRANSFER_DEST_APP, AST_ATTENDED_TRANSFER_DEST_BRIDGE_MERGE, AST_ATTENDED_TRANSFER_DEST_FAIL, AST_ATTENDED_TRANSFER_DEST_LINK, AST_ATTENDED_TRANSFER_DEST_LOCAL_APP, AST_ATTENDED_TRANSFER_DEST_THREEWAY, ast_free, ast_log, ast_queue_log(), ast_str_buffer(), ast_str_create, ast_str_set(), ast_channel_snapshot::base, ast_attended_transfer_message::bridge, queue_stasis_data::caller_pos, queue_stasis_data::caller_uniqueid, ast_attended_transfer_message::dest, ast_attended_transfer_message::dest_type, queue_stasis_data::holdstart, ast_attended_transfer_message::links, LOG_WARNING, queue_stasis_data::member, member::membername, call_queue::name, ast_channel_snapshot_base::name, NULL, queue_stasis_data::queue, RAII_VAR, and queue_stasis_data::starttime.

Referenced by handle_attended_transfer().

◆ manager_add_queue_member()

static int manager_add_queue_member ( struct mansession s,
const struct message m 
)
static

Definition at line 10674 of file app_queue.c.

10675{
10676 const char *queuename, *interface, *penalty_s, *paused_s, *reason, *membername, *state_interface, *wrapuptime_s;
10677 int paused, penalty, wrapuptime = 0;
10678
10679 queuename = astman_get_header(m, "Queue");
10680 interface = astman_get_header(m, "Interface");
10681 penalty_s = astman_get_header(m, "Penalty");
10682 paused_s = astman_get_header(m, "Paused");
10683 reason = astman_get_header(m, "Reason"); /* Optional */
10684 membername = astman_get_header(m, "MemberName");
10685 state_interface = astman_get_header(m, "StateInterface");
10686 wrapuptime_s = astman_get_header(m, "Wrapuptime");
10687
10688 if (ast_strlen_zero(queuename)) {
10689 astman_send_error(s, m, "'Queue' not specified.");
10690 return 0;
10691 }
10692
10693 if (ast_strlen_zero(interface)) {
10694 astman_send_error(s, m, "'Interface' not specified.");
10695 return 0;
10696 }
10697
10698 if (ast_strlen_zero(penalty_s)) {
10699 penalty = 0;
10700 } else if (sscanf(penalty_s, "%30d", &penalty) != 1 || penalty < 0) {
10701 penalty = 0;
10702 }
10703
10704 if (ast_strlen_zero(wrapuptime_s)) {
10705 wrapuptime = 0;
10706 } else if (sscanf(wrapuptime_s, "%30d", &wrapuptime) != 1 || wrapuptime < 0) {
10707 wrapuptime = 0;
10708 }
10709
10710 if (ast_strlen_zero(paused_s)) {
10711 paused = 0;
10712 } else {
10713 paused = abs(ast_true(paused_s));
10714 }
10715
10716 switch (add_to_queue(queuename, interface, membername, penalty, paused, queue_persistent_members, state_interface, reason, wrapuptime)) {
10717 case RES_OKAY:
10718 if (ast_strlen_zero(membername) || !log_membername_as_agent) {
10719 ast_queue_log(queuename, "MANAGER", interface, "ADDMEMBER", "%s", paused ? "PAUSED" : "");
10720 } else {
10721 ast_queue_log(queuename, "MANAGER", membername, "ADDMEMBER", "%s", paused ? "PAUSED" : "");
10722 }
10723 astman_send_ack(s, m, "Added interface to queue");
10724 break;
10725 case RES_EXISTS:
10726 astman_send_error(s, m, "Unable to add interface: Already there");
10727 break;
10728 case RES_NOSUCHQUEUE:
10729 astman_send_error(s, m, "Unable to add interface to queue: No such queue");
10730 break;
10731 case RES_OUTOFMEMORY:
10732 astman_send_error(s, m, "Out of memory");
10733 break;
10734 }
10735
10736 return 0;
10737}
#define abs(x)
Definition: f2c.h:195
void astman_send_error(struct mansession *s, const struct message *m, char *error)
Send error in manager transaction.
Definition: manager.c:1969
void astman_send_ack(struct mansession *s, const struct message *m, char *msg)
Send ack in manager transaction.
Definition: manager.c:2001
const char * astman_get_header(const struct message *m, char *var)
Get header from manager transaction.
Definition: manager.c:1630

References abs, add_to_queue(), ast_queue_log(), ast_strlen_zero(), ast_true(), astman_get_header(), astman_send_ack(), astman_send_error(), log_membername_as_agent, queue_persistent_members, RES_EXISTS, RES_NOSUCHQUEUE, RES_OKAY, and RES_OUTOFMEMORY.

Referenced by load_module().

◆ manager_change_priority_caller_on_queue()

static int manager_change_priority_caller_on_queue ( struct mansession s,
const struct message m 
)
static

Definition at line 10970 of file app_queue.c.

10971{
10972 const char *queuename, *caller, *priority_s, *immediate_s;
10973 int priority = 0, immediate = 0;
10974
10975 queuename = astman_get_header(m, "Queue");
10976 caller = astman_get_header(m, "Caller");
10977 priority_s = astman_get_header(m, "Priority");
10978 immediate_s = astman_get_header(m, "Immediate");
10979
10980 if (ast_strlen_zero(queuename)) {
10981 astman_send_error(s, m, "'Queue' not specified.");
10982 return 0;
10983 }
10984
10985 if (ast_strlen_zero(caller)) {
10986 astman_send_error(s, m, "'Caller' not specified.");
10987 return 0;
10988 }
10989
10990 if (ast_strlen_zero(priority_s)) {
10991 astman_send_error(s, m, "'Priority' not specified.");
10992 return 0;
10993 } else if (sscanf(priority_s, "%30d", &priority) != 1) {
10994 astman_send_error(s, m, "'Priority' need integer.");
10995 return 0;
10996 }
10997
10998 if (!ast_strlen_zero(immediate_s)) {
10999 immediate = ast_true(immediate_s);
11000 }
11001
11002 switch (change_priority_caller_on_queue(queuename, caller, priority, immediate)) {
11003 case RES_OKAY:
11004 astman_send_ack(s, m, "Priority change for caller on queue");
11005 break;
11006 case RES_NOSUCHQUEUE:
11007 astman_send_error(s, m, "Unable to change priority caller on queue: No such queue");
11008 break;
11009 case RES_NOT_CALLER:
11010 astman_send_error(s, m, "Unable to change priority caller on queue: No such caller");
11011 break;
11012 }
11013
11014 return 0;
11015}

References ast_strlen_zero(), ast_true(), astman_get_header(), astman_send_ack(), astman_send_error(), change_priority_caller_on_queue(), priority, RES_NOSUCHQUEUE, RES_NOT_CALLER, and RES_OKAY.

Referenced by load_module().

◆ manager_pause_queue_member()

static int manager_pause_queue_member ( struct mansession s,
const struct message m 
)
static

Definition at line 10786 of file app_queue.c.

10787{
10788 const char *queuename, *interface, *paused_s, *reason;
10789 int paused;
10790
10791 interface = astman_get_header(m, "Interface");
10792 paused_s = astman_get_header(m, "Paused");
10793 queuename = astman_get_header(m, "Queue"); /* Optional - if not supplied, pause the given Interface in all queues */
10794 reason = astman_get_header(m, "Reason"); /* Optional */
10795
10796 if (ast_strlen_zero(interface) || ast_strlen_zero(paused_s)) {
10797 astman_send_error(s, m, "Need 'Interface' and 'Paused' parameters.");
10798 return 0;
10799 }
10800
10801 paused = abs(ast_true(paused_s));
10802
10803 if (set_member_paused(queuename, interface, reason, paused)) {
10804 astman_send_error(s, m, "Interface not found");
10805 } else {
10806 astman_send_ack(s, m, paused ? "Interface paused successfully" : "Interface unpaused successfully");
10807 }
10808 return 0;
10809}

References abs, ast_strlen_zero(), ast_true(), astman_get_header(), astman_send_ack(), astman_send_error(), and set_member_paused().

Referenced by load_module().

◆ manager_queue_log_custom()

static int manager_queue_log_custom ( struct mansession s,
const struct message m 
)
static

Definition at line 10811 of file app_queue.c.

10812{
10813 const char *queuename, *event, *message, *interface, *uniqueid;
10814
10815 queuename = astman_get_header(m, "Queue");
10816 uniqueid = astman_get_header(m, "UniqueId");
10817 interface = astman_get_header(m, "Interface");
10818 event = astman_get_header(m, "Event");
10819 message = astman_get_header(m, "Message");
10820
10821 if (ast_strlen_zero(queuename) || ast_strlen_zero(event)) {
10822 astman_send_error(s, m, "Need 'Queue' and 'Event' parameters.");
10823 return 0;
10824 }
10825
10826 ast_queue_log(queuename, S_OR(uniqueid, "NONE"), interface, event, "%s", message);
10827 astman_send_ack(s, m, "Event added successfully");
10828
10829 return 0;
10830}
Definition: astman.c:222

References ast_queue_log(), ast_strlen_zero(), astman_get_header(), astman_send_ack(), astman_send_error(), and S_OR.

Referenced by load_module().

◆ manager_queue_member_penalty()

static int manager_queue_member_penalty ( struct mansession s,
const struct message m 
)
static

Definition at line 10944 of file app_queue.c.

10945{
10946 const char *queuename, *interface, *penalty_s;
10947 int penalty;
10948
10949 interface = astman_get_header(m, "Interface");
10950 penalty_s = astman_get_header(m, "Penalty");
10951 /* Optional - if not supplied, set the penalty value for the given Interface in all queues */
10952 queuename = astman_get_header(m, "Queue");
10953
10954 if (ast_strlen_zero(interface) || ast_strlen_zero(penalty_s)) {
10955 astman_send_error(s, m, "Need 'Interface' and 'Penalty' parameters.");
10956 return 0;
10957 }
10958
10959 penalty = atoi(penalty_s);
10960
10961 if (set_member_value((char *)queuename, (char *)interface, MEMBER_PENALTY, penalty)) {
10962 astman_send_error(s, m, "Invalid interface, queuename or penalty");
10963 } else {
10964 astman_send_ack(s, m, "Interface penalty set successfully");
10965 }
10966
10967 return 0;
10968}

References ast_strlen_zero(), astman_get_header(), astman_send_ack(), astman_send_error(), MEMBER_PENALTY, and set_member_value().

Referenced by load_module().

◆ manager_queue_member_ringinuse()

static int manager_queue_member_ringinuse ( struct mansession s,
const struct message m 
)
static

Definition at line 10910 of file app_queue.c.

10911{
10912 const char *queuename, *interface, *ringinuse_s;
10913 int ringinuse;
10914
10915 interface = astman_get_header(m, "Interface");
10916 ringinuse_s = astman_get_header(m, "RingInUse");
10917
10918 /* Optional - if not supplied, set the ringinuse value for the given Interface in all queues */
10919 queuename = astman_get_header(m, "Queue");
10920
10921 if (ast_strlen_zero(interface) || ast_strlen_zero(ringinuse_s)) {
10922 astman_send_error(s, m, "Need 'Interface' and 'RingInUse' parameters.");
10923 return 0;
10924 }
10925
10926 if (ast_true(ringinuse_s)) {
10927 ringinuse = 1;
10928 } else if (ast_false(ringinuse_s)) {
10929 ringinuse = 0;
10930 } else {
10931 astman_send_error(s, m, "'RingInUse' parameter must be a truth value (yes/no, on/off, 0/1, etc)");
10932 return 0;
10933 }
10934
10935 if (set_member_value(queuename, interface, MEMBER_RINGINUSE, ringinuse)) {
10936 astman_send_error(s, m, "Invalid interface, queuename, or ringinuse value\n");
10937 } else {
10938 astman_send_ack(s, m, "Interface ringinuse set successfully");
10939 }
10940
10941 return 0;
10942}

References ast_false(), ast_strlen_zero(), ast_true(), astman_get_header(), astman_send_ack(), astman_send_error(), MEMBER_RINGINUSE, and set_member_value().

Referenced by load_module().

◆ manager_queue_reload()

static int manager_queue_reload ( struct mansession s,
const struct message m 
)
static

Definition at line 10832 of file app_queue.c.

10833{
10834 struct ast_flags mask = {0,};
10835 const char *queuename = NULL;
10836 int header_found = 0;
10837
10838 queuename = astman_get_header(m, "Queue");
10839 if (!strcasecmp(S_OR(astman_get_header(m, "Members"), ""), "yes")) {
10841 header_found = 1;
10842 }
10843 if (!strcasecmp(S_OR(astman_get_header(m, "Rules"), ""), "yes")) {
10845 header_found = 1;
10846 }
10847 if (!strcasecmp(S_OR(astman_get_header(m, "Parameters"), ""), "yes")) {
10849 header_found = 1;
10850 }
10851
10852 if (!header_found) {
10854 }
10855
10856 if (!reload_handler(1, &mask, queuename)) {
10857 astman_send_ack(s, m, "Queue reloaded successfully");
10858 } else {
10859 astman_send_error(s, m, "Error encountered while reloading queue");
10860 }
10861 return 0;
10862}

References AST_FLAGS_ALL, ast_set_flag, astman_get_header(), astman_send_ack(), astman_send_error(), NULL, QUEUE_RELOAD_MEMBER, QUEUE_RELOAD_PARAMETERS, QUEUE_RELOAD_RULES, QUEUE_RESET_STATS, reload_handler(), and S_OR.

Referenced by load_module().

◆ manager_queue_reset()

static int manager_queue_reset ( struct mansession s,
const struct message m 
)
static

Definition at line 10864 of file app_queue.c.

10865{
10866 const char *queuename = NULL;
10867 struct ast_flags mask = {QUEUE_RESET_STATS,};
10868
10869 queuename = astman_get_header(m, "Queue");
10870
10871 if (!reload_handler(1, &mask, queuename)) {
10872 astman_send_ack(s, m, "Queue stats reset successfully");
10873 } else {
10874 astman_send_error(s, m, "Error encountered while resetting queue stats");
10875 }
10876 return 0;
10877}

References astman_get_header(), astman_send_ack(), astman_send_error(), NULL, QUEUE_RESET_STATS, and reload_handler().

Referenced by load_module().

◆ manager_queue_rule_show()

static int manager_queue_rule_show ( struct mansession s,
const struct message m 
)
static

Definition at line 10433 of file app_queue.c.

10434{
10435 const char *rule = astman_get_header(m, "Rule");
10436 const char *id = astman_get_header(m, "ActionID");
10437 struct rule_list *rl_iter;
10438 struct penalty_rule *pr_iter;
10439
10440 astman_append(s, "Response: Success\r\n");
10441 if (!ast_strlen_zero(id)) {
10442 astman_append(s, "ActionID: %s\r\n", id);
10443 }
10444
10446 AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) {
10447 if (ast_strlen_zero(rule) || !strcasecmp(rule, rl_iter->name)) {
10448 astman_append(s, "RuleList: %s\r\n", rl_iter->name);
10449 AST_LIST_TRAVERSE(&rl_iter->rules, pr_iter, list) {
10450 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 );
10451 }
10452 if (!ast_strlen_zero(rule)) {
10453 break;
10454 }
10455 }
10456 }
10458
10459 /*
10460 * Two blank lines instead of one because the Response and
10461 * ActionID headers used to not be present.
10462 */
10463 astman_append(s, "\r\n\r\n");
10464
10465 return RESULT_SUCCESS;
10466}

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().

◆ manager_queues_status()

static int manager_queues_status ( struct mansession s,
const struct message m 
)
static

Queue status info via AMI.

Definition at line 10551 of file app_queue.c.

10552{
10553 time_t now;
10554 int pos;
10555 int q_items = 0;
10556 const char *id = astman_get_header(m,"ActionID");
10557 const char *queuefilter = astman_get_header(m,"Queue");
10558 const char *memberfilter = astman_get_header(m,"Member");
10559 char idText[256];
10560 struct call_queue *q;
10561 struct queue_ent *qe;
10562 float sl = 0;
10563 float sl2 = 0;
10564 struct member *mem;
10565 struct ao2_iterator queue_iter;
10566 struct ao2_iterator mem_iter;
10567
10568 if (ast_check_realtime("queues")) {
10569 load_realtime_queues(queuefilter);
10570 }
10571
10572 astman_send_listack(s, m, "Queue status will follow", "start");
10573 time(&now);
10574 idText[0] = '\0';
10575 if (!ast_strlen_zero(id)) {
10576 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
10577 }
10578
10579 queue_iter = ao2_iterator_init(queues, 0);
10580 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
10581 ao2_lock(q);
10582
10583 /* List queue properties */
10584 if (ast_strlen_zero(queuefilter) || !strcasecmp(q->name, queuefilter)) {
10585 sl = ((q->callscompleted > 0) ? 100 * ((float)q->callscompletedinsl / (float)q->callscompleted) : 0);
10586 sl2 = (((q->callscompleted + q->callsabandoned) > 0) ? 100 * (((float)q->callsabandonedinsl + (float)q->callscompletedinsl) / ((float)q->callsabandoned + (float)q->callscompleted)) : 0);
10587
10588 astman_append(s, "Event: QueueParams\r\n"
10589 "Queue: %s\r\n"
10590 "Max: %d\r\n"
10591 "Strategy: %s\r\n"
10592 "Calls: %d\r\n"
10593 "Holdtime: %d\r\n"
10594 "TalkTime: %d\r\n"
10595 "Completed: %d\r\n"
10596 "Abandoned: %d\r\n"
10597 "ServiceLevel: %d\r\n"
10598 "ServicelevelPerf: %2.1f\r\n"
10599 "ServicelevelPerf2: %2.1f\r\n"
10600 "Weight: %d\r\n"
10601 "%s"
10602 "\r\n",
10603 q->name, q->maxlen, int2strat(q->strategy), q->count, q->holdtime, q->talktime, q->callscompleted,
10604 q->callsabandoned, q->servicelevel, sl, sl2, q->weight, idText);
10605 ++q_items;
10606
10607 /* List Queue Members */
10608 mem_iter = ao2_iterator_init(q->members, 0);
10609 while ((mem = ao2_iterator_next(&mem_iter))) {
10610 if (ast_strlen_zero(memberfilter) || !strcmp(mem->interface, memberfilter) || !strcmp(mem->membername, memberfilter)) {
10611 astman_append(s, "Event: QueueMember\r\n"
10612 "Queue: %s\r\n"
10613 "Name: %s\r\n"
10614 "Location: %s\r\n"
10615 "StateInterface: %s\r\n"
10616 "Membership: %s\r\n"
10617 "Penalty: %d\r\n"
10618 "CallsTaken: %d\r\n"
10619 "LastCall: %d\r\n"
10620 "LastPause: %d\r\n"
10621 "LoginTime: %d\r\n"
10622 "InCall: %d\r\n"
10623 "Status: %d\r\n"
10624 "Paused: %d\r\n"
10625 "PausedReason: %s\r\n"
10626 "Wrapuptime: %d\r\n"
10627 "%s"
10628 "\r\n",
10629 q->name, mem->membername, mem->interface, mem->state_interface, mem->dynamic ? "dynamic" : "static",
10630 mem->penalty, mem->calls, (int)mem->lastcall, (int)mem->lastpause, (int)mem->logintime, mem->starttime ? 1 : 0, mem->status,
10631 mem->paused, mem->reason_paused, mem->wrapuptime, idText);
10632 ++q_items;
10633 }
10634 ao2_ref(mem, -1);
10635 }
10636 ao2_iterator_destroy(&mem_iter);
10637
10638 /* List Queue Entries */
10639 pos = 1;
10640 for (qe = q->head; qe; qe = qe->next) {
10641 astman_append(s, "Event: QueueEntry\r\n"
10642 "Queue: %s\r\n"
10643 "Position: %d\r\n"
10644 "Channel: %s\r\n"
10645 "Uniqueid: %s\r\n"
10646 "CallerIDNum: %s\r\n"
10647 "CallerIDName: %s\r\n"
10648 "ConnectedLineNum: %s\r\n"
10649 "ConnectedLineName: %s\r\n"
10650 "Wait: %ld\r\n"
10651 "Priority: %d\r\n"
10652 "%s"
10653 "\r\n",
10654 q->name, pos++, ast_channel_name(qe->chan), ast_channel_uniqueid(qe->chan),
10659 (long) (now - qe->start), qe->prio, idText);
10660 ++q_items;
10661 }
10662 }
10663 ao2_unlock(q);
10664 queue_t_unref(q, "Done with iterator");
10665 }
10666 ao2_iterator_destroy(&queue_iter);
10667
10668 astman_send_list_complete_start(s, m, "QueueStatusComplete", q_items);
10670
10671 return RESULT_SUCCESS;
10672}
static void load_realtime_queues(const char *queuename)
Definition: app_queue.c:3985
static const char * int2strat(int strategy)
Definition: app_queue.c:1951
struct ast_party_connected_line * ast_channel_connected(struct ast_channel *chan)
struct ast_party_caller * ast_channel_caller(struct ast_channel *chan)
void astman_send_listack(struct mansession *s, const struct message *m, char *msg, char *listflag)
Send ack in manager transaction to begin a list.
Definition: manager.c:2011
void astman_send_list_complete_start(struct mansession *s, const struct message *m, const char *event_name, int count)
Start the list complete event.
Definition: manager.c:2047
void astman_send_list_complete_end(struct mansession *s)
End the list complete event.
Definition: manager.c:2055
#define S_COR(a, b, c)
returns the equivalent of logic or for strings, with an additional boolean check: second one if not e...
Definition: strings.h:87
struct ast_party_id id
Caller party ID.
Definition: channel.h:422
struct ast_party_id id
Connected party ID.
Definition: channel.h:460
struct ast_party_name name
Subscriber name.
Definition: channel.h:342
struct ast_party_number number
Subscriber phone number.
Definition: channel.h:344
unsigned char valid
TRUE if the name information is valid/present.
Definition: channel.h:281
char * str
Subscriber name (Malloced)
Definition: channel.h:266
unsigned char valid
TRUE if the number information is valid/present.
Definition: channel.h:299
char * str
Subscriber phone number (Malloced)
Definition: channel.h:293

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_lock, ao2_ref, ao2_t_iterator_next, ao2_unlock, ast_channel_caller(), ast_channel_connected(), ast_channel_name(), ast_channel_uniqueid(), ast_check_realtime(), ast_strlen_zero(), astman_append(), astman_get_header(), astman_send_list_complete_end(), astman_send_list_complete_start(), astman_send_listack(), member::calls, call_queue::callsabandoned, call_queue::callsabandonedinsl, call_queue::callscompleted, call_queue::callscompletedinsl, queue_ent::chan, call_queue::count, member::dynamic, call_queue::head, call_queue::holdtime, ast_party_caller::id, ast_party_connected_line::id, int2strat(), member::interface, member::lastcall, member::lastpause, load_realtime_queues(), member::logintime, call_queue::maxlen, member::membername, call_queue::members, call_queue::name, ast_party_id::name, queue_ent::next, ast_party_id::number, member::paused, member::penalty, queue_ent::prio, queue_t_unref, queues, member::reason_paused, RESULT_SUCCESS, S_COR, call_queue::servicelevel, queue_ent::start, member::starttime, member::state_interface, member::status, ast_party_name::str, ast_party_number::str, call_queue::strategy, call_queue::talktime, ast_party_name::valid, ast_party_number::valid, call_queue::weight, and member::wrapuptime.

Referenced by load_module().

◆ manager_queues_summary()

static int manager_queues_summary ( struct mansession s,
const struct message m 
)
static

Summary of queue info via the AMI.

Definition at line 10469 of file app_queue.c.

10470{
10471 time_t now;
10472 int qmemcount = 0;
10473 int qmemavail = 0;
10474 int qchancount = 0;
10475 int qlongestholdtime = 0;
10476 int qsummaries = 0;
10477 const char *id = astman_get_header(m, "ActionID");
10478 const char *queuefilter = astman_get_header(m, "Queue");
10479 char idText[256];
10480 struct call_queue *q;
10481 struct queue_ent *qe;
10482 struct member *mem;
10483 struct ao2_iterator queue_iter;
10484 struct ao2_iterator mem_iter;
10485
10486 if (ast_check_realtime("queues")) {
10487 load_realtime_queues(queuefilter);
10488 }
10489
10490 astman_send_listack(s, m, "Queue summary will follow", "start");
10491 time(&now);
10492 idText[0] = '\0';
10493 if (!ast_strlen_zero(id)) {
10494 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
10495 }
10496 queue_iter = ao2_iterator_init(queues, 0);
10497 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
10498 ao2_lock(q);
10499
10500 /* List queue properties */
10501 if (ast_strlen_zero(queuefilter) || !strcasecmp(q->name, queuefilter)) {
10502 /* Reset the necessary local variables if no queuefilter is set*/
10503 qmemcount = 0;
10504 qmemavail = 0;
10505 qchancount = 0;
10506 qlongestholdtime = 0;
10507
10508 /* List Queue Members */
10509 mem_iter = ao2_iterator_init(q->members, 0);
10510 while ((mem = ao2_iterator_next(&mem_iter))) {
10511 if ((mem->status != AST_DEVICE_UNAVAILABLE) && (mem->status != AST_DEVICE_INVALID)) {
10512 ++qmemcount;
10513 if (member_status_available(mem->status) && !mem->paused) {
10514 ++qmemavail;
10515 }
10516 }
10517 ao2_ref(mem, -1);
10518 }
10519 ao2_iterator_destroy(&mem_iter);
10520 for (qe = q->head; qe; qe = qe->next) {
10521 if ((now - qe->start) > qlongestholdtime) {
10522 qlongestholdtime = now - qe->start;
10523 }
10524 ++qchancount;
10525 }
10526 astman_append(s, "Event: QueueSummary\r\n"
10527 "Queue: %s\r\n"
10528 "LoggedIn: %d\r\n"
10529 "Available: %d\r\n"
10530 "Callers: %d\r\n"
10531 "HoldTime: %d\r\n"
10532 "TalkTime: %d\r\n"
10533 "LongestHoldTime: %d\r\n"
10534 "%s"
10535 "\r\n",
10536 q->name, qmemcount, qmemavail, qchancount, q->holdtime, q->talktime, qlongestholdtime, idText);
10537 ++qsummaries;
10538 }
10539 ao2_unlock(q);
10540 queue_t_unref(q, "Done with iterator");
10541 }
10542 ao2_iterator_destroy(&queue_iter);
10543
10544 astman_send_list_complete_start(s, m, "QueueSummaryComplete", qsummaries);
10546
10547 return RESULT_SUCCESS;
10548}

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_lock, ao2_ref, ao2_t_iterator_next, ao2_unlock, ast_check_realtime(), AST_DEVICE_INVALID, AST_DEVICE_UNAVAILABLE, ast_strlen_zero(), astman_append(), astman_get_header(), astman_send_list_complete_end(), astman_send_list_complete_start(), astman_send_listack(), call_queue::head, call_queue::holdtime, load_realtime_queues(), member_status_available(), call_queue::members, call_queue::name, queue_ent::next, member::paused, queue_t_unref, queues, RESULT_SUCCESS, queue_ent::start, member::status, and call_queue::talktime.

Referenced by load_module().

◆ manager_remove_queue_member()

static int manager_remove_queue_member ( struct mansession s,
const struct message m 
)
static

Definition at line 10739 of file app_queue.c.

10740{
10741 const char *queuename, *interface;
10742 struct member *mem = NULL;
10743
10744 queuename = astman_get_header(m, "Queue");
10745 interface = astman_get_header(m, "Interface");
10746
10747 if (ast_strlen_zero(queuename) || ast_strlen_zero(interface)) {
10748 astman_send_error(s, m, "Need 'Queue' and 'Interface' parameters.");
10749 return 0;
10750 }
10751
10753 mem = find_member_by_queuename_and_interface(queuename, interface);
10754 }
10755
10756 switch (remove_from_queue(queuename, interface)) {
10757 case RES_OKAY:
10758 if (!mem || ast_strlen_zero(mem->membername)) {
10759 ast_queue_log(queuename, "MANAGER", interface, "REMOVEMEMBER", "%s", "");
10760 } else {
10761 ast_queue_log(queuename, "MANAGER", mem->membername, "REMOVEMEMBER", "%s", "");
10762 }
10763 astman_send_ack(s, m, "Removed interface from queue");
10764 break;
10765 case RES_EXISTS:
10766 astman_send_error(s, m, "Unable to remove interface: Not there");
10767 break;
10768 case RES_NOSUCHQUEUE:
10769 astman_send_error(s, m, "Unable to remove interface from queue: No such queue");
10770 break;
10771 case RES_OUTOFMEMORY:
10772 astman_send_error(s, m, "Out of memory");
10773 break;
10774 case RES_NOT_DYNAMIC:
10775 astman_send_error(s, m, "Member not dynamic");
10776 break;
10777 }
10778
10779 if (mem) {
10780 ao2_ref(mem, -1);
10781 }
10782
10783 return 0;
10784}

References ao2_ref, ast_queue_log(), ast_strlen_zero(), astman_get_header(), astman_send_ack(), astman_send_error(), find_member_by_queuename_and_interface(), log_membername_as_agent, member::membername, NULL, remove_from_queue(), RES_EXISTS, RES_NOSUCHQUEUE, RES_NOT_DYNAMIC, RES_OKAY, and RES_OUTOFMEMORY.

Referenced by load_module().

◆ manager_request_withdraw_caller_from_queue()

static int manager_request_withdraw_caller_from_queue ( struct mansession s,
const struct message m 
)
static

Definition at line 11017 of file app_queue.c.

11018{
11019 const char *queuename, *caller, *withdraw_info;
11020
11021 queuename = astman_get_header(m, "Queue");
11022 caller = astman_get_header(m, "Caller");
11023 withdraw_info = astman_get_header(m, "WithdrawInfo");
11024
11025 if (ast_strlen_zero(queuename)) {
11026 astman_send_error(s, m, "'Queue' not specified.");
11027 return 0;
11028 }
11029
11030 if (ast_strlen_zero(caller)) {
11031 astman_send_error(s, m, "'Caller' not specified.");
11032 return 0;
11033 }
11034
11035 switch (request_withdraw_caller_from_queue(queuename, caller, withdraw_info)) {
11036 case RES_OKAY:
11037 astman_send_ack(s, m, "Withdraw requested successfully");
11038 break;
11039 case RES_NOSUCHQUEUE:
11040 astman_send_error(s, m, "Unable to request withdraw from queue: No such queue");
11041 break;
11042 case RES_NOT_CALLER:
11043 astman_send_error(s, m, "Unable to request withdraw from queue: No such caller");
11044 break;
11045 case RES_EXISTS:
11046 astman_send_error(s, m, "Unable to request withdraw from queue: Already requested");
11047 break;
11048 }
11049
11050 return 0;
11051}
static int request_withdraw_caller_from_queue(const char *queuename, const char *caller, const char *withdraw_info)
Request to withdraw a caller from a queue.
Definition: app_queue.c:7751

References ast_strlen_zero(), astman_get_header(), astman_send_ack(), astman_send_error(), request_withdraw_caller_from_queue(), RES_EXISTS, RES_NOSUCHQUEUE, RES_NOT_CALLER, and RES_OKAY.

Referenced by load_module().

◆ mark_member_dead()

static int mark_member_dead ( void *  obj,
void *  arg,
int  flags 
)
static

Definition at line 9791 of file app_queue.c.

9792{
9793 struct member *member = obj;
9794 if (!member->dynamic && !member->realtime) {
9795 member->delme = 1;
9796 }
9797 return 0;
9798}

References member::delme, member::dynamic, and member::realtime.

Referenced by reload_single_queue().

◆ mark_unfound()

static int mark_unfound ( void *  obj,
void *  arg,
int  flags 
)
static

Definition at line 9945 of file app_queue.c.

9946{
9947 struct call_queue *q = obj;
9948 char *queuename = arg;
9949 if (!q->realtime && (ast_strlen_zero(queuename) || !strcasecmp(queuename, q->name))) {
9950 q->found = 0;
9951 }
9952 return 0;
9953}

References ast_strlen_zero(), call_queue::found, call_queue::name, and call_queue::realtime.

Referenced by reload_queues().

◆ member_add_to_queue()

static void member_add_to_queue ( struct call_queue queue,
struct member mem 
)
static

◆ member_cmp_fn()

static int member_cmp_fn ( void *  obj1,
void *  obj2,
int  flags 
)
static

Definition at line 2965 of file app_queue.c.

2966{
2967 struct member *mem1 = obj1;
2968 struct member *mem2 = obj2;
2969 const char *interface = (flags & OBJ_KEY) ? obj2 : mem2->interface;
2970
2971 return strcasecmp(mem1->interface, interface) ? 0 : CMP_MATCH | CMP_STOP;
2972}
@ CMP_STOP
Definition: astobj2.h:1028

References CMP_MATCH, CMP_STOP, member::interface, and OBJ_KEY.

Referenced by init_queue().

◆ member_hash_fn()

static int member_hash_fn ( const void *  obj,
const int  flags 
)
static

Definition at line 2949 of file app_queue.c.

2950{
2951 const struct member *mem = obj;
2952 const char *interface = (flags & OBJ_KEY) ? obj : mem->interface;
2953 const char *chname = strchr(interface, '/');
2954 int ret = 0, i;
2955
2956 if (!chname) {
2957 chname = interface;
2958 }
2959 for (i = 0; i < 5 && chname[i]; i++) {
2960 ret += compress_char(chname[i]) << (i * 6);
2961 }
2962 return ret;
2963}
static int compress_char(const char c)
Definition: app_queue.c:2939

References compress_char(), member::interface, and OBJ_KEY.

Referenced by init_queue().

◆ member_remove_from_queue()

static void member_remove_from_queue ( struct call_queue queue,
struct member mem 
)
static

Definition at line 3591 of file app_queue.c.

3592{
3594 ao2_lock(queue->members);
3597 ao2_unlink(queue->members, mem);
3598 ao2_unlock(queue->members);
3599}
static void queue_member_follower_removal(struct call_queue *queue, struct member *mem)
Definition: app_queue.c:2071
#define QUEUE_UNKNOWN_PAUSED_DEVSTATE
Definition: app_queue.c:3567
#define ao2_unlink(container, obj)
Remove an object from a container.
Definition: astobj2.h:1578

References ao2_lock, ao2_unlink, ao2_unlock, AST_DEVSTATE_CACHABLE, ast_devstate_changed(), member::interface, call_queue::members, call_queue::name, pending_members_remove(), queue_member_follower_removal(), and QUEUE_UNKNOWN_PAUSED_DEVSTATE.

Referenced by find_queue_by_name_rt(), free_members(), remove_from_queue(), and update_realtime_members().

◆ member_status_available()

static int member_status_available ( int  status)
static

Definition at line 4672 of file app_queue.c.

4673{
4675}

References AST_DEVICE_NOT_INUSE, AST_DEVICE_UNKNOWN, and status.

Referenced by can_ring_entry(), and manager_queues_summary().

◆ num_available_members()

static int num_available_members ( struct call_queue q)
static

Get the number of members available to accept a call.

Note
The queue passed in should be locked prior to this function call
Parameters
[in]qThe queue for which we are counting the number of available members
Returns
Return the number of available members in queue q

Definition at line 4538 of file app_queue.c.

4539{
4540 struct member *mem;
4541 int avl = 0;
4542 struct ao2_iterator mem_iter;
4543
4544 mem_iter = ao2_iterator_init(q->members, 0);
4545 while ((mem = ao2_iterator_next(&mem_iter))) {
4546
4547 avl += is_member_available(q, mem);
4548 ao2_ref(mem, -1);
4549
4550 /* If autofill is not enabled or if the queue's strategy is ringall, then
4551 * we really don't care about the number of available members so much as we
4552 * do that there is at least one available.
4553 *
4554 * In fact, we purposely will return from this function stating that only
4555 * one member is available if either of those conditions hold. That way,
4556 * functions which determine what action to take based on the number of available
4557 * members will operate properly. The reasoning is that even if multiple
4558 * members are available, only the head caller can actually be serviced.
4559 */
4560 if ((!q->autofill || q->strategy == QUEUE_STRATEGY_RINGALL) && avl) {
4561 break;
4562 }
4563 }
4564 ao2_iterator_destroy(&mem_iter);
4565
4566 return avl;
4567}

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_ref, call_queue::autofill, is_member_available(), call_queue::members, QUEUE_STRATEGY_RINGALL, and call_queue::strategy.

Referenced by compare_weight(), is_our_turn(), remove_from_queue(), and set_queue_member_pause().

◆ parse_empty_options()

static void parse_empty_options ( const char *  value,
enum empty_conditions empty,
int  joinempty 
)
static

Definition at line 3318 of file app_queue.c.

3319{
3320 char *value_copy = ast_strdupa(value);
3321 char *option = NULL;
3322 while ((option = strsep(&value_copy, ","))) {
3323 if (!strcasecmp(option, "paused")) {
3324 *empty |= QUEUE_EMPTY_PAUSED;
3325 } else if (!strcasecmp(option, "penalty")) {
3326 *empty |= QUEUE_EMPTY_PENALTY;
3327 } else if (!strcasecmp(option, "inuse")) {
3328 *empty |= QUEUE_EMPTY_INUSE;
3329 } else if (!strcasecmp(option, "ringing")) {
3330 *empty |= QUEUE_EMPTY_RINGING;
3331 } else if (!strcasecmp(option, "invalid")) {
3332 *empty |= QUEUE_EMPTY_INVALID;
3333 } else if (!strcasecmp(option, "wrapup")) {
3334 *empty |= QUEUE_EMPTY_WRAPUP;
3335 } else if (!strcasecmp(option, "unavailable")) {
3336 *empty |= QUEUE_EMPTY_UNAVAILABLE;
3337 } else if (!strcasecmp(option, "unknown")) {
3338 *empty |= QUEUE_EMPTY_UNKNOWN;
3339 } else if (!strcasecmp(option, "loose")) {
3341 } else if (!strcasecmp(option, "strict")) {
3343 } else if ((ast_false(option) && joinempty) || (ast_true(option) && !joinempty)) {
3345 } else if ((ast_false(option) && !joinempty) || (ast_true(option) && joinempty)) {
3346 *empty = 0;
3347 } else {
3348 ast_log(LOG_WARNING, "Unknown option %s for '%s'\n", option, joinempty ? "joinempty" : "leavewhenempty");
3349 }
3350 }
3351}

References ast_false(), ast_log, ast_strdupa, ast_true(), LOG_WARNING, NULL, QUEUE_EMPTY_INUSE, QUEUE_EMPTY_INVALID, QUEUE_EMPTY_PAUSED, QUEUE_EMPTY_PENALTY, QUEUE_EMPTY_RINGING, QUEUE_EMPTY_UNAVAILABLE, QUEUE_EMPTY_UNKNOWN, QUEUE_EMPTY_WRAPUP, strsep(), and value.

Referenced by queue_set_param().

◆ pending_members_cmp()

static int pending_members_cmp ( void *  obj,
void *  arg,
int  flags 
)
static

Definition at line 2565 of file app_queue.c.

2566{
2567 const struct member *object_left = obj;
2568 const struct member *object_right = arg;
2569 const char *right_key = arg;
2570 int cmp;
2571
2572 switch (flags & OBJ_SEARCH_MASK) {
2573 case OBJ_SEARCH_OBJECT:
2574 right_key = object_right->interface;
2575 /* Fall through */
2576 case OBJ_SEARCH_KEY:
2577 cmp = strcasecmp(object_left->interface, right_key);
2578 break;
2580 /* Not supported by container. */
2581 ast_assert(0);
2582 return 0;
2583 default:
2584 cmp = 0;
2585 break;
2586 }
2587 if (cmp) {
2588 return 0;
2589 }
2590 return CMP_MATCH;
2591}
@ OBJ_SEARCH_PARTIAL_KEY
The arg parameter is a partial search key similar to OBJ_SEARCH_KEY.
Definition: astobj2.h:1116
@ OBJ_SEARCH_MASK
Search option field mask.
Definition: astobj2.h:1072
@ OBJ_SEARCH_KEY
The arg parameter is a search key, but is not an object.
Definition: astobj2.h:1101

References ast_assert, CMP_MATCH, member::interface, OBJ_SEARCH_KEY, OBJ_SEARCH_MASK, OBJ_SEARCH_OBJECT, and OBJ_SEARCH_PARTIAL_KEY.

Referenced by load_module().

◆ pending_members_hash()

static int pending_members_hash ( const void *  obj,
const int  flags 
)
static

Definition at line 2545 of file app_queue.c.

2546{
2547 const struct member *object;
2548 const char *key;
2549
2550 switch (flags & OBJ_SEARCH_MASK) {
2551 case OBJ_SEARCH_KEY:
2552 key = obj;
2553 break;
2554 case OBJ_SEARCH_OBJECT:
2555 object = obj;
2556 key = object->interface;
2557 break;
2558 default:
2559 ast_assert(0);
2560 return 0;
2561 }
2562 return ast_str_case_hash(key);
2563}
static force_inline int attribute_pure ast_str_case_hash(const char *str)
Compute a hash value on a case-insensitive string.
Definition: strings.h:1303

References ast_assert, ast_str_case_hash(), OBJ_SEARCH_KEY, OBJ_SEARCH_MASK, and OBJ_SEARCH_OBJECT.

Referenced by load_module().

◆ pending_members_remove()

static void pending_members_remove ( struct member mem)
static

Definition at line 2593 of file app_queue.c.

2594{
2595 ast_debug(3, "Removed %s from pending_members\n", mem->membername);
2597}
@ OBJ_NODATA
Definition: astobj2.h:1044
@ OBJ_UNLINK
Definition: astobj2.h:1039

References ao2_find, ast_debug, member::membername, OBJ_NODATA, OBJ_POINTER, OBJ_UNLINK, and pending_members.

Referenced by can_ring_entry(), do_hang(), hangupcalls(), member_remove_from_queue(), ring_entry(), try_calling(), update_queue(), and update_status().

◆ play_file()

static int play_file ( struct ast_channel chan,
const char *  filename 
)
static

Definition at line 4172 of file app_queue.c.

4173{
4174 int res;
4175
4176 if (ast_strlen_zero(filename)) {
4177 return 0;
4178 }
4179
4180 if (!ast_fileexists(filename, NULL, ast_channel_language(chan))) {
4181 return 0;
4182 }
4183
4184 ast_stopstream(chan);
4185
4186 res = ast_streamfile(chan, filename, ast_channel_language(chan));
4187 if (!res) {
4188 res = ast_waitstream(chan, AST_DIGIT_ANY);
4189 }
4190
4191 ast_stopstream(chan);
4192
4193 return res;
4194}
const char * ast_channel_language(const struct ast_channel *chan)
int ast_stopstream(struct ast_channel *c)
Stops a stream.
Definition: file.c:222
int ast_streamfile(struct ast_channel *c, const char *filename, const char *preflang)
Streams a file.
Definition: file.c:1293
int ast_fileexists(const char *filename, const char *fmt, const char *preflang)
Checks for the existence of a given file.
Definition: file.c:1129
#define AST_DIGIT_ANY
Definition: file.h:48
int ast_waitstream(struct ast_channel *c, const char *breakon)
Waits for a stream to stop or digit to be pressed.
Definition: file.c:1840

References ast_channel_language(), AST_DIGIT_ANY, ast_fileexists(), ast_stopstream(), ast_streamfile(), ast_strlen_zero(), ast_waitstream(), queue_ent::chan, and NULL.

Referenced by say_periodic_announcement(), say_position(), and try_calling().

◆ pqm_exec()

static int pqm_exec ( struct ast_channel chan,
const char *  data 
)
static

PauseQueueMember application.

Definition at line 8240 of file app_queue.c.

8241{
8242 char *parse;
8244 AST_APP_ARG(queuename);
8245 AST_APP_ARG(interface);
8247 AST_APP_ARG(reason);
8248 );
8249
8250 if (ast_strlen_zero(data)) {
8251 ast_log(LOG_WARNING, "PauseQueueMember requires an argument ([queuename],interface[,options][,reason])\n");
8252 return -1;
8253 }
8254
8255 parse = ast_strdupa(data);
8256
8258
8259 if (ast_strlen_zero(args.interface)) {
8260 ast_log(LOG_WARNING, "Missing interface argument to PauseQueueMember ([queuename],interface[,options[,reason]])\n");
8261 return -1;
8262 }
8263
8264 if (set_member_paused(args.queuename, args.interface, args.reason, 1)) {
8265 ast_log(LOG_WARNING, "Attempt to pause interface %s, not found\n", args.interface);
8266 pbx_builtin_setvar_helper(chan, "PQMSTATUS", "NOTFOUND");
8267 return 0;
8268 }
8269
8270 pbx_builtin_setvar_helper(chan, "PQMSTATUS", "PAUSED");
8271
8272 return 0;
8273}

References args, AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_log, AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), LOG_WARNING, options, pbx_builtin_setvar_helper(), and set_member_paused().

Referenced by load_module().

◆ print_queue()

static void print_queue ( struct mansession s,
int  fd,
struct call_queue q 
)
static

Print a single queue to AMI or the CLI.

Definition at line 10093 of file app_queue.c.

10094{
10095 float sl;
10096 float sl2;
10097 struct ao2_iterator mem_iter;
10098 struct ast_str *out = ast_str_alloca(512);
10099 time_t now = time(NULL);
10100
10101 ast_str_set(&out, 0, "%s has %d calls (max ", q->name, q->count);
10102 if (q->maxlen) {
10103 ast_str_append(&out, 0, "%d", q->maxlen);
10104 } else {
10105 ast_str_append(&out, 0, "unlimited");
10106 }
10107 sl = 0;
10108 sl2 = 0;
10109 if (q->callscompleted > 0) {
10110 sl = 100 * ((float) q->callscompletedinsl / (float) q->callscompleted);
10111 }
10112 if (q->callscompleted + q->callsabandoned > 0) {
10113 sl2 =100 * (((float)q->callsabandonedinsl + (float)q->callscompletedinsl) / ((float)q->callsabandoned + (float)q->callscompleted));
10114 }
10115
10116 ast_str_append(&out, 0, ") in '%s' strategy (%ds holdtime, %ds talktime), W:%d, C:%d, A:%d, SL:%2.1f%%, SL2:%2.1f%% within %ds",
10118 do_print(s, fd, ast_str_buffer(out));
10119 if (!ao2_container_count(q->members)) {
10120 do_print(s, fd, " No Members");
10121 } else {
10122 struct member *mem;
10123
10124 do_print(s, fd, " Members: ");
10125 mem_iter = ao2_iterator_init(q->members, 0);
10126 while ((mem = ao2_iterator_next(&mem_iter))) {
10127 ast_str_set(&out, 0, " %s", mem->membername);
10128 if (strcasecmp(mem->membername, mem->interface)) {
10129 ast_str_append(&out, 0, " (%s", mem->interface);
10131 && strcmp(mem->state_interface, mem->interface)) {
10132 ast_str_append(&out, 0, " from %s", mem->state_interface);
10133 }
10134 ast_str_append(&out, 0, ")");
10135 }
10136 if (mem->penalty) {
10137 ast_str_append(&out, 0, " with penalty %d", mem->penalty);
10138 }
10139
10140 ast_str_append(&out, 0, " (ringinuse %s)", mem->ringinuse ? "enabled" : "disabled");
10141
10142 ast_str_append(&out, 0, "%s%s%s%s%s%s%s%s%s",
10143 mem->dynamic ? ast_term_color(COLOR_CYAN, COLOR_BLACK) : "", mem->dynamic ? " (dynamic)" : "", ast_term_reset(),
10144 mem->realtime ? ast_term_color(COLOR_MAGENTA, COLOR_BLACK) : "", mem->realtime ? " (realtime)" : "", ast_term_reset(),
10145 mem->starttime ? ast_term_color(COLOR_BROWN, COLOR_BLACK) : "", mem->starttime ? " (in call)" : "", ast_term_reset());
10146
10147 if (mem->paused) {
10148 ast_str_append(&out, 0, " %s(paused%s%s was %ld secs ago)%s",
10150 ast_strlen_zero(mem->reason_paused) ? "" : ":",
10152 (long) (now - mem->lastpause),
10153 ast_term_reset());
10154 }
10155
10156 ast_str_append(&out, 0, " (%s%s%s)",
10161 if (mem->calls) {
10162 ast_str_append(&out, 0, " has taken %d calls (last was %ld secs ago)",
10163 mem->calls, (long) (now - mem->lastcall));
10164 } else {
10165 ast_str_append(&out, 0, " has taken no calls yet");
10166 }
10167 ast_str_append(&out, 0, " %s(login was %ld secs ago)%s",
10169 (long) (now - mem->logintime),
10170 ast_term_reset());
10171 do_print(s, fd, ast_str_buffer(out));
10172 ao2_ref(mem, -1);
10173 }
10174 ao2_iterator_destroy(&mem_iter);
10175 }
10176 if (!q->head) {
10177 do_print(s, fd, " No Callers");
10178 } else {
10179 struct queue_ent *qe;
10180 int pos = 1;
10181
10182 do_print(s, fd, " Callers: ");
10183 for (qe = q->head; qe; qe = qe->next) {
10184 ast_str_set(&out, 0, " %d. %s (wait: %ld:%2.2ld, prio: %d)",
10185 pos++, ast_channel_name(qe->chan), (long) (now - qe->start) / 60,
10186 (long) (now - qe->start) % 60, qe->prio);
10187 do_print(s, fd, ast_str_buffer(out));
10188 }
10189 }
10190 do_print(s, fd, ""); /* blank line between entries */
10191}
const char * ast_term_reset(void)
Returns the terminal reset code.
Definition: term.c:357
#define COLOR_CYAN
Definition: term.h:62
#define COLOR_MAGENTA
Definition: term.h:60
#define COLOR_BROWN
Definition: term.h:56
const char * ast_term_color(int fgcolor, int bgcolor)
Return a color sequence string.
Definition: term.c:341
#define COLOR_BLACK
Definition: term.h:50
#define COLOR_RED
Definition: term.h:52
#define COLOR_GREEN
Definition: term.h:54

References ao2_container_count(), ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_ref, ast_channel_name(), AST_DEVICE_UNAVAILABLE, AST_DEVICE_UNKNOWN, ast_devstate2str(), ast_str_alloca, ast_str_append(), ast_str_buffer(), ast_str_set(), ast_strlen_zero(), ast_term_color(), ast_term_reset(), member::calls, call_queue::callsabandoned, call_queue::callsabandonedinsl, call_queue::callscompleted, call_queue::callscompletedinsl, queue_ent::chan, COLOR_BLACK, COLOR_BROWN, COLOR_CYAN, COLOR_GREEN, COLOR_MAGENTA, COLOR_RED, call_queue::count, do_print(), member::dynamic, call_queue::head, call_queue::holdtime, int2strat(), member::interface, member::lastcall, member::lastpause, member::logintime, call_queue::maxlen, member::membername, call_queue::members, call_queue::name, queue_ent::next, NULL, out, member::paused, member::penalty, queue_ent::pos, queue_ent::prio, member::realtime, member::reason_paused, member::ringinuse, call_queue::servicelevel, queue_ent::start, member::starttime, member::state_interface, member::status, call_queue::strategy, call_queue::talktime, and call_queue::weight.

Referenced by __queues_show().

◆ publish_dial_end_event()

static void publish_dial_end_event ( struct ast_channel in,
struct callattempt outgoing,
struct ast_channel exception,
const char *  status 
)
static

Definition at line 4486 of file app_queue.c.

4487{
4488 struct callattempt *cur;
4489
4490 for (cur = outgoing; cur; cur = cur->q_next) {
4491 if (cur->chan && cur->chan != exception) {
4493 }
4494 }
4495}
struct callattempt * q_next
Definition: app_queue.c:1699
FILE * in
Definition: utils/frame.c:33

References ast_channel_publish_dial(), callattempt::chan, in, NULL, callattempt::q_next, and status.

Referenced by ring_entry(), and wait_for_answer().

◆ publish_queue_member_pause()

static int publish_queue_member_pause ( struct call_queue q,
struct member member 
)
static

Definition at line 7790 of file app_queue.c.

7791{
7792 struct ast_json *json_blob = queue_member_blob_create(q, member);
7793
7794 if (!json_blob) {
7795 return -1;
7796 }
7797
7798 queue_publish_member_blob(queue_member_pause_type(), json_blob);
7799
7800 return 0;
7801}

References queue_member_blob_create(), and queue_publish_member_blob().

Referenced by set_queue_member_pause().

◆ ql_exec()

static int ql_exec ( struct ast_channel chan,
const char *  data 
)
static

QueueLog application.

Definition at line 8477 of file app_queue.c.

8478{
8479 char *parse;
8480
8482 AST_APP_ARG(queuename);
8483 AST_APP_ARG(uniqueid);
8484 AST_APP_ARG(membername);
8486 AST_APP_ARG(params);
8487 );
8488
8489 if (ast_strlen_zero(data)) {
8490 ast_log(LOG_WARNING, "QueueLog requires arguments (queuename,uniqueid,membername,event[,additionalinfo]\n");
8491 return -1;
8492 }
8493
8494 parse = ast_strdupa(data);
8495
8497
8498 if (ast_strlen_zero(args.queuename) || ast_strlen_zero(args.uniqueid)
8499 || ast_strlen_zero(args.membername) || ast_strlen_zero(args.event)) {
8500 ast_log(LOG_WARNING, "QueueLog requires arguments (queuename,uniqueid,membername,event[,additionalinfo])\n");
8501 return -1;
8502 }
8503
8504 ast_queue_log(args.queuename, args.uniqueid, args.membername, args.event,
8505 "%s", args.params ? args.params : "");
8506
8507 return 0;
8508}

References args, AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_log, ast_queue_log(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), and LOG_WARNING.

Referenced by load_module().

◆ queue_agent_called_to_ami()

static struct ast_manager_event_blob * queue_agent_called_to_ami ( struct stasis_message message)
static

Definition at line 2293 of file app_queue.c.

2294{
2295 return queue_multi_channel_to_ami("AgentCalled", message);
2296}
static struct ast_manager_event_blob * queue_multi_channel_to_ami(const char *type, struct stasis_message *message)
Definition: app_queue.c:2252

References queue_multi_channel_to_ami().

◆ queue_agent_cb()

static void queue_agent_cb ( void *  userdata,
struct stasis_subscription sub,
struct stasis_message msg 
)
static

Definition at line 6189 of file app_queue.c.

6191{
6192 struct ast_channel_blob *agent_blob;
6193
6194 agent_blob = stasis_message_data(msg);
6195
6197 ast_queue_log("NONE", agent_blob->snapshot->base->uniqueid,
6198 ast_json_string_get(ast_json_object_get(agent_blob->blob, "agent")),
6199 "AGENTLOGIN", "%s", agent_blob->snapshot->base->name);
6201 ast_queue_log("NONE", agent_blob->snapshot->base->uniqueid,
6202 ast_json_string_get(ast_json_object_get(agent_blob->blob, "agent")),
6203 "AGENTLOGOFF", "%s|%ld", agent_blob->snapshot->base->name,
6204 (long) ast_json_integer_get(ast_json_object_get(agent_blob->blob, "logintime")));
6205 }
6206}

References ast_channel_agent_login_type(), ast_channel_agent_logoff_type(), ast_json_integer_get(), ast_json_object_get(), ast_json_string_get(), ast_queue_log(), ast_channel_snapshot::base, ast_channel_blob::blob, ast_channel_snapshot_base::name, ast_channel_blob::snapshot, stasis_message_data(), stasis_message_type(), and ast_channel_snapshot_base::uniqueid.

Referenced by load_module().

◆ queue_agent_complete_to_ami()

static struct ast_manager_event_blob * queue_agent_complete_to_ami ( struct stasis_message message)
static

Definition at line 2303 of file app_queue.c.

2304{
2305 return queue_multi_channel_to_ami("AgentComplete", message);
2306}

References queue_multi_channel_to_ami().

◆ queue_agent_connect_to_ami()

static struct ast_manager_event_blob * queue_agent_connect_to_ami ( struct stasis_message message)
static

Definition at line 2298 of file app_queue.c.

2299{
2300 return queue_multi_channel_to_ami("AgentConnect", message);
2301}

References queue_multi_channel_to_ami().

◆ queue_agent_dump_to_ami()

static struct ast_manager_event_blob * queue_agent_dump_to_ami ( struct stasis_message message)
static

Definition at line 2308 of file app_queue.c.

2309{
2310 return queue_multi_channel_to_ami("AgentDump", message);
2311}

References queue_multi_channel_to_ami().

◆ queue_agent_ringnoanswer_to_ami()

static struct ast_manager_event_blob * queue_agent_ringnoanswer_to_ami ( struct stasis_message message)
static

Definition at line 2313 of file app_queue.c.

2314{
2315 return queue_multi_channel_to_ami("AgentRingNoAnswer", message);
2316}

References queue_multi_channel_to_ami().

◆ queue_bridge_cb()

static void queue_bridge_cb ( void *  userdata,
struct stasis_subscription sub,
struct stasis_message msg 
)
static

Definition at line 6552 of file app_queue.c.

6554{
6556 ao2_cleanup(userdata);
6557 }
6558}
struct stasis_forward * sub
Definition: res_corosync.c:240
int stasis_subscription_final_message(struct stasis_subscription *sub, struct stasis_message *msg)
Determine whether a message is the final message to be received on a subscription.
Definition: stasis.c:1175

References ao2_cleanup, stasis_subscription_final_message(), and sub.

Referenced by setup_stasis_subs().

◆ queue_caller_abandon_to_ami()

static struct ast_manager_event_blob * queue_caller_abandon_to_ami ( struct stasis_message message)
static

Definition at line 2173 of file app_queue.c.

2174{
2175 return queue_channel_to_ami("QueueCallerAbandon", message);
2176}
static struct ast_manager_event_blob * queue_channel_to_ami(const char *type, struct stasis_message *message)
Definition: app_queue.c:2144

References queue_channel_to_ami().

◆ queue_caller_join_to_ami()

static struct ast_manager_event_blob * queue_caller_join_to_ami ( struct stasis_message message)
static

Definition at line 2163 of file app_queue.c.

2164{
2165 return queue_channel_to_ami("QueueCallerJoin", message);
2166}

References queue_channel_to_ami().

◆ queue_caller_leave_to_ami()

static struct ast_manager_event_blob * queue_caller_leave_to_ami ( struct stasis_message message)
static

Definition at line 2168 of file app_queue.c.

2169{
2170 return queue_channel_to_ami("QueueCallerLeave", message);
2171}

References queue_channel_to_ami().

◆ queue_channel_cb()

static void queue_channel_cb ( void *  userdata,
struct stasis_subscription sub,
struct stasis_message msg 
)
static

Definition at line 6777 of file app_queue.c.

6779{
6781 ao2_cleanup(userdata);
6782 }
6783}

References ao2_cleanup, stasis_subscription_final_message(), and sub.

Referenced by setup_stasis_subs().

◆ queue_channel_to_ami()

static struct ast_manager_event_blob * queue_channel_to_ami ( const char *  type,
struct stasis_message message 
)
static

Definition at line 2144 of file app_queue.c.

2145{
2147 RAII_VAR(struct ast_str *, channel_string, NULL, ast_free);
2148 RAII_VAR(struct ast_str *, event_string, NULL, ast_free);
2149
2150 channel_string = ast_manager_build_channel_state_string(obj->snapshot);
2151 event_string = ast_manager_str_from_json_object(obj->blob, NULL);
2152 if (!channel_string || !event_string) {
2153 return NULL;
2154 }
2155
2157 "%s"
2158 "%s",
2159 ast_str_buffer(channel_string),
2160 ast_str_buffer(event_string));
2161}
static const char type[]
Definition: chan_ooh323.c:109
struct ast_str * ast_manager_str_from_json_object(struct ast_json *blob, key_exclusion_cb exclusion_cb)
Convert a JSON object into an AMI compatible string.
Definition: manager.c:554
struct ast_str * ast_manager_build_channel_state_string(const struct ast_channel_snapshot *snapshot)
Generate the AMI message body from a channel snapshot.
struct ast_manager_event_blob * ast_manager_event_blob_create(int event_flags, const char *manager_event, const char *extra_fields_fmt,...)
Construct a ast_manager_event_blob.
Definition: manager.c:10128

References ast_free, ast_manager_build_channel_state_string(), ast_manager_event_blob_create(), ast_manager_str_from_json_object(), ast_str_buffer(), ast_channel_blob::blob, EVENT_FLAG_AGENT, NULL, RAII_VAR, ast_channel_blob::snapshot, stasis_message_data(), and type.

Referenced by queue_caller_abandon_to_ami(), queue_caller_join_to_ami(), and queue_caller_leave_to_ami().

◆ queue_cmp_cb()

static int queue_cmp_cb ( void *  obj,
void *  arg,
int  flags 
)
static

Definition at line 2007 of file app_queue.c.

2008{
2009 struct call_queue *q = obj, *q2 = arg;
2010 return !strcasecmp(q->name, q2->name) ? CMP_MATCH | CMP_STOP : 0;
2011}

References CMP_MATCH, CMP_STOP, and call_queue::name.

Referenced by load_module().

◆ queue_delme_members_decrement_followers()

static int queue_delme_members_decrement_followers ( void *  obj,
void *  arg,
int  flag 
)
static

Definition at line 2053 of file app_queue.c.

2054{
2055 struct member *mem = obj;
2056 struct call_queue *queue = arg;
2057 int rrpos = mem->queuepos;
2058
2059 if (mem->delme) {
2061 }
2062
2063 return 0;
2064}
static int queue_member_decrement_followers(void *obj, void *arg, int flag)
Definition: app_queue.c:2034
#define ao2_callback(c, flags, cb_fn, arg)
ao2_callback() is a generic function that applies cb_fn() to all objects in a container,...
Definition: astobj2.h:1693
@ OBJ_MULTIPLE
Definition: astobj2.h:1049

References ao2_callback, member::delme, call_queue::members, OBJ_MULTIPLE, OBJ_NODATA, queue_member_decrement_followers(), member::queuepos, and call_queue::rrpos.

Referenced by reload_single_queue().

◆ queue_exec()

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 8554 of file app_queue.c.

8555{
8556 int res=-1;
8557 int ringing=0;
8558 const char *user_priority;
8559 const char *max_penalty_str;
8560 const char *min_penalty_str;
8561 const char *raise_penalty_str;
8562 int prio;
8563 int qcontinue = 0;
8564 int max_penalty, min_penalty, raise_penalty;
8565 enum queue_result reason = QUEUE_UNKNOWN;
8566 /* whether to exit Queue application after the timeout hits */
8567 int tries = 0;
8568 int noption = 0;
8569 char *parse;
8570 int makeannouncement = 0;
8571 int position = 0;
8573 AST_APP_ARG(queuename);
8576 AST_APP_ARG(announceoverride);
8577 AST_APP_ARG(queuetimeoutstr);
8578 AST_APP_ARG(agi);
8579 AST_APP_ARG(gosub);
8581 AST_APP_ARG(position);
8582 );
8583 /* Our queue entry */
8584 struct queue_ent qe = { 0 };
8585 struct ast_flags opts = { 0, };
8586 char *opt_args[OPT_ARG_ARRAY_SIZE];
8587 int max_forwards;
8588 int cid_allow;
8589
8590 if (ast_strlen_zero(data)) {
8591 ast_log(LOG_WARNING, "Queue requires an argument: queuename[,options[,URL[,announceoverride[,timeout[,agi[,gosub[,rule[,position]]]]]]]]\n");
8592 return -1;
8593 }
8594
8595 ast_channel_lock(chan);
8597 ast_channel_unlock(chan);
8598
8599 if (max_forwards <= 0) {
8600 ast_log(LOG_WARNING, "Channel '%s' cannot enter queue. Max forwards exceeded\n", ast_channel_name(chan));
8601 return -1;
8602 }
8603
8604 parse = ast_strdupa(data);
8606
8607 ast_debug(1, "queue: %s, options: %s, url: %s, announce: %s, timeout: %s, agi: %s, gosub: %s, rule: %s, position: %s\n",
8608 args.queuename,
8609 S_OR(args.options, ""),
8610 S_OR(args.url, ""),
8611 S_OR(args.announceoverride, ""),
8612 S_OR(args.queuetimeoutstr, ""),
8613 S_OR(args.agi, ""),
8614 S_OR(args.gosub, ""),
8615 S_OR(args.rule, ""),
8616 S_OR(args.position, ""));
8617
8618 if (!ast_strlen_zero(args.options)) {
8619 ast_app_parse_options(queue_exec_options, &opts, opt_args, args.options);
8620 }
8621
8622 /* Setup our queue entry */
8623 qe.start = time(NULL);
8624
8625 pbx_builtin_setvar_helper(chan, "ABANDONED", NULL);
8626
8627 /* set the expire time based on the supplied timeout; */
8628 if (!ast_strlen_zero(args.queuetimeoutstr)) {
8629 qe.expire = qe.start + atoi(args.queuetimeoutstr);
8630 } else {
8631 qe.expire = 0;
8632 }
8633
8634 /* Get the priority from the variable ${QUEUE_PRIO} */
8635 ast_channel_lock(chan);
8636 user_priority = pbx_builtin_getvar_helper(chan, "QUEUE_PRIO");
8637 if (user_priority) {
8638 if (sscanf(user_priority, "%30d", &prio) == 1) {
8639 ast_debug(1, "%s: Got priority %d from ${QUEUE_PRIO}.\n", ast_channel_name(chan), prio);
8640 } else {
8641 ast_log(LOG_WARNING, "${QUEUE_PRIO}: Invalid value (%s), channel %s.\n",
8642 user_priority, ast_channel_name(chan));
8643 prio = 0;
8644 }
8645 } else {
8646 ast_debug(3, "NO QUEUE_PRIO variable found. Using default.\n");
8647 prio = 0;
8648 }
8649
8650 /* Get the maximum penalty from the variable ${QUEUE_MAX_PENALTY} */
8651
8652 if ((max_penalty_str = pbx_builtin_getvar_helper(chan, "QUEUE_MAX_PENALTY"))) {
8653 if (sscanf(max_penalty_str, "%30d", &max_penalty) == 1) {
8654 ast_debug(1, "%s: Got max penalty %d from ${QUEUE_MAX_PENALTY}.\n", ast_channel_name(chan), max_penalty);
8655 } else {
8656 ast_log(LOG_WARNING, "${QUEUE_MAX_PENALTY}: Invalid value (%s), channel %s.\n",
8657 max_penalty_str, ast_channel_name(chan));
8658 max_penalty = INT_MAX;
8659 }
8660 } else {
8661 max_penalty = INT_MAX;
8662 }
8663
8664 if ((min_penalty_str = pbx_builtin_getvar_helper(chan, "QUEUE_MIN_PENALTY"))) {
8665 if (sscanf(min_penalty_str, "%30d", &min_penalty) == 1) {
8666 ast_debug(1, "%s: Got min penalty %d from ${QUEUE_MIN_PENALTY}.\n", ast_channel_name(chan), min_penalty);
8667 } else {
8668 ast_log(LOG_WARNING, "${QUEUE_MIN_PENALTY}: Invalid value (%s), channel %s.\n",
8669 min_penalty_str, ast_channel_name(chan));
8670 min_penalty = INT_MAX;
8671 }
8672 } else {
8673 min_penalty = INT_MAX;
8674 }
8675
8676 if ((raise_penalty_str = pbx_builtin_getvar_helper(chan, "QUEUE_RAISE_PENALTY"))) {
8677 if (sscanf(raise_penalty_str, "%30d", &raise_penalty) == 1) {
8678 ast_debug(1, "%s: Got raise penalty %d from ${QUEUE_RAISE_PENALTY}.\n", ast_channel_name(chan), raise_penalty);
8679 } else {
8680 ast_log(LOG_WARNING, "${QUEUE_RAISE_PENALTY}: Invalid value (%s), channel %s.\n",
8681 raise_penalty_str, ast_channel_name(chan));
8682 raise_penalty = INT_MAX;
8683 }
8684 } else {
8685 raise_penalty = INT_MAX;
8686 }
8687 ast_channel_unlock(chan);
8688
8689 if (ast_test_flag(&opts, OPT_RINGING)) {
8690 ringing = 1;
8691 }
8692
8693 if (ringing != 1 && ast_test_flag(&opts, OPT_RING_WHEN_RINGING)) {
8694 qe.ring_when_ringing = 1;
8695 }
8696
8697 if (ast_test_flag(&opts, OPT_GO_ON)) {
8698 qcontinue = 1;
8699 }
8700
8701 if (args.position) {
8702 position = atoi(args.position);
8703 if (position < 0) {
8704 ast_log(LOG_WARNING, "Invalid position '%s' given for call to queue '%s'. Assuming no preference for position\n", args.position, args.queuename);
8705 position = 0;
8706 }
8707 }
8708
8709 ast_debug(1, "queue: %s, expires: %ld, priority: %d\n",
8710 args.queuename, (long)qe.expire, prio);
8711
8712 qe.chan = chan;
8713 qe.prio = prio;
8714 qe.max_penalty = max_penalty;
8715 qe.min_penalty = min_penalty;
8716 qe.raise_penalty = raise_penalty;
8717 qe.last_pos_said = 0;
8718 qe.last_pos = 0;
8721 qe.valid_digits = 0;
8722 if (join_queue(args.queuename, &qe, &reason, position)) {
8723 ast_log(LOG_WARNING, "Unable to join queue '%s'\n", args.queuename);
8724 set_queue_result(chan, reason);
8725 return 0;
8726 }
8727 ast_assert(qe.parent != NULL);
8728
8729 if (qe.parent->periodicannouncestartdelay >= 0) {
8732 }
8733
8735
8736 ast_queue_log(args.queuename, ast_channel_uniqueid(chan), "NONE", "ENTERQUEUE", "%s|%s|%d",
8737 S_OR(args.url, ""),
8738 S_COR(cid_allow && ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, ""),
8739 qe.opos);
8740
8741 /* PREDIAL: Preprocess any callee gosub arguments. */
8743 && !ast_strlen_zero(opt_args[OPT_ARG_PREDIAL_CALLEE])) {
8746 }
8747
8748 /* PREDIAL: Run gosub on the caller's channel */
8750 && !ast_strlen_zero(opt_args[OPT_ARG_PREDIAL_CALLER])) {
8752 ast_app_exec_sub(NULL, chan, opt_args[OPT_ARG_PREDIAL_CALLER], 0);
8753 }
8754
8755 /* Music on hold class override */
8758 ast_copy_string(qe.moh, opt_args[OPT_ARG_MUSICONHOLD_CLASS], sizeof(qe.moh));
8759 }
8760
8761 copy_rules(&qe, args.rule);
8762 qe.pr = AST_LIST_FIRST(&qe.qe_rules);
8763check_turns:
8764 if (ringing) {
8766 } else {
8767 ast_moh_start(chan, qe.moh, NULL);
8768 }
8769
8770 /* This is the wait loop for callers 2 through maxlen */
8771 res = wait_our_turn(&qe, ringing, &reason);
8772 if (res) {
8773 goto stop;
8774 }
8775
8776 makeannouncement = qe.parent->announce_to_first_user;
8777
8778 for (;;) {
8779 /* This is the wait loop for the head caller*/
8780 /* To exit, they may get their call answered; */
8781 /* they may dial a digit from the queue context; */
8782 /* or, they may timeout. */
8783
8784 /* A request to withdraw this call from the queue arrived */
8785 if (qe.withdraw) {
8786 reason = QUEUE_WITHDRAW;
8787 res = 1;
8788 break;
8789 }
8790
8791 /* Leave if we have exceeded our queuetimeout */
8792 if (qe.expire && (time(NULL) >= qe.expire)) {
8793 record_abandoned(&qe);
8794 reason = QUEUE_TIMEOUT;
8795 res = 0;
8796 ast_queue_log(args.queuename, ast_channel_uniqueid(chan),"NONE", "EXITWITHTIMEOUT", "%d|%d|%ld",
8797 qe.pos, qe.opos, (long) (time(NULL) - qe.start));
8798 break;
8799 }
8800
8801 if (makeannouncement) {
8802 /* Make a position announcement, if enabled */
8803 if (qe.parent->announcefrequency) {
8804 if ((res = say_position(&qe, ringing))) {
8805 goto stop;
8806 }
8807 }
8808 }
8809 makeannouncement = 1;
8810
8811 /* Make a periodic announcement, if enabled */
8813 if ((res = say_periodic_announcement(&qe, ringing))) {
8814 goto stop;
8815 }
8816 }
8817
8818 /* A request to withdraw this call from the queue arrived */
8819 if (qe.withdraw) {
8820 reason = QUEUE_WITHDRAW;
8821 res = 1;
8822 break;
8823 }
8824
8825 /* Leave if we have exceeded our queuetimeout */
8826 if (qe.expire && (time(NULL) >= qe.expire)) {
8827 record_abandoned(&qe);
8828 reason = QUEUE_TIMEOUT;
8829 res = 0;
8830 ast_queue_log(args.queuename, ast_channel_uniqueid(chan), "NONE", "EXITWITHTIMEOUT",
8831 "%d|%d|%ld", qe.pos, qe.opos, (long) (time(NULL) - qe.start));
8832 break;
8833 }
8834
8835 /* see if we need to move to the next penalty level for this queue */
8836 while (qe.pr && ((time(NULL) - qe.start) > qe.pr->time)) {
8837 update_qe_rule(&qe);
8838 }
8839
8840 /* Try calling all queue members for 'timeout' seconds */
8841 res = try_calling(&qe, opts, opt_args, args.announceoverride, args.url, &tries, &noption, args.agi, args.gosub, ringing);
8842 if (res) {
8843 goto stop;
8844 }
8845
8846 if (qe.parent->leavewhenempty) {
8847 int status = 0;
8849 record_abandoned(&qe);
8850 reason = QUEUE_LEAVEEMPTY;
8851 ast_queue_log(args.queuename, ast_channel_uniqueid(chan), "NONE", "EXITEMPTY", "%d|%d|%ld", qe.pos, qe.opos, (long)(time(NULL) - qe.start));
8852 res = 0;
8853 break;
8854 }
8855 }
8856
8857 /* exit after 'timeout' cycle if 'n' option enabled */
8858 if (noption && tries >= ao2_container_count(qe.parent->members)) {
8859 ast_verb(3, "Exiting on time-out cycle\n");
8860 ast_queue_log(args.queuename, ast_channel_uniqueid(chan), "NONE", "EXITWITHTIMEOUT",
8861 "%d|%d|%ld", qe.pos, qe.opos, (long) (time(NULL) - qe.start));
8862 record_abandoned(&qe);
8863 reason = QUEUE_TIMEOUT;
8864 res = 0;
8865 break;
8866 }
8867
8868
8869 /* Leave if we have exceeded our queuetimeout */
8870 if (qe.expire && (time(NULL) >= qe.expire)) {
8871 record_abandoned(&qe);
8872 reason = QUEUE_TIMEOUT;
8873 res = 0;
8874 ast_queue_log(qe.parent->name, ast_channel_uniqueid(qe.chan),"NONE", "EXITWITHTIMEOUT", "%d|%d|%ld", qe.pos, qe.opos, (long) (time(NULL) - qe.start));
8875 break;
8876 }
8877
8878 /* OK, we didn't get anybody; wait for 'retry' seconds; may get a digit to exit with */
8879 res = wait_a_bit(&qe);
8880 if (res) {
8881 goto stop;
8882 }
8883
8884 /* If using dynamic realtime members, we should regenerate the member list for this queue */
8886
8887 /* Since this is a priority queue and
8888 * it is not sure that we are still at the head
8889 * of the queue, go and check for our turn again.
8890 */
8891 if (!is_our_turn(&qe)) {
8892 ast_debug(1, "Darn priorities, going back in queue (%s)!\n", ast_channel_name(qe.chan));
8893 goto check_turns;
8894 }
8895 }
8896
8897stop:
8898 if (res) {
8899 if (reason == QUEUE_WITHDRAW) {
8900 record_abandoned(&qe);
8901 ast_queue_log(qe.parent->name, ast_channel_uniqueid(qe.chan), "NONE", "WITHDRAW", "%d|%d|%ld|%.40s", qe.pos, qe.opos, (long) (time(NULL) - qe.start), qe.withdraw_info ? qe.withdraw_info : "");
8902 if (qe.withdraw_info) {
8903 pbx_builtin_setvar_helper(qe.chan, "QUEUE_WITHDRAW_INFO", qe.withdraw_info);
8904 }
8905 res = 0;
8906 } else if (res < 0) {
8907 if (!qe.handled) {
8908 record_abandoned(&qe);
8909 ast_queue_log(args.queuename, ast_channel_uniqueid(chan), "NONE", "ABANDON",
8910 "%d|%d|%ld", qe.pos, qe.opos,
8911 (long) (time(NULL) - qe.start));
8912 res = -1;
8913 } else if (reason == QUEUE_LEAVEEMPTY) {
8914 /* Return back to dialplan, don't hang up */
8915 res = 0;
8916 } else if (qcontinue) {
8917 reason = QUEUE_CONTINUE;
8918 res = 0;
8919 }
8920 } else if (qe.valid_digits) {
8921 ast_queue_log(args.queuename, ast_channel_uniqueid(chan), "NONE", "EXITWITHKEY",
8922 "%s|%d|%d|%ld", qe.digits, qe.pos, qe.opos, (long) (time(NULL) - qe.start));
8923 }
8924 }
8925
8926 /* Free the optional withdraw info if present */
8927 /* This is done here to catch all cases. e.g. if the call eventually wasn't withdrawn, e.g. answered */
8928 if (qe.withdraw_info) {
8930 qe.withdraw_info = NULL;
8931 }
8932
8933 /* Don't allow return code > 0 */
8934 if (res >= 0) {
8935 res = 0;
8936 if (ringing) {
8937 ast_indicate(chan, -1);
8938 } else {
8939 ast_moh_stop(chan);
8940 }
8941 ast_stopstream(chan);
8942 }
8943
8945
8946 leave_queue(&qe);
8947 if (reason != QUEUE_UNKNOWN)
8948 set_queue_result(chan, reason);
8949
8950 /*
8951 * every queue_ent is given a reference to it's parent
8952 * call_queue when it joins the queue. This ref must be taken
8953 * away right before the queue_ent is destroyed. In this case
8954 * the queue_ent is about to be returned on the stack
8955 */
8956 qe.parent = queue_unref(qe.parent);
8957
8958 return res;
8959}
static int is_our_turn(struct queue_ent *qe)
Check if we should start attempting to call queue members.
Definition: app_queue.c:5774
static void record_abandoned(struct queue_ent *qe)
Record that a caller gave up on waiting in queue.
Definition: app_queue.c:5108
static void set_queue_result(struct ast_channel *chan, enum queue_result res)
sets the QUEUESTATUS channel variable
Definition: app_queue.c:1939
static void leave_queue(struct queue_ent *qe)
Caller leaving queue.
Definition: app_queue.c:4401
static int say_periodic_announcement(struct queue_ent *qe, int ringing)
Playback announcement to queued members if period has elapsed.
Definition: app_queue.c:5047
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.
Definition: app_queue.c:5913
static void copy_rules(struct queue_ent *qe, const char *rulename)
Copy rule from global list into specified queue.
Definition: app_queue.c:8511
static const struct ast_app_option queue_exec_options[128]
Definition: app_queue.c:1516
queue_result
Definition: app_queue.c:1654
static void update_qe_rule(struct queue_ent *qe)
update rules for queues
Definition: app_queue.c:5823
static int join_queue(char *queuename, struct queue_ent *qe, enum queue_result *reason, int position)
Definition: app_queue.c:4088
static int say_position(struct queue_ent *qe, int ringing)
Definition: app_queue.c:4236
static int wait_a_bit(struct queue_ent *qe)
Definition: app_queue.c:7474
static int try_calling(struct queue_ent *qe, struct ast_flags opts, char **opt_args, char *announceoverride, const char *url, int *tries, int *noption, const char *agi, const char *gosub, int ringing)
Definition: app_queue.c:7007
unsigned int stop
Definition: app_sla.c:336
static void ringing(struct ast_channel *chan)
Helper method to send a ringing indication to a channel in a bridge.
#define AST_PRES_ALLOWED
Definition: callerid.h:432
#define AST_PRES_RESTRICTION
Definition: callerid.h:431
int ast_party_id_presentation(const struct ast_party_id *id)
Determine the overall presentation value for the given party.
Definition: channel.c:1840
#define ast_channel_lock(chan)
Definition: channel.h:2968
int ast_indicate(struct ast_channel *chan, int condition)
Indicates condition of channel.
Definition: channel.c:4296
#define ast_channel_unlock(chan)
Definition: channel.h:2969
int ast_app_exec_sub(struct ast_channel *autoservice_chan, struct ast_channel *sub_chan, const char *sub_args, int ignore_hangup)
Run a subroutine on a channel, placing an optional second channel into autoservice.
Definition: main/app.c:297
@ AST_CONTROL_RINGING
#define ast_verb(level,...)
#define AST_LIST_FIRST(head)
Returns the first entry contained in a list.
Definition: linkedlists.h:421
int ast_max_forwards_get(struct ast_channel *chan)
Get the current max forwards for a particular channel.
Definition: max_forwards.c:121
int ast_moh_start(struct ast_channel *chan, const char *mclass, const char *interpclass)
Turn on music on hold on a given channel.
Definition: channel.c:7788
void ast_moh_stop(struct ast_channel *chan)
Turn off music on hold on a given channel.
Definition: channel.c:7798
static char url[512]
Channel datastore data for max forwards.
Definition: max_forwards.c:29
Number structure.
Definition: app_followme.c:154
char digits[AST_MAX_EXTENSION]
Definition: app_queue.c:1726
int valid_digits
Definition: app_queue.c:1728
time_t last_pos
Definition: app_queue.c:1735
time_t last_periodic_announce_time
Definition: app_queue.c:1733
time_t expire
Definition: app_queue.c:1745
unsigned int withdraw
Definition: app_queue.c:1747
int ring_when_ringing
Definition: app_queue.c:1732
char * withdraw_info
Definition: app_queue.c:1748
int handled
Definition: app_queue.c:1737
int last_pos_said
Definition: app_queue.c:1731
int last_periodic_announce_sound
Definition: app_queue.c:1734
const char * predial_callee
Definition: app_queue.c:1727
void ast_replace_subargument_delimiter(char *s)
Replace '^' in a string with ','.
Definition: utils.c:2343

References call_queue::announce_to_first_user, call_queue::announcefrequency, ao2_container_count(), args, AST_APP_ARG, ast_app_exec_sub(), ast_app_parse_options(), ast_assert, ast_channel_caller(), ast_channel_lock, ast_channel_name(), ast_channel_uniqueid(), ast_channel_unlock, AST_CONTROL_RINGING, ast_copy_string(), ast_debug, AST_DECLARE_APP_ARGS, ast_free, ast_indicate(), AST_LIST_FIRST, ast_log, ast_max_forwards_get(), ast_moh_start(), ast_moh_stop(), ast_party_id_presentation(), AST_PRES_ALLOWED, AST_PRES_RESTRICTION, ast_queue_log(), ast_replace_subargument_delimiter(), AST_STANDARD_APP_ARGS, ast_stopstream(), ast_strdupa, ast_strlen_zero(), ast_test_flag, ast_verb, queue_ent::chan, copy_rules(), queue_ent::digits, queue_ent::expire, get_member_status(), queue_ent::handled, is_our_turn(), join_queue(), queue_ent::last_periodic_announce_sound, queue_ent::last_periodic_announce_time, queue_ent::last_pos, queue_ent::last_pos_said, leave_queue(), call_queue::leavewhenempty, call_queue::log_restricted_caller_id, LOG_WARNING, queue_ent::max_penalty, call_queue::members, queue_ent::min_penalty, queue_ent::moh, call_queue::name, NULL, queue_ent::opos, OPT_ARG_ARRAY_SIZE, OPT_ARG_MUSICONHOLD_CLASS, OPT_ARG_PREDIAL_CALLEE, OPT_ARG_PREDIAL_CALLER, OPT_GO_ON, OPT_MUSICONHOLD_CLASS, OPT_PREDIAL_CALLEE, OPT_PREDIAL_CALLER, OPT_RING_WHEN_RINGING, OPT_RINGING, options, queue_ent::parent, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), call_queue::periodicannouncefrequency, call_queue::periodicannouncestartdelay, queue_ent::pos, queue_ent::pr, queue_ent::predial_callee, queue_ent::prio, queue_ent::qe_rules, QUEUE_CONTINUE, queue_exec_options, QUEUE_LEAVEEMPTY, QUEUE_TIMEOUT, QUEUE_UNKNOWN, queue_unref, QUEUE_WITHDRAW, queue_ent::raise_penalty, record_abandoned(), queue_ent::ring_when_ringing, ringing(), S_COR, S_OR, say_periodic_announcement(), say_position(), set_queue_result(), set_queue_variables(), queue_ent::start, status, stop, penalty_rule::time, try_calling(), update_qe_rule(), update_realtime_members(), url, queue_ent::valid_digits, wait_a_bit(), wait_our_turn(), queue_ent::withdraw, and queue_ent::withdraw_info.

Referenced by load_module().

◆ queue_function_exists()

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 9010 of file app_queue.c.

9011{
9012 struct call_queue *q;
9013
9014 buf[0] = '\0';
9015
9016 if (ast_strlen_zero(data)) {
9017 ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd);
9018 return -1;
9019 }
9021 snprintf(buf, len, "%d", q != NULL? 1 : 0);
9022 if (q) {
9023 queue_t_unref(q, "Done with temporary reference in QUEUE_EXISTS()");
9024 }
9025
9026 return 0;
9027}
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)

References ast_log, ast_strlen_zero(), buf, find_load_queue_rt_friendly(), len(), LOG_ERROR, NULL, and queue_t_unref.

◆ queue_function_mem_read()

static int queue_function_mem_read ( 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.

Get or set member properties penalty / paused / ringinuse

Return values
numberof members (busy / free / ready / total) or member info (penalty / paused / ringinuse)
-1on error

Definition at line 9052 of file app_queue.c.

9053{
9054 int count = 0;
9055 struct member *m;
9056 struct ao2_iterator mem_iter;
9057 struct call_queue *q;
9058
9060 AST_APP_ARG(queuename);
9061 AST_APP_ARG(option);
9062 AST_APP_ARG(interface);
9063 );
9064 /* Make sure the returned value on error is zero length string. */
9065 buf[0] = '\0';
9066
9067 if (ast_strlen_zero(data)) {
9069 "Missing required argument. %s(<queuename>,<option>[,<interface>])\n",
9070 cmd);
9071 return -1;
9072 }
9073
9075
9076 if (ast_strlen_zero(args.queuename) || ast_strlen_zero(args.option)) {
9078 "Missing required argument. %s(<queuename>,<option>[,<interface>])\n",
9079 cmd);
9080 return -1;
9081 }
9082
9083 if ((q = find_load_queue_rt_friendly(args.queuename))) {
9084 ao2_lock(q);
9085 if (!strcasecmp(args.option, "logged")) {
9086 mem_iter = ao2_iterator_init(q->members, 0);
9087 while ((m = ao2_iterator_next(&mem_iter))) {
9088 /* Count the agents who are logged in and presently answering calls */
9089 if ((m->status != AST_DEVICE_UNAVAILABLE) && (m->status != AST_DEVICE_INVALID)) {
9090 count++;
9091 }
9092 ao2_ref(m, -1);
9093 }
9094 ao2_iterator_destroy(&mem_iter);
9095 } else if (!strcasecmp(args.option, "free")) {
9096 mem_iter = ao2_iterator_init(q->members, 0);
9097 while ((m = ao2_iterator_next(&mem_iter))) {
9098 /* Count the agents who are logged in and presently answering calls */
9099 if ((m->status == AST_DEVICE_NOT_INUSE) && (!m->paused)) {
9100 count++;
9101 }
9102 ao2_ref(m, -1);
9103 }
9104 ao2_iterator_destroy(&mem_iter);
9105 } else if (!strcasecmp(args.option, "ready")) {
9106 time_t now;
9107 time(&now);
9108 mem_iter = ao2_iterator_init(q->members, 0);
9109 while ((m = ao2_iterator_next(&mem_iter))) {
9110 /* Count the agents who are logged in, not paused and not wrapping up */
9111 if ((m->status == AST_DEVICE_NOT_INUSE) && (!m->paused) &&
9112 !(m->lastcall && get_wrapuptime(q, m) && ((now - get_wrapuptime(q, m)) < m->lastcall))) {
9113 count++;
9114 }
9115 ao2_ref(m, -1);
9116 }
9117 ao2_iterator_destroy(&mem_iter);
9118 } else if (!strcasecmp(args.option, "count")) {
9120 } else if (!strcasecmp(args.option, "penalty")) {
9121 m = get_interface_helper(q, args.interface);
9122 if (m) {
9123 count = m->penalty;
9124 ao2_ref(m, -1);
9125 }
9126 } else if (!strcasecmp(args.option, "paused")) {
9127 m = get_interface_helper(q, args.interface);
9128 if (m) {
9129 count = m->paused;
9130 ao2_ref(m, -1);
9131 }
9132 } else if ((!strcasecmp(args.option, "ignorebusy") /* ignorebusy is legacy */
9133 || !strcasecmp(args.option, "ringinuse"))) {
9134 m = get_interface_helper(q, args.interface);
9135 if (m) {
9136 count = m->ringinuse;
9137 ao2_ref(m, -1);
9138 }
9139 } else {
9140 ast_log(LOG_ERROR, "%s: Invalid option '%s' provided.\n", cmd, args.option);
9141 }
9142 ao2_unlock(q);
9143 queue_t_unref(q, "Done with temporary reference in QUEUE_MEMBER()");
9144 } else {
9145 ast_log(LOG_WARNING, "queue %s was not found\n", args.queuename);
9146 }
9147
9148 snprintf(buf, len, "%d", count);
9149
9150 return 0;
9151}
static struct member * get_interface_helper(struct call_queue *q, const char *interface)
Definition: app_queue.c:9029

References ao2_container_count(), ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_lock, ao2_ref, ao2_unlock, args, AST_APP_ARG, AST_DECLARE_APP_ARGS, AST_DEVICE_INVALID, AST_DEVICE_NOT_INUSE, AST_DEVICE_UNAVAILABLE, ast_log, AST_STANDARD_APP_ARGS, ast_strlen_zero(), buf, call_queue::count, find_load_queue_rt_friendly(), get_interface_helper(), get_wrapuptime(), member::lastcall, len(), LOG_ERROR, LOG_WARNING, call_queue::members, member::paused, member::penalty, queue_t_unref, member::ringinuse, and member::status.

◆ queue_function_mem_write()

static int queue_function_mem_write ( struct ast_channel chan,
const char *  cmd,
char *  data,
const char *  value 
)
static

Dialplan function QUEUE_MEMBER() Sets the members penalty / paused / ringinuse.

Definition at line 9154 of file app_queue.c.

9155{
9156 int memvalue;
9157
9159 AST_APP_ARG(queuename);
9160 AST_APP_ARG(option);
9161 AST_APP_ARG(interface);
9162 );
9163
9164 if (ast_strlen_zero(data)) {
9166 "Missing required argument. %s([<queuename>],<option>,<interface>)\n",
9167 cmd);
9168 return -1;
9169 }
9170
9172
9173 if (ast_strlen_zero(args.option)
9174 || ast_strlen_zero(args.interface)) {
9176 "Missing required argument. %s([<queuename>],<option>,<interface>)\n",
9177 cmd);
9178 return -1;
9179 }
9180
9181 /*
9182 * If queuename is empty then the option will be
9183 * set for the interface in all queues.
9184 */
9185
9186 memvalue = atoi(value);
9187 if (!strcasecmp(args.option, "penalty")) {
9188 if (set_member_value(args.queuename, args.interface, MEMBER_PENALTY, memvalue)) {
9189 ast_log(LOG_ERROR, "Invalid interface, queue, or penalty\n");
9190 return -1;
9191 }
9192 } else if (!strcasecmp(args.option, "paused")) {
9193 memvalue = (memvalue <= 0) ? 0 : 1;
9194 if (set_member_paused(args.queuename, args.interface, NULL, memvalue)) {
9195 ast_log(LOG_ERROR, "Invalid interface or queue\n");
9196 return -1;
9197 }
9198 } else if (!strcasecmp(args.option, "ignorebusy") /* ignorebusy is legacy */
9199 || !strcasecmp(args.option, "ringinuse")) {
9200 memvalue = (memvalue <= 0) ? 0 : 1;
9201 if (set_member_value(args.queuename, args.interface, MEMBER_RINGINUSE, memvalue)) {
9202 ast_log(LOG_ERROR, "Invalid interface or queue\n");
9203 return -1;
9204 }
9205 } else {
9206 ast_log(LOG_ERROR, "%s: Invalid option '%s' provided.\n", cmd, args.option);
9207 return -1;
9208 }
9209 return 0;
9210}

References args, AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_log, AST_STANDARD_APP_ARGS, ast_strlen_zero(), LOG_ERROR, MEMBER_PENALTY, MEMBER_RINGINUSE, NULL, set_member_paused(), set_member_value(), and value.

◆ queue_function_memberpenalty_read()

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 9422 of file app_queue.c.

9423{
9424 int penalty;
9426 AST_APP_ARG(queuename);
9427 AST_APP_ARG(interface);
9428 );
9429 /* Make sure the returned value on error is NULL. */
9430 buf[0] = '\0';
9431
9432 if (ast_strlen_zero(data)) {
9433 ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n");
9434 return -1;
9435 }
9436
9438
9439 if (args.argc < 2) {
9440 ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n");
9441 return -1;
9442 }
9443
9444 penalty = get_member_penalty (args.queuename, args.interface);
9445
9446 if (penalty >= 0) { /* remember that buf is already '\0' */
9447 snprintf (buf, len, "%d", penalty);
9448 }
9449
9450 return 0;
9451}
static int get_member_penalty(char *queuename, char *interface)
Gets members penalty.
Definition: app_queue.c:8098

References args, AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_log, AST_STANDARD_APP_ARGS, ast_strlen_zero(), buf, get_member_penalty(), len(), and LOG_ERROR.

◆ queue_function_memberpenalty_write()

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 9454 of file app_queue.c.

9455{
9456 int penalty;
9458 AST_APP_ARG(queuename);
9459 AST_APP_ARG(interface);
9460 );
9461
9462 if (ast_strlen_zero(data)) {
9463 ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n");
9464 return -1;
9465 }
9466
9468
9469 if (args.argc < 2) {
9470 ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n");
9471 return -1;
9472 }
9473
9474 penalty = atoi(value);
9475
9476 if (ast_strlen_zero(args.interface)) {
9477 ast_log (LOG_ERROR, "<interface> parameter can't be null\n");
9478 return -1;
9479 }
9480
9481 /* if queuename = NULL then penalty will be set for interface in all the queues. */
9482 if (set_member_value(args.queuename, args.interface, MEMBER_PENALTY, penalty)) {
9483 ast_log(LOG_ERROR, "Invalid interface, queue or penalty\n");
9484 return -1;
9485 }
9486
9487 return 0;
9488}

References args, AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_log, AST_STANDARD_APP_ARGS, ast_strlen_zero(), LOG_ERROR, MEMBER_PENALTY, set_member_value(), and value.

◆ queue_function_qac_dep()

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)

Return values
numberof members
-1on error

Definition at line 9217 of file app_queue.c.

9218{
9219 int count = 0;
9220 struct member *m;
9221 struct call_queue *q;
9222 struct ao2_iterator mem_iter;
9223 static int depflag = 1;
9224
9225 if (depflag) {
9226 depflag = 0;
9227 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");
9228 }
9229
9230 if (ast_strlen_zero(data)) {
9231 ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd);
9232 return -1;
9233 }
9234
9235 if ((q = find_load_queue_rt_friendly(data))) {
9236 ao2_lock(q);
9237 mem_iter = ao2_iterator_init(q->members, 0);
9238 while ((m = ao2_iterator_next(&mem_iter))) {
9239 /* Count the agents who are logged in and presently answering calls */
9240 if ((m->status != AST_DEVICE_UNAVAILABLE) && (m->status != AST_DEVICE_INVALID)) {
9241 count++;
9242 }
9243 ao2_ref(m, -1);
9244 }
9245 ao2_iterator_destroy(&mem_iter);
9246 ao2_unlock(q);
9247 queue_t_unref(q, "Done with temporary reference in QUEUE_MEMBER_COUNT");
9248 } else {
9249 ast_log(LOG_WARNING, "queue %s was not found\n", data);
9250 }
9251
9252 snprintf(buf, len, "%d", count);
9253
9254 return 0;
9255}

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(), buf, call_queue::count, find_load_queue_rt_friendly(), len(), LOG_ERROR, LOG_NOTICE, LOG_WARNING, call_queue::members, queue_t_unref, and member::status.

◆ queue_function_queuegetchannel()

static int queue_function_queuegetchannel ( struct ast_channel chan,
const char *  cmd,
char *  data,
char *  buf,
size_t  len 
)
static

Dialplan function QUEUE_GET_CHANNEL() Get caller channel waiting at specified position in the queue.

Definition at line 9258 of file app_queue.c.

9259{
9260 int position;
9261 char *parse;
9262 struct call_queue *q;
9263 struct ast_variable *var;
9264
9266 AST_APP_ARG(queuename);
9267 AST_APP_ARG(position);
9268 );
9269
9270 buf[0] = '\0';
9271
9272 if (ast_strlen_zero(data)) {
9273 ast_log(LOG_ERROR, "Missing argument. QUEUE_GET_CHANNEL(<queuename>,<position>)\n");
9274 return -1;
9275 }
9276
9277 parse = ast_strdupa(data);
9279
9280 if (ast_strlen_zero(args.queuename)) {
9281 ast_log (LOG_ERROR, "The <queuename> parameter is required.\n");
9282 return -1;
9283 }
9284
9285 if (ast_strlen_zero(args.position)) {
9286 position = 1;
9287 } else {
9288 if (sscanf(args.position, "%30d", &position) != 1) {
9289 ast_log (LOG_ERROR, "<position> parameter must be an integer.\n");
9290 return -1;
9291 }
9292 if (position < 1) {
9293 ast_log (LOG_ERROR, "<position> parameter must be an integer greater than zero.\n");
9294 return -1;
9295 }
9296 }
9297
9298 {
9299 struct call_queue tmpq = {
9300 .name = args.queuename,
9301 };
9302
9303 q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Find for QUEUE_GET_CHANNEL()");
9304 }
9305 if (q) {
9306 ao2_lock(q);
9307 if (q->count >= position) {
9308 struct queue_ent *qe;
9309
9310 for (qe = q->head; qe; qe = qe->next) {
9311 if (qe->pos == position) {
9313 break;
9314 }
9315 }
9316 }
9317 ao2_unlock(q);
9318 queue_t_unref(q, "Done with reference in QUEUE_GET_CHANNEL()");
9319 return 0;
9320 }
9321
9322 var = ast_load_realtime("queues", "name", args.queuename, SENTINEL);
9323 if (var) {
9324 /* if the queue is realtime but was not found in memory, this
9325 * means that the queue had been deleted from memory since it was
9326 * "dead."
9327 */
9329 return 0;
9330 }
9331
9332 ast_log(LOG_WARNING, "queue %s was not found\n", args.queuename);
9333 return 0;
9334}

References ao2_lock, ao2_t_find, ao2_unlock, args, AST_APP_ARG, ast_channel_name(), ast_copy_string(), AST_DECLARE_APP_ARGS, ast_load_realtime(), ast_log, AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), ast_variables_destroy(), buf, queue_ent::chan, call_queue::count, call_queue::head, len(), LOG_ERROR, LOG_WARNING, call_queue::name, queue_ent::next, OBJ_POINTER, queue_ent::pos, queue_t_unref, queues, SENTINEL, and var.

◆ queue_function_queuememberlist()

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 9374 of file app_queue.c.

9375{
9376 struct call_queue *q;
9377 struct member *m;
9378
9379 /* Ensure an otherwise empty list doesn't return garbage */
9380 buf[0] = '\0';
9381
9382 if (ast_strlen_zero(data)) {
9383 ast_log(LOG_ERROR, "QUEUE_MEMBER_LIST requires an argument: queuename\n");
9384 return -1;
9385 }
9386
9387 if ((q = find_load_queue_rt_friendly(data))) {
9388 int buflen = 0, count = 0;
9389 struct ao2_iterator mem_iter;
9390
9391 ao2_lock(q);
9392 mem_iter = ao2_iterator_init(q->members, 0);
9393 while ((m = ao2_iterator_next(&mem_iter))) {
9394 /* strcat() is always faster than printf() */
9395 if (count++) {
9396 strncat(buf + buflen, ",", len - buflen - 1);
9397 buflen++;
9398 }
9399 strncat(buf + buflen, m->interface, len - buflen - 1);
9400 buflen += strlen(m->interface);
9401 /* Safeguard against overflow (negative length) */
9402 if (buflen >= len - 2) {
9403 ao2_ref(m, -1);
9404 ast_log(LOG_WARNING, "Truncating list\n");
9405 break;
9406 }
9407 ao2_ref(m, -1);
9408 }
9409 ao2_iterator_destroy(&mem_iter);
9410 ao2_unlock(q);
9411 queue_t_unref(q, "Done with QUEUE_MEMBER_LIST()");
9412 } else
9413 ast_log(LOG_WARNING, "queue %s was not found\n", data);
9414
9415 /* We should already be terminated, but let's make sure. */
9416 buf[len - 1] = '\0';
9417
9418 return 0;
9419}

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_lock, ao2_ref, ao2_unlock, ast_log, ast_strlen_zero(), buf, find_load_queue_rt_friendly(), member::interface, len(), LOG_ERROR, LOG_WARNING, call_queue::members, and queue_t_unref.

◆ queue_function_queuewaitingcount()

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 9337 of file app_queue.c.

9338{
9339 int count = 0;
9340 struct call_queue *q, tmpq = {
9341 .name = data,
9342 };
9343 struct ast_variable *var = NULL;
9344
9345 buf[0] = '\0';
9346
9347 if (ast_strlen_zero(data)) {
9348 ast_log(LOG_ERROR, "QUEUE_WAITING_COUNT requires an argument: queuename\n");
9349 return -1;
9350 }
9351
9352 if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Find for QUEUE_WAITING_COUNT()"))) {
9353 ao2_lock(q);
9354 count = q->count;
9355 ao2_unlock(q);
9356 queue_t_unref(q, "Done with reference in QUEUE_WAITING_COUNT()");
9357 } else if ((var = ast_load_realtime("queues", "name", data, SENTINEL))) {
9358 /* if the queue is realtime but was not found in memory, this
9359 * means that the queue had been deleted from memory since it was
9360 * "dead." This means it has a 0 waiting count
9361 */
9362 count = 0;
9364 } else {
9365 ast_log(LOG_WARNING, "queue %s was not found\n", data);
9366 }
9367
9368 snprintf(buf, len, "%d", count);
9369
9370 return 0;
9371}

References ao2_lock, ao2_t_find, ao2_unlock, ast_load_realtime(), ast_log, ast_strlen_zero(), ast_variables_destroy(), buf, call_queue::count, len(), LOG_ERROR, LOG_WARNING, call_queue::name, NULL, OBJ_POINTER, queue_t_unref, queues, SENTINEL, and var.

◆ queue_function_var()

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.

Return values
0on success
-1on error

Definition at line 8966 of file app_queue.c.

8967{
8968 int res = -1;
8969 struct call_queue *q;
8970 char interfacevar[256] = "";
8971 float sl = 0;
8972
8973 if (ast_strlen_zero(data)) {
8974 ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd);
8975 return -1;
8976 }
8977
8978 if ((q = find_load_queue_rt_friendly(data))) {
8979 ao2_lock(q);
8980 if (q->setqueuevar) {
8981 sl = 0;
8982 res = 0;
8983
8984 if (q->callscompleted > 0) {
8985 sl = 100 * ((float) q->callscompletedinsl / (float) q->callscompleted);
8986 }
8987
8988 snprintf(interfacevar, sizeof(interfacevar),
8989 "QUEUEMAX=%d,QUEUESTRATEGY=%s,QUEUECALLS=%d,QUEUEHOLDTIME=%d,QUEUETALKTIME=%d,QUEUECOMPLETED=%d,QUEUEABANDONED=%d,QUEUESRVLEVEL=%d,QUEUESRVLEVELPERF=%2.1f",
8991
8992 pbx_builtin_setvar_multiple(chan, interfacevar);
8993 }
8994
8995 ao2_unlock(q);
8996 queue_t_unref(q, "Done with QUEUE() function");
8997 } else {
8998 ast_log(LOG_WARNING, "queue %s was not found\n", data);
8999 }
9000
9001 snprintf(buf, len, "%d", res);
9002
9003 return 0;
9004}
int pbx_builtin_setvar_multiple(struct ast_channel *chan, const char *data)
Parse and set multiple channel variables, where the pairs are separated by the ',' character,...

References ao2_lock, ao2_unlock, ast_log, ast_strlen_zero(), buf, call_queue::callsabandoned, call_queue::callscompleted, call_queue::callscompletedinsl, call_queue::count, find_load_queue_rt_friendly(), call_queue::holdtime, int2strat(), len(), LOG_ERROR, LOG_WARNING, call_queue::maxlen, pbx_builtin_setvar_multiple(), queue_t_unref, call_queue::servicelevel, call_queue::setqueuevar, call_queue::strategy, and call_queue::talktime.

◆ queue_hash_cb()

static int queue_hash_cb ( const void *  obj,
const int  flags 
)
static

Definition at line 2000 of file app_queue.c.

2001{
2002 const struct call_queue *q = obj;
2003
2004 return ast_str_case_hash(q->name);
2005}

References ast_str_case_hash(), and call_queue::name.

Referenced by load_module().

◆ queue_member_added_to_ami()

static struct ast_manager_event_blob * queue_member_added_to_ami ( struct stasis_message message)
static

Definition at line 2208 of file app_queue.c.

2209{
2210 return queue_member_to_ami("QueueMemberAdded", message);
2211}
static struct ast_manager_event_blob * queue_member_to_ami(const char *type, struct stasis_message *message)
Definition: app_queue.c:2188

References queue_member_to_ami().

◆ queue_member_blob_create()

static struct ast_json * queue_member_blob_create ( struct call_queue q,
struct member mem 
)
static

Definition at line 2424 of file app_queue.c.

2425{
2426 return ast_json_pack("{s: s, s: s, s: s, s: s, s: s, s: i, s: i, s: i, s: i, s: i, s: i, s: i, s: i, s: s, s: i, s: i}",
2427 "Queue", q->name,
2428 "MemberName", mem->membername,
2429 "Interface", mem->interface,
2430 "StateInterface", mem->state_interface,
2431 "Membership", (mem->dynamic ? "dynamic" : (mem->realtime ? "realtime" : "static")),
2432 "Penalty", mem->penalty,
2433 "CallsTaken", mem->calls,
2434 "LastCall", (int)mem->lastcall,
2435 "LastPause", (int)mem->lastpause,
2436 "LoginTime", (int)mem->logintime,
2437 "InCall", mem->starttime ? 1 : 0,
2438 "Status", mem->status,
2439 "Paused", mem->paused,
2440 "PausedReason", mem->reason_paused,
2441 "Ringinuse", mem->ringinuse,
2442 "Wrapuptime", mem->wrapuptime);
2443}

References ast_json_pack(), member::calls, member::dynamic, member::interface, member::lastcall, member::lastpause, member::logintime, member::membername, call_queue::name, member::paused, member::penalty, member::realtime, member::reason_paused, member::ringinuse, member::starttime, member::state_interface, member::status, and member::wrapuptime.

Referenced by add_to_queue(), publish_queue_member_pause(), remove_from_queue(), set_member_penalty_help_members(), set_queue_member_ringinuse(), and update_status().

◆ queue_member_decrement_followers()

static int queue_member_decrement_followers ( void *  obj,
void *  arg,
int  flag 
)
static

Definition at line 2034 of file app_queue.c.

2035{
2036 struct member *mem = obj;
2037 int *decrement_followers_after = arg;
2038
2039 if (mem->queuepos > *decrement_followers_after) {
2040 mem->queuepos--;
2041 }
2042
2043 return 0;
2044}

References member::queuepos.

Referenced by queue_delme_members_decrement_followers(), and queue_member_follower_removal().

◆ queue_member_follower_removal()

static void queue_member_follower_removal ( struct call_queue queue,
struct member mem 
)
static

Definition at line 2071 of file app_queue.c.

2072{
2073 int pos = mem->queuepos;
2074
2075 /* If the position being removed is less than the current place in the queue, reduce the queue position by one so that we don't skip the member
2076 * who would have been next otherwise. */
2077 if (pos < queue->rrpos) {
2078 queue->rrpos--;
2079 }
2080
2082}

References ao2_callback, call_queue::members, OBJ_MULTIPLE, OBJ_NODATA, queue_member_decrement_followers(), member::queuepos, and call_queue::rrpos.

Referenced by member_remove_from_queue().

◆ queue_member_pause_to_ami()

static struct ast_manager_event_blob * queue_member_pause_to_ami ( struct stasis_message message)
static

Definition at line 2218 of file app_queue.c.

2219{
2220 return queue_member_to_ami("QueueMemberPause", message);
2221}

References queue_member_to_ami().

◆ queue_member_penalty_to_ami()

static struct ast_manager_event_blob * queue_member_penalty_to_ami ( struct stasis_message message)
static

Definition at line 2223 of file app_queue.c.

2224{
2225 return queue_member_to_ami("QueueMemberPenalty", message);
2226}

References queue_member_to_ami().

◆ queue_member_removed_to_ami()

static struct ast_manager_event_blob * queue_member_removed_to_ami ( struct stasis_message message)
static

Definition at line 2213 of file app_queue.c.

2214{
2215 return queue_member_to_ami("QueueMemberRemoved", message);
2216}

References queue_member_to_ami().

◆ queue_member_ringinuse_to_ami()

static struct ast_manager_event_blob * queue_member_ringinuse_to_ami ( struct stasis_message message)
static

Definition at line 2228 of file app_queue.c.

2229{
2230 return queue_member_to_ami("QueueMemberRinginuse", message);
2231}

References queue_member_to_ami().

◆ queue_member_status_to_ami()

static struct ast_manager_event_blob * queue_member_status_to_ami ( struct stasis_message message)
static

Definition at line 2203 of file app_queue.c.

2204{
2205 return queue_member_to_ami("QueueMemberStatus", message);
2206}

References queue_member_to_ami().

◆ queue_member_to_ami()

static struct ast_manager_event_blob * queue_member_to_ami ( const char *  type,
struct stasis_message message 
)
static

◆ queue_multi_channel_to_ami()

static struct ast_manager_event_blob * queue_multi_channel_to_ami ( const char *  type,
struct stasis_message message 
)
static

Definition at line 2252 of file app_queue.c.

2253{
2256 struct ast_channel_snapshot *agent;
2257 RAII_VAR(struct ast_str *, caller_event_string, NULL, ast_free);
2258 RAII_VAR(struct ast_str *, agent_event_string, NULL, ast_free);
2259 RAII_VAR(struct ast_str *, event_string, NULL, ast_free);
2260
2262 if (caller) {
2263 caller_event_string = ast_manager_build_channel_state_string(caller);
2264 if (!caller_event_string) {
2265 ast_log(LOG_NOTICE, "No caller event string, bailing\n");
2266 return NULL;
2267 }
2268 }
2269
2270 agent = ast_multi_channel_blob_get_channel(obj, "agent");
2271 if (agent) {
2272 agent_event_string = ast_manager_build_channel_state_string_prefix(agent, "Dest");
2273 if (!agent_event_string) {
2274 ast_log(LOG_NOTICE, "No agent event string, bailing\n");
2275 return NULL;
2276 }
2277 }
2278
2280 if (!event_string) {
2281 return NULL;
2282 }
2283
2285 "%s"
2286 "%s"
2287 "%s",
2288 caller_event_string ? ast_str_buffer(caller_event_string) : "",
2289 agent_event_string ? ast_str_buffer(agent_event_string) : "",
2290 ast_str_buffer(event_string));
2291}
struct ast_str * ast_manager_build_channel_state_string_prefix(const struct ast_channel_snapshot *snapshot, const char *prefix)
Generate the AMI message body from a channel snapshot.
struct ast_channel_snapshot_caller * caller

References ast_free, ast_log, ast_manager_build_channel_state_string(), ast_manager_build_channel_state_string_prefix(), ast_manager_event_blob_create(), ast_manager_str_from_json_object(), ast_multi_channel_blob_get_channel(), ast_multi_channel_blob_get_json(), ast_str_buffer(), ast_channel_snapshot::caller, EVENT_FLAG_AGENT, LOG_NOTICE, NULL, RAII_VAR, stasis_message_data(), and type.

Referenced by queue_agent_called_to_ami(), queue_agent_complete_to_ami(), queue_agent_connect_to_ami(), queue_agent_dump_to_ami(), and queue_agent_ringnoanswer_to_ami().

◆ queue_publish_member_blob()

static void queue_publish_member_blob ( struct stasis_message_type type,
struct ast_json blob 
)
static

Definition at line 2400 of file app_queue.c.

2401{
2402 RAII_VAR(struct ast_json_payload *, payload, NULL, ao2_cleanup);
2403 RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
2404
2405 if (!blob || !type) {
2406 ast_json_unref(blob);
2407 return;
2408 }
2409
2410 payload = ast_json_payload_create(blob);
2411 ast_json_unref(blob);
2412 if (!payload) {
2413 return;
2414 }
2415
2416 msg = stasis_message_create(type, payload);
2417 if (!msg) {
2418 return;
2419 }
2420
2422}
struct ast_json_payload * ast_json_payload_create(struct ast_json *json)
Create an ao2 object to pass json blobs as data payloads for stasis.
Definition: json.c:756
struct stasis_message * stasis_message_create(struct stasis_message_type *type, void *data)
Create a new message.
void stasis_publish(struct stasis_topic *topic, struct stasis_message *message)
Publish a message to a topic's subscribers.
Definition: stasis.c:1512

References ao2_cleanup, ast_json_payload_create(), ast_json_unref(), ast_manager_get_topic(), NULL, RAII_VAR, stasis_message_create(), stasis_publish(), and type.

Referenced by add_to_queue(), publish_queue_member_pause(), remove_from_queue(), set_member_penalty_help_members(), set_queue_member_ringinuse(), and update_status().

◆ queue_publish_multi_channel_blob()

static void queue_publish_multi_channel_blob ( struct ast_channel caller,
struct ast_channel agent,
struct stasis_message_type type,
struct ast_json blob 
)
static

Definition at line 2369 of file app_queue.c.

2371{
2372 RAII_VAR(struct ast_channel_snapshot *, caller_snapshot, NULL, ao2_cleanup);
2373 RAII_VAR(struct ast_channel_snapshot *, agent_snapshot, NULL, ao2_cleanup);
2374
2375 ast_channel_lock(caller);
2376 caller_snapshot = ast_channel_snapshot_create(caller);
2377 ast_channel_unlock(caller);
2378 ast_channel_lock(agent);
2379 agent_snapshot = ast_channel_snapshot_create(agent);
2380 ast_channel_unlock(agent);
2381
2382 if (!caller_snapshot || !agent_snapshot) {
2383 return;
2384 }
2385
2387 agent_snapshot, type, blob);
2388}
static void queue_publish_multi_channel_snapshot_blob(struct stasis_topic *topic, struct ast_channel_snapshot *caller_snapshot, struct ast_channel_snapshot *agent_snapshot, struct stasis_message_type *type, struct ast_json *blob)
Definition: app_queue.c:2334
struct stasis_topic * ast_channel_topic(struct ast_channel *chan)
A topic which publishes the events for a particular channel.
struct ast_channel_snapshot * ast_channel_snapshot_create(struct ast_channel *chan)
Generate a snapshot of the channel state. This is an ao2 object, so ao2_cleanup() to deallocate.

References ao2_cleanup, ast_channel_lock, ast_channel_snapshot_create(), ast_channel_topic(), ast_channel_unlock, NULL, queue_publish_multi_channel_snapshot_blob(), RAII_VAR, and type.

Referenced by ring_entry(), rna(), and try_calling().

◆ queue_publish_multi_channel_snapshot_blob()

static void queue_publish_multi_channel_snapshot_blob ( struct stasis_topic topic,
struct ast_channel_snapshot caller_snapshot,
struct ast_channel_snapshot agent_snapshot,
struct stasis_message_type type,
struct ast_json blob 
)
static

Definition at line 2334 of file app_queue.c.

2338{
2339 RAII_VAR(struct ast_multi_channel_blob *, payload, NULL, ao2_cleanup);
2340 RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
2341
2342 if (!type) {
2343 return;
2344 }
2345
2346 payload = ast_multi_channel_blob_create(blob);
2347 if (!payload) {
2348 return;
2349 }
2350
2351 if (caller_snapshot) {
2352 ast_multi_channel_blob_add_channel(payload, "caller", caller_snapshot);
2353 } else {
2354 ast_debug(1, "Empty caller_snapshot; sending incomplete event\n");
2355 }
2356
2357 if (agent_snapshot) {
2358 ast_multi_channel_blob_add_channel(payload, "agent", agent_snapshot);
2359 }
2360
2361 msg = stasis_message_create(type, payload);
2362 if (!msg) {
2363 return;
2364 }
2365
2366 stasis_publish(topic, msg);
2367}
struct ast_multi_channel_blob * ast_multi_channel_blob_create(struct ast_json *blob)
Create a ast_multi_channel_blob suitable for a stasis_message.
void ast_multi_channel_blob_add_channel(struct ast_multi_channel_blob *obj, const char *role, struct ast_channel_snapshot *snapshot)
Add a ast_channel_snapshot to a ast_multi_channel_blob object.

References ao2_cleanup, ast_debug, ast_multi_channel_blob_add_channel(), ast_multi_channel_blob_create(), NULL, RAII_VAR, stasis_message_create(), stasis_publish(), and type.

Referenced by queue_publish_multi_channel_blob(), and send_agent_complete().

◆ queue_reset_global_params()

static void queue_reset_global_params ( void  )
static

Always set the global queue defaults, even if there is no "general" section in queues.conf

Definition at line 9612 of file app_queue.c.

9613{
9615 autofill_default = 0;
9616 montype_default = 0;
9617 shared_lastcall = 0;
9621}
static int montype_default
queues.conf [general] option
Definition: app_queue.c:1628
static int negative_penalty_invalid
queues.conf [general] option
Definition: app_queue.c:1640
static int shared_lastcall
queues.conf [general] option
Definition: app_queue.c:1631

References autofill_default, force_longest_waiting_caller, log_membername_as_agent, montype_default, negative_penalty_invalid, queue_persistent_members, and shared_lastcall.

Referenced by reload_queues().

◆ queue_rules_reset_global_params()

static void queue_rules_reset_global_params ( void  )
static

Reset the global queue rules parameters even if there is no "general" section of queuerules.conf

Definition at line 9533 of file app_queue.c.

9534{
9535 realtime_rules = 0;
9536}
static int realtime_rules
queuerules.conf [general] option
Definition: app_queue.c:1634

References realtime_rules.

Referenced by reload_queue_rules().

◆ queue_rules_set_global_params()

static void queue_rules_set_global_params ( struct ast_config cfg)
static

Set the global queue rules parameters as defined in the "general" section of queuerules.conf

Definition at line 9539 of file app_queue.c.

9540{
9541 const char *general_val = NULL;
9542 if ((general_val = ast_variable_retrieve(cfg, "general", "realtime_rules"))) {
9543 realtime_rules = ast_true(general_val);
9544 }
9545}

References ast_true(), ast_variable_retrieve(), NULL, and realtime_rules.

Referenced by reload_queue_rules().

◆ queue_set_global_params()

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 9624 of file app_queue.c.

9625{
9626 const char *general_val = NULL;
9627 if ((general_val = ast_variable_retrieve(cfg, "general", "persistentmembers"))) {
9628 queue_persistent_members = ast_true(general_val);
9629 }
9630 if ((general_val = ast_variable_retrieve(cfg, "general", "autofill"))) {
9631 autofill_default = ast_true(general_val);
9632 }
9633 if ((general_val = ast_variable_retrieve(cfg, "general", "monitor-type"))) {
9634 if (!strcasecmp(general_val, "mixmonitor"))
9635 montype_default = 1;
9636 }
9637 if ((general_val = ast_variable_retrieve(cfg, "general", "shared_lastcall"))) {
9638 shared_lastcall = ast_true(general_val);
9639 }
9640 if ((general_val = ast_variable_retrieve(cfg, "general", "negative_penalty_invalid"))) {
9641 negative_penalty_invalid = ast_true(general_val);
9642 }
9643 if ((general_val = ast_variable_retrieve(cfg, "general", "log_membername_as_agent"))) {
9644 log_membername_as_agent = ast_true(general_val);
9645 }
9646 if ((general_val = ast_variable_retrieve(cfg, "general", "force_longest_waiting_caller"))) {
9648 }
9649}

References ast_true(), ast_variable_retrieve(), autofill_default, force_longest_waiting_caller, log_membername_as_agent, montype_default, negative_penalty_invalid, NULL, queue_persistent_members, and shared_lastcall.

Referenced by reload_queues().

◆ queue_set_param()

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.

Note
For error reporting, line number is passed for .conf static configuration, for Realtime queues, linenum is -1.

Definition at line 3361 of file app_queue.c.

3362{
3363 if (!strcasecmp(param, "musicclass") ||
3364 !strcasecmp(param, "music") || !strcasecmp(param, "musiconhold")) {
3365 ast_string_field_set(q, moh, val);
3366 } else if (!strcasecmp(param, "announce")) {
3367 ast_string_field_set(q, announce, val);
3368 } else if (!strcasecmp(param, "context")) {
3370 } else if (!strcasecmp(param, "timeout")) {
3371 q->timeout = atoi(val);
3372 if (q->timeout < 0) {
3374 }
3375 } else if (!strcasecmp(param, "ringinuse")) {
3376 q->ringinuse = ast_true(val);
3377 } else if (!strcasecmp(param, "setinterfacevar")) {
3379 } else if (!strcasecmp(param, "setqueuevar")) {
3380 q->setqueuevar = ast_true(val);
3381 } else if (!strcasecmp(param, "setqueueentryvar")) {
3383 } else if (!strcasecmp(param, "monitor-format")) {
3384 ast_copy_string(q->monfmt, val, sizeof(q->monfmt));
3385 } else if (!strcasecmp(param, "membergosub")) {
3386 ast_string_field_set(q, membergosub, val);
3387 } else if (!strcasecmp(param, "queue-youarenext")) {
3388 ast_string_field_set(q, sound_next, val);
3389 } else if (!strcasecmp(param, "queue-thereare")) {
3390 ast_string_field_set(q, sound_thereare, val);
3391 } else if (!strcasecmp(param, "queue-callswaiting")) {
3392 ast_string_field_set(q, sound_calls, val);
3393 } else if (!strcasecmp(param, "queue-quantity1")) {
3394 ast_string_field_set(q, queue_quantity1, val);
3395 } else if (!strcasecmp(param, "queue-quantity2")) {
3396 ast_string_field_set(q, queue_quantity2, val);
3397 } else if (!strcasecmp(param, "queue-holdtime")) {
3398 ast_string_field_set(q, sound_holdtime, val);
3399 } else if (!strcasecmp(param, "queue-minutes")) {
3400 ast_string_field_set(q, sound_minutes, val);
3401 } else if (!strcasecmp(param, "queue-minute")) {
3402 ast_string_field_set(q, sound_minute, val);
3403 } else if (!strcasecmp(param, "queue-seconds")) {
3404 ast_string_field_set(q, sound_seconds, val);
3405 } else if (!strcasecmp(param, "queue-thankyou")) {
3406 ast_string_field_set(q, sound_thanks, val);
3407 } else if (!strcasecmp(param, "queue-callerannounce")) {
3408 ast_string_field_set(q, sound_callerannounce, val);
3409 } else if (!strcasecmp(param, "queue-reporthold")) {
3410 ast_string_field_set(q, sound_reporthold, val);
3411 } else if (!strcasecmp(param, "announce-frequency")) {
3412 q->announcefrequency = atoi(val);
3413 } else if (!strcasecmp(param, "announce-to-first-user")) {
3415 } else if (!strcasecmp(param, "min-announce-frequency")) {
3416 q->minannouncefrequency = atoi(val);
3417 ast_debug(1, "%s=%s for queue '%s'\n", param, val, q->name);
3418 } else if (!strcasecmp(param, "announce-round-seconds")) {
3419 q->roundingseconds = atoi(val);
3420 /* Rounding to any other values just doesn't make sense... */
3421 if (!(q->roundingseconds == 0 || q->roundingseconds == 5 || q->roundingseconds == 10
3422 || q->roundingseconds == 15 || q->roundingseconds == 20 || q->roundingseconds == 30)) {
3423 if (linenum >= 0) {
3424 ast_log(LOG_WARNING, "'%s' isn't a valid value for %s "
3425 "using 0 instead for queue '%s' at line %d of queues.conf\n",
3426 val, param, q->name, linenum);
3427 } else {
3428 ast_log(LOG_WARNING, "'%s' isn't a valid value for %s "
3429 "using 0 instead for queue '%s'\n", val, param, q->name);
3430 }
3431 q->roundingseconds=0;
3432 }
3433 } else if (!strcasecmp(param, "announce-holdtime")) {
3434 if (!strcasecmp(val, "once")) {
3436 } else if (ast_true(val)) {
3438 } else {
3439 q->announceholdtime = 0;
3440 }
3441 } else if (!strcasecmp(param, "announce-position")) {
3442 if (!strcasecmp(val, "limit")) {
3444 } else if (!strcasecmp(val, "more")) {
3446 } else if (ast_true(val)) {
3448 } else {
3450 }
3451 } else if (!strcasecmp(param, "announce-position-only-up")) {
3453 } else if (!strcasecmp(param, "announce-position-limit")) {
3454 q->announcepositionlimit = atoi(val);
3455 } else if (!strcasecmp(param, "periodic-announce")) {
3456 if (strchr(val, ',')) {
3457 char *s, *buf = ast_strdupa(val);
3458 unsigned int i = 0;
3459
3460 while ((s = strsep(&buf, ",|"))) {
3461 if (!q->sound_periodicannounce[i]) {
3463 }
3464 ast_str_set(&q->sound_periodicannounce[i], 0, "%s", s);
3465 i++;
3466 if (i == MAX_PERIODIC_ANNOUNCEMENTS) {
3467 break;
3468 }
3469 }
3470 q->numperiodicannounce = i;
3471 } else {
3472 ast_str_set(&q->sound_periodicannounce[0], 0, "%s", val);
3473 q->numperiodicannounce = 1;
3474 }
3475 } else if (!strcasecmp(param, "periodic-announce-startdelay")) {
3477 } else if (!strcasecmp(param, "periodic-announce-frequency")) {
3478 q->periodicannouncefrequency = atoi(val);
3479 } else if (!strcasecmp(param, "relative-periodic-announce")) {
3481 } else if (!strcasecmp(param, "random-periodic-announce")) {
3483 } else if (!strcasecmp(param, "retry")) {
3484 q->retry = atoi(val);
3485 if (q->retry <= 0) {
3486 q->retry = DEFAULT_RETRY;
3487 }
3488 } else if (!strcasecmp(param, "wrapuptime")) {
3489 q->wrapuptime = atoi(val);
3490 } else if (!strcasecmp(param, "penaltymemberslimit")) {
3491 if ((sscanf(val, "%10d", &q->penaltymemberslimit) != 1)) {
3492 q->penaltymemberslimit = 0;
3493 }
3494 } else if (!strcasecmp(param, "autofill")) {
3495 q->autofill = ast_true(val);
3496 } else if (!strcasecmp(param, "autopause")) {
3498 } else if (!strcasecmp(param, "autopausedelay")) {
3499 q->autopausedelay = atoi(val);
3500 } else if (!strcasecmp(param, "autopausebusy")) {
3502 } else if (!strcasecmp(param, "autopauseunavail")) {
3504 } else if (!strcasecmp(param, "maxlen")) {
3505 q->maxlen = atoi(val);
3506 if (q->maxlen < 0) {
3507 q->maxlen = 0;
3508 }
3509 } else if (!strcasecmp(param, "servicelevel")) {
3510 q->servicelevel= atoi(val);
3511 } else if (!strcasecmp(param, "strategy")) {
3512 int strategy;
3513
3514 /* We are a static queue and already have set this, no need to do it again */
3515 if (failunknown) {
3516 return;
3517 }
3519 if (strategy < 0) {
3520 ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n",
3521 val, q->name);
3523 }
3524 if (strategy == q->strategy) {
3525 return;
3526 }
3528 ast_log(LOG_WARNING, "Changing to the linear strategy currently requires asterisk to be restarted.\n");
3529 return;
3530 }
3531 q->strategy = strategy;
3532 } else if (!strcasecmp(param, "joinempty")) {
3534 } else if (!strcasecmp(param, "leavewhenempty")) {
3536 } else if (!strcasecmp(param, "reportholdtime")) {
3538 } else if (!strcasecmp(param, "memberdelay")) {
3539 q->memberdelay = atoi(val);
3540 } else if (!strcasecmp(param, "weight")) {
3541 q->weight = atoi(val);
3542 } else if (!strcasecmp(param, "timeoutrestart")) {
3544 } else if (!strcasecmp(param, "defaultrule")) {
3545 ast_string_field_set(q, defaultrule, val);
3546 } else if (!strcasecmp(param, "timeoutpriority")) {
3547 if (!strcasecmp(val, "conf")) {
3549 } else {
3551 }
3552 } else if (!strcasecmp(param, "log-restricted-caller-id")) {
3554 } else if (failunknown) {
3555 if (linenum >= 0) {
3556 ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s at line %d of queues.conf\n",
3557 q->name, param, linenum);
3558 } else {
3559 ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s\n", q->name, param);
3560 }
3561 }
3562}
#define ANNOUNCEPOSITION_MORE_THAN
Definition: app_queue.c:1817
static void parse_empty_options(const char *value, enum empty_conditions *empty, int joinempty)
Definition: app_queue.c:3318
#define ANNOUNCEPOSITION_NO
Definition: app_queue.c:1816
#define ANNOUNCEHOLDTIME_ALWAYS
Definition: app_queue.c:1800
#define ANNOUNCEPOSITION_LIMIT
Definition: app_queue.c:1818
#define ANNOUNCEHOLDTIME_ONCE
Definition: app_queue.c:1801
static int autopause2int(const char *autopause)
Definition: app_queue.c:1977
Definition: ast_expr2.c:325

References call_queue::announce_to_first_user, call_queue::announcefrequency, call_queue::announceholdtime, ANNOUNCEHOLDTIME_ALWAYS, ANNOUNCEHOLDTIME_ONCE, call_queue::announceposition, ANNOUNCEPOSITION_LIMIT, ANNOUNCEPOSITION_MORE_THAN, ANNOUNCEPOSITION_NO, call_queue::announceposition_only_up, 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(), call_queue::autopausebusy, call_queue::autopausedelay, call_queue::autopauseunavail, buf, voicemailpwcheck::context, DEFAULT_RETRY, DEFAULT_TIMEOUT, call_queue::joinempty, call_queue::leavewhenempty, call_queue::log_restricted_caller_id, LOG_WARNING, MAX_PERIODIC_ANNOUNCEMENTS, call_queue::maxlen, call_queue::memberdelay, call_queue::minannouncefrequency, call_queue::monfmt, call_queue::name, call_queue::numperiodicannounce, parse_empty_options(), call_queue::penaltymemberslimit, call_queue::periodicannouncefrequency, call_queue::periodicannouncestartdelay, 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 find_queue_by_name_rt(), and reload_single_queue().

◆ queue_show()

static char * queue_show ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
)
static

Definition at line 10417 of file app_queue.c.

10418{
10419 switch ( cmd ) {
10420 case CLI_INIT:
10421 e->command = "queue show";
10422 e->usage =
10423 "Usage: queue show\n"
10424 " Provides summary information on a specified queue.\n";
10425 return NULL;
10426 case CLI_GENERATE:
10427 return complete_queue_show(a->line, a->word, a->pos, a->n);
10428 }
10429
10430 return __queues_show(NULL, a->fd, a->argc, a->argv);
10431}
static char * complete_queue_show(const char *line, const char *word, int pos, int state)
Definition: app_queue.c:10409
static char * __queues_show(struct mansession *s, int fd, int argc, const char *const *argv)
Show queue(s) status and statistics.
Definition: app_queue.c:10201

References __queues_show(), a, CLI_GENERATE, CLI_INIT, ast_cli_entry::command, complete_queue_show(), NULL, and ast_cli_entry::usage.

◆ queue_stasis_data_alloc()

static struct queue_stasis_data * queue_stasis_data_alloc ( struct queue_ent qe,
struct ast_channel peer,
struct member mem,
time_t  holdstart,
time_t  starttime,
int  callcompletedinsl 
)
static

Definition at line 6320 of file app_queue.c.

6323{
6324 struct queue_stasis_data *queue_data;
6325
6326 queue_data = ao2_alloc(sizeof(*queue_data), queue_stasis_data_destructor);
6327 if (!queue_data) {
6328 return NULL;
6329 }
6330
6331 if (ast_string_field_init(queue_data, 64)) {
6332 ao2_cleanup(queue_data);
6333 return NULL;
6334 }
6335
6338 queue_data->queue = queue_ref(qe->parent);
6339 queue_data->starttime = starttime;
6340 queue_data->holdstart = holdstart;
6342 queue_data->caller_pos = qe->opos;
6343 ao2_ref(mem, +1);
6344 queue_data->member = mem;
6345
6346 return queue_data;
6347}
static void queue_stasis_data_destructor(void *obj)
Definition: app_queue.c:6288

References ao2_alloc, ao2_cleanup, ao2_ref, ast_channel_uniqueid(), ast_string_field_init, ast_string_field_set, queue_stasis_data::callcompletedinsl, queue_stasis_data::caller_pos, queue_stasis_data::caller_uniqueid, queue_ent::chan, queue_stasis_data::holdstart, queue_stasis_data::member, queue_stasis_data::member_uniqueid, NULL, queue_ent::opos, queue_ent::parent, queue_stasis_data::queue, queue_ref, queue_stasis_data_destructor(), and queue_stasis_data::starttime.

Referenced by setup_stasis_subs().

◆ queue_stasis_data_destructor()

static void queue_stasis_data_destructor ( void *  obj)
static

Definition at line 6288 of file app_queue.c.

6289{
6290 struct queue_stasis_data *queue_data = obj;
6291
6292 /* This can only happen if refcounts for this object have got severely messed up */
6293 ast_assert(queue_data->bridge_router == NULL);
6294 ast_assert(queue_data->channel_router == NULL);
6295
6296 ao2_cleanup(queue_data->member);
6297 queue_unref(queue_data->queue);
6298 ast_string_field_free_memory(queue_data);
6299}
struct stasis_message_router * channel_router
Definition: app_queue.c:6277
struct stasis_message_router * bridge_router
Definition: app_queue.c:6275

References ao2_cleanup, ast_assert, ast_string_field_free_memory, queue_stasis_data::bridge_router, queue_stasis_data::channel_router, queue_stasis_data::member, NULL, queue_stasis_data::queue, and queue_unref.

Referenced by queue_stasis_data_alloc().

◆ qupd_exec()

static int qupd_exec ( struct ast_channel chan,
const char *  data 
)
static

Update Queue with data of an outgoing call.

Definition at line 11662 of file app_queue.c.

11663{
11664 int oldtalktime;
11665 char *parse;
11666 struct call_queue *q;
11667 struct member *mem;
11668 int newtalktime = 0;
11669
11671 AST_APP_ARG(queuename);
11672 AST_APP_ARG(uniqueid);
11673 AST_APP_ARG(agent);
11675 AST_APP_ARG(talktime);
11676 AST_APP_ARG(params););
11677
11678 if (ast_strlen_zero(data)) {
11679 ast_log(LOG_WARNING, "QueueUpdate requires arguments (queuename,uniqueid,agent,status,talktime,params[totaltime,callednumber])\n");
11680 return -1;
11681 }
11682
11683 parse = ast_strdupa(data);
11684
11686
11687 if (ast_strlen_zero(args.queuename) || ast_strlen_zero(args.uniqueid) || ast_strlen_zero(args.agent) || ast_strlen_zero(args.status)) {
11688 ast_log(LOG_WARNING, "Missing argument to QueueUpdate (queuename,uniqueid,agent,status,talktime,params[totaltime|callednumber])\n");
11689 return -1;
11690 }
11691
11692 if (!ast_strlen_zero(args.talktime)) {
11693 newtalktime = atoi(args.talktime);
11694 }
11695
11696 q = find_load_queue_rt_friendly(args.queuename);
11697 if (!q) {
11698 ast_log(LOG_WARNING, "QueueUpdate could not find requested queue '%s'\n", args.queuename);
11699 return 0;
11700 }
11701
11702 ao2_lock(q);
11703 if (q->members) {
11704 struct ao2_iterator mem_iter = ao2_iterator_init(q->members, 0);
11705 while ((mem = ao2_iterator_next(&mem_iter))) {
11706 if (!strcasecmp(mem->membername, args.agent)) {
11707 if (!strcasecmp(args.status, "ANSWER")) {
11708 oldtalktime = q->talktime;
11709 q->talktime = (((oldtalktime << 2) - oldtalktime) + newtalktime) >> 2;
11710 time(&mem->lastcall);
11711 mem->calls++;
11712 mem->lastqueue = q;
11713 q->callscompleted++;
11714
11715 if (newtalktime <= q->servicelevel) {
11716 q->callscompletedinsl++;
11717 }
11718 } else {
11719
11720 time(&mem->lastcall);
11721 q->callsabandoned++;
11722 }
11723
11724 ast_queue_log(args.queuename, args.uniqueid, args.agent, "OUTCALL", "%s|%s|%s", args.status, args.talktime, args.params);
11725 }
11726
11727 ao2_ref(mem, -1);
11728 }
11729
11730 ao2_iterator_destroy(&mem_iter);
11731 }
11732
11733 ao2_unlock(q);
11734 queue_t_unref(q, "Done with temporary pointer");
11735
11736 return 0;
11737}

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_lock, ao2_ref, ao2_unlock, args, AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_log, ast_queue_log(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), member::calls, call_queue::callsabandoned, call_queue::callscompleted, call_queue::callscompletedinsl, find_load_queue_rt_friendly(), member::lastcall, member::lastqueue, LOG_WARNING, member::membername, call_queue::members, queue_t_unref, status, and call_queue::talktime.

Referenced by load_module().

◆ recalc_holdtime()

static void recalc_holdtime ( struct queue_ent qe,
int  newholdtime 
)
static

Definition at line 4378 of file app_queue.c.

4379{
4380 int oldvalue;
4381
4382 /* Calculate holdtime using an exponential average */
4383 /* Thanks to SRT for this contribution */
4384 /* 2^2 (4) is the filter coefficient; a higher exponent would give old entries more weight */
4385
4386 ao2_lock(qe->parent);
4387 if ((qe->parent->callscompleted + qe->parent->callsabandoned) == 0) {
4388 qe->parent->holdtime = newholdtime;
4389 } else {
4390 oldvalue = qe->parent->holdtime;
4391 qe->parent->holdtime = (((oldvalue << 2) - oldvalue) + newholdtime) >> 2;
4392 }
4393 ao2_unlock(qe->parent);
4394}

References ao2_lock, ao2_unlock, call_queue::callsabandoned, call_queue::callscompleted, call_queue::holdtime, and queue_ent::parent.

Referenced by try_calling().

◆ record_abandoned()

static void record_abandoned ( struct queue_ent qe)
static

Record that a caller gave up on waiting in queue.

Definition at line 5108 of file app_queue.c.

5109{
5110 int callabandonedinsl = 0;
5111 time_t now;
5112
5113 RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
5114
5115 pbx_builtin_setvar_helper(qe->chan, "ABANDONED", "TRUE");
5116
5118 ao2_lock(qe->parent);
5119 blob = ast_json_pack("{s: s, s: i, s: i, s: i}",
5120 "Queue", qe->parent->name,
5121 "Position", qe->pos,
5122 "OriginalPosition", qe->opos,
5123 "HoldTime", (int)(time(NULL) - qe->start));
5124
5125
5126 time(&now);
5127 callabandonedinsl = ((now - qe->start) <= qe->parent->servicelevel);
5128 if (callabandonedinsl) {
5130 }
5131
5132 qe->parent->callsabandoned++;
5133 ao2_unlock(qe->parent);
5134
5135 ast_channel_publish_cached_blob(qe->chan, queue_caller_abandon_type(), blob);
5136}

References ao2_lock, ao2_unlock, ast_channel_publish_cached_blob(), ast_json_pack(), ast_json_unref(), call_queue::callsabandoned, call_queue::callsabandonedinsl, queue_ent::chan, call_queue::name, NULL, queue_ent::opos, queue_ent::parent, pbx_builtin_setvar_helper(), queue_ent::pos, RAII_VAR, call_queue::servicelevel, set_queue_variables(), and queue_ent::start.

Referenced by queue_exec(), try_calling(), and wait_our_turn().

◆ reload()

static int reload ( void  )
static

Definition at line 11986 of file app_queue.c.

11987{
11988 struct ast_flags mask = {AST_FLAGS_ALL & ~QUEUE_RESET_STATS,};
11989 ast_unload_realtime("queue_members");
11990 reload_handler(1, &mask, NULL);
11991 return 0;
11992}
int ast_unload_realtime(const char *family)
Release any resources cached for a realtime family.
Definition: main/config.c:3591

References AST_FLAGS_ALL, ast_unload_realtime(), NULL, and reload_handler().

Referenced by reload_handler(), reload_queue_rules(), and reload_queues().

◆ reload_handler()

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.

Parameters
reloadTrue if we are reloading information, false if we are loading information for the first time.
maskA bitmask which tells the handler what actions to take
queuenameThe name of the queue on which we wish to take action
Return values
0All reloads were successful
non-zeroThere was a failure

Definition at line 10066 of file app_queue.c.

10067{
10068 int res = 0;
10069
10070 if (ast_test_flag(mask, QUEUE_RELOAD_RULES)) {
10071 res |= reload_queue_rules(reload);
10072 }
10073 if (ast_test_flag(mask, QUEUE_RESET_STATS)) {
10074 res |= clear_stats(queuename);
10075 }
10077 res |= reload_queues(reload, mask, queuename);
10078 }
10079 return res;
10080}
static int reload_queues(int reload, struct ast_flags *mask, const char *queuename)
reload the queues.conf file
Definition: app_queue.c:9979
static int reload_queue_rules(int reload)
Reload the rules defined in queuerules.conf.
Definition: app_queue.c:9553
static int clear_stats(const char *queuename)
Facilitates resetting statistics for a queue.
Definition: app_queue.c:10036
static int reload(void)
Definition: app_queue.c:11986

References ast_test_flag, clear_stats(), QUEUE_RELOAD_MEMBER, QUEUE_RELOAD_PARAMETERS, QUEUE_RELOAD_RULES, QUEUE_RESET_STATS, reload(), reload_queue_rules(), and reload_queues().

Referenced by handle_queue_reload(), handle_queue_reset(), load_module(), manager_queue_reload(), manager_queue_reset(), and reload().

◆ reload_queue_members()

static void reload_queue_members ( void  )
static

Reload dynamic queue members persisted into the astdb.

Definition at line 8129 of file app_queue.c.

8130{
8131 char *cur_ptr;
8132 const char *queue_name;
8133 char *member;
8134 char *interface;
8135 char *membername = NULL;
8136 char *state_interface;
8137 char *penalty_tok;
8138 int penalty = 0;
8139 char *paused_tok;
8140 int paused = 0;
8141 char *wrapuptime_tok;
8142 int wrapuptime = 0;
8143 char *reason_paused;
8144 struct ast_db_entry *db_tree;
8145 struct ast_db_entry *entry;
8146 struct call_queue *cur_queue;
8147 char *queue_data;
8148
8149 /* Each key in 'pm_family' is the name of a queue */
8150 db_tree = ast_db_gettree(pm_family, NULL);
8151 for (entry = db_tree; entry; entry = entry->next) {
8152
8153 queue_name = entry->key + strlen(pm_family) + 2;
8154
8155 {
8156 struct call_queue tmpq = {
8157 .name = queue_name,
8158 };
8159 cur_queue = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Reload queue members");
8160 }
8161
8162 if (!cur_queue) {
8163 cur_queue = find_load_queue_rt_friendly(queue_name);
8164 }
8165
8166 if (!cur_queue) {
8167 /* If the queue no longer exists, remove it from the
8168 * database */
8169 ast_log(LOG_WARNING, "Error loading persistent queue: '%s': it does not exist\n", queue_name);
8170 ast_db_del(pm_family, queue_name);
8171 continue;
8172 }
8173
8174 if (ast_db_get_allocated(pm_family, queue_name, &queue_data)) {
8175 queue_t_unref(cur_queue, "Expire reload reference");
8176 continue;
8177 }
8178
8179 cur_ptr = queue_data;
8180 while ((member = strsep(&cur_ptr, ",|"))) {
8181 if (ast_strlen_zero(member)) {
8182 continue;
8183 }
8184
8185 interface = strsep(&member, ";");
8186 penalty_tok = strsep(&member, ";");
8187 paused_tok = strsep(&member, ";");
8188 membername = strsep(&member, ";");
8189 state_interface = strsep(&member, ";");
8190 reason_paused = strsep(&member, ";");
8191 wrapuptime_tok = strsep(&member, ";");
8192
8193 if (!penalty_tok) {
8194 ast_log(LOG_WARNING, "Error parsing persistent member string for '%s' (penalty)\n", queue_name);
8195 break;
8196 }
8197 penalty = strtol(penalty_tok, NULL, 10);
8198 if (errno == ERANGE) {
8199 ast_log(LOG_WARNING, "Error converting penalty: %s: Out of range.\n", penalty_tok);
8200 break;
8201 }
8202
8203 if (!paused_tok) {
8204 ast_log(LOG_WARNING, "Error parsing persistent member string for '%s' (paused)\n", queue_name);
8205 break;
8206 }
8207 paused = strtol(paused_tok, NULL, 10);
8208 if ((errno == ERANGE) || paused < 0 || paused > 1) {
8209 ast_log(LOG_WARNING, "Error converting paused: %s: Expected 0 or 1.\n", paused_tok);
8210 break;
8211 }
8212
8213 if (!ast_strlen_zero(wrapuptime_tok)) {
8214 wrapuptime = strtol(wrapuptime_tok, NULL, 10);
8215 if (errno == ERANGE) {
8216 ast_log(LOG_WARNING, "Error converting wrapuptime: %s: Out of range.\n", wrapuptime_tok);
8217 break;
8218 }
8219 }
8220
8221 ast_debug(1, "Reload Members: Queue: %s Member: %s Name: %s Penalty: %d Paused: %d ReasonPause: %s Wrapuptime: %d\n",
8222 queue_name, interface, membername, penalty, paused, reason_paused, wrapuptime);
8223
8224 if (add_to_queue(queue_name, interface, membername, penalty, paused, 0, state_interface, reason_paused, wrapuptime) == RES_OUTOFMEMORY) {
8225 ast_log(LOG_ERROR, "Out of Memory when reloading persistent queue member\n");
8226 break;
8227 }
8228 }
8229 queue_t_unref(cur_queue, "Expire reload reference");
8230 ast_free(queue_data);
8231 }
8232
8233 if (db_tree) {
8234 ast_log(LOG_NOTICE, "Queue members successfully reloaded from database.\n");
8235 ast_db_freetree(db_tree);
8236 }
8237}
int ast_db_get_allocated(const char *family, const char *key, char **out)
Get key value specified by family/key as a heap allocated string.
Definition: main/db.c:437
struct ast_db_entry * ast_db_gettree(const char *family, const char *keytree)
Get a list of values within the astdb tree.
Definition: main/db.c:641
void ast_db_freetree(struct ast_db_entry *entry)
Free structure created by ast_db_gettree()
Definition: main/db.c:701
int errno
Definition: astdb.h:31
Definition: search.h:40
char * key
Definition: search.h:41

References add_to_queue(), ao2_t_find, ast_db_del(), ast_db_freetree(), ast_db_get_allocated(), ast_db_gettree(), ast_debug, ast_free, ast_log, ast_strlen_zero(), errno, find_load_queue_rt_friendly(), member::interface, entry::key, LOG_ERROR, LOG_NOTICE, LOG_WARNING, member::membername, call_queue::name, NULL, OBJ_POINTER, member::paused, member::penalty, pm_family, queue_t_unref, queues, member::reason_paused, RES_OUTOFMEMORY, member::state_interface, strsep(), and member::wrapuptime.

Referenced by load_module().

◆ reload_queue_rules()

static int reload_queue_rules ( int  reload)
static

Reload the rules defined in queuerules.conf.

Parameters
reloadIf 1, then only process queuerules.conf if the file has changed since the last time we inspected it.
Returns
Always returns AST_MODULE_LOAD_SUCCESS

Definition at line 9553 of file app_queue.c.

9554{
9555 struct ast_config *cfg;
9556 struct rule_list *rl_iter, *new_rl;
9557 struct penalty_rule *pr_iter;
9558 char *rulecat = NULL;
9559 struct ast_variable *rulevar = NULL;
9560 struct ast_flags config_flags = { (reload && !realtime_rules) ? CONFIG_FLAG_FILEUNCHANGED : 0 };
9561
9562 if (!(cfg = ast_config_load("queuerules.conf", config_flags))) {
9563 ast_log(LOG_NOTICE, "No queuerules.conf file found, queues will not follow penalty rules\n");
9565 } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
9566 ast_log(LOG_NOTICE, "queuerules.conf has not changed since it was last loaded. Not taking any action.\n");
9568 } else if (cfg == CONFIG_STATUS_FILEINVALID) {
9569 ast_log(LOG_ERROR, "Config file queuerules.conf is in an invalid format. Aborting.\n");
9571 }
9572
9574 while ((rl_iter = AST_LIST_REMOVE_HEAD(&rule_lists, list))) {
9575 while ((pr_iter = AST_LIST_REMOVE_HEAD(&rl_iter->rules, list)))
9576 ast_free(pr_iter);
9577 ast_free(rl_iter);
9578 }
9580 while ((rulecat = ast_category_browse(cfg, rulecat))) {
9581 if (!strcasecmp(rulecat, "general")) {
9583 continue;
9584 }
9585 if (!(new_rl = ast_calloc(1, sizeof(*new_rl)))) {
9587 ast_config_destroy(cfg);
9589 } else {
9590 ast_copy_string(new_rl->name, rulecat, sizeof(new_rl->name));
9591 AST_LIST_INSERT_TAIL(&rule_lists, new_rl, list);
9592 for (rulevar = ast_variable_browse(cfg, rulecat); rulevar; rulevar = rulevar->next)
9593 if(!strcasecmp(rulevar->name, "penaltychange"))
9594 insert_penaltychange(new_rl->name, rulevar->value, rulevar->lineno);
9595 else
9596 ast_log(LOG_WARNING, "Don't know how to handle rule type '%s' on line %d\n", rulevar->name, rulevar->lineno);
9597 }
9598 }
9599
9600 ast_config_destroy(cfg);
9601
9605 }
9606
9609}
static int load_realtime_rules(void)
Load queue rules from realtime.
Definition: app_queue.c:3216
static void queue_rules_reset_global_params(void)
Definition: app_queue.c:9533
static int insert_penaltychange(const char *list_name, const char *content, const int linenum)
Change queue penalty by adding rule.
Definition: app_queue.c:3112
static void queue_rules_set_global_params(struct ast_config *cfg)
Definition: app_queue.c:9539
#define ast_config_load(filename, flags)
Load a config file.
#define CONFIG_STATUS_FILEUNCHANGED
#define CONFIG_STATUS_FILEINVALID
struct ast_variable * ast_variable_browse(const struct ast_config *config, const char *category_name)
Definition: extconf.c:1215
@ CONFIG_FLAG_FILEUNCHANGED

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_DECLINE, AST_MODULE_LOAD_SUCCESS, ast_variable_browse(), CONFIG_FLAG_FILEUNCHANGED, CONFIG_STATUS_FILEINVALID, CONFIG_STATUS_FILEUNCHANGED, insert_penaltychange(), ast_variable::lineno, load_realtime_rules(), LOG_ERROR, LOG_NOTICE, LOG_WARNING, rule_list::name, ast_variable::name, ast_variable::next, NULL, queue_rules_reset_global_params(), queue_rules_set_global_params(), realtime_rules, reload(), rule_list::rules, and ast_variable::value.

Referenced by reload_handler().

◆ reload_queues()

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.

Parameters
reload0 if we are calling this the first time, 1 every other time
maskGives flags telling us what information to actually reload
queuenameIf set to a non-zero string, then only reload information from that particular queue. Otherwise inspect all queues
Return values
-1Failure occurred
0All clear!

Definition at line 9979 of file app_queue.c.

9980{
9981 struct ast_config *cfg;
9982 char *cat;
9983 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
9984 const int queue_reload = ast_test_flag(mask, QUEUE_RELOAD_PARAMETERS);
9985
9986 if (!(cfg = ast_config_load("queues.conf", config_flags))) {
9987 ast_log(LOG_NOTICE, "No call queueing config file (queues.conf), so no call queues\n");
9988 return -1;
9989 } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
9990 return 0;
9991 } else if (cfg == CONFIG_STATUS_FILEINVALID) {
9992 ast_log(LOG_ERROR, "Config file queues.conf is in an invalid format. Aborting.\n");
9993 return -1;
9994 }
9995
9996 /* We've made it here, so it looks like we're doing operations on all queues. */
9998
9999 /* Mark non-realtime queues not found at the beginning. */
10000 ao2_callback(queues, OBJ_NODATA, mark_unfound, (char *) queuename);
10001
10002 /* Chug through config file. */
10003 cat = NULL;
10005 while ((cat = ast_category_browse(cfg, cat)) ) {
10006 if (!strcasecmp(cat, "general") && queue_reload) {
10008 continue;
10009 }
10010 if (ast_strlen_zero(queuename) || !strcasecmp(cat, queuename))
10011 reload_single_queue(cfg, mask, cat);
10012 }
10013
10014 ast_config_destroy(cfg);
10015 if (queue_reload) {
10016 /* Unlink and mark dead all non-realtime queues that were not found in the configuration file. */
10018 }
10020 return 0;
10021}
static void queue_reset_global_params(void)
Definition: app_queue.c:9612
static void reload_single_queue(struct ast_config *cfg, struct ast_flags *mask, const char *queuename)
Reload information pertaining to a particular queue.
Definition: app_queue.c:9822
static void queue_set_global_params(struct ast_config *cfg)
Definition: app_queue.c:9624
static int mark_unfound(void *obj, void *arg, int flags)
Definition: app_queue.c:9945
static int kill_if_unfound(void *obj, void *arg, int flags)
Definition: app_queue.c:9955

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_STATUS_FILEINVALID, CONFIG_STATUS_FILEUNCHANGED, kill_if_unfound(), LOG_ERROR, LOG_NOTICE, mark_unfound(), NULL, OBJ_MULTIPLE, OBJ_NODATA, OBJ_NOLOCK, OBJ_UNLINK, QUEUE_RELOAD_PARAMETERS, queue_reset_global_params(), queue_set_global_params(), queues, reload(), and reload_single_queue().

Referenced by reload_handler().

◆ reload_single_member()

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.

Parameters
memberdataThe part after member = in the config file
qThe queue to which this member belongs

Definition at line 9659 of file app_queue.c.

9660{
9661 char *membername, *interface, *state_interface, *tmp;
9662 char *parse;
9663 struct member *cur, *newm;
9664 struct member tmpmem;
9665 int penalty;
9666 int ringinuse;
9667 int wrapuptime;
9668 int paused;
9677 );
9678
9679 if (ast_strlen_zero(memberdata)) {
9680 ast_log(LOG_WARNING, "Empty queue member definition. Moving on!\n");
9681 return;
9682 }
9683
9684 /* Add a new member */
9685 parse = ast_strdupa(memberdata);
9686
9688
9689 interface = args.interface;
9690 if (!ast_strlen_zero(args.penalty)) {
9691 tmp = args.penalty;
9692 ast_strip(tmp);
9693 penalty = atoi(tmp);
9694 if (penalty < 0) {
9695 penalty = 0;
9696 }
9697 } else {
9698 penalty = 0;
9699 }
9700
9701 if (!ast_strlen_zero(args.membername)) {
9702 membername = args.membername;
9703 ast_strip(membername);
9704 } else {
9705 membername = interface;
9706 }
9707
9708 if (!ast_strlen_zero(args.state_interface)) {
9709 state_interface = args.state_interface;
9710 ast_strip(state_interface);
9711 } else {
9712 state_interface = interface;
9713 }
9714
9715 if (!ast_strlen_zero(args.ringinuse)) {
9716 tmp = args.ringinuse;
9717 ast_strip(tmp);
9718 if (ast_true(tmp)) {
9719 ringinuse = 1;
9720 } else if (ast_false(tmp)) {
9721 ringinuse = 0;
9722 } else {
9723 ast_log(LOG_ERROR, "Member %s has an invalid ringinuse value. Using %s ringinuse value.\n",
9724 membername, q->name);
9725 ringinuse = q->ringinuse;
9726 }
9727 } else {
9728 ringinuse = q->ringinuse;
9729 }
9730
9731 if (!ast_strlen_zero(args.wrapuptime)) {
9732 tmp = args.wrapuptime;
9733 ast_strip(tmp);
9734 wrapuptime = atoi(tmp);
9735 if (wrapuptime < 0) {
9736 wrapuptime = 0;
9737 }
9738 } else {
9739 wrapuptime = 0;
9740 }
9741
9742 if (!ast_strlen_zero(args.paused)) {
9743 tmp = args.paused;
9744 ast_strip(tmp);
9745 if (ast_true(tmp)) {
9746 paused = 1;
9747 } else if (ast_false(tmp)) {
9748 paused = 0;
9749 } else {
9750 ast_log(LOG_ERROR, "Member %s has an invalid paused value.\n", membername);
9751 paused = 0;
9752 }
9753 } else {
9754 paused = 0;
9755 }
9756
9757 /* Find the old position in the list */
9758 ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface));
9759 cur = ao2_find(q->members, &tmpmem, OBJ_POINTER);
9760
9761 if (cur) {
9762 paused = cur->paused;
9763 }
9764
9765 if ((newm = create_queue_member(interface, membername, penalty, paused, state_interface, ringinuse, wrapuptime))) {
9766 newm->wrapuptime = wrapuptime;
9767 if (cur) {
9768 ao2_lock(q->members);
9769 /* Round Robin Queue Position must be copied if this is replacing an existing member */
9770 newm->queuepos = cur->queuepos;
9771 /* Don't reset agent stats either */
9772 newm->calls = cur->calls;
9773 newm->lastcall = cur->lastcall;
9774
9775 ao2_link(q->members, newm);
9776 ao2_unlink(q->members, cur);
9777 ao2_unlock(q->members);
9778 } else {
9779 /* Otherwise we need to add using the function that will apply a round robin queue position manually. */
9780 member_add_to_queue(q, newm);
9781 }
9782 ao2_ref(newm, -1);
9783 }
9784 newm = NULL;
9785
9786 if (cur) {
9787 ao2_ref(cur, -1);
9788 }
9789}

References ao2_find, ao2_link, ao2_lock, ao2_ref, ao2_unlink, ao2_unlock, args, AST_APP_ARG, ast_copy_string(), AST_DECLARE_APP_ARGS, ast_false(), ast_log, AST_STANDARD_APP_ARGS, ast_strdupa, ast_strip(), ast_strlen_zero(), ast_true(), member::calls, create_queue_member(), member::interface, member::lastcall, LOG_ERROR, LOG_WARNING, member_add_to_queue(), member::membername, call_queue::members, call_queue::name, NULL, OBJ_POINTER, member::paused, member::penalty, member::queuepos, member::ringinuse, call_queue::ringinuse, member::state_interface, tmp(), and member::wrapuptime.

Referenced by reload_single_queue().

◆ reload_single_queue()

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

Parameters
cfgThe configuration which we are reading
maskTells us what information we need to reload
queuenameThe name of the queue we are reloading information from

Definition at line 9822 of file app_queue.c.

9823{
9824 int new;
9825 struct call_queue *q = NULL;
9826 struct member *member;
9827 /*We're defining a queue*/
9828 struct call_queue tmpq = {
9829 .name = queuename,
9830 };
9831 const char *tmpvar;
9832 const int queue_reload = ast_test_flag(mask, QUEUE_RELOAD_PARAMETERS);
9833 const int member_reload = ast_test_flag(mask, QUEUE_RELOAD_MEMBER);
9834 int prev_weight = 0;
9835 struct ast_variable *var;
9836 struct ao2_iterator mem_iter;
9837
9838 if (!(q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Find queue for reload"))) {
9839 if (queue_reload) {
9840 /* Make one then */
9841 if (!(q = alloc_queue(queuename))) {
9842 return;
9843 }
9844 } else {
9845 /* Since we're not reloading queues, this means that we found a queue
9846 * in the configuration file which we don't know about yet. Just return.
9847 */
9848 return;
9849 }
9850 new = 1;
9851 } else {
9852 new = 0;
9853 }
9854
9855 if (!new) {
9856 ao2_lock(q);
9857 prev_weight = q->weight ? 1 : 0;
9858 }
9859 /* Check if we already found a queue with this name in the config file */
9860 if (q->found) {
9861 ast_log(LOG_WARNING, "Queue '%s' already defined! Skipping!\n", queuename);
9862 if (!new) {
9863 /* It should be impossible to *not* hit this case*/
9864 ao2_unlock(q);
9865 }
9866 queue_t_unref(q, "We exist! Expiring temporary pointer");
9867 return;
9868 }
9869 /* Due to the fact that the "linear" strategy will have a different allocation
9870 * scheme for queue members, we must devise the queue's strategy before other initializations.
9871 * To be specific, the linear strategy needs to function like a linked list, meaning the ao2
9872 * container used will have only a single bucket instead of the typical number.
9873 */
9874 if (queue_reload) {
9875 if ((tmpvar = ast_variable_retrieve(cfg, queuename, "strategy"))) {
9876 q->strategy = strat2int(tmpvar);
9877 if (q->strategy < 0) {
9878 ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n",
9879 tmpvar, q->name);
9881 }
9882 } else {
9884 }
9885 init_queue(q);
9886 }
9887 if (member_reload) {
9889 q->found = 1;
9890 }
9891
9892 /* On the first pass we just read the parameters of the queue */
9893 for (var = ast_variable_browse(cfg, queuename); var; var = var->next) {
9894 if (queue_reload && strcasecmp(var->name, "member")) {
9895 queue_set_param(q, var->name, var->value, var->lineno, 1);
9896 }
9897 }
9898
9899 /* On the second pass, we read members */
9900 for (var = ast_variable_browse(cfg, queuename); var; var = var->next) {
9901 if (member_reload && !strcasecmp(var->name, "member")) {
9902 reload_single_member(var->value, q);
9903 }
9904 }
9905
9906 /* Update ringinuse for dynamic members */
9907 if (member_reload) {
9908 ao2_lock(q->members);
9910 while ((member = ao2_iterator_next(&mem_iter))) {
9911 if (member->dynamic) {
9913 }
9914 ao2_ref(member, -1);
9915 }
9916 ao2_iterator_destroy(&mem_iter);
9917 ao2_unlock(q->members);
9918 }
9919
9920 /* At this point, we've determined if the queue has a weight, so update use_weight
9921 * as appropriate
9922 */
9923 if (!q->weight && prev_weight) {
9925 } else if (q->weight && !prev_weight) {
9927 }
9928
9929 /* Free remaining members marked as delme */
9930 if (member_reload) {
9931 ao2_lock(q->members);
9934 ao2_unlock(q->members);
9935 }
9936
9937 if (new) {
9938 queues_t_link(queues, q, "Add queue to container");
9939 } else {
9940 ao2_unlock(q);
9941 }
9942 queue_t_unref(q, "Expiring creation reference");
9943}
static int mark_member_dead(void *obj, void *arg, int flags)
Definition: app_queue.c:9791
static void reload_single_member(const char *memberdata, struct call_queue *q)
reload information pertaining to a single member
Definition: app_queue.c:9659
static int kill_dead_members(void *obj, void *arg, int flags)
Definition: app_queue.c:9800
static int queue_delme_members_decrement_followers(void *obj, void *arg, int flag)
Definition: app_queue.c:2053

References alloc_queue(), ao2_callback, ao2_iterator_destroy(), AO2_ITERATOR_DONTLOCK, ao2_iterator_init(), ao2_iterator_next, ao2_lock, ao2_ref, ao2_t_find, ao2_unlock, ast_atomic_fetchadd_int(), ast_log, ast_test_flag, ast_variable_browse(), ast_variable_retrieve(), member::dynamic, call_queue::found, init_queue(), kill_dead_members(), LOG_WARNING, mark_member_dead(), call_queue::members, call_queue::name, NULL, OBJ_MULTIPLE, OBJ_NODATA, OBJ_POINTER, OBJ_UNLINK, queue_delme_members_decrement_followers(), QUEUE_RELOAD_MEMBER, QUEUE_RELOAD_PARAMETERS, queue_set_param(), QUEUE_STRATEGY_RINGALL, queue_t_unref, queues, queues_t_link, reload_single_member(), member::ringinuse, call_queue::ringinuse, strat2int(), call_queue::strategy, use_weight, var, and call_queue::weight.

Referenced by reload_queues().

◆ remove_from_queue()

static int remove_from_queue ( const char *  queuename,
const char *  interface 
)
static

Remove member from queue.

Return values
RES_NOT_DYNAMICwhen they aren't a RT member
RES_NOSUCHQUEUEqueue does not exist
RES_OKAYremoved member from queue
RES_EXISTSqueue exists but no members

Definition at line 7569 of file app_queue.c.

7570{
7571 struct call_queue *q, tmpq = {
7572 .name = queuename,
7573 };
7574 struct member *mem, tmpmem;
7575 int res = RES_NOSUCHQUEUE;
7576
7577 ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface));
7578 if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Temporary reference for interface removal"))) {
7579 ao2_lock(q);
7580 if ((mem = ao2_find(q->members, &tmpmem, OBJ_POINTER))) {
7581 /* XXX future changes should beware of this assumption!! */
7582 /*Change Penalty on realtime users*/
7584 update_realtime_member_field(mem, q->name, "penalty", "-1");
7585 } else if (!mem->dynamic) {
7586 ao2_ref(mem, -1);
7587 ao2_unlock(q);
7588 queue_t_unref(q, "Interface wasn't dynamic, expiring temporary reference");
7589 return RES_NOT_DYNAMIC;
7590 }
7591 queue_publish_member_blob(queue_member_removed_type(), queue_member_blob_create(q, mem));
7592
7594 ao2_ref(mem, -1);
7595
7598 }
7599
7600 if (!num_available_members(q)) {
7602 }
7603
7604 res = RES_OKAY;
7605 } else {
7606 res = RES_EXISTS;
7607 }
7608 ao2_unlock(q);
7609 queue_t_unref(q, "Expiring temporary reference");
7610 }
7611
7612 return res;
7613}
static int update_realtime_member_field(struct member *mem, const char *queue_name, const char *field, const char *value)
Definition: app_queue.c:4013
char rt_uniqueid[80]
Definition: app_queue.c:1779

References ao2_find, ao2_lock, ao2_ref, ao2_t_find, ao2_unlock, ast_copy_string(), AST_DEVICE_INUSE, AST_DEVSTATE_CACHABLE, ast_devstate_changed(), ast_strlen_zero(), dump_queue_members(), member::dynamic, member::interface, member_remove_from_queue(), call_queue::members, call_queue::name, negative_penalty_invalid, num_available_members(), OBJ_POINTER, queue_member_blob_create(), queue_persistent_members, queue_publish_member_blob(), queue_t_unref, queues, member::realtime, RES_EXISTS, RES_NOSUCHQUEUE, RES_NOT_DYNAMIC, RES_OKAY, member::rt_uniqueid, and update_realtime_member_field().

Referenced by handle_queue_remove_member(), manager_remove_queue_member(), and rqm_exec().

◆ remove_stasis_subscriptions()

static void remove_stasis_subscriptions ( struct queue_stasis_data queue_data)
static

Definition at line 6305 of file app_queue.c.

6306{
6307 SCOPED_AO2LOCK(lock, queue_data);
6308
6309 queue_data->dying = 1;
6311 queue_data->bridge_router = NULL;
6313 queue_data->channel_router = NULL;
6314}
void stasis_message_router_unsubscribe(struct stasis_message_router *router)
Unsubscribe the router from the upstream topic.

References queue_stasis_data::bridge_router, queue_stasis_data::channel_router, queue_stasis_data::dying, lock, NULL, SCOPED_AO2LOCK, and stasis_message_router_unsubscribe().

Referenced by handle_attended_transfer(), handle_blind_transfer(), and handle_hangup().

◆ request_withdraw_caller_from_queue()

static int request_withdraw_caller_from_queue ( const char *  queuename,
const char *  caller,
const char *  withdraw_info 
)
static

Request to withdraw a caller from a queue.

Return values
RES_NOSUCHQUEUEqueue does not exist
RES_OKAYwithdraw request sent
RES_NOT_CALLERqueue exists but no caller
RES_EXISTSa withdraw request was already sent for this caller (channel) and queue
Note
Ensure the appropriate realtime queue is loaded. Note that this short-circuits if the queue is already in memory.

Definition at line 7751 of file app_queue.c.

7752{
7753 struct call_queue *q;
7754 struct queue_ent *qe;
7755 int res = RES_NOSUCHQUEUE;
7756
7757 /*! \note Ensure the appropriate realtime queue is loaded. Note that this
7758 * short-circuits if the queue is already in memory. */
7759 if (!(q = find_load_queue_rt_friendly(queuename))) {
7760 return res;
7761 }
7762
7763 ao2_lock(q);
7764 res = RES_NOT_CALLER;
7765 for (qe = q->head; qe; qe = qe->next) {
7766 if (!strcmp(ast_channel_name(qe->chan), caller)) {
7767 if (qe->withdraw) {
7768 ast_debug(1, "Ignoring duplicate withdraw request of caller %s from queue %s\n", caller, queuename);
7769 res = RES_EXISTS;
7770 } else {
7771 ast_debug(1, "Requested withdraw of caller %s from queue %s\n", caller, queuename);
7772 /* It is not possible to change the withdraw info by further withdraw requests for this caller (channel)
7773 in this queue, so we do not need to worry about a memory leak here. */
7774 if (withdraw_info) {
7776 }
7777 qe->withdraw = 1;
7778 res = RES_OKAY;
7779 }
7780 break;
7781 }
7782 }
7783 ao2_unlock(q);
7784 queue_unref(q);
7785
7786 return res;
7787}

References ao2_lock, ao2_unlock, ast_channel_name(), ast_debug, ast_strdup, queue_ent::chan, find_load_queue_rt_friendly(), call_queue::head, queue_ent::next, queue_unref, RES_EXISTS, RES_NOSUCHQUEUE, RES_NOT_CALLER, RES_OKAY, queue_ent::withdraw, and queue_ent::withdraw_info.

Referenced by manager_request_withdraw_caller_from_queue().

◆ ring_entry()

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:

  • Agent on call
  • Agent is paused
  • Wrapup time not expired
  • Priority by another queue
Return values
1on success to reach a free agent
0on failure to get agent.

Definition at line 4782 of file app_queue.c.

4783{
4784 int res;
4785 int status;
4786 char tech[256];
4787 char *location;
4788 struct ast_format_cap *nativeformats;
4789 RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
4790
4791 /* on entry here, we know that tmp->chan == NULL */
4792 if (!can_ring_entry(qe, tmp)) {
4793 tmp->stillgoing = 0;
4794 ++*busies;
4795 return 0;
4796 }
4797
4798 ast_copy_string(tech, tmp->interface, sizeof(tech));
4799 if ((location = strchr(tech, '/'))) {
4800 *location++ = '\0';
4801 } else {
4802 location = "";
4803 }
4804
4806 nativeformats = ao2_bump(ast_channel_nativeformats(qe->chan));
4808
4809 /* Request the peer */
4810 tmp->chan = ast_request(tech, nativeformats, NULL, qe->chan, location, &status);
4811 ao2_cleanup(nativeformats);
4812 if (!tmp->chan) { /* If we can't, just go on to the next call */
4813 ao2_lock(qe->parent);
4814 qe->parent->rrpos++;
4815 qe->linpos++;
4816 ao2_unlock(qe->parent);
4817
4818 pending_members_remove(tmp->member);
4819
4820 publish_dial_end_event(qe->chan, tmp, NULL, "BUSY");
4821 tmp->stillgoing = 0;
4822 ++*busies;
4823 return 0;
4824 }
4825
4826 ast_channel_lock_both(tmp->chan, qe->chan);
4827
4830 if (qe->cancel_answered_elsewhere) {
4832 }
4833 ast_channel_appl_set(tmp->chan, "AppQueue");
4834 ast_channel_data_set(tmp->chan, "(Outgoing Line)");
4835 memset(ast_channel_whentohangup(tmp->chan), 0, sizeof(*ast_channel_whentohangup(tmp->chan)));
4836
4837 /* If the new channel has no callerid, try to guess what it should be */
4838 if (!ast_channel_caller(tmp->chan)->id.number.valid) {
4840 struct ast_party_caller caller;
4841
4843 caller.id = ast_channel_connected(qe->chan)->id;
4844 caller.ani = ast_channel_connected(qe->chan)->ani;
4845 ast_channel_set_caller_event(tmp->chan, &caller, NULL);
4846 } else if (!ast_strlen_zero(ast_channel_dialed(qe->chan)->number.str)) {
4848 } else if (!ast_strlen_zero(ast_channel_exten(qe->chan))) {
4850 }
4851 tmp->dial_callerid_absent = 1;
4852 }
4853
4855
4857
4859
4860 /* Inherit specially named variables from parent channel */
4864
4865 /* Presense of ADSI CPE on outgoing channel follows ours */
4867
4868 /* Inherit context and extension */
4869 ast_channel_dialcontext_set(tmp->chan, ast_channel_context(qe->chan));
4871
4872 /* Save the original channel name to detect call pickup masquerading in. */
4873 tmp->orig_chan_name = ast_strdup(ast_channel_name(tmp->chan));
4874
4875 ast_channel_unlock(tmp->chan);
4877
4878 /* location is tmp->interface where tech/ has been stripped, so it follow the same syntax as DIALEDPEERNUMBER in app_dial.c */
4879 pbx_builtin_setvar_helper(tmp->chan, "DIALEDPEERNUMBER", strlen(location) ? location : tmp->interface);
4880
4881 /* PREDIAL: Run gosub on the callee's channel */
4882 if (qe->predial_callee) {
4883 ast_pre_call(tmp->chan, qe->predial_callee);
4884 }
4885
4886 /* Place the call, but don't wait on the answer */
4887 if ((res = ast_call(tmp->chan, location, 0))) {
4888 /* Again, keep going even if there's an error */
4889 ast_verb(3, "Couldn't call %s\n", tmp->interface);
4890 do_hang(tmp);
4891 ++*busies;
4892 return 0;
4893 }
4894
4895 ast_channel_lock_both(tmp->chan, qe->chan);
4896
4897 blob = ast_json_pack("{s: s, s: s, s: s}",
4898 "Queue", qe->parent->name,
4899 "Interface", tmp->interface,
4900 "MemberName", tmp->member->membername);
4901 queue_publish_multi_channel_blob(qe->chan, tmp->chan, queue_agent_called_type(), blob);
4902
4903 ast_channel_publish_dial(qe->chan, tmp->chan, tmp->interface, NULL);
4904
4905 ast_channel_unlock(tmp->chan);
4907
4908 ast_verb(3, "Called %s\n", tmp->interface);
4909
4910 return 1;
4911}
static void do_hang(struct callattempt *o)
common hangup actions
Definition: app_queue.c:4656
static int can_ring_entry(struct queue_ent *qe, struct callattempt *call)
Definition: app_queue.c:4686
static void queue_publish_multi_channel_blob(struct ast_channel *caller, struct ast_channel *agent, struct stasis_message_type *type, struct ast_json *blob)
Definition: app_queue.c:2369
static void publish_dial_end_event(struct ast_channel *in, struct callattempt *outgoing, struct ast_channel *exception, const char *status)
Definition: app_queue.c:4486
#define ao2_bump(obj)
Bump refcount on an AO2 object by one, returning the object.
Definition: astobj2.h:480
void ast_channel_exten_set(struct ast_channel *chan, const char *value)
void ast_channel_appl_set(struct ast_channel *chan, const char *value)
int ast_call(struct ast_channel *chan, const char *addr, int timeout)
Make a call.
Definition: channel.c:6480
@ AST_CHANNEL_REQUESTOR_BRIDGE_PEER
Definition: channel.h:1523
void ast_channel_set_caller_event(struct ast_channel *chan, const struct ast_party_caller *caller, const struct ast_set_party_caller *update)
Set the caller id information in the Asterisk channel and generate an AMI event if the caller id name...
Definition: channel.c:7394
struct ast_format_cap * ast_channel_nativeformats(const struct ast_channel *chan)
void ast_channel_data_set(struct ast_channel *chan, const char *value)
struct ast_party_redirecting * ast_channel_redirecting(struct ast_channel *chan)
#define ast_channel_lock_both(chan1, chan2)
Lock two channels.
Definition: channel.h:2975
int ast_channel_datastore_inherit(struct ast_channel *from, struct ast_channel *to)
Inherit datastores from a parent to a child.
Definition: channel.c:2387
const char * ast_channel_context(const struct ast_channel *chan)
ast_channel_adsicpe
Definition: channel.h:888
void ast_party_caller_set_init(struct ast_party_caller *init, const struct ast_party_caller *guide)
Initialize the given caller structure using the given guide for a set update operation.
Definition: channel.c:2018
void ast_set_callerid(struct ast_channel *chan, const char *cid_num, const char *cid_name, const char *cid_ani)
Set caller ID number, name and ANI and generate AMI event.
Definition: channel.c:7356
void ast_channel_inherit_variables(const struct ast_channel *parent, struct ast_channel *child)
Inherits channel variable from parent to child channel.
Definition: channel.c:6790
struct ast_party_dialed * ast_channel_dialed(struct ast_channel *chan)
struct timeval * ast_channel_whentohangup(struct ast_channel *chan)
void ast_connected_line_copy_from_caller(struct ast_party_connected_line *dest, const struct ast_party_caller *src)
Copy the caller information to the connected line information.
Definition: channel.c:8315
void ast_channel_req_accountcodes_precious(struct ast_channel *chan, const struct ast_channel *requestor, enum ast_channel_requestor_relationship relationship)
Setup new channel accountcodes from the requestor channel after ast_request().
Definition: channel.c:6458
int ast_pre_call(struct ast_channel *chan, const char *sub_args)
Execute a Gosub call on the channel before a call is placed.
Definition: channel.c:6463
void ast_channel_adsicpe_set(struct ast_channel *chan, enum ast_channel_adsicpe value)
struct ast_channel * ast_request(const char *type, struct ast_format_cap *request_cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *addr, int *cause)
Requests a channel.
Definition: channel.c:6373
const char * ast_channel_exten(const struct ast_channel *chan)
void ast_party_redirecting_copy(struct ast_party_redirecting *dest, const struct ast_party_redirecting *src)
Copy the source redirecting information to the destination redirecting.
Definition: channel.c:2154
int ast_max_forwards_decrement(struct ast_channel *chan)
Decrement the max forwards count for a particular channel.
Definition: max_forwards.c:135
Format capabilities structure, holds formats + preference order + etc.
Definition: format_cap.c:54
Caller Party information.
Definition: channel.h:420
struct ast_party_id ani
Automatic Number Identification (ANI)
Definition: channel.h:467
struct ast_party_dialed::@208 number
Dialed/Called number.
char * str
Subscriber phone number (Malloced)
Definition: channel.h:388
int transit_network_select
Transit Network Select.
Definition: channel.h:399
int cancel_answered_elsewhere
Definition: app_queue.c:1746

References ast_party_caller::ani, ast_party_connected_line::ani, ao2_bump, ao2_cleanup, ao2_lock, ao2_unlock, ast_call(), AST_CAUSE_ANSWERED_ELSEWHERE, ast_channel_adsicpe_set(), ast_channel_appl_set(), ast_channel_caller(), ast_channel_connected(), ast_channel_context(), ast_channel_data_set(), ast_channel_datastore_inherit(), ast_channel_dialed(), ast_channel_exten(), ast_channel_exten_set(), ast_channel_hangupcause_set(), ast_channel_inherit_variables(), ast_channel_lock, ast_channel_lock_both, ast_channel_name(), ast_channel_nativeformats(), ast_channel_publish_dial(), ast_channel_redirecting(), ast_channel_req_accountcodes_precious(), AST_CHANNEL_REQUESTOR_BRIDGE_PEER, ast_channel_set_caller_event(), ast_channel_unlock, ast_channel_whentohangup(), ast_connected_line_copy_from_caller(), ast_copy_string(), ast_json_pack(), ast_json_unref(), ast_max_forwards_decrement(), ast_party_caller_set_init(), ast_party_redirecting_copy(), ast_pre_call(), ast_request(), ast_set_callerid(), ast_strdup, ast_strlen_zero(), ast_verb, can_ring_entry(), queue_ent::cancel_answered_elsewhere, queue_ent::chan, do_hang(), ast_party_caller::id, ast_party_connected_line::id, queue_ent::linpos, call_queue::name, NULL, ast_party_id::number, ast_party_dialed::number, queue_ent::parent, pbx_builtin_setvar_helper(), pending_members_remove(), queue_ent::predial_callee, publish_dial_end_event(), queue_publish_multi_channel_blob(), RAII_VAR, call_queue::rrpos, status, ast_party_dialed::str, tmp(), ast_party_dialed::transit_network_select, and ast_party_number::valid.

Referenced by ring_one().

◆ ring_one()

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

Return values
1if a member was called successfully
0otherwise

Definition at line 4939 of file app_queue.c.

4940{
4941 int ret = 0;
4942 struct callattempt *cur;
4943
4944 if (qe->predial_callee) {
4946 for (cur = outgoing; cur; cur = cur->q_next) {
4947 if (cur->stillgoing && cur->chan) {
4949 }
4950 }
4951 }
4952
4953 while (ret == 0) {
4954 struct callattempt *best = find_best(outgoing);
4955 if (!best) {
4956 ast_debug(1, "Nobody left to try ringing in queue\n");
4957 break;
4958 }
4960 /* Ring everyone who shares this best metric (for ringall) */
4961 for (cur = outgoing; cur; cur = cur->q_next) {
4962 if (cur->stillgoing && !cur->chan && cur->metric <= best->metric) {
4963 ast_debug(1, "(Parallel) Trying '%s' with metric %d\n", cur->interface, cur->metric);
4964 ret |= ring_entry(qe, cur, busies);
4965 if (qe->predial_callee && cur->chan) {
4967 }
4968 }
4969 }
4970 } else {
4971 /* Ring just the best channel */
4972 ast_debug(1, "Trying '%s' with metric %d\n", best->interface, best->metric);
4973 ret = ring_entry(qe, best, busies);
4974 if (qe->predial_callee && best->chan) {
4976 }
4977 }
4978
4979 /* If we have timed out, break out */
4980 if (qe->expire && (time(NULL) >= qe->expire)) {
4981 ast_debug(1, "Queue timed out while ringing members.\n");
4982 ret = 0;
4983 break;
4984 }
4985 }
4986 if (qe->predial_callee) {
4987 for (cur = outgoing; cur; cur = cur->q_next) {
4988 if (cur->stillgoing && cur->chan) {
4990 }
4991 }
4993 }
4994
4995 return ret;
4996}
static int ring_entry(struct queue_ent *qe, struct callattempt *tmp, int *busies)
Part 2 of ring_one.
Definition: app_queue.c:4782
static struct callattempt * find_best(struct callattempt *outgoing)
find the entry with the best metric, or NULL
Definition: app_queue.c:4914
int ast_autoservice_stop(struct ast_channel *chan)
Stop servicing a channel for us...
Definition: autoservice.c:266
int ast_autoservice_start(struct ast_channel *chan)
Automatically service a channel for us...
Definition: autoservice.c:200
char interface[256]
Definition: app_queue.c:1702

References ast_autoservice_start(), ast_autoservice_stop(), ast_debug, callattempt::chan, queue_ent::chan, queue_ent::expire, find_best(), callattempt::interface, callattempt::metric, NULL, queue_ent::parent, queue_ent::predial_callee, callattempt::q_next, QUEUE_STRATEGY_RINGALL, ring_entry(), callattempt::stillgoing, and call_queue::strategy.

Referenced by try_calling(), and wait_for_answer().

◆ rna()

static void rna ( int  rnatime,
struct queue_ent qe,
struct ast_channel peer,
char *  interface,
char *  membername,
int  autopause 
)
static

RNA == Ring No Answer. Common code that is executed when we try a queue member and they don't answer.

Definition at line 5139 of file app_queue.c.

5140{
5141 RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
5142
5143 ast_verb(3, "Nobody picked up in %d ms\n", rnatime);
5144
5145 /* Stop ringing, and resume MOH if specified */
5146 if (qe->ring_when_ringing) {
5147 ast_indicate(qe->chan, -1);
5148 ast_moh_start(qe->chan, qe->moh, NULL);
5149 }
5150
5151 blob = ast_json_pack("{s: s, s: s, s: s, s: i}",
5152 "Queue", qe->parent->name,
5153 "Interface", interface,
5154 "MemberName", membername,
5155 "RingTime", rnatime);
5156 queue_publish_multi_channel_blob(qe->chan, peer, queue_agent_ringnoanswer_type(), blob);
5157
5158 ast_queue_log(qe->parent->name, ast_channel_uniqueid(qe->chan), membername, "RINGNOANSWER", "%d", rnatime);
5160 if (qe->parent->autopausedelay > 0) {
5161 struct member *mem;
5162 ao2_lock(qe->parent);
5163 if ((mem = interface_exists(qe->parent, interface))) {
5164 time_t idletime = time(&idletime)-mem->lastcall;
5165 if ((mem->lastcall != 0) && (qe->parent->autopausedelay > idletime)) {
5166 ao2_unlock(qe->parent);
5167 ao2_ref(mem, -1);
5168 return;
5169 }
5170 ao2_ref(mem, -1);
5171 }
5172 ao2_unlock(qe->parent);
5173 }
5174 if (qe->parent->autopause == QUEUE_AUTOPAUSE_ON) {
5175 if (!set_member_paused(qe->parent->name, interface, "Auto-Pause", 1)) {
5176 ast_verb(3, "Auto-Pausing Queue Member %s in queue %s since they failed to answer.\n",
5177 interface, qe->parent->name);
5178 } else {
5179 ast_verb(3, "Failed to pause Queue Member %s in queue %s!\n", interface, qe->parent->name);
5180 }
5181 } else {
5182 /* If queue autopause is mode all, just don't send any queue to stop.
5183 * the function will stop in all queues */
5184 if (!set_member_paused("", interface, "Auto-Pause", 1)) {
5185 ast_verb(3, "Auto-Pausing Queue Member %s in all queues since they failed to answer on queue %s.\n",
5186 interface, qe->parent->name);
5187 } else {
5188 ast_verb(3, "Failed to pause Queue Member %s in all queues!\n", interface);
5189 }
5190 }
5191 }
5192 return;
5193}

References ao2_lock, ao2_ref, ao2_unlock, ast_channel_uniqueid(), ast_indicate(), ast_json_pack(), ast_json_unref(), ast_moh_start(), ast_queue_log(), ast_verb, call_queue::autopause, call_queue::autopausedelay, queue_ent::chan, callattempt::interface, member::interface, interface_exists(), member::lastcall, queue_ent::moh, call_queue::name, NULL, queue_ent::parent, QUEUE_AUTOPAUSE_OFF, QUEUE_AUTOPAUSE_ON, queue_publish_multi_channel_blob(), RAII_VAR, queue_ent::ring_when_ringing, and set_member_paused().

Referenced by wait_for_answer().

◆ rqm_exec()

static int rqm_exec ( struct ast_channel chan,
const char *  data 
)
static

RemoveQueueMember application.

Definition at line 8312 of file app_queue.c.

8313{
8314 int res=-1;
8315 char *parse, *temppos = NULL;
8316 struct member *mem = NULL;
8317
8319 AST_APP_ARG(queuename);
8321 );
8322
8323
8324 if (ast_strlen_zero(data)) {
8325 ast_log(LOG_WARNING, "RemoveQueueMember requires an argument (queuename[,interface])\n");
8326 return -1;
8327 }
8328
8329 parse = ast_strdupa(data);
8330
8332
8333 if (ast_strlen_zero(args.interface)) {
8334 args.interface = ast_strdupa(ast_channel_name(chan));
8335 temppos = strrchr(args.interface, '-');
8336 if (temppos) {
8337 *temppos = '\0';
8338 }
8339 }
8340
8341 ast_debug(1, "queue: %s, member: %s\n", args.queuename, args.interface);
8342
8344 mem = find_member_by_queuename_and_interface(args.queuename, args.interface);
8345 }
8346
8347 switch (remove_from_queue(args.queuename, args.interface)) {
8348 case RES_OKAY:
8349 if (!mem || ast_strlen_zero(mem->membername)) {
8350 ast_queue_log(args.queuename, ast_channel_uniqueid(chan), args.interface, "REMOVEMEMBER", "%s", "");
8351 } else {
8352 ast_queue_log(args.queuename, ast_channel_uniqueid(chan), mem->membername, "REMOVEMEMBER", "%s", "");
8353 }
8354 ast_log(LOG_NOTICE, "Removed interface '%s' from queue '%s'\n", args.interface, args.queuename);
8355 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "REMOVED");
8356 res = 0;
8357 break;
8358 case RES_EXISTS:
8359 ast_debug(1, "Unable to remove interface '%s' from queue '%s': Not there\n", args.interface, args.queuename);
8360 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOTINQUEUE");
8361 res = 0;
8362 break;
8363 case RES_NOSUCHQUEUE:
8364 ast_log(LOG_WARNING, "Unable to remove interface from queue '%s': No such queue\n", args.queuename);
8365 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOSUCHQUEUE");
8366 res = 0;
8367 break;
8368 case RES_NOT_DYNAMIC:
8369 ast_log(LOG_WARNING, "Unable to remove interface from queue '%s': '%s' is not a dynamic member\n", args.queuename, args.interface);
8370 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOTDYNAMIC");
8371 res = 0;
8372 break;
8373 }
8374
8375 if (mem) {
8376 ao2_ref(mem, -1);
8377 }
8378
8379 return res;
8380}

References ao2_ref, args, AST_APP_ARG, ast_channel_name(), ast_channel_uniqueid(), ast_debug, AST_DECLARE_APP_ARGS, ast_log, ast_queue_log(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), find_member_by_queuename_and_interface(), member::interface, log_membername_as_agent, LOG_NOTICE, LOG_WARNING, member::membername, NULL, pbx_builtin_setvar_helper(), remove_from_queue(), RES_EXISTS, RES_NOSUCHQUEUE, RES_NOT_DYNAMIC, and RES_OKAY.

Referenced by load_module().

◆ rt_handle_member_record()

static void rt_handle_member_record ( struct call_queue q,
char *  category,
struct ast_config member_config 
)
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 3607 of file app_queue.c.

3608{
3609 struct member *m;
3610 struct ao2_iterator mem_iter;
3611 int penalty = 0;
3612 int paused = 0;
3613 int found = 0;
3614 int wrapuptime = 0;
3615 int ringinuse = q->ringinuse;
3616
3617 const char *config_val;
3618 const char *interface = ast_variable_retrieve(member_config, category, "interface");
3619 const char *rt_uniqueid = ast_variable_retrieve(member_config, category, "uniqueid");
3620 const char *membername = S_OR(ast_variable_retrieve(member_config, category, "membername"), interface);
3621 const char *state_interface = S_OR(ast_variable_retrieve(member_config, category, "state_interface"), interface);
3622 const char *penalty_str = ast_variable_retrieve(member_config, category, "penalty");
3623 const char *paused_str = ast_variable_retrieve(member_config, category, "paused");
3624 const char *wrapuptime_str = ast_variable_retrieve(member_config, category, "wrapuptime");
3625 const char *reason_paused = ast_variable_retrieve(member_config, category, "reason_paused");
3626
3627 if (ast_strlen_zero(rt_uniqueid)) {
3628 ast_log(LOG_WARNING, "Realtime field 'uniqueid' is empty for member %s\n",
3629 S_OR(membername, "NULL"));
3630 return;
3631 }
3632
3633 if (ast_strlen_zero(interface)) {
3634 ast_log(LOG_WARNING, "Realtime field 'interface' is empty for member %s\n",
3635 S_OR(membername, "NULL"));
3636 return;
3637 }
3638
3639 if (penalty_str) {
3640 penalty = atoi(penalty_str);
3641 if ((penalty < 0) && negative_penalty_invalid) {
3642 return;
3643 } else if (penalty < 0) {
3644 penalty = 0;
3645 }
3646 }
3647
3648 if (paused_str) {
3649 paused = atoi(paused_str);
3650 if (paused < 0) {
3651 paused = 0;
3652 }
3653 }
3654
3655 if (wrapuptime_str) {
3656 wrapuptime = atoi(wrapuptime_str);
3657 if (wrapuptime < 0) {
3658 wrapuptime = 0;
3659 }
3660 }
3661
3662 if ((config_val = ast_variable_retrieve(member_config, category, realtime_ringinuse_field))) {
3663 if (ast_true(config_val)) {
3664 ringinuse = 1;
3665 } else if (ast_false(config_val)) {
3666 ringinuse = 0;
3667 } else {
3668 ast_log(LOG_WARNING, "Invalid value of '%s' field for %s in queue '%s'\n", realtime_ringinuse_field, interface, q->name);
3669 }
3670 }
3671
3672 /* Find member by realtime uniqueid and update */
3673 mem_iter = ao2_iterator_init(q->members, 0);
3674 while ((m = ao2_iterator_next(&mem_iter))) {
3675 if (!strcasecmp(m->rt_uniqueid, rt_uniqueid)) {
3676 m->dead = 0; /* Do not delete this one. */
3677 ast_copy_string(m->rt_uniqueid, rt_uniqueid, sizeof(m->rt_uniqueid));
3678 if (paused_str) {
3679 m->paused = paused;
3680 if (paused && m->lastpause == 0) {
3681 time(&m->lastpause); /* XXX: Should this come from realtime? */
3682 }
3684 AST_DEVSTATE_CACHABLE, "Queue:%s_pause_%s", q->name, m->interface);
3685 }
3686 if (strcasecmp(state_interface, m->state_interface)) {
3687 ast_copy_string(m->state_interface, state_interface, sizeof(m->state_interface));
3688 }
3689 m->penalty = penalty;
3690 m->ringinuse = ringinuse;
3691 m->wrapuptime = wrapuptime;
3693 ast_copy_string(m->reason_paused, S_OR(reason_paused, ""), sizeof(m->reason_paused));
3694 }
3695 found = 1;
3696 ao2_ref(m, -1);
3697 break;
3698 }
3699 ao2_ref(m, -1);
3700 }
3701 ao2_iterator_destroy(&mem_iter);
3702
3703 /* Create a new member */
3704 if (!found) {
3705 if ((m = create_queue_member(interface, membername, penalty, paused, state_interface, ringinuse, wrapuptime))) {
3706 m->dead = 0;
3707 m->realtime = 1;
3708 ast_copy_string(m->rt_uniqueid, rt_uniqueid, sizeof(m->rt_uniqueid));
3709 if (!ast_strlen_zero(reason_paused)) {
3710 ast_copy_string(m->reason_paused, reason_paused, sizeof(m->reason_paused));
3711 }
3713 ast_queue_log(q->name, "REALTIME", m->interface, "ADDMEMBER", "%s", paused ? "PAUSED" : "");
3714 } else {
3715 ast_queue_log(q->name, "REALTIME", m->membername, "ADDMEMBER", "%s", paused ? "PAUSED" : "");
3716 }
3717 member_add_to_queue(q, m);
3718 ao2_ref(m, -1);
3719 m = NULL;
3720 }
3721 }
3722}

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_ref, ast_copy_string(), AST_DEVSTATE_CACHABLE, ast_devstate_changed(), ast_false(), ast_log, ast_queue_log(), ast_strlen_zero(), ast_true(), ast_variable_retrieve(), create_queue_member(), member::dead, member::interface, member::lastpause, log_membername_as_agent, LOG_WARNING, member_add_to_queue(), member::membername, call_queue::members, call_queue::name, negative_penalty_invalid, NULL, member::paused, member::penalty, QUEUE_PAUSED_DEVSTATE, QUEUE_UNPAUSED_DEVSTATE, member::realtime, realtime_reason_paused, realtime_ringinuse_field, member::reason_paused, member::ringinuse, call_queue::ringinuse, member::rt_uniqueid, S_OR, member::state_interface, and member::wrapuptime.

Referenced by find_queue_by_name_rt(), and update_realtime_members().

◆ say_periodic_announcement()

static int say_periodic_announcement ( struct queue_ent qe,
int  ringing 
)
static

Playback announcement to queued members if period has elapsed.

Definition at line 5047 of file app_queue.c.

5048{
5049 int res = 0;
5050 time_t now;
5051
5052 /* Get the current time */
5053 time(&now);
5054
5055 /* Check to see if it is time to announce */
5057 return 0;
5058 }
5059
5060 /* Stop the music on hold so we can play our own file */
5061 if (ringing) {
5062 ast_indicate(qe->chan,-1);
5063 } else {
5064 ast_moh_stop(qe->chan);
5065 }
5066
5067 ast_verb(3, "Playing periodic announcement\n");
5068
5070 qe->last_periodic_announce_sound = ((unsigned long) ast_random()) % qe->parent->numperiodicannounce;
5074 }
5075
5076 /* play the announcement */
5078
5079 if (res > 0 && !valid_exit(qe, res)) {
5080 res = 0;
5081 }
5082
5083 /* Resume Music on Hold if the caller is going to stay in the queue */
5084 if (!res) {
5085 if (ringing) {
5087 } else {
5088 ast_moh_start(qe->chan, qe->moh, NULL);
5089 }
5090 }
5091
5092 /* update last_periodic_announce_time */
5094 time(&qe->last_periodic_announce_time);
5095 } else {
5097 }
5098
5099 /* Update the current periodic announcement to the next announcement */
5100 if (!qe->parent->randomperiodicannounce) {
5102 }
5103
5104 return res;
5105}
static int play_file(struct ast_channel *chan, const char *filename)
Definition: app_queue.c:4172
static int valid_exit(struct queue_ent *qe, char digit)
Check for valid exit from queue via goto.
Definition: app_queue.c:4201

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, NULL, call_queue::numperiodicannounce, queue_ent::parent, call_queue::periodicannouncefrequency, play_file(), call_queue::randomperiodicannounce, call_queue::relativeperiodicannounce, ringing(), call_queue::sound_periodicannounce, and valid_exit().

Referenced by queue_exec(), and wait_our_turn().

◆ say_position()

static int say_position ( struct queue_ent qe,
int  ringing 
)
static

Definition at line 4236 of file app_queue.c.

4237{
4238 int res = 0, say_thanks = 0;
4239 long avgholdmins, avgholdsecs;
4240 time_t now;
4241
4242 /* Let minannouncefrequency seconds pass between the start of each position announcement */
4243 time(&now);
4244 if ((now - qe->last_pos) < qe->parent->minannouncefrequency) {
4245 return 0;
4246 }
4247
4248 /* If either our position has changed, or we are over the freq timer, say position */
4249 if ((qe->last_pos_said == qe->pos) && ((now - qe->last_pos) < qe->parent->announcefrequency)) {
4250 return 0;
4251 }
4252
4253 /* Only announce if the caller's queue position has improved since last time */
4254 if (qe->parent->announceposition_only_up && qe->last_pos_said <= qe->pos) {
4255 return 0;
4256 }
4257
4258 if (ringing) {
4259 ast_indicate(qe->chan,-1);
4260 } else {
4261 ast_moh_stop(qe->chan);
4262 }
4263
4267 qe->pos <= qe->parent->announcepositionlimit)) {
4268 say_thanks = 1;
4269 /* Say we're next, if we are */
4270 if (qe->pos == 1) {
4271 res = play_file(qe->chan, qe->parent->sound_next);
4272 if (!res) {
4273 goto posout;
4274 }
4275 /* Say there are more than N callers */
4277 res = (
4278 play_file(qe->chan, qe->parent->queue_quantity1) ||
4280 ast_channel_language(qe->chan), NULL) || /* Needs gender */
4282 /* Say there are currently N callers waiting */
4283 } else {
4284 res = (
4285 play_file(qe->chan, qe->parent->sound_thereare) ||
4287 ast_channel_language(qe->chan), "n") || /* Needs gender */
4288 play_file(qe->chan, qe->parent->sound_calls));
4289 }
4290 if (res) {
4291 goto playout;
4292 }
4293 }
4294 /* Round hold time to nearest minute */
4295 avgholdmins = labs(((qe->parent->holdtime + 30) - (now - qe->start)) / 60);
4296
4297 /* If they have specified a rounding then round the seconds as well */
4298 if (qe->parent->roundingseconds) {
4299 avgholdsecs = (labs(((qe->parent->holdtime + 30) - (now - qe->start))) - 60 * avgholdmins) / qe->parent->roundingseconds;
4300 avgholdsecs *= qe->parent->roundingseconds;
4301 } else {
4302 avgholdsecs = 0;
4303 }
4304
4305 ast_verb(3, "Hold time for %s is %ld minute(s) %ld seconds\n", qe->parent->name, avgholdmins, avgholdsecs);
4306
4307 /* If the hold time is >1 min, if it's enabled, and if it's not
4308 supposed to be only once and we have already said it, say it */
4309 if ((avgholdmins+avgholdsecs) > 0 && qe->parent->announceholdtime &&
4312 say_thanks = 1;
4313 res = play_file(qe->chan, qe->parent->sound_holdtime);
4314 if (res) {
4315 goto playout;
4316 }
4317
4318 if (avgholdmins >= 1) {
4319 res = ast_say_number(qe->chan, avgholdmins, AST_DIGIT_ANY, ast_channel_language(qe->chan), "n");
4320 if (res) {
4321 goto playout;
4322 }
4323
4324 if (avgholdmins == 1) {
4325 res = play_file(qe->chan, qe->parent->sound_minute);
4326 if (res) {
4327 goto playout;
4328 }
4329 } else {
4330 res = play_file(qe->chan, qe->parent->sound_minutes);
4331 if (res) {
4332 goto playout;
4333 }
4334 }
4335 }
4336 if (avgholdsecs >= 1) {
4337 res = ast_say_number(qe->chan, avgholdsecs, AST_DIGIT_ANY, ast_channel_language(qe->chan), "n");
4338 if (res) {
4339 goto playout;
4340 }
4341
4342 res = play_file(qe->chan, qe->parent->sound_seconds);
4343 if (res) {
4344 goto playout;
4345 }
4346 }
4347 }
4348
4349posout:
4350 if (qe->parent->announceposition) {
4351 ast_verb(3, "Told %s in %s their queue position (which was %d)\n",
4352 ast_channel_name(qe->chan), qe->parent->name, qe->pos);
4353 }
4354 if (say_thanks) {
4355 res = play_file(qe->chan, qe->parent->sound_thanks);
4356 }
4357playout:
4358
4359 if ((res > 0 && !valid_exit(qe, res))) {
4360 res = 0;
4361 }
4362
4363 /* Set our last_pos indicators */
4364 qe->last_pos = now;
4365 qe->last_pos_said = qe->pos;
4366
4367 /* Don't restart music on hold if we're about to exit the caller from the queue */
4368 if (!res) {
4369 if (ringing) {
4371 } else {
4372 ast_moh_start(qe->chan, qe->moh, NULL);
4373 }
4374 }
4375 return res;
4376}
int ast_say_number(struct ast_channel *chan, int num, const char *ints, const char *lang, const char *options)
says a number
Definition: channel.c:8257
const ast_string_field sound_thereare
Definition: app_queue.c:1858
const ast_string_field sound_holdtime
Definition: app_queue.c:1858
const ast_string_field sound_seconds
Definition: app_queue.c:1858
const ast_string_field sound_thanks
Definition: app_queue.c:1858
const ast_string_field queue_quantity2
Definition: app_queue.c:1858
const ast_string_field sound_calls
Definition: app_queue.c:1858
const ast_string_field sound_minute
Definition: app_queue.c:1858
const ast_string_field sound_minutes
Definition: app_queue.c:1858
const ast_string_field queue_quantity1
Definition: app_queue.c:1858
const ast_string_field sound_next
Definition: app_queue.c:1858

References call_queue::announcefrequency, call_queue::announceholdtime, ANNOUNCEHOLDTIME_ONCE, call_queue::announceposition, ANNOUNCEPOSITION_LIMIT, ANNOUNCEPOSITION_MORE_THAN, call_queue::announceposition_only_up, ANNOUNCEPOSITION_YES, call_queue::announcepositionlimit, ast_channel_language(), ast_channel_name(), 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, queue_ent::last_pos, queue_ent::last_pos_said, call_queue::minannouncefrequency, queue_ent::moh, call_queue::name, NULL, queue_ent::parent, play_file(), queue_ent::pos, call_queue::queue_quantity1, call_queue::queue_quantity2, ringing(), 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(), and wait_our_turn().

◆ send_agent_complete()

static void send_agent_complete ( const char *  queuename,
struct ast_channel_snapshot caller,
struct ast_channel_snapshot peer,
const struct member member,
time_t  holdstart,
time_t  callstart,
enum agent_complete_reason  rsn 
)
static

Send out AMI message with member call completion status information.

Definition at line 6158 of file app_queue.c.

6161{
6162 const char *reason = NULL; /* silence dumb compilers */
6163 RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
6164
6165 switch (rsn) {
6166 case CALLER:
6167 reason = "caller";
6168 break;
6169 case AGENT:
6170 reason = "agent";
6171 break;
6172 case TRANSFER:
6173 reason = "transfer";
6174 break;
6175 }
6176
6177 blob = ast_json_pack("{s: s, s: s, s: s, s: I, s: I, s: s}",
6178 "Queue", queuename,
6179 "Interface", member->interface,
6180 "MemberName", member->membername,
6181 "HoldTime", (ast_json_int_t)(callstart - holdstart),
6182 "TalkTime", (ast_json_int_t)(time(NULL) - callstart),
6183 "Reason", reason ?: "");
6184
6186 queue_agent_complete_type(), blob);
6187}
struct stasis_topic * ast_queue_topic(const char *queuename)
Get the Stasis Message Bus API topic for queue messages for a particular queue name.
Definition: main/app.c:3349
AST_JSON_INT_T ast_json_int_t
Primarily used to cast when packing to an "I" type.
Definition: json.h:87

References AGENT, ast_json_pack(), ast_json_unref(), ast_queue_topic(), CALLER, member::interface, member::membername, NULL, queue_publish_multi_channel_snapshot_blob(), RAII_VAR, and TRANSFER.

Referenced by handle_attended_transfer(), handle_blind_transfer(), and handle_hangup().

◆ set_member_paused()

static int set_member_paused ( const char *  queuename,
const char *  interface,
const char *  reason,
int  paused 
)
static

Definition at line 7881 of file app_queue.c.

7882{
7883 int found = 0;
7884 struct call_queue *q;
7885 struct ao2_iterator queue_iter;
7886
7887 if (ast_check_realtime("queues")) {
7888 load_realtime_queues(queuename);
7889 }
7890
7891 queue_iter = ao2_iterator_init(queues, 0);
7892 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate over queues"))) {
7893 ao2_lock(q);
7894 if (ast_strlen_zero(queuename) || !strcasecmp(q->name, queuename)) {
7895 struct member *mem;
7896
7897 if ((mem = interface_exists(q, interface))) {
7898 /*
7899 * Before we do the PAUSE/UNPAUSE, log if this was a
7900 * PAUSEALL/UNPAUSEALL but only on the first found entry.
7901 */
7902 ++found;
7903 if (found == 1
7904 && ast_strlen_zero(queuename)) {
7905 /*
7906 * XXX In all other cases, we use the queue name,
7907 * but since this affects all queues, we cannot.
7908 */
7909 ast_queue_log("NONE", "NONE", mem->membername,
7910 (paused ? "PAUSEALL" : "UNPAUSEALL"), "%s", S_OR(reason, ""));
7911 }
7912
7913 set_queue_member_pause(q, mem, reason, paused);
7914 ao2_ref(mem, -1);
7915 }
7916
7917 if (!ast_strlen_zero(queuename)) {
7918 ao2_unlock(q);
7919 queue_t_unref(q, "Done with iterator");
7920 break;
7921 }
7922 }
7923
7924 ao2_unlock(q);
7925 queue_t_unref(q, "Done with iterator");
7926 }
7927 ao2_iterator_destroy(&queue_iter);
7928
7929 return found ? RESULT_SUCCESS : RESULT_FAILURE;
7930}
static void set_queue_member_pause(struct call_queue *q, struct member *mem, const char *reason, int paused)
Definition: app_queue.c:7814

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_lock, ao2_ref, ao2_t_iterator_next, ao2_unlock, ast_check_realtime(), ast_queue_log(), ast_strlen_zero(), member::interface, interface_exists(), load_realtime_queues(), member::membername, call_queue::name, member::paused, queue_t_unref, queues, RESULT_FAILURE, RESULT_SUCCESS, S_OR, and set_queue_member_pause().

Referenced by handle_queue_pause_member(), manager_pause_queue_member(), pqm_exec(), queue_function_mem_write(), rna(), and upqm_exec().

◆ set_member_penalty_help_members()

static int set_member_penalty_help_members ( struct call_queue q,
const char *  interface,
int  penalty 
)
static

Definition at line 7941 of file app_queue.c.

7942{
7943 struct member *mem;
7944 int foundinterface = 0;
7945
7946 ao2_lock(q);
7947 if ((mem = interface_exists(q, interface))) {
7948 foundinterface++;
7949 if (mem->realtime) {
7950 char rtpenalty[80];
7951
7952 sprintf(rtpenalty, "%i", penalty);
7953 update_realtime_member_field(mem, q->name, "penalty", rtpenalty);
7954 }
7955
7956 mem->penalty = penalty;
7957
7958 ast_queue_log(q->name, "NONE", interface, "PENALTY", "%d", penalty);
7959 queue_publish_member_blob(queue_member_penalty_type(), queue_member_blob_create(q, mem));
7960 ao2_ref(mem, -1);
7961 }
7962 ao2_unlock(q);
7963
7964 return foundinterface;
7965}

References ao2_lock, ao2_ref, ao2_unlock, ast_queue_log(), member::interface, interface_exists(), call_queue::name, member::penalty, queue_member_blob_create(), queue_publish_member_blob(), member::realtime, and update_realtime_member_field().

Referenced by set_member_value_help_members().

◆ set_member_ringinuse_help_members()

static int set_member_ringinuse_help_members ( struct call_queue q,
const char *  interface,
int  ringinuse 
)
static

Definition at line 7990 of file app_queue.c.

7991{
7992 struct member *mem;
7993 int foundinterface = 0;
7994
7995 ao2_lock(q);
7996 if ((mem = interface_exists(q, interface))) {
7997 foundinterface++;
7999 ao2_ref(mem, -1);
8000 }
8001 ao2_unlock(q);
8002
8003 return foundinterface;
8004}
static void set_queue_member_ringinuse(struct call_queue *q, struct member *mem, int ringinuse)
Definition: app_queue.c:7977

References ao2_lock, ao2_ref, ao2_unlock, member::interface, interface_exists(), member::ringinuse, and set_queue_member_ringinuse().

Referenced by set_member_value_help_members().

◆ set_member_value()

static int set_member_value ( const char *  queuename,
const char *  interface,
int  property,
int  value 
)
static

Definition at line 8029 of file app_queue.c.

8030{
8031 int foundinterface = 0, foundqueue = 0;
8032 struct call_queue *q;
8033 struct ast_config *queue_config = NULL;
8034 struct ao2_iterator queue_iter;
8035
8036 /* property dependent restrictions on values should be checked in this switch */
8037 switch (property) {
8038 case MEMBER_PENALTY:
8039 if (value < 0 && !negative_penalty_invalid) {
8040 ast_log(LOG_ERROR, "Invalid penalty (%d)\n", value);
8041 return RESULT_FAILURE;
8042 }
8043 }
8044
8045 if (ast_strlen_zero(queuename)) { /* This means we need to iterate through all the queues. */
8046 if (ast_check_realtime("queues")) {
8047 queue_config = ast_load_realtime_multientry("queues", "name LIKE", "%", SENTINEL);
8048 if (queue_config) {
8049 char *category = NULL;
8050 while ((category = ast_category_browse(queue_config, category))) {
8051 const char *name = ast_variable_retrieve(queue_config, category, "name");
8052 if (ast_strlen_zero(name)) {
8053 ast_log(LOG_WARNING, "Ignoring realtime queue with a NULL or empty 'name.'\n");
8054 continue;
8055 }
8056 if ((q = find_load_queue_rt_friendly(name))) {
8057 foundqueue++;
8058 foundinterface += set_member_value_help_members(q, interface, property, value);
8059 queue_unref(q);
8060 }
8061 }
8062
8063 ast_config_destroy(queue_config);
8064 }
8065 }
8066
8067 /* After hitting realtime queues, go back and get the regular ones. */
8068 queue_iter = ao2_iterator_init(queues, 0);
8069 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
8070 foundqueue++;
8071 foundinterface += set_member_value_help_members(q, interface, property, value);
8072 queue_unref(q);
8073 }
8074 ao2_iterator_destroy(&queue_iter);
8075 } else { /* We actually have a queuename, so we can just act on the single queue. */
8076 if ((q = find_load_queue_rt_friendly(queuename))) {
8077 foundqueue++;
8078 foundinterface += set_member_value_help_members(q, interface, property, value);
8079 queue_unref(q);
8080 }
8081 }
8082
8083 if (foundinterface) {
8084 return RESULT_SUCCESS;
8085 } else if (!foundqueue) {
8086 ast_log (LOG_ERROR, "Invalid queuename\n");
8087 } else {
8088 ast_log (LOG_ERROR, "Invalid interface\n");
8089 }
8090
8091 return RESULT_FAILURE;
8092}
static int set_member_value_help_members(struct call_queue *q, const char *interface, int property, int value)
Definition: app_queue.c:8006

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_t_iterator_next, ast_category_browse(), ast_check_realtime(), ast_config_destroy(), ast_load_realtime_multientry(), ast_log, ast_strlen_zero(), ast_variable_retrieve(), find_load_queue_rt_friendly(), LOG_ERROR, LOG_WARNING, MEMBER_PENALTY, name, negative_penalty_invalid, NULL, queue_unref, queues, RESULT_FAILURE, RESULT_SUCCESS, SENTINEL, set_member_value_help_members(), and value.

Referenced by handle_queue_set_member_penalty(), handle_queue_set_member_ringinuse(), manager_queue_member_penalty(), manager_queue_member_ringinuse(), queue_function_mem_write(), and queue_function_memberpenalty_write().

◆ set_member_value_help_members()

static int set_member_value_help_members ( struct call_queue q,
const char *  interface,
int  property,
int  value 
)
static

Definition at line 8006 of file app_queue.c.

8007{
8008 switch(property) {
8009 case MEMBER_PENALTY:
8010 return set_member_penalty_help_members(q, interface, value);
8011
8012 case MEMBER_RINGINUSE:
8013 return set_member_ringinuse_help_members(q, interface, value);
8014
8015 default:
8016 ast_log(LOG_ERROR, "Attempted to set invalid property\n");
8017 return 0;
8018 }
8019}
static int set_member_ringinuse_help_members(struct call_queue *q, const char *interface, int ringinuse)
Definition: app_queue.c:7990
static int set_member_penalty_help_members(struct call_queue *q, const char *interface, int penalty)
Definition: app_queue.c:7941

References ast_log, member::interface, LOG_ERROR, MEMBER_PENALTY, MEMBER_RINGINUSE, set_member_penalty_help_members(), set_member_ringinuse_help_members(), and value.

Referenced by set_member_value().

◆ set_queue_member_pause()

static void set_queue_member_pause ( struct call_queue q,
struct member mem,
const char *  reason,
int  paused 
)
static

Definition at line 7814 of file app_queue.c.

7815{
7816 if (mem->paused == paused) {
7817 ast_debug(1, "%spausing already-%spaused queue member %s:%s\n",
7818 (paused ? "" : "un"), (paused ? "" : "un"), q->name, mem->interface);
7819 }
7820
7821 if (mem->realtime && !ast_strlen_zero(mem->rt_uniqueid)) {
7823 if (ast_update_realtime("queue_members", "uniqueid", mem->rt_uniqueid, "reason_paused", S_OR(reason, ""), "paused", paused ? "1" : "0", SENTINEL) < 0) {
7824 ast_log(LOG_WARNING, "Failed update of realtime queue member %s:%s %spause and reason '%s'\n",
7825 q->name, mem->interface, (paused ? "" : "un"), S_OR(reason, ""));
7826 }
7827 } else {
7828 if (ast_update_realtime("queue_members", "uniqueid", mem->rt_uniqueid, "paused", paused ? "1" : "0", SENTINEL) < 0) {
7829 ast_log(LOG_WARNING, "Failed %spause update of realtime queue member %s:%s\n",
7830 (paused ? "" : "un"), q->name, mem->interface);
7831 }
7832 }
7833 }
7834
7835 mem->paused = paused;
7836 if (paused) {
7837 time(&mem->lastpause); /* update last pause field */
7838 }
7839 if (paused && !ast_strlen_zero(reason)) {
7840 ast_copy_string(mem->reason_paused, reason, sizeof(mem->reason_paused));
7841 } else {
7842 /* We end up filling this in again later (temporarily) but we need it
7843 * empty for now so that the intervening code - specifically
7844 * dump_queue_members() - has the correct view of things. */
7845 mem->reason_paused[0] = '\0';
7846 }
7847
7849 AST_DEVSTATE_CACHABLE, "Queue:%s_pause_%s", q->name, mem->interface);
7850
7853 }
7854
7855 if (is_member_available(q, mem)) {
7857 "Queue:%s_avail", q->name);
7858 } else if (!num_available_members(q)) {
7860 "Queue:%s_avail", q->name);
7861 }
7862
7863 if (!paused && !ast_strlen_zero(reason)) {
7864 /* Because we've been unpaused with a 'reason' we need to ensure that
7865 * that reason is emitted when the subsequent PauseQueueMember event
7866 * is raised. So temporarily set it on the member and clear it out
7867 * again right after. */
7868 ast_copy_string(mem->reason_paused, reason, sizeof(mem->reason_paused));
7869 }
7870
7871 ast_queue_log(q->name, "NONE", mem->membername, paused ? "PAUSE" : "UNPAUSE",
7872 "%s", mem->reason_paused);
7873
7875
7876 if (!paused) {
7877 mem->reason_paused[0] = '\0';
7878 }
7879}
static int publish_queue_member_pause(struct call_queue *q, struct member *member)
Definition: app_queue.c:7790
int ast_update_realtime(const char *family, const char *keyfield, const char *lookup,...) attribute_sentinel
Update realtime configuration.
Definition: main/config.c:3674

References ast_copy_string(), ast_debug, AST_DEVICE_INUSE, AST_DEVICE_NOT_INUSE, AST_DEVSTATE_CACHABLE, ast_devstate_changed(), ast_log, ast_queue_log(), ast_strlen_zero(), ast_update_realtime(), dump_queue_members(), member::interface, is_member_available(), member::lastpause, LOG_WARNING, member::membername, call_queue::name, num_available_members(), member::paused, publish_queue_member_pause(), QUEUE_PAUSED_DEVSTATE, queue_persistent_members, QUEUE_UNPAUSED_DEVSTATE, member::realtime, realtime_reason_paused, member::reason_paused, member::rt_uniqueid, S_OR, and SENTINEL.

Referenced by set_member_paused().

◆ set_queue_member_ringinuse()

static void set_queue_member_ringinuse ( struct call_queue q,
struct member mem,
int  ringinuse 
)
static

Definition at line 7977 of file app_queue.c.

7978{
7979 if (mem->realtime) {
7981 ringinuse ? "1" : "0");
7982 }
7983
7984 mem->ringinuse = ringinuse;
7985
7986 ast_queue_log(q->name, "NONE", mem->interface, "RINGINUSE", "%d", ringinuse);
7987 queue_publish_member_blob(queue_member_ringinuse_type(), queue_member_blob_create(q, mem));
7988}

References ast_queue_log(), member::interface, call_queue::name, queue_member_blob_create(), queue_publish_member_blob(), member::realtime, realtime_ringinuse_field, member::ringinuse, and update_realtime_member_field().

Referenced by set_member_ringinuse_help_members().

◆ set_queue_result()

static void set_queue_result ( struct ast_channel chan,
enum queue_result  res 
)
static

sets the QUEUESTATUS channel variable

Definition at line 1939 of file app_queue.c.

1940{
1941 int i;
1942
1943 for (i = 0; i < ARRAY_LEN(queue_results); i++) {
1944 if (queue_results[i].id == res) {
1945 pbx_builtin_setvar_helper(chan, "QUEUESTATUS", queue_results[i].text);
1946 return;
1947 }
1948 }
1949}
static const struct @50 queue_results[]
char * text
Definition: app_queue.c:1668

References ARRAY_LEN, pbx_builtin_setvar_helper(), queue_results, and text.

Referenced by queue_exec().

◆ set_queue_variables()

static void set_queue_variables ( struct call_queue q,
struct ast_channel chan 
)
static

Set variables of queue.

Definition at line 2092 of file app_queue.c.

2093{
2094 char interfacevar[256]="";
2095 float sl = 0;
2096
2097 ao2_lock(q);
2098
2099 if (q->setqueuevar) {
2100 sl = 0;
2101 if (q->callscompleted > 0) {
2102 sl = 100 * ((float) q->callscompletedinsl / (float) q->callscompleted);
2103 }
2104
2105 snprintf(interfacevar, sizeof(interfacevar),
2106 "QUEUENAME=%s,QUEUEMAX=%d,QUEUESTRATEGY=%s,QUEUECALLS=%d,QUEUEHOLDTIME=%d,QUEUETALKTIME=%d,QUEUECOMPLETED=%d,QUEUEABANDONED=%d,QUEUESRVLEVEL=%d,QUEUESRVLEVELPERF=%2.1f",
2108
2109 ao2_unlock(q);
2110
2111 pbx_builtin_setvar_multiple(chan, interfacevar);
2112 } else {
2113 ao2_unlock(q);
2114 }
2115}

References ao2_lock, ao2_unlock, call_queue::callsabandoned, call_queue::callscompleted, call_queue::callscompletedinsl, 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(), queue_exec(), record_abandoned(), and try_calling().

◆ setup_mixmonitor()

static void setup_mixmonitor ( struct queue_ent qe,
const char *  filename 
)
static

Definition at line 6934 of file app_queue.c.

6935{
6936 char escaped_filename[256];
6937 char file_with_ext[sizeof(escaped_filename) + sizeof(qe->parent->monfmt)];
6938 char mixmonargs[1512];
6939 char escaped_monitor_exec[1024];
6940 const char *monitor_options;
6941 const char *monitor_exec;
6942
6943 escaped_monitor_exec[0] = '\0';
6944
6945 if (filename) {
6946 escape_and_substitute(qe->chan, filename, escaped_filename, sizeof(escaped_filename));
6947 } else {
6948 ast_copy_string(escaped_filename, ast_channel_uniqueid(qe->chan), sizeof(escaped_filename));
6949 }
6950
6952 if ((monitor_exec = pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC"))) {
6953 monitor_exec = ast_strdupa(monitor_exec);
6954 }
6955 if ((monitor_options = pbx_builtin_getvar_helper(qe->chan, "MONITOR_OPTIONS"))) {
6956 monitor_options = ast_strdupa(monitor_options);
6957 } else {
6958 monitor_options = "";
6959 }
6961
6962 if (monitor_exec) {
6963 escape_and_substitute(qe->chan, monitor_exec, escaped_monitor_exec, sizeof(escaped_monitor_exec));
6964 }
6965
6966 snprintf(file_with_ext, sizeof(file_with_ext), "%s.%s", escaped_filename, qe->parent->monfmt);
6967
6968 if (!ast_strlen_zero(escaped_monitor_exec)) {
6969 snprintf(mixmonargs, sizeof(mixmonargs), "b%s,%s", monitor_options, escaped_monitor_exec);
6970 } else {
6971 snprintf(mixmonargs, sizeof(mixmonargs), "b%s", monitor_options);
6972 }
6973
6974 ast_debug(1, "Arguments being passed to MixMonitor: %s,%s\n", file_with_ext, mixmonargs);
6975
6976 if (ast_start_mixmonitor(qe->chan, file_with_ext, mixmonargs)) {
6977 ast_log(LOG_WARNING, "Unable to start mixmonitor. Is the MixMonitor app loaded?\n");
6978 }
6979}
static void escape_and_substitute(struct ast_channel *chan, const char *input, char *output, size_t size)
Definition: app_queue.c:6903
int ast_start_mixmonitor(struct ast_channel *chan, const char *filename, const char *options)
Start a mixmonitor on a channel with the given parameters.
Definition: mixmonitor.c:74

References ast_channel_lock, ast_channel_uniqueid(), ast_channel_unlock, ast_copy_string(), ast_debug, ast_log, ast_start_mixmonitor(), ast_strdupa, ast_strlen_zero(), queue_ent::chan, escape_and_substitute(), LOG_WARNING, call_queue::monfmt, queue_ent::parent, and pbx_builtin_getvar_helper().

Referenced by try_calling().

◆ setup_peer_after_bridge_goto()

static void setup_peer_after_bridge_goto ( struct ast_channel chan,
struct ast_channel peer,
struct ast_flags opts,
char *  opt_args[] 
)
static

Definition at line 6886 of file app_queue.c.

6887{
6888 const char *context;
6889 const char *extension;
6890 int priority;
6891
6892 if (ast_test_flag(opts, OPT_CALLEE_GO_ON)) {
6893 ast_channel_lock(chan);
6897 ast_channel_unlock(chan);
6899 opt_args[OPT_ARG_CALLEE_GO_ON]);
6900 }
6901}
void ast_bridge_set_after_go_on(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *parseable_goto)
Set channel to go on in the dialplan after the bridge.
Definition: bridge_after.c:622
int ast_channel_priority(const struct ast_channel *chan)
structure to hold extensions

References ast_bridge_set_after_go_on(), ast_channel_context(), ast_channel_exten(), ast_channel_lock, ast_channel_priority(), ast_channel_unlock, ast_strdupa, ast_test_flag, voicemailpwcheck::context, OPT_ARG_CALLEE_GO_ON, OPT_CALLEE_GO_ON, and priority.

Referenced by try_calling().

◆ setup_stasis_subs()

static int setup_stasis_subs ( struct queue_ent qe,
struct ast_channel peer,
struct member mem,
time_t  holdstart,
time_t  starttime,
int  callcompletedinsl 
)
static

Definition at line 6802 of file app_queue.c.

6804{
6805 struct queue_stasis_data *queue_data = queue_stasis_data_alloc(qe, peer, mem, holdstart, starttime, callcompletedinsl);
6806
6807 if (!queue_data) {
6808 return -1;
6809 }
6810
6812 if (!queue_data->bridge_router) {
6813 ao2_ref(queue_data, -1);
6814 return -1;
6815 }
6816
6818 handle_bridge_enter, queue_data);
6820 handle_blind_transfer, queue_data);
6822 handle_attended_transfer, queue_data);
6824 queue_bridge_cb, queue_data);
6825
6827 if (!queue_data->channel_router) {
6828 /* Unsubscribing from the bridge router will remove the only ref of queue_data,
6829 * thus beginning the destruction process
6830 */
6832 queue_data->bridge_router = NULL;
6833 return -1;
6834 }
6835
6836 ao2_ref(queue_data, +1);
6840 handle_local_optimization_end, queue_data);
6842 handle_hangup, queue_data);
6844 handle_masquerade, queue_data);
6846 queue_channel_cb, queue_data);
6847
6848 return 0;
6849}
static void handle_bridge_enter(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Definition: app_queue.c:6405
static void queue_bridge_cb(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Definition: app_queue.c:6552
static void handle_attended_transfer(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Handle an attended transfer event.
Definition: app_queue.c:6497
static void handle_masquerade(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Definition: app_queue.c:6743
static void handle_local_optimization_begin(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Definition: app_queue.c:6571
static void handle_local_optimization_end(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Definition: app_queue.c:6622
static struct queue_stasis_data * queue_stasis_data_alloc(struct queue_ent *qe, struct ast_channel *peer, struct member *mem, time_t holdstart, time_t starttime, int callcompletedinsl)
Definition: app_queue.c:6320
static void queue_channel_cb(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Definition: app_queue.c:6777
static void handle_hangup(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Definition: app_queue.c:6686
static void handle_blind_transfer(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Handle a blind transfer event.
Definition: app_queue.c:6438
struct stasis_message_type * ast_local_optimization_end_type(void)
Message type for when a local channel optimization completes.
struct stasis_message_type * ast_local_optimization_begin_type(void)
Message type for when a local channel optimization begins.
struct stasis_message_type * ast_channel_masquerade_type(void)
Message type for when a channel is being masqueraded.
struct stasis_message_type * ast_channel_hangup_request_type(void)
Message type for when a hangup is requested on a channel.
struct stasis_message_type * ast_channel_entered_bridge_type(void)
Message type for ast_channel enter bridge blob messages.
struct stasis_message_type * ast_blind_transfer_type(void)
Message type for ast_blind_transfer_message.
struct stasis_message_type * ast_attended_transfer_type(void)
Message type for ast_attended_transfer_message.
struct stasis_topic * ast_bridge_topic_all(void)
A topic which publishes the events for all bridges.
#define stasis_message_router_create_pool(topic)
Create a new message router object.
int stasis_message_router_set_default(struct stasis_message_router *router, stasis_subscription_cb callback, void *data)
Sets the default route of a router.

References ao2_ref, ast_attended_transfer_type(), ast_blind_transfer_type(), ast_bridge_topic_all(), ast_channel_entered_bridge_type(), ast_channel_hangup_request_type(), ast_channel_masquerade_type(), ast_channel_topic_all(), ast_local_optimization_begin_type(), ast_local_optimization_end_type(), queue_stasis_data::bridge_router, queue_stasis_data::callcompletedinsl, queue_stasis_data::channel_router, handle_attended_transfer(), handle_blind_transfer(), handle_bridge_enter(), handle_hangup(), handle_local_optimization_begin(), handle_local_optimization_end(), handle_masquerade(), queue_stasis_data::holdstart, NULL, queue_bridge_cb(), queue_channel_cb(), queue_stasis_data_alloc(), queue_stasis_data::starttime, stasis_message_router_add(), stasis_message_router_create_pool, stasis_message_router_set_default(), and stasis_message_router_unsubscribe().

Referenced by try_calling().

◆ STASIS_MESSAGE_TYPE_DEFN_LOCAL() [1/14]

STASIS_MESSAGE_TYPE_DEFN_LOCAL ( queue_agent_called_type  ,
to_ami = queue_agent_called_to_ami 
)

◆ STASIS_MESSAGE_TYPE_DEFN_LOCAL() [2/14]

STASIS_MESSAGE_TYPE_DEFN_LOCAL ( queue_agent_complete_type  ,
to_ami = queue_agent_complete_to_ami 
)

◆ STASIS_MESSAGE_TYPE_DEFN_LOCAL() [3/14]

STASIS_MESSAGE_TYPE_DEFN_LOCAL ( queue_agent_connect_type  ,
to_ami = queue_agent_connect_to_ami 
)

◆ STASIS_MESSAGE_TYPE_DEFN_LOCAL() [4/14]

STASIS_MESSAGE_TYPE_DEFN_LOCAL ( queue_agent_dump_type  ,
to_ami = queue_agent_dump_to_ami 
)

◆ STASIS_MESSAGE_TYPE_DEFN_LOCAL() [5/14]

STASIS_MESSAGE_TYPE_DEFN_LOCAL ( queue_agent_ringnoanswer_type  ,
to_ami = queue_agent_ringnoanswer_to_ami 
)

◆ STASIS_MESSAGE_TYPE_DEFN_LOCAL() [6/14]

STASIS_MESSAGE_TYPE_DEFN_LOCAL ( queue_caller_abandon_type  ,
to_ami = queue_caller_abandon_to_ami 
)

◆ STASIS_MESSAGE_TYPE_DEFN_LOCAL() [7/14]

STASIS_MESSAGE_TYPE_DEFN_LOCAL ( queue_caller_join_type  ,
to_ami = queue_caller_join_to_ami 
)

◆ STASIS_MESSAGE_TYPE_DEFN_LOCAL() [8/14]

STASIS_MESSAGE_TYPE_DEFN_LOCAL ( queue_caller_leave_type  ,
to_ami = queue_caller_leave_to_ami 
)

◆ STASIS_MESSAGE_TYPE_DEFN_LOCAL() [9/14]

STASIS_MESSAGE_TYPE_DEFN_LOCAL ( queue_member_added_type  ,
to_ami = queue_member_added_to_ami 
)

◆ STASIS_MESSAGE_TYPE_DEFN_LOCAL() [10/14]

STASIS_MESSAGE_TYPE_DEFN_LOCAL ( queue_member_pause_type  ,
to_ami = queue_member_pause_to_ami 
)

◆ STASIS_MESSAGE_TYPE_DEFN_LOCAL() [11/14]

STASIS_MESSAGE_TYPE_DEFN_LOCAL ( queue_member_penalty_type  ,
to_ami = queue_member_penalty_to_ami 
)

◆ STASIS_MESSAGE_TYPE_DEFN_LOCAL() [12/14]

STASIS_MESSAGE_TYPE_DEFN_LOCAL ( queue_member_removed_type  ,
to_ami = queue_member_removed_to_ami 
)

◆ STASIS_MESSAGE_TYPE_DEFN_LOCAL() [13/14]

STASIS_MESSAGE_TYPE_DEFN_LOCAL ( queue_member_ringinuse_type  ,
to_ami = queue_member_ringinuse_to_ami 
)

◆ STASIS_MESSAGE_TYPE_DEFN_LOCAL() [14/14]

STASIS_MESSAGE_TYPE_DEFN_LOCAL ( queue_member_status_type  ,
to_ami = queue_member_status_to_ami 
)

◆ store_next_lin()

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 5023 of file app_queue.c.

5024{
5025 struct callattempt *best = find_best(outgoing);
5026
5027 if (best) {
5028 /* Ring just the best channel */
5029 ast_debug(1, "Next is '%s' with metric %d\n", best->interface, best->metric);
5030 qe->linpos = best->metric % 1000;
5031 } else {
5032 /* Just increment rrpos */
5033 if (qe->linwrapped) {
5034 /* No more channels, start over */
5035 qe->linpos = 0;
5036 } else {
5037 /* Prioritize next entry */
5038 qe->linpos++;
5039 }
5040 }
5041 qe->linwrapped = 0;
5042
5043 return 0;
5044}

References ast_debug, find_best(), callattempt::interface, queue_ent::linpos, queue_ent::linwrapped, and callattempt::metric.

Referenced by try_calling().

◆ store_next_rr()

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 4999 of file app_queue.c.

5000{
5001 struct callattempt *best = find_best(outgoing);
5002
5003 if (best) {
5004 /* Ring just the best channel */
5005 ast_debug(1, "Next is '%s' with metric %d\n", best->interface, best->metric);
5006 qe->parent->rrpos = best->metric % 1000;
5007 } else {
5008 /* Just increment rrpos */
5009 if (qe->parent->wrapped) {
5010 /* No more channels, start over */
5011 qe->parent->rrpos = 0;
5012 } else {
5013 /* Prioritize next entry */
5014 qe->parent->rrpos++;
5015 }
5016 }
5017 qe->parent->wrapped = 0;
5018
5019 return 0;
5020}

References ast_debug, find_best(), callattempt::interface, callattempt::metric, queue_ent::parent, call_queue::rrpos, and call_queue::wrapped.

Referenced by try_calling().

◆ strat2int()

static int strat2int ( const char *  strategy)
static

Definition at line 1964 of file app_queue.c.

1965{
1966 int x;
1967
1968 for (x = 0; x < ARRAY_LEN(strategies); x++) {
1969 if (!strcasecmp(strategy, strategies[x].name)) {
1970 return strategies[x].strategy;
1971 }
1972 }
1973
1974 return -1;
1975}
int strategy
Definition: app_queue.c:1559

References ARRAY_LEN, name, strategies, and strategy::strategy.

Referenced by find_queue_by_name_rt(), queue_set_param(), and reload_single_queue().

◆ try_calling()

static int try_calling ( struct queue_ent qe,
struct ast_flags  opts,
char **  opt_args,
char *  announceoverride,
const char *  url,
int *  tries,
int *  noption,
const char *  agi,
const char *  gosub,
int  ringing 
)
static

Definition at line 7007 of file app_queue.c.

7008{
7009 struct member *cur;
7010 struct callattempt *outgoing = NULL; /* the list of calls we are building */
7011 int to, orig;
7012 char oldexten[AST_MAX_EXTENSION]="";
7013 char oldcontext[AST_MAX_CONTEXT]="";
7014 char queuename[256]="";
7015 struct ast_channel *peer;
7016 struct callattempt *lpeer;
7017 struct member *member;
7018 struct ast_app *application;
7019 int res = 0, bridge = 0;
7020 int numbusies = 0;
7021 int x=0;
7022 char *announce = NULL;
7023 char digit = 0;
7024 time_t now = time(NULL);
7025 struct ast_bridge_config bridge_config;
7026 char nondataquality = 1;
7027 char *agiexec = NULL;
7028 char *gosubexec = NULL;
7029 const char *monitorfilename;
7030 int forwardsallowed = 1;
7031 int block_connected_line = 0;
7032 struct ao2_iterator memi;
7034 int callcompletedinsl;
7035 time_t starttime;
7036
7037 memset(&bridge_config, 0, sizeof(bridge_config));
7038 time(&now);
7039
7040 /* If we've already exceeded our timeout, then just stop
7041 * This should be extremely rare. queue_exec will take care
7042 * of removing the caller and reporting the timeout as the reason.
7043 */
7044 if (qe->expire && now >= qe->expire) {
7045 res = 0;
7046 goto out;
7047 }
7048
7049 if (ast_test_flag(&opts, OPT_CALLEE_TRANSFER)) {
7050 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_REDIRECT);
7051 }
7052 if (ast_test_flag(&opts, OPT_CALLER_TRANSFER)) {
7053 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_REDIRECT);
7054 }
7055 if (ast_test_flag(&opts, OPT_CALLEE_AUTOMON)) {
7056 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_AUTOMON);
7057 }
7058 if (ast_test_flag(&opts, OPT_CALLER_AUTOMON)) {
7059 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_AUTOMON);
7060 }
7061 if (ast_test_flag(&opts, OPT_DATA_QUALITY)) {
7062 nondataquality = 0;
7063 }
7064 if (ast_test_flag(&opts, OPT_CALLEE_HANGUP)) {
7065 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_DISCONNECT);
7066 }
7067 if (ast_test_flag(&opts, OPT_CALLER_HANGUP)) {
7068 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT);
7069 }
7070 if (ast_test_flag(&opts, OPT_CALLEE_PARK)) {
7071 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_PARKCALL);
7072 }
7073 if (ast_test_flag(&opts, OPT_CALLER_PARK)) {
7074 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_PARKCALL);
7075 }
7076 if (ast_test_flag(&opts, OPT_NO_RETRY)) {
7079 (*tries)++;
7080 } else {
7081 *tries = ao2_container_count(qe->parent->members);
7082 }
7083 *noption = 1;
7084 }
7085 if (ast_test_flag(&opts, OPT_IGNORE_CALL_FW)) {
7086 forwardsallowed = 0;
7087 }
7089 block_connected_line = 1;
7090 }
7092 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_AUTOMIXMON);
7093 }
7095 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_AUTOMIXMON);
7096 }
7097 if (ast_test_flag(&opts, OPT_MARK_AS_ANSWERED)) {
7099 }
7100
7101 /* if the calling channel has AST_CAUSE_ANSWERED_ELSEWHERE set, make sure this is inherited.
7102 (this is mainly to support unreal/local channels)
7103 */
7106 }
7107
7108 ao2_lock(qe->parent);
7109 ast_debug(1, "%s is trying to call a queue member.\n",
7110 ast_channel_name(qe->chan));
7111 ast_copy_string(queuename, qe->parent->name, sizeof(queuename));
7112 if (!ast_strlen_zero(qe->announce)) {
7113 announce = qe->announce;
7114 }
7115 if (!ast_strlen_zero(announceoverride)) {
7116 announce = announceoverride;
7117 }
7118
7119 memi = ao2_iterator_init(qe->parent->members, 0);
7120 while ((cur = ao2_iterator_next(&memi))) {
7121 struct callattempt *tmp = ast_calloc(1, sizeof(*tmp));
7122 if (!tmp) {
7123 ao2_ref(cur, -1);
7124 ao2_iterator_destroy(&memi);
7125 ao2_unlock(qe->parent);
7126 goto out;
7127 }
7128
7129 /*
7130 * Seed the callattempt's connected line information with previously
7131 * acquired connected line info from the queued channel. The
7132 * previously acquired connected line info could have been set
7133 * through the CONNECTED_LINE dialplan function.
7134 */
7138
7139 tmp->block_connected_update = block_connected_line;
7140 tmp->stillgoing = 1;
7141 tmp->member = cur; /* Place the reference for cur into callattempt. */
7142 ast_copy_string(tmp->interface, cur->interface, sizeof(tmp->interface));
7143 /* Calculate the metric for the appropriate strategy. */
7144 if (!calc_metric(qe->parent, cur, x++, qe, tmp)) {
7145 /* Put them in the list of outgoing thingies... We're ready now.
7146 XXX If we're forcibly removed, these outgoing calls won't get
7147 hung up XXX */
7148 tmp->q_next = outgoing;
7149 outgoing = tmp;
7150 } else {
7152 }
7153 }
7154 ao2_iterator_destroy(&memi);
7155
7157 /* Application arguments have higher timeout priority (behaviour for <=1.6) */
7158 if (qe->expire && (!qe->parent->timeout || (qe->expire - now) <= qe->parent->timeout)) {
7159 to = (qe->expire - now) * 1000;
7160 } else {
7161 to = (qe->parent->timeout) ? qe->parent->timeout * 1000 : -1;
7162 }
7163 } else {
7164 /* Config timeout is higher priority thatn application timeout */
7165 if (qe->expire && qe->expire<=now) {
7166 to = 0;
7167 } else if (qe->parent->timeout) {
7168 to = qe->parent->timeout * 1000;
7169 } else {
7170 to = -1;
7171 }
7172 }
7173 orig = to;
7174 ++qe->pending;
7175 ao2_unlock(qe->parent);
7176 /* Call the queue members with the best metric now. */
7177 ring_one(qe, outgoing, &numbusies);
7178 lpeer = wait_for_answer(qe, outgoing, &to, &digit, numbusies,
7179 ast_test_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT),
7180 forwardsallowed);
7181
7182 ao2_lock(qe->parent);
7185
7186 }
7189 }
7190 ao2_unlock(qe->parent);
7191 peer = lpeer ? lpeer->chan : NULL;
7192 if (!peer) {
7193 qe->pending = 0;
7194 if (to) {
7195 /* Must gotten hung up */
7196 res = -1;
7197 } else {
7198 /* User exited by pressing a digit */
7199 res = digit;
7200 }
7201 if (res == -1) {
7202 ast_debug(1, "%s: Nobody answered.\n", ast_channel_name(qe->chan));
7203 }
7204 } else { /* peer is valid */
7205 RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
7206 RAII_VAR(struct ast_str *, interfacevar, ast_str_create(325), ast_free);
7207 /* Ah ha! Someone answered within the desired timeframe. Of course after this
7208 we will always return with -1 so that it is hung up properly after the
7209 conversation. */
7210 if (!strcmp(ast_channel_tech(qe->chan)->type, "DAHDI")) {
7211 ast_channel_setoption(qe->chan, AST_OPTION_TONE_VERIFY, &nondataquality, sizeof(nondataquality), 0);
7212 }
7213 if (!strcmp(ast_channel_tech(peer)->type, "DAHDI")) {
7214 ast_channel_setoption(peer, AST_OPTION_TONE_VERIFY, &nondataquality, sizeof(nondataquality), 0);
7215 }
7216 /* Update parameters for the queue */
7217 time(&now);
7218 recalc_holdtime(qe, (now - qe->start));
7219 member = lpeer->member;
7220 ao2_lock(qe->parent);
7221 callcompletedinsl = member->callcompletedinsl = ((now - qe->start) <= qe->parent->servicelevel);
7222 ao2_unlock(qe->parent);
7223 /* Increment the refcount for this member, since we're going to be using it for awhile in here. */
7224 ao2_ref(member, 1);
7226 outgoing = NULL;
7227 if (announce || qe->parent->reportholdtime || qe->parent->memberdelay) {
7228 int res2;
7229
7230 res2 = ast_autoservice_start(qe->chan);
7231 if (!res2) {
7232 if (qe->parent->memberdelay) {
7233 ast_log(LOG_NOTICE, "Delaying member connect for %d seconds\n", qe->parent->memberdelay);
7234 res2 = ast_safe_sleep(peer, qe->parent->memberdelay * 1000);
7235 }
7236 if (!res2 && announce) {
7237 char *front;
7238 char *announcefiles = ast_strdupa(announce);
7239 while ((front = ast_strsep(&announcefiles, '&', AST_STRSEP_STRIP | AST_STRSEP_TRIM))) {
7240 if (play_file(peer, front) < 0) {
7241 ast_log(LOG_ERROR, "play_file failed for '%s' on %s\n", front, ast_channel_name(peer));
7242 }
7243 }
7244 }
7245 if (!res2 && qe->parent->reportholdtime) {
7246 if (!play_file(peer, qe->parent->sound_reporthold)) {
7247 long holdtime, holdtimesecs;
7248
7249 time(&now);
7250 holdtime = labs((now - qe->start) / 60);
7251 holdtimesecs = labs((now - qe->start) % 60);
7252 if (holdtime > 0) {
7253 ast_say_number(peer, holdtime, AST_DIGIT_ANY, ast_channel_language(peer), "n");
7254 if (play_file(peer, qe->parent->sound_minutes) < 0) {
7255 ast_log(LOG_ERROR, "play_file failed for '%s' on %s\n", qe->parent->sound_minutes, ast_channel_name(peer));
7256 }
7257 }
7258 if (holdtimesecs > 1) {
7259 ast_say_number(peer, holdtimesecs, AST_DIGIT_ANY, ast_channel_language(peer), "n");
7260 if (play_file(peer, qe->parent->sound_seconds) < 0) {
7261 ast_log(LOG_ERROR, "play_file failed for '%s' on %s\n", qe->parent->sound_seconds, ast_channel_name(peer));
7262 }
7263 }
7264 }
7265 }
7267 }
7268 if (ast_check_hangup(peer)) {
7269 /* Agent must have hung up */
7270 ast_log(LOG_WARNING, "Agent on %s hungup on the customer.\n", ast_channel_name(peer));
7271 ast_queue_log(queuename, ast_channel_uniqueid(qe->chan), member->membername, "AGENTDUMP", "%s", "");
7272
7273 blob = ast_json_pack("{s: s, s: s, s: s}",
7274 "Queue", queuename,
7275 "Interface", member->interface,
7276 "MemberName", member->membername);
7277 queue_publish_multi_channel_blob(qe->chan, peer, queue_agent_dump_type(), blob);
7278
7282 ao2_ref(member, -1);
7283 goto out;
7284 } else if (ast_check_hangup(qe->chan)) {
7285 /* Caller must have hung up just before being connected */
7286 ast_log(LOG_NOTICE, "Caller was about to talk to agent on %s but the caller hungup.\n", ast_channel_name(peer));
7287 ast_queue_log(queuename, ast_channel_uniqueid(qe->chan), member->membername, "ABANDON", "%d|%d|%ld", qe->pos, qe->opos, (long) (time(NULL) - qe->start));
7288 record_abandoned(qe);
7289 qe->handled = -1;
7293 ao2_ref(member, -1);
7294 return -1;
7295 }
7296 }
7297 /* Stop music on hold */
7298 if (ringing) {
7299 ast_indicate(qe->chan,-1);
7300 } else {
7301 ast_moh_stop(qe->chan);
7302 }
7303
7304 /* Make sure channels are compatible */
7305 res = ast_channel_make_compatible(qe->chan, peer);
7306 if (res < 0) {
7307 ast_queue_log(queuename, ast_channel_uniqueid(qe->chan), member->membername, "SYSCOMPAT", "%s", "");
7308 ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", ast_channel_name(qe->chan), ast_channel_name(peer));
7309 record_abandoned(qe);
7313 ao2_ref(member, -1);
7314 return -1;
7315 }
7316
7317 /* Play announcement to the caller telling it's his turn if defined */
7319 if (play_file(qe->chan, qe->parent->sound_callerannounce)) {
7320 ast_log(LOG_WARNING, "Announcement file '%s' is unavailable, continuing anyway...\n", qe->parent->sound_callerannounce);
7321 }
7322 }
7323
7324 ao2_lock(qe->parent);
7325 /* if setinterfacevar is defined, make member variables available to the channel */
7326 /* use pbx_builtin_setvar to set a load of variables with one call */
7327 if (qe->parent->setinterfacevar && interfacevar) {
7328 ast_str_set(&interfacevar, 0, "MEMBERINTERFACE=%s,MEMBERNAME=%s,MEMBERCALLS=%d,MEMBERLASTCALL=%ld,MEMBERPENALTY=%d,MEMBERDYNAMIC=%d,MEMBERREALTIME=%d",
7331 pbx_builtin_setvar_multiple(peer, ast_str_buffer(interfacevar));
7332 }
7333
7334 /* if setqueueentryvar is defined, make queue entry (i.e. the caller) variables available to the channel */
7335 /* use pbx_builtin_setvar to set a load of variables with one call */
7336 if (qe->parent->setqueueentryvar && interfacevar) {
7337 ast_str_set(&interfacevar, 0, "QEHOLDTIME=%ld,QEORIGINALPOS=%d",
7338 (long) (time(NULL) - qe->start), qe->opos);
7340 pbx_builtin_setvar_multiple(peer, ast_str_buffer(interfacevar));
7341 }
7342
7343 ao2_unlock(qe->parent);
7344
7345 /* try to set queue variables if configured to do so*/
7347 set_queue_variables(qe->parent, peer);
7348
7349 setup_peer_after_bridge_goto(qe->chan, peer, &opts, opt_args);
7351 if ((monitorfilename = pbx_builtin_getvar_helper(qe->chan, "MONITOR_FILENAME"))) {
7352 monitorfilename = ast_strdupa(monitorfilename);
7353 }
7355
7356 /* Begin Monitoring */
7357 if (*qe->parent->monfmt) {
7358 setup_mixmonitor(qe, monitorfilename);
7359 }
7360 /* Drop out of the queue at this point, to prepare for next caller */
7361 leave_queue(qe);
7363 ast_debug(1, "app_queue: sendurl=%s.\n", url);
7364 ast_channel_sendurl(peer, url);
7365 }
7366
7367 /* run a gosub for this connection if defined. The gosub simply returns, no action is taken on the result */
7368 /* use gosub from dialplan if passed as a option, otherwise use the default queue gosub */
7369 if (!ast_strlen_zero(gosub)) {
7370 gosubexec = ast_strdupa(gosub);
7371 } else {
7372 if (qe->parent->membergosub) {
7373 gosubexec = ast_strdupa(qe->parent->membergosub);
7374 }
7375 }
7376
7377 if (!ast_strlen_zero(gosubexec)) {
7378 char *gosub_args = NULL;
7379 char *gosub_argstart;
7380
7381 ast_debug(1, "app_queue: gosub=%s.\n", gosubexec);
7382
7383 gosub_argstart = strchr(gosubexec, ',');
7384 if (gosub_argstart) {
7385 const char *what_is_s = "s";
7386 *gosub_argstart = 0;
7387 if (!ast_exists_extension(peer, gosubexec, "s", 1, S_COR(ast_channel_caller(peer)->id.number.valid, ast_channel_caller(peer)->id.number.str, NULL)) &&
7388 ast_exists_extension(peer, gosubexec, "~~s~~", 1, S_COR(ast_channel_caller(peer)->id.number.valid, ast_channel_caller(peer)->id.number.str, NULL))) {
7389 what_is_s = "~~s~~";
7390 }
7391 if (ast_asprintf(&gosub_args, "%s,%s,1(%s)", gosubexec, what_is_s, gosub_argstart + 1) < 0) {
7392 gosub_args = NULL;
7393 }
7394 *gosub_argstart = ',';
7395 } else {
7396 const char *what_is_s = "s";
7397 if (!ast_exists_extension(peer, gosubexec, "s", 1, S_COR(ast_channel_caller(peer)->id.number.valid, ast_channel_caller(peer)->id.number.str, NULL)) &&
7398 ast_exists_extension(peer, gosubexec, "~~s~~", 1, S_COR(ast_channel_caller(peer)->id.number.valid, ast_channel_caller(peer)->id.number.str, NULL))) {
7399 what_is_s = "~~s~~";
7400 }
7401 if (ast_asprintf(&gosub_args, "%s,%s,1", gosubexec, what_is_s) < 0) {
7402 gosub_args = NULL;
7403 }
7404 }
7405 if (gosub_args) {
7406 ast_app_exec_sub(qe->chan, peer, gosub_args, 0);
7407 ast_free(gosub_args);
7408 } else {
7409 ast_log(LOG_ERROR, "Could not Allocate string for Gosub arguments -- Gosub Call Aborted!\n");
7410 }
7411 }
7412
7413 if (!ast_strlen_zero(agi)) {
7414 ast_debug(1, "app_queue: agi=%s.\n", agi);
7415 application = pbx_findapp("agi");
7416 if (application) {
7417 agiexec = ast_strdupa(agi);
7418 pbx_exec(qe->chan, application, agiexec);
7419 } else {
7420 ast_log(LOG_WARNING, "Asked to execute an AGI on this channel, but could not find application (agi)!\n");
7421 }
7422 }
7423 qe->handled++;
7424
7425 ast_queue_log(queuename, ast_channel_uniqueid(qe->chan), member->membername, "CONNECT", "%ld|%s|%ld", (long) (time(NULL) - qe->start), ast_channel_uniqueid(peer),
7426 (long)(orig - to > 0 ? (orig - to) / 1000 : 0));
7427
7428 blob = ast_json_pack("{s: s, s: s, s: s, s: I, s: I}",
7429 "Queue", queuename,
7430 "Interface", member->interface,
7431 "MemberName", member->membername,
7432 "HoldTime", (ast_json_int_t)(time(NULL) - qe->start),
7433 "RingTime", (ast_json_int_t)(orig - to > 0 ? (orig - to) / 1000 : 0));
7434 queue_publish_multi_channel_blob(qe->chan, peer, queue_agent_connect_type(), blob);
7435
7436 ast_copy_string(oldcontext, ast_channel_context(qe->chan), sizeof(oldcontext));
7437 ast_copy_string(oldexten, ast_channel_exten(qe->chan), sizeof(oldexten));
7438
7439 if ((queue_end_bridge = ao2_alloc(sizeof(*queue_end_bridge), NULL))) {
7440 queue_end_bridge->q = qe->parent;
7441 queue_end_bridge->chan = qe->chan;
7442 bridge_config.end_bridge_callback = end_bridge_callback;
7443 bridge_config.end_bridge_callback_data = queue_end_bridge;
7444 bridge_config.end_bridge_callback_data_fixup = end_bridge_callback_data_fixup;
7445 /* Since queue_end_bridge can survive beyond the life of this call to Queue, we need
7446 * to make sure to increase the refcount of this queue so it cannot be freed until we
7447 * are done with it. We remove this reference in end_bridge_callback.
7448 */
7449 queue_t_ref(qe->parent, "For bridge_config reference");
7450 }
7451
7452 ao2_lock(qe->parent);
7453 time(&member->starttime);
7454 starttime = member->starttime;
7455 ao2_unlock(qe->parent);
7456 /* As a queue member may end up in multiple calls at once if a transfer occurs with
7457 * a Local channel in the mix we pass the current call information (starttime) to the
7458 * Stasis subscriptions so when they update the queue member data it becomes a noop
7459 * if this call is no longer between the caller and the queue member.
7460 */
7461 setup_stasis_subs(qe, peer, member, qe->start, starttime, callcompletedinsl);
7462 bridge = ast_bridge_call_with_flags(qe->chan, peer, &bridge_config,
7464
7465 res = bridge ? bridge : 1;
7466 ao2_ref(member, -1);
7467 }
7468out:
7470
7471 return res;
7472}
char digit
static int setup_stasis_subs(struct queue_ent *qe, struct ast_channel *peer, struct member *mem, time_t holdstart, time_t starttime, int callcompletedinsl)
Definition: app_queue.c:6802
static void setup_mixmonitor(struct queue_ent *qe, const char *filename)
Definition: app_queue.c:6934
static void recalc_holdtime(struct queue_ent *qe, int newholdtime)
Definition: app_queue.c:4378
static void hangupcalls(struct queue_ent *qe, struct callattempt *outgoing, struct ast_channel *exception, int cancel_answered_elsewhere)
Hang up a list of outgoing calls.
Definition: app_queue.c:4498
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.
Definition: app_queue.c:6073
static int store_next_lin(struct queue_ent *qe, struct callattempt *outgoing)
Search for best metric and add to Linear queue.
Definition: app_queue.c:5023
static struct callattempt * wait_for_answer(struct queue_ent *qe, struct callattempt *outgoing, int *to, char *digit, int prebusies, int caller_disconnect, int forwardsallowed)
Wait for a member to answer the call.
Definition: app_queue.c:5234
static int store_next_rr(struct queue_ent *qe, struct callattempt *outgoing)
Search for best metric and add to Round Robbin queue.
Definition: app_queue.c:4999
static void end_bridge_callback(void *data)
Definition: app_queue.c:6863
static void end_bridge_callback_data_fixup(struct ast_bridge_config *bconfig, struct ast_channel *originator, struct ast_channel *terminator)
Definition: app_queue.c:6856
static void setup_peer_after_bridge_goto(struct ast_channel *chan, struct ast_channel *peer, struct ast_flags *opts, char *opt_args[])
Definition: app_queue.c:6886
static int ring_one(struct queue_ent *qe, struct callattempt *outgoing, int *busies)
Place a call to a queue member.
Definition: app_queue.c:4939
#define ast_asprintf(ret, fmt,...)
A wrapper for asprintf()
Definition: astmm.h:267
@ AST_BRIDGE_FLAG_SWAP_INHIBIT_FROM
@ AST_BRIDGE_FLAG_MERGE_INHIBIT_TO
@ AST_BRIDGE_FLAG_MERGE_INHIBIT_FROM
int ast_channel_make_compatible(struct ast_channel *chan, struct ast_channel *peer)
Make the frame formats of two channels compatible.
Definition: channel.c:6739
@ AST_FEATURE_AUTOMIXMON
Definition: channel.h:1089
@ AST_FEATURE_REDIRECT
Definition: channel.h:1084
@ AST_FEATURE_PARKCALL
Definition: channel.h:1088
@ AST_FEATURE_AUTOMON
Definition: channel.h:1087
@ AST_FEATURE_DISCONNECT
Definition: channel.h:1085
void ast_party_connected_line_copy(struct ast_party_connected_line *dest, const struct ast_party_connected_line *src)
Copy the source connected line information to the destination connected line.
Definition: channel.c:2050
int ast_channel_supports_html(struct ast_channel *channel)
Checks for HTML support on a channel.
Definition: channel.c:6642
int ast_check_hangup(struct ast_channel *chan)
Check to see if a channel is needing hang up.
Definition: channel.c:445
int ast_channel_hangupcause(const struct ast_channel *chan)
#define AST_MAX_CONTEXT
Definition: channel.h:135
int ast_channel_sendurl(struct ast_channel *channel, const char *url)
Sends a URL on a given link Send URL on link.
Definition: channel.c:6654
const struct ast_channel_tech * ast_channel_tech(const struct ast_channel *chan)
int ast_channel_setoption(struct ast_channel *channel, int option, void *data, int datalen, int block)
Sets an option on a channel.
Definition: channel.c:7444
void ast_autoservice_chan_hangup_peer(struct ast_channel *chan, struct ast_channel *peer)
Put chan into autoservice while hanging up peer.
Definition: autoservice.c:349
int ast_safe_sleep(struct ast_channel *chan, int ms)
Wait for a specified amount of time, looking for hangups.
Definition: channel.c:1593
#define AST_MAX_EXTENSION
Definition: channel.h:134
const char * ast_hangup_cause_to_dial_status(int hangup_cause)
Convert a hangup cause to a publishable dial status.
Definition: dial.c:749
int ast_bridge_call_with_flags(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, unsigned int flags)
Bridge a call, and add additional flags to the bridge.
Definition: features.c:595
#define AST_OPTION_TONE_VERIFY
int ast_exists_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
Determine whether an extension exists.
Definition: pbx.c:4175
int pbx_exec(struct ast_channel *c, struct ast_app *app, const char *data)
Execute an application.
Definition: pbx_app.c:471
struct ast_app * pbx_findapp(const char *app)
Look up an application.
Definition: ael_main.c:165
@ AST_STRSEP_TRIM
Definition: strings.h:256
@ AST_STRSEP_STRIP
Definition: strings.h:255
char * ast_strsep(char **s, const char sep, uint32_t flags)
Act like strsep but ignore separators inside quotes.
Definition: utils.c:1835
ast_app: A registered application
Definition: pbx_app.c:45
bridge configuration
Definition: channel.h:1096
const char *const type
Definition: channel.h:649
const ast_string_field sound_callerannounce
Definition: app_queue.c:1858
const ast_string_field sound_reporthold
Definition: app_queue.c:1858
const ast_string_field membergosub
Definition: app_queue.c:1858

References queue_ent::announce, ao2_alloc, ao2_container_count(), ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_lock, ao2_ref, ao2_unlock, ast_app_exec_sub(), ast_asprintf, ast_autoservice_chan_hangup_peer(), ast_autoservice_start(), ast_autoservice_stop(), ast_bridge_call_with_flags(), AST_BRIDGE_FLAG_MERGE_INHIBIT_FROM, AST_BRIDGE_FLAG_MERGE_INHIBIT_TO, AST_BRIDGE_FLAG_SWAP_INHIBIT_FROM, ast_calloc, AST_CAUSE_ANSWERED_ELSEWHERE, ast_channel_caller(), ast_channel_connected(), ast_channel_context(), ast_channel_exten(), ast_channel_hangupcause(), ast_channel_language(), ast_channel_lock, ast_channel_make_compatible(), ast_channel_name(), ast_channel_publish_dial(), ast_channel_sendurl(), ast_channel_setoption(), ast_channel_supports_html(), ast_channel_tech(), ast_channel_uniqueid(), ast_channel_unlock, ast_check_hangup(), ast_copy_string(), ast_debug, AST_DIGIT_ANY, ast_exists_extension(), AST_FEATURE_AUTOMIXMON, AST_FEATURE_AUTOMON, AST_FEATURE_DISCONNECT, AST_FEATURE_PARKCALL, AST_FEATURE_REDIRECT, ast_free, ast_hangup_cause_to_dial_status(), ast_indicate(), ast_json_pack(), ast_json_unref(), ast_log, AST_MAX_CONTEXT, AST_MAX_EXTENSION, ast_moh_stop(), AST_OPTION_TONE_VERIFY, ast_party_connected_line_copy(), ast_queue_log(), ast_safe_sleep(), ast_say_number(), ast_set_flag, ast_str_buffer(), ast_str_create, ast_str_set(), ast_strdupa, ast_strlen_zero(), ast_strsep(), AST_STRSEP_STRIP, AST_STRSEP_TRIM, ast_test_flag, calc_metric(), callattempt_free(), member::callcompletedinsl, member::calls, queue_ent::cancel_answered_elsewhere, callattempt::chan, queue_ent::chan, queue_end_bridge::chan, digit, member::dynamic, end_bridge_callback(), ast_bridge_config::end_bridge_callback, ast_bridge_config::end_bridge_callback_data, end_bridge_callback_data_fixup(), ast_bridge_config::end_bridge_callback_data_fixup, queue_ent::expire, ast_bridge_config::features_callee, ast_bridge_config::features_caller, queue_ent::handled, hangupcalls(), member::interface, member::lastcall, leave_queue(), LOG_ERROR, LOG_NOTICE, LOG_WARNING, callattempt::member, call_queue::memberdelay, call_queue::membergosub, member::membername, call_queue::members, call_queue::monfmt, call_queue::name, NULL, queue_ent::opos, OPT_CALLEE_AUTOMIXMON, OPT_CALLEE_AUTOMON, OPT_CALLEE_HANGUP, OPT_CALLEE_PARK, OPT_CALLEE_TRANSFER, OPT_CALLER_AUTOMIXMON, OPT_CALLER_AUTOMON, OPT_CALLER_HANGUP, OPT_CALLER_PARK, OPT_CALLER_TRANSFER, OPT_DATA_QUALITY, OPT_IGNORE_CALL_FW, OPT_IGNORE_CONNECTEDLINE, OPT_MARK_AS_ANSWERED, OPT_NO_RETRY, out, queue_ent::parent, pbx_builtin_getvar_helper(), pbx_builtin_setvar_multiple(), pbx_exec(), pbx_findapp(), member::penalty, queue_ent::pending, pending_members_remove(), play_file(), queue_ent::pos, queue_end_bridge::q, queue_publish_multi_channel_blob(), QUEUE_STRATEGY_LINEAR, QUEUE_STRATEGY_RRMEMORY, QUEUE_STRATEGY_RRORDERED, queue_t_ref, RAII_VAR, member::realtime, recalc_holdtime(), record_abandoned(), call_queue::reportholdtime, ring_one(), ringing(), S_COR, call_queue::servicelevel, set_queue_variables(), call_queue::setinterfacevar, call_queue::setqueueentryvar, setup_mixmonitor(), setup_peer_after_bridge_goto(), setup_stasis_subs(), call_queue::sound_callerannounce, call_queue::sound_minutes, call_queue::sound_reporthold, call_queue::sound_seconds, queue_ent::start, member::starttime, store_next_lin(), store_next_rr(), call_queue::strategy, call_queue::timeout, TIMEOUT_PRIORITY_APP, call_queue::timeoutpriority, tmp(), type, ast_channel_tech::type, url, and wait_for_answer().

Referenced by queue_exec().

◆ unload_module()

static int unload_module ( void  )
static

Definition at line 11755 of file app_queue.c.

11756{
11759
11761
11762 STASIS_MESSAGE_TYPE_CLEANUP(queue_caller_join_type);
11763 STASIS_MESSAGE_TYPE_CLEANUP(queue_caller_leave_type);
11764 STASIS_MESSAGE_TYPE_CLEANUP(queue_caller_abandon_type);
11765
11766 STASIS_MESSAGE_TYPE_CLEANUP(queue_member_status_type);
11767 STASIS_MESSAGE_TYPE_CLEANUP(queue_member_added_type);
11768 STASIS_MESSAGE_TYPE_CLEANUP(queue_member_removed_type);
11769 STASIS_MESSAGE_TYPE_CLEANUP(queue_member_pause_type);
11770 STASIS_MESSAGE_TYPE_CLEANUP(queue_member_penalty_type);
11771 STASIS_MESSAGE_TYPE_CLEANUP(queue_member_ringinuse_type);
11772
11773 STASIS_MESSAGE_TYPE_CLEANUP(queue_agent_called_type);
11774 STASIS_MESSAGE_TYPE_CLEANUP(queue_agent_connect_type);
11775 STASIS_MESSAGE_TYPE_CLEANUP(queue_agent_complete_type);
11776 STASIS_MESSAGE_TYPE_CLEANUP(queue_agent_dump_type);
11777 STASIS_MESSAGE_TYPE_CLEANUP(queue_agent_ringnoanswer_type);
11778
11780 ast_manager_unregister("QueueStatus");
11781 ast_manager_unregister("QueueRule");
11782 ast_manager_unregister("QueueSummary");
11783 ast_manager_unregister("QueueAdd");
11784 ast_manager_unregister("QueueRemove");
11785 ast_manager_unregister("QueuePause");
11786 ast_manager_unregister("QueueLog");
11787 ast_manager_unregister("QueueUpdate");
11788 ast_manager_unregister("QueuePenalty");
11789 ast_manager_unregister("QueueReload");
11790 ast_manager_unregister("QueueReset");
11791 ast_manager_unregister("QueueMemberRingInUse");
11792 ast_manager_unregister("QueueChangePriorityCaller");
11793 ast_manager_unregister("QueueWithdrawCaller");
11809
11811
11812 ast_unload_realtime("queue_members");
11815
11816 queues = NULL;
11817 return 0;
11818}
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
Definition: clicompat.c:30
int ast_manager_unregister(const char *action)
Unregister a registered manager command.
Definition: manager.c:7608
int ast_unregister_application(const char *app)
Unregister an application.
Definition: pbx_app.c:392
int ast_custom_function_unregister(struct ast_custom_function *acf)
Unregister a custom function.
#define STASIS_MESSAGE_TYPE_CLEANUP(name)
Boiler-plate messaging macro for cleaning up message types.
Definition: stasis.h:1515
struct stasis_forward * stasis_forward_cancel(struct stasis_forward *forward)
Definition: stasis.c:1549
struct stasis_subscription * stasis_unsubscribe_and_join(struct stasis_subscription *subscription)
Cancel a subscription, blocking until the last message is processed.
Definition: stasis.c:1135
void stasis_message_router_unsubscribe_and_join(struct stasis_message_router *router)
Unsubscribe the router from the upstream topic, blocking until the final message has been processed.

References agent_router, ao2_cleanup, app, app_aqm, app_pqm, app_ql, app_qupd, app_rqm, app_upqm, ARRAY_LEN, ast_cli_unregister_multiple(), ast_custom_function_unregister(), ast_manager_unregister(), ast_unload_realtime(), ast_unregister_application(), cli_queue, device_state_sub, NULL, pending_members, queueexists_function, queuegetchannel_function, queuemembercount_dep, queuemembercount_function, queuememberlist_function, queuememberpenalty_function, queues, queuevar_function, queuewaitingcount_function, stasis_forward_cancel(), stasis_message_router_unsubscribe_and_join(), STASIS_MESSAGE_TYPE_CLEANUP, stasis_unsubscribe_and_join(), and topic_forwarder.

Referenced by load_module().

◆ update_connected_line_from_peer()

static void update_connected_line_from_peer ( struct ast_channel chan,
struct ast_channel peer,
int  is_caller 
)
static

Definition at line 5204 of file app_queue.c.

5205{
5206 struct ast_party_connected_line connected_caller;
5207
5208 ast_party_connected_line_init(&connected_caller);
5209
5210 ast_channel_lock(peer);
5212 ast_channel_unlock(peer);
5213 connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
5214 if (ast_channel_connected_line_sub(peer, chan, &connected_caller, 0)) {
5215 ast_channel_update_connected_line(chan, &connected_caller, NULL);
5216 }
5217 ast_party_connected_line_free(&connected_caller);
5218}
@ AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER
Definition: callerid.h:554
int ast_channel_connected_line_sub(struct ast_channel *autoservice_chan, struct ast_channel *sub_chan, const void *connected_info, int frame)
Run a connected line interception subroutine and update a channel's connected line information.
Definition: channel.c:10360
void ast_channel_update_connected_line(struct ast_channel *chan, const struct ast_party_connected_line *connected, const struct ast_set_party_connected_line *update)
Indicate that the connected line information has changed.
Definition: channel.c:9115
void ast_party_connected_line_init(struct ast_party_connected_line *init)
Initialize the given connected line structure.
Definition: channel.c:2041
Connected Line/Party information.
Definition: channel.h:458

References ast_channel_caller(), ast_channel_connected_line_sub(), ast_channel_lock, ast_channel_unlock, ast_channel_update_connected_line(), ast_connected_line_copy_from_caller(), AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER, ast_party_connected_line_free(), ast_party_connected_line_init(), NULL, and ast_party_connected_line::source.

Referenced by wait_for_answer().

◆ update_qe_rule()

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 5823 of file app_queue.c.

5824{
5825 int max_penalty = INT_MAX;
5826
5827 if (qe->max_penalty != INT_MAX) {
5828 char max_penalty_str[20];
5829
5830 if (qe->pr->max_relative) {
5831 max_penalty = qe->max_penalty + qe->pr->max_value;
5832 } else {
5833 max_penalty = qe->pr->max_value;
5834 }
5835
5836 /* a relative change to the penalty could put it below 0 */
5837 if (max_penalty < 0) {
5838 max_penalty = 0;
5839 }
5840
5841 snprintf(max_penalty_str, sizeof(max_penalty_str), "%d", max_penalty);
5842 pbx_builtin_setvar_helper(qe->chan, "QUEUE_MAX_PENALTY", max_penalty_str);
5843 qe->max_penalty = max_penalty;
5844 ast_debug(3, "Setting max penalty to %d for caller %s since %d seconds have elapsed\n",
5845 qe->max_penalty, ast_channel_name(qe->chan), qe->pr->time);
5846 }
5847
5848 if (qe->min_penalty != INT_MAX) {
5849 char min_penalty_str[20];
5850 int min_penalty;
5851
5852 if (qe->pr->min_relative) {
5853 min_penalty = qe->min_penalty + qe->pr->min_value;
5854 } else {
5855 min_penalty = qe->pr->min_value;
5856 }
5857
5858 /* a relative change to the penalty could put it below 0 */
5859 if (min_penalty < 0) {
5860 min_penalty = 0;
5861 }
5862
5863 if (max_penalty != INT_MAX && min_penalty > max_penalty) {
5864 min_penalty = max_penalty;
5865 }
5866
5867 snprintf(min_penalty_str, sizeof(min_penalty_str), "%d", min_penalty);
5868 pbx_builtin_setvar_helper(qe->chan, "QUEUE_MIN_PENALTY", min_penalty_str);
5869 qe->min_penalty = min_penalty;
5870 ast_debug(3, "Setting min penalty to %d for caller %s since %d seconds have elapsed\n",
5871 qe->min_penalty, ast_channel_name(qe->chan), qe->pr->time);
5872 }
5873
5874 if (qe->raise_penalty != INT_MAX) {
5875 char raise_penalty_str[20];
5876 int raise_penalty;
5877
5878 if (qe->pr->raise_relative) {
5879 raise_penalty = qe->raise_penalty + qe->pr->raise_value;
5880 } else {
5881 raise_penalty = qe->pr->raise_value;
5882 }
5883
5884 /* a relative change to the penalty could put it below 0 */
5885 if (raise_penalty < 0) {
5886 raise_penalty = 0;
5887 }
5888
5889 if (max_penalty != INT_MAX && raise_penalty > max_penalty) {
5890 raise_penalty = max_penalty;
5891 }
5892
5893 snprintf(raise_penalty_str, sizeof(raise_penalty_str), "%d", raise_penalty);
5894 pbx_builtin_setvar_helper(qe->chan, "QUEUE_RAISE_PENALTY", raise_penalty_str);
5895 qe->raise_penalty = raise_penalty;
5896 ast_debug(3, "Setting raised penalty to %d for caller %s since %d seconds have elapsed\n",
5897 qe->raise_penalty, ast_channel_name(qe->chan), qe->pr->time);
5898 }
5899
5900 qe->pr = AST_LIST_NEXT(qe->pr, list);
5901}
#define AST_LIST_NEXT(elm, field)
Returns the next entry in the list after the given entry.
Definition: linkedlists.h:439

References ast_channel_name(), 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, pbx_builtin_setvar_helper(), queue_ent::pr, queue_ent::raise_penalty, penalty_rule::raise_relative, penalty_rule::raise_value, and penalty_rule::time.

Referenced by queue_exec(), and wait_our_turn().

◆ update_queue()

static int update_queue ( struct call_queue q,
struct member member,
int  callcompletedinsl,
time_t  starttime 
)
static

update the queue status

Return values
0always

Definition at line 6001 of file app_queue.c.

6002{
6003 int oldtalktime;
6004 int newtalktime = time(NULL) - starttime;
6005 struct member *mem;
6006 struct call_queue *qtmp;
6007 struct ao2_iterator queue_iter;
6008
6009 /* It is possible for us to be called when a call has already been considered terminated
6010 * and data updated, so to ensure we only act on the call that the agent is currently in
6011 * we check when the call was bridged.
6012 */
6013 if (!starttime || (member->starttime != starttime)) {
6014 return 0;
6015 }
6016
6017 if (shared_lastcall) {
6018 queue_iter = ao2_iterator_init(queues, 0);
6019 while ((qtmp = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
6020 ao2_lock(qtmp);
6021 if ((mem = ao2_find(qtmp->members, member, OBJ_POINTER))) {
6022 time(&mem->lastcall);
6023 mem->calls++;
6024 mem->callcompletedinsl = 0;
6025 mem->starttime = 0;
6026 mem->lastqueue = q;
6027 ao2_ref(mem, -1);
6028 }
6029 ao2_unlock(qtmp);
6030 queue_t_unref(qtmp, "Done with iterator");
6031 }
6032 ao2_iterator_destroy(&queue_iter);
6033 } else {
6034 ao2_lock(q);
6035 time(&member->lastcall);
6037 member->calls++;
6038 member->starttime = 0;
6039 member->lastqueue = q;
6040 ao2_unlock(q);
6041 }
6042 /* Member might never experience any direct status change (local
6043 * channel with forwarding in particular). If that's the case,
6044 * this is the last chance to remove it from pending or subsequent
6045 * calls will not occur.
6046 */
6048
6049 ao2_lock(q);
6050 q->callscompleted++;
6051 if (callcompletedinsl) {
6052 q->callscompletedinsl++;
6053 }
6054 if (q->callscompleted == 1) {
6055 q->talktime = newtalktime;
6056 } else {
6057 /* Calculate talktime using the same exponential average as holdtime code */
6058 oldtalktime = q->talktime;
6059 q->talktime = (((oldtalktime << 2) - oldtalktime) + newtalktime) >> 2;
6060 }
6061 ao2_unlock(q);
6062 return 0;
6063}

References ao2_find, ao2_iterator_destroy(), ao2_iterator_init(), ao2_lock, ao2_ref, ao2_t_iterator_next, ao2_unlock, member::callcompletedinsl, member::calls, call_queue::callscompleted, call_queue::callscompletedinsl, member::lastcall, member::lastqueue, call_queue::members, NULL, OBJ_POINTER, pending_members_remove(), queue_t_unref, queues, shared_lastcall, member::starttime, and call_queue::talktime.

Referenced by handle_attended_transfer(), handle_blind_transfer(), handle_hangup(), and update_status().

◆ update_realtime_member_field()

static int update_realtime_member_field ( struct member mem,
const char *  queue_name,
const char *  field,
const char *  value 
)
static

Definition at line 4013 of file app_queue.c.

4014{
4015 int ret = -1;
4016
4017 if (ast_strlen_zero(mem->rt_uniqueid)) {
4018 return ret;
4019 }
4020
4021 if ((ast_update_realtime("queue_members", "uniqueid", mem->rt_uniqueid, field, value, SENTINEL)) >= 0) {
4022 ret = 0;
4023 }
4024
4025 return ret;
4026}

References ast_strlen_zero(), ast_update_realtime(), member::rt_uniqueid, SENTINEL, and value.

Referenced by remove_from_queue(), set_member_penalty_help_members(), and set_queue_member_ringinuse().

◆ update_realtime_members()

static void update_realtime_members ( struct call_queue q)
static

Definition at line 4029 of file app_queue.c.

4030{
4031 struct ast_config *member_config = NULL;
4032 struct member *m;
4033 char *category = NULL;
4034 struct ao2_iterator mem_iter;
4035
4036 if (!(member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name", q->name , SENTINEL))) {
4037 /* This queue doesn't have realtime members. If the queue still has any realtime
4038 * members in memory, they need to be removed.
4039 */
4040 ao2_lock(q);
4041 mem_iter = ao2_iterator_init(q->members, 0);
4042 while ((m = ao2_iterator_next(&mem_iter))) {
4043 if (m->realtime) {
4045 }
4046 ao2_ref(m, -1);
4047 }
4048 ao2_iterator_destroy(&mem_iter);
4049 ast_debug(3, "Queue %s has no realtime members defined. No need for update\n", q->name);
4050 ao2_unlock(q);
4051 return;
4052 }
4053
4054 ao2_lock(q);
4055
4056 /* Temporarily set realtime members dead so we can detect deleted ones.*/
4057 mem_iter = ao2_iterator_init(q->members, 0);
4058 while ((m = ao2_iterator_next(&mem_iter))) {
4059 if (m->realtime) {
4060 m->dead = 1;
4061 }
4062 ao2_ref(m, -1);
4063 }
4064 ao2_iterator_destroy(&mem_iter);
4065
4066 while ((category = ast_category_browse(member_config, category))) {
4067 rt_handle_member_record(q, category, member_config);
4068 }
4069
4070 /* Delete all realtime members that have been deleted in DB. */
4071 mem_iter = ao2_iterator_init(q->members, 0);
4072 while ((m = ao2_iterator_next(&mem_iter))) {
4073 if (m->dead) {
4075 ast_queue_log(q->name, "REALTIME", m->interface, "REMOVEMEMBER", "%s", "");
4076 } else {
4077 ast_queue_log(q->name, "REALTIME", m->membername, "REMOVEMEMBER", "%s", "");
4078 }
4080 }
4081 ao2_ref(m, -1);
4082 }
4083 ao2_iterator_destroy(&mem_iter);
4084 ao2_unlock(q);
4085 ast_config_destroy(member_config);
4086}

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_lock, ao2_ref, ao2_unlock, ast_category_browse(), ast_config_destroy(), ast_debug, ast_load_realtime_multientry(), ast_queue_log(), ast_strlen_zero(), member::dead, member::interface, log_membername_as_agent, member_remove_from_queue(), member::membername, call_queue::members, call_queue::name, NULL, member::realtime, rt_handle_member_record(), and SENTINEL.

Referenced by find_load_queue_rt_friendly(), is_our_turn(), and queue_exec().

◆ update_status()

static void 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 2604 of file app_queue.c.

2605{
2606 if (m->status != status) {
2607 /* If this member has transitioned to being available then update their queue
2608 * information. If they are currently in a call then the leg to the agent will be
2609 * considered done and the call finished.
2610 */
2613 }
2614
2615 m->status = status;
2616
2617 /* Remove the member from the pending members pool only when the status changes.
2618 * This is not done unconditionally because we can occasionally see multiple
2619 * device state notifications of not in use after a previous call has ended,
2620 * including after we have initiated a new call. This is more likely to
2621 * happen when there is latency in the connection to the member.
2622 */
2624
2625 queue_publish_member_blob(queue_member_status_type(), queue_member_blob_create(q, m));
2626 }
2627}

References AST_DEVICE_NOT_INUSE, member::callcompletedinsl, pending_members_remove(), queue_member_blob_create(), queue_publish_member_blob(), member::starttime, status, member::status, and update_queue().

Referenced by device_state_cb(), and extension_state_cb().

◆ upqm_exec()

static int upqm_exec ( struct ast_channel chan,
const char *  data 
)
static

UnpauseQueueMember application.

Definition at line 8276 of file app_queue.c.

8277{
8278 char *parse;
8280 AST_APP_ARG(queuename);
8281 AST_APP_ARG(interface);
8283 AST_APP_ARG(reason);
8284 );
8285
8286 if (ast_strlen_zero(data)) {
8287 ast_log(LOG_WARNING, "UnpauseQueueMember requires an argument ([queuename],interface[,options[,reason]])\n");
8288 return -1;
8289 }
8290
8291 parse = ast_strdupa(data);
8292
8294
8295 if (ast_strlen_zero(args.interface)) {
8296 ast_log(LOG_WARNING, "Missing interface argument to UnpauseQueueMember ([queuename],interface[,options[,reason]])\n");
8297 return -1;
8298 }
8299
8300 if (set_member_paused(args.queuename, args.interface, args.reason, 0)) {
8301 ast_log(LOG_WARNING, "Attempt to unpause interface %s, not found\n", args.interface);
8302 pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "NOTFOUND");
8303 return 0;
8304 }
8305
8306 pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "UNPAUSED");
8307
8308 return 0;
8309}

References args, AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_log, AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), LOG_WARNING, options, pbx_builtin_setvar_helper(), and set_member_paused().

Referenced by load_module().

◆ valid_exit()

static int valid_exit ( struct queue_ent qe,
char  digit 
)
static

Check for valid exit from queue via goto.

Return values
0if failure
1if successful

Definition at line 4201 of file app_queue.c.

4202{
4203 int digitlen = strlen(qe->digits);
4204
4205 /* Prevent possible buffer overflow */
4206 if (digitlen < sizeof(qe->digits) - 2) {
4207 qe->digits[digitlen] = digit;
4208 qe->digits[digitlen + 1] = '\0';
4209 } else {
4210 qe->digits[0] = '\0';
4211 return 0;
4212 }
4213
4214 /* If there's no context to goto, short-circuit */
4215 if (ast_strlen_zero(qe->context)) {
4216 return 0;
4217 }
4218
4219 /* If the extension is bad, then reset the digits to blank */
4220 if (!ast_canmatch_extension(qe->chan, qe->context, qe->digits, 1,
4222 qe->digits[0] = '\0';
4223 return 0;
4224 }
4225
4226 /* We have an exact match */
4227 if (!ast_goto_if_exists(qe->chan, qe->context, qe->digits, 1)) {
4228 qe->valid_digits = 1;
4229 /* Return 1 on a successful goto */
4230 return 1;
4231 }
4232
4233 return 0;
4234}
int ast_goto_if_exists(struct ast_channel *chan, const char *context, const char *exten, int priority)
Definition: pbx.c:8781
int ast_canmatch_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
Looks for a valid matching extension.
Definition: pbx.c:4190

References ast_canmatch_extension(), ast_channel_caller(), ast_goto_if_exists(), ast_strlen_zero(), queue_ent::chan, queue_ent::context, digit, queue_ent::digits, ast_party_caller::id, NULL, 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(), wait_a_bit(), wait_for_answer(), and wait_our_turn().

◆ wait_a_bit()

static int wait_a_bit ( struct queue_ent qe)
static

Definition at line 7474 of file app_queue.c.

7475{
7476 /* Don't need to hold the lock while we setup the outgoing calls */
7477 int retrywait = qe->parent->retry * 1000;
7478
7479 int res = ast_waitfordigit(qe->chan, retrywait);
7480 if (res > 0 && !valid_exit(qe, res)) {
7481 res = 0;
7482 }
7483
7484 return res;
7485}
int ast_waitfordigit(struct ast_channel *c, int ms)
Waits for a digit.
Definition: channel.c:3194

References ast_waitfordigit(), queue_ent::chan, queue_ent::parent, call_queue::retry, and valid_exit().

Referenced by queue_exec().

◆ wait_for_answer()

static struct callattempt * wait_for_answer ( struct queue_ent qe,
struct callattempt outgoing,
int *  to,
char *  digit,
int  prebusies,
int  caller_disconnect,
int  forwardsallowed 
)
static

Wait for a member to answer the call.

Parameters
[in]qethe queue_ent corresponding to the caller in the queue
[in]outgoingthe list of callattempts. Relevant ones will have their chan and stillgoing parameters non-zero
[in]tothe amount of time (in milliseconds) to wait for a response
[out]digitif a user presses a digit to exit the queue, this is the digit the caller pressed
[in]prebusiesnumber of busy members calculated prior to calling wait_for_answer
[in]caller_disconnectif the 'H' option is used when calling Queue(), this is used to detect if the caller pressed * to disconnect the call
[in]forwardsallowedused to detect if we should allow call forwarding, based on the 'i' option to Queue()
Todo:
eventually all call forward logic should be integrated into and replaced by ast_call_forward()

Definition at line 5234 of file app_queue.c.

5235{
5236 const char *queue = qe->parent->name;
5237 struct callattempt *o, *start = NULL, *prev = NULL;
5238 int status;
5239 int numbusies = prebusies;
5240 int numnochan = 0;
5241 int stillgoing = 0;
5242 int orig = *to;
5243 struct ast_frame *f;
5244 struct callattempt *peer = NULL;
5245 struct ast_channel *winner;
5246 struct ast_channel *in = qe->chan;
5247 char on[80] = "";
5248 char membername[80] = "";
5249 long starttime = 0;
5250 long endtime = 0;
5251 char *inchan_name;
5252 struct timeval start_time_tv = ast_tvnow();
5253 int canceled_by_caller = 0; /* 1 when caller hangs up or press digit or press * */
5254
5256 inchan_name = ast_strdupa(ast_channel_name(qe->chan));
5258
5259 starttime = (long) time(NULL);
5260
5261 while ((*to = ast_remaining_ms(start_time_tv, orig)) && !peer) {
5262 int numlines, retry, pos = 1;
5263 struct ast_channel *watchers[AST_MAX_WATCHERS];
5264 watchers[0] = in;
5265 start = NULL;
5266
5267 for (retry = 0; retry < 2; retry++) {
5268 numlines = 0;
5269 for (o = outgoing; o; o = o->q_next) { /* Keep track of important channels */
5270 if (o->stillgoing) { /* Keep track of important channels */
5271 stillgoing = 1;
5272 if (o->chan) {
5273 if (pos < AST_MAX_WATCHERS) {
5274 watchers[pos++] = o->chan;
5275 }
5276 if (!start) {
5277 start = o;
5278 } else {
5279 prev->call_next = o;
5280 }
5281 prev = o;
5282 }
5283 } else if (prev) {
5284 prev->call_next = NULL;
5285 }
5286 numlines++;
5287 }
5288 if (pos > 1 /* found */ || !stillgoing /* nobody listening */ ||
5289 (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) /* ring would not be delivered */) {
5290 break;
5291 }
5292 /* On "ringall" strategy we only move to the next penalty level
5293 when *all* ringing phones are done in the current penalty level */
5294 ring_one(qe, outgoing, &numbusies);
5295 /* and retry... */
5296 }
5297 if (pos == 1 /* not found */) {
5298 if (numlines == (numbusies + numnochan)) {
5299 ast_debug(1, "Everyone is busy at this time\n");
5300 } else {
5301 ast_debug(3, "No one is answering queue '%s' (%d numlines / %d busies / %d failed channels)\n", queue, numlines, numbusies, numnochan);
5302 }
5303 *to = 0;
5304 return NULL;
5305 }
5306
5307 /* Poll for events from both the incoming channel as well as any outgoing channels */
5308 winner = ast_waitfor_n(watchers, pos, to);
5309
5310 /* Service all of the outgoing channels */
5311 for (o = start; o; o = o->call_next) {
5312 /* We go with a fixed buffer here instead of using ast_strdupa. Using
5313 * ast_strdupa in a loop like this one can cause a stack overflow
5314 */
5315 char ochan_name[AST_CHANNEL_NAME];
5316
5317 if (o->chan) {
5319 ast_copy_string(ochan_name, ast_channel_name(o->chan), sizeof(ochan_name));
5321 }
5322 if (o->stillgoing && (o->chan) && (ast_channel_state(o->chan) == AST_STATE_UP)) {
5323 if (!peer) {
5324 ast_verb(3, "%s answered %s\n", ochan_name, inchan_name);
5325 if (o->orig_chan_name
5326 && strcmp(o->orig_chan_name, ochan_name)) {
5327 /*
5328 * The channel name changed so we must generate COLP update.
5329 * Likely because a call pickup channel masqueraded in.
5330 */
5332 } else if (!o->block_connected_update) {
5333 if (o->pending_connected_update) {
5336 }
5337 } else if (!o->dial_callerid_absent) {
5339 }
5340 }
5341 if (o->aoc_s_rate_list) {
5342 size_t encoded_size;
5343 struct ast_aoc_encoded *encoded;
5344 if ((encoded = ast_aoc_encode(o->aoc_s_rate_list, &encoded_size, o->chan))) {
5345 ast_indicate_data(in, AST_CONTROL_AOC, encoded, encoded_size);
5346 ast_aoc_destroy_encoded(encoded);
5347 }
5348 }
5349 peer = o;
5350 }
5351 } else if (o->chan && (o->chan == winner)) {
5352
5353 ast_copy_string(on, o->member->interface, sizeof(on));
5354 ast_copy_string(membername, o->member->membername, sizeof(membername));
5355
5356 /* Before processing channel, go ahead and check for forwarding */
5357 if (!ast_strlen_zero(ast_channel_call_forward(o->chan)) && !forwardsallowed) {
5358 ast_verb(3, "Forwarding %s to '%s' prevented.\n", inchan_name, ast_channel_call_forward(o->chan));
5360 "CANCEL", ast_channel_call_forward(o->chan));
5361 numnochan++;
5362 do_hang(o);
5363 winner = NULL;
5364 continue;
5366 struct ast_channel *original = o->chan;
5367 char forwarder[AST_CHANNEL_NAME];
5368 char tmpchan[256];
5369 char *stuff;
5370 char *tech;
5371 int failed = 0;
5372
5373 ast_copy_string(tmpchan, ast_channel_call_forward(o->chan), sizeof(tmpchan));
5374 ast_copy_string(forwarder, ast_channel_name(o->chan), sizeof(forwarder));
5375 if ((stuff = strchr(tmpchan, '/'))) {
5376 *stuff++ = '\0';
5377 tech = tmpchan;
5378 } else {
5379 const char *forward_context;
5381 forward_context = pbx_builtin_getvar_helper(o->chan, "FORWARD_CONTEXT");
5382 snprintf(tmpchan, sizeof(tmpchan), "%s@%s", ast_channel_call_forward(o->chan), forward_context ? forward_context : ast_channel_context(o->chan));
5384 stuff = tmpchan;
5385 tech = "Local";
5386 }
5387 if (!strcasecmp(tech, "Local")) {
5388 /*
5389 * Drop the connected line update block for local channels since
5390 * this is going to run dialplan and the user can change his
5391 * mind about what connected line information he wants to send.
5392 */
5394 }
5395
5396 ast_verb(3, "Now forwarding %s to '%s/%s' (thanks to %s)\n", inchan_name, tech, stuff, ochan_name);
5397 /* Setup parameters */
5399 if (!o->chan) {
5401 "Forwarding failed to create channel to dial '%s/%s'\n",
5402 tech, stuff);
5403 o->stillgoing = 0;
5404 numnochan++;
5405 } else {
5406 ast_channel_lock_both(o->chan, original);
5408 ast_channel_redirecting(original));
5410 ast_channel_unlock(original);
5411
5415 pbx_builtin_setvar_helper(o->chan, "FORWARDERNAME", forwarder);
5417
5418 if (o->pending_connected_update) {
5419 /*
5420 * Re-seed the callattempt's connected line information with
5421 * previously acquired connected line info from the queued
5422 * channel. The previously acquired connected line info could
5423 * have been set through the CONNECTED_LINE dialplan function.
5424 */
5427 }
5428
5431
5433
5436 /*
5437 * The call was not previously redirected so it is
5438 * now redirected from this number.
5439 */
5445 }
5446
5448
5453
5456 && !o->block_connected_update) {
5457 struct ast_party_redirecting redirecting;
5458
5459 /*
5460 * Redirecting updates to the caller make sense only on single
5461 * call at a time strategies.
5462 *
5463 * Need to re-evaluate if calling unlock is still required as we no longer
5464 * use macro.
5465 */
5466 ast_party_redirecting_init(&redirecting);
5469 if (ast_channel_redirecting_sub(o->chan, in, &redirecting, 0)) {
5470 ast_channel_update_redirecting(in, &redirecting, NULL);
5471 }
5472 ast_party_redirecting_free(&redirecting);
5473 } else {
5475 }
5476
5477 if (ast_call(o->chan, stuff, 0)) {
5478 ast_log(LOG_NOTICE, "Forwarding failed to dial '%s/%s'\n",
5479 tech, stuff);
5480 failed = 1;
5481 }
5482 }
5483
5485 "CANCEL", ast_channel_call_forward(original));
5486 if (o->chan) {
5487 ast_channel_publish_dial(qe->chan, o->chan, stuff, NULL);
5488 }
5489
5490 if (failed) {
5491 do_hang(o);
5492 numnochan++;
5493 }
5494
5495 /* Hangup the original channel now, in case we needed it */
5496 ast_hangup(winner);
5497 continue;
5498 }
5499 f = ast_read(winner);
5500 if (f) {
5501 if (f->frametype == AST_FRAME_CONTROL) {
5502 switch (f->subclass.integer) {
5503 case AST_CONTROL_ANSWER:
5504 /* This is our guy if someone answered. */
5505 if (!peer) {
5506 ast_verb(3, "%s answered %s\n", ochan_name, inchan_name);
5507 ast_channel_publish_dial(qe->chan, o->chan, on, "ANSWER");
5508 publish_dial_end_event(qe->chan, outgoing, o->chan, "CANCEL");
5509 if (o->orig_chan_name
5510 && strcmp(o->orig_chan_name, ochan_name)) {
5511 /*
5512 * The channel name changed so we must generate COLP update.
5513 * Likely because a call pickup channel masqueraded in.
5514 */
5516 } else if (!o->block_connected_update) {
5517 if (o->pending_connected_update) {
5520 }
5521 } else if (!o->dial_callerid_absent) {
5523 }
5524 }
5525 if (o->aoc_s_rate_list) {
5526 size_t encoded_size;
5527 struct ast_aoc_encoded *encoded;
5528 if ((encoded = ast_aoc_encode(o->aoc_s_rate_list, &encoded_size, o->chan))) {
5529 ast_indicate_data(in, AST_CONTROL_AOC, encoded, encoded_size);
5530 ast_aoc_destroy_encoded(encoded);
5531 }
5532 }
5533 peer = o;
5534 }
5535 break;
5536 case AST_CONTROL_BUSY:
5537 ast_verb(3, "%s is busy\n", ochan_name);
5538 ast_channel_publish_dial(qe->chan, o->chan, on, "BUSY");
5539 endtime = (long) time(NULL);
5540 endtime -= starttime;
5541 rna(endtime * 1000, qe, o->chan, on, membername, qe->parent->autopausebusy);
5542 do_hang(o);
5544 if (qe->parent->timeoutrestart) {
5545 start_time_tv = ast_tvnow();
5546 }
5547 /* Have enough time for a queue member to answer? */
5548 if (ast_remaining_ms(start_time_tv, orig) > 500) {
5549 ring_one(qe, outgoing, &numbusies);
5550 starttime = (long) time(NULL);
5551 }
5552 }
5553 numbusies++;
5554 break;
5556 ast_verb(3, "%s is circuit-busy\n", ochan_name);
5557 ast_channel_publish_dial(qe->chan, o->chan, on, "CONGESTION");
5558 endtime = (long) time(NULL);
5559 endtime -= starttime;
5560 rna(endtime * 1000, qe, o->chan, on, membername, qe->parent->autopauseunavail);
5561 do_hang(o);
5563 if (qe->parent->timeoutrestart) {
5564 start_time_tv = ast_tvnow();
5565 }
5566 if (ast_remaining_ms(start_time_tv, orig) > 500) {
5567 ring_one(qe, outgoing, &numbusies);
5568 starttime = (long) time(NULL);
5569 }
5570 }
5571 numbusies++;
5572 break;
5574 ast_verb(3, "%s is ringing\n", ochan_name);
5575
5576 ast_channel_publish_dial(qe->chan, o->chan, on, "RINGING");
5577
5578 /* Start ring indication when the channel is ringing, if specified */
5579 if (qe->ring_when_ringing) {
5580 ast_moh_stop(qe->chan);
5582 }
5583 break;
5585 /* Ignore going off hook */
5586 break;
5588 if (o->block_connected_update) {
5589 ast_verb(3, "Connected line update to %s prevented.\n", inchan_name);
5590 break;
5591 }
5594
5595 ast_verb(3, "%s connected line has changed. Saving it until answer for %s\n", ochan_name, inchan_name);
5601 break;
5602 }
5603
5604 /*
5605 * Prevent using the CallerID from the outgoing channel since we
5606 * got a connected line update from it.
5607 */
5608 o->dial_callerid_absent = 1;
5609
5610 if (ast_channel_connected_line_sub(o->chan, in, f, 1)) {
5612 }
5613 break;
5614 case AST_CONTROL_AOC:
5615 {
5616 struct ast_aoc_decoded *decoded = ast_aoc_decode(f->data.ptr, f->datalen, o->chan);
5617 if (decoded && (ast_aoc_get_msg_type(decoded) == AST_AOC_S)) {
5619 o->aoc_s_rate_list = decoded;
5620 } else {
5621 ast_aoc_destroy_decoded(decoded);
5622 }
5623 }
5624 break;
5627 /*
5628 * Redirecting updates to the caller make sense only on single
5629 * call at a time strategies.
5630 */
5631 break;
5632 }
5633 if (o->block_connected_update) {
5634 ast_verb(3, "Redirecting update to %s prevented\n",
5635 inchan_name);
5636 break;
5637 }
5638 ast_verb(3, "%s redirecting info has changed, passing it to %s\n",
5639 ochan_name, inchan_name);
5640 if (ast_channel_redirecting_sub(o->chan, in, f, 1)) {
5642 }
5643 break;
5646 break;
5647 default:
5648 ast_debug(1, "Dunno what to do with control type %d\n", f->subclass.integer);
5649 break;
5650 }
5651 }
5652 ast_frfree(f);
5653 } else { /* ast_read() returned NULL */
5654 endtime = (long) time(NULL) - starttime;
5655 ast_channel_publish_dial(qe->chan, o->chan, on, "NOANSWER");
5656 rna(endtime * 1000, qe, o->chan, on, membername, 1);
5657 do_hang(o);
5659 if (qe->parent->timeoutrestart) {
5660 start_time_tv = ast_tvnow();
5661 }
5662 if (ast_remaining_ms(start_time_tv, orig) > 500) {
5663 ring_one(qe, outgoing, &numbusies);
5664 starttime = (long) time(NULL);
5665 }
5666 }
5667 }
5668 }
5669 }
5670
5671 /* If we received an event from the caller, deal with it. */
5672 if (winner == in) {
5673 f = ast_read(in);
5674 if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass.integer == AST_CONTROL_HANGUP))) {
5675 /* Got hung up */
5676 *to = -1;
5677 if (f) {
5678 if (f->data.uint32) {
5680 }
5681 ast_frfree(f);
5682 }
5683 canceled_by_caller = 1;
5684 } else if ((f->frametype == AST_FRAME_DTMF) && caller_disconnect && (f->subclass.integer == '*')) {
5685 ast_verb(3, "User hit %c to disconnect call.\n", f->subclass.integer);
5686 *to = 0;
5687 ast_frfree(f);
5688 canceled_by_caller = 1;
5689 } else if ((f->frametype == AST_FRAME_DTMF) && valid_exit(qe, f->subclass.integer)) {
5690 ast_verb(3, "User pressed digit: %c\n", f->subclass.integer);
5691 *to = 0;
5692 *digit = f->subclass.integer;
5693 ast_frfree(f);
5694 canceled_by_caller = 1;
5695 }
5696 /* When caller hung up or pressed * or digit. */
5697 if (canceled_by_caller) {
5699 for (o = start; o; o = o->call_next) {
5700 if (o->chan) {
5701 ast_queue_log(qe->parent->name, ast_channel_uniqueid(qe->chan), o->member->membername, "RINGCANCELED", "%d", (int) ast_tvdiff_ms(ast_tvnow(), start_time_tv));
5702 }
5703 }
5704 return NULL;
5705 }
5706
5707 /* Send the frame from the in channel to all outgoing channels. */
5708 for (o = start; o; o = o->call_next) {
5709 if (!o->stillgoing || !o->chan) {
5710 /* This outgoing channel has died so don't send the frame to it. */
5711 continue;
5712 }
5713 switch (f->frametype) {
5714 case AST_FRAME_CONTROL:
5715 switch (f->subclass.integer) {
5717 if (o->block_connected_update) {
5718 ast_verb(3, "Connected line update to %s prevented.\n", ast_channel_name(o->chan));
5719 break;
5720 }
5721 if (ast_channel_connected_line_sub(in, o->chan, f, 1)) {
5723 }
5724 break;
5726 if (o->block_connected_update) {
5727 ast_verb(3, "Redirecting update to %s prevented.\n", ast_channel_name(o->chan));
5728 break;
5729 }
5730 if (ast_channel_redirecting_sub(in, o->chan, f, 1)) {
5732 }
5733 break;
5734 default:
5735 /* We are not going to do anything with this frame. */
5736 goto skip_frame;
5737 }
5738 break;
5739 default:
5740 /* We are not going to do anything with this frame. */
5741 goto skip_frame;
5742 }
5743 }
5744skip_frame:;
5745
5746 ast_frfree(f);
5747 }
5748 }
5749
5750 if (!*to) {
5751 for (o = start; o; o = o->call_next) {
5752 if (o->chan) {
5753 rna(orig, qe, o->chan, o->interface, o->member->membername, 1);
5754 }
5755 }
5756
5757 publish_dial_end_event(qe->chan, outgoing, NULL, "NOANSWER");
5758 }
5759
5760 return peer;
5761}
void * ast_aoc_destroy_encoded(struct ast_aoc_encoded *encoded)
free an ast_aoc_encoded object
Definition: aoc.c:313
enum ast_aoc_type ast_aoc_get_msg_type(struct ast_aoc_decoded *decoded)
get the message type, AOC-D, AOC-E, or AOC Request
Definition: aoc.c:892
struct ast_aoc_decoded * ast_aoc_decode(struct ast_aoc_encoded *encoded, size_t size, struct ast_channel *chan)
decodes an encoded aoc payload.
Definition: aoc.c:449
struct ast_aoc_encoded * ast_aoc_encode(struct ast_aoc_decoded *decoded, size_t *out_size, struct ast_channel *chan)
encodes a decoded aoc structure so it can be passed on the wire
Definition: aoc.c:650
@ AST_AOC_S
Definition: aoc.h:64
#define AST_MAX_WATCHERS
Definition: app_queue.c:5220
static void update_connected_line_from_peer(struct ast_channel *chan, struct ast_channel *peer, int is_caller)
Definition: app_queue.c:5204
static void rna(int rnatime, struct queue_ent *qe, struct ast_channel *peer, char *interface, char *membername, int autopause)
RNA == Ring No Answer. Common code that is executed when we try a queue member and they don't answer.
Definition: app_queue.c:5139
void ast_party_redirecting_init(struct ast_party_redirecting *init)
Initialize the given redirecting structure.
Definition: channel.c:2141
void ast_party_number_init(struct ast_party_number *init)
Initialize the given number structure.
Definition: channel.c:1663
struct ast_channel * ast_waitfor_n(struct ast_channel **chan, int n, int *ms)
Waits for input on a group of channels Wait for input on an array of channels for a given # of millis...
Definition: channel.c:3176
void ast_party_connected_line_set(struct ast_party_connected_line *dest, const struct ast_party_connected_line *src, const struct ast_set_party_connected_line *update)
Set the connected line information based on another connected line source.
Definition: channel.c:2073
void ast_channel_req_accountcodes(struct ast_channel *chan, const struct ast_channel *requestor, enum ast_channel_requestor_relationship relationship)
Setup new channel accountcodes from the requestor channel after ast_request().
Definition: channel.c:6453
struct ast_frame * ast_read(struct ast_channel *chan)
Reads a frame.
Definition: channel.c:4276
int ast_channel_redirecting_sub(struct ast_channel *autoservice_chan, struct ast_channel *sub_chan, const void *redirecting_info, int is_frame)
Run a redirecting interception subroutine and update a channel's redirecting information.
Definition: channel.c:10405
int ast_connected_line_parse_data(const unsigned char *data, size_t datalen, struct ast_party_connected_line *connected)
Parse connected line indication frame data.
Definition: channel.c:8807
int ast_indicate_data(struct ast_channel *chan, int condition, const void *data, size_t datalen)
Indicates condition of channel, with payload.
Definition: channel.c:4672
void ast_channel_update_redirecting(struct ast_channel *chan, const struct ast_party_redirecting *redirecting, const struct ast_set_party_redirecting *update)
Indicate that the redirecting id has changed.
Definition: channel.c:10306
#define AST_CHANNEL_NAME
Definition: channel.h:173
void ast_party_number_free(struct ast_party_number *doomed)
Destroy the party number contents.
Definition: channel.c:1710
void ast_party_redirecting_free(struct ast_party_redirecting *doomed)
Destroy the redirecting information contents.
Definition: channel.c:2198
const char * ast_channel_call_forward(const struct ast_channel *chan)
void ast_party_connected_line_set_init(struct ast_party_connected_line *init, const struct ast_party_connected_line *guide)
Initialize the given connected line structure using the given guide for a set update operation.
Definition: channel.c:2064
ast_channel_state
ast_channel states
Definition: channelstate.h:35
@ AST_STATE_UP
Definition: channelstate.h:42
char connected
Definition: eagi_proxy.c:82
void ast_channel_publish_dial_forward(struct ast_channel *caller, struct ast_channel *peer, struct ast_channel *forwarded, const char *dialstring, const char *dialstatus, const char *forward)
Publish in the ast_channel_topic or ast_channel_topic_all topics a stasis message for the channels in...
#define AST_FRAME_DTMF
#define ast_frfree(fr)
@ AST_FRAME_CONTROL
@ AST_CONTROL_OFFHOOK
@ AST_CONTROL_BUSY
@ AST_CONTROL_REDIRECTING
@ AST_CONTROL_CONGESTION
@ AST_CONTROL_ANSWER
@ AST_CONTROL_HANGUP
@ AST_CONTROL_CONNECTED_LINE
@ AST_CONTROL_AOC
@ AST_CONTROL_PVT_CAUSE_CODE
const struct ast_channel_tech * tech
Data structure associated with a single frame of data.
struct ast_frame_subclass subclass
union ast_frame::@226 data
enum ast_frame_type frametype
Redirecting Line information. RDNIS (Redirecting Directory Number Information Service) Where a call d...
Definition: channel.h:524
struct ast_party_id from
Who is redirecting the call (Sent to the party the call is redirected toward)
Definition: channel.h:529
unsigned int dial_callerid_absent
Definition: app_queue.c:1712
unsigned int block_connected_update
Definition: app_queue.c:1710
struct callattempt * call_next
Definition: app_queue.c:1700
unsigned int pending_connected_update
Definition: app_queue.c:1708
int ast_remaining_ms(struct timeval start, int max_ms)
Calculate remaining milliseconds given a starting timestamp and upper bound.
Definition: utils.c:2281
int64_t ast_tvdiff_ms(struct timeval end, struct timeval start)
Computes the difference (in milliseconds) between two struct timeval instances.
Definition: time.h:107
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:159

References callattempt::aoc_s_rate_list, ast_aoc_decode(), ast_aoc_destroy_decoded(), ast_aoc_destroy_encoded(), ast_aoc_encode(), ast_aoc_get_msg_type(), AST_AOC_S, ast_call(), ast_channel_call_forward(), ast_channel_caller(), ast_channel_connected(), ast_channel_connected_line_sub(), ast_channel_context(), ast_channel_datastore_inherit(), ast_channel_dialed(), ast_channel_exten(), ast_channel_hangupcause_set(), ast_channel_inherit_variables(), ast_channel_lock, ast_channel_lock_both, AST_CHANNEL_NAME, ast_channel_name(), ast_channel_nativeformats(), ast_channel_publish_dial(), ast_channel_publish_dial_forward(), ast_channel_redirecting(), ast_channel_redirecting_sub(), ast_channel_req_accountcodes(), AST_CHANNEL_REQUESTOR_BRIDGE_PEER, ast_channel_uniqueid(), ast_channel_unlock, ast_channel_update_connected_line(), ast_channel_update_redirecting(), ast_connected_line_copy_from_caller(), ast_connected_line_parse_data(), AST_CONTROL_ANSWER, AST_CONTROL_AOC, AST_CONTROL_BUSY, AST_CONTROL_CONGESTION, AST_CONTROL_CONNECTED_LINE, AST_CONTROL_HANGUP, AST_CONTROL_OFFHOOK, AST_CONTROL_PVT_CAUSE_CODE, AST_CONTROL_REDIRECTING, AST_CONTROL_RINGING, ast_copy_string(), ast_debug, AST_FRAME_CONTROL, AST_FRAME_DTMF, ast_free, ast_frfree, ast_hangup(), ast_indicate(), ast_indicate_data(), ast_log, ast_max_forwards_decrement(), AST_MAX_WATCHERS, ast_moh_stop(), ast_party_connected_line_copy(), ast_party_connected_line_free(), ast_party_connected_line_set(), ast_party_connected_line_set_init(), ast_party_number_free(), ast_party_number_init(), ast_party_redirecting_copy(), ast_party_redirecting_free(), ast_party_redirecting_init(), ast_queue_log(), ast_read(), ast_remaining_ms(), ast_request(), AST_STATE_UP, ast_strdup, ast_strdupa, ast_strlen_zero(), ast_tvdiff_ms(), ast_tvnow(), ast_verb, ast_waitfor_n(), call_queue::autopausebusy, call_queue::autopauseunavail, callattempt::block_connected_update, callattempt::call_next, callattempt::chan, queue_ent::chan, callattempt::connected, connected, ast_frame::data, ast_frame::datalen, callattempt::dial_callerid_absent, digit, do_hang(), ast_frame::frametype, ast_party_redirecting::from, ast_party_caller::id, in, ast_frame_subclass::integer, callattempt::interface, member::interface, LOG_NOTICE, callattempt::member, member::membername, call_queue::name, NULL, ast_party_id::number, callattempt::orig_chan_name, queue_ent::parent, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), callattempt::pending_connected_update, ast_frame::ptr, publish_dial_end_event(), callattempt::q_next, QUEUE_STRATEGY_RINGALL, ring_one(), queue_ent::ring_when_ringing, rna(), status, callattempt::stillgoing, ast_party_number::str, call_queue::strategy, ast_frame::subclass, ast_channel::tech, call_queue::timeoutrestart, ast_party_dialed::transit_network_select, ast_frame::uint32, update_connected_line_from_peer(), ast_party_number::valid, and valid_exit().

Referenced by try_calling().

◆ wait_our_turn()

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

Return values
0if the caller's turn has arrived
-1if the caller should exit the queue.

Definition at line 5913 of file app_queue.c.

5914{
5915 int res = 0;
5916
5917 /* This is the holding pen for callers 2 through maxlen */
5918 for (;;) {
5919
5920 /* A request to withdraw this call from the queue arrived */
5921 if (qe->withdraw) {
5922 *reason = QUEUE_WITHDRAW;
5923 res = 1;
5924 break;
5925 }
5926
5927 if (is_our_turn(qe)) {
5928 break;
5929 }
5930
5931 /* If we have timed out, break out */
5932 if (qe->expire && (time(NULL) >= qe->expire)) {
5933 *reason = QUEUE_TIMEOUT;
5934 break;
5935 }
5936
5937 if (qe->parent->leavewhenempty) {
5938 int status = 0;
5939
5941 record_abandoned(qe);
5942 *reason = QUEUE_LEAVEEMPTY;
5943 ast_queue_log(qe->parent->name, ast_channel_uniqueid(qe->chan), "NONE", "EXITEMPTY", "%d|%d|%ld", qe->pos, qe->opos, (long) (time(NULL) - qe->start));
5944 res = -1;
5945 qe->handled = -1;
5946 break;
5947 }
5948 }
5949
5950 /* Make a position announcement, if enabled */
5951 if (qe->parent->announcefrequency &&
5952 (res = say_position(qe,ringing))) {
5953 break;
5954 }
5955
5956 /* If we have timed out, break out */
5957 if (qe->expire && (time(NULL) >= qe->expire)) {
5958 *reason = QUEUE_TIMEOUT;
5959 break;
5960 }
5961
5962 /* Make a periodic announcement, if enabled */
5965 break;
5966
5967 /* see if we need to move to the next penalty level for this queue */
5968 while (qe->pr && ((time(NULL) - qe->start) >= qe->pr->time)) {
5969 update_qe_rule(qe);
5970 }
5971
5972 /* If we have timed out, break out */
5973 if (qe->expire && (time(NULL) >= qe->expire)) {
5974 *reason = QUEUE_TIMEOUT;
5975 break;
5976 }
5977
5978 /* Wait a second before checking again */
5979 if ((res = ast_waitfordigit(qe->chan, RECHECK * 1000))) {
5980 if (res > 0 && !valid_exit(qe, res)) {
5981 res = 0;
5982 } else {
5983 break;
5984 }
5985 }
5986
5987 /* If we have timed out, break out */
5988 if (qe->expire && (time(NULL) >= qe->expire)) {
5989 *reason = QUEUE_TIMEOUT;
5990 break;
5991 }
5992 }
5993
5994 return res;
5995}
#define RECHECK
Definition: app_queue.c:1584

References call_queue::announcefrequency, ast_channel_uniqueid(), ast_queue_log(), ast_waitfordigit(), queue_ent::chan, queue_ent::expire, get_member_status(), queue_ent::handled, is_our_turn(), call_queue::leavewhenempty, queue_ent::max_penalty, queue_ent::min_penalty, call_queue::name, NULL, queue_ent::opos, queue_ent::parent, call_queue::periodicannouncefrequency, queue_ent::pos, queue_ent::pr, QUEUE_LEAVEEMPTY, QUEUE_TIMEOUT, QUEUE_WITHDRAW, queue_ent::raise_penalty, RECHECK, record_abandoned(), ringing(), say_periodic_announcement(), say_position(), queue_ent::start, status, penalty_rule::time, update_qe_rule(), valid_exit(), and queue_ent::withdraw.

Referenced by queue_exec().

◆ word_in_list()

static int word_in_list ( const char *  list,
const char *  word 
)
static

Check if a given word is in a space-delimited list.

Parameters
listSpace delimited list of words
wordThe word used to search the list
Note
This function will not return 1 if the word is at the very end of the list (followed immediately by a \0, not a space) since it is used for checking tab-completion and a word at the end is still being tab-completed.
Return values
1if the word is found
0if the word is not found

Definition at line 10313 of file app_queue.c.

10313 {
10314 int list_len, word_len = strlen(word);
10315 const char *find, *end_find, *end_list;
10316
10317 /* strip whitespace from front */
10318 while(isspace(*list)) {
10319 list++;
10320 }
10321
10322 while((find = strstr(list, word))) {
10323 /* beginning of find starts inside another word? */
10324 if (find != list && *(find - 1) != ' ') {
10325 list = find;
10326 /* strip word from front */
10327 while(!isspace(*list) && *list != '\0') {
10328 list++;
10329 }
10330 /* strip whitespace from front */
10331 while(isspace(*list)) {
10332 list++;
10333 }
10334 continue;
10335 }
10336
10337 /* end of find ends inside another word or at very end of list? */
10338 list_len = strlen(list);
10339 end_find = find + word_len;
10340 end_list = list + list_len;
10341 if (end_find == end_list || *end_find != ' ') {
10342 list = find;
10343 /* strip word from front */
10344 while(!isspace(*list) && *list != '\0') {
10345 list++;
10346 }
10347 /* strip whitespace from front */
10348 while(isspace(*list)) {
10349 list++;
10350 }
10351 continue;
10352 }
10353
10354 /* terminating conditions satisfied, word at beginning or separated by ' ' */
10355 return 1;
10356 }
10357
10358 return 0;
10359}

References call_queue::list.

Referenced by complete_queue().

Variable Documentation

◆ __mod_info

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 = AST_BUILDOPT_SUM, .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, .reload = reload, .load_pri = AST_MODPRI_DEVSTATE_CONSUMER, }
static

Definition at line 12018 of file app_queue.c.

◆ agent_router

struct stasis_message_router* agent_router
static

Definition at line 11752 of file app_queue.c.

Referenced by load_module(), and unload_module().

◆ app

char* app = "Queue"
static

Definition at line 1601 of file app_queue.c.

Referenced by load_module(), and unload_module().

◆ app_aqm

char* app_aqm = "AddQueueMember"
static

Definition at line 1603 of file app_queue.c.

Referenced by load_module(), and unload_module().

◆ app_pqm

char* app_pqm = "PauseQueueMember"
static

Definition at line 1607 of file app_queue.c.

Referenced by load_module(), and unload_module().

◆ app_ql

char* app_ql = "QueueLog"
static

Definition at line 1611 of file app_queue.c.

Referenced by load_module(), and unload_module().

◆ app_qupd

char* app_qupd = "QueueUpdate"
static

Definition at line 1613 of file app_queue.c.

Referenced by load_module(), and unload_module().

◆ app_rqm

char* app_rqm = "RemoveQueueMember"
static

Definition at line 1605 of file app_queue.c.

Referenced by load_module(), and unload_module().

◆ app_upqm

char* app_upqm = "UnpauseQueueMember"
static

Definition at line 1609 of file app_queue.c.

Referenced by load_module(), and unload_module().

◆ aqm_opts

const struct ast_app_option aqm_opts[128] = { [ 'p' ] = { .flag = AQMFLAG_PAUSED }, [ 'r' ] = { .flag = AQMFLAG_REASON , .arg_index = AQM_OPT_ARG_PAUSE_REASON + 1 }, }
static

Definition at line 1532 of file app_queue.c.

Referenced by aqm_exec().

◆ ast_module_info

const struct ast_module_info* ast_module_info = &__mod_info
static

Definition at line 12018 of file app_queue.c.

◆ autofill_default

int autofill_default
static

queues.conf [general] option

Definition at line 1625 of file app_queue.c.

Referenced by init_queue(), queue_reset_global_params(), and queue_set_global_params().

◆ autopausesmodes

const struct autopause autopausesmodes[]
static
Initial value:
= {
{ QUEUE_AUTOPAUSE_ON, "yes" },
}

Referenced by autopause2int().

◆ cli_queue

struct ast_cli_entry cli_queue[]
static

Definition at line 11739 of file app_queue.c.

Referenced by load_module(), and unload_module().

◆ device_state_sub

struct stasis_subscription* device_state_sub
static

Subscription to device state change messages.

Definition at line 1637 of file app_queue.c.

Referenced by load_module(), and unload_module().

◆ force_longest_waiting_caller

int force_longest_waiting_caller
static

queues.conf [general] option

Definition at line 1646 of file app_queue.c.

Referenced by can_ring_entry(), queue_reset_global_params(), and queue_set_global_params().

◆ id

enum queue_result id

Definition at line 1667 of file app_queue.c.

Referenced by OrderedDict::__repr__(), add_action_to_menu_entry(), add_diversion_header(), add_eprofile_to_tdata(), aeap_create(), ast_aeap_message_id(), ast_aoc_set_association_id(), ast_aoc_set_billing_id(), ast_bucket_file_json(), ast_bucket_json(), ast_cc_extension_monitor_add_dialstring(), ast_format_cap_append_by_type(), ast_io_change(), ast_jb_create_framehook(), ast_party_id_presentation(), ast_rtp_instance_extmap_get_id(), ast_sched_del_nonrunning(), ast_sip_modify_id_header(), ast_sip_set_id_from_invite(), bridge_sync_init(), cache_find(), clearcbone(), cleardisplay(), clearflag(), cleartimer(), contact_alloc(), create_new_id_hdr(), digitcollect(), digitdirect(), extension_state_add_destroy(), fetch_callerid_num(), frame_drop_helper(), frame_trace_helper(), generate_content_id_hdr(), handle_local_optimization_begin(), handle_local_optimization_end(), handle_registrations(), idemodulator(), load_engine(), mbl_load_adapter(), mbox(), mwi_mailbox_get(), party_id_build_data(), party_id_read(), party_id_write(), pidf_generate_body_content(), process_extmap_attributes(), queue_connected_line_update(), session_end_if_disconnected(), session_inv_on_tsx_state_changed(), set_id_from_from(), set_id_from_hdr(), set_id_from_pai(), set_id_from_rpid(), set_state(), setflag(), should_queue_connected_line_update(), showdisplay(), showkeys(), sip_subscription_to_ami(), sorcery_realtime_create(), sorcery_realtime_retrieve_fields(), sorcery_realtime_retrieve_multiple(), startelm(), starttimer(), state_id_by_topic(), try_merge_optimize_out(), try_swap_optimize_out(), and update_incoming_connected_line().

◆ log_membername_as_agent

int log_membername_as_agent
static

◆ montype_default

int montype_default
static

queues.conf [general] option

Definition at line 1628 of file app_queue.c.

Referenced by queue_reset_global_params(), and queue_set_global_params().

◆ negative_penalty_invalid

int negative_penalty_invalid
static

queues.conf [general] option

Definition at line 1640 of file app_queue.c.

Referenced by queue_reset_global_params(), queue_set_global_params(), remove_from_queue(), rt_handle_member_record(), and set_member_value().

◆ pending_members

struct ao2_container* pending_members
static

Definition at line 2542 of file app_queue.c.

Referenced by can_ring_entry(), load_module(), pending_members_remove(), and unload_module().

◆ pm_family

const char* const pm_family = "Queue/PersistentMembers"
static

Persistent Members astdb family.

Definition at line 1616 of file app_queue.c.

Referenced by dump_queue_members(), and reload_queue_members().

◆ queue_exec_options

const struct ast_app_option queue_exec_options[128] = { [ 'b' ] = { .flag = OPT_PREDIAL_CALLEE , .arg_index = OPT_ARG_PREDIAL_CALLEE + 1 }, [ 'B' ] = { .flag = OPT_PREDIAL_CALLER , .arg_index = OPT_ARG_PREDIAL_CALLER + 1 }, [ 'C' ] = { .flag = OPT_MARK_AS_ANSWERED }, [ 'c' ] = { .flag = OPT_GO_ON }, [ 'd' ] = { .flag = OPT_DATA_QUALITY }, [ 'F' ] = { .flag = OPT_CALLEE_GO_ON , .arg_index = OPT_ARG_CALLEE_GO_ON + 1 }, [ 'h' ] = { .flag = OPT_CALLEE_HANGUP }, [ 'H' ] = { .flag = OPT_CALLER_HANGUP }, [ 'i' ] = { .flag = OPT_IGNORE_CALL_FW }, [ 'I' ] = { .flag = OPT_IGNORE_CONNECTEDLINE }, [ 'k' ] = { .flag = OPT_CALLEE_PARK }, [ 'K' ] = { .flag = OPT_CALLER_PARK }, [ 'm' ] = { .flag = OPT_MUSICONHOLD_CLASS , .arg_index = OPT_ARG_MUSICONHOLD_CLASS + 1 }, [ 'n' ] = { .flag = OPT_NO_RETRY }, [ 'r' ] = { .flag = OPT_RINGING }, [ 'R' ] = { .flag = OPT_RING_WHEN_RINGING }, [ 't' ] = { .flag = OPT_CALLEE_TRANSFER }, [ 'T' ] = { .flag = OPT_CALLER_TRANSFER }, [ 'x' ] = { .flag = OPT_CALLEE_AUTOMIXMON }, [ 'X' ] = { .flag = OPT_CALLER_AUTOMIXMON }, [ 'w' ] = { .flag = OPT_CALLEE_AUTOMON }, [ 'W' ] = { .flag = OPT_CALLER_AUTOMON }, }
static

Definition at line 1516 of file app_queue.c.

Referenced by queue_exec().

◆ queue_persistent_members

int queue_persistent_members
static

◆ 

const struct { ... } queue_results[]

Referenced by set_queue_result().

◆ queueexists_function

struct ast_custom_function queueexists_function
static
Initial value:
= {
.name = "QUEUE_EXISTS",
}
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.
Definition: app_queue.c:9010

Definition at line 9490 of file app_queue.c.

Referenced by load_module(), and unload_module().

◆ queuegetchannel_function

struct ast_custom_function queuegetchannel_function
static
Initial value:
= {
.name = "QUEUE_GET_CHANNEL",
}
static int queue_function_queuegetchannel(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
Dialplan function QUEUE_GET_CHANNEL() Get caller channel waiting at specified position in the queue.
Definition: app_queue.c:9258

Definition at line 9511 of file app_queue.c.

Referenced by load_module(), and unload_module().

◆ queuemembercount_dep

struct ast_custom_function queuemembercount_dep
static
Initial value:
= {
.name = "QUEUE_MEMBER_COUNT",
}
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)
Definition: app_queue.c:9217

Definition at line 9506 of file app_queue.c.

Referenced by load_module(), and unload_module().

◆ queuemembercount_function

struct ast_custom_function queuemembercount_function
static
Initial value:
= {
.name = "QUEUE_MEMBER",
}
static int queue_function_mem_read(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.
Definition: app_queue.c:9052
static int queue_function_mem_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
Dialplan function QUEUE_MEMBER() Sets the members penalty / paused / ringinuse.
Definition: app_queue.c:9154

Definition at line 9500 of file app_queue.c.

Referenced by load_module(), and unload_module().

◆ queuememberlist_function

struct ast_custom_function queuememberlist_function
static
Initial value:
= {
.name = "QUEUE_MEMBER_LIST",
}
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.
Definition: app_queue.c:9374

Definition at line 9521 of file app_queue.c.

Referenced by load_module(), and unload_module().

◆ queuememberpenalty_function

struct ast_custom_function queuememberpenalty_function
static
Initial value:
= {
.name = "QUEUE_MEMBER_PENALTY",
}
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.
Definition: app_queue.c:9422
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.
Definition: app_queue.c:9454

Definition at line 9526 of file app_queue.c.

Referenced by load_module(), and unload_module().

◆ queues

struct ao2_container* queues
static

◆ queuevar_function

struct ast_custom_function queuevar_function
static
Initial value:
= {
.name = "QUEUE_VARIABLES",
}
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.
Definition: app_queue.c:8966

Definition at line 9495 of file app_queue.c.

Referenced by load_module(), and unload_module().

◆ queuewaitingcount_function

struct ast_custom_function queuewaitingcount_function
static
Initial value:
= {
.name = "QUEUE_WAITING_COUNT",
}
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.
Definition: app_queue.c:9337

Definition at line 9516 of file app_queue.c.

Referenced by load_module(), and unload_module().

◆ realtime_reason_paused

int realtime_reason_paused
static

does realtime backend support reason_paused

Definition at line 1652 of file app_queue.c.

Referenced by load_module(), rt_handle_member_record(), and set_queue_member_pause().

◆ realtime_ringinuse_field

char* realtime_ringinuse_field
static

name of the ringinuse field in the realtime database

Definition at line 1649 of file app_queue.c.

Referenced by load_module(), rt_handle_member_record(), and set_queue_member_ringinuse().

◆ realtime_rules

int realtime_rules
static

queuerules.conf [general] option

Definition at line 1634 of file app_queue.c.

Referenced by queue_rules_reset_global_params(), queue_rules_set_global_params(), and reload_queue_rules().

◆ rule_lists

struct rule_lists rule_lists = { .first = NULL, .last = NULL, .lock = { PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP , NULL, {1, 0} } , }
static

◆ shared_lastcall

int shared_lastcall
static

queues.conf [general] option

Definition at line 1631 of file app_queue.c.

Referenced by queue_reset_global_params(), queue_set_global_params(), and update_queue().

◆ strategies

const struct strategy strategies[]
static

Referenced by int2strat(), and strat2int().

◆ text

char* text

◆ topic_forwarder

struct stasis_forward* topic_forwarder
static

Definition at line 11753 of file app_queue.c.

Referenced by load_module(), and unload_module().

◆ use_weight

int use_weight
static

Records that one or more queues use weight.

Definition at line 1622 of file app_queue.c.

Referenced by can_ring_entry(), find_load_queue_rt_friendly(), load_module(), and reload_single_queue().