Asterisk - The Open Source Telephony Project GIT-master-4f2b068
Loading...
Searching...
No Matches
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 <inttypes.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.
 
#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.
 
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.
 
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.
 
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.
 
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.
 
static void clear_queue (struct call_queue *q)
 
static int clear_stats (const char *queuename)
 Facilitates resetting statistics for a queue.
 
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.
 
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.
 
static void copy_rules (struct queue_ent *qe, const char *rulename)
 Copy rule from global list into specified queue.
 
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
 
static void destroy_queue (void *obj)
 Free queue's member list then its string fields.
 
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
 
static void do_hang (struct callattempt *o)
 common hangup actions
 
static void do_print (struct mansession *s, int fd, const char *str)
 direct output to manager or cli with proper terminator
 
static void dump_queue_members (struct call_queue *pm_queue)
 Dump all members in a specific queue to the database.
 
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.
 
static struct callattemptfind_best (struct callattempt *outgoing)
 find the entry with the best metric, or NULL
 
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.
 
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.
 
static void free_members (struct call_queue *q, int all)
 Iterate through queue's member list and delete them.
 
static struct memberget_interface_helper (struct call_queue *q, const char *interface)
 
static int get_member_penalty (char *queuename, char *interface)
 Gets members penalty.
 
static int get_member_status (struct call_queue *q, int max_penalty, int min_penalty, int raise_penalty, enum empty_conditions conditions, int devstate, int raise_respect_min)
 Check if members are available.
 
static int get_queue_member_status (struct member *cur)
 Return the current state of a member.
 
static int get_wrapuptime (struct call_queue *q, struct member *member)
 Return wrapuptime.
 
static void handle_attended_transfer (void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
 Handle an attended transfer event.
 
static void handle_blind_transfer (void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
 Handle a blind transfer event.
 
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.
 
static void init_queue (struct call_queue *q)
 Initialize Queue default values.
 
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'.
 
static int insert_penaltychange (const char *list_name, const char *content, const int linenum)
 Change queue penalty by adding rule.
 
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.
 
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.
 
static int load_module (void)
 Load the module.
 
static void load_realtime_queues (const char *queuename)
 
static int load_realtime_rules (void)
 Load queue rules from realtime.
 
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.
 
static int manager_queues_summary (struct mansession *s, const struct message *m)
 Summary of queue info via the AMI.
 
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.
 
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.
 
static void print_queue (struct mansession *s, int fd, struct call_queue *q)
 Print a single queue to AMI or the CLI.
 
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.
 
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.
 
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.
 
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.
 
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.
 
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.
 
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.
 
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.
 
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.
 
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.
 
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.
 
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.
 
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.
 
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.
 
static int reload (void)
 
static int reload_handler (int reload, struct ast_flags *mask, const char *queuename)
 The command center for all reload operations.
 
static void reload_queue_members (void)
 Reload dynamic queue members persisted into the astdb.
 
static int reload_queue_rules (int reload)
 Reload the rules defined in queuerules.conf.
 
static int reload_queues (int reload, struct ast_flags *mask, const char *queuename)
 reload the queues.conf file
 
static void reload_single_member (const char *memberdata, struct call_queue *q)
 reload information pertaining to a single member
 
static void reload_single_queue (struct ast_config *cfg, struct ast_flags *mask, const char *queuename)
 Reload information pertaining to a particular queue.
 
static int remove_from_queue (const char *queuename, const char *interface)
 Remove member from queue.
 
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.
 
static int ring_entry (struct queue_ent *qe, struct callattempt *tmp, int *busies)
 Part 2 of ring_one.
 
static int ring_one (struct queue_ent *qe, struct callattempt *outgoing, int *busies)
 Place a call to a queue member.
 
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.
 
static int rqm_exec (struct ast_channel *chan, const char *data)
 RemoveQueueMember application.
 
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.
 
static int say_periodic_announcement (struct queue_ent *qe, int ringing)
 Playback announcement to queued members if period has elapsed.
 
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.
 
static void set_duration_var (struct ast_channel *chan, const char *var_base, int64_t duration)
 
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
 
static void set_queue_variables (struct call_queue *q, struct ast_channel *chan)
 Set variables of queue.
 
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.
 
static int store_next_rr (struct queue_ent *qe, struct callattempt *outgoing)
 Search for best metric and add to Round Robbin queue.
 
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
 
static int update_queue (struct call_queue *q, struct member *member, int callcompletedinsl, time_t starttime)
 update the queue status
 
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.
 
static int upqm_exec (struct ast_channel *chan, const char *data)
 UnpauseQueueMember application.
 
static int valid_exit (struct queue_ent *qe, char digit)
 Check for valid exit from queue via goto.
 
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.
 
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.
 
static int word_in_list (const char *list, const char *word)
 Check if a given word is in a space-delimited list.
 

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "True Call Queueing" , .key = ASTERISK_GPL_KEY , .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
 
static const struct autopause autopausesmodes []
 
static struct ast_cli_entry cli_queue []
 
static struct stasis_subscriptiondevice_state_sub
 Subscription to device state change messages.
 
static int force_longest_waiting_caller
 queues.conf [general] option
 
static int log_caller_id_name
 queues.conf [general] option
 
static int log_membername_as_agent
 queues.conf [general] option
 
static int log_unpause_on_reason_change
 queues.conf [general] option
 
static int montype_default
 queues.conf [general] option
 
static int negative_penalty_invalid
 queues.conf [general] option
 
static struct ao2_containerpending_members
 
static const char *const pm_family = "Queue/PersistentMembers"
 Persistent Members astdb family.
 
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
 
struct { 
 
   enum queue_result   id 
 
   char *   text 
 
queue_results [] 
 
static struct ast_custom_function queueexists_function
 
static struct ast_custom_function queuegetchannel_function
 
static struct ast_custom_function queuemembercount_function
 
static struct ast_custom_function queuememberlist_function
 
static struct ast_custom_function queuememberpenalty_function
 
static struct ao2_containerqueues
 
static struct ast_custom_function queuevar_function
 
static struct ast_custom_function queuewaitingcount_function
 
static int realtime_reason_paused
 does realtime backend support reason_paused
 
static char * realtime_ringinuse_field
 name of the ringinuse field in the realtime database
 
static int realtime_rules
 queuerules.conf [general] option
 
static struct rule_lists rule_lists = AST_LIST_HEAD_INIT_VALUE
 
static int shared_lastcall
 queues.conf [general] option
 
static const struct strategy strategies []
 
static struct stasis_forwardtopic_forwarder
 
static int use_weight
 Records that one or more queues use weight.
 

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

◆ ANNOUNCEHOLDTIME_ONCE

#define ANNOUNCEHOLDTIME_ONCE   2

Definition at line 1925 of file app_queue.c.

◆ ANNOUNCEPOSITION_LIMIT

#define ANNOUNCEPOSITION_LIMIT   4

We not announce position more than <limit>

Definition at line 1943 of file app_queue.c.

◆ ANNOUNCEPOSITION_MORE_THAN

#define ANNOUNCEPOSITION_MORE_THAN   3

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

Definition at line 1942 of file app_queue.c.

◆ ANNOUNCEPOSITION_NO

#define ANNOUNCEPOSITION_NO   2

We don't announce position

Definition at line 1941 of file app_queue.c.

◆ ANNOUNCEPOSITION_YES

#define ANNOUNCEPOSITION_YES   1

We announce position

Definition at line 1940 of file app_queue.c.

◆ AST_MAX_WATCHERS

#define AST_MAX_WATCHERS   256

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

◆ DEFAULT_RETRY

#define DEFAULT_RETRY   5

Definition at line 1699 of file app_queue.c.

◆ DEFAULT_TIMEOUT

#define DEFAULT_TIMEOUT   15

Definition at line 1700 of file app_queue.c.

◆ MAX_CALL_ATTEMPT_BUCKETS

#define MAX_CALL_ATTEMPT_BUCKETS   353

Definition at line 2673 of file app_queue.c.

◆ MAX_PERIODIC_ANNOUNCEMENTS

#define MAX_PERIODIC_ANNOUNCEMENTS   10

The maximum periodic announcements we can have

Definition at line 1702 of file app_queue.c.

◆ MAX_QUEUE_BUCKETS

#define MAX_QUEUE_BUCKETS   53

Definition at line 1709 of file app_queue.c.

◆ QUEUE_EVENT_VARIABLES

#define QUEUE_EVENT_VARIABLES   3

Definition at line 1926 of file app_queue.c.

◆ QUEUE_PAUSED_DEVSTATE

#define QUEUE_PAUSED_DEVSTATE   AST_DEVICE_INUSE

Definition at line 3710 of file app_queue.c.

◆ queue_ref

#define queue_ref (   q)    ao2_bump(q)

Definition at line 2209 of file app_queue.c.

◆ queue_t_ref

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

Definition at line 2211 of file app_queue.c.

◆ queue_t_unref

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

Definition at line 2212 of file app_queue.c.

◆ QUEUE_UNKNOWN_PAUSED_DEVSTATE

#define QUEUE_UNKNOWN_PAUSED_DEVSTATE   AST_DEVICE_NOT_INUSE

Definition at line 3712 of file app_queue.c.

◆ QUEUE_UNPAUSED_DEVSTATE

#define QUEUE_UNPAUSED_DEVSTATE   AST_DEVICE_NOT_INUSE

Definition at line 3711 of file app_queue.c.

◆ queue_unref

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

Definition at line 2210 of file app_queue.c.

◆ queues_t_link

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

Definition at line 2213 of file app_queue.c.

◆ queues_t_unlink

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

Definition at line 2214 of file app_queue.c.

◆ RECHECK

#define RECHECK   1

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

Definition at line 1701 of file app_queue.c.

◆ RES_EXISTS

#define RES_EXISTS   (-1)

Entry already exists

Definition at line 1712 of file app_queue.c.

◆ RES_NOSUCHQUEUE

#define RES_NOSUCHQUEUE   (-3)

No such queue

Definition at line 1714 of file app_queue.c.

◆ RES_NOT_CALLER

#define RES_NOT_CALLER   (-5)

Caller not found

Definition at line 1716 of file app_queue.c.

◆ RES_NOT_DYNAMIC

#define RES_NOT_DYNAMIC   (-4)

Member is not dynamic

Definition at line 1715 of file app_queue.c.

◆ RES_OKAY

#define RES_OKAY   0

Action completed

Definition at line 1711 of file app_queue.c.

◆ RES_OUTOFMEMORY

#define RES_OUTOFMEMORY   (-2)

Out of memory

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

1576 {
1577 OPT_MARK_AS_ANSWERED = (1 << 0),
1578 OPT_GO_ON = (1 << 1),
1579 OPT_DATA_QUALITY = (1 << 2),
1580 OPT_CALLEE_GO_ON = (1 << 3),
1581 OPT_CALLEE_HANGUP = (1 << 4),
1582 OPT_CALLER_HANGUP = (1 << 5),
1583 OPT_IGNORE_CALL_FW = (1 << 6),
1584 OPT_IGNORE_CONNECTEDLINE = (1 << 7),
1585 OPT_CALLEE_PARK = (1 << 8),
1586 OPT_CALLER_PARK = (1 << 9),
1587 OPT_NO_RETRY = (1 << 10),
1588 OPT_RINGING = (1 << 11),
1589 OPT_RING_WHEN_RINGING = (1 << 12),
1590 OPT_CALLEE_TRANSFER = (1 << 13),
1591 OPT_CALLER_TRANSFER = (1 << 14),
1592 OPT_CALLEE_AUTOMIXMON = (1 << 15),
1593 OPT_CALLER_AUTOMIXMON = (1 << 16),
1594 OPT_CALLEE_AUTOMON = (1 << 17),
1595 OPT_CALLER_AUTOMON = (1 << 18),
1596 OPT_PREDIAL_CALLEE = (1 << 19),
1597 OPT_PREDIAL_CALLER = (1 << 20),
1598 OPT_MUSICONHOLD_CLASS = (1 << 21),
1599};
@ OPT_CALLER_AUTOMON
Definition app_queue.c:1595
@ OPT_CALLEE_PARK
Definition app_queue.c:1585
@ OPT_PREDIAL_CALLER
Definition app_queue.c:1597
@ OPT_GO_ON
Definition app_queue.c:1578
@ OPT_IGNORE_CONNECTEDLINE
Definition app_queue.c:1584
@ OPT_CALLEE_AUTOMON
Definition app_queue.c:1594
@ OPT_CALLEE_TRANSFER
Definition app_queue.c:1590
@ OPT_CALLEE_GO_ON
Definition app_queue.c:1580
@ OPT_MARK_AS_ANSWERED
Definition app_queue.c:1577
@ OPT_IGNORE_CALL_FW
Definition app_queue.c:1583
@ OPT_CALLER_PARK
Definition app_queue.c:1586
@ OPT_NO_RETRY
Definition app_queue.c:1587
@ OPT_DATA_QUALITY
Definition app_queue.c:1579
@ OPT_CALLER_HANGUP
Definition app_queue.c:1582
@ OPT_MUSICONHOLD_CLASS
Definition app_queue.c:1598
@ OPT_CALLEE_AUTOMIXMON
Definition app_queue.c:1592
@ OPT_CALLEE_HANGUP
Definition app_queue.c:1581
@ OPT_CALLER_AUTOMIXMON
Definition app_queue.c:1593
@ OPT_RINGING
Definition app_queue.c:1588
@ OPT_CALLER_TRANSFER
Definition app_queue.c:1591
@ OPT_PREDIAL_CALLEE
Definition app_queue.c:1596
@ OPT_RING_WHEN_RINGING
Definition app_queue.c:1589

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

1601 {
1606 /* note: this entry _MUST_ be the last one in the enum */
1608};
@ OPT_ARG_CALLEE_GO_ON
Definition app_queue.c:1602
@ OPT_ARG_PREDIAL_CALLEE
Definition app_queue.c:1603
@ OPT_ARG_MUSICONHOLD_CLASS
Definition app_queue.c:1605
@ OPT_ARG_PREDIAL_CALLER
Definition app_queue.c:1604
@ OPT_ARG_ARRAY_SIZE
Definition app_queue.c:1607

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

1651 {
1660};
@ QUEUE_STRATEGY_RINGALL
Definition app_queue.c:1652
@ QUEUE_STRATEGY_RRMEMORY
Definition app_queue.c:1656
@ QUEUE_STRATEGY_LINEAR
Definition app_queue.c:1657
@ QUEUE_STRATEGY_LEASTRECENT
Definition app_queue.c:1653
@ QUEUE_STRATEGY_RANDOM
Definition app_queue.c:1655
@ QUEUE_STRATEGY_FEWESTCALLS
Definition app_queue.c:1654
@ QUEUE_STRATEGY_RRORDERED
Definition app_queue.c:1659
@ QUEUE_STRATEGY_WRANDOM
Definition app_queue.c:1658

◆ anonymous enum

anonymous enum
Enumerator
QUEUE_AUTOPAUSE_OFF 
QUEUE_AUTOPAUSE_ON 
QUEUE_AUTOPAUSE_ALL 

Definition at line 1662 of file app_queue.c.

1662 {
1666};
@ QUEUE_AUTOPAUSE_ON
Definition app_queue.c:1664
@ QUEUE_AUTOPAUSE_OFF
Definition app_queue.c:1663
@ QUEUE_AUTOPAUSE_ALL
Definition app_queue.c:1665

◆ agent_complete_reason

Enumerator
CALLER 
AGENT 
TRANSFER 

Definition at line 6298 of file app_queue.c.

6298 {
6299 CALLER,
6300 AGENT,
6301 TRANSFER
6302};
@ AGENT
Definition app_queue.c:6300
@ CALLER
Definition app_queue.c:6299
@ TRANSFER
Definition app_queue.c:6301

◆ aqm_args

enum aqm_args
Enumerator
AQM_OPT_ARG_PAUSE_REASON 
AQM_OPT_ARG_ARRAY_SIZE 

Definition at line 1641 of file app_queue.c.

1641 {
1643 AQM_OPT_ARG_ARRAY_SIZE, /* Always last element of the enum */
1644};
@ AQM_OPT_ARG_ARRAY_SIZE
Definition app_queue.c:1643
@ AQM_OPT_ARG_PAUSE_REASON
Definition app_queue.c:1642

◆ aqm_flags

enum aqm_flags
Enumerator
AQMFLAG_PAUSED 
AQMFLAG_REASON 

Definition at line 1636 of file app_queue.c.

1636 {
1637 AQMFLAG_PAUSED = (1 << 1),
1638 AQMFLAG_REASON = (1 << 2),
1639};
@ AQMFLAG_REASON
Definition app_queue.c:1638
@ AQMFLAG_PAUSED
Definition app_queue.c:1637

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

1907 {
1908 QUEUE_EMPTY_PENALTY = (1 << 0),
1909 QUEUE_EMPTY_PAUSED = (1 << 1),
1910 QUEUE_EMPTY_INUSE = (1 << 2),
1911 QUEUE_EMPTY_RINGING = (1 << 3),
1912 QUEUE_EMPTY_UNAVAILABLE = (1 << 4),
1913 QUEUE_EMPTY_INVALID = (1 << 5),
1914 QUEUE_EMPTY_UNKNOWN = (1 << 6),
1915 QUEUE_EMPTY_WRAPUP = (1 << 7),
1916};
@ QUEUE_EMPTY_INVALID
Definition app_queue.c:1913
@ QUEUE_EMPTY_UNKNOWN
Definition app_queue.c:1914
@ QUEUE_EMPTY_PENALTY
Definition app_queue.c:1908
@ QUEUE_EMPTY_RINGING
Definition app_queue.c:1911
@ QUEUE_EMPTY_INUSE
Definition app_queue.c:1910
@ QUEUE_EMPTY_UNAVAILABLE
Definition app_queue.c:1912
@ QUEUE_EMPTY_WRAPUP
Definition app_queue.c:1915
@ QUEUE_EMPTY_PAUSED
Definition app_queue.c:1909

◆ member_properties

Enumerator
MEMBER_PENALTY 
MEMBER_RINGINUSE 

Definition at line 1918 of file app_queue.c.

1918 {
1919 MEMBER_PENALTY = 0,
1920 MEMBER_RINGINUSE = 1,
1921};
@ MEMBER_RINGINUSE
Definition app_queue.c:1920
@ MEMBER_PENALTY
Definition app_queue.c:1919

◆ queue_reload_mask

Enumerator
QUEUE_RELOAD_PARAMETERS 
QUEUE_RELOAD_MEMBER 
QUEUE_RELOAD_RULES 
QUEUE_RESET_STATS 

Definition at line 1668 of file app_queue.c.

1668 {
1669 QUEUE_RELOAD_PARAMETERS = (1 << 0),
1670 QUEUE_RELOAD_MEMBER = (1 << 1),
1671 QUEUE_RELOAD_RULES = (1 << 2),
1672 QUEUE_RESET_STATS = (1 << 3),
1673};
@ QUEUE_RELOAD_RULES
Definition app_queue.c:1671
@ QUEUE_RELOAD_MEMBER
Definition app_queue.c:1670
@ QUEUE_RESET_STATS
Definition app_queue.c:1672
@ QUEUE_RELOAD_PARAMETERS
Definition app_queue.c:1669

◆ queue_result

Enumerator
QUEUE_UNKNOWN 
QUEUE_TIMEOUT 
QUEUE_JOINEMPTY 
QUEUE_LEAVEEMPTY 
QUEUE_JOINUNAVAIL 
QUEUE_LEAVEUNAVAIL 
QUEUE_FULL 
QUEUE_CONTINUE 
QUEUE_WITHDRAW 

Definition at line 1777 of file app_queue.c.

1777 {
1778 QUEUE_UNKNOWN = 0,
1779 QUEUE_TIMEOUT = 1,
1780 QUEUE_JOINEMPTY = 2,
1781 QUEUE_LEAVEEMPTY = 3,
1784 QUEUE_FULL = 6,
1785 QUEUE_CONTINUE = 7,
1786 QUEUE_WITHDRAW = 8,
1787};
@ QUEUE_FULL
Definition app_queue.c:1784
@ QUEUE_UNKNOWN
Definition app_queue.c:1778
@ QUEUE_WITHDRAW
Definition app_queue.c:1786
@ QUEUE_CONTINUE
Definition app_queue.c:1785
@ QUEUE_LEAVEEMPTY
Definition app_queue.c:1781
@ QUEUE_LEAVEUNAVAIL
Definition app_queue.c:1783
@ QUEUE_JOINUNAVAIL
Definition app_queue.c:1782
@ QUEUE_JOINEMPTY
Definition app_queue.c:1780
@ QUEUE_TIMEOUT
Definition app_queue.c:1779

◆ queue_timeout_priority

Enumerator
TIMEOUT_PRIORITY_APP 
TIMEOUT_PRIORITY_CONF 

Definition at line 1804 of file app_queue.c.

1804 {
1807};
@ TIMEOUT_PRIORITY_CONF
Definition app_queue.c:1806
@ TIMEOUT_PRIORITY_APP
Definition app_queue.c:1805

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

10407{
10408 struct call_queue *q;
10409 struct ast_str *out = ast_str_alloca(512);
10410 struct ao2_container *sorted_queues;
10411
10412 struct ao2_iterator queue_iter;
10413 int found = 0;
10414
10415 if (argc != 2 && argc != 3) {
10416 return CLI_SHOWUSAGE;
10417 }
10418
10419 if (argc == 3) { /* specific queue */
10420 if ((q = find_load_queue_rt_friendly(argv[2]))) {
10421 ao2_lock(q);
10422 print_queue(s, fd, q);
10423 ao2_unlock(q);
10424 queue_unref(q);
10425 } else {
10426 ast_str_set(&out, 0, "No such queue: %s.", argv[2]);
10427 do_print(s, fd, ast_str_buffer(out));
10428 }
10429 return CLI_SUCCESS;
10430 }
10431
10432 if (ast_check_realtime("queues")) {
10433 /* This block is to find any queues which are defined in realtime but
10434 * which have not yet been added to the in-core container
10435 */
10436 struct ast_config *cfg = ast_load_realtime_multientry("queues", "name LIKE", "%", SENTINEL);
10437 if (cfg) {
10438 char *category = NULL;
10439 while ((category = ast_category_browse(cfg, category))) {
10440 const char *queuename = ast_variable_retrieve(cfg, category, "name");
10441 if (ast_strlen_zero(queuename)) {
10442 ast_log(LOG_WARNING, "Ignoring realtime queue with a NULL or empty 'name.'\n");
10443 continue;
10444 }
10445 if ((q = find_load_queue_rt_friendly(queuename))) {
10446 queue_t_unref(q, "Done with temporary pointer");
10447 }
10448 }
10449 ast_config_destroy(cfg);
10450 }
10451 }
10452
10453 /*
10454 * Snapping a copy of the container prevents having to lock both the queues container
10455 * and the queue itself at the same time. It also allows us to sort the entries.
10456 */
10457 sorted_queues = ao2_container_alloc_rbtree(AO2_ALLOC_OPT_LOCK_NOLOCK, 0, call_queue_sort_fn, NULL);
10458 if (!sorted_queues) {
10459 return CLI_SUCCESS;
10460 }
10461 if (ao2_container_dup(sorted_queues, queues, 0)) {
10462 ao2_ref(sorted_queues, -1);
10463 return CLI_SUCCESS;
10464 }
10465
10466 /*
10467 * No need to lock the container since it's temporary and static.
10468 * We also unlink the entries as we use them so the container is
10469 * empty when the iterator finishes. We can then just unref the container.
10470 */
10471 queue_iter = ao2_iterator_init(sorted_queues, AO2_ITERATOR_DONTLOCK | AO2_ITERATOR_UNLINK);
10472 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
10473 struct call_queue *realtime_queue = NULL;
10474 ao2_lock(q);
10475 /* This check is to make sure we don't print information for realtime
10476 * queues which have been deleted from realtime but which have not yet
10477 * been deleted from the in-core container. Only do this if we're not
10478 * looking for a specific queue.
10479 */
10480 if (q->realtime) {
10481 realtime_queue = find_load_queue_rt_friendly(q->name);
10482 if (!realtime_queue) {
10483 ao2_unlock(q);
10484 queue_t_unref(q, "Done with iterator");
10485 continue;
10486 }
10487 queue_t_unref(realtime_queue, "Queue is already in memory");
10488 }
10489
10490 found = 1;
10491 print_queue(s, fd, q);
10492
10493 ao2_unlock(q);
10494 queue_t_unref(q, "Done with iterator"); /* Unref the iterator's reference */
10495 }
10496 ao2_iterator_destroy(&queue_iter);
10497 ao2_ref(sorted_queues, -1);
10498 if (!found) {
10499 ast_str_set(&out, 0, "No queues.");
10500 do_print(s, fd, ast_str_buffer(out));
10501 }
10502 return CLI_SUCCESS;
10503}
static void print_queue(struct mansession *s, int fd, struct call_queue *q)
Print a single queue to AMI or the CLI.
static struct ao2_container * queues
Definition app_queue.c:2055
#define queue_t_unref(q, tag)
Definition app_queue.c:2212
#define queue_unref(q)
Definition app_queue.c:2210
static void do_print(struct mansession *s, int fd, const char *str)
direct output to manager or cli with proper terminator
static struct call_queue * find_load_queue_rt_friendly(const char *queuename)
Definition app_queue.c:4069
#define ast_log
Definition astobj2.c:42
int ao2_container_dup(struct ao2_container *dest, struct ao2_container *src, enum search_flags flags)
Copy all object references in the src container into the dest container.
@ AO2_ALLOC_OPT_LOCK_NOLOCK
Definition astobj2.h:367
#define ao2_t_iterator_next(iter, tag)
Definition astobj2.h:1909
@ AO2_ITERATOR_UNLINK
Definition astobj2.h:1863
@ AO2_ITERATOR_DONTLOCK
Assume that the ao2_container is already locked.
Definition astobj2.h:1852
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
#define ao2_container_alloc_rbtree(ao2_options, container_options, sort_fn, cmp_fn)
Allocate and initialize a red-black tree container.
Definition astobj2.h:1349
#define ao2_unlock(a)
Definition astobj2.h:729
#define ao2_lock(a)
Definition astobj2.h:717
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition astobj2.h:459
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
#define CLI_SHOWUSAGE
Definition cli.h:45
#define CLI_SUCCESS
Definition cli.h:44
#define SENTINEL
Definition compiler.h:87
char * ast_category_browse(struct ast_config *config, const char *prev_name)
Browse categories.
Definition extconf.c:3324
struct ast_config * ast_load_realtime_multientry(const char *family,...) attribute_sentinel
Retrieve realtime configuration.
int ast_check_realtime(const char *family)
Check if realtime engine is configured for family.
void ast_config_destroy(struct ast_config *cfg)
Destroys a config.
Definition extconf.c:1287
const char * ast_variable_retrieve(struct ast_config *config, const char *category, const char *variable)
#define LOG_WARNING
#define NULL
Definition resample.c:96
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
char *attribute_pure ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition strings.h:761
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:1999
unsigned int found
Definition app_queue.c:2000
const ast_string_field name
Definition app_queue.c:1983
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 12221 of file app_queue.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

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

7810{
7811 struct call_queue *q;
7812 struct member *new_member, *old_member;
7813 int res = RES_NOSUCHQUEUE;
7814
7815 /*! \note Ensure the appropriate realtime queue is loaded. Note that this
7816 * short-circuits if the queue is already in memory. */
7817 if (!(q = find_load_queue_rt_friendly(queuename))) {
7818 return res;
7819 }
7820
7821 ao2_lock(q);
7822 if ((old_member = interface_exists(q, interface)) == NULL) {
7824 new_member->dynamic = 1;
7825 if (reason_paused) {
7826 ast_copy_string(new_member->reason_paused, reason_paused, sizeof(new_member->reason_paused));
7827 }
7828 member_add_to_queue(q, new_member);
7829 queue_publish_member_blob(queue_member_added_type(), queue_member_blob_create(q, new_member));
7830
7831 if (is_member_available(q, new_member)) {
7833 }
7834
7835 ao2_ref(new_member, -1);
7836 new_member = NULL;
7837
7838 if (dump) {
7840 }
7841
7842 res = RES_OKAY;
7843 } else {
7844 res = RES_OUTOFMEMORY;
7845 }
7846 } else {
7847 ao2_ref(old_member, -1);
7848 res = RES_EXISTS;
7849 }
7850 ao2_unlock(q);
7851 queue_t_unref(q, "Expiring temporary reference");
7852
7853 return res;
7854}
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:3024
static struct member * interface_exists(struct call_queue *q, const char *interface)
Definition app_queue.c:7674
static void dump_queue_members(struct call_queue *pm_queue)
Dump all members in a specific queue to the database.
Definition app_queue.c:7701
static int is_member_available(struct call_queue *q, struct member *mem)
Definition app_queue.c:2765
#define RES_OUTOFMEMORY
Definition app_queue.c:1713
#define RES_NOSUCHQUEUE
Definition app_queue.c:1714
#define RES_OKAY
Definition app_queue.c:1711
static void member_add_to_queue(struct call_queue *queue, struct member *mem)
Definition app_queue.c:3720
static struct ast_json * queue_member_blob_create(struct call_queue *q, struct member *mem)
Definition app_queue.c:2549
#define RES_EXISTS
Definition app_queue.c:1712
static void queue_publish_member_blob(struct stasis_message_type *type, struct ast_json *blob)
Definition app_queue.c:2525
@ 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.
@ 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:1987
char interface[AST_CHANNEL_NAME]
Definition app_queue.c:1880
int dynamic
Definition app_queue.c:1888
char membername[80]
Definition app_queue.c:1885
int penalty
Definition app_queue.c:1886
int paused
Definition app_queue.c:1891
int wrapuptime
Definition app_queue.c:1895
char reason_paused[80]
Definition app_queue.c:1892
char state_interface[AST_CHANNEL_NAME]
Definition app_queue.c:1883

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

3902{
3903 struct call_queue *q;
3904
3905 if ((q = ao2_t_alloc(sizeof(*q), destroy_queue, "Allocate queue"))) {
3906 if (ast_string_field_init(q, 64)) {
3907 queue_t_unref(q, "String field allocation failed");
3908 return NULL;
3909 }
3910 ast_string_field_set(q, name, queuename);
3911 }
3912 return q;
3913}
static void destroy_queue(void *obj)
Free queue's member list then its string fields.
Definition app_queue.c:3886
#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.
#define ast_string_field_init(x, size)
Initialize a field pool and fields.

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

8576{
8577 int res=-1;
8578 char *parse, *tmp, *temppos = NULL, *reason = NULL;
8580 AST_APP_ARG(queuename);
8581 AST_APP_ARG(interface);
8582 AST_APP_ARG(penalty);
8584 AST_APP_ARG(membername);
8585 AST_APP_ARG(state_interface);
8586 AST_APP_ARG(wrapuptime);
8587 );
8588 int penalty = 0;
8589 int paused = 0;
8590 int wrapuptime;
8591 struct ast_flags flags = { 0 };
8592
8593 if (ast_strlen_zero(data)) {
8594 ast_log(LOG_WARNING, "AddQueueMember requires an argument (queuename[,interface[,penalty[,options[,membername[,stateinterface][,wrapuptime]]]]])\n");
8595 return -1;
8596 }
8597
8598 parse = ast_strdupa(data);
8599
8601
8602 if (args.options) {
8603 char *opts[AQM_OPT_ARG_ARRAY_SIZE] = { NULL, };
8604 ast_app_parse_options(aqm_opts, &flags, opts, args.options);
8606 paused = 1;
8608 reason = ast_strdupa(opts[AQM_OPT_ARG_PAUSE_REASON]);
8609 }
8610 }
8611 }
8612
8613 if (ast_strlen_zero(args.interface)) {
8614 args.interface = ast_strdupa(ast_channel_name(chan));
8615 temppos = strrchr(args.interface, '-');
8616 if (temppos) {
8617 *temppos = '\0';
8618 }
8619 }
8620
8621 if (!ast_strlen_zero(args.penalty)) {
8622 if ((sscanf(args.penalty, "%30d", &penalty) != 1) || penalty < 0) {
8623 ast_log(LOG_WARNING, "Penalty '%s' is invalid, must be an integer >= 0\n", args.penalty);
8624 penalty = 0;
8625 }
8626 }
8627
8628 if (!ast_strlen_zero(args.wrapuptime)) {
8629 tmp = args.wrapuptime;
8630 ast_strip(tmp);
8631 wrapuptime = atoi(tmp);
8632 if (wrapuptime < 0) {
8633 wrapuptime = 0;
8634 }
8635 } else {
8636 wrapuptime = 0;
8637 }
8638
8639 switch (add_to_queue(args.queuename, args.interface, args.membername, penalty, paused, queue_persistent_members, args.state_interface, reason, wrapuptime)) {
8640 case RES_OKAY:
8641 if (ast_strlen_zero(args.membername) || !log_membername_as_agent) {
8642 ast_queue_log(args.queuename, ast_channel_uniqueid(chan), args.interface, "ADDMEMBER", "%s", paused ? "PAUSED" : "");
8643 } else {
8644 ast_queue_log(args.queuename, ast_channel_uniqueid(chan), args.membername, "ADDMEMBER", "%s", paused ? "PAUSED" : "");
8645 }
8646 ast_log(LOG_NOTICE, "Added interface '%s' to queue '%s'\n", args.interface, args.queuename);
8647 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "ADDED");
8648 res = 0;
8649 break;
8650 case RES_EXISTS:
8651 ast_log(LOG_WARNING, "Unable to add interface '%s' to queue '%s': Already there\n", args.interface, args.queuename);
8652 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "MEMBERALREADY");
8653 res = 0;
8654 break;
8655 case RES_NOSUCHQUEUE:
8656 ast_log(LOG_WARNING, "Unable to add interface to queue '%s': No such queue\n", args.queuename);
8657 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "NOSUCHQUEUE");
8658 res = 0;
8659 break;
8660 case RES_OUTOFMEMORY:
8661 ast_log(LOG_ERROR, "Out of memory adding interface %s to queue %s\n", args.interface, args.queuename);
8662 break;
8663 }
8664
8665 return res;
8666}
static int queue_persistent_members
queues.conf [general] option
Definition app_queue.c:1736
static int log_membername_as_agent
queues.conf [general] option
Definition app_queue.c:1760
static const struct ast_app_option aqm_opts[128]
Definition app_queue.c:1649
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:7809
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition astmm.h:298
const char * ast_channel_name(const struct ast_channel *chan)
const char * ast_channel_uniqueid(const struct ast_channel *chan)
#define AST_APP_ARG(name)
Define an application argument.
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application's arguments.
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the 'standard' argument separation process for an application.
int ast_app_parse_options(const struct ast_app_option *options, struct ast_flags *flags, char **args, char *optstr)
Parses a string containing application options and sets flags/arguments.
Definition main/app.c:3066
void ast_queue_log(const char *queuename, const char *callid, const char *agent, const char *event, const char *fmt,...)
Definition logger.c:957
#define LOG_ERROR
#define LOG_NOTICE
int pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value)
Add a variable to the channel variable stack, removing the most recently set value for the same name.
static struct @522 args
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:220
unsigned int flags
Definition utils.h:221
static struct test_options options
#define ast_test_flag(p, flag)
Definition utils.h:64

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

◆ autopause2int()

static int autopause2int ( const char *  autopause)
static

Definition at line 2102 of file app_queue.c.

2103{
2104 int x;
2105 /*This 'double check' that default value is OFF */
2107 return QUEUE_AUTOPAUSE_OFF;
2108 }
2109
2110 /*This 'double check' is to ensure old values works */
2111 if(ast_true(autopause)) {
2112 return QUEUE_AUTOPAUSE_ON;
2113 }
2114
2115 for (x = 0; x < ARRAY_LEN(autopausesmodes); x++) {
2116 if (!strcasecmp(autopause, autopausesmodes[x].name)) {
2117 return autopausesmodes[x].autopause;
2118 }
2119 }
2120
2121 /*This 'double check' that default value is OFF */
2122 return QUEUE_AUTOPAUSE_OFF;
2123}
static const struct autopause autopausesmodes[]
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is "true"....
Definition utils.c:2235
int autopause
Definition app_queue.c:1691
#define ARRAY_LEN(a)
Definition utils.h:706

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

6221{
6222 /* disregarding penalty on too few members? */
6223 int membercount = ao2_container_count(q->members);
6224 unsigned char usepenalty = (membercount <= q->penaltymemberslimit) ? 0 : 1;
6225 int penalty = mem->penalty;
6226
6227 if (usepenalty) {
6228 if (qe->raise_penalty != INT_MAX && penalty < qe->raise_penalty && !(qe->raise_respect_min && qe->min_penalty != INT_MAX && penalty < qe->min_penalty)) {
6229 /* Low penalty is raised up to the current minimum */
6230 penalty = qe->raise_penalty;
6231 }
6232 if ((qe->max_penalty != INT_MAX && penalty > qe->max_penalty) ||
6233 (qe->min_penalty != INT_MAX && penalty < qe->min_penalty)) {
6234 return -1;
6235 }
6236 } else {
6237 ast_debug(1, "Disregarding penalty, %d members and %d in penaltymemberslimit.\n",
6238 membercount, q->penaltymemberslimit);
6239 }
6240
6241 switch (q->strategy) {
6243 /* Everyone equal, except for penalty */
6244 tmp->metric = penalty * 1000000 * usepenalty;
6245 break;
6247 if (pos < qe->linpos) {
6248 tmp->metric = 1000 + pos;
6249 } else {
6250 if (pos > qe->linpos) {
6251 /* Indicate there is another priority */
6252 qe->linwrapped = 1;
6253 }
6254 tmp->metric = pos;
6255 }
6256 tmp->metric += penalty * 1000000 * usepenalty;
6257 break;
6260 pos = mem->queuepos;
6261 if (pos < q->rrpos) {
6262 tmp->metric = 1000 + pos;
6263 } else {
6264 if (pos > q->rrpos) {
6265 /* Indicate there is another priority */
6266 q->wrapped = 1;
6267 }
6268 tmp->metric = pos;
6269 }
6270 tmp->metric += penalty * 1000000 * usepenalty;
6271 break;
6273 tmp->metric = ast_random() % 1000;
6274 tmp->metric += penalty * 1000000 * usepenalty;
6275 break;
6277 tmp->metric = ast_random() % ((1 + penalty) * 1000);
6278 break;
6280 tmp->metric = mem->calls;
6281 tmp->metric += penalty * 1000000 * usepenalty;
6282 break;
6284 if (!mem->lastcall) {
6285 tmp->metric = 0;
6286 } else {
6287 tmp->metric = 1000000 - (time(NULL) - mem->lastcall);
6288 }
6289 tmp->metric += penalty * 1000000 * usepenalty;
6290 break;
6291 default:
6292 ast_log(LOG_WARNING, "Can't calculate metric for unknown strategy %d\n", q->strategy);
6293 break;
6294 }
6295 return 0;
6296}
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:2041
int penaltymemberslimit
Definition app_queue.c:2025
unsigned int wrapped
Definition app_queue.c:1993
int queuepos
Definition app_queue.c:1893
time_t lastcall
Definition app_queue.c:1897
int calls
Definition app_queue.c:1887
int raise_respect_min
Definition app_queue.c:1865
int max_penalty
Definition app_queue.c:1862
int raise_penalty
Definition app_queue.c:1864
int min_penalty
Definition app_queue.c:1863
int linwrapped
Definition app_queue.c:1867
long int ast_random(void)
Definition utils.c:2348

References ao2_container_count(), ast_debug, ast_log, ast_random(), member::calls, member::lastcall, queue_ent::linpos, queue_ent::linwrapped, LOG_WARNING, queue_ent::max_penalty, call_queue::members, callattempt::metric, queue_ent::min_penalty, NULL, member::penalty, call_queue::penaltymemberslimit, QUEUE_STRATEGY_FEWESTCALLS, QUEUE_STRATEGY_LEASTRECENT, QUEUE_STRATEGY_LINEAR, QUEUE_STRATEGY_RANDOM, QUEUE_STRATEGY_RINGALL, QUEUE_STRATEGY_RRMEMORY, QUEUE_STRATEGY_RRORDERED, QUEUE_STRATEGY_WRANDOM, member::queuepos, queue_ent::raise_penalty, queue_ent::raise_respect_min, 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 4621 of file app_queue.c.

4622{
4623 if (doomed->member) {
4624 ao2_ref(doomed->member, -1);
4625 }
4627 ast_free(doomed->orig_chan_name);
4628 ast_free(doomed);
4629}
#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:2058
struct ast_party_connected_line connected
Definition app_queue.c:1829
char * orig_chan_name
Definition app_queue.c:1840
struct member * member
Definition app_queue.c:1827

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

4834{
4835 struct member *memberp = call->member;
4836 int wrapuptime;
4837
4838 if (memberp->paused) {
4839 ast_debug(1, "%s paused, can't receive call\n", call->interface);
4840 return 0;
4841 }
4842
4843 if (!memberp->ringinuse && !member_status_available(memberp->status)) {
4844 ast_debug(1, "%s not available, can't receive call\n", call->interface);
4845 return 0;
4846 }
4847
4848 if (memberp->lastqueue) {
4849 wrapuptime = get_wrapuptime(memberp->lastqueue, memberp);
4850 } else {
4851 wrapuptime = get_wrapuptime(qe->parent, memberp);
4852 }
4853 if (wrapuptime && (time(NULL) - memberp->lastcall) < wrapuptime) {
4854 ast_debug(1, "Wrapuptime not yet expired on queue %s for %s\n",
4855 (memberp->lastqueue ? memberp->lastqueue->name : qe->parent->name),
4856 call->interface);
4857 return 0;
4858 }
4859
4860 if (use_weight && compare_weight(qe->parent, memberp)) {
4861 ast_debug(1, "Priority queue delaying call to %s:%s\n",
4862 qe->parent->name, call->interface);
4863 return 0;
4864 }
4865
4867 ast_debug(1, "Another caller was waiting longer; delaying call to %s:%s\n",
4868 qe->parent->name, call->interface);
4869 return 0;
4870 }
4871
4872 if (!memberp->ringinuse) {
4873 struct member *mem;
4874
4876
4877 mem = ao2_find(pending_members, memberp,
4879 if (mem) {
4880 /*
4881 * If found that means this member is currently being attempted
4882 * from another calling thread, so stop trying from this thread
4883 */
4884 ast_debug(1, "%s has another call trying, can't receive call\n",
4885 call->interface);
4886 ao2_ref(mem, -1);
4888 return 0;
4889 }
4890
4891 /*
4892 * If not found add it to the container so another queue
4893 * won't attempt to call this member at the same time.
4894 */
4895 ast_debug(3, "Add %s to pending_members\n", memberp->membername);
4896 ao2_link(pending_members, memberp);
4898
4899 /*
4900 * The queue member is available. Get current status to be sure
4901 * because the device state and extension state callbacks may
4902 * not have updated the status yet.
4903 */
4905 ast_debug(1, "%s actually not available, can't receive call\n",
4906 call->interface);
4907 pending_members_remove(memberp);
4908 return 0;
4909 }
4910 }
4911
4912 return 1;
4913}
static int is_longest_waiting_caller(struct queue_ent *caller, struct member *member)
Definition app_queue.c:4750
static int get_wrapuptime(struct call_queue *q, struct member *member)
Return wrapuptime.
Definition app_queue.c:2145
static int compare_weight(struct call_queue *rq, struct member *member)
Definition app_queue.c:4716
static struct ao2_container * pending_members
Definition app_queue.c:2672
static int force_longest_waiting_caller
queues.conf [general] option
Definition app_queue.c:1763
static void pending_members_remove(struct member *mem)
Definition app_queue.c:2723
static int get_queue_member_status(struct member *cur)
Return the current state of a member.
Definition app_queue.c:3009
static int use_weight
Records that one or more queues use weight.
Definition app_queue.c:1739
static int member_status_available(int status)
Definition app_queue.c:4819
#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)
int status
Definition app_queue.c:1890
unsigned int ringinuse
Definition app_queue.c:1904
struct call_queue * lastqueue
Definition app_queue.c:1900
struct call_queue * parent
Definition app_queue.c:1845

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

7863{
7864 struct call_queue *q;
7865 struct queue_ent *current, *prev = NULL, *caller_qe = NULL;
7866 int res = RES_NOSUCHQUEUE;
7867
7868 /*! \note Ensure the appropriate realtime queue is loaded. Note that this
7869 * short-circuits if the queue is already in memory. */
7871 return res;
7872 }
7873
7874 ao2_lock(q);
7876 for (current = q->head; current; current = current->next) {
7877 if (strcmp(ast_channel_name(current->chan), caller) == 0) {
7878 ast_debug(1, "%s Caller new priority %d in queue %s\n",
7879 caller, priority, queuename);
7880 current->prio = priority;
7881 if (immediate) {
7882 /* This caller is being immediately moved in the queue so remove them */
7883 if (prev) {
7884 prev->next = current->next;
7885 } else {
7886 q->head = current->next;
7887 }
7889 /* The position for all callers is not recalculated in here as it will
7890 * be updated when the moved caller is inserted back into the queue
7891 */
7892 }
7893 res = RES_OKAY;
7894 break;
7895 } else if (immediate) {
7896 prev = current;
7897 }
7898 }
7899
7900 if (caller_qe) {
7901 int inserted = 0, pos = 0;
7902
7903 /* If a caller queue entry exists, we are applying their priority immediately
7904 * and have to reinsert them at the correct position.
7905 */
7906 prev = NULL;
7907 current = q->head;
7908 while (current) {
7909 if (!inserted && (caller_qe->prio > current->prio)) {
7910 insert_entry(q, prev, caller_qe, &pos);
7911 inserted = 1;
7912 }
7913
7914 /* We always update the position as it may have changed */
7915 current->pos = ++pos;
7916
7917 /* Move to the next caller in the queue */
7918 prev = current;
7919 current = current->next;
7920 }
7921
7922 if (!inserted) {
7923 insert_entry(q, prev, caller_qe, &pos);
7924 }
7925 }
7926
7927 ao2_unlock(q);
7928 return res;
7929}
#define RES_NOT_CALLER
Definition app_queue.c:1716
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:2243
static int priority
size_t current
struct queue_ent * head
Definition app_queue.c:2042
time_t start
Definition app_queue.c:1868
struct queue_ent * next
Definition app_queue.c:1876

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, RES_OKAY, and queue_ent::start.

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

3211{
3212 q->holdtime = 0;
3213 q->callscompleted = 0;
3214 q->callsabandoned = 0;
3215 q->callscompletedinsl = 0;
3216 q->callsabandonedinsl = 0;
3217 q->talktime = 0;
3218
3219 if (q->members) {
3220 struct member *mem;
3221 struct ao2_iterator mem_iter = ao2_iterator_init(q->members, 0);
3222 while ((mem = ao2_iterator_next(&mem_iter))) {
3223 mem->calls = 0;
3224 mem->callcompletedinsl = 0;
3225 mem->lastcall = 0;
3226 mem->starttime = 0;
3227 ao2_ref(mem, -1);
3228 }
3229 ao2_iterator_destroy(&mem_iter);
3230 }
3231}
#define ao2_iterator_next(iter)
Definition astobj2.h:1911
int callsabandoned
Definition app_queue.c:2017
int callscompleted
Definition app_queue.c:2016
int callsabandonedinsl
Definition app_queue.c:2018
int callscompletedinsl
Definition app_queue.c:2020
time_t starttime
Definition app_queue.c:1896
int callcompletedinsl
Definition app_queue.c:1894

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

10242{
10243 struct call_queue *q;
10244 struct ao2_iterator queue_iter;
10245
10246 queue_iter = ao2_iterator_init(queues, 0);
10247 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
10248 ao2_lock(q);
10249 if (ast_strlen_zero(queuename) || !strcasecmp(q->name, queuename))
10250 clear_queue(q);
10251 ao2_unlock(q);
10252 queue_t_unref(q, "Done with iterator");
10253 }
10254 ao2_iterator_destroy(&queue_iter);
10255 return 0;
10256}
static void clear_queue(struct call_queue *q)
Definition app_queue.c:3210

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

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

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

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

11510{
11511 /* 0 - queue; 1 - pause; 2 - member; 3 - <interface>; 4 - queue; 5 - <queue>; 6 - reason; 7 - <reason> */
11512 switch (pos) {
11513 case 3: /* Don't attempt to complete name of interface (infinite possibilities) */
11514 return NULL;
11515 case 4: /* only one possible match, "queue" */
11516 return state == 0 ? ast_strdup("queue") : NULL;
11517 case 5: /* <queue> */
11518 return complete_queue(line, word, pos, state, 0);
11519 case 6: /* "reason" */
11520 return state == 0 ? ast_strdup("reason") : NULL;
11521 case 7: /* Can't autocomplete a reason, since it's 100% customizeable */
11522 return NULL;
11523 default:
11524 return NULL;
11525 }
11526}

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

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

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

11705{
11706 int which = 0;
11707 struct rule_list *rl_iter;
11708 int wordlen = strlen(word);
11709 char *ret = NULL;
11710 if (pos != 3) /* Wha? */ {
11711 return NULL;
11712 }
11713
11715 AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) {
11716 if (!strncasecmp(word, rl_iter->name, wordlen) && ++which > state) {
11717 ret = ast_strdup(rl_iter->name);
11718 break;
11719 }
11720 }
11722
11723 return ret;
11724}
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
#define AST_LIST_LOCK(head)
Locks a list.
Definition linkedlists.h:40
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
char name[80]
Definition app_queue.c:2048
struct rule_list::@57 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 11583 of file app_queue.c.

11584{
11585 /* 0 - queue; 1 - set; 2 - penalty/ringinuse; 3 - <value>; 4 - on; 5 - <member>; 6 - in; 7 - <queue>;*/
11586 switch (pos) {
11587 case 4:
11588 if (state == 0) {
11589 return ast_strdup("on");
11590 } else {
11591 return NULL;
11592 }
11593 case 6:
11594 if (state == 0) {
11595 return ast_strdup("in");
11596 } else {
11597 return NULL;
11598 }
11599 case 7:
11600 return complete_queue(line, word, pos, state, 0);
11601 default:
11602 return NULL;
11603 }
11604}

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

10615{
10616 if (pos == 2) {
10617 return complete_queue(line, word, pos, state, 0);
10618 }
10619 return NULL;
10620}

References complete_queue(), and NULL.

Referenced by queue_show().

◆ compress_char()

static int compress_char ( const char  c)
static

Definition at line 3069 of file app_queue.c.

3070{
3071 if (c < 32) {
3072 return 0;
3073 } else if (c > 96) {
3074 return c - 64;
3075 }
3076 return c - 32;
3077}
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 2936 of file app_queue.c.

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

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

Referenced by context_included(), and extension_state_cb().

◆ copy_rules()

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

Copy rule from global list into specified queue.

Definition at line 8703 of file app_queue.c.

8704{
8705 struct penalty_rule *pr_iter;
8706 struct rule_list *rl_iter;
8707 const char *tmp = ast_strlen_zero(rulename) ? qe->parent->defaultrule : rulename;
8709 AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) {
8710 if (!strcasecmp(rl_iter->name, tmp)) {
8711 break;
8712 }
8713 }
8714 if (rl_iter) {
8715 AST_LIST_TRAVERSE(&rl_iter->rules, pr_iter, list) {
8716 struct penalty_rule *new_pr = ast_calloc(1, sizeof(*new_pr));
8717 if (!new_pr) {
8718 ast_log(LOG_ERROR, "Memory allocation error when copying penalty rules! Aborting!\n");
8719 break;
8720 }
8721 new_pr->time = pr_iter->time;
8722 new_pr->max_value = pr_iter->max_value;
8723 new_pr->min_value = pr_iter->min_value;
8724 new_pr->raise_value = pr_iter->raise_value;
8725 new_pr->max_relative = pr_iter->max_relative;
8726 new_pr->min_relative = pr_iter->min_relative;
8727 new_pr->raise_relative = pr_iter->raise_relative;
8728 AST_LIST_INSERT_TAIL(&qe->qe_rules, new_pr, list);
8729 }
8730 }
8732}
#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.
const ast_string_field defaultrule
Definition app_queue.c:1983
struct penalty_rule::@53 list
struct queue_ent::@52 qe_rules
struct rule_list::@56 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 3024 of file app_queue.c.

3025{
3026 struct member *cur;
3027
3028 if ((cur = ao2_alloc(sizeof(*cur), destroy_queue_member_cb))) {
3029 cur->ringinuse = ringinuse;
3030 cur->penalty = penalty;
3031 cur->paused = paused;
3032 cur->wrapuptime = wrapuptime;
3033 if (paused) {
3034 time(&cur->lastpause); /* Update time of last pause */
3035 }
3036 time(&cur->logintime);
3037 ast_copy_string(cur->interface, interface, sizeof(cur->interface));
3040 } else {
3042 }
3044 ast_copy_string(cur->membername, membername, sizeof(cur->membername));
3045 } else {
3046 ast_copy_string(cur->membername, interface, sizeof(cur->membername));
3047 }
3048 if (!strchr(cur->interface, '/')) {
3049 ast_log(LOG_WARNING, "No location at interface '%s'\n", interface);
3050 }
3051 if (!strncmp(cur->state_interface, "hint:", 5)) {
3052 char *tmp = ast_strdupa(cur->state_interface), *context = tmp;
3053 char *exten = strsep(&context, "@") + 5;
3054
3055 ast_copy_string(cur->state_exten, exten, sizeof(cur->state_exten));
3056 ast_copy_string(cur->state_context, S_OR(context, "default"), sizeof(cur->state_context));
3057
3059 } else {
3060 cur->state_id = -1;
3061 }
3062 cur->status = get_queue_member_status(cur);
3063 }
3064
3065 return cur;
3066}
static int extension_state_cb(const char *context, const char *exten, struct ast_state_cb_info *info, void *data)
Definition app_queue.c:2965
static void destroy_queue_member_cb(void *obj)
Definition app_queue.c:3014
char * strsep(char **str, const char *delims)
#define ao2_alloc(data_size, destructor_fn)
Definition astobj2.h:409
int ast_extension_state_add(const char *context, const char *exten, ast_state_cb_type change_cb, void *data)
Add watcher for extension states.
Definition pbx.c:3844
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one.
Definition strings.h:80
time_t logintime
Definition app_queue.c:1899
char state_exten[AST_MAX_EXTENSION]
Definition app_queue.c:1881
char state_context[AST_MAX_CONTEXT]
Definition app_queue.c:1882
int state_id
Definition app_queue.c:1884
time_t lastpause
Definition app_queue.c:1898

References ao2_alloc, ast_copy_string(), ast_extension_state_add(), ast_log, ast_strdupa, ast_strlen_zero(), 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 3886 of file app_queue.c.

3887{
3888 struct call_queue *q = obj;
3889 int i;
3890
3891 free_members(q, 1);
3893 for (i = 0; i < MAX_PERIODIC_ANNOUNCEMENTS; i++) {
3894 if (q->sound_periodicannounce[i]) {
3896 }
3897 }
3898 ao2_ref(q->members, -1);
3899}
#define MAX_PERIODIC_ANNOUNCEMENTS
Definition app_queue.c:1702
static void free_members(struct call_queue *q, int all)
Iterate through queue's member list and delete them.
Definition app_queue.c:3870
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
struct ast_str * sound_periodicannounce[MAX_PERIODIC_ANNOUNCEMENTS]
Definition app_queue.c:1985

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

3015{
3016 struct member *mem = obj;
3017
3018 if (mem->state_id != -1) {
3020 }
3021}
int ast_extension_state_del(int id, ast_state_cb_type change_cb)
Deletes a state change watcher by ID.
Definition pbx.c:3877

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

Referenced by create_queue_member().

◆ device_state_cb()

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

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

Definition at line 2800 of file app_queue.c.

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

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

4804{
4805 o->stillgoing = 0;
4806 ast_hangup(o->chan);
4808 o->chan = NULL;
4809}
void ast_hangup(struct ast_channel *chan)
Hang up a channel.
Definition channel.c:2538
struct ast_channel * chan
Definition app_queue.c:1824
unsigned int stillgoing
Definition app_queue.c:1837

References ast_hangup(), NULL, pending_members_remove(), and queue_ent::start.

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

10289{
10290 if (s) {
10291 astman_append(s, "%s\r\n", str);
10292 } else {
10293 ast_cli(fd, "%s\n", str);
10294 }
10295}
const char * str
Definition app_jack.c:150
void ast_cli(int fd, const char *fmt,...)
Definition clicompat.c:6
void astman_append(struct mansession *s, const char *fmt,...)
Definition manager.c:1903

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

Referenced by __queues_show(), and print_queue().

◆ dump_queue_members()

static void dump_queue_members ( struct call_queue pm_queue)
static

Dump all members in a specific queue to the database.

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

Definition at line 7701 of file app_queue.c.

7702{
7703 struct member *cur_member;
7704 struct ast_str *value;
7705 struct ao2_iterator mem_iter;
7706
7707 if (!pm_queue) {
7708 return;
7709 }
7710
7711 /* 4K is a reasonable default for most applications, but we grow to
7712 * accommodate more if necessary. */
7713 if (!(value = ast_str_create(4096))) {
7714 return;
7715 }
7716
7717 mem_iter = ao2_iterator_init(pm_queue->members, 0);
7718 while ((cur_member = ao2_iterator_next(&mem_iter))) {
7719 if (!cur_member->dynamic) {
7720 ao2_ref(cur_member, -1);
7721 continue;
7722 }
7723
7724 ast_str_append(&value, 0, "%s%s;%d;%d;%s;%s;%s;%d",
7725 ast_str_strlen(value) ? "|" : "",
7726 cur_member->interface,
7727 cur_member->penalty,
7728 cur_member->paused,
7729 cur_member->membername,
7730 cur_member->state_interface,
7731 cur_member->reason_paused,
7732 cur_member->wrapuptime);
7733
7734 ao2_ref(cur_member, -1);
7735 }
7736 ao2_iterator_destroy(&mem_iter);
7737
7738 if (ast_str_strlen(value) && !cur_member) {
7739 if (ast_db_put(pm_family, pm_queue->name, ast_str_buffer(value))) {
7740 ast_log(LOG_WARNING, "failed to create persistent dynamic entry!\n");
7741 }
7742 } else {
7743 /* Delete the entry if the queue is empty or there is an error */
7744 ast_db_del(pm_family, pm_queue->name);
7745 }
7746
7747 ast_free(value);
7748}
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
size_t attribute_pure ast_str_strlen(const struct ast_str *buf)
Returns the current length of the string stored within buf.
Definition strings.h:730
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
Definition strings.h:659
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 7036 of file app_queue.c.

7037{
7038 struct queue_end_bridge *qeb = data;
7039 struct call_queue *q = qeb->q;
7040 struct ast_channel *chan = qeb->chan;
7041 int64_t answered_time_ms;
7042
7043 if (ao2_ref(qeb, -1) == 1) {
7044 set_queue_variables(q, chan);
7045
7046 /* Match Dial() timing variables */
7047 ast_channel_lock(chan);
7049 answered_time_ms = ast_tvdiff_ms(ast_tvnow(), qeb->start_time);
7050 set_duration_var(chan, "ANSWEREDTIME", answered_time_ms);
7051 set_duration_var(chan, "DIALEDTIME", ast_channel_get_duration_ms(chan));
7053 ast_channel_unlock(chan);
7054
7055 /* This unrefs the reference we made in try_calling when we allocated qeb */
7056 queue_t_unref(q, "Expire bridge_config reference");
7057 }
7058}
static void set_queue_variables(struct call_queue *q, struct ast_channel *chan)
Set variables of queue.
Definition app_queue.c:2217
static void set_duration_var(struct ast_channel *chan, const char *var_base, int64_t duration)
Definition app_queue.c:7016
#define ast_channel_lock(chan)
Definition channel.h:2982
int64_t ast_channel_get_duration_ms(struct ast_channel *chan)
Obtain how long it's been, in milliseconds, since the channel was created.
Definition channel.c:2818
#define ast_channel_unlock(chan)
Definition channel.h:2983
void ast_channel_stage_snapshot_done(struct ast_channel *chan)
Clear flag to indicate channel snapshot is being staged, and publish snapshot.
void ast_channel_stage_snapshot(struct ast_channel *chan)
Set flag to indicate channel snapshot is being staged.
Main Channel structure associated with a channel.
struct call_queue * q
Definition app_queue.c:7007
struct ast_channel * chan
Definition app_queue.c:7008
struct timeval start_time
Definition app_queue.c:7009
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 ao2_ref, ast_channel_get_duration_ms(), ast_channel_lock, ast_channel_stage_snapshot(), ast_channel_stage_snapshot_done(), ast_channel_unlock, ast_tvdiff_ms(), ast_tvnow(), queue_end_bridge::chan, queue_end_bridge::q, queue_t_unref, set_duration_var(), set_queue_variables(), and queue_end_bridge::start_time.

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

7030{
7031 struct queue_end_bridge *qeb = bconfig->end_bridge_callback_data;
7032 ao2_ref(qeb, +1);
7033 qeb->chan = originator;
7034}
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 7087 of file app_queue.c.

7089{
7090 const char *m = input;
7091 char escaped[size];
7092 char *p;
7093
7094 for (p = escaped; p < escaped + size - 1; p++, m++) {
7095 switch (*m) {
7096 case '^':
7097 if (*(m + 1) == '{') {
7098 *p = '$';
7099 }
7100 break;
7101 case ',':
7102 *p++ = '\\';
7103 /* Fall through */
7104 default:
7105 *p = *m;
7106 }
7107 if (*m == '\0')
7108 break;
7109 }
7110
7111 if (p == escaped + size) {
7112 escaped[size - 1] = '\0';
7113 }
7114
7115 pbx_substitute_variables_helper(chan, escaped, output, size - 1);
7116}
void pbx_substitute_variables_helper(struct ast_channel *c, const char *cp1, char *cp2, int count)
Definition ael_main.c:211

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

2966{
2967 struct ao2_iterator miter, qiter;
2968 struct member *m;
2969 struct call_queue *q;
2970 int state = info->exten_state;
2971 int found = 0, device_state = extensionstate2devicestate(state);
2972
2973 /* only interested in extension state updates involving device states */
2974 if (info->reason != AST_HINT_UPDATE_DEVICE) {
2975 return 0;
2976 }
2977
2978 qiter = ao2_iterator_init(queues, 0);
2979 while ((q = ao2_t_iterator_next(&qiter, "Iterate through queues"))) {
2980 ao2_lock(q);
2981
2982 miter = ao2_iterator_init(q->members, 0);
2983 for (; (m = ao2_iterator_next(&miter)); ao2_ref(m, -1)) {
2984 if (!strcmp(m->state_exten, exten) &&
2986 /* context could be included in m->state_context. We need to check. */
2987 found = 1;
2988 update_status(q, m, device_state);
2989 }
2990 }
2991 ao2_iterator_destroy(&miter);
2992
2993 ao2_unlock(q);
2994 queue_t_unref(q, "Done with iterator");
2995 }
2996 ao2_iterator_destroy(&qiter);
2997
2998 if (found) {
2999 ast_debug(1, "Extension '%s@%s' changed to state '%d' (%s)\n", exten, context, device_state, ast_devstate2str(device_state));
3000 } else {
3001 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",
3002 exten, context, device_state, ast_devstate2str(device_state));
3003 }
3004
3005 return 0;
3006}
static int extensionstate2devicestate(int state)
Helper function which converts from extension state to device state values.
Definition app_queue.c:2887
@ AST_HINT_UPDATE_DEVICE
Definition pbx.h:91
const ast_string_field context
Definition app_queue.c:1983

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, call_queue::context, context_included(), extensionstate2devicestate(), call_queue::found, 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 2887 of file app_queue.c.

2888{
2889 switch (state) {
2892 break;
2895 break;
2896 case AST_EXTENSION_BUSY:
2898 break;
2901 break;
2904 break;
2907 break;
2910 break;
2913 break;
2916 default:
2918 break;
2919 }
2920
2921 return state;
2922}
@ 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, and AST_EXTENSION_UNAVAILABLE.

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

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

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

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

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

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

◆ find_member_by_queuename_and_interface()

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

Find a member by looking up queuename and interface.

Returns
member or NULL if member not found.

Definition at line 12201 of file app_queue.c.

12202{
12203 struct member *mem = NULL;
12204 struct call_queue *q;
12205
12206 if ((q = find_load_queue_rt_friendly(queuename))) {
12207 ao2_lock(q);
12208 mem = ao2_find(q->members, interface, OBJ_KEY);
12209 ao2_unlock(q);
12210 queue_t_unref(q, "Expiring temporary reference.");
12211 }
12212 return mem;
12213}
#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 3925 of file app_queue.c.

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

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

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

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

9277{
9278 struct member *m;
9279
9281 ast_log(LOG_ERROR, "QUEUE_MEMBER: Missing required interface argument.\n");
9282 return NULL;
9283 }
9284
9286 if (!m) {
9287 ast_log(LOG_ERROR, "Queue member interface '%s' not in queue '%s'.\n",
9288 interface, q->name);
9289 }
9290 return m;
9291}

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

8291{
8292 int foundqueue = 0, penalty;
8293 struct call_queue *q;
8294 struct member *mem;
8295
8296 if ((q = find_load_queue_rt_friendly(queuename))) {
8297 foundqueue = 1;
8298 ao2_lock(q);
8299 if ((mem = interface_exists(q, interface))) {
8300 penalty = mem->penalty;
8301 ao2_ref(mem, -1);
8302 ao2_unlock(q);
8303 queue_t_unref(q, "Search complete");
8304 return penalty;
8305 }
8306 ao2_unlock(q);
8307 queue_t_unref(q, "Search complete");
8308 }
8309
8310 /* some useful debugging */
8311 if (foundqueue) {
8312 ast_log (LOG_ERROR, "Invalid queuename\n");
8313 } else {
8314 ast_log (LOG_ERROR, "Invalid interface\n");
8315 }
8316
8317 return RESULT_FAILURE;
8318}
#define RESULT_FAILURE
Definition cli.h:42

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

Referenced by queue_function_memberpenalty_read().

◆ get_member_status()

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

Check if members are available.

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

Definition at line 2576 of file app_queue.c.

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

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

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

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

◆ get_wrapuptime()

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

Return wrapuptime.

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

Returns
integer value

Definition at line 2145 of file app_queue.c.

2146{
2147 if (member->wrapuptime) {
2148 return member->wrapuptime;
2149 }
2150 return q->wrapuptime;
2151}

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

6646{
6647 struct queue_stasis_data *queue_data = userdata;
6648 struct ast_attended_transfer_message *atxfer_msg = stasis_message_data(msg);
6649 RAII_VAR(struct ast_channel_snapshot *, caller_snapshot, NULL, ao2_cleanup);
6650 RAII_VAR(struct ast_channel_snapshot *, member_snapshot, NULL, ao2_cleanup);
6651
6652 if (atxfer_msg->result != AST_BRIDGE_TRANSFER_SUCCESS ||
6654 return;
6655 }
6656
6657 ao2_lock(queue_data);
6658
6659 if (queue_data->dying) {
6660 ao2_unlock(queue_data);
6661 return;
6662 }
6663
6664 if (ast_strlen_zero(queue_data->bridge_uniqueid)) {
6665 ao2_unlock(queue_data);
6666 return;
6667 }
6668
6669 if ((!atxfer_msg->to_transferee.bridge_snapshot || strcmp(queue_data->bridge_uniqueid,
6670 atxfer_msg->to_transferee.bridge_snapshot->uniqueid)) &&
6671 (!atxfer_msg->to_transfer_target.bridge_snapshot || strcmp(queue_data->bridge_uniqueid,
6673 ao2_unlock(queue_data);
6674 return;
6675 }
6676
6677 caller_snapshot = ast_channel_snapshot_get_latest(queue_data->caller_uniqueid);
6678 member_snapshot = ast_channel_snapshot_get_latest(queue_data->member_uniqueid);
6679
6680 ao2_unlock(queue_data);
6681
6682 ast_debug(3, "Detected attended transfer in queue %s\n", queue_data->queue->name);
6683 log_attended_transfer(queue_data, atxfer_msg);
6684
6685 send_agent_complete(queue_data->queue->name, caller_snapshot, member_snapshot, queue_data->member,
6686 queue_data->holdstart, queue_data->starttime, TRANSFER);
6687 update_queue(queue_data->queue, queue_data->member, queue_data->callcompletedinsl,
6688 queue_data->starttime);
6689 remove_stasis_subscriptions(queue_data);
6690}
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:6305
static int update_queue(struct call_queue *q, struct member *member, int callcompletedinsl, time_t starttime)
update the queue status
Definition app_queue.c:6148
static void remove_stasis_subscriptions(struct queue_stasis_data *queue_data)
Definition app_queue.c:6452
static void log_attended_transfer(struct queue_stasis_data *queue_data, struct ast_attended_transfer_message *atxfer_msg)
Definition app_queue.c:6506
#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:6398
const ast_string_field caller_uniqueid
Definition app_queue.c:6406
const ast_string_field member_uniqueid
Definition app_queue.c:6406
struct call_queue * queue
Definition app_queue.c:6408
const ast_string_field bridge_uniqueid
Definition app_queue.c:6406
struct member * member
Definition app_queue.c:6410
#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:981

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

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

6554{
6555 struct queue_stasis_data *queue_data = userdata;
6556 struct ast_bridge_blob *enter_blob = stasis_message_data(msg);
6557 SCOPED_AO2LOCK(lock, queue_data);
6558
6559 if (queue_data->dying) {
6560 return;
6561 }
6562
6563 if (!ast_strlen_zero(queue_data->bridge_uniqueid)) {
6564 return;
6565 }
6566
6567 if (!strcmp(enter_blob->channel->base->uniqueid, queue_data->caller_uniqueid)) {
6568 ast_string_field_set(queue_data, bridge_uniqueid,
6569 enter_blob->bridge->uniqueid);
6570 ast_debug(3, "Detected entry of caller channel %s into bridge %s\n",
6571 enter_blob->channel->base->name, queue_data->bridge_uniqueid);
6572 }
6573}
ast_mutex_t lock
Definition app_sla.c:337
#define SCOPED_AO2LOCK(varname, obj)
scoped lock specialization for ao2 mutexes.
Definition lock.h:611
Blob of data associated with a bridge.
struct ast_bridge_snapshot * bridge
struct ast_channel_snapshot * channel
const ast_string_field uniqueid
const ast_string_field name
struct ast_channel_snapshot_base * base

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

Referenced by setup_stasis_subs().

◆ handle_hangup()

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

Definition at line 6841 of file app_queue.c.

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

6720{
6721 struct queue_stasis_data *queue_data = userdata;
6722 struct ast_multi_channel_blob *optimization_blob = stasis_message_data(msg);
6723 struct ast_channel_snapshot *local_one = ast_multi_channel_blob_get_channel(optimization_blob, "1");
6724 struct ast_channel_snapshot *local_two = ast_multi_channel_blob_get_channel(optimization_blob, "2");
6725 struct ast_channel_snapshot *source = ast_multi_channel_blob_get_channel(optimization_blob, "source");
6726 struct local_optimization *optimization;
6727 unsigned int id;
6728 SCOPED_AO2LOCK(lock, queue_data);
6729
6730 if (!local_one || !local_two || !source) {
6731 ast_debug(1, "Local optimization begin missing channel snapshots:%s%s%s\n",
6732 !local_one ? " local_one," : "",
6733 !local_two ? " local_two," : "",
6734 !source ? " source," : "");
6735 return;
6736 }
6737
6738 if (queue_data->dying) {
6739 return;
6740 }
6741
6742 if (!strcmp(local_one->base->uniqueid, queue_data->member_uniqueid)) {
6743 optimization = &queue_data->member_optimize;
6744 } else if (!strcmp(local_two->base->uniqueid, queue_data->caller_uniqueid)) {
6745 optimization = &queue_data->caller_optimize;
6746 } else {
6747 return;
6748 }
6749
6750 /* We only allow move-swap optimizations, so there had BETTER be a source */
6751 ast_assert(source != NULL);
6752
6753 optimization->source_chan_uniqueid = ast_strdup(source->base->uniqueid);
6754 if (!optimization->source_chan_uniqueid) {
6755 ast_log(LOG_ERROR, "Unable to track local channel optimization for channel %s. Expect further errors\n", local_one->base->name);
6756 return;
6757 }
6759
6760 optimization->id = id;
6761 optimization->in_progress = 1;
6762}
enum queue_result id
Definition app_queue.c:1790
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:6374
const char * source_chan_uniqueid
Definition app_queue.c:6376
unsigned int id
Definition app_queue.c:6380
struct local_optimization member_optimize
Definition app_queue.c:6428
struct local_optimization caller_optimize
Definition app_queue.c:6426
#define ast_assert(a)
Definition utils.h:779

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

Referenced by setup_stasis_subs().

◆ handle_local_optimization_end()

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

Definition at line 6777 of file app_queue.c.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

◆ hangupcalls()

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

Hang up a list of outgoing calls.

Definition at line 4643 of file app_queue.c.

4644{
4645 struct callattempt *oo;
4646
4647 while (outgoing) {
4648 /* If someone else answered the call we should indicate this in the CANCEL */
4649 /* Hangup any existing lines we have open */
4650 if (outgoing->chan && (outgoing->chan != exception)) {
4651 if (exception || cancel_answered_elsewhere) {
4653 }
4654 ast_channel_publish_dial(qe->chan, outgoing->chan, outgoing->interface, "CANCEL");
4655
4656 /* When dialing channels it is possible that they may not ever
4657 * leave the not in use state (Local channels in particular) by
4658 * the time we cancel them. If this occurs but we know they were
4659 * dialed we explicitly remove them from the pending members
4660 * container so that subsequent call attempts occur.
4661 */
4662 if (outgoing->member->status == AST_DEVICE_NOT_INUSE) {
4664 }
4665
4666 ast_hangup(outgoing->chan);
4667 }
4668 oo = outgoing;
4669 outgoing = outgoing->q_next;
4671 callattempt_free(oo);
4672 }
4673}
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:4621
#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:1838
struct ast_channel * chan
Definition app_queue.c:1873

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

3109{
3110 int i;
3111 struct penalty_rule *pr_iter;
3112
3113 q->dead = 0;
3114 q->retry = DEFAULT_RETRY;
3116 q->maxlen = 0;
3117
3118 ast_string_field_set(q, announce, "");
3119 ast_string_field_set(q, context, "");
3120 ast_string_field_set(q, membergosub, "");
3121 ast_string_field_set(q, defaultrule, "");
3122
3123 q->announcefrequency = 0;
3125 q->announceholdtime = 1;
3127 q->announcepositionlimit = 10; /* Default 10 positions */
3128 q->announceposition = ANNOUNCEPOSITION_YES; /* Default yes */
3129 q->roundingseconds = 0; /* Default - don't announce seconds */
3130 q->servicelevel = 0;
3131 q->ringinuse = 1;
3133 q->setinterfacevar = 0;
3134 q->setqueuevar = 0;
3135 q->setqueueentryvar = 0;
3137 q->monfmt[0] = '\0';
3138 q->reportholdtime = 0;
3139 q->wrapuptime = 0;
3140 q->penaltymemberslimit = 0;
3141 q->joinempty = 0;
3142 q->leavewhenempty = 0;
3143 q->memberdelay = 0;
3144 q->weight = 0;
3145 q->timeoutrestart = 0;
3149 q->numperiodicannounce = 0;
3152 q->autopausebusy = 0;
3153 q->autopauseunavail = 0;
3155 q->autopausedelay = 0;
3157 if (!q->members) {
3159 /* linear strategy depends on order, so we have to place all members in a list */
3161 } else {
3164 }
3165 }
3166 q->found = 1;
3167
3168 ast_string_field_set(q, moh, "");
3169 ast_string_field_set(q, sound_next, "queue-youarenext");
3170 ast_string_field_set(q, sound_thereare, "queue-thereare");
3171 ast_string_field_set(q, sound_calls, "queue-callswaiting");
3172 ast_string_field_set(q, queue_quantity1, "queue-quantity1");
3173 ast_string_field_set(q, queue_quantity2, "queue-quantity2");
3174 ast_string_field_set(q, sound_holdtime, "queue-holdtime");
3175 ast_string_field_set(q, sound_minutes, "queue-minutes");
3176 ast_string_field_set(q, sound_minute, "queue-minute");
3177 ast_string_field_set(q, sound_seconds, "queue-seconds");
3178 ast_string_field_set(q, sound_thanks, "queue-thankyou");
3179 ast_string_field_set(q, sound_callerannounce, "");
3180 ast_string_field_set(q, sound_reporthold, "queue-reporthold");
3181
3182 if (!q->sound_periodicannounce[0]) {
3184 }
3185
3186 if (q->sound_periodicannounce[0]) {
3187 ast_str_set(&q->sound_periodicannounce[0], 0, "queue-periodic-announce");
3188 }
3189
3190 for (i = 1; i < MAX_PERIODIC_ANNOUNCEMENTS; i++) {
3191 if (q->sound_periodicannounce[i]) {
3192 ast_str_set(&q->sound_periodicannounce[i], 0, "%s", "");
3193 }
3194 }
3195
3196 while ((pr_iter = AST_LIST_REMOVE_HEAD(&q->rules,list))) {
3197 ast_free(pr_iter);
3198 }
3199
3200 /* On restart assume no members are available.
3201 * The queue_avail hint is a boolean state to indicate whether a member is available or not.
3202 *
3203 * This seems counter intuitive, but is required to light a BLF
3204 * AST_DEVICE_INUSE indicates no members are available.
3205 * AST_DEVICE_NOT_INUSE indicates a member is available.
3206 */
3208}
#define DEFAULT_RETRY
Definition app_queue.c:1699
static int member_hash_fn(const void *obj, const int flags)
Definition app_queue.c:3079
static int member_cmp_fn(void *obj1, void *obj2, int flags)
Definition app_queue.c:3095
#define DEFAULT_MIN_ANNOUNCE_FREQUENCY
The minimum number of seconds between position announcements.
Definition app_queue.c:1707
#define DEFAULT_TIMEOUT
Definition app_queue.c:1700
static int autofill_default
queues.conf [general] option
Definition app_queue.c:1742
#define ANNOUNCEPOSITION_YES
Definition app_queue.c:1940
@ 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.
unsigned int autopauseunavail
Definition app_queue.c:2003
unsigned int setinterfacevar
Definition app_queue.c:1989
int announcefrequency
Definition app_queue.c:2007
unsigned int announceholdtime
Definition app_queue.c:1995
unsigned int reportholdtime
Definition app_queue.c:1992
unsigned int setqueueentryvar
Definition app_queue.c:1991
unsigned int timeoutrestart
Definition app_queue.c:1994
int periodicannouncefrequency
Definition app_queue.c:2010
unsigned int announceposition_only_up
Definition app_queue.c:1997
unsigned int setqueuevar
Definition app_queue.c:1990
int announcepositionlimit
Definition app_queue.c:2006
unsigned int announce_to_first_user
Definition app_queue.c:1988
int randomperiodicannounce
Definition app_queue.c:2012
int periodicannouncestartdelay
Definition app_queue.c:2009
int log_restricted_caller_id
Definition app_queue.c:2039
int servicelevel
Definition app_queue.c:2019
int minannouncefrequency
Definition app_queue.c:2008
enum empty_conditions leavewhenempty
Definition app_queue.c:2005
int roundingseconds
Definition app_queue.c:2013
int numperiodicannounce
Definition app_queue.c:2011
unsigned int announceposition
Definition app_queue.c:1996
char monfmt[8]
Definition app_queue.c:2021
enum empty_conditions joinempty
Definition app_queue.c:2004
struct call_queue::@55 rules
int memberdelay
Definition app_queue.c:2036
unsigned int autopausebusy
Definition app_queue.c:2002
int autopausedelay
Definition app_queue.c:2031
int timeoutpriority
Definition app_queue.c:2032
unsigned int relativeperiodicannounce
Definition app_queue.c:2001

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

2244{
2245 struct queue_ent *cur;
2246
2247 if (!q || !new)
2248 return;
2249 if (prev) {
2250 cur = prev->next;
2251 prev->next = new;
2252 } else {
2253 cur = q->head;
2254 q->head = new;
2255 }
2256 new->next = cur;
2257
2258 /* every queue_ent must have a reference to it's parent call_queue, this
2259 * reference does not go away until the end of the queue_ent's life, meaning
2260 * that even when the queue_ent leaves the call_queue this ref must remain. */
2261 if (!new->parent) {
2262 queue_ref(q);
2263 new->parent = q;
2264 }
2265 new->pos = ++(*pos);
2266 new->opos = *pos;
2267}
#define queue_ref(q)
Definition app_queue.c:2209

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

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

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

2077{
2078 int x;
2079
2080 for (x = 0; x < ARRAY_LEN(strategies); x++) {
2081 if (strategy == strategies[x].strategy) {
2082 return strategies[x].name;
2083 }
2084 }
2085
2086 return "<unknown>";
2087}
static const struct strategy strategies[]
const char * name
Definition app_queue.c:1677

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

7675{
7676 struct member *mem;
7677 struct ao2_iterator mem_iter;
7678
7679 if (!q) {
7680 return NULL;
7681 }
7682 mem_iter = ao2_iterator_init(q->members, 0);
7683 while ((mem = ao2_iterator_next(&mem_iter))) {
7684 if (!strcasecmp(interface, mem->interface)) {
7685 ao2_iterator_destroy(&mem_iter);
7686 return mem;
7687 }
7688 ao2_ref(mem, -1);
7689 }
7690 ao2_iterator_destroy(&mem_iter);
7691
7692 return NULL;
7693}

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

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

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, OBJ_POINTER, queue_ent::parent, 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 2765 of file app_queue.c.

2766{
2767 int available = 0;
2768 int wrapuptime;
2769
2770 switch (mem->status) {
2771 case AST_DEVICE_INVALID:
2773 break;
2774 case AST_DEVICE_INUSE:
2775 case AST_DEVICE_BUSY:
2776 case AST_DEVICE_RINGING:
2778 case AST_DEVICE_ONHOLD:
2779 if (!mem->ringinuse) {
2780 break;
2781 }
2782 /* else fall through */
2784 case AST_DEVICE_UNKNOWN:
2785 if (!mem->paused) {
2786 available = 1;
2787 }
2788 break;
2789 }
2790
2791 /* Let wrapuptimes override device state availability */
2792 wrapuptime = get_wrapuptime(q, mem);
2793 if (mem->lastcall && wrapuptime && (time(NULL) - wrapuptime < mem->lastcall)) {
2794 available = 0;
2795 }
2796 return available;
2797}
static int available(struct dahdi_pvt **pvt, int is_specific_channel)

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

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

References ao2_lock, ao2_unlock, ast_channel_name(), ast_debug, num_available_members(), queue_ent::start, 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 4233 of file app_queue.c.

4234{
4235 struct call_queue *q;
4236 struct queue_ent *cur, *prev = NULL;
4237 int res = -1;
4238 int pos = 0;
4239 int inserted = 0;
4240
4242 return res;
4243 }
4244 ao2_lock(q);
4245
4246 /* This is our one */
4247 if (q->joinempty) {
4248 int status = 0;
4249 if ((status = get_member_status(q, qe->max_penalty, qe->min_penalty, qe->raise_penalty, q->joinempty, 0, qe->raise_respect_min))) {
4250 *reason = QUEUE_JOINEMPTY;
4251 ao2_unlock(q);
4252 queue_t_unref(q, "Done with realtime queue");
4253 return res;
4254 }
4255 }
4256 if (*reason == QUEUE_UNKNOWN && q->maxlen && (q->count >= q->maxlen)) {
4257 *reason = QUEUE_FULL;
4258 } else if (*reason == QUEUE_UNKNOWN) {
4259 RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
4260
4261 /* There's space for us, put us at the right position inside
4262 * the queue.
4263 * Take into account the priority of the calling user */
4264 inserted = 0;
4265 prev = NULL;
4266 cur = q->head;
4267 while (cur) {
4268 /* We have higher priority than the current user, enter
4269 * before him, after all the other users with priority
4270 * higher or equal to our priority. */
4271 if ((!inserted) && (qe->prio > cur->prio)) {
4272 insert_entry(q, prev, qe, &pos);
4273 inserted = 1;
4274 }
4275 /* <= is necessary for the position comparison because it may not be possible to enter
4276 * at our desired position since higher-priority callers may have taken the position we want
4277 */
4278 if (!inserted && (qe->prio >= cur->prio) && position && (position <= pos + 1)) {
4279 insert_entry(q, prev, qe, &pos);
4280 inserted = 1;
4281 /*pos is incremented inside insert_entry, so don't need to add 1 here*/
4282 if (position < pos) {
4283 ast_log(LOG_NOTICE, "Asked to be inserted at position %d but forced into position %d due to higher priority callers\n", position, pos);
4284 }
4285 }
4286 cur->pos = ++pos;
4287 prev = cur;
4288 cur = cur->next;
4289 }
4290 /* No luck, join at the end of the queue */
4291 if (!inserted) {
4292 insert_entry(q, prev, qe, &pos);
4293 }
4294 ast_copy_string(qe->moh, q->moh, sizeof(qe->moh));
4295 ast_copy_string(qe->announce, q->announce, sizeof(qe->announce));
4296 ast_copy_string(qe->context, q->context, sizeof(qe->context));
4297 q->count++;
4298 if (q->count == 1) {
4300 }
4301
4302 res = 0;
4303
4304 blob = ast_json_pack("{s: s, s: i, s: i}",
4305 "Queue", q->name,
4306 "Position", qe->pos,
4307 "Count", q->count);
4309 ast_debug(1, "Queue '%s' Join, Channel '%s', Position '%d'\n", q->name, ast_channel_name(qe->chan), qe->pos );
4310 }
4311 ao2_unlock(q);
4312 queue_t_unref(q, "Done with realtime queue");
4313
4314 return res;
4315}
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:1983
const ast_string_field announce
Definition app_queue.c:1983

References 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, call_queue::context, call_queue::count, find_load_queue_rt_friendly(), get_member_status(), call_queue::head, insert_entry(), call_queue::joinempty, LOG_NOTICE, call_queue::maxlen, 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::start, and status.

Referenced by queue_exec().

◆ kill_dead_members()

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

Definition at line 10005 of file app_queue.c.

10006{
10007 struct member *member = obj;
10008
10009 if (!member->delme) {
10011 return 0;
10012 } else {
10013 return CMP_MATCH;
10014 }
10015}
@ CMP_MATCH
Definition astobj2.h:1027
unsigned int delme
Definition app_queue.c:1902

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

10161{
10162 struct call_queue *q = obj;
10163 char *queuename = arg;
10164 if (!q->realtime && !q->found && (ast_strlen_zero(queuename) || !strcasecmp(queuename, q->name))) {
10165 q->dead = 1;
10166 return CMP_MATCH;
10167 } else {
10168 return 0;
10169 }
10170}

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

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

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

12035{
12036 int err = 0;
12037 struct ast_flags mask = {AST_FLAGS_ALL, };
12038 struct ast_config *member_config;
12039 struct stasis_topic *queue_topic;
12041
12044 if (!queues) {
12046 }
12047
12050 if (!pending_members) {
12051 unload_module();
12053 }
12054
12055 use_weight = 0;
12056
12057 if (reload_handler(0, &mask, NULL)) {
12058 unload_module();
12060 }
12061
12062 ast_realtime_require_field("queue_members", "paused", RQ_INTEGER1, 1, "uniqueid", RQ_UINTEGER2, 5, "reason_paused", RQ_CHAR, 80, SENTINEL);
12063
12064 /*
12065 * This section is used to determine which name for 'ringinuse' to use in realtime members
12066 * Necessary for supporting older setups.
12067 *
12068 * It also checks if 'reason_paused' exists in the realtime backend
12069 */
12070 member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name LIKE", "%", SENTINEL);
12071 if (!member_config) {
12072 realtime_ringinuse_field = "ringinuse";
12073 } else {
12074 const char *config_val;
12075
12076 if ((config_val = ast_variable_retrieve(member_config, NULL, "ringinuse"))) {
12077 ast_log(LOG_NOTICE, "ringinuse field entries found in queue_members table. Using 'ringinuse'\n");
12078 realtime_ringinuse_field = "ringinuse";
12079 } else if ((config_val = ast_variable_retrieve(member_config, NULL, "ignorebusy"))) {
12080 ast_log(LOG_NOTICE, "ignorebusy field found in queue_members table with no ringinuse field. Using 'ignorebusy'\n");
12081 realtime_ringinuse_field = "ignorebusy";
12082 } else {
12083 ast_log(LOG_NOTICE, "No entries were found for ringinuse/ignorebusy in queue_members table. Using 'ringinuse'\n");
12084 realtime_ringinuse_field = "ringinuse";
12085 }
12086
12087 if (ast_variable_retrieve(member_config, NULL, "reason_paused")) {
12089 }
12090 }
12091 ast_config_destroy(member_config);
12092
12095 }
12096
12105 err |= ast_manager_register_xml("QueueStatus", 0, manager_queues_status);
12106 err |= ast_manager_register_xml("QueueSummary", 0, manager_queues_summary);
12113 err |= ast_manager_register_xml("QueueRule", 0, manager_queue_rule_show);
12114 err |= ast_manager_register_xml("QueueReload", 0, manager_queue_reload);
12115 err |= ast_manager_register_xml("QueueReset", 0, manager_queue_reset);
12116 err |= ast_manager_register_xml("QueueChangePriorityCaller", 0, manager_change_priority_caller_on_queue);
12125
12126 /* in the following subscribe call, do I use DEVICE_STATE, or DEVICE_STATE_CHANGE? */
12128 if (!device_state_sub) {
12129 err = -1;
12130 }
12133
12135 queue_topic = ast_queue_topic_all();
12136 if (!manager_topic || !queue_topic) {
12137 unload_module();
12139 }
12141 if (!topic_forwarder) {
12142 unload_module();
12144 }
12145
12148 unload_module();
12150 }
12152 if (!agent_router) {
12153 unload_module();
12155 }
12159 NULL);
12163 NULL);
12164
12165 err |= STASIS_MESSAGE_TYPE_INIT(queue_caller_join_type);
12166 err |= STASIS_MESSAGE_TYPE_INIT(queue_caller_leave_type);
12167 err |= STASIS_MESSAGE_TYPE_INIT(queue_caller_abandon_type);
12168
12169 err |= STASIS_MESSAGE_TYPE_INIT(queue_member_status_type);
12170 err |= STASIS_MESSAGE_TYPE_INIT(queue_member_added_type);
12171 err |= STASIS_MESSAGE_TYPE_INIT(queue_member_removed_type);
12172 err |= STASIS_MESSAGE_TYPE_INIT(queue_member_pause_type);
12173 err |= STASIS_MESSAGE_TYPE_INIT(queue_member_penalty_type);
12174 err |= STASIS_MESSAGE_TYPE_INIT(queue_member_ringinuse_type);
12175
12176 err |= STASIS_MESSAGE_TYPE_INIT(queue_agent_called_type);
12177 err |= STASIS_MESSAGE_TYPE_INIT(queue_agent_connect_type);
12178 err |= STASIS_MESSAGE_TYPE_INIT(queue_agent_complete_type);
12179 err |= STASIS_MESSAGE_TYPE_INIT(queue_agent_dump_type);
12180 err |= STASIS_MESSAGE_TYPE_INIT(queue_agent_ringnoanswer_type);
12181
12182 if (err) {
12183 unload_module();
12185 }
12187}
static struct ast_custom_function queuevar_function
Definition app_queue.c:9697
static int manager_queue_reset(struct mansession *s, const struct message *m)
static int pending_members_cmp(void *obj, void *arg, int flags)
Definition app_queue.c:2695
static struct ast_custom_function queuemembercount_function
Definition app_queue.c:9702
static struct ast_custom_function queuewaitingcount_function
Definition app_queue.c:9713
static char * app_pqm
Definition app_queue.c:1724
static struct ast_custom_function queuememberlist_function
Definition app_queue.c:9718
static char * realtime_ringinuse_field
name of the ringinuse field in the realtime database
Definition app_queue.c:1772
static int manager_add_queue_member(struct mansession *s, const struct message *m)
static int aqm_exec(struct ast_channel *chan, const char *data)
AddQueueMember application.
Definition app_queue.c:8575
#define MAX_QUEUE_BUCKETS
Definition app_queue.c:1709
static int upqm_exec(struct ast_channel *chan, const char *data)
UnpauseQueueMember application.
Definition app_queue.c:8468
static void queue_agent_cb(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Definition app_queue.c:6336
static char * app_ql
Definition app_queue.c:1728
static void reload_queue_members(void)
Reload dynamic queue members persisted into the astdb.
Definition app_queue.c:8321
static int rqm_exec(struct ast_channel *chan, const char *data)
RemoveQueueMember application.
Definition app_queue.c:8504
#define MAX_CALL_ATTEMPT_BUCKETS
Definition app_queue.c:2673
static char * app_rqm
Definition app_queue.c:1722
static int manager_queue_rule_show(struct mansession *s, const struct message *m)
static int manager_queue_reload(struct mansession *s, const struct message *m)
static int pqm_exec(struct ast_channel *chan, const char *data)
PauseQueueMember application.
Definition app_queue.c:8432
static int qupd_exec(struct ast_channel *chan, const char *data)
Update Queue with data of an outgoing call.
static int manager_queue_member_ringinuse(struct mansession *s, const struct message *m)
static char * app_qupd
Definition app_queue.c:1730
static int manager_queue_member_penalty(struct mansession *s, const struct message *m)
static char * app_upqm
Definition app_queue.c:1726
static struct ast_custom_function queuememberpenalty_function
Definition app_queue.c:9723
static int queue_cmp_cb(void *obj, void *arg, int flags)
Definition app_queue.c:2132
static int manager_request_withdraw_caller_from_queue(struct mansession *s, const struct message *m)
static char * app
Definition app_queue.c:1718
static int queue_hash_cb(const void *obj, const int flags)
Definition app_queue.c:2125
static int queue_exec(struct ast_channel *chan, const char *data)
The starting point for all queue calls.
Definition app_queue.c:8746
static int pending_members_hash(const void *obj, const int flags)
Definition app_queue.c:2675
static int manager_pause_queue_member(struct mansession *s, const struct message *m)
static int ql_exec(struct ast_channel *chan, const char *data)
QueueLog application.
Definition app_queue.c:8669
static int manager_remove_queue_member(struct mansession *s, const struct message *m)
static struct stasis_message_router * agent_router
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:2800
static struct stasis_subscription * device_state_sub
Subscription to device state change messages.
Definition app_queue.c:1754
static int manager_queues_summary(struct mansession *s, const struct message *m)
Summary of queue info via the AMI.
static int unload_module(void)
static int manager_queues_status(struct mansession *s, const struct message *m)
Queue status info via AMI.
static int realtime_reason_paused
does realtime backend support reason_paused
Definition app_queue.c:1775
static char * app_aqm
Definition app_queue.c:1720
static struct ast_cli_entry cli_queue[]
static struct ast_custom_function queuegetchannel_function
Definition app_queue.c:9708
static struct stasis_forward * topic_forwarder
static struct ast_custom_function queueexists_function
Definition app_queue.c:9692
static int manager_change_priority_caller_on_queue(struct mansession *s, const struct message *m)
static int manager_queue_log_custom(struct mansession *s, const struct message *m)
#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.
struct stasis_topic * ast_manager_get_topic(void)
Get the Stasis Message Bus API topic for AMI.
Definition manager.c:450
static struct stasis_topic * manager_topic
A stasis_topic that all topics AMI cares about will be forwarded to.
Definition manager.c:182
struct stasis_topic * ast_channel_topic_all(void)
A topic which publishes the events for all channels.
struct stasis_message_type * ast_channel_agent_logoff_type(void)
Message type for agent logoff on a channel.
struct stasis_message_type * ast_channel_agent_login_type(void)
Message type for agent login on a channel.
struct stasis_topic * ast_queue_topic_all(void)
Get the Stasis Message Bus API topic for queue messages.
Definition main/app.c:3344
int ast_realtime_require_field(const char *family,...) attribute_sentinel
Inform realtime what fields that may be stored.
#define ast_manager_register_xml(action, authority, func)
Register a manager callback using XML documentation to describe the manager.
Definition manager.h:192
#define EVENT_FLAG_AGENT
Definition manager.h:80
@ AST_MODULE_LOAD_SUCCESS
Definition module.h:70
@ AST_MODULE_LOAD_DECLINE
Module has failed to load, may be in an inconsistent state.
Definition module.h:78
#define ast_register_application_xml(app, execute)
Register an application using XML documentation.
Definition module.h:640
#define ast_custom_function_register(acf)
Register a custom function.
Definition pbx.h:1562
@ STASIS_SUBSCRIPTION_FILTER_SELECTIVE
Definition stasis.h:297
int stasis_subscription_accept_message_type(struct stasis_subscription *subscription, const struct stasis_message_type *type)
Indicate to a subscription that we are interested in a message type.
Definition stasis.c:1090
int stasis_subscription_set_filter(struct stasis_subscription *subscription, enum stasis_subscription_message_filter filter)
Set the message type filtering level on a subscription.
Definition stasis.c:1144
#define STASIS_MESSAGE_TYPE_INIT(name)
Boiler-plate messaging macro for initializing message types.
Definition stasis.h:1493
struct stasis_forward * stasis_forward_all(struct stasis_topic *from_topic, struct stasis_topic *to_topic)
Create a subscription which forwards all messages from one topic to another.
Definition stasis.c:1645
#define stasis_subscribe(topic, callback, data)
Definition stasis.h:649
#define stasis_message_router_create(topic)
Create a new message router object.
int stasis_message_router_add(struct stasis_message_router *router, struct stasis_message_type *message_type, stasis_subscription_cb callback, void *data)
Add a route to a message router.

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

◆ load_realtime_queues()

static void load_realtime_queues ( const char *  queuename)
static

Definition at line 4130 of file app_queue.c.

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

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

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

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

Referenced by reload_queue_rules().

◆ log_attended_transfer()

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

Definition at line 6506 of file app_queue.c.

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

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

Referenced by handle_attended_transfer().

◆ manager_add_queue_member()

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

Definition at line 10879 of file app_queue.c.

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

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

Referenced by load_module().

◆ manager_change_priority_caller_on_queue()

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

Definition at line 11175 of file app_queue.c.

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

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

10992{
10993 const char *queuename, *interface, *paused_s, *reason;
10994 int paused;
10995
10996 interface = astman_get_header(m, "Interface");
10997 paused_s = astman_get_header(m, "Paused");
10998 queuename = astman_get_header(m, "Queue"); /* Optional - if not supplied, pause the given Interface in all queues */
10999 reason = astman_get_header(m, "Reason"); /* Optional */
11000
11001 if (ast_strlen_zero(interface) || ast_strlen_zero(paused_s)) {
11002 astman_send_error(s, m, "Need 'Interface' and 'Paused' parameters.");
11003 return 0;
11004 }
11005
11006 paused = abs(ast_true(paused_s));
11007
11008 if (set_member_paused(queuename, interface, reason, paused)) {
11009 astman_send_error(s, m, "Interface not found");
11010 } else {
11011 astman_send_ack(s, m, paused ? "Interface paused successfully" : "Interface unpaused successfully");
11012 }
11013 return 0;
11014}

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

11017{
11018 const char *queuename, *event, *message, *interface, *uniqueid;
11019
11020 queuename = astman_get_header(m, "Queue");
11021 uniqueid = astman_get_header(m, "UniqueId");
11022 interface = astman_get_header(m, "Interface");
11023 event = astman_get_header(m, "Event");
11024 message = astman_get_header(m, "Message");
11025
11026 if (ast_strlen_zero(queuename) || ast_strlen_zero(event)) {
11027 astman_send_error(s, m, "Need 'Queue' and 'Event' parameters.");
11028 return 0;
11029 }
11030
11031 ast_queue_log(queuename, S_OR(uniqueid, "NONE"), interface, event, "%s", message);
11032 astman_send_ack(s, m, "Event added successfully");
11033
11034 return 0;
11035}

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

11150{
11151 const char *queuename, *interface, *penalty_s;
11152 int penalty;
11153
11154 interface = astman_get_header(m, "Interface");
11155 penalty_s = astman_get_header(m, "Penalty");
11156 /* Optional - if not supplied, set the penalty value for the given Interface in all queues */
11157 queuename = astman_get_header(m, "Queue");
11158
11159 if (ast_strlen_zero(interface) || ast_strlen_zero(penalty_s)) {
11160 astman_send_error(s, m, "Need 'Interface' and 'Penalty' parameters.");
11161 return 0;
11162 }
11163
11164 penalty = atoi(penalty_s);
11165
11166 if (set_member_value((char *)queuename, (char *)interface, MEMBER_PENALTY, penalty)) {
11167 astman_send_error(s, m, "Invalid interface, queuename or penalty");
11168 } else {
11169 astman_send_ack(s, m, "Interface penalty set successfully");
11170 }
11171
11172 return 0;
11173}

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

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

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

11038{
11039 struct ast_flags mask = {0,};
11040 const char *queuename = NULL;
11041 int header_found = 0;
11042
11043 queuename = astman_get_header(m, "Queue");
11044 if (!strcasecmp(S_OR(astman_get_header(m, "Members"), ""), "yes")) {
11046 header_found = 1;
11047 }
11048 if (!strcasecmp(S_OR(astman_get_header(m, "Rules"), ""), "yes")) {
11050 header_found = 1;
11051 }
11052 if (!strcasecmp(S_OR(astman_get_header(m, "Parameters"), ""), "yes")) {
11054 header_found = 1;
11055 }
11056
11057 if (!header_found) {
11059 }
11060
11061 if (!reload_handler(1, &mask, queuename)) {
11062 astman_send_ack(s, m, "Queue reloaded successfully");
11063 } else {
11064 astman_send_error(s, m, "Error encountered while reloading queue");
11065 }
11066 return 0;
11067}

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

11070{
11071 const char *queuename = NULL;
11072 struct ast_flags mask = {QUEUE_RESET_STATS,};
11073
11074 queuename = astman_get_header(m, "Queue");
11075
11076 if (!reload_handler(1, &mask, queuename)) {
11077 astman_send_ack(s, m, "Queue stats reset successfully");
11078 } else {
11079 astman_send_error(s, m, "Error encountered while resetting queue stats");
11080 }
11081 return 0;
11082}

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

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

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

10757{
10758 time_t now;
10759 int pos;
10760 int q_items = 0;
10761 const char *id = astman_get_header(m,"ActionID");
10762 const char *queuefilter = astman_get_header(m,"Queue");
10763 const char *memberfilter = astman_get_header(m,"Member");
10764 char idText[256];
10765 struct call_queue *q;
10766 struct queue_ent *qe;
10767 float sl = 0;
10768 float sl2 = 0;
10769 struct member *mem;
10770 struct ao2_iterator queue_iter;
10771 struct ao2_iterator mem_iter;
10772
10773 if (ast_check_realtime("queues")) {
10774 load_realtime_queues(queuefilter);
10775 }
10776
10777 astman_send_listack(s, m, "Queue status will follow", "start");
10778 time(&now);
10779 idText[0] = '\0';
10780 if (!ast_strlen_zero(id)) {
10781 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
10782 }
10783
10784 queue_iter = ao2_iterator_init(queues, 0);
10785 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
10786 ao2_lock(q);
10787
10788 /* List queue properties */
10789 if (ast_strlen_zero(queuefilter) || !strcasecmp(q->name, queuefilter)) {
10790 sl = ((q->callscompleted > 0) ? 100 * ((float)q->callscompletedinsl / (float)q->callscompleted) : 0);
10791 sl2 = (((q->callscompleted + q->callsabandoned) > 0) ? 100 * (((float)q->callsabandonedinsl + (float)q->callscompletedinsl) / ((float)q->callsabandoned + (float)q->callscompleted)) : 0);
10792
10793 astman_append(s, "Event: QueueParams\r\n"
10794 "Queue: %s\r\n"
10795 "Max: %d\r\n"
10796 "Strategy: %s\r\n"
10797 "Calls: %d\r\n"
10798 "Holdtime: %d\r\n"
10799 "TalkTime: %d\r\n"
10800 "Completed: %d\r\n"
10801 "Abandoned: %d\r\n"
10802 "ServiceLevel: %d\r\n"
10803 "ServicelevelPerf: %2.1f\r\n"
10804 "ServicelevelPerf2: %2.1f\r\n"
10805 "Weight: %d\r\n"
10806 "%s"
10807 "\r\n",
10808 q->name, q->maxlen, int2strat(q->strategy), q->count, q->holdtime, q->talktime, q->callscompleted,
10809 q->callsabandoned, q->servicelevel, sl, sl2, q->weight, idText);
10810 ++q_items;
10811
10812 /* List Queue Members */
10813 mem_iter = ao2_iterator_init(q->members, 0);
10814 while ((mem = ao2_iterator_next(&mem_iter))) {
10815 if (ast_strlen_zero(memberfilter) || !strcmp(mem->interface, memberfilter) || !strcmp(mem->membername, memberfilter)) {
10816 astman_append(s, "Event: QueueMember\r\n"
10817 "Queue: %s\r\n"
10818 "Name: %s\r\n"
10819 "Location: %s\r\n"
10820 "StateInterface: %s\r\n"
10821 "Membership: %s\r\n"
10822 "Penalty: %d\r\n"
10823 "CallsTaken: %d\r\n"
10824 "LastCall: %d\r\n"
10825 "LastPause: %d\r\n"
10826 "LoginTime: %d\r\n"
10827 "InCall: %d\r\n"
10828 "Status: %d\r\n"
10829 "Paused: %d\r\n"
10830 "PausedReason: %s\r\n"
10831 "Wrapuptime: %d\r\n"
10832 "%s"
10833 "\r\n",
10834 q->name, mem->membername, mem->interface, mem->state_interface, mem->dynamic ? "dynamic" : "static",
10835 mem->penalty, mem->calls, (int)mem->lastcall, (int)mem->lastpause, (int)mem->logintime, mem->starttime ? 1 : 0, mem->status,
10836 mem->paused, mem->reason_paused, mem->wrapuptime, idText);
10837 ++q_items;
10838 }
10839 ao2_ref(mem, -1);
10840 }
10841 ao2_iterator_destroy(&mem_iter);
10842
10843 /* List Queue Entries */
10844 pos = 1;
10845 for (qe = q->head; qe; qe = qe->next) {
10846 astman_append(s, "Event: QueueEntry\r\n"
10847 "Queue: %s\r\n"
10848 "Position: %d\r\n"
10849 "Channel: %s\r\n"
10850 "Uniqueid: %s\r\n"
10851 "CallerIDNum: %s\r\n"
10852 "CallerIDName: %s\r\n"
10853 "ConnectedLineNum: %s\r\n"
10854 "ConnectedLineName: %s\r\n"
10855 "Wait: %ld\r\n"
10856 "Priority: %d\r\n"
10857 "%s"
10858 "\r\n",
10859 q->name, pos++, ast_channel_name(qe->chan), ast_channel_uniqueid(qe->chan),
10864 (long) (now - qe->start), qe->prio, idText);
10865 ++q_items;
10866 }
10867 }
10868 ao2_unlock(q);
10869 queue_t_unref(q, "Done with iterator");
10870 }
10871 ao2_iterator_destroy(&queue_iter);
10872
10873 astman_send_list_complete_start(s, m, "QueueStatusComplete", q_items);
10875
10876 return RESULT_SUCCESS;
10877}
static void load_realtime_queues(const char *queuename)
Definition app_queue.c:4130
static const char * int2strat(int strategy)
Definition app_queue.c:2076
struct ast_party_connected_line * ast_channel_connected(struct ast_channel *chan)
struct ast_party_caller * ast_channel_caller(struct ast_channel *chan)
void astman_send_listack(struct mansession *s, const struct message *m, char *msg, char *listflag)
Send ack in manager transaction to begin a list.
Definition manager.c:2024
void astman_send_list_complete_start(struct mansession *s, const struct message *m, const char *event_name, int count)
Start the list complete event.
Definition manager.c:2060
void astman_send_list_complete_end(struct mansession *s)
End the list complete event.
Definition manager.c:2068
#define S_COR(a, b, c)
returns the equivalent of logic or for strings, with an additional boolean check: second one if not e...
Definition strings.h:87
struct ast_party_id id
Caller party ID.
Definition channel.h:422
struct ast_party_id id
Connected party ID.
Definition channel.h:460
struct ast_party_name name
Subscriber name.
Definition channel.h:342
struct ast_party_number number
Subscriber phone number.
Definition channel.h:344
unsigned char valid
TRUE if the name information is valid/present.
Definition channel.h:281
char * str
Subscriber name (Malloced)
Definition channel.h:266
unsigned char valid
TRUE if the number information is valid/present.
Definition channel.h:299
char * str
Subscriber phone number (Malloced)
Definition channel.h:293

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

Referenced by load_module().

◆ manager_queues_summary()

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

Summary of queue info via the AMI.

Definition at line 10674 of file app_queue.c.

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

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

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

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

11223{
11224 const char *queuename, *caller, *withdraw_info;
11225
11226 queuename = astman_get_header(m, "Queue");
11227 caller = astman_get_header(m, "Caller");
11228 withdraw_info = astman_get_header(m, "WithdrawInfo");
11229
11230 if (ast_strlen_zero(queuename)) {
11231 astman_send_error(s, m, "'Queue' not specified.");
11232 return 0;
11233 }
11234
11235 if (ast_strlen_zero(caller)) {
11236 astman_send_error(s, m, "'Caller' not specified.");
11237 return 0;
11238 }
11239
11240 switch (request_withdraw_caller_from_queue(queuename, caller, withdraw_info)) {
11241 case RES_OKAY:
11242 astman_send_ack(s, m, "Withdraw requested successfully");
11243 break;
11244 case RES_NOSUCHQUEUE:
11245 astman_send_error(s, m, "Unable to request withdraw from queue: No such queue");
11246 break;
11247 case RES_NOT_CALLER:
11248 astman_send_error(s, m, "Unable to request withdraw from queue: No such caller");
11249 break;
11250 case RES_EXISTS:
11251 astman_send_error(s, m, "Unable to request withdraw from queue: Already requested");
11252 break;
11253 }
11254
11255 return 0;
11256}
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:7938

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

9997{
9998 struct member *member = obj;
9999 if (!member->dynamic && !member->realtime) {
10000 member->delme = 1;
10001 }
10002 return 0;
10003}

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

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

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

3096{
3097 struct member *mem1 = obj1;
3098 struct member *mem2 = obj2;
3099 const char *interface = (flags & OBJ_KEY) ? obj2 : mem2->interface;
3100
3101 return strcasecmp(mem1->interface, interface) ? 0 : CMP_MATCH | CMP_STOP;
3102}
@ 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 3079 of file app_queue.c.

3080{
3081 const struct member *mem = obj;
3082 const char *interface = (flags & OBJ_KEY) ? obj : mem->interface;
3083 const char *chname = strchr(interface, '/');
3084 int ret = 0, i;
3085
3086 if (!chname) {
3087 chname = interface;
3088 }
3089 for (i = 0; i < 5 && chname[i]; i++) {
3090 ret += compress_char(chname[i]) << (i * 6);
3091 }
3092 return ret;
3093}
static int compress_char(const char c)
Definition app_queue.c:3069

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

3737{
3739 ao2_lock(queue->members);
3742 ao2_unlink(queue->members, mem);
3743 ao2_unlock(queue->members);
3744}
static void queue_member_follower_removal(struct call_queue *queue, struct member *mem)
Definition app_queue.c:2196
#define QUEUE_UNKNOWN_PAUSED_DEVSTATE
Definition app_queue.c:3712
#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 4819 of file app_queue.c.

4820{
4822}

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

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

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

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

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

2696{
2697 const struct member *object_left = obj;
2698 const struct member *object_right = arg;
2699 const char *right_key = arg;
2700 int cmp;
2701
2702 switch (flags & OBJ_SEARCH_MASK) {
2703 case OBJ_SEARCH_OBJECT:
2704 right_key = object_right->interface;
2705 /* Fall through */
2706 case OBJ_SEARCH_KEY:
2707 cmp = strcasecmp(object_left->interface, right_key);
2708 break;
2710 /* Not supported by container. */
2711 ast_assert(0);
2712 return 0;
2713 default:
2714 cmp = 0;
2715 break;
2716 }
2717 if (cmp) {
2718 return 0;
2719 }
2720 return CMP_MATCH;
2721}
@ 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 2675 of file app_queue.c.

2676{
2677 const struct member *object;
2678 const char *key;
2679
2680 switch (flags & OBJ_SEARCH_MASK) {
2681 case OBJ_SEARCH_KEY:
2682 key = obj;
2683 break;
2684 case OBJ_SEARCH_OBJECT:
2685 object = obj;
2686 key = object->interface;
2687 break;
2688 default:
2689 ast_assert(0);
2690 return 0;
2691 }
2692 return ast_str_case_hash(key);
2693}
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(), member::interface, 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 2723 of file app_queue.c.

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

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

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

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

8433{
8434 char *parse;
8436 AST_APP_ARG(queuename);
8437 AST_APP_ARG(interface);
8439 AST_APP_ARG(reason);
8440 );
8441
8442 if (ast_strlen_zero(data)) {
8443 ast_log(LOG_WARNING, "PauseQueueMember requires an argument ([queuename],interface[,options][,reason])\n");
8444 return -1;
8445 }
8446
8447 parse = ast_strdupa(data);
8448
8450
8451 if (ast_strlen_zero(args.interface)) {
8452 ast_log(LOG_WARNING, "Missing interface argument to PauseQueueMember ([queuename],interface[,options[,reason]])\n");
8453 return -1;
8454 }
8455
8456 if (set_member_paused(args.queuename, args.interface, args.reason, 1)) {
8457 ast_log(LOG_WARNING, "Attempt to pause interface %s, not found\n", args.interface);
8458 pbx_builtin_setvar_helper(chan, "PQMSTATUS", "NOTFOUND");
8459 return 0;
8460 }
8461
8462 pbx_builtin_setvar_helper(chan, "PQMSTATUS", "PAUSED");
8463
8464 return 0;
8465}

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

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

4632{
4633 struct callattempt *cur;
4634
4635 for (cur = outgoing; cur; cur = cur->q_next) {
4636 if (cur->chan && cur->chan != exception) {
4638 }
4639 }
4640}
struct callattempt * q_next
Definition app_queue.c:1822
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 7977 of file app_queue.c.

7978{
7979 struct ast_json *json_blob = queue_member_blob_create(q, member);
7980
7981 if (!json_blob) {
7982 return -1;
7983 }
7984
7985 queue_publish_member_blob(queue_member_pause_type(), json_blob);
7986
7987 return 0;
7988}

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

8670{
8671 char *parse;
8672
8674 AST_APP_ARG(queuename);
8675 AST_APP_ARG(uniqueid);
8676 AST_APP_ARG(membername);
8678 AST_APP_ARG(params);
8679 );
8680
8681 if (ast_strlen_zero(data)) {
8682 ast_log(LOG_WARNING, "QueueLog requires arguments (queuename,uniqueid,membername,event[,additionalinfo]\n");
8683 return -1;
8684 }
8685
8686 parse = ast_strdupa(data);
8687
8689
8690 if (ast_strlen_zero(args.queuename) || ast_strlen_zero(args.uniqueid)
8691 || ast_strlen_zero(args.membername) || ast_strlen_zero(args.event)) {
8692 ast_log(LOG_WARNING, "QueueLog requires arguments (queuename,uniqueid,membername,event[,additionalinfo])\n");
8693 return -1;
8694 }
8695
8696 ast_queue_log(args.queuename, args.uniqueid, args.membername, args.event,
8697 "%s", args.params ? args.params : "");
8698
8699 return 0;
8700}

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

2419{
2420 return queue_multi_channel_to_ami("AgentCalled", message);
2421}
static struct ast_manager_event_blob * queue_multi_channel_to_ami(const char *type, struct stasis_message *message)
Definition app_queue.c:2377

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

6338{
6339 struct ast_channel_blob *agent_blob;
6340
6341 agent_blob = stasis_message_data(msg);
6342
6344 ast_queue_log("NONE", agent_blob->snapshot->base->uniqueid,
6345 ast_json_string_get(ast_json_object_get(agent_blob->blob, "agent")),
6346 "AGENTLOGIN", "%s", agent_blob->snapshot->base->name);
6348 ast_queue_log("NONE", agent_blob->snapshot->base->uniqueid,
6349 ast_json_string_get(ast_json_object_get(agent_blob->blob, "agent")),
6350 "AGENTLOGOFF", "%s|%ld", agent_blob->snapshot->base->name,
6351 (long) ast_json_integer_get(ast_json_object_get(agent_blob->blob, "logintime")));
6352 }
6353}

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

2429{
2430 return queue_multi_channel_to_ami("AgentComplete", message);
2431}

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

2424{
2425 return queue_multi_channel_to_ami("AgentConnect", message);
2426}

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

2434{
2435 return queue_multi_channel_to_ami("AgentDump", message);
2436}

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

2439{
2440 return queue_multi_channel_to_ami("AgentRingNoAnswer", message);
2441}

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

6701{
6703 ao2_cleanup(userdata);
6704 }
6705}
static struct stasis_subscription * sub
Statsd channel stats. Exmaple of how to subscribe to Stasis events.
int stasis_subscription_final_message(struct stasis_subscription *sub, struct stasis_message *msg)
Determine whether a message is the final message to be received on a subscription.
Definition stasis.c:1241

References ao2_cleanup, stasis_subscription_final_message(), and sub.

Referenced by setup_stasis_subs().

◆ queue_caller_abandon_to_ami()

static struct ast_manager_event_blob * queue_caller_abandon_to_ami ( struct stasis_message message)
static

Definition at line 2298 of file app_queue.c.

2299{
2300 return queue_channel_to_ami("QueueCallerAbandon", message);
2301}
static struct ast_manager_event_blob * queue_channel_to_ami(const char *type, struct stasis_message *message)
Definition app_queue.c:2269

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

2289{
2290 return queue_channel_to_ami("QueueCallerJoin", message);
2291}

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

2294{
2295 return queue_channel_to_ami("QueueCallerLeave", message);
2296}

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

6934{
6936 ao2_cleanup(userdata);
6937 }
6938}

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

2270{
2272 RAII_VAR(struct ast_str *, channel_string, NULL, ast_free);
2273 RAII_VAR(struct ast_str *, event_string, NULL, ast_free);
2274
2275 channel_string = ast_manager_build_channel_state_string(obj->snapshot);
2276 event_string = ast_manager_str_from_json_object(obj->blob, NULL);
2277 if (!channel_string || !event_string) {
2278 return NULL;
2279 }
2280
2282 "%s"
2283 "%s",
2284 ast_str_buffer(channel_string),
2285 ast_str_buffer(event_string));
2286}
static const char type[]
struct ast_str * ast_manager_str_from_json_object(struct ast_json *blob, key_exclusion_cb exclusion_cb)
Convert a JSON object into an AMI compatible string.
Definition manager.c:551
struct ast_str * ast_manager_build_channel_state_string(const struct ast_channel_snapshot *snapshot)
Generate the AMI message body from a channel snapshot.
struct ast_manager_event_blob * ast_manager_event_blob_create(int event_flags, const char *manager_event, const char *extra_fields_fmt,...)
Construct a ast_manager_event_blob.
Definition manager.c:10144

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

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

◆ queue_cmp_cb()

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

Definition at line 2132 of file app_queue.c.

2133{
2134 struct call_queue *q = obj, *q2 = arg;
2135 return !strcasecmp(q->name, q2->name) ? CMP_MATCH | CMP_STOP : 0;
2136}

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

2179{
2180 struct member *mem = obj;
2181 struct call_queue *queue = arg;
2182 int rrpos = mem->queuepos;
2183
2184 if (mem->delme) {
2186 }
2187
2188 return 0;
2189}
static int queue_member_decrement_followers(void *obj, void *arg, int flag)
Definition app_queue.c:2159
#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 8746 of file app_queue.c.

8747{
8748 int res=-1;
8749 int ringing=0;
8750 const char *user_priority;
8751 const char *max_penalty_str;
8752 const char *min_penalty_str;
8753 const char *raise_penalty_str;
8754 int prio;
8755 int qcontinue = 0;
8756 int max_penalty, min_penalty, raise_penalty;
8757 enum queue_result reason = QUEUE_UNKNOWN;
8758 /* whether to exit Queue application after the timeout hits */
8759 int tries = 0;
8760 int noption = 0;
8761 char *parse;
8762 int makeannouncement = 0;
8763 int position = 0;
8765 AST_APP_ARG(queuename);
8768 AST_APP_ARG(announceoverride);
8769 AST_APP_ARG(queuetimeoutstr);
8770 AST_APP_ARG(agi);
8771 AST_APP_ARG(gosub);
8773 AST_APP_ARG(position);
8774 );
8775 /* Our queue entry */
8776 struct queue_ent qe = { 0 };
8777 struct ast_flags opts = { 0, };
8778 char *opt_args[OPT_ARG_ARRAY_SIZE];
8779 int max_forwards;
8780 int cid_allow;
8781 /* Reset variables to avoid stale data */
8782 pbx_builtin_setvar_helper(chan, "ANSWEREDTIME", "");
8783 pbx_builtin_setvar_helper(chan, "ANSWEREDTIME_MS", "");
8784 pbx_builtin_setvar_helper(chan, "DIALEDTIME", "");
8785 pbx_builtin_setvar_helper(chan, "DIALEDTIME_MS", "");
8786 pbx_builtin_setvar_helper(chan, "QUEUEWAIT", "");
8787 pbx_builtin_setvar_helper(chan, "QUEUEWAIT_MS", "");
8788
8789 if (ast_strlen_zero(data)) {
8790 ast_log(LOG_WARNING, "Queue requires an argument: queuename[,options[,URL[,announceoverride[,timeout[,agi[,gosub[,rule[,position]]]]]]]]\n");
8791 return -1;
8792 }
8793
8794 ast_channel_lock(chan);
8796 ast_channel_unlock(chan);
8797
8798 if (max_forwards <= 0) {
8799 ast_log(LOG_WARNING, "Channel '%s' cannot enter queue. Max forwards exceeded\n", ast_channel_name(chan));
8800 return -1;
8801 }
8802
8803 parse = ast_strdupa(data);
8805
8806 ast_debug(1, "queue: %s, options: %s, url: %s, announce: %s, timeout: %s, agi: %s, gosub: %s, rule: %s, position: %s\n",
8807 args.queuename,
8808 S_OR(args.options, ""),
8809 S_OR(args.url, ""),
8810 S_OR(args.announceoverride, ""),
8811 S_OR(args.queuetimeoutstr, ""),
8812 S_OR(args.agi, ""),
8813 S_OR(args.gosub, ""),
8814 S_OR(args.rule, ""),
8815 S_OR(args.position, ""));
8816
8817 if (!ast_strlen_zero(args.options)) {
8818 ast_app_parse_options(queue_exec_options, &opts, opt_args, args.options);
8819 }
8820
8821 /* Setup our queue entry */
8822 qe.start = time(NULL);
8823
8824 pbx_builtin_setvar_helper(chan, "ABANDONED", NULL);
8825
8826 /* set the expire time based on the supplied timeout; */
8827 if (!ast_strlen_zero(args.queuetimeoutstr)) {
8828 qe.expire = qe.start + atoi(args.queuetimeoutstr);
8829 } else {
8830 qe.expire = 0;
8831 }
8832
8833 /* Get the priority from the variable ${QUEUE_PRIO} */
8834 ast_channel_lock(chan);
8835 user_priority = pbx_builtin_getvar_helper(chan, "QUEUE_PRIO");
8836 if (user_priority) {
8837 if (sscanf(user_priority, "%30d", &prio) == 1) {
8838 ast_debug(1, "%s: Got priority %d from ${QUEUE_PRIO}.\n", ast_channel_name(chan), prio);
8839 } else {
8840 ast_log(LOG_WARNING, "${QUEUE_PRIO}: Invalid value (%s), channel %s.\n",
8841 user_priority, ast_channel_name(chan));
8842 prio = 0;
8843 }
8844 } else {
8845 ast_debug(3, "NO QUEUE_PRIO variable found. Using default.\n");
8846 prio = 0;
8847 }
8848
8849 /* Get the maximum penalty from the variable ${QUEUE_MAX_PENALTY} */
8850
8851 if ((max_penalty_str = pbx_builtin_getvar_helper(chan, "QUEUE_MAX_PENALTY"))) {
8852 if (sscanf(max_penalty_str, "%30d", &max_penalty) == 1) {
8853 ast_debug(1, "%s: Got max penalty %d from ${QUEUE_MAX_PENALTY}.\n", ast_channel_name(chan), max_penalty);
8854 } else {
8855 ast_log(LOG_WARNING, "${QUEUE_MAX_PENALTY}: Invalid value (%s), channel %s.\n",
8856 max_penalty_str, ast_channel_name(chan));
8857 max_penalty = INT_MAX;
8858 }
8859 } else {
8860 max_penalty = INT_MAX;
8861 }
8862
8863 if ((min_penalty_str = pbx_builtin_getvar_helper(chan, "QUEUE_MIN_PENALTY"))) {
8864 if (sscanf(min_penalty_str, "%30d", &min_penalty) == 1) {
8865 ast_debug(1, "%s: Got min penalty %d from ${QUEUE_MIN_PENALTY}.\n", ast_channel_name(chan), min_penalty);
8866 } else {
8867 ast_log(LOG_WARNING, "${QUEUE_MIN_PENALTY}: Invalid value (%s), channel %s.\n",
8868 min_penalty_str, ast_channel_name(chan));
8869 min_penalty = INT_MAX;
8870 }
8871 } else {
8872 min_penalty = INT_MAX;
8873 }
8874
8875 if ((raise_penalty_str = pbx_builtin_getvar_helper(chan, "QUEUE_RAISE_PENALTY"))) {
8876 if (*raise_penalty_str == 'r') {
8877 qe.raise_respect_min = 1;
8878 raise_penalty_str++;
8879 } else {
8880 qe.raise_respect_min = 0;
8881 }
8882 if (sscanf(raise_penalty_str, "%30d", &raise_penalty) == 1) {
8883 ast_debug(1, "%s: Got raise penalty %s%d from ${QUEUE_RAISE_PENALTY}.\n", ast_channel_name(chan), qe.raise_respect_min ? "r" : "", raise_penalty);
8884 } else {
8885 ast_log(LOG_WARNING, "${QUEUE_RAISE_PENALTY}: Invalid value (%s), channel %s.\n",
8886 raise_penalty_str, ast_channel_name(chan));
8887 raise_penalty = INT_MAX;
8888 }
8889 } else {
8890 raise_penalty = INT_MAX;
8891 }
8892 ast_channel_unlock(chan);
8893
8894 if (ast_test_flag(&opts, OPT_RINGING)) {
8895 ringing = 1;
8896 }
8897
8898 if (ringing != 1 && ast_test_flag(&opts, OPT_RING_WHEN_RINGING)) {
8899 qe.ring_when_ringing = 1;
8900 }
8901
8902 if (ast_test_flag(&opts, OPT_GO_ON)) {
8903 qcontinue = 1;
8904 }
8905
8906 if (args.position) {
8907 position = atoi(args.position);
8908 if (position < 0) {
8909 ast_log(LOG_WARNING, "Invalid position '%s' given for call to queue '%s'. Assuming no preference for position\n", args.position, args.queuename);
8910 position = 0;
8911 }
8912 }
8913
8914 ast_debug(1, "queue: %s, expires: %ld, priority: %d\n",
8915 args.queuename, (long)qe.expire, prio);
8916
8917 qe.chan = chan;
8918 qe.prio = prio;
8919 qe.max_penalty = max_penalty;
8920 qe.min_penalty = min_penalty;
8921 qe.raise_penalty = raise_penalty;
8922 qe.last_pos_said = 0;
8923 qe.last_pos = 0;
8926 qe.valid_digits = 0;
8927 if (join_queue(args.queuename, &qe, &reason, position)) {
8928 ast_log(LOG_WARNING, "Unable to join queue '%s'\n", args.queuename);
8929 set_queue_result(chan, reason);
8930 return 0;
8931 }
8932 ast_assert(qe.parent != NULL);
8933
8934 if (qe.parent->periodicannouncestartdelay >= 0) {
8937 }
8938
8940
8941 if (log_caller_id_name) {
8942 char *escaped_cidname = NULL;
8943 /* Ensure caller ID name is valid and not NULL before processing */
8944 if (cid_allow && ast_channel_caller(chan)->id.name.valid && ast_channel_caller(chan)->id.name.str) {
8945 escaped_cidname = ast_strdupa(ast_channel_caller(chan)->id.name.str);
8946 /* Only iterate if '|' is found */
8947 if (strchr(escaped_cidname, '|')) {
8948 for (char *p = escaped_cidname; *p; p++) {
8949 if (*p == '|') {
8950 *p = '_';
8951 }
8952 }
8953 }
8954 }
8955
8956 ast_queue_log(args.queuename, ast_channel_uniqueid(chan), "NONE", "ENTERQUEUE", "%s|%s|%d|%s",
8957 S_OR(args.url, ""),
8958 S_COR(cid_allow && ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, ""),
8959 qe.opos,
8960 S_OR(escaped_cidname, ""));
8961 } else {
8962 ast_queue_log(args.queuename, ast_channel_uniqueid(chan), "NONE", "ENTERQUEUE", "%s|%s|%d",
8963 S_OR(args.url, ""),
8964 S_COR(cid_allow && ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, ""),
8965 qe.opos);
8966 }
8967
8968 /* PREDIAL: Preprocess any callee gosub arguments. */
8970 && !ast_strlen_zero(opt_args[OPT_ARG_PREDIAL_CALLEE])) {
8973 }
8974
8975 /* PREDIAL: Run gosub on the caller's channel */
8977 && !ast_strlen_zero(opt_args[OPT_ARG_PREDIAL_CALLER])) {
8979 ast_app_exec_sub(NULL, chan, opt_args[OPT_ARG_PREDIAL_CALLER], 0);
8980 }
8981
8982 /* Music on hold class override */
8985 ast_copy_string(qe.moh, opt_args[OPT_ARG_MUSICONHOLD_CLASS], sizeof(qe.moh));
8986 }
8987
8988 copy_rules(&qe, args.rule);
8989 qe.pr = AST_LIST_FIRST(&qe.qe_rules);
8990check_turns:
8991 if (ringing) {
8993 } else {
8994 ast_moh_start(chan, qe.moh, NULL);
8995 }
8996
8997 /* This is the wait loop for callers 2 through maxlen */
8998 res = wait_our_turn(&qe, ringing, &reason);
8999 if (res) {
9000 goto stop;
9001 }
9002
9003 makeannouncement = qe.parent->announce_to_first_user;
9004
9005 for (;;) {
9006 /* This is the wait loop for the head caller*/
9007 /* To exit, they may get their call answered; */
9008 /* they may dial a digit from the queue context; */
9009 /* or, they may timeout. */
9010
9011 /* A request to withdraw this call from the queue arrived */
9012 if (qe.withdraw) {
9013 reason = QUEUE_WITHDRAW;
9014 res = 1;
9015 break;
9016 }
9017
9018 /* Leave if we have exceeded our queuetimeout */
9019 if (qe.expire && (time(NULL) >= qe.expire)) {
9020 record_abandoned(&qe);
9021 reason = QUEUE_TIMEOUT;
9022 res = 0;
9023 ast_queue_log(args.queuename, ast_channel_uniqueid(chan),"NONE", "EXITWITHTIMEOUT", "%d|%d|%ld",
9024 qe.pos, qe.opos, (long) (time(NULL) - qe.start));
9025 break;
9026 }
9027
9028 if (makeannouncement) {
9029 /* Make a position announcement, if enabled */
9030 if (qe.parent->announcefrequency) {
9031 if ((res = say_position(&qe, ringing))) {
9032 goto stop;
9033 }
9034 }
9035
9036 /* Make a periodic announcement, if enabled */
9038 if ((res = say_periodic_announcement(&qe, ringing))) {
9039 goto stop;
9040 }
9041 }
9042 }
9043
9044 /* A request to withdraw this call from the queue arrived */
9045 if (qe.withdraw) {
9046 reason = QUEUE_WITHDRAW;
9047 res = 1;
9048 break;
9049 }
9050
9051 /* Leave if we have exceeded our queuetimeout */
9052 if (qe.expire && (time(NULL) >= qe.expire)) {
9053 record_abandoned(&qe);
9054 reason = QUEUE_TIMEOUT;
9055 res = 0;
9056 ast_queue_log(args.queuename, ast_channel_uniqueid(chan), "NONE", "EXITWITHTIMEOUT",
9057 "%d|%d|%ld", qe.pos, qe.opos, (long) (time(NULL) - qe.start));
9058 break;
9059 }
9060
9061 /* see if we need to move to the next penalty level for this queue */
9062 while (qe.pr && ((time(NULL) - qe.start) > qe.pr->time)) {
9063 update_qe_rule(&qe);
9064 }
9065
9066 /* Try calling all queue members for 'timeout' seconds */
9067 res = try_calling(&qe, opts, opt_args, args.announceoverride, args.url, &tries, &noption, args.agi, args.gosub, ringing);
9068 if (res) {
9069 goto stop;
9070 }
9071
9072 if (qe.parent->leavewhenempty) {
9073 int status = 0;
9075 record_abandoned(&qe);
9076 reason = QUEUE_LEAVEEMPTY;
9077 ast_queue_log(args.queuename, ast_channel_uniqueid(chan), "NONE", "EXITEMPTY", "%d|%d|%ld", qe.pos, qe.opos, (long)(time(NULL) - qe.start));
9078 res = 0;
9079 break;
9080 }
9081 }
9082
9083 /* exit after 'timeout' cycle if 'n' option enabled */
9084 if (noption && tries >= ao2_container_count(qe.parent->members)) {
9085 ast_verb(3, "Exiting on time-out cycle\n");
9086 ast_queue_log(args.queuename, ast_channel_uniqueid(chan), "NONE", "EXITWITHTIMEOUT",
9087 "%d|%d|%ld", qe.pos, qe.opos, (long) (time(NULL) - qe.start));
9088 record_abandoned(&qe);
9089 reason = QUEUE_TIMEOUT;
9090 res = 0;
9091 break;
9092 }
9093
9094
9095 /* Leave if we have exceeded our queuetimeout */
9096 if (qe.expire && (time(NULL) >= qe.expire)) {
9097 record_abandoned(&qe);
9098 reason = QUEUE_TIMEOUT;
9099 res = 0;
9100 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));
9101 break;
9102 }
9103
9104 /* OK, we didn't get anybody; wait for 'retry' seconds; may get a digit to exit with */
9105 res = wait_a_bit(&qe);
9106 if (res) {
9107 goto stop;
9108 }
9109
9110 /* If using dynamic realtime members, we should regenerate the member list for this queue */
9112
9113 /* Since this is a priority queue and
9114 * it is not sure that we are still at the head
9115 * of the queue, go and check for our turn again.
9116 */
9117 if (!is_our_turn(&qe)) {
9118 ast_debug(1, "Darn priorities, going back in queue (%s)!\n", ast_channel_name(qe.chan));
9119 goto check_turns;
9120 }
9121 }
9122
9123stop:
9124 if (qe.chan) {
9127 /* 1. Handle QUEUEWAIT (Total time spent waiting in queue) */
9128 if (ast_strlen_zero(pbx_builtin_getvar_helper(qe.chan, "QUEUEWAIT"))) {
9129 set_duration_var(qe.chan, "QUEUEWAIT", (int64_t)(time(NULL) - qe.start) * 1000);
9130 }
9131
9132 /* 2. Handle DIALEDTIME (Total time spent from beginning of the call) */
9133 if (ast_strlen_zero(pbx_builtin_getvar_helper(qe.chan, "DIALEDTIME"))) {
9135 }
9136
9137 /* 3. Handle ANSWEREDTIME (Time spent talking to an agent) */
9138 if (ast_strlen_zero(pbx_builtin_getvar_helper(qe.chan, "ANSWEREDTIME"))) {
9139 /* If we are here and it's still empty, the call was never answered */
9140 set_duration_var(qe.chan, "ANSWEREDTIME", 0);
9141 }
9144 }
9145 if (res) {
9146 if (reason == QUEUE_WITHDRAW) {
9147 record_abandoned(&qe);
9148 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 : "");
9149 if (qe.withdraw_info) {
9150 pbx_builtin_setvar_helper(qe.chan, "QUEUE_WITHDRAW_INFO", qe.withdraw_info);
9151 }
9152 res = 0;
9153 } else if (res < 0) {
9154 if (!qe.handled) {
9155 record_abandoned(&qe);
9156 ast_queue_log(args.queuename, ast_channel_uniqueid(chan), "NONE", "ABANDON",
9157 "%d|%d|%ld", qe.pos, qe.opos,
9158 (long) (time(NULL) - qe.start));
9159 res = -1;
9160 } else if (reason == QUEUE_LEAVEEMPTY) {
9161 /* Return back to dialplan, don't hang up */
9162 res = 0;
9163 } else if (qcontinue) {
9164 reason = QUEUE_CONTINUE;
9165 res = 0;
9166 }
9167 } else if (qe.valid_digits) {
9168 ast_queue_log(args.queuename, ast_channel_uniqueid(chan), "NONE", "EXITWITHKEY",
9169 "%s|%d|%d|%ld", qe.digits, qe.pos, qe.opos, (long) (time(NULL) - qe.start));
9170 }
9171 }
9172
9173 /* Free the optional withdraw info if present */
9174 /* This is done here to catch all cases. e.g. if the call eventually wasn't withdrawn, e.g. answered */
9175 if (qe.withdraw_info) {
9177 qe.withdraw_info = NULL;
9178 }
9179
9180 /* Don't allow return code > 0 */
9181 if (res >= 0) {
9182 res = 0;
9183 if (ringing) {
9184 ast_indicate(chan, -1);
9185 } else {
9186 ast_moh_stop(chan);
9187 }
9188 ast_stopstream(chan);
9189 }
9190
9192
9193 leave_queue(&qe);
9194 if (reason != QUEUE_UNKNOWN)
9195 set_queue_result(chan, reason);
9196
9197 /*
9198 * every queue_ent is given a reference to it's parent
9199 * call_queue when it joins the queue. This ref must be taken
9200 * away right before the queue_ent is destroyed. In this case
9201 * the queue_ent is about to be returned on the stack
9202 */
9203 qe.parent = queue_unref(qe.parent);
9204
9205 return res;
9206}
static int is_our_turn(struct queue_ent *qe)
Check if we should start attempting to call queue members.
Definition app_queue.c:5921
static void record_abandoned(struct queue_ent *qe)
Record that a caller gave up on waiting in queue.
Definition app_queue.c:5255
static int log_caller_id_name
queues.conf [general] option
Definition app_queue.c:1766
static void set_queue_result(struct ast_channel *chan, enum queue_result res)
sets the QUEUESTATUS channel variable
Definition app_queue.c:2064
static void leave_queue(struct queue_ent *qe)
Caller leaving queue.
Definition app_queue.c:4546
static int say_periodic_announcement(struct queue_ent *qe, int ringing)
Playback announcement to queued members if period has elapsed.
Definition app_queue.c:5194
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:6060
static void copy_rules(struct queue_ent *qe, const char *rulename)
Copy rule from global list into specified queue.
Definition app_queue.c:8703
static const struct ast_app_option queue_exec_options[128]
Definition app_queue.c:1633
queue_result
Definition app_queue.c:1777
static void update_qe_rule(struct queue_ent *qe)
update rules for queues
Definition app_queue.c:5970
static int join_queue(char *queuename, struct queue_ent *qe, enum queue_result *reason, int position)
Definition app_queue.c:4233
static int say_position(struct queue_ent *qe, int ringing)
Definition app_queue.c:4381
static int wait_a_bit(struct queue_ent *qe)
Definition app_queue.c:7661
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:7191
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:1807
int ast_indicate(struct ast_channel *chan, int condition)
Indicates condition of channel.
Definition channel.c:4270
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.
int ast_max_forwards_get(struct ast_channel *chan)
Get the current max forwards for a particular channel.
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:7778
void ast_moh_stop(struct ast_channel *chan)
Turn off music on hold on a given channel.
Definition channel.c:7788
static char url[512]
Channel datastore data for max forwards.
Number structure.
char digits[AST_MAX_EXTENSION]
Definition app_queue.c:1849
int valid_digits
Definition app_queue.c:1851
time_t last_pos
Definition app_queue.c:1858
time_t last_periodic_announce_time
Definition app_queue.c:1856
time_t expire
Definition app_queue.c:1869
unsigned int withdraw
Definition app_queue.c:1871
int ring_when_ringing
Definition app_queue.c:1855
char * withdraw_info
Definition app_queue.c:1872
char moh[MAX_MUSICCLASS]
Definition app_queue.c:1846
int last_pos_said
Definition app_queue.c:1854
int last_periodic_announce_sound
Definition app_queue.c:1857
const char * predial_callee
Definition app_queue.c:1850
void ast_replace_subargument_delimiter(char *s)
Replace '^' in a string with ','.
Definition utils.c:2379

References call_queue::announce_to_first_user, call_queue::announcefrequency, ao2_container_count(), args, AST_APP_ARG, ast_app_exec_sub(), ast_app_parse_options(), ast_assert, ast_channel_caller(), ast_channel_get_duration_ms(), ast_channel_lock, ast_channel_name(), ast_channel_stage_snapshot(), ast_channel_stage_snapshot_done(), ast_channel_uniqueid(), ast_channel_unlock, AST_CONTROL_RINGING, ast_copy_string(), ast_debug, AST_DECLARE_APP_ARGS, ast_free, ast_indicate(), AST_LIST_FIRST, ast_log, ast_max_forwards_get(), ast_moh_start(), ast_moh_stop(), ast_party_id_presentation(), AST_PRES_ALLOWED, AST_PRES_RESTRICTION, ast_queue_log(), ast_replace_subargument_delimiter(), AST_STANDARD_APP_ARGS, ast_stopstream(), ast_strdupa, ast_strlen_zero(), ast_test_flag, ast_verb, queue_ent::chan, copy_rules(), queue_ent::digits, queue_ent::expire, get_member_status(), queue_ent::handled, ast_party_caller::id, is_our_turn(), join_queue(), queue_ent::last_periodic_announce_sound, queue_ent::last_periodic_announce_time, queue_ent::last_pos, queue_ent::last_pos_said, leave_queue(), call_queue::leavewhenempty, log_caller_id_name, call_queue::log_restricted_caller_id, LOG_WARNING, queue_ent::max_penalty, call_queue::members, queue_ent::min_penalty, queue_ent::moh, name, call_queue::name, ast_party_id::name, NULL, queue_ent::opos, OPT_ARG_ARRAY_SIZE, OPT_ARG_MUSICONHOLD_CLASS, OPT_ARG_PREDIAL_CALLEE, OPT_ARG_PREDIAL_CALLER, OPT_GO_ON, OPT_MUSICONHOLD_CLASS, OPT_PREDIAL_CALLEE, OPT_PREDIAL_CALLER, OPT_RING_WHEN_RINGING, OPT_RINGING, options, queue_ent::parent, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), call_queue::periodicannouncefrequency, call_queue::periodicannouncestartdelay, queue_ent::pos, queue_ent::pr, queue_ent::predial_callee, queue_ent::prio, queue_ent::qe_rules, QUEUE_CONTINUE, queue_exec_options, QUEUE_LEAVEEMPTY, QUEUE_TIMEOUT, QUEUE_UNKNOWN, queue_unref, QUEUE_WITHDRAW, queue_ent::raise_penalty, queue_ent::raise_respect_min, record_abandoned(), queue_ent::ring_when_ringing, ringing(), S_COR, S_OR, say_periodic_announcement(), say_position(), set_duration_var(), 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 9257 of file app_queue.c.

9258{
9259 struct call_queue *q;
9260
9261 buf[0] = '\0';
9262
9263 if (ast_strlen_zero(data)) {
9264 ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd);
9265 return -1;
9266 }
9268 snprintf(buf, len, "%d", q != NULL? 1 : 0);
9269 if (q) {
9270 queue_t_unref(q, "Done with temporary reference in QUEUE_EXISTS()");
9271 }
9272
9273 return 0;
9274}
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 9299 of file app_queue.c.

9300{
9301 int count = 0;
9302 struct member *m;
9303 struct ao2_iterator mem_iter;
9304 struct call_queue *q;
9305
9307 AST_APP_ARG(queuename);
9308 AST_APP_ARG(option);
9309 AST_APP_ARG(interface);
9310 );
9311 /* Make sure the returned value on error is zero length string. */
9312 buf[0] = '\0';
9313
9314 if (ast_strlen_zero(data)) {
9316 "Missing required argument. %s(<queuename>,<option>[,<interface>])\n",
9317 cmd);
9318 return -1;
9319 }
9320
9322
9323 if (ast_strlen_zero(args.queuename) || ast_strlen_zero(args.option)) {
9325 "Missing required argument. %s(<queuename>,<option>[,<interface>])\n",
9326 cmd);
9327 return -1;
9328 }
9329
9330 if ((q = find_load_queue_rt_friendly(args.queuename))) {
9331 ao2_lock(q);
9332 if (!strcasecmp(args.option, "logged")) {
9333 mem_iter = ao2_iterator_init(q->members, 0);
9334 while ((m = ao2_iterator_next(&mem_iter))) {
9335 /* Count the agents who are logged in and presently answering calls */
9336 if ((m->status != AST_DEVICE_UNAVAILABLE) && (m->status != AST_DEVICE_INVALID)) {
9337 count++;
9338 }
9339 ao2_ref(m, -1);
9340 }
9341 ao2_iterator_destroy(&mem_iter);
9342 } else if (!strcasecmp(args.option, "free")) {
9343 mem_iter = ao2_iterator_init(q->members, 0);
9344 while ((m = ao2_iterator_next(&mem_iter))) {
9345 /* Count the agents who are logged in and presently answering calls */
9346 if ((m->status == AST_DEVICE_NOT_INUSE) && (!m->paused)) {
9347 count++;
9348 }
9349 ao2_ref(m, -1);
9350 }
9351 ao2_iterator_destroy(&mem_iter);
9352 } else if (!strcasecmp(args.option, "ready")) {
9353 time_t now;
9354 time(&now);
9355 mem_iter = ao2_iterator_init(q->members, 0);
9356 while ((m = ao2_iterator_next(&mem_iter))) {
9357 /* Count the agents who are logged in, not paused and not wrapping up */
9358 if ((m->status == AST_DEVICE_NOT_INUSE) && (!m->paused) &&
9359 !(m->lastcall && get_wrapuptime(q, m) && ((now - get_wrapuptime(q, m)) < m->lastcall))) {
9360 count++;
9361 }
9362 ao2_ref(m, -1);
9363 }
9364 ao2_iterator_destroy(&mem_iter);
9365 } else if (!strcasecmp(args.option, "count")) {
9367 } else if (!strcasecmp(args.option, "penalty")) {
9368 m = get_interface_helper(q, args.interface);
9369 if (m) {
9370 count = m->penalty;
9371 ao2_ref(m, -1);
9372 }
9373 } else if (!strcasecmp(args.option, "paused")) {
9374 m = get_interface_helper(q, args.interface);
9375 if (m) {
9376 count = m->paused;
9377 ao2_ref(m, -1);
9378 }
9379 } else if ((!strcasecmp(args.option, "ignorebusy") /* ignorebusy is legacy */
9380 || !strcasecmp(args.option, "ringinuse"))) {
9381 m = get_interface_helper(q, args.interface);
9382 if (m) {
9383 count = m->ringinuse;
9384 ao2_ref(m, -1);
9385 }
9386 } else {
9387 ast_log(LOG_ERROR, "%s: Invalid option '%s' provided.\n", cmd, args.option);
9388 }
9389 ao2_unlock(q);
9390 queue_t_unref(q, "Done with temporary reference in QUEUE_MEMBER()");
9391 } else {
9392 ast_log(LOG_WARNING, "queue %s was not found\n", args.queuename);
9393 }
9394
9395 snprintf(buf, len, "%d", count);
9396
9397 return 0;
9398}
static struct member * get_interface_helper(struct call_queue *q, const char *interface)
Definition app_queue.c:9276

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

9402{
9403 int memvalue;
9404
9406 AST_APP_ARG(queuename);
9407 AST_APP_ARG(option);
9408 AST_APP_ARG(interface);
9409 );
9410
9411 if (ast_strlen_zero(data)) {
9413 "Missing required argument. %s([<queuename>],<option>,<interface>)\n",
9414 cmd);
9415 return -1;
9416 }
9417
9419
9420 if (ast_strlen_zero(args.option)
9421 || ast_strlen_zero(args.interface)) {
9423 "Missing required argument. %s([<queuename>],<option>,<interface>)\n",
9424 cmd);
9425 return -1;
9426 }
9427
9428 /*
9429 * If queuename is empty then the option will be
9430 * set for the interface in all queues.
9431 */
9432
9433 memvalue = atoi(value);
9434 if (!strcasecmp(args.option, "penalty")) {
9435 if (set_member_value(args.queuename, args.interface, MEMBER_PENALTY, memvalue)) {
9436 ast_log(LOG_ERROR, "Invalid interface, queue, or penalty\n");
9437 return -1;
9438 }
9439 } else if (!strcasecmp(args.option, "paused")) {
9440 memvalue = (memvalue <= 0) ? 0 : 1;
9441 if (set_member_paused(args.queuename, args.interface, NULL, memvalue)) {
9442 ast_log(LOG_ERROR, "Invalid interface or queue\n");
9443 return -1;
9444 }
9445 } else if (!strcasecmp(args.option, "ignorebusy") /* ignorebusy is legacy */
9446 || !strcasecmp(args.option, "ringinuse")) {
9447 memvalue = (memvalue <= 0) ? 0 : 1;
9448 if (set_member_value(args.queuename, args.interface, MEMBER_RINGINUSE, memvalue)) {
9449 ast_log(LOG_ERROR, "Invalid interface or queue\n");
9450 return -1;
9451 }
9452 } else {
9453 ast_log(LOG_ERROR, "%s: Invalid option '%s' provided.\n", cmd, args.option);
9454 return -1;
9455 }
9456 return 0;
9457}

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

9625{
9626 int penalty;
9628 AST_APP_ARG(queuename);
9629 AST_APP_ARG(interface);
9630 );
9631 /* Make sure the returned value on error is NULL. */
9632 buf[0] = '\0';
9633
9634 if (ast_strlen_zero(data)) {
9635 ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n");
9636 return -1;
9637 }
9638
9640
9641 if (args.argc < 2) {
9642 ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n");
9643 return -1;
9644 }
9645
9646 penalty = get_member_penalty (args.queuename, args.interface);
9647
9648 if (penalty >= 0) { /* remember that buf is already '\0' */
9649 snprintf (buf, len, "%d", penalty);
9650 }
9651
9652 return 0;
9653}
static int get_member_penalty(char *queuename, char *interface)
Gets members penalty.
Definition app_queue.c:8290

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

9657{
9658 int penalty;
9660 AST_APP_ARG(queuename);
9661 AST_APP_ARG(interface);
9662 );
9663
9664 if (ast_strlen_zero(data)) {
9665 ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n");
9666 return -1;
9667 }
9668
9670
9671 if (args.argc < 2) {
9672 ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n");
9673 return -1;
9674 }
9675
9676 penalty = atoi(value);
9677
9678 if (ast_strlen_zero(args.interface)) {
9679 ast_log (LOG_ERROR, "<interface> parameter can't be null\n");
9680 return -1;
9681 }
9682
9683 /* if queuename = NULL then penalty will be set for interface in all the queues. */
9684 if (set_member_value(args.queuename, args.interface, MEMBER_PENALTY, penalty)) {
9685 ast_log(LOG_ERROR, "Invalid interface, queue or penalty\n");
9686 return -1;
9687 }
9688
9689 return 0;
9690}

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

◆ queue_function_queuegetchannel()

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

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

Definition at line 9460 of file app_queue.c.

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

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, call_queue::count, call_queue::head, len(), LOG_ERROR, LOG_WARNING, call_queue::name, OBJ_POINTER, queue_t_unref, queues, SENTINEL, queue_ent::start, 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 9576 of file app_queue.c.

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

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

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

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

9214{
9215 int res = -1;
9216 struct call_queue *q;
9217 char interfacevar[256] = "";
9218 float sl = 0;
9219
9220 if (ast_strlen_zero(data)) {
9221 ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd);
9222 return -1;
9223 }
9224
9225 if ((q = find_load_queue_rt_friendly(data))) {
9226 ao2_lock(q);
9227 if (q->setqueuevar) {
9228 sl = 0;
9229 res = 0;
9230
9231 if (q->callscompleted > 0) {
9232 sl = 100 * ((float) q->callscompletedinsl / (float) q->callscompleted);
9233 }
9234
9235 snprintf(interfacevar, sizeof(interfacevar),
9236 "QUEUEMAX=%d,QUEUESTRATEGY=%s,QUEUECALLS=%d,QUEUEHOLDTIME=%d,QUEUETALKTIME=%d,QUEUECOMPLETED=%d,QUEUEABANDONED=%d,QUEUESRVLEVEL=%d,QUEUESRVLEVELPERF=%2.1f",
9238
9239 pbx_builtin_setvar_multiple(chan, interfacevar);
9240 }
9241
9242 ao2_unlock(q);
9243 queue_t_unref(q, "Done with QUEUE() function");
9244 } else {
9245 ast_log(LOG_WARNING, "queue %s was not found\n", data);
9246 }
9247
9248 snprintf(buf, len, "%d", res);
9249
9250 return 0;
9251}
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 2125 of file app_queue.c.

2126{
2127 const struct call_queue *q = obj;
2128
2129 return ast_str_case_hash(q->name);
2130}

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

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

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

2550{
2551 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}",
2552 "Queue", q->name,
2553 "MemberName", mem->membername,
2554 "Interface", mem->interface,
2555 "StateInterface", mem->state_interface,
2556 "Membership", (mem->dynamic ? "dynamic" : (mem->realtime ? "realtime" : "static")),
2557 "Penalty", mem->penalty,
2558 "CallsTaken", mem->calls,
2559 "LastCall", (int)mem->lastcall,
2560 "LastPause", (int)mem->lastpause,
2561 "LoginTime", (int)mem->logintime,
2562 "InCall", mem->starttime ? 1 : 0,
2563 "Status", mem->status,
2564 "Paused", mem->paused,
2565 "PausedReason", mem->reason_paused,
2566 "Ringinuse", mem->ringinuse,
2567 "Wrapuptime", mem->wrapuptime);
2568}

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

2160{
2161 struct member *mem = obj;
2162 int *decrement_followers_after = arg;
2163
2164 if (mem->queuepos > *decrement_followers_after) {
2165 mem->queuepos--;
2166 }
2167
2168 return 0;
2169}

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

2197{
2198 int pos = mem->queuepos;
2199
2200 /* 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
2201 * who would have been next otherwise. */
2202 if (pos < queue->rrpos) {
2203 queue->rrpos--;
2204 }
2205
2207}

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

2344{
2345 return queue_member_to_ami("QueueMemberPause", message);
2346}

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

2349{
2350 return queue_member_to_ami("QueueMemberPenalty", message);
2351}

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

2339{
2340 return queue_member_to_ami("QueueMemberRemoved", message);
2341}

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

2354{
2355 return queue_member_to_ami("QueueMemberRinginuse", message);
2356}

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

2329{
2330 return queue_member_to_ami("QueueMemberStatus", message);
2331}

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

2378{
2381 struct ast_channel_snapshot *agent;
2382 RAII_VAR(struct ast_str *, caller_event_string, NULL, ast_free);
2383 RAII_VAR(struct ast_str *, agent_event_string, NULL, ast_free);
2384 RAII_VAR(struct ast_str *, event_string, NULL, ast_free);
2385
2387 if (caller) {
2388 caller_event_string = ast_manager_build_channel_state_string(caller);
2389 if (!caller_event_string) {
2390 ast_log(LOG_NOTICE, "No caller event string, bailing\n");
2391 return NULL;
2392 }
2393 }
2394
2395 agent = ast_multi_channel_blob_get_channel(obj, "agent");
2396 if (agent) {
2397 agent_event_string = ast_manager_build_channel_state_string_prefix(agent, "Dest");
2398 if (!agent_event_string) {
2399 ast_log(LOG_NOTICE, "No agent event string, bailing\n");
2400 return NULL;
2401 }
2402 }
2403
2405 if (!event_string) {
2406 return NULL;
2407 }
2408
2410 "%s"
2411 "%s"
2412 "%s",
2413 caller_event_string ? ast_str_buffer(caller_event_string) : "",
2414 agent_event_string ? ast_str_buffer(agent_event_string) : "",
2415 ast_str_buffer(event_string));
2416}
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 2525 of file app_queue.c.

2526{
2527 RAII_VAR(struct ast_json_payload *, payload, NULL, ao2_cleanup);
2528 RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
2529
2530 if (!blob || !type) {
2531 ast_json_unref(blob);
2532 return;
2533 }
2534
2535 payload = ast_json_payload_create(blob);
2536 ast_json_unref(blob);
2537 if (!payload) {
2538 return;
2539 }
2540
2541 msg = stasis_message_create(type, payload);
2542 if (!msg) {
2543 return;
2544 }
2545
2547}
struct ast_json_payload * ast_json_payload_create(struct ast_json *json)
Create an ao2 object to pass json blobs as data payloads for stasis.
Definition json.c:756
struct stasis_message * stasis_message_create(struct stasis_message_type *type, void *data)
Create a new message.
void stasis_publish(struct stasis_topic *topic, struct stasis_message *message)
Publish a message to a topic's subscribers.
Definition stasis.c:1578

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

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

◆ queue_publish_multi_channel_blob()

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

Definition at line 2494 of file app_queue.c.

2496{
2497 RAII_VAR(struct ast_channel_snapshot *, caller_snapshot, NULL, ao2_cleanup);
2498 RAII_VAR(struct ast_channel_snapshot *, agent_snapshot, NULL, ao2_cleanup);
2499
2500 ast_channel_lock(caller);
2501 caller_snapshot = ast_channel_snapshot_create(caller);
2502 ast_channel_unlock(caller);
2503 ast_channel_lock(agent);
2504 agent_snapshot = ast_channel_snapshot_create(agent);
2505 ast_channel_unlock(agent);
2506
2507 if (!caller_snapshot || !agent_snapshot) {
2508 return;
2509 }
2510
2512 agent_snapshot, type, blob);
2513}
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:2459
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 2459 of file app_queue.c.

2463{
2464 RAII_VAR(struct ast_multi_channel_blob *, payload, NULL, ao2_cleanup);
2465 RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
2466
2467 if (!type) {
2468 return;
2469 }
2470
2471 payload = ast_multi_channel_blob_create(blob);
2472 if (!payload) {
2473 return;
2474 }
2475
2476 if (caller_snapshot) {
2477 ast_multi_channel_blob_add_channel(payload, "caller", caller_snapshot);
2478 } else {
2479 ast_debug(1, "Empty caller_snapshot; sending incomplete event\n");
2480 }
2481
2482 if (agent_snapshot) {
2483 ast_multi_channel_blob_add_channel(payload, "agent", agent_snapshot);
2484 }
2485
2486 msg = stasis_message_create(type, payload);
2487 if (!msg) {
2488 return;
2489 }
2490
2491 stasis_publish(topic, msg);
2492}
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 9809 of file app_queue.c.

9810{
9812 autofill_default = 0;
9813 montype_default = 0;
9814 shared_lastcall = 0;
9819}
static int montype_default
queues.conf [general] option
Definition app_queue.c:1745
static int negative_penalty_invalid
queues.conf [general] option
Definition app_queue.c:1757
static int shared_lastcall
queues.conf [general] option
Definition app_queue.c:1748
static int log_unpause_on_reason_change
queues.conf [general] option
Definition app_queue.c:1769

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

Referenced by reload_queues().

◆ queue_rules_reset_global_params()

static void queue_rules_reset_global_params ( void  )
static

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

Definition at line 9730 of file app_queue.c.

9731{
9732 realtime_rules = 0;
9733}
static int realtime_rules
queuerules.conf [general] option
Definition app_queue.c:1751

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

9737{
9738 const char *general_val = NULL;
9739 if ((general_val = ast_variable_retrieve(cfg, "general", "realtime_rules"))) {
9740 realtime_rules = ast_true(general_val);
9741 }
9742}

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

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

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

Referenced by reload_queues().

◆ queue_set_param()

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

Configure a queue parameter.

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

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

Definition at line 3506 of file app_queue.c.

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

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

10623{
10624 switch ( cmd ) {
10625 case CLI_INIT:
10626 e->command = "queue show";
10627 e->usage =
10628 "Usage: queue show\n"
10629 " Provides summary information on a specified queue.\n";
10630 return NULL;
10631 case CLI_GENERATE:
10632 return complete_queue_show(a->line, a->word, a->pos, a->n);
10633 }
10634
10635 return __queues_show(NULL, a->fd, a->argc, a->argv);
10636}
static char * complete_queue_show(const char *line, const char *word, int pos, int state)
static char * __queues_show(struct mansession *s, int fd, int argc, const char *const *argv)
Show queue(s) status and statistics.

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

6470{
6471 struct queue_stasis_data *queue_data;
6472
6473 queue_data = ao2_alloc(sizeof(*queue_data), queue_stasis_data_destructor);
6474 if (!queue_data) {
6475 return NULL;
6476 }
6477
6478 if (ast_string_field_init(queue_data, 64)) {
6479 ao2_cleanup(queue_data);
6480 return NULL;
6481 }
6482
6485 queue_data->queue = queue_ref(qe->parent);
6486 queue_data->starttime = starttime;
6487 queue_data->holdstart = holdstart;
6489 queue_data->caller_pos = qe->opos;
6490 ao2_ref(mem, +1);
6491 queue_data->member = mem;
6492
6493 return queue_data;
6494}
static void queue_stasis_data_destructor(void *obj)
Definition app_queue.c:6435

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

6436{
6437 struct queue_stasis_data *queue_data = obj;
6438
6439 /* This can only happen if refcounts for this object have got severely messed up */
6440 ast_assert(queue_data->bridge_router == NULL);
6441 ast_assert(queue_data->channel_router == NULL);
6442
6443 ao2_cleanup(queue_data->member);
6444 queue_unref(queue_data->queue);
6445 ast_string_field_free_memory(queue_data);
6446}
struct stasis_message_router * channel_router
Definition app_queue.c:6424
struct stasis_message_router * bridge_router
Definition app_queue.c:6422

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

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

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

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

References ao2_lock, ao2_unlock, and queue_ent::start.

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

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

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

12190{
12191 struct ast_flags mask = {AST_FLAGS_ALL & ~QUEUE_RESET_STATS,};
12192 ast_unload_realtime("queue_members");
12193 reload_handler(1, &mask, NULL);
12194 return 0;
12195}
int ast_unload_realtime(const char *family)
Release any resources cached for a realtime family.

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

10272{
10273 int res = 0;
10274
10275 if (ast_test_flag(mask, QUEUE_RELOAD_RULES)) {
10276 res |= reload_queue_rules(reload);
10277 }
10278 if (ast_test_flag(mask, QUEUE_RESET_STATS)) {
10279 res |= clear_stats(queuename);
10280 }
10282 res |= reload_queues(reload, mask, queuename);
10283 }
10284 return res;
10285}
static int reload_queues(int reload, struct ast_flags *mask, const char *queuename)
reload the queues.conf file
static int reload_queue_rules(int reload)
Reload the rules defined in queuerules.conf.
Definition app_queue.c:9750
static int clear_stats(const char *queuename)
Facilitates resetting statistics for a queue.
static int reload(void)

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

8322{
8323 char *cur_ptr;
8324 const char *queue_name;
8325 char *member;
8326 char *interface;
8327 char *membername = NULL;
8328 char *state_interface;
8329 char *penalty_tok;
8330 int penalty = 0;
8331 char *paused_tok;
8332 int paused = 0;
8333 char *wrapuptime_tok;
8334 int wrapuptime = 0;
8335 char *reason_paused;
8336 struct ast_db_entry *db_tree;
8337 struct ast_db_entry *entry;
8338 struct call_queue *cur_queue;
8339 char *queue_data;
8340
8341 /* Each key in 'pm_family' is the name of a queue */
8342 db_tree = ast_db_gettree(pm_family, NULL);
8343 for (entry = db_tree; entry; entry = entry->next) {
8344
8345 queue_name = entry->key + strlen(pm_family) + 2;
8346
8347 {
8348 struct call_queue tmpq = {
8349 .name = queue_name,
8350 };
8351 cur_queue = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Reload queue members");
8352 }
8353
8354 if (!cur_queue) {
8355 cur_queue = find_load_queue_rt_friendly(queue_name);
8356 }
8357
8358 if (!cur_queue) {
8359 /* If the queue no longer exists, remove it from the
8360 * database */
8361 ast_log(LOG_WARNING, "Error loading persistent queue: '%s': it does not exist\n", queue_name);
8362 ast_db_del(pm_family, queue_name);
8363 continue;
8364 }
8365
8366 if (ast_db_get_allocated(pm_family, queue_name, &queue_data)) {
8367 queue_t_unref(cur_queue, "Expire reload reference");
8368 continue;
8369 }
8370
8371 cur_ptr = queue_data;
8372 while ((member = strsep(&cur_ptr, ",|"))) {
8373 if (ast_strlen_zero(member)) {
8374 continue;
8375 }
8376
8377 interface = strsep(&member, ";");
8378 penalty_tok = strsep(&member, ";");
8379 paused_tok = strsep(&member, ";");
8380 membername = strsep(&member, ";");
8381 state_interface = strsep(&member, ";");
8382 reason_paused = strsep(&member, ";");
8383 wrapuptime_tok = strsep(&member, ";");
8384
8385 if (!penalty_tok) {
8386 ast_log(LOG_WARNING, "Error parsing persistent member string for '%s' (penalty)\n", queue_name);
8387 break;
8388 }
8389 penalty = strtol(penalty_tok, NULL, 10);
8390 if (errno == ERANGE) {
8391 ast_log(LOG_WARNING, "Error converting penalty: %s: Out of range.\n", penalty_tok);
8392 break;
8393 }
8394
8395 if (!paused_tok) {
8396 ast_log(LOG_WARNING, "Error parsing persistent member string for '%s' (paused)\n", queue_name);
8397 break;
8398 }
8399 paused = strtol(paused_tok, NULL, 10);
8400 if ((errno == ERANGE) || paused < 0 || paused > 1) {
8401 ast_log(LOG_WARNING, "Error converting paused: %s: Expected 0 or 1.\n", paused_tok);
8402 break;
8403 }
8404
8405 if (!ast_strlen_zero(wrapuptime_tok)) {
8406 wrapuptime = strtol(wrapuptime_tok, NULL, 10);
8407 if (errno == ERANGE) {
8408 ast_log(LOG_WARNING, "Error converting wrapuptime: %s: Out of range.\n", wrapuptime_tok);
8409 break;
8410 }
8411 }
8412
8413 ast_debug(1, "Reload Members: Queue: %s Member: %s Name: %s Penalty: %d Paused: %d ReasonPause: %s Wrapuptime: %d\n",
8414 queue_name, interface, membername, penalty, paused, reason_paused, wrapuptime);
8415
8416 if (add_to_queue(queue_name, interface, membername, penalty, paused, 0, state_interface, reason_paused, wrapuptime) == RES_OUTOFMEMORY) {
8417 ast_log(LOG_ERROR, "Out of Memory when reloading persistent queue member\n");
8418 break;
8419 }
8420 }
8421 queue_t_unref(cur_queue, "Expire reload reference");
8422 ast_free(queue_data);
8423 }
8424
8425 if (db_tree) {
8426 ast_log(LOG_NOTICE, "Queue members successfully reloaded from database.\n");
8427 ast_db_freetree(db_tree);
8428 }
8429}
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 9750 of file app_queue.c.

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

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

Referenced by reload_handler().

◆ reload_queues()

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

reload the queues.conf file

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

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

Definition at line 10184 of file app_queue.c.

10185{
10186 struct ast_config *cfg;
10187 char *cat;
10188 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
10189 const int queue_reload = ast_test_flag(mask, QUEUE_RELOAD_PARAMETERS);
10190
10191 if (!(cfg = ast_config_load("queues.conf", config_flags))) {
10192 ast_log(LOG_NOTICE, "No call queueing config file (queues.conf), so no call queues\n");
10193 return -1;
10194 } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
10195 return 0;
10196 } else if (cfg == CONFIG_STATUS_FILEINVALID) {
10197 ast_log(LOG_ERROR, "Config file queues.conf is in an invalid format. Aborting.\n");
10198 return -1;
10199 }
10200
10201 /* We've made it here, so it looks like we're doing operations on all queues. */
10203
10204 /* Mark non-realtime queues not found at the beginning. */
10205 ao2_callback(queues, OBJ_NODATA, mark_unfound, (char *) queuename);
10206
10207 /* Chug through config file. */
10208 cat = NULL;
10210 while ((cat = ast_category_browse(cfg, cat)) ) {
10211 if (!strcasecmp(cat, "general") && queue_reload) {
10213 continue;
10214 }
10215 if (ast_strlen_zero(queuename) || !strcasecmp(cat, queuename))
10216 reload_single_queue(cfg, mask, cat);
10217 }
10218
10219 ast_config_destroy(cfg);
10220 if (queue_reload) {
10221 /* Unlink and mark dead all non-realtime queues that were not found in the configuration file. */
10223 }
10225 return 0;
10226}
static void queue_reset_global_params(void)
Definition app_queue.c:9809
static void reload_single_queue(struct ast_config *cfg, struct ast_flags *mask, const char *queuename)
Reload information pertaining to a particular queue.
static void queue_set_global_params(struct ast_config *cfg)
Definition app_queue.c:9822
static int mark_unfound(void *obj, void *arg, int flags)
static int kill_if_unfound(void *obj, void *arg, int flags)

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

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

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

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

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, ast_variable::next, 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 7756 of file app_queue.c.

7757{
7758 struct call_queue *q, tmpq = {
7759 .name = queuename,
7760 };
7761 struct member *mem, tmpmem;
7762 int res = RES_NOSUCHQUEUE;
7763
7764 ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface));
7765 if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Temporary reference for interface removal"))) {
7766 ao2_lock(q);
7767 if ((mem = ao2_find(q->members, &tmpmem, OBJ_POINTER))) {
7768 /* XXX future changes should beware of this assumption!! */
7769 /*Change Penalty on realtime users*/
7771 update_realtime_member_field(mem, q->name, "penalty", "-1");
7772 } else if (!mem->dynamic) {
7773 ao2_ref(mem, -1);
7774 ao2_unlock(q);
7775 queue_t_unref(q, "Interface wasn't dynamic, expiring temporary reference");
7776 return RES_NOT_DYNAMIC;
7777 }
7778 queue_publish_member_blob(queue_member_removed_type(), queue_member_blob_create(q, mem));
7779
7781 ao2_ref(mem, -1);
7782
7785 }
7786
7787 if (!num_available_members(q)) {
7789 }
7790
7791 res = RES_OKAY;
7792 } else {
7793 res = RES_EXISTS;
7794 }
7795 ao2_unlock(q);
7796 queue_t_unref(q, "Expiring temporary reference");
7797 }
7798
7799 return res;
7800}
static int update_realtime_member_field(struct member *mem, const char *queue_name, const char *field, const char *value)
Definition app_queue.c:4158
char rt_uniqueid[80]
Definition app_queue.c:1903

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

6453{
6454 SCOPED_AO2LOCK(lock, queue_data);
6455
6456 queue_data->dying = 1;
6458 queue_data->bridge_router = NULL;
6460 queue_data->channel_router = NULL;
6461}
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 7938 of file app_queue.c.

7939{
7940 struct call_queue *q;
7941 struct queue_ent *qe;
7942 int res = RES_NOSUCHQUEUE;
7943
7944 /*! \note Ensure the appropriate realtime queue is loaded. Note that this
7945 * short-circuits if the queue is already in memory. */
7947 return res;
7948 }
7949
7950 ao2_lock(q);
7952 for (qe = q->head; qe; qe = qe->next) {
7953 if (!strcmp(ast_channel_name(qe->chan), caller)) {
7954 if (qe->withdraw) {
7955 ast_debug(1, "Ignoring duplicate withdraw request of caller %s from queue %s\n", caller, queuename);
7956 res = RES_EXISTS;
7957 } else {
7958 ast_debug(1, "Requested withdraw of caller %s from queue %s\n", caller, queuename);
7959 /* It is not possible to change the withdraw info by further withdraw requests for this caller (channel)
7960 in this queue, so we do not need to worry about a memory leak here. */
7961 if (withdraw_info) {
7962 qe->withdraw_info = ast_strdup(withdraw_info);
7963 }
7964 qe->withdraw = 1;
7965 res = RES_OKAY;
7966 }
7967 break;
7968 }
7969 }
7970 ao2_unlock(q);
7971 queue_unref(q);
7972
7973 return res;
7974}

References ao2_lock, ao2_unlock, ast_channel_name(), ast_debug, ast_strdup, find_load_queue_rt_friendly(), call_queue::head, queue_unref, RES_EXISTS, RES_NOSUCHQUEUE, RES_NOT_CALLER, RES_OKAY, queue_ent::start, 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 4929 of file app_queue.c.

4930{
4931 int res;
4932 int status;
4933 char tech[256];
4934 char *location;
4935 struct ast_format_cap *nativeformats;
4936 RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
4937
4938 /* on entry here, we know that tmp->chan == NULL */
4939 if (!can_ring_entry(qe, tmp)) {
4940 tmp->stillgoing = 0;
4941 ++*busies;
4942 return 0;
4943 }
4944
4945 ast_copy_string(tech, tmp->interface, sizeof(tech));
4946 if ((location = strchr(tech, '/'))) {
4947 *location++ = '\0';
4948 } else {
4949 location = "";
4950 }
4951
4953 nativeformats = ao2_bump(ast_channel_nativeformats(qe->chan));
4955
4956 /* Request the peer */
4957 tmp->chan = ast_request(tech, nativeformats, NULL, qe->chan, location, &status);
4958 ao2_cleanup(nativeformats);
4959 if (!tmp->chan) { /* If we can't, just go on to the next call */
4960 ao2_lock(qe->parent);
4961 qe->parent->rrpos++;
4962 qe->linpos++;
4963 ao2_unlock(qe->parent);
4964
4966
4967 publish_dial_end_event(qe->chan, tmp, NULL, "BUSY");
4968 tmp->stillgoing = 0;
4969 ++*busies;
4970 return 0;
4971 }
4972
4973 ast_channel_lock_both(tmp->chan, qe->chan);
4974
4977 if (qe->cancel_answered_elsewhere) {
4979 }
4980 ast_channel_appl_set(tmp->chan, "AppQueue");
4981 ast_channel_data_set(tmp->chan, "(Outgoing Line)");
4982 memset(ast_channel_whentohangup(tmp->chan), 0, sizeof(*ast_channel_whentohangup(tmp->chan)));
4983
4984 /* If the new channel has no callerid, try to guess what it should be */
4985 if (!ast_channel_caller(tmp->chan)->id.number.valid) {
4987 struct ast_party_caller caller;
4988
4990 caller.id = ast_channel_connected(qe->chan)->id;
4991 caller.ani = ast_channel_connected(qe->chan)->ani;
4992 ast_channel_set_caller_event(tmp->chan, &caller, NULL);
4993 } else if (!ast_strlen_zero(ast_channel_dialed(qe->chan)->number.str)) {
4995 } else if (!ast_strlen_zero(ast_channel_exten(qe->chan))) {
4997 }
4998 tmp->dial_callerid_absent = 1;
4999 }
5000
5002
5004
5006
5007 /* Inherit specially named variables from parent channel */
5011
5012 /* Presense of ADSI CPE on outgoing channel follows ours */
5014
5015 /* Inherit context and extension */
5016 ast_channel_dialcontext_set(tmp->chan, ast_channel_context(qe->chan));
5018
5019 /* Save the original channel name to detect call pickup masquerading in. */
5021
5024
5025 /* location is tmp->interface where tech/ has been stripped, so it follow the same syntax as DIALEDPEERNUMBER in app_dial.c */
5026 pbx_builtin_setvar_helper(tmp->chan, "DIALEDPEERNUMBER", strlen(location) ? location : tmp->interface);
5027
5028 /* PREDIAL: Run gosub on the callee's channel */
5029 if (qe->predial_callee) {
5030 ast_pre_call(tmp->chan, qe->predial_callee);
5031 }
5032
5033 /* Place the call, but don't wait on the answer */
5034 if ((res = ast_call(tmp->chan, location, 0))) {
5035 /* Again, keep going even if there's an error */
5036 ast_verb(3, "Couldn't call %s\n", tmp->interface);
5037 do_hang(tmp);
5038 ++*busies;
5039 return 0;
5040 }
5041
5042 ast_channel_lock_both(tmp->chan, qe->chan);
5043
5044 blob = ast_json_pack("{s: s, s: s, s: s}",
5045 "Queue", qe->parent->name,
5046 "Interface", tmp->interface,
5047 "MemberName", tmp->member->membername);
5048 queue_publish_multi_channel_blob(qe->chan, tmp->chan, queue_agent_called_type(), blob);
5049
5051
5054
5055 ast_verb(3, "Called %s\n", tmp->interface);
5056
5057 return 1;
5058}
static void do_hang(struct callattempt *o)
common hangup actions
Definition app_queue.c:4803
static int can_ring_entry(struct queue_ent *qe, struct callattempt *call)
Definition app_queue.c:4833
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:2494
static void publish_dial_end_event(struct ast_channel *in, struct callattempt *outgoing, struct ast_channel *exception, const char *status)
Definition app_queue.c:4631
#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:6456
@ AST_CHANNEL_REQUESTOR_BRIDGE_PEER
Definition channel.h:1525
void ast_channel_set_caller_event(struct ast_channel *chan, const struct ast_party_caller *caller, const struct ast_set_party_caller *update)
Set the caller id information in the Asterisk channel and generate an AMI event if the caller id name...
Definition channel.c:7384
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:2989
int ast_channel_datastore_inherit(struct ast_channel *from, struct ast_channel *to)
Inherit datastores from a parent to a child.
Definition channel.c:2358
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:1985
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:7346
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:6771
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:8337
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:6434
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:6439
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:6349
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:2121
int ast_max_forwards_decrement(struct ast_channel *chan)
Decrement the max forwards count for a particular channel.
Format capabilities structure, holds formats + preference order + etc.
Definition format_cap.c:54
Caller Party information.
Definition channel.h:420
struct ast_party_id ani
Automatic Number Identification (ANI)
Definition channel.h:467
char * str
Subscriber phone number (Malloced)
Definition channel.h:388
struct ast_party_dialed::@221 number
Dialed/Called number.
int transit_network_select
Transit Network Select.
Definition channel.h:399
unsigned int dial_callerid_absent
Definition app_queue.c:1835
char interface[256]
Definition app_queue.c:1825
int cancel_answered_elsewhere
Definition app_queue.c:1870

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

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

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

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

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

8505{
8506 int res=-1;
8507 char *parse, *temppos = NULL;
8508 struct member *mem = NULL;
8509
8511 AST_APP_ARG(queuename);
8513 );
8514
8515
8516 if (ast_strlen_zero(data)) {
8517 ast_log(LOG_WARNING, "RemoveQueueMember requires an argument (queuename[,interface])\n");
8518 return -1;
8519 }
8520
8521 parse = ast_strdupa(data);
8522
8524
8525 if (ast_strlen_zero(args.interface)) {
8526 args.interface = ast_strdupa(ast_channel_name(chan));
8527 temppos = strrchr(args.interface, '-');
8528 if (temppos) {
8529 *temppos = '\0';
8530 }
8531 }
8532
8533 ast_debug(1, "queue: %s, member: %s\n", args.queuename, args.interface);
8534
8536 mem = find_member_by_queuename_and_interface(args.queuename, args.interface);
8537 }
8538
8539 switch (remove_from_queue(args.queuename, args.interface)) {
8540 case RES_OKAY:
8541 if (!mem || ast_strlen_zero(mem->membername)) {
8542 ast_queue_log(args.queuename, ast_channel_uniqueid(chan), args.interface, "REMOVEMEMBER", "%s", "");
8543 } else {
8544 ast_queue_log(args.queuename, ast_channel_uniqueid(chan), mem->membername, "REMOVEMEMBER", "%s", "");
8545 }
8546 ast_log(LOG_NOTICE, "Removed interface '%s' from queue '%s'\n", args.interface, args.queuename);
8547 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "REMOVED");
8548 res = 0;
8549 break;
8550 case RES_EXISTS:
8551 ast_debug(1, "Unable to remove interface '%s' from queue '%s': Not there\n", args.interface, args.queuename);
8552 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOTINQUEUE");
8553 res = 0;
8554 break;
8555 case RES_NOSUCHQUEUE:
8556 ast_log(LOG_WARNING, "Unable to remove interface from queue '%s': No such queue\n", args.queuename);
8557 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOSUCHQUEUE");
8558 res = 0;
8559 break;
8560 case RES_NOT_DYNAMIC:
8561 ast_log(LOG_WARNING, "Unable to remove interface from queue '%s': '%s' is not a dynamic member\n", args.queuename, args.interface);
8562 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOTDYNAMIC");
8563 res = 0;
8564 break;
8565 }
8566
8567 if (mem) {
8568 ao2_ref(mem, -1);
8569 }
8570
8571 return res;
8572}

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

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

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

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

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

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

References ANNOUNCEHOLDTIME_ONCE, ANNOUNCEPOSITION_LIMIT, ANNOUNCEPOSITION_MORE_THAN, ANNOUNCEPOSITION_YES, 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, NULL, play_file(), ringing(), 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 6305 of file app_queue.c.

6308{
6309 const char *reason = NULL; /* silence dumb compilers */
6310 RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
6311
6312 switch (rsn) {
6313 case CALLER:
6314 reason = "caller";
6315 break;
6316 case AGENT:
6317 reason = "agent";
6318 break;
6319 case TRANSFER:
6320 reason = "transfer";
6321 break;
6322 }
6323
6324 blob = ast_json_pack("{s: s, s: s, s: s, s: I, s: I, s: s}",
6325 "Queue", queuename,
6326 "Interface", member->interface,
6327 "MemberName", member->membername,
6328 "HoldTime", (ast_json_int_t)(callstart - holdstart),
6329 "TalkTime", (ast_json_int_t)(time(NULL) - callstart),
6330 "Reason", reason ?: "");
6331
6333 queue_agent_complete_type(), blob);
6334}
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_duration_var()

static void set_duration_var ( struct ast_channel chan,
const char *  var_base,
int64_t  duration 
)
static

Definition at line 7016 of file app_queue.c.

7017{
7018 char buf[32];
7019 char full_var_name[128];
7020
7021 snprintf(buf, sizeof(buf), "%" PRId64, duration / 1000);
7022 pbx_builtin_setvar_helper(chan, var_base, buf);
7023
7024 snprintf(full_var_name, sizeof(full_var_name), "%s_MS", var_base);
7025 snprintf(buf, sizeof(buf), "%" PRId64, duration);
7026 pbx_builtin_setvar_helper(chan, full_var_name, buf);
7027}

References buf, and pbx_builtin_setvar_helper().

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

◆ set_member_paused()

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

Definition at line 8073 of file app_queue.c.

8074{
8075 int found = 0;
8076 struct call_queue *q;
8077 struct ao2_iterator queue_iter;
8078
8079 if (ast_check_realtime("queues")) {
8080 load_realtime_queues(queuename);
8081 }
8082
8083 queue_iter = ao2_iterator_init(queues, 0);
8084 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate over queues"))) {
8085 ao2_lock(q);
8086 if (ast_strlen_zero(queuename) || !strcasecmp(q->name, queuename)) {
8087 struct member *mem;
8088
8089 if ((mem = interface_exists(q, interface))) {
8090 /*
8091 * Before we do the PAUSE/UNPAUSE, log if this was a
8092 * PAUSEALL/UNPAUSEALL but only on the first found entry.
8093 */
8094 ++found;
8095 if (found == 1
8096 && ast_strlen_zero(queuename)) {
8097 /*
8098 * XXX In all other cases, we use the queue name,
8099 * but since this affects all queues, we cannot.
8100 */
8101 ast_queue_log("NONE", "NONE", mem->membername,
8102 (paused ? "PAUSEALL" : "UNPAUSEALL"), "%s", S_OR(reason, ""));
8103 }
8104
8105 set_queue_member_pause(q, mem, reason, paused);
8106 ao2_ref(mem, -1);
8107 }
8108
8109 if (!ast_strlen_zero(queuename)) {
8110 ao2_unlock(q);
8111 queue_t_unref(q, "Done with iterator");
8112 break;
8113 }
8114 }
8115
8116 ao2_unlock(q);
8117 queue_t_unref(q, "Done with iterator");
8118 }
8119 ao2_iterator_destroy(&queue_iter);
8120
8121 return found ? RESULT_SUCCESS : RESULT_FAILURE;
8122}
static void set_queue_member_pause(struct call_queue *q, struct member *mem, const char *reason, int paused)
Definition app_queue.c:8001

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

8134{
8135 struct member *mem;
8136 int foundinterface = 0;
8137
8138 ao2_lock(q);
8139 if ((mem = interface_exists(q, interface))) {
8140 foundinterface++;
8141 if (mem->realtime) {
8142 char rtpenalty[80];
8143
8144 sprintf(rtpenalty, "%i", penalty);
8145 update_realtime_member_field(mem, q->name, "penalty", rtpenalty);
8146 }
8147
8148 mem->penalty = penalty;
8149
8150 ast_queue_log(q->name, "NONE", interface, "PENALTY", "%d", penalty);
8151 queue_publish_member_blob(queue_member_penalty_type(), queue_member_blob_create(q, mem));
8152 ao2_ref(mem, -1);
8153 }
8154 ao2_unlock(q);
8155
8156 return foundinterface;
8157}

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

8183{
8184 struct member *mem;
8185 int foundinterface = 0;
8186
8187 ao2_lock(q);
8188 if ((mem = interface_exists(q, interface))) {
8189 foundinterface++;
8191 ao2_ref(mem, -1);
8192 }
8193 ao2_unlock(q);
8194
8195 return foundinterface;
8196}
static void set_queue_member_ringinuse(struct call_queue *q, struct member *mem, int ringinuse)
Definition app_queue.c:8169

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

8222{
8223 int foundinterface = 0, foundqueue = 0;
8224 struct call_queue *q;
8225 struct ast_config *queue_config = NULL;
8226 struct ao2_iterator queue_iter;
8227
8228 /* property dependent restrictions on values should be checked in this switch */
8229 switch (property) {
8230 case MEMBER_PENALTY:
8231 if (value < 0 && !negative_penalty_invalid) {
8232 ast_log(LOG_ERROR, "Invalid penalty (%d)\n", value);
8233 return RESULT_FAILURE;
8234 }
8235 }
8236
8237 if (ast_strlen_zero(queuename)) { /* This means we need to iterate through all the queues. */
8238 if (ast_check_realtime("queues")) {
8239 queue_config = ast_load_realtime_multientry("queues", "name LIKE", "%", SENTINEL);
8240 if (queue_config) {
8241 char *category = NULL;
8242 while ((category = ast_category_browse(queue_config, category))) {
8243 const char *name = ast_variable_retrieve(queue_config, category, "name");
8244 if (ast_strlen_zero(name)) {
8245 ast_log(LOG_WARNING, "Ignoring realtime queue with a NULL or empty 'name.'\n");
8246 continue;
8247 }
8248 if ((q = find_load_queue_rt_friendly(name))) {
8249 foundqueue++;
8250 foundinterface += set_member_value_help_members(q, interface, property, value);
8251 queue_unref(q);
8252 }
8253 }
8254
8255 ast_config_destroy(queue_config);
8256 }
8257 }
8258
8259 /* After hitting realtime queues, go back and get the regular ones. */
8260 queue_iter = ao2_iterator_init(queues, 0);
8261 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
8262 foundqueue++;
8263 foundinterface += set_member_value_help_members(q, interface, property, value);
8264 queue_unref(q);
8265 }
8266 ao2_iterator_destroy(&queue_iter);
8267 } else { /* We actually have a queuename, so we can just act on the single queue. */
8268 if ((q = find_load_queue_rt_friendly(queuename))) {
8269 foundqueue++;
8270 foundinterface += set_member_value_help_members(q, interface, property, value);
8271 queue_unref(q);
8272 }
8273 }
8274
8275 if (foundinterface) {
8276 return RESULT_SUCCESS;
8277 } else if (!foundqueue) {
8278 ast_log (LOG_ERROR, "Invalid queuename\n");
8279 } else {
8280 ast_log (LOG_ERROR, "Invalid interface\n");
8281 }
8282
8283 return RESULT_FAILURE;
8284}
static int set_member_value_help_members(struct call_queue *q, const char *interface, int property, int value)
Definition app_queue.c:8198

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

8199{
8200 switch(property) {
8201 case MEMBER_PENALTY:
8202 return set_member_penalty_help_members(q, interface, value);
8203
8204 case MEMBER_RINGINUSE:
8205 return set_member_ringinuse_help_members(q, interface, value);
8206
8207 default:
8208 ast_log(LOG_ERROR, "Attempted to set invalid property\n");
8209 return 0;
8210 }
8211}
static int set_member_ringinuse_help_members(struct call_queue *q, const char *interface, int ringinuse)
Definition app_queue.c:8182
static int set_member_penalty_help_members(struct call_queue *q, const char *interface, int penalty)
Definition app_queue.c:8133

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

8002{
8003 if (mem->paused == paused) {
8004 ast_debug(1, "%spausing already-%spaused queue member %s:%s\n",
8005 (paused ? "" : "un"), (paused ? "" : "un"), q->name, mem->interface);
8006 if (log_unpause_on_reason_change && paused) {
8007 if (!ast_strings_equal(mem->reason_paused, reason)) {
8008 ast_queue_log(q->name, "NONE", mem->membername, "UNPAUSE", "%s", "Auto-Unpause");
8009 }
8010 }
8011 }
8012
8013 if (mem->realtime && !ast_strlen_zero(mem->rt_uniqueid)) {
8015 if (ast_update_realtime("queue_members", "uniqueid", mem->rt_uniqueid, "reason_paused", S_OR(reason, ""), "paused", paused ? "1" : "0", SENTINEL) < 0) {
8016 ast_log(LOG_WARNING, "Failed update of realtime queue member %s:%s %spause and reason '%s'\n",
8017 q->name, mem->interface, (paused ? "" : "un"), S_OR(reason, ""));
8018 }
8019 } else {
8020 if (ast_update_realtime("queue_members", "uniqueid", mem->rt_uniqueid, "paused", paused ? "1" : "0", SENTINEL) < 0) {
8021 ast_log(LOG_WARNING, "Failed %spause update of realtime queue member %s:%s\n",
8022 (paused ? "" : "un"), q->name, mem->interface);
8023 }
8024 }
8025 }
8026
8027 mem->paused = paused;
8028 if (paused) {
8029 time(&mem->lastpause); /* update last pause field */
8030 }
8031 if (paused && !ast_strlen_zero(reason)) {
8032 ast_copy_string(mem->reason_paused, reason, sizeof(mem->reason_paused));
8033 } else {
8034 /* We end up filling this in again later (temporarily) but we need it
8035 * empty for now so that the intervening code - specifically
8036 * dump_queue_members() - has the correct view of things. */
8037 mem->reason_paused[0] = '\0';
8038 }
8039
8041 AST_DEVSTATE_CACHABLE, "Queue:%s_pause_%s", q->name, mem->interface);
8042
8045 }
8046
8047 if (is_member_available(q, mem)) {
8049 "Queue:%s_avail", q->name);
8050 } else if (!num_available_members(q)) {
8052 "Queue:%s_avail", q->name);
8053 }
8054
8055 if (!paused && !ast_strlen_zero(reason)) {
8056 /* Because we've been unpaused with a 'reason' we need to ensure that
8057 * that reason is emitted when the subsequent PauseQueueMember event
8058 * is raised. So temporarily set it on the member and clear it out
8059 * again right after. */
8060 ast_copy_string(mem->reason_paused, reason, sizeof(mem->reason_paused));
8061 }
8062
8063 ast_queue_log(q->name, "NONE", mem->membername, paused ? "PAUSE" : "UNPAUSE",
8064 "%s", mem->reason_paused);
8065
8067
8068 if (!paused) {
8069 mem->reason_paused[0] = '\0';
8070 }
8071}
static int publish_queue_member_pause(struct call_queue *q, struct member *member)
Definition app_queue.c:7977
int ast_update_realtime(const char *family, const char *keyfield, const char *lookup,...) attribute_sentinel
Update realtime configuration.
int ast_strings_equal(const char *str1, const char *str2)
Compare strings for equality checking for NULL.
Definition strings.c:238

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

Referenced by set_member_paused().

◆ set_queue_member_ringinuse()

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

Definition at line 8169 of file app_queue.c.

8170{
8171 if (mem->realtime) {
8173 ringinuse ? "1" : "0");
8174 }
8175
8176 mem->ringinuse = ringinuse;
8177
8178 ast_queue_log(q->name, "NONE", mem->interface, "RINGINUSE", "%d", ringinuse);
8179 queue_publish_member_blob(queue_member_ringinuse_type(), queue_member_blob_create(q, mem));
8180}

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

2065{
2066 int i;
2067
2068 for (i = 0; i < ARRAY_LEN(queue_results); i++) {
2069 if (queue_results[i].id == res) {
2070 pbx_builtin_setvar_helper(chan, "QUEUESTATUS", queue_results[i].text);
2071 return;
2072 }
2073 }
2074}
char * text
Definition app_queue.c:1791
static const struct @51 queue_results[]

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

2218{
2219 char interfacevar[256]="";
2220 float sl = 0;
2221
2222 ao2_lock(q);
2223
2224 if (q->setqueuevar) {
2225 sl = 0;
2226 if (q->callscompleted > 0) {
2227 sl = 100 * ((float) q->callscompletedinsl / (float) q->callscompleted);
2228 }
2229
2230 snprintf(interfacevar, sizeof(interfacevar),
2231 "QUEUENAME=%s,QUEUEMAX=%d,QUEUESTRATEGY=%s,QUEUECALLS=%d,QUEUEHOLDTIME=%d,QUEUETALKTIME=%d,QUEUECOMPLETED=%d,QUEUEABANDONED=%d,QUEUESRVLEVEL=%d,QUEUESRVLEVELPERF=%2.1f",
2233
2234 ao2_unlock(q);
2235
2236 pbx_builtin_setvar_multiple(chan, interfacevar);
2237 } else {
2238 ao2_unlock(q);
2239 }
2240}

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

7119{
7120 char escaped_filename[256];
7121 char file_with_ext[sizeof(escaped_filename) + sizeof(qe->parent->monfmt)];
7122 char mixmonargs[1512];
7123 char escaped_monitor_exec[1024];
7124 const char *monitor_options;
7125 const char *monitor_exec;
7126
7127 escaped_monitor_exec[0] = '\0';
7128
7129 if (filename) {
7130 escape_and_substitute(qe->chan, filename, escaped_filename, sizeof(escaped_filename));
7131 } else {
7132 ast_copy_string(escaped_filename, ast_channel_uniqueid(qe->chan), sizeof(escaped_filename));
7133 }
7134
7136 if ((monitor_exec = pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC"))) {
7137 monitor_exec = ast_strdupa(monitor_exec);
7138 }
7139 if ((monitor_options = pbx_builtin_getvar_helper(qe->chan, "MONITOR_OPTIONS"))) {
7140 monitor_options = ast_strdupa(monitor_options);
7141 } else {
7142 monitor_options = "";
7143 }
7145
7146 if (monitor_exec) {
7147 escape_and_substitute(qe->chan, monitor_exec, escaped_monitor_exec, sizeof(escaped_monitor_exec));
7148 }
7149
7150 snprintf(file_with_ext, sizeof(file_with_ext), "%s.%s", escaped_filename, qe->parent->monfmt);
7151
7152 if (!ast_strlen_zero(escaped_monitor_exec)) {
7153 snprintf(mixmonargs, sizeof(mixmonargs), "b%s,%s", monitor_options, escaped_monitor_exec);
7154 } else {
7155 snprintf(mixmonargs, sizeof(mixmonargs), "b%s", monitor_options);
7156 }
7157
7158 ast_debug(1, "Arguments being passed to MixMonitor: %s,%s\n", file_with_ext, mixmonargs);
7159
7160 if (ast_start_mixmonitor(qe->chan, file_with_ext, mixmonargs)) {
7161 ast_log(LOG_WARNING, "Unable to start mixmonitor. Is the MixMonitor app loaded?\n");
7162 }
7163}
static void escape_and_substitute(struct ast_channel *chan, const char *input, char *output, size_t size)
Definition app_queue.c:7087
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 7070 of file app_queue.c.

7071{
7072 const char *context;
7073 const char *extension;
7074 int priority;
7075
7076 if (ast_test_flag(opts, OPT_CALLEE_GO_ON)) {
7077 ast_channel_lock(chan);
7081 ast_channel_unlock(chan);
7083 opt_args[OPT_ARG_CALLEE_GO_ON]);
7084 }
7085}
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.
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, ast_channel::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 6957 of file app_queue.c.

6959{
6960 struct queue_stasis_data *queue_data = queue_stasis_data_alloc(qe, peer, mem, holdstart, starttime, callcompletedinsl);
6961
6962 if (!queue_data) {
6963 return -1;
6964 }
6965
6967 if (!queue_data->bridge_router) {
6968 ao2_ref(queue_data, -1);
6969 return -1;
6970 }
6971
6973 handle_bridge_enter, queue_data);
6975 handle_blind_transfer, queue_data);
6977 handle_attended_transfer, queue_data);
6979 queue_bridge_cb, queue_data);
6980
6982 if (!queue_data->channel_router) {
6983 /* Unsubscribing from the bridge router will remove the only ref of queue_data,
6984 * thus beginning the destruction process
6985 */
6987 queue_data->bridge_router = NULL;
6988 return -1;
6989 }
6990
6991 ao2_ref(queue_data, +1);
6995 handle_local_optimization_end, queue_data);
6997 handle_hangup, queue_data);
6999 handle_masquerade, queue_data);
7001 queue_channel_cb, queue_data);
7002
7003 return 0;
7004}
static void handle_bridge_enter(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Definition app_queue.c:6552
static void queue_bridge_cb(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Definition app_queue.c:6699
static void handle_attended_transfer(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Handle an attended transfer event.
Definition app_queue.c:6644
static void handle_masquerade(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Definition app_queue.c:6898
static void handle_local_optimization_begin(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Definition app_queue.c:6718
static void handle_local_optimization_end(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Definition app_queue.c:6777
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:6467
static void queue_channel_cb(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Definition app_queue.c:6932
static void handle_hangup(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Definition app_queue.c:6841
static void handle_blind_transfer(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Handle a blind transfer event.
Definition app_queue.c:6585
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 * stasis_subscription_change_type(void)
Gets the message type for subscription change notices.
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.

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_unsubscribe(), and stasis_subscription_change_type().

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

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

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

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

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

2090{
2091 int x;
2092
2093 for (x = 0; x < ARRAY_LEN(strategies); x++) {
2094 if (!strcasecmp(strategy, strategies[x].name)) {
2095 return strategies[x].strategy;
2096 }
2097 }
2098
2099 return -1;
2100}
int strategy
Definition app_queue.c:1676

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

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

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_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, ast_tvnow(), 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_duration_var(), 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, queue_end_bridge::start_time, 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 11960 of file app_queue.c.

11961{
11964
11966
11967 STASIS_MESSAGE_TYPE_CLEANUP(queue_caller_join_type);
11968 STASIS_MESSAGE_TYPE_CLEANUP(queue_caller_leave_type);
11969 STASIS_MESSAGE_TYPE_CLEANUP(queue_caller_abandon_type);
11970
11971 STASIS_MESSAGE_TYPE_CLEANUP(queue_member_status_type);
11972 STASIS_MESSAGE_TYPE_CLEANUP(queue_member_added_type);
11973 STASIS_MESSAGE_TYPE_CLEANUP(queue_member_removed_type);
11974 STASIS_MESSAGE_TYPE_CLEANUP(queue_member_pause_type);
11975 STASIS_MESSAGE_TYPE_CLEANUP(queue_member_penalty_type);
11976 STASIS_MESSAGE_TYPE_CLEANUP(queue_member_ringinuse_type);
11977
11978 STASIS_MESSAGE_TYPE_CLEANUP(queue_agent_called_type);
11979 STASIS_MESSAGE_TYPE_CLEANUP(queue_agent_connect_type);
11980 STASIS_MESSAGE_TYPE_CLEANUP(queue_agent_complete_type);
11981 STASIS_MESSAGE_TYPE_CLEANUP(queue_agent_dump_type);
11982 STASIS_MESSAGE_TYPE_CLEANUP(queue_agent_ringnoanswer_type);
11983
11985 ast_manager_unregister("QueueStatus");
11986 ast_manager_unregister("QueueRule");
11987 ast_manager_unregister("QueueSummary");
11988 ast_manager_unregister("QueueAdd");
11989 ast_manager_unregister("QueueRemove");
11990 ast_manager_unregister("QueuePause");
11991 ast_manager_unregister("QueueLog");
11992 ast_manager_unregister("QueueUpdate");
11993 ast_manager_unregister("QueuePenalty");
11994 ast_manager_unregister("QueueReload");
11995 ast_manager_unregister("QueueReset");
11996 ast_manager_unregister("QueueMemberRingInUse");
11997 ast_manager_unregister("QueueChangePriorityCaller");
11998 ast_manager_unregister("QueueWithdrawCaller");
12013
12015
12016 ast_unload_realtime("queue_members");
12019
12020 queues = NULL;
12021 return 0;
12022}
void ast_cli_unregister_multiple(void)
Definition ael_main.c:408
int ast_manager_unregister(const char *action)
Unregister a registered manager command.
Definition manager.c:7698
int ast_unregister_application(const char *app)
Unregister an application.
Definition pbx_app.c:392
int ast_custom_function_unregister(struct ast_custom_function *acf)
Unregister a custom function.
#define STASIS_MESSAGE_TYPE_CLEANUP(name)
Boiler-plate messaging macro for cleaning up message types.
Definition stasis.h:1515
struct stasis_forward * stasis_forward_cancel(struct stasis_forward *forward)
Definition stasis.c:1615
struct stasis_subscription * stasis_unsubscribe_and_join(struct stasis_subscription *subscription)
Cancel a subscription, blocking until the last message is processed.
Definition stasis.c:1201
void stasis_message_router_unsubscribe_and_join(struct stasis_message_router *router)
Unsubscribe the router from the upstream topic, blocking until the final message has been processed.

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

Referenced by load_module().

◆ update_connected_line_from_peer()

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

Definition at line 5351 of file app_queue.c.

5352{
5353 struct ast_party_connected_line connected_caller;
5354
5355 ast_party_connected_line_init(&connected_caller);
5356
5357 ast_channel_lock(peer);
5359 ast_channel_unlock(peer);
5360 connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
5361 if (ast_channel_connected_line_sub(peer, chan, &connected_caller, 0)) {
5362 ast_channel_update_connected_line(chan, &connected_caller, NULL);
5363 }
5364 ast_party_connected_line_free(&connected_caller);
5365}
@ 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:10382
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:9137
void ast_party_connected_line_init(struct ast_party_connected_line *init)
Initialize the given connected line structure.
Definition channel.c:2008
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 5970 of file app_queue.c.

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

References ast_channel_name(), ast_debug, AST_LIST_NEXT, queue_ent::max_penalty, queue_ent::min_penalty, pbx_builtin_setvar_helper(), queue_ent::raise_penalty, and queue_ent::start.

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

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

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

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

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

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

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

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

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

8469{
8470 char *parse;
8472 AST_APP_ARG(queuename);
8473 AST_APP_ARG(interface);
8475 AST_APP_ARG(reason);
8476 );
8477
8478 if (ast_strlen_zero(data)) {
8479 ast_log(LOG_WARNING, "UnpauseQueueMember requires an argument ([queuename],interface[,options[,reason]])\n");
8480 return -1;
8481 }
8482
8483 parse = ast_strdupa(data);
8484
8486
8487 if (ast_strlen_zero(args.interface)) {
8488 ast_log(LOG_WARNING, "Missing interface argument to UnpauseQueueMember ([queuename],interface[,options[,reason]])\n");
8489 return -1;
8490 }
8491
8492 if (set_member_paused(args.queuename, args.interface, args.reason, 0)) {
8493 ast_log(LOG_WARNING, "Attempt to unpause interface %s, not found\n", args.interface);
8494 pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "NOTFOUND");
8495 return 0;
8496 }
8497
8498 pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "UNPAUSED");
8499
8500 return 0;
8501}

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

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

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

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

7662{
7663 /* Don't need to hold the lock while we setup the outgoing calls */
7664 int retrywait = qe->parent->retry * 1000;
7665
7666 int res = ast_waitfordigit(qe->chan, retrywait);
7667 if (res > 0 && !valid_exit(qe, res)) {
7668 res = 0;
7669 }
7670
7671 return res;
7672}
int ast_waitfordigit(struct ast_channel *c, int ms)
Waits for a digit.
Definition channel.c:3172

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

5382{
5383 const char *queue = qe->parent->name;
5384 struct callattempt *o, *start = NULL, *prev = NULL;
5385 int status;
5386 int numbusies = prebusies;
5387 int numnochan = 0;
5388 int stillgoing = 0;
5389 int orig = *to;
5390 struct ast_frame *f;
5391 struct callattempt *peer = NULL;
5392 struct ast_channel *winner;
5393 struct ast_channel *in = qe->chan;
5394 char on[80] = "";
5395 char membername[80] = "";
5396 long starttime = 0;
5397 long endtime = 0;
5398 char *inchan_name;
5399 struct timeval start_time_tv = ast_tvnow();
5400 int canceled_by_caller = 0; /* 1 when caller hangs up or press digit or press * */
5401
5403 inchan_name = ast_strdupa(ast_channel_name(qe->chan));
5405
5406 starttime = (long) time(NULL);
5407
5408 while ((*to = ast_remaining_ms(start_time_tv, orig)) && !peer) {
5409 int numlines, retry, pos = 1;
5410 struct ast_channel *watchers[AST_MAX_WATCHERS];
5411 watchers[0] = in;
5412 start = NULL;
5413
5414 for (retry = 0; retry < 2; retry++) {
5415 numlines = 0;
5416 for (o = outgoing; o; o = o->q_next) { /* Keep track of important channels */
5417 if (o->stillgoing) { /* Keep track of important channels */
5418 stillgoing = 1;
5419 if (o->chan) {
5420 if (pos < AST_MAX_WATCHERS) {
5421 watchers[pos++] = o->chan;
5422 }
5423 if (!start) {
5424 start = o;
5425 } else {
5426 prev->call_next = o;
5427 }
5428 prev = o;
5429 }
5430 } else if (prev) {
5431 prev->call_next = NULL;
5432 }
5433 numlines++;
5434 }
5435 if (pos > 1 /* found */ || !stillgoing /* nobody listening */ ||
5436 (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) /* ring would not be delivered */) {
5437 break;
5438 }
5439 /* On "ringall" strategy we only move to the next penalty level
5440 when *all* ringing phones are done in the current penalty level */
5441 ring_one(qe, outgoing, &numbusies);
5442 /* and retry... */
5443 }
5444 if (pos == 1 /* not found */) {
5445 if (numlines == (numbusies + numnochan)) {
5446 ast_debug(1, "Everyone is busy at this time\n");
5447 } else {
5448 ast_debug(3, "No one is answering queue '%s' (%d numlines / %d busies / %d failed channels)\n", queue, numlines, numbusies, numnochan);
5449 }
5450 *to = 0;
5451 return NULL;
5452 }
5453
5454 /* Poll for events from both the incoming channel as well as any outgoing channels */
5455 winner = ast_waitfor_n(watchers, pos, to);
5456
5457 /* Service all of the outgoing channels */
5458 for (o = start; o; o = o->call_next) {
5459 /* We go with a fixed buffer here instead of using ast_strdupa. Using
5460 * ast_strdupa in a loop like this one can cause a stack overflow
5461 */
5462 char ochan_name[AST_CHANNEL_NAME];
5463
5464 if (o->chan) {
5466 ast_copy_string(ochan_name, ast_channel_name(o->chan), sizeof(ochan_name));
5468 }
5469 if (o->stillgoing && (o->chan) && (ast_channel_state(o->chan) == AST_STATE_UP)) {
5470 if (!peer) {
5471 ast_verb(3, "%s answered %s\n", ochan_name, inchan_name);
5472 if (o->orig_chan_name
5473 && strcmp(o->orig_chan_name, ochan_name)) {
5474 /*
5475 * The channel name changed so we must generate COLP update.
5476 * Likely because a call pickup channel masqueraded in.
5477 */
5479 } else if (!o->block_connected_update) {
5480 if (o->pending_connected_update) {
5483 }
5484 } else if (!o->dial_callerid_absent) {
5486 }
5487 }
5488 if (o->aoc_s_rate_list) {
5489 size_t encoded_size;
5490 struct ast_aoc_encoded *encoded;
5491 if ((encoded = ast_aoc_encode(o->aoc_s_rate_list, &encoded_size, o->chan))) {
5492 ast_indicate_data(in, AST_CONTROL_AOC, encoded, encoded_size);
5493 ast_aoc_destroy_encoded(encoded);
5494 }
5495 }
5496 peer = o;
5497 }
5498 } else if (o->chan && (o->chan == winner)) {
5499
5500 ast_copy_string(on, o->member->interface, sizeof(on));
5501 ast_copy_string(membername, o->member->membername, sizeof(membername));
5502
5503 /* Before processing channel, go ahead and check for forwarding */
5504 if (!ast_strlen_zero(ast_channel_call_forward(o->chan)) && !forwardsallowed) {
5505 ast_verb(3, "Forwarding %s to '%s' prevented.\n", inchan_name, ast_channel_call_forward(o->chan));
5507 "CANCEL", ast_channel_call_forward(o->chan));
5508 numnochan++;
5509 do_hang(o);
5510 winner = NULL;
5511 continue;
5513 struct ast_channel *original = o->chan;
5514 char forwarder[AST_CHANNEL_NAME];
5515 char tmpchan[256];
5516 char *stuff;
5517 char *tech;
5518 int failed = 0;
5519
5520 ast_copy_string(tmpchan, ast_channel_call_forward(o->chan), sizeof(tmpchan));
5521 ast_copy_string(forwarder, ast_channel_name(o->chan), sizeof(forwarder));
5522 if ((stuff = strchr(tmpchan, '/'))) {
5523 *stuff++ = '\0';
5524 tech = tmpchan;
5525 } else {
5526 const char *forward_context;
5528 forward_context = pbx_builtin_getvar_helper(o->chan, "FORWARD_CONTEXT");
5529 snprintf(tmpchan, sizeof(tmpchan), "%s@%s", ast_channel_call_forward(o->chan), forward_context ? forward_context : ast_channel_context(o->chan));
5531 stuff = tmpchan;
5532 tech = "Local";
5533 }
5534 if (!strcasecmp(tech, "Local")) {
5535 /*
5536 * Drop the connected line update block for local channels since
5537 * this is going to run dialplan and the user can change his
5538 * mind about what connected line information he wants to send.
5539 */
5541 }
5542
5543 ast_verb(3, "Now forwarding %s to '%s/%s' (thanks to %s)\n", inchan_name, tech, stuff, ochan_name);
5544 /* Setup parameters */
5546 if (!o->chan) {
5548 "Forwarding failed to create channel to dial '%s/%s'\n",
5549 tech, stuff);
5550 o->stillgoing = 0;
5551 numnochan++;
5552 } else {
5553 ast_channel_lock_both(o->chan, original);
5555 ast_channel_redirecting(original));
5557 ast_channel_unlock(original);
5558
5562 pbx_builtin_setvar_helper(o->chan, "FORWARDERNAME", forwarder);
5564
5565 if (o->pending_connected_update) {
5566 /*
5567 * Re-seed the callattempt's connected line information with
5568 * previously acquired connected line info from the queued
5569 * channel. The previously acquired connected line info could
5570 * have been set through the CONNECTED_LINE dialplan function.
5571 */
5574 }
5575
5578
5580
5583 /*
5584 * The call was not previously redirected so it is
5585 * now redirected from this number.
5586 */
5592 }
5593
5595
5600
5603 && !o->block_connected_update) {
5604 struct ast_party_redirecting redirecting;
5605
5606 /*
5607 * Redirecting updates to the caller make sense only on single
5608 * call at a time strategies.
5609 *
5610 * Need to re-evaluate if calling unlock is still required as we no longer
5611 * use macro.
5612 */
5613 ast_party_redirecting_init(&redirecting);
5616 if (ast_channel_redirecting_sub(o->chan, in, &redirecting, 0)) {
5617 ast_channel_update_redirecting(in, &redirecting, NULL);
5618 }
5619 ast_party_redirecting_free(&redirecting);
5620 } else {
5622 }
5623
5624 if (ast_call(o->chan, stuff, 0)) {
5625 ast_log(LOG_NOTICE, "Forwarding failed to dial '%s/%s'\n",
5626 tech, stuff);
5627 failed = 1;
5628 }
5629 }
5630
5632 "CANCEL", ast_channel_call_forward(original));
5633 if (o->chan) {
5634 ast_channel_publish_dial(qe->chan, o->chan, stuff, NULL);
5635 }
5636
5637 if (failed) {
5638 do_hang(o);
5639 numnochan++;
5640 }
5641
5642 /* Hangup the original channel now, in case we needed it */
5643 ast_hangup(winner);
5644 continue;
5645 }
5646 f = ast_read(winner);
5647 if (f) {
5648 if (f->frametype == AST_FRAME_CONTROL) {
5649 switch (f->subclass.integer) {
5650 case AST_CONTROL_ANSWER:
5651 /* This is our guy if someone answered. */
5652 if (!peer) {
5653 ast_verb(3, "%s answered %s\n", ochan_name, inchan_name);
5654 ast_channel_publish_dial(qe->chan, o->chan, on, "ANSWER");
5655 publish_dial_end_event(qe->chan, outgoing, o->chan, "CANCEL");
5656 if (o->orig_chan_name
5657 && strcmp(o->orig_chan_name, ochan_name)) {
5658 /*
5659 * The channel name changed so we must generate COLP update.
5660 * Likely because a call pickup channel masqueraded in.
5661 */
5663 } else if (!o->block_connected_update) {
5664 if (o->pending_connected_update) {
5667 }
5668 } else if (!o->dial_callerid_absent) {
5670 }
5671 }
5672 if (o->aoc_s_rate_list) {
5673 size_t encoded_size;
5674 struct ast_aoc_encoded *encoded;
5675 if ((encoded = ast_aoc_encode(o->aoc_s_rate_list, &encoded_size, o->chan))) {
5676 ast_indicate_data(in, AST_CONTROL_AOC, encoded, encoded_size);
5677 ast_aoc_destroy_encoded(encoded);
5678 }
5679 }
5680 peer = o;
5681 }
5682 break;
5683 case AST_CONTROL_BUSY:
5684 ast_verb(3, "%s is busy\n", ochan_name);
5685 ast_channel_publish_dial(qe->chan, o->chan, on, "BUSY");
5686 endtime = (long) time(NULL);
5687 endtime -= starttime;
5688 rna(endtime * 1000, qe, o->chan, on, membername, qe->parent->autopausebusy);
5689 do_hang(o);
5691 if (qe->parent->timeoutrestart) {
5692 start_time_tv = ast_tvnow();
5693 }
5694 /* Have enough time for a queue member to answer? */
5695 if (ast_remaining_ms(start_time_tv, orig) > 500) {
5696 ring_one(qe, outgoing, &numbusies);
5697 starttime = (long) time(NULL);
5698 }
5699 }
5700 numbusies++;
5701 break;
5703 ast_verb(3, "%s is circuit-busy\n", ochan_name);
5704 ast_channel_publish_dial(qe->chan, o->chan, on, "CONGESTION");
5705 endtime = (long) time(NULL);
5706 endtime -= starttime;
5707 rna(endtime * 1000, qe, o->chan, on, membername, qe->parent->autopauseunavail);
5708 do_hang(o);
5710 if (qe->parent->timeoutrestart) {
5711 start_time_tv = ast_tvnow();
5712 }
5713 if (ast_remaining_ms(start_time_tv, orig) > 500) {
5714 ring_one(qe, outgoing, &numbusies);
5715 starttime = (long) time(NULL);
5716 }
5717 }
5718 numbusies++;
5719 break;
5721 ast_verb(3, "%s is ringing\n", ochan_name);
5722
5723 ast_channel_publish_dial(qe->chan, o->chan, on, "RINGING");
5724
5725 /* Start ring indication when the channel is ringing, if specified */
5726 if (qe->ring_when_ringing) {
5727 ast_moh_stop(qe->chan);
5729 }
5730 break;
5732 /* Ignore going off hook */
5733 break;
5735 if (o->block_connected_update) {
5736 ast_verb(3, "Connected line update to %s prevented.\n", inchan_name);
5737 break;
5738 }
5741
5742 ast_verb(3, "%s connected line has changed. Saving it until answer for %s\n", ochan_name, inchan_name);
5748 break;
5749 }
5750
5751 /*
5752 * Prevent using the CallerID from the outgoing channel since we
5753 * got a connected line update from it.
5754 */
5755 o->dial_callerid_absent = 1;
5756
5757 if (ast_channel_connected_line_sub(o->chan, in, f, 1)) {
5759 }
5760 break;
5761 case AST_CONTROL_AOC:
5762 {
5763 struct ast_aoc_decoded *decoded = ast_aoc_decode(f->data.ptr, f->datalen, o->chan);
5764 if (decoded && (ast_aoc_get_msg_type(decoded) == AST_AOC_S)) {
5766 o->aoc_s_rate_list = decoded;
5767 } else {
5768 ast_aoc_destroy_decoded(decoded);
5769 }
5770 }
5771 break;
5774 /*
5775 * Redirecting updates to the caller make sense only on single
5776 * call at a time strategies.
5777 */
5778 break;
5779 }
5780 if (o->block_connected_update) {
5781 ast_verb(3, "Redirecting update to %s prevented\n",
5782 inchan_name);
5783 break;
5784 }
5785 ast_verb(3, "%s redirecting info has changed, passing it to %s\n",
5786 ochan_name, inchan_name);
5787 if (ast_channel_redirecting_sub(o->chan, in, f, 1)) {
5789 }
5790 break;
5793 break;
5794 default:
5795 ast_debug(1, "Dunno what to do with control type %d\n", f->subclass.integer);
5796 break;
5797 }
5798 }
5799 ast_frfree(f);
5800 } else { /* ast_read() returned NULL */
5801 endtime = (long) time(NULL) - starttime;
5802 ast_channel_publish_dial(qe->chan, o->chan, on, "NOANSWER");
5803 rna(endtime * 1000, qe, o->chan, on, membername, 1);
5804 do_hang(o);
5806 if (qe->parent->timeoutrestart) {
5807 start_time_tv = ast_tvnow();
5808 }
5809 if (ast_remaining_ms(start_time_tv, orig) > 500) {
5810 ring_one(qe, outgoing, &numbusies);
5811 starttime = (long) time(NULL);
5812 }
5813 }
5814 }
5815 }
5816 }
5817
5818 /* If we received an event from the caller, deal with it. */
5819 if (winner == in) {
5820 f = ast_read(in);
5821 if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass.integer == AST_CONTROL_HANGUP))) {
5822 /* Got hung up */
5823 *to = -1;
5824 if (f) {
5825 if (f->data.uint32) {
5827 }
5828 ast_frfree(f);
5829 }
5830 canceled_by_caller = 1;
5831 } else if ((f->frametype == AST_FRAME_DTMF) && caller_disconnect && (f->subclass.integer == '*')) {
5832 ast_verb(3, "User hit %c to disconnect call.\n", f->subclass.integer);
5833 *to = 0;
5834 ast_frfree(f);
5835 canceled_by_caller = 1;
5836 } else if ((f->frametype == AST_FRAME_DTMF) && valid_exit(qe, f->subclass.integer)) {
5837 ast_verb(3, "User pressed digit: %c\n", f->subclass.integer);
5838 *to = 0;
5839 *digit = f->subclass.integer;
5840 ast_frfree(f);
5841 canceled_by_caller = 1;
5842 }
5843 /* When caller hung up or pressed * or digit. */
5844 if (canceled_by_caller) {
5846 for (o = start; o; o = o->call_next) {
5847 if (o->chan) {
5848 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));
5849 }
5850 }
5851 return NULL;
5852 }
5853
5854 /* Send the frame from the in channel to all outgoing channels. */
5855 for (o = start; o; o = o->call_next) {
5856 if (!o->stillgoing || !o->chan) {
5857 /* This outgoing channel has died so don't send the frame to it. */
5858 continue;
5859 }
5860 switch (f->frametype) {
5861 case AST_FRAME_CONTROL:
5862 switch (f->subclass.integer) {
5864 if (o->block_connected_update) {
5865 ast_verb(3, "Connected line update to %s prevented.\n", ast_channel_name(o->chan));
5866 break;
5867 }
5868 if (ast_channel_connected_line_sub(in, o->chan, f, 1)) {
5870 }
5871 break;
5873 if (o->block_connected_update) {
5874 ast_verb(3, "Redirecting update to %s prevented.\n", ast_channel_name(o->chan));
5875 break;
5876 }
5877 if (ast_channel_redirecting_sub(in, o->chan, f, 1)) {
5879 }
5880 break;
5881 default:
5882 /* We are not going to do anything with this frame. */
5883 goto skip_frame;
5884 }
5885 break;
5886 default:
5887 /* We are not going to do anything with this frame. */
5888 goto skip_frame;
5889 }
5890 }
5891skip_frame:;
5892
5893 ast_frfree(f);
5894 }
5895 }
5896
5897 if (!*to) {
5898 for (o = start; o; o = o->call_next) {
5899 if (o->chan) {
5900 rna(orig, qe, o->chan, o->interface, o->member->membername, 1);
5901 }
5902 }
5903
5904 publish_dial_end_event(qe->chan, outgoing, NULL, "NOANSWER");
5905 }
5906
5907 return peer;
5908}
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:5367
static void update_connected_line_from_peer(struct ast_channel *chan, struct ast_channel *peer, int is_caller)
Definition app_queue.c:5351
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:5286
static int connected
Definition cdr_pgsql.c:73
void ast_party_redirecting_init(struct ast_party_redirecting *init)
Initialize the given redirecting structure.
Definition channel.c:2108
void ast_party_number_init(struct ast_party_number *init)
Initialize the given number structure.
Definition channel.c:1630
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:3154
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:2040
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:6429
struct ast_frame * ast_read(struct ast_channel *chan)
Reads a frame.
Definition channel.c:4250
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:10427
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:8829
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:4648
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:10328
#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:1677
void ast_party_redirecting_free(struct ast_party_redirecting *doomed)
Destroy the redirecting information contents.
Definition channel.c:2165
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:2031
ast_channel_state
ast_channel states
@ AST_STATE_UP
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_REDIRECTING
@ AST_CONTROL_CONGESTION
@ AST_CONTROL_ANSWER
@ AST_CONTROL_HANGUP
@ AST_CONTROL_CONNECTED_LINE
@ AST_CONTROL_PVT_CAUSE_CODE
const struct ast_channel_tech * tech
Data structure associated with a single frame of data.
struct ast_frame_subclass subclass
enum ast_frame_type frametype
union ast_frame::@239 data
Redirecting Line information. RDNIS (Redirecting Directory Number Information Service) Where a call d...
Definition channel.h:524
struct ast_party_id from
Who is redirecting the call (Sent to the party the call is redirected toward)
Definition channel.h:529
struct callattempt * call_next
Definition app_queue.c:1823
unsigned int pending_connected_update
Definition app_queue.c:1831
int ast_remaining_ms(struct timeval start, int max_ms)
Calculate remaining milliseconds given a starting timestamp and upper bound.
Definition utils.c:2317

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

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

References ast_channel_uniqueid(), ast_queue_log(), ast_waitfordigit(), get_member_status(), is_our_turn(), NULL, QUEUE_LEAVEEMPTY, QUEUE_TIMEOUT, QUEUE_WITHDRAW, RECHECK, record_abandoned(), ringing(), say_periodic_announcement(), say_position(), queue_ent::start, status, update_qe_rule(), and valid_exit().

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

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

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 = ASTERISK_GPL_KEY , .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 12221 of file app_queue.c.

◆ agent_router

struct stasis_message_router* agent_router
static

Definition at line 11957 of file app_queue.c.

Referenced by load_module(), and unload_module().

◆ app

char* app = "Queue"
static

Definition at line 1718 of file app_queue.c.

Referenced by load_module(), and unload_module().

◆ app_aqm

char* app_aqm = "AddQueueMember"
static

Definition at line 1720 of file app_queue.c.

Referenced by load_module(), and unload_module().

◆ app_pqm

char* app_pqm = "PauseQueueMember"
static

Definition at line 1724 of file app_queue.c.

Referenced by load_module(), and unload_module().

◆ app_ql

char* app_ql = "QueueLog"
static

Definition at line 1728 of file app_queue.c.

Referenced by load_module(), and unload_module().

◆ app_qupd

char* app_qupd = "QueueUpdate"
static

Definition at line 1730 of file app_queue.c.

Referenced by load_module(), and unload_module().

◆ app_rqm

char* app_rqm = "RemoveQueueMember"
static

Definition at line 1722 of file app_queue.c.

Referenced by load_module(), and unload_module().

◆ app_upqm

char* app_upqm = "UnpauseQueueMember"
static

Definition at line 1726 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 1649 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 12221 of file app_queue.c.

◆ autofill_default

int autofill_default
static

queues.conf [general] option

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

11944 {
11945 AST_CLI_DEFINE(queue_show, "Show status of a specified queue"),
11946 AST_CLI_DEFINE(handle_queue_rule_show, "Show the rules defined in queuerules.conf"),
11947 AST_CLI_DEFINE(handle_queue_add_member, "Add a channel to a specified queue"),
11948 AST_CLI_DEFINE(handle_queue_remove_member, "Removes a channel from a specified queue"),
11949 AST_CLI_DEFINE(handle_queue_pause_member, "Pause or unpause a queue member"),
11950 AST_CLI_DEFINE(handle_queue_set_member_penalty, "Set penalty for a channel of a specified queue"),
11951 AST_CLI_DEFINE(handle_queue_set_member_ringinuse, "Set ringinuse for a channel of a specified queue"),
11952 AST_CLI_DEFINE(handle_queue_reload, "Reload queues, members, queue rules, or parameters"),
11953 AST_CLI_DEFINE(handle_queue_reset, "Reset statistics for a queue"),
11954 AST_CLI_DEFINE(handle_queue_change_priority_caller, "Change priority caller on queue"),
11955};
static char * queue_show(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_set_member_penalty(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_set_member_ringinuse(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_rule_show(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_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_queue_add_member(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
#define AST_CLI_DEFINE(fn, txt,...)
Definition cli.h:197

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 1754 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 1763 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 1790 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(), cli_endpoint_print_body(), 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_command(), handle_local_optimization_begin(), handle_local_optimization_end(), handle_registrations(), idemodulator(), load_engine(), mbl_load_adapter(), mbox(), mwi_mailbox_get(), object_type_loaded_observer(), 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(), sorcery_realtime_update(), startelm(), starttimer(), state_id_by_topic(), try_merge_optimize_out(), try_swap_optimize_out(), and update_incoming_connected_line().

◆ log_caller_id_name

int log_caller_id_name
static

queues.conf [general] option

Definition at line 1766 of file app_queue.c.

Referenced by queue_exec(), and queue_set_global_params().

◆ log_membername_as_agent

int log_membername_as_agent
static

◆ log_unpause_on_reason_change

int log_unpause_on_reason_change
static

queues.conf [general] option

Definition at line 1769 of file app_queue.c.

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

◆ montype_default

int montype_default
static

queues.conf [general] option

Definition at line 1745 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 1757 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 2672 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 1733 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 1633 of file app_queue.c.

Referenced by queue_exec().

◆ queue_persistent_members

int queue_persistent_members
static

◆ [struct]

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

Definition at line 9692 of file app_queue.c.

9692 {
9693 .name = "QUEUE_EXISTS",
9694 .read = queue_function_exists,
9695};

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

Definition at line 9708 of file app_queue.c.

9708 {
9709 .name = "QUEUE_GET_CHANNEL",
9711};

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:9299
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:9401

Definition at line 9702 of file app_queue.c.

9702 {
9703 .name = "QUEUE_MEMBER",
9705 .write = queue_function_mem_write,
9706};

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

Definition at line 9718 of file app_queue.c.

9718 {
9719 .name = "QUEUE_MEMBER_LIST",
9721};

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:9624
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:9656

Definition at line 9723 of file app_queue.c.

9723 {
9724 .name = "QUEUE_MEMBER_PENALTY",
9727};

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

Definition at line 9697 of file app_queue.c.

9697 {
9698 .name = "QUEUE_VARIABLES",
9699 .read = queue_function_var,
9700};

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

Definition at line 9713 of file app_queue.c.

9713 {
9714 .name = "QUEUE_WAITING_COUNT",
9716};

Referenced by load_module(), and unload_module().

◆ realtime_reason_paused

int realtime_reason_paused
static

does realtime backend support reason_paused

Definition at line 1775 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 1772 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 1751 of file app_queue.c.

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

◆ rule_lists

◆ shared_lastcall

int shared_lastcall
static

queues.conf [general] option

Definition at line 1748 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 11958 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 1739 of file app_queue.c.

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