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

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

#include "asterisk.h"
#include <sys/time.h>
#include <signal.h>
#include <netinet/in.h>
#include <ctype.h>
#include "asterisk/lock.h"
#include "asterisk/file.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/app.h"
#include "asterisk/linkedlists.h"
#include "asterisk/module.h"
#include "asterisk/translate.h"
#include "asterisk/say.h"
#include "asterisk/features.h"
#include "asterisk/musiconhold.h"
#include "asterisk/cli.h"
#include "asterisk/manager.h"
#include "asterisk/config.h"
#include "asterisk/utils.h"
#include "asterisk/causes.h"
#include "asterisk/astdb.h"
#include "asterisk/devicestate.h"
#include "asterisk/stringfields.h"
#include "asterisk/astobj2.h"
#include "asterisk/strings.h"
#include "asterisk/taskprocessor.h"
#include "asterisk/aoc.h"
#include "asterisk/callerid.h"
#include "asterisk/term.h"
#include "asterisk/dial.h"
#include "asterisk/stasis_channels.h"
#include "asterisk/stasis_message_router.h"
#include "asterisk/bridge_after.h"
#include "asterisk/stasis_bridges.h"
#include "asterisk/core_local.h"
#include "asterisk/mixmonitor.h"
#include "asterisk/bridge_basic.h"
#include "asterisk/max_forwards.h"
Include dependency graph for app_queue.c:

Go to the source code of this file.

Data Structures

struct  autopause
 
struct  call_queue
 
struct  callattempt
 We define a custom "local user" structure because we use it not only for keeping track of what is in use but also for keeping track of who we're dialing. More...
 
struct  local_optimization
 Structure representing relevant data during a local channel optimization. More...
 
struct  member
 
struct  penalty_rule
 
struct  queue_end_bridge
 
struct  queue_ent
 
struct  queue_stasis_data
 User data for stasis subscriptions used for queue calls. More...
 
struct  rule_list
 
struct  rule_lists
 
struct  strategy
 

Macros

#define ANNOUNCEHOLDTIME_ALWAYS   1
 
#define ANNOUNCEHOLDTIME_ONCE   2
 
#define ANNOUNCEPOSITION_LIMIT   4
 
#define ANNOUNCEPOSITION_MORE_THAN   3
 
#define ANNOUNCEPOSITION_NO   2
 
#define ANNOUNCEPOSITION_YES   1
 
#define AST_MAX_WATCHERS   256
 
#define DEFAULT_MIN_ANNOUNCE_FREQUENCY   15
 The minimum number of seconds between position announcements. More...
 
#define DEFAULT_RETRY   5
 
#define DEFAULT_TIMEOUT   15
 
#define MAX_CALL_ATTEMPT_BUCKETS   353
 
#define MAX_PERIODIC_ANNOUNCEMENTS   10
 
#define MAX_QUEUE_BUCKETS   53
 
#define QUEUE_EVENT_VARIABLES   3
 
#define QUEUE_PAUSED_DEVSTATE   AST_DEVICE_INUSE
 
#define queue_ref(q)   ao2_bump(q)
 
#define queue_t_ref(q, tag)   ao2_t_bump(q, tag)
 
#define queue_t_unref(q, tag)   ({ ao2_t_cleanup(q, tag); NULL; })
 
#define QUEUE_UNKNOWN_PAUSED_DEVSTATE   AST_DEVICE_NOT_INUSE
 
#define QUEUE_UNPAUSED_DEVSTATE   AST_DEVICE_NOT_INUSE
 
#define queue_unref(q)   ({ ao2_cleanup(q); NULL; })
 
#define queues_t_link(c, q, tag)   ao2_t_link(c, q, tag)
 
#define queues_t_unlink(c, q, tag)   ao2_t_unlink(c, q, tag)
 
#define RECHECK   1
 
#define RES_EXISTS   (-1)
 
#define RES_NOSUCHQUEUE   (-3)
 
#define RES_NOT_CALLER   (-5)
 
#define RES_NOT_DYNAMIC   (-4)
 
#define RES_OKAY   0
 
#define RES_OUTOFMEMORY   (-2)
 

Enumerations

enum  {
  OPT_MARK_AS_ANSWERED = (1 << 0) , OPT_GO_ON = (1 << 1) , OPT_DATA_QUALITY = (1 << 2) , OPT_CALLEE_GO_ON = (1 << 3) ,
  OPT_CALLEE_HANGUP = (1 << 4) , OPT_CALLER_HANGUP = (1 << 5) , OPT_IGNORE_CALL_FW = (1 << 6) , OPT_IGNORE_CONNECTEDLINE = (1 << 7) ,
  OPT_CALLEE_PARK = (1 << 8) , OPT_CALLER_PARK = (1 << 9) , OPT_NO_RETRY = (1 << 10) , OPT_RINGING = (1 << 11) ,
  OPT_RING_WHEN_RINGING = (1 << 12) , OPT_CALLEE_TRANSFER = (1 << 13) , OPT_CALLER_TRANSFER = (1 << 14) , OPT_CALLEE_AUTOMIXMON = (1 << 15) ,
  OPT_CALLER_AUTOMIXMON = (1 << 16) , OPT_CALLEE_AUTOMON = (1 << 17) , OPT_CALLER_AUTOMON = (1 << 18) , OPT_PREDIAL_CALLEE = (1 << 19) ,
  OPT_PREDIAL_CALLER = (1 << 20) , OPT_MUSICONHOLD_CLASS = (1 << 21)
}
 
enum  {
  OPT_ARG_CALLEE_GO_ON = 0 , OPT_ARG_PREDIAL_CALLEE , OPT_ARG_PREDIAL_CALLER , OPT_ARG_MUSICONHOLD_CLASS ,
  OPT_ARG_ARRAY_SIZE
}
 
enum  {
  QUEUE_STRATEGY_RINGALL = 0 , QUEUE_STRATEGY_LEASTRECENT , QUEUE_STRATEGY_FEWESTCALLS , QUEUE_STRATEGY_RANDOM ,
  QUEUE_STRATEGY_RRMEMORY , QUEUE_STRATEGY_LINEAR , QUEUE_STRATEGY_WRANDOM , QUEUE_STRATEGY_RRORDERED
}
 
enum  { QUEUE_AUTOPAUSE_OFF = 0 , QUEUE_AUTOPAUSE_ON , QUEUE_AUTOPAUSE_ALL }
 
enum  agent_complete_reason { CALLER , AGENT , TRANSFER }
 
enum  aqm_args { AQM_OPT_ARG_PAUSE_REASON = 0 , AQM_OPT_ARG_ARRAY_SIZE }
 
enum  aqm_flags { AQMFLAG_PAUSED = (1 << 1) , AQMFLAG_REASON = (1 << 2) }
 
enum  empty_conditions {
  QUEUE_EMPTY_PENALTY = (1 << 0) , QUEUE_EMPTY_PAUSED = (1 << 1) , QUEUE_EMPTY_INUSE = (1 << 2) , QUEUE_EMPTY_RINGING = (1 << 3) ,
  QUEUE_EMPTY_UNAVAILABLE = (1 << 4) , QUEUE_EMPTY_INVALID = (1 << 5) , QUEUE_EMPTY_UNKNOWN = (1 << 6) , QUEUE_EMPTY_WRAPUP = (1 << 7)
}
 
enum  member_properties { MEMBER_PENALTY = 0 , MEMBER_RINGINUSE = 1 }
 
enum  queue_reload_mask { QUEUE_RELOAD_PARAMETERS = (1 << 0) , QUEUE_RELOAD_MEMBER = (1 << 1) , QUEUE_RELOAD_RULES = (1 << 2) , QUEUE_RESET_STATS = (1 << 3) }
 
enum  queue_result {
  QUEUE_UNKNOWN = 0 , QUEUE_TIMEOUT = 1 , QUEUE_JOINEMPTY = 2 , QUEUE_LEAVEEMPTY = 3 ,
  QUEUE_JOINUNAVAIL = 4 , QUEUE_LEAVEUNAVAIL = 5 , QUEUE_FULL = 6 , QUEUE_CONTINUE = 7 ,
  QUEUE_WITHDRAW = 8
}
 
enum  queue_timeout_priority { TIMEOUT_PRIORITY_APP , TIMEOUT_PRIORITY_CONF }
 

Functions

static char * __queues_show (struct mansession *s, int fd, int argc, const char *const *argv)
 Show queue(s) status and statistics. More...
 
static void __reg_module (void)
 
static void __unreg_module (void)
 
static int add_to_queue (const char *queuename, const char *interface, const char *membername, int penalty, int paused, int dump, const char *state_interface, const char *reason_paused, int wrapuptime)
 Add member to queue. More...
 
static struct call_queuealloc_queue (const char *queuename)
 
 AO2_STRING_FIELD_SORT_FN (call_queue, name)
 
static int aqm_exec (struct ast_channel *chan, const char *data)
 AddQueueMember application. More...
 
struct ast_moduleAST_MODULE_SELF_SYM (void)
 
static int autopause2int (const char *autopause)
 
static int calc_metric (struct call_queue *q, struct member *mem, int pos, struct queue_ent *qe, struct callattempt *tmp)
 Calculate the metric of each member in the outgoing callattempts. More...
 
static void callattempt_free (struct callattempt *doomed)
 
static int can_ring_entry (struct queue_ent *qe, struct callattempt *call)
 
static int change_priority_caller_on_queue (const char *queuename, const char *caller, int priority, int immediate)
 Change priority caller into a queue. More...
 
static void clear_queue (struct call_queue *q)
 
static int clear_stats (const char *queuename)
 Facilitates resetting statistics for a queue. More...
 
static int compare_weight (struct call_queue *rq, struct member *member)
 
static char * complete_queue (const char *line, const char *word, int pos, int state, ptrdiff_t word_list_offset)
 Check if a given word is in a space-delimited list. More...
 
static char * complete_queue_add_member (const char *line, const char *word, int pos, int state)
 
static char * complete_queue_pause_member (const char *line, const char *word, int pos, int state)
 
static char * complete_queue_remove_member (const char *line, const char *word, int pos, int state)
 
static char * complete_queue_rule_show (const char *line, const char *word, int pos, int state)
 
static char * complete_queue_set_member_value (const char *line, const char *word, int pos, int state)
 
static char * complete_queue_show (const char *line, const char *word, int pos, int state)
 
static int compress_char (const char c)
 
static int context_included (const char *parent, const char *child)
 Returns if one context includes another context. More...
 
static void copy_rules (struct queue_ent *qe, const char *rulename)
 Copy rule from global list into specified queue. More...
 
static struct membercreate_queue_member (const char *interface, const char *membername, int penalty, int paused, const char *state_interface, int ringinuse, int wrapuptime)
 allocate space for new queue member and set fields based on parameters passed More...
 
static void destroy_queue (void *obj)
 Free queue's member list then its string fields. More...
 
static void destroy_queue_member_cb (void *obj)
 
static void device_state_cb (void *unused, struct stasis_subscription *sub, struct stasis_message *msg)
 set a member's status based on device state of that member's interface More...
 
static void do_hang (struct callattempt *o)
 common hangup actions More...
 
static void do_print (struct mansession *s, int fd, const char *str)
 direct output to manager or cli with proper terminator More...
 
static void dump_queue_members (struct call_queue *pm_queue)
 Dump all members in a specific queue to the database. More...
 
static void end_bridge_callback (void *data)
 
static void end_bridge_callback_data_fixup (struct ast_bridge_config *bconfig, struct ast_channel *originator, struct ast_channel *terminator)
 
static void escape_and_substitute (struct ast_channel *chan, const char *input, char *output, size_t size)
 
static int extension_state_cb (const char *context, const char *exten, struct ast_state_cb_info *info, void *data)
 
static int extensionstate2devicestate (int state)
 Helper function which converts from extension state to device state values. More...
 
static struct callattemptfind_best (struct callattempt *outgoing)
 find the entry with the best metric, or NULL More...
 
static struct call_queuefind_load_queue_rt_friendly (const char *queuename)
 
static struct memberfind_member_by_queuename_and_interface (const char *queuename, const char *interface)
 Find a member by looking up queuename and interface. More...
 
static struct call_queuefind_queue_by_name_rt (const char *queuename, struct ast_variable *queue_vars, struct ast_config *member_config)
 Reload a single queue via realtime. More...
 
static void free_members (struct call_queue *q, int all)
 Iterate through queue's member list and delete them. More...
 
static struct memberget_interface_helper (struct call_queue *q, const char *interface)
 
static int get_member_penalty (char *queuename, char *interface)
 Gets members penalty. More...
 
static int get_member_status (struct call_queue *q, int max_penalty, int min_penalty, int raise_penalty, enum empty_conditions conditions, int devstate)
 Check if members are available. More...
 
static int get_queue_member_status (struct member *cur)
 Return the current state of a member. More...
 
static int get_wrapuptime (struct call_queue *q, struct member *member)
 Return wrapuptime. More...
 
static void handle_attended_transfer (void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
 Handle an attended transfer event. More...
 
static void handle_blind_transfer (void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
 Handle a blind transfer event. More...
 
static void handle_bridge_enter (void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
 
static void handle_hangup (void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
 
static void handle_local_optimization_begin (void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
 
static void handle_local_optimization_end (void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
 
static void handle_masquerade (void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
 
static char * handle_queue_add_member (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 
static char * handle_queue_change_priority_caller (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 
static char * handle_queue_pause_member (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 
static char * handle_queue_reload (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 
static char * handle_queue_remove_member (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 
static char * handle_queue_reset (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 
static char * handle_queue_rule_show (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 
static char * handle_queue_set_member_penalty (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 
static char * handle_queue_set_member_ringinuse (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 
static void hangupcalls (struct queue_ent *qe, struct callattempt *outgoing, struct ast_channel *exception, int cancel_answered_elsewhere)
 Hang up a list of outgoing calls. More...
 
static void init_queue (struct call_queue *q)
 Initialize Queue default values. More...
 
static void insert_entry (struct call_queue *q, struct queue_ent *prev, struct queue_ent *new, int *pos)
 Insert the 'new' entry after the 'prev' entry of queue 'q'. More...
 
static int insert_penaltychange (const char *list_name, const char *content, const int linenum)
 Change queue penalty by adding rule. More...
 
static const char * int2strat (int strategy)
 
static struct memberinterface_exists (struct call_queue *q, const char *interface)
 
static int is_longest_waiting_caller (struct queue_ent *caller, struct member *member)
 
static int is_member_available (struct call_queue *q, struct member *mem)
 
static int is_our_turn (struct queue_ent *qe)
 Check if we should start attempting to call queue members. More...
 
static int join_queue (char *queuename, struct queue_ent *qe, enum queue_result *reason, int position)
 
static int kill_dead_members (void *obj, void *arg, int flags)
 
static int kill_if_unfound (void *obj, void *arg, int flags)
 
static void leave_queue (struct queue_ent *qe)
 Caller leaving queue. More...
 
static int load_module (void)
 Load the module. More...
 
static void load_realtime_queues (const char *queuename)
 
static int load_realtime_rules (void)
 Load queue rules from realtime. More...
 
static void log_attended_transfer (struct queue_stasis_data *queue_data, struct ast_attended_transfer_message *atxfer_msg)
 
static int manager_add_queue_member (struct mansession *s, const struct message *m)
 
static int manager_change_priority_caller_on_queue (struct mansession *s, const struct message *m)
 
static int manager_pause_queue_member (struct mansession *s, const struct message *m)
 
static int manager_queue_log_custom (struct mansession *s, const struct message *m)
 
static int manager_queue_member_penalty (struct mansession *s, const struct message *m)
 
static int manager_queue_member_ringinuse (struct mansession *s, const struct message *m)
 
static int manager_queue_reload (struct mansession *s, const struct message *m)
 
static int manager_queue_reset (struct mansession *s, const struct message *m)
 
static int manager_queue_rule_show (struct mansession *s, const struct message *m)
 
static int manager_queues_status (struct mansession *s, const struct message *m)
 Queue status info via AMI. More...
 
static int manager_queues_summary (struct mansession *s, const struct message *m)
 Summary of queue info via the AMI. More...
 
static int manager_remove_queue_member (struct mansession *s, const struct message *m)
 
static int manager_request_withdraw_caller_from_queue (struct mansession *s, const struct message *m)
 
static int mark_member_dead (void *obj, void *arg, int flags)
 
static int mark_unfound (void *obj, void *arg, int flags)
 
static void member_add_to_queue (struct call_queue *queue, struct member *mem)
 
static int member_cmp_fn (void *obj1, void *obj2, int flags)
 
static int member_hash_fn (const void *obj, const int flags)
 
static void member_remove_from_queue (struct call_queue *queue, struct member *mem)
 
static int member_status_available (int status)
 
static int num_available_members (struct call_queue *q)
 Get the number of members available to accept a call. More...
 
static void parse_empty_options (const char *value, enum empty_conditions *empty, int joinempty)
 
static int pending_members_cmp (void *obj, void *arg, int flags)
 
static int pending_members_hash (const void *obj, const int flags)
 
static void pending_members_remove (struct member *mem)
 
static int play_file (struct ast_channel *chan, const char *filename)
 
static int pqm_exec (struct ast_channel *chan, const char *data)
 PauseQueueMember application. More...
 
static void print_queue (struct mansession *s, int fd, struct call_queue *q)
 Print a single queue to AMI or the CLI. More...
 
static void publish_dial_end_event (struct ast_channel *in, struct callattempt *outgoing, struct ast_channel *exception, const char *status)
 
static int publish_queue_member_pause (struct call_queue *q, struct member *member)
 
static int ql_exec (struct ast_channel *chan, const char *data)
 QueueLog application. More...
 
static struct ast_manager_event_blobqueue_agent_called_to_ami (struct stasis_message *message)
 
static void queue_agent_cb (void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
 
static struct ast_manager_event_blobqueue_agent_complete_to_ami (struct stasis_message *message)
 
static struct ast_manager_event_blobqueue_agent_connect_to_ami (struct stasis_message *message)
 
static struct ast_manager_event_blobqueue_agent_dump_to_ami (struct stasis_message *message)
 
static struct ast_manager_event_blobqueue_agent_ringnoanswer_to_ami (struct stasis_message *message)
 
static void queue_bridge_cb (void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
 
static struct ast_manager_event_blobqueue_caller_abandon_to_ami (struct stasis_message *message)
 
static struct ast_manager_event_blobqueue_caller_join_to_ami (struct stasis_message *message)
 
static struct ast_manager_event_blobqueue_caller_leave_to_ami (struct stasis_message *message)
 
static void queue_channel_cb (void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
 
static struct ast_manager_event_blobqueue_channel_to_ami (const char *type, struct stasis_message *message)
 
static int queue_cmp_cb (void *obj, void *arg, int flags)
 
static int queue_delme_members_decrement_followers (void *obj, void *arg, int flag)
 
static int queue_exec (struct ast_channel *chan, const char *data)
 The starting point for all queue calls. More...
 
static int queue_function_exists (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
 Check if a given queue exists. More...
 
static int queue_function_mem_read (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
 Get number either busy / free / ready or total members of a specific queue. More...
 
static int queue_function_mem_write (struct ast_channel *chan, const char *cmd, char *data, const char *value)
 Dialplan function QUEUE_MEMBER() Sets the members penalty / paused / ringinuse. More...
 
static int queue_function_memberpenalty_read (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
 Dialplan function QUEUE_MEMBER_PENALTY() Gets the members penalty. More...
 
static int queue_function_memberpenalty_write (struct ast_channel *chan, const char *cmd, char *data, const char *value)
 Dialplan function QUEUE_MEMBER_PENALTY() Sets the members penalty. More...
 
static int queue_function_qac_dep (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
 Get the total number of members in a specific queue (Deprecated) More...
 
static int queue_function_queuegetchannel (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
 Dialplan function QUEUE_GET_CHANNEL() Get caller channel waiting at specified position in the queue. More...
 
static int queue_function_queuememberlist (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
 Dialplan function QUEUE_MEMBER_LIST() Get list of members in a specific queue. More...
 
static int queue_function_queuewaitingcount (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
 Dialplan function QUEUE_WAITING_COUNT() Get number callers waiting in a specific queue. More...
 
static int queue_function_var (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
 create interface var with all queue details. More...
 
static int queue_hash_cb (const void *obj, const int flags)
 
static struct ast_manager_event_blobqueue_member_added_to_ami (struct stasis_message *message)
 
static struct ast_jsonqueue_member_blob_create (struct call_queue *q, struct member *mem)
 
static int queue_member_decrement_followers (void *obj, void *arg, int flag)
 
static void queue_member_follower_removal (struct call_queue *queue, struct member *mem)
 
static struct ast_manager_event_blobqueue_member_pause_to_ami (struct stasis_message *message)
 
static struct ast_manager_event_blobqueue_member_penalty_to_ami (struct stasis_message *message)
 
static struct ast_manager_event_blobqueue_member_removed_to_ami (struct stasis_message *message)
 
static struct ast_manager_event_blobqueue_member_ringinuse_to_ami (struct stasis_message *message)
 
static struct ast_manager_event_blobqueue_member_status_to_ami (struct stasis_message *message)
 
static struct ast_manager_event_blobqueue_member_to_ami (const char *type, struct stasis_message *message)
 
static struct ast_manager_event_blobqueue_multi_channel_to_ami (const char *type, struct stasis_message *message)
 
static void queue_publish_member_blob (struct stasis_message_type *type, struct ast_json *blob)
 
static void queue_publish_multi_channel_blob (struct ast_channel *caller, struct ast_channel *agent, struct stasis_message_type *type, struct ast_json *blob)
 
static void queue_publish_multi_channel_snapshot_blob (struct stasis_topic *topic, struct ast_channel_snapshot *caller_snapshot, struct ast_channel_snapshot *agent_snapshot, struct stasis_message_type *type, struct ast_json *blob)
 
static void queue_reset_global_params (void)
 
static void queue_rules_reset_global_params (void)
 
static void queue_rules_set_global_params (struct ast_config *cfg)
 
static void queue_set_global_params (struct ast_config *cfg)
 
static void queue_set_param (struct call_queue *q, const char *param, const char *val, int linenum, int failunknown)
 Configure a queue parameter. More...
 
static char * queue_show (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 
static struct queue_stasis_dataqueue_stasis_data_alloc (struct queue_ent *qe, struct ast_channel *peer, struct member *mem, time_t holdstart, time_t starttime, int callcompletedinsl)
 
static void queue_stasis_data_destructor (void *obj)
 
static int qupd_exec (struct ast_channel *chan, const char *data)
 Update Queue with data of an outgoing call. More...
 
static void recalc_holdtime (struct queue_ent *qe, int newholdtime)
 
static void record_abandoned (struct queue_ent *qe)
 Record that a caller gave up on waiting in queue. More...
 
static int reload (void)
 
static int reload_handler (int reload, struct ast_flags *mask, const char *queuename)
 The command center for all reload operations. More...
 
static void reload_queue_members (void)
 Reload dynamic queue members persisted into the astdb. More...
 
static int reload_queue_rules (int reload)
 Reload the rules defined in queuerules.conf. More...
 
static int reload_queues (int reload, struct ast_flags *mask, const char *queuename)
 reload the queues.conf file More...
 
static void reload_single_member (const char *memberdata, struct call_queue *q)
 reload information pertaining to a single member More...
 
static void reload_single_queue (struct ast_config *cfg, struct ast_flags *mask, const char *queuename)
 Reload information pertaining to a particular queue. More...
 
static int remove_from_queue (const char *queuename, const char *interface)
 Remove member from queue. More...
 
static void remove_stasis_subscriptions (struct queue_stasis_data *queue_data)
 
static int request_withdraw_caller_from_queue (const char *queuename, const char *caller, const char *withdraw_info)
 Request to withdraw a caller from a queue. More...
 
static int ring_entry (struct queue_ent *qe, struct callattempt *tmp, int *busies)
 Part 2 of ring_one. More...
 
static int ring_one (struct queue_ent *qe, struct callattempt *outgoing, int *busies)
 Place a call to a queue member. More...
 
static void rna (int rnatime, struct queue_ent *qe, struct ast_channel *peer, char *interface, char *membername, int autopause)
 RNA == Ring No Answer. Common code that is executed when we try a queue member and they don't answer. More...
 
static int rqm_exec (struct ast_channel *chan, const char *data)
 RemoveQueueMember application. More...
 
static void rt_handle_member_record (struct call_queue *q, char *category, struct ast_config *member_config)
 Find rt member record to update otherwise create one. More...
 
static int say_periodic_announcement (struct queue_ent *qe, int ringing)
 Playback announcement to queued members if period has elapsed. More...
 
static int say_position (struct queue_ent *qe, int ringing)
 
static void send_agent_complete (const char *queuename, struct ast_channel_snapshot *caller, struct ast_channel_snapshot *peer, const struct member *member, time_t holdstart, time_t callstart, enum agent_complete_reason rsn)
 Send out AMI message with member call completion status information. More...
 
static int set_member_paused (const char *queuename, const char *interface, const char *reason, int paused)
 
static int set_member_penalty_help_members (struct call_queue *q, const char *interface, int penalty)
 
static int set_member_ringinuse_help_members (struct call_queue *q, const char *interface, int ringinuse)
 
static int set_member_value (const char *queuename, const char *interface, int property, int value)
 
static int set_member_value_help_members (struct call_queue *q, const char *interface, int property, int value)
 
static void set_queue_member_pause (struct call_queue *q, struct member *mem, const char *reason, int paused)
 
static void set_queue_member_ringinuse (struct call_queue *q, struct member *mem, int ringinuse)
 
static void set_queue_result (struct ast_channel *chan, enum queue_result res)
 sets the QUEUESTATUS channel variable More...
 
static void set_queue_variables (struct call_queue *q, struct ast_channel *chan)
 Set variables of queue. More...
 
static void setup_mixmonitor (struct queue_ent *qe, const char *filename)
 
static void setup_peer_after_bridge_goto (struct ast_channel *chan, struct ast_channel *peer, struct ast_flags *opts, char *opt_args[])
 
static int setup_stasis_subs (struct queue_ent *qe, struct ast_channel *peer, struct member *mem, time_t holdstart, time_t starttime, int callcompletedinsl)
 
 STASIS_MESSAGE_TYPE_DEFN_LOCAL (queue_agent_called_type,.to_ami=queue_agent_called_to_ami,)
 
 STASIS_MESSAGE_TYPE_DEFN_LOCAL (queue_agent_complete_type,.to_ami=queue_agent_complete_to_ami,)
 
 STASIS_MESSAGE_TYPE_DEFN_LOCAL (queue_agent_connect_type,.to_ami=queue_agent_connect_to_ami,)
 
 STASIS_MESSAGE_TYPE_DEFN_LOCAL (queue_agent_dump_type,.to_ami=queue_agent_dump_to_ami,)
 
 STASIS_MESSAGE_TYPE_DEFN_LOCAL (queue_agent_ringnoanswer_type,.to_ami=queue_agent_ringnoanswer_to_ami,)
 
 STASIS_MESSAGE_TYPE_DEFN_LOCAL (queue_caller_abandon_type,.to_ami=queue_caller_abandon_to_ami,)
 
 STASIS_MESSAGE_TYPE_DEFN_LOCAL (queue_caller_join_type,.to_ami=queue_caller_join_to_ami,)
 
 STASIS_MESSAGE_TYPE_DEFN_LOCAL (queue_caller_leave_type,.to_ami=queue_caller_leave_to_ami,)
 
 STASIS_MESSAGE_TYPE_DEFN_LOCAL (queue_member_added_type,.to_ami=queue_member_added_to_ami,)
 
 STASIS_MESSAGE_TYPE_DEFN_LOCAL (queue_member_pause_type,.to_ami=queue_member_pause_to_ami,)
 
 STASIS_MESSAGE_TYPE_DEFN_LOCAL (queue_member_penalty_type,.to_ami=queue_member_penalty_to_ami,)
 
 STASIS_MESSAGE_TYPE_DEFN_LOCAL (queue_member_removed_type,.to_ami=queue_member_removed_to_ami,)
 
 STASIS_MESSAGE_TYPE_DEFN_LOCAL (queue_member_ringinuse_type,.to_ami=queue_member_ringinuse_to_ami,)
 
 STASIS_MESSAGE_TYPE_DEFN_LOCAL (queue_member_status_type,.to_ami=queue_member_status_to_ami,)
 
static int store_next_lin (struct queue_ent *qe, struct callattempt *outgoing)
 Search for best metric and add to Linear queue. More...
 
static int store_next_rr (struct queue_ent *qe, struct callattempt *outgoing)
 Search for best metric and add to Round Robbin queue. More...
 
static int strat2int (const char *strategy)
 
static int try_calling (struct queue_ent *qe, struct ast_flags opts, char **opt_args, char *announceoverride, const char *url, int *tries, int *noption, const char *agi, const char *gosub, int ringing)
 
static int unload_module (void)
 
static void update_connected_line_from_peer (struct ast_channel *chan, struct ast_channel *peer, int is_caller)
 
static void update_qe_rule (struct queue_ent *qe)
 update rules for queues More...
 
static int update_queue (struct call_queue *q, struct member *member, int callcompletedinsl, time_t starttime)
 update the queue status More...
 
static int update_realtime_member_field (struct member *mem, const char *queue_name, const char *field, const char *value)
 
static void update_realtime_members (struct call_queue *q)
 
static void update_status (struct call_queue *q, struct member *m, const int status)
 set a member's status based on device state of that member's state_interface. More...
 
static int upqm_exec (struct ast_channel *chan, const char *data)
 UnpauseQueueMember application. More...
 
static int valid_exit (struct queue_ent *qe, char digit)
 Check for valid exit from queue via goto. More...
 
static int wait_a_bit (struct queue_ent *qe)
 
static struct callattemptwait_for_answer (struct queue_ent *qe, struct callattempt *outgoing, int *to, char *digit, int prebusies, int caller_disconnect, int forwardsallowed)
 Wait for a member to answer the call. More...
 
static int wait_our_turn (struct queue_ent *qe, int ringing, enum queue_result *reason)
 The waiting areas for callers who are not actively calling members. More...
 
static int word_in_list (const char *list, const char *word)
 Check if a given word is in a space-delimited list. More...
 

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "True Call Queueing" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, .reload = reload, .load_pri = AST_MODPRI_DEVSTATE_CONSUMER, }
 
static struct stasis_message_routeragent_router
 
static char * app = "Queue"
 
static char * app_aqm = "AddQueueMember"
 
static char * app_pqm = "PauseQueueMember"
 
static char * app_ql = "QueueLog"
 
static char * app_qupd = "QueueUpdate"
 
static char * app_rqm = "RemoveQueueMember"
 
static char * app_upqm = "UnpauseQueueMember"
 
static const struct ast_app_option aqm_opts [128] = { [ 'p' ] = { .flag = AQMFLAG_PAUSED }, [ 'r' ] = { .flag = AQMFLAG_REASON , .arg_index = AQM_OPT_ARG_PAUSE_REASON + 1 }, }
 
static const struct ast_module_infoast_module_info = &__mod_info
 
static int autofill_default
 queues.conf [general] option More...
 
static const struct autopause autopausesmodes []
 
static struct ast_cli_entry cli_queue []
 
static struct stasis_subscriptiondevice_state_sub
 Subscription to device state change messages. More...
 
static int force_longest_waiting_caller
 queues.conf [general] option More...
 
static int log_membername_as_agent
 queues.conf [general] option More...
 
static int montype_default
 queues.conf [general] option More...
 
static int negative_penalty_invalid
 queues.conf [general] option More...
 
static struct ao2_containerpending_members
 
static const char *const pm_family = "Queue/PersistentMembers"
 Persistent Members astdb family. More...
 
static const struct ast_app_option queue_exec_options [128] = { [ 'b' ] = { .flag = OPT_PREDIAL_CALLEE , .arg_index = OPT_ARG_PREDIAL_CALLEE + 1 }, [ 'B' ] = { .flag = OPT_PREDIAL_CALLER , .arg_index = OPT_ARG_PREDIAL_CALLER + 1 }, [ 'C' ] = { .flag = OPT_MARK_AS_ANSWERED }, [ 'c' ] = { .flag = OPT_GO_ON }, [ 'd' ] = { .flag = OPT_DATA_QUALITY }, [ 'F' ] = { .flag = OPT_CALLEE_GO_ON , .arg_index = OPT_ARG_CALLEE_GO_ON + 1 }, [ 'h' ] = { .flag = OPT_CALLEE_HANGUP }, [ 'H' ] = { .flag = OPT_CALLER_HANGUP }, [ 'i' ] = { .flag = OPT_IGNORE_CALL_FW }, [ 'I' ] = { .flag = OPT_IGNORE_CONNECTEDLINE }, [ 'k' ] = { .flag = OPT_CALLEE_PARK }, [ 'K' ] = { .flag = OPT_CALLER_PARK }, [ 'm' ] = { .flag = OPT_MUSICONHOLD_CLASS , .arg_index = OPT_ARG_MUSICONHOLD_CLASS + 1 }, [ 'n' ] = { .flag = OPT_NO_RETRY }, [ 'r' ] = { .flag = OPT_RINGING }, [ 'R' ] = { .flag = OPT_RING_WHEN_RINGING }, [ 't' ] = { .flag = OPT_CALLEE_TRANSFER }, [ 'T' ] = { .flag = OPT_CALLER_TRANSFER }, [ 'x' ] = { .flag = OPT_CALLEE_AUTOMIXMON }, [ 'X' ] = { .flag = OPT_CALLER_AUTOMIXMON }, [ 'w' ] = { .flag = OPT_CALLEE_AUTOMON }, [ 'W' ] = { .flag = OPT_CALLER_AUTOMON }, }
 
static int queue_persistent_members
 queues.conf [general] option More...
 
struct {
   enum queue_result   id
 
   char *   text
 
queue_results []
 
static struct ast_custom_function queueexists_function
 
static struct ast_custom_function queuegetchannel_function
 
static struct ast_custom_function queuemembercount_dep
 
static struct ast_custom_function queuemembercount_function
 
static struct ast_custom_function queuememberlist_function
 
static struct ast_custom_function queuememberpenalty_function
 
static struct ao2_containerqueues
 
static struct ast_custom_function queuevar_function
 
static struct ast_custom_function queuewaitingcount_function
 
static int realtime_reason_paused
 does realtime backend support reason_paused More...
 
static char * realtime_ringinuse_field
 name of the ringinuse field in the realtime database More...
 
static int realtime_rules
 queuerules.conf [general] option More...
 
static struct rule_lists rule_lists = { .first = NULL, .last = NULL, .lock = { PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP , NULL, {1, 0} } , }
 
static int shared_lastcall
 queues.conf [general] option More...
 
static const struct strategy strategies []
 
static struct stasis_forwardtopic_forwarder
 
static int use_weight
 Records that one or more queues use weight. More...
 

Detailed Description

True call queues with optional send URL on answer.

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

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

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

Patch Version 1.07 2003-12-24 01

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

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

Definition in file app_queue.c.

Macro Definition Documentation

◆ ANNOUNCEHOLDTIME_ALWAYS

#define ANNOUNCEHOLDTIME_ALWAYS   1

Definition at line 1800 of file app_queue.c.

◆ ANNOUNCEHOLDTIME_ONCE

#define ANNOUNCEHOLDTIME_ONCE   2

Definition at line 1801 of file app_queue.c.

◆ ANNOUNCEPOSITION_LIMIT

#define ANNOUNCEPOSITION_LIMIT   4

We not announce position more than <limit>

Definition at line 1818 of file app_queue.c.

◆ ANNOUNCEPOSITION_MORE_THAN

#define ANNOUNCEPOSITION_MORE_THAN   3

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

Definition at line 1817 of file app_queue.c.

◆ ANNOUNCEPOSITION_NO

#define ANNOUNCEPOSITION_NO   2

We don't announce position

Definition at line 1816 of file app_queue.c.

◆ ANNOUNCEPOSITION_YES

#define ANNOUNCEPOSITION_YES   1

We announce position

Definition at line 1815 of file app_queue.c.

◆ AST_MAX_WATCHERS

#define AST_MAX_WATCHERS   256

Definition at line 5220 of file app_queue.c.

◆ DEFAULT_MIN_ANNOUNCE_FREQUENCY

#define DEFAULT_MIN_ANNOUNCE_FREQUENCY   15

The minimum number of seconds between position announcements.

Note
The default value of 15 provides backwards compatibility.

Definition at line 1590 of file app_queue.c.

◆ DEFAULT_RETRY

#define DEFAULT_RETRY   5

Definition at line 1582 of file app_queue.c.

◆ DEFAULT_TIMEOUT

#define DEFAULT_TIMEOUT   15

Definition at line 1583 of file app_queue.c.

◆ MAX_CALL_ATTEMPT_BUCKETS

#define MAX_CALL_ATTEMPT_BUCKETS   353

Definition at line 2543 of file app_queue.c.

◆ MAX_PERIODIC_ANNOUNCEMENTS

#define MAX_PERIODIC_ANNOUNCEMENTS   10

The maximum periodic announcements we can have

Definition at line 1585 of file app_queue.c.

◆ MAX_QUEUE_BUCKETS

#define MAX_QUEUE_BUCKETS   53

Definition at line 1592 of file app_queue.c.

◆ QUEUE_EVENT_VARIABLES

#define QUEUE_EVENT_VARIABLES   3

Definition at line 1802 of file app_queue.c.

◆ QUEUE_PAUSED_DEVSTATE

#define QUEUE_PAUSED_DEVSTATE   AST_DEVICE_INUSE

Definition at line 3565 of file app_queue.c.

◆ queue_ref

#define queue_ref (   q)    ao2_bump(q)

Definition at line 2084 of file app_queue.c.

◆ queue_t_ref

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

Definition at line 2086 of file app_queue.c.

◆ queue_t_unref

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

Definition at line 2087 of file app_queue.c.

◆ QUEUE_UNKNOWN_PAUSED_DEVSTATE

#define QUEUE_UNKNOWN_PAUSED_DEVSTATE   AST_DEVICE_NOT_INUSE

Definition at line 3567 of file app_queue.c.

◆ QUEUE_UNPAUSED_DEVSTATE

#define QUEUE_UNPAUSED_DEVSTATE   AST_DEVICE_NOT_INUSE

Definition at line 3566 of file app_queue.c.

◆ queue_unref

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

Definition at line 2085 of file app_queue.c.

◆ queues_t_link

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

Definition at line 2088 of file app_queue.c.

◆ queues_t_unlink

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

Definition at line 2089 of file app_queue.c.

◆ RECHECK

#define RECHECK   1

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

Definition at line 1584 of file app_queue.c.

◆ RES_EXISTS

#define RES_EXISTS   (-1)

Entry already exists

Definition at line 1595 of file app_queue.c.

◆ RES_NOSUCHQUEUE

#define RES_NOSUCHQUEUE   (-3)

No such queue

Definition at line 1597 of file app_queue.c.

◆ RES_NOT_CALLER

#define RES_NOT_CALLER   (-5)

Caller not found

Definition at line 1599 of file app_queue.c.

◆ RES_NOT_DYNAMIC

#define RES_NOT_DYNAMIC   (-4)

Member is not dynamic

Definition at line 1598 of file app_queue.c.

◆ RES_OKAY

#define RES_OKAY   0

Action completed

Definition at line 1594 of file app_queue.c.

◆ RES_OUTOFMEMORY

#define RES_OUTOFMEMORY   (-2)

Out of memory

Definition at line 1596 of file app_queue.c.

Enumeration Type Documentation

◆ anonymous enum

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

Definition at line 1459 of file app_queue.c.

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

◆ anonymous enum

anonymous enum
Enumerator
OPT_ARG_CALLEE_GO_ON 
OPT_ARG_PREDIAL_CALLEE 
OPT_ARG_PREDIAL_CALLER 
OPT_ARG_MUSICONHOLD_CLASS 
OPT_ARG_ARRAY_SIZE 

Definition at line 1484 of file app_queue.c.

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

◆ anonymous enum

anonymous enum
Enumerator
QUEUE_STRATEGY_RINGALL 
QUEUE_STRATEGY_LEASTRECENT 
QUEUE_STRATEGY_FEWESTCALLS 
QUEUE_STRATEGY_RANDOM 
QUEUE_STRATEGY_RRMEMORY 
QUEUE_STRATEGY_LINEAR 
QUEUE_STRATEGY_WRANDOM 
QUEUE_STRATEGY_RRORDERED 

Definition at line 1534 of file app_queue.c.

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

◆ anonymous enum

anonymous enum
Enumerator
QUEUE_AUTOPAUSE_OFF 
QUEUE_AUTOPAUSE_ON 
QUEUE_AUTOPAUSE_ALL 

Definition at line 1545 of file app_queue.c.

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

◆ agent_complete_reason

Enumerator
CALLER 
AGENT 
TRANSFER 

Definition at line 6151 of file app_queue.c.

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

◆ aqm_args

enum aqm_args
Enumerator
AQM_OPT_ARG_PAUSE_REASON 
AQM_OPT_ARG_ARRAY_SIZE 

Definition at line 1524 of file app_queue.c.

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

◆ aqm_flags

enum aqm_flags
Enumerator
AQMFLAG_PAUSED 
AQMFLAG_REASON 

Definition at line 1519 of file app_queue.c.

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

◆ empty_conditions

Enumerator
QUEUE_EMPTY_PENALTY 
QUEUE_EMPTY_PAUSED 
QUEUE_EMPTY_INUSE 
QUEUE_EMPTY_RINGING 
QUEUE_EMPTY_UNAVAILABLE 
QUEUE_EMPTY_INVALID 
QUEUE_EMPTY_UNKNOWN 
QUEUE_EMPTY_WRAPUP 

Definition at line 1783 of file app_queue.c.

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

◆ member_properties

Enumerator
MEMBER_PENALTY 
MEMBER_RINGINUSE 

Definition at line 1794 of file app_queue.c.

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

◆ queue_reload_mask

Enumerator
QUEUE_RELOAD_PARAMETERS 
QUEUE_RELOAD_MEMBER 
QUEUE_RELOAD_RULES 
QUEUE_RESET_STATS 

Definition at line 1551 of file app_queue.c.

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

◆ queue_result

Enumerator
QUEUE_UNKNOWN 
QUEUE_TIMEOUT 
QUEUE_JOINEMPTY 
QUEUE_LEAVEEMPTY 
QUEUE_JOINUNAVAIL 
QUEUE_LEAVEUNAVAIL 
QUEUE_FULL 
QUEUE_CONTINUE 
QUEUE_WITHDRAW 

Definition at line 1654 of file app_queue.c.

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

◆ queue_timeout_priority

Enumerator
TIMEOUT_PRIORITY_APP 
TIMEOUT_PRIORITY_CONF 

Definition at line 1681 of file app_queue.c.

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

Function Documentation

◆ __queues_show()

static char * __queues_show ( struct mansession s,
int  fd,
int  argc,
const char *const *  argv 
)
static

Show queue(s) status and statistics.

List the queues strategy, calls processed, members logged in, other queue statistics such as avg hold time.

Definition at line 10201 of file app_queue.c.

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

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

Referenced by queue_show().

◆ __reg_module()

static void __reg_module ( void  )
static

Definition at line 12018 of file app_queue.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

Definition at line 12018 of file app_queue.c.

◆ add_to_queue()

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

Add member to queue.

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

Definition at line 7622 of file app_queue.c.

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

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

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

◆ alloc_queue()

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

Definition at line 3756 of file app_queue.c.

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

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

Referenced by find_queue_by_name_rt(), and reload_single_queue().

◆ AO2_STRING_FIELD_SORT_FN()

AO2_STRING_FIELD_SORT_FN ( call_queue  ,
name   
)

◆ aqm_exec()

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

AddQueueMember application.

Definition at line 8383 of file app_queue.c.

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

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

Referenced by load_module().

◆ AST_MODULE_SELF_SYM()

struct ast_module * AST_MODULE_SELF_SYM ( void  )

Definition at line 12018 of file app_queue.c.

◆ autopause2int()

static int autopause2int ( const char *  autopause)
static

Definition at line 1977 of file app_queue.c.

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

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

Referenced by queue_set_param().

◆ calc_metric()

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

Calculate the metric of each member in the outgoing callattempts.

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

Return values
-1if penalties are exceeded
0otherwise

Definition at line 6073 of file app_queue.c.

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

References ao2_container_count(), ast_debug, ast_log, ast_random(), member::calls, member::lastcall, queue_ent::linpos, queue_ent::linwrapped, LOG_WARNING, queue_ent::max_penalty, call_queue::members, queue_ent::min_penalty, NULL, member::penalty, call_queue::penaltymemberslimit, QUEUE_STRATEGY_FEWESTCALLS, QUEUE_STRATEGY_LEASTRECENT, QUEUE_STRATEGY_LINEAR, QUEUE_STRATEGY_RANDOM, QUEUE_STRATEGY_RINGALL, QUEUE_STRATEGY_RRMEMORY, QUEUE_STRATEGY_RRORDERED, QUEUE_STRATEGY_WRANDOM, member::queuepos, queue_ent::raise_penalty, call_queue::rrpos, call_queue::strategy, tmp(), and call_queue::wrapped.

Referenced by try_calling().

◆ callattempt_free()

static void callattempt_free ( struct callattempt doomed)
static

Definition at line 4476 of file app_queue.c.

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

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

Referenced by hangupcalls(), and try_calling().

◆ can_ring_entry()

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

Definition at line 4686 of file app_queue.c.

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

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

Referenced by ring_entry().

◆ change_priority_caller_on_queue()

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

Change priority caller into a queue.

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

Definition at line 7675 of file app_queue.c.

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

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

Referenced by handle_queue_change_priority_caller(), and manager_change_priority_caller_on_queue().

◆ clear_queue()

static void clear_queue ( struct call_queue q)
static

Definition at line 3080 of file app_queue.c.

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

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

Referenced by clear_stats(), and find_queue_by_name_rt().

◆ clear_stats()

static int clear_stats ( const char *  queuename)
static

Facilitates resetting statistics for a queue.

This function actually does not reset any statistics, but rather finds a call_queue struct which corresponds to the passed-in queue name and passes that structure to the clear_queue function. If no queuename is passed in, then all queues will have their statistics reset.

Parameters
queuenameThe name of the queue to reset the statistics for. If this is NULL or zero-length, then this means to reset the statistics for all queues
Return values
0always

Definition at line 10036 of file app_queue.c.

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

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

Referenced by reload_handler().

◆ compare_weight()

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

Definition at line 4571 of file app_queue.c.

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

References ao2_find, ao2_iterator_destroy(), ao2_iterator_init(), ao2_lock, ao2_ref, ao2_t_iterator_next, ao2_unlock, ast_debug, call_queue::count, member::interface, call_queue::members, call_queue::name, num_available_members(), OBJ_POINTER, queue_t_unref, queues, and call_queue::weight.

Referenced by can_ring_entry().

◆ complete_queue()

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

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

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

Definition at line 10372 of file app_queue.c.

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

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

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

◆ complete_queue_add_member()

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

Definition at line 10879 of file app_queue.c.

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

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

Referenced by handle_queue_add_member().

◆ complete_queue_pause_member()

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

Definition at line 11304 of file app_queue.c.

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

References ast_strdup, complete_queue(), and NULL.

Referenced by handle_queue_pause_member().

◆ complete_queue_remove_member()

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

Definition at line 11139 of file app_queue.c.

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

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_lock, ao2_ref, ao2_t_iterator_next, ao2_unlock, ast_strdup, complete_queue(), member::interface, member::membername, call_queue::members, NULL, queue_t_unref, queues, and tmp().

Referenced by handle_queue_remove_member().

◆ complete_queue_rule_show()

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

Definition at line 11499 of file app_queue.c.

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

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

Referenced by handle_queue_rule_show().

◆ complete_queue_set_member_value()

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

Definition at line 11378 of file app_queue.c.

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

References ast_strdup, complete_queue(), and NULL.

Referenced by handle_queue_set_member_penalty(), and handle_queue_set_member_ringinuse().

◆ complete_queue_show()

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

Definition at line 10409 of file app_queue.c.

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

References complete_queue(), and NULL.

Referenced by queue_show().

◆ compress_char()

static int compress_char ( const char  c)
static

Definition at line 2939 of file app_queue.c.

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

References c.

Referenced by member_hash_fn().

◆ context_included()

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

Returns if one context includes another context.

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

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

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

Definition at line 2806 of file app_queue.c.

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

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

Referenced by context_included(), and extension_state_cb().

◆ copy_rules()

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

Copy rule from global list into specified queue.

Definition at line 8511 of file app_queue.c.

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

References ast_calloc, AST_LIST_INSERT_TAIL, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log, ast_strlen_zero(), call_queue::defaultrule, penalty_rule::list, rule_list::list, LOG_ERROR, penalty_rule::max_relative, penalty_rule::max_value, penalty_rule::min_relative, penalty_rule::min_value, rule_list::name, queue_ent::parent, queue_ent::qe_rules, penalty_rule::raise_relative, penalty_rule::raise_value, rule_list::rules, penalty_rule::time, and tmp().

Referenced by queue_exec().

◆ create_queue_member()

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

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

Definition at line 2894 of file app_queue.c.

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

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

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

◆ destroy_queue()

static void destroy_queue ( void *  obj)
static

Free queue's member list then its string fields.

Definition at line 3741 of file app_queue.c.

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

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

Referenced by alloc_queue().

◆ destroy_queue_member_cb()

static void destroy_queue_member_cb ( void *  obj)
static

Definition at line 2884 of file app_queue.c.

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

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

Referenced by create_queue_member().

◆ device_state_cb()

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

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

Definition at line 2670 of file app_queue.c.

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

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_lock, ao2_ref, ao2_t_iterator_next, ao2_unlock, ast_copy_string(), ast_debug, AST_DEVICE_INUSE, AST_DEVICE_NOT_INUSE, ast_device_state_message_type(), ast_devstate2str(), AST_DEVSTATE_CACHABLE, ast_devstate_changed(), ast_device_state_message::device, ast_device_state_message::eid, call_queue::found, is_member_available(), call_queue::members, call_queue::name, queue_t_unref, queues, stasis_message_data(), stasis_message_type(), ast_device_state_message::state, member::state_interface, and update_status().

Referenced by load_module().

◆ do_hang()

static void do_hang ( struct callattempt o)
static

common hangup actions

Definition at line 4656 of file app_queue.c.

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

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

Referenced by ring_entry(), and wait_for_answer().

◆ do_print()

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

direct output to manager or cli with proper terminator

Definition at line 10083 of file app_queue.c.

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

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

Referenced by __queues_show(), and print_queue().

◆ dump_queue_members()

static void dump_queue_members ( struct call_queue pm_queue)
static

Dump all members in a specific queue to the database.

<pm_family>/<queuename> = <interface>;<penalty>;<paused>;<state_interface>[|...]
static const char *const pm_family
Persistent Members astdb family.
Definition: app_queue.c:1616

Definition at line 7514 of file app_queue.c.

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

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

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

◆ end_bridge_callback()

static void end_bridge_callback ( void *  data)
static

Definition at line 6863 of file app_queue.c.

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

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

Referenced by try_calling().

◆ end_bridge_callback_data_fixup()

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

Definition at line 6856 of file app_queue.c.

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

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

Referenced by try_calling().

◆ escape_and_substitute()

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

Definition at line 6903 of file app_queue.c.

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

References input(), and pbx_substitute_variables_helper().

Referenced by setup_mixmonitor().

◆ extension_state_cb()

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

Definition at line 2835 of file app_queue.c.

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

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

Referenced by create_queue_member(), and destroy_queue_member_cb().

◆ extensionstate2devicestate()

static int extensionstate2devicestate ( int  state)
static

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

Definition at line 2757 of file app_queue.c.

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

References AST_DEVICE_BUSY, AST_DEVICE_INUSE, AST_DEVICE_INVALID, AST_DEVICE_NOT_INUSE, AST_DEVICE_ONHOLD, AST_DEVICE_RINGING, AST_DEVICE_RINGINUSE, AST_DEVICE_UNAVAILABLE, AST_EXTENSION_BUSY, AST_EXTENSION_DEACTIVATED, AST_EXTENSION_INUSE, AST_EXTENSION_NOT_INUSE, AST_EXTENSION_ONHOLD, AST_EXTENSION_REMOVED, AST_EXTENSION_RINGING, AST_EXTENSION_UNAVAILABLE, and state.

Referenced by extension_state_cb(), and get_queue_member_status().

◆ find_best()

static struct callattempt * find_best ( struct callattempt outgoing)
static

find the entry with the best metric, or NULL

Definition at line 4914 of file app_queue.c.

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

References callattempt::metric, and NULL.

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

◆ find_load_queue_rt_friendly()

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

note

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

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

Definition at line 3924 of file app_queue.c.

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

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

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

◆ find_member_by_queuename_and_interface()

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

Find a member by looking up queuename and interface.

Returns
member or NULL if member not found.

Definition at line 11998 of file app_queue.c.

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

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

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

◆ find_queue_by_name_rt()

static struct call_queue * find_queue_by_name_rt ( const char *  queuename,
struct ast_variable queue_vars,
struct ast_config member_config 
)
static

Reload a single queue via realtime.

Check for statically defined queue first, check if deleted RT queue, check for new RT queue, if queue vars are not defined init them with defaults. reload RT queue vars, set RT queue members dead and reload them, return finished queue.

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

Definition at line 3780 of file app_queue.c.

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

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

Referenced by find_load_queue_rt_friendly().

◆ free_members()

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

Iterate through queue's member list and delete them.

Definition at line 3725 of file app_queue.c.

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

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

Referenced by destroy_queue().

◆ get_interface_helper()

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

Definition at line 9029 of file app_queue.c.

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

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

Referenced by queue_function_mem_read().

◆ get_member_penalty()

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

Gets members penalty.

Returns
Return the members penalty or RESULT_FAILURE on error.

Definition at line 8098 of file app_queue.c.

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

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

Referenced by queue_function_memberpenalty_read().

◆ get_member_status()

static int get_member_status ( struct call_queue q,
int  max_penalty,
int  min_penalty,
int  raise_penalty,
enum empty_conditions  conditions,
int  devstate 
)
static

Check if members are available.

This function checks to see if members are available to be called. If any member is available, the function immediately returns 0. If no members are available, then -1 is returned.

Definition at line 2451 of file app_queue.c.

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

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_lock, ao2_ref, ao2_unlock, ast_debug, AST_DEVICE_INUSE, AST_DEVICE_INVALID, AST_DEVICE_RINGING, AST_DEVICE_UNAVAILABLE, AST_DEVICE_UNKNOWN, get_member_status(), get_wrapuptime(), member::lastcall, member::membername, call_queue::members, NULL, member::paused, member::penalty, QUEUE_EMPTY_INUSE, QUEUE_EMPTY_INVALID, QUEUE_EMPTY_PAUSED, QUEUE_EMPTY_PENALTY, QUEUE_EMPTY_RINGING, QUEUE_EMPTY_UNAVAILABLE, QUEUE_EMPTY_UNKNOWN, QUEUE_EMPTY_WRAPUP, member::state_interface, and member::status.

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

◆ get_queue_member_status()

static int get_queue_member_status ( struct member cur)
static

Return the current state of a member.

Definition at line 2879 of file app_queue.c.

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

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

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

◆ get_wrapuptime()

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

Return wrapuptime.

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

Returns
integer value

Definition at line 2020 of file app_queue.c.

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

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

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

◆ handle_attended_transfer()

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

Handle an attended transfer event.

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

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

Definition at line 6497 of file app_queue.c.

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

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

Referenced by setup_stasis_subs().

◆ handle_blind_transfer()

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

Handle a blind transfer event.

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

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

Definition at line 6438 of file app_queue.c.

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

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

Referenced by setup_stasis_subs().

◆ handle_bridge_enter()

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

Definition at line 6405 of file app_queue.c.

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

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

Referenced by setup_stasis_subs().

◆ handle_hangup()

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

Definition at line 6686 of file app_queue.c.

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

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

Referenced by setup_stasis_subs().

◆ handle_local_optimization_begin()

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

Definition at line 6571 of file app_queue.c.

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

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

Referenced by setup_stasis_subs().

◆ handle_local_optimization_end()

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

Definition at line 6622 of file app_queue.c.

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

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

Referenced by setup_stasis_subs().

◆ handle_masquerade()

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

Definition at line 6743 of file app_queue.c.

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

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

Referenced by setup_stasis_subs().

◆ handle_queue_add_member()

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

Definition at line 11054 of file app_queue.c.

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

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

◆ handle_queue_change_priority_caller()

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

Definition at line 11250 of file app_queue.c.

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