Asterisk - The Open Source Telephony Project GIT-master-c753fe4
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros Modules Pages
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_qac_dep (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
 Get the total number of members in a specific queue (Deprecated) More...
 
static int queue_function_queuegetchannel (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
 Dialplan function QUEUE_GET_CHANNEL() Get caller channel waiting at specified position in the queue. More...
 
static int queue_function_queuememberlist (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
 Dialplan function QUEUE_MEMBER_LIST() Get list of members in a specific queue. More...
 
static int queue_function_queuewaitingcount (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
 Dialplan function QUEUE_WAITING_COUNT() Get number callers waiting in a specific queue. More...
 
static int queue_function_var (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
 create interface var with all queue details. More...
 
static int queue_hash_cb (const void *obj, const int flags)
 
static struct ast_manager_event_blobqueue_member_added_to_ami (struct stasis_message *message)
 
static struct ast_jsonqueue_member_blob_create (struct call_queue *q, struct member *mem)
 
static int queue_member_decrement_followers (void *obj, void *arg, int flag)
 
static void queue_member_follower_removal (struct call_queue *queue, struct member *mem)
 
static struct ast_manager_event_blobqueue_member_pause_to_ami (struct stasis_message *message)
 
static struct ast_manager_event_blobqueue_member_penalty_to_ami (struct stasis_message *message)
 
static struct ast_manager_event_blobqueue_member_removed_to_ami (struct stasis_message *message)
 
static struct ast_manager_event_blobqueue_member_ringinuse_to_ami (struct stasis_message *message)
 
static struct ast_manager_event_blobqueue_member_status_to_ami (struct stasis_message *message)
 
static struct ast_manager_event_blobqueue_member_to_ami (const char *type, struct stasis_message *message)
 
static struct ast_manager_event_blobqueue_multi_channel_to_ami (const char *type, struct stasis_message *message)
 
static void queue_publish_member_blob (struct stasis_message_type *type, struct ast_json *blob)
 
static void queue_publish_multi_channel_blob (struct ast_channel *caller, struct ast_channel *agent, struct stasis_message_type *type, struct ast_json *blob)
 
static void queue_publish_multi_channel_snapshot_blob (struct stasis_topic *topic, struct ast_channel_snapshot *caller_snapshot, struct ast_channel_snapshot *agent_snapshot, struct stasis_message_type *type, struct ast_json *blob)
 
static void queue_reset_global_params (void)
 
static void queue_rules_reset_global_params (void)
 
static void queue_rules_set_global_params (struct ast_config *cfg)
 
static void queue_set_global_params (struct ast_config *cfg)
 
static void queue_set_param (struct call_queue *q, const char *param, const char *val, int linenum, int failunknown)
 Configure a queue parameter. More...
 
static char * queue_show (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 
static struct queue_stasis_dataqueue_stasis_data_alloc (struct queue_ent *qe, struct ast_channel *peer, struct member *mem, time_t holdstart, time_t starttime, int callcompletedinsl)
 
static void queue_stasis_data_destructor (void *obj)
 
static int qupd_exec (struct ast_channel *chan, const char *data)
 Update Queue with data of an outgoing call. More...
 
static void recalc_holdtime (struct queue_ent *qe, int newholdtime)
 
static void record_abandoned (struct queue_ent *qe)
 Record that a caller gave up on waiting in queue. More...
 
static int reload (void)
 
static int reload_handler (int reload, struct ast_flags *mask, const char *queuename)
 The command center for all reload operations. More...
 
static void reload_queue_members (void)
 Reload dynamic queue members persisted into the astdb. More...
 
static int reload_queue_rules (int reload)
 Reload the rules defined in queuerules.conf. More...
 
static int reload_queues (int reload, struct ast_flags *mask, const char *queuename)
 reload the queues.conf file More...
 
static void reload_single_member (const char *memberdata, struct call_queue *q)
 reload information pertaining to a single member More...
 
static void reload_single_queue (struct ast_config *cfg, struct ast_flags *mask, const char *queuename)
 Reload information pertaining to a particular queue. More...
 
static int remove_from_queue (const char *queuename, const char *interface)
 Remove member from queue. More...
 
static void remove_stasis_subscriptions (struct queue_stasis_data *queue_data)
 
static int request_withdraw_caller_from_queue (const char *queuename, const char *caller, const char *withdraw_info)
 Request to withdraw a caller from a queue. More...
 
static int ring_entry (struct queue_ent *qe, struct callattempt *tmp, int *busies)
 Part 2 of ring_one. More...
 
static int ring_one (struct queue_ent *qe, struct callattempt *outgoing, int *busies)
 Place a call to a queue member. More...
 
static void rna (int rnatime, struct queue_ent *qe, struct ast_channel *peer, char *interface, char *membername, int autopause)
 RNA == Ring No Answer. Common code that is executed when we try a queue member and they don't answer. More...
 
static int rqm_exec (struct ast_channel *chan, const char *data)
 RemoveQueueMember application. More...
 
static void rt_handle_member_record (struct call_queue *q, char *category, struct ast_config *member_config)
 Find rt member record to update otherwise create one. More...
 
static int say_periodic_announcement (struct queue_ent *qe, int ringing)
 Playback announcement to queued members if period has elapsed. More...
 
static int say_position (struct queue_ent *qe, int ringing)
 
static void send_agent_complete (const char *queuename, struct ast_channel_snapshot *caller, struct ast_channel_snapshot *peer, const struct member *member, time_t holdstart, time_t callstart, enum agent_complete_reason rsn)
 Send out AMI message with member call completion status information. More...
 
static int set_member_paused (const char *queuename, const char *interface, const char *reason, int paused)
 
static int set_member_penalty_help_members (struct call_queue *q, const char *interface, int penalty)
 
static int set_member_ringinuse_help_members (struct call_queue *q, const char *interface, int ringinuse)
 
static int set_member_value (const char *queuename, const char *interface, int property, int value)
 
static int set_member_value_help_members (struct call_queue *q, const char *interface, int property, int value)
 
static void set_queue_member_pause (struct call_queue *q, struct member *mem, const char *reason, int paused)
 
static void set_queue_member_ringinuse (struct call_queue *q, struct member *mem, int ringinuse)
 
static void set_queue_result (struct ast_channel *chan, enum queue_result res)
 sets the QUEUESTATUS channel variable More...
 
static void set_queue_variables (struct call_queue *q, struct ast_channel *chan)
 Set variables of queue. More...
 
static void setup_mixmonitor (struct queue_ent *qe, const char *filename)
 
static void setup_peer_after_bridge_goto (struct ast_channel *chan, struct ast_channel *peer, struct ast_flags *opts, char *opt_args[])
 
static int setup_stasis_subs (struct queue_ent *qe, struct ast_channel *peer, struct member *mem, time_t holdstart, time_t starttime, int callcompletedinsl)
 
 STASIS_MESSAGE_TYPE_DEFN_LOCAL (queue_agent_called_type,.to_ami=queue_agent_called_to_ami,)
 
 STASIS_MESSAGE_TYPE_DEFN_LOCAL (queue_agent_complete_type,.to_ami=queue_agent_complete_to_ami,)
 
 STASIS_MESSAGE_TYPE_DEFN_LOCAL (queue_agent_connect_type,.to_ami=queue_agent_connect_to_ami,)
 
 STASIS_MESSAGE_TYPE_DEFN_LOCAL (queue_agent_dump_type,.to_ami=queue_agent_dump_to_ami,)
 
 STASIS_MESSAGE_TYPE_DEFN_LOCAL (queue_agent_ringnoanswer_type,.to_ami=queue_agent_ringnoanswer_to_ami,)
 
 STASIS_MESSAGE_TYPE_DEFN_LOCAL (queue_caller_abandon_type,.to_ami=queue_caller_abandon_to_ami,)
 
 STASIS_MESSAGE_TYPE_DEFN_LOCAL (queue_caller_join_type,.to_ami=queue_caller_join_to_ami,)
 
 STASIS_MESSAGE_TYPE_DEFN_LOCAL (queue_caller_leave_type,.to_ami=queue_caller_leave_to_ami,)
 
 STASIS_MESSAGE_TYPE_DEFN_LOCAL (queue_member_added_type,.to_ami=queue_member_added_to_ami,)
 
 STASIS_MESSAGE_TYPE_DEFN_LOCAL (queue_member_pause_type,.to_ami=queue_member_pause_to_ami,)
 
 STASIS_MESSAGE_TYPE_DEFN_LOCAL (queue_member_penalty_type,.to_ami=queue_member_penalty_to_ami,)
 
 STASIS_MESSAGE_TYPE_DEFN_LOCAL (queue_member_removed_type,.to_ami=queue_member_removed_to_ami,)
 
 STASIS_MESSAGE_TYPE_DEFN_LOCAL (queue_member_ringinuse_type,.to_ami=queue_member_ringinuse_to_ami,)
 
 STASIS_MESSAGE_TYPE_DEFN_LOCAL (queue_member_status_type,.to_ami=queue_member_status_to_ami,)
 
static int store_next_lin (struct queue_ent *qe, struct callattempt *outgoing)
 Search for best metric and add to Linear queue. More...
 
static int store_next_rr (struct queue_ent *qe, struct callattempt *outgoing)
 Search for best metric and add to Round Robbin queue. More...
 
static int strat2int (const char *strategy)
 
static int try_calling (struct queue_ent *qe, struct ast_flags opts, char **opt_args, char *announceoverride, const char *url, int *tries, int *noption, const char *agi, const char *gosub, int ringing)
 
static int unload_module (void)
 
static void update_connected_line_from_peer (struct ast_channel *chan, struct ast_channel *peer, int is_caller)
 
static void update_qe_rule (struct queue_ent *qe)
 update rules for queues More...
 
static int update_queue (struct call_queue *q, struct member *member, int callcompletedinsl, time_t starttime)
 update the queue status More...
 
static int update_realtime_member_field (struct member *mem, const char *queue_name, const char *field, const char *value)
 
static void update_realtime_members (struct call_queue *q)
 
static void update_status (struct call_queue *q, struct member *m, const int status)
 set a member's status based on device state of that member's state_interface. More...
 
static int upqm_exec (struct ast_channel *chan, const char *data)
 UnpauseQueueMember application. More...
 
static int valid_exit (struct queue_ent *qe, char digit)
 Check for valid exit from queue via goto. More...
 
static int wait_a_bit (struct queue_ent *qe)
 
static struct callattemptwait_for_answer (struct queue_ent *qe, struct callattempt *outgoing, int *to, char *digit, int prebusies, int caller_disconnect, int forwardsallowed)
 Wait for a member to answer the call. More...
 
static int wait_our_turn (struct queue_ent *qe, int ringing, enum queue_result *reason)
 The waiting areas for callers who are not actively calling members. More...
 
static int word_in_list (const char *list, const char *word)
 Check if a given word is in a space-delimited list. More...
 

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "True Call Queueing" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, .reload = reload, .load_pri = AST_MODPRI_DEVSTATE_CONSUMER, }
 
static struct stasis_message_routeragent_router
 
static char * app = "Queue"
 
static char * app_aqm = "AddQueueMember"
 
static char * app_pqm = "PauseQueueMember"
 
static char * app_ql = "QueueLog"
 
static char * app_qupd = "QueueUpdate"
 
static char * app_rqm = "RemoveQueueMember"
 
static char * app_upqm = "UnpauseQueueMember"
 
static const struct ast_app_option aqm_opts [128] = { [ 'p' ] = { .flag = AQMFLAG_PAUSED }, [ 'r' ] = { .flag = AQMFLAG_REASON , .arg_index = AQM_OPT_ARG_PAUSE_REASON + 1 }, }
 
static const struct ast_module_infoast_module_info = &__mod_info
 
static int autofill_default
 queues.conf [general] option More...
 
static const struct autopause autopausesmodes []
 
static struct ast_cli_entry cli_queue []
 
static struct stasis_subscriptiondevice_state_sub
 Subscription to device state change messages. More...
 
static int force_longest_waiting_caller
 queues.conf [general] option More...
 
static int log_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_dep
 
static struct ast_custom_function queuemembercount_function
 
static struct ast_custom_function queuememberlist_function
 
static struct ast_custom_function queuememberpenalty_function
 
static struct ao2_containerqueues
 
static struct ast_custom_function queuevar_function
 
static struct ast_custom_function queuewaitingcount_function
 
static int realtime_reason_paused
 does realtime backend support reason_paused More...
 
static char * realtime_ringinuse_field
 name of the ringinuse field in the realtime database More...
 
static int realtime_rules
 queuerules.conf [general] option More...
 
static struct rule_lists rule_lists = { .first = NULL, .last = NULL, .lock = { PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP , NULL, {1, 0} } , }
 
static int shared_lastcall
 queues.conf [general] option More...
 
static const struct strategy strategies []
 
static struct stasis_forwardtopic_forwarder
 
static int use_weight
 Records that one or more queues use weight. More...
 

Detailed Description

True call queues with optional send URL on answer.

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

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

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

Patch Version 1.07 2003-12-24 01

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

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

Definition in file app_queue.c.

Macro Definition Documentation

◆ ANNOUNCEHOLDTIME_ALWAYS

#define ANNOUNCEHOLDTIME_ALWAYS   1

Definition at line 1942 of file app_queue.c.

◆ ANNOUNCEHOLDTIME_ONCE

#define ANNOUNCEHOLDTIME_ONCE   2

Definition at line 1943 of file app_queue.c.

◆ ANNOUNCEPOSITION_LIMIT

#define ANNOUNCEPOSITION_LIMIT   4

We not announce position more than <limit>

Definition at line 1961 of file app_queue.c.

◆ ANNOUNCEPOSITION_MORE_THAN

#define ANNOUNCEPOSITION_MORE_THAN   3

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

Definition at line 1960 of file app_queue.c.

◆ ANNOUNCEPOSITION_NO

#define ANNOUNCEPOSITION_NO   2

We don't announce position

Definition at line 1959 of file app_queue.c.

◆ ANNOUNCEPOSITION_YES

#define ANNOUNCEPOSITION_YES   1

We announce position

Definition at line 1958 of file app_queue.c.

◆ AST_MAX_WATCHERS

#define AST_MAX_WATCHERS   256

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

◆ DEFAULT_RETRY

#define DEFAULT_RETRY   5

Definition at line 1720 of file app_queue.c.

◆ DEFAULT_TIMEOUT

#define DEFAULT_TIMEOUT   15

Definition at line 1721 of file app_queue.c.

◆ MAX_CALL_ATTEMPT_BUCKETS

#define MAX_CALL_ATTEMPT_BUCKETS   353

Definition at line 2691 of file app_queue.c.

◆ MAX_PERIODIC_ANNOUNCEMENTS

#define MAX_PERIODIC_ANNOUNCEMENTS   10

The maximum periodic announcements we can have

Definition at line 1723 of file app_queue.c.

◆ MAX_QUEUE_BUCKETS

#define MAX_QUEUE_BUCKETS   53

Definition at line 1730 of file app_queue.c.

◆ QUEUE_EVENT_VARIABLES

#define QUEUE_EVENT_VARIABLES   3

Definition at line 1944 of file app_queue.c.

◆ QUEUE_PAUSED_DEVSTATE

#define QUEUE_PAUSED_DEVSTATE   AST_DEVICE_INUSE

Definition at line 3728 of file app_queue.c.

◆ queue_ref

#define queue_ref (   q)    ao2_bump(q)

Definition at line 2227 of file app_queue.c.

◆ queue_t_ref

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

Definition at line 2229 of file app_queue.c.

◆ queue_t_unref

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

Definition at line 2230 of file app_queue.c.

◆ QUEUE_UNKNOWN_PAUSED_DEVSTATE

#define QUEUE_UNKNOWN_PAUSED_DEVSTATE   AST_DEVICE_NOT_INUSE

Definition at line 3730 of file app_queue.c.

◆ QUEUE_UNPAUSED_DEVSTATE

#define QUEUE_UNPAUSED_DEVSTATE   AST_DEVICE_NOT_INUSE

Definition at line 3729 of file app_queue.c.

◆ queue_unref

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

Definition at line 2228 of file app_queue.c.

◆ queues_t_link

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

Definition at line 2231 of file app_queue.c.

◆ queues_t_unlink

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

Definition at line 2232 of file app_queue.c.

◆ RECHECK

#define RECHECK   1

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

Definition at line 1722 of file app_queue.c.

◆ RES_EXISTS

#define RES_EXISTS   (-1)

Entry already exists

Definition at line 1733 of file app_queue.c.

◆ RES_NOSUCHQUEUE

#define RES_NOSUCHQUEUE   (-3)

No such queue

Definition at line 1735 of file app_queue.c.

◆ RES_NOT_CALLER

#define RES_NOT_CALLER   (-5)

Caller not found

Definition at line 1737 of file app_queue.c.

◆ RES_NOT_DYNAMIC

#define RES_NOT_DYNAMIC   (-4)

Member is not dynamic

Definition at line 1736 of file app_queue.c.

◆ RES_OKAY

#define RES_OKAY   0

Action completed

Definition at line 1732 of file app_queue.c.

◆ RES_OUTOFMEMORY

#define RES_OUTOFMEMORY   (-2)

Out of memory

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

1597 {
1598 OPT_MARK_AS_ANSWERED = (1 << 0),
1599 OPT_GO_ON = (1 << 1),
1600 OPT_DATA_QUALITY = (1 << 2),
1601 OPT_CALLEE_GO_ON = (1 << 3),
1602 OPT_CALLEE_HANGUP = (1 << 4),
1603 OPT_CALLER_HANGUP = (1 << 5),
1604 OPT_IGNORE_CALL_FW = (1 << 6),
1605 OPT_IGNORE_CONNECTEDLINE = (1 << 7),
1606 OPT_CALLEE_PARK = (1 << 8),
1607 OPT_CALLER_PARK = (1 << 9),
1608 OPT_NO_RETRY = (1 << 10),
1609 OPT_RINGING = (1 << 11),
1610 OPT_RING_WHEN_RINGING = (1 << 12),
1611 OPT_CALLEE_TRANSFER = (1 << 13),
1612 OPT_CALLER_TRANSFER = (1 << 14),
1613 OPT_CALLEE_AUTOMIXMON = (1 << 15),
1614 OPT_CALLER_AUTOMIXMON = (1 << 16),
1615 OPT_CALLEE_AUTOMON = (1 << 17),
1616 OPT_CALLER_AUTOMON = (1 << 18),
1617 OPT_PREDIAL_CALLEE = (1 << 19),
1618 OPT_PREDIAL_CALLER = (1 << 20),
1619 OPT_MUSICONHOLD_CLASS = (1 << 21),
1620};
@ OPT_CALLER_AUTOMON
Definition: app_queue.c:1616
@ OPT_CALLEE_PARK
Definition: app_queue.c:1606
@ OPT_PREDIAL_CALLER
Definition: app_queue.c:1618
@ OPT_GO_ON
Definition: app_queue.c:1599
@ OPT_IGNORE_CONNECTEDLINE
Definition: app_queue.c:1605
@ OPT_CALLEE_AUTOMON
Definition: app_queue.c:1615
@ OPT_CALLEE_TRANSFER
Definition: app_queue.c:1611
@ OPT_CALLEE_GO_ON
Definition: app_queue.c:1601
@ OPT_MARK_AS_ANSWERED
Definition: app_queue.c:1598
@ OPT_IGNORE_CALL_FW
Definition: app_queue.c:1604
@ OPT_CALLER_PARK
Definition: app_queue.c:1607
@ OPT_NO_RETRY
Definition: app_queue.c:1608
@ OPT_DATA_QUALITY
Definition: app_queue.c:1600
@ OPT_CALLER_HANGUP
Definition: app_queue.c:1603
@ OPT_MUSICONHOLD_CLASS
Definition: app_queue.c:1619
@ OPT_CALLEE_AUTOMIXMON
Definition: app_queue.c:1613
@ OPT_CALLEE_HANGUP
Definition: app_queue.c:1602
@ OPT_CALLER_AUTOMIXMON
Definition: app_queue.c:1614
@ OPT_RINGING
Definition: app_queue.c:1609
@ OPT_CALLER_TRANSFER
Definition: app_queue.c:1612
@ OPT_PREDIAL_CALLEE
Definition: app_queue.c:1617
@ OPT_RING_WHEN_RINGING
Definition: app_queue.c:1610

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

1622 {
1627 /* note: this entry _MUST_ be the last one in the enum */
1629};
@ OPT_ARG_CALLEE_GO_ON
Definition: app_queue.c:1623
@ OPT_ARG_PREDIAL_CALLEE
Definition: app_queue.c:1624
@ OPT_ARG_MUSICONHOLD_CLASS
Definition: app_queue.c:1626
@ OPT_ARG_PREDIAL_CALLER
Definition: app_queue.c:1625
@ OPT_ARG_ARRAY_SIZE
Definition: app_queue.c:1628

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

1672 {
1681};
@ QUEUE_STRATEGY_RINGALL
Definition: app_queue.c:1673
@ QUEUE_STRATEGY_RRMEMORY
Definition: app_queue.c:1677
@ QUEUE_STRATEGY_LINEAR
Definition: app_queue.c:1678
@ QUEUE_STRATEGY_LEASTRECENT
Definition: app_queue.c:1674
@ QUEUE_STRATEGY_RANDOM
Definition: app_queue.c:1676
@ QUEUE_STRATEGY_FEWESTCALLS
Definition: app_queue.c:1675
@ QUEUE_STRATEGY_RRORDERED
Definition: app_queue.c:1680
@ QUEUE_STRATEGY_WRANDOM
Definition: app_queue.c:1679

◆ anonymous enum

anonymous enum
Enumerator
QUEUE_AUTOPAUSE_OFF 
QUEUE_AUTOPAUSE_ON 
QUEUE_AUTOPAUSE_ALL 

Definition at line 1683 of file app_queue.c.

1683 {
1687};
@ QUEUE_AUTOPAUSE_ON
Definition: app_queue.c:1685
@ QUEUE_AUTOPAUSE_OFF
Definition: app_queue.c:1684
@ QUEUE_AUTOPAUSE_ALL
Definition: app_queue.c:1686

◆ agent_complete_reason

Enumerator
CALLER 
AGENT 
TRANSFER 

Definition at line 6314 of file app_queue.c.

6314 {
6315 CALLER,
6316 AGENT,
6317 TRANSFER
6318};
@ AGENT
Definition: app_queue.c:6316
@ CALLER
Definition: app_queue.c:6315
@ TRANSFER
Definition: app_queue.c:6317

◆ aqm_args

enum aqm_args
Enumerator
AQM_OPT_ARG_PAUSE_REASON 
AQM_OPT_ARG_ARRAY_SIZE 

Definition at line 1662 of file app_queue.c.

1662 {
1664 AQM_OPT_ARG_ARRAY_SIZE, /* Always last element of the enum */
1665};
@ AQM_OPT_ARG_ARRAY_SIZE
Definition: app_queue.c:1664
@ AQM_OPT_ARG_PAUSE_REASON
Definition: app_queue.c:1663

◆ aqm_flags

enum aqm_flags
Enumerator
AQMFLAG_PAUSED 
AQMFLAG_REASON 

Definition at line 1657 of file app_queue.c.

1657 {
1658 AQMFLAG_PAUSED = (1 << 1),
1659 AQMFLAG_REASON = (1 << 2),
1660};
@ AQMFLAG_REASON
Definition: app_queue.c:1659
@ AQMFLAG_PAUSED
Definition: app_queue.c:1658

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

1925 {
1926 QUEUE_EMPTY_PENALTY = (1 << 0),
1927 QUEUE_EMPTY_PAUSED = (1 << 1),
1928 QUEUE_EMPTY_INUSE = (1 << 2),
1929 QUEUE_EMPTY_RINGING = (1 << 3),
1930 QUEUE_EMPTY_UNAVAILABLE = (1 << 4),
1931 QUEUE_EMPTY_INVALID = (1 << 5),
1932 QUEUE_EMPTY_UNKNOWN = (1 << 6),
1933 QUEUE_EMPTY_WRAPUP = (1 << 7),
1934};
@ QUEUE_EMPTY_INVALID
Definition: app_queue.c:1931
@ QUEUE_EMPTY_UNKNOWN
Definition: app_queue.c:1932
@ QUEUE_EMPTY_PENALTY
Definition: app_queue.c:1926
@ QUEUE_EMPTY_RINGING
Definition: app_queue.c:1929
@ QUEUE_EMPTY_INUSE
Definition: app_queue.c:1928
@ QUEUE_EMPTY_UNAVAILABLE
Definition: app_queue.c:1930
@ QUEUE_EMPTY_WRAPUP
Definition: app_queue.c:1933
@ QUEUE_EMPTY_PAUSED
Definition: app_queue.c:1927

◆ member_properties

Enumerator
MEMBER_PENALTY 
MEMBER_RINGINUSE 

Definition at line 1936 of file app_queue.c.

1936 {
1937 MEMBER_PENALTY = 0,
1938 MEMBER_RINGINUSE = 1,
1939};
@ MEMBER_RINGINUSE
Definition: app_queue.c:1938
@ MEMBER_PENALTY
Definition: app_queue.c:1937

◆ queue_reload_mask

Enumerator
QUEUE_RELOAD_PARAMETERS 
QUEUE_RELOAD_MEMBER 
QUEUE_RELOAD_RULES 
QUEUE_RESET_STATS 

Definition at line 1689 of file app_queue.c.

1689 {
1690 QUEUE_RELOAD_PARAMETERS = (1 << 0),
1691 QUEUE_RELOAD_MEMBER = (1 << 1),
1692 QUEUE_RELOAD_RULES = (1 << 2),
1693 QUEUE_RESET_STATS = (1 << 3),
1694};
@ QUEUE_RELOAD_RULES
Definition: app_queue.c:1692
@ QUEUE_RELOAD_MEMBER
Definition: app_queue.c:1691
@ QUEUE_RESET_STATS
Definition: app_queue.c:1693
@ QUEUE_RELOAD_PARAMETERS
Definition: app_queue.c:1690

◆ queue_result

Enumerator
QUEUE_UNKNOWN 
QUEUE_TIMEOUT 
QUEUE_JOINEMPTY 
QUEUE_LEAVEEMPTY 
QUEUE_JOINUNAVAIL 
QUEUE_LEAVEUNAVAIL 
QUEUE_FULL 
QUEUE_CONTINUE 
QUEUE_WITHDRAW 

Definition at line 1795 of file app_queue.c.

1795 {
1796 QUEUE_UNKNOWN = 0,
1797 QUEUE_TIMEOUT = 1,
1798 QUEUE_JOINEMPTY = 2,
1799 QUEUE_LEAVEEMPTY = 3,
1802 QUEUE_FULL = 6,
1803 QUEUE_CONTINUE = 7,
1804 QUEUE_WITHDRAW = 8,
1805};
@ QUEUE_FULL
Definition: app_queue.c:1802
@ QUEUE_UNKNOWN
Definition: app_queue.c:1796
@ QUEUE_WITHDRAW
Definition: app_queue.c:1804
@ QUEUE_CONTINUE
Definition: app_queue.c:1803
@ QUEUE_LEAVEEMPTY
Definition: app_queue.c:1799
@ QUEUE_LEAVEUNAVAIL
Definition: app_queue.c:1801
@ QUEUE_JOINUNAVAIL
Definition: app_queue.c:1800
@ QUEUE_JOINEMPTY
Definition: app_queue.c:1798
@ QUEUE_TIMEOUT
Definition: app_queue.c:1797

◆ queue_timeout_priority

Enumerator
TIMEOUT_PRIORITY_APP 
TIMEOUT_PRIORITY_CONF 

Definition at line 1822 of file app_queue.c.

1822 {
1825};
@ TIMEOUT_PRIORITY_CONF
Definition: app_queue.c:1824
@ TIMEOUT_PRIORITY_APP
Definition: app_queue.c:1823

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

10397{
10398 struct call_queue *q;
10399 struct ast_str *out = ast_str_alloca(512);
10400 struct ao2_container *sorted_queues;
10401
10402 struct ao2_iterator queue_iter;
10403 int found = 0;
10404
10405 if (argc != 2 && argc != 3) {
10406 return CLI_SHOWUSAGE;
10407 }
10408
10409 if (argc == 3) { /* specific queue */
10410 if ((q = find_load_queue_rt_friendly(argv[2]))) {
10411 ao2_lock(q);
10412 print_queue(s, fd, q);
10413 ao2_unlock(q);
10414 queue_unref(q);
10415 } else {
10416 ast_str_set(&out, 0, "No such queue: %s.", argv[2]);
10417 do_print(s, fd, ast_str_buffer(out));
10418 }
10419 return CLI_SUCCESS;
10420 }
10421
10422 if (ast_check_realtime("queues")) {
10423 /* This block is to find any queues which are defined in realtime but
10424 * which have not yet been added to the in-core container
10425 */
10426 struct ast_config *cfg = ast_load_realtime_multientry("queues", "name LIKE", "%", SENTINEL);
10427 if (cfg) {
10428 char *category = NULL;
10429 while ((category = ast_category_browse(cfg, category))) {
10430 const char *queuename = ast_variable_retrieve(cfg, category, "name");
10431 if (ast_strlen_zero(queuename)) {
10432 ast_log(LOG_WARNING, "Ignoring realtime queue with a NULL or empty 'name.'\n");
10433 continue;
10434 }
10435 if ((q = find_load_queue_rt_friendly(queuename))) {
10436 queue_t_unref(q, "Done with temporary pointer");
10437 }
10438 }
10439 ast_config_destroy(cfg);
10440 }
10441 }
10442
10443 /*
10444 * Snapping a copy of the container prevents having to lock both the queues container
10445 * and the queue itself at the same time. It also allows us to sort the entries.
10446 */
10447 sorted_queues = ao2_container_alloc_rbtree(AO2_ALLOC_OPT_LOCK_NOLOCK, 0, call_queue_sort_fn, NULL);
10448 if (!sorted_queues) {
10449 return CLI_SUCCESS;
10450 }
10451 if (ao2_container_dup(sorted_queues, queues, 0)) {
10452 ao2_ref(sorted_queues, -1);
10453 return CLI_SUCCESS;
10454 }
10455
10456 /*
10457 * No need to lock the container since it's temporary and static.
10458 * We also unlink the entries as we use them so the container is
10459 * empty when the iterator finishes. We can then just unref the container.
10460 */
10461 queue_iter = ao2_iterator_init(sorted_queues, AO2_ITERATOR_DONTLOCK | AO2_ITERATOR_UNLINK);
10462 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
10463 struct call_queue *realtime_queue = NULL;
10464 ao2_lock(q);
10465 /* This check is to make sure we don't print information for realtime
10466 * queues which have been deleted from realtime but which have not yet
10467 * been deleted from the in-core container. Only do this if we're not
10468 * looking for a specific queue.
10469 */
10470 if (q->realtime) {
10471 realtime_queue = find_load_queue_rt_friendly(q->name);
10472 if (!realtime_queue) {
10473 ao2_unlock(q);
10474 queue_t_unref(q, "Done with iterator");
10475 continue;
10476 }
10477 queue_t_unref(realtime_queue, "Queue is already in memory");
10478 }
10479
10480 found = 1;
10481 print_queue(s, fd, q);
10482
10483 ao2_unlock(q);
10484 queue_t_unref(q, "Done with iterator"); /* Unref the iterator's reference */
10485 }
10486 ao2_iterator_destroy(&queue_iter);
10487 ao2_ref(sorted_queues, -1);
10488 if (!found) {
10489 ast_str_set(&out, 0, "No queues.");
10490 do_print(s, fd, ast_str_buffer(out));
10491 }
10492 return CLI_SUCCESS;
10493}
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:10288
static struct ao2_container * queues
Definition: app_queue.c:2073
#define queue_t_unref(q, tag)
Definition: app_queue.c:2230
#define queue_unref(q)
Definition: app_queue.c:2228
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:10278
static struct call_queue * find_load_queue_rt_friendly(const char *queuename)
Definition: app_queue.c:4087
#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:3842
int ast_check_realtime(const char *family)
Check if realtime engine is configured for family.
Definition: main/config.c:3750
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:2017
unsigned int found
Definition: app_queue.c:2018
const ast_string_field name
Definition: app_queue.c:2001
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 12213 of file app_queue.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

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

7786{
7787 struct call_queue *q;
7788 struct member *new_member, *old_member;
7789 int res = RES_NOSUCHQUEUE;
7790
7791 /*! \note Ensure the appropriate realtime queue is loaded. Note that this
7792 * short-circuits if the queue is already in memory. */
7793 if (!(q = find_load_queue_rt_friendly(queuename))) {
7794 return res;
7795 }
7796
7797 ao2_lock(q);
7798 if ((old_member = interface_exists(q, interface)) == NULL) {
7800 new_member->dynamic = 1;
7801 if (reason_paused) {
7802 ast_copy_string(new_member->reason_paused, reason_paused, sizeof(new_member->reason_paused));
7803 }
7804 member_add_to_queue(q, new_member);
7805 queue_publish_member_blob(queue_member_added_type(), queue_member_blob_create(q, new_member));
7806
7807 if (is_member_available(q, new_member)) {
7809 }
7810
7811 ao2_ref(new_member, -1);
7812 new_member = NULL;
7813
7814 if (dump) {
7816 }
7817
7818 res = RES_OKAY;
7819 } else {
7820 res = RES_OUTOFMEMORY;
7821 }
7822 } else {
7823 ao2_ref(old_member, -1);
7824 res = RES_EXISTS;
7825 }
7826 ao2_unlock(q);
7827 queue_t_unref(q, "Expiring temporary reference");
7828
7829 return res;
7830}
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:3042
static struct member * interface_exists(struct call_queue *q, const char *interface)
Definition: app_queue.c:7650
static void dump_queue_members(struct call_queue *pm_queue)
Dump all members in a specific queue to the database.
Definition: app_queue.c:7677
static int is_member_available(struct call_queue *q, struct member *mem)
Definition: app_queue.c:2783
#define RES_OUTOFMEMORY
Definition: app_queue.c:1734
#define RES_NOSUCHQUEUE
Definition: app_queue.c:1735
#define RES_OKAY
Definition: app_queue.c:1732
static void member_add_to_queue(struct call_queue *queue, struct member *mem)
Definition: app_queue.c:3738
static struct ast_json * queue_member_blob_create(struct call_queue *q, struct member *mem)
Definition: app_queue.c:2567
#define RES_EXISTS
Definition: app_queue.c:1733
static void queue_publish_member_blob(struct stasis_message_type *type, struct ast_json *blob)
Definition: app_queue.c:2543
@ 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:2005
char interface[AST_CHANNEL_NAME]
Definition: app_queue.c:1898
int dynamic
Definition: app_queue.c:1906
char membername[80]
Definition: app_queue.c:1903
int penalty
Definition: app_queue.c:1904
int paused
Definition: app_queue.c:1909
int wrapuptime
Definition: app_queue.c:1913
char reason_paused[80]
Definition: app_queue.c:1910
char state_interface[AST_CHANNEL_NAME]
Definition: app_queue.c:1901

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

3920{
3921 struct call_queue *q;
3922
3923 if ((q = ao2_t_alloc(sizeof(*q), destroy_queue, "Allocate queue"))) {
3924 if (ast_string_field_init(q, 64)) {
3925 queue_t_unref(q, "String field allocation failed");
3926 return NULL;
3927 }
3928 ast_string_field_set(q, name, queuename);
3929 }
3930 return q;
3931}
static void destroy_queue(void *obj)
Free queue's member list then its string fields.
Definition: app_queue.c:3904
#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 8546 of file app_queue.c.

8547{
8548 int res=-1;
8549 char *parse, *tmp, *temppos = NULL, *reason = NULL;
8551 AST_APP_ARG(queuename);
8552 AST_APP_ARG(interface);
8553 AST_APP_ARG(penalty);
8555 AST_APP_ARG(membername);
8556 AST_APP_ARG(state_interface);
8557 AST_APP_ARG(wrapuptime);
8558 );
8559 int penalty = 0;
8560 int paused = 0;
8561 int wrapuptime;
8562 struct ast_flags flags = { 0 };
8563
8564 if (ast_strlen_zero(data)) {
8565 ast_log(LOG_WARNING, "AddQueueMember requires an argument (queuename[,interface[,penalty[,options[,membername[,stateinterface][,wrapuptime]]]]])\n");
8566 return -1;
8567 }
8568
8569 parse = ast_strdupa(data);
8570
8572
8573 if (args.options) {
8574 char *opts[AQM_OPT_ARG_ARRAY_SIZE] = { NULL, };
8575 ast_app_parse_options(aqm_opts, &flags, opts, args.options);
8577 paused = 1;
8579 reason = ast_strdupa(opts[AQM_OPT_ARG_PAUSE_REASON]);
8580 }
8581 }
8582 }
8583
8584 if (ast_strlen_zero(args.interface)) {
8585 args.interface = ast_strdupa(ast_channel_name(chan));
8586 temppos = strrchr(args.interface, '-');
8587 if (temppos) {
8588 *temppos = '\0';
8589 }
8590 }
8591
8592 if (!ast_strlen_zero(args.penalty)) {
8593 if ((sscanf(args.penalty, "%30d", &penalty) != 1) || penalty < 0) {
8594 ast_log(LOG_WARNING, "Penalty '%s' is invalid, must be an integer >= 0\n", args.penalty);
8595 penalty = 0;
8596 }
8597 }
8598
8599 if (!ast_strlen_zero(args.wrapuptime)) {
8600 tmp = args.wrapuptime;
8601 ast_strip(tmp);
8602 wrapuptime = atoi(tmp);
8603 if (wrapuptime < 0) {
8604 wrapuptime = 0;
8605 }
8606 } else {
8607 wrapuptime = 0;
8608 }
8609
8610 switch (add_to_queue(args.queuename, args.interface, args.membername, penalty, paused, queue_persistent_members, args.state_interface, reason, wrapuptime)) {
8611 case RES_OKAY:
8612 if (ast_strlen_zero(args.membername) || !log_membername_as_agent) {
8613 ast_queue_log(args.queuename, ast_channel_uniqueid(chan), args.interface, "ADDMEMBER", "%s", paused ? "PAUSED" : "");
8614 } else {
8615 ast_queue_log(args.queuename, ast_channel_uniqueid(chan), args.membername, "ADDMEMBER", "%s", paused ? "PAUSED" : "");
8616 }
8617 ast_log(LOG_NOTICE, "Added interface '%s' to queue '%s'\n", args.interface, args.queuename);
8618 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "ADDED");
8619 res = 0;
8620 break;
8621 case RES_EXISTS:
8622 ast_log(LOG_WARNING, "Unable to add interface '%s' to queue '%s': Already there\n", args.interface, args.queuename);
8623 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "MEMBERALREADY");
8624 res = 0;
8625 break;
8626 case RES_NOSUCHQUEUE:
8627 ast_log(LOG_WARNING, "Unable to add interface to queue '%s': No such queue\n", args.queuename);
8628 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "NOSUCHQUEUE");
8629 res = 0;
8630 break;
8631 case RES_OUTOFMEMORY:
8632 ast_log(LOG_ERROR, "Out of memory adding interface %s to queue %s\n", args.interface, args.queuename);
8633 break;
8634 }
8635
8636 return res;
8637}
static int queue_persistent_members
queues.conf [general] option
Definition: app_queue.c:1757
static int log_membername_as_agent
queues.conf [general] option
Definition: app_queue.c:1781
static const struct ast_app_option aqm_opts[128]
Definition: app_queue.c:1670
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:7785
#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:962
#define LOG_ERROR
#define LOG_NOTICE
int pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value)
Add a variable to the channel variable stack, removing the most recently set value for the same name.
char * ast_strip(char *s)
Strip leading/trailing whitespace from a string.
Definition: strings.h:223
Structure used to handle boolean flags.
Definition: utils.h:199
unsigned int flags
Definition: utils.h:200
const char * args
static struct test_options options
#define ast_test_flag(p, flag)
Definition: utils.h:63

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

Referenced by load_module().

◆ AST_MODULE_SELF_SYM()

struct ast_module * AST_MODULE_SELF_SYM ( void  )

Definition at line 12213 of file app_queue.c.

◆ autopause2int()

static int autopause2int ( const char *  autopause)
static

Definition at line 2120 of file app_queue.c.

2121{
2122 int x;
2123 /*This 'double check' that default value is OFF */
2125 return QUEUE_AUTOPAUSE_OFF;
2126 }
2127
2128 /*This 'double check' is to ensure old values works */
2129 if(ast_true(autopause)) {
2130 return QUEUE_AUTOPAUSE_ON;
2131 }
2132
2133 for (x = 0; x < ARRAY_LEN(autopausesmodes); x++) {
2134 if (!strcasecmp(autopause, autopausesmodes[x].name)) {
2135 return autopausesmodes[x].autopause;
2136 }
2137 }
2138
2139 /*This 'double check' that default value is OFF */
2140 return QUEUE_AUTOPAUSE_OFF;
2141}
static const struct autopause autopausesmodes[]
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is "true"....
Definition: utils.c:2199
int autopause
Definition: app_queue.c:1712
#define ARRAY_LEN(a)
Definition: utils.h:666

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

Referenced by queue_set_param().

◆ calc_metric()

static int calc_metric ( struct call_queue q,
struct member mem,
int  pos,
struct queue_ent qe,
struct callattempt tmp 
)
static

Calculate the metric of each member in the outgoing callattempts.

A numeric metric is given to each member depending on the ring strategy used by the queue. Members with lower metrics will be called before members with higher metrics

Return values
-1if penalties are exceeded
0otherwise

Definition at line 6236 of file app_queue.c.

6237{
6238 /* disregarding penalty on too few members? */
6239 int membercount = ao2_container_count(q->members);
6240 unsigned char usepenalty = (membercount <= q->penaltymemberslimit) ? 0 : 1;
6241 int penalty = mem->penalty;
6242
6243 if (usepenalty) {
6244 if (qe->raise_penalty != INT_MAX && penalty < qe->raise_penalty) {
6245 /* Low penalty is raised up to the current minimum */
6246 penalty = qe->raise_penalty;
6247 }
6248 if ((qe->max_penalty != INT_MAX && penalty > qe->max_penalty) ||
6249 (qe->min_penalty != INT_MAX && penalty < qe->min_penalty)) {
6250 return -1;
6251 }
6252 } else {
6253 ast_debug(1, "Disregarding penalty, %d members and %d in penaltymemberslimit.\n",
6254 membercount, q->penaltymemberslimit);
6255 }
6256
6257 switch (q->strategy) {
6259 /* Everyone equal, except for penalty */
6260 tmp->metric = penalty * 1000000 * usepenalty;
6261 break;
6263 if (pos < qe->linpos) {
6264 tmp->metric = 1000 + pos;
6265 } else {
6266 if (pos > qe->linpos) {
6267 /* Indicate there is another priority */
6268 qe->linwrapped = 1;
6269 }
6270 tmp->metric = pos;
6271 }
6272 tmp->metric += penalty * 1000000 * usepenalty;
6273 break;
6276 pos = mem->queuepos;
6277 if (pos < q->rrpos) {
6278 tmp->metric = 1000 + pos;
6279 } else {
6280 if (pos > q->rrpos) {
6281 /* Indicate there is another priority */
6282 q->wrapped = 1;
6283 }
6284 tmp->metric = pos;
6285 }
6286 tmp->metric += penalty * 1000000 * usepenalty;
6287 break;
6289 tmp->metric = ast_random() % 1000;
6290 tmp->metric += penalty * 1000000 * usepenalty;
6291 break;
6293 tmp->metric = ast_random() % ((1 + penalty) * 1000);
6294 break;
6296 tmp->metric = mem->calls;
6297 tmp->metric += penalty * 1000000 * usepenalty;
6298 break;
6300 if (!mem->lastcall) {
6301 tmp->metric = 0;
6302 } else {
6303 tmp->metric = 1000000 - (time(NULL) - mem->lastcall);
6304 }
6305 tmp->metric += penalty * 1000000 * usepenalty;
6306 break;
6307 default:
6308 ast_log(LOG_WARNING, "Can't calculate metric for unknown strategy %d\n", q->strategy);
6309 break;
6310 }
6311 return 0;
6312}
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:2059
int penaltymemberslimit
Definition: app_queue.c:2043
unsigned int wrapped
Definition: app_queue.c:2011
int strategy
Definition: app_queue.c:2016
int queuepos
Definition: app_queue.c:1911
time_t lastcall
Definition: app_queue.c:1915
int calls
Definition: app_queue.c:1905
int linpos
Definition: app_queue.c:1884
int max_penalty
Definition: app_queue.c:1880
int raise_penalty
Definition: app_queue.c:1882
int min_penalty
Definition: app_queue.c:1881
int linwrapped
Definition: app_queue.c:1885
long int ast_random(void)
Definition: utils.c:2312

References ao2_container_count(), ast_debug, ast_log, ast_random(), member::calls, member::lastcall, queue_ent::linpos, queue_ent::linwrapped, LOG_WARNING, queue_ent::max_penalty, call_queue::members, 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 4639 of file app_queue.c.

4640{
4641 if (doomed->member) {
4642 ao2_ref(doomed->member, -1);
4643 }
4645 ast_free(doomed->orig_chan_name);
4646 ast_free(doomed);
4647}
#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:2039
struct ast_party_connected_line connected
Definition: app_queue.c:1847
char * orig_chan_name
Definition: app_queue.c:1858
struct member * member
Definition: app_queue.c:1845

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

4850{
4851 struct member *memberp = call->member;
4852 int wrapuptime;
4853
4854 if (memberp->paused) {
4855 ast_debug(1, "%s paused, can't receive call\n", call->interface);
4856 return 0;
4857 }
4858
4859 if (!memberp->ringinuse && !member_status_available(memberp->status)) {
4860 ast_debug(1, "%s not available, can't receive call\n", call->interface);
4861 return 0;
4862 }
4863
4864 if (memberp->lastqueue) {
4865 wrapuptime = get_wrapuptime(memberp->lastqueue, memberp);
4866 } else {
4867 wrapuptime = get_wrapuptime(qe->parent, memberp);
4868 }
4869 if (wrapuptime && (time(NULL) - memberp->lastcall) < wrapuptime) {
4870 ast_debug(1, "Wrapuptime not yet expired on queue %s for %s\n",
4871 (memberp->lastqueue ? memberp->lastqueue->name : qe->parent->name),
4872 call->interface);
4873 return 0;
4874 }
4875
4876 if (use_weight && compare_weight(qe->parent, memberp)) {
4877 ast_debug(1, "Priority queue delaying call to %s:%s\n",
4878 qe->parent->name, call->interface);
4879 return 0;
4880 }
4881
4883 ast_debug(1, "Another caller was waiting longer; delaying call to %s:%s\n",
4884 qe->parent->name, call->interface);
4885 return 0;
4886 }
4887
4888 if (!memberp->ringinuse) {
4889 struct member *mem;
4890
4892
4893 mem = ao2_find(pending_members, memberp,
4895 if (mem) {
4896 /*
4897 * If found that means this member is currently being attempted
4898 * from another calling thread, so stop trying from this thread
4899 */
4900 ast_debug(1, "%s has another call trying, can't receive call\n",
4901 call->interface);
4902 ao2_ref(mem, -1);
4904 return 0;
4905 }
4906
4907 /*
4908 * If not found add it to the container so another queue
4909 * won't attempt to call this member at the same time.
4910 */
4911 ast_debug(3, "Add %s to pending_members\n", memberp->membername);
4912 ao2_link(pending_members, memberp);
4914
4915 /*
4916 * The queue member is available. Get current status to be sure
4917 * because the device state and extension state callbacks may
4918 * not have updated the status yet.
4919 */
4921 ast_debug(1, "%s actually not available, can't receive call\n",
4922 call->interface);
4923 pending_members_remove(memberp);
4924 return 0;
4925 }
4926 }
4927
4928 return 1;
4929}
static int is_longest_waiting_caller(struct queue_ent *caller, struct member *member)
Definition: app_queue.c:4768
static int get_wrapuptime(struct call_queue *q, struct member *member)
Return wrapuptime.
Definition: app_queue.c:2163
static int compare_weight(struct call_queue *rq, struct member *member)
Definition: app_queue.c:4734
static struct ao2_container * pending_members
Definition: app_queue.c:2690
static int force_longest_waiting_caller
queues.conf [general] option
Definition: app_queue.c:1784
static void pending_members_remove(struct member *mem)
Definition: app_queue.c:2741
static int get_queue_member_status(struct member *cur)
Return the current state of a member.
Definition: app_queue.c:3027
static int use_weight
Records that one or more queues use weight.
Definition: app_queue.c:1760
static int member_status_available(int status)
Definition: app_queue.c:4835
#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:2395
int status
Definition: app_queue.c:1908
unsigned int ringinuse
Definition: app_queue.c:1922
struct call_queue * lastqueue
Definition: app_queue.c:1918
struct call_queue * parent
Definition: app_queue.c:1863

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

7839{
7840 struct call_queue *q;
7841 struct queue_ent *current, *prev = NULL, *caller_qe = NULL;
7842 int res = RES_NOSUCHQUEUE;
7843
7844 /*! \note Ensure the appropriate realtime queue is loaded. Note that this
7845 * short-circuits if the queue is already in memory. */
7846 if (!(q = find_load_queue_rt_friendly(queuename))) {
7847 return res;
7848 }
7849
7850 ao2_lock(q);
7851 res = RES_NOT_CALLER;
7852 for (current = q->head; current; current = current->next) {
7853 if (strcmp(ast_channel_name(current->chan), caller) == 0) {
7854 ast_debug(1, "%s Caller new priority %d in queue %s\n",
7855 caller, priority, queuename);
7856 current->prio = priority;
7857 if (immediate) {
7858 /* This caller is being immediately moved in the queue so remove them */
7859 if (prev) {
7860 prev->next = current->next;
7861 } else {
7862 q->head = current->next;
7863 }
7864 caller_qe = current;
7865 /* The position for all callers is not recalculated in here as it will
7866 * be updated when the moved caller is inserted back into the queue
7867 */
7868 }
7869 res = RES_OKAY;
7870 break;
7871 } else if (immediate) {
7872 prev = current;
7873 }
7874 }
7875
7876 if (caller_qe) {
7877 int inserted = 0, pos = 0;
7878
7879 /* If a caller queue entry exists, we are applying their priority immediately
7880 * and have to reinsert them at the correct position.
7881 */
7882 prev = NULL;
7883 current = q->head;
7884 while (current) {
7885 if (!inserted && (caller_qe->prio > current->prio)) {
7886 insert_entry(q, prev, caller_qe, &pos);
7887 inserted = 1;
7888 }
7889
7890 /* We always update the position as it may have changed */
7891 current->pos = ++pos;
7892
7893 /* Move to the next caller in the queue */
7894 prev = current;
7895 current = current->next;
7896 }
7897
7898 if (!inserted) {
7899 insert_entry(q, prev, caller_qe, &pos);
7900 }
7901 }
7902
7903 ao2_unlock(q);
7904 return res;
7905}
#define RES_NOT_CALLER
Definition: app_queue.c:1737
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:2261
static int priority
size_t current
struct queue_ent * head
Definition: app_queue.c:2060
struct queue_ent * next
Definition: app_queue.c:1894

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

3229{
3230 q->holdtime = 0;
3231 q->callscompleted = 0;
3232 q->callsabandoned = 0;
3233 q->callscompletedinsl = 0;
3234 q->callsabandonedinsl = 0;
3235 q->talktime = 0;
3236
3237 if (q->members) {
3238 struct member *mem;
3239 struct ao2_iterator mem_iter = ao2_iterator_init(q->members, 0);
3240 while ((mem = ao2_iterator_next(&mem_iter))) {
3241 mem->calls = 0;
3242 mem->callcompletedinsl = 0;
3243 mem->lastcall = 0;
3244 mem->starttime = 0;
3245 ao2_ref(mem, -1);
3246 }
3247 ao2_iterator_destroy(&mem_iter);
3248 }
3249}
#define ao2_iterator_next(iter)
Definition: astobj2.h:1911
int talktime
Definition: app_queue.c:2033
int callsabandoned
Definition: app_queue.c:2035
int callscompleted
Definition: app_queue.c:2034
int callsabandonedinsl
Definition: app_queue.c:2036
int callscompletedinsl
Definition: app_queue.c:2038
int holdtime
Definition: app_queue.c:2032
time_t starttime
Definition: app_queue.c:1914
int callcompletedinsl
Definition: app_queue.c:1912

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

10232{
10233 struct call_queue *q;
10234 struct ao2_iterator queue_iter;
10235
10236 queue_iter = ao2_iterator_init(queues, 0);
10237 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
10238 ao2_lock(q);
10239 if (ast_strlen_zero(queuename) || !strcasecmp(q->name, queuename))
10240 clear_queue(q);
10241 ao2_unlock(q);
10242 queue_t_unref(q, "Done with iterator");
10243 }
10244 ao2_iterator_destroy(&queue_iter);
10245 return 0;
10246}
static void clear_queue(struct call_queue *q)
Definition: app_queue.c:3228

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

4735{
4736 struct call_queue *q;
4737 struct member *mem;
4738 int found = 0;
4739 struct ao2_iterator queue_iter;
4740
4741 queue_iter = ao2_iterator_init(queues, 0);
4742 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
4743 if (q == rq) { /* don't check myself, could deadlock */
4744 queue_t_unref(q, "Done with iterator");
4745 continue;
4746 }
4747 ao2_lock(q);
4748 if (q->count && q->members) {
4749 if ((mem = ao2_find(q->members, member, OBJ_POINTER))) {
4750 ast_debug(1, "Found matching member %s in queue '%s'\n", mem->interface, q->name);
4751 if (q->weight > rq->weight && q->count >= num_available_members(q)) {
4752 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);
4753 found = 1;
4754 }
4755 ao2_ref(mem, -1);
4756 }
4757 }
4758 ao2_unlock(q);
4759 queue_t_unref(q, "Done with iterator");
4760 if (found) {
4761 break;
4762 }
4763 }
4764 ao2_iterator_destroy(&queue_iter);
4765 return found;
4766}
static int num_available_members(struct call_queue *q)
Get the number of members available to accept a call.
Definition: app_queue.c:4701
#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 10567 of file app_queue.c.

10568{
10569 struct call_queue *q;
10570 char *ret = NULL;
10571 int which = 0;
10572 int wordlen = strlen(word);
10573 struct ao2_iterator queue_iter;
10574 const char *word_list = NULL;
10575
10576 /* for certain commands, already completed items should be left out of
10577 * the list */
10578 if (word_list_offset && strlen(line) >= word_list_offset) {
10579 word_list = line + word_list_offset;
10580 }
10581
10582 queue_iter = ao2_iterator_init(queues, 0);
10583 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
10584 if (!strncasecmp(word, q->name, wordlen) && ++which > state
10585 && (!word_list_offset || !word_in_list(word_list, q->name))) {
10586 ret = ast_strdup(q->name);
10587 queue_t_unref(q, "Done with iterator");
10588 break;
10589 }
10590 queue_t_unref(q, "Done with iterator");
10591 }
10592 ao2_iterator_destroy(&queue_iter);
10593
10594 /* Pretend "rules" is at the end of the queues list in certain
10595 * circumstances since it is an alternate command that should be
10596 * tab-completable for "queue show" */
10597 if (!ret && which == state && !wordlen && !strncmp("queue show", line, 10)) {
10598 ret = ast_strdup("rules");
10599 }
10600
10601 return ret;
10602}
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:10508
#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 11074 of file app_queue.c.

11075{
11076 /* 0 - queue; 1 - add; 2 - member; 3 - <interface>; 4 - to; 5 - <queue>; 6 - penalty; 7 - <penalty>; 8 - as; 9 - <membername> */
11077 switch (pos) {
11078 case 3: /* Don't attempt to complete name of interface (infinite possibilities) */
11079 return NULL;
11080 case 4: /* only one possible match, "to" */
11081 return state == 0 ? ast_strdup("to") : NULL;
11082 case 5: /* <queue> */
11083 return complete_queue(line, word, pos, state, 0);
11084 case 6: /* only one possible match, "penalty" */
11085 return state == 0 ? ast_strdup("penalty") : NULL;
11086 case 7:
11087 if (0 <= state && state < 100) { /* 0-99 */
11088 char *num;
11089 if ((num = ast_malloc(3))) {
11090 sprintf(num, "%d", state);
11091 }
11092 return num;
11093 } else {
11094 return NULL;
11095 }
11096 case 8: /* only one possible match, "as" */
11097 return state == 0 ? ast_strdup("as") : NULL;
11098 case 9: /* Don't attempt to complete name of member (infinite possibilities) */
11099 return NULL;
11100 default:
11101 return NULL;
11102 }
11103}
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:10567
#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 11499 of file app_queue.c.

11500{
11501 /* 0 - queue; 1 - pause; 2 - member; 3 - <interface>; 4 - queue; 5 - <queue>; 6 - reason; 7 - <reason> */
11502 switch (pos) {
11503 case 3: /* Don't attempt to complete name of interface (infinite possibilities) */
11504 return NULL;
11505 case 4: /* only one possible match, "queue" */
11506 return state == 0 ? ast_strdup("queue") : NULL;
11507 case 5: /* <queue> */
11508 return complete_queue(line, word, pos, state, 0);
11509 case 6: /* "reason" */
11510 return state == 0 ? ast_strdup("reason") : NULL;
11511 case 7: /* Can't autocomplete a reason, since it's 100% customizeable */
11512 return NULL;
11513 default:
11514 return NULL;
11515 }
11516}

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

11335{
11336 int which = 0;
11337 struct call_queue *q;
11338 struct member *m;
11339 struct ao2_iterator queue_iter;
11340 struct ao2_iterator mem_iter;
11341 int wordlen = strlen(word);
11342
11343 /* 0 - queue; 1 - remove; 2 - member; 3 - <member>; 4 - from; 5 - <queue> */
11344 if (pos > 5 || pos < 3) {
11345 return NULL;
11346 }
11347 if (pos == 4) { /* only one possible match, 'from' */
11348 return (state == 0 ? ast_strdup("from") : NULL);
11349 }
11350
11351 if (pos == 5) { /* No need to duplicate code */
11352 return complete_queue(line, word, pos, state, 0);
11353 }
11354
11355 /* here is the case for 3, <member> */
11356 queue_iter = ao2_iterator_init(queues, 0);
11357 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
11358 ao2_lock(q);
11359 mem_iter = ao2_iterator_init(q->members, 0);
11360 while ((m = ao2_iterator_next(&mem_iter))) {
11361 if (!strncasecmp(word, m->membername, wordlen) && ++which > state) {
11362 char *tmp;
11363 tmp = ast_strdup(m->interface);
11364 ao2_ref(m, -1);
11365 ao2_iterator_destroy(&mem_iter);
11366 ao2_unlock(q);
11367 queue_t_unref(q, "Done with iterator, returning interface name");
11368 ao2_iterator_destroy(&queue_iter);
11369 return tmp;
11370 }
11371 ao2_ref(m, -1);
11372 }
11373 ao2_iterator_destroy(&mem_iter);
11374 ao2_unlock(q);
11375 queue_t_unref(q, "Done with iterator");
11376 }
11377 ao2_iterator_destroy(&queue_iter);
11378
11379 return NULL;
11380}

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

11695{
11696 int which = 0;
11697 struct rule_list *rl_iter;
11698 int wordlen = strlen(word);
11699 char *ret = NULL;
11700 if (pos != 3) /* Wha? */ {
11701 return NULL;
11702 }
11703
11705 AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) {
11706 if (!strncasecmp(word, rl_iter->name, wordlen) && ++which > state) {
11707 ret = ast_strdup(rl_iter->name);
11708 break;
11709 }
11710 }
11712
11713 return ret;
11714}
#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:2066
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 11573 of file app_queue.c.

11574{
11575 /* 0 - queue; 1 - set; 2 - penalty/ringinuse; 3 - <value>; 4 - on; 5 - <member>; 6 - in; 7 - <queue>;*/
11576 switch (pos) {
11577 case 4:
11578 if (state == 0) {
11579 return ast_strdup("on");
11580 } else {
11581 return NULL;
11582 }
11583 case 6:
11584 if (state == 0) {
11585 return ast_strdup("in");
11586 } else {
11587 return NULL;
11588 }
11589 case 7:
11590 return complete_queue(line, word, pos, state, 0);
11591 default:
11592 return NULL;
11593 }
11594}

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

10605{
10606 if (pos == 2) {
10607 return complete_queue(line, word, pos, state, 0);
10608 }
10609 return NULL;
10610}

References complete_queue(), and NULL.

Referenced by queue_show().

◆ compress_char()

static int compress_char ( const char  c)
static

Definition at line 3087 of file app_queue.c.

3088{
3089 if (c < 32) {
3090 return 0;
3091 } else if (c > 96) {
3092 return c - 64;
3093 }
3094 return c - 32;
3095}
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 2954 of file app_queue.c.

2955{
2956 struct ast_context *c = NULL;
2957
2958 c = ast_context_find(parent);
2959 if (!c) {
2960 /* well, if parent doesn't exist, how can the child be included in it? */
2961 return 0;
2962 }
2963 if (!strcmp(ast_get_context_name(c), parent)) {
2964 /* found the context of the hint app_queue is using. Now, see
2965 if that context includes the one that just changed state */
2966 struct ast_include *inc = NULL;
2967
2968 while ((inc = (struct ast_include*) ast_walk_context_includes(c, inc))) {
2969 const char *includename = ast_get_include_name(inc);
2970 if (!strcasecmp(child, includename)) {
2971 return 1;
2972 }
2973 /* recurse on this context, for nested includes. The
2974 PBX extension parser will prevent infinite recursion. */
2975 if (context_included(includename, child)) {
2976 return 1;
2977 }
2978 }
2979 }
2980 return 0;
2981}
static int context_included(const char *parent, const char *child)
Returns if one context includes another context.
Definition: app_queue.c:2954
const struct ast_include * ast_walk_context_includes(const struct ast_context *con, const struct ast_include *inc)
Definition: pbx.c:8665
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 8674 of file app_queue.c.

8675{
8676 struct penalty_rule *pr_iter;
8677 struct rule_list *rl_iter;
8678 const char *tmp = ast_strlen_zero(rulename) ? qe->parent->defaultrule : rulename;
8680 AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) {
8681 if (!strcasecmp(rl_iter->name, tmp)) {
8682 break;
8683 }
8684 }
8685 if (rl_iter) {
8686 AST_LIST_TRAVERSE(&rl_iter->rules, pr_iter, list) {
8687 struct penalty_rule *new_pr = ast_calloc(1, sizeof(*new_pr));
8688 if (!new_pr) {
8689 ast_log(LOG_ERROR, "Memory allocation error when copying penalty rules! Aborting!\n");
8690 break;
8691 }
8692 new_pr->time = pr_iter->time;
8693 new_pr->max_value = pr_iter->max_value;
8694 new_pr->min_value = pr_iter->min_value;
8695 new_pr->raise_value = pr_iter->raise_value;
8696 new_pr->max_relative = pr_iter->max_relative;
8697 new_pr->min_relative = pr_iter->min_relative;
8698 new_pr->raise_relative = pr_iter->raise_relative;
8699 AST_LIST_INSERT_TAIL(&qe->qe_rules, new_pr, list);
8700 }
8701 }
8703}
#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:2001
int raise_relative
Definition: app_queue.c:1953
struct penalty_rule::@52 list
int min_relative
Definition: app_queue.c:1952
int max_relative
Definition: app_queue.c:1951
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 3042 of file app_queue.c.

3043{
3044 struct member *cur;
3045
3046 if ((cur = ao2_alloc(sizeof(*cur), destroy_queue_member_cb))) {
3047 cur->ringinuse = ringinuse;
3048 cur->penalty = penalty;
3049 cur->paused = paused;
3050 cur->wrapuptime = wrapuptime;
3051 if (paused) {
3052 time(&cur->lastpause); /* Update time of last pause */
3053 }
3054 time(&cur->logintime);
3055 ast_copy_string(cur->interface, interface, sizeof(cur->interface));
3058 } else {
3060 }
3062 ast_copy_string(cur->membername, membername, sizeof(cur->membername));
3063 } else {
3064 ast_copy_string(cur->membername, interface, sizeof(cur->membername));
3065 }
3066 if (!strchr(cur->interface, '/')) {
3067 ast_log(LOG_WARNING, "No location at interface '%s'\n", interface);
3068 }
3069 if (!strncmp(cur->state_interface, "hint:", 5)) {
3070 char *tmp = ast_strdupa(cur->state_interface), *context = tmp;
3071 char *exten = strsep(&context, "@") + 5;
3072
3073 ast_copy_string(cur->state_exten, exten, sizeof(cur->state_exten));
3074 ast_copy_string(cur->state_context, S_OR(context, "default"), sizeof(cur->state_context));
3075
3077 } else {
3078 cur->state_id = -1;
3079 }
3080 cur->status = get_queue_member_status(cur);
3081 }
3082
3083 return cur;
3084}
static int extension_state_cb(const char *context, const char *exten, struct ast_state_cb_info *info, void *data)
Definition: app_queue.c:2983
static void destroy_queue_member_cb(void *obj)
Definition: app_queue.c:3032
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:3838
#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:1917
char state_exten[AST_MAX_EXTENSION]
Definition: app_queue.c:1899
char state_context[AST_MAX_CONTEXT]
Definition: app_queue.c:1900
int state_id
Definition: app_queue.c:1902
time_t lastpause
Definition: app_queue.c:1916

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

3905{
3906 struct call_queue *q = obj;
3907 int i;
3908
3909 free_members(q, 1);
3911 for (i = 0; i < MAX_PERIODIC_ANNOUNCEMENTS; i++) {
3912 if (q->sound_periodicannounce[i]) {
3914 }
3915 }
3916 ao2_ref(q->members, -1);
3917}
#define MAX_PERIODIC_ANNOUNCEMENTS
Definition: app_queue.c:1723
static void free_members(struct call_queue *q, int all)
Iterate through queue's member list and delete them.
Definition: app_queue.c:3888
#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:2003

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

3033{
3034 struct member *mem = obj;
3035
3036 if (mem->state_id != -1) {
3038 }
3039}
int ast_extension_state_del(int id, ast_state_cb_type change_cb)
Deletes a state change watcher by ID.
Definition: pbx.c:3871

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

2819{
2820 struct ao2_iterator miter, qiter;
2821 struct ast_device_state_message *dev_state;
2822 struct member *m;
2823 struct call_queue *q;
2824 char interface[80], *slash_pos;
2825 int found = 0; /* Found this member in any queue */
2826 int found_member; /* Found this member in this queue */
2827 int avail = 0; /* Found an available member in this queue */
2828
2830 return;
2831 }
2832
2833 dev_state = stasis_message_data(msg);
2834 if (dev_state->eid) {
2835 /* ignore non-aggregate states */
2836 return;
2837 }
2838
2839 qiter = ao2_iterator_init(queues, 0);
2840 while ((q = ao2_t_iterator_next(&qiter, "Iterate over queues"))) {
2841 ao2_lock(q);
2842
2843 avail = 0;
2844 found_member = 0;
2845 miter = ao2_iterator_init(q->members, 0);
2846 for (; (m = ao2_iterator_next(&miter)); ao2_ref(m, -1)) {
2847 if (!found_member) {
2848 ast_copy_string(interface, m->state_interface, sizeof(interface));
2849
2850 if ((slash_pos = strchr(interface, '/'))) {
2851 if (!strncasecmp(interface, "Local/", 6) && (slash_pos = strchr(slash_pos + 1, '/'))) {
2852 *slash_pos = '\0';
2853 }
2854 }
2855
2856 if (!strcasecmp(interface, dev_state->device)) {
2857 found_member = 1;
2858 update_status(q, m, dev_state->state);
2859 }
2860 }
2861
2862 /* check every member until we find one NOT_INUSE */
2863 if (!avail) {
2864 avail = is_member_available(q, m);
2865 }
2866 if (avail && found_member) {
2867 /* early exit as we've found an available member and the member of interest */
2868 ao2_ref(m, -1);
2869 break;
2870 }
2871 }
2872
2873 if (found_member) {
2874 found = 1;
2875 if (avail) {
2877 } else {
2879 }
2880 }
2881
2882 ao2_iterator_destroy(&miter);
2883
2884 ao2_unlock(q);
2885 queue_t_unref(q, "Done with iterator");
2886 }
2887 ao2_iterator_destroy(&qiter);
2888
2889 if (found) {
2890 ast_debug(1, "Device '%s' changed to state '%u' (%s)\n",
2891 dev_state->device,
2892 dev_state->state,
2893 ast_devstate2str(dev_state->state));
2894 } else {
2895 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",
2896 dev_state->device,
2897 dev_state->state,
2898 ast_devstate2str(dev_state->state));
2899 }
2900
2901 return;
2902}
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:2752
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 4819 of file app_queue.c.

4820{
4821 o->stillgoing = 0;
4822 ast_hangup(o->chan);
4824 o->chan = NULL;
4825}
void ast_hangup(struct ast_channel *chan)
Hang up a channel.
Definition: channel.c:2510
struct ast_channel * chan
Definition: app_queue.c:1842
unsigned int stillgoing
Definition: app_queue.c:1855

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

10279{
10280 if (s) {
10281 astman_append(s, "%s\r\n", str);
10282 } else {
10283 ast_cli(fd, "%s\n", str);
10284 }
10285}
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:1907

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

Definition at line 7677 of file app_queue.c.

7678{
7679 struct member *cur_member;
7680 struct ast_str *value;
7681 struct ao2_iterator mem_iter;
7682
7683 if (!pm_queue) {
7684 return;
7685 }
7686
7687 /* 4K is a reasonable default for most applications, but we grow to
7688 * accommodate more if necessary. */
7689 if (!(value = ast_str_create(4096))) {
7690 return;
7691 }
7692
7693 mem_iter = ao2_iterator_init(pm_queue->members, 0);
7694 while ((cur_member = ao2_iterator_next(&mem_iter))) {
7695 if (!cur_member->dynamic) {
7696 ao2_ref(cur_member, -1);
7697 continue;
7698 }
7699
7700 ast_str_append(&value, 0, "%s%s;%d;%d;%s;%s;%s;%d",
7701 ast_str_strlen(value) ? "|" : "",
7702 cur_member->interface,
7703 cur_member->penalty,
7704 cur_member->paused,
7705 cur_member->membername,
7706 cur_member->state_interface,
7707 cur_member->reason_paused,
7708 cur_member->wrapuptime);
7709
7710 ao2_ref(cur_member, -1);
7711 }
7712 ao2_iterator_destroy(&mem_iter);
7713
7714 if (ast_str_strlen(value) && !cur_member) {
7715 if (ast_db_put(pm_family, pm_queue->name, ast_str_buffer(value))) {
7716 ast_log(LOG_WARNING, "failed to create persistent dynamic entry!\n");
7717 }
7718 } else {
7719 /* Delete the entry if the queue is empty or there is an error */
7720 ast_db_del(pm_family, pm_queue->name);
7721 }
7722
7723 ast_free(value);
7724}
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 7026 of file app_queue.c.

7027{
7028 struct queue_end_bridge *qeb = data;
7029 struct call_queue *q = qeb->q;
7030 struct ast_channel *chan = qeb->chan;
7031
7032 if (ao2_ref(qeb, -1) == 1) {
7033 set_queue_variables(q, chan);
7034 /* This unrefs the reference we made in try_calling when we allocated qeb */
7035 queue_t_unref(q, "Expire bridge_config reference");
7036 }
7037}
static void set_queue_variables(struct call_queue *q, struct ast_channel *chan)
Set variables of queue.
Definition: app_queue.c:2235
Main Channel structure associated with a channel.
struct call_queue * q
Definition: app_queue.c:7015
struct ast_channel * chan
Definition: app_queue.c:7016

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

7020{
7021 struct queue_end_bridge *qeb = bconfig->end_bridge_callback_data;
7022 ao2_ref(qeb, +1);
7023 qeb->chan = originator;
7024}
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 7066 of file app_queue.c.

7068{
7069 const char *m = input;
7070 char escaped[size];
7071 char *p;
7072
7073 for (p = escaped; p < escaped + size - 1; p++, m++) {
7074 switch (*m) {
7075 case '^':
7076 if (*(m + 1) == '{') {
7077 *p = '$';
7078 }
7079 break;
7080 case ',':
7081 *p++ = '\\';
7082 /* Fall through */
7083 default:
7084 *p = *m;
7085 }
7086 if (*m == '\0')
7087 break;
7088 }
7089
7090 if (p == escaped + size) {
7091 escaped[size - 1] = '\0';
7092 }
7093
7094 pbx_substitute_variables_helper(chan, escaped, output, size - 1);
7095}
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 2983 of file app_queue.c.

2984{
2985 struct ao2_iterator miter, qiter;
2986 struct member *m;
2987 struct call_queue *q;
2988 int state = info->exten_state;
2989 int found = 0, device_state = extensionstate2devicestate(state);
2990
2991 /* only interested in extension state updates involving device states */
2992 if (info->reason != AST_HINT_UPDATE_DEVICE) {
2993 return 0;
2994 }
2995
2996 qiter = ao2_iterator_init(queues, 0);
2997 while ((q = ao2_t_iterator_next(&qiter, "Iterate through queues"))) {
2998 ao2_lock(q);
2999
3000 miter = ao2_iterator_init(q->members, 0);
3001 for (; (m = ao2_iterator_next(&miter)); ao2_ref(m, -1)) {
3002 if (!strcmp(m->state_exten, exten) &&
3004 /* context could be included in m->state_context. We need to check. */
3005 found = 1;
3006 update_status(q, m, device_state);
3007 }
3008 }
3009 ao2_iterator_destroy(&miter);
3010
3011 ao2_unlock(q);
3012 queue_t_unref(q, "Done with iterator");
3013 }
3014 ao2_iterator_destroy(&qiter);
3015
3016 if (found) {
3017 ast_debug(1, "Extension '%s@%s' changed to state '%d' (%s)\n", exten, context, device_state, ast_devstate2str(device_state));
3018 } else {
3019 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",
3020 exten, context, device_state, ast_devstate2str(device_state));
3021 }
3022
3023 return 0;
3024}
static int extensionstate2devicestate(int state)
Helper function which converts from extension state to device state values.
Definition: app_queue.c:2905
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 2905 of file app_queue.c.

2906{
2907 switch (state) {
2910 break;
2913 break;
2914 case AST_EXTENSION_BUSY:
2916 break;
2919 break;
2922 break;
2925 break;
2928 break;
2931 break;
2934 default:
2936 break;
2937 }
2938
2939 return state;
2940}
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 5077 of file app_queue.c.

5078{
5079 struct callattempt *best = NULL, *cur;
5080
5081 for (cur = outgoing; cur; cur = cur->q_next) {
5082 if (cur->stillgoing && /* Not already done */
5083 !cur->chan && /* Isn't already going */
5084 (!best || cur->metric < best->metric)) { /* We haven't found one yet, or it's better */
5085 best = cur;
5086 }
5087 }
5088
5089 return best;
5090}
We define a custom "local user" structure because we use it not only for keeping track of what is in ...
Definition: app_queue.c:1839

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

4088{
4089 struct ast_variable *queue_vars;
4090 struct ast_config *member_config = NULL;
4091 struct call_queue *q = NULL, tmpq = {
4092 .name = queuename,
4093 };
4094 int prev_weight = 0;
4095
4096 /* Find the queue in the in-core list first. */
4097 q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Look for queue in memory first");
4098
4099 if (!q || q->realtime) {
4100 /*! \note Load from realtime before taking the "queues" container lock, to avoid blocking all
4101 queue operations while waiting for the DB.
4102
4103 This will be two separate database transactions, so we might
4104 see queue parameters as they were before another process
4105 changed the queue and member list as it was after the change.
4106 Thus we might see an empty member list when a queue is
4107 deleted. In practise, this is unlikely to cause a problem. */
4108
4109 queue_vars = ast_load_realtime("queues", "name", queuename, SENTINEL);
4110 if (queue_vars) {
4111 member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name", queuename, SENTINEL);
4112 if (!member_config) {
4113 ast_debug(1, "No queue_members defined in config extconfig.conf\n");
4114 member_config = ast_config_new();
4115 }
4116 }
4117 if (q) {
4118 prev_weight = q->weight ? 1 : 0;
4119 queue_t_unref(q, "Need to find realtime queue");
4120 }
4121
4122 q = find_queue_by_name_rt(queuename, queue_vars, member_config);
4123 ast_config_destroy(member_config);
4124 ast_variables_destroy(queue_vars);
4125
4126 /* update the use_weight value if the queue's has gained or lost a weight */
4127 if (q) {
4128 if (!q->weight && prev_weight) {
4130 }
4131 if (q->weight && !prev_weight) {
4133 }
4134 }
4135 /* Other cases will end up with the proper value for use_weight */
4136 } else {
4138 }
4139 return q;
4140}
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:3943
static void update_realtime_members(struct call_queue *q)
Definition: app_queue.c:4192
#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:3726
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_qac_dep(), queue_function_queuememberlist(), queue_function_var(), qupd_exec(), reload_queue_members(), request_withdraw_caller_from_queue(), and set_member_value().

◆ find_member_by_queuename_and_interface()

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

Find a member by looking up queuename and interface.

Returns
member or NULL if member not found.

Definition at line 12193 of file app_queue.c.

12194{
12195 struct member *mem = NULL;
12196 struct call_queue *q;
12197
12198 if ((q = find_load_queue_rt_friendly(queuename))) {
12199 ao2_lock(q);
12200 mem = ao2_find(q->members, interface, OBJ_KEY);
12201 ao2_unlock(q);
12202 queue_t_unref(q, "Expiring temporary reference.");
12203 }
12204 return mem;
12205}
#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 3943 of file app_queue.c.

3944{
3945 struct ast_variable *v;
3946 struct call_queue *q, tmpq = {
3947 .name = queuename,
3948 };
3949 struct member *m;
3950 struct ao2_iterator mem_iter;
3951 char *category = NULL;
3952 const char *tmp_name;
3953 char *tmp;
3954 char tmpbuf[64]; /* Must be longer than the longest queue param name. */
3955
3956 /* Static queues override realtime. */
3957 if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Check if static queue exists"))) {
3958 ao2_lock(q);
3959 if (!q->realtime) {
3960 if (q->dead) {
3961 ao2_unlock(q);
3962 queue_t_unref(q, "Queue is dead; can't return it");
3963 return NULL;
3964 }
3965 ast_log(LOG_WARNING, "Static queue '%s' already exists. Not loading from realtime\n", q->name);
3966 ao2_unlock(q);
3967 return q;
3968 }
3969 } else if (!member_config) {
3970 /* Not found in the list, and it's not realtime ... */
3971 return NULL;
3972 }
3973 /* Check if queue is defined in realtime. */
3974 if (!queue_vars) {
3975 /* Delete queue from in-core list if it has been deleted in realtime. */
3976 if (q) {
3977 /*! \note Hmm, can't seem to distinguish a DB failure from a not
3978 found condition... So we might delete an in-core queue
3979 in case of DB failure. */
3980 ast_debug(1, "Queue %s not found in realtime.\n", queuename);
3981
3982 q->dead = 1;
3983 /* Delete if unused (else will be deleted when last caller leaves). */
3984 queues_t_unlink(queues, q, "Unused; removing from container");
3985 ao2_unlock(q);
3986 queue_t_unref(q, "Queue is dead; can't return it");
3987 }
3988 return NULL;
3989 }
3990
3991 /* Create a new queue if an in-core entry does not exist yet. */
3992 if (!q) {
3993 struct ast_variable *tmpvar = NULL;
3994 if (!(q = alloc_queue(queuename))) {
3995 return NULL;
3996 }
3997 ao2_lock(q);
3998 clear_queue(q);
3999 q->realtime = 1;
4000 /*Before we initialize the queue, we need to set the strategy, so that linear strategy
4001 * will allocate the members properly
4002 */
4003 for (tmpvar = queue_vars; tmpvar; tmpvar = tmpvar->next) {
4004 if (!strcasecmp(tmpvar->name, "strategy")) {
4005 q->strategy = strat2int(tmpvar->value);
4006 if (q->strategy < 0) {
4007 ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n",
4008 tmpvar->value, q->name);
4010 }
4011 break;
4012 }
4013 }
4014 /* We traversed all variables and didn't find a strategy */
4015 if (!tmpvar) {
4017 }
4018 queues_t_link(queues, q, "Add queue to container");
4019 }
4020 init_queue(q); /* Ensure defaults for all parameters not set explicitly. */
4021
4022 memset(tmpbuf, 0, sizeof(tmpbuf));
4023 for (v = queue_vars; v; v = v->next) {
4024 /* Convert to dashes `-' from underscores `_' as the latter are more SQL friendly. */
4025 if (strchr(v->name, '_')) {
4026 ast_copy_string(tmpbuf, v->name, sizeof(tmpbuf));
4027 tmp_name = tmpbuf;
4028 tmp = tmpbuf;
4029 while ((tmp = strchr(tmp, '_'))) {
4030 *tmp++ = '-';
4031 }
4032 } else {
4033 tmp_name = v->name;
4034 }
4035
4036 /* NULL values don't get returned from realtime; blank values should
4037 * still get set. If someone doesn't want a value to be set, they
4038 * should set the realtime column to NULL, not blank. */
4039 queue_set_param(q, tmp_name, v->value, -1, 0);
4040 }
4041
4042 /* Temporarily set realtime members dead so we can detect deleted ones. */
4043 mem_iter = ao2_iterator_init(q->members, 0);
4044 while ((m = ao2_iterator_next(&mem_iter))) {
4045 if (m->realtime) {
4046 m->dead = 1;
4047 }
4048 ao2_ref(m, -1);
4049 }
4050 ao2_iterator_destroy(&mem_iter);
4051
4052 while ((category = ast_category_browse(member_config, category))) {
4053 rt_handle_member_record(q, category, member_config);
4054 }
4055
4056 /* Delete all realtime members that have been deleted in DB. */
4057 mem_iter = ao2_iterator_init(q->members, 0);
4058 while ((m = ao2_iterator_next(&mem_iter))) {
4059 if (m->dead) {
4061 ast_queue_log(q->name, "REALTIME", m->interface, "REMOVEMEMBER", "%s", "");
4062 } else {
4063 ast_queue_log(q->name, "REALTIME", m->membername, "REMOVEMEMBER", "%s", "");
4064 }
4066 }
4067 ao2_ref(m, -1);
4068 }
4069 ao2_iterator_destroy(&mem_iter);
4070
4071 ao2_unlock(q);
4072
4073 return q;
4074}
static void member_remove_from_queue(struct call_queue *queue, struct member *mem)
Definition: app_queue.c:3754
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:3770
#define queues_t_unlink(c, q, tag)
Definition: app_queue.c:2232
#define queues_t_link(c, q, tag)
Definition: app_queue.c:2231
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:3524
static void init_queue(struct call_queue *q)
Initialize Queue default values.
Definition: app_queue.c:3126
static struct call_queue * alloc_queue(const char *queuename)
Definition: app_queue.c:3919
static int strat2int(const char *strategy)
Definition: app_queue.c:2107
struct ast_variable * next
unsigned int dead
Definition: app_queue.c:2004
unsigned int dead
Definition: app_queue.c:1919
int realtime
Definition: app_queue.c:1907

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

3889{
3890 /* Free non-dynamic members */
3891 struct member *cur;
3892 struct ao2_iterator mem_iter = ao2_iterator_init(q->members, 0);
3893
3894 while ((cur = ao2_iterator_next(&mem_iter))) {
3895 if (all || !cur->dynamic) {
3897 }
3898 ao2_ref(cur, -1);
3899 }
3900 ao2_iterator_destroy(&mem_iter);
3901}

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

9221{
9222 struct member *m;
9223
9225 ast_log(LOG_ERROR, "QUEUE_MEMBER: Missing required interface argument.\n");
9226 return NULL;
9227 }
9228
9230 if (!m) {
9231 ast_log(LOG_ERROR, "Queue member interface '%s' not in queue '%s'.\n",
9232 interface, q->name);
9233 }
9234 return m;
9235}

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

8262{
8263 int foundqueue = 0, penalty;
8264 struct call_queue *q;
8265 struct member *mem;
8266
8267 if ((q = find_load_queue_rt_friendly(queuename))) {
8268 foundqueue = 1;
8269 ao2_lock(q);
8270 if ((mem = interface_exists(q, interface))) {
8271 penalty = mem->penalty;
8272 ao2_ref(mem, -1);
8273 ao2_unlock(q);
8274 queue_t_unref(q, "Search complete");
8275 return penalty;
8276 }
8277 ao2_unlock(q);
8278 queue_t_unref(q, "Search complete");
8279 }
8280
8281 /* some useful debugging */
8282 if (foundqueue) {
8283 ast_log (LOG_ERROR, "Invalid queuename\n");
8284 } else {
8285 ast_log (LOG_ERROR, "Invalid interface\n");
8286 }
8287
8288 return RESULT_FAILURE;
8289}
#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 2594 of file app_queue.c.

2595{
2596 struct member *member;
2597 struct ao2_iterator mem_iter;
2598
2599 ao2_lock(q);
2600 mem_iter = ao2_iterator_init(q->members, 0);
2601 for (; (member = ao2_iterator_next(&mem_iter)); ao2_ref(member, -1)) {
2602 int penalty = member->penalty;
2603 if (raise_penalty != INT_MAX && penalty < raise_penalty) {
2604 /* Check if we should respect minimum penalty threshold */
2605 if (raise_respect_min && penalty < min_penalty) {
2606 ast_debug(4, "%s penalty %d not raised (below min %d)\n", member->membername, penalty, min_penalty);
2607 } else {
2608 ast_debug(4, "%s is having his penalty raised up from %d to %d\n", member->membername, penalty, raise_penalty);
2609 penalty = raise_penalty;
2610 }
2611 }
2612 if ((max_penalty != INT_MAX && penalty > max_penalty) || (min_penalty != INT_MAX && penalty < min_penalty)) {
2613 if (conditions & QUEUE_EMPTY_PENALTY) {
2614 ast_debug(4, "%s is unavailable because his penalty is not between %d and %d\n", member->membername, min_penalty, max_penalty);
2615 continue;
2616 }
2617 }
2618
2619 switch (devstate ? ast_device_state(member->state_interface) : member->status) {
2620 case AST_DEVICE_INVALID:
2621 if (conditions & QUEUE_EMPTY_INVALID) {
2622 ast_debug(4, "%s is unavailable because his device state is 'invalid'\n", member->membername);
2623 break;
2624 }
2625 goto default_case;
2627 if (conditions & QUEUE_EMPTY_UNAVAILABLE) {
2628 ast_debug(4, "%s is unavailable because his device state is 'unavailable'\n", member->membername);
2629 break;
2630 }
2631 goto default_case;
2632 case AST_DEVICE_INUSE:
2633 if (conditions & QUEUE_EMPTY_INUSE) {
2634 ast_debug(4, "%s is unavailable because his device state is 'inuse'\n", member->membername);
2635 break;
2636 }
2637 goto default_case;
2638 case AST_DEVICE_RINGING:
2639 if (conditions & QUEUE_EMPTY_RINGING) {
2640 ast_debug(4, "%s is unavailable because his device state is 'ringing'\n", member->membername);
2641 break;
2642 }
2643 goto default_case;
2644 case AST_DEVICE_UNKNOWN:
2645 if (conditions & QUEUE_EMPTY_UNKNOWN) {
2646 ast_debug(4, "%s is unavailable because his device state is 'unknown'\n", member->membername);
2647 break;
2648 }
2649 /* Fall-through */
2650 default:
2651 default_case:
2652 if (member->paused && (conditions & QUEUE_EMPTY_PAUSED)) {
2653 ast_debug(4, "%s is unavailable because he is paused'\n", member->membername);
2654 break;
2655 } else if ((conditions & QUEUE_EMPTY_WRAPUP)
2656 && member->lastcall
2657 && get_wrapuptime(q, member)
2658 && (time(NULL) - get_wrapuptime(q, member) < member->lastcall)) {
2659 ast_debug(4, "%s is unavailable because it has only been %d seconds since his last call (wrapup time is %d)\n",
2660 member->membername, (int) (time(NULL) - member->lastcall), get_wrapuptime(q, member));
2661 break;
2662 } else {
2663 ao2_ref(member, -1);
2664 ao2_iterator_destroy(&mem_iter);
2665 ao2_unlock(q);
2666 ast_debug(4, "%s is available.\n", member->membername);
2667 return 0;
2668 }
2669 break;
2670 }
2671 }
2672 ao2_iterator_destroy(&mem_iter);
2673 ao2_unlock(q);
2674
2675 if (!devstate && (conditions & QUEUE_EMPTY_RINGING)) {
2676 /* member state still may be RINGING due to lag in event message - check again with device state */
2677 return get_member_status(q, max_penalty, min_penalty, raise_penalty, conditions, 1, raise_respect_min);
2678 }
2679 return -1;
2680}
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:2594
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 3027 of file app_queue.c.

3028{
3029 return ast_strlen_zero(cur->state_exten) ? ast_device_state(cur->state_interface) : extensionstate2devicestate(ast_extension_state(NULL, cur->state_context, cur->state_exten));
3030}
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:3185

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

2164{
2165 if (member->wrapuptime) {
2166 return member->wrapuptime;
2167 }
2168 return q->wrapuptime;
2169}
int wrapuptime
Definition: app_queue.c:2042

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

6662{
6663 struct queue_stasis_data *queue_data = userdata;
6664 struct ast_attended_transfer_message *atxfer_msg = stasis_message_data(msg);
6665 RAII_VAR(struct ast_channel_snapshot *, caller_snapshot, NULL, ao2_cleanup);
6666 RAII_VAR(struct ast_channel_snapshot *, member_snapshot, NULL, ao2_cleanup);
6667
6668 if (atxfer_msg->result != AST_BRIDGE_TRANSFER_SUCCESS ||
6670 return;
6671 }
6672
6673 ao2_lock(queue_data);
6674
6675 if (queue_data->dying) {
6676 ao2_unlock(queue_data);
6677 return;
6678 }
6679
6680 if (ast_strlen_zero(queue_data->bridge_uniqueid)) {
6681 ao2_unlock(queue_data);
6682 return;
6683 }
6684
6685 if ((!atxfer_msg->to_transferee.bridge_snapshot || strcmp(queue_data->bridge_uniqueid,
6686 atxfer_msg->to_transferee.bridge_snapshot->uniqueid)) &&
6687 (!atxfer_msg->to_transfer_target.bridge_snapshot || strcmp(queue_data->bridge_uniqueid,
6689 ao2_unlock(queue_data);
6690 return;
6691 }
6692
6693 caller_snapshot = ast_channel_snapshot_get_latest(queue_data->caller_uniqueid);
6694 member_snapshot = ast_channel_snapshot_get_latest(queue_data->member_uniqueid);
6695
6696 ao2_unlock(queue_data);
6697
6698 ast_debug(3, "Detected attended transfer in queue %s\n", queue_data->queue->name);
6699 log_attended_transfer(queue_data, atxfer_msg);
6700
6701 send_agent_complete(queue_data->queue->name, caller_snapshot, member_snapshot, queue_data->member,
6702 queue_data->holdstart, queue_data->starttime, TRANSFER);
6703 update_queue(queue_data->queue, queue_data->member, queue_data->callcompletedinsl,
6704 queue_data->starttime);
6705 remove_stasis_subscriptions(queue_data);
6706}
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:6321
static int update_queue(struct call_queue *q, struct member *member, int callcompletedinsl, time_t starttime)
update the queue status
Definition: app_queue.c:6164
static void remove_stasis_subscriptions(struct queue_stasis_data *queue_data)
Definition: app_queue.c:6468
static void log_attended_transfer(struct queue_stasis_data *queue_data, struct ast_attended_transfer_message *atxfer_msg)
Definition: app_queue.c:6522
#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:6414
const ast_string_field caller_uniqueid
Definition: app_queue.c:6422
const ast_string_field member_uniqueid
Definition: app_queue.c:6422
struct call_queue * queue
Definition: app_queue.c:6424
const ast_string_field bridge_uniqueid
Definition: app_queue.c:6422
struct member * member
Definition: app_queue.c:6426
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:941

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

Referenced by setup_stasis_subs().

◆ handle_blind_transfer()

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

Handle a blind transfer event.

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

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

Definition at line 6601 of file app_queue.c.

6603{
6604 struct queue_stasis_data *queue_data = userdata;
6605 struct ast_blind_transfer_message *transfer_msg = stasis_message_data(msg);
6606 const char *exten;
6607 const char *context;
6608 RAII_VAR(struct ast_channel_snapshot *, caller_snapshot, NULL, ao2_cleanup);
6609 RAII_VAR(struct ast_channel_snapshot *, member_snapshot, NULL, ao2_cleanup);
6610
6611 if (transfer_msg->result != AST_BRIDGE_TRANSFER_SUCCESS) {
6612 return;
6613 }
6614
6615 ao2_lock(queue_data);
6616
6617 if (queue_data->dying) {
6618 ao2_unlock(queue_data);
6619 return;
6620 }
6621
6622 if (ast_strlen_zero(queue_data->bridge_uniqueid) ||
6623 strcmp(queue_data->bridge_uniqueid, transfer_msg->bridge->uniqueid)) {
6624 ao2_unlock(queue_data);
6625 return;
6626 }
6627
6628 caller_snapshot = ast_channel_snapshot_get_latest(queue_data->caller_uniqueid);
6629 member_snapshot = ast_channel_snapshot_get_latest(queue_data->member_uniqueid);
6630
6631 ao2_unlock(queue_data);
6632
6633 exten = transfer_msg->exten;
6634 context = transfer_msg->context;
6635
6636 ast_debug(3, "Detected blind transfer in queue %s\n", queue_data->queue->name);
6637 ast_queue_log(queue_data->queue->name, queue_data->caller_uniqueid, queue_data->member->membername,
6638 "BLINDTRANSFER", "%s|%s|%ld|%ld|%d",
6639 exten, context,
6640 (long) (queue_data->starttime - queue_data->holdstart),
6641 (long) (time(NULL) - queue_data->starttime), queue_data->caller_pos);
6642
6643 send_agent_complete(queue_data->queue->name, caller_snapshot, member_snapshot, queue_data->member,
6644 queue_data->holdstart, queue_data->starttime, TRANSFER);
6645 update_queue(queue_data->queue, queue_data->member, queue_data->callcompletedinsl,
6646 queue_data->starttime);
6647 remove_stasis_subscriptions(queue_data);
6648}
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 6568 of file app_queue.c.

6570{
6571 struct queue_stasis_data *queue_data = userdata;
6572 struct ast_bridge_blob *enter_blob = stasis_message_data(msg);
6573 SCOPED_AO2LOCK(lock, queue_data);
6574
6575 if (queue_data->dying) {
6576 return;
6577 }
6578
6579 if (!ast_strlen_zero(queue_data->bridge_uniqueid)) {
6580 return;
6581 }
6582
6583 if (!strcmp(enter_blob->channel->base->uniqueid, queue_data->caller_uniqueid)) {
6584 ast_string_field_set(queue_data, bridge_uniqueid,
6585 enter_blob->bridge->uniqueid);
6586 ast_debug(3, "Detected entry of caller channel %s into bridge %s\n",
6587 enter_blob->channel->base->name, queue_data->bridge_uniqueid);
6588 }
6589}
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 6849 of file app_queue.c.

6851{
6852 struct queue_stasis_data *queue_data = userdata;
6853 struct ast_channel_blob *channel_blob = stasis_message_data(msg);
6854 RAII_VAR(struct ast_channel_snapshot *, caller_snapshot, NULL, ao2_cleanup);
6855 RAII_VAR(struct ast_channel_snapshot *, member_snapshot, NULL, ao2_cleanup);
6856 RAII_VAR(struct ast_channel *, chan, NULL, ao2_cleanup);
6857 enum agent_complete_reason reason;
6858
6859 ao2_lock(queue_data);
6860
6861 if (queue_data->dying) {
6862 ao2_unlock(queue_data);
6863 return;
6864 }
6865
6866 if (!strcmp(channel_blob->snapshot->base->uniqueid, queue_data->caller_uniqueid)) {
6867 reason = CALLER;
6868 } else if (!strcmp(channel_blob->snapshot->base->uniqueid, queue_data->member_uniqueid)) {
6869 reason = AGENT;
6870 } else {
6871 ao2_unlock(queue_data);
6872 return;
6873 }
6874
6875 chan = ast_channel_get_by_name(channel_blob->snapshot->base->name);
6876 if (chan && (ast_channel_has_role(chan, AST_TRANSFERER_ROLE_NAME) ||
6877 !ast_strlen_zero(pbx_builtin_getvar_helper(chan, "ATTENDEDTRANSFER")) ||
6878 !ast_strlen_zero(pbx_builtin_getvar_helper(chan, "BLINDTRANSFER")))) {
6879 /* Channel that is hanging up is doing it as part of a transfer.
6880 * We'll get a transfer event later
6881 */
6882 ao2_unlock(queue_data);
6883 return;
6884 }
6885
6886 caller_snapshot = ast_channel_snapshot_get_latest(queue_data->caller_uniqueid);
6887 member_snapshot = ast_channel_snapshot_get_latest(queue_data->member_uniqueid);
6888
6889 ao2_unlock(queue_data);
6890
6891 ast_debug(3, "Detected hangup of queue %s channel %s\n", reason == CALLER ? "caller" : "member",
6892 channel_blob->snapshot->base->name);
6893
6894 ast_queue_log(queue_data->queue->name, queue_data->caller_uniqueid, queue_data->member->membername,
6895 reason == CALLER ? "COMPLETECALLER" : "COMPLETEAGENT", "%ld|%ld|%d",
6896 (long) (queue_data->starttime - queue_data->holdstart),
6897 (long) (time(NULL) - queue_data->starttime), queue_data->caller_pos);
6898
6899 send_agent_complete(queue_data->queue->name, caller_snapshot, member_snapshot, queue_data->member,
6900 queue_data->holdstart, queue_data->starttime, reason);
6901 update_queue(queue_data->queue, queue_data->member, queue_data->callcompletedinsl,
6902 queue_data->starttime);
6903 remove_stasis_subscriptions(queue_data);
6904}
agent_complete_reason
Definition: app_queue.c:6314
#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:1397
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 6734 of file app_queue.c.

6736{
6737 struct queue_stasis_data *queue_data = userdata;
6738 struct ast_multi_channel_blob *optimization_blob = stasis_message_data(msg);
6739 struct ast_channel_snapshot *local_one = ast_multi_channel_blob_get_channel(optimization_blob, "1");
6740 struct ast_channel_snapshot *local_two = ast_multi_channel_blob_get_channel(optimization_blob, "2");
6741 struct ast_channel_snapshot *source = ast_multi_channel_blob_get_channel(optimization_blob, "source");
6742 struct local_optimization *optimization;
6743 unsigned int id;
6744 SCOPED_AO2LOCK(lock, queue_data);
6745
6746 if (queue_data->dying) {
6747 return;
6748 }
6749
6750 if (!strcmp(local_one->base->uniqueid, queue_data->member_uniqueid)) {
6751 optimization = &queue_data->member_optimize;
6752 } else if (!strcmp(local_two->base->uniqueid, queue_data->caller_uniqueid)) {
6753 optimization = &queue_data->caller_optimize;
6754 } else {
6755 return;
6756 }
6757
6758 /* We only allow move-swap optimizations, so there had BETTER be a source */
6759 ast_assert(source != NULL);
6760
6761 optimization->source_chan_uniqueid = ast_strdup(source->base->uniqueid);
6762 if (!optimization->source_chan_uniqueid) {
6763 ast_log(LOG_ERROR, "Unable to track local channel optimization for channel %s. Expect further errors\n", local_one->base->name);
6764 return;
6765 }
6767
6768 optimization->id = id;
6769 optimization->in_progress = 1;
6770}
enum queue_result id
Definition: app_queue.c:1808
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:6390
const char * source_chan_uniqueid
Definition: app_queue.c:6392
unsigned int id
Definition: app_queue.c:6396
struct local_optimization member_optimize
Definition: app_queue.c:6444
struct local_optimization caller_optimize
Definition: app_queue.c:6442
#define ast_assert(a)
Definition: utils.h:739

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

Referenced by setup_stasis_subs().

◆ handle_local_optimization_end()

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

Definition at line 6785 of file app_queue.c.

6787{
6788 struct queue_stasis_data *queue_data = userdata;
6789 struct ast_multi_channel_blob *optimization_blob = stasis_message_data(msg);
6790 struct ast_channel_snapshot *local_one = ast_multi_channel_blob_get_channel(optimization_blob, "1");
6791 struct ast_channel_snapshot *local_two = ast_multi_channel_blob_get_channel(optimization_blob, "2");
6792 struct local_optimization *optimization;
6793 int is_caller;
6794 unsigned int id;
6795 SCOPED_AO2LOCK(lock, queue_data);
6796
6797 if (queue_data->dying) {
6798 return;
6799 }
6800
6801 if (!strcmp(local_one->base->uniqueid, queue_data->member_uniqueid)) {
6802 optimization = &queue_data->member_optimize;
6803 is_caller = 0;
6804 } else if (!strcmp(local_two->base->uniqueid, queue_data->caller_uniqueid)) {
6805 optimization = &queue_data->caller_optimize;
6806 is_caller = 1;
6807 } else {
6808 return;
6809 }
6810
6812
6813 if (!optimization->in_progress) {
6814 ast_log(LOG_WARNING, "Told of a local optimization end when we had no previous begin\n");
6815 return;
6816 }
6817
6818 if (id != optimization->id) {
6819 ast_log(LOG_WARNING, "Local optimization end event ID does not match begin (%u != %u)\n",
6820 id, optimization->id);
6821 return;
6822 }
6823
6824 if (is_caller) {
6825 ast_debug(3, "Local optimization: Changing queue caller uniqueid from %s to %s\n",
6826 queue_data->caller_uniqueid, optimization->source_chan_uniqueid);
6827 ast_string_field_set(queue_data, caller_uniqueid, optimization->source_chan_uniqueid);
6828 } else {
6829 ast_debug(3, "Local optimization: Changing queue member uniqueid from %s to %s\n",
6830 queue_data->member_uniqueid, optimization->source_chan_uniqueid);
6831 ast_string_field_set(queue_data, member_uniqueid, optimization->source_chan_uniqueid);
6832 }
6833
6834 optimization->in_progress = 0;
6835}

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

6908{
6909 struct queue_stasis_data *queue_data = userdata;
6910 struct ast_channel_blob *channel_blob = stasis_message_data(msg);
6911 const char *new_channel_id;
6912
6913 new_channel_id = ast_json_string_get(ast_json_object_get(channel_blob->blob, "newchanneluniqueid"));
6914
6915 ao2_lock(queue_data);
6916
6917 if (queue_data->dying) {
6918 ao2_unlock(queue_data);
6919 return;
6920 }
6921
6922 if (!strcmp(channel_blob->snapshot->base->uniqueid, queue_data->caller_uniqueid)) {
6923 ast_debug(1, "Replacing caller channel %s with %s due to masquerade\n", queue_data->caller_uniqueid, new_channel_id);
6924 ast_string_field_set(queue_data, caller_uniqueid, new_channel_id);
6925 } else if (!strcmp(channel_blob->snapshot->base->uniqueid, queue_data->member_uniqueid)) {
6926 ast_debug(1, "Replacing member channel %s with %s due to masquerade\n", queue_data->member_uniqueid, new_channel_id);
6927 ast_string_field_set(queue_data, member_uniqueid, new_channel_id);
6928 }
6929
6930 ao2_unlock(queue_data);
6931}
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 11249 of file app_queue.c.

11250{
11251 const char *queuename, *interface, *membername = NULL, *state_interface = NULL, *reason = NULL;
11252 int penalty, paused = 0;
11253
11254 switch ( cmd ) {
11255 case CLI_INIT:
11256 e->command = "queue add member";
11257 e->usage =
11258 "Usage: queue add member <dial string> to <queue> [penalty <penalty> [as <membername> [state_interface <interface> [paused <reason>]]]]\n"
11259 " 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";
11260 return NULL;
11261 case CLI_GENERATE:
11262 return complete_queue_add_member(a->line, a->word, a->pos, a->n);
11263 }
11264
11265 if ((a->argc != 6) && (a->argc != 8) && (a->argc != 10) && (a->argc != 12) && (a->argc != 14)) {
11266 return CLI_SHOWUSAGE;
11267 } else if (strcmp(a->argv[4], "to")) {
11268 return CLI_SHOWUSAGE;
11269 } else if ((a->argc >= 8) && strcmp(a->argv[6], "penalty")) {
11270 return CLI_SHOWUSAGE;
11271 } else if ((a->argc >= 10) && strcmp(a->argv[8], "as")) {
11272 return CLI_SHOWUSAGE;
11273 } else if ((a->argc == 12) && strcmp(a->argv[10], "state_interface")) {
11274 return CLI_SHOWUSAGE;
11275 } else if ((a->argc == 14) && strcmp(a->argv[12], "paused")) {
11276 return CLI_SHOWUSAGE;
11277 }
11278
11279 queuename = a->argv[5];
11280 interface = a->argv[3];
11281 if (a->argc >= 8) {
11282 if (sscanf(a->argv[7], "%30d", &penalty) == 1) {
11283 if (penalty < 0) {
11284 ast_cli(a->fd, "Penalty must be >= 0\n");
11285 penalty = 0;
11286 }
11287 } else {
11288 ast_cli(a->fd, "Penalty must be an integer >= 0\n");
11289 penalty = 0;
11290 }
11291 } else {
11292 penalty = 0;
11293 }
11294
11295 if (a->argc >= 10) {
11296 membername = a->argv[9];
11297 }
11298
11299 if (a->argc >= 12) {
11300 state_interface = a->argv[11];
11301 }
11302
11303 if (a->argc >= 14) {
11304 paused = 1;
11305 reason = a->argv[13];
11306 }
11307
11308 switch (add_to_queue(queuename, interface, membername, penalty, paused, queue_persistent_members, state_interface, reason, 0)) {
11309 case RES_OKAY:
11310 if (ast_strlen_zero(membername) || !log_membername_as_agent) {
11311 ast_queue_log(queuename, "CLI", interface, "ADDMEMBER", "%s", paused ? "PAUSED" : "");
11312 } else {
11313 ast_queue_log(queuename, "CLI", membername, "ADDMEMBER", "%s", paused ? "PAUSED" : "");
11314 }
11315 ast_cli(a->fd, "Added interface '%s' to queue '%s'\n", interface, queuename);
11316 return CLI_SUCCESS;
11317 case RES_EXISTS:
11318 ast_cli(a->fd, "Unable to add interface '%s' to queue '%s': Already there\n", interface, queuename);
11319 return CLI_FAILURE;
11320 case RES_NOSUCHQUEUE:
11321 ast_cli(a->fd, "Unable to add interface to queue '%s': No such queue\n", queuename);
11322 return CLI_FAILURE;
11323 case RES_OUTOFMEMORY:
11324 ast_cli(a->fd, "Out of memory\n");
11325 return CLI_FAILURE;
11326 case RES_NOT_DYNAMIC:
11327 ast_cli(a->fd, "Member not dynamic\n");
11328 return CLI_FAILURE;
11329 default:
11330 return CLI_FAILURE;
11331 }
11332}
#define RES_NOT_DYNAMIC
Definition: app_queue.c:1736
static char * complete_queue_add_member(const char *line, const char *word, int pos, int state)
Definition: app_queue.c:11074
@ 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 11445 of file app_queue.c.

11446{
11447 const char *queuename, *caller;
11448 int priority, immediate = 0;
11449 char *res = CLI_FAILURE;
11450
11451 switch (cmd) {
11452 case CLI_INIT:
11453 e->command = "queue priority caller";
11454 e->usage =
11455 "Usage: queue priority caller <channel> on <queue> to <priority> [immediate]\n"
11456 " Change the priority of a channel on a queue, optionally applying the change in relation to existing callers.\n";
11457 return NULL;
11458 case CLI_GENERATE:
11459 return NULL;
11460 }
11461
11462 if (a->argc < 8) {
11463 return CLI_SHOWUSAGE;
11464 } else if (strcmp(a->argv[4], "on")) {
11465 return CLI_SHOWUSAGE;
11466 } else if (strcmp(a->argv[6], "to")) {
11467 return CLI_SHOWUSAGE;
11468 } else if (sscanf(a->argv[7], "%30d", &priority) != 1) {
11469 ast_log (LOG_ERROR, "<priority> parameter must be an integer.\n");
11470 return CLI_SHOWUSAGE;
11471 } else if (a->argc == 9) {
11472 if (strcmp(a->argv[8], "immediate")) {
11473 return CLI_SHOWUSAGE;
11474 }
11475 immediate = 1;
11476 }
11477
11478 caller = a->argv[3];
11479 queuename = a->argv[5];
11480
11481 switch (change_priority_caller_on_queue(queuename, caller, priority, immediate)) {
11482 case RES_OKAY:
11483 res = CLI_SUCCESS;
11484 break;
11485 case RES_NOSUCHQUEUE:
11486 ast_cli(a->fd, "Unable change priority caller %s on queue '%s': No such queue\n", caller, queuename);
11487 break;
11488 case RES_NOT_CALLER:
11489 ast_cli(a->fd, "Unable to change priority caller '%s' on queue '%s': Not there\n", caller, queuename);
11490
11491 break;
11492 }
11493
11494 return res;
11495}
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:7838

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

11519{
11520 const char *queuename, *interface, *reason;
11521 int paused;
11522
11523 switch (cmd) {
11524 case CLI_INIT:
11525 e->command = "queue {pause|unpause} member";
11526 e->usage =
11527 "Usage: queue {pause|unpause} member <member> [queue <queue> [reason <reason>]]\n"
11528 " Pause or unpause a queue member. Not specifying a particular queue\n"
11529 " will pause or unpause a member across all queues to which the member\n"
11530 " belongs.\n";
11531 return NULL;
11532 case CLI_GENERATE:
11533 return complete_queue_pause_member(a->line, a-> word, a->pos, a->n);
11534 }
11535
11536 if (a->argc < 4 || a->argc == 5 || a->argc == 7 || a->argc > 8) {
11537 return CLI_SHOWUSAGE;
11538 } else if (a->argc >= 5 && strcmp(a->argv[4], "queue")) {
11539 return CLI_SHOWUSAGE;
11540 } else if (a->argc == 8 && strcmp(a->argv[6], "reason")) {
11541 return CLI_SHOWUSAGE;
11542 }
11543
11544
11545 interface = a->argv[3];
11546 queuename = a->argc >= 6 ? a->argv[5] : NULL;
11547 reason = a->argc == 8 ? a->argv[7] : NULL;
11548 paused = !strcasecmp(a->argv[1], "pause");
11549
11550 if (set_member_paused(queuename, interface, reason, paused) == RESULT_SUCCESS) {
11551 ast_cli(a->fd, "%spaused interface '%s'", paused ? "" : "un", interface);
11552 if (!ast_strlen_zero(queuename)) {
11553 ast_cli(a->fd, " in queue '%s'", queuename);
11554 }
11555 if (!ast_strlen_zero(reason)) {
11556 ast_cli(a->fd, " for reason '%s'", reason);
11557 }
11558 ast_cli(a->fd, "\n");
11559 return CLI_SUCCESS;
11560 } else {
11561 ast_cli(a->fd, "Unable to %spause interface '%s'", paused ? "" : "un", interface);
11562 if (!ast_strlen_zero(queuename)) {
11563 ast_cli(a->fd, " in queue '%s'", queuename);
11564 }
11565 if (!ast_strlen_zero(reason)) {
11566 ast_cli(a->fd, " for reason '%s'", reason);
11567 }
11568 ast_cli(a->fd, "\n");
11569 return CLI_FAILURE;
11570 }
11571}
static char * complete_queue_pause_member(const char *line, const char *word, int pos, int state)
Definition: app_queue.c:11499
static int set_member_paused(const char *queuename, const char *interface, const char *reason, int paused)
Definition: app_queue.c:8044
#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 11790 of file app_queue.c.

11791{
11792 struct ast_flags mask = {0,};
11793 int i;
11794
11795 switch (cmd) {
11796 case CLI_INIT:
11797 e->command = "queue reload {parameters|members|rules|all}";
11798 e->usage =
11799 "Usage: queue reload {parameters|members|rules|all} [<queuenames>]\n"
11800 "Reload queues. If <queuenames> are specified, only reload information pertaining\n"
11801 "to <queuenames>. One of 'parameters,' 'members,' 'rules,' or 'all' must be\n"
11802 "specified in order to know what information to reload. Below is an explanation\n"
11803 "of each of these qualifiers.\n"
11804 "\n"
11805 "\t'members' - reload queue members from queues.conf\n"
11806 "\t'parameters' - reload all queue options except for queue members\n"
11807 "\t'rules' - reload the queuerules.conf file\n"
11808 "\t'all' - reload queue rules, parameters, and members\n"
11809 "\n"
11810 "Note: the 'rules' qualifier here cannot actually be applied to a specific queue.\n"
11811 "Use of the 'rules' qualifier causes queuerules.conf to be reloaded. Even if only\n"
11812 "one queue is specified when using this command, reloading queue rules may cause\n"
11813 "other queues to be affected\n";
11814 return NULL;
11815 case CLI_GENERATE:
11816 if (a->pos >= 3) {
11817 /* find the point at which the list of queue names starts */
11818 const char *command_end = a->line + strlen("queue reload ");
11819 command_end = strchr(command_end, ' ');
11820 if (!command_end) {
11821 command_end = a->line + strlen(a->line);
11822 }
11823 return complete_queue(a->line, a->word, a->pos, a->n, command_end - a->line);
11824 } else {
11825 return NULL;
11826 }
11827 }
11828
11829 if (a->argc < 3)
11830 return CLI_SHOWUSAGE;
11831
11832 if (!strcasecmp(a->argv[2], "rules")) {
11834 } else if (!strcasecmp(a->argv[2], "members")) {
11836 } else if (!strcasecmp(a->argv[2], "parameters")) {
11838 } else if (!strcasecmp(a->argv[2], "all")) {
11840 }
11841
11842 if (a->argc == 3) {
11843 reload_handler(1, &mask, NULL);
11844 return CLI_SUCCESS;
11845 }
11846
11847 for (i = 3; i < a->argc; ++i) {
11848 reload_handler(1, &mask, a->argv[i]);
11849 }
11850
11851 return CLI_SUCCESS;
11852}
static int reload_handler(int reload, struct ast_flags *mask, const char *queuename)
The command center for all reload operations.
Definition: app_queue.c:10261
#define ast_set_flag(p, flag)
Definition: utils.h:70
#define AST_FLAGS_ALL
Definition: utils.h:196

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

◆ handle_queue_remove_member()

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

Definition at line 11382 of file app_queue.c.

11383{
11384 const char *queuename, *interface;
11385 struct member *mem = NULL;
11386 char *res = CLI_FAILURE;
11387
11388 switch (cmd) {
11389 case CLI_INIT:
11390 e->command = "queue remove member";
11391 e->usage =
11392 "Usage: queue remove member <channel> from <queue>\n"
11393 " Remove a specific channel from a queue.\n";
11394 return NULL;
11395 case CLI_GENERATE:
11396 return complete_queue_remove_member(a->line, a->word, a->pos, a->n);
11397 }
11398
11399 if (a->argc != 6) {
11400 return CLI_SHOWUSAGE;
11401 } else if (strcmp(a->argv[4], "from")) {
11402 return CLI_SHOWUSAGE;
11403 }
11404
11405 queuename = a->argv[5];
11406 interface = a->argv[3];
11407
11409 mem = find_member_by_queuename_and_interface(queuename, interface);
11410 }
11411
11412 switch (remove_from_queue(queuename, interface)) {
11413 case RES_OKAY:
11414 if (!mem || ast_strlen_zero(mem->membername)) {
11415 ast_queue_log(queuename, "CLI", interface, "REMOVEMEMBER", "%s", "");
11416 } else {
11417 ast_queue_log(queuename, "CLI", mem->membername, "REMOVEMEMBER", "%s", "");
11418 }
11419 ast_cli(a->fd, "Removed interface %s from queue '%s'\n", interface, queuename);
11420 res = CLI_SUCCESS;
11421 break;
11422 case RES_EXISTS:
11423 ast_cli(a->fd, "Unable to remove interface '%s' from queue '%s': Not there\n", interface, queuename);
11424 break;
11425 case RES_NOSUCHQUEUE:
11426 ast_cli(a->fd, "Unable to remove interface from queue '%s': No such queue\n", queuename);
11427 break;
11428 case RES_OUTOFMEMORY:
11429 ast_cli(a->fd, "Out of memory\n");
11430 break;
11431 case RES_NOT_DYNAMIC:
11432 ast_cli(a->fd, "Unable to remove interface '%s' from queue '%s': Member is not dynamic\n", interface, queuename);
11433 break;
11434 }
11435
11436 if (mem) {
11437 ao2_ref(mem, -1);
11438 }
11439
11440 return res;
11441}
static int remove_from_queue(const char *queuename, const char *interface)
Remove member from queue.
Definition: app_queue.c:7732
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:12193
static char * complete_queue_remove_member(const char *line, const char *word, int pos, int state)
Definition: app_queue.c:11334

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

11752{
11753 struct ast_flags mask = {QUEUE_RESET_STATS,};
11754 int i;
11755
11756 switch (cmd) {
11757 case CLI_INIT:
11758 e->command = "queue reset stats";
11759 e->usage =
11760 "Usage: queue reset stats [<queuenames>]\n"
11761 "\n"
11762 "Issuing this command will reset statistics for\n"
11763 "<queuenames>, or for all queues if no queue is\n"
11764 "specified.\n";
11765 return NULL;
11766 case CLI_GENERATE:
11767 if (a->pos >= 3) {
11768 return complete_queue(a->line, a->word, a->pos, a->n, 17);
11769 } else {
11770 return NULL;
11771 }
11772 }
11773
11774 if (a->argc < 3) {
11775 return CLI_SHOWUSAGE;
11776 }
11777
11778 if (a->argc == 3) {
11779 reload_handler(1, &mask, NULL);
11780 return CLI_SUCCESS;
11781 }
11782
11783 for (i = 3; i < a->argc; ++i) {
11784 reload_handler(1, &mask, a->argv[i]);
11785 }
11786
11787 return CLI_SUCCESS;
11788}

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

11717{
11718 const char *rule;
11719 struct rule_list *rl_iter;
11720 struct penalty_rule *pr_iter;
11721 switch (cmd) {
11722 case CLI_INIT:
11723 e->command = "queue show rules";
11724 e->usage =
11725 "Usage: queue show rules [rulename]\n"
11726 " Show the list of rules associated with rulename. If no\n"
11727 " rulename is specified, list all rules defined in queuerules.conf\n";
11728 return NULL;
11729 case CLI_GENERATE:
11730 return complete_queue_rule_show(a->line, a->word, a->pos, a->n);
11731 }
11732
11733 if (a->argc != 3 && a->argc != 4) {
11734 return CLI_SHOWUSAGE;
11735 }
11736
11737 rule = a->argc == 4 ? a->argv[3] : "";
11739 AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) {
11740 if (ast_strlen_zero(rule) || !strcasecmp(rl_iter->name, rule)) {
11741 ast_cli(a->fd, "Rule: %s\n", rl_iter->name);
11742 AST_LIST_TRAVERSE(&rl_iter->rules, pr_iter, list) {
11743 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);
11744 }
11745 }
11746 }
11748 return CLI_SUCCESS;
11749}
static char * complete_queue_rule_show(const char *line, const char *word, int pos, int state)
Definition: app_queue.c:11694

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

11654{
11655 const char *queuename = NULL, *interface;
11656 int penalty = 0;
11657
11658 switch (cmd) {
11659 case CLI_INIT:
11660 e->command = "queue set penalty";
11661 e->usage =
11662 "Usage: queue set penalty <penalty> on <interface> [in <queue>]\n"
11663 " Set a member's penalty in the queue specified. If no queue is specified\n"
11664 " then that interface's penalty is set in all queues to which that interface is a member\n";
11665 return NULL;
11666 case CLI_GENERATE:
11667 return complete_queue_set_member_value(a->line, a->word, a->pos, a->n);
11668 }
11669
11670 if (a->argc != 6 && a->argc != 8) {
11671 return CLI_SHOWUSAGE;
11672 } else if (strcmp(a->argv[4], "on") || (a->argc > 6 && strcmp(a->argv[6], "in"))) {
11673 return CLI_SHOWUSAGE;
11674 }
11675
11676 if (a->argc == 8) {
11677 queuename = a->argv[7];
11678 }
11679 interface = a->argv[5];
11680 penalty = atoi(a->argv[3]);
11681
11682 switch (set_member_value(queuename, interface, MEMBER_PENALTY, penalty)) {
11683 case RESULT_SUCCESS:
11684 ast_cli(a->fd, "Set penalty on interface '%s' from queue '%s'\n", interface, queuename);
11685 return CLI_SUCCESS;
11686 case RESULT_FAILURE:
11687 ast_cli(a->fd, "Failed to set penalty on interface '%s' from queue '%s'\n", interface, queuename);
11688 return CLI_FAILURE;
11689 default:
11690 return CLI_FAILURE;
11691 }
11692}
static int set_member_value(const char *queuename, const char *interface, int property, int value)
Definition: app_queue.c:8192
static char * complete_queue_set_member_value(const char *line, const char *word, int pos, int state)
Definition: app_queue.c:11573

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

11597{
11598 const char *queuename = NULL, *interface;
11599 int ringinuse;
11600
11601 switch (cmd) {
11602 case CLI_INIT:
11603 e->command = "queue set ringinuse";
11604 e->usage =
11605 "Usage: queue set ringinuse <yes/no> on <interface> [in <queue>]\n"
11606 " Set a member's ringinuse in the queue specified. If no queue is specified\n"
11607 " then that interface's penalty is set in all queues to which that interface is a member.\n";
11608 break;
11609 return NULL;
11610 case CLI_GENERATE:
11611 return complete_queue_set_member_value(a->line, a->word, a->pos, a->n);
11612 }
11613
11614 /* Sensible argument counts */
11615 if (a->argc != 6 && a->argc != 8) {
11616 return CLI_SHOWUSAGE;
11617 }
11618
11619 /* Uses proper indicational words */
11620 if (strcmp(a->argv[4], "on") || (a->argc > 6 && strcmp(a->argv[6], "in"))) {
11621 return CLI_SHOWUSAGE;
11622 }
11623
11624 /* Set the queue name if applicable */
11625 if (a->argc == 8) {
11626 queuename = a->argv[7];
11627 }
11628
11629 /* Interface being set */
11630 interface = a->argv[5];
11631
11632 /* Check and set the ringinuse value */
11633 if (ast_true(a->argv[3])) {
11634 ringinuse = 1;
11635 } else if (ast_false(a->argv[3])) {
11636 ringinuse = 0;
11637 } else {
11638 return CLI_SHOWUSAGE;
11639 }
11640
11641 switch (set_member_value(queuename, interface, MEMBER_RINGINUSE, ringinuse)) {
11642 case RESULT_SUCCESS:
11643 ast_cli(a->fd, "Set ringinuse on interface '%s' from queue '%s'\n", interface, queuename);
11644 return CLI_SUCCESS;
11645 case RESULT_FAILURE:
11646 ast_cli(a->fd, "Failed to set ringinuse on interface '%s' from queue '%s'\n", interface, queuename);
11647 return CLI_FAILURE;
11648 default:
11649 return CLI_FAILURE;
11650 }
11651}
int attribute_pure ast_false(const char *val)
Make sure something is false. Determine if a string containing a boolean value is "false"....
Definition: utils.c:2216

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

◆ hangupcalls()

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

Hang up a list of outgoing calls.

Definition at line 4661 of file app_queue.c.

4662{
4663 struct callattempt *oo;
4664
4665 while (outgoing) {
4666 /* If someone else answered the call we should indicate this in the CANCEL */
4667 /* Hangup any existing lines we have open */
4668 if (outgoing->chan && (outgoing->chan != exception)) {
4669 if (exception || cancel_answered_elsewhere) {
4671 }
4672 ast_channel_publish_dial(qe->chan, outgoing->chan, outgoing->interface, "CANCEL");
4673
4674 /* When dialing channels it is possible that they may not ever
4675 * leave the not in use state (Local channels in particular) by
4676 * the time we cancel them. If this occurs but we know they were
4677 * dialed we explicitly remove them from the pending members
4678 * container so that subsequent call attempts occur.
4679 */
4680 if (outgoing->member->status == AST_DEVICE_NOT_INUSE) {
4682 }
4683
4684 ast_hangup(outgoing->chan);
4685 }
4686 oo = outgoing;
4687 outgoing = outgoing->q_next;
4689 callattempt_free(oo);
4690 }
4691}
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:4639
#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:1856
struct ast_channel * chan
Definition: app_queue.c:1891

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

3127{
3128 int i;
3129 struct penalty_rule *pr_iter;
3130
3131 q->dead = 0;
3132 q->retry = DEFAULT_RETRY;
3134 q->maxlen = 0;
3135
3136 ast_string_field_set(q, announce, "");
3138 ast_string_field_set(q, membergosub, "");
3139 ast_string_field_set(q, defaultrule, "");
3140
3141 q->announcefrequency = 0;
3143 q->announceholdtime = 1;
3145 q->announcepositionlimit = 10; /* Default 10 positions */
3146 q->announceposition = ANNOUNCEPOSITION_YES; /* Default yes */
3147 q->roundingseconds = 0; /* Default - don't announce seconds */
3148 q->servicelevel = 0;
3149 q->ringinuse = 1;
3151 q->setinterfacevar = 0;
3152 q->setqueuevar = 0;
3153 q->setqueueentryvar = 0;
3155 q->monfmt[0] = '\0';
3156 q->reportholdtime = 0;
3157 q->wrapuptime = 0;
3158 q->penaltymemberslimit = 0;
3159 q->joinempty = 0;
3160 q->leavewhenempty = 0;
3161 q->memberdelay = 0;
3162 q->weight = 0;
3163 q->timeoutrestart = 0;
3167 q->numperiodicannounce = 0;
3170 q->autopausebusy = 0;
3171 q->autopauseunavail = 0;
3173 q->autopausedelay = 0;
3175 if (!q->members) {
3177 /* linear strategy depends on order, so we have to place all members in a list */
3179 } else {
3182 }
3183 }
3184 q->found = 1;
3185
3186 ast_string_field_set(q, moh, "");
3187 ast_string_field_set(q, sound_next, "queue-youarenext");
3188 ast_string_field_set(q, sound_thereare, "queue-thereare");
3189 ast_string_field_set(q, sound_calls, "queue-callswaiting");
3190 ast_string_field_set(q, queue_quantity1, "queue-quantity1");
3191 ast_string_field_set(q, queue_quantity2, "queue-quantity2");
3192 ast_string_field_set(q, sound_holdtime, "queue-holdtime");
3193 ast_string_field_set(q, sound_minutes, "queue-minutes");
3194 ast_string_field_set(q, sound_minute, "queue-minute");
3195 ast_string_field_set(q, sound_seconds, "queue-seconds");
3196 ast_string_field_set(q, sound_thanks, "queue-thankyou");
3197 ast_string_field_set(q, sound_callerannounce, "");
3198 ast_string_field_set(q, sound_reporthold, "queue-reporthold");
3199
3200 if (!q->sound_periodicannounce[0]) {
3202 }
3203
3204 if (q->sound_periodicannounce[0]) {
3205 ast_str_set(&q->sound_periodicannounce[0], 0, "queue-periodic-announce");
3206 }
3207
3208 for (i = 1; i < MAX_PERIODIC_ANNOUNCEMENTS; i++) {
3209 if (q->sound_periodicannounce[i]) {
3210 ast_str_set(&q->sound_periodicannounce[i], 0, "%s", "");
3211 }
3212 }
3213
3214 while ((pr_iter = AST_LIST_REMOVE_HEAD(&q->rules,list))) {
3215 ast_free(pr_iter);
3216 }
3217
3218 /* On restart assume no members are available.
3219 * The queue_avail hint is a boolean state to indicate whether a member is available or not.
3220 *
3221 * This seems counter intuitive, but is required to light a BLF
3222 * AST_DEVICE_INUSE indicates no members are available.
3223 * AST_DEVICE_NOT_INUSE indicates a member is available.
3224 */
3226}
#define DEFAULT_RETRY
Definition: app_queue.c:1720
static int member_hash_fn(const void *obj, const int flags)
Definition: app_queue.c:3097
static int member_cmp_fn(void *obj1, void *obj2, int flags)
Definition: app_queue.c:3113
#define DEFAULT_MIN_ANNOUNCE_FREQUENCY
The minimum number of seconds between position announcements.
Definition: app_queue.c:1728
#define DEFAULT_TIMEOUT
Definition: app_queue.c:1721
static int autofill_default
queues.conf [general] option
Definition: app_queue.c:1763
#define ANNOUNCEPOSITION_YES
Definition: app_queue.c:1958
@ 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:2021
unsigned int setinterfacevar
Definition: app_queue.c:2007
int announcefrequency
Definition: app_queue.c:2025
unsigned int announceholdtime
Definition: app_queue.c:2013
unsigned int reportholdtime
Definition: app_queue.c:2010
unsigned int setqueueentryvar
Definition: app_queue.c:2009
unsigned int timeoutrestart
Definition: app_queue.c:2012
int periodicannouncefrequency
Definition: app_queue.c:2028
unsigned int announceposition_only_up
Definition: app_queue.c:2015
unsigned int setqueuevar
Definition: app_queue.c:2008
int announcepositionlimit
Definition: app_queue.c:2024
unsigned int announce_to_first_user
Definition: app_queue.c:2006
int randomperiodicannounce
Definition: app_queue.c:2030
int autopause
Definition: app_queue.c:2048
int periodicannouncestartdelay
Definition: app_queue.c:2027
int log_restricted_caller_id
Definition: app_queue.c:2057
struct call_queue::@54 rules
int servicelevel
Definition: app_queue.c:2037
int autofill
Definition: app_queue.c:2055
int minannouncefrequency
Definition: app_queue.c:2026
enum empty_conditions leavewhenempty
Definition: app_queue.c:2023
int roundingseconds
Definition: app_queue.c:2031
int numperiodicannounce
Definition: app_queue.c:2029
unsigned int announceposition
Definition: app_queue.c:2014
char monfmt[8]
Definition: app_queue.c:2039
enum empty_conditions joinempty
Definition: app_queue.c:2022
int memberdelay
Definition: app_queue.c:2054
unsigned int autopausebusy
Definition: app_queue.c:2020
int autopausedelay
Definition: app_queue.c:2049
int timeoutpriority
Definition: app_queue.c:2050
unsigned int relativeperiodicannounce
Definition: app_queue.c:2019

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

2262{
2263 struct queue_ent *cur;
2264
2265 if (!q || !new)
2266 return;
2267 if (prev) {
2268 cur = prev->next;
2269 prev->next = new;
2270 } else {
2271 cur = q->head;
2272 q->head = new;
2273 }
2274 new->next = cur;
2275
2276 /* every queue_ent must have a reference to it's parent call_queue, this
2277 * reference does not go away until the end of the queue_ent's life, meaning
2278 * that even when the queue_ent leaves the call_queue this ref must remain. */
2279 if (!new->parent) {
2280 queue_ref(q);
2281 new->parent = q;
2282 }
2283 new->pos = ++(*pos);
2284 new->opos = *pos;
2285}
#define queue_ref(q)
Definition: app_queue.c:2227

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

3261{
3262 char *timestr, *maxstr, *minstr, *raisestr, *contentdup;
3263 struct penalty_rule *rule = NULL, *rule_iter;
3264 struct rule_list *rl_iter;
3265 int penaltychangetime, inserted = 0;
3266
3267 if (!(rule = ast_calloc(1, sizeof(*rule)))) {
3268 return -1;
3269 }
3270
3271 contentdup = ast_strdupa(content);
3272
3273 if (!(maxstr = strchr(contentdup, ','))) {
3274 ast_log(LOG_WARNING, "Improperly formatted penaltychange rule at line %d. Ignoring.\n", linenum);
3275 ast_free(rule);
3276 return -1;
3277 }
3278
3279 *maxstr++ = '\0';
3280 if ((minstr = strchr(maxstr,','))) {
3281 *minstr++ = '\0';
3282 if ((raisestr = strchr(minstr,','))) {
3283 *raisestr++ = '\0';
3284 }
3285 } else {
3286 raisestr = NULL;
3287 }
3288
3289 timestr = contentdup;
3290 if ((penaltychangetime = atoi(timestr)) < 0) {
3291 ast_log(LOG_WARNING, "Improper time parameter specified for penaltychange rule at line %d. Ignoring.\n", linenum);
3292 ast_free(rule);
3293 return -1;
3294 }
3295
3296 rule->time = penaltychangetime;
3297
3298 /* The last check will evaluate true if either no penalty change is indicated for a given rule
3299 * OR if a min penalty change is indicated but no max penalty change is */
3300 if (*maxstr == '+' || *maxstr == '-' || *maxstr == '\0') {
3301 rule->max_relative = 1;
3302 }
3303
3304 rule->max_value = atoi(maxstr);
3305
3306 if (!ast_strlen_zero(minstr)) {
3307 if (*minstr == '+' || *minstr == '-') {
3308 rule->min_relative = 1;
3309 }
3310 rule->min_value = atoi(minstr);
3311 } else { /*there was no minimum specified, so assume this means no change*/
3312 rule->min_relative = 1;
3313 }
3314
3315 if (!ast_strlen_zero(raisestr)) {
3316 rule->raise_respect_min = 0; /* Initialize to 0 */
3317 if (*raisestr == 'r') {
3318 rule->raise_respect_min = 1; /* Set the flag */
3319 raisestr++;
3320 }
3321 if (*raisestr == '+' || *raisestr == '-') {
3322 rule->raise_relative = 1;
3323 }
3324 rule->raise_value = atoi(raisestr);
3325 } else { /*there was no raise specified, so assume this means no change*/
3326 rule->raise_relative = 1;
3327 }
3328
3329 /*We have the rule made, now we need to insert it where it belongs*/
3330 AST_LIST_TRAVERSE(&rule_lists, rl_iter, list){
3331 if (strcasecmp(rl_iter->name, list_name)) {
3332 continue;
3333 }
3334
3335 AST_LIST_TRAVERSE_SAFE_BEGIN(&rl_iter->rules, rule_iter, list) {
3336 if (rule->time < rule_iter->time) {
3338 inserted = 1;
3339 break;
3340 }
3341 }
3343
3344 if (!inserted) {
3345 AST_LIST_INSERT_TAIL(&rl_iter->rules, rule, list);
3346 inserted = 1;
3347 }
3348
3349 break;
3350 }
3351
3352 if (!inserted) {
3353 ast_log(LOG_WARNING, "Unknown rule list name %s; ignoring.\n", list_name);
3354 ast_free(rule);
3355 return -1;
3356 }
3357 return 0;
3358}
#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 2094 of file app_queue.c.

2095{
2096 int x;
2097
2098 for (x = 0; x < ARRAY_LEN(strategies); x++) {
2099 if (strategy == strategies[x].strategy) {
2100 return strategies[x].name;
2101 }
2102 }
2103
2104 return "<unknown>";
2105}
static const struct strategy strategies[]
const char * name
Definition: app_queue.c:1698

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

7651{
7652 struct member *mem;
7653 struct ao2_iterator mem_iter;
7654
7655 if (!q) {
7656 return NULL;
7657 }
7658 mem_iter = ao2_iterator_init(q->members, 0);
7659 while ((mem = ao2_iterator_next(&mem_iter))) {
7660 if (!strcasecmp(interface, mem->interface)) {
7661 ao2_iterator_destroy(&mem_iter);
7662 return mem;
7663 }
7664 ao2_ref(mem, -1);
7665 }
7666 ao2_iterator_destroy(&mem_iter);
7667
7668 return NULL;
7669}

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

4769{
4770 struct call_queue *q;
4771 struct member *mem;
4772 int is_longest_waiting = 1;
4773 struct ao2_iterator queue_iter;
4774 struct queue_ent *ch;
4775
4776 queue_iter = ao2_iterator_init(queues, 0);
4777 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
4778 if (q == caller->parent) { /* don't check myself, could deadlock */
4779 queue_t_unref(q, "Done with iterator");
4780 continue;
4781 }
4782 ao2_lock(q);
4783 /*
4784 * If the other queue has equal weight, see if we should let that handle
4785 * their call first. If weights are not equal, compare_weights will step in.
4786 */
4787 if (q->weight == caller->parent->weight && q->count && q->members) {
4788 if ((mem = ao2_find(q->members, member, OBJ_POINTER))) {
4789 ast_debug(2, "Found matching member %s in queue '%s'\n", mem->interface, q->name);
4790
4791 /* Does this queue have a caller that's been waiting longer? */
4792 ch = q->head;
4793 while (ch) {
4794 /* If ch->pending, the other call (which may be waiting for a longer period of time),
4795 * is already ringing at another agent. Ignore such callers; otherwise, all agents
4796 * will be unused until the first caller is picked up.
4797 */
4798 if (ch->start < caller->start && !ch->pending) {
4799 ast_debug(1, "Queue %s has a call at position %i that's been waiting longer (%li vs %li)\n",
4800 q->name, ch->pos, ch->start, caller->start);
4801 is_longest_waiting = 0;
4802 break;
4803 }
4804 ch = ch->next;
4805 }
4806 }
4807 }
4808 ao2_unlock(q);
4809 queue_t_unref(q, "Done with iterator");
4810 if (!is_longest_waiting) {
4811 break;
4812 }
4813 }
4814 ao2_iterator_destroy(&queue_iter);
4815 return is_longest_waiting;
4816}
int pending
Definition: app_queue.c:1879
time_t start
Definition: app_queue.c:1886

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

2784{
2785 int available = 0;
2786 int wrapuptime;
2787
2788 switch (mem->status) {
2789 case AST_DEVICE_INVALID:
2791 break;
2792 case AST_DEVICE_INUSE:
2793 case AST_DEVICE_BUSY:
2794 case AST_DEVICE_RINGING:
2796 case AST_DEVICE_ONHOLD:
2797 if (!mem->ringinuse) {
2798 break;
2799 }
2800 /* else fall through */
2802 case AST_DEVICE_UNKNOWN:
2803 if (!mem->paused) {
2804 available = 1;
2805 }
2806 break;
2807 }
2808
2809 /* Let wrapuptimes override device state availability */
2810 wrapuptime = get_wrapuptime(q, mem);
2811 if (mem->lastcall && wrapuptime && (time(NULL) - wrapuptime < mem->lastcall)) {
2812 available = 0;
2813 }
2814 return available;
2815}
static int available(struct dahdi_pvt **pvt, int is_specific_channel)
Definition: chan_dahdi.c:13574

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

5938{
5939 struct queue_ent *ch;
5940 int res;
5941 int avl;
5942 int idx = 0;
5943 /* This needs a lock. How many members are available to be served? */
5944 ao2_lock(qe->parent);
5945
5946 avl = num_available_members(qe->parent);
5947
5948 ch = qe->parent->head;
5949
5950 ast_debug(1, "There %s %d available %s.\n", avl != 1 ? "are" : "is", avl, avl != 1 ? "members" : "member");
5951
5952 while ((idx < avl) && (ch) && (ch != qe)) {
5953 if (!ch->pending) {
5954 idx++;
5955 }
5956 ch = ch->next;
5957 }
5958
5959 ao2_unlock(qe->parent);
5960 /* If the queue entry is within avl [the number of available members] calls from the top ...
5961 * Autofill and position check added to support autofill=no (as only calls
5962 * from the front of the queue are valid when autofill is disabled)
5963 */
5964 if (ch && idx < avl && (qe->parent->autofill || qe->pos == 1)) {
5965 ast_debug(1, "It's our turn (%s).\n", ast_channel_name(qe->chan));
5966 res = 1;
5967 } else {
5968 ast_debug(1, "It's not our turn (%s).\n", ast_channel_name(qe->chan));
5969 res = 0;
5970 }
5971
5972 /* Update realtime members if this is the first call and number of avalable members is 0 */
5973 if (avl == 0 && qe->pos == 1) {
5975 }
5976
5977 return res;
5978}

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

4252{
4253 struct call_queue *q;
4254 struct queue_ent *cur, *prev = NULL;
4255 int res = -1;
4256 int pos = 0;
4257 int inserted = 0;
4258
4259 if (!(q = find_load_queue_rt_friendly(queuename))) {
4260 return res;
4261 }
4262 ao2_lock(q);
4263
4264 /* This is our one */
4265 if (q->joinempty) {
4266 int status = 0;
4268 *reason = QUEUE_JOINEMPTY;
4269 ao2_unlock(q);
4270 queue_t_unref(q, "Done with realtime queue");
4271 return res;
4272 }
4273 }
4274 if (*reason == QUEUE_UNKNOWN && q->maxlen && (q->count >= q->maxlen)) {
4275 *reason = QUEUE_FULL;
4276 } else if (*reason == QUEUE_UNKNOWN) {
4277 RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
4278
4279 /* There's space for us, put us at the right position inside
4280 * the queue.
4281 * Take into account the priority of the calling user */
4282 inserted = 0;
4283 prev = NULL;
4284 cur = q->head;
4285 while (cur) {
4286 /* We have higher priority than the current user, enter
4287 * before him, after all the other users with priority
4288 * higher or equal to our priority. */
4289 if ((!inserted) && (qe->prio > cur->prio)) {
4290 insert_entry(q, prev, qe, &pos);
4291 inserted = 1;
4292 }
4293 /* <= is necessary for the position comparison because it may not be possible to enter
4294 * at our desired position since higher-priority callers may have taken the position we want
4295 */
4296 if (!inserted && (qe->prio >= cur->prio) && position && (position <= pos + 1)) {
4297 insert_entry(q, prev, qe, &pos);
4298 inserted = 1;
4299 /*pos is incremented inside insert_entry, so don't need to add 1 here*/
4300 if (position < pos) {
4301 ast_log(LOG_NOTICE, "Asked to be inserted at position %d but forced into position %d due to higher priority callers\n", position, pos);
4302 }
4303 }
4304 cur->pos = ++pos;
4305 prev = cur;
4306 cur = cur->next;
4307 }
4308 /* No luck, join at the end of the queue */
4309 if (!inserted) {
4310 insert_entry(q, prev, qe, &pos);
4311 }
4312 ast_copy_string(qe->moh, q->moh, sizeof(qe->moh));
4313 ast_copy_string(qe->announce, q->announce, sizeof(qe->announce));
4314 ast_copy_string(qe->context, q->context, sizeof(qe->context));
4315 q->count++;
4316 if (q->count == 1) {
4318 }
4319
4320 res = 0;
4321
4322 blob = ast_json_pack("{s: s, s: i, s: i}",
4323 "Queue", q->name,
4324 "Position", qe->pos,
4325 "Count", q->count);
4326 ast_channel_publish_cached_blob(qe->chan, queue_caller_join_type(), blob);
4327 ast_debug(1, "Queue '%s' Join, Channel '%s', Position '%d'\n", q->name, ast_channel_name(qe->chan), qe->pos );
4328 }
4329 ao2_unlock(q);
4330 queue_t_unref(q, "Done with realtime queue");
4331
4332 return res;
4333}
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:2001
const ast_string_field context
Definition: app_queue.c:2001
const ast_string_field announce
Definition: app_queue.c:2001
int raise_respect_min
Definition: app_queue.c:1883
char announce[PATH_MAX]
Definition: app_queue.c:1865
char moh[MAX_MUSICCLASS]
Definition: app_queue.c:1864
char context[AST_MAX_CONTEXT]
Definition: app_queue.c:1866

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

9996{
9997 struct member *member = obj;
9998
9999 if (!member->delme) {
10001 return 0;
10002 } else {
10003 return CMP_MATCH;
10004 }
10005}
@ CMP_MATCH
Definition: astobj2.h:1027
unsigned int delme
Definition: app_queue.c:1920

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

10151{
10152 struct call_queue *q = obj;
10153 char *queuename = arg;
10154 if (!q->realtime && !q->found && (ast_strlen_zero(queuename) || !strcasecmp(queuename, q->name))) {
10155 q->dead = 1;
10156 return CMP_MATCH;
10157 } else {
10158 return 0;
10159 }
10160}

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

4565{
4566 struct call_queue *q;
4567 struct queue_ent *current, *prev = NULL;
4568 struct penalty_rule *pr_iter;
4569 int pos = 0;
4570
4571 if (!(q = qe->parent)) {
4572 return;
4573 }
4574 queue_t_ref(q, "Copy queue pointer from queue entry");
4575 ao2_lock(q);
4576
4577 prev = NULL;
4578 for (current = q->head; current; current = current->next) {
4579 if (current == qe) {
4580 RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
4581 char posstr[20];
4582 q->count--;
4583 if (!q->count) {
4585 }
4586
4587 blob = ast_json_pack("{s: s, s: i, s: i}",
4588 "Queue", q->name,
4589 "Position", qe->pos,
4590 "Count", q->count);
4591 ast_channel_publish_cached_blob(qe->chan, queue_caller_leave_type(), blob);
4592 ast_debug(1, "Queue '%s' Leave, Channel '%s'\n", q->name, ast_channel_name(qe->chan));
4593 /* Take us out of the queue */
4594 if (prev) {
4595 prev->next = current->next;
4596 } else {
4597 q->head = current->next;
4598 }
4599 /* Free penalty rules */
4600 while ((pr_iter = AST_LIST_REMOVE_HEAD(&qe->qe_rules, list))) {
4601 ast_free(pr_iter);
4602 }
4603 qe->pr = NULL;
4604 snprintf(posstr, sizeof(posstr), "%d", qe->pos);
4605 pbx_builtin_setvar_helper(qe->chan, "QUEUEPOSITION", posstr);
4606 } else {
4607 /* Renumber the people after us in the queue based on a new count */
4608 current->pos = ++pos;
4609 prev = current;
4610 }
4611 }
4612 ao2_unlock(q);
4613
4614 /*If the queue is a realtime queue, check to see if it's still defined in real time*/
4615 if (q->realtime) {
4616 struct ast_variable *var;
4617 if (!(var = ast_load_realtime("queues", "name", q->name, SENTINEL))) {
4618 q->dead = 1;
4619 } else {
4621 }
4622 }
4623
4624 if (q->dead) {
4625 /* It's dead and nobody is in it, so kill it */
4626 queues_t_unlink(queues, q, "Queue is now dead; remove it from the container");
4627 }
4628 /* unref the explicit ref earlier in the function */
4629 queue_t_unref(q, "Expire copied reference");
4630}
#define queue_t_ref(q, tag)
Definition: app_queue.c:2229
#define var
Definition: ast_expr2f.c:605
struct penalty_rule * pr
Definition: app_queue.c:1893

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

12026{
12027 int err = 0;
12028 struct ast_flags mask = {AST_FLAGS_ALL, };
12029 struct ast_config *member_config;
12030 struct stasis_topic *queue_topic;
12032
12035 if (!queues) {
12037 }
12038
12041 if (!pending_members) {
12042 unload_module();
12044 }
12045
12046 use_weight = 0;
12047
12048 if (reload_handler(0, &mask, NULL)) {
12049 unload_module();
12051 }
12052
12053 ast_realtime_require_field("queue_members", "paused", RQ_INTEGER1, 1, "uniqueid", RQ_UINTEGER2, 5, "reason_paused", RQ_CHAR, 80, SENTINEL);
12054
12055 /*
12056 * This section is used to determine which name for 'ringinuse' to use in realtime members
12057 * Necessary for supporting older setups.
12058 *
12059 * It also checks if 'reason_paused' exists in the realtime backend
12060 */
12061 member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name LIKE", "%", SENTINEL);
12062 if (!member_config) {
12063 realtime_ringinuse_field = "ringinuse";
12064 } else {
12065 const char *config_val;
12066
12067 if ((config_val = ast_variable_retrieve(member_config, NULL, "ringinuse"))) {
12068 ast_log(LOG_NOTICE, "ringinuse field entries found in queue_members table. Using 'ringinuse'\n");
12069 realtime_ringinuse_field = "ringinuse";
12070 } else if ((config_val = ast_variable_retrieve(member_config, NULL, "ignorebusy"))) {
12071 ast_log(LOG_NOTICE, "ignorebusy field found in queue_members table with no ringinuse field. Using 'ignorebusy'\n");
12072 realtime_ringinuse_field = "ignorebusy";
12073 } else {
12074 ast_log(LOG_NOTICE, "No entries were found for ringinuse/ignorebusy in queue_members table. Using 'ringinuse'\n");
12075 realtime_ringinuse_field = "ringinuse";
12076 }
12077
12078 if (ast_variable_retrieve(member_config, NULL, "reason_paused")) {
12080 }
12081 }
12082 ast_config_destroy(member_config);
12083
12086 }
12087
12096 err |= ast_manager_register_xml("QueueStatus", 0, manager_queues_status);
12097 err |= ast_manager_register_xml("QueueSummary", 0, manager_queues_summary);
12104 err |= ast_manager_register_xml("QueueRule", 0, manager_queue_rule_show);
12105 err |= ast_manager_register_xml("QueueReload", 0, manager_queue_reload);
12106 err |= ast_manager_register_xml("QueueReset", 0, manager_queue_reset);
12107 err |= ast_manager_register_xml("QueueChangePriorityCaller", 0, manager_change_priority_caller_on_queue);
12117
12118 /* in the following subscribe call, do I use DEVICE_STATE, or DEVICE_STATE_CHANGE? */
12120 if (!device_state_sub) {
12121 err = -1;
12122 }
12125
12127 queue_topic = ast_queue_topic_all();
12128 if (!manager_topic || !queue_topic) {
12129 unload_module();
12131 }
12133 if (!topic_forwarder) {
12134 unload_module();
12136 }
12137
12140 unload_module();
12142 }
12144 if (!agent_router) {
12145 unload_module();
12147 }
12151 NULL);
12155 NULL);
12156
12157 err |= STASIS_MESSAGE_TYPE_INIT(queue_caller_join_type);
12158 err |= STASIS_MESSAGE_TYPE_INIT(queue_caller_leave_type);
12159 err |= STASIS_MESSAGE_TYPE_INIT(queue_caller_abandon_type);
12160
12161 err |= STASIS_MESSAGE_TYPE_INIT(queue_member_status_type);
12162 err |= STASIS_MESSAGE_TYPE_INIT(queue_member_added_type);
12163 err |= STASIS_MESSAGE_TYPE_INIT(queue_member_removed_type);
12164 err |= STASIS_MESSAGE_TYPE_INIT(queue_member_pause_type);
12165 err |= STASIS_MESSAGE_TYPE_INIT(queue_member_penalty_type);
12166 err |= STASIS_MESSAGE_TYPE_INIT(queue_member_ringinuse_type);
12167
12168 err |= STASIS_MESSAGE_TYPE_INIT(queue_agent_called_type);
12169 err |= STASIS_MESSAGE_TYPE_INIT(queue_agent_connect_type);
12170 err |= STASIS_MESSAGE_TYPE_INIT(queue_agent_complete_type);
12171 err |= STASIS_MESSAGE_TYPE_INIT(queue_agent_dump_type);
12172 err |= STASIS_MESSAGE_TYPE_INIT(queue_agent_ringnoanswer_type);
12173
12174 if (err) {
12175 unload_module();
12177 }
12179}
static struct ast_custom_function queuevar_function
Definition: app_queue.c:9686
static int manager_queue_reset(struct mansession *s, const struct message *m)
Definition: app_queue.c:11059
static int pending_members_cmp(void *obj, void *arg, int flags)
Definition: app_queue.c:2713
static struct ast_custom_function queuemembercount_function
Definition: app_queue.c:9691
static struct ast_custom_function queuewaitingcount_function
Definition: app_queue.c:9707
static char * app_pqm
Definition: app_queue.c:1745
static struct ast_custom_function queuememberlist_function
Definition: app_queue.c:9712
static char * realtime_ringinuse_field
name of the ringinuse field in the realtime database
Definition: app_queue.c:1790
static int manager_add_queue_member(struct mansession *s, const struct message *m)
Definition: app_queue.c:10869
static int aqm_exec(struct ast_channel *chan, const char *data)
AddQueueMember application.
Definition: app_queue.c:8546
#define MAX_QUEUE_BUCKETS
Definition: app_queue.c:1730
static int upqm_exec(struct ast_channel *chan, const char *data)
UnpauseQueueMember application.
Definition: app_queue.c:8439
static void queue_agent_cb(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Definition: app_queue.c:6352
static char * app_ql
Definition: app_queue.c:1749
static void reload_queue_members(void)
Reload dynamic queue members persisted into the astdb.
Definition: app_queue.c:8292
static int rqm_exec(struct ast_channel *chan, const char *data)
RemoveQueueMember application.
Definition: app_queue.c:8475
#define MAX_CALL_ATTEMPT_BUCKETS
Definition: app_queue.c:2691
static char * app_rqm
Definition: app_queue.c:1743
static int manager_queue_rule_show(struct mansession *s, const struct message *m)
Definition: app_queue.c:10628
static int manager_queue_reload(struct mansession *s, const struct message *m)
Definition: app_queue.c:11027
static int pqm_exec(struct ast_channel *chan, const char *data)
PauseQueueMember application.
Definition: app_queue.c:8403
static int qupd_exec(struct ast_channel *chan, const char *data)
Update Queue with data of an outgoing call.
Definition: app_queue.c:11857
static int manager_queue_member_ringinuse(struct mansession *s, const struct message *m)
Definition: app_queue.c:11105
static char * app_qupd
Definition: app_queue.c:1751
static int manager_queue_member_penalty(struct mansession *s, const struct message *m)
Definition: app_queue.c:11139
static char * app_upqm
Definition: app_queue.c:1747
static struct ast_custom_function queuememberpenalty_function
Definition: app_queue.c:9717
static int queue_cmp_cb(void *obj, void *arg, int flags)
Definition: app_queue.c:2150
static int manager_request_withdraw_caller_from_queue(struct mansession *s, const struct message *m)
Definition: app_queue.c:11212
static char * app
Definition: app_queue.c:1739
static int queue_hash_cb(const void *obj, const int flags)
Definition: app_queue.c:2143
static int queue_exec(struct ast_channel *chan, const char *data)
The starting point for all queue calls.
Definition: app_queue.c:8717
static int pending_members_hash(const void *obj, const int flags)
Definition: app_queue.c:2693
static int manager_pause_queue_member(struct mansession *s, const struct message *m)
Definition: app_queue.c:10981
static int ql_exec(struct ast_channel *chan, const char *data)
QueueLog application.
Definition: app_queue.c:8640
static int manager_remove_queue_member(struct mansession *s, const struct message *m)
Definition: app_queue.c:10934
static struct stasis_message_router * agent_router
Definition: app_queue.c:11947
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:2818
static struct stasis_subscription * device_state_sub
Subscription to device state change messages.
Definition: app_queue.c:1775
static int manager_queues_summary(struct mansession *s, const struct message *m)
Summary of queue info via the AMI.
Definition: app_queue.c:10664
static int unload_module(void)
Definition: app_queue.c:11950
static int manager_queues_status(struct mansession *s, const struct message *m)
Queue status info via AMI.
Definition: app_queue.c:10746
static int realtime_reason_paused
does realtime backend support reason_paused
Definition: app_queue.c:1793
static struct ast_custom_function queuemembercount_dep
Definition: app_queue.c:9697
static char * app_aqm
Definition: app_queue.c:1741
static struct ast_cli_entry cli_queue[]
Definition: app_queue.c:11934
static struct ast_custom_function queuegetchannel_function
Definition: app_queue.c:9702
static struct stasis_forward * topic_forwarder
Definition: app_queue.c:11948
static struct ast_custom_function queueexists_function
Definition: app_queue.c:9681
static int manager_change_priority_caller_on_queue(struct mansession *s, const struct message *m)
Definition: app_queue.c:11165
static int manager_queue_log_custom(struct mansession *s, const struct message *m)
Definition: app_queue.c:11006
#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:454
static struct stasis_topic * manager_topic
A stasis_topic that all topics AMI cares about will be forwarded to.
Definition: manager.c:186
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:3769
#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:1559
@ 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_dep, queuemembercount_function, queuememberlist_function, queuememberpenalty_function, queues, queuevar_function, queuewaitingcount_function, qupd_exec(), realtime_reason_paused, realtime_ringinuse_field, reload_handler(), reload_queue_members(), RQ_CHAR, RQ_INTEGER1, RQ_UINTEGER2, rqm_exec(), SENTINEL, stasis_forward_all(), stasis_message_router_add(), stasis_message_router_create, STASIS_MESSAGE_TYPE_INIT, stasis_subscribe, stasis_subscription_accept_message_type(), STASIS_SUBSCRIPTION_FILTER_SELECTIVE, stasis_subscription_set_filter(), topic_forwarder, unload_module(), upqm_exec(), and use_weight.

◆ load_realtime_queues()

static void load_realtime_queues ( const char *  queuename)
static

Definition at line 4148 of file app_queue.c.

4149{
4150 struct ast_config *cfg = NULL;
4151 char *category = NULL;
4152 const char *name = NULL;
4153 struct call_queue *q = NULL;
4154
4155 if (!ast_check_realtime("queues")) {
4156 return;
4157 }
4158
4159 if (ast_strlen_zero(queuename)) {
4160 if ((cfg = ast_load_realtime_multientry("queues", "name LIKE", "%", SENTINEL))) {
4161 while ((category = ast_category_browse(cfg, category))) {
4162 name = ast_variable_retrieve(cfg, category, "name");
4164 queue_unref(q);
4165 }
4166 }
4167 ast_config_destroy(cfg);
4168 }
4169 } else {
4170 if ((q = find_load_queue_rt_friendly(queuename))) {
4171 queue_unref(q);
4172 }
4173 }
4174}

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

3370{
3371 struct ast_config *cfg;
3372 struct rule_list *rl_iter, *new_rl;
3373 struct penalty_rule *pr_iter;
3374 char *rulecat = NULL;
3375
3376 if (!ast_check_realtime("queue_rules")) {
3377 ast_log(LOG_WARNING, "Missing \"queue_rules\" in extconfig.conf\n");
3378 return 0;
3379 }
3380 if (!(cfg = ast_load_realtime_multientry("queue_rules", "rule_name LIKE", "%", SENTINEL))) {
3381 ast_log(LOG_WARNING, "Failed to load queue rules from realtime\n");
3382 return 0;
3383 }
3384 while ((rulecat = ast_category_browse(cfg, rulecat))) {
3385 const char *timestr, *maxstr, *minstr, *raisestr, *rule_name;
3386 int penaltychangetime, rule_exists = 0, inserted = 0;
3387 int max_penalty = 0, min_penalty = 0, raise_penalty = 0;
3388 int min_relative = 0, max_relative = 0, raise_relative = 0;
3389 struct penalty_rule *new_penalty_rule = NULL;
3390
3391 rule_name = ast_variable_retrieve(cfg, rulecat, "rule_name");
3392 if (ast_strlen_zero(rule_name)) {
3393 continue;
3394 }
3395
3396 AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) {
3397 if (!(strcasecmp(rl_iter->name, rule_name))) {
3398 rule_exists = 1;
3399 new_rl = rl_iter;
3400 break;
3401 }
3402 }
3403 if (!rule_exists) {
3404 if (!(new_rl = ast_calloc(1, sizeof(*new_rl)))) {
3405 ast_config_destroy(cfg);
3406 return -1;
3407 }
3408 ast_copy_string(new_rl->name, rule_name, sizeof(new_rl->name));
3410 }
3411 timestr = ast_variable_retrieve(cfg, rulecat, "time");
3412 if (!(timestr) || sscanf(timestr, "%30d", &penaltychangetime) != 1) {
3413 ast_log(LOG_NOTICE, "Failed to parse time (%s) for one of the %s rules, skipping it\n",
3414 (ast_strlen_zero(timestr) ? "invalid value" : timestr), rule_name);
3415 continue;
3416 }
3417 if (!(new_penalty_rule = ast_calloc(1, sizeof(*new_penalty_rule)))) {
3418 ast_config_destroy(cfg);
3419 return -1;
3420 }
3421 if (!(maxstr = ast_variable_retrieve(cfg, rulecat, "max_penalty")) ||
3422 ast_strlen_zero(maxstr) || sscanf(maxstr, "%30d", &max_penalty) != 1) {
3423 max_penalty = 0;
3424 max_relative = 1;
3425 } else {
3426 if (*maxstr == '+' || *maxstr == '-') {
3427 max_relative = 1;
3428 }
3429 }
3430 if (!(minstr = ast_variable_retrieve(cfg, rulecat, "min_penalty")) ||
3431 ast_strlen_zero(minstr) || sscanf(minstr, "%30d", &min_penalty) != 1) {
3432 min_penalty = 0;
3433 min_relative = 1;
3434 } else {
3435 if (*minstr == '+' || *minstr == '-') {
3436 min_relative = 1;
3437 }
3438 }
3439 if (!(raisestr = ast_variable_retrieve(cfg, rulecat, "raise_penalty")) ||
3440 ast_strlen_zero(raisestr) ) {
3441 raise_penalty = 0;
3442 raise_relative = 1;
3443 } else {
3444 if (*raisestr == 'r') {
3445 new_penalty_rule->raise_respect_min = 1;
3446 raisestr++;
3447 } else {
3448 new_penalty_rule->raise_respect_min = 0;
3449 }
3450 if (*raisestr == '+' || *raisestr == '-') {
3451 raise_relative = 1;
3452 }
3453 if (sscanf(raisestr, "%30d", &raise_penalty) != 1) {
3454 raise_penalty = 0;
3455 raise_relative = 1;
3456 }
3457 }
3458 new_penalty_rule->time = penaltychangetime;
3459 new_penalty_rule->max_relative = max_relative;
3460 new_penalty_rule->max_value = max_penalty;
3461 new_penalty_rule->min_relative = min_relative;
3462 new_penalty_rule->min_value = min_penalty;
3463 new_penalty_rule->raise_relative = raise_relative;
3464 new_penalty_rule->raise_value = raise_penalty;
3465 AST_LIST_TRAVERSE_SAFE_BEGIN(&new_rl->rules, pr_iter, list) {
3466 if (new_penalty_rule->time < pr_iter->time) {
3467 AST_LIST_INSERT_BEFORE_CURRENT(new_penalty_rule, list);
3468 inserted = 1;
3469 }
3470 }
3472 if (!inserted) {
3473 AST_LIST_INSERT_TAIL(&new_rl->rules, new_penalty_rule, list);
3474 }
3475 }
3476
3477 ast_config_destroy(cfg);
3478 return 0;
3479}
int raise_respect_min
Definition: app_queue.c:1954

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

6524{
6525 RAII_VAR(struct ast_str *, transfer_str, ast_str_create(32), ast_free);
6526
6527 if (!transfer_str) {
6528 ast_log(LOG_WARNING, "Unable to log attended transfer to queue log\n");
6529 return;
6530 }
6531
6532 switch (atxfer_msg->dest_type) {
6534 ast_str_set(&transfer_str, 0, "BRIDGE|%s", atxfer_msg->dest.bridge);
6535 break;
6538 ast_str_set(&transfer_str, 0, "APP|%s", atxfer_msg->dest.app);
6539 break;
6541 ast_str_set(&transfer_str, 0, "LINK|%s|%s", atxfer_msg->dest.links[0]->base->name,
6542 atxfer_msg->dest.links[1]->base->name);
6543 break;
6546 /* Threeways are headed off and should not be logged here */
6547 ast_assert(0);
6548 return;
6549 }
6550
6551 ast_queue_log(queue_data->queue->name, queue_data->caller_uniqueid, queue_data->member->membername, "ATTENDEDTRANSFER", "%s|%ld|%ld|%d",
6552 ast_str_buffer(transfer_str),
6553 (long) (queue_data->starttime - queue_data->holdstart),
6554 (long) (time(NULL) - queue_data->starttime), queue_data->caller_pos);
6555}
@ AST_ATTENDED_TRANSFER_DEST_FAIL
@ AST_ATTENDED_TRANSFER_DEST_BRIDGE_MERGE
@ AST_ATTENDED_TRANSFER_DEST_LOCAL_APP
@ AST_ATTENDED_TRANSFER_DEST_LINK
@ AST_ATTENDED_TRANSFER_DEST_APP
union ast_attended_transfer_message::@286 dest
struct ast_channel_snapshot * links[2]
char bridge[AST_UUID_STR_LEN]

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

Referenced by handle_attended_transfer().

◆ manager_add_queue_member()

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

Definition at line 10869 of file app_queue.c.

10870{
10871 const char *queuename, *interface, *penalty_s, *paused_s, *reason, *membername, *state_interface, *wrapuptime_s;
10872 int paused, penalty, wrapuptime = 0;
10873
10874 queuename = astman_get_header(m, "Queue");
10875 interface = astman_get_header(m, "Interface");
10876 penalty_s = astman_get_header(m, "Penalty");
10877 paused_s = astman_get_header(m, "Paused");
10878 reason = astman_get_header(m, "Reason"); /* Optional */
10879 membername = astman_get_header(m, "MemberName");
10880 state_interface = astman_get_header(m, "StateInterface");
10881 wrapuptime_s = astman_get_header(m, "Wrapuptime");
10882
10883 if (ast_strlen_zero(queuename)) {
10884 astman_send_error(s, m, "'Queue' not specified.");
10885 return 0;
10886 }
10887
10888 if (ast_strlen_zero(interface)) {
10889 astman_send_error(s, m, "'Interface' not specified.");
10890 return 0;
10891 }
10892
10893 if (ast_strlen_zero(penalty_s)) {
10894 penalty = 0;
10895 } else if (sscanf(penalty_s, "%30d", &penalty) != 1 || penalty < 0) {
10896 penalty = 0;
10897 }
10898
10899 if (ast_strlen_zero(wrapuptime_s)) {
10900 wrapuptime = 0;
10901 } else if (sscanf(wrapuptime_s, "%30d", &wrapuptime) != 1 || wrapuptime < 0) {
10902 wrapuptime = 0;
10903 }
10904
10905 if (ast_strlen_zero(paused_s)) {
10906 paused = 0;
10907 } else {
10908 paused = abs(ast_true(paused_s));
10909 }
10910
10911 switch (add_to_queue(queuename, interface, membername, penalty, paused, queue_persistent_members, state_interface, reason, wrapuptime)) {
10912 case RES_OKAY:
10913 if (ast_strlen_zero(membername) || !log_membername_as_agent) {
10914 ast_queue_log(queuename, "MANAGER", interface, "ADDMEMBER", "%s", paused ? "PAUSED" : "");
10915 } else {
10916 ast_queue_log(queuename, "MANAGER", membername, "ADDMEMBER", "%s", paused ? "PAUSED" : "");
10917 }
10918 astman_send_ack(s, m, "Added interface to queue");
10919 break;
10920 case RES_EXISTS:
10921 astman_send_error(s, m, "Unable to add interface: Already there");
10922 break;
10923 case RES_NOSUCHQUEUE:
10924 astman_send_error(s, m, "Unable to add interface to queue: No such queue");
10925 break;
10926 case RES_OUTOFMEMORY:
10927 astman_send_error(s, m, "Out of memory");
10928 break;
10929 }
10930
10931 return 0;
10932}
#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:1986
void astman_send_ack(struct mansession *s, const struct message *m, char *msg)
Send ack in manager transaction.
Definition: manager.c:2018
const char * astman_get_header(const struct message *m, char *var)
Get header from manager transaction.
Definition: manager.c:1647

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

11166{
11167 const char *queuename, *caller, *priority_s, *immediate_s;
11168 int priority = 0, immediate = 0;
11169
11170 queuename = astman_get_header(m, "Queue");
11171 caller = astman_get_header(m, "Caller");
11172 priority_s = astman_get_header(m, "Priority");
11173 immediate_s = astman_get_header(m, "Immediate");
11174
11175 if (ast_strlen_zero(queuename)) {
11176 astman_send_error(s, m, "'Queue' not specified.");
11177 return 0;
11178 }
11179
11180 if (ast_strlen_zero(caller)) {
11181 astman_send_error(s, m, "'Caller' not specified.");
11182 return 0;
11183 }
11184
11185 if (ast_strlen_zero(priority_s)) {
11186 astman_send_error(s, m, "'Priority' not specified.");
11187 return 0;
11188 } else if (sscanf(priority_s, "%30d", &priority) != 1) {
11189 astman_send_error(s, m, "'Priority' need integer.");
11190 return 0;
11191 }
11192
11193 if (!ast_strlen_zero(immediate_s)) {
11194 immediate = ast_true(immediate_s);
11195 }
11196
11197 switch (change_priority_caller_on_queue(queuename, caller, priority, immediate)) {
11198 case RES_OKAY:
11199 astman_send_ack(s, m, "Priority change for caller on queue");
11200 break;
11201 case RES_NOSUCHQUEUE:
11202 astman_send_error(s, m, "Unable to change priority caller on queue: No such queue");
11203 break;
11204 case RES_NOT_CALLER:
11205 astman_send_error(s, m, "Unable to change priority caller on queue: No such caller");
11206 break;
11207 }
11208
11209 return 0;
11210}

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

10982{
10983 const char *queuename, *interface, *paused_s, *reason;
10984 int paused;
10985
10986 interface = astman_get_header(m, "Interface");
10987 paused_s = astman_get_header(m, "Paused");
10988 queuename = astman_get_header(m, "Queue"); /* Optional - if not supplied, pause the given Interface in all queues */
10989 reason = astman_get_header(m, "Reason"); /* Optional */
10990
10991 if (ast_strlen_zero(interface) || ast_strlen_zero(paused_s)) {
10992 astman_send_error(s, m, "Need 'Interface' and 'Paused' parameters.");
10993 return 0;
10994 }
10995
10996 paused = abs(ast_true(paused_s));
10997
10998 if (set_member_paused(queuename, interface, reason, paused)) {
10999 astman_send_error(s, m, "Interface not found");
11000 } else {
11001 astman_send_ack(s, m, paused ? "Interface paused successfully" : "Interface unpaused successfully");
11002 }
11003 return 0;
11004}

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

11007{
11008 const char *queuename, *event, *message, *interface, *uniqueid;
11009
11010 queuename = astman_get_header(m, "Queue");
11011 uniqueid = astman_get_header(m, "UniqueId");
11012 interface = astman_get_header(m, "Interface");
11013 event = astman_get_header(m, "Event");
11014 message = astman_get_header(m, "Message");
11015
11016 if (ast_strlen_zero(queuename) || ast_strlen_zero(event)) {
11017 astman_send_error(s, m, "Need 'Queue' and 'Event' parameters.");
11018 return 0;
11019 }
11020
11021 ast_queue_log(queuename, S_OR(uniqueid, "NONE"), interface, event, "%s", message);
11022 astman_send_ack(s, m, "Event added successfully");
11023
11024 return 0;
11025}
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 11139 of file app_queue.c.

11140{
11141 const char *queuename, *interface, *penalty_s;
11142 int penalty;
11143
11144 interface = astman_get_header(m, "Interface");
11145 penalty_s = astman_get_header(m, "Penalty");
11146 /* Optional - if not supplied, set the penalty value for the given Interface in all queues */
11147 queuename = astman_get_header(m, "Queue");
11148
11149 if (ast_strlen_zero(interface) || ast_strlen_zero(penalty_s)) {
11150 astman_send_error(s, m, "Need 'Interface' and 'Penalty' parameters.");
11151 return 0;
11152 }
11153
11154 penalty = atoi(penalty_s);
11155
11156 if (set_member_value((char *)queuename, (char *)interface, MEMBER_PENALTY, penalty)) {
11157 astman_send_error(s, m, "Invalid interface, queuename or penalty");
11158 } else {
11159 astman_send_ack(s, m, "Interface penalty set successfully");
11160 }
11161
11162 return 0;
11163}

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

11106{
11107 const char *queuename, *interface, *ringinuse_s;
11108 int ringinuse;
11109
11110 interface = astman_get_header(m, "Interface");
11111 ringinuse_s = astman_get_header(m, "RingInUse");
11112
11113 /* Optional - if not supplied, set the ringinuse value for the given Interface in all queues */
11114 queuename = astman_get_header(m, "Queue");
11115
11116 if (ast_strlen_zero(interface) || ast_strlen_zero(ringinuse_s)) {
11117 astman_send_error(s, m, "Need 'Interface' and 'RingInUse' parameters.");
11118 return 0;
11119 }
11120
11121 if (ast_true(ringinuse_s)) {
11122 ringinuse = 1;
11123 } else if (ast_false(ringinuse_s)) {
11124 ringinuse = 0;
11125 } else {
11126 astman_send_error(s, m, "'RingInUse' parameter must be a truth value (yes/no, on/off, 0/1, etc)");
11127 return 0;
11128 }
11129
11130 if (set_member_value(queuename, interface, MEMBER_RINGINUSE, ringinuse)) {
11131 astman_send_error(s, m, "Invalid interface, queuename, or ringinuse value\n");
11132 } else {
11133 astman_send_ack(s, m, "Interface ringinuse set successfully");
11134 }
11135
11136 return 0;
11137}

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

11028{
11029 struct ast_flags mask = {0,};
11030 const char *queuename = NULL;
11031 int header_found = 0;
11032
11033 queuename = astman_get_header(m, "Queue");
11034 if (!strcasecmp(S_OR(astman_get_header(m, "Members"), ""), "yes")) {
11036 header_found = 1;
11037 }
11038 if (!strcasecmp(S_OR(astman_get_header(m, "Rules"), ""), "yes")) {
11040 header_found = 1;
11041 }
11042 if (!strcasecmp(S_OR(astman_get_header(m, "Parameters"), ""), "yes")) {
11044 header_found = 1;
11045 }
11046
11047 if (!header_found) {
11049 }
11050
11051 if (!reload_handler(1, &mask, queuename)) {
11052 astman_send_ack(s, m, "Queue reloaded successfully");
11053 } else {
11054 astman_send_error(s, m, "Error encountered while reloading queue");
11055 }
11056 return 0;
11057}

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

11060{
11061 const char *queuename = NULL;
11062 struct ast_flags mask = {QUEUE_RESET_STATS,};
11063
11064 queuename = astman_get_header(m, "Queue");
11065
11066 if (!reload_handler(1, &mask, queuename)) {
11067 astman_send_ack(s, m, "Queue stats reset successfully");
11068 } else {
11069 astman_send_error(s, m, "Error encountered while resetting queue stats");
11070 }
11071 return 0;
11072}

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

10629{
10630 const char *rule = astman_get_header(m, "Rule");
10631 const char *id = astman_get_header(m, "ActionID");
10632 struct rule_list *rl_iter;
10633 struct penalty_rule *pr_iter;
10634
10635 astman_append(s, "Response: Success\r\n");
10636 if (!ast_strlen_zero(id)) {
10637 astman_append(s, "ActionID: %s\r\n", id);
10638 }
10639
10641 AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) {
10642 if (ast_strlen_zero(rule) || !strcasecmp(rule, rl_iter->name)) {
10643 astman_append(s, "RuleList: %s\r\n", rl_iter->name);
10644 AST_LIST_TRAVERSE(&rl_iter->rules, pr_iter, list) {
10645 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 );
10646 }
10647 if (!ast_strlen_zero(rule)) {
10648 break;
10649 }
10650 }
10651 }
10653
10654 /*
10655 * Two blank lines instead of one because the Response and
10656 * ActionID headers used to not be present.
10657 */
10658 astman_append(s, "\r\n\r\n");
10659
10660 return RESULT_SUCCESS;
10661}

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

10747{
10748 time_t now;
10749 int pos;
10750 int q_items = 0;
10751 const char *id = astman_get_header(m,"ActionID");
10752 const char *queuefilter = astman_get_header(m,"Queue");
10753 const char *memberfilter = astman_get_header(m,"Member");
10754 char idText[256];
10755 struct call_queue *q;
10756 struct queue_ent *qe;
10757 float sl = 0;
10758 float sl2 = 0;
10759 struct member *mem;
10760 struct ao2_iterator queue_iter;
10761 struct ao2_iterator mem_iter;
10762
10763 if (ast_check_realtime("queues")) {
10764 load_realtime_queues(queuefilter);
10765 }
10766
10767 astman_send_listack(s, m, "Queue status will follow", "start");
10768 time(&now);
10769 idText[0] = '\0';
10770 if (!ast_strlen_zero(id)) {
10771 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
10772 }
10773
10774 queue_iter = ao2_iterator_init(queues, 0);
10775 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
10776 ao2_lock(q);
10777
10778 /* List queue properties */
10779 if (ast_strlen_zero(queuefilter) || !strcasecmp(q->name, queuefilter)) {
10780 sl = ((q->callscompleted > 0) ? 100 * ((float)q->callscompletedinsl / (float)q->callscompleted) : 0);
10781 sl2 = (((q->callscompleted + q->callsabandoned) > 0) ? 100 * (((float)q->callsabandonedinsl + (float)q->callscompletedinsl) / ((float)q->callsabandoned + (float)q->callscompleted)) : 0);
10782
10783 astman_append(s, "Event: QueueParams\r\n"
10784 "Queue: %s\r\n"
10785 "Max: %d\r\n"
10786 "Strategy: %s\r\n"
10787 "Calls: %d\r\n"
10788 "Holdtime: %d\r\n"
10789 "TalkTime: %d\r\n"
10790 "Completed: %d\r\n"
10791 "Abandoned: %d\r\n"
10792 "ServiceLevel: %d\r\n"
10793 "ServicelevelPerf: %2.1f\r\n"
10794 "ServicelevelPerf2: %2.1f\r\n"
10795 "Weight: %d\r\n"
10796 "%s"
10797 "\r\n",
10798 q->name, q->maxlen, int2strat(q->strategy), q->count, q->holdtime, q->talktime, q->callscompleted,
10799 q->callsabandoned, q->servicelevel, sl, sl2, q->weight, idText);
10800 ++q_items;
10801
10802 /* List Queue Members */
10803 mem_iter = ao2_iterator_init(q->members, 0);
10804 while ((mem = ao2_iterator_next(&mem_iter))) {
10805 if (ast_strlen_zero(memberfilter) || !strcmp(mem->interface, memberfilter) || !strcmp(mem->membername, memberfilter)) {
10806 astman_append(s, "Event: QueueMember\r\n"
10807 "Queue: %s\r\n"
10808 "Name: %s\r\n"
10809 "Location: %s\r\n"
10810 "StateInterface: %s\r\n"
10811 "Membership: %s\r\n"
10812 "Penalty: %d\r\n"
10813 "CallsTaken: %d\r\n"
10814 "LastCall: %d\r\n"
10815 "LastPause: %d\r\n"
10816 "LoginTime: %d\r\n"
10817 "InCall: %d\r\n"
10818 "Status: %d\r\n"
10819 "Paused: %d\r\n"
10820 "PausedReason: %s\r\n"
10821 "Wrapuptime: %d\r\n"
10822 "%s"
10823 "\r\n",
10824 q->name, mem->membername, mem->interface, mem->state_interface, mem->dynamic ? "dynamic" : "static",
10825 mem->penalty, mem->calls, (int)mem->lastcall, (int)mem->lastpause, (int)mem->logintime, mem->starttime ? 1 : 0, mem->status,
10826 mem->paused, mem->reason_paused, mem->wrapuptime, idText);
10827 ++q_items;
10828 }
10829 ao2_ref(mem, -1);
10830 }
10831 ao2_iterator_destroy(&mem_iter);
10832
10833 /* List Queue Entries */
10834 pos = 1;
10835 for (qe = q->head; qe; qe = qe->next) {
10836 astman_append(s, "Event: QueueEntry\r\n"
10837 "Queue: %s\r\n"
10838 "Position: %d\r\n"
10839 "Channel: %s\r\n"
10840 "Uniqueid: %s\r\n"
10841 "CallerIDNum: %s\r\n"
10842 "CallerIDName: %s\r\n"
10843 "ConnectedLineNum: %s\r\n"
10844 "ConnectedLineName: %s\r\n"
10845 "Wait: %ld\r\n"
10846 "Priority: %d\r\n"
10847 "%s"
10848 "\r\n",
10849 q->name, pos++, ast_channel_name(qe->chan), ast_channel_uniqueid(qe->chan),
10854 (long) (now - qe->start), qe->prio, idText);
10855 ++q_items;
10856 }
10857 }
10858 ao2_unlock(q);
10859 queue_t_unref(q, "Done with iterator");
10860 }
10861 ao2_iterator_destroy(&queue_iter);
10862
10863 astman_send_list_complete_start(s, m, "QueueStatusComplete", q_items);
10865
10866 return RESULT_SUCCESS;
10867}
static void load_realtime_queues(const char *queuename)
Definition: app_queue.c:4148
static const char * int2strat(int strategy)
Definition: app_queue.c:2094
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:2028
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:2064
void astman_send_list_complete_end(struct mansession *s)
End the list complete event.
Definition: manager.c:2072
#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 10664 of file app_queue.c.

10665{
10666 time_t now;
10667 int qmemcount = 0;
10668 int qmemavail = 0;
10669 int qchancount = 0;
10670 int qlongestholdtime = 0;
10671 int qsummaries = 0;
10672 const char *id = astman_get_header(m, "ActionID");
10673 const char *queuefilter = astman_get_header(m, "Queue");
10674 char idText[256];
10675 struct call_queue *q;
10676 struct queue_ent *qe;
10677 struct member *mem;
10678 struct ao2_iterator queue_iter;
10679 struct ao2_iterator mem_iter;
10680
10681 if (ast_check_realtime("queues")) {
10682 load_realtime_queues(queuefilter);
10683 }
10684
10685 astman_send_listack(s, m, "Queue summary will follow", "start");
10686 time(&now);
10687 idText[0] = '\0';
10688 if (!ast_strlen_zero(id)) {
10689 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
10690 }
10691 queue_iter = ao2_iterator_init(queues, 0);
10692 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
10693 ao2_lock(q);
10694
10695 /* List queue properties */
10696 if (ast_strlen_zero(queuefilter) || !strcasecmp(q->name, queuefilter)) {
10697 /* Reset the necessary local variables if no queuefilter is set*/
10698 qmemcount = 0;
10699 qmemavail = 0;
10700 qchancount = 0;
10701 qlongestholdtime = 0;
10702
10703 /* List Queue Members */
10704 mem_iter = ao2_iterator_init(q->members, 0);
10705 while ((mem = ao2_iterator_next(&mem_iter))) {
10706 if ((mem->status != AST_DEVICE_UNAVAILABLE) && (mem->status != AST_DEVICE_INVALID)) {
10707 ++qmemcount;
10708 if (member_status_available(mem->status) && !mem->paused) {
10709 ++qmemavail;
10710 }
10711 }
10712 ao2_ref(mem, -1);
10713 }
10714 ao2_iterator_destroy(&mem_iter);
10715 for (qe = q->head; qe; qe = qe->next) {
10716 if ((now - qe->start) > qlongestholdtime) {
10717 qlongestholdtime = now - qe->start;
10718 }
10719 ++qchancount;
10720 }
10721 astman_append(s, "Event: QueueSummary\r\n"
10722 "Queue: %s\r\n"
10723 "LoggedIn: %d\r\n"
10724 "Available: %d\r\n"
10725 "Callers: %d\r\n"
10726 "HoldTime: %d\r\n"
10727 "TalkTime: %d\r\n"
10728 "LongestHoldTime: %d\r\n"
10729 "%s"
10730 "\r\n",
10731 q->name, qmemcount, qmemavail, qchancount, q->holdtime, q->talktime, qlongestholdtime, idText);
10732 ++qsummaries;
10733 }
10734 ao2_unlock(q);
10735 queue_t_unref(q, "Done with iterator");
10736 }
10737 ao2_iterator_destroy(&queue_iter);
10738
10739 astman_send_list_complete_start(s, m, "QueueSummaryComplete", qsummaries);
10741
10742 return RESULT_SUCCESS;
10743}

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

10935{
10936 const char *queuename, *interface;
10937 struct member *mem = NULL;
10938
10939 queuename = astman_get_header(m, "Queue");
10940 interface = astman_get_header(m, "Interface");
10941
10942 if (ast_strlen_zero(queuename) || ast_strlen_zero(interface)) {
10943 astman_send_error(s, m, "Need 'Queue' and 'Interface' parameters.");
10944 return 0;
10945 }
10946
10948 mem = find_member_by_queuename_and_interface(queuename, interface);
10949 }
10950
10951 switch (remove_from_queue(queuename, interface)) {
10952 case RES_OKAY:
10953 if (!mem || ast_strlen_zero(mem->membername)) {
10954 ast_queue_log(queuename, "MANAGER", interface, "REMOVEMEMBER", "%s", "");
10955 } else {
10956 ast_queue_log(queuename, "MANAGER", mem->membername, "REMOVEMEMBER", "%s", "");
10957 }
10958 astman_send_ack(s, m, "Removed interface from queue");
10959 break;
10960 case RES_EXISTS:
10961 astman_send_error(s, m, "Unable to remove interface: Not there");
10962 break;
10963 case RES_NOSUCHQUEUE:
10964 astman_send_error(s, m, "Unable to remove interface from queue: No such queue");
10965 break;
10966 case RES_OUTOFMEMORY:
10967 astman_send_error(s, m, "Out of memory");
10968 break;
10969 case RES_NOT_DYNAMIC:
10970 astman_send_error(s, m, "Member not dynamic");
10971 break;
10972 }
10973
10974 if (mem) {
10975 ao2_ref(mem, -1);
10976 }
10977
10978 return 0;
10979}

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

11213{
11214 const char *queuename, *caller, *withdraw_info;
11215
11216 queuename = astman_get_header(m, "Queue");
11217 caller = astman_get_header(m, "Caller");
11218 withdraw_info = astman_get_header(m, "WithdrawInfo");
11219
11220 if (ast_strlen_zero(queuename)) {
11221 astman_send_error(s, m, "'Queue' not specified.");
11222 return 0;
11223 }
11224
11225 if (ast_strlen_zero(caller)) {
11226 astman_send_error(s, m, "'Caller' not specified.");
11227 return 0;
11228 }
11229
11230 switch (request_withdraw_caller_from_queue(queuename, caller, withdraw_info)) {
11231 case RES_OKAY:
11232 astman_send_ack(s, m, "Withdraw requested successfully");
11233 break;
11234 case RES_NOSUCHQUEUE:
11235 astman_send_error(s, m, "Unable to request withdraw from queue: No such queue");
11236 break;
11237 case RES_NOT_CALLER:
11238 astman_send_error(s, m, "Unable to request withdraw from queue: No such caller");
11239 break;
11240 case RES_EXISTS:
11241 astman_send_error(s, m, "Unable to request withdraw from queue: Already requested");
11242 break;
11243 }
11244
11245 return 0;
11246}
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:7914

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

9987{
9988 struct member *member = obj;
9989 if (!member->dynamic && !member->realtime) {
9990 member->delme = 1;
9991 }
9992 return 0;
9993}

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

10141{
10142 struct call_queue *q = obj;
10143 char *queuename = arg;
10144 if (!q->realtime && (ast_strlen_zero(queuename) || !strcasecmp(queuename, q->name))) {
10145 q->found = 0;
10146 }
10147 return 0;
10148}

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

3114{
3115 struct member *mem1 = obj1;
3116 struct member *mem2 = obj2;
3117 const char *interface = (flags & OBJ_KEY) ? obj2 : mem2->interface;
3118
3119 return strcasecmp(mem1->interface, interface) ? 0 : CMP_MATCH | CMP_STOP;
3120}
@ 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 3097 of file app_queue.c.

3098{
3099 const struct member *mem = obj;
3100 const char *interface = (flags & OBJ_KEY) ? obj : mem->interface;
3101 const char *chname = strchr(interface, '/');
3102 int ret = 0, i;
3103
3104 if (!chname) {
3105 chname = interface;
3106 }
3107 for (i = 0; i < 5 && chname[i]; i++) {
3108 ret += compress_char(chname[i]) << (i * 6);
3109 }
3110 return ret;
3111}
static int compress_char(const char c)
Definition: app_queue.c:3087

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

3755{
3757 ao2_lock(queue->members);
3760 ao2_unlink(queue->members, mem);
3761 ao2_unlock(queue->members);
3762}
static void queue_member_follower_removal(struct call_queue *queue, struct member *mem)
Definition: app_queue.c:2214
#define QUEUE_UNKNOWN_PAUSED_DEVSTATE
Definition: app_queue.c:3730
#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 4835 of file app_queue.c.

4836{
4838}

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

4702{
4703 struct member *mem;
4704 int avl = 0;
4705 struct ao2_iterator mem_iter;
4706
4707 mem_iter = ao2_iterator_init(q->members, 0);
4708 while ((mem = ao2_iterator_next(&mem_iter))) {
4709
4710 avl += is_member_available(q, mem);
4711 ao2_ref(mem, -1);
4712
4713 /* If autofill is not enabled or if the queue's strategy is ringall, then
4714 * we really don't care about the number of available members so much as we
4715 * do that there is at least one available.
4716 *
4717 * In fact, we purposely will return from this function stating that only
4718 * one member is available if either of those conditions hold. That way,
4719 * functions which determine what action to take based on the number of available
4720 * members will operate properly. The reasoning is that even if multiple
4721 * members are available, only the head caller can actually be serviced.
4722 */
4723 if ((!q->autofill || q->strategy == QUEUE_STRATEGY_RINGALL) && avl) {
4724 break;
4725 }
4726 }
4727 ao2_iterator_destroy(&mem_iter);
4728
4729 return avl;
4730}

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

3482{
3483 char *value_copy = ast_strdupa(value);
3484 char *option = NULL;
3485 while ((option = strsep(&value_copy, ","))) {
3486 if (!strcasecmp(option, "paused")) {
3487 *empty |= QUEUE_EMPTY_PAUSED;
3488 } else if (!strcasecmp(option, "penalty")) {
3489 *empty |= QUEUE_EMPTY_PENALTY;
3490 } else if (!strcasecmp(option, "inuse")) {
3491 *empty |= QUEUE_EMPTY_INUSE;
3492 } else if (!strcasecmp(option, "ringing")) {
3493 *empty |= QUEUE_EMPTY_RINGING;
3494 } else if (!strcasecmp(option, "invalid")) {
3495 *empty |= QUEUE_EMPTY_INVALID;
3496 } else if (!strcasecmp(option, "wrapup")) {
3497 *empty |= QUEUE_EMPTY_WRAPUP;
3498 } else if (!strcasecmp(option, "unavailable")) {
3499 *empty |= QUEUE_EMPTY_UNAVAILABLE;
3500 } else if (!strcasecmp(option, "unknown")) {
3501 *empty |= QUEUE_EMPTY_UNKNOWN;
3502 } else if (!strcasecmp(option, "loose")) {
3504 } else if (!strcasecmp(option, "strict")) {
3506 } else if ((ast_false(option) && joinempty) || (ast_true(option) && !joinempty)) {
3508 } else if ((ast_false(option) && !joinempty) || (ast_true(option) && joinempty)) {
3509 *empty = 0;
3510 } else {
3511 ast_log(LOG_WARNING, "Unknown option %s for '%s'\n", option, joinempty ? "joinempty" : "leavewhenempty");
3512 }
3513 }
3514}

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

2714{
2715 const struct member *object_left = obj;
2716 const struct member *object_right = arg;
2717 const char *right_key = arg;
2718 int cmp;
2719
2720 switch (flags & OBJ_SEARCH_MASK) {
2721 case OBJ_SEARCH_OBJECT:
2722 right_key = object_right->interface;
2723 /* Fall through */
2724 case OBJ_SEARCH_KEY:
2725 cmp = strcasecmp(object_left->interface, right_key);
2726 break;
2728 /* Not supported by container. */
2729 ast_assert(0);
2730 return 0;
2731 default:
2732 cmp = 0;
2733 break;
2734 }
2735 if (cmp) {
2736 return 0;
2737 }
2738 return CMP_MATCH;
2739}
@ 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 2693 of file app_queue.c.

2694{
2695 const struct member *object;
2696 const char *key;
2697
2698 switch (flags & OBJ_SEARCH_MASK) {
2699 case OBJ_SEARCH_KEY:
2700 key = obj;
2701 break;
2702 case OBJ_SEARCH_OBJECT:
2703 object = obj;
2704 key = object->interface;
2705 break;
2706 default:
2707 ast_assert(0);
2708 return 0;
2709 }
2710 return ast_str_case_hash(key);
2711}
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 2741 of file app_queue.c.

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

4336{
4337 int res;
4338
4339 if (ast_strlen_zero(filename)) {
4340 return 0;
4341 }
4342
4343 if (!ast_fileexists(filename, NULL, ast_channel_language(chan))) {
4344 return 0;
4345 }
4346
4347 ast_stopstream(chan);
4348
4349 res = ast_streamfile(chan, filename, ast_channel_language(chan));
4350 if (!res) {
4351 res = ast_waitstream(chan, AST_DIGIT_ANY);
4352 }
4353
4354 ast_stopstream(chan);
4355
4356 return res;
4357}
const char * ast_channel_language(const struct ast_channel *chan)
int ast_stopstream(struct ast_channel *c)
Stops a stream.
Definition: file.c:222
int ast_streamfile(struct ast_channel *c, const char *filename, const char *preflang)
Streams a file.
Definition: file.c:1301
int ast_fileexists(const char *filename, const char *fmt, const char *preflang)
Checks for the existence of a given file.
Definition: file.c:1137
#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:1848

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

8404{
8405 char *parse;
8407 AST_APP_ARG(queuename);
8408 AST_APP_ARG(interface);
8410 AST_APP_ARG(reason);
8411 );
8412
8413 if (ast_strlen_zero(data)) {
8414 ast_log(LOG_WARNING, "PauseQueueMember requires an argument ([queuename],interface[,options][,reason])\n");
8415 return -1;
8416 }
8417
8418 parse = ast_strdupa(data);
8419
8421
8422 if (ast_strlen_zero(args.interface)) {
8423 ast_log(LOG_WARNING, "Missing interface argument to PauseQueueMember ([queuename],interface[,options[,reason]])\n");
8424 return -1;
8425 }
8426
8427 if (set_member_paused(args.queuename, args.interface, args.reason, 1)) {
8428 ast_log(LOG_WARNING, "Attempt to pause interface %s, not found\n", args.interface);
8429 pbx_builtin_setvar_helper(chan, "PQMSTATUS", "NOTFOUND");
8430 return 0;
8431 }
8432
8433 pbx_builtin_setvar_helper(chan, "PQMSTATUS", "PAUSED");
8434
8435 return 0;
8436}

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

10289{
10290 float sl;
10291 float sl2;
10292 struct ao2_iterator mem_iter;
10293 struct ast_str *out = ast_str_alloca(512);
10294 time_t now = time(NULL);
10295
10296 ast_str_set(&out, 0, "%s has %d calls (max ", q->name, q->count);
10297 if (q->maxlen) {
10298 ast_str_append(&out, 0, "%d", q->maxlen);
10299 } else {
10300 ast_str_append(&out, 0, "unlimited");
10301 }
10302 sl = 0;
10303 sl2 = 0;
10304 if (q->callscompleted > 0) {
10305 sl = 100 * ((float) q->callscompletedinsl / (float) q->callscompleted);
10306 }
10307 if (q->callscompleted + q->callsabandoned > 0) {
10308 sl2 =100 * (((float)q->callsabandonedinsl + (float)q->callscompletedinsl) / ((float)q->callsabandoned + (float)q->callscompleted));
10309 }
10310
10311 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",
10313 do_print(s, fd, ast_str_buffer(out));
10314 if (!ao2_container_count(q->members)) {
10315 do_print(s, fd, " No Members");
10316 } else {
10317 struct member *mem;
10318
10319 do_print(s, fd, " Members: ");
10320 mem_iter = ao2_iterator_init(q->members, 0);
10321 while ((mem = ao2_iterator_next(&mem_iter))) {
10322 ast_str_set(&out, 0, " %s", mem->membername);
10323 if (strcasecmp(mem->membername, mem->interface)) {
10324 ast_str_append(&out, 0, " (%s", mem->interface);
10326 && strcmp(mem->state_interface, mem->interface)) {
10327 ast_str_append(&out, 0, " from %s", mem->state_interface);
10328 }
10329 ast_str_append(&out, 0, ")");
10330 }
10331 if (mem->penalty) {
10332 ast_str_append(&out, 0, " with penalty %d", mem->penalty);
10333 }
10334
10335 ast_str_append(&out, 0, " (ringinuse %s)", mem->ringinuse ? "enabled" : "disabled");
10336
10337 ast_str_append(&out, 0, "%s%s%s%s%s%s%s%s%s",
10338 mem->dynamic ? ast_term_color(COLOR_CYAN, COLOR_BLACK) : "", mem->dynamic ? " (dynamic)" : "", ast_term_reset(),
10339 mem->realtime ? ast_term_color(COLOR_MAGENTA, COLOR_BLACK) : "", mem->realtime ? " (realtime)" : "", ast_term_reset(),
10340 mem->starttime ? ast_term_color(COLOR_BROWN, COLOR_BLACK) : "", mem->starttime ? " (in call)" : "", ast_term_reset());
10341
10342 if (mem->paused) {
10343 ast_str_append(&out, 0, " %s(paused%s%s was %ld secs ago)%s",
10345 ast_strlen_zero(mem->reason_paused) ? "" : ":",
10347 (long) (now - mem->lastpause),
10348 ast_term_reset());
10349 }
10350
10351 ast_str_append(&out, 0, " (%s%s%s)",
10356 if (mem->calls) {
10357 ast_str_append(&out, 0, " has taken %d calls (last was %ld secs ago)",
10358 mem->calls, (long) (now - mem->lastcall));
10359 } else {
10360 ast_str_append(&out, 0, " has taken no calls yet");
10361 }
10362 ast_str_append(&out, 0, " %s(login was %ld secs ago)%s",
10364 (long) (now - mem->logintime),
10365 ast_term_reset());
10366 do_print(s, fd, ast_str_buffer(out));
10367 ao2_ref(mem, -1);
10368 }
10369 ao2_iterator_destroy(&mem_iter);
10370 }
10371 if (!q->head) {
10372 do_print(s, fd, " No Callers");
10373 } else {
10374 struct queue_ent *qe;
10375 int pos = 1;
10376
10377 do_print(s, fd, " Callers: ");
10378 for (qe = q->head; qe; qe = qe->next) {
10379 ast_str_set(&out, 0, " %d. %s (wait: %ld:%2.2ld, prio: %d)",
10380 pos++, ast_channel_name(qe->chan), (long) (now - qe->start) / 60,
10381 (long) (now - qe->start) % 60, qe->prio);
10382 do_print(s, fd, ast_str_buffer(out));
10383 }
10384 }
10385 do_print(s, fd, ""); /* blank line between entries */
10386}
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 4649 of file app_queue.c.

4650{
4651 struct callattempt *cur;
4652
4653 for (cur = outgoing; cur; cur = cur->q_next) {
4654 if (cur->chan && cur->chan != exception) {
4656 }
4657 }
4658}
struct callattempt * q_next
Definition: app_queue.c:1840
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 7953 of file app_queue.c.

7954{
7955 struct ast_json *json_blob = queue_member_blob_create(q, member);
7956
7957 if (!json_blob) {
7958 return -1;
7959 }
7960
7961 queue_publish_member_blob(queue_member_pause_type(), json_blob);
7962
7963 return 0;
7964}

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

8641{
8642 char *parse;
8643
8645 AST_APP_ARG(queuename);
8646 AST_APP_ARG(uniqueid);
8647 AST_APP_ARG(membername);
8649 AST_APP_ARG(params);
8650 );
8651
8652 if (ast_strlen_zero(data)) {
8653 ast_log(LOG_WARNING, "QueueLog requires arguments (queuename,uniqueid,membername,event[,additionalinfo]\n");
8654 return -1;
8655 }
8656
8657 parse = ast_strdupa(data);
8658
8660
8661 if (ast_strlen_zero(args.queuename) || ast_strlen_zero(args.uniqueid)
8662 || ast_strlen_zero(args.membername) || ast_strlen_zero(args.event)) {
8663 ast_log(LOG_WARNING, "QueueLog requires arguments (queuename,uniqueid,membername,event[,additionalinfo])\n");
8664 return -1;
8665 }
8666
8667 ast_queue_log(args.queuename, args.uniqueid, args.membername, args.event,
8668 "%s", args.params ? args.params : "");
8669
8670 return 0;
8671}

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

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

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

6354{
6355 struct ast_channel_blob *agent_blob;
6356
6357 agent_blob = stasis_message_data(msg);
6358
6360 ast_queue_log("NONE", agent_blob->snapshot->base->uniqueid,
6361 ast_json_string_get(ast_json_object_get(agent_blob->blob, "agent")),
6362 "AGENTLOGIN", "%s", agent_blob->snapshot->base->name);
6364 ast_queue_log("NONE", agent_blob->snapshot->base->uniqueid,
6365 ast_json_string_get(ast_json_object_get(agent_blob->blob, "agent")),
6366 "AGENTLOGOFF", "%s|%ld", agent_blob->snapshot->base->name,
6367 (long) ast_json_integer_get(ast_json_object_get(agent_blob->blob, "logintime")));
6368 }
6369}

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

2447{
2448 return queue_multi_channel_to_ami("AgentComplete", message);
2449}

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

2442{
2443 return queue_multi_channel_to_ami("AgentConnect", message);
2444}

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

2452{
2453 return queue_multi_channel_to_ami("AgentDump", message);
2454}

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

2457{
2458 return queue_multi_channel_to_ami("AgentRingNoAnswer", message);
2459}

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

6717{
6719 ao2_cleanup(userdata);
6720 }
6721}
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 2316 of file app_queue.c.

2317{
2318 return queue_channel_to_ami("QueueCallerAbandon", message);
2319}
static struct ast_manager_event_blob * queue_channel_to_ami(const char *type, struct stasis_message *message)
Definition: app_queue.c:2287

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

2307{
2308 return queue_channel_to_ami("QueueCallerJoin", message);
2309}

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

2312{
2313 return queue_channel_to_ami("QueueCallerLeave", message);
2314}

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

6942{
6944 ao2_cleanup(userdata);
6945 }
6946}

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

2288{
2290 RAII_VAR(struct ast_str *, channel_string, NULL, ast_free);
2291 RAII_VAR(struct ast_str *, event_string, NULL, ast_free);
2292
2293 channel_string = ast_manager_build_channel_state_string(obj->snapshot);
2294 event_string = ast_manager_str_from_json_object(obj->blob, NULL);
2295 if (!channel_string || !event_string) {
2296 return NULL;
2297 }
2298
2300 "%s"
2301 "%s",
2302 ast_str_buffer(channel_string),
2303 ast_str_buffer(event_string));
2304}
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:555
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:10239

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

2151{
2152 struct call_queue *q = obj, *q2 = arg;
2153 return !strcasecmp(q->name, q2->name) ? CMP_MATCH | CMP_STOP : 0;
2154}

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

2197{
2198 struct member *mem = obj;
2199 struct call_queue *queue = arg;
2200 int rrpos = mem->queuepos;
2201
2202 if (mem->delme) {
2204 }
2205
2206 return 0;
2207}
static int queue_member_decrement_followers(void *obj, void *arg, int flag)
Definition: app_queue.c:2177
#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 8717 of file app_queue.c.

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

References call_queue::announce_to_first_user, call_queue::announcefrequency, ao2_container_count(), args, AST_APP_ARG, ast_app_exec_sub(), ast_app_parse_options(), ast_assert, ast_channel_caller(), ast_channel_lock, ast_channel_name(), ast_channel_uniqueid(), ast_channel_unlock, AST_CONTROL_RINGING, ast_copy_string(), ast_debug, AST_DECLARE_APP_ARGS, ast_free, ast_indicate(), AST_LIST_FIRST, ast_log, ast_max_forwards_get(), ast_moh_start(), ast_moh_stop(), ast_party_id_presentation(), AST_PRES_ALLOWED, AST_PRES_RESTRICTION, ast_queue_log(), ast_replace_subargument_delimiter(), AST_STANDARD_APP_ARGS, ast_stopstream(), ast_strdupa, ast_strlen_zero(), ast_test_flag, ast_verb, queue_ent::chan, copy_rules(), queue_ent::digits, queue_ent::expire, get_member_status(), queue_ent::handled, 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 9201 of file app_queue.c.

9202{
9203 struct call_queue *q;
9204
9205 buf[0] = '\0';
9206
9207 if (ast_strlen_zero(data)) {
9208 ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd);
9209 return -1;
9210 }
9212 snprintf(buf, len, "%d", q != NULL? 1 : 0);
9213 if (q) {
9214 queue_t_unref(q, "Done with temporary reference in QUEUE_EXISTS()");
9215 }
9216
9217 return 0;
9218}
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 9243 of file app_queue.c.

9244{
9245 int count = 0;
9246 struct member *m;
9247 struct ao2_iterator mem_iter;
9248 struct call_queue *q;
9249
9251 AST_APP_ARG(queuename);
9252 AST_APP_ARG(option);
9253 AST_APP_ARG(interface);
9254 );
9255 /* Make sure the returned value on error is zero length string. */
9256 buf[0] = '\0';
9257
9258 if (ast_strlen_zero(data)) {
9260 "Missing required argument. %s(<queuename>,<option>[,<interface>])\n",
9261 cmd);
9262 return -1;
9263 }
9264
9266
9267 if (ast_strlen_zero(args.queuename) || ast_strlen_zero(args.option)) {
9269 "Missing required argument. %s(<queuename>,<option>[,<interface>])\n",
9270 cmd);
9271 return -1;
9272 }
9273
9274 if ((q = find_load_queue_rt_friendly(args.queuename))) {
9275 ao2_lock(q);
9276 if (!strcasecmp(args.option, "logged")) {
9277 mem_iter = ao2_iterator_init(q->members, 0);
9278 while ((m = ao2_iterator_next(&mem_iter))) {
9279 /* Count the agents who are logged in and presently answering calls */
9280 if ((m->status != AST_DEVICE_UNAVAILABLE) && (m->status != AST_DEVICE_INVALID)) {
9281 count++;
9282 }
9283 ao2_ref(m, -1);
9284 }
9285 ao2_iterator_destroy(&mem_iter);
9286 } else if (!strcasecmp(args.option, "free")) {
9287 mem_iter = ao2_iterator_init(q->members, 0);
9288 while ((m = ao2_iterator_next(&mem_iter))) {
9289 /* Count the agents who are logged in and presently answering calls */
9290 if ((m->status == AST_DEVICE_NOT_INUSE) && (!m->paused)) {
9291 count++;
9292 }
9293 ao2_ref(m, -1);
9294 }
9295 ao2_iterator_destroy(&mem_iter);
9296 } else if (!strcasecmp(args.option, "ready")) {
9297 time_t now;
9298 time(&now);
9299 mem_iter = ao2_iterator_init(q->members, 0);
9300 while ((m = ao2_iterator_next(&mem_iter))) {
9301 /* Count the agents who are logged in, not paused and not wrapping up */
9302 if ((m->status == AST_DEVICE_NOT_INUSE) && (!m->paused) &&
9303 !(m->lastcall && get_wrapuptime(q, m) && ((now - get_wrapuptime(q, m)) < m->lastcall))) {
9304 count++;
9305 }
9306 ao2_ref(m, -1);
9307 }
9308 ao2_iterator_destroy(&mem_iter);
9309 } else if (!strcasecmp(args.option, "count")) {
9311 } else if (!strcasecmp(args.option, "penalty")) {
9312 m = get_interface_helper(q, args.interface);
9313 if (m) {
9314 count = m->penalty;
9315 ao2_ref(m, -1);
9316 }
9317 } else if (!strcasecmp(args.option, "paused")) {
9318 m = get_interface_helper(q, args.interface);
9319 if (m) {
9320 count = m->paused;
9321 ao2_ref(m, -1);
9322 }
9323 } else if ((!strcasecmp(args.option, "ignorebusy") /* ignorebusy is legacy */
9324 || !strcasecmp(args.option, "ringinuse"))) {
9325 m = get_interface_helper(q, args.interface);
9326 if (m) {
9327 count = m->ringinuse;
9328 ao2_ref(m, -1);
9329 }
9330 } else {
9331 ast_log(LOG_ERROR, "%s: Invalid option '%s' provided.\n", cmd, args.option);
9332 }
9333 ao2_unlock(q);
9334 queue_t_unref(q, "Done with temporary reference in QUEUE_MEMBER()");
9335 } else {
9336 ast_log(LOG_WARNING, "queue %s was not found\n", args.queuename);
9337 }
9338
9339 snprintf(buf, len, "%d", count);
9340
9341 return 0;
9342}
static struct member * get_interface_helper(struct call_queue *q, const char *interface)
Definition: app_queue.c:9220

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

9346{
9347 int memvalue;
9348
9350 AST_APP_ARG(queuename);
9351 AST_APP_ARG(option);
9352 AST_APP_ARG(interface);
9353 );
9354
9355 if (ast_strlen_zero(data)) {
9357 "Missing required argument. %s([<queuename>],<option>,<interface>)\n",
9358 cmd);
9359 return -1;
9360 }
9361
9363
9364 if (ast_strlen_zero(args.option)
9365 || ast_strlen_zero(args.interface)) {
9367 "Missing required argument. %s([<queuename>],<option>,<interface>)\n",
9368 cmd);
9369 return -1;
9370 }
9371
9372 /*
9373 * If queuename is empty then the option will be
9374 * set for the interface in all queues.
9375 */
9376
9377 memvalue = atoi(value);
9378 if (!strcasecmp(args.option, "penalty")) {
9379 if (set_member_value(args.queuename, args.interface, MEMBER_PENALTY, memvalue)) {
9380 ast_log(LOG_ERROR, "Invalid interface, queue, or penalty\n");
9381 return -1;
9382 }
9383 } else if (!strcasecmp(args.option, "paused")) {
9384 memvalue = (memvalue <= 0) ? 0 : 1;
9385 if (set_member_paused(args.queuename, args.interface, NULL, memvalue)) {
9386 ast_log(LOG_ERROR, "Invalid interface or queue\n");
9387 return -1;
9388 }
9389 } else if (!strcasecmp(args.option, "ignorebusy") /* ignorebusy is legacy */
9390 || !strcasecmp(args.option, "ringinuse")) {
9391 memvalue = (memvalue <= 0) ? 0 : 1;
9392 if (set_member_value(args.queuename, args.interface, MEMBER_RINGINUSE, memvalue)) {
9393 ast_log(LOG_ERROR, "Invalid interface or queue\n");
9394 return -1;
9395 }
9396 } else {
9397 ast_log(LOG_ERROR, "%s: Invalid option '%s' provided.\n", cmd, args.option);
9398 return -1;
9399 }
9400 return 0;
9401}

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

9614{
9615 int penalty;
9617 AST_APP_ARG(queuename);
9618 AST_APP_ARG(interface);
9619 );
9620 /* Make sure the returned value on error is NULL. */
9621 buf[0] = '\0';
9622
9623 if (ast_strlen_zero(data)) {
9624 ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n");
9625 return -1;
9626 }
9627
9629
9630 if (args.argc < 2) {
9631 ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n");
9632 return -1;
9633 }
9634
9635 penalty = get_member_penalty (args.queuename, args.interface);
9636
9637 if (penalty >= 0) { /* remember that buf is already '\0' */
9638 snprintf (buf, len, "%d", penalty);
9639 }
9640
9641 return 0;
9642}
static int get_member_penalty(char *queuename, char *interface)
Gets members penalty.
Definition: app_queue.c:8261

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

9646{
9647 int penalty;
9649 AST_APP_ARG(queuename);
9650 AST_APP_ARG(interface);
9651 );
9652
9653 if (ast_strlen_zero(data)) {
9654 ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n");
9655 return -1;
9656 }
9657
9659
9660 if (args.argc < 2) {
9661 ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n");
9662 return -1;
9663 }
9664
9665 penalty = atoi(value);
9666
9667 if (ast_strlen_zero(args.interface)) {
9668 ast_log (LOG_ERROR, "<interface> parameter can't be null\n");
9669 return -1;
9670 }
9671
9672 /* if queuename = NULL then penalty will be set for interface in all the queues. */
9673 if (set_member_value(args.queuename, args.interface, MEMBER_PENALTY, penalty)) {
9674 ast_log(LOG_ERROR, "Invalid interface, queue or penalty\n");
9675 return -1;
9676 }
9677
9678 return 0;
9679}

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

◆ queue_function_qac_dep()

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

Get the total number of members in a specific queue (Deprecated)

Return values
numberof members
-1on error

Definition at line 9408 of file app_queue.c.

9409{
9410 int count = 0;
9411 struct member *m;
9412 struct call_queue *q;
9413 struct ao2_iterator mem_iter;
9414 static int depflag = 1;
9415
9416 if (depflag) {
9417 depflag = 0;
9418 ast_log(LOG_NOTICE, "The function QUEUE_MEMBER_COUNT has been deprecated in favor of the QUEUE_MEMBER function and will not be in further releases.\n");
9419 }
9420
9421 if (ast_strlen_zero(data)) {
9422 ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd);
9423 return -1;
9424 }
9425
9426 if ((q = find_load_queue_rt_friendly(data))) {
9427 ao2_lock(q);
9428 mem_iter = ao2_iterator_init(q->members, 0);
9429 while ((m = ao2_iterator_next(&mem_iter))) {
9430 /* Count the agents who are logged in and presently answering calls */
9431 if ((m->status != AST_DEVICE_UNAVAILABLE) && (m->status != AST_DEVICE_INVALID)) {
9432 count++;
9433 }
9434 ao2_ref(m, -1);
9435 }
9436 ao2_iterator_destroy(&mem_iter);
9437 ao2_unlock(q);
9438 queue_t_unref(q, "Done with temporary reference in QUEUE_MEMBER_COUNT");
9439 } else {
9440 ast_log(LOG_WARNING, "queue %s was not found\n", data);
9441 }
9442
9443 snprintf(buf, len, "%d", count);
9444
9445 return 0;
9446}

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

◆ queue_function_queuegetchannel()

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

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

Definition at line 9449 of file app_queue.c.

9450{
9451 int position;
9452 char *parse;
9453 struct call_queue *q;
9454 struct ast_variable *var;
9455
9457 AST_APP_ARG(queuename);
9458 AST_APP_ARG(position);
9459 );
9460
9461 buf[0] = '\0';
9462
9463 if (ast_strlen_zero(data)) {
9464 ast_log(LOG_ERROR, "Missing argument. QUEUE_GET_CHANNEL(<queuename>,<position>)\n");
9465 return -1;
9466 }
9467
9468 parse = ast_strdupa(data);
9470
9471 if (ast_strlen_zero(args.queuename)) {
9472 ast_log (LOG_ERROR, "The <queuename> parameter is required.\n");
9473 return -1;
9474 }
9475
9476 if (ast_strlen_zero(args.position)) {
9477 position = 1;
9478 } else {
9479 if (sscanf(args.position, "%30d", &position) != 1) {
9480 ast_log (LOG_ERROR, "<position> parameter must be an integer.\n");
9481 return -1;
9482 }
9483 if (position < 1) {
9484 ast_log (LOG_ERROR, "<position> parameter must be an integer greater than zero.\n");
9485 return -1;
9486 }
9487 }
9488
9489 {
9490 struct call_queue tmpq = {
9491 .name = args.queuename,
9492 };
9493
9494 q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Find for QUEUE_GET_CHANNEL()");
9495 }
9496 if (q) {
9497 ao2_lock(q);
9498 if (q->count >= position) {
9499 struct queue_ent *qe;
9500
9501 for (qe = q->head; qe; qe = qe->next) {
9502 if (qe->pos == position) {
9504 break;
9505 }
9506 }
9507 }
9508 ao2_unlock(q);
9509 queue_t_unref(q, "Done with reference in QUEUE_GET_CHANNEL()");
9510 return 0;
9511 }
9512
9513 var = ast_load_realtime("queues", "name", args.queuename, SENTINEL);
9514 if (var) {
9515 /* if the queue is realtime but was not found in memory, this
9516 * means that the queue had been deleted from memory since it was
9517 * "dead."
9518 */
9520 return 0;
9521 }
9522
9523 ast_log(LOG_WARNING, "queue %s was not found\n", args.queuename);
9524 return 0;
9525}

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

9566{
9567 struct call_queue *q;
9568 struct member *m;
9569
9570 /* Ensure an otherwise empty list doesn't return garbage */
9571 buf[0] = '\0';
9572
9573 if (ast_strlen_zero(data)) {
9574 ast_log(LOG_ERROR, "QUEUE_MEMBER_LIST requires an argument: queuename\n");
9575 return -1;
9576 }
9577
9578 if ((q = find_load_queue_rt_friendly(data))) {
9579 int buflen = 0, count = 0;
9580 struct ao2_iterator mem_iter;
9581
9582 ao2_lock(q);
9583 mem_iter = ao2_iterator_init(q->members, 0);
9584 while ((m = ao2_iterator_next(&mem_iter))) {
9585 /* strcat() is always faster than printf() */
9586 if (count++) {
9587 strncat(buf + buflen, ",", len - buflen - 1);
9588 buflen++;
9589 }
9590 strncat(buf + buflen, m->interface, len - buflen - 1);
9591 buflen += strlen(m->interface);
9592 /* Safeguard against overflow (negative length) */
9593 if (buflen >= len - 2) {
9594 ao2_ref(m, -1);
9595 ast_log(LOG_WARNING, "Truncating list\n");
9596 break;
9597 }
9598 ao2_ref(m, -1);
9599 }
9600 ao2_iterator_destroy(&mem_iter);
9601 ao2_unlock(q);
9602 queue_t_unref(q, "Done with QUEUE_MEMBER_LIST()");
9603 } else
9604 ast_log(LOG_WARNING, "queue %s was not found\n", data);
9605
9606 /* We should already be terminated, but let's make sure. */
9607 buf[len - 1] = '\0';
9608
9609 return 0;
9610}

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

9529{
9530 int count = 0;
9531 struct call_queue *q, tmpq = {
9532 .name = data,
9533 };
9534 struct ast_variable *var = NULL;
9535
9536 buf[0] = '\0';
9537
9538 if (ast_strlen_zero(data)) {
9539 ast_log(LOG_ERROR, "QUEUE_WAITING_COUNT requires an argument: queuename\n");
9540 return -1;
9541 }
9542
9543 if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Find for QUEUE_WAITING_COUNT()"))) {
9544 ao2_lock(q);
9545 count = q->count;
9546 ao2_unlock(q);
9547 queue_t_unref(q, "Done with reference in QUEUE_WAITING_COUNT()");
9548 } else if ((var = ast_load_realtime("queues", "name", data, SENTINEL))) {
9549 /* if the queue is realtime but was not found in memory, this
9550 * means that the queue had been deleted from memory since it was
9551 * "dead." This means it has a 0 waiting count
9552 */
9553 count = 0;
9555 } else {
9556 ast_log(LOG_WARNING, "queue %s was not found\n", data);
9557 }
9558
9559 snprintf(buf, len, "%d", count);
9560
9561 return 0;
9562}

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

9158{
9159 int res = -1;
9160 struct call_queue *q;
9161 char interfacevar[256] = "";
9162 float sl = 0;
9163
9164 if (ast_strlen_zero(data)) {
9165 ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd);
9166 return -1;
9167 }
9168
9169 if ((q = find_load_queue_rt_friendly(data))) {
9170 ao2_lock(q);
9171 if (q->setqueuevar) {
9172 sl = 0;
9173 res = 0;
9174
9175 if (q->callscompleted > 0) {
9176 sl = 100 * ((float) q->callscompletedinsl / (float) q->callscompleted);
9177 }
9178
9179 snprintf(interfacevar, sizeof(interfacevar),
9180 "QUEUEMAX=%d,QUEUESTRATEGY=%s,QUEUECALLS=%d,QUEUEHOLDTIME=%d,QUEUETALKTIME=%d,QUEUECOMPLETED=%d,QUEUEABANDONED=%d,QUEUESRVLEVEL=%d,QUEUESRVLEVELPERF=%2.1f",
9182
9183 pbx_builtin_setvar_multiple(chan, interfacevar);
9184 }
9185
9186 ao2_unlock(q);
9187 queue_t_unref(q, "Done with QUEUE() function");
9188 } else {
9189 ast_log(LOG_WARNING, "queue %s was not found\n", data);
9190 }
9191
9192 snprintf(buf, len, "%d", res);
9193
9194 return 0;
9195}
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 2143 of file app_queue.c.

2144{
2145 const struct call_queue *q = obj;
2146
2147 return ast_str_case_hash(q->name);
2148}

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

2352{
2353 return queue_member_to_ami("QueueMemberAdded", message);
2354}
static struct ast_manager_event_blob * queue_member_to_ami(const char *type, struct stasis_message *message)
Definition: app_queue.c:2331

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

2568{
2569 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}",
2570 "Queue", q->name,
2571 "MemberName", mem->membername,
2572 "Interface", mem->interface,
2573 "StateInterface", mem->state_interface,
2574 "Membership", (mem->dynamic ? "dynamic" : (mem->realtime ? "realtime" : "static")),
2575 "Penalty", mem->penalty,
2576 "CallsTaken", mem->calls,
2577 "LastCall", (int)mem->lastcall,
2578 "LastPause", (int)mem->lastpause,
2579 "LoginTime", (int)mem->logintime,
2580 "InCall", mem->starttime ? 1 : 0,
2581 "Status", mem->status,
2582 "Paused", mem->paused,
2583 "PausedReason", mem->reason_paused,
2584 "Ringinuse", mem->ringinuse,
2585 "Wrapuptime", mem->wrapuptime);
2586}

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

2178{
2179 struct member *mem = obj;
2180 int *decrement_followers_after = arg;
2181
2182 if (mem->queuepos > *decrement_followers_after) {
2183 mem->queuepos--;
2184 }
2185
2186 return 0;
2187}

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

2215{
2216 int pos = mem->queuepos;
2217
2218 /* 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
2219 * who would have been next otherwise. */
2220 if (pos < queue->rrpos) {
2221 queue->rrpos--;
2222 }
2223
2225}

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

2362{
2363 return queue_member_to_ami("QueueMemberPause", message);
2364}

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

2367{
2368 return queue_member_to_ami("QueueMemberPenalty", message);
2369}

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

2357{
2358 return queue_member_to_ami("QueueMemberRemoved", message);
2359}

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

2372{
2373 return queue_member_to_ami("QueueMemberRinginuse", message);
2374}

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

2347{
2348 return queue_member_to_ami("QueueMemberStatus", message);
2349}

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

2396{
2399 struct ast_channel_snapshot *agent;
2400 RAII_VAR(struct ast_str *, caller_event_string, NULL, ast_free);
2401 RAII_VAR(struct ast_str *, agent_event_string, NULL, ast_free);
2402 RAII_VAR(struct ast_str *, event_string, NULL, ast_free);
2403
2405 if (caller) {
2406 caller_event_string = ast_manager_build_channel_state_string(caller);
2407 if (!caller_event_string) {
2408 ast_log(LOG_NOTICE, "No caller event string, bailing\n");
2409 return NULL;
2410 }
2411 }
2412
2413 agent = ast_multi_channel_blob_get_channel(obj, "agent");
2414 if (agent) {
2415 agent_event_string = ast_manager_build_channel_state_string_prefix(agent, "Dest");
2416 if (!agent_event_string) {
2417 ast_log(LOG_NOTICE, "No agent event string, bailing\n");
2418 return NULL;
2419 }
2420 }
2421
2423 if (!event_string) {
2424 return NULL;
2425 }
2426
2428 "%s"
2429 "%s"
2430 "%s",
2431 caller_event_string ? ast_str_buffer(caller_event_string) : "",
2432 agent_event_string ? ast_str_buffer(agent_event_string) : "",
2433 ast_str_buffer(event_string));
2434}
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 2543 of file app_queue.c.

2544{
2545 RAII_VAR(struct ast_json_payload *, payload, NULL, ao2_cleanup);
2546 RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
2547
2548 if (!blob || !type) {
2549 ast_json_unref(blob);
2550 return;
2551 }
2552
2553 payload = ast_json_payload_create(blob);
2554 ast_json_unref(blob);
2555 if (!payload) {
2556 return;
2557 }
2558
2559 msg = stasis_message_create(type, payload);
2560 if (!msg) {
2561 return;
2562 }
2563
2565}
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 2512 of file app_queue.c.

2514{
2515 RAII_VAR(struct ast_channel_snapshot *, caller_snapshot, NULL, ao2_cleanup);
2516 RAII_VAR(struct ast_channel_snapshot *, agent_snapshot, NULL, ao2_cleanup);
2517
2518 ast_channel_lock(caller);
2519 caller_snapshot = ast_channel_snapshot_create(caller);
2520 ast_channel_unlock(caller);
2521 ast_channel_lock(agent);
2522 agent_snapshot = ast_channel_snapshot_create(agent);
2523 ast_channel_unlock(agent);
2524
2525 if (!caller_snapshot || !agent_snapshot) {
2526 return;
2527 }
2528
2530 agent_snapshot, type, blob);
2531}
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:2477
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 2477 of file app_queue.c.

2481{
2482 RAII_VAR(struct ast_multi_channel_blob *, payload, NULL, ao2_cleanup);
2483 RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
2484
2485 if (!type) {
2486 return;
2487 }
2488
2489 payload = ast_multi_channel_blob_create(blob);
2490 if (!payload) {
2491 return;
2492 }
2493
2494 if (caller_snapshot) {
2495 ast_multi_channel_blob_add_channel(payload, "caller", caller_snapshot);
2496 } else {
2497 ast_debug(1, "Empty caller_snapshot; sending incomplete event\n");
2498 }
2499
2500 if (agent_snapshot) {
2501 ast_multi_channel_blob_add_channel(payload, "agent", agent_snapshot);
2502 }
2503
2504 msg = stasis_message_create(type, payload);
2505 if (!msg) {
2506 return;
2507 }
2508
2509 stasis_publish(topic, msg);
2510}
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 9803 of file app_queue.c.

9804{
9806 autofill_default = 0;
9807 montype_default = 0;
9808 shared_lastcall = 0;
9812}
static int montype_default
queues.conf [general] option
Definition: app_queue.c:1766
static int negative_penalty_invalid
queues.conf [general] option
Definition: app_queue.c:1778
static int shared_lastcall
queues.conf [general] option
Definition: app_queue.c:1769

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

9725{
9726 realtime_rules = 0;
9727}
static int realtime_rules
queuerules.conf [general] option
Definition: app_queue.c:1772

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

9731{
9732 const char *general_val = NULL;
9733 if ((general_val = ast_variable_retrieve(cfg, "general", "realtime_rules"))) {
9734 realtime_rules = ast_true(general_val);
9735 }
9736}

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

9816{
9817 const char *general_val = NULL;
9818 if ((general_val = ast_variable_retrieve(cfg, "general", "persistentmembers"))) {
9819 queue_persistent_members = ast_true(general_val);
9820 }
9821 if ((general_val = ast_variable_retrieve(cfg, "general", "autofill"))) {
9822 autofill_default = ast_true(general_val);
9823 }
9824 if ((general_val = ast_variable_retrieve(cfg, "general", "monitor-type"))) {
9825 if (!strcasecmp(general_val, "mixmonitor"))
9826 montype_default = 1;
9827 }
9828 if ((general_val = ast_variable_retrieve(cfg, "general", "shared_lastcall"))) {
9829 shared_lastcall = ast_true(general_val);
9830 }
9831 if ((general_val = ast_variable_retrieve(cfg, "general", "negative_penalty_invalid"))) {
9832 negative_penalty_invalid = ast_true(general_val);
9833 }
9834 if ((general_val = ast_variable_retrieve(cfg, "general", "log_membername_as_agent"))) {
9835 log_membername_as_agent = ast_true(general_val);
9836 }
9837 if ((general_val = ast_variable_retrieve(cfg, "general", "force_longest_waiting_caller"))) {
9839 }
9840 /* Apply log-caller-id-name in the same place as other global settings */
9841 if ((general_val = ast_variable_retrieve(cfg, "general", "log-caller-id-name"))) {
9842 log_caller_id_name = ast_true(general_val);
9843 }
9844}

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

3525{
3526 if (!strcasecmp(param, "musicclass") ||
3527 !strcasecmp(param, "music") || !strcasecmp(param, "musiconhold")) {
3528 ast_string_field_set(q, moh, val);
3529 } else if (!strcasecmp(param, "announce")) {
3530 ast_string_field_set(q, announce, val);
3531 } else if (!strcasecmp(param, "context")) {
3533 } else if (!strcasecmp(param, "timeout")) {
3534 q->timeout = atoi(val);
3535 if (q->timeout < 0) {
3537 }
3538 } else if (!strcasecmp(param, "ringinuse")) {
3539 q->ringinuse = ast_true(val);
3540 } else if (!strcasecmp(param, "setinterfacevar")) {
3542 } else if (!strcasecmp(param, "setqueuevar")) {
3543 q->setqueuevar = ast_true(val);
3544 } else if (!strcasecmp(param, "setqueueentryvar")) {
3546 } else if (!strcasecmp(param, "monitor-format")) {
3547 ast_copy_string(q->monfmt, val, sizeof(q->monfmt));
3548 } else if (!strcasecmp(param, "membergosub")) {
3549 ast_string_field_set(q, membergosub, val);
3550 } else if (!strcasecmp(param, "queue-youarenext")) {
3551 ast_string_field_set(q, sound_next, val);
3552 } else if (!strcasecmp(param, "queue-thereare")) {
3553 ast_string_field_set(q, sound_thereare, val);
3554 } else if (!strcasecmp(param, "queue-callswaiting")) {
3555 ast_string_field_set(q, sound_calls, val);
3556 } else if (!strcasecmp(param, "queue-quantity1")) {
3557 ast_string_field_set(q, queue_quantity1, val);
3558 } else if (!strcasecmp(param, "queue-quantity2")) {
3559 ast_string_field_set(q, queue_quantity2, val);
3560 } else if (!strcasecmp(param, "queue-holdtime")) {
3561 ast_string_field_set(q, sound_holdtime, val);
3562 } else if (!strcasecmp(param, "queue-minutes")) {
3563 ast_string_field_set(q, sound_minutes, val);
3564 } else if (!strcasecmp(param, "queue-minute")) {
3565 ast_string_field_set(q, sound_minute, val);
3566 } else if (!strcasecmp(param, "queue-seconds")) {
3567 ast_string_field_set(q, sound_seconds, val);
3568 } else if (!strcasecmp(param, "queue-thankyou")) {
3569 ast_string_field_set(q, sound_thanks, val);
3570 } else if (!strcasecmp(param, "queue-callerannounce")) {
3571 ast_string_field_set(q, sound_callerannounce, val);
3572 } else if (!strcasecmp(param, "queue-reporthold")) {
3573 ast_string_field_set(q, sound_reporthold, val);
3574 } else if (!strcasecmp(param, "announce-frequency")) {
3575 q->announcefrequency = atoi(val);
3576 } else if (!strcasecmp(param, "announce-to-first-user")) {
3578 } else if (!strcasecmp(param, "min-announce-frequency")) {
3579 q->minannouncefrequency = atoi(val);
3580 ast_debug(1, "%s=%s for queue '%s'\n", param, val, q->name);
3581 } else if (!strcasecmp(param, "announce-round-seconds")) {
3582 q->roundingseconds = atoi(val);
3583 /* Rounding to any other values just doesn't make sense... */
3584 if (!(q->roundingseconds == 0 || q->roundingseconds == 5 || q->roundingseconds == 10
3585 || q->roundingseconds == 15 || q->roundingseconds == 20 || q->roundingseconds == 30)) {
3586 if (linenum >= 0) {
3587 ast_log(LOG_WARNING, "'%s' isn't a valid value for %s "
3588 "using 0 instead for queue '%s' at line %d of queues.conf\n",
3589 val, param, q->name, linenum);
3590 } else {
3591 ast_log(LOG_WARNING, "'%s' isn't a valid value for %s "
3592 "using 0 instead for queue '%s'\n", val, param, q->name);
3593 }
3594 q->roundingseconds=0;
3595 }
3596 } else if (!strcasecmp(param, "announce-holdtime")) {
3597 if (!strcasecmp(val, "once")) {
3599 } else if (ast_true(val)) {
3601 } else {
3602 q->announceholdtime = 0;
3603 }
3604 } else if (!strcasecmp(param, "announce-position")) {
3605 if (!strcasecmp(val, "limit")) {
3607 } else if (!strcasecmp(val, "more")) {
3609 } else if (ast_true(val)) {
3611 } else {
3613 }
3614 } else if (!strcasecmp(param, "announce-position-only-up")) {
3616 } else if (!strcasecmp(param, "announce-position-limit")) {
3617 q->announcepositionlimit = atoi(val);
3618 } else if (!strcasecmp(param, "periodic-announce")) {
3619 if (strchr(val, ',')) {
3620 char *s, *buf = ast_strdupa(val);
3621 unsigned int i = 0;
3622
3623 while ((s = strsep(&buf, ",|"))) {
3624 if (!q->sound_periodicannounce[i]) {
3626 }
3627 ast_str_set(&q->sound_periodicannounce[i], 0, "%s", s);
3628 i++;
3629 if (i == MAX_PERIODIC_ANNOUNCEMENTS) {
3630 break;
3631 }
3632 }
3633 q->numperiodicannounce = i;
3634 } else {
3635 ast_str_set(&q->sound_periodicannounce[0], 0, "%s", val);
3636 q->numperiodicannounce = 1;
3637 }
3638 } else if (!strcasecmp(param, "periodic-announce-startdelay")) {
3640 } else if (!strcasecmp(param, "periodic-announce-frequency")) {
3641 q->periodicannouncefrequency = atoi(val);
3642 } else if (!strcasecmp(param, "relative-periodic-announce")) {
3644 } else if (!strcasecmp(param, "random-periodic-announce")) {
3646 } else if (!strcasecmp(param, "retry")) {
3647 q->retry = atoi(val);
3648 if (q->retry <= 0) {
3649 q->retry = DEFAULT_RETRY;
3650 }
3651 } else if (!strcasecmp(param, "wrapuptime")) {
3652 q->wrapuptime = atoi(val);
3653 } else if (!strcasecmp(param, "penaltymemberslimit")) {
3654 if ((sscanf(val, "%10d", &q->penaltymemberslimit) != 1)) {
3655 q->penaltymemberslimit = 0;
3656 }
3657 } else if (!strcasecmp(param, "autofill")) {
3658 q->autofill = ast_true(val);
3659 } else if (!strcasecmp(param, "autopause")) {
3661 } else if (!strcasecmp(param, "autopausedelay")) {
3662 q->autopausedelay = atoi(val);
3663 } else if (!strcasecmp(param, "autopausebusy")) {
3665 } else if (!strcasecmp(param, "autopauseunavail")) {
3667 } else if (!strcasecmp(param, "maxlen")) {
3668 q->maxlen = atoi(val);
3669 if (q->maxlen < 0) {
3670 q->maxlen = 0;
3671 }
3672 } else if (!strcasecmp(param, "servicelevel")) {
3673 q->servicelevel= atoi(val);
3674 } else if (!strcasecmp(param, "strategy")) {
3675 int strategy;
3676
3677 /* We are a static queue and already have set this, no need to do it again */
3678 if (failunknown) {
3679 return;
3680 }
3682 if (strategy < 0) {
3683 ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n",
3684 val, q->name);
3686 }
3687 if (strategy == q->strategy) {
3688 return;
3689 }
3691 ast_log(LOG_WARNING, "Changing to the linear strategy currently requires asterisk to be restarted.\n");
3692 return;
3693 }
3694 q->strategy = strategy;
3695 } else if (!strcasecmp(param, "joinempty")) {
3697 } else if (!strcasecmp(param, "leavewhenempty")) {
3699 } else if (!strcasecmp(param, "reportholdtime")) {
3701 } else if (!strcasecmp(param, "memberdelay")) {
3702 q->memberdelay = atoi(val);
3703 } else if (!strcasecmp(param, "weight")) {
3704 q->weight = atoi(val);
3705 } else if (!strcasecmp(param, "timeoutrestart")) {
3707 } else if (!strcasecmp(param, "defaultrule")) {
3708 ast_string_field_set(q, defaultrule, val);
3709 } else if (!strcasecmp(param, "timeoutpriority")) {
3710 if (!strcasecmp(val, "conf")) {
3712 } else {
3714 }
3715 } else if (!strcasecmp(param, "log-restricted-caller-id")) {
3717 } else if (failunknown) {
3718 if (linenum >= 0) {
3719 ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s at line %d of queues.conf\n",
3720 q->name, param, linenum);
3721 } else {
3722 ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s\n", q->name, param);
3723 }
3724 }
3725}
#define ANNOUNCEPOSITION_MORE_THAN
Definition: app_queue.c:1960
static void parse_empty_options(const char *value, enum empty_conditions *empty, int joinempty)
Definition: app_queue.c:3481
#define ANNOUNCEPOSITION_NO
Definition: app_queue.c:1959
#define ANNOUNCEHOLDTIME_ALWAYS
Definition: app_queue.c:1942
#define ANNOUNCEPOSITION_LIMIT
Definition: app_queue.c:1961
#define ANNOUNCEHOLDTIME_ONCE
Definition: app_queue.c:1943
static int autopause2int(const char *autopause)
Definition: app_queue.c:2120
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 10612 of file app_queue.c.

10613{
10614 switch ( cmd ) {
10615 case CLI_INIT:
10616 e->command = "queue show";
10617 e->usage =
10618 "Usage: queue show\n"
10619 " Provides summary information on a specified queue.\n";
10620 return NULL;
10621 case CLI_GENERATE:
10622 return complete_queue_show(a->line, a->word, a->pos, a->n);
10623 }
10624
10625 return __queues_show(NULL, a->fd, a->argc, a->argv);
10626}
static char * complete_queue_show(const char *line, const char *word, int pos, int state)
Definition: app_queue.c:10604
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:10396

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

6486{
6487 struct queue_stasis_data *queue_data;
6488
6489 queue_data = ao2_alloc(sizeof(*queue_data), queue_stasis_data_destructor);
6490 if (!queue_data) {
6491 return NULL;
6492 }
6493
6494 if (ast_string_field_init(queue_data, 64)) {
6495 ao2_cleanup(queue_data);
6496 return NULL;
6497 }
6498
6501 queue_data->queue = queue_ref(qe->parent);
6502 queue_data->starttime = starttime;
6503 queue_data->holdstart = holdstart;
6505 queue_data->caller_pos = qe->opos;
6506 ao2_ref(mem, +1);
6507 queue_data->member = mem;
6508
6509 return queue_data;
6510}
static void queue_stasis_data_destructor(void *obj)
Definition: app_queue.c:6451

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

6452{
6453 struct queue_stasis_data *queue_data = obj;
6454
6455 /* This can only happen if refcounts for this object have got severely messed up */
6456 ast_assert(queue_data->bridge_router == NULL);
6457 ast_assert(queue_data->channel_router == NULL);
6458
6459 ao2_cleanup(queue_data->member);
6460 queue_unref(queue_data->queue);
6461 ast_string_field_free_memory(queue_data);
6462}
struct stasis_message_router * channel_router
Definition: app_queue.c:6440
struct stasis_message_router * bridge_router
Definition: app_queue.c:6438

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

11858{
11859 int oldtalktime;
11860 char *parse;
11861 struct call_queue *q;
11862 struct member *mem;
11863 int newtalktime = 0;
11864
11866 AST_APP_ARG(queuename);
11867 AST_APP_ARG(uniqueid);
11868 AST_APP_ARG(agent);
11870 AST_APP_ARG(talktime);
11871 AST_APP_ARG(params););
11872
11873 if (ast_strlen_zero(data)) {
11874 ast_log(LOG_WARNING, "QueueUpdate requires arguments (queuename,uniqueid,agent,status,talktime,params[totaltime,callednumber])\n");
11875 return -1;
11876 }
11877
11878 parse = ast_strdupa(data);
11879
11881
11882 if (ast_strlen_zero(args.queuename) || ast_strlen_zero(args.uniqueid) || ast_strlen_zero(args.agent) || ast_strlen_zero(args.status)) {
11883 ast_log(LOG_WARNING, "Missing argument to QueueUpdate (queuename,uniqueid,agent,status,talktime,params[totaltime|callednumber])\n");
11884 return -1;
11885 }
11886
11887 if (!ast_strlen_zero(args.talktime)) {
11888 newtalktime = atoi(args.talktime);
11889 }
11890
11891 q = find_load_queue_rt_friendly(args.queuename);
11892 if (!q) {
11893 ast_log(LOG_WARNING, "QueueUpdate could not find requested queue '%s'\n", args.queuename);
11894 return 0;
11895 }
11896
11897 ao2_lock(q);
11898 if (q->members) {
11899 struct ao2_iterator mem_iter = ao2_iterator_init(q->members, 0);
11900 while ((mem = ao2_iterator_next(&mem_iter))) {
11901 if (!strcasecmp(mem->membername, args.agent)) {
11902 if (!strcasecmp(args.status, "ANSWER")) {
11903 oldtalktime = q->talktime;
11904 q->talktime = (((oldtalktime << 2) - oldtalktime) + newtalktime) >> 2;
11905 time(&mem->lastcall);
11906 mem->calls++;
11907 mem->lastqueue = q;
11908 q->callscompleted++;
11909
11910 if (newtalktime <= q->servicelevel) {
11911 q->callscompletedinsl++;
11912 }
11913 } else {
11914
11915 time(&mem->lastcall);
11916 q->callsabandoned++;
11917 }
11918
11919 ast_queue_log(args.queuename, args.uniqueid, args.agent, "OUTCALL", "%s|%s|%s", args.status, args.talktime, args.params);
11920 }
11921
11922 ao2_ref(mem, -1);
11923 }
11924
11925 ao2_iterator_destroy(&mem_iter);
11926 }
11927
11928 ao2_unlock(q);
11929 queue_t_unref(q, "Done with temporary pointer");
11930
11931 return 0;
11932}

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

4542{
4543 int oldvalue;
4544
4545 /* Calculate holdtime using an exponential average */
4546 /* Thanks to SRT for this contribution */
4547 /* 2^2 (4) is the filter coefficient; a higher exponent would give old entries more weight */
4548
4549 ao2_lock(qe->parent);
4550 if ((qe->parent->callscompleted + qe->parent->callsabandoned) == 0) {
4551 qe->parent->holdtime = newholdtime;
4552 } else {
4553 oldvalue = qe->parent->holdtime;
4554 qe->parent->holdtime = (((oldvalue << 2) - oldvalue) + newholdtime) >> 2;
4555 }
4556 ao2_unlock(qe->parent);
4557}

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

5272{
5273 int callabandonedinsl = 0;
5274 time_t now;
5275
5276 RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
5277
5278 pbx_builtin_setvar_helper(qe->chan, "ABANDONED", "TRUE");
5279
5281 ao2_lock(qe->parent);
5282 blob = ast_json_pack("{s: s, s: i, s: i, s: i}",
5283 "Queue", qe->parent->name,
5284 "Position", qe->pos,
5285 "OriginalPosition", qe->opos,
5286 "HoldTime", (int)(time(NULL) - qe->start));
5287
5288
5289 time(&now);
5290 callabandonedinsl = ((now - qe->start) <= qe->parent->servicelevel);
5291 if (callabandonedinsl) {
5293 }
5294
5295 qe->parent->callsabandoned++;
5296 ao2_unlock(qe->parent);
5297
5298 ast_channel_publish_cached_blob(qe->chan, queue_caller_abandon_type(), blob);
5299}

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

12182{
12183 struct ast_flags mask = {AST_FLAGS_ALL & ~QUEUE_RESET_STATS,};
12184 ast_unload_realtime("queue_members");
12185 reload_handler(1, &mask, NULL);
12186 return 0;
12187}
int ast_unload_realtime(const char *family)
Release any resources cached for a realtime family.
Definition: main/config.c:3796

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

10262{
10263 int res = 0;
10264
10265 if (ast_test_flag(mask, QUEUE_RELOAD_RULES)) {
10266 res |= reload_queue_rules(reload);
10267 }
10268 if (ast_test_flag(mask, QUEUE_RESET_STATS)) {
10269 res |= clear_stats(queuename);
10270 }
10272 res |= reload_queues(reload, mask, queuename);
10273 }
10274 return res;
10275}
static int reload_queues(int reload, struct ast_flags *mask, const char *queuename)
reload the queues.conf file
Definition: app_queue.c:10174
static int reload_queue_rules(int reload)
Reload the rules defined in queuerules.conf.
Definition: app_queue.c:9744
static int clear_stats(const char *queuename)
Facilitates resetting statistics for a queue.
Definition: app_queue.c:10231
static int reload(void)
Definition: app_queue.c:12181

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

8293{
8294 char *cur_ptr;
8295 const char *queue_name;
8296 char *member;
8297 char *interface;
8298 char *membername = NULL;
8299 char *state_interface;
8300 char *penalty_tok;
8301 int penalty = 0;
8302 char *paused_tok;
8303 int paused = 0;
8304 char *wrapuptime_tok;
8305 int wrapuptime = 0;
8306 char *reason_paused;
8307 struct ast_db_entry *db_tree;
8308 struct ast_db_entry *entry;
8309 struct call_queue *cur_queue;
8310 char *queue_data;
8311
8312 /* Each key in 'pm_family' is the name of a queue */
8313 db_tree = ast_db_gettree(pm_family, NULL);
8314 for (entry = db_tree; entry; entry = entry->next) {
8315
8316 queue_name = entry->key + strlen(pm_family) + 2;
8317
8318 {
8319 struct call_queue tmpq = {
8320 .name = queue_name,
8321 };
8322 cur_queue = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Reload queue members");
8323 }
8324
8325 if (!cur_queue) {
8326 cur_queue = find_load_queue_rt_friendly(queue_name);
8327 }
8328
8329 if (!cur_queue) {
8330 /* If the queue no longer exists, remove it from the
8331 * database */
8332 ast_log(LOG_WARNING, "Error loading persistent queue: '%s': it does not exist\n", queue_name);
8333 ast_db_del(pm_family, queue_name);
8334 continue;
8335 }
8336
8337 if (ast_db_get_allocated(pm_family, queue_name, &queue_data)) {
8338 queue_t_unref(cur_queue, "Expire reload reference");
8339 continue;
8340 }
8341
8342 cur_ptr = queue_data;
8343 while ((member = strsep(&cur_ptr, ",|"))) {
8344 if (ast_strlen_zero(member)) {
8345 continue;
8346 }
8347
8348 interface = strsep(&member, ";");
8349 penalty_tok = strsep(&member, ";");
8350 paused_tok = strsep(&member, ";");
8351 membername = strsep(&member, ";");
8352 state_interface = strsep(&member, ";");
8353 reason_paused = strsep(&member, ";");
8354 wrapuptime_tok = strsep(&member, ";");
8355
8356 if (!penalty_tok) {
8357 ast_log(LOG_WARNING, "Error parsing persistent member string for '%s' (penalty)\n", queue_name);
8358 break;
8359 }
8360 penalty = strtol(penalty_tok, NULL, 10);
8361 if (errno == ERANGE) {
8362 ast_log(LOG_WARNING, "Error converting penalty: %s: Out of range.\n", penalty_tok);
8363 break;
8364 }
8365
8366 if (!paused_tok) {
8367 ast_log(LOG_WARNING, "Error parsing persistent member string for '%s' (paused)\n", queue_name);
8368 break;
8369 }
8370 paused = strtol(paused_tok, NULL, 10);
8371 if ((errno == ERANGE) || paused < 0 || paused > 1) {
8372 ast_log(LOG_WARNING, "Error converting paused: %s: Expected 0 or 1.\n", paused_tok);
8373 break;
8374 }
8375
8376 if (!ast_strlen_zero(wrapuptime_tok)) {
8377 wrapuptime = strtol(wrapuptime_tok, NULL, 10);
8378 if (errno == ERANGE) {
8379 ast_log(LOG_WARNING, "Error converting wrapuptime: %s: Out of range.\n", wrapuptime_tok);
8380 break;
8381 }
8382 }
8383
8384 ast_debug(1, "Reload Members: Queue: %s Member: %s Name: %s Penalty: %d Paused: %d ReasonPause: %s Wrapuptime: %d\n",
8385 queue_name, interface, membername, penalty, paused, reason_paused, wrapuptime);
8386
8387 if (add_to_queue(queue_name, interface, membername, penalty, paused, 0, state_interface, reason_paused, wrapuptime) == RES_OUTOFMEMORY) {
8388 ast_log(LOG_ERROR, "Out of Memory when reloading persistent queue member\n");
8389 break;
8390 }
8391 }
8392 queue_t_unref(cur_queue, "Expire reload reference");
8393 ast_free(queue_data);
8394 }
8395
8396 if (db_tree) {
8397 ast_log(LOG_NOTICE, "Queue members successfully reloaded from database.\n");
8398 ast_db_freetree(db_tree);
8399 }
8400}
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 9744 of file app_queue.c.

9745{
9746 struct ast_config *cfg;
9747 struct rule_list *rl_iter, *new_rl;
9748 struct penalty_rule *pr_iter;
9749 char *rulecat = NULL;
9750 struct ast_variable *rulevar = NULL;
9751 struct ast_flags config_flags = { (reload && !realtime_rules) ? CONFIG_FLAG_FILEUNCHANGED : 0 };
9752
9753 if (!(cfg = ast_config_load("queuerules.conf", config_flags))) {
9754 ast_log(LOG_NOTICE, "No queuerules.conf file found, queues will not follow penalty rules\n");
9756 } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
9757 ast_log(LOG_NOTICE, "queuerules.conf has not changed since it was last loaded. Not taking any action.\n");
9759 } else if (cfg == CONFIG_STATUS_FILEINVALID) {
9760 ast_log(LOG_ERROR, "Config file queuerules.conf is in an invalid format. Aborting.\n");
9762 }
9763
9765 while ((rl_iter = AST_LIST_REMOVE_HEAD(&rule_lists, list))) {
9766 while ((pr_iter = AST_LIST_REMOVE_HEAD(&rl_iter->rules, list)))
9767 ast_free(pr_iter);
9768 ast_free(rl_iter);
9769 }
9771 while ((rulecat = ast_category_browse(cfg, rulecat))) {
9772 if (!strcasecmp(rulecat, "general")) {
9774 continue;
9775 }
9776 if (!(new_rl = ast_calloc(1, sizeof(*new_rl)))) {
9778 ast_config_destroy(cfg);
9780 } else {
9781 ast_copy_string(new_rl->name, rulecat, sizeof(new_rl->name));
9782 AST_LIST_INSERT_TAIL(&rule_lists, new_rl, list);
9783 for (rulevar = ast_variable_browse(cfg, rulecat); rulevar; rulevar = rulevar->next)
9784 if(!strcasecmp(rulevar->name, "penaltychange"))
9785 insert_penaltychange(new_rl->name, rulevar->value, rulevar->lineno);
9786 else
9787 ast_log(LOG_WARNING, "Don't know how to handle rule type '%s' on line %d\n", rulevar->name, rulevar->lineno);
9788 }
9789 }
9790
9791 ast_config_destroy(cfg);
9792
9796 }
9797
9800}
static int load_realtime_rules(void)
Load queue rules from realtime.
Definition: app_queue.c:3369
static void queue_rules_reset_global_params(void)
Definition: app_queue.c:9724
static int insert_penaltychange(const char *list_name, const char *content, const int linenum)
Change queue penalty by adding rule.
Definition: app_queue.c:3260
static void queue_rules_set_global_params(struct ast_config *cfg)
Definition: app_queue.c:9730
#define ast_config_load(filename, flags)
Load a config file.
@ CONFIG_FLAG_FILEUNCHANGED
#define CONFIG_STATUS_FILEUNCHANGED
#define CONFIG_STATUS_FILEINVALID
struct ast_variable * ast_variable_browse(const struct ast_config *config, const char *category_name)
Definition: extconf.c:1215

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

10175{
10176 struct ast_config *cfg;
10177 char *cat;
10178 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
10179 const int queue_reload = ast_test_flag(mask, QUEUE_RELOAD_PARAMETERS);
10180
10181 if (!(cfg = ast_config_load("queues.conf", config_flags))) {
10182 ast_log(LOG_NOTICE, "No call queueing config file (queues.conf), so no call queues\n");
10183 return -1;
10184 } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
10185 return 0;
10186 } else if (cfg == CONFIG_STATUS_FILEINVALID) {
10187 ast_log(LOG_ERROR, "Config file queues.conf is in an invalid format. Aborting.\n");
10188 return -1;
10189 }
10190
10191 /* We've made it here, so it looks like we're doing operations on all queues. */
10193
10194 /* Mark non-realtime queues not found at the beginning. */
10195 ao2_callback(queues, OBJ_NODATA, mark_unfound, (char *) queuename);
10196
10197 /* Chug through config file. */
10198 cat = NULL;
10200 while ((cat = ast_category_browse(cfg, cat)) ) {
10201 if (!strcasecmp(cat, "general") && queue_reload) {
10203 continue;
10204 }
10205 if (ast_strlen_zero(queuename) || !strcasecmp(cat, queuename))
10206 reload_single_queue(cfg, mask, cat);
10207 }
10208
10209 ast_config_destroy(cfg);
10210 if (queue_reload) {
10211 /* Unlink and mark dead all non-realtime queues that were not found in the configuration file. */
10213 }
10215 return 0;
10216}
static void queue_reset_global_params(void)
Definition: app_queue.c:9803
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:10017
static void queue_set_global_params(struct ast_config *cfg)
Definition: app_queue.c:9815
static int mark_unfound(void *obj, void *arg, int flags)
Definition: app_queue.c:10140
static int kill_if_unfound(void *obj, void *arg, int flags)
Definition: app_queue.c:10150

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

9855{
9856 char *membername, *interface, *state_interface, *tmp;
9857 char *parse;
9858 struct member *cur, *newm;
9859 struct member tmpmem;
9860 int penalty;
9861 int ringinuse;
9862 int wrapuptime;
9863 int paused;
9872 );
9873
9874 if (ast_strlen_zero(memberdata)) {
9875 ast_log(LOG_WARNING, "Empty queue member definition. Moving on!\n");
9876 return;
9877 }
9878
9879 /* Add a new member */
9880 parse = ast_strdupa(memberdata);
9881
9883
9884 interface = args.interface;
9885 if (!ast_strlen_zero(args.penalty)) {
9886 tmp = args.penalty;
9887 ast_strip(tmp);
9888 penalty = atoi(tmp);
9889 if (penalty < 0) {
9890 penalty = 0;
9891 }
9892 } else {
9893 penalty = 0;
9894 }
9895
9896 if (!ast_strlen_zero(args.membername)) {
9897 membername = args.membername;
9898 ast_strip(membername);
9899 } else {
9900 membername = interface;
9901 }
9902
9903 if (!ast_strlen_zero(args.state_interface)) {
9904 state_interface = args.state_interface;
9905 ast_strip(state_interface);
9906 } else {
9907 state_interface = interface;
9908 }
9909
9910 if (!ast_strlen_zero(args.ringinuse)) {
9911 tmp = args.ringinuse;
9912 ast_strip(tmp);
9913 if (ast_true(tmp)) {
9914 ringinuse = 1;
9915 } else if (ast_false(tmp)) {
9916 ringinuse = 0;
9917 } else {
9918 ast_log(LOG_ERROR, "Member %s has an invalid ringinuse value. Using %s ringinuse value.\n",
9919 membername, q->name);
9920 ringinuse = q->ringinuse;
9921 }
9922 } else {
9923 ringinuse = q->ringinuse;
9924 }
9925
9926 if (!ast_strlen_zero(args.wrapuptime)) {
9927 tmp = args.wrapuptime;
9928 ast_strip(tmp);
9929 wrapuptime = atoi(tmp);
9930 if (wrapuptime < 0) {
9931 wrapuptime = 0;
9932 }
9933 } else {
9934 wrapuptime = 0;
9935 }
9936
9937 if (!ast_strlen_zero(args.paused)) {
9938 tmp = args.paused;
9939 ast_strip(tmp);
9940 if (ast_true(tmp)) {
9941 paused = 1;
9942 } else if (ast_false(tmp)) {
9943 paused = 0;
9944 } else {
9945 ast_log(LOG_ERROR, "Member %s has an invalid paused value.\n", membername);
9946 paused = 0;
9947 }
9948 } else {
9949 paused = 0;
9950 }
9951
9952 /* Find the old position in the list */
9953 ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface));
9954 cur = ao2_find(q->members, &tmpmem, OBJ_POINTER);
9955
9956 if (cur) {
9957 paused = cur->paused;
9958 }
9959
9960 if ((newm = create_queue_member(interface, membername, penalty, paused, state_interface, ringinuse, wrapuptime))) {
9961 newm->wrapuptime = wrapuptime;
9962 if (cur) {
9963 ao2_lock(q->members);
9964 /* Round Robin Queue Position must be copied if this is replacing an existing member */
9965 newm->queuepos = cur->queuepos;
9966 /* Don't reset agent stats either */
9967 newm->calls = cur->calls;
9968 newm->lastcall = cur->lastcall;
9969
9970 ao2_link(q->members, newm);
9971 ao2_unlink(q->members, cur);
9972 ao2_unlock(q->members);
9973 } else {
9974 /* Otherwise we need to add using the function that will apply a round robin queue position manually. */
9975 member_add_to_queue(q, newm);
9976 }
9977 ao2_ref(newm, -1);
9978 }
9979 newm = NULL;
9980
9981 if (cur) {
9982 ao2_ref(cur, -1);
9983 }
9984}

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

10018{
10019 int new;
10020 struct call_queue *q = NULL;
10021 struct member *member;
10022 /*We're defining a queue*/
10023 struct call_queue tmpq = {
10024 .name = queuename,
10025 };
10026 const char *tmpvar;
10027 const int queue_reload = ast_test_flag(mask, QUEUE_RELOAD_PARAMETERS);
10028 const int member_reload = ast_test_flag(mask, QUEUE_RELOAD_MEMBER);
10029 int prev_weight = 0;
10030 struct ast_variable *var;
10031 struct ao2_iterator mem_iter;
10032
10033 if (!(q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Find queue for reload"))) {
10034 if (queue_reload) {
10035 /* Make one then */
10036 if (!(q = alloc_queue(queuename))) {
10037 return;
10038 }
10039 } else {
10040 /* Since we're not reloading queues, this means that we found a queue
10041 * in the configuration file which we don't know about yet. Just return.
10042 */
10043 return;
10044 }
10045 new = 1;
10046 } else {
10047 new = 0;
10048 }
10049
10050 if (!new) {
10051 ao2_lock(q);
10052 prev_weight = q->weight ? 1 : 0;
10053 }
10054 /* Check if we already found a queue with this name in the config file */
10055 if (q->found) {
10056 ast_log(LOG_WARNING, "Queue '%s' already defined! Skipping!\n", queuename);
10057 if (!new) {
10058 /* It should be impossible to *not* hit this case*/
10059 ao2_unlock(q);
10060 }
10061 queue_t_unref(q, "We exist! Expiring temporary pointer");
10062 return;
10063 }
10064 /* Due to the fact that the "linear" strategy will have a different allocation
10065 * scheme for queue members, we must devise the queue's strategy before other initializations.
10066 * To be specific, the linear strategy needs to function like a linked list, meaning the ao2
10067 * container used will have only a single bucket instead of the typical number.
10068 */
10069 if (queue_reload) {
10070 if ((tmpvar = ast_variable_retrieve(cfg, queuename, "strategy"))) {
10071 q->strategy = strat2int(tmpvar);
10072 if (q->strategy < 0) {
10073 ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n",
10074 tmpvar, q->name);
10076 }
10077 } else {
10079 }
10080 init_queue(q);
10081 }
10082 if (member_reload) {
10084 q->found = 1;
10085 }
10086
10087 /* On the first pass we just read the parameters of the queue */
10088 for (var = ast_variable_browse(cfg, queuename); var; var = var->next) {
10089 if (queue_reload && strcasecmp(var->name, "member")) {
10090 queue_set_param(q, var->name, var->value, var->lineno, 1);
10091 }
10092 }
10093
10094 /* On the second pass, we read members */
10095 for (var = ast_variable_browse(cfg, queuename); var; var = var->next) {
10096 if (member_reload && !strcasecmp(var->name, "member")) {
10097 reload_single_member(var->value, q);
10098 }
10099 }
10100
10101 /* Update ringinuse for dynamic members */
10102 if (member_reload) {
10103 ao2_lock(q->members);
10105 while ((member = ao2_iterator_next(&mem_iter))) {
10106 if (member->dynamic) {
10108 }
10109 ao2_ref(member, -1);
10110 }
10111 ao2_iterator_destroy(&mem_iter);
10112 ao2_unlock(q->members);
10113 }
10114
10115 /* At this point, we've determined if the queue has a weight, so update use_weight
10116 * as appropriate
10117 */
10118 if (!q->weight && prev_weight) {
10120 } else if (q->weight && !prev_weight) {
10122 }
10123
10124 /* Free remaining members marked as delme */
10125 if (member_reload) {
10126 ao2_lock(q->members);
10129 ao2_unlock(q->members);
10130 }
10131
10132 if (new) {
10133 queues_t_link(queues, q, "Add queue to container");
10134 } else {
10135 ao2_unlock(q);
10136 }
10137 queue_t_unref(q, "Expiring creation reference");
10138}
static int mark_member_dead(void *obj, void *arg, int flags)
Definition: app_queue.c:9986
static void reload_single_member(const char *memberdata, struct call_queue *q)
reload information pertaining to a single member
Definition: app_queue.c:9854
static int kill_dead_members(void *obj, void *arg, int flags)
Definition: app_queue.c:9995
static int queue_delme_members_decrement_followers(void *obj, void *arg, int flag)
Definition: app_queue.c:2196

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

7733{
7734 struct call_queue *q, tmpq = {
7735 .name = queuename,
7736 };
7737 struct member *mem, tmpmem;
7738 int res = RES_NOSUCHQUEUE;
7739
7740 ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface));
7741 if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Temporary reference for interface removal"))) {
7742 ao2_lock(q);
7743 if ((mem = ao2_find(q->members, &tmpmem, OBJ_POINTER))) {
7744 /* XXX future changes should beware of this assumption!! */
7745 /*Change Penalty on realtime users*/
7747 update_realtime_member_field(mem, q->name, "penalty", "-1");
7748 } else if (!mem->dynamic) {
7749 ao2_ref(mem, -1);
7750 ao2_unlock(q);
7751 queue_t_unref(q, "Interface wasn't dynamic, expiring temporary reference");
7752 return RES_NOT_DYNAMIC;
7753 }
7754 queue_publish_member_blob(queue_member_removed_type(), queue_member_blob_create(q, mem));
7755
7757 ao2_ref(mem, -1);
7758
7761 }
7762
7763 if (!num_available_members(q)) {
7765 }
7766
7767 res = RES_OKAY;
7768 } else {
7769 res = RES_EXISTS;
7770 }
7771 ao2_unlock(q);
7772 queue_t_unref(q, "Expiring temporary reference");
7773 }
7774
7775 return res;
7776}
static int update_realtime_member_field(struct member *mem, const char *queue_name, const char *field, const char *value)
Definition: app_queue.c:4176
char rt_uniqueid[80]
Definition: app_queue.c:1921

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

6469{
6470 SCOPED_AO2LOCK(lock, queue_data);
6471
6472 queue_data->dying = 1;
6474 queue_data->bridge_router = NULL;
6476 queue_data->channel_router = NULL;
6477}
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 7914 of file app_queue.c.

7915{
7916 struct call_queue *q;
7917 struct queue_ent *qe;
7918 int res = RES_NOSUCHQUEUE;
7919
7920 /*! \note Ensure the appropriate realtime queue is loaded. Note that this
7921 * short-circuits if the queue is already in memory. */
7922 if (!(q = find_load_queue_rt_friendly(queuename))) {
7923 return res;
7924 }
7925
7926 ao2_lock(q);
7927 res = RES_NOT_CALLER;
7928 for (qe = q->head; qe; qe = qe->next) {
7929 if (!strcmp(ast_channel_name(qe->chan), caller)) {
7930 if (qe->withdraw) {
7931 ast_debug(1, "Ignoring duplicate withdraw request of caller %s from queue %s\n", caller, queuename);
7932 res = RES_EXISTS;
7933 } else {
7934 ast_debug(1, "Requested withdraw of caller %s from queue %s\n", caller, queuename);
7935 /* It is not possible to change the withdraw info by further withdraw requests for this caller (channel)
7936 in this queue, so we do not need to worry about a memory leak here. */
7937 if (withdraw_info) {
7939 }
7940 qe->withdraw = 1;
7941 res = RES_OKAY;
7942 }
7943 break;
7944 }
7945 }
7946 ao2_unlock(q);
7947 queue_unref(q);
7948
7949 return res;
7950}

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

4946{
4947 int res;
4948 int status;
4949 char tech[256];
4950 char *location;
4951 struct ast_format_cap *nativeformats;
4952 RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
4953
4954 /* on entry here, we know that tmp->chan == NULL */
4955 if (!can_ring_entry(qe, tmp)) {
4956 tmp->stillgoing = 0;
4957 ++*busies;
4958 return 0;
4959 }
4960
4961 ast_copy_string(tech, tmp->interface, sizeof(tech));
4962 if ((location = strchr(tech, '/'))) {
4963 *location++ = '\0';
4964 } else {
4965 location = "";
4966 }
4967
4969 nativeformats = ao2_bump(ast_channel_nativeformats(qe->chan));
4971
4972 /* Request the peer */
4973 tmp->chan = ast_request(tech, nativeformats, NULL, qe->chan, location, &status);
4974 ao2_cleanup(nativeformats);
4975 if (!tmp->chan) { /* If we can't, just go on to the next call */
4976 ao2_lock(qe->parent);
4977 qe->parent->rrpos++;
4978 qe->linpos++;
4979 ao2_unlock(qe->parent);
4980
4982
4983 publish_dial_end_event(qe->chan, tmp, NULL, "BUSY");
4984 tmp->stillgoing = 0;
4985 ++*busies;
4986 return 0;
4987 }
4988
4989 ast_channel_lock_both(tmp->chan, qe->chan);
4990
4993 if (qe->cancel_answered_elsewhere) {
4995 }
4996 ast_channel_appl_set(tmp->chan, "AppQueue");
4997 ast_channel_data_set(tmp->chan, "(Outgoing Line)");
4998 memset(ast_channel_whentohangup(tmp->chan), 0, sizeof(*ast_channel_whentohangup(tmp->chan)));
4999
5000 /* If the new channel has no callerid, try to guess what it should be */
5001 if (!ast_channel_caller(tmp->chan)->id.number.valid) {
5003 struct ast_party_caller caller;
5004
5006 caller.id = ast_channel_connected(qe->chan)->id;
5007 caller.ani = ast_channel_connected(qe->chan)->ani;
5008 ast_channel_set_caller_event(tmp->chan, &caller, NULL);
5009 } else if (!ast_strlen_zero(ast_channel_dialed(qe->chan)->number.str)) {
5011 } else if (!ast_strlen_zero(ast_channel_exten(qe->chan))) {
5013 }
5014 tmp->dial_callerid_absent = 1;
5015 }
5016
5018
5020
5022
5023 /* Inherit specially named variables from parent channel */
5027
5028 /* Presense of ADSI CPE on outgoing channel follows ours */
5030
5031 /* Inherit context and extension */
5032 ast_channel_dialcontext_set(tmp->chan, ast_channel_context(qe->chan));
5034
5035 /* Save the original channel name to detect call pickup masquerading in. */
5037
5040
5041 /* location is tmp->interface where tech/ has been stripped, so it follow the same syntax as DIALEDPEERNUMBER in app_dial.c */
5042 pbx_builtin_setvar_helper(tmp->chan, "DIALEDPEERNUMBER", strlen(location) ? location : tmp->interface);
5043
5044 /* PREDIAL: Run gosub on the callee's channel */
5045 if (qe->predial_callee) {
5046 ast_pre_call(tmp->chan, qe->predial_callee);
5047 }
5048
5049 /* Place the call, but don't wait on the answer */
5050 if ((res = ast_call(tmp->chan, location, 0))) {
5051 /* Again, keep going even if there's an error */
5052 ast_verb(3, "Couldn't call %s\n", tmp->interface);
5053 do_hang(tmp);
5054 ++*busies;
5055 return 0;
5056 }
5057
5058 ast_channel_lock_both(tmp->chan, qe->chan);
5059
5060 blob = ast_json_pack("{s: s, s: s, s: s}",
5061 "Queue", qe->parent->name,
5062 "Interface", tmp->interface,
5063 "MemberName", tmp->member->membername);
5064 queue_publish_multi_channel_blob(qe->chan, tmp->chan, queue_agent_called_type(), blob);
5065
5067
5070
5071 ast_verb(3, "Called %s\n", tmp->interface);
5072
5073 return 1;
5074}
static void do_hang(struct callattempt *o)
common hangup actions
Definition: app_queue.c:4819
static int can_ring_entry(struct queue_ent *qe, struct callattempt *call)
Definition: app_queue.c:4849
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:2512
static void publish_dial_end_event(struct ast_channel *in, struct callattempt *outgoing, struct ast_channel *exception, const char *status)
Definition: app_queue.c:4649
#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:6420
@ 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:7345
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:2337
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:1966
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:7307
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:6735
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:8298
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:6398
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:6403
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:6313
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:2102
int ast_max_forwards_decrement(struct ast_channel *chan)
Decrement the max forwards count for a particular channel.
Definition: max_forwards.c:135
Format capabilities structure, holds formats + preference order + etc.
Definition: format_cap.c:54
Caller Party information.
Definition: channel.h:420
struct ast_party_id ani
Automatic Number Identification (ANI)
Definition: channel.h:467
struct ast_party_dialed::@210 number
Dialed/Called number.
char * str
Subscriber phone number (Malloced)
Definition: channel.h:388
int transit_network_select
Transit Network Select.
Definition: channel.h:399
unsigned int dial_callerid_absent
Definition: app_queue.c:1853
char interface[256]
Definition: app_queue.c:1843
int cancel_answered_elsewhere
Definition: app_queue.c:1888

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

5103{
5104 int ret = 0;
5105 struct callattempt *cur;
5106
5107 if (qe->predial_callee) {
5109 for (cur = outgoing; cur; cur = cur->q_next) {
5110 if (cur->stillgoing && cur->chan) {
5112 }
5113 }
5114 }
5115
5116 while (ret == 0) {
5117 struct callattempt *best = find_best(outgoing);
5118 if (!best) {
5119 ast_debug(1, "Nobody left to try ringing in queue\n");
5120 break;
5121 }
5123 /* Ring everyone who shares this best metric (for ringall) */
5124 for (cur = outgoing; cur; cur = cur->q_next) {
5125 if (cur->stillgoing && !cur->chan && cur->metric <= best->metric) {
5126 ast_debug(1, "(Parallel) Trying '%s' with metric %d\n", cur->interface, cur->metric);
5127 ret |= ring_entry(qe, cur, busies);
5128 if (qe->predial_callee && cur->chan) {
5130 }
5131 }
5132 }
5133 } else {
5134 /* Ring just the best channel */
5135 ast_debug(1, "Trying '%s' with metric %d\n", best->interface, best->metric);
5136 ret = ring_entry(qe, best, busies);
5137 if (qe->predial_callee && best->chan) {
5139 }
5140 }
5141
5142 /* If we have timed out, break out */
5143 if (qe->expire && (time(NULL) >= qe->expire)) {
5144 ast_debug(1, "Queue timed out while ringing members.\n");
5145 ret = 0;
5146 break;
5147 }
5148 }
5149 if (qe->predial_callee) {
5150 for (cur = outgoing; cur; cur = cur->q_next) {
5151 if (cur->stillgoing && cur->chan) {
5153 }
5154 }
5156 }
5157
5158 return ret;
5159}
static int ring_entry(struct queue_ent *qe, struct callattempt *tmp, int *busies)
Part 2 of ring_one.
Definition: app_queue.c:4945
static struct callattempt * find_best(struct callattempt *outgoing)
find the entry with the best metric, or NULL
Definition: app_queue.c:5077
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 5302 of file app_queue.c.

5303{
5304 RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
5305
5306 ast_verb(3, "Nobody picked up in %d ms\n", rnatime);
5307
5308 /* Stop ringing, and resume MOH if specified */
5309 if (qe->ring_when_ringing) {
5310 ast_indicate(qe->chan, -1);
5311 ast_moh_start(qe->chan, qe->moh, NULL);
5312 }
5313
5314 blob = ast_json_pack("{s: s, s: s, s: s, s: i}",
5315 "Queue", qe->parent->name,
5316 "Interface", interface,
5317 "MemberName", membername,
5318 "RingTime", rnatime);
5319 queue_publish_multi_channel_blob(qe->chan, peer, queue_agent_ringnoanswer_type(), blob);
5320
5321 ast_queue_log(qe->parent->name, ast_channel_uniqueid(qe->chan), membername, "RINGNOANSWER", "%d", rnatime);
5323 if (qe->parent->autopausedelay > 0) {
5324 struct member *mem;
5325 ao2_lock(qe->parent);
5326 if ((mem = interface_exists(qe->parent, interface))) {
5327 time_t idletime = time(&idletime)-mem->lastcall;
5328 if ((mem->lastcall != 0) && (qe->parent->autopausedelay > idletime)) {
5329 ao2_unlock(qe->parent);
5330 ao2_ref(mem, -1);
5331 return;
5332 }
5333 ao2_ref(mem, -1);
5334 }
5335 ao2_unlock(qe->parent);
5336 }
5337 if (qe->parent->autopause == QUEUE_AUTOPAUSE_ON) {
5338 if (!set_member_paused(qe->parent->name, interface, "Auto-Pause", 1)) {
5339 ast_verb(3, "Auto-Pausing Queue Member %s in queue %s since they failed to answer.\n",
5340 interface, qe->parent->name);
5341 } else {
5342 ast_verb(3, "Failed to pause Queue Member %s in queue %s!\n", interface, qe->parent->name);
5343 }
5344 } else {
5345 /* If queue autopause is mode all, just don't send any queue to stop.
5346 * the function will stop in all queues */
5347 if (!set_member_paused("", interface, "Auto-Pause", 1)) {
5348 ast_verb(3, "Auto-Pausing Queue Member %s in all queues since they failed to answer on queue %s.\n",
5349 interface, qe->parent->name);
5350 } else {
5351 ast_verb(3, "Failed to pause Queue Member %s in all queues!\n", interface);
5352 }
5353 }
5354 }
5355 return;
5356}

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

8476{
8477 int res=-1;
8478 char *parse, *temppos = NULL;
8479 struct member *mem = NULL;
8480
8482 AST_APP_ARG(queuename);
8484 );
8485
8486
8487 if (ast_strlen_zero(data)) {
8488 ast_log(LOG_WARNING, "RemoveQueueMember requires an argument (queuename[,interface])\n");
8489 return -1;
8490 }
8491
8492 parse = ast_strdupa(data);
8493
8495
8496 if (ast_strlen_zero(args.interface)) {
8497 args.interface = ast_strdupa(ast_channel_name(chan));
8498 temppos = strrchr(args.interface, '-');
8499 if (temppos) {
8500 *temppos = '\0';
8501 }
8502 }
8503
8504 ast_debug(1, "queue: %s, member: %s\n", args.queuename, args.interface);
8505
8507 mem = find_member_by_queuename_and_interface(args.queuename, args.interface);
8508 }
8509
8510 switch (remove_from_queue(args.queuename, args.interface)) {
8511 case RES_OKAY:
8512 if (!mem || ast_strlen_zero(mem->membername)) {
8513 ast_queue_log(args.queuename, ast_channel_uniqueid(chan), args.interface, "REMOVEMEMBER", "%s", "");
8514 } else {
8515 ast_queue_log(args.queuename, ast_channel_uniqueid(chan), mem->membername, "REMOVEMEMBER", "%s", "");
8516 }
8517 ast_log(LOG_NOTICE, "Removed interface '%s' from queue '%s'\n", args.interface, args.queuename);
8518 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "REMOVED");
8519 res = 0;
8520 break;
8521 case RES_EXISTS:
8522 ast_debug(1, "Unable to remove interface '%s' from queue '%s': Not there\n", args.interface, args.queuename);
8523 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOTINQUEUE");
8524 res = 0;
8525 break;
8526 case RES_NOSUCHQUEUE:
8527 ast_log(LOG_WARNING, "Unable to remove interface from queue '%s': No such queue\n", args.queuename);
8528 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOSUCHQUEUE");
8529 res = 0;
8530 break;
8531 case RES_NOT_DYNAMIC:
8532 ast_log(LOG_WARNING, "Unable to remove interface from queue '%s': '%s' is not a dynamic member\n", args.queuename, args.interface);
8533 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOTDYNAMIC");
8534 res = 0;
8535 break;
8536 }
8537
8538 if (mem) {
8539 ao2_ref(mem, -1);
8540 }
8541
8542 return res;
8543}

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

3771{
3772 struct member *m;
3773 struct ao2_iterator mem_iter;
3774 int penalty = 0;
3775 int paused = 0;
3776 int found = 0;
3777 int wrapuptime = 0;
3778 int ringinuse = q->ringinuse;
3779
3780 const char *config_val;
3781 const char *interface = ast_variable_retrieve(member_config, category, "interface");
3782 const char *rt_uniqueid = ast_variable_retrieve(member_config, category, "uniqueid");
3783 const char *membername = S_OR(ast_variable_retrieve(member_config, category, "membername"), interface);
3784 const char *state_interface = S_OR(ast_variable_retrieve(member_config, category, "state_interface"), interface);
3785 const char *penalty_str = ast_variable_retrieve(member_config, category, "penalty");
3786 const char *paused_str = ast_variable_retrieve(member_config, category, "paused");
3787 const char *wrapuptime_str = ast_variable_retrieve(member_config, category, "wrapuptime");
3788 const char *reason_paused = ast_variable_retrieve(member_config, category, "reason_paused");
3789
3790 if (ast_strlen_zero(rt_uniqueid)) {
3791 ast_log(LOG_WARNING, "Realtime field 'uniqueid' is empty for member %s\n",
3792 S_OR(membername, "NULL"));
3793 return;
3794 }
3795
3796 if (ast_strlen_zero(interface)) {
3797 ast_log(LOG_WARNING, "Realtime field 'interface' is empty for member %s\n",
3798 S_OR(membername, "NULL"));
3799 return;
3800 }
3801
3802 if (penalty_str) {
3803 penalty = atoi(penalty_str);
3804 if ((penalty < 0) && negative_penalty_invalid) {
3805 return;
3806 } else if (penalty < 0) {
3807 penalty = 0;
3808 }
3809 }
3810
3811 if (paused_str) {
3812 paused = atoi(paused_str);
3813 if (paused < 0) {
3814 paused = 0;
3815 }
3816 }
3817
3818 if (wrapuptime_str) {
3819 wrapuptime = atoi(wrapuptime_str);
3820 if (wrapuptime < 0) {
3821 wrapuptime = 0;
3822 }
3823 }
3824
3825 if ((config_val = ast_variable_retrieve(member_config, category, realtime_ringinuse_field))) {
3826 if (ast_true(config_val)) {
3827 ringinuse = 1;
3828 } else if (ast_false(config_val)) {
3829 ringinuse = 0;
3830 } else {
3831 ast_log(LOG_WARNING, "Invalid value of '%s' field for %s in queue '%s'\n", realtime_ringinuse_field, interface, q->name);
3832 }
3833 }
3834
3835 /* Find member by realtime uniqueid and update */
3836 mem_iter = ao2_iterator_init(q->members, 0);
3837 while ((m = ao2_iterator_next(&mem_iter))) {
3838 if (!strcasecmp(m->rt_uniqueid, rt_uniqueid)) {
3839 m->dead = 0; /* Do not delete this one. */
3840 ast_copy_string(m->rt_uniqueid, rt_uniqueid, sizeof(m->rt_uniqueid));
3841 if (paused_str) {
3842 m->paused = paused;
3843 if (paused && m->lastpause == 0) {
3844 time(&m->lastpause); /* XXX: Should this come from realtime? */
3845 }
3847 AST_DEVSTATE_CACHABLE, "Queue:%s_pause_%s", q->name, m->interface);
3848 }
3849 if (strcasecmp(state_interface, m->state_interface)) {
3850 ast_copy_string(m->state_interface, state_interface, sizeof(m->state_interface));
3851 }
3852 m->penalty = penalty;
3853 m->ringinuse = ringinuse;
3854 m->wrapuptime = wrapuptime;
3856 ast_copy_string(m->reason_paused, S_OR(reason_paused, ""), sizeof(m->reason_paused));
3857 }
3858 found = 1;
3859 ao2_ref(m, -1);
3860 break;
3861 }
3862 ao2_ref(m, -1);
3863 }
3864 ao2_iterator_destroy(&mem_iter);
3865
3866 /* Create a new member */
3867 if (!found) {
3868 if ((m = create_queue_member(interface, membername, penalty, paused, state_interface, ringinuse, wrapuptime))) {
3869 m->dead = 0;
3870 m->realtime = 1;
3871 ast_copy_string(m->rt_uniqueid, rt_uniqueid, sizeof(m->rt_uniqueid));
3872 if (!ast_strlen_zero(reason_paused)) {
3873 ast_copy_string(m->reason_paused, reason_paused, sizeof(m->reason_paused));
3874 }
3876 ast_queue_log(q->name, "REALTIME", m->interface, "ADDMEMBER", "%s", paused ? "PAUSED" : "");
3877 } else {
3878 ast_queue_log(q->name, "REALTIME", m->membername, "ADDMEMBER", "%s", paused ? "PAUSED" : "");
3879 }
3880 member_add_to_queue(q, m);
3881 ao2_ref(m, -1);
3882 m = NULL;
3883 }
3884 }
3885}

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

5211{
5212 int res = 0;
5213 time_t now;
5214
5215 /* Get the current time */
5216 time(&now);
5217
5218 /* Check to see if it is time to announce */
5220 return 0;
5221 }
5222
5223 /* Stop the music on hold so we can play our own file */
5224 if (ringing) {
5225 ast_indicate(qe->chan,-1);
5226 } else {
5227 ast_moh_stop(qe->chan);
5228 }
5229
5230 ast_verb(3, "Playing periodic announcement\n");
5231
5233 qe->last_periodic_announce_sound = ((unsigned long) ast_random()) % qe->parent->numperiodicannounce;
5237 }
5238
5239 /* play the announcement */
5241
5242 if (res > 0 && !valid_exit(qe, res)) {
5243 res = 0;
5244 }
5245
5246 /* Resume Music on Hold if the caller is going to stay in the queue */
5247 if (!res) {
5248 if (ringing) {
5250 } else {
5251 ast_moh_start(qe->chan, qe->moh, NULL);
5252 }
5253 }
5254
5255 /* update last_periodic_announce_time */
5257 time(&qe->last_periodic_announce_time);
5258 } else {
5260 }
5261
5262 /* Update the current periodic announcement to the next announcement */
5263 if (!qe->parent->randomperiodicannounce) {
5265 }
5266
5267 return res;
5268}
static int play_file(struct ast_channel *chan, const char *filename)
Definition: app_queue.c:4335
static int valid_exit(struct queue_ent *qe, char digit)
Check for valid exit from queue via goto.
Definition: app_queue.c:4364

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

4400{
4401 int res = 0, say_thanks = 0;
4402 long avgholdmins, avgholdsecs;
4403 time_t now;
4404
4405 /* Let minannouncefrequency seconds pass between the start of each position announcement */
4406 time(&now);
4407 if ((now - qe->last_pos) < qe->parent->minannouncefrequency) {
4408 return 0;
4409 }
4410
4411 /* If either our position has changed, or we are over the freq timer, say position */
4412 if ((qe->last_pos_said == qe->pos) && ((now - qe->last_pos) < qe->parent->announcefrequency)) {
4413 return 0;
4414 }
4415
4416 /* Only announce if the caller's queue position has improved since last time */
4417 if (qe->parent->announceposition_only_up && qe->last_pos_said <= qe->pos) {
4418 return 0;
4419 }
4420
4421 if (ringing) {
4422 ast_indicate(qe->chan,-1);
4423 } else {
4424 ast_moh_stop(qe->chan);
4425 }
4426
4430 qe->pos <= qe->parent->announcepositionlimit)) {
4431 say_thanks = 1;
4432 /* Say we're next, if we are */
4433 if (qe->pos == 1) {
4434 res = play_file(qe->chan, qe->parent->sound_next);
4435 if (!res) {
4436 goto posout;
4437 }
4438 /* Say there are more than N callers */
4440 res = (
4441 play_file(qe->chan, qe->parent->queue_quantity1) ||
4443 ast_channel_language(qe->chan), NULL) || /* Needs gender */
4445 /* Say there are currently N callers waiting */
4446 } else {
4447 res = (
4448 play_file(qe->chan, qe->parent->sound_thereare) ||
4450 ast_channel_language(qe->chan), "n") || /* Needs gender */
4451 play_file(qe->chan, qe->parent->sound_calls));
4452 }
4453 if (res) {
4454 goto playout;
4455 }
4456 }
4457 /* Round hold time to nearest minute */
4458 avgholdmins = labs(((qe->parent->holdtime + 30) - (now - qe->start)) / 60);
4459
4460 /* If they have specified a rounding then round the seconds as well */
4461 if (qe->parent->roundingseconds) {
4462 avgholdsecs = (labs(((qe->parent->holdtime + 30) - (now - qe->start))) - 60 * avgholdmins) / qe->parent->roundingseconds;
4463 avgholdsecs *= qe->parent->roundingseconds;
4464 } else {
4465 avgholdsecs = 0;
4466 }
4467
4468 ast_verb(3, "Hold time for %s is %ld minute(s) %ld seconds\n", qe->parent->name, avgholdmins, avgholdsecs);
4469
4470 /* If the hold time is >1 min, if it's enabled, and if it's not
4471 supposed to be only once and we have already said it, say it */
4472 if ((avgholdmins+avgholdsecs) > 0 && qe->parent->announceholdtime &&
4475 say_thanks = 1;
4476 res = play_file(qe->chan, qe->parent->sound_holdtime);
4477 if (res) {
4478 goto playout;
4479 }
4480
4481 if (avgholdmins >= 1) {
4482 res = ast_say_number(qe->chan, avgholdmins, AST_DIGIT_ANY, ast_channel_language(qe->chan), "n");
4483 if (res) {
4484 goto playout;
4485 }
4486
4487 if (avgholdmins == 1) {
4488 res = play_file(qe->chan, qe->parent->sound_minute);
4489 if (res) {
4490 goto playout;
4491 }
4492 } else {
4493 res = play_file(qe->chan, qe->parent->sound_minutes);
4494 if (res) {
4495 goto playout;
4496 }
4497 }
4498 }
4499 if (avgholdsecs >= 1) {
4500 res = ast_say_number(qe->chan, avgholdsecs, AST_DIGIT_ANY, ast_channel_language(qe->chan), "n");
4501 if (res) {
4502 goto playout;
4503 }
4504
4505 res = play_file(qe->chan, qe->parent->sound_seconds);
4506 if (res) {
4507 goto playout;
4508 }
4509 }
4510 }
4511
4512posout:
4513 if (qe->parent->announceposition) {
4514 ast_verb(3, "Told %s in %s their queue position (which was %d)\n",
4515 ast_channel_name(qe->chan), qe->parent->name, qe->pos);
4516 }
4517 if (say_thanks) {
4518 res = play_file(qe->chan, qe->parent->sound_thanks);
4519 }
4520playout:
4521
4522 if ((res > 0 && !valid_exit(qe, res))) {
4523 res = 0;
4524 }
4525
4526 /* Set our last_pos indicators */
4527 qe->last_pos = now;
4528 qe->last_pos_said = qe->pos;
4529
4530 /* Don't restart music on hold if we're about to exit the caller from the queue */
4531 if (!res) {
4532 if (ringing) {
4534 } else {
4535 ast_moh_start(qe->chan, qe->moh, NULL);
4536 }
4537 }
4538 return res;
4539}
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:8240
const ast_string_field sound_thereare
Definition: app_queue.c:2001
const ast_string_field sound_holdtime
Definition: app_queue.c:2001
const ast_string_field sound_seconds
Definition: app_queue.c:2001
const ast_string_field sound_thanks
Definition: app_queue.c:2001
const ast_string_field queue_quantity2
Definition: app_queue.c:2001
const ast_string_field sound_calls
Definition: app_queue.c:2001
const ast_string_field sound_minute
Definition: app_queue.c:2001
const ast_string_field sound_minutes
Definition: app_queue.c:2001
const ast_string_field queue_quantity1
Definition: app_queue.c:2001
const ast_string_field sound_next
Definition: app_queue.c:2001

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

6324{
6325 const char *reason = NULL; /* silence dumb compilers */
6326 RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
6327
6328 switch (rsn) {
6329 case CALLER:
6330 reason = "caller";
6331 break;
6332 case AGENT:
6333 reason = "agent";
6334 break;
6335 case TRANSFER:
6336 reason = "transfer";
6337 break;
6338 }
6339
6340 blob = ast_json_pack("{s: s, s: s, s: s, s: I, s: I, s: s}",
6341 "Queue", queuename,
6342 "Interface", member->interface,
6343 "MemberName", member->membername,
6344 "HoldTime", (ast_json_int_t)(callstart - holdstart),
6345 "TalkTime", (ast_json_int_t)(time(NULL) - callstart),
6346 "Reason", reason ?: "");
6347
6349 queue_agent_complete_type(), blob);
6350}
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 8044 of file app_queue.c.

8045{
8046 int found = 0;
8047 struct call_queue *q;
8048 struct ao2_iterator queue_iter;
8049
8050 if (ast_check_realtime("queues")) {
8051 load_realtime_queues(queuename);
8052 }
8053
8054 queue_iter = ao2_iterator_init(queues, 0);
8055 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate over queues"))) {
8056 ao2_lock(q);
8057 if (ast_strlen_zero(queuename) || !strcasecmp(q->name, queuename)) {
8058 struct member *mem;
8059
8060 if ((mem = interface_exists(q, interface))) {
8061 /*
8062 * Before we do the PAUSE/UNPAUSE, log if this was a
8063 * PAUSEALL/UNPAUSEALL but only on the first found entry.
8064 */
8065 ++found;
8066 if (found == 1
8067 && ast_strlen_zero(queuename)) {
8068 /*
8069 * XXX In all other cases, we use the queue name,
8070 * but since this affects all queues, we cannot.
8071 */
8072 ast_queue_log("NONE", "NONE", mem->membername,
8073 (paused ? "PAUSEALL" : "UNPAUSEALL"), "%s", S_OR(reason, ""));
8074 }
8075
8076 set_queue_member_pause(q, mem, reason, paused);
8077 ao2_ref(mem, -1);
8078 }
8079
8080 if (!ast_strlen_zero(queuename)) {
8081 ao2_unlock(q);
8082 queue_t_unref(q, "Done with iterator");
8083 break;
8084 }
8085 }
8086
8087 ao2_unlock(q);
8088 queue_t_unref(q, "Done with iterator");
8089 }
8090 ao2_iterator_destroy(&queue_iter);
8091
8092 return found ? RESULT_SUCCESS : RESULT_FAILURE;
8093}
static void set_queue_member_pause(struct call_queue *q, struct member *mem, const char *reason, int paused)
Definition: app_queue.c:7977

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

8105{
8106 struct member *mem;
8107 int foundinterface = 0;
8108
8109 ao2_lock(q);
8110 if ((mem = interface_exists(q, interface))) {
8111 foundinterface++;
8112 if (mem->realtime) {
8113 char rtpenalty[80];
8114
8115 sprintf(rtpenalty, "%i", penalty);
8116 update_realtime_member_field(mem, q->name, "penalty", rtpenalty);
8117 }
8118
8119 mem->penalty = penalty;
8120
8121 ast_queue_log(q->name, "NONE", interface, "PENALTY", "%d", penalty);
8122 queue_publish_member_blob(queue_member_penalty_type(), queue_member_blob_create(q, mem));
8123 ao2_ref(mem, -1);
8124 }
8125 ao2_unlock(q);
8126
8127 return foundinterface;
8128}

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

8154{
8155 struct member *mem;
8156 int foundinterface = 0;
8157
8158 ao2_lock(q);
8159 if ((mem = interface_exists(q, interface))) {
8160 foundinterface++;
8162 ao2_ref(mem, -1);
8163 }
8164 ao2_unlock(q);
8165
8166 return foundinterface;
8167}
static void set_queue_member_ringinuse(struct call_queue *q, struct member *mem, int ringinuse)
Definition: app_queue.c:8140

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

8193{
8194 int foundinterface = 0, foundqueue = 0;
8195 struct call_queue *q;
8196 struct ast_config *queue_config = NULL;
8197 struct ao2_iterator queue_iter;
8198
8199 /* property dependent restrictions on values should be checked in this switch */
8200 switch (property) {
8201 case MEMBER_PENALTY:
8202 if (value < 0 && !negative_penalty_invalid) {
8203 ast_log(LOG_ERROR, "Invalid penalty (%d)\n", value);
8204 return RESULT_FAILURE;
8205 }
8206 }
8207
8208 if (ast_strlen_zero(queuename)) { /* This means we need to iterate through all the queues. */
8209 if (ast_check_realtime("queues")) {
8210 queue_config = ast_load_realtime_multientry("queues", "name LIKE", "%", SENTINEL);
8211 if (queue_config) {
8212 char *category = NULL;
8213 while ((category = ast_category_browse(queue_config, category))) {
8214 const char *name = ast_variable_retrieve(queue_config, category, "name");
8215 if (ast_strlen_zero(name)) {
8216 ast_log(LOG_WARNING, "Ignoring realtime queue with a NULL or empty 'name.'\n");
8217 continue;
8218 }
8219 if ((q = find_load_queue_rt_friendly(name))) {
8220 foundqueue++;
8221 foundinterface += set_member_value_help_members(q, interface, property, value);
8222 queue_unref(q);
8223 }
8224 }
8225
8226 ast_config_destroy(queue_config);
8227 }
8228 }
8229
8230 /* After hitting realtime queues, go back and get the regular ones. */
8231 queue_iter = ao2_iterator_init(queues, 0);
8232 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
8233 foundqueue++;
8234 foundinterface += set_member_value_help_members(q, interface, property, value);
8235 queue_unref(q);
8236 }
8237 ao2_iterator_destroy(&queue_iter);
8238 } else { /* We actually have a queuename, so we can just act on the single queue. */
8239 if ((q = find_load_queue_rt_friendly(queuename))) {
8240 foundqueue++;
8241 foundinterface += set_member_value_help_members(q, interface, property, value);
8242 queue_unref(q);
8243 }
8244 }
8245
8246 if (foundinterface) {
8247 return RESULT_SUCCESS;
8248 } else if (!foundqueue) {
8249 ast_log (LOG_ERROR, "Invalid queuename\n");
8250 } else {
8251 ast_log (LOG_ERROR, "Invalid interface\n");
8252 }
8253
8254 return RESULT_FAILURE;
8255}
static int set_member_value_help_members(struct call_queue *q, const char *interface, int property, int value)
Definition: app_queue.c:8169

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

8170{
8171 switch(property) {
8172 case MEMBER_PENALTY:
8173 return set_member_penalty_help_members(q, interface, value);
8174
8175 case MEMBER_RINGINUSE:
8176 return set_member_ringinuse_help_members(q, interface, value);
8177
8178 default:
8179 ast_log(LOG_ERROR, "Attempted to set invalid property\n");
8180 return 0;
8181 }
8182}
static int set_member_ringinuse_help_members(struct call_queue *q, const char *interface, int ringinuse)
Definition: app_queue.c:8153
static int set_member_penalty_help_members(struct call_queue *q, const char *interface, int penalty)
Definition: app_queue.c:8104

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

7978{
7979 if (mem->paused == paused) {
7980 ast_debug(1, "%spausing already-%spaused queue member %s:%s\n",
7981 (paused ? "" : "un"), (paused ? "" : "un"), q->name, mem->interface);
7982 }
7983
7984 if (mem->realtime && !ast_strlen_zero(mem->rt_uniqueid)) {
7986 if (ast_update_realtime("queue_members", "uniqueid", mem->rt_uniqueid, "reason_paused", S_OR(reason, ""), "paused", paused ? "1" : "0", SENTINEL) < 0) {
7987 ast_log(LOG_WARNING, "Failed update of realtime queue member %s:%s %spause and reason '%s'\n",
7988 q->name, mem->interface, (paused ? "" : "un"), S_OR(reason, ""));
7989 }
7990 } else {
7991 if (ast_update_realtime("queue_members", "uniqueid", mem->rt_uniqueid, "paused", paused ? "1" : "0", SENTINEL) < 0) {
7992 ast_log(LOG_WARNING, "Failed %spause update of realtime queue member %s:%s\n",
7993 (paused ? "" : "un"), q->name, mem->interface);
7994 }
7995 }
7996 }
7997
7998 mem->paused = paused;
7999 if (paused) {
8000 time(&mem->lastpause); /* update last pause field */
8001 }
8002 if (paused && !ast_strlen_zero(reason)) {
8003 ast_copy_string(mem->reason_paused, reason, sizeof(mem->reason_paused));
8004 } else {
8005 /* We end up filling this in again later (temporarily) but we need it
8006 * empty for now so that the intervening code - specifically
8007 * dump_queue_members() - has the correct view of things. */
8008 mem->reason_paused[0] = '\0';
8009 }
8010
8012 AST_DEVSTATE_CACHABLE, "Queue:%s_pause_%s", q->name, mem->interface);
8013
8016 }
8017
8018 if (is_member_available(q, mem)) {
8020 "Queue:%s_avail", q->name);
8021 } else if (!num_available_members(q)) {
8023 "Queue:%s_avail", q->name);
8024 }
8025
8026 if (!paused && !ast_strlen_zero(reason)) {
8027 /* Because we've been unpaused with a 'reason' we need to ensure that
8028 * that reason is emitted when the subsequent PauseQueueMember event
8029 * is raised. So temporarily set it on the member and clear it out
8030 * again right after. */
8031 ast_copy_string(mem->reason_paused, reason, sizeof(mem->reason_paused));
8032 }
8033
8034 ast_queue_log(q->name, "NONE", mem->membername, paused ? "PAUSE" : "UNPAUSE",
8035 "%s", mem->reason_paused);
8036
8038
8039 if (!paused) {
8040 mem->reason_paused[0] = '\0';
8041 }
8042}
static int publish_queue_member_pause(struct call_queue *q, struct member *member)
Definition: app_queue.c:7953
int ast_update_realtime(const char *family, const char *keyfield, const char *lookup,...) attribute_sentinel
Update realtime configuration.
Definition: main/config.c:3879

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

8141{
8142 if (mem->realtime) {
8144 ringinuse ? "1" : "0");
8145 }
8146
8147 mem->ringinuse = ringinuse;
8148
8149 ast_queue_log(q->name, "NONE", mem->interface, "RINGINUSE", "%d", ringinuse);
8150 queue_publish_member_blob(queue_member_ringinuse_type(), queue_member_blob_create(q, mem));
8151}

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

2083{
2084 int i;
2085
2086 for (i = 0; i < ARRAY_LEN(queue_results); i++) {
2087 if (queue_results[i].id == res) {
2088 pbx_builtin_setvar_helper(chan, "QUEUESTATUS", queue_results[i].text);
2089 return;
2090 }
2091 }
2092}
static const struct @50 queue_results[]
char * text
Definition: app_queue.c:1809

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

2236{
2237 char interfacevar[256]="";
2238 float sl = 0;
2239
2240 ao2_lock(q);
2241
2242 if (q->setqueuevar) {
2243 sl = 0;
2244 if (q->callscompleted > 0) {
2245 sl = 100 * ((float) q->callscompletedinsl / (float) q->callscompleted);
2246 }
2247
2248 snprintf(interfacevar, sizeof(interfacevar),
2249 "QUEUENAME=%s,QUEUEMAX=%d,QUEUESTRATEGY=%s,QUEUECALLS=%d,QUEUEHOLDTIME=%d,QUEUETALKTIME=%d,QUEUECOMPLETED=%d,QUEUEABANDONED=%d,QUEUESRVLEVEL=%d,QUEUESRVLEVELPERF=%2.1f",
2251
2252 ao2_unlock(q);
2253
2254 pbx_builtin_setvar_multiple(chan, interfacevar);
2255 } else {
2256 ao2_unlock(q);
2257 }
2258}

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

7098{
7099 char escaped_filename[256];
7100 char file_with_ext[sizeof(escaped_filename) + sizeof(qe->parent->monfmt)];
7101 char mixmonargs[1512];
7102 char escaped_monitor_exec[1024];
7103 const char *monitor_options;
7104 const char *monitor_exec;
7105
7106 escaped_monitor_exec[0] = '\0';
7107
7108 if (filename) {
7109 escape_and_substitute(qe->chan, filename, escaped_filename, sizeof(escaped_filename));
7110 } else {
7111 ast_copy_string(escaped_filename, ast_channel_uniqueid(qe->chan), sizeof(escaped_filename));
7112 }
7113
7115 if ((monitor_exec = pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC"))) {
7116 monitor_exec = ast_strdupa(monitor_exec);
7117 }
7118 if ((monitor_options = pbx_builtin_getvar_helper(qe->chan, "MONITOR_OPTIONS"))) {
7119 monitor_options = ast_strdupa(monitor_options);
7120 } else {
7121 monitor_options = "";
7122 }
7124
7125 if (monitor_exec) {
7126 escape_and_substitute(qe->chan, monitor_exec, escaped_monitor_exec, sizeof(escaped_monitor_exec));
7127 }
7128
7129 snprintf(file_with_ext, sizeof(file_with_ext), "%s.%s", escaped_filename, qe->parent->monfmt);
7130
7131 if (!ast_strlen_zero(escaped_monitor_exec)) {
7132 snprintf(mixmonargs, sizeof(mixmonargs), "b%s,%s", monitor_options, escaped_monitor_exec);
7133 } else {
7134 snprintf(mixmonargs, sizeof(mixmonargs), "b%s", monitor_options);
7135 }
7136
7137 ast_debug(1, "Arguments being passed to MixMonitor: %s,%s\n", file_with_ext, mixmonargs);
7138
7139 if (ast_start_mixmonitor(qe->chan, file_with_ext, mixmonargs)) {
7140 ast_log(LOG_WARNING, "Unable to start mixmonitor. Is the MixMonitor app loaded?\n");
7141 }
7142}
static void escape_and_substitute(struct ast_channel *chan, const char *input, char *output, size_t size)
Definition: app_queue.c:7066
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 7049 of file app_queue.c.

7050{
7051 const char *context;
7052 const char *extension;
7053 int priority;
7054
7055 if (ast_test_flag(opts, OPT_CALLEE_GO_ON)) {
7056 ast_channel_lock(chan);
7060 ast_channel_unlock(chan);
7062 opt_args[OPT_ARG_CALLEE_GO_ON]);
7063 }
7064}
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 6965 of file app_queue.c.

6967{
6968 struct queue_stasis_data *queue_data = queue_stasis_data_alloc(qe, peer, mem, holdstart, starttime, callcompletedinsl);
6969
6970 if (!queue_data) {
6971 return -1;
6972 }
6973
6975 if (!queue_data->bridge_router) {
6976 ao2_ref(queue_data, -1);
6977 return -1;
6978 }
6979
6981 handle_bridge_enter, queue_data);
6983 handle_blind_transfer, queue_data);
6985 handle_attended_transfer, queue_data);
6987 queue_bridge_cb, queue_data);
6988
6990 if (!queue_data->channel_router) {
6991 /* Unsubscribing from the bridge router will remove the only ref of queue_data,
6992 * thus beginning the destruction process
6993 */
6995 queue_data->bridge_router = NULL;
6996 return -1;
6997 }
6998
6999 ao2_ref(queue_data, +1);
7003 handle_local_optimization_end, queue_data);
7005 handle_hangup, queue_data);
7007 handle_masquerade, queue_data);
7009 queue_channel_cb, queue_data);
7010
7011 return 0;
7012}
static void handle_bridge_enter(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Definition: app_queue.c:6568
static void queue_bridge_cb(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Definition: app_queue.c:6715
static void handle_attended_transfer(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Handle an attended transfer event.
Definition: app_queue.c:6660
static void handle_masquerade(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Definition: app_queue.c:6906
static void handle_local_optimization_begin(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Definition: app_queue.c:6734
static void handle_local_optimization_end(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Definition: app_queue.c:6785
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:6483
static void queue_channel_cb(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Definition: app_queue.c:6940
static void handle_hangup(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Definition: app_queue.c:6849
static void handle_blind_transfer(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Handle a blind transfer event.
Definition: app_queue.c:6601
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 5186 of file app_queue.c.

5187{
5188 struct callattempt *best = find_best(outgoing);
5189
5190 if (best) {
5191 /* Ring just the best channel */
5192 ast_debug(1, "Next is '%s' with metric %d\n", best->interface, best->metric);
5193 qe->linpos = best->metric % 1000;
5194 } else {
5195 /* Just increment rrpos */
5196 if (qe->linwrapped) {
5197 /* No more channels, start over */
5198 qe->linpos = 0;
5199 } else {
5200 /* Prioritize next entry */
5201 qe->linpos++;
5202 }
5203 }
5204 qe->linwrapped = 0;
5205
5206 return 0;
5207}

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

5163{
5164 struct callattempt *best = find_best(outgoing);
5165
5166 if (best) {
5167 /* Ring just the best channel */
5168 ast_debug(1, "Next is '%s' with metric %d\n", best->interface, best->metric);
5169 qe->parent->rrpos = best->metric % 1000;
5170 } else {
5171 /* Just increment rrpos */
5172 if (qe->parent->wrapped) {
5173 /* No more channels, start over */
5174 qe->parent->rrpos = 0;
5175 } else {
5176 /* Prioritize next entry */
5177 qe->parent->rrpos++;
5178 }
5179 }
5180 qe->parent->wrapped = 0;
5181
5182 return 0;
5183}

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

2108{
2109 int x;
2110
2111 for (x = 0; x < ARRAY_LEN(strategies); x++) {
2112 if (!strcasecmp(strategy, strategies[x].name)) {
2113 return strategies[x].strategy;
2114 }
2115 }
2116
2117 return -1;
2118}
int strategy
Definition: app_queue.c:1697

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

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

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

11951{
11954
11956
11957 STASIS_MESSAGE_TYPE_CLEANUP(queue_caller_join_type);
11958 STASIS_MESSAGE_TYPE_CLEANUP(queue_caller_leave_type);
11959 STASIS_MESSAGE_TYPE_CLEANUP(queue_caller_abandon_type);
11960
11961 STASIS_MESSAGE_TYPE_CLEANUP(queue_member_status_type);
11962 STASIS_MESSAGE_TYPE_CLEANUP(queue_member_added_type);
11963 STASIS_MESSAGE_TYPE_CLEANUP(queue_member_removed_type);
11964 STASIS_MESSAGE_TYPE_CLEANUP(queue_member_pause_type);
11965 STASIS_MESSAGE_TYPE_CLEANUP(queue_member_penalty_type);
11966 STASIS_MESSAGE_TYPE_CLEANUP(queue_member_ringinuse_type);
11967
11968 STASIS_MESSAGE_TYPE_CLEANUP(queue_agent_called_type);
11969 STASIS_MESSAGE_TYPE_CLEANUP(queue_agent_connect_type);
11970 STASIS_MESSAGE_TYPE_CLEANUP(queue_agent_complete_type);
11971 STASIS_MESSAGE_TYPE_CLEANUP(queue_agent_dump_type);
11972 STASIS_MESSAGE_TYPE_CLEANUP(queue_agent_ringnoanswer_type);
11973
11975 ast_manager_unregister("QueueStatus");
11976 ast_manager_unregister("QueueRule");
11977 ast_manager_unregister("QueueSummary");
11978 ast_manager_unregister("QueueAdd");
11979 ast_manager_unregister("QueueRemove");
11980 ast_manager_unregister("QueuePause");
11981 ast_manager_unregister("QueueLog");
11982 ast_manager_unregister("QueueUpdate");
11983 ast_manager_unregister("QueuePenalty");
11984 ast_manager_unregister("QueueReload");
11985 ast_manager_unregister("QueueReset");
11986 ast_manager_unregister("QueueMemberRingInUse");
11987 ast_manager_unregister("QueueChangePriorityCaller");
11988 ast_manager_unregister("QueueWithdrawCaller");
12004
12006
12007 ast_unload_realtime("queue_members");
12010
12011 queues = NULL;
12012 return 0;
12013}
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:7699
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_dep, queuemembercount_function, queuememberlist_function, queuememberpenalty_function, queues, queuevar_function, queuewaitingcount_function, stasis_forward_cancel(), stasis_message_router_unsubscribe_and_join(), STASIS_MESSAGE_TYPE_CLEANUP, stasis_unsubscribe_and_join(), and topic_forwarder.

Referenced by load_module().

◆ update_connected_line_from_peer()

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

Definition at line 5367 of file app_queue.c.

5368{
5369 struct ast_party_connected_line connected_caller;
5370
5371 ast_party_connected_line_init(&connected_caller);
5372
5373 ast_channel_lock(peer);
5375 ast_channel_unlock(peer);
5376 connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
5377 if (ast_channel_connected_line_sub(peer, chan, &connected_caller, 0)) {
5378 ast_channel_update_connected_line(chan, &connected_caller, NULL);
5379 }
5380 ast_party_connected_line_free(&connected_caller);
5381}
@ 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:10343
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:9098
void ast_party_connected_line_init(struct ast_party_connected_line *init)
Initialize the given connected line structure.
Definition: channel.c:1989
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 5986 of file app_queue.c.

5987{
5988 int max_penalty = INT_MAX;
5989
5990 if (qe->max_penalty != INT_MAX) {
5991 char max_penalty_str[20];
5992
5993 if (qe->pr->max_relative) {
5994 max_penalty = qe->max_penalty + qe->pr->max_value;
5995 } else {
5996 max_penalty = qe->pr->max_value;
5997 }
5998
5999 /* a relative change to the penalty could put it below 0 */
6000 if (max_penalty < 0) {
6001 max_penalty = 0;
6002 }
6003
6004 snprintf(max_penalty_str, sizeof(max_penalty_str), "%d", max_penalty);
6005 pbx_builtin_setvar_helper(qe->chan, "QUEUE_MAX_PENALTY", max_penalty_str);
6006 qe->max_penalty = max_penalty;
6007 ast_debug(3, "Setting max penalty to %d for caller %s since %d seconds have elapsed\n",
6008 qe->max_penalty, ast_channel_name(qe->chan), qe->pr->time);
6009 }
6010
6011 if (qe->min_penalty != INT_MAX) {
6012 char min_penalty_str[20];
6013 int min_penalty;
6014
6015 if (qe->pr->min_relative) {
6016 min_penalty = qe->min_penalty + qe->pr->min_value;
6017 } else {
6018 min_penalty = qe->pr->min_value;
6019 }
6020
6021 /* a relative change to the penalty could put it below 0 */
6022 if (min_penalty < 0) {
6023 min_penalty = 0;
6024 }
6025
6026 if (max_penalty != INT_MAX && min_penalty > max_penalty) {
6027 min_penalty = max_penalty;
6028 }
6029
6030 snprintf(min_penalty_str, sizeof(min_penalty_str), "%d", min_penalty);
6031 pbx_builtin_setvar_helper(qe->chan, "QUEUE_MIN_PENALTY", min_penalty_str);
6032 qe->min_penalty = min_penalty;
6033 ast_debug(3, "Setting min penalty to %d for caller %s since %d seconds have elapsed\n",
6034 qe->min_penalty, ast_channel_name(qe->chan), qe->pr->time);
6035 }
6036
6037 if (qe->raise_penalty != INT_MAX) {
6038 char raise_penalty_str[20];
6039 int raise_penalty;
6040
6041 if (qe->pr->raise_relative) {
6042 raise_penalty = qe->raise_penalty + qe->pr->raise_value;
6043 } else {
6044 raise_penalty = qe->pr->raise_value;
6045 }
6046
6047 /* a relative change to the penalty could put it below 0 */
6048 if (raise_penalty < 0) {
6049 raise_penalty = 0;
6050 }
6051
6052 if (max_penalty != INT_MAX && raise_penalty > max_penalty) {
6053 raise_penalty = max_penalty;
6054 }
6055
6056 snprintf(raise_penalty_str, sizeof(raise_penalty_str), "%d", raise_penalty);
6057 pbx_builtin_setvar_helper(qe->chan, "QUEUE_RAISE_PENALTY", raise_penalty_str);
6058 qe->raise_penalty = raise_penalty;
6059 ast_debug(3, "Setting raised penalty to %d for caller %s since %d seconds have elapsed\n",
6060 qe->raise_penalty, ast_channel_name(qe->chan), qe->pr->time);
6061 }
6062
6063 qe->pr = AST_LIST_NEXT(qe->pr, list);
6064}
#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 6164 of file app_queue.c.

6165{
6166 int oldtalktime;
6167 int newtalktime = time(NULL) - starttime;
6168 struct member *mem;
6169 struct call_queue *qtmp;
6170 struct ao2_iterator queue_iter;
6171
6172 /* It is possible for us to be called when a call has already been considered terminated
6173 * and data updated, so to ensure we only act on the call that the agent is currently in
6174 * we check when the call was bridged.
6175 */
6176 if (!starttime || (member->starttime != starttime)) {
6177 return 0;
6178 }
6179
6180 if (shared_lastcall) {
6181 queue_iter = ao2_iterator_init(queues, 0);
6182 while ((qtmp = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
6183 ao2_lock(qtmp);
6184 if ((mem = ao2_find(qtmp->members, member, OBJ_POINTER))) {
6185 time(&mem->lastcall);
6186 mem->calls++;
6187 mem->callcompletedinsl = 0;
6188 mem->starttime = 0;
6189 mem->lastqueue = q;
6190 ao2_ref(mem, -1);
6191 }
6192 ao2_unlock(qtmp);
6193 queue_t_unref(qtmp, "Done with iterator");
6194 }
6195 ao2_iterator_destroy(&queue_iter);
6196 } else {
6197 ao2_lock(q);
6198 time(&member->lastcall);
6200 member->calls++;
6201 member->starttime = 0;
6202 member->lastqueue = q;
6203 ao2_unlock(q);
6204 }
6205 /* Member might never experience any direct status change (local
6206 * channel with forwarding in particular). If that's the case,
6207 * this is the last chance to remove it from pending or subsequent
6208 * calls will not occur.
6209 */
6211
6212 ao2_lock(q);
6213 q->callscompleted++;
6214 if (callcompletedinsl) {
6215 q->callscompletedinsl++;
6216 }
6217 if (q->callscompleted == 1) {
6218 q->talktime = newtalktime;
6219 } else {
6220 /* Calculate talktime using the same exponential average as holdtime code */
6221 oldtalktime = q->talktime;
6222 q->talktime = (((oldtalktime << 2) - oldtalktime) + newtalktime) >> 2;
6223 }
6224 ao2_unlock(q);
6225 return 0;
6226}

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

4177{
4178 int ret = -1;
4179
4180 if (ast_strlen_zero(mem->rt_uniqueid)) {
4181 return ret;
4182 }
4183
4184 if ((ast_update_realtime("queue_members", "uniqueid", mem->rt_uniqueid, field, value, SENTINEL)) >= 0) {
4185 ret = 0;
4186 }
4187
4188 return ret;
4189}

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

4193{
4194 struct ast_config *member_config = NULL;
4195 struct member *m;
4196 char *category = NULL;
4197 struct ao2_iterator mem_iter;
4198
4199 if (!(member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name", q->name , SENTINEL))) {
4200 /* This queue doesn't have realtime members. If the queue still has any realtime
4201 * members in memory, they need to be removed.
4202 */
4203 ao2_lock(q);
4204 mem_iter = ao2_iterator_init(q->members, 0);
4205 while ((m = ao2_iterator_next(&mem_iter))) {
4206 if (m->realtime) {
4208 }
4209 ao2_ref(m, -1);
4210 }
4211 ao2_iterator_destroy(&mem_iter);
4212 ast_debug(3, "Queue %s has no realtime members defined. No need for update\n", q->name);
4213 ao2_unlock(q);
4214 return;
4215 }
4216
4217 ao2_lock(q);
4218
4219 /* Temporarily set realtime members dead so we can detect deleted ones.*/
4220 mem_iter = ao2_iterator_init(q->members, 0);
4221 while ((m = ao2_iterator_next(&mem_iter))) {
4222 if (m->realtime) {
4223 m->dead = 1;
4224 }
4225 ao2_ref(m, -1);
4226 }
4227 ao2_iterator_destroy(&mem_iter);
4228
4229 while ((category = ast_category_browse(member_config, category))) {
4230 rt_handle_member_record(q, category, member_config);
4231 }
4232
4233 /* Delete all realtime members that have been deleted in DB. */
4234 mem_iter = ao2_iterator_init(q->members, 0);
4235 while ((m = ao2_iterator_next(&mem_iter))) {
4236 if (m->dead) {
4238 ast_queue_log(q->name, "REALTIME", m->interface, "REMOVEMEMBER", "%s", "");
4239 } else {
4240 ast_queue_log(q->name, "REALTIME", m->membername, "REMOVEMEMBER", "%s", "");
4241 }
4243 }
4244 ao2_ref(m, -1);
4245 }
4246 ao2_iterator_destroy(&mem_iter);
4247 ao2_unlock(q);
4248 ast_config_destroy(member_config);
4249}

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

2753{
2754 if (m->status != status) {
2755 /* If this member has transitioned to being available then update their queue
2756 * information. If they are currently in a call then the leg to the agent will be
2757 * considered done and the call finished.
2758 */
2761 }
2762
2763 m->status = status;
2764
2765 /* Remove the member from the pending members pool only when the status changes.
2766 * This is not done unconditionally because we can occasionally see multiple
2767 * device state notifications of not in use after a previous call has ended,
2768 * including after we have initiated a new call. This is more likely to
2769 * happen when there is latency in the connection to the member.
2770 */
2772
2773 queue_publish_member_blob(queue_member_status_type(), queue_member_blob_create(q, m));
2774 }
2775}

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

8440{
8441 char *parse;
8443 AST_APP_ARG(queuename);
8444 AST_APP_ARG(interface);
8446 AST_APP_ARG(reason);
8447 );
8448
8449 if (ast_strlen_zero(data)) {
8450 ast_log(LOG_WARNING, "UnpauseQueueMember requires an argument ([queuename],interface[,options[,reason]])\n");
8451 return -1;
8452 }
8453
8454 parse = ast_strdupa(data);
8455
8457
8458 if (ast_strlen_zero(args.interface)) {
8459 ast_log(LOG_WARNING, "Missing interface argument to UnpauseQueueMember ([queuename],interface[,options[,reason]])\n");
8460 return -1;
8461 }
8462
8463 if (set_member_paused(args.queuename, args.interface, args.reason, 0)) {
8464 ast_log(LOG_WARNING, "Attempt to unpause interface %s, not found\n", args.interface);
8465 pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "NOTFOUND");
8466 return 0;
8467 }
8468
8469 pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "UNPAUSED");
8470
8471 return 0;
8472}

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

4365{
4366 int digitlen = strlen(qe->digits);
4367
4368 /* Prevent possible buffer overflow */
4369 if (digitlen < sizeof(qe->digits) - 2) {
4370 qe->digits[digitlen] = digit;
4371 qe->digits[digitlen + 1] = '\0';
4372 } else {
4373 qe->digits[0] = '\0';
4374 return 0;
4375 }
4376
4377 /* If there's no context to goto, short-circuit */
4378 if (ast_strlen_zero(qe->context)) {
4379 return 0;
4380 }
4381
4382 /* If the extension is bad, then reset the digits to blank */
4383 if (!ast_canmatch_extension(qe->chan, qe->context, qe->digits, 1,
4385 qe->digits[0] = '\0';
4386 return 0;
4387 }
4388
4389 /* We have an exact match */
4390 if (!ast_goto_if_exists(qe->chan, qe->context, qe->digits, 1)) {
4391 qe->valid_digits = 1;
4392 /* Return 1 on a successful goto */
4393 return 1;
4394 }
4395
4396 return 0;
4397}
int ast_goto_if_exists(struct ast_channel *chan, const char *context, const char *exten, int priority)
Definition: pbx.c:8796
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:4205

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

7638{
7639 /* Don't need to hold the lock while we setup the outgoing calls */
7640 int retrywait = qe->parent->retry * 1000;
7641
7642 int res = ast_waitfordigit(qe->chan, retrywait);
7643 if (res > 0 && !valid_exit(qe, res)) {
7644 res = 0;
7645 }
7646
7647 return res;
7648}
int ast_waitfordigit(struct ast_channel *c, int ms)
Waits for a digit.
Definition: channel.c:3143

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

5398{
5399 const char *queue = qe->parent->name;
5400 struct callattempt *o, *start = NULL, *prev = NULL;
5401 int status;
5402 int numbusies = prebusies;
5403 int numnochan = 0;
5404 int stillgoing = 0;
5405 int orig = *to;
5406 struct ast_frame *f;
5407 struct callattempt *peer = NULL;
5408 struct ast_channel *winner;
5409 struct ast_channel *in = qe->chan;
5410 char on[80] = "";
5411 char membername[80] = "";
5412 long starttime = 0;
5413 long endtime = 0;
5414 char *inchan_name;
5415 struct timeval start_time_tv = ast_tvnow();
5416 int canceled_by_caller = 0; /* 1 when caller hangs up or press digit or press * */
5417
5419 inchan_name = ast_strdupa(ast_channel_name(qe->chan));
5421
5422 starttime = (long) time(NULL);
5423
5424 while ((*to = ast_remaining_ms(start_time_tv, orig)) && !peer) {
5425 int numlines, retry, pos = 1;
5426 struct ast_channel *watchers[AST_MAX_WATCHERS];
5427 watchers[0] = in;
5428 start = NULL;
5429
5430 for (retry = 0; retry < 2; retry++) {
5431 numlines = 0;
5432 for (o = outgoing; o; o = o->q_next) { /* Keep track of important channels */
5433 if (o->stillgoing) { /* Keep track of important channels */
5434 stillgoing = 1;
5435 if (o->chan) {
5436 if (pos < AST_MAX_WATCHERS) {
5437 watchers[pos++] = o->chan;
5438 }
5439 if (!start) {
5440 start = o;
5441 } else {
5442 prev->call_next = o;
5443 }
5444 prev = o;
5445 }
5446 } else if (prev) {
5447 prev->call_next = NULL;
5448 }
5449 numlines++;
5450 }
5451 if (pos > 1 /* found */ || !stillgoing /* nobody listening */ ||
5452 (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) /* ring would not be delivered */) {
5453 break;
5454 }
5455 /* On "ringall" strategy we only move to the next penalty level
5456 when *all* ringing phones are done in the current penalty level */
5457 ring_one(qe, outgoing, &numbusies);
5458 /* and retry... */
5459 }
5460 if (pos == 1 /* not found */) {
5461 if (numlines == (numbusies + numnochan)) {
5462 ast_debug(1, "Everyone is busy at this time\n");
5463 } else {
5464 ast_debug(3, "No one is answering queue '%s' (%d numlines / %d busies / %d failed channels)\n", queue, numlines, numbusies, numnochan);
5465 }
5466 *to = 0;
5467 return NULL;
5468 }
5469
5470 /* Poll for events from both the incoming channel as well as any outgoing channels */
5471 winner = ast_waitfor_n(watchers, pos, to);
5472
5473 /* Service all of the outgoing channels */
5474 for (o = start; o; o = o->call_next) {
5475 /* We go with a fixed buffer here instead of using ast_strdupa. Using
5476 * ast_strdupa in a loop like this one can cause a stack overflow
5477 */
5478 char ochan_name[AST_CHANNEL_NAME];
5479
5480 if (o->chan) {
5482 ast_copy_string(ochan_name, ast_channel_name(o->chan), sizeof(ochan_name));
5484 }
5485 if (o->stillgoing && (o->chan) && (ast_channel_state(o->chan) == AST_STATE_UP)) {
5486 if (!peer) {
5487 ast_verb(3, "%s answered %s\n", ochan_name, inchan_name);
5488 if (o->orig_chan_name
5489 && strcmp(o->orig_chan_name, ochan_name)) {
5490 /*
5491 * The channel name changed so we must generate COLP update.
5492 * Likely because a call pickup channel masqueraded in.
5493 */
5495 } else if (!o->block_connected_update) {
5496 if (o->pending_connected_update) {
5499 }
5500 } else if (!o->dial_callerid_absent) {
5502 }
5503 }
5504 if (o->aoc_s_rate_list) {
5505 size_t encoded_size;
5506 struct ast_aoc_encoded *encoded;
5507 if ((encoded = ast_aoc_encode(o->aoc_s_rate_list, &encoded_size, o->chan))) {
5508 ast_indicate_data(in, AST_CONTROL_AOC, encoded, encoded_size);
5509 ast_aoc_destroy_encoded(encoded);
5510 }
5511 }
5512 peer = o;
5513 }
5514 } else if (o->chan && (o->chan == winner)) {
5515
5516 ast_copy_string(on, o->member->interface, sizeof(on));
5517 ast_copy_string(membername, o->member->membername, sizeof(membername));
5518
5519 /* Before processing channel, go ahead and check for forwarding */
5520 if (!ast_strlen_zero(ast_channel_call_forward(o->chan)) && !forwardsallowed) {
5521 ast_verb(3, "Forwarding %s to '%s' prevented.\n", inchan_name, ast_channel_call_forward(o->chan));
5523 "CANCEL", ast_channel_call_forward(o->chan));
5524 numnochan++;
5525 do_hang(o);
5526 winner = NULL;
5527 continue;
5529 struct ast_channel *original = o->chan;
5530 char forwarder[AST_CHANNEL_NAME];
5531 char tmpchan[256];
5532 char *stuff;
5533 char *tech;
5534 int failed = 0;
5535
5536 ast_copy_string(tmpchan, ast_channel_call_forward(o->chan), sizeof(tmpchan));
5537 ast_copy_string(forwarder, ast_channel_name(o->chan), sizeof(forwarder));
5538 if ((stuff = strchr(tmpchan, '/'))) {
5539 *stuff++ = '\0';
5540 tech = tmpchan;
5541 } else {
5542 const char *forward_context;
5544 forward_context = pbx_builtin_getvar_helper(o->chan, "FORWARD_CONTEXT");
5545 snprintf(tmpchan, sizeof(tmpchan), "%s@%s", ast_channel_call_forward(o->chan), forward_context ? forward_context : ast_channel_context(o->chan));
5547 stuff = tmpchan;
5548 tech = "Local";
5549 }
5550 if (!strcasecmp(tech, "Local")) {
5551 /*
5552 * Drop the connected line update block for local channels since
5553 * this is going to run dialplan and the user can change his
5554 * mind about what connected line information he wants to send.
5555 */
5557 }
5558
5559 ast_verb(3, "Now forwarding %s to '%s/%s' (thanks to %s)\n", inchan_name, tech, stuff, ochan_name);
5560 /* Setup parameters */
5562 if (!o->chan) {
5564 "Forwarding failed to create channel to dial '%s/%s'\n",
5565 tech, stuff);
5566 o->stillgoing = 0;
5567 numnochan++;
5568 } else {
5569 ast_channel_lock_both(o->chan, original);
5571 ast_channel_redirecting(original));
5573 ast_channel_unlock(original);
5574
5578 pbx_builtin_setvar_helper(o->chan, "FORWARDERNAME", forwarder);
5580
5581 if (o->pending_connected_update) {
5582 /*
5583 * Re-seed the callattempt's connected line information with
5584 * previously acquired connected line info from the queued
5585 * channel. The previously acquired connected line info could
5586 * have been set through the CONNECTED_LINE dialplan function.
5587 */
5590 }
5591
5594
5596
5599 /*
5600 * The call was not previously redirected so it is
5601 * now redirected from this number.
5602 */
5608 }
5609
5611
5616
5619 && !o->block_connected_update) {
5620 struct ast_party_redirecting redirecting;
5621
5622 /*
5623 * Redirecting updates to the caller make sense only on single
5624 * call at a time strategies.
5625 *
5626 * Need to re-evaluate if calling unlock is still required as we no longer
5627 * use macro.
5628 */
5629 ast_party_redirecting_init(&redirecting);
5632 if (ast_channel_redirecting_sub(o->chan, in, &redirecting, 0)) {
5633 ast_channel_update_redirecting(in, &redirecting, NULL);
5634 }
5635 ast_party_redirecting_free(&redirecting);
5636 } else {
5638 }
5639
5640 if (ast_call(o->chan, stuff, 0)) {
5641 ast_log(LOG_NOTICE, "Forwarding failed to dial '%s/%s'\n",
5642 tech, stuff);
5643 failed = 1;
5644 }
5645 }
5646
5648 "CANCEL", ast_channel_call_forward(original));
5649 if (o->chan) {
5650 ast_channel_publish_dial(qe->chan, o->chan, stuff, NULL);
5651 }
5652
5653 if (failed) {
5654 do_hang(o);
5655 numnochan++;
5656 }
5657
5658 /* Hangup the original channel now, in case we needed it */
5659 ast_hangup(winner);
5660 continue;
5661 }
5662 f = ast_read(winner);
5663 if (f) {
5664 if (f->frametype == AST_FRAME_CONTROL) {
5665 switch (f->subclass.integer) {
5666 case AST_CONTROL_ANSWER:
5667 /* This is our guy if someone answered. */
5668 if (!peer) {
5669 ast_verb(3, "%s answered %s\n", ochan_name, inchan_name);
5670 ast_channel_publish_dial(qe->chan, o->chan, on, "ANSWER");
5671 publish_dial_end_event(qe->chan, outgoing, o->chan, "CANCEL");
5672 if (o->orig_chan_name
5673 && strcmp(o->orig_chan_name, ochan_name)) {
5674 /*
5675 * The channel name changed so we must generate COLP update.
5676 * Likely because a call pickup channel masqueraded in.
5677 */
5679 } else if (!o->block_connected_update) {
5680 if (o->pending_connected_update) {
5683 }
5684 } else if (!o->dial_callerid_absent) {
5686 }
5687 }
5688 if (o->aoc_s_rate_list) {
5689 size_t encoded_size;
5690 struct ast_aoc_encoded *encoded;
5691 if ((encoded = ast_aoc_encode(o->aoc_s_rate_list, &encoded_size, o->chan))) {
5692 ast_indicate_data(in, AST_CONTROL_AOC, encoded, encoded_size);
5693 ast_aoc_destroy_encoded(encoded);
5694 }
5695 }
5696 peer = o;
5697 }
5698 break;
5699 case AST_CONTROL_BUSY:
5700 ast_verb(3, "%s is busy\n", ochan_name);
5701 ast_channel_publish_dial(qe->chan, o->chan, on, "BUSY");
5702 endtime = (long) time(NULL);
5703 endtime -= starttime;
5704 rna(endtime * 1000, qe, o->chan, on, membername, qe->parent->autopausebusy);
5705 do_hang(o);
5707 if (qe->parent->timeoutrestart) {
5708 start_time_tv = ast_tvnow();
5709 }
5710 /* Have enough time for a queue member to answer? */
5711 if (ast_remaining_ms(start_time_tv, orig) > 500) {
5712 ring_one(qe, outgoing, &numbusies);
5713 starttime = (long) time(NULL);
5714 }
5715 }
5716 numbusies++;
5717 break;
5719 ast_verb(3, "%s is circuit-busy\n", ochan_name);
5720 ast_channel_publish_dial(qe->chan, o->chan, on, "CONGESTION");
5721 endtime = (long) time(NULL);
5722 endtime -= starttime;
5723 rna(endtime * 1000, qe, o->chan, on, membername, qe->parent->autopauseunavail);
5724 do_hang(o);
5726 if (qe->parent->timeoutrestart) {
5727 start_time_tv = ast_tvnow();
5728 }
5729 if (ast_remaining_ms(start_time_tv, orig) > 500) {
5730 ring_one(qe, outgoing, &numbusies);
5731 starttime = (long) time(NULL);
5732 }
5733 }
5734 numbusies++;
5735 break;
5737 ast_verb(3, "%s is ringing\n", ochan_name);
5738
5739 ast_channel_publish_dial(qe->chan, o->chan, on, "RINGING");
5740
5741 /* Start ring indication when the channel is ringing, if specified */
5742 if (qe->ring_when_ringing) {
5743 ast_moh_stop(qe->chan);
5745 }
5746 break;
5748 /* Ignore going off hook */
5749 break;
5751 if (o->block_connected_update) {
5752 ast_verb(3, "Connected line update to %s prevented.\n", inchan_name);
5753 break;
5754 }
5757
5758 ast_verb(3, "%s connected line has changed. Saving it until answer for %s\n", ochan_name, inchan_name);
5764 break;
5765 }
5766
5767 /*
5768 * Prevent using the CallerID from the outgoing channel since we
5769 * got a connected line update from it.
5770 */
5771 o->dial_callerid_absent = 1;
5772
5773 if (ast_channel_connected_line_sub(o->chan, in, f, 1)) {
5775 }
5776 break;
5777 case AST_CONTROL_AOC:
5778 {
5779 struct ast_aoc_decoded *decoded = ast_aoc_decode(f->data.ptr, f->datalen, o->chan);
5780 if (decoded && (ast_aoc_get_msg_type(decoded) == AST_AOC_S)) {
5782 o->aoc_s_rate_list = decoded;
5783 } else {
5784 ast_aoc_destroy_decoded(decoded);
5785 }
5786 }
5787 break;
5790 /*
5791 * Redirecting updates to the caller make sense only on single
5792 * call at a time strategies.
5793 */
5794 break;
5795 }
5796 if (o->block_connected_update) {
5797 ast_verb(3, "Redirecting update to %s prevented\n",
5798 inchan_name);
5799 break;
5800 }
5801 ast_verb(3, "%s redirecting info has changed, passing it to %s\n",
5802 ochan_name, inchan_name);
5803 if (ast_channel_redirecting_sub(o->chan, in, f, 1)) {
5805 }
5806 break;
5809 break;
5810 default:
5811 ast_debug(1, "Dunno what to do with control type %d\n", f->subclass.integer);
5812 break;
5813 }
5814 }
5815 ast_frfree(f);
5816 } else { /* ast_read() returned NULL */
5817 endtime = (long) time(NULL) - starttime;
5818 ast_channel_publish_dial(qe->chan, o->chan, on, "NOANSWER");
5819 rna(endtime * 1000, qe, o->chan, on, membername, 1);
5820 do_hang(o);
5822 if (qe->parent->timeoutrestart) {
5823 start_time_tv = ast_tvnow();
5824 }
5825 if (ast_remaining_ms(start_time_tv, orig) > 500) {
5826 ring_one(qe, outgoing, &numbusies);
5827 starttime = (long) time(NULL);
5828 }
5829 }
5830 }
5831 }
5832 }
5833
5834 /* If we received an event from the caller, deal with it. */
5835 if (winner == in) {
5836 f = ast_read(in);
5837 if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass.integer == AST_CONTROL_HANGUP))) {
5838 /* Got hung up */
5839 *to = -1;
5840 if (f) {
5841 if (f->data.uint32) {
5843 }
5844 ast_frfree(f);
5845 }
5846 canceled_by_caller = 1;
5847 } else if ((f->frametype == AST_FRAME_DTMF) && caller_disconnect && (f->subclass.integer == '*')) {
5848 ast_verb(3, "User hit %c to disconnect call.\n", f->subclass.integer);
5849 *to = 0;
5850 ast_frfree(f);
5851 canceled_by_caller = 1;
5852 } else if ((f->frametype == AST_FRAME_DTMF) && valid_exit(qe, f->subclass.integer)) {
5853 ast_verb(3, "User pressed digit: %c\n", f->subclass.integer);
5854 *to = 0;
5855 *digit = f->subclass.integer;
5856 ast_frfree(f);
5857 canceled_by_caller = 1;
5858 }
5859 /* When caller hung up or pressed * or digit. */
5860 if (canceled_by_caller) {
5862 for (o = start; o; o = o->call_next) {
5863 if (o->chan) {
5864 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));
5865 }
5866 }
5867 return NULL;
5868 }
5869
5870 /* Send the frame from the in channel to all outgoing channels. */
5871 for (o = start; o; o = o->call_next) {
5872 if (!o->stillgoing || !o->chan) {
5873 /* This outgoing channel has died so don't send the frame to it. */
5874 continue;
5875 }
5876 switch (f->frametype) {
5877 case AST_FRAME_CONTROL:
5878 switch (f->subclass.integer) {
5880 if (o->block_connected_update) {
5881 ast_verb(3, "Connected line update to %s prevented.\n", ast_channel_name(o->chan));
5882 break;
5883 }
5884 if (ast_channel_connected_line_sub(in, o->chan, f, 1)) {
5886 }
5887 break;
5889 if (o->block_connected_update) {
5890 ast_verb(3, "Redirecting update to %s prevented.\n", ast_channel_name(o->chan));
5891 break;
5892 }
5893 if (ast_channel_redirecting_sub(in, o->chan, f, 1)) {
5895 }
5896 break;
5897 default:
5898 /* We are not going to do anything with this frame. */
5899 goto skip_frame;
5900 }
5901 break;
5902 default:
5903 /* We are not going to do anything with this frame. */
5904 goto skip_frame;
5905 }
5906 }
5907skip_frame:;
5908
5909 ast_frfree(f);
5910 }
5911 }
5912
5913 if (!*to) {
5914 for (o = start; o; o = o->call_next) {
5915 if (o->chan) {
5916 rna(orig, qe, o->chan, o->interface, o->member->membername, 1);
5917 }
5918 }
5919
5920 publish_dial_end_event(qe->chan, outgoing, NULL, "NOANSWER");
5921 }
5922
5923 return peer;
5924}
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:5383
static void update_connected_line_from_peer(struct ast_channel *chan, struct ast_channel *peer, int is_caller)
Definition: app_queue.c:5367
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:5302
void ast_party_redirecting_init(struct ast_party_redirecting *init)
Initialize the given redirecting structure.
Definition: channel.c:2089
void ast_party_number_init(struct ast_party_number *init)
Initialize the given number structure.
Definition: channel.c:1611
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:3125
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:2021
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:6393
struct ast_frame * ast_read(struct ast_channel *chan)
Reads a frame.
Definition: channel.c:4214
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:10388
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:8790
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:4612
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:10289
#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:1658
void ast_party_redirecting_free(struct ast_party_redirecting *doomed)
Destroy the redirecting information contents.
Definition: channel.c:2146
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:2012
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.
union ast_frame::@228 data
struct ast_frame_subclass subclass
enum ast_frame_type frametype
Redirecting Line information. RDNIS (Redirecting Directory Number Information Service) Where a call d...
Definition: channel.h:524
struct ast_party_id from
Who is redirecting the call (Sent to the party the call is redirected toward)
Definition: channel.h:529
struct callattempt * call_next
Definition: app_queue.c:1841
unsigned int pending_connected_update
Definition: app_queue.c:1849
int ast_remaining_ms(struct timeval start, int max_ms)
Calculate remaining milliseconds given a starting timestamp and upper bound.
Definition: utils.c:2281
int64_t ast_tvdiff_ms(struct timeval end, struct timeval start)
Computes the difference (in milliseconds) between two struct timeval instances.
Definition: time.h:107
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:159

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

Referenced by try_calling().

◆ wait_our_turn()

static int wait_our_turn ( struct queue_ent qe,
int  ringing,
enum queue_result reason 
)
static

The waiting areas for callers who are not actively calling members.

This function is one large loop. This function will return if a caller either exits the queue or it becomes that caller's turn to attempt calling queue members. Inside the loop, we service the caller with periodic announcements, holdtime announcements, etc. as configured in queues.conf

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

Definition at line 6076 of file app_queue.c.

6077{
6078 int res = 0;
6079
6080 /* This is the holding pen for callers 2 through maxlen */
6081 for (;;) {
6082
6083 /* A request to withdraw this call from the queue arrived */
6084 if (qe->withdraw) {
6085 *reason = QUEUE_WITHDRAW;
6086 res = 1;
6087 break;
6088 }
6089
6090 if (is_our_turn(qe)) {
6091 break;
6092 }
6093
6094 /* If we have timed out, break out */
6095 if (qe->expire && (time(NULL) >= qe->expire)) {
6096 *reason = QUEUE_TIMEOUT;
6097 break;
6098 }
6099
6100 if (qe->parent->leavewhenempty) {
6101 int status = 0;
6102
6104 record_abandoned(qe);
6105 *reason = QUEUE_LEAVEEMPTY;
6106 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));
6107 res = -1;
6108 qe->handled = -1;
6109 break;
6110 }
6111 }
6112
6113 /* Make a position announcement, if enabled */
6114 if (qe->parent->announcefrequency &&
6115 (res = say_position(qe,ringing))) {
6116 break;
6117 }
6118
6119 /* If we have timed out, break out */
6120 if (qe->expire && (time(NULL) >= qe->expire)) {
6121 *reason = QUEUE_TIMEOUT;
6122 break;
6123 }
6124
6125 /* Make a periodic announcement, if enabled */
6128 break;
6129
6130 /* see if we need to move to the next penalty level for this queue */
6131 while (qe->pr && ((time(NULL) - qe->start) >= qe->pr->time)) {
6132 update_qe_rule(qe);
6133 }
6134
6135 /* If we have timed out, break out */
6136 if (qe->expire && (time(NULL) >= qe->expire)) {
6137 *reason = QUEUE_TIMEOUT;
6138 break;
6139 }
6140
6141 /* Wait a second before checking again */
6142 if ((res = ast_waitfordigit(qe->chan, RECHECK * 1000))) {
6143 if (res > 0 && !valid_exit(qe, res)) {
6144 res = 0;
6145 } else {
6146 break;
6147 }
6148 }
6149
6150 /* If we have timed out, break out */
6151 if (qe->expire && (time(NULL) >= qe->expire)) {
6152 *reason = QUEUE_TIMEOUT;
6153 break;
6154 }
6155 }
6156
6157 return res;
6158}
#define RECHECK
Definition: app_queue.c:1722

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

10508 {
10509 int list_len, word_len = strlen(word);
10510 const char *find, *end_find, *end_list;
10511
10512 /* strip whitespace from front */
10513 while(isspace(*list)) {
10514 list++;
10515 }
10516
10517 while((find = strstr(list, word))) {
10518 /* beginning of find starts inside another word? */
10519 if (find != list && *(find - 1) != ' ') {
10520 list = find;
10521 /* strip word from front */
10522 while(!isspace(*list) && *list != '\0') {
10523 list++;
10524 }
10525 /* strip whitespace from front */
10526 while(isspace(*list)) {
10527 list++;
10528 }
10529 continue;
10530 }
10531
10532 /* end of find ends inside another word or at very end of list? */
10533 list_len = strlen(list);
10534 end_find = find + word_len;
10535 end_list = list + list_len;
10536 if (end_find == end_list || *end_find != ' ') {
10537 list = find;
10538 /* strip word from front */
10539 while(!isspace(*list) && *list != '\0') {
10540 list++;
10541 }
10542 /* strip whitespace from front */
10543 while(isspace(*list)) {
10544 list++;
10545 }
10546 continue;
10547 }
10548
10549 /* terminating conditions satisfied, word at beginning or separated by ' ' */
10550 return 1;
10551 }
10552
10553 return 0;
10554}

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

◆ agent_router

struct stasis_message_router* agent_router
static

Definition at line 11947 of file app_queue.c.

Referenced by load_module(), and unload_module().

◆ app

char* app = "Queue"
static

Definition at line 1739 of file app_queue.c.

Referenced by load_module(), and unload_module().

◆ app_aqm

char* app_aqm = "AddQueueMember"
static

Definition at line 1741 of file app_queue.c.

Referenced by load_module(), and unload_module().

◆ app_pqm

char* app_pqm = "PauseQueueMember"
static

Definition at line 1745 of file app_queue.c.

Referenced by load_module(), and unload_module().

◆ app_ql

char* app_ql = "QueueLog"
static

Definition at line 1749 of file app_queue.c.

Referenced by load_module(), and unload_module().

◆ app_qupd

char* app_qupd = "QueueUpdate"
static

Definition at line 1751 of file app_queue.c.

Referenced by load_module(), and unload_module().

◆ app_rqm

char* app_rqm = "RemoveQueueMember"
static

Definition at line 1743 of file app_queue.c.

Referenced by load_module(), and unload_module().

◆ app_upqm

char* app_upqm = "UnpauseQueueMember"
static

Definition at line 1747 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 1670 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 12213 of file app_queue.c.

◆ autofill_default

int autofill_default
static

queues.conf [general] option

Definition at line 1763 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 11934 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 1775 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 1784 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 1808 of file app_queue.c.

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

◆ log_caller_id_name

int log_caller_id_name
static

queues.conf [general] option

Definition at line 1787 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 1766 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 1778 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 2690 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 1754 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 1654 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:9201

Definition at line 9681 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:9449

Definition at line 9702 of file app_queue.c.

Referenced by load_module(), and unload_module().

◆ queuemembercount_dep

struct ast_custom_function queuemembercount_dep
static
Initial value:
= {
.name = "QUEUE_MEMBER_COUNT",
}
static int queue_function_qac_dep(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
Get the total number of members in a specific queue (Deprecated)
Definition: app_queue.c:9408

Definition at line 9697 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:9243
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:9345

Definition at line 9691 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:9565

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

Definition at line 9717 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:9157

Definition at line 9686 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:9528

Definition at line 9707 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 1793 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 1790 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 1772 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 1769 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 11948 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 1760 of file app_queue.c.

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