Asterisk - The Open Source Telephony Project GIT-master-754dea3
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros Modules Pages
Data Structures | Macros | Enumerations | Functions | Variables
app_queue.c File Reference

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

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

Go to the source code of this file.

Data Structures

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

Macros

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

Enumerations

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

Functions

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

Variables

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

Detailed Description

True call queues with optional send URL on answer.

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

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

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

Patch Version 1.07 2003-12-24 01

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

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

Definition in file app_queue.c.

Macro Definition Documentation

◆ ANNOUNCEHOLDTIME_ALWAYS

#define ANNOUNCEHOLDTIME_ALWAYS   1

Definition at line 1941 of file app_queue.c.

◆ ANNOUNCEHOLDTIME_ONCE

#define ANNOUNCEHOLDTIME_ONCE   2

Definition at line 1942 of file app_queue.c.

◆ ANNOUNCEPOSITION_LIMIT

#define ANNOUNCEPOSITION_LIMIT   4

We not announce position more than <limit>

Definition at line 1959 of file app_queue.c.

◆ ANNOUNCEPOSITION_MORE_THAN

#define ANNOUNCEPOSITION_MORE_THAN   3

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

Definition at line 1958 of file app_queue.c.

◆ ANNOUNCEPOSITION_NO

#define ANNOUNCEPOSITION_NO   2

We don't announce position

Definition at line 1957 of file app_queue.c.

◆ ANNOUNCEPOSITION_YES

#define ANNOUNCEPOSITION_YES   1

We announce position

Definition at line 1956 of file app_queue.c.

◆ AST_MAX_WATCHERS

#define AST_MAX_WATCHERS   256

Definition at line 5361 of file app_queue.c.

◆ DEFAULT_MIN_ANNOUNCE_FREQUENCY

#define DEFAULT_MIN_ANNOUNCE_FREQUENCY   15

The minimum number of seconds between position announcements.

Note
The default value of 15 provides backwards compatibility.

Definition at line 1728 of file app_queue.c.

◆ DEFAULT_RETRY

#define DEFAULT_RETRY   5

Definition at line 1720 of file app_queue.c.

◆ DEFAULT_TIMEOUT

#define DEFAULT_TIMEOUT   15

Definition at line 1721 of file app_queue.c.

◆ MAX_CALL_ATTEMPT_BUCKETS

#define MAX_CALL_ATTEMPT_BUCKETS   353

Definition at line 2684 of file app_queue.c.

◆ MAX_PERIODIC_ANNOUNCEMENTS

#define MAX_PERIODIC_ANNOUNCEMENTS   10

The maximum periodic announcements we can have

Definition at line 1723 of file app_queue.c.

◆ MAX_QUEUE_BUCKETS

#define MAX_QUEUE_BUCKETS   53

Definition at line 1730 of file app_queue.c.

◆ QUEUE_EVENT_VARIABLES

#define QUEUE_EVENT_VARIABLES   3

Definition at line 1943 of file app_queue.c.

◆ QUEUE_PAUSED_DEVSTATE

#define QUEUE_PAUSED_DEVSTATE   AST_DEVICE_INUSE

Definition at line 3706 of file app_queue.c.

◆ queue_ref

#define queue_ref (   q)    ao2_bump(q)

Definition at line 2225 of file app_queue.c.

◆ queue_t_ref

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

Definition at line 2227 of file app_queue.c.

◆ queue_t_unref

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

Definition at line 2228 of file app_queue.c.

◆ QUEUE_UNKNOWN_PAUSED_DEVSTATE

#define QUEUE_UNKNOWN_PAUSED_DEVSTATE   AST_DEVICE_NOT_INUSE

Definition at line 3708 of file app_queue.c.

◆ QUEUE_UNPAUSED_DEVSTATE

#define QUEUE_UNPAUSED_DEVSTATE   AST_DEVICE_NOT_INUSE

Definition at line 3707 of file app_queue.c.

◆ queue_unref

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

Definition at line 2226 of file app_queue.c.

◆ queues_t_link

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

Definition at line 2229 of file app_queue.c.

◆ queues_t_unlink

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

Definition at line 2230 of file app_queue.c.

◆ RECHECK

#define RECHECK   1

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

Definition at line 1722 of file app_queue.c.

◆ RES_EXISTS

#define RES_EXISTS   (-1)

Entry already exists

Definition at line 1733 of file app_queue.c.

◆ RES_NOSUCHQUEUE

#define RES_NOSUCHQUEUE   (-3)

No such queue

Definition at line 1735 of file app_queue.c.

◆ RES_NOT_CALLER

#define RES_NOT_CALLER   (-5)

Caller not found

Definition at line 1737 of file app_queue.c.

◆ RES_NOT_DYNAMIC

#define RES_NOT_DYNAMIC   (-4)

Member is not dynamic

Definition at line 1736 of file app_queue.c.

◆ RES_OKAY

#define RES_OKAY   0

Action completed

Definition at line 1732 of file app_queue.c.

◆ RES_OUTOFMEMORY

#define RES_OUTOFMEMORY   (-2)

Out of memory

Definition at line 1734 of file app_queue.c.

Enumeration Type Documentation

◆ anonymous enum

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

Definition at line 1597 of file app_queue.c.

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

◆ anonymous enum

anonymous enum
Enumerator
OPT_ARG_CALLEE_GO_ON 
OPT_ARG_PREDIAL_CALLEE 
OPT_ARG_PREDIAL_CALLER 
OPT_ARG_MUSICONHOLD_CLASS 
OPT_ARG_ARRAY_SIZE 

Definition at line 1622 of file app_queue.c.

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

◆ anonymous enum

anonymous enum
Enumerator
QUEUE_STRATEGY_RINGALL 
QUEUE_STRATEGY_LEASTRECENT 
QUEUE_STRATEGY_FEWESTCALLS 
QUEUE_STRATEGY_RANDOM 
QUEUE_STRATEGY_RRMEMORY 
QUEUE_STRATEGY_LINEAR 
QUEUE_STRATEGY_WRANDOM 
QUEUE_STRATEGY_RRORDERED 

Definition at line 1672 of file app_queue.c.

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

◆ anonymous enum

anonymous enum
Enumerator
QUEUE_AUTOPAUSE_OFF 
QUEUE_AUTOPAUSE_ON 
QUEUE_AUTOPAUSE_ALL 

Definition at line 1683 of file app_queue.c.

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

◆ agent_complete_reason

Enumerator
CALLER 
AGENT 
TRANSFER 

Definition at line 6292 of file app_queue.c.

6292 {
6293 CALLER,
6294 AGENT,
6295 TRANSFER
6296};
@ AGENT
Definition: app_queue.c:6294
@ CALLER
Definition: app_queue.c:6293
@ TRANSFER
Definition: app_queue.c:6295

◆ aqm_args

enum aqm_args
Enumerator
AQM_OPT_ARG_PAUSE_REASON 
AQM_OPT_ARG_ARRAY_SIZE 

Definition at line 1662 of file app_queue.c.

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

◆ aqm_flags

enum aqm_flags
Enumerator
AQMFLAG_PAUSED 
AQMFLAG_REASON 

Definition at line 1657 of file app_queue.c.

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

◆ empty_conditions

Enumerator
QUEUE_EMPTY_PENALTY 
QUEUE_EMPTY_PAUSED 
QUEUE_EMPTY_INUSE 
QUEUE_EMPTY_RINGING 
QUEUE_EMPTY_UNAVAILABLE 
QUEUE_EMPTY_INVALID 
QUEUE_EMPTY_UNKNOWN 
QUEUE_EMPTY_WRAPUP 

Definition at line 1924 of file app_queue.c.

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

◆ member_properties

Enumerator
MEMBER_PENALTY 
MEMBER_RINGINUSE 

Definition at line 1935 of file app_queue.c.

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

◆ queue_reload_mask

Enumerator
QUEUE_RELOAD_PARAMETERS 
QUEUE_RELOAD_MEMBER 
QUEUE_RELOAD_RULES 
QUEUE_RESET_STATS 

Definition at line 1689 of file app_queue.c.

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

◆ queue_result

Enumerator
QUEUE_UNKNOWN 
QUEUE_TIMEOUT 
QUEUE_JOINEMPTY 
QUEUE_LEAVEEMPTY 
QUEUE_JOINUNAVAIL 
QUEUE_LEAVEUNAVAIL 
QUEUE_FULL 
QUEUE_CONTINUE 
QUEUE_WITHDRAW 

Definition at line 1795 of file app_queue.c.

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

◆ queue_timeout_priority

Enumerator
TIMEOUT_PRIORITY_APP 
TIMEOUT_PRIORITY_CONF 

Definition at line 1822 of file app_queue.c.

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

Function Documentation

◆ __queues_show()

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

Show queue(s) status and statistics.

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

Definition at line 10368 of file app_queue.c.

10369{
10370 struct call_queue *q;
10371 struct ast_str *out = ast_str_alloca(512);
10372 struct ao2_container *sorted_queues;
10373
10374 struct ao2_iterator queue_iter;
10375 int found = 0;
10376
10377 if (argc != 2 && argc != 3) {
10378 return CLI_SHOWUSAGE;
10379 }
10380
10381 if (argc == 3) { /* specific queue */
10382 if ((q = find_load_queue_rt_friendly(argv[2]))) {
10383 ao2_lock(q);
10384 print_queue(s, fd, q);
10385 ao2_unlock(q);
10386 queue_unref(q);
10387 } else {
10388 ast_str_set(&out, 0, "No such queue: %s.", argv[2]);
10389 do_print(s, fd, ast_str_buffer(out));
10390 }
10391 return CLI_SUCCESS;
10392 }
10393
10394 if (ast_check_realtime("queues")) {
10395 /* This block is to find any queues which are defined in realtime but
10396 * which have not yet been added to the in-core container
10397 */
10398 struct ast_config *cfg = ast_load_realtime_multientry("queues", "name LIKE", "%", SENTINEL);
10399 if (cfg) {
10400 char *category = NULL;
10401 while ((category = ast_category_browse(cfg, category))) {
10402 const char *queuename = ast_variable_retrieve(cfg, category, "name");
10403 if (ast_strlen_zero(queuename)) {
10404 ast_log(LOG_WARNING, "Ignoring realtime queue with a NULL or empty 'name.'\n");
10405 continue;
10406 }
10407 if ((q = find_load_queue_rt_friendly(queuename))) {
10408 queue_t_unref(q, "Done with temporary pointer");
10409 }
10410 }
10411 ast_config_destroy(cfg);
10412 }
10413 }
10414
10415 /*
10416 * Snapping a copy of the container prevents having to lock both the queues container
10417 * and the queue itself at the same time. It also allows us to sort the entries.
10418 */
10419 sorted_queues = ao2_container_alloc_rbtree(AO2_ALLOC_OPT_LOCK_NOLOCK, 0, call_queue_sort_fn, NULL);
10420 if (!sorted_queues) {
10421 return CLI_SUCCESS;
10422 }
10423 if (ao2_container_dup(sorted_queues, queues, 0)) {
10424 ao2_ref(sorted_queues, -1);
10425 return CLI_SUCCESS;
10426 }
10427
10428 /*
10429 * No need to lock the container since it's temporary and static.
10430 * We also unlink the entries as we use them so the container is
10431 * empty when the iterator finishes. We can then just unref the container.
10432 */
10433 queue_iter = ao2_iterator_init(sorted_queues, AO2_ITERATOR_DONTLOCK | AO2_ITERATOR_UNLINK);
10434 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
10435 struct call_queue *realtime_queue = NULL;
10436 ao2_lock(q);
10437 /* This check is to make sure we don't print information for realtime
10438 * queues which have been deleted from realtime but which have not yet
10439 * been deleted from the in-core container. Only do this if we're not
10440 * looking for a specific queue.
10441 */
10442 if (q->realtime) {
10443 realtime_queue = find_load_queue_rt_friendly(q->name);
10444 if (!realtime_queue) {
10445 ao2_unlock(q);
10446 queue_t_unref(q, "Done with iterator");
10447 continue;
10448 }
10449 queue_t_unref(realtime_queue, "Queue is already in memory");
10450 }
10451
10452 found = 1;
10453 print_queue(s, fd, q);
10454
10455 ao2_unlock(q);
10456 queue_t_unref(q, "Done with iterator"); /* Unref the iterator's reference */
10457 }
10458 ao2_iterator_destroy(&queue_iter);
10459 ao2_ref(sorted_queues, -1);
10460 if (!found) {
10461 ast_str_set(&out, 0, "No queues.");
10462 do_print(s, fd, ast_str_buffer(out));
10463 }
10464 return CLI_SUCCESS;
10465}
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:10260
static struct ao2_container * queues
Definition: app_queue.c:2071
#define queue_t_unref(q, tag)
Definition: app_queue.c:2228
#define queue_unref(q)
Definition: app_queue.c:2226
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:10250
static struct call_queue * find_load_queue_rt_friendly(const char *queuename)
Definition: app_queue.c:4065
#define ast_log
Definition: astobj2.c:42
int ao2_container_dup(struct ao2_container *dest, struct ao2_container *src, enum search_flags flags)
Copy all object references in the src container into the dest container.
@ AO2_ALLOC_OPT_LOCK_NOLOCK
Definition: astobj2.h:367
#define ao2_t_iterator_next(iter, tag)
Definition: astobj2.h:1909
@ AO2_ITERATOR_UNLINK
Definition: astobj2.h:1863
@ AO2_ITERATOR_DONTLOCK
Assume that the ao2_container is already locked.
Definition: astobj2.h:1852
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
#define ao2_container_alloc_rbtree(ao2_options, container_options, sort_fn, cmp_fn)
Allocate and initialize a red-black tree container.
Definition: astobj2.h:1349
#define ao2_unlock(a)
Definition: astobj2.h:729
#define ao2_lock(a)
Definition: astobj2.h:717
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
#define CLI_SHOWUSAGE
Definition: cli.h:45
#define CLI_SUCCESS
Definition: cli.h:44
#define SENTINEL
Definition: compiler.h:87
char * ast_category_browse(struct ast_config *config, const char *prev_name)
Browse categories.
Definition: extconf.c:3326
struct ast_config * ast_load_realtime_multientry(const char *family,...) attribute_sentinel
Retrieve realtime configuration.
Definition: main/config.c:3842
int ast_check_realtime(const char *family)
Check if realtime engine is configured for family.
Definition: main/config.c:3750
void ast_config_destroy(struct ast_config *cfg)
Destroys a config.
Definition: extconf.c:1289
const char * ast_variable_retrieve(struct ast_config *config, const char *category, const char *variable)
Definition: main/config.c:869
#define LOG_WARNING
#define NULL
Definition: resample.c:96
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:761
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:65
#define ast_str_alloca(init_len)
Definition: strings.h:848
int ast_str_set(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Set a dynamic string using variable arguments.
Definition: strings.h:1113
Generic container type.
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1821
Support for dynamic strings.
Definition: strings.h:623
unsigned int realtime
Definition: app_queue.c:2015
unsigned int found
Definition: app_queue.c:2016
const ast_string_field name
Definition: app_queue.c:1999
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 12185 of file app_queue.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

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

7764{
7765 struct call_queue *q;
7766 struct member *new_member, *old_member;
7767 int res = RES_NOSUCHQUEUE;
7768
7769 /*! \note Ensure the appropriate realtime queue is loaded. Note that this
7770 * short-circuits if the queue is already in memory. */
7771 if (!(q = find_load_queue_rt_friendly(queuename))) {
7772 return res;
7773 }
7774
7775 ao2_lock(q);
7776 if ((old_member = interface_exists(q, interface)) == NULL) {
7778 new_member->dynamic = 1;
7779 if (reason_paused) {
7780 ast_copy_string(new_member->reason_paused, reason_paused, sizeof(new_member->reason_paused));
7781 }
7782 member_add_to_queue(q, new_member);
7783 queue_publish_member_blob(queue_member_added_type(), queue_member_blob_create(q, new_member));
7784
7785 if (is_member_available(q, new_member)) {
7787 }
7788
7789 ao2_ref(new_member, -1);
7790 new_member = NULL;
7791
7792 if (dump) {
7794 }
7795
7796 res = RES_OKAY;
7797 } else {
7798 res = RES_OUTOFMEMORY;
7799 }
7800 } else {
7801 ao2_ref(old_member, -1);
7802 res = RES_EXISTS;
7803 }
7804 ao2_unlock(q);
7805 queue_t_unref(q, "Expiring temporary reference");
7806
7807 return res;
7808}
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:3035
static struct member * interface_exists(struct call_queue *q, const char *interface)
Definition: app_queue.c:7628
static void dump_queue_members(struct call_queue *pm_queue)
Dump all members in a specific queue to the database.
Definition: app_queue.c:7655
static int is_member_available(struct call_queue *q, struct member *mem)
Definition: app_queue.c:2776
#define RES_OUTOFMEMORY
Definition: app_queue.c:1734
#define RES_NOSUCHQUEUE
Definition: app_queue.c:1735
#define RES_OKAY
Definition: app_queue.c:1732
static void member_add_to_queue(struct call_queue *queue, struct member *mem)
Definition: app_queue.c:3716
static struct ast_json * queue_member_blob_create(struct call_queue *q, struct member *mem)
Definition: app_queue.c:2565
#define RES_EXISTS
Definition: app_queue.c:1733
static void queue_publish_member_blob(struct stasis_message_type *type, struct ast_json *blob)
Definition: app_queue.c:2541
@ AST_DEVSTATE_CACHABLE
Definition: devicestate.h:70
int ast_devstate_changed(enum ast_device_state state, enum ast_devstate_cache cachable, const char *fmt,...)
Tells Asterisk the State for Device is changed.
Definition: devicestate.c:513
@ AST_DEVICE_NOT_INUSE
Definition: devicestate.h:54
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:425
unsigned int ringinuse
Definition: app_queue.c:2003
char interface[AST_CHANNEL_NAME]
Definition: app_queue.c:1897
int dynamic
Definition: app_queue.c:1905
char membername[80]
Definition: app_queue.c:1902
int penalty
Definition: app_queue.c:1903
int paused
Definition: app_queue.c:1908
int wrapuptime
Definition: app_queue.c:1912
char reason_paused[80]
Definition: app_queue.c:1909
char state_interface[AST_CHANNEL_NAME]
Definition: app_queue.c:1900

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

3898{
3899 struct call_queue *q;
3900
3901 if ((q = ao2_t_alloc(sizeof(*q), destroy_queue, "Allocate queue"))) {
3902 if (ast_string_field_init(q, 64)) {
3903 queue_t_unref(q, "String field allocation failed");
3904 return NULL;
3905 }
3906 ast_string_field_set(q, name, queuename);
3907 }
3908 return q;
3909}
static void destroy_queue(void *obj)
Free queue's member list then its string fields.
Definition: app_queue.c:3882
#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 8524 of file app_queue.c.

8525{
8526 int res=-1;
8527 char *parse, *tmp, *temppos = NULL, *reason = NULL;
8529 AST_APP_ARG(queuename);
8530 AST_APP_ARG(interface);
8531 AST_APP_ARG(penalty);
8533 AST_APP_ARG(membername);
8534 AST_APP_ARG(state_interface);
8535 AST_APP_ARG(wrapuptime);
8536 );
8537 int penalty = 0;
8538 int paused = 0;
8539 int wrapuptime;
8540 struct ast_flags flags = { 0 };
8541
8542 if (ast_strlen_zero(data)) {
8543 ast_log(LOG_WARNING, "AddQueueMember requires an argument (queuename[,interface[,penalty[,options[,membername[,stateinterface][,wrapuptime]]]]])\n");
8544 return -1;
8545 }
8546
8547 parse = ast_strdupa(data);
8548
8550
8551 if (args.options) {
8552 char *opts[AQM_OPT_ARG_ARRAY_SIZE] = { NULL, };
8553 ast_app_parse_options(aqm_opts, &flags, opts, args.options);
8555 paused = 1;
8557 reason = ast_strdupa(opts[AQM_OPT_ARG_PAUSE_REASON]);
8558 }
8559 }
8560 }
8561
8562 if (ast_strlen_zero(args.interface)) {
8563 args.interface = ast_strdupa(ast_channel_name(chan));
8564 temppos = strrchr(args.interface, '-');
8565 if (temppos) {
8566 *temppos = '\0';
8567 }
8568 }
8569
8570 if (!ast_strlen_zero(args.penalty)) {
8571 if ((sscanf(args.penalty, "%30d", &penalty) != 1) || penalty < 0) {
8572 ast_log(LOG_WARNING, "Penalty '%s' is invalid, must be an integer >= 0\n", args.penalty);
8573 penalty = 0;
8574 }
8575 }
8576
8577 if (!ast_strlen_zero(args.wrapuptime)) {
8578 tmp = args.wrapuptime;
8579 ast_strip(tmp);
8580 wrapuptime = atoi(tmp);
8581 if (wrapuptime < 0) {
8582 wrapuptime = 0;
8583 }
8584 } else {
8585 wrapuptime = 0;
8586 }
8587
8588 switch (add_to_queue(args.queuename, args.interface, args.membername, penalty, paused, queue_persistent_members, args.state_interface, reason, wrapuptime)) {
8589 case RES_OKAY:
8590 if (ast_strlen_zero(args.membername) || !log_membername_as_agent) {
8591 ast_queue_log(args.queuename, ast_channel_uniqueid(chan), args.interface, "ADDMEMBER", "%s", paused ? "PAUSED" : "");
8592 } else {
8593 ast_queue_log(args.queuename, ast_channel_uniqueid(chan), args.membername, "ADDMEMBER", "%s", paused ? "PAUSED" : "");
8594 }
8595 ast_log(LOG_NOTICE, "Added interface '%s' to queue '%s'\n", args.interface, args.queuename);
8596 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "ADDED");
8597 res = 0;
8598 break;
8599 case RES_EXISTS:
8600 ast_log(LOG_WARNING, "Unable to add interface '%s' to queue '%s': Already there\n", args.interface, args.queuename);
8601 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "MEMBERALREADY");
8602 res = 0;
8603 break;
8604 case RES_NOSUCHQUEUE:
8605 ast_log(LOG_WARNING, "Unable to add interface to queue '%s': No such queue\n", args.queuename);
8606 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "NOSUCHQUEUE");
8607 res = 0;
8608 break;
8609 case RES_OUTOFMEMORY:
8610 ast_log(LOG_ERROR, "Out of memory adding interface %s to queue %s\n", args.interface, args.queuename);
8611 break;
8612 }
8613
8614 return res;
8615}
static int queue_persistent_members
queues.conf [general] option
Definition: app_queue.c:1757
static int log_membername_as_agent
queues.conf [general] option
Definition: app_queue.c:1781
static const struct ast_app_option aqm_opts[128]
Definition: app_queue.c:1670
static int add_to_queue(const char *queuename, const char *interface, const char *membername, int penalty, int paused, int dump, const char *state_interface, const char *reason_paused, int wrapuptime)
Add member to queue.
Definition: app_queue.c:7763
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:298
const char * ast_channel_name(const struct ast_channel *chan)
const char * ast_channel_uniqueid(const struct ast_channel *chan)
#define AST_APP_ARG(name)
Define an application argument.
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application's arguments.
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the 'standard' argument separation process for an application.
int ast_app_parse_options(const struct ast_app_option *options, struct ast_flags *flags, char **args, char *optstr)
Parses a string containing application options and sets flags/arguments.
Definition: main/app.c:3066
void ast_queue_log(const char *queuename, const char *callid, const char *agent, const char *event, const char *fmt,...)
Definition: logger.c:962
#define LOG_ERROR
#define LOG_NOTICE
int pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value)
Add a variable to the channel variable stack, removing the most recently set value for the same name.
char * ast_strip(char *s)
Strip leading/trailing whitespace from a string.
Definition: strings.h:223
Structure used to handle boolean flags.
Definition: utils.h:199
unsigned int flags
Definition: utils.h:200
const char * args
static struct test_options options
#define ast_test_flag(p, flag)
Definition: utils.h:63

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

Referenced by load_module().

◆ AST_MODULE_SELF_SYM()

struct ast_module * AST_MODULE_SELF_SYM ( void  )

Definition at line 12185 of file app_queue.c.

◆ autopause2int()

static int autopause2int ( const char *  autopause)
static

Definition at line 2118 of file app_queue.c.

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

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

Referenced by queue_set_param().

◆ calc_metric()

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

Calculate the metric of each member in the outgoing callattempts.

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

Return values
-1if penalties are exceeded
0otherwise

Definition at line 6214 of file app_queue.c.

6215{
6216 /* disregarding penalty on too few members? */
6217 int membercount = ao2_container_count(q->members);
6218 unsigned char usepenalty = (membercount <= q->penaltymemberslimit) ? 0 : 1;
6219 int penalty = mem->penalty;
6220
6221 if (usepenalty) {
6222 if (qe->raise_penalty != INT_MAX && penalty < qe->raise_penalty) {
6223 /* Low penalty is raised up to the current minimum */
6224 penalty = qe->raise_penalty;
6225 }
6226 if ((qe->max_penalty != INT_MAX && penalty > qe->max_penalty) ||
6227 (qe->min_penalty != INT_MAX && penalty < qe->min_penalty)) {
6228 return -1;
6229 }
6230 } else {
6231 ast_debug(1, "Disregarding penalty, %d members and %d in penaltymemberslimit.\n",
6232 membercount, q->penaltymemberslimit);
6233 }
6234
6235 switch (q->strategy) {
6237 /* Everyone equal, except for penalty */
6238 tmp->metric = penalty * 1000000 * usepenalty;
6239 break;
6241 if (pos < qe->linpos) {
6242 tmp->metric = 1000 + pos;
6243 } else {
6244 if (pos > qe->linpos) {
6245 /* Indicate there is another priority */
6246 qe->linwrapped = 1;
6247 }
6248 tmp->metric = pos;
6249 }
6250 tmp->metric += penalty * 1000000 * usepenalty;
6251 break;
6254 pos = mem->queuepos;
6255 if (pos < q->rrpos) {
6256 tmp->metric = 1000 + pos;
6257 } else {
6258 if (pos > q->rrpos) {
6259 /* Indicate there is another priority */
6260 q->wrapped = 1;
6261 }
6262 tmp->metric = pos;
6263 }
6264 tmp->metric += penalty * 1000000 * usepenalty;
6265 break;
6267 tmp->metric = ast_random() % 1000;
6268 tmp->metric += penalty * 1000000 * usepenalty;
6269 break;
6271 tmp->metric = ast_random() % ((1 + penalty) * 1000);
6272 break;
6274 tmp->metric = mem->calls;
6275 tmp->metric += penalty * 1000000 * usepenalty;
6276 break;
6278 if (!mem->lastcall) {
6279 tmp->metric = 0;
6280 } else {
6281 tmp->metric = 1000000 - (time(NULL) - mem->lastcall);
6282 }
6283 tmp->metric += penalty * 1000000 * usepenalty;
6284 break;
6285 default:
6286 ast_log(LOG_WARNING, "Can't calculate metric for unknown strategy %d\n", q->strategy);
6287 break;
6288 }
6289 return 0;
6290}
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:2057
int penaltymemberslimit
Definition: app_queue.c:2041
unsigned int wrapped
Definition: app_queue.c:2009
int strategy
Definition: app_queue.c:2014
int queuepos
Definition: app_queue.c:1910
time_t lastcall
Definition: app_queue.c:1914
int calls
Definition: app_queue.c:1904
int linpos
Definition: app_queue.c:1883
int max_penalty
Definition: app_queue.c:1880
int raise_penalty
Definition: app_queue.c:1882
int min_penalty
Definition: app_queue.c:1881
int linwrapped
Definition: app_queue.c:1884
long int ast_random(void)
Definition: utils.c:2312

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

Referenced by try_calling().

◆ callattempt_free()

static void callattempt_free ( struct callattempt doomed)
static

Definition at line 4617 of file app_queue.c.

4618{
4619 if (doomed->member) {
4620 ao2_ref(doomed->member, -1);
4621 }
4623 ast_free(doomed->orig_chan_name);
4624 ast_free(doomed);
4625}
#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:2099
struct ast_party_connected_line connected
Definition: app_queue.c:1847
char * orig_chan_name
Definition: app_queue.c:1858
struct member * member
Definition: app_queue.c:1845

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

Referenced by hangupcalls(), and try_calling().

◆ can_ring_entry()

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

Definition at line 4827 of file app_queue.c.

4828{
4829 struct member *memberp = call->member;
4830 int wrapuptime;
4831
4832 if (memberp->paused) {
4833 ast_debug(1, "%s paused, can't receive call\n", call->interface);
4834 return 0;
4835 }
4836
4837 if (!memberp->ringinuse && !member_status_available(memberp->status)) {
4838 ast_debug(1, "%s not available, can't receive call\n", call->interface);
4839 return 0;
4840 }
4841
4842 if (memberp->lastqueue) {
4843 wrapuptime = get_wrapuptime(memberp->lastqueue, memberp);
4844 } else {
4845 wrapuptime = get_wrapuptime(qe->parent, memberp);
4846 }
4847 if (wrapuptime && (time(NULL) - memberp->lastcall) < wrapuptime) {
4848 ast_debug(1, "Wrapuptime not yet expired on queue %s for %s\n",
4849 (memberp->lastqueue ? memberp->lastqueue->name : qe->parent->name),
4850 call->interface);
4851 return 0;
4852 }
4853
4854 if (use_weight && compare_weight(qe->parent, memberp)) {
4855 ast_debug(1, "Priority queue delaying call to %s:%s\n",
4856 qe->parent->name, call->interface);
4857 return 0;
4858 }
4859
4861 ast_debug(1, "Another caller was waiting longer; delaying call to %s:%s\n",
4862 qe->parent->name, call->interface);
4863 return 0;
4864 }
4865
4866 if (!memberp->ringinuse) {
4867 struct member *mem;
4868
4870
4871 mem = ao2_find(pending_members, memberp,
4873 if (mem) {
4874 /*
4875 * If found that means this member is currently being attempted
4876 * from another calling thread, so stop trying from this thread
4877 */
4878 ast_debug(1, "%s has another call trying, can't receive call\n",
4879 call->interface);
4880 ao2_ref(mem, -1);
4882 return 0;
4883 }
4884
4885 /*
4886 * If not found add it to the container so another queue
4887 * won't attempt to call this member at the same time.
4888 */
4889 ast_debug(3, "Add %s to pending_members\n", memberp->membername);
4890 ao2_link(pending_members, memberp);
4892
4893 /*
4894 * The queue member is available. Get current status to be sure
4895 * because the device state and extension state callbacks may
4896 * not have updated the status yet.
4897 */
4899 ast_debug(1, "%s actually not available, can't receive call\n",
4900 call->interface);
4901 pending_members_remove(memberp);
4902 return 0;
4903 }
4904 }
4905
4906 return 1;
4907}
static int is_longest_waiting_caller(struct queue_ent *caller, struct member *member)
Definition: app_queue.c:4746
static int get_wrapuptime(struct call_queue *q, struct member *member)
Return wrapuptime.
Definition: app_queue.c:2161
static int compare_weight(struct call_queue *rq, struct member *member)
Definition: app_queue.c:4712
static struct ao2_container * pending_members
Definition: app_queue.c:2683
static int force_longest_waiting_caller
queues.conf [general] option
Definition: app_queue.c:1784
static void pending_members_remove(struct member *mem)
Definition: app_queue.c:2734
static int get_queue_member_status(struct member *cur)
Return the current state of a member.
Definition: app_queue.c:3020
static int use_weight
Records that one or more queues use weight.
Definition: app_queue.c:1760
static int member_status_available(int status)
Definition: app_queue.c:4813
#define ao2_link(container, obj)
Add an object to a container.
Definition: astobj2.h:1532
#define ao2_find(container, arg, flags)
Definition: astobj2.h:1736
@ OBJ_SEARCH_OBJECT
The arg parameter is an object of the same type.
Definition: astobj2.h:1087
@ OBJ_NOLOCK
Assume that the ao2_container is already locked.
Definition: astobj2.h:1063
static int call(void *data)
Definition: chan_pjsip.c:2395
int status
Definition: app_queue.c:1907
unsigned int ringinuse
Definition: app_queue.c:1921
struct call_queue * lastqueue
Definition: app_queue.c:1917
struct call_queue * parent
Definition: app_queue.c:1863

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

Referenced by ring_entry().

◆ change_priority_caller_on_queue()

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

Change priority caller into a queue.

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

Definition at line 7816 of file app_queue.c.

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

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

3222{
3223 q->holdtime = 0;
3224 q->callscompleted = 0;
3225 q->callsabandoned = 0;
3226 q->callscompletedinsl = 0;
3227 q->callsabandonedinsl = 0;
3228 q->talktime = 0;
3229
3230 if (q->members) {
3231 struct member *mem;
3232 struct ao2_iterator mem_iter = ao2_iterator_init(q->members, 0);
3233 while ((mem = ao2_iterator_next(&mem_iter))) {
3234 mem->calls = 0;
3235 mem->callcompletedinsl = 0;
3236 mem->lastcall = 0;
3237 mem->starttime = 0;
3238 ao2_ref(mem, -1);
3239 }
3240 ao2_iterator_destroy(&mem_iter);
3241 }
3242}
#define ao2_iterator_next(iter)
Definition: astobj2.h:1911
int talktime
Definition: app_queue.c:2031
int callsabandoned
Definition: app_queue.c:2033
int callscompleted
Definition: app_queue.c:2032
int callsabandonedinsl
Definition: app_queue.c:2034
int callscompletedinsl
Definition: app_queue.c:2036
int holdtime
Definition: app_queue.c:2030
time_t starttime
Definition: app_queue.c:1913
int callcompletedinsl
Definition: app_queue.c:1911

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

10204{
10205 struct call_queue *q;
10206 struct ao2_iterator queue_iter;
10207
10208 queue_iter = ao2_iterator_init(queues, 0);
10209 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
10210 ao2_lock(q);
10211 if (ast_strlen_zero(queuename) || !strcasecmp(q->name, queuename))
10212 clear_queue(q);
10213 ao2_unlock(q);
10214 queue_t_unref(q, "Done with iterator");
10215 }
10216 ao2_iterator_destroy(&queue_iter);
10217 return 0;
10218}
static void clear_queue(struct call_queue *q)
Definition: app_queue.c:3221

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

4713{
4714 struct call_queue *q;
4715 struct member *mem;
4716 int found = 0;
4717 struct ao2_iterator queue_iter;
4718
4719 queue_iter = ao2_iterator_init(queues, 0);
4720 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
4721 if (q == rq) { /* don't check myself, could deadlock */
4722 queue_t_unref(q, "Done with iterator");
4723 continue;
4724 }
4725 ao2_lock(q);
4726 if (q->count && q->members) {
4727 if ((mem = ao2_find(q->members, member, OBJ_POINTER))) {
4728 ast_debug(1, "Found matching member %s in queue '%s'\n", mem->interface, q->name);
4729 if (q->weight > rq->weight && q->count >= num_available_members(q)) {
4730 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);
4731 found = 1;
4732 }
4733 ao2_ref(mem, -1);
4734 }
4735 }
4736 ao2_unlock(q);
4737 queue_t_unref(q, "Done with iterator");
4738 if (found) {
4739 break;
4740 }
4741 }
4742 ao2_iterator_destroy(&queue_iter);
4743 return found;
4744}
static int num_available_members(struct call_queue *q)
Get the number of members available to accept a call.
Definition: app_queue.c:4679
#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 10539 of file app_queue.c.

10540{
10541 struct call_queue *q;
10542 char *ret = NULL;
10543 int which = 0;
10544 int wordlen = strlen(word);
10545 struct ao2_iterator queue_iter;
10546 const char *word_list = NULL;
10547
10548 /* for certain commands, already completed items should be left out of
10549 * the list */
10550 if (word_list_offset && strlen(line) >= word_list_offset) {
10551 word_list = line + word_list_offset;
10552 }
10553
10554 queue_iter = ao2_iterator_init(queues, 0);
10555 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
10556 if (!strncasecmp(word, q->name, wordlen) && ++which > state
10557 && (!word_list_offset || !word_in_list(word_list, q->name))) {
10558 ret = ast_strdup(q->name);
10559 queue_t_unref(q, "Done with iterator");
10560 break;
10561 }
10562 queue_t_unref(q, "Done with iterator");
10563 }
10564 ao2_iterator_destroy(&queue_iter);
10565
10566 /* Pretend "rules" is at the end of the queues list in certain
10567 * circumstances since it is an alternate command that should be
10568 * tab-completable for "queue show" */
10569 if (!ret && which == state && !wordlen && !strncmp("queue show", line, 10)) {
10570 ret = ast_strdup("rules");
10571 }
10572
10573 return ret;
10574}
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:10480
#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 11046 of file app_queue.c.

11047{
11048 /* 0 - queue; 1 - add; 2 - member; 3 - <interface>; 4 - to; 5 - <queue>; 6 - penalty; 7 - <penalty>; 8 - as; 9 - <membername> */
11049 switch (pos) {
11050 case 3: /* Don't attempt to complete name of interface (infinite possibilities) */
11051 return NULL;
11052 case 4: /* only one possible match, "to" */
11053 return state == 0 ? ast_strdup("to") : NULL;
11054 case 5: /* <queue> */
11055 return complete_queue(line, word, pos, state, 0);
11056 case 6: /* only one possible match, "penalty" */
11057 return state == 0 ? ast_strdup("penalty") : NULL;
11058 case 7:
11059 if (0 <= state && state < 100) { /* 0-99 */
11060 char *num;
11061 if ((num = ast_malloc(3))) {
11062 sprintf(num, "%d", state);
11063 }
11064 return num;
11065 } else {
11066 return NULL;
11067 }
11068 case 8: /* only one possible match, "as" */
11069 return state == 0 ? ast_strdup("as") : NULL;
11070 case 9: /* Don't attempt to complete name of member (infinite possibilities) */
11071 return NULL;
11072 default:
11073 return NULL;
11074 }
11075}
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:10539
#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 11471 of file app_queue.c.

11472{
11473 /* 0 - queue; 1 - pause; 2 - member; 3 - <interface>; 4 - queue; 5 - <queue>; 6 - reason; 7 - <reason> */
11474 switch (pos) {
11475 case 3: /* Don't attempt to complete name of interface (infinite possibilities) */
11476 return NULL;
11477 case 4: /* only one possible match, "queue" */
11478 return state == 0 ? ast_strdup("queue") : NULL;
11479 case 5: /* <queue> */
11480 return complete_queue(line, word, pos, state, 0);
11481 case 6: /* "reason" */
11482 return state == 0 ? ast_strdup("reason") : NULL;
11483 case 7: /* Can't autocomplete a reason, since it's 100% customizeable */
11484 return NULL;
11485 default:
11486 return NULL;
11487 }
11488}

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

11307{
11308 int which = 0;
11309 struct call_queue *q;
11310 struct member *m;
11311 struct ao2_iterator queue_iter;
11312 struct ao2_iterator mem_iter;
11313 int wordlen = strlen(word);
11314
11315 /* 0 - queue; 1 - remove; 2 - member; 3 - <member>; 4 - from; 5 - <queue> */
11316 if (pos > 5 || pos < 3) {
11317 return NULL;
11318 }
11319 if (pos == 4) { /* only one possible match, 'from' */
11320 return (state == 0 ? ast_strdup("from") : NULL);
11321 }
11322
11323 if (pos == 5) { /* No need to duplicate code */
11324 return complete_queue(line, word, pos, state, 0);
11325 }
11326
11327 /* here is the case for 3, <member> */
11328 queue_iter = ao2_iterator_init(queues, 0);
11329 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
11330 ao2_lock(q);
11331 mem_iter = ao2_iterator_init(q->members, 0);
11332 while ((m = ao2_iterator_next(&mem_iter))) {
11333 if (!strncasecmp(word, m->membername, wordlen) && ++which > state) {
11334 char *tmp;
11335 tmp = ast_strdup(m->interface);
11336 ao2_ref(m, -1);
11337 ao2_iterator_destroy(&mem_iter);
11338 ao2_unlock(q);
11339 queue_t_unref(q, "Done with iterator, returning interface name");
11340 ao2_iterator_destroy(&queue_iter);
11341 return tmp;
11342 }
11343 ao2_ref(m, -1);
11344 }
11345 ao2_iterator_destroy(&mem_iter);
11346 ao2_unlock(q);
11347 queue_t_unref(q, "Done with iterator");
11348 }
11349 ao2_iterator_destroy(&queue_iter);
11350
11351 return NULL;
11352}

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

Referenced by handle_queue_remove_member().

◆ complete_queue_rule_show()

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

Definition at line 11666 of file app_queue.c.

11667{
11668 int which = 0;
11669 struct rule_list *rl_iter;
11670 int wordlen = strlen(word);
11671 char *ret = NULL;
11672 if (pos != 3) /* Wha? */ {
11673 return NULL;
11674 }
11675
11677 AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) {
11678 if (!strncasecmp(word, rl_iter->name, wordlen) && ++which > state) {
11679 ret = ast_strdup(rl_iter->name);
11680 break;
11681 }
11682 }
11684
11685 return ret;
11686}
#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:2064
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 11545 of file app_queue.c.

11546{
11547 /* 0 - queue; 1 - set; 2 - penalty/ringinuse; 3 - <value>; 4 - on; 5 - <member>; 6 - in; 7 - <queue>;*/
11548 switch (pos) {
11549 case 4:
11550 if (state == 0) {
11551 return ast_strdup("on");
11552 } else {
11553 return NULL;
11554 }
11555 case 6:
11556 if (state == 0) {
11557 return ast_strdup("in");
11558 } else {
11559 return NULL;
11560 }
11561 case 7:
11562 return complete_queue(line, word, pos, state, 0);
11563 default:
11564 return NULL;
11565 }
11566}

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

10577{
10578 if (pos == 2) {
10579 return complete_queue(line, word, pos, state, 0);
10580 }
10581 return NULL;
10582}

References complete_queue(), and NULL.

Referenced by queue_show().

◆ compress_char()

static int compress_char ( const char  c)
static

Definition at line 3080 of file app_queue.c.

3081{
3082 if (c < 32) {
3083 return 0;
3084 } else if (c > 96) {
3085 return c - 64;
3086 }
3087 return c - 32;
3088}
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 2947 of file app_queue.c.

2948{
2949 struct ast_context *c = NULL;
2950
2951 c = ast_context_find(parent);
2952 if (!c) {
2953 /* well, if parent doesn't exist, how can the child be included in it? */
2954 return 0;
2955 }
2956 if (!strcmp(ast_get_context_name(c), parent)) {
2957 /* found the context of the hint app_queue is using. Now, see
2958 if that context includes the one that just changed state */
2959 struct ast_include *inc = NULL;
2960
2961 while ((inc = (struct ast_include*) ast_walk_context_includes(c, inc))) {
2962 const char *includename = ast_get_include_name(inc);
2963 if (!strcasecmp(child, includename)) {
2964 return 1;
2965 }
2966 /* recurse on this context, for nested includes. The
2967 PBX extension parser will prevent infinite recursion. */
2968 if (context_included(includename, child)) {
2969 return 1;
2970 }
2971 }
2972 }
2973 return 0;
2974}
static int context_included(const char *parent, const char *child)
Returns if one context includes another context.
Definition: app_queue.c:2947
const struct ast_include * ast_walk_context_includes(const struct ast_context *con, const struct ast_include *inc)
Definition: pbx.c:8665
struct ast_context * ast_context_find(const char *name)
Find a context.
Definition: extconf.c:4172
const char * ast_get_include_name(const struct ast_include *include)
Definition: pbx_include.c:50
const char * ast_get_context_name(struct ast_context *con)
Definition: ael_main.c:421
ast_context: An extension context
Definition: pbx.c:299
ast_include: include= support in extensions.conf
Definition: pbx_include.c:37

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

Referenced by context_included(), and extension_state_cb().

◆ copy_rules()

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

Copy rule from global list into specified queue.

Definition at line 8652 of file app_queue.c.

8653{
8654 struct penalty_rule *pr_iter;
8655 struct rule_list *rl_iter;
8656 const char *tmp = ast_strlen_zero(rulename) ? qe->parent->defaultrule : rulename;
8658 AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) {
8659 if (!strcasecmp(rl_iter->name, tmp)) {
8660 break;
8661 }
8662 }
8663 if (rl_iter) {
8664 AST_LIST_TRAVERSE(&rl_iter->rules, pr_iter, list) {
8665 struct penalty_rule *new_pr = ast_calloc(1, sizeof(*new_pr));
8666 if (!new_pr) {
8667 ast_log(LOG_ERROR, "Memory allocation error when copying penalty rules! Aborting!\n");
8668 break;
8669 }
8670 new_pr->time = pr_iter->time;
8671 new_pr->max_value = pr_iter->max_value;
8672 new_pr->min_value = pr_iter->min_value;
8673 new_pr->raise_value = pr_iter->raise_value;
8674 new_pr->max_relative = pr_iter->max_relative;
8675 new_pr->min_relative = pr_iter->min_relative;
8676 new_pr->raise_relative = pr_iter->raise_relative;
8677 AST_LIST_INSERT_TAIL(&qe->qe_rules, new_pr, list);
8678 }
8679 }
8681}
#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:1999
int raise_relative
Definition: app_queue.c:1952
struct penalty_rule::@52 list
int min_relative
Definition: app_queue.c:1951
int max_relative
Definition: app_queue.c:1950
struct queue_ent::@51 qe_rules
struct rule_list::@55 rules

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

Referenced by queue_exec().

◆ create_queue_member()

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

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

Definition at line 3035 of file app_queue.c.

3036{
3037 struct member *cur;
3038
3039 if ((cur = ao2_alloc(sizeof(*cur), destroy_queue_member_cb))) {
3040 cur->ringinuse = ringinuse;
3041 cur->penalty = penalty;
3042 cur->paused = paused;
3043 cur->wrapuptime = wrapuptime;
3044 if (paused) {
3045 time(&cur->lastpause); /* Update time of last pause */
3046 }
3047 time(&cur->logintime);
3048 ast_copy_string(cur->interface, interface, sizeof(cur->interface));
3051 } else {
3053 }
3055 ast_copy_string(cur->membername, membername, sizeof(cur->membername));
3056 } else {
3057 ast_copy_string(cur->membername, interface, sizeof(cur->membername));
3058 }
3059 if (!strchr(cur->interface, '/')) {
3060 ast_log(LOG_WARNING, "No location at interface '%s'\n", interface);
3061 }
3062 if (!strncmp(cur->state_interface, "hint:", 5)) {
3063 char *tmp = ast_strdupa(cur->state_interface), *context = tmp;
3064 char *exten = strsep(&context, "@") + 5;
3065
3066 ast_copy_string(cur->state_exten, exten, sizeof(cur->state_exten));
3067 ast_copy_string(cur->state_context, S_OR(context, "default"), sizeof(cur->state_context));
3068
3070 } else {
3071 cur->state_id = -1;
3072 }
3073 cur->status = get_queue_member_status(cur);
3074 }
3075
3076 return cur;
3077}
static int extension_state_cb(const char *context, const char *exten, struct ast_state_cb_info *info, void *data)
Definition: app_queue.c:2976
static void destroy_queue_member_cb(void *obj)
Definition: app_queue.c:3025
char * strsep(char **str, const char *delims)
#define ao2_alloc(data_size, destructor_fn)
Definition: astobj2.h:409
int ast_extension_state_add(const char *context, const char *exten, ast_state_cb_type change_cb, void *data)
Add watcher for extension states.
Definition: pbx.c:3838
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one.
Definition: strings.h:80
time_t logintime
Definition: app_queue.c:1916
char state_exten[AST_MAX_EXTENSION]
Definition: app_queue.c:1898
char state_context[AST_MAX_CONTEXT]
Definition: app_queue.c:1899
int state_id
Definition: app_queue.c:1901
time_t lastpause
Definition: app_queue.c:1915

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

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

◆ destroy_queue()

static void destroy_queue ( void *  obj)
static

Free queue's member list then its string fields.

Definition at line 3882 of file app_queue.c.

3883{
3884 struct call_queue *q = obj;
3885 int i;
3886
3887 free_members(q, 1);
3889 for (i = 0; i < MAX_PERIODIC_ANNOUNCEMENTS; i++) {
3890 if (q->sound_periodicannounce[i]) {
3892 }
3893 }
3894 ao2_ref(q->members, -1);
3895}
#define MAX_PERIODIC_ANNOUNCEMENTS
Definition: app_queue.c:1723
static void free_members(struct call_queue *q, int all)
Iterate through queue's member list and delete them.
Definition: app_queue.c:3866
#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:2001

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

3026{
3027 struct member *mem = obj;
3028
3029 if (mem->state_id != -1) {
3031 }
3032}
int ast_extension_state_del(int id, ast_state_cb_type change_cb)
Deletes a state change watcher by ID.
Definition: pbx.c:3871

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

Referenced by create_queue_member().

◆ device_state_cb()

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

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

Definition at line 2811 of file app_queue.c.

2812{
2813 struct ao2_iterator miter, qiter;
2814 struct ast_device_state_message *dev_state;
2815 struct member *m;
2816 struct call_queue *q;
2817 char interface[80], *slash_pos;
2818 int found = 0; /* Found this member in any queue */
2819 int found_member; /* Found this member in this queue */
2820 int avail = 0; /* Found an available member in this queue */
2821
2823 return;
2824 }
2825
2826 dev_state = stasis_message_data(msg);
2827 if (dev_state->eid) {
2828 /* ignore non-aggregate states */
2829 return;
2830 }
2831
2832 qiter = ao2_iterator_init(queues, 0);
2833 while ((q = ao2_t_iterator_next(&qiter, "Iterate over queues"))) {
2834 ao2_lock(q);
2835
2836 avail = 0;
2837 found_member = 0;
2838 miter = ao2_iterator_init(q->members, 0);
2839 for (; (m = ao2_iterator_next(&miter)); ao2_ref(m, -1)) {
2840 if (!found_member) {
2841 ast_copy_string(interface, m->state_interface, sizeof(interface));
2842
2843 if ((slash_pos = strchr(interface, '/'))) {
2844 if (!strncasecmp(interface, "Local/", 6) && (slash_pos = strchr(slash_pos + 1, '/'))) {
2845 *slash_pos = '\0';
2846 }
2847 }
2848
2849 if (!strcasecmp(interface, dev_state->device)) {
2850 found_member = 1;
2851 update_status(q, m, dev_state->state);
2852 }
2853 }
2854
2855 /* check every member until we find one NOT_INUSE */
2856 if (!avail) {
2857 avail = is_member_available(q, m);
2858 }
2859 if (avail && found_member) {
2860 /* early exit as we've found an available member and the member of interest */
2861 ao2_ref(m, -1);
2862 break;
2863 }
2864 }
2865
2866 if (found_member) {
2867 found = 1;
2868 if (avail) {
2870 } else {
2872 }
2873 }
2874
2875 ao2_iterator_destroy(&miter);
2876
2877 ao2_unlock(q);
2878 queue_t_unref(q, "Done with iterator");
2879 }
2880 ao2_iterator_destroy(&qiter);
2881
2882 if (found) {
2883 ast_debug(1, "Device '%s' changed to state '%u' (%s)\n",
2884 dev_state->device,
2885 dev_state->state,
2886 ast_devstate2str(dev_state->state));
2887 } else {
2888 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",
2889 dev_state->device,
2890 dev_state->state,
2891 ast_devstate2str(dev_state->state));
2892 }
2893
2894 return;
2895}
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:2745
struct stasis_message_type * ast_device_state_message_type(void)
Get the Stasis message type for device state messages.
const char * ast_devstate2str(enum ast_device_state devstate) attribute_pure
Convert device state to text string for output.
Definition: devicestate.c:240
@ AST_DEVICE_INUSE
Definition: devicestate.h:55
struct stasis_message_type * stasis_message_type(const struct stasis_message *msg)
Get the message type for a stasis_message.
void * stasis_message_data(const struct stasis_message *msg)
Get the data contained in a message.
The structure that contains device state.
Definition: devicestate.h:238
enum ast_device_state state
Definition: devicestate.h:248
const struct ast_eid * eid
The EID of the server where this message originated.
Definition: devicestate.h:246

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

Referenced by load_module().

◆ do_hang()

static void do_hang ( struct callattempt o)
static

common hangup actions

Definition at line 4797 of file app_queue.c.

4798{
4799 o->stillgoing = 0;
4800 ast_hangup(o->chan);
4802 o->chan = NULL;
4803}
void ast_hangup(struct ast_channel *chan)
Hang up a channel.
Definition: channel.c:2570
struct ast_channel * chan
Definition: app_queue.c:1842
unsigned int stillgoing
Definition: app_queue.c:1855

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

Referenced by ring_entry(), and wait_for_answer().

◆ do_print()

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

direct output to manager or cli with proper terminator

Definition at line 10250 of file app_queue.c.

10251{
10252 if (s) {
10253 astman_append(s, "%s\r\n", str);
10254 } else {
10255 ast_cli(fd, "%s\n", str);
10256 }
10257}
const char * str
Definition: app_jack.c:150
void ast_cli(int fd, const char *fmt,...)
Definition: clicompat.c:6
void astman_append(struct mansession *s, const char *fmt,...)
Definition: manager.c:1907

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

Referenced by __queues_show(), and print_queue().

◆ dump_queue_members()

static void dump_queue_members ( struct call_queue pm_queue)
static

Dump all members in a specific queue to the database.

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

Definition at line 7655 of file app_queue.c.

7656{
7657 struct member *cur_member;
7658 struct ast_str *value;
7659 struct ao2_iterator mem_iter;
7660
7661 if (!pm_queue) {
7662 return;
7663 }
7664
7665 /* 4K is a reasonable default for most applications, but we grow to
7666 * accommodate more if necessary. */
7667 if (!(value = ast_str_create(4096))) {
7668 return;
7669 }
7670
7671 mem_iter = ao2_iterator_init(pm_queue->members, 0);
7672 while ((cur_member = ao2_iterator_next(&mem_iter))) {
7673 if (!cur_member->dynamic) {
7674 ao2_ref(cur_member, -1);
7675 continue;
7676 }
7677
7678 ast_str_append(&value, 0, "%s%s;%d;%d;%s;%s;%s;%d",
7679 ast_str_strlen(value) ? "|" : "",
7680 cur_member->interface,
7681 cur_member->penalty,
7682 cur_member->paused,
7683 cur_member->membername,
7684 cur_member->state_interface,
7685 cur_member->reason_paused,
7686 cur_member->wrapuptime);
7687
7688 ao2_ref(cur_member, -1);
7689 }
7690 ao2_iterator_destroy(&mem_iter);
7691
7692 if (ast_str_strlen(value) && !cur_member) {
7693 if (ast_db_put(pm_family, pm_queue->name, ast_str_buffer(value))) {
7694 ast_log(LOG_WARNING, "failed to create persistent dynamic entry!\n");
7695 }
7696 } else {
7697 /* Delete the entry if the queue is empty or there is an error */
7698 ast_db_del(pm_family, pm_queue->name);
7699 }
7700
7701 ast_free(value);
7702}
int ast_db_put(const char *family, const char *key, const char *value)
Store value addressed by family/key.
Definition: db.c:335
int ast_db_del(const char *family, const char *key)
Delete entry in astdb.
Definition: db.c:472
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
Definition: strings.h:1139
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
Definition: strings.h:659
size_t ast_str_strlen(const struct ast_str *buf)
Returns the current length of the string stored within buf.
Definition: strings.h:730
int value
Definition: syslog.c:37

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

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

◆ end_bridge_callback()

static void end_bridge_callback ( void *  data)
static

Definition at line 7004 of file app_queue.c.

7005{
7006 struct queue_end_bridge *qeb = data;
7007 struct call_queue *q = qeb->q;
7008 struct ast_channel *chan = qeb->chan;
7009
7010 if (ao2_ref(qeb, -1) == 1) {
7011 set_queue_variables(q, chan);
7012 /* This unrefs the reference we made in try_calling when we allocated qeb */
7013 queue_t_unref(q, "Expire bridge_config reference");
7014 }
7015}
static void set_queue_variables(struct call_queue *q, struct ast_channel *chan)
Set variables of queue.
Definition: app_queue.c:2233
Main Channel structure associated with a channel.
struct call_queue * q
Definition: app_queue.c:6993
struct ast_channel * chan
Definition: app_queue.c:6994

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

6998{
6999 struct queue_end_bridge *qeb = bconfig->end_bridge_callback_data;
7000 ao2_ref(qeb, +1);
7001 qeb->chan = originator;
7002}
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 7044 of file app_queue.c.

7046{
7047 const char *m = input;
7048 char escaped[size];
7049 char *p;
7050
7051 for (p = escaped; p < escaped + size - 1; p++, m++) {
7052 switch (*m) {
7053 case '^':
7054 if (*(m + 1) == '{') {
7055 *p = '$';
7056 }
7057 break;
7058 case ',':
7059 *p++ = '\\';
7060 /* Fall through */
7061 default:
7062 *p = *m;
7063 }
7064 if (*m == '\0')
7065 break;
7066 }
7067
7068 if (p == escaped + size) {
7069 escaped[size - 1] = '\0';
7070 }
7071
7072 pbx_substitute_variables_helper(chan, escaped, output, size - 1);
7073}
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 2976 of file app_queue.c.

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

2899{
2900 switch (state) {
2903 break;
2906 break;
2907 case AST_EXTENSION_BUSY:
2909 break;
2912 break;
2915 break;
2918 break;
2921 break;
2924 break;
2927 default:
2929 break;
2930 }
2931
2932 return state;
2933}
enum cc_state state
Definition: ccss.c:399
@ AST_DEVICE_RINGINUSE
Definition: devicestate.h:60
@ AST_DEVICE_ONHOLD
Definition: devicestate.h:61
@ AST_DEVICE_RINGING
Definition: devicestate.h:59
@ AST_DEVICE_INVALID
Definition: devicestate.h:57
@ AST_DEVICE_BUSY
Definition: devicestate.h:56
@ AST_DEVICE_UNAVAILABLE
Definition: devicestate.h:58
@ AST_EXTENSION_REMOVED
Definition: pbx.h:62
@ AST_EXTENSION_RINGING
Definition: pbx.h:68
@ AST_EXTENSION_NOT_INUSE
Definition: pbx.h:64
@ AST_EXTENSION_INUSE
Definition: pbx.h:65
@ AST_EXTENSION_UNAVAILABLE
Definition: pbx.h:67
@ AST_EXTENSION_ONHOLD
Definition: pbx.h:69
@ AST_EXTENSION_BUSY
Definition: pbx.h:66
@ AST_EXTENSION_DEACTIVATED
Definition: pbx.h:63

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

Referenced by extension_state_cb(), and get_queue_member_status().

◆ find_best()

static struct callattempt * find_best ( struct callattempt outgoing)
static

find the entry with the best metric, or NULL

Definition at line 5055 of file app_queue.c.

5056{
5057 struct callattempt *best = NULL, *cur;
5058
5059 for (cur = outgoing; cur; cur = cur->q_next) {
5060 if (cur->stillgoing && /* Not already done */
5061 !cur->chan && /* Isn't already going */
5062 (!best || cur->metric < best->metric)) { /* We haven't found one yet, or it's better */
5063 best = cur;
5064 }
5065 }
5066
5067 return best;
5068}
We define a custom "local user" structure because we use it not only for keeping track of what is in ...
Definition: app_queue.c:1839

References callattempt::metric, and NULL.

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

◆ find_load_queue_rt_friendly()

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

note

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

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

Definition at line 4065 of file app_queue.c.

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

12166{
12167 struct member *mem = NULL;
12168 struct call_queue *q;
12169
12170 if ((q = find_load_queue_rt_friendly(queuename))) {
12171 ao2_lock(q);
12172 mem = ao2_find(q->members, interface, OBJ_KEY);
12173 ao2_unlock(q);
12174 queue_t_unref(q, "Expiring temporary reference.");
12175 }
12176 return mem;
12177}
#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 3921 of file app_queue.c.

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

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

Referenced by find_load_queue_rt_friendly().

◆ free_members()

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

Iterate through queue's member list and delete them.

Definition at line 3866 of file app_queue.c.

3867{
3868 /* Free non-dynamic members */
3869 struct member *cur;
3870 struct ao2_iterator mem_iter = ao2_iterator_init(q->members, 0);
3871
3872 while ((cur = ao2_iterator_next(&mem_iter))) {
3873 if (all || !cur->dynamic) {
3875 }
3876 ao2_ref(cur, -1);
3877 }
3878 ao2_iterator_destroy(&mem_iter);
3879}

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

Referenced by destroy_queue().

◆ get_interface_helper()

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

Definition at line 9192 of file app_queue.c.

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

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

Referenced by queue_function_mem_read().

◆ get_member_penalty()

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

Gets members penalty.

Returns
Return the members penalty or RESULT_FAILURE on error.

Definition at line 8239 of file app_queue.c.

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

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

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

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

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

◆ get_wrapuptime()

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

Return wrapuptime.

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

Returns
integer value

Definition at line 2161 of file app_queue.c.

2162{
2163 if (member->wrapuptime) {
2164 return member->wrapuptime;
2165 }
2166 return q->wrapuptime;
2167}
int wrapuptime
Definition: app_queue.c:2040

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

6640{
6641 struct queue_stasis_data *queue_data = userdata;
6642 struct ast_attended_transfer_message *atxfer_msg = stasis_message_data(msg);
6643 RAII_VAR(struct ast_channel_snapshot *, caller_snapshot, NULL, ao2_cleanup);
6644 RAII_VAR(struct ast_channel_snapshot *, member_snapshot, NULL, ao2_cleanup);
6645
6646 if (atxfer_msg->result != AST_BRIDGE_TRANSFER_SUCCESS ||
6648 return;
6649 }
6650
6651 ao2_lock(queue_data);
6652
6653 if (queue_data->dying) {
6654 ao2_unlock(queue_data);
6655 return;
6656 }
6657
6658 if (ast_strlen_zero(queue_data->bridge_uniqueid)) {
6659 ao2_unlock(queue_data);
6660 return;
6661 }
6662
6663 if ((!atxfer_msg->to_transferee.bridge_snapshot || strcmp(queue_data->bridge_uniqueid,
6664 atxfer_msg->to_transferee.bridge_snapshot->uniqueid)) &&
6665 (!atxfer_msg->to_transfer_target.bridge_snapshot || strcmp(queue_data->bridge_uniqueid,
6667 ao2_unlock(queue_data);
6668 return;
6669 }
6670
6671 caller_snapshot = ast_channel_snapshot_get_latest(queue_data->caller_uniqueid);
6672 member_snapshot = ast_channel_snapshot_get_latest(queue_data->member_uniqueid);
6673
6674 ao2_unlock(queue_data);
6675
6676 ast_debug(3, "Detected attended transfer in queue %s\n", queue_data->queue->name);
6677 log_attended_transfer(queue_data, atxfer_msg);
6678
6679 send_agent_complete(queue_data->queue->name, caller_snapshot, member_snapshot, queue_data->member,
6680 queue_data->holdstart, queue_data->starttime, TRANSFER);
6681 update_queue(queue_data->queue, queue_data->member, queue_data->callcompletedinsl,
6682 queue_data->starttime);
6683 remove_stasis_subscriptions(queue_data);
6684}
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:6299
static int update_queue(struct call_queue *q, struct member *member, int callcompletedinsl, time_t starttime)
update the queue status
Definition: app_queue.c:6142
static void remove_stasis_subscriptions(struct queue_stasis_data *queue_data)
Definition: app_queue.c:6446
static void log_attended_transfer(struct queue_stasis_data *queue_data, struct ast_attended_transfer_message *atxfer_msg)
Definition: app_queue.c:6500
#define ao2_cleanup(obj)
Definition: astobj2.h:1934
@ AST_BRIDGE_TRANSFER_SUCCESS
Definition: bridge.h:1104
struct ast_channel_snapshot * ast_channel_snapshot_get_latest(const char *uniqueid)
Obtain the latest ast_channel_snapshot from the Stasis Message Bus API cache. This is an ao2 object,...
@ AST_ATTENDED_TRANSFER_DEST_THREEWAY
Message representing attended transfer.
enum ast_attended_transfer_dest_type dest_type
struct ast_bridge_channel_snapshot_pair to_transfer_target
enum ast_transfer_result result
struct ast_bridge_channel_snapshot_pair to_transferee
struct ast_bridge_snapshot * bridge_snapshot
const ast_string_field uniqueid
Definition: bridge.h:332
Structure representing a snapshot of channel state.
User data for stasis subscriptions used for queue calls.
Definition: app_queue.c:6392
const ast_string_field caller_uniqueid
Definition: app_queue.c:6400
const ast_string_field member_uniqueid
Definition: app_queue.c:6400
struct call_queue * queue
Definition: app_queue.c:6402
const ast_string_field bridge_uniqueid
Definition: app_queue.c:6400
struct member * member
Definition: app_queue.c:6404
#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 6579 of file app_queue.c.

6581{
6582 struct queue_stasis_data *queue_data = userdata;
6583 struct ast_blind_transfer_message *transfer_msg = stasis_message_data(msg);
6584 const char *exten;
6585 const char *context;
6586 RAII_VAR(struct ast_channel_snapshot *, caller_snapshot, NULL, ao2_cleanup);
6587 RAII_VAR(struct ast_channel_snapshot *, member_snapshot, NULL, ao2_cleanup);
6588
6589 if (transfer_msg->result != AST_BRIDGE_TRANSFER_SUCCESS) {
6590 return;
6591 }
6592
6593 ao2_lock(queue_data);
6594
6595 if (queue_data->dying) {
6596 ao2_unlock(queue_data);
6597 return;
6598 }
6599
6600 if (ast_strlen_zero(queue_data->bridge_uniqueid) ||
6601 strcmp(queue_data->bridge_uniqueid, transfer_msg->bridge->uniqueid)) {
6602 ao2_unlock(queue_data);
6603 return;
6604 }
6605
6606 caller_snapshot = ast_channel_snapshot_get_latest(queue_data->caller_uniqueid);
6607 member_snapshot = ast_channel_snapshot_get_latest(queue_data->member_uniqueid);
6608
6609 ao2_unlock(queue_data);
6610
6611 exten = transfer_msg->exten;
6612 context = transfer_msg->context;
6613
6614 ast_debug(3, "Detected blind transfer in queue %s\n", queue_data->queue->name);
6615 ast_queue_log(queue_data->queue->name, queue_data->caller_uniqueid, queue_data->member->membername,
6616 "BLINDTRANSFER", "%s|%s|%ld|%ld|%d",
6617 exten, context,
6618 (long) (queue_data->starttime - queue_data->holdstart),
6619 (long) (time(NULL) - queue_data->starttime), queue_data->caller_pos);
6620
6621 send_agent_complete(queue_data->queue->name, caller_snapshot, member_snapshot, queue_data->member,
6622 queue_data->holdstart, queue_data->starttime, TRANSFER);
6623 update_queue(queue_data->queue, queue_data->member, queue_data->callcompletedinsl,
6624 queue_data->starttime);
6625 remove_stasis_subscriptions(queue_data);
6626}
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 6546 of file app_queue.c.

6548{
6549 struct queue_stasis_data *queue_data = userdata;
6550 struct ast_bridge_blob *enter_blob = stasis_message_data(msg);
6551 SCOPED_AO2LOCK(lock, queue_data);
6552
6553 if (queue_data->dying) {
6554 return;
6555 }
6556
6557 if (!ast_strlen_zero(queue_data->bridge_uniqueid)) {
6558 return;
6559 }
6560
6561 if (!strcmp(enter_blob->channel->base->uniqueid, queue_data->caller_uniqueid)) {
6562 ast_string_field_set(queue_data, bridge_uniqueid,
6563 enter_blob->bridge->uniqueid);
6564 ast_debug(3, "Detected entry of caller channel %s into bridge %s\n",
6565 enter_blob->channel->base->name, queue_data->bridge_uniqueid);
6566 }
6567}
ast_mutex_t lock
Definition: app_sla.c:337
#define SCOPED_AO2LOCK(varname, obj)
scoped lock specialization for ao2 mutexes.
Definition: lock.h:608
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 6827 of file app_queue.c.

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

6714{
6715 struct queue_stasis_data *queue_data = userdata;
6716 struct ast_multi_channel_blob *optimization_blob = stasis_message_data(msg);
6717 struct ast_channel_snapshot *local_one = ast_multi_channel_blob_get_channel(optimization_blob, "1");
6718 struct ast_channel_snapshot *local_two = ast_multi_channel_blob_get_channel(optimization_blob, "2");
6719 struct ast_channel_snapshot *source = ast_multi_channel_blob_get_channel(optimization_blob, "source");
6720 struct local_optimization *optimization;
6721 unsigned int id;
6722 SCOPED_AO2LOCK(lock, queue_data);
6723
6724 if (queue_data->dying) {
6725 return;
6726 }
6727
6728 if (!strcmp(local_one->base->uniqueid, queue_data->member_uniqueid)) {
6729 optimization = &queue_data->member_optimize;
6730 } else if (!strcmp(local_two->base->uniqueid, queue_data->caller_uniqueid)) {
6731 optimization = &queue_data->caller_optimize;
6732 } else {
6733 return;
6734 }
6735
6736 /* We only allow move-swap optimizations, so there had BETTER be a source */
6737 ast_assert(source != NULL);
6738
6739 optimization->source_chan_uniqueid = ast_strdup(source->base->uniqueid);
6740 if (!optimization->source_chan_uniqueid) {
6741 ast_log(LOG_ERROR, "Unable to track local channel optimization for channel %s. Expect further errors\n", local_one->base->name);
6742 return;
6743 }
6745
6746 optimization->id = id;
6747 optimization->in_progress = 1;
6748}
enum queue_result id
Definition: app_queue.c:1808
struct ast_channel_snapshot * ast_multi_channel_blob_get_channel(struct ast_multi_channel_blob *obj, const char *role)
Retrieve a channel snapshot associated with a specific role from a ast_multi_channel_blob.
struct ast_json * ast_multi_channel_blob_get_json(struct ast_multi_channel_blob *obj)
Retrieve the JSON blob from a ast_multi_channel_blob. Returned ast_json is still owned by obj.
struct ast_json * ast_json_object_get(struct ast_json *object, const char *key)
Get a field from a JSON object.
Definition: json.c:407
intmax_t ast_json_integer_get(const struct ast_json *integer)
Get the value from a JSON integer.
Definition: json.c:332
A multi channel blob data structure for multi_channel_blob stasis messages.
Structure representing relevant data during a local channel optimization.
Definition: app_queue.c:6368
const char * source_chan_uniqueid
Definition: app_queue.c:6370
unsigned int id
Definition: app_queue.c:6374
struct local_optimization member_optimize
Definition: app_queue.c:6422
struct local_optimization caller_optimize
Definition: app_queue.c:6420
#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 6763 of file app_queue.c.

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

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

6886{
6887 struct queue_stasis_data *queue_data = userdata;
6888 struct ast_channel_blob *channel_blob = stasis_message_data(msg);
6889 const char *new_channel_id;
6890
6891 new_channel_id = ast_json_string_get(ast_json_object_get(channel_blob->blob, "newchanneluniqueid"));
6892
6893 ao2_lock(queue_data);
6894
6895 if (queue_data->dying) {
6896 ao2_unlock(queue_data);
6897 return;
6898 }
6899
6900 if (!strcmp(channel_blob->snapshot->base->uniqueid, queue_data->caller_uniqueid)) {
6901 ast_debug(1, "Replacing caller channel %s with %s due to masquerade\n", queue_data->caller_uniqueid, new_channel_id);
6902 ast_string_field_set(queue_data, caller_uniqueid, new_channel_id);
6903 } else if (!strcmp(channel_blob->snapshot->base->uniqueid, queue_data->member_uniqueid)) {
6904 ast_debug(1, "Replacing member channel %s with %s due to masquerade\n", queue_data->member_uniqueid, new_channel_id);
6905 ast_string_field_set(queue_data, member_uniqueid, new_channel_id);
6906 }
6907
6908 ao2_unlock(queue_data);
6909}
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 11221 of file app_queue.c.

11222{
11223 const char *queuename, *interface, *membername = NULL, *state_interface = NULL, *reason = NULL;
11224 int penalty, paused = 0;
11225
11226 switch ( cmd ) {
11227 case CLI_INIT:
11228 e->command = "queue add member";
11229 e->usage =
11230 "Usage: queue add member <dial string> to <queue> [penalty <penalty> [as <membername> [state_interface <interface> [paused <reason>]]]]\n"
11231 " 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";
11232 return NULL;
11233 case CLI_GENERATE:
11234 return complete_queue_add_member(a->line, a->word, a->pos, a->n);
11235 }
11236
11237 if ((a->argc != 6) && (a->argc != 8) && (a->argc != 10) && (a->argc != 12) && (a->argc != 14)) {
11238 return CLI_SHOWUSAGE;
11239 } else if (strcmp(a->argv[4], "to")) {
11240 return CLI_SHOWUSAGE;
11241 } else if ((a->argc >= 8) && strcmp(a->argv[6], "penalty")) {
11242 return CLI_SHOWUSAGE;
11243 } else if ((a->argc >= 10) && strcmp(a->argv[8], "as")) {
11244 return CLI_SHOWUSAGE;
11245 } else if ((a->argc == 12) && strcmp(a->argv[10], "state_interface")) {
11246 return CLI_SHOWUSAGE;
11247 } else if ((a->argc == 14) && strcmp(a->argv[12], "paused")) {
11248 return CLI_SHOWUSAGE;
11249 }
11250
11251 queuename = a->argv[5];
11252 interface = a->argv[3];
11253 if (a->argc >= 8) {
11254 if (sscanf(a->argv[7], "%30d", &penalty) == 1) {
11255 if (penalty < 0) {
11256 ast_cli(a->fd, "Penalty must be >= 0\n");
11257 penalty = 0;
11258 }
11259 } else {
11260 ast_cli(a->fd, "Penalty must be an integer >= 0\n");
11261 penalty = 0;
11262 }
11263 } else {
11264 penalty = 0;
11265 }
11266
11267 if (a->argc >= 10) {
11268 membername = a->argv[9];
11269 }
11270
11271 if (a->argc >= 12) {
11272 state_interface = a->argv[11];
11273 }
11274
11275 if (a->argc >= 14) {
11276 paused = 1;
11277 reason = a->argv[13];
11278 }
11279
11280 switch (add_to_queue(queuename, interface, membername, penalty, paused, queue_persistent_members, state_interface, reason, 0)) {
11281 case RES_OKAY:
11282 if (ast_strlen_zero(membername) || !log_membername_as_agent) {
11283 ast_queue_log(queuename, "CLI", interface, "ADDMEMBER", "%s", paused ? "PAUSED" : "");
11284 } else {
11285 ast_queue_log(queuename, "CLI", membername, "ADDMEMBER", "%s", paused ? "PAUSED" : "");
11286 }
11287 ast_cli(a->fd, "Added interface '%s' to queue '%s'\n", interface, queuename);
11288 return CLI_SUCCESS;
11289 case RES_EXISTS:
11290 ast_cli(a->fd, "Unable to add interface '%s' to queue '%s': Already there\n", interface, queuename);
11291 return CLI_FAILURE;
11292 case RES_NOSUCHQUEUE:
11293 ast_cli(a->fd, "Unable to add interface to queue '%s': No such queue\n", queuename);
11294 return CLI_FAILURE;
11295 case RES_OUTOFMEMORY:
11296 ast_cli(a->fd, "Out of memory\n");
11297 return CLI_FAILURE;
11298 case RES_NOT_DYNAMIC:
11299 ast_cli(a->fd, "Member not dynamic\n");
11300 return CLI_FAILURE;
11301 default:
11302 return CLI_FAILURE;
11303 }
11304}
#define RES_NOT_DYNAMIC
Definition: app_queue.c:1736
static char * complete_queue_add_member(const char *line, const char *word, int pos, int state)
Definition: app_queue.c:11046
@ 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 11417 of file app_queue.c.

11418{
11419 const char *queuename, *caller;
11420 int priority, immediate = 0;
11421 char *res = CLI_FAILURE;
11422
11423 switch (cmd) {
11424 case CLI_INIT:
11425 e->command = "queue priority caller";
11426 e->usage =
11427 "Usage: queue priority caller <channel> on <queue> to <priority> [immediate]\n"
11428 " Change the priority of a channel on a queue, optionally applying the change in relation to existing callers.\n";
11429 return NULL;
11430 case CLI_GENERATE:
11431 return NULL;
11432 }
11433
11434 if (a->argc < 8) {
11435 return CLI_SHOWUSAGE;
11436 } else if (strcmp(a->argv[4], "on")) {
11437 return CLI_SHOWUSAGE;
11438 } else if (strcmp(a->argv[6], "to")) {
11439 return CLI_SHOWUSAGE;
11440 } else if (sscanf(a->argv[7], "%30d", &priority) != 1) {
11441 ast_log (LOG_ERROR, "<priority> parameter must be an integer.\n");
11442 return CLI_SHOWUSAGE;
11443 } else if (a->argc == 9) {
11444 if (strcmp(a->argv[8], "immediate")) {
11445 return CLI_SHOWUSAGE;
11446 }
11447 immediate = 1;
11448 }
11449
11450 caller = a->argv[3];
11451 queuename = a->argv[5];
11452
11453 switch (change_priority_caller_on_queue(queuename, caller, priority, immediate)) {
11454 case RES_OKAY:
11455 res = CLI_SUCCESS;
11456 break;
11457 case RES_NOSUCHQUEUE:
11458 ast_cli(a->fd, "Unable change priority caller %s on queue '%s': No such queue\n", caller, queuename);
11459 break;
11460 case RES_NOT_CALLER:
11461 ast_cli(a->fd, "Unable to change priority caller '%s' on queue '%s': Not there\n", caller, queuename);
11462
11463 break;
11464 }
11465
11466 return res;
11467}
static int change_priority_caller_on_queue(const char *queuename, const char *caller, int priority, int immediate)
Change priority caller into a queue.
Definition: app_queue.c:7816

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

◆ handle_queue_pause_member()

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

Definition at line 11490 of file app_queue.c.

11491{
11492 const char *queuename, *interface, *reason;
11493 int paused;
11494
11495 switch (cmd) {
11496 case CLI_INIT:
11497 e->command = "queue {pause|unpause} member";
11498 e->usage =
11499 "Usage: queue {pause|unpause} member <member> [queue <queue> [reason <reason>]]\n"
11500 " Pause or unpause a queue member. Not specifying a particular queue\n"
11501 " will pause or unpause a member across all queues to which the member\n"
11502 " belongs.\n";
11503 return NULL;
11504 case CLI_GENERATE:
11505 return complete_queue_pause_member(a->line, a-> word, a->pos, a->n);
11506 }
11507
11508 if (a->argc < 4 || a->argc == 5 || a->argc == 7 || a->argc > 8) {
11509 return CLI_SHOWUSAGE;
11510 } else if (a->argc >= 5 && strcmp(a->argv[4], "queue")) {
11511 return CLI_SHOWUSAGE;
11512 } else if (a->argc == 8 && strcmp(a->argv[6], "reason")) {
11513 return CLI_SHOWUSAGE;
11514 }
11515
11516
11517 interface = a->argv[3];
11518 queuename = a->argc >= 6 ? a->argv[5] : NULL;
11519 reason = a->argc == 8 ? a->argv[7] : NULL;
11520 paused = !strcasecmp(a->argv[1], "pause");
11521
11522 if (set_member_paused(queuename, interface, reason, paused) == RESULT_SUCCESS) {
11523 ast_cli(a->fd, "%spaused interface '%s'", paused ? "" : "un", interface);
11524 if (!ast_strlen_zero(queuename)) {
11525 ast_cli(a->fd, " in queue '%s'", queuename);
11526 }
11527 if (!ast_strlen_zero(reason)) {
11528 ast_cli(a->fd, " for reason '%s'", reason);
11529 }
11530 ast_cli(a->fd, "\n");
11531 return CLI_SUCCESS;
11532 } else {
11533 ast_cli(a->fd, "Unable to %spause interface '%s'", paused ? "" : "un", interface);
11534 if (!ast_strlen_zero(queuename)) {
11535 ast_cli(a->fd, " in queue '%s'", queuename);
11536 }
11537 if (!ast_strlen_zero(reason)) {
11538 ast_cli(a->fd, " for reason '%s'", reason);
11539 }
11540 ast_cli(a->fd, "\n");
11541 return CLI_FAILURE;
11542 }
11543}
static char * complete_queue_pause_member(const char *line, const char *word, int pos, int state)
Definition: app_queue.c:11471
static int set_member_paused(const char *queuename, const char *interface, const char *reason, int paused)
Definition: app_queue.c:8022
#define RESULT_SUCCESS
Definition: cli.h:40

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

◆ handle_queue_reload()

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

Definition at line 11762 of file app_queue.c.

11763{
11764 struct ast_flags mask = {0,};
11765 int i;
11766
11767 switch (cmd) {
11768 case CLI_INIT:
11769 e->command = "queue reload {parameters|members|rules|all}";
11770 e->usage =
11771 "Usage: queue reload {parameters|members|rules|all} [<queuenames>]\n"
11772 "Reload queues. If <queuenames> are specified, only reload information pertaining\n"
11773 "to <queuenames>. One of 'parameters,' 'members,' 'rules,' or 'all' must be\n"
11774 "specified in order to know what information to reload. Below is an explanation\n"
11775 "of each of these qualifiers.\n"
11776 "\n"
11777 "\t'members' - reload queue members from queues.conf\n"
11778 "\t'parameters' - reload all queue options except for queue members\n"
11779 "\t'rules' - reload the queuerules.conf file\n"
11780 "\t'all' - reload queue rules, parameters, and members\n"
11781 "\n"
11782 "Note: the 'rules' qualifier here cannot actually be applied to a specific queue.\n"
11783 "Use of the 'rules' qualifier causes queuerules.conf to be reloaded. Even if only\n"
11784 "one queue is specified when using this command, reloading queue rules may cause\n"
11785 "other queues to be affected\n";
11786 return NULL;
11787 case CLI_GENERATE:
11788 if (a->pos >= 3) {
11789 /* find the point at which the list of queue names starts */
11790 const char *command_end = a->line + strlen("queue reload ");
11791 command_end = strchr(command_end, ' ');
11792 if (!command_end) {
11793 command_end = a->line + strlen(a->line);
11794 }
11795 return complete_queue(a->line, a->word, a->pos, a->n, command_end - a->line);
11796 } else {
11797 return NULL;
11798 }
11799 }
11800
11801 if (a->argc < 3)
11802 return CLI_SHOWUSAGE;
11803
11804 if (!strcasecmp(a->argv[2], "rules")) {
11806 } else if (!strcasecmp(a->argv[2], "members")) {
11808 } else if (!strcasecmp(a->argv[2], "parameters")) {
11810 } else if (!strcasecmp(a->argv[2], "all")) {
11812 }
11813
11814 if (a->argc == 3) {
11815 reload_handler(1, &mask, NULL);
11816 return CLI_SUCCESS;
11817 }
11818
11819 for (i = 3; i < a->argc; ++i) {
11820 reload_handler(1, &mask, a->argv[i]);
11821 }
11822
11823 return CLI_SUCCESS;
11824}
static int reload_handler(int reload, struct ast_flags *mask, const char *queuename)
The command center for all reload operations.
Definition: app_queue.c:10233
#define ast_set_flag(p, flag)
Definition: utils.h:70
#define AST_FLAGS_ALL
Definition: utils.h:196

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

◆ handle_queue_remove_member()

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

Definition at line 11354 of file app_queue.c.

11355{
11356 const char *queuename, *interface;
11357 struct member *mem = NULL;
11358 char *res = CLI_FAILURE;
11359
11360 switch (cmd) {
11361 case CLI_INIT:
11362 e->command = "queue remove member";
11363 e->usage =
11364 "Usage: queue remove member <channel> from <queue>\n"
11365 " Remove a specific channel from a queue.\n";
11366 return NULL;
11367 case CLI_GENERATE:
11368 return complete_queue_remove_member(a->line, a->word, a->pos, a->n);
11369 }
11370
11371 if (a->argc != 6) {
11372 return CLI_SHOWUSAGE;
11373 } else if (strcmp(a->argv[4], "from")) {
11374 return CLI_SHOWUSAGE;
11375 }
11376
11377 queuename = a->argv[5];
11378 interface = a->argv[3];
11379
11381 mem = find_member_by_queuename_and_interface(queuename, interface);
11382 }
11383
11384 switch (remove_from_queue(queuename, interface)) {
11385 case RES_OKAY:
11386 if (!mem || ast_strlen_zero(mem->membername)) {
11387 ast_queue_log(queuename, "CLI", interface, "REMOVEMEMBER", "%s", "");
11388 } else {
11389 ast_queue_log(queuename, "CLI", mem->membername, "REMOVEMEMBER", "%s", "");
11390 }
11391 ast_cli(a->fd, "Removed interface %s from queue '%s'\n", interface, queuename);
11392 res = CLI_SUCCESS;
11393 break;
11394 case RES_EXISTS:
11395 ast_cli(a->fd, "Unable to remove interface '%s' from queue '%s': Not there\n", interface, queuename);
11396 break;
11397 case RES_NOSUCHQUEUE:
11398 ast_cli(a->fd, "Unable to remove interface from queue '%s': No such queue\n", queuename);
11399 break;
11400 case RES_OUTOFMEMORY:
11401 ast_cli(a->fd, "Out of memory\n");
11402 break;
11403 case RES_NOT_DYNAMIC:
11404 ast_cli(a->fd, "Unable to remove interface '%s' from queue '%s': Member is not dynamic\n", interface, queuename);
11405 break;
11406 }
11407
11408 if (mem) {
11409 ao2_ref(mem, -1);
11410 }
11411
11412 return res;
11413}
static int remove_from_queue(const char *queuename, const char *interface)
Remove member from queue.
Definition: app_queue.c:7710
static struct member * find_member_by_queuename_and_interface(const char *queuename, const char *interface)
Find a member by looking up queuename and interface.
Definition: app_queue.c:12165
static char * complete_queue_remove_member(const char *line, const char *word, int pos, int state)
Definition: app_queue.c:11306

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

◆ handle_queue_reset()

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

Definition at line 11723 of file app_queue.c.

11724{
11725 struct ast_flags mask = {QUEUE_RESET_STATS,};
11726 int i;
11727
11728 switch (cmd) {
11729 case CLI_INIT:
11730 e->command = "queue reset stats";
11731 e->usage =
11732 "Usage: queue reset stats [<queuenames>]\n"
11733 "\n"
11734 "Issuing this command will reset statistics for\n"
11735 "<queuenames>, or for all queues if no queue is\n"
11736 "specified.\n";
11737 return NULL;
11738 case CLI_GENERATE:
11739 if (a->pos >= 3) {
11740 return complete_queue(a->line, a->word, a->pos, a->n, 17);
11741 } else {
11742 return NULL;
11743 }
11744 }
11745
11746 if (a->argc < 3) {
11747 return CLI_SHOWUSAGE;
11748 }
11749
11750 if (a->argc == 3) {
11751 reload_handler(1, &mask, NULL);
11752 return CLI_SUCCESS;
11753 }
11754
11755 for (i = 3; i < a->argc; ++i) {
11756 reload_handler(1, &mask, a->argv[i]);
11757 }
11758
11759 return CLI_SUCCESS;
11760}

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

◆ handle_queue_rule_show()

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

Definition at line 11688 of file app_queue.c.

11689{
11690 const char *rule;
11691 struct rule_list *rl_iter;
11692 struct penalty_rule *pr_iter;
11693 switch (cmd) {
11694 case CLI_INIT:
11695 e->command = "queue show rules";
11696 e->usage =
11697 "Usage: queue show rules [rulename]\n"
11698 " Show the list of rules associated with rulename. If no\n"
11699 " rulename is specified, list all rules defined in queuerules.conf\n";
11700 return NULL;
11701 case CLI_GENERATE:
11702 return complete_queue_rule_show(a->line, a->word, a->pos, a->n);
11703 }
11704
11705 if (a->argc != 3 && a->argc != 4) {
11706 return CLI_SHOWUSAGE;
11707 }
11708
11709 rule = a->argc == 4 ? a->argv[3] : "";
11711 AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) {
11712 if (ast_strlen_zero(rule) || !strcasecmp(rl_iter->name, rule)) {
11713 ast_cli(a->fd, "Rule: %s\n", rl_iter->name);
11714 AST_LIST_TRAVERSE(&rl_iter->rules, pr_iter, list) {
11715 ast_cli(a->fd, "\tAfter %d seconds, adjust QUEUE_MAX_PENALTY %s %d, adjust QUEUE_MIN_PENALTY %s %d and adjust QUEUE_RAISE_PENALTY %s %d\n", pr_iter->time, pr_iter->max_relative ? "by" : "to", pr_iter->max_value, pr_iter->min_relative ? "by" : "to", pr_iter->min_value, pr_iter->raise_relative ? "by" : "to", pr_iter->raise_value);
11716 }
11717 }
11718 }
11720 return CLI_SUCCESS;
11721}
static char * complete_queue_rule_show(const char *line, const char *word, int pos, int state)
Definition: app_queue.c:11666

References a, ast_cli(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_strlen_zero(), CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, complete_queue_rule_show(), penalty_rule::list, penalty_rule::max_relative, penalty_rule::max_value, penalty_rule::min_relative, penalty_rule::min_value, rule_list::name, NULL, penalty_rule::raise_relative, penalty_rule::raise_value, rule_list::rules, penalty_rule::time, and ast_cli_entry::usage.

◆ handle_queue_set_member_penalty()

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

Definition at line 11625 of file app_queue.c.

11626{
11627 const char *queuename = NULL, *interface;
11628 int penalty = 0;
11629
11630 switch (cmd) {
11631 case CLI_INIT:
11632 e->command = "queue set penalty";
11633 e->usage =
11634 "Usage: queue set penalty <penalty> on <interface> [in <queue>]\n"
11635 " Set a member's penalty in the queue specified. If no queue is specified\n"
11636 " then that interface's penalty is set in all queues to which that interface is a member\n";
11637 return NULL;
11638 case CLI_GENERATE:
11639 return complete_queue_set_member_value(a->line, a->word, a->pos, a->n);
11640 }
11641
11642 if (a->argc != 6 && a->argc != 8) {
11643 return CLI_SHOWUSAGE;
11644 } else if (strcmp(a->argv[4], "on") || (a->argc > 6 && strcmp(a->argv[6], "in"))) {
11645 return CLI_SHOWUSAGE;
11646 }
11647
11648 if (a->argc == 8) {
11649 queuename = a->argv[7];
11650 }
11651 interface = a->argv[5];
11652 penalty = atoi(a->argv[3]);
11653
11654 switch (set_member_value(queuename, interface, MEMBER_PENALTY, penalty)) {
11655 case RESULT_SUCCESS:
11656 ast_cli(a->fd, "Set penalty on interface '%s' from queue '%s'\n", interface, queuename);
11657 return CLI_SUCCESS;
11658 case RESULT_FAILURE:
11659 ast_cli(a->fd, "Failed to set penalty on interface '%s' from queue '%s'\n", interface, queuename);
11660 return CLI_FAILURE;
11661 default:
11662 return CLI_FAILURE;
11663 }
11664}
static int set_member_value(const char *queuename, const char *interface, int property, int value)
Definition: app_queue.c:8170
static char * complete_queue_set_member_value(const char *line, const char *word, int pos, int state)
Definition: app_queue.c:11545

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

◆ handle_queue_set_member_ringinuse()

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

Definition at line 11568 of file app_queue.c.

11569{
11570 const char *queuename = NULL, *interface;
11571 int ringinuse;
11572
11573 switch (cmd) {
11574 case CLI_INIT:
11575 e->command = "queue set ringinuse";
11576 e->usage =
11577 "Usage: queue set ringinuse <yes/no> on <interface> [in <queue>]\n"
11578 " Set a member's ringinuse in the queue specified. If no queue is specified\n"
11579 " then that interface's penalty is set in all queues to which that interface is a member.\n";
11580 break;
11581 return NULL;
11582 case CLI_GENERATE:
11583 return complete_queue_set_member_value(a->line, a->word, a->pos, a->n);
11584 }
11585
11586 /* Sensible argument counts */
11587 if (a->argc != 6 && a->argc != 8) {
11588 return CLI_SHOWUSAGE;
11589 }
11590
11591 /* Uses proper indicational words */
11592 if (strcmp(a->argv[4], "on") || (a->argc > 6 && strcmp(a->argv[6], "in"))) {
11593 return CLI_SHOWUSAGE;
11594 }
11595
11596 /* Set the queue name if applicable */
11597 if (a->argc == 8) {
11598 queuename = a->argv[7];
11599 }
11600
11601 /* Interface being set */
11602 interface = a->argv[5];
11603
11604 /* Check and set the ringinuse value */
11605 if (ast_true(a->argv[3])) {
11606 ringinuse = 1;
11607 } else if (ast_false(a->argv[3])) {
11608 ringinuse = 0;
11609 } else {
11610 return CLI_SHOWUSAGE;
11611 }
11612
11613 switch (set_member_value(queuename, interface, MEMBER_RINGINUSE, ringinuse)) {
11614 case RESULT_SUCCESS:
11615 ast_cli(a->fd, "Set ringinuse on interface '%s' from queue '%s'\n", interface, queuename);
11616 return CLI_SUCCESS;
11617 case RESULT_FAILURE:
11618 ast_cli(a->fd, "Failed to set ringinuse on interface '%s' from queue '%s'\n", interface, queuename);
11619 return CLI_FAILURE;
11620 default:
11621 return CLI_FAILURE;
11622 }
11623}
int attribute_pure ast_false(const char *val)
Make sure something is false. Determine if a string containing a boolean value is "false"....
Definition: utils.c:2216

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

◆ hangupcalls()

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

Hang up a list of outgoing calls.

Definition at line 4639 of file app_queue.c.

4640{
4641 struct callattempt *oo;
4642
4643 while (outgoing) {
4644 /* If someone else answered the call we should indicate this in the CANCEL */
4645 /* Hangup any existing lines we have open */
4646 if (outgoing->chan && (outgoing->chan != exception)) {
4647 if (exception || cancel_answered_elsewhere) {
4649 }
4650 ast_channel_publish_dial(qe->chan, outgoing->chan, outgoing->interface, "CANCEL");
4651
4652 /* When dialing channels it is possible that they may not ever
4653 * leave the not in use state (Local channels in particular) by
4654 * the time we cancel them. If this occurs but we know they were
4655 * dialed we explicitly remove them from the pending members
4656 * container so that subsequent call attempts occur.
4657 */
4658 if (outgoing->member->status == AST_DEVICE_NOT_INUSE) {
4660 }
4661
4662 ast_hangup(outgoing->chan);
4663 }
4664 oo = outgoing;
4665 outgoing = outgoing->q_next;
4667 callattempt_free(oo);
4668 }
4669}
void * ast_aoc_destroy_decoded(struct ast_aoc_decoded *decoded)
free an ast_aoc_decoded object
Definition: aoc.c:316
static void callattempt_free(struct callattempt *doomed)
Definition: app_queue.c:4617
#define AST_CAUSE_ANSWERED_ELSEWHERE
Definition: causes.h:114
void ast_channel_hangupcause_set(struct ast_channel *chan, int value)
void ast_channel_publish_dial(struct ast_channel *caller, struct ast_channel *peer, const char *dialstring, const char *dialstatus)
Publish in the ast_channel_topic or ast_channel_topic_all topics a stasis message for the channels in...
struct ast_aoc_decoded * aoc_s_rate_list
Definition: app_queue.c:1856
struct ast_channel * chan
Definition: app_queue.c:1890

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

Referenced by try_calling().

◆ init_queue()

static void init_queue ( struct call_queue q)
static

Initialize Queue default values.

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

Definition at line 3119 of file app_queue.c.

3120{
3121 int i;
3122 struct penalty_rule *pr_iter;
3123
3124 q->dead = 0;
3125 q->retry = DEFAULT_RETRY;
3127 q->maxlen = 0;
3128
3129 ast_string_field_set(q, announce, "");
3131 ast_string_field_set(q, membergosub, "");
3132 ast_string_field_set(q, defaultrule, "");
3133
3134 q->announcefrequency = 0;
3136 q->announceholdtime = 1;
3138 q->announcepositionlimit = 10; /* Default 10 positions */
3139 q->announceposition = ANNOUNCEPOSITION_YES; /* Default yes */
3140 q->roundingseconds = 0; /* Default - don't announce seconds */
3141 q->servicelevel = 0;
3142 q->ringinuse = 1;
3144 q->setinterfacevar = 0;
3145 q->setqueuevar = 0;
3146 q->setqueueentryvar = 0;
3148 q->monfmt[0] = '\0';
3149 q->reportholdtime = 0;
3150 q->wrapuptime = 0;
3151 q->penaltymemberslimit = 0;
3152 q->joinempty = 0;
3153 q->leavewhenempty = 0;
3154 q->memberdelay = 0;
3155 q->weight = 0;
3156 q->timeoutrestart = 0;
3160 q->numperiodicannounce = 0;
3163 q->autopausebusy = 0;
3164 q->autopauseunavail = 0;
3166 q->autopausedelay = 0;
3168 if (!q->members) {
3170 /* linear strategy depends on order, so we have to place all members in a list */
3172 } else {
3175 }
3176 }
3177 q->found = 1;
3178
3179 ast_string_field_set(q, moh, "");
3180 ast_string_field_set(q, sound_next, "queue-youarenext");
3181 ast_string_field_set(q, sound_thereare, "queue-thereare");
3182 ast_string_field_set(q, sound_calls, "queue-callswaiting");
3183 ast_string_field_set(q, queue_quantity1, "queue-quantity1");
3184 ast_string_field_set(q, queue_quantity2, "queue-quantity2");
3185 ast_string_field_set(q, sound_holdtime, "queue-holdtime");
3186 ast_string_field_set(q, sound_minutes, "queue-minutes");
3187 ast_string_field_set(q, sound_minute, "queue-minute");
3188 ast_string_field_set(q, sound_seconds, "queue-seconds");
3189 ast_string_field_set(q, sound_thanks, "queue-thankyou");
3190 ast_string_field_set(q, sound_callerannounce, "");
3191 ast_string_field_set(q, sound_reporthold, "queue-reporthold");
3192
3193 if (!q->sound_periodicannounce[0]) {
3195 }
3196
3197 if (q->sound_periodicannounce[0]) {
3198 ast_str_set(&q->sound_periodicannounce[0], 0, "queue-periodic-announce");
3199 }
3200
3201 for (i = 1; i < MAX_PERIODIC_ANNOUNCEMENTS; i++) {
3202 if (q->sound_periodicannounce[i]) {
3203 ast_str_set(&q->sound_periodicannounce[i], 0, "%s", "");
3204 }
3205 }
3206
3207 while ((pr_iter = AST_LIST_REMOVE_HEAD(&q->rules,list))) {
3208 ast_free(pr_iter);
3209 }
3210
3211 /* On restart assume no members are available.
3212 * The queue_avail hint is a boolean state to indicate whether a member is available or not.
3213 *
3214 * This seems counter intuitive, but is required to light a BLF
3215 * AST_DEVICE_INUSE indicates no members are available.
3216 * AST_DEVICE_NOT_INUSE indicates a member is available.
3217 */
3219}
#define DEFAULT_RETRY
Definition: app_queue.c:1720
static int member_hash_fn(const void *obj, const int flags)
Definition: app_queue.c:3090
static int member_cmp_fn(void *obj1, void *obj2, int flags)
Definition: app_queue.c:3106
#define DEFAULT_MIN_ANNOUNCE_FREQUENCY
The minimum number of seconds between position announcements.
Definition: app_queue.c:1728
#define DEFAULT_TIMEOUT
Definition: app_queue.c:1721
static int autofill_default
queues.conf [general] option
Definition: app_queue.c:1763
#define ANNOUNCEPOSITION_YES
Definition: app_queue.c:1956
@ AO2_ALLOC_OPT_LOCK_MUTEX
Definition: astobj2.h:363
#define ao2_container_alloc_list(ao2_options, container_options, sort_fn, cmp_fn)
Allocate and initialize a list container.
Definition: astobj2.h:1327
#define ao2_container_alloc_hash(ao2_options, container_options, n_buckets, hash_fn, sort_fn, cmp_fn)
Allocate and initialize a hash container with the desired number of buckets.
Definition: astobj2.h:1303
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:833
unsigned int autopauseunavail
Definition: app_queue.c:2019
unsigned int setinterfacevar
Definition: app_queue.c:2005
int announcefrequency
Definition: app_queue.c:2023
unsigned int announceholdtime
Definition: app_queue.c:2011
unsigned int reportholdtime
Definition: app_queue.c:2008
unsigned int setqueueentryvar
Definition: app_queue.c:2007
unsigned int timeoutrestart
Definition: app_queue.c:2010
int periodicannouncefrequency
Definition: app_queue.c:2026
unsigned int announceposition_only_up
Definition: app_queue.c:2013
unsigned int setqueuevar
Definition: app_queue.c:2006
int announcepositionlimit
Definition: app_queue.c:2022
unsigned int announce_to_first_user
Definition: app_queue.c:2004
int randomperiodicannounce
Definition: app_queue.c:2028
int autopause
Definition: app_queue.c:2046
int periodicannouncestartdelay
Definition: app_queue.c:2025
int log_restricted_caller_id
Definition: app_queue.c:2055
struct call_queue::@54 rules
int servicelevel
Definition: app_queue.c:2035
int autofill
Definition: app_queue.c:2053
int minannouncefrequency
Definition: app_queue.c:2024
enum empty_conditions leavewhenempty
Definition: app_queue.c:2021
int roundingseconds
Definition: app_queue.c:2029
int numperiodicannounce
Definition: app_queue.c:2027
unsigned int announceposition
Definition: app_queue.c:2012
char monfmt[8]
Definition: app_queue.c:2037
enum empty_conditions joinempty
Definition: app_queue.c:2020
int memberdelay
Definition: app_queue.c:2052
unsigned int autopausebusy
Definition: app_queue.c:2018
int autopausedelay
Definition: app_queue.c:2047
int timeoutpriority
Definition: app_queue.c:2048
unsigned int relativeperiodicannounce
Definition: app_queue.c:2017

References call_queue::announce_to_first_user, call_queue::announcefrequency, call_queue::announceholdtime, call_queue::announceposition, call_queue::announceposition_only_up, ANNOUNCEPOSITION_YES, call_queue::announcepositionlimit, AO2_ALLOC_OPT_LOCK_MUTEX, ao2_container_alloc_hash, ao2_container_alloc_list, AST_DEVICE_INUSE, AST_DEVSTATE_CACHABLE, ast_devstate_changed(), ast_free, AST_LIST_REMOVE_HEAD, ast_str_create, ast_str_set(), ast_string_field_set, call_queue::autofill, autofill_default, call_queue::autopause, call_queue::autopausebusy, call_queue::autopausedelay, call_queue::autopauseunavail, voicemailpwcheck::context, call_queue::dead, DEFAULT_MIN_ANNOUNCE_FREQUENCY, DEFAULT_RETRY, DEFAULT_TIMEOUT, call_queue::found, call_queue::joinempty, call_queue::leavewhenempty, penalty_rule::list, call_queue::log_restricted_caller_id, MAX_PERIODIC_ANNOUNCEMENTS, call_queue::maxlen, member_cmp_fn(), member_hash_fn(), call_queue::memberdelay, call_queue::members, call_queue::minannouncefrequency, call_queue::monfmt, call_queue::name, NULL, call_queue::numperiodicannounce, call_queue::penaltymemberslimit, call_queue::periodicannouncefrequency, call_queue::periodicannouncestartdelay, QUEUE_AUTOPAUSE_OFF, QUEUE_STRATEGY_LINEAR, QUEUE_STRATEGY_RRORDERED, call_queue::randomperiodicannounce, call_queue::relativeperiodicannounce, call_queue::reportholdtime, call_queue::retry, call_queue::ringinuse, call_queue::roundingseconds, call_queue::rules, call_queue::servicelevel, call_queue::setinterfacevar, call_queue::setqueueentryvar, call_queue::setqueuevar, call_queue::sound_periodicannounce, call_queue::strategy, call_queue::timeout, TIMEOUT_PRIORITY_APP, call_queue::timeoutpriority, call_queue::timeoutrestart, call_queue::weight, and call_queue::wrapuptime.

Referenced by find_queue_by_name_rt(), and reload_single_queue().

◆ insert_entry()

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

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

Definition at line 2259 of file app_queue.c.

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

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

Referenced by change_priority_caller_on_queue(), and join_queue().

◆ insert_penaltychange()

static int insert_penaltychange ( const char *  list_name,
const char *  content,
const int  linenum 
)
static

Change queue penalty by adding rule.

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

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

Definition at line 3253 of file app_queue.c.

3254{
3255 char *timestr, *maxstr, *minstr, *raisestr, *contentdup;
3256 struct penalty_rule *rule = NULL, *rule_iter;
3257 struct rule_list *rl_iter;
3258 int penaltychangetime, inserted = 0;
3259
3260 if (!(rule = ast_calloc(1, sizeof(*rule)))) {
3261 return -1;
3262 }
3263
3264 contentdup = ast_strdupa(content);
3265
3266 if (!(maxstr = strchr(contentdup, ','))) {
3267 ast_log(LOG_WARNING, "Improperly formatted penaltychange rule at line %d. Ignoring.\n", linenum);
3268 ast_free(rule);
3269 return -1;
3270 }
3271
3272 *maxstr++ = '\0';
3273 if ((minstr = strchr(maxstr,','))) {
3274 *minstr++ = '\0';
3275 if ((raisestr = strchr(minstr,','))) {
3276 *raisestr++ = '\0';
3277 }
3278 } else {
3279 raisestr = NULL;
3280 }
3281
3282 timestr = contentdup;
3283 if ((penaltychangetime = atoi(timestr)) < 0) {
3284 ast_log(LOG_WARNING, "Improper time parameter specified for penaltychange rule at line %d. Ignoring.\n", linenum);
3285 ast_free(rule);
3286 return -1;
3287 }
3288
3289 rule->time = penaltychangetime;
3290
3291 /* The last check will evaluate true if either no penalty change is indicated for a given rule
3292 * OR if a min penalty change is indicated but no max penalty change is */
3293 if (*maxstr == '+' || *maxstr == '-' || *maxstr == '\0') {
3294 rule->max_relative = 1;
3295 }
3296
3297 rule->max_value = atoi(maxstr);
3298
3299 if (!ast_strlen_zero(minstr)) {
3300 if (*minstr == '+' || *minstr == '-') {
3301 rule->min_relative = 1;
3302 }
3303 rule->min_value = atoi(minstr);
3304 } else { /*there was no minimum specified, so assume this means no change*/
3305 rule->min_relative = 1;
3306 }
3307
3308 if (!ast_strlen_zero(raisestr)) {
3309 if (*raisestr == '+' || *raisestr == '-') {
3310 rule->raise_relative = 1;
3311 }
3312 rule->raise_value = atoi(raisestr);
3313 } else { /*there was no raise specified, so assume this means no change*/
3314 rule->raise_relative = 1;
3315 }
3316
3317 /*We have the rule made, now we need to insert it where it belongs*/
3318 AST_LIST_TRAVERSE(&rule_lists, rl_iter, list){
3319 if (strcasecmp(rl_iter->name, list_name)) {
3320 continue;
3321 }
3322
3323 AST_LIST_TRAVERSE_SAFE_BEGIN(&rl_iter->rules, rule_iter, list) {
3324 if (rule->time < rule_iter->time) {
3326 inserted = 1;
3327 break;
3328 }
3329 }
3331
3332 if (!inserted) {
3333 AST_LIST_INSERT_TAIL(&rl_iter->rules, rule, list);
3334 inserted = 1;
3335 }
3336
3337 break;
3338 }
3339
3340 if (!inserted) {
3341 ast_log(LOG_WARNING, "Unknown rule list name %s; ignoring.\n", list_name);
3342 ast_free(rule);
3343 return -1;
3344 }
3345 return 0;
3346}
#define AST_LIST_TRAVERSE_SAFE_END
Closes a safe loop traversal block.
Definition: linkedlists.h:615
#define AST_LIST_INSERT_BEFORE_CURRENT(elm, field)
Inserts a list entry before the current entry during a traversal.
Definition: linkedlists.h:599
#define AST_LIST_TRAVERSE_SAFE_BEGIN(head, var, field)
Loops safely over (traverses) the entries in a list.
Definition: linkedlists.h:529

References ast_calloc, ast_free, AST_LIST_INSERT_BEFORE_CURRENT, AST_LIST_INSERT_TAIL, AST_LIST_TRAVERSE, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, ast_log, ast_strdupa, ast_strlen_zero(), rule_list::list, LOG_WARNING, rule_list::name, NULL, and rule_list::rules.

Referenced by reload_queue_rules().

◆ int2strat()

static const char * int2strat ( int  strategy)
static

Definition at line 2092 of file app_queue.c.

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

References ARRAY_LEN, strategy::name, and strategies.

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

◆ interface_exists()

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

Definition at line 7628 of file app_queue.c.

7629{
7630 struct member *mem;
7631 struct ao2_iterator mem_iter;
7632
7633 if (!q) {
7634 return NULL;
7635 }
7636 mem_iter = ao2_iterator_init(q->members, 0);
7637 while ((mem = ao2_iterator_next(&mem_iter))) {
7638 if (!strcasecmp(interface, mem->interface)) {
7639 ao2_iterator_destroy(&mem_iter);
7640 return mem;
7641 }
7642 ao2_ref(mem, -1);
7643 }
7644 ao2_iterator_destroy(&mem_iter);
7645
7646 return NULL;
7647}

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

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

◆ is_longest_waiting_caller()

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

Definition at line 4746 of file app_queue.c.

4747{
4748 struct call_queue *q;
4749 struct member *mem;
4750 int is_longest_waiting = 1;
4751 struct ao2_iterator queue_iter;
4752 struct queue_ent *ch;
4753
4754 queue_iter = ao2_iterator_init(queues, 0);
4755 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
4756 if (q == caller->parent) { /* don't check myself, could deadlock */
4757 queue_t_unref(q, "Done with iterator");
4758 continue;
4759 }
4760 ao2_lock(q);
4761 /*
4762 * If the other queue has equal weight, see if we should let that handle
4763 * their call first. If weights are not equal, compare_weights will step in.
4764 */
4765 if (q->weight == caller->parent->weight && q->count && q->members) {
4766 if ((mem = ao2_find(q->members, member, OBJ_POINTER))) {
4767 ast_debug(2, "Found matching member %s in queue '%s'\n", mem->interface, q->name);
4768
4769 /* Does this queue have a caller that's been waiting longer? */
4770 ch = q->head;
4771 while (ch) {
4772 /* If ch->pending, the other call (which may be waiting for a longer period of time),
4773 * is already ringing at another agent. Ignore such callers; otherwise, all agents
4774 * will be unused until the first caller is picked up.
4775 */
4776 if (ch->start < caller->start && !ch->pending) {
4777 ast_debug(1, "Queue %s has a call at position %i that's been waiting longer (%li vs %li)\n",
4778 q->name, ch->pos, ch->start, caller->start);
4779 is_longest_waiting = 0;
4780 break;
4781 }
4782 ch = ch->next;
4783 }
4784 }
4785 }
4786 ao2_unlock(q);
4787 queue_t_unref(q, "Done with iterator");
4788 if (!is_longest_waiting) {
4789 break;
4790 }
4791 }
4792 ao2_iterator_destroy(&queue_iter);
4793 return is_longest_waiting;
4794}
int pending
Definition: app_queue.c:1879
time_t start
Definition: app_queue.c:1885

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

Referenced by can_ring_entry().

◆ is_member_available()

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

Definition at line 2776 of file app_queue.c.

2777{
2778 int available = 0;
2779 int wrapuptime;
2780
2781 switch (mem->status) {
2782 case AST_DEVICE_INVALID:
2784 break;
2785 case AST_DEVICE_INUSE:
2786 case AST_DEVICE_BUSY:
2787 case AST_DEVICE_RINGING:
2789 case AST_DEVICE_ONHOLD:
2790 if (!mem->ringinuse) {
2791 break;
2792 }
2793 /* else fall through */
2795 case AST_DEVICE_UNKNOWN:
2796 if (!mem->paused) {
2797 available = 1;
2798 }
2799 break;
2800 }
2801
2802 /* Let wrapuptimes override device state availability */
2803 wrapuptime = get_wrapuptime(q, mem);
2804 if (mem->lastcall && wrapuptime && (time(NULL) - wrapuptime < mem->lastcall)) {
2805 available = 0;
2806 }
2807 return available;
2808}
static int available(struct dahdi_pvt **pvt, int is_specific_channel)
Definition: chan_dahdi.c:13552

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

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

◆ is_our_turn()

static int is_our_turn ( struct queue_ent qe)
static

Check if we should start attempting to call queue members.

A simple process, really. Count the number of members who are available to take our call and then see if we are in a position in the queue at which a member could accept our call.

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

Definition at line 5915 of file app_queue.c.

5916{
5917 struct queue_ent *ch;
5918 int res;
5919 int avl;
5920 int idx = 0;
5921 /* This needs a lock. How many members are available to be served? */
5922 ao2_lock(qe->parent);
5923
5924 avl = num_available_members(qe->parent);
5925
5926 ch = qe->parent->head;
5927
5928 ast_debug(1, "There %s %d available %s.\n", avl != 1 ? "are" : "is", avl, avl != 1 ? "members" : "member");
5929
5930 while ((idx < avl) && (ch) && (ch != qe)) {
5931 if (!ch->pending) {
5932 idx++;
5933 }
5934 ch = ch->next;
5935 }
5936
5937 ao2_unlock(qe->parent);
5938 /* If the queue entry is within avl [the number of available members] calls from the top ...
5939 * Autofill and position check added to support autofill=no (as only calls
5940 * from the front of the queue are valid when autofill is disabled)
5941 */
5942 if (ch && idx < avl && (qe->parent->autofill || qe->pos == 1)) {
5943 ast_debug(1, "It's our turn (%s).\n", ast_channel_name(qe->chan));
5944 res = 1;
5945 } else {
5946 ast_debug(1, "It's not our turn (%s).\n", ast_channel_name(qe->chan));
5947 res = 0;
5948 }
5949
5950 /* Update realtime members if this is the first call and number of avalable members is 0 */
5951 if (avl == 0 && qe->pos == 1) {
5953 }
5954
5955 return res;
5956}

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

Referenced by queue_exec(), and wait_our_turn().

◆ join_queue()

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

Definition at line 4229 of file app_queue.c.

4230{
4231 struct call_queue *q;
4232 struct queue_ent *cur, *prev = NULL;
4233 int res = -1;
4234 int pos = 0;
4235 int inserted = 0;
4236
4237 if (!(q = find_load_queue_rt_friendly(queuename))) {
4238 return res;
4239 }
4240 ao2_lock(q);
4241
4242 /* This is our one */
4243 if (q->joinempty) {
4244 int status = 0;
4245 if ((status = get_member_status(q, qe->max_penalty, qe->min_penalty, qe->raise_penalty, q->joinempty, 0))) {
4246 *reason = QUEUE_JOINEMPTY;
4247 ao2_unlock(q);
4248 queue_t_unref(q, "Done with realtime queue");
4249 return res;
4250 }
4251 }
4252 if (*reason == QUEUE_UNKNOWN && q->maxlen && (q->count >= q->maxlen)) {
4253 *reason = QUEUE_FULL;
4254 } else if (*reason == QUEUE_UNKNOWN) {
4255 RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
4256
4257 /* There's space for us, put us at the right position inside
4258 * the queue.
4259 * Take into account the priority of the calling user */
4260 inserted = 0;
4261 prev = NULL;
4262 cur = q->head;
4263 while (cur) {
4264 /* We have higher priority than the current user, enter
4265 * before him, after all the other users with priority
4266 * higher or equal to our priority. */
4267 if ((!inserted) && (qe->prio > cur->prio)) {
4268 insert_entry(q, prev, qe, &pos);
4269 inserted = 1;
4270 }
4271 /* <= is necessary for the position comparison because it may not be possible to enter
4272 * at our desired position since higher-priority callers may have taken the position we want
4273 */
4274 if (!inserted && (qe->prio >= cur->prio) && position && (position <= pos + 1)) {
4275 insert_entry(q, prev, qe, &pos);
4276 inserted = 1;
4277 /*pos is incremented inside insert_entry, so don't need to add 1 here*/
4278 if (position < pos) {
4279 ast_log(LOG_NOTICE, "Asked to be inserted at position %d but forced into position %d due to higher priority callers\n", position, pos);
4280 }
4281 }
4282 cur->pos = ++pos;
4283 prev = cur;
4284 cur = cur->next;
4285 }
4286 /* No luck, join at the end of the queue */
4287 if (!inserted) {
4288 insert_entry(q, prev, qe, &pos);
4289 }
4290 ast_copy_string(qe->moh, q->moh, sizeof(qe->moh));
4291 ast_copy_string(qe->announce, q->announce, sizeof(qe->announce));
4292 ast_copy_string(qe->context, q->context, sizeof(qe->context));
4293 q->count++;
4294 if (q->count == 1) {
4296 }
4297
4298 res = 0;
4299
4300 blob = ast_json_pack("{s: s, s: i, s: i}",
4301 "Queue", q->name,
4302 "Position", qe->pos,
4303 "Count", q->count);
4304 ast_channel_publish_cached_blob(qe->chan, queue_caller_join_type(), blob);
4305 ast_debug(1, "Queue '%s' Join, Channel '%s', Position '%d'\n", q->name, ast_channel_name(qe->chan), qe->pos );
4306 }
4307 ao2_unlock(q);
4308 queue_t_unref(q, "Done with realtime queue");
4309
4310 return res;
4311}
jack_status_t status
Definition: app_jack.c:149
void ast_channel_publish_cached_blob(struct ast_channel *chan, struct stasis_message_type *type, struct ast_json *blob)
Publish a channel blob message using the latest snapshot from the cache.
void ast_json_unref(struct ast_json *value)
Decrease refcount on value. If refcount reaches zero, value is freed.
Definition: json.c:73
struct ast_json * ast_json_pack(char const *format,...)
Helper for creating complex JSON values.
Definition: json.c:612
Abstract JSON element (object, array, string, int, ...).
const ast_string_field moh
Definition: app_queue.c:1999
const ast_string_field context
Definition: app_queue.c:1999
const ast_string_field announce
Definition: app_queue.c:1999
char announce[PATH_MAX]
Definition: app_queue.c:1865
char moh[MAX_MUSICCLASS]
Definition: app_queue.c:1864
char context[AST_MAX_CONTEXT]
Definition: app_queue.c:1866

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

Referenced by queue_exec().

◆ kill_dead_members()

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

Definition at line 9967 of file app_queue.c.

9968{
9969 struct member *member = obj;
9970
9971 if (!member->delme) {
9973 return 0;
9974 } else {
9975 return CMP_MATCH;
9976 }
9977}
@ CMP_MATCH
Definition: astobj2.h:1027
unsigned int delme
Definition: app_queue.c:1919

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

Referenced by reload_single_queue().

◆ kill_if_unfound()

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

Definition at line 10122 of file app_queue.c.

10123{
10124 struct call_queue *q = obj;
10125 char *queuename = arg;
10126 if (!q->realtime && !q->found && (ast_strlen_zero(queuename) || !strcasecmp(queuename, q->name))) {
10127 q->dead = 1;
10128 return CMP_MATCH;
10129 } else {
10130 return 0;
10131 }
10132}

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

Referenced by reload_queues().

◆ leave_queue()

static void leave_queue ( struct queue_ent qe)
static

Caller leaving queue.

Search the queue to find the leaving client, if found remove from queue create manager event, move others up the queue.

Definition at line 4542 of file app_queue.c.

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

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

Referenced by queue_exec(), and try_calling().

◆ load_module()

static int load_module ( void  )
static

Load the module.

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

Definition at line 11997 of file app_queue.c.

11998{
11999 int err = 0;
12000 struct ast_flags mask = {AST_FLAGS_ALL, };
12001 struct ast_config *member_config;
12002 struct stasis_topic *queue_topic;
12004
12007 if (!queues) {
12009 }
12010
12013 if (!pending_members) {
12014 unload_module();
12016 }
12017
12018 use_weight = 0;
12019
12020 if (reload_handler(0, &mask, NULL)) {
12021 unload_module();
12023 }
12024
12025 ast_realtime_require_field("queue_members", "paused", RQ_INTEGER1, 1, "uniqueid", RQ_UINTEGER2, 5, "reason_paused", RQ_CHAR, 80, SENTINEL);
12026
12027 /*
12028 * This section is used to determine which name for 'ringinuse' to use in realtime members
12029 * Necessary for supporting older setups.
12030 *
12031 * It also checks if 'reason_paused' exists in the realtime backend
12032 */
12033 member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name LIKE", "%", SENTINEL);
12034 if (!member_config) {
12035 realtime_ringinuse_field = "ringinuse";
12036 } else {
12037 const char *config_val;
12038
12039 if ((config_val = ast_variable_retrieve(member_config, NULL, "ringinuse"))) {
12040 ast_log(LOG_NOTICE, "ringinuse field entries found in queue_members table. Using 'ringinuse'\n");
12041 realtime_ringinuse_field = "ringinuse";
12042 } else if ((config_val = ast_variable_retrieve(member_config, NULL, "ignorebusy"))) {
12043 ast_log(LOG_NOTICE, "ignorebusy field found in queue_members table with no ringinuse field. Using 'ignorebusy'\n");
12044 realtime_ringinuse_field = "ignorebusy";
12045 } else {
12046 ast_log(LOG_NOTICE, "No entries were found for ringinuse/ignorebusy in queue_members table. Using 'ringinuse'\n");
12047 realtime_ringinuse_field = "ringinuse";
12048 }
12049
12050 if (ast_variable_retrieve(member_config, NULL, "reason_paused")) {
12052 }
12053 }
12054 ast_config_destroy(member_config);
12055
12058 }
12059
12068 err |= ast_manager_register_xml("QueueStatus", 0, manager_queues_status);
12069 err |= ast_manager_register_xml("QueueSummary", 0, manager_queues_summary);
12076 err |= ast_manager_register_xml("QueueRule", 0, manager_queue_rule_show);
12077 err |= ast_manager_register_xml("QueueReload", 0, manager_queue_reload);
12078 err |= ast_manager_register_xml("QueueReset", 0, manager_queue_reset);
12079 err |= ast_manager_register_xml("QueueChangePriorityCaller", 0, manager_change_priority_caller_on_queue);
12089
12090 /* in the following subscribe call, do I use DEVICE_STATE, or DEVICE_STATE_CHANGE? */
12092 if (!device_state_sub) {
12093 err = -1;
12094 }
12097
12099 queue_topic = ast_queue_topic_all();
12100 if (!manager_topic || !queue_topic) {
12101 unload_module();
12103 }
12105 if (!topic_forwarder) {
12106 unload_module();
12108 }
12109
12112 unload_module();
12114 }
12116 if (!agent_router) {
12117 unload_module();
12119 }
12123 NULL);
12127 NULL);
12128
12129 err |= STASIS_MESSAGE_TYPE_INIT(queue_caller_join_type);
12130 err |= STASIS_MESSAGE_TYPE_INIT(queue_caller_leave_type);
12131 err |= STASIS_MESSAGE_TYPE_INIT(queue_caller_abandon_type);
12132
12133 err |= STASIS_MESSAGE_TYPE_INIT(queue_member_status_type);
12134 err |= STASIS_MESSAGE_TYPE_INIT(queue_member_added_type);
12135 err |= STASIS_MESSAGE_TYPE_INIT(queue_member_removed_type);
12136 err |= STASIS_MESSAGE_TYPE_INIT(queue_member_pause_type);
12137 err |= STASIS_MESSAGE_TYPE_INIT(queue_member_penalty_type);
12138 err |= STASIS_MESSAGE_TYPE_INIT(queue_member_ringinuse_type);
12139
12140 err |= STASIS_MESSAGE_TYPE_INIT(queue_agent_called_type);
12141 err |= STASIS_MESSAGE_TYPE_INIT(queue_agent_connect_type);
12142 err |= STASIS_MESSAGE_TYPE_INIT(queue_agent_complete_type);
12143 err |= STASIS_MESSAGE_TYPE_INIT(queue_agent_dump_type);
12144 err |= STASIS_MESSAGE_TYPE_INIT(queue_agent_ringnoanswer_type);
12145
12146 if (err) {
12147 unload_module();
12149 }
12151}
static struct ast_custom_function queuevar_function
Definition: app_queue.c:9658
static int manager_queue_reset(struct mansession *s, const struct message *m)
Definition: app_queue.c:11031
static int pending_members_cmp(void *obj, void *arg, int flags)
Definition: app_queue.c:2706
static struct ast_custom_function queuemembercount_function
Definition: app_queue.c:9663
static struct ast_custom_function queuewaitingcount_function
Definition: app_queue.c:9679
static char * app_pqm
Definition: app_queue.c:1745
static struct ast_custom_function queuememberlist_function
Definition: app_queue.c:9684
static char * realtime_ringinuse_field
name of the ringinuse field in the realtime database
Definition: app_queue.c:1790
static int manager_add_queue_member(struct mansession *s, const struct message *m)
Definition: app_queue.c:10841
static int aqm_exec(struct ast_channel *chan, const char *data)
AddQueueMember application.
Definition: app_queue.c:8524
#define MAX_QUEUE_BUCKETS
Definition: app_queue.c:1730
static int upqm_exec(struct ast_channel *chan, const char *data)
UnpauseQueueMember application.
Definition: app_queue.c:8417
static void queue_agent_cb(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Definition: app_queue.c:6330
static char * app_ql
Definition: app_queue.c:1749
static void reload_queue_members(void)
Reload dynamic queue members persisted into the astdb.
Definition: app_queue.c:8270
static int rqm_exec(struct ast_channel *chan, const char *data)
RemoveQueueMember application.
Definition: app_queue.c:8453
#define MAX_CALL_ATTEMPT_BUCKETS
Definition: app_queue.c:2684
static char * app_rqm
Definition: app_queue.c:1743
static int manager_queue_rule_show(struct mansession *s, const struct message *m)
Definition: app_queue.c:10600
static int manager_queue_reload(struct mansession *s, const struct message *m)
Definition: app_queue.c:10999
static int pqm_exec(struct ast_channel *chan, const char *data)
PauseQueueMember application.
Definition: app_queue.c:8381
static int qupd_exec(struct ast_channel *chan, const char *data)
Update Queue with data of an outgoing call.
Definition: app_queue.c:11829
static int manager_queue_member_ringinuse(struct mansession *s, const struct message *m)
Definition: app_queue.c:11077
static char * app_qupd
Definition: app_queue.c:1751
static int manager_queue_member_penalty(struct mansession *s, const struct message *m)
Definition: app_queue.c:11111
static char * app_upqm
Definition: app_queue.c:1747
static struct ast_custom_function queuememberpenalty_function
Definition: app_queue.c:9689
static int queue_cmp_cb(void *obj, void *arg, int flags)
Definition: app_queue.c:2148
static int manager_request_withdraw_caller_from_queue(struct mansession *s, const struct message *m)
Definition: app_queue.c:11184
static char * app
Definition: app_queue.c:1739
static int queue_hash_cb(const void *obj, const int flags)
Definition: app_queue.c:2141
static int queue_exec(struct ast_channel *chan, const char *data)
The starting point for all queue calls.
Definition: app_queue.c:8695
static int pending_members_hash(const void *obj, const int flags)
Definition: app_queue.c:2686
static int manager_pause_queue_member(struct mansession *s, const struct message *m)
Definition: app_queue.c:10953
static int ql_exec(struct ast_channel *chan, const char *data)
QueueLog application.
Definition: app_queue.c:8618
static int manager_remove_queue_member(struct mansession *s, const struct message *m)
Definition: app_queue.c:10906
static struct stasis_message_router * agent_router
Definition: app_queue.c:11919
static void device_state_cb(void *unused, struct stasis_subscription *sub, struct stasis_message *msg)
set a member's status based on device state of that member's interface
Definition: app_queue.c:2811
static struct stasis_subscription * device_state_sub
Subscription to device state change messages.
Definition: app_queue.c:1775
static int manager_queues_summary(struct mansession *s, const struct message *m)
Summary of queue info via the AMI.
Definition: app_queue.c:10636
static int unload_module(void)
Definition: app_queue.c:11922
static int manager_queues_status(struct mansession *s, const struct message *m)
Queue status info via AMI.
Definition: app_queue.c:10718
static int realtime_reason_paused
does realtime backend support reason_paused
Definition: app_queue.c:1793
static struct ast_custom_function queuemembercount_dep
Definition: app_queue.c:9669
static char * app_aqm
Definition: app_queue.c:1741
static struct ast_cli_entry cli_queue[]
Definition: app_queue.c:11906
static struct ast_custom_function queuegetchannel_function
Definition: app_queue.c:9674
static struct stasis_forward * topic_forwarder
Definition: app_queue.c:11920
static struct ast_custom_function queueexists_function
Definition: app_queue.c:9653
static int manager_change_priority_caller_on_queue(struct mansession *s, const struct message *m)
Definition: app_queue.c:11137
static int manager_queue_log_custom(struct mansession *s, const struct message *m)
Definition: app_queue.c:10978
#define ast_cli_register_multiple(e, len)
Register multiple commands.
Definition: cli.h:265
struct stasis_topic * ast_device_state_topic_all(void)
Get the Stasis topic for device state messages.
Definition: devicestate.c:671
struct stasis_topic * ast_manager_get_topic(void)
Get the Stasis Message Bus API topic for AMI.
Definition: manager.c:454
static struct stasis_topic * manager_topic
A stasis_topic that all topics AMI cares about will be forwarded to.
Definition: manager.c:186
struct stasis_topic * ast_channel_topic_all(void)
A topic which publishes the events for all channels.
struct stasis_message_type * ast_channel_agent_logoff_type(void)
Message type for agent logoff on a channel.
struct stasis_message_type * ast_channel_agent_login_type(void)
Message type for agent login on a channel.
struct stasis_topic * ast_queue_topic_all(void)
Get the Stasis Message Bus API topic for queue messages.
Definition: main/app.c:3344
int ast_realtime_require_field(const char *family,...) attribute_sentinel
Inform realtime what fields that may be stored.
Definition: main/config.c:3769
#define ast_manager_register_xml(action, authority, func)
Register a manager callback using XML documentation to describe the manager.
Definition: manager.h:192
#define EVENT_FLAG_AGENT
Definition: manager.h:80
@ AST_MODULE_LOAD_SUCCESS
Definition: module.h:70
@ AST_MODULE_LOAD_DECLINE
Module has failed to load, may be in an inconsistent state.
Definition: module.h:78
#define ast_register_application_xml(app, execute)
Register an application using XML documentation.
Definition: module.h:640
#define ast_custom_function_register(acf)
Register a custom function.
Definition: pbx.h:1559
@ STASIS_SUBSCRIPTION_FILTER_SELECTIVE
Definition: stasis.h:297
int stasis_subscription_accept_message_type(struct stasis_subscription *subscription, const struct stasis_message_type *type)
Indicate to a subscription that we are interested in a message type.
Definition: stasis.c:1050
int stasis_subscription_set_filter(struct stasis_subscription *subscription, enum stasis_subscription_message_filter filter)
Set the message type filtering level on a subscription.
Definition: stasis.c:1104
#define STASIS_MESSAGE_TYPE_INIT(name)
Boiler-plate messaging macro for initializing message types.
Definition: stasis.h:1493
struct stasis_forward * stasis_forward_all(struct stasis_topic *from_topic, struct stasis_topic *to_topic)
Create a subscription which forwards all messages from one topic to another.
Definition: stasis.c:1605
#define stasis_subscribe(topic, callback, data)
Definition: stasis.h:649
#define stasis_message_router_create(topic)
Create a new message router object.
int stasis_message_router_add(struct stasis_message_router *router, struct stasis_message_type *message_type, stasis_subscription_cb callback, void *data)
Add a route to a message router.

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

◆ load_realtime_queues()

static void load_realtime_queues ( const char *  queuename)
static

Definition at line 4126 of file app_queue.c.

4127{
4128 struct ast_config *cfg = NULL;
4129 char *category = NULL;
4130 const char *name = NULL;
4131 struct call_queue *q = NULL;
4132
4133 if (!ast_check_realtime("queues")) {
4134 return;
4135 }
4136
4137 if (ast_strlen_zero(queuename)) {
4138 if ((cfg = ast_load_realtime_multientry("queues", "name LIKE", "%", SENTINEL))) {
4139 while ((category = ast_category_browse(cfg, category))) {
4140 name = ast_variable_retrieve(cfg, category, "name");
4142 queue_unref(q);
4143 }
4144 }
4145 ast_config_destroy(cfg);
4146 }
4147 } else {
4148 if ((q = find_load_queue_rt_friendly(queuename))) {
4149 queue_unref(q);
4150 }
4151 }
4152}

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

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

◆ load_realtime_rules()

static int load_realtime_rules ( void  )
static

Load queue rules from realtime.

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

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

Definition at line 3357 of file app_queue.c.

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

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

Referenced by reload_queue_rules().

◆ log_attended_transfer()

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

Definition at line 6500 of file app_queue.c.

6502{
6503 RAII_VAR(struct ast_str *, transfer_str, ast_str_create(32), ast_free);
6504
6505 if (!transfer_str) {
6506 ast_log(LOG_WARNING, "Unable to log attended transfer to queue log\n");
6507 return;
6508 }
6509
6510 switch (atxfer_msg->dest_type) {
6512 ast_str_set(&transfer_str, 0, "BRIDGE|%s", atxfer_msg->dest.bridge);
6513 break;
6516 ast_str_set(&transfer_str, 0, "APP|%s", atxfer_msg->dest.app);
6517 break;
6519 ast_str_set(&transfer_str, 0, "LINK|%s|%s", atxfer_msg->dest.links[0]->base->name,
6520 atxfer_msg->dest.links[1]->base->name);
6521 break;
6524 /* Threeways are headed off and should not be logged here */
6525 ast_assert(0);
6526 return;
6527 }
6528
6529 ast_queue_log(queue_data->queue->name, queue_data->caller_uniqueid, queue_data->member->membername, "ATTENDEDTRANSFER", "%s|%ld|%ld|%d",
6530 ast_str_buffer(transfer_str),
6531 (long) (queue_data->starttime - queue_data->holdstart),
6532 (long) (time(NULL) - queue_data->starttime), queue_data->caller_pos);
6533}
@ AST_ATTENDED_TRANSFER_DEST_FAIL
@ AST_ATTENDED_TRANSFER_DEST_BRIDGE_MERGE
@ AST_ATTENDED_TRANSFER_DEST_LOCAL_APP
@ AST_ATTENDED_TRANSFER_DEST_LINK
@ AST_ATTENDED_TRANSFER_DEST_APP
union ast_attended_transfer_message::@286 dest
struct ast_channel_snapshot * links[2]
char bridge[AST_UUID_STR_LEN]

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

Referenced by handle_attended_transfer().

◆ manager_add_queue_member()

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

Definition at line 10841 of file app_queue.c.

10842{
10843 const char *queuename, *interface, *penalty_s, *paused_s, *reason, *membername, *state_interface, *wrapuptime_s;
10844 int paused, penalty, wrapuptime = 0;
10845
10846 queuename = astman_get_header(m, "Queue");
10847 interface = astman_get_header(m, "Interface");
10848 penalty_s = astman_get_header(m, "Penalty");
10849 paused_s = astman_get_header(m, "Paused");
10850 reason = astman_get_header(m, "Reason"); /* Optional */
10851 membername = astman_get_header(m, "MemberName");
10852 state_interface = astman_get_header(m, "StateInterface");
10853 wrapuptime_s = astman_get_header(m, "Wrapuptime");
10854
10855 if (ast_strlen_zero(queuename)) {
10856 astman_send_error(s, m, "'Queue' not specified.");
10857 return 0;
10858 }
10859
10860 if (ast_strlen_zero(interface)) {
10861 astman_send_error(s, m, "'Interface' not specified.");
10862 return 0;
10863 }
10864
10865 if (ast_strlen_zero(penalty_s)) {
10866 penalty = 0;
10867 } else if (sscanf(penalty_s, "%30d", &penalty) != 1 || penalty < 0) {
10868 penalty = 0;
10869 }
10870
10871 if (ast_strlen_zero(wrapuptime_s)) {
10872 wrapuptime = 0;
10873 } else if (sscanf(wrapuptime_s, "%30d", &wrapuptime) != 1 || wrapuptime < 0) {
10874 wrapuptime = 0;
10875 }
10876
10877 if (ast_strlen_zero(paused_s)) {
10878 paused = 0;
10879 } else {
10880 paused = abs(ast_true(paused_s));
10881 }
10882
10883 switch (add_to_queue(queuename, interface, membername, penalty, paused, queue_persistent_members, state_interface, reason, wrapuptime)) {
10884 case RES_OKAY:
10885 if (ast_strlen_zero(membername) || !log_membername_as_agent) {
10886 ast_queue_log(queuename, "MANAGER", interface, "ADDMEMBER", "%s", paused ? "PAUSED" : "");
10887 } else {
10888 ast_queue_log(queuename, "MANAGER", membername, "ADDMEMBER", "%s", paused ? "PAUSED" : "");
10889 }
10890 astman_send_ack(s, m, "Added interface to queue");
10891 break;
10892 case RES_EXISTS:
10893 astman_send_error(s, m, "Unable to add interface: Already there");
10894 break;
10895 case RES_NOSUCHQUEUE:
10896 astman_send_error(s, m, "Unable to add interface to queue: No such queue");
10897 break;
10898 case RES_OUTOFMEMORY:
10899 astman_send_error(s, m, "Out of memory");
10900 break;
10901 }
10902
10903 return 0;
10904}
#define abs(x)
Definition: f2c.h:195
void astman_send_error(struct mansession *s, const struct message *m, char *error)
Send error in manager transaction.
Definition: manager.c:1986
void astman_send_ack(struct mansession *s, const struct message *m, char *msg)
Send ack in manager transaction.
Definition: manager.c:2018
const char * astman_get_header(const struct message *m, char *var)
Get header from manager transaction.
Definition: manager.c:1647

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

Referenced by load_module().

◆ manager_change_priority_caller_on_queue()

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

Definition at line 11137 of file app_queue.c.

11138{
11139 const char *queuename, *caller, *priority_s, *immediate_s;
11140 int priority = 0, immediate = 0;
11141
11142 queuename = astman_get_header(m, "Queue");
11143 caller = astman_get_header(m, "Caller");
11144 priority_s = astman_get_header(m, "Priority");
11145 immediate_s = astman_get_header(m, "Immediate");
11146
11147 if (ast_strlen_zero(queuename)) {
11148 astman_send_error(s, m, "'Queue' not specified.");
11149 return 0;
11150 }
11151
11152 if (ast_strlen_zero(caller)) {
11153 astman_send_error(s, m, "'Caller' not specified.");
11154 return 0;
11155 }
11156
11157 if (ast_strlen_zero(priority_s)) {
11158 astman_send_error(s, m, "'Priority' not specified.");
11159 return 0;
11160 } else if (sscanf(priority_s, "%30d", &priority) != 1) {
11161 astman_send_error(s, m, "'Priority' need integer.");
11162 return 0;
11163 }
11164
11165 if (!ast_strlen_zero(immediate_s)) {
11166 immediate = ast_true(immediate_s);
11167 }
11168
11169 switch (change_priority_caller_on_queue(queuename, caller, priority, immediate)) {
11170 case RES_OKAY:
11171 astman_send_ack(s, m, "Priority change for caller on queue");
11172 break;
11173 case RES_NOSUCHQUEUE:
11174 astman_send_error(s, m, "Unable to change priority caller on queue: No such queue");
11175 break;
11176 case RES_NOT_CALLER:
11177 astman_send_error(s, m, "Unable to change priority caller on queue: No such caller");
11178 break;
11179 }
11180
11181 return 0;
11182}

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

Referenced by load_module().

◆ manager_pause_queue_member()

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

Definition at line 10953 of file app_queue.c.

10954{
10955 const char *queuename, *interface, *paused_s, *reason;
10956 int paused;
10957
10958 interface = astman_get_header(m, "Interface");
10959 paused_s = astman_get_header(m, "Paused");
10960 queuename = astman_get_header(m, "Queue"); /* Optional - if not supplied, pause the given Interface in all queues */
10961 reason = astman_get_header(m, "Reason"); /* Optional */
10962
10963 if (ast_strlen_zero(interface) || ast_strlen_zero(paused_s)) {
10964 astman_send_error(s, m, "Need 'Interface' and 'Paused' parameters.");
10965 return 0;
10966 }
10967
10968 paused = abs(ast_true(paused_s));
10969
10970 if (set_member_paused(queuename, interface, reason, paused)) {
10971 astman_send_error(s, m, "Interface not found");
10972 } else {
10973 astman_send_ack(s, m, paused ? "Interface paused successfully" : "Interface unpaused successfully");
10974 }
10975 return 0;
10976}

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

Referenced by load_module().

◆ manager_queue_log_custom()

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

Definition at line 10978 of file app_queue.c.

10979{
10980 const char *queuename, *event, *message, *interface, *uniqueid;
10981
10982 queuename = astman_get_header(m, "Queue");
10983 uniqueid = astman_get_header(m, "UniqueId");
10984 interface = astman_get_header(m, "Interface");
10985 event = astman_get_header(m, "Event");
10986 message = astman_get_header(m, "Message");
10987
10988 if (ast_strlen_zero(queuename) || ast_strlen_zero(event)) {
10989 astman_send_error(s, m, "Need 'Queue' and 'Event' parameters.");
10990 return 0;
10991 }
10992
10993 ast_queue_log(queuename, S_OR(uniqueid, "NONE"), interface, event, "%s", message);
10994 astman_send_ack(s, m, "Event added successfully");
10995
10996 return 0;
10997}
Definition: astman.c:222

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

Referenced by load_module().

◆ manager_queue_member_penalty()

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

Definition at line 11111 of file app_queue.c.

11112{
11113 const char *queuename, *interface, *penalty_s;
11114 int penalty;
11115
11116 interface = astman_get_header(m, "Interface");
11117 penalty_s = astman_get_header(m, "Penalty");
11118 /* Optional - if not supplied, set the penalty value for the given Interface in all queues */
11119 queuename = astman_get_header(m, "Queue");
11120
11121 if (ast_strlen_zero(interface) || ast_strlen_zero(penalty_s)) {
11122 astman_send_error(s, m, "Need 'Interface' and 'Penalty' parameters.");
11123 return 0;
11124 }
11125
11126 penalty = atoi(penalty_s);
11127
11128 if (set_member_value((char *)queuename, (char *)interface, MEMBER_PENALTY, penalty)) {
11129 astman_send_error(s, m, "Invalid interface, queuename or penalty");
11130 } else {
11131 astman_send_ack(s, m, "Interface penalty set successfully");
11132 }
11133
11134 return 0;
11135}

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

Referenced by load_module().

◆ manager_queue_member_ringinuse()

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

Definition at line 11077 of file app_queue.c.

11078{
11079 const char *queuename, *interface, *ringinuse_s;
11080 int ringinuse;
11081
11082 interface = astman_get_header(m, "Interface");
11083 ringinuse_s = astman_get_header(m, "RingInUse");
11084
11085 /* Optional - if not supplied, set the ringinuse value for the given Interface in all queues */
11086 queuename = astman_get_header(m, "Queue");
11087
11088 if (ast_strlen_zero(interface) || ast_strlen_zero(ringinuse_s)) {
11089 astman_send_error(s, m, "Need 'Interface' and 'RingInUse' parameters.");
11090 return 0;
11091 }
11092
11093 if (ast_true(ringinuse_s)) {
11094 ringinuse = 1;
11095 } else if (ast_false(ringinuse_s)) {
11096 ringinuse = 0;
11097 } else {
11098 astman_send_error(s, m, "'RingInUse' parameter must be a truth value (yes/no, on/off, 0/1, etc)");
11099 return 0;
11100 }
11101
11102 if (set_member_value(queuename, interface, MEMBER_RINGINUSE, ringinuse)) {
11103 astman_send_error(s, m, "Invalid interface, queuename, or ringinuse value\n");
11104 } else {
11105 astman_send_ack(s, m, "Interface ringinuse set successfully");
11106 }
11107
11108 return 0;
11109}

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

Referenced by load_module().

◆ manager_queue_reload()

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

Definition at line 10999 of file app_queue.c.

11000{
11001 struct ast_flags mask = {0,};
11002 const char *queuename = NULL;
11003 int header_found = 0;
11004
11005 queuename = astman_get_header(m, "Queue");
11006 if (!strcasecmp(S_OR(astman_get_header(m, "Members"), ""), "yes")) {
11008 header_found = 1;
11009 }
11010 if (!strcasecmp(S_OR(astman_get_header(m, "Rules"), ""), "yes")) {
11012 header_found = 1;
11013 }
11014 if (!strcasecmp(S_OR(astman_get_header(m, "Parameters"), ""), "yes")) {
11016 header_found = 1;
11017 }
11018
11019 if (!header_found) {
11021 }
11022
11023 if (!reload_handler(1, &mask, queuename)) {
11024 astman_send_ack(s, m, "Queue reloaded successfully");
11025 } else {
11026 astman_send_error(s, m, "Error encountered while reloading queue");
11027 }
11028 return 0;
11029}

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

Referenced by load_module().

◆ manager_queue_reset()

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

Definition at line 11031 of file app_queue.c.

11032{
11033 const char *queuename = NULL;
11034 struct ast_flags mask = {QUEUE_RESET_STATS,};
11035
11036 queuename = astman_get_header(m, "Queue");
11037
11038 if (!reload_handler(1, &mask, queuename)) {
11039 astman_send_ack(s, m, "Queue stats reset successfully");
11040 } else {
11041 astman_send_error(s, m, "Error encountered while resetting queue stats");
11042 }
11043 return 0;
11044}

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

Referenced by load_module().

◆ manager_queue_rule_show()

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

Definition at line 10600 of file app_queue.c.

10601{
10602 const char *rule = astman_get_header(m, "Rule");
10603 const char *id = astman_get_header(m, "ActionID");
10604 struct rule_list *rl_iter;
10605 struct penalty_rule *pr_iter;
10606
10607 astman_append(s, "Response: Success\r\n");
10608 if (!ast_strlen_zero(id)) {
10609 astman_append(s, "ActionID: %s\r\n", id);
10610 }
10611
10613 AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) {
10614 if (ast_strlen_zero(rule) || !strcasecmp(rule, rl_iter->name)) {
10615 astman_append(s, "RuleList: %s\r\n", rl_iter->name);
10616 AST_LIST_TRAVERSE(&rl_iter->rules, pr_iter, list) {
10617 astman_append(s, "Rule: %d,%s%d,%s%d\r\n", pr_iter->time, pr_iter->max_relative && pr_iter->max_value >= 0 ? "+" : "", pr_iter->max_value, pr_iter->min_relative && pr_iter->min_value >= 0 ? "+" : "", pr_iter->min_value );
10618 }
10619 if (!ast_strlen_zero(rule)) {
10620 break;
10621 }
10622 }
10623 }
10625
10626 /*
10627 * Two blank lines instead of one because the Response and
10628 * ActionID headers used to not be present.
10629 */
10630 astman_append(s, "\r\n\r\n");
10631
10632 return RESULT_SUCCESS;
10633}

References AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_strlen_zero(), astman_append(), astman_get_header(), penalty_rule::list, penalty_rule::max_relative, penalty_rule::max_value, penalty_rule::min_relative, penalty_rule::min_value, rule_list::name, RESULT_SUCCESS, rule_list::rules, and penalty_rule::time.

Referenced by load_module().

◆ manager_queues_status()

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

Queue status info via AMI.

Definition at line 10718 of file app_queue.c.

10719{
10720 time_t now;
10721 int pos;
10722 int q_items = 0;
10723 const char *id = astman_get_header(m,"ActionID");
10724 const char *queuefilter = astman_get_header(m,"Queue");
10725 const char *memberfilter = astman_get_header(m,"Member");
10726 char idText[256];
10727 struct call_queue *q;
10728 struct queue_ent *qe;
10729 float sl = 0;
10730 float sl2 = 0;
10731 struct member *mem;
10732 struct ao2_iterator queue_iter;
10733 struct ao2_iterator mem_iter;
10734
10735 if (ast_check_realtime("queues")) {
10736 load_realtime_queues(queuefilter);
10737 }
10738
10739 astman_send_listack(s, m, "Queue status will follow", "start");
10740 time(&now);
10741 idText[0] = '\0';
10742 if (!ast_strlen_zero(id)) {
10743 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
10744 }
10745
10746 queue_iter = ao2_iterator_init(queues, 0);
10747 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
10748 ao2_lock(q);
10749
10750 /* List queue properties */
10751 if (ast_strlen_zero(queuefilter) || !strcasecmp(q->name, queuefilter)) {
10752 sl = ((q->callscompleted > 0) ? 100 * ((float)q->callscompletedinsl / (float)q->callscompleted) : 0);
10753 sl2 = (((q->callscompleted + q->callsabandoned) > 0) ? 100 * (((float)q->callsabandonedinsl + (float)q->callscompletedinsl) / ((float)q->callsabandoned + (float)q->callscompleted)) : 0);
10754
10755 astman_append(s, "Event: QueueParams\r\n"
10756 "Queue: %s\r\n"
10757 "Max: %d\r\n"
10758 "Strategy: %s\r\n"
10759 "Calls: %d\r\n"
10760 "Holdtime: %d\r\n"
10761 "TalkTime: %d\r\n"
10762 "Completed: %d\r\n"
10763 "Abandoned: %d\r\n"
10764 "ServiceLevel: %d\r\n"
10765 "ServicelevelPerf: %2.1f\r\n"
10766 "ServicelevelPerf2: %2.1f\r\n"
10767 "Weight: %d\r\n"
10768 "%s"
10769 "\r\n",
10770 q->name, q->maxlen, int2strat(q->strategy), q->count, q->holdtime, q->talktime, q->callscompleted,
10771 q->callsabandoned, q->servicelevel, sl, sl2, q->weight, idText);
10772 ++q_items;
10773
10774 /* List Queue Members */
10775 mem_iter = ao2_iterator_init(q->members, 0);
10776 while ((mem = ao2_iterator_next(&mem_iter))) {
10777 if (ast_strlen_zero(memberfilter) || !strcmp(mem->interface, memberfilter) || !strcmp(mem->membername, memberfilter)) {
10778 astman_append(s, "Event: QueueMember\r\n"
10779 "Queue: %s\r\n"
10780 "Name: %s\r\n"
10781 "Location: %s\r\n"
10782 "StateInterface: %s\r\n"
10783 "Membership: %s\r\n"
10784 "Penalty: %d\r\n"
10785 "CallsTaken: %d\r\n"
10786 "LastCall: %d\r\n"
10787 "LastPause: %d\r\n"
10788 "LoginTime: %d\r\n"
10789 "InCall: %d\r\n"
10790 "Status: %d\r\n"
10791 "Paused: %d\r\n"
10792 "PausedReason: %s\r\n"
10793 "Wrapuptime: %d\r\n"
10794 "%s"
10795 "\r\n",
10796 q->name, mem->membername, mem->interface, mem->state_interface, mem->dynamic ? "dynamic" : "static",
10797 mem->penalty, mem->calls, (int)mem->lastcall, (int)mem->lastpause, (int)mem->logintime, mem->starttime ? 1 : 0, mem->status,
10798 mem->paused, mem->reason_paused, mem->wrapuptime, idText);
10799 ++q_items;
10800 }
10801 ao2_ref(mem, -1);
10802 }
10803 ao2_iterator_destroy(&mem_iter);
10804
10805 /* List Queue Entries */
10806 pos = 1;
10807 for (qe = q->head; qe; qe = qe->next) {
10808 astman_append(s, "Event: QueueEntry\r\n"
10809 "Queue: %s\r\n"
10810 "Position: %d\r\n"
10811 "Channel: %s\r\n"
10812 "Uniqueid: %s\r\n"
10813 "CallerIDNum: %s\r\n"
10814 "CallerIDName: %s\r\n"
10815 "ConnectedLineNum: %s\r\n"
10816 "ConnectedLineName: %s\r\n"
10817 "Wait: %ld\r\n"
10818 "Priority: %d\r\n"
10819 "%s"
10820 "\r\n",
10821 q->name, pos++, ast_channel_name(qe->chan), ast_channel_uniqueid(qe->chan),
10826 (long) (now - qe->start), qe->prio, idText);
10827 ++q_items;
10828 }
10829 }
10830 ao2_unlock(q);
10831 queue_t_unref(q, "Done with iterator");
10832 }
10833 ao2_iterator_destroy(&queue_iter);
10834
10835 astman_send_list_complete_start(s, m, "QueueStatusComplete", q_items);
10837
10838 return RESULT_SUCCESS;
10839}
static void load_realtime_queues(const char *queuename)
Definition: app_queue.c:4126
static const char * int2strat(int strategy)
Definition: app_queue.c:2092
struct ast_party_connected_line * ast_channel_connected(struct ast_channel *chan)
struct ast_party_caller * ast_channel_caller(struct ast_channel *chan)
void astman_send_listack(struct mansession *s, const struct message *m, char *msg, char *listflag)
Send ack in manager transaction to begin a list.
Definition: manager.c:2028
void astman_send_list_complete_start(struct mansession *s, const struct message *m, const char *event_name, int count)
Start the list complete event.
Definition: manager.c:2064
void astman_send_list_complete_end(struct mansession *s)
End the list complete event.
Definition: manager.c:2072
#define S_COR(a, b, c)
returns the equivalent of logic or for strings, with an additional boolean check: second one if not e...
Definition: strings.h:87
struct ast_party_id id
Caller party ID.
Definition: channel.h:422
struct ast_party_id id
Connected party ID.
Definition: channel.h:460
struct ast_party_name name
Subscriber name.
Definition: channel.h:342
struct ast_party_number number
Subscriber phone number.
Definition: channel.h:344
unsigned char valid
TRUE if the name information is valid/present.
Definition: channel.h:281
char * str
Subscriber name (Malloced)
Definition: channel.h:266
unsigned char valid
TRUE if the number information is valid/present.
Definition: channel.h:299
char * str
Subscriber phone number (Malloced)
Definition: channel.h:293

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

Referenced by load_module().

◆ manager_queues_summary()

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

Summary of queue info via the AMI.

Definition at line 10636 of file app_queue.c.

10637{
10638 time_t now;
10639 int qmemcount = 0;
10640 int qmemavail = 0;
10641 int qchancount = 0;
10642 int qlongestholdtime = 0;
10643 int qsummaries = 0;
10644 const char *id = astman_get_header(m, "ActionID");
10645 const char *queuefilter = astman_get_header(m, "Queue");
10646 char idText[256];
10647 struct call_queue *q;
10648 struct queue_ent *qe;
10649 struct member *mem;
10650 struct ao2_iterator queue_iter;
10651 struct ao2_iterator mem_iter;
10652
10653 if (ast_check_realtime("queues")) {
10654 load_realtime_queues(queuefilter);
10655 }
10656
10657 astman_send_listack(s, m, "Queue summary will follow", "start");
10658 time(&now);
10659 idText[0] = '\0';
10660 if (!ast_strlen_zero(id)) {
10661 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
10662 }
10663 queue_iter = ao2_iterator_init(queues, 0);
10664 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
10665 ao2_lock(q);
10666
10667 /* List queue properties */
10668 if (ast_strlen_zero(queuefilter) || !strcasecmp(q->name, queuefilter)) {
10669 /* Reset the necessary local variables if no queuefilter is set*/
10670 qmemcount = 0;
10671 qmemavail = 0;
10672 qchancount = 0;
10673 qlongestholdtime = 0;
10674
10675 /* List Queue Members */
10676 mem_iter = ao2_iterator_init(q->members, 0);
10677 while ((mem = ao2_iterator_next(&mem_iter))) {
10678 if ((mem->status != AST_DEVICE_UNAVAILABLE) && (mem->status != AST_DEVICE_INVALID)) {
10679 ++qmemcount;
10680 if (member_status_available(mem->status) && !mem->paused) {
10681 ++qmemavail;
10682 }
10683 }
10684 ao2_ref(mem, -1);
10685 }
10686 ao2_iterator_destroy(&mem_iter);
10687 for (qe = q->head; qe; qe = qe->next) {
10688 if ((now - qe->start) > qlongestholdtime) {
10689 qlongestholdtime = now - qe->start;
10690 }
10691 ++qchancount;
10692 }
10693 astman_append(s, "Event: QueueSummary\r\n"
10694 "Queue: %s\r\n"
10695 "LoggedIn: %d\r\n"
10696 "Available: %d\r\n"
10697 "Callers: %d\r\n"
10698 "HoldTime: %d\r\n"
10699 "TalkTime: %d\r\n"
10700 "LongestHoldTime: %d\r\n"
10701 "%s"
10702 "\r\n",
10703 q->name, qmemcount, qmemavail, qchancount, q->holdtime, q->talktime, qlongestholdtime, idText);
10704 ++qsummaries;
10705 }
10706 ao2_unlock(q);
10707 queue_t_unref(q, "Done with iterator");
10708 }
10709 ao2_iterator_destroy(&queue_iter);
10710
10711 astman_send_list_complete_start(s, m, "QueueSummaryComplete", qsummaries);
10713
10714 return RESULT_SUCCESS;
10715}

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

Referenced by load_module().

◆ manager_remove_queue_member()

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

Definition at line 10906 of file app_queue.c.

10907{
10908 const char *queuename, *interface;
10909 struct member *mem = NULL;
10910
10911 queuename = astman_get_header(m, "Queue");
10912 interface = astman_get_header(m, "Interface");
10913
10914 if (ast_strlen_zero(queuename) || ast_strlen_zero(interface)) {
10915 astman_send_error(s, m, "Need 'Queue' and 'Interface' parameters.");
10916 return 0;
10917 }
10918
10920 mem = find_member_by_queuename_and_interface(queuename, interface);
10921 }
10922
10923 switch (remove_from_queue(queuename, interface)) {
10924 case RES_OKAY:
10925 if (!mem || ast_strlen_zero(mem->membername)) {
10926 ast_queue_log(queuename, "MANAGER", interface, "REMOVEMEMBER", "%s", "");
10927 } else {
10928 ast_queue_log(queuename, "MANAGER", mem->membername, "REMOVEMEMBER", "%s", "");
10929 }
10930 astman_send_ack(s, m, "Removed interface from queue");
10931 break;
10932 case RES_EXISTS:
10933 astman_send_error(s, m, "Unable to remove interface: Not there");
10934 break;
10935 case RES_NOSUCHQUEUE:
10936 astman_send_error(s, m, "Unable to remove interface from queue: No such queue");
10937 break;
10938 case RES_OUTOFMEMORY:
10939 astman_send_error(s, m, "Out of memory");
10940 break;
10941 case RES_NOT_DYNAMIC:
10942 astman_send_error(s, m, "Member not dynamic");
10943 break;
10944 }
10945
10946 if (mem) {
10947 ao2_ref(mem, -1);
10948 }
10949
10950 return 0;
10951}

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

Referenced by load_module().

◆ manager_request_withdraw_caller_from_queue()

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

Definition at line 11184 of file app_queue.c.

11185{
11186 const char *queuename, *caller, *withdraw_info;
11187
11188 queuename = astman_get_header(m, "Queue");
11189 caller = astman_get_header(m, "Caller");
11190 withdraw_info = astman_get_header(m, "WithdrawInfo");
11191
11192 if (ast_strlen_zero(queuename)) {
11193 astman_send_error(s, m, "'Queue' not specified.");
11194 return 0;
11195 }
11196
11197 if (ast_strlen_zero(caller)) {
11198 astman_send_error(s, m, "'Caller' not specified.");
11199 return 0;
11200 }
11201
11202 switch (request_withdraw_caller_from_queue(queuename, caller, withdraw_info)) {
11203 case RES_OKAY:
11204 astman_send_ack(s, m, "Withdraw requested successfully");
11205 break;
11206 case RES_NOSUCHQUEUE:
11207 astman_send_error(s, m, "Unable to request withdraw from queue: No such queue");
11208 break;
11209 case RES_NOT_CALLER:
11210 astman_send_error(s, m, "Unable to request withdraw from queue: No such caller");
11211 break;
11212 case RES_EXISTS:
11213 astman_send_error(s, m, "Unable to request withdraw from queue: Already requested");
11214 break;
11215 }
11216
11217 return 0;
11218}
static int request_withdraw_caller_from_queue(const char *queuename, const char *caller, const char *withdraw_info)
Request to withdraw a caller from a queue.
Definition: app_queue.c:7892

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

Referenced by load_module().

◆ mark_member_dead()

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

Definition at line 9958 of file app_queue.c.

9959{
9960 struct member *member = obj;
9961 if (!member->dynamic && !member->realtime) {
9962 member->delme = 1;
9963 }
9964 return 0;
9965}

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

Referenced by reload_single_queue().

◆ mark_unfound()

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

Definition at line 10112 of file app_queue.c.

10113{
10114 struct call_queue *q = obj;
10115 char *queuename = arg;
10116 if (!q->realtime && (ast_strlen_zero(queuename) || !strcasecmp(queuename, q->name))) {
10117 q->found = 0;
10118 }
10119 return 0;
10120}

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

Referenced by reload_queues().

◆ member_add_to_queue()

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

◆ member_cmp_fn()

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

Definition at line 3106 of file app_queue.c.

3107{
3108 struct member *mem1 = obj1;
3109 struct member *mem2 = obj2;
3110 const char *interface = (flags & OBJ_KEY) ? obj2 : mem2->interface;
3111
3112 return strcasecmp(mem1->interface, interface) ? 0 : CMP_MATCH | CMP_STOP;
3113}
@ CMP_STOP
Definition: astobj2.h:1028

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

Referenced by init_queue().

◆ member_hash_fn()

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

Definition at line 3090 of file app_queue.c.

3091{
3092 const struct member *mem = obj;
3093 const char *interface = (flags & OBJ_KEY) ? obj : mem->interface;
3094 const char *chname = strchr(interface, '/');
3095 int ret = 0, i;
3096
3097 if (!chname) {
3098 chname = interface;
3099 }
3100 for (i = 0; i < 5 && chname[i]; i++) {
3101 ret += compress_char(chname[i]) << (i * 6);
3102 }
3103 return ret;
3104}
static int compress_char(const char c)
Definition: app_queue.c:3080

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

Referenced by init_queue().

◆ member_remove_from_queue()

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

Definition at line 3732 of file app_queue.c.

3733{
3735 ao2_lock(queue->members);
3738 ao2_unlink(queue->members, mem);
3739 ao2_unlock(queue->members);
3740}
static void queue_member_follower_removal(struct call_queue *queue, struct member *mem)
Definition: app_queue.c:2212
#define QUEUE_UNKNOWN_PAUSED_DEVSTATE
Definition: app_queue.c:3708
#define ao2_unlink(container, obj)
Remove an object from a container.
Definition: astobj2.h:1578

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

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

◆ member_status_available()

static int member_status_available ( int  status)
static

Definition at line 4813 of file app_queue.c.

4814{
4816}

References AST_DEVICE_NOT_INUSE, AST_DEVICE_UNKNOWN, and status.

Referenced by can_ring_entry(), and manager_queues_summary().

◆ num_available_members()

static int num_available_members ( struct call_queue q)
static

Get the number of members available to accept a call.

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

Definition at line 4679 of file app_queue.c.

4680{
4681 struct member *mem;
4682 int avl = 0;
4683 struct ao2_iterator mem_iter;
4684
4685 mem_iter = ao2_iterator_init(q->members, 0);
4686 while ((mem = ao2_iterator_next(&mem_iter))) {
4687
4688 avl += is_member_available(q, mem);
4689 ao2_ref(mem, -1);
4690
4691 /* If autofill is not enabled or if the queue's strategy is ringall, then
4692 * we really don't care about the number of available members so much as we
4693 * do that there is at least one available.
4694 *
4695 * In fact, we purposely will return from this function stating that only
4696 * one member is available if either of those conditions hold. That way,
4697 * functions which determine what action to take based on the number of available
4698 * members will operate properly. The reasoning is that even if multiple
4699 * members are available, only the head caller can actually be serviced.
4700 */
4701 if ((!q->autofill || q->strategy == QUEUE_STRATEGY_RINGALL) && avl) {
4702 break;
4703 }
4704 }
4705 ao2_iterator_destroy(&mem_iter);
4706
4707 return avl;
4708}

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

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

◆ parse_empty_options()

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

Definition at line 3459 of file app_queue.c.

3460{
3461 char *value_copy = ast_strdupa(value);
3462 char *option = NULL;
3463 while ((option = strsep(&value_copy, ","))) {
3464 if (!strcasecmp(option, "paused")) {
3465 *empty |= QUEUE_EMPTY_PAUSED;
3466 } else if (!strcasecmp(option, "penalty")) {
3467 *empty |= QUEUE_EMPTY_PENALTY;
3468 } else if (!strcasecmp(option, "inuse")) {
3469 *empty |= QUEUE_EMPTY_INUSE;
3470 } else if (!strcasecmp(option, "ringing")) {
3471 *empty |= QUEUE_EMPTY_RINGING;
3472 } else if (!strcasecmp(option, "invalid")) {
3473 *empty |= QUEUE_EMPTY_INVALID;
3474 } else if (!strcasecmp(option, "wrapup")) {
3475 *empty |= QUEUE_EMPTY_WRAPUP;
3476 } else if (!strcasecmp(option, "unavailable")) {
3477 *empty |= QUEUE_EMPTY_UNAVAILABLE;
3478 } else if (!strcasecmp(option, "unknown")) {
3479 *empty |= QUEUE_EMPTY_UNKNOWN;
3480 } else if (!strcasecmp(option, "loose")) {
3482 } else if (!strcasecmp(option, "strict")) {
3484 } else if ((ast_false(option) && joinempty) || (ast_true(option) && !joinempty)) {
3486 } else if ((ast_false(option) && !joinempty) || (ast_true(option) && joinempty)) {
3487 *empty = 0;
3488 } else {
3489 ast_log(LOG_WARNING, "Unknown option %s for '%s'\n", option, joinempty ? "joinempty" : "leavewhenempty");
3490 }
3491 }
3492}

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

Referenced by queue_set_param().

◆ pending_members_cmp()

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

Definition at line 2706 of file app_queue.c.

2707{
2708 const struct member *object_left = obj;
2709 const struct member *object_right = arg;
2710 const char *right_key = arg;
2711 int cmp;
2712
2713 switch (flags & OBJ_SEARCH_MASK) {
2714 case OBJ_SEARCH_OBJECT:
2715 right_key = object_right->interface;
2716 /* Fall through */
2717 case OBJ_SEARCH_KEY:
2718 cmp = strcasecmp(object_left->interface, right_key);
2719 break;
2721 /* Not supported by container. */
2722 ast_assert(0);
2723 return 0;
2724 default:
2725 cmp = 0;
2726 break;
2727 }
2728 if (cmp) {
2729 return 0;
2730 }
2731 return CMP_MATCH;
2732}
@ OBJ_SEARCH_PARTIAL_KEY
The arg parameter is a partial search key similar to OBJ_SEARCH_KEY.
Definition: astobj2.h:1116
@ OBJ_SEARCH_MASK
Search option field mask.
Definition: astobj2.h:1072
@ OBJ_SEARCH_KEY
The arg parameter is a search key, but is not an object.
Definition: astobj2.h:1101

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

Referenced by load_module().

◆ pending_members_hash()

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

Definition at line 2686 of file app_queue.c.

2687{
2688 const struct member *object;
2689 const char *key;
2690
2691 switch (flags & OBJ_SEARCH_MASK) {
2692 case OBJ_SEARCH_KEY:
2693 key = obj;
2694 break;
2695 case OBJ_SEARCH_OBJECT:
2696 object = obj;
2697 key = object->interface;
2698 break;
2699 default:
2700 ast_assert(0);
2701 return 0;
2702 }
2703 return ast_str_case_hash(key);
2704}
static force_inline int attribute_pure ast_str_case_hash(const char *str)
Compute a hash value on a case-insensitive string.
Definition: strings.h:1303

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

Referenced by load_module().

◆ pending_members_remove()

static void pending_members_remove ( struct member mem)
static

Definition at line 2734 of file app_queue.c.

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

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

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

◆ play_file()

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

Definition at line 4313 of file app_queue.c.

4314{
4315 int res;
4316
4317 if (ast_strlen_zero(filename)) {
4318 return 0;
4319 }
4320
4321 if (!ast_fileexists(filename, NULL, ast_channel_language(chan))) {
4322 return 0;
4323 }
4324
4325 ast_stopstream(chan);
4326
4327 res = ast_streamfile(chan, filename, ast_channel_language(chan));
4328 if (!res) {
4329 res = ast_waitstream(chan, AST_DIGIT_ANY);
4330 }
4331
4332 ast_stopstream(chan);
4333
4334 return res;
4335}
const char * ast_channel_language(const struct ast_channel *chan)
int ast_stopstream(struct ast_channel *c)
Stops a stream.
Definition: file.c:222
int ast_streamfile(struct ast_channel *c, const char *filename, const char *preflang)
Streams a file.
Definition: file.c:1301
int ast_fileexists(const char *filename, const char *fmt, const char *preflang)
Checks for the existence of a given file.
Definition: file.c:1137
#define AST_DIGIT_ANY
Definition: file.h:48
int ast_waitstream(struct ast_channel *c, const char *breakon)
Waits for a stream to stop or digit to be pressed.
Definition: file.c:1848

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

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

◆ pqm_exec()

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

PauseQueueMember application.

Definition at line 8381 of file app_queue.c.

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

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

Referenced by load_module().

◆ print_queue()

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

Print a single queue to AMI or the CLI.

Definition at line 10260 of file app_queue.c.

10261{
10262 float sl;
10263 float sl2;
10264 struct ao2_iterator mem_iter;
10265 struct ast_str *out = ast_str_alloca(512);
10266 time_t now = time(NULL);
10267
10268 ast_str_set(&out, 0, "%s has %d calls (max ", q->name, q->count);
10269 if (q->maxlen) {
10270 ast_str_append(&out, 0, "%d", q->maxlen);
10271 } else {
10272 ast_str_append(&out, 0, "unlimited");
10273 }
10274 sl = 0;
10275 sl2 = 0;
10276 if (q->callscompleted > 0) {
10277 sl = 100 * ((float) q->callscompletedinsl / (float) q->callscompleted);
10278 }
10279 if (q->callscompleted + q->callsabandoned > 0) {
10280 sl2 =100 * (((float)q->callsabandonedinsl + (float)q->callscompletedinsl) / ((float)q->callsabandoned + (float)q->callscompleted));
10281 }
10282
10283 ast_str_append(&out, 0, ") in '%s' strategy (%ds holdtime, %ds talktime), W:%d, C:%d, A:%d, SL:%2.1f%%, SL2:%2.1f%% within %ds",
10285 do_print(s, fd, ast_str_buffer(out));
10286 if (!ao2_container_count(q->members)) {
10287 do_print(s, fd, " No Members");
10288 } else {
10289 struct member *mem;
10290
10291 do_print(s, fd, " Members: ");
10292 mem_iter = ao2_iterator_init(q->members, 0);
10293 while ((mem = ao2_iterator_next(&mem_iter))) {
10294 ast_str_set(&out, 0, " %s", mem->membername);
10295 if (strcasecmp(mem->membername, mem->interface)) {
10296 ast_str_append(&out, 0, " (%s", mem->interface);
10298 && strcmp(mem->state_interface, mem->interface)) {
10299 ast_str_append(&out, 0, " from %s", mem->state_interface);
10300 }
10301 ast_str_append(&out, 0, ")");
10302 }
10303 if (mem->penalty) {
10304 ast_str_append(&out, 0, " with penalty %d", mem->penalty);
10305 }
10306
10307 ast_str_append(&out, 0, " (ringinuse %s)", mem->ringinuse ? "enabled" : "disabled");
10308
10309 ast_str_append(&out, 0, "%s%s%s%s%s%s%s%s%s",
10310 mem->dynamic ? ast_term_color(COLOR_CYAN, COLOR_BLACK) : "", mem->dynamic ? " (dynamic)" : "", ast_term_reset(),
10311 mem->realtime ? ast_term_color(COLOR_MAGENTA, COLOR_BLACK) : "", mem->realtime ? " (realtime)" : "", ast_term_reset(),
10312 mem->starttime ? ast_term_color(COLOR_BROWN, COLOR_BLACK) : "", mem->starttime ? " (in call)" : "", ast_term_reset());
10313
10314 if (mem->paused) {
10315 ast_str_append(&out, 0, " %s(paused%s%s was %ld secs ago)%s",
10317 ast_strlen_zero(mem->reason_paused) ? "" : ":",
10319 (long) (now - mem->lastpause),
10320 ast_term_reset());
10321 }
10322
10323 ast_str_append(&out, 0, " (%s%s%s)",
10328 if (mem->calls) {
10329 ast_str_append(&out, 0, " has taken %d calls (last was %ld secs ago)",
10330 mem->calls, (long) (now - mem->lastcall));
10331 } else {
10332 ast_str_append(&out, 0, " has taken no calls yet");
10333 }
10334 ast_str_append(&out, 0, " %s(login was %ld secs ago)%s",
10336 (long) (now - mem->logintime),
10337 ast_term_reset());
10338 do_print(s, fd, ast_str_buffer(out));
10339 ao2_ref(mem, -1);
10340 }
10341 ao2_iterator_destroy(&mem_iter);
10342 }
10343 if (!q->head) {
10344 do_print(s, fd, " No Callers");
10345 } else {
10346 struct queue_ent *qe;
10347 int pos = 1;
10348
10349 do_print(s, fd, " Callers: ");
10350 for (qe = q->head; qe; qe = qe->next) {
10351 ast_str_set(&out, 0, " %d. %s (wait: %ld:%2.2ld, prio: %d)",
10352 pos++, ast_channel_name(qe->chan), (long) (now - qe->start) / 60,
10353 (long) (now - qe->start) % 60, qe->prio);
10354 do_print(s, fd, ast_str_buffer(out));
10355 }
10356 }
10357 do_print(s, fd, ""); /* blank line between entries */
10358}
const char * ast_term_reset(void)
Returns the terminal reset code.
Definition: term.c:357
#define COLOR_CYAN
Definition: term.h:62
#define COLOR_MAGENTA
Definition: term.h:60
#define COLOR_BROWN
Definition: term.h:56
const char * ast_term_color(int fgcolor, int bgcolor)
Return a color sequence string.
Definition: term.c:341
#define COLOR_BLACK
Definition: term.h:50
#define COLOR_RED
Definition: term.h:52
#define COLOR_GREEN
Definition: term.h:54

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

Referenced by __queues_show().

◆ publish_dial_end_event()

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

Definition at line 4627 of file app_queue.c.

4628{
4629 struct callattempt *cur;
4630
4631 for (cur = outgoing; cur; cur = cur->q_next) {
4632 if (cur->chan && cur->chan != exception) {
4634 }
4635 }
4636}
struct callattempt * q_next
Definition: app_queue.c:1840
FILE * in
Definition: utils/frame.c:33

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

Referenced by ring_entry(), and wait_for_answer().

◆ publish_queue_member_pause()

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

Definition at line 7931 of file app_queue.c.

7932{
7933 struct ast_json *json_blob = queue_member_blob_create(q, member);
7934
7935 if (!json_blob) {
7936 return -1;
7937 }
7938
7939 queue_publish_member_blob(queue_member_pause_type(), json_blob);
7940
7941 return 0;
7942}

References queue_member_blob_create(), and queue_publish_member_blob().

Referenced by set_queue_member_pause().

◆ ql_exec()

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

QueueLog application.

Definition at line 8618 of file app_queue.c.

8619{
8620 char *parse;
8621
8623 AST_APP_ARG(queuename);
8624 AST_APP_ARG(uniqueid);
8625 AST_APP_ARG(membername);
8627 AST_APP_ARG(params);
8628 );
8629
8630 if (ast_strlen_zero(data)) {
8631 ast_log(LOG_WARNING, "QueueLog requires arguments (queuename,uniqueid,membername,event[,additionalinfo]\n");
8632 return -1;
8633 }
8634
8635 parse = ast_strdupa(data);
8636
8638
8639 if (ast_strlen_zero(args.queuename) || ast_strlen_zero(args.uniqueid)
8640 || ast_strlen_zero(args.membername) || ast_strlen_zero(args.event)) {
8641 ast_log(LOG_WARNING, "QueueLog requires arguments (queuename,uniqueid,membername,event[,additionalinfo])\n");
8642 return -1;
8643 }
8644
8645 ast_queue_log(args.queuename, args.uniqueid, args.membername, args.event,
8646 "%s", args.params ? args.params : "");
8647
8648 return 0;
8649}

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

Referenced by load_module().

◆ queue_agent_called_to_ami()

static struct ast_manager_event_blob * queue_agent_called_to_ami ( struct stasis_message message)
static

Definition at line 2434 of file app_queue.c.

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

References queue_multi_channel_to_ami().

◆ queue_agent_cb()

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

Definition at line 6330 of file app_queue.c.

6332{
6333 struct ast_channel_blob *agent_blob;
6334
6335 agent_blob = stasis_message_data(msg);
6336
6338 ast_queue_log("NONE", agent_blob->snapshot->base->uniqueid,
6339 ast_json_string_get(ast_json_object_get(agent_blob->blob, "agent")),
6340 "AGENTLOGIN", "%s", agent_blob->snapshot->base->name);
6342 ast_queue_log("NONE", agent_blob->snapshot->base->uniqueid,
6343 ast_json_string_get(ast_json_object_get(agent_blob->blob, "agent")),
6344 "AGENTLOGOFF", "%s|%ld", agent_blob->snapshot->base->name,
6345 (long) ast_json_integer_get(ast_json_object_get(agent_blob->blob, "logintime")));
6346 }
6347}

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

Referenced by load_module().

◆ queue_agent_complete_to_ami()

static struct ast_manager_event_blob * queue_agent_complete_to_ami ( struct stasis_message message)
static

Definition at line 2444 of file app_queue.c.

2445{
2446 return queue_multi_channel_to_ami("AgentComplete", message);
2447}

References queue_multi_channel_to_ami().

◆ queue_agent_connect_to_ami()

static struct ast_manager_event_blob * queue_agent_connect_to_ami ( struct stasis_message message)
static

Definition at line 2439 of file app_queue.c.

2440{
2441 return queue_multi_channel_to_ami("AgentConnect", message);
2442}

References queue_multi_channel_to_ami().

◆ queue_agent_dump_to_ami()

static struct ast_manager_event_blob * queue_agent_dump_to_ami ( struct stasis_message message)
static

Definition at line 2449 of file app_queue.c.

2450{
2451 return queue_multi_channel_to_ami("AgentDump", message);
2452}

References queue_multi_channel_to_ami().

◆ queue_agent_ringnoanswer_to_ami()

static struct ast_manager_event_blob * queue_agent_ringnoanswer_to_ami ( struct stasis_message message)
static

Definition at line 2454 of file app_queue.c.

2455{
2456 return queue_multi_channel_to_ami("AgentRingNoAnswer", message);
2457}

References queue_multi_channel_to_ami().

◆ queue_bridge_cb()

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

Definition at line 6693 of file app_queue.c.

6695{
6697 ao2_cleanup(userdata);
6698 }
6699}
struct stasis_forward * sub
Definition: res_corosync.c:240
int stasis_subscription_final_message(struct stasis_subscription *sub, struct stasis_message *msg)
Determine whether a message is the final message to be received on a subscription.
Definition: stasis.c:1201

References ao2_cleanup, stasis_subscription_final_message(), and sub.

Referenced by setup_stasis_subs().

◆ queue_caller_abandon_to_ami()

static struct ast_manager_event_blob * queue_caller_abandon_to_ami ( struct stasis_message message)
static

Definition at line 2314 of file app_queue.c.

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

References queue_channel_to_ami().

◆ queue_caller_join_to_ami()

static struct ast_manager_event_blob * queue_caller_join_to_ami ( struct stasis_message message)
static

Definition at line 2304 of file app_queue.c.

2305{
2306 return queue_channel_to_ami("QueueCallerJoin", message);
2307}

References queue_channel_to_ami().

◆ queue_caller_leave_to_ami()

static struct ast_manager_event_blob * queue_caller_leave_to_ami ( struct stasis_message message)
static

Definition at line 2309 of file app_queue.c.

2310{
2311 return queue_channel_to_ami("QueueCallerLeave", message);
2312}

References queue_channel_to_ami().

◆ queue_channel_cb()

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

Definition at line 6918 of file app_queue.c.

6920{
6922 ao2_cleanup(userdata);
6923 }
6924}

References ao2_cleanup, stasis_subscription_final_message(), and sub.

Referenced by setup_stasis_subs().

◆ queue_channel_to_ami()

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

Definition at line 2285 of file app_queue.c.

2286{
2288 RAII_VAR(struct ast_str *, channel_string, NULL, ast_free);
2289 RAII_VAR(struct ast_str *, event_string, NULL, ast_free);
2290
2291 channel_string = ast_manager_build_channel_state_string(obj->snapshot);
2292 event_string = ast_manager_str_from_json_object(obj->blob, NULL);
2293 if (!channel_string || !event_string) {
2294 return NULL;
2295 }
2296
2298 "%s"
2299 "%s",
2300 ast_str_buffer(channel_string),
2301 ast_str_buffer(event_string));
2302}
static const char type[]
Definition: chan_ooh323.c:109
struct ast_str * ast_manager_str_from_json_object(struct ast_json *blob, key_exclusion_cb exclusion_cb)
Convert a JSON object into an AMI compatible string.
Definition: manager.c:555
struct ast_str * ast_manager_build_channel_state_string(const struct ast_channel_snapshot *snapshot)
Generate the AMI message body from a channel snapshot.
struct ast_manager_event_blob * ast_manager_event_blob_create(int event_flags, const char *manager_event, const char *extra_fields_fmt,...)
Construct a ast_manager_event_blob.
Definition: manager.c:10237

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

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

◆ queue_cmp_cb()

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

Definition at line 2148 of file app_queue.c.

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

References CMP_MATCH, CMP_STOP, and call_queue::name.

Referenced by load_module().

◆ queue_delme_members_decrement_followers()

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

Definition at line 2194 of file app_queue.c.

2195{
2196 struct member *mem = obj;
2197 struct call_queue *queue = arg;
2198 int rrpos = mem->queuepos;
2199
2200 if (mem->delme) {
2202 }
2203
2204 return 0;
2205}
static int queue_member_decrement_followers(void *obj, void *arg, int flag)
Definition: app_queue.c:2175
#define ao2_callback(c, flags, cb_fn, arg)
ao2_callback() is a generic function that applies cb_fn() to all objects in a container,...
Definition: astobj2.h:1693
@ OBJ_MULTIPLE
Definition: astobj2.h:1049

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

Referenced by reload_single_queue().

◆ queue_exec()

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

The starting point for all queue calls.

The process involved here is to

  1. Parse the options specified in the call to Queue()
  2. Join the queue
  3. Wait in a loop until it is our turn to try calling a queue member
  4. Attempt to call a queue member
  5. If 4. did not result in a bridged call, then check for between call options such as periodic announcements etc.
  6. Try 4 again unless some condition (such as an expiration time) causes us to exit the queue.

Definition at line 8695 of file app_queue.c.

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

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

Referenced by load_module().

◆ queue_function_exists()

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

Check if a given queue exists.

Definition at line 9173 of file app_queue.c.

9174{
9175 struct call_queue *q;
9176
9177 buf[0] = '\0';
9178
9179 if (ast_strlen_zero(data)) {
9180 ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd);
9181 return -1;
9182 }
9184 snprintf(buf, len, "%d", q != NULL? 1 : 0);
9185 if (q) {
9186 queue_t_unref(q, "Done with temporary reference in QUEUE_EXISTS()");
9187 }
9188
9189 return 0;
9190}
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)

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

◆ queue_function_mem_read()

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

Get number either busy / free / ready or total members of a specific queue.

Get or set member properties penalty / paused / ringinuse

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

Definition at line 9215 of file app_queue.c.

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

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

◆ queue_function_mem_write()

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

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

Definition at line 9317 of file app_queue.c.

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

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

◆ queue_function_memberpenalty_read()

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

Dialplan function QUEUE_MEMBER_PENALTY() Gets the members penalty.

Definition at line 9585 of file app_queue.c.

9586{
9587 int penalty;
9589 AST_APP_ARG(queuename);
9590 AST_APP_ARG(interface);
9591 );
9592 /* Make sure the returned value on error is NULL. */
9593 buf[0] = '\0';
9594
9595 if (ast_strlen_zero(data)) {
9596 ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n");
9597 return -1;
9598 }
9599
9601
9602 if (args.argc < 2) {
9603 ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n");
9604 return -1;
9605 }
9606
9607 penalty = get_member_penalty (args.queuename, args.interface);
9608
9609 if (penalty >= 0) { /* remember that buf is already '\0' */
9610 snprintf (buf, len, "%d", penalty);
9611 }
9612
9613 return 0;
9614}
static int get_member_penalty(char *queuename, char *interface)
Gets members penalty.
Definition: app_queue.c:8239

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

◆ queue_function_memberpenalty_write()

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

Dialplan function QUEUE_MEMBER_PENALTY() Sets the members penalty.

Definition at line 9617 of file app_queue.c.

9618{
9619 int penalty;
9621 AST_APP_ARG(queuename);
9622 AST_APP_ARG(interface);
9623 );
9624
9625 if (ast_strlen_zero(data)) {
9626 ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n");
9627 return -1;
9628 }
9629
9631
9632 if (args.argc < 2) {
9633 ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n");
9634 return -1;
9635 }
9636
9637 penalty = atoi(value);
9638
9639 if (ast_strlen_zero(args.interface)) {
9640 ast_log (LOG_ERROR, "<interface> parameter can't be null\n");
9641 return -1;
9642 }
9643
9644 /* if queuename = NULL then penalty will be set for interface in all the queues. */
9645 if (set_member_value(args.queuename, args.interface, MEMBER_PENALTY, penalty)) {
9646 ast_log(LOG_ERROR, "Invalid interface, queue or penalty\n");
9647 return -1;
9648 }
9649
9650 return 0;
9651}

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

◆ queue_function_qac_dep()

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

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

Return values
numberof members
-1on error

Definition at line 9380 of file app_queue.c.

9381{
9382 int count = 0;
9383 struct member *m;
9384 struct call_queue *q;
9385 struct ao2_iterator mem_iter;
9386 static int depflag = 1;
9387
9388 if (depflag) {
9389 depflag = 0;
9390 ast_log(LOG_NOTICE, "The function QUEUE_MEMBER_COUNT has been deprecated in favor of the QUEUE_MEMBER function and will not be in further releases.\n");
9391 }
9392
9393 if (ast_strlen_zero(data)) {
9394 ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd);
9395 return -1;
9396 }
9397
9398 if ((q = find_load_queue_rt_friendly(data))) {
9399 ao2_lock(q);
9400 mem_iter = ao2_iterator_init(q->members, 0);
9401 while ((m = ao2_iterator_next(&mem_iter))) {
9402 /* Count the agents who are logged in and presently answering calls */
9403 if ((m->status != AST_DEVICE_UNAVAILABLE) && (m->status != AST_DEVICE_INVALID)) {
9404 count++;
9405 }
9406 ao2_ref(m, -1);
9407 }
9408 ao2_iterator_destroy(&mem_iter);
9409 ao2_unlock(q);
9410 queue_t_unref(q, "Done with temporary reference in QUEUE_MEMBER_COUNT");
9411 } else {
9412 ast_log(LOG_WARNING, "queue %s was not found\n", data);
9413 }
9414
9415 snprintf(buf, len, "%d", count);
9416
9417 return 0;
9418}

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

◆ queue_function_queuegetchannel()

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

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

Definition at line 9421 of file app_queue.c.

9422{
9423 int position;
9424 char *parse;
9425 struct call_queue *q;
9426 struct ast_variable *var;
9427
9429 AST_APP_ARG(queuename);
9430 AST_APP_ARG(position);
9431 );
9432
9433 buf[0] = '\0';
9434
9435 if (ast_strlen_zero(data)) {
9436 ast_log(LOG_ERROR, "Missing argument. QUEUE_GET_CHANNEL(<queuename>,<position>)\n");
9437 return -1;
9438 }
9439
9440 parse = ast_strdupa(data);
9442
9443 if (ast_strlen_zero(args.queuename)) {
9444 ast_log (LOG_ERROR, "The <queuename> parameter is required.\n");
9445 return -1;
9446 }
9447
9448 if (ast_strlen_zero(args.position)) {
9449 position = 1;
9450 } else {
9451 if (sscanf(args.position, "%30d", &position) != 1) {
9452 ast_log (LOG_ERROR, "<position> parameter must be an integer.\n");
9453 return -1;
9454 }
9455 if (position < 1) {
9456 ast_log (LOG_ERROR, "<position> parameter must be an integer greater than zero.\n");
9457 return -1;
9458 }
9459 }
9460
9461 {
9462 struct call_queue tmpq = {
9463 .name = args.queuename,
9464 };
9465
9466 q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Find for QUEUE_GET_CHANNEL()");
9467 }
9468 if (q) {
9469 ao2_lock(q);
9470 if (q->count >= position) {
9471 struct queue_ent *qe;
9472
9473 for (qe = q->head; qe; qe = qe->next) {
9474 if (qe->pos == position) {
9476 break;
9477 }
9478 }
9479 }
9480 ao2_unlock(q);
9481 queue_t_unref(q, "Done with reference in QUEUE_GET_CHANNEL()");
9482 return 0;
9483 }
9484
9485 var = ast_load_realtime("queues", "name", args.queuename, SENTINEL);
9486 if (var) {
9487 /* if the queue is realtime but was not found in memory, this
9488 * means that the queue had been deleted from memory since it was
9489 * "dead."
9490 */
9492 return 0;
9493 }
9494
9495 ast_log(LOG_WARNING, "queue %s was not found\n", args.queuename);
9496 return 0;
9497}

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

◆ queue_function_queuememberlist()

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

Dialplan function QUEUE_MEMBER_LIST() Get list of members in a specific queue.

Definition at line 9537 of file app_queue.c.

9538{
9539 struct call_queue *q;
9540 struct member *m;
9541
9542 /* Ensure an otherwise empty list doesn't return garbage */
9543 buf[0] = '\0';
9544
9545 if (ast_strlen_zero(data)) {
9546 ast_log(LOG_ERROR, "QUEUE_MEMBER_LIST requires an argument: queuename\n");
9547 return -1;
9548 }
9549
9550 if ((q = find_load_queue_rt_friendly(data))) {
9551 int buflen = 0, count = 0;
9552 struct ao2_iterator mem_iter;
9553
9554 ao2_lock(q);
9555 mem_iter = ao2_iterator_init(q->members, 0);
9556 while ((m = ao2_iterator_next(&mem_iter))) {
9557 /* strcat() is always faster than printf() */
9558 if (count++) {
9559 strncat(buf + buflen, ",", len - buflen - 1);
9560 buflen++;
9561 }
9562 strncat(buf + buflen, m->interface, len - buflen - 1);
9563 buflen += strlen(m->interface);
9564 /* Safeguard against overflow (negative length) */
9565 if (buflen >= len - 2) {
9566 ao2_ref(m, -1);
9567 ast_log(LOG_WARNING, "Truncating list\n");
9568 break;
9569 }
9570 ao2_ref(m, -1);
9571 }
9572 ao2_iterator_destroy(&mem_iter);
9573 ao2_unlock(q);
9574 queue_t_unref(q, "Done with QUEUE_MEMBER_LIST()");
9575 } else
9576 ast_log(LOG_WARNING, "queue %s was not found\n", data);
9577
9578 /* We should already be terminated, but let's make sure. */
9579 buf[len - 1] = '\0';
9580
9581 return 0;
9582}

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

◆ queue_function_queuewaitingcount()

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

Dialplan function QUEUE_WAITING_COUNT() Get number callers waiting in a specific queue.

Definition at line 9500 of file app_queue.c.

9501{
9502 int count = 0;
9503 struct call_queue *q, tmpq = {
9504 .name = data,
9505 };
9506 struct ast_variable *var = NULL;
9507
9508 buf[0] = '\0';
9509
9510 if (ast_strlen_zero(data)) {
9511 ast_log(LOG_ERROR, "QUEUE_WAITING_COUNT requires an argument: queuename\n");
9512 return -1;
9513 }
9514
9515 if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Find for QUEUE_WAITING_COUNT()"))) {
9516 ao2_lock(q);
9517 count = q->count;
9518 ao2_unlock(q);
9519 queue_t_unref(q, "Done with reference in QUEUE_WAITING_COUNT()");
9520 } else if ((var = ast_load_realtime("queues", "name", data, SENTINEL))) {
9521 /* if the queue is realtime but was not found in memory, this
9522 * means that the queue had been deleted from memory since it was
9523 * "dead." This means it has a 0 waiting count
9524 */
9525 count = 0;
9527 } else {
9528 ast_log(LOG_WARNING, "queue %s was not found\n", data);
9529 }
9530
9531 snprintf(buf, len, "%d", count);
9532
9533 return 0;
9534}

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

◆ queue_function_var()

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

create interface var with all queue details.

Return values
0on success
-1on error

Definition at line 9129 of file app_queue.c.

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

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

◆ queue_hash_cb()

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

Definition at line 2141 of file app_queue.c.

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

References ast_str_case_hash(), and call_queue::name.

Referenced by load_module().

◆ queue_member_added_to_ami()

static struct ast_manager_event_blob * queue_member_added_to_ami ( struct stasis_message message)
static

Definition at line 2349 of file app_queue.c.

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

References queue_member_to_ami().

◆ queue_member_blob_create()

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

Definition at line 2565 of file app_queue.c.

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

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

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

◆ queue_member_decrement_followers()

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

Definition at line 2175 of file app_queue.c.

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

References member::queuepos.

Referenced by queue_delme_members_decrement_followers(), and queue_member_follower_removal().

◆ queue_member_follower_removal()

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

Definition at line 2212 of file app_queue.c.

2213{
2214 int pos = mem->queuepos;
2215
2216 /* If the position being removed is less than the current place in the queue, reduce the queue position by one so that we don't skip the member
2217 * who would have been next otherwise. */
2218 if (pos < queue->rrpos) {
2219 queue->rrpos--;
2220 }
2221
2223}

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

Referenced by member_remove_from_queue().

◆ queue_member_pause_to_ami()

static struct ast_manager_event_blob * queue_member_pause_to_ami ( struct stasis_message message)
static

Definition at line 2359 of file app_queue.c.

2360{
2361 return queue_member_to_ami("QueueMemberPause", message);
2362}

References queue_member_to_ami().

◆ queue_member_penalty_to_ami()

static struct ast_manager_event_blob * queue_member_penalty_to_ami ( struct stasis_message message)
static

Definition at line 2364 of file app_queue.c.

2365{
2366 return queue_member_to_ami("QueueMemberPenalty", message);
2367}

References queue_member_to_ami().

◆ queue_member_removed_to_ami()

static struct ast_manager_event_blob * queue_member_removed_to_ami ( struct stasis_message message)
static

Definition at line 2354 of file app_queue.c.

2355{
2356 return queue_member_to_ami("QueueMemberRemoved", message);
2357}

References queue_member_to_ami().

◆ queue_member_ringinuse_to_ami()

static struct ast_manager_event_blob * queue_member_ringinuse_to_ami ( struct stasis_message message)
static

Definition at line 2369 of file app_queue.c.

2370{
2371 return queue_member_to_ami("QueueMemberRinginuse", message);
2372}

References queue_member_to_ami().

◆ queue_member_status_to_ami()

static struct ast_manager_event_blob * queue_member_status_to_ami ( struct stasis_message message)
static

Definition at line 2344 of file app_queue.c.

2345{
2346 return queue_member_to_ami("QueueMemberStatus", message);
2347}

References queue_member_to_ami().

◆ queue_member_to_ami()

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

◆ queue_multi_channel_to_ami()

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

Definition at line 2393 of file app_queue.c.

2394{
2397 struct ast_channel_snapshot *agent;
2398 RAII_VAR(struct ast_str *, caller_event_string, NULL, ast_free);
2399 RAII_VAR(struct ast_str *, agent_event_string, NULL, ast_free);
2400 RAII_VAR(struct ast_str *, event_string, NULL, ast_free);
2401
2403 if (caller) {
2404 caller_event_string = ast_manager_build_channel_state_string(caller);
2405 if (!caller_event_string) {
2406 ast_log(LOG_NOTICE, "No caller event string, bailing\n");
2407 return NULL;
2408 }
2409 }
2410
2411 agent = ast_multi_channel_blob_get_channel(obj, "agent");
2412 if (agent) {
2413 agent_event_string = ast_manager_build_channel_state_string_prefix(agent, "Dest");
2414 if (!agent_event_string) {
2415 ast_log(LOG_NOTICE, "No agent event string, bailing\n");
2416 return NULL;
2417 }
2418 }
2419
2421 if (!event_string) {
2422 return NULL;
2423 }
2424
2426 "%s"
2427 "%s"
2428 "%s",
2429 caller_event_string ? ast_str_buffer(caller_event_string) : "",
2430 agent_event_string ? ast_str_buffer(agent_event_string) : "",
2431 ast_str_buffer(event_string));
2432}
struct ast_str * ast_manager_build_channel_state_string_prefix(const struct ast_channel_snapshot *snapshot, const char *prefix)
Generate the AMI message body from a channel snapshot.
struct ast_channel_snapshot_caller * caller

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

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

◆ queue_publish_member_blob()

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

Definition at line 2541 of file app_queue.c.

2542{
2543 RAII_VAR(struct ast_json_payload *, payload, NULL, ao2_cleanup);
2544 RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
2545
2546 if (!blob || !type) {
2547 ast_json_unref(blob);
2548 return;
2549 }
2550
2551 payload = ast_json_payload_create(blob);
2552 ast_json_unref(blob);
2553 if (!payload) {
2554 return;
2555 }
2556
2557 msg = stasis_message_create(type, payload);
2558 if (!msg) {
2559 return;
2560 }
2561
2563}
struct ast_json_payload * ast_json_payload_create(struct ast_json *json)
Create an ao2 object to pass json blobs as data payloads for stasis.
Definition: json.c:756
struct stasis_message * stasis_message_create(struct stasis_message_type *type, void *data)
Create a new message.
void stasis_publish(struct stasis_topic *topic, struct stasis_message *message)
Publish a message to a topic's subscribers.
Definition: stasis.c:1538

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

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

◆ queue_publish_multi_channel_blob()

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

Definition at line 2510 of file app_queue.c.

2512{
2513 RAII_VAR(struct ast_channel_snapshot *, caller_snapshot, NULL, ao2_cleanup);
2514 RAII_VAR(struct ast_channel_snapshot *, agent_snapshot, NULL, ao2_cleanup);
2515
2516 ast_channel_lock(caller);
2517 caller_snapshot = ast_channel_snapshot_create(caller);
2518 ast_channel_unlock(caller);
2519 ast_channel_lock(agent);
2520 agent_snapshot = ast_channel_snapshot_create(agent);
2521 ast_channel_unlock(agent);
2522
2523 if (!caller_snapshot || !agent_snapshot) {
2524 return;
2525 }
2526
2528 agent_snapshot, type, blob);
2529}
static void queue_publish_multi_channel_snapshot_blob(struct stasis_topic *topic, struct ast_channel_snapshot *caller_snapshot, struct ast_channel_snapshot *agent_snapshot, struct stasis_message_type *type, struct ast_json *blob)
Definition: app_queue.c:2475
struct stasis_topic * ast_channel_topic(struct ast_channel *chan)
A topic which publishes the events for a particular channel.
struct ast_channel_snapshot * ast_channel_snapshot_create(struct ast_channel *chan)
Generate a snapshot of the channel state. This is an ao2 object, so ao2_cleanup() to deallocate.

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

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

◆ queue_publish_multi_channel_snapshot_blob()

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

Definition at line 2475 of file app_queue.c.

2479{
2480 RAII_VAR(struct ast_multi_channel_blob *, payload, NULL, ao2_cleanup);
2481 RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
2482
2483 if (!type) {
2484 return;
2485 }
2486
2487 payload = ast_multi_channel_blob_create(blob);
2488 if (!payload) {
2489 return;
2490 }
2491
2492 if (caller_snapshot) {
2493 ast_multi_channel_blob_add_channel(payload, "caller", caller_snapshot);
2494 } else {
2495 ast_debug(1, "Empty caller_snapshot; sending incomplete event\n");
2496 }
2497
2498 if (agent_snapshot) {
2499 ast_multi_channel_blob_add_channel(payload, "agent", agent_snapshot);
2500 }
2501
2502 msg = stasis_message_create(type, payload);
2503 if (!msg) {
2504 return;
2505 }
2506
2507 stasis_publish(topic, msg);
2508}
struct ast_multi_channel_blob * ast_multi_channel_blob_create(struct ast_json *blob)
Create a ast_multi_channel_blob suitable for a stasis_message.
void ast_multi_channel_blob_add_channel(struct ast_multi_channel_blob *obj, const char *role, struct ast_channel_snapshot *snapshot)
Add a ast_channel_snapshot to a ast_multi_channel_blob object.

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

Referenced by queue_publish_multi_channel_blob(), and send_agent_complete().

◆ queue_reset_global_params()

static void queue_reset_global_params ( void  )
static

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

Definition at line 9775 of file app_queue.c.

9776{
9778 autofill_default = 0;
9779 montype_default = 0;
9780 shared_lastcall = 0;
9784}
static int montype_default
queues.conf [general] option
Definition: app_queue.c:1766
static int negative_penalty_invalid
queues.conf [general] option
Definition: app_queue.c:1778
static int shared_lastcall
queues.conf [general] option
Definition: app_queue.c:1769

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

Referenced by reload_queues().

◆ queue_rules_reset_global_params()

static void queue_rules_reset_global_params ( void  )
static

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

Definition at line 9696 of file app_queue.c.

9697{
9698 realtime_rules = 0;
9699}
static int realtime_rules
queuerules.conf [general] option
Definition: app_queue.c:1772

References realtime_rules.

Referenced by reload_queue_rules().

◆ queue_rules_set_global_params()

static void queue_rules_set_global_params ( struct ast_config cfg)
static

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

Definition at line 9702 of file app_queue.c.

9703{
9704 const char *general_val = NULL;
9705 if ((general_val = ast_variable_retrieve(cfg, "general", "realtime_rules"))) {
9706 realtime_rules = ast_true(general_val);
9707 }
9708}

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

Referenced by reload_queue_rules().

◆ queue_set_global_params()

static void queue_set_global_params ( struct ast_config cfg)
static

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

Definition at line 9787 of file app_queue.c.

9788{
9789 const char *general_val = NULL;
9790 if ((general_val = ast_variable_retrieve(cfg, "general", "persistentmembers"))) {
9791 queue_persistent_members = ast_true(general_val);
9792 }
9793 if ((general_val = ast_variable_retrieve(cfg, "general", "autofill"))) {
9794 autofill_default = ast_true(general_val);
9795 }
9796 if ((general_val = ast_variable_retrieve(cfg, "general", "monitor-type"))) {
9797 if (!strcasecmp(general_val, "mixmonitor"))
9798 montype_default = 1;
9799 }
9800 if ((general_val = ast_variable_retrieve(cfg, "general", "shared_lastcall"))) {
9801 shared_lastcall = ast_true(general_val);
9802 }
9803 if ((general_val = ast_variable_retrieve(cfg, "general", "negative_penalty_invalid"))) {
9804 negative_penalty_invalid = ast_true(general_val);
9805 }
9806 if ((general_val = ast_variable_retrieve(cfg, "general", "log_membername_as_agent"))) {
9807 log_membername_as_agent = ast_true(general_val);
9808 }
9809 if ((general_val = ast_variable_retrieve(cfg, "general", "force_longest_waiting_caller"))) {
9811 }
9812 /* Apply log-caller-id-name in the same place as other global settings */
9813 if ((general_val = ast_variable_retrieve(cfg, "general", "log-caller-id-name"))) {
9814 log_caller_id_name = ast_true(general_val);
9815 }
9816}

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

Referenced by reload_queues().

◆ queue_set_param()

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

Configure a queue parameter.

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

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

Definition at line 3502 of file app_queue.c.

3503{
3504 if (!strcasecmp(param, "musicclass") ||
3505 !strcasecmp(param, "music") || !strcasecmp(param, "musiconhold")) {
3506 ast_string_field_set(q, moh, val);
3507 } else if (!strcasecmp(param, "announce")) {
3508 ast_string_field_set(q, announce, val);
3509 } else if (!strcasecmp(param, "context")) {
3511 } else if (!strcasecmp(param, "timeout")) {
3512 q->timeout = atoi(val);
3513 if (q->timeout < 0) {
3515 }
3516 } else if (!strcasecmp(param, "ringinuse")) {
3517 q->ringinuse = ast_true(val);
3518 } else if (!strcasecmp(param, "setinterfacevar")) {
3520 } else if (!strcasecmp(param, "setqueuevar")) {
3521 q->setqueuevar = ast_true(val);
3522 } else if (!strcasecmp(param, "setqueueentryvar")) {
3524 } else if (!strcasecmp(param, "monitor-format")) {
3525 ast_copy_string(q->monfmt, val, sizeof(q->monfmt));
3526 } else if (!strcasecmp(param, "membergosub")) {
3527 ast_string_field_set(q, membergosub, val);
3528 } else if (!strcasecmp(param, "queue-youarenext")) {
3529 ast_string_field_set(q, sound_next, val);
3530 } else if (!strcasecmp(param, "queue-thereare")) {
3531 ast_string_field_set(q, sound_thereare, val);
3532 } else if (!strcasecmp(param, "queue-callswaiting")) {
3533 ast_string_field_set(q, sound_calls, val);
3534 } else if (!strcasecmp(param, "queue-quantity1")) {
3535 ast_string_field_set(q, queue_quantity1, val);
3536 } else if (!strcasecmp(param, "queue-quantity2")) {
3537 ast_string_field_set(q, queue_quantity2, val);
3538 } else if (!strcasecmp(param, "queue-holdtime")) {
3539 ast_string_field_set(q, sound_holdtime, val);
3540 } else if (!strcasecmp(param, "queue-minutes")) {
3541 ast_string_field_set(q, sound_minutes, val);
3542 } else if (!strcasecmp(param, "queue-minute")) {
3543 ast_string_field_set(q, sound_minute, val);
3544 } else if (!strcasecmp(param, "queue-seconds")) {
3545 ast_string_field_set(q, sound_seconds, val);
3546 } else if (!strcasecmp(param, "queue-thankyou")) {
3547 ast_string_field_set(q, sound_thanks, val);
3548 } else if (!strcasecmp(param, "queue-callerannounce")) {
3549 ast_string_field_set(q, sound_callerannounce, val);
3550 } else if (!strcasecmp(param, "queue-reporthold")) {
3551 ast_string_field_set(q, sound_reporthold, val);
3552 } else if (!strcasecmp(param, "announce-frequency")) {
3553 q->announcefrequency = atoi(val);
3554 } else if (!strcasecmp(param, "announce-to-first-user")) {
3556 } else if (!strcasecmp(param, "min-announce-frequency")) {
3557 q->minannouncefrequency = atoi(val);
3558 ast_debug(1, "%s=%s for queue '%s'\n", param, val, q->name);
3559 } else if (!strcasecmp(param, "announce-round-seconds")) {
3560 q->roundingseconds = atoi(val);
3561 /* Rounding to any other values just doesn't make sense... */
3562 if (!(q->roundingseconds == 0 || q->roundingseconds == 5 || q->roundingseconds == 10
3563 || q->roundingseconds == 15 || q->roundingseconds == 20 || q->roundingseconds == 30)) {
3564 if (linenum >= 0) {
3565 ast_log(LOG_WARNING, "'%s' isn't a valid value for %s "
3566 "using 0 instead for queue '%s' at line %d of queues.conf\n",
3567 val, param, q->name, linenum);
3568 } else {
3569 ast_log(LOG_WARNING, "'%s' isn't a valid value for %s "
3570 "using 0 instead for queue '%s'\n", val, param, q->name);
3571 }
3572 q->roundingseconds=0;
3573 }
3574 } else if (!strcasecmp(param, "announce-holdtime")) {
3575 if (!strcasecmp(val, "once")) {
3577 } else if (ast_true(val)) {
3579 } else {
3580 q->announceholdtime = 0;
3581 }
3582 } else if (!strcasecmp(param, "announce-position")) {
3583 if (!strcasecmp(val, "limit")) {
3585 } else if (!strcasecmp(val, "more")) {
3587 } else if (ast_true(val)) {
3589 } else {
3591 }
3592 } else if (!strcasecmp(param, "announce-position-only-up")) {
3594 } else if (!strcasecmp(param, "announce-position-limit")) {
3595 q->announcepositionlimit = atoi(val);
3596 } else if (!strcasecmp(param, "periodic-announce")) {
3597 if (strchr(val, ',')) {
3598 char *s, *buf = ast_strdupa(val);
3599 unsigned int i = 0;
3600
3601 while ((s = strsep(&buf, ",|"))) {
3602 if (!q->sound_periodicannounce[i]) {
3604 }
3605 ast_str_set(&q->sound_periodicannounce[i], 0, "%s", s);
3606 i++;
3607 if (i == MAX_PERIODIC_ANNOUNCEMENTS) {
3608 break;
3609 }
3610 }
3611 q->numperiodicannounce = i;
3612 } else {
3613 ast_str_set(&q->sound_periodicannounce[0], 0, "%s", val);
3614 q->numperiodicannounce = 1;
3615 }
3616 } else if (!strcasecmp(param, "periodic-announce-startdelay")) {
3618 } else if (!strcasecmp(param, "periodic-announce-frequency")) {
3619 q->periodicannouncefrequency = atoi(val);
3620 } else if (!strcasecmp(param, "relative-periodic-announce")) {
3622 } else if (!strcasecmp(param, "random-periodic-announce")) {
3624 } else if (!strcasecmp(param, "retry")) {
3625 q->retry = atoi(val);
3626 if (q->retry <= 0) {
3627 q->retry = DEFAULT_RETRY;
3628 }
3629 } else if (!strcasecmp(param, "wrapuptime")) {
3630 q->wrapuptime = atoi(val);
3631 } else if (!strcasecmp(param, "penaltymemberslimit")) {
3632 if ((sscanf(val, "%10d", &q->penaltymemberslimit) != 1)) {
3633 q->penaltymemberslimit = 0;
3634 }
3635 } else if (!strcasecmp(param, "autofill")) {
3636 q->autofill = ast_true(val);
3637 } else if (!strcasecmp(param, "autopause")) {
3639 } else if (!strcasecmp(param, "autopausedelay")) {
3640 q->autopausedelay = atoi(val);
3641 } else if (!strcasecmp(param, "autopausebusy")) {
3643 } else if (!strcasecmp(param, "autopauseunavail")) {
3645 } else if (!strcasecmp(param, "maxlen")) {
3646 q->maxlen = atoi(val);
3647 if (q->maxlen < 0) {
3648 q->maxlen = 0;
3649 }
3650 } else if (!strcasecmp(param, "servicelevel")) {
3651 q->servicelevel= atoi(val);
3652 } else if (!strcasecmp(param, "strategy")) {
3653 int strategy;
3654
3655 /* We are a static queue and already have set this, no need to do it again */
3656 if (failunknown) {
3657 return;
3658 }
3660 if (strategy < 0) {
3661 ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n",
3662 val, q->name);
3664 }
3665 if (strategy == q->strategy) {
3666 return;
3667 }
3669 ast_log(LOG_WARNING, "Changing to the linear strategy currently requires asterisk to be restarted.\n");
3670 return;
3671 }
3672 q->strategy = strategy;
3673 } else if (!strcasecmp(param, "joinempty")) {
3675 } else if (!strcasecmp(param, "leavewhenempty")) {
3677 } else if (!strcasecmp(param, "reportholdtime")) {
3679 } else if (!strcasecmp(param, "memberdelay")) {
3680 q->memberdelay = atoi(val);
3681 } else if (!strcasecmp(param, "weight")) {
3682 q->weight = atoi(val);
3683 } else if (!strcasecmp(param, "timeoutrestart")) {
3685 } else if (!strcasecmp(param, "defaultrule")) {
3686 ast_string_field_set(q, defaultrule, val);
3687 } else if (!strcasecmp(param, "timeoutpriority")) {
3688 if (!strcasecmp(val, "conf")) {
3690 } else {
3692 }
3693 } else if (!strcasecmp(param, "log-restricted-caller-id")) {
3695 } else if (failunknown) {
3696 if (linenum >= 0) {
3697 ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s at line %d of queues.conf\n",
3698 q->name, param, linenum);
3699 } else {
3700 ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s\n", q->name, param);
3701 }
3702 }
3703}
#define ANNOUNCEPOSITION_MORE_THAN
Definition: app_queue.c:1958
static void parse_empty_options(const char *value, enum empty_conditions *empty, int joinempty)
Definition: app_queue.c:3459
#define ANNOUNCEPOSITION_NO
Definition: app_queue.c:1957
#define ANNOUNCEHOLDTIME_ALWAYS
Definition: app_queue.c:1941
#define ANNOUNCEPOSITION_LIMIT
Definition: app_queue.c:1959
#define ANNOUNCEHOLDTIME_ONCE
Definition: app_queue.c:1942
static int autopause2int(const char *autopause)
Definition: app_queue.c:2118
Definition: ast_expr2.c:325

References call_queue::announce_to_first_user, call_queue::announcefrequency, call_queue::announceholdtime, ANNOUNCEHOLDTIME_ALWAYS, ANNOUNCEHOLDTIME_ONCE, call_queue::announceposition, ANNOUNCEPOSITION_LIMIT, ANNOUNCEPOSITION_MORE_THAN, ANNOUNCEPOSITION_NO, call_queue::announceposition_only_up, ANNOUNCEPOSITION_YES, call_queue::announcepositionlimit, ast_copy_string(), ast_debug, ast_log, ast_str_create, ast_str_set(), ast_strdupa, ast_string_field_set, ast_true(), call_queue::autofill, call_queue::autopause, autopause2int(), call_queue::autopausebusy, call_queue::autopausedelay, call_queue::autopauseunavail, buf, voicemailpwcheck::context, DEFAULT_RETRY, DEFAULT_TIMEOUT, call_queue::joinempty, call_queue::leavewhenempty, call_queue::log_restricted_caller_id, LOG_WARNING, MAX_PERIODIC_ANNOUNCEMENTS, call_queue::maxlen, call_queue::memberdelay, call_queue::minannouncefrequency, call_queue::monfmt, call_queue::name, call_queue::numperiodicannounce, parse_empty_options(), call_queue::penaltymemberslimit, call_queue::periodicannouncefrequency, call_queue::periodicannouncestartdelay, QUEUE_STRATEGY_LINEAR, QUEUE_STRATEGY_RINGALL, call_queue::randomperiodicannounce, call_queue::relativeperiodicannounce, call_queue::reportholdtime, call_queue::retry, call_queue::ringinuse, call_queue::roundingseconds, call_queue::servicelevel, call_queue::setinterfacevar, call_queue::setqueueentryvar, call_queue::setqueuevar, call_queue::sound_periodicannounce, strat2int(), call_queue::strategy, strsep(), call_queue::timeout, TIMEOUT_PRIORITY_APP, TIMEOUT_PRIORITY_CONF, call_queue::timeoutpriority, call_queue::timeoutrestart, call_queue::weight, and call_queue::wrapuptime.

Referenced by find_queue_by_name_rt(), and reload_single_queue().

◆ queue_show()

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

Definition at line 10584 of file app_queue.c.

10585{
10586 switch ( cmd ) {
10587 case CLI_INIT:
10588 e->command = "queue show";
10589 e->usage =
10590 "Usage: queue show\n"
10591 " Provides summary information on a specified queue.\n";
10592 return NULL;
10593 case CLI_GENERATE:
10594 return complete_queue_show(a->line, a->word, a->pos, a->n);
10595 }
10596
10597 return __queues_show(NULL, a->fd, a->argc, a->argv);
10598}
static char * complete_queue_show(const char *line, const char *word, int pos, int state)
Definition: app_queue.c:10576
static char * __queues_show(struct mansession *s, int fd, int argc, const char *const *argv)
Show queue(s) status and statistics.
Definition: app_queue.c:10368

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

◆ queue_stasis_data_alloc()

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

Definition at line 6461 of file app_queue.c.

6464{
6465 struct queue_stasis_data *queue_data;
6466
6467 queue_data = ao2_alloc(sizeof(*queue_data), queue_stasis_data_destructor);
6468 if (!queue_data) {
6469 return NULL;
6470 }
6471
6472 if (ast_string_field_init(queue_data, 64)) {
6473 ao2_cleanup(queue_data);
6474 return NULL;
6475 }
6476
6479 queue_data->queue = queue_ref(qe->parent);
6480 queue_data->starttime = starttime;
6481 queue_data->holdstart = holdstart;
6483 queue_data->caller_pos = qe->opos;
6484 ao2_ref(mem, +1);
6485 queue_data->member = mem;
6486
6487 return queue_data;
6488}
static void queue_stasis_data_destructor(void *obj)
Definition: app_queue.c:6429

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

Referenced by setup_stasis_subs().

◆ queue_stasis_data_destructor()

static void queue_stasis_data_destructor ( void *  obj)
static

Definition at line 6429 of file app_queue.c.

6430{
6431 struct queue_stasis_data *queue_data = obj;
6432
6433 /* This can only happen if refcounts for this object have got severely messed up */
6434 ast_assert(queue_data->bridge_router == NULL);
6435 ast_assert(queue_data->channel_router == NULL);
6436
6437 ao2_cleanup(queue_data->member);
6438 queue_unref(queue_data->queue);
6439 ast_string_field_free_memory(queue_data);
6440}
struct stasis_message_router * channel_router
Definition: app_queue.c:6418
struct stasis_message_router * bridge_router
Definition: app_queue.c:6416

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

Referenced by queue_stasis_data_alloc().

◆ qupd_exec()

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

Update Queue with data of an outgoing call.

Definition at line 11829 of file app_queue.c.

11830{
11831 int oldtalktime;
11832 char *parse;
11833 struct call_queue *q;
11834 struct member *mem;
11835 int newtalktime = 0;
11836
11838 AST_APP_ARG(queuename);
11839 AST_APP_ARG(uniqueid);
11840 AST_APP_ARG(agent);
11842 AST_APP_ARG(talktime);
11843 AST_APP_ARG(params););
11844
11845 if (ast_strlen_zero(data)) {
11846 ast_log(LOG_WARNING, "QueueUpdate requires arguments (queuename,uniqueid,agent,status,talktime,params[totaltime,callednumber])\n");
11847 return -1;
11848 }
11849
11850 parse = ast_strdupa(data);
11851
11853
11854 if (ast_strlen_zero(args.queuename) || ast_strlen_zero(args.uniqueid) || ast_strlen_zero(args.agent) || ast_strlen_zero(args.status)) {
11855 ast_log(LOG_WARNING, "Missing argument to QueueUpdate (queuename,uniqueid,agent,status,talktime,params[totaltime|callednumber])\n");
11856 return -1;
11857 }
11858
11859 if (!ast_strlen_zero(args.talktime)) {
11860 newtalktime = atoi(args.talktime);
11861 }
11862
11863 q = find_load_queue_rt_friendly(args.queuename);
11864 if (!q) {
11865 ast_log(LOG_WARNING, "QueueUpdate could not find requested queue '%s'\n", args.queuename);
11866 return 0;
11867 }
11868
11869 ao2_lock(q);
11870 if (q->members) {
11871 struct ao2_iterator mem_iter = ao2_iterator_init(q->members, 0);
11872 while ((mem = ao2_iterator_next(&mem_iter))) {
11873 if (!strcasecmp(mem->membername, args.agent)) {
11874 if (!strcasecmp(args.status, "ANSWER")) {
11875 oldtalktime = q->talktime;
11876 q->talktime = (((oldtalktime << 2) - oldtalktime) + newtalktime) >> 2;
11877 time(&mem->lastcall);
11878 mem->calls++;
11879 mem->lastqueue = q;
11880 q->callscompleted++;
11881
11882 if (newtalktime <= q->servicelevel) {
11883 q->callscompletedinsl++;
11884 }
11885 } else {
11886
11887 time(&mem->lastcall);
11888 q->callsabandoned++;
11889 }
11890
11891 ast_queue_log(args.queuename, args.uniqueid, args.agent, "OUTCALL", "%s|%s|%s", args.status, args.talktime, args.params);
11892 }
11893
11894 ao2_ref(mem, -1);
11895 }
11896
11897 ao2_iterator_destroy(&mem_iter);
11898 }
11899
11900 ao2_unlock(q);
11901 queue_t_unref(q, "Done with temporary pointer");
11902
11903 return 0;
11904}

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

Referenced by load_module().

◆ recalc_holdtime()

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

Definition at line 4519 of file app_queue.c.

4520{
4521 int oldvalue;
4522
4523 /* Calculate holdtime using an exponential average */
4524 /* Thanks to SRT for this contribution */
4525 /* 2^2 (4) is the filter coefficient; a higher exponent would give old entries more weight */
4526
4527 ao2_lock(qe->parent);
4528 if ((qe->parent->callscompleted + qe->parent->callsabandoned) == 0) {
4529 qe->parent->holdtime = newholdtime;
4530 } else {
4531 oldvalue = qe->parent->holdtime;
4532 qe->parent->holdtime = (((oldvalue << 2) - oldvalue) + newholdtime) >> 2;
4533 }
4534 ao2_unlock(qe->parent);
4535}

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

Referenced by try_calling().

◆ record_abandoned()

static void record_abandoned ( struct queue_ent qe)
static

Record that a caller gave up on waiting in queue.

Definition at line 5249 of file app_queue.c.

5250{
5251 int callabandonedinsl = 0;
5252 time_t now;
5253
5254 RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
5255
5256 pbx_builtin_setvar_helper(qe->chan, "ABANDONED", "TRUE");
5257
5259 ao2_lock(qe->parent);
5260 blob = ast_json_pack("{s: s, s: i, s: i, s: i}",
5261 "Queue", qe->parent->name,
5262 "Position", qe->pos,
5263 "OriginalPosition", qe->opos,
5264 "HoldTime", (int)(time(NULL) - qe->start));
5265
5266
5267 time(&now);
5268 callabandonedinsl = ((now - qe->start) <= qe->parent->servicelevel);
5269 if (callabandonedinsl) {
5271 }
5272
5273 qe->parent->callsabandoned++;
5274 ao2_unlock(qe->parent);
5275
5276 ast_channel_publish_cached_blob(qe->chan, queue_caller_abandon_type(), blob);
5277}

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

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

◆ reload()

static int reload ( void  )
static

Definition at line 12153 of file app_queue.c.

12154{
12155 struct ast_flags mask = {AST_FLAGS_ALL & ~QUEUE_RESET_STATS,};
12156 ast_unload_realtime("queue_members");
12157 reload_handler(1, &mask, NULL);
12158 return 0;
12159}
int ast_unload_realtime(const char *family)
Release any resources cached for a realtime family.
Definition: main/config.c:3796

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

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

◆ reload_handler()

static int reload_handler ( int  reload,
struct ast_flags mask,
const char *  queuename 
)
static

The command center for all reload operations.

Whenever any piece of queue information is to be reloaded, this function is called. It interprets the flags set in the mask parameter and acts based on how they are set.

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

Definition at line 10233 of file app_queue.c.

10234{
10235 int res = 0;
10236
10237 if (ast_test_flag(mask, QUEUE_RELOAD_RULES)) {
10238 res |= reload_queue_rules(reload);
10239 }
10240 if (ast_test_flag(mask, QUEUE_RESET_STATS)) {
10241 res |= clear_stats(queuename);
10242 }
10244 res |= reload_queues(reload, mask, queuename);
10245 }
10246 return res;
10247}
static int reload_queues(int reload, struct ast_flags *mask, const char *queuename)
reload the queues.conf file
Definition: app_queue.c:10146
static int reload_queue_rules(int reload)
Reload the rules defined in queuerules.conf.
Definition: app_queue.c:9716
static int clear_stats(const char *queuename)
Facilitates resetting statistics for a queue.
Definition: app_queue.c:10203
static int reload(void)
Definition: app_queue.c:12153

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

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

◆ reload_queue_members()

static void reload_queue_members ( void  )
static

Reload dynamic queue members persisted into the astdb.

Definition at line 8270 of file app_queue.c.

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

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

Referenced by load_module().

◆ reload_queue_rules()

static int reload_queue_rules ( int  reload)
static

Reload the rules defined in queuerules.conf.

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

Definition at line 9716 of file app_queue.c.

9717{
9718 struct ast_config *cfg;
9719 struct rule_list *rl_iter, *new_rl;
9720 struct penalty_rule *pr_iter;
9721 char *rulecat = NULL;
9722 struct ast_variable *rulevar = NULL;
9723 struct ast_flags config_flags = { (reload && !realtime_rules) ? CONFIG_FLAG_FILEUNCHANGED : 0 };
9724
9725 if (!(cfg = ast_config_load("queuerules.conf", config_flags))) {
9726 ast_log(LOG_NOTICE, "No queuerules.conf file found, queues will not follow penalty rules\n");
9728 } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
9729 ast_log(LOG_NOTICE, "queuerules.conf has not changed since it was last loaded. Not taking any action.\n");
9731 } else if (cfg == CONFIG_STATUS_FILEINVALID) {
9732 ast_log(LOG_ERROR, "Config file queuerules.conf is in an invalid format. Aborting.\n");
9734 }
9735
9737 while ((rl_iter = AST_LIST_REMOVE_HEAD(&rule_lists, list))) {
9738 while ((pr_iter = AST_LIST_REMOVE_HEAD(&rl_iter->rules, list)))
9739 ast_free(pr_iter);
9740 ast_free(rl_iter);
9741 }
9743 while ((rulecat = ast_category_browse(cfg, rulecat))) {
9744 if (!strcasecmp(rulecat, "general")) {
9746 continue;
9747 }
9748 if (!(new_rl = ast_calloc(1, sizeof(*new_rl)))) {
9750 ast_config_destroy(cfg);
9752 } else {
9753 ast_copy_string(new_rl->name, rulecat, sizeof(new_rl->name));
9754 AST_LIST_INSERT_TAIL(&rule_lists, new_rl, list);
9755 for (rulevar = ast_variable_browse(cfg, rulecat); rulevar; rulevar = rulevar->next)
9756 if(!strcasecmp(rulevar->name, "penaltychange"))
9757 insert_penaltychange(new_rl->name, rulevar->value, rulevar->lineno);
9758 else
9759 ast_log(LOG_WARNING, "Don't know how to handle rule type '%s' on line %d\n", rulevar->name, rulevar->lineno);
9760 }
9761 }
9762
9763 ast_config_destroy(cfg);
9764
9768 }
9769
9772}
static int load_realtime_rules(void)
Load queue rules from realtime.
Definition: app_queue.c:3357
static void queue_rules_reset_global_params(void)
Definition: app_queue.c:9696
static int insert_penaltychange(const char *list_name, const char *content, const int linenum)
Change queue penalty by adding rule.
Definition: app_queue.c:3253
static void queue_rules_set_global_params(struct ast_config *cfg)
Definition: app_queue.c:9702
#define ast_config_load(filename, flags)
Load a config file.
@ CONFIG_FLAG_FILEUNCHANGED
#define CONFIG_STATUS_FILEUNCHANGED
#define CONFIG_STATUS_FILEINVALID
struct ast_variable * ast_variable_browse(const struct ast_config *config, const char *category_name)
Definition: extconf.c:1215

References ast_calloc, ast_category_browse(), ast_config_destroy(), ast_config_load, ast_copy_string(), ast_free, AST_LIST_INSERT_TAIL, AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, ast_log, AST_MODULE_LOAD_DECLINE, AST_MODULE_LOAD_SUCCESS, ast_variable_browse(), CONFIG_FLAG_FILEUNCHANGED, CONFIG_STATUS_FILEINVALID, CONFIG_STATUS_FILEUNCHANGED, insert_penaltychange(), ast_variable::lineno, load_realtime_rules(), LOG_ERROR, LOG_NOTICE, LOG_WARNING, rule_list::name, ast_variable::name, ast_variable::next, NULL, queue_rules_reset_global_params(), queue_rules_set_global_params(), realtime_rules, reload(), rule_list::rules, and ast_variable::value.

Referenced by reload_handler().

◆ reload_queues()

static int reload_queues ( int  reload,
struct ast_flags mask,
const char *  queuename 
)
static

reload the queues.conf file

This function reloads the information in the general section of the queues.conf file and potentially more, depending on the value of mask.

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

Definition at line 10146 of file app_queue.c.

10147{
10148 struct ast_config *cfg;
10149 char *cat;
10150 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
10151 const int queue_reload = ast_test_flag(mask, QUEUE_RELOAD_PARAMETERS);
10152
10153 if (!(cfg = ast_config_load("queues.conf", config_flags))) {
10154 ast_log(LOG_NOTICE, "No call queueing config file (queues.conf), so no call queues\n");
10155 return -1;
10156 } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
10157 return 0;
10158 } else if (cfg == CONFIG_STATUS_FILEINVALID) {
10159 ast_log(LOG_ERROR, "Config file queues.conf is in an invalid format. Aborting.\n");
10160 return -1;
10161 }
10162
10163 /* We've made it here, so it looks like we're doing operations on all queues. */
10165
10166 /* Mark non-realtime queues not found at the beginning. */
10167 ao2_callback(queues, OBJ_NODATA, mark_unfound, (char *) queuename);
10168
10169 /* Chug through config file. */
10170 cat = NULL;
10172 while ((cat = ast_category_browse(cfg, cat)) ) {
10173 if (!strcasecmp(cat, "general") && queue_reload) {
10175 continue;
10176 }
10177 if (ast_strlen_zero(queuename) || !strcasecmp(cat, queuename))
10178 reload_single_queue(cfg, mask, cat);
10179 }
10180
10181 ast_config_destroy(cfg);
10182 if (queue_reload) {
10183 /* Unlink and mark dead all non-realtime queues that were not found in the configuration file. */
10185 }
10187 return 0;
10188}
static void queue_reset_global_params(void)
Definition: app_queue.c:9775
static void reload_single_queue(struct ast_config *cfg, struct ast_flags *mask, const char *queuename)
Reload information pertaining to a particular queue.
Definition: app_queue.c:9989
static void queue_set_global_params(struct ast_config *cfg)
Definition: app_queue.c:9787
static int mark_unfound(void *obj, void *arg, int flags)
Definition: app_queue.c:10112
static int kill_if_unfound(void *obj, void *arg, int flags)
Definition: app_queue.c:10122

References ao2_callback, ao2_lock, ao2_unlock, ast_category_browse(), ast_config_destroy(), ast_config_load, ast_log, ast_strlen_zero(), ast_test_flag, CONFIG_FLAG_FILEUNCHANGED, CONFIG_STATUS_FILEINVALID, CONFIG_STATUS_FILEUNCHANGED, kill_if_unfound(), LOG_ERROR, LOG_NOTICE, mark_unfound(), NULL, OBJ_MULTIPLE, OBJ_NODATA, OBJ_NOLOCK, OBJ_UNLINK, QUEUE_RELOAD_PARAMETERS, queue_reset_global_params(), queue_set_global_params(), queues, reload(), and reload_single_queue().

Referenced by reload_handler().

◆ reload_single_member()

static void reload_single_member ( const char *  memberdata,
struct call_queue q 
)
static

reload information pertaining to a single member

This function is called when a member = line is encountered in queues.conf.

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

Definition at line 9826 of file app_queue.c.

9827{
9828 char *membername, *interface, *state_interface, *tmp;
9829 char *parse;
9830 struct member *cur, *newm;
9831 struct member tmpmem;
9832 int penalty;
9833 int ringinuse;
9834 int wrapuptime;
9835 int paused;
9844 );
9845
9846 if (ast_strlen_zero(memberdata)) {
9847 ast_log(LOG_WARNING, "Empty queue member definition. Moving on!\n");
9848 return;
9849 }
9850
9851 /* Add a new member */
9852 parse = ast_strdupa(memberdata);
9853
9855
9856 interface = args.interface;
9857 if (!ast_strlen_zero(args.penalty)) {
9858 tmp = args.penalty;
9859 ast_strip(tmp);
9860 penalty = atoi(tmp);
9861 if (penalty < 0) {
9862 penalty = 0;
9863 }
9864 } else {
9865 penalty = 0;
9866 }
9867
9868 if (!ast_strlen_zero(args.membername)) {
9869 membername = args.membername;
9870 ast_strip(membername);
9871 } else {
9872 membername = interface;
9873 }
9874
9875 if (!ast_strlen_zero(args.state_interface)) {
9876 state_interface = args.state_interface;
9877 ast_strip(state_interface);
9878 } else {
9879 state_interface = interface;
9880 }
9881
9882 if (!ast_strlen_zero(args.ringinuse)) {
9883 tmp = args.ringinuse;
9884 ast_strip(tmp);
9885 if (ast_true(tmp)) {
9886 ringinuse = 1;
9887 } else if (ast_false(tmp)) {
9888 ringinuse = 0;
9889 } else {
9890 ast_log(LOG_ERROR, "Member %s has an invalid ringinuse value. Using %s ringinuse value.\n",
9891 membername, q->name);
9892 ringinuse = q->ringinuse;
9893 }
9894 } else {
9895 ringinuse = q->ringinuse;
9896 }
9897
9898 if (!ast_strlen_zero(args.wrapuptime)) {
9899 tmp = args.wrapuptime;
9900 ast_strip(tmp);
9901 wrapuptime = atoi(tmp);
9902 if (wrapuptime < 0) {
9903 wrapuptime = 0;
9904 }
9905 } else {
9906 wrapuptime = 0;
9907 }
9908
9909 if (!ast_strlen_zero(args.paused)) {
9910 tmp = args.paused;
9911 ast_strip(tmp);
9912 if (ast_true(tmp)) {
9913 paused = 1;
9914 } else if (ast_false(tmp)) {
9915 paused = 0;
9916 } else {
9917 ast_log(LOG_ERROR, "Member %s has an invalid paused value.\n", membername);
9918 paused = 0;
9919 }
9920 } else {
9921 paused = 0;
9922 }
9923
9924 /* Find the old position in the list */
9925 ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface));
9926 cur = ao2_find(q->members, &tmpmem, OBJ_POINTER);
9927
9928 if (cur) {
9929 paused = cur->paused;
9930 }
9931
9932 if ((newm = create_queue_member(interface, membername, penalty, paused, state_interface, ringinuse, wrapuptime))) {
9933 newm->wrapuptime = wrapuptime;
9934 if (cur) {
9935 ao2_lock(q->members);
9936 /* Round Robin Queue Position must be copied if this is replacing an existing member */
9937 newm->queuepos = cur->queuepos;
9938 /* Don't reset agent stats either */
9939 newm->calls = cur->calls;
9940 newm->lastcall = cur->lastcall;
9941
9942 ao2_link(q->members, newm);
9943 ao2_unlink(q->members, cur);
9944 ao2_unlock(q->members);
9945 } else {
9946 /* Otherwise we need to add using the function that will apply a round robin queue position manually. */
9947 member_add_to_queue(q, newm);
9948 }
9949 ao2_ref(newm, -1);
9950 }
9951 newm = NULL;
9952
9953 if (cur) {
9954 ao2_ref(cur, -1);
9955 }
9956}

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

Referenced by reload_single_queue().

◆ reload_single_queue()

static void reload_single_queue ( struct ast_config cfg,
struct ast_flags mask,
const char *  queuename 
)
static

Reload information pertaining to a particular queue.

Once we have isolated a queue within reload_queues, we call this. This will either reload information for the queue or if we're just reloading member information, we'll just reload that without touching other settings within the queue

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

Definition at line 9989 of file app_queue.c.

9990{
9991 int new;
9992 struct call_queue *q = NULL;
9993 struct member *member;
9994 /*We're defining a queue*/
9995 struct call_queue tmpq = {
9996 .name = queuename,
9997 };
9998 const char *tmpvar;
9999 const int queue_reload = ast_test_flag(mask, QUEUE_RELOAD_PARAMETERS);
10000 const int member_reload = ast_test_flag(mask, QUEUE_RELOAD_MEMBER);
10001 int prev_weight = 0;
10002 struct ast_variable *var;
10003 struct ao2_iterator mem_iter;
10004
10005 if (!(q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Find queue for reload"))) {
10006 if (queue_reload) {
10007 /* Make one then */
10008 if (!(q = alloc_queue(queuename))) {
10009 return;
10010 }
10011 } else {
10012 /* Since we're not reloading queues, this means that we found a queue
10013 * in the configuration file which we don't know about yet. Just return.
10014 */
10015 return;
10016 }
10017 new = 1;
10018 } else {
10019 new = 0;
10020 }
10021
10022 if (!new) {
10023 ao2_lock(q);
10024 prev_weight = q->weight ? 1 : 0;
10025 }
10026 /* Check if we already found a queue with this name in the config file */
10027 if (q->found) {
10028 ast_log(LOG_WARNING, "Queue '%s' already defined! Skipping!\n", queuename);
10029 if (!new) {
10030 /* It should be impossible to *not* hit this case*/
10031 ao2_unlock(q);
10032 }
10033 queue_t_unref(q, "We exist! Expiring temporary pointer");
10034 return;
10035 }
10036 /* Due to the fact that the "linear" strategy will have a different allocation
10037 * scheme for queue members, we must devise the queue's strategy before other initializations.
10038 * To be specific, the linear strategy needs to function like a linked list, meaning the ao2
10039 * container used will have only a single bucket instead of the typical number.
10040 */
10041 if (queue_reload) {
10042 if ((tmpvar = ast_variable_retrieve(cfg, queuename, "strategy"))) {
10043 q->strategy = strat2int(tmpvar);
10044 if (q->strategy < 0) {
10045 ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n",
10046 tmpvar, q->name);
10048 }
10049 } else {
10051 }
10052 init_queue(q);
10053 }
10054 if (member_reload) {
10056 q->found = 1;
10057 }
10058
10059 /* On the first pass we just read the parameters of the queue */
10060 for (var = ast_variable_browse(cfg, queuename); var; var = var->next) {
10061 if (queue_reload && strcasecmp(var->name, "member")) {
10062 queue_set_param(q, var->name, var->value, var->lineno, 1);
10063 }
10064 }
10065
10066 /* On the second pass, we read members */
10067 for (var = ast_variable_browse(cfg, queuename); var; var = var->next) {
10068 if (member_reload && !strcasecmp(var->name, "member")) {
10069 reload_single_member(var->value, q);
10070 }
10071 }
10072
10073 /* Update ringinuse for dynamic members */
10074 if (member_reload) {
10075 ao2_lock(q->members);
10077 while ((member = ao2_iterator_next(&mem_iter))) {
10078 if (member->dynamic) {
10080 }
10081 ao2_ref(member, -1);
10082 }
10083 ao2_iterator_destroy(&mem_iter);
10084 ao2_unlock(q->members);
10085 }
10086
10087 /* At this point, we've determined if the queue has a weight, so update use_weight
10088 * as appropriate
10089 */
10090 if (!q->weight && prev_weight) {
10092 } else if (q->weight && !prev_weight) {
10094 }
10095
10096 /* Free remaining members marked as delme */
10097 if (member_reload) {
10098 ao2_lock(q->members);
10101 ao2_unlock(q->members);
10102 }
10103
10104 if (new) {
10105 queues_t_link(queues, q, "Add queue to container");
10106 } else {
10107 ao2_unlock(q);
10108 }
10109 queue_t_unref(q, "Expiring creation reference");
10110}
static int mark_member_dead(void *obj, void *arg, int flags)
Definition: app_queue.c:9958
static void reload_single_member(const char *memberdata, struct call_queue *q)
reload information pertaining to a single member
Definition: app_queue.c:9826
static int kill_dead_members(void *obj, void *arg, int flags)
Definition: app_queue.c:9967
static int queue_delme_members_decrement_followers(void *obj, void *arg, int flag)
Definition: app_queue.c:2194

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

Referenced by reload_queues().

◆ remove_from_queue()

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

Remove member from queue.

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

Definition at line 7710 of file app_queue.c.

7711{
7712 struct call_queue *q, tmpq = {
7713 .name = queuename,
7714 };
7715 struct member *mem, tmpmem;
7716 int res = RES_NOSUCHQUEUE;
7717
7718 ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface));
7719 if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Temporary reference for interface removal"))) {
7720 ao2_lock(q);
7721 if ((mem = ao2_find(q->members, &tmpmem, OBJ_POINTER))) {
7722 /* XXX future changes should beware of this assumption!! */
7723 /*Change Penalty on realtime users*/
7725 update_realtime_member_field(mem, q->name, "penalty", "-1");
7726 } else if (!mem->dynamic) {
7727 ao2_ref(mem, -1);
7728 ao2_unlock(q);
7729 queue_t_unref(q, "Interface wasn't dynamic, expiring temporary reference");
7730 return RES_NOT_DYNAMIC;
7731 }
7732 queue_publish_member_blob(queue_member_removed_type(), queue_member_blob_create(q, mem));
7733
7735 ao2_ref(mem, -1);
7736
7739 }
7740
7741 if (!num_available_members(q)) {
7743 }
7744
7745 res = RES_OKAY;
7746 } else {
7747 res = RES_EXISTS;
7748 }
7749 ao2_unlock(q);
7750 queue_t_unref(q, "Expiring temporary reference");
7751 }
7752
7753 return res;
7754}
static int update_realtime_member_field(struct member *mem, const char *queue_name, const char *field, const char *value)
Definition: app_queue.c:4154
char rt_uniqueid[80]
Definition: app_queue.c:1920

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

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

◆ remove_stasis_subscriptions()

static void remove_stasis_subscriptions ( struct queue_stasis_data queue_data)
static

Definition at line 6446 of file app_queue.c.

6447{
6448 SCOPED_AO2LOCK(lock, queue_data);
6449
6450 queue_data->dying = 1;
6452 queue_data->bridge_router = NULL;
6454 queue_data->channel_router = NULL;
6455}
void stasis_message_router_unsubscribe(struct stasis_message_router *router)
Unsubscribe the router from the upstream topic.

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

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

◆ request_withdraw_caller_from_queue()

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

Request to withdraw a caller from a queue.

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

Definition at line 7892 of file app_queue.c.

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

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

Referenced by manager_request_withdraw_caller_from_queue().

◆ ring_entry()

static int ring_entry ( struct queue_ent qe,
struct callattempt tmp,
int *  busies 
)
static

Part 2 of ring_one.

Does error checking before attempting to request a channel and call a member. This function is only called from ring_one(). Failure can occur if:

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

Definition at line 4923 of file app_queue.c.

4924{
4925 int res;
4926 int status;
4927 char tech[256];
4928 char *location;
4929 struct ast_format_cap *nativeformats;
4930 RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
4931
4932 /* on entry here, we know that tmp->chan == NULL */
4933 if (!can_ring_entry(qe, tmp)) {
4934 tmp->stillgoing = 0;
4935 ++*busies;
4936 return 0;
4937 }
4938
4939 ast_copy_string(tech, tmp->interface, sizeof(tech));
4940 if ((location = strchr(tech, '/'))) {
4941 *location++ = '\0';
4942 } else {
4943 location = "";
4944 }
4945
4947 nativeformats = ao2_bump(ast_channel_nativeformats(qe->chan));
4949
4950 /* Request the peer */
4951 tmp->chan = ast_request(tech, nativeformats, NULL, qe->chan, location, &status);
4952 ao2_cleanup(nativeformats);
4953 if (!tmp->chan) { /* If we can't, just go on to the next call */
4954 ao2_lock(qe->parent);
4955 qe->parent->rrpos++;
4956 qe->linpos++;
4957 ao2_unlock(qe->parent);
4958
4960
4961 publish_dial_end_event(qe->chan, tmp, NULL, "BUSY");
4962 tmp->stillgoing = 0;
4963 ++*busies;
4964 return 0;
4965 }
4966
4967 ast_channel_lock_both(tmp->chan, qe->chan);
4968
4971 if (qe->cancel_answered_elsewhere) {
4973 }
4974 ast_channel_appl_set(tmp->chan, "AppQueue");
4975 ast_channel_data_set(tmp->chan, "(Outgoing Line)");
4976 memset(ast_channel_whentohangup(tmp->chan), 0, sizeof(*ast_channel_whentohangup(tmp->chan)));
4977
4978 /* If the new channel has no callerid, try to guess what it should be */
4979 if (!ast_channel_caller(tmp->chan)->id.number.valid) {
4981 struct ast_party_caller caller;
4982
4984 caller.id = ast_channel_connected(qe->chan)->id;
4985 caller.ani = ast_channel_connected(qe->chan)->ani;
4986 ast_channel_set_caller_event(tmp->chan, &caller, NULL);
4987 } else if (!ast_strlen_zero(ast_channel_dialed(qe->chan)->number.str)) {
4989 } else if (!ast_strlen_zero(ast_channel_exten(qe->chan))) {
4991 }
4992 tmp->dial_callerid_absent = 1;
4993 }
4994
4996
4998
5000
5001 /* Inherit specially named variables from parent channel */
5005
5006 /* Presense of ADSI CPE on outgoing channel follows ours */
5008
5009 /* Inherit context and extension */
5010 ast_channel_dialcontext_set(tmp->chan, ast_channel_context(qe->chan));
5012
5013 /* Save the original channel name to detect call pickup masquerading in. */
5015
5018
5019 /* location is tmp->interface where tech/ has been stripped, so it follow the same syntax as DIALEDPEERNUMBER in app_dial.c */
5020 pbx_builtin_setvar_helper(tmp->chan, "DIALEDPEERNUMBER", strlen(location) ? location : tmp->interface);
5021
5022 /* PREDIAL: Run gosub on the callee's channel */
5023 if (qe->predial_callee) {
5024 ast_pre_call(tmp->chan, qe->predial_callee);
5025 }
5026
5027 /* Place the call, but don't wait on the answer */
5028 if ((res = ast_call(tmp->chan, location, 0))) {
5029 /* Again, keep going even if there's an error */
5030 ast_verb(3, "Couldn't call %s\n", tmp->interface);
5031 do_hang(tmp);
5032 ++*busies;
5033 return 0;
5034 }
5035
5036 ast_channel_lock_both(tmp->chan, qe->chan);
5037
5038 blob = ast_json_pack("{s: s, s: s, s: s}",
5039 "Queue", qe->parent->name,
5040 "Interface", tmp->interface,
5041 "MemberName", tmp->member->membername);
5042 queue_publish_multi_channel_blob(qe->chan, tmp->chan, queue_agent_called_type(), blob);
5043
5045
5048
5049 ast_verb(3, "Called %s\n", tmp->interface);
5050
5051 return 1;
5052}
static void do_hang(struct callattempt *o)
common hangup actions
Definition: app_queue.c:4797
static int can_ring_entry(struct queue_ent *qe, struct callattempt *call)
Definition: app_queue.c:4827
static void queue_publish_multi_channel_blob(struct ast_channel *caller, struct ast_channel *agent, struct stasis_message_type *type, struct ast_json *blob)
Definition: app_queue.c:2510
static void publish_dial_end_event(struct ast_channel *in, struct callattempt *outgoing, struct ast_channel *exception, const char *status)
Definition: app_queue.c:4627
#define ao2_bump(obj)
Bump refcount on an AO2 object by one, returning the object.
Definition: astobj2.h:480
void ast_channel_exten_set(struct ast_channel *chan, const char *value)
void ast_channel_appl_set(struct ast_channel *chan, const char *value)
int ast_call(struct ast_channel *chan, const char *addr, int timeout)
Make a call.
Definition: channel.c:6478
@ AST_CHANNEL_REQUESTOR_BRIDGE_PEER
Definition: channel.h:1523
void ast_channel_set_caller_event(struct ast_channel *chan, const struct ast_party_caller *caller, const struct ast_set_party_caller *update)
Set the caller id information in the Asterisk channel and generate an AMI event if the caller id name...
Definition: channel.c:7393
struct ast_format_cap * ast_channel_nativeformats(const struct ast_channel *chan)
void ast_channel_data_set(struct ast_channel *chan, const char *value)
struct ast_party_redirecting * ast_channel_redirecting(struct ast_channel *chan)
#define ast_channel_lock_both(chan1, chan2)
Lock two channels.
Definition: channel.h:2977
int ast_channel_datastore_inherit(struct ast_channel *from, struct ast_channel *to)
Inherit datastores from a parent to a child.
Definition: channel.c:2397
const char * ast_channel_context(const struct ast_channel *chan)
ast_channel_adsicpe
Definition: channel.h:888
void ast_party_caller_set_init(struct ast_party_caller *init, const struct ast_party_caller *guide)
Initialize the given caller structure using the given guide for a set update operation.
Definition: channel.c:2026
void ast_set_callerid(struct ast_channel *chan, const char *cid_num, const char *cid_name, const char *cid_ani)
Set caller ID number, name and ANI and generate AMI event.
Definition: channel.c:7355
void ast_channel_inherit_variables(const struct ast_channel *parent, struct ast_channel *child)
Inherits channel variable from parent to child channel.
Definition: channel.c:6793
struct ast_party_dialed * ast_channel_dialed(struct ast_channel *chan)
struct timeval * ast_channel_whentohangup(struct ast_channel *chan)
void ast_connected_line_copy_from_caller(struct ast_party_connected_line *dest, const struct ast_party_caller *src)
Copy the caller information to the connected line information.
Definition: channel.c:8319
void ast_channel_req_accountcodes_precious(struct ast_channel *chan, const struct ast_channel *requestor, enum ast_channel_requestor_relationship relationship)
Setup new channel accountcodes from the requestor channel after ast_request().
Definition: channel.c:6456
int ast_pre_call(struct ast_channel *chan, const char *sub_args)
Execute a Gosub call on the channel before a call is placed.
Definition: channel.c:6461
void ast_channel_adsicpe_set(struct ast_channel *chan, enum ast_channel_adsicpe value)
struct ast_channel * ast_request(const char *type, struct ast_format_cap *request_cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *addr, int *cause)
Requests a channel.
Definition: channel.c:6371
const char * ast_channel_exten(const struct ast_channel *chan)
void ast_party_redirecting_copy(struct ast_party_redirecting *dest, const struct ast_party_redirecting *src)
Copy the source redirecting information to the destination redirecting.
Definition: channel.c:2162
int ast_max_forwards_decrement(struct ast_channel *chan)
Decrement the max forwards count for a particular channel.
Definition: max_forwards.c:135
Format capabilities structure, holds formats + preference order + etc.
Definition: format_cap.c:54
Caller Party information.
Definition: channel.h:420
struct ast_party_id ani
Automatic Number Identification (ANI)
Definition: channel.h:467
struct ast_party_dialed::@210 number
Dialed/Called number.
char * str
Subscriber phone number (Malloced)
Definition: channel.h:388
int transit_network_select
Transit Network Select.
Definition: channel.h:399
unsigned int dial_callerid_absent
Definition: app_queue.c:1853
char interface[256]
Definition: app_queue.c:1843
int cancel_answered_elsewhere
Definition: app_queue.c:1887

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

Referenced by ring_one().

◆ ring_one()

static int ring_one ( struct queue_ent qe,
struct callattempt outgoing,
int *  busies 
)
static

Place a call to a queue member.

Once metrics have been calculated for each member, this function is used to place a call to the appropriate member (or members). The low-level channel-handling and error detection is handled in ring_entry

Return values
1if a member was called successfully
0otherwise

Definition at line 5080 of file app_queue.c.

5081{
5082 int ret = 0;
5083 struct callattempt *cur;
5084
5085 if (qe->predial_callee) {
5087 for (cur = outgoing; cur; cur = cur->q_next) {
5088 if (cur->stillgoing && cur->chan) {
5090 }
5091 }
5092 }
5093
5094 while (ret == 0) {
5095 struct callattempt *best = find_best(outgoing);
5096 if (!best) {
5097 ast_debug(1, "Nobody left to try ringing in queue\n");
5098 break;
5099 }
5101 /* Ring everyone who shares this best metric (for ringall) */
5102 for (cur = outgoing; cur; cur = cur->q_next) {
5103 if (cur->stillgoing && !cur->chan && cur->metric <= best->metric) {
5104 ast_debug(1, "(Parallel) Trying '%s' with metric %d\n", cur->interface, cur->metric);
5105 ret |= ring_entry(qe, cur, busies);
5106 if (qe->predial_callee && cur->chan) {
5108 }
5109 }
5110 }
5111 } else {
5112 /* Ring just the best channel */
5113 ast_debug(1, "Trying '%s' with metric %d\n", best->interface, best->metric);
5114 ret = ring_entry(qe, best, busies);
5115 if (qe->predial_callee && best->chan) {
5117 }
5118 }
5119
5120 /* If we have timed out, break out */
5121 if (qe->expire && (time(NULL) >= qe->expire)) {
5122 ast_debug(1, "Queue timed out while ringing members.\n");
5123 ret = 0;
5124 break;
5125 }
5126 }
5127 if (qe->predial_callee) {
5128 for (cur = outgoing; cur; cur = cur->q_next) {
5129 if (cur->stillgoing && cur->chan) {
5131 }
5132 }
5134 }
5135
5136 return ret;
5137}
static int ring_entry(struct queue_ent *qe, struct callattempt *tmp, int *busies)
Part 2 of ring_one.
Definition: app_queue.c:4923
static struct callattempt * find_best(struct callattempt *outgoing)
find the entry with the best metric, or NULL
Definition: app_queue.c:5055
int ast_autoservice_stop(struct ast_channel *chan)
Stop servicing a channel for us...
Definition: autoservice.c:266
int ast_autoservice_start(struct ast_channel *chan)
Automatically service a channel for us...
Definition: autoservice.c:200

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

Referenced by try_calling(), and wait_for_answer().

◆ rna()

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

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

Definition at line 5280 of file app_queue.c.

5281{
5282 RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
5283
5284 ast_verb(3, "Nobody picked up in %d ms\n", rnatime);
5285
5286 /* Stop ringing, and resume MOH if specified */
5287 if (qe->ring_when_ringing) {
5288 ast_indicate(qe->chan, -1);
5289 ast_moh_start(qe->chan, qe->moh, NULL);
5290 }
5291
5292 blob = ast_json_pack("{s: s, s: s, s: s, s: i}",
5293 "Queue", qe->parent->name,
5294 "Interface", interface,
5295 "MemberName", membername,
5296 "RingTime", rnatime);
5297 queue_publish_multi_channel_blob(qe->chan, peer, queue_agent_ringnoanswer_type(), blob);
5298
5299 ast_queue_log(qe->parent->name, ast_channel_uniqueid(qe->chan), membername, "RINGNOANSWER", "%d", rnatime);
5301 if (qe->parent->autopausedelay > 0) {
5302 struct member *mem;
5303 ao2_lock(qe->parent);
5304 if ((mem = interface_exists(qe->parent, interface))) {
5305 time_t idletime = time(&idletime)-mem->lastcall;
5306 if ((mem->lastcall != 0) && (qe->parent->autopausedelay > idletime)) {
5307 ao2_unlock(qe->parent);
5308 ao2_ref(mem, -1);
5309 return;
5310 }
5311 ao2_ref(mem, -1);
5312 }
5313 ao2_unlock(qe->parent);
5314 }
5315 if (qe->parent->autopause == QUEUE_AUTOPAUSE_ON) {
5316 if (!set_member_paused(qe->parent->name, interface, "Auto-Pause", 1)) {
5317 ast_verb(3, "Auto-Pausing Queue Member %s in queue %s since they failed to answer.\n",
5318 interface, qe->parent->name);
5319 } else {
5320 ast_verb(3, "Failed to pause Queue Member %s in queue %s!\n", interface, qe->parent->name);
5321 }
5322 } else {
5323 /* If queue autopause is mode all, just don't send any queue to stop.
5324 * the function will stop in all queues */
5325 if (!set_member_paused("", interface, "Auto-Pause", 1)) {
5326 ast_verb(3, "Auto-Pausing Queue Member %s in all queues since they failed to answer on queue %s.\n",
5327 interface, qe->parent->name);
5328 } else {
5329 ast_verb(3, "Failed to pause Queue Member %s in all queues!\n", interface);
5330 }
5331 }
5332 }
5333 return;
5334}

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

Referenced by wait_for_answer().

◆ rqm_exec()

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

RemoveQueueMember application.

Definition at line 8453 of file app_queue.c.

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

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

Referenced by load_module().

◆ rt_handle_member_record()

static void rt_handle_member_record ( struct call_queue q,
char *  category,
struct ast_config member_config 
)
static

Find rt member record to update otherwise create one.

Search for member in queue, if found update penalty/paused state, if no member exists create one flag it as a RT member and add to queue member list.

Definition at line 3748 of file app_queue.c.

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

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

Referenced by find_queue_by_name_rt(), and update_realtime_members().

◆ say_periodic_announcement()

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

Playback announcement to queued members if period has elapsed.

Definition at line 5188 of file app_queue.c.

5189{
5190 int res = 0;
5191 time_t now;
5192
5193 /* Get the current time */
5194 time(&now);
5195
5196 /* Check to see if it is time to announce */
5198 return 0;
5199 }
5200
5201 /* Stop the music on hold so we can play our own file */
5202 if (ringing) {
5203 ast_indicate(qe->chan,-1);
5204 } else {
5205 ast_moh_stop(qe->chan);
5206 }
5207
5208 ast_verb(3, "Playing periodic announcement\n");
5209
5211 qe->last_periodic_announce_sound = ((unsigned long) ast_random()) % qe->parent->numperiodicannounce;
5215 }
5216
5217 /* play the announcement */
5219
5220 if (res > 0 && !valid_exit(qe, res)) {
5221 res = 0;
5222 }
5223
5224 /* Resume Music on Hold if the caller is going to stay in the queue */
5225 if (!res) {
5226 if (ringing) {
5228 } else {
5229 ast_moh_start(qe->chan, qe->moh, NULL);
5230 }
5231 }
5232
5233 /* update last_periodic_announce_time */
5235 time(&qe->last_periodic_announce_time);
5236 } else {
5238 }
5239
5240 /* Update the current periodic announcement to the next announcement */
5241 if (!qe->parent->randomperiodicannounce) {
5243 }
5244
5245 return res;
5246}
static int play_file(struct ast_channel *chan, const char *filename)
Definition: app_queue.c:4313
static int valid_exit(struct queue_ent *qe, char digit)
Check for valid exit from queue via goto.
Definition: app_queue.c:4342

References AST_CONTROL_RINGING, ast_indicate(), ast_moh_start(), ast_moh_stop(), ast_random(), ast_str_buffer(), ast_str_strlen(), ast_verb, queue_ent::chan, queue_ent::last_periodic_announce_sound, queue_ent::last_periodic_announce_time, queue_ent::moh, NULL, call_queue::numperiodicannounce, queue_ent::parent, call_queue::periodicannouncefrequency, play_file(), call_queue::randomperiodicannounce, call_queue::relativeperiodicannounce, ringing(), call_queue::sound_periodicannounce, and valid_exit().

Referenced by queue_exec(), and wait_our_turn().

◆ say_position()

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

Definition at line 4377 of file app_queue.c.

4378{
4379 int res = 0, say_thanks = 0;
4380 long avgholdmins, avgholdsecs;
4381 time_t now;
4382
4383 /* Let minannouncefrequency seconds pass between the start of each position announcement */
4384 time(&now);
4385 if ((now - qe->last_pos) < qe->parent->minannouncefrequency) {
4386 return 0;
4387 }
4388
4389 /* If either our position has changed, or we are over the freq timer, say position */
4390 if ((qe->last_pos_said == qe->pos) && ((now - qe->last_pos) < qe->parent->announcefrequency)) {
4391 return 0;
4392 }
4393
4394 /* Only announce if the caller's queue position has improved since last time */
4395 if (qe->parent->announceposition_only_up && qe->last_pos_said <= qe->pos) {
4396 return 0;
4397 }
4398
4399 if (ringing) {
4400 ast_indicate(qe->chan,-1);
4401 } else {
4402 ast_moh_stop(qe->chan);
4403 }
4404
4408 qe->pos <= qe->parent->announcepositionlimit)) {
4409 say_thanks = 1;
4410 /* Say we're next, if we are */
4411 if (qe->pos == 1) {
4412 res = play_file(qe->chan, qe->parent->sound_next);
4413 if (!res) {
4414 goto posout;
4415 }
4416 /* Say there are more than N callers */
4418 res = (
4419 play_file(qe->chan, qe->parent->queue_quantity1) ||
4421 ast_channel_language(qe->chan), NULL) || /* Needs gender */
4423 /* Say there are currently N callers waiting */
4424 } else {
4425 res = (
4426 play_file(qe->chan, qe->parent->sound_thereare) ||
4428 ast_channel_language(qe->chan), "n") || /* Needs gender */
4429 play_file(qe->chan, qe->parent->sound_calls));
4430 }
4431 if (res) {
4432 goto playout;
4433 }
4434 }
4435 /* Round hold time to nearest minute */
4436 avgholdmins = labs(((qe->parent->holdtime + 30) - (now - qe->start)) / 60);
4437
4438 /* If they have specified a rounding then round the seconds as well */
4439 if (qe->parent->roundingseconds) {
4440 avgholdsecs = (labs(((qe->parent->holdtime + 30) - (now - qe->start))) - 60 * avgholdmins) / qe->parent->roundingseconds;
4441 avgholdsecs *= qe->parent->roundingseconds;
4442 } else {
4443 avgholdsecs = 0;
4444 }
4445
4446 ast_verb(3, "Hold time for %s is %ld minute(s) %ld seconds\n", qe->parent->name, avgholdmins, avgholdsecs);
4447
4448 /* If the hold time is >1 min, if it's enabled, and if it's not
4449 supposed to be only once and we have already said it, say it */
4450 if ((avgholdmins+avgholdsecs) > 0 && qe->parent->announceholdtime &&
4453 say_thanks = 1;
4454 res = play_file(qe->chan, qe->parent->sound_holdtime);
4455 if (res) {
4456 goto playout;
4457 }
4458
4459 if (avgholdmins >= 1) {
4460 res = ast_say_number(qe->chan, avgholdmins, AST_DIGIT_ANY, ast_channel_language(qe->chan), "n");
4461 if (res) {
4462 goto playout;
4463 }
4464
4465 if (avgholdmins == 1) {
4466 res = play_file(qe->chan, qe->parent->sound_minute);
4467 if (res) {
4468 goto playout;
4469 }
4470 } else {
4471 res = play_file(qe->chan, qe->parent->sound_minutes);
4472 if (res) {
4473 goto playout;
4474 }
4475 }
4476 }
4477 if (avgholdsecs >= 1) {
4478 res = ast_say_number(qe->chan, avgholdsecs, AST_DIGIT_ANY, ast_channel_language(qe->chan), "n");
4479 if (res) {
4480 goto playout;
4481 }
4482
4483 res = play_file(qe->chan, qe->parent->sound_seconds);
4484 if (res) {
4485 goto playout;
4486 }
4487 }
4488 }
4489
4490posout:
4491 if (qe->parent->announceposition) {
4492 ast_verb(3, "Told %s in %s their queue position (which was %d)\n",
4493 ast_channel_name(qe->chan), qe->parent->name, qe->pos);
4494 }
4495 if (say_thanks) {
4496 res = play_file(qe->chan, qe->parent->sound_thanks);
4497 }
4498playout:
4499
4500 if ((res > 0 && !valid_exit(qe, res))) {
4501 res = 0;
4502 }
4503
4504 /* Set our last_pos indicators */
4505 qe->last_pos = now;
4506 qe->last_pos_said = qe->pos;
4507
4508 /* Don't restart music on hold if we're about to exit the caller from the queue */
4509 if (!res) {
4510 if (ringing) {
4512 } else {
4513 ast_moh_start(qe->chan, qe->moh, NULL);
4514 }
4515 }
4516 return res;
4517}
int ast_say_number(struct ast_channel *chan, int num, const char *ints, const char *lang, const char *options)
says a number
Definition: channel.c:8261
const ast_string_field sound_thereare
Definition: app_queue.c:1999
const ast_string_field sound_holdtime
Definition: app_queue.c:1999
const ast_string_field sound_seconds
Definition: app_queue.c:1999
const ast_string_field sound_thanks
Definition: app_queue.c:1999
const ast_string_field queue_quantity2
Definition: app_queue.c:1999
const ast_string_field sound_calls
Definition: app_queue.c:1999
const ast_string_field sound_minute
Definition: app_queue.c:1999
const ast_string_field sound_minutes
Definition: app_queue.c:1999
const ast_string_field queue_quantity1
Definition: app_queue.c:1999
const ast_string_field sound_next
Definition: app_queue.c:1999

References call_queue::announcefrequency, call_queue::announceholdtime, ANNOUNCEHOLDTIME_ONCE, call_queue::announceposition, ANNOUNCEPOSITION_LIMIT, ANNOUNCEPOSITION_MORE_THAN, call_queue::announceposition_only_up, ANNOUNCEPOSITION_YES, call_queue::announcepositionlimit, ast_channel_language(), ast_channel_name(), AST_CONTROL_RINGING, AST_DIGIT_ANY, ast_indicate(), ast_moh_start(), ast_moh_stop(), ast_say_number(), ast_verb, queue_ent::chan, call_queue::holdtime, queue_ent::last_pos, queue_ent::last_pos_said, call_queue::minannouncefrequency, queue_ent::moh, call_queue::name, NULL, queue_ent::parent, play_file(), queue_ent::pos, call_queue::queue_quantity1, call_queue::queue_quantity2, ringing(), call_queue::roundingseconds, call_queue::sound_calls, call_queue::sound_holdtime, call_queue::sound_minute, call_queue::sound_minutes, call_queue::sound_next, call_queue::sound_seconds, call_queue::sound_thanks, call_queue::sound_thereare, queue_ent::start, and valid_exit().

Referenced by queue_exec(), and wait_our_turn().

◆ send_agent_complete()

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

Send out AMI message with member call completion status information.

Definition at line 6299 of file app_queue.c.

6302{
6303 const char *reason = NULL; /* silence dumb compilers */
6304 RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
6305
6306 switch (rsn) {
6307 case CALLER:
6308 reason = "caller";
6309 break;
6310 case AGENT:
6311 reason = "agent";
6312 break;
6313 case TRANSFER:
6314 reason = "transfer";
6315 break;
6316 }
6317
6318 blob = ast_json_pack("{s: s, s: s, s: s, s: I, s: I, s: s}",
6319 "Queue", queuename,
6320 "Interface", member->interface,
6321 "MemberName", member->membername,
6322 "HoldTime", (ast_json_int_t)(callstart - holdstart),
6323 "TalkTime", (ast_json_int_t)(time(NULL) - callstart),
6324 "Reason", reason ?: "");
6325
6327 queue_agent_complete_type(), blob);
6328}
struct stasis_topic * ast_queue_topic(const char *queuename)
Get the Stasis Message Bus API topic for queue messages for a particular queue name.
Definition: main/app.c:3349
AST_JSON_INT_T ast_json_int_t
Primarily used to cast when packing to an "I" type.
Definition: json.h:87

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

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

◆ set_member_paused()

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

Definition at line 8022 of file app_queue.c.

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

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

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

◆ set_member_penalty_help_members()

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

Definition at line 8082 of file app_queue.c.

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

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

Referenced by set_member_value_help_members().

◆ set_member_ringinuse_help_members()

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

Definition at line 8131 of file app_queue.c.

8132{
8133 struct member *mem;
8134 int foundinterface = 0;
8135
8136 ao2_lock(q);
8137 if ((mem = interface_exists(q, interface))) {
8138 foundinterface++;
8140 ao2_ref(mem, -1);
8141 }
8142 ao2_unlock(q);
8143
8144 return foundinterface;
8145}
static void set_queue_member_ringinuse(struct call_queue *q, struct member *mem, int ringinuse)
Definition: app_queue.c:8118

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

Referenced by set_member_value_help_members().

◆ set_member_value()

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

Definition at line 8170 of file app_queue.c.

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

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

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

◆ set_member_value_help_members()

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

Definition at line 8147 of file app_queue.c.

8148{
8149 switch(property) {
8150 case MEMBER_PENALTY:
8151 return set_member_penalty_help_members(q, interface, value);
8152
8153 case MEMBER_RINGINUSE:
8154 return set_member_ringinuse_help_members(q, interface, value);
8155
8156 default:
8157 ast_log(LOG_ERROR, "Attempted to set invalid property\n");
8158 return 0;
8159 }
8160}
static int set_member_ringinuse_help_members(struct call_queue *q, const char *interface, int ringinuse)
Definition: app_queue.c:8131
static int set_member_penalty_help_members(struct call_queue *q, const char *interface, int penalty)
Definition: app_queue.c:8082

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

Referenced by set_member_value().

◆ set_queue_member_pause()

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

Definition at line 7955 of file app_queue.c.

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

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

Referenced by set_member_paused().

◆ set_queue_member_ringinuse()

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

Definition at line 8118 of file app_queue.c.

8119{
8120 if (mem->realtime) {
8122 ringinuse ? "1" : "0");
8123 }
8124
8125 mem->ringinuse = ringinuse;
8126
8127 ast_queue_log(q->name, "NONE", mem->interface, "RINGINUSE", "%d", ringinuse);
8128 queue_publish_member_blob(queue_member_ringinuse_type(), queue_member_blob_create(q, mem));
8129}

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

Referenced by set_member_ringinuse_help_members().

◆ set_queue_result()

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

sets the QUEUESTATUS channel variable

Definition at line 2080 of file app_queue.c.

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

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

Referenced by queue_exec().

◆ set_queue_variables()

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

Set variables of queue.

Definition at line 2233 of file app_queue.c.

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

References ao2_lock, ao2_unlock, call_queue::callsabandoned, call_queue::callscompleted, call_queue::callscompletedinsl, call_queue::count, call_queue::holdtime, int2strat(), call_queue::maxlen, call_queue::name, pbx_builtin_setvar_multiple(), call_queue::servicelevel, call_queue::setqueuevar, call_queue::strategy, and call_queue::talktime.

Referenced by end_bridge_callback(), queue_exec(), record_abandoned(), and try_calling().

◆ setup_mixmonitor()

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

Definition at line 7075 of file app_queue.c.

7076{
7077 char escaped_filename[256];
7078 char file_with_ext[sizeof(escaped_filename) + sizeof(qe->parent->monfmt)];
7079 char mixmonargs[1512];
7080 char escaped_monitor_exec[1024];
7081 const char *monitor_options;
7082 const char *monitor_exec;
7083
7084 escaped_monitor_exec[0] = '\0';
7085
7086 if (filename) {
7087 escape_and_substitute(qe->chan, filename, escaped_filename, sizeof(escaped_filename));
7088 } else {
7089 ast_copy_string(escaped_filename, ast_channel_uniqueid(qe->chan), sizeof(escaped_filename));
7090 }
7091
7093 if ((monitor_exec = pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC"))) {
7094 monitor_exec = ast_strdupa(monitor_exec);
7095 }
7096 if ((monitor_options = pbx_builtin_getvar_helper(qe->chan, "MONITOR_OPTIONS"))) {
7097 monitor_options = ast_strdupa(monitor_options);
7098 } else {
7099 monitor_options = "";
7100 }
7102
7103 if (monitor_exec) {
7104 escape_and_substitute(qe->chan, monitor_exec, escaped_monitor_exec, sizeof(escaped_monitor_exec));
7105 }
7106
7107 snprintf(file_with_ext, sizeof(file_with_ext), "%s.%s", escaped_filename, qe->parent->monfmt);
7108
7109 if (!ast_strlen_zero(escaped_monitor_exec)) {
7110 snprintf(mixmonargs, sizeof(mixmonargs), "b%s,%s", monitor_options, escaped_monitor_exec);
7111 } else {
7112 snprintf(mixmonargs, sizeof(mixmonargs), "b%s", monitor_options);
7113 }
7114
7115 ast_debug(1, "Arguments being passed to MixMonitor: %s,%s\n", file_with_ext, mixmonargs);
7116
7117 if (ast_start_mixmonitor(qe->chan, file_with_ext, mixmonargs)) {
7118 ast_log(LOG_WARNING, "Unable to start mixmonitor. Is the MixMonitor app loaded?\n");
7119 }
7120}
static void escape_and_substitute(struct ast_channel *chan, const char *input, char *output, size_t size)
Definition: app_queue.c:7044
int ast_start_mixmonitor(struct ast_channel *chan, const char *filename, const char *options)
Start a mixmonitor on a channel with the given parameters.
Definition: mixmonitor.c:74

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

Referenced by try_calling().

◆ setup_peer_after_bridge_goto()

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

Definition at line 7027 of file app_queue.c.

7028{
7029 const char *context;
7030 const char *extension;
7031 int priority;
7032
7033 if (ast_test_flag(opts, OPT_CALLEE_GO_ON)) {
7034 ast_channel_lock(chan);
7038 ast_channel_unlock(chan);
7040 opt_args[OPT_ARG_CALLEE_GO_ON]);
7041 }
7042}
void ast_bridge_set_after_go_on(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *parseable_goto)
Set channel to go on in the dialplan after the bridge.
Definition: bridge_after.c:622
int ast_channel_priority(const struct ast_channel *chan)
structure to hold extensions

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

Referenced by try_calling().

◆ setup_stasis_subs()

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

Definition at line 6943 of file app_queue.c.

6945{
6946 struct queue_stasis_data *queue_data = queue_stasis_data_alloc(qe, peer, mem, holdstart, starttime, callcompletedinsl);
6947
6948 if (!queue_data) {
6949 return -1;
6950 }
6951
6953 if (!queue_data->bridge_router) {
6954 ao2_ref(queue_data, -1);
6955 return -1;
6956 }
6957
6959 handle_bridge_enter, queue_data);
6961 handle_blind_transfer, queue_data);
6963 handle_attended_transfer, queue_data);
6965 queue_bridge_cb, queue_data);
6966
6968 if (!queue_data->channel_router) {
6969 /* Unsubscribing from the bridge router will remove the only ref of queue_data,
6970 * thus beginning the destruction process
6971 */
6973 queue_data->bridge_router = NULL;
6974 return -1;
6975 }
6976
6977 ao2_ref(queue_data, +1);
6981 handle_local_optimization_end, queue_data);
6983 handle_hangup, queue_data);
6985 handle_masquerade, queue_data);
6987 queue_channel_cb, queue_data);
6988
6989 return 0;
6990}
static void handle_bridge_enter(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Definition: app_queue.c:6546
static void queue_bridge_cb(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Definition: app_queue.c:6693
static void handle_attended_transfer(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Handle an attended transfer event.
Definition: app_queue.c:6638
static void handle_masquerade(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Definition: app_queue.c:6884
static void handle_local_optimization_begin(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Definition: app_queue.c:6712
static void handle_local_optimization_end(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Definition: app_queue.c:6763
static struct queue_stasis_data * queue_stasis_data_alloc(struct queue_ent *qe, struct ast_channel *peer, struct member *mem, time_t holdstart, time_t starttime, int callcompletedinsl)
Definition: app_queue.c:6461
static void queue_channel_cb(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Definition: app_queue.c:6918
static void handle_hangup(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Definition: app_queue.c:6827
static void handle_blind_transfer(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Handle a blind transfer event.
Definition: app_queue.c:6579
struct stasis_message_type * ast_local_optimization_end_type(void)
Message type for when a local channel optimization completes.
struct stasis_message_type * ast_local_optimization_begin_type(void)
Message type for when a local channel optimization begins.
struct stasis_message_type * ast_channel_masquerade_type(void)
Message type for when a channel is being masqueraded.
struct stasis_message_type * ast_channel_hangup_request_type(void)
Message type for when a hangup is requested on a channel.
struct stasis_message_type * ast_channel_entered_bridge_type(void)
Message type for ast_channel enter bridge blob messages.
struct stasis_message_type * ast_blind_transfer_type(void)
Message type for ast_blind_transfer_message.
struct stasis_message_type * ast_attended_transfer_type(void)
Message type for ast_attended_transfer_message.
struct stasis_topic * ast_bridge_topic_all(void)
A topic which publishes the events for all bridges.
#define stasis_message_router_create_pool(topic)
Create a new message router object.
int stasis_message_router_set_default(struct stasis_message_router *router, stasis_subscription_cb callback, void *data)
Sets the default route of a router.

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

Referenced by try_calling().

◆ STASIS_MESSAGE_TYPE_DEFN_LOCAL() [1/14]

STASIS_MESSAGE_TYPE_DEFN_LOCAL ( queue_agent_called_type  ,
to_ami = queue_agent_called_to_ami 
)

◆ STASIS_MESSAGE_TYPE_DEFN_LOCAL() [2/14]

STASIS_MESSAGE_TYPE_DEFN_LOCAL ( queue_agent_complete_type  ,
to_ami = queue_agent_complete_to_ami 
)

◆ STASIS_MESSAGE_TYPE_DEFN_LOCAL() [3/14]

STASIS_MESSAGE_TYPE_DEFN_LOCAL ( queue_agent_connect_type  ,
to_ami = queue_agent_connect_to_ami 
)

◆ STASIS_MESSAGE_TYPE_DEFN_LOCAL() [4/14]

STASIS_MESSAGE_TYPE_DEFN_LOCAL ( queue_agent_dump_type  ,
to_ami = queue_agent_dump_to_ami 
)

◆ STASIS_MESSAGE_TYPE_DEFN_LOCAL() [5/14]

STASIS_MESSAGE_TYPE_DEFN_LOCAL ( queue_agent_ringnoanswer_type  ,
to_ami = queue_agent_ringnoanswer_to_ami 
)

◆ STASIS_MESSAGE_TYPE_DEFN_LOCAL() [6/14]

STASIS_MESSAGE_TYPE_DEFN_LOCAL ( queue_caller_abandon_type  ,
to_ami = queue_caller_abandon_to_ami 
)

◆ STASIS_MESSAGE_TYPE_DEFN_LOCAL() [7/14]

STASIS_MESSAGE_TYPE_DEFN_LOCAL ( queue_caller_join_type  ,
to_ami = queue_caller_join_to_ami 
)

◆ STASIS_MESSAGE_TYPE_DEFN_LOCAL() [8/14]

STASIS_MESSAGE_TYPE_DEFN_LOCAL ( queue_caller_leave_type  ,
to_ami = queue_caller_leave_to_ami 
)

◆ STASIS_MESSAGE_TYPE_DEFN_LOCAL() [9/14]

STASIS_MESSAGE_TYPE_DEFN_LOCAL ( queue_member_added_type  ,
to_ami = queue_member_added_to_ami 
)

◆ STASIS_MESSAGE_TYPE_DEFN_LOCAL() [10/14]

STASIS_MESSAGE_TYPE_DEFN_LOCAL ( queue_member_pause_type  ,
to_ami = queue_member_pause_to_ami 
)

◆ STASIS_MESSAGE_TYPE_DEFN_LOCAL() [11/14]

STASIS_MESSAGE_TYPE_DEFN_LOCAL ( queue_member_penalty_type  ,
to_ami = queue_member_penalty_to_ami 
)

◆ STASIS_MESSAGE_TYPE_DEFN_LOCAL() [12/14]

STASIS_MESSAGE_TYPE_DEFN_LOCAL ( queue_member_removed_type  ,
to_ami = queue_member_removed_to_ami 
)

◆ STASIS_MESSAGE_TYPE_DEFN_LOCAL() [13/14]

STASIS_MESSAGE_TYPE_DEFN_LOCAL ( queue_member_ringinuse_type  ,
to_ami = queue_member_ringinuse_to_ami 
)

◆ STASIS_MESSAGE_TYPE_DEFN_LOCAL() [14/14]

STASIS_MESSAGE_TYPE_DEFN_LOCAL ( queue_member_status_type  ,
to_ami = queue_member_status_to_ami 
)

◆ store_next_lin()

static int store_next_lin ( struct queue_ent qe,
struct callattempt outgoing 
)
static

Search for best metric and add to Linear queue.

Definition at line 5164 of file app_queue.c.

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

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

Referenced by try_calling().

◆ store_next_rr()

static int store_next_rr ( struct queue_ent qe,
struct callattempt outgoing 
)
static

Search for best metric and add to Round Robbin queue.

Definition at line 5140 of file app_queue.c.

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

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

Referenced by try_calling().

◆ strat2int()

static int strat2int ( const char *  strategy)
static

Definition at line 2105 of file app_queue.c.

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

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

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

◆ try_calling()

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

Definition at line 7148 of file app_queue.c.

7149{
7150 struct member *cur;
7151 struct callattempt *outgoing = NULL; /* the list of calls we are building */
7152 int to, orig;
7153 char oldexten[AST_MAX_EXTENSION]="";
7154 char oldcontext[AST_MAX_CONTEXT]="";
7155 char queuename[256]="";
7156 struct ast_channel *peer;
7157 struct callattempt *lpeer;
7158 struct member *member;
7159 struct ast_app *application;
7160 int res = 0, bridge = 0;
7161 int numbusies = 0;
7162 int x=0;
7163 char *announce = NULL;
7164 char digit = 0;
7165 time_t now = time(NULL);
7166 struct ast_bridge_config bridge_config;
7167 char nondataquality = 1;
7168 char *agiexec = NULL;
7169 char *gosubexec = NULL;
7170 const char *monitorfilename;
7171 int forwardsallowed = 1;
7172 int block_connected_line = 0;
7173 struct ao2_iterator memi;
7175 int callcompletedinsl;
7176 time_t starttime;
7177
7178 memset(&bridge_config, 0, sizeof(bridge_config));
7179 time(&now);
7180
7181 /* If we've already exceeded our timeout, then just stop
7182 * This should be extremely rare. queue_exec will take care
7183 * of removing the caller and reporting the timeout as the reason.
7184 */
7185 if (qe->expire && now >= qe->expire) {
7186 res = 0;
7187 goto out;
7188 }
7189
7190 if (ast_test_flag(&opts, OPT_CALLEE_TRANSFER)) {
7191 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_REDIRECT);
7192 }
7193 if (ast_test_flag(&opts, OPT_CALLER_TRANSFER)) {
7194 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_REDIRECT);
7195 }
7196 if (ast_test_flag(&opts, OPT_CALLEE_AUTOMON)) {
7197 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_AUTOMON);
7198 }
7199 if (ast_test_flag(&opts, OPT_CALLER_AUTOMON)) {
7200 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_AUTOMON);
7201 }
7202 if (ast_test_flag(&opts, OPT_DATA_QUALITY)) {
7203 nondataquality = 0;
7204 }
7205 if (ast_test_flag(&opts, OPT_CALLEE_HANGUP)) {
7206 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_DISCONNECT);
7207 }
7208 if (ast_test_flag(&opts, OPT_CALLER_HANGUP)) {
7209 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT);
7210 }
7211 if (ast_test_flag(&opts, OPT_CALLEE_PARK)) {
7212 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_PARKCALL);
7213 }
7214 if (ast_test_flag(&opts, OPT_CALLER_PARK)) {
7215 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_PARKCALL);
7216 }
7217 if (ast_test_flag(&opts, OPT_NO_RETRY)) {
7220 (*tries)++;
7221 } else {
7222 *tries = ao2_container_count(qe->parent->members);
7223 }
7224 *noption = 1;
7225 }
7226 if (ast_test_flag(&opts, OPT_IGNORE_CALL_FW)) {
7227 forwardsallowed = 0;
7228 }
7230 block_connected_line = 1;
7231 }
7233 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_AUTOMIXMON);
7234 }
7236 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_AUTOMIXMON);
7237 }
7238 if (ast_test_flag(&opts, OPT_MARK_AS_ANSWERED)) {
7240 }
7241
7242 /* if the calling channel has AST_CAUSE_ANSWERED_ELSEWHERE set, make sure this is inherited.
7243 (this is mainly to support unreal/local channels)
7244 */
7247 }
7248
7249 ao2_lock(qe->parent);
7250 ast_debug(1, "%s is trying to call a queue member.\n",
7251 ast_channel_name(qe->chan));
7252 ast_copy_string(queuename, qe->parent->name, sizeof(queuename));
7253 if (!ast_strlen_zero(qe->announce)) {
7254 announce = qe->announce;
7255 }
7256 if (!ast_strlen_zero(announceoverride)) {
7257 announce = announceoverride;
7258 }
7259
7260 memi = ao2_iterator_init(qe->parent->members, 0);
7261 while ((cur = ao2_iterator_next(&memi))) {
7262 struct callattempt *tmp = ast_calloc(1, sizeof(*tmp));
7263 if (!tmp) {
7264 ao2_ref(cur, -1);
7265 ao2_iterator_destroy(&memi);
7266 ao2_unlock(qe->parent);
7267 goto out;
7268 }
7269
7270 /*
7271 * Seed the callattempt's connected line information with previously
7272 * acquired connected line info from the queued channel. The
7273 * previously acquired connected line info could have been set
7274 * through the CONNECTED_LINE dialplan function.
7275 */
7279
7280 tmp->block_connected_update = block_connected_line;
7281 tmp->stillgoing = 1;
7282 tmp->member = cur; /* Place the reference for cur into callattempt. */
7283 ast_copy_string(tmp->interface, cur->interface, sizeof(tmp->interface));
7284 /* Calculate the metric for the appropriate strategy. */
7285 if (!calc_metric(qe->parent, cur, x++, qe, tmp)) {
7286 /* Put them in the list of outgoing thingies... We're ready now.
7287 XXX If we're forcibly removed, these outgoing calls won't get
7288 hung up XXX */
7289 tmp->q_next = outgoing;
7290 outgoing = tmp;
7291 } else {
7292 callattempt_free(tmp);
7293 }
7294 }
7295 ao2_iterator_destroy(&memi);
7296
7298 /* Application arguments have higher timeout priority (behaviour for <=1.6) */
7299 if (qe->expire && (!qe->parent->timeout || (qe->expire - now) <= qe->parent->timeout)) {
7300 to = (qe->expire - now) * 1000;
7301 } else {
7302 to = (qe->parent->timeout) ? qe->parent->timeout * 1000 : -1;
7303 }
7304 } else {
7305 /* Config timeout is higher priority thatn application timeout */
7306 if (qe->expire && qe->expire<=now) {
7307 to = 0;
7308 } else if (qe->parent->timeout) {
7309 to = qe->parent->timeout * 1000;
7310 } else {
7311 to = -1;
7312 }
7313 }
7314 orig = to;
7315 ++qe->pending;
7316 ao2_unlock(qe->parent);
7317 /* Call the queue members with the best metric now. */
7318 ring_one(qe, outgoing, &numbusies);
7319 lpeer = wait_for_answer(qe, outgoing, &to, &digit, numbusies,
7320 ast_test_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT),
7321 forwardsallowed);
7322
7323 ao2_lock(qe->parent);
7326
7327 }
7330 }
7331 ao2_unlock(qe->parent);
7332 peer = lpeer ? lpeer->chan : NULL;
7333 if (!peer) {
7334 qe->pending = 0;
7335 if (to) {
7336 /* Must gotten hung up */
7337 res = -1;
7338 } else {
7339 /* User exited by pressing a digit */
7340 res = digit;
7341 }
7342 if (res == -1) {
7343 ast_debug(1, "%s: Nobody answered.\n", ast_channel_name(qe->chan));
7344 }
7345 } else { /* peer is valid */
7346 RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
7347 RAII_VAR(struct ast_str *, interfacevar, ast_str_create(325), ast_free);
7348 /* Ah ha! Someone answered within the desired timeframe. Of course after this
7349 we will always return with -1 so that it is hung up properly after the
7350 conversation. */
7351 if (!strcmp(ast_channel_tech(qe->chan)->type, "DAHDI")) {
7352 ast_channel_setoption(qe->chan, AST_OPTION_TONE_VERIFY, &nondataquality, sizeof(nondataquality), 0);
7353 }
7354 if (!strcmp(ast_channel_tech(peer)->type, "DAHDI")) {
7355 ast_channel_setoption(peer, AST_OPTION_TONE_VERIFY, &nondataquality, sizeof(nondataquality), 0);
7356 }
7357 /* Update parameters for the queue */
7358 time(&now);
7359 recalc_holdtime(qe, (now - qe->start));
7360 member = lpeer->member;
7361 ao2_lock(qe->parent);
7362 callcompletedinsl = member->callcompletedinsl = ((now - qe->start) <= qe->parent->servicelevel);
7363 ao2_unlock(qe->parent);
7364 /* Increment the refcount for this member, since we're going to be using it for awhile in here. */
7365 ao2_ref(member, 1);
7367 outgoing = NULL;
7368 if (announce || qe->parent->reportholdtime || qe->parent->memberdelay) {
7369 int res2;
7370
7371 res2 = ast_autoservice_start(qe->chan);
7372 if (!res2) {
7373 if (qe->parent->memberdelay) {
7374 ast_log(LOG_NOTICE, "Delaying member connect for %d seconds\n", qe->parent->memberdelay);
7375 res2 = ast_safe_sleep(peer, qe->parent->memberdelay * 1000);
7376 }
7377 if (!res2 && announce) {
7378 char *front;
7379 char *announcefiles = ast_strdupa(announce);
7380 while ((front = ast_strsep(&announcefiles, '&', AST_STRSEP_STRIP | AST_STRSEP_TRIM))) {
7381 if (play_file(peer, front) < 0) {
7382 ast_log(LOG_ERROR, "play_file failed for '%s' on %s\n", front, ast_channel_name(peer));
7383 }
7384 }
7385 }
7386 if (!res2 && qe->parent->reportholdtime) {
7387 if (!play_file(peer, qe->parent->sound_reporthold)) {
7388 long holdtime, holdtimesecs;
7389
7390 time(&now);
7391 holdtime = labs((now - qe->start) / 60);
7392 holdtimesecs = labs((now - qe->start) % 60);
7393 if (holdtime > 0) {
7394 ast_say_number(peer, holdtime, AST_DIGIT_ANY, ast_channel_language(peer), "n");
7395 if (play_file(peer, qe->parent->sound_minutes) < 0) {
7396 ast_log(LOG_ERROR, "play_file failed for '%s' on %s\n", qe->parent->sound_minutes, ast_channel_name(peer));
7397 }
7398 }
7399 if (holdtimesecs > 1) {
7400 ast_say_number(peer, holdtimesecs, AST_DIGIT_ANY, ast_channel_language(peer), "n");
7401 if (play_file(peer, qe->parent->sound_seconds) < 0) {
7402 ast_log(LOG_ERROR, "play_file failed for '%s' on %s\n", qe->parent->sound_seconds, ast_channel_name(peer));
7403 }
7404 }
7405 }
7406 }
7408 }
7409 if (ast_check_hangup(peer)) {
7410 /* Agent must have hung up */
7411 ast_log(LOG_WARNING, "Agent on %s hungup on the customer.\n", ast_channel_name(peer));
7412 ast_queue_log(queuename, ast_channel_uniqueid(qe->chan), member->membername, "AGENTDUMP", "%s", "");
7413
7414 blob = ast_json_pack("{s: s, s: s, s: s}",
7415 "Queue", queuename,
7416 "Interface", member->interface,
7417 "MemberName", member->membername);
7418 queue_publish_multi_channel_blob(qe->chan, peer, queue_agent_dump_type(), blob);
7419
7423 ao2_ref(member, -1);
7424 goto out;
7425 } else if (ast_check_hangup(qe->chan)) {
7426 /* Caller must have hung up just before being connected */
7427 ast_log(LOG_NOTICE, "Caller was about to talk to agent on %s but the caller hungup.\n", ast_channel_name(peer));
7428 ast_queue_log(queuename, ast_channel_uniqueid(qe->chan), member->membername, "ABANDON", "%d|%d|%ld", qe->pos, qe->opos, (long) (time(NULL) - qe->start));
7429 record_abandoned(qe);
7430 qe->handled = -1;
7434 ao2_ref(member, -1);
7435 return -1;
7436 }
7437 }
7438 /* Stop music on hold */
7439 if (ringing) {
7440 ast_indicate(qe->chan,-1);
7441 } else {
7442 ast_moh_stop(qe->chan);
7443 }
7444
7445 /* Make sure channels are compatible */
7446 res = ast_channel_make_compatible(qe->chan, peer);
7447 if (res < 0) {
7448 ast_queue_log(queuename, ast_channel_uniqueid(qe->chan), member->membername, "SYSCOMPAT", "%s", "");
7449 ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", ast_channel_name(qe->chan), ast_channel_name(peer));
7450 record_abandoned(qe);
7454 ao2_ref(member, -1);
7455 return -1;
7456 }
7457
7458 /* Play announcement to the caller telling it's his turn if defined */
7460 if (play_file(qe->chan, qe->parent->sound_callerannounce)) {
7461 ast_log(LOG_WARNING, "Announcement file '%s' is unavailable, continuing anyway...\n", qe->parent->sound_callerannounce);
7462 }
7463 }
7464
7465 ao2_lock(qe->parent);
7466 /* if setinterfacevar is defined, make member variables available to the channel */
7467 /* use pbx_builtin_setvar to set a load of variables with one call */
7468 if (qe->parent->setinterfacevar && interfacevar) {
7469 ast_str_set(&interfacevar, 0, "MEMBERINTERFACE=%s,MEMBERNAME=%s,MEMBERCALLS=%d,MEMBERLASTCALL=%ld,MEMBERPENALTY=%d,MEMBERDYNAMIC=%d,MEMBERREALTIME=%d",
7472 pbx_builtin_setvar_multiple(peer, ast_str_buffer(interfacevar));
7473 }
7474
7475 /* if setqueueentryvar is defined, make queue entry (i.e. the caller) variables available to the channel */
7476 /* use pbx_builtin_setvar to set a load of variables with one call */
7477 if (qe->parent->setqueueentryvar && interfacevar) {
7478 ast_str_set(&interfacevar, 0, "QEHOLDTIME=%ld,QEORIGINALPOS=%d",
7479 (long) (time(NULL) - qe->start), qe->opos);
7481 pbx_builtin_setvar_multiple(peer, ast_str_buffer(interfacevar));
7482 }
7483
7484 ao2_unlock(qe->parent);
7485
7486 /* try to set queue variables if configured to do so*/
7488 set_queue_variables(qe->parent, peer);
7489
7490 setup_peer_after_bridge_goto(qe->chan, peer, &opts, opt_args);
7492 if ((monitorfilename = pbx_builtin_getvar_helper(qe->chan, "MONITOR_FILENAME"))) {
7493 monitorfilename = ast_strdupa(monitorfilename);
7494 }
7496
7497 /* Begin Monitoring */
7498 if (*qe->parent->monfmt) {
7499 setup_mixmonitor(qe, monitorfilename);
7500 }
7501 /* Drop out of the queue at this point, to prepare for next caller */
7502 leave_queue(qe);
7504 ast_debug(1, "app_queue: sendurl=%s.\n", url);
7505 ast_channel_sendurl(peer, url);
7506 }
7507
7508 /* run a gosub for this connection if defined. The gosub simply returns, no action is taken on the result */
7509 /* use gosub from dialplan if passed as a option, otherwise use the default queue gosub */
7510 if (!ast_strlen_zero(gosub)) {
7511 gosubexec = ast_strdupa(gosub);
7512 } else {
7513 if (qe->parent->membergosub) {
7514 gosubexec = ast_strdupa(qe->parent->membergosub);
7515 }
7516 }
7517
7518 if (!ast_strlen_zero(gosubexec)) {
7519 char *gosub_args = NULL;
7520 char *gosub_argstart;
7521
7522 ast_debug(1, "app_queue: gosub=%s.\n", gosubexec);
7523
7524 gosub_argstart = strchr(gosubexec, ',');
7525 if (gosub_argstart) {
7526 const char *what_is_s = "s";
7527 *gosub_argstart = 0;
7528 if (!ast_exists_extension(peer, gosubexec, "s", 1, S_COR(ast_channel_caller(peer)->id.number.valid, ast_channel_caller(peer)->id.number.str, NULL)) &&
7529 ast_exists_extension(peer, gosubexec, "~~s~~", 1, S_COR(ast_channel_caller(peer)->id.number.valid, ast_channel_caller(peer)->id.number.str, NULL))) {
7530 what_is_s = "~~s~~";
7531 }
7532 if (ast_asprintf(&gosub_args, "%s,%s,1(%s)", gosubexec, what_is_s, gosub_argstart + 1) < 0) {
7533 gosub_args = NULL;
7534 }
7535 *gosub_argstart = ',';
7536 } else {
7537 const char *what_is_s = "s";
7538 if (!ast_exists_extension(peer, gosubexec, "s", 1, S_COR(ast_channel_caller(peer)->id.number.valid, ast_channel_caller(peer)->id.number.str, NULL)) &&
7539 ast_exists_extension(peer, gosubexec, "~~s~~", 1, S_COR(ast_channel_caller(peer)->id.number.valid, ast_channel_caller(peer)->id.number.str, NULL))) {
7540 what_is_s = "~~s~~";
7541 }
7542 if (ast_asprintf(&gosub_args, "%s,%s,1", gosubexec, what_is_s) < 0) {
7543 gosub_args = NULL;
7544 }
7545 }
7546 if (gosub_args) {
7547 ast_app_exec_sub(qe->chan, peer, gosub_args, 0);
7548 ast_free(gosub_args);
7549 } else {
7550 ast_log(LOG_ERROR, "Could not Allocate string for Gosub arguments -- Gosub Call Aborted!\n");
7551 }
7552 }
7553
7554 if (!ast_strlen_zero(agi)) {
7555 ast_debug(1, "app_queue: agi=%s.\n", agi);
7556 application = pbx_findapp("agi");
7557 if (application) {
7558 agiexec = ast_strdupa(agi);
7559 pbx_exec(qe->chan, application, agiexec);
7560 } else {
7561 ast_log(LOG_WARNING, "Asked to execute an AGI on this channel, but could not find application (agi)!\n");
7562 }
7563 }
7564 qe->handled++;
7565
7566 ast_queue_log(queuename, ast_channel_uniqueid(qe->chan), member->membername, "CONNECT", "%ld|%s|%ld", (long) (time(NULL) - qe->start), ast_channel_uniqueid(peer),
7567 (long)(orig - to > 0 ? (orig - to) / 1000 : 0));
7568
7569 blob = ast_json_pack("{s: s, s: s, s: s, s: I, s: I}",
7570 "Queue", queuename,
7571 "Interface", member->interface,
7572 "MemberName", member->membername,
7573 "HoldTime", (ast_json_int_t)(time(NULL) - qe->start),
7574 "RingTime", (ast_json_int_t)(orig - to > 0 ? (orig - to) / 1000 : 0));
7575 queue_publish_multi_channel_blob(qe->chan, peer, queue_agent_connect_type(), blob);
7576
7577 ast_copy_string(oldcontext, ast_channel_context(qe->chan), sizeof(oldcontext));
7578 ast_copy_string(oldexten, ast_channel_exten(qe->chan), sizeof(oldexten));
7579
7580 if ((queue_end_bridge = ao2_alloc(sizeof(*queue_end_bridge), NULL))) {
7581 queue_end_bridge->q = qe->parent;
7582 queue_end_bridge->chan = qe->chan;
7583 bridge_config.end_bridge_callback = end_bridge_callback;
7584 bridge_config.end_bridge_callback_data = queue_end_bridge;
7585 bridge_config.end_bridge_callback_data_fixup = end_bridge_callback_data_fixup;
7586 /* Since queue_end_bridge can survive beyond the life of this call to Queue, we need
7587 * to make sure to increase the refcount of this queue so it cannot be freed until we
7588 * are done with it. We remove this reference in end_bridge_callback.
7589 */
7590 queue_t_ref(qe->parent, "For bridge_config reference");
7591 }
7592
7593 ao2_lock(qe->parent);
7594 time(&member->starttime);
7595 starttime = member->starttime;
7596 ao2_unlock(qe->parent);
7597 /* As a queue member may end up in multiple calls at once if a transfer occurs with
7598 * a Local channel in the mix we pass the current call information (starttime) to the
7599 * Stasis subscriptions so when they update the queue member data it becomes a noop
7600 * if this call is no longer between the caller and the queue member.
7601 */
7602 setup_stasis_subs(qe, peer, member, qe->start, starttime, callcompletedinsl);
7603 bridge = ast_bridge_call_with_flags(qe->chan, peer, &bridge_config,
7605
7606 res = bridge ? bridge : 1;
7607 ao2_ref(member, -1);
7608 }
7609out:
7611
7612 return res;
7613}
char digit
static int setup_stasis_subs(struct queue_ent *qe, struct ast_channel *peer, struct member *mem, time_t holdstart, time_t starttime, int callcompletedinsl)
Definition: app_queue.c:6943
static void setup_mixmonitor(struct queue_ent *qe, const char *filename)
Definition: app_queue.c:7075
static void recalc_holdtime(struct queue_ent *qe, int newholdtime)
Definition: app_queue.c:4519
static void hangupcalls(struct queue_ent *qe, struct callattempt *outgoing, struct ast_channel *exception, int cancel_answered_elsewhere)
Hang up a list of outgoing calls.
Definition: app_queue.c:4639
static int calc_metric(struct call_queue *q, struct member *mem, int pos, struct queue_ent *qe, struct callattempt *tmp)
Calculate the metric of each member in the outgoing callattempts.
Definition: app_queue.c:6214
static int store_next_lin(struct queue_ent *qe, struct callattempt *outgoing)
Search for best metric and add to Linear queue.
Definition: app_queue.c:5164
static struct callattempt * wait_for_answer(struct queue_ent *qe, struct callattempt *outgoing, int *to, char *digit, int prebusies, int caller_disconnect, int forwardsallowed)
Wait for a member to answer the call.
Definition: app_queue.c:5375
static int store_next_rr(struct queue_ent *qe, struct callattempt *outgoing)
Search for best metric and add to Round Robbin queue.
Definition: app_queue.c:5140
static void end_bridge_callback(void *data)
Definition: app_queue.c:7004
static void end_bridge_callback_data_fixup(struct ast_bridge_config *bconfig, struct ast_channel *originator, struct ast_channel *terminator)
Definition: app_queue.c:6997
static void setup_peer_after_bridge_goto(struct ast_channel *chan, struct ast_channel *peer, struct ast_flags *opts, char *opt_args[])
Definition: app_queue.c:7027
static int ring_one(struct queue_ent *qe, struct callattempt *outgoing, int *busies)
Place a call to a queue member.
Definition: app_queue.c:5080
#define ast_asprintf(ret, fmt,...)
A wrapper for asprintf()
Definition: astmm.h:267
@ AST_BRIDGE_FLAG_SWAP_INHIBIT_FROM
@ AST_BRIDGE_FLAG_MERGE_INHIBIT_TO
@ AST_BRIDGE_FLAG_MERGE_INHIBIT_FROM
@ AST_FEATURE_AUTOMIXMON
Definition: channel.h:1089
@ AST_FEATURE_REDIRECT
Definition: channel.h:1084
@ AST_FEATURE_PARKCALL
Definition: channel.h:1088
@ AST_FEATURE_AUTOMON
Definition: channel.h:1087
@ AST_FEATURE_DISCONNECT
Definition: channel.h:1085
int ast_channel_make_compatible(struct ast_channel *chan, struct ast_channel *peer)
Make the frame formats of two channels compatible.
Definition: channel.c:6737
void ast_party_connected_line_copy(struct ast_party_connected_line *dest, const struct ast_party_connected_line *src)
Copy the source connected line information to the destination connected line.
Definition: channel.c:2058
int ast_channel_supports_html(struct ast_channel *channel)
Checks for HTML support on a channel.
Definition: channel.c:6640
int ast_check_hangup(struct ast_channel *chan)
Check to see if a channel is needing hang up.
Definition: channel.c:445
int ast_channel_hangupcause(const struct ast_channel *chan)
#define AST_MAX_CONTEXT
Definition: channel.h:135
int ast_channel_sendurl(struct ast_channel *channel, const char *url)
Sends a URL on a given link Send URL on link.
Definition: channel.c:6652
const struct ast_channel_tech * ast_channel_tech(const struct ast_channel *chan)
int ast_channel_setoption(struct ast_channel *channel, int option, void *data, int datalen, int block)
Sets an option on a channel.
Definition: channel.c:7443
void ast_autoservice_chan_hangup_peer(struct ast_channel *chan, struct ast_channel *peer)
Put chan into autoservice while hanging up peer.
Definition: autoservice.c:349
int ast_safe_sleep(struct ast_channel *chan, int ms)
Wait for a specified amount of time, looking for hangups.
Definition: channel.c:1601
#define AST_MAX_EXTENSION
Definition: channel.h:134
const char * ast_hangup_cause_to_dial_status(int hangup_cause)
Convert a hangup cause to a publishable dial status.
Definition: dial.c:749
int ast_bridge_call_with_flags(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, unsigned int flags)
Bridge a call, and add additional flags to the bridge.
Definition: features.c:601
#define AST_OPTION_TONE_VERIFY
int ast_exists_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
Determine whether an extension exists.
Definition: pbx.c:4190
int pbx_exec(struct ast_channel *c, struct ast_app *app, const char *data)
Execute an application.
Definition: pbx_app.c:471
struct ast_app * pbx_findapp(const char *app)
Look up an application.
Definition: ael_main.c:165
@ AST_STRSEP_TRIM
Definition: strings.h:256
@ AST_STRSEP_STRIP
Definition: strings.h:255
char * ast_strsep(char **s, const char sep, uint32_t flags)
Act like strsep but ignore separators inside quotes.
Definition: utils.c:1835
ast_app: A registered application
Definition: pbx_app.c:45
bridge configuration
Definition: channel.h:1096
const char *const type
Definition: channel.h:649
const ast_string_field sound_callerannounce
Definition: app_queue.c:1999
const ast_string_field sound_reporthold
Definition: app_queue.c:1999
const ast_string_field membergosub
Definition: app_queue.c:1999
unsigned int block_connected_update
Definition: app_queue.c:1851

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

Referenced by queue_exec().

◆ unload_module()

static int unload_module ( void  )
static

Definition at line 11922 of file app_queue.c.

11923{
11926
11928
11929 STASIS_MESSAGE_TYPE_CLEANUP(queue_caller_join_type);
11930 STASIS_MESSAGE_TYPE_CLEANUP(queue_caller_leave_type);
11931 STASIS_MESSAGE_TYPE_CLEANUP(queue_caller_abandon_type);
11932
11933 STASIS_MESSAGE_TYPE_CLEANUP(queue_member_status_type);
11934 STASIS_MESSAGE_TYPE_CLEANUP(queue_member_added_type);
11935 STASIS_MESSAGE_TYPE_CLEANUP(queue_member_removed_type);
11936 STASIS_MESSAGE_TYPE_CLEANUP(queue_member_pause_type);
11937 STASIS_MESSAGE_TYPE_CLEANUP(queue_member_penalty_type);
11938 STASIS_MESSAGE_TYPE_CLEANUP(queue_member_ringinuse_type);
11939
11940 STASIS_MESSAGE_TYPE_CLEANUP(queue_agent_called_type);
11941 STASIS_MESSAGE_TYPE_CLEANUP(queue_agent_connect_type);
11942 STASIS_MESSAGE_TYPE_CLEANUP(queue_agent_complete_type);
11943 STASIS_MESSAGE_TYPE_CLEANUP(queue_agent_dump_type);
11944 STASIS_MESSAGE_TYPE_CLEANUP(queue_agent_ringnoanswer_type);
11945
11947 ast_manager_unregister("QueueStatus");
11948 ast_manager_unregister("QueueRule");
11949 ast_manager_unregister("QueueSummary");
11950 ast_manager_unregister("QueueAdd");
11951 ast_manager_unregister("QueueRemove");
11952 ast_manager_unregister("QueuePause");
11953 ast_manager_unregister("QueueLog");
11954 ast_manager_unregister("QueueUpdate");
11955 ast_manager_unregister("QueuePenalty");
11956 ast_manager_unregister("QueueReload");
11957 ast_manager_unregister("QueueReset");
11958 ast_manager_unregister("QueueMemberRingInUse");
11959 ast_manager_unregister("QueueChangePriorityCaller");
11960 ast_manager_unregister("QueueWithdrawCaller");
11976
11978
11979 ast_unload_realtime("queue_members");
11982
11983 queues = NULL;
11984 return 0;
11985}
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
Definition: clicompat.c:30
int ast_manager_unregister(const char *action)
Unregister a registered manager command.
Definition: manager.c:7697
int ast_unregister_application(const char *app)
Unregister an application.
Definition: pbx_app.c:392
int ast_custom_function_unregister(struct ast_custom_function *acf)
Unregister a custom function.
#define STASIS_MESSAGE_TYPE_CLEANUP(name)
Boiler-plate messaging macro for cleaning up message types.
Definition: stasis.h:1515
struct stasis_forward * stasis_forward_cancel(struct stasis_forward *forward)
Definition: stasis.c:1575
struct stasis_subscription * stasis_unsubscribe_and_join(struct stasis_subscription *subscription)
Cancel a subscription, blocking until the last message is processed.
Definition: stasis.c:1161
void stasis_message_router_unsubscribe_and_join(struct stasis_message_router *router)
Unsubscribe the router from the upstream topic, blocking until the final message has been processed.

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

Referenced by load_module().

◆ update_connected_line_from_peer()

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

Definition at line 5345 of file app_queue.c.

5346{
5347 struct ast_party_connected_line connected_caller;
5348
5349 ast_party_connected_line_init(&connected_caller);
5350
5351 ast_channel_lock(peer);
5353 ast_channel_unlock(peer);
5354 connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
5355 if (ast_channel_connected_line_sub(peer, chan, &connected_caller, 0)) {
5356 ast_channel_update_connected_line(chan, &connected_caller, NULL);
5357 }
5358 ast_party_connected_line_free(&connected_caller);
5359}
@ AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER
Definition: callerid.h:554
int ast_channel_connected_line_sub(struct ast_channel *autoservice_chan, struct ast_channel *sub_chan, const void *connected_info, int frame)
Run a connected line interception subroutine and update a channel's connected line information.
Definition: channel.c:10364
void ast_channel_update_connected_line(struct ast_channel *chan, const struct ast_party_connected_line *connected, const struct ast_set_party_connected_line *update)
Indicate that the connected line information has changed.
Definition: channel.c:9119
void ast_party_connected_line_init(struct ast_party_connected_line *init)
Initialize the given connected line structure.
Definition: channel.c:2049
Connected Line/Party information.
Definition: channel.h:458

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

Referenced by wait_for_answer().

◆ update_qe_rule()

static void update_qe_rule ( struct queue_ent qe)
static

update rules for queues

Calculate min/max penalties making sure if relative they stay within bounds. Update queues penalty and set dialplan vars, goto next list entry.

Definition at line 5964 of file app_queue.c.

5965{
5966 int max_penalty = INT_MAX;
5967
5968 if (qe->max_penalty != INT_MAX) {
5969 char max_penalty_str[20];
5970
5971 if (qe->pr->max_relative) {
5972 max_penalty = qe->max_penalty + qe->pr->max_value;
5973 } else {
5974 max_penalty = qe->pr->max_value;
5975 }
5976
5977 /* a relative change to the penalty could put it below 0 */
5978 if (max_penalty < 0) {
5979 max_penalty = 0;
5980 }
5981
5982 snprintf(max_penalty_str, sizeof(max_penalty_str), "%d", max_penalty);
5983 pbx_builtin_setvar_helper(qe->chan, "QUEUE_MAX_PENALTY", max_penalty_str);
5984 qe->max_penalty = max_penalty;
5985 ast_debug(3, "Setting max penalty to %d for caller %s since %d seconds have elapsed\n",
5986 qe->max_penalty, ast_channel_name(qe->chan), qe->pr->time);
5987 }
5988
5989 if (qe->min_penalty != INT_MAX) {
5990 char min_penalty_str[20];
5991 int min_penalty;
5992
5993 if (qe->pr->min_relative) {
5994 min_penalty = qe->min_penalty + qe->pr->min_value;
5995 } else {
5996 min_penalty = qe->pr->min_value;
5997 }
5998
5999 /* a relative change to the penalty could put it below 0 */
6000 if (min_penalty < 0) {
6001 min_penalty = 0;
6002 }
6003
6004 if (max_penalty != INT_MAX && min_penalty > max_penalty) {
6005 min_penalty = max_penalty;
6006 }
6007
6008 snprintf(min_penalty_str, sizeof(min_penalty_str), "%d", min_penalty);
6009 pbx_builtin_setvar_helper(qe->chan, "QUEUE_MIN_PENALTY", min_penalty_str);
6010 qe->min_penalty = min_penalty;
6011 ast_debug(3, "Setting min penalty to %d for caller %s since %d seconds have elapsed\n",
6012 qe->min_penalty, ast_channel_name(qe->chan), qe->pr->time);
6013 }
6014
6015 if (qe->raise_penalty != INT_MAX) {
6016 char raise_penalty_str[20];
6017 int raise_penalty;
6018
6019 if (qe->pr->raise_relative) {
6020 raise_penalty = qe->raise_penalty + qe->pr->raise_value;
6021 } else {
6022 raise_penalty = qe->pr->raise_value;
6023 }
6024
6025 /* a relative change to the penalty could put it below 0 */
6026 if (raise_penalty < 0) {
6027 raise_penalty = 0;
6028 }
6029
6030 if (max_penalty != INT_MAX && raise_penalty > max_penalty) {
6031 raise_penalty = max_penalty;
6032 }
6033
6034 snprintf(raise_penalty_str, sizeof(raise_penalty_str), "%d", raise_penalty);
6035 pbx_builtin_setvar_helper(qe->chan, "QUEUE_RAISE_PENALTY", raise_penalty_str);
6036 qe->raise_penalty = raise_penalty;
6037 ast_debug(3, "Setting raised penalty to %d for caller %s since %d seconds have elapsed\n",
6038 qe->raise_penalty, ast_channel_name(qe->chan), qe->pr->time);
6039 }
6040
6041 qe->pr = AST_LIST_NEXT(qe->pr, list);
6042}
#define AST_LIST_NEXT(elm, field)
Returns the next entry in the list after the given entry.
Definition: linkedlists.h:439

References ast_channel_name(), ast_debug, AST_LIST_NEXT, queue_ent::chan, queue_ent::max_penalty, penalty_rule::max_relative, penalty_rule::max_value, queue_ent::min_penalty, penalty_rule::min_relative, penalty_rule::min_value, pbx_builtin_setvar_helper(), queue_ent::pr, queue_ent::raise_penalty, penalty_rule::raise_relative, penalty_rule::raise_value, and penalty_rule::time.

Referenced by queue_exec(), and wait_our_turn().

◆ update_queue()

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

update the queue status

Return values
0always

Definition at line 6142 of file app_queue.c.

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

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

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

◆ update_realtime_member_field()

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

Definition at line 4154 of file app_queue.c.

4155{
4156 int ret = -1;
4157
4158 if (ast_strlen_zero(mem->rt_uniqueid)) {
4159 return ret;
4160 }
4161
4162 if ((ast_update_realtime("queue_members", "uniqueid", mem->rt_uniqueid, field, value, SENTINEL)) >= 0) {
4163 ret = 0;
4164 }
4165
4166 return ret;
4167}

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

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

◆ update_realtime_members()

static void update_realtime_members ( struct call_queue q)
static

Definition at line 4170 of file app_queue.c.

4171{
4172 struct ast_config *member_config = NULL;
4173 struct member *m;
4174 char *category = NULL;
4175 struct ao2_iterator mem_iter;
4176
4177 if (!(member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name", q->name , SENTINEL))) {
4178 /* This queue doesn't have realtime members. If the queue still has any realtime
4179 * members in memory, they need to be removed.
4180 */
4181 ao2_lock(q);
4182 mem_iter = ao2_iterator_init(q->members, 0);
4183 while ((m = ao2_iterator_next(&mem_iter))) {
4184 if (m->realtime) {
4186 }
4187 ao2_ref(m, -1);
4188 }
4189 ao2_iterator_destroy(&mem_iter);
4190 ast_debug(3, "Queue %s has no realtime members defined. No need for update\n", q->name);
4191 ao2_unlock(q);
4192 return;
4193 }
4194
4195 ao2_lock(q);
4196
4197 /* Temporarily set realtime members dead so we can detect deleted ones.*/
4198 mem_iter = ao2_iterator_init(q->members, 0);
4199 while ((m = ao2_iterator_next(&mem_iter))) {
4200 if (m->realtime) {
4201 m->dead = 1;
4202 }
4203 ao2_ref(m, -1);
4204 }
4205 ao2_iterator_destroy(&mem_iter);
4206
4207 while ((category = ast_category_browse(member_config, category))) {
4208 rt_handle_member_record(q, category, member_config);
4209 }
4210
4211 /* Delete all realtime members that have been deleted in DB. */
4212 mem_iter = ao2_iterator_init(q->members, 0);
4213 while ((m = ao2_iterator_next(&mem_iter))) {
4214 if (m->dead) {
4216 ast_queue_log(q->name, "REALTIME", m->interface, "REMOVEMEMBER", "%s", "");
4217 } else {
4218 ast_queue_log(q->name, "REALTIME", m->membername, "REMOVEMEMBER", "%s", "");
4219 }
4221 }
4222 ao2_ref(m, -1);
4223 }
4224 ao2_iterator_destroy(&mem_iter);
4225 ao2_unlock(q);
4226 ast_config_destroy(member_config);
4227}

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

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

◆ update_status()

static void update_status ( struct call_queue q,
struct member m,
const int  status 
)
static

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

Lock interface list find sc, iterate through each queues queue_member list for member to update state inside queues

Definition at line 2745 of file app_queue.c.

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

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

Referenced by device_state_cb(), and extension_state_cb().

◆ upqm_exec()

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

UnpauseQueueMember application.

Definition at line 8417 of file app_queue.c.

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

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

Referenced by load_module().

◆ valid_exit()

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

Check for valid exit from queue via goto.

Return values
0if failure
1if successful

Definition at line 4342 of file app_queue.c.

4343{
4344 int digitlen = strlen(qe->digits);
4345
4346 /* Prevent possible buffer overflow */
4347 if (digitlen < sizeof(qe->digits) - 2) {
4348 qe->digits[digitlen] = digit;
4349 qe->digits[digitlen + 1] = '\0';
4350 } else {
4351 qe->digits[0] = '\0';
4352 return 0;
4353 }
4354
4355 /* If there's no context to goto, short-circuit */
4356 if (ast_strlen_zero(qe->context)) {
4357 return 0;
4358 }
4359
4360 /* If the extension is bad, then reset the digits to blank */
4361 if (!ast_canmatch_extension(qe->chan, qe->context, qe->digits, 1,
4363 qe->digits[0] = '\0';
4364 return 0;
4365 }
4366
4367 /* We have an exact match */
4368 if (!ast_goto_if_exists(qe->chan, qe->context, qe->digits, 1)) {
4369 qe->valid_digits = 1;
4370 /* Return 1 on a successful goto */
4371 return 1;
4372 }
4373
4374 return 0;
4375}
int ast_goto_if_exists(struct ast_channel *chan, const char *context, const char *exten, int priority)
Definition: pbx.c:8796
int ast_canmatch_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
Looks for a valid matching extension.
Definition: pbx.c:4205

References ast_canmatch_extension(), ast_channel_caller(), ast_goto_if_exists(), ast_strlen_zero(), queue_ent::chan, queue_ent::context, digit, queue_ent::digits, ast_party_caller::id, NULL, ast_party_id::number, S_COR, ast_party_number::str, ast_party_number::valid, and queue_ent::valid_digits.

Referenced by say_periodic_announcement(), say_position(), wait_a_bit(), wait_for_answer(), and wait_our_turn().

◆ wait_a_bit()

static int wait_a_bit ( struct queue_ent qe)
static

Definition at line 7615 of file app_queue.c.

7616{
7617 /* Don't need to hold the lock while we setup the outgoing calls */
7618 int retrywait = qe->parent->retry * 1000;
7619
7620 int res = ast_waitfordigit(qe->chan, retrywait);
7621 if (res > 0 && !valid_exit(qe, res)) {
7622 res = 0;
7623 }
7624
7625 return res;
7626}
int ast_waitfordigit(struct ast_channel *c, int ms)
Waits for a digit.
Definition: channel.c:3203

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

Referenced by queue_exec().

◆ wait_for_answer()

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

Wait for a member to answer the call.

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

Definition at line 5375 of file app_queue.c.

5376{
5377 const char *queue = qe->parent->name;
5378 struct callattempt *o, *start = NULL, *prev = NULL;
5379 int status;
5380 int numbusies = prebusies;
5381 int numnochan = 0;
5382 int stillgoing = 0;
5383 int orig = *to;
5384 struct ast_frame *f;
5385 struct callattempt *peer = NULL;
5386 struct ast_channel *winner;
5387 struct ast_channel *in = qe->chan;
5388 char on[80] = "";
5389 char membername[80] = "";
5390 long starttime = 0;
5391 long endtime = 0;
5392 char *inchan_name;
5393 struct timeval start_time_tv = ast_tvnow();
5394 int canceled_by_caller = 0; /* 1 when caller hangs up or press digit or press * */
5395
5397 inchan_name = ast_strdupa(ast_channel_name(qe->chan));
5399
5400 starttime = (long) time(NULL);
5401
5402 while ((*to = ast_remaining_ms(start_time_tv, orig)) && !peer) {
5403 int numlines, retry, pos = 1;
5404 struct ast_channel *watchers[AST_MAX_WATCHERS];
5405 watchers[0] = in;
5406 start = NULL;
5407
5408 for (retry = 0; retry < 2; retry++) {
5409 numlines = 0;
5410 for (o = outgoing; o; o = o->q_next) { /* Keep track of important channels */
5411 if (o->stillgoing) { /* Keep track of important channels */
5412 stillgoing = 1;
5413 if (o->chan) {
5414 if (pos < AST_MAX_WATCHERS) {
5415 watchers[pos++] = o->chan;
5416 }
5417 if (!start) {
5418 start = o;
5419 } else {
5420 prev->call_next = o;
5421 }
5422 prev = o;
5423 }
5424 } else if (prev) {
5425 prev->call_next = NULL;
5426 }
5427 numlines++;
5428 }
5429 if (pos > 1 /* found */ || !stillgoing /* nobody listening */ ||
5430 (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) /* ring would not be delivered */) {
5431 break;
5432 }
5433 /* On "ringall" strategy we only move to the next penalty level
5434 when *all* ringing phones are done in the current penalty level */
5435 ring_one(qe, outgoing, &numbusies);
5436 /* and retry... */
5437 }
5438 if (pos == 1 /* not found */) {
5439 if (numlines == (numbusies + numnochan)) {
5440 ast_debug(1, "Everyone is busy at this time\n");
5441 } else {
5442 ast_debug(3, "No one is answering queue '%s' (%d numlines / %d busies / %d failed channels)\n", queue, numlines, numbusies, numnochan);
5443 }
5444 *to = 0;
5445 return NULL;
5446 }
5447
5448 /* Poll for events from both the incoming channel as well as any outgoing channels */
5449 winner = ast_waitfor_n(watchers, pos, to);
5450
5451 /* Service all of the outgoing channels */
5452 for (o = start; o; o = o->call_next) {
5453 /* We go with a fixed buffer here instead of using ast_strdupa. Using
5454 * ast_strdupa in a loop like this one can cause a stack overflow
5455 */
5456 char ochan_name[AST_CHANNEL_NAME];
5457
5458 if (o->chan) {
5460 ast_copy_string(ochan_name, ast_channel_name(o->chan), sizeof(ochan_name));
5462 }
5463 if (o->stillgoing && (o->chan) && (ast_channel_state(o->chan) == AST_STATE_UP)) {
5464 if (!peer) {
5465 ast_verb(3, "%s answered %s\n", ochan_name, inchan_name);
5466 if (o->orig_chan_name
5467 && strcmp(o->orig_chan_name, ochan_name)) {
5468 /*
5469 * The channel name changed so we must generate COLP update.
5470 * Likely because a call pickup channel masqueraded in.
5471 */
5473 } else if (!o->block_connected_update) {
5474 if (o->pending_connected_update) {
5477 }
5478 } else if (!o->dial_callerid_absent) {
5480 }
5481 }
5482 if (o->aoc_s_rate_list) {
5483 size_t encoded_size;
5484 struct ast_aoc_encoded *encoded;
5485 if ((encoded = ast_aoc_encode(o->aoc_s_rate_list, &encoded_size, o->chan))) {
5486 ast_indicate_data(in, AST_CONTROL_AOC, encoded, encoded_size);
5487 ast_aoc_destroy_encoded(encoded);
5488 }
5489 }
5490 peer = o;
5491 }
5492 } else if (o->chan && (o->chan == winner)) {
5493
5494 ast_copy_string(on, o->member->interface, sizeof(on));
5495 ast_copy_string(membername, o->member->membername, sizeof(membername));
5496
5497 /* Before processing channel, go ahead and check for forwarding */
5498 if (!ast_strlen_zero(ast_channel_call_forward(o->chan)) && !forwardsallowed) {
5499 ast_verb(3, "Forwarding %s to '%s' prevented.\n", inchan_name, ast_channel_call_forward(o->chan));
5501 "CANCEL", ast_channel_call_forward(o->chan));
5502 numnochan++;
5503 do_hang(o);
5504 winner = NULL;
5505 continue;
5507 struct ast_channel *original = o->chan;
5508 char forwarder[AST_CHANNEL_NAME];
5509 char tmpchan[256];
5510 char *stuff;
5511 char *tech;
5512 int failed = 0;
5513
5514 ast_copy_string(tmpchan, ast_channel_call_forward(o->chan), sizeof(tmpchan));
5515 ast_copy_string(forwarder, ast_channel_name(o->chan), sizeof(forwarder));
5516 if ((stuff = strchr(tmpchan, '/'))) {
5517 *stuff++ = '\0';
5518 tech = tmpchan;
5519 } else {
5520 const char *forward_context;
5522 forward_context = pbx_builtin_getvar_helper(o->chan, "FORWARD_CONTEXT");
5523 snprintf(tmpchan, sizeof(tmpchan), "%s@%s", ast_channel_call_forward(o->chan), forward_context ? forward_context : ast_channel_context(o->chan));
5525 stuff = tmpchan;
5526 tech = "Local";
5527 }
5528 if (!strcasecmp(tech, "Local")) {
5529 /*
5530 * Drop the connected line update block for local channels since
5531 * this is going to run dialplan and the user can change his
5532 * mind about what connected line information he wants to send.
5533 */
5535 }
5536
5537 ast_verb(3, "Now forwarding %s to '%s/%s' (thanks to %s)\n", inchan_name, tech, stuff, ochan_name);
5538 /* Setup parameters */
5540 if (!o->chan) {
5542 "Forwarding failed to create channel to dial '%s/%s'\n",
5543 tech, stuff);
5544 o->stillgoing = 0;
5545 numnochan++;
5546 } else {
5547 ast_channel_lock_both(o->chan, original);
5549 ast_channel_redirecting(original));
5551 ast_channel_unlock(original);
5552
5556 pbx_builtin_setvar_helper(o->chan, "FORWARDERNAME", forwarder);
5558
5559 if (o->pending_connected_update) {
5560 /*
5561 * Re-seed the callattempt's connected line information with
5562 * previously acquired connected line info from the queued
5563 * channel. The previously acquired connected line info could
5564 * have been set through the CONNECTED_LINE dialplan function.
5565 */
5568 }
5569
5572
5574
5577 /*
5578 * The call was not previously redirected so it is
5579 * now redirected from this number.
5580 */
5586 }
5587
5589
5594
5597 && !o->block_connected_update) {
5598 struct ast_party_redirecting redirecting;
5599
5600 /*
5601 * Redirecting updates to the caller make sense only on single
5602 * call at a time strategies.
5603 *
5604 * Need to re-evaluate if calling unlock is still required as we no longer
5605 * use macro.
5606 */
5607 ast_party_redirecting_init(&redirecting);
5610 if (ast_channel_redirecting_sub(o->chan, in, &redirecting, 0)) {
5611 ast_channel_update_redirecting(in, &redirecting, NULL);
5612 }
5613 ast_party_redirecting_free(&redirecting);
5614 } else {
5616 }
5617
5618 if (ast_call(o->chan, stuff, 0)) {
5619 ast_log(LOG_NOTICE, "Forwarding failed to dial '%s/%s'\n",
5620 tech, stuff);
5621 failed = 1;
5622 }
5623 }
5624
5626 "CANCEL", ast_channel_call_forward(original));
5627 if (o->chan) {
5628 ast_channel_publish_dial(qe->chan, o->chan, stuff, NULL);
5629 }
5630
5631 if (failed) {
5632 do_hang(o);
5633 numnochan++;
5634 }
5635
5636 /* Hangup the original channel now, in case we needed it */
5637 ast_hangup(winner);
5638 continue;
5639 }
5640 f = ast_read(winner);
5641 if (f) {
5642 if (f->frametype == AST_FRAME_CONTROL) {
5643 switch (f->subclass.integer) {
5644 case AST_CONTROL_ANSWER:
5645 /* This is our guy if someone answered. */
5646 if (!peer) {
5647 ast_verb(3, "%s answered %s\n", ochan_name, inchan_name);
5648 ast_channel_publish_dial(qe->chan, o->chan, on, "ANSWER");
5649 publish_dial_end_event(qe->chan, outgoing, o->chan, "CANCEL");
5650 if (o->orig_chan_name
5651 && strcmp(o->orig_chan_name, ochan_name)) {
5652 /*
5653 * The channel name changed so we must generate COLP update.
5654 * Likely because a call pickup channel masqueraded in.
5655 */
5657 } else if (!o->block_connected_update) {
5658 if (o->pending_connected_update) {
5661 }
5662 } else if (!o->dial_callerid_absent) {
5664 }
5665 }
5666 if (o->aoc_s_rate_list) {
5667 size_t encoded_size;
5668 struct ast_aoc_encoded *encoded;
5669 if ((encoded = ast_aoc_encode(o->aoc_s_rate_list, &encoded_size, o->chan))) {
5670 ast_indicate_data(in, AST_CONTROL_AOC, encoded, encoded_size);
5671 ast_aoc_destroy_encoded(encoded);
5672 }
5673 }
5674 peer = o;
5675 }
5676 break;
5677 case AST_CONTROL_BUSY:
5678 ast_verb(3, "%s is busy\n", ochan_name);
5679 ast_channel_publish_dial(qe->chan, o->chan, on, "BUSY");
5680 endtime = (long) time(NULL);
5681 endtime -= starttime;
5682 rna(endtime * 1000, qe, o->chan, on, membername, qe->parent->autopausebusy);
5683 do_hang(o);
5685 if (qe->parent->timeoutrestart) {
5686 start_time_tv = ast_tvnow();
5687 }
5688 /* Have enough time for a queue member to answer? */
5689 if (ast_remaining_ms(start_time_tv, orig) > 500) {
5690 ring_one(qe, outgoing, &numbusies);
5691 starttime = (long) time(NULL);
5692 }
5693 }
5694 numbusies++;
5695 break;
5697 ast_verb(3, "%s is circuit-busy\n", ochan_name);
5698 ast_channel_publish_dial(qe->chan, o->chan, on, "CONGESTION");
5699 endtime = (long) time(NULL);
5700 endtime -= starttime;
5701 rna(endtime * 1000, qe, o->chan, on, membername, qe->parent->autopauseunavail);
5702 do_hang(o);
5704 if (qe->parent->timeoutrestart) {
5705 start_time_tv = ast_tvnow();
5706 }
5707 if (ast_remaining_ms(start_time_tv, orig) > 500) {
5708 ring_one(qe, outgoing, &numbusies);
5709 starttime = (long) time(NULL);
5710 }
5711 }
5712 numbusies++;
5713 break;
5715 ast_verb(3, "%s is ringing\n", ochan_name);
5716
5717 ast_channel_publish_dial(qe->chan, o->chan, on, "RINGING");
5718
5719 /* Start ring indication when the channel is ringing, if specified */
5720 if (qe->ring_when_ringing) {
5721 ast_moh_stop(qe->chan);
5723 }
5724 break;
5726 /* Ignore going off hook */
5727 break;
5729 if (o->block_connected_update) {
5730 ast_verb(3, "Connected line update to %s prevented.\n", inchan_name);
5731 break;
5732 }
5735
5736 ast_verb(3, "%s connected line has changed. Saving it until answer for %s\n", ochan_name, inchan_name);
5742 break;
5743 }
5744
5745 /*
5746 * Prevent using the CallerID from the outgoing channel since we
5747 * got a connected line update from it.
5748 */
5749 o->dial_callerid_absent = 1;
5750
5751 if (ast_channel_connected_line_sub(o->chan, in, f, 1)) {
5753 }
5754 break;
5755 case AST_CONTROL_AOC:
5756 {
5757 struct ast_aoc_decoded *decoded = ast_aoc_decode(f->data.ptr, f->datalen, o->chan);
5758 if (decoded && (ast_aoc_get_msg_type(decoded) == AST_AOC_S)) {
5760 o->aoc_s_rate_list = decoded;
5761 } else {
5762 ast_aoc_destroy_decoded(decoded);
5763 }
5764 }
5765 break;
5768 /*
5769 * Redirecting updates to the caller make sense only on single
5770 * call at a time strategies.
5771 */
5772 break;
5773 }
5774 if (o->block_connected_update) {
5775 ast_verb(3, "Redirecting update to %s prevented\n",
5776 inchan_name);
5777 break;
5778 }
5779 ast_verb(3, "%s redirecting info has changed, passing it to %s\n",
5780 ochan_name, inchan_name);
5781 if (ast_channel_redirecting_sub(o->chan, in, f, 1)) {
5783 }
5784 break;
5787 break;
5788 default:
5789 ast_debug(1, "Dunno what to do with control type %d\n", f->subclass.integer);
5790 break;
5791 }
5792 }
5793 ast_frfree(f);
5794 } else { /* ast_read() returned NULL */
5795 endtime = (long) time(NULL) - starttime;
5796 ast_channel_publish_dial(qe->chan, o->chan, on, "NOANSWER");
5797 rna(endtime * 1000, qe, o->chan, on, membername, 1);
5798 do_hang(o);
5800 if (qe->parent->timeoutrestart) {
5801 start_time_tv = ast_tvnow();
5802 }
5803 if (ast_remaining_ms(start_time_tv, orig) > 500) {
5804 ring_one(qe, outgoing, &numbusies);
5805 starttime = (long) time(NULL);
5806 }
5807 }
5808 }
5809 }
5810 }
5811
5812 /* If we received an event from the caller, deal with it. */
5813 if (winner == in) {
5814 f = ast_read(in);
5815 if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass.integer == AST_CONTROL_HANGUP))) {
5816 /* Got hung up */
5817 *to = -1;
5818 if (f) {
5819 if (f->data.uint32) {
5821 }
5822 ast_frfree(f);
5823 }
5824 canceled_by_caller = 1;
5825 } else if ((f->frametype == AST_FRAME_DTMF) && caller_disconnect && (f->subclass.integer == '*')) {
5826 ast_verb(3, "User hit %c to disconnect call.\n", f->subclass.integer);
5827 *to = 0;
5828 ast_frfree(f);
5829 canceled_by_caller = 1;
5830 } else if ((f->frametype == AST_FRAME_DTMF) && valid_exit(qe, f->subclass.integer)) {
5831 ast_verb(3, "User pressed digit: %c\n", f->subclass.integer);
5832 *to = 0;
5833 *digit = f->subclass.integer;
5834 ast_frfree(f);
5835 canceled_by_caller = 1;
5836 }
5837 /* When caller hung up or pressed * or digit. */
5838 if (canceled_by_caller) {
5840 for (o = start; o; o = o->call_next) {
5841 if (o->chan) {
5842 ast_queue_log(qe->parent->name, ast_channel_uniqueid(qe->chan), o->member->membername, "RINGCANCELED", "%d", (int) ast_tvdiff_ms(ast_tvnow(), start_time_tv));
5843 }
5844 }
5845 return NULL;
5846 }
5847
5848 /* Send the frame from the in channel to all outgoing channels. */
5849 for (o = start; o; o = o->call_next) {
5850 if (!o->stillgoing || !o->chan) {
5851 /* This outgoing channel has died so don't send the frame to it. */
5852 continue;
5853 }
5854 switch (f->frametype) {
5855 case AST_FRAME_CONTROL:
5856 switch (f->subclass.integer) {
5858 if (o->block_connected_update) {
5859 ast_verb(3, "Connected line update to %s prevented.\n", ast_channel_name(o->chan));
5860 break;
5861 }
5862 if (ast_channel_connected_line_sub(in, o->chan, f, 1)) {
5864 }
5865 break;
5867 if (o->block_connected_update) {
5868 ast_verb(3, "Redirecting update to %s prevented.\n", ast_channel_name(o->chan));
5869 break;
5870 }
5871 if (ast_channel_redirecting_sub(in, o->chan, f, 1)) {
5873 }
5874 break;
5875 default:
5876 /* We are not going to do anything with this frame. */
5877 goto skip_frame;
5878 }
5879 break;
5880 default:
5881 /* We are not going to do anything with this frame. */
5882 goto skip_frame;
5883 }
5884 }
5885skip_frame:;
5886
5887 ast_frfree(f);
5888 }
5889 }
5890
5891 if (!*to) {
5892 for (o = start; o; o = o->call_next) {
5893 if (o->chan) {
5894 rna(orig, qe, o->chan, o->interface, o->member->membername, 1);
5895 }
5896 }
5897
5898 publish_dial_end_event(qe->chan, outgoing, NULL, "NOANSWER");
5899 }
5900
5901 return peer;
5902}
void * ast_aoc_destroy_encoded(struct ast_aoc_encoded *encoded)
free an ast_aoc_encoded object
Definition: aoc.c:322
enum ast_aoc_type ast_aoc_get_msg_type(struct ast_aoc_decoded *decoded)
get the message type, AOC-D, AOC-E, or AOC Request
Definition: aoc.c:901
struct ast_aoc_decoded * ast_aoc_decode(struct ast_aoc_encoded *encoded, size_t size, struct ast_channel *chan)
decodes an encoded aoc payload.
Definition: aoc.c:458
struct ast_aoc_encoded * ast_aoc_encode(struct ast_aoc_decoded *decoded, size_t *out_size, struct ast_channel *chan)
encodes a decoded aoc structure so it can be passed on the wire
Definition: aoc.c:659
@ AST_AOC_S
Definition: aoc.h:64
#define AST_MAX_WATCHERS
Definition: app_queue.c:5361
static void update_connected_line_from_peer(struct ast_channel *chan, struct ast_channel *peer, int is_caller)
Definition: app_queue.c:5345
static void rna(int rnatime, struct queue_ent *qe, struct ast_channel *peer, char *interface, char *membername, int autopause)
RNA == Ring No Answer. Common code that is executed when we try a queue member and they don't answer.
Definition: app_queue.c:5280
void ast_party_redirecting_init(struct ast_party_redirecting *init)
Initialize the given redirecting structure.
Definition: channel.c:2149
void ast_party_number_init(struct ast_party_number *init)
Initialize the given number structure.
Definition: channel.c:1671
struct ast_channel * ast_waitfor_n(struct ast_channel **chan, int n, int *ms)
Waits for input on a group of channels Wait for input on an array of channels for a given # of millis...
Definition: channel.c:3185
void ast_party_connected_line_set(struct ast_party_connected_line *dest, const struct ast_party_connected_line *src, const struct ast_set_party_connected_line *update)
Set the connected line information based on another connected line source.
Definition: channel.c:2081
void ast_channel_req_accountcodes(struct ast_channel *chan, const struct ast_channel *requestor, enum ast_channel_requestor_relationship relationship)
Setup new channel accountcodes from the requestor channel after ast_request().
Definition: channel.c:6451
struct ast_frame * ast_read(struct ast_channel *chan)
Reads a frame.
Definition: channel.c:4274
int ast_channel_redirecting_sub(struct ast_channel *autoservice_chan, struct ast_channel *sub_chan, const void *redirecting_info, int is_frame)
Run a redirecting interception subroutine and update a channel's redirecting information.
Definition: channel.c:10409
int ast_connected_line_parse_data(const unsigned char *data, size_t datalen, struct ast_party_connected_line *connected)
Parse connected line indication frame data.
Definition: channel.c:8811
int ast_indicate_data(struct ast_channel *chan, int condition, const void *data, size_t datalen)
Indicates condition of channel, with payload.
Definition: channel.c:4670
void ast_channel_update_redirecting(struct ast_channel *chan, const struct ast_party_redirecting *redirecting, const struct ast_set_party_redirecting *update)
Indicate that the redirecting id has changed.
Definition: channel.c:10310
#define AST_CHANNEL_NAME
Definition: channel.h:173
void ast_party_number_free(struct ast_party_number *doomed)
Destroy the party number contents.
Definition: channel.c:1718
void ast_party_redirecting_free(struct ast_party_redirecting *doomed)
Destroy the redirecting information contents.
Definition: channel.c:2206
const char * ast_channel_call_forward(const struct ast_channel *chan)
void ast_party_connected_line_set_init(struct ast_party_connected_line *init, const struct ast_party_connected_line *guide)
Initialize the given connected line structure using the given guide for a set update operation.
Definition: channel.c:2072
ast_channel_state
ast_channel states
Definition: channelstate.h:35
@ AST_STATE_UP
Definition: channelstate.h:42
char connected
Definition: eagi_proxy.c:82
void ast_channel_publish_dial_forward(struct ast_channel *caller, struct ast_channel *peer, struct ast_channel *forwarded, const char *dialstring, const char *dialstatus, const char *forward)
Publish in the ast_channel_topic or ast_channel_topic_all topics a stasis message for the channels in...
#define AST_FRAME_DTMF
#define ast_frfree(fr)
@ AST_FRAME_CONTROL
@ AST_CONTROL_OFFHOOK
@ AST_CONTROL_BUSY
@ AST_CONTROL_REDIRECTING
@ AST_CONTROL_CONGESTION
@ AST_CONTROL_ANSWER
@ AST_CONTROL_HANGUP
@ AST_CONTROL_CONNECTED_LINE
@ AST_CONTROL_AOC
@ AST_CONTROL_PVT_CAUSE_CODE
const struct ast_channel_tech * tech
Data structure associated with a single frame of data.
union ast_frame::@228 data
struct ast_frame_subclass subclass
enum ast_frame_type frametype
Redirecting Line information. RDNIS (Redirecting Directory Number Information Service) Where a call d...
Definition: channel.h:524
struct ast_party_id from
Who is redirecting the call (Sent to the party the call is redirected toward)
Definition: channel.h:529
struct callattempt * call_next
Definition: app_queue.c:1841
unsigned int pending_connected_update
Definition: app_queue.c:1849
int ast_remaining_ms(struct timeval start, int max_ms)
Calculate remaining milliseconds given a starting timestamp and upper bound.
Definition: utils.c:2281
int64_t ast_tvdiff_ms(struct timeval end, struct timeval start)
Computes the difference (in milliseconds) between two struct timeval instances.
Definition: time.h:107
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:159

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

Referenced by try_calling().

◆ wait_our_turn()

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

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

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

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

Definition at line 6054 of file app_queue.c.

6055{
6056 int res = 0;
6057
6058 /* This is the holding pen for callers 2 through maxlen */
6059 for (;;) {
6060
6061 /* A request to withdraw this call from the queue arrived */
6062 if (qe->withdraw) {
6063 *reason = QUEUE_WITHDRAW;
6064 res = 1;
6065 break;
6066 }
6067
6068 if (is_our_turn(qe)) {
6069 break;
6070 }
6071
6072 /* If we have timed out, break out */
6073 if (qe->expire && (time(NULL) >= qe->expire)) {
6074 *reason = QUEUE_TIMEOUT;
6075 break;
6076 }
6077
6078 if (qe->parent->leavewhenempty) {
6079 int status = 0;
6080
6082 record_abandoned(qe);
6083 *reason = QUEUE_LEAVEEMPTY;
6084 ast_queue_log(qe->parent->name, ast_channel_uniqueid(qe->chan), "NONE", "EXITEMPTY", "%d|%d|%ld", qe->pos, qe->opos, (long) (time(NULL) - qe->start));
6085 res = -1;
6086 qe->handled = -1;
6087 break;
6088 }
6089 }
6090
6091 /* Make a position announcement, if enabled */
6092 if (qe->parent->announcefrequency &&
6093 (res = say_position(qe,ringing))) {
6094 break;
6095 }
6096
6097 /* If we have timed out, break out */
6098 if (qe->expire && (time(NULL) >= qe->expire)) {
6099 *reason = QUEUE_TIMEOUT;
6100 break;
6101 }
6102
6103 /* Make a periodic announcement, if enabled */
6106 break;
6107
6108 /* see if we need to move to the next penalty level for this queue */
6109 while (qe->pr && ((time(NULL) - qe->start) >= qe->pr->time)) {
6110 update_qe_rule(qe);
6111 }
6112
6113 /* If we have timed out, break out */
6114 if (qe->expire && (time(NULL) >= qe->expire)) {
6115 *reason = QUEUE_TIMEOUT;
6116 break;
6117 }
6118
6119 /* Wait a second before checking again */
6120 if ((res = ast_waitfordigit(qe->chan, RECHECK * 1000))) {
6121 if (res > 0 && !valid_exit(qe, res)) {
6122 res = 0;
6123 } else {
6124 break;
6125 }
6126 }
6127
6128 /* If we have timed out, break out */
6129 if (qe->expire && (time(NULL) >= qe->expire)) {
6130 *reason = QUEUE_TIMEOUT;
6131 break;
6132 }
6133 }
6134
6135 return res;
6136}
#define RECHECK
Definition: app_queue.c:1722

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

Referenced by queue_exec().

◆ word_in_list()

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

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

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

Definition at line 10480 of file app_queue.c.

10480 {
10481 int list_len, word_len = strlen(word);
10482 const char *find, *end_find, *end_list;
10483
10484 /* strip whitespace from front */
10485 while(isspace(*list)) {
10486 list++;
10487 }
10488
10489 while((find = strstr(list, word))) {
10490 /* beginning of find starts inside another word? */
10491 if (find != list && *(find - 1) != ' ') {
10492 list = find;
10493 /* strip word from front */
10494 while(!isspace(*list) && *list != '\0') {
10495 list++;
10496 }
10497 /* strip whitespace from front */
10498 while(isspace(*list)) {
10499 list++;
10500 }
10501 continue;
10502 }
10503
10504 /* end of find ends inside another word or at very end of list? */
10505 list_len = strlen(list);
10506 end_find = find + word_len;
10507 end_list = list + list_len;
10508 if (end_find == end_list || *end_find != ' ') {
10509 list = find;
10510 /* strip word from front */
10511 while(!isspace(*list) && *list != '\0') {
10512 list++;
10513 }
10514 /* strip whitespace from front */
10515 while(isspace(*list)) {
10516 list++;
10517 }
10518 continue;
10519 }
10520
10521 /* terminating conditions satisfied, word at beginning or separated by ' ' */
10522 return 1;
10523 }
10524
10525 return 0;
10526}

References call_queue::list.

Referenced by complete_queue().

Variable Documentation

◆ __mod_info

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "True Call Queueing" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, .reload = reload, .load_pri = AST_MODPRI_DEVSTATE_CONSUMER, }
static

Definition at line 12185 of file app_queue.c.

◆ agent_router

struct stasis_message_router* agent_router
static

Definition at line 11919 of file app_queue.c.

Referenced by load_module(), and unload_module().

◆ app

char* app = "Queue"
static

Definition at line 1739 of file app_queue.c.

Referenced by load_module(), and unload_module().

◆ app_aqm

char* app_aqm = "AddQueueMember"
static

Definition at line 1741 of file app_queue.c.

Referenced by load_module(), and unload_module().

◆ app_pqm

char* app_pqm = "PauseQueueMember"
static

Definition at line 1745 of file app_queue.c.

Referenced by load_module(), and unload_module().

◆ app_ql

char* app_ql = "QueueLog"
static

Definition at line 1749 of file app_queue.c.

Referenced by load_module(), and unload_module().

◆ app_qupd

char* app_qupd = "QueueUpdate"
static

Definition at line 1751 of file app_queue.c.

Referenced by load_module(), and unload_module().

◆ app_rqm

char* app_rqm = "RemoveQueueMember"
static

Definition at line 1743 of file app_queue.c.

Referenced by load_module(), and unload_module().

◆ app_upqm

char* app_upqm = "UnpauseQueueMember"
static

Definition at line 1747 of file app_queue.c.

Referenced by load_module(), and unload_module().

◆ aqm_opts

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

Definition at line 1670 of file app_queue.c.

Referenced by aqm_exec().

◆ ast_module_info

const struct ast_module_info* ast_module_info = &__mod_info
static

Definition at line 12185 of file app_queue.c.

◆ autofill_default

int autofill_default
static

queues.conf [general] option

Definition at line 1763 of file app_queue.c.

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

◆ autopausesmodes

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

Referenced by autopause2int().

◆ cli_queue

struct ast_cli_entry cli_queue[]
static

Definition at line 11906 of file app_queue.c.

Referenced by load_module(), and unload_module().

◆ device_state_sub

struct stasis_subscription* device_state_sub
static

Subscription to device state change messages.

Definition at line 1775 of file app_queue.c.

Referenced by load_module(), and unload_module().

◆ force_longest_waiting_caller

int force_longest_waiting_caller
static

queues.conf [general] option

Definition at line 1784 of file app_queue.c.

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

◆ id

enum queue_result id

Definition at line 1808 of file app_queue.c.

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

◆ log_caller_id_name

int log_caller_id_name
static

queues.conf [general] option

Definition at line 1787 of file app_queue.c.

Referenced by queue_exec(), and queue_set_global_params().

◆ log_membername_as_agent

int log_membername_as_agent
static

◆ montype_default

int montype_default
static

queues.conf [general] option

Definition at line 1766 of file app_queue.c.

Referenced by queue_reset_global_params(), and queue_set_global_params().

◆ negative_penalty_invalid

int negative_penalty_invalid
static

queues.conf [general] option

Definition at line 1778 of file app_queue.c.

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

◆ pending_members

struct ao2_container* pending_members
static

Definition at line 2683 of file app_queue.c.

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

◆ pm_family

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

Persistent Members astdb family.

Definition at line 1754 of file app_queue.c.

Referenced by dump_queue_members(), and reload_queue_members().

◆ queue_exec_options

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

Definition at line 1654 of file app_queue.c.

Referenced by queue_exec().

◆ queue_persistent_members

int queue_persistent_members
static

◆ 

const struct { ... } queue_results[]

Referenced by set_queue_result().

◆ queueexists_function

struct ast_custom_function queueexists_function
static
Initial value:
= {
.name = "QUEUE_EXISTS",
}
static int queue_function_exists(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
Check if a given queue exists.
Definition: app_queue.c:9173

Definition at line 9653 of file app_queue.c.

Referenced by load_module(), and unload_module().

◆ queuegetchannel_function

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

Definition at line 9674 of file app_queue.c.

Referenced by load_module(), and unload_module().

◆ queuemembercount_dep

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

Definition at line 9669 of file app_queue.c.

Referenced by load_module(), and unload_module().

◆ queuemembercount_function

struct ast_custom_function queuemembercount_function
static
Initial value:
= {
.name = "QUEUE_MEMBER",
}
static int queue_function_mem_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
Get number either busy / free / ready or total members of a specific queue.
Definition: app_queue.c:9215
static int queue_function_mem_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
Dialplan function QUEUE_MEMBER() Sets the members penalty / paused / ringinuse.
Definition: app_queue.c:9317

Definition at line 9663 of file app_queue.c.

Referenced by load_module(), and unload_module().

◆ queuememberlist_function

struct ast_custom_function queuememberlist_function
static
Initial value:
= {
.name = "QUEUE_MEMBER_LIST",
}
static int queue_function_queuememberlist(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
Dialplan function QUEUE_MEMBER_LIST() Get list of members in a specific queue.
Definition: app_queue.c:9537

Definition at line 9684 of file app_queue.c.

Referenced by load_module(), and unload_module().

◆ queuememberpenalty_function

struct ast_custom_function queuememberpenalty_function
static
Initial value:
= {
.name = "QUEUE_MEMBER_PENALTY",
}
static int queue_function_memberpenalty_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
Dialplan function QUEUE_MEMBER_PENALTY() Gets the members penalty.
Definition: app_queue.c:9585
static int queue_function_memberpenalty_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
Dialplan function QUEUE_MEMBER_PENALTY() Sets the members penalty.
Definition: app_queue.c:9617

Definition at line 9689 of file app_queue.c.

Referenced by load_module(), and unload_module().

◆ queues

struct ao2_container* queues
static

◆ queuevar_function

struct ast_custom_function queuevar_function
static
Initial value:
= {
.name = "QUEUE_VARIABLES",
}
static int queue_function_var(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
create interface var with all queue details.
Definition: app_queue.c:9129

Definition at line 9658 of file app_queue.c.

Referenced by load_module(), and unload_module().

◆ queuewaitingcount_function

struct ast_custom_function queuewaitingcount_function
static
Initial value:
= {
.name = "QUEUE_WAITING_COUNT",
}
static int queue_function_queuewaitingcount(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
Dialplan function QUEUE_WAITING_COUNT() Get number callers waiting in a specific queue.
Definition: app_queue.c:9500

Definition at line 9679 of file app_queue.c.

Referenced by load_module(), and unload_module().

◆ realtime_reason_paused

int realtime_reason_paused
static

does realtime backend support reason_paused

Definition at line 1793 of file app_queue.c.

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

◆ realtime_ringinuse_field

char* realtime_ringinuse_field
static

name of the ringinuse field in the realtime database

Definition at line 1790 of file app_queue.c.

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

◆ realtime_rules

int realtime_rules
static

queuerules.conf [general] option

Definition at line 1772 of file app_queue.c.

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

◆ rule_lists

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

◆ shared_lastcall

int shared_lastcall
static

queues.conf [general] option

Definition at line 1769 of file app_queue.c.

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

◆ strategies

const struct strategy strategies[]
static

Referenced by int2strat(), and strat2int().

◆ text

char* text

◆ topic_forwarder

struct stasis_forward* topic_forwarder
static

Definition at line 11920 of file app_queue.c.

Referenced by load_module(), and unload_module().

◆ use_weight

int use_weight
static

Records that one or more queues use weight.

Definition at line 1760 of file app_queue.c.

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