Asterisk - The Open Source Telephony Project GIT-master-27fb039
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 "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 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 1905 of file app_queue.c.

◆ ANNOUNCEHOLDTIME_ONCE

#define ANNOUNCEHOLDTIME_ONCE   2

Definition at line 1906 of file app_queue.c.

◆ ANNOUNCEPOSITION_LIMIT

#define ANNOUNCEPOSITION_LIMIT   4

We not announce position more than <limit>

Definition at line 1924 of file app_queue.c.

◆ ANNOUNCEPOSITION_MORE_THAN

#define ANNOUNCEPOSITION_MORE_THAN   3

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

Definition at line 1923 of file app_queue.c.

◆ ANNOUNCEPOSITION_NO

#define ANNOUNCEPOSITION_NO   2

We don't announce position

Definition at line 1922 of file app_queue.c.

◆ ANNOUNCEPOSITION_YES

#define ANNOUNCEPOSITION_YES   1

We announce position

Definition at line 1921 of file app_queue.c.

◆ AST_MAX_WATCHERS

#define AST_MAX_WATCHERS   256

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

◆ DEFAULT_RETRY

#define DEFAULT_RETRY   5

Definition at line 1680 of file app_queue.c.

◆ DEFAULT_TIMEOUT

#define DEFAULT_TIMEOUT   15

Definition at line 1681 of file app_queue.c.

◆ MAX_CALL_ATTEMPT_BUCKETS

#define MAX_CALL_ATTEMPT_BUCKETS   353

Definition at line 2654 of file app_queue.c.

◆ MAX_PERIODIC_ANNOUNCEMENTS

#define MAX_PERIODIC_ANNOUNCEMENTS   10

The maximum periodic announcements we can have

Definition at line 1683 of file app_queue.c.

◆ MAX_QUEUE_BUCKETS

#define MAX_QUEUE_BUCKETS   53

Definition at line 1690 of file app_queue.c.

◆ QUEUE_EVENT_VARIABLES

#define QUEUE_EVENT_VARIABLES   3

Definition at line 1907 of file app_queue.c.

◆ QUEUE_PAUSED_DEVSTATE

#define QUEUE_PAUSED_DEVSTATE   AST_DEVICE_INUSE

Definition at line 3691 of file app_queue.c.

◆ queue_ref

#define queue_ref (   q)    ao2_bump(q)

Definition at line 2190 of file app_queue.c.

◆ queue_t_ref

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

Definition at line 2192 of file app_queue.c.

◆ queue_t_unref

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

Definition at line 2193 of file app_queue.c.

◆ QUEUE_UNKNOWN_PAUSED_DEVSTATE

#define QUEUE_UNKNOWN_PAUSED_DEVSTATE   AST_DEVICE_NOT_INUSE

Definition at line 3693 of file app_queue.c.

◆ QUEUE_UNPAUSED_DEVSTATE

#define QUEUE_UNPAUSED_DEVSTATE   AST_DEVICE_NOT_INUSE

Definition at line 3692 of file app_queue.c.

◆ queue_unref

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

Definition at line 2191 of file app_queue.c.

◆ queues_t_link

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

Definition at line 2194 of file app_queue.c.

◆ queues_t_unlink

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

Definition at line 2195 of file app_queue.c.

◆ RECHECK

#define RECHECK   1

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

Definition at line 1682 of file app_queue.c.

◆ RES_EXISTS

#define RES_EXISTS   (-1)

Entry already exists

Definition at line 1693 of file app_queue.c.

◆ RES_NOSUCHQUEUE

#define RES_NOSUCHQUEUE   (-3)

No such queue

Definition at line 1695 of file app_queue.c.

◆ RES_NOT_CALLER

#define RES_NOT_CALLER   (-5)

Caller not found

Definition at line 1697 of file app_queue.c.

◆ RES_NOT_DYNAMIC

#define RES_NOT_DYNAMIC   (-4)

Member is not dynamic

Definition at line 1696 of file app_queue.c.

◆ RES_OKAY

#define RES_OKAY   0

Action completed

Definition at line 1692 of file app_queue.c.

◆ RES_OUTOFMEMORY

#define RES_OUTOFMEMORY   (-2)

Out of memory

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

1557 {
1558 OPT_MARK_AS_ANSWERED = (1 << 0),
1559 OPT_GO_ON = (1 << 1),
1560 OPT_DATA_QUALITY = (1 << 2),
1561 OPT_CALLEE_GO_ON = (1 << 3),
1562 OPT_CALLEE_HANGUP = (1 << 4),
1563 OPT_CALLER_HANGUP = (1 << 5),
1564 OPT_IGNORE_CALL_FW = (1 << 6),
1565 OPT_IGNORE_CONNECTEDLINE = (1 << 7),
1566 OPT_CALLEE_PARK = (1 << 8),
1567 OPT_CALLER_PARK = (1 << 9),
1568 OPT_NO_RETRY = (1 << 10),
1569 OPT_RINGING = (1 << 11),
1570 OPT_RING_WHEN_RINGING = (1 << 12),
1571 OPT_CALLEE_TRANSFER = (1 << 13),
1572 OPT_CALLER_TRANSFER = (1 << 14),
1573 OPT_CALLEE_AUTOMIXMON = (1 << 15),
1574 OPT_CALLER_AUTOMIXMON = (1 << 16),
1575 OPT_CALLEE_AUTOMON = (1 << 17),
1576 OPT_CALLER_AUTOMON = (1 << 18),
1577 OPT_PREDIAL_CALLEE = (1 << 19),
1578 OPT_PREDIAL_CALLER = (1 << 20),
1579 OPT_MUSICONHOLD_CLASS = (1 << 21),
1580};
@ OPT_CALLER_AUTOMON
Definition app_queue.c:1576
@ OPT_CALLEE_PARK
Definition app_queue.c:1566
@ OPT_PREDIAL_CALLER
Definition app_queue.c:1578
@ OPT_GO_ON
Definition app_queue.c:1559
@ OPT_IGNORE_CONNECTEDLINE
Definition app_queue.c:1565
@ OPT_CALLEE_AUTOMON
Definition app_queue.c:1575
@ OPT_CALLEE_TRANSFER
Definition app_queue.c:1571
@ OPT_CALLEE_GO_ON
Definition app_queue.c:1561
@ OPT_MARK_AS_ANSWERED
Definition app_queue.c:1558
@ OPT_IGNORE_CALL_FW
Definition app_queue.c:1564
@ OPT_CALLER_PARK
Definition app_queue.c:1567
@ OPT_NO_RETRY
Definition app_queue.c:1568
@ OPT_DATA_QUALITY
Definition app_queue.c:1560
@ OPT_CALLER_HANGUP
Definition app_queue.c:1563
@ OPT_MUSICONHOLD_CLASS
Definition app_queue.c:1579
@ OPT_CALLEE_AUTOMIXMON
Definition app_queue.c:1573
@ OPT_CALLEE_HANGUP
Definition app_queue.c:1562
@ OPT_CALLER_AUTOMIXMON
Definition app_queue.c:1574
@ OPT_RINGING
Definition app_queue.c:1569
@ OPT_CALLER_TRANSFER
Definition app_queue.c:1572
@ OPT_PREDIAL_CALLEE
Definition app_queue.c:1577
@ OPT_RING_WHEN_RINGING
Definition app_queue.c:1570

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

1582 {
1587 /* note: this entry _MUST_ be the last one in the enum */
1589};
@ OPT_ARG_CALLEE_GO_ON
Definition app_queue.c:1583
@ OPT_ARG_PREDIAL_CALLEE
Definition app_queue.c:1584
@ OPT_ARG_MUSICONHOLD_CLASS
Definition app_queue.c:1586
@ OPT_ARG_PREDIAL_CALLER
Definition app_queue.c:1585
@ OPT_ARG_ARRAY_SIZE
Definition app_queue.c:1588

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

1632 {
1641};
@ QUEUE_STRATEGY_RINGALL
Definition app_queue.c:1633
@ QUEUE_STRATEGY_RRMEMORY
Definition app_queue.c:1637
@ QUEUE_STRATEGY_LINEAR
Definition app_queue.c:1638
@ QUEUE_STRATEGY_LEASTRECENT
Definition app_queue.c:1634
@ QUEUE_STRATEGY_RANDOM
Definition app_queue.c:1636
@ QUEUE_STRATEGY_FEWESTCALLS
Definition app_queue.c:1635
@ QUEUE_STRATEGY_RRORDERED
Definition app_queue.c:1640
@ QUEUE_STRATEGY_WRANDOM
Definition app_queue.c:1639

◆ anonymous enum

anonymous enum
Enumerator
QUEUE_AUTOPAUSE_OFF 
QUEUE_AUTOPAUSE_ON 
QUEUE_AUTOPAUSE_ALL 

Definition at line 1643 of file app_queue.c.

1643 {
1647};
@ QUEUE_AUTOPAUSE_ON
Definition app_queue.c:1645
@ QUEUE_AUTOPAUSE_OFF
Definition app_queue.c:1644
@ QUEUE_AUTOPAUSE_ALL
Definition app_queue.c:1646

◆ agent_complete_reason

Enumerator
CALLER 
AGENT 
TRANSFER 

Definition at line 6277 of file app_queue.c.

6277 {
6278 CALLER,
6279 AGENT,
6280 TRANSFER
6281};
@ AGENT
Definition app_queue.c:6279
@ CALLER
Definition app_queue.c:6278
@ TRANSFER
Definition app_queue.c:6280

◆ aqm_args

enum aqm_args
Enumerator
AQM_OPT_ARG_PAUSE_REASON 
AQM_OPT_ARG_ARRAY_SIZE 

Definition at line 1622 of file app_queue.c.

1622 {
1624 AQM_OPT_ARG_ARRAY_SIZE, /* Always last element of the enum */
1625};
@ AQM_OPT_ARG_ARRAY_SIZE
Definition app_queue.c:1624
@ AQM_OPT_ARG_PAUSE_REASON
Definition app_queue.c:1623

◆ aqm_flags

enum aqm_flags
Enumerator
AQMFLAG_PAUSED 
AQMFLAG_REASON 

Definition at line 1617 of file app_queue.c.

1617 {
1618 AQMFLAG_PAUSED = (1 << 1),
1619 AQMFLAG_REASON = (1 << 2),
1620};
@ AQMFLAG_REASON
Definition app_queue.c:1619
@ AQMFLAG_PAUSED
Definition app_queue.c:1618

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

1888 {
1889 QUEUE_EMPTY_PENALTY = (1 << 0),
1890 QUEUE_EMPTY_PAUSED = (1 << 1),
1891 QUEUE_EMPTY_INUSE = (1 << 2),
1892 QUEUE_EMPTY_RINGING = (1 << 3),
1893 QUEUE_EMPTY_UNAVAILABLE = (1 << 4),
1894 QUEUE_EMPTY_INVALID = (1 << 5),
1895 QUEUE_EMPTY_UNKNOWN = (1 << 6),
1896 QUEUE_EMPTY_WRAPUP = (1 << 7),
1897};
@ QUEUE_EMPTY_INVALID
Definition app_queue.c:1894
@ QUEUE_EMPTY_UNKNOWN
Definition app_queue.c:1895
@ QUEUE_EMPTY_PENALTY
Definition app_queue.c:1889
@ QUEUE_EMPTY_RINGING
Definition app_queue.c:1892
@ QUEUE_EMPTY_INUSE
Definition app_queue.c:1891
@ QUEUE_EMPTY_UNAVAILABLE
Definition app_queue.c:1893
@ QUEUE_EMPTY_WRAPUP
Definition app_queue.c:1896
@ QUEUE_EMPTY_PAUSED
Definition app_queue.c:1890

◆ member_properties

Enumerator
MEMBER_PENALTY 
MEMBER_RINGINUSE 

Definition at line 1899 of file app_queue.c.

1899 {
1900 MEMBER_PENALTY = 0,
1901 MEMBER_RINGINUSE = 1,
1902};
@ MEMBER_RINGINUSE
Definition app_queue.c:1901
@ MEMBER_PENALTY
Definition app_queue.c:1900

◆ queue_reload_mask

Enumerator
QUEUE_RELOAD_PARAMETERS 
QUEUE_RELOAD_MEMBER 
QUEUE_RELOAD_RULES 
QUEUE_RESET_STATS 

Definition at line 1649 of file app_queue.c.

1649 {
1650 QUEUE_RELOAD_PARAMETERS = (1 << 0),
1651 QUEUE_RELOAD_MEMBER = (1 << 1),
1652 QUEUE_RELOAD_RULES = (1 << 2),
1653 QUEUE_RESET_STATS = (1 << 3),
1654};
@ QUEUE_RELOAD_RULES
Definition app_queue.c:1652
@ QUEUE_RELOAD_MEMBER
Definition app_queue.c:1651
@ QUEUE_RESET_STATS
Definition app_queue.c:1653
@ QUEUE_RELOAD_PARAMETERS
Definition app_queue.c:1650

◆ queue_result

Enumerator
QUEUE_UNKNOWN 
QUEUE_TIMEOUT 
QUEUE_JOINEMPTY 
QUEUE_LEAVEEMPTY 
QUEUE_JOINUNAVAIL 
QUEUE_LEAVEUNAVAIL 
QUEUE_FULL 
QUEUE_CONTINUE 
QUEUE_WITHDRAW 

Definition at line 1758 of file app_queue.c.

1758 {
1759 QUEUE_UNKNOWN = 0,
1760 QUEUE_TIMEOUT = 1,
1761 QUEUE_JOINEMPTY = 2,
1762 QUEUE_LEAVEEMPTY = 3,
1765 QUEUE_FULL = 6,
1766 QUEUE_CONTINUE = 7,
1767 QUEUE_WITHDRAW = 8,
1768};
@ QUEUE_FULL
Definition app_queue.c:1765
@ QUEUE_UNKNOWN
Definition app_queue.c:1759
@ QUEUE_WITHDRAW
Definition app_queue.c:1767
@ QUEUE_CONTINUE
Definition app_queue.c:1766
@ QUEUE_LEAVEEMPTY
Definition app_queue.c:1762
@ QUEUE_LEAVEUNAVAIL
Definition app_queue.c:1764
@ QUEUE_JOINUNAVAIL
Definition app_queue.c:1763
@ QUEUE_JOINEMPTY
Definition app_queue.c:1761
@ QUEUE_TIMEOUT
Definition app_queue.c:1760

◆ queue_timeout_priority

Enumerator
TIMEOUT_PRIORITY_APP 
TIMEOUT_PRIORITY_CONF 

Definition at line 1785 of file app_queue.c.

1785 {
1788};
@ TIMEOUT_PRIORITY_CONF
Definition app_queue.c:1787
@ TIMEOUT_PRIORITY_APP
Definition app_queue.c:1786

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

10327{
10328 struct call_queue *q;
10329 struct ast_str *out = ast_str_alloca(512);
10330 struct ao2_container *sorted_queues;
10331
10332 struct ao2_iterator queue_iter;
10333 int found = 0;
10334
10335 if (argc != 2 && argc != 3) {
10336 return CLI_SHOWUSAGE;
10337 }
10338
10339 if (argc == 3) { /* specific queue */
10340 if ((q = find_load_queue_rt_friendly(argv[2]))) {
10341 ao2_lock(q);
10342 print_queue(s, fd, q);
10343 ao2_unlock(q);
10344 queue_unref(q);
10345 } else {
10346 ast_str_set(&out, 0, "No such queue: %s.", argv[2]);
10347 do_print(s, fd, ast_str_buffer(out));
10348 }
10349 return CLI_SUCCESS;
10350 }
10351
10352 if (ast_check_realtime("queues")) {
10353 /* This block is to find any queues which are defined in realtime but
10354 * which have not yet been added to the in-core container
10355 */
10356 struct ast_config *cfg = ast_load_realtime_multientry("queues", "name LIKE", "%", SENTINEL);
10357 if (cfg) {
10358 char *category = NULL;
10359 while ((category = ast_category_browse(cfg, category))) {
10360 const char *queuename = ast_variable_retrieve(cfg, category, "name");
10361 if (ast_strlen_zero(queuename)) {
10362 ast_log(LOG_WARNING, "Ignoring realtime queue with a NULL or empty 'name.'\n");
10363 continue;
10364 }
10365 if ((q = find_load_queue_rt_friendly(queuename))) {
10366 queue_t_unref(q, "Done with temporary pointer");
10367 }
10368 }
10369 ast_config_destroy(cfg);
10370 }
10371 }
10372
10373 /*
10374 * Snapping a copy of the container prevents having to lock both the queues container
10375 * and the queue itself at the same time. It also allows us to sort the entries.
10376 */
10377 sorted_queues = ao2_container_alloc_rbtree(AO2_ALLOC_OPT_LOCK_NOLOCK, 0, call_queue_sort_fn, NULL);
10378 if (!sorted_queues) {
10379 return CLI_SUCCESS;
10380 }
10381 if (ao2_container_dup(sorted_queues, queues, 0)) {
10382 ao2_ref(sorted_queues, -1);
10383 return CLI_SUCCESS;
10384 }
10385
10386 /*
10387 * No need to lock the container since it's temporary and static.
10388 * We also unlink the entries as we use them so the container is
10389 * empty when the iterator finishes. We can then just unref the container.
10390 */
10391 queue_iter = ao2_iterator_init(sorted_queues, AO2_ITERATOR_DONTLOCK | AO2_ITERATOR_UNLINK);
10392 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
10393 struct call_queue *realtime_queue = NULL;
10394 ao2_lock(q);
10395 /* This check is to make sure we don't print information for realtime
10396 * queues which have been deleted from realtime but which have not yet
10397 * been deleted from the in-core container. Only do this if we're not
10398 * looking for a specific queue.
10399 */
10400 if (q->realtime) {
10401 realtime_queue = find_load_queue_rt_friendly(q->name);
10402 if (!realtime_queue) {
10403 ao2_unlock(q);
10404 queue_t_unref(q, "Done with iterator");
10405 continue;
10406 }
10407 queue_t_unref(realtime_queue, "Queue is already in memory");
10408 }
10409
10410 found = 1;
10411 print_queue(s, fd, q);
10412
10413 ao2_unlock(q);
10414 queue_t_unref(q, "Done with iterator"); /* Unref the iterator's reference */
10415 }
10416 ao2_iterator_destroy(&queue_iter);
10417 ao2_ref(sorted_queues, -1);
10418 if (!found) {
10419 ast_str_set(&out, 0, "No queues.");
10420 do_print(s, fd, ast_str_buffer(out));
10421 }
10422 return CLI_SUCCESS;
10423}
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:2036
#define queue_t_unref(q, tag)
Definition app_queue.c:2193
#define queue_unref(q)
Definition app_queue.c:2191
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:4050
#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:1980
unsigned int found
Definition app_queue.c:1981
const ast_string_field name
Definition app_queue.c:1964
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 12141 of file app_queue.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

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

7757{
7758 struct call_queue *q;
7759 struct member *new_member, *old_member;
7760 int res = RES_NOSUCHQUEUE;
7761
7762 /*! \note Ensure the appropriate realtime queue is loaded. Note that this
7763 * short-circuits if the queue is already in memory. */
7764 if (!(q = find_load_queue_rt_friendly(queuename))) {
7765 return res;
7766 }
7767
7768 ao2_lock(q);
7769 if ((old_member = interface_exists(q, interface)) == NULL) {
7771 new_member->dynamic = 1;
7772 if (reason_paused) {
7773 ast_copy_string(new_member->reason_paused, reason_paused, sizeof(new_member->reason_paused));
7774 }
7775 member_add_to_queue(q, new_member);
7776 queue_publish_member_blob(queue_member_added_type(), queue_member_blob_create(q, new_member));
7777
7778 if (is_member_available(q, new_member)) {
7780 }
7781
7782 ao2_ref(new_member, -1);
7783 new_member = NULL;
7784
7785 if (dump) {
7787 }
7788
7789 res = RES_OKAY;
7790 } else {
7791 res = RES_OUTOFMEMORY;
7792 }
7793 } else {
7794 ao2_ref(old_member, -1);
7795 res = RES_EXISTS;
7796 }
7797 ao2_unlock(q);
7798 queue_t_unref(q, "Expiring temporary reference");
7799
7800 return res;
7801}
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:3005
static struct member * interface_exists(struct call_queue *q, const char *interface)
Definition app_queue.c:7621
static void dump_queue_members(struct call_queue *pm_queue)
Dump all members in a specific queue to the database.
Definition app_queue.c:7648
static int is_member_available(struct call_queue *q, struct member *mem)
Definition app_queue.c:2746
#define RES_OUTOFMEMORY
Definition app_queue.c:1694
#define RES_NOSUCHQUEUE
Definition app_queue.c:1695
#define RES_OKAY
Definition app_queue.c:1692
static void member_add_to_queue(struct call_queue *queue, struct member *mem)
Definition app_queue.c:3701
static struct ast_json * queue_member_blob_create(struct call_queue *q, struct member *mem)
Definition app_queue.c:2530
#define RES_EXISTS
Definition app_queue.c:1693
static void queue_publish_member_blob(struct stasis_message_type *type, struct ast_json *blob)
Definition app_queue.c:2506
@ 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:1968
char interface[AST_CHANNEL_NAME]
Definition app_queue.c:1861
int dynamic
Definition app_queue.c:1869
char membername[80]
Definition app_queue.c:1866
int penalty
Definition app_queue.c:1867
int paused
Definition app_queue.c:1872
int wrapuptime
Definition app_queue.c:1876
char reason_paused[80]
Definition app_queue.c:1873
char state_interface[AST_CHANNEL_NAME]
Definition app_queue.c:1864

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

3883{
3884 struct call_queue *q;
3885
3886 if ((q = ao2_t_alloc(sizeof(*q), destroy_queue, "Allocate queue"))) {
3887 if (ast_string_field_init(q, 64)) {
3888 queue_t_unref(q, "String field allocation failed");
3889 return NULL;
3890 }
3891 ast_string_field_set(q, name, queuename);
3892 }
3893 return q;
3894}
static void destroy_queue(void *obj)
Free queue's member list then its string fields.
Definition app_queue.c:3867
#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 8522 of file app_queue.c.

8523{
8524 int res=-1;
8525 char *parse, *tmp, *temppos = NULL, *reason = NULL;
8527 AST_APP_ARG(queuename);
8528 AST_APP_ARG(interface);
8529 AST_APP_ARG(penalty);
8531 AST_APP_ARG(membername);
8532 AST_APP_ARG(state_interface);
8533 AST_APP_ARG(wrapuptime);
8534 );
8535 int penalty = 0;
8536 int paused = 0;
8537 int wrapuptime;
8538 struct ast_flags flags = { 0 };
8539
8540 if (ast_strlen_zero(data)) {
8541 ast_log(LOG_WARNING, "AddQueueMember requires an argument (queuename[,interface[,penalty[,options[,membername[,stateinterface][,wrapuptime]]]]])\n");
8542 return -1;
8543 }
8544
8545 parse = ast_strdupa(data);
8546
8548
8549 if (args.options) {
8550 char *opts[AQM_OPT_ARG_ARRAY_SIZE] = { NULL, };
8551 ast_app_parse_options(aqm_opts, &flags, opts, args.options);
8553 paused = 1;
8555 reason = ast_strdupa(opts[AQM_OPT_ARG_PAUSE_REASON]);
8556 }
8557 }
8558 }
8559
8560 if (ast_strlen_zero(args.interface)) {
8561 args.interface = ast_strdupa(ast_channel_name(chan));
8562 temppos = strrchr(args.interface, '-');
8563 if (temppos) {
8564 *temppos = '\0';
8565 }
8566 }
8567
8568 if (!ast_strlen_zero(args.penalty)) {
8569 if ((sscanf(args.penalty, "%30d", &penalty) != 1) || penalty < 0) {
8570 ast_log(LOG_WARNING, "Penalty '%s' is invalid, must be an integer >= 0\n", args.penalty);
8571 penalty = 0;
8572 }
8573 }
8574
8575 if (!ast_strlen_zero(args.wrapuptime)) {
8576 tmp = args.wrapuptime;
8577 ast_strip(tmp);
8578 wrapuptime = atoi(tmp);
8579 if (wrapuptime < 0) {
8580 wrapuptime = 0;
8581 }
8582 } else {
8583 wrapuptime = 0;
8584 }
8585
8586 switch (add_to_queue(args.queuename, args.interface, args.membername, penalty, paused, queue_persistent_members, args.state_interface, reason, wrapuptime)) {
8587 case RES_OKAY:
8588 if (ast_strlen_zero(args.membername) || !log_membername_as_agent) {
8589 ast_queue_log(args.queuename, ast_channel_uniqueid(chan), args.interface, "ADDMEMBER", "%s", paused ? "PAUSED" : "");
8590 } else {
8591 ast_queue_log(args.queuename, ast_channel_uniqueid(chan), args.membername, "ADDMEMBER", "%s", paused ? "PAUSED" : "");
8592 }
8593 ast_log(LOG_NOTICE, "Added interface '%s' to queue '%s'\n", args.interface, args.queuename);
8594 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "ADDED");
8595 res = 0;
8596 break;
8597 case RES_EXISTS:
8598 ast_log(LOG_WARNING, "Unable to add interface '%s' to queue '%s': Already there\n", args.interface, args.queuename);
8599 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "MEMBERALREADY");
8600 res = 0;
8601 break;
8602 case RES_NOSUCHQUEUE:
8603 ast_log(LOG_WARNING, "Unable to add interface to queue '%s': No such queue\n", args.queuename);
8604 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "NOSUCHQUEUE");
8605 res = 0;
8606 break;
8607 case RES_OUTOFMEMORY:
8608 ast_log(LOG_ERROR, "Out of memory adding interface %s to queue %s\n", args.interface, args.queuename);
8609 break;
8610 }
8611
8612 return res;
8613}
static int queue_persistent_members
queues.conf [general] option
Definition app_queue.c:1717
static int log_membername_as_agent
queues.conf [general] option
Definition app_queue.c:1741
static const struct ast_app_option aqm_opts[128]
Definition app_queue.c:1630
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:7756
#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 @519 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 12141 of file app_queue.c.

◆ autopause2int()

static int autopause2int ( const char *  autopause)
static

Definition at line 2083 of file app_queue.c.

2084{
2085 int x;
2086 /*This 'double check' that default value is OFF */
2088 return QUEUE_AUTOPAUSE_OFF;
2089 }
2090
2091 /*This 'double check' is to ensure old values works */
2092 if(ast_true(autopause)) {
2093 return QUEUE_AUTOPAUSE_ON;
2094 }
2095
2096 for (x = 0; x < ARRAY_LEN(autopausesmodes); x++) {
2097 if (!strcasecmp(autopause, autopausesmodes[x].name)) {
2098 return autopausesmodes[x].autopause;
2099 }
2100 }
2101
2102 /*This 'double check' that default value is OFF */
2103 return QUEUE_AUTOPAUSE_OFF;
2104}
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:1672
#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 6199 of file app_queue.c.

6200{
6201 /* disregarding penalty on too few members? */
6202 int membercount = ao2_container_count(q->members);
6203 unsigned char usepenalty = (membercount <= q->penaltymemberslimit) ? 0 : 1;
6204 int penalty = mem->penalty;
6205
6206 if (usepenalty) {
6207 if (qe->raise_penalty != INT_MAX && penalty < qe->raise_penalty) {
6208 /* Low penalty is raised up to the current minimum */
6209 penalty = qe->raise_penalty;
6210 }
6211 if ((qe->max_penalty != INT_MAX && penalty > qe->max_penalty) ||
6212 (qe->min_penalty != INT_MAX && penalty < qe->min_penalty)) {
6213 return -1;
6214 }
6215 } else {
6216 ast_debug(1, "Disregarding penalty, %d members and %d in penaltymemberslimit.\n",
6217 membercount, q->penaltymemberslimit);
6218 }
6219
6220 switch (q->strategy) {
6222 /* Everyone equal, except for penalty */
6223 tmp->metric = penalty * 1000000 * usepenalty;
6224 break;
6226 if (pos < qe->linpos) {
6227 tmp->metric = 1000 + pos;
6228 } else {
6229 if (pos > qe->linpos) {
6230 /* Indicate there is another priority */
6231 qe->linwrapped = 1;
6232 }
6233 tmp->metric = pos;
6234 }
6235 tmp->metric += penalty * 1000000 * usepenalty;
6236 break;
6239 pos = mem->queuepos;
6240 if (pos < q->rrpos) {
6241 tmp->metric = 1000 + pos;
6242 } else {
6243 if (pos > q->rrpos) {
6244 /* Indicate there is another priority */
6245 q->wrapped = 1;
6246 }
6247 tmp->metric = pos;
6248 }
6249 tmp->metric += penalty * 1000000 * usepenalty;
6250 break;
6252 tmp->metric = ast_random() % 1000;
6253 tmp->metric += penalty * 1000000 * usepenalty;
6254 break;
6256 tmp->metric = ast_random() % ((1 + penalty) * 1000);
6257 break;
6259 tmp->metric = mem->calls;
6260 tmp->metric += penalty * 1000000 * usepenalty;
6261 break;
6263 if (!mem->lastcall) {
6264 tmp->metric = 0;
6265 } else {
6266 tmp->metric = 1000000 - (time(NULL) - mem->lastcall);
6267 }
6268 tmp->metric += penalty * 1000000 * usepenalty;
6269 break;
6270 default:
6271 ast_log(LOG_WARNING, "Can't calculate metric for unknown strategy %d\n", q->strategy);
6272 break;
6273 }
6274 return 0;
6275}
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:2022
int penaltymemberslimit
Definition app_queue.c:2006
unsigned int wrapped
Definition app_queue.c:1974
int queuepos
Definition app_queue.c:1874
time_t lastcall
Definition app_queue.c:1878
int calls
Definition app_queue.c:1868
int max_penalty
Definition app_queue.c:1843
int raise_penalty
Definition app_queue.c:1845
int min_penalty
Definition app_queue.c:1844
int linwrapped
Definition app_queue.c:1848
long int ast_random(void)
Definition utils.c:2348

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

Referenced by try_calling().

◆ callattempt_free()

static void callattempt_free ( struct callattempt doomed)
static

Definition at line 4602 of file app_queue.c.

4603{
4604 if (doomed->member) {
4605 ao2_ref(doomed->member, -1);
4606 }
4608 ast_free(doomed->orig_chan_name);
4609 ast_free(doomed);
4610}
#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:1810
char * orig_chan_name
Definition app_queue.c:1821
struct member * member
Definition app_queue.c:1808

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

4813{
4814 struct member *memberp = call->member;
4815 int wrapuptime;
4816
4817 if (memberp->paused) {
4818 ast_debug(1, "%s paused, can't receive call\n", call->interface);
4819 return 0;
4820 }
4821
4822 if (!memberp->ringinuse && !member_status_available(memberp->status)) {
4823 ast_debug(1, "%s not available, can't receive call\n", call->interface);
4824 return 0;
4825 }
4826
4827 if (memberp->lastqueue) {
4828 wrapuptime = get_wrapuptime(memberp->lastqueue, memberp);
4829 } else {
4830 wrapuptime = get_wrapuptime(qe->parent, memberp);
4831 }
4832 if (wrapuptime && (time(NULL) - memberp->lastcall) < wrapuptime) {
4833 ast_debug(1, "Wrapuptime not yet expired on queue %s for %s\n",
4834 (memberp->lastqueue ? memberp->lastqueue->name : qe->parent->name),
4835 call->interface);
4836 return 0;
4837 }
4838
4839 if (use_weight && compare_weight(qe->parent, memberp)) {
4840 ast_debug(1, "Priority queue delaying call to %s:%s\n",
4841 qe->parent->name, call->interface);
4842 return 0;
4843 }
4844
4846 ast_debug(1, "Another caller was waiting longer; delaying call to %s:%s\n",
4847 qe->parent->name, call->interface);
4848 return 0;
4849 }
4850
4851 if (!memberp->ringinuse) {
4852 struct member *mem;
4853
4855
4856 mem = ao2_find(pending_members, memberp,
4858 if (mem) {
4859 /*
4860 * If found that means this member is currently being attempted
4861 * from another calling thread, so stop trying from this thread
4862 */
4863 ast_debug(1, "%s has another call trying, can't receive call\n",
4864 call->interface);
4865 ao2_ref(mem, -1);
4867 return 0;
4868 }
4869
4870 /*
4871 * If not found add it to the container so another queue
4872 * won't attempt to call this member at the same time.
4873 */
4874 ast_debug(3, "Add %s to pending_members\n", memberp->membername);
4875 ao2_link(pending_members, memberp);
4877
4878 /*
4879 * The queue member is available. Get current status to be sure
4880 * because the device state and extension state callbacks may
4881 * not have updated the status yet.
4882 */
4884 ast_debug(1, "%s actually not available, can't receive call\n",
4885 call->interface);
4886 pending_members_remove(memberp);
4887 return 0;
4888 }
4889 }
4890
4891 return 1;
4892}
static int is_longest_waiting_caller(struct queue_ent *caller, struct member *member)
Definition app_queue.c:4731
static int get_wrapuptime(struct call_queue *q, struct member *member)
Return wrapuptime.
Definition app_queue.c:2126
static int compare_weight(struct call_queue *rq, struct member *member)
Definition app_queue.c:4697
static struct ao2_container * pending_members
Definition app_queue.c:2653
static int force_longest_waiting_caller
queues.conf [general] option
Definition app_queue.c:1744
static void pending_members_remove(struct member *mem)
Definition app_queue.c:2704
static int get_queue_member_status(struct member *cur)
Return the current state of a member.
Definition app_queue.c:2990
static int use_weight
Records that one or more queues use weight.
Definition app_queue.c:1720
static int member_status_available(int status)
Definition app_queue.c:4798
#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:1871
unsigned int ringinuse
Definition app_queue.c:1885
struct call_queue * lastqueue
Definition app_queue.c:1881
struct call_queue * parent
Definition app_queue.c:1826

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

7810{
7811 struct call_queue *q;
7812 struct queue_ent *current, *prev = NULL, *caller_qe = NULL;
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. */
7818 return res;
7819 }
7820
7821 ao2_lock(q);
7823 for (current = q->head; current; current = current->next) {
7824 if (strcmp(ast_channel_name(current->chan), caller) == 0) {
7825 ast_debug(1, "%s Caller new priority %d in queue %s\n",
7826 caller, priority, queuename);
7827 current->prio = priority;
7828 if (immediate) {
7829 /* This caller is being immediately moved in the queue so remove them */
7830 if (prev) {
7831 prev->next = current->next;
7832 } else {
7833 q->head = current->next;
7834 }
7836 /* The position for all callers is not recalculated in here as it will
7837 * be updated when the moved caller is inserted back into the queue
7838 */
7839 }
7840 res = RES_OKAY;
7841 break;
7842 } else if (immediate) {
7843 prev = current;
7844 }
7845 }
7846
7847 if (caller_qe) {
7848 int inserted = 0, pos = 0;
7849
7850 /* If a caller queue entry exists, we are applying their priority immediately
7851 * and have to reinsert them at the correct position.
7852 */
7853 prev = NULL;
7854 current = q->head;
7855 while (current) {
7856 if (!inserted && (caller_qe->prio > current->prio)) {
7857 insert_entry(q, prev, caller_qe, &pos);
7858 inserted = 1;
7859 }
7860
7861 /* We always update the position as it may have changed */
7862 current->pos = ++pos;
7863
7864 /* Move to the next caller in the queue */
7865 prev = current;
7866 current = current->next;
7867 }
7868
7869 if (!inserted) {
7870 insert_entry(q, prev, caller_qe, &pos);
7871 }
7872 }
7873
7874 ao2_unlock(q);
7875 return res;
7876}
#define RES_NOT_CALLER
Definition app_queue.c:1697
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:2224
static int priority
size_t current
struct queue_ent * head
Definition app_queue.c:2023
time_t start
Definition app_queue.c:1849
struct queue_ent * next
Definition app_queue.c:1857

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

3192{
3193 q->holdtime = 0;
3194 q->callscompleted = 0;
3195 q->callsabandoned = 0;
3196 q->callscompletedinsl = 0;
3197 q->callsabandonedinsl = 0;
3198 q->talktime = 0;
3199
3200 if (q->members) {
3201 struct member *mem;
3202 struct ao2_iterator mem_iter = ao2_iterator_init(q->members, 0);
3203 while ((mem = ao2_iterator_next(&mem_iter))) {
3204 mem->calls = 0;
3205 mem->callcompletedinsl = 0;
3206 mem->lastcall = 0;
3207 mem->starttime = 0;
3208 ao2_ref(mem, -1);
3209 }
3210 ao2_iterator_destroy(&mem_iter);
3211 }
3212}
#define ao2_iterator_next(iter)
Definition astobj2.h:1911
int callsabandoned
Definition app_queue.c:1998
int callscompleted
Definition app_queue.c:1997
int callsabandonedinsl
Definition app_queue.c:1999
int callscompletedinsl
Definition app_queue.c:2001
time_t starttime
Definition app_queue.c:1877
int callcompletedinsl
Definition app_queue.c:1875

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

10162{
10163 struct call_queue *q;
10164 struct ao2_iterator queue_iter;
10165
10166 queue_iter = ao2_iterator_init(queues, 0);
10167 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
10168 ao2_lock(q);
10169 if (ast_strlen_zero(queuename) || !strcasecmp(q->name, queuename))
10170 clear_queue(q);
10171 ao2_unlock(q);
10172 queue_t_unref(q, "Done with iterator");
10173 }
10174 ao2_iterator_destroy(&queue_iter);
10175 return 0;
10176}
static void clear_queue(struct call_queue *q)
Definition app_queue.c:3191

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

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

10498{
10499 struct call_queue *q;
10500 char *ret = NULL;
10501 int which = 0;
10502 int wordlen = strlen(word);
10503 struct ao2_iterator queue_iter;
10504 const char *word_list = NULL;
10505
10506 /* for certain commands, already completed items should be left out of
10507 * the list */
10508 if (word_list_offset && strlen(line) >= word_list_offset) {
10509 word_list = line + word_list_offset;
10510 }
10511
10512 queue_iter = ao2_iterator_init(queues, 0);
10513 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
10514 if (!strncasecmp(word, q->name, wordlen) && ++which > state
10515 && (!word_list_offset || !word_list || !word_in_list(word_list, q->name))) {
10516 ret = ast_strdup(q->name);
10517 queue_t_unref(q, "Done with iterator");
10518 break;
10519 }
10520 queue_t_unref(q, "Done with iterator");
10521 }
10522 ao2_iterator_destroy(&queue_iter);
10523
10524 /* Pretend "rules" is at the end of the queues list in certain
10525 * circumstances since it is an alternate command that should be
10526 * tab-completable for "queue show" */
10527 if (!ret && which == state && !wordlen && !strncmp("queue show", line, 10)) {
10528 ret = ast_strdup("rules");
10529 }
10530
10531 return ret;
10532}
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 11004 of file app_queue.c.

11005{
11006 /* 0 - queue; 1 - add; 2 - member; 3 - <interface>; 4 - to; 5 - <queue>; 6 - penalty; 7 - <penalty>; 8 - as; 9 - <membername> */
11007 switch (pos) {
11008 case 3: /* Don't attempt to complete name of interface (infinite possibilities) */
11009 return NULL;
11010 case 4: /* only one possible match, "to" */
11011 return state == 0 ? ast_strdup("to") : NULL;
11012 case 5: /* <queue> */
11013 return complete_queue(line, word, pos, state, 0);
11014 case 6: /* only one possible match, "penalty" */
11015 return state == 0 ? ast_strdup("penalty") : NULL;
11016 case 7:
11017 if (0 <= state && state < 100) { /* 0-99 */
11018 char *num;
11019 if ((num = ast_malloc(3))) {
11020 sprintf(num, "%d", state);
11021 }
11022 return num;
11023 } else {
11024 return NULL;
11025 }
11026 case 8: /* only one possible match, "as" */
11027 return state == 0 ? ast_strdup("as") : NULL;
11028 case 9: /* Don't attempt to complete name of member (infinite possibilities) */
11029 return NULL;
11030 default:
11031 return NULL;
11032 }
11033}
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 11429 of file app_queue.c.

11430{
11431 /* 0 - queue; 1 - pause; 2 - member; 3 - <interface>; 4 - queue; 5 - <queue>; 6 - reason; 7 - <reason> */
11432 switch (pos) {
11433 case 3: /* Don't attempt to complete name of interface (infinite possibilities) */
11434 return NULL;
11435 case 4: /* only one possible match, "queue" */
11436 return state == 0 ? ast_strdup("queue") : NULL;
11437 case 5: /* <queue> */
11438 return complete_queue(line, word, pos, state, 0);
11439 case 6: /* "reason" */
11440 return state == 0 ? ast_strdup("reason") : NULL;
11441 case 7: /* Can't autocomplete a reason, since it's 100% customizeable */
11442 return NULL;
11443 default:
11444 return NULL;
11445 }
11446}

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

11265{
11266 int which = 0;
11267 struct call_queue *q;
11268 struct member *m;
11269 struct ao2_iterator queue_iter;
11270 struct ao2_iterator mem_iter;
11271 int wordlen = strlen(word);
11272
11273 /* 0 - queue; 1 - remove; 2 - member; 3 - <member>; 4 - from; 5 - <queue> */
11274 if (pos > 5 || pos < 3) {
11275 return NULL;
11276 }
11277 if (pos == 4) { /* only one possible match, 'from' */
11278 return (state == 0 ? ast_strdup("from") : NULL);
11279 }
11280
11281 if (pos == 5) { /* No need to duplicate code */
11282 return complete_queue(line, word, pos, state, 0);
11283 }
11284
11285 /* here is the case for 3, <member> */
11286 queue_iter = ao2_iterator_init(queues, 0);
11287 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
11288 ao2_lock(q);
11289 mem_iter = ao2_iterator_init(q->members, 0);
11290 while ((m = ao2_iterator_next(&mem_iter))) {
11291 if (!strncasecmp(word, m->membername, wordlen) && ++which > state) {
11292 char *tmp;
11293 tmp = ast_strdup(m->interface);
11294 ao2_ref(m, -1);
11295 ao2_iterator_destroy(&mem_iter);
11296 ao2_unlock(q);
11297 queue_t_unref(q, "Done with iterator, returning interface name");
11298 ao2_iterator_destroy(&queue_iter);
11299 return tmp;
11300 }
11301 ao2_ref(m, -1);
11302 }
11303 ao2_iterator_destroy(&mem_iter);
11304 ao2_unlock(q);
11305 queue_t_unref(q, "Done with iterator");
11306 }
11307 ao2_iterator_destroy(&queue_iter);
11308
11309 return NULL;
11310}

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

11625{
11626 int which = 0;
11627 struct rule_list *rl_iter;
11628 int wordlen = strlen(word);
11629 char *ret = NULL;
11630 if (pos != 3) /* Wha? */ {
11631 return NULL;
11632 }
11633
11635 AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) {
11636 if (!strncasecmp(word, rl_iter->name, wordlen) && ++which > state) {
11637 ret = ast_strdup(rl_iter->name);
11638 break;
11639 }
11640 }
11642
11643 return ret;
11644}
#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:2029
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 11503 of file app_queue.c.

11504{
11505 /* 0 - queue; 1 - set; 2 - penalty/ringinuse; 3 - <value>; 4 - on; 5 - <member>; 6 - in; 7 - <queue>;*/
11506 switch (pos) {
11507 case 4:
11508 if (state == 0) {
11509 return ast_strdup("on");
11510 } else {
11511 return NULL;
11512 }
11513 case 6:
11514 if (state == 0) {
11515 return ast_strdup("in");
11516 } else {
11517 return NULL;
11518 }
11519 case 7:
11520 return complete_queue(line, word, pos, state, 0);
11521 default:
11522 return NULL;
11523 }
11524}

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

10535{
10536 if (pos == 2) {
10537 return complete_queue(line, word, pos, state, 0);
10538 }
10539 return NULL;
10540}

References complete_queue(), and NULL.

Referenced by queue_show().

◆ compress_char()

static int compress_char ( const char  c)
static

Definition at line 3050 of file app_queue.c.

3051{
3052 if (c < 32) {
3053 return 0;
3054 } else if (c > 96) {
3055 return c - 64;
3056 }
3057 return c - 32;
3058}
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 2917 of file app_queue.c.

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

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

3006{
3007 struct member *cur;
3008
3009 if ((cur = ao2_alloc(sizeof(*cur), destroy_queue_member_cb))) {
3010 cur->ringinuse = ringinuse;
3011 cur->penalty = penalty;
3012 cur->paused = paused;
3013 cur->wrapuptime = wrapuptime;
3014 if (paused) {
3015 time(&cur->lastpause); /* Update time of last pause */
3016 }
3017 time(&cur->logintime);
3018 ast_copy_string(cur->interface, interface, sizeof(cur->interface));
3021 } else {
3023 }
3025 ast_copy_string(cur->membername, membername, sizeof(cur->membername));
3026 } else {
3027 ast_copy_string(cur->membername, interface, sizeof(cur->membername));
3028 }
3029 if (!strchr(cur->interface, '/')) {
3030 ast_log(LOG_WARNING, "No location at interface '%s'\n", interface);
3031 }
3032 if (!strncmp(cur->state_interface, "hint:", 5)) {
3033 char *tmp = ast_strdupa(cur->state_interface), *context = tmp;
3034 char *exten = strsep(&context, "@") + 5;
3035
3036 ast_copy_string(cur->state_exten, exten, sizeof(cur->state_exten));
3037 ast_copy_string(cur->state_context, S_OR(context, "default"), sizeof(cur->state_context));
3038
3040 } else {
3041 cur->state_id = -1;
3042 }
3043 cur->status = get_queue_member_status(cur);
3044 }
3045
3046 return cur;
3047}
static int extension_state_cb(const char *context, const char *exten, struct ast_state_cb_info *info, void *data)
Definition app_queue.c:2946
static void destroy_queue_member_cb(void *obj)
Definition app_queue.c:2995
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:1880
char state_exten[AST_MAX_EXTENSION]
Definition app_queue.c:1862
char state_context[AST_MAX_CONTEXT]
Definition app_queue.c:1863
int state_id
Definition app_queue.c:1865
time_t lastpause
Definition app_queue.c:1879

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

3868{
3869 struct call_queue *q = obj;
3870 int i;
3871
3872 free_members(q, 1);
3874 for (i = 0; i < MAX_PERIODIC_ANNOUNCEMENTS; i++) {
3875 if (q->sound_periodicannounce[i]) {
3877 }
3878 }
3879 ao2_ref(q->members, -1);
3880}
#define MAX_PERIODIC_ANNOUNCEMENTS
Definition app_queue.c:1683
static void free_members(struct call_queue *q, int all)
Iterate through queue's member list and delete them.
Definition app_queue.c:3851
#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:1966

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

2996{
2997 struct member *mem = obj;
2998
2999 if (mem->state_id != -1) {
3001 }
3002}
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 2781 of file app_queue.c.

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

4783{
4784 o->stillgoing = 0;
4785 ast_hangup(o->chan);
4787 o->chan = NULL;
4788}
void ast_hangup(struct ast_channel *chan)
Hang up a channel.
Definition channel.c:2538
struct ast_channel * chan
Definition app_queue.c:1805
unsigned int stillgoing
Definition app_queue.c:1818

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

10209{
10210 if (s) {
10211 astman_append(s, "%s\r\n", str);
10212 } else {
10213 ast_cli(fd, "%s\n", str);
10214 }
10215}
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:1714

Definition at line 7648 of file app_queue.c.

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

6998{
6999 struct queue_end_bridge *qeb = data;
7000 struct call_queue *q = qeb->q;
7001 struct ast_channel *chan = qeb->chan;
7002
7003 if (ao2_ref(qeb, -1) == 1) {
7004 set_queue_variables(q, chan);
7005 /* This unrefs the reference we made in try_calling when we allocated qeb */
7006 queue_t_unref(q, "Expire bridge_config reference");
7007 }
7008}
static void set_queue_variables(struct call_queue *q, struct ast_channel *chan)
Set variables of queue.
Definition app_queue.c:2198
Main Channel structure associated with a channel.
struct call_queue * q
Definition app_queue.c:6986
struct ast_channel * chan
Definition app_queue.c:6987

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

Referenced by try_calling().

◆ end_bridge_callback_data_fixup()

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

Definition at line 6990 of file app_queue.c.

6991{
6992 struct queue_end_bridge *qeb = bconfig->end_bridge_callback_data;
6993 ao2_ref(qeb, +1);
6994 qeb->chan = originator;
6995}
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 7037 of file app_queue.c.

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

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

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

2869{
2870 switch (state) {
2873 break;
2876 break;
2877 case AST_EXTENSION_BUSY:
2879 break;
2882 break;
2885 break;
2888 break;
2891 break;
2894 break;
2897 default:
2899 break;
2900 }
2901
2902 return state;
2903}
@ 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 5040 of file app_queue.c.

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

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

4051{
4052 struct ast_variable *queue_vars;
4053 struct ast_config *member_config = NULL;
4054 struct call_queue *q = NULL, tmpq = {
4055 .name = queuename,
4056 };
4057 int prev_weight = 0;
4058
4059 /* Find the queue in the in-core list first. */
4060 q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Look for queue in memory first");
4061
4062 if (!q || q->realtime) {
4063 /*! \note Load from realtime before taking the "queues" container lock, to avoid blocking all
4064 queue operations while waiting for the DB.
4065
4066 This will be two separate database transactions, so we might
4067 see queue parameters as they were before another process
4068 changed the queue and member list as it was after the change.
4069 Thus we might see an empty member list when a queue is
4070 deleted. In practise, this is unlikely to cause a problem. */
4071
4072 queue_vars = ast_load_realtime("queues", "name", queuename, SENTINEL);
4073 if (queue_vars) {
4074 member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name", queuename, SENTINEL);
4075 if (!member_config) {
4076 ast_debug(1, "No queue_members defined in config extconfig.conf\n");
4077 member_config = ast_config_new();
4078 }
4079 }
4080 if (q) {
4081 prev_weight = q->weight ? 1 : 0;
4082 queue_t_unref(q, "Need to find realtime queue");
4083 }
4084
4085 q = find_queue_by_name_rt(queuename, queue_vars, member_config);
4086 ast_config_destroy(member_config);
4087 ast_variables_destroy(queue_vars);
4088
4089 /* update the use_weight value if the queue's has gained or lost a weight */
4090 if (q) {
4091 if (!q->weight && prev_weight) {
4093 }
4094 if (q->weight && !prev_weight) {
4096 }
4097 }
4098 /* Other cases will end up with the proper value for use_weight */
4099 } else {
4101 }
4102 return q;
4103}
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:3906
static void update_realtime_members(struct call_queue *q)
Definition app_queue.c:4155
#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 12121 of file app_queue.c.

12122{
12123 struct member *mem = NULL;
12124 struct call_queue *q;
12125
12126 if ((q = find_load_queue_rt_friendly(queuename))) {
12127 ao2_lock(q);
12128 mem = ao2_find(q->members, interface, OBJ_KEY);
12129 ao2_unlock(q);
12130 queue_t_unref(q, "Expiring temporary reference.");
12131 }
12132 return mem;
12133}
#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 3906 of file app_queue.c.

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

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

3852{
3853 /* Free non-dynamic members */
3854 struct member *cur;
3855 struct ao2_iterator mem_iter = ao2_iterator_init(q->members, 0);
3856
3857 while ((cur = ao2_iterator_next(&mem_iter))) {
3858 if (all || !cur->dynamic) {
3860 }
3861 ao2_ref(cur, -1);
3862 }
3863 ao2_iterator_destroy(&mem_iter);
3864}

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

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

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

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

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

2991{
2992 return ast_strlen_zero(cur->state_exten) ? ast_device_state(cur->state_interface) : extensionstate2devicestate(ast_extension_state(NULL, cur->state_context, cur->state_exten));
2993}
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 2126 of file app_queue.c.

2127{
2128 if (member->wrapuptime) {
2129 return member->wrapuptime;
2130 }
2131 return q->wrapuptime;
2132}

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

6625{
6626 struct queue_stasis_data *queue_data = userdata;
6627 struct ast_attended_transfer_message *atxfer_msg = stasis_message_data(msg);
6628 RAII_VAR(struct ast_channel_snapshot *, caller_snapshot, NULL, ao2_cleanup);
6629 RAII_VAR(struct ast_channel_snapshot *, member_snapshot, NULL, ao2_cleanup);
6630
6631 if (atxfer_msg->result != AST_BRIDGE_TRANSFER_SUCCESS ||
6633 return;
6634 }
6635
6636 ao2_lock(queue_data);
6637
6638 if (queue_data->dying) {
6639 ao2_unlock(queue_data);
6640 return;
6641 }
6642
6643 if (ast_strlen_zero(queue_data->bridge_uniqueid)) {
6644 ao2_unlock(queue_data);
6645 return;
6646 }
6647
6648 if ((!atxfer_msg->to_transferee.bridge_snapshot || strcmp(queue_data->bridge_uniqueid,
6649 atxfer_msg->to_transferee.bridge_snapshot->uniqueid)) &&
6650 (!atxfer_msg->to_transfer_target.bridge_snapshot || strcmp(queue_data->bridge_uniqueid,
6652 ao2_unlock(queue_data);
6653 return;
6654 }
6655
6656 caller_snapshot = ast_channel_snapshot_get_latest(queue_data->caller_uniqueid);
6657 member_snapshot = ast_channel_snapshot_get_latest(queue_data->member_uniqueid);
6658
6659 ao2_unlock(queue_data);
6660
6661 ast_debug(3, "Detected attended transfer in queue %s\n", queue_data->queue->name);
6662 log_attended_transfer(queue_data, atxfer_msg);
6663
6664 send_agent_complete(queue_data->queue->name, caller_snapshot, member_snapshot, queue_data->member,
6665 queue_data->holdstart, queue_data->starttime, TRANSFER);
6666 update_queue(queue_data->queue, queue_data->member, queue_data->callcompletedinsl,
6667 queue_data->starttime);
6668 remove_stasis_subscriptions(queue_data);
6669}
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:6284
static int update_queue(struct call_queue *q, struct member *member, int callcompletedinsl, time_t starttime)
update the queue status
Definition app_queue.c:6127
static void remove_stasis_subscriptions(struct queue_stasis_data *queue_data)
Definition app_queue.c:6431
static void log_attended_transfer(struct queue_stasis_data *queue_data, struct ast_attended_transfer_message *atxfer_msg)
Definition app_queue.c:6485
#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:6377
const ast_string_field caller_uniqueid
Definition app_queue.c:6385
const ast_string_field member_uniqueid
Definition app_queue.c:6385
struct call_queue * queue
Definition app_queue.c:6387
const ast_string_field bridge_uniqueid
Definition app_queue.c:6385
struct member * member
Definition app_queue.c:6389
#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 6564 of file app_queue.c.

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

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

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

6699{
6700 struct queue_stasis_data *queue_data = userdata;
6701 struct ast_multi_channel_blob *optimization_blob = stasis_message_data(msg);
6702 struct ast_channel_snapshot *local_one = ast_multi_channel_blob_get_channel(optimization_blob, "1");
6703 struct ast_channel_snapshot *local_two = ast_multi_channel_blob_get_channel(optimization_blob, "2");
6704 struct ast_channel_snapshot *source = ast_multi_channel_blob_get_channel(optimization_blob, "source");
6705 struct local_optimization *optimization;
6706 unsigned int id;
6707 SCOPED_AO2LOCK(lock, queue_data);
6708
6709 if (!local_one || !local_two || !source) {
6710 ast_debug(1, "Local optimization begin missing channel snapshots:%s%s%s\n",
6711 !local_one ? " local_one," : "",
6712 !local_two ? " local_two," : "",
6713 !source ? " source," : "");
6714 return;
6715 }
6716
6717 if (queue_data->dying) {
6718 return;
6719 }
6720
6721 if (!strcmp(local_one->base->uniqueid, queue_data->member_uniqueid)) {
6722 optimization = &queue_data->member_optimize;
6723 } else if (!strcmp(local_two->base->uniqueid, queue_data->caller_uniqueid)) {
6724 optimization = &queue_data->caller_optimize;
6725 } else {
6726 return;
6727 }
6728
6729 /* We only allow move-swap optimizations, so there had BETTER be a source */
6730 ast_assert(source != NULL);
6731
6732 optimization->source_chan_uniqueid = ast_strdup(source->base->uniqueid);
6733 if (!optimization->source_chan_uniqueid) {
6734 ast_log(LOG_ERROR, "Unable to track local channel optimization for channel %s. Expect further errors\n", local_one->base->name);
6735 return;
6736 }
6738
6739 optimization->id = id;
6740 optimization->in_progress = 1;
6741}
enum queue_result id
Definition app_queue.c:1771
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:6353
const char * source_chan_uniqueid
Definition app_queue.c:6355
unsigned int id
Definition app_queue.c:6359
struct local_optimization member_optimize
Definition app_queue.c:6407
struct local_optimization caller_optimize
Definition app_queue.c:6405
#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 6756 of file app_queue.c.

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

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

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

11180{
11181 const char *queuename, *interface, *membername = NULL, *state_interface = NULL, *reason = NULL;
11182 int penalty, paused = 0;
11183
11184 switch ( cmd ) {
11185 case CLI_INIT:
11186 e->command = "queue add member";
11187 e->usage =
11188 "Usage: queue add member <dial string> to <queue> [penalty <penalty> [as <membername> [state_interface <interface> [paused <reason>]]]]\n"
11189 " 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";
11190 return NULL;
11191 case CLI_GENERATE:
11192 return complete_queue_add_member(a->line, a->word, a->pos, a->n);
11193 }
11194
11195 if ((a->argc != 6) && (a->argc != 8) && (a->argc != 10) && (a->argc != 12) && (a->argc != 14)) {
11196 return CLI_SHOWUSAGE;
11197 } else if (strcmp(a->argv[4], "to")) {
11198 return CLI_SHOWUSAGE;
11199 } else if ((a->argc >= 8) && strcmp(a->argv[6], "penalty")) {
11200 return CLI_SHOWUSAGE;
11201 } else if ((a->argc >= 10) && strcmp(a->argv[8], "as")) {
11202 return CLI_SHOWUSAGE;
11203 } else if ((a->argc == 12) && strcmp(a->argv[10], "state_interface")) {
11204 return CLI_SHOWUSAGE;
11205 } else if ((a->argc == 14) && strcmp(a->argv[12], "paused")) {
11206 return CLI_SHOWUSAGE;
11207 }
11208
11209 queuename = a->argv[5];
11210 interface = a->argv[3];
11211 if (a->argc >= 8) {
11212 if (sscanf(a->argv[7], "%30d", &penalty) == 1) {
11213 if (penalty < 0) {
11214 ast_cli(a->fd, "Penalty must be >= 0\n");
11215 penalty = 0;
11216 }
11217 } else {
11218 ast_cli(a->fd, "Penalty must be an integer >= 0\n");
11219 penalty = 0;
11220 }
11221 } else {
11222 penalty = 0;
11223 }
11224
11225 if (a->argc >= 10) {
11226 membername = a->argv[9];
11227 }
11228
11229 if (a->argc >= 12) {
11230 state_interface = a->argv[11];
11231 }
11232
11233 if (a->argc >= 14) {
11234 paused = 1;
11235 reason = a->argv[13];
11236 }
11237
11238 switch (add_to_queue(queuename, interface, membername, penalty, paused, queue_persistent_members, state_interface, reason, 0)) {
11239 case RES_OKAY:
11240 if (ast_strlen_zero(membername) || !log_membername_as_agent) {
11241 ast_queue_log(queuename, "CLI", interface, "ADDMEMBER", "%s", paused ? "PAUSED" : "");
11242 } else {
11243 ast_queue_log(queuename, "CLI", membername, "ADDMEMBER", "%s", paused ? "PAUSED" : "");
11244 }
11245 ast_cli(a->fd, "Added interface '%s' to queue '%s'\n", interface, queuename);
11246 return CLI_SUCCESS;
11247 case RES_EXISTS:
11248 ast_cli(a->fd, "Unable to add interface '%s' to queue '%s': Already there\n", interface, queuename);
11249 return CLI_FAILURE;
11250 case RES_NOSUCHQUEUE:
11251 ast_cli(a->fd, "Unable to add interface to queue '%s': No such queue\n", queuename);
11252 return CLI_FAILURE;
11253 case RES_OUTOFMEMORY:
11254 ast_cli(a->fd, "Out of memory\n");
11255 return CLI_FAILURE;
11256 case RES_NOT_DYNAMIC:
11257 ast_cli(a->fd, "Member not dynamic\n");
11258 return CLI_FAILURE;
11259 default:
11260 return CLI_FAILURE;
11261 }
11262}
#define RES_NOT_DYNAMIC
Definition app_queue.c:1696
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 11375 of file app_queue.c.

11376{
11377 const char *queuename, *caller;
11378 int priority, immediate = 0;
11379 char *res = CLI_FAILURE;
11380
11381 switch (cmd) {
11382 case CLI_INIT:
11383 e->command = "queue priority caller";
11384 e->usage =
11385 "Usage: queue priority caller <channel> on <queue> to <priority> [immediate]\n"
11386 " Change the priority of a channel on a queue, optionally applying the change in relation to existing callers.\n";
11387 return NULL;
11388 case CLI_GENERATE:
11389 return NULL;
11390 }
11391
11392 if (a->argc < 8) {
11393 return CLI_SHOWUSAGE;
11394 } else if (strcmp(a->argv[4], "on")) {
11395 return CLI_SHOWUSAGE;
11396 } else if (strcmp(a->argv[6], "to")) {
11397 return CLI_SHOWUSAGE;
11398 } else if (sscanf(a->argv[7], "%30d", &priority) != 1) {
11399 ast_log (LOG_ERROR, "<priority> parameter must be an integer.\n");
11400 return CLI_SHOWUSAGE;
11401 } else if (a->argc == 9) {
11402 if (strcmp(a->argv[8], "immediate")) {
11403 return CLI_SHOWUSAGE;
11404 }
11405 immediate = 1;
11406 }
11407
11408 caller = a->argv[3];
11409 queuename = a->argv[5];
11410
11411 switch (change_priority_caller_on_queue(queuename, caller, priority, immediate)) {
11412 case RES_OKAY:
11413 res = CLI_SUCCESS;
11414 break;
11415 case RES_NOSUCHQUEUE:
11416 ast_cli(a->fd, "Unable change priority caller %s on queue '%s': No such queue\n", caller, queuename);
11417 break;
11418 case RES_NOT_CALLER:
11419 ast_cli(a->fd, "Unable to change priority caller '%s' on queue '%s': Not there\n", caller, queuename);
11420
11421 break;
11422 }
11423
11424 return res;
11425}
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:7809

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

11449{
11450 const char *queuename, *interface, *reason;
11451 int paused;
11452
11453 switch (cmd) {
11454 case CLI_INIT:
11455 e->command = "queue {pause|unpause} member";
11456 e->usage =
11457 "Usage: queue {pause|unpause} member <member> [queue <queue> [reason <reason>]]\n"
11458 " Pause or unpause a queue member. Not specifying a particular queue\n"
11459 " will pause or unpause a member across all queues to which the member\n"
11460 " belongs.\n";
11461 return NULL;
11462 case CLI_GENERATE:
11463 return complete_queue_pause_member(a->line, a-> word, a->pos, a->n);
11464 }
11465
11466 if (a->argc < 4 || a->argc == 5 || a->argc == 7 || a->argc > 8) {
11467 return CLI_SHOWUSAGE;
11468 } else if (a->argc >= 5 && strcmp(a->argv[4], "queue")) {
11469 return CLI_SHOWUSAGE;
11470 } else if (a->argc == 8 && strcmp(a->argv[6], "reason")) {
11471 return CLI_SHOWUSAGE;
11472 }
11473
11474
11475 interface = a->argv[3];
11476 queuename = a->argc >= 6 ? a->argv[5] : NULL;
11477 reason = a->argc == 8 ? a->argv[7] : NULL;
11478 paused = !strcasecmp(a->argv[1], "pause");
11479
11480 if (set_member_paused(queuename, interface, reason, paused) == RESULT_SUCCESS) {
11481 ast_cli(a->fd, "%spaused interface '%s'", paused ? "" : "un", interface);
11482 if (!ast_strlen_zero(queuename)) {
11483 ast_cli(a->fd, " in queue '%s'", queuename);
11484 }
11485 if (!ast_strlen_zero(reason)) {
11486 ast_cli(a->fd, " for reason '%s'", reason);
11487 }
11488 ast_cli(a->fd, "\n");
11489 return CLI_SUCCESS;
11490 } else {
11491 ast_cli(a->fd, "Unable to %spause interface '%s'", paused ? "" : "un", interface);
11492 if (!ast_strlen_zero(queuename)) {
11493 ast_cli(a->fd, " in queue '%s'", queuename);
11494 }
11495 if (!ast_strlen_zero(reason)) {
11496 ast_cli(a->fd, " for reason '%s'", reason);
11497 }
11498 ast_cli(a->fd, "\n");
11499 return CLI_FAILURE;
11500 }
11501}
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:8020
#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 11720 of file app_queue.c.

11721{
11722 struct ast_flags mask = {0,};
11723 int i;
11724
11725 switch (cmd) {
11726 case CLI_INIT:
11727 e->command = "queue reload {parameters|members|rules|all}";
11728 e->usage =
11729 "Usage: queue reload {parameters|members|rules|all} [<queuenames>]\n"
11730 "Reload queues. If <queuenames> are specified, only reload information pertaining\n"
11731 "to <queuenames>. One of 'parameters,' 'members,' 'rules,' or 'all' must be\n"
11732 "specified in order to know what information to reload. Below is an explanation\n"
11733 "of each of these qualifiers.\n"
11734 "\n"
11735 "\t'members' - reload queue members from queues.conf\n"
11736 "\t'parameters' - reload all queue options except for queue members\n"
11737 "\t'rules' - reload the queuerules.conf file\n"
11738 "\t'all' - reload queue rules, parameters, and members\n"
11739 "\n"
11740 "Note: the 'rules' qualifier here cannot actually be applied to a specific queue.\n"
11741 "Use of the 'rules' qualifier causes queuerules.conf to be reloaded. Even if only\n"
11742 "one queue is specified when using this command, reloading queue rules may cause\n"
11743 "other queues to be affected\n";
11744 return NULL;
11745 case CLI_GENERATE:
11746 if (a->pos >= 3) {
11747 /* find the point at which the list of queue names starts */
11748 const char *command_end = a->line + strlen("queue reload ");
11749 command_end = strchr(command_end, ' ');
11750 if (!command_end) {
11751 command_end = a->line + strlen(a->line);
11752 }
11753 return complete_queue(a->line, a->word, a->pos, a->n, command_end - a->line);
11754 } else {
11755 return NULL;
11756 }
11757 }
11758
11759 if (a->argc < 3)
11760 return CLI_SHOWUSAGE;
11761
11762 if (!strcasecmp(a->argv[2], "rules")) {
11764 } else if (!strcasecmp(a->argv[2], "members")) {
11766 } else if (!strcasecmp(a->argv[2], "parameters")) {
11768 } else if (!strcasecmp(a->argv[2], "all")) {
11770 }
11771
11772 if (a->argc == 3) {
11773 reload_handler(1, &mask, NULL);
11774 return CLI_SUCCESS;
11775 }
11776
11777 for (i = 3; i < a->argc; ++i) {
11778 reload_handler(1, &mask, a->argv[i]);
11779 }
11780
11781 return CLI_SUCCESS;
11782}
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 11312 of file app_queue.c.

11313{
11314 const char *queuename, *interface;
11315 struct member *mem = NULL;
11316 char *res = CLI_FAILURE;
11317
11318 switch (cmd) {
11319 case CLI_INIT:
11320 e->command = "queue remove member";
11321 e->usage =
11322 "Usage: queue remove member <channel> from <queue>\n"
11323 " Remove a specific channel from a queue.\n";
11324 return NULL;
11325 case CLI_GENERATE:
11326 return complete_queue_remove_member(a->line, a->word, a->pos, a->n);
11327 }
11328
11329 if (a->argc != 6) {
11330 return CLI_SHOWUSAGE;
11331 } else if (strcmp(a->argv[4], "from")) {
11332 return CLI_SHOWUSAGE;
11333 }
11334
11335 queuename = a->argv[5];
11336 interface = a->argv[3];
11337
11339 mem = find_member_by_queuename_and_interface(queuename, interface);
11340 }
11341
11342 switch (remove_from_queue(queuename, interface)) {
11343 case RES_OKAY:
11344 if (!mem || ast_strlen_zero(mem->membername)) {
11345 ast_queue_log(queuename, "CLI", interface, "REMOVEMEMBER", "%s", "");
11346 } else {
11347 ast_queue_log(queuename, "CLI", mem->membername, "REMOVEMEMBER", "%s", "");
11348 }
11349 ast_cli(a->fd, "Removed interface %s from queue '%s'\n", interface, queuename);
11350 res = CLI_SUCCESS;
11351 break;
11352 case RES_EXISTS:
11353 ast_cli(a->fd, "Unable to remove interface '%s' from queue '%s': Not there\n", interface, queuename);
11354 break;
11355 case RES_NOSUCHQUEUE:
11356 ast_cli(a->fd, "Unable to remove interface from queue '%s': No such queue\n", queuename);
11357 break;
11358 case RES_OUTOFMEMORY:
11359 ast_cli(a->fd, "Out of memory\n");
11360 break;
11361 case RES_NOT_DYNAMIC:
11362 ast_cli(a->fd, "Unable to remove interface '%s' from queue '%s': Member is not dynamic\n", interface, queuename);
11363 break;
11364 }
11365
11366 if (mem) {
11367 ao2_ref(mem, -1);
11368 }
11369
11370 return res;
11371}
static int remove_from_queue(const char *queuename, const char *interface)
Remove member from queue.
Definition app_queue.c:7703
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 11681 of file app_queue.c.

11682{
11683 struct ast_flags mask = {QUEUE_RESET_STATS,};
11684 int i;
11685
11686 switch (cmd) {
11687 case CLI_INIT:
11688 e->command = "queue reset stats";
11689 e->usage =
11690 "Usage: queue reset stats [<queuenames>]\n"
11691 "\n"
11692 "Issuing this command will reset statistics for\n"
11693 "<queuenames>, or for all queues if no queue is\n"
11694 "specified.\n";
11695 return NULL;
11696 case CLI_GENERATE:
11697 if (a->pos >= 3) {
11698 return complete_queue(a->line, a->word, a->pos, a->n, 17);
11699 } else {
11700 return NULL;
11701 }
11702 }
11703
11704 if (a->argc < 3) {
11705 return CLI_SHOWUSAGE;
11706 }
11707
11708 if (a->argc == 3) {
11709 reload_handler(1, &mask, NULL);
11710 return CLI_SUCCESS;
11711 }
11712
11713 for (i = 3; i < a->argc; ++i) {
11714 reload_handler(1, &mask, a->argv[i]);
11715 }
11716
11717 return CLI_SUCCESS;
11718}

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

11647{
11648 const char *rule;
11649 struct rule_list *rl_iter;
11650 struct penalty_rule *pr_iter;
11651 switch (cmd) {
11652 case CLI_INIT:
11653 e->command = "queue show rules";
11654 e->usage =
11655 "Usage: queue show rules [rulename]\n"
11656 " Show the list of rules associated with rulename. If no\n"
11657 " rulename is specified, list all rules defined in queuerules.conf\n";
11658 return NULL;
11659 case CLI_GENERATE:
11660 return complete_queue_rule_show(a->line, a->word, a->pos, a->n);
11661 }
11662
11663 if (a->argc != 3 && a->argc != 4) {
11664 return CLI_SHOWUSAGE;
11665 }
11666
11667 rule = a->argc == 4 ? a->argv[3] : "";
11669 AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) {
11670 if (ast_strlen_zero(rule) || !strcasecmp(rl_iter->name, rule)) {
11671 ast_cli(a->fd, "Rule: %s\n", rl_iter->name);
11672 AST_LIST_TRAVERSE(&rl_iter->rules, pr_iter, list) {
11673 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);
11674 }
11675 }
11676 }
11678 return CLI_SUCCESS;
11679}
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 11583 of file app_queue.c.

11584{
11585 const char *queuename = NULL, *interface;
11586 int penalty = 0;
11587
11588 switch (cmd) {
11589 case CLI_INIT:
11590 e->command = "queue set penalty";
11591 e->usage =
11592 "Usage: queue set penalty <penalty> on <interface> [in <queue>]\n"
11593 " Set a member's penalty in the queue specified. If no queue is specified\n"
11594 " then that interface's penalty is set in all queues to which that interface is a member\n";
11595 return NULL;
11596 case CLI_GENERATE:
11597 return complete_queue_set_member_value(a->line, a->word, a->pos, a->n);
11598 }
11599
11600 if (a->argc != 6 && a->argc != 8) {
11601 return CLI_SHOWUSAGE;
11602 } else if (strcmp(a->argv[4], "on") || (a->argc > 6 && strcmp(a->argv[6], "in"))) {
11603 return CLI_SHOWUSAGE;
11604 }
11605
11606 if (a->argc == 8) {
11607 queuename = a->argv[7];
11608 }
11609 interface = a->argv[5];
11610 penalty = atoi(a->argv[3]);
11611
11612 switch (set_member_value(queuename, interface, MEMBER_PENALTY, penalty)) {
11613 case RESULT_SUCCESS:
11614 ast_cli(a->fd, "Set penalty on interface '%s' from queue '%s'\n", interface, queuename);
11615 return CLI_SUCCESS;
11616 case RESULT_FAILURE:
11617 ast_cli(a->fd, "Failed to set penalty on interface '%s' from queue '%s'\n", interface, queuename);
11618 return CLI_FAILURE;
11619 default:
11620 return CLI_FAILURE;
11621 }
11622}
static int set_member_value(const char *queuename, const char *interface, int property, int value)
Definition app_queue.c:8168
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 11526 of file app_queue.c.

11527{
11528 const char *queuename = NULL, *interface;
11529 int ringinuse;
11530
11531 switch (cmd) {
11532 case CLI_INIT:
11533 e->command = "queue set ringinuse";
11534 e->usage =
11535 "Usage: queue set ringinuse <yes/no> on <interface> [in <queue>]\n"
11536 " Set a member's ringinuse in the queue specified. If no queue is specified\n"
11537 " then that interface's penalty is set in all queues to which that interface is a member.\n";
11538 break;
11539 return NULL;
11540 case CLI_GENERATE:
11541 return complete_queue_set_member_value(a->line, a->word, a->pos, a->n);
11542 }
11543
11544 /* Sensible argument counts */
11545 if (a->argc != 6 && a->argc != 8) {
11546 return CLI_SHOWUSAGE;
11547 }
11548
11549 /* Uses proper indicational words */
11550 if (strcmp(a->argv[4], "on") || (a->argc > 6 && strcmp(a->argv[6], "in"))) {
11551 return CLI_SHOWUSAGE;
11552 }
11553
11554 /* Set the queue name if applicable */
11555 if (a->argc == 8) {
11556 queuename = a->argv[7];
11557 }
11558
11559 /* Interface being set */
11560 interface = a->argv[5];
11561
11562 /* Check and set the ringinuse value */
11563 if (ast_true(a->argv[3])) {
11564 ringinuse = 1;
11565 } else if (ast_false(a->argv[3])) {
11566 ringinuse = 0;
11567 } else {
11568 return CLI_SHOWUSAGE;
11569 }
11570
11571 switch (set_member_value(queuename, interface, MEMBER_RINGINUSE, ringinuse)) {
11572 case RESULT_SUCCESS:
11573 ast_cli(a->fd, "Set ringinuse on interface '%s' from queue '%s'\n", interface, queuename);
11574 return CLI_SUCCESS;
11575 case RESULT_FAILURE:
11576 ast_cli(a->fd, "Failed to set ringinuse on interface '%s' from queue '%s'\n", interface, queuename);
11577 return CLI_FAILURE;
11578 default:
11579 return CLI_FAILURE;
11580 }
11581}
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 4624 of file app_queue.c.

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

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

3090{
3091 int i;
3092 struct penalty_rule *pr_iter;
3093
3094 q->dead = 0;
3095 q->retry = DEFAULT_RETRY;
3097 q->maxlen = 0;
3098
3099 ast_string_field_set(q, announce, "");
3100 ast_string_field_set(q, context, "");
3101 ast_string_field_set(q, membergosub, "");
3102 ast_string_field_set(q, defaultrule, "");
3103
3104 q->announcefrequency = 0;
3106 q->announceholdtime = 1;
3108 q->announcepositionlimit = 10; /* Default 10 positions */
3109 q->announceposition = ANNOUNCEPOSITION_YES; /* Default yes */
3110 q->roundingseconds = 0; /* Default - don't announce seconds */
3111 q->servicelevel = 0;
3112 q->ringinuse = 1;
3114 q->setinterfacevar = 0;
3115 q->setqueuevar = 0;
3116 q->setqueueentryvar = 0;
3118 q->monfmt[0] = '\0';
3119 q->reportholdtime = 0;
3120 q->wrapuptime = 0;
3121 q->penaltymemberslimit = 0;
3122 q->joinempty = 0;
3123 q->leavewhenempty = 0;
3124 q->memberdelay = 0;
3125 q->weight = 0;
3126 q->timeoutrestart = 0;
3130 q->numperiodicannounce = 0;
3133 q->autopausebusy = 0;
3134 q->autopauseunavail = 0;
3136 q->autopausedelay = 0;
3138 if (!q->members) {
3140 /* linear strategy depends on order, so we have to place all members in a list */
3142 } else {
3145 }
3146 }
3147 q->found = 1;
3148
3149 ast_string_field_set(q, moh, "");
3150 ast_string_field_set(q, sound_next, "queue-youarenext");
3151 ast_string_field_set(q, sound_thereare, "queue-thereare");
3152 ast_string_field_set(q, sound_calls, "queue-callswaiting");
3153 ast_string_field_set(q, queue_quantity1, "queue-quantity1");
3154 ast_string_field_set(q, queue_quantity2, "queue-quantity2");
3155 ast_string_field_set(q, sound_holdtime, "queue-holdtime");
3156 ast_string_field_set(q, sound_minutes, "queue-minutes");
3157 ast_string_field_set(q, sound_minute, "queue-minute");
3158 ast_string_field_set(q, sound_seconds, "queue-seconds");
3159 ast_string_field_set(q, sound_thanks, "queue-thankyou");
3160 ast_string_field_set(q, sound_callerannounce, "");
3161 ast_string_field_set(q, sound_reporthold, "queue-reporthold");
3162
3163 if (!q->sound_periodicannounce[0]) {
3165 }
3166
3167 if (q->sound_periodicannounce[0]) {
3168 ast_str_set(&q->sound_periodicannounce[0], 0, "queue-periodic-announce");
3169 }
3170
3171 for (i = 1; i < MAX_PERIODIC_ANNOUNCEMENTS; i++) {
3172 if (q->sound_periodicannounce[i]) {
3173 ast_str_set(&q->sound_periodicannounce[i], 0, "%s", "");
3174 }
3175 }
3176
3177 while ((pr_iter = AST_LIST_REMOVE_HEAD(&q->rules,list))) {
3178 ast_free(pr_iter);
3179 }
3180
3181 /* On restart assume no members are available.
3182 * The queue_avail hint is a boolean state to indicate whether a member is available or not.
3183 *
3184 * This seems counter intuitive, but is required to light a BLF
3185 * AST_DEVICE_INUSE indicates no members are available.
3186 * AST_DEVICE_NOT_INUSE indicates a member is available.
3187 */
3189}
#define DEFAULT_RETRY
Definition app_queue.c:1680
static int member_hash_fn(const void *obj, const int flags)
Definition app_queue.c:3060
static int member_cmp_fn(void *obj1, void *obj2, int flags)
Definition app_queue.c:3076
#define DEFAULT_MIN_ANNOUNCE_FREQUENCY
The minimum number of seconds between position announcements.
Definition app_queue.c:1688
#define DEFAULT_TIMEOUT
Definition app_queue.c:1681
static int autofill_default
queues.conf [general] option
Definition app_queue.c:1723
#define ANNOUNCEPOSITION_YES
Definition app_queue.c:1921
@ 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:1984
unsigned int setinterfacevar
Definition app_queue.c:1970
int announcefrequency
Definition app_queue.c:1988
unsigned int announceholdtime
Definition app_queue.c:1976
unsigned int reportholdtime
Definition app_queue.c:1973
unsigned int setqueueentryvar
Definition app_queue.c:1972
unsigned int timeoutrestart
Definition app_queue.c:1975
int periodicannouncefrequency
Definition app_queue.c:1991
unsigned int announceposition_only_up
Definition app_queue.c:1978
unsigned int setqueuevar
Definition app_queue.c:1971
int announcepositionlimit
Definition app_queue.c:1987
unsigned int announce_to_first_user
Definition app_queue.c:1969
int randomperiodicannounce
Definition app_queue.c:1993
int periodicannouncestartdelay
Definition app_queue.c:1990
int log_restricted_caller_id
Definition app_queue.c:2020
int servicelevel
Definition app_queue.c:2000
int minannouncefrequency
Definition app_queue.c:1989
enum empty_conditions leavewhenempty
Definition app_queue.c:1986
int roundingseconds
Definition app_queue.c:1994
int numperiodicannounce
Definition app_queue.c:1992
unsigned int announceposition
Definition app_queue.c:1977
char monfmt[8]
Definition app_queue.c:2002
enum empty_conditions joinempty
Definition app_queue.c:1985
struct call_queue::@55 rules
int memberdelay
Definition app_queue.c:2017
unsigned int autopausebusy
Definition app_queue.c:1983
int autopausedelay
Definition app_queue.c:2012
int timeoutpriority
Definition app_queue.c:2013
unsigned int relativeperiodicannounce
Definition app_queue.c:1982

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

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

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

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

2058{
2059 int x;
2060
2061 for (x = 0; x < ARRAY_LEN(strategies); x++) {
2062 if (strategy == strategies[x].strategy) {
2063 return strategies[x].name;
2064 }
2065 }
2066
2067 return "<unknown>";
2068}
static const struct strategy strategies[]
const char * name
Definition app_queue.c:1658

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

7622{
7623 struct member *mem;
7624 struct ao2_iterator mem_iter;
7625
7626 if (!q) {
7627 return NULL;
7628 }
7629 mem_iter = ao2_iterator_init(q->members, 0);
7630 while ((mem = ao2_iterator_next(&mem_iter))) {
7631 if (!strcasecmp(interface, mem->interface)) {
7632 ao2_iterator_destroy(&mem_iter);
7633 return mem;
7634 }
7635 ao2_ref(mem, -1);
7636 }
7637 ao2_iterator_destroy(&mem_iter);
7638
7639 return NULL;
7640}

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

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

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

2747{
2748 int available = 0;
2749 int wrapuptime;
2750
2751 switch (mem->status) {
2752 case AST_DEVICE_INVALID:
2754 break;
2755 case AST_DEVICE_INUSE:
2756 case AST_DEVICE_BUSY:
2757 case AST_DEVICE_RINGING:
2759 case AST_DEVICE_ONHOLD:
2760 if (!mem->ringinuse) {
2761 break;
2762 }
2763 /* else fall through */
2765 case AST_DEVICE_UNKNOWN:
2766 if (!mem->paused) {
2767 available = 1;
2768 }
2769 break;
2770 }
2771
2772 /* Let wrapuptimes override device state availability */
2773 wrapuptime = get_wrapuptime(q, mem);
2774 if (mem->lastcall && wrapuptime && (time(NULL) - wrapuptime < mem->lastcall)) {
2775 available = 0;
2776 }
2777 return available;
2778}
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 5900 of file app_queue.c.

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

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

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

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

9926{
9927 struct member *member = obj;
9928
9929 if (!member->delme) {
9931 return 0;
9932 } else {
9933 return CMP_MATCH;
9934 }
9935}
@ CMP_MATCH
Definition astobj2.h:1027
unsigned int delme
Definition app_queue.c:1883

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

10081{
10082 struct call_queue *q = obj;
10083 char *queuename = arg;
10084 if (!q->realtime && !q->found && (ast_strlen_zero(queuename) || !strcasecmp(queuename, q->name))) {
10085 q->dead = 1;
10086 return CMP_MATCH;
10087 } else {
10088 return 0;
10089 }
10090}

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

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

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

11955{
11956 int err = 0;
11957 struct ast_flags mask = {AST_FLAGS_ALL, };
11958 struct ast_config *member_config;
11959 struct stasis_topic *queue_topic;
11961
11964 if (!queues) {
11966 }
11967
11970 if (!pending_members) {
11971 unload_module();
11973 }
11974
11975 use_weight = 0;
11976
11977 if (reload_handler(0, &mask, NULL)) {
11978 unload_module();
11980 }
11981
11982 ast_realtime_require_field("queue_members", "paused", RQ_INTEGER1, 1, "uniqueid", RQ_UINTEGER2, 5, "reason_paused", RQ_CHAR, 80, SENTINEL);
11983
11984 /*
11985 * This section is used to determine which name for 'ringinuse' to use in realtime members
11986 * Necessary for supporting older setups.
11987 *
11988 * It also checks if 'reason_paused' exists in the realtime backend
11989 */
11990 member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name LIKE", "%", SENTINEL);
11991 if (!member_config) {
11992 realtime_ringinuse_field = "ringinuse";
11993 } else {
11994 const char *config_val;
11995
11996 if ((config_val = ast_variable_retrieve(member_config, NULL, "ringinuse"))) {
11997 ast_log(LOG_NOTICE, "ringinuse field entries found in queue_members table. Using 'ringinuse'\n");
11998 realtime_ringinuse_field = "ringinuse";
11999 } else if ((config_val = ast_variable_retrieve(member_config, NULL, "ignorebusy"))) {
12000 ast_log(LOG_NOTICE, "ignorebusy field found in queue_members table with no ringinuse field. Using 'ignorebusy'\n");
12001 realtime_ringinuse_field = "ignorebusy";
12002 } else {
12003 ast_log(LOG_NOTICE, "No entries were found for ringinuse/ignorebusy in queue_members table. Using 'ringinuse'\n");
12004 realtime_ringinuse_field = "ringinuse";
12005 }
12006
12007 if (ast_variable_retrieve(member_config, NULL, "reason_paused")) {
12009 }
12010 }
12011 ast_config_destroy(member_config);
12012
12015 }
12016
12025 err |= ast_manager_register_xml("QueueStatus", 0, manager_queues_status);
12026 err |= ast_manager_register_xml("QueueSummary", 0, manager_queues_summary);
12033 err |= ast_manager_register_xml("QueueRule", 0, manager_queue_rule_show);
12034 err |= ast_manager_register_xml("QueueReload", 0, manager_queue_reload);
12035 err |= ast_manager_register_xml("QueueReset", 0, manager_queue_reset);
12036 err |= ast_manager_register_xml("QueueChangePriorityCaller", 0, manager_change_priority_caller_on_queue);
12045
12046 /* in the following subscribe call, do I use DEVICE_STATE, or DEVICE_STATE_CHANGE? */
12048 if (!device_state_sub) {
12049 err = -1;
12050 }
12053
12055 queue_topic = ast_queue_topic_all();
12056 if (!manager_topic || !queue_topic) {
12057 unload_module();
12059 }
12061 if (!topic_forwarder) {
12062 unload_module();
12064 }
12065
12068 unload_module();
12070 }
12072 if (!agent_router) {
12073 unload_module();
12075 }
12079 NULL);
12083 NULL);
12084
12085 err |= STASIS_MESSAGE_TYPE_INIT(queue_caller_join_type);
12086 err |= STASIS_MESSAGE_TYPE_INIT(queue_caller_leave_type);
12087 err |= STASIS_MESSAGE_TYPE_INIT(queue_caller_abandon_type);
12088
12089 err |= STASIS_MESSAGE_TYPE_INIT(queue_member_status_type);
12090 err |= STASIS_MESSAGE_TYPE_INIT(queue_member_added_type);
12091 err |= STASIS_MESSAGE_TYPE_INIT(queue_member_removed_type);
12092 err |= STASIS_MESSAGE_TYPE_INIT(queue_member_pause_type);
12093 err |= STASIS_MESSAGE_TYPE_INIT(queue_member_penalty_type);
12094 err |= STASIS_MESSAGE_TYPE_INIT(queue_member_ringinuse_type);
12095
12096 err |= STASIS_MESSAGE_TYPE_INIT(queue_agent_called_type);
12097 err |= STASIS_MESSAGE_TYPE_INIT(queue_agent_connect_type);
12098 err |= STASIS_MESSAGE_TYPE_INIT(queue_agent_complete_type);
12099 err |= STASIS_MESSAGE_TYPE_INIT(queue_agent_dump_type);
12100 err |= STASIS_MESSAGE_TYPE_INIT(queue_agent_ringnoanswer_type);
12101
12102 if (err) {
12103 unload_module();
12105 }
12107}
static struct ast_custom_function queuevar_function
Definition app_queue.c:9617
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:2676
static struct ast_custom_function queuemembercount_function
Definition app_queue.c:9622
static struct ast_custom_function queuewaitingcount_function
Definition app_queue.c:9633
static char * app_pqm
Definition app_queue.c:1705
static struct ast_custom_function queuememberlist_function
Definition app_queue.c:9638
static char * realtime_ringinuse_field
name of the ringinuse field in the realtime database
Definition app_queue.c:1753
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:8522
#define MAX_QUEUE_BUCKETS
Definition app_queue.c:1690
static int upqm_exec(struct ast_channel *chan, const char *data)
UnpauseQueueMember application.
Definition app_queue.c:8415
static void queue_agent_cb(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Definition app_queue.c:6315
static char * app_ql
Definition app_queue.c:1709
static void reload_queue_members(void)
Reload dynamic queue members persisted into the astdb.
Definition app_queue.c:8268
static int rqm_exec(struct ast_channel *chan, const char *data)
RemoveQueueMember application.
Definition app_queue.c:8451
#define MAX_CALL_ATTEMPT_BUCKETS
Definition app_queue.c:2654
static char * app_rqm
Definition app_queue.c:1703
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:8379
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:1711
static int manager_queue_member_penalty(struct mansession *s, const struct message *m)
static char * app_upqm
Definition app_queue.c:1707
static struct ast_custom_function queuememberpenalty_function
Definition app_queue.c:9643
static int queue_cmp_cb(void *obj, void *arg, int flags)
Definition app_queue.c:2113
static int manager_request_withdraw_caller_from_queue(struct mansession *s, const struct message *m)
static char * app
Definition app_queue.c:1699
static int queue_hash_cb(const void *obj, const int flags)
Definition app_queue.c:2106
static int queue_exec(struct ast_channel *chan, const char *data)
The starting point for all queue calls.
Definition app_queue.c:8693
static int pending_members_hash(const void *obj, const int flags)
Definition app_queue.c:2656
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:8616
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:2781
static struct stasis_subscription * device_state_sub
Subscription to device state change messages.
Definition app_queue.c:1735
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:1756
static char * app_aqm
Definition app_queue.c:1701
static struct ast_cli_entry cli_queue[]
static struct ast_custom_function queuegetchannel_function
Definition app_queue.c:9628
static struct stasis_forward * topic_forwarder
static struct ast_custom_function queueexists_function
Definition app_queue.c:9612
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 4111 of file app_queue.c.

4112{
4113 struct ast_config *cfg = NULL;
4114 char *category = NULL;
4115 const char *name = NULL;
4116 struct call_queue *q = NULL;
4117
4118 if (!ast_check_realtime("queues")) {
4119 return;
4120 }
4121
4122 if (ast_strlen_zero(queuename)) {
4123 if ((cfg = ast_load_realtime_multientry("queues", "name LIKE", "%", SENTINEL))) {
4124 while ((category = ast_category_browse(cfg, category))) {
4125 name = ast_variable_retrieve(cfg, category, "name");
4127 queue_unref(q);
4128 }
4129 }
4130 ast_config_destroy(cfg);
4131 }
4132 } else {
4133 if ((q = find_load_queue_rt_friendly(queuename))) {
4134 queue_unref(q);
4135 }
4136 }
4137}

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

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

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

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

10800{
10801 const char *queuename, *interface, *penalty_s, *paused_s, *reason, *membername, *state_interface, *wrapuptime_s;
10802 int paused, penalty, wrapuptime = 0;
10803
10804 queuename = astman_get_header(m, "Queue");
10805 interface = astman_get_header(m, "Interface");
10806 penalty_s = astman_get_header(m, "Penalty");
10807 paused_s = astman_get_header(m, "Paused");
10808 reason = astman_get_header(m, "Reason"); /* Optional */
10809 membername = astman_get_header(m, "MemberName");
10810 state_interface = astman_get_header(m, "StateInterface");
10811 wrapuptime_s = astman_get_header(m, "Wrapuptime");
10812
10813 if (ast_strlen_zero(queuename)) {
10814 astman_send_error(s, m, "'Queue' not specified.");
10815 return 0;
10816 }
10817
10818 if (ast_strlen_zero(interface)) {
10819 astman_send_error(s, m, "'Interface' not specified.");
10820 return 0;
10821 }
10822
10823 if (ast_strlen_zero(penalty_s)) {
10824 penalty = 0;
10825 } else if (sscanf(penalty_s, "%30d", &penalty) != 1 || penalty < 0) {
10826 penalty = 0;
10827 }
10828
10829 if (ast_strlen_zero(wrapuptime_s)) {
10830 wrapuptime = 0;
10831 } else if (sscanf(wrapuptime_s, "%30d", &wrapuptime) != 1 || wrapuptime < 0) {
10832 wrapuptime = 0;
10833 }
10834
10835 if (ast_strlen_zero(paused_s)) {
10836 paused = 0;
10837 } else {
10838 paused = abs(ast_true(paused_s));
10839 }
10840
10841 switch (add_to_queue(queuename, interface, membername, penalty, paused, queue_persistent_members, state_interface, reason, wrapuptime)) {
10842 case RES_OKAY:
10843 if (ast_strlen_zero(membername) || !log_membername_as_agent) {
10844 ast_queue_log(queuename, "MANAGER", interface, "ADDMEMBER", "%s", paused ? "PAUSED" : "");
10845 } else {
10846 ast_queue_log(queuename, "MANAGER", membername, "ADDMEMBER", "%s", paused ? "PAUSED" : "");
10847 }
10848 astman_send_ack(s, m, "Added interface to queue");
10849 break;
10850 case RES_EXISTS:
10851 astman_send_error(s, m, "Unable to add interface: Already there");
10852 break;
10853 case RES_NOSUCHQUEUE:
10854 astman_send_error(s, m, "Unable to add interface to queue: No such queue");
10855 break;
10856 case RES_OUTOFMEMORY:
10857 astman_send_error(s, m, "Out of memory");
10858 break;
10859 }
10860
10861 return 0;
10862}
#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 11095 of file app_queue.c.

11096{
11097 const char *queuename, *caller, *priority_s, *immediate_s;
11098 int priority = 0, immediate = 0;
11099
11100 queuename = astman_get_header(m, "Queue");
11101 caller = astman_get_header(m, "Caller");
11102 priority_s = astman_get_header(m, "Priority");
11103 immediate_s = astman_get_header(m, "Immediate");
11104
11105 if (ast_strlen_zero(queuename)) {
11106 astman_send_error(s, m, "'Queue' not specified.");
11107 return 0;
11108 }
11109
11110 if (ast_strlen_zero(caller)) {
11111 astman_send_error(s, m, "'Caller' not specified.");
11112 return 0;
11113 }
11114
11115 if (ast_strlen_zero(priority_s)) {
11116 astman_send_error(s, m, "'Priority' not specified.");
11117 return 0;
11118 } else if (sscanf(priority_s, "%30d", &priority) != 1) {
11119 astman_send_error(s, m, "'Priority' need integer.");
11120 return 0;
11121 }
11122
11123 if (!ast_strlen_zero(immediate_s)) {
11124 immediate = ast_true(immediate_s);
11125 }
11126
11127 switch (change_priority_caller_on_queue(queuename, caller, priority, immediate)) {
11128 case RES_OKAY:
11129 astman_send_ack(s, m, "Priority change for caller on queue");
11130 break;
11131 case RES_NOSUCHQUEUE:
11132 astman_send_error(s, m, "Unable to change priority caller on queue: No such queue");
11133 break;
11134 case RES_NOT_CALLER:
11135 astman_send_error(s, m, "Unable to change priority caller on queue: No such caller");
11136 break;
11137 }
11138
11139 return 0;
11140}

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

10912{
10913 const char *queuename, *interface, *paused_s, *reason;
10914 int paused;
10915
10916 interface = astman_get_header(m, "Interface");
10917 paused_s = astman_get_header(m, "Paused");
10918 queuename = astman_get_header(m, "Queue"); /* Optional - if not supplied, pause the given Interface in all queues */
10919 reason = astman_get_header(m, "Reason"); /* Optional */
10920
10921 if (ast_strlen_zero(interface) || ast_strlen_zero(paused_s)) {
10922 astman_send_error(s, m, "Need 'Interface' and 'Paused' parameters.");
10923 return 0;
10924 }
10925
10926 paused = abs(ast_true(paused_s));
10927
10928 if (set_member_paused(queuename, interface, reason, paused)) {
10929 astman_send_error(s, m, "Interface not found");
10930 } else {
10931 astman_send_ack(s, m, paused ? "Interface paused successfully" : "Interface unpaused successfully");
10932 }
10933 return 0;
10934}

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

10937{
10938 const char *queuename, *event, *message, *interface, *uniqueid;
10939
10940 queuename = astman_get_header(m, "Queue");
10941 uniqueid = astman_get_header(m, "UniqueId");
10942 interface = astman_get_header(m, "Interface");
10943 event = astman_get_header(m, "Event");
10944 message = astman_get_header(m, "Message");
10945
10946 if (ast_strlen_zero(queuename) || ast_strlen_zero(event)) {
10947 astman_send_error(s, m, "Need 'Queue' and 'Event' parameters.");
10948 return 0;
10949 }
10950
10951 ast_queue_log(queuename, S_OR(uniqueid, "NONE"), interface, event, "%s", message);
10952 astman_send_ack(s, m, "Event added successfully");
10953
10954 return 0;
10955}

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

11070{
11071 const char *queuename, *interface, *penalty_s;
11072 int penalty;
11073
11074 interface = astman_get_header(m, "Interface");
11075 penalty_s = astman_get_header(m, "Penalty");
11076 /* Optional - if not supplied, set the penalty value for the given Interface in all queues */
11077 queuename = astman_get_header(m, "Queue");
11078
11079 if (ast_strlen_zero(interface) || ast_strlen_zero(penalty_s)) {
11080 astman_send_error(s, m, "Need 'Interface' and 'Penalty' parameters.");
11081 return 0;
11082 }
11083
11084 penalty = atoi(penalty_s);
11085
11086 if (set_member_value((char *)queuename, (char *)interface, MEMBER_PENALTY, penalty)) {
11087 astman_send_error(s, m, "Invalid interface, queuename or penalty");
11088 } else {
11089 astman_send_ack(s, m, "Interface penalty set successfully");
11090 }
11091
11092 return 0;
11093}

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

11036{
11037 const char *queuename, *interface, *ringinuse_s;
11038 int ringinuse;
11039
11040 interface = astman_get_header(m, "Interface");
11041 ringinuse_s = astman_get_header(m, "RingInUse");
11042
11043 /* Optional - if not supplied, set the ringinuse value for the given Interface in all queues */
11044 queuename = astman_get_header(m, "Queue");
11045
11046 if (ast_strlen_zero(interface) || ast_strlen_zero(ringinuse_s)) {
11047 astman_send_error(s, m, "Need 'Interface' and 'RingInUse' parameters.");
11048 return 0;
11049 }
11050
11051 if (ast_true(ringinuse_s)) {
11052 ringinuse = 1;
11053 } else if (ast_false(ringinuse_s)) {
11054 ringinuse = 0;
11055 } else {
11056 astman_send_error(s, m, "'RingInUse' parameter must be a truth value (yes/no, on/off, 0/1, etc)");
11057 return 0;
11058 }
11059
11060 if (set_member_value(queuename, interface, MEMBER_RINGINUSE, ringinuse)) {
11061 astman_send_error(s, m, "Invalid interface, queuename, or ringinuse value\n");
11062 } else {
11063 astman_send_ack(s, m, "Interface ringinuse set successfully");
11064 }
11065
11066 return 0;
11067}

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

10958{
10959 struct ast_flags mask = {0,};
10960 const char *queuename = NULL;
10961 int header_found = 0;
10962
10963 queuename = astman_get_header(m, "Queue");
10964 if (!strcasecmp(S_OR(astman_get_header(m, "Members"), ""), "yes")) {
10966 header_found = 1;
10967 }
10968 if (!strcasecmp(S_OR(astman_get_header(m, "Rules"), ""), "yes")) {
10970 header_found = 1;
10971 }
10972 if (!strcasecmp(S_OR(astman_get_header(m, "Parameters"), ""), "yes")) {
10974 header_found = 1;
10975 }
10976
10977 if (!header_found) {
10979 }
10980
10981 if (!reload_handler(1, &mask, queuename)) {
10982 astman_send_ack(s, m, "Queue reloaded successfully");
10983 } else {
10984 astman_send_error(s, m, "Error encountered while reloading queue");
10985 }
10986 return 0;
10987}

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

10990{
10991 const char *queuename = NULL;
10992 struct ast_flags mask = {QUEUE_RESET_STATS,};
10993
10994 queuename = astman_get_header(m, "Queue");
10995
10996 if (!reload_handler(1, &mask, queuename)) {
10997 astman_send_ack(s, m, "Queue stats reset successfully");
10998 } else {
10999 astman_send_error(s, m, "Error encountered while resetting queue stats");
11000 }
11001 return 0;
11002}

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

10559{
10560 const char *rule = astman_get_header(m, "Rule");
10561 const char *id = astman_get_header(m, "ActionID");
10562 struct rule_list *rl_iter;
10563 struct penalty_rule *pr_iter;
10564
10565 astman_append(s, "Response: Success\r\n");
10566 if (!ast_strlen_zero(id)) {
10567 astman_append(s, "ActionID: %s\r\n", id);
10568 }
10569
10571 AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) {
10572 if (ast_strlen_zero(rule) || !strcasecmp(rule, rl_iter->name)) {
10573 astman_append(s, "RuleList: %s\r\n", rl_iter->name);
10574 AST_LIST_TRAVERSE(&rl_iter->rules, pr_iter, list) {
10575 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 );
10576 }
10577 if (!ast_strlen_zero(rule)) {
10578 break;
10579 }
10580 }
10581 }
10583
10584 /*
10585 * Two blank lines instead of one because the Response and
10586 * ActionID headers used to not be present.
10587 */
10588 astman_append(s, "\r\n\r\n");
10589
10590 return RESULT_SUCCESS;
10591}

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

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

10595{
10596 time_t now;
10597 int qmemcount = 0;
10598 int qmemavail = 0;
10599 int qchancount = 0;
10600 int qlongestholdtime = 0;
10601 int qsummaries = 0;
10602 const char *id = astman_get_header(m, "ActionID");
10603 const char *queuefilter = astman_get_header(m, "Queue");
10604 char idText[256];
10605 struct call_queue *q;
10606 struct queue_ent *qe;
10607 struct member *mem;
10608 struct ao2_iterator queue_iter;
10609 struct ao2_iterator mem_iter;
10610
10611 if (ast_check_realtime("queues")) {
10612 load_realtime_queues(queuefilter);
10613 }
10614
10615 astman_send_listack(s, m, "Queue summary will follow", "start");
10616 time(&now);
10617 idText[0] = '\0';
10618 if (!ast_strlen_zero(id)) {
10619 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
10620 }
10621 queue_iter = ao2_iterator_init(queues, 0);
10622 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
10623 ao2_lock(q);
10624
10625 /* List queue properties */
10626 if (ast_strlen_zero(queuefilter) || !strcasecmp(q->name, queuefilter)) {
10627 /* Reset the necessary local variables if no queuefilter is set*/
10628 qmemcount = 0;
10629 qmemavail = 0;
10630 qchancount = 0;
10631 qlongestholdtime = 0;
10632
10633 /* List Queue Members */
10634 mem_iter = ao2_iterator_init(q->members, 0);
10635 while ((mem = ao2_iterator_next(&mem_iter))) {
10636 if ((mem->status != AST_DEVICE_UNAVAILABLE) && (mem->status != AST_DEVICE_INVALID)) {
10637 ++qmemcount;
10638 if (member_status_available(mem->status) && !mem->paused) {
10639 ++qmemavail;
10640 }
10641 }
10642 ao2_ref(mem, -1);
10643 }
10644 ao2_iterator_destroy(&mem_iter);
10645 for (qe = q->head; qe; qe = qe->next) {
10646 if ((now - qe->start) > qlongestholdtime) {
10647 qlongestholdtime = now - qe->start;
10648 }
10649 ++qchancount;
10650 }
10651 astman_append(s, "Event: QueueSummary\r\n"
10652 "Queue: %s\r\n"
10653 "LoggedIn: %d\r\n"
10654 "Available: %d\r\n"
10655 "Callers: %d\r\n"
10656 "HoldTime: %d\r\n"
10657 "TalkTime: %d\r\n"
10658 "LongestHoldTime: %d\r\n"
10659 "%s"
10660 "\r\n",
10661 q->name, qmemcount, qmemavail, qchancount, q->holdtime, q->talktime, qlongestholdtime, idText);
10662 ++qsummaries;
10663 }
10664 ao2_unlock(q);
10665 queue_t_unref(q, "Done with iterator");
10666 }
10667 ao2_iterator_destroy(&queue_iter);
10668
10669 astman_send_list_complete_start(s, m, "QueueSummaryComplete", qsummaries);
10671
10672 return RESULT_SUCCESS;
10673}

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

10865{
10866 const char *queuename, *interface;
10867 struct member *mem = NULL;
10868
10869 queuename = astman_get_header(m, "Queue");
10870 interface = astman_get_header(m, "Interface");
10871
10872 if (ast_strlen_zero(queuename) || ast_strlen_zero(interface)) {
10873 astman_send_error(s, m, "Need 'Queue' and 'Interface' parameters.");
10874 return 0;
10875 }
10876
10878 mem = find_member_by_queuename_and_interface(queuename, interface);
10879 }
10880
10881 switch (remove_from_queue(queuename, interface)) {
10882 case RES_OKAY:
10883 if (!mem || ast_strlen_zero(mem->membername)) {
10884 ast_queue_log(queuename, "MANAGER", interface, "REMOVEMEMBER", "%s", "");
10885 } else {
10886 ast_queue_log(queuename, "MANAGER", mem->membername, "REMOVEMEMBER", "%s", "");
10887 }
10888 astman_send_ack(s, m, "Removed interface from queue");
10889 break;
10890 case RES_EXISTS:
10891 astman_send_error(s, m, "Unable to remove interface: Not there");
10892 break;
10893 case RES_NOSUCHQUEUE:
10894 astman_send_error(s, m, "Unable to remove interface from queue: No such queue");
10895 break;
10896 case RES_OUTOFMEMORY:
10897 astman_send_error(s, m, "Out of memory");
10898 break;
10899 case RES_NOT_DYNAMIC:
10900 astman_send_error(s, m, "Member not dynamic");
10901 break;
10902 }
10903
10904 if (mem) {
10905 ao2_ref(mem, -1);
10906 }
10907
10908 return 0;
10909}

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

11143{
11144 const char *queuename, *caller, *withdraw_info;
11145
11146 queuename = astman_get_header(m, "Queue");
11147 caller = astman_get_header(m, "Caller");
11148 withdraw_info = astman_get_header(m, "WithdrawInfo");
11149
11150 if (ast_strlen_zero(queuename)) {
11151 astman_send_error(s, m, "'Queue' not specified.");
11152 return 0;
11153 }
11154
11155 if (ast_strlen_zero(caller)) {
11156 astman_send_error(s, m, "'Caller' not specified.");
11157 return 0;
11158 }
11159
11160 switch (request_withdraw_caller_from_queue(queuename, caller, withdraw_info)) {
11161 case RES_OKAY:
11162 astman_send_ack(s, m, "Withdraw requested successfully");
11163 break;
11164 case RES_NOSUCHQUEUE:
11165 astman_send_error(s, m, "Unable to request withdraw from queue: No such queue");
11166 break;
11167 case RES_NOT_CALLER:
11168 astman_send_error(s, m, "Unable to request withdraw from queue: No such caller");
11169 break;
11170 case RES_EXISTS:
11171 astman_send_error(s, m, "Unable to request withdraw from queue: Already requested");
11172 break;
11173 }
11174
11175 return 0;
11176}
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:7885

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

9917{
9918 struct member *member = obj;
9919 if (!member->dynamic && !member->realtime) {
9920 member->delme = 1;
9921 }
9922 return 0;
9923}

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

10071{
10072 struct call_queue *q = obj;
10073 char *queuename = arg;
10074 if (!q->realtime && (ast_strlen_zero(queuename) || !strcasecmp(queuename, q->name))) {
10075 q->found = 0;
10076 }
10077 return 0;
10078}

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

3077{
3078 struct member *mem1 = obj1;
3079 struct member *mem2 = obj2;
3080 const char *interface = (flags & OBJ_KEY) ? obj2 : mem2->interface;
3081
3082 return strcasecmp(mem1->interface, interface) ? 0 : CMP_MATCH | CMP_STOP;
3083}
@ 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 3060 of file app_queue.c.

3061{
3062 const struct member *mem = obj;
3063 const char *interface = (flags & OBJ_KEY) ? obj : mem->interface;
3064 const char *chname = strchr(interface, '/');
3065 int ret = 0, i;
3066
3067 if (!chname) {
3068 chname = interface;
3069 }
3070 for (i = 0; i < 5 && chname[i]; i++) {
3071 ret += compress_char(chname[i]) << (i * 6);
3072 }
3073 return ret;
3074}
static int compress_char(const char c)
Definition app_queue.c:3050

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

3718{
3720 ao2_lock(queue->members);
3723 ao2_unlink(queue->members, mem);
3724 ao2_unlock(queue->members);
3725}
static void queue_member_follower_removal(struct call_queue *queue, struct member *mem)
Definition app_queue.c:2177
#define QUEUE_UNKNOWN_PAUSED_DEVSTATE
Definition app_queue.c:3693
#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 4798 of file app_queue.c.

4799{
4801}

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

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

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

3445{
3446 char *value_copy = ast_strdupa(value);
3447 char *option = NULL;
3448 while ((option = strsep(&value_copy, ","))) {
3449 if (!strcasecmp(option, "paused")) {
3450 *empty |= QUEUE_EMPTY_PAUSED;
3451 } else if (!strcasecmp(option, "penalty")) {
3452 *empty |= QUEUE_EMPTY_PENALTY;
3453 } else if (!strcasecmp(option, "inuse")) {
3454 *empty |= QUEUE_EMPTY_INUSE;
3455 } else if (!strcasecmp(option, "ringing")) {
3456 *empty |= QUEUE_EMPTY_RINGING;
3457 } else if (!strcasecmp(option, "invalid")) {
3458 *empty |= QUEUE_EMPTY_INVALID;
3459 } else if (!strcasecmp(option, "wrapup")) {
3460 *empty |= QUEUE_EMPTY_WRAPUP;
3461 } else if (!strcasecmp(option, "unavailable")) {
3462 *empty |= QUEUE_EMPTY_UNAVAILABLE;
3463 } else if (!strcasecmp(option, "unknown")) {
3464 *empty |= QUEUE_EMPTY_UNKNOWN;
3465 } else if (!strcasecmp(option, "loose")) {
3467 } else if (!strcasecmp(option, "strict")) {
3469 } else if ((ast_false(option) && joinempty) || (ast_true(option) && !joinempty)) {
3471 } else if ((ast_false(option) && !joinempty) || (ast_true(option) && joinempty)) {
3472 *empty = 0;
3473 } else {
3474 ast_log(LOG_WARNING, "Unknown option %s for '%s'\n", option, joinempty ? "joinempty" : "leavewhenempty");
3475 }
3476 }
3477}

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

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

2657{
2658 const struct member *object;
2659 const char *key;
2660
2661 switch (flags & OBJ_SEARCH_MASK) {
2662 case OBJ_SEARCH_KEY:
2663 key = obj;
2664 break;
2665 case OBJ_SEARCH_OBJECT:
2666 object = obj;
2667 key = object->interface;
2668 break;
2669 default:
2670 ast_assert(0);
2671 return 0;
2672 }
2673 return ast_str_case_hash(key);
2674}
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 2704 of file app_queue.c.

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

4299{
4300 int res;
4301
4302 if (ast_strlen_zero(filename)) {
4303 return 0;
4304 }
4305
4306 if (!ast_fileexists(filename, NULL, ast_channel_language(chan))) {
4307 return 0;
4308 }
4309
4310 ast_stopstream(chan);
4311
4312 res = ast_streamfile(chan, filename, ast_channel_language(chan));
4313 if (!res) {
4314 res = ast_waitstream(chan, AST_DIGIT_ANY);
4315 }
4316
4317 ast_stopstream(chan);
4318
4319 return res;
4320}
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 8379 of file app_queue.c.

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

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

10219{
10220 float sl;
10221 float sl2;
10222 struct ao2_iterator mem_iter;
10223 struct ast_str *out = ast_str_alloca(512);
10224 time_t now = time(NULL);
10225
10226 ast_str_set(&out, 0, "%s has %d calls (max ", q->name, q->count);
10227 if (q->maxlen) {
10228 ast_str_append(&out, 0, "%d", q->maxlen);
10229 } else {
10230 ast_str_append(&out, 0, "unlimited");
10231 }
10232 sl = 0;
10233 sl2 = 0;
10234 if (q->callscompleted > 0) {
10235 sl = 100 * ((float) q->callscompletedinsl / (float) q->callscompleted);
10236 }
10237 if (q->callscompleted + q->callsabandoned > 0) {
10238 sl2 =100 * (((float)q->callsabandonedinsl + (float)q->callscompletedinsl) / ((float)q->callsabandoned + (float)q->callscompleted));
10239 }
10240
10241 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",
10243 do_print(s, fd, ast_str_buffer(out));
10244 if (!ao2_container_count(q->members)) {
10245 do_print(s, fd, " No Members");
10246 } else {
10247 struct member *mem;
10248
10249 do_print(s, fd, " Members: ");
10250 mem_iter = ao2_iterator_init(q->members, 0);
10251 while ((mem = ao2_iterator_next(&mem_iter))) {
10252 ast_str_set(&out, 0, " %s", mem->membername);
10253 if (strcasecmp(mem->membername, mem->interface)) {
10254 ast_str_append(&out, 0, " (%s", mem->interface);
10256 && strcmp(mem->state_interface, mem->interface)) {
10257 ast_str_append(&out, 0, " from %s", mem->state_interface);
10258 }
10259 ast_str_append(&out, 0, ")");
10260 }
10261 if (mem->penalty) {
10262 ast_str_append(&out, 0, " with penalty %d", mem->penalty);
10263 }
10264
10265 ast_str_append(&out, 0, " (ringinuse %s)", mem->ringinuse ? "enabled" : "disabled");
10266
10267 ast_str_append(&out, 0, "%s%s%s%s%s%s%s%s%s",
10268 mem->dynamic ? ast_term_color(COLOR_CYAN, COLOR_BLACK) : "", mem->dynamic ? " (dynamic)" : "", ast_term_reset(),
10269 mem->realtime ? ast_term_color(COLOR_MAGENTA, COLOR_BLACK) : "", mem->realtime ? " (realtime)" : "", ast_term_reset(),
10270 mem->starttime ? ast_term_color(COLOR_BROWN, COLOR_BLACK) : "", mem->starttime ? " (in call)" : "", ast_term_reset());
10271
10272 if (mem->paused) {
10273 ast_str_append(&out, 0, " %s(paused%s%s was %ld secs ago)%s",
10275 ast_strlen_zero(mem->reason_paused) ? "" : ":",
10277 (long) (now - mem->lastpause),
10278 ast_term_reset());
10279 }
10280
10281 ast_str_append(&out, 0, " (%s%s%s)",
10286 if (mem->calls) {
10287 ast_str_append(&out, 0, " has taken %d calls (last was %ld secs ago)",
10288 mem->calls, (long) (now - mem->lastcall));
10289 } else {
10290 ast_str_append(&out, 0, " has taken no calls yet");
10291 }
10292 ast_str_append(&out, 0, " %s(login was %ld secs ago)%s",
10294 (long) (now - mem->logintime),
10295 ast_term_reset());
10296 do_print(s, fd, ast_str_buffer(out));
10297 ao2_ref(mem, -1);
10298 }
10299 ao2_iterator_destroy(&mem_iter);
10300 }
10301 if (!q->head) {
10302 do_print(s, fd, " No Callers");
10303 } else {
10304 struct queue_ent *qe;
10305 int pos = 1;
10306
10307 do_print(s, fd, " Callers: ");
10308 for (qe = q->head; qe; qe = qe->next) {
10309 ast_str_set(&out, 0, " %d. %s (wait: %ld:%2.2ld, prio: %d)",
10310 pos++, ast_channel_name(qe->chan), (long) (now - qe->start) / 60,
10311 (long) (now - qe->start) % 60, qe->prio);
10312 do_print(s, fd, ast_str_buffer(out));
10313 }
10314 }
10315 do_print(s, fd, ""); /* blank line between entries */
10316}
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 4612 of file app_queue.c.

4613{
4614 struct callattempt *cur;
4615
4616 for (cur = outgoing; cur; cur = cur->q_next) {
4617 if (cur->chan && cur->chan != exception) {
4619 }
4620 }
4621}
struct callattempt * q_next
Definition app_queue.c:1803
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 7924 of file app_queue.c.

7925{
7926 struct ast_json *json_blob = queue_member_blob_create(q, member);
7927
7928 if (!json_blob) {
7929 return -1;
7930 }
7931
7932 queue_publish_member_blob(queue_member_pause_type(), json_blob);
7933
7934 return 0;
7935}

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

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

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

2400{
2401 return queue_multi_channel_to_ami("AgentCalled", message);
2402}
static struct ast_manager_event_blob * queue_multi_channel_to_ami(const char *type, struct stasis_message *message)
Definition app_queue.c:2358

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

6317{
6318 struct ast_channel_blob *agent_blob;
6319
6320 agent_blob = stasis_message_data(msg);
6321
6323 ast_queue_log("NONE", agent_blob->snapshot->base->uniqueid,
6324 ast_json_string_get(ast_json_object_get(agent_blob->blob, "agent")),
6325 "AGENTLOGIN", "%s", agent_blob->snapshot->base->name);
6327 ast_queue_log("NONE", agent_blob->snapshot->base->uniqueid,
6328 ast_json_string_get(ast_json_object_get(agent_blob->blob, "agent")),
6329 "AGENTLOGOFF", "%s|%ld", agent_blob->snapshot->base->name,
6330 (long) ast_json_integer_get(ast_json_object_get(agent_blob->blob, "logintime")));
6331 }
6332}

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

2410{
2411 return queue_multi_channel_to_ami("AgentComplete", message);
2412}

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

2405{
2406 return queue_multi_channel_to_ami("AgentConnect", message);
2407}

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

2415{
2416 return queue_multi_channel_to_ami("AgentDump", message);
2417}

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

2420{
2421 return queue_multi_channel_to_ami("AgentRingNoAnswer", message);
2422}

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

6680{
6682 ao2_cleanup(userdata);
6683 }
6684}
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 2279 of file app_queue.c.

2280{
2281 return queue_channel_to_ami("QueueCallerAbandon", message);
2282}
static struct ast_manager_event_blob * queue_channel_to_ami(const char *type, struct stasis_message *message)
Definition app_queue.c:2250

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

2270{
2271 return queue_channel_to_ami("QueueCallerJoin", message);
2272}

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

2275{
2276 return queue_channel_to_ami("QueueCallerLeave", message);
2277}

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

6913{
6915 ao2_cleanup(userdata);
6916 }
6917}

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

2251{
2253 RAII_VAR(struct ast_str *, channel_string, NULL, ast_free);
2254 RAII_VAR(struct ast_str *, event_string, NULL, ast_free);
2255
2256 channel_string = ast_manager_build_channel_state_string(obj->snapshot);
2257 event_string = ast_manager_str_from_json_object(obj->blob, NULL);
2258 if (!channel_string || !event_string) {
2259 return NULL;
2260 }
2261
2263 "%s"
2264 "%s",
2265 ast_str_buffer(channel_string),
2266 ast_str_buffer(event_string));
2267}
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 2113 of file app_queue.c.

2114{
2115 struct call_queue *q = obj, *q2 = arg;
2116 return !strcasecmp(q->name, q2->name) ? CMP_MATCH | CMP_STOP : 0;
2117}

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

2160{
2161 struct member *mem = obj;
2162 struct call_queue *queue = arg;
2163 int rrpos = mem->queuepos;
2164
2165 if (mem->delme) {
2167 }
2168
2169 return 0;
2170}
static int queue_member_decrement_followers(void *obj, void *arg, int flag)
Definition app_queue.c:2140
#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 8693 of file app_queue.c.

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

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

Referenced by load_module().

◆ queue_function_exists()

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

Check if a given queue exists.

Definition at line 9177 of file app_queue.c.

9178{
9179 struct call_queue *q;
9180
9181 buf[0] = '\0';
9182
9183 if (ast_strlen_zero(data)) {
9184 ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd);
9185 return -1;
9186 }
9188 snprintf(buf, len, "%d", q != NULL? 1 : 0);
9189 if (q) {
9190 queue_t_unref(q, "Done with temporary reference in QUEUE_EXISTS()");
9191 }
9192
9193 return 0;
9194}
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 9219 of file app_queue.c.

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

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

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

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

9545{
9546 int penalty;
9548 AST_APP_ARG(queuename);
9549 AST_APP_ARG(interface);
9550 );
9551 /* Make sure the returned value on error is NULL. */
9552 buf[0] = '\0';
9553
9554 if (ast_strlen_zero(data)) {
9555 ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n");
9556 return -1;
9557 }
9558
9560
9561 if (args.argc < 2) {
9562 ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n");
9563 return -1;
9564 }
9565
9566 penalty = get_member_penalty (args.queuename, args.interface);
9567
9568 if (penalty >= 0) { /* remember that buf is already '\0' */
9569 snprintf (buf, len, "%d", penalty);
9570 }
9571
9572 return 0;
9573}
static int get_member_penalty(char *queuename, char *interface)
Gets members penalty.
Definition app_queue.c:8237

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

9577{
9578 int penalty;
9580 AST_APP_ARG(queuename);
9581 AST_APP_ARG(interface);
9582 );
9583
9584 if (ast_strlen_zero(data)) {
9585 ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n");
9586 return -1;
9587 }
9588
9590
9591 if (args.argc < 2) {
9592 ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n");
9593 return -1;
9594 }
9595
9596 penalty = atoi(value);
9597
9598 if (ast_strlen_zero(args.interface)) {
9599 ast_log (LOG_ERROR, "<interface> parameter can't be null\n");
9600 return -1;
9601 }
9602
9603 /* if queuename = NULL then penalty will be set for interface in all the queues. */
9604 if (set_member_value(args.queuename, args.interface, MEMBER_PENALTY, penalty)) {
9605 ast_log(LOG_ERROR, "Invalid interface, queue or penalty\n");
9606 return -1;
9607 }
9608
9609 return 0;
9610}

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

9381{
9382 int position;
9383 char *parse;
9384 struct call_queue *q;
9385 struct ast_variable *var;
9386
9388 AST_APP_ARG(queuename);
9389 AST_APP_ARG(position);
9390 );
9391
9392 buf[0] = '\0';
9393
9394 if (ast_strlen_zero(data)) {
9395 ast_log(LOG_ERROR, "Missing argument. QUEUE_GET_CHANNEL(<queuename>,<position>)\n");
9396 return -1;
9397 }
9398
9399 parse = ast_strdupa(data);
9401
9402 if (ast_strlen_zero(args.queuename)) {
9403 ast_log (LOG_ERROR, "The <queuename> parameter is required.\n");
9404 return -1;
9405 }
9406
9407 if (ast_strlen_zero(args.position)) {
9408 position = 1;
9409 } else {
9410 if (sscanf(args.position, "%30d", &position) != 1) {
9411 ast_log (LOG_ERROR, "<position> parameter must be an integer.\n");
9412 return -1;
9413 }
9414 if (position < 1) {
9415 ast_log (LOG_ERROR, "<position> parameter must be an integer greater than zero.\n");
9416 return -1;
9417 }
9418 }
9419
9420 {
9421 struct call_queue tmpq = {
9422 .name = args.queuename,
9423 };
9424
9425 q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Find for QUEUE_GET_CHANNEL()");
9426 }
9427 if (q) {
9428 ao2_lock(q);
9429 if (q->count >= position) {
9430 struct queue_ent *qe;
9431
9432 for (qe = q->head; qe; qe = qe->next) {
9433 if (qe->pos == position) {
9435 break;
9436 }
9437 }
9438 }
9439 ao2_unlock(q);
9440 queue_t_unref(q, "Done with reference in QUEUE_GET_CHANNEL()");
9441 return 0;
9442 }
9443
9444 var = ast_load_realtime("queues", "name", args.queuename, SENTINEL);
9445 if (var) {
9446 /* if the queue is realtime but was not found in memory, this
9447 * means that the queue had been deleted from memory since it was
9448 * "dead."
9449 */
9451 return 0;
9452 }
9453
9454 ast_log(LOG_WARNING, "queue %s was not found\n", args.queuename);
9455 return 0;
9456}

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

9497{
9498 struct call_queue *q;
9499 struct member *m;
9500
9501 /* Ensure an otherwise empty list doesn't return garbage */
9502 buf[0] = '\0';
9503
9504 if (ast_strlen_zero(data)) {
9505 ast_log(LOG_ERROR, "QUEUE_MEMBER_LIST requires an argument: queuename\n");
9506 return -1;
9507 }
9508
9509 if ((q = find_load_queue_rt_friendly(data))) {
9510 int buflen = 0, count = 0;
9511 struct ao2_iterator mem_iter;
9512
9513 ao2_lock(q);
9514 mem_iter = ao2_iterator_init(q->members, 0);
9515 while ((m = ao2_iterator_next(&mem_iter))) {
9516 /* strcat() is always faster than printf() */
9517 if (count++) {
9518 strncat(buf + buflen, ",", len - buflen - 1);
9519 buflen++;
9520 }
9521 strncat(buf + buflen, m->interface, len - buflen - 1);
9522 buflen += strlen(m->interface);
9523 /* Safeguard against overflow (negative length) */
9524 if (buflen >= len - 2) {
9525 ao2_ref(m, -1);
9526 ast_log(LOG_WARNING, "Truncating list\n");
9527 break;
9528 }
9529 ao2_ref(m, -1);
9530 }
9531 ao2_iterator_destroy(&mem_iter);
9532 ao2_unlock(q);
9533 queue_t_unref(q, "Done with QUEUE_MEMBER_LIST()");
9534 } else
9535 ast_log(LOG_WARNING, "queue %s was not found\n", data);
9536
9537 /* We should already be terminated, but let's make sure. */
9538 buf[len - 1] = '\0';
9539
9540 return 0;
9541}

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

9460{
9461 int count = 0;
9462 struct call_queue *q, tmpq = {
9463 .name = data,
9464 };
9465 struct ast_variable *var = NULL;
9466
9467 buf[0] = '\0';
9468
9469 if (ast_strlen_zero(data)) {
9470 ast_log(LOG_ERROR, "QUEUE_WAITING_COUNT requires an argument: queuename\n");
9471 return -1;
9472 }
9473
9474 if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Find for QUEUE_WAITING_COUNT()"))) {
9475 ao2_lock(q);
9476 count = q->count;
9477 ao2_unlock(q);
9478 queue_t_unref(q, "Done with reference in QUEUE_WAITING_COUNT()");
9479 } else if ((var = ast_load_realtime("queues", "name", data, SENTINEL))) {
9480 /* if the queue is realtime but was not found in memory, this
9481 * means that the queue had been deleted from memory since it was
9482 * "dead." This means it has a 0 waiting count
9483 */
9484 count = 0;
9486 } else {
9487 ast_log(LOG_WARNING, "queue %s was not found\n", data);
9488 }
9489
9490 snprintf(buf, len, "%d", count);
9491
9492 return 0;
9493}

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

9134{
9135 int res = -1;
9136 struct call_queue *q;
9137 char interfacevar[256] = "";
9138 float sl = 0;
9139
9140 if (ast_strlen_zero(data)) {
9141 ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd);
9142 return -1;
9143 }
9144
9145 if ((q = find_load_queue_rt_friendly(data))) {
9146 ao2_lock(q);
9147 if (q->setqueuevar) {
9148 sl = 0;
9149 res = 0;
9150
9151 if (q->callscompleted > 0) {
9152 sl = 100 * ((float) q->callscompletedinsl / (float) q->callscompleted);
9153 }
9154
9155 snprintf(interfacevar, sizeof(interfacevar),
9156 "QUEUEMAX=%d,QUEUESTRATEGY=%s,QUEUECALLS=%d,QUEUEHOLDTIME=%d,QUEUETALKTIME=%d,QUEUECOMPLETED=%d,QUEUEABANDONED=%d,QUEUESRVLEVEL=%d,QUEUESRVLEVELPERF=%2.1f",
9158
9159 pbx_builtin_setvar_multiple(chan, interfacevar);
9160 }
9161
9162 ao2_unlock(q);
9163 queue_t_unref(q, "Done with QUEUE() function");
9164 } else {
9165 ast_log(LOG_WARNING, "queue %s was not found\n", data);
9166 }
9167
9168 snprintf(buf, len, "%d", res);
9169
9170 return 0;
9171}
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 2106 of file app_queue.c.

2107{
2108 const struct call_queue *q = obj;
2109
2110 return ast_str_case_hash(q->name);
2111}

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

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

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

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

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

2141{
2142 struct member *mem = obj;
2143 int *decrement_followers_after = arg;
2144
2145 if (mem->queuepos > *decrement_followers_after) {
2146 mem->queuepos--;
2147 }
2148
2149 return 0;
2150}

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

2178{
2179 int pos = mem->queuepos;
2180
2181 /* 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
2182 * who would have been next otherwise. */
2183 if (pos < queue->rrpos) {
2184 queue->rrpos--;
2185 }
2186
2188}

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

2325{
2326 return queue_member_to_ami("QueueMemberPause", message);
2327}

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

2330{
2331 return queue_member_to_ami("QueueMemberPenalty", message);
2332}

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

2320{
2321 return queue_member_to_ami("QueueMemberRemoved", message);
2322}

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

2335{
2336 return queue_member_to_ami("QueueMemberRinginuse", message);
2337}

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

2310{
2311 return queue_member_to_ami("QueueMemberStatus", message);
2312}

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

2359{
2362 struct ast_channel_snapshot *agent;
2363 RAII_VAR(struct ast_str *, caller_event_string, NULL, ast_free);
2364 RAII_VAR(struct ast_str *, agent_event_string, NULL, ast_free);
2365 RAII_VAR(struct ast_str *, event_string, NULL, ast_free);
2366
2368 if (caller) {
2369 caller_event_string = ast_manager_build_channel_state_string(caller);
2370 if (!caller_event_string) {
2371 ast_log(LOG_NOTICE, "No caller event string, bailing\n");
2372 return NULL;
2373 }
2374 }
2375
2376 agent = ast_multi_channel_blob_get_channel(obj, "agent");
2377 if (agent) {
2378 agent_event_string = ast_manager_build_channel_state_string_prefix(agent, "Dest");
2379 if (!agent_event_string) {
2380 ast_log(LOG_NOTICE, "No agent event string, bailing\n");
2381 return NULL;
2382 }
2383 }
2384
2386 if (!event_string) {
2387 return NULL;
2388 }
2389
2391 "%s"
2392 "%s"
2393 "%s",
2394 caller_event_string ? ast_str_buffer(caller_event_string) : "",
2395 agent_event_string ? ast_str_buffer(agent_event_string) : "",
2396 ast_str_buffer(event_string));
2397}
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 2506 of file app_queue.c.

2507{
2508 RAII_VAR(struct ast_json_payload *, payload, NULL, ao2_cleanup);
2509 RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
2510
2511 if (!blob || !type) {
2512 ast_json_unref(blob);
2513 return;
2514 }
2515
2516 payload = ast_json_payload_create(blob);
2517 ast_json_unref(blob);
2518 if (!payload) {
2519 return;
2520 }
2521
2522 msg = stasis_message_create(type, payload);
2523 if (!msg) {
2524 return;
2525 }
2526
2528}
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 2475 of file app_queue.c.

2477{
2478 RAII_VAR(struct ast_channel_snapshot *, caller_snapshot, NULL, ao2_cleanup);
2479 RAII_VAR(struct ast_channel_snapshot *, agent_snapshot, NULL, ao2_cleanup);
2480
2481 ast_channel_lock(caller);
2482 caller_snapshot = ast_channel_snapshot_create(caller);
2483 ast_channel_unlock(caller);
2484 ast_channel_lock(agent);
2485 agent_snapshot = ast_channel_snapshot_create(agent);
2486 ast_channel_unlock(agent);
2487
2488 if (!caller_snapshot || !agent_snapshot) {
2489 return;
2490 }
2491
2493 agent_snapshot, type, blob);
2494}
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:2440
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 2440 of file app_queue.c.

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

9730{
9732 autofill_default = 0;
9733 montype_default = 0;
9734 shared_lastcall = 0;
9739}
static int montype_default
queues.conf [general] option
Definition app_queue.c:1726
static int negative_penalty_invalid
queues.conf [general] option
Definition app_queue.c:1738
static int shared_lastcall
queues.conf [general] option
Definition app_queue.c:1729
static int log_unpause_on_reason_change
queues.conf [general] option
Definition app_queue.c:1750

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

9651{
9652 realtime_rules = 0;
9653}
static int realtime_rules
queuerules.conf [general] option
Definition app_queue.c:1732

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

9657{
9658 const char *general_val = NULL;
9659 if ((general_val = ast_variable_retrieve(cfg, "general", "realtime_rules"))) {
9660 realtime_rules = ast_true(general_val);
9661 }
9662}

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

9743{
9744 const char *general_val = NULL;
9745 if ((general_val = ast_variable_retrieve(cfg, "general", "persistentmembers"))) {
9746 queue_persistent_members = ast_true(general_val);
9747 }
9748 if ((general_val = ast_variable_retrieve(cfg, "general", "autofill"))) {
9749 autofill_default = ast_true(general_val);
9750 }
9751 if ((general_val = ast_variable_retrieve(cfg, "general", "monitor-type"))) {
9752 if (!strcasecmp(general_val, "mixmonitor"))
9753 montype_default = 1;
9754 }
9755 if ((general_val = ast_variable_retrieve(cfg, "general", "shared_lastcall"))) {
9756 shared_lastcall = ast_true(general_val);
9757 }
9758 if ((general_val = ast_variable_retrieve(cfg, "general", "negative_penalty_invalid"))) {
9759 negative_penalty_invalid = ast_true(general_val);
9760 }
9761 if ((general_val = ast_variable_retrieve(cfg, "general", "log_membername_as_agent"))) {
9762 log_membername_as_agent = ast_true(general_val);
9763 }
9764 if ((general_val = ast_variable_retrieve(cfg, "general", "force_longest_waiting_caller"))) {
9766 }
9767 if ((general_val = ast_variable_retrieve(cfg, "general", "log_unpause_on_reason_change"))) {
9769 }
9770 /* Apply log-caller-id-name in the same place as other global settings */
9771 if ((general_val = ast_variable_retrieve(cfg, "general", "log-caller-id-name"))) {
9772 log_caller_id_name = ast_true(general_val);
9773 }
9774}

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

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

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

10543{
10544 switch ( cmd ) {
10545 case CLI_INIT:
10546 e->command = "queue show";
10547 e->usage =
10548 "Usage: queue show\n"
10549 " Provides summary information on a specified queue.\n";
10550 return NULL;
10551 case CLI_GENERATE:
10552 return complete_queue_show(a->line, a->word, a->pos, a->n);
10553 }
10554
10555 return __queues_show(NULL, a->fd, a->argc, a->argv);
10556}
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 6446 of file app_queue.c.

6449{
6450 struct queue_stasis_data *queue_data;
6451
6452 queue_data = ao2_alloc(sizeof(*queue_data), queue_stasis_data_destructor);
6453 if (!queue_data) {
6454 return NULL;
6455 }
6456
6457 if (ast_string_field_init(queue_data, 64)) {
6458 ao2_cleanup(queue_data);
6459 return NULL;
6460 }
6461
6464 queue_data->queue = queue_ref(qe->parent);
6465 queue_data->starttime = starttime;
6466 queue_data->holdstart = holdstart;
6468 queue_data->caller_pos = qe->opos;
6469 ao2_ref(mem, +1);
6470 queue_data->member = mem;
6471
6472 return queue_data;
6473}
static void queue_stasis_data_destructor(void *obj)
Definition app_queue.c:6414

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

6415{
6416 struct queue_stasis_data *queue_data = obj;
6417
6418 /* This can only happen if refcounts for this object have got severely messed up */
6419 ast_assert(queue_data->bridge_router == NULL);
6420 ast_assert(queue_data->channel_router == NULL);
6421
6422 ao2_cleanup(queue_data->member);
6423 queue_unref(queue_data->queue);
6424 ast_string_field_free_memory(queue_data);
6425}
struct stasis_message_router * channel_router
Definition app_queue.c:6403
struct stasis_message_router * bridge_router
Definition app_queue.c:6401

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

11788{
11789 int oldtalktime;
11790 char *parse;
11791 struct call_queue *q;
11792 struct member *mem;
11793 int newtalktime = 0;
11794
11796 AST_APP_ARG(queuename);
11797 AST_APP_ARG(uniqueid);
11798 AST_APP_ARG(agent);
11800 AST_APP_ARG(talktime);
11801 AST_APP_ARG(params););
11802
11803 if (ast_strlen_zero(data)) {
11804 ast_log(LOG_WARNING, "QueueUpdate requires arguments (queuename,uniqueid,agent,status,talktime,params[totaltime,callednumber])\n");
11805 return -1;
11806 }
11807
11808 parse = ast_strdupa(data);
11809
11811
11812 if (ast_strlen_zero(args.queuename) || ast_strlen_zero(args.uniqueid) || ast_strlen_zero(args.agent) || ast_strlen_zero(args.status)) {
11813 ast_log(LOG_WARNING, "Missing argument to QueueUpdate (queuename,uniqueid,agent,status,talktime,params[totaltime|callednumber])\n");
11814 return -1;
11815 }
11816
11817 if (!ast_strlen_zero(args.talktime)) {
11818 newtalktime = atoi(args.talktime);
11819 }
11820
11821 q = find_load_queue_rt_friendly(args.queuename);
11822 if (!q) {
11823 ast_log(LOG_WARNING, "QueueUpdate could not find requested queue '%s'\n", args.queuename);
11824 return 0;
11825 }
11826
11827 ao2_lock(q);
11828 if (q->members) {
11829 struct ao2_iterator mem_iter = ao2_iterator_init(q->members, 0);
11830 while ((mem = ao2_iterator_next(&mem_iter))) {
11831 if (!strcasecmp(mem->membername, args.agent)) {
11832 if (!strcasecmp(args.status, "ANSWER")) {
11833 oldtalktime = q->talktime;
11834 q->talktime = (((oldtalktime << 2) - oldtalktime) + newtalktime) >> 2;
11835 time(&mem->lastcall);
11836 mem->calls++;
11837 mem->lastqueue = q;
11838 q->callscompleted++;
11839
11840 if (newtalktime <= q->servicelevel) {
11841 q->callscompletedinsl++;
11842 }
11843 } else {
11844
11845 time(&mem->lastcall);
11846 q->callsabandoned++;
11847 }
11848
11849 ast_queue_log(args.queuename, args.uniqueid, args.agent, "OUTCALL", "%s|%s|%s", args.status, args.talktime, args.params);
11850 }
11851
11852 ao2_ref(mem, -1);
11853 }
11854
11855 ao2_iterator_destroy(&mem_iter);
11856 }
11857
11858 ao2_unlock(q);
11859 queue_t_unref(q, "Done with temporary pointer");
11860
11861 return 0;
11862}

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

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

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

5235{
5236 int callabandonedinsl = 0;
5237 time_t now;
5238
5239 RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
5240
5241 pbx_builtin_setvar_helper(qe->chan, "ABANDONED", "TRUE");
5242
5244 ao2_lock(qe->parent);
5245 blob = ast_json_pack("{s: s, s: i, s: i, s: i}",
5246 "Queue", qe->parent->name,
5247 "Position", qe->pos,
5248 "OriginalPosition", qe->opos,
5249 "HoldTime", (int)(time(NULL) - qe->start));
5250
5251
5252 time(&now);
5253 callabandonedinsl = ((now - qe->start) <= qe->parent->servicelevel);
5254 if (callabandonedinsl) {
5256 }
5257
5258 qe->parent->callsabandoned++;
5259 ao2_unlock(qe->parent);
5260
5261 ast_channel_publish_cached_blob(qe->chan, queue_caller_abandon_type(), blob);
5262}

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

12110{
12111 struct ast_flags mask = {AST_FLAGS_ALL & ~QUEUE_RESET_STATS,};
12112 ast_unload_realtime("queue_members");
12113 reload_handler(1, &mask, NULL);
12114 return 0;
12115}
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 10191 of file app_queue.c.

10192{
10193 int res = 0;
10194
10195 if (ast_test_flag(mask, QUEUE_RELOAD_RULES)) {
10196 res |= reload_queue_rules(reload);
10197 }
10198 if (ast_test_flag(mask, QUEUE_RESET_STATS)) {
10199 res |= clear_stats(queuename);
10200 }
10202 res |= reload_queues(reload, mask, queuename);
10203 }
10204 return res;
10205}
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:9670
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 8268 of file app_queue.c.

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

9671{
9672 struct ast_config *cfg;
9673 struct rule_list *rl_iter, *new_rl;
9674 struct penalty_rule *pr_iter;
9675 char *rulecat = NULL;
9676 struct ast_variable *rulevar = NULL;
9677 struct ast_flags config_flags = { (reload && !realtime_rules) ? CONFIG_FLAG_FILEUNCHANGED : 0 };
9678
9679 if (!(cfg = ast_config_load("queuerules.conf", config_flags))) {
9680 ast_log(LOG_NOTICE, "No queuerules.conf file found, queues will not follow penalty rules\n");
9682 } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
9683 ast_log(LOG_NOTICE, "queuerules.conf has not changed since it was last loaded. Not taking any action.\n");
9685 } else if (cfg == CONFIG_STATUS_FILEINVALID) {
9686 ast_log(LOG_ERROR, "Config file queuerules.conf is in an invalid format. Aborting.\n");
9688 }
9689
9691 while ((rl_iter = AST_LIST_REMOVE_HEAD(&rule_lists, list))) {
9692 while ((pr_iter = AST_LIST_REMOVE_HEAD(&rl_iter->rules, list)))
9693 ast_free(pr_iter);
9694 ast_free(rl_iter);
9695 }
9697 while ((rulecat = ast_category_browse(cfg, rulecat))) {
9698 if (!strcasecmp(rulecat, "general")) {
9700 continue;
9701 }
9702 if (!(new_rl = ast_calloc(1, sizeof(*new_rl)))) {
9704 ast_config_destroy(cfg);
9706 } else {
9707 ast_copy_string(new_rl->name, rulecat, sizeof(new_rl->name));
9708 AST_LIST_INSERT_TAIL(&rule_lists, new_rl, list);
9709 for (rulevar = ast_variable_browse(cfg, rulecat); rulevar; rulevar = rulevar->next)
9710 if(!strcasecmp(rulevar->name, "penaltychange"))
9711 insert_penaltychange(new_rl->name, rulevar->value, rulevar->lineno);
9712 else
9713 ast_log(LOG_WARNING, "Don't know how to handle rule type '%s' on line %d\n", rulevar->name, rulevar->lineno);
9714 }
9715 }
9716
9717 ast_config_destroy(cfg);
9718
9722 }
9723
9726}
static int load_realtime_rules(void)
Load queue rules from realtime.
Definition app_queue.c:3332
static void queue_rules_reset_global_params(void)
Definition app_queue.c:9650
static int insert_penaltychange(const char *list_name, const char *content, const int linenum)
Change queue penalty by adding rule.
Definition app_queue.c:3223
static void queue_rules_set_global_params(struct ast_config *cfg)
Definition app_queue.c:9656
#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 10104 of file app_queue.c.

10105{
10106 struct ast_config *cfg;
10107 char *cat;
10108 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
10109 const int queue_reload = ast_test_flag(mask, QUEUE_RELOAD_PARAMETERS);
10110
10111 if (!(cfg = ast_config_load("queues.conf", config_flags))) {
10112 ast_log(LOG_NOTICE, "No call queueing config file (queues.conf), so no call queues\n");
10113 return -1;
10114 } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
10115 return 0;
10116 } else if (cfg == CONFIG_STATUS_FILEINVALID) {
10117 ast_log(LOG_ERROR, "Config file queues.conf is in an invalid format. Aborting.\n");
10118 return -1;
10119 }
10120
10121 /* We've made it here, so it looks like we're doing operations on all queues. */
10123
10124 /* Mark non-realtime queues not found at the beginning. */
10125 ao2_callback(queues, OBJ_NODATA, mark_unfound, (char *) queuename);
10126
10127 /* Chug through config file. */
10128 cat = NULL;
10130 while ((cat = ast_category_browse(cfg, cat)) ) {
10131 if (!strcasecmp(cat, "general") && queue_reload) {
10133 continue;
10134 }
10135 if (ast_strlen_zero(queuename) || !strcasecmp(cat, queuename))
10136 reload_single_queue(cfg, mask, cat);
10137 }
10138
10139 ast_config_destroy(cfg);
10140 if (queue_reload) {
10141 /* Unlink and mark dead all non-realtime queues that were not found in the configuration file. */
10143 }
10145 return 0;
10146}
static void queue_reset_global_params(void)
Definition app_queue.c:9729
static void reload_single_queue(struct ast_config *cfg, struct ast_flags *mask, const char *queuename)
Reload information pertaining to a particular queue.
Definition app_queue.c:9947
static void queue_set_global_params(struct ast_config *cfg)
Definition app_queue.c:9742
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 9784 of file app_queue.c.

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

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

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

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

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

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

6432{
6433 SCOPED_AO2LOCK(lock, queue_data);
6434
6435 queue_data->dying = 1;
6437 queue_data->bridge_router = NULL;
6439 queue_data->channel_router = NULL;
6440}
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 7885 of file app_queue.c.

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

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

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

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

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

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

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

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

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

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

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

5174{
5175 int res = 0;
5176 time_t now;
5177
5178 /* Get the current time */
5179 time(&now);
5180
5181 /* Check to see if it is time to announce */
5183 return 0;
5184 }
5185
5186 /* Stop the music on hold so we can play our own file */
5187 if (ringing) {
5188 ast_indicate(qe->chan,-1);
5189 } else {
5190 ast_moh_stop(qe->chan);
5191 }
5192
5193 ast_verb(3, "Playing periodic announcement\n");
5194
5196 qe->last_periodic_announce_sound = ((unsigned long) ast_random()) % qe->parent->numperiodicannounce;
5200 }
5201
5202 /* play the announcement */
5204
5205 if (res > 0 && !valid_exit(qe, res)) {
5206 res = 0;
5207 }
5208
5209 /* Resume Music on Hold if the caller is going to stay in the queue */
5210 if (!res) {
5211 if (ringing) {
5213 } else {
5214 ast_moh_start(qe->chan, qe->moh, NULL);
5215 }
5216 }
5217
5218 /* update last_periodic_announce_time */
5220 time(&qe->last_periodic_announce_time);
5221 } else {
5223 }
5224
5225 /* Update the current periodic announcement to the next announcement */
5226 if (!qe->parent->randomperiodicannounce) {
5228 }
5229
5230 return res;
5231}
static int play_file(struct ast_channel *chan, const char *filename)
Definition app_queue.c:4298
static int valid_exit(struct queue_ent *qe, char digit)
Check for valid exit from queue via goto.
Definition app_queue.c:4327

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

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

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

6287{
6288 const char *reason = NULL; /* silence dumb compilers */
6289 RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
6290
6291 switch (rsn) {
6292 case CALLER:
6293 reason = "caller";
6294 break;
6295 case AGENT:
6296 reason = "agent";
6297 break;
6298 case TRANSFER:
6299 reason = "transfer";
6300 break;
6301 }
6302
6303 blob = ast_json_pack("{s: s, s: s, s: s, s: I, s: I, s: s}",
6304 "Queue", queuename,
6305 "Interface", member->interface,
6306 "MemberName", member->membername,
6307 "HoldTime", (ast_json_int_t)(callstart - holdstart),
6308 "TalkTime", (ast_json_int_t)(time(NULL) - callstart),
6309 "Reason", reason ?: "");
6310
6312 queue_agent_complete_type(), blob);
6313}
struct stasis_topic * ast_queue_topic(const char *queuename)
Get the Stasis Message Bus API topic for queue messages for a particular queue name.
Definition main/app.c:3349
AST_JSON_INT_T ast_json_int_t
Primarily used to cast when packing to an "I" type.
Definition json.h:87

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

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

◆ set_member_paused()

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

Definition at line 8020 of file app_queue.c.

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

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

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

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

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

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

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

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

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

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

7949{
7950 if (mem->paused == paused) {
7951 ast_debug(1, "%spausing already-%spaused queue member %s:%s\n",
7952 (paused ? "" : "un"), (paused ? "" : "un"), q->name, mem->interface);
7953 if (log_unpause_on_reason_change && paused) {
7954 if (!ast_strings_equal(mem->reason_paused, reason)) {
7955 ast_queue_log(q->name, "NONE", mem->membername, "UNPAUSE", "%s", "Auto-Unpause");
7956 }
7957 }
7958 }
7959
7960 if (mem->realtime && !ast_strlen_zero(mem->rt_uniqueid)) {
7962 if (ast_update_realtime("queue_members", "uniqueid", mem->rt_uniqueid, "reason_paused", S_OR(reason, ""), "paused", paused ? "1" : "0", SENTINEL) < 0) {
7963 ast_log(LOG_WARNING, "Failed update of realtime queue member %s:%s %spause and reason '%s'\n",
7964 q->name, mem->interface, (paused ? "" : "un"), S_OR(reason, ""));
7965 }
7966 } else {
7967 if (ast_update_realtime("queue_members", "uniqueid", mem->rt_uniqueid, "paused", paused ? "1" : "0", SENTINEL) < 0) {
7968 ast_log(LOG_WARNING, "Failed %spause update of realtime queue member %s:%s\n",
7969 (paused ? "" : "un"), q->name, mem->interface);
7970 }
7971 }
7972 }
7973
7974 mem->paused = paused;
7975 if (paused) {
7976 time(&mem->lastpause); /* update last pause field */
7977 }
7978 if (paused && !ast_strlen_zero(reason)) {
7979 ast_copy_string(mem->reason_paused, reason, sizeof(mem->reason_paused));
7980 } else {
7981 /* We end up filling this in again later (temporarily) but we need it
7982 * empty for now so that the intervening code - specifically
7983 * dump_queue_members() - has the correct view of things. */
7984 mem->reason_paused[0] = '\0';
7985 }
7986
7988 AST_DEVSTATE_CACHABLE, "Queue:%s_pause_%s", q->name, mem->interface);
7989
7992 }
7993
7994 if (is_member_available(q, mem)) {
7996 "Queue:%s_avail", q->name);
7997 } else if (!num_available_members(q)) {
7999 "Queue:%s_avail", q->name);
8000 }
8001
8002 if (!paused && !ast_strlen_zero(reason)) {
8003 /* Because we've been unpaused with a 'reason' we need to ensure that
8004 * that reason is emitted when the subsequent PauseQueueMember event
8005 * is raised. So temporarily set it on the member and clear it out
8006 * again right after. */
8007 ast_copy_string(mem->reason_paused, reason, sizeof(mem->reason_paused));
8008 }
8009
8010 ast_queue_log(q->name, "NONE", mem->membername, paused ? "PAUSE" : "UNPAUSE",
8011 "%s", mem->reason_paused);
8012
8014
8015 if (!paused) {
8016 mem->reason_paused[0] = '\0';
8017 }
8018}
static int publish_queue_member_pause(struct call_queue *q, struct member *member)
Definition app_queue.c:7924
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 8116 of file app_queue.c.

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

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

2046{
2047 int i;
2048
2049 for (i = 0; i < ARRAY_LEN(queue_results); i++) {
2050 if (queue_results[i].id == res) {
2051 pbx_builtin_setvar_helper(chan, "QUEUESTATUS", queue_results[i].text);
2052 return;
2053 }
2054 }
2055}
char * text
Definition app_queue.c:1772
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 2198 of file app_queue.c.

2199{
2200 char interfacevar[256]="";
2201 float sl = 0;
2202
2203 ao2_lock(q);
2204
2205 if (q->setqueuevar) {
2206 sl = 0;
2207 if (q->callscompleted > 0) {
2208 sl = 100 * ((float) q->callscompletedinsl / (float) q->callscompleted);
2209 }
2210
2211 snprintf(interfacevar, sizeof(interfacevar),
2212 "QUEUENAME=%s,QUEUEMAX=%d,QUEUESTRATEGY=%s,QUEUECALLS=%d,QUEUEHOLDTIME=%d,QUEUETALKTIME=%d,QUEUECOMPLETED=%d,QUEUEABANDONED=%d,QUEUESRVLEVEL=%d,QUEUESRVLEVELPERF=%2.1f",
2214
2215 ao2_unlock(q);
2216
2217 pbx_builtin_setvar_multiple(chan, interfacevar);
2218 } else {
2219 ao2_unlock(q);
2220 }
2221}

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

7069{
7070 char escaped_filename[256];
7071 char file_with_ext[sizeof(escaped_filename) + sizeof(qe->parent->monfmt)];
7072 char mixmonargs[1512];
7073 char escaped_monitor_exec[1024];
7074 const char *monitor_options;
7075 const char *monitor_exec;
7076
7077 escaped_monitor_exec[0] = '\0';
7078
7079 if (filename) {
7080 escape_and_substitute(qe->chan, filename, escaped_filename, sizeof(escaped_filename));
7081 } else {
7082 ast_copy_string(escaped_filename, ast_channel_uniqueid(qe->chan), sizeof(escaped_filename));
7083 }
7084
7086 if ((monitor_exec = pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC"))) {
7087 monitor_exec = ast_strdupa(monitor_exec);
7088 }
7089 if ((monitor_options = pbx_builtin_getvar_helper(qe->chan, "MONITOR_OPTIONS"))) {
7090 monitor_options = ast_strdupa(monitor_options);
7091 } else {
7092 monitor_options = "";
7093 }
7095
7096 if (monitor_exec) {
7097 escape_and_substitute(qe->chan, monitor_exec, escaped_monitor_exec, sizeof(escaped_monitor_exec));
7098 }
7099
7100 snprintf(file_with_ext, sizeof(file_with_ext), "%s.%s", escaped_filename, qe->parent->monfmt);
7101
7102 if (!ast_strlen_zero(escaped_monitor_exec)) {
7103 snprintf(mixmonargs, sizeof(mixmonargs), "b%s,%s", monitor_options, escaped_monitor_exec);
7104 } else {
7105 snprintf(mixmonargs, sizeof(mixmonargs), "b%s", monitor_options);
7106 }
7107
7108 ast_debug(1, "Arguments being passed to MixMonitor: %s,%s\n", file_with_ext, mixmonargs);
7109
7110 if (ast_start_mixmonitor(qe->chan, file_with_ext, mixmonargs)) {
7111 ast_log(LOG_WARNING, "Unable to start mixmonitor. Is the MixMonitor app loaded?\n");
7112 }
7113}
static void escape_and_substitute(struct ast_channel *chan, const char *input, char *output, size_t size)
Definition app_queue.c:7037
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 7020 of file app_queue.c.

7021{
7022 const char *context;
7023 const char *extension;
7024 int priority;
7025
7026 if (ast_test_flag(opts, OPT_CALLEE_GO_ON)) {
7027 ast_channel_lock(chan);
7031 ast_channel_unlock(chan);
7033 opt_args[OPT_ARG_CALLEE_GO_ON]);
7034 }
7035}
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 6936 of file app_queue.c.

6938{
6939 struct queue_stasis_data *queue_data = queue_stasis_data_alloc(qe, peer, mem, holdstart, starttime, callcompletedinsl);
6940
6941 if (!queue_data) {
6942 return -1;
6943 }
6944
6946 if (!queue_data->bridge_router) {
6947 ao2_ref(queue_data, -1);
6948 return -1;
6949 }
6950
6952 handle_bridge_enter, queue_data);
6954 handle_blind_transfer, queue_data);
6956 handle_attended_transfer, queue_data);
6958 queue_bridge_cb, queue_data);
6959
6961 if (!queue_data->channel_router) {
6962 /* Unsubscribing from the bridge router will remove the only ref of queue_data,
6963 * thus beginning the destruction process
6964 */
6966 queue_data->bridge_router = NULL;
6967 return -1;
6968 }
6969
6970 ao2_ref(queue_data, +1);
6974 handle_local_optimization_end, queue_data);
6976 handle_hangup, queue_data);
6978 handle_masquerade, queue_data);
6980 queue_channel_cb, queue_data);
6981
6982 return 0;
6983}
static void handle_bridge_enter(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Definition app_queue.c:6531
static void queue_bridge_cb(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Definition app_queue.c:6678
static void handle_attended_transfer(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Handle an attended transfer event.
Definition app_queue.c:6623
static void handle_masquerade(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Definition app_queue.c:6877
static void handle_local_optimization_begin(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Definition app_queue.c:6697
static void handle_local_optimization_end(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Definition app_queue.c:6756
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:6446
static void queue_channel_cb(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Definition app_queue.c:6911
static void handle_hangup(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Definition app_queue.c:6820
static void handle_blind_transfer(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Handle a blind transfer event.
Definition app_queue.c:6564
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 5149 of file app_queue.c.

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

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

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

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

2071{
2072 int x;
2073
2074 for (x = 0; x < ARRAY_LEN(strategies); x++) {
2075 if (!strcasecmp(strategy, strategies[x].name)) {
2076 return strategies[x].strategy;
2077 }
2078 }
2079
2080 return -1;
2081}
int strategy
Definition app_queue.c:1657

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

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

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, callattempt::block_connected_update, calc_metric(), callattempt_free(), member::callcompletedinsl, member::calls, queue_ent::cancel_answered_elsewhere, callattempt::chan, queue_ent::chan, queue_end_bridge::chan, callattempt::connected, digit, member::dynamic, end_bridge_callback(), ast_bridge_config::end_bridge_callback, ast_bridge_config::end_bridge_callback_data, end_bridge_callback_data_fixup(), ast_bridge_config::end_bridge_callback_data_fixup, queue_ent::expire, ast_bridge_config::features_callee, ast_bridge_config::features_caller, queue_ent::handled, hangupcalls(), callattempt::interface, member::interface, member::lastcall, leave_queue(), LOG_ERROR, LOG_NOTICE, LOG_WARNING, callattempt::member, call_queue::memberdelay, call_queue::membergosub, member::membername, call_queue::members, call_queue::monfmt, call_queue::name, NULL, queue_ent::opos, OPT_CALLEE_AUTOMIXMON, OPT_CALLEE_AUTOMON, OPT_CALLEE_HANGUP, OPT_CALLEE_PARK, OPT_CALLEE_TRANSFER, OPT_CALLER_AUTOMIXMON, OPT_CALLER_AUTOMON, OPT_CALLER_HANGUP, OPT_CALLER_PARK, OPT_CALLER_TRANSFER, OPT_DATA_QUALITY, OPT_IGNORE_CALL_FW, OPT_IGNORE_CONNECTEDLINE, OPT_MARK_AS_ANSWERED, OPT_NO_RETRY, out, queue_ent::parent, pbx_builtin_getvar_helper(), pbx_builtin_setvar_multiple(), pbx_exec(), pbx_findapp(), member::penalty, queue_ent::pending, pending_members_remove(), play_file(), queue_ent::pos, queue_end_bridge::q, callattempt::q_next, queue_publish_multi_channel_blob(), QUEUE_STRATEGY_LINEAR, QUEUE_STRATEGY_RRMEMORY, QUEUE_STRATEGY_RRORDERED, queue_t_ref, RAII_VAR, member::realtime, recalc_holdtime(), record_abandoned(), call_queue::reportholdtime, ring_one(), ringing(), S_COR, call_queue::servicelevel, set_queue_variables(), call_queue::setinterfacevar, call_queue::setqueueentryvar, setup_mixmonitor(), setup_peer_after_bridge_goto(), setup_stasis_subs(), call_queue::sound_callerannounce, call_queue::sound_minutes, call_queue::sound_reporthold, call_queue::sound_seconds, queue_ent::start, member::starttime, callattempt::stillgoing, store_next_lin(), store_next_rr(), call_queue::strategy, call_queue::timeout, TIMEOUT_PRIORITY_APP, call_queue::timeoutpriority, type, ast_channel_tech::type, url, and wait_for_answer().

Referenced by queue_exec().

◆ unload_module()

static int unload_module ( void  )
static

Definition at line 11880 of file app_queue.c.

11881{
11884
11886
11887 STASIS_MESSAGE_TYPE_CLEANUP(queue_caller_join_type);
11888 STASIS_MESSAGE_TYPE_CLEANUP(queue_caller_leave_type);
11889 STASIS_MESSAGE_TYPE_CLEANUP(queue_caller_abandon_type);
11890
11891 STASIS_MESSAGE_TYPE_CLEANUP(queue_member_status_type);
11892 STASIS_MESSAGE_TYPE_CLEANUP(queue_member_added_type);
11893 STASIS_MESSAGE_TYPE_CLEANUP(queue_member_removed_type);
11894 STASIS_MESSAGE_TYPE_CLEANUP(queue_member_pause_type);
11895 STASIS_MESSAGE_TYPE_CLEANUP(queue_member_penalty_type);
11896 STASIS_MESSAGE_TYPE_CLEANUP(queue_member_ringinuse_type);
11897
11898 STASIS_MESSAGE_TYPE_CLEANUP(queue_agent_called_type);
11899 STASIS_MESSAGE_TYPE_CLEANUP(queue_agent_connect_type);
11900 STASIS_MESSAGE_TYPE_CLEANUP(queue_agent_complete_type);
11901 STASIS_MESSAGE_TYPE_CLEANUP(queue_agent_dump_type);
11902 STASIS_MESSAGE_TYPE_CLEANUP(queue_agent_ringnoanswer_type);
11903
11905 ast_manager_unregister("QueueStatus");
11906 ast_manager_unregister("QueueRule");
11907 ast_manager_unregister("QueueSummary");
11908 ast_manager_unregister("QueueAdd");
11909 ast_manager_unregister("QueueRemove");
11910 ast_manager_unregister("QueuePause");
11911 ast_manager_unregister("QueueLog");
11912 ast_manager_unregister("QueueUpdate");
11913 ast_manager_unregister("QueuePenalty");
11914 ast_manager_unregister("QueueReload");
11915 ast_manager_unregister("QueueReset");
11916 ast_manager_unregister("QueueMemberRingInUse");
11917 ast_manager_unregister("QueueChangePriorityCaller");
11918 ast_manager_unregister("QueueWithdrawCaller");
11933
11935
11936 ast_unload_realtime("queue_members");
11939
11940 queues = NULL;
11941 return 0;
11942}
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 5330 of file app_queue.c.

5331{
5332 struct ast_party_connected_line connected_caller;
5333
5334 ast_party_connected_line_init(&connected_caller);
5335
5336 ast_channel_lock(peer);
5338 ast_channel_unlock(peer);
5339 connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
5340 if (ast_channel_connected_line_sub(peer, chan, &connected_caller, 0)) {
5341 ast_channel_update_connected_line(chan, &connected_caller, NULL);
5342 }
5343 ast_party_connected_line_free(&connected_caller);
5344}
@ 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 5949 of file app_queue.c.

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

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

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

4140{
4141 int ret = -1;
4142
4143 if (ast_strlen_zero(mem->rt_uniqueid)) {
4144 return ret;
4145 }
4146
4147 if ((ast_update_realtime("queue_members", "uniqueid", mem->rt_uniqueid, field, value, SENTINEL)) >= 0) {
4148 ret = 0;
4149 }
4150
4151 return ret;
4152}

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

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

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

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

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

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

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

4328{
4329 int digitlen = strlen(qe->digits);
4330
4331 /* Prevent possible buffer overflow */
4332 if (digitlen < sizeof(qe->digits) - 2) {
4333 qe->digits[digitlen] = digit;
4334 qe->digits[digitlen + 1] = '\0';
4335 } else {
4336 qe->digits[0] = '\0';
4337 return 0;
4338 }
4339
4340 /* If there's no context to goto, short-circuit */
4341 if (ast_strlen_zero(qe->context)) {
4342 return 0;
4343 }
4344
4345 /* If the extension is bad, then reset the digits to blank */
4346 if (!ast_canmatch_extension(qe->chan, qe->context, qe->digits, 1,
4348 qe->digits[0] = '\0';
4349 return 0;
4350 }
4351
4352 /* We have an exact match */
4353 if (!ast_goto_if_exists(qe->chan, qe->context, qe->digits, 1)) {
4354 qe->valid_digits = 1;
4355 /* Return 1 on a successful goto */
4356 return 1;
4357 }
4358
4359 return 0;
4360}
int ast_goto_if_exists(struct ast_channel *chan, const char *context, const char *exten, int priority)
Definition pbx.c:8806
int ast_canmatch_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
Looks for a valid matching extension.
Definition pbx.c:4211
char context[AST_MAX_CONTEXT]
Definition app_queue.c:1829

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

7609{
7610 /* Don't need to hold the lock while we setup the outgoing calls */
7611 int retrywait = qe->parent->retry * 1000;
7612
7613 int res = ast_waitfordigit(qe->chan, retrywait);
7614 if (res > 0 && !valid_exit(qe, res)) {
7615 res = 0;
7616 }
7617
7618 return res;
7619}
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 5360 of file app_queue.c.

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

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

Referenced by try_calling().

◆ wait_our_turn()

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

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

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

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

Definition at line 6039 of file app_queue.c.

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

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

10438 {
10439 int list_len, word_len = strlen(word);
10440 const char *find, *end_find, *end_list;
10441
10442 /* strip whitespace from front */
10443 while(isspace(*list)) {
10444 list++;
10445 }
10446
10447 while((find = strstr(list, word))) {
10448 /* beginning of find starts inside another word? */
10449 if (find != list && *(find - 1) != ' ') {
10450 list = find;
10451 /* strip word from front */
10452 while(!isspace(*list) && *list != '\0') {
10453 list++;
10454 }
10455 /* strip whitespace from front */
10456 while(isspace(*list)) {
10457 list++;
10458 }
10459 continue;
10460 }
10461
10462 /* end of find ends inside another word or at very end of list? */
10463 list_len = strlen(list);
10464 end_find = find + word_len;
10465 end_list = list + list_len;
10466 if (end_find == end_list || *end_find != ' ') {
10467 list = find;
10468 /* strip word from front */
10469 while(!isspace(*list) && *list != '\0') {
10470 list++;
10471 }
10472 /* strip whitespace from front */
10473 while(isspace(*list)) {
10474 list++;
10475 }
10476 continue;
10477 }
10478
10479 /* terminating conditions satisfied, word at beginning or separated by ' ' */
10480 return 1;
10481 }
10482
10483 return 0;
10484}

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

◆ agent_router

struct stasis_message_router* agent_router
static

Definition at line 11877 of file app_queue.c.

Referenced by load_module(), and unload_module().

◆ app

char* app = "Queue"
static

Definition at line 1699 of file app_queue.c.

Referenced by load_module(), and unload_module().

◆ app_aqm

char* app_aqm = "AddQueueMember"
static

Definition at line 1701 of file app_queue.c.

Referenced by load_module(), and unload_module().

◆ app_pqm

char* app_pqm = "PauseQueueMember"
static

Definition at line 1705 of file app_queue.c.

Referenced by load_module(), and unload_module().

◆ app_ql

char* app_ql = "QueueLog"
static

Definition at line 1709 of file app_queue.c.

Referenced by load_module(), and unload_module().

◆ app_qupd

char* app_qupd = "QueueUpdate"
static

Definition at line 1711 of file app_queue.c.

Referenced by load_module(), and unload_module().

◆ app_rqm

char* app_rqm = "RemoveQueueMember"
static

Definition at line 1703 of file app_queue.c.

Referenced by load_module(), and unload_module().

◆ app_upqm

char* app_upqm = "UnpauseQueueMember"
static

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

◆ autofill_default

int autofill_default
static

queues.conf [general] option

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

11864 {
11865 AST_CLI_DEFINE(queue_show, "Show status of a specified queue"),
11866 AST_CLI_DEFINE(handle_queue_rule_show, "Show the rules defined in queuerules.conf"),
11867 AST_CLI_DEFINE(handle_queue_add_member, "Add a channel to a specified queue"),
11868 AST_CLI_DEFINE(handle_queue_remove_member, "Removes a channel from a specified queue"),
11869 AST_CLI_DEFINE(handle_queue_pause_member, "Pause or unpause a queue member"),
11870 AST_CLI_DEFINE(handle_queue_set_member_penalty, "Set penalty for a channel of a specified queue"),
11871 AST_CLI_DEFINE(handle_queue_set_member_ringinuse, "Set ringinuse for a channel of a specified queue"),
11872 AST_CLI_DEFINE(handle_queue_reload, "Reload queues, members, queue rules, or parameters"),
11873 AST_CLI_DEFINE(handle_queue_reset, "Reset statistics for a queue"),
11874 AST_CLI_DEFINE(handle_queue_change_priority_caller, "Change priority caller on queue"),
11875};
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 1735 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 1744 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 1771 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_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(), process_text_message(), queue_connected_line_update(), session_end_if_disconnected(), session_inv_on_tsx_state_changed(), set_id_from_from(), set_id_from_hdr(), set_id_from_pai(), set_id_from_rpid(), set_state(), setflag(), should_queue_connected_line_update(), showdisplay(), showkeys(), sip_subscription_to_ami(), sorcery_realtime_create(), sorcery_realtime_retrieve_fields(), sorcery_realtime_retrieve_multiple(), sorcery_realtime_update(), startelm(), starttimer(), state_id_by_topic(), try_merge_optimize_out(), try_swap_optimize_out(), and update_incoming_connected_line().

◆ log_caller_id_name

int log_caller_id_name
static

queues.conf [general] option

Definition at line 1747 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 1750 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 1726 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 1738 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 2653 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 1714 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 1614 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:9177

Definition at line 9612 of file app_queue.c.

9612 {
9613 .name = "QUEUE_EXISTS",
9614 .read = queue_function_exists,
9615};

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

Definition at line 9628 of file app_queue.c.

9628 {
9629 .name = "QUEUE_GET_CHANNEL",
9631};

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:9219
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:9321

Definition at line 9622 of file app_queue.c.

9622 {
9623 .name = "QUEUE_MEMBER",
9625 .write = queue_function_mem_write,
9626};

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

Definition at line 9638 of file app_queue.c.

9638 {
9639 .name = "QUEUE_MEMBER_LIST",
9641};

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

Definition at line 9643 of file app_queue.c.

9643 {
9644 .name = "QUEUE_MEMBER_PENALTY",
9647};

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

Definition at line 9617 of file app_queue.c.

9617 {
9618 .name = "QUEUE_VARIABLES",
9619 .read = queue_function_var,
9620};

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

Definition at line 9633 of file app_queue.c.

9633 {
9634 .name = "QUEUE_WAITING_COUNT",
9636};

Referenced by load_module(), and unload_module().

◆ realtime_reason_paused

int realtime_reason_paused
static

does realtime backend support reason_paused

Definition at line 1756 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 1753 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 1732 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 1729 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 11878 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 1720 of file app_queue.c.

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