Asterisk - The Open Source Telephony Project GIT-master-ff80666
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, int raise_respect_min)
 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_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_caller_id_name
 queues.conf [general] option More...
 
static int log_membername_as_agent
 queues.conf [general] option More...
 
static int log_unpause_on_reason_change
 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_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 1901 of file app_queue.c.

◆ ANNOUNCEHOLDTIME_ONCE

#define ANNOUNCEHOLDTIME_ONCE   2

Definition at line 1902 of file app_queue.c.

◆ ANNOUNCEPOSITION_LIMIT

#define ANNOUNCEPOSITION_LIMIT   4

We not announce position more than <limit>

Definition at line 1920 of file app_queue.c.

◆ ANNOUNCEPOSITION_MORE_THAN

#define ANNOUNCEPOSITION_MORE_THAN   3

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

Definition at line 1919 of file app_queue.c.

◆ ANNOUNCEPOSITION_NO

#define ANNOUNCEPOSITION_NO   2

We don't announce position

Definition at line 1918 of file app_queue.c.

◆ ANNOUNCEPOSITION_YES

#define ANNOUNCEPOSITION_YES   1

We announce position

Definition at line 1917 of file app_queue.c.

◆ AST_MAX_WATCHERS

#define AST_MAX_WATCHERS   256

Definition at line 5342 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 1684 of file app_queue.c.

◆ DEFAULT_RETRY

#define DEFAULT_RETRY   5

Definition at line 1676 of file app_queue.c.

◆ DEFAULT_TIMEOUT

#define DEFAULT_TIMEOUT   15

Definition at line 1677 of file app_queue.c.

◆ MAX_CALL_ATTEMPT_BUCKETS

#define MAX_CALL_ATTEMPT_BUCKETS   353

Definition at line 2650 of file app_queue.c.

◆ MAX_PERIODIC_ANNOUNCEMENTS

#define MAX_PERIODIC_ANNOUNCEMENTS   10

The maximum periodic announcements we can have

Definition at line 1679 of file app_queue.c.

◆ MAX_QUEUE_BUCKETS

#define MAX_QUEUE_BUCKETS   53

Definition at line 1686 of file app_queue.c.

◆ QUEUE_EVENT_VARIABLES

#define QUEUE_EVENT_VARIABLES   3

Definition at line 1903 of file app_queue.c.

◆ QUEUE_PAUSED_DEVSTATE

#define QUEUE_PAUSED_DEVSTATE   AST_DEVICE_INUSE

Definition at line 3687 of file app_queue.c.

◆ queue_ref

#define queue_ref (   q)    ao2_bump(q)

Definition at line 2186 of file app_queue.c.

◆ queue_t_ref

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

Definition at line 2188 of file app_queue.c.

◆ queue_t_unref

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

Definition at line 2189 of file app_queue.c.

◆ QUEUE_UNKNOWN_PAUSED_DEVSTATE

#define QUEUE_UNKNOWN_PAUSED_DEVSTATE   AST_DEVICE_NOT_INUSE

Definition at line 3689 of file app_queue.c.

◆ QUEUE_UNPAUSED_DEVSTATE

#define QUEUE_UNPAUSED_DEVSTATE   AST_DEVICE_NOT_INUSE

Definition at line 3688 of file app_queue.c.

◆ queue_unref

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

Definition at line 2187 of file app_queue.c.

◆ queues_t_link

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

Definition at line 2190 of file app_queue.c.

◆ queues_t_unlink

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

Definition at line 2191 of file app_queue.c.

◆ RECHECK

#define RECHECK   1

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

Definition at line 1678 of file app_queue.c.

◆ RES_EXISTS

#define RES_EXISTS   (-1)

Entry already exists

Definition at line 1689 of file app_queue.c.

◆ RES_NOSUCHQUEUE

#define RES_NOSUCHQUEUE   (-3)

No such queue

Definition at line 1691 of file app_queue.c.

◆ RES_NOT_CALLER

#define RES_NOT_CALLER   (-5)

Caller not found

Definition at line 1693 of file app_queue.c.

◆ RES_NOT_DYNAMIC

#define RES_NOT_DYNAMIC   (-4)

Member is not dynamic

Definition at line 1692 of file app_queue.c.

◆ RES_OKAY

#define RES_OKAY   0

Action completed

Definition at line 1688 of file app_queue.c.

◆ RES_OUTOFMEMORY

#define RES_OUTOFMEMORY   (-2)

Out of memory

Definition at line 1690 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 1553 of file app_queue.c.

1553 {
1554 OPT_MARK_AS_ANSWERED = (1 << 0),
1555 OPT_GO_ON = (1 << 1),
1556 OPT_DATA_QUALITY = (1 << 2),
1557 OPT_CALLEE_GO_ON = (1 << 3),
1558 OPT_CALLEE_HANGUP = (1 << 4),
1559 OPT_CALLER_HANGUP = (1 << 5),
1560 OPT_IGNORE_CALL_FW = (1 << 6),
1561 OPT_IGNORE_CONNECTEDLINE = (1 << 7),
1562 OPT_CALLEE_PARK = (1 << 8),
1563 OPT_CALLER_PARK = (1 << 9),
1564 OPT_NO_RETRY = (1 << 10),
1565 OPT_RINGING = (1 << 11),
1566 OPT_RING_WHEN_RINGING = (1 << 12),
1567 OPT_CALLEE_TRANSFER = (1 << 13),
1568 OPT_CALLER_TRANSFER = (1 << 14),
1569 OPT_CALLEE_AUTOMIXMON = (1 << 15),
1570 OPT_CALLER_AUTOMIXMON = (1 << 16),
1571 OPT_CALLEE_AUTOMON = (1 << 17),
1572 OPT_CALLER_AUTOMON = (1 << 18),
1573 OPT_PREDIAL_CALLEE = (1 << 19),
1574 OPT_PREDIAL_CALLER = (1 << 20),
1575 OPT_MUSICONHOLD_CLASS = (1 << 21),
1576};
@ OPT_CALLER_AUTOMON
Definition: app_queue.c:1572
@ OPT_CALLEE_PARK
Definition: app_queue.c:1562
@ OPT_PREDIAL_CALLER
Definition: app_queue.c:1574
@ OPT_GO_ON
Definition: app_queue.c:1555
@ OPT_IGNORE_CONNECTEDLINE
Definition: app_queue.c:1561
@ OPT_CALLEE_AUTOMON
Definition: app_queue.c:1571
@ OPT_CALLEE_TRANSFER
Definition: app_queue.c:1567
@ OPT_CALLEE_GO_ON
Definition: app_queue.c:1557
@ OPT_MARK_AS_ANSWERED
Definition: app_queue.c:1554
@ OPT_IGNORE_CALL_FW
Definition: app_queue.c:1560
@ OPT_CALLER_PARK
Definition: app_queue.c:1563
@ OPT_NO_RETRY
Definition: app_queue.c:1564
@ OPT_DATA_QUALITY
Definition: app_queue.c:1556
@ OPT_CALLER_HANGUP
Definition: app_queue.c:1559
@ OPT_MUSICONHOLD_CLASS
Definition: app_queue.c:1575
@ OPT_CALLEE_AUTOMIXMON
Definition: app_queue.c:1569
@ OPT_CALLEE_HANGUP
Definition: app_queue.c:1558
@ OPT_CALLER_AUTOMIXMON
Definition: app_queue.c:1570
@ OPT_RINGING
Definition: app_queue.c:1565
@ OPT_CALLER_TRANSFER
Definition: app_queue.c:1568
@ OPT_PREDIAL_CALLEE
Definition: app_queue.c:1573
@ OPT_RING_WHEN_RINGING
Definition: app_queue.c:1566

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

1578 {
1583 /* note: this entry _MUST_ be the last one in the enum */
1585};
@ OPT_ARG_CALLEE_GO_ON
Definition: app_queue.c:1579
@ OPT_ARG_PREDIAL_CALLEE
Definition: app_queue.c:1580
@ OPT_ARG_MUSICONHOLD_CLASS
Definition: app_queue.c:1582
@ OPT_ARG_PREDIAL_CALLER
Definition: app_queue.c:1581
@ OPT_ARG_ARRAY_SIZE
Definition: app_queue.c:1584

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

1628 {
1637};
@ QUEUE_STRATEGY_RINGALL
Definition: app_queue.c:1629
@ QUEUE_STRATEGY_RRMEMORY
Definition: app_queue.c:1633
@ QUEUE_STRATEGY_LINEAR
Definition: app_queue.c:1634
@ QUEUE_STRATEGY_LEASTRECENT
Definition: app_queue.c:1630
@ QUEUE_STRATEGY_RANDOM
Definition: app_queue.c:1632
@ QUEUE_STRATEGY_FEWESTCALLS
Definition: app_queue.c:1631
@ QUEUE_STRATEGY_RRORDERED
Definition: app_queue.c:1636
@ QUEUE_STRATEGY_WRANDOM
Definition: app_queue.c:1635

◆ anonymous enum

anonymous enum
Enumerator
QUEUE_AUTOPAUSE_OFF 
QUEUE_AUTOPAUSE_ON 
QUEUE_AUTOPAUSE_ALL 

Definition at line 1639 of file app_queue.c.

1639 {
1643};
@ QUEUE_AUTOPAUSE_ON
Definition: app_queue.c:1641
@ QUEUE_AUTOPAUSE_OFF
Definition: app_queue.c:1640
@ QUEUE_AUTOPAUSE_ALL
Definition: app_queue.c:1642

◆ agent_complete_reason

Enumerator
CALLER 
AGENT 
TRANSFER 

Definition at line 6273 of file app_queue.c.

6273 {
6274 CALLER,
6275 AGENT,
6276 TRANSFER
6277};
@ AGENT
Definition: app_queue.c:6275
@ CALLER
Definition: app_queue.c:6274
@ TRANSFER
Definition: app_queue.c:6276

◆ aqm_args

enum aqm_args
Enumerator
AQM_OPT_ARG_PAUSE_REASON 
AQM_OPT_ARG_ARRAY_SIZE 

Definition at line 1618 of file app_queue.c.

1618 {
1620 AQM_OPT_ARG_ARRAY_SIZE, /* Always last element of the enum */
1621};
@ AQM_OPT_ARG_ARRAY_SIZE
Definition: app_queue.c:1620
@ AQM_OPT_ARG_PAUSE_REASON
Definition: app_queue.c:1619

◆ aqm_flags

enum aqm_flags
Enumerator
AQMFLAG_PAUSED 
AQMFLAG_REASON 

Definition at line 1613 of file app_queue.c.

1613 {
1614 AQMFLAG_PAUSED = (1 << 1),
1615 AQMFLAG_REASON = (1 << 2),
1616};
@ AQMFLAG_REASON
Definition: app_queue.c:1615
@ AQMFLAG_PAUSED
Definition: app_queue.c:1614

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

1884 {
1885 QUEUE_EMPTY_PENALTY = (1 << 0),
1886 QUEUE_EMPTY_PAUSED = (1 << 1),
1887 QUEUE_EMPTY_INUSE = (1 << 2),
1888 QUEUE_EMPTY_RINGING = (1 << 3),
1889 QUEUE_EMPTY_UNAVAILABLE = (1 << 4),
1890 QUEUE_EMPTY_INVALID = (1 << 5),
1891 QUEUE_EMPTY_UNKNOWN = (1 << 6),
1892 QUEUE_EMPTY_WRAPUP = (1 << 7),
1893};
@ QUEUE_EMPTY_INVALID
Definition: app_queue.c:1890
@ QUEUE_EMPTY_UNKNOWN
Definition: app_queue.c:1891
@ QUEUE_EMPTY_PENALTY
Definition: app_queue.c:1885
@ QUEUE_EMPTY_RINGING
Definition: app_queue.c:1888
@ QUEUE_EMPTY_INUSE
Definition: app_queue.c:1887
@ QUEUE_EMPTY_UNAVAILABLE
Definition: app_queue.c:1889
@ QUEUE_EMPTY_WRAPUP
Definition: app_queue.c:1892
@ QUEUE_EMPTY_PAUSED
Definition: app_queue.c:1886

◆ member_properties

Enumerator
MEMBER_PENALTY 
MEMBER_RINGINUSE 

Definition at line 1895 of file app_queue.c.

1895 {
1896 MEMBER_PENALTY = 0,
1897 MEMBER_RINGINUSE = 1,
1898};
@ MEMBER_RINGINUSE
Definition: app_queue.c:1897
@ MEMBER_PENALTY
Definition: app_queue.c:1896

◆ queue_reload_mask

Enumerator
QUEUE_RELOAD_PARAMETERS 
QUEUE_RELOAD_MEMBER 
QUEUE_RELOAD_RULES 
QUEUE_RESET_STATS 

Definition at line 1645 of file app_queue.c.

1645 {
1646 QUEUE_RELOAD_PARAMETERS = (1 << 0),
1647 QUEUE_RELOAD_MEMBER = (1 << 1),
1648 QUEUE_RELOAD_RULES = (1 << 2),
1649 QUEUE_RESET_STATS = (1 << 3),
1650};
@ QUEUE_RELOAD_RULES
Definition: app_queue.c:1648
@ QUEUE_RELOAD_MEMBER
Definition: app_queue.c:1647
@ QUEUE_RESET_STATS
Definition: app_queue.c:1649
@ QUEUE_RELOAD_PARAMETERS
Definition: app_queue.c:1646

◆ queue_result

Enumerator
QUEUE_UNKNOWN 
QUEUE_TIMEOUT 
QUEUE_JOINEMPTY 
QUEUE_LEAVEEMPTY 
QUEUE_JOINUNAVAIL 
QUEUE_LEAVEUNAVAIL 
QUEUE_FULL 
QUEUE_CONTINUE 
QUEUE_WITHDRAW 

Definition at line 1754 of file app_queue.c.

1754 {
1755 QUEUE_UNKNOWN = 0,
1756 QUEUE_TIMEOUT = 1,
1757 QUEUE_JOINEMPTY = 2,
1758 QUEUE_LEAVEEMPTY = 3,
1761 QUEUE_FULL = 6,
1762 QUEUE_CONTINUE = 7,
1763 QUEUE_WITHDRAW = 8,
1764};
@ QUEUE_FULL
Definition: app_queue.c:1761
@ QUEUE_UNKNOWN
Definition: app_queue.c:1755
@ QUEUE_WITHDRAW
Definition: app_queue.c:1763
@ QUEUE_CONTINUE
Definition: app_queue.c:1762
@ QUEUE_LEAVEEMPTY
Definition: app_queue.c:1758
@ QUEUE_LEAVEUNAVAIL
Definition: app_queue.c:1760
@ QUEUE_JOINUNAVAIL
Definition: app_queue.c:1759
@ QUEUE_JOINEMPTY
Definition: app_queue.c:1757
@ QUEUE_TIMEOUT
Definition: app_queue.c:1756

◆ queue_timeout_priority

Enumerator
TIMEOUT_PRIORITY_APP 
TIMEOUT_PRIORITY_CONF 

Definition at line 1781 of file app_queue.c.

1781 {
1784};
@ TIMEOUT_PRIORITY_CONF
Definition: app_queue.c:1783
@ TIMEOUT_PRIORITY_APP
Definition: app_queue.c:1782

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

10323{
10324 struct call_queue *q;
10325 struct ast_str *out = ast_str_alloca(512);
10326 struct ao2_container *sorted_queues;
10327
10328 struct ao2_iterator queue_iter;
10329 int found = 0;
10330
10331 if (argc != 2 && argc != 3) {
10332 return CLI_SHOWUSAGE;
10333 }
10334
10335 if (argc == 3) { /* specific queue */
10336 if ((q = find_load_queue_rt_friendly(argv[2]))) {
10337 ao2_lock(q);
10338 print_queue(s, fd, q);
10339 ao2_unlock(q);
10340 queue_unref(q);
10341 } else {
10342 ast_str_set(&out, 0, "No such queue: %s.", argv[2]);
10343 do_print(s, fd, ast_str_buffer(out));
10344 }
10345 return CLI_SUCCESS;
10346 }
10347
10348 if (ast_check_realtime("queues")) {
10349 /* This block is to find any queues which are defined in realtime but
10350 * which have not yet been added to the in-core container
10351 */
10352 struct ast_config *cfg = ast_load_realtime_multientry("queues", "name LIKE", "%", SENTINEL);
10353 if (cfg) {
10354 char *category = NULL;
10355 while ((category = ast_category_browse(cfg, category))) {
10356 const char *queuename = ast_variable_retrieve(cfg, category, "name");
10357 if (ast_strlen_zero(queuename)) {
10358 ast_log(LOG_WARNING, "Ignoring realtime queue with a NULL or empty 'name.'\n");
10359 continue;
10360 }
10361 if ((q = find_load_queue_rt_friendly(queuename))) {
10362 queue_t_unref(q, "Done with temporary pointer");
10363 }
10364 }
10365 ast_config_destroy(cfg);
10366 }
10367 }
10368
10369 /*
10370 * Snapping a copy of the container prevents having to lock both the queues container
10371 * and the queue itself at the same time. It also allows us to sort the entries.
10372 */
10373 sorted_queues = ao2_container_alloc_rbtree(AO2_ALLOC_OPT_LOCK_NOLOCK, 0, call_queue_sort_fn, NULL);
10374 if (!sorted_queues) {
10375 return CLI_SUCCESS;
10376 }
10377 if (ao2_container_dup(sorted_queues, queues, 0)) {
10378 ao2_ref(sorted_queues, -1);
10379 return CLI_SUCCESS;
10380 }
10381
10382 /*
10383 * No need to lock the container since it's temporary and static.
10384 * We also unlink the entries as we use them so the container is
10385 * empty when the iterator finishes. We can then just unref the container.
10386 */
10387 queue_iter = ao2_iterator_init(sorted_queues, AO2_ITERATOR_DONTLOCK | AO2_ITERATOR_UNLINK);
10388 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
10389 struct call_queue *realtime_queue = NULL;
10390 ao2_lock(q);
10391 /* This check is to make sure we don't print information for realtime
10392 * queues which have been deleted from realtime but which have not yet
10393 * been deleted from the in-core container. Only do this if we're not
10394 * looking for a specific queue.
10395 */
10396 if (q->realtime) {
10397 realtime_queue = find_load_queue_rt_friendly(q->name);
10398 if (!realtime_queue) {
10399 ao2_unlock(q);
10400 queue_t_unref(q, "Done with iterator");
10401 continue;
10402 }
10403 queue_t_unref(realtime_queue, "Queue is already in memory");
10404 }
10405
10406 found = 1;
10407 print_queue(s, fd, q);
10408
10409 ao2_unlock(q);
10410 queue_t_unref(q, "Done with iterator"); /* Unref the iterator's reference */
10411 }
10412 ao2_iterator_destroy(&queue_iter);
10413 ao2_ref(sorted_queues, -1);
10414 if (!found) {
10415 ast_str_set(&out, 0, "No queues.");
10416 do_print(s, fd, ast_str_buffer(out));
10417 }
10418 return CLI_SUCCESS;
10419}
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:10214
static struct ao2_container * queues
Definition: app_queue.c:2032
#define queue_t_unref(q, tag)
Definition: app_queue.c:2189
#define queue_unref(q)
Definition: app_queue.c:2187
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:10204
static struct call_queue * find_load_queue_rt_friendly(const char *queuename)
Definition: app_queue.c:4046
#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:3324
struct ast_config * ast_load_realtime_multientry(const char *family,...) attribute_sentinel
Retrieve realtime configuration.
Definition: main/config.c:3889
int ast_check_realtime(const char *family)
Check if realtime engine is configured for family.
Definition: main/config.c:3797
void ast_config_destroy(struct ast_config *cfg)
Destroys a config.
Definition: extconf.c:1287
const char * ast_variable_retrieve(struct ast_config *config, const char *category, const char *variable)
Definition: main/config.c:870
#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:1976
unsigned int found
Definition: app_queue.c:1977
const ast_string_field name
Definition: app_queue.c:1960
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 12137 of file app_queue.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

Definition at line 12137 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 7752 of file app_queue.c.

7753{
7754 struct call_queue *q;
7755 struct member *new_member, *old_member;
7756 int res = RES_NOSUCHQUEUE;
7757
7758 /*! \note Ensure the appropriate realtime queue is loaded. Note that this
7759 * short-circuits if the queue is already in memory. */
7760 if (!(q = find_load_queue_rt_friendly(queuename))) {
7761 return res;
7762 }
7763
7764 ao2_lock(q);
7765 if ((old_member = interface_exists(q, interface)) == NULL) {
7767 new_member->dynamic = 1;
7768 if (reason_paused) {
7769 ast_copy_string(new_member->reason_paused, reason_paused, sizeof(new_member->reason_paused));
7770 }
7771 member_add_to_queue(q, new_member);
7772 queue_publish_member_blob(queue_member_added_type(), queue_member_blob_create(q, new_member));
7773
7774 if (is_member_available(q, new_member)) {
7776 }
7777
7778 ao2_ref(new_member, -1);
7779 new_member = NULL;
7780
7781 if (dump) {
7783 }
7784
7785 res = RES_OKAY;
7786 } else {
7787 res = RES_OUTOFMEMORY;
7788 }
7789 } else {
7790 ao2_ref(old_member, -1);
7791 res = RES_EXISTS;
7792 }
7793 ao2_unlock(q);
7794 queue_t_unref(q, "Expiring temporary reference");
7795
7796 return res;
7797}
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:3001
static struct member * interface_exists(struct call_queue *q, const char *interface)
Definition: app_queue.c:7617
static void dump_queue_members(struct call_queue *pm_queue)
Dump all members in a specific queue to the database.
Definition: app_queue.c:7644
static int is_member_available(struct call_queue *q, struct member *mem)
Definition: app_queue.c:2742
#define RES_OUTOFMEMORY
Definition: app_queue.c:1690
#define RES_NOSUCHQUEUE
Definition: app_queue.c:1691
#define RES_OKAY
Definition: app_queue.c:1688
static void member_add_to_queue(struct call_queue *queue, struct member *mem)
Definition: app_queue.c:3697
static struct ast_json * queue_member_blob_create(struct call_queue *q, struct member *mem)
Definition: app_queue.c:2526
#define RES_EXISTS
Definition: app_queue.c:1689
static void queue_publish_member_blob(struct stasis_message_type *type, struct ast_json *blob)
Definition: app_queue.c:2502
@ 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:513
@ 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:1964
char interface[AST_CHANNEL_NAME]
Definition: app_queue.c:1857
int dynamic
Definition: app_queue.c:1865
char membername[80]
Definition: app_queue.c:1862
int penalty
Definition: app_queue.c:1863
int paused
Definition: app_queue.c:1868
int wrapuptime
Definition: app_queue.c:1872
char reason_paused[80]
Definition: app_queue.c:1869
char state_interface[AST_CHANNEL_NAME]
Definition: app_queue.c:1860

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

3879{
3880 struct call_queue *q;
3881
3882 if ((q = ao2_t_alloc(sizeof(*q), destroy_queue, "Allocate queue"))) {
3883 if (ast_string_field_init(q, 64)) {
3884 queue_t_unref(q, "String field allocation failed");
3885 return NULL;
3886 }
3887 ast_string_field_set(q, name, queuename);
3888 }
3889 return q;
3890}
static void destroy_queue(void *obj)
Free queue's member list then its string fields.
Definition: app_queue.c:3863
#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 8518 of file app_queue.c.

8519{
8520 int res=-1;
8521 char *parse, *tmp, *temppos = NULL, *reason = NULL;
8523 AST_APP_ARG(queuename);
8524 AST_APP_ARG(interface);
8525 AST_APP_ARG(penalty);
8527 AST_APP_ARG(membername);
8528 AST_APP_ARG(state_interface);
8529 AST_APP_ARG(wrapuptime);
8530 );
8531 int penalty = 0;
8532 int paused = 0;
8533 int wrapuptime;
8534 struct ast_flags flags = { 0 };
8535
8536 if (ast_strlen_zero(data)) {
8537 ast_log(LOG_WARNING, "AddQueueMember requires an argument (queuename[,interface[,penalty[,options[,membername[,stateinterface][,wrapuptime]]]]])\n");
8538 return -1;
8539 }
8540
8541 parse = ast_strdupa(data);
8542
8544
8545 if (args.options) {
8546 char *opts[AQM_OPT_ARG_ARRAY_SIZE] = { NULL, };
8547 ast_app_parse_options(aqm_opts, &flags, opts, args.options);
8549 paused = 1;
8551 reason = ast_strdupa(opts[AQM_OPT_ARG_PAUSE_REASON]);
8552 }
8553 }
8554 }
8555
8556 if (ast_strlen_zero(args.interface)) {
8557 args.interface = ast_strdupa(ast_channel_name(chan));
8558 temppos = strrchr(args.interface, '-');
8559 if (temppos) {
8560 *temppos = '\0';
8561 }
8562 }
8563
8564 if (!ast_strlen_zero(args.penalty)) {
8565 if ((sscanf(args.penalty, "%30d", &penalty) != 1) || penalty < 0) {
8566 ast_log(LOG_WARNING, "Penalty '%s' is invalid, must be an integer >= 0\n", args.penalty);
8567 penalty = 0;
8568 }
8569 }
8570
8571 if (!ast_strlen_zero(args.wrapuptime)) {
8572 tmp = args.wrapuptime;
8573 ast_strip(tmp);
8574 wrapuptime = atoi(tmp);
8575 if (wrapuptime < 0) {
8576 wrapuptime = 0;
8577 }
8578 } else {
8579 wrapuptime = 0;
8580 }
8581
8582 switch (add_to_queue(args.queuename, args.interface, args.membername, penalty, paused, queue_persistent_members, args.state_interface, reason, wrapuptime)) {
8583 case RES_OKAY:
8584 if (ast_strlen_zero(args.membername) || !log_membername_as_agent) {
8585 ast_queue_log(args.queuename, ast_channel_uniqueid(chan), args.interface, "ADDMEMBER", "%s", paused ? "PAUSED" : "");
8586 } else {
8587 ast_queue_log(args.queuename, ast_channel_uniqueid(chan), args.membername, "ADDMEMBER", "%s", paused ? "PAUSED" : "");
8588 }
8589 ast_log(LOG_NOTICE, "Added interface '%s' to queue '%s'\n", args.interface, args.queuename);
8590 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "ADDED");
8591 res = 0;
8592 break;
8593 case RES_EXISTS:
8594 ast_log(LOG_WARNING, "Unable to add interface '%s' to queue '%s': Already there\n", args.interface, args.queuename);
8595 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "MEMBERALREADY");
8596 res = 0;
8597 break;
8598 case RES_NOSUCHQUEUE:
8599 ast_log(LOG_WARNING, "Unable to add interface to queue '%s': No such queue\n", args.queuename);
8600 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "NOSUCHQUEUE");
8601 res = 0;
8602 break;
8603 case RES_OUTOFMEMORY:
8604 ast_log(LOG_ERROR, "Out of memory adding interface %s to queue %s\n", args.interface, args.queuename);
8605 break;
8606 }
8607
8608 return res;
8609}
static int queue_persistent_members
queues.conf [general] option
Definition: app_queue.c:1713
static int log_membername_as_agent
queues.conf [general] option
Definition: app_queue.c:1737
static const struct ast_app_option aqm_opts[128]
Definition: app_queue.c:1626
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:7752
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:298
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:957
#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:217
unsigned int flags
Definition: utils.h:218
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, and member::wrapuptime.

Referenced by load_module().

◆ AST_MODULE_SELF_SYM()

struct ast_module * AST_MODULE_SELF_SYM ( void  )

Definition at line 12137 of file app_queue.c.

◆ autopause2int()

static int autopause2int ( const char *  autopause)
static

Definition at line 2079 of file app_queue.c.

2080{
2081 int x;
2082 /*This 'double check' that default value is OFF */
2084 return QUEUE_AUTOPAUSE_OFF;
2085 }
2086
2087 /*This 'double check' is to ensure old values works */
2088 if(ast_true(autopause)) {
2089 return QUEUE_AUTOPAUSE_ON;
2090 }
2091
2092 for (x = 0; x < ARRAY_LEN(autopausesmodes); x++) {
2093 if (!strcasecmp(autopause, autopausesmodes[x].name)) {
2094 return autopausesmodes[x].autopause;
2095 }
2096 }
2097
2098 /*This 'double check' that default value is OFF */
2099 return QUEUE_AUTOPAUSE_OFF;
2100}
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:2235
int autopause
Definition: app_queue.c:1668
#define ARRAY_LEN(a)
Definition: utils.h:703

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

6196{
6197 /* disregarding penalty on too few members? */
6198 int membercount = ao2_container_count(q->members);
6199 unsigned char usepenalty = (membercount <= q->penaltymemberslimit) ? 0 : 1;
6200 int penalty = mem->penalty;
6201
6202 if (usepenalty) {
6203 if (qe->raise_penalty != INT_MAX && penalty < qe->raise_penalty) {
6204 /* Low penalty is raised up to the current minimum */
6205 penalty = qe->raise_penalty;
6206 }
6207 if ((qe->max_penalty != INT_MAX && penalty > qe->max_penalty) ||
6208 (qe->min_penalty != INT_MAX && penalty < qe->min_penalty)) {
6209 return -1;
6210 }
6211 } else {
6212 ast_debug(1, "Disregarding penalty, %d members and %d in penaltymemberslimit.\n",
6213 membercount, q->penaltymemberslimit);
6214 }
6215
6216 switch (q->strategy) {
6218 /* Everyone equal, except for penalty */
6219 tmp->metric = penalty * 1000000 * usepenalty;
6220 break;
6222 if (pos < qe->linpos) {
6223 tmp->metric = 1000 + pos;
6224 } else {
6225 if (pos > qe->linpos) {
6226 /* Indicate there is another priority */
6227 qe->linwrapped = 1;
6228 }
6229 tmp->metric = pos;
6230 }
6231 tmp->metric += penalty * 1000000 * usepenalty;
6232 break;
6235 pos = mem->queuepos;
6236 if (pos < q->rrpos) {
6237 tmp->metric = 1000 + pos;
6238 } else {
6239 if (pos > q->rrpos) {
6240 /* Indicate there is another priority */
6241 q->wrapped = 1;
6242 }
6243 tmp->metric = pos;
6244 }
6245 tmp->metric += penalty * 1000000 * usepenalty;
6246 break;
6248 tmp->metric = ast_random() % 1000;
6249 tmp->metric += penalty * 1000000 * usepenalty;
6250 break;
6252 tmp->metric = ast_random() % ((1 + penalty) * 1000);
6253 break;
6255 tmp->metric = mem->calls;
6256 tmp->metric += penalty * 1000000 * usepenalty;
6257 break;
6259 if (!mem->lastcall) {
6260 tmp->metric = 0;
6261 } else {
6262 tmp->metric = 1000000 - (time(NULL) - mem->lastcall);
6263 }
6264 tmp->metric += penalty * 1000000 * usepenalty;
6265 break;
6266 default:
6267 ast_log(LOG_WARNING, "Can't calculate metric for unknown strategy %d\n", q->strategy);
6268 break;
6269 }
6270 return 0;
6271}
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:2018
int penaltymemberslimit
Definition: app_queue.c:2002
unsigned int wrapped
Definition: app_queue.c:1970
int strategy
Definition: app_queue.c:1975
int queuepos
Definition: app_queue.c:1870
time_t lastcall
Definition: app_queue.c:1874
int calls
Definition: app_queue.c:1864
int linpos
Definition: app_queue.c:1843
int max_penalty
Definition: app_queue.c:1839
int raise_penalty
Definition: app_queue.c:1841
int min_penalty
Definition: app_queue.c:1840
int linwrapped
Definition: app_queue.c:1844
long int ast_random(void)
Definition: utils.c:2348

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, callattempt::metric, 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, and call_queue::wrapped.

Referenced by try_calling().

◆ callattempt_free()

static void callattempt_free ( struct callattempt doomed)
static

Definition at line 4598 of file app_queue.c.

4599{
4600 if (doomed->member) {
4601 ao2_ref(doomed->member, -1);
4602 }
4604 ast_free(doomed->orig_chan_name);
4605 ast_free(doomed);
4606}
#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:2040
struct ast_party_connected_line connected
Definition: app_queue.c:1806
char * orig_chan_name
Definition: app_queue.c:1817
struct member * member
Definition: app_queue.c:1804

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

4809{
4810 struct member *memberp = call->member;
4811 int wrapuptime;
4812
4813 if (memberp->paused) {
4814 ast_debug(1, "%s paused, can't receive call\n", call->interface);
4815 return 0;
4816 }
4817
4818 if (!memberp->ringinuse && !member_status_available(memberp->status)) {
4819 ast_debug(1, "%s not available, can't receive call\n", call->interface);
4820 return 0;
4821 }
4822
4823 if (memberp->lastqueue) {
4824 wrapuptime = get_wrapuptime(memberp->lastqueue, memberp);
4825 } else {
4826 wrapuptime = get_wrapuptime(qe->parent, memberp);
4827 }
4828 if (wrapuptime && (time(NULL) - memberp->lastcall) < wrapuptime) {
4829 ast_debug(1, "Wrapuptime not yet expired on queue %s for %s\n",
4830 (memberp->lastqueue ? memberp->lastqueue->name : qe->parent->name),
4831 call->interface);
4832 return 0;
4833 }
4834
4835 if (use_weight && compare_weight(qe->parent, memberp)) {
4836 ast_debug(1, "Priority queue delaying call to %s:%s\n",
4837 qe->parent->name, call->interface);
4838 return 0;
4839 }
4840
4842 ast_debug(1, "Another caller was waiting longer; delaying call to %s:%s\n",
4843 qe->parent->name, call->interface);
4844 return 0;
4845 }
4846
4847 if (!memberp->ringinuse) {
4848 struct member *mem;
4849
4851
4852 mem = ao2_find(pending_members, memberp,
4854 if (mem) {
4855 /*
4856 * If found that means this member is currently being attempted
4857 * from another calling thread, so stop trying from this thread
4858 */
4859 ast_debug(1, "%s has another call trying, can't receive call\n",
4860 call->interface);
4861 ao2_ref(mem, -1);
4863 return 0;
4864 }
4865
4866 /*
4867 * If not found add it to the container so another queue
4868 * won't attempt to call this member at the same time.
4869 */
4870 ast_debug(3, "Add %s to pending_members\n", memberp->membername);
4871 ao2_link(pending_members, memberp);
4873
4874 /*
4875 * The queue member is available. Get current status to be sure
4876 * because the device state and extension state callbacks may
4877 * not have updated the status yet.
4878 */
4880 ast_debug(1, "%s actually not available, can't receive call\n",
4881 call->interface);
4882 pending_members_remove(memberp);
4883 return 0;
4884 }
4885 }
4886
4887 return 1;
4888}
static int is_longest_waiting_caller(struct queue_ent *caller, struct member *member)
Definition: app_queue.c:4727
static int get_wrapuptime(struct call_queue *q, struct member *member)
Return wrapuptime.
Definition: app_queue.c:2122
static int compare_weight(struct call_queue *rq, struct member *member)
Definition: app_queue.c:4693
static struct ao2_container * pending_members
Definition: app_queue.c:2649
static int force_longest_waiting_caller
queues.conf [general] option
Definition: app_queue.c:1740
static void pending_members_remove(struct member *mem)
Definition: app_queue.c:2700
static int get_queue_member_status(struct member *cur)
Return the current state of a member.
Definition: app_queue.c:2986
static int use_weight
Records that one or more queues use weight.
Definition: app_queue.c:1716
static int member_status_available(int status)
Definition: app_queue.c:4794
#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:2403
int status
Definition: app_queue.c:1867
unsigned int ringinuse
Definition: app_queue.c:1881
struct call_queue * lastqueue
Definition: app_queue.c:1877
struct call_queue * parent
Definition: app_queue.c:1822

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

7806{
7807 struct call_queue *q;
7808 struct queue_ent *current, *prev = NULL, *caller_qe = NULL;
7809 int res = RES_NOSUCHQUEUE;
7810
7811 /*! \note Ensure the appropriate realtime queue is loaded. Note that this
7812 * short-circuits if the queue is already in memory. */
7813 if (!(q = find_load_queue_rt_friendly(queuename))) {
7814 return res;
7815 }
7816
7817 ao2_lock(q);
7818 res = RES_NOT_CALLER;
7819 for (current = q->head; current; current = current->next) {
7820 if (strcmp(ast_channel_name(current->chan), caller) == 0) {
7821 ast_debug(1, "%s Caller new priority %d in queue %s\n",
7822 caller, priority, queuename);
7823 current->prio = priority;
7824 if (immediate) {
7825 /* This caller is being immediately moved in the queue so remove them */
7826 if (prev) {
7827 prev->next = current->next;
7828 } else {
7829 q->head = current->next;
7830 }
7831 caller_qe = current;
7832 /* The position for all callers is not recalculated in here as it will
7833 * be updated when the moved caller is inserted back into the queue
7834 */
7835 }
7836 res = RES_OKAY;
7837 break;
7838 } else if (immediate) {
7839 prev = current;
7840 }
7841 }
7842
7843 if (caller_qe) {
7844 int inserted = 0, pos = 0;
7845
7846 /* If a caller queue entry exists, we are applying their priority immediately
7847 * and have to reinsert them at the correct position.
7848 */
7849 prev = NULL;
7850 current = q->head;
7851 while (current) {
7852 if (!inserted && (caller_qe->prio > current->prio)) {
7853 insert_entry(q, prev, caller_qe, &pos);
7854 inserted = 1;
7855 }
7856
7857 /* We always update the position as it may have changed */
7858 current->pos = ++pos;
7859
7860 /* Move to the next caller in the queue */
7861 prev = current;
7862 current = current->next;
7863 }
7864
7865 if (!inserted) {
7866 insert_entry(q, prev, caller_qe, &pos);
7867 }
7868 }
7869
7870 ao2_unlock(q);
7871 return res;
7872}
#define RES_NOT_CALLER
Definition: app_queue.c:1693
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:2220
static int priority
size_t current
struct queue_ent * head
Definition: app_queue.c:2019
struct queue_ent * next
Definition: app_queue.c:1853

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

3188{
3189 q->holdtime = 0;
3190 q->callscompleted = 0;
3191 q->callsabandoned = 0;
3192 q->callscompletedinsl = 0;
3193 q->callsabandonedinsl = 0;
3194 q->talktime = 0;
3195
3196 if (q->members) {
3197 struct member *mem;
3198 struct ao2_iterator mem_iter = ao2_iterator_init(q->members, 0);
3199 while ((mem = ao2_iterator_next(&mem_iter))) {
3200 mem->calls = 0;
3201 mem->callcompletedinsl = 0;
3202 mem->lastcall = 0;
3203 mem->starttime = 0;
3204 ao2_ref(mem, -1);
3205 }
3206 ao2_iterator_destroy(&mem_iter);
3207 }
3208}
#define ao2_iterator_next(iter)
Definition: astobj2.h:1911
int talktime
Definition: app_queue.c:1992
int callsabandoned
Definition: app_queue.c:1994
int callscompleted
Definition: app_queue.c:1993
int callsabandonedinsl
Definition: app_queue.c:1995
int callscompletedinsl
Definition: app_queue.c:1997
int holdtime
Definition: app_queue.c:1991
time_t starttime
Definition: app_queue.c:1873
int callcompletedinsl
Definition: app_queue.c:1871

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

10158{
10159 struct call_queue *q;
10160 struct ao2_iterator queue_iter;
10161
10162 queue_iter = ao2_iterator_init(queues, 0);
10163 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
10164 ao2_lock(q);
10165 if (ast_strlen_zero(queuename) || !strcasecmp(q->name, queuename))
10166 clear_queue(q);
10167 ao2_unlock(q);
10168 queue_t_unref(q, "Done with iterator");
10169 }
10170 ao2_iterator_destroy(&queue_iter);
10171 return 0;
10172}
static void clear_queue(struct call_queue *q)
Definition: app_queue.c:3187

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

4694{
4695 struct call_queue *q;
4696 struct member *mem;
4697 int found = 0;
4698 struct ao2_iterator queue_iter;
4699
4700 queue_iter = ao2_iterator_init(queues, 0);
4701 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
4702 if (q == rq) { /* don't check myself, could deadlock */
4703 queue_t_unref(q, "Done with iterator");
4704 continue;
4705 }
4706 ao2_lock(q);
4707 if (q->count && q->members) {
4708 if ((mem = ao2_find(q->members, member, OBJ_POINTER))) {
4709 ast_debug(1, "Found matching member %s in queue '%s'\n", mem->interface, q->name);
4710 if (q->weight > rq->weight && q->count >= num_available_members(q)) {
4711 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);
4712 found = 1;
4713 }
4714 ao2_ref(mem, -1);
4715 }
4716 }
4717 ao2_unlock(q);
4718 queue_t_unref(q, "Done with iterator");
4719 if (found) {
4720 break;
4721 }
4722 }
4723 ao2_iterator_destroy(&queue_iter);
4724 return found;
4725}
static int num_available_members(struct call_queue *q)
Get the number of members available to accept a call.
Definition: app_queue.c:4660
#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 10493 of file app_queue.c.

10494{
10495 struct call_queue *q;
10496 char *ret = NULL;
10497 int which = 0;
10498 int wordlen = strlen(word);
10499 struct ao2_iterator queue_iter;
10500 const char *word_list = NULL;
10501
10502 /* for certain commands, already completed items should be left out of
10503 * the list */
10504 if (word_list_offset && strlen(line) >= word_list_offset) {
10505 word_list = line + word_list_offset;
10506 }
10507
10508 queue_iter = ao2_iterator_init(queues, 0);
10509 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
10510 if (!strncasecmp(word, q->name, wordlen) && ++which > state
10511 && (!word_list_offset || !word_list || !word_in_list(word_list, q->name))) {
10512 ret = ast_strdup(q->name);
10513 queue_t_unref(q, "Done with iterator");
10514 break;
10515 }
10516 queue_t_unref(q, "Done with iterator");
10517 }
10518 ao2_iterator_destroy(&queue_iter);
10519
10520 /* Pretend "rules" is at the end of the queues list in certain
10521 * circumstances since it is an alternate command that should be
10522 * tab-completable for "queue show" */
10523 if (!ret && which == state && !wordlen && !strncmp("queue show", line, 10)) {
10524 ret = ast_strdup("rules");
10525 }
10526
10527 return ret;
10528}
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:10434
#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 11000 of file app_queue.c.

11001{
11002 /* 0 - queue; 1 - add; 2 - member; 3 - <interface>; 4 - to; 5 - <queue>; 6 - penalty; 7 - <penalty>; 8 - as; 9 - <membername> */
11003 switch (pos) {
11004 case 3: /* Don't attempt to complete name of interface (infinite possibilities) */
11005 return NULL;
11006 case 4: /* only one possible match, "to" */
11007 return state == 0 ? ast_strdup("to") : NULL;
11008 case 5: /* <queue> */
11009 return complete_queue(line, word, pos, state, 0);
11010 case 6: /* only one possible match, "penalty" */
11011 return state == 0 ? ast_strdup("penalty") : NULL;
11012 case 7:
11013 if (0 <= state && state < 100) { /* 0-99 */
11014 char *num;
11015 if ((num = ast_malloc(3))) {
11016 sprintf(num, "%d", state);
11017 }
11018 return num;
11019 } else {
11020 return NULL;
11021 }
11022 case 8: /* only one possible match, "as" */
11023 return state == 0 ? ast_strdup("as") : NULL;
11024 case 9: /* Don't attempt to complete name of member (infinite possibilities) */
11025 return NULL;
11026 default:
11027 return NULL;
11028 }
11029}
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:10493
#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 11425 of file app_queue.c.

11426{
11427 /* 0 - queue; 1 - pause; 2 - member; 3 - <interface>; 4 - queue; 5 - <queue>; 6 - reason; 7 - <reason> */
11428 switch (pos) {
11429 case 3: /* Don't attempt to complete name of interface (infinite possibilities) */
11430 return NULL;
11431 case 4: /* only one possible match, "queue" */
11432 return state == 0 ? ast_strdup("queue") : NULL;
11433 case 5: /* <queue> */
11434 return complete_queue(line, word, pos, state, 0);
11435 case 6: /* "reason" */
11436 return state == 0 ? ast_strdup("reason") : NULL;
11437 case 7: /* Can't autocomplete a reason, since it's 100% customizeable */
11438 return NULL;
11439 default:
11440 return NULL;
11441 }
11442}

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

11261{
11262 int which = 0;
11263 struct call_queue *q;
11264 struct member *m;
11265 struct ao2_iterator queue_iter;
11266 struct ao2_iterator mem_iter;
11267 int wordlen = strlen(word);
11268
11269 /* 0 - queue; 1 - remove; 2 - member; 3 - <member>; 4 - from; 5 - <queue> */
11270 if (pos > 5 || pos < 3) {
11271 return NULL;
11272 }
11273 if (pos == 4) { /* only one possible match, 'from' */
11274 return (state == 0 ? ast_strdup("from") : NULL);
11275 }
11276
11277 if (pos == 5) { /* No need to duplicate code */
11278 return complete_queue(line, word, pos, state, 0);
11279 }
11280
11281 /* here is the case for 3, <member> */
11282 queue_iter = ao2_iterator_init(queues, 0);
11283 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
11284 ao2_lock(q);
11285 mem_iter = ao2_iterator_init(q->members, 0);
11286 while ((m = ao2_iterator_next(&mem_iter))) {
11287 if (!strncasecmp(word, m->membername, wordlen) && ++which > state) {
11288 char *tmp;
11289 tmp = ast_strdup(m->interface);
11290 ao2_ref(m, -1);
11291 ao2_iterator_destroy(&mem_iter);
11292 ao2_unlock(q);
11293 queue_t_unref(q, "Done with iterator, returning interface name");
11294 ao2_iterator_destroy(&queue_iter);
11295 return tmp;
11296 }
11297 ao2_ref(m, -1);
11298 }
11299 ao2_iterator_destroy(&mem_iter);
11300 ao2_unlock(q);
11301 queue_t_unref(q, "Done with iterator");
11302 }
11303 ao2_iterator_destroy(&queue_iter);
11304
11305 return NULL;
11306}

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, and queues.

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

11621{
11622 int which = 0;
11623 struct rule_list *rl_iter;
11624 int wordlen = strlen(word);
11625 char *ret = NULL;
11626 if (pos != 3) /* Wha? */ {
11627 return NULL;
11628 }
11629
11631 AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) {
11632 if (!strncasecmp(word, rl_iter->name, wordlen) && ++which > state) {
11633 ret = ast_strdup(rl_iter->name);
11634 break;
11635 }
11636 }
11638
11639 return ret;
11640}
#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:2025
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 11499 of file app_queue.c.

11500{
11501 /* 0 - queue; 1 - set; 2 - penalty/ringinuse; 3 - <value>; 4 - on; 5 - <member>; 6 - in; 7 - <queue>;*/
11502 switch (pos) {
11503 case 4:
11504 if (state == 0) {
11505 return ast_strdup("on");
11506 } else {
11507 return NULL;
11508 }
11509 case 6:
11510 if (state == 0) {
11511 return ast_strdup("in");
11512 } else {
11513 return NULL;
11514 }
11515 case 7:
11516 return complete_queue(line, word, pos, state, 0);
11517 default:
11518 return NULL;
11519 }
11520}

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

10531{
10532 if (pos == 2) {
10533 return complete_queue(line, word, pos, state, 0);
10534 }
10535 return NULL;
10536}

References complete_queue(), and NULL.

Referenced by queue_show().

◆ compress_char()

static int compress_char ( const char  c)
static

Definition at line 3046 of file app_queue.c.

3047{
3048 if (c < 32) {
3049 return 0;
3050 } else if (c > 96) {
3051 return c - 64;
3052 }
3053 return c - 32;
3054}
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 2913 of file app_queue.c.

2914{
2915 struct ast_context *c = NULL;
2916
2917 c = ast_context_find(parent);
2918 if (!c) {
2919 /* well, if parent doesn't exist, how can the child be included in it? */
2920 return 0;
2921 }
2922 if (!strcmp(ast_get_context_name(c), parent)) {
2923 /* found the context of the hint app_queue is using. Now, see
2924 if that context includes the one that just changed state */
2925 struct ast_include *inc = NULL;
2926
2927 while ((inc = (struct ast_include*) ast_walk_context_includes(c, inc))) {
2928 const char *includename = ast_get_include_name(inc);
2929 if (!strcasecmp(child, includename)) {
2930 return 1;
2931 }
2932 /* recurse on this context, for nested includes. The
2933 PBX extension parser will prevent infinite recursion. */
2934 if (context_included(includename, child)) {
2935 return 1;
2936 }
2937 }
2938 }
2939 return 0;
2940}
static int context_included(const char *parent, const char *child)
Returns if one context includes another context.
Definition: app_queue.c:2913
const struct ast_include * ast_walk_context_includes(const struct ast_context *con, const struct ast_include *inc)
Definition: pbx.c:8675
struct ast_context * ast_context_find(const char *name)
Find a context.
Definition: extconf.c:4170
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:299
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 8646 of file app_queue.c.

8647{
8648 struct penalty_rule *pr_iter;
8649 struct rule_list *rl_iter;
8650 const char *tmp = ast_strlen_zero(rulename) ? qe->parent->defaultrule : rulename;
8652 AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) {
8653 if (!strcasecmp(rl_iter->name, tmp)) {
8654 break;
8655 }
8656 }
8657 if (rl_iter) {
8658 AST_LIST_TRAVERSE(&rl_iter->rules, pr_iter, list) {
8659 struct penalty_rule *new_pr = ast_calloc(1, sizeof(*new_pr));
8660 if (!new_pr) {
8661 ast_log(LOG_ERROR, "Memory allocation error when copying penalty rules! Aborting!\n");
8662 break;
8663 }
8664 new_pr->time = pr_iter->time;
8665 new_pr->max_value = pr_iter->max_value;
8666 new_pr->min_value = pr_iter->min_value;
8667 new_pr->raise_value = pr_iter->raise_value;
8668 new_pr->max_relative = pr_iter->max_relative;
8669 new_pr->min_relative = pr_iter->min_relative;
8670 new_pr->raise_relative = pr_iter->raise_relative;
8671 AST_LIST_INSERT_TAIL(&qe->qe_rules, new_pr, list);
8672 }
8673 }
8675}
#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:1960
int raise_relative
Definition: app_queue.c:1912
struct penalty_rule::@52 list
int min_relative
Definition: app_queue.c:1911
int max_relative
Definition: app_queue.c:1910
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, and penalty_rule::time.

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

3002{
3003 struct member *cur;
3004
3005 if ((cur = ao2_alloc(sizeof(*cur), destroy_queue_member_cb))) {
3006 cur->ringinuse = ringinuse;
3007 cur->penalty = penalty;
3008 cur->paused = paused;
3009 cur->wrapuptime = wrapuptime;
3010 if (paused) {
3011 time(&cur->lastpause); /* Update time of last pause */
3012 }
3013 time(&cur->logintime);
3014 ast_copy_string(cur->interface, interface, sizeof(cur->interface));
3017 } else {
3019 }
3021 ast_copy_string(cur->membername, membername, sizeof(cur->membername));
3022 } else {
3023 ast_copy_string(cur->membername, interface, sizeof(cur->membername));
3024 }
3025 if (!strchr(cur->interface, '/')) {
3026 ast_log(LOG_WARNING, "No location at interface '%s'\n", interface);
3027 }
3028 if (!strncmp(cur->state_interface, "hint:", 5)) {
3029 char *tmp = ast_strdupa(cur->state_interface), *context = tmp;
3030 char *exten = strsep(&context, "@") + 5;
3031
3032 ast_copy_string(cur->state_exten, exten, sizeof(cur->state_exten));
3033 ast_copy_string(cur->state_context, S_OR(context, "default"), sizeof(cur->state_context));
3034
3036 } else {
3037 cur->state_id = -1;
3038 }
3039 cur->status = get_queue_member_status(cur);
3040 }
3041
3042 return cur;
3043}
static int extension_state_cb(const char *context, const char *exten, struct ast_state_cb_info *info, void *data)
Definition: app_queue.c:2942
static void destroy_queue_member_cb(void *obj)
Definition: app_queue.c:2991
char * strsep(char **str, const char *delims)
#define ao2_alloc(data_size, destructor_fn)
Definition: astobj2.h:409
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:3844
#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:1876
char state_exten[AST_MAX_EXTENSION]
Definition: app_queue.c:1858
char state_context[AST_MAX_CONTEXT]
Definition: app_queue.c:1859
int state_id
Definition: app_queue.c:1861
time_t lastpause
Definition: app_queue.c:1875

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(), 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 3863 of file app_queue.c.

3864{
3865 struct call_queue *q = obj;
3866 int i;
3867
3868 free_members(q, 1);
3870 for (i = 0; i < MAX_PERIODIC_ANNOUNCEMENTS; i++) {
3871 if (q->sound_periodicannounce[i]) {
3873 }
3874 }
3875 ao2_ref(q->members, -1);
3876}
#define MAX_PERIODIC_ANNOUNCEMENTS
Definition: app_queue.c:1679
static void free_members(struct call_queue *q, int all)
Iterate through queue's member list and delete them.
Definition: app_queue.c:3847
#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:1962

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

2992{
2993 struct member *mem = obj;
2994
2995 if (mem->state_id != -1) {
2997 }
2998}
int ast_extension_state_del(int id, ast_state_cb_type change_cb)
Deletes a state change watcher by ID.
Definition: pbx.c:3877

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

2778{
2779 struct ao2_iterator miter, qiter;
2780 struct ast_device_state_message *dev_state;
2781 struct member *m;
2782 struct call_queue *q;
2783 char interface[80], *slash_pos;
2784 int found = 0; /* Found this member in any queue */
2785 int found_member; /* Found this member in this queue */
2786 int avail = 0; /* Found an available member in this queue */
2787
2789 return;
2790 }
2791
2792 dev_state = stasis_message_data(msg);
2793 if (dev_state->eid) {
2794 /* ignore non-aggregate states */
2795 return;
2796 }
2797
2798 qiter = ao2_iterator_init(queues, 0);
2799 while ((q = ao2_t_iterator_next(&qiter, "Iterate over queues"))) {
2800 ao2_lock(q);
2801
2802 avail = 0;
2803 found_member = 0;
2804 miter = ao2_iterator_init(q->members, 0);
2805 for (; (m = ao2_iterator_next(&miter)); ao2_ref(m, -1)) {
2806 if (!found_member) {
2807 ast_copy_string(interface, m->state_interface, sizeof(interface));
2808
2809 if ((slash_pos = strchr(interface, '/'))) {
2810 if (!strncasecmp(interface, "Local/", 6) && (slash_pos = strchr(slash_pos + 1, '/'))) {
2811 *slash_pos = '\0';
2812 }
2813 }
2814
2815 if (!strcasecmp(interface, dev_state->device)) {
2816 found_member = 1;
2817 update_status(q, m, dev_state->state);
2818 }
2819 }
2820
2821 /* check every member until we find one NOT_INUSE */
2822 if (!avail) {
2823 avail = is_member_available(q, m);
2824 }
2825 if (avail && found_member) {
2826 /* early exit as we've found an available member and the member of interest */
2827 ao2_ref(m, -1);
2828 break;
2829 }
2830 }
2831
2832 if (found_member) {
2833 found = 1;
2834 if (avail) {
2836 } else {
2838 }
2839 }
2840
2841 ao2_iterator_destroy(&miter);
2842
2843 ao2_unlock(q);
2844 queue_t_unref(q, "Done with iterator");
2845 }
2846 ao2_iterator_destroy(&qiter);
2847
2848 if (found) {
2849 ast_debug(1, "Device '%s' changed to state '%u' (%s)\n",
2850 dev_state->device,
2851 dev_state->state,
2852 ast_devstate2str(dev_state->state));
2853 } else {
2854 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",
2855 dev_state->device,
2856 dev_state->state,
2857 ast_devstate2str(dev_state->state));
2858 }
2859
2860 return;
2861}
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:2711
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:240
@ 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 4778 of file app_queue.c.

4779{
4780 o->stillgoing = 0;
4781 ast_hangup(o->chan);
4783 o->chan = NULL;
4784}
void ast_hangup(struct ast_channel *chan)
Hang up a channel.
Definition: channel.c:2511
struct ast_channel * chan
Definition: app_queue.c:1801
unsigned int stillgoing
Definition: app_queue.c:1814

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

10205{
10206 if (s) {
10207 astman_append(s, "%s\r\n", str);
10208 } else {
10209 ast_cli(fd, "%s\n", str);
10210 }
10211}
const char * str
Definition: app_jack.c:150
void ast_cli(int fd, const char *fmt,...)
Definition: clicompat.c:6
void astman_append(struct mansession *s, const char *fmt,...)
Definition: manager.c:1903

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:1710

Definition at line 7644 of file app_queue.c.

7645{
7646 struct member *cur_member;
7647 struct ast_str *value;
7648 struct ao2_iterator mem_iter;
7649
7650 if (!pm_queue) {
7651 return;
7652 }
7653
7654 /* 4K is a reasonable default for most applications, but we grow to
7655 * accommodate more if necessary. */
7656 if (!(value = ast_str_create(4096))) {
7657 return;
7658 }
7659
7660 mem_iter = ao2_iterator_init(pm_queue->members, 0);
7661 while ((cur_member = ao2_iterator_next(&mem_iter))) {
7662 if (!cur_member->dynamic) {
7663 ao2_ref(cur_member, -1);
7664 continue;
7665 }
7666
7667 ast_str_append(&value, 0, "%s%s;%d;%d;%s;%s;%s;%d",
7668 ast_str_strlen(value) ? "|" : "",
7669 cur_member->interface,
7670 cur_member->penalty,
7671 cur_member->paused,
7672 cur_member->membername,
7673 cur_member->state_interface,
7674 cur_member->reason_paused,
7675 cur_member->wrapuptime);
7676
7677 ao2_ref(cur_member, -1);
7678 }
7679 ao2_iterator_destroy(&mem_iter);
7680
7681 if (ast_str_strlen(value) && !cur_member) {
7682 if (ast_db_put(pm_family, pm_queue->name, ast_str_buffer(value))) {
7683 ast_log(LOG_WARNING, "failed to create persistent dynamic entry!\n");
7684 }
7685 } else {
7686 /* Delete the entry if the queue is empty or there is an error */
7687 ast_db_del(pm_family, pm_queue->name);
7688 }
7689
7690 ast_free(value);
7691}
int ast_db_put(const char *family, const char *key, const char *value)
Store value addressed by family/key.
Definition: db.c:335
int ast_db_del(const char *family, const char *key)
Delete entry in astdb.
Definition: db.c:472
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 6993 of file app_queue.c.

6994{
6995 struct queue_end_bridge *qeb = data;
6996 struct call_queue *q = qeb->q;
6997 struct ast_channel *chan = qeb->chan;
6998
6999 if (ao2_ref(qeb, -1) == 1) {
7000 set_queue_variables(q, chan);
7001 /* This unrefs the reference we made in try_calling when we allocated qeb */
7002 queue_t_unref(q, "Expire bridge_config reference");
7003 }
7004}
static void set_queue_variables(struct call_queue *q, struct ast_channel *chan)
Set variables of queue.
Definition: app_queue.c:2194
Main Channel structure associated with a channel.
struct call_queue * q
Definition: app_queue.c:6982
struct ast_channel * chan
Definition: app_queue.c:6983

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

6987{
6988 struct queue_end_bridge *qeb = bconfig->end_bridge_callback_data;
6989 ao2_ref(qeb, +1);
6990 qeb->chan = originator;
6991}
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 7033 of file app_queue.c.

7035{
7036 const char *m = input;
7037 char escaped[size];
7038 char *p;
7039
7040 for (p = escaped; p < escaped + size - 1; p++, m++) {
7041 switch (*m) {
7042 case '^':
7043 if (*(m + 1) == '{') {
7044 *p = '$';
7045 }
7046 break;
7047 case ',':
7048 *p++ = '\\';
7049 /* Fall through */
7050 default:
7051 *p = *m;
7052 }
7053 if (*m == '\0')
7054 break;
7055 }
7056
7057 if (p == escaped + size) {
7058 escaped[size - 1] = '\0';
7059 }
7060
7061 pbx_substitute_variables_helper(chan, escaped, output, size - 1);
7062}
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 2942 of file app_queue.c.

2943{
2944 struct ao2_iterator miter, qiter;
2945 struct member *m;
2946 struct call_queue *q;
2947 int state = info->exten_state;
2948 int found = 0, device_state = extensionstate2devicestate(state);
2949
2950 /* only interested in extension state updates involving device states */
2951 if (info->reason != AST_HINT_UPDATE_DEVICE) {
2952 return 0;
2953 }
2954
2955 qiter = ao2_iterator_init(queues, 0);
2956 while ((q = ao2_t_iterator_next(&qiter, "Iterate through queues"))) {
2957 ao2_lock(q);
2958
2959 miter = ao2_iterator_init(q->members, 0);
2960 for (; (m = ao2_iterator_next(&miter)); ao2_ref(m, -1)) {
2961 if (!strcmp(m->state_exten, exten) &&
2963 /* context could be included in m->state_context. We need to check. */
2964 found = 1;
2965 update_status(q, m, device_state);
2966 }
2967 }
2968 ao2_iterator_destroy(&miter);
2969
2970 ao2_unlock(q);
2971 queue_t_unref(q, "Done with iterator");
2972 }
2973 ao2_iterator_destroy(&qiter);
2974
2975 if (found) {
2976 ast_debug(1, "Extension '%s@%s' changed to state '%d' (%s)\n", exten, context, device_state, ast_devstate2str(device_state));
2977 } else {
2978 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",
2979 exten, context, device_state, ast_devstate2str(device_state));
2980 }
2981
2982 return 0;
2983}
static int extensionstate2devicestate(int state)
Helper function which converts from extension state to device state values.
Definition: app_queue.c:2864
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 2864 of file app_queue.c.

2865{
2866 switch (state) {
2869 break;
2872 break;
2873 case AST_EXTENSION_BUSY:
2875 break;
2878 break;
2881 break;
2884 break;
2887 break;
2890 break;
2893 default:
2895 break;
2896 }
2897
2898 return state;
2899}
enum cc_state state
Definition: ccss.c:399
@ 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 5036 of file app_queue.c.

5037{
5038 struct callattempt *best = NULL, *cur;
5039
5040 for (cur = outgoing; cur; cur = cur->q_next) {
5041 if (cur->stillgoing && /* Not already done */
5042 !cur->chan && /* Isn't already going */
5043 (!best || cur->metric < best->metric)) { /* We haven't found one yet, or it's better */
5044 best = cur;
5045 }
5046 }
5047
5048 return best;
5049}
We define a custom "local user" structure because we use it not only for keeping track of what is in ...
Definition: app_queue.c:1798

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

4047{
4048 struct ast_variable *queue_vars;
4049 struct ast_config *member_config = NULL;
4050 struct call_queue *q = NULL, tmpq = {
4051 .name = queuename,
4052 };
4053 int prev_weight = 0;
4054
4055 /* Find the queue in the in-core list first. */
4056 q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Look for queue in memory first");
4057
4058 if (!q || q->realtime) {
4059 /*! \note Load from realtime before taking the "queues" container lock, to avoid blocking all
4060 queue operations while waiting for the DB.
4061
4062 This will be two separate database transactions, so we might
4063 see queue parameters as they were before another process
4064 changed the queue and member list as it was after the change.
4065 Thus we might see an empty member list when a queue is
4066 deleted. In practise, this is unlikely to cause a problem. */
4067
4068 queue_vars = ast_load_realtime("queues", "name", queuename, SENTINEL);
4069 if (queue_vars) {
4070 member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name", queuename, SENTINEL);
4071 if (!member_config) {
4072 ast_debug(1, "No queue_members defined in config extconfig.conf\n");
4073 member_config = ast_config_new();
4074 }
4075 }
4076 if (q) {
4077 prev_weight = q->weight ? 1 : 0;
4078 queue_t_unref(q, "Need to find realtime queue");
4079 }
4080
4081 q = find_queue_by_name_rt(queuename, queue_vars, member_config);
4082 ast_config_destroy(member_config);
4083 ast_variables_destroy(queue_vars);
4084
4085 /* update the use_weight value if the queue's has gained or lost a weight */
4086 if (q) {
4087 if (!q->weight && prev_weight) {
4089 }
4090 if (q->weight && !prev_weight) {
4092 }
4093 }
4094 /* Other cases will end up with the proper value for use_weight */
4095 } else {
4097 }
4098 return q;
4099}
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:3902
static void update_realtime_members(struct call_queue *q)
Definition: app_queue.c:4151
#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:3272
struct ast_variable * ast_load_realtime(const char *family,...) attribute_sentinel
Definition: main/config.c:3773
void ast_variables_destroy(struct ast_variable *var)
Free variable list.
Definition: extconf.c:1260
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:764
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_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 12117 of file app_queue.c.

12118{
12119 struct member *mem = NULL;
12120 struct call_queue *q;
12121
12122 if ((q = find_load_queue_rt_friendly(queuename))) {
12123 ao2_lock(q);
12124 mem = ao2_find(q->members, interface, OBJ_KEY);
12125 ao2_unlock(q);
12126 queue_t_unref(q, "Expiring temporary reference.");
12127 }
12128 return mem;
12129}
#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 3902 of file app_queue.c.

3903{
3904 struct ast_variable *v;
3905 struct call_queue *q, tmpq = {
3906 .name = queuename,
3907 };
3908 struct member *m;
3909 struct ao2_iterator mem_iter;
3910 char *category = NULL;
3911 const char *tmp_name;
3912 char *tmp;
3913 char tmpbuf[64]; /* Must be longer than the longest queue param name. */
3914
3915 /* Static queues override realtime. */
3916 if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Check if static queue exists"))) {
3917 ao2_lock(q);
3918 if (!q->realtime) {
3919 if (q->dead) {
3920 ao2_unlock(q);
3921 queue_t_unref(q, "Queue is dead; can't return it");
3922 return NULL;
3923 }
3924 ast_log(LOG_WARNING, "Static queue '%s' already exists. Not loading from realtime\n", q->name);
3925 ao2_unlock(q);
3926 return q;
3927 }
3928 } else if (!member_config) {
3929 /* Not found in the list, and it's not realtime ... */
3930 return NULL;
3931 }
3932 /* Check if queue is defined in realtime. */
3933 if (!queue_vars) {
3934 /* Delete queue from in-core list if it has been deleted in realtime. */
3935 if (q) {
3936 /*! \note Hmm, can't seem to distinguish a DB failure from a not
3937 found condition... So we might delete an in-core queue
3938 in case of DB failure. */
3939 ast_debug(1, "Queue %s not found in realtime.\n", queuename);
3940
3941 q->dead = 1;
3942 /* Delete if unused (else will be deleted when last caller leaves). */
3943 queues_t_unlink(queues, q, "Unused; removing from container");
3944 ao2_unlock(q);
3945 queue_t_unref(q, "Queue is dead; can't return it");
3946 }
3947 return NULL;
3948 }
3949
3950 /* Create a new queue if an in-core entry does not exist yet. */
3951 if (!q) {
3952 struct ast_variable *tmpvar = NULL;
3953 if (!(q = alloc_queue(queuename))) {
3954 return NULL;
3955 }
3956 ao2_lock(q);
3957 clear_queue(q);
3958 q->realtime = 1;
3959 /*Before we initialize the queue, we need to set the strategy, so that linear strategy
3960 * will allocate the members properly
3961 */
3962 for (tmpvar = queue_vars; tmpvar; tmpvar = tmpvar->next) {
3963 if (!strcasecmp(tmpvar->name, "strategy")) {
3964 q->strategy = strat2int(tmpvar->value);
3965 if (q->strategy < 0) {
3966 ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n",
3967 tmpvar->value, q->name);
3969 }
3970 break;
3971 }
3972 }
3973 /* We traversed all variables and didn't find a strategy */
3974 if (!tmpvar) {
3976 }
3977 queues_t_link(queues, q, "Add queue to container");
3978 }
3979 init_queue(q); /* Ensure defaults for all parameters not set explicitly. */
3980
3981 memset(tmpbuf, 0, sizeof(tmpbuf));
3982 for (v = queue_vars; v; v = v->next) {
3983 /* Convert to dashes `-' from underscores `_' as the latter are more SQL friendly. */
3984 if (strchr(v->name, '_')) {
3985 ast_copy_string(tmpbuf, v->name, sizeof(tmpbuf));
3986 tmp_name = tmpbuf;
3987 tmp = tmpbuf;
3988 while ((tmp = strchr(tmp, '_'))) {
3989 *tmp++ = '-';
3990 }
3991 } else {
3992 tmp_name = v->name;
3993 }
3994
3995 /* NULL values don't get returned from realtime; blank values should
3996 * still get set. If someone doesn't want a value to be set, they
3997 * should set the realtime column to NULL, not blank. */
3998 queue_set_param(q, tmp_name, v->value, -1, 0);
3999 }
4000
4001 /* Temporarily set realtime members dead so we can detect deleted ones. */
4002 mem_iter = ao2_iterator_init(q->members, 0);
4003 while ((m = ao2_iterator_next(&mem_iter))) {
4004 if (m->realtime) {
4005 m->dead = 1;
4006 }
4007 ao2_ref(m, -1);
4008 }
4009 ao2_iterator_destroy(&mem_iter);
4010
4011 while ((category = ast_category_browse(member_config, category))) {
4012 rt_handle_member_record(q, category, member_config);
4013 }
4014
4015 /* Delete all realtime members that have been deleted in DB. */
4016 mem_iter = ao2_iterator_init(q->members, 0);
4017 while ((m = ao2_iterator_next(&mem_iter))) {
4018 if (m->dead) {
4020 ast_queue_log(q->name, "REALTIME", m->interface, "REMOVEMEMBER", "%s", "");
4021 } else {
4022 ast_queue_log(q->name, "REALTIME", m->membername, "REMOVEMEMBER", "%s", "");
4023 }
4025 }
4026 ao2_ref(m, -1);
4027 }
4028 ao2_iterator_destroy(&mem_iter);
4029
4030 ao2_unlock(q);
4031
4032 return q;
4033}
static void member_remove_from_queue(struct call_queue *queue, struct member *mem)
Definition: app_queue.c:3713
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:3729
#define queues_t_unlink(c, q, tag)
Definition: app_queue.c:2191
#define queues_t_link(c, q, tag)
Definition: app_queue.c:2190
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:3483
static void init_queue(struct call_queue *q)
Initialize Queue default values.
Definition: app_queue.c:3085
static struct call_queue * alloc_queue(const char *queuename)
Definition: app_queue.c:3878
static int strat2int(const char *strategy)
Definition: app_queue.c:2066
struct ast_variable * next
unsigned int dead
Definition: app_queue.c:1963
unsigned int dead
Definition: app_queue.c:1878
int realtime
Definition: app_queue.c:1866

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

3848{
3849 /* Free non-dynamic members */
3850 struct member *cur;
3851 struct ao2_iterator mem_iter = ao2_iterator_init(q->members, 0);
3852
3853 while ((cur = ao2_iterator_next(&mem_iter))) {
3854 if (all || !cur->dynamic) {
3856 }
3857 ao2_ref(cur, -1);
3858 }
3859 ao2_iterator_destroy(&mem_iter);
3860}

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

9193{
9194 struct member *m;
9195
9197 ast_log(LOG_ERROR, "QUEUE_MEMBER: Missing required interface argument.\n");
9198 return NULL;
9199 }
9200
9202 if (!m) {
9203 ast_log(LOG_ERROR, "Queue member interface '%s' not in queue '%s'.\n",
9204 interface, q->name);
9205 }
9206 return m;
9207}

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

8234{
8235 int foundqueue = 0, penalty;
8236 struct call_queue *q;
8237 struct member *mem;
8238
8239 if ((q = find_load_queue_rt_friendly(queuename))) {
8240 foundqueue = 1;
8241 ao2_lock(q);
8242 if ((mem = interface_exists(q, interface))) {
8243 penalty = mem->penalty;
8244 ao2_ref(mem, -1);
8245 ao2_unlock(q);
8246 queue_t_unref(q, "Search complete");
8247 return penalty;
8248 }
8249 ao2_unlock(q);
8250 queue_t_unref(q, "Search complete");
8251 }
8252
8253 /* some useful debugging */
8254 if (foundqueue) {
8255 ast_log (LOG_ERROR, "Invalid queuename\n");
8256 } else {
8257 ast_log (LOG_ERROR, "Invalid interface\n");
8258 }
8259
8260 return RESULT_FAILURE;
8261}
#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,
int  raise_respect_min 
)
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 2553 of file app_queue.c.

2554{
2555 struct member *member;
2556 struct ao2_iterator mem_iter;
2557
2558 ao2_lock(q);
2559 mem_iter = ao2_iterator_init(q->members, 0);
2560 for (; (member = ao2_iterator_next(&mem_iter)); ao2_ref(member, -1)) {
2561 int penalty = member->penalty;
2562 if (raise_penalty != INT_MAX && penalty < raise_penalty) {
2563 /* Check if we should respect minimum penalty threshold */
2564 if (raise_respect_min && penalty < min_penalty) {
2565 ast_debug(4, "%s penalty %d not raised (below min %d)\n", member->membername, penalty, min_penalty);
2566 } else {
2567 ast_debug(4, "%s is having his penalty raised up from %d to %d\n", member->membername, penalty, raise_penalty);
2568 penalty = raise_penalty;
2569 }
2570 }
2571 if ((max_penalty != INT_MAX && penalty > max_penalty) || (min_penalty != INT_MAX && penalty < min_penalty)) {
2572 if (conditions & QUEUE_EMPTY_PENALTY) {
2573 ast_debug(4, "%s is unavailable because his penalty is not between %d and %d\n", member->membername, min_penalty, max_penalty);
2574 continue;
2575 }
2576 }
2577
2578 switch (devstate ? ast_device_state(member->state_interface) : member->status) {
2579 case AST_DEVICE_INVALID:
2580 if (conditions & QUEUE_EMPTY_INVALID) {
2581 ast_debug(4, "%s is unavailable because his device state is 'invalid'\n", member->membername);
2582 break;
2583 }
2584 goto default_case;
2586 if (conditions & QUEUE_EMPTY_UNAVAILABLE) {
2587 ast_debug(4, "%s is unavailable because his device state is 'unavailable'\n", member->membername);
2588 break;
2589 }
2590 goto default_case;
2591 case AST_DEVICE_INUSE:
2592 if (conditions & QUEUE_EMPTY_INUSE) {
2593 ast_debug(4, "%s is unavailable because his device state is 'inuse'\n", member->membername);
2594 break;
2595 }
2596 goto default_case;
2597 case AST_DEVICE_RINGING:
2598 if (conditions & QUEUE_EMPTY_RINGING) {
2599 ast_debug(4, "%s is unavailable because his device state is 'ringing'\n", member->membername);
2600 break;
2601 }
2602 goto default_case;
2603 case AST_DEVICE_UNKNOWN:
2604 if (conditions & QUEUE_EMPTY_UNKNOWN) {
2605 ast_debug(4, "%s is unavailable because his device state is 'unknown'\n", member->membername);
2606 break;
2607 }
2608 /* Fall-through */
2609 default:
2610 default_case:
2611 if (member->paused && (conditions & QUEUE_EMPTY_PAUSED)) {
2612 ast_debug(4, "%s is unavailable because he is paused'\n", member->membername);
2613 break;
2614 } else if ((conditions & QUEUE_EMPTY_WRAPUP)
2615 && member->lastcall
2616 && get_wrapuptime(q, member)
2617 && (time(NULL) - get_wrapuptime(q, member) < member->lastcall)) {
2618 ast_debug(4, "%s is unavailable because it has only been %d seconds since his last call (wrapup time is %d)\n",
2619 member->membername, (int) (time(NULL) - member->lastcall), get_wrapuptime(q, member));
2620 break;
2621 } else {
2622 ao2_ref(member, -1);
2623 ao2_iterator_destroy(&mem_iter);
2624 ao2_unlock(q);
2625 ast_debug(4, "%s is available.\n", member->membername);
2626 return 0;
2627 }
2628 break;
2629 }
2630 }
2631 ao2_iterator_destroy(&mem_iter);
2632 ao2_unlock(q);
2633
2634 if (!devstate && (conditions & QUEUE_EMPTY_RINGING)) {
2635 /* member state still may be RINGING due to lag in event message - check again with device state */
2636 return get_member_status(q, max_penalty, min_penalty, raise_penalty, conditions, 1, raise_respect_min);
2637 }
2638 return -1;
2639}
static int get_member_status(struct call_queue *q, int max_penalty, int min_penalty, int raise_penalty, enum empty_conditions conditions, int devstate, int raise_respect_min)
Check if members are available.
Definition: app_queue.c:2553
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 2986 of file app_queue.c.

2987{
2988 return ast_strlen_zero(cur->state_exten) ? ast_device_state(cur->state_interface) : extensionstate2devicestate(ast_extension_state(NULL, cur->state_context, cur->state_exten));
2989}
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:3191

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

2123{
2124 if (member->wrapuptime) {
2125 return member->wrapuptime;
2126 }
2127 return q->wrapuptime;
2128}
int wrapuptime
Definition: app_queue.c:2001

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

6621{
6622 struct queue_stasis_data *queue_data = userdata;
6623 struct ast_attended_transfer_message *atxfer_msg = stasis_message_data(msg);
6624 RAII_VAR(struct ast_channel_snapshot *, caller_snapshot, NULL, ao2_cleanup);
6625 RAII_VAR(struct ast_channel_snapshot *, member_snapshot, NULL, ao2_cleanup);
6626
6627 if (atxfer_msg->result != AST_BRIDGE_TRANSFER_SUCCESS ||
6629 return;
6630 }
6631
6632 ao2_lock(queue_data);
6633
6634 if (queue_data->dying) {
6635 ao2_unlock(queue_data);
6636 return;
6637 }
6638
6639 if (ast_strlen_zero(queue_data->bridge_uniqueid)) {
6640 ao2_unlock(queue_data);
6641 return;
6642 }
6643
6644 if ((!atxfer_msg->to_transferee.bridge_snapshot || strcmp(queue_data->bridge_uniqueid,
6645 atxfer_msg->to_transferee.bridge_snapshot->uniqueid)) &&
6646 (!atxfer_msg->to_transfer_target.bridge_snapshot || strcmp(queue_data->bridge_uniqueid,
6648 ao2_unlock(queue_data);
6649 return;
6650 }
6651
6652 caller_snapshot = ast_channel_snapshot_get_latest(queue_data->caller_uniqueid);
6653 member_snapshot = ast_channel_snapshot_get_latest(queue_data->member_uniqueid);
6654
6655 ao2_unlock(queue_data);
6656
6657 ast_debug(3, "Detected attended transfer in queue %s\n", queue_data->queue->name);
6658 log_attended_transfer(queue_data, atxfer_msg);
6659
6660 send_agent_complete(queue_data->queue->name, caller_snapshot, member_snapshot, queue_data->member,
6661 queue_data->holdstart, queue_data->starttime, TRANSFER);
6662 update_queue(queue_data->queue, queue_data->member, queue_data->callcompletedinsl,
6663 queue_data->starttime);
6664 remove_stasis_subscriptions(queue_data);
6665}
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:6280
static int update_queue(struct call_queue *q, struct member *member, int callcompletedinsl, time_t starttime)
update the queue status
Definition: app_queue.c:6123
static void remove_stasis_subscriptions(struct queue_stasis_data *queue_data)
Definition: app_queue.c:6427
static void log_attended_transfer(struct queue_stasis_data *queue_data, struct ast_attended_transfer_message *atxfer_msg)
Definition: app_queue.c:6481
#define ao2_cleanup(obj)
Definition: astobj2.h:1934
@ AST_BRIDGE_TRANSFER_SUCCESS
Definition: bridge.h:1104
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:332
Structure representing a snapshot of channel state.
User data for stasis subscriptions used for queue calls.
Definition: app_queue.c:6373
const ast_string_field caller_uniqueid
Definition: app_queue.c:6381
const ast_string_field member_uniqueid
Definition: app_queue.c:6381
struct call_queue * queue
Definition: app_queue.c:6383
const ast_string_field bridge_uniqueid
Definition: app_queue.c:6381
struct member * member
Definition: app_queue.c:6385
#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:978

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

6562{
6563 struct queue_stasis_data *queue_data = userdata;
6564 struct ast_blind_transfer_message *transfer_msg = stasis_message_data(msg);
6565 const char *exten;
6566 const char *context;
6567 RAII_VAR(struct ast_channel_snapshot *, caller_snapshot, NULL, ao2_cleanup);
6568 RAII_VAR(struct ast_channel_snapshot *, member_snapshot, NULL, ao2_cleanup);
6569
6570 if (transfer_msg->result != AST_BRIDGE_TRANSFER_SUCCESS) {
6571 return;
6572 }
6573
6574 ao2_lock(queue_data);
6575
6576 if (queue_data->dying) {
6577 ao2_unlock(queue_data);
6578 return;
6579 }
6580
6581 if (ast_strlen_zero(queue_data->bridge_uniqueid) ||
6582 strcmp(queue_data->bridge_uniqueid, transfer_msg->bridge->uniqueid)) {
6583 ao2_unlock(queue_data);
6584 return;
6585 }
6586
6587 caller_snapshot = ast_channel_snapshot_get_latest(queue_data->caller_uniqueid);
6588 member_snapshot = ast_channel_snapshot_get_latest(queue_data->member_uniqueid);
6589
6590 ao2_unlock(queue_data);
6591
6592 exten = transfer_msg->exten;
6593 context = transfer_msg->context;
6594
6595 ast_debug(3, "Detected blind transfer in queue %s\n", queue_data->queue->name);
6596 ast_queue_log(queue_data->queue->name, queue_data->caller_uniqueid, queue_data->member->membername,
6597 "BLINDTRANSFER", "%s|%s|%ld|%ld|%d",
6598 exten, context,
6599 (long) (queue_data->starttime - queue_data->holdstart),
6600 (long) (time(NULL) - queue_data->starttime), queue_data->caller_pos);
6601
6602 send_agent_complete(queue_data->queue->name, caller_snapshot, member_snapshot, queue_data->member,
6603 queue_data->holdstart, queue_data->starttime, TRANSFER);
6604 update_queue(queue_data->queue, queue_data->member, queue_data->callcompletedinsl,
6605 queue_data->starttime);
6606 remove_stasis_subscriptions(queue_data);
6607}
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 6527 of file app_queue.c.

6529{
6530 struct queue_stasis_data *queue_data = userdata;
6531 struct ast_bridge_blob *enter_blob = stasis_message_data(msg);
6532 SCOPED_AO2LOCK(lock, queue_data);
6533
6534 if (queue_data->dying) {
6535 return;
6536 }
6537
6538 if (!ast_strlen_zero(queue_data->bridge_uniqueid)) {
6539 return;
6540 }
6541
6542 if (!strcmp(enter_blob->channel->base->uniqueid, queue_data->caller_uniqueid)) {
6543 ast_string_field_set(queue_data, bridge_uniqueid,
6544 enter_blob->bridge->uniqueid);
6545 ast_debug(3, "Detected entry of caller channel %s into bridge %s\n",
6546 enter_blob->channel->base->name, queue_data->bridge_uniqueid);
6547 }
6548}
ast_mutex_t lock
Definition: app_sla.c:337
#define SCOPED_AO2LOCK(varname, obj)
scoped lock specialization for ao2 mutexes.
Definition: lock.h:611
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 6816 of file app_queue.c.

6818{
6819 struct queue_stasis_data *queue_data = userdata;
6820 struct ast_channel_blob *channel_blob = stasis_message_data(msg);
6821 RAII_VAR(struct ast_channel_snapshot *, caller_snapshot, NULL, ao2_cleanup);
6822 RAII_VAR(struct ast_channel_snapshot *, member_snapshot, NULL, ao2_cleanup);
6823 RAII_VAR(struct ast_channel *, chan, NULL, ao2_cleanup);
6824 enum agent_complete_reason reason;
6825
6826 ao2_lock(queue_data);
6827
6828 if (queue_data->dying) {
6829 ao2_unlock(queue_data);
6830 return;
6831 }
6832
6833 if (!strcmp(channel_blob->snapshot->base->uniqueid, queue_data->caller_uniqueid)) {
6834 reason = CALLER;
6835 } else if (!strcmp(channel_blob->snapshot->base->uniqueid, queue_data->member_uniqueid)) {
6836 reason = AGENT;
6837 } else {
6838 ao2_unlock(queue_data);
6839 return;
6840 }
6841
6842 chan = ast_channel_get_by_name(channel_blob->snapshot->base->name);
6843 if (chan && (ast_channel_has_role(chan, AST_TRANSFERER_ROLE_NAME) ||
6844 !ast_strlen_zero(pbx_builtin_getvar_helper(chan, "ATTENDEDTRANSFER")) ||
6845 !ast_strlen_zero(pbx_builtin_getvar_helper(chan, "BLINDTRANSFER")))) {
6846 /* Channel that is hanging up is doing it as part of a transfer.
6847 * We'll get a transfer event later
6848 */
6849 ao2_unlock(queue_data);
6850 return;
6851 }
6852
6853 caller_snapshot = ast_channel_snapshot_get_latest(queue_data->caller_uniqueid);
6854 member_snapshot = ast_channel_snapshot_get_latest(queue_data->member_uniqueid);
6855
6856 ao2_unlock(queue_data);
6857
6858 ast_debug(3, "Detected hangup of queue %s channel %s\n", reason == CALLER ? "caller" : "member",
6859 channel_blob->snapshot->base->name);
6860
6861 ast_queue_log(queue_data->queue->name, queue_data->caller_uniqueid, queue_data->member->membername,
6862 reason == CALLER ? "COMPLETECALLER" : "COMPLETEAGENT", "%ld|%ld|%d",
6863 (long) (queue_data->starttime - queue_data->holdstart),
6864 (long) (time(NULL) - queue_data->starttime), queue_data->caller_pos);
6865
6866 send_agent_complete(queue_data->queue->name, caller_snapshot, member_snapshot, queue_data->member,
6867 queue_data->holdstart, queue_data->starttime, reason);
6868 update_queue(queue_data->queue, queue_data->member, queue_data->callcompletedinsl,
6869 queue_data->starttime);
6870 remove_stasis_subscriptions(queue_data);
6871}
agent_complete_reason
Definition: app_queue.c:6273
#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 *search)
Find a channel by name or uniqueid.
Definition: channel.c:1398
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 6693 of file app_queue.c.

6695{
6696 struct queue_stasis_data *queue_data = userdata;
6697 struct ast_multi_channel_blob *optimization_blob = stasis_message_data(msg);
6698 struct ast_channel_snapshot *local_one = ast_multi_channel_blob_get_channel(optimization_blob, "1");
6699 struct ast_channel_snapshot *local_two = ast_multi_channel_blob_get_channel(optimization_blob, "2");
6700 struct ast_channel_snapshot *source = ast_multi_channel_blob_get_channel(optimization_blob, "source");
6701 struct local_optimization *optimization;
6702 unsigned int id;
6703 SCOPED_AO2LOCK(lock, queue_data);
6704
6705 if (!local_one || !local_two || !source) {
6706 ast_debug(1, "Local optimization begin missing channel snapshots:%s%s%s\n",
6707 !local_one ? " local_one," : "",
6708 !local_two ? " local_two," : "",
6709 !source ? " source," : "");
6710 return;
6711 }
6712
6713 if (queue_data->dying) {
6714 return;
6715 }
6716
6717 if (!strcmp(local_one->base->uniqueid, queue_data->member_uniqueid)) {
6718 optimization = &queue_data->member_optimize;
6719 } else if (!strcmp(local_two->base->uniqueid, queue_data->caller_uniqueid)) {
6720 optimization = &queue_data->caller_optimize;
6721 } else {
6722 return;
6723 }
6724
6725 /* We only allow move-swap optimizations, so there had BETTER be a source */
6726 ast_assert(source != NULL);
6727
6728 optimization->source_chan_uniqueid = ast_strdup(source->base->uniqueid);
6729 if (!optimization->source_chan_uniqueid) {
6730 ast_log(LOG_ERROR, "Unable to track local channel optimization for channel %s. Expect further errors\n", local_one->base->name);
6731 return;
6732 }
6734
6735 optimization->id = id;
6736 optimization->in_progress = 1;
6737}
enum queue_result id
Definition: app_queue.c:1767
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:6349
const char * source_chan_uniqueid
Definition: app_queue.c:6351
unsigned int id
Definition: app_queue.c:6355
struct local_optimization member_optimize
Definition: app_queue.c:6403
struct local_optimization caller_optimize
Definition: app_queue.c:6401
#define ast_assert(a)
Definition: utils.h:776

References ast_assert, 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_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 6752 of file app_queue.c.

6754{
6755 struct queue_stasis_data *queue_data = userdata;
6756 struct ast_multi_channel_blob *optimization_blob = stasis_message_data(msg);
6757 struct ast_channel_snapshot *local_one = ast_multi_channel_blob_get_channel(optimization_blob, "1");
6758 struct ast_channel_snapshot *local_two = ast_multi_channel_blob_get_channel(optimization_blob, "2");
6759 struct local_optimization *optimization;
6760 int is_caller;
6761 unsigned int id;
6762 SCOPED_AO2LOCK(lock, queue_data);
6763
6764 if (queue_data->dying) {
6765 return;
6766 }
6767
6768 if (!strcmp(local_one->base->uniqueid, queue_data->member_uniqueid)) {
6769 optimization = &queue_data->member_optimize;
6770 is_caller = 0;
6771 } else if (!strcmp(local_two->base->uniqueid, queue_data->caller_uniqueid)) {
6772 optimization = &queue_data->caller_optimize;
6773 is_caller = 1;
6774 } else {
6775 return;
6776 }
6777
6779
6780 if (!optimization->in_progress) {
6781 ast_log(LOG_WARNING, "Told of a local optimization end when we had no previous begin\n");
6782 return;
6783 }
6784
6785 if (id != optimization->id) {
6786 ast_log(LOG_WARNING, "Local optimization end event ID does not match begin (%u != %u)\n",
6787 id, optimization->id);
6788 return;
6789 }
6790
6791 if (is_caller) {
6792 ast_debug(3, "Local optimization: Changing queue caller uniqueid from %s to %s\n",
6793 queue_data->caller_uniqueid, optimization->source_chan_uniqueid);
6794 ast_string_field_set(queue_data, caller_uniqueid, optimization->source_chan_uniqueid);
6795 } else {
6796 ast_debug(3, "Local optimization: Changing queue member uniqueid from %s to %s\n",
6797 queue_data->member_uniqueid, optimization->source_chan_uniqueid);
6798 ast_string_field_set(queue_data, member_uniqueid, optimization->source_chan_uniqueid);
6799 }
6800
6801 optimization->in_progress = 0;
6802}

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

6875{
6876 struct queue_stasis_data *queue_data = userdata;
6877 struct ast_channel_blob *channel_blob = stasis_message_data(msg);
6878 const char *new_channel_id;
6879
6880 new_channel_id = ast_json_string_get(ast_json_object_get(channel_blob->blob, "newchanneluniqueid"));
6881
6882 ao2_lock(queue_data);
6883
6884 if (queue_data->dying) {
6885 ao2_unlock(queue_data);
6886 return;
6887 }
6888
6889 if (!strcmp(channel_blob->snapshot->base->uniqueid, queue_data->caller_uniqueid)) {
6890 ast_debug(1, "Replacing caller channel %s with %s due to masquerade\n", queue_data->caller_uniqueid, new_channel_id);
6891 ast_string_field_set(queue_data, caller_uniqueid, new_channel_id);
6892 } else if (!strcmp(channel_blob->snapshot->base->uniqueid, queue_data->member_uniqueid)) {
6893 ast_debug(1, "Replacing member channel %s with %s due to masquerade\n", queue_data->member_uniqueid, new_channel_id);
6894 ast_string_field_set(queue_data, member_uniqueid, new_channel_id);
6895 }
6896
6897 ao2_unlock(queue_data);
6898}
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 11175 of file app_queue.c.

11176{
11177 const char *queuename, *interface, *membername = NULL, *state_interface = NULL, *reason = NULL;
11178 int penalty, paused = 0;
11179
11180 switch ( cmd ) {
11181 case CLI_INIT:
11182 e->command = "queue add member";
11183 e->usage =
11184 "Usage: queue add member <dial string> to <queue> [penalty <penalty> [as <membername> [state_interface <interface> [paused <reason>]]]]\n"
11185 " 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";
11186 return NULL;
11187 case CLI_GENERATE:
11188 return complete_queue_add_member(a->line, a->word, a->pos, a->n);
11189 }
11190
11191 if ((a->argc != 6) && (a->argc != 8) && (a->argc != 10) && (a->argc != 12) && (a->argc != 14)) {
11192 return CLI_SHOWUSAGE;
11193 } else if (strcmp(a->argv[4], "to")) {
11194 return CLI_SHOWUSAGE;
11195 } else if ((a->argc >= 8) && strcmp(a->argv[6], "penalty")) {
11196 return CLI_SHOWUSAGE;
11197 } else if ((a->argc >= 10) && strcmp(a->argv[8], "as")) {
11198 return CLI_SHOWUSAGE;
11199 } else if ((a->argc == 12) && strcmp(a->argv[10], "state_interface")) {
11200 return CLI_SHOWUSAGE;
11201 } else if ((a->argc == 14) && strcmp(a->argv[12], "paused")) {
11202 return CLI_SHOWUSAGE;
11203 }
11204
11205 queuename = a->argv[5];
11206 interface = a->argv[3];
11207 if (a->argc >= 8) {
11208 if (sscanf(a->argv[7], "%30d", &penalty) == 1) {
11209 if (penalty < 0) {
11210 ast_cli(a->fd, "Penalty must be >= 0\n");
11211 penalty = 0;
11212 }
11213 } else {
11214 ast_cli(a->fd, "Penalty must be an integer >= 0\n");
11215 penalty = 0;
11216 }
11217 } else {
11218 penalty = 0;
11219 }
11220
11221 if (a->argc >= 10) {
11222 membername = a->argv[9];
11223 }
11224
11225 if (a->argc >= 12) {
11226 state_interface = a->argv[11];
11227 }
11228
11229 if (a->argc >= 14) {
11230 paused = 1;
11231 reason = a->argv[13];
11232 }
11233
11234 switch (add_to_queue(queuename, interface, membername, penalty, paused, queue_persistent_members, state_interface, reason, 0)) {
11235 case RES_OKAY:
11236 if (ast_strlen_zero(membername) || !log_membername_as_agent) {
11237 ast_queue_log(queuename, "CLI", interface, "ADDMEMBER", "%s", paused ? "PAUSED" : "");
11238 } else {
11239 ast_queue_log(queuename, "CLI", membername, "ADDMEMBER", "%s", paused ? "PAUSED" : "");
11240 }
11241 ast_cli(a->fd, "Added interface '%s' to queue '%s'\n", interface, queuename);
11242 return CLI_SUCCESS;
11243 case RES_EXISTS:
11244 ast_cli(a->fd, "Unable to add interface '%s' to queue '%s': Already there\n", interface, queuename);
11245 return CLI_FAILURE;
11246 case RES_NOSUCHQUEUE:
11247 ast_cli(a->fd, "Unable to add interface to queue '%s': No such queue\n", queuename);
11248 return CLI_FAILURE;
11249 case RES_OUTOFMEMORY:
11250 ast_cli(a->fd, "Out of memory\n");
11251 return CLI_FAILURE;
11252 case RES_NOT_DYNAMIC:
11253 ast_cli(a->fd, "Member not dynamic\n");
11254 return CLI_FAILURE;
11255 default:
11256 return CLI_FAILURE;
11257 }
11258}
#define RES_NOT_DYNAMIC
Definition: app_queue.c:1692
static char * complete_queue_add_member(const char *line, const char *word, int pos, int state)
Definition: app_queue.c:11000
@ 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 11371 of file app_queue.c.

11372{
11373 const char *queuename, *caller;
11374 int priority, immediate = 0;
11375 char *res = CLI_FAILURE;
11376
11377 switch (cmd) {
11378 case CLI_INIT:
11379 e->command = "queue priority caller";
11380 e->usage =
11381 "Usage: queue priority caller <channel> on <queue> to <priority> [immediate]\n"
11382 " Change the priority of a channel on a queue, optionally applying the change in relation to existing callers.\n";
11383 return NULL;
11384 case CLI_GENERATE:
11385 return NULL;
11386 }
11387
11388 if (a->argc < 8) {
11389 return CLI_SHOWUSAGE;
11390 } else if (strcmp(a->argv[4], "on")) {
11391 return CLI_SHOWUSAGE;
11392 } else if (strcmp(a->argv[6], "to")) {
11393 return CLI_SHOWUSAGE;
11394 } else if (sscanf(a->argv[7], "%30d", &priority) != 1) {
11395 ast_log (LOG_ERROR, "<priority> parameter must be an integer.\n");
11396 return CLI_SHOWUSAGE;
11397 } else if (a->argc == 9) {
11398 if (strcmp(a->argv[8], "immediate")) {
11399 return CLI_SHOWUSAGE;
11400 }
11401 immediate = 1;
11402 }
11403
11404 caller = a->argv[3];
11405 queuename = a->argv[5];
11406
11407 switch (change_priority_caller_on_queue(queuename, caller, priority, immediate)) {
11408 case RES_OKAY:
11409 res = CLI_SUCCESS;
11410 break;
11411 case RES_NOSUCHQUEUE:
11412 ast_cli(a->fd, "Unable change priority caller %s on queue '%s': No such queue\n", caller, queuename);
11413 break;
11414 case RES_NOT_CALLER:
11415 ast_cli(a->fd, "Unable to change priority caller '%s' on queue '%s': Not there\n", caller, queuename);
11416
11417 break;
11418 }
11419
11420 return res;
11421}
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:7805

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

11445{
11446 const char *queuename, *interface, *reason;
11447 int paused;
11448
11449 switch (cmd) {
11450 case CLI_INIT:
11451 e->command = "queue {pause|unpause} member";
11452 e->usage =
11453 "Usage: queue {pause|unpause} member <member> [queue <queue> [reason <reason>]]\n"
11454 " Pause or unpause a queue member. Not specifying a particular queue\n"
11455 " will pause or unpause a member across all queues to which the member\n"
11456 " belongs.\n";
11457 return NULL;
11458 case CLI_GENERATE:
11459 return complete_queue_pause_member(a->line, a-> word, a->pos, a->n);
11460 }
11461
11462 if (a->argc < 4 || a->argc == 5 || a->argc == 7 || a->argc > 8) {
11463 return CLI_SHOWUSAGE;
11464 } else if (a->argc >= 5 && strcmp(a->argv[4], "queue")) {
11465 return CLI_SHOWUSAGE;
11466 } else if (a->argc == 8 && strcmp(a->argv[6], "reason")) {
11467 return CLI_SHOWUSAGE;
11468 }
11469
11470
11471 interface = a->argv[3];
11472 queuename = a->argc >= 6 ? a->argv[5] : NULL;
11473 reason = a->argc == 8 ? a->argv[7] : NULL;
11474 paused = !strcasecmp(a->argv[1], "pause");
11475
11476 if (set_member_paused(queuename, interface, reason, paused) == RESULT_SUCCESS) {
11477 ast_cli(a->fd, "%spaused interface '%s'", paused ? "" : "un", interface);
11478 if (!ast_strlen_zero(queuename)) {
11479 ast_cli(a->fd, " in queue '%s'", queuename);
11480 }
11481 if (!ast_strlen_zero(reason)) {
11482 ast_cli(a->fd, " for reason '%s'", reason);
11483 }
11484 ast_cli(a->fd, "\n");
11485 return CLI_SUCCESS;
11486 } else {
11487 ast_cli(a->fd, "Unable to %spause interface '%s'", paused ? "" : "un", interface);
11488 if (!ast_strlen_zero(queuename)) {
11489 ast_cli(a->fd, " in queue '%s'", queuename);
11490 }
11491 if (!ast_strlen_zero(reason)) {
11492 ast_cli(a->fd, " for reason '%s'", reason);
11493 }
11494 ast_cli(a->fd, "\n");
11495 return CLI_FAILURE;
11496 }
11497}
static char * complete_queue_pause_member(const char *line, const char *word, int pos, int state)
Definition: app_queue.c:11425
static int set_member_paused(const char *queuename, const char *interface, const char *reason, int paused)
Definition: app_queue.c:8016
#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 11716 of file app_queue.c.

11717{
11718 struct ast_flags mask = {0,};
11719 int i;
11720
11721 switch (cmd) {
11722 case CLI_INIT:
11723 e->command = "queue reload {parameters|members|rules|all}";
11724 e->usage =
11725 "Usage: queue reload {parameters|members|rules|all} [<queuenames>]\n"
11726 "Reload queues. If <queuenames> are specified, only reload information pertaining\n"
11727 "to <queuenames>. One of 'parameters,' 'members,' 'rules,' or 'all' must be\n"
11728 "specified in order to know what information to reload. Below is an explanation\n"
11729 "of each of these qualifiers.\n"
11730 "\n"
11731 "\t'members' - reload queue members from queues.conf\n"
11732 "\t'parameters' - reload all queue options except for queue members\n"
11733 "\t'rules' - reload the queuerules.conf file\n"
11734 "\t'all' - reload queue rules, parameters, and members\n"
11735 "\n"
11736 "Note: the 'rules' qualifier here cannot actually be applied to a specific queue.\n"
11737 "Use of the 'rules' qualifier causes queuerules.conf to be reloaded. Even if only\n"
11738 "one queue is specified when using this command, reloading queue rules may cause\n"
11739 "other queues to be affected\n";
11740 return NULL;
11741 case CLI_GENERATE:
11742 if (a->pos >= 3) {
11743 /* find the point at which the list of queue names starts */
11744 const char *command_end = a->line + strlen("queue reload ");
11745 command_end = strchr(command_end, ' ');
11746 if (!command_end) {
11747 command_end = a->line + strlen(a->line);
11748 }
11749 return complete_queue(a->line, a->word, a->pos, a->n, command_end - a->line);
11750 } else {
11751 return NULL;
11752 }
11753 }
11754
11755 if (a->argc < 3)
11756 return CLI_SHOWUSAGE;
11757
11758 if (!strcasecmp(a->argv[2], "rules")) {
11760 } else if (!strcasecmp(a->argv[2], "members")) {
11762 } else if (!strcasecmp(a->argv[2], "parameters")) {
11764 } else if (!strcasecmp(a->argv[2], "all")) {
11766 }
11767
11768 if (a->argc == 3) {
11769 reload_handler(1, &mask, NULL);
11770 return CLI_SUCCESS;
11771 }
11772
11773 for (i = 3; i < a->argc; ++i) {
11774 reload_handler(1, &mask, a->argv[i]);
11775 }
11776
11777 return CLI_SUCCESS;
11778}
static int reload_handler(int reload, struct ast_flags *mask, const char *queuename)
The command center for all reload operations.
Definition: app_queue.c:10187
#define ast_set_flag(p, flag)
Definition: utils.h:70
#define AST_FLAGS_ALL
Definition: utils.h:214

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

11309{
11310 const char *queuename, *interface;
11311 struct member *mem = NULL;
11312 char *res = CLI_FAILURE;
11313
11314 switch (cmd) {
11315 case CLI_INIT:
11316 e->command = "queue remove member";
11317 e->usage =
11318 "Usage: queue remove member <channel> from <queue>\n"
11319 " Remove a specific channel from a queue.\n";
11320 return NULL;
11321 case CLI_GENERATE:
11322 return complete_queue_remove_member(a->line, a->word, a->pos, a->n);
11323 }
11324
11325 if (a->argc != 6) {
11326 return CLI_SHOWUSAGE;
11327 } else if (strcmp(a->argv[4], "from")) {
11328 return CLI_SHOWUSAGE;
11329 }
11330
11331 queuename = a->argv[5];
11332 interface = a->argv[3];
11333
11335 mem = find_member_by_queuename_and_interface(queuename, interface);
11336 }
11337
11338 switch (remove_from_queue(queuename, interface)) {
11339 case RES_OKAY:
11340 if (!mem || ast_strlen_zero(mem->membername)) {
11341 ast_queue_log(queuename, "CLI", interface, "REMOVEMEMBER", "%s", "");
11342 } else {
11343 ast_queue_log(queuename, "CLI", mem->membername, "REMOVEMEMBER", "%s", "");
11344 }
11345 ast_cli(a->fd, "Removed interface %s from queue '%s'\n", interface, queuename);
11346 res = CLI_SUCCESS;
11347 break;
11348 case RES_EXISTS:
11349 ast_cli(a->fd, "Unable to remove interface '%s' from queue '%s': Not there\n", interface, queuename);
11350 break;
11351 case RES_NOSUCHQUEUE:
11352 ast_cli(a->fd, "Unable to remove interface from queue '%s': No such queue\n", queuename);
11353 break;
11354 case RES_OUTOFMEMORY:
11355 ast_cli(a->fd, "Out of memory\n");
11356 break;
11357 case RES_NOT_DYNAMIC:
11358 ast_cli(a->fd, "Unable to remove interface '%s' from queue '%s': Member is not dynamic\n", interface, queuename);
11359 break;
11360 }
11361
11362 if (mem) {
11363 ao2_ref(mem, -1);
11364 }
11365
11366 return res;
11367}
static int remove_from_queue(const char *queuename, const char *interface)
Remove member from queue.
Definition: app_queue.c:7699
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:12117
static char * complete_queue_remove_member(const char *line, const char *word, int pos, int state)
Definition: app_queue.c:11260

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

11678{
11679 struct ast_flags mask = {QUEUE_RESET_STATS,};
11680 int i;
11681
11682 switch (cmd) {
11683 case CLI_INIT:
11684 e->command = "queue reset stats";
11685 e->usage =
11686 "Usage: queue reset stats [<queuenames>]\n"
11687 "\n"
11688 "Issuing this command will reset statistics for\n"
11689 "<queuenames>, or for all queues if no queue is\n"
11690 "specified.\n";
11691 return NULL;
11692 case CLI_GENERATE:
11693 if (a->pos >= 3) {
11694 return complete_queue(a->line, a->word, a->pos, a->n, 17);
11695 } else {
11696 return NULL;
11697 }
11698 }
11699
11700 if (a->argc < 3) {
11701 return CLI_SHOWUSAGE;
11702 }
11703
11704 if (a->argc == 3) {
11705 reload_handler(1, &mask, NULL);
11706 return CLI_SUCCESS;
11707 }
11708
11709 for (i = 3; i < a->argc; ++i) {
11710 reload_handler(1, &mask, a->argv[i]);
11711 }
11712
11713 return CLI_SUCCESS;
11714}

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

11643{
11644 const char *rule;
11645 struct rule_list *rl_iter;
11646 struct penalty_rule *pr_iter;
11647 switch (cmd) {
11648 case CLI_INIT:
11649 e->command = "queue show rules";
11650 e->usage =
11651 "Usage: queue show rules [rulename]\n"
11652 " Show the list of rules associated with rulename. If no\n"
11653 " rulename is specified, list all rules defined in queuerules.conf\n";
11654 return NULL;
11655 case CLI_GENERATE:
11656 return complete_queue_rule_show(a->line, a->word, a->pos, a->n);
11657 }
11658
11659 if (a->argc != 3 && a->argc != 4) {
11660 return CLI_SHOWUSAGE;
11661 }
11662
11663 rule = a->argc == 4 ? a->argv[3] : "";
11665 AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) {
11666 if (ast_strlen_zero(rule) || !strcasecmp(rl_iter->name, rule)) {
11667 ast_cli(a->fd, "Rule: %s\n", rl_iter->name);
11668 AST_LIST_TRAVERSE(&rl_iter->rules, pr_iter, list) {
11669 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);
11670 }
11671 }
11672 }
11674 return CLI_SUCCESS;
11675}
static char * complete_queue_rule_show(const char *line, const char *word, int pos, int state)
Definition: app_queue.c:11620

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

11580{
11581 const char *queuename = NULL, *interface;
11582 int penalty = 0;
11583
11584 switch (cmd) {
11585 case CLI_INIT:
11586 e->command = "queue set penalty";
11587 e->usage =
11588 "Usage: queue set penalty <penalty> on <interface> [in <queue>]\n"
11589 " Set a member's penalty in the queue specified. If no queue is specified\n"
11590 " then that interface's penalty is set in all queues to which that interface is a member\n";
11591 return NULL;
11592 case CLI_GENERATE:
11593 return complete_queue_set_member_value(a->line, a->word, a->pos, a->n);
11594 }
11595
11596 if (a->argc != 6 && a->argc != 8) {
11597 return CLI_SHOWUSAGE;
11598 } else if (strcmp(a->argv[4], "on") || (a->argc > 6 && strcmp(a->argv[6], "in"))) {
11599 return CLI_SHOWUSAGE;
11600 }
11601
11602 if (a->argc == 8) {
11603 queuename = a->argv[7];
11604 }
11605 interface = a->argv[5];
11606 penalty = atoi(a->argv[3]);
11607
11608 switch (set_member_value(queuename, interface, MEMBER_PENALTY, penalty)) {
11609 case RESULT_SUCCESS:
11610 ast_cli(a->fd, "Set penalty on interface '%s' from queue '%s'\n", interface, queuename);
11611 return CLI_SUCCESS;
11612 case RESULT_FAILURE:
11613 ast_cli(a->fd, "Failed to set penalty on interface '%s' from queue '%s'\n", interface, queuename);
11614 return CLI_FAILURE;
11615 default:
11616 return CLI_FAILURE;
11617 }
11618}
static int set_member_value(const char *queuename, const char *interface, int property, int value)
Definition: app_queue.c:8164
static char * complete_queue_set_member_value(const char *line, const char *word, int pos, int state)
Definition: app_queue.c:11499

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

11523{
11524 const char *queuename = NULL, *interface;
11525 int ringinuse;
11526
11527 switch (cmd) {
11528 case CLI_INIT:
11529 e->command = "queue set ringinuse";
11530 e->usage =
11531 "Usage: queue set ringinuse <yes/no> on <interface> [in <queue>]\n"
11532 " Set a member's ringinuse in the queue specified. If no queue is specified\n"
11533 " then that interface's penalty is set in all queues to which that interface is a member.\n";
11534 break;
11535 return NULL;
11536 case CLI_GENERATE:
11537 return complete_queue_set_member_value(a->line, a->word, a->pos, a->n);
11538 }
11539
11540 /* Sensible argument counts */
11541 if (a->argc != 6 && a->argc != 8) {
11542 return CLI_SHOWUSAGE;
11543 }
11544
11545 /* Uses proper indicational words */
11546 if (strcmp(a->argv[4], "on") || (a->argc > 6 && strcmp(a->argv[6], "in"))) {
11547 return CLI_SHOWUSAGE;
11548 }
11549
11550 /* Set the queue name if applicable */
11551 if (a->argc == 8) {
11552 queuename = a->argv[7];
11553 }
11554
11555 /* Interface being set */
11556 interface = a->argv[5];
11557
11558 /* Check and set the ringinuse value */
11559 if (ast_true(a->argv[3])) {
11560 ringinuse = 1;
11561 } else if (ast_false(a->argv[3])) {
11562 ringinuse = 0;
11563 } else {
11564 return CLI_SHOWUSAGE;
11565 }
11566
11567 switch (set_member_value(queuename, interface, MEMBER_RINGINUSE, ringinuse)) {
11568 case RESULT_SUCCESS:
11569 ast_cli(a->fd, "Set ringinuse on interface '%s' from queue '%s'\n", interface, queuename);
11570 return CLI_SUCCESS;
11571 case RESULT_FAILURE:
11572 ast_cli(a->fd, "Failed to set ringinuse on interface '%s' from queue '%s'\n", interface, queuename);
11573 return CLI_FAILURE;
11574 default:
11575 return CLI_FAILURE;
11576 }
11577}
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:2252

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

4621{
4622 struct callattempt *oo;
4623
4624 while (outgoing) {
4625 /* If someone else answered the call we should indicate this in the CANCEL */
4626 /* Hangup any existing lines we have open */
4627 if (outgoing->chan && (outgoing->chan != exception)) {
4628 if (exception || cancel_answered_elsewhere) {
4630 }
4631 ast_channel_publish_dial(qe->chan, outgoing->chan, outgoing->interface, "CANCEL");
4632
4633 /* When dialing channels it is possible that they may not ever
4634 * leave the not in use state (Local channels in particular) by
4635 * the time we cancel them. If this occurs but we know they were
4636 * dialed we explicitly remove them from the pending members
4637 * container so that subsequent call attempts occur.
4638 */
4639 if (outgoing->member->status == AST_DEVICE_NOT_INUSE) {
4641 }
4642
4643 ast_hangup(outgoing->chan);
4644 }
4645 oo = outgoing;
4646 outgoing = outgoing->q_next;
4648 callattempt_free(oo);
4649 }
4650}
void * ast_aoc_destroy_decoded(struct ast_aoc_decoded *decoded)
free an ast_aoc_decoded object
Definition: aoc.c:316
static void callattempt_free(struct callattempt *doomed)
Definition: app_queue.c:4598
#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:1815
struct ast_channel * chan
Definition: app_queue.c:1850

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

3086{
3087 int i;
3088 struct penalty_rule *pr_iter;
3089
3090 q->dead = 0;
3091 q->retry = DEFAULT_RETRY;
3093 q->maxlen = 0;
3094
3095 ast_string_field_set(q, announce, "");
3097 ast_string_field_set(q, membergosub, "");
3098 ast_string_field_set(q, defaultrule, "");
3099
3100 q->announcefrequency = 0;
3102 q->announceholdtime = 1;
3104 q->announcepositionlimit = 10; /* Default 10 positions */
3105 q->announceposition = ANNOUNCEPOSITION_YES; /* Default yes */
3106 q->roundingseconds = 0; /* Default - don't announce seconds */
3107 q->servicelevel = 0;
3108 q->ringinuse = 1;
3110 q->setinterfacevar = 0;
3111 q->setqueuevar = 0;
3112 q->setqueueentryvar = 0;
3114 q->monfmt[0] = '\0';
3115 q->reportholdtime = 0;
3116 q->wrapuptime = 0;
3117 q->penaltymemberslimit = 0;
3118 q->joinempty = 0;
3119 q->leavewhenempty = 0;
3120 q->memberdelay = 0;
3121 q->weight = 0;
3122 q->timeoutrestart = 0;
3126 q->numperiodicannounce = 0;
3129 q->autopausebusy = 0;
3130 q->autopauseunavail = 0;
3132 q->autopausedelay = 0;
3134 if (!q->members) {
3136 /* linear strategy depends on order, so we have to place all members in a list */
3138 } else {
3141 }
3142 }
3143 q->found = 1;
3144
3145 ast_string_field_set(q, moh, "");
3146 ast_string_field_set(q, sound_next, "queue-youarenext");
3147 ast_string_field_set(q, sound_thereare, "queue-thereare");
3148 ast_string_field_set(q, sound_calls, "queue-callswaiting");
3149 ast_string_field_set(q, queue_quantity1, "queue-quantity1");
3150 ast_string_field_set(q, queue_quantity2, "queue-quantity2");
3151 ast_string_field_set(q, sound_holdtime, "queue-holdtime");
3152 ast_string_field_set(q, sound_minutes, "queue-minutes");
3153 ast_string_field_set(q, sound_minute, "queue-minute");
3154 ast_string_field_set(q, sound_seconds, "queue-seconds");
3155 ast_string_field_set(q, sound_thanks, "queue-thankyou");
3156 ast_string_field_set(q, sound_callerannounce, "");
3157 ast_string_field_set(q, sound_reporthold, "queue-reporthold");
3158
3159 if (!q->sound_periodicannounce[0]) {
3161 }
3162
3163 if (q->sound_periodicannounce[0]) {
3164 ast_str_set(&q->sound_periodicannounce[0], 0, "queue-periodic-announce");
3165 }
3166
3167 for (i = 1; i < MAX_PERIODIC_ANNOUNCEMENTS; i++) {
3168 if (q->sound_periodicannounce[i]) {
3169 ast_str_set(&q->sound_periodicannounce[i], 0, "%s", "");
3170 }
3171 }
3172
3173 while ((pr_iter = AST_LIST_REMOVE_HEAD(&q->rules,list))) {
3174 ast_free(pr_iter);
3175 }
3176
3177 /* On restart assume no members are available.
3178 * The queue_avail hint is a boolean state to indicate whether a member is available or not.
3179 *
3180 * This seems counter intuitive, but is required to light a BLF
3181 * AST_DEVICE_INUSE indicates no members are available.
3182 * AST_DEVICE_NOT_INUSE indicates a member is available.
3183 */
3185}
#define DEFAULT_RETRY
Definition: app_queue.c:1676
static int member_hash_fn(const void *obj, const int flags)
Definition: app_queue.c:3056
static int member_cmp_fn(void *obj1, void *obj2, int flags)
Definition: app_queue.c:3072
#define DEFAULT_MIN_ANNOUNCE_FREQUENCY
The minimum number of seconds between position announcements.
Definition: app_queue.c:1684
#define DEFAULT_TIMEOUT
Definition: app_queue.c:1677
static int autofill_default
queues.conf [general] option
Definition: app_queue.c:1719
#define ANNOUNCEPOSITION_YES
Definition: app_queue.c:1917
@ 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:1980
unsigned int setinterfacevar
Definition: app_queue.c:1966
int announcefrequency
Definition: app_queue.c:1984
unsigned int announceholdtime
Definition: app_queue.c:1972
unsigned int reportholdtime
Definition: app_queue.c:1969
unsigned int setqueueentryvar
Definition: app_queue.c:1968
unsigned int timeoutrestart
Definition: app_queue.c:1971
int periodicannouncefrequency
Definition: app_queue.c:1987
unsigned int announceposition_only_up
Definition: app_queue.c:1974
unsigned int setqueuevar
Definition: app_queue.c:1967
int announcepositionlimit
Definition: app_queue.c:1983
unsigned int announce_to_first_user
Definition: app_queue.c:1965
int randomperiodicannounce
Definition: app_queue.c:1989
int autopause
Definition: app_queue.c:2007
int periodicannouncestartdelay
Definition: app_queue.c:1986
int log_restricted_caller_id
Definition: app_queue.c:2016
struct call_queue::@54 rules
int servicelevel
Definition: app_queue.c:1996
int autofill
Definition: app_queue.c:2014
int minannouncefrequency
Definition: app_queue.c:1985
enum empty_conditions leavewhenempty
Definition: app_queue.c:1982
int roundingseconds
Definition: app_queue.c:1990
int numperiodicannounce
Definition: app_queue.c:1988
unsigned int announceposition
Definition: app_queue.c:1973
char monfmt[8]
Definition: app_queue.c:1998
enum empty_conditions joinempty
Definition: app_queue.c:1981
int memberdelay
Definition: app_queue.c:2013
unsigned int autopausebusy
Definition: app_queue.c:1979
int autopausedelay
Definition: app_queue.c:2008
int timeoutpriority
Definition: app_queue.c:2009
unsigned int relativeperiodicannounce
Definition: app_queue.c:1978

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

2221{
2222 struct queue_ent *cur;
2223
2224 if (!q || !new)
2225 return;
2226 if (prev) {
2227 cur = prev->next;
2228 prev->next = new;
2229 } else {
2230 cur = q->head;
2231 q->head = new;
2232 }
2233 new->next = cur;
2234
2235 /* every queue_ent must have a reference to it's parent call_queue, this
2236 * reference does not go away until the end of the queue_ent's life, meaning
2237 * that even when the queue_ent leaves the call_queue this ref must remain. */
2238 if (!new->parent) {
2239 queue_ref(q);
2240 new->parent = q;
2241 }
2242 new->pos = ++(*pos);
2243 new->opos = *pos;
2244}
#define queue_ref(q)
Definition: app_queue.c:2186

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

3220{
3221 char *timestr, *maxstr, *minstr, *raisestr, *contentdup;
3222 struct penalty_rule *rule = NULL, *rule_iter;
3223 struct rule_list *rl_iter;
3224 int penaltychangetime, inserted = 0;
3225
3226 if (!(rule = ast_calloc(1, sizeof(*rule)))) {
3227 return -1;
3228 }
3229
3230 contentdup = ast_strdupa(content);
3231
3232 if (!(maxstr = strchr(contentdup, ','))) {
3233 ast_log(LOG_WARNING, "Improperly formatted penaltychange rule at line %d. Ignoring.\n", linenum);
3234 ast_free(rule);
3235 return -1;
3236 }
3237
3238 *maxstr++ = '\0';
3239 if ((minstr = strchr(maxstr,','))) {
3240 *minstr++ = '\0';
3241 if ((raisestr = strchr(minstr,','))) {
3242 *raisestr++ = '\0';
3243 }
3244 } else {
3245 raisestr = NULL;
3246 }
3247
3248 timestr = contentdup;
3249 if ((penaltychangetime = atoi(timestr)) < 0) {
3250 ast_log(LOG_WARNING, "Improper time parameter specified for penaltychange rule at line %d. Ignoring.\n", linenum);
3251 ast_free(rule);
3252 return -1;
3253 }
3254
3255 rule->time = penaltychangetime;
3256
3257 /* The last check will evaluate true if either no penalty change is indicated for a given rule
3258 * OR if a min penalty change is indicated but no max penalty change is */
3259 if (*maxstr == '+' || *maxstr == '-' || *maxstr == '\0') {
3260 rule->max_relative = 1;
3261 }
3262
3263 rule->max_value = atoi(maxstr);
3264
3265 if (!ast_strlen_zero(minstr)) {
3266 if (*minstr == '+' || *minstr == '-') {
3267 rule->min_relative = 1;
3268 }
3269 rule->min_value = atoi(minstr);
3270 } else { /*there was no minimum specified, so assume this means no change*/
3271 rule->min_relative = 1;
3272 }
3273
3274 if (!ast_strlen_zero(raisestr)) {
3275 rule->raise_respect_min = 0; /* Initialize to 0 */
3276 if (*raisestr == 'r') {
3277 rule->raise_respect_min = 1; /* Set the flag */
3278 raisestr++;
3279 }
3280 if (*raisestr == '+' || *raisestr == '-') {
3281 rule->raise_relative = 1;
3282 }
3283 rule->raise_value = atoi(raisestr);
3284 } else { /*there was no raise specified, so assume this means no change*/
3285 rule->raise_relative = 1;
3286 }
3287
3288 /*We have the rule made, now we need to insert it where it belongs*/
3289 AST_LIST_TRAVERSE(&rule_lists, rl_iter, list){
3290 if (strcasecmp(rl_iter->name, list_name)) {
3291 continue;
3292 }
3293
3294 AST_LIST_TRAVERSE_SAFE_BEGIN(&rl_iter->rules, rule_iter, list) {
3295 if (rule->time < rule_iter->time) {
3297 inserted = 1;
3298 break;
3299 }
3300 }
3302
3303 if (!inserted) {
3304 AST_LIST_INSERT_TAIL(&rl_iter->rules, rule, list);
3305 inserted = 1;
3306 }
3307
3308 break;
3309 }
3310
3311 if (!inserted) {
3312 ast_log(LOG_WARNING, "Unknown rule list name %s; ignoring.\n", list_name);
3313 ast_free(rule);
3314 return -1;
3315 }
3316 return 0;
3317}
#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 2053 of file app_queue.c.

2054{
2055 int x;
2056
2057 for (x = 0; x < ARRAY_LEN(strategies); x++) {
2058 if (strategy == strategies[x].strategy) {
2059 return strategies[x].name;
2060 }
2061 }
2062
2063 return "<unknown>";
2064}
static const struct strategy strategies[]
const char * name
Definition: app_queue.c:1654

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

7618{
7619 struct member *mem;
7620 struct ao2_iterator mem_iter;
7621
7622 if (!q) {
7623 return NULL;
7624 }
7625 mem_iter = ao2_iterator_init(q->members, 0);
7626 while ((mem = ao2_iterator_next(&mem_iter))) {
7627 if (!strcasecmp(interface, mem->interface)) {
7628 ao2_iterator_destroy(&mem_iter);
7629 return mem;
7630 }
7631 ao2_ref(mem, -1);
7632 }
7633 ao2_iterator_destroy(&mem_iter);
7634
7635 return NULL;
7636}

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

4728{
4729 struct call_queue *q;
4730 struct member *mem;
4731 int is_longest_waiting = 1;
4732 struct ao2_iterator queue_iter;
4733 struct queue_ent *ch;
4734
4735 queue_iter = ao2_iterator_init(queues, 0);
4736 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
4737 if (q == caller->parent) { /* don't check myself, could deadlock */
4738 queue_t_unref(q, "Done with iterator");
4739 continue;
4740 }
4741 ao2_lock(q);
4742 /*
4743 * If the other queue has equal weight, see if we should let that handle
4744 * their call first. If weights are not equal, compare_weights will step in.
4745 */
4746 if (q->weight == caller->parent->weight && q->count && q->members) {
4747 if ((mem = ao2_find(q->members, member, OBJ_POINTER))) {
4748 ast_debug(2, "Found matching member %s in queue '%s'\n", mem->interface, q->name);
4749
4750 /* Does this queue have a caller that's been waiting longer? */
4751 ch = q->head;
4752 while (ch) {
4753 /* If ch->pending, the other call (which may be waiting for a longer period of time),
4754 * is already ringing at another agent. Ignore such callers; otherwise, all agents
4755 * will be unused until the first caller is picked up.
4756 */
4757 if (ch->start < caller->start && !ch->pending) {
4758 ast_debug(1, "Queue %s has a call at position %i that's been waiting longer (%li vs %li)\n",
4759 q->name, ch->pos, ch->start, caller->start);
4760 is_longest_waiting = 0;
4761 break;
4762 }
4763 ch = ch->next;
4764 }
4765 }
4766 }
4767 ao2_unlock(q);
4768 queue_t_unref(q, "Done with iterator");
4769 if (!is_longest_waiting) {
4770 break;
4771 }
4772 }
4773 ao2_iterator_destroy(&queue_iter);
4774 return is_longest_waiting;
4775}
int pending
Definition: app_queue.c:1838
time_t start
Definition: app_queue.c:1845

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

2743{
2744 int available = 0;
2745 int wrapuptime;
2746
2747 switch (mem->status) {
2748 case AST_DEVICE_INVALID:
2750 break;
2751 case AST_DEVICE_INUSE:
2752 case AST_DEVICE_BUSY:
2753 case AST_DEVICE_RINGING:
2755 case AST_DEVICE_ONHOLD:
2756 if (!mem->ringinuse) {
2757 break;
2758 }
2759 /* else fall through */
2761 case AST_DEVICE_UNKNOWN:
2762 if (!mem->paused) {
2763 available = 1;
2764 }
2765 break;
2766 }
2767
2768 /* Let wrapuptimes override device state availability */
2769 wrapuptime = get_wrapuptime(q, mem);
2770 if (mem->lastcall && wrapuptime && (time(NULL) - wrapuptime < mem->lastcall)) {
2771 available = 0;
2772 }
2773 return available;
2774}
static int available(struct dahdi_pvt **pvt, int is_specific_channel)
Definition: chan_dahdi.c:13565

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

5897{
5898 struct queue_ent *ch;
5899 int res;
5900 int avl;
5901 int idx = 0;
5902 /* This needs a lock. How many members are available to be served? */
5903 ao2_lock(qe->parent);
5904
5905 avl = num_available_members(qe->parent);
5906
5907 ch = qe->parent->head;
5908
5909 ast_debug(1, "There %s %d available %s.\n", avl != 1 ? "are" : "is", avl, avl != 1 ? "members" : "member");
5910
5911 while ((idx < avl) && (ch) && (ch != qe)) {
5912 if (!ch->pending) {
5913 idx++;
5914 }
5915 ch = ch->next;
5916 }
5917
5918 ao2_unlock(qe->parent);
5919 /* If the queue entry is within avl [the number of available members] calls from the top ...
5920 * Autofill and position check added to support autofill=no (as only calls
5921 * from the front of the queue are valid when autofill is disabled)
5922 */
5923 if (ch && idx < avl && (qe->parent->autofill || qe->pos == 1)) {
5924 ast_debug(1, "It's our turn (%s).\n", ast_channel_name(qe->chan));
5925 res = 1;
5926 } else {
5927 ast_debug(1, "It's not our turn (%s).\n", ast_channel_name(qe->chan));
5928 res = 0;
5929 }
5930
5931 /* Update realtime members if this is the first call and number of avalable members is 0 */
5932 if (avl == 0 && qe->pos == 1) {
5934 }
5935
5936 return res;
5937}

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

4211{
4212 struct call_queue *q;
4213 struct queue_ent *cur, *prev = NULL;
4214 int res = -1;
4215 int pos = 0;
4216 int inserted = 0;
4217
4218 if (!(q = find_load_queue_rt_friendly(queuename))) {
4219 return res;
4220 }
4221 ao2_lock(q);
4222
4223 /* This is our one */
4224 if (q->joinempty) {
4225 int status = 0;
4227 *reason = QUEUE_JOINEMPTY;
4228 ao2_unlock(q);
4229 queue_t_unref(q, "Done with realtime queue");
4230 return res;
4231 }
4232 }
4233 if (*reason == QUEUE_UNKNOWN && q->maxlen && (q->count >= q->maxlen)) {
4234 *reason = QUEUE_FULL;
4235 } else if (*reason == QUEUE_UNKNOWN) {
4236 RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
4237
4238 /* There's space for us, put us at the right position inside
4239 * the queue.
4240 * Take into account the priority of the calling user */
4241 inserted = 0;
4242 prev = NULL;
4243 cur = q->head;
4244 while (cur) {
4245 /* We have higher priority than the current user, enter
4246 * before him, after all the other users with priority
4247 * higher or equal to our priority. */
4248 if ((!inserted) && (qe->prio > cur->prio)) {
4249 insert_entry(q, prev, qe, &pos);
4250 inserted = 1;
4251 }
4252 /* <= is necessary for the position comparison because it may not be possible to enter
4253 * at our desired position since higher-priority callers may have taken the position we want
4254 */
4255 if (!inserted && (qe->prio >= cur->prio) && position && (position <= pos + 1)) {
4256 insert_entry(q, prev, qe, &pos);
4257 inserted = 1;
4258 /*pos is incremented inside insert_entry, so don't need to add 1 here*/
4259 if (position < pos) {
4260 ast_log(LOG_NOTICE, "Asked to be inserted at position %d but forced into position %d due to higher priority callers\n", position, pos);
4261 }
4262 }
4263 cur->pos = ++pos;
4264 prev = cur;
4265 cur = cur->next;
4266 }
4267 /* No luck, join at the end of the queue */
4268 if (!inserted) {
4269 insert_entry(q, prev, qe, &pos);
4270 }
4271 ast_copy_string(qe->moh, q->moh, sizeof(qe->moh));
4272 ast_copy_string(qe->announce, q->announce, sizeof(qe->announce));
4273 ast_copy_string(qe->context, q->context, sizeof(qe->context));
4274 q->count++;
4275 if (q->count == 1) {
4277 }
4278
4279 res = 0;
4280
4281 blob = ast_json_pack("{s: s, s: i, s: i}",
4282 "Queue", q->name,
4283 "Position", qe->pos,
4284 "Count", q->count);
4285 ast_channel_publish_cached_blob(qe->chan, queue_caller_join_type(), blob);
4286 ast_debug(1, "Queue '%s' Join, Channel '%s', Position '%d'\n", q->name, ast_channel_name(qe->chan), qe->pos );
4287 }
4288 ao2_unlock(q);
4289 queue_t_unref(q, "Done with realtime queue");
4290
4291 return res;
4292}
jack_status_t status
Definition: app_jack.c:149
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:1960
const ast_string_field context
Definition: app_queue.c:1960
const ast_string_field announce
Definition: app_queue.c:1960
int raise_respect_min
Definition: app_queue.c:1842
char announce[PATH_MAX]
Definition: app_queue.c:1824
char moh[MAX_MUSICCLASS]
Definition: app_queue.c:1823
char context[AST_MAX_CONTEXT]
Definition: app_queue.c:1825

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, queue_ent::raise_respect_min, and status.

Referenced by queue_exec().

◆ kill_dead_members()

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

Definition at line 9921 of file app_queue.c.

9922{
9923 struct member *member = obj;
9924
9925 if (!member->delme) {
9927 return 0;
9928 } else {
9929 return CMP_MATCH;
9930 }
9931}
@ CMP_MATCH
Definition: astobj2.h:1027
unsigned int delme
Definition: app_queue.c:1879

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

10077{
10078 struct call_queue *q = obj;
10079 char *queuename = arg;
10080 if (!q->realtime && !q->found && (ast_strlen_zero(queuename) || !strcasecmp(queuename, q->name))) {
10081 q->dead = 1;
10082 return CMP_MATCH;
10083 } else {
10084 return 0;
10085 }
10086}

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

4524{
4525 struct call_queue *q;
4526 struct queue_ent *current, *prev = NULL;
4527 struct penalty_rule *pr_iter;
4528 int pos = 0;
4529
4530 if (!(q = qe->parent)) {
4531 return;
4532 }
4533 queue_t_ref(q, "Copy queue pointer from queue entry");
4534 ao2_lock(q);
4535
4536 prev = NULL;
4537 for (current = q->head; current; current = current->next) {
4538 if (current == qe) {
4539 RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
4540 char posstr[20];
4541 q->count--;
4542 if (!q->count) {
4544 }
4545
4546 blob = ast_json_pack("{s: s, s: i, s: i}",
4547 "Queue", q->name,
4548 "Position", qe->pos,
4549 "Count", q->count);
4550 ast_channel_publish_cached_blob(qe->chan, queue_caller_leave_type(), blob);
4551 ast_debug(1, "Queue '%s' Leave, Channel '%s'\n", q->name, ast_channel_name(qe->chan));
4552 /* Take us out of the queue */
4553 if (prev) {
4554 prev->next = current->next;
4555 } else {
4556 q->head = current->next;
4557 }
4558 /* Free penalty rules */
4559 while ((pr_iter = AST_LIST_REMOVE_HEAD(&qe->qe_rules, list))) {
4560 ast_free(pr_iter);
4561 }
4562 qe->pr = NULL;
4563 snprintf(posstr, sizeof(posstr), "%d", qe->pos);
4564 pbx_builtin_setvar_helper(qe->chan, "QUEUEPOSITION", posstr);
4565 } else {
4566 /* Renumber the people after us in the queue based on a new count */
4567 current->pos = ++pos;
4568 prev = current;
4569 }
4570 }
4571 ao2_unlock(q);
4572
4573 /*If the queue is a realtime queue, check to see if it's still defined in real time*/
4574 if (q->realtime) {
4575 struct ast_variable *var;
4576 if (!(var = ast_load_realtime("queues", "name", q->name, SENTINEL))) {
4577 q->dead = 1;
4578 } else {
4580 }
4581 }
4582
4583 if (q->dead) {
4584 /* It's dead and nobody is in it, so kill it */
4585 queues_t_unlink(queues, q, "Queue is now dead; remove it from the container");
4586 }
4587 /* unref the explicit ref earlier in the function */
4588 queue_t_unref(q, "Expire copied reference");
4589}
#define queue_t_ref(q, tag)
Definition: app_queue.c:2188
#define var
Definition: ast_expr2f.c:605
struct penalty_rule * pr
Definition: app_queue.c:1852

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

11951{
11952 int err = 0;
11953 struct ast_flags mask = {AST_FLAGS_ALL, };
11954 struct ast_config *member_config;
11955 struct stasis_topic *queue_topic;
11957
11960 if (!queues) {
11962 }
11963
11966 if (!pending_members) {
11967 unload_module();
11969 }
11970
11971 use_weight = 0;
11972
11973 if (reload_handler(0, &mask, NULL)) {
11974 unload_module();
11976 }
11977
11978 ast_realtime_require_field("queue_members", "paused", RQ_INTEGER1, 1, "uniqueid", RQ_UINTEGER2, 5, "reason_paused", RQ_CHAR, 80, SENTINEL);
11979
11980 /*
11981 * This section is used to determine which name for 'ringinuse' to use in realtime members
11982 * Necessary for supporting older setups.
11983 *
11984 * It also checks if 'reason_paused' exists in the realtime backend
11985 */
11986 member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name LIKE", "%", SENTINEL);
11987 if (!member_config) {
11988 realtime_ringinuse_field = "ringinuse";
11989 } else {
11990 const char *config_val;
11991
11992 if ((config_val = ast_variable_retrieve(member_config, NULL, "ringinuse"))) {
11993 ast_log(LOG_NOTICE, "ringinuse field entries found in queue_members table. Using 'ringinuse'\n");
11994 realtime_ringinuse_field = "ringinuse";
11995 } else if ((config_val = ast_variable_retrieve(member_config, NULL, "ignorebusy"))) {
11996 ast_log(LOG_NOTICE, "ignorebusy field found in queue_members table with no ringinuse field. Using 'ignorebusy'\n");
11997 realtime_ringinuse_field = "ignorebusy";
11998 } else {
11999 ast_log(LOG_NOTICE, "No entries were found for ringinuse/ignorebusy in queue_members table. Using 'ringinuse'\n");
12000 realtime_ringinuse_field = "ringinuse";
12001 }
12002
12003 if (ast_variable_retrieve(member_config, NULL, "reason_paused")) {
12005 }
12006 }
12007 ast_config_destroy(member_config);
12008
12011 }
12012
12021 err |= ast_manager_register_xml("QueueStatus", 0, manager_queues_status);
12022 err |= ast_manager_register_xml("QueueSummary", 0, manager_queues_summary);
12029 err |= ast_manager_register_xml("QueueRule", 0, manager_queue_rule_show);
12030 err |= ast_manager_register_xml("QueueReload", 0, manager_queue_reload);
12031 err |= ast_manager_register_xml("QueueReset", 0, manager_queue_reset);
12032 err |= ast_manager_register_xml("QueueChangePriorityCaller", 0, manager_change_priority_caller_on_queue);
12041
12042 /* in the following subscribe call, do I use DEVICE_STATE, or DEVICE_STATE_CHANGE? */
12044 if (!device_state_sub) {
12045 err = -1;
12046 }
12049
12051 queue_topic = ast_queue_topic_all();
12052 if (!manager_topic || !queue_topic) {
12053 unload_module();
12055 }
12057 if (!topic_forwarder) {
12058 unload_module();
12060 }
12061
12064 unload_module();
12066 }
12068 if (!agent_router) {
12069 unload_module();
12071 }
12075 NULL);
12079 NULL);
12080
12081 err |= STASIS_MESSAGE_TYPE_INIT(queue_caller_join_type);
12082 err |= STASIS_MESSAGE_TYPE_INIT(queue_caller_leave_type);
12083 err |= STASIS_MESSAGE_TYPE_INIT(queue_caller_abandon_type);
12084
12085 err |= STASIS_MESSAGE_TYPE_INIT(queue_member_status_type);
12086 err |= STASIS_MESSAGE_TYPE_INIT(queue_member_added_type);
12087 err |= STASIS_MESSAGE_TYPE_INIT(queue_member_removed_type);
12088 err |= STASIS_MESSAGE_TYPE_INIT(queue_member_pause_type);
12089 err |= STASIS_MESSAGE_TYPE_INIT(queue_member_penalty_type);
12090 err |= STASIS_MESSAGE_TYPE_INIT(queue_member_ringinuse_type);
12091
12092 err |= STASIS_MESSAGE_TYPE_INIT(queue_agent_called_type);
12093 err |= STASIS_MESSAGE_TYPE_INIT(queue_agent_connect_type);
12094 err |= STASIS_MESSAGE_TYPE_INIT(queue_agent_complete_type);
12095 err |= STASIS_MESSAGE_TYPE_INIT(queue_agent_dump_type);
12096 err |= STASIS_MESSAGE_TYPE_INIT(queue_agent_ringnoanswer_type);
12097
12098 if (err) {
12099 unload_module();
12101 }
12103}
static struct ast_custom_function queuevar_function
Definition: app_queue.c:9613
static int manager_queue_reset(struct mansession *s, const struct message *m)
Definition: app_queue.c:10985
static int pending_members_cmp(void *obj, void *arg, int flags)
Definition: app_queue.c:2672
static struct ast_custom_function queuemembercount_function
Definition: app_queue.c:9618
static struct ast_custom_function queuewaitingcount_function
Definition: app_queue.c:9629
static char * app_pqm
Definition: app_queue.c:1701
static struct ast_custom_function queuememberlist_function
Definition: app_queue.c:9634
static char * realtime_ringinuse_field
name of the ringinuse field in the realtime database
Definition: app_queue.c:1749
static int manager_add_queue_member(struct mansession *s, const struct message *m)
Definition: app_queue.c:10795
static int aqm_exec(struct ast_channel *chan, const char *data)
AddQueueMember application.
Definition: app_queue.c:8518
#define MAX_QUEUE_BUCKETS
Definition: app_queue.c:1686
static int upqm_exec(struct ast_channel *chan, const char *data)
UnpauseQueueMember application.
Definition: app_queue.c:8411
static void queue_agent_cb(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Definition: app_queue.c:6311
static char * app_ql
Definition: app_queue.c:1705
static void reload_queue_members(void)
Reload dynamic queue members persisted into the astdb.
Definition: app_queue.c:8264
static int rqm_exec(struct ast_channel *chan, const char *data)
RemoveQueueMember application.
Definition: app_queue.c:8447
#define MAX_CALL_ATTEMPT_BUCKETS
Definition: app_queue.c:2650
static char * app_rqm
Definition: app_queue.c:1699
static int manager_queue_rule_show(struct mansession *s, const struct message *m)
Definition: app_queue.c:10554
static int manager_queue_reload(struct mansession *s, const struct message *m)
Definition: app_queue.c:10953
static int pqm_exec(struct ast_channel *chan, const char *data)
PauseQueueMember application.
Definition: app_queue.c:8375
static int qupd_exec(struct ast_channel *chan, const char *data)
Update Queue with data of an outgoing call.
Definition: app_queue.c:11783
static int manager_queue_member_ringinuse(struct mansession *s, const struct message *m)
Definition: app_queue.c:11031
static char * app_qupd
Definition: app_queue.c:1707
static int manager_queue_member_penalty(struct mansession *s, const struct message *m)
Definition: app_queue.c:11065
static char * app_upqm
Definition: app_queue.c:1703
static struct ast_custom_function queuememberpenalty_function
Definition: app_queue.c:9639
static int queue_cmp_cb(void *obj, void *arg, int flags)
Definition: app_queue.c:2109
static int manager_request_withdraw_caller_from_queue(struct mansession *s, const struct message *m)
Definition: app_queue.c:11138
static char * app
Definition: app_queue.c:1695
static int queue_hash_cb(const void *obj, const int flags)
Definition: app_queue.c:2102
static int queue_exec(struct ast_channel *chan, const char *data)
The starting point for all queue calls.
Definition: app_queue.c:8689
static int pending_members_hash(const void *obj, const int flags)
Definition: app_queue.c:2652
static int manager_pause_queue_member(struct mansession *s, const struct message *m)
Definition: app_queue.c:10907
static int ql_exec(struct ast_channel *chan, const char *data)
QueueLog application.
Definition: app_queue.c:8612
static int manager_remove_queue_member(struct mansession *s, const struct message *m)
Definition: app_queue.c:10860
static struct stasis_message_router * agent_router
Definition: app_queue.c:11873
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:2777
static struct stasis_subscription * device_state_sub
Subscription to device state change messages.
Definition: app_queue.c:1731
static int manager_queues_summary(struct mansession *s, const struct message *m)
Summary of queue info via the AMI.
Definition: app_queue.c:10590
static int unload_module(void)
Definition: app_queue.c:11876
static int manager_queues_status(struct mansession *s, const struct message *m)
Queue status info via AMI.
Definition: app_queue.c:10672
static int realtime_reason_paused
does realtime backend support reason_paused
Definition: app_queue.c:1752
static char * app_aqm
Definition: app_queue.c:1697
static struct ast_cli_entry cli_queue[]
Definition: app_queue.c:11860
static struct ast_custom_function queuegetchannel_function
Definition: app_queue.c:9624
static struct stasis_forward * topic_forwarder
Definition: app_queue.c:11874
static struct ast_custom_function queueexists_function
Definition: app_queue.c:9608
static int manager_change_priority_caller_on_queue(struct mansession *s, const struct message *m)
Definition: app_queue.c:11091
static int manager_queue_log_custom(struct mansession *s, const struct message *m)
Definition: app_queue.c:10932
#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:671
struct stasis_topic * ast_manager_get_topic(void)
Get the Stasis Message Bus API topic for AMI.
Definition: manager.c:450
static struct stasis_topic * manager_topic
A stasis_topic that all topics AMI cares about will be forwarded to.
Definition: manager.c:182
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:3816
#define ast_manager_register_xml(action, authority, func)
Register a manager callback using XML documentation to describe the manager.
Definition: manager.h:192
#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:1562
@ 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:1090
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:1144
#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:1645
#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_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 4107 of file app_queue.c.

4108{
4109 struct ast_config *cfg = NULL;
4110 char *category = NULL;
4111 const char *name = NULL;
4112 struct call_queue *q = NULL;
4113
4114 if (!ast_check_realtime("queues")) {
4115 return;
4116 }
4117
4118 if (ast_strlen_zero(queuename)) {
4119 if ((cfg = ast_load_realtime_multientry("queues", "name LIKE", "%", SENTINEL))) {
4120 while ((category = ast_category_browse(cfg, category))) {
4121 name = ast_variable_retrieve(cfg, category, "name");
4123 queue_unref(q);
4124 }
4125 }
4126 ast_config_destroy(cfg);
4127 }
4128 } else {
4129 if ((q = find_load_queue_rt_friendly(queuename))) {
4130 queue_unref(q);
4131 }
4132 }
4133}

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

3329{
3330 struct ast_config *cfg;
3331 struct rule_list *rl_iter, *new_rl;
3332 struct penalty_rule *pr_iter;
3333 char *rulecat = NULL;
3334
3335 if (!ast_check_realtime("queue_rules")) {
3336 ast_log(LOG_WARNING, "Missing \"queue_rules\" in extconfig.conf\n");
3337 return 0;
3338 }
3339 if (!(cfg = ast_load_realtime_multientry("queue_rules", "rule_name LIKE", "%", SENTINEL))) {
3340 ast_log(LOG_WARNING, "Failed to load queue rules from realtime\n");
3341 return 0;
3342 }
3343 while ((rulecat = ast_category_browse(cfg, rulecat))) {
3344 const char *timestr, *maxstr, *minstr, *raisestr, *rule_name;
3345 int penaltychangetime, rule_exists = 0, inserted = 0;
3346 int max_penalty = 0, min_penalty = 0, raise_penalty = 0;
3347 int min_relative = 0, max_relative = 0, raise_relative = 0;
3348 struct penalty_rule *new_penalty_rule = NULL;
3349
3350 rule_name = ast_variable_retrieve(cfg, rulecat, "rule_name");
3351 if (ast_strlen_zero(rule_name)) {
3352 continue;
3353 }
3354
3355 AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) {
3356 if (!(strcasecmp(rl_iter->name, rule_name))) {
3357 rule_exists = 1;
3358 new_rl = rl_iter;
3359 break;
3360 }
3361 }
3362 if (!rule_exists) {
3363 if (!(new_rl = ast_calloc(1, sizeof(*new_rl)))) {
3364 ast_config_destroy(cfg);
3365 return -1;
3366 }
3367 ast_copy_string(new_rl->name, rule_name, sizeof(new_rl->name));
3369 }
3370 timestr = ast_variable_retrieve(cfg, rulecat, "time");
3371 if (!(timestr) || sscanf(timestr, "%30d", &penaltychangetime) != 1) {
3372 ast_log(LOG_NOTICE, "Failed to parse time (%s) for one of the %s rules, skipping it\n",
3373 (ast_strlen_zero(timestr) ? "invalid value" : timestr), rule_name);
3374 continue;
3375 }
3376 if (!(new_penalty_rule = ast_calloc(1, sizeof(*new_penalty_rule)))) {
3377 ast_config_destroy(cfg);
3378 return -1;
3379 }
3380 if (!(maxstr = ast_variable_retrieve(cfg, rulecat, "max_penalty")) ||
3381 ast_strlen_zero(maxstr) || sscanf(maxstr, "%30d", &max_penalty) != 1) {
3382 max_penalty = 0;
3383 max_relative = 1;
3384 } else {
3385 if (*maxstr == '+' || *maxstr == '-') {
3386 max_relative = 1;
3387 }
3388 }
3389 if (!(minstr = ast_variable_retrieve(cfg, rulecat, "min_penalty")) ||
3390 ast_strlen_zero(minstr) || sscanf(minstr, "%30d", &min_penalty) != 1) {
3391 min_penalty = 0;
3392 min_relative = 1;
3393 } else {
3394 if (*minstr == '+' || *minstr == '-') {
3395 min_relative = 1;
3396 }
3397 }
3398 if (!(raisestr = ast_variable_retrieve(cfg, rulecat, "raise_penalty")) ||
3399 ast_strlen_zero(raisestr) ) {
3400 raise_penalty = 0;
3401 raise_relative = 1;
3402 } else {
3403 if (*raisestr == 'r') {
3404 new_penalty_rule->raise_respect_min = 1;
3405 raisestr++;
3406 } else {
3407 new_penalty_rule->raise_respect_min = 0;
3408 }
3409 if (*raisestr == '+' || *raisestr == '-') {
3410 raise_relative = 1;
3411 }
3412 if (sscanf(raisestr, "%30d", &raise_penalty) != 1) {
3413 raise_penalty = 0;
3414 raise_relative = 1;
3415 }
3416 }
3417 new_penalty_rule->time = penaltychangetime;
3418 new_penalty_rule->max_relative = max_relative;
3419 new_penalty_rule->max_value = max_penalty;
3420 new_penalty_rule->min_relative = min_relative;
3421 new_penalty_rule->min_value = min_penalty;
3422 new_penalty_rule->raise_relative = raise_relative;
3423 new_penalty_rule->raise_value = raise_penalty;
3424 AST_LIST_TRAVERSE_SAFE_BEGIN(&new_rl->rules, pr_iter, list) {
3425 if (new_penalty_rule->time < pr_iter->time) {
3426 AST_LIST_INSERT_BEFORE_CURRENT(new_penalty_rule, list);
3427 inserted = 1;
3428 }
3429 }
3431 if (!inserted) {
3432 AST_LIST_INSERT_TAIL(&new_rl->rules, new_penalty_rule, list);
3433 }
3434 }
3435
3436 ast_config_destroy(cfg);
3437 return 0;
3438}
int raise_respect_min
Definition: app_queue.c:1913

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_respect_min, 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 6481 of file app_queue.c.

6483{
6484 RAII_VAR(struct ast_str *, transfer_str, ast_str_create(32), ast_free);
6485
6486 if (!transfer_str) {
6487 ast_log(LOG_WARNING, "Unable to log attended transfer to queue log\n");
6488 return;
6489 }
6490
6491 switch (atxfer_msg->dest_type) {
6493 ast_str_set(&transfer_str, 0, "BRIDGE|%s", atxfer_msg->dest.bridge);
6494 break;
6497 ast_str_set(&transfer_str, 0, "APP|%s", atxfer_msg->dest.app);
6498 break;
6500 ast_str_set(&transfer_str, 0, "LINK|%s|%s", atxfer_msg->dest.links[0]->base->name,
6501 atxfer_msg->dest.links[1]->base->name);
6502 break;
6505 /* Threeways are headed off and should not be logged here */
6506 ast_assert(0);
6507 return;
6508 }
6509
6510 ast_queue_log(queue_data->queue->name, queue_data->caller_uniqueid, queue_data->member->membername, "ATTENDEDTRANSFER", "%s|%ld|%ld|%d",
6511 ast_str_buffer(transfer_str),
6512 (long) (queue_data->starttime - queue_data->holdstart),
6513 (long) (time(NULL) - queue_data->starttime), queue_data->caller_pos);
6514}
@ 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
struct ast_channel_snapshot * links[2]
union ast_attended_transfer_message::@289 dest
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 10795 of file app_queue.c.

10796{
10797 const char *queuename, *interface, *penalty_s, *paused_s, *reason, *membername, *state_interface, *wrapuptime_s;
10798 int paused, penalty, wrapuptime = 0;
10799
10800 queuename = astman_get_header(m, "Queue");
10801 interface = astman_get_header(m, "Interface");
10802 penalty_s = astman_get_header(m, "Penalty");
10803 paused_s = astman_get_header(m, "Paused");
10804 reason = astman_get_header(m, "Reason"); /* Optional */
10805 membername = astman_get_header(m, "MemberName");
10806 state_interface = astman_get_header(m, "StateInterface");
10807 wrapuptime_s = astman_get_header(m, "Wrapuptime");
10808
10809 if (ast_strlen_zero(queuename)) {
10810 astman_send_error(s, m, "'Queue' not specified.");
10811 return 0;
10812 }
10813
10814 if (ast_strlen_zero(interface)) {
10815 astman_send_error(s, m, "'Interface' not specified.");
10816 return 0;
10817 }
10818
10819 if (ast_strlen_zero(penalty_s)) {
10820 penalty = 0;
10821 } else if (sscanf(penalty_s, "%30d", &penalty) != 1 || penalty < 0) {
10822 penalty = 0;
10823 }
10824
10825 if (ast_strlen_zero(wrapuptime_s)) {
10826 wrapuptime = 0;
10827 } else if (sscanf(wrapuptime_s, "%30d", &wrapuptime) != 1 || wrapuptime < 0) {
10828 wrapuptime = 0;
10829 }
10830
10831 if (ast_strlen_zero(paused_s)) {
10832 paused = 0;
10833 } else {
10834 paused = abs(ast_true(paused_s));
10835 }
10836
10837 switch (add_to_queue(queuename, interface, membername, penalty, paused, queue_persistent_members, state_interface, reason, wrapuptime)) {
10838 case RES_OKAY:
10839 if (ast_strlen_zero(membername) || !log_membername_as_agent) {
10840 ast_queue_log(queuename, "MANAGER", interface, "ADDMEMBER", "%s", paused ? "PAUSED" : "");
10841 } else {
10842 ast_queue_log(queuename, "MANAGER", membername, "ADDMEMBER", "%s", paused ? "PAUSED" : "");
10843 }
10844 astman_send_ack(s, m, "Added interface to queue");
10845 break;
10846 case RES_EXISTS:
10847 astman_send_error(s, m, "Unable to add interface: Already there");
10848 break;
10849 case RES_NOSUCHQUEUE:
10850 astman_send_error(s, m, "Unable to add interface to queue: No such queue");
10851 break;
10852 case RES_OUTOFMEMORY:
10853 astman_send_error(s, m, "Out of memory");
10854 break;
10855 }
10856
10857 return 0;
10858}
#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:1982
void astman_send_ack(struct mansession *s, const struct message *m, char *msg)
Send ack in manager transaction.
Definition: manager.c:2014
const char * astman_get_header(const struct message *m, char *var)
Get header from manager transaction.
Definition: manager.c:1643

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

11092{
11093 const char *queuename, *caller, *priority_s, *immediate_s;
11094 int priority = 0, immediate = 0;
11095
11096 queuename = astman_get_header(m, "Queue");
11097 caller = astman_get_header(m, "Caller");
11098 priority_s = astman_get_header(m, "Priority");
11099 immediate_s = astman_get_header(m, "Immediate");
11100
11101 if (ast_strlen_zero(queuename)) {
11102 astman_send_error(s, m, "'Queue' not specified.");
11103 return 0;
11104 }
11105
11106 if (ast_strlen_zero(caller)) {
11107 astman_send_error(s, m, "'Caller' not specified.");
11108 return 0;
11109 }
11110
11111 if (ast_strlen_zero(priority_s)) {
11112 astman_send_error(s, m, "'Priority' not specified.");
11113 return 0;
11114 } else if (sscanf(priority_s, "%30d", &priority) != 1) {
11115 astman_send_error(s, m, "'Priority' need integer.");
11116 return 0;
11117 }
11118
11119 if (!ast_strlen_zero(immediate_s)) {
11120 immediate = ast_true(immediate_s);
11121 }
11122
11123 switch (change_priority_caller_on_queue(queuename, caller, priority, immediate)) {
11124 case RES_OKAY:
11125 astman_send_ack(s, m, "Priority change for caller on queue");
11126 break;
11127 case RES_NOSUCHQUEUE:
11128 astman_send_error(s, m, "Unable to change priority caller on queue: No such queue");
11129 break;
11130 case RES_NOT_CALLER:
11131 astman_send_error(s, m, "Unable to change priority caller on queue: No such caller");
11132 break;
11133 }
11134
11135 return 0;
11136}

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

10908{
10909 const char *queuename, *interface, *paused_s, *reason;
10910 int paused;
10911
10912 interface = astman_get_header(m, "Interface");
10913 paused_s = astman_get_header(m, "Paused");
10914 queuename = astman_get_header(m, "Queue"); /* Optional - if not supplied, pause the given Interface in all queues */
10915 reason = astman_get_header(m, "Reason"); /* Optional */
10916
10917 if (ast_strlen_zero(interface) || ast_strlen_zero(paused_s)) {
10918 astman_send_error(s, m, "Need 'Interface' and 'Paused' parameters.");
10919 return 0;
10920 }
10921
10922 paused = abs(ast_true(paused_s));
10923
10924 if (set_member_paused(queuename, interface, reason, paused)) {
10925 astman_send_error(s, m, "Interface not found");
10926 } else {
10927 astman_send_ack(s, m, paused ? "Interface paused successfully" : "Interface unpaused successfully");
10928 }
10929 return 0;
10930}

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

10933{
10934 const char *queuename, *event, *message, *interface, *uniqueid;
10935
10936 queuename = astman_get_header(m, "Queue");
10937 uniqueid = astman_get_header(m, "UniqueId");
10938 interface = astman_get_header(m, "Interface");
10939 event = astman_get_header(m, "Event");
10940 message = astman_get_header(m, "Message");
10941
10942 if (ast_strlen_zero(queuename) || ast_strlen_zero(event)) {
10943 astman_send_error(s, m, "Need 'Queue' and 'Event' parameters.");
10944 return 0;
10945 }
10946
10947 ast_queue_log(queuename, S_OR(uniqueid, "NONE"), interface, event, "%s", message);
10948 astman_send_ack(s, m, "Event added successfully");
10949
10950 return 0;
10951}
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 11065 of file app_queue.c.

11066{
11067 const char *queuename, *interface, *penalty_s;
11068 int penalty;
11069
11070 interface = astman_get_header(m, "Interface");
11071 penalty_s = astman_get_header(m, "Penalty");
11072 /* Optional - if not supplied, set the penalty value for the given Interface in all queues */
11073 queuename = astman_get_header(m, "Queue");
11074
11075 if (ast_strlen_zero(interface) || ast_strlen_zero(penalty_s)) {
11076 astman_send_error(s, m, "Need 'Interface' and 'Penalty' parameters.");
11077 return 0;
11078 }
11079
11080 penalty = atoi(penalty_s);
11081
11082 if (set_member_value((char *)queuename, (char *)interface, MEMBER_PENALTY, penalty)) {
11083 astman_send_error(s, m, "Invalid interface, queuename or penalty");
11084 } else {
11085 astman_send_ack(s, m, "Interface penalty set successfully");
11086 }
11087
11088 return 0;
11089}

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

11032{
11033 const char *queuename, *interface, *ringinuse_s;
11034 int ringinuse;
11035
11036 interface = astman_get_header(m, "Interface");
11037 ringinuse_s = astman_get_header(m, "RingInUse");
11038
11039 /* Optional - if not supplied, set the ringinuse value for the given Interface in all queues */
11040 queuename = astman_get_header(m, "Queue");
11041
11042 if (ast_strlen_zero(interface) || ast_strlen_zero(ringinuse_s)) {
11043 astman_send_error(s, m, "Need 'Interface' and 'RingInUse' parameters.");
11044 return 0;
11045 }
11046
11047 if (ast_true(ringinuse_s)) {
11048 ringinuse = 1;
11049 } else if (ast_false(ringinuse_s)) {
11050 ringinuse = 0;
11051 } else {
11052 astman_send_error(s, m, "'RingInUse' parameter must be a truth value (yes/no, on/off, 0/1, etc)");
11053 return 0;
11054 }
11055
11056 if (set_member_value(queuename, interface, MEMBER_RINGINUSE, ringinuse)) {
11057 astman_send_error(s, m, "Invalid interface, queuename, or ringinuse value\n");
11058 } else {
11059 astman_send_ack(s, m, "Interface ringinuse set successfully");
11060 }
11061
11062 return 0;
11063}

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

10954{
10955 struct ast_flags mask = {0,};
10956 const char *queuename = NULL;
10957 int header_found = 0;
10958
10959 queuename = astman_get_header(m, "Queue");
10960 if (!strcasecmp(S_OR(astman_get_header(m, "Members"), ""), "yes")) {
10962 header_found = 1;
10963 }
10964 if (!strcasecmp(S_OR(astman_get_header(m, "Rules"), ""), "yes")) {
10966 header_found = 1;
10967 }
10968 if (!strcasecmp(S_OR(astman_get_header(m, "Parameters"), ""), "yes")) {
10970 header_found = 1;
10971 }
10972
10973 if (!header_found) {
10975 }
10976
10977 if (!reload_handler(1, &mask, queuename)) {
10978 astman_send_ack(s, m, "Queue reloaded successfully");
10979 } else {
10980 astman_send_error(s, m, "Error encountered while reloading queue");
10981 }
10982 return 0;
10983}

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

10986{
10987 const char *queuename = NULL;
10988 struct ast_flags mask = {QUEUE_RESET_STATS,};
10989
10990 queuename = astman_get_header(m, "Queue");
10991
10992 if (!reload_handler(1, &mask, queuename)) {
10993 astman_send_ack(s, m, "Queue stats reset successfully");
10994 } else {
10995 astman_send_error(s, m, "Error encountered while resetting queue stats");
10996 }
10997 return 0;
10998}

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

10555{
10556 const char *rule = astman_get_header(m, "Rule");
10557 const char *id = astman_get_header(m, "ActionID");
10558 struct rule_list *rl_iter;
10559 struct penalty_rule *pr_iter;
10560
10561 astman_append(s, "Response: Success\r\n");
10562 if (!ast_strlen_zero(id)) {
10563 astman_append(s, "ActionID: %s\r\n", id);
10564 }
10565
10567 AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) {
10568 if (ast_strlen_zero(rule) || !strcasecmp(rule, rl_iter->name)) {
10569 astman_append(s, "RuleList: %s\r\n", rl_iter->name);
10570 AST_LIST_TRAVERSE(&rl_iter->rules, pr_iter, list) {
10571 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 );
10572 }
10573 if (!ast_strlen_zero(rule)) {
10574 break;
10575 }
10576 }
10577 }
10579
10580 /*
10581 * Two blank lines instead of one because the Response and
10582 * ActionID headers used to not be present.
10583 */
10584 astman_append(s, "\r\n\r\n");
10585
10586 return RESULT_SUCCESS;
10587}

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

10673{
10674 time_t now;
10675 int pos;
10676 int q_items = 0;
10677 const char *id = astman_get_header(m,"ActionID");
10678 const char *queuefilter = astman_get_header(m,"Queue");
10679 const char *memberfilter = astman_get_header(m,"Member");
10680 char idText[256];
10681 struct call_queue *q;
10682 struct queue_ent *qe;
10683 float sl = 0;
10684 float sl2 = 0;
10685 struct member *mem;
10686 struct ao2_iterator queue_iter;
10687 struct ao2_iterator mem_iter;
10688
10689 if (ast_check_realtime("queues")) {
10690 load_realtime_queues(queuefilter);
10691 }
10692
10693 astman_send_listack(s, m, "Queue status will follow", "start");
10694 time(&now);
10695 idText[0] = '\0';
10696 if (!ast_strlen_zero(id)) {
10697 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
10698 }
10699
10700 queue_iter = ao2_iterator_init(queues, 0);
10701 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
10702 ao2_lock(q);
10703
10704 /* List queue properties */
10705 if (ast_strlen_zero(queuefilter) || !strcasecmp(q->name, queuefilter)) {
10706 sl = ((q->callscompleted > 0) ? 100 * ((float)q->callscompletedinsl / (float)q->callscompleted) : 0);
10707 sl2 = (((q->callscompleted + q->callsabandoned) > 0) ? 100 * (((float)q->callsabandonedinsl + (float)q->callscompletedinsl) / ((float)q->callsabandoned + (float)q->callscompleted)) : 0);
10708
10709 astman_append(s, "Event: QueueParams\r\n"
10710 "Queue: %s\r\n"
10711 "Max: %d\r\n"
10712 "Strategy: %s\r\n"
10713 "Calls: %d\r\n"
10714 "Holdtime: %d\r\n"
10715 "TalkTime: %d\r\n"
10716 "Completed: %d\r\n"
10717 "Abandoned: %d\r\n"
10718 "ServiceLevel: %d\r\n"
10719 "ServicelevelPerf: %2.1f\r\n"
10720 "ServicelevelPerf2: %2.1f\r\n"
10721 "Weight: %d\r\n"
10722 "%s"
10723 "\r\n",
10724 q->name, q->maxlen, int2strat(q->strategy), q->count, q->holdtime, q->talktime, q->callscompleted,
10725 q->callsabandoned, q->servicelevel, sl, sl2, q->weight, idText);
10726 ++q_items;
10727
10728 /* List Queue Members */
10729 mem_iter = ao2_iterator_init(q->members, 0);
10730 while ((mem = ao2_iterator_next(&mem_iter))) {
10731 if (ast_strlen_zero(memberfilter) || !strcmp(mem->interface, memberfilter) || !strcmp(mem->membername, memberfilter)) {
10732 astman_append(s, "Event: QueueMember\r\n"
10733 "Queue: %s\r\n"
10734 "Name: %s\r\n"
10735 "Location: %s\r\n"
10736 "StateInterface: %s\r\n"
10737 "Membership: %s\r\n"
10738 "Penalty: %d\r\n"
10739 "CallsTaken: %d\r\n"
10740 "LastCall: %d\r\n"
10741 "LastPause: %d\r\n"
10742 "LoginTime: %d\r\n"
10743 "InCall: %d\r\n"
10744 "Status: %d\r\n"
10745 "Paused: %d\r\n"
10746 "PausedReason: %s\r\n"
10747 "Wrapuptime: %d\r\n"
10748 "%s"
10749 "\r\n",
10750 q->name, mem->membername, mem->interface, mem->state_interface, mem->dynamic ? "dynamic" : "static",
10751 mem->penalty, mem->calls, (int)mem->lastcall, (int)mem->lastpause, (int)mem->logintime, mem->starttime ? 1 : 0, mem->status,
10752 mem->paused, mem->reason_paused, mem->wrapuptime, idText);
10753 ++q_items;
10754 }
10755 ao2_ref(mem, -1);
10756 }
10757 ao2_iterator_destroy(&mem_iter);
10758
10759 /* List Queue Entries */
10760 pos = 1;
10761 for (qe = q->head; qe; qe = qe->next) {
10762 astman_append(s, "Event: QueueEntry\r\n"
10763 "Queue: %s\r\n"
10764 "Position: %d\r\n"
10765 "Channel: %s\r\n"
10766 "Uniqueid: %s\r\n"
10767 "CallerIDNum: %s\r\n"
10768 "CallerIDName: %s\r\n"
10769 "ConnectedLineNum: %s\r\n"
10770 "ConnectedLineName: %s\r\n"
10771 "Wait: %ld\r\n"
10772 "Priority: %d\r\n"
10773 "%s"
10774 "\r\n",
10775 q->name, pos++, ast_channel_name(qe->chan), ast_channel_uniqueid(qe->chan),
10780 (long) (now - qe->start), qe->prio, idText);
10781 ++q_items;
10782 }
10783 }
10784 ao2_unlock(q);
10785 queue_t_unref(q, "Done with iterator");
10786 }
10787 ao2_iterator_destroy(&queue_iter);
10788
10789 astman_send_list_complete_start(s, m, "QueueStatusComplete", q_items);
10791
10792 return RESULT_SUCCESS;
10793}
static void load_realtime_queues(const char *queuename)
Definition: app_queue.c:4107
static const char * int2strat(int strategy)
Definition: app_queue.c:2053
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:2024
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:2060
void astman_send_list_complete_end(struct mansession *s)
End the list complete event.
Definition: manager.c:2068
#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 10590 of file app_queue.c.

10591{
10592 time_t now;
10593 int qmemcount = 0;
10594 int qmemavail = 0;
10595 int qchancount = 0;
10596 int qlongestholdtime = 0;
10597 int qsummaries = 0;
10598 const char *id = astman_get_header(m, "ActionID");
10599 const char *queuefilter = astman_get_header(m, "Queue");
10600 char idText[256];
10601 struct call_queue *q;
10602 struct queue_ent *qe;
10603 struct member *mem;
10604 struct ao2_iterator queue_iter;
10605 struct ao2_iterator mem_iter;
10606
10607 if (ast_check_realtime("queues")) {
10608 load_realtime_queues(queuefilter);
10609 }
10610
10611 astman_send_listack(s, m, "Queue summary will follow", "start");
10612 time(&now);
10613 idText[0] = '\0';
10614 if (!ast_strlen_zero(id)) {
10615 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
10616 }
10617 queue_iter = ao2_iterator_init(queues, 0);
10618 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
10619 ao2_lock(q);
10620
10621 /* List queue properties */
10622 if (ast_strlen_zero(queuefilter) || !strcasecmp(q->name, queuefilter)) {
10623 /* Reset the necessary local variables if no queuefilter is set*/
10624 qmemcount = 0;
10625 qmemavail = 0;
10626 qchancount = 0;
10627 qlongestholdtime = 0;
10628
10629 /* List Queue Members */
10630 mem_iter = ao2_iterator_init(q->members, 0);
10631 while ((mem = ao2_iterator_next(&mem_iter))) {
10632 if ((mem->status != AST_DEVICE_UNAVAILABLE) && (mem->status != AST_DEVICE_INVALID)) {
10633 ++qmemcount;
10634 if (member_status_available(mem->status) && !mem->paused) {
10635 ++qmemavail;
10636 }
10637 }
10638 ao2_ref(mem, -1);
10639 }
10640 ao2_iterator_destroy(&mem_iter);
10641 for (qe = q->head; qe; qe = qe->next) {
10642 if ((now - qe->start) > qlongestholdtime) {
10643 qlongestholdtime = now - qe->start;
10644 }
10645 ++qchancount;
10646 }
10647 astman_append(s, "Event: QueueSummary\r\n"
10648 "Queue: %s\r\n"
10649 "LoggedIn: %d\r\n"
10650 "Available: %d\r\n"
10651 "Callers: %d\r\n"
10652 "HoldTime: %d\r\n"
10653 "TalkTime: %d\r\n"
10654 "LongestHoldTime: %d\r\n"
10655 "%s"
10656 "\r\n",
10657 q->name, qmemcount, qmemavail, qchancount, q->holdtime, q->talktime, qlongestholdtime, idText);
10658 ++qsummaries;
10659 }
10660 ao2_unlock(q);
10661 queue_t_unref(q, "Done with iterator");
10662 }
10663 ao2_iterator_destroy(&queue_iter);
10664
10665 astman_send_list_complete_start(s, m, "QueueSummaryComplete", qsummaries);
10667
10668 return RESULT_SUCCESS;
10669}

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

10861{
10862 const char *queuename, *interface;
10863 struct member *mem = NULL;
10864
10865 queuename = astman_get_header(m, "Queue");
10866 interface = astman_get_header(m, "Interface");
10867
10868 if (ast_strlen_zero(queuename) || ast_strlen_zero(interface)) {
10869 astman_send_error(s, m, "Need 'Queue' and 'Interface' parameters.");
10870 return 0;
10871 }
10872
10874 mem = find_member_by_queuename_and_interface(queuename, interface);
10875 }
10876
10877 switch (remove_from_queue(queuename, interface)) {
10878 case RES_OKAY:
10879 if (!mem || ast_strlen_zero(mem->membername)) {
10880 ast_queue_log(queuename, "MANAGER", interface, "REMOVEMEMBER", "%s", "");
10881 } else {
10882 ast_queue_log(queuename, "MANAGER", mem->membername, "REMOVEMEMBER", "%s", "");
10883 }
10884 astman_send_ack(s, m, "Removed interface from queue");
10885 break;
10886 case RES_EXISTS:
10887 astman_send_error(s, m, "Unable to remove interface: Not there");
10888 break;
10889 case RES_NOSUCHQUEUE:
10890 astman_send_error(s, m, "Unable to remove interface from queue: No such queue");
10891 break;
10892 case RES_OUTOFMEMORY:
10893 astman_send_error(s, m, "Out of memory");
10894 break;
10895 case RES_NOT_DYNAMIC:
10896 astman_send_error(s, m, "Member not dynamic");
10897 break;
10898 }
10899
10900 if (mem) {
10901 ao2_ref(mem, -1);
10902 }
10903
10904 return 0;
10905}

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

11139{
11140 const char *queuename, *caller, *withdraw_info;
11141
11142 queuename = astman_get_header(m, "Queue");
11143 caller = astman_get_header(m, "Caller");
11144 withdraw_info = astman_get_header(m, "WithdrawInfo");
11145
11146 if (ast_strlen_zero(queuename)) {
11147 astman_send_error(s, m, "'Queue' not specified.");
11148 return 0;
11149 }
11150
11151 if (ast_strlen_zero(caller)) {
11152 astman_send_error(s, m, "'Caller' not specified.");
11153 return 0;
11154 }
11155
11156 switch (request_withdraw_caller_from_queue(queuename, caller, withdraw_info)) {
11157 case RES_OKAY:
11158 astman_send_ack(s, m, "Withdraw requested successfully");
11159 break;
11160 case RES_NOSUCHQUEUE:
11161 astman_send_error(s, m, "Unable to request withdraw from queue: No such queue");
11162 break;
11163 case RES_NOT_CALLER:
11164 astman_send_error(s, m, "Unable to request withdraw from queue: No such caller");
11165 break;
11166 case RES_EXISTS:
11167 astman_send_error(s, m, "Unable to request withdraw from queue: Already requested");
11168 break;
11169 }
11170
11171 return 0;
11172}
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:7881

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

9913{
9914 struct member *member = obj;
9915 if (!member->dynamic && !member->realtime) {
9916 member->delme = 1;
9917 }
9918 return 0;
9919}

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

10067{
10068 struct call_queue *q = obj;
10069 char *queuename = arg;
10070 if (!q->realtime && (ast_strlen_zero(queuename) || !strcasecmp(queuename, q->name))) {
10071 q->found = 0;
10072 }
10073 return 0;
10074}

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

3073{
3074 struct member *mem1 = obj1;
3075 struct member *mem2 = obj2;
3076 const char *interface = (flags & OBJ_KEY) ? obj2 : mem2->interface;
3077
3078 return strcasecmp(mem1->interface, interface) ? 0 : CMP_MATCH | CMP_STOP;
3079}
@ 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 3056 of file app_queue.c.

3057{
3058 const struct member *mem = obj;
3059 const char *interface = (flags & OBJ_KEY) ? obj : mem->interface;
3060 const char *chname = strchr(interface, '/');
3061 int ret = 0, i;
3062
3063 if (!chname) {
3064 chname = interface;
3065 }
3066 for (i = 0; i < 5 && chname[i]; i++) {
3067 ret += compress_char(chname[i]) << (i * 6);
3068 }
3069 return ret;
3070}
static int compress_char(const char c)
Definition: app_queue.c:3046

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

3714{
3716 ao2_lock(queue->members);
3719 ao2_unlink(queue->members, mem);
3720 ao2_unlock(queue->members);
3721}
static void queue_member_follower_removal(struct call_queue *queue, struct member *mem)
Definition: app_queue.c:2173
#define QUEUE_UNKNOWN_PAUSED_DEVSTATE
Definition: app_queue.c:3689
#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 4794 of file app_queue.c.

4795{
4797}

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

4661{
4662 struct member *mem;
4663 int avl = 0;
4664 struct ao2_iterator mem_iter;
4665
4666 mem_iter = ao2_iterator_init(q->members, 0);
4667 while ((mem = ao2_iterator_next(&mem_iter))) {
4668
4669 avl += is_member_available(q, mem);
4670 ao2_ref(mem, -1);
4671
4672 /* If autofill is not enabled or if the queue's strategy is ringall, then
4673 * we really don't care about the number of available members so much as we
4674 * do that there is at least one available.
4675 *
4676 * In fact, we purposely will return from this function stating that only
4677 * one member is available if either of those conditions hold. That way,
4678 * functions which determine what action to take based on the number of available
4679 * members will operate properly. The reasoning is that even if multiple
4680 * members are available, only the head caller can actually be serviced.
4681 */
4682 if ((!q->autofill || q->strategy == QUEUE_STRATEGY_RINGALL) && avl) {
4683 break;
4684 }
4685 }
4686 ao2_iterator_destroy(&mem_iter);
4687
4688 return avl;
4689}

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

3441{
3442 char *value_copy = ast_strdupa(value);
3443 char *option = NULL;
3444 while ((option = strsep(&value_copy, ","))) {
3445 if (!strcasecmp(option, "paused")) {
3446 *empty |= QUEUE_EMPTY_PAUSED;
3447 } else if (!strcasecmp(option, "penalty")) {
3448 *empty |= QUEUE_EMPTY_PENALTY;
3449 } else if (!strcasecmp(option, "inuse")) {
3450 *empty |= QUEUE_EMPTY_INUSE;
3451 } else if (!strcasecmp(option, "ringing")) {
3452 *empty |= QUEUE_EMPTY_RINGING;
3453 } else if (!strcasecmp(option, "invalid")) {
3454 *empty |= QUEUE_EMPTY_INVALID;
3455 } else if (!strcasecmp(option, "wrapup")) {
3456 *empty |= QUEUE_EMPTY_WRAPUP;
3457 } else if (!strcasecmp(option, "unavailable")) {
3458 *empty |= QUEUE_EMPTY_UNAVAILABLE;
3459 } else if (!strcasecmp(option, "unknown")) {
3460 *empty |= QUEUE_EMPTY_UNKNOWN;
3461 } else if (!strcasecmp(option, "loose")) {
3463 } else if (!strcasecmp(option, "strict")) {
3465 } else if ((ast_false(option) && joinempty) || (ast_true(option) && !joinempty)) {
3467 } else if ((ast_false(option) && !joinempty) || (ast_true(option) && joinempty)) {
3468 *empty = 0;
3469 } else {
3470 ast_log(LOG_WARNING, "Unknown option %s for '%s'\n", option, joinempty ? "joinempty" : "leavewhenempty");
3471 }
3472 }
3473}

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

2673{
2674 const struct member *object_left = obj;
2675 const struct member *object_right = arg;
2676 const char *right_key = arg;
2677 int cmp;
2678
2679 switch (flags & OBJ_SEARCH_MASK) {
2680 case OBJ_SEARCH_OBJECT:
2681 right_key = object_right->interface;
2682 /* Fall through */
2683 case OBJ_SEARCH_KEY:
2684 cmp = strcasecmp(object_left->interface, right_key);
2685 break;
2687 /* Not supported by container. */
2688 ast_assert(0);
2689 return 0;
2690 default:
2691 cmp = 0;
2692 break;
2693 }
2694 if (cmp) {
2695 return 0;
2696 }
2697 return CMP_MATCH;
2698}
@ 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 2652 of file app_queue.c.

2653{
2654 const struct member *object;
2655 const char *key;
2656
2657 switch (flags & OBJ_SEARCH_MASK) {
2658 case OBJ_SEARCH_KEY:
2659 key = obj;
2660 break;
2661 case OBJ_SEARCH_OBJECT:
2662 object = obj;
2663 key = object->interface;
2664 break;
2665 default:
2666 ast_assert(0);
2667 return 0;
2668 }
2669 return ast_str_case_hash(key);
2670}
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 2700 of file app_queue.c.

2701{
2702 ast_debug(3, "Removed %s from pending_members\n", mem->membername);
2704}
@ 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 4294 of file app_queue.c.

4295{
4296 int res;
4297
4298 if (ast_strlen_zero(filename)) {
4299 return 0;
4300 }
4301
4302 if (!ast_fileexists(filename, NULL, ast_channel_language(chan))) {
4303 return 0;
4304 }
4305
4306 ast_stopstream(chan);
4307
4308 res = ast_streamfile(chan, filename, ast_channel_language(chan));
4309 if (!res) {
4310 res = ast_waitstream(chan, AST_DIGIT_ANY);
4311 }
4312
4313 ast_stopstream(chan);
4314
4315 return res;
4316}
const char * ast_channel_language(const struct ast_channel *chan)
int ast_stopstream(struct ast_channel *c)
Stops a stream.
Definition: file.c:223
int ast_streamfile(struct ast_channel *c, const char *filename, const char *preflang)
Streams a file.
Definition: file.c:1312
int ast_fileexists(const char *filename, const char *fmt, const char *preflang)
Checks for the existence of a given file.
Definition: file.c:1148
#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:1874

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

8376{
8377 char *parse;
8379 AST_APP_ARG(queuename);
8380 AST_APP_ARG(interface);
8382 AST_APP_ARG(reason);
8383 );
8384
8385 if (ast_strlen_zero(data)) {
8386 ast_log(LOG_WARNING, "PauseQueueMember requires an argument ([queuename],interface[,options][,reason])\n");
8387 return -1;
8388 }
8389
8390 parse = ast_strdupa(data);
8391
8393
8394 if (ast_strlen_zero(args.interface)) {
8395 ast_log(LOG_WARNING, "Missing interface argument to PauseQueueMember ([queuename],interface[,options[,reason]])\n");
8396 return -1;
8397 }
8398
8399 if (set_member_paused(args.queuename, args.interface, args.reason, 1)) {
8400 ast_log(LOG_WARNING, "Attempt to pause interface %s, not found\n", args.interface);
8401 pbx_builtin_setvar_helper(chan, "PQMSTATUS", "NOTFOUND");
8402 return 0;
8403 }
8404
8405 pbx_builtin_setvar_helper(chan, "PQMSTATUS", "PAUSED");
8406
8407 return 0;
8408}

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

10215{
10216 float sl;
10217 float sl2;
10218 struct ao2_iterator mem_iter;
10219 struct ast_str *out = ast_str_alloca(512);
10220 time_t now = time(NULL);
10221
10222 ast_str_set(&out, 0, "%s has %d calls (max ", q->name, q->count);
10223 if (q->maxlen) {
10224 ast_str_append(&out, 0, "%d", q->maxlen);
10225 } else {
10226 ast_str_append(&out, 0, "unlimited");
10227 }
10228 sl = 0;
10229 sl2 = 0;
10230 if (q->callscompleted > 0) {
10231 sl = 100 * ((float) q->callscompletedinsl / (float) q->callscompleted);
10232 }
10233 if (q->callscompleted + q->callsabandoned > 0) {
10234 sl2 =100 * (((float)q->callsabandonedinsl + (float)q->callscompletedinsl) / ((float)q->callsabandoned + (float)q->callscompleted));
10235 }
10236
10237 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",
10239 do_print(s, fd, ast_str_buffer(out));
10240 if (!ao2_container_count(q->members)) {
10241 do_print(s, fd, " No Members");
10242 } else {
10243 struct member *mem;
10244
10245 do_print(s, fd, " Members: ");
10246 mem_iter = ao2_iterator_init(q->members, 0);
10247 while ((mem = ao2_iterator_next(&mem_iter))) {
10248 ast_str_set(&out, 0, " %s", mem->membername);
10249 if (strcasecmp(mem->membername, mem->interface)) {
10250 ast_str_append(&out, 0, " (%s", mem->interface);
10252 && strcmp(mem->state_interface, mem->interface)) {
10253 ast_str_append(&out, 0, " from %s", mem->state_interface);
10254 }
10255 ast_str_append(&out, 0, ")");
10256 }
10257 if (mem->penalty) {
10258 ast_str_append(&out, 0, " with penalty %d", mem->penalty);
10259 }
10260
10261 ast_str_append(&out, 0, " (ringinuse %s)", mem->ringinuse ? "enabled" : "disabled");
10262
10263 ast_str_append(&out, 0, "%s%s%s%s%s%s%s%s%s",
10264 mem->dynamic ? ast_term_color(COLOR_CYAN, COLOR_BLACK) : "", mem->dynamic ? " (dynamic)" : "", ast_term_reset(),
10265 mem->realtime ? ast_term_color(COLOR_MAGENTA, COLOR_BLACK) : "", mem->realtime ? " (realtime)" : "", ast_term_reset(),
10266 mem->starttime ? ast_term_color(COLOR_BROWN, COLOR_BLACK) : "", mem->starttime ? " (in call)" : "", ast_term_reset());
10267
10268 if (mem->paused) {
10269 ast_str_append(&out, 0, " %s(paused%s%s was %ld secs ago)%s",
10271 ast_strlen_zero(mem->reason_paused) ? "" : ":",
10273 (long) (now - mem->lastpause),
10274 ast_term_reset());
10275 }
10276
10277 ast_str_append(&out, 0, " (%s%s%s)",
10282 if (mem->calls) {
10283 ast_str_append(&out, 0, " has taken %d calls (last was %ld secs ago)",
10284 mem->calls, (long) (now - mem->lastcall));
10285 } else {
10286 ast_str_append(&out, 0, " has taken no calls yet");
10287 }
10288 ast_str_append(&out, 0, " %s(login was %ld secs ago)%s",
10290 (long) (now - mem->logintime),
10291 ast_term_reset());
10292 do_print(s, fd, ast_str_buffer(out));
10293 ao2_ref(mem, -1);
10294 }
10295 ao2_iterator_destroy(&mem_iter);
10296 }
10297 if (!q->head) {
10298 do_print(s, fd, " No Callers");
10299 } else {
10300 struct queue_ent *qe;
10301 int pos = 1;
10302
10303 do_print(s, fd, " Callers: ");
10304 for (qe = q->head; qe; qe = qe->next) {
10305 ast_str_set(&out, 0, " %d. %s (wait: %ld:%2.2ld, prio: %d)",
10306 pos++, ast_channel_name(qe->chan), (long) (now - qe->start) / 60,
10307 (long) (now - qe->start) % 60, qe->prio);
10308 do_print(s, fd, ast_str_buffer(out));
10309 }
10310 }
10311 do_print(s, fd, ""); /* blank line between entries */
10312}
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 4608 of file app_queue.c.

4609{
4610 struct callattempt *cur;
4611
4612 for (cur = outgoing; cur; cur = cur->q_next) {
4613 if (cur->chan && cur->chan != exception) {
4615 }
4616 }
4617}
struct callattempt * q_next
Definition: app_queue.c:1799
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 7920 of file app_queue.c.

7921{
7922 struct ast_json *json_blob = queue_member_blob_create(q, member);
7923
7924 if (!json_blob) {
7925 return -1;
7926 }
7927
7928 queue_publish_member_blob(queue_member_pause_type(), json_blob);
7929
7930 return 0;
7931}

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

8613{
8614 char *parse;
8615
8617 AST_APP_ARG(queuename);
8618 AST_APP_ARG(uniqueid);
8619 AST_APP_ARG(membername);
8621 AST_APP_ARG(params);
8622 );
8623
8624 if (ast_strlen_zero(data)) {
8625 ast_log(LOG_WARNING, "QueueLog requires arguments (queuename,uniqueid,membername,event[,additionalinfo]\n");
8626 return -1;
8627 }
8628
8629 parse = ast_strdupa(data);
8630
8632
8633 if (ast_strlen_zero(args.queuename) || ast_strlen_zero(args.uniqueid)
8634 || ast_strlen_zero(args.membername) || ast_strlen_zero(args.event)) {
8635 ast_log(LOG_WARNING, "QueueLog requires arguments (queuename,uniqueid,membername,event[,additionalinfo])\n");
8636 return -1;
8637 }
8638
8639 ast_queue_log(args.queuename, args.uniqueid, args.membername, args.event,
8640 "%s", args.params ? args.params : "");
8641
8642 return 0;
8643}

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

2396{
2397 return queue_multi_channel_to_ami("AgentCalled", message);
2398}
static struct ast_manager_event_blob * queue_multi_channel_to_ami(const char *type, struct stasis_message *message)
Definition: app_queue.c:2354

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

6313{
6314 struct ast_channel_blob *agent_blob;
6315
6316 agent_blob = stasis_message_data(msg);
6317
6319 ast_queue_log("NONE", agent_blob->snapshot->base->uniqueid,
6320 ast_json_string_get(ast_json_object_get(agent_blob->blob, "agent")),
6321 "AGENTLOGIN", "%s", agent_blob->snapshot->base->name);
6323 ast_queue_log("NONE", agent_blob->snapshot->base->uniqueid,
6324 ast_json_string_get(ast_json_object_get(agent_blob->blob, "agent")),
6325 "AGENTLOGOFF", "%s|%ld", agent_blob->snapshot->base->name,
6326 (long) ast_json_integer_get(ast_json_object_get(agent_blob->blob, "logintime")));
6327 }
6328}

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

2406{
2407 return queue_multi_channel_to_ami("AgentComplete", message);
2408}

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

2401{
2402 return queue_multi_channel_to_ami("AgentConnect", message);
2403}

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

2411{
2412 return queue_multi_channel_to_ami("AgentDump", message);
2413}

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

2416{
2417 return queue_multi_channel_to_ami("AgentRingNoAnswer", message);
2418}

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

6676{
6678 ao2_cleanup(userdata);
6679 }
6680}
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:1241

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

2276{
2277 return queue_channel_to_ami("QueueCallerAbandon", message);
2278}
static struct ast_manager_event_blob * queue_channel_to_ami(const char *type, struct stasis_message *message)
Definition: app_queue.c:2246

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

2266{
2267 return queue_channel_to_ami("QueueCallerJoin", message);
2268}

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

2271{
2272 return queue_channel_to_ami("QueueCallerLeave", message);
2273}

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

6909{
6911 ao2_cleanup(userdata);
6912 }
6913}

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

2247{
2249 RAII_VAR(struct ast_str *, channel_string, NULL, ast_free);
2250 RAII_VAR(struct ast_str *, event_string, NULL, ast_free);
2251
2252 channel_string = ast_manager_build_channel_state_string(obj->snapshot);
2253 event_string = ast_manager_str_from_json_object(obj->blob, NULL);
2254 if (!channel_string || !event_string) {
2255 return NULL;
2256 }
2257
2259 "%s"
2260 "%s",
2261 ast_str_buffer(channel_string),
2262 ast_str_buffer(event_string));
2263}
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:551
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:10144

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

2110{
2111 struct call_queue *q = obj, *q2 = arg;
2112 return !strcasecmp(q->name, q2->name) ? CMP_MATCH | CMP_STOP : 0;
2113}

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

2156{
2157 struct member *mem = obj;
2158 struct call_queue *queue = arg;
2159 int rrpos = mem->queuepos;
2160
2161 if (mem->delme) {
2163 }
2164
2165 return 0;
2166}
static int queue_member_decrement_followers(void *obj, void *arg, int flag)
Definition: app_queue.c:2136
#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 8689 of file app_queue.c.

8690{
8691 int res=-1;
8692 int ringing=0;
8693 const char *user_priority;
8694 const char *max_penalty_str;
8695 const char *min_penalty_str;
8696 const char *raise_penalty_str;
8697 int prio;
8698 int qcontinue = 0;
8699 int max_penalty, min_penalty, raise_penalty;
8700 enum queue_result reason = QUEUE_UNKNOWN;
8701 /* whether to exit Queue application after the timeout hits */
8702 int tries = 0;
8703 int noption = 0;
8704 char *parse;
8705 int makeannouncement = 0;
8706 int position = 0;
8708 AST_APP_ARG(queuename);
8711 AST_APP_ARG(announceoverride);
8712 AST_APP_ARG(queuetimeoutstr);
8713 AST_APP_ARG(agi);
8714 AST_APP_ARG(gosub);
8716 AST_APP_ARG(position);
8717 );
8718 /* Our queue entry */
8719 struct queue_ent qe = { 0 };
8720 struct ast_flags opts = { 0, };
8721 char *opt_args[OPT_ARG_ARRAY_SIZE];
8722 int max_forwards;
8723 int cid_allow;
8724
8725 if (ast_strlen_zero(data)) {
8726 ast_log(LOG_WARNING, "Queue requires an argument: queuename[,options[,URL[,announceoverride[,timeout[,agi[,gosub[,rule[,position]]]]]]]]\n");
8727 return -1;
8728 }
8729
8730 ast_channel_lock(chan);
8732 ast_channel_unlock(chan);
8733
8734 if (max_forwards <= 0) {
8735 ast_log(LOG_WARNING, "Channel '%s' cannot enter queue. Max forwards exceeded\n", ast_channel_name(chan));
8736 return -1;
8737 }
8738
8739 parse = ast_strdupa(data);
8741
8742 ast_debug(1, "queue: %s, options: %s, url: %s, announce: %s, timeout: %s, agi: %s, gosub: %s, rule: %s, position: %s\n",
8743 args.queuename,
8744 S_OR(args.options, ""),
8745 S_OR(args.url, ""),
8746 S_OR(args.announceoverride, ""),
8747 S_OR(args.queuetimeoutstr, ""),
8748 S_OR(args.agi, ""),
8749 S_OR(args.gosub, ""),
8750 S_OR(args.rule, ""),
8751 S_OR(args.position, ""));
8752
8753 if (!ast_strlen_zero(args.options)) {
8754 ast_app_parse_options(queue_exec_options, &opts, opt_args, args.options);
8755 }
8756
8757 /* Setup our queue entry */
8758 qe.start = time(NULL);
8759
8760 pbx_builtin_setvar_helper(chan, "ABANDONED", NULL);
8761
8762 /* set the expire time based on the supplied timeout; */
8763 if (!ast_strlen_zero(args.queuetimeoutstr)) {
8764 qe.expire = qe.start + atoi(args.queuetimeoutstr);
8765 } else {
8766 qe.expire = 0;
8767 }
8768
8769 /* Get the priority from the variable ${QUEUE_PRIO} */
8770 ast_channel_lock(chan);
8771 user_priority = pbx_builtin_getvar_helper(chan, "QUEUE_PRIO");
8772 if (user_priority) {
8773 if (sscanf(user_priority, "%30d", &prio) == 1) {
8774 ast_debug(1, "%s: Got priority %d from ${QUEUE_PRIO}.\n", ast_channel_name(chan), prio);
8775 } else {
8776 ast_log(LOG_WARNING, "${QUEUE_PRIO}: Invalid value (%s), channel %s.\n",
8777 user_priority, ast_channel_name(chan));
8778 prio = 0;
8779 }
8780 } else {
8781 ast_debug(3, "NO QUEUE_PRIO variable found. Using default.\n");
8782 prio = 0;
8783 }
8784
8785 /* Get the maximum penalty from the variable ${QUEUE_MAX_PENALTY} */
8786
8787 if ((max_penalty_str = pbx_builtin_getvar_helper(chan, "QUEUE_MAX_PENALTY"))) {
8788 if (sscanf(max_penalty_str, "%30d", &max_penalty) == 1) {
8789 ast_debug(1, "%s: Got max penalty %d from ${QUEUE_MAX_PENALTY}.\n", ast_channel_name(chan), max_penalty);
8790 } else {
8791 ast_log(LOG_WARNING, "${QUEUE_MAX_PENALTY}: Invalid value (%s), channel %s.\n",
8792 max_penalty_str, ast_channel_name(chan));
8793 max_penalty = INT_MAX;
8794 }
8795 } else {
8796 max_penalty = INT_MAX;
8797 }
8798
8799 if ((min_penalty_str = pbx_builtin_getvar_helper(chan, "QUEUE_MIN_PENALTY"))) {
8800 if (sscanf(min_penalty_str, "%30d", &min_penalty) == 1) {
8801 ast_debug(1, "%s: Got min penalty %d from ${QUEUE_MIN_PENALTY}.\n", ast_channel_name(chan), min_penalty);
8802 } else {
8803 ast_log(LOG_WARNING, "${QUEUE_MIN_PENALTY}: Invalid value (%s), channel %s.\n",
8804 min_penalty_str, ast_channel_name(chan));
8805 min_penalty = INT_MAX;
8806 }
8807 } else {
8808 min_penalty = INT_MAX;
8809 }
8810
8811 if ((raise_penalty_str = pbx_builtin_getvar_helper(chan, "QUEUE_RAISE_PENALTY"))) {
8812 if (*raise_penalty_str == 'r') {
8813 qe.raise_respect_min = 1;
8814 raise_penalty_str++;
8815 } else {
8816 qe.raise_respect_min = 0;
8817 }
8818 if (sscanf(raise_penalty_str, "%30d", &raise_penalty) == 1) {
8819 ast_debug(1, "%s: Got raise penalty %s%d from ${QUEUE_RAISE_PENALTY}.\n", ast_channel_name(chan), qe.raise_respect_min ? "r" : "", raise_penalty);
8820 } else {
8821 ast_log(LOG_WARNING, "${QUEUE_RAISE_PENALTY}: Invalid value (%s), channel %s.\n",
8822 raise_penalty_str, ast_channel_name(chan));
8823 raise_penalty = INT_MAX;
8824 }
8825 } else {
8826 raise_penalty = INT_MAX;
8827 }
8828 ast_channel_unlock(chan);
8829
8830 if (ast_test_flag(&opts, OPT_RINGING)) {
8831 ringing = 1;
8832 }
8833
8834 if (ringing != 1 && ast_test_flag(&opts, OPT_RING_WHEN_RINGING)) {
8835 qe.ring_when_ringing = 1;
8836 }
8837
8838 if (ast_test_flag(&opts, OPT_GO_ON)) {
8839 qcontinue = 1;
8840 }
8841
8842 if (args.position) {
8843 position = atoi(args.position);
8844 if (position < 0) {
8845 ast_log(LOG_WARNING, "Invalid position '%s' given for call to queue '%s'. Assuming no preference for position\n", args.position, args.queuename);
8846 position = 0;
8847 }
8848 }
8849
8850 ast_debug(1, "queue: %s, expires: %ld, priority: %d\n",
8851 args.queuename, (long)qe.expire, prio);
8852
8853 qe.chan = chan;
8854 qe.prio = prio;
8855 qe.max_penalty = max_penalty;
8856 qe.min_penalty = min_penalty;
8857 qe.raise_penalty = raise_penalty;
8858 qe.last_pos_said = 0;
8859 qe.last_pos = 0;
8862 qe.valid_digits = 0;
8863 if (join_queue(args.queuename, &qe, &reason, position)) {
8864 ast_log(LOG_WARNING, "Unable to join queue '%s'\n", args.queuename);
8865 set_queue_result(chan, reason);
8866 return 0;
8867 }
8868 ast_assert(qe.parent != NULL);
8869
8870 if (qe.parent->periodicannouncestartdelay >= 0) {
8873 }
8874
8876
8877 if (log_caller_id_name) {
8878 char *escaped_cidname = NULL;
8879 /* Ensure caller ID name is valid and not NULL before processing */
8880 if (cid_allow && ast_channel_caller(chan)->id.name.valid && ast_channel_caller(chan)->id.name.str) {
8881 escaped_cidname = ast_strdupa(ast_channel_caller(chan)->id.name.str);
8882 /* Only iterate if '|' is found */
8883 if (strchr(escaped_cidname, '|')) {
8884 for (char *p = escaped_cidname; *p; p++) {
8885 if (*p == '|') {
8886 *p = '_';
8887 }
8888 }
8889 }
8890 }
8891
8892 ast_queue_log(args.queuename, ast_channel_uniqueid(chan), "NONE", "ENTERQUEUE", "%s|%s|%d|%s",
8893 S_OR(args.url, ""),
8894 S_COR(cid_allow && ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, ""),
8895 qe.opos,
8896 S_OR(escaped_cidname, ""));
8897 } else {
8898 ast_queue_log(args.queuename, ast_channel_uniqueid(chan), "NONE", "ENTERQUEUE", "%s|%s|%d",
8899 S_OR(args.url, ""),
8900 S_COR(cid_allow && ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, ""),
8901 qe.opos);
8902 }
8903
8904 /* PREDIAL: Preprocess any callee gosub arguments. */
8906 && !ast_strlen_zero(opt_args[OPT_ARG_PREDIAL_CALLEE])) {
8909 }
8910
8911 /* PREDIAL: Run gosub on the caller's channel */
8913 && !ast_strlen_zero(opt_args[OPT_ARG_PREDIAL_CALLER])) {
8915 ast_app_exec_sub(NULL, chan, opt_args[OPT_ARG_PREDIAL_CALLER], 0);
8916 }
8917
8918 /* Music on hold class override */
8921 ast_copy_string(qe.moh, opt_args[OPT_ARG_MUSICONHOLD_CLASS], sizeof(qe.moh));
8922 }
8923
8924 copy_rules(&qe, args.rule);
8925 qe.pr = AST_LIST_FIRST(&qe.qe_rules);
8926check_turns:
8927 if (ringing) {
8929 } else {
8930 ast_moh_start(chan, qe.moh, NULL);
8931 }
8932
8933 /* This is the wait loop for callers 2 through maxlen */
8934 res = wait_our_turn(&qe, ringing, &reason);
8935 if (res) {
8936 goto stop;
8937 }
8938
8939 makeannouncement = qe.parent->announce_to_first_user;
8940
8941 for (;;) {
8942 /* This is the wait loop for the head caller*/
8943 /* To exit, they may get their call answered; */
8944 /* they may dial a digit from the queue context; */
8945 /* or, they may timeout. */
8946
8947 /* A request to withdraw this call from the queue arrived */
8948 if (qe.withdraw) {
8949 reason = QUEUE_WITHDRAW;
8950 res = 1;
8951 break;
8952 }
8953
8954 /* Leave if we have exceeded our queuetimeout */
8955 if (qe.expire && (time(NULL) >= qe.expire)) {
8956 record_abandoned(&qe);
8957 reason = QUEUE_TIMEOUT;
8958 res = 0;
8959 ast_queue_log(args.queuename, ast_channel_uniqueid(chan),"NONE", "EXITWITHTIMEOUT", "%d|%d|%ld",
8960 qe.pos, qe.opos, (long) (time(NULL) - qe.start));
8961 break;
8962 }
8963
8964 if (makeannouncement) {
8965 /* Make a position announcement, if enabled */
8966 if (qe.parent->announcefrequency) {
8967 if ((res = say_position(&qe, ringing))) {
8968 goto stop;
8969 }
8970 }
8971 }
8972 makeannouncement = 1;
8973
8974 /* Make a periodic announcement, if enabled */
8976 if ((res = say_periodic_announcement(&qe, ringing))) {
8977 goto stop;
8978 }
8979 }
8980
8981 /* A request to withdraw this call from the queue arrived */
8982 if (qe.withdraw) {
8983 reason = QUEUE_WITHDRAW;
8984 res = 1;
8985 break;
8986 }
8987
8988 /* Leave if we have exceeded our queuetimeout */
8989 if (qe.expire && (time(NULL) >= qe.expire)) {
8990 record_abandoned(&qe);
8991 reason = QUEUE_TIMEOUT;
8992 res = 0;
8993 ast_queue_log(args.queuename, ast_channel_uniqueid(chan), "NONE", "EXITWITHTIMEOUT",
8994 "%d|%d|%ld", qe.pos, qe.opos, (long) (time(NULL) - qe.start));
8995 break;
8996 }
8997
8998 /* see if we need to move to the next penalty level for this queue */
8999 while (qe.pr && ((time(NULL) - qe.start) > qe.pr->time)) {
9000 update_qe_rule(&qe);
9001 }
9002
9003 /* Try calling all queue members for 'timeout' seconds */
9004 res = try_calling(&qe, opts, opt_args, args.announceoverride, args.url, &tries, &noption, args.agi, args.gosub, ringing);
9005 if (res) {
9006 goto stop;
9007 }
9008
9009 if (qe.parent->leavewhenempty) {
9010 int status = 0;
9012 record_abandoned(&qe);
9013 reason = QUEUE_LEAVEEMPTY;
9014 ast_queue_log(args.queuename, ast_channel_uniqueid(chan), "NONE", "EXITEMPTY", "%d|%d|%ld", qe.pos, qe.opos, (long)(time(NULL) - qe.start));
9015 res = 0;
9016 break;
9017 }
9018 }
9019
9020 /* exit after 'timeout' cycle if 'n' option enabled */
9021 if (noption && tries >= ao2_container_count(qe.parent->members)) {
9022 ast_verb(3, "Exiting on time-out cycle\n");
9023 ast_queue_log(args.queuename, ast_channel_uniqueid(chan), "NONE", "EXITWITHTIMEOUT",
9024 "%d|%d|%ld", qe.pos, qe.opos, (long) (time(NULL) - qe.start));
9025 record_abandoned(&qe);
9026 reason = QUEUE_TIMEOUT;
9027 res = 0;
9028 break;
9029 }
9030
9031
9032 /* Leave if we have exceeded our queuetimeout */
9033 if (qe.expire && (time(NULL) >= qe.expire)) {
9034 record_abandoned(&qe);
9035 reason = QUEUE_TIMEOUT;
9036 res = 0;
9037 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));
9038 break;
9039 }
9040
9041 /* OK, we didn't get anybody; wait for 'retry' seconds; may get a digit to exit with */
9042 res = wait_a_bit(&qe);
9043 if (res) {
9044 goto stop;
9045 }
9046
9047 /* If using dynamic realtime members, we should regenerate the member list for this queue */
9049
9050 /* Since this is a priority queue and
9051 * it is not sure that we are still at the head
9052 * of the queue, go and check for our turn again.
9053 */
9054 if (!is_our_turn(&qe)) {
9055 ast_debug(1, "Darn priorities, going back in queue (%s)!\n", ast_channel_name(qe.chan));
9056 goto check_turns;
9057 }
9058 }
9059
9060stop:
9061 if (res) {
9062 if (reason == QUEUE_WITHDRAW) {
9063 record_abandoned(&qe);
9064 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 : "");
9065 if (qe.withdraw_info) {
9066 pbx_builtin_setvar_helper(qe.chan, "QUEUE_WITHDRAW_INFO", qe.withdraw_info);
9067 }
9068 res = 0;
9069 } else if (res < 0) {
9070 if (!qe.handled) {
9071 record_abandoned(&qe);
9072 ast_queue_log(args.queuename, ast_channel_uniqueid(chan), "NONE", "ABANDON",
9073 "%d|%d|%ld", qe.pos, qe.opos,
9074 (long) (time(NULL) - qe.start));
9075 res = -1;
9076 } else if (reason == QUEUE_LEAVEEMPTY) {
9077 /* Return back to dialplan, don't hang up */
9078 res = 0;
9079 } else if (qcontinue) {
9080 reason = QUEUE_CONTINUE;
9081 res = 0;
9082 }
9083 } else if (qe.valid_digits) {
9084 ast_queue_log(args.queuename, ast_channel_uniqueid(chan), "NONE", "EXITWITHKEY",
9085 "%s|%d|%d|%ld", qe.digits, qe.pos, qe.opos, (long) (time(NULL) - qe.start));
9086 }
9087 }
9088
9089 /* Free the optional withdraw info if present */
9090 /* This is done here to catch all cases. e.g. if the call eventually wasn't withdrawn, e.g. answered */
9091 if (qe.withdraw_info) {
9093 qe.withdraw_info = NULL;
9094 }
9095
9096 /* Don't allow return code > 0 */
9097 if (res >= 0) {
9098 res = 0;
9099 if (ringing) {
9100 ast_indicate(chan, -1);
9101 } else {
9102 ast_moh_stop(chan);
9103 }
9104 ast_stopstream(chan);
9105 }
9106
9108
9109 leave_queue(&qe);
9110 if (reason != QUEUE_UNKNOWN)
9111 set_queue_result(chan, reason);
9112
9113 /*
9114 * every queue_ent is given a reference to it's parent
9115 * call_queue when it joins the queue. This ref must be taken
9116 * away right before the queue_ent is destroyed. In this case
9117 * the queue_ent is about to be returned on the stack
9118 */
9119 qe.parent = queue_unref(qe.parent);
9120
9121 return res;
9122}
static int is_our_turn(struct queue_ent *qe)
Check if we should start attempting to call queue members.
Definition: app_queue.c:5896
static void record_abandoned(struct queue_ent *qe)
Record that a caller gave up on waiting in queue.
Definition: app_queue.c:5230
static int log_caller_id_name
queues.conf [general] option
Definition: app_queue.c:1743
static void set_queue_result(struct ast_channel *chan, enum queue_result res)
sets the QUEUESTATUS channel variable
Definition: app_queue.c:2041
static void leave_queue(struct queue_ent *qe)
Caller leaving queue.
Definition: app_queue.c:4523
static int say_periodic_announcement(struct queue_ent *qe, int ringing)
Playback announcement to queued members if period has elapsed.
Definition: app_queue.c:5169
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:6035
static void copy_rules(struct queue_ent *qe, const char *rulename)
Copy rule from global list into specified queue.
Definition: app_queue.c:8646
static const struct ast_app_option queue_exec_options[128]
Definition: app_queue.c:1610
queue_result
Definition: app_queue.c:1754
static void update_qe_rule(struct queue_ent *qe)
update rules for queues
Definition: app_queue.c:5945
static int join_queue(char *queuename, struct queue_ent *qe, enum queue_result *reason, int position)
Definition: app_queue.c:4210
static int say_position(struct queue_ent *qe, int ringing)
Definition: app_queue.c:4358
static int wait_a_bit(struct queue_ent *qe)
Definition: app_queue.c:7604
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:7137
unsigned int stop
Definition: app_sla.c:342
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:1789
#define ast_channel_lock(chan)
Definition: channel.h:2972
int ast_indicate(struct ast_channel *chan, int condition)
Indicates condition of channel.
Definition: channel.c:4243
#define ast_channel_unlock(chan)
Definition: channel.h:2973
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:7748
void ast_moh_stop(struct ast_channel *chan)
Turn off music on hold on a given channel.
Definition: channel.c:7758
static char url[512]
Channel datastore data for max forwards.
Definition: max_forwards.c:29
Number structure.
Definition: app_followme.c:157
char digits[AST_MAX_EXTENSION]
Definition: app_queue.c:1826
int valid_digits
Definition: app_queue.c:1828
time_t last_pos
Definition: app_queue.c:1835
time_t last_periodic_announce_time
Definition: app_queue.c:1833
time_t expire
Definition: app_queue.c:1846
unsigned int withdraw
Definition: app_queue.c:1848
int ring_when_ringing
Definition: app_queue.c:1832
char * withdraw_info
Definition: app_queue.c:1849
int handled
Definition: app_queue.c:1837
int last_pos_said
Definition: app_queue.c:1831
int last_periodic_announce_sound
Definition: app_queue.c:1834
const char * predial_callee
Definition: app_queue.c:1827
void ast_replace_subargument_delimiter(char *s)
Replace '^' in a string with ','.
Definition: utils.c:2379

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, ast_party_caller::id, is_our_turn(), join_queue(), queue_ent::last_periodic_announce_sound, queue_ent::last_periodic_announce_time, queue_ent::last_pos, queue_ent::last_pos_said, leave_queue(), call_queue::leavewhenempty, log_caller_id_name, call_queue::log_restricted_caller_id, LOG_WARNING, queue_ent::max_penalty, call_queue::members, queue_ent::min_penalty, queue_ent::moh, name, call_queue::name, ast_party_id::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, queue_ent::raise_respect_min, 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, ast_party_name::str, penalty_rule::time, try_calling(), update_qe_rule(), update_realtime_members(), url, ast_party_name::valid, 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 9173 of file app_queue.c.

9174{
9175 struct call_queue *q;
9176
9177 buf[0] = '\0';
9178
9179 if (ast_strlen_zero(data)) {
9180 ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd);
9181 return -1;
9182 }
9184 snprintf(buf, len, "%d", q != NULL? 1 : 0);
9185 if (q) {
9186 queue_t_unref(q, "Done with temporary reference in QUEUE_EXISTS()");
9187 }
9188
9189 return 0;
9190}
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 9215 of file app_queue.c.

9216{
9217 int count = 0;
9218 struct member *m;
9219 struct ao2_iterator mem_iter;
9220 struct call_queue *q;
9221
9223 AST_APP_ARG(queuename);
9224 AST_APP_ARG(option);
9225 AST_APP_ARG(interface);
9226 );
9227 /* Make sure the returned value on error is zero length string. */
9228 buf[0] = '\0';
9229
9230 if (ast_strlen_zero(data)) {
9232 "Missing required argument. %s(<queuename>,<option>[,<interface>])\n",
9233 cmd);
9234 return -1;
9235 }
9236
9238
9239 if (ast_strlen_zero(args.queuename) || ast_strlen_zero(args.option)) {
9241 "Missing required argument. %s(<queuename>,<option>[,<interface>])\n",
9242 cmd);
9243 return -1;
9244 }
9245
9246 if ((q = find_load_queue_rt_friendly(args.queuename))) {
9247 ao2_lock(q);
9248 if (!strcasecmp(args.option, "logged")) {
9249 mem_iter = ao2_iterator_init(q->members, 0);
9250 while ((m = ao2_iterator_next(&mem_iter))) {
9251 /* Count the agents who are logged in and presently answering calls */
9252 if ((m->status != AST_DEVICE_UNAVAILABLE) && (m->status != AST_DEVICE_INVALID)) {
9253 count++;
9254 }
9255 ao2_ref(m, -1);
9256 }
9257 ao2_iterator_destroy(&mem_iter);
9258 } else if (!strcasecmp(args.option, "free")) {
9259 mem_iter = ao2_iterator_init(q->members, 0);
9260 while ((m = ao2_iterator_next(&mem_iter))) {
9261 /* Count the agents who are logged in and presently answering calls */
9262 if ((m->status == AST_DEVICE_NOT_INUSE) && (!m->paused)) {
9263 count++;
9264 }
9265 ao2_ref(m, -1);
9266 }
9267 ao2_iterator_destroy(&mem_iter);
9268 } else if (!strcasecmp(args.option, "ready")) {
9269 time_t now;
9270 time(&now);
9271 mem_iter = ao2_iterator_init(q->members, 0);
9272 while ((m = ao2_iterator_next(&mem_iter))) {
9273 /* Count the agents who are logged in, not paused and not wrapping up */
9274 if ((m->status == AST_DEVICE_NOT_INUSE) && (!m->paused) &&
9275 !(m->lastcall && get_wrapuptime(q, m) && ((now - get_wrapuptime(q, m)) < m->lastcall))) {
9276 count++;
9277 }
9278 ao2_ref(m, -1);
9279 }
9280 ao2_iterator_destroy(&mem_iter);
9281 } else if (!strcasecmp(args.option, "count")) {
9283 } else if (!strcasecmp(args.option, "penalty")) {
9284 m = get_interface_helper(q, args.interface);
9285 if (m) {
9286 count = m->penalty;
9287 ao2_ref(m, -1);
9288 }
9289 } else if (!strcasecmp(args.option, "paused")) {
9290 m = get_interface_helper(q, args.interface);
9291 if (m) {
9292 count = m->paused;
9293 ao2_ref(m, -1);
9294 }
9295 } else if ((!strcasecmp(args.option, "ignorebusy") /* ignorebusy is legacy */
9296 || !strcasecmp(args.option, "ringinuse"))) {
9297 m = get_interface_helper(q, args.interface);
9298 if (m) {
9299 count = m->ringinuse;
9300 ao2_ref(m, -1);
9301 }
9302 } else {
9303 ast_log(LOG_ERROR, "%s: Invalid option '%s' provided.\n", cmd, args.option);
9304 }
9305 ao2_unlock(q);
9306 queue_t_unref(q, "Done with temporary reference in QUEUE_MEMBER()");
9307 } else {
9308 ast_log(LOG_WARNING, "queue %s was not found\n", args.queuename);
9309 }
9310
9311 snprintf(buf, len, "%d", count);
9312
9313 return 0;
9314}
static struct member * get_interface_helper(struct call_queue *q, const char *interface)
Definition: app_queue.c:9192

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

9318{
9319 int memvalue;
9320
9322 AST_APP_ARG(queuename);
9323 AST_APP_ARG(option);
9324 AST_APP_ARG(interface);
9325 );
9326
9327 if (ast_strlen_zero(data)) {
9329 "Missing required argument. %s([<queuename>],<option>,<interface>)\n",
9330 cmd);
9331 return -1;
9332 }
9333
9335
9336 if (ast_strlen_zero(args.option)
9337 || ast_strlen_zero(args.interface)) {
9339 "Missing required argument. %s([<queuename>],<option>,<interface>)\n",
9340 cmd);
9341 return -1;
9342 }
9343
9344 /*
9345 * If queuename is empty then the option will be
9346 * set for the interface in all queues.
9347 */
9348
9349 memvalue = atoi(value);
9350 if (!strcasecmp(args.option, "penalty")) {
9351 if (set_member_value(args.queuename, args.interface, MEMBER_PENALTY, memvalue)) {
9352 ast_log(LOG_ERROR, "Invalid interface, queue, or penalty\n");
9353 return -1;
9354 }
9355 } else if (!strcasecmp(args.option, "paused")) {
9356 memvalue = (memvalue <= 0) ? 0 : 1;
9357 if (set_member_paused(args.queuename, args.interface, NULL, memvalue)) {
9358 ast_log(LOG_ERROR, "Invalid interface or queue\n");
9359 return -1;
9360 }
9361 } else if (!strcasecmp(args.option, "ignorebusy") /* ignorebusy is legacy */
9362 || !strcasecmp(args.option, "ringinuse")) {
9363 memvalue = (memvalue <= 0) ? 0 : 1;
9364 if (set_member_value(args.queuename, args.interface, MEMBER_RINGINUSE, memvalue)) {
9365 ast_log(LOG_ERROR, "Invalid interface or queue\n");
9366 return -1;
9367 }
9368 } else {
9369 ast_log(LOG_ERROR, "%s: Invalid option '%s' provided.\n", cmd, args.option);
9370 return -1;
9371 }
9372 return 0;
9373}

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

9541{
9542 int penalty;
9544 AST_APP_ARG(queuename);
9545 AST_APP_ARG(interface);
9546 );
9547 /* Make sure the returned value on error is NULL. */
9548 buf[0] = '\0';
9549
9550 if (ast_strlen_zero(data)) {
9551 ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n");
9552 return -1;
9553 }
9554
9556
9557 if (args.argc < 2) {
9558 ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n");
9559 return -1;
9560 }
9561
9562 penalty = get_member_penalty (args.queuename, args.interface);
9563
9564 if (penalty >= 0) { /* remember that buf is already '\0' */
9565 snprintf (buf, len, "%d", penalty);
9566 }
9567
9568 return 0;
9569}
static int get_member_penalty(char *queuename, char *interface)
Gets members penalty.
Definition: app_queue.c:8233

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

9573{
9574 int penalty;
9576 AST_APP_ARG(queuename);
9577 AST_APP_ARG(interface);
9578 );
9579
9580 if (ast_strlen_zero(data)) {
9581 ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n");
9582 return -1;
9583 }
9584
9586
9587 if (args.argc < 2) {
9588 ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n");
9589 return -1;
9590 }
9591
9592 penalty = atoi(value);
9593
9594 if (ast_strlen_zero(args.interface)) {
9595 ast_log (LOG_ERROR, "<interface> parameter can't be null\n");
9596 return -1;
9597 }
9598
9599 /* if queuename = NULL then penalty will be set for interface in all the queues. */
9600 if (set_member_value(args.queuename, args.interface, MEMBER_PENALTY, penalty)) {
9601 ast_log(LOG_ERROR, "Invalid interface, queue or penalty\n");
9602 return -1;
9603 }
9604
9605 return 0;
9606}

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

9377{
9378 int position;
9379 char *parse;
9380 struct call_queue *q;
9381 struct ast_variable *var;
9382
9384 AST_APP_ARG(queuename);
9385 AST_APP_ARG(position);
9386 );
9387
9388 buf[0] = '\0';
9389
9390 if (ast_strlen_zero(data)) {
9391 ast_log(LOG_ERROR, "Missing argument. QUEUE_GET_CHANNEL(<queuename>,<position>)\n");
9392 return -1;
9393 }
9394
9395 parse = ast_strdupa(data);
9397
9398 if (ast_strlen_zero(args.queuename)) {
9399 ast_log (LOG_ERROR, "The <queuename> parameter is required.\n");
9400 return -1;
9401 }
9402
9403 if (ast_strlen_zero(args.position)) {
9404 position = 1;
9405 } else {
9406 if (sscanf(args.position, "%30d", &position) != 1) {
9407 ast_log (LOG_ERROR, "<position> parameter must be an integer.\n");
9408 return -1;
9409 }
9410 if (position < 1) {
9411 ast_log (LOG_ERROR, "<position> parameter must be an integer greater than zero.\n");
9412 return -1;
9413 }
9414 }
9415
9416 {
9417 struct call_queue tmpq = {
9418 .name = args.queuename,
9419 };
9420
9421 q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Find for QUEUE_GET_CHANNEL()");
9422 }
9423 if (q) {
9424 ao2_lock(q);
9425 if (q->count >= position) {
9426 struct queue_ent *qe;
9427
9428 for (qe = q->head; qe; qe = qe->next) {
9429 if (qe->pos == position) {
9431 break;
9432 }
9433 }
9434 }
9435 ao2_unlock(q);
9436 queue_t_unref(q, "Done with reference in QUEUE_GET_CHANNEL()");
9437 return 0;
9438 }
9439
9440 var = ast_load_realtime("queues", "name", args.queuename, SENTINEL);
9441 if (var) {
9442 /* if the queue is realtime but was not found in memory, this
9443 * means that the queue had been deleted from memory since it was
9444 * "dead."
9445 */
9447 return 0;
9448 }
9449
9450 ast_log(LOG_WARNING, "queue %s was not found\n", args.queuename);
9451 return 0;
9452}

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

9493{
9494 struct call_queue *q;
9495 struct member *m;
9496
9497 /* Ensure an otherwise empty list doesn't return garbage */
9498 buf[0] = '\0';
9499
9500 if (ast_strlen_zero(data)) {
9501 ast_log(LOG_ERROR, "QUEUE_MEMBER_LIST requires an argument: queuename\n");
9502 return -1;
9503 }
9504
9505 if ((q = find_load_queue_rt_friendly(data))) {
9506 int buflen = 0, count = 0;
9507 struct ao2_iterator mem_iter;
9508
9509 ao2_lock(q);
9510 mem_iter = ao2_iterator_init(q->members, 0);
9511 while ((m = ao2_iterator_next(&mem_iter))) {
9512 /* strcat() is always faster than printf() */
9513 if (count++) {
9514 strncat(buf + buflen, ",", len - buflen - 1);
9515 buflen++;
9516 }
9517 strncat(buf + buflen, m->interface, len - buflen - 1);
9518 buflen += strlen(m->interface);
9519 /* Safeguard against overflow (negative length) */
9520 if (buflen >= len - 2) {
9521 ao2_ref(m, -1);
9522 ast_log(LOG_WARNING, "Truncating list\n");
9523 break;
9524 }
9525 ao2_ref(m, -1);
9526 }
9527 ao2_iterator_destroy(&mem_iter);
9528 ao2_unlock(q);
9529 queue_t_unref(q, "Done with QUEUE_MEMBER_LIST()");
9530 } else
9531 ast_log(LOG_WARNING, "queue %s was not found\n", data);
9532
9533 /* We should already be terminated, but let's make sure. */
9534 buf[len - 1] = '\0';
9535
9536 return 0;
9537}

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

9456{
9457 int count = 0;
9458 struct call_queue *q, tmpq = {
9459 .name = data,
9460 };
9461 struct ast_variable *var = NULL;
9462
9463 buf[0] = '\0';
9464
9465 if (ast_strlen_zero(data)) {
9466 ast_log(LOG_ERROR, "QUEUE_WAITING_COUNT requires an argument: queuename\n");
9467 return -1;
9468 }
9469
9470 if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Find for QUEUE_WAITING_COUNT()"))) {
9471 ao2_lock(q);
9472 count = q->count;
9473 ao2_unlock(q);
9474 queue_t_unref(q, "Done with reference in QUEUE_WAITING_COUNT()");
9475 } else if ((var = ast_load_realtime("queues", "name", data, SENTINEL))) {
9476 /* if the queue is realtime but was not found in memory, this
9477 * means that the queue had been deleted from memory since it was
9478 * "dead." This means it has a 0 waiting count
9479 */
9480 count = 0;
9482 } else {
9483 ast_log(LOG_WARNING, "queue %s was not found\n", data);
9484 }
9485
9486 snprintf(buf, len, "%d", count);
9487
9488 return 0;
9489}

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

9130{
9131 int res = -1;
9132 struct call_queue *q;
9133 char interfacevar[256] = "";
9134 float sl = 0;
9135
9136 if (ast_strlen_zero(data)) {
9137 ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd);
9138 return -1;
9139 }
9140
9141 if ((q = find_load_queue_rt_friendly(data))) {
9142 ao2_lock(q);
9143 if (q->setqueuevar) {
9144 sl = 0;
9145 res = 0;
9146
9147 if (q->callscompleted > 0) {
9148 sl = 100 * ((float) q->callscompletedinsl / (float) q->callscompleted);
9149 }
9150
9151 snprintf(interfacevar, sizeof(interfacevar),
9152 "QUEUEMAX=%d,QUEUESTRATEGY=%s,QUEUECALLS=%d,QUEUEHOLDTIME=%d,QUEUETALKTIME=%d,QUEUECOMPLETED=%d,QUEUEABANDONED=%d,QUEUESRVLEVEL=%d,QUEUESRVLEVELPERF=%2.1f",
9154
9155 pbx_builtin_setvar_multiple(chan, interfacevar);
9156 }
9157
9158 ao2_unlock(q);
9159 queue_t_unref(q, "Done with QUEUE() function");
9160 } else {
9161 ast_log(LOG_WARNING, "queue %s was not found\n", data);
9162 }
9163
9164 snprintf(buf, len, "%d", res);
9165
9166 return 0;
9167}
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 2102 of file app_queue.c.

2103{
2104 const struct call_queue *q = obj;
2105
2106 return ast_str_case_hash(q->name);
2107}

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

2311{
2312 return queue_member_to_ami("QueueMemberAdded", message);
2313}
static struct ast_manager_event_blob * queue_member_to_ami(const char *type, struct stasis_message *message)
Definition: app_queue.c:2290

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

2527{
2528 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}",
2529 "Queue", q->name,
2530 "MemberName", mem->membername,
2531 "Interface", mem->interface,
2532 "StateInterface", mem->state_interface,
2533 "Membership", (mem->dynamic ? "dynamic" : (mem->realtime ? "realtime" : "static")),
2534 "Penalty", mem->penalty,
2535 "CallsTaken", mem->calls,
2536 "LastCall", (int)mem->lastcall,
2537 "LastPause", (int)mem->lastpause,
2538 "LoginTime", (int)mem->logintime,
2539 "InCall", mem->starttime ? 1 : 0,
2540 "Status", mem->status,
2541 "Paused", mem->paused,
2542 "PausedReason", mem->reason_paused,
2543 "Ringinuse", mem->ringinuse,
2544 "Wrapuptime", mem->wrapuptime);
2545}

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

2137{
2138 struct member *mem = obj;
2139 int *decrement_followers_after = arg;
2140
2141 if (mem->queuepos > *decrement_followers_after) {
2142 mem->queuepos--;
2143 }
2144
2145 return 0;
2146}

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

2174{
2175 int pos = mem->queuepos;
2176
2177 /* 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
2178 * who would have been next otherwise. */
2179 if (pos < queue->rrpos) {
2180 queue->rrpos--;
2181 }
2182
2184}

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

2321{
2322 return queue_member_to_ami("QueueMemberPause", message);
2323}

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

2326{
2327 return queue_member_to_ami("QueueMemberPenalty", message);
2328}

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

2316{
2317 return queue_member_to_ami("QueueMemberRemoved", message);
2318}

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

2331{
2332 return queue_member_to_ami("QueueMemberRinginuse", message);
2333}

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

2306{
2307 return queue_member_to_ami("QueueMemberStatus", message);
2308}

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

2355{
2358 struct ast_channel_snapshot *agent;
2359 RAII_VAR(struct ast_str *, caller_event_string, NULL, ast_free);
2360 RAII_VAR(struct ast_str *, agent_event_string, NULL, ast_free);
2361 RAII_VAR(struct ast_str *, event_string, NULL, ast_free);
2362
2364 if (caller) {
2365 caller_event_string = ast_manager_build_channel_state_string(caller);
2366 if (!caller_event_string) {
2367 ast_log(LOG_NOTICE, "No caller event string, bailing\n");
2368 return NULL;
2369 }
2370 }
2371
2372 agent = ast_multi_channel_blob_get_channel(obj, "agent");
2373 if (agent) {
2374 agent_event_string = ast_manager_build_channel_state_string_prefix(agent, "Dest");
2375 if (!agent_event_string) {
2376 ast_log(LOG_NOTICE, "No agent event string, bailing\n");
2377 return NULL;
2378 }
2379 }
2380
2382 if (!event_string) {
2383 return NULL;
2384 }
2385
2387 "%s"
2388 "%s"
2389 "%s",
2390 caller_event_string ? ast_str_buffer(caller_event_string) : "",
2391 agent_event_string ? ast_str_buffer(agent_event_string) : "",
2392 ast_str_buffer(event_string));
2393}
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 2502 of file app_queue.c.

2503{
2504 RAII_VAR(struct ast_json_payload *, payload, NULL, ao2_cleanup);
2505 RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
2506
2507 if (!blob || !type) {
2508 ast_json_unref(blob);
2509 return;
2510 }
2511
2512 payload = ast_json_payload_create(blob);
2513 ast_json_unref(blob);
2514 if (!payload) {
2515 return;
2516 }
2517
2518 msg = stasis_message_create(type, payload);
2519 if (!msg) {
2520 return;
2521 }
2522
2524}
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:1578

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

2473{
2474 RAII_VAR(struct ast_channel_snapshot *, caller_snapshot, NULL, ao2_cleanup);
2475 RAII_VAR(struct ast_channel_snapshot *, agent_snapshot, NULL, ao2_cleanup);
2476
2477 ast_channel_lock(caller);
2478 caller_snapshot = ast_channel_snapshot_create(caller);
2479 ast_channel_unlock(caller);
2480 ast_channel_lock(agent);
2481 agent_snapshot = ast_channel_snapshot_create(agent);
2482 ast_channel_unlock(agent);
2483
2484 if (!caller_snapshot || !agent_snapshot) {
2485 return;
2486 }
2487
2489 agent_snapshot, type, blob);
2490}
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:2436
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 2436 of file app_queue.c.

2440{
2441 RAII_VAR(struct ast_multi_channel_blob *, payload, NULL, ao2_cleanup);
2442 RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
2443
2444 if (!type) {
2445 return;
2446 }
2447
2448 payload = ast_multi_channel_blob_create(blob);
2449 if (!payload) {
2450 return;
2451 }
2452
2453 if (caller_snapshot) {
2454 ast_multi_channel_blob_add_channel(payload, "caller", caller_snapshot);
2455 } else {
2456 ast_debug(1, "Empty caller_snapshot; sending incomplete event\n");
2457 }
2458
2459 if (agent_snapshot) {
2460 ast_multi_channel_blob_add_channel(payload, "agent", agent_snapshot);
2461 }
2462
2463 msg = stasis_message_create(type, payload);
2464 if (!msg) {
2465 return;
2466 }
2467
2468 stasis_publish(topic, msg);
2469}
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 9725 of file app_queue.c.

9726{
9728 autofill_default = 0;
9729 montype_default = 0;
9730 shared_lastcall = 0;
9735}
static int montype_default
queues.conf [general] option
Definition: app_queue.c:1722
static int negative_penalty_invalid
queues.conf [general] option
Definition: app_queue.c:1734
static int shared_lastcall
queues.conf [general] option
Definition: app_queue.c:1725
static int log_unpause_on_reason_change
queues.conf [general] option
Definition: app_queue.c:1746

References autofill_default, force_longest_waiting_caller, log_membername_as_agent, log_unpause_on_reason_change, 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 9646 of file app_queue.c.

9647{
9648 realtime_rules = 0;
9649}
static int realtime_rules
queuerules.conf [general] option
Definition: app_queue.c:1728

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

9653{
9654 const char *general_val = NULL;
9655 if ((general_val = ast_variable_retrieve(cfg, "general", "realtime_rules"))) {
9656 realtime_rules = ast_true(general_val);
9657 }
9658}

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

9739{
9740 const char *general_val = NULL;
9741 if ((general_val = ast_variable_retrieve(cfg, "general", "persistentmembers"))) {
9742 queue_persistent_members = ast_true(general_val);
9743 }
9744 if ((general_val = ast_variable_retrieve(cfg, "general", "autofill"))) {
9745 autofill_default = ast_true(general_val);
9746 }
9747 if ((general_val = ast_variable_retrieve(cfg, "general", "monitor-type"))) {
9748 if (!strcasecmp(general_val, "mixmonitor"))
9749 montype_default = 1;
9750 }
9751 if ((general_val = ast_variable_retrieve(cfg, "general", "shared_lastcall"))) {
9752 shared_lastcall = ast_true(general_val);
9753 }
9754 if ((general_val = ast_variable_retrieve(cfg, "general", "negative_penalty_invalid"))) {
9755 negative_penalty_invalid = ast_true(general_val);
9756 }
9757 if ((general_val = ast_variable_retrieve(cfg, "general", "log_membername_as_agent"))) {
9758 log_membername_as_agent = ast_true(general_val);
9759 }
9760 if ((general_val = ast_variable_retrieve(cfg, "general", "force_longest_waiting_caller"))) {
9762 }
9763 if ((general_val = ast_variable_retrieve(cfg, "general", "log_unpause_on_reason_change"))) {
9765 }
9766 /* Apply log-caller-id-name in the same place as other global settings */
9767 if ((general_val = ast_variable_retrieve(cfg, "general", "log-caller-id-name"))) {
9768 log_caller_id_name = ast_true(general_val);
9769 }
9770}

References ast_true(), ast_variable_retrieve(), autofill_default, force_longest_waiting_caller, log_caller_id_name, log_membername_as_agent, log_unpause_on_reason_change, 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 3483 of file app_queue.c.

3484{
3485 if (!strcasecmp(param, "musicclass") ||
3486 !strcasecmp(param, "music") || !strcasecmp(param, "musiconhold")) {
3487 ast_string_field_set(q, moh, val);
3488 } else if (!strcasecmp(param, "announce")) {
3489 ast_string_field_set(q, announce, val);
3490 } else if (!strcasecmp(param, "context")) {
3492 } else if (!strcasecmp(param, "timeout")) {
3493 q->timeout = atoi(val);
3494 if (q->timeout < 0) {
3496 }
3497 } else if (!strcasecmp(param, "ringinuse")) {
3498 q->ringinuse = ast_true(val);
3499 } else if (!strcasecmp(param, "setinterfacevar")) {
3501 } else if (!strcasecmp(param, "setqueuevar")) {
3502 q->setqueuevar = ast_true(val);
3503 } else if (!strcasecmp(param, "setqueueentryvar")) {
3505 } else if (!strcasecmp(param, "monitor-format")) {
3506 ast_copy_string(q->monfmt, val, sizeof(q->monfmt));
3507 } else if (!strcasecmp(param, "membergosub")) {
3508 ast_string_field_set(q, membergosub, val);
3509 } else if (!strcasecmp(param, "queue-youarenext")) {
3510 ast_string_field_set(q, sound_next, val);
3511 } else if (!strcasecmp(param, "queue-thereare")) {
3512 ast_string_field_set(q, sound_thereare, val);
3513 } else if (!strcasecmp(param, "queue-callswaiting")) {
3514 ast_string_field_set(q, sound_calls, val);
3515 } else if (!strcasecmp(param, "queue-quantity1")) {
3516 ast_string_field_set(q, queue_quantity1, val);
3517 } else if (!strcasecmp(param, "queue-quantity2")) {
3518 ast_string_field_set(q, queue_quantity2, val);
3519 } else if (!strcasecmp(param, "queue-holdtime")) {
3520 ast_string_field_set(q, sound_holdtime, val);
3521 } else if (!strcasecmp(param, "queue-minutes")) {
3522 ast_string_field_set(q, sound_minutes, val);
3523 } else if (!strcasecmp(param, "queue-minute")) {
3524 ast_string_field_set(q, sound_minute, val);
3525 } else if (!strcasecmp(param, "queue-seconds")) {
3526 ast_string_field_set(q, sound_seconds, val);
3527 } else if (!strcasecmp(param, "queue-thankyou")) {
3528 ast_string_field_set(q, sound_thanks, val);
3529 } else if (!strcasecmp(param, "queue-callerannounce")) {
3530 ast_string_field_set(q, sound_callerannounce, val);
3531 } else if (!strcasecmp(param, "queue-reporthold")) {
3532 ast_string_field_set(q, sound_reporthold, val);
3533 } else if (!strcasecmp(param, "announce-frequency")) {
3534 q->announcefrequency = atoi(val);
3535 } else if (!strcasecmp(param, "announce-to-first-user")) {
3537 } else if (!strcasecmp(param, "min-announce-frequency")) {
3538 q->minannouncefrequency = atoi(val);
3539 ast_debug(1, "%s=%s for queue '%s'\n", param, val, q->name);
3540 } else if (!strcasecmp(param, "announce-round-seconds")) {
3541 q->roundingseconds = atoi(val);
3542 /* Rounding to any other values just doesn't make sense... */
3543 if (!(q->roundingseconds == 0 || q->roundingseconds == 5 || q->roundingseconds == 10
3544 || q->roundingseconds == 15 || q->roundingseconds == 20 || q->roundingseconds == 30)) {
3545 if (linenum >= 0) {
3546 ast_log(LOG_WARNING, "'%s' isn't a valid value for %s "
3547 "using 0 instead for queue '%s' at line %d of queues.conf\n",
3548 val, param, q->name, linenum);
3549 } else {
3550 ast_log(LOG_WARNING, "'%s' isn't a valid value for %s "
3551 "using 0 instead for queue '%s'\n", val, param, q->name);
3552 }
3553 q->roundingseconds=0;
3554 }
3555 } else if (!strcasecmp(param, "announce-holdtime")) {
3556 if (!strcasecmp(val, "once")) {
3558 } else if (ast_true(val)) {
3560 } else {
3561 q->announceholdtime = 0;
3562 }
3563 } else if (!strcasecmp(param, "announce-position")) {
3564 if (!strcasecmp(val, "limit")) {
3566 } else if (!strcasecmp(val, "more")) {
3568 } else if (ast_true(val)) {
3570 } else {
3572 }
3573 } else if (!strcasecmp(param, "announce-position-only-up")) {
3575 } else if (!strcasecmp(param, "announce-position-limit")) {
3576 q->announcepositionlimit = atoi(val);
3577 } else if (!strcasecmp(param, "periodic-announce")) {
3578 if (strchr(val, ',')) {
3579 char *s, *buf = ast_strdupa(val);
3580 unsigned int i = 0;
3581
3582 while ((s = strsep(&buf, ",|"))) {
3583 if (!q->sound_periodicannounce[i]) {
3585 }
3586 ast_str_set(&q->sound_periodicannounce[i], 0, "%s", s);
3587 i++;
3588 if (i == MAX_PERIODIC_ANNOUNCEMENTS) {
3589 break;
3590 }
3591 }
3592 q->numperiodicannounce = i;
3593 } else {
3594 ast_str_set(&q->sound_periodicannounce[0], 0, "%s", val);
3595 q->numperiodicannounce = 1;
3596 }
3597 } else if (!strcasecmp(param, "periodic-announce-startdelay")) {
3599 } else if (!strcasecmp(param, "periodic-announce-frequency")) {
3600 q->periodicannouncefrequency = atoi(val);
3601 } else if (!strcasecmp(param, "relative-periodic-announce")) {
3603 } else if (!strcasecmp(param, "random-periodic-announce")) {
3605 } else if (!strcasecmp(param, "retry")) {
3606 q->retry = atoi(val);
3607 if (q->retry <= 0) {
3608 q->retry = DEFAULT_RETRY;
3609 }
3610 } else if (!strcasecmp(param, "wrapuptime")) {
3611 q->wrapuptime = atoi(val);
3612 } else if (!strcasecmp(param, "penaltymemberslimit")) {
3613 if ((sscanf(val, "%10d", &q->penaltymemberslimit) != 1)) {
3614 q->penaltymemberslimit = 0;
3615 }
3616 } else if (!strcasecmp(param, "autofill")) {
3617 q->autofill = ast_true(val);
3618 } else if (!strcasecmp(param, "autopause")) {
3620 } else if (!strcasecmp(param, "autopausedelay")) {
3621 q->autopausedelay = atoi(val);
3622 } else if (!strcasecmp(param, "autopausebusy")) {
3624 } else if (!strcasecmp(param, "autopauseunavail")) {
3626 } else if (!strcasecmp(param, "maxlen")) {
3627 q->maxlen = atoi(val);
3628 if (q->maxlen < 0) {
3629 q->maxlen = 0;
3630 }
3631 } else if (!strcasecmp(param, "servicelevel")) {
3632 q->servicelevel= atoi(val);
3633 } else if (!strcasecmp(param, "strategy")) {
3634 int strategy;
3635
3636 /* We are a static queue and already have set this, no need to do it again */
3637 if (failunknown) {
3638 return;
3639 }
3641 if (strategy < 0) {
3642 ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n",
3643 val, q->name);
3645 }
3646 if (strategy == q->strategy) {
3647 return;
3648 }
3650 ast_log(LOG_WARNING, "Changing to the linear strategy currently requires asterisk to be restarted.\n");
3651 return;
3652 }
3653 q->strategy = strategy;
3654 } else if (!strcasecmp(param, "joinempty")) {
3656 } else if (!strcasecmp(param, "leavewhenempty")) {
3658 } else if (!strcasecmp(param, "reportholdtime")) {
3660 } else if (!strcasecmp(param, "memberdelay")) {
3661 q->memberdelay = atoi(val);
3662 } else if (!strcasecmp(param, "weight")) {
3663 q->weight = atoi(val);
3664 } else if (!strcasecmp(param, "timeoutrestart")) {
3666 } else if (!strcasecmp(param, "defaultrule")) {
3667 ast_string_field_set(q, defaultrule, val);
3668 } else if (!strcasecmp(param, "timeoutpriority")) {
3669 if (!strcasecmp(val, "conf")) {
3671 } else {
3673 }
3674 } else if (!strcasecmp(param, "log-restricted-caller-id")) {
3676 } else if (failunknown) {
3677 if (linenum >= 0) {
3678 ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s at line %d of queues.conf\n",
3679 q->name, param, linenum);
3680 } else {
3681 ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s\n", q->name, param);
3682 }
3683 }
3684}
#define ANNOUNCEPOSITION_MORE_THAN
Definition: app_queue.c:1919
static void parse_empty_options(const char *value, enum empty_conditions *empty, int joinempty)
Definition: app_queue.c:3440
#define ANNOUNCEPOSITION_NO
Definition: app_queue.c:1918
#define ANNOUNCEHOLDTIME_ALWAYS
Definition: app_queue.c:1901
#define ANNOUNCEPOSITION_LIMIT
Definition: app_queue.c:1920
#define ANNOUNCEHOLDTIME_ONCE
Definition: app_queue.c:1902
static int autopause2int(const char *autopause)
Definition: app_queue.c:2079
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 10538 of file app_queue.c.

10539{
10540 switch ( cmd ) {
10541 case CLI_INIT:
10542 e->command = "queue show";
10543 e->usage =
10544 "Usage: queue show\n"
10545 " Provides summary information on a specified queue.\n";
10546 return NULL;
10547 case CLI_GENERATE:
10548 return complete_queue_show(a->line, a->word, a->pos, a->n);
10549 }
10550
10551 return __queues_show(NULL, a->fd, a->argc, a->argv);
10552}
static char * complete_queue_show(const char *line, const char *word, int pos, int state)
Definition: app_queue.c:10530
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:10322

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

6445{
6446 struct queue_stasis_data *queue_data;
6447
6448 queue_data = ao2_alloc(sizeof(*queue_data), queue_stasis_data_destructor);
6449 if (!queue_data) {
6450 return NULL;
6451 }
6452
6453 if (ast_string_field_init(queue_data, 64)) {
6454 ao2_cleanup(queue_data);
6455 return NULL;
6456 }
6457
6460 queue_data->queue = queue_ref(qe->parent);
6461 queue_data->starttime = starttime;
6462 queue_data->holdstart = holdstart;
6464 queue_data->caller_pos = qe->opos;
6465 ao2_ref(mem, +1);
6466 queue_data->member = mem;
6467
6468 return queue_data;
6469}
static void queue_stasis_data_destructor(void *obj)
Definition: app_queue.c:6410

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

6411{
6412 struct queue_stasis_data *queue_data = obj;
6413
6414 /* This can only happen if refcounts for this object have got severely messed up */
6415 ast_assert(queue_data->bridge_router == NULL);
6416 ast_assert(queue_data->channel_router == NULL);
6417
6418 ao2_cleanup(queue_data->member);
6419 queue_unref(queue_data->queue);
6420 ast_string_field_free_memory(queue_data);
6421}
struct stasis_message_router * channel_router
Definition: app_queue.c:6399
struct stasis_message_router * bridge_router
Definition: app_queue.c:6397

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

11784{
11785 int oldtalktime;
11786 char *parse;
11787 struct call_queue *q;
11788 struct member *mem;
11789 int newtalktime = 0;
11790
11792 AST_APP_ARG(queuename);
11793 AST_APP_ARG(uniqueid);
11794 AST_APP_ARG(agent);
11796 AST_APP_ARG(talktime);
11797 AST_APP_ARG(params););
11798
11799 if (ast_strlen_zero(data)) {
11800 ast_log(LOG_WARNING, "QueueUpdate requires arguments (queuename,uniqueid,agent,status,talktime,params[totaltime,callednumber])\n");
11801 return -1;
11802 }
11803
11804 parse = ast_strdupa(data);
11805
11807
11808 if (ast_strlen_zero(args.queuename) || ast_strlen_zero(args.uniqueid) || ast_strlen_zero(args.agent) || ast_strlen_zero(args.status)) {
11809 ast_log(LOG_WARNING, "Missing argument to QueueUpdate (queuename,uniqueid,agent,status,talktime,params[totaltime|callednumber])\n");
11810 return -1;
11811 }
11812
11813 if (!ast_strlen_zero(args.talktime)) {
11814 newtalktime = atoi(args.talktime);
11815 }
11816
11817 q = find_load_queue_rt_friendly(args.queuename);
11818 if (!q) {
11819 ast_log(LOG_WARNING, "QueueUpdate could not find requested queue '%s'\n", args.queuename);
11820 return 0;
11821 }
11822
11823 ao2_lock(q);
11824 if (q->members) {
11825 struct ao2_iterator mem_iter = ao2_iterator_init(q->members, 0);
11826 while ((mem = ao2_iterator_next(&mem_iter))) {
11827 if (!strcasecmp(mem->membername, args.agent)) {
11828 if (!strcasecmp(args.status, "ANSWER")) {
11829 oldtalktime = q->talktime;
11830 q->talktime = (((oldtalktime << 2) - oldtalktime) + newtalktime) >> 2;
11831 time(&mem->lastcall);
11832 mem->calls++;
11833 mem->lastqueue = q;
11834 q->callscompleted++;
11835
11836 if (newtalktime <= q->servicelevel) {
11837 q->callscompletedinsl++;
11838 }
11839 } else {
11840
11841 time(&mem->lastcall);
11842 q->callsabandoned++;
11843 }
11844
11845 ast_queue_log(args.queuename, args.uniqueid, args.agent, "OUTCALL", "%s|%s|%s", args.status, args.talktime, args.params);
11846 }
11847
11848 ao2_ref(mem, -1);
11849 }
11850
11851 ao2_iterator_destroy(&mem_iter);
11852 }
11853
11854 ao2_unlock(q);
11855 queue_t_unref(q, "Done with temporary pointer");
11856
11857 return 0;
11858}

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

4501{
4502 int oldvalue;
4503
4504 /* Calculate holdtime using an exponential average */
4505 /* Thanks to SRT for this contribution */
4506 /* 2^2 (4) is the filter coefficient; a higher exponent would give old entries more weight */
4507
4508 ao2_lock(qe->parent);
4509 if ((qe->parent->callscompleted + qe->parent->callsabandoned) == 0) {
4510 qe->parent->holdtime = newholdtime;
4511 } else {
4512 oldvalue = qe->parent->holdtime;
4513 qe->parent->holdtime = (((oldvalue << 2) - oldvalue) + newholdtime) >> 2;
4514 }
4515 ao2_unlock(qe->parent);
4516}

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

5231{
5232 int callabandonedinsl = 0;
5233 time_t now;
5234
5235 RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
5236
5237 pbx_builtin_setvar_helper(qe->chan, "ABANDONED", "TRUE");
5238
5240 ao2_lock(qe->parent);
5241 blob = ast_json_pack("{s: s, s: i, s: i, s: i}",
5242 "Queue", qe->parent->name,
5243 "Position", qe->pos,
5244 "OriginalPosition", qe->opos,
5245 "HoldTime", (int)(time(NULL) - qe->start));
5246
5247
5248 time(&now);
5249 callabandonedinsl = ((now - qe->start) <= qe->parent->servicelevel);
5250 if (callabandonedinsl) {
5252 }
5253
5254 qe->parent->callsabandoned++;
5255 ao2_unlock(qe->parent);
5256
5257 ast_channel_publish_cached_blob(qe->chan, queue_caller_abandon_type(), blob);
5258}

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

12106{
12107 struct ast_flags mask = {AST_FLAGS_ALL & ~QUEUE_RESET_STATS,};
12108 ast_unload_realtime("queue_members");
12109 reload_handler(1, &mask, NULL);
12110 return 0;
12111}
int ast_unload_realtime(const char *family)
Release any resources cached for a realtime family.
Definition: main/config.c:3843

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

10188{
10189 int res = 0;
10190
10191 if (ast_test_flag(mask, QUEUE_RELOAD_RULES)) {
10192 res |= reload_queue_rules(reload);
10193 }
10194 if (ast_test_flag(mask, QUEUE_RESET_STATS)) {
10195 res |= clear_stats(queuename);
10196 }
10198 res |= reload_queues(reload, mask, queuename);
10199 }
10200 return res;
10201}
static int reload_queues(int reload, struct ast_flags *mask, const char *queuename)
reload the queues.conf file
Definition: app_queue.c:10100
static int reload_queue_rules(int reload)
Reload the rules defined in queuerules.conf.
Definition: app_queue.c:9666
static int clear_stats(const char *queuename)
Facilitates resetting statistics for a queue.
Definition: app_queue.c:10157
static int reload(void)
Definition: app_queue.c:12105

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

8265{
8266 char *cur_ptr;
8267 const char *queue_name;
8268 char *member;
8269 char *interface;
8270 char *membername = NULL;
8271 char *state_interface;
8272 char *penalty_tok;
8273 int penalty = 0;
8274 char *paused_tok;
8275 int paused = 0;
8276 char *wrapuptime_tok;
8277 int wrapuptime = 0;
8278 char *reason_paused;
8279 struct ast_db_entry *db_tree;
8280 struct ast_db_entry *entry;
8281 struct call_queue *cur_queue;
8282 char *queue_data;
8283
8284 /* Each key in 'pm_family' is the name of a queue */
8285 db_tree = ast_db_gettree(pm_family, NULL);
8286 for (entry = db_tree; entry; entry = entry->next) {
8287
8288 queue_name = entry->key + strlen(pm_family) + 2;
8289
8290 {
8291 struct call_queue tmpq = {
8292 .name = queue_name,
8293 };
8294 cur_queue = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Reload queue members");
8295 }
8296
8297 if (!cur_queue) {
8298 cur_queue = find_load_queue_rt_friendly(queue_name);
8299 }
8300
8301 if (!cur_queue) {
8302 /* If the queue no longer exists, remove it from the
8303 * database */
8304 ast_log(LOG_WARNING, "Error loading persistent queue: '%s': it does not exist\n", queue_name);
8305 ast_db_del(pm_family, queue_name);
8306 continue;
8307 }
8308
8309 if (ast_db_get_allocated(pm_family, queue_name, &queue_data)) {
8310 queue_t_unref(cur_queue, "Expire reload reference");
8311 continue;
8312 }
8313
8314 cur_ptr = queue_data;
8315 while ((member = strsep(&cur_ptr, ",|"))) {
8316 if (ast_strlen_zero(member)) {
8317 continue;
8318 }
8319
8320 interface = strsep(&member, ";");
8321 penalty_tok = strsep(&member, ";");
8322 paused_tok = strsep(&member, ";");
8323 membername = strsep(&member, ";");
8324 state_interface = strsep(&member, ";");
8325 reason_paused = strsep(&member, ";");
8326 wrapuptime_tok = strsep(&member, ";");
8327
8328 if (!penalty_tok) {
8329 ast_log(LOG_WARNING, "Error parsing persistent member string for '%s' (penalty)\n", queue_name);
8330 break;
8331 }
8332 penalty = strtol(penalty_tok, NULL, 10);
8333 if (errno == ERANGE) {
8334 ast_log(LOG_WARNING, "Error converting penalty: %s: Out of range.\n", penalty_tok);
8335 break;
8336 }
8337
8338 if (!paused_tok) {
8339 ast_log(LOG_WARNING, "Error parsing persistent member string for '%s' (paused)\n", queue_name);
8340 break;
8341 }
8342 paused = strtol(paused_tok, NULL, 10);
8343 if ((errno == ERANGE) || paused < 0 || paused > 1) {
8344 ast_log(LOG_WARNING, "Error converting paused: %s: Expected 0 or 1.\n", paused_tok);
8345 break;
8346 }
8347
8348 if (!ast_strlen_zero(wrapuptime_tok)) {
8349 wrapuptime = strtol(wrapuptime_tok, NULL, 10);
8350 if (errno == ERANGE) {
8351 ast_log(LOG_WARNING, "Error converting wrapuptime: %s: Out of range.\n", wrapuptime_tok);
8352 break;
8353 }
8354 }
8355
8356 ast_debug(1, "Reload Members: Queue: %s Member: %s Name: %s Penalty: %d Paused: %d ReasonPause: %s Wrapuptime: %d\n",
8357 queue_name, interface, membername, penalty, paused, reason_paused, wrapuptime);
8358
8359 if (add_to_queue(queue_name, interface, membername, penalty, paused, 0, state_interface, reason_paused, wrapuptime) == RES_OUTOFMEMORY) {
8360 ast_log(LOG_ERROR, "Out of Memory when reloading persistent queue member\n");
8361 break;
8362 }
8363 }
8364 queue_t_unref(cur_queue, "Expire reload reference");
8365 ast_free(queue_data);
8366 }
8367
8368 if (db_tree) {
8369 ast_log(LOG_NOTICE, "Queue members successfully reloaded from database.\n");
8370 ast_db_freetree(db_tree);
8371 }
8372}
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: db.c:431
struct ast_db_entry * ast_db_gettree(const char *family, const char *keytree)
Get a list of values within the astdb tree.
Definition: db.c:635
void ast_db_freetree(struct ast_db_entry *entry)
Free structure created by ast_db_gettree()
Definition: db.c:695
int errno
Definition: astdb.h:31
struct ast_db_entry * next
Definition: astdb.h:32
char * key
Definition: astdb.h:33

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, ast_db_entry::key, LOG_ERROR, LOG_NOTICE, LOG_WARNING, member::membername, call_queue::name, ast_db_entry::next, 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 9666 of file app_queue.c.

9667{
9668 struct ast_config *cfg;
9669 struct rule_list *rl_iter, *new_rl;
9670 struct penalty_rule *pr_iter;
9671 char *rulecat = NULL;
9672 struct ast_variable *rulevar = NULL;
9673 struct ast_flags config_flags = { (reload && !realtime_rules) ? CONFIG_FLAG_FILEUNCHANGED : 0 };
9674
9675 if (!(cfg = ast_config_load("queuerules.conf", config_flags))) {
9676 ast_log(LOG_NOTICE, "No queuerules.conf file found, queues will not follow penalty rules\n");
9678 } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
9679 ast_log(LOG_NOTICE, "queuerules.conf has not changed since it was last loaded. Not taking any action.\n");
9681 } else if (cfg == CONFIG_STATUS_FILEINVALID) {
9682 ast_log(LOG_ERROR, "Config file queuerules.conf is in an invalid format. Aborting.\n");
9684 }
9685
9687 while ((rl_iter = AST_LIST_REMOVE_HEAD(&rule_lists, list))) {
9688 while ((pr_iter = AST_LIST_REMOVE_HEAD(&rl_iter->rules, list)))
9689 ast_free(pr_iter);
9690 ast_free(rl_iter);
9691 }
9693 while ((rulecat = ast_category_browse(cfg, rulecat))) {
9694 if (!strcasecmp(rulecat, "general")) {
9696 continue;
9697 }
9698 if (!(new_rl = ast_calloc(1, sizeof(*new_rl)))) {
9700 ast_config_destroy(cfg);
9702 } else {
9703 ast_copy_string(new_rl->name, rulecat, sizeof(new_rl->name));
9704 AST_LIST_INSERT_TAIL(&rule_lists, new_rl, list);
9705 for (rulevar = ast_variable_browse(cfg, rulecat); rulevar; rulevar = rulevar->next)
9706 if(!strcasecmp(rulevar->name, "penaltychange"))
9707 insert_penaltychange(new_rl->name, rulevar->value, rulevar->lineno);
9708 else
9709 ast_log(LOG_WARNING, "Don't know how to handle rule type '%s' on line %d\n", rulevar->name, rulevar->lineno);
9710 }
9711 }
9712
9713 ast_config_destroy(cfg);
9714
9718 }
9719
9722}
static int load_realtime_rules(void)
Load queue rules from realtime.
Definition: app_queue.c:3328
static void queue_rules_reset_global_params(void)
Definition: app_queue.c:9646
static int insert_penaltychange(const char *list_name, const char *content, const int linenum)
Change queue penalty by adding rule.
Definition: app_queue.c:3219
static void queue_rules_set_global_params(struct ast_config *cfg)
Definition: app_queue.c:9652
#define ast_config_load(filename, flags)
Load a config file.
#define CONFIG_STATUS_FILEUNCHANGED
#define CONFIG_STATUS_FILEINVALID
@ CONFIG_FLAG_FILEUNCHANGED
struct ast_variable * ast_variable_browse(const struct ast_config *config, const char *category_name)
Definition: extconf.c:1213

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

10101{
10102 struct ast_config *cfg;
10103 char *cat;
10104 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
10105 const int queue_reload = ast_test_flag(mask, QUEUE_RELOAD_PARAMETERS);
10106
10107 if (!(cfg = ast_config_load("queues.conf", config_flags))) {
10108 ast_log(LOG_NOTICE, "No call queueing config file (queues.conf), so no call queues\n");
10109 return -1;
10110 } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
10111 return 0;
10112 } else if (cfg == CONFIG_STATUS_FILEINVALID) {
10113 ast_log(LOG_ERROR, "Config file queues.conf is in an invalid format. Aborting.\n");
10114 return -1;
10115 }
10116
10117 /* We've made it here, so it looks like we're doing operations on all queues. */
10119
10120 /* Mark non-realtime queues not found at the beginning. */
10121 ao2_callback(queues, OBJ_NODATA, mark_unfound, (char *) queuename);
10122
10123 /* Chug through config file. */
10124 cat = NULL;
10126 while ((cat = ast_category_browse(cfg, cat)) ) {
10127 if (!strcasecmp(cat, "general") && queue_reload) {
10129 continue;
10130 }
10131 if (ast_strlen_zero(queuename) || !strcasecmp(cat, queuename))
10132 reload_single_queue(cfg, mask, cat);
10133 }
10134
10135 ast_config_destroy(cfg);
10136 if (queue_reload) {
10137 /* Unlink and mark dead all non-realtime queues that were not found in the configuration file. */
10139 }
10141 return 0;
10142}
static void queue_reset_global_params(void)
Definition: app_queue.c:9725
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:9943
static void queue_set_global_params(struct ast_config *cfg)
Definition: app_queue.c:9738
static int mark_unfound(void *obj, void *arg, int flags)
Definition: app_queue.c:10066
static int kill_if_unfound(void *obj, void *arg, int flags)
Definition: app_queue.c:10076

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

9781{
9782 char *membername, *interface, *state_interface, *tmp;
9783 char *parse;
9784 struct member *cur, *newm;
9785 struct member tmpmem;
9786 int penalty;
9787 int ringinuse;
9788 int wrapuptime;
9789 int paused;
9798 );
9799
9800 if (ast_strlen_zero(memberdata)) {
9801 ast_log(LOG_WARNING, "Empty queue member definition. Moving on!\n");
9802 return;
9803 }
9804
9805 /* Add a new member */
9806 parse = ast_strdupa(memberdata);
9807
9809
9810 interface = args.interface;
9811 if (!ast_strlen_zero(args.penalty)) {
9812 tmp = args.penalty;
9813 ast_strip(tmp);
9814 penalty = atoi(tmp);
9815 if (penalty < 0) {
9816 penalty = 0;
9817 }
9818 } else {
9819 penalty = 0;
9820 }
9821
9822 if (!ast_strlen_zero(args.membername)) {
9823 membername = args.membername;
9824 ast_strip(membername);
9825 } else {
9826 membername = interface;
9827 }
9828
9829 if (!ast_strlen_zero(args.state_interface)) {
9830 state_interface = args.state_interface;
9831 ast_strip(state_interface);
9832 } else {
9833 state_interface = interface;
9834 }
9835
9836 if (!ast_strlen_zero(args.ringinuse)) {
9837 tmp = args.ringinuse;
9838 ast_strip(tmp);
9839 if (ast_true(tmp)) {
9840 ringinuse = 1;
9841 } else if (ast_false(tmp)) {
9842 ringinuse = 0;
9843 } else {
9844 ast_log(LOG_ERROR, "Member %s has an invalid ringinuse value. Using %s ringinuse value.\n",
9845 membername, q->name);
9846 ringinuse = q->ringinuse;
9847 }
9848 } else {
9849 ringinuse = q->ringinuse;
9850 }
9851
9852 if (!ast_strlen_zero(args.wrapuptime)) {
9853 tmp = args.wrapuptime;
9854 ast_strip(tmp);
9855 wrapuptime = atoi(tmp);
9856 if (wrapuptime < 0) {
9857 wrapuptime = 0;
9858 }
9859 } else {
9860 wrapuptime = 0;
9861 }
9862
9863 if (!ast_strlen_zero(args.paused)) {
9864 tmp = args.paused;
9865 ast_strip(tmp);
9866 if (ast_true(tmp)) {
9867 paused = 1;
9868 } else if (ast_false(tmp)) {
9869 paused = 0;
9870 } else {
9871 ast_log(LOG_ERROR, "Member %s has an invalid paused value.\n", membername);
9872 paused = 0;
9873 }
9874 } else {
9875 paused = 0;
9876 }
9877
9878 /* Find the old position in the list */
9879 ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface));
9880 cur = ao2_find(q->members, &tmpmem, OBJ_POINTER);
9881
9882 if (cur) {
9883 paused = cur->paused;
9884 }
9885
9886 if ((newm = create_queue_member(interface, membername, penalty, paused, state_interface, ringinuse, wrapuptime))) {
9887 newm->wrapuptime = wrapuptime;
9888 if (cur) {
9889 ao2_lock(q->members);
9890 /* Round Robin Queue Position must be copied if this is replacing an existing member */
9891 newm->queuepos = cur->queuepos;
9892 /* Don't reset agent stats either */
9893 newm->calls = cur->calls;
9894 newm->lastcall = cur->lastcall;
9895
9896 ao2_link(q->members, newm);
9897 ao2_unlink(q->members, cur);
9898 ao2_unlock(q->members);
9899 } else {
9900 /* Otherwise we need to add using the function that will apply a round robin queue position manually. */
9901 member_add_to_queue(q, newm);
9902 }
9903 ao2_ref(newm, -1);
9904 }
9905 newm = NULL;
9906
9907 if (cur) {
9908 ao2_ref(cur, -1);
9909 }
9910}

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

9944{
9945 int new;
9946 struct call_queue *q = NULL;
9947 struct member *member;
9948 /*We're defining a queue*/
9949 struct call_queue tmpq = {
9950 .name = queuename,
9951 };
9952 const char *tmpvar;
9953 const int queue_reload = ast_test_flag(mask, QUEUE_RELOAD_PARAMETERS);
9954 const int member_reload = ast_test_flag(mask, QUEUE_RELOAD_MEMBER);
9955 int prev_weight = 0;
9956 struct ast_variable *var;
9957 struct ao2_iterator mem_iter;
9958
9959 if (!(q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Find queue for reload"))) {
9960 if (queue_reload) {
9961 /* Make one then */
9962 if (!(q = alloc_queue(queuename))) {
9963 return;
9964 }
9965 } else {
9966 /* Since we're not reloading queues, this means that we found a queue
9967 * in the configuration file which we don't know about yet. Just return.
9968 */
9969 return;
9970 }
9971 new = 1;
9972 } else {
9973 new = 0;
9974 }
9975
9976 if (!new) {
9977 ao2_lock(q);
9978 prev_weight = q->weight ? 1 : 0;
9979 }
9980 /* Check if we already found a queue with this name in the config file */
9981 if (q->found) {
9982 ast_log(LOG_WARNING, "Queue '%s' already defined! Skipping!\n", queuename);
9983 if (!new) {
9984 /* It should be impossible to *not* hit this case*/
9985 ao2_unlock(q);
9986 }
9987 queue_t_unref(q, "We exist! Expiring temporary pointer");
9988 return;
9989 }
9990 /* Due to the fact that the "linear" strategy will have a different allocation
9991 * scheme for queue members, we must devise the queue's strategy before other initializations.
9992 * To be specific, the linear strategy needs to function like a linked list, meaning the ao2
9993 * container used will have only a single bucket instead of the typical number.
9994 */
9995 if (queue_reload) {
9996 if ((tmpvar = ast_variable_retrieve(cfg, queuename, "strategy"))) {
9997 q->strategy = strat2int(tmpvar);
9998 if (q->strategy < 0) {
9999 ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n",
10000 tmpvar, q->name);
10002 }
10003 } else {
10005 }
10006 init_queue(q);
10007 }
10008 if (member_reload) {
10010 q->found = 1;
10011 }
10012
10013 /* On the first pass we just read the parameters of the queue */
10014 for (var = ast_variable_browse(cfg, queuename); var; var = var->next) {
10015 if (queue_reload && strcasecmp(var->name, "member")) {
10016 queue_set_param(q, var->name, var->value, var->lineno, 1);
10017 }
10018 }
10019
10020 /* On the second pass, we read members */
10021 for (var = ast_variable_browse(cfg, queuename); var; var = var->next) {
10022 if (member_reload && !strcasecmp(var->name, "member")) {
10023 reload_single_member(var->value, q);
10024 }
10025 }
10026
10027 /* Update ringinuse for dynamic members */
10028 if (member_reload) {
10029 ao2_lock(q->members);
10031 while ((member = ao2_iterator_next(&mem_iter))) {
10032 if (member->dynamic) {
10034 }
10035 ao2_ref(member, -1);
10036 }
10037 ao2_iterator_destroy(&mem_iter);
10038 ao2_unlock(q->members);
10039 }
10040
10041 /* At this point, we've determined if the queue has a weight, so update use_weight
10042 * as appropriate
10043 */
10044 if (!q->weight && prev_weight) {
10046 } else if (q->weight && !prev_weight) {
10048 }
10049
10050 /* Free remaining members marked as delme */
10051 if (member_reload) {
10052 ao2_lock(q->members);
10055 ao2_unlock(q->members);
10056 }
10057
10058 if (new) {
10059 queues_t_link(queues, q, "Add queue to container");
10060 } else {
10061 ao2_unlock(q);
10062 }
10063 queue_t_unref(q, "Expiring creation reference");
10064}
static int mark_member_dead(void *obj, void *arg, int flags)
Definition: app_queue.c:9912
static void reload_single_member(const char *memberdata, struct call_queue *q)
reload information pertaining to a single member
Definition: app_queue.c:9780
static int kill_dead_members(void *obj, void *arg, int flags)
Definition: app_queue.c:9921
static int queue_delme_members_decrement_followers(void *obj, void *arg, int flag)
Definition: app_queue.c:2155

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

7700{
7701 struct call_queue *q, tmpq = {
7702 .name = queuename,
7703 };
7704 struct member *mem, tmpmem;
7705 int res = RES_NOSUCHQUEUE;
7706
7707 ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface));
7708 if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Temporary reference for interface removal"))) {
7709 ao2_lock(q);
7710 if ((mem = ao2_find(q->members, &tmpmem, OBJ_POINTER))) {
7711 /* XXX future changes should beware of this assumption!! */
7712 /*Change Penalty on realtime users*/
7714 update_realtime_member_field(mem, q->name, "penalty", "-1");
7715 } else if (!mem->dynamic) {
7716 ao2_ref(mem, -1);
7717 ao2_unlock(q);
7718 queue_t_unref(q, "Interface wasn't dynamic, expiring temporary reference");
7719 return RES_NOT_DYNAMIC;
7720 }
7721 queue_publish_member_blob(queue_member_removed_type(), queue_member_blob_create(q, mem));
7722
7724 ao2_ref(mem, -1);
7725
7728 }
7729
7730 if (!num_available_members(q)) {
7732 }
7733
7734 res = RES_OKAY;
7735 } else {
7736 res = RES_EXISTS;
7737 }
7738 ao2_unlock(q);
7739 queue_t_unref(q, "Expiring temporary reference");
7740 }
7741
7742 return res;
7743}
static int update_realtime_member_field(struct member *mem, const char *queue_name, const char *field, const char *value)
Definition: app_queue.c:4135
char rt_uniqueid[80]
Definition: app_queue.c:1880

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

6428{
6429 SCOPED_AO2LOCK(lock, queue_data);
6430
6431 queue_data->dying = 1;
6433 queue_data->bridge_router = NULL;
6435 queue_data->channel_router = NULL;
6436}
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 7881 of file app_queue.c.

7882{
7883 struct call_queue *q;
7884 struct queue_ent *qe;
7885 int res = RES_NOSUCHQUEUE;
7886
7887 /*! \note Ensure the appropriate realtime queue is loaded. Note that this
7888 * short-circuits if the queue is already in memory. */
7889 if (!(q = find_load_queue_rt_friendly(queuename))) {
7890 return res;
7891 }
7892
7893 ao2_lock(q);
7894 res = RES_NOT_CALLER;
7895 for (qe = q->head; qe; qe = qe->next) {
7896 if (!strcmp(ast_channel_name(qe->chan), caller)) {
7897 if (qe->withdraw) {
7898 ast_debug(1, "Ignoring duplicate withdraw request of caller %s from queue %s\n", caller, queuename);
7899 res = RES_EXISTS;
7900 } else {
7901 ast_debug(1, "Requested withdraw of caller %s from queue %s\n", caller, queuename);
7902 /* It is not possible to change the withdraw info by further withdraw requests for this caller (channel)
7903 in this queue, so we do not need to worry about a memory leak here. */
7904 if (withdraw_info) {
7906 }
7907 qe->withdraw = 1;
7908 res = RES_OKAY;
7909 }
7910 break;
7911 }
7912 }
7913 ao2_unlock(q);
7914 queue_unref(q);
7915
7916 return res;
7917}

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

4905{
4906 int res;
4907 int status;
4908 char tech[256];
4909 char *location;
4910 struct ast_format_cap *nativeformats;
4911 RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
4912
4913 /* on entry here, we know that tmp->chan == NULL */
4914 if (!can_ring_entry(qe, tmp)) {
4915 tmp->stillgoing = 0;
4916 ++*busies;
4917 return 0;
4918 }
4919
4920 ast_copy_string(tech, tmp->interface, sizeof(tech));
4921 if ((location = strchr(tech, '/'))) {
4922 *location++ = '\0';
4923 } else {
4924 location = "";
4925 }
4926
4928 nativeformats = ao2_bump(ast_channel_nativeformats(qe->chan));
4930
4931 /* Request the peer */
4932 tmp->chan = ast_request(tech, nativeformats, NULL, qe->chan, location, &status);
4933 ao2_cleanup(nativeformats);
4934 if (!tmp->chan) { /* If we can't, just go on to the next call */
4935 ao2_lock(qe->parent);
4936 qe->parent->rrpos++;
4937 qe->linpos++;
4938 ao2_unlock(qe->parent);
4939
4941
4942 publish_dial_end_event(qe->chan, tmp, NULL, "BUSY");
4943 tmp->stillgoing = 0;
4944 ++*busies;
4945 return 0;
4946 }
4947
4948 ast_channel_lock_both(tmp->chan, qe->chan);
4949
4952 if (qe->cancel_answered_elsewhere) {
4954 }
4955 ast_channel_appl_set(tmp->chan, "AppQueue");
4956 ast_channel_data_set(tmp->chan, "(Outgoing Line)");
4957 memset(ast_channel_whentohangup(tmp->chan), 0, sizeof(*ast_channel_whentohangup(tmp->chan)));
4958
4959 /* If the new channel has no callerid, try to guess what it should be */
4960 if (!ast_channel_caller(tmp->chan)->id.number.valid) {
4962 struct ast_party_caller caller;
4963
4965 caller.id = ast_channel_connected(qe->chan)->id;
4966 caller.ani = ast_channel_connected(qe->chan)->ani;
4967 ast_channel_set_caller_event(tmp->chan, &caller, NULL);
4968 } else if (!ast_strlen_zero(ast_channel_dialed(qe->chan)->number.str)) {
4970 } else if (!ast_strlen_zero(ast_channel_exten(qe->chan))) {
4972 }
4973 tmp->dial_callerid_absent = 1;
4974 }
4975
4977
4979
4981
4982 /* Inherit specially named variables from parent channel */
4986
4987 /* Presense of ADSI CPE on outgoing channel follows ours */
4989
4990 /* Inherit context and extension */
4991 ast_channel_dialcontext_set(tmp->chan, ast_channel_context(qe->chan));
4993
4994 /* Save the original channel name to detect call pickup masquerading in. */
4996
4999
5000 /* location is tmp->interface where tech/ has been stripped, so it follow the same syntax as DIALEDPEERNUMBER in app_dial.c */
5001 pbx_builtin_setvar_helper(tmp->chan, "DIALEDPEERNUMBER", strlen(location) ? location : tmp->interface);
5002
5003 /* PREDIAL: Run gosub on the callee's channel */
5004 if (qe->predial_callee) {
5005 ast_pre_call(tmp->chan, qe->predial_callee);
5006 }
5007
5008 /* Place the call, but don't wait on the answer */
5009 if ((res = ast_call(tmp->chan, location, 0))) {
5010 /* Again, keep going even if there's an error */
5011 ast_verb(3, "Couldn't call %s\n", tmp->interface);
5012 do_hang(tmp);
5013 ++*busies;
5014 return 0;
5015 }
5016
5017 ast_channel_lock_both(tmp->chan, qe->chan);
5018
5019 blob = ast_json_pack("{s: s, s: s, s: s}",
5020 "Queue", qe->parent->name,
5021 "Interface", tmp->interface,
5022 "MemberName", tmp->member->membername);
5023 queue_publish_multi_channel_blob(qe->chan, tmp->chan, queue_agent_called_type(), blob);
5024
5026
5029
5030 ast_verb(3, "Called %s\n", tmp->interface);
5031
5032 return 1;
5033}
static void do_hang(struct callattempt *o)
common hangup actions
Definition: app_queue.c:4778
static int can_ring_entry(struct queue_ent *qe, struct callattempt *call)
Definition: app_queue.c:4808
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:2471
static void publish_dial_end_event(struct ast_channel *in, struct callattempt *outgoing, struct ast_channel *exception, const char *status)
Definition: app_queue.c:4608
#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:6429
@ AST_CHANNEL_REQUESTOR_BRIDGE_PEER
Definition: channel.h:1525
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:7354
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:2979
int ast_channel_datastore_inherit(struct ast_channel *from, struct ast_channel *to)
Inherit datastores from a parent to a child.
Definition: channel.c:2338
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:1967
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:7316
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:6744
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:8307
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:6407
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:6412
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:6322
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:2103
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
char * str
Subscriber phone number (Malloced)
Definition: channel.h:388
struct ast_party_dialed::@213 number
Dialed/Called number.
int transit_network_select
Transit Network Select.
Definition: channel.h:399
unsigned int dial_callerid_absent
Definition: app_queue.c:1812
char interface[256]
Definition: app_queue.c:1802
int cancel_answered_elsewhere
Definition: app_queue.c:1847

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, callattempt::chan, queue_ent::chan, callattempt::dial_callerid_absent, do_hang(), ast_party_caller::id, ast_party_connected_line::id, callattempt::interface, queue_ent::linpos, callattempt::member, member::membername, call_queue::name, NULL, ast_party_id::number, ast_party_dialed::number, callattempt::orig_chan_name, 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, callattempt::stillgoing, ast_party_dialed::str, 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 5061 of file app_queue.c.

5062{
5063 int ret = 0;
5064 struct callattempt *cur;
5065
5066 if (qe->predial_callee) {
5068 for (cur = outgoing; cur; cur = cur->q_next) {
5069 if (cur->stillgoing && cur->chan) {
5071 }
5072 }
5073 }
5074
5075 while (ret == 0) {
5076 struct callattempt *best = find_best(outgoing);
5077 if (!best) {
5078 ast_debug(1, "Nobody left to try ringing in queue\n");
5079 break;
5080 }
5082 /* Ring everyone who shares this best metric (for ringall) */
5083 for (cur = outgoing; cur; cur = cur->q_next) {
5084 if (cur->stillgoing && !cur->chan && cur->metric <= best->metric) {
5085 ast_debug(1, "(Parallel) Trying '%s' with metric %d\n", cur->interface, cur->metric);
5086 ret |= ring_entry(qe, cur, busies);
5087 if (qe->predial_callee && cur->chan) {
5089 }
5090 }
5091 }
5092 } else {
5093 /* Ring just the best channel */
5094 ast_debug(1, "Trying '%s' with metric %d\n", best->interface, best->metric);
5095 ret = ring_entry(qe, best, busies);
5096 if (qe->predial_callee && best->chan) {
5098 }
5099 }
5100
5101 /* If we have timed out, break out */
5102 if (qe->expire && (time(NULL) >= qe->expire)) {
5103 ast_debug(1, "Queue timed out while ringing members.\n");
5104 ret = 0;
5105 break;
5106 }
5107 }
5108 if (qe->predial_callee) {
5109 for (cur = outgoing; cur; cur = cur->q_next) {
5110 if (cur->stillgoing && cur->chan) {
5112 }
5113 }
5115 }
5116
5117 return ret;
5118}
static int ring_entry(struct queue_ent *qe, struct callattempt *tmp, int *busies)
Part 2 of ring_one.
Definition: app_queue.c:4904
static struct callattempt * find_best(struct callattempt *outgoing)
find the entry with the best metric, or NULL
Definition: app_queue.c:5036
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

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

5262{
5263 RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
5264
5265 ast_verb(3, "Nobody picked up in %d ms\n", rnatime);
5266
5267 /* Stop ringing, and resume MOH if specified */
5268 if (qe->ring_when_ringing) {
5269 ast_indicate(qe->chan, -1);
5270 ast_moh_start(qe->chan, qe->moh, NULL);
5271 }
5272
5273 blob = ast_json_pack("{s: s, s: s, s: s, s: i}",
5274 "Queue", qe->parent->name,
5275 "Interface", interface,
5276 "MemberName", membername,
5277 "RingTime", rnatime);
5278 queue_publish_multi_channel_blob(qe->chan, peer, queue_agent_ringnoanswer_type(), blob);
5279
5280 ast_queue_log(qe->parent->name, ast_channel_uniqueid(qe->chan), membername, "RINGNOANSWER", "%d", rnatime);
5282 if (qe->parent->autopausedelay > 0) {
5283 struct member *mem;
5284 ao2_lock(qe->parent);
5285 if ((mem = interface_exists(qe->parent, interface))) {
5286 time_t idletime = time(&idletime)-mem->lastcall;
5287 if ((mem->lastcall != 0) && (qe->parent->autopausedelay > idletime)) {
5288 ao2_unlock(qe->parent);
5289 ao2_ref(mem, -1);
5290 return;
5291 }
5292 ao2_ref(mem, -1);
5293 }
5294 ao2_unlock(qe->parent);
5295 }
5296 if (qe->parent->autopause == QUEUE_AUTOPAUSE_ON) {
5297 if (!set_member_paused(qe->parent->name, interface, "Auto-Pause", 1)) {
5298 ast_verb(3, "Auto-Pausing Queue Member %s in queue %s since they failed to answer.\n",
5299 interface, qe->parent->name);
5300 } else {
5301 ast_verb(3, "Failed to pause Queue Member %s in queue %s!\n", interface, qe->parent->name);
5302 }
5303 } else {
5304 /* If queue autopause is mode all, just don't send any queue to stop.
5305 * the function will stop in all queues */
5306 if (!set_member_paused("", interface, "Auto-Pause", 1)) {
5307 ast_verb(3, "Auto-Pausing Queue Member %s in all queues since they failed to answer on queue %s.\n",
5308 interface, qe->parent->name);
5309 } else {
5310 ast_verb(3, "Failed to pause Queue Member %s in all queues!\n", interface);
5311 }
5312 }
5313 }
5314 return;
5315}

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

8448{
8449 int res=-1;
8450 char *parse, *temppos = NULL;
8451 struct member *mem = NULL;
8452
8454 AST_APP_ARG(queuename);
8456 );
8457
8458
8459 if (ast_strlen_zero(data)) {
8460 ast_log(LOG_WARNING, "RemoveQueueMember requires an argument (queuename[,interface])\n");
8461 return -1;
8462 }
8463
8464 parse = ast_strdupa(data);
8465
8467
8468 if (ast_strlen_zero(args.interface)) {
8469 args.interface = ast_strdupa(ast_channel_name(chan));
8470 temppos = strrchr(args.interface, '-');
8471 if (temppos) {
8472 *temppos = '\0';
8473 }
8474 }
8475
8476 ast_debug(1, "queue: %s, member: %s\n", args.queuename, args.interface);
8477
8479 mem = find_member_by_queuename_and_interface(args.queuename, args.interface);
8480 }
8481
8482 switch (remove_from_queue(args.queuename, args.interface)) {
8483 case RES_OKAY:
8484 if (!mem || ast_strlen_zero(mem->membername)) {
8485 ast_queue_log(args.queuename, ast_channel_uniqueid(chan), args.interface, "REMOVEMEMBER", "%s", "");
8486 } else {
8487 ast_queue_log(args.queuename, ast_channel_uniqueid(chan), mem->membername, "REMOVEMEMBER", "%s", "");
8488 }
8489 ast_log(LOG_NOTICE, "Removed interface '%s' from queue '%s'\n", args.interface, args.queuename);
8490 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "REMOVED");
8491 res = 0;
8492 break;
8493 case RES_EXISTS:
8494 ast_debug(1, "Unable to remove interface '%s' from queue '%s': Not there\n", args.interface, args.queuename);
8495 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOTINQUEUE");
8496 res = 0;
8497 break;
8498 case RES_NOSUCHQUEUE:
8499 ast_log(LOG_WARNING, "Unable to remove interface from queue '%s': No such queue\n", args.queuename);
8500 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOSUCHQUEUE");
8501 res = 0;
8502 break;
8503 case RES_NOT_DYNAMIC:
8504 ast_log(LOG_WARNING, "Unable to remove interface from queue '%s': '%s' is not a dynamic member\n", args.queuename, args.interface);
8505 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOTDYNAMIC");
8506 res = 0;
8507 break;
8508 }
8509
8510 if (mem) {
8511 ao2_ref(mem, -1);
8512 }
8513
8514 return res;
8515}

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

3730{
3731 struct member *m;
3732 struct ao2_iterator mem_iter;
3733 int penalty = 0;
3734 int paused = 0;
3735 int found = 0;
3736 int wrapuptime = 0;
3737 int ringinuse = q->ringinuse;
3738
3739 const char *config_val;
3740 const char *interface = ast_variable_retrieve(member_config, category, "interface");
3741 const char *rt_uniqueid = ast_variable_retrieve(member_config, category, "uniqueid");
3742 const char *membername = S_OR(ast_variable_retrieve(member_config, category, "membername"), interface);
3743 const char *state_interface = S_OR(ast_variable_retrieve(member_config, category, "state_interface"), interface);
3744 const char *penalty_str = ast_variable_retrieve(member_config, category, "penalty");
3745 const char *paused_str = ast_variable_retrieve(member_config, category, "paused");
3746 const char *wrapuptime_str = ast_variable_retrieve(member_config, category, "wrapuptime");
3747 const char *reason_paused = ast_variable_retrieve(member_config, category, "reason_paused");
3748
3749 if (ast_strlen_zero(rt_uniqueid)) {
3750 ast_log(LOG_WARNING, "Realtime field 'uniqueid' is empty for member %s\n",
3751 S_OR(membername, "NULL"));
3752 return;
3753 }
3754
3755 if (ast_strlen_zero(interface)) {
3756 ast_log(LOG_WARNING, "Realtime field 'interface' is empty for member %s\n",
3757 S_OR(membername, "NULL"));
3758 return;
3759 }
3760
3761 if (penalty_str) {
3762 penalty = atoi(penalty_str);
3763 if ((penalty < 0) && negative_penalty_invalid) {
3764 return;
3765 } else if (penalty < 0) {
3766 penalty = 0;
3767 }
3768 }
3769
3770 if (paused_str) {
3771 paused = atoi(paused_str);
3772 if (paused < 0) {
3773 paused = 0;
3774 }
3775 }
3776
3777 if (wrapuptime_str) {
3778 wrapuptime = atoi(wrapuptime_str);
3779 if (wrapuptime < 0) {
3780 wrapuptime = 0;
3781 }
3782 }
3783
3784 if ((config_val = ast_variable_retrieve(member_config, category, realtime_ringinuse_field))) {
3785 if (ast_true(config_val)) {
3786 ringinuse = 1;
3787 } else if (ast_false(config_val)) {
3788 ringinuse = 0;
3789 } else {
3790 ast_log(LOG_WARNING, "Invalid value of '%s' field for %s in queue '%s'\n", realtime_ringinuse_field, interface, q->name);
3791 }
3792 }
3793
3794 /* Find member by realtime uniqueid and update */
3795 mem_iter = ao2_iterator_init(q->members, 0);
3796 while ((m = ao2_iterator_next(&mem_iter))) {
3797 if (!strcasecmp(m->rt_uniqueid, rt_uniqueid)) {
3798 m->dead = 0; /* Do not delete this one. */
3799 ast_copy_string(m->rt_uniqueid, rt_uniqueid, sizeof(m->rt_uniqueid));
3800 if (paused_str) {
3801 m->paused = paused;
3802 if (paused && m->lastpause == 0) {
3803 time(&m->lastpause); /* XXX: Should this come from realtime? */
3804 }
3806 AST_DEVSTATE_CACHABLE, "Queue:%s_pause_%s", q->name, m->interface);
3807 }
3808 if (strcasecmp(state_interface, m->state_interface)) {
3809 ast_copy_string(m->state_interface, state_interface, sizeof(m->state_interface));
3810 }
3811 m->penalty = penalty;
3812 m->ringinuse = ringinuse;
3813 m->wrapuptime = wrapuptime;
3815 ast_copy_string(m->reason_paused, S_OR(reason_paused, ""), sizeof(m->reason_paused));
3816 }
3817 found = 1;
3818 ao2_ref(m, -1);
3819 break;
3820 }
3821 ao2_ref(m, -1);
3822 }
3823 ao2_iterator_destroy(&mem_iter);
3824
3825 /* Create a new member */
3826 if (!found) {
3827 if ((m = create_queue_member(interface, membername, penalty, paused, state_interface, ringinuse, wrapuptime))) {
3828 m->dead = 0;
3829 m->realtime = 1;
3830 ast_copy_string(m->rt_uniqueid, rt_uniqueid, sizeof(m->rt_uniqueid));
3831 if (!ast_strlen_zero(reason_paused)) {
3832 ast_copy_string(m->reason_paused, reason_paused, sizeof(m->reason_paused));
3833 }
3835 ast_queue_log(q->name, "REALTIME", m->interface, "ADDMEMBER", "%s", paused ? "PAUSED" : "");
3836 } else {
3837 ast_queue_log(q->name, "REALTIME", m->membername, "ADDMEMBER", "%s", paused ? "PAUSED" : "");
3838 }
3839 member_add_to_queue(q, m);
3840 ao2_ref(m, -1);
3841 m = NULL;
3842 }
3843 }
3844}

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

5170{
5171 int res = 0;
5172 time_t now;
5173
5174 /* Get the current time */
5175 time(&now);
5176
5177 /* Check to see if it is time to announce */
5179 return 0;
5180 }
5181
5182 /* Stop the music on hold so we can play our own file */
5183 if (ringing) {
5184 ast_indicate(qe->chan,-1);
5185 } else {
5186 ast_moh_stop(qe->chan);
5187 }
5188
5189 ast_verb(3, "Playing periodic announcement\n");
5190
5192 qe->last_periodic_announce_sound = ((unsigned long) ast_random()) % qe->parent->numperiodicannounce;
5196 }
5197
5198 /* play the announcement */
5200
5201 if (res > 0 && !valid_exit(qe, res)) {
5202 res = 0;
5203 }
5204
5205 /* Resume Music on Hold if the caller is going to stay in the queue */
5206 if (!res) {
5207 if (ringing) {
5209 } else {
5210 ast_moh_start(qe->chan, qe->moh, NULL);
5211 }
5212 }
5213
5214 /* update last_periodic_announce_time */
5216 time(&qe->last_periodic_announce_time);
5217 } else {
5219 }
5220
5221 /* Update the current periodic announcement to the next announcement */
5222 if (!qe->parent->randomperiodicannounce) {
5224 }
5225
5226 return res;
5227}
static int play_file(struct ast_channel *chan, const char *filename)
Definition: app_queue.c:4294
static int valid_exit(struct queue_ent *qe, char digit)
Check for valid exit from queue via goto.
Definition: app_queue.c:4323

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

4359{
4360 int res = 0, say_thanks = 0;
4361 long avgholdmins, avgholdsecs;
4362 time_t now;
4363
4364 /* Let minannouncefrequency seconds pass between the start of each position announcement */
4365 time(&now);
4366 if ((now - qe->last_pos) < qe->parent->minannouncefrequency) {
4367 return 0;
4368 }
4369
4370 /* If either our position has changed, or we are over the freq timer, say position */
4371 if ((qe->last_pos_said == qe->pos) && ((now - qe->last_pos) < qe->parent->announcefrequency)) {
4372 return 0;
4373 }
4374
4375 /* Only announce if the caller's queue position has improved since last time */
4376 if (qe->parent->announceposition_only_up && qe->last_pos_said > 0 && qe->last_pos_said <= qe->pos) {
4377 return 0;
4378 }
4379
4380 if (ringing) {
4381 ast_indicate(qe->chan,-1);
4382 } else {
4383 ast_moh_stop(qe->chan);
4384 }
4385
4389 qe->pos <= qe->parent->announcepositionlimit)) {
4390 say_thanks = 1;
4391 /* Say we're next, if we are */
4392 if (qe->pos == 1) {
4393 res = play_file(qe->chan, qe->parent->sound_next);
4394 if (!res) {
4395 goto posout;
4396 }
4397 /* Say there are more than N callers */
4399 res = (
4400 play_file(qe->chan, qe->parent->queue_quantity1) ||
4402 ast_channel_language(qe->chan), NULL) || /* Needs gender */
4404 /* Say there are currently N callers waiting */
4405 } else {
4406 res = (
4407 play_file(qe->chan, qe->parent->sound_thereare) ||
4409 ast_channel_language(qe->chan), "n") || /* Needs gender */
4410 play_file(qe->chan, qe->parent->sound_calls));
4411 }
4412 if (res) {
4413 goto playout;
4414 }
4415 }
4416 /* Round hold time to nearest minute */
4417 avgholdmins = labs(((qe->parent->holdtime + 30) - (now - qe->start)) / 60);
4418
4419 /* If they have specified a rounding then round the seconds as well */
4420 if (qe->parent->roundingseconds) {
4421 avgholdsecs = (labs(((qe->parent->holdtime + 30) - (now - qe->start))) - 60 * avgholdmins) / qe->parent->roundingseconds;
4422 avgholdsecs *= qe->parent->roundingseconds;
4423 } else {
4424 avgholdsecs = 0;
4425 }
4426
4427 ast_verb(3, "Hold time for %s is %ld minute(s) %ld seconds\n", qe->parent->name, avgholdmins, avgholdsecs);
4428
4429 /* If the hold time is >1 min, if it's enabled, and if it's not
4430 supposed to be only once and we have already said it, say it */
4431 if ((avgholdmins+avgholdsecs) > 0 && qe->parent->announceholdtime &&
4434 say_thanks = 1;
4435 res = play_file(qe->chan, qe->parent->sound_holdtime);
4436 if (res) {
4437 goto playout;
4438 }
4439
4440 if (avgholdmins >= 1) {
4441 res = ast_say_number(qe->chan, avgholdmins, AST_DIGIT_ANY, ast_channel_language(qe->chan), "n");
4442 if (res) {
4443 goto playout;
4444 }
4445
4446 if (avgholdmins == 1) {
4447 res = play_file(qe->chan, qe->parent->sound_minute);
4448 if (res) {
4449 goto playout;
4450 }
4451 } else {
4452 res = play_file(qe->chan, qe->parent->sound_minutes);
4453 if (res) {
4454 goto playout;
4455 }
4456 }
4457 }
4458 if (avgholdsecs >= 1) {
4459 res = ast_say_number(qe->chan, avgholdsecs, AST_DIGIT_ANY, ast_channel_language(qe->chan), "n");
4460 if (res) {
4461 goto playout;
4462 }
4463
4464 res = play_file(qe->chan, qe->parent->sound_seconds);
4465 if (res) {
4466 goto playout;
4467 }
4468 }
4469 }
4470
4471posout:
4472 if (qe->parent->announceposition) {
4473 ast_verb(3, "Told %s in %s their queue position (which was %d)\n",
4474 ast_channel_name(qe->chan), qe->parent->name, qe->pos);
4475 }
4476 if (say_thanks) {
4477 res = play_file(qe->chan, qe->parent->sound_thanks);
4478 }
4479playout:
4480
4481 if ((res > 0 && !valid_exit(qe, res))) {
4482 res = 0;
4483 }
4484
4485 /* Set our last_pos indicators */
4486 qe->last_pos = now;
4487 qe->last_pos_said = qe->pos;
4488
4489 /* Don't restart music on hold if we're about to exit the caller from the queue */
4490 if (!res) {
4491 if (ringing) {
4493 } else {
4494 ast_moh_start(qe->chan, qe->moh, NULL);
4495 }
4496 }
4497 return res;
4498}
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:8249
const ast_string_field sound_thereare
Definition: app_queue.c:1960
const ast_string_field sound_holdtime
Definition: app_queue.c:1960
const ast_string_field sound_seconds
Definition: app_queue.c:1960
const ast_string_field sound_thanks
Definition: app_queue.c:1960
const ast_string_field queue_quantity2
Definition: app_queue.c:1960
const ast_string_field sound_calls
Definition: app_queue.c:1960
const ast_string_field sound_minute
Definition: app_queue.c:1960
const ast_string_field sound_minutes
Definition: app_queue.c:1960
const ast_string_field queue_quantity1
Definition: app_queue.c:1960
const ast_string_field sound_next
Definition: app_queue.c:1960

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

6283{
6284 const char *reason = NULL; /* silence dumb compilers */
6285 RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
6286
6287 switch (rsn) {
6288 case CALLER:
6289 reason = "caller";
6290 break;
6291 case AGENT:
6292 reason = "agent";
6293 break;
6294 case TRANSFER:
6295 reason = "transfer";
6296 break;
6297 }
6298
6299 blob = ast_json_pack("{s: s, s: s, s: s, s: I, s: I, s: s}",
6300 "Queue", queuename,
6301 "Interface", member->interface,
6302 "MemberName", member->membername,
6303 "HoldTime", (ast_json_int_t)(callstart - holdstart),
6304 "TalkTime", (ast_json_int_t)(time(NULL) - callstart),
6305 "Reason", reason ?: "");
6306
6308 queue_agent_complete_type(), blob);
6309}
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 8016 of file app_queue.c.

8017{
8018 int found = 0;
8019 struct call_queue *q;
8020 struct ao2_iterator queue_iter;
8021
8022 if (ast_check_realtime("queues")) {
8023 load_realtime_queues(queuename);
8024 }
8025
8026 queue_iter = ao2_iterator_init(queues, 0);
8027 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate over queues"))) {
8028 ao2_lock(q);
8029 if (ast_strlen_zero(queuename) || !strcasecmp(q->name, queuename)) {
8030 struct member *mem;
8031
8032 if ((mem = interface_exists(q, interface))) {
8033 /*
8034 * Before we do the PAUSE/UNPAUSE, log if this was a
8035 * PAUSEALL/UNPAUSEALL but only on the first found entry.
8036 */
8037 ++found;
8038 if (found == 1
8039 && ast_strlen_zero(queuename)) {
8040 /*
8041 * XXX In all other cases, we use the queue name,
8042 * but since this affects all queues, we cannot.
8043 */
8044 ast_queue_log("NONE", "NONE", mem->membername,
8045 (paused ? "PAUSEALL" : "UNPAUSEALL"), "%s", S_OR(reason, ""));
8046 }
8047
8048 set_queue_member_pause(q, mem, reason, paused);
8049 ao2_ref(mem, -1);
8050 }
8051
8052 if (!ast_strlen_zero(queuename)) {
8053 ao2_unlock(q);
8054 queue_t_unref(q, "Done with iterator");
8055 break;
8056 }
8057 }
8058
8059 ao2_unlock(q);
8060 queue_t_unref(q, "Done with iterator");
8061 }
8062 ao2_iterator_destroy(&queue_iter);
8063
8064 return found ? RESULT_SUCCESS : RESULT_FAILURE;
8065}
static void set_queue_member_pause(struct call_queue *q, struct member *mem, const char *reason, int paused)
Definition: app_queue.c:7944

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

8077{
8078 struct member *mem;
8079 int foundinterface = 0;
8080
8081 ao2_lock(q);
8082 if ((mem = interface_exists(q, interface))) {
8083 foundinterface++;
8084 if (mem->realtime) {
8085 char rtpenalty[80];
8086
8087 sprintf(rtpenalty, "%i", penalty);
8088 update_realtime_member_field(mem, q->name, "penalty", rtpenalty);
8089 }
8090
8091 mem->penalty = penalty;
8092
8093 ast_queue_log(q->name, "NONE", interface, "PENALTY", "%d", penalty);
8094 queue_publish_member_blob(queue_member_penalty_type(), queue_member_blob_create(q, mem));
8095 ao2_ref(mem, -1);
8096 }
8097 ao2_unlock(q);
8098
8099 return foundinterface;
8100}

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

8126{
8127 struct member *mem;
8128 int foundinterface = 0;
8129
8130 ao2_lock(q);
8131 if ((mem = interface_exists(q, interface))) {
8132 foundinterface++;
8134 ao2_ref(mem, -1);
8135 }
8136 ao2_unlock(q);
8137
8138 return foundinterface;
8139}
static void set_queue_member_ringinuse(struct call_queue *q, struct member *mem, int ringinuse)
Definition: app_queue.c:8112

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

8165{
8166 int foundinterface = 0, foundqueue = 0;
8167 struct call_queue *q;
8168 struct ast_config *queue_config = NULL;
8169 struct ao2_iterator queue_iter;
8170
8171 /* property dependent restrictions on values should be checked in this switch */
8172 switch (property) {
8173 case MEMBER_PENALTY:
8174 if (value < 0 && !negative_penalty_invalid) {
8175 ast_log(LOG_ERROR, "Invalid penalty (%d)\n", value);
8176 return RESULT_FAILURE;
8177 }
8178 }
8179
8180 if (ast_strlen_zero(queuename)) { /* This means we need to iterate through all the queues. */
8181 if (ast_check_realtime("queues")) {
8182 queue_config = ast_load_realtime_multientry("queues", "name LIKE", "%", SENTINEL);
8183 if (queue_config) {
8184 char *category = NULL;
8185 while ((category = ast_category_browse(queue_config, category))) {
8186 const char *name = ast_variable_retrieve(queue_config, category, "name");
8187 if (ast_strlen_zero(name)) {
8188 ast_log(LOG_WARNING, "Ignoring realtime queue with a NULL or empty 'name.'\n");
8189 continue;
8190 }
8191 if ((q = find_load_queue_rt_friendly(name))) {
8192 foundqueue++;
8193 foundinterface += set_member_value_help_members(q, interface, property, value);
8194 queue_unref(q);
8195 }
8196 }
8197
8198 ast_config_destroy(queue_config);
8199 }
8200 }
8201
8202 /* After hitting realtime queues, go back and get the regular ones. */
8203 queue_iter = ao2_iterator_init(queues, 0);
8204 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
8205 foundqueue++;
8206 foundinterface += set_member_value_help_members(q, interface, property, value);
8207 queue_unref(q);
8208 }
8209 ao2_iterator_destroy(&queue_iter);
8210 } else { /* We actually have a queuename, so we can just act on the single queue. */
8211 if ((q = find_load_queue_rt_friendly(queuename))) {
8212 foundqueue++;
8213 foundinterface += set_member_value_help_members(q, interface, property, value);
8214 queue_unref(q);
8215 }
8216 }
8217
8218 if (foundinterface) {
8219 return RESULT_SUCCESS;
8220 } else if (!foundqueue) {
8221 ast_log (LOG_ERROR, "Invalid queuename\n");
8222 } else {
8223 ast_log (LOG_ERROR, "Invalid interface\n");
8224 }
8225
8226 return RESULT_FAILURE;
8227}
static int set_member_value_help_members(struct call_queue *q, const char *interface, int property, int value)
Definition: app_queue.c:8141

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

8142{
8143 switch(property) {
8144 case MEMBER_PENALTY:
8145 return set_member_penalty_help_members(q, interface, value);
8146
8147 case MEMBER_RINGINUSE:
8148 return set_member_ringinuse_help_members(q, interface, value);
8149
8150 default:
8151 ast_log(LOG_ERROR, "Attempted to set invalid property\n");
8152 return 0;
8153 }
8154}
static int set_member_ringinuse_help_members(struct call_queue *q, const char *interface, int ringinuse)
Definition: app_queue.c:8125
static int set_member_penalty_help_members(struct call_queue *q, const char *interface, int penalty)
Definition: app_queue.c:8076

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

7945{
7946 if (mem->paused == paused) {
7947 ast_debug(1, "%spausing already-%spaused queue member %s:%s\n",
7948 (paused ? "" : "un"), (paused ? "" : "un"), q->name, mem->interface);
7949 if (log_unpause_on_reason_change && paused) {
7950 if (!ast_strings_equal(mem->reason_paused, reason)) {
7951 ast_queue_log(q->name, "NONE", mem->membername, "UNPAUSE", "%s", "Auto-Unpause");
7952 }
7953 }
7954 }
7955
7956 if (mem->realtime && !ast_strlen_zero(mem->rt_uniqueid)) {
7958 if (ast_update_realtime("queue_members", "uniqueid", mem->rt_uniqueid, "reason_paused", S_OR(reason, ""), "paused", paused ? "1" : "0", SENTINEL) < 0) {
7959 ast_log(LOG_WARNING, "Failed update of realtime queue member %s:%s %spause and reason '%s'\n",
7960 q->name, mem->interface, (paused ? "" : "un"), S_OR(reason, ""));
7961 }
7962 } else {
7963 if (ast_update_realtime("queue_members", "uniqueid", mem->rt_uniqueid, "paused", paused ? "1" : "0", SENTINEL) < 0) {
7964 ast_log(LOG_WARNING, "Failed %spause update of realtime queue member %s:%s\n",
7965 (paused ? "" : "un"), q->name, mem->interface);
7966 }
7967 }
7968 }
7969
7970 mem->paused = paused;
7971 if (paused) {
7972 time(&mem->lastpause); /* update last pause field */
7973 }
7974 if (paused && !ast_strlen_zero(reason)) {
7975 ast_copy_string(mem->reason_paused, reason, sizeof(mem->reason_paused));
7976 } else {
7977 /* We end up filling this in again later (temporarily) but we need it
7978 * empty for now so that the intervening code - specifically
7979 * dump_queue_members() - has the correct view of things. */
7980 mem->reason_paused[0] = '\0';
7981 }
7982
7984 AST_DEVSTATE_CACHABLE, "Queue:%s_pause_%s", q->name, mem->interface);
7985
7988 }
7989
7990 if (is_member_available(q, mem)) {
7992 "Queue:%s_avail", q->name);
7993 } else if (!num_available_members(q)) {
7995 "Queue:%s_avail", q->name);
7996 }
7997
7998 if (!paused && !ast_strlen_zero(reason)) {
7999 /* Because we've been unpaused with a 'reason' we need to ensure that
8000 * that reason is emitted when the subsequent PauseQueueMember event
8001 * is raised. So temporarily set it on the member and clear it out
8002 * again right after. */
8003 ast_copy_string(mem->reason_paused, reason, sizeof(mem->reason_paused));
8004 }
8005
8006 ast_queue_log(q->name, "NONE", mem->membername, paused ? "PAUSE" : "UNPAUSE",
8007 "%s", mem->reason_paused);
8008
8010
8011 if (!paused) {
8012 mem->reason_paused[0] = '\0';
8013 }
8014}
static int publish_queue_member_pause(struct call_queue *q, struct member *member)
Definition: app_queue.c:7920
int ast_update_realtime(const char *family, const char *keyfield, const char *lookup,...) attribute_sentinel
Update realtime configuration.
Definition: main/config.c:3926
int ast_strings_equal(const char *str1, const char *str2)
Compare strings for equality checking for NULL.
Definition: strings.c:238

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_strings_equal(), ast_strlen_zero(), ast_update_realtime(), dump_queue_members(), member::interface, is_member_available(), member::lastpause, log_unpause_on_reason_change, 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 8112 of file app_queue.c.

8113{
8114 if (mem->realtime) {
8116 ringinuse ? "1" : "0");
8117 }
8118
8119 mem->ringinuse = ringinuse;
8120
8121 ast_queue_log(q->name, "NONE", mem->interface, "RINGINUSE", "%d", ringinuse);
8122 queue_publish_member_blob(queue_member_ringinuse_type(), queue_member_blob_create(q, mem));
8123}

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

2042{
2043 int i;
2044
2045 for (i = 0; i < ARRAY_LEN(queue_results); i++) {
2046 if (queue_results[i].id == res) {
2047 pbx_builtin_setvar_helper(chan, "QUEUESTATUS", queue_results[i].text);
2048 return;
2049 }
2050 }
2051}
static const struct @50 queue_results[]
char * text
Definition: app_queue.c:1768

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

2195{
2196 char interfacevar[256]="";
2197 float sl = 0;
2198
2199 ao2_lock(q);
2200
2201 if (q->setqueuevar) {
2202 sl = 0;
2203 if (q->callscompleted > 0) {
2204 sl = 100 * ((float) q->callscompletedinsl / (float) q->callscompleted);
2205 }
2206
2207 snprintf(interfacevar, sizeof(interfacevar),
2208 "QUEUENAME=%s,QUEUEMAX=%d,QUEUESTRATEGY=%s,QUEUECALLS=%d,QUEUEHOLDTIME=%d,QUEUETALKTIME=%d,QUEUECOMPLETED=%d,QUEUEABANDONED=%d,QUEUESRVLEVEL=%d,QUEUESRVLEVELPERF=%2.1f",
2210
2211 ao2_unlock(q);
2212
2213 pbx_builtin_setvar_multiple(chan, interfacevar);
2214 } else {
2215 ao2_unlock(q);
2216 }
2217}

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

7065{
7066 char escaped_filename[256];
7067 char file_with_ext[sizeof(escaped_filename) + sizeof(qe->parent->monfmt)];
7068 char mixmonargs[1512];
7069 char escaped_monitor_exec[1024];
7070 const char *monitor_options;
7071 const char *monitor_exec;
7072
7073 escaped_monitor_exec[0] = '\0';
7074
7075 if (filename) {
7076 escape_and_substitute(qe->chan, filename, escaped_filename, sizeof(escaped_filename));
7077 } else {
7078 ast_copy_string(escaped_filename, ast_channel_uniqueid(qe->chan), sizeof(escaped_filename));
7079 }
7080
7082 if ((monitor_exec = pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC"))) {
7083 monitor_exec = ast_strdupa(monitor_exec);
7084 }
7085 if ((monitor_options = pbx_builtin_getvar_helper(qe->chan, "MONITOR_OPTIONS"))) {
7086 monitor_options = ast_strdupa(monitor_options);
7087 } else {
7088 monitor_options = "";
7089 }
7091
7092 if (monitor_exec) {
7093 escape_and_substitute(qe->chan, monitor_exec, escaped_monitor_exec, sizeof(escaped_monitor_exec));
7094 }
7095
7096 snprintf(file_with_ext, sizeof(file_with_ext), "%s.%s", escaped_filename, qe->parent->monfmt);
7097
7098 if (!ast_strlen_zero(escaped_monitor_exec)) {
7099 snprintf(mixmonargs, sizeof(mixmonargs), "b%s,%s", monitor_options, escaped_monitor_exec);
7100 } else {
7101 snprintf(mixmonargs, sizeof(mixmonargs), "b%s", monitor_options);
7102 }
7103
7104 ast_debug(1, "Arguments being passed to MixMonitor: %s,%s\n", file_with_ext, mixmonargs);
7105
7106 if (ast_start_mixmonitor(qe->chan, file_with_ext, mixmonargs)) {
7107 ast_log(LOG_WARNING, "Unable to start mixmonitor. Is the MixMonitor app loaded?\n");
7108 }
7109}
static void escape_and_substitute(struct ast_channel *chan, const char *input, char *output, size_t size)
Definition: app_queue.c:7033
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 7016 of file app_queue.c.

7017{
7018 const char *context;
7019 const char *extension;
7020 int priority;
7021
7022 if (ast_test_flag(opts, OPT_CALLEE_GO_ON)) {
7023 ast_channel_lock(chan);
7027 ast_channel_unlock(chan);
7029 opt_args[OPT_ARG_CALLEE_GO_ON]);
7030 }
7031}
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 6932 of file app_queue.c.

6934{
6935 struct queue_stasis_data *queue_data = queue_stasis_data_alloc(qe, peer, mem, holdstart, starttime, callcompletedinsl);
6936
6937 if (!queue_data) {
6938 return -1;
6939 }
6940
6942 if (!queue_data->bridge_router) {
6943 ao2_ref(queue_data, -1);
6944 return -1;
6945 }
6946
6948 handle_bridge_enter, queue_data);
6950 handle_blind_transfer, queue_data);
6952 handle_attended_transfer, queue_data);
6954 queue_bridge_cb, queue_data);
6955
6957 if (!queue_data->channel_router) {
6958 /* Unsubscribing from the bridge router will remove the only ref of queue_data,
6959 * thus beginning the destruction process
6960 */
6962 queue_data->bridge_router = NULL;
6963 return -1;
6964 }
6965
6966 ao2_ref(queue_data, +1);
6970 handle_local_optimization_end, queue_data);
6972 handle_hangup, queue_data);
6974 handle_masquerade, queue_data);
6976 queue_channel_cb, queue_data);
6977
6978 return 0;
6979}
static void handle_bridge_enter(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Definition: app_queue.c:6527
static void queue_bridge_cb(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Definition: app_queue.c:6674
static void handle_attended_transfer(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Handle an attended transfer event.
Definition: app_queue.c:6619
static void handle_masquerade(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Definition: app_queue.c:6873
static void handle_local_optimization_begin(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Definition: app_queue.c:6693
static void handle_local_optimization_end(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Definition: app_queue.c:6752
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:6442
static void queue_channel_cb(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Definition: app_queue.c:6907
static void handle_hangup(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Definition: app_queue.c:6816
static void handle_blind_transfer(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Handle a blind transfer event.
Definition: app_queue.c:6560
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 5145 of file app_queue.c.

5146{
5147 struct callattempt *best = find_best(outgoing);
5148
5149 if (best) {
5150 /* Ring just the best channel */
5151 ast_debug(1, "Next is '%s' with metric %d\n", best->interface, best->metric);
5152 qe->linpos = best->metric % 1000;
5153 } else {
5154 /* Just increment rrpos */
5155 if (qe->linwrapped) {
5156 /* No more channels, start over */
5157 qe->linpos = 0;
5158 } else {
5159 /* Prioritize next entry */
5160 qe->linpos++;
5161 }
5162 }
5163 qe->linwrapped = 0;
5164
5165 return 0;
5166}

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

5122{
5123 struct callattempt *best = find_best(outgoing);
5124
5125 if (best) {
5126 /* Ring just the best channel */
5127 ast_debug(1, "Next is '%s' with metric %d\n", best->interface, best->metric);
5128 qe->parent->rrpos = best->metric % 1000;
5129 } else {
5130 /* Just increment rrpos */
5131 if (qe->parent->wrapped) {
5132 /* No more channels, start over */
5133 qe->parent->rrpos = 0;
5134 } else {
5135 /* Prioritize next entry */
5136 qe->parent->rrpos++;
5137 }
5138 }
5139 qe->parent->wrapped = 0;
5140
5141 return 0;
5142}

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

2067{
2068 int x;
2069
2070 for (x = 0; x < ARRAY_LEN(strategies); x++) {
2071 if (!strcasecmp(strategy, strategies[x].name)) {
2072 return strategies[x].strategy;
2073 }
2074 }
2075
2076 return -1;
2077}
int strategy
Definition: app_queue.c:1653

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

7138{
7139 struct member *cur;
7140 struct callattempt *outgoing = NULL; /* the list of calls we are building */
7141 int to, orig;
7142 char oldexten[AST_MAX_EXTENSION]="";
7143 char oldcontext[AST_MAX_CONTEXT]="";
7144 char queuename[256]="";
7145 struct ast_channel *peer;
7146 struct callattempt *lpeer;
7147 struct member *member;
7148 struct ast_app *application;
7149 int res = 0, bridge = 0;
7150 int numbusies = 0;
7151 int x=0;
7152 char *announce = NULL;
7153 char digit = 0;
7154 time_t now = time(NULL);
7155 struct ast_bridge_config bridge_config;
7156 char nondataquality = 1;
7157 char *agiexec = NULL;
7158 char *gosubexec = NULL;
7159 const char *monitorfilename;
7160 int forwardsallowed = 1;
7161 int block_connected_line = 0;
7162 struct ao2_iterator memi;
7164 int callcompletedinsl;
7165 time_t starttime;
7166
7167 memset(&bridge_config, 0, sizeof(bridge_config));
7168 time(&now);
7169
7170 /* If we've already exceeded our timeout, then just stop
7171 * This should be extremely rare. queue_exec will take care
7172 * of removing the caller and reporting the timeout as the reason.
7173 */
7174 if (qe->expire && now >= qe->expire) {
7175 res = 0;
7176 goto out;
7177 }
7178
7179 if (ast_test_flag(&opts, OPT_CALLEE_TRANSFER)) {
7180 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_REDIRECT);
7181 }
7182 if (ast_test_flag(&opts, OPT_CALLER_TRANSFER)) {
7183 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_REDIRECT);
7184 }
7185 if (ast_test_flag(&opts, OPT_CALLEE_AUTOMON)) {
7186 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_AUTOMON);
7187 }
7188 if (ast_test_flag(&opts, OPT_CALLER_AUTOMON)) {
7189 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_AUTOMON);
7190 }
7191 if (ast_test_flag(&opts, OPT_DATA_QUALITY)) {
7192 nondataquality = 0;
7193 }
7194 if (ast_test_flag(&opts, OPT_CALLEE_HANGUP)) {
7195 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_DISCONNECT);
7196 }
7197 if (ast_test_flag(&opts, OPT_CALLER_HANGUP)) {
7198 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT);
7199 }
7200 if (ast_test_flag(&opts, OPT_CALLEE_PARK)) {
7201 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_PARKCALL);
7202 }
7203 if (ast_test_flag(&opts, OPT_CALLER_PARK)) {
7204 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_PARKCALL);
7205 }
7206 if (ast_test_flag(&opts, OPT_NO_RETRY)) {
7209 (*tries)++;
7210 } else {
7211 *tries = ao2_container_count(qe->parent->members);
7212 }
7213 *noption = 1;
7214 }
7215 if (ast_test_flag(&opts, OPT_IGNORE_CALL_FW)) {
7216 forwardsallowed = 0;
7217 }
7219 block_connected_line = 1;
7220 }
7222 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_AUTOMIXMON);
7223 }
7225 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_AUTOMIXMON);
7226 }
7227 if (ast_test_flag(&opts, OPT_MARK_AS_ANSWERED)) {
7229 }
7230
7231 /* if the calling channel has AST_CAUSE_ANSWERED_ELSEWHERE set, make sure this is inherited.
7232 (this is mainly to support unreal/local channels)
7233 */
7236 }
7237
7238 ao2_lock(qe->parent);
7239 ast_debug(1, "%s is trying to call a queue member.\n",
7240 ast_channel_name(qe->chan));
7241 ast_copy_string(queuename, qe->parent->name, sizeof(queuename));
7242 if (!ast_strlen_zero(qe->announce)) {
7243 announce = qe->announce;
7244 }
7245 if (!ast_strlen_zero(announceoverride)) {
7246 announce = announceoverride;
7247 }
7248
7249 memi = ao2_iterator_init(qe->parent->members, 0);
7250 while ((cur = ao2_iterator_next(&memi))) {
7251 struct callattempt *tmp = ast_calloc(1, sizeof(*tmp));
7252 if (!tmp) {
7253 ao2_ref(cur, -1);
7254 ao2_iterator_destroy(&memi);
7255 ao2_unlock(qe->parent);
7256 goto out;
7257 }
7258
7259 /*
7260 * Seed the callattempt's connected line information with previously
7261 * acquired connected line info from the queued channel. The
7262 * previously acquired connected line info could have been set
7263 * through the CONNECTED_LINE dialplan function.
7264 */
7268
7269 tmp->block_connected_update = block_connected_line;
7270 tmp->stillgoing = 1;
7271 tmp->member = cur; /* Place the reference for cur into callattempt. */
7272 ast_copy_string(tmp->interface, cur->interface, sizeof(tmp->interface));
7273 /* Calculate the metric for the appropriate strategy. */
7274 if (!calc_metric(qe->parent, cur, x++, qe, tmp)) {
7275 /* Put them in the list of outgoing thingies... We're ready now.
7276 XXX If we're forcibly removed, these outgoing calls won't get
7277 hung up XXX */
7278 tmp->q_next = outgoing;
7279 outgoing = tmp;
7280 } else {
7281 callattempt_free(tmp);
7282 }
7283 }
7284 ao2_iterator_destroy(&memi);
7285
7287 /* Application arguments have higher timeout priority (behaviour for <=1.6) */
7288 if (qe->expire && (!qe->parent->timeout || (qe->expire - now) <= qe->parent->timeout)) {
7289 to = (qe->expire - now) * 1000;
7290 } else {
7291 to = (qe->parent->timeout) ? qe->parent->timeout * 1000 : -1;
7292 }
7293 } else {
7294 /* Config timeout is higher priority thatn application timeout */
7295 if (qe->expire && qe->expire<=now) {
7296 to = 0;
7297 } else if (qe->parent->timeout) {
7298 to = qe->parent->timeout * 1000;
7299 } else {
7300 to = -1;
7301 }
7302 }
7303 orig = to;
7304 ++qe->pending;
7305 ao2_unlock(qe->parent);
7306 /* Call the queue members with the best metric now. */
7307 ring_one(qe, outgoing, &numbusies);
7308 lpeer = wait_for_answer(qe, outgoing, &to, &digit, numbusies,
7309 ast_test_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT),
7310 forwardsallowed);
7311
7312 ao2_lock(qe->parent);
7315
7316 }
7319 }
7320 ao2_unlock(qe->parent);
7321 peer = lpeer ? lpeer->chan : NULL;
7322 if (!peer) {
7323 qe->pending = 0;
7324 if (to) {
7325 /* Must gotten hung up */
7326 res = -1;
7327 } else {
7328 /* User exited by pressing a digit */
7329 res = digit;
7330 }
7331 if (res == -1) {
7332 ast_debug(1, "%s: Nobody answered.\n", ast_channel_name(qe->chan));
7333 }
7334 } else { /* peer is valid */
7335 RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
7336 RAII_VAR(struct ast_str *, interfacevar, ast_str_create(325), ast_free);
7337 /* Ah ha! Someone answered within the desired timeframe. Of course after this
7338 we will always return with -1 so that it is hung up properly after the
7339 conversation. */
7340 if (!strcmp(ast_channel_tech(qe->chan)->type, "DAHDI")) {
7341 ast_channel_setoption(qe->chan, AST_OPTION_TONE_VERIFY, &nondataquality, sizeof(nondataquality), 0);
7342 }
7343 if (!strcmp(ast_channel_tech(peer)->type, "DAHDI")) {
7344 ast_channel_setoption(peer, AST_OPTION_TONE_VERIFY, &nondataquality, sizeof(nondataquality), 0);
7345 }
7346 /* Update parameters for the queue */
7347 time(&now);
7348 recalc_holdtime(qe, (now - qe->start));
7349 member = lpeer->member;
7350 ao2_lock(qe->parent);
7351 callcompletedinsl = member->callcompletedinsl = ((now - qe->start) <= qe->parent->servicelevel);
7352 ao2_unlock(qe->parent);
7353 /* Increment the refcount for this member, since we're going to be using it for awhile in here. */
7354 ao2_ref(member, 1);
7356 outgoing = NULL;
7357 if (announce || qe->parent->reportholdtime || qe->parent->memberdelay) {
7358 int res2;
7359
7360 res2 = ast_autoservice_start(qe->chan);
7361 if (!res2) {
7362 if (qe->parent->memberdelay) {
7363 ast_log(LOG_NOTICE, "Delaying member connect for %d seconds\n", qe->parent->memberdelay);
7364 res2 = ast_safe_sleep(peer, qe->parent->memberdelay * 1000);
7365 }
7366 if (!res2 && announce) {
7367 char *front;
7368 char *announcefiles = ast_strdupa(announce);
7369 while ((front = ast_strsep(&announcefiles, '&', AST_STRSEP_STRIP | AST_STRSEP_TRIM))) {
7370 if (play_file(peer, front) < 0) {
7371 ast_log(LOG_ERROR, "play_file failed for '%s' on %s\n", front, ast_channel_name(peer));
7372 }
7373 }
7374 }
7375 if (!res2 && qe->parent->reportholdtime) {
7376 if (!play_file(peer, qe->parent->sound_reporthold)) {
7377 long holdtime, holdtimesecs;
7378
7379 time(&now);
7380 holdtime = labs((now - qe->start) / 60);
7381 holdtimesecs = labs((now - qe->start) % 60);
7382 if (holdtime > 0) {
7383 ast_say_number(peer, holdtime, AST_DIGIT_ANY, ast_channel_language(peer), "n");
7384 if (play_file(peer, qe->parent->sound_minutes) < 0) {
7385 ast_log(LOG_ERROR, "play_file failed for '%s' on %s\n", qe->parent->sound_minutes, ast_channel_name(peer));
7386 }
7387 }
7388 if (holdtimesecs > 1) {
7389 ast_say_number(peer, holdtimesecs, AST_DIGIT_ANY, ast_channel_language(peer), "n");
7390 if (play_file(peer, qe->parent->sound_seconds) < 0) {
7391 ast_log(LOG_ERROR, "play_file failed for '%s' on %s\n", qe->parent->sound_seconds, ast_channel_name(peer));
7392 }
7393 }
7394 }
7395 }
7397 }
7398 if (ast_check_hangup(peer)) {
7399 /* Agent must have hung up */
7400 ast_log(LOG_WARNING, "Agent on %s hungup on the customer.\n", ast_channel_name(peer));
7401 ast_queue_log(queuename, ast_channel_uniqueid(qe->chan), member->membername, "AGENTDUMP", "%s", "");
7402
7403 blob = ast_json_pack("{s: s, s: s, s: s}",
7404 "Queue", queuename,
7405 "Interface", member->interface,
7406 "MemberName", member->membername);
7407 queue_publish_multi_channel_blob(qe->chan, peer, queue_agent_dump_type(), blob);
7408
7412 ao2_ref(member, -1);
7413 goto out;
7414 } else if (ast_check_hangup(qe->chan)) {
7415 /* Caller must have hung up just before being connected */
7416 ast_log(LOG_NOTICE, "Caller was about to talk to agent on %s but the caller hungup.\n", ast_channel_name(peer));
7417 ast_queue_log(queuename, ast_channel_uniqueid(qe->chan), member->membername, "ABANDON", "%d|%d|%ld", qe->pos, qe->opos, (long) (time(NULL) - qe->start));
7418 record_abandoned(qe);
7419 qe->handled = -1;
7423 ao2_ref(member, -1);
7424 return -1;
7425 }
7426 }
7427 /* Stop music on hold */
7428 if (ringing) {
7429 ast_indicate(qe->chan,-1);
7430 } else {
7431 ast_moh_stop(qe->chan);
7432 }
7433
7434 /* Make sure channels are compatible */
7435 res = ast_channel_make_compatible(qe->chan, peer);
7436 if (res < 0) {
7437 ast_queue_log(queuename, ast_channel_uniqueid(qe->chan), member->membername, "SYSCOMPAT", "%s", "");
7438 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));
7439 record_abandoned(qe);
7443 ao2_ref(member, -1);
7444 return -1;
7445 }
7446
7447 /* Play announcement to the caller telling it's his turn if defined */
7449 if (play_file(qe->chan, qe->parent->sound_callerannounce)) {
7450 ast_log(LOG_WARNING, "Announcement file '%s' is unavailable, continuing anyway...\n", qe->parent->sound_callerannounce);
7451 }
7452 }
7453
7454 ao2_lock(qe->parent);
7455 /* if setinterfacevar is defined, make member variables available to the channel */
7456 /* use pbx_builtin_setvar to set a load of variables with one call */
7457 if (qe->parent->setinterfacevar && interfacevar) {
7458 ast_str_set(&interfacevar, 0, "MEMBERINTERFACE=%s,MEMBERNAME=%s,MEMBERCALLS=%d,MEMBERLASTCALL=%ld,MEMBERPENALTY=%d,MEMBERDYNAMIC=%d,MEMBERREALTIME=%d",
7461 pbx_builtin_setvar_multiple(peer, ast_str_buffer(interfacevar));
7462 }
7463
7464 /* if setqueueentryvar is defined, make queue entry (i.e. the caller) variables available to the channel */
7465 /* use pbx_builtin_setvar to set a load of variables with one call */
7466 if (qe->parent->setqueueentryvar && interfacevar) {
7467 ast_str_set(&interfacevar, 0, "QEHOLDTIME=%ld,QEORIGINALPOS=%d",
7468 (long) (time(NULL) - qe->start), qe->opos);
7470 pbx_builtin_setvar_multiple(peer, ast_str_buffer(interfacevar));
7471 }
7472
7473 ao2_unlock(qe->parent);
7474
7475 /* try to set queue variables if configured to do so*/
7477 set_queue_variables(qe->parent, peer);
7478
7479 setup_peer_after_bridge_goto(qe->chan, peer, &opts, opt_args);
7481 if ((monitorfilename = pbx_builtin_getvar_helper(qe->chan, "MONITOR_FILENAME"))) {
7482 monitorfilename = ast_strdupa(monitorfilename);
7483 }
7485
7486 /* Begin Monitoring */
7487 if (*qe->parent->monfmt) {
7488 setup_mixmonitor(qe, monitorfilename);
7489 }
7490 /* Drop out of the queue at this point, to prepare for next caller */
7491 leave_queue(qe);
7493 ast_debug(1, "app_queue: sendurl=%s.\n", url);
7494 ast_channel_sendurl(peer, url);
7495 }
7496
7497 /* run a gosub for this connection if defined. The gosub simply returns, no action is taken on the result */
7498 /* use gosub from dialplan if passed as a option, otherwise use the default queue gosub */
7499 if (!ast_strlen_zero(gosub)) {
7500 gosubexec = ast_strdupa(gosub);
7501 } else {
7502 if (qe->parent->membergosub) {
7503 gosubexec = ast_strdupa(qe->parent->membergosub);
7504 }
7505 }
7506
7507 if (!ast_strlen_zero(gosubexec)) {
7508 char *gosub_args = NULL;
7509 char *gosub_argstart;
7510
7511 ast_debug(1, "app_queue: gosub=%s.\n", gosubexec);
7512
7513 gosub_argstart = strchr(gosubexec, ',');
7514 if (gosub_argstart) {
7515 const char *what_is_s = "s";
7516 *gosub_argstart = 0;
7517 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)) &&
7518 ast_exists_extension(peer, gosubexec, "~~s~~", 1, S_COR(ast_channel_caller(peer)->id.number.valid, ast_channel_caller(peer)->id.number.str, NULL))) {
7519 what_is_s = "~~s~~";
7520 }
7521 if (ast_asprintf(&gosub_args, "%s,%s,1(%s)", gosubexec, what_is_s, gosub_argstart + 1) < 0) {
7522 gosub_args = NULL;
7523 }
7524 *gosub_argstart = ',';
7525 } else {
7526 const char *what_is_s = "s";
7527 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)) &&
7528 ast_exists_extension(peer, gosubexec, "~~s~~", 1, S_COR(ast_channel_caller(peer)->id.number.valid, ast_channel_caller(peer)->id.number.str, NULL))) {
7529 what_is_s = "~~s~~";
7530 }
7531 if (ast_asprintf(&gosub_args, "%s,%s,1", gosubexec, what_is_s) < 0) {
7532 gosub_args = NULL;
7533 }
7534 }
7535 if (gosub_args) {
7536 ast_app_exec_sub(qe->chan, peer, gosub_args, 0);
7537 ast_free(gosub_args);
7538 } else {
7539 ast_log(LOG_ERROR, "Could not Allocate string for Gosub arguments -- Gosub Call Aborted!\n");
7540 }
7541 }
7542
7543 if (!ast_strlen_zero(agi)) {
7544 ast_debug(1, "app_queue: agi=%s.\n", agi);
7545 application = pbx_findapp("agi");
7546 if (application) {
7547 agiexec = ast_strdupa(agi);
7548 pbx_exec(qe->chan, application, agiexec);
7549 } else {
7550 ast_log(LOG_WARNING, "Asked to execute an AGI on this channel, but could not find application (agi)!\n");
7551 }
7552 }
7553 qe->handled++;
7554
7555 ast_queue_log(queuename, ast_channel_uniqueid(qe->chan), member->membername, "CONNECT", "%ld|%s|%ld", (long) (time(NULL) - qe->start), ast_channel_uniqueid(peer),
7556 (long)(orig - to > 0 ? (orig - to) / 1000 : 0));
7557
7558 blob = ast_json_pack("{s: s, s: s, s: s, s: I, s: I}",
7559 "Queue", queuename,
7560 "Interface", member->interface,
7561 "MemberName", member->membername,
7562 "HoldTime", (ast_json_int_t)(time(NULL) - qe->start),
7563 "RingTime", (ast_json_int_t)(orig - to > 0 ? (orig - to) / 1000 : 0));
7564 queue_publish_multi_channel_blob(qe->chan, peer, queue_agent_connect_type(), blob);
7565
7566 ast_copy_string(oldcontext, ast_channel_context(qe->chan), sizeof(oldcontext));
7567 ast_copy_string(oldexten, ast_channel_exten(qe->chan), sizeof(oldexten));
7568
7569 if ((queue_end_bridge = ao2_alloc(sizeof(*queue_end_bridge), NULL))) {
7570 queue_end_bridge->q = qe->parent;
7571 queue_end_bridge->chan = qe->chan;
7572 bridge_config.end_bridge_callback = end_bridge_callback;
7573 bridge_config.end_bridge_callback_data = queue_end_bridge;
7574 bridge_config.end_bridge_callback_data_fixup = end_bridge_callback_data_fixup;
7575 /* Since queue_end_bridge can survive beyond the life of this call to Queue, we need
7576 * to make sure to increase the refcount of this queue so it cannot be freed until we
7577 * are done with it. We remove this reference in end_bridge_callback.
7578 */
7579 queue_t_ref(qe->parent, "For bridge_config reference");
7580 }
7581
7582 ao2_lock(qe->parent);
7583 time(&member->starttime);
7584 starttime = member->starttime;
7585 ao2_unlock(qe->parent);
7586 /* As a queue member may end up in multiple calls at once if a transfer occurs with
7587 * a Local channel in the mix we pass the current call information (starttime) to the
7588 * Stasis subscriptions so when they update the queue member data it becomes a noop
7589 * if this call is no longer between the caller and the queue member.
7590 */
7591 setup_stasis_subs(qe, peer, member, qe->start, starttime, callcompletedinsl);
7592 bridge = ast_bridge_call_with_flags(qe->chan, peer, &bridge_config,
7594
7595 res = bridge ? bridge : 1;
7596 ao2_ref(member, -1);
7597 }
7598out:
7600
7601 return res;
7602}
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:6932
static void setup_mixmonitor(struct queue_ent *qe, const char *filename)
Definition: app_queue.c:7064
static void recalc_holdtime(struct queue_ent *qe, int newholdtime)
Definition: app_queue.c:4500
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:4620
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:6195
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:5145
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:5356
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:5121
static void end_bridge_callback(void *data)
Definition: app_queue.c:6993
static void end_bridge_callback_data_fixup(struct ast_bridge_config *bconfig, struct ast_channel *originator, struct ast_channel *terminator)
Definition: app_queue.c:6986
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:7016
static int ring_one(struct queue_ent *qe, struct callattempt *outgoing, int *busies)
Place a call to a queue member.
Definition: app_queue.c:5061
#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:6688
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:1999
@ 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
int ast_channel_supports_html(struct ast_channel *channel)
Checks for HTML support on a channel.
Definition: channel.c:6591
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:6603
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:7404
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:1542
#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:604
#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:4196
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:1871
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:1960
const ast_string_field sound_reporthold
Definition: app_queue.c:1960
const ast_string_field membergosub
Definition: app_queue.c:1960
unsigned int block_connected_update
Definition: app_queue.c:1810

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, callattempt::block_connected_update, calc_metric(), callattempt_free(), member::callcompletedinsl, member::calls, queue_ent::cancel_answered_elsewhere, callattempt::chan, queue_ent::chan, queue_end_bridge::chan, callattempt::connected, 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(), callattempt::interface, 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, callattempt::q_next, 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, callattempt::stillgoing, store_next_lin(), store_next_rr(), call_queue::strategy, call_queue::timeout, TIMEOUT_PRIORITY_APP, call_queue::timeoutpriority, 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 11876 of file app_queue.c.

11877{
11880
11882
11883 STASIS_MESSAGE_TYPE_CLEANUP(queue_caller_join_type);
11884 STASIS_MESSAGE_TYPE_CLEANUP(queue_caller_leave_type);
11885 STASIS_MESSAGE_TYPE_CLEANUP(queue_caller_abandon_type);
11886
11887 STASIS_MESSAGE_TYPE_CLEANUP(queue_member_status_type);
11888 STASIS_MESSAGE_TYPE_CLEANUP(queue_member_added_type);
11889 STASIS_MESSAGE_TYPE_CLEANUP(queue_member_removed_type);
11890 STASIS_MESSAGE_TYPE_CLEANUP(queue_member_pause_type);
11891 STASIS_MESSAGE_TYPE_CLEANUP(queue_member_penalty_type);
11892 STASIS_MESSAGE_TYPE_CLEANUP(queue_member_ringinuse_type);
11893
11894 STASIS_MESSAGE_TYPE_CLEANUP(queue_agent_called_type);
11895 STASIS_MESSAGE_TYPE_CLEANUP(queue_agent_connect_type);
11896 STASIS_MESSAGE_TYPE_CLEANUP(queue_agent_complete_type);
11897 STASIS_MESSAGE_TYPE_CLEANUP(queue_agent_dump_type);
11898 STASIS_MESSAGE_TYPE_CLEANUP(queue_agent_ringnoanswer_type);
11899
11901 ast_manager_unregister("QueueStatus");
11902 ast_manager_unregister("QueueRule");
11903 ast_manager_unregister("QueueSummary");
11904 ast_manager_unregister("QueueAdd");
11905 ast_manager_unregister("QueueRemove");
11906 ast_manager_unregister("QueuePause");
11907 ast_manager_unregister("QueueLog");
11908 ast_manager_unregister("QueueUpdate");
11909 ast_manager_unregister("QueuePenalty");
11910 ast_manager_unregister("QueueReload");
11911 ast_manager_unregister("QueueReset");
11912 ast_manager_unregister("QueueMemberRingInUse");
11913 ast_manager_unregister("QueueChangePriorityCaller");
11914 ast_manager_unregister("QueueWithdrawCaller");
11929
11931
11932 ast_unload_realtime("queue_members");
11935
11936 queues = NULL;
11937 return 0;
11938}
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:7698
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:1615
struct stasis_subscription * stasis_unsubscribe_and_join(struct stasis_subscription *subscription)
Cancel a subscription, blocking until the last message is processed.
Definition: stasis.c:1201
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_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 5326 of file app_queue.c.

5327{
5328 struct ast_party_connected_line connected_caller;
5329
5330 ast_party_connected_line_init(&connected_caller);
5331
5332 ast_channel_lock(peer);
5334 ast_channel_unlock(peer);
5335 connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
5336 if (ast_channel_connected_line_sub(peer, chan, &connected_caller, 0)) {
5337 ast_channel_update_connected_line(chan, &connected_caller, NULL);
5338 }
5339 ast_party_connected_line_free(&connected_caller);
5340}
@ 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:10352
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:9107
void ast_party_connected_line_init(struct ast_party_connected_line *init)
Initialize the given connected line structure.
Definition: channel.c:1990
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 5945 of file app_queue.c.

5946{
5947 int max_penalty = INT_MAX;
5948
5949 if (qe->max_penalty != INT_MAX) {
5950 char max_penalty_str[20];
5951
5952 if (qe->pr->max_relative) {
5953 max_penalty = qe->max_penalty + qe->pr->max_value;
5954 } else {
5955 max_penalty = qe->pr->max_value;
5956 }
5957
5958 /* a relative change to the penalty could put it below 0 */
5959 if (max_penalty < 0) {
5960 max_penalty = 0;
5961 }
5962
5963 snprintf(max_penalty_str, sizeof(max_penalty_str), "%d", max_penalty);
5964 pbx_builtin_setvar_helper(qe->chan, "QUEUE_MAX_PENALTY", max_penalty_str);
5965 qe->max_penalty = max_penalty;
5966 ast_debug(3, "Setting max penalty to %d for caller %s since %d seconds have elapsed\n",
5967 qe->max_penalty, ast_channel_name(qe->chan), qe->pr->time);
5968 }
5969
5970 if (qe->min_penalty != INT_MAX) {
5971 char min_penalty_str[20];
5972 int min_penalty;
5973
5974 if (qe->pr->min_relative) {
5975 min_penalty = qe->min_penalty + qe->pr->min_value;
5976 } else {
5977 min_penalty = qe->pr->min_value;
5978 }
5979
5980 /* a relative change to the penalty could put it below 0 */
5981 if (min_penalty < 0) {
5982 min_penalty = 0;
5983 }
5984
5985 if (max_penalty != INT_MAX && min_penalty > max_penalty) {
5986 min_penalty = max_penalty;
5987 }
5988
5989 snprintf(min_penalty_str, sizeof(min_penalty_str), "%d", min_penalty);
5990 pbx_builtin_setvar_helper(qe->chan, "QUEUE_MIN_PENALTY", min_penalty_str);
5991 qe->min_penalty = min_penalty;
5992 ast_debug(3, "Setting min penalty to %d for caller %s since %d seconds have elapsed\n",
5993 qe->min_penalty, ast_channel_name(qe->chan), qe->pr->time);
5994 }
5995
5996 if (qe->raise_penalty != INT_MAX) {
5997 char raise_penalty_str[20];
5998 int raise_penalty;
5999
6000 if (qe->pr->raise_relative) {
6001 raise_penalty = qe->raise_penalty + qe->pr->raise_value;
6002 } else {
6003 raise_penalty = qe->pr->raise_value;
6004 }
6005
6006 /* a relative change to the penalty could put it below 0 */
6007 if (raise_penalty < 0) {
6008 raise_penalty = 0;
6009 }
6010
6011 if (max_penalty != INT_MAX && raise_penalty > max_penalty) {
6012 raise_penalty = max_penalty;
6013 }
6014
6015 snprintf(raise_penalty_str, sizeof(raise_penalty_str), "%d", raise_penalty);
6016 pbx_builtin_setvar_helper(qe->chan, "QUEUE_RAISE_PENALTY", raise_penalty_str);
6017 qe->raise_penalty = raise_penalty;
6018 ast_debug(3, "Setting raised penalty to %d for caller %s since %d seconds have elapsed\n",
6019 qe->raise_penalty, ast_channel_name(qe->chan), qe->pr->time);
6020 }
6021
6022 qe->pr = AST_LIST_NEXT(qe->pr, list);
6023}
#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 6123 of file app_queue.c.

6124{
6125 int oldtalktime;
6126 int newtalktime = time(NULL) - starttime;
6127 struct member *mem;
6128 struct call_queue *qtmp;
6129 struct ao2_iterator queue_iter;
6130
6131 /* It is possible for us to be called when a call has already been considered terminated
6132 * and data updated, so to ensure we only act on the call that the agent is currently in
6133 * we check when the call was bridged.
6134 */
6135 if (!starttime || (member->starttime != starttime)) {
6136 return 0;
6137 }
6138
6139 if (shared_lastcall) {
6140 queue_iter = ao2_iterator_init(queues, 0);
6141 while ((qtmp = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
6142 ao2_lock(qtmp);
6143 if ((mem = ao2_find(qtmp->members, member, OBJ_POINTER))) {
6144 time(&mem->lastcall);
6145 mem->calls++;
6146 mem->callcompletedinsl = 0;
6147 mem->starttime = 0;
6148 mem->lastqueue = q;
6149 ao2_ref(mem, -1);
6150 }
6151 ao2_unlock(qtmp);
6152 queue_t_unref(qtmp, "Done with iterator");
6153 }
6154 ao2_iterator_destroy(&queue_iter);
6155 } else {
6156 ao2_lock(q);
6157 time(&member->lastcall);
6159 member->calls++;
6160 member->starttime = 0;
6161 member->lastqueue = q;
6162 ao2_unlock(q);
6163 }
6164 /* Member might never experience any direct status change (local
6165 * channel with forwarding in particular). If that's the case,
6166 * this is the last chance to remove it from pending or subsequent
6167 * calls will not occur.
6168 */
6170
6171 ao2_lock(q);
6172 q->callscompleted++;
6173 if (callcompletedinsl) {
6174 q->callscompletedinsl++;
6175 }
6176 if (q->callscompleted == 1) {
6177 q->talktime = newtalktime;
6178 } else {
6179 /* Calculate talktime using the same exponential average as holdtime code */
6180 oldtalktime = q->talktime;
6181 q->talktime = (((oldtalktime << 2) - oldtalktime) + newtalktime) >> 2;
6182 }
6183 ao2_unlock(q);
6184 return 0;
6185}

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

4136{
4137 int ret = -1;
4138
4139 if (ast_strlen_zero(mem->rt_uniqueid)) {
4140 return ret;
4141 }
4142
4143 if ((ast_update_realtime("queue_members", "uniqueid", mem->rt_uniqueid, field, value, SENTINEL)) >= 0) {
4144 ret = 0;
4145 }
4146
4147 return ret;
4148}

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

4152{
4153 struct ast_config *member_config = NULL;
4154 struct member *m;
4155 char *category = NULL;
4156 struct ao2_iterator mem_iter;
4157
4158 if (!(member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name", q->name , SENTINEL))) {
4159 /* This queue doesn't have realtime members. If the queue still has any realtime
4160 * members in memory, they need to be removed.
4161 */
4162 ao2_lock(q);
4163 mem_iter = ao2_iterator_init(q->members, 0);
4164 while ((m = ao2_iterator_next(&mem_iter))) {
4165 if (m->realtime) {
4167 }
4168 ao2_ref(m, -1);
4169 }
4170 ao2_iterator_destroy(&mem_iter);
4171 ast_debug(3, "Queue %s has no realtime members defined. No need for update\n", q->name);
4172 ao2_unlock(q);
4173 return;
4174 }
4175
4176 ao2_lock(q);
4177
4178 /* Temporarily set realtime members dead so we can detect deleted ones.*/
4179 mem_iter = ao2_iterator_init(q->members, 0);
4180 while ((m = ao2_iterator_next(&mem_iter))) {
4181 if (m->realtime) {
4182 m->dead = 1;
4183 }
4184 ao2_ref(m, -1);
4185 }
4186 ao2_iterator_destroy(&mem_iter);
4187
4188 while ((category = ast_category_browse(member_config, category))) {
4189 rt_handle_member_record(q, category, member_config);
4190 }
4191
4192 /* Delete all realtime members that have been deleted in DB. */
4193 mem_iter = ao2_iterator_init(q->members, 0);
4194 while ((m = ao2_iterator_next(&mem_iter))) {
4195 if (m->dead) {
4197 ast_queue_log(q->name, "REALTIME", m->interface, "REMOVEMEMBER", "%s", "");
4198 } else {
4199 ast_queue_log(q->name, "REALTIME", m->membername, "REMOVEMEMBER", "%s", "");
4200 }
4202 }
4203 ao2_ref(m, -1);
4204 }
4205 ao2_iterator_destroy(&mem_iter);
4206 ao2_unlock(q);
4207 ast_config_destroy(member_config);
4208}

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

2712{
2713 if (m->status != status) {
2714 /* If this member has transitioned to being available then update their queue
2715 * information. If they are currently in a call then the leg to the agent will be
2716 * considered done and the call finished.
2717 */
2720 }
2721
2722 m->status = status;
2723
2724 /* Remove the member from the pending members pool only when the status changes.
2725 * This is not done unconditionally because we can occasionally see multiple
2726 * device state notifications of not in use after a previous call has ended,
2727 * including after we have initiated a new call. This is more likely to
2728 * happen when there is latency in the connection to the member.
2729 */
2731
2732 queue_publish_member_blob(queue_member_status_type(), queue_member_blob_create(q, m));
2733 }
2734}

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

8412{
8413 char *parse;
8415 AST_APP_ARG(queuename);
8416 AST_APP_ARG(interface);
8418 AST_APP_ARG(reason);
8419 );
8420
8421 if (ast_strlen_zero(data)) {
8422 ast_log(LOG_WARNING, "UnpauseQueueMember requires an argument ([queuename],interface[,options[,reason]])\n");
8423 return -1;
8424 }
8425
8426 parse = ast_strdupa(data);
8427
8429
8430 if (ast_strlen_zero(args.interface)) {
8431 ast_log(LOG_WARNING, "Missing interface argument to UnpauseQueueMember ([queuename],interface[,options[,reason]])\n");
8432 return -1;
8433 }
8434
8435 if (set_member_paused(args.queuename, args.interface, args.reason, 0)) {
8436 ast_log(LOG_WARNING, "Attempt to unpause interface %s, not found\n", args.interface);
8437 pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "NOTFOUND");
8438 return 0;
8439 }
8440
8441 pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "UNPAUSED");
8442
8443 return 0;
8444}

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

4324{
4325 int digitlen = strlen(qe->digits);
4326
4327 /* Prevent possible buffer overflow */
4328 if (digitlen < sizeof(qe->digits) - 2) {
4329 qe->digits[digitlen] = digit;
4330 qe->digits[digitlen + 1] = '\0';
4331 } else {
4332 qe->digits[0] = '\0';
4333 return 0;
4334 }
4335
4336 /* If there's no context to goto, short-circuit */
4337 if (ast_strlen_zero(qe->context)) {
4338 return 0;
4339 }
4340
4341 /* If the extension is bad, then reset the digits to blank */
4342 if (!ast_canmatch_extension(qe->chan, qe->context, qe->digits, 1,
4344 qe->digits[0] = '\0';
4345 return 0;
4346 }
4347
4348 /* We have an exact match */
4349 if (!ast_goto_if_exists(qe->chan, qe->context, qe->digits, 1)) {
4350 qe->valid_digits = 1;
4351 /* Return 1 on a successful goto */
4352 return 1;
4353 }
4354
4355 return 0;
4356}
int ast_goto_if_exists(struct ast_channel *chan, const char *context, const char *exten, int priority)
Definition: pbx.c:8806
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:4211

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

7605{
7606 /* Don't need to hold the lock while we setup the outgoing calls */
7607 int retrywait = qe->parent->retry * 1000;
7608
7609 int res = ast_waitfordigit(qe->chan, retrywait);
7610 if (res > 0 && !valid_exit(qe, res)) {
7611 res = 0;
7612 }
7613
7614 return res;
7615}
int ast_waitfordigit(struct ast_channel *c, int ms)
Waits for a digit.
Definition: channel.c:3145

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

5357{
5358 const char *queue = qe->parent->name;
5359 struct callattempt *o, *start = NULL, *prev = NULL;
5360 int status;
5361 int numbusies = prebusies;
5362 int numnochan = 0;
5363 int stillgoing = 0;
5364 int orig = *to;
5365 struct ast_frame *f;
5366 struct callattempt *peer = NULL;
5367 struct ast_channel *winner;
5368 struct ast_channel *in = qe->chan;
5369 char on[80] = "";
5370 char membername[80] = "";
5371 long starttime = 0;
5372 long endtime = 0;
5373 char *inchan_name;
5374 struct timeval start_time_tv = ast_tvnow();
5375 int canceled_by_caller = 0; /* 1 when caller hangs up or press digit or press * */
5376
5378 inchan_name = ast_strdupa(ast_channel_name(qe->chan));
5380
5381 starttime = (long) time(NULL);
5382
5383 while ((*to = ast_remaining_ms(start_time_tv, orig)) && !peer) {
5384 int numlines, retry, pos = 1;
5385 struct ast_channel *watchers[AST_MAX_WATCHERS];
5386 watchers[0] = in;
5387 start = NULL;
5388
5389 for (retry = 0; retry < 2; retry++) {
5390 numlines = 0;
5391 for (o = outgoing; o; o = o->q_next) { /* Keep track of important channels */
5392 if (o->stillgoing) { /* Keep track of important channels */
5393 stillgoing = 1;
5394 if (o->chan) {
5395 if (pos < AST_MAX_WATCHERS) {
5396 watchers[pos++] = o->chan;
5397 }
5398 if (!start) {
5399 start = o;
5400 } else {
5401 prev->call_next = o;
5402 }
5403 prev = o;
5404 }
5405 } else if (prev) {
5406 prev->call_next = NULL;
5407 }
5408 numlines++;
5409 }
5410 if (pos > 1 /* found */ || !stillgoing /* nobody listening */ ||
5411 (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) /* ring would not be delivered */) {
5412 break;
5413 }
5414 /* On "ringall" strategy we only move to the next penalty level
5415 when *all* ringing phones are done in the current penalty level */
5416 ring_one(qe, outgoing, &numbusies);
5417 /* and retry... */
5418 }
5419 if (pos == 1 /* not found */) {
5420 if (numlines == (numbusies + numnochan)) {
5421 ast_debug(1, "Everyone is busy at this time\n");
5422 } else {
5423 ast_debug(3, "No one is answering queue '%s' (%d numlines / %d busies / %d failed channels)\n", queue, numlines, numbusies, numnochan);
5424 }
5425 *to = 0;
5426 return NULL;
5427 }
5428
5429 /* Poll for events from both the incoming channel as well as any outgoing channels */
5430 winner = ast_waitfor_n(watchers, pos, to);
5431
5432 /* Service all of the outgoing channels */
5433 for (o = start; o; o = o->call_next) {
5434 /* We go with a fixed buffer here instead of using ast_strdupa. Using
5435 * ast_strdupa in a loop like this one can cause a stack overflow
5436 */
5437 char ochan_name[AST_CHANNEL_NAME];
5438
5439 if (o->chan) {
5441 ast_copy_string(ochan_name, ast_channel_name(o->chan), sizeof(ochan_name));
5443 }
5444 if (o->stillgoing && (o->chan) && (ast_channel_state(o->chan) == AST_STATE_UP)) {
5445 if (!peer) {
5446 ast_verb(3, "%s answered %s\n", ochan_name, inchan_name);
5447 if (o->orig_chan_name
5448 && strcmp(o->orig_chan_name, ochan_name)) {
5449 /*
5450 * The channel name changed so we must generate COLP update.
5451 * Likely because a call pickup channel masqueraded in.
5452 */
5454 } else if (!o->block_connected_update) {
5455 if (o->pending_connected_update) {
5458 }
5459 } else if (!o->dial_callerid_absent) {
5461 }
5462 }
5463 if (o->aoc_s_rate_list) {
5464 size_t encoded_size;
5465 struct ast_aoc_encoded *encoded;
5466 if ((encoded = ast_aoc_encode(o->aoc_s_rate_list, &encoded_size, o->chan))) {
5467 ast_indicate_data(in, AST_CONTROL_AOC, encoded, encoded_size);
5468 ast_aoc_destroy_encoded(encoded);
5469 }
5470 }
5471 peer = o;
5472 }
5473 } else if (o->chan && (o->chan == winner)) {
5474
5475 ast_copy_string(on, o->member->interface, sizeof(on));
5476 ast_copy_string(membername, o->member->membername, sizeof(membername));
5477
5478 /* Before processing channel, go ahead and check for forwarding */
5479 if (!ast_strlen_zero(ast_channel_call_forward(o->chan)) && !forwardsallowed) {
5480 ast_verb(3, "Forwarding %s to '%s' prevented.\n", inchan_name, ast_channel_call_forward(o->chan));
5482 "CANCEL", ast_channel_call_forward(o->chan));
5483 numnochan++;
5484 do_hang(o);
5485 winner = NULL;
5486 continue;
5488 struct ast_channel *original = o->chan;
5489 char forwarder[AST_CHANNEL_NAME];
5490 char tmpchan[256];
5491 char *stuff;
5492 char *tech;
5493 int failed = 0;
5494
5495 ast_copy_string(tmpchan, ast_channel_call_forward(o->chan), sizeof(tmpchan));
5496 ast_copy_string(forwarder, ast_channel_name(o->chan), sizeof(forwarder));
5497 if ((stuff = strchr(tmpchan, '/'))) {
5498 *stuff++ = '\0';
5499 tech = tmpchan;
5500 } else {
5501 const char *forward_context;
5503 forward_context = pbx_builtin_getvar_helper(o->chan, "FORWARD_CONTEXT");
5504 snprintf(tmpchan, sizeof(tmpchan), "%s@%s", ast_channel_call_forward(o->chan), forward_context ? forward_context : ast_channel_context(o->chan));
5506 stuff = tmpchan;
5507 tech = "Local";
5508 }
5509 if (!strcasecmp(tech, "Local")) {
5510 /*
5511 * Drop the connected line update block for local channels since
5512 * this is going to run dialplan and the user can change his
5513 * mind about what connected line information he wants to send.
5514 */
5516 }
5517
5518 ast_verb(3, "Now forwarding %s to '%s/%s' (thanks to %s)\n", inchan_name, tech, stuff, ochan_name);
5519 /* Setup parameters */
5521 if (!o->chan) {
5523 "Forwarding failed to create channel to dial '%s/%s'\n",
5524 tech, stuff);
5525 o->stillgoing = 0;
5526 numnochan++;
5527 } else {
5528 ast_channel_lock_both(o->chan, original);
5530 ast_channel_redirecting(original));
5532 ast_channel_unlock(original);
5533
5537 pbx_builtin_setvar_helper(o->chan, "FORWARDERNAME", forwarder);
5539
5540 if (o->pending_connected_update) {
5541 /*
5542 * Re-seed the callattempt's connected line information with
5543 * previously acquired connected line info from the queued
5544 * channel. The previously acquired connected line info could
5545 * have been set through the CONNECTED_LINE dialplan function.
5546 */
5549 }
5550
5553
5555
5558 /*
5559 * The call was not previously redirected so it is
5560 * now redirected from this number.
5561 */
5567 }
5568
5570
5575
5578 && !o->block_connected_update) {
5579 struct ast_party_redirecting redirecting;
5580
5581 /*
5582 * Redirecting updates to the caller make sense only on single
5583 * call at a time strategies.
5584 *
5585 * Need to re-evaluate if calling unlock is still required as we no longer
5586 * use macro.
5587 */
5588 ast_party_redirecting_init(&redirecting);
5591 if (ast_channel_redirecting_sub(o->chan, in, &redirecting, 0)) {
5592 ast_channel_update_redirecting(in, &redirecting, NULL);
5593 }
5594 ast_party_redirecting_free(&redirecting);
5595 } else {
5597 }
5598
5599 if (ast_call(o->chan, stuff, 0)) {
5600 ast_log(LOG_NOTICE, "Forwarding failed to dial '%s/%s'\n",
5601 tech, stuff);
5602 failed = 1;
5603 }
5604 }
5605
5607 "CANCEL", ast_channel_call_forward(original));
5608 if (o->chan) {
5609 ast_channel_publish_dial(qe->chan, o->chan, stuff, NULL);
5610 }
5611
5612 if (failed) {
5613 do_hang(o);
5614 numnochan++;
5615 }
5616
5617 /* Hangup the original channel now, in case we needed it */
5618 ast_hangup(winner);
5619 continue;
5620 }
5621 f = ast_read(winner);
5622 if (f) {
5623 if (f->frametype == AST_FRAME_CONTROL) {
5624 switch (f->subclass.integer) {
5625 case AST_CONTROL_ANSWER:
5626 /* This is our guy if someone answered. */
5627 if (!peer) {
5628 ast_verb(3, "%s answered %s\n", ochan_name, inchan_name);
5629 ast_channel_publish_dial(qe->chan, o->chan, on, "ANSWER");
5630 publish_dial_end_event(qe->chan, outgoing, o->chan, "CANCEL");
5631 if (o->orig_chan_name
5632 && strcmp(o->orig_chan_name, ochan_name)) {
5633 /*
5634 * The channel name changed so we must generate COLP update.
5635 * Likely because a call pickup channel masqueraded in.
5636 */
5638 } else if (!o->block_connected_update) {
5639 if (o->pending_connected_update) {
5642 }
5643 } else if (!o->dial_callerid_absent) {
5645 }
5646 }
5647 if (o->aoc_s_rate_list) {
5648 size_t encoded_size;
5649 struct ast_aoc_encoded *encoded;
5650 if ((encoded = ast_aoc_encode(o->aoc_s_rate_list, &encoded_size, o->chan))) {
5651 ast_indicate_data(in, AST_CONTROL_AOC, encoded, encoded_size);
5652 ast_aoc_destroy_encoded(encoded);
5653 }
5654 }
5655 peer = o;
5656 }
5657 break;
5658 case AST_CONTROL_BUSY:
5659 ast_verb(3, "%s is busy\n", ochan_name);
5660 ast_channel_publish_dial(qe->chan, o->chan, on, "BUSY");
5661 endtime = (long) time(NULL);
5662 endtime -= starttime;
5663 rna(endtime * 1000, qe, o->chan, on, membername, qe->parent->autopausebusy);
5664 do_hang(o);
5666 if (qe->parent->timeoutrestart) {
5667 start_time_tv = ast_tvnow();
5668 }
5669 /* Have enough time for a queue member to answer? */
5670 if (ast_remaining_ms(start_time_tv, orig) > 500) {
5671 ring_one(qe, outgoing, &numbusies);
5672 starttime = (long) time(NULL);
5673 }
5674 }
5675 numbusies++;
5676 break;
5678 ast_verb(3, "%s is circuit-busy\n", ochan_name);
5679 ast_channel_publish_dial(qe->chan, o->chan, on, "CONGESTION");
5680 endtime = (long) time(NULL);
5681 endtime -= starttime;
5682 rna(endtime * 1000, qe, o->chan, on, membername, qe->parent->autopauseunavail);
5683 do_hang(o);
5685 if (qe->parent->timeoutrestart) {
5686 start_time_tv = ast_tvnow();
5687 }
5688 if (ast_remaining_ms(start_time_tv, orig) > 500) {
5689 ring_one(qe, outgoing, &numbusies);
5690 starttime = (long) time(NULL);
5691 }
5692 }
5693 numbusies++;
5694 break;
5696 ast_verb(3, "%s is ringing\n", ochan_name);
5697
5698 ast_channel_publish_dial(qe->chan, o->chan, on, "RINGING");
5699
5700 /* Start ring indication when the channel is ringing, if specified */
5701 if (qe->ring_when_ringing) {
5702 ast_moh_stop(qe->chan);
5704 }
5705 break;
5707 /* Ignore going off hook */
5708 break;
5710 if (o->block_connected_update) {
5711 ast_verb(3, "Connected line update to %s prevented.\n", inchan_name);
5712 break;
5713 }
5716
5717 ast_verb(3, "%s connected line has changed. Saving it until answer for %s\n", ochan_name, inchan_name);
5723 break;
5724 }
5725
5726 /*
5727 * Prevent using the CallerID from the outgoing channel since we
5728 * got a connected line update from it.
5729 */
5730 o->dial_callerid_absent = 1;
5731
5732 if (ast_channel_connected_line_sub(o->chan, in, f, 1)) {
5734 }
5735 break;
5736 case AST_CONTROL_AOC:
5737 {
5738 struct ast_aoc_decoded *decoded = ast_aoc_decode(f->data.ptr, f->datalen, o->chan);
5739 if (decoded && (ast_aoc_get_msg_type(decoded) == AST_AOC_S)) {
5741 o->aoc_s_rate_list = decoded;
5742 } else {
5743 ast_aoc_destroy_decoded(decoded);
5744 }
5745 }
5746 break;
5749 /*
5750 * Redirecting updates to the caller make sense only on single
5751 * call at a time strategies.
5752 */
5753 break;
5754 }
5755 if (o->block_connected_update) {
5756 ast_verb(3, "Redirecting update to %s prevented\n",
5757 inchan_name);
5758 break;
5759 }
5760 ast_verb(3, "%s redirecting info has changed, passing it to %s\n",
5761 ochan_name, inchan_name);
5762 if (ast_channel_redirecting_sub(o->chan, in, f, 1)) {
5764 }
5765 break;
5768 break;
5769 default:
5770 ast_debug(1, "Dunno what to do with control type %d\n", f->subclass.integer);
5771 break;
5772 }
5773 }
5774 ast_frfree(f);
5775 } else { /* ast_read() returned NULL */
5776 endtime = (long) time(NULL) - starttime;
5777 ast_channel_publish_dial(qe->chan, o->chan, on, "NOANSWER");
5778 rna(endtime * 1000, qe, o->chan, on, membername, 1);
5779 do_hang(o);
5781 if (qe->parent->timeoutrestart) {
5782 start_time_tv = ast_tvnow();
5783 }
5784 if (ast_remaining_ms(start_time_tv, orig) > 500) {
5785 ring_one(qe, outgoing, &numbusies);
5786 starttime = (long) time(NULL);
5787 }
5788 }
5789 }
5790 }
5791 }
5792
5793 /* If we received an event from the caller, deal with it. */
5794 if (winner == in) {
5795 f = ast_read(in);
5796 if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass.integer == AST_CONTROL_HANGUP))) {
5797 /* Got hung up */
5798 *to = -1;
5799 if (f) {
5800 if (f->data.uint32) {
5802 }
5803 ast_frfree(f);
5804 }
5805 canceled_by_caller = 1;
5806 } else if ((f->frametype == AST_FRAME_DTMF) && caller_disconnect && (f->subclass.integer == '*')) {
5807 ast_verb(3, "User hit %c to disconnect call.\n", f->subclass.integer);
5808 *to = 0;
5809 ast_frfree(f);
5810 canceled_by_caller = 1;
5811 } else if ((f->frametype == AST_FRAME_DTMF) && valid_exit(qe, f->subclass.integer)) {
5812 ast_verb(3, "User pressed digit: %c\n", f->subclass.integer);
5813 *to = 0;
5814 *digit = f->subclass.integer;
5815 ast_frfree(f);
5816 canceled_by_caller = 1;
5817 }
5818 /* When caller hung up or pressed * or digit. */
5819 if (canceled_by_caller) {
5821 for (o = start; o; o = o->call_next) {
5822 if (o->chan) {
5823 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));
5824 }
5825 }
5826 return NULL;
5827 }
5828
5829 /* Send the frame from the in channel to all outgoing channels. */
5830 for (o = start; o; o = o->call_next) {
5831 if (!o->stillgoing || !o->chan) {
5832 /* This outgoing channel has died so don't send the frame to it. */
5833 continue;
5834 }
5835 switch (f->frametype) {
5836 case AST_FRAME_CONTROL:
5837 switch (f->subclass.integer) {
5839 if (o->block_connected_update) {
5840 ast_verb(3, "Connected line update to %s prevented.\n", ast_channel_name(o->chan));
5841 break;
5842 }
5843 if (ast_channel_connected_line_sub(in, o->chan, f, 1)) {
5845 }
5846 break;
5848 if (o->block_connected_update) {
5849 ast_verb(3, "Redirecting update to %s prevented.\n", ast_channel_name(o->chan));
5850 break;
5851 }
5852 if (ast_channel_redirecting_sub(in, o->chan, f, 1)) {
5854 }
5855 break;
5856 default:
5857 /* We are not going to do anything with this frame. */
5858 goto skip_frame;
5859 }
5860 break;
5861 default:
5862 /* We are not going to do anything with this frame. */
5863 goto skip_frame;
5864 }
5865 }
5866skip_frame:;
5867
5868 ast_frfree(f);
5869 }
5870 }
5871
5872 if (!*to) {
5873 for (o = start; o; o = o->call_next) {
5874 if (o->chan) {
5875 rna(orig, qe, o->chan, o->interface, o->member->membername, 1);
5876 }
5877 }
5878
5879 publish_dial_end_event(qe->chan, outgoing, NULL, "NOANSWER");
5880 }
5881
5882 return peer;
5883}
void * ast_aoc_destroy_encoded(struct ast_aoc_encoded *encoded)
free an ast_aoc_encoded object
Definition: aoc.c:322
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:901
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:458
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:659
@ AST_AOC_S
Definition: aoc.h:64
#define AST_MAX_WATCHERS
Definition: app_queue.c:5342
static void update_connected_line_from_peer(struct ast_channel *chan, struct ast_channel *peer, int is_caller)
Definition: app_queue.c:5326
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:5261
void ast_party_redirecting_init(struct ast_party_redirecting *init)
Initialize the given redirecting structure.
Definition: channel.c:2090
void ast_party_number_init(struct ast_party_number *init)
Initialize the given number structure.
Definition: channel.c:1612
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:3127
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:2022
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:6402
struct ast_frame * ast_read(struct ast_channel *chan)
Reads a frame.
Definition: channel.c:4223
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:10397
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:8799
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:4621
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:10298
#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:1659
void ast_party_redirecting_free(struct ast_party_redirecting *doomed)
Destroy the redirecting information contents.
Definition: channel.c:2147
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:2013
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
enum ast_frame_type frametype
union ast_frame::@231 data
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
struct callattempt * call_next
Definition: app_queue.c:1800
unsigned int pending_connected_update
Definition: app_queue.c:1808
int ast_remaining_ms(struct timeval start, int max_ms)
Calculate remaining milliseconds given a starting timestamp and upper bound.
Definition: utils.c:2317
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 6035 of file app_queue.c.

6036{
6037 int res = 0;
6038
6039 /* This is the holding pen for callers 2 through maxlen */
6040 for (;;) {
6041
6042 /* A request to withdraw this call from the queue arrived */
6043 if (qe->withdraw) {
6044 *reason = QUEUE_WITHDRAW;
6045 res = 1;
6046 break;
6047 }
6048
6049 if (is_our_turn(qe)) {
6050 break;
6051 }
6052
6053 /* If we have timed out, break out */
6054 if (qe->expire && (time(NULL) >= qe->expire)) {
6055 *reason = QUEUE_TIMEOUT;
6056 break;
6057 }
6058
6059 if (qe->parent->leavewhenempty) {
6060 int status = 0;
6061
6063 record_abandoned(qe);
6064 *reason = QUEUE_LEAVEEMPTY;
6065 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));
6066 res = -1;
6067 qe->handled = -1;
6068 break;
6069 }
6070 }
6071
6072 /* Make a position announcement, if enabled */
6073 if (qe->parent->announcefrequency &&
6074 (res = say_position(qe,ringing))) {
6075 break;
6076 }
6077
6078 /* If we have timed out, break out */
6079 if (qe->expire && (time(NULL) >= qe->expire)) {
6080 *reason = QUEUE_TIMEOUT;
6081 break;
6082 }
6083
6084 /* Make a periodic announcement, if enabled */
6087 break;
6088
6089 /* see if we need to move to the next penalty level for this queue */
6090 while (qe->pr && ((time(NULL) - qe->start) >= qe->pr->time)) {
6091 update_qe_rule(qe);
6092 }
6093
6094 /* If we have timed out, break out */
6095 if (qe->expire && (time(NULL) >= qe->expire)) {
6096 *reason = QUEUE_TIMEOUT;
6097 break;
6098 }
6099
6100 /* Wait a second before checking again */
6101 if ((res = ast_waitfordigit(qe->chan, RECHECK * 1000))) {
6102 if (res > 0 && !valid_exit(qe, res)) {
6103 res = 0;
6104 } else {
6105 break;
6106 }
6107 }
6108
6109 /* If we have timed out, break out */
6110 if (qe->expire && (time(NULL) >= qe->expire)) {
6111 *reason = QUEUE_TIMEOUT;
6112 break;
6113 }
6114 }
6115
6116 return res;
6117}
#define RECHECK
Definition: app_queue.c:1678

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, queue_ent::raise_respect_min, 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 10434 of file app_queue.c.

10434 {
10435 int list_len, word_len = strlen(word);
10436 const char *find, *end_find, *end_list;
10437
10438 /* strip whitespace from front */
10439 while(isspace(*list)) {
10440 list++;
10441 }
10442
10443 while((find = strstr(list, word))) {
10444 /* beginning of find starts inside another word? */
10445 if (find != list && *(find - 1) != ' ') {
10446 list = find;
10447 /* strip word from front */
10448 while(!isspace(*list) && *list != '\0') {
10449 list++;
10450 }
10451 /* strip whitespace from front */
10452 while(isspace(*list)) {
10453 list++;
10454 }
10455 continue;
10456 }
10457
10458 /* end of find ends inside another word or at very end of list? */
10459 list_len = strlen(list);
10460 end_find = find + word_len;
10461 end_list = list + list_len;
10462 if (end_find == end_list || *end_find != ' ') {
10463 list = find;
10464 /* strip word from front */
10465 while(!isspace(*list) && *list != '\0') {
10466 list++;
10467 }
10468 /* strip whitespace from front */
10469 while(isspace(*list)) {
10470 list++;
10471 }
10472 continue;
10473 }
10474
10475 /* terminating conditions satisfied, word at beginning or separated by ' ' */
10476 return 1;
10477 }
10478
10479 return 0;
10480}

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

◆ agent_router

struct stasis_message_router* agent_router
static

Definition at line 11873 of file app_queue.c.

Referenced by load_module(), and unload_module().

◆ app

char* app = "Queue"
static

Definition at line 1695 of file app_queue.c.

Referenced by load_module(), and unload_module().

◆ app_aqm

char* app_aqm = "AddQueueMember"
static

Definition at line 1697 of file app_queue.c.

Referenced by load_module(), and unload_module().

◆ app_pqm

char* app_pqm = "PauseQueueMember"
static

Definition at line 1701 of file app_queue.c.

Referenced by load_module(), and unload_module().

◆ app_ql

char* app_ql = "QueueLog"
static

Definition at line 1705 of file app_queue.c.

Referenced by load_module(), and unload_module().

◆ app_qupd

char* app_qupd = "QueueUpdate"
static

Definition at line 1707 of file app_queue.c.

Referenced by load_module(), and unload_module().

◆ app_rqm

char* app_rqm = "RemoveQueueMember"
static

Definition at line 1699 of file app_queue.c.

Referenced by load_module(), and unload_module().

◆ app_upqm

char* app_upqm = "UnpauseQueueMember"
static

Definition at line 1703 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 1626 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 12137 of file app_queue.c.

◆ autofill_default

int autofill_default
static

queues.conf [general] option

Definition at line 1719 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 11860 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 1731 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 1740 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 1767 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(), process_text_message(), 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(), sorcery_realtime_update(), startelm(), starttimer(), state_id_by_topic(), try_merge_optimize_out(), try_swap_optimize_out(), and update_incoming_connected_line().

◆ log_caller_id_name

int log_caller_id_name
static

queues.conf [general] option

Definition at line 1743 of file app_queue.c.

Referenced by queue_exec(), and queue_set_global_params().

◆ log_membername_as_agent

int log_membername_as_agent
static

◆ log_unpause_on_reason_change

int log_unpause_on_reason_change
static

queues.conf [general] option

Definition at line 1746 of file app_queue.c.

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

◆ montype_default

int montype_default
static

queues.conf [general] option

Definition at line 1722 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 1734 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 2649 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 1710 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 1610 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:9173

Definition at line 9608 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:9376

Definition at line 9624 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:9215
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:9317

Definition at line 9618 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:9492

Definition at line 9634 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:9540
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:9572

Definition at line 9639 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:9129

Definition at line 9613 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:9455

Definition at line 9629 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 1752 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 1749 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 1728 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 1725 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 11874 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 1716 of file app_queue.c.

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