Asterisk - The Open Source Telephony Project GIT-master-0a46be9
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 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 1898 of file app_queue.c.

◆ ANNOUNCEHOLDTIME_ONCE

#define ANNOUNCEHOLDTIME_ONCE   2

Definition at line 1899 of file app_queue.c.

◆ ANNOUNCEPOSITION_LIMIT

#define ANNOUNCEPOSITION_LIMIT   4

We not announce position more than <limit>

Definition at line 1917 of file app_queue.c.

◆ ANNOUNCEPOSITION_MORE_THAN

#define ANNOUNCEPOSITION_MORE_THAN   3

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

Definition at line 1916 of file app_queue.c.

◆ ANNOUNCEPOSITION_NO

#define ANNOUNCEPOSITION_NO   2

We don't announce position

Definition at line 1915 of file app_queue.c.

◆ ANNOUNCEPOSITION_YES

#define ANNOUNCEPOSITION_YES   1

We announce position

Definition at line 1914 of file app_queue.c.

◆ AST_MAX_WATCHERS

#define AST_MAX_WATCHERS   256

Definition at line 5339 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 2647 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 1900 of file app_queue.c.

◆ QUEUE_PAUSED_DEVSTATE

#define QUEUE_PAUSED_DEVSTATE   AST_DEVICE_INUSE

Definition at line 3684 of file app_queue.c.

◆ queue_ref

#define queue_ref (   q)    ao2_bump(q)

Definition at line 2183 of file app_queue.c.

◆ queue_t_ref

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

Definition at line 2185 of file app_queue.c.

◆ queue_t_unref

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

Definition at line 2186 of file app_queue.c.

◆ QUEUE_UNKNOWN_PAUSED_DEVSTATE

#define QUEUE_UNKNOWN_PAUSED_DEVSTATE   AST_DEVICE_NOT_INUSE

Definition at line 3686 of file app_queue.c.

◆ QUEUE_UNPAUSED_DEVSTATE

#define QUEUE_UNPAUSED_DEVSTATE   AST_DEVICE_NOT_INUSE

Definition at line 3685 of file app_queue.c.

◆ queue_unref

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

Definition at line 2184 of file app_queue.c.

◆ queues_t_link

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

Definition at line 2187 of file app_queue.c.

◆ queues_t_unlink

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

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

6270 {
6271 CALLER,
6272 AGENT,
6273 TRANSFER
6274};
@ AGENT
Definition: app_queue.c:6272
@ CALLER
Definition: app_queue.c:6271
@ TRANSFER
Definition: app_queue.c:6273

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

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

◆ member_properties

Enumerator
MEMBER_PENALTY 
MEMBER_RINGINUSE 

Definition at line 1892 of file app_queue.c.

1892 {
1893 MEMBER_PENALTY = 0,
1894 MEMBER_RINGINUSE = 1,
1895};
@ MEMBER_RINGINUSE
Definition: app_queue.c:1894
@ MEMBER_PENALTY
Definition: app_queue.c:1893

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

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

◆ queue_timeout_priority

Enumerator
TIMEOUT_PRIORITY_APP 
TIMEOUT_PRIORITY_CONF 

Definition at line 1778 of file app_queue.c.

1778 {
1781};
@ TIMEOUT_PRIORITY_CONF
Definition: app_queue.c:1780
@ TIMEOUT_PRIORITY_APP
Definition: app_queue.c:1779

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

10303{
10304 struct call_queue *q;
10305 struct ast_str *out = ast_str_alloca(512);
10306 struct ao2_container *sorted_queues;
10307
10308 struct ao2_iterator queue_iter;
10309 int found = 0;
10310
10311 if (argc != 2 && argc != 3) {
10312 return CLI_SHOWUSAGE;
10313 }
10314
10315 if (argc == 3) { /* specific queue */
10316 if ((q = find_load_queue_rt_friendly(argv[2]))) {
10317 ao2_lock(q);
10318 print_queue(s, fd, q);
10319 ao2_unlock(q);
10320 queue_unref(q);
10321 } else {
10322 ast_str_set(&out, 0, "No such queue: %s.", argv[2]);
10323 do_print(s, fd, ast_str_buffer(out));
10324 }
10325 return CLI_SUCCESS;
10326 }
10327
10328 if (ast_check_realtime("queues")) {
10329 /* This block is to find any queues which are defined in realtime but
10330 * which have not yet been added to the in-core container
10331 */
10332 struct ast_config *cfg = ast_load_realtime_multientry("queues", "name LIKE", "%", SENTINEL);
10333 if (cfg) {
10334 char *category = NULL;
10335 while ((category = ast_category_browse(cfg, category))) {
10336 const char *queuename = ast_variable_retrieve(cfg, category, "name");
10337 if (ast_strlen_zero(queuename)) {
10338 ast_log(LOG_WARNING, "Ignoring realtime queue with a NULL or empty 'name.'\n");
10339 continue;
10340 }
10341 if ((q = find_load_queue_rt_friendly(queuename))) {
10342 queue_t_unref(q, "Done with temporary pointer");
10343 }
10344 }
10345 ast_config_destroy(cfg);
10346 }
10347 }
10348
10349 /*
10350 * Snapping a copy of the container prevents having to lock both the queues container
10351 * and the queue itself at the same time. It also allows us to sort the entries.
10352 */
10353 sorted_queues = ao2_container_alloc_rbtree(AO2_ALLOC_OPT_LOCK_NOLOCK, 0, call_queue_sort_fn, NULL);
10354 if (!sorted_queues) {
10355 return CLI_SUCCESS;
10356 }
10357 if (ao2_container_dup(sorted_queues, queues, 0)) {
10358 ao2_ref(sorted_queues, -1);
10359 return CLI_SUCCESS;
10360 }
10361
10362 /*
10363 * No need to lock the container since it's temporary and static.
10364 * We also unlink the entries as we use them so the container is
10365 * empty when the iterator finishes. We can then just unref the container.
10366 */
10367 queue_iter = ao2_iterator_init(sorted_queues, AO2_ITERATOR_DONTLOCK | AO2_ITERATOR_UNLINK);
10368 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
10369 struct call_queue *realtime_queue = NULL;
10370 ao2_lock(q);
10371 /* This check is to make sure we don't print information for realtime
10372 * queues which have been deleted from realtime but which have not yet
10373 * been deleted from the in-core container. Only do this if we're not
10374 * looking for a specific queue.
10375 */
10376 if (q->realtime) {
10377 realtime_queue = find_load_queue_rt_friendly(q->name);
10378 if (!realtime_queue) {
10379 ao2_unlock(q);
10380 queue_t_unref(q, "Done with iterator");
10381 continue;
10382 }
10383 queue_t_unref(realtime_queue, "Queue is already in memory");
10384 }
10385
10386 found = 1;
10387 print_queue(s, fd, q);
10388
10389 ao2_unlock(q);
10390 queue_t_unref(q, "Done with iterator"); /* Unref the iterator's reference */
10391 }
10392 ao2_iterator_destroy(&queue_iter);
10393 ao2_ref(sorted_queues, -1);
10394 if (!found) {
10395 ast_str_set(&out, 0, "No queues.");
10396 do_print(s, fd, ast_str_buffer(out));
10397 }
10398 return CLI_SUCCESS;
10399}
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:10194
static struct ao2_container * queues
Definition: app_queue.c:2029
#define queue_t_unref(q, tag)
Definition: app_queue.c:2186
#define queue_unref(q)
Definition: app_queue.c:2184
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:10184
static struct call_queue * find_load_queue_rt_friendly(const char *queuename)
Definition: app_queue.c:4043
#define ast_log
Definition: astobj2.c:42
int ao2_container_dup(struct ao2_container *dest, struct ao2_container *src, enum search_flags flags)
Copy all object references in the src container into the dest container.
@ AO2_ALLOC_OPT_LOCK_NOLOCK
Definition: astobj2.h:367
#define ao2_t_iterator_next(iter, tag)
Definition: astobj2.h:1909
@ AO2_ITERATOR_UNLINK
Definition: astobj2.h:1863
@ AO2_ITERATOR_DONTLOCK
Assume that the ao2_container is already locked.
Definition: astobj2.h:1852
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
#define ao2_container_alloc_rbtree(ao2_options, container_options, sort_fn, cmp_fn)
Allocate and initialize a red-black tree container.
Definition: astobj2.h:1349
#define ao2_unlock(a)
Definition: astobj2.h:729
#define ao2_lock(a)
Definition: astobj2.h:717
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
#define CLI_SHOWUSAGE
Definition: cli.h:45
#define CLI_SUCCESS
Definition: cli.h:44
#define SENTINEL
Definition: compiler.h:87
char * ast_category_browse(struct ast_config *config, const char *prev_name)
Browse categories.
Definition: extconf.c:3326
struct ast_config * ast_load_realtime_multientry(const char *family,...) attribute_sentinel
Retrieve realtime configuration.
Definition: main/config.c:3854
int ast_check_realtime(const char *family)
Check if realtime engine is configured for family.
Definition: main/config.c:3762
void ast_config_destroy(struct ast_config *cfg)
Destroys a config.
Definition: extconf.c:1289
const char * ast_variable_retrieve(struct ast_config *config, const char *category, const char *variable)
Definition: main/config.c:869
#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:1973
unsigned int found
Definition: app_queue.c:1974
const ast_string_field name
Definition: app_queue.c:1957
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 12117 of file app_queue.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

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

7742{
7743 struct call_queue *q;
7744 struct member *new_member, *old_member;
7745 int res = RES_NOSUCHQUEUE;
7746
7747 /*! \note Ensure the appropriate realtime queue is loaded. Note that this
7748 * short-circuits if the queue is already in memory. */
7749 if (!(q = find_load_queue_rt_friendly(queuename))) {
7750 return res;
7751 }
7752
7753 ao2_lock(q);
7754 if ((old_member = interface_exists(q, interface)) == NULL) {
7756 new_member->dynamic = 1;
7757 if (reason_paused) {
7758 ast_copy_string(new_member->reason_paused, reason_paused, sizeof(new_member->reason_paused));
7759 }
7760 member_add_to_queue(q, new_member);
7761 queue_publish_member_blob(queue_member_added_type(), queue_member_blob_create(q, new_member));
7762
7763 if (is_member_available(q, new_member)) {
7765 }
7766
7767 ao2_ref(new_member, -1);
7768 new_member = NULL;
7769
7770 if (dump) {
7772 }
7773
7774 res = RES_OKAY;
7775 } else {
7776 res = RES_OUTOFMEMORY;
7777 }
7778 } else {
7779 ao2_ref(old_member, -1);
7780 res = RES_EXISTS;
7781 }
7782 ao2_unlock(q);
7783 queue_t_unref(q, "Expiring temporary reference");
7784
7785 return res;
7786}
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:2998
static struct member * interface_exists(struct call_queue *q, const char *interface)
Definition: app_queue.c:7606
static void dump_queue_members(struct call_queue *pm_queue)
Dump all members in a specific queue to the database.
Definition: app_queue.c:7633
static int is_member_available(struct call_queue *q, struct member *mem)
Definition: app_queue.c:2739
#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:3694
static struct ast_json * queue_member_blob_create(struct call_queue *q, struct member *mem)
Definition: app_queue.c:2523
#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:2499
@ 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:1961
char interface[AST_CHANNEL_NAME]
Definition: app_queue.c:1854
int dynamic
Definition: app_queue.c:1862
char membername[80]
Definition: app_queue.c:1859
int penalty
Definition: app_queue.c:1860
int paused
Definition: app_queue.c:1865
int wrapuptime
Definition: app_queue.c:1869
char reason_paused[80]
Definition: app_queue.c:1866
char state_interface[AST_CHANNEL_NAME]
Definition: app_queue.c:1857

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

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

8503{
8504 int res=-1;
8505 char *parse, *tmp, *temppos = NULL, *reason = NULL;
8507 AST_APP_ARG(queuename);
8508 AST_APP_ARG(interface);
8509 AST_APP_ARG(penalty);
8511 AST_APP_ARG(membername);
8512 AST_APP_ARG(state_interface);
8513 AST_APP_ARG(wrapuptime);
8514 );
8515 int penalty = 0;
8516 int paused = 0;
8517 int wrapuptime;
8518 struct ast_flags flags = { 0 };
8519
8520 if (ast_strlen_zero(data)) {
8521 ast_log(LOG_WARNING, "AddQueueMember requires an argument (queuename[,interface[,penalty[,options[,membername[,stateinterface][,wrapuptime]]]]])\n");
8522 return -1;
8523 }
8524
8525 parse = ast_strdupa(data);
8526
8528
8529 if (args.options) {
8530 char *opts[AQM_OPT_ARG_ARRAY_SIZE] = { NULL, };
8531 ast_app_parse_options(aqm_opts, &flags, opts, args.options);
8533 paused = 1;
8535 reason = ast_strdupa(opts[AQM_OPT_ARG_PAUSE_REASON]);
8536 }
8537 }
8538 }
8539
8540 if (ast_strlen_zero(args.interface)) {
8541 args.interface = ast_strdupa(ast_channel_name(chan));
8542 temppos = strrchr(args.interface, '-');
8543 if (temppos) {
8544 *temppos = '\0';
8545 }
8546 }
8547
8548 if (!ast_strlen_zero(args.penalty)) {
8549 if ((sscanf(args.penalty, "%30d", &penalty) != 1) || penalty < 0) {
8550 ast_log(LOG_WARNING, "Penalty '%s' is invalid, must be an integer >= 0\n", args.penalty);
8551 penalty = 0;
8552 }
8553 }
8554
8555 if (!ast_strlen_zero(args.wrapuptime)) {
8556 tmp = args.wrapuptime;
8557 ast_strip(tmp);
8558 wrapuptime = atoi(tmp);
8559 if (wrapuptime < 0) {
8560 wrapuptime = 0;
8561 }
8562 } else {
8563 wrapuptime = 0;
8564 }
8565
8566 switch (add_to_queue(args.queuename, args.interface, args.membername, penalty, paused, queue_persistent_members, args.state_interface, reason, wrapuptime)) {
8567 case RES_OKAY:
8568 if (ast_strlen_zero(args.membername) || !log_membername_as_agent) {
8569 ast_queue_log(args.queuename, ast_channel_uniqueid(chan), args.interface, "ADDMEMBER", "%s", paused ? "PAUSED" : "");
8570 } else {
8571 ast_queue_log(args.queuename, ast_channel_uniqueid(chan), args.membername, "ADDMEMBER", "%s", paused ? "PAUSED" : "");
8572 }
8573 ast_log(LOG_NOTICE, "Added interface '%s' to queue '%s'\n", args.interface, args.queuename);
8574 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "ADDED");
8575 res = 0;
8576 break;
8577 case RES_EXISTS:
8578 ast_log(LOG_WARNING, "Unable to add interface '%s' to queue '%s': Already there\n", args.interface, args.queuename);
8579 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "MEMBERALREADY");
8580 res = 0;
8581 break;
8582 case RES_NOSUCHQUEUE:
8583 ast_log(LOG_WARNING, "Unable to add interface to queue '%s': No such queue\n", args.queuename);
8584 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "NOSUCHQUEUE");
8585 res = 0;
8586 break;
8587 case RES_OUTOFMEMORY:
8588 ast_log(LOG_ERROR, "Out of memory adding interface %s to queue %s\n", args.interface, args.queuename);
8589 break;
8590 }
8591
8592 return res;
8593}
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:7741
#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 12117 of file app_queue.c.

◆ autopause2int()

static int autopause2int ( const char *  autopause)
static

Definition at line 2076 of file app_queue.c.

2077{
2078 int x;
2079 /*This 'double check' that default value is OFF */
2081 return QUEUE_AUTOPAUSE_OFF;
2082 }
2083
2084 /*This 'double check' is to ensure old values works */
2085 if(ast_true(autopause)) {
2086 return QUEUE_AUTOPAUSE_ON;
2087 }
2088
2089 for (x = 0; x < ARRAY_LEN(autopausesmodes); x++) {
2090 if (!strcasecmp(autopause, autopausesmodes[x].name)) {
2091 return autopausesmodes[x].autopause;
2092 }
2093 }
2094
2095 /*This 'double check' that default value is OFF */
2096 return QUEUE_AUTOPAUSE_OFF;
2097}
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 6192 of file app_queue.c.

6193{
6194 /* disregarding penalty on too few members? */
6195 int membercount = ao2_container_count(q->members);
6196 unsigned char usepenalty = (membercount <= q->penaltymemberslimit) ? 0 : 1;
6197 int penalty = mem->penalty;
6198
6199 if (usepenalty) {
6200 if (qe->raise_penalty != INT_MAX && penalty < qe->raise_penalty) {
6201 /* Low penalty is raised up to the current minimum */
6202 penalty = qe->raise_penalty;
6203 }
6204 if ((qe->max_penalty != INT_MAX && penalty > qe->max_penalty) ||
6205 (qe->min_penalty != INT_MAX && penalty < qe->min_penalty)) {
6206 return -1;
6207 }
6208 } else {
6209 ast_debug(1, "Disregarding penalty, %d members and %d in penaltymemberslimit.\n",
6210 membercount, q->penaltymemberslimit);
6211 }
6212
6213 switch (q->strategy) {
6215 /* Everyone equal, except for penalty */
6216 tmp->metric = penalty * 1000000 * usepenalty;
6217 break;
6219 if (pos < qe->linpos) {
6220 tmp->metric = 1000 + pos;
6221 } else {
6222 if (pos > qe->linpos) {
6223 /* Indicate there is another priority */
6224 qe->linwrapped = 1;
6225 }
6226 tmp->metric = pos;
6227 }
6228 tmp->metric += penalty * 1000000 * usepenalty;
6229 break;
6232 pos = mem->queuepos;
6233 if (pos < q->rrpos) {
6234 tmp->metric = 1000 + pos;
6235 } else {
6236 if (pos > q->rrpos) {
6237 /* Indicate there is another priority */
6238 q->wrapped = 1;
6239 }
6240 tmp->metric = pos;
6241 }
6242 tmp->metric += penalty * 1000000 * usepenalty;
6243 break;
6245 tmp->metric = ast_random() % 1000;
6246 tmp->metric += penalty * 1000000 * usepenalty;
6247 break;
6249 tmp->metric = ast_random() % ((1 + penalty) * 1000);
6250 break;
6252 tmp->metric = mem->calls;
6253 tmp->metric += penalty * 1000000 * usepenalty;
6254 break;
6256 if (!mem->lastcall) {
6257 tmp->metric = 0;
6258 } else {
6259 tmp->metric = 1000000 - (time(NULL) - mem->lastcall);
6260 }
6261 tmp->metric += penalty * 1000000 * usepenalty;
6262 break;
6263 default:
6264 ast_log(LOG_WARNING, "Can't calculate metric for unknown strategy %d\n", q->strategy);
6265 break;
6266 }
6267 return 0;
6268}
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:2015
int penaltymemberslimit
Definition: app_queue.c:1999
unsigned int wrapped
Definition: app_queue.c:1967
int strategy
Definition: app_queue.c:1972
int queuepos
Definition: app_queue.c:1867
time_t lastcall
Definition: app_queue.c:1871
int calls
Definition: app_queue.c:1861
int linpos
Definition: app_queue.c:1840
int max_penalty
Definition: app_queue.c:1836
int raise_penalty
Definition: app_queue.c:1838
int min_penalty
Definition: app_queue.c:1837
int linwrapped
Definition: app_queue.c:1841
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 4595 of file app_queue.c.

4596{
4597 if (doomed->member) {
4598 ao2_ref(doomed->member, -1);
4599 }
4601 ast_free(doomed->orig_chan_name);
4602 ast_free(doomed);
4603}
#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:1803
char * orig_chan_name
Definition: app_queue.c:1814
struct member * member
Definition: app_queue.c:1801

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

4806{
4807 struct member *memberp = call->member;
4808 int wrapuptime;
4809
4810 if (memberp->paused) {
4811 ast_debug(1, "%s paused, can't receive call\n", call->interface);
4812 return 0;
4813 }
4814
4815 if (!memberp->ringinuse && !member_status_available(memberp->status)) {
4816 ast_debug(1, "%s not available, can't receive call\n", call->interface);
4817 return 0;
4818 }
4819
4820 if (memberp->lastqueue) {
4821 wrapuptime = get_wrapuptime(memberp->lastqueue, memberp);
4822 } else {
4823 wrapuptime = get_wrapuptime(qe->parent, memberp);
4824 }
4825 if (wrapuptime && (time(NULL) - memberp->lastcall) < wrapuptime) {
4826 ast_debug(1, "Wrapuptime not yet expired on queue %s for %s\n",
4827 (memberp->lastqueue ? memberp->lastqueue->name : qe->parent->name),
4828 call->interface);
4829 return 0;
4830 }
4831
4832 if (use_weight && compare_weight(qe->parent, memberp)) {
4833 ast_debug(1, "Priority queue delaying call to %s:%s\n",
4834 qe->parent->name, call->interface);
4835 return 0;
4836 }
4837
4839 ast_debug(1, "Another caller was waiting longer; delaying call to %s:%s\n",
4840 qe->parent->name, call->interface);
4841 return 0;
4842 }
4843
4844 if (!memberp->ringinuse) {
4845 struct member *mem;
4846
4848
4849 mem = ao2_find(pending_members, memberp,
4851 if (mem) {
4852 /*
4853 * If found that means this member is currently being attempted
4854 * from another calling thread, so stop trying from this thread
4855 */
4856 ast_debug(1, "%s has another call trying, can't receive call\n",
4857 call->interface);
4858 ao2_ref(mem, -1);
4860 return 0;
4861 }
4862
4863 /*
4864 * If not found add it to the container so another queue
4865 * won't attempt to call this member at the same time.
4866 */
4867 ast_debug(3, "Add %s to pending_members\n", memberp->membername);
4868 ao2_link(pending_members, memberp);
4870
4871 /*
4872 * The queue member is available. Get current status to be sure
4873 * because the device state and extension state callbacks may
4874 * not have updated the status yet.
4875 */
4877 ast_debug(1, "%s actually not available, can't receive call\n",
4878 call->interface);
4879 pending_members_remove(memberp);
4880 return 0;
4881 }
4882 }
4883
4884 return 1;
4885}
static int is_longest_waiting_caller(struct queue_ent *caller, struct member *member)
Definition: app_queue.c:4724
static int get_wrapuptime(struct call_queue *q, struct member *member)
Return wrapuptime.
Definition: app_queue.c:2119
static int compare_weight(struct call_queue *rq, struct member *member)
Definition: app_queue.c:4690
static struct ao2_container * pending_members
Definition: app_queue.c:2646
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:2697
static int get_queue_member_status(struct member *cur)
Return the current state of a member.
Definition: app_queue.c:2983
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:4791
#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:1864
unsigned int ringinuse
Definition: app_queue.c:1878
struct call_queue * lastqueue
Definition: app_queue.c:1874
struct call_queue * parent
Definition: app_queue.c:1819

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

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

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

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

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

10138{
10139 struct call_queue *q;
10140 struct ao2_iterator queue_iter;
10141
10142 queue_iter = ao2_iterator_init(queues, 0);
10143 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
10144 ao2_lock(q);
10145 if (ast_strlen_zero(queuename) || !strcasecmp(q->name, queuename))
10146 clear_queue(q);
10147 ao2_unlock(q);
10148 queue_t_unref(q, "Done with iterator");
10149 }
10150 ao2_iterator_destroy(&queue_iter);
10151 return 0;
10152}
static void clear_queue(struct call_queue *q)
Definition: app_queue.c:3184

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

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

10474{
10475 struct call_queue *q;
10476 char *ret = NULL;
10477 int which = 0;
10478 int wordlen = strlen(word);
10479 struct ao2_iterator queue_iter;
10480 const char *word_list = NULL;
10481
10482 /* for certain commands, already completed items should be left out of
10483 * the list */
10484 if (word_list_offset && strlen(line) >= word_list_offset) {
10485 word_list = line + word_list_offset;
10486 }
10487
10488 queue_iter = ao2_iterator_init(queues, 0);
10489 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
10490 if (!strncasecmp(word, q->name, wordlen) && ++which > state
10491 && (!word_list_offset || !word_in_list(word_list, q->name))) {
10492 ret = ast_strdup(q->name);
10493 queue_t_unref(q, "Done with iterator");
10494 break;
10495 }
10496 queue_t_unref(q, "Done with iterator");
10497 }
10498 ao2_iterator_destroy(&queue_iter);
10499
10500 /* Pretend "rules" is at the end of the queues list in certain
10501 * circumstances since it is an alternate command that should be
10502 * tab-completable for "queue show" */
10503 if (!ret && which == state && !wordlen && !strncmp("queue show", line, 10)) {
10504 ret = ast_strdup("rules");
10505 }
10506
10507 return ret;
10508}
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:10414
#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 10980 of file app_queue.c.

10981{
10982 /* 0 - queue; 1 - add; 2 - member; 3 - <interface>; 4 - to; 5 - <queue>; 6 - penalty; 7 - <penalty>; 8 - as; 9 - <membername> */
10983 switch (pos) {
10984 case 3: /* Don't attempt to complete name of interface (infinite possibilities) */
10985 return NULL;
10986 case 4: /* only one possible match, "to" */
10987 return state == 0 ? ast_strdup("to") : NULL;
10988 case 5: /* <queue> */
10989 return complete_queue(line, word, pos, state, 0);
10990 case 6: /* only one possible match, "penalty" */
10991 return state == 0 ? ast_strdup("penalty") : NULL;
10992 case 7:
10993 if (0 <= state && state < 100) { /* 0-99 */
10994 char *num;
10995 if ((num = ast_malloc(3))) {
10996 sprintf(num, "%d", state);
10997 }
10998 return num;
10999 } else {
11000 return NULL;
11001 }
11002 case 8: /* only one possible match, "as" */
11003 return state == 0 ? ast_strdup("as") : NULL;
11004 case 9: /* Don't attempt to complete name of member (infinite possibilities) */
11005 return NULL;
11006 default:
11007 return NULL;
11008 }
11009}
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:10473
#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 11405 of file app_queue.c.

11406{
11407 /* 0 - queue; 1 - pause; 2 - member; 3 - <interface>; 4 - queue; 5 - <queue>; 6 - reason; 7 - <reason> */
11408 switch (pos) {
11409 case 3: /* Don't attempt to complete name of interface (infinite possibilities) */
11410 return NULL;
11411 case 4: /* only one possible match, "queue" */
11412 return state == 0 ? ast_strdup("queue") : NULL;
11413 case 5: /* <queue> */
11414 return complete_queue(line, word, pos, state, 0);
11415 case 6: /* "reason" */
11416 return state == 0 ? ast_strdup("reason") : NULL;
11417 case 7: /* Can't autocomplete a reason, since it's 100% customizeable */
11418 return NULL;
11419 default:
11420 return NULL;
11421 }
11422}

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

11241{
11242 int which = 0;
11243 struct call_queue *q;
11244 struct member *m;
11245 struct ao2_iterator queue_iter;
11246 struct ao2_iterator mem_iter;
11247 int wordlen = strlen(word);
11248
11249 /* 0 - queue; 1 - remove; 2 - member; 3 - <member>; 4 - from; 5 - <queue> */
11250 if (pos > 5 || pos < 3) {
11251 return NULL;
11252 }
11253 if (pos == 4) { /* only one possible match, 'from' */
11254 return (state == 0 ? ast_strdup("from") : NULL);
11255 }
11256
11257 if (pos == 5) { /* No need to duplicate code */
11258 return complete_queue(line, word, pos, state, 0);
11259 }
11260
11261 /* here is the case for 3, <member> */
11262 queue_iter = ao2_iterator_init(queues, 0);
11263 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
11264 ao2_lock(q);
11265 mem_iter = ao2_iterator_init(q->members, 0);
11266 while ((m = ao2_iterator_next(&mem_iter))) {
11267 if (!strncasecmp(word, m->membername, wordlen) && ++which > state) {
11268 char *tmp;
11269 tmp = ast_strdup(m->interface);
11270 ao2_ref(m, -1);
11271 ao2_iterator_destroy(&mem_iter);
11272 ao2_unlock(q);
11273 queue_t_unref(q, "Done with iterator, returning interface name");
11274 ao2_iterator_destroy(&queue_iter);
11275 return tmp;
11276 }
11277 ao2_ref(m, -1);
11278 }
11279 ao2_iterator_destroy(&mem_iter);
11280 ao2_unlock(q);
11281 queue_t_unref(q, "Done with iterator");
11282 }
11283 ao2_iterator_destroy(&queue_iter);
11284
11285 return NULL;
11286}

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

11601{
11602 int which = 0;
11603 struct rule_list *rl_iter;
11604 int wordlen = strlen(word);
11605 char *ret = NULL;
11606 if (pos != 3) /* Wha? */ {
11607 return NULL;
11608 }
11609
11611 AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) {
11612 if (!strncasecmp(word, rl_iter->name, wordlen) && ++which > state) {
11613 ret = ast_strdup(rl_iter->name);
11614 break;
11615 }
11616 }
11618
11619 return ret;
11620}
#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:2022
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 11479 of file app_queue.c.

11480{
11481 /* 0 - queue; 1 - set; 2 - penalty/ringinuse; 3 - <value>; 4 - on; 5 - <member>; 6 - in; 7 - <queue>;*/
11482 switch (pos) {
11483 case 4:
11484 if (state == 0) {
11485 return ast_strdup("on");
11486 } else {
11487 return NULL;
11488 }
11489 case 6:
11490 if (state == 0) {
11491 return ast_strdup("in");
11492 } else {
11493 return NULL;
11494 }
11495 case 7:
11496 return complete_queue(line, word, pos, state, 0);
11497 default:
11498 return NULL;
11499 }
11500}

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

10511{
10512 if (pos == 2) {
10513 return complete_queue(line, word, pos, state, 0);
10514 }
10515 return NULL;
10516}

References complete_queue(), and NULL.

Referenced by queue_show().

◆ compress_char()

static int compress_char ( const char  c)
static

Definition at line 3043 of file app_queue.c.

3044{
3045 if (c < 32) {
3046 return 0;
3047 } else if (c > 96) {
3048 return c - 64;
3049 }
3050 return c - 32;
3051}
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 2910 of file app_queue.c.

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

8631{
8632 struct penalty_rule *pr_iter;
8633 struct rule_list *rl_iter;
8634 const char *tmp = ast_strlen_zero(rulename) ? qe->parent->defaultrule : rulename;
8636 AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) {
8637 if (!strcasecmp(rl_iter->name, tmp)) {
8638 break;
8639 }
8640 }
8641 if (rl_iter) {
8642 AST_LIST_TRAVERSE(&rl_iter->rules, pr_iter, list) {
8643 struct penalty_rule *new_pr = ast_calloc(1, sizeof(*new_pr));
8644 if (!new_pr) {
8645 ast_log(LOG_ERROR, "Memory allocation error when copying penalty rules! Aborting!\n");
8646 break;
8647 }
8648 new_pr->time = pr_iter->time;
8649 new_pr->max_value = pr_iter->max_value;
8650 new_pr->min_value = pr_iter->min_value;
8651 new_pr->raise_value = pr_iter->raise_value;
8652 new_pr->max_relative = pr_iter->max_relative;
8653 new_pr->min_relative = pr_iter->min_relative;
8654 new_pr->raise_relative = pr_iter->raise_relative;
8655 AST_LIST_INSERT_TAIL(&qe->qe_rules, new_pr, list);
8656 }
8657 }
8659}
#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:1957
int raise_relative
Definition: app_queue.c:1909
struct penalty_rule::@52 list
int min_relative
Definition: app_queue.c:1908
int max_relative
Definition: app_queue.c:1907
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 2998 of file app_queue.c.

2999{
3000 struct member *cur;
3001
3002 if ((cur = ao2_alloc(sizeof(*cur), destroy_queue_member_cb))) {
3003 cur->ringinuse = ringinuse;
3004 cur->penalty = penalty;
3005 cur->paused = paused;
3006 cur->wrapuptime = wrapuptime;
3007 if (paused) {
3008 time(&cur->lastpause); /* Update time of last pause */
3009 }
3010 time(&cur->logintime);
3011 ast_copy_string(cur->interface, interface, sizeof(cur->interface));
3014 } else {
3016 }
3018 ast_copy_string(cur->membername, membername, sizeof(cur->membername));
3019 } else {
3020 ast_copy_string(cur->membername, interface, sizeof(cur->membername));
3021 }
3022 if (!strchr(cur->interface, '/')) {
3023 ast_log(LOG_WARNING, "No location at interface '%s'\n", interface);
3024 }
3025 if (!strncmp(cur->state_interface, "hint:", 5)) {
3026 char *tmp = ast_strdupa(cur->state_interface), *context = tmp;
3027 char *exten = strsep(&context, "@") + 5;
3028
3029 ast_copy_string(cur->state_exten, exten, sizeof(cur->state_exten));
3030 ast_copy_string(cur->state_context, S_OR(context, "default"), sizeof(cur->state_context));
3031
3033 } else {
3034 cur->state_id = -1;
3035 }
3036 cur->status = get_queue_member_status(cur);
3037 }
3038
3039 return cur;
3040}
static int extension_state_cb(const char *context, const char *exten, struct ast_state_cb_info *info, void *data)
Definition: app_queue.c:2939
static void destroy_queue_member_cb(void *obj)
Definition: app_queue.c:2988
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:1873
char state_exten[AST_MAX_EXTENSION]
Definition: app_queue.c:1855
char state_context[AST_MAX_CONTEXT]
Definition: app_queue.c:1856
int state_id
Definition: app_queue.c:1858
time_t lastpause
Definition: app_queue.c:1872

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

3861{
3862 struct call_queue *q = obj;
3863 int i;
3864
3865 free_members(q, 1);
3867 for (i = 0; i < MAX_PERIODIC_ANNOUNCEMENTS; i++) {
3868 if (q->sound_periodicannounce[i]) {
3870 }
3871 }
3872 ao2_ref(q->members, -1);
3873}
#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:3844
#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:1959

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

2989{
2990 struct member *mem = obj;
2991
2992 if (mem->state_id != -1) {
2994 }
2995}
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 2774 of file app_queue.c.

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

4776{
4777 o->stillgoing = 0;
4778 ast_hangup(o->chan);
4780 o->chan = NULL;
4781}
void ast_hangup(struct ast_channel *chan)
Hang up a channel.
Definition: channel.c:2511
struct ast_channel * chan
Definition: app_queue.c:1798
unsigned int stillgoing
Definition: app_queue.c:1811

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

10185{
10186 if (s) {
10187 astman_append(s, "%s\r\n", str);
10188 } else {
10189 ast_cli(fd, "%s\n", str);
10190 }
10191}
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 7633 of file app_queue.c.

7634{
7635 struct member *cur_member;
7636 struct ast_str *value;
7637 struct ao2_iterator mem_iter;
7638
7639 if (!pm_queue) {
7640 return;
7641 }
7642
7643 /* 4K is a reasonable default for most applications, but we grow to
7644 * accommodate more if necessary. */
7645 if (!(value = ast_str_create(4096))) {
7646 return;
7647 }
7648
7649 mem_iter = ao2_iterator_init(pm_queue->members, 0);
7650 while ((cur_member = ao2_iterator_next(&mem_iter))) {
7651 if (!cur_member->dynamic) {
7652 ao2_ref(cur_member, -1);
7653 continue;
7654 }
7655
7656 ast_str_append(&value, 0, "%s%s;%d;%d;%s;%s;%s;%d",
7657 ast_str_strlen(value) ? "|" : "",
7658 cur_member->interface,
7659 cur_member->penalty,
7660 cur_member->paused,
7661 cur_member->membername,
7662 cur_member->state_interface,
7663 cur_member->reason_paused,
7664 cur_member->wrapuptime);
7665
7666 ao2_ref(cur_member, -1);
7667 }
7668 ao2_iterator_destroy(&mem_iter);
7669
7670 if (ast_str_strlen(value) && !cur_member) {
7671 if (ast_db_put(pm_family, pm_queue->name, ast_str_buffer(value))) {
7672 ast_log(LOG_WARNING, "failed to create persistent dynamic entry!\n");
7673 }
7674 } else {
7675 /* Delete the entry if the queue is empty or there is an error */
7676 ast_db_del(pm_family, pm_queue->name);
7677 }
7678
7679 ast_free(value);
7680}
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 6982 of file app_queue.c.

6983{
6984 struct queue_end_bridge *qeb = data;
6985 struct call_queue *q = qeb->q;
6986 struct ast_channel *chan = qeb->chan;
6987
6988 if (ao2_ref(qeb, -1) == 1) {
6989 set_queue_variables(q, chan);
6990 /* This unrefs the reference we made in try_calling when we allocated qeb */
6991 queue_t_unref(q, "Expire bridge_config reference");
6992 }
6993}
static void set_queue_variables(struct call_queue *q, struct ast_channel *chan)
Set variables of queue.
Definition: app_queue.c:2191
Main Channel structure associated with a channel.
struct call_queue * q
Definition: app_queue.c:6971
struct ast_channel * chan
Definition: app_queue.c:6972

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

6976{
6977 struct queue_end_bridge *qeb = bconfig->end_bridge_callback_data;
6978 ao2_ref(qeb, +1);
6979 qeb->chan = originator;
6980}
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 7022 of file app_queue.c.

7024{
7025 const char *m = input;
7026 char escaped[size];
7027 char *p;
7028
7029 for (p = escaped; p < escaped + size - 1; p++, m++) {
7030 switch (*m) {
7031 case '^':
7032 if (*(m + 1) == '{') {
7033 *p = '$';
7034 }
7035 break;
7036 case ',':
7037 *p++ = '\\';
7038 /* Fall through */
7039 default:
7040 *p = *m;
7041 }
7042 if (*m == '\0')
7043 break;
7044 }
7045
7046 if (p == escaped + size) {
7047 escaped[size - 1] = '\0';
7048 }
7049
7050 pbx_substitute_variables_helper(chan, escaped, output, size - 1);
7051}
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 2939 of file app_queue.c.

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

2862{
2863 switch (state) {
2866 break;
2869 break;
2870 case AST_EXTENSION_BUSY:
2872 break;
2875 break;
2878 break;
2881 break;
2884 break;
2887 break;
2890 default:
2892 break;
2893 }
2894
2895 return state;
2896}
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 5033 of file app_queue.c.

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

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

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

12098{
12099 struct member *mem = NULL;
12100 struct call_queue *q;
12101
12102 if ((q = find_load_queue_rt_friendly(queuename))) {
12103 ao2_lock(q);
12104 mem = ao2_find(q->members, interface, OBJ_KEY);
12105 ao2_unlock(q);
12106 queue_t_unref(q, "Expiring temporary reference.");
12107 }
12108 return mem;
12109}
#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 3899 of file app_queue.c.

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

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

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

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

9177{
9178 struct member *m;
9179
9181 ast_log(LOG_ERROR, "QUEUE_MEMBER: Missing required interface argument.\n");
9182 return NULL;
9183 }
9184
9186 if (!m) {
9187 ast_log(LOG_ERROR, "Queue member interface '%s' not in queue '%s'.\n",
9188 interface, q->name);
9189 }
9190 return m;
9191}

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

8218{
8219 int foundqueue = 0, penalty;
8220 struct call_queue *q;
8221 struct member *mem;
8222
8223 if ((q = find_load_queue_rt_friendly(queuename))) {
8224 foundqueue = 1;
8225 ao2_lock(q);
8226 if ((mem = interface_exists(q, interface))) {
8227 penalty = mem->penalty;
8228 ao2_ref(mem, -1);
8229 ao2_unlock(q);
8230 queue_t_unref(q, "Search complete");
8231 return penalty;
8232 }
8233 ao2_unlock(q);
8234 queue_t_unref(q, "Search complete");
8235 }
8236
8237 /* some useful debugging */
8238 if (foundqueue) {
8239 ast_log (LOG_ERROR, "Invalid queuename\n");
8240 } else {
8241 ast_log (LOG_ERROR, "Invalid interface\n");
8242 }
8243
8244 return RESULT_FAILURE;
8245}
#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 2550 of file app_queue.c.

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

2984{
2985 return ast_strlen_zero(cur->state_exten) ? ast_device_state(cur->state_interface) : extensionstate2devicestate(ast_extension_state(NULL, cur->state_context, cur->state_exten));
2986}
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 2119 of file app_queue.c.

2120{
2121 if (member->wrapuptime) {
2122 return member->wrapuptime;
2123 }
2124 return q->wrapuptime;
2125}
int wrapuptime
Definition: app_queue.c:1998

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

6618{
6619 struct queue_stasis_data *queue_data = userdata;
6620 struct ast_attended_transfer_message *atxfer_msg = stasis_message_data(msg);
6621 RAII_VAR(struct ast_channel_snapshot *, caller_snapshot, NULL, ao2_cleanup);
6622 RAII_VAR(struct ast_channel_snapshot *, member_snapshot, NULL, ao2_cleanup);
6623
6624 if (atxfer_msg->result != AST_BRIDGE_TRANSFER_SUCCESS ||
6626 return;
6627 }
6628
6629 ao2_lock(queue_data);
6630
6631 if (queue_data->dying) {
6632 ao2_unlock(queue_data);
6633 return;
6634 }
6635
6636 if (ast_strlen_zero(queue_data->bridge_uniqueid)) {
6637 ao2_unlock(queue_data);
6638 return;
6639 }
6640
6641 if ((!atxfer_msg->to_transferee.bridge_snapshot || strcmp(queue_data->bridge_uniqueid,
6642 atxfer_msg->to_transferee.bridge_snapshot->uniqueid)) &&
6643 (!atxfer_msg->to_transfer_target.bridge_snapshot || strcmp(queue_data->bridge_uniqueid,
6645 ao2_unlock(queue_data);
6646 return;
6647 }
6648
6649 caller_snapshot = ast_channel_snapshot_get_latest(queue_data->caller_uniqueid);
6650 member_snapshot = ast_channel_snapshot_get_latest(queue_data->member_uniqueid);
6651
6652 ao2_unlock(queue_data);
6653
6654 ast_debug(3, "Detected attended transfer in queue %s\n", queue_data->queue->name);
6655 log_attended_transfer(queue_data, atxfer_msg);
6656
6657 send_agent_complete(queue_data->queue->name, caller_snapshot, member_snapshot, queue_data->member,
6658 queue_data->holdstart, queue_data->starttime, TRANSFER);
6659 update_queue(queue_data->queue, queue_data->member, queue_data->callcompletedinsl,
6660 queue_data->starttime);
6661 remove_stasis_subscriptions(queue_data);
6662}
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:6277
static int update_queue(struct call_queue *q, struct member *member, int callcompletedinsl, time_t starttime)
update the queue status
Definition: app_queue.c:6120
static void remove_stasis_subscriptions(struct queue_stasis_data *queue_data)
Definition: app_queue.c:6424
static void log_attended_transfer(struct queue_stasis_data *queue_data, struct ast_attended_transfer_message *atxfer_msg)
Definition: app_queue.c:6478
#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:6370
const ast_string_field caller_uniqueid
Definition: app_queue.c:6378
const ast_string_field member_uniqueid
Definition: app_queue.c:6378
struct call_queue * queue
Definition: app_queue.c:6380
const ast_string_field bridge_uniqueid
Definition: app_queue.c:6378
struct member * member
Definition: app_queue.c:6382
#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 6557 of file app_queue.c.

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

6526{
6527 struct queue_stasis_data *queue_data = userdata;
6528 struct ast_bridge_blob *enter_blob = stasis_message_data(msg);
6529 SCOPED_AO2LOCK(lock, queue_data);
6530
6531 if (queue_data->dying) {
6532 return;
6533 }
6534
6535 if (!ast_strlen_zero(queue_data->bridge_uniqueid)) {
6536 return;
6537 }
6538
6539 if (!strcmp(enter_blob->channel->base->uniqueid, queue_data->caller_uniqueid)) {
6540 ast_string_field_set(queue_data, bridge_uniqueid,
6541 enter_blob->bridge->uniqueid);
6542 ast_debug(3, "Detected entry of caller channel %s into bridge %s\n",
6543 enter_blob->channel->base->name, queue_data->bridge_uniqueid);
6544 }
6545}
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 6805 of file app_queue.c.

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

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

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

Referenced by setup_stasis_subs().

◆ handle_local_optimization_end()

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

Definition at line 6741 of file app_queue.c.

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

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

6864{
6865 struct queue_stasis_data *queue_data = userdata;
6866 struct ast_channel_blob *channel_blob = stasis_message_data(msg);
6867 const char *new_channel_id;
6868
6869 new_channel_id = ast_json_string_get(ast_json_object_get(channel_blob->blob, "newchanneluniqueid"));
6870
6871 ao2_lock(queue_data);
6872
6873 if (queue_data->dying) {
6874 ao2_unlock(queue_data);
6875 return;
6876 }
6877
6878 if (!strcmp(channel_blob->snapshot->base->uniqueid, queue_data->caller_uniqueid)) {
6879 ast_debug(1, "Replacing caller channel %s with %s due to masquerade\n", queue_data->caller_uniqueid, new_channel_id);
6880 ast_string_field_set(queue_data, caller_uniqueid, new_channel_id);
6881 } else if (!strcmp(channel_blob->snapshot->base->uniqueid, queue_data->member_uniqueid)) {
6882 ast_debug(1, "Replacing member channel %s with %s due to masquerade\n", queue_data->member_uniqueid, new_channel_id);
6883 ast_string_field_set(queue_data, member_uniqueid, new_channel_id);
6884 }
6885
6886 ao2_unlock(queue_data);
6887}
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 11155 of file app_queue.c.

11156{
11157 const char *queuename, *interface, *membername = NULL, *state_interface = NULL, *reason = NULL;
11158 int penalty, paused = 0;
11159
11160 switch ( cmd ) {
11161 case CLI_INIT:
11162 e->command = "queue add member";
11163 e->usage =
11164 "Usage: queue add member <dial string> to <queue> [penalty <penalty> [as <membername> [state_interface <interface> [paused <reason>]]]]\n"
11165 " 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";
11166 return NULL;
11167 case CLI_GENERATE:
11168 return complete_queue_add_member(a->line, a->word, a->pos, a->n);
11169 }
11170
11171 if ((a->argc != 6) && (a->argc != 8) && (a->argc != 10) && (a->argc != 12) && (a->argc != 14)) {
11172 return CLI_SHOWUSAGE;
11173 } else if (strcmp(a->argv[4], "to")) {
11174 return CLI_SHOWUSAGE;
11175 } else if ((a->argc >= 8) && strcmp(a->argv[6], "penalty")) {
11176 return CLI_SHOWUSAGE;
11177 } else if ((a->argc >= 10) && strcmp(a->argv[8], "as")) {
11178 return CLI_SHOWUSAGE;
11179 } else if ((a->argc == 12) && strcmp(a->argv[10], "state_interface")) {
11180 return CLI_SHOWUSAGE;
11181 } else if ((a->argc == 14) && strcmp(a->argv[12], "paused")) {
11182 return CLI_SHOWUSAGE;
11183 }
11184
11185 queuename = a->argv[5];
11186 interface = a->argv[3];
11187 if (a->argc >= 8) {
11188 if (sscanf(a->argv[7], "%30d", &penalty) == 1) {
11189 if (penalty < 0) {
11190 ast_cli(a->fd, "Penalty must be >= 0\n");
11191 penalty = 0;
11192 }
11193 } else {
11194 ast_cli(a->fd, "Penalty must be an integer >= 0\n");
11195 penalty = 0;
11196 }
11197 } else {
11198 penalty = 0;
11199 }
11200
11201 if (a->argc >= 10) {
11202 membername = a->argv[9];
11203 }
11204
11205 if (a->argc >= 12) {
11206 state_interface = a->argv[11];
11207 }
11208
11209 if (a->argc >= 14) {
11210 paused = 1;
11211 reason = a->argv[13];
11212 }
11213
11214 switch (add_to_queue(queuename, interface, membername, penalty, paused, queue_persistent_members, state_interface, reason, 0)) {
11215 case RES_OKAY:
11216 if (ast_strlen_zero(membername) || !log_membername_as_agent) {
11217 ast_queue_log(queuename, "CLI", interface, "ADDMEMBER", "%s", paused ? "PAUSED" : "");
11218 } else {
11219 ast_queue_log(queuename, "CLI", membername, "ADDMEMBER", "%s", paused ? "PAUSED" : "");
11220 }
11221 ast_cli(a->fd, "Added interface '%s' to queue '%s'\n", interface, queuename);
11222 return CLI_SUCCESS;
11223 case RES_EXISTS:
11224 ast_cli(a->fd, "Unable to add interface '%s' to queue '%s': Already there\n", interface, queuename);
11225 return CLI_FAILURE;
11226 case RES_NOSUCHQUEUE:
11227 ast_cli(a->fd, "Unable to add interface to queue '%s': No such queue\n", queuename);
11228 return CLI_FAILURE;
11229 case RES_OUTOFMEMORY:
11230 ast_cli(a->fd, "Out of memory\n");
11231 return CLI_FAILURE;
11232 case RES_NOT_DYNAMIC:
11233 ast_cli(a->fd, "Member not dynamic\n");
11234 return CLI_FAILURE;
11235 default:
11236 return CLI_FAILURE;
11237 }
11238}
#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:10980
@ 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 11351 of file app_queue.c.

11352{
11353 const char *queuename, *caller;
11354 int priority, immediate = 0;
11355 char *res = CLI_FAILURE;
11356
11357 switch (cmd) {
11358 case CLI_INIT:
11359 e->command = "queue priority caller";
11360 e->usage =
11361 "Usage: queue priority caller <channel> on <queue> to <priority> [immediate]\n"
11362 " Change the priority of a channel on a queue, optionally applying the change in relation to existing callers.\n";
11363 return NULL;
11364 case CLI_GENERATE:
11365 return NULL;
11366 }
11367
11368 if (a->argc < 8) {
11369 return CLI_SHOWUSAGE;
11370 } else if (strcmp(a->argv[4], "on")) {
11371 return CLI_SHOWUSAGE;
11372 } else if (strcmp(a->argv[6], "to")) {
11373 return CLI_SHOWUSAGE;
11374 } else if (sscanf(a->argv[7], "%30d", &priority) != 1) {
11375 ast_log (LOG_ERROR, "<priority> parameter must be an integer.\n");
11376 return CLI_SHOWUSAGE;
11377 } else if (a->argc == 9) {
11378 if (strcmp(a->argv[8], "immediate")) {
11379 return CLI_SHOWUSAGE;
11380 }
11381 immediate = 1;
11382 }
11383
11384 caller = a->argv[3];
11385 queuename = a->argv[5];
11386
11387 switch (change_priority_caller_on_queue(queuename, caller, priority, immediate)) {
11388 case RES_OKAY:
11389 res = CLI_SUCCESS;
11390 break;
11391 case RES_NOSUCHQUEUE:
11392 ast_cli(a->fd, "Unable change priority caller %s on queue '%s': No such queue\n", caller, queuename);
11393 break;
11394 case RES_NOT_CALLER:
11395 ast_cli(a->fd, "Unable to change priority caller '%s' on queue '%s': Not there\n", caller, queuename);
11396
11397 break;
11398 }
11399
11400 return res;
11401}
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:7794

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

11425{
11426 const char *queuename, *interface, *reason;
11427 int paused;
11428
11429 switch (cmd) {
11430 case CLI_INIT:
11431 e->command = "queue {pause|unpause} member";
11432 e->usage =
11433 "Usage: queue {pause|unpause} member <member> [queue <queue> [reason <reason>]]\n"
11434 " Pause or unpause a queue member. Not specifying a particular queue\n"
11435 " will pause or unpause a member across all queues to which the member\n"
11436 " belongs.\n";
11437 return NULL;
11438 case CLI_GENERATE:
11439 return complete_queue_pause_member(a->line, a-> word, a->pos, a->n);
11440 }
11441
11442 if (a->argc < 4 || a->argc == 5 || a->argc == 7 || a->argc > 8) {
11443 return CLI_SHOWUSAGE;
11444 } else if (a->argc >= 5 && strcmp(a->argv[4], "queue")) {
11445 return CLI_SHOWUSAGE;
11446 } else if (a->argc == 8 && strcmp(a->argv[6], "reason")) {
11447 return CLI_SHOWUSAGE;
11448 }
11449
11450
11451 interface = a->argv[3];
11452 queuename = a->argc >= 6 ? a->argv[5] : NULL;
11453 reason = a->argc == 8 ? a->argv[7] : NULL;
11454 paused = !strcasecmp(a->argv[1], "pause");
11455
11456 if (set_member_paused(queuename, interface, reason, paused) == RESULT_SUCCESS) {
11457 ast_cli(a->fd, "%spaused interface '%s'", paused ? "" : "un", interface);
11458 if (!ast_strlen_zero(queuename)) {
11459 ast_cli(a->fd, " in queue '%s'", queuename);
11460 }
11461 if (!ast_strlen_zero(reason)) {
11462 ast_cli(a->fd, " for reason '%s'", reason);
11463 }
11464 ast_cli(a->fd, "\n");
11465 return CLI_SUCCESS;
11466 } else {
11467 ast_cli(a->fd, "Unable to %spause interface '%s'", paused ? "" : "un", interface);
11468 if (!ast_strlen_zero(queuename)) {
11469 ast_cli(a->fd, " in queue '%s'", queuename);
11470 }
11471 if (!ast_strlen_zero(reason)) {
11472 ast_cli(a->fd, " for reason '%s'", reason);
11473 }
11474 ast_cli(a->fd, "\n");
11475 return CLI_FAILURE;
11476 }
11477}
static char * complete_queue_pause_member(const char *line, const char *word, int pos, int state)
Definition: app_queue.c:11405
static int set_member_paused(const char *queuename, const char *interface, const char *reason, int paused)
Definition: app_queue.c:8000
#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 11696 of file app_queue.c.

11697{
11698 struct ast_flags mask = {0,};
11699 int i;
11700
11701 switch (cmd) {
11702 case CLI_INIT:
11703 e->command = "queue reload {parameters|members|rules|all}";
11704 e->usage =
11705 "Usage: queue reload {parameters|members|rules|all} [<queuenames>]\n"
11706 "Reload queues. If <queuenames> are specified, only reload information pertaining\n"
11707 "to <queuenames>. One of 'parameters,' 'members,' 'rules,' or 'all' must be\n"
11708 "specified in order to know what information to reload. Below is an explanation\n"
11709 "of each of these qualifiers.\n"
11710 "\n"
11711 "\t'members' - reload queue members from queues.conf\n"
11712 "\t'parameters' - reload all queue options except for queue members\n"
11713 "\t'rules' - reload the queuerules.conf file\n"
11714 "\t'all' - reload queue rules, parameters, and members\n"
11715 "\n"
11716 "Note: the 'rules' qualifier here cannot actually be applied to a specific queue.\n"
11717 "Use of the 'rules' qualifier causes queuerules.conf to be reloaded. Even if only\n"
11718 "one queue is specified when using this command, reloading queue rules may cause\n"
11719 "other queues to be affected\n";
11720 return NULL;
11721 case CLI_GENERATE:
11722 if (a->pos >= 3) {
11723 /* find the point at which the list of queue names starts */
11724 const char *command_end = a->line + strlen("queue reload ");
11725 command_end = strchr(command_end, ' ');
11726 if (!command_end) {
11727 command_end = a->line + strlen(a->line);
11728 }
11729 return complete_queue(a->line, a->word, a->pos, a->n, command_end - a->line);
11730 } else {
11731 return NULL;
11732 }
11733 }
11734
11735 if (a->argc < 3)
11736 return CLI_SHOWUSAGE;
11737
11738 if (!strcasecmp(a->argv[2], "rules")) {
11740 } else if (!strcasecmp(a->argv[2], "members")) {
11742 } else if (!strcasecmp(a->argv[2], "parameters")) {
11744 } else if (!strcasecmp(a->argv[2], "all")) {
11746 }
11747
11748 if (a->argc == 3) {
11749 reload_handler(1, &mask, NULL);
11750 return CLI_SUCCESS;
11751 }
11752
11753 for (i = 3; i < a->argc; ++i) {
11754 reload_handler(1, &mask, a->argv[i]);
11755 }
11756
11757 return CLI_SUCCESS;
11758}
static int reload_handler(int reload, struct ast_flags *mask, const char *queuename)
The command center for all reload operations.
Definition: app_queue.c:10167
#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 11288 of file app_queue.c.

11289{
11290 const char *queuename, *interface;
11291 struct member *mem = NULL;
11292 char *res = CLI_FAILURE;
11293
11294 switch (cmd) {
11295 case CLI_INIT:
11296 e->command = "queue remove member";
11297 e->usage =
11298 "Usage: queue remove member <channel> from <queue>\n"
11299 " Remove a specific channel from a queue.\n";
11300 return NULL;
11301 case CLI_GENERATE:
11302 return complete_queue_remove_member(a->line, a->word, a->pos, a->n);
11303 }
11304
11305 if (a->argc != 6) {
11306 return CLI_SHOWUSAGE;
11307 } else if (strcmp(a->argv[4], "from")) {
11308 return CLI_SHOWUSAGE;
11309 }
11310
11311 queuename = a->argv[5];
11312 interface = a->argv[3];
11313
11315 mem = find_member_by_queuename_and_interface(queuename, interface);
11316 }
11317
11318 switch (remove_from_queue(queuename, interface)) {
11319 case RES_OKAY:
11320 if (!mem || ast_strlen_zero(mem->membername)) {
11321 ast_queue_log(queuename, "CLI", interface, "REMOVEMEMBER", "%s", "");
11322 } else {
11323 ast_queue_log(queuename, "CLI", mem->membername, "REMOVEMEMBER", "%s", "");
11324 }
11325 ast_cli(a->fd, "Removed interface %s from queue '%s'\n", interface, queuename);
11326 res = CLI_SUCCESS;
11327 break;
11328 case RES_EXISTS:
11329 ast_cli(a->fd, "Unable to remove interface '%s' from queue '%s': Not there\n", interface, queuename);
11330 break;
11331 case RES_NOSUCHQUEUE:
11332 ast_cli(a->fd, "Unable to remove interface from queue '%s': No such queue\n", queuename);
11333 break;
11334 case RES_OUTOFMEMORY:
11335 ast_cli(a->fd, "Out of memory\n");
11336 break;
11337 case RES_NOT_DYNAMIC:
11338 ast_cli(a->fd, "Unable to remove interface '%s' from queue '%s': Member is not dynamic\n", interface, queuename);
11339 break;
11340 }
11341
11342 if (mem) {
11343 ao2_ref(mem, -1);
11344 }
11345
11346 return res;
11347}
static int remove_from_queue(const char *queuename, const char *interface)
Remove member from queue.
Definition: app_queue.c:7688
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:12097
static char * complete_queue_remove_member(const char *line, const char *word, int pos, int state)
Definition: app_queue.c:11240

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

11658{
11659 struct ast_flags mask = {QUEUE_RESET_STATS,};
11660 int i;
11661
11662 switch (cmd) {
11663 case CLI_INIT:
11664 e->command = "queue reset stats";
11665 e->usage =
11666 "Usage: queue reset stats [<queuenames>]\n"
11667 "\n"
11668 "Issuing this command will reset statistics for\n"
11669 "<queuenames>, or for all queues if no queue is\n"
11670 "specified.\n";
11671 return NULL;
11672 case CLI_GENERATE:
11673 if (a->pos >= 3) {
11674 return complete_queue(a->line, a->word, a->pos, a->n, 17);
11675 } else {
11676 return NULL;
11677 }
11678 }
11679
11680 if (a->argc < 3) {
11681 return CLI_SHOWUSAGE;
11682 }
11683
11684 if (a->argc == 3) {
11685 reload_handler(1, &mask, NULL);
11686 return CLI_SUCCESS;
11687 }
11688
11689 for (i = 3; i < a->argc; ++i) {
11690 reload_handler(1, &mask, a->argv[i]);
11691 }
11692
11693 return CLI_SUCCESS;
11694}

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

11623{
11624 const char *rule;
11625 struct rule_list *rl_iter;
11626 struct penalty_rule *pr_iter;
11627 switch (cmd) {
11628 case CLI_INIT:
11629 e->command = "queue show rules";
11630 e->usage =
11631 "Usage: queue show rules [rulename]\n"
11632 " Show the list of rules associated with rulename. If no\n"
11633 " rulename is specified, list all rules defined in queuerules.conf\n";
11634 return NULL;
11635 case CLI_GENERATE:
11636 return complete_queue_rule_show(a->line, a->word, a->pos, a->n);
11637 }
11638
11639 if (a->argc != 3 && a->argc != 4) {
11640 return CLI_SHOWUSAGE;
11641 }
11642
11643 rule = a->argc == 4 ? a->argv[3] : "";
11645 AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) {
11646 if (ast_strlen_zero(rule) || !strcasecmp(rl_iter->name, rule)) {
11647 ast_cli(a->fd, "Rule: %s\n", rl_iter->name);
11648 AST_LIST_TRAVERSE(&rl_iter->rules, pr_iter, list) {
11649 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);
11650 }
11651 }
11652 }
11654 return CLI_SUCCESS;
11655}
static char * complete_queue_rule_show(const char *line, const char *word, int pos, int state)
Definition: app_queue.c:11600

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

11560{
11561 const char *queuename = NULL, *interface;
11562 int penalty = 0;
11563
11564 switch (cmd) {
11565 case CLI_INIT:
11566 e->command = "queue set penalty";
11567 e->usage =
11568 "Usage: queue set penalty <penalty> on <interface> [in <queue>]\n"
11569 " Set a member's penalty in the queue specified. If no queue is specified\n"
11570 " then that interface's penalty is set in all queues to which that interface is a member\n";
11571 return NULL;
11572 case CLI_GENERATE:
11573 return complete_queue_set_member_value(a->line, a->word, a->pos, a->n);
11574 }
11575
11576 if (a->argc != 6 && a->argc != 8) {
11577 return CLI_SHOWUSAGE;
11578 } else if (strcmp(a->argv[4], "on") || (a->argc > 6 && strcmp(a->argv[6], "in"))) {
11579 return CLI_SHOWUSAGE;
11580 }
11581
11582 if (a->argc == 8) {
11583 queuename = a->argv[7];
11584 }
11585 interface = a->argv[5];
11586 penalty = atoi(a->argv[3]);
11587
11588 switch (set_member_value(queuename, interface, MEMBER_PENALTY, penalty)) {
11589 case RESULT_SUCCESS:
11590 ast_cli(a->fd, "Set penalty on interface '%s' from queue '%s'\n", interface, queuename);
11591 return CLI_SUCCESS;
11592 case RESULT_FAILURE:
11593 ast_cli(a->fd, "Failed to set penalty on interface '%s' from queue '%s'\n", interface, queuename);
11594 return CLI_FAILURE;
11595 default:
11596 return CLI_FAILURE;
11597 }
11598}
static int set_member_value(const char *queuename, const char *interface, int property, int value)
Definition: app_queue.c:8148
static char * complete_queue_set_member_value(const char *line, const char *word, int pos, int state)
Definition: app_queue.c:11479

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

11503{
11504 const char *queuename = NULL, *interface;
11505 int ringinuse;
11506
11507 switch (cmd) {
11508 case CLI_INIT:
11509 e->command = "queue set ringinuse";
11510 e->usage =
11511 "Usage: queue set ringinuse <yes/no> on <interface> [in <queue>]\n"
11512 " Set a member's ringinuse in the queue specified. If no queue is specified\n"
11513 " then that interface's penalty is set in all queues to which that interface is a member.\n";
11514 break;
11515 return NULL;
11516 case CLI_GENERATE:
11517 return complete_queue_set_member_value(a->line, a->word, a->pos, a->n);
11518 }
11519
11520 /* Sensible argument counts */
11521 if (a->argc != 6 && a->argc != 8) {
11522 return CLI_SHOWUSAGE;
11523 }
11524
11525 /* Uses proper indicational words */
11526 if (strcmp(a->argv[4], "on") || (a->argc > 6 && strcmp(a->argv[6], "in"))) {
11527 return CLI_SHOWUSAGE;
11528 }
11529
11530 /* Set the queue name if applicable */
11531 if (a->argc == 8) {
11532 queuename = a->argv[7];
11533 }
11534
11535 /* Interface being set */
11536 interface = a->argv[5];
11537
11538 /* Check and set the ringinuse value */
11539 if (ast_true(a->argv[3])) {
11540 ringinuse = 1;
11541 } else if (ast_false(a->argv[3])) {
11542 ringinuse = 0;
11543 } else {
11544 return CLI_SHOWUSAGE;
11545 }
11546
11547 switch (set_member_value(queuename, interface, MEMBER_RINGINUSE, ringinuse)) {
11548 case RESULT_SUCCESS:
11549 ast_cli(a->fd, "Set ringinuse on interface '%s' from queue '%s'\n", interface, queuename);
11550 return CLI_SUCCESS;
11551 case RESULT_FAILURE:
11552 ast_cli(a->fd, "Failed to set ringinuse on interface '%s' from queue '%s'\n", interface, queuename);
11553 return CLI_FAILURE;
11554 default:
11555 return CLI_FAILURE;
11556 }
11557}
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 4617 of file app_queue.c.

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

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

3083{
3084 int i;
3085 struct penalty_rule *pr_iter;
3086
3087 q->dead = 0;
3088 q->retry = DEFAULT_RETRY;
3090 q->maxlen = 0;
3091
3092 ast_string_field_set(q, announce, "");
3094 ast_string_field_set(q, membergosub, "");
3095 ast_string_field_set(q, defaultrule, "");
3096
3097 q->announcefrequency = 0;
3099 q->announceholdtime = 1;
3101 q->announcepositionlimit = 10; /* Default 10 positions */
3102 q->announceposition = ANNOUNCEPOSITION_YES; /* Default yes */
3103 q->roundingseconds = 0; /* Default - don't announce seconds */
3104 q->servicelevel = 0;
3105 q->ringinuse = 1;
3107 q->setinterfacevar = 0;
3108 q->setqueuevar = 0;
3109 q->setqueueentryvar = 0;
3111 q->monfmt[0] = '\0';
3112 q->reportholdtime = 0;
3113 q->wrapuptime = 0;
3114 q->penaltymemberslimit = 0;
3115 q->joinempty = 0;
3116 q->leavewhenempty = 0;
3117 q->memberdelay = 0;
3118 q->weight = 0;
3119 q->timeoutrestart = 0;
3123 q->numperiodicannounce = 0;
3126 q->autopausebusy = 0;
3127 q->autopauseunavail = 0;
3129 q->autopausedelay = 0;
3131 if (!q->members) {
3133 /* linear strategy depends on order, so we have to place all members in a list */
3135 } else {
3138 }
3139 }
3140 q->found = 1;
3141
3142 ast_string_field_set(q, moh, "");
3143 ast_string_field_set(q, sound_next, "queue-youarenext");
3144 ast_string_field_set(q, sound_thereare, "queue-thereare");
3145 ast_string_field_set(q, sound_calls, "queue-callswaiting");
3146 ast_string_field_set(q, queue_quantity1, "queue-quantity1");
3147 ast_string_field_set(q, queue_quantity2, "queue-quantity2");
3148 ast_string_field_set(q, sound_holdtime, "queue-holdtime");
3149 ast_string_field_set(q, sound_minutes, "queue-minutes");
3150 ast_string_field_set(q, sound_minute, "queue-minute");
3151 ast_string_field_set(q, sound_seconds, "queue-seconds");
3152 ast_string_field_set(q, sound_thanks, "queue-thankyou");
3153 ast_string_field_set(q, sound_callerannounce, "");
3154 ast_string_field_set(q, sound_reporthold, "queue-reporthold");
3155
3156 if (!q->sound_periodicannounce[0]) {
3158 }
3159
3160 if (q->sound_periodicannounce[0]) {
3161 ast_str_set(&q->sound_periodicannounce[0], 0, "queue-periodic-announce");
3162 }
3163
3164 for (i = 1; i < MAX_PERIODIC_ANNOUNCEMENTS; i++) {
3165 if (q->sound_periodicannounce[i]) {
3166 ast_str_set(&q->sound_periodicannounce[i], 0, "%s", "");
3167 }
3168 }
3169
3170 while ((pr_iter = AST_LIST_REMOVE_HEAD(&q->rules,list))) {
3171 ast_free(pr_iter);
3172 }
3173
3174 /* On restart assume no members are available.
3175 * The queue_avail hint is a boolean state to indicate whether a member is available or not.
3176 *
3177 * This seems counter intuitive, but is required to light a BLF
3178 * AST_DEVICE_INUSE indicates no members are available.
3179 * AST_DEVICE_NOT_INUSE indicates a member is available.
3180 */
3182}
#define DEFAULT_RETRY
Definition: app_queue.c:1676
static int member_hash_fn(const void *obj, const int flags)
Definition: app_queue.c:3053
static int member_cmp_fn(void *obj1, void *obj2, int flags)
Definition: app_queue.c:3069
#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:1914
@ 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:1977
unsigned int setinterfacevar
Definition: app_queue.c:1963
int announcefrequency
Definition: app_queue.c:1981
unsigned int announceholdtime
Definition: app_queue.c:1969
unsigned int reportholdtime
Definition: app_queue.c:1966
unsigned int setqueueentryvar
Definition: app_queue.c:1965
unsigned int timeoutrestart
Definition: app_queue.c:1968
int periodicannouncefrequency
Definition: app_queue.c:1984
unsigned int announceposition_only_up
Definition: app_queue.c:1971
unsigned int setqueuevar
Definition: app_queue.c:1964
int announcepositionlimit
Definition: app_queue.c:1980
unsigned int announce_to_first_user
Definition: app_queue.c:1962
int randomperiodicannounce
Definition: app_queue.c:1986
int autopause
Definition: app_queue.c:2004
int periodicannouncestartdelay
Definition: app_queue.c:1983
int log_restricted_caller_id
Definition: app_queue.c:2013
struct call_queue::@54 rules
int servicelevel
Definition: app_queue.c:1993
int autofill
Definition: app_queue.c:2011
int minannouncefrequency
Definition: app_queue.c:1982
enum empty_conditions leavewhenempty
Definition: app_queue.c:1979
int roundingseconds
Definition: app_queue.c:1987
int numperiodicannounce
Definition: app_queue.c:1985
unsigned int announceposition
Definition: app_queue.c:1970
char monfmt[8]
Definition: app_queue.c:1995
enum empty_conditions joinempty
Definition: app_queue.c:1978
int memberdelay
Definition: app_queue.c:2010
unsigned int autopausebusy
Definition: app_queue.c:1976
int autopausedelay
Definition: app_queue.c:2005
int timeoutpriority
Definition: app_queue.c:2006
unsigned int relativeperiodicannounce
Definition: app_queue.c:1975

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

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

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

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

2051{
2052 int x;
2053
2054 for (x = 0; x < ARRAY_LEN(strategies); x++) {
2055 if (strategy == strategies[x].strategy) {
2056 return strategies[x].name;
2057 }
2058 }
2059
2060 return "<unknown>";
2061}
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 7606 of file app_queue.c.

7607{
7608 struct member *mem;
7609 struct ao2_iterator mem_iter;
7610
7611 if (!q) {
7612 return NULL;
7613 }
7614 mem_iter = ao2_iterator_init(q->members, 0);
7615 while ((mem = ao2_iterator_next(&mem_iter))) {
7616 if (!strcasecmp(interface, mem->interface)) {
7617 ao2_iterator_destroy(&mem_iter);
7618 return mem;
7619 }
7620 ao2_ref(mem, -1);
7621 }
7622 ao2_iterator_destroy(&mem_iter);
7623
7624 return NULL;
7625}

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

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

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

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

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

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

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

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

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

9902{
9903 struct member *member = obj;
9904
9905 if (!member->delme) {
9907 return 0;
9908 } else {
9909 return CMP_MATCH;
9910 }
9911}
@ CMP_MATCH
Definition: astobj2.h:1027
unsigned int delme
Definition: app_queue.c:1876

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

10057{
10058 struct call_queue *q = obj;
10059 char *queuename = arg;
10060 if (!q->realtime && !q->found && (ast_strlen_zero(queuename) || !strcasecmp(queuename, q->name))) {
10061 q->dead = 1;
10062 return CMP_MATCH;
10063 } else {
10064 return 0;
10065 }
10066}

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

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

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

11931{
11932 int err = 0;
11933 struct ast_flags mask = {AST_FLAGS_ALL, };
11934 struct ast_config *member_config;
11935 struct stasis_topic *queue_topic;
11937
11940 if (!queues) {
11942 }
11943
11946 if (!pending_members) {
11947 unload_module();
11949 }
11950
11951 use_weight = 0;
11952
11953 if (reload_handler(0, &mask, NULL)) {
11954 unload_module();
11956 }
11957
11958 ast_realtime_require_field("queue_members", "paused", RQ_INTEGER1, 1, "uniqueid", RQ_UINTEGER2, 5, "reason_paused", RQ_CHAR, 80, SENTINEL);
11959
11960 /*
11961 * This section is used to determine which name for 'ringinuse' to use in realtime members
11962 * Necessary for supporting older setups.
11963 *
11964 * It also checks if 'reason_paused' exists in the realtime backend
11965 */
11966 member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name LIKE", "%", SENTINEL);
11967 if (!member_config) {
11968 realtime_ringinuse_field = "ringinuse";
11969 } else {
11970 const char *config_val;
11971
11972 if ((config_val = ast_variable_retrieve(member_config, NULL, "ringinuse"))) {
11973 ast_log(LOG_NOTICE, "ringinuse field entries found in queue_members table. Using 'ringinuse'\n");
11974 realtime_ringinuse_field = "ringinuse";
11975 } else if ((config_val = ast_variable_retrieve(member_config, NULL, "ignorebusy"))) {
11976 ast_log(LOG_NOTICE, "ignorebusy field found in queue_members table with no ringinuse field. Using 'ignorebusy'\n");
11977 realtime_ringinuse_field = "ignorebusy";
11978 } else {
11979 ast_log(LOG_NOTICE, "No entries were found for ringinuse/ignorebusy in queue_members table. Using 'ringinuse'\n");
11980 realtime_ringinuse_field = "ringinuse";
11981 }
11982
11983 if (ast_variable_retrieve(member_config, NULL, "reason_paused")) {
11985 }
11986 }
11987 ast_config_destroy(member_config);
11988
11991 }
11992
12001 err |= ast_manager_register_xml("QueueStatus", 0, manager_queues_status);
12002 err |= ast_manager_register_xml("QueueSummary", 0, manager_queues_summary);
12009 err |= ast_manager_register_xml("QueueRule", 0, manager_queue_rule_show);
12010 err |= ast_manager_register_xml("QueueReload", 0, manager_queue_reload);
12011 err |= ast_manager_register_xml("QueueReset", 0, manager_queue_reset);
12012 err |= ast_manager_register_xml("QueueChangePriorityCaller", 0, manager_change_priority_caller_on_queue);
12021
12022 /* in the following subscribe call, do I use DEVICE_STATE, or DEVICE_STATE_CHANGE? */
12024 if (!device_state_sub) {
12025 err = -1;
12026 }
12029
12031 queue_topic = ast_queue_topic_all();
12032 if (!manager_topic || !queue_topic) {
12033 unload_module();
12035 }
12037 if (!topic_forwarder) {
12038 unload_module();
12040 }
12041
12044 unload_module();
12046 }
12048 if (!agent_router) {
12049 unload_module();
12051 }
12055 NULL);
12059 NULL);
12060
12061 err |= STASIS_MESSAGE_TYPE_INIT(queue_caller_join_type);
12062 err |= STASIS_MESSAGE_TYPE_INIT(queue_caller_leave_type);
12063 err |= STASIS_MESSAGE_TYPE_INIT(queue_caller_abandon_type);
12064
12065 err |= STASIS_MESSAGE_TYPE_INIT(queue_member_status_type);
12066 err |= STASIS_MESSAGE_TYPE_INIT(queue_member_added_type);
12067 err |= STASIS_MESSAGE_TYPE_INIT(queue_member_removed_type);
12068 err |= STASIS_MESSAGE_TYPE_INIT(queue_member_pause_type);
12069 err |= STASIS_MESSAGE_TYPE_INIT(queue_member_penalty_type);
12070 err |= STASIS_MESSAGE_TYPE_INIT(queue_member_ringinuse_type);
12071
12072 err |= STASIS_MESSAGE_TYPE_INIT(queue_agent_called_type);
12073 err |= STASIS_MESSAGE_TYPE_INIT(queue_agent_connect_type);
12074 err |= STASIS_MESSAGE_TYPE_INIT(queue_agent_complete_type);
12075 err |= STASIS_MESSAGE_TYPE_INIT(queue_agent_dump_type);
12076 err |= STASIS_MESSAGE_TYPE_INIT(queue_agent_ringnoanswer_type);
12077
12078 if (err) {
12079 unload_module();
12081 }
12083}
static struct ast_custom_function queuevar_function
Definition: app_queue.c:9597
static int manager_queue_reset(struct mansession *s, const struct message *m)
Definition: app_queue.c:10965
static int pending_members_cmp(void *obj, void *arg, int flags)
Definition: app_queue.c:2669
static struct ast_custom_function queuemembercount_function
Definition: app_queue.c:9602
static struct ast_custom_function queuewaitingcount_function
Definition: app_queue.c:9613
static char * app_pqm
Definition: app_queue.c:1701
static struct ast_custom_function queuememberlist_function
Definition: app_queue.c:9618
static char * realtime_ringinuse_field
name of the ringinuse field in the realtime database
Definition: app_queue.c:1746
static int manager_add_queue_member(struct mansession *s, const struct message *m)
Definition: app_queue.c:10775
static int aqm_exec(struct ast_channel *chan, const char *data)
AddQueueMember application.
Definition: app_queue.c:8502
#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:8395
static void queue_agent_cb(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Definition: app_queue.c:6308
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:8248
static int rqm_exec(struct ast_channel *chan, const char *data)
RemoveQueueMember application.
Definition: app_queue.c:8431
#define MAX_CALL_ATTEMPT_BUCKETS
Definition: app_queue.c:2647
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:10534
static int manager_queue_reload(struct mansession *s, const struct message *m)
Definition: app_queue.c:10933
static int pqm_exec(struct ast_channel *chan, const char *data)
PauseQueueMember application.
Definition: app_queue.c:8359
static int qupd_exec(struct ast_channel *chan, const char *data)
Update Queue with data of an outgoing call.
Definition: app_queue.c:11763
static int manager_queue_member_ringinuse(struct mansession *s, const struct message *m)
Definition: app_queue.c:11011
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:11045
static char * app_upqm
Definition: app_queue.c:1703
static struct ast_custom_function queuememberpenalty_function
Definition: app_queue.c:9623
static int queue_cmp_cb(void *obj, void *arg, int flags)
Definition: app_queue.c:2106
static int manager_request_withdraw_caller_from_queue(struct mansession *s, const struct message *m)
Definition: app_queue.c:11118
static char * app
Definition: app_queue.c:1695
static int queue_hash_cb(const void *obj, const int flags)
Definition: app_queue.c:2099
static int queue_exec(struct ast_channel *chan, const char *data)
The starting point for all queue calls.
Definition: app_queue.c:8673
static int pending_members_hash(const void *obj, const int flags)
Definition: app_queue.c:2649
static int manager_pause_queue_member(struct mansession *s, const struct message *m)
Definition: app_queue.c:10887
static int ql_exec(struct ast_channel *chan, const char *data)
QueueLog application.
Definition: app_queue.c:8596
static int manager_remove_queue_member(struct mansession *s, const struct message *m)
Definition: app_queue.c:10840
static struct stasis_message_router * agent_router
Definition: app_queue.c:11853
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:2774
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:10570
static int unload_module(void)
Definition: app_queue.c:11856
static int manager_queues_status(struct mansession *s, const struct message *m)
Queue status info via AMI.
Definition: app_queue.c:10652
static int realtime_reason_paused
does realtime backend support reason_paused
Definition: app_queue.c:1749
static char * app_aqm
Definition: app_queue.c:1697
static struct ast_cli_entry cli_queue[]
Definition: app_queue.c:11840
static struct ast_custom_function queuegetchannel_function
Definition: app_queue.c:9608
static struct stasis_forward * topic_forwarder
Definition: app_queue.c:11854
static struct ast_custom_function queueexists_function
Definition: app_queue.c:9592
static int manager_change_priority_caller_on_queue(struct mansession *s, const struct message *m)
Definition: app_queue.c:11071
static int manager_queue_log_custom(struct mansession *s, const struct message *m)
Definition: app_queue.c:10912
#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:3781
#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:1050
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:1104
#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:1605
#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 4104 of file app_queue.c.

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

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

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

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

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

10776{
10777 const char *queuename, *interface, *penalty_s, *paused_s, *reason, *membername, *state_interface, *wrapuptime_s;
10778 int paused, penalty, wrapuptime = 0;
10779
10780 queuename = astman_get_header(m, "Queue");
10781 interface = astman_get_header(m, "Interface");
10782 penalty_s = astman_get_header(m, "Penalty");
10783 paused_s = astman_get_header(m, "Paused");
10784 reason = astman_get_header(m, "Reason"); /* Optional */
10785 membername = astman_get_header(m, "MemberName");
10786 state_interface = astman_get_header(m, "StateInterface");
10787 wrapuptime_s = astman_get_header(m, "Wrapuptime");
10788
10789 if (ast_strlen_zero(queuename)) {
10790 astman_send_error(s, m, "'Queue' not specified.");
10791 return 0;
10792 }
10793
10794 if (ast_strlen_zero(interface)) {
10795 astman_send_error(s, m, "'Interface' not specified.");
10796 return 0;
10797 }
10798
10799 if (ast_strlen_zero(penalty_s)) {
10800 penalty = 0;
10801 } else if (sscanf(penalty_s, "%30d", &penalty) != 1 || penalty < 0) {
10802 penalty = 0;
10803 }
10804
10805 if (ast_strlen_zero(wrapuptime_s)) {
10806 wrapuptime = 0;
10807 } else if (sscanf(wrapuptime_s, "%30d", &wrapuptime) != 1 || wrapuptime < 0) {
10808 wrapuptime = 0;
10809 }
10810
10811 if (ast_strlen_zero(paused_s)) {
10812 paused = 0;
10813 } else {
10814 paused = abs(ast_true(paused_s));
10815 }
10816
10817 switch (add_to_queue(queuename, interface, membername, penalty, paused, queue_persistent_members, state_interface, reason, wrapuptime)) {
10818 case RES_OKAY:
10819 if (ast_strlen_zero(membername) || !log_membername_as_agent) {
10820 ast_queue_log(queuename, "MANAGER", interface, "ADDMEMBER", "%s", paused ? "PAUSED" : "");
10821 } else {
10822 ast_queue_log(queuename, "MANAGER", membername, "ADDMEMBER", "%s", paused ? "PAUSED" : "");
10823 }
10824 astman_send_ack(s, m, "Added interface to queue");
10825 break;
10826 case RES_EXISTS:
10827 astman_send_error(s, m, "Unable to add interface: Already there");
10828 break;
10829 case RES_NOSUCHQUEUE:
10830 astman_send_error(s, m, "Unable to add interface to queue: No such queue");
10831 break;
10832 case RES_OUTOFMEMORY:
10833 astman_send_error(s, m, "Out of memory");
10834 break;
10835 }
10836
10837 return 0;
10838}
#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 11071 of file app_queue.c.

11072{
11073 const char *queuename, *caller, *priority_s, *immediate_s;
11074 int priority = 0, immediate = 0;
11075
11076 queuename = astman_get_header(m, "Queue");
11077 caller = astman_get_header(m, "Caller");
11078 priority_s = astman_get_header(m, "Priority");
11079 immediate_s = astman_get_header(m, "Immediate");
11080
11081 if (ast_strlen_zero(queuename)) {
11082 astman_send_error(s, m, "'Queue' not specified.");
11083 return 0;
11084 }
11085
11086 if (ast_strlen_zero(caller)) {
11087 astman_send_error(s, m, "'Caller' not specified.");
11088 return 0;
11089 }
11090
11091 if (ast_strlen_zero(priority_s)) {
11092 astman_send_error(s, m, "'Priority' not specified.");
11093 return 0;
11094 } else if (sscanf(priority_s, "%30d", &priority) != 1) {
11095 astman_send_error(s, m, "'Priority' need integer.");
11096 return 0;
11097 }
11098
11099 if (!ast_strlen_zero(immediate_s)) {
11100 immediate = ast_true(immediate_s);
11101 }
11102
11103 switch (change_priority_caller_on_queue(queuename, caller, priority, immediate)) {
11104 case RES_OKAY:
11105 astman_send_ack(s, m, "Priority change for caller on queue");
11106 break;
11107 case RES_NOSUCHQUEUE:
11108 astman_send_error(s, m, "Unable to change priority caller on queue: No such queue");
11109 break;
11110 case RES_NOT_CALLER:
11111 astman_send_error(s, m, "Unable to change priority caller on queue: No such caller");
11112 break;
11113 }
11114
11115 return 0;
11116}

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

10888{
10889 const char *queuename, *interface, *paused_s, *reason;
10890 int paused;
10891
10892 interface = astman_get_header(m, "Interface");
10893 paused_s = astman_get_header(m, "Paused");
10894 queuename = astman_get_header(m, "Queue"); /* Optional - if not supplied, pause the given Interface in all queues */
10895 reason = astman_get_header(m, "Reason"); /* Optional */
10896
10897 if (ast_strlen_zero(interface) || ast_strlen_zero(paused_s)) {
10898 astman_send_error(s, m, "Need 'Interface' and 'Paused' parameters.");
10899 return 0;
10900 }
10901
10902 paused = abs(ast_true(paused_s));
10903
10904 if (set_member_paused(queuename, interface, reason, paused)) {
10905 astman_send_error(s, m, "Interface not found");
10906 } else {
10907 astman_send_ack(s, m, paused ? "Interface paused successfully" : "Interface unpaused successfully");
10908 }
10909 return 0;
10910}

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

10913{
10914 const char *queuename, *event, *message, *interface, *uniqueid;
10915
10916 queuename = astman_get_header(m, "Queue");
10917 uniqueid = astman_get_header(m, "UniqueId");
10918 interface = astman_get_header(m, "Interface");
10919 event = astman_get_header(m, "Event");
10920 message = astman_get_header(m, "Message");
10921
10922 if (ast_strlen_zero(queuename) || ast_strlen_zero(event)) {
10923 astman_send_error(s, m, "Need 'Queue' and 'Event' parameters.");
10924 return 0;
10925 }
10926
10927 ast_queue_log(queuename, S_OR(uniqueid, "NONE"), interface, event, "%s", message);
10928 astman_send_ack(s, m, "Event added successfully");
10929
10930 return 0;
10931}
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 11045 of file app_queue.c.

11046{
11047 const char *queuename, *interface, *penalty_s;
11048 int penalty;
11049
11050 interface = astman_get_header(m, "Interface");
11051 penalty_s = astman_get_header(m, "Penalty");
11052 /* Optional - if not supplied, set the penalty value for the given Interface in all queues */
11053 queuename = astman_get_header(m, "Queue");
11054
11055 if (ast_strlen_zero(interface) || ast_strlen_zero(penalty_s)) {
11056 astman_send_error(s, m, "Need 'Interface' and 'Penalty' parameters.");
11057 return 0;
11058 }
11059
11060 penalty = atoi(penalty_s);
11061
11062 if (set_member_value((char *)queuename, (char *)interface, MEMBER_PENALTY, penalty)) {
11063 astman_send_error(s, m, "Invalid interface, queuename or penalty");
11064 } else {
11065 astman_send_ack(s, m, "Interface penalty set successfully");
11066 }
11067
11068 return 0;
11069}

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

11012{
11013 const char *queuename, *interface, *ringinuse_s;
11014 int ringinuse;
11015
11016 interface = astman_get_header(m, "Interface");
11017 ringinuse_s = astman_get_header(m, "RingInUse");
11018
11019 /* Optional - if not supplied, set the ringinuse value for the given Interface in all queues */
11020 queuename = astman_get_header(m, "Queue");
11021
11022 if (ast_strlen_zero(interface) || ast_strlen_zero(ringinuse_s)) {
11023 astman_send_error(s, m, "Need 'Interface' and 'RingInUse' parameters.");
11024 return 0;
11025 }
11026
11027 if (ast_true(ringinuse_s)) {
11028 ringinuse = 1;
11029 } else if (ast_false(ringinuse_s)) {
11030 ringinuse = 0;
11031 } else {
11032 astman_send_error(s, m, "'RingInUse' parameter must be a truth value (yes/no, on/off, 0/1, etc)");
11033 return 0;
11034 }
11035
11036 if (set_member_value(queuename, interface, MEMBER_RINGINUSE, ringinuse)) {
11037 astman_send_error(s, m, "Invalid interface, queuename, or ringinuse value\n");
11038 } else {
11039 astman_send_ack(s, m, "Interface ringinuse set successfully");
11040 }
11041
11042 return 0;
11043}

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

10934{
10935 struct ast_flags mask = {0,};
10936 const char *queuename = NULL;
10937 int header_found = 0;
10938
10939 queuename = astman_get_header(m, "Queue");
10940 if (!strcasecmp(S_OR(astman_get_header(m, "Members"), ""), "yes")) {
10942 header_found = 1;
10943 }
10944 if (!strcasecmp(S_OR(astman_get_header(m, "Rules"), ""), "yes")) {
10946 header_found = 1;
10947 }
10948 if (!strcasecmp(S_OR(astman_get_header(m, "Parameters"), ""), "yes")) {
10950 header_found = 1;
10951 }
10952
10953 if (!header_found) {
10955 }
10956
10957 if (!reload_handler(1, &mask, queuename)) {
10958 astman_send_ack(s, m, "Queue reloaded successfully");
10959 } else {
10960 astman_send_error(s, m, "Error encountered while reloading queue");
10961 }
10962 return 0;
10963}

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

10966{
10967 const char *queuename = NULL;
10968 struct ast_flags mask = {QUEUE_RESET_STATS,};
10969
10970 queuename = astman_get_header(m, "Queue");
10971
10972 if (!reload_handler(1, &mask, queuename)) {
10973 astman_send_ack(s, m, "Queue stats reset successfully");
10974 } else {
10975 astman_send_error(s, m, "Error encountered while resetting queue stats");
10976 }
10977 return 0;
10978}

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

10535{
10536 const char *rule = astman_get_header(m, "Rule");
10537 const char *id = astman_get_header(m, "ActionID");
10538 struct rule_list *rl_iter;
10539 struct penalty_rule *pr_iter;
10540
10541 astman_append(s, "Response: Success\r\n");
10542 if (!ast_strlen_zero(id)) {
10543 astman_append(s, "ActionID: %s\r\n", id);
10544 }
10545
10547 AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) {
10548 if (ast_strlen_zero(rule) || !strcasecmp(rule, rl_iter->name)) {
10549 astman_append(s, "RuleList: %s\r\n", rl_iter->name);
10550 AST_LIST_TRAVERSE(&rl_iter->rules, pr_iter, list) {
10551 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 );
10552 }
10553 if (!ast_strlen_zero(rule)) {
10554 break;
10555 }
10556 }
10557 }
10559
10560 /*
10561 * Two blank lines instead of one because the Response and
10562 * ActionID headers used to not be present.
10563 */
10564 astman_append(s, "\r\n\r\n");
10565
10566 return RESULT_SUCCESS;
10567}

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

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

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

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

10841{
10842 const char *queuename, *interface;
10843 struct member *mem = NULL;
10844
10845 queuename = astman_get_header(m, "Queue");
10846 interface = astman_get_header(m, "Interface");
10847
10848 if (ast_strlen_zero(queuename) || ast_strlen_zero(interface)) {
10849 astman_send_error(s, m, "Need 'Queue' and 'Interface' parameters.");
10850 return 0;
10851 }
10852
10854 mem = find_member_by_queuename_and_interface(queuename, interface);
10855 }
10856
10857 switch (remove_from_queue(queuename, interface)) {
10858 case RES_OKAY:
10859 if (!mem || ast_strlen_zero(mem->membername)) {
10860 ast_queue_log(queuename, "MANAGER", interface, "REMOVEMEMBER", "%s", "");
10861 } else {
10862 ast_queue_log(queuename, "MANAGER", mem->membername, "REMOVEMEMBER", "%s", "");
10863 }
10864 astman_send_ack(s, m, "Removed interface from queue");
10865 break;
10866 case RES_EXISTS:
10867 astman_send_error(s, m, "Unable to remove interface: Not there");
10868 break;
10869 case RES_NOSUCHQUEUE:
10870 astman_send_error(s, m, "Unable to remove interface from queue: No such queue");
10871 break;
10872 case RES_OUTOFMEMORY:
10873 astman_send_error(s, m, "Out of memory");
10874 break;
10875 case RES_NOT_DYNAMIC:
10876 astman_send_error(s, m, "Member not dynamic");
10877 break;
10878 }
10879
10880 if (mem) {
10881 ao2_ref(mem, -1);
10882 }
10883
10884 return 0;
10885}

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

11119{
11120 const char *queuename, *caller, *withdraw_info;
11121
11122 queuename = astman_get_header(m, "Queue");
11123 caller = astman_get_header(m, "Caller");
11124 withdraw_info = astman_get_header(m, "WithdrawInfo");
11125
11126 if (ast_strlen_zero(queuename)) {
11127 astman_send_error(s, m, "'Queue' not specified.");
11128 return 0;
11129 }
11130
11131 if (ast_strlen_zero(caller)) {
11132 astman_send_error(s, m, "'Caller' not specified.");
11133 return 0;
11134 }
11135
11136 switch (request_withdraw_caller_from_queue(queuename, caller, withdraw_info)) {
11137 case RES_OKAY:
11138 astman_send_ack(s, m, "Withdraw requested successfully");
11139 break;
11140 case RES_NOSUCHQUEUE:
11141 astman_send_error(s, m, "Unable to request withdraw from queue: No such queue");
11142 break;
11143 case RES_NOT_CALLER:
11144 astman_send_error(s, m, "Unable to request withdraw from queue: No such caller");
11145 break;
11146 case RES_EXISTS:
11147 astman_send_error(s, m, "Unable to request withdraw from queue: Already requested");
11148 break;
11149 }
11150
11151 return 0;
11152}
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:7870

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

9893{
9894 struct member *member = obj;
9895 if (!member->dynamic && !member->realtime) {
9896 member->delme = 1;
9897 }
9898 return 0;
9899}

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

10047{
10048 struct call_queue *q = obj;
10049 char *queuename = arg;
10050 if (!q->realtime && (ast_strlen_zero(queuename) || !strcasecmp(queuename, q->name))) {
10051 q->found = 0;
10052 }
10053 return 0;
10054}

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

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

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

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

3711{
3713 ao2_lock(queue->members);
3716 ao2_unlink(queue->members, mem);
3717 ao2_unlock(queue->members);
3718}
static void queue_member_follower_removal(struct call_queue *queue, struct member *mem)
Definition: app_queue.c:2170
#define QUEUE_UNKNOWN_PAUSED_DEVSTATE
Definition: app_queue.c:3686
#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 4791 of file app_queue.c.

4792{
4794}

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

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

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

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

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

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

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

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

4292{
4293 int res;
4294
4295 if (ast_strlen_zero(filename)) {
4296 return 0;
4297 }
4298
4299 if (!ast_fileexists(filename, NULL, ast_channel_language(chan))) {
4300 return 0;
4301 }
4302
4303 ast_stopstream(chan);
4304
4305 res = ast_streamfile(chan, filename, ast_channel_language(chan));
4306 if (!res) {
4307 res = ast_waitstream(chan, AST_DIGIT_ANY);
4308 }
4309
4310 ast_stopstream(chan);
4311
4312 return res;
4313}
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 8359 of file app_queue.c.

8360{
8361 char *parse;
8363 AST_APP_ARG(queuename);
8364 AST_APP_ARG(interface);
8366 AST_APP_ARG(reason);
8367 );
8368
8369 if (ast_strlen_zero(data)) {
8370 ast_log(LOG_WARNING, "PauseQueueMember requires an argument ([queuename],interface[,options][,reason])\n");
8371 return -1;
8372 }
8373
8374 parse = ast_strdupa(data);
8375
8377
8378 if (ast_strlen_zero(args.interface)) {
8379 ast_log(LOG_WARNING, "Missing interface argument to PauseQueueMember ([queuename],interface[,options[,reason]])\n");
8380 return -1;
8381 }
8382
8383 if (set_member_paused(args.queuename, args.interface, args.reason, 1)) {
8384 ast_log(LOG_WARNING, "Attempt to pause interface %s, not found\n", args.interface);
8385 pbx_builtin_setvar_helper(chan, "PQMSTATUS", "NOTFOUND");
8386 return 0;
8387 }
8388
8389 pbx_builtin_setvar_helper(chan, "PQMSTATUS", "PAUSED");
8390
8391 return 0;
8392}

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

10195{
10196 float sl;
10197 float sl2;
10198 struct ao2_iterator mem_iter;
10199 struct ast_str *out = ast_str_alloca(512);
10200 time_t now = time(NULL);
10201
10202 ast_str_set(&out, 0, "%s has %d calls (max ", q->name, q->count);
10203 if (q->maxlen) {
10204 ast_str_append(&out, 0, "%d", q->maxlen);
10205 } else {
10206 ast_str_append(&out, 0, "unlimited");
10207 }
10208 sl = 0;
10209 sl2 = 0;
10210 if (q->callscompleted > 0) {
10211 sl = 100 * ((float) q->callscompletedinsl / (float) q->callscompleted);
10212 }
10213 if (q->callscompleted + q->callsabandoned > 0) {
10214 sl2 =100 * (((float)q->callsabandonedinsl + (float)q->callscompletedinsl) / ((float)q->callsabandoned + (float)q->callscompleted));
10215 }
10216
10217 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",
10219 do_print(s, fd, ast_str_buffer(out));
10220 if (!ao2_container_count(q->members)) {
10221 do_print(s, fd, " No Members");
10222 } else {
10223 struct member *mem;
10224
10225 do_print(s, fd, " Members: ");
10226 mem_iter = ao2_iterator_init(q->members, 0);
10227 while ((mem = ao2_iterator_next(&mem_iter))) {
10228 ast_str_set(&out, 0, " %s", mem->membername);
10229 if (strcasecmp(mem->membername, mem->interface)) {
10230 ast_str_append(&out, 0, " (%s", mem->interface);
10232 && strcmp(mem->state_interface, mem->interface)) {
10233 ast_str_append(&out, 0, " from %s", mem->state_interface);
10234 }
10235 ast_str_append(&out, 0, ")");
10236 }
10237 if (mem->penalty) {
10238 ast_str_append(&out, 0, " with penalty %d", mem->penalty);
10239 }
10240
10241 ast_str_append(&out, 0, " (ringinuse %s)", mem->ringinuse ? "enabled" : "disabled");
10242
10243 ast_str_append(&out, 0, "%s%s%s%s%s%s%s%s%s",
10244 mem->dynamic ? ast_term_color(COLOR_CYAN, COLOR_BLACK) : "", mem->dynamic ? " (dynamic)" : "", ast_term_reset(),
10245 mem->realtime ? ast_term_color(COLOR_MAGENTA, COLOR_BLACK) : "", mem->realtime ? " (realtime)" : "", ast_term_reset(),
10246 mem->starttime ? ast_term_color(COLOR_BROWN, COLOR_BLACK) : "", mem->starttime ? " (in call)" : "", ast_term_reset());
10247
10248 if (mem->paused) {
10249 ast_str_append(&out, 0, " %s(paused%s%s was %ld secs ago)%s",
10251 ast_strlen_zero(mem->reason_paused) ? "" : ":",
10253 (long) (now - mem->lastpause),
10254 ast_term_reset());
10255 }
10256
10257 ast_str_append(&out, 0, " (%s%s%s)",
10262 if (mem->calls) {
10263 ast_str_append(&out, 0, " has taken %d calls (last was %ld secs ago)",
10264 mem->calls, (long) (now - mem->lastcall));
10265 } else {
10266 ast_str_append(&out, 0, " has taken no calls yet");
10267 }
10268 ast_str_append(&out, 0, " %s(login was %ld secs ago)%s",
10270 (long) (now - mem->logintime),
10271 ast_term_reset());
10272 do_print(s, fd, ast_str_buffer(out));
10273 ao2_ref(mem, -1);
10274 }
10275 ao2_iterator_destroy(&mem_iter);
10276 }
10277 if (!q->head) {
10278 do_print(s, fd, " No Callers");
10279 } else {
10280 struct queue_ent *qe;
10281 int pos = 1;
10282
10283 do_print(s, fd, " Callers: ");
10284 for (qe = q->head; qe; qe = qe->next) {
10285 ast_str_set(&out, 0, " %d. %s (wait: %ld:%2.2ld, prio: %d)",
10286 pos++, ast_channel_name(qe->chan), (long) (now - qe->start) / 60,
10287 (long) (now - qe->start) % 60, qe->prio);
10288 do_print(s, fd, ast_str_buffer(out));
10289 }
10290 }
10291 do_print(s, fd, ""); /* blank line between entries */
10292}
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 4605 of file app_queue.c.

4606{
4607 struct callattempt *cur;
4608
4609 for (cur = outgoing; cur; cur = cur->q_next) {
4610 if (cur->chan && cur->chan != exception) {
4612 }
4613 }
4614}
struct callattempt * q_next
Definition: app_queue.c:1796
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 7909 of file app_queue.c.

7910{
7911 struct ast_json *json_blob = queue_member_blob_create(q, member);
7912
7913 if (!json_blob) {
7914 return -1;
7915 }
7916
7917 queue_publish_member_blob(queue_member_pause_type(), json_blob);
7918
7919 return 0;
7920}

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

8597{
8598 char *parse;
8599
8601 AST_APP_ARG(queuename);
8602 AST_APP_ARG(uniqueid);
8603 AST_APP_ARG(membername);
8605 AST_APP_ARG(params);
8606 );
8607
8608 if (ast_strlen_zero(data)) {
8609 ast_log(LOG_WARNING, "QueueLog requires arguments (queuename,uniqueid,membername,event[,additionalinfo]\n");
8610 return -1;
8611 }
8612
8613 parse = ast_strdupa(data);
8614
8616
8617 if (ast_strlen_zero(args.queuename) || ast_strlen_zero(args.uniqueid)
8618 || ast_strlen_zero(args.membername) || ast_strlen_zero(args.event)) {
8619 ast_log(LOG_WARNING, "QueueLog requires arguments (queuename,uniqueid,membername,event[,additionalinfo])\n");
8620 return -1;
8621 }
8622
8623 ast_queue_log(args.queuename, args.uniqueid, args.membername, args.event,
8624 "%s", args.params ? args.params : "");
8625
8626 return 0;
8627}

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

2393{
2394 return queue_multi_channel_to_ami("AgentCalled", message);
2395}
static struct ast_manager_event_blob * queue_multi_channel_to_ami(const char *type, struct stasis_message *message)
Definition: app_queue.c:2351

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

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

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

2403{
2404 return queue_multi_channel_to_ami("AgentComplete", message);
2405}

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

2398{
2399 return queue_multi_channel_to_ami("AgentConnect", message);
2400}

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

2408{
2409 return queue_multi_channel_to_ami("AgentDump", message);
2410}

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

2413{
2414 return queue_multi_channel_to_ami("AgentRingNoAnswer", message);
2415}

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

6673{
6675 ao2_cleanup(userdata);
6676 }
6677}
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:1201

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

2273{
2274 return queue_channel_to_ami("QueueCallerAbandon", message);
2275}
static struct ast_manager_event_blob * queue_channel_to_ami(const char *type, struct stasis_message *message)
Definition: app_queue.c:2243

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

2263{
2264 return queue_channel_to_ami("QueueCallerJoin", message);
2265}

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

2268{
2269 return queue_channel_to_ami("QueueCallerLeave", message);
2270}

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

6898{
6900 ao2_cleanup(userdata);
6901 }
6902}

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

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

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

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

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

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

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

9158{
9159 struct call_queue *q;
9160
9161 buf[0] = '\0';
9162
9163 if (ast_strlen_zero(data)) {
9164 ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd);
9165 return -1;
9166 }
9168 snprintf(buf, len, "%d", q != NULL? 1 : 0);
9169 if (q) {
9170 queue_t_unref(q, "Done with temporary reference in QUEUE_EXISTS()");
9171 }
9172
9173 return 0;
9174}
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 9199 of file app_queue.c.

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

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

9302{
9303 int memvalue;
9304
9306 AST_APP_ARG(queuename);
9307 AST_APP_ARG(option);
9308 AST_APP_ARG(interface);
9309 );
9310
9311 if (ast_strlen_zero(data)) {
9313 "Missing required argument. %s([<queuename>],<option>,<interface>)\n",
9314 cmd);
9315 return -1;
9316 }
9317
9319
9320 if (ast_strlen_zero(args.option)
9321 || ast_strlen_zero(args.interface)) {
9323 "Missing required argument. %s([<queuename>],<option>,<interface>)\n",
9324 cmd);
9325 return -1;
9326 }
9327
9328 /*
9329 * If queuename is empty then the option will be
9330 * set for the interface in all queues.
9331 */
9332
9333 memvalue = atoi(value);
9334 if (!strcasecmp(args.option, "penalty")) {
9335 if (set_member_value(args.queuename, args.interface, MEMBER_PENALTY, memvalue)) {
9336 ast_log(LOG_ERROR, "Invalid interface, queue, or penalty\n");
9337 return -1;
9338 }
9339 } else if (!strcasecmp(args.option, "paused")) {
9340 memvalue = (memvalue <= 0) ? 0 : 1;
9341 if (set_member_paused(args.queuename, args.interface, NULL, memvalue)) {
9342 ast_log(LOG_ERROR, "Invalid interface or queue\n");
9343 return -1;
9344 }
9345 } else if (!strcasecmp(args.option, "ignorebusy") /* ignorebusy is legacy */
9346 || !strcasecmp(args.option, "ringinuse")) {
9347 memvalue = (memvalue <= 0) ? 0 : 1;
9348 if (set_member_value(args.queuename, args.interface, MEMBER_RINGINUSE, memvalue)) {
9349 ast_log(LOG_ERROR, "Invalid interface or queue\n");
9350 return -1;
9351 }
9352 } else {
9353 ast_log(LOG_ERROR, "%s: Invalid option '%s' provided.\n", cmd, args.option);
9354 return -1;
9355 }
9356 return 0;
9357}

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

9525{
9526 int penalty;
9528 AST_APP_ARG(queuename);
9529 AST_APP_ARG(interface);
9530 );
9531 /* Make sure the returned value on error is NULL. */
9532 buf[0] = '\0';
9533
9534 if (ast_strlen_zero(data)) {
9535 ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n");
9536 return -1;
9537 }
9538
9540
9541 if (args.argc < 2) {
9542 ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n");
9543 return -1;
9544 }
9545
9546 penalty = get_member_penalty (args.queuename, args.interface);
9547
9548 if (penalty >= 0) { /* remember that buf is already '\0' */
9549 snprintf (buf, len, "%d", penalty);
9550 }
9551
9552 return 0;
9553}
static int get_member_penalty(char *queuename, char *interface)
Gets members penalty.
Definition: app_queue.c:8217

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

9557{
9558 int penalty;
9560 AST_APP_ARG(queuename);
9561 AST_APP_ARG(interface);
9562 );
9563
9564 if (ast_strlen_zero(data)) {
9565 ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n");
9566 return -1;
9567 }
9568
9570
9571 if (args.argc < 2) {
9572 ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n");
9573 return -1;
9574 }
9575
9576 penalty = atoi(value);
9577
9578 if (ast_strlen_zero(args.interface)) {
9579 ast_log (LOG_ERROR, "<interface> parameter can't be null\n");
9580 return -1;
9581 }
9582
9583 /* if queuename = NULL then penalty will be set for interface in all the queues. */
9584 if (set_member_value(args.queuename, args.interface, MEMBER_PENALTY, penalty)) {
9585 ast_log(LOG_ERROR, "Invalid interface, queue or penalty\n");
9586 return -1;
9587 }
9588
9589 return 0;
9590}

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

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

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

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

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

9440{
9441 int count = 0;
9442 struct call_queue *q, tmpq = {
9443 .name = data,
9444 };
9445 struct ast_variable *var = NULL;
9446
9447 buf[0] = '\0';
9448
9449 if (ast_strlen_zero(data)) {
9450 ast_log(LOG_ERROR, "QUEUE_WAITING_COUNT requires an argument: queuename\n");
9451 return -1;
9452 }
9453
9454 if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Find for QUEUE_WAITING_COUNT()"))) {
9455 ao2_lock(q);
9456 count = q->count;
9457 ao2_unlock(q);
9458 queue_t_unref(q, "Done with reference in QUEUE_WAITING_COUNT()");
9459 } else if ((var = ast_load_realtime("queues", "name", data, SENTINEL))) {
9460 /* if the queue is realtime but was not found in memory, this
9461 * means that the queue had been deleted from memory since it was
9462 * "dead." This means it has a 0 waiting count
9463 */
9464 count = 0;
9466 } else {
9467 ast_log(LOG_WARNING, "queue %s was not found\n", data);
9468 }
9469
9470 snprintf(buf, len, "%d", count);
9471
9472 return 0;
9473}

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

9114{
9115 int res = -1;
9116 struct call_queue *q;
9117 char interfacevar[256] = "";
9118 float sl = 0;
9119
9120 if (ast_strlen_zero(data)) {
9121 ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd);
9122 return -1;
9123 }
9124
9125 if ((q = find_load_queue_rt_friendly(data))) {
9126 ao2_lock(q);
9127 if (q->setqueuevar) {
9128 sl = 0;
9129 res = 0;
9130
9131 if (q->callscompleted > 0) {
9132 sl = 100 * ((float) q->callscompletedinsl / (float) q->callscompleted);
9133 }
9134
9135 snprintf(interfacevar, sizeof(interfacevar),
9136 "QUEUEMAX=%d,QUEUESTRATEGY=%s,QUEUECALLS=%d,QUEUEHOLDTIME=%d,QUEUETALKTIME=%d,QUEUECOMPLETED=%d,QUEUEABANDONED=%d,QUEUESRVLEVEL=%d,QUEUESRVLEVELPERF=%2.1f",
9138
9139 pbx_builtin_setvar_multiple(chan, interfacevar);
9140 }
9141
9142 ao2_unlock(q);
9143 queue_t_unref(q, "Done with QUEUE() function");
9144 } else {
9145 ast_log(LOG_WARNING, "queue %s was not found\n", data);
9146 }
9147
9148 snprintf(buf, len, "%d", res);
9149
9150 return 0;
9151}
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 2099 of file app_queue.c.

2100{
2101 const struct call_queue *q = obj;
2102
2103 return ast_str_case_hash(q->name);
2104}

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

2308{
2309 return queue_member_to_ami("QueueMemberAdded", message);
2310}
static struct ast_manager_event_blob * queue_member_to_ami(const char *type, struct stasis_message *message)
Definition: app_queue.c:2287

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

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

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

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

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

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

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

2318{
2319 return queue_member_to_ami("QueueMemberPause", message);
2320}

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

2323{
2324 return queue_member_to_ami("QueueMemberPenalty", message);
2325}

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

2313{
2314 return queue_member_to_ami("QueueMemberRemoved", message);
2315}

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

2328{
2329 return queue_member_to_ami("QueueMemberRinginuse", message);
2330}

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

2303{
2304 return queue_member_to_ami("QueueMemberStatus", message);
2305}

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

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

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

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

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

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

9710{
9712 autofill_default = 0;
9713 montype_default = 0;
9714 shared_lastcall = 0;
9718}
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

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

Referenced by reload_queues().

◆ queue_rules_reset_global_params()

static void queue_rules_reset_global_params ( void  )
static

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

Definition at line 9630 of file app_queue.c.

9631{
9632 realtime_rules = 0;
9633}
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 9636 of file app_queue.c.

9637{
9638 const char *general_val = NULL;
9639 if ((general_val = ast_variable_retrieve(cfg, "general", "realtime_rules"))) {
9640 realtime_rules = ast_true(general_val);
9641 }
9642}

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

9722{
9723 const char *general_val = NULL;
9724 if ((general_val = ast_variable_retrieve(cfg, "general", "persistentmembers"))) {
9725 queue_persistent_members = ast_true(general_val);
9726 }
9727 if ((general_val = ast_variable_retrieve(cfg, "general", "autofill"))) {
9728 autofill_default = ast_true(general_val);
9729 }
9730 if ((general_val = ast_variable_retrieve(cfg, "general", "monitor-type"))) {
9731 if (!strcasecmp(general_val, "mixmonitor"))
9732 montype_default = 1;
9733 }
9734 if ((general_val = ast_variable_retrieve(cfg, "general", "shared_lastcall"))) {
9735 shared_lastcall = ast_true(general_val);
9736 }
9737 if ((general_val = ast_variable_retrieve(cfg, "general", "negative_penalty_invalid"))) {
9738 negative_penalty_invalid = ast_true(general_val);
9739 }
9740 if ((general_val = ast_variable_retrieve(cfg, "general", "log_membername_as_agent"))) {
9741 log_membername_as_agent = ast_true(general_val);
9742 }
9743 if ((general_val = ast_variable_retrieve(cfg, "general", "force_longest_waiting_caller"))) {
9745 }
9746 /* Apply log-caller-id-name in the same place as other global settings */
9747 if ((general_val = ast_variable_retrieve(cfg, "general", "log-caller-id-name"))) {
9748 log_caller_id_name = ast_true(general_val);
9749 }
9750}

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

Referenced by reload_queues().

◆ queue_set_param()

static void queue_set_param ( struct call_queue q,
const char *  param,
const char *  val,
int  linenum,
int  failunknown 
)
static

Configure a queue parameter.

The failunknown flag is set for config files (and static realtime) to show errors for unknown parameters. It is cleared for dynamic realtime to allow extra fields in the tables.

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

Definition at line 3480 of file app_queue.c.

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

10519{
10520 switch ( cmd ) {
10521 case CLI_INIT:
10522 e->command = "queue show";
10523 e->usage =
10524 "Usage: queue show\n"
10525 " Provides summary information on a specified queue.\n";
10526 return NULL;
10527 case CLI_GENERATE:
10528 return complete_queue_show(a->line, a->word, a->pos, a->n);
10529 }
10530
10531 return __queues_show(NULL, a->fd, a->argc, a->argv);
10532}
static char * complete_queue_show(const char *line, const char *word, int pos, int state)
Definition: app_queue.c:10510
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:10302

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

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

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

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

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

11764{
11765 int oldtalktime;
11766 char *parse;
11767 struct call_queue *q;
11768 struct member *mem;
11769 int newtalktime = 0;
11770
11772 AST_APP_ARG(queuename);
11773 AST_APP_ARG(uniqueid);
11774 AST_APP_ARG(agent);
11776 AST_APP_ARG(talktime);
11777 AST_APP_ARG(params););
11778
11779 if (ast_strlen_zero(data)) {
11780 ast_log(LOG_WARNING, "QueueUpdate requires arguments (queuename,uniqueid,agent,status,talktime,params[totaltime,callednumber])\n");
11781 return -1;
11782 }
11783
11784 parse = ast_strdupa(data);
11785
11787
11788 if (ast_strlen_zero(args.queuename) || ast_strlen_zero(args.uniqueid) || ast_strlen_zero(args.agent) || ast_strlen_zero(args.status)) {
11789 ast_log(LOG_WARNING, "Missing argument to QueueUpdate (queuename,uniqueid,agent,status,talktime,params[totaltime|callednumber])\n");
11790 return -1;
11791 }
11792
11793 if (!ast_strlen_zero(args.talktime)) {
11794 newtalktime = atoi(args.talktime);
11795 }
11796
11797 q = find_load_queue_rt_friendly(args.queuename);
11798 if (!q) {
11799 ast_log(LOG_WARNING, "QueueUpdate could not find requested queue '%s'\n", args.queuename);
11800 return 0;
11801 }
11802
11803 ao2_lock(q);
11804 if (q->members) {
11805 struct ao2_iterator mem_iter = ao2_iterator_init(q->members, 0);
11806 while ((mem = ao2_iterator_next(&mem_iter))) {
11807 if (!strcasecmp(mem->membername, args.agent)) {
11808 if (!strcasecmp(args.status, "ANSWER")) {
11809 oldtalktime = q->talktime;
11810 q->talktime = (((oldtalktime << 2) - oldtalktime) + newtalktime) >> 2;
11811 time(&mem->lastcall);
11812 mem->calls++;
11813 mem->lastqueue = q;
11814 q->callscompleted++;
11815
11816 if (newtalktime <= q->servicelevel) {
11817 q->callscompletedinsl++;
11818 }
11819 } else {
11820
11821 time(&mem->lastcall);
11822 q->callsabandoned++;
11823 }
11824
11825 ast_queue_log(args.queuename, args.uniqueid, args.agent, "OUTCALL", "%s|%s|%s", args.status, args.talktime, args.params);
11826 }
11827
11828 ao2_ref(mem, -1);
11829 }
11830
11831 ao2_iterator_destroy(&mem_iter);
11832 }
11833
11834 ao2_unlock(q);
11835 queue_t_unref(q, "Done with temporary pointer");
11836
11837 return 0;
11838}

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

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

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

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

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

12086{
12087 struct ast_flags mask = {AST_FLAGS_ALL & ~QUEUE_RESET_STATS,};
12088 ast_unload_realtime("queue_members");
12089 reload_handler(1, &mask, NULL);
12090 return 0;
12091}
int ast_unload_realtime(const char *family)
Release any resources cached for a realtime family.
Definition: main/config.c:3808

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

10168{
10169 int res = 0;
10170
10171 if (ast_test_flag(mask, QUEUE_RELOAD_RULES)) {
10172 res |= reload_queue_rules(reload);
10173 }
10174 if (ast_test_flag(mask, QUEUE_RESET_STATS)) {
10175 res |= clear_stats(queuename);
10176 }
10178 res |= reload_queues(reload, mask, queuename);
10179 }
10180 return res;
10181}
static int reload_queues(int reload, struct ast_flags *mask, const char *queuename)
reload the queues.conf file
Definition: app_queue.c:10080
static int reload_queue_rules(int reload)
Reload the rules defined in queuerules.conf.
Definition: app_queue.c:9650
static int clear_stats(const char *queuename)
Facilitates resetting statistics for a queue.
Definition: app_queue.c:10137
static int reload(void)
Definition: app_queue.c:12085

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

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

9651{
9652 struct ast_config *cfg;
9653 struct rule_list *rl_iter, *new_rl;
9654 struct penalty_rule *pr_iter;
9655 char *rulecat = NULL;
9656 struct ast_variable *rulevar = NULL;
9657 struct ast_flags config_flags = { (reload && !realtime_rules) ? CONFIG_FLAG_FILEUNCHANGED : 0 };
9658
9659 if (!(cfg = ast_config_load("queuerules.conf", config_flags))) {
9660 ast_log(LOG_NOTICE, "No queuerules.conf file found, queues will not follow penalty rules\n");
9662 } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
9663 ast_log(LOG_NOTICE, "queuerules.conf has not changed since it was last loaded. Not taking any action.\n");
9665 } else if (cfg == CONFIG_STATUS_FILEINVALID) {
9666 ast_log(LOG_ERROR, "Config file queuerules.conf is in an invalid format. Aborting.\n");
9668 }
9669
9671 while ((rl_iter = AST_LIST_REMOVE_HEAD(&rule_lists, list))) {
9672 while ((pr_iter = AST_LIST_REMOVE_HEAD(&rl_iter->rules, list)))
9673 ast_free(pr_iter);
9674 ast_free(rl_iter);
9675 }
9677 while ((rulecat = ast_category_browse(cfg, rulecat))) {
9678 if (!strcasecmp(rulecat, "general")) {
9680 continue;
9681 }
9682 if (!(new_rl = ast_calloc(1, sizeof(*new_rl)))) {
9684 ast_config_destroy(cfg);
9686 } else {
9687 ast_copy_string(new_rl->name, rulecat, sizeof(new_rl->name));
9688 AST_LIST_INSERT_TAIL(&rule_lists, new_rl, list);
9689 for (rulevar = ast_variable_browse(cfg, rulecat); rulevar; rulevar = rulevar->next)
9690 if(!strcasecmp(rulevar->name, "penaltychange"))
9691 insert_penaltychange(new_rl->name, rulevar->value, rulevar->lineno);
9692 else
9693 ast_log(LOG_WARNING, "Don't know how to handle rule type '%s' on line %d\n", rulevar->name, rulevar->lineno);
9694 }
9695 }
9696
9697 ast_config_destroy(cfg);
9698
9702 }
9703
9706}
static int load_realtime_rules(void)
Load queue rules from realtime.
Definition: app_queue.c:3325
static void queue_rules_reset_global_params(void)
Definition: app_queue.c:9630
static int insert_penaltychange(const char *list_name, const char *content, const int linenum)
Change queue penalty by adding rule.
Definition: app_queue.c:3216
static void queue_rules_set_global_params(struct ast_config *cfg)
Definition: app_queue.c:9636
#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:1215

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

10081{
10082 struct ast_config *cfg;
10083 char *cat;
10084 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
10085 const int queue_reload = ast_test_flag(mask, QUEUE_RELOAD_PARAMETERS);
10086
10087 if (!(cfg = ast_config_load("queues.conf", config_flags))) {
10088 ast_log(LOG_NOTICE, "No call queueing config file (queues.conf), so no call queues\n");
10089 return -1;
10090 } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
10091 return 0;
10092 } else if (cfg == CONFIG_STATUS_FILEINVALID) {
10093 ast_log(LOG_ERROR, "Config file queues.conf is in an invalid format. Aborting.\n");
10094 return -1;
10095 }
10096
10097 /* We've made it here, so it looks like we're doing operations on all queues. */
10099
10100 /* Mark non-realtime queues not found at the beginning. */
10101 ao2_callback(queues, OBJ_NODATA, mark_unfound, (char *) queuename);
10102
10103 /* Chug through config file. */
10104 cat = NULL;
10106 while ((cat = ast_category_browse(cfg, cat)) ) {
10107 if (!strcasecmp(cat, "general") && queue_reload) {
10109 continue;
10110 }
10111 if (ast_strlen_zero(queuename) || !strcasecmp(cat, queuename))
10112 reload_single_queue(cfg, mask, cat);
10113 }
10114
10115 ast_config_destroy(cfg);
10116 if (queue_reload) {
10117 /* Unlink and mark dead all non-realtime queues that were not found in the configuration file. */
10119 }
10121 return 0;
10122}
static void queue_reset_global_params(void)
Definition: app_queue.c:9709
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:9923
static void queue_set_global_params(struct ast_config *cfg)
Definition: app_queue.c:9721
static int mark_unfound(void *obj, void *arg, int flags)
Definition: app_queue.c:10046
static int kill_if_unfound(void *obj, void *arg, int flags)
Definition: app_queue.c:10056

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

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

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

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

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

7689{
7690 struct call_queue *q, tmpq = {
7691 .name = queuename,
7692 };
7693 struct member *mem, tmpmem;
7694 int res = RES_NOSUCHQUEUE;
7695
7696 ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface));
7697 if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Temporary reference for interface removal"))) {
7698 ao2_lock(q);
7699 if ((mem = ao2_find(q->members, &tmpmem, OBJ_POINTER))) {
7700 /* XXX future changes should beware of this assumption!! */
7701 /*Change Penalty on realtime users*/
7703 update_realtime_member_field(mem, q->name, "penalty", "-1");
7704 } else if (!mem->dynamic) {
7705 ao2_ref(mem, -1);
7706 ao2_unlock(q);
7707 queue_t_unref(q, "Interface wasn't dynamic, expiring temporary reference");
7708 return RES_NOT_DYNAMIC;
7709 }
7710 queue_publish_member_blob(queue_member_removed_type(), queue_member_blob_create(q, mem));
7711
7713 ao2_ref(mem, -1);
7714
7717 }
7718
7719 if (!num_available_members(q)) {
7721 }
7722
7723 res = RES_OKAY;
7724 } else {
7725 res = RES_EXISTS;
7726 }
7727 ao2_unlock(q);
7728 queue_t_unref(q, "Expiring temporary reference");
7729 }
7730
7731 return res;
7732}
static int update_realtime_member_field(struct member *mem, const char *queue_name, const char *field, const char *value)
Definition: app_queue.c:4132
char rt_uniqueid[80]
Definition: app_queue.c:1877

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

6425{
6426 SCOPED_AO2LOCK(lock, queue_data);
6427
6428 queue_data->dying = 1;
6430 queue_data->bridge_router = NULL;
6432 queue_data->channel_router = NULL;
6433}
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 7870 of file app_queue.c.

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

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

4902{
4903 int res;
4904 int status;
4905 char tech[256];
4906 char *location;
4907 struct ast_format_cap *nativeformats;
4908 RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
4909
4910 /* on entry here, we know that tmp->chan == NULL */
4911 if (!can_ring_entry(qe, tmp)) {
4912 tmp->stillgoing = 0;
4913 ++*busies;
4914 return 0;
4915 }
4916
4917 ast_copy_string(tech, tmp->interface, sizeof(tech));
4918 if ((location = strchr(tech, '/'))) {
4919 *location++ = '\0';
4920 } else {
4921 location = "";
4922 }
4923
4925 nativeformats = ao2_bump(ast_channel_nativeformats(qe->chan));
4927
4928 /* Request the peer */
4929 tmp->chan = ast_request(tech, nativeformats, NULL, qe->chan, location, &status);
4930 ao2_cleanup(nativeformats);
4931 if (!tmp->chan) { /* If we can't, just go on to the next call */
4932 ao2_lock(qe->parent);
4933 qe->parent->rrpos++;
4934 qe->linpos++;
4935 ao2_unlock(qe->parent);
4936
4938
4939 publish_dial_end_event(qe->chan, tmp, NULL, "BUSY");
4940 tmp->stillgoing = 0;
4941 ++*busies;
4942 return 0;
4943 }
4944
4945 ast_channel_lock_both(tmp->chan, qe->chan);
4946
4949 if (qe->cancel_answered_elsewhere) {
4951 }
4952 ast_channel_appl_set(tmp->chan, "AppQueue");
4953 ast_channel_data_set(tmp->chan, "(Outgoing Line)");
4954 memset(ast_channel_whentohangup(tmp->chan), 0, sizeof(*ast_channel_whentohangup(tmp->chan)));
4955
4956 /* If the new channel has no callerid, try to guess what it should be */
4957 if (!ast_channel_caller(tmp->chan)->id.number.valid) {
4959 struct ast_party_caller caller;
4960
4962 caller.id = ast_channel_connected(qe->chan)->id;
4963 caller.ani = ast_channel_connected(qe->chan)->ani;
4964 ast_channel_set_caller_event(tmp->chan, &caller, NULL);
4965 } else if (!ast_strlen_zero(ast_channel_dialed(qe->chan)->number.str)) {
4967 } else if (!ast_strlen_zero(ast_channel_exten(qe->chan))) {
4969 }
4970 tmp->dial_callerid_absent = 1;
4971 }
4972
4974
4976
4978
4979 /* Inherit specially named variables from parent channel */
4983
4984 /* Presense of ADSI CPE on outgoing channel follows ours */
4986
4987 /* Inherit context and extension */
4988 ast_channel_dialcontext_set(tmp->chan, ast_channel_context(qe->chan));
4990
4991 /* Save the original channel name to detect call pickup masquerading in. */
4993
4996
4997 /* location is tmp->interface where tech/ has been stripped, so it follow the same syntax as DIALEDPEERNUMBER in app_dial.c */
4998 pbx_builtin_setvar_helper(tmp->chan, "DIALEDPEERNUMBER", strlen(location) ? location : tmp->interface);
4999
5000 /* PREDIAL: Run gosub on the callee's channel */
5001 if (qe->predial_callee) {
5002 ast_pre_call(tmp->chan, qe->predial_callee);
5003 }
5004
5005 /* Place the call, but don't wait on the answer */
5006 if ((res = ast_call(tmp->chan, location, 0))) {
5007 /* Again, keep going even if there's an error */
5008 ast_verb(3, "Couldn't call %s\n", tmp->interface);
5009 do_hang(tmp);
5010 ++*busies;
5011 return 0;
5012 }
5013
5014 ast_channel_lock_both(tmp->chan, qe->chan);
5015
5016 blob = ast_json_pack("{s: s, s: s, s: s}",
5017 "Queue", qe->parent->name,
5018 "Interface", tmp->interface,
5019 "MemberName", tmp->member->membername);
5020 queue_publish_multi_channel_blob(qe->chan, tmp->chan, queue_agent_called_type(), blob);
5021
5023
5026
5027 ast_verb(3, "Called %s\n", tmp->interface);
5028
5029 return 1;
5030}
static void do_hang(struct callattempt *o)
common hangup actions
Definition: app_queue.c:4775
static int can_ring_entry(struct queue_ent *qe, struct callattempt *call)
Definition: app_queue.c:4805
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:2468
static void publish_dial_end_event(struct ast_channel *in, struct callattempt *outgoing, struct ast_channel *exception, const char *status)
Definition: app_queue.c:4605
#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:1809
char interface[256]
Definition: app_queue.c:1799
int cancel_answered_elsewhere
Definition: app_queue.c:1844

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

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

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

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

8432{
8433 int res=-1;
8434 char *parse, *temppos = NULL;
8435 struct member *mem = NULL;
8436
8438 AST_APP_ARG(queuename);
8440 );
8441
8442
8443 if (ast_strlen_zero(data)) {
8444 ast_log(LOG_WARNING, "RemoveQueueMember requires an argument (queuename[,interface])\n");
8445 return -1;
8446 }
8447
8448 parse = ast_strdupa(data);
8449
8451
8452 if (ast_strlen_zero(args.interface)) {
8453 args.interface = ast_strdupa(ast_channel_name(chan));
8454 temppos = strrchr(args.interface, '-');
8455 if (temppos) {
8456 *temppos = '\0';
8457 }
8458 }
8459
8460 ast_debug(1, "queue: %s, member: %s\n", args.queuename, args.interface);
8461
8463 mem = find_member_by_queuename_and_interface(args.queuename, args.interface);
8464 }
8465
8466 switch (remove_from_queue(args.queuename, args.interface)) {
8467 case RES_OKAY:
8468 if (!mem || ast_strlen_zero(mem->membername)) {
8469 ast_queue_log(args.queuename, ast_channel_uniqueid(chan), args.interface, "REMOVEMEMBER", "%s", "");
8470 } else {
8471 ast_queue_log(args.queuename, ast_channel_uniqueid(chan), mem->membername, "REMOVEMEMBER", "%s", "");
8472 }
8473 ast_log(LOG_NOTICE, "Removed interface '%s' from queue '%s'\n", args.interface, args.queuename);
8474 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "REMOVED");
8475 res = 0;
8476 break;
8477 case RES_EXISTS:
8478 ast_debug(1, "Unable to remove interface '%s' from queue '%s': Not there\n", args.interface, args.queuename);
8479 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOTINQUEUE");
8480 res = 0;
8481 break;
8482 case RES_NOSUCHQUEUE:
8483 ast_log(LOG_WARNING, "Unable to remove interface from queue '%s': No such queue\n", args.queuename);
8484 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOSUCHQUEUE");
8485 res = 0;
8486 break;
8487 case RES_NOT_DYNAMIC:
8488 ast_log(LOG_WARNING, "Unable to remove interface from queue '%s': '%s' is not a dynamic member\n", args.queuename, args.interface);
8489 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOTDYNAMIC");
8490 res = 0;
8491 break;
8492 }
8493
8494 if (mem) {
8495 ao2_ref(mem, -1);
8496 }
8497
8498 return res;
8499}

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

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

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

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

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

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

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

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

8001{
8002 int found = 0;
8003 struct call_queue *q;
8004 struct ao2_iterator queue_iter;
8005
8006 if (ast_check_realtime("queues")) {
8007 load_realtime_queues(queuename);
8008 }
8009
8010 queue_iter = ao2_iterator_init(queues, 0);
8011 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate over queues"))) {
8012 ao2_lock(q);
8013 if (ast_strlen_zero(queuename) || !strcasecmp(q->name, queuename)) {
8014 struct member *mem;
8015
8016 if ((mem = interface_exists(q, interface))) {
8017 /*
8018 * Before we do the PAUSE/UNPAUSE, log if this was a
8019 * PAUSEALL/UNPAUSEALL but only on the first found entry.
8020 */
8021 ++found;
8022 if (found == 1
8023 && ast_strlen_zero(queuename)) {
8024 /*
8025 * XXX In all other cases, we use the queue name,
8026 * but since this affects all queues, we cannot.
8027 */
8028 ast_queue_log("NONE", "NONE", mem->membername,
8029 (paused ? "PAUSEALL" : "UNPAUSEALL"), "%s", S_OR(reason, ""));
8030 }
8031
8032 set_queue_member_pause(q, mem, reason, paused);
8033 ao2_ref(mem, -1);
8034 }
8035
8036 if (!ast_strlen_zero(queuename)) {
8037 ao2_unlock(q);
8038 queue_t_unref(q, "Done with iterator");
8039 break;
8040 }
8041 }
8042
8043 ao2_unlock(q);
8044 queue_t_unref(q, "Done with iterator");
8045 }
8046 ao2_iterator_destroy(&queue_iter);
8047
8048 return found ? RESULT_SUCCESS : RESULT_FAILURE;
8049}
static void set_queue_member_pause(struct call_queue *q, struct member *mem, const char *reason, int paused)
Definition: app_queue.c:7933

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

8061{
8062 struct member *mem;
8063 int foundinterface = 0;
8064
8065 ao2_lock(q);
8066 if ((mem = interface_exists(q, interface))) {
8067 foundinterface++;
8068 if (mem->realtime) {
8069 char rtpenalty[80];
8070
8071 sprintf(rtpenalty, "%i", penalty);
8072 update_realtime_member_field(mem, q->name, "penalty", rtpenalty);
8073 }
8074
8075 mem->penalty = penalty;
8076
8077 ast_queue_log(q->name, "NONE", interface, "PENALTY", "%d", penalty);
8078 queue_publish_member_blob(queue_member_penalty_type(), queue_member_blob_create(q, mem));
8079 ao2_ref(mem, -1);
8080 }
8081 ao2_unlock(q);
8082
8083 return foundinterface;
8084}

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

8110{
8111 struct member *mem;
8112 int foundinterface = 0;
8113
8114 ao2_lock(q);
8115 if ((mem = interface_exists(q, interface))) {
8116 foundinterface++;
8118 ao2_ref(mem, -1);
8119 }
8120 ao2_unlock(q);
8121
8122 return foundinterface;
8123}
static void set_queue_member_ringinuse(struct call_queue *q, struct member *mem, int ringinuse)
Definition: app_queue.c:8096

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

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

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

8126{
8127 switch(property) {
8128 case MEMBER_PENALTY:
8129 return set_member_penalty_help_members(q, interface, value);
8130
8131 case MEMBER_RINGINUSE:
8132 return set_member_ringinuse_help_members(q, interface, value);
8133
8134 default:
8135 ast_log(LOG_ERROR, "Attempted to set invalid property\n");
8136 return 0;
8137 }
8138}
static int set_member_ringinuse_help_members(struct call_queue *q, const char *interface, int ringinuse)
Definition: app_queue.c:8109
static int set_member_penalty_help_members(struct call_queue *q, const char *interface, int penalty)
Definition: app_queue.c:8060

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

7934{
7935 if (mem->paused == paused) {
7936 ast_debug(1, "%spausing already-%spaused queue member %s:%s\n",
7937 (paused ? "" : "un"), (paused ? "" : "un"), q->name, mem->interface);
7938 }
7939
7940 if (mem->realtime && !ast_strlen_zero(mem->rt_uniqueid)) {
7942 if (ast_update_realtime("queue_members", "uniqueid", mem->rt_uniqueid, "reason_paused", S_OR(reason, ""), "paused", paused ? "1" : "0", SENTINEL) < 0) {
7943 ast_log(LOG_WARNING, "Failed update of realtime queue member %s:%s %spause and reason '%s'\n",
7944 q->name, mem->interface, (paused ? "" : "un"), S_OR(reason, ""));
7945 }
7946 } else {
7947 if (ast_update_realtime("queue_members", "uniqueid", mem->rt_uniqueid, "paused", paused ? "1" : "0", SENTINEL) < 0) {
7948 ast_log(LOG_WARNING, "Failed %spause update of realtime queue member %s:%s\n",
7949 (paused ? "" : "un"), q->name, mem->interface);
7950 }
7951 }
7952 }
7953
7954 mem->paused = paused;
7955 if (paused) {
7956 time(&mem->lastpause); /* update last pause field */
7957 }
7958 if (paused && !ast_strlen_zero(reason)) {
7959 ast_copy_string(mem->reason_paused, reason, sizeof(mem->reason_paused));
7960 } else {
7961 /* We end up filling this in again later (temporarily) but we need it
7962 * empty for now so that the intervening code - specifically
7963 * dump_queue_members() - has the correct view of things. */
7964 mem->reason_paused[0] = '\0';
7965 }
7966
7968 AST_DEVSTATE_CACHABLE, "Queue:%s_pause_%s", q->name, mem->interface);
7969
7972 }
7973
7974 if (is_member_available(q, mem)) {
7976 "Queue:%s_avail", q->name);
7977 } else if (!num_available_members(q)) {
7979 "Queue:%s_avail", q->name);
7980 }
7981
7982 if (!paused && !ast_strlen_zero(reason)) {
7983 /* Because we've been unpaused with a 'reason' we need to ensure that
7984 * that reason is emitted when the subsequent PauseQueueMember event
7985 * is raised. So temporarily set it on the member and clear it out
7986 * again right after. */
7987 ast_copy_string(mem->reason_paused, reason, sizeof(mem->reason_paused));
7988 }
7989
7990 ast_queue_log(q->name, "NONE", mem->membername, paused ? "PAUSE" : "UNPAUSE",
7991 "%s", mem->reason_paused);
7992
7994
7995 if (!paused) {
7996 mem->reason_paused[0] = '\0';
7997 }
7998}
static int publish_queue_member_pause(struct call_queue *q, struct member *member)
Definition: app_queue.c:7909
int ast_update_realtime(const char *family, const char *keyfield, const char *lookup,...) attribute_sentinel
Update realtime configuration.
Definition: main/config.c:3891

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

Referenced by set_member_paused().

◆ set_queue_member_ringinuse()

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

Definition at line 8096 of file app_queue.c.

8097{
8098 if (mem->realtime) {
8100 ringinuse ? "1" : "0");
8101 }
8102
8103 mem->ringinuse = ringinuse;
8104
8105 ast_queue_log(q->name, "NONE", mem->interface, "RINGINUSE", "%d", ringinuse);
8106 queue_publish_member_blob(queue_member_ringinuse_type(), queue_member_blob_create(q, mem));
8107}

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

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

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

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

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

7054{
7055 char escaped_filename[256];
7056 char file_with_ext[sizeof(escaped_filename) + sizeof(qe->parent->monfmt)];
7057 char mixmonargs[1512];
7058 char escaped_monitor_exec[1024];
7059 const char *monitor_options;
7060 const char *monitor_exec;
7061
7062 escaped_monitor_exec[0] = '\0';
7063
7064 if (filename) {
7065 escape_and_substitute(qe->chan, filename, escaped_filename, sizeof(escaped_filename));
7066 } else {
7067 ast_copy_string(escaped_filename, ast_channel_uniqueid(qe->chan), sizeof(escaped_filename));
7068 }
7069
7071 if ((monitor_exec = pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC"))) {
7072 monitor_exec = ast_strdupa(monitor_exec);
7073 }
7074 if ((monitor_options = pbx_builtin_getvar_helper(qe->chan, "MONITOR_OPTIONS"))) {
7075 monitor_options = ast_strdupa(monitor_options);
7076 } else {
7077 monitor_options = "";
7078 }
7080
7081 if (monitor_exec) {
7082 escape_and_substitute(qe->chan, monitor_exec, escaped_monitor_exec, sizeof(escaped_monitor_exec));
7083 }
7084
7085 snprintf(file_with_ext, sizeof(file_with_ext), "%s.%s", escaped_filename, qe->parent->monfmt);
7086
7087 if (!ast_strlen_zero(escaped_monitor_exec)) {
7088 snprintf(mixmonargs, sizeof(mixmonargs), "b%s,%s", monitor_options, escaped_monitor_exec);
7089 } else {
7090 snprintf(mixmonargs, sizeof(mixmonargs), "b%s", monitor_options);
7091 }
7092
7093 ast_debug(1, "Arguments being passed to MixMonitor: %s,%s\n", file_with_ext, mixmonargs);
7094
7095 if (ast_start_mixmonitor(qe->chan, file_with_ext, mixmonargs)) {
7096 ast_log(LOG_WARNING, "Unable to start mixmonitor. Is the MixMonitor app loaded?\n");
7097 }
7098}
static void escape_and_substitute(struct ast_channel *chan, const char *input, char *output, size_t size)
Definition: app_queue.c:7022
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 7005 of file app_queue.c.

7006{
7007 const char *context;
7008 const char *extension;
7009 int priority;
7010
7011 if (ast_test_flag(opts, OPT_CALLEE_GO_ON)) {
7012 ast_channel_lock(chan);
7016 ast_channel_unlock(chan);
7018 opt_args[OPT_ARG_CALLEE_GO_ON]);
7019 }
7020}
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 6921 of file app_queue.c.

6923{
6924 struct queue_stasis_data *queue_data = queue_stasis_data_alloc(qe, peer, mem, holdstart, starttime, callcompletedinsl);
6925
6926 if (!queue_data) {
6927 return -1;
6928 }
6929
6931 if (!queue_data->bridge_router) {
6932 ao2_ref(queue_data, -1);
6933 return -1;
6934 }
6935
6937 handle_bridge_enter, queue_data);
6939 handle_blind_transfer, queue_data);
6941 handle_attended_transfer, queue_data);
6943 queue_bridge_cb, queue_data);
6944
6946 if (!queue_data->channel_router) {
6947 /* Unsubscribing from the bridge router will remove the only ref of queue_data,
6948 * thus beginning the destruction process
6949 */
6951 queue_data->bridge_router = NULL;
6952 return -1;
6953 }
6954
6955 ao2_ref(queue_data, +1);
6959 handle_local_optimization_end, queue_data);
6961 handle_hangup, queue_data);
6963 handle_masquerade, queue_data);
6965 queue_channel_cb, queue_data);
6966
6967 return 0;
6968}
static void handle_bridge_enter(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Definition: app_queue.c:6524
static void queue_bridge_cb(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Definition: app_queue.c:6671
static void handle_attended_transfer(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Handle an attended transfer event.
Definition: app_queue.c:6616
static void handle_masquerade(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Definition: app_queue.c:6862
static void handle_local_optimization_begin(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Definition: app_queue.c:6690
static void handle_local_optimization_end(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Definition: app_queue.c:6741
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:6439
static void queue_channel_cb(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Definition: app_queue.c:6896
static void handle_hangup(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Definition: app_queue.c:6805
static void handle_blind_transfer(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Handle a blind transfer event.
Definition: app_queue.c:6557
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 5142 of file app_queue.c.

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

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

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

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

2064{
2065 int x;
2066
2067 for (x = 0; x < ARRAY_LEN(strategies); x++) {
2068 if (!strcasecmp(strategy, strategies[x].name)) {
2069 return strategies[x].strategy;
2070 }
2071 }
2072
2073 return -1;
2074}
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 7126 of file app_queue.c.

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

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

11857{
11860
11862
11863 STASIS_MESSAGE_TYPE_CLEANUP(queue_caller_join_type);
11864 STASIS_MESSAGE_TYPE_CLEANUP(queue_caller_leave_type);
11865 STASIS_MESSAGE_TYPE_CLEANUP(queue_caller_abandon_type);
11866
11867 STASIS_MESSAGE_TYPE_CLEANUP(queue_member_status_type);
11868 STASIS_MESSAGE_TYPE_CLEANUP(queue_member_added_type);
11869 STASIS_MESSAGE_TYPE_CLEANUP(queue_member_removed_type);
11870 STASIS_MESSAGE_TYPE_CLEANUP(queue_member_pause_type);
11871 STASIS_MESSAGE_TYPE_CLEANUP(queue_member_penalty_type);
11872 STASIS_MESSAGE_TYPE_CLEANUP(queue_member_ringinuse_type);
11873
11874 STASIS_MESSAGE_TYPE_CLEANUP(queue_agent_called_type);
11875 STASIS_MESSAGE_TYPE_CLEANUP(queue_agent_connect_type);
11876 STASIS_MESSAGE_TYPE_CLEANUP(queue_agent_complete_type);
11877 STASIS_MESSAGE_TYPE_CLEANUP(queue_agent_dump_type);
11878 STASIS_MESSAGE_TYPE_CLEANUP(queue_agent_ringnoanswer_type);
11879
11881 ast_manager_unregister("QueueStatus");
11882 ast_manager_unregister("QueueRule");
11883 ast_manager_unregister("QueueSummary");
11884 ast_manager_unregister("QueueAdd");
11885 ast_manager_unregister("QueueRemove");
11886 ast_manager_unregister("QueuePause");
11887 ast_manager_unregister("QueueLog");
11888 ast_manager_unregister("QueueUpdate");
11889 ast_manager_unregister("QueuePenalty");
11890 ast_manager_unregister("QueueReload");
11891 ast_manager_unregister("QueueReset");
11892 ast_manager_unregister("QueueMemberRingInUse");
11893 ast_manager_unregister("QueueChangePriorityCaller");
11894 ast_manager_unregister("QueueWithdrawCaller");
11909
11911
11912 ast_unload_realtime("queue_members");
11915
11916 queues = NULL;
11917 return 0;
11918}
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:7695
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:1575
struct stasis_subscription * stasis_unsubscribe_and_join(struct stasis_subscription *subscription)
Cancel a subscription, blocking until the last message is processed.
Definition: stasis.c:1161
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 5323 of file app_queue.c.

5324{
5325 struct ast_party_connected_line connected_caller;
5326
5327 ast_party_connected_line_init(&connected_caller);
5328
5329 ast_channel_lock(peer);
5331 ast_channel_unlock(peer);
5332 connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
5333 if (ast_channel_connected_line_sub(peer, chan, &connected_caller, 0)) {
5334 ast_channel_update_connected_line(chan, &connected_caller, NULL);
5335 }
5336 ast_party_connected_line_free(&connected_caller);
5337}
@ 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 5942 of file app_queue.c.

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

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

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

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

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

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

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

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

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

8396{
8397 char *parse;
8399 AST_APP_ARG(queuename);
8400 AST_APP_ARG(interface);
8402 AST_APP_ARG(reason);
8403 );
8404
8405 if (ast_strlen_zero(data)) {
8406 ast_log(LOG_WARNING, "UnpauseQueueMember requires an argument ([queuename],interface[,options[,reason]])\n");
8407 return -1;
8408 }
8409
8410 parse = ast_strdupa(data);
8411
8413
8414 if (ast_strlen_zero(args.interface)) {
8415 ast_log(LOG_WARNING, "Missing interface argument to UnpauseQueueMember ([queuename],interface[,options[,reason]])\n");
8416 return -1;
8417 }
8418
8419 if (set_member_paused(args.queuename, args.interface, args.reason, 0)) {
8420 ast_log(LOG_WARNING, "Attempt to unpause interface %s, not found\n", args.interface);
8421 pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "NOTFOUND");
8422 return 0;
8423 }
8424
8425 pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "UNPAUSED");
8426
8427 return 0;
8428}

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

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

7594{
7595 /* Don't need to hold the lock while we setup the outgoing calls */
7596 int retrywait = qe->parent->retry * 1000;
7597
7598 int res = ast_waitfordigit(qe->chan, retrywait);
7599 if (res > 0 && !valid_exit(qe, res)) {
7600 res = 0;
7601 }
7602
7603 return res;
7604}
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 5353 of file app_queue.c.

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

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

10414 {
10415 int list_len, word_len = strlen(word);
10416 const char *find, *end_find, *end_list;
10417
10418 /* strip whitespace from front */
10419 while(isspace(*list)) {
10420 list++;
10421 }
10422
10423 while((find = strstr(list, word))) {
10424 /* beginning of find starts inside another word? */
10425 if (find != list && *(find - 1) != ' ') {
10426 list = find;
10427 /* strip word from front */
10428 while(!isspace(*list) && *list != '\0') {
10429 list++;
10430 }
10431 /* strip whitespace from front */
10432 while(isspace(*list)) {
10433 list++;
10434 }
10435 continue;
10436 }
10437
10438 /* end of find ends inside another word or at very end of list? */
10439 list_len = strlen(list);
10440 end_find = find + word_len;
10441 end_list = list + list_len;
10442 if (end_find == end_list || *end_find != ' ') {
10443 list = find;
10444 /* strip word from front */
10445 while(!isspace(*list) && *list != '\0') {
10446 list++;
10447 }
10448 /* strip whitespace from front */
10449 while(isspace(*list)) {
10450 list++;
10451 }
10452 continue;
10453 }
10454
10455 /* terminating conditions satisfied, word at beginning or separated by ' ' */
10456 return 1;
10457 }
10458
10459 return 0;
10460}

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

◆ agent_router

struct stasis_message_router* agent_router
static

Definition at line 11853 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 12117 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 11840 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 1764 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

◆ 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 2646 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:9157

Definition at line 9592 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:9360

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

Definition at line 9602 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:9476

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

Definition at line 9623 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:9113

Definition at line 9597 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:9439

Definition at line 9613 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 1749 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 1746 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 11854 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().